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:
authorLukas Tönne <lukas.toenne@gmail.com>2018-06-09 08:43:15 +0300
committerLukas Tönne <lukas.toenne@gmail.com>2018-06-09 08:43:15 +0300
commitb7b6f72cb57af13f0a0637c515a06e3831989909 (patch)
tree424fccbc7cf4701ffe37d8930b1ca10972991adb
parent4f2532e88cca35a3aaad753cbb27cb93d13dbb7a (diff)
parent86660aa29468d6902e2da9dda2789eb2f973df48 (diff)
Merge branch 'blender2.8' into hair_guides
-rw-r--r--CMakeLists.txt24
-rw-r--r--build_files/cmake/platform/platform_win32.cmake3
-rw-r--r--build_files/windows/configure_msbuild.cmd7
-rw-r--r--build_files/windows/configure_ninja.cmd6
-rw-r--r--build_files/windows/detect_msvc2017.cmd7
-rw-r--r--build_files/windows/parse_arguments.cmd4
-rw-r--r--build_files/windows/reset_variables.cmd4
-rw-r--r--build_files/windows/show_help.cmd12
-rw-r--r--extern/audaspace/plugins/ffmpeg/FFMPEG.cpp2
-rw-r--r--extern/audaspace/plugins/ffmpeg/FFMPEGReader.cpp124
-rw-r--r--extern/audaspace/plugins/ffmpeg/FFMPEGReader.h5
-rw-r--r--extern/audaspace/plugins/ffmpeg/FFMPEGWriter.cpp216
-rw-r--r--extern/audaspace/plugins/ffmpeg/FFMPEGWriter.h13
-rw-r--r--intern/cycles/blender/addon/ui.py76
-rw-r--r--intern/cycles/blender/blender_object.cpp16
-rw-r--r--intern/cycles/kernel/bvh/bvh.h25
-rw-r--r--intern/cycles/kernel/bvh/bvh_local.h26
-rw-r--r--intern/gawain/gawain/gwn_common.h2
-rw-r--r--intern/gawain/src/gwn_batch.c2
-rw-r--r--intern/gawain/src/gwn_immediate.c2
-rw-r--r--intern/ghost/CMakeLists.txt4
-rw-r--r--intern/ghost/GHOST_C-api.h12
-rw-r--r--intern/ghost/GHOST_IEvent.h10
-rw-r--r--intern/ghost/GHOST_ISystem.h2
-rw-r--r--intern/ghost/GHOST_ISystemPaths.h4
-rw-r--r--intern/ghost/GHOST_ITimerTask.h6
-rw-r--r--intern/ghost/GHOST_IWindow.h2
-rw-r--r--intern/ghost/GHOST_Path-api.h4
-rw-r--r--intern/ghost/GHOST_Types.h20
-rw-r--r--intern/ghost/intern/GHOST_Buttons.h2
-rw-r--r--intern/ghost/intern/GHOST_C-api.cpp48
-rw-r--r--intern/ghost/intern/GHOST_ContextWGL.h2
-rw-r--r--intern/ghost/intern/GHOST_Debug.h4
-rw-r--r--intern/ghost/intern/GHOST_DisplayManager.cpp4
-rw-r--r--intern/ghost/intern/GHOST_DisplayManager.h8
-rw-r--r--intern/ghost/intern/GHOST_DisplayManagerCocoa.h8
-rw-r--r--intern/ghost/intern/GHOST_DisplayManagerWin32.cpp14
-rw-r--r--intern/ghost/intern/GHOST_DisplayManagerWin32.h6
-rw-r--r--intern/ghost/intern/GHOST_DisplayManagerX11.cpp2
-rw-r--r--intern/ghost/intern/GHOST_DisplayManagerX11.h8
-rw-r--r--intern/ghost/intern/GHOST_DropTargetWin32.cpp36
-rw-r--r--intern/ghost/intern/GHOST_DropTargetWin32.h22
-rw-r--r--intern/ghost/intern/GHOST_Event.h4
-rw-r--r--intern/ghost/intern/GHOST_EventDragnDrop.h16
-rw-r--r--intern/ghost/intern/GHOST_EventKey.h4
-rw-r--r--intern/ghost/intern/GHOST_EventManager.cpp2
-rw-r--r--intern/ghost/intern/GHOST_EventManager.h2
-rw-r--r--intern/ghost/intern/GHOST_EventNDOF.h2
-rw-r--r--intern/ghost/intern/GHOST_EventPrinter.cpp12
-rw-r--r--intern/ghost/intern/GHOST_ISystemPaths.cpp2
-rw-r--r--intern/ghost/intern/GHOST_NDOFManager.cpp2
-rw-r--r--intern/ghost/intern/GHOST_NDOFManager.h2
-rw-r--r--intern/ghost/intern/GHOST_NDOFManagerCocoa.h2
-rw-r--r--intern/ghost/intern/GHOST_NDOFManagerUnix.cpp2
-rw-r--r--intern/ghost/intern/GHOST_NDOFManagerUnix.h4
-rw-r--r--intern/ghost/intern/GHOST_NDOFManagerWin32.cpp4
-rw-r--r--intern/ghost/intern/GHOST_NDOFManagerWin32.h2
-rw-r--r--intern/ghost/intern/GHOST_Rect.cpp2
-rw-r--r--intern/ghost/intern/GHOST_System.cpp6
-rw-r--r--intern/ghost/intern/GHOST_System.h16
-rw-r--r--intern/ghost/intern/GHOST_SystemCocoa.h30
-rw-r--r--intern/ghost/intern/GHOST_SystemPaths.h4
-rw-r--r--intern/ghost/intern/GHOST_SystemPathsCocoa.h4
-rw-r--r--intern/ghost/intern/GHOST_SystemPathsUnix.cpp4
-rw-r--r--intern/ghost/intern/GHOST_SystemPathsUnix.h6
-rw-r--r--intern/ghost/intern/GHOST_SystemPathsWin32.cpp2
-rw-r--r--intern/ghost/intern/GHOST_SystemWin32.cpp146
-rw-r--r--intern/ghost/intern/GHOST_SystemWin32.h18
-rw-r--r--intern/ghost/intern/GHOST_SystemX11.cpp122
-rw-r--r--intern/ghost/intern/GHOST_SystemX11.h22
-rw-r--r--intern/ghost/intern/GHOST_TaskbarWin32.h2
-rw-r--r--intern/ghost/intern/GHOST_TaskbarX11.cpp2
-rw-r--r--intern/ghost/intern/GHOST_TimerManager.cpp6
-rw-r--r--intern/ghost/intern/GHOST_TimerManager.h4
-rw-r--r--intern/ghost/intern/GHOST_TimerTask.h10
-rw-r--r--intern/ghost/intern/GHOST_Window.cpp10
-rw-r--r--intern/ghost/intern/GHOST_Window.h42
-rw-r--r--intern/ghost/intern/GHOST_WindowCocoa.h34
-rw-r--r--intern/ghost/intern/GHOST_WindowManager.cpp10
-rw-r--r--intern/ghost/intern/GHOST_WindowManager.h18
-rw-r--r--intern/ghost/intern/GHOST_WindowWin32.cpp10
-rw-r--r--intern/ghost/intern/GHOST_WindowWin32.h20
-rw-r--r--intern/ghost/intern/GHOST_WindowX11.cpp62
-rw-r--r--intern/ghost/intern/GHOST_WindowX11.h26
-rw-r--r--intern/ghost/test/CMakeLists.txt4
-rw-r--r--intern/ghost/test/gears/GHOST_C-Test.c68
-rw-r--r--intern/ghost/test/gears/GHOST_Test.cpp4
-rw-r--r--intern/ghost/test/multitest/Basic.h8
-rw-r--r--intern/ghost/test/multitest/EventToBuf.c4
-rw-r--r--intern/ghost/test/multitest/MultiTest.c168
-rw-r--r--intern/ghost/test/multitest/ScrollBar.c8
-rw-r--r--intern/ghost/test/multitest/ScrollBar.h2
-rw-r--r--intern/ghost/test/multitest/Util.c10
-rw-r--r--intern/ghost/test/multitest/WindowData.c2
-rw-r--r--intern/ghost/test/multitest/WindowData.h4
-rw-r--r--release/datafiles/studiolights/matcap/license.txt3
-rw-r--r--release/datafiles/studiolights/matcap/mc01.jpgbin0 -> 20830 bytes
-rw-r--r--release/datafiles/studiolights/matcap/mc02.jpgbin0 -> 23428 bytes
-rw-r--r--release/datafiles/studiolights/matcap/mc03.jpgbin0 -> 17550 bytes
-rw-r--r--release/datafiles/studiolights/matcap/mc04.jpgbin0 -> 29197 bytes
-rw-r--r--release/datafiles/studiolights/matcap/mc05.jpgbin0 -> 25454 bytes
-rw-r--r--release/datafiles/studiolights/matcap/mc06.jpgbin0 -> 19864 bytes
-rw-r--r--release/datafiles/studiolights/matcap/mc07.jpgbin0 -> 59262 bytes
-rw-r--r--release/datafiles/studiolights/matcap/mc08.jpgbin0 -> 24133 bytes
-rw-r--r--release/datafiles/studiolights/matcap/mc09.jpgbin0 -> 31101 bytes
-rw-r--r--release/datafiles/studiolights/matcap/mc10.jpgbin0 -> 28973 bytes
-rw-r--r--release/datafiles/studiolights/matcap/mc11.jpgbin0 -> 21395 bytes
-rw-r--r--release/datafiles/studiolights/matcap/mc12.jpgbin0 -> 23797 bytes
-rw-r--r--release/datafiles/studiolights/matcap/mc13.jpgbin0 -> 45661 bytes
-rw-r--r--release/datafiles/studiolights/matcap/mc14.jpgbin0 -> 44762 bytes
-rw-r--r--release/datafiles/studiolights/matcap/mc15.jpgbin0 -> 27456 bytes
-rw-r--r--release/datafiles/studiolights/matcap/mc16.jpgbin0 -> 33401 bytes
-rw-r--r--release/datafiles/studiolights/matcap/mc17.jpgbin0 -> 49292 bytes
-rw-r--r--release/datafiles/studiolights/matcap/mc18.jpgbin0 -> 40254 bytes
-rw-r--r--release/datafiles/studiolights/matcap/mc19.jpgbin0 -> 46330 bytes
-rw-r--r--release/datafiles/studiolights/matcap/mc20.jpgbin0 -> 52893 bytes
-rw-r--r--release/datafiles/studiolights/matcap/mc21.jpgbin0 -> 28717 bytes
-rw-r--r--release/datafiles/studiolights/matcap/mc22.jpgbin0 -> 33801 bytes
-rw-r--r--release/datafiles/studiolights/matcap/mc23.jpgbin0 -> 26688 bytes
-rw-r--r--release/datafiles/studiolights/matcap/mc24.jpgbin0 -> 14149 bytes
m---------release/scripts/addons0
m---------release/scripts/addons_contrib0
-rw-r--r--release/scripts/startup/bl_operators/wm.py126
-rw-r--r--release/scripts/startup/bl_ui/__init__.py4
-rw-r--r--release/scripts/startup/bl_ui/properties_constraint.py1
-rw-r--r--release/scripts/startup/bl_ui/properties_data_curve.py3
-rw-r--r--release/scripts/startup/bl_ui/properties_data_lamp.py1
-rw-r--r--release/scripts/startup/bl_ui/properties_freestyle.py19
-rw-r--r--release/scripts/startup/bl_ui/properties_grease_pencil_common.py5
-rw-r--r--release/scripts/startup/bl_ui/properties_mask_common.py32
-rw-r--r--release/scripts/startup/bl_ui/properties_paint_common.py2
-rw-r--r--release/scripts/startup/bl_ui/properties_particle.py55
-rw-r--r--release/scripts/startup/bl_ui/properties_physics_cloth.py1
-rw-r--r--release/scripts/startup/bl_ui/properties_physics_common.py2
-rw-r--r--release/scripts/startup/bl_ui/properties_physics_rigidbody.py2
-rw-r--r--release/scripts/startup/bl_ui/properties_render.py19
-rw-r--r--release/scripts/startup/bl_ui/properties_scene.py23
-rw-r--r--release/scripts/startup/bl_ui/properties_texture.py2
-rw-r--r--release/scripts/startup/bl_ui/properties_view_layer.py2
-rw-r--r--release/scripts/startup/bl_ui/space_clip.py9
-rw-r--r--release/scripts/startup/bl_ui/space_dopesheet.py76
-rw-r--r--release/scripts/startup/bl_ui/space_graph.py72
-rw-r--r--release/scripts/startup/bl_ui/space_image.py41
-rw-r--r--release/scripts/startup/bl_ui/space_node.py41
-rw-r--r--release/scripts/startup/bl_ui/space_outliner.py14
-rw-r--r--release/scripts/startup/bl_ui/space_properties.py3
-rw-r--r--release/scripts/startup/bl_ui/space_statusbar.py1
-rw-r--r--release/scripts/startup/bl_ui/space_time.py2
-rw-r--r--release/scripts/startup/bl_ui/space_toolsystem_common.py23
-rw-r--r--release/scripts/startup/bl_ui/space_toolsystem_toolbar.py3
-rw-r--r--release/scripts/startup/bl_ui/space_topbar.py2
-rw-r--r--release/scripts/startup/bl_ui/space_userpref.py87
-rw-r--r--release/scripts/startup/bl_ui/space_view3d.py401
-rw-r--r--release/scripts/startup/bl_ui/space_view3d_toolbar.py35
-rw-r--r--source/blender/alembic/ABC_alembic.h15
-rw-r--r--source/blender/alembic/intern/abc_camera.cc6
-rw-r--r--source/blender/alembic/intern/abc_camera.h4
-rw-r--r--source/blender/alembic/intern/abc_curves.cc53
-rw-r--r--source/blender/alembic/intern/abc_curves.h21
-rw-r--r--source/blender/alembic/intern/abc_exporter.cc101
-rw-r--r--source/blender/alembic/intern/abc_exporter.h18
-rw-r--r--source/blender/alembic/intern/abc_hair.cc60
-rw-r--r--source/blender/alembic/intern/abc_hair.h9
-rw-r--r--source/blender/alembic/intern/abc_mball.cc9
-rw-r--r--source/blender/alembic/intern/abc_mball.h2
-rw-r--r--source/blender/alembic/intern/abc_mesh.cc362
-rw-r--r--source/blender/alembic/intern/abc_mesh.h42
-rw-r--r--source/blender/alembic/intern/abc_nurbs.cc20
-rw-r--r--source/blender/alembic/intern/abc_nurbs.h4
-rw-r--r--source/blender/alembic/intern/abc_object.cc16
-rw-r--r--source/blender/alembic/intern/abc_object.h16
-rw-r--r--source/blender/alembic/intern/abc_points.cc56
-rw-r--r--source/blender/alembic/intern/abc_points.h12
-rw-r--r--source/blender/alembic/intern/abc_transform.cc17
-rw-r--r--source/blender/alembic/intern/abc_transform.h3
-rw-r--r--source/blender/alembic/intern/abc_util.cc10
-rw-r--r--source/blender/alembic/intern/alembic_capi.cc38
-rw-r--r--source/blender/blenfont/intern/blf.c2
-rw-r--r--source/blender/blenfont/intern/blf_dir.c16
-rw-r--r--source/blender/blenfont/intern/blf_font.c2
-rw-r--r--source/blender/blenfont/intern/blf_glyph.c4
-rw-r--r--source/blender/blenfont/intern/blf_internal_types.h2
-rw-r--r--source/blender/blenkernel/BKE_DerivedMesh.h12
-rw-r--r--source/blender/blenkernel/BKE_anim.h34
-rw-r--r--source/blender/blenkernel/BKE_collection.h1
-rw-r--r--source/blender/blenkernel/BKE_library.h3
-rw-r--r--source/blender/blenkernel/BKE_mball.h2
-rw-r--r--source/blender/blenkernel/BKE_mesh.h19
-rw-r--r--source/blender/blenkernel/BKE_mesh_runtime.h85
-rw-r--r--source/blender/blenkernel/BKE_movieclip.h2
-rw-r--r--source/blender/blenkernel/BKE_node.h3
-rw-r--r--source/blender/blenkernel/BKE_object.h1
-rw-r--r--source/blender/blenkernel/BKE_paint.h6
-rw-r--r--source/blender/blenkernel/BKE_particle.h3
-rw-r--r--source/blender/blenkernel/BKE_pbvh.h2
-rw-r--r--source/blender/blenkernel/BKE_studiolight.h30
-rw-r--r--source/blender/blenkernel/intern/DerivedMesh.c13
-rw-r--r--source/blender/blenkernel/intern/blender_undo.c12
-rw-r--r--source/blender/blenkernel/intern/blendfile.c44
-rw-r--r--source/blender/blenkernel/intern/bpath.c2
-rw-r--r--source/blender/blenkernel/intern/bvhutils.c1
-rw-r--r--source/blender/blenkernel/intern/cachefile.c23
-rw-r--r--source/blender/blenkernel/intern/cdderivedmesh.c2
-rw-r--r--source/blender/blenkernel/intern/cloth.c2
-rw-r--r--source/blender/blenkernel/intern/collection.c41
-rw-r--r--source/blender/blenkernel/intern/data_transfer.c1
-rw-r--r--source/blender/blenkernel/intern/displist.c94
-rw-r--r--source/blender/blenkernel/intern/dynamicpaint.c2
-rw-r--r--source/blender/blenkernel/intern/font.c6
-rw-r--r--source/blender/blenkernel/intern/image.c9
-rw-r--r--source/blender/blenkernel/intern/layer.c10
-rw-r--r--source/blender/blenkernel/intern/library.c22
-rw-r--r--source/blender/blenkernel/intern/material.c4
-rw-r--r--source/blender/blenkernel/intern/mball.c5
-rw-r--r--source/blender/blenkernel/intern/mesh.c63
-rw-r--r--source/blender/blenkernel/intern/mesh_convert.c5
-rw-r--r--source/blender/blenkernel/intern/mesh_evaluate.c14
-rw-r--r--source/blender/blenkernel/intern/mesh_runtime.c22
-rw-r--r--source/blender/blenkernel/intern/movieclip.c18
-rw-r--r--source/blender/blenkernel/intern/multires.c1
-rw-r--r--source/blender/blenkernel/intern/node.c34
-rw-r--r--source/blender/blenkernel/intern/object.c30
-rw-r--r--source/blender/blenkernel/intern/object_dupli.c75
-rw-r--r--source/blender/blenkernel/intern/object_update.c1
-rw-r--r--source/blender/blenkernel/intern/packedFile.c14
-rw-r--r--source/blender/blenkernel/intern/paint.c134
-rw-r--r--source/blender/blenkernel/intern/particle.c47
-rw-r--r--source/blender/blenkernel/intern/particle_system.c12
-rw-r--r--source/blender/blenkernel/intern/pbvh.c7
-rw-r--r--source/blender/blenkernel/intern/pointcache.c2
-rw-r--r--source/blender/blenkernel/intern/rigidbody.c3
-rw-r--r--source/blender/blenkernel/intern/scene.c6
-rw-r--r--source/blender/blenkernel/intern/seqeffects.c13
-rw-r--r--source/blender/blenkernel/intern/sequencer.c21
-rw-r--r--source/blender/blenkernel/intern/sound.c4
-rw-r--r--source/blender/blenkernel/intern/studiolight.c82
-rw-r--r--source/blender/blenkernel/intern/subsurf_ccg.c2
-rw-r--r--source/blender/blenkernel/intern/text.c6
-rw-r--r--source/blender/blenkernel/intern/undo_system.c2
-rw-r--r--source/blender/blenkernel/intern/world.c9
-rw-r--r--source/blender/blenkernel/intern/writeavi.c2
-rw-r--r--source/blender/blenkernel/intern/writeffmpeg.c2
-rw-r--r--source/blender/blenlib/BLI_math_base.h18
-rw-r--r--source/blender/blenloader/intern/readfile.c16
-rw-r--r--source/blender/blenloader/intern/readfile.h16
-rw-r--r--source/blender/blenloader/intern/undofile.c2
-rw-r--r--source/blender/blenloader/intern/versioning_250.c254
-rw-r--r--source/blender/blenloader/intern/versioning_260.c390
-rw-r--r--source/blender/blenloader/intern/versioning_270.c270
-rw-r--r--source/blender/blenloader/intern/versioning_280.c221
-rw-r--r--source/blender/blenloader/intern/versioning_legacy.c422
-rw-r--r--source/blender/blenloader/intern/writefile.c2
-rw-r--r--source/blender/bmesh/intern/bmesh_log.c8
-rw-r--r--source/blender/bmesh/intern/bmesh_mesh_conv.c1
-rw-r--r--source/blender/collada/AnimationExporter.cpp54
-rw-r--r--source/blender/collada/AnimationExporter.h22
-rw-r--r--source/blender/collada/AnimationImporter.cpp121
-rw-r--r--source/blender/collada/AnimationImporter.h28
-rw-r--r--source/blender/collada/ArmatureExporter.cpp21
-rw-r--r--source/blender/collada/ArmatureExporter.h4
-rw-r--r--source/blender/collada/ArmatureImporter.cpp57
-rw-r--r--source/blender/collada/ArmatureImporter.h10
-rw-r--r--source/blender/collada/CameraExporter.cpp4
-rw-r--r--source/blender/collada/ControllerExporter.cpp22
-rw-r--r--source/blender/collada/DocumentExporter.cpp21
-rw-r--r--source/blender/collada/DocumentExporter.h2
-rw-r--r--source/blender/collada/DocumentImporter.cpp92
-rw-r--r--source/blender/collada/DocumentImporter.h6
-rw-r--r--source/blender/collada/EffectExporter.cpp22
-rw-r--r--source/blender/collada/EffectExporter.h10
-rw-r--r--source/blender/collada/ErrorHandler.cpp2
-rw-r--r--source/blender/collada/ExtraHandler.cpp4
-rw-r--r--source/blender/collada/ExtraHandler.h18
-rw-r--r--source/blender/collada/ExtraTags.cpp2
-rw-r--r--source/blender/collada/ExtraTags.h16
-rw-r--r--source/blender/collada/GeometryExporter.cpp92
-rw-r--r--source/blender/collada/GeometryExporter.h8
-rw-r--r--source/blender/collada/ImageExporter.cpp10
-rw-r--r--source/blender/collada/ImageExporter.h2
-rw-r--r--source/blender/collada/InstanceWriter.cpp8
-rw-r--r--source/blender/collada/LightExporter.cpp16
-rw-r--r--source/blender/collada/MaterialExporter.h2
-rw-r--r--source/blender/collada/MeshImporter.cpp82
-rw-r--r--source/blender/collada/MeshImporter.h10
-rw-r--r--source/blender/collada/SceneExporter.cpp28
-rw-r--r--source/blender/collada/SceneExporter.h8
-rw-r--r--source/blender/collada/SkinInfo.cpp8
-rw-r--r--source/blender/collada/SkinInfo.h4
-rw-r--r--source/blender/collada/TransformReader.cpp6
-rw-r--r--source/blender/collada/TransformReader.h2
-rw-r--r--source/blender/collada/TransformWriter.cpp2
-rw-r--r--source/blender/collada/collada.cpp5
-rw-r--r--source/blender/collada/collada.h4
-rw-r--r--source/blender/collada/collada_internal.h8
-rw-r--r--source/blender/collada/collada_utils.cpp24
-rw-r--r--source/blender/collada/collada_utils.h8
-rw-r--r--source/blender/compositor/operations/COM_OutputFileMultiViewOperation.cpp10
-rw-r--r--source/blender/compositor/operations/COM_OutputFileOperation.cpp7
-rw-r--r--source/blender/datatoc/datatoc_icon.c2
-rw-r--r--source/blender/depsgraph/DEG_depsgraph_query.h13
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_cycle.cc4
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_nodes.cc228
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_nodes.h24
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_nodes_rig.cc31
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_nodes_view_layer.cc12
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_relations.cc421
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_relations.h23
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_relations_rig.cc44
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_relations_view_layer.cc12
-rw-r--r--source/blender/depsgraph/intern/depsgraph_query_iter.cc6
-rw-r--r--source/blender/depsgraph/intern/depsgraph_tag.cc14
-rw-r--r--source/blender/depsgraph/intern/depsgraph_type_defines.cc2
-rw-r--r--source/blender/depsgraph/intern/depsgraph_types.h15
-rw-r--r--source/blender/draw/CMakeLists.txt2
-rw-r--r--source/blender/draw/engines/basic/basic_engine.c2
-rw-r--r--source/blender/draw/engines/clay/clay_engine.c2
-rw-r--r--source/blender/draw/engines/eevee/eevee_lights.c144
-rw-r--r--source/blender/draw/engines/eevee/eevee_lookdev.c6
-rw-r--r--source/blender/draw/engines/eevee/eevee_private.h2
-rw-r--r--source/blender/draw/engines/eevee/eevee_render.c32
-rw-r--r--source/blender/draw/engines/eevee/shaders/shadow_store_frag.glsl2
-rw-r--r--source/blender/draw/engines/workbench/shaders/workbench_cavity_frag.glsl71
-rw-r--r--source/blender/draw/engines/workbench/shaders/workbench_cavity_lib.glsl79
-rw-r--r--source/blender/draw/engines/workbench/shaders/workbench_data_lib.glsl3
-rw-r--r--source/blender/draw/engines/workbench/shaders/workbench_deferred_composite_frag.glsl46
-rw-r--r--source/blender/draw/engines/workbench/shaders/workbench_forward_transparent_accum_frag.glsl17
-rw-r--r--source/blender/draw/engines/workbench/shaders/workbench_prepass_frag.glsl25
-rw-r--r--source/blender/draw/engines/workbench/shaders/workbench_prepass_vert.glsl2
-rw-r--r--source/blender/draw/engines/workbench/shaders/workbench_world_light_lib.glsl6
-rw-r--r--source/blender/draw/engines/workbench/workbench_data.c72
-rw-r--r--source/blender/draw/engines/workbench/workbench_deferred.c154
-rw-r--r--source/blender/draw/engines/workbench/workbench_forward.c17
-rw-r--r--source/blender/draw/engines/workbench/workbench_materials.c60
-rw-r--r--source/blender/draw/engines/workbench/workbench_private.h30
-rw-r--r--source/blender/draw/intern/DRW_render.h3
-rw-r--r--source/blender/draw/intern/draw_armature.c29
-rw-r--r--source/blender/draw/intern/draw_cache_impl_mesh.c97
-rw-r--r--source/blender/draw/intern/draw_cache_impl_particles.c4
-rw-r--r--source/blender/draw/intern/draw_hair.c1
-rw-r--r--source/blender/draw/intern/draw_instance_data.h2
-rw-r--r--source/blender/draw/intern/draw_manager.c30
-rw-r--r--source/blender/draw/intern/draw_manager_data.c39
-rw-r--r--source/blender/draw/intern/draw_manager_shader.c36
-rw-r--r--source/blender/draw/modes/object_mode.c6
-rw-r--r--source/blender/draw/modes/overlay_mode.c49
-rw-r--r--source/blender/draw/modes/particle_mode.c6
-rw-r--r--source/blender/draw/modes/pose_mode.c24
-rw-r--r--source/blender/draw/modes/shaders/armature_shape_outline_geom.glsl2
-rw-r--r--source/blender/draw/modes/shaders/overlay_face_wireframe_frag.glsl21
-rw-r--r--source/blender/draw/modes/shaders/overlay_face_wireframe_geom.glsl36
-rw-r--r--source/blender/draw/modes/shaders/overlay_face_wireframe_vert.glsl75
-rw-r--r--source/blender/editors/animation/anim_channels_defines.c4
-rw-r--r--source/blender/editors/animation/anim_deps.c14
-rw-r--r--source/blender/editors/animation/anim_filter.c14
-rw-r--r--source/blender/editors/animation/keyframes_general.c8
-rw-r--r--source/blender/editors/animation/keyframing.c44
-rw-r--r--source/blender/editors/animation/keyingsets.c5
-rw-r--r--source/blender/editors/armature/armature_edit.c13
-rw-r--r--source/blender/editors/armature/armature_naming.c20
-rw-r--r--source/blender/editors/armature/armature_relations.c18
-rw-r--r--source/blender/editors/armature/armature_skinning.c1
-rw-r--r--source/blender/editors/armature/armature_utils.c4
-rw-r--r--source/blender/editors/armature/editarmature_retarget.c2644
-rw-r--r--source/blender/editors/armature/meshlaplacian.c1
-rw-r--r--source/blender/editors/armature/pose_edit.c7
-rw-r--r--source/blender/editors/armature/pose_lib.c15
-rw-r--r--source/blender/editors/armature/pose_transform.c3
-rw-r--r--source/blender/editors/curve/editcurve.c12
-rw-r--r--source/blender/editors/curve/editcurve_paint.c2
-rw-r--r--source/blender/editors/gpencil/gpencil_convert.c4
-rw-r--r--source/blender/editors/gpencil/gpencil_edit.c1
-rw-r--r--source/blender/editors/gpencil/gpencil_paint.c13
-rw-r--r--source/blender/editors/gpencil/gpencil_utils.c3
-rw-r--r--source/blender/editors/include/ED_anim_api.h4
-rw-r--r--source/blender/editors/include/ED_armature.h13
-rw-r--r--source/blender/editors/include/ED_curve.h11
-rw-r--r--source/blender/editors/include/ED_keyframing.h6
-rw-r--r--source/blender/editors/include/ED_object.h4
-rw-r--r--source/blender/editors/include/ED_screen.h4
-rw-r--r--source/blender/editors/include/ED_transform_snap_object_context.h4
-rw-r--r--source/blender/editors/include/ED_view3d.h4
-rw-r--r--source/blender/editors/include/UI_interface.h7
-rw-r--r--source/blender/editors/interface/interface.c9
-rw-r--r--source/blender/editors/interface/interface_anim.c4
-rw-r--r--source/blender/editors/interface/interface_eyedropper_depth.c1
-rw-r--r--source/blender/editors/interface/interface_handlers.c36
-rw-r--r--source/blender/editors/interface/interface_icons.c2
-rw-r--r--source/blender/editors/interface/interface_intern.h2
-rw-r--r--source/blender/editors/interface/interface_layout.c28
-rw-r--r--source/blender/editors/interface/interface_ops.c2
-rw-r--r--source/blender/editors/interface/interface_panel.c37
-rw-r--r--source/blender/editors/interface/interface_region_menu_pie.c12
-rw-r--r--source/blender/editors/interface/interface_region_popover.c8
-rw-r--r--source/blender/editors/interface/interface_templates.c4
-rw-r--r--source/blender/editors/interface/interface_widgets.c21
-rw-r--r--source/blender/editors/interface/resources.c4
-rw-r--r--source/blender/editors/io/io_alembic.c8
-rw-r--r--source/blender/editors/io/io_cache.c2
-rw-r--r--source/blender/editors/io/io_collada.c15
-rw-r--r--source/blender/editors/mesh/editmesh_knife_project.c1
-rw-r--r--source/blender/editors/mesh/editmesh_tools.c3
-rw-r--r--source/blender/editors/mesh/mesh_ops.c18
-rw-r--r--source/blender/editors/mesh/meshtools.c1
-rw-r--r--source/blender/editors/object/object_add.c1
-rw-r--r--source/blender/editors/object/object_bake_api.c3
-rw-r--r--source/blender/editors/object/object_constraint.c17
-rw-r--r--source/blender/editors/object/object_data_transfer.c1
-rw-r--r--source/blender/editors/object/object_edit.c13
-rw-r--r--source/blender/editors/object/object_group.c2
-rw-r--r--source/blender/editors/object/object_hook.c9
-rw-r--r--source/blender/editors/object/object_modes.c2
-rw-r--r--source/blender/editors/object/object_modifier.c9
-rw-r--r--source/blender/editors/object/object_ops.c22
-rw-r--r--source/blender/editors/object/object_relations.c2
-rw-r--r--source/blender/editors/object/object_transform.c4
-rw-r--r--source/blender/editors/object/object_vgroup.c1
-rw-r--r--source/blender/editors/physics/particle_edit.c52
-rw-r--r--source/blender/editors/physics/particle_object.c1
-rw-r--r--source/blender/editors/render/render_opengl.c6
-rw-r--r--source/blender/editors/render/render_preview.c6
-rw-r--r--source/blender/editors/screen/area.c8
-rw-r--r--source/blender/editors/screen/screen_edit.c11
-rw-r--r--source/blender/editors/screen/screen_intern.h2
-rw-r--r--source/blender/editors/screen/screen_ops.c6
-rw-r--r--source/blender/editors/screen/screendump.c6
-rw-r--r--source/blender/editors/screen/workspace_edit.c8
-rw-r--r--source/blender/editors/screen/workspace_layout_edit.c6
-rw-r--r--source/blender/editors/sculpt_paint/paint_hide.c8
-rw-r--r--source/blender/editors/sculpt_paint/paint_image_proj.c1
-rw-r--r--source/blender/editors/sculpt_paint/paint_vertex.c19
-rw-r--r--source/blender/editors/sculpt_paint/paint_vertex_color_ops.c1
-rw-r--r--source/blender/editors/sculpt_paint/paint_vertex_proj.c1
-rw-r--r--source/blender/editors/sculpt_paint/paint_vertex_weight_ops.c1
-rw-r--r--source/blender/editors/sculpt_paint/sculpt.c30
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_undo.c9
-rw-r--r--source/blender/editors/sound/sound_ops.c2
-rw-r--r--source/blender/editors/space_action/action_edit.c6
-rw-r--r--source/blender/editors/space_action/action_ops.c4
-rw-r--r--source/blender/editors/space_action/space_action.c3
-rw-r--r--source/blender/editors/space_buttons/buttons_context.c3
-rw-r--r--source/blender/editors/space_buttons/buttons_ops.c5
-rw-r--r--source/blender/editors/space_buttons/space_buttons.c49
-rw-r--r--source/blender/editors/space_clip/clip_ops.c4
-rw-r--r--source/blender/editors/space_file/file_draw.c6
-rw-r--r--source/blender/editors/space_file/file_intern.h6
-rw-r--r--source/blender/editors/space_file/file_ops.c48
-rw-r--r--source/blender/editors/space_file/filelist.c9
-rw-r--r--source/blender/editors/space_file/filesel.c12
-rw-r--r--source/blender/editors/space_graph/graph_edit.c6
-rw-r--r--source/blender/editors/space_graph/graph_ops.c3
-rw-r--r--source/blender/editors/space_image/image_ops.c16
-rw-r--r--source/blender/editors/space_image/space_image.c3
-rw-r--r--source/blender/editors/space_info/info_ops.c4
-rw-r--r--source/blender/editors/space_node/node_ops.c2
-rw-r--r--source/blender/editors/space_node/node_relationships.c11
-rw-r--r--source/blender/editors/space_node/node_templates.c8
-rw-r--r--source/blender/editors/space_node/node_view.c11
-rw-r--r--source/blender/editors/space_outliner/outliner_draw.c8
-rw-r--r--source/blender/editors/space_outliner/outliner_select.c4
-rw-r--r--source/blender/editors/space_sequencer/sequencer_add.c4
-rw-r--r--source/blender/editors/space_sequencer/sequencer_edit.c6
-rw-r--r--source/blender/editors/space_text/text_ops.c8
-rw-r--r--source/blender/editors/space_view3d/drawobject.c1
-rw-r--r--source/blender/editors/space_view3d/space_view3d.c4
-rw-r--r--source/blender/editors/space_view3d/view3d_draw.c8
-rw-r--r--source/blender/editors/space_view3d/view3d_edit.c5
-rw-r--r--source/blender/editors/space_view3d/view3d_header.c27
-rw-r--r--source/blender/editors/space_view3d/view3d_intern.h4
-rw-r--r--source/blender/editors/space_view3d/view3d_iterators.c1
-rw-r--r--source/blender/editors/space_view3d/view3d_manipulator_armature.c5
-rw-r--r--source/blender/editors/space_view3d/view3d_manipulator_camera.c11
-rw-r--r--source/blender/editors/space_view3d/view3d_manipulator_empty.c5
-rw-r--r--source/blender/editors/space_view3d/view3d_manipulator_forcefield.c5
-rw-r--r--source/blender/editors/space_view3d/view3d_manipulator_lamp.c16
-rw-r--r--source/blender/editors/space_view3d/view3d_manipulator_navigate.c7
-rw-r--r--source/blender/editors/space_view3d/view3d_manipulator_ruler.c7
-rw-r--r--source/blender/editors/space_view3d/view3d_ops.c3
-rw-r--r--source/blender/editors/space_view3d/view3d_ruler.c6
-rw-r--r--source/blender/editors/space_view3d/view3d_select.c1
-rw-r--r--source/blender/editors/space_view3d/view3d_utils.c5
-rw-r--r--source/blender/editors/space_view3d/view3d_walk.c4
-rw-r--r--source/blender/editors/transform/transform.c12
-rw-r--r--source/blender/editors/transform/transform.h2
-rw-r--r--source/blender/editors/transform/transform_conversions.c183
-rw-r--r--source/blender/editors/transform/transform_generics.c6
-rw-r--r--source/blender/editors/transform/transform_manipulator_3d.c51
-rw-r--r--source/blender/editors/transform/transform_orientations.c12
-rw-r--r--source/blender/editors/transform/transform_snap.c8
-rw-r--r--source/blender/editors/transform/transform_snap_object.c9
-rw-r--r--source/blender/editors/util/ed_util.c4
-rw-r--r--source/blender/editors/uvedit/uvedit_draw.c2
-rw-r--r--source/blender/editors/uvedit/uvedit_ops.c2
-rw-r--r--source/blender/freestyle/intern/blender_interface/BlenderFileLoader.cpp2
-rw-r--r--source/blender/gpu/GPU_material.h19
-rw-r--r--source/blender/gpu/GPU_texture.h6
-rw-r--r--source/blender/gpu/GPU_uniformbuffer.h2
-rw-r--r--source/blender/gpu/intern/gpu_codegen.c199
-rw-r--r--source/blender/gpu/intern/gpu_codegen.h16
-rw-r--r--source/blender/gpu/intern/gpu_init_exit.c6
-rw-r--r--source/blender/gpu/intern/gpu_material.c176
-rw-r--r--source/blender/gpu/intern/gpu_texture.c8
-rw-r--r--source/blender/gpu/intern/gpu_uniformbuffer.c79
-rw-r--r--source/blender/ikplugin/CMakeLists.txt2
-rw-r--r--source/blender/ikplugin/intern/ikplugin_api.c2
-rw-r--r--source/blender/ikplugin/intern/itasc_plugin.cpp2
-rw-r--r--source/blender/makesdna/DNA_ID.h2
-rw-r--r--source/blender/makesdna/DNA_object_types.h22
-rw-r--r--source/blender/makesdna/DNA_space_types.h7
-rw-r--r--source/blender/makesdna/DNA_userdef_types.h1
-rw-r--r--source/blender/makesdna/DNA_view3d_types.h12
-rw-r--r--source/blender/makesrna/RNA_access.h1
-rw-r--r--source/blender/makesrna/RNA_define.h2
-rw-r--r--source/blender/makesrna/RNA_enum_types.h1
-rw-r--r--source/blender/makesrna/RNA_types.h32
-rw-r--r--source/blender/makesrna/intern/makesrna.c2
-rw-r--r--source/blender/makesrna/intern/rna_access.c11
-rw-r--r--source/blender/makesrna/intern/rna_animation.c9
-rw-r--r--source/blender/makesrna/intern/rna_armature.c10
-rw-r--r--source/blender/makesrna/intern/rna_color.c4
-rw-r--r--source/blender/makesrna/intern/rna_constraint.c4
-rw-r--r--source/blender/makesrna/intern/rna_define.c10
-rw-r--r--source/blender/makesrna/intern/rna_depsgraph.c23
-rw-r--r--source/blender/makesrna/intern/rna_fcurve.c8
-rw-r--r--source/blender/makesrna/intern/rna_group.c7
-rw-r--r--source/blender/makesrna/intern/rna_image.c28
-rw-r--r--source/blender/makesrna/intern/rna_image_api.c2
-rw-r--r--source/blender/makesrna/intern/rna_internal_types.h2
-rw-r--r--source/blender/makesrna/intern/rna_layer.c34
-rw-r--r--source/blender/makesrna/intern/rna_main_api.c2
-rw-r--r--source/blender/makesrna/intern/rna_modifier.c10
-rw-r--r--source/blender/makesrna/intern/rna_movieclip.c4
-rw-r--r--source/blender/makesrna/intern/rna_nla.c2
-rw-r--r--source/blender/makesrna/intern/rna_nodetree.c24
-rw-r--r--source/blender/makesrna/intern/rna_object.c41
-rw-r--r--source/blender/makesrna/intern/rna_particle.c8
-rw-r--r--source/blender/makesrna/intern/rna_pose.c18
-rw-r--r--source/blender/makesrna/intern/rna_rna.c33
-rw-r--r--source/blender/makesrna/intern/rna_scene.c106
-rw-r--r--source/blender/makesrna/intern/rna_scene_api.c8
-rw-r--r--source/blender/makesrna/intern/rna_sculpt_paint.c2
-rw-r--r--source/blender/makesrna/intern/rna_space.c275
-rw-r--r--source/blender/makesrna/intern/rna_ui.c14
-rw-r--r--source/blender/makesrna/intern/rna_userdef.c189
-rw-r--r--source/blender/makesrna/intern/rna_wm.c2
-rw-r--r--source/blender/modifiers/intern/MOD_collision.c1
-rw-r--r--source/blender/modifiers/intern/MOD_laplaciandeform.c2
-rw-r--r--source/blender/modifiers/intern/MOD_meshsequencecache.c55
-rw-r--r--source/blender/modifiers/intern/MOD_particleinstance.c12
-rw-r--r--source/blender/modifiers/intern/MOD_remesh.c1
-rw-r--r--source/blender/modifiers/intern/MOD_surfacedeform.c2
-rw-r--r--source/blender/nodes/composite/node_composite_tree.c36
-rw-r--r--source/blender/nodes/composite/node_composite_util.c2
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_bokehblur.c2
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_bokehimage.c2
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_boxmask.c2
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_brightness.c2
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_colorSpill.c2
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_colorbalance.c4
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_common.c4
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_dilate.c2
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_ellipsemask.c2
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_gamma.c4
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_huecorrect.c6
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_image.c20
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_inpaint.c2
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_math.c2
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_moviedistortion.c2
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_normalize.c4
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_outputFile.c34
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_splitViewer.c2
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_stabilize2d.c4
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_valToRgb.c4
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_viewer.c2
-rw-r--r--source/blender/nodes/intern/node_common.c100
-rw-r--r--source/blender/nodes/intern/node_exec.c62
-rw-r--r--source/blender/nodes/intern/node_exec.h6
-rw-r--r--source/blender/nodes/intern/node_socket.c84
-rw-r--r--source/blender/nodes/intern/node_util.c38
-rw-r--r--source/blender/nodes/shader/node_shader_tree.c52
-rw-r--r--source/blender/nodes/shader/node_shader_util.c20
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_brightness.c4
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_bump.c2
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_common.c42
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_curves.c4
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_fresnel.c2
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_gamma.c4
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_geom.c163
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_hueSatVal.c2
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_invert.c8
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_mapping.c6
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_material.c374
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_math.c12
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_mixRgb.c2
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_normal.c10
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_output.c97
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_output_world.c2
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_sepcombHSV.c4
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_sepcombRGB.c4
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_squeeze.c4
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_tex_brick.c2
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_tex_coord.c4
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_tex_environment.c6
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_texture.c166
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_valToRgb.c2
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_vectMath.c24
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_vectTransform.c8
-rw-r--r--source/blender/nodes/texture/node_texture_tree.c56
-rw-r--r--source/blender/nodes/texture/node_texture_util.c16
-rw-r--r--source/blender/nodes/texture/nodes/node_texture_at.c6
-rw-r--r--source/blender/nodes/texture/nodes/node_texture_bricks.c26
-rw-r--r--source/blender/nodes/texture/nodes/node_texture_checker.c8
-rw-r--r--source/blender/nodes/texture/nodes/node_texture_common.c28
-rw-r--r--source/blender/nodes/texture/nodes/node_texture_compose.c6
-rw-r--r--source/blender/nodes/texture/nodes/node_texture_coord.c4
-rw-r--r--source/blender/nodes/texture/nodes/node_texture_curves.c14
-rw-r--r--source/blender/nodes/texture/nodes/node_texture_decompose.c6
-rw-r--r--source/blender/nodes/texture/nodes/node_texture_distance.c4
-rw-r--r--source/blender/nodes/texture/nodes/node_texture_hueSatVal.c16
-rw-r--r--source/blender/nodes/texture/nodes/node_texture_image.c16
-rw-r--r--source/blender/nodes/texture/nodes/node_texture_invert.c10
-rw-r--r--source/blender/nodes/texture/nodes/node_texture_mixRgb.c10
-rw-r--r--source/blender/nodes/texture/nodes/node_texture_output.c26
-rw-r--r--source/blender/nodes/texture/nodes/node_texture_proc.c38
-rw-r--r--source/blender/nodes/texture/nodes/node_texture_rotate.c20
-rw-r--r--source/blender/nodes/texture/nodes/node_texture_scale.c10
-rw-r--r--source/blender/nodes/texture/nodes/node_texture_texture.c14
-rw-r--r--source/blender/nodes/texture/nodes/node_texture_translate.c12
-rw-r--r--source/blender/nodes/texture/nodes/node_texture_valToNor.c10
-rw-r--r--source/blender/nodes/texture/nodes/node_texture_valToRgb.c10
-rw-r--r--source/blender/nodes/texture/nodes/node_texture_viewer.c6
-rw-r--r--source/blender/physics/intern/BPH_mass_spring.cpp334
-rw-r--r--source/blender/physics/intern/ConstrainedConjugateGradient.h34
-rw-r--r--source/blender/physics/intern/eigen_utils.h42
-rw-r--r--source/blender/physics/intern/hair_volume.cpp264
-rw-r--r--source/blender/physics/intern/implicit.h2
-rw-r--r--source/blender/physics/intern/implicit_blender.c436
-rw-r--r--source/blender/physics/intern/implicit_eigen.cpp326
-rw-r--r--source/blender/python/generic/CMakeLists.txt2
-rw-r--r--source/blender/python/generic/imbuf_py_api.c447
-rw-r--r--source/blender/python/generic/imbuf_py_api.h30
-rw-r--r--source/blender/python/intern/bpy_interface.c4
-rw-r--r--source/blender/python/intern/bpy_library_load.c2
-rw-r--r--source/blender/python/intern/bpy_library_write.c2
-rw-r--r--source/blender/python/intern/bpy_rna_anim.c7
-rw-r--r--source/blender/python/intern/gpu_offscreen.c2
-rw-r--r--source/blender/render/CMakeLists.txt2
-rw-r--r--source/blender/render/extern/include/RE_pipeline.h20
-rw-r--r--source/blender/render/intern/include/envmap.h54
-rw-r--r--source/blender/render/intern/include/initrender.h2
-rw-r--r--source/blender/render/intern/include/pixelblending.h65
-rw-r--r--source/blender/render/intern/include/pixelshading.h62
-rw-r--r--source/blender/render/intern/include/pointdensity.h51
-rw-r--r--source/blender/render/intern/include/raycounter.h74
-rw-r--r--source/blender/render/intern/include/rayintersection.h136
-rw-r--r--source/blender/render/intern/include/render_types.h34
-rw-r--r--source/blender/render/intern/include/rendercore.h105
-rw-r--r--source/blender/render/intern/include/shading.h105
-rw-r--r--source/blender/render/intern/include/strand.h99
-rw-r--r--source/blender/render/intern/include/sunsky.h81
-rw-r--r--source/blender/render/intern/include/texture_ocean.h35
-rw-r--r--source/blender/render/intern/include/voxeldata.h47
-rw-r--r--source/blender/render/intern/include/zbuf.h2
-rw-r--r--source/blender/render/intern/raytrace/bvh.h407
-rw-r--r--source/blender/render/intern/raytrace/rayobject.cpp534
-rw-r--r--source/blender/render/intern/raytrace/rayobject_hint.h72
-rw-r--r--source/blender/render/intern/raytrace/rayobject_instance.cpp211
-rw-r--r--source/blender/render/intern/raytrace/rayobject_octree.cpp1101
-rw-r--r--source/blender/render/intern/raytrace/rayobject_qbvh.cpp160
-rw-r--r--source/blender/render/intern/raytrace/rayobject_raycounter.cpp91
-rw-r--r--source/blender/render/intern/raytrace/rayobject_rtbuild.cpp531
-rw-r--r--source/blender/render/intern/raytrace/rayobject_rtbuild.h125
-rw-r--r--source/blender/render/intern/raytrace/rayobject_svbvh.cpp192
-rw-r--r--source/blender/render/intern/raytrace/rayobject_vbvh.cpp206
-rw-r--r--source/blender/render/intern/raytrace/reorganize.h513
-rw-r--r--source/blender/render/intern/raytrace/svbvh.h317
-rw-r--r--source/blender/render/intern/raytrace/vbvh.h238
-rw-r--r--source/blender/render/intern/source/bake.c1342
-rw-r--r--source/blender/render/intern/source/convertblender.c6014
-rw-r--r--source/blender/render/intern/source/envmap.c822
-rw-r--r--source/blender/render/intern/source/external_engine.c10
-rw-r--r--source/blender/render/intern/source/imagetexture.c132
-rw-r--r--source/blender/render/intern/source/initrender.c46
-rw-r--r--source/blender/render/intern/source/occlusion.c1533
-rw-r--r--source/blender/render/intern/source/pipeline.c188
-rw-r--r--source/blender/render/intern/source/pixelblending.c400
-rw-r--r--source/blender/render/intern/source/pixelshading.c650
-rw-r--r--source/blender/render/intern/source/pointdensity.c44
-rw-r--r--source/blender/render/intern/source/rayshade.c2503
-rw-r--r--source/blender/render/intern/source/render_result.c85
-rw-r--r--source/blender/render/intern/source/render_texture.c192
-rw-r--r--source/blender/render/intern/source/rendercore.c2030
-rw-r--r--source/blender/render/intern/source/renderdatabase.c1603
-rw-r--r--source/blender/render/intern/source/shadbuf.c2647
-rw-r--r--source/blender/render/intern/source/shadeinput.c1490
-rw-r--r--source/blender/render/intern/source/shadeoutput.c2182
-rw-r--r--source/blender/render/intern/source/sss.c1074
-rw-r--r--source/blender/render/intern/source/strand.c1069
-rw-r--r--source/blender/render/intern/source/sunsky.c506
-rw-r--r--source/blender/render/intern/source/volume_precache.c855
-rw-r--r--source/blender/render/intern/source/volumetric.c836
-rw-r--r--source/blender/render/intern/source/voxeldata.c571
-rw-r--r--source/blender/render/intern/source/zbuf.c52
-rw-r--r--source/blender/windowmanager/WM_api.h2
-rw-r--r--source/blender/windowmanager/WM_keymap.h6
-rw-r--r--source/blender/windowmanager/WM_types.h38
-rw-r--r--source/blender/windowmanager/intern/wm.c31
-rw-r--r--source/blender/windowmanager/intern/wm_cursors.c58
-rw-r--r--source/blender/windowmanager/intern/wm_dragdrop.c66
-rw-r--r--source/blender/windowmanager/intern/wm_draw.c10
-rw-r--r--source/blender/windowmanager/intern/wm_event_system.c438
-rw-r--r--source/blender/windowmanager/intern/wm_files.c131
-rw-r--r--source/blender/windowmanager/intern/wm_files_link.c12
-rw-r--r--source/blender/windowmanager/intern/wm_gesture.c20
-rw-r--r--source/blender/windowmanager/intern/wm_init_exit.c46
-rw-r--r--source/blender/windowmanager/intern/wm_jobs.c108
-rw-r--r--source/blender/windowmanager/intern/wm_keymap.c72
-rw-r--r--source/blender/windowmanager/intern/wm_operators.c168
-rw-r--r--source/blender/windowmanager/intern/wm_playanim.c34
-rw-r--r--source/blender/windowmanager/intern/wm_window.c256
-rw-r--r--source/blender/windowmanager/wm.h4
-rw-r--r--source/blender/windowmanager/wm_cursors.h36
-rw-r--r--source/blender/windowmanager/wm_event_types.h2
m---------source/tools0
-rw-r--r--tests/gtests/alembic/abc_export_test.cc10
-rw-r--r--tests/gtests/blenlib/BLI_heap_test.cc2
-rw-r--r--tests/python/bl_pyapi_mathutils.py2
-rw-r--r--tests/python/collada/animation/test_animation_simple.py236
-rw-r--r--tests/python/collada/mesh/test_mesh_simple.py6
-rwxr-xr-xtests/python/ffmpeg_tests.py2
-rwxr-xr-xtests/python/modules/test_utils.py2
-rw-r--r--tests/python/rna_array.py16
-rw-r--r--tests/python/view_layer/CMakeLists.txt4
732 files changed, 47740 insertions, 7564 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 43820159456..69d0abe1e25 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -817,18 +817,20 @@ set(PLATFORM_LINKLIBS "")
set(PLATFORM_LINKFLAGS "")
set(PLATFORM_LINKFLAGS_DEBUG "")
-if(WITH_COMPILER_ASAN)
- set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} ${COMPILER_ASAN_CFLAGS}")
- set(CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_RELWITHDEBINFO} ${COMPILER_ASAN_CFLAGS}")
-
- set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} ${COMPILER_ASAN_CXXFLAGS}")
- set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} ${COMPILER_ASAN_CXXFLAGS}")
- if(MSVC)
- set(COMPILER_ASAN_LINKER_FLAGS "/FUNCTIONPADMIN:6")
+if (NOT CMAKE_BUILD_TYPE MATCHES "Release")
+ if(WITH_COMPILER_ASAN)
+ set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} ${COMPILER_ASAN_CFLAGS}")
+ set(CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_RELWITHDEBINFO} ${COMPILER_ASAN_CFLAGS}")
+
+ set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} ${COMPILER_ASAN_CXXFLAGS}")
+ set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} ${COMPILER_ASAN_CXXFLAGS}")
+ if(MSVC)
+ set(COMPILER_ASAN_LINKER_FLAGS "/FUNCTIONPADMIN:6")
+ endif()
+ set(PLATFORM_LINKLIBS "${PLATFORM_LINKLIBS};${COMPILER_ASAN_LIBRARY}")
+ set(PLATFORM_LINKFLAGS "${COMPILER_ASAN_LIBRARY} ${COMPILER_ASAN_LINKER_FLAGS}")
+ set(PLATFORM_LINKFLAGS_DEBUG "${COMPILER_ASAN_LIBRARY} ${COMPILER_ASAN_LINKER_FLAGS}")
endif()
- set(PLATFORM_LINKLIBS "${PLATFORM_LINKLIBS};${COMPILER_ASAN_LIBRARY}")
- set(PLATFORM_LINKFLAGS "${COMPILER_ASAN_LIBRARY} ${COMPILER_ASAN_LINKER_FLAGS}")
- set(PLATFORM_LINKFLAGS_DEBUG "${COMPILER_ASAN_LIBRARY} ${COMPILER_ASAN_LINKER_FLAGS}")
endif()
#-----------------------------------------------------------------------------
diff --git a/build_files/cmake/platform/platform_win32.cmake b/build_files/cmake/platform/platform_win32.cmake
index f55178b89e2..0ee0845be33 100644
--- a/build_files/cmake/platform/platform_win32.cmake
+++ b/build_files/cmake/platform/platform_win32.cmake
@@ -31,7 +31,8 @@ endif()
if(CMAKE_C_COMPILER_ID MATCHES "Clang")
set(MSVC_CLANG On)
- set(MSVC_REDIST_DIR $ENV{VCToolsRedistDir})
+ set(VC_TOOLS_DIR $ENV{VCToolsRedistDir} CACHE STRING "Location of the msvc redistributables")
+ set(MSVC_REDIST_DIR ${VC_TOOLS_DIR})
if (DEFINED MSVC_REDIST_DIR)
file(TO_CMAKE_PATH ${MSVC_REDIST_DIR} MSVC_REDIST_DIR)
else()
diff --git a/build_files/windows/configure_msbuild.cmd b/build_files/windows/configure_msbuild.cmd
index eee21f568be..f8c2a87de8e 100644
--- a/build_files/windows/configure_msbuild.cmd
+++ b/build_files/windows/configure_msbuild.cmd
@@ -1,5 +1,3 @@
-set BUILD_CMAKE_ARGS=%BUILD_CMAKE_ARGS% -G "Visual Studio %BUILD_VS_VER% %BUILD_VS_YEAR%%WINDOWS_ARCH%" %TESTS_CMAKE_ARGS%
-
if "%BUILD_ARCH%"=="x64" (
set MSBUILD_PLATFORM=x64
) else if "%BUILD_ARCH%"=="x86" (
@@ -11,9 +9,9 @@ if "%BUILD_ARCH%"=="x64" (
)
if "%WITH_CLANG%"=="1" (
- set BUILD_CMAKE_ARGS=%BUILD_CMAKE_ARGS% -T"LLVM-vs2017"
+ set CLANG_CMAKE_ARGS=-T"LLVM-vs2017"
if "%WITH_ASAN%"=="1" (
- set BUILD_CMAKE_ARGS=%BUILD_CMAKE_ARGS% -DWITH_COMPILER_ASAN=On
+ set ASAN_CMAKE_ARGS=-DWITH_COMPILER_ASAN=On
)
) else (
if "%WITH_ASAN%"=="1" (
@@ -21,6 +19,7 @@ if "%WITH_CLANG%"=="1" (
exit /b 1
)
)
+set BUILD_CMAKE_ARGS=%BUILD_CMAKE_ARGS% -G "Visual Studio %BUILD_VS_VER% %BUILD_VS_YEAR%%WINDOWS_ARCH%" %TESTS_CMAKE_ARGS% %CLANG_CMAKE_ARGS% %ASAN_CMAKE_ARGS%
if NOT EXIST %BUILD_DIR%\nul (
mkdir %BUILD_DIR%
diff --git a/build_files/windows/configure_ninja.cmd b/build_files/windows/configure_ninja.cmd
index d3b002e9a24..224d761adf6 100644
--- a/build_files/windows/configure_ninja.cmd
+++ b/build_files/windows/configure_ninja.cmd
@@ -1,3 +1,9 @@
+ninja --version 1>NUL 2>&1
+if %ERRORLEVEL% NEQ 0 (
+ echo "Ninja not detected in the path"
+ exit /b 1
+ )
+
set BUILD_CMAKE_ARGS=%BUILD_CMAKE_ARGS% -G "Ninja" %TESTS_CMAKE_ARGS% -DCMAKE_BUILD_TYPE=%BUILD_TYPE%
if "%WITH_CLANG%" == "1" (
diff --git a/build_files/windows/detect_msvc2017.cmd b/build_files/windows/detect_msvc2017.cmd
index 90fad8744b5..060e9f88617 100644
--- a/build_files/windows/detect_msvc2017.cmd
+++ b/build_files/windows/detect_msvc2017.cmd
@@ -12,7 +12,12 @@ if not exist "%vs_where%" (
goto FAIL
)
)
-for /f "usebackq tokens=1* delims=: " %%i in (`"%vs_where%" -products * -latest %VSWHERE_ARGS% -requires Microsoft.VisualStudio.Component.VC.Tools.x86.x64`) do (
+
+if NOT "%verbose%" == "" (
+ echo "%vs_where%" -latest %VSWHERE_ARGS% -requires Microsoft.VisualStudio.Component.VC.Tools.x86.x64`
+ )
+
+for /f "usebackq tokens=1* delims=: " %%i in (`"%vs_where%" -latest %VSWHERE_ARGS% -requires Microsoft.VisualStudio.Component.VC.Tools.x86.x64`) do (
if /i "%%i"=="installationPath" set VS_InstallDir=%%j
)
diff --git a/build_files/windows/parse_arguments.cmd b/build_files/windows/parse_arguments.cmd
index 2cc0acfd243..8a6d743978d 100644
--- a/build_files/windows/parse_arguments.cmd
+++ b/build_files/windows/parse_arguments.cmd
@@ -53,6 +53,10 @@ if NOT "%1" == "" (
) else if "%1" == "2017pre" (
set BUILD_VS_YEAR=2017
set VSWHERE_ARGS=-prerelease
+ set BUILD_VS_YEAR=2017
+ ) else if "%1" == "2017b" (
+ set BUILD_VS_YEAR=2017
+ set VSWHERE_ARGS=-products Microsoft.VisualStudio.Product.BuildTools
) else if "%1" == "2015" (
set BUILD_VS_YEAR=2015
) else if "%1" == "2013" (
diff --git a/build_files/windows/reset_variables.cmd b/build_files/windows/reset_variables.cmd
index f933729b91c..a522ed7407f 100644
--- a/build_files/windows/reset_variables.cmd
+++ b/build_files/windows/reset_variables.cmd
@@ -22,4 +22,6 @@ set BUILD_SHOW_HASHES=
set SHOW_HELP=
set BUILD_WITH_NINJA=
set WITH_CLANG=
-set WITH_ASAN= \ No newline at end of file
+set WITH_ASAN=
+set CLANG_CMAKE_ARGS=
+set ASAN_CMAKE_ARGS=
diff --git a/build_files/windows/show_help.cmd b/build_files/windows/show_help.cmd
index 0524e8a84fc..2b297120f4b 100644
--- a/build_files/windows/show_help.cmd
+++ b/build_files/windows/show_help.cmd
@@ -23,7 +23,13 @@ echo - buildir [newdir] ^(override default build folder^)
echo - x86 ^(override host auto-detect and build 32 bit code^)
echo - x64 ^(override host auto-detect and build 64 bit code^)
echo - 2013 ^(build with visual studio 2013^)
-echo - 2015 ^(build with visual studio 2015^) [EXPERIMENTAL]
-echo - 2017 ^(build with visual studio 2017^) [EXPERIMENTAL]
-echo - 2017pre ^(build with visual studio 2017 pre-release^) [EXPERIMENTAL]
+echo.
+echo Experimental options
+echo - 2015 ^(build with visual studio 2015^)
+echo - 2017 ^(build with visual studio 2017^)
+echo - 2017pre ^(build with visual studio 2017 pre-release^)
+echo - 2017b ^(build with visual studio 2017 Build Tools^)
+echo - clang ^(enable building with clang^)
+echo - asan ^(enable asan when building with clang^)
+echo - ninja ^(enable building with ninja instead of msbuild^)
echo.
diff --git a/extern/audaspace/plugins/ffmpeg/FFMPEG.cpp b/extern/audaspace/plugins/ffmpeg/FFMPEG.cpp
index 7f9b762f816..3ffe963b2b9 100644
--- a/extern/audaspace/plugins/ffmpeg/FFMPEG.cpp
+++ b/extern/audaspace/plugins/ffmpeg/FFMPEG.cpp
@@ -23,7 +23,9 @@ AUD_NAMESPACE_BEGIN
FFMPEG::FFMPEG()
{
+#if LIBAVCODEC_VERSION_MAJOR < 58
av_register_all();
+#endif
}
void FFMPEG::registerPlugin()
diff --git a/extern/audaspace/plugins/ffmpeg/FFMPEGReader.cpp b/extern/audaspace/plugins/ffmpeg/FFMPEGReader.cpp
index 6b79cc5abfd..2da84ce0d4c 100644
--- a/extern/audaspace/plugins/ffmpeg/FFMPEGReader.cpp
+++ b/extern/audaspace/plugins/ffmpeg/FFMPEGReader.cpp
@@ -22,37 +22,37 @@
extern "C" {
#include <libavcodec/avcodec.h>
#include <libavformat/avio.h>
+#include <libavutil/avutil.h>
}
AUD_NAMESPACE_BEGIN
+#if LIBAVCODEC_VERSION_MAJOR < 58
+#define FFMPEG_OLD_CODE
+#endif
+
int FFMPEGReader::decode(AVPacket& packet, Buffer& buffer)
{
- AVFrame* frame = nullptr;
+ int buf_size = buffer.getSize();
+ int buf_pos = 0;
+
+#ifdef FFMPEG_OLD_CODE
int got_frame;
int read_length;
uint8_t* orig_data = packet.data;
int orig_size = packet.size;
- int buf_size = buffer.getSize();
- int buf_pos = 0;
-
while(packet.size > 0)
{
got_frame = 0;
- if(!frame)
- frame = av_frame_alloc();
- else
- av_frame_unref(frame);
-
- read_length = avcodec_decode_audio4(m_codecCtx, frame, &got_frame, &packet);
+ read_length = avcodec_decode_audio4(m_codecCtx, m_frame, &got_frame, &packet);
if(read_length < 0)
break;
if(got_frame)
{
- int data_size = av_samples_get_buffer_size(nullptr, m_codecCtx->channels, frame->nb_samples, m_codecCtx->sample_fmt, 1);
+ int data_size = av_samples_get_buffer_size(nullptr, m_codecCtx->channels, m_frame->nb_samples, m_codecCtx->sample_fmt, 1);
if(buf_size - buf_pos < data_size)
{
@@ -62,18 +62,18 @@ int FFMPEGReader::decode(AVPacket& packet, Buffer& buffer)
if(m_tointerleave)
{
- int single_size = data_size / m_codecCtx->channels / frame->nb_samples;
+ int single_size = data_size / m_codecCtx->channels / m_frame->nb_samples;
for(int channel = 0; channel < m_codecCtx->channels; channel++)
{
- for(int i = 0; i < frame->nb_samples; i++)
+ for(int i = 0; i < m_frame->nb_samples; i++)
{
std::memcpy(((data_t*)buffer.getBuffer()) + buf_pos + ((m_codecCtx->channels * i) + channel) * single_size,
- frame->data[channel] + i * single_size, single_size);
+ m_frame->data[channel] + i * single_size, single_size);
}
}
}
else
- std::memcpy(((data_t*)buffer.getBuffer()) + buf_pos, frame->data[0], data_size);
+ std::memcpy(((data_t*)buffer.getBuffer()) + buf_pos, m_frame->data[0], data_size);
buf_pos += data_size;
}
@@ -83,7 +83,42 @@ int FFMPEGReader::decode(AVPacket& packet, Buffer& buffer)
packet.data = orig_data;
packet.size = orig_size;
- av_free(frame);
+#else
+ avcodec_send_packet(m_codecCtx, &packet);
+
+ while(true)
+ {
+ auto ret = avcodec_receive_frame(m_codecCtx, m_frame);
+
+ if(ret != 0)
+ break;
+
+ int data_size = av_samples_get_buffer_size(nullptr, m_codecCtx->channels, m_frame->nb_samples, m_codecCtx->sample_fmt, 1);
+
+ if(buf_size - buf_pos < data_size)
+ {
+ buffer.resize(buf_size + data_size, true);
+ buf_size += data_size;
+ }
+
+ if(m_tointerleave)
+ {
+ int single_size = data_size / m_codecCtx->channels / m_frame->nb_samples;
+ for(int channel = 0; channel < m_codecCtx->channels; channel++)
+ {
+ for(int i = 0; i < m_frame->nb_samples; i++)
+ {
+ std::memcpy(((data_t*)buffer.getBuffer()) + buf_pos + ((m_codecCtx->channels * i) + channel) * single_size,
+ m_frame->data[channel] + i * single_size, single_size);
+ }
+ }
+ }
+ else
+ std::memcpy(((data_t*)buffer.getBuffer()) + buf_pos, m_frame->data[0], data_size);
+
+ buf_pos += data_size;
+ }
+#endif
return buf_pos;
}
@@ -101,7 +136,11 @@ void FFMPEGReader::init()
for(unsigned int i = 0; i < m_formatCtx->nb_streams; i++)
{
+#ifdef FFMPEG_OLD_CODE
if((m_formatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_AUDIO)
+#else
+ if((m_formatCtx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO)
+#endif
&& (m_stream < 0))
{
m_stream=i;
@@ -112,12 +151,34 @@ void FFMPEGReader::init()
if(m_stream == -1)
AUD_THROW(FileException, "File couldn't be read, no audio stream found by ffmpeg.");
- m_codecCtx = m_formatCtx->streams[m_stream]->codec;
-
// get a decoder and open it
- AVCodec* aCodec = avcodec_find_decoder(m_codecCtx->codec_id);
+#ifndef FFMPEG_OLD_CODE
+ AVCodec* aCodec = avcodec_find_decoder(m_formatCtx->streams[m_stream]->codecpar->codec_id);
+
if(!aCodec)
AUD_THROW(FileException, "File couldn't be read, no decoder found with ffmpeg.");
+#endif
+
+ m_frame = av_frame_alloc();
+
+ if(!m_frame)
+ AUD_THROW(FileException, "File couldn't be read, ffmpeg frame couldn't be allocated.");
+
+#ifdef FFMPEG_OLD_CODE
+ m_codecCtx = m_formatCtx->streams[m_stream]->codec;
+
+ AVCodec* aCodec = avcodec_find_decoder(m_codecCtx->codec_id);
+#else
+ m_codecCtx = avcodec_alloc_context3(aCodec);
+#endif
+
+ if(!m_codecCtx)
+ AUD_THROW(FileException, "File couldn't be read, ffmpeg context couldn't be allocated.");
+
+#ifndef FFMPEG_OLD_CODE
+ if(avcodec_parameters_to_context(m_codecCtx, m_formatCtx->streams[m_stream]->codecpar) < 0)
+ AUD_THROW(FileException, "File couldn't be read, ffmpeg decoder parameters couldn't be copied to decoder context.");
+#endif
if(avcodec_open2(m_codecCtx, aCodec, nullptr) < 0)
AUD_THROW(FileException, "File couldn't be read, ffmpeg codec couldn't be opened.");
@@ -157,6 +218,8 @@ void FFMPEGReader::init()
FFMPEGReader::FFMPEGReader(std::string filename) :
m_pkgbuf(),
m_formatCtx(nullptr),
+ m_codecCtx(nullptr),
+ m_frame(nullptr),
m_aviocontext(nullptr),
m_membuf(nullptr)
{
@@ -177,12 +240,14 @@ FFMPEGReader::FFMPEGReader(std::string filename) :
FFMPEGReader::FFMPEGReader(std::shared_ptr<Buffer> buffer) :
m_pkgbuf(),
+ m_codecCtx(nullptr),
+ m_frame(nullptr),
m_membuffer(buffer),
m_membufferpos(0)
{
- m_membuf = reinterpret_cast<data_t*>(av_malloc(FF_MIN_BUFFER_SIZE + FF_INPUT_BUFFER_PADDING_SIZE));
+ m_membuf = reinterpret_cast<data_t*>(av_malloc(AV_INPUT_BUFFER_MIN_SIZE + AV_INPUT_BUFFER_PADDING_SIZE));
- m_aviocontext = avio_alloc_context(m_membuf, FF_MIN_BUFFER_SIZE, 0, this, read_packet, nullptr, seek_packet);
+ m_aviocontext = avio_alloc_context(m_membuf, AV_INPUT_BUFFER_MIN_SIZE, 0, this, read_packet, nullptr, seek_packet);
if(!m_aviocontext)
{
@@ -212,7 +277,14 @@ FFMPEGReader::FFMPEGReader(std::shared_ptr<Buffer> buffer) :
FFMPEGReader::~FFMPEGReader()
{
+ if(m_frame)
+ av_frame_free(&m_frame);
+#ifdef FFMPEG_OLD_CODE
avcodec_close(m_codecCtx);
+#else
+ if(m_codecCtx)
+ avcodec_free_context(&m_codecCtx);
+#endif
avformat_close_input(&m_formatCtx);
}
@@ -312,7 +384,7 @@ void FFMPEGReader::seek(int position)
}
}
}
- av_free_packet(&packet);
+ av_packet_unref(&packet);
}
}
else
@@ -343,7 +415,7 @@ Specs FFMPEGReader::getSpecs() const
void FFMPEGReader::read(int& length, bool& eos, sample_t* buffer)
{
// read packages and decode them
- AVPacket packet;
+ AVPacket packet = {};
int data_size = 0;
int pkgbuf_pos;
int left = length;
@@ -359,7 +431,7 @@ void FFMPEGReader::read(int& length, bool& eos, sample_t* buffer)
data_size = std::min(pkgbuf_pos, left * sample_size);
m_convert((data_t*) buf, (data_t*) m_pkgbuf.getBuffer(), data_size / AUD_FORMAT_SIZE(m_specs.format));
buf += data_size / AUD_FORMAT_SIZE(m_specs.format);
- left -= data_size/sample_size;
+ left -= data_size / sample_size;
}
// for each frame read as long as there isn't enough data already
@@ -375,9 +447,9 @@ void FFMPEGReader::read(int& length, bool& eos, sample_t* buffer)
data_size = std::min(pkgbuf_pos, left * sample_size);
m_convert((data_t*) buf, (data_t*) m_pkgbuf.getBuffer(), data_size / AUD_FORMAT_SIZE(m_specs.format));
buf += data_size / AUD_FORMAT_SIZE(m_specs.format);
- left -= data_size/sample_size;
+ left -= data_size / sample_size;
}
- av_free_packet(&packet);
+ av_packet_unref(&packet);
}
// read more data than necessary?
if(pkgbuf_pos > data_size)
diff --git a/extern/audaspace/plugins/ffmpeg/FFMPEGReader.h b/extern/audaspace/plugins/ffmpeg/FFMPEGReader.h
index e2ae959912d..a69ac7709c8 100644
--- a/extern/audaspace/plugins/ffmpeg/FFMPEGReader.h
+++ b/extern/audaspace/plugins/ffmpeg/FFMPEGReader.h
@@ -80,6 +80,11 @@ private:
AVCodecContext* m_codecCtx;
/**
+ * The AVFrame structure for using ffmpeg.
+ */
+ AVFrame* m_frame;
+
+ /**
* The AVIOContext to read the data from.
*/
AVIOContext* m_aviocontext;
diff --git a/extern/audaspace/plugins/ffmpeg/FFMPEGWriter.cpp b/extern/audaspace/plugins/ffmpeg/FFMPEGWriter.cpp
index f79f0f7fc6b..09b70897c31 100644
--- a/extern/audaspace/plugins/ffmpeg/FFMPEGWriter.cpp
+++ b/extern/audaspace/plugins/ffmpeg/FFMPEGWriter.cpp
@@ -27,6 +27,10 @@ extern "C" {
AUD_NAMESPACE_BEGIN
+#if LIBAVCODEC_VERSION_MAJOR < 58
+#define FFMPEG_OLD_CODE
+#endif
+
void FFMPEGWriter::encode()
{
sample_t* data = m_input_buffer.getBuffer();
@@ -58,82 +62,106 @@ void FFMPEGWriter::encode()
if(m_input_size)
m_convert(reinterpret_cast<data_t*>(data), reinterpret_cast<data_t*>(data), m_input_samples * m_specs.channels);
- AVPacket packet;
-
- packet.data = nullptr;
- packet.size = 0;
+#ifdef FFMPEG_OLD_CODE
+ m_packet->data = nullptr;
+ m_packet->size = 0;
- av_init_packet(&packet);
+ av_init_packet(m_packet);
- AVFrame* frame = av_frame_alloc();
- av_frame_unref(frame);
+ av_frame_unref(m_frame);
int got_packet;
+#endif
- frame->nb_samples = m_input_samples;
- frame->format = m_codecCtx->sample_fmt;
- frame->channel_layout = m_codecCtx->channel_layout;
+ m_frame->nb_samples = m_input_samples;
+ m_frame->format = m_codecCtx->sample_fmt;
+ m_frame->channel_layout = m_codecCtx->channel_layout;
- if(avcodec_fill_audio_frame(frame, m_specs.channels, m_codecCtx->sample_fmt, reinterpret_cast<data_t*>(data), m_input_buffer.getSize(), 0) < 0)
+ if(avcodec_fill_audio_frame(m_frame, m_specs.channels, m_codecCtx->sample_fmt, reinterpret_cast<data_t*>(data), m_input_buffer.getSize(), 0) < 0)
AUD_THROW(FileException, "File couldn't be written, filling the audio frame failed with ffmpeg.");
AVRational sample_time = { 1, static_cast<int>(m_specs.rate) };
- frame->pts = av_rescale_q(m_position - m_input_samples, m_codecCtx->time_base, sample_time);
+ m_frame->pts = av_rescale_q(m_position - m_input_samples, m_codecCtx->time_base, sample_time);
- if(avcodec_encode_audio2(m_codecCtx, &packet, frame, &got_packet))
+#ifdef FFMPEG_OLD_CODE
+ if(avcodec_encode_audio2(m_codecCtx, m_packet, m_frame, &got_packet))
{
- av_frame_free(&frame);
AUD_THROW(FileException, "File couldn't be written, audio encoding failed with ffmpeg.");
}
if(got_packet)
{
- packet.flags |= AV_PKT_FLAG_KEY;
- packet.stream_index = m_stream->index;
- if(av_write_frame(m_formatCtx, &packet) < 0)
+ m_packet->flags |= AV_PKT_FLAG_KEY;
+ m_packet->stream_index = m_stream->index;
+ if(av_write_frame(m_formatCtx, m_packet) < 0)
{
- av_free_packet(&packet);
- av_frame_free(&frame);
+ av_free_packet(m_packet);
AUD_THROW(FileException, "Frame couldn't be writen to the file with ffmpeg.");
}
- av_free_packet(&packet);
+ av_free_packet(m_packet);
}
+#else
+ if(avcodec_send_frame(m_codecCtx, m_frame) < 0)
+ AUD_THROW(FileException, "File couldn't be written, audio encoding failed with ffmpeg.");
+
+ while(avcodec_receive_packet(m_codecCtx, m_packet) == 0)
+ {
+ m_packet->stream_index = m_stream->index;
- av_frame_free(&frame);
+ if(av_write_frame(m_formatCtx, m_packet) < 0)
+ AUD_THROW(FileException, "Frame couldn't be writen to the file with ffmpeg.");
+ }
+#endif
}
void FFMPEGWriter::close()
{
+#ifdef FFMPEG_OLD_CODE
int got_packet = true;
while(got_packet)
{
- AVPacket packet;
+ m_packet->data = nullptr;
+ m_packet->size = 0;
- packet.data = nullptr;
- packet.size = 0;
+ av_init_packet(m_packet);
- av_init_packet(&packet);
-
- if(avcodec_encode_audio2(m_codecCtx, &packet, nullptr, &got_packet))
+ if(avcodec_encode_audio2(m_codecCtx, m_packet, nullptr, &got_packet))
AUD_THROW(FileException, "File end couldn't be written, audio encoding failed with ffmpeg.");
if(got_packet)
{
- packet.flags |= AV_PKT_FLAG_KEY;
- packet.stream_index = m_stream->index;
- if(av_write_frame(m_formatCtx, &packet))
+ m_packet->flags |= AV_PKT_FLAG_KEY;
+ m_packet->stream_index = m_stream->index;
+ if(av_write_frame(m_formatCtx, m_packet))
{
- av_free_packet(&packet);
+ av_free_packet(m_packet);
AUD_THROW(FileException, "Final frames couldn't be writen to the file with ffmpeg.");
}
- av_free_packet(&packet);
+ av_free_packet(m_packet);
}
}
+#else
+ if(avcodec_send_frame(m_codecCtx, nullptr) < 0)
+ AUD_THROW(FileException, "File couldn't be written, audio encoding failed with ffmpeg.");
+
+ while(avcodec_receive_packet(m_codecCtx, m_packet) == 0)
+ {
+ m_packet->stream_index = m_stream->index;
+
+ if(av_write_frame(m_formatCtx, m_packet) < 0)
+ AUD_THROW(FileException, "Frame couldn't be writen to the file with ffmpeg.");
+ }
+#endif
}
FFMPEGWriter::FFMPEGWriter(std::string filename, DeviceSpecs specs, Container format, Codec codec, unsigned int bitrate) :
m_position(0),
m_specs(specs),
+ m_formatCtx(nullptr),
+ m_codecCtx(nullptr),
+ m_stream(nullptr),
+ m_packet(nullptr),
+ m_frame(nullptr),
m_input_samples(0),
m_deinterleave(false)
{
@@ -142,75 +170,105 @@ FFMPEGWriter::FFMPEGWriter(std::string filename, DeviceSpecs specs, Container fo
if(avformat_alloc_output_context2(&m_formatCtx, nullptr, formats[format], filename.c_str()) < 0)
AUD_THROW(FileException, "File couldn't be written, format couldn't be found with ffmpeg.");
- m_outputFmt = m_formatCtx->oformat;
+ AVOutputFormat* outputFmt = m_formatCtx->oformat;
- if(!m_outputFmt) {
+ if(!outputFmt) {
avformat_free_context(m_formatCtx);
AUD_THROW(FileException, "File couldn't be written, output format couldn't be found with ffmpeg.");
}
- m_outputFmt->audio_codec = AV_CODEC_ID_NONE;
+ outputFmt->audio_codec = AV_CODEC_ID_NONE;
switch(codec)
{
case CODEC_AAC:
- m_outputFmt->audio_codec = AV_CODEC_ID_AAC;
+ outputFmt->audio_codec = AV_CODEC_ID_AAC;
break;
case CODEC_AC3:
- m_outputFmt->audio_codec = AV_CODEC_ID_AC3;
+ outputFmt->audio_codec = AV_CODEC_ID_AC3;
break;
case CODEC_FLAC:
- m_outputFmt->audio_codec = AV_CODEC_ID_FLAC;
+ outputFmt->audio_codec = AV_CODEC_ID_FLAC;
break;
case CODEC_MP2:
- m_outputFmt->audio_codec = AV_CODEC_ID_MP2;
+ outputFmt->audio_codec = AV_CODEC_ID_MP2;
break;
case CODEC_MP3:
- m_outputFmt->audio_codec = AV_CODEC_ID_MP3;
+ outputFmt->audio_codec = AV_CODEC_ID_MP3;
break;
case CODEC_OPUS:
- m_outputFmt->audio_codec = AV_CODEC_ID_OPUS;
+ outputFmt->audio_codec = AV_CODEC_ID_OPUS;
break;
case CODEC_PCM:
switch(specs.format)
{
case FORMAT_U8:
- m_outputFmt->audio_codec = AV_CODEC_ID_PCM_U8;
+ outputFmt->audio_codec = AV_CODEC_ID_PCM_U8;
break;
case FORMAT_S16:
- m_outputFmt->audio_codec = AV_CODEC_ID_PCM_S16LE;
+ outputFmt->audio_codec = AV_CODEC_ID_PCM_S16LE;
break;
case FORMAT_S24:
- m_outputFmt->audio_codec = AV_CODEC_ID_PCM_S24LE;
+ outputFmt->audio_codec = AV_CODEC_ID_PCM_S24LE;
break;
case FORMAT_S32:
- m_outputFmt->audio_codec = AV_CODEC_ID_PCM_S32LE;
+ outputFmt->audio_codec = AV_CODEC_ID_PCM_S32LE;
break;
case FORMAT_FLOAT32:
- m_outputFmt->audio_codec = AV_CODEC_ID_PCM_F32LE;
+ outputFmt->audio_codec = AV_CODEC_ID_PCM_F32LE;
break;
case FORMAT_FLOAT64:
- m_outputFmt->audio_codec = AV_CODEC_ID_PCM_F64LE;
+ outputFmt->audio_codec = AV_CODEC_ID_PCM_F64LE;
break;
default:
- m_outputFmt->audio_codec = AV_CODEC_ID_NONE;
+ outputFmt->audio_codec = AV_CODEC_ID_NONE;
break;
}
break;
case CODEC_VORBIS:
- m_outputFmt->audio_codec = AV_CODEC_ID_VORBIS;
+ outputFmt->audio_codec = AV_CODEC_ID_VORBIS;
break;
default:
- m_outputFmt->audio_codec = AV_CODEC_ID_NONE;
+ outputFmt->audio_codec = AV_CODEC_ID_NONE;
+ break;
+ }
+
+ uint64_t channel_layout = 0;
+
+ switch(m_specs.channels)
+ {
+ case CHANNELS_MONO:
+ channel_layout = AV_CH_LAYOUT_MONO;
+ break;
+ case CHANNELS_STEREO:
+ channel_layout = AV_CH_LAYOUT_STEREO;
+ break;
+ case CHANNELS_STEREO_LFE:
+ channel_layout = AV_CH_LAYOUT_2POINT1;
+ break;
+ case CHANNELS_SURROUND4:
+ channel_layout = AV_CH_LAYOUT_QUAD;
+ break;
+ case CHANNELS_SURROUND5:
+ channel_layout = AV_CH_LAYOUT_5POINT0_BACK;
+ break;
+ case CHANNELS_SURROUND51:
+ channel_layout = AV_CH_LAYOUT_5POINT1_BACK;
+ break;
+ case CHANNELS_SURROUND61:
+ channel_layout = AV_CH_LAYOUT_6POINT1_BACK;
+ break;
+ case CHANNELS_SURROUND71:
+ channel_layout = AV_CH_LAYOUT_7POINT1;
break;
}
try
{
- if(m_outputFmt->audio_codec == AV_CODEC_ID_NONE)
+ if(outputFmt->audio_codec == AV_CODEC_ID_NONE)
AUD_THROW(FileException, "File couldn't be written, audio codec not found with ffmpeg.");
- AVCodec* codec = avcodec_find_encoder(m_outputFmt->audio_codec);
+ AVCodec* codec = avcodec_find_encoder(outputFmt->audio_codec);
if(!codec)
AUD_THROW(FileException, "File couldn't be written, audio encoder couldn't be found with ffmpeg.");
@@ -220,7 +278,14 @@ FFMPEGWriter::FFMPEGWriter(std::string filename, DeviceSpecs specs, Container fo
m_stream->id = m_formatCtx->nb_streams - 1;
+#ifdef FFMPEG_OLD_CODE
m_codecCtx = m_stream->codec;
+#else
+ m_codecCtx = avcodec_alloc_context3(codec);
+#endif
+
+ if(!m_codecCtx)
+ AUD_THROW(FileException, "File couldn't be written, context creation failed with ffmpeg.");
switch(m_specs.format)
{
@@ -247,7 +312,7 @@ FFMPEGWriter::FFMPEGWriter(std::string filename, DeviceSpecs specs, Container fo
}
if(m_formatCtx->oformat->flags & AVFMT_GLOBALHEADER)
- m_codecCtx->flags |= CODEC_FLAG_GLOBAL_HEADER;
+ m_codecCtx->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
bool format_supported = false;
@@ -328,9 +393,13 @@ FFMPEGWriter::FFMPEGWriter(std::string filename, DeviceSpecs specs, Container fo
m_specs.rate = m_codecCtx->sample_rate;
- m_codecCtx->codec_id = m_outputFmt->audio_codec;
+#ifdef FFMPEG_OLD_CODE
+ m_codecCtx->codec_id = outputFmt->audio_codec;
+#endif
+
m_codecCtx->codec_type = AVMEDIA_TYPE_AUDIO;
m_codecCtx->bit_rate = bitrate;
+ m_codecCtx->channel_layout = channel_layout;
m_codecCtx->channels = m_specs.channels;
m_stream->time_base.num = m_codecCtx->time_base.num = 1;
m_stream->time_base.den = m_codecCtx->time_base.den = m_codecCtx->sample_rate;
@@ -338,6 +407,11 @@ FFMPEGWriter::FFMPEGWriter(std::string filename, DeviceSpecs specs, Container fo
if(avcodec_open2(m_codecCtx, codec, nullptr) < 0)
AUD_THROW(FileException, "File couldn't be written, encoder couldn't be opened with ffmpeg.");
+#ifndef FFMPEG_OLD_CODE
+ if(avcodec_parameters_from_context(m_stream->codecpar, m_codecCtx) < 0)
+ AUD_THROW(FileException, "File couldn't be written, codec parameters couldn't be copied to the context.");
+#endif
+
int samplesize = std::max(int(AUD_SAMPLE_SIZE(m_specs)), AUD_DEVICE_SAMPLE_SIZE(m_specs));
if((m_input_size = m_codecCtx->frame_size))
@@ -346,13 +420,26 @@ FFMPEGWriter::FFMPEGWriter(std::string filename, DeviceSpecs specs, Container fo
if(avio_open(&m_formatCtx->pb, filename.c_str(), AVIO_FLAG_WRITE))
AUD_THROW(FileException, "File couldn't be written, file opening failed with ffmpeg.");
- avformat_write_header(m_formatCtx, nullptr);
+ if(avformat_write_header(m_formatCtx, nullptr) < 0)
+ AUD_THROW(FileException, "File couldn't be written, writing the header failed.");
}
catch(Exception&)
{
+#ifndef FFMPEG_OLD_CODE
+ if(m_codecCtx)
+ avcodec_free_context(&m_codecCtx);
+#endif
avformat_free_context(m_formatCtx);
throw;
}
+
+#ifdef FFMPEG_OLD_CODE
+ m_packet = new AVPacket({});
+#else
+ m_packet = av_packet_alloc();
+#endif
+
+ m_frame = av_frame_alloc();
}
FFMPEGWriter::~FFMPEGWriter()
@@ -365,9 +452,26 @@ FFMPEGWriter::~FFMPEGWriter()
av_write_trailer(m_formatCtx);
+ if(m_frame)
+ av_frame_free(&m_frame);
+
+ if(m_packet)
+ {
+#ifdef FFMPEG_OLD_CODE
+ delete m_packet;
+#else
+ av_packet_free(&m_packet);
+#endif
+ }
+
+#ifdef FFMPEG_OLD_CODE
avcodec_close(m_codecCtx);
+#else
+ if(m_codecCtx)
+ avcodec_free_context(&m_codecCtx);
+#endif
- avio_close(m_formatCtx->pb);
+ avio_closep(&m_formatCtx->pb);
avformat_free_context(m_formatCtx);
}
diff --git a/extern/audaspace/plugins/ffmpeg/FFMPEGWriter.h b/extern/audaspace/plugins/ffmpeg/FFMPEGWriter.h
index 690185deb64..c22f479d83c 100644
--- a/extern/audaspace/plugins/ffmpeg/FFMPEGWriter.h
+++ b/extern/audaspace/plugins/ffmpeg/FFMPEGWriter.h
@@ -66,14 +66,19 @@ private:
AVCodecContext* m_codecCtx;
/**
- * The AVOutputFormat structure for using ffmpeg.
+ * The AVStream structure for using ffmpeg.
*/
- AVOutputFormat* m_outputFmt;
+ AVStream* m_stream;
/**
- * The AVStream structure for using ffmpeg.
+ * The AVPacket structure for using ffmpeg.
*/
- AVStream* m_stream;
+ AVPacket* m_packet;
+
+ /**
+ * The AVFrame structure for using ffmpeg.
+ */
+ AVFrame* m_frame;
/**
* The input buffer for the format converted data before encoding.
diff --git a/intern/cycles/blender/addon/ui.py b/intern/cycles/blender/addon/ui.py
index 5c68115cd86..721b395e596 100644
--- a/intern/cycles/blender/addon/ui.py
+++ b/intern/cycles/blender/addon/ui.py
@@ -1480,26 +1480,6 @@ class CYCLES_MATERIAL_PT_settings_surface(CyclesButtonsPanel, Panel):
col = layout.column()
col.prop(cmat, "sample_as_light", text="Multiple Importance")
col.prop(cmat, "use_transparent_shadow")
-
-
-class CYCLES_MATERIAL_PT_settings_geometry(CyclesButtonsPanel, Panel):
- bl_label = "Geometry"
- bl_parent_id = "CYCLES_MATERIAL_PT_settings"
- bl_context = "material"
-
- @classmethod
- def poll(cls, context):
- return context.material and CyclesButtonsPanel.poll(context)
-
- def draw(self, context):
- layout = self.layout
- layout.use_property_split = True
-
- mat = context.material
- cmat = mat.cycles
-
- col = layout.column()
-
col.prop(cmat, "displacement_method", text="Displacement Method")
@@ -1674,29 +1654,7 @@ class CYCLES_SCENE_PT_simplify(CyclesButtonsPanel, Panel):
self.layout.prop(rd, "use_simplify", text="")
def draw(self, context):
- layout = self.layout
- layout.use_property_split = True
-
- scene = context.scene
- rd = scene.render
- cscene = scene.cycles
-
- layout.active = rd.use_simplify
-
- col = layout.column()
- col.prop(cscene, "use_camera_cull")
- sub = col.column()
- sub.active = cscene.use_camera_cull
- sub.prop(cscene, "camera_cull_margin")
-
- layout.separator()
-
- col = layout.column()
-
- col.prop(cscene, "use_distance_cull")
- sub = col.column()
- sub.active = cscene.use_distance_cull
- sub.prop(cscene, "distance_cull_margin", text="Distance")
+ pass
class CYCLES_SCENE_PT_simplify_viewport(CyclesButtonsPanel, Panel):
@@ -1746,6 +1704,36 @@ class CYCLES_SCENE_PT_simplify_render(CyclesButtonsPanel, Panel):
col.prop(cscene, "ao_bounces_render", text="AO Bounces")
+class CYCLES_SCENE_PT_simplify_culling(CyclesButtonsPanel, Panel):
+ bl_label = "Culling"
+ bl_context = "scene"
+ bl_parent_id = "CYCLES_SCENE_PT_simplify"
+ bl_options = {'DEFAULT_CLOSED'}
+ COMPAT_ENGINES = {'CYCLES'}
+
+ def draw(self, context):
+ layout = self.layout
+ layout.use_property_split = True
+
+ scene = context.scene
+ rd = scene.render
+ cscene = scene.cycles
+
+ layout.active = rd.use_simplify
+
+ col = layout.column()
+ col.prop(cscene, "use_camera_cull")
+ sub = col.column()
+ sub.active = cscene.use_camera_cull
+ sub.prop(cscene, "camera_cull_margin")
+
+ col = layout.column()
+ col.prop(cscene, "use_distance_cull")
+ sub = col.column()
+ sub.active = cscene.use_distance_cull
+ sub.prop(cscene, "distance_cull_margin", text="Distance")
+
+
def draw_device(self, context):
scene = context.scene
layout = self.layout
@@ -1847,13 +1835,13 @@ classes = (
CYCLES_MATERIAL_PT_displacement,
CYCLES_MATERIAL_PT_settings,
CYCLES_MATERIAL_PT_settings_surface,
- CYCLES_MATERIAL_PT_settings_geometry,
CYCLES_MATERIAL_PT_settings_volume,
CYCLES_RENDER_PT_bake,
CYCLES_RENDER_PT_debug,
CYCLES_SCENE_PT_simplify,
CYCLES_SCENE_PT_simplify_viewport,
CYCLES_SCENE_PT_simplify_render,
+ CYCLES_SCENE_PT_simplify_culling,
)
diff --git a/intern/cycles/blender/blender_object.cpp b/intern/cycles/blender/blender_object.cpp
index 3c38c7a4584..8ed3eafb488 100644
--- a/intern/cycles/blender/blender_object.cpp
+++ b/intern/cycles/blender/blender_object.cpp
@@ -482,7 +482,8 @@ static bool object_render_hide_original(BL::Object::type_enum ob_type,
static bool object_render_hide(BL::Object& b_ob,
bool top_level,
bool parent_hide,
- bool& hide_triangles)
+ bool& hide_triangles,
+ BL::Depsgraph::mode_enum depsgraph_mode)
{
/* check if we should render or hide particle emitter */
BL::Object::particle_systems_iterator b_psys;
@@ -501,11 +502,16 @@ static bool object_render_hide(BL::Object& b_ob,
has_particles = true;
}
+ /* Both mode_PREVIEW and mode_VIEWPORT are treated the same here.*/
+ const bool show_duplicator = depsgraph_mode == BL::Depsgraph::mode_RENDER
+ ? b_ob.show_duplicator_for_render()
+ : b_ob.show_duplicator_for_viewport();
+
if(has_particles) {
- show_emitter = b_ob.show_duplicator_for_render();
+ show_emitter = show_duplicator;
hide_emitter = !show_emitter;
} else if(b_ob.is_duplicator()) {
- if(top_level || b_ob.show_duplicator_for_render()) {
+ if(top_level || show_duplicator) {
hide_as_dupli_parent = true;
}
}
@@ -563,6 +569,8 @@ void BlenderSync::sync_objects(BL::Depsgraph& b_depsgraph, float motion_time)
bool cancel = false;
bool use_portal = false;
+ BL::Depsgraph::mode_enum depsgraph_mode = b_depsgraph.mode();
+
BL::Depsgraph::object_instances_iterator b_instance_iter;
for(b_depsgraph.object_instances.begin(b_instance_iter);
b_instance_iter != b_depsgraph.object_instances.end() && !cancel;
@@ -582,7 +590,7 @@ void BlenderSync::sync_objects(BL::Depsgraph& b_depsgraph, float motion_time)
/* test if object needs to be hidden */
bool hide_tris;
- if(!object_render_hide(b_ob, true, true, hide_tris)) {
+ if(!object_render_hide(b_ob, true, true, hide_tris, depsgraph_mode)) {
/* object itself */
sync_object(b_depsgraph,
b_instance,
diff --git a/intern/cycles/kernel/bvh/bvh.h b/intern/cycles/kernel/bvh/bvh.h
index c0a5bb434ea..d3e0b25a200 100644
--- a/intern/cycles/kernel/bvh/bvh.h
+++ b/intern/cycles/kernel/bvh/bvh.h
@@ -212,21 +212,20 @@ ccl_device_intersect void scene_intersect_local(KernelGlobals *kg,
{
#ifdef __OBJECT_MOTION__
if(kernel_data.bvh.have_motion) {
- bvh_intersect_local_motion(kg,
- &ray,
- local_isect,
- local_object,
- lcg_state,
- max_hits);
- return;
+ return bvh_intersect_local_motion(kg,
+ &ray,
+ local_isect,
+ local_object,
+ lcg_state,
+ max_hits);
}
#endif /* __OBJECT_MOTION__ */
- bvh_intersect_local(kg,
- &ray,
- local_isect,
- local_object,
- lcg_state,
- max_hits);
+ return bvh_intersect_local(kg,
+ &ray,
+ local_isect,
+ local_object,
+ lcg_state,
+ max_hits);
}
#endif
diff --git a/intern/cycles/kernel/bvh/bvh_local.h b/intern/cycles/kernel/bvh/bvh_local.h
index 605d4166819..9292cc76a5c 100644
--- a/intern/cycles/kernel/bvh/bvh_local.h
+++ b/intern/cycles/kernel/bvh/bvh_local.h
@@ -246,22 +246,20 @@ ccl_device_inline void BVH_FUNCTION_NAME(KernelGlobals *kg,
switch(kernel_data.bvh.bvh_layout) {
#ifdef __QBVH__
case BVH_LAYOUT_BVH4:
- BVH_FUNCTION_FULL_NAME(QBVH)(kg,
- ray,
- local_isect,
- local_object,
- lcg_state,
- max_hits);
- break;
+ return BVH_FUNCTION_FULL_NAME(QBVH)(kg,
+ ray,
+ local_isect,
+ local_object,
+ lcg_state,
+ max_hits);
#endif
case BVH_LAYOUT_BVH2:
- BVH_FUNCTION_FULL_NAME(BVH)(kg,
- ray,
- local_isect,
- local_object,
- lcg_state,
- max_hits);
- break;
+ return BVH_FUNCTION_FULL_NAME(BVH)(kg,
+ ray,
+ local_isect,
+ local_object,
+ lcg_state,
+ max_hits);
}
kernel_assert(!"Should not happen");
}
diff --git a/intern/gawain/gawain/gwn_common.h b/intern/gawain/gawain/gwn_common.h
index dc0a52ca096..f1512bf4466 100644
--- a/intern/gawain/gawain/gwn_common.h
+++ b/intern/gawain/gawain/gwn_common.h
@@ -33,4 +33,4 @@
# define GWN_INLINE static __forceinline
#else
# define GWN_INLINE static inline __attribute__((always_inline)) __attribute__((__unused__))
-#endif \ No newline at end of file
+#endif
diff --git a/intern/gawain/src/gwn_batch.c b/intern/gawain/src/gwn_batch.c
index 2e3a4eff0f0..64d5d146578 100644
--- a/intern/gawain/src/gwn_batch.c
+++ b/intern/gawain/src/gwn_batch.c
@@ -179,7 +179,7 @@ int GWN_batch_vertbuf_add_ex(
return v;
}
}
-
+
// we only make it this far if there is no room for another Gwn_VertBuf
#if TRUST_NO_ONE
assert(false);
diff --git a/intern/gawain/src/gwn_immediate.c b/intern/gawain/src/gwn_immediate.c
index 006af0abe01..b0b587d1b8c 100644
--- a/intern/gawain/src/gwn_immediate.c
+++ b/intern/gawain/src/gwn_immediate.c
@@ -47,7 +47,7 @@ typedef struct {
GLuint vbo_id;
GLuint vao_id;
-
+
GLuint bound_program;
const Gwn_ShaderInterface* shader_interface;
Gwn_AttrBinding attrib_binding;
diff --git a/intern/ghost/CMakeLists.txt b/intern/ghost/CMakeLists.txt
index e4b74ae24af..d8330d43c16 100644
--- a/intern/ghost/CMakeLists.txt
+++ b/intern/ghost/CMakeLists.txt
@@ -280,7 +280,7 @@ elseif(WIN32)
if(NOT WITH_GL_EGL)
list(APPEND SRC
intern/GHOST_ContextWGL.cpp
-
+
intern/GHOST_ContextWGL.h
)
endif()
@@ -307,7 +307,7 @@ endif()
if(WITH_GL_EGL AND NOT (WITH_HEADLESS OR WITH_GHOST_SDL))
list(APPEND SRC
intern/GHOST_ContextEGL.cpp
-
+
intern/GHOST_ContextEGL.h
)
endif()
diff --git a/intern/ghost/GHOST_C-api.h b/intern/ghost/GHOST_C-api.h
index 071474e57dc..a911c4560e4 100644
--- a/intern/ghost/GHOST_C-api.h
+++ b/intern/ghost/GHOST_C-api.h
@@ -36,7 +36,7 @@
#include "GHOST_Types.h"
#ifdef __cplusplus
-extern "C" {
+extern "C" {
#endif
/**
@@ -103,7 +103,7 @@ extern GHOST_TUns64 GHOST_GetMilliSeconds(GHOST_SystemHandle systemhandle);
/**
* Installs a timer.
- * Note that, on most operating systems, messages need to be processed in order
+ * Note that, on most operating systems, messages need to be processed in order
* for the timer callbacks to be invoked.
* \param systemhandle The handle to the system
* \param delay The time to wait for the first call to the timerProc (in milliseconds)
@@ -165,7 +165,7 @@ extern void GHOST_GetAllDisplayDimensions(GHOST_SystemHandle systemhandle,
/**
* Create a new window.
- * The new window is added to the list of windows managed.
+ * The new window is added to the list of windows managed.
* Never explicitly delete the window, use disposeWindow() instead.
* \param systemhandle The handle to the system
* \param title The name of the window (displayed in the title bar of the window if the OS supports it).
@@ -218,7 +218,7 @@ extern GHOST_TUserDataPtr GHOST_GetWindowUserData(GHOST_WindowHandle windowhandl
* \param windowhandle The handle to the window
* \param userdata The window user data.
*/
-extern void GHOST_SetWindowUserData(GHOST_WindowHandle windowhandle,
+extern void GHOST_SetWindowUserData(GHOST_WindowHandle windowhandle,
GHOST_TUserDataPtr userdata);
/**
@@ -488,7 +488,7 @@ extern GHOST_TEventType GHOST_GetEventType(GHOST_EventHandle eventhandle);
extern GHOST_TUns64 GHOST_GetEventTime(GHOST_EventHandle eventhandle);
/**
- * Returns the window this event was generated on,
+ * Returns the window this event was generated on,
* or NULL if it is a 'system' event.
* \param eventhandle The handle to the event
* \return The generating window.
@@ -566,7 +566,7 @@ extern void GHOST_SetTitle(GHOST_WindowHandle windowhandle,
/**
* Returns the title displayed in the title bar. The title
* should be free'd with free().
- *
+ *
* \param windowhandle The handle to the window
* \return The title, free with free().
*/
diff --git a/intern/ghost/GHOST_IEvent.h b/intern/ghost/GHOST_IEvent.h
index ba5d9ee33b9..83273716950 100644
--- a/intern/ghost/GHOST_IEvent.h
+++ b/intern/ghost/GHOST_IEvent.h
@@ -42,8 +42,8 @@ class GHOST_IWindow;
* Interface class for events received from GHOST.
* You should not need to inherit this class. The system will pass these events
* to the GHOST_IEventConsumer::processEvent() method of event consumers.<br>
- * Use the getType() method to retrieve the type of event and the getData()
- * method to get the event data out. Using the event type you can cast the
+ * Use the getType() method to retrieve the type of event and the getData()
+ * method to get the event data out. Using the event type you can cast the
* event data to the correct event dat structure.
* \see GHOST_IEventConsumer#processEvent
* \see GHOST_TEventType
@@ -73,18 +73,18 @@ public:
virtual GHOST_TUns64 getTime() = 0;
/**
- * Returns the window this event was generated on,
+ * Returns the window this event was generated on,
* or NULL if it is a 'system' event.
* \return The generating window.
*/
virtual GHOST_IWindow *getWindow() = 0;
-
+
/**
* Returns the event data.
* \return The event data.
*/
virtual GHOST_TEventDataPtr getData() = 0;
-
+
#ifdef WITH_CXX_GUARDEDALLOC
MEM_CXX_CLASS_ALLOC_FUNCS("GHOST:GHOST_IEvent")
#endif
diff --git a/intern/ghost/GHOST_ISystem.h b/intern/ghost/GHOST_ISystem.h
index 25b7fb26e0e..1a6c0f9a1bf 100644
--- a/intern/ghost/GHOST_ISystem.h
+++ b/intern/ghost/GHOST_ISystem.h
@@ -315,7 +315,7 @@ public:
* \return The current status.
*/
virtual bool getFullScreen(void) = 0;
-
+
/**
* Native pixel size support (MacBook 'retina').
*/
diff --git a/intern/ghost/GHOST_ISystemPaths.h b/intern/ghost/GHOST_ISystemPaths.h
index 8f81a226f94..14b1183af2c 100644
--- a/intern/ghost/GHOST_ISystemPaths.h
+++ b/intern/ghost/GHOST_ISystemPaths.h
@@ -4,7 +4,7 @@
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
+ * of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -18,7 +18,7 @@
* The Original Code is Copyright (C) 2009 Blender Foundation.
* All rights reserved.
*
- *
+ *
* Contributor(s): Blender Foundation
*
* ***** END GPL LICENSE BLOCK *****
diff --git a/intern/ghost/GHOST_ITimerTask.h b/intern/ghost/GHOST_ITimerTask.h
index 9bea697cbc8..dd3db5623cc 100644
--- a/intern/ghost/GHOST_ITimerTask.h
+++ b/intern/ghost/GHOST_ITimerTask.h
@@ -39,11 +39,11 @@
/**
* Interface for a timer task.
* Timer tasks are created by the system and can be installed by the system.
- * After installation, the timer callback-procedure or "timerProc" will be called
+ * After installation, the timer callback-procedure or "timerProc" will be called
* periodically. You should not need to inherit this class. It is passed to the
* application in the timer-callback.<br>
* <br>
- * Note that GHOST processes timers in the UI thread. You should ask GHOST
+ * Note that GHOST processes timers in the UI thread. You should ask GHOST
* process messages in order for the timer-callbacks to be called.
* \see GHOST_ISystem#installTimer
* \see GHOST_TimerProcPtr
@@ -77,7 +77,7 @@ public:
* \return The timer user data.
*/
virtual GHOST_TUserDataPtr getUserData() const = 0;
-
+
/**
* Changes the time user data.
* \param userData: The timer user data.
diff --git a/intern/ghost/GHOST_IWindow.h b/intern/ghost/GHOST_IWindow.h
index 4a4d6be5ced..5a3403bcbd3 100644
--- a/intern/ghost/GHOST_IWindow.h
+++ b/intern/ghost/GHOST_IWindow.h
@@ -361,7 +361,7 @@ public:
*/
virtual void endIME() = 0;
#endif /* WITH_INPUT_IME */
-
+
#ifdef WITH_CXX_GUARDEDALLOC
MEM_CXX_CLASS_ALLOC_FUNCS("GHOST:GHOST_IWindow")
#endif
diff --git a/intern/ghost/GHOST_Path-api.h b/intern/ghost/GHOST_Path-api.h
index 5af3adaa570..9a4d065d2ad 100644
--- a/intern/ghost/GHOST_Path-api.h
+++ b/intern/ghost/GHOST_Path-api.h
@@ -36,7 +36,7 @@
#include "GHOST_Types.h"
#ifdef __cplusplus
-extern "C" {
+extern "C" {
#endif
GHOST_DECLARE_HANDLE(GHOST_SystemPathsHandle);
@@ -79,7 +79,7 @@ extern const GHOST_TUns8 *GHOST_getBinaryDir(void);
extern void GHOST_addToSystemRecentFiles(const char *filename);
#ifdef __cplusplus
-}
+}
#endif
#endif
diff --git a/intern/ghost/GHOST_Types.h b/intern/ghost/GHOST_Types.h
index 02b5063e515..b206bb677a7 100644
--- a/intern/ghost/GHOST_Types.h
+++ b/intern/ghost/GHOST_Types.h
@@ -77,7 +77,7 @@ typedef enum {
GHOST_kSuccess
} GHOST_TSuccess;
-/* Xtilt and Ytilt represent how much the pen is tilted away from
+/* Xtilt and Ytilt represent how much the pen is tilted away from
* vertically upright in either the X or Y direction, with X and Y the
* axes of the tablet surface.
* In other words, Xtilt and Ytilt are components of a vector created by projecting
@@ -190,12 +190,12 @@ typedef enum {
GHOST_kEventWindowSize,
GHOST_kEventWindowMove,
GHOST_kEventWindowDPIHintChanged,
-
+
GHOST_kEventDraggingEntered,
GHOST_kEventDraggingUpdated,
GHOST_kEventDraggingExited,
GHOST_kEventDraggingDropDone,
-
+
GHOST_kEventOpenMainFile, // Needed for Cocoa to open double-clicked .blend file at startup
GHOST_kEventNativeResolutionChange, // Needed for Cocoa when window moves to other display
@@ -214,9 +214,9 @@ typedef enum {
GHOST_kStandardCursorDefault = 0,
GHOST_kStandardCursorRightArrow,
GHOST_kStandardCursorLeftArrow,
- GHOST_kStandardCursorInfo,
+ GHOST_kStandardCursorInfo,
GHOST_kStandardCursorDestroy,
- GHOST_kStandardCursorHelp,
+ GHOST_kStandardCursorHelp,
GHOST_kStandardCursorCycle,
GHOST_kStandardCursorSpray,
GHOST_kStandardCursorWait,
@@ -233,7 +233,7 @@ typedef enum {
GHOST_kStandardCursorBottomRightCorner,
GHOST_kStandardCursorBottomLeftCorner,
GHOST_kStandardCursorCopy,
- GHOST_kStandardCursorCustom,
+ GHOST_kStandardCursorCustom,
GHOST_kStandardCursorPencil,
GHOST_kStandardCursorNumCursors
@@ -247,7 +247,7 @@ typedef enum {
GHOST_kKeyLinefeed,
GHOST_kKeyClear,
GHOST_kKeyEnter = 0x0D,
-
+
GHOST_kKeyEsc = 0x1B,
GHOST_kKeySpace = ' ',
GHOST_kKeyQuote = 0x27,
@@ -305,7 +305,7 @@ typedef enum {
GHOST_kKeyBackslash = 0x5C,
GHOST_kKeyAccentGrave = '`',
-
+
GHOST_kKeyLeftShift = 0x100,
GHOST_kKeyRightShift,
GHOST_kKeyLeftControl,
@@ -377,7 +377,7 @@ typedef enum {
GHOST_kKeyF22,
GHOST_kKeyF23,
GHOST_kKeyF24,
-
+
// Multimedia keypad buttons
GHOST_kKeyMediaPlay,
GHOST_kKeyMediaStop,
@@ -418,7 +418,7 @@ typedef enum {
GHOST_kTrackpadEventSwipe, /* Reserved, not used for now */
GHOST_kTrackpadEventMagnify
} GHOST_TTrackpadEventSubTypes;
-
+
typedef struct {
/** The event subtype */
diff --git a/intern/ghost/intern/GHOST_Buttons.h b/intern/ghost/intern/GHOST_Buttons.h
index 0aa93a2fad0..aed9a3cc81f 100644
--- a/intern/ghost/intern/GHOST_Buttons.h
+++ b/intern/ghost/intern/GHOST_Buttons.h
@@ -38,7 +38,7 @@
/**
* This struct stores the state of the mouse buttons.
- * Buttons can be set using button masks.
+ * Buttons can be set using button masks.
* \author Maarten Gribnau
* \date May 15, 2001
*/
diff --git a/intern/ghost/intern/GHOST_C-api.cpp b/intern/ghost/intern/GHOST_C-api.cpp
index c89ef49de33..90956cf541a 100644
--- a/intern/ghost/intern/GHOST_C-api.cpp
+++ b/intern/ghost/intern/GHOST_C-api.cpp
@@ -119,7 +119,7 @@ void GHOST_GetMainDisplayDimensions(GHOST_SystemHandle systemhandle,
GHOST_TUns32 *height)
{
GHOST_ISystem *system = (GHOST_ISystem *) systemhandle;
-
+
system->getMainDisplayDimensions(*width, *height);
}
@@ -182,7 +182,7 @@ GHOST_TSuccess GHOST_DisposeWindow(GHOST_SystemHandle systemhandle,
{
GHOST_ISystem *system = (GHOST_ISystem *) systemhandle;
GHOST_IWindow *window = (GHOST_IWindow *) windowhandle;
-
+
return system->disposeWindow(window);
}
@@ -193,7 +193,7 @@ int GHOST_ValidWindow(GHOST_SystemHandle systemhandle,
{
GHOST_ISystem *system = (GHOST_ISystem *) systemhandle;
GHOST_IWindow *window = (GHOST_IWindow *) windowhandle;
-
+
return (int) system->validWindow(window);
}
@@ -211,7 +211,7 @@ GHOST_WindowHandle GHOST_BeginFullScreen(GHOST_SystemHandle systemhandle,
bstereoVisual = true;
else
bstereoVisual = false;
-
+
system->beginFullScreen(*setting, &window, bstereoVisual);
return (GHOST_WindowHandle)window;
@@ -240,7 +240,7 @@ int GHOST_GetFullScreen(GHOST_SystemHandle systemhandle)
int GHOST_ProcessEvents(GHOST_SystemHandle systemhandle, int waitForEvent)
{
GHOST_ISystem *system = (GHOST_ISystem *) systemhandle;
-
+
return (int) system->processEvents(waitForEvent ? true : false);
}
@@ -249,7 +249,7 @@ int GHOST_ProcessEvents(GHOST_SystemHandle systemhandle, int waitForEvent)
void GHOST_DispatchEvents(GHOST_SystemHandle systemhandle)
{
GHOST_ISystem *system = (GHOST_ISystem *) systemhandle;
-
+
system->dispatchEvents();
}
@@ -257,7 +257,7 @@ void GHOST_DispatchEvents(GHOST_SystemHandle systemhandle)
GHOST_TSuccess GHOST_AddEventConsumer(GHOST_SystemHandle systemhandle, GHOST_EventConsumerHandle consumerhandle)
{
GHOST_ISystem *system = (GHOST_ISystem *) systemhandle;
-
+
return system->addEventConsumer((GHOST_CallbackEventConsumer *)consumerhandle);
}
@@ -353,7 +353,7 @@ GHOST_TSuccess GHOST_GetCursorPosition(GHOST_SystemHandle systemhandle,
GHOST_TInt32 *y)
{
GHOST_ISystem *system = (GHOST_ISystem *) systemhandle;
-
+
return system->getCursorPosition(*x, *y);
}
@@ -364,7 +364,7 @@ GHOST_TSuccess GHOST_SetCursorPosition(GHOST_SystemHandle systemhandle,
GHOST_TInt32 y)
{
GHOST_ISystem *system = (GHOST_ISystem *) systemhandle;
-
+
return system->setCursorPosition(x, y);
}
@@ -398,7 +398,7 @@ GHOST_TSuccess GHOST_GetModifierKeyState(GHOST_SystemHandle systemhandle,
GHOST_ISystem *system = (GHOST_ISystem *) systemhandle;
GHOST_TSuccess result;
bool isdown = false;
-
+
result = system->getModifierKeyState(mask, isdown);
*isDown = (int) isdown;
@@ -414,7 +414,7 @@ GHOST_TSuccess GHOST_GetButtonState(GHOST_SystemHandle systemhandle,
GHOST_ISystem *system = (GHOST_ISystem *) systemhandle;
GHOST_TSuccess result;
bool isdown = false;
-
+
result = system->getButtonState(mask, isdown);
*isDown = (int) isdown;
@@ -441,7 +441,7 @@ void GHOST_setAcceptDragOperation(GHOST_WindowHandle windowhandle, GHOST_TInt8 c
GHOST_TEventType GHOST_GetEventType(GHOST_EventHandle eventhandle)
{
GHOST_IEvent *event = (GHOST_IEvent *) eventhandle;
-
+
return event->getType();
}
@@ -466,7 +466,7 @@ GHOST_WindowHandle GHOST_GetEventWindow(GHOST_EventHandle eventhandle)
GHOST_TEventDataPtr GHOST_GetEventData(GHOST_EventHandle eventhandle)
{
GHOST_IEvent *event = (GHOST_IEvent *) eventhandle;
-
+
return event->getData();
}
@@ -475,7 +475,7 @@ GHOST_TEventDataPtr GHOST_GetEventData(GHOST_EventHandle eventhandle)
GHOST_TimerProcPtr GHOST_GetTimerProc(GHOST_TimerTaskHandle timertaskhandle)
{
GHOST_ITimerTask *timertask = (GHOST_ITimerTask *) timertaskhandle;
-
+
return timertask->getTimerProc();
}
@@ -485,7 +485,7 @@ void GHOST_SetTimerProc(GHOST_TimerTaskHandle timertaskhandle,
GHOST_TimerProcPtr timerproc)
{
GHOST_ITimerTask *timertask = (GHOST_ITimerTask *) timertaskhandle;
-
+
timertask->setTimerProc(timerproc);
}
@@ -504,13 +504,13 @@ void GHOST_SetTimerTaskUserData(GHOST_TimerTaskHandle timertaskhandle,
GHOST_TUserDataPtr userdata)
{
GHOST_ITimerTask *timertask = (GHOST_ITimerTask *) timertaskhandle;
-
+
timertask->setUserData(userdata);
}
-int GHOST_GetValid(GHOST_WindowHandle windowhandle)
+int GHOST_GetValid(GHOST_WindowHandle windowhandle)
{
GHOST_IWindow *window = (GHOST_IWindow *) windowhandle;
@@ -542,7 +542,7 @@ void GHOST_SetTitle(GHOST_WindowHandle windowhandle,
const char *title)
{
GHOST_IWindow *window = (GHOST_IWindow *) windowhandle;
-
+
window->setTitle(title);
}
@@ -567,7 +567,7 @@ char *GHOST_GetTitle(GHOST_WindowHandle windowhandle)
-GHOST_RectangleHandle GHOST_GetWindowBounds(GHOST_WindowHandle windowhandle)
+GHOST_RectangleHandle GHOST_GetWindowBounds(GHOST_WindowHandle windowhandle)
{
GHOST_IWindow *window = (GHOST_IWindow *) windowhandle;
GHOST_Rect *rectangle = NULL;
@@ -580,7 +580,7 @@ GHOST_RectangleHandle GHOST_GetWindowBounds(GHOST_WindowHandle windowhandle)
-GHOST_RectangleHandle GHOST_GetClientBounds(GHOST_WindowHandle windowhandle)
+GHOST_RectangleHandle GHOST_GetClientBounds(GHOST_WindowHandle windowhandle)
{
GHOST_IWindow *window = (GHOST_IWindow *) windowhandle;
GHOST_Rect *rectangle = NULL;
@@ -678,16 +678,16 @@ GHOST_TSuccess GHOST_SetWindowState(GHOST_WindowHandle windowhandle,
GHOST_TSuccess GHOST_SetWindowModifiedState(GHOST_WindowHandle windowhandle, GHOST_TUns8 isUnsavedChanges)
{
GHOST_IWindow *window = (GHOST_IWindow *) windowhandle;
-
+
return window->setModifiedState(isUnsavedChanges);
-}
+}
GHOST_TSuccess GHOST_SetWindowOrder(GHOST_WindowHandle windowhandle,
GHOST_TWindowOrder order)
{
GHOST_IWindow *window = (GHOST_IWindow *) windowhandle;
-
+
return window->setOrder(order);
}
@@ -725,7 +725,7 @@ GHOST_TUns16 GHOST_GetNumOfAASamples(GHOST_WindowHandle windowhandle)
GHOST_TSuccess GHOST_ActivateWindowDrawingContext(GHOST_WindowHandle windowhandle)
{
GHOST_IWindow *window = (GHOST_IWindow *) windowhandle;
-
+
return window->activateDrawingContext();
}
diff --git a/intern/ghost/intern/GHOST_ContextWGL.h b/intern/ghost/intern/GHOST_ContextWGL.h
index 6f575db73c6..be9575844c9 100644
--- a/intern/ghost/intern/GHOST_ContextWGL.h
+++ b/intern/ghost/intern/GHOST_ContextWGL.h
@@ -158,7 +158,7 @@ private:
const int m_contextResetNotificationStrategy;
HGLRC m_hGLRC;
-
+
#ifndef NDEBUG
const char *m_dummyVendor;
const char *m_dummyRenderer;
diff --git a/intern/ghost/intern/GHOST_Debug.h b/intern/ghost/intern/GHOST_Debug.h
index db49627b378..658c9bf5d2c 100644
--- a/intern/ghost/intern/GHOST_Debug.h
+++ b/intern/ghost/intern/GHOST_Debug.h
@@ -40,9 +40,9 @@
# endif // DEBUG
#endif // _MSC_VER
-#ifdef WITH_GHOST_DEBUG
+#ifdef WITH_GHOST_DEBUG
# define GHOST_DEBUG // spit ghost events to stdout
-#endif // WITH_GHOST_DEBUG
+#endif // WITH_GHOST_DEBUG
#ifdef GHOST_DEBUG
# include <iostream>
diff --git a/intern/ghost/intern/GHOST_DisplayManager.cpp b/intern/ghost/intern/GHOST_DisplayManager.cpp
index 9f0b32148f6..2f8240e826b 100644
--- a/intern/ghost/intern/GHOST_DisplayManager.cpp
+++ b/intern/ghost/intern/GHOST_DisplayManager.cpp
@@ -179,9 +179,9 @@ GHOST_DisplayManager::findMatch(
best = score;
}
}
-
+
match = m_settings[display][found];
-
+
GHOST_PRINT("GHOST_DisplayManager::findMatch(): settings of match:\n");
GHOST_PRINT(" setting.xPixels=" << match.xPixels << "\n");
GHOST_PRINT(" setting.yPixels=" << match.yPixels << "\n");
diff --git a/intern/ghost/intern/GHOST_DisplayManager.h b/intern/ghost/intern/GHOST_DisplayManager.h
index afdb11543e9..02a742a54db 100644
--- a/intern/ghost/intern/GHOST_DisplayManager.h
+++ b/intern/ghost/intern/GHOST_DisplayManager.h
@@ -50,7 +50,7 @@ public:
* Constructor.
*/
GHOST_DisplayManager(void);
-
+
/**
* Destructor.
*/
@@ -79,7 +79,7 @@ public:
GHOST_TInt32& numSettings) const;
/**
- * Returns the current setting for this display device.
+ * Returns the current setting for this display device.
* \param display The index of the display to query with 0 <= display < getNumDisplays().
* \param index The setting index to be returned.
* \param setting The setting of the display device with this index.
@@ -90,7 +90,7 @@ public:
GHOST_DisplaySetting& setting) const;
/**
- * Returns the current setting for this display device.
+ * Returns the current setting for this display device.
* \param display The index of the display to query with 0 <= display < getNumDisplays().
* \param setting The current setting of the display device with this index.
* \return Indication of success.
@@ -128,7 +128,7 @@ protected:
* \return Indication of success.
*/
GHOST_TSuccess initializeSettings(void);
-
+
/** Tells whether the list of display modes has been stored already. */
bool m_settingsInitialized;
/** The list with display settings for the main display. */
diff --git a/intern/ghost/intern/GHOST_DisplayManagerCocoa.h b/intern/ghost/intern/GHOST_DisplayManagerCocoa.h
index f580820d8f6..3ce0b4e2239 100644
--- a/intern/ghost/intern/GHOST_DisplayManagerCocoa.h
+++ b/intern/ghost/intern/GHOST_DisplayManagerCocoa.h
@@ -69,7 +69,7 @@ public:
GHOST_TSuccess getNumDisplaySettings(GHOST_TUns8 display, GHOST_TInt32& numSettings) const;
/**
- * Returns the current setting for this display device.
+ * Returns the current setting for this display device.
* \param display The index of the display to query with 0 <= display < getNumDisplays().
* \param index The setting index to be returned.
* \param setting The setting of the display device with this index.
@@ -78,7 +78,7 @@ public:
GHOST_TSuccess getDisplaySetting(GHOST_TUns8 display, GHOST_TInt32 index, GHOST_DisplaySetting& setting) const;
/**
- * Returns the current setting for this display device.
+ * Returns the current setting for this display device.
* \param display The index of the display to query with 0 <= display < getNumDisplays().
* \param setting The current setting of the display device with this index.
* \return Indication of success.
@@ -86,14 +86,14 @@ public:
GHOST_TSuccess getCurrentDisplaySetting(GHOST_TUns8 display, GHOST_DisplaySetting& setting) const;
/**
- * Changes the current setting for this display device.
+ * Changes the current setting for this display device.
* \param display The index of the display to query with 0 <= display < getNumDisplays().
* \param setting The current setting of the display device with this index.
* \return Indication of success.
*/
GHOST_TSuccess setCurrentDisplaySetting(GHOST_TUns8 display, const GHOST_DisplaySetting& setting);
-protected:
+protected:
//Do not cache values as OS X supports screen hot plug
/** Cached number of displays. */
//CGDisplayCount m_numDisplays;
diff --git a/intern/ghost/intern/GHOST_DisplayManagerWin32.cpp b/intern/ghost/intern/GHOST_DisplayManagerWin32.cpp
index 7b9a897fe57..f5f6de330a9 100644
--- a/intern/ghost/intern/GHOST_DisplayManagerWin32.cpp
+++ b/intern/ghost/intern/GHOST_DisplayManagerWin32.cpp
@@ -62,11 +62,11 @@ static BOOL get_dd(DWORD d, DISPLAY_DEVICE *dd)
}
/*
- * When you call EnumDisplaySettings with iModeNum set to zero, the operating system
- * initializes and caches information about the display device. When you call
- * EnumDisplaySettings with iModeNum set to a non-zero value, the function returns
+ * When you call EnumDisplaySettings with iModeNum set to zero, the operating system
+ * initializes and caches information about the display device. When you call
+ * EnumDisplaySettings with iModeNum set to a non-zero value, the function returns
* the information that was cached the last time the function was called with iModeNum
- * set to zero.
+ * set to zero.
*/
GHOST_TSuccess GHOST_DisplayManagerWin32::getNumDisplaySettings(GHOST_TUns8 display, GHOST_TInt32& numSettings) const
{
@@ -98,9 +98,9 @@ GHOST_TSuccess GHOST_DisplayManagerWin32::getDisplaySetting(GHOST_TUns8 display,
setting.bpp = dm.dmBitsPerPel;
/* When you call the EnumDisplaySettings function, the dmDisplayFrequency member
* may return with the value 0 or 1. These values represent the display hardware's
- * default refresh rate. This default rate is typically set by switches on a display
- * card or computer motherboard, or by a configuration program that does not use
- * Win32 display functions such as ChangeDisplaySettings.
+ * default refresh rate. This default rate is typically set by switches on a display
+ * card or computer motherboard, or by a configuration program that does not use
+ * Win32 display functions such as ChangeDisplaySettings.
*/
/* First, we tried to explicitly set the frequency to 60 if EnumDisplaySettings
* returned 0 or 1 but this doesn't work since later on an exact match will
diff --git a/intern/ghost/intern/GHOST_DisplayManagerWin32.h b/intern/ghost/intern/GHOST_DisplayManagerWin32.h
index ff8849f03c9..f0d6d62083c 100644
--- a/intern/ghost/intern/GHOST_DisplayManagerWin32.h
+++ b/intern/ghost/intern/GHOST_DisplayManagerWin32.h
@@ -69,7 +69,7 @@ public:
GHOST_TSuccess getNumDisplaySettings(GHOST_TUns8 display, GHOST_TInt32& numSettings) const;
/**
- * Returns the current setting for this display device.
+ * Returns the current setting for this display device.
* \param display The index of the display to query with 0 <= display < getNumDisplays().
* \param index The setting index to be returned.
* \param setting The setting of the display device with this index.
@@ -78,7 +78,7 @@ public:
GHOST_TSuccess getDisplaySetting(GHOST_TUns8 display, GHOST_TInt32 index, GHOST_DisplaySetting& setting) const;
/**
- * Returns the current setting for this display device.
+ * Returns the current setting for this display device.
* \param display The index of the display to query with 0 <= display < getNumDisplays().
* \param setting The current setting of the display device with this index.
* \return Indication of success.
@@ -86,7 +86,7 @@ public:
GHOST_TSuccess getCurrentDisplaySetting(GHOST_TUns8 display, GHOST_DisplaySetting& setting) const;
/**
- * Changes the current setting for this display device.
+ * Changes the current setting for this display device.
* \param display The index of the display to query with 0 <= display < getNumDisplays().
* \param setting The current setting of the display device with this index.
* \return Indication of success.
diff --git a/intern/ghost/intern/GHOST_DisplayManagerX11.cpp b/intern/ghost/intern/GHOST_DisplayManagerX11.cpp
index b3e6f2e53fa..8a629b2bf18 100644
--- a/intern/ghost/intern/GHOST_DisplayManagerX11.cpp
+++ b/intern/ghost/intern/GHOST_DisplayManagerX11.cpp
@@ -158,7 +158,7 @@ getDisplaySetting(
return GHOST_kSuccess;
}
-
+
GHOST_TSuccess
GHOST_DisplayManagerX11::
getCurrentDisplaySetting(
diff --git a/intern/ghost/intern/GHOST_DisplayManagerX11.h b/intern/ghost/intern/GHOST_DisplayManagerX11.h
index b54c53c67bd..857a8a5fce8 100644
--- a/intern/ghost/intern/GHOST_DisplayManagerX11.h
+++ b/intern/ghost/intern/GHOST_DisplayManagerX11.h
@@ -76,7 +76,7 @@ public:
) const;
/**
- * Returns the current setting for this display device.
+ * Returns the current setting for this display device.
* \param display The index of the display to query with 0 <= display < getNumDisplays().
* \param index The setting index to be returned.
* \param setting The setting of the display device with this index.
@@ -90,7 +90,7 @@ public:
) const;
/**
- * Returns the current setting for this display device.
+ * Returns the current setting for this display device.
* \param display The index of the display to query with 0 <= display < getNumDisplays().
* \param setting The current setting of the display device with this index.
* \return Indication of success.
@@ -102,7 +102,7 @@ public:
) const;
/**
- * Changes the current setting for this display device.
+ * Changes the current setting for this display device.
* \param display The index of the display to query with 0 <= display < getNumDisplays().
* \param setting The current setting of the display device with this index.
* \return Indication of success.
@@ -119,5 +119,5 @@ private:
};
-#endif //
+#endif //
diff --git a/intern/ghost/intern/GHOST_DropTargetWin32.cpp b/intern/ghost/intern/GHOST_DropTargetWin32.cpp
index cbf37bf1b16..79d7a2d48b4 100644
--- a/intern/ghost/intern/GHOST_DropTargetWin32.cpp
+++ b/intern/ghost/intern/GHOST_DropTargetWin32.cpp
@@ -29,7 +29,7 @@
* \ingroup GHOST
*/
-
+
#include "GHOST_Debug.h"
#include "GHOST_DropTargetWin32.h"
#include <shellapi.h>
@@ -59,7 +59,7 @@ GHOST_DropTargetWin32::~GHOST_DropTargetWin32()
}
-/*
+/*
* IUnknown::QueryInterface
*/
HRESULT __stdcall GHOST_DropTargetWin32::QueryInterface(REFIID riid, void **ppvObj)
@@ -81,8 +81,8 @@ HRESULT __stdcall GHOST_DropTargetWin32::QueryInterface(REFIID riid, void **ppvO
}
-/*
- * IUnknown::AddRef
+/*
+ * IUnknown::AddRef
*/
ULONG __stdcall GHOST_DropTargetWin32::AddRef(void)
@@ -90,13 +90,13 @@ ULONG __stdcall GHOST_DropTargetWin32::AddRef(void)
return ::InterlockedIncrement(&m_cRef);
}
-/*
+/*
* IUnknown::Release
*/
ULONG __stdcall GHOST_DropTargetWin32::Release(void)
{
ULONG refs = ::InterlockedDecrement(&m_cRef);
-
+
if (refs == 0) {
delete this;
return 0;
@@ -106,7 +106,7 @@ ULONG __stdcall GHOST_DropTargetWin32::Release(void)
}
}
-/*
+/*
* Implementation of IDropTarget::DragEnter
*/
HRESULT __stdcall GHOST_DropTargetWin32::DragEnter(IDataObject *pDataObject, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect)
@@ -114,13 +114,13 @@ HRESULT __stdcall GHOST_DropTargetWin32::DragEnter(IDataObject *pDataObject, DWO
// we accept all drop by default
m_window->setAcceptDragOperation(true);
*pdwEffect = DROPEFFECT_NONE;
-
+
m_draggedObjectType = getGhostType(pDataObject);
m_system->pushDragDropEvent(GHOST_kEventDraggingEntered, m_draggedObjectType, m_window, pt.x, pt.y, NULL);
return S_OK;
}
-/*
+/*
* Implementation of IDropTarget::DragOver
*/
HRESULT __stdcall GHOST_DropTargetWin32::DragOver(DWORD grfKeyState, POINTL pt, DWORD *pdwEffect)
@@ -136,7 +136,7 @@ HRESULT __stdcall GHOST_DropTargetWin32::DragOver(DWORD grfKeyState, POINTL pt,
return S_OK;
}
-/*
+/*
* Implementation of IDropTarget::DragLeave
*/
HRESULT __stdcall GHOST_DropTargetWin32::DragLeave(void)
@@ -147,7 +147,7 @@ HRESULT __stdcall GHOST_DropTargetWin32::DragLeave(void)
}
/* Implementation of IDropTarget::Drop
- * This function will not be called if pdwEffect is set to DROPEFFECT_NONE in
+ * This function will not be called if pdwEffect is set to DROPEFFECT_NONE in
* the implementation of IDropTarget::DragOver
*/
HRESULT __stdcall GHOST_DropTargetWin32::Drop(IDataObject *pDataObject, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect)
@@ -162,15 +162,15 @@ HRESULT __stdcall GHOST_DropTargetWin32::Drop(IDataObject *pDataObject, DWORD gr
}
if (data)
m_system->pushDragDropEvent(GHOST_kEventDraggingDropDone, m_draggedObjectType, m_window, pt.x, pt.y, data);
-
+
m_draggedObjectType = GHOST_kDragnDropTypeUnknown;
return S_OK;
}
-/*
+/*
* Helpers
*/
-
+
DWORD GHOST_DropTargetWin32::allowedDropEffect(DWORD dwAllowed)
{
DWORD dwEffect = DROPEFFECT_NONE;
@@ -264,7 +264,7 @@ void *GHOST_DropTargetWin32::getDropDataAsFilenames(IDataObject *pDataObject)
// Free up memory.
::GlobalUnlock(stgmed.hGlobal);
::ReleaseStgMedium(&stgmed);
-
+
return strArray;
}
}
@@ -301,7 +301,7 @@ void *GHOST_DropTargetWin32::getDropDataAsString(IDataObject *pDataObject)
if (pDataObject->QueryGetData(&fmtetc) == S_OK) {
if (pDataObject->GetData(&fmtetc, &stgmed) == S_OK) {
char *str = (char *)::GlobalLock(stgmed.hGlobal);
-
+
tmp_string = (char *)::malloc(::strlen(str) + 1);
if (!tmp_string) {
::GlobalUnlock(stgmed.hGlobal);
@@ -320,7 +320,7 @@ void *GHOST_DropTargetWin32::getDropDataAsString(IDataObject *pDataObject)
return tmp_string;
}
}
-
+
return NULL;
}
@@ -338,7 +338,7 @@ int GHOST_DropTargetWin32::WideCharToANSI(LPCWSTR in, char * &out)
0,
NULL, NULL
);
-
+
if (!size) {
#ifdef GHOST_DEBUG
::printLastError();
diff --git a/intern/ghost/intern/GHOST_DropTargetWin32.h b/intern/ghost/intern/GHOST_DropTargetWin32.h
index 56bae1fd1b2..3d7be45799f 100644
--- a/intern/ghost/intern/GHOST_DropTargetWin32.h
+++ b/intern/ghost/intern/GHOST_DropTargetWin32.h
@@ -41,11 +41,11 @@ class GHOST_DropTargetWin32 : public IDropTarget
{
public:
/* IUnknownd implementation.
- * Enables clients to get pointers to other interfaces on a given object
+ * Enables clients to get pointers to other interfaces on a given object
* through the QueryInterface method, and manage the existence of the object
- * through the AddRef and Release methods. All other COM interfaces are
- * inherited, directly or indirectly, from IUnknown. Therefore, the three
- * methods in IUnknown are the first entries in the VTable for every interface.
+ * through the AddRef and Release methods. All other COM interfaces are
+ * inherited, directly or indirectly, from IUnknown. Therefore, the three
+ * methods in IUnknown are the first entries in the VTable for every interface.
*/
HRESULT __stdcall QueryInterface(REFIID riid, void **ppvObj);
ULONG __stdcall AddRef(void);
@@ -56,20 +56,20 @@ public:
* provide drag-and-drop operations in your application. It contains methods
* used in any application that can be a target for data during a
* drag-and-drop operation. A drop-target application is responsible for:
- *
+ *
* - Determining the effect of the drop on the target application.
* - Incorporating any valid dropped data when the drop occurs.
* - Communicating target feedback to the source so the source application
* can provide appropriate visual feedback such as setting the cursor.
* - Implementing drag scrolling.
* - Registering and revoking its application windows as drop targets.
- *
- * The IDropTarget interface contains methods that handle all these
- * responsibilities except registering and revoking the application window
- * as a drop target, for which you must call the RegisterDragDrop and the
+ *
+ * The IDropTarget interface contains methods that handle all these
+ * responsibilities except registering and revoking the application window
+ * as a drop target, for which you must call the RegisterDragDrop and the
* RevokeDragDrop functions.
*/
-
+
HRESULT __stdcall DragEnter(IDataObject *pDataObject, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect);
HRESULT __stdcall DragOver(DWORD grfKeyState, POINTL pt, DWORD *pdwEffect);
HRESULT __stdcall DragLeave(void);
@@ -133,7 +133,7 @@ private:
/**
* Convert Unicode to ANSI, replacing unconvertable chars with '?'.
- * The ANSI codepage is the system default codepage,
+ * The ANSI codepage is the system default codepage,
* and can change from system to system.
* \param in LPCWSTR.
* \param out char *. Is set to NULL on failure.
diff --git a/intern/ghost/intern/GHOST_Event.h b/intern/ghost/intern/GHOST_Event.h
index 6a715498b87..278870738c2 100644
--- a/intern/ghost/intern/GHOST_Event.h
+++ b/intern/ghost/intern/GHOST_Event.h
@@ -60,7 +60,7 @@ public:
* \return The event type.
*/
GHOST_TEventType getType()
- {
+ {
return m_type;
}
@@ -74,7 +74,7 @@ public:
}
/**
- * Returns the window this event was generated on,
+ * Returns the window this event was generated on,
* or NULL if it is a 'system' event.
* \return The generating window.
*/
diff --git a/intern/ghost/intern/GHOST_EventDragnDrop.h b/intern/ghost/intern/GHOST_EventDragnDrop.h
index b7bf37c99d8..c9f4f08b53c 100644
--- a/intern/ghost/intern/GHOST_EventDragnDrop.h
+++ b/intern/ghost/intern/GHOST_EventDragnDrop.h
@@ -41,9 +41,9 @@ extern "C" {
/**
* Drag & drop event
- *
+ *
* The dragging sequence is performed in four phases:
- *
+ *
* <li> Start sequence (GHOST_kEventDraggingEntered) that tells a drag'n'drop operation has started.
* Already gives the object data type, and the entering mouse location
*
@@ -93,13 +93,13 @@ public:
m_dragnDropEventData.data = data;
m_data = &m_dragnDropEventData;
}
-
+
~GHOST_EventDragnDrop()
{
//Free the dropped object data
if (m_dragnDropEventData.data == NULL)
return;
-
+
switch (m_dragnDropEventData.dataType) {
case GHOST_kDragnDropTypeBitmap:
IMB_freeImBuf((ImBuf *)m_dragnDropEventData.data);
@@ -108,10 +108,10 @@ public:
{
GHOST_TStringArray *strArray = (GHOST_TStringArray *)m_dragnDropEventData.data;
int i;
-
+
for (i = 0; i < strArray->count; i++)
free(strArray->strings[i]);
-
+
free(strArray->strings);
free(strArray);
}
@@ -124,8 +124,8 @@ public:
break;
}
}
-
-
+
+
protected:
/** The x,y-coordinates of the cursor position. */
diff --git a/intern/ghost/intern/GHOST_EventKey.h b/intern/ghost/intern/GHOST_EventKey.h
index 54e38c00d05..7e867596503 100644
--- a/intern/ghost/intern/GHOST_EventKey.h
+++ b/intern/ghost/intern/GHOST_EventKey.h
@@ -60,7 +60,7 @@ public:
m_keyEventData.utf8_buf[0] = '\0';
m_data = &m_keyEventData;
}
-
+
/**
* Constructor.
* \param msec The time this event was generated.
@@ -82,7 +82,7 @@ public:
else m_keyEventData.utf8_buf[0] = '\0';
m_data = &m_keyEventData;
}
-
+
protected:
/** The key event data. */
GHOST_TEventKeyData m_keyEventData;
diff --git a/intern/ghost/intern/GHOST_EventManager.cpp b/intern/ghost/intern/GHOST_EventManager.cpp
index 0675ac734ed..bf92fa4517b 100644
--- a/intern/ghost/intern/GHOST_EventManager.cpp
+++ b/intern/ghost/intern/GHOST_EventManager.cpp
@@ -127,7 +127,7 @@ GHOST_TSuccess GHOST_EventManager::addConsumer(GHOST_IEventConsumer *consumer)
{
GHOST_TSuccess success;
GHOST_ASSERT(consumer, "invalid consumer");
-
+
// Check to see whether the consumer is already in our list
TConsumerVector::const_iterator iter = std::find(m_consumers.begin(), m_consumers.end(), consumer);
diff --git a/intern/ghost/intern/GHOST_EventManager.h b/intern/ghost/intern/GHOST_EventManager.h
index ae2971ea1a8..efad19616ad 100644
--- a/intern/ghost/intern/GHOST_EventManager.h
+++ b/intern/ghost/intern/GHOST_EventManager.h
@@ -143,7 +143,7 @@ protected:
/** A stack with events. */
typedef std::deque<GHOST_IEvent *> TEventStack;
-
+
/** The event stack. */
std::deque<GHOST_IEvent *> m_events;
std::deque<GHOST_IEvent *> m_handled_events;
diff --git a/intern/ghost/intern/GHOST_EventNDOF.h b/intern/ghost/intern/GHOST_EventNDOF.h
index 754e1091860..b81f74becee 100644
--- a/intern/ghost/intern/GHOST_EventNDOF.h
+++ b/intern/ghost/intern/GHOST_EventNDOF.h
@@ -4,7 +4,7 @@
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
+ * of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
diff --git a/intern/ghost/intern/GHOST_EventPrinter.cpp b/intern/ghost/intern/GHOST_EventPrinter.cpp
index a6adba12152..221b85b80ba 100644
--- a/intern/ghost/intern/GHOST_EventPrinter.cpp
+++ b/intern/ghost/intern/GHOST_EventPrinter.cpp
@@ -41,7 +41,7 @@
bool GHOST_EventPrinter::processEvent(GHOST_IEvent *event)
{
bool handled = true;
-
+
GHOST_ASSERT(event, "event==0");
if (event->getType() == GHOST_kEventWindowUpdate) return false;
@@ -95,7 +95,7 @@ bool GHOST_EventPrinter::processEvent(GHOST_IEvent *event)
std::cout << "GHOST_kEventKeyDown, key: " << str;
}
break;
-
+
case GHOST_kEventDraggingEntered:
{
GHOST_TEventDragnDropData *dragnDropData = (GHOST_TEventDragnDropData *)((GHOST_IEvent *)event)->getData();
@@ -103,7 +103,7 @@ bool GHOST_EventPrinter::processEvent(GHOST_IEvent *event)
std::cout << " mouse at x=" << dragnDropData->x << " y=" << dragnDropData->y;
}
break;
-
+
case GHOST_kEventDraggingUpdated:
{
GHOST_TEventDragnDropData *dragnDropData = (GHOST_TEventDragnDropData *)((GHOST_IEvent *)event)->getData();
@@ -118,7 +118,7 @@ bool GHOST_EventPrinter::processEvent(GHOST_IEvent *event)
std::cout << "GHOST_kEventDraggingExited, dragged object type : " << dragnDropData->dataType;
}
break;
-
+
case GHOST_kEventDraggingDropDone:
{
GHOST_TEventDragnDropData *dragnDropData = (GHOST_TEventDragnDropData *)((GHOST_IEvent *)event)->getData();
@@ -148,14 +148,14 @@ bool GHOST_EventPrinter::processEvent(GHOST_IEvent *event)
case GHOST_kEventOpenMainFile:
{
GHOST_TEventDataPtr eventData = ((GHOST_IEvent *)event)->getData();
-
+
if (eventData)
std::cout << "GHOST_kEventOpenMainFile for path : " << (char *)eventData;
else
std::cout << "GHOST_kEventOpenMainFile with no path specified!!";
}
break;
-
+
case GHOST_kEventQuit:
std::cout << "GHOST_kEventQuit";
break;
diff --git a/intern/ghost/intern/GHOST_ISystemPaths.cpp b/intern/ghost/intern/GHOST_ISystemPaths.cpp
index 93ca0bc3880..8bd7fbe4f9b 100644
--- a/intern/ghost/intern/GHOST_ISystemPaths.cpp
+++ b/intern/ghost/intern/GHOST_ISystemPaths.cpp
@@ -67,7 +67,7 @@ GHOST_TSuccess GHOST_ISystemPaths::create()
# else
m_systemPaths = new GHOST_SystemPathsUnix();
# endif
-#endif
+#endif
success = m_systemPaths != NULL ? GHOST_kSuccess : GHOST_kFailure;
}
else {
diff --git a/intern/ghost/intern/GHOST_NDOFManager.cpp b/intern/ghost/intern/GHOST_NDOFManager.cpp
index cab9bf45b80..1f2af73b743 100644
--- a/intern/ghost/intern/GHOST_NDOFManager.cpp
+++ b/intern/ghost/intern/GHOST_NDOFManager.cpp
@@ -4,7 +4,7 @@
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
+ * of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
diff --git a/intern/ghost/intern/GHOST_NDOFManager.h b/intern/ghost/intern/GHOST_NDOFManager.h
index 0c0b945d548..78f24e07a6e 100644
--- a/intern/ghost/intern/GHOST_NDOFManager.h
+++ b/intern/ghost/intern/GHOST_NDOFManager.h
@@ -4,7 +4,7 @@
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
+ * of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
diff --git a/intern/ghost/intern/GHOST_NDOFManagerCocoa.h b/intern/ghost/intern/GHOST_NDOFManagerCocoa.h
index 3f1bfcf57fc..6e676faba1e 100644
--- a/intern/ghost/intern/GHOST_NDOFManagerCocoa.h
+++ b/intern/ghost/intern/GHOST_NDOFManagerCocoa.h
@@ -4,7 +4,7 @@
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
+ * of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
diff --git a/intern/ghost/intern/GHOST_NDOFManagerUnix.cpp b/intern/ghost/intern/GHOST_NDOFManagerUnix.cpp
index fff5aba6f9e..624d39b6347 100644
--- a/intern/ghost/intern/GHOST_NDOFManagerUnix.cpp
+++ b/intern/ghost/intern/GHOST_NDOFManagerUnix.cpp
@@ -4,7 +4,7 @@
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
+ * of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
diff --git a/intern/ghost/intern/GHOST_NDOFManagerUnix.h b/intern/ghost/intern/GHOST_NDOFManagerUnix.h
index 3fd171d9e76..8d83ac7b670 100644
--- a/intern/ghost/intern/GHOST_NDOFManagerUnix.h
+++ b/intern/ghost/intern/GHOST_NDOFManagerUnix.h
@@ -4,7 +4,7 @@
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
+ * of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -20,7 +20,7 @@
*
* ***** END GPL LICENSE BLOCK *****
*/
-
+
#ifndef __GHOST_NDOFMANAGERUNIX_H__
#define __GHOST_NDOFMANAGERUNIX_H__
diff --git a/intern/ghost/intern/GHOST_NDOFManagerWin32.cpp b/intern/ghost/intern/GHOST_NDOFManagerWin32.cpp
index 0023ee7e1d0..fbdac249eb0 100644
--- a/intern/ghost/intern/GHOST_NDOFManagerWin32.cpp
+++ b/intern/ghost/intern/GHOST_NDOFManagerWin32.cpp
@@ -1,11 +1,11 @@
/*
- *
+ *
* ***** BEGIN GPL LICENSE BLOCK *****
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
+ * of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
diff --git a/intern/ghost/intern/GHOST_NDOFManagerWin32.h b/intern/ghost/intern/GHOST_NDOFManagerWin32.h
index 2f7bc9ee732..522a79ffc0c 100644
--- a/intern/ghost/intern/GHOST_NDOFManagerWin32.h
+++ b/intern/ghost/intern/GHOST_NDOFManagerWin32.h
@@ -4,7 +4,7 @@
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
+ * of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
diff --git a/intern/ghost/intern/GHOST_Rect.cpp b/intern/ghost/intern/GHOST_Rect.cpp
index 9af4f30ebc1..646dae9f242 100644
--- a/intern/ghost/intern/GHOST_Rect.cpp
+++ b/intern/ghost/intern/GHOST_Rect.cpp
@@ -108,7 +108,7 @@ void GHOST_Rect::setCenter(GHOST_TInt32 cx, GHOST_TInt32 cy)
void GHOST_Rect::setCenter(GHOST_TInt32 cx, GHOST_TInt32 cy, GHOST_TInt32 w, GHOST_TInt32 h)
{
long w_2, h_2;
-
+
w_2 = w >> 1;
h_2 = h >> 1;
m_l = cx - w_2;
diff --git a/intern/ghost/intern/GHOST_System.cpp b/intern/ghost/intern/GHOST_System.cpp
index 4db2f0616d7..f849993ae6d 100644
--- a/intern/ghost/intern/GHOST_System.cpp
+++ b/intern/ghost/intern/GHOST_System.cpp
@@ -113,7 +113,7 @@ GHOST_TSuccess GHOST_System::disposeWindow(GHOST_IWindow *window)
/*
* Remove all pending events for the window.
- */
+ */
if (m_windowManager->getWindowFound(window)) {
m_eventManager->removeWindowEvents(window);
}
@@ -272,7 +272,7 @@ GHOST_TSuccess GHOST_System::pushEvent(GHOST_IEvent *event)
GHOST_TSuccess GHOST_System::getModifierKeyState(GHOST_TModifierKeyMask mask, bool& isDown) const
{
GHOST_ModifierKeys keys;
- // Get the state of all modifier keys
+ // Get the state of all modifier keys
GHOST_TSuccess success = getModifierKeys(keys);
if (success) {
// Isolate the state of the key requested
@@ -306,7 +306,7 @@ GHOST_TSuccess GHOST_System::init()
m_timerManager = new GHOST_TimerManager();
m_windowManager = new GHOST_WindowManager();
m_eventManager = new GHOST_EventManager();
-
+
#ifdef GHOST_DEBUG
if (m_eventManager) {
m_eventPrinter = new GHOST_EventPrinter();
diff --git a/intern/ghost/intern/GHOST_System.h b/intern/ghost/intern/GHOST_System.h
index 50c893b1113..6831b3d07d9 100644
--- a/intern/ghost/intern/GHOST_System.h
+++ b/intern/ghost/intern/GHOST_System.h
@@ -91,7 +91,7 @@ public:
/**
* Installs a timer.
- * Note that, on most operating systems, messages need to be processed in order
+ * Note that, on most operating systems, messages need to be processed in order
* for the timer callbacks to be invoked.
* \param delay The time to wait for the first call to the timerProc (in milliseconds)
* \param interval The interval between calls to the timerProc
@@ -114,7 +114,7 @@ public:
/***************************************************************************************
* Display/window management functionality
***************************************************************************************/
-
+
/**
* Inherited from GHOST_ISystem but left pure virtual
*
@@ -169,7 +169,7 @@ public:
*/
bool getFullScreen(void);
-
+
/**
* Native pixel size support (MacBook 'retina').
* \return The pixel size in float.
@@ -237,7 +237,7 @@ public:
* \return Indication of success.
*/
GHOST_TSuccess getButtonState(GHOST_TButtonMask mask, bool& isDown) const;
-
+
#ifdef WITH_INPUT_NDOF
/***************************************************************************************
* Access to 3D mouse.
@@ -305,7 +305,7 @@ public:
*
*/
virtual GHOST_TUns8 *getClipboard(bool selection) const = 0;
-
+
/**
* Put data to the Clipboard
* \param buffer The buffer to copy to the clipboard
@@ -324,7 +324,7 @@ public:
*/
virtual bool supportsNativeDialogs(void);
-
+
protected:
/**
* Initialize the system.
@@ -362,7 +362,7 @@ protected:
/** The N-degree of freedom device manager */
GHOST_NDOFManager *m_ndofManager;
#endif
-
+
/** Prints all the events. */
#ifdef GHOST_DEBUG
GHOST_EventPrinter *m_eventPrinter;
@@ -370,7 +370,7 @@ protected:
/** Settings of the display before the display went fullscreen. */
GHOST_DisplaySetting m_preFullScreenSetting;
-
+
};
inline GHOST_TimerManager *GHOST_System::getTimerManager() const
diff --git a/intern/ghost/intern/GHOST_SystemCocoa.h b/intern/ghost/intern/GHOST_SystemCocoa.h
index 8586c91b615..f0702737b46 100644
--- a/intern/ghost/intern/GHOST_SystemCocoa.h
+++ b/intern/ghost/intern/GHOST_SystemCocoa.h
@@ -88,7 +88,7 @@ public:
* \return The dimension of the main display.
*/
void getMainDisplayDimensions(GHOST_TUns32& width, GHOST_TUns32& height) const;
-
+
/** Returns the combine dimensions of all monitors.
* \return The dimension of the workspace.
*/
@@ -122,7 +122,7 @@ public:
const bool exclusive = false,
const GHOST_TEmbedderWindowID parentWindow = 0
);
-
+
/**
* Create a new offscreen context.
* Never explicitly delete the context, use disposeContext() instead.
@@ -152,19 +152,19 @@ public:
* \return Indication of the presence of events.
*/
bool processEvents(bool waitForEvent);
-
+
/**
* Handle User request to quit, from Menu bar Quit, and Cmd+Q
* Display alert panel if changes performed since last save
*/
GHOST_TUns8 handleQuitRequest();
-
+
/**
* Handle Cocoa openFile event
* Display confirmation request panel if changes performed since last save
*/
bool handleOpenDocumentRequest(void *filepathStr);
-
+
/**
* Handles a drag'n'drop destination event. Called by GHOST_WindowCocoa window subclass
* \param eventType The type of drag'n'drop event
@@ -176,7 +176,7 @@ public:
*/
GHOST_TSuccess handleDraggingEvent(GHOST_TEventType eventType, GHOST_TDragnDropTypes draggedObjectType,
GHOST_WindowCocoa *window, int mouseX, int mouseY, void *data);
-
+
/***************************************************************************************
* Cursor management functionality
***************************************************************************************/
@@ -196,7 +196,7 @@ public:
* \return Indication of success.
*/
GHOST_TSuccess setCursorPosition(GHOST_TInt32 x, GHOST_TInt32 y);
-
+
/***************************************************************************************
* Access to mouse button and keyboard states.
***************************************************************************************/
@@ -221,7 +221,7 @@ public:
* \return Returns the selected buffer
*/
GHOST_TUns8 *getClipboard(bool selection) const;
-
+
/**
* Puts buffer to system clipboard
* \param buffer The buffer to be copied
@@ -236,7 +236,7 @@ public:
* \return Indication whether the event was handled.
*/
GHOST_TSuccess handleWindowEvent(GHOST_TEventType eventType, GHOST_WindowCocoa *window);
-
+
/**
* Handles the Cocoa event telling the application has become active (again)
* \return Indication whether the event was handled.
@@ -254,7 +254,7 @@ public:
int toggleConsole(int action) {
return 0;
}
-
+
/**
* Handles a tablet event.
* \param eventPtr An NSEvent pointer (casted to void* to enable compilation in standard C++)
@@ -279,7 +279,7 @@ public:
* \return Indication whether the event was handled.
*/
GHOST_TSuccess handleKeyEvent(void *eventPtr);
-
+
/**
* Informs if the system provides native dialogs (eg. confirm quit)
*/
@@ -303,19 +303,19 @@ protected:
/** Start time at initialization. */
GHOST_TUns64 m_start_time;
-
+
/** Event has been processed directly by Cocoa (or NDOF manager) and has sent a ghost event to be dispatched */
bool m_outsideLoopEventProcessed;
-
+
/** Raised window is not yet known by the window manager, so delay application become active event handling */
bool m_needDelayedApplicationBecomeActiveEventProcessing;
-
+
/** State of the modifiers. */
GHOST_TUns32 m_modifierMask;
/** Ignores window size messages (when window is dragged). */
bool m_ignoreWindowSizedMessages;
-
+
/** Temporarily ignore momentum scroll events */
bool m_ignoreMomentumScroll;
/** Is the scroll wheel event generated by a multitouch trackpad or mouse? */
diff --git a/intern/ghost/intern/GHOST_SystemPaths.h b/intern/ghost/intern/GHOST_SystemPaths.h
index 22879c71e1e..fbaa8ad8ba5 100644
--- a/intern/ghost/intern/GHOST_SystemPaths.h
+++ b/intern/ghost/intern/GHOST_SystemPaths.h
@@ -4,7 +4,7 @@
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
+ * of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -18,7 +18,7 @@
* The Original Code is Copyright (C) 2009 Blender Foundation.
* All rights reserved.
*
- *
+ *
* Contributor(s): Blender Foundation
*
* ***** END GPL LICENSE BLOCK *****
diff --git a/intern/ghost/intern/GHOST_SystemPathsCocoa.h b/intern/ghost/intern/GHOST_SystemPathsCocoa.h
index 1c76284857c..3a1f3e1aacf 100644
--- a/intern/ghost/intern/GHOST_SystemPathsCocoa.h
+++ b/intern/ghost/intern/GHOST_SystemPathsCocoa.h
@@ -4,7 +4,7 @@
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
+ * of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -18,7 +18,7 @@
* The Original Code is Copyright (C) 2010 Blender Foundation.
* All rights reserved.
*
- *
+ *
* Contributor(s): Damien Plisson 2010
*
* ***** END GPL LICENSE BLOCK *****
diff --git a/intern/ghost/intern/GHOST_SystemPathsUnix.cpp b/intern/ghost/intern/GHOST_SystemPathsUnix.cpp
index 8738b8dd0fe..b4e1259d824 100644
--- a/intern/ghost/intern/GHOST_SystemPathsUnix.cpp
+++ b/intern/ghost/intern/GHOST_SystemPathsUnix.cpp
@@ -4,7 +4,7 @@
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
+ * of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -18,7 +18,7 @@
* The Original Code is Copyright (C) 2010 Blender Foundation.
* All rights reserved.
*
- *
+ *
* Contributor(s): Blender Foundation
*
* ***** END GPL LICENSE BLOCK *****
diff --git a/intern/ghost/intern/GHOST_SystemPathsUnix.h b/intern/ghost/intern/GHOST_SystemPathsUnix.h
index 1502160c8d6..69c37c00ce0 100644
--- a/intern/ghost/intern/GHOST_SystemPathsUnix.h
+++ b/intern/ghost/intern/GHOST_SystemPathsUnix.h
@@ -4,7 +4,7 @@
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
+ * of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -18,7 +18,7 @@
* The Original Code is Copyright (C) 2010 Blender Foundation.
* All rights reserved.
*
- *
+ *
* Contributor(s): Blender Foundation
*
* ***** END GPL LICENSE BLOCK *****
@@ -44,7 +44,7 @@ public:
* this class should only be instanciated by GHOST_ISystem.
*/
GHOST_SystemPathsUnix();
-
+
/**
* Destructor.
*/
diff --git a/intern/ghost/intern/GHOST_SystemPathsWin32.cpp b/intern/ghost/intern/GHOST_SystemPathsWin32.cpp
index 8056bc76edb..d122d3dd51f 100644
--- a/intern/ghost/intern/GHOST_SystemPathsWin32.cpp
+++ b/intern/ghost/intern/GHOST_SystemPathsWin32.cpp
@@ -17,7 +17,7 @@
*
* The Original Code is Copyright (C) 2011 Blender Foundation.
* All rights reserved.
- *
+ *
* Contributor(s): Blender Foundation
* Andrea Weikert
*
diff --git a/intern/ghost/intern/GHOST_SystemWin32.cpp b/intern/ghost/intern/GHOST_SystemWin32.cpp
index ccc90e363b7..625a34aa142 100644
--- a/intern/ghost/intern/GHOST_SystemWin32.cpp
+++ b/intern/ghost/intern/GHOST_SystemWin32.cpp
@@ -240,7 +240,7 @@ GHOST_TUns64 GHOST_SystemWin32::getMilliSeconds() const
__int64 delta = 1000 * (count - m_start);
GHOST_TUns64 t = (GHOST_TUns64)(delta / m_freq);
- return t;
+ return t;
}
@@ -407,7 +407,7 @@ bool GHOST_SystemWin32::processEvents(bool waitForEvent)
#else
GHOST_TUns64 next = timerMgr->nextFireTime();
GHOST_TInt64 maxSleep = next - getMilliSeconds();
-
+
if (next == GHOST_kFireTimeNever) {
::WaitMessage();
}
@@ -469,17 +469,17 @@ GHOST_TSuccess GHOST_SystemWin32::getModifierKeys(GHOST_ModifierKeys &keys) cons
keys.set(GHOST_kModifierKeyLeftShift, down);
down = HIBYTE(::GetKeyState(VK_RSHIFT)) != 0;
keys.set(GHOST_kModifierKeyRightShift, down);
-
+
down = HIBYTE(::GetKeyState(VK_LMENU)) != 0;
keys.set(GHOST_kModifierKeyLeftAlt, down);
down = HIBYTE(::GetKeyState(VK_RMENU)) != 0;
keys.set(GHOST_kModifierKeyRightAlt, down);
-
+
down = HIBYTE(::GetKeyState(VK_LCONTROL)) != 0;
keys.set(GHOST_kModifierKeyLeftControl, down);
down = HIBYTE(::GetKeyState(VK_RCONTROL)) != 0;
keys.set(GHOST_kModifierKeyRightControl, down);
-
+
bool lwindown = HIBYTE(::GetKeyState(VK_LWIN)) != 0;
bool rwindown = HIBYTE(::GetKeyState(VK_RWIN)) != 0;
if (lwindown || rwindown)
@@ -512,7 +512,7 @@ GHOST_TSuccess GHOST_SystemWin32::getButtons(GHOST_Buttons &buttons) const
GHOST_TSuccess GHOST_SystemWin32::init()
{
GHOST_TSuccess success = GHOST_System::init();
-
+
/* Disable scaling on high DPI displays on Vista */
HMODULE
user32 = ::LoadLibraryA("user32.dll");
@@ -542,12 +542,12 @@ GHOST_TSuccess GHOST_SystemWin32::init()
wc.cbWndExtra = 0;
wc.hInstance = ::GetModuleHandle(0);
wc.hIcon = ::LoadIcon(wc.hInstance, "APPICON");
-
+
if (!wc.hIcon) {
::LoadIcon(NULL, IDI_APPLICATION);
}
wc.hCursor = ::LoadCursor(0, IDC_ARROW);
- wc.hbrBackground =
+ wc.hbrBackground =
#ifdef INW32_COMPISITING
(HBRUSH)CreateSolidBrush
#endif
@@ -560,7 +560,7 @@ GHOST_TSuccess GHOST_SystemWin32::init()
success = GHOST_kFailure;
}
}
-
+
return success;
}
@@ -583,7 +583,7 @@ GHOST_TKey GHOST_SystemWin32::hardKey(RAWINPUT const &raw, int *keyDown, char *v
*keyDown = !(raw.data.keyboard.Flags & RI_KEY_BREAK) && msg != WM_KEYUP && msg != WM_SYSKEYUP;
key = this->convertKey(raw.data.keyboard.VKey, raw.data.keyboard.MakeCode, (raw.data.keyboard.Flags & (RI_KEY_E1 | RI_KEY_E0)));
-
+
// extra handling of modifier keys: don't send repeats out from GHOST
if (key >= GHOST_kKeyLeftShift && key <= GHOST_kKeyRightAlt) {
bool changed = false;
@@ -628,7 +628,7 @@ GHOST_TKey GHOST_SystemWin32::hardKey(RAWINPUT const &raw, int *keyDown, char *v
default:
break;
}
-
+
if (changed) {
modifiers.set(modifier, (bool)*keyDown);
system->storeModifierKeys(modifiers);
@@ -637,7 +637,7 @@ GHOST_TKey GHOST_SystemWin32::hardKey(RAWINPUT const &raw, int *keyDown, char *v
key = GHOST_kKeyUnknown;
}
}
-
+
if (vk) *vk = raw.data.keyboard.VKey;
@@ -682,7 +682,7 @@ GHOST_TKey GHOST_SystemWin32::convertKey(short vKey, short scanCode, short exten
switch (vKey) {
case VK_RETURN:
key = (extend) ? GHOST_kKeyNumpadEnter : GHOST_kKeyEnter; break;
-
+
case VK_BACK: key = GHOST_kKeyBackSpace; break;
case VK_TAB: key = GHOST_kKeyTab; break;
case VK_ESCAPE: key = GHOST_kKeyEsc; break;
@@ -782,7 +782,7 @@ GHOST_TKey GHOST_SystemWin32::convertKey(short vKey, short scanCode, short exten
break;
}
}
-
+
return key;
}
@@ -799,7 +799,7 @@ GHOST_EventCursor *GHOST_SystemWin32::processCursorEvent(GHOST_TEventType type,
{
GHOST_TInt32 x_screen, y_screen;
GHOST_SystemWin32 *system = (GHOST_SystemWin32 *) getSystem();
-
+
system->getCursorPosition(x_screen, y_screen);
/* TODO: CHECK IF THIS IS A TABLET EVENT */
@@ -856,7 +856,7 @@ void GHOST_SystemWin32::processWheelEvent(GHOST_WindowWin32 *window, WPARAM wPar
int acc = system->m_wheelDeltaAccum;
int delta = GET_WHEEL_DELTA_WPARAM(wParam);
-
+
if (acc * delta < 0) {
// scroll direction reversed.
acc = 0;
@@ -864,7 +864,7 @@ void GHOST_SystemWin32::processWheelEvent(GHOST_WindowWin32 *window, WPARAM wPar
acc += delta;
int direction = (acc >= 0) ? 1 : -1;
acc = abs(acc);
-
+
while (acc >= WHEEL_DELTA) {
system->pushEvent(new GHOST_EventWheel(system->getMilliSeconds(), window, direction));
acc -= WHEEL_DELTA;
@@ -1178,10 +1178,10 @@ LRESULT WINAPI GHOST_SystemWin32::s_wndProc(HWND hwnd, UINT msg, WPARAM wParam,
*/
case WM_DEADCHAR:
/* The WM_DEADCHAR message is posted to the window with the keyboard focus when a
- * WM_KEYUP message is translated by the TranslateMessage function. WM_DEADCHAR
- * specifies a character code generated by a dead key. A dead key is a key that
- * generates a character, such as the umlaut (double-dot), that is combined with
- * another character to form a composite character. For example, the umlaut-O
+ * WM_KEYUP message is translated by the TranslateMessage function. WM_DEADCHAR
+ * specifies a character code generated by a dead key. A dead key is a key that
+ * generates a character, such as the umlaut (double-dot), that is combined with
+ * another character to form a composite character. For example, the umlaut-O
* character (Ö) is generated by typing the dead key for the umlaut character, and
* then typing the O key.
*/
@@ -1193,16 +1193,16 @@ LRESULT WINAPI GHOST_SystemWin32::s_wndProc(HWND hwnd, UINT msg, WPARAM wParam,
* a dead key that is pressed while holding down the alt key.
*/
case WM_SYSCHAR:
- /* The WM_SYSCHAR message is sent to the window with the keyboard focus when
- * a WM_SYSCHAR message is translated by the TranslateMessage function.
- * WM_SYSCHAR specifies the character code of a dead key - that is,
+ /* The WM_SYSCHAR message is sent to the window with the keyboard focus when
+ * a WM_SYSCHAR message is translated by the TranslateMessage function.
+ * WM_SYSCHAR specifies the character code of a dead key - that is,
* a dead key that is pressed while holding down the alt key.
* To prevent the sound, DefWindowProc must be avoided by return
*/
break;
case WM_SYSCOMMAND:
- /* The WM_SYSCHAR message is sent to the window when system commands such as
- * maximize, minimize or close the window are triggered. Also it is sent when ALT
+ /* The WM_SYSCHAR message is sent to the window when system commands such as
+ * maximize, minimize or close the window are triggered. Also it is sent when ALT
* button is press for menu. To prevent this we must return preventing DefWindowProc.
*/
if (wParam == SC_KEYMENU) {
@@ -1269,11 +1269,11 @@ LRESULT WINAPI GHOST_SystemWin32::s_wndProc(HWND hwnd, UINT msg, WPARAM wParam,
break;
case WM_MOUSEWHEEL:
{
- /* The WM_MOUSEWHEEL message is sent to the focus window
- * when the mouse wheel is rotated. The DefWindowProc
+ /* The WM_MOUSEWHEEL message is sent to the focus window
+ * when the mouse wheel is rotated. The DefWindowProc
* function propagates the message to the window's parent.
- * There should be no internal forwarding of the message,
- * since DefWindowProc propagates it up the parent chain
+ * There should be no internal forwarding of the message,
+ * since DefWindowProc propagates it up the parent chain
* until it finds a window that processes it.
*/
@@ -1281,7 +1281,7 @@ LRESULT WINAPI GHOST_SystemWin32::s_wndProc(HWND hwnd, UINT msg, WPARAM wParam,
POINT mouse_pos = {GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)};
HWND mouse_hwnd = ChildWindowFromPoint(HWND_DESKTOP, mouse_pos);
GHOST_WindowWin32 *mouse_window = (GHOST_WindowWin32 *)::GetWindowLongPtr(mouse_hwnd, GWLP_USERDATA);
-
+
processWheelEvent(mouse_window ? mouse_window : window , wParam, lParam);
eventHandled = true;
#ifdef BROKEN_PEEK_TOUCHPAD
@@ -1293,7 +1293,7 @@ LRESULT WINAPI GHOST_SystemWin32::s_wndProc(HWND hwnd, UINT msg, WPARAM wParam,
/* The WM_SETCURSOR message is sent to a window if the mouse causes the cursor
* to move within a window and mouse input is not captured.
* This means we have to set the cursor shape every time the mouse moves!
- * The DefWindowProc function uses this message to set the cursor to an
+ * The DefWindowProc function uses this message to set the cursor to an
* arrow if it is not in the client area.
*/
if (LOWORD(lParam) == HTCLIENT) {
@@ -1301,7 +1301,7 @@ LRESULT WINAPI GHOST_SystemWin32::s_wndProc(HWND hwnd, UINT msg, WPARAM wParam,
window->loadCursor(window->getCursorVisibility(), window->getCursorShape());
// Bypass call to DefWindowProc
return 0;
- }
+ }
else {
// Outside of client area show standard cursor
window->loadCursor(true, GHOST_kStandardCursorDefault);
@@ -1317,10 +1317,10 @@ LRESULT WINAPI GHOST_SystemWin32::s_wndProc(HWND hwnd, UINT msg, WPARAM wParam,
* that contains the cursor. If a window has captured the mouse, this message is not posted.
*/
case WM_NCHITTEST:
- /* The WM_NCHITTEST message is sent to a window when the cursor moves, or
- * when a mouse button is pressed or released. If the mouse is not captured,
- * the message is sent to the window beneath the cursor. Otherwise, the message
- * is sent to the window that has captured the mouse.
+ /* The WM_NCHITTEST message is sent to a window when the cursor moves, or
+ * when a mouse button is pressed or released. If the mouse is not captured,
+ * the message is sent to the window beneath the cursor. Otherwise, the message
+ * is sent to the window that has captured the mouse.
*/
break;
@@ -1332,11 +1332,11 @@ LRESULT WINAPI GHOST_SystemWin32::s_wndProc(HWND hwnd, UINT msg, WPARAM wParam,
event = processWindowEvent(GHOST_kEventWindowClose, window);
break;
case WM_ACTIVATE:
- /* The WM_ACTIVATE message is sent to both the window being activated and the window being
- * deactivated. If the windows use the same input queue, the message is sent synchronously,
+ /* The WM_ACTIVATE message is sent to both the window being activated and the window being
+ * deactivated. If the windows use the same input queue, the message is sent synchronously,
* first to the window procedure of the top-level window being deactivated, then to the window
* procedure of the top-level window being activated. If the windows use different input queues,
- * the message is sent asynchronously, so the window is activated immediately.
+ * the message is sent asynchronously, so the window is activated immediately.
*/
{
GHOST_ModifierKeys modifiers;
@@ -1353,12 +1353,12 @@ LRESULT WINAPI GHOST_SystemWin32::s_wndProc(HWND hwnd, UINT msg, WPARAM wParam,
break;
}
case WM_ENTERSIZEMOVE:
- /* The WM_ENTERSIZEMOVE message is sent one time to a window after it enters the moving
- * or sizing modal loop. The window enters the moving or sizing modal loop when the user
- * clicks the window's title bar or sizing border, or when the window passes the
- * WM_SYSCOMMAND message to the DefWindowProc function and the wParam parameter of the
- * message specifies the SC_MOVE or SC_SIZE value. The operation is complete when
- * DefWindowProc returns.
+ /* The WM_ENTERSIZEMOVE message is sent one time to a window after it enters the moving
+ * or sizing modal loop. The window enters the moving or sizing modal loop when the user
+ * clicks the window's title bar or sizing border, or when the window passes the
+ * WM_SYSCOMMAND message to the DefWindowProc function and the wParam parameter of the
+ * message specifies the SC_MOVE or SC_SIZE value. The operation is complete when
+ * DefWindowProc returns.
*/
window->m_inLiveResize = 1;
break;
@@ -1366,11 +1366,11 @@ LRESULT WINAPI GHOST_SystemWin32::s_wndProc(HWND hwnd, UINT msg, WPARAM wParam,
window->m_inLiveResize = 0;
break;
case WM_PAINT:
- /* An application sends the WM_PAINT message when the system or another application
+ /* An application sends the WM_PAINT message when the system or another application
* makes a request to paint a portion of an application's window. The message is sent
- * when the UpdateWindow or RedrawWindow function is called, or by the DispatchMessage
- * function when the application obtains a WM_PAINT message by using the GetMessage or
- * PeekMessage function.
+ * when the UpdateWindow or RedrawWindow function is called, or by the DispatchMessage
+ * function when the application obtains a WM_PAINT message by using the GetMessage or
+ * PeekMessage function.
*/
if (!window->m_inLiveResize) {
event = processWindowEvent(GHOST_kEventWindowUpdate, window);
@@ -1381,10 +1381,10 @@ LRESULT WINAPI GHOST_SystemWin32::s_wndProc(HWND hwnd, UINT msg, WPARAM wParam,
}
break;
case WM_GETMINMAXINFO:
- /* The WM_GETMINMAXINFO message is sent to a window when the size or
- * position of the window is about to change. An application can use
- * this message to override the window's default maximized size and
- * position, or its default minimum or maximum tracking size.
+ /* The WM_GETMINMAXINFO message is sent to a window when the size or
+ * position of the window is about to change. An application can use
+ * this message to override the window's default maximized size and
+ * position, or its default minimum or maximum tracking size.
*/
processMinMaxInfo((MINMAXINFO *) lParam);
/* Let DefWindowProc handle it. */
@@ -1392,9 +1392,9 @@ LRESULT WINAPI GHOST_SystemWin32::s_wndProc(HWND hwnd, UINT msg, WPARAM wParam,
case WM_SIZING:
case WM_SIZE:
/* The WM_SIZE message is sent to a window after its size has changed.
- * The WM_SIZE and WM_MOVE messages are not sent if an application handles the
+ * The WM_SIZE and WM_MOVE messages are not sent if an application handles the
* WM_WINDOWPOSCHANGED message without calling DefWindowProc. It is more efficient
- * to perform any move or size change processing during the WM_WINDOWPOSCHANGED
+ * to perform any move or size change processing during the WM_WINDOWPOSCHANGED
* message without calling DefWindowProc.
*/
/* we get first WM_SIZE before we fully init. So, do not dispatch before we continiously resizng */
@@ -1415,10 +1415,10 @@ LRESULT WINAPI GHOST_SystemWin32::s_wndProc(HWND hwnd, UINT msg, WPARAM wParam,
* and, if needed, change its size or position.
*/
case WM_MOVE:
- /* The WM_SIZE and WM_MOVE messages are not sent if an application handles the
+ /* The WM_SIZE and WM_MOVE messages are not sent if an application handles the
* WM_WINDOWPOSCHANGED message without calling DefWindowProc. It is more efficient
- * to perform any move or size change processing during the WM_WINDOWPOSCHANGED
- * message without calling DefWindowProc.
+ * to perform any move or size change processing during the WM_WINDOWPOSCHANGED
+ * message without calling DefWindowProc.
*/
/* see WM_SIZE comment*/
if (window->m_inLiveResize) {
@@ -1487,13 +1487,13 @@ LRESULT WINAPI GHOST_SystemWin32::s_wndProc(HWND hwnd, UINT msg, WPARAM wParam,
* that all child windows still exist.
*/
case WM_NCDESTROY:
- /* The WM_NCDESTROY message informs a window that its nonclient area is being destroyed. The
+ /* The WM_NCDESTROY message informs a window that its nonclient area is being destroyed. The
* DestroyWindow function sends the WM_NCDESTROY message to the window following the WM_DESTROY
- * message. WM_DESTROY is used to free the allocated memory object associated with the window.
+ * message. WM_DESTROY is used to free the allocated memory object associated with the window.
*/
break;
case WM_KILLFOCUS:
- /* The WM_KILLFOCUS message is sent to a window immediately before it loses the keyboard focus.
+ /* The WM_KILLFOCUS message is sent to a window immediately before it loses the keyboard focus.
* We want to prevent this if a window is still active and it loses focus to nowhere*/
if (!wParam && hwnd == ::GetActiveWindow())
::SetFocus(hwnd);
@@ -1526,7 +1526,7 @@ LRESULT WINAPI GHOST_SystemWin32::s_wndProc(HWND hwnd, UINT msg, WPARAM wParam,
* when a timer expires. You can process the message by providing a WM_TIMER
* case in the window procedure. Otherwise, the default window procedure will
* call the TimerProc callback function specified in the call to the SetTimer
- * function used to install the timer.
+ * function used to install the timer.
*
* In GHOST, we let DefWindowProc call the timer callback.
*/
@@ -1565,7 +1565,7 @@ LRESULT WINAPI GHOST_SystemWin32::s_wndProc(HWND hwnd, UINT msg, WPARAM wParam,
GHOST_TUns8 *GHOST_SystemWin32::getClipboard(bool selection) const
{
char *temp_buff;
-
+
if (IsClipboardFormatAvailable(CF_UNICODETEXT) && OpenClipboard(NULL) ) {
wchar_t *buffer;
HANDLE hData = GetClipboardData(CF_UNICODETEXT);
@@ -1578,14 +1578,14 @@ GHOST_TUns8 *GHOST_SystemWin32::getClipboard(bool selection) const
CloseClipboard();
return NULL;
}
-
+
temp_buff = alloc_utf_8_from_16(buffer, 0);
-
+
/* Buffer mustn't be accessed after CloseClipboard
* it would like accessing free-d memory */
GlobalUnlock(hData);
CloseClipboard();
-
+
return (GHOST_TUns8 *)temp_buff;
}
else if (IsClipboardFormatAvailable(CF_TEXT) && OpenClipboard(NULL) ) {
@@ -1601,17 +1601,17 @@ GHOST_TUns8 *GHOST_SystemWin32::getClipboard(bool selection) const
CloseClipboard();
return NULL;
}
-
+
len = strlen(buffer);
temp_buff = (char *) malloc(len + 1);
strncpy(temp_buff, buffer, len);
temp_buff[len] = '\0';
-
+
/* Buffer mustn't be accessed after CloseClipboard
* it would like accessing free-d memory */
GlobalUnlock(hData);
CloseClipboard();
-
+
return (GHOST_TUns8 *)temp_buff;
}
else {
@@ -1626,11 +1626,11 @@ void GHOST_SystemWin32::putClipboard(GHOST_TInt8 *buffer, bool selection) const
if (OpenClipboard(NULL)) {
HLOCAL clipbuffer;
wchar_t *data;
-
+
if (buffer) {
size_t len = count_utf_16_from_8(buffer);
EmptyClipboard();
-
+
clipbuffer = LocalAlloc(LMEM_FIXED, sizeof(wchar_t) * len);
data = (wchar_t *)GlobalLock(clipbuffer);
@@ -1686,7 +1686,7 @@ static bool getProcessName(int pid, char *buffer, int max_len)
static bool isStartedFromCommandPrompt()
{
HWND hwnd = GetConsoleWindow();
-
+
if (hwnd) {
DWORD pid = (DWORD)-1;
DWORD ppid = GetParentProcessID();
diff --git a/intern/ghost/intern/GHOST_SystemWin32.h b/intern/ghost/intern/GHOST_SystemWin32.h
index 0f15f9180ae..e1fd82ec239 100644
--- a/intern/ghost/intern/GHOST_SystemWin32.h
+++ b/intern/ghost/intern/GHOST_SystemWin32.h
@@ -110,7 +110,7 @@ public:
/**
* Create a new window.
- * The new window is added to the list of windows managed.
+ * The new window is added to the list of windows managed.
* Never explicitly delete the window, use disposeWindow() instead.
* \param title The name of the window (displayed in the title bar of the window if the OS supports it).
* \param left The coordinate of the left edge of the window.
@@ -157,7 +157,7 @@ public:
* \return Indication of the presence of events.
*/
bool processEvents(bool waitForEvent);
-
+
/***************************************************************************************
** Cursor management functionality
@@ -203,7 +203,7 @@ public:
* \return Returns the Clipboard
*/
GHOST_TUns8 *getClipboard(bool selection) const;
-
+
/**
* Puts buffer to system clipboard
* \param selection Used by X11 only
@@ -212,7 +212,7 @@ public:
void putClipboard(GHOST_TInt8 *buffer, bool selection) const;
/**
- * Creates a drag'n'drop event and pushes it immediately onto the event queue.
+ * Creates a drag'n'drop event and pushes it immediately onto the event queue.
* Called by GHOST_DropTargetWin32 class.
* \param eventType The type of drag'n'drop event
* \param draggedObjectType The type object concerned (currently array of file names, string, ?bitmap)
@@ -222,7 +222,7 @@ public:
* \return Indication whether the event was handled.
*/
static GHOST_TSuccess pushDragDropEvent(GHOST_TEventType eventType, GHOST_TDragnDropTypes draggedObjectType, GHOST_WindowWin32 *window, int mouseX, int mouseY, void *data);
-
+
/**
* Confirms quitting he program when there is just one window left open
* in the application
@@ -242,7 +242,7 @@ protected:
* \return A success value.
*/
GHOST_TSuccess exit();
-
+
/**
* Converts raw WIN32 key codes from the wndproc to GHOST keys.
* \param vKey The virtual key from hardKey
@@ -303,7 +303,7 @@ protected:
*/
GHOST_TKey processSpecialKey(short vKey, short scanCode) const;
- /**
+ /**
* Creates a window event.
* \param type The type of event to create.
* \param window The window receiving the event (the active window).
@@ -351,7 +351,7 @@ protected:
* param keys The new state of the modifier keys.
*/
inline void storeModifierKeys(const GHOST_ModifierKeys& keys);
-
+
/**
* Check current key layout for AltGr
*/
@@ -373,7 +373,7 @@ protected:
* \return current status (1 -visible, 0 - hidden)
*/
int toggleConsole(int action);
-
+
/** The current state of the modifier keys. */
GHOST_ModifierKeys m_modifierKeys;
/** State variable set at initialization. */
diff --git a/intern/ghost/intern/GHOST_SystemX11.cpp b/intern/ghost/intern/GHOST_SystemX11.cpp
index 69aa3a09977..b7bd0be017d 100644
--- a/intern/ghost/intern/GHOST_SystemX11.cpp
+++ b/intern/ghost/intern/GHOST_SystemX11.cpp
@@ -121,7 +121,7 @@ GHOST_SystemX11(
{
XInitThreads();
m_display = XOpenDisplay(NULL);
-
+
if (!m_display) {
std::cerr << "Unable to open a display" << std::endl;
abort(); /* was return before, but this would just mean it will crash later */
@@ -179,16 +179,16 @@ GHOST_SystemX11(
if (gettimeofday(&tv, NULL) == -1) {
GHOST_ASSERT(false, "Could not instantiate timer!");
}
-
+
/* Taking care not to overflow the tv.tv_sec * 1000 */
m_start_time = GHOST_TUns64(tv.tv_sec) * 1000 + tv.tv_usec / 1000;
-
-
+
+
/* use detectable autorepeate, mac and windows also do this */
int use_xkb;
int xkb_opcode, xkb_event, xkb_error;
int xkb_major = XkbMajorVersion, xkb_minor = XkbMinorVersion;
-
+
use_xkb = XkbQueryExtension(m_display, &xkb_opcode, &xkb_event, &xkb_error, &xkb_major, &xkb_minor);
if (use_xkb) {
XkbSetDetectableAutoRepeat(m_display, true, NULL);
@@ -244,7 +244,7 @@ GHOST_SystemX11::
/* close tablet devices */
if (m_xtablet.StylusDevice)
XCloseDevice(m_display, m_xtablet.StylusDevice);
-
+
if (m_xtablet.EraserDevice)
XCloseDevice(m_display, m_xtablet.EraserDevice);
#endif /* WITH_X11_XINPUT */
@@ -285,7 +285,7 @@ getMilliSeconds() const
/* Taking care not to overflow the tv.tv_sec * 1000 */
return GHOST_TUns64(tv.tv_sec) * 1000 + tv.tv_usec / 1000 - m_start_time;
}
-
+
GHOST_TUns8
GHOST_SystemX11::
getNumDisplays() const
@@ -358,9 +358,9 @@ createWindow(const STR_String& title,
const GHOST_TEmbedderWindowID parentWindow)
{
GHOST_WindowX11 *window = NULL;
-
+
if (!m_display) return 0;
-
+
window = new GHOST_WindowX11(this, m_display, title,
left, top, width, height,
state, parentWindow, type,
@@ -386,7 +386,7 @@ createWindow(const STR_String& title,
return window;
}
-bool GHOST_SystemX11::supportsNativeDialogs(void)
+bool GHOST_SystemX11::supportsNativeDialogs(void)
{
return false;
}
@@ -516,7 +516,7 @@ GHOST_SystemX11::
findGhostWindow(
Window xwind) const
{
-
+
if (xwind == 0) return NULL;
/* It is not entirely safe to do this as the backptr may point
@@ -528,7 +528,7 @@ findGhostWindow(
vector<GHOST_IWindow *>::iterator win_it = win_vec.begin();
vector<GHOST_IWindow *>::const_iterator win_end = win_vec.end();
-
+
for (; win_it != win_end; ++win_it) {
GHOST_WindowX11 *window = static_cast<GHOST_WindowX11 *>(*win_it);
if (window->getXWindow() == xwind) {
@@ -536,14 +536,14 @@ findGhostWindow(
}
}
return NULL;
-
+
}
static void SleepTillEvent(Display *display, GHOST_TInt64 maxSleep)
{
int fd = ConnectionNumber(display);
fd_set fds;
-
+
FD_ZERO(&fds);
FD_SET(fd, &fds);
@@ -555,7 +555,7 @@ static void SleepTillEvent(Display *display, GHOST_TInt64 maxSleep)
tv.tv_sec = maxSleep / 1000;
tv.tv_usec = (maxSleep - tv.tv_sec * 1000) * 1000;
-
+
select(fd + 1, &fds, NULL, NULL, &tv);
}
}
@@ -618,15 +618,15 @@ processEvents(
{
/* Get all the current events -- translate them into
* ghost events and call base class pushEvent() method. */
-
+
bool anyProcessed = false;
-
+
do {
GHOST_TimerManager *timerMgr = getTimerManager();
-
+
if (waitForEvent && m_dirty_windows.empty() && !XPending(m_display)) {
GHOST_TUns64 next = timerMgr->nextFireTime();
-
+
if (next == GHOST_kFireTimeNever) {
SleepTillEvent(m_display, -1);
}
@@ -637,11 +637,11 @@ processEvents(
SleepTillEvent(m_display, next - getMilliSeconds());
}
}
-
+
if (timerMgr->fireTimers(getMilliSeconds())) {
anyProcessed = true;
}
-
+
while (XPending(m_display)) {
XEvent xevent;
XNextEvent(m_display, &xevent);
@@ -669,10 +669,8 @@ processEvents(
}
/* dispatch event to XIM server */
- if ((XFilterEvent(&xevent, (Window)NULL) == True) && (xevent.type != KeyRelease)) {
- /* do nothing now, the event is consumed by XIM.
- * however, KeyRelease event should be processed
- * here, otherwise modifiers remain activated. */
+ if ((XFilterEvent(&xevent, (Window)NULL) == True)) {
+ /* do nothing now, the event is consumed by XIM. */
continue;
}
#endif
@@ -738,7 +736,7 @@ processEvents(
#endif /* USE_UNITY_WORKAROUND */
}
-
+
if (generateWindowExposeEvents()) {
anyProcessed = true;
}
@@ -748,9 +746,9 @@ processEvents(
anyProcessed = true;
}
#endif
-
+
} while (waitForEvent && !anyProcessed);
-
+
return anyProcessed;
}
@@ -971,7 +969,7 @@ GHOST_SystemX11::processEvent(XEvent *xe)
#else
char *utf8_buf = NULL;
#endif
-
+
GHOST_TEventType type = (xke->type == KeyPress) ? GHOST_kEventKeyDown : GHOST_kEventKeyUp;
GHOST_TKey gkey;
@@ -1084,7 +1082,7 @@ GHOST_SystemX11::processEvent(XEvent *xe)
}
gkey = convertXKey(key_sym);
-
+
if (!XLookupString(xke, &ascii, 1, NULL, NULL)) {
ascii = '\0';
}
@@ -1178,7 +1176,7 @@ GHOST_SystemX11::processEvent(XEvent *xe)
if (utf8_buf != utf8_array)
free(utf8_buf);
#endif
-
+
break;
}
@@ -1187,7 +1185,7 @@ GHOST_SystemX11::processEvent(XEvent *xe)
{
XButtonEvent & xbe = xe->xbutton;
GHOST_TButtonMask gbmask = GHOST_kButtonMaskLeft;
- GHOST_TEventType type = (xbe.type == ButtonPress) ?
+ GHOST_TEventType type = (xbe.type == ButtonPress) ?
GHOST_kEventButtonDown : GHOST_kEventButtonUp;
/* process wheel mouse events and break, only pass on press events */
@@ -1201,7 +1199,7 @@ GHOST_SystemX11::processEvent(XEvent *xe)
g_event = new GHOST_EventWheel(getMilliSeconds(), window, -1);
break;
}
-
+
/* process rest of normal mouse buttons */
if (xbe.button == Button1)
gbmask = GHOST_kButtonMaskLeft;
@@ -1233,13 +1231,13 @@ GHOST_SystemX11::processEvent(XEvent *xe)
);
break;
}
-
+
/* change of size, border, layer etc. */
case ConfigureNotify:
{
/* XConfigureEvent & xce = xe->xconfigure; */
- g_event = new
+ g_event = new
GHOST_Event(
getMilliSeconds(),
GHOST_kEventWindowSize,
@@ -1255,10 +1253,10 @@ GHOST_SystemX11::processEvent(XEvent *xe)
/* TODO: make sure this is the correct place for activate/deactivate */
// printf("X: focus %s for window %d\n", xfe.type == FocusIn ? "in" : "out", (int) xfe.window);
-
+
/* May have to look at the type of event and filter some out. */
- GHOST_TEventType gtype = (xfe.type == FocusIn) ?
+ GHOST_TEventType gtype = (xfe.type == FocusIn) ?
GHOST_kEventWindowActivate : GHOST_kEventWindowDeactivate;
#if defined(WITH_X11_XINPUT) && defined(X_HAVE_UTF8_STRING)
@@ -1271,7 +1269,7 @@ GHOST_SystemX11::processEvent(XEvent *xe)
}
#endif
- g_event = new
+ g_event = new
GHOST_Event(
getMilliSeconds(),
gtype,
@@ -1285,7 +1283,7 @@ GHOST_SystemX11::processEvent(XEvent *xe)
XClientMessageEvent & xcme = xe->xclient;
if (((Atom)xcme.data.l[0]) == m_atom.WM_DELETE_WINDOW) {
- g_event = new
+ g_event = new
GHOST_Event(
getMilliSeconds(),
GHOST_kEventWindowClose,
@@ -1329,14 +1327,14 @@ GHOST_SystemX11::processEvent(XEvent *xe)
break;
}
-
+
case DestroyNotify:
::exit(-1);
/* We're not interested in the following things.(yet...) */
case NoExpose:
case GraphicsExpose:
break;
-
+
case EnterNotify:
case LeaveNotify:
{
@@ -1349,7 +1347,7 @@ GHOST_SystemX11::processEvent(XEvent *xe)
*/
XCrossingEvent &xce = xe->xcrossing;
if (xce.mode == NotifyNormal) {
- g_event = new
+ g_event = new
GHOST_EventCursor(
getMilliSeconds(),
GHOST_kEventCursorMove,
@@ -1397,18 +1395,18 @@ GHOST_SystemX11::processEvent(XEvent *xe)
XEvent nxe;
Atom target, utf8_string, string, compound_text, c_string;
XSelectionRequestEvent *xse = &xe->xselectionrequest;
-
+
target = XInternAtom(m_display, "TARGETS", False);
utf8_string = XInternAtom(m_display, "UTF8_STRING", False);
string = XInternAtom(m_display, "STRING", False);
compound_text = XInternAtom(m_display, "COMPOUND_TEXT", False);
c_string = XInternAtom(m_display, "C_STRING", False);
-
+
/* support obsolete clients */
if (xse->property == None) {
xse->property = xse->target;
}
-
+
nxe.xselection.type = SelectionNotify;
nxe.xselection.requestor = xse->requestor;
nxe.xselection.property = xse->property;
@@ -1416,7 +1414,7 @@ GHOST_SystemX11::processEvent(XEvent *xe)
nxe.xselection.selection = xse->selection;
nxe.xselection.target = xse->target;
nxe.xselection.time = xse->time;
-
+
/* Check to see if the requestor is asking for String */
if (xse->target == utf8_string ||
xse->target == string ||
@@ -1447,13 +1445,13 @@ GHOST_SystemX11::processEvent(XEvent *xe)
/* Change property to None because we do not support anything but STRING */
nxe.xselection.property = None;
}
-
+
/* Send the event to the client 0 0 == False, SelectionNotify */
XSendEvent(m_display, xse->requestor, 0, 0, &nxe);
XFlush(m_display);
break;
}
-
+
default:
{
#ifdef WITH_X11_XINPUT
@@ -1584,7 +1582,7 @@ getButtons(
}
else {
return GHOST_kFailure;
- }
+ }
return GHOST_kSuccess;
}
@@ -1688,7 +1686,7 @@ setCursorPosition(
#endif
XSync(m_display, 0); /* Sync to process all requests */
-
+
return GHOST_kSuccess;
}
@@ -1699,7 +1697,7 @@ addDirtyWindow(
GHOST_WindowX11 *bad_wind)
{
GHOST_ASSERT((bad_wind != NULL), "addDirtyWindow() NULL ptr trapped (window)");
-
+
m_dirty_windows.push_back(bad_wind);
}
@@ -1711,7 +1709,7 @@ generateWindowExposeEvents()
vector<GHOST_WindowX11 *>::iterator w_start = m_dirty_windows.begin();
vector<GHOST_WindowX11 *>::const_iterator w_end = m_dirty_windows.end();
bool anyProcessed = false;
-
+
for (; w_start != w_end; ++w_start) {
GHOST_Event *g_event = new
GHOST_Event(
@@ -1721,7 +1719,7 @@ generateWindowExposeEvents()
);
(*w_start)->validate();
-
+
if (g_event) {
pushEvent(g_event);
anyProcessed = true;
@@ -1843,7 +1841,15 @@ convertXKey(KeySym key)
GXMAP(type, XF86XK_AudioForward, GHOST_kKeyMediaLast);
#endif
#endif
+ /* Non US keyboard layouts: avoid 'UnknownKey' - TODO(campbell): lookup scan-codes. */
+ GXMAP(type, XK_dead_circumflex, GHOST_kKeyAccentGrave); /* 'de' */
+ GXMAP(type, XK_masculine, GHOST_kKeyAccentGrave); /* 'es' */
+ GXMAP(type, XK_onehalf, GHOST_kKeyAccentGrave); /* 'dk' */
+ GXMAP(type, XK_twosuperior, GHOST_kKeyAccentGrave); /* 'fr' */
default:
+#ifdef GHOST_DEBUG
+ printf("%s: unknown key: %lu / 0x%lx\n", __func__, key, key);
+#endif
type = GHOST_kKeyUnknown;
break;
}
@@ -2110,12 +2116,12 @@ GHOST_TUns8 *GHOST_SystemX11::getClipboard(bool selection) const
unsigned char *tmp_data = (unsigned char *) malloc(sel_len + 1);
memcpy((char *)tmp_data, (char *)sel_buf, sel_len);
tmp_data[sel_len] = '\0';
-
+
if (sseln == m_atom.STRING)
XFree(sel_buf);
else
free(sel_buf);
-
+
return tmp_data;
}
return(NULL);
@@ -2156,7 +2162,7 @@ void GHOST_SystemX11::putClipboard(GHOST_TInt8 *buffer, bool selection) const
}
#ifdef WITH_XDND
-GHOST_TSuccess GHOST_SystemX11::pushDragDropEvent(GHOST_TEventType eventType,
+GHOST_TSuccess GHOST_SystemX11::pushDragDropEvent(GHOST_TEventType eventType,
GHOST_TDragnDropTypes draggedObjectType,
GHOST_IWindow *window,
int mouseX, int mouseY,
@@ -2322,7 +2328,7 @@ void GHOST_SystemX11::refreshXInputDevices()
for (int i = 0; i < device_count; ++i) {
char *device_type = device_info[i].type ? XGetAtomName(m_display, device_info[i].type) : NULL;
-
+
// printf("Tablet type:'%s', name:'%s', index:%d\n", device_type, device_info[i].name, i);
@@ -2355,7 +2361,7 @@ void GHOST_SystemX11::refreshXInputDevices()
break;
}
-
+
ici = (XAnyClassPtr)(((char *)ici) + ici->length);
}
}
diff --git a/intern/ghost/intern/GHOST_SystemX11.h b/intern/ghost/intern/GHOST_SystemX11.h
index b910589a1ad..f279cf53dcd 100644
--- a/intern/ghost/intern/GHOST_SystemX11.h
+++ b/intern/ghost/intern/GHOST_SystemX11.h
@@ -86,7 +86,7 @@ public:
GHOST_SystemX11(
);
-
+
/**
* Destructor.
*/
@@ -114,7 +114,7 @@ public:
GHOST_TUns64
getMilliSeconds(
) const;
-
+
/**
* Returns the number of displays on this system.
@@ -146,7 +146,7 @@ public:
/**
* Create a new window.
- * The new window is added to the list of windows managed.
+ * The new window is added to the list of windows managed.
* Never explicitly delete the window, use disposeWindow() instead.
* \param title The name of the window (displayed in the title bar of the window if the OS supports it).
* \param left The coordinate of the left edge of the window.
@@ -210,7 +210,7 @@ public:
GHOST_TInt32& x,
GHOST_TInt32& y
) const;
-
+
GHOST_TSuccess
setCursorPosition(
GHOST_TInt32 x,
@@ -239,15 +239,15 @@ public:
/**
* Flag a window as dirty. This will
- * generate a GHOST window update event on a call to processEvents()
+ * generate a GHOST window update event on a call to processEvents()
*/
void
addDirtyWindow(
GHOST_WindowX11 *bad_wind
);
-
-
+
+
/**
* return a pointer to the X11 display structure
*/
@@ -256,7 +256,7 @@ public:
getXDisplay(
) {
return m_display;
- }
+ }
#if defined(WITH_X11_XINPUT) && defined(X_HAVE_UTF8_STRING)
XIM
@@ -277,7 +277,7 @@ public:
* \return Returns the Clipboard indicated by Flag
*/
GHOST_TUns8 *getClipboard(bool selection) const;
-
+
/**
* Puts buffer to system clipboard
* \param buffer The buffer to copy to the clipboard
@@ -287,14 +287,14 @@ public:
#ifdef WITH_XDND
/**
- * Creates a drag'n'drop event and pushes it immediately onto the event queue.
+ * Creates a drag'n'drop event and pushes it immediately onto the event queue.
* Called by GHOST_DropTargetX11 class.
* \param eventType The type of drag'n'drop event
* \param draggedObjectType The type object concerned (currently array of file names, string, ?bitmap)
* \param mouseX x mouse coordinate (in window coordinates)
* \param mouseY y mouse coordinate
* \param window The window on which the event occurred
- * \return Indication whether the event was handled.
+ * \return Indication whether the event was handled.
*/
static GHOST_TSuccess pushDragDropEvent(GHOST_TEventType eventType, GHOST_TDragnDropTypes draggedObjectType, GHOST_IWindow *window, int mouseX, int mouseY, void *data);
#endif
diff --git a/intern/ghost/intern/GHOST_TaskbarWin32.h b/intern/ghost/intern/GHOST_TaskbarWin32.h
index 0ef71754717..f65207af706 100644
--- a/intern/ghost/intern/GHOST_TaskbarWin32.h
+++ b/intern/ghost/intern/GHOST_TaskbarWin32.h
@@ -87,7 +87,7 @@ typedef enum TBPFLAG {
TBPF_PAUSED = 0x8,
} TBPFLAG;
-#define THBN_CLICKED 0x1800
+#define THBN_CLICKED 0x1800
extern "C" {
const GUID IID_ITaskList3 = {0xEA1AFB91, 0x9E28, 0x4B86, {0x90, 0xE9, 0x9E, 0x9F, 0x8A, 0x5E, 0xEF, 0xAF}};
diff --git a/intern/ghost/intern/GHOST_TaskbarX11.cpp b/intern/ghost/intern/GHOST_TaskbarX11.cpp
index b47068df39f..2ef82dc6636 100644
--- a/intern/ghost/intern/GHOST_TaskbarX11.cpp
+++ b/intern/ghost/intern/GHOST_TaskbarX11.cpp
@@ -127,4 +127,4 @@ void GHOST_TaskBarX11::set_progress_enabled(bool enabled)
assert(is_valid());
unity_set_progress_visible(handle, enabled ? 1 : 0);
unity_event_loop(NULL, 0);
-} \ No newline at end of file
+}
diff --git a/intern/ghost/intern/GHOST_TimerManager.cpp b/intern/ghost/intern/GHOST_TimerManager.cpp
index f6ec9d3febe..1918fc26151 100644
--- a/intern/ghost/intern/GHOST_TimerManager.cpp
+++ b/intern/ghost/intern/GHOST_TimerManager.cpp
@@ -102,14 +102,14 @@ GHOST_TUns64 GHOST_TimerManager::nextFireTime()
{
GHOST_TUns64 smallest = GHOST_kFireTimeNever;
TTimerVector::iterator iter;
-
+
for (iter = m_timers.begin(); iter != m_timers.end(); ++iter) {
GHOST_TUns64 next = (*iter)->getNext();
-
+
if (next < smallest)
smallest = next;
}
-
+
return smallest;
}
diff --git a/intern/ghost/intern/GHOST_TimerManager.h b/intern/ghost/intern/GHOST_TimerManager.h
index 6cf4bcf40eb..78026a743eb 100644
--- a/intern/ghost/intern/GHOST_TimerManager.h
+++ b/intern/ghost/intern/GHOST_TimerManager.h
@@ -90,11 +90,11 @@ public:
/**
* Finds the soonest time the next timer would fire.
- * \return The soonest time the next timer would fire,
+ * \return The soonest time the next timer would fire,
* or GHOST_kFireTimeNever if no timers exist.
*/
GHOST_TUns64 nextFireTime();
-
+
/**
* Checks all timer tasks to see if they are expired and fires them if needed.
* \param time The current time.
diff --git a/intern/ghost/intern/GHOST_TimerTask.h b/intern/ghost/intern/GHOST_TimerTask.h
index 45aa66e4630..fa35fd134f5 100644
--- a/intern/ghost/intern/GHOST_TimerTask.h
+++ b/intern/ghost/intern/GHOST_TimerTask.h
@@ -78,7 +78,7 @@ public:
* \param start The timer start time.
*/
void setStart(GHOST_TUns64 start)
- {
+ {
m_start = start;
}
@@ -96,7 +96,7 @@ public:
* \param interval The timer interval.
*/
void setInterval(GHOST_TUns64 interval)
- {
+ {
m_interval = interval;
}
@@ -114,7 +114,7 @@ public:
* \param next The time the timerProc will be called.
*/
void setNext(GHOST_TUns64 next)
- {
+ {
m_next = next;
}
@@ -144,7 +144,7 @@ public:
{
return m_userData;
}
-
+
/**
* Changes the time user data.
* \param userData: The timer user data.
@@ -168,7 +168,7 @@ public:
* \param auxData The auxiliary storage room.
*/
void setAuxData(GHOST_TUns32 auxData)
- {
+ {
m_auxData = auxData;
}
diff --git a/intern/ghost/intern/GHOST_Window.cpp b/intern/ghost/intern/GHOST_Window.cpp
index 71fa260f0f2..6596028d5a1 100644
--- a/intern/ghost/intern/GHOST_Window.cpp
+++ b/intern/ghost/intern/GHOST_Window.cpp
@@ -58,12 +58,12 @@ GHOST_Window::GHOST_Window(
{
m_isUnsavedChanges = false;
m_canAcceptDragOperation = false;
-
+
m_progressBarVisible = false;
-
+
m_cursorGrabAccumPos[0] = 0;
m_cursorGrabAccumPos[1] = 0;
-
+
m_nativePixelSize = 1.0f;
m_fullScreen = state == GHOST_kWindowStateFullScreen;
@@ -208,7 +208,7 @@ GHOST_TSuccess GHOST_Window::setCustomCursorShape(GHOST_TUns8 bitmap[16][2], GHO
16, 16, hotX, hotY, 0, 1);
}
-GHOST_TSuccess GHOST_Window::setCustomCursorShape(GHOST_TUns8 *bitmap, GHOST_TUns8 *mask,
+GHOST_TSuccess GHOST_Window::setCustomCursorShape(GHOST_TUns8 *bitmap, GHOST_TUns8 *mask,
int sizex, int sizey, int hotX, int hotY,
int fg_color, int bg_color)
{
@@ -234,7 +234,7 @@ bool GHOST_Window::canAcceptDragOperation() const
GHOST_TSuccess GHOST_Window::setModifiedState(bool isUnsavedChanges)
{
m_isUnsavedChanges = isUnsavedChanges;
-
+
return GHOST_kSuccess;
}
diff --git a/intern/ghost/intern/GHOST_Window.h b/intern/ghost/intern/GHOST_Window.h
index 2798bdf72f3..413a3315225 100644
--- a/intern/ghost/intern/GHOST_Window.h
+++ b/intern/ghost/intern/GHOST_Window.h
@@ -40,7 +40,7 @@ class GHOST_Context;
/**
* Platform independent implementation of GHOST_IWindow.
- * Dimensions are given in screen coordinates that are relative to the
+ * Dimensions are given in screen coordinates that are relative to the
* upper-left corner of the screen.
* Implements part of the GHOST_IWindow interface and adds some methods to
* be implemented by childs of this class.
@@ -94,7 +94,7 @@ public:
* virtual GHOST_TSuccess activateDrawingContext() = 0;
* virtual GHOST_TSuccess invalidate() = 0;
*/
-
+
/**
* Destructor.
* Closes the window and disposes resources allocated.
@@ -105,7 +105,7 @@ public:
* Returns indication as to whether the window is valid.
* \return The validity of the window.
*/
- virtual bool getValid() const {
+ virtual bool getValid() const {
return m_context != NULL;
}
@@ -114,7 +114,7 @@ public:
* \return The associated OS object/handle
*/
virtual void *getOSWindow() const;
-
+
/**
* Returns the current cursor shape.
* \return The current cursor shape.
@@ -185,14 +185,14 @@ public:
virtual GHOST_TSuccess setProgressBar(float /*progress*/) {
return GHOST_kFailure;
}
-
+
/**
* Hides the progress bar in the icon
*/
virtual GHOST_TSuccess endProgressBar() {
return GHOST_kFailure;
}
-
+
/**
* Sets the swap interval for swapBuffers.
* \param interval The swap interval to use.
@@ -216,26 +216,26 @@ public:
* Tells if the ongoing drag'n'drop object can be accepted upon mouse drop
*/
void setAcceptDragOperation(bool canAccept);
-
+
/**
* Returns acceptance of the dropped object
* Usually called by the "object dropped" event handling function
*/
bool canAcceptDragOperation() const;
-
+
/**
* Sets the window "modified" status, indicating unsaved changes
* \param isUnsavedChanges Unsaved changes or not
* \return Indication of success.
*/
virtual GHOST_TSuccess setModifiedState(bool isUnsavedChanges);
-
+
/**
* Gets the window "modified" status, indicating unsaved changes
* \return True if there are unsaved changes
*/
virtual bool getModifiedState();
-
+
/**
* Returns the type of drawing context used in this window.
* \return The current type of drawing context.
@@ -278,7 +278,7 @@ public:
{
return m_userData;
}
-
+
/**
* Changes the window user data.
* \param userData: The window user data.
@@ -287,7 +287,7 @@ public:
{
m_userData = userData;
}
-
+
float getNativePixelSize(void)
{
if (m_nativePixelSize > 0.0f)
@@ -341,7 +341,7 @@ protected:
virtual GHOST_TSuccess setWindowCursorGrab(GHOST_TGrabCursorMode /*mode*/) {
return GHOST_kSuccess;
}
-
+
/**
* Sets the cursor shape on the window using
* native window system calls.
@@ -355,15 +355,15 @@ protected:
virtual GHOST_TSuccess setWindowCustomCursorShape(GHOST_TUns8 bitmap[16][2],
GHOST_TUns8 mask[16][2],
int hotX, int hotY) = 0;
-
- virtual GHOST_TSuccess setWindowCustomCursorShape(GHOST_TUns8 *bitmap, GHOST_TUns8 *mask,
+
+ virtual GHOST_TSuccess setWindowCustomCursorShape(GHOST_TUns8 *bitmap, GHOST_TUns8 *mask,
int szx, int szy, int hotX, int hotY, int fg, int bg) = 0;
GHOST_TSuccess releaseNativeHandles();
/** The drawing context installed in this window. */
GHOST_TDrawingContextType m_drawingContextType;
-
+
/** The window user data */
GHOST_TUserDataPtr m_userData;
@@ -384,16 +384,16 @@ protected:
/** The current shape of the cursor */
GHOST_TStandardCursor m_cursorShape;
-
+
/** The presence of progress indicator with the application icon */
bool m_progressBarVisible;
-
+
/** The acceptance of the "drop candidate" of the current drag'n'drop operation */
bool m_canAcceptDragOperation;
-
+
/** Modified state : are there unsaved changes */
bool m_isUnsavedChanges;
-
+
/** Stores whether this is a full screen window. */
bool m_fullScreen;
@@ -407,7 +407,7 @@ protected:
GHOST_TUns32 m_fullScreenWidth;
/** Full-screen height */
GHOST_TUns32 m_fullScreenHeight;
-
+
/* OSX only, retina screens */
float m_nativePixelSize;
diff --git a/intern/ghost/intern/GHOST_WindowCocoa.h b/intern/ghost/intern/GHOST_WindowCocoa.h
index 9dbc85d91e2..54ecd2b44c8 100644
--- a/intern/ghost/intern/GHOST_WindowCocoa.h
+++ b/intern/ghost/intern/GHOST_WindowCocoa.h
@@ -89,7 +89,7 @@ public:
* \return The validity of the window.
*/
bool getValid() const;
-
+
/**
* Returns the associated NSWindow object
* \return The associated NSWindow object
@@ -110,11 +110,11 @@ public:
/**
* Returns the window rectangle dimensions.
- * The dimensions are given in screen coordinates that are relative to the upper-left corner of the screen.
+ * The dimensions are given in screen coordinates that are relative to the upper-left corner of the screen.
* \param bounds The bounding rectangle of the window.
*/
void getWindowBounds(GHOST_Rect& bounds) const;
-
+
/**
* Returns the client rectangle dimensions.
* The left and top members of the rectangle are always zero.
@@ -153,7 +153,7 @@ public:
* \return Indication of success.
*/
GHOST_TSuccess setModifiedState(bool isUnsavedChanges);
-
+
/**
* Converts a point in screen coordinates to client rectangle coordinates
* \param inX The x-coordinate on the screen.
@@ -197,7 +197,7 @@ public:
* \return The NSScreen object
*/
NSScreen *getScreen();
-
+
/**
* Sets the state of the window (normal, minimized, maximized).
* \param state The state of the window.
@@ -213,7 +213,7 @@ public:
GHOST_TSuccess setOrder(GHOST_TWindowOrder order);
void loadCursor(bool visible, GHOST_TStandardCursor cursor) const;
-
+
const GHOST_TabletData *GetTabletData()
{
return &m_tablet;
@@ -223,32 +223,32 @@ public:
{
return m_tablet;
}
-
+
/**
* Sets the progress bar value displayed in the window/application icon
* \param progress The progress % (0.0 to 1.0)
*/
GHOST_TSuccess setProgressBar(float progress);
-
+
/**
* Hides the progress bar icon
*/
GHOST_TSuccess endProgressBar();
-
-
+
+
void setNativePixelSize(void);
GHOST_TSuccess beginFullScreen() const {return GHOST_kFailure;}
GHOST_TSuccess endFullScreen() const {return GHOST_kFailure;}
-
+
/** public function to get the window containing the OpenGL view */
CocoaWindow *getCocoaWindow() const {return m_window;};
/* Internal value to ensure proper redraws during animations */
void setImmediateDraw(bool value) { m_immediateDraw = value; }
bool getImmediateDraw(void) const { return m_immediateDraw; }
-
+
protected:
/**
@@ -268,13 +268,13 @@ protected:
* native window system calls.
*/
GHOST_TSuccess setWindowCursorVisibility(bool visible);
-
+
/**
* Sets the cursor grab on the window using
* native window system calls.
*/
GHOST_TSuccess setWindowCursorGrab(GHOST_TGrabCursorMode mode);
-
+
/**
* Sets the cursor shape on the window using
* native window system calls.
@@ -287,14 +287,14 @@ protected:
*/
GHOST_TSuccess setWindowCustomCursorShape(GHOST_TUns8 *bitmap, GHOST_TUns8 *mask,
int sizex, int sizey, int hotX, int hotY, int fg_color, int bg_color);
-
+
GHOST_TSuccess setWindowCustomCursorShape(GHOST_TUns8 bitmap[16][2], GHOST_TUns8 mask[16][2], int hotX, int hotY);
/** The window containing the OpenGL view */
CocoaWindow *m_window;
-
+
/** The openGL view */
- CocoaOpenGLView *m_openGLView;
+ CocoaOpenGLView *m_openGLView;
/** The mother SystemCocoa class to send events */
GHOST_SystemCocoa *m_systemCocoa;
diff --git a/intern/ghost/intern/GHOST_WindowManager.cpp b/intern/ghost/intern/GHOST_WindowManager.cpp
index 790c73deca5..31e1b0401f1 100644
--- a/intern/ghost/intern/GHOST_WindowManager.cpp
+++ b/intern/ghost/intern/GHOST_WindowManager.cpp
@@ -42,7 +42,7 @@
#include "GHOST_Window.h"
-GHOST_WindowManager::GHOST_WindowManager() :
+GHOST_WindowManager::GHOST_WindowManager() :
m_fullScreenWindow(0),
m_activeWindow(0),
m_activeWindowBeforeFullScreen(0)
@@ -61,7 +61,7 @@ GHOST_TSuccess GHOST_WindowManager::addWindow(GHOST_IWindow *window)
GHOST_TSuccess success = GHOST_kFailure;
if (window) {
if (!getWindowFound(window)) {
- // Store the pointer to the window
+ // Store the pointer to the window
m_windows.push_back(window);
success = GHOST_kSuccess;
}
@@ -170,7 +170,7 @@ GHOST_TSuccess GHOST_WindowManager::setActiveWindow(GHOST_IWindow *window)
}
return success;
}
-
+
GHOST_IWindow *GHOST_WindowManager::getActiveWindow(void) const
{
@@ -200,7 +200,7 @@ GHOST_IWindow *GHOST_WindowManager::getWindowAssociatedWithOSWindow(void *osWind
if ((*iter)->getOSWindow() == osWindow)
return *iter;
}
-
+
return NULL;
}
@@ -208,7 +208,7 @@ bool GHOST_WindowManager::getAnyModifiedState()
{
bool isAnyModified = false;
std::vector<GHOST_IWindow *>::iterator iter;
-
+
for (iter = m_windows.begin(); iter != m_windows.end(); ++iter) {
if ((*iter)->getModifiedState())
isAnyModified = true;
diff --git a/intern/ghost/intern/GHOST_WindowManager.h b/intern/ghost/intern/GHOST_WindowManager.h
index e868a9b0416..a7dde2af39c 100644
--- a/intern/ghost/intern/GHOST_WindowManager.h
+++ b/intern/ghost/intern/GHOST_WindowManager.h
@@ -110,38 +110,38 @@ public:
* \param window The new active window.
*/
GHOST_TSuccess setActiveWindow(GHOST_IWindow *window);
-
+
/**
* Returns the active window (the window receiving events).
* There can be only one window active which should be in the current window list.
* \return window The active window (or NULL if there is none).
*/
GHOST_IWindow *getActiveWindow(void) const;
-
+
/**
* Set this window to be inactive (not receiving events).
* \param window The window to deactivate.
*/
void setWindowInactive(const GHOST_IWindow *window);
-
+
/**
- * Return a vector of the windows currently managed by this
- * class.
+ * Return a vector of the windows currently managed by this
+ * class.
* \warning It is very dangerous to mess with the contents of
- * this vector. Please do not destroy or add windows use the
+ * this vector. Please do not destroy or add windows use the
* interface above for this,
*/
std::vector<GHOST_IWindow *> & getWindows();
-
+
/**
* Finds the window associated with an OS window object/handle
* \param osWindow The OS window object/handle
* \return The associated window, null if none corresponds
*/
GHOST_IWindow *getWindowAssociatedWithOSWindow(void *osWindow);
-
+
/**
* Return true if any windows has a modified status
* \return True if any window has unsaved changes
@@ -164,7 +164,7 @@ protected:
#ifdef WITH_CXX_GUARDEDALLOC
MEM_CXX_CLASS_ALLOC_FUNCS("GHOST:GHOST_WindowManager")
#endif
-
+
};
#endif // __GHOST_WINDOWMANAGER_H__
diff --git a/intern/ghost/intern/GHOST_WindowWin32.cpp b/intern/ghost/intern/GHOST_WindowWin32.cpp
index 3c9c7c415bb..676a29f28d4 100644
--- a/intern/ghost/intern/GHOST_WindowWin32.cpp
+++ b/intern/ghost/intern/GHOST_WindowWin32.cpp
@@ -99,7 +99,7 @@ GHOST_WindowWin32::GHOST_WindowWin32(GHOST_SystemWin32 *system,
if (state != GHOST_kWindowStateFullScreen) {
RECT rect;
MONITORINFO monitor;
- GHOST_TUns32 tw, th;
+ GHOST_TUns32 tw, th;
#ifndef _MSC_VER
int cxsizeframe = GetSystemMetrics(SM_CXSIZEFRAME);
@@ -158,7 +158,7 @@ GHOST_WindowWin32::GHOST_WindowWin32(GHOST_SystemWin32 *system,
width = rect.right - rect.left;
height = rect.bottom - rect.top;
}
-
+
wchar_t *title_16 = alloc_utf16_from_8((char *)(const char *)title, 0);
m_hWnd = ::CreateWindowW(
s_windowClassName, // pointer to registered class name
@@ -225,7 +225,7 @@ GHOST_WindowWin32::GHOST_WindowWin32(GHOST_SystemWin32 *system,
::ShowWindow(m_hWnd, nCmdShow);
#ifdef WIN32_COMPOSITING
if (alphaBackground && parentwindowhwnd == 0) {
-
+
HRESULT hr = S_OK;
// Create and populate the Blur Behind structure
@@ -817,7 +817,7 @@ GHOST_TSuccess GHOST_WindowWin32::setWindowCursorGrab(GHOST_TGrabCursorMode mode
m_cursorGrabBounds.m_l = m_cursorGrabBounds.m_r = -1; /* disable */
registerMouseClickEvent(3);
}
-
+
return GHOST_kSuccess;
}
@@ -1041,7 +1041,7 @@ GHOST_TSuccess GHOST_WindowWin32::setWindowCustomCursorShape(
GHOST_TSuccess GHOST_WindowWin32::setProgressBar(float progress)
-{
+{
/*SetProgressValue sets state to TBPF_NORMAL automaticly*/
if (m_Bar && S_OK == m_Bar->SetProgressValue(m_hWnd, 10000 * progress, 10000))
return GHOST_kSuccess;
diff --git a/intern/ghost/intern/GHOST_WindowWin32.h b/intern/ghost/intern/GHOST_WindowWin32.h
index 75a33951ff4..d998e86c9b1 100644
--- a/intern/ghost/intern/GHOST_WindowWin32.h
+++ b/intern/ghost/intern/GHOST_WindowWin32.h
@@ -132,11 +132,11 @@ public:
/**
* Returns the window rectangle dimensions.
- * The dimensions are given in screen coordinates that are relative to the upper-left corner of the screen.
+ * The dimensions are given in screen coordinates that are relative to the upper-left corner of the screen.
* \param bounds The bounding rectangle of the window.
*/
void getWindowBounds(GHOST_Rect& bounds) const;
-
+
/**
* Returns the client rectangle dimensions.
* The left and top members of the rectangle are always zero.
@@ -211,19 +211,19 @@ public:
* \param progress The progress %
*/
GHOST_TSuccess setProgressBar(float progress);
-
+
/**
* Hides the progress bar in the icon
*/
GHOST_TSuccess endProgressBar();
-
+
/**
- * Register a mouse click event (should be called
+ * Register a mouse click event (should be called
* for any real button press, controls mouse
* capturing).
*
- * \param press
+ * \param press
* 0 - mouse pressed
* 1 - mouse released
* 2 - operator grab
@@ -286,14 +286,14 @@ private:
* native window system calls.
*/
GHOST_TSuccess setWindowCursorVisibility(bool visible);
-
+
/**
* Sets the cursor grab on the window using native window system calls.
* Using registerMouseClickEvent.
* \param mode GHOST_TGrabCursorMode.
*/
GHOST_TSuccess setWindowCursorGrab(GHOST_TGrabCursorMode mode);
-
+
/**
* Sets the cursor shape on the window using
* native window system calls.
@@ -318,7 +318,7 @@ private:
int fg_color,
int bg_color
);
-
+
/** Pointer to system */
GHOST_SystemWin32 *m_system;
/** Pointer to COM IDropTarget implementor */
@@ -330,7 +330,7 @@ private:
/** Flag for if window has captured the mouse */
bool m_hasMouseCaptured;
- /** Flag if an operator grabs the mouse with WM_cursor_grab_enable/ungrab()
+ /** Flag if an operator grabs the mouse with WM_cursor_grab_enable/ungrab()
* Multiple grabs must be released with a single ungrab */
bool m_hasGrabMouse;
/** Count of number of pressed buttons */
diff --git a/intern/ghost/intern/GHOST_WindowX11.cpp b/intern/ghost/intern/GHOST_WindowX11.cpp
index 3c291bd5ec6..ade4799a52d 100644
--- a/intern/ghost/intern/GHOST_WindowX11.cpp
+++ b/intern/ghost/intern/GHOST_WindowX11.cpp
@@ -204,7 +204,7 @@ static XVisualInfo *x11_visualinfo_from_glx(
numOfAASamples = 0;
actualSamples = 0;
}
-
+
#ifdef WITH_X11_ALPHA
if ( needAlpha
&& glx_version >= 103
@@ -276,7 +276,7 @@ static XVisualInfo *x11_visualinfo_from_glx(
/* legacy, don't use extension */
for (;;) {
GHOST_X11_GL_GetAttributes(glx_attribs, 64, actualSamples, stereoVisual, needAlpha, false);
-
+
visual = glXChooseVisual(display, DefaultScreen(display), glx_attribs);
/* Any sample level or even zero, which means oversampling disabled, is good
@@ -408,7 +408,7 @@ GHOST_WindowX11(GHOST_SystemX11 *system,
Window root_return;
int x_return, y_return;
unsigned int w_return, h_return, border_w_return, depth_return;
-
+
XGetGeometry(m_display, parentWindow, &root_return, &x_return, &y_return,
&w_return, &h_return, &border_w_return, &depth_return);
@@ -430,8 +430,8 @@ GHOST_WindowX11(GHOST_SystemX11 *system,
&xattributes);
XSelectInput(m_display, parentWindow, SubstructureNotifyMask);
-
- }
+
+ }
#ifdef WITH_XDND
/* initialize drop target for newly created window */
@@ -717,12 +717,12 @@ getTitle(
STR_String& title) const
{
char *name = NULL;
-
+
XFetchName(m_display, m_window, &name);
title = name ? name : "untitled";
XFree(name);
}
-
+
void
GHOST_WindowX11::
getWindowBounds(
@@ -742,12 +742,12 @@ getClientBounds(
int x_return, y_return;
unsigned int w_return, h_return, border_w_return, depth_return;
GHOST_TInt32 screen_x, screen_y;
-
+
XGetGeometry(m_display, m_window, &root_return, &x_return, &y_return,
&w_return, &h_return, &border_w_return, &depth_return);
clientToScreen(0, 0, screen_x, screen_y);
-
+
bounds.m_l = screen_x;
bounds.m_r = bounds.m_l + w_return;
bounds.m_t = screen_y;
@@ -794,7 +794,7 @@ setClientSize(
XConfigureWindow(m_display, m_window, value_mask, &values);
return GHOST_kSuccess;
-}
+}
void
GHOST_WindowX11::
@@ -818,7 +818,7 @@ screenToClient(
outX = ax;
outY = ay;
}
-
+
void
GHOST_WindowX11::
clientToScreen(
@@ -1159,7 +1159,7 @@ setOrder(
GHOST_TWindowOrder order)
{
if (order == GHOST_kWindowOrderTop) {
- XWindowAttributes attr;
+ XWindowAttributes attr;
Atom atom;
/* We use both XRaiseWindow and _NET_ACTIVE_WINDOW, since some
@@ -1209,7 +1209,7 @@ setOrder(
else {
return GHOST_kFailure;
}
-
+
return GHOST_kSuccess;
}
@@ -1233,8 +1233,8 @@ invalidate()
if (m_invalid_window == false) {
m_system->addDirtyWindow(this);
m_invalid_window = true;
- }
-
+ }
+
return GHOST_kSuccess;
}
@@ -1242,15 +1242,15 @@ invalidate()
* called by the X11 system implementation when expose events
* for the window have been pushed onto the GHOST queue
*/
-
+
void
GHOST_WindowX11::
validate()
{
m_invalid_window = false;
-}
-
-
+}
+
+
/**
* Destructor.
* Closes the window and disposes resources allocated.
@@ -1289,7 +1289,7 @@ GHOST_WindowX11::
XSetSelectionOwner(m_display, Clipboard_atom, None, CurrentTime);
}
}
-
+
if (m_visualInfo) {
XFree(m_visualInfo);
}
@@ -1425,13 +1425,13 @@ getStandardCursor(
if (xcursor_id) {
Cursor xcursor = m_standard_cursors[xcursor_id];
-
+
if (!xcursor) {
xcursor = XCreateFontCursor(m_display, xcursor_id);
m_standard_cursors[xcursor_id] = xcursor;
}
-
+
return xcursor;
}
else {
@@ -1447,7 +1447,7 @@ getEmptyCursor(
Pixmap blank;
XColor dummy = {0};
char data[1] = {0};
-
+
/* make a blank cursor */
blank = XCreateBitmapFromData(
m_display,
@@ -1468,7 +1468,7 @@ setWindowCursorVisibility(
bool visible)
{
Cursor xcursor;
-
+
if (visible) {
if (m_visible_cursor)
xcursor = m_visible_cursor;
@@ -1481,7 +1481,7 @@ setWindowCursorVisibility(
XDefineCursor(m_display, m_window, xcursor);
XFlush(m_display);
-
+
return GHOST_kSuccess;
}
@@ -1544,7 +1544,7 @@ setWindowCursorGrab(
}
XFlush(m_display);
-
+
return GHOST_kSuccess;
}
@@ -1556,7 +1556,7 @@ setWindowCursorShape(
Cursor xcursor = getStandardCursor(shape);
m_visible_cursor = xcursor;
-
+
XDefineCursor(m_display, m_window, xcursor);
XFlush(m_display);
@@ -1578,7 +1578,7 @@ setWindowCustomCursorShape(
GHOST_TSuccess
GHOST_WindowX11::
-setWindowCustomCursorShape(
+setWindowCustomCursorShape(
GHOST_TUns8 *bitmap,
GHOST_TUns8 *mask,
int sizex,
@@ -1591,7 +1591,7 @@ setWindowCustomCursorShape(
Colormap colormap = DefaultColormap(m_display, m_visualInfo->screen);
Pixmap bitmap_pix, mask_pix;
XColor fg, bg;
-
+
if (XAllocNamedColor(m_display, colormap, "White", &fg, &fg) == 0) return GHOST_kFailure;
if (XAllocNamedColor(m_display, colormap, "Black", &bg, &bg) == 0) return GHOST_kFailure;
@@ -1601,13 +1601,13 @@ setWindowCustomCursorShape(
bitmap_pix = XCreateBitmapFromData(m_display, m_window, (char *) bitmap, sizex, sizey);
mask_pix = XCreateBitmapFromData(m_display, m_window, (char *) mask, sizex, sizey);
-
+
m_custom_cursor = XCreatePixmapCursor(m_display, bitmap_pix, mask_pix, &fg, &bg, hotX, hotY);
XDefineCursor(m_display, m_window, m_custom_cursor);
XFlush(m_display);
m_visible_cursor = m_custom_cursor;
-
+
XFreePixmap(m_display, bitmap_pix);
XFreePixmap(m_display, mask_pix);
diff --git a/intern/ghost/intern/GHOST_WindowX11.h b/intern/ghost/intern/GHOST_WindowX11.h
index 236fe0b76b0..bf2497ee6d6 100644
--- a/intern/ghost/intern/GHOST_WindowX11.h
+++ b/intern/ghost/intern/GHOST_WindowX11.h
@@ -54,7 +54,7 @@ class GHOST_DropTargetX11;
/**
* X11 implementation of GHOST_IWindow.
- * Dimensions are given in screen coordinates that are relative to the upper-left corner of the screen.
+ * Dimensions are given in screen coordinates that are relative to the upper-left corner of the screen.
* \author Laurence Bourn
* \date October 26, 2001
*/
@@ -112,7 +112,7 @@ public:
getWindowBounds(
GHOST_Rect& bounds
) const;
-
+
void
getClientBounds(
GHOST_Rect& bounds
@@ -149,7 +149,7 @@ public:
GHOST_TInt32& outX,
GHOST_TInt32& outY
) const;
-
+
GHOST_TWindowState
getState(
) const;
@@ -158,12 +158,12 @@ public:
setState(
GHOST_TWindowState state
);
-
+
GHOST_TSuccess
setOrder(
GHOST_TWindowOrder order
);
-
+
GHOST_TSuccess
invalidate(
);
@@ -191,7 +191,7 @@ public:
validate(
);
- /**
+ /**
* Return a handle to the x11 window type.
*/
Window
@@ -257,7 +257,7 @@ protected:
setWindowCursorVisibility(
bool visible
);
-
+
/**
* Sets the cursor grab on the window using
* native window system calls.
@@ -290,7 +290,7 @@ protected:
int hotX,
int hotY
);
-
+
/**
* Sets the cursor shape on the window using
* native window system calls (Arbitrary size/color).
@@ -310,7 +310,7 @@ protected:
private:
/// Force use of public constructor.
-
+
GHOST_WindowX11(
);
@@ -322,11 +322,11 @@ private:
getStandardCursor(
GHOST_TStandardCursor g_cursor
);
-
+
Cursor
getEmptyCursor(
);
-
+
Window m_window;
Display *m_display;
XVisualInfo *m_visualInfo;
@@ -342,13 +342,13 @@ private:
/** XCursor structure of an empty (blank) cursor */
Cursor m_empty_cursor;
-
+
/** XCursor structure of the custom cursor */
Cursor m_custom_cursor;
/** XCursor to show when cursor is visible */
Cursor m_visible_cursor;
-
+
/** Cache of XC_* ID's to XCursor structures */
std::map<unsigned int, Cursor> m_standard_cursors;
diff --git a/intern/ghost/test/CMakeLists.txt b/intern/ghost/test/CMakeLists.txt
index 0cec217630c..9f714ae4fba 100644
--- a/intern/ghost/test/CMakeLists.txt
+++ b/intern/ghost/test/CMakeLists.txt
@@ -103,7 +103,7 @@ suffix_relpaths(SRC_NEW "${SRC}" "../../guardedalloc/")
include_directories(${INC_NEW})
add_library(guardedalloc_lib ${SRC_NEW})
-# blenfont
+# blenfont
include(${CMAKE_SOURCE_DIR}/../../../source/blender/blenfont/CMakeLists.txt)
suffix_relpaths(INC_NEW "${INC}" "../../../source/blender/blenfont/")
suffix_relpaths(SRC_NEW "${SRC}" "../../../source/blender/blenfont/")
@@ -128,7 +128,7 @@ add_library(glewmx_lib ${SRC_NEW})
include_directories(
"../../../source/blender/blenlib"
)
-add_library(bli_lib
+add_library(bli_lib
"../../../source/blender/blenlib/intern/fileops.c"
"../../../source/blender/blenlib/intern/gsqueue.c"
"../../../source/blender/blenlib/intern/rct.c"
diff --git a/intern/ghost/test/gears/GHOST_C-Test.c b/intern/ghost/test/gears/GHOST_C-Test.c
index c635ab9be5b..abaa6258122 100644
--- a/intern/ghost/test/gears/GHOST_C-Test.c
+++ b/intern/ghost/test/gears/GHOST_C-Test.c
@@ -84,16 +84,16 @@ static void gearGL(GLfloat inner_radius, GLfloat outer_radius, GLfloat width, GL
GLfloat angle, da;
GLfloat u, v, len;
const double pi = 3.14159264;
-
+
r0 = inner_radius;
r1 = (float)(outer_radius - tooth_depth / 2.0);
r2 = (float)(outer_radius + tooth_depth / 2.0);
-
+
da = (float)(2.0 * pi / teeth / 4.0);
-
+
glShadeModel(GL_FLAT);
glNormal3f(0.0, 0.0, 1.0);
-
+
/* draw front face */
glBegin(GL_QUAD_STRIP);
for (i = 0; i <= teeth; i++) {
@@ -104,7 +104,7 @@ static void gearGL(GLfloat inner_radius, GLfloat outer_radius, GLfloat width, GL
glVertex3f((float)(r1 * cos(angle + 3 * da)), (float)(r1 * sin(angle + 3 * da)), (float)(width * 0.5));
}
glEnd();
-
+
/* draw front sides of teeth */
glBegin(GL_QUADS);
da = (float)(2.0 * pi / teeth / 4.0);
@@ -116,9 +116,9 @@ static void gearGL(GLfloat inner_radius, GLfloat outer_radius, GLfloat width, GL
glVertex3f((float)(r1 * cos(angle + 3 * da)), (float)(r1 * sin(angle + 3 * da)), (float)(width * 0.5));
}
glEnd();
-
+
glNormal3f(0.0, 0.0, -1.0);
-
+
/* draw back face */
glBegin(GL_QUAD_STRIP);
for (i = 0; i <= teeth; i++) {
@@ -129,7 +129,7 @@ static void gearGL(GLfloat inner_radius, GLfloat outer_radius, GLfloat width, GL
glVertex3f((float)(r0 * cos(angle)), (float)(r0 * sin(angle)), (float)(-width * 0.5));
}
glEnd();
-
+
/* draw back sides of teeth */
glBegin(GL_QUADS);
da = (float)(2.0 * pi / teeth / 4.0);
@@ -141,7 +141,7 @@ static void gearGL(GLfloat inner_radius, GLfloat outer_radius, GLfloat width, GL
glVertex3f((float)(r1 * cos(angle)), (float)(r1 * sin(angle)), (float)(-width * 0.5));
}
glEnd();
-
+
/* draw outward faces of teeth */
glBegin(GL_QUAD_STRIP);
for (i = 0; i < teeth; i++) {
@@ -169,9 +169,9 @@ static void gearGL(GLfloat inner_radius, GLfloat outer_radius, GLfloat width, GL
glVertex3f((float)(r1 * cos(0.0)), (float)(r1 * sin(0.0)), (float)(width * 0.5));
glVertex3f((float)(r1 * cos(0.0)), (float)(r1 * sin(0.0)), (float)(-width * 0.5));
glEnd();
-
+
glShadeModel(GL_SMOOTH);
-
+
/* draw inside radius cylinder */
glBegin(GL_QUAD_STRIP);
for (i = 0; i <= teeth; i++) {
@@ -191,13 +191,13 @@ static void drawGearGL(int id)
static GLfloat ared[4] = { 0.8f, 0.1f, 0.0f, 1.0f };
static GLfloat agreen[4] = { 0.0f, 0.8f, 0.2f, 1.0f };
static GLfloat ablue[4] = { 0.2f, 0.2f, 1.0f, 1.0f };
-
+
glLightfv(GL_LIGHT0, GL_POSITION, pos);
glEnable(GL_CULL_FACE);
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);
glEnable(GL_DEPTH_TEST);
-
+
switch (id)
{
case 1:
@@ -222,32 +222,32 @@ static void drawGearGL(int id)
static void drawGL(void)
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
-
+
glPushMatrix();
-
+
glRotatef(view_rotx, 1.0, 0.0, 0.0);
glRotatef(view_roty, 0.0, 1.0, 0.0);
glRotatef(view_rotz, 0.0, 0.0, 1.0);
-
+
glPushMatrix();
glTranslatef(-3.0, -2.0, 0.0);
glRotatef(fAngle, 0.0, 0.0, 1.0);
drawGearGL(1);
glPopMatrix();
-
+
glPushMatrix();
glTranslatef(3.1f, -2.0f, 0.0f);
glRotatef((float)(-2.0 * fAngle - 9.0), 0.0, 0.0, 1.0);
drawGearGL(2);
glPopMatrix();
-
+
glPushMatrix();
glTranslatef(-3.1f, 2.2f, -1.8f);
glRotatef(90.0f, 1.0f, 0.0f, 0.0f);
glRotatef((float)(2.0 * fAngle - 2.0), 0.0, 0.0, 1.0);
drawGearGL(3);
glPopMatrix();
-
+
glPopMatrix();
}
@@ -256,13 +256,13 @@ static void setViewPortGL(GHOST_WindowHandle hWindow)
{
GHOST_RectangleHandle hRect = NULL;
GLfloat w, h;
-
+
GHOST_ActivateWindowDrawingContext(hWindow);
hRect = GHOST_GetClientBounds(hWindow);
-
+
w = (float)GHOST_GetWidthRectangle(hRect) / (float)GHOST_GetHeightRectangle(hRect);
h = 1.0;
-
+
glViewport(0, 0, GHOST_GetWidthRectangle(hRect), GHOST_GetHeightRectangle(hRect));
glMatrixMode(GL_PROJECTION);
@@ -272,7 +272,7 @@ static void setViewPortGL(GHOST_WindowHandle hWindow)
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glTranslatef(0.0, 0.0, -40.0);
-
+
glClearColor(.2f, 0.0f, 0.0f, 0.0f);
glClear(GL_COLOR_BUFFER_BIT);
@@ -290,7 +290,7 @@ int processEvent(GHOST_EventHandle hEvent, GHOST_TUserDataPtr userData)
GHOST_TEventWheelData *wheelData = NULL;
GHOST_DisplaySetting setting;
GHOST_WindowHandle window = GHOST_GetEventWindow(hEvent);
-
+
switch (GHOST_GetEventType(hEvent))
{
#if 0
@@ -316,7 +316,7 @@ int processEvent(GHOST_EventHandle hEvent, GHOST_TUserDataPtr userData)
case GHOST_kEventKeyUp:
break;
-
+
case GHOST_kEventKeyDown:
{
keyData = (GHOST_TEventKeyData *)GHOST_GetEventData(hEvent);
@@ -391,7 +391,7 @@ int processEvent(GHOST_EventHandle hEvent, GHOST_TUserDataPtr userData)
sprintf(ntitle, "%s-", title);
GHOST_SetTitle(sMainWindow, ntitle);
-
+
free(ntitle);
free(title);
}
@@ -402,7 +402,7 @@ int processEvent(GHOST_EventHandle hEvent, GHOST_TUserDataPtr userData)
}
}
break;
-
+
case GHOST_kEventWindowClose:
{
GHOST_WindowHandle window2 = GHOST_GetEventWindow(hEvent);
@@ -420,7 +420,7 @@ int processEvent(GHOST_EventHandle hEvent, GHOST_TUserDataPtr userData)
}
}
break;
-
+
case GHOST_kEventWindowActivate:
handled = 0;
break;
@@ -437,7 +437,7 @@ int processEvent(GHOST_EventHandle hEvent, GHOST_TUserDataPtr userData)
GHOST_SwapWindowBuffers(window2);
}
break;
-
+
default:
handled = 0;
break;
@@ -456,7 +456,7 @@ int main(int argc, char **argv)
/* Create the system */
shSystem = GHOST_CreateSystem();
GHOST_AddEventConsumer(shSystem, consumer);
-
+
if (shSystem)
{
/* Create the main window */
@@ -471,7 +471,7 @@ int main(int argc, char **argv)
printf("could not create main window\n");
exit(-1);
}
-
+
/* Create a secondary window */
sSecondaryWindow = GHOST_CreateWindow(
shSystem,
@@ -485,7 +485,7 @@ int main(int argc, char **argv)
printf("could not create secondary window\n");
exit(-1);
}
-
+
/* Install a timer to have the gears running */
sGearsTimer = GHOST_InstallTimer(shSystem,
0,
@@ -496,7 +496,7 @@ int main(int argc, char **argv)
/* Enter main loop */
while (!sExitRequested)
{
- if (!GHOST_ProcessEvents(shSystem, 0))
+ if (!GHOST_ProcessEvents(shSystem, 0))
{
#ifdef WIN32
/* If there were no events, be nice to other applications */
@@ -519,7 +519,7 @@ int main(int argc, char **argv)
/* Dispose the system */
GHOST_DisposeSystem(shSystem);
-
+
return 0;
}
diff --git a/intern/ghost/test/gears/GHOST_Test.cpp b/intern/ghost/test/gears/GHOST_Test.cpp
index f58a220055f..8c4d93fcbc4 100644
--- a/intern/ghost/test/gears/GHOST_Test.cpp
+++ b/intern/ghost/test/gears/GHOST_Test.cpp
@@ -273,7 +273,7 @@ static void View(GHOST_IWindow *window, bool stereo, int eye = 0)
if (stereo)
{
if (nVidiaWindows)
- {
+ {
// handled by nVidia driver so act as normal (explicitly put here since
// it -is- stereo)
glViewport(0, 0, bnds.getWidth(), bnds.getHeight());
@@ -666,7 +666,7 @@ bool Application::processEvent(GHOST_IEvent *event)
window2->swapBuffers();
}
break;
-
+
default:
handled = false;
break;
diff --git a/intern/ghost/test/multitest/Basic.h b/intern/ghost/test/multitest/Basic.h
index c8f61d40c57..86d68ef06cb 100644
--- a/intern/ghost/test/multitest/Basic.h
+++ b/intern/ghost/test/multitest/Basic.h
@@ -28,11 +28,11 @@
int min_i (int a, int b);
int max_i (int a, int b);
-int clamp_i (int val, int min, int max);
+int clamp_i (int val, int min, int max);
-float min_f (float a, float b);
-float max_f (float a, float b);
-float clamp_f (float val, float min, float max);
+float min_f (float a, float b);
+float max_f (float a, float b);
+float clamp_f (float val, float min, float max);
void rect_copy (int dst[2][2], int src[2][2]);
int rect_contains_pt (int rect[2][2], int pt[2]);
diff --git a/intern/ghost/test/multitest/EventToBuf.c b/intern/ghost/test/multitest/EventToBuf.c
index 49255de5e64..7401ab83dbf 100644
--- a/intern/ghost/test/multitest/EventToBuf.c
+++ b/intern/ghost/test/multitest/EventToBuf.c
@@ -47,7 +47,7 @@ char *eventtype_to_string(GHOST_TEventType type)
case GHOST_kEventQuit: return "Quit";
case GHOST_kEventWindowClose: return "WindowClose";
- case GHOST_kEventWindowActivate: return "WindowActivate";
+ case GHOST_kEventWindowActivate: return "WindowActivate";
case GHOST_kEventWindowDeactivate: return "WindowDeactivate";
case GHOST_kEventWindowUpdate: return "WindowUpdate";
case GHOST_kEventWindowSize: return "WindowSize";
@@ -188,7 +188,7 @@ static char *keytype_to_string(GHOST_TKey key)
K(KeyF22);
K(KeyF23);
K(KeyF24);
-
+
default:
return "KeyUnknown";
}
diff --git a/intern/ghost/test/multitest/MultiTest.c b/intern/ghost/test/multitest/MultiTest.c
index 833b5c720a1..8cd31c3137e 100644
--- a/intern/ghost/test/multitest/MultiTest.c
+++ b/intern/ghost/test/multitest/MultiTest.c
@@ -79,7 +79,7 @@ void rect_bevel_side(int rect[2][2], int side, float *lt, float *dk, const float
int ltidx = (side / 2) % 4;
int dkidx = (ltidx + 1 + (side & 1)) % 4;
int i, corner;
-
+
glBegin(GL_LINES);
for (i = 0; i < width; i++) {
float ltf = pow(lt[i], 1.0 / 2.2), dkf = pow(dk[i], 1.0 / 2.2);
@@ -102,7 +102,7 @@ void rect_bevel_side(int rect[2][2], int side, float *lt, float *dk, const float
}
}
glEnd();
-
+
glColor3fv(col);
glRecti(rect[0][0] + width, rect[0][1] + width, rect[1][0] - width, rect[1][1] - width);
}
@@ -113,17 +113,17 @@ void rect_bevel_smooth(int rect[2][2], int width)
float *dk = malloc(sizeof(*dk) * width);
float col[4];
int i;
-
+
for (i = 0; i < width; i++) {
float v = width - 1 ? ((float) i / (width - 1)) : 0;
lt[i] = 1.2 + (1.0 - 1.2) * v;
dk[i] = 0.2 + (1.0 - 0.2) * v;
}
-
+
glGetFloatv(GL_CURRENT_COLOR, col);
-
+
rect_bevel_side(rect, 3, lt, dk, col, width);
-
+
free(lt);
free(dk);
}
@@ -136,11 +136,11 @@ typedef struct {
MultiTestApp *app;
GHOST_WindowHandle win;
-
+
int size[2];
-
+
int lmouse[2], lmbut[3];
-
+
int tmouse[2];
} MainWindow;
@@ -152,18 +152,18 @@ static void mainwindow_log(MainWindow *mw, char *str)
static void mainwindow_do_draw(MainWindow *mw)
{
GHOST_ActivateWindowDrawingContext(mw->win);
-
+
if (mw->lmbut[0]) {
glClearColor(0.5, 0.5, 0.5, 1);
}
else {
glClearColor(1, 1, 1, 1);
- }
+ }
glClear(GL_COLOR_BUFFER_BIT);
-
+
glColor3f(0.5, 0.6, 0.8);
glRecti(mw->tmouse[0] - 5, mw->tmouse[1] - 5, mw->tmouse[0] + 5, mw->tmouse[1] + 5);
-
+
GHOST_SwapWindowBuffers(mw->win);
}
@@ -175,7 +175,7 @@ static void mainwindow_do_reshape(MainWindow *mw)
mw->size[0] = GHOST_GetWidthRectangle(bounds);
mw->size[1] = GHOST_GetHeightRectangle(bounds);
-
+
glViewport(0, 0, mw->size[0], mw->size[1]);
glMatrixMode(GL_PROJECTION);
@@ -234,7 +234,7 @@ static void mainwindow_do_key(MainWindow *mw, GHOST_TKey key, int press)
static void mainwindow_do_move(MainWindow *mw, int x, int y)
{
mw->lmouse[0] = x, mw->lmouse[1] = y;
-
+
if (mw->lmbut[0]) {
mw->tmouse[0] = x, mw->tmouse[1] = y;
GHOST_InvalidateWindow(mw->win);
@@ -261,10 +261,10 @@ static void mainwindow_handle(void *priv, GHOST_EventHandle evt)
MainWindow *mw = priv;
GHOST_TEventType type = GHOST_GetEventType(evt);
char buf[256];
-
+
event_to_buf(evt, buf);
mainwindow_log(mw, buf);
-
+
switch (type) {
case GHOST_kEventCursorMove:
{
@@ -304,7 +304,7 @@ static void mainwindow_timer_proc(GHOST_TimerTaskHandle task, GHOST_TUns64 time)
{
MainWindow *mw = GHOST_GetTimerTaskUserData(task);
char buf[64];
-
+
sprintf(buf, "timer: %6.2f", (double) ((GHOST_TInt64) time) / 1000);
mainwindow_log(mw, buf);
}
@@ -314,23 +314,23 @@ 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,
glSettings);
-
+
if (win) {
MainWindow *mw = MEM_callocN(sizeof(*mw), "mainwindow_new");
mw->app = app;
mw->win = win;
-
+
GHOST_SetWindowUserData(mw->win, windowdata_new(mw, mainwindow_handle));
-
+
GHOST_InstallTimer(sys, 1000, 10000, mainwindow_timer_proc, mw);
-
+
return mw;
}
else {
@@ -356,23 +356,23 @@ struct _LoggerWindow {
GHOST_WindowHandle win;
-#ifdef USE_BMF
+#ifdef USE_BMF
BMF_Font *font;
#else
int font;
#endif
int fonttexid;
int fontheight;
-
+
int size[2];
-
+
int ndisplines;
int textarea[2][2];
ScrollBar *scroll;
-
+
char **loglines;
int nloglines, logsize;
-
+
int lmbut[3];
int lmouse[2];
};
@@ -383,7 +383,7 @@ struct _LoggerWindow {
static void loggerwindow_recalc_regions(LoggerWindow *lw)
{
int nscroll[2][2];
-
+
nscroll[0][0] = SCROLLBAR_PAD;
nscroll[0][1] = SCROLLBAR_PAD;
nscroll[1][0] = nscroll[0][0] + SCROLLBAR_WIDTH;
@@ -418,10 +418,10 @@ static void loggerwindow_do_reshape(LoggerWindow *lw)
GHOST_RectangleHandle bounds = GHOST_GetClientBounds(lw->win);
GHOST_ActivateWindowDrawingContext(lw->win);
-
+
lw->size[0] = GHOST_GetWidthRectangle(bounds);
lw->size[1] = GHOST_GetHeightRectangle(bounds);
-
+
loggerwindow_recalc_regions(lw);
loggerwindow_setup_window_gl(lw);
}
@@ -430,21 +430,21 @@ static void loggerwindow_do_draw(LoggerWindow *lw)
{
int i, ndisplines, startline;
int sb_rect[2][2], sb_thumb[2][2];
-
+
GHOST_ActivateWindowDrawingContext(lw->win);
-
+
glClearColor(1, 1, 1, 1);
glClear(GL_COLOR_BUFFER_BIT);
glColor3f(0.8, 0.8, 0.8);
rect_bevel_smooth(lw->textarea, 4);
-
+
scrollbar_get_rect(lw->scroll, sb_rect);
scrollbar_get_thumb(lw->scroll, sb_thumb);
-
+
glColor3f(0.6, 0.6, 0.6);
rect_bevel_smooth(sb_rect, 1);
-
+
if (scrollbar_is_scrolling(lw->scroll)) {
glColor3f(0.6, 0.7, 0.5);
}
@@ -452,16 +452,16 @@ static void loggerwindow_do_draw(LoggerWindow *lw)
glColor3f(0.9, 0.9, 0.92);
}
rect_bevel_smooth(sb_thumb, 1);
-
+
startline = scrollbar_get_thumbpos(lw->scroll) * (lw->nloglines - 1);
ndisplines = min_i(lw->ndisplines, lw->nloglines - startline);
if (lw->fonttexid != -1) {
glBindTexture(GL_TEXTURE_2D, lw->fonttexid);
-
+
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glEnable(GL_BLEND);
- glEnable(GL_TEXTURE_2D);
+ glEnable(GL_TEXTURE_2D);
}
glColor3f(0, 0, 0);
for (i = 0; i < ndisplines; i++) {
@@ -470,7 +470,7 @@ static void loggerwindow_do_draw(LoggerWindow *lw)
int x_pos = lw->textarea[0][0] + 4;
int y_pos = lw->textarea[0][1] + 4 + i * lw->fontheight;
-#ifdef USE_BMF
+#ifdef USE_BMF
if (lw->fonttexid == -1) {
glRasterPos2i(x_pos, y_pos);
BMF_DrawString(lw->font, line);
@@ -486,7 +486,7 @@ static void loggerwindow_do_draw(LoggerWindow *lw)
#ifdef USE_BMF
if (lw->fonttexid != -1) {
- glDisable(GL_TEXTURE_2D);
+ glDisable(GL_TEXTURE_2D);
glDisable(GL_BLEND);
}
#endif
@@ -497,7 +497,7 @@ static void loggerwindow_do_draw(LoggerWindow *lw)
static void loggerwindow_do_move(LoggerWindow *lw, int x, int y)
{
lw->lmouse[0] = x, lw->lmouse[1] = y;
-
+
if (scrollbar_is_scrolling(lw->scroll)) {
scrollbar_keep_scrolling(lw->scroll, y);
GHOST_InvalidateWindow(lw->win);
@@ -508,10 +508,10 @@ static void loggerwindow_do_button(LoggerWindow *lw, int which, int press)
{
if (which == GHOST_kButtonMaskLeft) {
lw->lmbut[0] = press;
-
+
if (press) {
if (scrollbar_contains_pt(lw->scroll, lw->lmouse)) {
- scrollbar_start_scrolling(lw->scroll, lw->lmouse[1]);
+ scrollbar_start_scrolling(lw->scroll, lw->lmouse[1]);
GHOST_SetCursorShape(lw->win, GHOST_kStandardCursorUpDown);
GHOST_InvalidateWindow(lw->win);
}
@@ -546,7 +546,7 @@ static void loggerwindow_handle(void *priv, GHOST_EventHandle evt)
{
LoggerWindow *lw = priv;
GHOST_TEventType type = GHOST_GetEventType(evt);
-
+
switch (type) {
case GHOST_kEventCursorMove:
{
@@ -588,7 +588,7 @@ LoggerWindow *loggerwindow_new(MultiTestApp *app)
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",
@@ -596,7 +596,7 @@ LoggerWindow *loggerwindow_new(MultiTestApp *app)
GHOST_kWindowStateNormal,
GHOST_kDrawingContextTypeOpenGL,
glSettings);
-
+
if (win) {
LoggerWindow *lw = MEM_callocN(sizeof(*lw), "loggerwindow_new");
int bbox[2][2];
@@ -614,12 +614,12 @@ LoggerWindow *loggerwindow_new(MultiTestApp *app)
BLF_size(lw->font, 11, 72);
lw->fontheight = BLF_height(lw->font, "A_", 2);
#endif
-
+
lw->nloglines = lw->logsize = 0;
lw->loglines = MEM_mallocN(sizeof(*lw->loglines) * lw->nloglines, "loglines");
-
+
lw->scroll = scrollbar_new(2, 40);
-
+
GHOST_SetWindowUserData(lw->win, windowdata_new(lw, loggerwindow_handle));
loggerwindow_do_reshape(lw);
@@ -636,10 +636,10 @@ void loggerwindow_log(LoggerWindow *lw, char *line)
if (lw->nloglines == lw->logsize) {
lw->loglines = memdbl(lw->loglines, &lw->logsize, sizeof(*lw->loglines));
}
-
+
lw->loglines[lw->nloglines++] = string_dup(line);
scrollbar_set_thumbpct(lw->scroll, (float) lw->ndisplines / lw->nloglines);
-
+
GHOST_InvalidateWindow(lw->win);
}
@@ -652,7 +652,7 @@ void loggerwindow_free(LoggerWindow *lw)
MEM_freeN(lw->loglines[i]);
}
MEM_freeN(lw->loglines);
-
+
windowdata_free(GHOST_GetWindowUserData(lw->win));
GHOST_DisposeWindow(sys, lw->win);
MEM_freeN(lw);
@@ -667,7 +667,7 @@ typedef struct {
MultiTestApp *app;
GHOST_WindowHandle win;
-
+
int size[2];
} ExtraWindow;
@@ -677,10 +677,10 @@ static void extrawindow_do_draw(ExtraWindow *ew)
glClearColor(1, 1, 1, 1);
glClear(GL_COLOR_BUFFER_BIT);
-
+
glColor3f(0.8, 0.8, 0.8);
glRecti(10, 10, ew->size[0] - 10, ew->size[1] - 10);
-
+
GHOST_SwapWindowBuffers(ew->win);
}
@@ -692,7 +692,7 @@ static void extrawindow_do_reshape(ExtraWindow *ew)
ew->size[0] = GHOST_GetWidthRectangle(bounds);
ew->size[1] = GHOST_GetHeightRectangle(bounds);
-
+
glViewport(0, 0, ew->size[0], ew->size[1]);
glMatrixMode(GL_PROJECTION);
@@ -721,15 +721,15 @@ static void extrawindow_spin_cursor(ExtraWindow *ew, GHOST_TUns64 time)
double ftime = (double) ((GHOST_TInt64) time) / 1000;
float angle = fmod(ftime, 1.0) * 3.1415 * 2;
int i;
-
+
memset(&bitmap, 0, sizeof(bitmap));
memset(&mask, 0, sizeof(mask));
-
+
bitmap[0][0] |= mask[0][0] |= 0xF;
bitmap[1][0] |= mask[1][0] |= 0xF;
bitmap[2][0] |= mask[2][0] |= 0xF;
bitmap[3][0] |= mask[3][0] |= 0xF;
-
+
for (i = 0; i < 7; i++) {
int x = 7 + cos(angle) * i;
int y = 7 + sin(angle) * i;
@@ -740,10 +740,10 @@ static void extrawindow_spin_cursor(ExtraWindow *ew, GHOST_TUns64 time)
float v = (i / 63.0) * 3.1415 * 2;
int x = 7 + cos(v) * 7;
int y = 7 + sin(v) * 7;
-
+
mask[y][x / 8] |= (1 << (x % 8));
}
-
+
GHOST_SetCustomCursorShape(ew->win, bitmap, mask, 0, 0);
}
@@ -752,10 +752,10 @@ static void extrawindow_handle(void *priv, GHOST_EventHandle evt)
ExtraWindow *ew = priv;
GHOST_TEventType type = GHOST_GetEventType(evt);
char buf[256];
-
+
event_to_buf(evt, buf);
loggerwindow_log(multitestapp_get_logger(ew->app), buf);
-
+
switch (type) {
case GHOST_kEventKeyDown:
case GHOST_kEventKeyUp:
@@ -790,21 +790,21 @@ 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,
glSettings);
-
+
if (win) {
ExtraWindow *ew = MEM_callocN(sizeof(*ew), "mainwindow_new");
ew->app = app;
ew->win = win;
-
+
GHOST_SetWindowUserData(ew->win, windowdata_new(ew, extrawindow_handle));
-
+
return ew;
}
else {
@@ -824,13 +824,13 @@ void extrawindow_free(ExtraWindow *ew)
/*
* MultiTestApp
*/
-
+
struct _MultiTestApp {
GHOST_SystemHandle sys;
MainWindow *main;
LoggerWindow *logger;
ExtraWindow *extra;
-
+
int exit;
};
@@ -838,21 +838,21 @@ static int multitest_event_handler(GHOST_EventHandle evt, GHOST_TUserDataPtr dat
{
MultiTestApp *app = data;
GHOST_WindowHandle win;
-
+
win = GHOST_GetEventWindow(evt);
if (win && !GHOST_ValidWindow(app->sys, win)) {
loggerwindow_log(app->logger, "WARNING: bad event, non-valid window\n");
return 1;
}
-
+
if (win) {
WindowData *wb = GHOST_GetWindowUserData(win);
-
+
windowdata_handle(wb, evt);
}
else {
GHOST_TEventType type = GHOST_GetEventType(evt);
-
+
/* GHOST_kEventQuit are the only 'system' events,
* that is, events without a window.
*/
@@ -866,7 +866,7 @@ static int multitest_event_handler(GHOST_EventHandle evt, GHOST_TUserDataPtr dat
break;
}
}
-
+
return 1;
}
@@ -880,25 +880,25 @@ MultiTestApp *multitestapp_new(void) {
if (!app->sys)
fatal("Unable to create ghost system");
- if (!GHOST_AddEventConsumer(app->sys, consumer))
+ if (!GHOST_AddEventConsumer(app->sys, consumer))
fatal("Unable to add multitest event consumer ");
-
+
app->main = mainwindow_new(app);
- if (!app->main)
+ if (!app->main)
fatal("Unable to create main window");
-
+
app->logger = loggerwindow_new(app);
if (!app->logger)
fatal("Unable to create logger window");
app->extra = NULL;
app->exit = 0;
-
+
return app;
}
LoggerWindow *multitestapp_get_logger(MultiTestApp *app) {
- return app->logger;
+ return app->logger;
}
GHOST_SystemHandle multitestapp_get_system(MultiTestApp *app) {
@@ -943,7 +943,7 @@ void multitestapp_free(MultiTestApp *app)
}
/***/
-
+
int main(int argc, char **argv)
{
MultiTestApp *app;
@@ -953,9 +953,9 @@ int main(int argc, char **argv)
#endif
app = multitestapp_new();
-
+
multitestapp_run(app);
multitestapp_free(app);
-
+
return 0;
}
diff --git a/intern/ghost/test/multitest/ScrollBar.c b/intern/ghost/test/multitest/ScrollBar.c
index 8964d304920..2a363f3ce5d 100644
--- a/intern/ghost/test/multitest/ScrollBar.c
+++ b/intern/ghost/test/multitest/ScrollBar.c
@@ -37,7 +37,7 @@
struct _ScrollBar {
int rect[2][2];
float thumbpos, thumbpct;
-
+
int inset;
int minthumb;
@@ -48,7 +48,7 @@ struct _ScrollBar {
static int scrollbar_get_thumbH(ScrollBar *sb)
{
int scrollable_h = rect_height(sb->rect) - 2 * sb->inset;
-
+
return clamp_i(sb->thumbpct * scrollable_h, sb->minthumb, scrollable_h);
}
@@ -56,7 +56,7 @@ static int scrollbar_get_thumbableH(ScrollBar *sb)
{
int scrollable_h = rect_height(sb->rect) - 2 * sb->inset;
int thumb_h = scrollbar_get_thumbH(sb);
-
+
return scrollable_h - thumb_h;
}
@@ -76,7 +76,7 @@ ScrollBar *scrollbar_new(int inset, int minthumb)
ScrollBar *sb = MEM_callocN(sizeof(*sb), "scrollbar_new");
sb->inset = inset;
sb->minthumb = minthumb;
-
+
return sb;
}
diff --git a/intern/ghost/test/multitest/ScrollBar.h b/intern/ghost/test/multitest/ScrollBar.h
index 8c8d02d197e..dd737539bf2 100644
--- a/intern/ghost/test/multitest/ScrollBar.h
+++ b/intern/ghost/test/multitest/ScrollBar.h
@@ -29,7 +29,7 @@ typedef struct _ScrollBar ScrollBar;
/***/
-
+
ScrollBar* scrollbar_new (int inset, int minthumb);
int scrollbar_is_scrolling (ScrollBar *sb);
diff --git a/intern/ghost/test/multitest/Util.c b/intern/ghost/test/multitest/Util.c
index bacd0a313d4..9ac7ae0263d 100644
--- a/intern/ghost/test/multitest/Util.c
+++ b/intern/ghost/test/multitest/Util.c
@@ -40,10 +40,10 @@ void *memdbl(void *mem, int *size_pr, int item_size)
int cur_size = *size_pr;
int new_size = cur_size ? (cur_size * 2) : 1;
void *nmem = MEM_mallocN(new_size * item_size, "memdbl");
-
+
memcpy(nmem, mem, cur_size * item_size);
MEM_freeN(mem);
-
+
*size_pr = new_size;
return nmem;
}
@@ -54,19 +54,19 @@ char *string_dup(char *str)
char *nstr = MEM_mallocN(len + 1, "string_dup");
memcpy(nstr, str, len + 1);
-
+
return nstr;
}
void fatal(char *fmt, ...)
{
va_list ap;
-
+
fprintf(stderr, "FATAL: ");
va_start(ap, fmt);
vfprintf(stderr, fmt, ap);
va_end(ap);
fprintf(stderr, "\n");
-
+
exit(1);
}
diff --git a/intern/ghost/test/multitest/WindowData.c b/intern/ghost/test/multitest/WindowData.c
index de4992ab2a0..07078cd9238 100644
--- a/intern/ghost/test/multitest/WindowData.c
+++ b/intern/ghost/test/multitest/WindowData.c
@@ -43,7 +43,7 @@ WindowData *windowdata_new(void *data, WindowDataHandler handler)
WindowData *wb = MEM_mallocN(sizeof(*wb), "windowdata_new");
wb->data = data;
wb->handler = handler;
-
+
return wb;
}
diff --git a/intern/ghost/test/multitest/WindowData.h b/intern/ghost/test/multitest/WindowData.h
index f8198101b8d..0e6c7518843 100644
--- a/intern/ghost/test/multitest/WindowData.h
+++ b/intern/ghost/test/multitest/WindowData.h
@@ -27,9 +27,9 @@
typedef void (*WindowDataHandler)(void *priv, GHOST_EventHandle evt);
typedef struct _WindowData WindowData;
-
+
/***/
-
+
WindowData* windowdata_new (void *data, WindowDataHandler handler);
void windowdata_handle (WindowData *wb, GHOST_EventHandle evt);
void windowdata_free (WindowData *wb);
diff --git a/release/datafiles/studiolights/matcap/license.txt b/release/datafiles/studiolights/matcap/license.txt
new file mode 100644
index 00000000000..358c8dcd832
--- /dev/null
+++ b/release/datafiles/studiolights/matcap/license.txt
@@ -0,0 +1,3 @@
+These matcap images are licensed as GNU GPL 2 or later, like the rest of Blender's code.
+
+Thanks to Kent Trammell, Aidy Burrows, John Herreno , Terry Wallwork and David Silverman for making the pictures.
diff --git a/release/datafiles/studiolights/matcap/mc01.jpg b/release/datafiles/studiolights/matcap/mc01.jpg
new file mode 100644
index 00000000000..8c7aef287ee
--- /dev/null
+++ b/release/datafiles/studiolights/matcap/mc01.jpg
Binary files differ
diff --git a/release/datafiles/studiolights/matcap/mc02.jpg b/release/datafiles/studiolights/matcap/mc02.jpg
new file mode 100644
index 00000000000..11deddfeaed
--- /dev/null
+++ b/release/datafiles/studiolights/matcap/mc02.jpg
Binary files differ
diff --git a/release/datafiles/studiolights/matcap/mc03.jpg b/release/datafiles/studiolights/matcap/mc03.jpg
new file mode 100644
index 00000000000..64d992fb61a
--- /dev/null
+++ b/release/datafiles/studiolights/matcap/mc03.jpg
Binary files differ
diff --git a/release/datafiles/studiolights/matcap/mc04.jpg b/release/datafiles/studiolights/matcap/mc04.jpg
new file mode 100644
index 00000000000..42be580ee93
--- /dev/null
+++ b/release/datafiles/studiolights/matcap/mc04.jpg
Binary files differ
diff --git a/release/datafiles/studiolights/matcap/mc05.jpg b/release/datafiles/studiolights/matcap/mc05.jpg
new file mode 100644
index 00000000000..586d233ef31
--- /dev/null
+++ b/release/datafiles/studiolights/matcap/mc05.jpg
Binary files differ
diff --git a/release/datafiles/studiolights/matcap/mc06.jpg b/release/datafiles/studiolights/matcap/mc06.jpg
new file mode 100644
index 00000000000..657883d0866
--- /dev/null
+++ b/release/datafiles/studiolights/matcap/mc06.jpg
Binary files differ
diff --git a/release/datafiles/studiolights/matcap/mc07.jpg b/release/datafiles/studiolights/matcap/mc07.jpg
new file mode 100644
index 00000000000..372caf7e87c
--- /dev/null
+++ b/release/datafiles/studiolights/matcap/mc07.jpg
Binary files differ
diff --git a/release/datafiles/studiolights/matcap/mc08.jpg b/release/datafiles/studiolights/matcap/mc08.jpg
new file mode 100644
index 00000000000..50eec402812
--- /dev/null
+++ b/release/datafiles/studiolights/matcap/mc08.jpg
Binary files differ
diff --git a/release/datafiles/studiolights/matcap/mc09.jpg b/release/datafiles/studiolights/matcap/mc09.jpg
new file mode 100644
index 00000000000..e05d441aaf9
--- /dev/null
+++ b/release/datafiles/studiolights/matcap/mc09.jpg
Binary files differ
diff --git a/release/datafiles/studiolights/matcap/mc10.jpg b/release/datafiles/studiolights/matcap/mc10.jpg
new file mode 100644
index 00000000000..ab82f17bb93
--- /dev/null
+++ b/release/datafiles/studiolights/matcap/mc10.jpg
Binary files differ
diff --git a/release/datafiles/studiolights/matcap/mc11.jpg b/release/datafiles/studiolights/matcap/mc11.jpg
new file mode 100644
index 00000000000..053550f082c
--- /dev/null
+++ b/release/datafiles/studiolights/matcap/mc11.jpg
Binary files differ
diff --git a/release/datafiles/studiolights/matcap/mc12.jpg b/release/datafiles/studiolights/matcap/mc12.jpg
new file mode 100644
index 00000000000..beb16f3742e
--- /dev/null
+++ b/release/datafiles/studiolights/matcap/mc12.jpg
Binary files differ
diff --git a/release/datafiles/studiolights/matcap/mc13.jpg b/release/datafiles/studiolights/matcap/mc13.jpg
new file mode 100644
index 00000000000..7fb8fa58e8f
--- /dev/null
+++ b/release/datafiles/studiolights/matcap/mc13.jpg
Binary files differ
diff --git a/release/datafiles/studiolights/matcap/mc14.jpg b/release/datafiles/studiolights/matcap/mc14.jpg
new file mode 100644
index 00000000000..ba868d2f95a
--- /dev/null
+++ b/release/datafiles/studiolights/matcap/mc14.jpg
Binary files differ
diff --git a/release/datafiles/studiolights/matcap/mc15.jpg b/release/datafiles/studiolights/matcap/mc15.jpg
new file mode 100644
index 00000000000..b10ea326a42
--- /dev/null
+++ b/release/datafiles/studiolights/matcap/mc15.jpg
Binary files differ
diff --git a/release/datafiles/studiolights/matcap/mc16.jpg b/release/datafiles/studiolights/matcap/mc16.jpg
new file mode 100644
index 00000000000..c6ce02d59df
--- /dev/null
+++ b/release/datafiles/studiolights/matcap/mc16.jpg
Binary files differ
diff --git a/release/datafiles/studiolights/matcap/mc17.jpg b/release/datafiles/studiolights/matcap/mc17.jpg
new file mode 100644
index 00000000000..14f15f70460
--- /dev/null
+++ b/release/datafiles/studiolights/matcap/mc17.jpg
Binary files differ
diff --git a/release/datafiles/studiolights/matcap/mc18.jpg b/release/datafiles/studiolights/matcap/mc18.jpg
new file mode 100644
index 00000000000..db572856b07
--- /dev/null
+++ b/release/datafiles/studiolights/matcap/mc18.jpg
Binary files differ
diff --git a/release/datafiles/studiolights/matcap/mc19.jpg b/release/datafiles/studiolights/matcap/mc19.jpg
new file mode 100644
index 00000000000..56d2efb1734
--- /dev/null
+++ b/release/datafiles/studiolights/matcap/mc19.jpg
Binary files differ
diff --git a/release/datafiles/studiolights/matcap/mc20.jpg b/release/datafiles/studiolights/matcap/mc20.jpg
new file mode 100644
index 00000000000..002a0910dd9
--- /dev/null
+++ b/release/datafiles/studiolights/matcap/mc20.jpg
Binary files differ
diff --git a/release/datafiles/studiolights/matcap/mc21.jpg b/release/datafiles/studiolights/matcap/mc21.jpg
new file mode 100644
index 00000000000..cb2fea573b8
--- /dev/null
+++ b/release/datafiles/studiolights/matcap/mc21.jpg
Binary files differ
diff --git a/release/datafiles/studiolights/matcap/mc22.jpg b/release/datafiles/studiolights/matcap/mc22.jpg
new file mode 100644
index 00000000000..2fc71b98c5a
--- /dev/null
+++ b/release/datafiles/studiolights/matcap/mc22.jpg
Binary files differ
diff --git a/release/datafiles/studiolights/matcap/mc23.jpg b/release/datafiles/studiolights/matcap/mc23.jpg
new file mode 100644
index 00000000000..3793c0fcaa5
--- /dev/null
+++ b/release/datafiles/studiolights/matcap/mc23.jpg
Binary files differ
diff --git a/release/datafiles/studiolights/matcap/mc24.jpg b/release/datafiles/studiolights/matcap/mc24.jpg
new file mode 100644
index 00000000000..2a9618d8fe1
--- /dev/null
+++ b/release/datafiles/studiolights/matcap/mc24.jpg
Binary files differ
diff --git a/release/scripts/addons b/release/scripts/addons
-Subproject 4b91309b122bcdcddd1854b1137407b2c4f55c7
+Subproject ebd058d7a6438d137522063bb3286c8acc325ca
diff --git a/release/scripts/addons_contrib b/release/scripts/addons_contrib
-Subproject cd57934bd04c174fc3402888d01a74e6e6653b2
+Subproject 474702157831f1a58bb50f5240ab8b1b02b6ba3
diff --git a/release/scripts/startup/bl_operators/wm.py b/release/scripts/startup/bl_operators/wm.py
index ee101bb3cc6..b0a5e19d269 100644
--- a/release/scripts/startup/bl_operators/wm.py
+++ b/release/scripts/startup/bl_operators/wm.py
@@ -19,13 +19,17 @@
# <pep8 compliant>
import bpy
-from bpy.types import Operator
+from bpy.types import (
+ Operator,
+ OperatorFileListElement
+)
from bpy.props import (
BoolProperty,
EnumProperty,
FloatProperty,
IntProperty,
StringProperty,
+ CollectionProperty,
)
from bpy.app.translations import pgettext_tip as tip_
@@ -2394,12 +2398,126 @@ class WM_OT_toolbar(Operator):
def draw_menu(popover, context):
layout = popover.layout
- cls.draw_cls(layout, context, detect_layout=False)
+ cls.draw_cls(layout, context, detect_layout=False, scale_y=1.0)
wm.popover(draw_menu, keymap=keymap)
return {'FINISHED'}
+# Studio Light operations
+class WM_OT_studiolight_install(Operator):
+ """Install a user defined studio light"""
+ bl_idname = "wm.studiolight_install"
+ bl_label = "Install Custom Studio Light"
+
+ files = CollectionProperty(
+ name="File Path",
+ type=OperatorFileListElement,
+ )
+ directory = StringProperty(
+ subtype='DIR_PATH',
+ )
+ filter_folder = BoolProperty(
+ name="Filter folders",
+ default=True,
+ options={'HIDDEN'},
+ )
+ filter_glob = StringProperty(
+ default="*.png;*.jpg;*.hdr;*.exr",
+ options={'HIDDEN'},
+ )
+ orientation = EnumProperty(
+ items=(
+ ("MATCAP", "MatCap", ""),
+ ("WORLD", "World", ""),
+ ("CAMERA", "Camera", ""),
+ )
+ )
+
+ def execute(self, context):
+ import traceback
+ import shutil
+ import pathlib
+ userpref = context.user_preferences
+
+ filepaths = [pathlib.Path(self.directory, e.name) for e in self.files]
+ path_studiolights = bpy.utils.user_resource('DATAFILES')
+
+ if not path_studiolights:
+ self.report({'ERROR'}, "Failed to get Studio Light path")
+ return {'CANCELLED'}
+
+ path_studiolights = pathlib.Path(path_studiolights, "studiolights", self.orientation.lower())
+ if not path_studiolights.exists():
+ try:
+ path_studiolights.mkdir(parents=True, exist_ok=True)
+ except:
+ traceback.print_exc()
+
+ for filepath in filepaths:
+ shutil.copy(str(filepath), str(path_studiolights))
+ userpref.studio_lights_refresh()
+
+ # print message
+ msg = (
+ tip_("StudioLight Installed %r into %r") %
+ (", ".join(str(x.name) for x in self.files), str(path_studiolights))
+ )
+ print(msg)
+ self.report({'INFO'}, msg)
+ return {'FINISHED'}
+
+ def invoke(self, context, event):
+ wm = context.window_manager
+ wm.fileselect_add(self)
+ return {'RUNNING_MODAL'}
+
+
+class WM_OT_studiolight_uninstall(Operator):
+ bl_idname = 'wm.studiolight_uninstall'
+ bl_label = "Uninstall Studio Light"
+ index = bpy.props.IntProperty()
+
+ def execute(self, context):
+ import pathlib
+ userpref = context.user_preferences
+ for studio_light in userpref.studio_lights:
+ if studio_light.index == self.index:
+ path = pathlib.Path(studio_light.path)
+ if path.exists():
+ path.unlink()
+ userpref.studio_lights_refresh()
+ return {'FINISHED'}
+ return {'CANCELLED'}
+
+
+class WM_OT_studiolight_expand(Operator):
+ bl_idname = "wm.studiolight_expand"
+ bl_label = "Expand Studio Light"
+ index = bpy.props.IntProperty()
+
+ def execute(self, context):
+ userpref = context.user_preferences
+ for studio_light in userpref.studio_lights:
+ if studio_light.index == self.index:
+ studio_light.show_expanded = not studio_light.show_expanded
+ break
+
+ return {'FINISHED'}
+
+
+class WM_OT_studiolight_userpref_show(Operator):
+ """Show light user preferences"""
+ bl_idname = "wm.studiolight_userpref_show"
+ bl_label = ""
+ bl_options = {'INTERNAL'}
+
+ def execute(self, context):
+ context.user_preferences.active_section = 'LIGHTS'
+ bpy.ops.screen.userpref_show('INVOKE_DEFAULT')
+ return {'FINISHED'}
+
+
classes = (
BRUSH_OT_active_index_set,
WM_OT_addon_disable,
@@ -2454,6 +2572,10 @@ classes = (
WM_OT_owner_disable,
WM_OT_owner_enable,
WM_OT_url_open,
+ WM_OT_studiolight_expand,
+ WM_OT_studiolight_install,
+ WM_OT_studiolight_uninstall,
+ WM_OT_studiolight_userpref_show,
WM_OT_tool_set_by_name,
WM_OT_toolbar,
)
diff --git a/release/scripts/startup/bl_ui/__init__.py b/release/scripts/startup/bl_ui/__init__.py
index b4ec29330c5..1518119eadc 100644
--- a/release/scripts/startup/bl_ui/__init__.py
+++ b/release/scripts/startup/bl_ui/__init__.py
@@ -89,7 +89,7 @@ _modules = [
"space_userpref",
"space_view3d",
"space_view3d_toolbar",
- ]
+]
import bpy
@@ -168,6 +168,8 @@ def unregister():
# Define a default UIList, when a list does not need any custom drawing...
# Keep in sync with its #defined name in UI_interface.h
+
+
class UI_UL_list(bpy.types.UIList):
# These are common filtering or ordering operations (same as the default C ones!).
@staticmethod
diff --git a/release/scripts/startup/bl_ui/properties_constraint.py b/release/scripts/startup/bl_ui/properties_constraint.py
index 9b61101778f..b7880e605b3 100644
--- a/release/scripts/startup/bl_ui/properties_constraint.py
+++ b/release/scripts/startup/bl_ui/properties_constraint.py
@@ -941,6 +941,7 @@ class BONE_PT_constraints(ConstraintButtonsPanel, Panel):
for con in context.pose_bone.constraints:
self.draw_constraint(context, con)
+
classes = (
OBJECT_PT_constraints,
BONE_PT_constraints,
diff --git a/release/scripts/startup/bl_ui/properties_data_curve.py b/release/scripts/startup/bl_ui/properties_data_curve.py
index 057a7233206..47c53d6ffb5 100644
--- a/release/scripts/startup/bl_ui/properties_data_curve.py
+++ b/release/scripts/startup/bl_ui/properties_data_curve.py
@@ -180,6 +180,7 @@ class DATA_PT_geometry_curve(CurveButtonsPanelCurve, Panel):
sub.active = curve.taper_object is not None
sub.prop(curve, "use_map_taper")
+
class DATA_PT_geometry_curve_bevel(CurveButtonsPanelCurve, Panel):
bl_label = "Bevel"
bl_parent_id = "DATA_PT_geometry_curve"
@@ -348,6 +349,7 @@ class DATA_PT_font(CurveButtonsPanelText, Panel):
row.prop(char, "use_underline", toggle=True)
row.prop(char, "use_small_caps", toggle=True)
+
class DATA_PT_font_transform(CurveButtonsPanelText, Panel):
bl_label = "Transform"
bl_parent_id = "DATA_PT_font"
@@ -404,7 +406,6 @@ class DATA_PT_paragraph_alignment(CurveButtonsPanelText, Panel):
layout.row().prop(text, "align_y", expand=True)
-
class DATA_PT_paragraph_spacing(CurveButtonsPanelText, Panel):
bl_parent_id = "DATA_PT_paragraph"
bl_label = "Spacing"
diff --git a/release/scripts/startup/bl_ui/properties_data_lamp.py b/release/scripts/startup/bl_ui/properties_data_lamp.py
index e5dd1bbd771..2727c84e820 100644
--- a/release/scripts/startup/bl_ui/properties_data_lamp.py
+++ b/release/scripts/startup/bl_ui/properties_data_lamp.py
@@ -182,7 +182,6 @@ class DATA_PT_EEVEE_shadow(DataButtonsPanel, Panel):
col.prop(lamp, "shadow_buffer_bleed_bias", text="Bleed Bias")
-
class DATA_PT_EEVEE_shadow_cascaded_shadow_map(DataButtonsPanel, Panel):
bl_label = "Cascaded Shadow Map"
bl_parent_id = "DATA_PT_EEVEE_shadow"
diff --git a/release/scripts/startup/bl_ui/properties_freestyle.py b/release/scripts/startup/bl_ui/properties_freestyle.py
index a9c9d512335..12ecbeb3e6b 100644
--- a/release/scripts/startup/bl_ui/properties_freestyle.py
+++ b/release/scripts/startup/bl_ui/properties_freestyle.py
@@ -629,7 +629,7 @@ class VIEWLAYER_PT_freestyle_linestyle(ViewLayerFreestyleEditorButtonsPanel, Pan
row = layout.row(align=True)
row.prop(linestyle, "panel", expand=True)
if linestyle.panel == 'STROKES':
- ## Chaining
+ # Chaining
layout.prop(linestyle, "use_chaining", text="Chaining:")
split = layout.split(align=True)
split.active = linestyle.use_chaining
@@ -643,7 +643,7 @@ class VIEWLAYER_PT_freestyle_linestyle(ViewLayerFreestyleEditorButtonsPanel, Pan
col = split.column()
col.prop(linestyle, "use_same_object")
- ## Splitting
+ # Splitting
layout.label(text="Splitting:")
split = layout.split(align=True)
# First column
@@ -679,7 +679,7 @@ class VIEWLAYER_PT_freestyle_linestyle(ViewLayerFreestyleEditorButtonsPanel, Pan
sub.prop(linestyle, "split_dash3", text="D3")
sub.prop(linestyle, "split_gap3", text="G3")
- ## Sorting
+ # Sorting
layout.prop(linestyle, "use_sorting", text="Sorting:")
col = layout.column()
col.active = linestyle.use_sorting
@@ -693,7 +693,7 @@ class VIEWLAYER_PT_freestyle_linestyle(ViewLayerFreestyleEditorButtonsPanel, Pan
row = col.row(align=True)
row.prop(linestyle, "sort_order", expand=True)
- ## Selection
+ # Selection
layout.label(text="Selection:")
split = layout.split(align=True)
# First column
@@ -716,12 +716,12 @@ class VIEWLAYER_PT_freestyle_linestyle(ViewLayerFreestyleEditorButtonsPanel, Pan
sub.active = linestyle.use_chain_count
sub.prop(linestyle, "chain_count")
- ## Caps
+ # Caps
layout.label(text="Caps:")
row = layout.row(align=True)
row.prop(linestyle, "caps", expand=True)
- ## Dashed lines
+ # Dashed lines
layout.prop(linestyle, "use_dashed_line", text="Dashed Line:")
row = layout.row(align=True)
row.active = linestyle.use_dashed_line
@@ -786,9 +786,10 @@ class VIEWLAYER_PT_freestyle_linestyle(ViewLayerFreestyleEditorButtonsPanel, Pan
row = layout.row()
props = row.operator(
- "wm.properties_context_change",
- text="Go to Linestyle Textures Properties",
- icon='TEXTURE')
+ "wm.properties_context_change",
+ text="Go to Linestyle Textures Properties",
+ icon='TEXTURE',
+ )
props.context = 'TEXTURE'
elif linestyle.panel == 'MISC':
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 decbbff5d60..a2ccfb4f1b8 100644
--- a/release/scripts/startup/bl_ui/properties_grease_pencil_common.py
+++ b/release/scripts/startup/bl_ui/properties_grease_pencil_common.py
@@ -242,7 +242,6 @@ class GreasePencilStrokeEditPanel:
if is_3d_view:
layout.separator()
-
layout.separator()
col = layout.column(align=True)
col.operator("gpencil.stroke_subdivide", text="Subdivide")
@@ -1100,11 +1099,11 @@ class GreasePencilPaletteColorPanel:
row = layout.row()
sub = row.row(align=True)
- sub.label(text="Isolate:") # based on active color only
+ sub.label(text="Isolate:") # based on active color only
sub.operator("gpencil.palettecolor_isolate", icon='LOCKED', text="").affect_visibility = False
sub.operator("gpencil.palettecolor_isolate", icon='RESTRICT_VIEW_OFF', text="").affect_visibility = True
sub = row.row(align=True)
- sub.label(text="Lock:") # based on other stuff...
+ sub.label(text="Lock:") # based on other stuff...
sub.operator("gpencil.stroke_lock_color", icon='BORDER_RECT', text="")
sub.operator("gpencil.palette_lock_layer", icon='COLOR', text="")
diff --git a/release/scripts/startup/bl_ui/properties_mask_common.py b/release/scripts/startup/bl_ui/properties_mask_common.py
index a7a67130f2f..450ca80bbc2 100644
--- a/release/scripts/startup/bl_ui/properties_mask_common.py
+++ b/release/scripts/startup/bl_ui/properties_mask_common.py
@@ -43,8 +43,8 @@ class MASK_UL_layers(UIList):
class MASK_PT_mask:
# subclasses must define...
- #~ bl_space_type = 'CLIP_EDITOR'
- #~ bl_region_type = 'UI'
+ # ~ bl_space_type = 'CLIP_EDITOR'
+ # ~ bl_region_type = 'UI'
bl_label = "Mask Settings"
bl_options = {'DEFAULT_CLOSED'}
@@ -66,8 +66,8 @@ class MASK_PT_mask:
class MASK_PT_layers:
# subclasses must define...
- #~ bl_space_type = 'CLIP_EDITOR'
- #~ bl_region_type = 'UI'
+ # ~ bl_space_type = 'CLIP_EDITOR'
+ # ~ bl_region_type = 'UI'
bl_label = "Mask Layers"
@classmethod
@@ -114,8 +114,8 @@ class MASK_PT_layers:
class MASK_PT_spline:
# subclasses must define...
- #~ bl_space_type = 'CLIP_EDITOR'
- #~ bl_region_type = 'UI'
+ # ~ bl_space_type = 'CLIP_EDITOR'
+ # ~ bl_region_type = 'UI'
bl_label = "Active Spline"
@classmethod
@@ -148,8 +148,8 @@ class MASK_PT_spline:
class MASK_PT_point:
# subclasses must define...
- #~ bl_space_type = 'CLIP_EDITOR'
- #~ bl_region_type = 'UI'
+ # ~ bl_space_type = 'CLIP_EDITOR'
+ # ~ bl_region_type = 'UI'
bl_label = "Active Point"
@classmethod
@@ -203,8 +203,8 @@ class MASK_PT_point:
class MASK_PT_display:
# subclasses must define...
- #~ bl_space_type = 'CLIP_EDITOR'
- #~ bl_region_type = 'UI'
+ # ~ bl_space_type = 'CLIP_EDITOR'
+ # ~ bl_region_type = 'UI'
bl_label = "Mask Display"
bl_options = {'DEFAULT_CLOSED'}
@@ -229,8 +229,8 @@ class MASK_PT_display:
class MASK_PT_transforms:
# subclasses must define...
- #~ bl_space_type = 'CLIP_EDITOR'
- #~ bl_region_type = 'TOOLS'
+ # ~ bl_space_type = 'CLIP_EDITOR'
+ # ~ bl_region_type = 'TOOLS'
bl_label = "Transforms"
bl_category = "Mask"
bl_options = {'DEFAULT_CLOSED'}
@@ -253,8 +253,8 @@ class MASK_PT_transforms:
class MASK_PT_tools:
# subclasses must define...
- #~ bl_space_type = 'CLIP_EDITOR'
- #~ bl_region_type = 'TOOLS'
+ # ~ bl_space_type = 'CLIP_EDITOR'
+ # ~ bl_region_type = 'TOOLS'
bl_label = "Mask Tools"
bl_category = "Mask"
@@ -291,8 +291,8 @@ class MASK_PT_tools:
class MASK_PT_add:
# subclasses must define...
- #~ bl_space_type = 'CLIP_EDITOR'
- #~ bl_region_type = 'TOOLS'
+ # ~ bl_space_type = 'CLIP_EDITOR'
+ # ~ bl_region_type = 'TOOLS'
bl_label = "Add"
bl_category = "Mask"
diff --git a/release/scripts/startup/bl_ui/properties_paint_common.py b/release/scripts/startup/bl_ui/properties_paint_common.py
index bc8bc523e12..f1e5102f061 100644
--- a/release/scripts/startup/bl_ui/properties_paint_common.py
+++ b/release/scripts/startup/bl_ui/properties_paint_common.py
@@ -126,7 +126,7 @@ def brush_texpaint_common(panel, context, layout, brush, settings, projpaint=Fal
col.prop(brush, "gradient_stroke_mode", text="Mode")
if brush.gradient_stroke_mode in {'SPACING_REPEAT', 'SPACING_CLAMP'}:
col.prop(brush, "grad_spacing")
- else: # if brush.image_tool == 'FILL':
+ else: # if brush.image_tool == 'FILL':
col.prop(brush, "gradient_fill_mode")
else:
row = col.row(align=True)
diff --git a/release/scripts/startup/bl_ui/properties_particle.py b/release/scripts/startup/bl_ui/properties_particle.py
index 9ffc9e983bb..00eb13dd222 100644
--- a/release/scripts/startup/bl_ui/properties_particle.py
+++ b/release/scripts/startup/bl_ui/properties_particle.py
@@ -404,7 +404,7 @@ class PARTICLE_PT_hair_dynamics_structure(ParticleButtonsPanel, Panel):
@classmethod
def poll(cls, context):
- return context.particle_system.cloth != None
+ return context.particle_system.cloth is not None
def draw(self, context):
layout = self.layout
@@ -436,7 +436,7 @@ class PARTICLE_PT_hair_dynamics_volume(ParticleButtonsPanel, Panel):
@classmethod
def poll(cls, context):
- return context.particle_system.cloth != None
+ return context.particle_system.cloth is not None
def draw(self, context):
layout = self.layout
@@ -591,6 +591,7 @@ class PARTICLE_PT_rotation(ParticleButtonsPanel, Panel):
if part.type != 'HAIR':
col.prop(part, "use_dynamic_rotation")
+
class PARTICLE_PT_rotation_angular_velocity(ParticleButtonsPanel, Panel):
bl_label = "Angular Velocity"
bl_parent_id = "PARTICLE_PT_rotation"
@@ -812,6 +813,7 @@ class PARTICLE_PT_physics(ParticleButtonsPanel, Panel):
sub.prop(key, "object", text="")
sub.prop(key, "system", text="System")
+
class PARTICLE_PT_physics_deflection(ParticleButtonsPanel, Panel):
bl_label = "Deflection"
bl_parent_id = "PARTICLE_PT_physics"
@@ -820,8 +822,8 @@ class PARTICLE_PT_physics_deflection(ParticleButtonsPanel, Panel):
@classmethod
def poll(cls, context):
- part = particle_get_settings(context)
- return part.physics_type in {'NEWTON', 'FLUID'}
+ part = particle_get_settings(context)
+ return part.physics_type in {'NEWTON', 'FLUID'}
def draw(self, context):
layout = self.layout
@@ -846,8 +848,8 @@ class PARTICLE_PT_physics_forces(ParticleButtonsPanel, Panel):
@classmethod
def poll(cls, context):
- part = particle_get_settings(context)
- return part.physics_type == 'NEWTON'
+ part = particle_get_settings(context)
+ return part.physics_type == 'NEWTON'
def draw(self, context):
layout = self.layout
@@ -873,8 +875,8 @@ class PARTICLE_PT_physics_integration(ParticleButtonsPanel, Panel):
@classmethod
def poll(cls, context):
- part = particle_get_settings(context)
- return part.physics_type == 'NEWTON'
+ part = particle_get_settings(context)
+ return part.physics_type == 'NEWTON'
def draw(self, context):
layout = self.layout
@@ -924,7 +926,7 @@ class PARTICLE_PT_boidbrain(ParticleButtonsPanel, Panel):
# Currently boids can only use the first state so these are commented out for now.
#row = layout.row()
- #row.template_list("UI_UL_list", "particle_boids", boids, "states",
+ # row.template_list("UI_UL_list", "particle_boids", boids, "states",
# boids, "active_boid_state_index", compact="True")
#col = row.row()
#sub = col.row(align=True)
@@ -1039,6 +1041,7 @@ class PARTICLE_PT_render(ParticleButtonsPanel, Panel):
col.prop(part, "material_slot", text="Material")
col.prop(psys, "parent", text="Coordinate System")
+
class PARTICLE_PT_render_extra(ParticleButtonsPanel, Panel):
bl_label = "Extra"
bl_parent_id = "PARTICLE_PT_render"
@@ -1058,7 +1061,7 @@ class PARTICLE_PT_render_extra(ParticleButtonsPanel, Panel):
ob = context.object
part = particle_get_settings(context)
- col=layout.column()
+ col = layout.column()
col = layout.column()
col.prop(part, "use_parent_particles", text="Parent Particles")
@@ -1066,7 +1069,6 @@ class PARTICLE_PT_render_extra(ParticleButtonsPanel, Panel):
col.prop(part, "use_dead", text="Dead")
-
class PARTICLE_PT_render_line(ParticleButtonsPanel, Panel):
bl_label = "Line"
bl_parent_id = "PARTICLE_PT_render"
@@ -1086,7 +1088,7 @@ class PARTICLE_PT_render_line(ParticleButtonsPanel, Panel):
ob = context.object
part = particle_get_settings(context)
- col=layout.column()
+ col = layout.column()
col.separator()
sub = col.column(align=True)
@@ -1094,6 +1096,7 @@ class PARTICLE_PT_render_line(ParticleButtonsPanel, Panel):
sub.prop(part, "line_length_head", text="Head")
col.prop(part, "use_velocity_length", text="Velocity Length")
+
class PARTICLE_PT_render_path(ParticleButtonsPanel, Panel):
bl_label = "Path"
bl_parent_id = "PARTICLE_PT_render"
@@ -1113,7 +1116,7 @@ class PARTICLE_PT_render_path(ParticleButtonsPanel, Panel):
ob = context.object
part = particle_get_settings(context)
- col=layout.column()
+ col = layout.column()
col.prop(part, "use_strand_primitive")
sub = col.column()
@@ -1148,7 +1151,7 @@ class PARTICLE_PT_render_path_timing(ParticleButtonsPanel, Panel):
ob = context.object
part = particle_get_settings(context)
- col=layout.column()
+ col = layout.column()
col.prop(part, "use_absolute_path_time")
@@ -1160,6 +1163,7 @@ class PARTICLE_PT_render_path_timing(ParticleButtonsPanel, Panel):
col.prop(part, "path_end", text="End", slider=not part.use_absolute_path_time)
col.prop(part, "length_random", text="Random", slider=True)
+
class PARTICLE_PT_render_object(ParticleButtonsPanel, Panel):
bl_label = "Object"
bl_parent_id = "PARTICLE_PT_render"
@@ -1179,7 +1183,7 @@ class PARTICLE_PT_render_object(ParticleButtonsPanel, Panel):
ob = context.object
part = particle_get_settings(context)
- col=layout.column()
+ col = layout.column()
col.prop(part, "dupli_object", text="Instance Object")
sub = col.column()
@@ -1207,7 +1211,7 @@ class PARTICLE_PT_render_collection(ParticleButtonsPanel, Panel):
ob = context.object
part = particle_get_settings(context)
- col=layout.column()
+ col = layout.column()
col.prop(part, "dupli_group")
@@ -1219,6 +1223,7 @@ class PARTICLE_PT_render_collection(ParticleButtonsPanel, Panel):
sub.prop(part, "use_rotation_dupli", text="Object Rotation")
sub.prop(part, "use_scale_dupli", text="Object Scale")
+
class PARTICLE_PT_render_collection_use_count(ParticleButtonsPanel, Panel):
bl_label = "Use Count"
bl_parent_id = "PARTICLE_PT_render_collection"
@@ -1246,13 +1251,13 @@ class PARTICLE_PT_render_collection_use_count(ParticleButtonsPanel, Panel):
ob = context.object
part = particle_get_settings(context)
- col=layout.column()
+ col = layout.column()
layout.active = part.use_group_count and not part.use_whole_group
row = layout.row()
row.template_list("UI_UL_list", "particle_dupli_weights", part, "dupli_weights",
- part, "active_dupliweight_index")
+ part, "active_dupliweight_index")
col = row.column()
sub = col.row()
@@ -1267,6 +1272,7 @@ class PARTICLE_PT_render_collection_use_count(ParticleButtonsPanel, Panel):
row = layout.row()
row.prop(weight, "count")
+
class PARTICLE_PT_render_billboards_alignment(ParticleButtonsPanel, Panel):
bl_label = "Billboard Alignment"
bl_parent_id = "PARTICLE_PT_render"
@@ -1286,12 +1292,13 @@ class PARTICLE_PT_render_billboards_alignment(ParticleButtonsPanel, Panel):
ob = context.object
part = particle_get_settings(context)
- col=layout.column()
+ col = layout.column()
col.prop(part, "billboard_align", text="Align To")
col.prop(part, "lock_billboard", text="Lock Axis")
col.prop(part, "billboard_object")
+
class PARTICLE_PT_render_billboards_tilt(ParticleButtonsPanel, Panel):
bl_label = "Billboard Tilt"
bl_parent_id = "PARTICLE_PT_render"
@@ -1311,7 +1318,7 @@ class PARTICLE_PT_render_billboards_tilt(ParticleButtonsPanel, Panel):
ob = context.object
part = particle_get_settings(context)
- col=layout.column()
+ col = layout.column()
sub = col.column(align=True)
sub.prop(part, "billboard_tilt", text="Angle", slider=True)
@@ -1325,6 +1332,7 @@ class PARTICLE_PT_render_billboards_tilt(ParticleButtonsPanel, Panel):
col.prop(part, "billboard_velocity_head", text="Velocity ScaleHead")
col.prop(part, "billboard_velocity_tail", text="Tail")
+
class PARTICLE_PT_render_billboards_uv(ParticleButtonsPanel, Panel):
bl_label = "Billboard UVs"
bl_parent_id = "PARTICLE_PT_render"
@@ -1344,7 +1352,7 @@ class PARTICLE_PT_render_billboards_uv(ParticleButtonsPanel, Panel):
ob = context.object
part = particle_get_settings(context)
- col=layout.column()
+ col = layout.column()
if psys:
col.prop_search(psys, "billboard_normal_uv", ob.data, "uv_layers")
@@ -1361,7 +1369,6 @@ class PARTICLE_PT_render_billboards_uv(ParticleButtonsPanel, Panel):
sub.prop(part, "billboard_offset_split")
-
class PARTICLE_PT_render_trails(ParticleButtonsPanel, Panel):
bl_label = "Trails"
bl_parent_id = "PARTICLE_PT_render"
@@ -1380,7 +1387,7 @@ class PARTICLE_PT_render_trails(ParticleButtonsPanel, Panel):
psys = context.particle_system
part = particle_get_settings(context)
- col=layout.column()
+ col = layout.column()
col.prop(part, "trail_count")
@@ -1532,6 +1539,7 @@ class PARTICLE_PT_children_parting(ParticleButtonsPanel, Panel):
col.prop(part, "child_parting_min", text="Min")
col.prop(part, "child_parting_max", text="Max")
+
class PARTICLE_PT_children_clumping(ParticleButtonsPanel, Panel):
bl_label = "Clumping"
bl_parent_id = "PARTICLE_PT_children"
@@ -1573,6 +1581,7 @@ class PARTICLE_PT_children_clumping(ParticleButtonsPanel, Panel):
if part.use_twist_curve:
sub.template_curve_mapping(part, "twist_curve")
+
class PARTICLE_PT_children_roughness(ParticleButtonsPanel, Panel):
bl_label = "Roughness"
bl_parent_id = "PARTICLE_PT_children"
diff --git a/release/scripts/startup/bl_ui/properties_physics_cloth.py b/release/scripts/startup/bl_ui/properties_physics_cloth.py
index e0d0327324b..f450bc61635 100644
--- a/release/scripts/startup/bl_ui/properties_physics_cloth.py
+++ b/release/scripts/startup/bl_ui/properties_physics_cloth.py
@@ -257,6 +257,7 @@ class PHYSICS_PT_cloth_field_weights(PhysicButtonsPanel, Panel):
cloth = context.cloth.settings
effector_weights_ui(self, context, cloth.effector_weights, 'CLOTH')
+
classes = (
CLOTH_MT_presets,
PHYSICS_PT_cloth,
diff --git a/release/scripts/startup/bl_ui/properties_physics_common.py b/release/scripts/startup/bl_ui/properties_physics_common.py
index 3615f8be48c..05c72bf47ee 100644
--- a/release/scripts/startup/bl_ui/properties_physics_common.py
+++ b/release/scripts/startup/bl_ui/properties_physics_common.py
@@ -274,7 +274,7 @@ def basic_force_field_settings_ui(self, context, field):
elif field.type == 'HARMONIC':
col.prop(field, "use_multiple_springs")
if field.type == 'FORCE':
- col.prop(field, "use_gravity_falloff", text="Gravitation")
+ col.prop(field, "use_gravity_falloff", text="Gravitation")
split = layout.split()
diff --git a/release/scripts/startup/bl_ui/properties_physics_rigidbody.py b/release/scripts/startup/bl_ui/properties_physics_rigidbody.py
index 817b0ab76ed..3cb9026fd02 100644
--- a/release/scripts/startup/bl_ui/properties_physics_rigidbody.py
+++ b/release/scripts/startup/bl_ui/properties_physics_rigidbody.py
@@ -117,7 +117,7 @@ class PHYSICS_PT_rigid_body_dynamics(PHYSICS_PT_rigidbody_panel, Panel):
rbo = ob.rigid_body
#col = layout.column(align=1)
- #col.label(text="Activation:")
+ # col.label(text="Activation:")
# XXX: settings such as activate on collison/etc.
split = layout.split()
diff --git a/release/scripts/startup/bl_ui/properties_render.py b/release/scripts/startup/bl_ui/properties_render.py
index d75d3b61f1e..7cb0ce55be3 100644
--- a/release/scripts/startup/bl_ui/properties_render.py
+++ b/release/scripts/startup/bl_ui/properties_render.py
@@ -152,7 +152,7 @@ class RENDER_PT_dimensions(RenderButtonsPanel, Panel):
sub.prop(rd, "use_crop_to_border", text="Crop")
col = layout.column(align=True)
- col.prop(scene, "frame_start", text="Frame Range Start")
+ col.prop(scene, "frame_start", text="Frame Start")
col.prop(scene, "frame_end", text="End")
col.prop(scene, "frame_step", text="Step")
@@ -161,8 +161,21 @@ class RENDER_PT_dimensions(RenderButtonsPanel, Panel):
col.label(text="Frame Rate")
self.draw_framerate(col, rd)
+
+class RENDER_PT_frame_remapping(RenderButtonsPanel, Panel):
+ bl_label = "Time Remapping"
+ bl_parent_id = "RENDER_PT_dimensions"
+ bl_options = {'DEFAULT_CLOSED'}
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'}
+
+ def draw(self, context):
+ layout = self.layout
+ layout.use_property_split = True
+
+ rd = context.scene.render
+
col = layout.column(align=True)
- col.prop(rd, "frame_map_old", text="Time Remapping Old")
+ col.prop(rd, "frame_map_old", text="Old")
col.prop(rd, "frame_map_new", text="New")
@@ -222,6 +235,7 @@ class RENDER_PT_stamp(RenderButtonsPanel, Panel):
sub.active = rd.use_stamp_note
sub.prop(rd, "stamp_note_text", text="")
+
class RENDER_PT_stamp_burn(RenderButtonsPanel, Panel):
bl_label = "Burn Into Image"
bl_parent_id = "RENDER_PT_stamp"
@@ -773,6 +787,7 @@ classes = (
RENDER_MT_framerate_presets,
RENDER_PT_context,
RENDER_PT_dimensions,
+ RENDER_PT_frame_remapping,
RENDER_PT_post_processing,
RENDER_PT_output,
RENDER_PT_encoding,
diff --git a/release/scripts/startup/bl_ui/properties_scene.py b/release/scripts/startup/bl_ui/properties_scene.py
index 380ee57962c..4c5b1a86235 100644
--- a/release/scripts/startup/bl_ui/properties_scene.py
+++ b/release/scripts/startup/bl_ui/properties_scene.py
@@ -296,9 +296,7 @@ class SCENE_PT_color_management_curves(SceneButtonsPanel, Panel):
layout.use_property_split = False
layout.enabled = view.use_curve_mapping
- layout.template_curve_mapping(view, "curve_mapping", levels = True)
-
-
+ layout.template_curve_mapping(view, "curve_mapping", levels=True)
class SCENE_PT_audio(SceneButtonsPanel, Panel):
@@ -478,6 +476,24 @@ class SCENE_PT_viewport_display(SceneButtonsPanel, Panel):
col.prop(scene.display, "shadow_shift")
+class SCENE_PT_viewport_display_ssao(SceneButtonsPanel, Panel):
+ bl_label = "Screen Space Ambient Occlusion"
+ bl_parent_id = "SCENE_PT_viewport_display"
+
+ @classmethod
+ def poll(cls, context):
+ return True
+
+ def draw(self, context):
+ layout = self.layout
+ layout.use_property_split = True
+ scene = context.scene
+ col = layout.column()
+ col.prop(scene.display, "matcap_ssao_samples")
+ col.prop(scene.display, "matcap_ssao_distance")
+ col.prop(scene.display, "matcap_ssao_attenuation")
+
+
class SCENE_PT_custom_props(SceneButtonsPanel, PropertyPanel, Panel):
COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_CLAY', 'BLENDER_EEVEE'}
_context_path = "scene"
@@ -494,6 +510,7 @@ classes = (
SCENE_PT_color_management,
SCENE_PT_color_management_curves,
SCENE_PT_viewport_display,
+ SCENE_PT_viewport_display_ssao,
SCENE_PT_audio,
SCENE_PT_physics,
SCENE_PT_rigid_body_world,
diff --git a/release/scripts/startup/bl_ui/properties_texture.py b/release/scripts/startup/bl_ui/properties_texture.py
index aa3227e0b72..e5bf2c910a0 100644
--- a/release/scripts/startup/bl_ui/properties_texture.py
+++ b/release/scripts/startup/bl_ui/properties_texture.py
@@ -59,6 +59,7 @@ class TEXTURE_UL_texslots(UIList):
layout.alignment = 'CENTER'
layout.label(text="", icon_value=icon)
+
def context_tex_datablock(context):
idblock = context.brush
if idblock:
@@ -106,6 +107,7 @@ class TEXTURE_PT_preview(TextureButtonsPanel, Panel):
if isinstance(idblock, Brush):
layout.prop(tex, "use_preview_alpha")
+
class TEXTURE_PT_context(TextureButtonsPanel, Panel):
bl_label = ""
bl_context = "texture"
diff --git a/release/scripts/startup/bl_ui/properties_view_layer.py b/release/scripts/startup/bl_ui/properties_view_layer.py
index 3c8552c3407..013fac3c099 100644
--- a/release/scripts/startup/bl_ui/properties_view_layer.py
+++ b/release/scripts/startup/bl_ui/properties_view_layer.py
@@ -43,7 +43,7 @@ class VIEWLAYER_PT_layer(ViewLayerButtonsPanel, Panel):
rd = scene.render
layer = bpy.context.view_layer
- layout.prop(layer, "use", text="Use for Rendering");
+ layout.prop(layer, "use", text="Use for Rendering")
layout.prop(rd, "use_single_layer", text="Render Single Layer")
diff --git a/release/scripts/startup/bl_ui/space_clip.py b/release/scripts/startup/bl_ui/space_clip.py
index a3dc401b484..40009090231 100644
--- a/release/scripts/startup/bl_ui/space_clip.py
+++ b/release/scripts/startup/bl_ui/space_clip.py
@@ -1018,9 +1018,11 @@ 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 / Timecode" if clip.source == 'MOVIE'
- else "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()
@@ -1189,6 +1191,7 @@ class CLIP_PT_tools_grease_pencil_brush(GreasePencilBrushPanel, Panel):
class CLIP_PT_tools_grease_pencil_brushcurves(GreasePencilBrushCurvesPanel, Panel):
bl_space_type = 'CLIP_EDITOR'
+
class CLIP_MT_view(Menu):
bl_label = "View"
diff --git a/release/scripts/startup/bl_ui/space_dopesheet.py b/release/scripts/startup/bl_ui/space_dopesheet.py
index 3fedf8bc08c..0dbb3f53332 100644
--- a/release/scripts/startup/bl_ui/space_dopesheet.py
+++ b/release/scripts/startup/bl_ui/space_dopesheet.py
@@ -425,11 +425,11 @@ class DOPESHEET_MT_gpencil_channel(Menu):
layout.operator("anim.channels_editable_toggle")
# XXX: to be enabled when these are ready for use!
- #layout.separator()
- #layout.operator("anim.channels_expand")
- #layout.operator("anim.channels_collapse")
+ # layout.separator()
+ # layout.operator("anim.channels_expand")
+ # layout.operator("anim.channels_collapse")
- #layout.separator()
+ # layout.separator()
#layout.operator_menu_enum("anim.channels_move", "direction", text="Move...")
@@ -450,9 +450,9 @@ class DOPESHEET_MT_gpencil_frame(Menu):
layout.separator()
layout.operator("action.keyframe_type")
- #layout.separator()
- #layout.operator("action.copy")
- #layout.operator("action.paste")
+ # layout.separator()
+ # layout.operator("action.copy")
+ # layout.operator("action.paste")
class DOPESHEET_MT_delete(Menu):
@@ -469,6 +469,66 @@ class DOPESHEET_MT_delete(Menu):
layout.operator("action.clean", text="Clean Channels").channels = True
+class DOPESHEET_MT_specials(Menu):
+ bl_label = "Dope Sheet Context Menu"
+
+ def draw(self, context):
+ layout = self.layout
+
+ layout.operator("action.copy", text="Copy")
+ layout.operator("action.paste", text="Paste")
+ layout.operator("action.paste", text="Paste Flipped").flipped = True
+
+ layout.separator()
+
+ layout.operator_menu_enum("action.handle_type", "type", text="Handle Type")
+ layout.operator_menu_enum("action.interpolation_type", "type", text="Interpolation Mode")
+ layout.operator_menu_enum("action.easing_type", "type", text="Easing Type")
+
+ layout.separator()
+
+ layout.operator("action.keyframe_insert").type = 'SEL'
+ layout.operator("action.duplicate_move")
+ layout.operator("action.delete")
+
+ layout.separator()
+
+ layout.operator_menu_enum("action.mirror", "type", text="Mirror")
+ layout.operator_menu_enum("action.snap", "type", text="Snap")
+
+
+class DOPESHEET_MT_channel_specials(Menu):
+ bl_label = "Dope Sheet Channel Context Menu"
+
+ def draw(self, context):
+ layout = self.layout
+
+ layout.operator("anim.channels_setting_enable", text="Mute Channels").type = 'MUTE'
+ layout.operator("anim.channels_setting_disable", text="Unmute Channels").type = 'MUTE'
+ layout.separator()
+ layout.operator("anim.channels_setting_enable", text="Protect Channels").type = 'PROTECT'
+ layout.operator("anim.channels_setting_disable", text="Unprotect Channels").type = 'PROTECT'
+
+ layout.separator()
+ layout.operator("anim.channels_group")
+ layout.operator("anim.channels_ungroup")
+
+ layout.separator()
+ layout.operator("anim.channels_editable_toggle")
+ layout.operator_menu_enum("action.extrapolation_type", "type", text="Extrapolation Mode")
+
+ layout.separator()
+ layout.operator("anim.channels_expand")
+ layout.operator("anim.channels_collapse")
+
+ layout.separator()
+ layout.operator_menu_enum("anim.channels_move", "direction", text="Move...")
+
+ layout.separator()
+
+ layout.operator("anim.channels_delete")
+
+
classes = (
DOPESHEET_HT_header,
DOPESHEET_HT_editor_buttons,
@@ -482,6 +542,8 @@ classes = (
DOPESHEET_MT_gpencil_channel,
DOPESHEET_MT_gpencil_frame,
DOPESHEET_MT_delete,
+ DOPESHEET_MT_specials,
+ DOPESHEET_MT_channel_specials,
)
if __name__ == "__main__": # only for live edit.
diff --git a/release/scripts/startup/bl_ui/space_graph.py b/release/scripts/startup/bl_ui/space_graph.py
index 7e927bb6385..6e809c4e86a 100644
--- a/release/scripts/startup/bl_ui/space_graph.py
+++ b/release/scripts/startup/bl_ui/space_graph.py
@@ -299,6 +299,76 @@ class GRAPH_MT_delete(Menu):
layout.operator("graph.clean").channels = False
layout.operator("graph.clean", text="Clean Channels").channels = True
+
+class GRAPH_MT_specials(Menu):
+ bl_label = "F-Curve Context Menu"
+
+ def draw(self, context):
+ layout = self.layout
+
+ layout.operator("graph.copy", text="Copy")
+ layout.operator("graph.paste", text="Paste")
+ layout.operator("graph.paste", text="Paste Flipped").flipped = True
+
+ layout.separator()
+
+ layout.operator_menu_enum("graph.handle_type", "type", text="Handle Type")
+ layout.operator_menu_enum("graph.interpolation_type", "type", text="Interpolation Mode")
+ layout.operator_menu_enum("graph.easing_type", "type", text="Easing Type")
+
+ layout.separator()
+
+ layout.operator("graph.keyframe_insert").type = 'SEL'
+ layout.operator("graph.duplicate_move")
+ layout.operator("graph.delete")
+
+ layout.separator()
+
+ layout.operator_menu_enum("graph.mirror", "type", text="Mirror")
+ layout.operator_menu_enum("graph.snap", "type", text="Snap")
+
+
+class GRAPH_MT_channel_specials(Menu):
+ bl_label = "F-Curve Channel Context Menu"
+
+ def draw(self, context):
+ layout = self.layout
+ st = context.space_data
+
+ layout.separator()
+ layout.operator("anim.channels_setting_enable", text="Mute Channels").type = 'MUTE'
+ layout.operator("anim.channels_setting_disable", text="Unmute Channels").type = 'MUTE'
+ layout.separator()
+ layout.operator("anim.channels_setting_enable", text="Protect Channels").type = 'PROTECT'
+ layout.operator("anim.channels_setting_disable", text="Unprotect Channels").type = 'PROTECT'
+
+ layout.separator()
+ layout.operator("anim.channels_group")
+ layout.operator("anim.channels_ungroup")
+
+ layout.separator()
+ layout.operator("anim.channels_editable_toggle")
+ layout.operator_menu_enum("graph.extrapolation_type", "type", text="Extrapolation Mode")
+
+ layout.separator()
+ layout.operator("graph.hide", text="Hide Selected Curves").unselected = False
+ layout.operator("graph.hide", text="Hide Unselected Curves").unselected = True
+ layout.operator("graph.reveal")
+
+ layout.separator()
+ layout.operator("anim.channels_expand")
+ layout.operator("anim.channels_collapse")
+
+ layout.separator()
+ layout.operator_menu_enum("anim.channels_move", "direction", text="Move...")
+
+ layout.separator()
+
+ layout.operator("anim.channels_delete")
+ if st.mode == 'DRIVERS':
+ layout.operator("graph.driver_delete_invalid")
+
+
classes = (
GRAPH_HT_header,
GRAPH_MT_editor_menus,
@@ -309,6 +379,8 @@ classes = (
GRAPH_MT_key,
GRAPH_MT_key_transform,
GRAPH_MT_delete,
+ GRAPH_MT_specials,
+ GRAPH_MT_channel_specials,
)
if __name__ == "__main__": # only for live edit.
diff --git a/release/scripts/startup/bl_ui/space_image.py b/release/scripts/startup/bl_ui/space_image.py
index b1ff1618d09..4b533d2f045 100644
--- a/release/scripts/startup/bl_ui/space_image.py
+++ b/release/scripts/startup/bl_ui/space_image.py
@@ -422,6 +422,43 @@ class IMAGE_MT_uvs_select_mode(Menu):
props.data_path = "tool_settings.uv_select_mode"
+class IMAGE_MT_specials(Menu):
+ bl_label = "UV Context Menu"
+
+ def draw(self, context):
+ layout = self.layout
+
+ sima = context.space_data
+
+ # UV Edit Mode
+ if sima.show_uvedit:
+ layout.operator("uv.unwrap")
+ layout.operator("uv.follow_active_quads")
+
+ layout.separator()
+
+ layout.operator("uv.pin").clear = False
+ layout.operator("uv.pin", text="Unpin").clear = True
+
+ layout.separator()
+
+ layout.operator("uv.weld")
+ layout.operator("uv.stitch")
+
+ layout.separator()
+
+ layout.operator_enum("uv.align", "axis") # W, 2/3/4
+
+ layout.separator()
+
+ layout.operator("transform.mirror", text="Mirror X").constraint_axis[0] = True
+ layout.operator("transform.mirror", text="Mirror Y").constraint_axis[1] = True
+
+ layout.separator()
+
+ layout.menu("IMAGE_MT_uvs_snap")
+
+
class IMAGE_HT_header(Header):
bl_space_type = 'IMAGE_EDITOR'
@@ -584,6 +621,7 @@ class IMAGE_PT_tools_mask(MASK_PT_tools, Panel):
bl_region_type = 'TOOLS'
bl_category = 'Mask'
+
class IMAGE_PT_tools_mask_add(MASK_PT_add, Panel):
bl_space_type = 'IMAGE_EDITOR'
bl_region_type = 'TOOLS'
@@ -1127,8 +1165,6 @@ class IMAGE_PT_uv_sculpt(Panel, ImagePaintPanel):
col.prop(uvsculpt, "show_brush")
-
-
class IMAGE_PT_options_uvs(Panel, UVToolsPanel):
bl_label = "UV Options"
bl_category = "Options"
@@ -1308,6 +1344,7 @@ classes = (
IMAGE_MT_uvs_mirror,
IMAGE_MT_uvs_weldalign,
IMAGE_MT_uvs_select_mode,
+ IMAGE_MT_specials,
IMAGE_HT_header,
MASK_MT_editor_menus,
IMAGE_PT_mask,
diff --git a/release/scripts/startup/bl_ui/space_node.py b/release/scripts/startup/bl_ui/space_node.py
index 0963613af5c..bf3fa64a852 100644
--- a/release/scripts/startup/bl_ui/space_node.py
+++ b/release/scripts/startup/bl_ui/space_node.py
@@ -290,6 +290,41 @@ class NODE_MT_node_color_specials(Menu):
layout.operator("node.node_copy_color", icon='COPY_ID')
+class NODE_MT_specials(Menu):
+ bl_label = "Node Context Menu"
+
+ def draw(self, context):
+ layout = self.layout
+
+ layout.operator_context = 'INVOKE_DEFAULT'
+ layout.operator("node.duplicate_move")
+ layout.operator("node.delete")
+ layout.operator_context = 'EXEC_DEFAULT'
+
+ layout.operator("node.delete_reconnect")
+
+ layout.separator()
+
+ layout.operator("node.link_make").replace = False
+ layout.operator("node.link_make", text="Make and Replace Links").replace = True
+ layout.operator("node.links_detach")
+
+ layout.separator()
+
+ layout.operator("node.group_make", text="Group")
+ layout.operator("node.group_ungroup", text="Ungroup")
+ layout.operator("node.group_edit").exit = False
+
+ layout.separator()
+
+ layout.operator("node.hide_toggle")
+ layout.operator("node.mute_toggle")
+ layout.operator("node.preview_toggle")
+ layout.operator("node.hide_socket_toggle")
+ layout.operator("node.options_toggle")
+ layout.operator("node.collapse_hide_unused_toggle")
+
+
class NODE_PT_active_node_generic(Panel):
bl_space_type = 'NODE_EDITOR'
bl_region_type = 'UI'
@@ -507,11 +542,15 @@ class NODE_PT_tools_grease_pencil_sculpt(GreasePencilStrokeSculptPanel, Panel):
bl_region_type = 'TOOLS'
# Grease Pencil drawing brushes
+
+
class NODE_PT_tools_grease_pencil_brush(GreasePencilBrushPanel, Panel):
bl_space_type = 'NODE_EDITOR'
bl_region_type = 'TOOLS'
# Grease Pencil drawing curves
+
+
class NODE_PT_tools_grease_pencil_brushcurves(GreasePencilBrushCurvesPanel, Panel):
bl_space_type = 'NODE_EDITOR'
bl_region_type = 'TOOLS'
@@ -522,6 +561,7 @@ class NODE_PT_tools_grease_pencil_brushcurves(GreasePencilBrushCurvesPanel, Pane
def node_draw_tree_view(layout, context):
pass
+
classes = (
NODE_HT_header,
NODE_MT_editor_menus,
@@ -531,6 +571,7 @@ classes = (
NODE_MT_node,
NODE_MT_node_color_presets,
NODE_MT_node_color_specials,
+ NODE_MT_specials,
NODE_PT_active_node_generic,
NODE_PT_active_node_color,
NODE_PT_active_node_properties,
diff --git a/release/scripts/startup/bl_ui/space_outliner.py b/release/scripts/startup/bl_ui/space_outliner.py
index 8b8526cf9f2..12cff72b61a 100644
--- a/release/scripts/startup/bl_ui/space_outliner.py
+++ b/release/scripts/startup/bl_ui/space_outliner.py
@@ -179,7 +179,7 @@ class OUTLINER_MT_collection(Menu):
layout.operator("outliner.collection_instance", text="Instance to Scene")
if space.display_mode != 'VIEW_LAYER':
layout.operator("outliner.collection_link", text="Link to Scene")
- layout.operator("outliner.id_operation", text="Unlink").type='UNLINK'
+ layout.operator("outliner.id_operation", text="Unlink").type = 'UNLINK'
if space.display_mode == 'VIEW_LAYER':
layout.separator()
@@ -206,20 +206,20 @@ class OUTLINER_MT_object(Menu):
space = context.space_data
- layout.operator("outliner.object_operation", text="Delete").type='DELETE'
+ layout.operator("outliner.object_operation", text="Delete").type = 'DELETE'
if space.display_mode == 'VIEW_LAYER' and not space.use_filter_collection:
- layout.operator("outliner.object_operation", text="Delete Hierarchy").type='DELETE_HIERARCHY'
+ layout.operator("outliner.object_operation", text="Delete Hierarchy").type = 'DELETE_HIERARCHY'
layout.separator()
- layout.operator("outliner.object_operation", text="Select").type='SELECT'
- layout.operator("outliner.object_operation", text="Select Hierarchy").type='SELECT_HIERARCHY'
- layout.operator("outliner.object_operation", text="Deselect").type='DESELECT'
+ layout.operator("outliner.object_operation", text="Select").type = 'SELECT'
+ layout.operator("outliner.object_operation", text="Select Hierarchy").type = 'SELECT_HIERARCHY'
+ layout.operator("outliner.object_operation", text="Deselect").type = 'DESELECT'
layout.separator()
if not (space.display_mode == 'VIEW_LAYER' and not space.use_filter_collection):
- layout.operator("outliner.id_operation", text="Unlink").type='UNLINK'
+ layout.operator("outliner.id_operation", text="Unlink").type = 'UNLINK'
layout.separator()
layout.operator_menu_enum("outliner.id_operation", 'type', text="ID Data")
diff --git a/release/scripts/startup/bl_ui/space_properties.py b/release/scripts/startup/bl_ui/space_properties.py
index cd7137e0254..2d1725b2087 100644
--- a/release/scripts/startup/bl_ui/space_properties.py
+++ b/release/scripts/startup/bl_ui/space_properties.py
@@ -32,8 +32,7 @@ class PROPERTIES_HT_header(Header):
row = layout.row()
row.template_header()
- if view.mode == 'DATA_PROPERTIES':
- row.prop(view, "context", expand=True, icon_only=True)
+ row.prop(view, "context", expand=True, icon_only=True)
classes = (
diff --git a/release/scripts/startup/bl_ui/space_statusbar.py b/release/scripts/startup/bl_ui/space_statusbar.py
index 983b474d18b..3a6fc4925d8 100644
--- a/release/scripts/startup/bl_ui/space_statusbar.py
+++ b/release/scripts/startup/bl_ui/space_statusbar.py
@@ -73,7 +73,6 @@ class STATUSBAR_HT_header(Header):
return
-
classes = (
STATUSBAR_HT_header,
)
diff --git a/release/scripts/startup/bl_ui/space_time.py b/release/scripts/startup/bl_ui/space_time.py
index d5609e219e3..7c584b3177b 100644
--- a/release/scripts/startup/bl_ui/space_time.py
+++ b/release/scripts/startup/bl_ui/space_time.py
@@ -117,6 +117,7 @@ class TIME_MT_editor_menus(Menu):
panel_type="TIME_PT_keyframing_settings",
text="Keying")
+
class TIME_MT_marker(Menu):
bl_label = "Marker"
@@ -217,6 +218,7 @@ def marker_menu_generic(layout):
###################################
+
class TimelinePanelButtons:
bl_space_type = 'DOPESHEET_EDITOR'
bl_region_type = 'UI'
diff --git a/release/scripts/startup/bl_ui/space_toolsystem_common.py b/release/scripts/startup/bl_ui/space_toolsystem_common.py
index cb6d3851d02..2b9d4207272 100644
--- a/release/scripts/startup/bl_ui/space_toolsystem_common.py
+++ b/release/scripts/startup/bl_ui/space_toolsystem_common.py
@@ -339,9 +339,7 @@ class ToolSelectPanelHelper:
# - None: Signal to finish (complete any final operations, e.g. add padding).
@staticmethod
- def _layout_generator_single_column(layout):
- scale_y = 2.0
-
+ def _layout_generator_single_column(layout, scale_y):
col = layout.column(align=True)
col.scale_y = scale_y
is_sep = False
@@ -355,9 +353,8 @@ class ToolSelectPanelHelper:
is_sep = yield col
@staticmethod
- def _layout_generator_multi_columns(layout, column_count):
- scale_y = 2.0
- scale_x = 2.2
+ def _layout_generator_multi_columns(layout, column_count, scale_y):
+ scale_x = scale_y * 1.1
column_last = column_count - 1
col = layout.column(align=True)
@@ -394,7 +391,7 @@ class ToolSelectPanelHelper:
column_index += 1
@staticmethod
- def _layout_generator_detect_from_region(layout, region):
+ def _layout_generator_detect_from_region(layout, region, scale_y):
"""
Choose an appropriate layout for the toolbar.
"""
@@ -421,15 +418,14 @@ class ToolSelectPanelHelper:
column_count = 1
if column_count == 1:
- ui_gen = ToolSelectPanelHelper._layout_generator_single_column(layout)
+ ui_gen = ToolSelectPanelHelper._layout_generator_single_column(layout, scale_y=scale_y)
else:
- ui_gen = ToolSelectPanelHelper._layout_generator_multi_columns(layout, column_count=column_count)
+ ui_gen = ToolSelectPanelHelper._layout_generator_multi_columns(layout, column_count=column_count, scale_y=scale_y)
return ui_gen, show_text
-
@classmethod
- def draw_cls(cls, layout, context, detect_layout=True):
+ def draw_cls(cls, layout, context, detect_layout=True, scale_y=2.0):
# Use a classmethod so it can be called outside of a panel context.
# XXX, this UI isn't very nice.
@@ -445,9 +441,9 @@ class ToolSelectPanelHelper:
)
if detect_layout:
- ui_gen, show_text = cls._layout_generator_detect_from_region(layout, context.region)
+ ui_gen, show_text = cls._layout_generator_detect_from_region(layout, context.region, scale_y)
else:
- ui_gen = ToolSelectPanelHelper._layout_generator_single_column(layout)
+ ui_gen = ToolSelectPanelHelper._layout_generator_single_column(layout, scale_y)
show_text = True
# Start iteration
@@ -676,6 +672,7 @@ def keymap_from_context(context, space_type):
wm.keyconfigs.update()
return keymap
+
classes = (
WM_MT_toolsystem_submenu,
)
diff --git a/release/scripts/startup/bl_ui/space_toolsystem_toolbar.py b/release/scripts/startup/bl_ui/space_toolsystem_toolbar.py
index 42fac9e03a4..da86c1c03bc 100644
--- a/release/scripts/startup/bl_ui/space_toolsystem_toolbar.py
+++ b/release/scripts/startup/bl_ui/space_toolsystem_toolbar.py
@@ -91,7 +91,7 @@ class _defs_view3d_generic:
("transform.translate",
dict(release_confirm=True, cursor_transform=True),
dict(type='EVT_TWEAK_A', value='ANY'),
- ),
+ ),
),
)
@@ -292,7 +292,6 @@ class _defs_edit_armature:
class _defs_edit_mesh:
-
@ToolDef.from_fn
def cube_add():
return dict(
diff --git a/release/scripts/startup/bl_ui/space_topbar.py b/release/scripts/startup/bl_ui/space_topbar.py
index 7beb97f31b6..c231d05ecdb 100644
--- a/release/scripts/startup/bl_ui/space_topbar.py
+++ b/release/scripts/startup/bl_ui/space_topbar.py
@@ -141,7 +141,7 @@ class TOPBAR_HT_lower_bar(Header):
elif mode == 'POSE':
pass
elif mode == 'PARTICLE':
- pass
+ layout.popover_group(space_type='PROPERTIES', region_type='WINDOW', context=".paint_common", category="")
def draw_right(self, context):
layout = self.layout
diff --git a/release/scripts/startup/bl_ui/space_userpref.py b/release/scripts/startup/bl_ui/space_userpref.py
index 1e090884fd1..a480fa433e1 100644
--- a/release/scripts/startup/bl_ui/space_userpref.py
+++ b/release/scripts/startup/bl_ui/space_userpref.py
@@ -22,6 +22,7 @@ from bpy.types import (
Header,
Menu,
Panel,
+ Operator,
)
from bpy.app.translations import pgettext_iface as iface_
from bpy.app.translations import contexts as i18n_contexts
@@ -71,6 +72,10 @@ class USERPREF_HT_header(Header):
layout.operator("wm.addon_install", icon='FILESEL')
layout.operator("wm.addon_refresh", icon='FILE_REFRESH')
layout.menu("USERPREF_MT_addons_online_resources")
+ elif userpref.active_section == 'LIGHTS':
+ layout.operator('wm.studiolight_install', text="Install MatCap").orientation='MATCAP'
+ layout.operator('wm.studiolight_install', text="Install World HDRI").orientation='WORLD'
+ layout.operator('wm.studiolight_install', text="Install Camera HDRI").orientation='CAMERA'
elif userpref.active_section == 'THEMES':
layout.operator("ui.reset_default_theme")
layout.operator("wm.theme_install")
@@ -141,7 +146,6 @@ class USERPREF_MT_app_templates(Menu):
layout.operator_context = 'INVOKE_DEFAULT'
props = layout.operator("wm.app_template_install")
-
def draw(self, context):
self.draw_ex(context, use_splash=False, use_default=True, use_install=True)
@@ -282,14 +286,14 @@ class USERPREF_PT_interface(Panel):
row.separator()
col = row.column()
- #Toolbox doesn't exist yet
- #col.label(text="Toolbox:")
+ # Toolbox doesn't exist yet
+ # col.label(text="Toolbox:")
#col.prop(view, "show_column_layout")
#col.label(text="Open Toolbox Delay:")
#col.prop(view, "open_left_mouse_delay", text="Hold LMB")
#col.prop(view, "open_right_mouse_delay", text="Hold RMB")
col.prop(view, "show_manipulator")
- ## Currently not working
+ # Currently not working
# col.prop(view, "show_manipulator_shaded")
sub = col.column()
sub.active = view.show_manipulator
@@ -328,7 +332,6 @@ class USERPREF_PT_interface(Panel):
col.prop(view, "show_view3d_cursor")
-
class USERPREF_PT_edit(Panel):
bl_space_type = 'USER_PREFERENCES'
bl_label = "Edit"
@@ -412,7 +415,7 @@ class USERPREF_PT_edit(Panel):
sub = col.column()
- #~ sub.active = edit.use_keyframe_insert_auto # incorrect, time-line can enable
+ # ~ sub.active = edit.use_keyframe_insert_auto # incorrect, time-line can enable
sub.prop(edit, "use_keyframe_insert_available", text="Only Insert Available")
col.separator()
@@ -1217,7 +1220,7 @@ class USERPREF_PT_input(Panel):
#sub.prop(inputs, "use_mouse_mmb_paste")
- #col.separator()
+ # col.separator()
sub = col.column()
sub.prop(inputs, "invert_zoom_wheel", text="Invert Wheel Zoom Direction")
@@ -1332,7 +1335,7 @@ class USERPREF_PT_addons(Panel):
'OFFICIAL': 'FILE_BLEND',
'COMMUNITY': 'POSE_DATA',
'TESTING': 'MOD_EXPLODE',
- }
+ }
@classmethod
def poll(cls, context):
@@ -1410,7 +1413,6 @@ class USERPREF_PT_addons(Panel):
sub_col.label(" " + addon_file)
sub_col.label(" " + addon_path)
-
if addon_utils.error_encoding:
self.draw_error(
col,
@@ -1435,11 +1437,11 @@ class USERPREF_PT_addons(Panel):
# check if addon should be visible with current filters
if ((filter == "All") or
- (filter == info["category"]) or
- (filter == "Enabled" and is_enabled) or
- (filter == "Disabled" and not is_enabled) or
- (filter == "User" and (mod.__file__.startswith((scripts_addons_folder, userpref_addons_folder))))
- ):
+ (filter == info["category"]) or
+ (filter == "Enabled" and is_enabled) or
+ (filter == "Disabled" and not is_enabled) or
+ (filter == "User" and (mod.__file__.startswith((scripts_addons_folder, userpref_addons_folder))))
+ ):
if search and search not in info["name"].lower():
if info["author"]:
if search not in info["author"].lower():
@@ -1573,6 +1575,60 @@ class USERPREF_PT_addons(Panel):
row.label(text=module_name, translate=False)
+class StudioLightPanelMixin():
+ bl_space_type = 'USER_PREFERENCES'
+ bl_region_type = 'WINDOW'
+
+ @classmethod
+ def poll(cls, context):
+ userpref = context.user_preferences
+ return (userpref.active_section == 'LIGHTS')
+
+ def _get_lights(self, userpref):
+ return [light for light in userpref.studio_lights if light.is_user_defined and light.orientation == self.sl_orientation]
+
+ def draw_header(self, context):
+ layout = self.layout
+ row = layout.row()
+ userpref = context.user_preferences
+ lights = self._get_lights(userpref)
+ row.label("({})".format(len(lights)))
+
+ def draw(self, context):
+ layout = self.layout
+ userpref = context.user_preferences
+ lights = self._get_lights(userpref)
+ if lights:
+ flow = layout.column_flow(4)
+ for studio_light in lights:
+ self.draw_studio_light(flow, studio_light)
+ else:
+ layout.label("No custom {} configured".format(self.bl_label))
+
+ def draw_studio_light(self, layout, studio_light):
+ box = layout.box()
+ row = box.row()
+
+ row.template_icon_view(studio_light, "icon_id")
+ op = row.operator('wm.studiolight_uninstall', text="", icon='ZOOMOUT')
+ op.index = studio_light.index
+
+
+class USERPREF_PT_studiolight_matcaps(Panel, StudioLightPanelMixin):
+ bl_label = "MatCaps"
+ sl_orientation = 'MATCAP'
+
+
+class USERPREF_PT_studiolight_world(Panel, StudioLightPanelMixin):
+ bl_label = "World HDRI"
+ sl_orientation = 'WORLD'
+
+
+class USERPREF_PT_studiolight_camera(Panel, StudioLightPanelMixin):
+ bl_label = "Camera HDRI"
+ sl_orientation = 'CAMERA'
+
+
classes = (
USERPREF_HT_header,
USERPREF_PT_tabs,
@@ -1593,6 +1649,9 @@ classes = (
USERPREF_PT_input,
USERPREF_MT_addons_online_resources,
USERPREF_PT_addons,
+ USERPREF_PT_studiolight_matcaps,
+ USERPREF_PT_studiolight_world,
+ USERPREF_PT_studiolight_camera,
)
if __name__ == "__main__": # only for live edit.
diff --git a/release/scripts/startup/bl_ui/space_view3d.py b/release/scripts/startup/bl_ui/space_view3d.py
index 4f3396c9ed8..3a8fb3ce2f0 100644
--- a/release/scripts/startup/bl_ui/space_view3d.py
+++ b/release/scripts/startup/bl_ui/space_view3d.py
@@ -1483,7 +1483,7 @@ class VIEW3D_MT_object_clear(Menu):
class VIEW3D_MT_object_specials(Menu):
- bl_label = "Context Menu"
+ bl_label = "Object Context Menu"
@classmethod
def poll(cls, context):
@@ -2113,7 +2113,7 @@ class VIEW3D_MT_particle(Menu):
class VIEW3D_MT_particle_specials(Menu):
- bl_label = "Context Menu"
+ bl_label = "Particle Context Menu"
def draw(self, context):
layout = self.layout
@@ -2363,7 +2363,7 @@ class VIEW3D_MT_pose_apply(Menu):
class VIEW3D_MT_pose_specials(Menu):
- bl_label = "Context Menu"
+ bl_label = "Pose Context Menu"
def draw(self, context):
layout = self.layout
@@ -2496,7 +2496,7 @@ class VIEW3D_MT_edit_mesh(Menu):
class VIEW3D_MT_edit_mesh_specials(Menu):
- bl_label = "Context Menu"
+ bl_label = "Mesh Context Menu"
def draw(self, context):
layout = self.layout
@@ -3030,7 +3030,7 @@ class VIEW3D_MT_edit_curve_clean(Menu):
class VIEW3D_MT_edit_curve_specials(Menu):
- bl_label = "Context Menu"
+ bl_label = "Curve Context Menu"
def draw(self, context):
layout = self.layout
@@ -3244,7 +3244,7 @@ class VIEW3D_MT_edit_armature(Menu):
class VIEW3D_MT_armature_specials(Menu):
- bl_label = "Context Menu"
+ bl_label = "Armature Context Menu"
def draw(self, context):
layout = self.layout
@@ -3394,6 +3394,28 @@ class VIEW3D_MT_edit_gpencil_interpolate(Menu):
layout.operator("gpencil.interpolate_sequence", text="Sequence")
+class VIEW3D_PIE_object_mode(Menu):
+ bl_label = "Mode"
+
+ def draw(self, context):
+ layout = self.layout
+
+ pie = layout.menu_pie()
+ pie.operator_enum("OBJECT_OT_mode_set", "mode")
+
+
+class VIEW3D_PIE_view(Menu):
+ bl_label = "View"
+ bl_idname = "VIEW3D_PIE_view"
+
+ def draw(self, context):
+ layout = self.layout
+
+ pie = layout.menu_pie()
+ pie.operator_enum("VIEW3D_OT_viewnumpad", "type")
+ pie.operator("view3d.view_selected", text="View Selected", icon='ZOOM_SELECTED')
+
+
# ********** Panel **********
@@ -3476,31 +3498,6 @@ class VIEW3D_PT_view3d_cursor(Panel):
layout.column().prop(view, "cursor_location", text="Location")
-class VIEW3D_PT_view3d_name(Panel):
- bl_space_type = 'VIEW_3D'
- bl_region_type = 'UI'
- bl_label = "Item"
-
- @classmethod
- def poll(cls, context):
- return (context.space_data and context.active_object)
-
- def draw(self, context):
- layout = self.layout
-
- ob = context.active_object
- row = layout.row()
- row.label(text="", icon='OBJECT_DATA')
- row.prop(ob, "name", text="")
-
- if ob.type == 'ARMATURE' and ob.mode in {'EDIT', 'POSE'}:
- bone = context.active_bone
- if bone:
- row = layout.row()
- row.label(text="", icon='BONE_DATA')
- row.prop(bone, "name", text="")
-
-
class VIEW3D_PT_shading(Panel):
bl_space_type = 'VIEW_3D'
bl_region_type = 'HEADER'
@@ -3517,48 +3514,72 @@ class VIEW3D_PT_shading(Panel):
shading = view.shading
col = layout.column()
-
- if shading.type == 'SOLID':
- col.row().prop(shading, "color_type", expand=True)
-
- if shading.color_type == 'SINGLE':
- col.row().prop(shading, "single_color", text="")
-
+ col.row().label("Lighting")
if shading.type in ('SOLID', 'TEXTURED'):
col.row().prop(shading, "light", expand=True)
if shading.light == 'STUDIO':
- col.row().template_icon_view(shading, "studio_light")
+ row = col.row()
+ row.template_icon_view(shading, "studio_light")
+ row.operator('wm.studiolight_userpref_show', emboss=False, text="", icon='ZOOMIN')
if shading.studio_light_orientation == 'WORLD':
col.row().prop(shading, "studiolight_rot_z")
- row = col.row()
- row.prop(shading, "show_specular_highlight")
+ elif shading.light == 'MATCAP':
+ row = col.row()
+ row.template_icon_view(shading, "matcap")
+ sub = row.column()
+ sub.operator('VIEW3D_OT_toggle_matcap_flip', emboss=False, text="", icon='ARROW_LEFTRIGHT')
+ sub.operator('wm.studiolight_userpref_show', emboss=False, text="", icon='ZOOMIN')
+ if shading.type == 'SOLID':
col.separator()
+ col.row().label("Color")
+ col.row().prop(shading, "color_type", expand=True)
- row = col.row()
- row.prop(shading, "show_xray")
- sub = row.row()
- sub.active = shading.show_xray
- sub.prop(shading, "xray_alpha", text="")
-
- row = col.row()
- row.active = not shading.show_xray
- row.prop(shading, "show_shadows")
- sub = row.row()
- sub.active = shading.show_shadows and not shading.show_xray
- sub.prop(shading, "shadow_intensity", text="")
+ if shading.color_type == 'SINGLE':
+ col.row().prop(shading, "single_color", text="")
- row = col.row()
- row.prop(shading, "show_object_outline")
- sub = row.row()
- sub.active = shading.show_object_outline
- sub.prop(shading, "object_outline_color", text="")
+ if shading.type in ('SOLID', 'TEXTURED'):
+ col.separator()
- col.prop(view, "show_world")
+ if not shading.light == 'MATCAP':
+ row = col.row()
+ row.prop(shading, "show_specular_highlight")
+
+ if shading.type in ('SOLID', 'TEXTURED'):
+ row = col.split(0.4)
+ row.prop(shading, "show_xray")
+ sub = row.row()
+ sub.active = shading.show_xray
+ sub.prop(shading, "xray_alpha", text="")
+
+ row = col.split(0.4)
+ row.active = not shading.show_xray
+ row.prop(shading, "show_shadows")
+ sub = row.row()
+ sub.active = shading.show_shadows and not shading.show_xray
+ sub.prop(shading, "shadow_intensity", text="")
+
+ row = col.split(0.4)
+ row.active = not shading.show_xray
+ row.prop(shading, "show_cavity")
+ sub = row.column(align=True)
+ sub.active = not shading.show_xray and shading.show_cavity
+ sub.prop(shading, "cavity_ridge_factor")
+ sub.prop(shading, "cavity_valley_factor")
+
+ row = col.split(0.4)
+ row.prop(shading, "show_object_outline")
+ sub = row.row()
+ sub.active = shading.show_object_outline
+ sub.prop(shading, "object_outline_color", text="")
+
+ col.prop(view, "show_world")
elif shading.type in ('MATERIAL'):
- col.row().template_icon_view(shading, "studio_light")
+ row = col.row()
+ row.template_icon_view(shading, "studio_light")
+ op = row.operator('wm.studiolight_userpref_show', emboss=False, text="", icon='ZOOMIN')
if shading.studio_light_orientation == 'WORLD':
col.row().prop(shading, "studiolight_rot_z")
col.row().prop(shading, "studiolight_background")
@@ -3580,7 +3601,6 @@ class VIEW3D_PT_overlay(Panel):
view = context.space_data
shading = view.shading
overlay = view.overlay
- scene = context.scene
toolsettings = context.tool_settings
display_all = overlay.show_overlays
@@ -3596,7 +3616,13 @@ class VIEW3D_PT_overlay(Panel):
col.prop(overlay, "show_relationship_lines")
col.prop(overlay, "show_motion_paths")
col.prop(overlay, "show_face_orientation")
- col.prop(overlay, "show_wireframes")
+
+ row = col.row()
+ row.prop(overlay, "show_wireframes")
+ sub = row.row()
+ sub.active = overlay.show_wireframes
+ sub.prop(overlay, "wireframe_threshold", text="")
+
col.prop(overlay, "show_backface_culling")
if shading.type == "MATERIAL":
@@ -3616,12 +3642,27 @@ class VIEW3D_PT_overlay(Panel):
sub.active = bool(overlay.show_floor or view.region_quadviews or not view.region_3d.is_perspective)
subsub = sub.column(align=True)
subsub.active = overlay.show_floor
- sub.prop(overlay, "grid_scale", text="Scale")
- sub.prop(overlay, "grid_subdivisions", text="Subdivisions")
+ subsub.prop(overlay, "grid_scale", text="Scale")
+ subsub.prop(overlay, "grid_subdivisions", text="Subdivisions")
+
+ col.prop(view, "show_reconstruction", text="Motion Tracking")
+ sub = col.column(align=True)
+
+ sub.active = view.show_reconstruction
+ sub.prop(view, "show_camera_path", text="Camera Path")
+ sub.prop(view, "show_bundle_names", text="3D Marker Names")
+ sub.label(text="Track Type and Size:")
+ row = sub.row(align=True)
+ row.prop(view, "tracks_draw_type", text="")
+ row.prop(view, "tracks_draw_size", text="")
+ col.separator()
if context.mode == 'EDIT_MESH':
+ data = context.active_object.data
+ statvis = context.tool_settings.statvis
+ with_freestyle = bpy.app.build_options.freestyle
col.separator()
- col.label(text="Edit Mode:")
+ col.label(text="Edit Mesh:")
col.prop(overlay, "show_occlude_wire")
@@ -3640,6 +3681,72 @@ class VIEW3D_PT_overlay(Panel):
sub.active = overlay.show_vertex_normals or overlay.show_face_normals or overlay.show_split_normals
sub.prop(overlay, "normals_length", text="Size")
+ split = col.split()
+
+ sub = split.column()
+ sub.prop(data, "show_faces", text="Faces")
+ sub.prop(data, "show_edges", text="Edges")
+ sub.prop(data, "show_edge_crease", text="Creases")
+
+ if with_freestyle:
+ sub.prop(data, "show_edge_seams", text="Seams")
+
+ sub = split.column()
+ if not with_freestyle:
+ sub.prop(data, "show_edge_seams", text="Seams")
+ sub.prop(data, "show_edge_sharp", text="Sharp", text_ctxt=i18n_contexts.plural)
+ col.prop(data, "show_edge_bevel_weight", text="Bevel")
+ if with_freestyle:
+ sub.prop(data, "show_freestyle_edge_marks", text="Edge Marks")
+ sub.prop(data, "show_freestyle_face_marks", text="Face Marks")
+
+ col.separator()
+ split = col.split()
+ sub = split.column()
+ sub.label(text="Edge Info:")
+ sub.prop(data, "show_extra_edge_length", text="Length")
+ sub.prop(data, "show_extra_edge_angle", text="Angle")
+ sub = split.column()
+ sub.label(text="Face Info:")
+ sub.prop(data, "show_extra_face_area", text="Area")
+ sub.prop(data, "show_extra_face_angle", text="Angle")
+ if bpy.app.debug:
+ sub.prop(data, "show_extra_indices", text="Indices")
+
+ col.prop(data, "show_statvis", text="Mesh Analysis")
+ sub = col.column()
+ sub.active = data.show_statvis
+ sub.prop(statvis, "type")
+ statvis_type = statvis.type
+ if statvis_type == 'OVERHANG':
+ row = sub.row(align=True)
+ row.prop(statvis, "overhang_min", text="")
+ row.prop(statvis, "overhang_max", text="")
+ layout.row().prop(statvis, "overhang_axis", expand=True)
+ elif statvis_type == 'THICKNESS':
+ row = sub.row(align=True)
+ row.prop(statvis, "thickness_min", text="")
+ row.prop(statvis, "thickness_max", text="")
+ layout.prop(statvis, "thickness_samples")
+ elif statvis_type == 'INTERSECT':
+ pass
+ elif statvis_type == 'DISTORT':
+ row = sub.row(align=True)
+ row.prop(statvis, "distort_min", text="")
+ row.prop(statvis, "distort_max", text="")
+ elif statvis_type == 'SHARP':
+ row = sub.row(align=True)
+ row.prop(statvis, "sharp_min", text="")
+ row.prop(statvis, "sharp_max", text="")
+
+ elif context.mode == 'EDIT_CURVE':
+ data = context.active_object.data
+ col.separator()
+ col.label(text="Edit Curve:")
+ row = col.row()
+ row.prop(data, "show_handles", text="Handles")
+ row.prop(data, "show_normal_face", text="Normals")
+
elif context.mode == 'POSE':
col.separator()
col.label(text="Pose Mode:")
@@ -3647,7 +3754,11 @@ class VIEW3D_PT_overlay(Panel):
col = layout.column()
col.active = display_all
col.prop(overlay, "show_transparent_bones")
- col.prop(overlay, "show_bone_selection")
+ row = col.split(0.65)
+ row.prop(overlay, "show_bone_selection")
+ sub = row.column()
+ sub.active = display_all and overlay.show_bone_selection
+ sub.prop(overlay, "bone_selection_alpha", text="")
elif context.mode == 'EDIT_ARMATURE':
col.separator()
@@ -3734,157 +3845,6 @@ class VIEW3D_PT_view3d_stereo(Panel):
split.prop(view, "stereo_3d_volume_alpha", text="Alpha")
-class VIEW3D_PT_view3d_motion_tracking(Panel):
- bl_space_type = 'VIEW_3D'
- bl_region_type = 'UI'
- bl_label = "Motion Tracking"
- bl_options = {'DEFAULT_CLOSED'}
-
- @classmethod
- def poll(cls, context):
- view = context.space_data
- return (view)
-
- def draw_header(self, context):
- view = context.space_data
-
- self.layout.prop(view, "show_reconstruction", text="")
-
- def draw(self, context):
- layout = self.layout
-
- view = context.space_data
-
- col = layout.column()
- col.active = view.show_reconstruction
- col.prop(view, "show_camera_path", text="Camera Path")
- col.prop(view, "show_bundle_names", text="3D Marker Names")
- col.label(text="Track Type and Size:")
- row = col.row(align=True)
- row.prop(view, "tracks_draw_type", text="")
- row.prop(view, "tracks_draw_size", text="")
-
-
-class VIEW3D_PT_view3d_meshdisplay(Panel):
- bl_space_type = 'VIEW_3D'
- bl_region_type = 'UI'
- bl_label = "Mesh Display"
-
- @classmethod
- def poll(cls, context):
- # The active object check is needed because of local-mode
- return (context.active_object and (context.mode == 'EDIT_MESH'))
-
- def draw(self, context):
- layout = self.layout
- with_freestyle = bpy.app.build_options.freestyle
-
- mesh = context.active_object.data
- scene = context.scene
-
- split = layout.split()
-
- col = split.column()
- col.label(text="Overlays:")
- col.prop(mesh, "show_faces", text="Faces")
- col.prop(mesh, "show_edges", text="Edges")
- col.prop(mesh, "show_edge_crease", text="Creases")
- if with_freestyle:
- col.prop(mesh, "show_edge_seams", text="Seams")
-
- col = split.column()
- col.label()
- if not with_freestyle:
- col.prop(mesh, "show_edge_seams", text="Seams")
- col.prop(mesh, "show_edge_sharp", text="Sharp", text_ctxt=i18n_contexts.plural)
- col.prop(mesh, "show_edge_bevel_weight", text="Bevel")
- if with_freestyle:
- col.prop(mesh, "show_freestyle_edge_marks", text="Edge Marks")
- col.prop(mesh, "show_freestyle_face_marks", text="Face Marks")
-
- col = layout.column()
-
- col.separator()
- split = layout.split()
- col = split.column()
- col.label(text="Edge Info:")
- col.prop(mesh, "show_extra_edge_length", text="Length")
- col.prop(mesh, "show_extra_edge_angle", text="Angle")
- col = split.column()
- col.label(text="Face Info:")
- col.prop(mesh, "show_extra_face_area", text="Area")
- col.prop(mesh, "show_extra_face_angle", text="Angle")
- if bpy.app.debug:
- layout.prop(mesh, "show_extra_indices", text="Indices")
-
-
-class VIEW3D_PT_view3d_meshstatvis(Panel):
- bl_space_type = 'VIEW_3D'
- bl_region_type = 'UI'
- bl_label = "Mesh Analysis"
-
- @classmethod
- def poll(cls, context):
- # The active object check is needed because of local-mode
- return (context.active_object and (context.mode == 'EDIT_MESH'))
-
- def draw_header(self, context):
- mesh = context.active_object.data
-
- self.layout.prop(mesh, "show_statvis", text="")
-
- def draw(self, context):
- layout = self.layout
-
- mesh = context.active_object.data
- statvis = context.tool_settings.statvis
- layout.active = mesh.show_statvis
-
- layout.prop(statvis, "type")
- statvis_type = statvis.type
- if statvis_type == 'OVERHANG':
- row = layout.row(align=True)
- row.prop(statvis, "overhang_min", text="")
- row.prop(statvis, "overhang_max", text="")
- layout.row().prop(statvis, "overhang_axis", expand=True)
- elif statvis_type == 'THICKNESS':
- row = layout.row(align=True)
- row.prop(statvis, "thickness_min", text="")
- row.prop(statvis, "thickness_max", text="")
- layout.prop(statvis, "thickness_samples")
- elif statvis_type == 'INTERSECT':
- pass
- elif statvis_type == 'DISTORT':
- row = layout.row(align=True)
- row.prop(statvis, "distort_min", text="")
- row.prop(statvis, "distort_max", text="")
- elif statvis_type == 'SHARP':
- row = layout.row(align=True)
- row.prop(statvis, "sharp_min", text="")
- row.prop(statvis, "sharp_max", text="")
-
-
-class VIEW3D_PT_view3d_curvedisplay(Panel):
- bl_space_type = 'VIEW_3D'
- bl_region_type = 'UI'
- bl_label = "Curve Display"
-
- @classmethod
- def poll(cls, context):
- editmesh = context.mode == 'EDIT_CURVE'
- return (editmesh)
-
- def draw(self, context):
- layout = self.layout
-
- curve = context.active_object.data
-
- col = layout.column()
- row = col.row()
- row.prop(curve, "show_handles", text="Handles")
- row.prop(curve, "show_normal_face", text="Normals")
-
-
class VIEW3D_PT_transform_orientations(Panel):
bl_space_type = 'VIEW_3D'
bl_region_type = 'UI'
@@ -4079,17 +4039,14 @@ classes = (
VIEW3D_MT_edit_armature_delete,
VIEW3D_MT_edit_gpencil_transform,
VIEW3D_MT_edit_gpencil_interpolate,
+ VIEW3D_PIE_object_mode,
+ VIEW3D_PIE_view,
VIEW3D_PT_grease_pencil,
VIEW3D_PT_grease_pencil_palettecolor,
VIEW3D_PT_view3d_properties,
VIEW3D_PT_view3d_cursor,
- VIEW3D_PT_view3d_name,
VIEW3D_PT_quad_view,
VIEW3D_PT_view3d_stereo,
- VIEW3D_PT_view3d_motion_tracking,
- VIEW3D_PT_view3d_meshdisplay,
- VIEW3D_PT_view3d_meshstatvis,
- VIEW3D_PT_view3d_curvedisplay,
VIEW3D_PT_shading,
VIEW3D_PT_overlay,
VIEW3D_PT_transform_orientations,
diff --git a/release/scripts/startup/bl_ui/space_view3d_toolbar.py b/release/scripts/startup/bl_ui/space_view3d_toolbar.py
index 48b80a1070a..db72dfc052e 100644
--- a/release/scripts/startup/bl_ui/space_view3d_toolbar.py
+++ b/release/scripts/startup/bl_ui/space_view3d_toolbar.py
@@ -69,7 +69,7 @@ def draw_vpaint_symmetry(layout, vpaint):
class VIEW3D_PT_tools_meshedit_options(View3DPanel, Panel):
bl_category = "Options"
- bl_context = ".mesh_edit" # dot on purpose (access from topbar)
+ bl_context = ".mesh_edit" # dot on purpose (access from topbar)
bl_label = "Mesh Options"
@classmethod
@@ -100,9 +100,10 @@ class VIEW3D_PT_tools_meshedit_options(View3DPanel, Panel):
# ********** default tools for editmode_curve ****************
+
class VIEW3D_PT_tools_curveedit_options_stroke(View3DPanel, Panel):
bl_category = "Options"
- bl_context = ".curve_edit" # dot on purpose (access from topbar)
+ bl_context = ".curve_edit" # dot on purpose (access from topbar)
bl_label = "Curve Stroke"
def draw(self, context):
@@ -154,8 +155,6 @@ class VIEW3D_PT_tools_curveedit_options_stroke(View3DPanel, Panel):
colsub.prop(cps, "surface_plane", expand=True)
-
-
# ********** default tools for editmode_armature ****************
@@ -174,7 +173,7 @@ class VIEW3D_PT_tools_armatureedit_options(View3DPanel, Panel):
class VIEW3D_PT_tools_posemode_options(View3DPanel, Panel):
bl_category = "Options"
- bl_context = ".posemode" # dot on purpose (access from topbar)
+ bl_context = ".posemode" # dot on purpose (access from topbar)
bl_label = "Pose Options"
def draw(self, context):
@@ -193,7 +192,7 @@ class View3DPaintPanel(UnifiedPaintPanel):
class VIEW3D_PT_imapaint_tools_missing(Panel, View3DPaintPanel):
bl_category = "Tools"
- bl_context = ".imagepaint" # dot on purpose (access from topbar)
+ bl_context = ".imagepaint" # dot on purpose (access from topbar)
bl_label = "Missing Data"
@classmethod
@@ -527,7 +526,7 @@ class VIEW3D_MT_tools_projectpaint_uvlayer(Menu):
class VIEW3D_PT_slots_projectpaint(View3DPanel, Panel):
- bl_context = ".imagepaint" # dot on purpose (access from topbar)
+ bl_context = ".imagepaint" # dot on purpose (access from topbar)
bl_label = "Slots"
bl_category = "Slots"
@@ -588,7 +587,7 @@ class VIEW3D_PT_slots_projectpaint(View3DPanel, Panel):
class VIEW3D_PT_stencil_projectpaint(View3DPanel, Panel):
- bl_context = ".imagepaint" # dot on purpose (access from topbar)
+ bl_context = ".imagepaint" # dot on purpose (access from topbar)
bl_label = "Mask"
bl_category = "Slots"
@@ -722,7 +721,7 @@ class VIEW3D_PT_tools_brush_texture(Panel, View3DPaintPanel):
class VIEW3D_PT_tools_mask_texture(Panel, View3DPaintPanel):
bl_category = "Tools"
- bl_context = ".imagepaint" # dot on purpose (access from topbar)
+ bl_context = ".imagepaint" # dot on purpose (access from topbar)
bl_label = "Texture Mask"
bl_options = {'DEFAULT_CLOSED'}
@@ -885,11 +884,11 @@ class VIEW3D_PT_sculpt_dyntopo(Panel, View3DPaintPanel):
def draw_header(self, context):
layout = self.layout
layout.operator(
- "sculpt.dynamic_topology_toggle",
- icon='CHECKBOX_HLT' if context.sculpt_object.use_dynamic_topology_sculpting else 'CHECKBOX_DEHLT',
- text="",
- emboss=False,
- )
+ "sculpt.dynamic_topology_toggle",
+ icon='CHECKBOX_HLT' if context.sculpt_object.use_dynamic_topology_sculpting else 'CHECKBOX_DEHLT',
+ text="",
+ emboss=False,
+ )
def draw(self, context):
layout = self.layout
@@ -1123,7 +1122,7 @@ class VIEW3D_PT_tools_vertexpaint_symmetry(Panel, View3DPaintPanel):
class VIEW3D_PT_tools_imagepaint_external(Panel, View3DPaintPanel):
bl_category = "Tools"
- bl_context = ".imagepaint" # dot on purpose (access from topbar)
+ bl_context = ".imagepaint" # dot on purpose (access from topbar)
bl_label = "External"
bl_options = {'DEFAULT_CLOSED'}
@@ -1145,7 +1144,7 @@ class VIEW3D_PT_tools_imagepaint_external(Panel, View3DPaintPanel):
class VIEW3D_PT_tools_imagepaint_symmetry(Panel, View3DPaintPanel):
bl_category = "Tools"
- bl_context = ".imagepaint" # dot on purpose (access from topbar)
+ bl_context = ".imagepaint" # dot on purpose (access from topbar)
bl_label = "Symmetry"
bl_options = {'DEFAULT_CLOSED'}
@@ -1164,7 +1163,7 @@ class VIEW3D_PT_tools_imagepaint_symmetry(Panel, View3DPaintPanel):
class VIEW3D_PT_tools_projectpaint(View3DPaintPanel, Panel):
bl_category = "Options"
- bl_context = ".imagepaint" # dot on purpose (access from topbar)
+ bl_context = ".imagepaint" # dot on purpose (access from topbar)
bl_label = "Project Paint"
@classmethod
@@ -1322,6 +1321,8 @@ class VIEW3D_PT_tools_grease_pencil_brush(GreasePencilBrushPanel, Panel):
bl_space_type = 'VIEW_3D'
# Grease Pencil drawingcurves
+
+
class VIEW3D_PT_tools_grease_pencil_brushcurves(GreasePencilBrushCurvesPanel, Panel):
bl_space_type = 'VIEW_3D'
diff --git a/source/blender/alembic/ABC_alembic.h b/source/blender/alembic/ABC_alembic.h
index 70250310213..08136fc2f49 100644
--- a/source/blender/alembic/ABC_alembic.h
+++ b/source/blender/alembic/ABC_alembic.h
@@ -29,8 +29,8 @@ extern "C" {
struct bContext;
struct CacheReader;
-struct DerivedMesh;
struct ListBase;
+struct Mesh;
struct Object;
struct Scene;
@@ -114,12 +114,13 @@ void ABC_get_transform(struct CacheReader *reader,
float time,
float scale);
-struct DerivedMesh *ABC_read_mesh(struct CacheReader *reader,
- struct Object *ob,
- struct DerivedMesh *dm,
- const float time,
- const char **err_str,
- int flags);
+/* Either modifies current_mesh in-place or constructs a new mesh. */
+struct Mesh *ABC_read_mesh(struct CacheReader *reader,
+ struct Object *ob,
+ struct Mesh *current_mesh,
+ const float time,
+ const char **err_str,
+ int flags);
void CacheReader_incref(struct CacheReader *reader);
void CacheReader_free(struct CacheReader *reader);
diff --git a/source/blender/alembic/intern/abc_camera.cc b/source/blender/alembic/intern/abc_camera.cc
index 4c91b9a6252..457bbd2b3af 100644
--- a/source/blender/alembic/intern/abc_camera.cc
+++ b/source/blender/alembic/intern/abc_camera.cc
@@ -49,13 +49,11 @@ using Alembic::AbcGeom::kWrapExisting;
/* ************************************************************************** */
-AbcCameraWriter::AbcCameraWriter(Depsgraph *depsgraph,
- Scene *scene,
- Object *ob,
+AbcCameraWriter::AbcCameraWriter(Object *ob,
AbcTransformWriter *parent,
uint32_t time_sampling,
ExportSettings &settings)
- : AbcObjectWriter(depsgraph, scene, ob, time_sampling, settings, parent)
+ : AbcObjectWriter(ob, time_sampling, settings, parent)
{
OCamera camera(parent->alembicXform(), m_name, m_time_sampling);
m_camera_schema = camera.getSchema();
diff --git a/source/blender/alembic/intern/abc_camera.h b/source/blender/alembic/intern/abc_camera.h
index a839ca947ca..dd5dc28d598 100644
--- a/source/blender/alembic/intern/abc_camera.h
+++ b/source/blender/alembic/intern/abc_camera.h
@@ -35,9 +35,7 @@ class AbcCameraWriter : public AbcObjectWriter {
Alembic::AbcGeom::OFloatProperty m_eye_separation;
public:
- AbcCameraWriter(Depsgraph *depsgraph,
- Scene *scene,
- Object *ob,
+ AbcCameraWriter(Object *ob,
AbcTransformWriter *parent,
uint32_t time_sampling,
ExportSettings &settings);
diff --git a/source/blender/alembic/intern/abc_curves.cc b/source/blender/alembic/intern/abc_curves.cc
index 41c1dacabc0..e27403305da 100644
--- a/source/blender/alembic/intern/abc_curves.cc
+++ b/source/blender/alembic/intern/abc_curves.cc
@@ -37,8 +37,8 @@ extern "C" {
#include "BLI_listbase.h"
-#include "BKE_cdderivedmesh.h"
#include "BKE_curve.h"
+#include "BKE_mesh.h"
#include "BKE_object.h"
#include "ED_curve.h"
@@ -71,13 +71,11 @@ using Alembic::AbcGeom::OV2fGeomParam;
/* ************************************************************************** */
-AbcCurveWriter::AbcCurveWriter(Depsgraph *depsgraph,
- Scene *scene,
- Object *ob,
+AbcCurveWriter::AbcCurveWriter(Object *ob,
AbcTransformWriter *parent,
uint32_t time_sampling,
ExportSettings &settings)
- : AbcObjectWriter(depsgraph, scene, ob, time_sampling, settings, parent)
+ : AbcObjectWriter(ob, time_sampling, settings, parent)
{
OCurves curves(parent->alembicXform(), m_name, m_time_sampling);
m_schema = curves.getSchema();
@@ -258,9 +256,21 @@ void AbcCurveReader::readObjectData(Main *bmain, const Alembic::Abc::ISampleSele
/* ************************************************************************** */
-void read_curve_sample(Curve *cu, const ICurvesSchema &schema, const ISampleSelector &sample_sel)
+void AbcCurveReader::read_curve_sample(Curve *cu, const ICurvesSchema &schema, const ISampleSelector &sample_sel)
{
- ICurvesSchema::Sample smp = schema.getValue(sample_sel);
+ ICurvesSchema::Sample smp;
+ try {
+ smp = schema.getValue(sample_sel);
+ }
+ catch(Alembic::Util::Exception &ex) {
+ printf("Alembic: error reading curve sample for '%s/%s' at time %f: %s\n",
+ m_iobject.getFullName().c_str(),
+ schema.getName().c_str(),
+ sample_sel.getRequestedTime(),
+ ex.what());
+ return;
+ }
+
const Int32ArraySamplePtr num_vertices = smp.getCurvesNumVertices();
const P3fArraySamplePtr positions = smp.getPositions();
const FloatArraySamplePtr weights = smp.getPositionWeights();
@@ -400,18 +410,31 @@ void read_curve_sample(Curve *cu, const ICurvesSchema &schema, const ISampleSele
}
}
-/* NOTE: Alembic only stores data about control points, but the DerivedMesh
+/* NOTE: Alembic only stores data about control points, but the Mesh
* passed from the cache modifier contains the displist, which has more data
* than the control points, so to avoid corrupting the displist we modify the
- * object directly and create a new DerivedMesh from that. Also we might need to
+ * object directly and create a new Mesh from that. Also we might need to
* create new or delete existing NURBS in the curve.
*/
-DerivedMesh *AbcCurveReader::read_derivedmesh(DerivedMesh * /*dm*/,
- const ISampleSelector &sample_sel,
- int /*read_flag*/,
- const char ** /*err_str*/)
+Mesh *AbcCurveReader::read_mesh(Mesh *existing_mesh,
+ const ISampleSelector &sample_sel,
+ int /*read_flag*/,
+ const char **err_str)
{
- const ICurvesSchema::Sample sample = m_curves_schema.getValue(sample_sel);
+ ICurvesSchema::Sample sample;
+
+ try {
+ sample = m_curves_schema.getValue(sample_sel);
+ }
+ catch(Alembic::Util::Exception &ex) {
+ *err_str = "Error reading curve sample; more detail on the console";
+ printf("Alembic: error reading curve sample for '%s/%s' at time %f: %s\n",
+ m_iobject.getFullName().c_str(),
+ m_curves_schema.getName().c_str(),
+ sample_sel.getRequestedTime(),
+ ex.what());
+ return existing_mesh;
+ }
const P3fArraySamplePtr &positions = sample.getPositions();
const Int32ArraySamplePtr num_vertices = sample.getCurvesNumVertices();
@@ -450,5 +473,5 @@ DerivedMesh *AbcCurveReader::read_derivedmesh(DerivedMesh * /*dm*/,
}
}
- return CDDM_from_curve(m_object);
+ return BKE_mesh_new_nomain_from_curve(m_object);
}
diff --git a/source/blender/alembic/intern/abc_curves.h b/source/blender/alembic/intern/abc_curves.h
index 1e7180bbb1f..eb80553620d 100644
--- a/source/blender/alembic/intern/abc_curves.h
+++ b/source/blender/alembic/intern/abc_curves.h
@@ -36,9 +36,7 @@ class AbcCurveWriter : public AbcObjectWriter {
Alembic::AbcGeom::OCurvesSchema::Sample m_sample;
public:
- AbcCurveWriter(Depsgraph *depsgraph,
- Scene *scene,
- Object *ob,
+ AbcCurveWriter(Object *ob,
AbcTransformWriter *parent,
uint32_t time_sampling,
ExportSettings &settings);
@@ -60,16 +58,17 @@ public:
const char **err_str) const;
void readObjectData(Main *bmain, const Alembic::Abc::ISampleSelector &sample_sel);
- DerivedMesh *read_derivedmesh(DerivedMesh *dm,
- const Alembic::Abc::ISampleSelector &sample_sel,
- int read_flag,
- const char **err_str);
+ struct Mesh *read_mesh(struct Mesh *existing_mesh,
+ const Alembic::Abc::ISampleSelector &sample_sel,
+ int read_flag,
+ const char **err_str);
+
+ void read_curve_sample(Curve *cu,
+ const Alembic::AbcGeom::ICurvesSchema &schema,
+ const Alembic::Abc::ISampleSelector &sample_selector);
+
};
/* ************************************************************************** */
-void read_curve_sample(Curve *cu,
- const Alembic::AbcGeom::ICurvesSchema &schema,
- const Alembic::Abc::ISampleSelector &sample_selector);
-
#endif /* __ABC_CURVES_H__ */
diff --git a/source/blender/alembic/intern/abc_exporter.cc b/source/blender/alembic/intern/abc_exporter.cc
index 093c4de085e..c766720d6cd 100644
--- a/source/blender/alembic/intern/abc_exporter.cc
+++ b/source/blender/alembic/intern/abc_exporter.cc
@@ -60,6 +60,8 @@ extern "C" {
#include "BKE_modifier.h"
#include "BKE_particle.h"
#include "BKE_scene.h"
+
+#include "DEG_depsgraph_query.h"
}
using Alembic::Abc::TimeSamplingPtr;
@@ -69,6 +71,8 @@ using Alembic::Abc::OBox3dProperty;
ExportSettings::ExportSettings()
: scene(NULL)
+ , view_layer(NULL)
+ , depsgraph(NULL)
, logger()
, selected_only(false)
, visible_layers_only(false)
@@ -168,16 +172,12 @@ static bool export_object(const ExportSettings * const settings, const Base * co
/* ************************************************************************** */
-AbcExporter::AbcExporter(Main *bmain, Scene *scene,
- Depsgraph *depsgraph,
- const char *filename, ExportSettings &settings)
+AbcExporter::AbcExporter(Main *bmain, const char *filename, ExportSettings &settings)
: m_bmain(bmain)
, m_settings(settings)
, m_filename(filename)
, m_trans_sampling_index(0)
, m_shape_sampling_index(0)
- , m_scene(scene)
- , m_depsgraph(depsgraph)
, m_writer(NULL)
{}
@@ -201,7 +201,7 @@ void AbcExporter::getShutterSamples(unsigned int nr_of_samples,
bool time_relative,
std::vector<double> &samples)
{
- Scene *scene = m_scene; /* for use in the FPS macro */
+ Scene *scene = m_settings.scene; /* for use in the FPS macro */
samples.clear();
unsigned int frame_offset = time_relative ? m_settings.frame_start : 0;
@@ -231,7 +231,7 @@ Alembic::Abc::TimeSamplingPtr AbcExporter::createTimeSampling(double step)
Alembic::Abc::TimeSamplingType ts(
static_cast<uint32_t>(samples.size()),
- 1.0 / m_scene->r.frs_sec);
+ 1.0 / m_settings.scene->r.frs_sec); /* TODO(Sybren): shouldn't we use the FPS macro here? */
return TimeSamplingPtr(new Alembic::Abc::TimeSampling(ts, samples));
}
@@ -265,7 +265,7 @@ void AbcExporter::operator()(float &progress, bool &was_canceled)
scene_name = "untitled";
}
- Scene *scene = m_scene;
+ Scene *scene = m_settings.scene;
const double fps = FPS;
char buf[16];
snprintf(buf, 15, "%f", fps);
@@ -297,8 +297,8 @@ void AbcExporter::operator()(float &progress, bool &was_canceled)
OBox3dProperty archive_bounds_prop = Alembic::AbcGeom::CreateOArchiveBounds(m_writer->archive(), m_trans_sampling_index);
- createTransformWritersHierarchy(m_depsgraph);
- createShapeWriters(m_depsgraph);
+ createTransformWritersHierarchy();
+ createShapeWriters();
/* Make a list of frames to export. */
@@ -360,7 +360,7 @@ void AbcExporter::operator()(float &progress, bool &was_canceled)
}
}
-void AbcExporter::createTransformWritersHierarchy(Depsgraph *depsgraph)
+void AbcExporter::createTransformWritersHierarchy()
{
for (Base *base = static_cast<Base *>(m_settings.view_layer->object_bases.first); base; base = base->next) {
Object *ob = base->object;
@@ -373,27 +373,26 @@ void AbcExporter::createTransformWritersHierarchy(Depsgraph *depsgraph)
/* We do not export transforms for objects of these classes. */
break;
default:
- exploreTransform(depsgraph, base, ob->parent, NULL);
+ exploreTransform(base, ob->parent, NULL);
}
}
}
}
-void AbcExporter::exploreTransform(Depsgraph *depsgraph, Base *ob_base, Object *parent, Object *dupliObParent)
+void AbcExporter::exploreTransform(Base *ob_base, Object *parent, Object *dupliObParent)
{
- Object *ob = ob_base->object;
-
/* If an object isn't exported itself, its duplilist shouldn't be
* exported either. */
if (!export_object(&m_settings, ob_base, dupliObParent != NULL)) {
return;
}
- if (object_type_is_exportable(m_scene, ob)) {
- createTransformWriter(depsgraph, ob, parent, dupliObParent);
+ Object *ob = DEG_get_evaluated_object(m_settings.depsgraph, ob_base->object);
+ if (object_type_is_exportable(m_settings.scene, ob)) {
+ createTransformWriter(ob, parent, dupliObParent);
}
- ListBase *lb = object_duplilist(depsgraph, m_scene, ob);
+ ListBase *lb = object_duplilist(m_settings.depsgraph, m_settings.scene, ob);
if (lb) {
Base fake_base = *ob_base; // copy flags (like selection state) from the real object.
@@ -414,15 +413,15 @@ void AbcExporter::exploreTransform(Depsgraph *depsgraph, Base *ob_base, Object *
dupli_parent = (dupli_ob->parent) ? dupli_ob->parent : ob;
fake_base.object = dupli_ob;
- exploreTransform(depsgraph, &fake_base, dupli_parent, ob);
+ exploreTransform(&fake_base, dupli_parent, ob);
}
}
- }
- free_object_duplilist(lb);
+ free_object_duplilist(lb);
+ }
}
-AbcTransformWriter * AbcExporter::createTransformWriter(Depsgraph *depsgraph, Object *ob, Object *parent, Object *dupliObParent)
+AbcTransformWriter * AbcExporter::createTransformWriter(Object *ob, Object *parent, Object *dupliObParent)
{
/* An object should not be its own parent, or we'll get infinite loops. */
BLI_assert(ob != parent);
@@ -457,29 +456,29 @@ AbcTransformWriter * AbcExporter::createTransformWriter(Depsgraph *depsgraph, Ob
* return the parent's AbcTransformWriter pointer. */
if (parent->parent) {
if (parent == dupliObParent) {
- parent_writer = createTransformWriter(depsgraph, parent, parent->parent, NULL);
+ parent_writer = createTransformWriter(parent, parent->parent, NULL);
}
else {
- parent_writer = createTransformWriter(depsgraph, parent, parent->parent, dupliObParent);
+ parent_writer = createTransformWriter(parent, parent->parent, dupliObParent);
}
}
else if (parent == dupliObParent) {
if (dupliObParent->parent == NULL) {
- parent_writer = createTransformWriter(depsgraph, parent, NULL, NULL);
+ parent_writer = createTransformWriter(parent, NULL, NULL);
}
else {
- parent_writer = createTransformWriter(depsgraph, parent, dupliObParent->parent, dupliObParent->parent);
+ parent_writer = createTransformWriter(parent, dupliObParent->parent, dupliObParent->parent);
}
}
else {
- parent_writer = createTransformWriter(depsgraph, parent, dupliObParent, dupliObParent);
+ parent_writer = createTransformWriter(parent, dupliObParent, dupliObParent);
}
BLI_assert(parent_writer);
alembic_parent = parent_writer->alembicXform();
}
- my_writer = new AbcTransformWriter(depsgraph, ob, alembic_parent, parent_writer,
+ my_writer = new AbcTransformWriter(ob, alembic_parent, parent_writer,
m_trans_sampling_index, m_settings);
/* When flattening, the matrix of the dupliobject has to be added. */
@@ -491,14 +490,14 @@ AbcTransformWriter * AbcExporter::createTransformWriter(Depsgraph *depsgraph, Ob
return my_writer;
}
-void AbcExporter::createShapeWriters(Depsgraph *depsgraph)
+void AbcExporter::createShapeWriters()
{
for (Base *base = static_cast<Base *>(m_settings.view_layer->object_bases.first); base; base = base->next) {
- exploreObject(depsgraph, base, NULL);
+ exploreObject(base, NULL);
}
}
-void AbcExporter::exploreObject(Depsgraph *depsgraph, Base *ob_base, Object *dupliObParent)
+void AbcExporter::exploreObject(Base *ob_base, Object *dupliObParent)
{
/* If an object isn't exported itself, its duplilist shouldn't be
* exported either. */
@@ -506,10 +505,10 @@ void AbcExporter::exploreObject(Depsgraph *depsgraph, Base *ob_base, Object *dup
return;
}
- createShapeWriter(ob_base, dupliObParent);
-
- Object *ob = ob_base->object;
- ListBase *lb = object_duplilist(depsgraph, m_scene, ob);
+ Object *ob = DEG_get_evaluated_object(m_settings.depsgraph, ob_base->object);
+ createShapeWriter(ob, dupliObParent);
+
+ ListBase *lb = object_duplilist(m_settings.depsgraph, m_settings.scene, ob);
if (lb) {
Base fake_base = *ob_base; // copy flags (like selection state) from the real object.
@@ -524,12 +523,12 @@ void AbcExporter::exploreObject(Depsgraph *depsgraph, Base *ob_base, Object *dup
}
if (link->type == OB_DUPLICOLLECTION) {
fake_base.object = link->ob;
- exploreObject(depsgraph, &fake_base, ob);
+ exploreObject(&fake_base, ob);
}
}
- }
- free_object_duplilist(lb);
+ free_object_duplilist(lb);
+ }
}
void AbcExporter::createParticleSystemsWriters(Object *ob, AbcTransformWriter *xform)
@@ -547,19 +546,17 @@ void AbcExporter::createParticleSystemsWriters(Object *ob, AbcTransformWriter *x
if (m_settings.export_hair && psys->part->type == PART_HAIR) {
m_settings.export_child_hairs = true;
- m_shapes.push_back(new AbcHairWriter(m_depsgraph, m_scene, ob, xform, m_shape_sampling_index, m_settings, psys));
+ m_shapes.push_back(new AbcHairWriter(ob, xform, m_shape_sampling_index, m_settings, psys));
}
else if (m_settings.export_particles && psys->part->type == PART_EMITTER) {
- m_shapes.push_back(new AbcPointsWriter(m_depsgraph, m_scene, ob, xform, m_shape_sampling_index, m_settings, psys));
+ m_shapes.push_back(new AbcPointsWriter(ob, xform, m_shape_sampling_index, m_settings, psys));
}
}
}
-void AbcExporter::createShapeWriter(Base *ob_base, Object *dupliObParent)
+void AbcExporter::createShapeWriter(Object *ob, Object *dupliObParent)
{
- Object *ob = ob_base->object;
-
- if (!object_type_is_exportable(m_scene, ob)) {
+ if (!object_type_is_exportable(m_settings.scene, ob)) {
return;
}
@@ -590,7 +587,7 @@ void AbcExporter::createShapeWriter(Base *ob_base, Object *dupliObParent)
return;
}
- m_shapes.push_back(new AbcMeshWriter(m_depsgraph, m_scene, ob, xform, m_shape_sampling_index, m_settings));
+ m_shapes.push_back(new AbcMeshWriter(ob, xform, m_shape_sampling_index, m_settings));
break;
}
case OB_SURF:
@@ -601,7 +598,7 @@ void AbcExporter::createShapeWriter(Base *ob_base, Object *dupliObParent)
return;
}
- m_shapes.push_back(new AbcNurbsWriter(m_depsgraph, m_scene, ob, xform, m_shape_sampling_index, m_settings));
+ m_shapes.push_back(new AbcNurbsWriter(ob, xform, m_shape_sampling_index, m_settings));
break;
}
case OB_CURVE:
@@ -612,7 +609,7 @@ void AbcExporter::createShapeWriter(Base *ob_base, Object *dupliObParent)
return;
}
- m_shapes.push_back(new AbcCurveWriter(m_depsgraph, m_scene, ob, xform, m_shape_sampling_index, m_settings));
+ m_shapes.push_back(new AbcCurveWriter(ob, xform, m_shape_sampling_index, m_settings));
break;
}
case OB_CAMERA:
@@ -620,7 +617,7 @@ void AbcExporter::createShapeWriter(Base *ob_base, Object *dupliObParent)
Camera *cam = static_cast<Camera *>(ob->data);
if (cam->type == CAM_PERSP) {
- m_shapes.push_back(new AbcCameraWriter(m_depsgraph, m_scene, ob, xform, m_shape_sampling_index, m_settings));
+ m_shapes.push_back(new AbcCameraWriter(ob, xform, m_shape_sampling_index, m_settings));
}
break;
@@ -633,7 +630,7 @@ void AbcExporter::createShapeWriter(Base *ob_base, Object *dupliObParent)
}
m_shapes.push_back(new AbcMBallWriter(
- m_bmain, m_depsgraph, m_scene, ob, xform,
+ m_bmain, ob, xform,
m_shape_sampling_index, m_settings));
break;
}
@@ -653,7 +650,7 @@ AbcTransformWriter *AbcExporter::getXForm(const std::string &name)
void AbcExporter::setCurrentFrame(Main *bmain, double t)
{
- m_scene->r.cfra = static_cast<int>(t);
- m_scene->r.subframe = static_cast<float>(t) - m_scene->r.cfra;
- BKE_scene_graph_update_for_newframe(m_depsgraph, bmain);
+ m_settings.scene->r.cfra = static_cast<int>(t);
+ m_settings.scene->r.subframe = static_cast<float>(t) - m_settings.scene->r.cfra;
+ BKE_scene_graph_update_for_newframe(m_settings.depsgraph, bmain);
}
diff --git a/source/blender/alembic/intern/abc_exporter.h b/source/blender/alembic/intern/abc_exporter.h
index c891824a114..a92e426292c 100644
--- a/source/blender/alembic/intern/abc_exporter.h
+++ b/source/blender/alembic/intern/abc_exporter.h
@@ -92,9 +92,6 @@ class AbcExporter {
unsigned int m_trans_sampling_index, m_shape_sampling_index;
- Scene *m_scene;
- Depsgraph *m_depsgraph;
-
ArchiveWriter *m_writer;
/* mapping from name to transform writer */
@@ -104,8 +101,7 @@ class AbcExporter {
std::vector<AbcObjectWriter *> m_shapes;
public:
- AbcExporter(Main *bmain, Scene *scene, Depsgraph *depsgraph,
- const char *filename, ExportSettings &settings);
+ AbcExporter(Main *bmain, const char *filename, ExportSettings &settings);
~AbcExporter();
void operator()(float &progress, bool &was_canceled);
@@ -119,12 +115,12 @@ protected:
private:
Alembic::Abc::TimeSamplingPtr createTimeSampling(double step);
- void createTransformWritersHierarchy(Depsgraph *depsgraph);
- AbcTransformWriter * createTransformWriter(Depsgraph *depsgraph, Object *ob, Object *parent, Object *dupliObParent);
- void exploreTransform(Depsgraph *depsgraph, Base *ob_base, Object *parent, Object *dupliObParent);
- void exploreObject(Depsgraph *depsgraph, Base *ob_base, Object *dupliObParent);
- void createShapeWriters(Depsgraph *depsgraph);
- void createShapeWriter(Base *ob_base, Object *dupliObParent);
+ void createTransformWritersHierarchy();
+ AbcTransformWriter * createTransformWriter(Object *ob, Object *parent, Object *dupliObParent);
+ void exploreTransform(Base *ob_base, Object *parent, Object *dupliObParent);
+ void exploreObject(Base *ob_base, Object *dupliObParent);
+ void createShapeWriters();
+ void createShapeWriter(Object *ob, Object *dupliObParent);
void createParticleSystemsWriters(Object *ob, AbcTransformWriter *xform);
AbcTransformWriter *getXForm(const std::string &name);
diff --git a/source/blender/alembic/intern/abc_hair.cc b/source/blender/alembic/intern/abc_hair.cc
index e7cc474e2e8..83a46a330fd 100644
--- a/source/blender/alembic/intern/abc_hair.cc
+++ b/source/blender/alembic/intern/abc_hair.cc
@@ -30,12 +30,16 @@
extern "C" {
#include "MEM_guardedalloc.h"
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
#include "DNA_modifier_types.h"
#include "BLI_listbase.h"
#include "BLI_math_geom.h"
-#include "BKE_DerivedMesh.h"
+#include "BKE_library.h"
+#include "BKE_mesh.h"
+#include "BKE_mesh_runtime.h"
#include "BKE_object.h"
#include "BKE_particle.h"
}
@@ -49,14 +53,12 @@ using Alembic::AbcGeom::OV2fGeomParam;
/* ************************************************************************** */
-AbcHairWriter::AbcHairWriter(Depsgraph *depsgraph,
- Scene *scene,
- Object *ob,
+AbcHairWriter::AbcHairWriter(Object *ob,
AbcTransformWriter *parent,
uint32_t time_sampling,
ExportSettings &settings,
ParticleSystem *psys)
- : AbcObjectWriter(depsgraph, scene, ob, time_sampling, settings, parent)
+ : AbcObjectWriter(ob, time_sampling, settings, parent)
, m_uv_warning_shown(false)
{
m_psys = psys;
@@ -70,15 +72,8 @@ void AbcHairWriter::do_write()
if (!m_psys) {
return;
}
-
- ParticleSystemModifierData *psmd = psys_get_modifier(m_object, m_psys);
-
- if (!psmd->mesh_final) {
- return;
- }
-
- DerivedMesh *dm = mesh_create_derived_render(m_depsgraph, m_scene, m_object, CD_MASK_MESH);
- DM_ensure_tessface(dm);
+ Mesh *mesh = mesh_get_eval_final(m_settings.depsgraph, m_settings.scene, m_object, CD_MASK_MESH);
+ BKE_mesh_tessface_ensure(mesh);
std::vector<Imath::V3f> verts;
std::vector<int32_t> hvertices;
@@ -88,15 +83,13 @@ void AbcHairWriter::do_write()
if (m_psys->pathcache) {
ParticleSettings *part = m_psys->part;
- write_hair_sample(dm, part, verts, norm_values, uv_values, hvertices);
+ write_hair_sample(mesh, part, verts, norm_values, uv_values, hvertices);
if (m_settings.export_child_hairs && m_psys->childcache) {
- write_hair_child_sample(dm, part, verts, norm_values, uv_values, hvertices);
+ write_hair_child_sample(mesh, part, verts, norm_values, uv_values, hvertices);
}
}
- dm->release(dm);
-
Alembic::Abc::P3fArraySample iPos(verts);
m_sample = OCurvesSchema::Sample(iPos, hvertices);
m_sample.setBasis(Alembic::AbcGeom::kNoBasis);
@@ -119,7 +112,7 @@ void AbcHairWriter::do_write()
m_schema.set(m_sample);
}
-void AbcHairWriter::write_hair_sample(DerivedMesh *dm,
+void AbcHairWriter::write_hair_sample(Mesh *mesh,
ParticleSettings *part,
std::vector<Imath::V3f> &verts,
std::vector<Imath::V3f> &norm_values,
@@ -130,9 +123,9 @@ void AbcHairWriter::write_hair_sample(DerivedMesh *dm,
float inv_mat[4][4];
invert_m4_m4_safe(inv_mat, m_object->obmat);
- MTFace *mtface = static_cast<MTFace *>(CustomData_get_layer(&dm->faceData, CD_MTFACE));
- MFace *mface = dm->getTessFaceArray(dm);
- MVert *mverts = dm->getVertArray(dm);
+ MTFace *mtface = mesh->mtface;
+ MFace *mface = mesh->mface;
+ MVert *mverts = mesh->mvert;
if ((!mtface || !mface) && !m_uv_warning_shown) {
std::fprintf(stderr, "Warning, no UV set found for underlying geometry of %s.\n",
@@ -152,11 +145,13 @@ void AbcHairWriter::write_hair_sample(DerivedMesh *dm,
/* underlying info for faces-only emission */
path = cache[p];
+ /* Write UV and normal vectors */
if (part->from == PART_FROM_FACE && mtface) {
const int num = pa->num_dmcache >= 0 ? pa->num_dmcache : pa->num;
- if (num < dm->getNumTessFaces(dm)) {
- MFace *face = static_cast<MFace *>(dm->getTessFaceData(dm, num, CD_MFACE));
+ if (num < mesh->totface) {
+ /* TODO(Sybren): check whether the NULL check here and if(mface) are actually required */
+ MFace *face = mface == NULL ? NULL : &mface[num];
MTFace *tface = mtface + num;
if (mface) {
@@ -172,7 +167,7 @@ void AbcHairWriter::write_hair_sample(DerivedMesh *dm,
}
}
else {
- std::fprintf(stderr, "Particle to faces overflow (%d/%d)\n", num, dm->getNumTessFaces(dm));
+ std::fprintf(stderr, "Particle to faces overflow (%d/%d)\n", num, mesh->totface);
}
}
else if (part->from == PART_FROM_VERT && mtface) {
@@ -180,8 +175,8 @@ void AbcHairWriter::write_hair_sample(DerivedMesh *dm,
const int num = (pa->num_dmcache >= 0) ? pa->num_dmcache : pa->num;
/* iterate over all faces to find a corresponding underlying UV */
- for (int n = 0; n < dm->getNumTessFaces(dm); ++n) {
- MFace *face = static_cast<MFace *>(dm->getTessFaceData(dm, n, CD_MFACE));
+ for (int n = 0; n < mesh->totface; ++n) {
+ MFace *face = &mface[n];
MTFace *tface = mtface + n;
unsigned int vtx[4];
vtx[0] = face->v1;
@@ -217,7 +212,7 @@ void AbcHairWriter::write_hair_sample(DerivedMesh *dm,
int steps = path->segments + 1;
hvertices.push_back(steps);
- for (k = 0; k < steps; ++k) {
+ for (k = 0; k < steps; ++k, ++path) {
float vert[3];
copy_v3_v3(vert, path->co);
mul_m4_v3(inv_mat, vert);
@@ -225,12 +220,11 @@ void AbcHairWriter::write_hair_sample(DerivedMesh *dm,
/* Convert Z-up to Y-up. */
verts.push_back(Imath::V3f(vert[0], vert[2], -vert[1]));
- ++path;
}
}
}
-void AbcHairWriter::write_hair_child_sample(DerivedMesh *dm,
+void AbcHairWriter::write_hair_child_sample(Mesh *mesh,
ParticleSettings *part,
std::vector<Imath::V3f> &verts,
std::vector<Imath::V3f> &norm_values,
@@ -241,8 +235,8 @@ void AbcHairWriter::write_hair_child_sample(DerivedMesh *dm,
float inv_mat[4][4];
invert_m4_m4_safe(inv_mat, m_object->obmat);
- MTFace *mtface = static_cast<MTFace *>(CustomData_get_layer(&dm->faceData, CD_MTFACE));
- MVert *mverts = dm->getVertArray(dm);
+ MTFace *mtface = mesh->mtface;
+ MVert *mverts = mesh->mvert;
ParticleCacheKey **cache = m_psys->childcache;
ParticleCacheKey *path;
@@ -265,7 +259,7 @@ void AbcHairWriter::write_hair_child_sample(DerivedMesh *dm,
continue;
}
- MFace *face = static_cast<MFace *>(dm->getTessFaceData(dm, num, CD_MFACE));
+ MFace *face = &mesh->mface[num];
MTFace *tface = mtface + num;
float r_uv[2], tmpnor[3], mapfw[4], vec[3];
diff --git a/source/blender/alembic/intern/abc_hair.h b/source/blender/alembic/intern/abc_hair.h
index 5627f7726e6..e2dffd4edaf 100644
--- a/source/blender/alembic/intern/abc_hair.h
+++ b/source/blender/alembic/intern/abc_hair.h
@@ -25,7 +25,6 @@
#include "abc_object.h"
-struct DerivedMesh;
struct ParticleSettings;
struct ParticleSystem;
@@ -40,9 +39,7 @@ class AbcHairWriter : public AbcObjectWriter {
bool m_uv_warning_shown;
public:
- AbcHairWriter(Depsgraph *depsgraph,
- Scene *scene,
- Object *ob,
+ AbcHairWriter(Object *ob,
AbcTransformWriter *parent,
uint32_t time_sampling,
ExportSettings &settings,
@@ -51,14 +48,14 @@ public:
private:
virtual void do_write();
- void write_hair_sample(DerivedMesh *dm,
+ void write_hair_sample(struct Mesh *mesh,
ParticleSettings *part,
std::vector<Imath::V3f> &verts,
std::vector<Imath::V3f> &norm_values,
std::vector<Imath::V2f> &uv_values,
std::vector<int32_t> &hvertices);
- void write_hair_child_sample(DerivedMesh *dm,
+ void write_hair_child_sample(struct Mesh *mesh,
ParticleSettings *part,
std::vector<Imath::V3f> &verts,
std::vector<Imath::V3f> &norm_values,
diff --git a/source/blender/alembic/intern/abc_mball.cc b/source/blender/alembic/intern/abc_mball.cc
index 1df55712abe..d6e54407922 100644
--- a/source/blender/alembic/intern/abc_mball.cc
+++ b/source/blender/alembic/intern/abc_mball.cc
@@ -42,13 +42,11 @@ extern "C" {
AbcMBallWriter::AbcMBallWriter(
Main *bmain,
- Depsgraph *depsgraph,
- Scene *scene,
Object *ob,
AbcTransformWriter *parent,
uint32_t time_sampling,
ExportSettings &settings)
- : AbcObjectWriter(depsgraph, scene, ob, time_sampling, settings, parent)
+ : AbcObjectWriter(ob, time_sampling, settings, parent)
, m_bmain(bmain)
{
m_is_animated = isAnimated();
@@ -58,8 +56,7 @@ AbcMBallWriter::AbcMBallWriter(
sizeof(CurveCache),
"CurveCache for AbcMBallWriter");
- m_mesh_writer = new AbcMeshWriter(depsgraph, scene, m_mesh_ob, parent,
- time_sampling, settings);
+ m_mesh_writer = new AbcMeshWriter(m_mesh_ob, parent, time_sampling, settings);
m_mesh_writer->setIsAnimated(m_is_animated);
}
@@ -101,7 +98,7 @@ void AbcMBallWriter::do_write()
* only contains for_render flag. As soon as CoW is
* implemented, this is to be rethinked.
*/
- BKE_displist_make_mball_forRender(m_depsgraph, m_scene, m_object, &disp);
+ BKE_displist_make_mball_forRender(m_settings.depsgraph, m_settings.scene, m_object, &disp);
BKE_mesh_from_metaball(&disp, tmpmesh);
BKE_displist_free(&disp);
diff --git a/source/blender/alembic/intern/abc_mball.h b/source/blender/alembic/intern/abc_mball.h
index bae4b6bcb76..07cb1908e95 100644
--- a/source/blender/alembic/intern/abc_mball.h
+++ b/source/blender/alembic/intern/abc_mball.h
@@ -43,8 +43,6 @@ class AbcMBallWriter : public AbcObjectWriter {
public:
AbcMBallWriter(
Main *bmain,
- Depsgraph *depsgraph,
- Scene *scene,
Object *ob,
AbcTransformWriter *parent,
uint32_t time_sampling,
diff --git a/source/blender/alembic/intern/abc_mesh.cc b/source/blender/alembic/intern/abc_mesh.cc
index d52d7f06048..2b739837239 100644
--- a/source/blender/alembic/intern/abc_mesh.cc
+++ b/source/blender/alembic/intern/abc_mesh.cc
@@ -30,6 +30,7 @@
extern "C" {
#include "DNA_material_types.h"
#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
#include "DNA_modifier_types.h"
#include "DNA_object_fluidsim_types.h"
#include "DNA_object_types.h"
@@ -37,10 +38,10 @@ extern "C" {
#include "BLI_math_geom.h"
#include "BLI_string.h"
-#include "BKE_cdderivedmesh.h"
#include "BKE_main.h"
#include "BKE_material.h"
#include "BKE_mesh.h"
+#include "BKE_mesh_runtime.h"
#include "BKE_modifier.h"
#include "BKE_object.h"
@@ -51,6 +52,8 @@ extern "C" {
#include "bmesh.h"
#include "bmesh_tools.h"
+
+#include "DEG_depsgraph_query.h"
}
using Alembic::Abc::FloatArraySample;
@@ -103,27 +106,27 @@ using Alembic::AbcGeom::IN3fGeomParam;
/* NOTE: Alembic's polygon winding order is clockwise, to match with Renderman. */
-static void get_vertices(DerivedMesh *dm, std::vector<Imath::V3f> &points)
+static void get_vertices(struct Mesh *mesh, std::vector<Imath::V3f> &points)
{
points.clear();
- points.resize(dm->getNumVerts(dm));
+ points.resize(mesh->totvert);
- MVert *verts = dm->getVertArray(dm);
+ MVert *verts = mesh->mvert;
- for (int i = 0, e = dm->getNumVerts(dm); i < e; ++i) {
+ for (int i = 0, e = mesh->totvert; i < e; ++i) {
copy_yup_from_zup(points[i].getValue(), verts[i].co);
}
}
-static void get_topology(DerivedMesh *dm,
+static void get_topology(struct Mesh *mesh,
std::vector<int32_t> &poly_verts,
std::vector<int32_t> &loop_counts,
bool &smooth_normal)
{
- const int num_poly = dm->getNumPolys(dm);
- const int num_loops = dm->getNumLoops(dm);
- MLoop *mloop = dm->getLoopArray(dm);
- MPoly *mpoly = dm->getPolyArray(dm);
+ const int num_poly = mesh->totpoly;
+ const int num_loops = mesh->totloop;
+ MLoop *mloop = mesh->mloop;
+ MPoly *mpoly = mesh->mpoly;
poly_verts.clear();
loop_counts.clear();
@@ -145,7 +148,7 @@ static void get_topology(DerivedMesh *dm,
}
}
-static void get_creases(DerivedMesh *dm,
+static void get_creases(struct Mesh *mesh,
std::vector<int32_t> &indices,
std::vector<int32_t> &lengths,
std::vector<float> &sharpnesses)
@@ -156,9 +159,9 @@ static void get_creases(DerivedMesh *dm,
lengths.clear();
sharpnesses.clear();
- MEdge *edge = dm->getEdgeArray(dm);
+ MEdge *edge = mesh->medge;
- for (int i = 0, e = dm->getNumEdges(dm); i < e; ++i) {
+ for (int i = 0, e = mesh->totedge; i < e; ++i) {
const float sharpness = static_cast<float>(edge[i].crease) * factor;
if (sharpness != 0.0f) {
@@ -171,41 +174,40 @@ static void get_creases(DerivedMesh *dm,
lengths.resize(sharpnesses.size(), 2);
}
-static void get_vertex_normals(DerivedMesh *dm, std::vector<Imath::V3f> &normals)
+static void get_vertex_normals(struct Mesh *mesh, std::vector<Imath::V3f> &normals)
{
normals.clear();
- normals.resize(dm->getNumVerts(dm));
+ normals.resize(mesh->totvert);
- MVert *verts = dm->getVertArray(dm);
+ MVert *verts = mesh->mvert;
float no[3];
- for (int i = 0, e = dm->getNumVerts(dm); i < e; ++i) {
+ for (int i = 0, e = mesh->totvert; i < e; ++i) {
normal_short_to_float_v3(no, verts[i].no);
copy_yup_from_zup(normals[i].getValue(), no);
}
}
-static void get_loop_normals(DerivedMesh *dm, std::vector<Imath::V3f> &normals)
+static void get_loop_normals(struct Mesh *mesh, std::vector<Imath::V3f> &normals)
{
- MPoly *mpoly = dm->getPolyArray(dm);
- MPoly *mp = mpoly;
+ MPoly *mp = mesh->mpoly;
- MLoop *mloop = dm->getLoopArray(dm);
+ MLoop *mloop = mesh->mloop;
MLoop *ml = mloop;
- MVert *verts = dm->getVertArray(dm);
+ MVert *verts = mesh->mvert;
- const float (*lnors)[3] = static_cast<float(*)[3]>(dm->getLoopDataArray(dm, CD_NORMAL));
+ const float (*lnors)[3] = static_cast<float(*)[3]>(CustomData_get_layer(&mesh->ldata, CD_NORMAL));
normals.clear();
- normals.resize(dm->getNumLoops(dm));
+ normals.resize(mesh->totloop);
unsigned loop_index = 0;
/* NOTE: data needs to be written in the reverse order. */
if (lnors) {
- for (int i = 0, e = dm->getNumPolys(dm); i < e; ++i, ++mp) {
+ for (int i = 0, e = mesh->totpoly; i < e; ++i, ++mp) {
ml = mloop + mp->loopstart + (mp->totloop - 1);
for (int j = 0; j < mp->totloop; --ml, ++j, ++loop_index) {
@@ -217,7 +219,7 @@ static void get_loop_normals(DerivedMesh *dm, std::vector<Imath::V3f> &normals)
else {
float no[3];
- for (int i = 0, e = dm->getNumPolys(dm); i < e; ++i, ++mp) {
+ for (int i = 0, e = mesh->totpoly; i < e; ++i, ++mp) {
ml = mloop + mp->loopstart + (mp->totloop - 1);
/* Flat shaded, use common normal for all verts. */
@@ -286,13 +288,11 @@ static ModifierData *get_liquid_sim_modifier(Scene *scene, Object *ob)
/* ************************************************************************** */
-AbcMeshWriter::AbcMeshWriter(Depsgraph *depsgraph,
- Scene *scene,
- Object *ob,
+AbcMeshWriter::AbcMeshWriter(Object *ob,
AbcTransformWriter *parent,
uint32_t time_sampling,
ExportSettings &settings)
- : AbcObjectWriter(depsgraph, scene, ob, time_sampling, settings, parent)
+ : AbcObjectWriter(ob, time_sampling, settings, parent)
{
m_is_animated = isAnimated();
m_subsurf_mod = NULL;
@@ -304,11 +304,11 @@ AbcMeshWriter::AbcMeshWriter(Depsgraph *depsgraph,
}
if (!m_settings.apply_subdiv) {
- m_subsurf_mod = get_subsurf_modifier(m_scene, m_object);
+ m_subsurf_mod = get_subsurf_modifier(m_settings.scene, m_object);
m_is_subd = (m_subsurf_mod != NULL);
}
- m_is_liquid = (get_liquid_sim_modifier(m_scene, m_object) != NULL);
+ m_is_liquid = (get_liquid_sim_modifier(m_settings.scene, m_object) != NULL);
while (parent->alembicXform().getChildHeader(m_name)) {
m_name.append("_");
@@ -369,36 +369,37 @@ void AbcMeshWriter::do_write()
if (!m_first_frame && !m_is_animated)
return;
- DerivedMesh *dm = getFinalMesh();
+ bool needsfree;
+ struct Mesh *mesh = getFinalMesh(needsfree);
try {
if (m_settings.use_subdiv_schema && m_subdiv_schema.valid()) {
- writeSubD(dm);
+ writeSubD(mesh);
}
else {
- writeMesh(dm);
+ writeMesh(mesh);
}
- freeMesh(dm);
+ if (needsfree) BKE_id_free(NULL, mesh);
}
catch (...) {
- freeMesh(dm);
+ if (needsfree) BKE_id_free(NULL, mesh);
throw;
}
}
-void AbcMeshWriter::writeMesh(DerivedMesh *dm)
+void AbcMeshWriter::writeMesh(struct Mesh *mesh)
{
std::vector<Imath::V3f> points, normals;
std::vector<int32_t> poly_verts, loop_counts;
bool smooth_normal = false;
- get_vertices(dm, points);
- get_topology(dm, poly_verts, loop_counts, smooth_normal);
+ get_vertices(mesh, points);
+ get_topology(mesh, poly_verts, loop_counts, smooth_normal);
if (m_first_frame && m_settings.export_face_sets) {
- writeFaceSets(dm, m_mesh_schema);
+ writeFaceSets(mesh, m_mesh_schema);
}
m_mesh_sample = OPolyMeshSchema::Sample(V3fArraySample(points),
@@ -407,7 +408,7 @@ void AbcMeshWriter::writeMesh(DerivedMesh *dm)
UVSample sample;
if (m_first_frame && m_settings.export_uvs) {
- const char *name = get_uv_sample(sample, m_custom_data_config, &dm->loopData);
+ const char *name = get_uv_sample(sample, m_custom_data_config, &mesh->ldata);
if (!sample.indices.empty() && !sample.uvs.empty()) {
OV2fGeomParam::Sample uv_sample;
@@ -419,15 +420,15 @@ void AbcMeshWriter::writeMesh(DerivedMesh *dm)
m_mesh_sample.setUVs(uv_sample);
}
- write_custom_data(m_mesh_schema.getArbGeomParams(), m_custom_data_config, &dm->loopData, CD_MLOOPUV);
+ write_custom_data(m_mesh_schema.getArbGeomParams(), m_custom_data_config, &mesh->ldata, CD_MLOOPUV);
}
if (m_settings.export_normals) {
if (smooth_normal) {
- get_loop_normals(dm, normals);
+ get_loop_normals(mesh, normals);
}
else {
- get_vertex_normals(dm, normals);
+ get_vertex_normals(mesh, normals);
}
ON3fGeomParam::Sample normals_sample;
@@ -441,7 +442,7 @@ void AbcMeshWriter::writeMesh(DerivedMesh *dm)
if (m_is_liquid) {
std::vector<Imath::V3f> velocities;
- getVelocities(dm, velocities);
+ getVelocities(mesh, velocities);
m_mesh_sample.setVelocities(V3fArraySample(velocities));
}
@@ -450,10 +451,10 @@ void AbcMeshWriter::writeMesh(DerivedMesh *dm)
m_mesh_schema.set(m_mesh_sample);
- writeArbGeoParams(dm);
+ writeArbGeoParams(mesh);
}
-void AbcMeshWriter::writeSubD(DerivedMesh *dm)
+void AbcMeshWriter::writeSubD(struct Mesh *mesh)
{
std::vector<float> crease_sharpness;
std::vector<Imath::V3f> points;
@@ -462,12 +463,12 @@ void AbcMeshWriter::writeSubD(DerivedMesh *dm)
bool smooth_normal = false;
- get_vertices(dm, points);
- get_topology(dm, poly_verts, loop_counts, smooth_normal);
- get_creases(dm, crease_indices, crease_lengths, crease_sharpness);
+ get_vertices(mesh, points);
+ get_topology(mesh, poly_verts, loop_counts, smooth_normal);
+ get_creases(mesh, crease_indices, crease_lengths, crease_sharpness);
if (m_first_frame && m_settings.export_face_sets) {
- writeFaceSets(dm, m_subdiv_schema);
+ writeFaceSets(mesh, m_subdiv_schema);
}
m_subdiv_sample = OSubDSchema::Sample(V3fArraySample(points),
@@ -476,7 +477,7 @@ void AbcMeshWriter::writeSubD(DerivedMesh *dm)
UVSample sample;
if (m_first_frame && m_settings.export_uvs) {
- const char *name = get_uv_sample(sample, m_custom_data_config, &dm->loopData);
+ const char *name = get_uv_sample(sample, m_custom_data_config, &mesh->ldata);
if (!sample.indices.empty() && !sample.uvs.empty()) {
OV2fGeomParam::Sample uv_sample;
@@ -488,7 +489,7 @@ void AbcMeshWriter::writeSubD(DerivedMesh *dm)
m_subdiv_sample.setUVs(uv_sample);
}
- write_custom_data(m_subdiv_schema.getArbGeomParams(), m_custom_data_config, &dm->loopData, CD_MLOOPUV);
+ write_custom_data(m_subdiv_schema.getArbGeomParams(), m_custom_data_config, &mesh->ldata, CD_MLOOPUV);
}
if (!crease_indices.empty()) {
@@ -500,11 +501,11 @@ void AbcMeshWriter::writeSubD(DerivedMesh *dm)
m_subdiv_sample.setSelfBounds(bounds());
m_subdiv_schema.set(m_subdiv_sample);
- writeArbGeoParams(dm);
+ writeArbGeoParams(mesh);
}
template <typename Schema>
-void AbcMeshWriter::writeFaceSets(DerivedMesh *dm, Schema &schema)
+void AbcMeshWriter::writeFaceSets(struct Mesh *dm, Schema &schema)
{
std::map< std::string, std::vector<int32_t> > geo_groups;
getGeoGroups(dm, geo_groups);
@@ -518,14 +519,17 @@ void AbcMeshWriter::writeFaceSets(DerivedMesh *dm, Schema &schema)
}
}
-DerivedMesh *AbcMeshWriter::getFinalMesh()
+Mesh *AbcMeshWriter::getFinalMesh(bool &r_needsfree)
{
/* We don't want subdivided mesh data */
if (m_subsurf_mod) {
m_subsurf_mod->mode |= eModifierMode_DisableTemporary;
}
- DerivedMesh *dm = mesh_create_derived_render(m_depsgraph, m_scene, m_object, CD_MASK_MESH);
+ Scene *scene = DEG_get_evaluated_scene(m_settings.depsgraph);
+ Object *ob_eval = DEG_get_evaluated_object(m_settings.depsgraph, m_object);
+ struct Mesh *mesh = mesh_get_eval_final(m_settings.depsgraph, scene, ob_eval, CD_MASK_MESH);
+ r_needsfree = false;
if (m_subsurf_mod) {
m_subsurf_mod->mode &= ~eModifierMode_DisableTemporary;
@@ -536,34 +540,31 @@ DerivedMesh *AbcMeshWriter::getFinalMesh()
const int quad_method = m_settings.quad_method;
const int ngon_method = m_settings.ngon_method;
- BMesh *bm = DM_to_bmesh(dm, true);
+ struct BMeshCreateParams bmcp = {false};
+ struct BMeshFromMeshParams bmfmp = {true, false, false, 0};
+ BMesh *bm = BKE_mesh_to_bmesh_ex(mesh, &bmcp, &bmfmp);
BM_mesh_triangulate(bm, quad_method, ngon_method, tag_only, NULL, NULL, NULL);
- DerivedMesh *result = CDDM_from_bmesh(bm, false);
+ struct BMeshToMeshParams bmmp = {0};
+ Mesh *result = BKE_bmesh_to_mesh_nomain(bm, &bmmp);
BM_mesh_free(bm);
- freeMesh(dm);
-
- dm = result;
+ mesh = result;
+ r_needsfree = true;
}
m_custom_data_config.pack_uvs = m_settings.pack_uv;
- m_custom_data_config.mpoly = dm->getPolyArray(dm);
- m_custom_data_config.mloop = dm->getLoopArray(dm);
- m_custom_data_config.totpoly = dm->getNumPolys(dm);
- m_custom_data_config.totloop = dm->getNumLoops(dm);
- m_custom_data_config.totvert = dm->getNumVerts(dm);
+ m_custom_data_config.mpoly = mesh->mpoly;
+ m_custom_data_config.mloop = mesh->mloop;
+ m_custom_data_config.totpoly = mesh->totpoly;
+ m_custom_data_config.totloop = mesh->totloop;
+ m_custom_data_config.totvert = mesh->totvert;
- return dm;
-}
-
-void AbcMeshWriter::freeMesh(DerivedMesh *dm)
-{
- dm->release(dm);
+ return mesh;
}
-void AbcMeshWriter::writeArbGeoParams(DerivedMesh *dm)
+void AbcMeshWriter::writeArbGeoParams(struct Mesh *dm)
{
if (m_is_liquid) {
/* We don't need anything more for liquid meshes. */
@@ -572,22 +573,22 @@ void AbcMeshWriter::writeArbGeoParams(DerivedMesh *dm)
if (m_first_frame && m_settings.export_vcols) {
if (m_subdiv_schema.valid()) {
- write_custom_data(m_subdiv_schema.getArbGeomParams(), m_custom_data_config, &dm->loopData, CD_MLOOPCOL);
+ write_custom_data(m_subdiv_schema.getArbGeomParams(), m_custom_data_config, &dm->ldata, CD_MLOOPCOL);
}
else {
- write_custom_data(m_mesh_schema.getArbGeomParams(), m_custom_data_config, &dm->loopData, CD_MLOOPCOL);
+ write_custom_data(m_mesh_schema.getArbGeomParams(), m_custom_data_config, &dm->ldata, CD_MLOOPCOL);
}
}
}
-void AbcMeshWriter::getVelocities(DerivedMesh *dm, std::vector<Imath::V3f> &vels)
+void AbcMeshWriter::getVelocities(struct Mesh *mesh, std::vector<Imath::V3f> &vels)
{
- const int totverts = dm->getNumVerts(dm);
+ const int totverts = mesh->totvert;
vels.clear();
vels.resize(totverts);
- ModifierData *md = get_liquid_sim_modifier(m_scene, m_object);
+ ModifierData *md = get_liquid_sim_modifier(m_settings.scene, m_object);
FluidsimModifierData *fmd = reinterpret_cast<FluidsimModifierData *>(md);
FluidsimSettings *fss = fmd->fss;
@@ -605,11 +606,11 @@ void AbcMeshWriter::getVelocities(DerivedMesh *dm, std::vector<Imath::V3f> &vels
}
void AbcMeshWriter::getGeoGroups(
- DerivedMesh *dm,
+ struct Mesh *mesh,
std::map<std::string, std::vector<int32_t> > &geo_groups)
{
- const int num_poly = dm->getNumPolys(dm);
- MPoly *polygons = dm->getPolyArray(dm);
+ const int num_poly = mesh->totpoly;
+ MPoly *polygons = mesh->mpoly;
for (int i = 0; i < num_poly; ++i) {
MPoly &current_poly = polygons[i];
@@ -638,7 +639,7 @@ void AbcMeshWriter::getGeoGroups(
std::vector<int32_t> faceArray;
- for (int i = 0, e = dm->getNumTessFaces(dm); i < e; ++i) {
+ for (int i = 0, e = mesh->totface; i < e; ++i) {
faceArray.push_back(i);
}
@@ -873,11 +874,11 @@ ABC_INLINE void read_normals_params(AbcMeshData &abc_data,
}
}
-static bool check_smooth_poly_flag(DerivedMesh *dm)
+static bool check_smooth_poly_flag(Mesh *mesh)
{
- MPoly *mpolys = dm->getPolyArray(dm);
+ MPoly *mpolys = mesh->mpoly;
- for (int i = 0, e = dm->getNumPolys(dm); i < e; ++i) {
+ for (int i = 0, e = mesh->totpoly; i < e; ++i) {
MPoly &poly = mpolys[i];
if ((poly.flag & ME_SMOOTH) != 0) {
@@ -888,11 +889,11 @@ static bool check_smooth_poly_flag(DerivedMesh *dm)
return false;
}
-static void set_smooth_poly_flag(DerivedMesh *dm)
+static void set_smooth_poly_flag(Mesh *mesh)
{
- MPoly *mpolys = dm->getPolyArray(dm);
+ MPoly *mpolys = mesh->mpoly;
- for (int i = 0, e = dm->getNumPolys(dm); i < e; ++i) {
+ for (int i = 0, e = mesh->totpoly; i < e; ++i) {
MPoly &poly = mpolys[i];
poly.flag |= ME_SMOOTH;
}
@@ -900,7 +901,7 @@ static void set_smooth_poly_flag(DerivedMesh *dm)
static void *add_customdata_cb(void *user_data, const char *name, int data_type)
{
- DerivedMesh *dm = static_cast<DerivedMesh *>(user_data);
+ Mesh *mesh = static_cast<Mesh *>(user_data);
CustomDataType cd_data_type = static_cast<CustomDataType>(data_type);
void *cd_ptr;
CustomData *loopdata;
@@ -911,7 +912,7 @@ static void *add_customdata_cb(void *user_data, const char *name, int data_type)
return NULL;
}
- loopdata = dm->getLoopDataLayout(dm);
+ loopdata = &mesh->ldata;
cd_ptr = CustomData_get_layer_named(loopdata, cd_data_type, name);
if (cd_ptr != NULL) {
/* layer already exists, so just return it. */
@@ -920,7 +921,7 @@ static void *add_customdata_cb(void *user_data, const char *name, int data_type)
/* create a new layer, taking care to construct the hopefully-soon-to-be-removed
* CD_MTEXPOLY layer too, with the same name. */
- numloops = dm->getNumLoops(dm);
+ numloops = mesh->totloop;
cd_ptr = CustomData_add_layer_named(loopdata, cd_data_type, CD_DEFAULT,
NULL, numloops, name);
return cd_ptr;
@@ -986,17 +987,19 @@ static void read_mesh_sample(const std::string & iobject_full_name,
}
}
-CDStreamConfig get_config(DerivedMesh *dm)
+CDStreamConfig get_config(Mesh *mesh)
{
CDStreamConfig config;
- config.user_data = dm;
- config.mvert = dm->getVertArray(dm);
- config.mloop = dm->getLoopArray(dm);
- config.mpoly = dm->getPolyArray(dm);
- config.totloop = dm->getNumLoops(dm);
- config.totpoly = dm->getNumPolys(dm);
- config.loopdata = dm->getLoopDataLayout(dm);
+ BLI_assert(mesh->mvert);
+
+ config.user_data = mesh;
+ config.mvert = mesh->mvert;
+ config.mloop = mesh->mloop;
+ config.mpoly = mesh->mpoly;
+ config.totloop = mesh->totloop;
+ config.totpoly = mesh->totpoly;
+ config.loopdata = &mesh->ldata;
config.add_customdata_cb = add_customdata_cb;
return config;
@@ -1027,14 +1030,8 @@ void AbcMeshReader::readObjectData(Main *bmain, const Alembic::Abc::ISampleSelec
m_object = BKE_object_add_only_object(bmain, OB_MESH, m_object_name.c_str());
m_object->data = mesh;
- DerivedMesh *dm = CDDM_from_mesh(mesh);
- DerivedMesh *ndm = this->read_derivedmesh(dm, sample_sel, MOD_MESHSEQ_READ_ALL, NULL);
-
- if (ndm != dm) {
- dm->release(dm);
- }
-
- DM_to_mesh(ndm, mesh, m_object, CD_MASK_MESH, true);
+ Mesh *read_mesh = this->read_mesh(mesh, sample_sel, MOD_MESHSEQ_READ_ALL, NULL);
+ BKE_mesh_nomain_to_mesh(read_mesh, mesh, m_object, CD_MASK_MESH, true);
if (m_settings->validate_meshes) {
BKE_mesh_validate(mesh, false, false);
@@ -1064,33 +1061,45 @@ bool AbcMeshReader::accepts_object_type(const Alembic::AbcCoreAbstract::ObjectHe
return true;
}
-DerivedMesh *AbcMeshReader::read_derivedmesh(DerivedMesh *dm,
- const ISampleSelector &sample_sel,
- int read_flag,
- const char **err_str)
+Mesh *AbcMeshReader::read_mesh(Mesh *existing_mesh,
+ const ISampleSelector &sample_sel,
+ int read_flag,
+ const char **err_str)
{
- const IPolyMeshSchema::Sample sample = m_schema.getValue(sample_sel);
+ IPolyMeshSchema::Sample sample;
+ try {
+ sample = m_schema.getValue(sample_sel);
+ }
+ catch(Alembic::Util::Exception &ex) {
+ *err_str = "Error reading mesh sample; more detail on the console";
+ printf("Alembic: error reading mesh sample for '%s/%s' at time %f: %s\n",
+ m_iobject.getFullName().c_str(),
+ m_schema.getName().c_str(),
+ sample_sel.getRequestedTime(),
+ ex.what());
+ return existing_mesh;
+ }
const P3fArraySamplePtr &positions = sample.getPositions();
const Alembic::Abc::Int32ArraySamplePtr &face_indices = sample.getFaceIndices();
const Alembic::Abc::Int32ArraySamplePtr &face_counts = sample.getFaceCounts();
- DerivedMesh *new_dm = NULL;
+ Mesh *new_mesh = NULL;
/* Only read point data when streaming meshes, unless we need to create new ones. */
ImportSettings settings;
settings.read_flag |= read_flag;
- bool topology_changed = positions->size() != dm->getNumVerts(dm) ||
- face_counts->size() != dm->getNumPolys(dm) ||
- face_indices->size() != dm->getNumLoops(dm);
+ bool topology_changed = positions->size() != existing_mesh->totvert ||
+ face_counts->size() != existing_mesh->totpoly ||
+ face_indices->size() != existing_mesh->totloop;
if (topology_changed) {
- new_dm = CDDM_from_template(dm,
- positions->size(),
- 0,
- 0,
- face_indices->size(),
- face_counts->size());
+ new_mesh = BKE_mesh_new_nomain_from_template(existing_mesh,
+ positions->size(),
+ 0,
+ 0,
+ face_indices->size(),
+ face_counts->size());
settings.read_flag |= MOD_MESHSEQ_READ_ALL;
}
@@ -1098,8 +1107,8 @@ DerivedMesh *AbcMeshReader::read_derivedmesh(DerivedMesh *dm,
/* If the face count changed (e.g. by triangulation), only read points.
* This prevents crash from T49813.
* TODO(kevin): perhaps find a better way to do this? */
- if (face_counts->size() != dm->getNumPolys(dm) ||
- face_indices->size() != dm->getNumLoops(dm))
+ if (face_counts->size() != existing_mesh->totpoly ||
+ face_indices->size() != existing_mesh->totloop)
{
settings.read_flag = MOD_MESHSEQ_READ_VERT;
@@ -1110,40 +1119,39 @@ DerivedMesh *AbcMeshReader::read_derivedmesh(DerivedMesh *dm,
}
}
- CDStreamConfig config = get_config(new_dm ? new_dm : dm);
+ CDStreamConfig config = get_config(new_mesh ? new_mesh : existing_mesh);
config.time = sample_sel.getRequestedTime();
bool do_normals = false;
read_mesh_sample(m_iobject.getFullName(),
&settings, m_schema, sample_sel, config, do_normals);
- if (new_dm) {
+ if (new_mesh) {
/* Check if we had ME_SMOOTH flag set to restore it. */
- if (!do_normals && check_smooth_poly_flag(dm)) {
- set_smooth_poly_flag(new_dm);
+ if (!do_normals && check_smooth_poly_flag(existing_mesh)) {
+ set_smooth_poly_flag(new_mesh);
}
- CDDM_calc_normals(new_dm);
- CDDM_calc_edges(new_dm);
+ BKE_mesh_calc_normals(new_mesh);
+ BKE_mesh_calc_edges(new_mesh, false, false);
/* Here we assume that the number of materials doesn't change, i.e. that
* the material slots that were created when the object was loaded from
* Alembic are still valid now. */
- size_t num_polys = new_dm->getNumPolys(new_dm);
+ size_t num_polys = new_mesh->totpoly;
if (num_polys > 0) {
- MPoly *dmpolies = new_dm->getPolyArray(new_dm);
std::map<std::string, int> mat_map;
- assign_facesets_to_mpoly(sample_sel, 0, dmpolies, num_polys, mat_map);
+ assign_facesets_to_mpoly(sample_sel, 0, new_mesh->mpoly, num_polys, mat_map);
}
- return new_dm;
+ return new_mesh;
}
if (do_normals) {
- CDDM_calc_normals(dm);
+ BKE_mesh_calc_normals(existing_mesh);
}
- return dm;
+ return existing_mesh;
}
void AbcMeshReader::assign_facesets_to_mpoly(
@@ -1305,16 +1313,22 @@ void AbcSubDReader::readObjectData(Main *bmain, const Alembic::Abc::ISampleSelec
m_object = BKE_object_add_only_object(bmain, OB_MESH, m_object_name.c_str());
m_object->data = mesh;
- DerivedMesh *dm = CDDM_from_mesh(mesh);
- DerivedMesh *ndm = this->read_derivedmesh(dm, sample_sel, MOD_MESHSEQ_READ_ALL, NULL);
+ Mesh *read_mesh = this->read_mesh(mesh, sample_sel, MOD_MESHSEQ_READ_ALL, NULL);
+ BKE_mesh_nomain_to_mesh(read_mesh, mesh, m_object, CD_MASK_MESH, true);
- if (ndm != dm) {
- dm->release(dm);
+ ISubDSchema::Sample sample;
+ try {
+ sample = m_schema.getValue(sample_sel);
+ }
+ catch(Alembic::Util::Exception &ex) {
+ printf("Alembic: error reading mesh sample for '%s/%s' at time %f: %s\n",
+ m_iobject.getFullName().c_str(),
+ m_schema.getName().c_str(),
+ sample_sel.getRequestedTime(),
+ ex.what());
+ return;
}
- DM_to_mesh(ndm, mesh, m_object, CD_MASK_MESH, true);
-
- const ISubDSchema::Sample sample = m_schema.getValue(sample_sel);
Int32ArraySamplePtr indices = sample.getCreaseIndices();
Alembic::Abc::FloatArraySamplePtr sharpnesses = sample.getCreaseSharpnesses();
@@ -1344,29 +1358,41 @@ void AbcSubDReader::readObjectData(Main *bmain, const Alembic::Abc::ISampleSelec
}
}
-DerivedMesh *AbcSubDReader::read_derivedmesh(DerivedMesh *dm,
- const ISampleSelector &sample_sel,
- int read_flag,
- const char **err_str)
+Mesh *AbcSubDReader::read_mesh(Mesh *existing_mesh,
+ const ISampleSelector &sample_sel,
+ int read_flag,
+ const char **err_str)
{
- const ISubDSchema::Sample sample = m_schema.getValue(sample_sel);
+ ISubDSchema::Sample sample;
+ try {
+ sample = m_schema.getValue(sample_sel);
+ }
+ catch(Alembic::Util::Exception &ex) {
+ *err_str = "Error reading mesh sample; more detail on the console";
+ printf("Alembic: error reading mesh sample for '%s/%s' at time %f: %s\n",
+ m_iobject.getFullName().c_str(),
+ m_schema.getName().c_str(),
+ sample_sel.getRequestedTime(),
+ ex.what());
+ return existing_mesh;
+ }
const P3fArraySamplePtr &positions = sample.getPositions();
const Alembic::Abc::Int32ArraySamplePtr &face_indices = sample.getFaceIndices();
const Alembic::Abc::Int32ArraySamplePtr &face_counts = sample.getFaceCounts();
- DerivedMesh *new_dm = NULL;
+ Mesh *new_mesh = NULL;
ImportSettings settings;
settings.read_flag |= read_flag;
- if (dm->getNumVerts(dm) != positions->size()) {
- new_dm = CDDM_from_template(dm,
- positions->size(),
- 0,
- 0,
- face_indices->size(),
- face_counts->size());
+ if (existing_mesh->totvert != positions->size()) {
+ new_mesh = BKE_mesh_new_nomain_from_template(existing_mesh,
+ positions->size(),
+ 0,
+ 0,
+ face_indices->size(),
+ face_counts->size());
settings.read_flag |= MOD_MESHSEQ_READ_ALL;
}
@@ -1374,8 +1400,8 @@ DerivedMesh *AbcSubDReader::read_derivedmesh(DerivedMesh *dm,
/* If the face count changed (e.g. by triangulation), only read points.
* This prevents crash from T49813.
* TODO(kevin): perhaps find a better way to do this? */
- if (face_counts->size() != dm->getNumPolys(dm) ||
- face_indices->size() != dm->getNumLoops(dm))
+ if (face_counts->size() != existing_mesh->totpoly ||
+ face_indices->size() != existing_mesh->totpoly)
{
settings.read_flag = MOD_MESHSEQ_READ_VERT;
@@ -1387,22 +1413,22 @@ DerivedMesh *AbcSubDReader::read_derivedmesh(DerivedMesh *dm,
}
/* Only read point data when streaming meshes, unless we need to create new ones. */
- CDStreamConfig config = get_config(new_dm ? new_dm : dm);
+ CDStreamConfig config = get_config(new_mesh ? new_mesh : existing_mesh);
config.time = sample_sel.getRequestedTime();
read_subd_sample(m_iobject.getFullName(),
&settings, m_schema, sample_sel, config);
- if (new_dm) {
+ if (new_mesh) {
/* Check if we had ME_SMOOTH flag set to restore it. */
- if (check_smooth_poly_flag(dm)) {
- set_smooth_poly_flag(new_dm);
+ if (check_smooth_poly_flag(existing_mesh)) {
+ set_smooth_poly_flag(new_mesh);
}
- CDDM_calc_normals(new_dm);
- CDDM_calc_edges(new_dm);
+ BKE_mesh_calc_normals(new_mesh);
+ BKE_mesh_calc_edges(new_mesh, false, false);
- return new_dm;
+ return new_mesh;
}
- return dm;
+ return existing_mesh;
}
diff --git a/source/blender/alembic/intern/abc_mesh.h b/source/blender/alembic/intern/abc_mesh.h
index c57123cda4c..e1507bedd01 100644
--- a/source/blender/alembic/intern/abc_mesh.h
+++ b/source/blender/alembic/intern/abc_mesh.h
@@ -26,7 +26,6 @@
#include "abc_customdata.h"
#include "abc_object.h"
-struct DerivedMesh;
struct Mesh;
struct ModifierData;
@@ -50,9 +49,7 @@ class AbcMeshWriter : public AbcObjectWriter {
bool m_is_subd;
public:
- AbcMeshWriter(Depsgraph *depsgraph,
- Scene *scene,
- Object *ob,
+ AbcMeshWriter(Object *ob,
AbcTransformWriter *parent,
uint32_t time_sampling,
ExportSettings &settings);
@@ -65,29 +62,28 @@ private:
bool isAnimated() const;
- void writeMesh(DerivedMesh *dm);
- void writeSubD(DerivedMesh *dm);
+ void writeMesh(struct Mesh *mesh);
+ void writeSubD(struct Mesh *mesh);
- void getMeshInfo(DerivedMesh *dm, std::vector<float> &points,
+ void getMeshInfo(struct Mesh *mesh, std::vector<float> &points,
std::vector<int32_t> &facePoints,
std::vector<int32_t> &faceCounts,
std::vector<int32_t> &creaseIndices,
std::vector<int32_t> &creaseLengths,
std::vector<float> &creaseSharpness);
- DerivedMesh *getFinalMesh();
- void freeMesh(DerivedMesh *dm);
+ struct Mesh *getFinalMesh(bool &r_needsfree);
- void getMaterialIndices(DerivedMesh *dm, std::vector<int32_t> &indices);
+ void getMaterialIndices(struct Mesh *mesh, std::vector<int32_t> &indices);
- void writeArbGeoParams(DerivedMesh *dm);
- void getGeoGroups(DerivedMesh *dm, std::map<std::string, std::vector<int32_t> > &geoGroups);
+ void writeArbGeoParams(struct Mesh *mesh);
+ void getGeoGroups(struct Mesh *mesh, std::map<std::string, std::vector<int32_t> > &geoGroups);
/* fluid surfaces support */
- void getVelocities(DerivedMesh *dm, std::vector<Imath::V3f> &vels);
+ void getVelocities(struct Mesh *mesh, std::vector<Imath::V3f> &vels);
template <typename Schema>
- void writeFaceSets(DerivedMesh *dm, Schema &schema);
+ void writeFaceSets(struct Mesh *mesh, Schema &schema);
};
/* ************************************************************************** */
@@ -106,10 +102,10 @@ public:
const char **err_str) const;
void readObjectData(Main *bmain, const Alembic::Abc::ISampleSelector &sample_sel);
- DerivedMesh *read_derivedmesh(DerivedMesh *dm,
- const Alembic::Abc::ISampleSelector &sample_sel,
- int read_flag,
- const char **err_str);
+ struct Mesh *read_mesh(struct Mesh *existing_mesh,
+ const Alembic::Abc::ISampleSelector &sample_sel,
+ int read_flag,
+ const char **err_str);
private:
void readFaceSetsSample(Main *bmain, Mesh *mesh, size_t poly_start,
@@ -136,10 +132,10 @@ public:
const Object *const ob,
const char **err_str) const;
void readObjectData(Main *bmain, const Alembic::Abc::ISampleSelector &sample_sel);
- DerivedMesh *read_derivedmesh(DerivedMesh *dm,
- const Alembic::Abc::ISampleSelector &sample_sel,
- int read_flag,
- const char **err_str);
+ struct Mesh *read_mesh(struct Mesh *existing_mesh,
+ const Alembic::Abc::ISampleSelector &sample_sel,
+ int read_flag,
+ const char **err_str);
};
/* ************************************************************************** */
@@ -148,6 +144,6 @@ void read_mverts(MVert *mverts,
const Alembic::AbcGeom::P3fArraySamplePtr &positions,
const Alembic::AbcGeom::N3fArraySamplePtr &normals);
-CDStreamConfig get_config(DerivedMesh *dm);
+CDStreamConfig get_config(struct Mesh *mesh);
#endif /* __ABC_MESH_H__ */
diff --git a/source/blender/alembic/intern/abc_nurbs.cc b/source/blender/alembic/intern/abc_nurbs.cc
index 1f042d0bafc..95d06fc5efe 100644
--- a/source/blender/alembic/intern/abc_nurbs.cc
+++ b/source/blender/alembic/intern/abc_nurbs.cc
@@ -60,13 +60,11 @@ using Alembic::AbcGeom::ONuPatchSchema;
/* ************************************************************************** */
-AbcNurbsWriter::AbcNurbsWriter(Depsgraph *depsgraph,
- Scene *scene,
- Object *ob,
+AbcNurbsWriter::AbcNurbsWriter(Object *ob,
AbcTransformWriter *parent,
uint32_t time_sampling,
ExportSettings &settings)
- : AbcObjectWriter(depsgraph, scene, ob, time_sampling, settings, parent)
+ : AbcObjectWriter(ob, time_sampling, settings, parent)
{
m_is_animated = isAnimated();
@@ -255,7 +253,19 @@ void AbcNurbsReader::readObjectData(Main *bmain, const Alembic::Abc::ISampleSele
nu->resolv = cu->resolv;
const INuPatchSchema &schema = it->first;
- const INuPatchSchema::Sample smp = schema.getValue(sample_sel);
+ INuPatchSchema::Sample smp;
+ try {
+ smp = schema.getValue(sample_sel);
+ }
+ catch(Alembic::Util::Exception &ex) {
+ printf("Alembic: error reading nurbs sample for '%s/%s' at time %f: %s\n",
+ m_iobject.getFullName().c_str(),
+ schema.getName().c_str(),
+ sample_sel.getRequestedTime(),
+ ex.what());
+ return;
+ }
+
nu->orderu = smp.getUOrder() - 1;
nu->orderv = smp.getVOrder() - 1;
diff --git a/source/blender/alembic/intern/abc_nurbs.h b/source/blender/alembic/intern/abc_nurbs.h
index d2422345c3f..827aa4b365f 100644
--- a/source/blender/alembic/intern/abc_nurbs.h
+++ b/source/blender/alembic/intern/abc_nurbs.h
@@ -32,9 +32,7 @@ class AbcNurbsWriter : public AbcObjectWriter {
bool m_is_animated;
public:
- AbcNurbsWriter(Depsgraph *depsgraph,
- Scene *scene,
- Object *ob,
+ AbcNurbsWriter(Object *ob,
AbcTransformWriter *parent,
uint32_t time_sampling,
ExportSettings &settings);
diff --git a/source/blender/alembic/intern/abc_object.cc b/source/blender/alembic/intern/abc_object.cc
index 85bda9aa8eb..7e0b1ccfbd4 100644
--- a/source/blender/alembic/intern/abc_object.cc
+++ b/source/blender/alembic/intern/abc_object.cc
@@ -58,16 +58,12 @@ using Alembic::AbcGeom::OStringProperty;
/* ************************************************************************** */
-AbcObjectWriter::AbcObjectWriter(Depsgraph *depsgraph,
- Scene *scene,
- Object *ob,
+AbcObjectWriter::AbcObjectWriter(Object *ob,
uint32_t time_sampling,
ExportSettings &settings,
AbcObjectWriter *parent)
: m_object(ob)
, m_settings(settings)
- , m_depsgraph(depsgraph)
- , m_scene(scene)
, m_time_sampling(time_sampling)
, m_first_frame(true)
{
@@ -248,12 +244,12 @@ Imath::M44d get_matrix(const IXformSchema &schema, const float time)
return s0.getMatrix();
}
-DerivedMesh *AbcObjectReader::read_derivedmesh(DerivedMesh *dm,
- const Alembic::Abc::ISampleSelector &UNUSED(sample_sel),
- int UNUSED(read_flag),
- const char **UNUSED(err_str))
+struct Mesh *AbcObjectReader::read_mesh(struct Mesh *existing_mesh,
+ const Alembic::Abc::ISampleSelector &UNUSED(sample_sel),
+ int UNUSED(read_flag),
+ const char **UNUSED(err_str))
{
- return dm;
+ return existing_mesh;
}
void AbcObjectReader::setupObjectTransform(const float time)
diff --git a/source/blender/alembic/intern/abc_object.h b/source/blender/alembic/intern/abc_object.h
index d41088bdcad..8794cb61708 100644
--- a/source/blender/alembic/intern/abc_object.h
+++ b/source/blender/alembic/intern/abc_object.h
@@ -44,8 +44,6 @@ protected:
Object *m_object;
ExportSettings &m_settings;
- Depsgraph *m_depsgraph;
- Scene *m_scene;
uint32_t m_time_sampling;
Imath::Box3d m_bounds;
@@ -57,9 +55,7 @@ protected:
std::string m_name;
public:
- AbcObjectWriter(Depsgraph *depsgraph,
- Scene *scene,
- Object *ob,
+ AbcObjectWriter(Object *ob,
uint32_t time_sampling,
ExportSettings &settings,
AbcObjectWriter *parent = NULL);
@@ -124,7 +120,7 @@ static bool has_animations(Schema &schema, ImportSettings *settings)
/* ************************************************************************** */
-struct DerivedMesh;
+struct Mesh;
using Alembic::AbcCoreAbstract::chrono_t;
@@ -180,10 +176,10 @@ public:
virtual void readObjectData(Main *bmain, const Alembic::Abc::ISampleSelector &sample_sel) = 0;
- virtual DerivedMesh *read_derivedmesh(DerivedMesh *dm,
- const Alembic::Abc::ISampleSelector &sample_sel,
- int read_flag,
- const char **err_str);
+ virtual struct Mesh *read_mesh(struct Mesh *mesh,
+ const Alembic::Abc::ISampleSelector &sample_sel,
+ int read_flag,
+ const char **err_str);
/** Reads the object matrix and sets up an object transform if animated. */
void setupObjectTransform(const float time);
diff --git a/source/blender/alembic/intern/abc_points.cc b/source/blender/alembic/intern/abc_points.cc
index 6f52ccec4a7..9ff995ffcbf 100644
--- a/source/blender/alembic/intern/abc_points.cc
+++ b/source/blender/alembic/intern/abc_points.cc
@@ -40,6 +40,8 @@ extern "C" {
#include "BKE_scene.h"
#include "BLI_math.h"
+
+#include "DEG_depsgraph_query.h"
}
using Alembic::AbcGeom::kVertexScope;
@@ -58,14 +60,12 @@ using Alembic::AbcGeom::OPointsSchema;
/* ************************************************************************** */
-AbcPointsWriter::AbcPointsWriter(Depsgraph *depsgraph,
- Scene *scene,
- Object *ob,
+AbcPointsWriter::AbcPointsWriter(Object *ob,
AbcTransformWriter *parent,
uint32_t time_sampling,
ExportSettings &settings,
ParticleSystem *psys)
- : AbcObjectWriter(depsgraph, scene, ob, time_sampling, settings, parent)
+ : AbcObjectWriter(ob, time_sampling, settings, parent)
{
m_psys = psys;
@@ -87,8 +87,8 @@ void AbcPointsWriter::do_write()
ParticleKey state;
ParticleSimulationData sim;
- sim.depsgraph = m_depsgraph;
- sim.scene = m_scene;
+ sim.depsgraph = m_settings.depsgraph;
+ sim.scene = m_settings.scene;
sim.ob = m_object;
sim.psys = m_psys;
@@ -102,7 +102,7 @@ void AbcPointsWriter::do_write()
continue;
}
- state.time = BKE_scene_frame_get(m_scene);
+ state.time = DEG_get_ctime(m_settings.depsgraph);
if (psys_get_particle_state(&sim, p, &state, 0) == 0) {
continue;
@@ -173,15 +173,9 @@ bool AbcPointsReader::accepts_object_type(const Alembic::AbcCoreAbstract::Object
void AbcPointsReader::readObjectData(Main *bmain, const Alembic::Abc::ISampleSelector &sample_sel)
{
Mesh *mesh = BKE_mesh_add(bmain, m_data_name.c_str());
+ Mesh *read_mesh = this->read_mesh(mesh, sample_sel, 0, NULL);
- DerivedMesh *dm = CDDM_from_mesh(mesh);
- DerivedMesh *ndm = this->read_derivedmesh(dm, sample_sel, 0, NULL);
-
- if (ndm != dm) {
- dm->release(dm);
- }
-
- DM_to_mesh(ndm, mesh, m_object, CD_MASK_MESH, true);
+ BKE_mesh_nomain_to_mesh(read_mesh, mesh, m_object, CD_MASK_MESH, true);
if (m_settings->validate_meshes) {
BKE_mesh_validate(mesh, false, false);
@@ -218,23 +212,35 @@ void read_points_sample(const IPointsSchema &schema,
read_mverts(config.mvert, positions, vnormals);
}
-DerivedMesh *AbcPointsReader::read_derivedmesh(DerivedMesh *dm,
- const ISampleSelector &sample_sel,
- int /*read_flag*/,
- const char ** /*err_str*/)
+struct Mesh *AbcPointsReader::read_mesh(struct Mesh *existing_mesh,
+ const ISampleSelector &sample_sel,
+ int /*read_flag*/,
+ const char **err_str)
{
- const IPointsSchema::Sample sample = m_schema.getValue(sample_sel);
+ IPointsSchema::Sample sample;
+ try {
+ sample = m_schema.getValue(sample_sel);
+ }
+ catch(Alembic::Util::Exception &ex) {
+ *err_str = "Error reading points sample; more detail on the console";
+ printf("Alembic: error reading points sample for '%s/%s' at time %f: %s\n",
+ m_iobject.getFullName().c_str(),
+ m_schema.getName().c_str(),
+ sample_sel.getRequestedTime(),
+ ex.what());
+ return existing_mesh;
+ }
const P3fArraySamplePtr &positions = sample.getPositions();
- DerivedMesh *new_dm = NULL;
+ Mesh *new_mesh = NULL;
- if (dm->getNumVerts(dm) != positions->size()) {
- new_dm = CDDM_new(positions->size(), 0, 0, 0, 0);
+ if (existing_mesh->totvert != positions->size()) {
+ new_mesh = BKE_mesh_new_nomain(positions->size(), 0, 0, 0, 0);
}
- CDStreamConfig config = get_config(new_dm ? new_dm : dm);
+ CDStreamConfig config = get_config(new_mesh ? new_mesh : existing_mesh);
read_points_sample(m_schema, sample_sel, config);
- return new_dm ? new_dm : dm;
+ return new_mesh ? new_mesh : existing_mesh;
}
diff --git a/source/blender/alembic/intern/abc_points.h b/source/blender/alembic/intern/abc_points.h
index 1ac8792ede1..e986f9448f4 100644
--- a/source/blender/alembic/intern/abc_points.h
+++ b/source/blender/alembic/intern/abc_points.h
@@ -38,9 +38,7 @@ class AbcPointsWriter : public AbcObjectWriter {
ParticleSystem *m_psys;
public:
- AbcPointsWriter(Depsgraph *depsgraph,
- Scene *scene,
- Object *ob,
+ AbcPointsWriter(Object *ob,
AbcTransformWriter *parent,
uint32_t time_sampling,
ExportSettings &settings,
@@ -65,10 +63,10 @@ public:
void readObjectData(Main *bmain, const Alembic::Abc::ISampleSelector &sample_sel);
- DerivedMesh *read_derivedmesh(DerivedMesh *dm,
- const Alembic::Abc::ISampleSelector &sample_sel,
- int read_flag,
- const char **err_str);
+ struct Mesh *read_mesh(struct Mesh *existing_mesh,
+ const Alembic::Abc::ISampleSelector &sample_sel,
+ int read_flag,
+ const char **err_str);
};
void read_points_sample(const Alembic::AbcGeom::IPointsSchema &schema,
diff --git a/source/blender/alembic/intern/abc_transform.cc b/source/blender/alembic/intern/abc_transform.cc
index e5da367b9a9..81ebfef3e11 100644
--- a/source/blender/alembic/intern/abc_transform.cc
+++ b/source/blender/alembic/intern/abc_transform.cc
@@ -32,6 +32,8 @@ extern "C" {
#include "BLI_math.h"
#include "BKE_object.h"
+
+#include "DEG_depsgraph_query.h"
}
using Alembic::AbcGeom::OObject;
@@ -57,13 +59,12 @@ static bool has_parent_camera(Object *ob)
/* ************************************************************************** */
-AbcTransformWriter::AbcTransformWriter(Depsgraph *depsgraph,
- Object *ob,
+AbcTransformWriter::AbcTransformWriter(Object *ob,
const OObject &abc_parent,
AbcTransformWriter *parent,
unsigned int time_sampling,
ExportSettings &settings)
- : AbcObjectWriter(depsgraph, NULL, ob, time_sampling, settings, parent)
+ : AbcObjectWriter(ob, time_sampling, settings, parent)
, m_proxy_from(NULL)
{
m_is_animated = hasAnimation(m_object);
@@ -81,29 +82,31 @@ AbcTransformWriter::AbcTransformWriter(Depsgraph *depsgraph,
void AbcTransformWriter::do_write()
{
+ Object *ob_eval = DEG_get_evaluated_object(m_settings.depsgraph, m_object);
+
if (m_first_frame) {
m_visibility = Alembic::AbcGeom::CreateVisibilityProperty(m_xform, m_xform.getSchema().getTimeSampling());
}
- m_visibility.set(!(m_object->restrictflag & OB_RESTRICT_VIEW));
+ m_visibility.set(!(ob_eval->restrictflag & OB_RESTRICT_VIEW));
if (!m_first_frame && !m_is_animated) {
return;
}
float yup_mat[4][4];
- create_transform_matrix(m_object, yup_mat,
+ create_transform_matrix(ob_eval, yup_mat,
m_inherits_xform ? ABC_MATRIX_LOCAL : ABC_MATRIX_WORLD,
m_proxy_from);
/* Only apply rotation to root camera, parenting will propagate it. */
- if (m_object->type == OB_CAMERA && (!m_inherits_xform || !has_parent_camera(m_object))) {
+ if (ob_eval->type == OB_CAMERA && (!m_inherits_xform || !has_parent_camera(ob_eval))) {
float rot_mat[4][4];
axis_angle_to_mat4_single(rot_mat, 'X', -M_PI_2);
mul_m4_m4m4(yup_mat, yup_mat, rot_mat);
}
- if (!m_object->parent || !m_inherits_xform) {
+ if (!ob_eval->parent || !m_inherits_xform) {
/* Only apply scaling to root objects, parenting will propagate it. */
float scale_mat[4][4];
scale_m4_fl(scale_mat, m_settings.global_scale);
diff --git a/source/blender/alembic/intern/abc_transform.h b/source/blender/alembic/intern/abc_transform.h
index 91420b28f93..12bf9d38007 100644
--- a/source/blender/alembic/intern/abc_transform.h
+++ b/source/blender/alembic/intern/abc_transform.h
@@ -43,8 +43,7 @@ public:
Object *m_proxy_from;
public:
- AbcTransformWriter(Depsgraph *depsgraph,
- Object *ob,
+ AbcTransformWriter(Object *ob,
const Alembic::AbcGeom::OObject &abc_parent,
AbcTransformWriter *parent,
unsigned int time_sampling,
diff --git a/source/blender/alembic/intern/abc_util.cc b/source/blender/alembic/intern/abc_util.cc
index 6787d118fa1..53860ab149d 100644
--- a/source/blender/alembic/intern/abc_util.cc
+++ b/source/blender/alembic/intern/abc_util.cc
@@ -181,11 +181,11 @@ void copy_m44_axis_swap(float dst_mat[4][4], float src_mat[4][4], AbcAxisSwapMod
unit_m3(dst_rot);
unit_m4(dst_scale_mat);
- /* We assume there is no sheer component and no homogeneous scaling component. */
- BLI_assert(fabs(src_mat[0][3]) < 2 * FLT_EPSILON);
- BLI_assert(fabs(src_mat[1][3]) < 2 * FLT_EPSILON);
- BLI_assert(fabs(src_mat[2][3]) < 2 * FLT_EPSILON);
- BLI_assert(fabs(src_mat[3][3] - 1.0f) < 2 * FLT_EPSILON);
+ /* TODO(Sybren): This code assumes there is no sheer component and no
+ * homogeneous scaling component, which is not always true when writing
+ * non-hierarchical (e.g. flat) objects (e.g. when parent has non-uniform
+ * scale and the child rotates). This is currently not taken into account
+ * when axis-swapping. */
/* Extract translation, rotation, and scale form matrix. */
mat4_to_loc_rot_size(src_trans, src_rot, src_scale, src_mat);
diff --git a/source/blender/alembic/intern/alembic_capi.cc b/source/blender/alembic/intern/alembic_capi.cc
index 1a6990a1de8..cc9923189c7 100644
--- a/source/blender/alembic/intern/alembic_capi.cc
+++ b/source/blender/alembic/intern/alembic_capi.cc
@@ -230,9 +230,7 @@ static void find_iobject(const IObject &object, IObject &ret,
}
struct ExportJobData {
- Scene *scene;
ViewLayer *view_layer;
- Depsgraph *depsgraph;
Main *bmain;
char filename[1024];
@@ -262,10 +260,16 @@ static void export_startjob(void *customdata, short *stop, short *do_update, flo
G.is_break = false;
+ DEG_graph_build_from_view_layer(data->settings.depsgraph,
+ data->bmain,
+ data->settings.scene,
+ data->view_layer);
+ BKE_scene_graph_update_tagged(data->settings.depsgraph, data->bmain);
+
try {
- Scene *scene = data->scene;
- AbcExporter exporter(data->bmain, scene, data->depsgraph, data->filename, data->settings);
+ AbcExporter exporter(data->bmain, data->filename, data->settings);
+ Scene *scene = data->settings.scene; /* for the CFRA macro */
const int orig_frame = CFRA;
data->was_canceled = false;
@@ -274,7 +278,7 @@ static void export_startjob(void *customdata, short *stop, short *do_update, flo
if (CFRA != orig_frame) {
CFRA = orig_frame;
- BKE_scene_graph_update_for_newframe(data->depsgraph, data->bmain);
+ BKE_scene_graph_update_for_newframe(data->settings.depsgraph, data->bmain);
}
data->export_ok = !data->was_canceled;
@@ -313,9 +317,7 @@ bool ABC_export(
{
ExportJobData *job = static_cast<ExportJobData *>(MEM_mallocN(sizeof(ExportJobData), "ExportJobData"));
- job->scene = scene;
job->view_layer = CTX_data_view_layer(C);
- job->depsgraph = CTX_data_depsgraph(C);
job->bmain = CTX_data_main(C);
job->export_ok = false;
BLI_strncpy(job->filename, filepath, 1024);
@@ -336,14 +338,14 @@ bool ABC_export(
* do bigger refactor and maybe there is a better way which does not involve
* hardcore refactoring. */
new (&job->settings) ExportSettings();
- job->settings.scene = job->scene;
- job->settings.depsgraph = job->depsgraph;
+ job->settings.scene = scene;
+ job->settings.depsgraph = DEG_graph_new(scene, job->view_layer, DAG_EVAL_RENDER);
/* Sybren: for now we only export the active scene layer.
* Later in the 2.8 development process this may be replaced by using
* a specific collection for Alembic I/O, which can then be toggled
* between "real" objects and cached Alembic files. */
- job->settings.view_layer = CTX_data_view_layer(C);
+ job->settings.view_layer = job->view_layer;
job->settings.frame_start = params->frame_start;
job->settings.frame_end = params->frame_end;
@@ -387,7 +389,7 @@ bool ABC_export(
if (as_background_job) {
wmJob *wm_job = WM_jobs_get(CTX_wm_manager(C),
CTX_wm_window(C),
- job->scene,
+ job->settings.scene,
"Alembic Export",
WM_JOB_PROGRESS,
WM_JOB_TYPE_ALEMBIC);
@@ -960,12 +962,12 @@ void ABC_get_transform(CacheReader *reader, float r_mat[4][4], float time, float
/* ************************************************************************** */
-DerivedMesh *ABC_read_mesh(CacheReader *reader,
- Object *ob,
- DerivedMesh *dm,
- const float time,
- const char **err_str,
- int read_flag)
+Mesh *ABC_read_mesh(CacheReader *reader,
+ Object *ob,
+ Mesh *existing_mesh,
+ const float time,
+ const char **err_str,
+ int read_flag)
{
AbcObjectReader *abc_reader = reinterpret_cast<AbcObjectReader *>(reader);
IObject iobject = abc_reader->iobject();
@@ -984,7 +986,7 @@ DerivedMesh *ABC_read_mesh(CacheReader *reader,
/* kFloorIndex is used to be compatible with non-interpolating
* properties; they use the floor. */
ISampleSelector sample_sel(time, ISampleSelector::kFloorIndex);
- return abc_reader->read_derivedmesh(dm, sample_sel, read_flag, err_str);
+ return abc_reader->read_mesh(existing_mesh, sample_sel, read_flag, err_str);
}
/* ************************************************************************** */
diff --git a/source/blender/blenfont/intern/blf.c b/source/blender/blenfont/intern/blf.c
index fafee125264..5dd692d3855 100644
--- a/source/blender/blenfont/intern/blf.c
+++ b/source/blender/blenfont/intern/blf.c
@@ -172,7 +172,7 @@ static int blf_search_available(void)
for (i = 0; i < BLF_MAX_FONT; i++)
if (!global_font[i])
return i;
-
+
return -1;
}
diff --git a/source/blender/blenfont/intern/blf_dir.c b/source/blender/blenfont/intern/blf_dir.c
index d3349a10834..ff5c1151a82 100644
--- a/source/blender/blenfont/intern/blf_dir.c
+++ b/source/blender/blenfont/intern/blf_dir.c
@@ -61,7 +61,7 @@ static ListBase global_font_dir = { NULL, NULL };
static DirBLF *blf_dir_find(const char *path)
{
DirBLF *p;
-
+
p = global_font_dir.first;
while (p) {
if (BLI_path_cmp(p->path, path) == 0)
@@ -74,11 +74,11 @@ static DirBLF *blf_dir_find(const char *path)
void BLF_dir_add(const char *path)
{
DirBLF *dir;
-
+
dir = blf_dir_find(path);
if (dir) /* already in the list ? just return. */
return;
-
+
dir = (DirBLF *)MEM_callocN(sizeof(DirBLF), "BLF_dir_add");
dir->path = BLI_strdup(path);
BLI_addhead(&global_font_dir, dir);
@@ -87,7 +87,7 @@ void BLF_dir_add(const char *path)
void BLF_dir_rem(const char *path)
{
DirBLF *dir;
-
+
dir = blf_dir_find(path);
if (dir) {
BLI_remlink(&global_font_dir, dir);
@@ -102,11 +102,11 @@ char **BLF_dir_get(int *ndir)
char **dirs;
char *path;
int i, count;
-
+
count = BLI_listbase_count(&global_font_dir);
if (!count)
return NULL;
-
+
dirs = (char **)MEM_callocN(sizeof(char *) * count, "BLF_dir_get");
p = global_font_dir.first;
i = 0;
@@ -123,7 +123,7 @@ void BLF_dir_free(char **dirs, int count)
{
char *path;
int i;
-
+
for (i = 0; i < count; i++) {
path = dirs[i];
MEM_freeN(path);
@@ -159,7 +159,7 @@ int blf_dir_split(const char *str, char *file, int *size)
{
int i, len;
char *s;
-
+
/* Window, Linux or Mac, this is always / */
s = strrchr(str, '/');
if (s) {
diff --git a/source/blender/blenfont/intern/blf_font.c b/source/blender/blenfont/intern/blf_font.c
index c31aacb0a54..1289dc6c5a6 100644
--- a/source/blender/blenfont/intern/blf_font.c
+++ b/source/blender/blenfont/intern/blf_font.c
@@ -553,7 +553,7 @@ static void blf_font_draw_buffer_ex(
width_clip -= chx + width_clip - buf_info->w;
if (height_clip + pen_y > buf_info->h)
height_clip -= pen_y + height_clip - buf_info->h;
-
+
/* drawing below the image? */
if (pen_y < 0) {
yb_start += (g->pitch < 0) ? -pen_y : pen_y;
diff --git a/source/blender/blenfont/intern/blf_glyph.c b/source/blender/blenfont/intern/blf_glyph.c
index f3789bee1fd..5a87c726566 100644
--- a/source/blender/blenfont/intern/blf_glyph.c
+++ b/source/blender/blenfont/intern/blf_glyph.c
@@ -292,11 +292,11 @@ GlyphBLF *blf_glyph_add(FontBLF *font, unsigned int index, unsigned int c)
if (font->flags & BLF_HINTING)
flags &= ~FT_LOAD_NO_HINTING;
-
+
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);
+ err = FT_Load_Glyph(font->face, (FT_UInt)index, flags);
if (err) {
BLI_spin_unlock(font->ft_lib_mutex);
diff --git a/source/blender/blenfont/intern/blf_internal_types.h b/source/blender/blenfont/intern/blf_internal_types.h
index 5b9d3f1eb5b..d7b526735d1 100644
--- a/source/blender/blenfont/intern/blf_internal_types.h
+++ b/source/blender/blenfont/intern/blf_internal_types.h
@@ -204,7 +204,7 @@ typedef struct FontBLF {
/* angle in radians. */
float angle;
-
+
#if 0 /* BLF_BLUR_ENABLE */
/* blur: 3 or 5 large kernel */
int blur;
diff --git a/source/blender/blenkernel/BKE_DerivedMesh.h b/source/blender/blenkernel/BKE_DerivedMesh.h
index e918f158682..79b0e5eb95f 100644
--- a/source/blender/blenkernel/BKE_DerivedMesh.h
+++ b/source/blender/blenkernel/BKE_DerivedMesh.h
@@ -531,18 +531,6 @@ DMCoNo *mesh_get_mapped_verts_nors(struct Scene *scene, struct Object *ob);
void mesh_get_mapped_verts_coords(DerivedMesh *dm, float (*r_cos)[3], const int totcos);
/* */
-DerivedMesh *mesh_get_derived_final(
- struct Depsgraph *depsgraph, struct Scene *scene,
- struct Object *ob, CustomDataMask dataMask);
-struct Mesh *mesh_get_eval_final(
- struct Depsgraph *depsgraph, struct Scene *scene, struct Object *ob, CustomDataMask dataMask);
-
-DerivedMesh *mesh_get_derived_deform(
- struct Depsgraph *depsgraph, struct Scene *scene,
- struct Object *ob, CustomDataMask dataMask);
-struct Mesh *mesh_get_eval_deform(
- struct Depsgraph *depsgraph, struct Scene *scene,
- struct Object *ob, CustomDataMask dataMask);
DerivedMesh *mesh_create_derived_for_modifier(
struct Depsgraph *depsgraph, struct Scene *scene, struct Object *ob,
diff --git a/source/blender/blenkernel/BKE_anim.h b/source/blender/blenkernel/BKE_anim.h
index 701be9d44cc..2f7d0eaba03 100644
--- a/source/blender/blenkernel/BKE_anim.h
+++ b/source/blender/blenkernel/BKE_anim.h
@@ -32,16 +32,17 @@
* \author nzc
* \since March 2001
*/
-struct Depsgraph;
-struct Path;
-struct Object;
-struct Scene;
-struct ListBase;
struct bAnimVizSettings;
struct bMotionPath;
struct bPoseChannel;
-struct ReportList;
+struct Depsgraph;
+struct ListBase;
struct Main;
+struct Object;
+struct ParticleSystem;
+struct Path;
+struct ReportList;
+struct Scene;
/* ---------------------------------------------------- */
/* Animation Visualization */
@@ -68,7 +69,6 @@ int where_on_path(struct Object *ob, float ctime, float vec[4], float dir[3], fl
/* ---------------------------------------------------- */
/* Dupli-Geometry */
-struct ListBase *object_duplilist_ex(struct Depsgraph *depsgraph, struct Scene *sce, struct Object *ob, bool update);
struct ListBase *object_duplilist(struct Depsgraph *depsgraph, struct Scene *sce, struct Object *ob);
void free_object_duplilist(struct ListBase *lb);
int count_duplilist(struct Object *ob);
@@ -83,6 +83,26 @@ typedef struct DupliApplyData {
DupliExtraData *extra;
} DupliApplyData;
+typedef struct DupliObject {
+ struct DupliObject *next, *prev;
+ struct Object *ob;
+ float mat[4][4];
+ float orco[3], uv[2];
+
+ short type; /* from Object.transflag */
+ char no_draw;
+
+ /* Persistent identifier for a dupli object, for inter-frame matching of
+ * objects with motion blur, or inter-update matching for syncing. */
+ int persistent_id[16]; /* 2*MAX_DUPLI_RECUR */
+
+ /* Particle this dupli was generated from. */
+ struct ParticleSystem *particle_system;
+
+ /* Random ID for shading */
+ unsigned int random_id;
+} DupliObject;
+
DupliApplyData *duplilist_apply(struct Depsgraph *depsgraph, 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_collection.h b/source/blender/blenkernel/BKE_collection.h
index edc24d9649e..fc5b19ccb4f 100644
--- a/source/blender/blenkernel/BKE_collection.h
+++ b/source/blender/blenkernel/BKE_collection.h
@@ -91,7 +91,6 @@ bool BKE_collection_is_in_scene(struct Collection *collection);
void BKE_collections_after_lib_link(struct Main *bmain);
bool BKE_collection_object_cyclic_check(struct Main *bmain, struct Object *object, struct Collection *collection);
bool BKE_collection_is_animated(struct Collection *collection, struct Object *parent);
-void BKE_collection_handle_recalc_and_update(struct Depsgraph *depsgraph, struct Scene *scene, struct Object *parent, struct Collection *collection);
/* Object list cache. */
diff --git a/source/blender/blenkernel/BKE_library.h b/source/blender/blenkernel/BKE_library.h
index 0f05170b47c..28bc254f25a 100644
--- a/source/blender/blenkernel/BKE_library.h
+++ b/source/blender/blenkernel/BKE_library.h
@@ -182,6 +182,9 @@ struct BlendThumbnail *BKE_main_thumbnail_from_imbuf(struct Main *bmain, struct
struct ImBuf *BKE_main_thumbnail_to_imbuf(struct Main *bmain, struct BlendThumbnail *data);
void BKE_main_thumbnail_create(struct Main *bmain);
+const char *BKE_main_blendfile_path(const struct Main *bmain) ATTR_NONNULL();
+const char *BKE_main_blendfile_path_from_global(void);
+
void BKE_main_id_tag_idcode(struct Main *mainvar, const short type, const int tag, const bool value);
void BKE_main_id_tag_listbase(struct ListBase *lb, const int tag, const bool value);
void BKE_main_id_tag_all(struct Main *mainvar, const int tag, const bool value);
diff --git a/source/blender/blenkernel/BKE_mball.h b/source/blender/blenkernel/BKE_mball.h
index 41f04c09e69..74ef9d9dbc0 100644
--- a/source/blender/blenkernel/BKE_mball.h
+++ b/source/blender/blenkernel/BKE_mball.h
@@ -76,8 +76,6 @@ void BKE_mball_select_swap(struct MetaBall *mb);
struct Depsgraph;
-void BKE_mball_eval_geometry(struct Depsgraph *depsgraph,
- struct MetaBall *mball);
/* Draw Cache */
enum {
diff --git a/source/blender/blenkernel/BKE_mesh.h b/source/blender/blenkernel/BKE_mesh.h
index efbc00c456f..cb58deb9511 100644
--- a/source/blender/blenkernel/BKE_mesh.h
+++ b/source/blender/blenkernel/BKE_mesh.h
@@ -178,9 +178,9 @@ struct Mesh *BKE_mesh_create_derived_for_modifier(
struct ModifierData *md, int build_shapekey_layers);
/* Copies a nomain-Mesh into an existing Mesh. */
-void BKE_nomain_mesh_to_mesh(struct Mesh *mesh_src, struct Mesh *mesh_dst, struct Object *ob,
+void BKE_mesh_nomain_to_mesh(struct Mesh *mesh_src, struct Mesh *mesh_dst, struct Object *ob,
CustomDataMask mask, bool take_ownership);
-void BKE_nomain_mesh_to_meshkey(struct Mesh *mesh_src, struct Mesh *mesh_dst, struct KeyBlock *kb);
+void BKE_mesh_nomain_to_meshkey(struct Mesh *mesh_src, struct Mesh *mesh_dst, struct KeyBlock *kb);
/* vertex level transformations & checks (no derived mesh) */
@@ -206,23 +206,10 @@ void BKE_mesh_mselect_active_set(struct Mesh *me, int index, int type);
void BKE_mesh_apply_vert_coords(struct Mesh *mesh, float (*vertCoords)[3]);
-/* *** mesh_runtime.c *** */
-void BKE_mesh_runtime_reset(struct Mesh *mesh);
-int BKE_mesh_runtime_looptri_len(const struct Mesh *mesh);
-void BKE_mesh_runtime_looptri_recalc(struct Mesh *mesh);
-const struct MLoopTri *BKE_mesh_runtime_looptri_ensure(struct Mesh *mesh);
-bool BKE_mesh_runtime_ensure_edit_data(struct Mesh *mesh);
-bool BKE_mesh_runtime_clear_edit_data(struct Mesh *mesh);
-void BKE_mesh_runtime_clear_geometry(struct Mesh *mesh);
-void BKE_mesh_runtime_clear_cache(struct Mesh *mesh);
-
-void BKE_mesh_runtime_verttri_from_looptri(
- struct MVertTri *r_verttri,
- const struct MLoop *mloop, const struct MLoopTri *looptri, int looptri_num);
-
/* *** mesh_evaluate.c *** */
+void BKE_mesh_calc_normals_mapping_simple(struct Mesh *me);
void BKE_mesh_calc_normals_mapping(
struct MVert *mverts, int numVerts,
const struct MLoop *mloop, const struct MPoly *mpolys, int numLoops, int numPolys, float (*r_polyNors)[3],
diff --git a/source/blender/blenkernel/BKE_mesh_runtime.h b/source/blender/blenkernel/BKE_mesh_runtime.h
new file mode 100644
index 00000000000..6904ad529de
--- /dev/null
+++ b/source/blender/blenkernel/BKE_mesh_runtime.h
@@ -0,0 +1,85 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): Blender Foundation
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+#ifndef __BKE_MESH_RUNTIME_H__
+#define __BKE_MESH_RUNTIME_H__
+
+/** \file BKE_mesh_runtime.h
+ * \ingroup bke
+ *
+ * This file contains access functions for the Mesh.runtime struct.
+ */
+
+#include "BKE_customdata.h" /* for CustomDataMask */
+
+struct Depsgraph;
+struct Mesh;
+struct MLoop;
+struct MLoopTri;
+struct MVertTri;
+struct Object;
+struct Scene;
+
+/* Undefine to hide DerivedMesh-based function declarations */
+#define USE_DERIVEDMESH
+
+#ifdef USE_DERIVEDMESH
+struct DerivedMesh;
+#endif
+
+void BKE_mesh_runtime_reset(struct Mesh *mesh);
+int BKE_mesh_runtime_looptri_len(const struct Mesh *mesh);
+void BKE_mesh_runtime_looptri_recalc(struct Mesh *mesh);
+const struct MLoopTri *BKE_mesh_runtime_looptri_ensure(struct Mesh *mesh);
+bool BKE_mesh_runtime_ensure_edit_data(struct Mesh *mesh);
+bool BKE_mesh_runtime_clear_edit_data(struct Mesh *mesh);
+void BKE_mesh_runtime_clear_geometry(struct Mesh *mesh);
+void BKE_mesh_runtime_clear_cache(struct Mesh *mesh);
+
+void BKE_mesh_runtime_verttri_from_looptri(
+ struct MVertTri *r_verttri,
+ const struct MLoop *mloop, const struct MLoopTri *looptri, int looptri_num);
+
+/* NOTE: the functions below are defined in DerivedMesh.c, and are intended to be moved
+ * to a more suitable location when that file is removed. */
+#ifdef USE_DERIVEDMESH
+struct DerivedMesh *mesh_get_derived_final(
+ struct Depsgraph *depsgraph, struct Scene *scene,
+ struct Object *ob, CustomDataMask dataMask);
+#endif
+struct Mesh *mesh_get_eval_final(
+ struct Depsgraph *depsgraph, struct Scene *scene, struct Object *ob, CustomDataMask dataMask);
+
+#ifdef USE_DERIVEDMESH
+struct DerivedMesh *mesh_get_derived_deform(
+ struct Depsgraph *depsgraph, struct Scene *scene,
+ struct Object *ob, CustomDataMask dataMask);
+#endif
+struct Mesh *mesh_get_eval_deform(
+ struct Depsgraph *depsgraph, struct Scene *scene,
+ struct Object *ob, CustomDataMask dataMask);
+
+#endif /* __BKE_MESH_RUNTIME_H__ */
diff --git a/source/blender/blenkernel/BKE_movieclip.h b/source/blender/blenkernel/BKE_movieclip.h
index 5b5ebbf035c..014ea2b9159 100644
--- a/source/blender/blenkernel/BKE_movieclip.h
+++ b/source/blender/blenkernel/BKE_movieclip.h
@@ -49,7 +49,7 @@ void BKE_movieclip_make_local(struct Main *bmain, struct MovieClip *clip, const
struct MovieClip *BKE_movieclip_file_add(struct Main *bmain, const char *name);
struct MovieClip *BKE_movieclip_file_add_exists_ex(struct Main *bmain, const char *name, bool *r_exists);
struct MovieClip *BKE_movieclip_file_add_exists(struct Main *bmain, const char *name);
-void BKE_movieclip_reload(struct MovieClip *clip);
+void BKE_movieclip_reload(struct Main *bmain, struct MovieClip *clip);
void BKE_movieclip_clear_cache(struct MovieClip *clip);
void BKE_movieclip_clear_proxy_cache(struct MovieClip *clip);
diff --git a/source/blender/blenkernel/BKE_node.h b/source/blender/blenkernel/BKE_node.h
index 915cafd5d3d..cb211b65948 100644
--- a/source/blender/blenkernel/BKE_node.h
+++ b/source/blender/blenkernel/BKE_node.h
@@ -1056,9 +1056,6 @@ void free_nodesystem(void);
struct Depsgraph;
-void BKE_nodetree_copy_default_values(struct bNodeTree *ntree_dst,
- const struct bNodeTree *ntree_src);
-
void BKE_nodetree_shading_params_eval(struct Depsgraph *depsgraph,
struct bNodeTree *ntree_dst,
const struct bNodeTree *ntree_src);
diff --git a/source/blender/blenkernel/BKE_object.h b/source/blender/blenkernel/BKE_object.h
index 7ff0093db6c..6172c9998af 100644
--- a/source/blender/blenkernel/BKE_object.h
+++ b/source/blender/blenkernel/BKE_object.h
@@ -66,6 +66,7 @@ void BKE_object_free_curve_cache(struct Object *ob);
void BKE_object_free(struct Object *ob);
void BKE_object_free_derived_caches(struct Object *ob);
+void BKE_object_free_derived_mesh_caches(struct Object *ob);
void BKE_object_free_caches(struct Object *object);
void BKE_object_modifier_hook_reset(struct Object *ob, struct HookModifierData *hmd);
diff --git a/source/blender/blenkernel/BKE_paint.h b/source/blender/blenkernel/BKE_paint.h
index 9bd73bd7553..412cf45de2b 100644
--- a/source/blender/blenkernel/BKE_paint.h
+++ b/source/blender/blenkernel/BKE_paint.h
@@ -40,6 +40,7 @@ struct CurveMapping;
struct MeshElemMap;
struct GridPaintMask;
struct Main;
+struct Mesh;
struct MLoop;
struct MLoopTri;
struct MFace;
@@ -185,7 +186,8 @@ typedef struct SculptSession {
float *vmask;
/* Mesh connectivity */
- const struct MeshElemMap *pmap;
+ struct MeshElemMap *pmap;
+ int *pmap_mem;
/* BMesh for dynamic topology sculpting */
struct BMesh *bm;
@@ -258,6 +260,8 @@ int BKE_sculpt_mask_layers_ensure(struct Object *ob,
struct MultiresModifierData *mmd);
void BKE_sculpt_toolsettings_data_ensure(struct Scene *scene);
+struct PBVH *BKE_sculpt_object_pbvh_ensure(struct Object *ob, struct Mesh *me_eval_deform);
+
enum {
SCULPT_MASK_LAYER_CALC_VERT = (1 << 0),
SCULPT_MASK_LAYER_CALC_LOOP = (1 << 1)
diff --git a/source/blender/blenkernel/BKE_particle.h b/source/blender/blenkernel/BKE_particle.h
index f4279fa9262..2f192c43504 100644
--- a/source/blender/blenkernel/BKE_particle.h
+++ b/source/blender/blenkernel/BKE_particle.h
@@ -303,9 +303,6 @@ void psys_set_current_num(Object *ob, int index);
struct LatticeDeformData *psys_create_lattice_deform_data(struct ParticleSimulationData *sim);
struct ParticleSystem *psys_orig_get(struct ParticleSystem *psys);
-struct ParticleSystem *psys_eval_get(struct Depsgraph *depsgraph,
- struct Object *object,
- struct ParticleSystem *psys);
bool psys_in_edit_mode(struct Depsgraph *depsgraph, struct ParticleSystem *psys);
bool psys_check_enabled(struct Object *ob, struct ParticleSystem *psys, const bool use_render_params);
bool psys_check_edited(struct ParticleSystem *psys);
diff --git a/source/blender/blenkernel/BKE_pbvh.h b/source/blender/blenkernel/BKE_pbvh.h
index c18288de1bc..78c766f6115 100644
--- a/source/blender/blenkernel/BKE_pbvh.h
+++ b/source/blender/blenkernel/BKE_pbvh.h
@@ -240,7 +240,7 @@ void BKE_pbvh_node_layer_disp_free(PBVHNode *node);
/* vertex deformer */
float (*BKE_pbvh_get_vertCos(struct PBVH *pbvh))[3];
-void BKE_pbvh_apply_vertCos(struct PBVH *pbvh, float (*vertCos)[3]);
+void BKE_pbvh_apply_vertCos(struct PBVH *pbvh, float (*vertCos)[3], const int totvert);
bool BKE_pbvh_isDeformed(struct PBVH *pbvh);
/* Vertex Iterator */
diff --git a/source/blender/blenkernel/BKE_studiolight.h b/source/blender/blenkernel/BKE_studiolight.h
index 2f2e948ab26..7883f89f33a 100644
--- a/source/blender/blenkernel/BKE_studiolight.h
+++ b/source/blender/blenkernel/BKE_studiolight.h
@@ -59,15 +59,23 @@ struct GPUTexture;
enum StudioLightFlag {
STUDIOLIGHT_DIFFUSE_LIGHT_CALCULATED = (1 << 0),
STUDIOLIGHT_LIGHT_DIRECTION_CALCULATED = (1 << 1),
- STUDIOLIGHT_EXTERNAL_FILE = (1 << 2),
- STUDIOLIGHT_ORIENTATION_CAMERA = (1 << 3),
- STUDIOLIGHT_ORIENTATION_WORLD = (1 << 4),
- STUDIOLIGHT_EQUIRECTANGULAR_IMAGE_LOADED = (1 << 5),
- STUDIOLIGHT_EQUIRECTANGULAR_IRRADIANCE_IMAGE_CALCULATED = (1 << 6),
- STUDIOLIGHT_EQUIRECTANGULAR_RADIANCE_GPUTEXTURE = (1 << 7),
- STUDIOLIGHT_EQUIRECTANGULAR_IRRADIANCE_GPUTEXTURE = (1 << 8),
- STUDIOLIGHT_RADIANCE_BUFFERS_CALCULATED = (1 << 9),
+ STUDIOLIGHT_INTERNAL = (1 << 2),
+ STUDIOLIGHT_EXTERNAL_FILE = (1 << 3),
+ STUDIOLIGHT_USER_DEFINED = (1 << 12),
+ STUDIOLIGHT_ORIENTATION_CAMERA = (1 << 4),
+ STUDIOLIGHT_ORIENTATION_WORLD = (1 << 5),
+ STUDIOLIGHT_ORIENTATION_VIEWNORMAL = (1 << 6),
+ STUDIOLIGHT_EXTERNAL_IMAGE_LOADED = (1 << 7),
+ STUDIOLIGHT_EQUIRECTANGULAR_IRRADIANCE_IMAGE_CALCULATED = (1 << 8),
+ STUDIOLIGHT_EQUIRECTANGULAR_RADIANCE_GPUTEXTURE = (1 << 9),
+ STUDIOLIGHT_EQUIRECTANGULAR_IRRADIANCE_GPUTEXTURE = (1 << 10),
+ STUDIOLIGHT_RADIANCE_BUFFERS_CALCULATED = (1 << 11),
+ STUDIOLIGHT_UI_EXPANDED = (1 << 13),
} StudioLightFlag;
+#define STUDIOLIGHT_FLAG_ALL (STUDIOLIGHT_INTERNAL | STUDIOLIGHT_EXTERNAL_FILE)
+#define STUDIOLIGHT_FLAG_ORIENTATIONS (STUDIOLIGHT_ORIENTATION_CAMERA | STUDIOLIGHT_ORIENTATION_WORLD | STUDIOLIGHT_ORIENTATION_VIEWNORMAL)
+#define STUDIOLIGHT_ORIENTATIONS_MATERIAL_MODE (STUDIOLIGHT_INTERNAL | STUDIOLIGHT_ORIENTATION_WORLD)
+#define STUDIOLIGHT_ORIENTATIONS_SOLID (STUDIOLIGHT_ORIENTATION_CAMERA | STUDIOLIGHT_ORIENTATION_WORLD)
typedef struct StudioLight {
struct StudioLight *next, *prev;
@@ -89,9 +97,11 @@ typedef struct StudioLight {
void BKE_studiolight_init(void);
void BKE_studiolight_free(void);
struct StudioLight *BKE_studiolight_find(const char *name, int flag);
-struct StudioLight *BKE_studiolight_findindex(int index);
+struct StudioLight *BKE_studiolight_findindex(int index, int flag);
+struct StudioLight *BKE_studiolight_find_first(int flag);
unsigned int *BKE_studiolight_preview(StudioLight *sl, int icon_size, int icon_id_type);
-const struct ListBase *BKE_studiolight_listbase(void);
+struct ListBase *BKE_studiolight_listbase(void);
void BKE_studiolight_ensure_flag(StudioLight *sl, int flag);
+void BKE_studiolight_refresh(void);
#endif /* __BKE_STUDIOLIGHT_H__ */
diff --git a/source/blender/blenkernel/intern/DerivedMesh.c b/source/blender/blenkernel/intern/DerivedMesh.c
index 1698946b506..c081bb0799f 100644
--- a/source/blender/blenkernel/intern/DerivedMesh.c
+++ b/source/blender/blenkernel/intern/DerivedMesh.c
@@ -61,6 +61,7 @@
#include "BKE_modifier.h"
#include "BKE_mesh.h"
#include "BKE_mesh_mapping.h"
+#include "BKE_mesh_runtime.h"
#include "BKE_mesh_tangent.h"
#include "BKE_object.h"
#include "BKE_object_deform.h"
@@ -94,7 +95,6 @@
static ThreadRWMutex loops_cache_lock = PTHREAD_RWLOCK_INITIALIZER;
-static void add_shapekey_layers(DerivedMesh *dm, Mesh *me, Object *ob);
static void shapekey_layers_to_keyblocks(DerivedMesh *dm, Mesh *me, int actshape_uid);
static void mesh_init_origspace(Mesh *mesh);
@@ -1157,6 +1157,8 @@ DerivedMesh *mesh_create_derived(Mesh *me, float (*vertCos)[3])
return dm;
}
+/* XXX2.8(Sybren): can be removed once DerivedMesh port is done */
+#ifdef WITH_DERIVEDMESH_DEPRECATED_FUNCS
DerivedMesh *mesh_create_derived_for_modifier(
struct Depsgraph *depsgraph, Scene *scene, Object *ob,
ModifierData *md, int build_shapekey_layers)
@@ -1207,6 +1209,7 @@ DerivedMesh *mesh_create_derived_for_modifier(
return dm;
}
+#endif
static float (*get_editbmesh_orco_verts(BMEditMesh *em))[3]
{
@@ -1920,7 +1923,7 @@ static void shapekey_layers_to_keyblocks(DerivedMesh *dm, Mesh *me, int actshape
}
}
-static void add_shapekey_layers(DerivedMesh *dm, Mesh *me, Object *UNUSED(ob))
+static void UNUSED_FUNCTION(add_shapekey_layers)(DerivedMesh *dm, Mesh *me, Object *UNUSED(ob))
{
KeyBlock *kb;
Key *key = me->key;
@@ -3104,6 +3107,7 @@ void makeDerivedMesh(
/***/
+#ifdef USE_DERIVEDMESH
/* Deprecated DM, use: 'mesh_get_eval_final'. */
DerivedMesh *mesh_get_derived_final(
struct Depsgraph *depsgraph, Scene *scene, Object *ob, CustomDataMask dataMask)
@@ -3124,6 +3128,7 @@ DerivedMesh *mesh_get_derived_final(
if (ob->derivedFinal) { BLI_assert(!(ob->derivedFinal->dirty & DM_DIRTY_NORMALS)); }
return ob->derivedFinal;
}
+#endif
Mesh *mesh_get_eval_final(
struct Depsgraph *depsgraph, Scene *scene, Object *ob, CustomDataMask dataMask)
{
@@ -3133,7 +3138,7 @@ Mesh *mesh_get_eval_final(
bool need_mapping;
dataMask |= object_get_datamask(depsgraph, ob, &need_mapping);
- if (!ob->derivedFinal ||
+ if (!ob->runtime.mesh_eval ||
((dataMask & ob->lastDataMask) != dataMask) ||
(need_mapping != ob->lastNeedMapping))
{
@@ -3144,6 +3149,7 @@ Mesh *mesh_get_eval_final(
return ob->runtime.mesh_eval;
}
+#ifdef USE_DERIVEDMESH
/* Deprecated DM, use: 'mesh_get_eval_deform' instead. */
DerivedMesh *mesh_get_derived_deform(struct Depsgraph *depsgraph, Scene *scene, Object *ob, CustomDataMask dataMask)
{
@@ -3163,6 +3169,7 @@ DerivedMesh *mesh_get_derived_deform(struct Depsgraph *depsgraph, Scene *scene,
return ob->derivedDeform;
}
+#endif
Mesh *mesh_get_eval_deform(struct Depsgraph *depsgraph, Scene *scene, Object *ob, CustomDataMask dataMask)
{
/* if there's no derived mesh or the last data mask used doesn't include
diff --git a/source/blender/blenkernel/intern/blender_undo.c b/source/blender/blenkernel/intern/blender_undo.c
index 98482bcc8b1..857fc72672c 100644
--- a/source/blender/blenkernel/intern/blender_undo.c
+++ b/source/blender/blenkernel/intern/blender_undo.c
@@ -67,10 +67,11 @@
bool BKE_memfile_undo_decode(MemFileUndoData *mfu, bContext *C)
{
- char mainstr[sizeof(G.main->name)];
+ Main *bmain = CTX_data_main(C);
+ char mainstr[sizeof(bmain->name)];
int success = 0, fileflags;
- BLI_strncpy(mainstr, G.main->name, sizeof(mainstr)); /* temporal store */
+ BLI_strncpy(mainstr, BKE_main_blendfile_path(bmain), sizeof(mainstr)); /* temporal store */
fileflags = G.fileflags;
G.fileflags |= G_FILE_NO_UI;
@@ -82,13 +83,14 @@ bool BKE_memfile_undo_decode(MemFileUndoData *mfu, bContext *C)
success = BKE_blendfile_read_from_memfile(C, &mfu->memfile, NULL, 0);
}
- /* restore */
- BLI_strncpy(G.main->name, mainstr, sizeof(G.main->name)); /* restore */
+ /* Restore, bmain has been re-allocated. */
+ bmain = CTX_data_main(C);
+ BLI_strncpy(bmain->name, mainstr, sizeof(bmain->name));
G.fileflags = fileflags;
if (success) {
/* important not to update time here, else non keyed tranforms are lost */
- DEG_on_visible_update(G.main, false);
+ DEG_on_visible_update(bmain, false);
}
return success;
diff --git a/source/blender/blenkernel/intern/blendfile.c b/source/blender/blenkernel/intern/blendfile.c
index 34079d778f7..597c69408b5 100644
--- a/source/blender/blenkernel/intern/blendfile.c
+++ b/source/blender/blenkernel/intern/blendfile.c
@@ -116,6 +116,7 @@ static void setup_app_data(
bContext *C, BlendFileData *bfd,
const char *filepath, ReportList *reports)
{
+ Main *bmain = G.main; /* Valid usage */
Scene *curscene = NULL;
const bool is_startup = (bfd->filename[0] == '\0');
const bool recover = (G.fileflags & G_FILE_RECOVER) != 0;
@@ -172,9 +173,9 @@ static void setup_app_data(
bool track_undo_scene;
/* comes from readfile.c */
- SWAP(ListBase, G.main->wm, bfd->main->wm);
- SWAP(ListBase, G.main->workspaces, bfd->main->workspaces);
- SWAP(ListBase, G.main->screen, bfd->main->screen);
+ SWAP(ListBase, bmain->wm, bfd->main->wm);
+ SWAP(ListBase, bmain->workspaces, bfd->main->workspaces);
+ SWAP(ListBase, bmain->screen, bfd->main->screen);
/* we re-use current window and screen */
win = CTX_wm_window(C);
@@ -236,9 +237,9 @@ static void setup_app_data(
/* clear old property update cache, in case some old references are left dangling */
RNA_property_update_cache_free();
- G.main = bfd->main;
+ bmain = G.main = bfd->main;
- CTX_data_main_set(C, G.main);
+ CTX_data_main_set(C, bmain);
if (bfd->user) {
@@ -266,7 +267,7 @@ static void setup_app_data(
/* Keep state from preferences. */
const int fileflags_skip = G_FILE_FLAGS_RUNTIME;
G.fileflags = (G.fileflags & fileflags_skip) | (bfd->fileflags & ~fileflags_skip);
- CTX_wm_manager_set(C, G.main->wm.first);
+ CTX_wm_manager_set(C, bmain->wm.first);
CTX_wm_screen_set(C, bfd->curscreen);
CTX_data_scene_set(C, bfd->curscene);
CTX_wm_area_set(C, NULL);
@@ -280,10 +281,10 @@ static void setup_app_data(
wmWindow *win = CTX_wm_window(C);
/* in case we don't even have a local scene, add one */
- if (!G.main->scene.first)
- BKE_scene_add(G.main, "Empty");
+ if (!bmain->scene.first)
+ BKE_scene_add(bmain, "Empty");
- CTX_data_scene_set(C, G.main->scene.first);
+ CTX_data_scene_set(C, bmain->scene.first);
win->scene = CTX_data_scene(C);
curscene = CTX_data_scene(C);
}
@@ -307,35 +308,35 @@ static void setup_app_data(
/* FIXME: this version patching should really be part of the file-reading code,
* but we still get too many unrelated data-corruption crashes otherwise... */
- if (G.main->versionfile < 250)
- do_versions_ipos_to_animato(G.main);
+ if (bmain->versionfile < 250)
+ do_versions_ipos_to_animato(bmain);
- G.main->recovered = 0;
+ bmain->recovered = 0;
/* startup.blend or recovered startup */
if (bfd->filename[0] == 0) {
- G.main->name[0] = 0;
+ bmain->name[0] = '\0';
}
else if (recover && G.relbase_valid) {
/* in case of autosave or quit.blend, use original filename instead
* use relbase_valid to make sure the file is saved, else we get <memory2> in the filename */
filepath = bfd->filename;
- G.main->recovered = 1;
+ bmain->recovered = 1;
/* these are the same at times, should never copy to the same location */
- if (G.main->name != filepath)
- BLI_strncpy(G.main->name, filepath, FILE_MAX);
+ if (bmain->name != filepath)
+ BLI_strncpy(bmain->name, filepath, FILE_MAX);
}
/* baseflags, groups, make depsgraph, etc */
/* first handle case if other windows have different scenes visible */
if (mode == LOAD_UI) {
- wmWindowManager *wm = G.main->wm.first;
+ wmWindowManager *wm = bmain->wm.first;
if (wm) {
for (wmWindow *win = wm->windows.first; win; win = win->next) {
if (win->scene && win->scene != curscene) {
- BKE_scene_set_background(G.main, win->scene);
+ BKE_scene_set_background(bmain, win->scene);
}
}
}
@@ -346,10 +347,10 @@ static void setup_app_data(
* constructing dependency graph.
*/
if (mode != LOAD_UNDO) {
- IMB_colormanagement_check_file_config(G.main);
+ IMB_colormanagement_check_file_config(bmain);
}
- BKE_scene_set_background(G.main, curscene);
+ BKE_scene_set_background(bmain, curscene);
if (mode != LOAD_UNDO) {
/* TODO(sergey): Can this be also move above? */
@@ -431,9 +432,10 @@ bool BKE_blendfile_read_from_memfile(
bContext *C, struct MemFile *memfile,
ReportList *reports, int skip_flags)
{
+ Main *bmain = CTX_data_main(C);
BlendFileData *bfd;
- bfd = BLO_read_from_memfile(CTX_data_main(C), G.main->name, memfile, reports, skip_flags);
+ bfd = BLO_read_from_memfile(bmain, BKE_main_blendfile_path(bmain), memfile, reports, skip_flags);
if (bfd) {
/* remove the unused screens and wm */
while (bfd->main->wm.first)
diff --git a/source/blender/blenkernel/intern/bpath.c b/source/blender/blenkernel/intern/bpath.c
index 1fd2797d2f8..82d9f9f8f69 100644
--- a/source/blender/blenkernel/intern/bpath.c
+++ b/source/blender/blenkernel/intern/bpath.c
@@ -325,7 +325,7 @@ void BKE_bpath_missing_files_find(Main *bmain, const char *searchpath, ReportLis
struct BPathFind_Data data = {NULL};
const int flag = BKE_BPATH_TRAVERSE_ABS | BKE_BPATH_TRAVERSE_RELOAD_EDITED;
- data.basedir = bmain->name;
+ data.basedir = BKE_main_blendfile_path(bmain);
data.reports = reports;
data.searchdir = searchpath;
data.find_all = find_all;
diff --git a/source/blender/blenkernel/intern/bvhutils.c b/source/blender/blenkernel/intern/bvhutils.c
index b3ea3de6ea9..e8328139d64 100644
--- a/source/blender/blenkernel/intern/bvhutils.c
+++ b/source/blender/blenkernel/intern/bvhutils.c
@@ -45,6 +45,7 @@
#include "BKE_DerivedMesh.h"
#include "BKE_editmesh.h"
#include "BKE_mesh.h"
+#include "BKE_mesh_runtime.h"
#include "MEM_guardedalloc.h"
diff --git a/source/blender/blenkernel/intern/cachefile.c b/source/blender/blenkernel/intern/cachefile.c
index 274f7b78529..74c0dca6279 100644
--- a/source/blender/blenkernel/intern/cachefile.c
+++ b/source/blender/blenkernel/intern/cachefile.c
@@ -89,13 +89,22 @@ void BKE_cachefile_free(CacheFile *cache_file)
{
BKE_animdata_free((ID *)cache_file, false);
+ if (cache_file->id.tag & LIB_TAG_NO_MAIN) {
+ /* CoW/no-main copies reuse the existing ArchiveReader and mutex */
+ return;
+ }
+
+ if (cache_file->handle) {
#ifdef WITH_ALEMBIC
- ABC_free_handle(cache_file->handle);
+ ABC_free_handle(cache_file->handle);
#endif
-
+ cache_file->handle = NULL;
+ }
if (cache_file->handle_mutex) {
BLI_mutex_free(cache_file->handle_mutex);
+ cache_file->handle_mutex = NULL;
}
+
BLI_freelistN(&cache_file->object_paths);
}
@@ -110,8 +119,14 @@ void BKE_cachefile_free(CacheFile *cache_file)
void BKE_cachefile_copy_data(
Main *UNUSED(bmain), CacheFile *cache_file_dst, const CacheFile *UNUSED(cache_file_src), const int UNUSED(flag))
{
+ if (cache_file_dst->id.tag & LIB_TAG_NO_MAIN) {
+ /* CoW/no-main copies reuse the existing ArchiveReader and mutex */
+ return;
+ }
+
cache_file_dst->handle = NULL;
- BLI_listbase_clear(&cache_file_dst->object_paths);
+ cache_file_dst->handle_mutex = NULL;
+ BLI_duplicatelist(&cache_file_dst->object_paths, &cache_file_dst->object_paths);
}
CacheFile *BKE_cachefile_copy(Main *bmain, const CacheFile *cache_file)
@@ -153,6 +168,8 @@ void BKE_cachefile_ensure_handle(const Main *bmain, CacheFile *cache_file)
BLI_mutex_lock(cache_file->handle_mutex);
if (cache_file->handle == NULL) {
+ /* Assigning to a CoW copy is a bad idea; assign to the original instead. */
+ BLI_assert((cache_file->id.tag & LIB_TAG_COPIED_ON_WRITE) == 0);
BKE_cachefile_reload(bmain, cache_file);
}
diff --git a/source/blender/blenkernel/intern/cdderivedmesh.c b/source/blender/blenkernel/intern/cdderivedmesh.c
index 13b2a3a5d64..7bcc05b0e37 100644
--- a/source/blender/blenkernel/intern/cdderivedmesh.c
+++ b/source/blender/blenkernel/intern/cdderivedmesh.c
@@ -325,7 +325,7 @@ static PBVH *cdDM_getPBVH(Object *ob, DerivedMesh *dm)
totvert = deformdm->getNumVerts(deformdm);
vertCos = MEM_malloc_arrayN(totvert, sizeof(float[3]), "cdDM_getPBVH vertCos");
deformdm->getVertCos(deformdm, vertCos);
- BKE_pbvh_apply_vertCos(cddm->pbvh, vertCos);
+ BKE_pbvh_apply_vertCos(cddm->pbvh, vertCos, totvert);
MEM_freeN(vertCos);
}
}
diff --git a/source/blender/blenkernel/intern/cloth.c b/source/blender/blenkernel/intern/cloth.c
index a39de284064..cc1c7260cbc 100644
--- a/source/blender/blenkernel/intern/cloth.c
+++ b/source/blender/blenkernel/intern/cloth.c
@@ -48,7 +48,7 @@
#include "BKE_cloth.h"
#include "BKE_effect.h"
#include "BKE_global.h"
-#include "BKE_mesh.h"
+#include "BKE_mesh_runtime.h"
#include "BKE_modifier.h"
#include "BKE_pointcache.h"
diff --git a/source/blender/blenkernel/intern/collection.c b/source/blender/blenkernel/intern/collection.c
index c4709a32f78..ab0ec8b0491 100644
--- a/source/blender/blenkernel/intern/collection.c
+++ b/source/blender/blenkernel/intern/collection.c
@@ -59,7 +59,7 @@
static bool collection_child_add(Collection *parent, Collection *collection, int flag, const bool add_us);
static bool collection_child_remove(Collection *parent, Collection *collection);
-static bool collection_object_add(Collection *collection, Object *ob, int flag, const bool add_us);
+static bool collection_object_add(Main *bmain, Collection *collection, Object *ob, int flag, const bool add_us);
static bool collection_object_remove(Main *bmain, Collection *collection, Object *ob, const bool free_us);
static CollectionChild *collection_find_child(Collection *parent, Collection *collection);
@@ -163,7 +163,7 @@ bool BKE_collection_delete(Main *bmain, Collection *collection, bool hierarchy)
/* Link child object into parent collections. */
for (CollectionParent *cparent = collection->parents.first; cparent; cparent = cparent->next) {
Collection *parent = cparent->collection;
- collection_object_add(parent, cob->ob, 0, true);
+ collection_object_add(bmain, parent, cob->ob, 0, true);
}
/* Remove child object. */
@@ -190,7 +190,7 @@ bool BKE_collection_delete(Main *bmain, Collection *collection, bool hierarchy)
* \param flag Copying options (see BKE_library.h's LIB_ID_COPY_... flags for more).
*/
void BKE_collection_copy_data(
- Main *UNUSED(bmain), Collection *collection_dst, const Collection *collection_src, const int flag)
+ Main *bmain, Collection *collection_dst, const Collection *collection_src, const int flag)
{
/* Do not copy collection's preview (same behavior as for objects). */
if ((flag & LIB_ID_COPY_NO_PREVIEW) == 0 && false) { /* XXX TODO temp hack */
@@ -211,7 +211,7 @@ void BKE_collection_copy_data(
collection_child_add(collection_dst, child->collection, flag, false);
}
for (CollectionObject *cob = collection_src->gobject.first; cob; cob = cob->next) {
- collection_object_add(collection_dst, cob->ob, flag, false);
+ collection_object_add(bmain, collection_dst, cob->ob, flag, false);
}
}
@@ -311,23 +311,6 @@ bool BKE_collection_is_animated(Collection *collection, Object *UNUSED(parent))
return false;
}
-/* puts all collection members in local timing system, after this call
- * you can draw everything, leaves tags in objects to signal it needs further updating */
-
-/* note: does not work for derivedmesh and render... it recreates all again in convertblender.c */
-void BKE_collection_handle_recalc_and_update(
- struct Depsgraph *depsgraph, Scene *scene, Object *UNUSED(parent), Collection *collection)
-{
- /* only do existing tags, as set by regular depsgraph */
- FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN(collection, object)
- {
- if (object->id.recalc & ID_RECALC_ALL) {
- BKE_object_handle_update(depsgraph, scene, object);
- }
- }
- FOREACH_COLLECTION_OBJECT_RECURSIVE_END;
-}
-
/* **************** Object List Cache *******************/
static void collection_object_cache_fill(ListBase *lb, Collection *collection, int parent_restrict)
@@ -367,12 +350,12 @@ ListBase BKE_collection_object_cache_get(Collection *collection)
if (!(collection->flag & COLLECTION_HAS_OBJECT_CACHE)) {
static ThreadMutex cache_lock = BLI_MUTEX_INITIALIZER;
+ BLI_mutex_lock(&cache_lock);
if (!(collection->flag & COLLECTION_HAS_OBJECT_CACHE)) {
- BLI_mutex_lock(&cache_lock);
collection_object_cache_fill(&collection->object_cache, collection, 0);
collection->flag |= COLLECTION_HAS_OBJECT_CACHE;
- BLI_mutex_unlock(&cache_lock);
}
+ BLI_mutex_unlock(&cache_lock);
}
return collection->object_cache;
@@ -522,7 +505,7 @@ Collection *BKE_collection_object_find(Main *bmain, Collection *collection, Obje
/********************** Collection Objects *********************/
-static bool collection_object_add(Collection *collection, Object *ob, int flag, const bool add_us)
+static bool collection_object_add(Main *bmain, Collection *collection, Object *ob, int flag, const bool add_us)
{
if (ob->dup_group) {
/* Cyclic dependency check. */
@@ -545,6 +528,10 @@ static bool collection_object_add(Collection *collection, Object *ob, int flag,
id_us_plus(&ob->id);
}
+ if ((flag & LIB_ID_CREATE_NO_MAIN) == 0) {
+ DEG_id_tag_update_ex(bmain, &collection->id, DEG_TAG_COPY_ON_WRITE);
+ }
+
return true;
}
@@ -565,6 +552,8 @@ static bool collection_object_remove(Main *bmain, Collection *collection, Object
id_us_min(&ob->id);
}
+ DEG_id_tag_update_ex(bmain, &collection->id, DEG_TAG_COPY_ON_WRITE);
+
return true;
}
@@ -577,7 +566,7 @@ bool BKE_collection_object_add(Main *bmain, Collection *collection, Object *ob)
return false;
}
- if (!collection_object_add(collection, ob, 0, true)) {
+ if (!collection_object_add(bmain, collection, ob, 0, true)) {
return false;
}
@@ -597,7 +586,7 @@ void BKE_collection_object_add_from(Main *bmain, Scene *scene, Object *ob_src, O
FOREACH_SCENE_COLLECTION_BEGIN(scene, collection)
{
if (BKE_collection_has_object(collection, ob_src)) {
- collection_object_add(collection, ob_dst, 0, true);
+ collection_object_add(bmain, collection, ob_dst, 0, true);
}
}
FOREACH_SCENE_COLLECTION_END;
diff --git a/source/blender/blenkernel/intern/data_transfer.c b/source/blender/blenkernel/intern/data_transfer.c
index 0451031c5b8..3639649eab5 100644
--- a/source/blender/blenkernel/intern/data_transfer.c
+++ b/source/blender/blenkernel/intern/data_transfer.c
@@ -50,6 +50,7 @@
#include "BKE_DerivedMesh.h"
#include "BKE_mesh.h"
#include "BKE_mesh_mapping.h"
+#include "BKE_mesh_runtime.h"
#include "BKE_mesh_remap.h"
#include "BKE_object.h"
#include "BKE_object_deform.h"
diff --git a/source/blender/blenkernel/intern/displist.c b/source/blender/blenkernel/intern/displist.c
index fa996b8f73e..a591ab354f6 100644
--- a/source/blender/blenkernel/intern/displist.c
+++ b/source/blender/blenkernel/intern/displist.c
@@ -37,6 +37,7 @@
#include "MEM_guardedalloc.h"
#include "DNA_curve_types.h"
+#include "DNA_mesh_types.h"
#include "DNA_scene_types.h"
#include "DNA_object_types.h"
#include "DNA_vfont_types.h"
@@ -51,8 +52,10 @@
#include "BKE_displist.h"
#include "BKE_cdderivedmesh.h"
#include "BKE_object.h"
+#include "BKE_library.h"
#include "BKE_mball.h"
#include "BKE_mball_tessellate.h"
+#include "BKE_mesh.h"
#include "BKE_curve.h"
#include "BKE_key.h"
#include "BKE_anim.h"
@@ -925,7 +928,7 @@ static void curve_calc_modifiers_post(
Curve *cu = ob->data;
int required_mode = 0, totvert = 0;
const bool editmode = (!for_render && (cu->editnurb || cu->editfont));
- DerivedMesh *dm = NULL, *ndm;
+ Mesh *modified = NULL, *mesh_applied;
float (*vertCos)[3] = NULL;
int useCache = !for_render;
ModifierApplyFlag app_flag = 0;
@@ -963,23 +966,21 @@ static void curve_calc_modifiers_post(
continue;
if (mti->type == eModifierTypeType_OnlyDeform ||
- (mti->type == eModifierTypeType_DeformOrConstruct && !dm))
+ (mti->type == eModifierTypeType_DeformOrConstruct && !modified))
{
- if (dm) {
+ if (modified) {
if (!vertCos) {
- totvert = dm->getNumVerts(dm);
- vertCos = MEM_mallocN(sizeof(*vertCos) * totvert, "dfmv");
- dm->getVertCos(dm, vertCos);
+ vertCos = BKE_mesh_vertexCos_get(modified, &totvert);
}
- modifier_deformVerts_DM_deprecated(md, &mectx_deform, dm, vertCos, totvert);
+ modifier_deformVerts(md, &mectx_deform, modified, vertCos, totvert);
}
else {
if (!vertCos) {
vertCos = displist_get_allverts(dispbase, &totvert);
}
- modifier_deformVerts_DM_deprecated(md, &mectx_deform, NULL, vertCos, totvert);
+ modifier_deformVerts(md, &mectx_deform, NULL, vertCos, totvert);
}
}
else {
@@ -991,13 +992,17 @@ static void curve_calc_modifiers_post(
break;
}
- if (dm) {
+ if (modified) {
if (vertCos) {
- DerivedMesh *tdm = CDDM_copy(dm);
- dm->release(dm);
- dm = tdm;
-
- CDDM_apply_vert_coords(dm, vertCos);
+ Mesh *temp_mesh;
+ BKE_id_copy_ex(NULL, &modified->id, (ID **)&temp_mesh,
+ LIB_ID_CREATE_NO_MAIN | LIB_ID_CREATE_NO_USER_REFCOUNT |
+ LIB_ID_CREATE_NO_DEG_TAG | LIB_ID_COPY_NO_PREVIEW,
+ false);
+ BKE_id_free(NULL, modified);
+ modified = temp_mesh;
+
+ BKE_mesh_apply_vert_coords(modified, vertCos);
}
}
else {
@@ -1009,7 +1014,7 @@ static void curve_calc_modifiers_post(
curve_to_filledpoly(cu, nurb, dispbase);
}
- dm = CDDM_from_curve_displist(ob, dispbase);
+ modified = BKE_mesh_new_nomain_from_curve_displist(ob, dispbase);
}
if (vertCos) {
@@ -1018,26 +1023,31 @@ static void curve_calc_modifiers_post(
vertCos = NULL;
}
- ndm = modwrap_applyModifier(md, &mectx_apply, dm);
+ mesh_applied = modifier_applyModifier(md, &mectx_apply, modified);
- if (ndm) {
+ if (mesh_applied) {
/* Modifier returned a new derived mesh */
- if (dm && dm != ndm) /* Modifier */
- dm->release(dm);
- dm = ndm;
+ if (modified && modified != mesh_applied) /* Modifier */
+ BKE_id_free(NULL, modified);
+ modified = mesh_applied;
}
}
}
if (vertCos) {
- if (dm) {
- DerivedMesh *tdm = CDDM_copy(dm);
- dm->release(dm);
- dm = tdm;
+ if (modified) {
+ Mesh *temp_mesh;
+ BKE_id_copy_ex(NULL, &modified->id, (ID **)&temp_mesh,
+ LIB_ID_CREATE_NO_MAIN | LIB_ID_CREATE_NO_USER_REFCOUNT |
+ LIB_ID_CREATE_NO_DEG_TAG | LIB_ID_COPY_NO_PREVIEW,
+ false);
+ BKE_id_free(NULL, modified);
+ modified = temp_mesh;
+
+ BKE_mesh_apply_vert_coords(modified, vertCos);
+ BKE_mesh_calc_normals_mapping_simple(modified);
- CDDM_apply_vert_coords(dm, vertCos);
- CDDM_calc_normals_mapping(dm);
MEM_freeN(vertCos);
}
else {
@@ -1048,22 +1058,27 @@ static void curve_calc_modifiers_post(
}
if (r_dm_final) {
- if (dm) {
+ if (modified) {
/* see: mesh_calc_modifiers */
- if (dm->getNumTessFaces(dm) == 0) {
- dm->recalcTessellation(dm);
+ if (modified->totface == 0) {
+ BKE_mesh_tessface_calc(modified);
}
/* Even if tessellation is not needed, some modifiers might have modified CD layers
* (like mloopcol or mloopuv), hence we have to update those. */
- else if (dm->dirty & DM_DIRTY_TESS_CDLAYERS) {
- DM_update_tessface_data(dm);
+ else if (modified->runtime.cd_dirty_vert & CD_MASK_TESSLOOPNORMAL) {
+ BKE_mesh_tessface_calc(modified);
}
- if (dm->type == DM_TYPE_CDDM) {
- CDDM_calc_normals_mapping_ex(dm, (dm->dirty & DM_DIRTY_NORMALS) ? false : true);
- }
+ /* XXX2.8(Sybren): make sure the face normals are recalculated as well */
+ BKE_mesh_ensure_normals(modified);
+
+ (*r_dm_final) = CDDM_from_mesh_ex(modified, CD_DUPLICATE, CD_MASK_MESH);
+ BKE_id_free(NULL, modified);
+ }
+ else {
+ (*r_dm_final) = NULL;
}
- (*r_dm_final) = dm;
+
}
}
@@ -1095,6 +1110,8 @@ static void displist_surf_indices(DispList *dl)
}
}
+/* XXX2.8(Sybren): unused function; impossible to test after porting to Mesh */
+#ifdef WITH_DERIVEDMESH_DEPRECATED_FUNCS
static DerivedMesh *create_orco_dm(Depsgraph *depsgraph, Scene *scene, Object *ob)
{
DerivedMesh *dm;
@@ -1138,7 +1155,10 @@ static void add_orco_dm(Object *ob, DerivedMesh *dm, DerivedMesh *orcodm)
else
DM_add_vert_layer(dm, CD_ORCO, CD_ASSIGN, orco);
}
+#endif
+/* XXX2.8(Sybren): unused function; impossible to test after porting to Mesh */
+#ifdef WITH_DERIVEDMESH_DEPRECATED_FUNCS
static void curve_calc_orcodm(
Depsgraph *depsgraph, Scene *scene, Object *ob, DerivedMesh *dm_final,
const bool for_render, const bool use_render_resolution)
@@ -1208,6 +1228,7 @@ static void curve_calc_orcodm(
orcodm->release(orcodm);
}
+#endif
void BKE_displist_make_surf(
Depsgraph *depsgraph, Scene *scene, Object *ob, ListBase *dispbase,
@@ -1816,6 +1837,8 @@ void BKE_displist_make_curveTypes_forOrco(
}
/* add Orco layer to the displist object which has got derived mesh and return orco */
+/* XXX2.8(Sybren): can be removed once DerivedMesh port is done */
+#ifdef WITH_DERIVEDMESH_DEPRECATED_FUNCS
float *BKE_displist_make_orco(
Depsgraph *depsgraph, Scene *scene, Object *ob, DerivedMesh *dm_final,
const bool for_render,
@@ -1838,6 +1861,7 @@ float *BKE_displist_make_orco(
return orco;
}
+#endif
void BKE_displist_minmax(ListBase *dispbase, float min[3], float max[3])
{
diff --git a/source/blender/blenkernel/intern/dynamicpaint.c b/source/blender/blenkernel/intern/dynamicpaint.c
index 89f5f8facda..36452e1d2cf 100644
--- a/source/blender/blenkernel/intern/dynamicpaint.c
+++ b/source/blender/blenkernel/intern/dynamicpaint.c
@@ -3216,7 +3216,7 @@ void dynamicPaint_outputSurfaceImage(DynamicPaintSurface *surface, char *filenam
BKE_image_path_ensure_ext_from_imtype(output_file, format);
/* Validate output file path */
- BLI_path_abs(output_file, G.main->name);
+ BLI_path_abs(output_file, BKE_main_blendfile_path_from_global());
BLI_make_existing_file(output_file);
/* Init image buffer */
diff --git a/source/blender/blenkernel/intern/font.c b/source/blender/blenkernel/intern/font.c
index 34b185417e3..f7ab5415d1c 100644
--- a/source/blender/blenkernel/intern/font.c
+++ b/source/blender/blenkernel/intern/font.c
@@ -255,8 +255,8 @@ VFont *BKE_vfont_load(Main *bmain, const char *filepath)
}
else {
BLI_split_file_part(filepath, filename, sizeof(filename));
- pf = newPackedFile(NULL, filepath, bmain->name);
- temp_pf = newPackedFile(NULL, filepath, bmain->name);
+ pf = newPackedFile(NULL, filepath, BKE_main_blendfile_path(bmain));
+ temp_pf = newPackedFile(NULL, filepath, BKE_main_blendfile_path(bmain));
is_builtin = false;
}
@@ -301,7 +301,7 @@ VFont *BKE_vfont_load_exists_ex(struct Main *bmain, const char *filepath, bool *
char str[FILE_MAX], strtest[FILE_MAX];
BLI_strncpy(str, filepath, sizeof(str));
- BLI_path_abs(str, bmain->name);
+ BLI_path_abs(str, BKE_main_blendfile_path(bmain));
/* first search an identical filepath */
for (vfont = bmain->vfont.first; vfont; vfont = vfont->id.next) {
diff --git a/source/blender/blenkernel/intern/image.c b/source/blender/blenkernel/intern/image.c
index e5c192b3e1e..9a29a8a898b 100644
--- a/source/blender/blenkernel/intern/image.c
+++ b/source/blender/blenkernel/intern/image.c
@@ -592,7 +592,7 @@ Image *BKE_image_load(Main *bmain, const char *filepath)
char str[FILE_MAX];
STRNCPY(str, filepath);
- BLI_path_abs(str, bmain->name);
+ BLI_path_abs(str, BKE_main_blendfile_path(bmain));
/* exists? */
file = BLI_open(str, O_BINARY | O_RDONLY, 0);
@@ -621,7 +621,7 @@ Image *BKE_image_load_exists_ex(const char *filepath, bool *r_exists)
char str[FILE_MAX], strtest[FILE_MAX];
STRNCPY(str, filepath);
- BLI_path_abs(str, G.main->name);
+ BLI_path_abs(str, BKE_main_blendfile_path_from_global());
/* first search an identical filepath */
for (ima = G.main->image.first; ima; ima = ima->id.next) {
@@ -1648,7 +1648,8 @@ static void stampdata(Scene *scene, Object *camera, StampData *stamp_data, int d
time_t t;
if (scene->r.stamp & R_STAMP_FILENAME) {
- SNPRINTF(stamp_data->file, do_prefix ? "File %s" : "%s", G.relbase_valid ? G.main->name : "<untitled>");
+ SNPRINTF(stamp_data->file, do_prefix ? "File %s" : "%s",
+ G.relbase_valid ? BKE_main_blendfile_path_from_global() : "<untitled>");
}
else {
stamp_data->file[0] = '\0';
@@ -4698,7 +4699,7 @@ static void image_update_views_format(Image *ima, ImageUser *iuser)
char str[FILE_MAX];
STRNCPY(str, iv->filepath);
- BLI_path_abs(str, G.main->name);
+ BLI_path_abs(str, BKE_main_blendfile_path_from_global());
/* exists? */
file = BLI_open(str, O_BINARY | O_RDONLY, 0);
diff --git a/source/blender/blenkernel/intern/layer.c b/source/blender/blenkernel/intern/layer.c
index 16e349465f6..c7bb24cdcee 100644
--- a/source/blender/blenkernel/intern/layer.c
+++ b/source/blender/blenkernel/intern/layer.c
@@ -1264,6 +1264,16 @@ void BKE_layer_eval_view_layer(
/* Store base in the array. */
view_layer->object_bases_array[base_index++] = base;
}
+ if (view_layer == DEG_get_evaluated_view_layer(depsgraph)) {
+ ViewLayer *view_layer_orig = DEG_get_input_view_layer(depsgraph);
+ Base *base_orig = view_layer_orig->object_bases.first;
+ const Base *base_eval = view_layer->object_bases.first;
+ while (base_orig != NULL) {
+ base_orig->flag = base_eval->flag;
+ base_orig = base_orig->next;
+ base_eval = base_eval->next;
+ }
+ }
}
void BKE_layer_eval_view_layer_indexed(
diff --git a/source/blender/blenkernel/intern/library.c b/source/blender/blenkernel/intern/library.c
index 667445e7e17..b9244ee1f83 100644
--- a/source/blender/blenkernel/intern/library.c
+++ b/source/blender/blenkernel/intern/library.c
@@ -155,7 +155,7 @@
* also note that the id _must_ have a library - campbell */
void BKE_id_lib_local_paths(Main *bmain, Library *lib, ID *id)
{
- const char *bpath_user_data[2] = {bmain->name, lib->filepath};
+ const char *bpath_user_data[2] = {BKE_main_blendfile_path(bmain), lib->filepath};
BKE_bpath_traverse_id(bmain, id,
BKE_bpath_relocate_visitor,
@@ -1739,6 +1739,24 @@ void BKE_main_thumbnail_create(struct Main *bmain)
bmain->blen_thumb->height = BLEN_THUMB_SIZE;
}
+/**
+ * Return filepath of given \a main.
+ */
+const char *BKE_main_blendfile_path(const Main *bmain)
+{
+ return bmain->name;
+}
+
+/**
+ * Return filepath of global main (G.main).
+ *
+ * \warning Usage is not recommended, you should always try to get a velid Main pointer from context...
+ */
+const char *BKE_main_blendfile_path_from_global(void)
+{
+ return BKE_main_blendfile_path(G.main);
+}
+
/* ***************** ID ************************ */
ID *BKE_libblock_find_name(struct Main *bmain, const short type, const char *name)
{
@@ -2527,7 +2545,7 @@ void BKE_library_filepath_set(Main *bmain, Library *lib, const char *filepath)
*/
/* Never make paths relative to parent lib - reading code (blenloader) always set *all* lib->name relative to
* current main, not to their parent for indirectly linked ones. */
- const char *basepath = bmain->name;
+ const char *basepath = BKE_main_blendfile_path(bmain);
BLI_path_abs(lib->filepath, basepath);
}
}
diff --git a/source/blender/blenkernel/intern/material.c b/source/blender/blenkernel/intern/material.c
index 109b436292e..1ea2f170922 100644
--- a/source/blender/blenkernel/intern/material.c
+++ b/source/blender/blenkernel/intern/material.c
@@ -1315,7 +1315,5 @@ void paste_matcopybuf(Main *bmain, Material *ma)
void BKE_material_eval(struct Depsgraph *depsgraph, Material *material)
{
DEG_debug_print_eval(depsgraph, __func__, material->id.name, material);
- if ((BLI_listbase_is_empty(&material->gpumaterial) == false)) {
- GPU_material_uniform_buffer_tag_dirty(&material->gpumaterial);
- }
+ GPU_material_free(&material->gpumaterial);
}
diff --git a/source/blender/blenkernel/intern/mball.c b/source/blender/blenkernel/intern/mball.c
index 339e79f2757..3afaf2d569e 100644
--- a/source/blender/blenkernel/intern/mball.c
+++ b/source/blender/blenkernel/intern/mball.c
@@ -563,11 +563,6 @@ void BKE_mball_select_swap(struct MetaBall *mb)
/* **** Depsgraph evaluation **** */
-void BKE_mball_eval_geometry(struct Depsgraph *UNUSED(depsgraph),
- MetaBall *UNUSED(mball))
-{
-}
-
/* Draw Engine */
void (*BKE_mball_batch_cache_dirty_cb)(MetaBall *mb, int mode) = NULL;
diff --git a/source/blender/blenkernel/intern/mesh.c b/source/blender/blenkernel/intern/mesh.c
index d27809586c2..b325d8d02d9 100644
--- a/source/blender/blenkernel/intern/mesh.c
+++ b/source/blender/blenkernel/intern/mesh.c
@@ -46,6 +46,7 @@
#include "BKE_DerivedMesh.h"
#include "BKE_global.h"
#include "BKE_mesh.h"
+#include "BKE_mesh_runtime.h"
#include "BKE_library.h"
#include "BKE_material.h"
#include "BKE_modifier.h"
@@ -581,6 +582,34 @@ void BKE_mesh_copy_data(Main *bmain, Mesh *me_dst, const Mesh *me_src, const int
}
}
+/* Custom data layer functions; those assume that totXXX are set correctly. */
+static void mesh_ensure_cdlayers_primary(Mesh *mesh, bool do_tessface)
+{
+ if (!CustomData_get_layer(&mesh->vdata, CD_MVERT))
+ CustomData_add_layer(&mesh->vdata, CD_MVERT, CD_CALLOC, NULL, mesh->totvert);
+ if (!CustomData_get_layer(&mesh->edata, CD_MEDGE))
+ CustomData_add_layer(&mesh->edata, CD_MEDGE, CD_CALLOC, NULL, mesh->totedge);
+ if (!CustomData_get_layer(&mesh->ldata, CD_MLOOP))
+ CustomData_add_layer(&mesh->ldata, CD_MLOOP, CD_CALLOC, NULL, mesh->totloop);
+ if (!CustomData_get_layer(&mesh->pdata, CD_MPOLY))
+ CustomData_add_layer(&mesh->pdata, CD_MPOLY, CD_CALLOC, NULL, mesh->totpoly);
+
+ if (do_tessface && !CustomData_get_layer(&mesh->fdata, CD_MFACE))
+ CustomData_add_layer(&mesh->fdata, CD_MFACE, CD_CALLOC, NULL, mesh->totface);
+}
+static void mesh_ensure_cdlayers_origindex(Mesh *mesh, bool do_tessface)
+{
+ if (!CustomData_get_layer(&mesh->vdata, CD_ORIGINDEX))
+ CustomData_add_layer(&mesh->vdata, CD_ORIGINDEX, CD_CALLOC, NULL, mesh->totvert);
+ if (!CustomData_get_layer(&mesh->edata, CD_ORIGINDEX))
+ CustomData_add_layer(&mesh->edata, CD_ORIGINDEX, CD_CALLOC, NULL, mesh->totedge);
+ if (!CustomData_get_layer(&mesh->pdata, CD_ORIGINDEX))
+ CustomData_add_layer(&mesh->pdata, CD_ORIGINDEX, CD_CALLOC, NULL, mesh->totpoly);
+
+ if (do_tessface && !CustomData_get_layer(&mesh->fdata, CD_ORIGINDEX))
+ CustomData_add_layer(&mesh->fdata, CD_ORIGINDEX, CD_CALLOC, NULL, mesh->totface);
+}
+
Mesh *BKE_mesh_new_nomain(int verts_len, int edges_len, int tessface_len, int loops_len, int polys_len)
{
Mesh *mesh = BKE_libblock_alloc(
@@ -598,28 +627,16 @@ Mesh *BKE_mesh_new_nomain(int verts_len, int edges_len, int tessface_len, int lo
copy_vn_i(mesh->ldata.typemap, CD_NUMTYPES, -1);
copy_vn_i(mesh->pdata.typemap, CD_NUMTYPES, -1);
- CustomData_add_layer(&mesh->vdata, CD_ORIGINDEX, CD_CALLOC, NULL, verts_len);
- CustomData_add_layer(&mesh->edata, CD_ORIGINDEX, CD_CALLOC, NULL, edges_len);
- CustomData_add_layer(&mesh->fdata, CD_ORIGINDEX, CD_CALLOC, NULL, tessface_len);
- CustomData_add_layer(&mesh->pdata, CD_ORIGINDEX, CD_CALLOC, NULL, polys_len);
-
- CustomData_add_layer(&mesh->vdata, CD_MVERT, CD_CALLOC, NULL, verts_len);
- CustomData_add_layer(&mesh->edata, CD_MEDGE, CD_CALLOC, NULL, edges_len);
- CustomData_add_layer(&mesh->fdata, CD_MFACE, CD_CALLOC, NULL, tessface_len);
- CustomData_add_layer(&mesh->ldata, CD_MLOOP, CD_CALLOC, NULL, loops_len);
- CustomData_add_layer(&mesh->pdata, CD_MPOLY, CD_CALLOC, NULL, polys_len);
-
- mesh->mvert = CustomData_get_layer(&mesh->vdata, CD_MVERT);
- mesh->medge = CustomData_get_layer(&mesh->edata, CD_MEDGE);
- mesh->mface = CustomData_get_layer(&mesh->fdata, CD_MFACE);
- mesh->mloop = CustomData_get_layer(&mesh->ldata, CD_MLOOP);
- mesh->mpoly = CustomData_get_layer(&mesh->pdata, CD_MPOLY);
-
mesh->totvert = verts_len;
mesh->totedge = edges_len;
+ mesh->totface = tessface_len;
mesh->totloop = loops_len;
mesh->totpoly = polys_len;
+ mesh_ensure_cdlayers_primary(mesh, true);
+ mesh_ensure_cdlayers_origindex(mesh, true);
+ BKE_mesh_update_customdata_pointers(mesh, false);
+
return mesh;
}
@@ -638,6 +655,7 @@ static Mesh *mesh_new_nomain_from_template_ex(
me_dst->totvert = verts_len;
me_dst->totedge = edges_len;
+ me_dst->totface = tessface_len;
me_dst->totloop = loops_len;
me_dst->totpoly = polys_len;
@@ -652,15 +670,12 @@ static Mesh *mesh_new_nomain_from_template_ex(
mesh_tessface_clear_intern(me_dst, false);
}
+ /* The destination mesh should at least have valid primary CD layers,
+ * even in cases where the source mesh does not. */
+ mesh_ensure_cdlayers_primary(me_dst, do_tessface);
+ mesh_ensure_cdlayers_origindex(me_dst, false);
BKE_mesh_update_customdata_pointers(me_dst, false);
- if (!CustomData_get_layer(&me_dst->vdata, CD_ORIGINDEX))
- CustomData_add_layer(&me_dst->vdata, CD_ORIGINDEX, CD_CALLOC, NULL, verts_len);
- if (!CustomData_get_layer(&me_dst->edata, CD_ORIGINDEX))
- CustomData_add_layer(&me_dst->edata, CD_ORIGINDEX, CD_CALLOC, NULL, edges_len);
- if (!CustomData_get_layer(&me_dst->pdata, CD_ORIGINDEX))
- CustomData_add_layer(&me_dst->pdata, CD_ORIGINDEX, CD_CALLOC, NULL, polys_len);
-
return me_dst;
}
diff --git a/source/blender/blenkernel/intern/mesh_convert.c b/source/blender/blenkernel/intern/mesh_convert.c
index a3eef7b17b2..acd0cf32b13 100644
--- a/source/blender/blenkernel/intern/mesh_convert.c
+++ b/source/blender/blenkernel/intern/mesh_convert.c
@@ -43,6 +43,7 @@
#include "BKE_global.h"
#include "BKE_key.h"
#include "BKE_mesh.h"
+#include "BKE_mesh_runtime.h"
#include "BKE_modifier.h"
#include "BKE_displist.h"
#include "BKE_library.h"
@@ -1263,7 +1264,7 @@ static void shapekey_layers_to_keyblocks(Mesh *mesh_src, Mesh *mesh_dst, int act
/* This is a Mesh-based copy of DM_to_mesh() */
-void BKE_nomain_mesh_to_mesh(Mesh *mesh_src, Mesh *mesh_dst, Object *ob, CustomDataMask mask, bool take_ownership)
+void BKE_mesh_nomain_to_mesh(Mesh *mesh_src, Mesh *mesh_dst, Object *ob, CustomDataMask mask, bool take_ownership)
{
/* mesh_src might depend on mesh_dst, so we need to do everything with a local copy */
/* TODO(Sybren): the above claim came from DM_to_mesh(); check whether it is still true with Mesh */
@@ -1414,7 +1415,7 @@ void BKE_nomain_mesh_to_mesh(Mesh *mesh_src, Mesh *mesh_dst, Object *ob, CustomD
}
/* This is a Mesh-based copy of DM_to_meshkey() */
-void BKE_nomain_mesh_to_meshkey(Mesh *mesh_src, Mesh *mesh_dst, KeyBlock *kb)
+void BKE_mesh_nomain_to_meshkey(Mesh *mesh_src, Mesh *mesh_dst, KeyBlock *kb)
{
int a, totvert = mesh_src->totvert;
float *fp;
diff --git a/source/blender/blenkernel/intern/mesh_evaluate.c b/source/blender/blenkernel/intern/mesh_evaluate.c
index 068be0ef304..2d8476d6f02 100644
--- a/source/blender/blenkernel/intern/mesh_evaluate.c
+++ b/source/blender/blenkernel/intern/mesh_evaluate.c
@@ -88,6 +88,20 @@ static void mesh_calc_normals_vert_fallback(MVert *mverts, int numVerts)
}
}
+/* TODO(Sybren): we can probably rename this to BKE_mesh_calc_normals_mapping(),
+ * and remove the function of the same name below, as that one doesn't seem to be
+ * called anywhere. */
+void BKE_mesh_calc_normals_mapping_simple(struct Mesh *mesh)
+{
+ const bool only_face_normals = CustomData_is_referenced_layer(&mesh->vdata, CD_MVERT);
+
+ BKE_mesh_calc_normals_mapping_ex(
+ mesh->mvert, mesh->totvert,
+ mesh->mloop, mesh->mpoly, mesh->totloop, mesh->totpoly, NULL,
+ mesh->mface, mesh->totface, NULL, NULL,
+ only_face_normals);
+}
+
/* Calculate vertex and face normals, face normals are returned in *r_faceNors if non-NULL
* and vertex normals are stored in actual mverts.
*/
diff --git a/source/blender/blenkernel/intern/mesh_runtime.c b/source/blender/blenkernel/intern/mesh_runtime.c
index c8416811694..cd9db408d19 100644
--- a/source/blender/blenkernel/intern/mesh_runtime.c
+++ b/source/blender/blenkernel/intern/mesh_runtime.c
@@ -35,13 +35,22 @@
#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
+#include "DNA_object_types.h"
#include "BLI_math_geom.h"
#include "BLI_threads.h"
#include "BKE_bvhutils.h"
#include "BKE_mesh.h"
+#include "BKE_mesh_runtime.h"
+#ifdef USE_DERIVEDMESH
+#include "BKE_DerivedMesh.h"
+#endif
+
+/* -------------------------------------------------------------------- */
+/** \name Mesh Runtime Struct Utils
+ * \{ */
static ThreadRWMutex loops_cache_lock = PTHREAD_RWLOCK_INITIALIZER;
@@ -145,8 +154,9 @@ const MLoopTri *BKE_mesh_runtime_looptri_ensure(Mesh *mesh)
}
/* This is a copy of DM_verttri_from_looptri(). */
-void BKE_mesh_runtime_verttri_from_looptri(MVertTri *r_verttri, const MLoop *mloop,
- const MLoopTri *looptri, int looptri_num)
+void BKE_mesh_runtime_verttri_from_looptri(
+ MVertTri *r_verttri, const MLoop *mloop,
+ const MLoopTri *looptri, int looptri_num)
{
int i;
for (i = 0; i < looptri_num; i++) {
@@ -192,6 +202,12 @@ void BKE_mesh_runtime_clear_geometry(Mesh *mesh)
MEM_SAFE_FREE(mesh->runtime.looptris.array);
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Mesh Batch Cache Callbacks
+ * \{ */
+
/* Draw Engine */
void (*BKE_mesh_batch_cache_dirty_cb)(Mesh *me, int mode) = NULL;
void (*BKE_mesh_batch_cache_free_cb)(Mesh *me) = NULL;
@@ -208,3 +224,5 @@ void BKE_mesh_batch_cache_free(Mesh *me)
BKE_mesh_batch_cache_free_cb(me);
}
}
+
+/** \} */
diff --git a/source/blender/blenkernel/intern/movieclip.c b/source/blender/blenkernel/intern/movieclip.c
index d742bcea69d..fc236cc2ad0 100644
--- a/source/blender/blenkernel/intern/movieclip.c
+++ b/source/blender/blenkernel/intern/movieclip.c
@@ -199,7 +199,7 @@ static void get_proxy_fname(const MovieClip *clip,
else
BLI_snprintf(name, FILE_MAX, "%s/%s/proxy_%d/%08d", dir, clipfile, size, proxynr);
- BLI_path_abs(name, G.main->name);
+ BLI_path_abs(name, BKE_main_blendfile_path_from_global());
BLI_path_frame(name, 1, 0);
strcat(name, ".jpg");
@@ -270,7 +270,7 @@ static void movieclip_open_anim_file(MovieClip *clip)
if (clip->flag & MCLIP_USE_PROXY_CUSTOM_DIR) {
char dir[FILE_MAX];
BLI_strncpy(dir, clip->proxy.dir, sizeof(dir));
- BLI_path_abs(dir, G.main->name);
+ BLI_path_abs(dir, BKE_main_blendfile_path_from_global());
IMB_anim_set_index_dir(clip->anim, dir);
}
}
@@ -627,13 +627,13 @@ static void movieclip_load_get_size(MovieClip *clip)
}
}
-static void detect_clip_source(MovieClip *clip)
+static void detect_clip_source(Main *bmain, MovieClip *clip)
{
ImBuf *ibuf;
char name[FILE_MAX];
BLI_strncpy(name, clip->name, sizeof(name));
- BLI_path_abs(name, G.main->name);
+ BLI_path_abs(name, BKE_main_blendfile_path(bmain));
ibuf = IMB_testiffname(name, IB_rect | IB_multilayer);
if (ibuf) {
@@ -656,7 +656,7 @@ MovieClip *BKE_movieclip_file_add(Main *bmain, const char *name)
char str[FILE_MAX];
BLI_strncpy(str, name, sizeof(str));
- BLI_path_abs(str, bmain->name);
+ BLI_path_abs(str, BKE_main_blendfile_path(bmain));
/* exists? */
file = BLI_open(str, O_BINARY | O_RDONLY, 0);
@@ -670,7 +670,7 @@ MovieClip *BKE_movieclip_file_add(Main *bmain, const char *name)
clip = movieclip_alloc(bmain, BLI_path_basename(name));
BLI_strncpy(clip->name, name, sizeof(clip->name));
- detect_clip_source(clip);
+ detect_clip_source(bmain, clip);
movieclip_load_get_size(clip);
if (clip->lastsize[0]) {
@@ -690,7 +690,7 @@ MovieClip *BKE_movieclip_file_add_exists_ex(Main *bmain, const char *filepath, b
char str[FILE_MAX], strtest[FILE_MAX];
BLI_strncpy(str, filepath, sizeof(str));
- BLI_path_abs(str, bmain->name);
+ BLI_path_abs(str, BKE_main_blendfile_path(bmain));
/* first search an identical filepath */
for (clip = bmain->movieclip.first; clip; clip = clip->id.next) {
@@ -1282,13 +1282,13 @@ void BKE_movieclip_clear_proxy_cache(MovieClip *clip)
}
}
-void BKE_movieclip_reload(MovieClip *clip)
+void BKE_movieclip_reload(Main *bmain, MovieClip *clip)
{
/* clear cache */
free_buffers(clip);
/* update clip source */
- detect_clip_source(clip);
+ detect_clip_source(bmain, clip);
clip->lastsize[0] = clip->lastsize[1] = 0;
movieclip_load_get_size(clip);
diff --git a/source/blender/blenkernel/intern/multires.c b/source/blender/blenkernel/intern/multires.c
index ee32c2398b2..39a472241bc 100644
--- a/source/blender/blenkernel/intern/multires.c
+++ b/source/blender/blenkernel/intern/multires.c
@@ -51,6 +51,7 @@
#include "BKE_cdderivedmesh.h"
#include "BKE_mesh.h"
#include "BKE_mesh_mapping.h"
+#include "BKE_mesh_runtime.h"
#include "BKE_modifier.h"
#include "BKE_multires.h"
#include "BKE_paint.h"
diff --git a/source/blender/blenkernel/intern/node.c b/source/blender/blenkernel/intern/node.c
index 7a1f6c5d2b6..bf25306028f 100644
--- a/source/blender/blenkernel/intern/node.c
+++ b/source/blender/blenkernel/intern/node.c
@@ -3739,43 +3739,9 @@ void BKE_nodetree_remove_layer_n(bNodeTree *ntree, Scene *scene, const int layer
}
}
-static void node_copy_default_values_list(ListBase *sockets_dst,
- const ListBase *sockets_src)
-{
- bNodeSocket *sock_dst = sockets_dst->first;
- const bNodeSocket *sock_src = sockets_src->first;
- while (sock_dst != NULL) {
- node_socket_copy_default_value(sock_dst, sock_src);
- sock_dst = sock_dst->next;
- sock_src = sock_src->next;
- }
-}
-
-static void node_copy_default_values(bNode *node_dst, const bNode *node_src)
-{
- node_copy_default_values_list(&node_dst->inputs, &node_src->inputs);
- node_copy_default_values_list(&node_dst->outputs, &node_src->outputs);
-}
-
-void BKE_nodetree_copy_default_values(bNodeTree *ntree_dst,
- const bNodeTree *ntree_src)
-{
- if (ntree_dst == ntree_src) {
- return;
- }
- bNode *node_dst = ntree_dst->nodes.first;
- const bNode *node_src = ntree_src->nodes.first;
- while (node_dst != NULL) {
- node_copy_default_values(node_dst, node_src);
- node_dst = node_dst->next;
- node_src = node_src->next;
- }
-}
-
void BKE_nodetree_shading_params_eval(struct Depsgraph *depsgraph,
bNodeTree *ntree_dst,
const bNodeTree *ntree_src)
{
DEG_debug_print_eval(depsgraph, __func__, ntree_src->id.name, ntree_dst);
- BKE_nodetree_copy_default_values(ntree_dst, ntree_src);
}
diff --git a/source/blender/blenkernel/intern/object.c b/source/blender/blenkernel/intern/object.c
index 522ed65174c..f55925f64f5 100644
--- a/source/blender/blenkernel/intern/object.c
+++ b/source/blender/blenkernel/intern/object.c
@@ -330,16 +330,7 @@ void BKE_object_free_derived_caches(Object *ob)
ob->bb = NULL;
}
- if (ob->derivedFinal) {
- ob->derivedFinal->needsFree = 1;
- ob->derivedFinal->release(ob->derivedFinal);
- ob->derivedFinal = NULL;
- }
- if (ob->derivedDeform) {
- ob->derivedDeform->needsFree = 1;
- ob->derivedDeform->release(ob->derivedDeform);
- ob->derivedDeform = NULL;
- }
+ BKE_object_free_derived_mesh_caches(ob);
if (ob->runtime.mesh_eval != NULL) {
Mesh *mesh_eval = ob->runtime.mesh_eval;
@@ -365,6 +356,20 @@ void BKE_object_free_derived_caches(Object *ob)
BKE_object_free_curve_cache(ob);
}
+void BKE_object_free_derived_mesh_caches(struct Object *ob)
+{
+ if (ob->derivedFinal) {
+ ob->derivedFinal->needsFree = 1;
+ ob->derivedFinal->release(ob->derivedFinal);
+ ob->derivedFinal = NULL;
+ }
+ if (ob->derivedDeform) {
+ ob->derivedDeform->needsFree = 1;
+ ob->derivedDeform->release(ob->derivedDeform);
+ ob->derivedDeform = NULL;
+ }
+}
+
void BKE_object_free_caches(Object *object)
{
ModifierData *md;
@@ -2875,8 +2880,7 @@ Mesh *BKE_object_get_pre_modified_mesh(Object *object)
if (object->runtime.mesh_orig != NULL) {
BLI_assert(object->id.tag & LIB_TAG_COPIED_ON_WRITE);
BLI_assert(object->id.orig_id != NULL);
- BLI_assert(object->runtime.mesh_orig->id.orig_id ==
- ((Object*)object->id.orig_id)->data);
+ BLI_assert(object->runtime.mesh_orig->id.orig_id == ((Object *)object->id.orig_id)->data);
Mesh *result = object->runtime.mesh_orig;
BLI_assert((result->id.tag & LIB_TAG_COPIED_ON_WRITE) != 0);
BLI_assert((result->id.tag & LIB_TAG_COPIED_ON_WRITE_EVAL_RESULT) == 0);
@@ -2900,7 +2904,7 @@ Mesh *BKE_object_get_original_mesh(Object *object)
}
else {
BLI_assert((object->id.tag & LIB_TAG_COPIED_ON_WRITE) != 0);
- result = ((Object*)object->id.orig_id)->data;
+ result = ((Object *)object->id.orig_id)->data;
}
BLI_assert(result != NULL);
BLI_assert((result->id.tag & (LIB_TAG_COPIED_ON_WRITE | LIB_TAG_COPIED_ON_WRITE_EVAL_RESULT)) == 0);
diff --git a/source/blender/blenkernel/intern/object_dupli.c b/source/blender/blenkernel/intern/object_dupli.c
index 2c94dc76854..324ad3a31dc 100644
--- a/source/blender/blenkernel/intern/object_dupli.c
+++ b/source/blender/blenkernel/intern/object_dupli.c
@@ -56,6 +56,7 @@
#include "BKE_lattice.h"
#include "BKE_main.h"
#include "BKE_mesh.h"
+#include "BKE_mesh_runtime.h"
#include "BKE_object.h"
#include "BKE_particle.h"
#include "BKE_scene.h"
@@ -72,8 +73,6 @@
typedef struct DupliContext {
Depsgraph *depsgraph;
- bool do_update;
- bool animated;
Collection *collection; /* XXX child objects are selected from this group if set, could be nicer */
Object *obedit; /* Only to check if the object is in edit-mode. */
@@ -99,14 +98,11 @@ 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, Depsgraph *depsgraph, Scene *scene, Object *ob, float space_mat[4][4], bool update)
+static void init_context(DupliContext *r_ctx, Depsgraph *depsgraph, Scene *scene, Object *ob, float space_mat[4][4])
{
r_ctx->depsgraph = depsgraph;
r_ctx->scene = scene;
r_ctx->view_layer = DEG_get_evaluated_view_layer(depsgraph);
- /* don't allow BKE_object_handle_update for viewport during render, can crash */
- r_ctx->do_update = update && !(G.is_rendering && DEG_get_mode(depsgraph) != DAG_EVAL_RENDER);
- r_ctx->animated = false;
r_ctx->collection = NULL;
r_ctx->object = ob;
@@ -123,12 +119,10 @@ static void init_context(DupliContext *r_ctx, Depsgraph *depsgraph, Scene *scene
}
/* create sub-context for recursive duplis */
-static void copy_dupli_context(DupliContext *r_ctx, const DupliContext *ctx, Object *ob, float mat[4][4], int index, bool animated)
+static void copy_dupli_context(DupliContext *r_ctx, const DupliContext *ctx, Object *ob, float mat[4][4], int index)
{
*r_ctx = *ctx;
- r_ctx->animated |= animated; /* object animation makes all children animated */
-
/* XXX annoying, previously was done by passing an ID* argument, this at least is more explicit */
if (ctx->gen->type == OB_DUPLICOLLECTION)
r_ctx->collection = ctx->object->dup_group;
@@ -146,8 +140,7 @@ static void copy_dupli_context(DupliContext *r_ctx, const DupliContext *ctx, Obj
* mat is transform of the object relative to current context (including object obmat)
*/
static DupliObject *make_dupli(const DupliContext *ctx,
- Object *ob, float mat[4][4], int index,
- bool animated, bool hide)
+ Object *ob, float mat[4][4], int index)
{
DupliObject *dob;
int i;
@@ -164,7 +157,6 @@ static DupliObject *make_dupli(const DupliContext *ctx,
dob->ob = ob;
mul_m4_m4m4(dob->mat, (float (*)[4])ctx->space_mat, mat);
dob->type = ctx->gen->type;
- dob->animated = animated || ctx->animated; /* object itself or some parent is animated */
/* set persistent id, which is an array with a persistent index for each level
* (particle number, vertex number, ..). by comparing this we can find the same
@@ -177,8 +169,6 @@ static DupliObject *make_dupli(const DupliContext *ctx,
for (; i < MAX_DUPLI_RECUR; i++)
dob->persistent_id[i] = INT_MAX;
- if (hide)
- dob->no_draw = true;
/* metaballs never draw in duplis, they are instead merged into one by the basis
* mball outside of the group. this does mean that if that mball is not in the
* scene, they will not show up at all, limitation that should be solved once. */
@@ -208,12 +198,12 @@ static DupliObject *make_dupli(const DupliContext *ctx,
/* recursive dupli objects
* space_mat is the local dupli space (excluding dupli object obmat!)
*/
-static void make_recursive_duplis(const DupliContext *ctx, Object *ob, float space_mat[4][4], int index, bool animated)
+static void make_recursive_duplis(const DupliContext *ctx, Object *ob, float space_mat[4][4], int index)
{
/* simple preventing of too deep nested collections with MAX_DUPLI_RECUR */
if (ctx->level < MAX_DUPLI_RECUR) {
DupliContext rctx;
- copy_dupli_context(&rctx, ctx, ob, space_mat, index, animated);
+ copy_dupli_context(&rctx, ctx, ob, space_mat, index);
if (rctx.gen) {
rctx.gen->make_duplis(&rctx);
}
@@ -247,7 +237,7 @@ static void make_child_duplis(const DupliContext *ctx, void *userdata, MakeChild
Object *ob = base->object;
if ((base->flag & BASE_VISIBLED) && ob != ctx->obedit && is_child(ob, parent)) {
DupliContext pctx;
- copy_dupli_context(&pctx, ctx, ctx->object, NULL, collectionid, false);
+ copy_dupli_context(&pctx, ctx, ctx->object, NULL, collectionid);
/* mballs have a different dupli handling */
if (ob->type != OB_MBALL) {
@@ -266,7 +256,7 @@ static void make_child_duplis(const DupliContext *ctx, void *userdata, MakeChild
Object *ob = base->object;
if ((ob != ctx->obedit) && is_child(ob, parent)) {
DupliContext pctx;
- copy_dupli_context(&pctx, ctx, ctx->object, NULL, baseid, false);
+ copy_dupli_context(&pctx, ctx, ctx->object, NULL, baseid);
/* mballs have a different dupli handling */
if (ob->type != OB_MBALL)
@@ -289,7 +279,6 @@ static void make_duplis_collection(const DupliContext *ctx)
Base *base;
float collection_mat[4][4];
int id;
- bool animated;
if (ob->dup_group == NULL) return;
collection = ob->dup_group;
@@ -300,17 +289,6 @@ static void make_duplis_collection(const DupliContext *ctx)
mul_m4_m4m4(collection_mat, ob->obmat, collection_mat);
/* don't access 'ob->obmat' from now on. */
- /* handles animated collections */
-
- /* 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_collection_handle_recalc_and_update(ctx->depsgraph, ctx->scene, ob, collection);
- }
-
- animated = BKE_collection_is_animated(collection, ob);
-
const ListBase dup_collection_objects = BKE_collection_object_cache_get(collection);
for (base = dup_collection_objects.first, id = 0; base; base = base->next, id++) {
if (base->object != ob && (base->flag & BASE_VISIBLED)) {
@@ -319,10 +297,10 @@ static void make_duplis_collection(const DupliContext *ctx)
/* collection dupli offset, should apply after everything else */
mul_m4_m4m4(mat, collection_mat, base->object->obmat);
- make_dupli(ctx, base->object, mat, id, animated, false);
+ make_dupli(ctx, base->object, mat, id);
/* recursion */
- make_recursive_duplis(ctx, base->object, collection_mat, id, animated);
+ make_recursive_duplis(ctx, base->object, collection_mat, id);
}
}
}
@@ -383,7 +361,7 @@ static void make_duplis_frames(const DupliContext *ctx)
BKE_animsys_evaluate_animdata(depsgraph, scene, &ob->id, ob->adt, (float)scene->r.cfra, ADT_RECALC_ANIM);
BKE_object_where_is_calc_time(depsgraph, scene, ob, (float)scene->r.cfra);
- make_dupli(ctx, ob, ob->obmat, scene->r.cfra, false, false);
+ make_dupli(ctx, ob, ob->obmat, scene->r.cfra);
}
}
@@ -469,13 +447,13 @@ static void vertex_dupli__mapFunc(void *userData, int index, const float co[3],
*/
mul_m4_m4m4(space_mat, obmat, inst_ob->imat);
- dob = make_dupli(vdd->ctx, vdd->inst_ob, obmat, index, false, false);
+ dob = make_dupli(vdd->ctx, vdd->inst_ob, obmat, index);
if (vdd->orco)
copy_v3_v3(dob->orco, vdd->orco[index]);
/* recursion */
- make_recursive_duplis(vdd->ctx, vdd->inst_ob, space_mat, index, false);
+ make_recursive_duplis(vdd->ctx, vdd->inst_ob, space_mat, index);
}
static void make_child_duplis_verts(const DupliContext *ctx, void *userdata, Object *child)
@@ -654,7 +632,7 @@ static void make_duplis_font(const DupliContext *ctx)
copy_v3_v3(obmat[3], vec);
- make_dupli(ctx, ob, obmat, a, false, false);
+ make_dupli(ctx, ob, obmat, a);
}
}
@@ -760,7 +738,7 @@ static void make_child_duplis_faces(const DupliContext *ctx, void *userdata, Obj
*/
mul_m4_m4m4(space_mat, obmat, inst_ob->imat);
- dob = make_dupli(ctx, inst_ob, obmat, a, false, false);
+ dob = make_dupli(ctx, inst_ob, obmat, a);
if (use_texcoords) {
float w = 1.0f / (float)mp->totloop;
@@ -780,7 +758,7 @@ static void make_child_duplis_faces(const DupliContext *ctx, void *userdata, Obj
}
/* recursion */
- make_recursive_duplis(ctx, inst_ob, space_mat, a, false);
+ make_recursive_duplis(ctx, inst_ob, space_mat, a);
}
}
@@ -925,10 +903,6 @@ static void make_duplis_particle_system(const DupliContext *ctx, ParticleSystem
/* gather list of objects or single object */
if (part->ren_as == PART_DRAW_GR) {
- if (ctx->do_update) {
- BKE_collection_handle_recalc_and_update(ctx->depsgraph, scene, par, part->dup_group);
- }
-
if (part->draw & PART_DRAW_COUNT_GR) {
for (dw = part->dupliweights.first; dw; dw = dw->next)
totcollection += dw->count;
@@ -1075,7 +1049,7 @@ static void make_duplis_particle_system(const DupliContext *ctx, ParticleSystem
/* individual particle transform */
mul_m4_m4m4(mat, pamat, tmat);
- dob = make_dupli(ctx, object, mat, a, false, false);
+ dob = make_dupli(ctx, object, mat, a);
dob->particle_system = psys;
if (use_texcoords) {
@@ -1129,7 +1103,7 @@ static void make_duplis_particle_system(const DupliContext *ctx, ParticleSystem
if (part->draw & PART_DRAW_GLOBAL_OB)
add_v3_v3v3(mat[3], mat[3], vec);
- dob = make_dupli(ctx, ob, mat, a, false, false);
+ dob = make_dupli(ctx, ob, mat, a);
dob->particle_system = psys;
if (use_texcoords)
psys_get_dupli_texture(psys, part, sim.psmd, pa, cpa, dob->uv, dob->orco);
@@ -1166,7 +1140,7 @@ static void make_duplis_particles(const DupliContext *ctx)
for (psys = ctx->object->particlesystem.first, psysid = 0; psys; psys = psys->next, psysid++) {
/* particles create one more level for persistent psys index */
DupliContext pctx;
- copy_dupli_context(&pctx, ctx, ctx->object, NULL, psysid, false);
+ copy_dupli_context(&pctx, ctx, ctx->object, NULL, psysid);
make_duplis_particle_system(&pctx, psys);
}
}
@@ -1220,11 +1194,11 @@ static const DupliGenerator *get_dupli_generator(const DupliContext *ctx)
/* ---- ListBase dupli container implementation ---- */
/* Returns a list of DupliObject */
-ListBase *object_duplilist_ex(Depsgraph *depsgraph, Scene *scene, Object *ob, bool update)
+ListBase *object_duplilist(Depsgraph *depsgraph, Scene *sce, Object *ob)
{
ListBase *duplilist = MEM_callocN(sizeof(ListBase), "duplilist");
DupliContext ctx;
- init_context(&ctx, depsgraph, scene, ob, NULL, update);
+ init_context(&ctx, depsgraph, sce, ob, NULL);
if (ctx.gen) {
ctx.duplilist = duplilist;
ctx.gen->make_duplis(&ctx);
@@ -1233,13 +1207,6 @@ ListBase *object_duplilist_ex(Depsgraph *depsgraph, Scene *scene, Object *ob, bo
return duplilist;
}
-/* note: previously updating was always done, this is why it defaults to be on
- * but there are likely places it can be called without updating */
-ListBase *object_duplilist(Depsgraph *depsgraph, Scene *sce, Object *ob)
-{
- return object_duplilist_ex(depsgraph, sce, ob, true);
-}
-
void free_object_duplilist(ListBase *lb)
{
BLI_freelistN(lb);
diff --git a/source/blender/blenkernel/intern/object_update.c b/source/blender/blenkernel/intern/object_update.c
index 852d8197a6c..3b684ebfd94 100644
--- a/source/blender/blenkernel/intern/object_update.c
+++ b/source/blender/blenkernel/intern/object_update.c
@@ -145,6 +145,7 @@ void BKE_object_eval_done(Depsgraph *depsgraph, Object *ob)
Object *ob_orig = DEG_get_original_object(ob);
copy_m4_m4(ob_orig->obmat, ob->obmat);
ob_orig->transflag = ob->transflag;
+ ob_orig->flag = ob->flag;
}
}
diff --git a/source/blender/blenkernel/intern/packedFile.c b/source/blender/blenkernel/intern/packedFile.c
index afb155f7646..baa88f00985 100644
--- a/source/blender/blenkernel/intern/packedFile.c
+++ b/source/blender/blenkernel/intern/packedFile.c
@@ -246,14 +246,14 @@ void packAll(Main *bmain, ReportList *reports, bool verbose)
for (vfont = bmain->vfont.first; vfont; vfont = vfont->id.next) {
if (vfont->packedfile == NULL && !ID_IS_LINKED(vfont) && BKE_vfont_is_builtin(vfont) == false) {
- vfont->packedfile = newPackedFile(reports, vfont->name, bmain->name);
+ vfont->packedfile = newPackedFile(reports, vfont->name, BKE_main_blendfile_path(bmain));
tot ++;
}
}
for (sound = bmain->sound.first; sound; sound = sound->id.next) {
if (sound->packedfile == NULL && !ID_IS_LINKED(sound)) {
- sound->packedfile = newPackedFile(reports, sound->name, bmain->name);
+ sound->packedfile = newPackedFile(reports, sound->name, BKE_main_blendfile_path(bmain));
tot++;
}
}
@@ -542,7 +542,7 @@ int unpackVFont(Main *bmain, ReportList *reports, VFont *vfont, int how)
if (vfont != NULL) {
unpack_generate_paths(vfont->name, (ID *)vfont, absname, localname, sizeof(absname), sizeof(localname));
- newname = unpackFile(reports, bmain->name, absname, localname, vfont->packedfile, how);
+ newname = unpackFile(reports, BKE_main_blendfile_path(bmain), absname, localname, vfont->packedfile, how);
if (newname != NULL) {
ret_value = RET_OK;
freePackedFile(vfont->packedfile);
@@ -563,7 +563,7 @@ int unpackSound(Main *bmain, ReportList *reports, bSound *sound, int how)
if (sound != NULL) {
unpack_generate_paths(sound->name, (ID *)sound, absname, localname, sizeof(absname), sizeof(localname));
- newname = unpackFile(reports, bmain->name, absname, localname, sound->packedfile, how);
+ newname = unpackFile(reports, BKE_main_blendfile_path(bmain), absname, localname, sound->packedfile, how);
if (newname != NULL) {
BLI_strncpy(sound->name, newname, sizeof(sound->name));
MEM_freeN(newname);
@@ -591,7 +591,7 @@ int unpackImage(Main *bmain, ReportList *reports, Image *ima, int how)
ImagePackedFile *imapf = ima->packedfiles.last;
unpack_generate_paths(imapf->filepath, (ID *)ima, absname, localname, sizeof(absname), sizeof(localname));
- newname = unpackFile(reports, bmain->name, absname, localname, imapf->packedfile, how);
+ newname = unpackFile(reports, BKE_main_blendfile_path(bmain), absname, localname, imapf->packedfile, how);
if (newname != NULL) {
ImageView *iv;
@@ -637,7 +637,7 @@ int unpackLibraries(Main *bmain, ReportList *reports)
for (lib = bmain->library.first; lib; lib = lib->id.next) {
if (lib->packedfile && lib->name[0]) {
- newname = unpackFile(reports, bmain->name, lib->filepath, lib->filepath, lib->packedfile, PF_WRITE_ORIGINAL);
+ newname = unpackFile(reports, BKE_main_blendfile_path(bmain), lib->filepath, lib->filepath, lib->packedfile, PF_WRITE_ORIGINAL);
if (newname != NULL) {
ret_value = RET_OK;
@@ -670,7 +670,7 @@ void packLibraries(Main *bmain, ReportList *reports)
for (lib = bmain->library.first; lib; lib = lib->id.next)
if (lib->packedfile == NULL)
- lib->packedfile = newPackedFile(reports, lib->name, bmain->name);
+ lib->packedfile = newPackedFile(reports, lib->name, BKE_main_blendfile_path(bmain));
}
void unpackAll(Main *bmain, ReportList *reports, int how)
diff --git a/source/blender/blenkernel/intern/paint.c b/source/blender/blenkernel/intern/paint.c
index f961510984a..f03b46c8a07 100644
--- a/source/blender/blenkernel/intern/paint.c
+++ b/source/blender/blenkernel/intern/paint.c
@@ -59,6 +59,8 @@
#include "BKE_key.h"
#include "BKE_library.h"
#include "BKE_mesh.h"
+#include "BKE_mesh_mapping.h"
+#include "BKE_mesh_runtime.h"
#include "BKE_modifier.h"
#include "BKE_object.h"
#include "BKE_paint.h"
@@ -753,7 +755,6 @@ void BKE_sculptsession_free(Object *ob)
{
if (ob && ob->sculpt) {
SculptSession *ss = ob->sculpt;
- DerivedMesh *dm = ob->derivedFinal;
if (ss->bm) {
BKE_sculptsession_bm_to_me(ob, true);
@@ -762,12 +763,11 @@ void BKE_sculptsession_free(Object *ob)
if (ss->pbvh)
BKE_pbvh_free(ss->pbvh);
+ MEM_SAFE_FREE(ss->pmap);
+ MEM_SAFE_FREE(ss->pmap_mem);
if (ss->bm_log)
BM_log_free(ss->bm_log);
- if (dm && dm->getPBVH)
- dm->getPBVH(NULL, dm); /* signal to clear */
-
if (ss->texcache)
MEM_freeN(ss->texcache);
@@ -872,9 +872,8 @@ void BKE_sculpt_update_mesh_elements(
return;
}
- DerivedMesh *dm;
SculptSession *ss = ob->sculpt;
- Mesh *me = ob->data;
+ Mesh *me = BKE_object_get_original_mesh(ob);
MultiresModifierData *mmd = BKE_sculpt_multires_active(scene, ob);
ss->modifiers_active = sculpt_modifiers_active(scene, sd, ob);
@@ -909,13 +908,14 @@ void BKE_sculpt_update_mesh_elements(
ss->kb = (mmd == NULL) ? BKE_keyblock_from_object(ob) : NULL;
- dm = mesh_get_derived_final(depsgraph, scene, ob, CD_MASK_BAREMESH);
+ Mesh *me_eval = mesh_get_eval_final(depsgraph, scene, ob, CD_MASK_BAREMESH);
+ Mesh *me_eval_deform = mesh_get_eval_deform(depsgraph, scene, ob, CD_MASK_BAREMESH);
/* VWPaint require mesh info for loop lookup, so require sculpt mode here */
if (mmd && ob->mode & OB_MODE_SCULPT) {
ss->multires = mmd;
- ss->totvert = dm->getNumVerts(dm);
- ss->totpoly = dm->getNumPolys(dm);
+ ss->totvert = me_eval->totvert;
+ ss->totpoly = me_eval->totpoly;
ss->mvert = NULL;
ss->mpoly = NULL;
ss->mloop = NULL;
@@ -930,8 +930,17 @@ void BKE_sculpt_update_mesh_elements(
ss->vmask = CustomData_get_layer(&me->vdata, CD_PAINT_MASK);
}
- ss->pbvh = dm->getPBVH(ob, dm);
- ss->pmap = (need_pmap && dm->getPolyMap) ? dm->getPolyMap(ob, dm) : NULL;
+ PBVH *pbvh = BKE_sculpt_object_pbvh_ensure(ob, me_eval_deform);
+ BLI_assert(pbvh == ss->pbvh);
+ UNUSED_VARS_NDEBUG(pbvh);
+ MEM_SAFE_FREE(ss->pmap);
+ MEM_SAFE_FREE(ss->pmap_mem);
+ if (need_pmap && ob->type == OB_MESH) {
+ BKE_mesh_vert_poly_map_create(
+ &ss->pmap, &ss->pmap_mem,
+ me->mpoly, me->mloop,
+ me->totvert, me->totpoly, me->totloop);
+ }
pbvh_show_diffuse_color_set(ss->pbvh, ss->show_diffuse_color);
pbvh_show_mask_set(ss->pbvh, ss->show_mask);
@@ -945,7 +954,7 @@ void BKE_sculpt_update_mesh_elements(
ss->orig_cos = (ss->kb) ? BKE_keyblock_convert_to_vertcos(ob, ss->kb) : BKE_mesh_vertexCos_get(me, NULL);
BKE_crazyspace_build_sculpt(depsgraph, scene, ob, &ss->deform_imats, &ss->deform_cos);
- BKE_pbvh_apply_vertCos(ss->pbvh, ss->deform_cos);
+ BKE_pbvh_apply_vertCos(ss->pbvh, ss->deform_cos, me->totvert);
for (a = 0; a < me->totvert; ++a) {
invert_m3(ss->deform_imats[a]);
@@ -962,14 +971,14 @@ void BKE_sculpt_update_mesh_elements(
/* if pbvh is deformed, key block is already applied to it */
if (ss->kb) {
- bool pbvh_deformd = BKE_pbvh_isDeformed(ss->pbvh);
- if (!pbvh_deformd || ss->deform_cos == NULL) {
+ bool pbvh_deformed = BKE_pbvh_isDeformed(ss->pbvh);
+ if (!pbvh_deformed || ss->deform_cos == NULL) {
float (*vertCos)[3] = BKE_keyblock_convert_to_vertcos(ob, ss->kb);
if (vertCos) {
- if (!pbvh_deformd) {
+ if (!pbvh_deformed) {
/* apply shape keys coordinates to PBVH */
- BKE_pbvh_apply_vertCos(ss->pbvh, vertCos);
+ BKE_pbvh_apply_vertCos(ss->pbvh, vertCos, me->totvert);
}
if (ss->deform_cos == NULL) {
ss->deform_cos = vertCos;
@@ -1091,3 +1100,96 @@ void BKE_sculpt_toolsettings_data_ensure(struct Scene *scene)
sd->paint.tile_offset[2] = 1.0f;
}
}
+
+static bool check_sculpt_object_deformed(Object *object, const bool for_construction)
+{
+ bool deformed = false;
+
+ /* Active modifiers means extra deformation, which can't be handled correct
+ * on birth of PBVH and sculpt "layer" levels, so use PBVH only for internal brush
+ * stuff and show final DerivedMesh so user would see actual object shape.
+ */
+ deformed |= object->sculpt->modifiers_active;
+
+ if (for_construction) {
+ deformed |= object->sculpt->kb != NULL;
+ }
+ else {
+ /* As in case with modifiers, we can't synchronize deformation made against
+ * PBVH and non-locked keyblock, so also use PBVH only for brushes and
+ * final DM to give final result to user.
+ */
+ deformed |= object->sculpt->kb && (object->shapeflag & OB_SHAPE_LOCK) == 0;
+ }
+
+ return deformed;
+}
+
+PBVH *BKE_sculpt_object_pbvh_ensure(Object *ob, Mesh *me_eval_deform)
+{
+ if (!ob) {
+ return NULL;
+ }
+
+ if (!ob->sculpt) {
+ return NULL;
+ }
+
+ PBVH *pbvh = ob->sculpt->pbvh;
+
+ /* Sculpting on a BMesh (dynamic-topology) gets a special PBVH */
+ if (!pbvh && ob->sculpt->bm) {
+ pbvh = BKE_pbvh_new();
+
+ BKE_pbvh_build_bmesh(pbvh, ob->sculpt->bm,
+ ob->sculpt->bm_smooth_shading,
+ ob->sculpt->bm_log, ob->sculpt->cd_vert_node_offset,
+ ob->sculpt->cd_face_node_offset);
+
+ pbvh_show_diffuse_color_set(pbvh, ob->sculpt->show_diffuse_color);
+ pbvh_show_mask_set(pbvh, ob->sculpt->show_mask);
+ }
+
+ /* always build pbvh from original mesh, and only use it for drawing if
+ * this derivedmesh is just original mesh. it's the multires subsurf dm
+ * that this is actually for, to support a pbvh on a modified mesh */
+ if (!pbvh && ob->type == OB_MESH) {
+ Mesh *me = BKE_object_get_original_mesh(ob);
+ const int looptris_num = poly_to_tri_count(me->totpoly, me->totloop);
+ MLoopTri *looptri;
+ bool deformed;
+
+ pbvh = BKE_pbvh_new();
+
+ looptri = MEM_malloc_arrayN(looptris_num, sizeof(*looptri), __func__);
+
+ BKE_mesh_recalc_looptri(
+ me->mloop, me->mpoly,
+ me->mvert,
+ me->totloop, me->totpoly,
+ looptri);
+
+ BKE_pbvh_build_mesh(
+ pbvh,
+ me->mpoly, me->mloop,
+ me->mvert, me->totvert, &me->vdata,
+ looptri, looptris_num);
+
+ pbvh_show_diffuse_color_set(pbvh, ob->sculpt->show_diffuse_color);
+ pbvh_show_mask_set(pbvh, ob->sculpt->show_mask);
+
+ deformed = check_sculpt_object_deformed(ob, true);
+
+ if (deformed && me_eval_deform) {
+ int totvert;
+ float (*v_cos)[3];
+
+ v_cos = BKE_mesh_vertexCos_get(me_eval_deform, &totvert);
+ BKE_pbvh_apply_vertCos(pbvh, v_cos, totvert);
+ MEM_freeN(v_cos);
+ }
+ }
+
+ ob->sculpt->pbvh = pbvh;
+ return pbvh;
+}
diff --git a/source/blender/blenkernel/intern/particle.c b/source/blender/blenkernel/intern/particle.c
index a142c839142..c1fb9130b5d 100644
--- a/source/blender/blenkernel/intern/particle.c
+++ b/source/blender/blenkernel/intern/particle.c
@@ -298,24 +298,6 @@ ParticleSystem *psys_orig_get(ParticleSystem *psys)
return psys->orig_psys;
}
-struct ParticleSystem *psys_eval_get(Depsgraph *depsgraph,
- Object *object,
- ParticleSystem *psys)
-{
- Object *object_eval = DEG_get_evaluated_object(depsgraph, object);
- if (object_eval == object) {
- return psys;
- }
- ParticleSystem *psys_eval = object_eval->particlesystem.first;
- while (psys_eval != NULL) {
- if (psys_eval->orig_psys == psys) {
- return psys_eval;
- }
- psys_eval = psys_eval->next;
- }
- return psys_eval;
-}
-
static PTCacheEdit *psys_orig_edit_get(ParticleSystem *psys)
{
if (psys->orig_psys == NULL) {
@@ -2623,7 +2605,6 @@ void psys_cache_paths(ParticleSimulationData *sim, float cfra, const bool use_re
}
void psys_cache_edit_paths(Depsgraph *depsgraph, Scene *scene, Object *ob, PTCacheEdit *edit, float cfra, const bool use_render_params)
{
- Object *ob_eval = DEG_get_evaluated_object(depsgraph, ob);
ParticleCacheKey *ca, **cache = edit->pathcache;
ParticleEditSettings *pset = &scene->toolsettings->particle;
@@ -2631,16 +2612,9 @@ void psys_cache_edit_paths(Depsgraph *depsgraph, Scene *scene, Object *ob, PTCac
PTCacheEditKey *ekey = NULL;
ParticleSystem *psys = edit->psys;
- ParticleSystem *psys_eval = NULL;
ParticleSystemModifierData *psmd = psys_get_modifier(ob, psys);
- ParticleSystemModifierData *psmd_eval = NULL;
- if (psmd != NULL) {
- psmd_eval = (ParticleSystemModifierData *)modifiers_findByName(ob_eval, psmd->modifier.name);
- psys_eval = psmd_eval->psys;
- }
-
- ParticleData *pa = psys_eval ? psys_eval->particles : NULL;
+ ParticleData *pa = psys ? psys->particles : NULL;
ParticleInterpolationData pind;
ParticleKey result;
@@ -2669,7 +2643,7 @@ void psys_cache_edit_paths(Depsgraph *depsgraph, Scene *scene, Object *ob, PTCac
/* frs_sec = (psys || edit->pid.flag & PTCACHE_VEL_PER_SEC) ? 25.0f : 1.0f; */ /* UNUSED */
- const bool use_weight = (pset->brushtype == PE_BRUSH_WEIGHT) && (psys_eval != NULL) && (psys_eval->particles != NULL);
+ const bool use_weight = (pset->brushtype == PE_BRUSH_WEIGHT) && (psys != NULL) && (psys->particles != NULL);
if (use_weight) {
; /* use weight painting colors now... */
@@ -2714,10 +2688,10 @@ void psys_cache_edit_paths(Depsgraph *depsgraph, Scene *scene, Object *ob, PTCac
cache[i]->segments = segments;
/*--get the first data points--*/
- init_particle_interpolation(ob_eval, psys_eval, pa, &pind);
+ init_particle_interpolation(ob, psys, pa, &pind);
- if (psys_eval) {
- psys_mat_hair_to_global(ob_eval, psmd_eval->mesh_final, psys->part->from, pa, hairmat);
+ if (psys) {
+ psys_mat_hair_to_global(ob, psmd->mesh_final, psys->part->from, pa, hairmat);
copy_v3_v3(rotmat[0], hairmat[2]);
copy_v3_v3(rotmat[1], hairmat[1]);
copy_v3_v3(rotmat[2], hairmat[0]);
@@ -2736,7 +2710,7 @@ void psys_cache_edit_paths(Depsgraph *depsgraph, Scene *scene, Object *ob, PTCac
time = (float)k / (float)segments;
t = birthtime + time * (dietime - birthtime);
result.time = -t;
- do_particle_interpolation(psys_eval, i, pa, t, &pind, &result);
+ do_particle_interpolation(psys, i, pa, t, &pind, &result);
copy_v3_v3(ca->co, result.co);
/* non-hair points are already in global space */
@@ -2833,9 +2807,9 @@ void psys_cache_edit_paths(Depsgraph *depsgraph, Scene *scene, Object *ob, PTCac
ParticleSimulationData sim = {0};
sim.depsgraph = depsgraph;
sim.scene = scene;
- sim.ob = ob_eval;
- sim.psys = psys_eval;
- sim.psmd = psys_get_modifier(ob_eval, psys_eval);
+ sim.ob = ob;
+ sim.psys = psys;
+ sim.psmd = psys_get_modifier(ob, psys);
psys_cache_child_paths(&sim, cfra, true, use_render_params);
}
@@ -3094,6 +3068,9 @@ void object_remove_particle_system(Scene *UNUSED(scene), Object *ob)
DEG_relations_tag_update(G.main);
DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
+
+ /* Flush object mode. */
+ DEG_id_tag_update(&ob->id, DEG_TAG_COPY_ON_WRITE);
}
static void default_particle_settings(ParticleSettings *part)
diff --git a/source/blender/blenkernel/intern/particle_system.c b/source/blender/blenkernel/intern/particle_system.c
index a2d9891ec2d..8d6991ff9f4 100644
--- a/source/blender/blenkernel/intern/particle_system.c
+++ b/source/blender/blenkernel/intern/particle_system.c
@@ -4217,6 +4217,18 @@ void particle_system_update(struct Depsgraph *depsgraph, Scene *scene, Object *o
if (!psys_check_enabled(ob, psys, use_render_params))
return;
+ if (DEG_is_active(depsgraph)) {
+ if (psys->orig_psys != NULL && psys->orig_psys->edit != NULL) {
+ psys_cache_edit_paths(
+ depsgraph,
+ (Scene *)DEG_get_original_id(&scene->id),
+ DEG_get_original_object(ob),
+ psys->orig_psys->edit,
+ DEG_get_ctime(depsgraph),
+ DEG_get_mode(depsgraph) == DAG_EVAL_RENDER);
+ }
+ }
+
cfra = DEG_get_ctime(depsgraph);
sim.depsgraph = depsgraph;
diff --git a/source/blender/blenkernel/intern/pbvh.c b/source/blender/blenkernel/intern/pbvh.c
index 7b53c5f8811..8cc8a8510f2 100644
--- a/source/blender/blenkernel/intern/pbvh.c
+++ b/source/blender/blenkernel/intern/pbvh.c
@@ -2189,8 +2189,13 @@ float (*BKE_pbvh_get_vertCos(PBVH *pbvh))[3]
return vertCos;
}
-void BKE_pbvh_apply_vertCos(PBVH *pbvh, float (*vertCos)[3])
+void BKE_pbvh_apply_vertCos(PBVH *pbvh, float (*vertCos)[3], const int totvert)
{
+ if (totvert != pbvh->totvert) {
+ BLI_assert(!"PBVH: Given deforming vcos number does not natch PBVH vertex number!");
+ return;
+ }
+
if (!pbvh->deformed) {
if (pbvh->verts) {
/* if pbvh is not already deformed, verts/faces points to the */
diff --git a/source/blender/blenkernel/intern/pointcache.c b/source/blender/blenkernel/intern/pointcache.c
index e219e27f851..af13909bf89 100644
--- a/source/blender/blenkernel/intern/pointcache.c
+++ b/source/blender/blenkernel/intern/pointcache.c
@@ -1802,7 +1802,7 @@ static int ptcache_frame_from_filename(const char *filename, const char *ext)
static int ptcache_path(PTCacheID *pid, char *filename)
{
Library *lib = (pid->ob) ? pid->ob->id.lib : NULL;
- const char *blendfilename= (lib && (pid->cache->flag & PTCACHE_IGNORE_LIBPATH)==0) ? lib->filepath: G.main->name;
+ const char *blendfilename= (lib && (pid->cache->flag & PTCACHE_IGNORE_LIBPATH)==0) ? lib->filepath: BKE_main_blendfile_path_from_global();
size_t i;
if (pid->cache->flag & PTCACHE_EXTERNAL) {
diff --git a/source/blender/blenkernel/intern/rigidbody.c b/source/blender/blenkernel/intern/rigidbody.c
index 75018bbe5bd..e79f86c6520 100644
--- a/source/blender/blenkernel/intern/rigidbody.c
+++ b/source/blender/blenkernel/intern/rigidbody.c
@@ -705,7 +705,8 @@ static void rigidbody_validate_sim_object(RigidBodyWorld *rbw, Object *ob, bool
/* --------------------- */
-static void rigidbody_constraint_set_limits(RigidBodyCon *rbc, void (*set_limits)(rbConstraint*,int,float,float))
+static void rigidbody_constraint_set_limits(
+ RigidBodyCon *rbc, void (*set_limits)(rbConstraint *, int, float, float))
{
if (rbc->flag & RBC_FLAG_USE_LIMIT_LIN_X)
set_limits(rbc->physics_constraint, RB_LIMIT_LIN_X, rbc->limit_lin_x_lower, rbc->limit_lin_x_upper);
diff --git a/source/blender/blenkernel/intern/scene.c b/source/blender/blenkernel/intern/scene.c
index a488386fed8..2916e5559c4 100644
--- a/source/blender/blenkernel/intern/scene.c
+++ b/source/blender/blenkernel/intern/scene.c
@@ -945,11 +945,11 @@ Scene *BKE_scene_set_name(Main *bmain, const char *name)
Scene *sce = (Scene *)BKE_libblock_find_name(bmain, ID_SCE, name);
if (sce) {
BKE_scene_set_background(bmain, sce);
- printf("Scene switch for render: '%s' in file: '%s'\n", name, bmain->name);
+ printf("Scene switch for render: '%s' in file: '%s'\n", name, BKE_main_blendfile_path(bmain));
return sce;
}
- printf("Can't find scene: '%s' in file: '%s'\n", name, bmain->name);
+ printf("Can't find scene: '%s' in file: '%s'\n", name, BKE_main_blendfile_path(bmain));
return NULL;
}
@@ -1029,7 +1029,7 @@ int BKE_scene_base_iter_next(
* this enters eternal loop because of
* makeDispListMBall getting called inside of collection_duplilist */
if ((*base)->object->dup_group == NULL) {
- iter->duplilist = object_duplilist_ex(depsgraph, (*scene), (*base)->object, false);
+ iter->duplilist = object_duplilist(depsgraph, (*scene), (*base)->object);
iter->dupob = iter->duplilist->first;
diff --git a/source/blender/blenkernel/intern/seqeffects.c b/source/blender/blenkernel/intern/seqeffects.c
index 0eca7a00515..00af9721f07 100644
--- a/source/blender/blenkernel/intern/seqeffects.c
+++ b/source/blender/blenkernel/intern/seqeffects.c
@@ -1767,13 +1767,13 @@ static float check_zone(WipeZone *wipezone, int x, int y, Sequence *seq, float f
if (output != output) output = 1;
if (wipe->forward) output = 1 - output;
break;
- /* BOX WIPE IS NOT WORKING YET */
+ /* BOX WIPE IS NOT WORKING YET */
/* case DO_CROSS_WIPE: */
/* BOX WIPE IS NOT WORKING YET */
#if 0
- case DO_BOX_WIPE:
- if (!wipe->forward)
- facf0 = 1.0f - facf0; /* Go the other direction */
+ case DO_BOX_WIPE:
+ if (!wipe->forward)
+ facf0 = 1.0f - facf0; /* Go the other direction */
width = (int)(wipe->edgeWidth * ((xo + yo) / 2.0));
hwidth = (float)width / 2.0;
@@ -1806,8 +1806,9 @@ static float check_zone(WipeZone *wipezone, int x, int y, Sequence *seq, float f
output = in_band(hwidth, hyp2, 1, 1) * in_band(hwidth, hyp, 1, 1);
}
- if (!wipe->forward)
- facf0 = 1.0f - facf0; /* Go the other direction */
+ if (!wipe->forward) {
+ facf0 = 1.0f - facf0; /* Go the other direction */
+ }
angle = -1 / angle;
b1 = posy / 2 - (-angle) * posx / 2;
b3 = (yo - posy / 2) - (-angle) * (xo - posx / 2);
diff --git a/source/blender/blenkernel/intern/sequencer.c b/source/blender/blenkernel/intern/sequencer.c
index f5d99e2615a..ecd0335fc4e 100644
--- a/source/blender/blenkernel/intern/sequencer.c
+++ b/source/blender/blenkernel/intern/sequencer.c
@@ -898,7 +898,7 @@ void BKE_sequence_reload_new_file(Scene *scene, Sequence *seq, const bool lock_r
BLI_join_dirfile(path, sizeof(path), seq->strip->dir,
seq->strip->stripdata->name);
- BLI_path_abs(path, G.main->name);
+ BLI_path_abs(path, BKE_main_blendfile_path_from_global());
BKE_sequence_free_anim(seq);
@@ -1546,7 +1546,7 @@ static void seq_open_anim_file(Scene *scene, Sequence *seq, bool openfile)
BLI_join_dirfile(name, sizeof(name),
seq->strip->dir, seq->strip->stripdata->name);
- BLI_path_abs(name, G.main->name);
+ BLI_path_abs(name, BKE_main_blendfile_path_from_global());
proxy = seq->strip->proxy;
@@ -1563,7 +1563,7 @@ static void seq_open_anim_file(Scene *scene, Sequence *seq, bool openfile)
else {
BLI_strncpy(dir, seq->strip->proxy->dir, sizeof(dir));
}
- BLI_path_abs(dir, G.main->name);
+ BLI_path_abs(dir, BKE_main_blendfile_path_from_global());
}
if (is_multiview && seq->views_format == R_IMF_VIEWS_INDIVIDUAL) {
@@ -1691,7 +1691,7 @@ static bool seq_proxy_get_fname(Editing *ed, Sequence *seq, int cfra, int render
return false;
}
BLI_path_append(dir, sizeof(dir), fname);
- BLI_path_abs(name, G.main->name);
+ BLI_path_abs(name, BKE_main_blendfile_path_from_global());
}
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));
@@ -1723,7 +1723,7 @@ static bool seq_proxy_get_fname(Editing *ed, Sequence *seq, int cfra, int render
{
char fname[FILE_MAXFILE];
BLI_join_dirfile(fname, PROXY_MAXFILE, dir, proxy->file);
- BLI_path_abs(fname, G.main->name);
+ BLI_path_abs(fname, BKE_main_blendfile_path_from_global());
if (suffix[0] != '\0') {
/* TODO(sergey): This will actually append suffix after extension
* which is weird but how was originally coded in multiview branch.
@@ -1749,7 +1749,7 @@ static bool seq_proxy_get_fname(Editing *ed, Sequence *seq, int cfra, int render
BLI_snprintf(name, PROXY_MAXFILE, "%s/proxy_misc/%d/####%s", dir, render_size, suffix);
}
- BLI_path_abs(name, G.main->name);
+ BLI_path_abs(name, BKE_main_blendfile_path_from_global());
BLI_path_frame(name, frameno, 0);
strcat(name, ".jpg");
@@ -1894,7 +1894,7 @@ static bool seq_proxy_multiview_context_invalid(Sequence *seq, Scene *scene, con
char path[FILE_MAX];
BLI_join_dirfile(path, sizeof(path), seq->strip->dir,
seq->strip->stripdata->name);
- BLI_path_abs(path, G.main->name);
+ BLI_path_abs(path, BKE_main_blendfile_path_from_global());
BKE_scene_multiview_view_prefix_get(scene, path, prefix, &ext);
}
else {
@@ -2846,7 +2846,7 @@ static ImBuf *seq_render_image_strip(const SeqRenderData *context, Sequence *seq
if (s_elem) {
BLI_join_dirfile(name, sizeof(name), seq->strip->dir, s_elem->name);
- BLI_path_abs(name, G.main->name);
+ BLI_path_abs(name, BKE_main_blendfile_path_from_global());
}
flag = IB_rect | IB_metadata;
@@ -5151,7 +5151,7 @@ void BKE_sequence_init_colorspace(Sequence *seq)
ImBuf *ibuf;
BLI_join_dirfile(name, sizeof(name), seq->strip->dir, seq->strip->stripdata->name);
- BLI_path_abs(name, G.main->name);
+ BLI_path_abs(name, BKE_main_blendfile_path_from_global());
/* initialize input color space */
if (seq->type == SEQ_TYPE_IMAGE) {
@@ -5319,6 +5319,7 @@ static void seq_anim_add_suffix(Scene *scene, struct anim *anim, const int view_
Sequence *BKE_sequencer_add_movie_strip(bContext *C, ListBase *seqbasep, SeqLoadInfo *seq_load)
{
+ Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C); /* only for sound */
char path[sizeof(seq_load->path)];
@@ -5333,7 +5334,7 @@ Sequence *BKE_sequencer_add_movie_strip(bContext *C, ListBase *seqbasep, SeqLoad
int i;
BLI_strncpy(path, seq_load->path, sizeof(path));
- BLI_path_abs(path, G.main->name);
+ BLI_path_abs(path, BKE_main_blendfile_path(bmain));
anim_arr = MEM_callocN(sizeof(struct anim *) * totfiles, "Video files");
diff --git a/source/blender/blenkernel/intern/sound.c b/source/blender/blenkernel/intern/sound.c
index 747ffdafe8b..a7f3fc1df9e 100644
--- a/source/blender/blenkernel/intern/sound.c
+++ b/source/blender/blenkernel/intern/sound.c
@@ -77,7 +77,7 @@ bSound *BKE_sound_new_file(struct Main *bmain, const char *filepath)
BLI_strncpy(str, filepath, sizeof(str));
- path = /*bmain ? bmain->name :*/ G.main->name;
+ path = BKE_main_blendfile_path(bmain);
BLI_path_abs(str, path);
@@ -96,7 +96,7 @@ bSound *BKE_sound_new_file_exists_ex(struct Main *bmain, const char *filepath, b
char str[FILE_MAX], strtest[FILE_MAX];
BLI_strncpy(str, filepath, sizeof(str));
- BLI_path_abs(str, bmain->name);
+ BLI_path_abs(str, BKE_main_blendfile_path(bmain));
/* first search an identical filepath */
for (sound = bmain->sound.first; sound; sound = sound->id.next) {
diff --git a/source/blender/blenkernel/intern/studiolight.c b/source/blender/blenkernel/intern/studiolight.c
index 4ef7b3d2247..e4b49656907 100644
--- a/source/blender/blenkernel/intern/studiolight.c
+++ b/source/blender/blenkernel/intern/studiolight.c
@@ -55,13 +55,13 @@
/* Statics */
static ListBase studiolights;
-#define STUDIOLIGHT_EXTENSIONS ".jpg", ".hdr"
#define STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE 8
#define STUDIOLIGHT_IRRADIANCE_EQUIRECTANGULAR_HEIGHT 32
#define STUDIOLIGHT_IRRADIANCE_EQUIRECTANGULAR_WIDTH (STUDIOLIGHT_IRRADIANCE_EQUIRECTANGULAR_HEIGHT * 2)
static const char *STUDIOLIGHT_CAMERA_FOLDER = "studiolights/camera/";
static const char *STUDIOLIGHT_WORLD_FOLDER = "studiolights/world/";
+static const char *STUDIOLIGHT_MATCAP_FOLDER = "studiolights/matcap/";
/* FUNCTIONS */
static void studiolight_free(struct StudioLight *sl)
@@ -168,16 +168,16 @@ static void studiolight_load_equierectangular_image(StudioLight *sl)
sl->equirectangular_radiance_buffer = ibuf;
}
}
- sl->flag |= STUDIOLIGHT_EQUIRECTANGULAR_IMAGE_LOADED;
+ sl->flag |= STUDIOLIGHT_EXTERNAL_IMAGE_LOADED;
}
static void studiolight_create_equierectangular_radiance_gputexture(StudioLight *sl)
{
if (sl->flag & STUDIOLIGHT_EXTERNAL_FILE) {
char error[256];
- BKE_studiolight_ensure_flag(sl, STUDIOLIGHT_EQUIRECTANGULAR_IMAGE_LOADED);
+ BKE_studiolight_ensure_flag(sl, STUDIOLIGHT_EXTERNAL_IMAGE_LOADED);
ImBuf *ibuf = sl->equirectangular_radiance_buffer;
- sl->equirectangular_radiance_gputexture = GPU_texture_create_2D(ibuf->x, ibuf->y, GPU_RGBA16F, ibuf->rect_float, error);
+ sl->equirectangular_radiance_gputexture = GPU_texture_create_2D(ibuf->x, ibuf->y, GPU_RGBA8, ibuf->rect_float, error);
GPUTexture *tex = sl->equirectangular_radiance_gputexture;
GPU_texture_bind(tex, 0);
GPU_texture_filter_mode(tex, true);
@@ -206,7 +206,7 @@ static void studiolight_create_equierectangular_irradiance_gputexture(StudioLigh
static void studiolight_calculate_radiance_cubemap_buffers(StudioLight *sl)
{
if (sl->flag & STUDIOLIGHT_EXTERNAL_FILE) {
- BKE_studiolight_ensure_flag(sl, STUDIOLIGHT_EQUIRECTANGULAR_IMAGE_LOADED);
+ BKE_studiolight_ensure_flag(sl, STUDIOLIGHT_EXTERNAL_IMAGE_LOADED);
ImBuf *ibuf = sl->equirectangular_radiance_buffer;
if (ibuf) {
float *colbuf = MEM_mallocN(SQUARE(STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE) * sizeof(float[4]), __func__);
@@ -481,7 +481,7 @@ static void studiolight_add_files_from_datafolder(const int folder_id, const cha
if ((dir[i].type & S_IFREG)) {
const char *filename = dir[i].relname;
const char *path = dir[i].path;
- if (BLI_testextensie_n(filename, STUDIOLIGHT_EXTENSIONS, NULL)) {
+ if (BLI_testextensie_array(filename, imb_ext_image)) {
sl = studiolight_create();
sl->flag = STUDIOLIGHT_EXTERNAL_FILE | flag;
BLI_strncpy(sl->name, filename, FILE_MAXFILE);
@@ -527,7 +527,7 @@ static int studiolight_cmp(const void *a, const void *b)
/* icons */
static uint *studiolight_radiance_preview(StudioLight *sl, int icon_size)
{
- BKE_studiolight_ensure_flag(sl, STUDIOLIGHT_EQUIRECTANGULAR_IMAGE_LOADED);
+ BKE_studiolight_ensure_flag(sl, STUDIOLIGHT_EXTERNAL_IMAGE_LOADED);
uint *rect = MEM_mallocN(icon_size * icon_size * sizeof(uint), __func__);
int icon_center = icon_size / 2;
@@ -579,6 +579,29 @@ static uint *studiolight_radiance_preview(StudioLight *sl, int icon_size)
return rect;
}
+static uint *studiolight_matcap_preview(StudioLight *sl, int icon_size)
+{
+ BKE_studiolight_ensure_flag(sl, STUDIOLIGHT_EXTERNAL_IMAGE_LOADED);
+
+ uint *rect = MEM_mallocN(icon_size * icon_size * sizeof(uint), __func__);
+ const uint alphamask = 0xff000000;
+ float color[4];
+ float fx, fy;
+ int offset = 0;
+ ImBuf *ibuf = sl->equirectangular_radiance_buffer;
+ for (int y = 0; y < icon_size; y++) {
+ for (int x = 0; x < icon_size; x++) {
+ fx = x * ibuf->x / icon_size;
+ fy = y * ibuf->y / icon_size;
+ nearest_interpolation_color(ibuf, NULL, color, fx, fy);
+ rect[offset++] = rgb_to_cpack(linearrgb_to_srgb(color[0]),
+ linearrgb_to_srgb(color[1]),
+ linearrgb_to_srgb(color[2])) | alphamask;
+ }
+ }
+ return rect;
+}
+
static uint *studiolight_irradiance_preview(StudioLight *sl, int icon_size)
{
if (/*!(sl->flag & STUDIOLIGHT_EXTERNAL_FILE)*/ 1) {
@@ -696,7 +719,7 @@ void BKE_studiolight_init(void)
/* Add default studio light */
sl = studiolight_create();
BLI_strncpy(sl->name, "INTERNAL_01", FILE_MAXFILE);
- sl->flag = STUDIOLIGHT_DIFFUSE_LIGHT_CALCULATED | STUDIOLIGHT_ORIENTATION_CAMERA;
+ sl->flag = STUDIOLIGHT_INTERNAL | STUDIOLIGHT_DIFFUSE_LIGHT_CALCULATED | STUDIOLIGHT_ORIENTATION_CAMERA;
copy_v3_fl(sl->diffuse_light[STUDIOLIGHT_X_POS], 0.0f);
copy_v3_fl(sl->diffuse_light[STUDIOLIGHT_X_NEG], 0.0f);
copy_v3_fl(sl->diffuse_light[STUDIOLIGHT_Y_POS], 0.8f);
@@ -706,9 +729,11 @@ void BKE_studiolight_init(void)
BLI_addtail(&studiolights, sl);
studiolight_add_files_from_datafolder(BLENDER_SYSTEM_DATAFILES, STUDIOLIGHT_CAMERA_FOLDER, STUDIOLIGHT_ORIENTATION_CAMERA);
- studiolight_add_files_from_datafolder(BLENDER_USER_DATAFILES, STUDIOLIGHT_CAMERA_FOLDER, STUDIOLIGHT_ORIENTATION_CAMERA);
+ studiolight_add_files_from_datafolder(BLENDER_USER_DATAFILES, STUDIOLIGHT_CAMERA_FOLDER, STUDIOLIGHT_ORIENTATION_CAMERA | STUDIOLIGHT_USER_DEFINED);
studiolight_add_files_from_datafolder(BLENDER_SYSTEM_DATAFILES, STUDIOLIGHT_WORLD_FOLDER, STUDIOLIGHT_ORIENTATION_WORLD);
- studiolight_add_files_from_datafolder(BLENDER_USER_DATAFILES, STUDIOLIGHT_WORLD_FOLDER, STUDIOLIGHT_ORIENTATION_WORLD);
+ studiolight_add_files_from_datafolder(BLENDER_USER_DATAFILES, STUDIOLIGHT_WORLD_FOLDER, STUDIOLIGHT_ORIENTATION_WORLD | STUDIOLIGHT_USER_DEFINED);
+ studiolight_add_files_from_datafolder(BLENDER_SYSTEM_DATAFILES, STUDIOLIGHT_MATCAP_FOLDER, STUDIOLIGHT_ORIENTATION_VIEWNORMAL);
+ studiolight_add_files_from_datafolder(BLENDER_USER_DATAFILES, STUDIOLIGHT_MATCAP_FOLDER, STUDIOLIGHT_ORIENTATION_VIEWNORMAL | STUDIOLIGHT_USER_DEFINED);
/* sort studio lights on filename. */
BLI_listbase_sort(&studiolights, studiolight_cmp);
@@ -722,24 +747,34 @@ void BKE_studiolight_free(void)
}
}
+struct StudioLight *BKE_studiolight_find_first(int flag)
+{
+ LISTBASE_FOREACH(StudioLight *, sl, &studiolights) {
+ if ((sl->flag & flag)) {
+ return sl;
+ }
+ }
+ return NULL;
+}
+
struct StudioLight *BKE_studiolight_find(const char *name, int flag)
{
LISTBASE_FOREACH(StudioLight *, sl, &studiolights) {
if (STREQLEN(sl->name, name, FILE_MAXFILE)) {
- if ((sl->flag & flag) == flag) {
+ if ((sl->flag & flag)) {
return sl;
}
else {
/* flags do not match, so use default */
- return studiolights.first;
+ return BKE_studiolight_find_first(flag);
}
}
}
/* When not found, use the default studio light */
- return studiolights.first;
+ return BKE_studiolight_find_first(flag);
}
-struct StudioLight *BKE_studiolight_findindex(int index)
+struct StudioLight *BKE_studiolight_findindex(int index, int flag)
{
LISTBASE_FOREACH(StudioLight *, sl, &studiolights) {
if (sl->index == index) {
@@ -747,10 +782,10 @@ struct StudioLight *BKE_studiolight_findindex(int index)
}
}
/* When not found, use the default studio light */
- return studiolights.first;
+ return BKE_studiolight_find_first(flag);
}
-const struct ListBase *BKE_studiolight_listbase(void)
+struct ListBase *BKE_studiolight_listbase(void)
{
return &studiolights;
}
@@ -758,7 +793,12 @@ const struct ListBase *BKE_studiolight_listbase(void)
uint *BKE_studiolight_preview(StudioLight *sl, int icon_size, int icon_id_type)
{
if (icon_id_type == STUDIOLIGHT_ICON_ID_TYPE_IRRADIANCE) {
- return studiolight_irradiance_preview(sl, icon_size);
+ if (sl->flag & STUDIOLIGHT_ORIENTATION_VIEWNORMAL) {
+ return studiolight_matcap_preview(sl, icon_size);
+ }
+ else {
+ return studiolight_irradiance_preview(sl, icon_size);
+ }
}
else {
return studiolight_radiance_preview(sl, icon_size);
@@ -771,7 +811,7 @@ void BKE_studiolight_ensure_flag(StudioLight *sl, int flag)
return;
}
- if ((flag & STUDIOLIGHT_EQUIRECTANGULAR_IMAGE_LOADED)) {
+ if ((flag & STUDIOLIGHT_EXTERNAL_IMAGE_LOADED)) {
studiolight_load_equierectangular_image(sl);
}
if ((flag & STUDIOLIGHT_RADIANCE_BUFFERS_CALCULATED)) {
@@ -793,3 +833,9 @@ void BKE_studiolight_ensure_flag(StudioLight *sl, int flag)
studiolight_calculate_irradiance_equirectangular_image(sl);
}
}
+
+void BKE_studiolight_refresh(void)
+{
+ BKE_studiolight_free();
+ BKE_studiolight_init();
+}
diff --git a/source/blender/blenkernel/intern/subsurf_ccg.c b/source/blender/blenkernel/intern/subsurf_ccg.c
index ef49a7af5f3..d735944c93d 100644
--- a/source/blender/blenkernel/intern/subsurf_ccg.c
+++ b/source/blender/blenkernel/intern/subsurf_ccg.c
@@ -2352,7 +2352,7 @@ static struct PBVH *ccgDM_getPBVH(Object *ob, DerivedMesh *dm)
totvert = deformdm->getNumVerts(deformdm);
vertCos = MEM_malloc_arrayN(totvert, sizeof(float[3]), "ccgDM_getPBVH vertCos");
deformdm->getVertCos(deformdm, vertCos);
- BKE_pbvh_apply_vertCos(ccgdm->pbvh, vertCos);
+ BKE_pbvh_apply_vertCos(ccgdm->pbvh, vertCos, totvert);
MEM_freeN(vertCos);
}
}
diff --git a/source/blender/blenkernel/intern/text.c b/source/blender/blenkernel/intern/text.c
index 3892b2f0546..a24020d7764 100644
--- a/source/blender/blenkernel/intern/text.c
+++ b/source/blender/blenkernel/intern/text.c
@@ -388,7 +388,7 @@ bool BKE_text_reload(Text *text)
}
BLI_strncpy(filepath_abs, text->name, FILE_MAX);
- BLI_path_abs(filepath_abs, G.main->name);
+ BLI_path_abs(filepath_abs, BKE_main_blendfile_path_from_global());
buffer = BLI_file_read_text_as_mem(filepath_abs, 0, &buffer_len);
if (buffer == NULL) {
@@ -557,7 +557,7 @@ int BKE_text_file_modified_check(Text *text)
return 0;
BLI_strncpy(file, text->name, FILE_MAX);
- BLI_path_abs(file, G.main->name);
+ BLI_path_abs(file, BKE_main_blendfile_path_from_global());
if (!BLI_exists(file))
return 2;
@@ -585,7 +585,7 @@ void BKE_text_file_modified_ignore(Text *text)
if (!text->name) return;
BLI_strncpy(file, text->name, FILE_MAX);
- BLI_path_abs(file, G.main->name);
+ BLI_path_abs(file, BKE_main_blendfile_path_from_global());
if (!BLI_exists(file)) return;
diff --git a/source/blender/blenkernel/intern/undo_system.c b/source/blender/blenkernel/intern/undo_system.c
index f5e4c354a02..a05e79aae1f 100644
--- a/source/blender/blenkernel/intern/undo_system.c
+++ b/source/blender/blenkernel/intern/undo_system.c
@@ -376,7 +376,7 @@ UndoStep *BKE_undosys_step_push_init_with_type(UndoStack *ustack, bContext *C, c
us->type = ut;
ustack->step_init = us;
ut->step_encode_init(C, us);
- undosys_stack_validate(ustack, true);
+ undosys_stack_validate(ustack, false);
return us;
}
else {
diff --git a/source/blender/blenkernel/intern/world.c b/source/blender/blenkernel/intern/world.c
index 15bf01d2049..1b06e7ed851 100644
--- a/source/blender/blenkernel/intern/world.c
+++ b/source/blender/blenkernel/intern/world.c
@@ -53,6 +53,8 @@
#include "BKE_node.h"
#include "BKE_world.h"
+#include "DEG_depsgraph.h"
+
#include "GPU_material.h"
/** Free (or release) any data used by this world (does not free the world itself). */
@@ -161,13 +163,10 @@ void BKE_world_make_local(Main *bmain, World *wrld, const bool lib_local)
BKE_id_make_local_generic(bmain, &wrld->id, true, lib_local);
}
-void BKE_world_eval(struct Depsgraph *UNUSED(depsgraph), World *world)
+void BKE_world_eval(struct Depsgraph *depsgraph, World *world)
{
- if (G.debug & G_DEBUG_DEPSGRAPH_EVAL) {
- printf("%s on %s (%p)\n", __func__, world->id.name, world);
- }
+ DEG_debug_print_eval(depsgraph, __func__, world->id.name, world);
if (!BLI_listbase_is_empty(&world->gpumaterial)) {
world->update_flag = 1;
- GPU_material_uniform_buffer_tag_dirty(&world->gpumaterial);
}
}
diff --git a/source/blender/blenkernel/intern/writeavi.c b/source/blender/blenkernel/intern/writeavi.c
index e357f13530d..33ac312425b 100644
--- a/source/blender/blenkernel/intern/writeavi.c
+++ b/source/blender/blenkernel/intern/writeavi.c
@@ -145,7 +145,7 @@ static void filepath_avi(char *string, RenderData *rd, bool preview, const char
}
strcpy(string, rd->pic);
- BLI_path_abs(string, G.main->name);
+ BLI_path_abs(string, BKE_main_blendfile_path_from_global());
BLI_make_existing_file(string);
diff --git a/source/blender/blenkernel/intern/writeffmpeg.c b/source/blender/blenkernel/intern/writeffmpeg.c
index 4a0f697c9ce..17c665f3bcd 100644
--- a/source/blender/blenkernel/intern/writeffmpeg.c
+++ b/source/blender/blenkernel/intern/writeffmpeg.c
@@ -1127,7 +1127,7 @@ static void ffmpeg_filepath_get(FFMpegContext *context, char *string, RenderData
}
strcpy(string, rd->pic);
- BLI_path_abs(string, G.main->name);
+ BLI_path_abs(string, BKE_main_blendfile_path_from_global());
BLI_make_existing_file(string);
diff --git a/source/blender/blenlib/BLI_math_base.h b/source/blender/blenlib/BLI_math_base.h
index 6f8e48d83b2..f455436ce63 100644
--- a/source/blender/blenlib/BLI_math_base.h
+++ b/source/blender/blenlib/BLI_math_base.h
@@ -200,24 +200,28 @@ double double_round(double x, int ndigits);
* check the vector is unit length, or zero length (which can't be helped in some cases).
*/
#ifndef NDEBUG
-/* note: 0.0001 is too small becaues normals may be converted from short's: see [#34322] */
+/** \note 0.0001 is too small becaues normals may be converted from short's: see T34322. */
# define BLI_ASSERT_UNIT_EPSILON 0.0002f
+/**
+ * \note Checks are flipped so NAN doesn't assert. This is done because we're making sure the value was normalized
+ * and in the case we don't want NAN to be raising asserts since there is nothing to be done in that case.
+ */
# define BLI_ASSERT_UNIT_V3(v) { \
const float _test_unit = len_squared_v3(v); \
- BLI_assert((fabsf(_test_unit - 1.0f) < BLI_ASSERT_UNIT_EPSILON) || \
- (fabsf(_test_unit) < BLI_ASSERT_UNIT_EPSILON)); \
+ BLI_assert(!(fabsf(_test_unit - 1.0f) >= BLI_ASSERT_UNIT_EPSILON) || \
+ !(fabsf(_test_unit) >= BLI_ASSERT_UNIT_EPSILON)); \
} (void)0
# define BLI_ASSERT_UNIT_V2(v) { \
const float _test_unit = len_squared_v2(v); \
- BLI_assert((fabsf(_test_unit - 1.0f) < BLI_ASSERT_UNIT_EPSILON) || \
- (fabsf(_test_unit) < BLI_ASSERT_UNIT_EPSILON)); \
+ BLI_assert(!(fabsf(_test_unit - 1.0f) >= BLI_ASSERT_UNIT_EPSILON) || \
+ !(fabsf(_test_unit) >= BLI_ASSERT_UNIT_EPSILON)); \
} (void)0
# define BLI_ASSERT_UNIT_QUAT(q) { \
const float _test_unit = dot_qtqt(q, q); \
- BLI_assert((fabsf(_test_unit - 1.0f) < BLI_ASSERT_UNIT_EPSILON * 10) || \
- (fabsf(_test_unit) < BLI_ASSERT_UNIT_EPSILON * 10)); \
+ BLI_assert(!(fabsf(_test_unit - 1.0f) >= BLI_ASSERT_UNIT_EPSILON * 10) || \
+ !(fabsf(_test_unit) >= BLI_ASSERT_UNIT_EPSILON * 10)); \
} (void)0
# define BLI_ASSERT_ZERO_M3(m) { \
diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c
index e6a5bc9a738..87dda371b88 100644
--- a/source/blender/blenloader/intern/readfile.c
+++ b/source/blender/blenloader/intern/readfile.c
@@ -141,6 +141,7 @@
#include "BKE_material.h"
#include "BKE_main.h" // for Main
#include "BKE_mesh.h" // for ME_ defines (patching)
+#include "BKE_mesh_runtime.h"
#include "BKE_modifier.h"
#include "BKE_multires.h"
#include "BKE_node.h" // for tree type defines
@@ -8518,11 +8519,11 @@ static BHead *read_global(BlendFileData *bfd, FileData *fd, BHead *bhead)
if (bfd->filename[0] == 0) {
if (fd->fileversion < 265 || (fd->fileversion == 265 && fg->subversion < 1))
if ((G.fileflags & G_FILE_RECOVER)==0)
- BLI_strncpy(bfd->filename, bfd->main->name, sizeof(bfd->filename));
+ BLI_strncpy(bfd->filename, BKE_main_blendfile_path(bfd->main), sizeof(bfd->filename));
/* early 2.50 version patch - filename not in FileGlobal struct at all */
if (fd->fileversion <= 250)
- BLI_strncpy(bfd->filename, bfd->main->name, sizeof(bfd->filename));
+ BLI_strncpy(bfd->filename, BKE_main_blendfile_path(bfd->main), sizeof(bfd->filename));
}
if (G.fileflags & G_FILE_RECOVER)
@@ -10093,6 +10094,7 @@ static void add_collections_to_scene(
/* Assign the collection. */
ob->dup_group = collection;
+ id_us_plus(&collection->id);
ob->transflag |= OB_DUPLICOLLECTION;
copy_v3_v3(ob->loc, scene->cursor.location);
}
@@ -10348,7 +10350,7 @@ static Main *library_link_begin(Main *mainvar, FileData **fd, const char *filepa
blo_split_main((*fd)->mainlist, mainvar);
/* which one do we need? */
- mainl = blo_find_main(*fd, filepath, G.main->name);
+ mainl = blo_find_main(*fd, filepath, BKE_main_blendfile_path(mainvar));
/* needed for do_version */
mainl->versionfile = (*fd)->fileversion;
@@ -10423,7 +10425,7 @@ static void library_link_end(Main *mainl, FileData **fd, const short flag, Main
BLI_strncpy(curlib->name, curlib->filepath, sizeof(curlib->name));
/* uses current .blend file as reference */
- BLI_path_rel(curlib->name, G.main->name);
+ BLI_path_rel(curlib->name, BKE_main_blendfile_path_from_global());
}
blo_join_main((*fd)->mainlist);
@@ -10453,7 +10455,7 @@ static void library_link_end(Main *mainl, FileData **fd, const short flag, Main
BKE_main_id_tag_all(mainvar, LIB_TAG_NEW, false);
lib_verify_nodetree(mainvar, false);
- fix_relpaths_library(G.main->name, mainvar); /* make all relative paths, relative to the open blend file */
+ fix_relpaths_library(BKE_main_blendfile_path(mainvar), mainvar); /* make all relative paths, relative to the open blend file */
/* Give a base to loose objects and collections.
* Only directly linked objects & collections are instantiated by `BLO_library_link_named_part_ex()` & co,
@@ -10574,7 +10576,7 @@ static void read_libraries(FileData *basefd, ListBase *mainlist)
while (fd == NULL) {
char newlib_path[FILE_MAX] = {0};
printf("Missing library...'\n");
- printf(" current file: %s\n", G.main->name);
+ printf(" current file: %s\n", BKE_main_blendfile_path_from_global());
printf(" absolute lib: %s\n", mainptr->curlib->filepath);
printf(" relative lib: %s\n", mainptr->curlib->name);
printf(" enter a new path:\n");
@@ -10582,7 +10584,7 @@ static void read_libraries(FileData *basefd, ListBase *mainlist)
if (scanf("%1023s", newlib_path) > 0) { /* Warning, keep length in sync with FILE_MAX! */
BLI_strncpy(mainptr->curlib->name, newlib_path, sizeof(mainptr->curlib->name));
BLI_strncpy(mainptr->curlib->filepath, newlib_path, sizeof(mainptr->curlib->filepath));
- BLI_cleanup_path(G.main->name, mainptr->curlib->filepath);
+ BLI_cleanup_path(BKE_main_blendfile_path_from_global(), mainptr->curlib->filepath);
fd = blo_openblenderfile(mainptr->curlib->filepath, basefd->reports);
diff --git a/source/blender/blenloader/intern/readfile.h b/source/blender/blenloader/intern/readfile.h
index 299c66f2bbb..7618c023882 100644
--- a/source/blender/blenloader/intern/readfile.h
+++ b/source/blender/blenloader/intern/readfile.h
@@ -169,14 +169,14 @@ void blo_do_version_old_trackto_to_constraints(struct Object *ob);
void blo_do_versions_view3d_split_250(struct View3D *v3d, struct ListBase *regions);
void blo_do_versions_key_uidgen(struct Key *key);
-void blo_do_versions_pre250(struct FileData *fd, struct Library *lib, struct Main *main);
-void blo_do_versions_250(struct FileData *fd, struct Library *lib, struct Main *main);
-void blo_do_versions_260(struct FileData *fd, struct Library *lib, struct Main *main);
-void blo_do_versions_270(struct FileData *fd, struct Library *lib, struct Main *main);
-void blo_do_versions_280(struct FileData *fd, struct Library *lib, struct Main *main);
-
-void do_versions_after_linking_270(struct Main *main);
-void do_versions_after_linking_280(struct Main *main);
+void blo_do_versions_pre250(struct FileData *fd, struct Library *lib, struct Main *bmain);
+void blo_do_versions_250(struct FileData *fd, struct Library *lib, struct Main *bmain);
+void blo_do_versions_260(struct FileData *fd, struct Library *lib, struct Main *bmain);
+void blo_do_versions_270(struct FileData *fd, struct Library *lib, struct Main *bmain);
+void blo_do_versions_280(struct FileData *fd, struct Library *lib, struct Main *bmain);
+
+void do_versions_after_linking_270(struct Main *bmain);
+void do_versions_after_linking_280(struct Main *bmain);
#endif
diff --git a/source/blender/blenloader/intern/undofile.c b/source/blender/blenloader/intern/undofile.c
index 7133dee0e82..e1ae267ea11 100644
--- a/source/blender/blenloader/intern/undofile.c
+++ b/source/blender/blenloader/intern/undofile.c
@@ -130,7 +130,7 @@ void memfile_chunk_add(
struct Main *BLO_memfile_main_get(struct MemFile *memfile, struct Main *oldmain, struct Scene **r_scene)
{
struct Main *bmain_undo = NULL;
- BlendFileData *bfd = BLO_read_from_memfile(oldmain, oldmain->name, memfile, NULL, BLO_READ_SKIP_NONE);
+ BlendFileData *bfd = BLO_read_from_memfile(oldmain, BKE_main_blendfile_path(oldmain), memfile, NULL, BLO_READ_SKIP_NONE);
if (bfd) {
bmain_undo = bfd->main;
diff --git a/source/blender/blenloader/intern/versioning_250.c b/source/blender/blenloader/intern/versioning_250.c
index 3f85011db0b..d51289bee43 100644
--- a/source/blender/blenloader/intern/versioning_250.c
+++ b/source/blender/blenloader/intern/versioning_250.c
@@ -641,11 +641,11 @@ static void do_versions_socket_default_value_259(bNodeSocket *sock)
}
}
-void blo_do_versions_250(FileData *fd, Library *lib, Main *main)
+void blo_do_versions_250(FileData *fd, Library *lib, Main *bmain)
{
/* WATCH IT!!!: pointers from libdata have not been converted */
- if (main->versionfile < 250) {
+ if (bmain->versionfile < 250) {
bScreen *screen;
Scene *scene;
Base *base;
@@ -663,22 +663,22 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *main)
bSound *sound;
Sequence *seq;
- for (sound = main->sound.first; sound; sound = sound->id.next) {
+ for (sound = bmain->sound.first; sound; sound = sound->id.next) {
if (sound->newpackedfile) {
sound->packedfile = sound->newpackedfile;
sound->newpackedfile = NULL;
}
}
- for (scene = main->scene.first; scene; scene = scene->id.next) {
+ for (scene = bmain->scene.first; scene; scene = scene->id.next) {
if (scene->ed && scene->ed->seqbasep) {
SEQ_BEGIN (scene->ed, seq)
{
if (seq->type == SEQ_TYPE_SOUND_HD) {
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 = BKE_sound_new_file(main, str);
+ BLI_path_abs(str, BKE_main_blendfile_path(bmain));
+ seq->sound = BKE_sound_new_file(bmain, str);
}
#define SEQ_USE_PROXY_CUSTOM_DIR (1 << 19)
#define SEQ_USE_PROXY_CUSTOM_FILE (1 << 21)
@@ -695,21 +695,21 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *main)
}
}
- for (screen = main->screen.first; screen; screen = screen->id.next) {
+ for (screen = bmain->screen.first; screen; screen = screen->id.next) {
do_versions_windowmanager_2_50(screen);
- do_versions_gpencil_2_50(main, screen);
+ do_versions_gpencil_2_50(bmain, screen);
}
/* shader, composite and texture node trees have id.name empty, put something in
* to have them show in RNA viewer and accessible otherwise.
*/
- for (ma = main->mat.first; ma; ma = ma->id.next) {
+ for (ma = bmain->mat.first; ma; ma = ma->id.next) {
if (ma->nodetree && ma->nodetree->id.name[0] == '\0')
strcpy(ma->nodetree->id.name, "NTShader Nodetree");
}
/* and composite trees */
- for (sce = main->scene.first; sce; sce = sce->id.next) {
+ for (sce = bmain->scene.first; sce; sce = sce->id.next) {
if (sce->nodetree && sce->nodetree->id.name[0] == '\0')
strcpy(sce->nodetree->id.name, "NTCompositing Nodetree");
@@ -729,7 +729,7 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *main)
}
/* and texture trees */
- for (tx = main->tex.first; tx; tx = tx->id.next) {
+ for (tx = bmain->tex.first; tx; tx = tx->id.next) {
bNode *node;
if (tx->nodetree) {
@@ -744,12 +744,12 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *main)
}
/* copy standard draw flag to meshes(used to be global, is not available here) */
- for (me = main->mesh.first; me; me = me->id.next) {
+ for (me = bmain->mesh.first; me; me = me->id.next) {
me->drawflag = ME_DRAWEDGES|ME_DRAWFACES|ME_DRAWCREASES;
}
/* particle draw and render types */
- for (part = main->particle.first; part; part = part->id.next) {
+ for (part = bmain->particle.first; part; part = part->id.next) {
if (part->draw_as) {
if (part->draw_as == PART_DRAW_DOT) {
part->ren_as = PART_DRAW_HALO;
@@ -768,7 +768,7 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *main)
}
/* set old pointcaches to have disk cache flag */
- for (ob = main->object.first; ob; ob = ob->id.next) {
+ for (ob = bmain->object.first; ob; ob = ob->id.next) {
//BKE_ptcache_ids_from_object(&pidlist, ob);
@@ -779,7 +779,7 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *main)
}
/* type was a mixed flag & enum. move the 2d flag elsewhere */
- for (cu = main->curve.first; cu; cu = cu->id.next) {
+ for (cu = bmain->curve.first; cu; cu = cu->id.next) {
Nurb *nu;
for (nu = cu->nurb.first; nu; nu = nu->next) {
@@ -789,7 +789,7 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *main)
}
}
- if (main->versionfile < 250 || (main->versionfile == 250 && main->subversionfile < 1)) {
+ if (bmain->versionfile < 250 || (bmain->versionfile == 250 && bmain->subversionfile < 1)) {
Object *ob;
Tex *tex;
Scene *sce;
@@ -797,7 +797,7 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *main)
//PTCacheID *pid;
//ListBase pidlist;
- for (ob = main->object.first; ob; ob = ob->id.next) {
+ for (ob = bmain->object.first; ob; ob = ob->id.next) {
//BKE_ptcache_ids_from_object(&pidlist, ob);
//for (pid = pidlist.first; pid; pid = pid->next) {
@@ -831,12 +831,12 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *main)
}
/* texture filter */
- for (tex = main->tex.first; tex; tex = tex->id.next) {
+ for (tex = bmain->tex.first; tex; tex = tex->id.next) {
if (tex->afmax == 0)
tex->afmax = 8;
}
- for (sce = main->scene.first; sce; sce = sce->id.next) {
+ for (sce = bmain->scene.first; sce; sce = sce->id.next) {
ts = sce->toolsettings;
if (!ts->uv_selectmode || ts->vgroup_weight == 0.0f) {
ts->selectmode = SCE_SELECT_VERTEX;
@@ -854,26 +854,26 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *main)
}
}
- if (main->versionfile < 250 || (main->versionfile == 250 && main->subversionfile < 2)) {
+ if (bmain->versionfile < 250 || (bmain->versionfile == 250 && bmain->subversionfile < 2)) {
Object *ob;
- for (ob = main->object.first; ob; ob = ob->id.next) {
+ for (ob = bmain->object.first; ob; ob = ob->id.next) {
if (ob->flag & 8192) // OB_POSEMODE = 8192
ob->mode |= OB_MODE_POSE;
}
}
- if (main->versionfile < 250 || (main->versionfile == 250 && main->subversionfile < 4)) {
+ if (bmain->versionfile < 250 || (bmain->versionfile == 250 && bmain->subversionfile < 4)) {
Scene *sce;
Object *ob;
ParticleSettings *part;
bool do_gravity = false;
- for (sce = main->scene.first; sce; sce = sce->id.next)
+ for (sce = bmain->scene.first; sce; sce = sce->id.next)
if (sce->unit.scale_length == 0.0f)
sce->unit.scale_length = 1.0f;
- for (ob = main->object.first; ob; ob = ob->id.next) {
+ for (ob = bmain->object.first; ob; ob = ob->id.next) {
/* fluid-sim stuff */
FluidsimModifierData *fluidmd = (FluidsimModifierData *) modifiers_findByType(ob, eModifierType_Fluidsim);
if (fluidmd)
@@ -883,7 +883,7 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *main)
ob->rotmode = ROT_MODE_EUL;
}
- for (sce = main->scene.first; sce; sce = sce->id.next) {
+ for (sce = bmain->scene.first; sce; sce = sce->id.next) {
if (sce->audio.main == 0.0f)
sce->audio.main = 1.0f;
@@ -895,7 +895,7 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *main)
}
/* Add default gravity to scenes */
- for (sce = main->scene.first; sce; sce = sce->id.next) {
+ for (sce = bmain->scene.first; sce; sce = sce->id.next) {
if ((sce->physics_settings.flag & PHYS_GLOBAL_GRAVITY) == 0 &&
is_zero_v3(sce->physics_settings.gravity))
{
@@ -908,11 +908,11 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *main)
/* Assign proper global gravity weights for dynamics (only z-coordinate is taken into account) */
if (do_gravity) {
- for (part = main->particle.first; part; part = part->id.next)
+ for (part = bmain->particle.first; part; part = part->id.next)
part->effector_weights->global_gravity = part->acc[2]/-9.81f;
}
- for (ob = main->object.first; ob; ob = ob->id.next) {
+ for (ob = bmain->object.first; ob; ob = ob->id.next) {
ModifierData *md;
if (do_gravity) {
@@ -941,11 +941,11 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *main)
}
}
- if (main->versionfile < 250 || (main->versionfile == 250 && main->subversionfile < 6)) {
+ if (bmain->versionfile < 250 || (bmain->versionfile == 250 && bmain->subversionfile < 6)) {
Object *ob;
/* New variables for axis-angle rotations and/or quaternion rotations were added, and need proper initialization */
- for (ob = main->object.first; ob; ob = ob->id.next) {
+ for (ob = bmain->object.first; ob; ob = ob->id.next) {
/* new variables for all objects */
ob->quat[0] = 1.0f;
ob->rotAxis[1] = 1.0f;
@@ -962,7 +962,7 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *main)
}
}
- if (main->versionfile < 250 || (main->versionfile == 250 && main->subversionfile < 7)) {
+ if (bmain->versionfile < 250 || (bmain->versionfile == 250 && bmain->subversionfile < 7)) {
Mesh *me;
Nurb *nu;
Lattice *lt;
@@ -974,7 +974,7 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *main)
/* shape keys are no longer applied to the mesh itself, but rather
* to the derivedmesh/displist, so here we ensure that the basis
* shape key is always set in the mesh coordinates. */
- for (me = main->mesh.first; me; me = me->id.next) {
+ for (me = bmain->mesh.first; me; me = me->id.next) {
if ((key = blo_do_versions_newlibadr(fd, lib, me->key)) && key->refkey) {
data = key->refkey->data;
tot = MIN2(me->totvert, key->refkey->totelem);
@@ -984,7 +984,7 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *main)
}
}
- for (lt = main->latt.first; lt; lt = lt->id.next) {
+ for (lt = bmain->latt.first; lt; lt = lt->id.next) {
if ((key = blo_do_versions_newlibadr(fd, lib, lt->key)) && key->refkey) {
data = key->refkey->data;
tot = MIN2(lt->pntsu*lt->pntsv*lt->pntsw, key->refkey->totelem);
@@ -994,7 +994,7 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *main)
}
}
- for (cu = main->curve.first; cu; cu = cu->id.next) {
+ for (cu = bmain->curve.first; cu; cu = cu->id.next) {
if ((key = blo_do_versions_newlibadr(fd, lib, cu->key)) && key->refkey) {
data = key->refkey->data;
@@ -1022,9 +1022,9 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *main)
}
}
- if (main->versionfile < 250 || (main->versionfile == 250 && main->subversionfile < 8)) {
+ if (bmain->versionfile < 250 || (bmain->versionfile == 250 && bmain->subversionfile < 8)) {
{
- Scene *sce = main->scene.first;
+ Scene *sce = bmain->scene.first;
while (sce) {
if (sce->r.frame_step == 0)
sce->r.frame_step = 1;
@@ -1039,7 +1039,7 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *main)
{
/* ensure all nodes have unique names */
- bNodeTree *ntree = main->nodetree.first;
+ bNodeTree *ntree = bmain->nodetree.first;
while (ntree) {
bNode *node = ntree->nodes.first;
@@ -1053,7 +1053,7 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *main)
}
{
- Object *ob = main->object.first;
+ Object *ob = bmain->object.first;
while (ob) {
/* shaded mode disabled for now */
if (ob->dt == OB_MATERIAL)
@@ -1067,7 +1067,7 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *main)
ScrArea *sa;
SpaceLink *sl;
- for (screen = main->screen.first; screen; screen = screen->id.next) {
+ for (screen = bmain->screen.first; screen; screen = screen->id.next) {
for (sa = screen->areabase.first; sa; sa = sa->next) {
for (sl = sa->spacedata.first; sl; sl = sl->next) {
if (sl->spacetype == SPACE_VIEW3D) {
@@ -1081,10 +1081,10 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *main)
}
/* only convert old 2.50 files with color management */
- if (main->versionfile == 250) {
- Scene *sce = main->scene.first;
- Material *ma = main->mat.first;
- Tex *tex = main->tex.first;
+ if (bmain->versionfile == 250) {
+ Scene *sce = bmain->scene.first;
+ Material *ma = bmain->mat.first;
+ Tex *tex = bmain->tex.first;
int i, convert = 0;
/* convert to new color management system:
@@ -1120,20 +1120,20 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *main)
}
}
- if (main->versionfile < 250 || (main->versionfile == 250 && main->subversionfile < 9)) {
+ if (bmain->versionfile < 250 || (bmain->versionfile == 250 && bmain->subversionfile < 9)) {
Scene *sce;
Mesh *me;
Object *ob;
- for (sce = main->scene.first; sce; sce = sce->id.next)
+ for (sce = bmain->scene.first; sce; sce = sce->id.next)
if (!sce->toolsettings->particle.selectmode)
sce->toolsettings->particle.selectmode = SCE_SELECT_PATH;
- if (main->versionfile == 250 && main->subversionfile > 1) {
- for (me = main->mesh.first; me; me = me->id.next)
+ if (bmain->versionfile == 250 && bmain->subversionfile > 1) {
+ for (me = bmain->mesh.first; me; me = me->id.next)
multires_load_old_250(me);
- for (ob = main->object.first; ob; ob = ob->id.next) {
+ for (ob = bmain->object.first; ob; ob = ob->id.next) {
MultiresModifierData *mmd = (MultiresModifierData *) modifiers_findByType(ob, eModifierType_Multires);
if (mmd) {
@@ -1146,11 +1146,11 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *main)
}
}
- if (main->versionfile < 250 || (main->versionfile == 250 && main->subversionfile < 10)) {
+ if (bmain->versionfile < 250 || (bmain->versionfile == 250 && bmain->subversionfile < 10)) {
Object *ob;
/* properly initialize hair clothsim data on old files */
- for (ob = main->object.first; ob; ob = ob->id.next) {
+ for (ob = bmain->object.first; ob; ob = ob->id.next) {
ModifierData *md;
for (md = ob->modifiers.first; md; md = md->next) {
if (md->type == eModifierType_Cloth) {
@@ -1163,14 +1163,14 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *main)
}
/* fix bad area setup in subversion 10 */
- if (main->versionfile == 250 && main->subversionfile == 10) {
+ if (bmain->versionfile == 250 && bmain->subversionfile == 10) {
/* fix for new view type in sequencer */
bScreen *screen;
ScrArea *sa;
SpaceLink *sl;
/* remove all preview window in wrong spaces */
- for (screen = main->screen.first; screen; screen = screen->id.next) {
+ for (screen = bmain->screen.first; screen; screen = screen->id.next) {
for (sa = screen->areabase.first; sa; sa = sa->next) {
for (sl = sa->spacedata.first; sl; sl = sl->next) {
if (sl->spacetype != SPACE_SEQ) {
@@ -1200,14 +1200,14 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *main)
}
}
- if (main->versionfile < 250 || (main->versionfile == 250 && main->subversionfile < 11)) {
+ if (bmain->versionfile < 250 || (bmain->versionfile == 250 && bmain->subversionfile < 11)) {
{
/* fix for new view type in sequencer */
bScreen *screen;
ScrArea *sa;
SpaceLink *sl;
- for (screen = main->screen.first; screen; screen = screen->id.next) {
+ for (screen = bmain->screen.first; screen; screen = screen->id.next) {
for (sa = screen->areabase.first; sa; sa = sa->next) {
for (sl = sa->spacedata.first; sl; sl = sl->next) {
if (sl->spacetype == SPACE_SEQ) {
@@ -1243,12 +1243,12 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *main)
}
}
- if (main->versionfile < 250 || (main->versionfile == 250 && main->subversionfile < 12)) {
+ if (bmain->versionfile < 250 || (bmain->versionfile == 250 && bmain->subversionfile < 12)) {
Object *ob;
Brush *brush;
/* anim viz changes */
- for (ob = main->object.first; ob; ob = ob->id.next) {
+ for (ob = bmain->object.first; ob; ob = ob->id.next) {
/* initialize object defaults */
animviz_settings_init(&ob->avs);
@@ -1323,19 +1323,19 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *main)
}
/* brush texture changes */
- for (brush = main->brush.first; brush; brush = brush->id.next) {
+ for (brush = bmain->brush.first; brush; brush = brush->id.next) {
BKE_texture_mtex_default(&brush->mtex);
BKE_texture_mtex_default(&brush->mask_mtex);
}
}
- if (main->versionfile < 250 || (main->versionfile == 250 && main->subversionfile < 13)) {
+ if (bmain->versionfile < 250 || (bmain->versionfile == 250 && bmain->subversionfile < 13)) {
/* NOTE: if you do more conversion, be sure to do it outside of this and
* increase subversion again, otherwise it will not be correct */
Object *ob;
/* convert degrees to radians for internal use */
- for (ob = main->object.first; ob; ob = ob->id.next) {
+ for (ob = bmain->object.first; ob; ob = ob->id.next) {
bPoseChannel *pchan;
do_version_constraints_radians_degrees_250(&ob->constraints);
@@ -1355,13 +1355,13 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *main)
}
}
- if (main->versionfile < 250 || (main->versionfile == 250 && main->subversionfile < 14)) {
+ if (bmain->versionfile < 250 || (bmain->versionfile == 250 && bmain->subversionfile < 14)) {
/* fix for bad View2D extents for Animation Editors */
bScreen *screen;
ScrArea *sa;
SpaceLink *sl;
- for (screen = main->screen.first; screen; screen = screen->id.next) {
+ for (screen = bmain->screen.first; screen; screen = screen->id.next) {
for (sa = screen->areabase.first; sa; sa = sa->next) {
for (sl = sa->spacedata.first; sl; sl = sl->next) {
ListBase *regionbase;
@@ -1385,12 +1385,12 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *main)
}
}
- if (main->versionfile < 250 || (main->versionfile == 250 && main->subversionfile < 17)) {
+ if (bmain->versionfile < 250 || (bmain->versionfile == 250 && bmain->subversionfile < 17)) {
Scene *sce;
Sequence *seq;
/* initialize to sane default so toggling on border shows something */
- for (sce = main->scene.first; sce; sce = sce->id.next) {
+ for (sce = bmain->scene.first; sce; sce = sce->id.next) {
if (sce->r.border.xmin == 0.0f && sce->r.border.ymin == 0.0f &&
sce->r.border.xmax == 0.0f && sce->r.border.ymax == 0.0f)
{
@@ -1411,7 +1411,7 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *main)
}
/* particle brush strength factor was changed from int to float */
- for (sce = main->scene.first; sce; sce = sce->id.next) {
+ for (sce = bmain->scene.first; sce; sce = sce->id.next) {
ParticleEditSettings *pset = &sce->toolsettings->particle;
int a;
@@ -1425,7 +1425,7 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *main)
ScrArea *sa;
SpaceLink *sl;
- for (screen = main->screen.first; screen; screen = screen->id.next) {
+ for (screen = bmain->screen.first; screen; screen = screen->id.next) {
for (sa = screen->areabase.first; sa; sa = sa->next) {
for (sl = sa->spacedata.first; sl; sl = sl->next) {
if (sl->spacetype == SPACE_SEQ) {
@@ -1454,14 +1454,14 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *main)
} /* sequencer changes */
}
- if (main->versionfile <= 251) { /* 2.5.1 had no subversions */
+ if (bmain->versionfile <= 251) { /* 2.5.1 had no subversions */
bScreen *sc;
/* Blender 2.5.2 - subversion 0 introduced a new setting: V3D_RENDER_OVERRIDE.
* This bit was used in the past for V3D_TRANSFORM_SNAP, which is now deprecated.
* Here we clear it for old files so they don't come in with V3D_RENDER_OVERRIDE set,
* which would cause cameras, lamps, etc to become invisible */
- for (sc = main->screen.first; sc; sc = sc->id.next) {
+ for (sc = bmain->screen.first; sc; sc = sc->id.next) {
ScrArea *sa;
for (sa = sc->areabase.first; sa; sa = sa->next) {
SpaceLink *sl;
@@ -1475,19 +1475,19 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *main)
}
}
- if (main->versionfile < 252 || (main->versionfile == 252 && main->subversionfile < 1)) {
+ if (bmain->versionfile < 252 || (bmain->versionfile == 252 && bmain->subversionfile < 1)) {
Brush *brush;
Object *ob;
Scene *scene;
bNodeTree *ntree;
- for (brush = main->brush.first; brush; brush = brush->id.next) {
+ for (brush = bmain->brush.first; brush; brush = brush->id.next) {
if (brush->curve)
brush->curve->preset = CURVE_PRESET_SMOOTH;
}
/* properly initialize active flag for fluidsim modifiers */
- for (ob = main->object.first; ob; ob = ob->id.next) {
+ for (ob = bmain->object.first; ob; ob = ob->id.next) {
ModifierData *md;
for (md = ob->modifiers.first; md; md = md->next) {
if (md->type == eModifierType_Fluidsim) {
@@ -1499,7 +1499,7 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *main)
}
/* adjustment to color balance node values */
- for (scene = main->scene.first; scene; scene = scene->id.next) {
+ for (scene = bmain->scene.first; scene; scene = scene->id.next) {
if (scene->nodetree) {
bNode *node = scene->nodetree->nodes.first;
@@ -1515,7 +1515,7 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *main)
}
}
/* check inside node groups too */
- for (ntree = main->nodetree.first; ntree; ntree = ntree->id.next) {
+ for (ntree = bmain->nodetree.first; ntree; ntree = ntree->id.next) {
bNode *node = ntree->nodes.first;
while (node) {
@@ -1532,18 +1532,18 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *main)
}
/* old-track -> constraints (this time we're really doing it!) */
- if (main->versionfile < 252 || (main->versionfile == 252 && main->subversionfile < 2)) {
+ if (bmain->versionfile < 252 || (bmain->versionfile == 252 && bmain->subversionfile < 2)) {
Object *ob;
- for (ob = main->object.first; ob; ob = ob->id.next)
+ for (ob = bmain->object.first; ob; ob = ob->id.next)
blo_do_version_old_trackto_to_constraints(ob);
}
- if (main->versionfile < 252 || (main->versionfile == 252 && main->subversionfile < 5)) {
+ if (bmain->versionfile < 252 || (bmain->versionfile == 252 && bmain->subversionfile < 5)) {
bScreen *sc;
/* Image editor scopes */
- for (sc = main->screen.first; sc; sc = sc->id.next) {
+ for (sc = bmain->screen.first; sc; sc = sc->id.next) {
ScrArea *sa;
for (sa = sc->areabase.first; sa; sa = sa->next) {
@@ -1559,14 +1559,14 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *main)
}
}
- if (main->versionfile < 253) {
+ if (bmain->versionfile < 253) {
Object *ob;
Scene *scene;
bScreen *sc;
Tex *tex;
Brush *brush;
- for (sc = main->screen.first; sc; sc = sc->id.next) {
+ for (sc = bmain->screen.first; sc; sc = sc->id.next) {
ScrArea *sa;
for (sa = sc->areabase.first; sa; sa = sa->next) {
SpaceLink *sl;
@@ -1600,10 +1600,10 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *main)
}
}
- do_version_mdef_250(main);
+ do_version_mdef_250(bmain);
/* parent type to modifier */
- for (ob = main->object.first; ob; ob = ob->id.next) {
+ for (ob = bmain->object.first; ob; ob = ob->id.next) {
if (ob->parent) {
Object *parent = (Object *) blo_do_versions_newlibadr(fd, lib, ob->parent);
if (parent) { /* parent may not be in group */
@@ -1638,7 +1638,7 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *main)
}
/* initialize scene active layer */
- for (scene = main->scene.first; scene; scene = scene->id.next) {
+ for (scene = bmain->scene.first; scene; scene = scene->id.next) {
int i;
for (i = 0; i < 20; i++) {
if (scene->lay & (1<<i)) {
@@ -1648,7 +1648,7 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *main)
}
}
- for (tex = main->tex.first; tex; tex = tex->id.next) {
+ for (tex = bmain->tex.first; tex; tex = tex->id.next) {
/* if youre picky, this isn't correct until we do a version bump
* since you could set saturation to be 0.0*/
if (tex->saturation == 0.0f)
@@ -1657,12 +1657,12 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *main)
{
Curve *cu;
- for (cu = main->curve.first; cu; cu = cu->id.next) {
+ for (cu = bmain->curve.first; cu; cu = cu->id.next) {
cu->smallcaps_scale = 0.75f;
}
}
- for (scene = main->scene.first; scene; scene = scene->id.next) {
+ for (scene = bmain->scene.first; scene; scene = scene->id.next) {
if (scene) {
Sequence *seq;
SEQ_BEGIN (scene->ed, seq)
@@ -1677,7 +1677,7 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *main)
/* GSOC 2010 Sculpt - New settings for Brush */
- for (brush = main->brush.first; brush; brush = brush->id.next) {
+ for (brush = bmain->brush.first; brush; brush = brush->id.next) {
/* Sanity Check */
/* infinite number of dabs */
@@ -1721,7 +1721,7 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *main)
brush->rate = 0.1f;
/* New Settings */
- if (main->versionfile < 252 || (main->versionfile == 252 && main->subversionfile < 5)) {
+ if (bmain->versionfile < 252 || (bmain->versionfile == 252 && bmain->subversionfile < 5)) {
brush->flag |= BRUSH_SPACE_ATTEN; // explicitly enable adaptive space
/* spacing was originally in pixels, convert it to percentage for new version
@@ -1751,9 +1751,9 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *main)
}
/* GSOC Sculpt 2010 - Sanity check on Sculpt/Paint settings */
- if (main->versionfile < 253) {
+ if (bmain->versionfile < 253) {
Scene *sce;
- for (sce = main->scene.first; sce; sce = sce->id.next) {
+ for (sce = bmain->scene.first; sce; sce = sce->id.next) {
if (sce->toolsettings->sculpt_paint_unified_alpha == 0)
sce->toolsettings->sculpt_paint_unified_alpha = 0.5f;
@@ -1765,10 +1765,10 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *main)
}
}
- if (main->versionfile < 253 || (main->versionfile == 253 && main->subversionfile < 1)) {
+ if (bmain->versionfile < 253 || (bmain->versionfile == 253 && bmain->subversionfile < 1)) {
Object *ob;
- for (ob = main->object.first; ob; ob = ob->id.next) {
+ for (ob = bmain->object.first; ob; ob = ob->id.next) {
ModifierData *md;
for (md = ob->modifiers.first; md; md = md->next) {
@@ -1788,7 +1788,7 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *main)
/* for now just add it to all flow objects in the scene */
{
Object *ob2;
- for (ob2 = main->object.first; ob2; ob2 = ob2->id.next) {
+ for (ob2 = bmain->object.first; ob2; ob2 = ob2->id.next) {
ModifierData *md2;
for (md2 = ob2->modifiers.first; md2; md2 = md2->next) {
if (md2->type == eModifierType_Smoke) {
@@ -1811,17 +1811,17 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *main)
}
}
- if (main->versionfile < 255 || (main->versionfile == 255 && main->subversionfile < 1)) {
+ if (bmain->versionfile < 255 || (bmain->versionfile == 255 && bmain->subversionfile < 1)) {
Brush *br;
ParticleSettings *part;
bScreen *sc;
- for (br = main->brush.first; br; br = br->id.next) {
+ for (br = bmain->brush.first; br; br = br->id.next) {
if (br->ob_mode == 0)
br->ob_mode = OB_MODE_ALL_PAINT;
}
- for (part = main->particle.first; part; part = part->id.next) {
+ for (part = bmain->particle.first; part; part = part->id.next) {
if (part->boids)
part->boids->pitch = 1.0f;
@@ -1829,7 +1829,7 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *main)
part->kink_amp_clump = 1.f; /* keep old files looking similar */
}
- for (sc = main->screen.first; sc; sc = sc->id.next) {
+ for (sc = bmain->screen.first; sc; sc = sc->id.next) {
ScrArea *sa;
for (sa = sc->areabase.first; sa; sa = sa->next) {
SpaceLink *sl;
@@ -1856,11 +1856,11 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *main)
}
}
- if (main->versionfile < 255 || (main->versionfile == 255 && main->subversionfile < 3)) {
+ if (bmain->versionfile < 255 || (bmain->versionfile == 255 && bmain->subversionfile < 3)) {
Object *ob;
/* ocean res is now squared, reset old ones - will be massive */
- for (ob = main->object.first; ob; ob = ob->id.next) {
+ for (ob = bmain->object.first; ob; ob = ob->id.next) {
ModifierData *md;
for (md = ob->modifiers.first; md; md = md->next) {
if (md->type == eModifierType_Ocean) {
@@ -1872,13 +1872,13 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *main)
}
}
- if (main->versionfile < 256) {
+ if (bmain->versionfile < 256) {
bScreen *sc;
ScrArea *sa;
Key *key;
/* Fix for sample line scope initializing with no height */
- for (sc = main->screen.first; sc; sc = sc->id.next) {
+ for (sc = bmain->screen.first; sc; sc = sc->id.next) {
sa = sc->areabase.first;
while (sa) {
SpaceLink *sl;
@@ -1897,7 +1897,7 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *main)
* 2.4x would never reveal this to users as a dummy value always ended up getting used
* instead
*/
- for (key = main->key.first; key; key = key->id.next) {
+ for (key = bmain->key.first; key; key = key->id.next) {
KeyBlock *kb;
for (kb = key->block.first; kb; kb = kb->next) {
@@ -1907,19 +1907,19 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *main)
}
}
- if (main->versionfile < 256 || (main->versionfile == 256 && main->subversionfile < 1)) {
+ if (bmain->versionfile < 256 || (bmain->versionfile == 256 && bmain->subversionfile < 1)) {
/* fix for bones that didn't have arm_roll before */
bArmature *arm;
Bone *bone;
Object *ob;
- for (arm = main->armature.first; arm; arm = arm->id.next)
+ for (arm = bmain->armature.first; arm; arm = arm->id.next)
for (bone = arm->bonebase.first; bone; bone = bone->next)
do_version_bone_roll_256(bone);
/* fix for objects which have zero dquat's
* since this is multiplied with the quat rather than added */
- for (ob = main->object.first; ob; ob = ob->id.next) {
+ for (ob = bmain->object.first; ob; ob = ob->id.next) {
if (is_zero_v4(ob->dquat)) {
unit_qt(ob->dquat);
}
@@ -1929,7 +1929,7 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *main)
}
}
- if (main->versionfile < 256 || (main->versionfile == 256 && main->subversionfile < 2)) {
+ if (bmain->versionfile < 256 || (bmain->versionfile == 256 && bmain->subversionfile < 2)) {
bNodeTree *ntree;
bNode *node;
bNodeSocket *sock, *gsock;
@@ -1938,7 +1938,7 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *main)
/* node sockets are not exposed automatically any more,
* this mimics the old behavior by adding all unlinked sockets to groups.
*/
- for (ntree=main->nodetree.first; ntree; ntree=ntree->id.next) {
+ for (ntree=bmain->nodetree.first; ntree; ntree=ntree->id.next) {
/* this adds copies and links from all unlinked internal sockets to group inputs/outputs. */
/* first make sure the own_index for new sockets is valid */
@@ -2007,14 +2007,14 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *main)
}
}
- if (main->versionfile < 256 || (main->versionfile == 256 && main->subversionfile < 3)) {
+ if (bmain->versionfile < 256 || (bmain->versionfile == 256 && bmain->subversionfile < 3)) {
bScreen *sc;
Brush *brush;
Object *ob;
ParticleSettings *part;
/* redraws flag in SpaceTime has been moved to Screen level */
- for (sc = main->screen.first; sc; sc = sc->id.next) {
+ for (sc = bmain->screen.first; sc; sc = sc->id.next) {
if (sc->redraws_flag == 0) {
/* just initialize to default? */
/* XXX: we could also have iterated through areas, and taken them from the first timeline available... */
@@ -2022,13 +2022,13 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *main)
}
}
- for (brush = main->brush.first; brush; brush = brush->id.next) {
+ for (brush = bmain->brush.first; brush; brush = brush->id.next) {
if (brush->height == 0)
brush->height = 0.4f;
}
/* replace 'rim material' option for in offset*/
- for (ob = main->object.first; ob; ob = ob->id.next) {
+ for (ob = bmain->object.first; ob; ob = ob->id.next) {
ModifierData *md;
for (md = ob->modifiers.first; md; md = md->next) {
if (md->type == eModifierType_Solidify) {
@@ -2042,24 +2042,24 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *main)
}
/* particle draw color from material */
- for (part = main->particle.first; part; part = part->id.next) {
+ for (part = bmain->particle.first; part; part = part->id.next) {
if (part->draw & PART_DRAW_MAT_COL)
part->draw_col = PART_DRAW_COL_MAT;
}
}
- if (main->versionfile < 256 || (main->versionfile == 256 && main->subversionfile < 6)) {
+ if (bmain->versionfile < 256 || (bmain->versionfile == 256 && bmain->subversionfile < 6)) {
Mesh *me;
- for (me = main->mesh.first; me; me = me->id.next)
+ for (me = bmain->mesh.first; me; me = me->id.next)
BKE_mesh_calc_normals_tessface(me->mvert, me->totvert, me->mface, me->totface, NULL);
}
- if (main->versionfile < 256 || (main->versionfile == 256 && main->subversionfile < 2)) {
+ if (bmain->versionfile < 256 || (bmain->versionfile == 256 && bmain->subversionfile < 2)) {
/* update blur area sizes from 0..1 range to 0..100 percentage */
Scene *scene;
bNode *node;
- for (scene = main->scene.first; scene; scene = scene->id.next)
+ for (scene = bmain->scene.first; scene; scene = scene->id.next)
if (scene->nodetree)
for (node = scene->nodetree->nodes.first; node; node = node->next)
if (node->type == CMP_NODE_BLUR) {
@@ -2069,13 +2069,13 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *main)
}
}
- if (main->versionfile < 258 || (main->versionfile == 258 && main->subversionfile < 1)) {
+ if (bmain->versionfile < 258 || (bmain->versionfile == 258 && bmain->subversionfile < 1)) {
/* screen view2d settings were not properly initialized [#27164]
* v2d->scroll caused the bug but best reset other values too which are in old blend files only.
* need to make less ugly - possibly an iterator? */
bScreen *screen;
- for (screen = main->screen.first; screen; screen = screen->id.next) {
+ for (screen = bmain->screen.first; screen; screen = screen->id.next) {
ScrArea *sa;
/* add regions */
for (sa = screen->areabase.first; sa; sa = sa->next) {
@@ -2106,19 +2106,19 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *main)
{
ParticleSettings *part;
- for (part = main->particle.first; part; part = part->id.next) {
+ for (part = bmain->particle.first; part; part = part->id.next) {
/* Initialize particle billboard scale */
part->bb_size[0] = part->bb_size[1] = 1.0f;
}
}
}
- if (main->versionfile < 259 || (main->versionfile == 259 && main->subversionfile < 1)) {
+ if (bmain->versionfile < 259 || (bmain->versionfile == 259 && bmain->subversionfile < 1)) {
{
Scene *scene;
Sequence *seq;
- for (scene = main->scene.first; scene; scene = scene->id.next) {
+ for (scene = bmain->scene.first; scene; scene = scene->id.next) {
scene->r.ffcodecdata.audio_channels = 2;
scene->audio.volume = 1.0f;
SEQ_BEGIN (scene->ed, seq)
@@ -2131,7 +2131,7 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *main)
{
bScreen *screen;
- for (screen = main->screen.first; screen; screen = screen->id.next) {
+ for (screen = bmain->screen.first; screen; screen = screen->id.next) {
ScrArea *sa;
/* add regions */
@@ -2172,7 +2172,7 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *main)
bAction *act;
FCurve *fcu;
- for (act = main->action.first; act; act = act->id.next) {
+ for (act = bmain->action.first; act; act = act->id.next) {
for (fcu = act->curves.first; fcu; fcu = fcu->next) {
BezTriple *bezt;
unsigned int i = 0;
@@ -2197,10 +2197,10 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *main)
}
}
- if (main->versionfile < 259 || (main->versionfile == 259 && main->subversionfile < 2)) {
+ if (bmain->versionfile < 259 || (bmain->versionfile == 259 && bmain->subversionfile < 2)) {
{
/* Convert default socket values from bNodeStack */
- FOREACH_NODETREE(main, ntree, id) {
+ FOREACH_NODETREE(bmain, ntree, id) {
bNode *node;
bNodeSocket *sock;
@@ -2227,17 +2227,17 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *main)
* associate them with specific node types for polling.
*/
bNodeTree *ntree;
- /* all node trees in main->nodetree are considered groups */
- for (ntree = main->nodetree.first; ntree; ntree = ntree->id.next)
+ /* all node trees in bmain->nodetree are considered groups */
+ for (ntree = bmain->nodetree.first; ntree; ntree = ntree->id.next)
ntree->nodetype = NODE_GROUP;
}
}
- if (main->versionfile < 259 || (main->versionfile == 259 && main->subversionfile < 4)) {
+ if (bmain->versionfile < 259 || (bmain->versionfile == 259 && bmain->subversionfile < 4)) {
{
/* Adaptive time step for particle systems */
ParticleSettings *part;
- for (part = main->particle.first; part; part = part->id.next) {
+ for (part = bmain->particle.first; part; part = part->id.next) {
part->courant_target = 0.2f;
part->time_flag &= ~PART_TIME_AUTOSF;
}
diff --git a/source/blender/blenloader/intern/versioning_260.c b/source/blender/blenloader/intern/versioning_260.c
index 8e0795f7e34..2cded68f7ec 100644
--- a/source/blender/blenloader/intern/versioning_260.c
+++ b/source/blender/blenloader/intern/versioning_260.c
@@ -608,15 +608,15 @@ static void do_versions_nodetree_customnodes(bNodeTree *ntree, int UNUSED(is_gro
}
}
-void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *main)
+void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *bmain)
{
- if (main->versionfile < 260) {
+ if (bmain->versionfile < 260) {
{
/* set default alpha value of Image outputs in image and render layer nodes to 0 */
Scene *sce;
bNodeTree *ntree;
- for (sce = main->scene.first; sce; sce = sce->id.next) {
+ for (sce = bmain->scene.first; sce; sce = sce->id.next) {
/* there are files with invalid audio_channels value, the real cause
* is unknown, but we fix it here anyway to avoid crashes */
if (sce->r.ffcodecdata.audio_channels == 0)
@@ -626,7 +626,7 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *main)
do_versions_nodetree_image_default_alpha_output(sce->nodetree);
}
- for (ntree = main->nodetree.first; ntree; ntree = ntree->id.next)
+ for (ntree = bmain->nodetree.first; ntree; ntree = ntree->id.next)
do_versions_nodetree_image_default_alpha_output(ntree);
}
@@ -634,7 +634,7 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *main)
/* support old particle dupliobject rotation settings */
ParticleSettings *part;
- for (part = main->particle.first; part; part = part->id.next) {
+ for (part = bmain->particle.first; part; part = part->id.next) {
if (ELEM(part->ren_as, PART_DRAW_OB, PART_DRAW_GR)) {
part->draw |= PART_DRAW_ROTATE_OB;
@@ -645,16 +645,16 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *main)
}
}
- if (main->versionfile < 260 || (main->versionfile == 260 && main->subversionfile < 1)) {
+ if (bmain->versionfile < 260 || (bmain->versionfile == 260 && bmain->subversionfile < 1)) {
Object *ob;
- for (ob = main->object.first; ob; ob = ob->id.next) {
+ for (ob = bmain->object.first; ob; ob = ob->id.next) {
ob->collision_boundtype = ob->boundtype;
}
{
Camera *cam;
- for (cam = main->camera.first; cam; cam = cam->id.next) {
+ for (cam = bmain->camera.first; cam; cam = cam->id.next) {
if (cam->sensor_x < 0.01f)
cam->sensor_x = DEFAULT_SENSOR_WIDTH;
@@ -664,8 +664,8 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *main)
}
}
- if (main->versionfile < 260 || (main->versionfile == 260 && main->subversionfile < 2)) {
- FOREACH_NODETREE(main, ntree, id) {
+ if (bmain->versionfile < 260 || (bmain->versionfile == 260 && bmain->subversionfile < 2)) {
+ FOREACH_NODETREE(bmain, ntree, id) {
if (ntree->type == NTREE_SHADER) {
bNode *node;
for (node = ntree->nodes.first; node; node = node->next) {
@@ -682,24 +682,24 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *main)
} FOREACH_NODETREE_END
}
- if (main->versionfile < 260 || (main->versionfile == 260 && main->subversionfile < 4)) {
+ if (bmain->versionfile < 260 || (bmain->versionfile == 260 && bmain->subversionfile < 4)) {
{
/* Convert node angles to radians! */
Scene *sce;
Material *mat;
bNodeTree *ntree;
- for (sce = main->scene.first; sce; sce = sce->id.next) {
+ for (sce = bmain->scene.first; sce; sce = sce->id.next) {
if (sce->nodetree)
do_versions_nodetree_convert_angle(sce->nodetree);
}
- for (mat = main->mat.first; mat; mat = mat->id.next) {
+ for (mat = bmain->mat.first; mat; mat = mat->id.next) {
if (mat->nodetree)
do_versions_nodetree_convert_angle(mat->nodetree);
}
- for (ntree = main->nodetree.first; ntree; ntree = ntree->id.next)
+ for (ntree = bmain->nodetree.first; ntree; ntree = ntree->id.next)
do_versions_nodetree_convert_angle(ntree);
}
@@ -708,7 +708,7 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *main)
bScreen *sc;
MovieClip *clip;
- for (sc = main->screen.first; sc; sc = sc->id.next) {
+ for (sc = bmain->screen.first; sc; sc = sc->id.next) {
ScrArea *sa;
for (sa = sc->areabase.first; sa; sa = sa->next) {
SpaceLink *sl;
@@ -732,7 +732,7 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *main)
}
}
- for (clip = main->movieclip.first; clip; clip = clip->id.next) {
+ for (clip = bmain->movieclip.first; clip; clip = clip->id.next) {
MovieTrackingTrack *track;
if (clip->aspx < 1.0f) {
@@ -764,16 +764,16 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *main)
}
}
- if (main->versionfile < 260 || (main->versionfile == 260 && main->subversionfile < 6)) {
+ if (bmain->versionfile < 260 || (bmain->versionfile == 260 && bmain->subversionfile < 6)) {
Scene *sce;
MovieClip *clip;
bScreen *sc;
- for (sce = main->scene.first; sce; sce = sce->id.next) {
+ for (sce = bmain->scene.first; sce; sce = sce->id.next) {
do_versions_image_settings_2_60(sce);
}
- for (clip = main->movieclip.first; clip; clip = clip->id.next) {
+ for (clip = bmain->movieclip.first; clip; clip = clip->id.next) {
MovieTrackingSettings *settings = &clip->tracking.settings;
if (settings->default_pattern_size == 0.0f) {
@@ -784,7 +784,7 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *main)
}
}
- for (sc = main->screen.first; sc; sc = sc->id.next) {
+ for (sc = bmain->screen.first; sc; sc = sc->id.next) {
ScrArea *sa;
for (sa = sc->areabase.first; sa; sa = sa->next) {
SpaceLink *sl;
@@ -799,7 +799,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) {
+ for (ob = bmain->object.first; ob; ob = ob->id.next) {
/* convert delta addition into delta scale */
int i;
for (i = 0; i < 3; i++) {
@@ -819,25 +819,25 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *main)
/* sigh, this dscale vs dsize version patching was not done right, fix for fix,
* this intentionally checks an exact subversion, also note this was never in a release,
* at some point this could be removed. */
- else if (main->versionfile == 260 && main->subversionfile == 6) {
+ else if (bmain->versionfile == 260 && bmain->subversionfile == 6) {
Object *ob;
- for (ob = main->object.first; ob; ob = ob->id.next) {
+ for (ob = bmain->object.first; ob; ob = ob->id.next) {
if (is_zero_v3(ob->dscale)) {
copy_vn_fl(ob->dscale, 3, 1.0f);
}
}
}
- if (main->versionfile < 260 || (main->versionfile == 260 && main->subversionfile < 8)) {
+ if (bmain->versionfile < 260 || (bmain->versionfile == 260 && bmain->subversionfile < 8)) {
Brush *brush;
- for (brush = main->brush.first; brush; brush = brush->id.next) {
+ for (brush = bmain->brush.first; brush; brush = brush->id.next) {
if (brush->sculpt_tool == SCULPT_TOOL_ROTATE)
brush->alpha = 1.0f;
}
}
- if (main->versionfile < 261 || (main->versionfile == 261 && main->subversionfile < 1)) {
+ if (bmain->versionfile < 261 || (bmain->versionfile == 261 && bmain->subversionfile < 1)) {
{
/* update use flags for node sockets (was only temporary before) */
Scene *sce;
@@ -847,32 +847,32 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *main)
World *world;
bNodeTree *ntree;
- for (sce = main->scene.first; sce; sce = sce->id.next) {
+ for (sce = bmain->scene.first; sce; sce = sce->id.next) {
if (sce->nodetree)
do_versions_nodetree_socket_use_flags_2_62(sce->nodetree);
}
- for (mat = main->mat.first; mat; mat = mat->id.next) {
+ for (mat = bmain->mat.first; mat; mat = mat->id.next) {
if (mat->nodetree)
do_versions_nodetree_socket_use_flags_2_62(mat->nodetree);
}
- for (tex = main->tex.first; tex; tex = tex->id.next) {
+ for (tex = bmain->tex.first; tex; tex = tex->id.next) {
if (tex->nodetree)
do_versions_nodetree_socket_use_flags_2_62(tex->nodetree);
}
- for (lamp = main->lamp.first; lamp; lamp = lamp->id.next) {
+ for (lamp = bmain->lamp.first; lamp; lamp = lamp->id.next) {
if (lamp->nodetree)
do_versions_nodetree_socket_use_flags_2_62(lamp->nodetree);
}
- for (world = main->world.first; world; world = world->id.next) {
+ for (world = bmain->world.first; world; world = world->id.next) {
if (world->nodetree)
do_versions_nodetree_socket_use_flags_2_62(world->nodetree);
}
- for (ntree = main->nodetree.first; ntree; ntree = ntree->id.next) {
+ for (ntree = bmain->nodetree.first; ntree; ntree = ntree->id.next) {
do_versions_nodetree_socket_use_flags_2_62(ntree);
}
}
@@ -880,7 +880,7 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *main)
MovieClip *clip;
Object *ob;
- for (clip = main->movieclip.first; clip; clip = clip->id.next) {
+ for (clip = bmain->movieclip.first; clip; clip = clip->id.next) {
MovieTracking *tracking = &clip->tracking;
MovieTrackingObject *tracking_object = tracking->objects.first;
@@ -900,7 +900,7 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *main)
}
}
- for (ob = main->object.first; ob; ob = ob->id.next) {
+ for (ob = bmain->object.first; ob; ob = ob->id.next) {
bConstraint *con;
for (con = ob->constraints.first; con; con = con->next) {
if (con->type == CONSTRAINT_TYPE_OBJECTSOLVER) {
@@ -914,12 +914,12 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *main)
}
}
- if (main->versionfile < 261 || (main->versionfile == 261 && main->subversionfile < 2)) {
+ if (bmain->versionfile < 261 || (bmain->versionfile == 261 && bmain->subversionfile < 2)) {
{
/* convert deprecated sculpt_paint_unified_* fields to
* UnifiedPaintSettings */
Scene *scene;
- for (scene = main->scene.first; scene; scene = scene->id.next) {
+ for (scene = bmain->scene.first; scene; scene = scene->id.next) {
ToolSettings *ts = scene->toolsettings;
UnifiedPaintSettings *ups = &ts->unified_paint_settings;
ups->size = ts->sculpt_paint_unified_size;
@@ -930,11 +930,11 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *main)
}
}
- if (main->versionfile < 261 || (main->versionfile == 261 && main->subversionfile < 3)) {
+ if (bmain->versionfile < 261 || (bmain->versionfile == 261 && bmain->subversionfile < 3)) {
{
/* convert extended ascii to utf-8 for text editor */
Text *text;
- for (text = main->text.first; text; text = text->id.next) {
+ for (text = bmain->text.first; text; text = text->id.next) {
if (!(text->flags & TXT_ISEXT)) {
TextLine *tl;
@@ -952,7 +952,7 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *main)
{
/* set new dynamic paint values */
Object *ob;
- for (ob = main->object.first; ob; ob = ob->id.next) {
+ for (ob = bmain->object.first; ob; ob = ob->id.next) {
ModifierData *md;
for (md = ob->modifiers.first; md; md = md->next) {
if (md->type == eModifierType_DynamicPaint) {
@@ -972,9 +972,9 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *main)
}
}
- if (main->versionfile < 262) {
+ if (bmain->versionfile < 262) {
Object *ob;
- for (ob = main->object.first; ob; ob = ob->id.next) {
+ for (ob = bmain->object.first; ob; ob = ob->id.next) {
ModifierData *md;
for (md = ob->modifiers.first; md; md = md->next) {
@@ -987,12 +987,12 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *main)
}
}
- if (main->versionfile < 263) {
+ if (bmain->versionfile < 263) {
/* set fluidsim rate. the version patch for this in 2.62 was wrong, so
* try to correct it, if rate is 0.0 that's likely not intentional */
Object *ob;
- for (ob = main->object.first; ob; ob = ob->id.next) {
+ for (ob = bmain->object.first; ob; ob = ob->id.next) {
ModifierData *md;
for (md = ob->modifiers.first; md; md = md->next) {
if (md->type == eModifierType_Fluidsim) {
@@ -1004,35 +1004,35 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *main)
}
}
- if (main->versionfile < 262 || (main->versionfile == 262 && main->subversionfile < 1)) {
+ if (bmain->versionfile < 262 || (bmain->versionfile == 262 && bmain->subversionfile < 1)) {
/* update use flags for node sockets (was only temporary before) */
Scene *sce;
bNodeTree *ntree;
- for (sce = main->scene.first; sce; sce = sce->id.next) {
+ for (sce = bmain->scene.first; sce; sce = sce->id.next) {
if (sce->nodetree)
do_versions_nodetree_multi_file_output_format_2_62_1(sce, sce->nodetree);
}
/* XXX can't associate with scene for group nodes, image format will stay uninitialized */
- for (ntree = main->nodetree.first; ntree; ntree = ntree->id.next)
+ for (ntree = bmain->nodetree.first; ntree; ntree = ntree->id.next)
do_versions_nodetree_multi_file_output_format_2_62_1(NULL, ntree);
}
/* only swap for pre-release bmesh merge which had MLoopCol red/blue swap */
- if (main->versionfile == 262 && main->subversionfile == 1) {
+ if (bmain->versionfile == 262 && bmain->subversionfile == 1) {
{
Mesh *me;
- for (me = main->mesh.first; me; me = me->id.next) {
+ for (me = bmain->mesh.first; me; me = me->id.next) {
do_versions_mesh_mloopcol_swap_2_62_1(me);
}
}
}
- if (main->versionfile < 262 || (main->versionfile == 262 && main->subversionfile < 2)) {
+ if (bmain->versionfile < 262 || (bmain->versionfile == 262 && bmain->subversionfile < 2)) {
/* Set new idname of keyingsets from their now "label-only" name. */
Scene *scene;
- for (scene = main->scene.first; scene; scene = scene->id.next) {
+ for (scene = bmain->scene.first; scene; scene = scene->id.next) {
KeyingSet *ks;
for (ks = scene->keyingsets.first; ks; ks = ks->next) {
if (!ks->idname[0])
@@ -1041,11 +1041,11 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *main)
}
}
- if (main->versionfile < 262 || (main->versionfile == 262 && main->subversionfile < 3)) {
+ if (bmain->versionfile < 262 || (bmain->versionfile == 262 && bmain->subversionfile < 3)) {
Object *ob;
ModifierData *md;
- for (ob = main->object.first; ob; ob = ob->id.next) {
+ for (ob = bmain->object.first; ob; ob = ob->id.next) {
for (md = ob->modifiers.first; md; md = md->next) {
if (md->type == eModifierType_Lattice) {
LatticeModifierData *lmd = (LatticeModifierData *)md;
@@ -1055,11 +1055,11 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *main)
}
}
- if (main->versionfile < 262 || (main->versionfile == 262 && main->subversionfile < 4)) {
+ if (bmain->versionfile < 262 || (bmain->versionfile == 262 && bmain->subversionfile < 4)) {
/* Read Viscosity presets from older files */
Object *ob;
- for (ob = main->object.first; ob; ob = ob->id.next) {
+ for (ob = bmain->object.first; ob; ob = ob->id.next) {
ModifierData *md;
for (md = ob->modifiers.first; md; md = md->next) {
if (md->type == eModifierType_Fluidsim) {
@@ -1079,27 +1079,27 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *main)
- if (main->versionfile < 263) {
+ if (bmain->versionfile < 263) {
/* Default for old files is to save particle rotations to pointcache */
ParticleSettings *part;
- for (part = main->particle.first; part; part = part->id.next) {
+ for (part = bmain->particle.first; part; part = part->id.next) {
part->flag |= PART_ROTATIONS;
}
}
- if (main->versionfile < 263 || (main->versionfile == 263 && main->subversionfile < 1)) {
+ if (bmain->versionfile < 263 || (bmain->versionfile == 263 && bmain->subversionfile < 1)) {
/* file output node paths are now stored in the file info struct instead socket name */
Scene *sce;
bNodeTree *ntree;
- for (sce = main->scene.first; sce; sce = sce->id.next)
+ for (sce = bmain->scene.first; sce; sce = sce->id.next)
if (sce->nodetree)
do_versions_nodetree_multi_file_output_path_2_63_1(sce->nodetree);
- for (ntree = main->nodetree.first; ntree; ntree = ntree->id.next)
+ for (ntree = bmain->nodetree.first; ntree; ntree = ntree->id.next)
do_versions_nodetree_multi_file_output_path_2_63_1(ntree);
}
- if (main->versionfile < 263 || (main->versionfile == 263 && main->subversionfile < 3)) {
+ if (bmain->versionfile < 263 || (bmain->versionfile == 263 && bmain->subversionfile < 3)) {
Scene *scene;
Brush *brush;
@@ -1107,7 +1107,7 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *main)
* unified paint settings also have weight. Update unified
* paint settings and brushes with a default weight value. */
- for (scene = main->scene.first; scene; scene = scene->id.next) {
+ for (scene = bmain->scene.first; scene; scene = scene->id.next) {
ToolSettings *ts = scene->toolsettings;
if (ts) {
ts->unified_paint_settings.weight = ts->vgroup_weight;
@@ -1115,15 +1115,15 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *main)
}
}
- for (brush = main->brush.first; brush; brush = brush->id.next) {
+ for (brush = bmain->brush.first; brush; brush = brush->id.next) {
brush->weight = 0.5;
}
}
- if (main->versionfile < 263 || (main->versionfile == 263 && main->subversionfile < 2)) {
+ if (bmain->versionfile < 263 || (bmain->versionfile == 263 && bmain->subversionfile < 2)) {
bScreen *sc;
- for (sc = main->screen.first; sc; sc = sc->id.next) {
+ for (sc = bmain->screen.first; sc; sc = sc->id.next) {
ScrArea *sa;
for (sa = sc->areabase.first; sa; sa = sa->next) {
SpaceLink *sl;
@@ -1155,18 +1155,18 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *main)
}
}
- if (main->versionfile < 263 || (main->versionfile == 263 && main->subversionfile < 4)) {
+ if (bmain->versionfile < 263 || (bmain->versionfile == 263 && bmain->subversionfile < 4)) {
Camera *cam;
Curve *cu;
- for (cam = main->camera.first; cam; cam = cam->id.next) {
+ for (cam = bmain->camera.first; cam; cam = cam->id.next) {
if (cam->flag & CAM_PANORAMA) {
cam->type = CAM_PANO;
cam->flag &= ~CAM_PANORAMA;
}
}
- for (cu = main->curve.first; cu; cu = cu->id.next) {
+ for (cu = bmain->curve.first; cu; cu = cu->id.next) {
if (cu->bevfac2 == 0.0f) {
cu->bevfac1 = 0.0f;
cu->bevfac2 = 1.0f;
@@ -1174,26 +1174,26 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *main)
}
}
- if (main->versionfile < 263 || (main->versionfile == 263 && main->subversionfile < 5)) {
+ if (bmain->versionfile < 263 || (bmain->versionfile == 263 && bmain->subversionfile < 5)) {
{
/* file output node paths are now stored in the file info struct instead socket name */
Scene *sce;
bNodeTree *ntree;
- for (sce = main->scene.first; sce; sce = sce->id.next) {
+ for (sce = bmain->scene.first; sce; sce = sce->id.next) {
if (sce->nodetree) {
do_versions_nodetree_file_output_layers_2_64_5(sce->nodetree);
do_versions_nodetree_image_layer_2_64_5(sce->nodetree);
}
}
- for (ntree = main->nodetree.first; ntree; ntree = ntree->id.next) {
+ for (ntree = bmain->nodetree.first; ntree; ntree = ntree->id.next) {
do_versions_nodetree_file_output_layers_2_64_5(ntree);
do_versions_nodetree_image_layer_2_64_5(ntree);
}
}
}
- if (main->versionfile < 263 || (main->versionfile == 263 && main->subversionfile < 6)) {
+ if (bmain->versionfile < 263 || (bmain->versionfile == 263 && bmain->subversionfile < 6)) {
/* update use flags for node sockets (was only temporary before) */
Scene *sce;
Material *mat;
@@ -1202,34 +1202,34 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *main)
World *world;
bNodeTree *ntree;
- for (sce = main->scene.first; sce; sce = sce->id.next)
+ for (sce = bmain->scene.first; sce; sce = sce->id.next)
if (sce->nodetree)
do_versions_nodetree_frame_2_64_6(sce->nodetree);
- for (mat = main->mat.first; mat; mat = mat->id.next)
+ for (mat = bmain->mat.first; mat; mat = mat->id.next)
if (mat->nodetree)
do_versions_nodetree_frame_2_64_6(mat->nodetree);
- for (tex = main->tex.first; tex; tex = tex->id.next)
+ for (tex = bmain->tex.first; tex; tex = tex->id.next)
if (tex->nodetree)
do_versions_nodetree_frame_2_64_6(tex->nodetree);
- for (lamp = main->lamp.first; lamp; lamp = lamp->id.next)
+ for (lamp = bmain->lamp.first; lamp; lamp = lamp->id.next)
if (lamp->nodetree)
do_versions_nodetree_frame_2_64_6(lamp->nodetree);
- for (world = main->world.first; world; world = world->id.next)
+ for (world = bmain->world.first; world; world = world->id.next)
if (world->nodetree)
do_versions_nodetree_frame_2_64_6(world->nodetree);
- for (ntree = main->nodetree.first; ntree; ntree = ntree->id.next)
+ for (ntree = bmain->nodetree.first; ntree; ntree = ntree->id.next)
do_versions_nodetree_frame_2_64_6(ntree);
}
- if (main->versionfile < 263 || (main->versionfile == 263 && main->subversionfile < 7)) {
+ if (bmain->versionfile < 263 || (bmain->versionfile == 263 && bmain->subversionfile < 7)) {
Object *ob;
- for (ob = main->object.first; ob; ob = ob->id.next) {
+ for (ob = bmain->object.first; ob; ob = ob->id.next) {
ModifierData *md;
for (md = ob->modifiers.first; md; md = md->next) {
if (md->type == eModifierType_Smoke) {
@@ -1244,8 +1244,8 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *main)
}
}
- if (main->versionfile < 263 || (main->versionfile == 263 && main->subversionfile < 9)) {
- FOREACH_NODETREE(main, ntree, id) {
+ if (bmain->versionfile < 263 || (bmain->versionfile == 263 && bmain->subversionfile < 9)) {
+ FOREACH_NODETREE(bmain, ntree, id) {
if (ntree->type == NTREE_SHADER) {
bNode *node;
for (node = ntree->nodes.first; node; node = node->next) {
@@ -1262,11 +1262,11 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *main)
} FOREACH_NODETREE_END
}
- if (main->versionfile < 263 || (main->versionfile == 263 && main->subversionfile < 10)) {
+ if (bmain->versionfile < 263 || (bmain->versionfile == 263 && bmain->subversionfile < 10)) {
{
Scene *scene;
// composite redesign
- for (scene = main->scene.first; scene; scene = scene->id.next) {
+ for (scene = bmain->scene.first; scene; scene = scene->id.next) {
if (scene->nodetree) {
if (scene->nodetree->chunksize == 0) {
scene->nodetree->chunksize = 256;
@@ -1274,7 +1274,7 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *main)
}
}
- FOREACH_NODETREE(main, ntree, id) {
+ FOREACH_NODETREE(bmain, ntree, id) {
if (ntree->type == NTREE_COMPOSIT) {
bNode *node;
for (node = ntree->nodes.first; node; node = node->next) {
@@ -1292,7 +1292,7 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *main)
{
bScreen *sc;
- for (sc = main->screen.first; sc; sc = sc->id.next) {
+ for (sc = bmain->screen.first; sc; sc = sc->id.next) {
ScrArea *sa;
for (sa = sc->areabase.first; sa; sa = sa->next) {
@@ -1314,16 +1314,16 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *main)
{
MovieClip *clip;
- for (clip = main->movieclip.first; clip; clip = clip->id.next) {
+ for (clip = bmain->movieclip.first; clip; clip = clip->id.next) {
clip->start_frame = 1;
}
}
}
- if (main->versionfile < 263 || (main->versionfile == 263 && main->subversionfile < 11)) {
+ if (bmain->versionfile < 263 || (bmain->versionfile == 263 && bmain->subversionfile < 11)) {
MovieClip *clip;
- for (clip = main->movieclip.first; clip; clip = clip->id.next) {
+ for (clip = bmain->movieclip.first; clip; clip = clip->id.next) {
MovieTrackingTrack *track;
track = clip->tracking.tracks.first;
@@ -1335,8 +1335,8 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *main)
}
}
- if (main->versionfile < 263 || (main->versionfile == 263 && main->subversionfile < 13)) {
- FOREACH_NODETREE(main, ntree, id) {
+ if (bmain->versionfile < 263 || (bmain->versionfile == 263 && bmain->subversionfile < 13)) {
+ FOREACH_NODETREE(bmain, ntree, id) {
if (ntree->type == NTREE_COMPOSIT) {
bNode *node;
for (node = ntree->nodes.first; node; node = node->next) {
@@ -1352,10 +1352,10 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *main)
} FOREACH_NODETREE_END
}
- if (main->versionfile < 263 || (main->versionfile == 263 && main->subversionfile < 14)) {
+ if (bmain->versionfile < 263 || (bmain->versionfile == 263 && bmain->subversionfile < 14)) {
ParticleSettings *part;
- FOREACH_NODETREE(main, ntree, id) {
+ FOREACH_NODETREE(bmain, ntree, id) {
if (ntree->type == NTREE_COMPOSIT) {
bNode *node;
for (node = ntree->nodes.first; node; node = node->next) {
@@ -1371,14 +1371,14 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *main)
} FOREACH_NODETREE_END
/* keep compatibility for dupliobject particle size */
- for (part = main->particle.first; part; part = part->id.next)
+ for (part = bmain->particle.first; part; part = part->id.next)
if (ELEM(part->ren_as, PART_DRAW_OB, PART_DRAW_GR))
if ((part->draw & PART_DRAW_ROTATE_OB) == 0)
part->draw |= PART_DRAW_NO_SCALE_OB;
}
- if (main->versionfile < 263 || (main->versionfile == 263 && main->subversionfile < 17)) {
- FOREACH_NODETREE(main, ntree, id) {
+ if (bmain->versionfile < 263 || (bmain->versionfile == 263 && bmain->subversionfile < 17)) {
+ FOREACH_NODETREE(bmain, ntree, id) {
if (ntree->type == NTREE_COMPOSIT) {
bNode *node;
for (node = ntree->nodes.first; node; node = node->next) {
@@ -1397,10 +1397,10 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *main)
} FOREACH_NODETREE_END
}
- if (main->versionfile < 263 || (main->versionfile == 263 && main->subversionfile < 18)) {
+ if (bmain->versionfile < 263 || (bmain->versionfile == 263 && bmain->subversionfile < 18)) {
Scene *scene;
- for (scene = main->scene.first; scene; scene = scene->id.next) {
+ for (scene = bmain->scene.first; scene; scene = scene->id.next) {
if (scene->ed) {
Sequence *seq;
@@ -1434,7 +1434,7 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *main)
}
/* color management pipeline changes compatibility code */
- if (main->versionfile < 263 || (main->versionfile == 263 && main->subversionfile < 19)) {
+ if (bmain->versionfile < 263 || (bmain->versionfile == 263 && bmain->subversionfile < 19)) {
Scene *scene;
Image *ima;
bool colormanagement_disabled = false;
@@ -1442,7 +1442,7 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *main)
/* make scenes which are not using color management have got None as display device,
* so they wouldn't perform linear-to-sRGB conversion on display
*/
- for (scene = main->scene.first; scene; scene = scene->id.next) {
+ for (scene = bmain->scene.first; scene; scene = scene->id.next) {
if ((scene->r.color_mgt_flag & R_COLOR_MANAGEMENT) == 0) {
ColorManagedDisplaySettings *display_settings = &scene->display_settings;
@@ -1455,7 +1455,7 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *main)
}
}
- for (ima = main->image.first; ima; ima = ima->id.next) {
+ for (ima = bmain->image.first; ima; ima = ima->id.next) {
if (ima->source == IMA_SRC_VIEWER) {
ima->flag |= IMA_VIEW_AS_RENDER;
}
@@ -1474,17 +1474,17 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *main)
}
}
- if (main->versionfile < 263 || (main->versionfile == 263 && main->subversionfile < 20)) {
+ if (bmain->versionfile < 263 || (bmain->versionfile == 263 && bmain->subversionfile < 20)) {
Key *key;
- for (key = main->key.first; key; key = key->id.next) {
+ for (key = bmain->key.first; key; key = key->id.next) {
blo_do_versions_key_uidgen(key);
}
}
- if (main->versionfile < 263 || (main->versionfile == 263 && main->subversionfile < 21)) {
+ if (bmain->versionfile < 263 || (bmain->versionfile == 263 && bmain->subversionfile < 21)) {
{
Mesh *me;
- for (me = main->mesh.first; me; me = me->id.next) {
+ for (me = bmain->mesh.first; me; me = me->id.next) {
CustomData_update_typemap(&me->vdata);
CustomData_free_layers(&me->vdata, CD_MSTICKY, me->totvert);
}
@@ -1495,10 +1495,10 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *main)
* didn't copy animation visualization, which lead to deadlocks on motion
* path calculation for proxied armatures, see [#32742]
*/
- if (main->versionfile < 264) {
+ if (bmain->versionfile < 264) {
Object *ob;
- for (ob = main->object.first; ob; ob = ob->id.next) {
+ for (ob = bmain->object.first; ob; ob = ob->id.next) {
if (ob->pose) {
if (ob->pose->avs.path_step == 0) {
animviz_settings_init(&ob->pose->avs);
@@ -1507,8 +1507,8 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *main)
}
}
- if (main->versionfile < 264 || (main->versionfile == 264 && main->subversionfile < 1)) {
- FOREACH_NODETREE(main, ntree, id) {
+ if (bmain->versionfile < 264 || (bmain->versionfile == 264 && bmain->subversionfile < 1)) {
+ FOREACH_NODETREE(bmain, ntree, id) {
if (ntree->type == NTREE_SHADER) {
bNode *node;
for (node = ntree->nodes.first; node; node = node->next)
@@ -1518,10 +1518,10 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *main)
} FOREACH_NODETREE_END
}
- if (main->versionfile < 264 || (main->versionfile == 264 && main->subversionfile < 2)) {
+ if (bmain->versionfile < 264 || (bmain->versionfile == 264 && bmain->subversionfile < 2)) {
MovieClip *clip;
- for (clip = main->movieclip.first; clip; clip = clip->id.next) {
+ for (clip = bmain->movieclip.first; clip; clip = clip->id.next) {
MovieTracking *tracking = &clip->tracking;
MovieTrackingObject *tracking_object;
@@ -1537,12 +1537,12 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *main)
}
}
- if (main->versionfile < 264 || (main->versionfile == 264 && main->subversionfile < 3)) {
+ if (bmain->versionfile < 264 || (bmain->versionfile == 264 && bmain->subversionfile < 3)) {
/* smoke branch */
{
Object *ob;
- for (ob = main->object.first; ob; ob = ob->id.next) {
+ for (ob = bmain->object.first; ob; ob = ob->id.next) {
ModifierData *md;
for (md = ob->modifiers.first; md; md = md->next) {
if (md->type == eModifierType_Smoke) {
@@ -1581,7 +1581,7 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *main)
{
bScreen *sc;
- for (sc = main->screen.first; sc; sc = sc->id.next) {
+ for (sc = bmain->screen.first; sc; sc = sc->id.next) {
ScrArea *sa;
for (sa = sc->areabase.first; sa; sa = sa->next) {
SpaceLink *sl;
@@ -1601,11 +1601,11 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *main)
}
}
- if (main->versionfile < 264 || (main->versionfile == 264 && main->subversionfile < 5)) {
+ if (bmain->versionfile < 264 || (bmain->versionfile == 264 && bmain->subversionfile < 5)) {
/* set a unwrapping margin and ABF by default */
Scene *scene;
- for (scene = main->scene.first; scene; scene = scene->id.next) {
+ for (scene = bmain->scene.first; scene; scene = scene->id.next) {
if (scene->toolsettings->uvcalc_margin == 0.0f) {
scene->toolsettings->uvcalc_margin = 0.001f;
scene->toolsettings->unwrapper = 0;
@@ -1613,11 +1613,11 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *main)
}
}
- if (main->versionfile < 264 || (main->versionfile == 264 && main->subversionfile < 6)) {
+ if (bmain->versionfile < 264 || (bmain->versionfile == 264 && bmain->subversionfile < 6)) {
/* Fix for bug #32982, internal_links list could get corrupted from r51630 onward.
* Simply remove bad internal_links lists to avoid NULL pointers.
*/
- FOREACH_NODETREE(main, ntree, id) {
+ FOREACH_NODETREE(bmain, ntree, id) {
bNode *node;
bNodeLink *link, *nextlink;
@@ -1632,12 +1632,12 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *main)
} FOREACH_NODETREE_END
}
- if (main->versionfile < 264 || (main->versionfile == 264 && main->subversionfile < 7)) {
+ if (bmain->versionfile < 264 || (bmain->versionfile == 264 && bmain->subversionfile < 7)) {
/* convert tiles size from resolution and number of tiles */
{
Scene *scene;
- for (scene = main->scene.first; scene; scene = scene->id.next) {
+ for (scene = bmain->scene.first; scene; scene = scene->id.next) {
if (scene->r.tilex == 0 || scene->r.tiley == 1) {
scene->r.tilex = scene->r.tiley = 64;
}
@@ -1647,7 +1647,7 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *main)
/* collision masks */
{
Object *ob;
- for (ob = main->object.first; ob; ob = ob->id.next) {
+ for (ob = bmain->object.first; ob; ob = ob->id.next) {
if (ob->col_group == 0) {
ob->col_group = 0x01;
ob->col_mask = 0xff;
@@ -1656,10 +1656,10 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *main)
}
}
- if (main->versionfile < 264 || (main->versionfile == 264 && main->subversionfile < 7)) {
+ if (bmain->versionfile < 264 || (bmain->versionfile == 264 && bmain->subversionfile < 7)) {
MovieClip *clip;
- for (clip = main->movieclip.first; clip; clip = clip->id.next) {
+ for (clip = bmain->movieclip.first; clip; clip = clip->id.next) {
MovieTrackingTrack *track;
MovieTrackingObject *object;
@@ -1675,9 +1675,9 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *main)
}
}
- if (main->versionfile < 265 || (main->versionfile == 265 && main->subversionfile < 3)) {
+ if (bmain->versionfile < 265 || (bmain->versionfile == 265 && bmain->subversionfile < 3)) {
bScreen *sc;
- for (sc = main->screen.first; sc; sc = sc->id.next) {
+ for (sc = bmain->screen.first; sc; sc = sc->id.next) {
ScrArea *sa;
for (sa = sc->areabase.first; sa; sa = sa->next) {
SpaceLink *sl;
@@ -1719,11 +1719,11 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *main)
}
}
- if (main->versionfile < 265 || (main->versionfile == 265 && main->subversionfile < 5)) {
+ if (bmain->versionfile < 265 || (bmain->versionfile == 265 && bmain->subversionfile < 5)) {
Scene *scene;
Tex *tex;
- for (scene = main->scene.first; scene; scene = scene->id.next) {
+ for (scene = bmain->scene.first; scene; scene = scene->id.next) {
Sequence *seq;
SEQ_BEGIN (scene->ed, seq)
@@ -1741,7 +1741,7 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *main)
scene->r.bake_samples = 256;
}
- for (Image *image = main->image.first; image; image = image->id.next) {
+ for (Image *image = bmain->image.first; image; image = image->id.next) {
if (image->flag & IMA_DO_PREMUL) {
image->alpha_mode = IMA_ALPHA_STRAIGHT;
}
@@ -1750,7 +1750,7 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *main)
}
}
- for (tex = main->tex.first; tex; tex = tex->id.next) {
+ for (tex = bmain->tex.first; tex; tex = tex->id.next) {
if (tex->type == TEX_IMAGE && (tex->imaflag & TEX_USEALPHA) == 0) {
Image *image = blo_do_versions_newlibadr(fd, tex->id.lib, tex->ima);
@@ -1759,7 +1759,7 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *main)
}
}
- FOREACH_NODETREE(main, ntree, id) {
+ FOREACH_NODETREE(bmain, ntree, id) {
if (ntree->type == NTREE_COMPOSIT) {
bNode *node;
for (node = ntree->nodes.first; node; node = node->next) {
@@ -1775,20 +1775,20 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *main)
}
} FOREACH_NODETREE_END
}
- else if (main->versionfile < 266 || (main->versionfile == 266 && main->subversionfile < 1)) {
+ else if (bmain->versionfile < 266 || (bmain->versionfile == 266 && bmain->subversionfile < 1)) {
/* texture use alpha was removed for 2.66 but added back again for 2.66a,
* for compatibility all textures assumed it to be enabled */
Tex *tex;
- for (tex = main->tex.first; tex; tex = tex->id.next)
+ for (tex = bmain->tex.first; tex; tex = tex->id.next)
if (tex->type == TEX_IMAGE)
tex->imaflag |= TEX_USEALPHA;
}
- if (main->versionfile < 265 || (main->versionfile == 265 && main->subversionfile < 7)) {
+ if (bmain->versionfile < 265 || (bmain->versionfile == 265 && bmain->subversionfile < 7)) {
Curve *cu;
- for (cu = main->curve.first; cu; cu = cu->id.next) {
+ for (cu = bmain->curve.first; cu; cu = cu->id.next) {
if (cu->flag & (CU_FRONT | CU_BACK)) {
if ( cu->ext1 != 0.0f || cu->ext2 != 0.0f) {
Nurb *nu;
@@ -1820,16 +1820,16 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *main)
}
}
- if (MAIN_VERSION_OLDER(main, 265, 9)) {
+ if (MAIN_VERSION_OLDER(bmain, 265, 9)) {
Mesh *me;
- for (me = main->mesh.first; me; me = me->id.next) {
+ for (me = bmain->mesh.first; me; me = me->id.next) {
BKE_mesh_do_versions_cd_flag_init(me);
}
}
- if (MAIN_VERSION_OLDER(main, 265, 10)) {
+ if (MAIN_VERSION_OLDER(bmain, 265, 10)) {
Brush *br;
- for (br = main->brush.first; br; br = br->id.next) {
+ for (br = bmain->brush.first; br; br = br->id.next) {
if (br->ob_mode & OB_MODE_TEXTURE_PAINT) {
br->mtex.brush_map_mode = MTEX_MAP_MODE_TILED;
}
@@ -1837,8 +1837,8 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *main)
}
// add storage for compositor translate nodes when not existing
- if (MAIN_VERSION_OLDER(main, 265, 11)) {
- FOREACH_NODETREE(main, ntree, id) {
+ if (MAIN_VERSION_OLDER(bmain, 265, 11)) {
+ FOREACH_NODETREE(bmain, ntree, id) {
if (ntree->type == NTREE_COMPOSIT) {
bNode *node;
for (node = ntree->nodes.first; node; node = node->next) {
@@ -1850,15 +1850,15 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *main)
} FOREACH_NODETREE_END
}
- if (MAIN_VERSION_OLDER(main, 266, 2)) {
- FOREACH_NODETREE(main, ntree, id) {
+ if (MAIN_VERSION_OLDER(bmain, 266, 2)) {
+ FOREACH_NODETREE(bmain, ntree, id) {
do_versions_nodetree_customnodes(ntree, ((ID *)ntree == id));
} FOREACH_NODETREE_END
}
- if (MAIN_VERSION_OLDER(main, 266, 2)) {
+ if (MAIN_VERSION_OLDER(bmain, 266, 2)) {
bScreen *sc;
- for (sc = main->screen.first; sc; sc = sc->id.next) {
+ for (sc = bmain->screen.first; sc; sc = sc->id.next) {
ScrArea *sa;
for (sa = sc->areabase.first; sa; sa = sa->next) {
SpaceLink *sl;
@@ -1892,7 +1892,7 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *main)
/* Set flag for delayed do_versions in lib_verify_nodetree. It needs valid typeinfo pointers ... */
{
- FOREACH_NODETREE(main, ntree, id) {
+ FOREACH_NODETREE(bmain, ntree, id) {
/* XXX This should be kept without version check for now!
* As long as USE_NODE_COMPAT_CUSTOMNODES is active, files will write links
* to tree interface sockets for forward compatibility. These links need to be removed again
@@ -1904,22 +1904,22 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *main)
/* Only add interface nodes once.
* In old Blender versions they will be removed automatically due to undefined type */
- if (MAIN_VERSION_OLDER(main, 266, 2))
+ if (MAIN_VERSION_OLDER(bmain, 266, 2))
ntree->flag |= NTREE_DO_VERSIONS_CUSTOMNODES_GROUP_CREATE_INTERFACE;
}
FOREACH_NODETREE_END
}
- if (MAIN_VERSION_OLDER(main, 266, 3)) {
+ if (MAIN_VERSION_OLDER(bmain, 266, 3)) {
{
/* Fix for a very old issue:
* Node names were nominally made unique in r24478 (2.50.8), but the do_versions check
- * to update existing node names only applied to main->nodetree (i.e. group nodes).
+ * to update existing node names only applied to bmain->nodetree (i.e. group nodes).
* Uniqueness is now required for proper preview mapping,
* so do this now to ensure old files don't break.
*/
bNode *node;
- FOREACH_NODETREE(main, ntree, id) {
+ FOREACH_NODETREE(bmain, ntree, id) {
if (id == &ntree->id)
continue; /* already fixed for node groups */
@@ -1930,9 +1930,9 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *main)
}
}
- if (!MAIN_VERSION_ATLEAST(main, 266, 4)) {
+ if (!MAIN_VERSION_ATLEAST(bmain, 266, 4)) {
Brush *brush;
- for (brush = main->brush.first; brush; brush = brush->id.next) {
+ for (brush = bmain->brush.first; brush; brush = brush->id.next) {
BKE_texture_mtex_default(&brush->mask_mtex);
if (brush->ob_mode & OB_MODE_TEXTURE_PAINT) {
@@ -1941,11 +1941,11 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *main)
}
}
- if (!MAIN_VERSION_ATLEAST(main, 266, 6)) {
+ if (!MAIN_VERSION_ATLEAST(bmain, 266, 6)) {
Brush *brush;
#define BRUSH_TEXTURE_OVERLAY (1 << 21)
- for (brush = main->brush.first; brush; brush = brush->id.next) {
+ for (brush = bmain->brush.first; brush; brush = brush->id.next) {
brush->overlay_flags = 0;
if (brush->flag & BRUSH_TEXTURE_OVERLAY)
brush->overlay_flags |= (BRUSH_OVERLAY_PRIMARY | BRUSH_OVERLAY_CURSOR);
@@ -1953,11 +1953,11 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *main)
#undef BRUSH_TEXTURE_OVERLAY
}
- if (main->versionfile < 267) {
+ if (bmain->versionfile < 267) {
//if (!DNA_struct_elem_find(fd->filesdna, "Brush", "int", "stencil_pos")) {
Brush *brush;
- for (brush = main->brush.first; brush; brush = brush->id.next) {
+ for (brush = bmain->brush.first; brush; brush = brush->id.next) {
if (brush->stencil_dimension[0] == 0) {
brush->stencil_dimension[0] = 256;
brush->stencil_dimension[1] = 256;
@@ -1982,12 +1982,12 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *main)
}
/* default values in Freestyle settings */
- if (main->versionfile < 267) {
+ if (bmain->versionfile < 267) {
Scene *sce;
SceneRenderLayer *srl;
FreestyleLineStyle *linestyle;
- for (sce = main->scene.first; sce; sce = sce->id.next) {
+ for (sce = bmain->scene.first; sce; sce = sce->id.next) {
if (sce->r.line_thickness_mode == 0) {
sce->r.line_thickness_mode = R_LINE_THICKNESS_ABSOLUTE;
sce->r.unit_line_thickness = 1.0f;
@@ -2023,7 +2023,7 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *main)
}
}
- for (linestyle = main->linestyle.first; linestyle; linestyle = linestyle->id.next) {
+ for (linestyle = bmain->linestyle.first; linestyle; linestyle = linestyle->id.next) {
#if 1
/* disable the Misc panel for now */
if (linestyle->panel == LS_PANEL_MISC) {
@@ -2041,13 +2041,13 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *main)
}
}
- if (main->versionfile < 267) {
+ if (bmain->versionfile < 267) {
/* Initialize the active_viewer_key for compositing */
bScreen *screen;
Scene *scene;
bNodeInstanceKey active_viewer_key = {0};
/* simply pick the first node space and use that for the active viewer key */
- for (screen = main->screen.first; screen; screen = screen->id.next) {
+ for (screen = bmain->screen.first; screen; screen = screen->id.next) {
ScrArea *sa;
for (sa = screen->areabase.first; sa; sa = sa->next) {
SpaceLink *sl;
@@ -2069,17 +2069,17 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *main)
break;
}
- for (scene = main->scene.first; scene; scene = scene->id.next) {
+ for (scene = bmain->scene.first; scene; scene = scene->id.next) {
/* NB: scene->nodetree is a local ID block, has been direct_link'ed */
if (scene->nodetree)
scene->nodetree->active_viewer_key = active_viewer_key;
}
}
- if (MAIN_VERSION_OLDER(main, 267, 1)) {
+ if (MAIN_VERSION_OLDER(bmain, 267, 1)) {
Object *ob;
- for (ob = main->object.first; ob; ob = ob->id.next) {
+ for (ob = bmain->object.first; ob; ob = ob->id.next) {
ModifierData *md;
for (md = ob->modifiers.first; md; md = md->next) {
if (md->type == eModifierType_Smoke) {
@@ -2097,17 +2097,17 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *main)
}
}
- if (!MAIN_VERSION_ATLEAST(main, 268, 1)) {
+ if (!MAIN_VERSION_ATLEAST(bmain, 268, 1)) {
Brush *brush;
- for (brush = main->brush.first; brush; brush = brush->id.next) {
+ for (brush = bmain->brush.first; brush; brush = brush->id.next) {
brush->spacing = MAX2(1, brush->spacing);
}
}
- if (!MAIN_VERSION_ATLEAST(main, 268, 2)) {
+ if (!MAIN_VERSION_ATLEAST(bmain, 268, 2)) {
Brush *brush;
#define BRUSH_FIXED (1 << 6)
- for (brush = main->brush.first; brush; brush = brush->id.next) {
+ for (brush = bmain->brush.first; brush; brush = brush->id.next) {
brush->flag &= ~BRUSH_FIXED;
if (brush->cursor_overlay_alpha < 2)
@@ -2121,11 +2121,11 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *main)
}
- if (!MAIN_VERSION_ATLEAST(main, 268, 4)) {
+ if (!MAIN_VERSION_ATLEAST(bmain, 268, 4)) {
bScreen *sc;
Object *ob;
- for (ob = main->object.first; ob; ob = ob->id.next) {
+ for (ob = bmain->object.first; ob; ob = ob->id.next) {
bConstraint *con;
for (con = ob->constraints.first; con; con = con->next) {
if (con->type == CONSTRAINT_TYPE_SHRINKWRAP) {
@@ -2138,7 +2138,7 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *main)
}
}
- for (ob = main->object.first; ob; ob = ob->id.next) {
+ for (ob = bmain->object.first; ob; ob = ob->id.next) {
ModifierData *md;
for (md = ob->modifiers.first; md; md = md->next) {
if (md->type == eModifierType_Smoke) {
@@ -2157,7 +2157,7 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *main)
*
* We moved this check to the do versions to be sure the value makes any sense.
*/
- for (sc = main->screen.first; sc; sc = sc->id.next) {
+ for (sc = bmain->screen.first; sc; sc = sc->id.next) {
ScrArea *sa;
for (sa = sc->areabase.first; sa; sa = sa->next) {
SpaceLink *sl;
@@ -2173,12 +2173,12 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *main)
}
}
- if (!MAIN_VERSION_ATLEAST(main, 268, 5)) {
+ if (!MAIN_VERSION_ATLEAST(bmain, 268, 5)) {
bScreen *sc;
ScrArea *sa;
/* add missing (+) expander in node editor */
- for (sc = main->screen.first; sc; sc = sc->id.next) {
+ for (sc = bmain->screen.first; sc; sc = sc->id.next) {
for (sa = sc->areabase.first; sa; sa = sa->next) {
ARegion *ar, *arnew;
@@ -2207,9 +2207,9 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *main)
}
}
- if (!MAIN_VERSION_ATLEAST(main, 269, 1)) {
+ if (!MAIN_VERSION_ATLEAST(bmain, 269, 1)) {
/* Removal of Cycles SSS Compatible falloff */
- FOREACH_NODETREE(main, ntree, id) {
+ FOREACH_NODETREE(bmain, ntree, id) {
if (ntree->type == NTREE_SHADER) {
bNode *node;
for (node = ntree->nodes.first; node; node = node->next) {
@@ -2223,9 +2223,9 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *main)
} FOREACH_NODETREE_END
}
- if (!MAIN_VERSION_ATLEAST(main, 269, 2)) {
+ if (!MAIN_VERSION_ATLEAST(bmain, 269, 2)) {
/* Initialize CDL settings for Color Balance nodes */
- FOREACH_NODETREE(main, ntree, id) {
+ FOREACH_NODETREE(bmain, ntree, id) {
if (ntree->type == NTREE_COMPOSIT) {
bNode *node;
for (node = ntree->nodes.first; node; node = node->next) {
@@ -2250,14 +2250,14 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *main)
} FOREACH_NODETREE_END
}
- if (!MAIN_VERSION_ATLEAST(main, 269, 3)) {
+ if (!MAIN_VERSION_ATLEAST(bmain, 269, 3)) {
bScreen *sc;
ScrArea *sa;
SpaceLink *sl;
Scene *scene;
/* Update files using invalid (outdated) outlinevis Outliner values. */
- for (sc = main->screen.first; sc; sc = sc->id.next) {
+ for (sc = bmain->screen.first; sc; sc = sc->id.next) {
for (sa = sc->areabase.first; sa; sa = sa->next) {
for (sl = sa->spacedata.first; sl; sl = sl->next) {
if (sl->spacetype == SPACE_OUTLINER) {
@@ -2278,7 +2278,7 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *main)
if (!DNA_struct_elem_find(fd->filesdna, "MovieTrackingTrack", "float", "weight")) {
MovieClip *clip;
- for (clip = main->movieclip.first; clip; clip = clip->id.next) {
+ for (clip = bmain->movieclip.first; clip; clip = clip->id.next) {
MovieTracking *tracking = &clip->tracking;
MovieTrackingObject *tracking_object;
for (tracking_object = tracking->objects.first;
@@ -2299,7 +2299,7 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *main)
if (!DNA_struct_elem_find(fd->filesdna, "TriangulateModifierData", "int", "quad_method")) {
Object *ob;
- for (ob = main->object.first; ob; ob = ob->id.next) {
+ for (ob = bmain->object.first; ob; ob = ob->id.next) {
ModifierData *md;
for (md = ob->modifiers.first; md; md = md->next) {
if (md->type == eModifierType_Triangulate) {
@@ -2317,7 +2317,7 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *main)
}
}
- for (scene = main->scene.first; scene; scene = scene->id.next) {
+ for (scene = bmain->scene.first; scene; scene = scene->id.next) {
/* this can now be turned off */
ToolSettings *ts = scene->toolsettings;
if (ts->sculpt)
@@ -2337,17 +2337,17 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *main)
}
}
- if (!MAIN_VERSION_ATLEAST(main, 269, 4)) {
+ if (!MAIN_VERSION_ATLEAST(bmain, 269, 4)) {
/* Internal degrees to radians conversions... */
{
Scene *scene;
Object *ob;
Lamp *lamp;
- for (lamp = main->lamp.first; lamp; lamp = lamp->id.next)
+ for (lamp = bmain->lamp.first; lamp; lamp = lamp->id.next)
lamp->spotsize = DEG2RADF(lamp->spotsize);
- for (ob = main->object.first; ob; ob = ob->id.next) {
+ for (ob = bmain->object.first; ob; ob = ob->id.next) {
ModifierData *md;
for (md = ob->modifiers.first; md; md = md->next) {
@@ -2362,7 +2362,7 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *main)
}
}
- for (scene = main->scene.first; scene; scene = scene->id.next) {
+ for (scene = bmain->scene.first; scene; scene = scene->id.next) {
Sequence *seq;
SEQ_BEGIN (scene->ed, seq)
{
@@ -2374,7 +2374,7 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *main)
SEQ_END
}
- FOREACH_NODETREE(main, ntree, id) {
+ FOREACH_NODETREE(bmain, ntree, id) {
if (ntree->type == NTREE_COMPOSIT) {
bNode *node;
for (node = ntree->nodes.first; node; node = node->next) {
@@ -2397,7 +2397,7 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *main)
if (!DNA_struct_elem_find(fd->filesdna, "MovieTrackingPlaneTrack", "float", "image_opacity")) {
MovieClip *clip;
- for (clip = main->movieclip.first; clip; clip = clip->id.next) {
+ for (clip = bmain->movieclip.first; clip; clip = clip->id.next) {
MovieTrackingPlaneTrack *plane_track;
for (plane_track = clip->tracking.plane_tracks.first;
plane_track;
@@ -2409,9 +2409,9 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *main)
}
}
- if (!MAIN_VERSION_ATLEAST(main, 269, 7)) {
+ if (!MAIN_VERSION_ATLEAST(bmain, 269, 7)) {
Scene *scene;
- for (scene = main->scene.first; scene; scene = scene->id.next) {
+ for (scene = bmain->scene.first; scene; scene = scene->id.next) {
Sculpt *sd = scene->toolsettings->sculpt;
if (sd) {
@@ -2429,20 +2429,20 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *main)
}
}
- if (!MAIN_VERSION_ATLEAST(main, 269, 8)) {
+ if (!MAIN_VERSION_ATLEAST(bmain, 269, 8)) {
Curve *cu;
- for (cu = main->curve.first; cu; cu = cu->id.next) {
+ for (cu = bmain->curve.first; cu; cu = cu->id.next) {
if (cu->str) {
cu->len_wchar = BLI_strlen_utf8(cu->str);
}
}
}
- if (!MAIN_VERSION_ATLEAST(main, 269, 9)) {
+ if (!MAIN_VERSION_ATLEAST(bmain, 269, 9)) {
Object *ob;
- for (ob = main->object.first; ob; ob = ob->id.next) {
+ for (ob = bmain->object.first; ob; ob = ob->id.next) {
ModifierData *md;
for (md = ob->modifiers.first; md; md = md->next) {
if (md->type == eModifierType_Build) {
@@ -2455,10 +2455,10 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *main)
}
}
- if (!MAIN_VERSION_ATLEAST(main, 269, 11)) {
+ if (!MAIN_VERSION_ATLEAST(bmain, 269, 11)) {
bScreen *sc;
- for (sc = main->screen.first; sc; sc = sc->id.next) {
+ for (sc = bmain->screen.first; sc; sc = sc->id.next) {
ScrArea *sa;
for (sa = sc->areabase.first; sa; sa = sa->next) {
SpaceLink *space_link;
diff --git a/source/blender/blenloader/intern/versioning_270.c b/source/blender/blenloader/intern/versioning_270.c
index ee589e511c6..ba714405cc0 100644
--- a/source/blender/blenloader/intern/versioning_270.c
+++ b/source/blender/blenloader/intern/versioning_270.c
@@ -346,14 +346,14 @@ static void do_version_bbone_easing_fcurve_fix(ID *UNUSED(id), FCurve *fcu, void
}
-void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main)
+void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *bmain)
{
- if (!MAIN_VERSION_ATLEAST(main, 270, 0)) {
+ if (!MAIN_VERSION_ATLEAST(bmain, 270, 0)) {
if (!DNA_struct_elem_find(fd->filesdna, "BevelModifierData", "float", "profile")) {
Object *ob;
- for (ob = main->object.first; ob; ob = ob->id.next) {
+ for (ob = bmain->object.first; ob; ob = ob->id.next) {
ModifierData *md;
for (md = ob->modifiers.first; md; md = md->next) {
if (md->type == eModifierType_Bevel) {
@@ -366,7 +366,7 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main)
}
/* nodes don't use fixed node->id any more, clean up */
- FOREACH_NODETREE(main, ntree, id) {
+ FOREACH_NODETREE(bmain, ntree, id) {
if (ntree->type == NTREE_COMPOSIT) {
bNode *node;
for (node = ntree->nodes.first; node; node = node->next) {
@@ -380,7 +380,7 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main)
{
bScreen *screen;
- for (screen = main->screen.first; screen; screen = screen->id.next) {
+ for (screen = bmain->screen.first; screen; screen = screen->id.next) {
ScrArea *area;
for (area = screen->areabase.first; area; area = area->next) {
SpaceLink *space_link;
@@ -398,17 +398,17 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main)
if (!DNA_struct_elem_find(fd->filesdna, "MovieTrackingSettings", "float", "default_weight")) {
MovieClip *clip;
- for (clip = main->movieclip.first; clip; clip = clip->id.next) {
+ for (clip = bmain->movieclip.first; clip; clip = clip->id.next) {
clip->tracking.settings.default_weight = 1.0f;
}
}
}
- if (!MAIN_VERSION_ATLEAST(main, 270, 1)) {
+ if (!MAIN_VERSION_ATLEAST(bmain, 270, 1)) {
Object *ob;
/* Update Transform constraint (another deg -> rad stuff). */
- for (ob = main->object.first; ob; ob = ob->id.next) {
+ for (ob = bmain->object.first; ob; ob = ob->id.next) {
do_version_constraints_radians_degrees_270_1(&ob->constraints);
if (ob->pose) {
@@ -421,32 +421,32 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main)
}
}
- if (!MAIN_VERSION_ATLEAST(main, 270, 2)) {
+ if (!MAIN_VERSION_ATLEAST(bmain, 270, 2)) {
Mesh *me;
/* Mesh smoothresh deg->rad. */
- for (me = main->mesh.first; me; me = me->id.next) {
+ for (me = bmain->mesh.first; me; me = me->id.next) {
me->smoothresh = DEG2RADF(me->smoothresh);
}
}
- if (!MAIN_VERSION_ATLEAST(main, 270, 3)) {
+ if (!MAIN_VERSION_ATLEAST(bmain, 270, 3)) {
FreestyleLineStyle *linestyle;
- for (linestyle = main->linestyle.first; linestyle; linestyle = linestyle->id.next) {
+ for (linestyle = bmain->linestyle.first; linestyle; linestyle = linestyle->id.next) {
linestyle->flag |= LS_NO_SORTING;
linestyle->sort_key = LS_SORT_KEY_DISTANCE_FROM_CAMERA;
linestyle->integration_type = LS_INTEGRATION_MEAN;
}
}
- if (!MAIN_VERSION_ATLEAST(main, 270, 4)) {
+ if (!MAIN_VERSION_ATLEAST(bmain, 270, 4)) {
/* ui_previews were not handled correctly when copying areas, leading to corrupted files (see T39847).
* This will always reset situation to a valid state.
*/
bScreen *sc;
- for (sc = main->screen.first; sc; sc = sc->id.next) {
+ for (sc = bmain->screen.first; sc; sc = sc->id.next) {
ScrArea *sa;
for (sa = sc->areabase.first; sa; sa = sa->next) {
SpaceLink *sl;
@@ -463,11 +463,11 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main)
}
}
- if (!MAIN_VERSION_ATLEAST(main, 270, 5)) {
+ if (!MAIN_VERSION_ATLEAST(bmain, 270, 5)) {
Object *ob;
/* Update Transform constraint (again :|). */
- for (ob = main->object.first; ob; ob = ob->id.next) {
+ for (ob = bmain->object.first; ob; ob = ob->id.next) {
do_version_constraints_radians_degrees_270_5(&ob->constraints);
if (ob->pose) {
@@ -480,11 +480,11 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main)
}
}
- if (!MAIN_VERSION_ATLEAST(main, 271, 0)) {
+ if (!MAIN_VERSION_ATLEAST(bmain, 271, 0)) {
if (!DNA_struct_elem_find(fd->filesdna, "RenderData", "BakeData", "bake")) {
Scene *sce;
- for (sce = main->scene.first; sce; sce = sce->id.next) {
+ for (sce = bmain->scene.first; sce; sce = sce->id.next) {
sce->r.bake.flag = R_BAKE_CLEAR;
sce->r.bake.width = 512;
sce->r.bake.height = 512;
@@ -506,7 +506,7 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main)
if (!DNA_struct_elem_find(fd->filesdna, "FreestyleLineStyle", "float", "texstep")) {
FreestyleLineStyle *linestyle;
- for (linestyle = main->linestyle.first; linestyle; linestyle = linestyle->id.next) {
+ for (linestyle = bmain->linestyle.first; linestyle; linestyle = linestyle->id.next) {
linestyle->flag |= LS_TEXTURE;
linestyle->texstep = 1.0;
}
@@ -514,18 +514,18 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main)
{
Scene *scene;
- for (scene = main->scene.first; scene; scene = scene->id.next) {
+ for (scene = bmain->scene.first; scene; scene = scene->id.next) {
int num_layers = BLI_listbase_count(&scene->r.layers);
scene->r.actlay = min_ff(scene->r.actlay, num_layers - 1);
}
}
}
- if (!MAIN_VERSION_ATLEAST(main, 271, 1)) {
+ if (!MAIN_VERSION_ATLEAST(bmain, 271, 1)) {
if (!DNA_struct_elem_find(fd->filesdna, "Material", "float", "line_col[4]")) {
Material *mat;
- for (mat = main->mat.first; mat; mat = mat->id.next) {
+ for (mat = bmain->mat.first; mat; mat = mat->id.next) {
mat->line_col[0] = mat->line_col[1] = mat->line_col[2] = 0.0f;
mat->line_col[3] = mat->alpha;
}
@@ -533,22 +533,22 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main)
if (!DNA_struct_elem_find(fd->filesdna, "RenderData", "int", "preview_start_resolution")) {
Scene *scene;
- for (scene = main->scene.first; scene; scene = scene->id.next) {
+ for (scene = bmain->scene.first; scene; scene = scene->id.next) {
scene->r.preview_start_resolution = 64;
}
}
}
- if (!MAIN_VERSION_ATLEAST(main, 271, 3)) {
+ if (!MAIN_VERSION_ATLEAST(bmain, 271, 3)) {
Brush *br;
- for (br = main->brush.first; br; br = br->id.next) {
+ for (br = bmain->brush.first; br; br = br->id.next) {
br->fill_threshold = 0.2f;
}
if (!DNA_struct_elem_find(fd->filesdna, "BevelModifierData", "int", "mat")) {
Object *ob;
- for (ob = main->object.first; ob; ob = ob->id.next) {
+ for (ob = bmain->object.first; ob; ob = ob->id.next) {
ModifierData *md;
for (md = ob->modifiers.first; md; md = md->next) {
@@ -561,9 +561,9 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main)
}
}
- if (!MAIN_VERSION_ATLEAST(main, 271, 6)) {
+ if (!MAIN_VERSION_ATLEAST(bmain, 271, 6)) {
Object *ob;
- for (ob = main->object.first; ob; ob = ob->id.next) {
+ for (ob = bmain->object.first; ob; ob = ob->id.next) {
ModifierData *md;
for (md = ob->modifiers.first; md; md = md->next) {
@@ -577,27 +577,27 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main)
}
}
- if (!MAIN_VERSION_ATLEAST(main, 272, 0)) {
+ if (!MAIN_VERSION_ATLEAST(bmain, 272, 0)) {
if (!DNA_struct_elem_find(fd->filesdna, "RenderData", "int", "preview_start_resolution")) {
Scene *scene;
- for (scene = main->scene.first; scene; scene = scene->id.next) {
+ for (scene = bmain->scene.first; scene; scene = scene->id.next) {
scene->r.preview_start_resolution = 64;
}
}
}
- if (!MAIN_VERSION_ATLEAST(main, 272, 1)) {
+ if (!MAIN_VERSION_ATLEAST(bmain, 272, 1)) {
Brush *br;
- for (br = main->brush.first; br; br = br->id.next) {
+ for (br = bmain->brush.first; br; br = br->id.next) {
if ((br->ob_mode & OB_MODE_SCULPT) && ELEM(br->sculpt_tool, SCULPT_TOOL_GRAB, SCULPT_TOOL_SNAKE_HOOK))
br->alpha = 1.0f;
}
}
- if (!MAIN_VERSION_ATLEAST(main, 272, 2)) {
+ if (!MAIN_VERSION_ATLEAST(bmain, 272, 2)) {
if (!DNA_struct_elem_find(fd->filesdna, "Image", "float", "gen_color")) {
Image *image;
- for (image = main->image.first; image != NULL; image = image->id.next) {
+ for (image = bmain->image.first; image != NULL; image = image->id.next) {
image->gen_color[3] = 1.0f;
}
}
@@ -606,7 +606,7 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main)
Object *ob;
/* Update Transform constraint (again :|). */
- for (ob = main->object.first; ob; ob = ob->id.next) {
+ for (ob = bmain->object.first; ob; ob = ob->id.next) {
do_version_constraints_stretch_to_limits(&ob->constraints);
if (ob->pose) {
@@ -620,13 +620,13 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main)
}
}
- if (!MAIN_VERSION_ATLEAST(main, 273, 1)) {
+ if (!MAIN_VERSION_ATLEAST(bmain, 273, 1)) {
#define BRUSH_RAKE (1 << 7)
#define BRUSH_RANDOM_ROTATION (1 << 25)
Brush *br;
- for (br = main->brush.first; br; br = br->id.next) {
+ for (br = bmain->brush.first; br; br = br->id.next) {
if (br->flag & BRUSH_RAKE) {
br->mtex.brush_angle_mode |= MTEX_ANGLE_RAKE;
br->mask_mtex.brush_angle_mode |= MTEX_ANGLE_RAKE;
@@ -644,11 +644,11 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main)
#undef BRUSH_RANDOM_ROTATION
/* Customizable Safe Areas */
- if (!MAIN_VERSION_ATLEAST(main, 273, 2)) {
+ if (!MAIN_VERSION_ATLEAST(bmain, 273, 2)) {
if (!DNA_struct_elem_find(fd->filesdna, "Scene", "DisplaySafeAreas", "safe_areas")) {
Scene *scene;
- for (scene = main->scene.first; scene; scene = scene->id.next) {
+ for (scene = bmain->scene.first; scene; scene = scene->id.next) {
copy_v2_fl2(scene->safe_areas.title, 3.5f / 100.0f, 3.5f / 100.0f);
copy_v2_fl2(scene->safe_areas.action, 10.0f / 100.0f, 5.0f / 100.0f);
copy_v2_fl2(scene->safe_areas.title_center, 17.5f / 100.0f, 5.0f / 100.0f);
@@ -657,9 +657,9 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main)
}
}
- if (!MAIN_VERSION_ATLEAST(main, 273, 3)) {
+ if (!MAIN_VERSION_ATLEAST(bmain, 273, 3)) {
ParticleSettings *part;
- for (part = main->particle.first; part; part = part->id.next) {
+ for (part = bmain->particle.first; part; part = part->id.next) {
if (part->clumpcurve)
part->child_flag |= PART_CHILD_USE_CLUMP_CURVE;
if (part->roughcurve)
@@ -667,11 +667,11 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main)
}
}
- if (!MAIN_VERSION_ATLEAST(main, 273, 6)) {
+ if (!MAIN_VERSION_ATLEAST(bmain, 273, 6)) {
if (!DNA_struct_elem_find(fd->filesdna, "ClothSimSettings", "float", "bending_damping")) {
Object *ob;
ModifierData *md;
- for (ob = main->object.first; ob; ob = ob->id.next) {
+ for (ob = bmain->object.first; ob; ob = ob->id.next) {
for (md = ob->modifiers.first; md; md = md->next) {
if (md->type == eModifierType_Cloth) {
ClothModifierData *clmd = (ClothModifierData *)md;
@@ -689,21 +689,21 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main)
if (!DNA_struct_elem_find(fd->filesdna, "ParticleSettings", "float", "clump_noise_size")) {
ParticleSettings *part;
- for (part = main->particle.first; part; part = part->id.next) {
+ for (part = bmain->particle.first; part; part = part->id.next) {
part->clump_noise_size = 1.0f;
}
}
if (!DNA_struct_elem_find(fd->filesdna, "ParticleSettings", "int", "kink_extra_steps")) {
ParticleSettings *part;
- for (part = main->particle.first; part; part = part->id.next) {
+ for (part = bmain->particle.first; part; part = part->id.next) {
part->kink_extra_steps = 4;
}
}
if (!DNA_struct_elem_find(fd->filesdna, "MTex", "float", "kinkampfac")) {
ParticleSettings *part;
- for (part = main->particle.first; part; part = part->id.next) {
+ for (part = bmain->particle.first; part; part = part->id.next) {
int a;
for (a = 0; a < MAX_MTEX; a++) {
MTex *mtex = part->mtex[a];
@@ -717,7 +717,7 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main)
if (!DNA_struct_elem_find(fd->filesdna, "HookModifierData", "char", "flag")) {
Object *ob;
- for (ob = main->object.first; ob; ob = ob->id.next) {
+ for (ob = bmain->object.first; ob; ob = ob->id.next) {
ModifierData *md;
for (md = ob->modifiers.first; md; md = md->next) {
if (md->type == eModifierType_Hook) {
@@ -729,7 +729,7 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main)
}
if (!DNA_struct_elem_find(fd->filesdna, "NodePlaneTrackDeformData", "char", "flag")) {
- FOREACH_NODETREE(main, ntree, id) {
+ FOREACH_NODETREE(bmain, ntree, id) {
if (ntree->type == NTREE_COMPOSIT) {
bNode *node;
for (node = ntree->nodes.first; node; node = node->next) {
@@ -747,7 +747,7 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main)
if (!DNA_struct_elem_find(fd->filesdna, "Camera", "GPUDOFSettings", "gpu_dof")) {
Camera *ca;
- for (ca = main->camera.first; ca; ca = ca->id.next) {
+ for (ca = bmain->camera.first; ca; ca = ca->id.next) {
ca->gpu_dof.fstop = 128.0f;
ca->gpu_dof.focal_length = 1.0f;
ca->gpu_dof.focus_distance = 1.0f;
@@ -756,9 +756,9 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main)
}
}
- if (!MAIN_VERSION_ATLEAST(main, 273, 8)) {
+ if (!MAIN_VERSION_ATLEAST(bmain, 273, 8)) {
Object *ob;
- for (ob = main->object.first; ob != NULL; ob = ob->id.next) {
+ for (ob = bmain->object.first; ob != NULL; ob = ob->id.next) {
ModifierData *md;
for (md = ob->modifiers.last; md != NULL; md = md->prev) {
if (modifier_unique_name(&ob->modifiers, md)) {
@@ -770,14 +770,14 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main)
}
}
- if (!MAIN_VERSION_ATLEAST(main, 273, 9)) {
+ if (!MAIN_VERSION_ATLEAST(bmain, 273, 9)) {
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 (scr = bmain->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) {
@@ -795,12 +795,12 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main)
}
}
- if (!MAIN_VERSION_ATLEAST(main, 274, 1)) {
+ if (!MAIN_VERSION_ATLEAST(bmain, 274, 1)) {
/* 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 (ob = bmain->object.first; ob; ob = ob->id.next) {
for (psys = ob->particlesystem.first; psys; psys = psys->next) {
if ((psys->pointcache->flag & PTCACHE_BAKED) == 0) {
psys->recalc |= PSYS_RECALC_RESET;
@@ -812,7 +812,7 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main)
/* 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) {
+ for (ob = bmain->object.first; ob; ob = ob->id.next) {
LodLevel *level;
for (level = ob->lodlevels.first; level; level = level->next) {
level->obhysteresis = 10;
@@ -821,7 +821,7 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main)
}
}
- if (!MAIN_VERSION_ATLEAST(main, 274, 4)) {
+ if (!MAIN_VERSION_ATLEAST(bmain, 274, 4)) {
SceneRenderView *srv;
wmWindowManager *wm;
bScreen *screen;
@@ -830,7 +830,7 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main)
Camera *cam;
Image *ima;
- for (scene = main->scene.first; scene; scene = scene->id.next) {
+ for (scene = bmain->scene.first; scene; scene = scene->id.next) {
Sequence *seq;
BKE_scene_add_render_view(scene, STEREO_LEFT_NAME);
@@ -860,7 +860,7 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main)
SEQ_END
}
- for (screen = main->screen.first; screen; screen = screen->id.next) {
+ for (screen = bmain->screen.first; screen; screen = screen->id.next) {
ScrArea *sa;
for (sa = screen->areabase.first; sa; sa = sa->next) {
SpaceLink *sl;
@@ -887,12 +887,12 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main)
}
}
- for (cam = main->camera.first; cam; cam = cam->id.next) {
+ for (cam = bmain->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) {
+ for (ima = bmain->image.first; ima; ima = ima->id.next) {
ima->stereo3d_format = MEM_callocN(sizeof(Stereo3dFormat), "Image Stereo 3d Format");
if (ima->packedfile) {
@@ -905,18 +905,18 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main)
}
}
- for (wm = main->wm.first; wm; wm = wm->id.next) {
+ for (wm = bmain->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 (!MAIN_VERSION_ATLEAST(main, 274, 6)) {
+ if (!MAIN_VERSION_ATLEAST(bmain, 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) {
+ for (screen = bmain->screen.first; screen; screen = screen->id.next) {
ScrArea *sa;
for (sa = screen->areabase.first; sa; sa = sa->next) {
@@ -937,7 +937,7 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main)
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) {
+ for (scene = bmain->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;
}
@@ -946,7 +946,7 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main)
if (!DNA_struct_elem_find(fd->filesdna, "DecimateModifierData", "float", "defgrp_factor")) {
Object *ob;
- for (ob = main->object.first; ob; ob = ob->id.next) {
+ for (ob = bmain->object.first; ob; ob = ob->id.next) {
ModifierData *md;
for (md = ob->modifiers.first; md; md = md->next) {
if (md->type == eModifierType_Decimate) {
@@ -958,20 +958,20 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main)
}
}
- if (!MAIN_VERSION_ATLEAST(main, 275, 3)) {
+ if (!MAIN_VERSION_ATLEAST(bmain, 275, 3)) {
Brush *br;
#define BRUSH_TORUS (1 << 1)
- for (br = main->brush.first; br; br = br->id.next) {
+ for (br = bmain->brush.first; br; br = br->id.next) {
br->flag &= ~BRUSH_TORUS;
}
#undef BRUSH_TORUS
}
- if (!MAIN_VERSION_ATLEAST(main, 276, 2)) {
+ if (!MAIN_VERSION_ATLEAST(bmain, 276, 2)) {
if (!DNA_struct_elem_find(fd->filesdna, "bPoseChannel", "float", "custom_scale")) {
Object *ob;
- for (ob = main->object.first; ob; ob = ob->id.next) {
+ for (ob = bmain->object.first; ob; ob = ob->id.next) {
if (ob->pose) {
bPoseChannel *pchan;
for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
@@ -984,7 +984,7 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main)
{
bScreen *screen;
#define RV3D_VIEW_PERSPORTHO 7
- for (screen = main->screen.first; screen; screen = screen->id.next) {
+ for (screen = bmain->screen.first; screen; screen = screen->id.next) {
ScrArea *sa;
for (sa = screen->areabase.first; sa; sa = sa->next) {
SpaceLink *sl;
@@ -1013,7 +1013,7 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main)
{
Lamp *lamp;
#define LA_YF_PHOTON 5
- for (lamp = main->lamp.first; lamp; lamp = lamp->id.next) {
+ for (lamp = bmain->lamp.first; lamp; lamp = lamp->id.next) {
if (lamp->type == LA_YF_PHOTON) {
lamp->type = LA_LOCAL;
}
@@ -1022,10 +1022,10 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main)
}
}
- if (!MAIN_VERSION_ATLEAST(main, 276, 3)) {
+ if (!MAIN_VERSION_ATLEAST(bmain, 276, 3)) {
if (!DNA_struct_elem_find(fd->filesdna, "RenderData", "CurveMapping", "mblur_shutter_curve")) {
Scene *scene;
- for (scene = main->scene.first; scene != NULL; scene = scene->id.next) {
+ for (scene = bmain->scene.first; scene != NULL; scene = scene->id.next) {
CurveMapping *curve_mapping = &scene->r.mblur_shutter_curve;
curvemapping_set_defaults(curve_mapping, 1, 0.0f, 0.0f, 1.0f, 1.0f);
curvemapping_initialize(curve_mapping);
@@ -1037,8 +1037,8 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main)
}
}
- if (!MAIN_VERSION_ATLEAST(main, 276, 4)) {
- for (Scene *scene = main->scene.first; scene; scene = scene->id.next) {
+ if (!MAIN_VERSION_ATLEAST(bmain, 276, 4)) {
+ for (Scene *scene = bmain->scene.first; scene; scene = scene->id.next) {
ToolSettings *ts = scene->toolsettings;
if (ts->gp_sculpt.brush[0].size == 0) {
@@ -1113,7 +1113,7 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main)
}
}
- for (bGPdata *gpd = main->gpencil.first; gpd; gpd = gpd->id.next) {
+ for (bGPdata *gpd = bmain->gpencil.first; gpd; gpd = gpd->id.next) {
bool enabled = false;
/* Ensure that the datablock's onionskinning toggle flag
@@ -1131,13 +1131,13 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main)
gpd->flag &= ~GP_DATA_SHOW_ONIONSKINS;
}
}
- if (!MAIN_VERSION_ATLEAST(main, 276, 5)) {
+ if (!MAIN_VERSION_ATLEAST(bmain, 276, 5)) {
ListBase *lbarray[MAX_LIBARRAY];
int a;
/* Important to clear all non-persistent flags from older versions here, otherwise they could collide
* with any new persistent flag we may add in the future. */
- a = set_listbasepointers(main, lbarray);
+ a = set_listbasepointers(bmain, lbarray);
while (a--) {
for (ID *id = lbarray[a]->first; id; id = id->next) {
id->flag &= LIB_FAKEUSER;
@@ -1145,15 +1145,15 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main)
}
}
- if (!MAIN_VERSION_ATLEAST(main, 276, 7)) {
+ if (!MAIN_VERSION_ATLEAST(bmain, 276, 7)) {
Scene *scene;
- for (scene = main->scene.first; scene != NULL; scene = scene->id.next) {
+ for (scene = bmain->scene.first; scene != NULL; scene = scene->id.next) {
scene->r.bake.pass_filter = R_BAKE_PASS_FILTER_ALL;
}
}
- if (!MAIN_VERSION_ATLEAST(main, 277, 1)) {
- for (Scene *scene = main->scene.first; scene; scene = scene->id.next) {
+ if (!MAIN_VERSION_ATLEAST(bmain, 277, 1)) {
+ for (Scene *scene = bmain->scene.first; scene; scene = scene->id.next) {
ParticleEditSettings *pset = &scene->toolsettings->particle;
for (int a = 0; a < ARRAY_SIZE(pset->brush); a++) {
if (pset->brush[a].strength > 1.0f) {
@@ -1162,7 +1162,7 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main)
}
}
- for (bScreen *screen = main->screen.first; screen; screen = screen->id.next) {
+ for (bScreen *screen = bmain->screen.first; screen; screen = screen->id.next) {
for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
for (SpaceLink *sl = sa->spacedata.first; sl; sl = sl->next) {
ListBase *regionbase = (sl == sa->spacedata.first) ? &sa->regionbase : &sl->regionbase;
@@ -1195,7 +1195,7 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main)
}
}
- for (Scene *scene = main->scene.first; scene; scene = scene->id.next) {
+ for (Scene *scene = bmain->scene.first; scene; scene = scene->id.next) {
CurvePaintSettings *cps = &scene->toolsettings->curve_paint_settings;
if (cps->error_threshold == 0) {
cps->curve_type = CU_BEZIER;
@@ -1206,7 +1206,7 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main)
}
}
- for (Scene *scene = main->scene.first; scene; scene = scene->id.next) {
+ for (Scene *scene = bmain->scene.first; scene; scene = scene->id.next) {
Sequence *seq;
SEQ_BEGIN (scene->ed, seq)
@@ -1230,7 +1230,7 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main)
}
/* Adding "Properties" region to DopeSheet */
- for (bScreen *screen = main->screen.first; screen; screen = screen->id.next) {
+ for (bScreen *screen = bmain->screen.first; screen; screen = screen->id.next) {
for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
/* handle pushed-back space data first */
for (SpaceLink *sl = sa->spacedata.first; sl; sl = sl->next) {
@@ -1248,14 +1248,14 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main)
}
}
- if (!MAIN_VERSION_ATLEAST(main, 277, 2)) {
+ if (!MAIN_VERSION_ATLEAST(bmain, 277, 2)) {
if (!DNA_struct_elem_find(fd->filesdna, "Bone", "float", "scaleIn")) {
- for (bArmature *arm = main->armature.first; arm; arm = arm->id.next) {
+ for (bArmature *arm = bmain->armature.first; arm; arm = arm->id.next) {
do_version_bones_super_bbone(&arm->bonebase);
}
}
if (!DNA_struct_elem_find(fd->filesdna, "bPoseChannel", "float", "scaleIn")) {
- for (Object *ob = main->object.first; ob; ob = ob->id.next) {
+ for (Object *ob = bmain->object.first; ob; ob = ob->id.next) {
if (ob->pose) {
for (bPoseChannel *pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
/* see do_version_bones_super_bbone()... */
@@ -1275,7 +1275,7 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main)
}
}
- for (Camera *camera = main->camera.first; camera != NULL; camera = camera->id.next) {
+ for (Camera *camera = bmain->camera.first; camera != NULL; camera = camera->id.next) {
if (camera->stereo.pole_merge_angle_from == 0.0f &&
camera->stereo.pole_merge_angle_to == 0.0f)
{
@@ -1287,7 +1287,7 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main)
if (!DNA_struct_elem_find(fd->filesdna, "NormalEditModifierData", "float", "mix_limit")) {
Object *ob;
- for (ob = main->object.first; ob; ob = ob->id.next) {
+ for (ob = bmain->object.first; ob; ob = ob->id.next) {
ModifierData *md;
for (md = ob->modifiers.first; md; md = md->next) {
if (md->type == eModifierType_NormalEdit) {
@@ -1300,7 +1300,7 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main)
if (!DNA_struct_elem_find(fd->filesdna, "BooleanModifierData", "float", "double_threshold")) {
Object *ob;
- for (ob = main->object.first; ob; ob = ob->id.next) {
+ for (ob = bmain->object.first; ob; ob = ob->id.next) {
ModifierData *md;
for (md = ob->modifiers.first; md; md = md->next) {
if (md->type == eModifierType_Boolean) {
@@ -1311,7 +1311,7 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main)
}
}
- for (Brush *br = main->brush.first; br; br = br->id.next) {
+ for (Brush *br = bmain->brush.first; br; br = br->id.next) {
if (br->sculpt_tool == SCULPT_TOOL_FLATTEN) {
br->flag |= BRUSH_ACCUMULATE;
}
@@ -1320,7 +1320,7 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main)
if (!DNA_struct_elem_find(fd->filesdna, "ClothSimSettings", "float", "time_scale")) {
Object *ob;
ModifierData *md;
- for (ob = main->object.first; ob; ob = ob->id.next) {
+ for (ob = bmain->object.first; ob; ob = ob->id.next) {
for (md = ob->modifiers.first; md; md = md->next) {
if (md->type == eModifierType_Cloth) {
ClothModifierData *clmd = (ClothModifierData *)md;
@@ -1337,10 +1337,10 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main)
}
}
- if (!MAIN_VERSION_ATLEAST(main, 277, 3)) {
+ if (!MAIN_VERSION_ATLEAST(bmain, 277, 3)) {
/* ------- init of grease pencil initialization --------------- */
if (!DNA_struct_elem_find(fd->filesdna, "bGPDstroke", "bGPDpalettecolor", "*palcolor")) {
- for (Scene *scene = main->scene.first; scene; scene = scene->id.next) {
+ for (Scene *scene = bmain->scene.first; scene; scene = scene->id.next) {
ToolSettings *ts = scene->toolsettings;
/* initialize use position for sculpt brushes */
ts->gp_sculpt.flag |= GP_BRUSHEDIT_FLAG_APPLY_POSITION;
@@ -1359,8 +1359,8 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main)
}
}
/* create a default grease pencil drawing brushes set */
- if (!BLI_listbase_is_empty(&main->gpencil)) {
- for (Scene *scene = main->scene.first; scene; scene = scene->id.next) {
+ if (!BLI_listbase_is_empty(&bmain->gpencil)) {
+ for (Scene *scene = bmain->scene.first; scene; scene = scene->id.next) {
ToolSettings *ts = scene->toolsettings;
if (BLI_listbase_is_empty(&ts->gp_brushes)) {
BKE_gpencil_brush_init_presets(ts);
@@ -1370,7 +1370,7 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main)
/* Convert Grease Pencil to new palettes/brushes
* Loop all strokes and create the palette and all colors
*/
- for (bGPdata *gpd = main->gpencil.first; gpd; gpd = gpd->id.next) {
+ for (bGPdata *gpd = bmain->gpencil.first; gpd; gpd = gpd->id.next) {
if (BLI_listbase_is_empty(&gpd->palettes)) {
/* create palette */
bGPDpalette *palette = BKE_gpencil_palette_addnew(gpd, "GP_Palette", true);
@@ -1423,10 +1423,10 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main)
/* ------- end of grease pencil initialization --------------- */
}
- if (!MAIN_VERSION_ATLEAST(main, 278, 0)) {
+ if (!MAIN_VERSION_ATLEAST(bmain, 278, 0)) {
if (!DNA_struct_elem_find(fd->filesdna, "MovieTrackingTrack", "float", "weight_stab")) {
MovieClip *clip;
- for (clip = main->movieclip.first; clip; clip = clip->id.next) {
+ for (clip = bmain->movieclip.first; clip; clip = clip->id.next) {
MovieTracking *tracking = &clip->tracking;
MovieTrackingObject *tracking_object;
for (tracking_object = tracking->objects.first;
@@ -1447,7 +1447,7 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main)
if (!DNA_struct_elem_find(fd->filesdna, "MovieTrackingStabilization", "int", "tot_rot_track")) {
MovieClip *clip;
- for (clip = main->movieclip.first; clip != NULL; clip = clip->id.next) {
+ for (clip = bmain->movieclip.first; clip != NULL; clip = clip->id.next) {
if (clip->tracking.stabilization.rot_track) {
migrate_single_rot_stabilization_track_settings(&clip->tracking.stabilization);
}
@@ -1467,15 +1467,15 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main)
}
}
}
- if (!MAIN_VERSION_ATLEAST(main, 278, 2)) {
+ if (!MAIN_VERSION_ATLEAST(bmain, 278, 2)) {
if (!DNA_struct_elem_find(fd->filesdna, "FFMpegCodecData", "int", "ffmpeg_preset")) {
- for (Scene *scene = main->scene.first; scene; scene = scene->id.next) {
+ for (Scene *scene = bmain->scene.first; scene; scene = scene->id.next) {
/* "medium" is the preset FFmpeg uses when no presets are given. */
scene->r.ffcodecdata.ffmpeg_preset = FFM_PRESET_MEDIUM;
}
}
if (!DNA_struct_elem_find(fd->filesdna, "FFMpegCodecData", "int", "constant_rate_factor")) {
- for (Scene *scene = main->scene.first; scene; scene = scene->id.next) {
+ for (Scene *scene = bmain->scene.first; scene; scene = scene->id.next) {
/* fall back to behaviour from before we introduced CRF for old files */
scene->r.ffcodecdata.constant_rate_factor = FFM_CRF_NONE;
}
@@ -1485,7 +1485,7 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main)
Object *ob;
ModifierData *md;
- for (ob = main->object.first; ob; ob = ob->id.next) {
+ for (ob = bmain->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;
@@ -1500,8 +1500,8 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main)
}
}
- if (!MAIN_VERSION_ATLEAST(main, 278, 3)) {
- for (Scene *scene = main->scene.first; scene != NULL; scene = scene->id.next) {
+ if (!MAIN_VERSION_ATLEAST(bmain, 278, 3)) {
+ for (Scene *scene = bmain->scene.first; scene != NULL; scene = scene->id.next) {
if (scene->toolsettings != NULL) {
ToolSettings *ts = scene->toolsettings;
ParticleEditSettings *pset = &ts->particle;
@@ -1515,7 +1515,7 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main)
if (!DNA_struct_elem_find(fd->filesdna, "RigidBodyCon", "float", "spring_stiffness_ang_x")) {
Object *ob;
- for (ob = main->object.first; ob; ob = ob->id.next) {
+ for (ob = bmain->object.first; ob; ob = ob->id.next) {
RigidBodyCon *rbc = ob->rigidbody_constraint;
if (rbc) {
rbc->spring_stiffness_ang_x = 10.0;
@@ -1530,7 +1530,7 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main)
/* constant detail for sculpting is now a resolution value instead of
* a percentage, we reuse old DNA struct member but convert it */
- for (Scene *scene = main->scene.first; scene != NULL; scene = scene->id.next) {
+ for (Scene *scene = bmain->scene.first; scene != NULL; scene = scene->id.next) {
if (scene->toolsettings != NULL) {
ToolSettings *ts = scene->toolsettings;
if (ts->sculpt && ts->sculpt->constant_detail != 0.0f) {
@@ -1540,16 +1540,16 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main)
}
}
- if (!MAIN_VERSION_ATLEAST(main, 278, 4)) {
+ if (!MAIN_VERSION_ATLEAST(bmain, 278, 4)) {
const float sqrt_3 = (float)M_SQRT3;
- for (Brush *br = main->brush.first; br; br = br->id.next) {
+ for (Brush *br = bmain->brush.first; br; br = br->id.next) {
br->fill_threshold /= sqrt_3;
}
/* Custom motion paths */
if (!DNA_struct_elem_find(fd->filesdna, "bMotionPath", "int", "line_thickness")) {
Object *ob;
- for (ob = main->object.first; ob; ob = ob->id.next) {
+ for (ob = bmain->object.first; ob; ob = ob->id.next) {
bMotionPath *mpath;
bPoseChannel *pchan;
mpath = ob->mpath;
@@ -1577,9 +1577,9 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main)
}
}
- if (!MAIN_VERSION_ATLEAST(main, 278, 5)) {
+ if (!MAIN_VERSION_ATLEAST(bmain, 278, 5)) {
/* Mask primitive adding code was not initializing correctly id_type of its points' parent. */
- for (Mask *mask = main->mask.first; mask; mask = mask->id.next) {
+ for (Mask *mask = bmain->mask.first; mask; mask = mask->id.next) {
for (MaskLayer *mlayer = mask->masklayers.first; mlayer; mlayer = mlayer->next) {
for (MaskSpline *mspline = mlayer->splines.first; mspline; mspline = mspline->next) {
int i = 0;
@@ -1594,7 +1594,7 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main)
/* Fix for T50736, Glare comp node using same var for two different things. */
if (!DNA_struct_elem_find(fd->filesdna, "NodeGlare", "char", "star_45")) {
- FOREACH_NODETREE(main, ntree, id) {
+ FOREACH_NODETREE(bmain, ntree, id) {
if (ntree->type == NTREE_COMPOSIT) {
ntreeSetTypes(NULL, ntree);
for (bNode *node = ntree->nodes.first; node; node = node->next) {
@@ -1617,7 +1617,7 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main)
}
if (!DNA_struct_elem_find(fd->filesdna, "SurfaceDeformModifierData", "float", "mat[4][4]")) {
- for (Object *ob = main->object.first; ob; ob = ob->id.next) {
+ for (Object *ob = bmain->object.first; ob; ob = ob->id.next) {
for (ModifierData *md = ob->modifiers.first; md; md = md->next) {
if (md->type == eModifierType_SurfaceDeform) {
SurfaceDeformModifierData *smd = (SurfaceDeformModifierData *)md;
@@ -1627,32 +1627,32 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main)
}
}
- FOREACH_NODETREE(main, ntree, id) {
+ FOREACH_NODETREE(bmain, ntree, id) {
if (ntree->type == NTREE_COMPOSIT) {
do_versions_compositor_render_passes(ntree);
}
} FOREACH_NODETREE_END
}
- if (!MAIN_VERSION_ATLEAST(main, 279, 0)) {
- for (Scene *scene = main->scene.first; scene; scene = scene->id.next) {
+ if (!MAIN_VERSION_ATLEAST(bmain, 279, 0)) {
+ for (Scene *scene = bmain->scene.first; scene; scene = scene->id.next) {
if (scene->r.im_format.exr_codec == R_IMF_EXR_CODEC_DWAB) {
scene->r.im_format.exr_codec = R_IMF_EXR_CODEC_DWAA;
}
}
/* Fix related to VGroup modifiers creating named defgroup CD layers! See T51520. */
- for (Mesh *me = main->mesh.first; me; me = me->id.next) {
+ for (Mesh *me = bmain->mesh.first; me; me = me->id.next) {
CustomData_set_layer_name(&me->vdata, CD_MDEFORMVERT, 0, "");
}
}
- if (!MAIN_VERSION_ATLEAST(main, 279, 3)) {
+ if (!MAIN_VERSION_ATLEAST(bmain, 279, 3)) {
if (!DNA_struct_elem_find(fd->filesdna, "SmokeDomainSettings", "float", "clipping")) {
Object *ob;
ModifierData *md;
- for (ob = main->object.first; ob; ob = ob->id.next) {
+ for (ob = bmain->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;
@@ -1667,7 +1667,7 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main)
{
/* Fix for invalid state of screen due to bug in older versions. */
- for (bScreen *sc = main->screen.first; sc; sc = sc->id.next) {
+ for (bScreen *sc = bmain->screen.first; sc; sc = sc->id.next) {
for (ScrArea *sa = sc->areabase.first; sa; sa = sa->next) {
if (sa->full && sc->state == SCREENNORMAL) {
sa->full = NULL;
@@ -1676,7 +1676,7 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main)
}
if (!DNA_struct_elem_find(fd->filesdna, "Brush", "float", "falloff_angle")) {
- for (Brush *br = main->brush.first; br; br = br->id.next) {
+ for (Brush *br = bmain->brush.first; br; br = br->id.next) {
br->falloff_angle = DEG2RADF(80);
br->flag &= ~(
BRUSH_FLAG_DEPRECATED_1 | BRUSH_FLAG_DEPRECATED_2 |
@@ -1684,7 +1684,7 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main)
BRUSH_FRONTFACE_FALLOFF);
}
- for (Scene *scene = main->scene.first; scene; scene = scene->id.next) {
+ for (Scene *scene = bmain->scene.first; scene; scene = scene->id.next) {
ToolSettings *ts = scene->toolsettings;
for (int i = 0; i < 2; i++) {
VPaint *vp = i ? ts->vpaint : ts->wpaint;
@@ -1699,7 +1699,7 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main)
/* Simple deform modifier no longer assumes Z axis (X for bend type).
* Must set previous defaults. */
if (!DNA_struct_elem_find(fd->filesdna, "SimpleDeformModifierData", "char", "deform_axis")) {
- for (Object *ob = main->object.first; ob; ob = ob->id.next) {
+ for (Object *ob = bmain->object.first; ob; ob = ob->id.next) {
for (ModifierData *md = ob->modifiers.first; md; md = md->next) {
if (md->type == eModifierType_SimpleDeform) {
SimpleDeformModifierData *smd = (SimpleDeformModifierData *)md;
@@ -1709,7 +1709,7 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main)
}
}
- for (Scene *scene = main->scene.first; scene; scene = scene->id.next) {
+ for (Scene *scene = bmain->scene.first; scene; scene = scene->id.next) {
int preset = scene->r.ffcodecdata.ffmpeg_preset;
if (preset == FFM_PRESET_NONE || preset >= FFM_PRESET_GOOD) {
continue;
@@ -1727,7 +1727,7 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main)
}
if (!DNA_struct_elem_find(fd->filesdna, "ParticleInstanceModifierData", "float", "particle_amount")) {
- for (Object *ob = main->object.first; ob; ob = ob->id.next) {
+ for (Object *ob = bmain->object.first; ob; ob = ob->id.next) {
for (ModifierData *md = ob->modifiers.first; md; md = md->next) {
if (md->type == eModifierType_ParticleInstance) {
ParticleInstanceModifierData *pimd = (ParticleInstanceModifierData *)md;
@@ -1740,11 +1740,11 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main)
}
}
-void do_versions_after_linking_270(Main *main)
+void do_versions_after_linking_270(Main *bmain)
{
/* To be added to next subversion bump! */
- if (!MAIN_VERSION_ATLEAST(main, 279, 0)) {
- FOREACH_NODETREE(main, ntree, id) {
+ if (!MAIN_VERSION_ATLEAST(bmain, 279, 0)) {
+ FOREACH_NODETREE(bmain, ntree, id) {
if (ntree->type == NTREE_COMPOSIT) {
ntreeSetTypes(NULL, ntree);
for (bNode *node = ntree->nodes.first; node; node = node->next) {
@@ -1756,9 +1756,9 @@ void do_versions_after_linking_270(Main *main)
} FOREACH_NODETREE_END
}
- if (!MAIN_VERSION_ATLEAST(main, 279, 2)) {
+ if (!MAIN_VERSION_ATLEAST(bmain, 279, 2)) {
/* B-Bones (bbone_in/out -> bbone_easein/out) + Stepped FMod Frame Start/End fix */
/* if (!DNA_struct_elem_find(fd->filesdna, "Bone", "float", "bbone_easein")) */
- BKE_fcurves_main_cb(main, do_version_bbone_easing_fcurve_fix, NULL);
+ BKE_fcurves_main_cb(bmain, do_version_bbone_easing_fcurve_fix, NULL);
}
}
diff --git a/source/blender/blenloader/intern/versioning_280.c b/source/blender/blenloader/intern/versioning_280.c
index 144b3889d30..eb165efb4f9 100644
--- a/source/blender/blenloader/intern/versioning_280.c
+++ b/source/blender/blenloader/intern/versioning_280.c
@@ -67,6 +67,7 @@
#include "BKE_report.h"
#include "BKE_scene.h"
#include "BKE_screen.h"
+#include "BKE_studiolight.h"
#include "BKE_workspace.h"
#include "BLO_readfile.h"
@@ -96,6 +97,9 @@ static void do_version_workspaces_create_from_screens(Main *bmain)
Scene *scene = screen->scene;
WorkSpace *workspace;
ViewLayer *layer = BLI_findlink(&scene->view_layers, scene->r.actlay);
+ if (screen->temp) {
+ continue;
+ }
if (!layer) {
layer = BKE_view_layer_default_view(scene);
}
@@ -671,15 +675,15 @@ static void do_version_layers_to_collections(Main *bmain, Scene *scene)
scene->basact = NULL;
}
-void do_versions_after_linking_280(Main *main)
+void do_versions_after_linking_280(Main *bmain)
{
bool use_collection_compat_28 = true;
- if (!MAIN_VERSION_ATLEAST(main, 280, 0)) {
+ if (!MAIN_VERSION_ATLEAST(bmain, 280, 0)) {
use_collection_compat_28 = false;
/* Convert group layer visibility flags to hidden nested collection. */
- for (Collection *collection = main->collection.first; collection; collection = collection->id.next) {
+ for (Collection *collection = bmain->collection.first; collection; collection = collection->id.next) {
/* Add fake user for all existing groups. */
id_fake_user_set(&collection->id);
@@ -694,25 +698,25 @@ void do_versions_after_linking_280(Main *main)
if (!(ob->lay & collection->layer)) {
if (collection_hidden == NULL) {
- collection_hidden = BKE_collection_add(main, collection, "Hidden");
+ collection_hidden = BKE_collection_add(bmain, collection, "Hidden");
collection_hidden->id.lib = collection->id.lib;
collection_hidden->flag |= COLLECTION_RESTRICT_VIEW | COLLECTION_RESTRICT_RENDER;
}
- BKE_collection_object_add(main, collection_hidden, ob);
- BKE_collection_object_remove(main, collection, ob, true);
+ BKE_collection_object_add(bmain, collection_hidden, ob);
+ BKE_collection_object_remove(bmain, collection, ob, true);
}
}
}
/* Convert layers to collections. */
- for (Scene *scene = main->scene.first; scene; scene = scene->id.next) {
- do_version_layers_to_collections(main, scene);
+ for (Scene *scene = bmain->scene.first; scene; scene = scene->id.next) {
+ do_version_layers_to_collections(bmain, scene);
}
}
- if (!MAIN_VERSION_ATLEAST(main, 280, 0)) {
- for (bScreen *screen = main->screen.first; screen; screen = screen->id.next) {
+ if (!MAIN_VERSION_ATLEAST(bmain, 280, 0)) {
+ for (bScreen *screen = bmain->screen.first; screen; screen = screen->id.next) {
/* same render-layer as do_version_workspaces_after_lib_link will activate,
* so same layer as BKE_view_layer_from_workspace_get would return */
ViewLayer *layer = screen->scene->view_layers.first;
@@ -746,14 +750,14 @@ void do_versions_after_linking_280(Main *main)
}
/* New workspace design */
- if (!MAIN_VERSION_ATLEAST(main, 280, 1)) {
- do_version_workspaces_after_lib_link(main);
+ if (!MAIN_VERSION_ATLEAST(bmain, 280, 1)) {
+ do_version_workspaces_after_lib_link(bmain);
}
- if (!MAIN_VERSION_ATLEAST(main, 280, 2)) {
+ if (!MAIN_VERSION_ATLEAST(bmain, 280, 2)) {
/* Cleanup any remaining SceneRenderLayer data for files that were created
* with Blender 2.8 before the SceneRenderLayer > RenderLayer refactor. */
- for (Scene *scene = main->scene.first; scene; scene = scene->id.next) {
+ for (Scene *scene = bmain->scene.first; scene; scene = scene->id.next) {
for (SceneRenderLayer *srl = scene->r.layers.first; srl; srl = srl->next) {
if (srl->prop) {
IDP_FreeProperty(srl->prop);
@@ -765,10 +769,10 @@ void do_versions_after_linking_280(Main *main)
}
}
- if (!MAIN_VERSION_ATLEAST(main, 280, 3)) {
+ if (!MAIN_VERSION_ATLEAST(bmain, 280, 3)) {
/* Due to several changes to particle RNA and draw code particles from older files may no longer
* be visible. Here we correct this by setting a default draw size for those files. */
- for (Object *object = main->object.first; object; object = object->id.next) {
+ for (Object *object = bmain->object.first; object; object = object->id.next) {
for (ParticleSystem *psys = object->particlesystem.first; psys; psys = psys->next) {
if (psys->part->draw_size == 0.0f) {
psys->part->draw_size = 0.1f;
@@ -777,8 +781,8 @@ void do_versions_after_linking_280(Main *main)
}
}
- if (!MAIN_VERSION_ATLEAST(main, 280, 4)) {
- for (Object *object = main->object.first; object; object = object->id.next) {
+ if (!MAIN_VERSION_ATLEAST(bmain, 280, 4)) {
+ for (Object *object = bmain->object.first; object; object = object->id.next) {
#ifndef VERSION_280_SUBVERSION_4
/* If any object already has an initialized value for
* duplicator_visibility_flag it means we've already doversioned it.
@@ -810,9 +814,9 @@ void do_versions_after_linking_280(Main *main)
}
/* SpaceTime & SpaceLogic removal/replacing */
- if (!MAIN_VERSION_ATLEAST(main, 280, 9)) {
- const wmWindowManager *wm = main->wm.first;
- const Scene *scene = main->scene.first;
+ if (!MAIN_VERSION_ATLEAST(bmain, 280, 9)) {
+ const wmWindowManager *wm = bmain->wm.first;
+ const Scene *scene = bmain->scene.first;
if (wm != NULL) {
/* Action editors need a scene for creation. First, update active
@@ -832,7 +836,7 @@ void do_versions_after_linking_280(Main *main)
}
}
if (scene != NULL) {
- for (bScreen *screen = main->screen.first; screen; screen = screen->id.next) {
+ for (bScreen *screen = bmain->screen.first; screen; screen = screen->id.next) {
for (ScrArea *area = screen->areabase.first; area; area = area->next) {
if (ELEM(area->butspacetype, SPACE_TIME, SPACE_LOGIC)) {
/* Areas that were already handled won't be handled again */
@@ -847,39 +851,39 @@ void do_versions_after_linking_280(Main *main)
}
#ifdef USE_COLLECTION_COMPAT_28
- if (use_collection_compat_28 && !MAIN_VERSION_ATLEAST(main, 280, 14)) {
- for (Collection *group = main->collection.first; group; group = group->id.next) {
- do_version_group_collection_to_collection(main, group);
+ if (use_collection_compat_28 && !MAIN_VERSION_ATLEAST(bmain, 280, 14)) {
+ for (Collection *group = bmain->collection.first; group; group = group->id.next) {
+ do_version_group_collection_to_collection(bmain, group);
}
- for (Scene *scene = main->scene.first; scene; scene = scene->id.next) {
- do_version_scene_collection_to_collection(main, scene);
+ for (Scene *scene = bmain->scene.first; scene; scene = scene->id.next) {
+ do_version_scene_collection_to_collection(bmain, scene);
}
}
#endif
}
-void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *main)
+void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain)
{
bool use_collection_compat_28 = true;
- if (!MAIN_VERSION_ATLEAST(main, 280, 0)) {
+ if (!MAIN_VERSION_ATLEAST(bmain, 280, 0)) {
use_collection_compat_28 = false;
- for (Scene *scene = main->scene.first; scene; scene = scene->id.next) {
+ for (Scene *scene = bmain->scene.first; scene; scene = scene->id.next) {
scene->r.gauss = 1.5f;
}
}
- if (!MAIN_VERSION_ATLEAST(main, 280, 1)) {
+ if (!MAIN_VERSION_ATLEAST(bmain, 280, 1)) {
if (!DNA_struct_elem_find(fd->filesdna, "Lamp", "float", "bleedexp")) {
- for (Lamp *la = main->lamp.first; la; la = la->id.next) {
+ for (Lamp *la = bmain->lamp.first; la; la = la->id.next) {
la->bleedexp = 2.5f;
}
}
if (!DNA_struct_elem_find(fd->filesdna, "GPUDOFSettings", "float", "ratio")) {
- for (Camera *ca = main->camera.first; ca; ca = ca->id.next) {
+ for (Camera *ca = bmain->camera.first; ca; ca = ca->id.next) {
ca->gpu_dof.ratio = 1.0f;
}
}
@@ -887,7 +891,7 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *main)
/* MTexPoly now removed. */
if (DNA_struct_find(fd->filesdna, "MTexPoly")) {
const int cd_mtexpoly = 15; /* CD_MTEXPOLY, deprecated */
- for (Mesh *me = main->mesh.first; me; me = me->id.next) {
+ for (Mesh *me = bmain->mesh.first; me; me = me->id.next) {
/* If we have UV's, so this file will have MTexPoly layers too! */
if (me->mloopuv != NULL) {
CustomData_update_typemap(&me->pdata);
@@ -898,9 +902,9 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *main)
}
}
- if (!MAIN_VERSION_ATLEAST(main, 280, 2)) {
+ if (!MAIN_VERSION_ATLEAST(bmain, 280, 2)) {
if (!DNA_struct_elem_find(fd->filesdna, "Lamp", "float", "cascade_max_dist")) {
- for (Lamp *la = main->lamp.first; la; la = la->id.next) {
+ for (Lamp *la = bmain->lamp.first; la; la = la->id.next) {
la->cascade_max_dist = 1000.0f;
la->cascade_count = 4;
la->cascade_exponent = 0.8f;
@@ -909,7 +913,7 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *main)
}
if (!DNA_struct_elem_find(fd->filesdna, "Lamp", "float", "contact_dist")) {
- for (Lamp *la = main->lamp.first; la; la = la->id.next) {
+ for (Lamp *la = bmain->lamp.first; la; la = la->id.next) {
la->contact_dist = 1.0f;
la->contact_bias = 0.03f;
la->contact_spread = 0.2f;
@@ -918,7 +922,7 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *main)
}
if (!DNA_struct_elem_find(fd->filesdna, "LightProbe", "float", "vis_bias")) {
- for (LightProbe *probe = main->lightprobe.first; probe; probe = probe->id.next) {
+ for (LightProbe *probe = bmain->lightprobe.first; probe; probe = probe->id.next) {
probe->vis_bias = 1.0f;
probe->vis_blur = 0.2f;
}
@@ -937,7 +941,7 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *main)
* Also, metallic node is now unified into the principled node. */
eNTreeDoVersionErrors error = NTREE_DOVERSION_NO_ERROR;
- FOREACH_NODETREE(main, ntree, id) {
+ FOREACH_NODETREE(bmain, ntree, id) {
if (ntree->type == NTREE_SHADER) {
for (bNode *node = ntree->nodes.first; node; node = node->next) {
if (node->type == 194 /* SH_NODE_EEVEE_METALLIC */ &&
@@ -986,7 +990,7 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *main)
(DNA_struct_elem_find(fd->filesdna, "ViewLayer", "FreestyleConfig", "freestyle_config") == false) &&
DNA_struct_elem_find(fd->filesdna, "Scene", "ListBase", "view_layers"))
{
- for (Scene *scene = main->scene.first; scene; scene = scene->id.next) {
+ for (Scene *scene = bmain->scene.first; scene; scene = scene->id.next) {
ViewLayer *view_layer;
for (view_layer = scene->view_layers.first; view_layer; view_layer = view_layer->next) {
view_layer->flag |= VIEW_LAYER_FREESTYLE;
@@ -1001,15 +1005,15 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *main)
}
#ifdef USE_COLLECTION_COMPAT_28
- if (use_collection_compat_28 && !MAIN_VERSION_ATLEAST(main, 280, 3)) {
- for (Scene *scene = main->scene.first; scene; scene = scene->id.next) {
+ if (use_collection_compat_28 && !MAIN_VERSION_ATLEAST(bmain, 280, 3)) {
+ for (Scene *scene = bmain->scene.first; scene; scene = scene->id.next) {
ViewLayer *view_layer;
for (view_layer = scene->view_layers.first; view_layer; view_layer = view_layer->next) {
do_version_view_layer_visibility(view_layer);
}
}
- for (Collection *group = main->collection.first; group; group = group->id.next) {
+ for (Collection *group = bmain->collection.first; group; group = group->id.next) {
if (group->view_layer != NULL) {
do_version_view_layer_visibility(group->view_layer);
}
@@ -1017,14 +1021,14 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *main)
}
#endif
- if (!MAIN_VERSION_ATLEAST(main, 280, 6)) {
+ if (!MAIN_VERSION_ATLEAST(bmain, 280, 6)) {
if (DNA_struct_elem_find(fd->filesdna, "SpaceOops", "int", "filter") == false) {
bScreen *sc;
ScrArea *sa;
SpaceLink *sl;
/* Update files using invalid (outdated) outlinevis Outliner values. */
- for (sc = main->screen.first; sc; sc = sc->id.next) {
+ for (sc = bmain->screen.first; sc; sc = sc->id.next) {
for (sa = sc->areabase.first; sa; sa = sa->next) {
for (sl = sa->spacedata.first; sl; sl = sl->next) {
if (sl->spacetype == SPACE_OUTLINER) {
@@ -1046,12 +1050,12 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *main)
}
if (!DNA_struct_elem_find(fd->filesdna, "LightProbe", "float", "intensity")) {
- for (LightProbe *probe = main->lightprobe.first; probe; probe = probe->id.next) {
+ for (LightProbe *probe = bmain->lightprobe.first; probe; probe = probe->id.next) {
probe->intensity = 1.0f;
}
}
- for (Object *ob = main->object.first; ob; ob = ob->id.next) {
+ for (Object *ob = bmain->object.first; ob; ob = ob->id.next) {
bConstraint *con, *con_next;
con = ob->constraints.first;
while (con) {
@@ -1066,12 +1070,12 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *main)
}
if (!DNA_struct_elem_find(fd->filesdna, "Scene", "int", "orientation_index_custom")) {
- for (Scene *scene = main->scene.first; scene; scene = scene->id.next) {
+ for (Scene *scene = bmain->scene.first; scene; scene = scene->id.next) {
scene->orientation_index_custom = -1;
}
}
- for (bScreen *sc = main->screen.first; sc; sc = sc->id.next) {
+ for (bScreen *sc = bmain->screen.first; sc; sc = sc->id.next) {
for (ScrArea *sa = sc->areabase.first; sa; sa = sa->next) {
for (SpaceLink *sl = sa->spacedata.first; sl; sl = sl->next) {
if (sl->spacetype == SPACE_VIEW3D) {
@@ -1081,7 +1085,7 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *main)
/* Assume (demo) files written with 2.8 want to show
* Eevee renders in the viewport. */
- if (MAIN_VERSION_ATLEAST(main, 280, 0)) {
+ if (MAIN_VERSION_ATLEAST(bmain, 280, 0)) {
v3d->drawtype = OB_MATERIAL;
}
}
@@ -1090,20 +1094,20 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *main)
}
}
- if (!MAIN_VERSION_ATLEAST(main, 280, 7)) {
+ if (!MAIN_VERSION_ATLEAST(bmain, 280, 7)) {
/* Render engine storage moved elsewhere and back during 2.8
* development, we assume any files saved in 2.8 had Eevee set
* as scene render engine. */
- if (MAIN_VERSION_ATLEAST(main, 280, 0)) {
- for (Scene *scene = main->scene.first; scene; scene = scene->id.next) {
+ if (MAIN_VERSION_ATLEAST(bmain, 280, 0)) {
+ for (Scene *scene = bmain->scene.first; scene; scene = scene->id.next) {
BLI_strncpy(scene->r.engine, RE_engine_id_BLENDER_EEVEE, sizeof(scene->r.engine));
}
}
}
- if (!MAIN_VERSION_ATLEAST(main, 280, 8)) {
+ if (!MAIN_VERSION_ATLEAST(bmain, 280, 8)) {
/* Blender Internal removal */
- for (Scene *scene = main->scene.first; scene; scene = scene->id.next) {
+ for (Scene *scene = bmain->scene.first; scene; scene = scene->id.next) {
if (STREQ(scene->r.engine, "BLENDER_RENDER") ||
STREQ(scene->r.engine, "BLENDER_GAME"))
{
@@ -1113,7 +1117,7 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *main)
scene->r.bake_mode = 0;
}
- for (Tex *tex = main->tex.first; tex; tex = tex->id.next) {
+ for (Tex *tex = bmain->tex.first; tex; tex = tex->id.next) {
/* Removed envmap, pointdensity, voxeldata, ocean textures. */
if (ELEM(tex->type, 10, 14, 15, 16)) {
tex->type = 0;
@@ -1121,10 +1125,10 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *main)
}
}
- if (!MAIN_VERSION_ATLEAST(main, 280, 11)) {
+ if (!MAIN_VERSION_ATLEAST(bmain, 280, 11)) {
/* Remove info editor, but only if at the top of the window. */
- for (bScreen *screen = main->screen.first; screen; screen = screen->id.next) {
+ for (bScreen *screen = bmain->screen.first; screen; screen = screen->id.next) {
/* Calculate window width/height from screen vertices */
int win_width = 0, win_height = 0;
for (ScrVert *vert = screen->vertbase.first; vert; vert = vert->next) {
@@ -1154,8 +1158,8 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *main)
}
}
- if (!MAIN_VERSION_ATLEAST(main, 280, 11)) {
- for (Lamp *lamp = main->lamp.first; lamp; lamp = lamp->id.next) {
+ if (!MAIN_VERSION_ATLEAST(bmain, 280, 11)) {
+ for (Lamp *lamp = bmain->lamp.first; lamp; lamp = lamp->id.next) {
if (lamp->mode & (1 << 13)) { /* LA_SHAD_RAY */
lamp->mode |= LA_SHADOW;
lamp->mode &= ~(1 << 13);
@@ -1163,9 +1167,9 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *main)
}
}
- if (!MAIN_VERSION_ATLEAST(main, 280, 12)) {
+ if (!MAIN_VERSION_ATLEAST(bmain, 280, 12)) {
/* Remove tool property regions. */
- for (bScreen *screen = main->screen.first; screen; screen = screen->id.next) {
+ for (bScreen *screen = bmain->screen.first; screen; screen = screen->id.next) {
for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
for (SpaceLink *sl = sa->spacedata.first; sl; sl = sl->next) {
if (ELEM(sl->spacetype, SPACE_VIEW3D, SPACE_CLIP)) {
@@ -1185,16 +1189,16 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *main)
}
}
- if (!MAIN_VERSION_ATLEAST(main, 280, 13)) {
+ if (!MAIN_VERSION_ATLEAST(bmain, 280, 13)) {
/* Initialize specular factor. */
if (!DNA_struct_elem_find(fd->filesdna, "Lamp", "float", "spec_fac")) {
- for (Lamp *la = main->lamp.first; la; la = la->id.next) {
+ for (Lamp *la = bmain->lamp.first; la; la = la->id.next) {
la->spec_fac = 1.0f;
}
}
/* Initialize new view3D options. */
- for (bScreen *screen = main->screen.first; screen; screen = screen->id.next) {
+ for (bScreen *screen = bmain->screen.first; screen; screen = screen->id.next) {
for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
for (SpaceLink *sl = sa->spacedata.first; sl; sl = sl->next) {
if (sl->spacetype == SPACE_VIEW3D) {
@@ -1213,10 +1217,10 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *main)
}
if (!DNA_struct_find(fd->filesdna, "View3DCursor")) {
- for (Scene *scene = main->scene.first; scene; scene = scene->id.next) {
+ for (Scene *scene = bmain->scene.first; scene; scene = scene->id.next) {
unit_qt(scene->cursor.rotation);
}
- for (bScreen *screen = main->screen.first; screen; screen = screen->id.next) {
+ for (bScreen *screen = bmain->screen.first; screen; screen = screen->id.next) {
for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
for (SpaceLink *sl = sa->spacedata.first; sl; sl = sl->next) {
if (sl->spacetype == SPACE_VIEW3D) {
@@ -1229,34 +1233,34 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *main)
}
}
- if (!MAIN_VERSION_ATLEAST(main, 280, 14)) {
+ if (!MAIN_VERSION_ATLEAST(bmain, 280, 14)) {
if (!DNA_struct_elem_find(fd->filesdna, "Scene", "SceneDisplay", "display")) {
/* Initialize new scene.SceneDisplay */
- for (Scene *scene = main->scene.first; scene; scene = scene->id.next) {
+ for (Scene *scene = bmain->scene.first; scene; scene = scene->id.next) {
copy_v3_v3(scene->display.light_direction, (float[3]){-M_SQRT1_3, -M_SQRT1_3, M_SQRT1_3});
}
}
if (!DNA_struct_elem_find(fd->filesdna, "SceneDisplay", "float", "shadow_shift")) {
- for (Scene *scene = main->scene.first; scene; scene = scene->id.next) {
+ for (Scene *scene = bmain->scene.first; scene; scene = scene->id.next) {
scene->display.shadow_shift = 0.1;
}
}
if (!DNA_struct_elem_find(fd->filesdna, "Object", "ObjectDisplay", "display")) {
/* Initialize new object.ObjectDisplay */
- for (Object *ob = main->object.first; ob; ob = ob->id.next) {
+ for (Object *ob = bmain->object.first; ob; ob = ob->id.next) {
ob->display.flag = OB_SHOW_SHADOW;
}
}
if (!DNA_struct_elem_find(fd->filesdna, "ToolSettings", "char", "transform_pivot_point")) {
- for (Scene *scene = main->scene.first; scene; scene = scene->id.next) {
+ for (Scene *scene = bmain->scene.first; scene; scene = scene->id.next) {
scene->toolsettings->transform_pivot_point = V3D_AROUND_CENTER_MEAN;
}
}
if (!DNA_struct_find(fd->filesdna, "SceneEEVEE")) {
- for (Scene *scene = main->scene.first; scene; scene = scene->id.next) {
+ for (Scene *scene = bmain->scene.first; scene; scene = scene->id.next) {
/* First set the default for all the properties. */
scene->eevee.gi_diffuse_bounces = 3;
@@ -1438,8 +1442,8 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *main)
}
- if (!MAIN_VERSION_ATLEAST(main, 280, 15)) {
- for (Scene *scene = main->scene.first; scene; scene = scene->id.next) {
+ if (!MAIN_VERSION_ATLEAST(bmain, 280, 15)) {
+ for (Scene *scene = bmain->scene.first; scene; scene = scene->id.next) {
scene->display.matcap_icon = 1;
scene->display.matcap_type = CLAY_MATCAP_NONE;
scene->display.matcap_hue = 0.5f;
@@ -1452,7 +1456,7 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *main)
scene->display.matcap_ssao_samples = 16;
}
- for (bScreen *screen = main->screen.first; screen; screen = screen->id.next) {
+ for (bScreen *screen = bmain->screen.first; screen; screen = screen->id.next) {
for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
for (SpaceLink *sl = sa->spacedata.first; sl; sl = sl->next) {
if (sl->spacetype == SPACE_OUTLINER) {
@@ -1464,7 +1468,7 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *main)
}
}
- for (Scene *scene = main->scene.first; scene; scene = scene->id.next) {
+ for (Scene *scene = bmain->scene.first; scene; scene = scene->id.next) {
switch (scene->toolsettings->snap_mode) {
case 0: scene->toolsettings->snap_mode = SCE_SNAP_MODE_INCREMENT; break;
case 1: scene->toolsettings->snap_mode = SCE_SNAP_MODE_VERTEX ; break;
@@ -1485,7 +1489,7 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *main)
}
ParticleSettings *part;
- for (part = main->particle.first; part; part = part->id.next) {
+ for (part = bmain->particle.first; part; part = part->id.next) {
part->shape_flag = PART_SHAPE_CLOSE_TIP;
part->shape = 0.0f;
part->rad_root = 1.0f;
@@ -1497,9 +1501,9 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *main)
}
{
if (!DNA_struct_elem_find(fd->filesdna, "Material", "float", "roughness")) {
- for (Material *mat = main->mat.first; mat; mat = mat->id.next) {
+ for (Material *mat = bmain->mat.first; mat; mat = mat->id.next) {
if (mat->use_nodes) {
- if (MAIN_VERSION_ATLEAST(main, 280, 0)) {
+ if (MAIN_VERSION_ATLEAST(bmain, 280, 0)) {
mat->roughness = mat->gloss_mir;
}
else {
@@ -1512,7 +1516,7 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *main)
mat->metallic = mat->ray_mirror;
}
- for (bScreen *screen = main->screen.first; screen; screen = screen->id.next) {
+ for (bScreen *screen = bmain->screen.first; screen; screen = screen->id.next) {
for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
for (SpaceLink *sl = sa->spacedata.first; sl; sl = sl->next) {
if (sl->spacetype == SPACE_VIEW3D) {
@@ -1525,7 +1529,7 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *main)
}
if (!DNA_struct_elem_find(fd->filesdna, "View3DShading", "float", "xray_alpha")) {
- for (bScreen *screen = main->screen.first; screen; screen = screen->id.next) {
+ for (bScreen *screen = bmain->screen.first; screen; screen = screen->id.next) {
for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
for (SpaceLink *sl = sa->spacedata.first; sl; sl = sl->next) {
if (sl->spacetype == SPACE_VIEW3D) {
@@ -1536,5 +1540,58 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *main)
}
}
}
+ if (!DNA_struct_elem_find(fd->filesdna, "View3DShading", "char", "matcap[256]")) {
+ StudioLight *default_matcap = BKE_studiolight_find_first(STUDIOLIGHT_ORIENTATION_VIEWNORMAL);
+ /* when loading the internal file is loaded before the matcaps */
+ if (default_matcap) {
+ for (bScreen *screen = bmain->screen.first; screen; screen = screen->id.next) {
+ for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
+ for (SpaceLink *sl = sa->spacedata.first; sl; sl = sl->next) {
+ if (sl->spacetype == SPACE_VIEW3D) {
+ View3D *v3d = (View3D *)sl;
+ BLI_strncpy(v3d->shading.matcap, default_matcap->name, FILE_MAXFILE);
+ }
+ }
+ }
+ }
+ }
+ }
+ if (!DNA_struct_elem_find(fd->filesdna, "View3DOverlay", "float", "wireframe_threshold")) {
+ for (bScreen *screen = bmain->screen.first; screen; screen = screen->id.next) {
+ for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
+ for (SpaceLink *sl = sa->spacedata.first; sl; sl = sl->next) {
+ if (sl->spacetype == SPACE_VIEW3D) {
+ View3D *v3d = (View3D *)sl;
+ v3d->overlay.wireframe_threshold = 0.5f;
+ }
+ }
+ }
+ }
+ }
+ if (!DNA_struct_elem_find(fd->filesdna, "View3DShading", "float", "cavity_valley_factor")) {
+ for (bScreen *screen = bmain->screen.first; screen; screen = screen->id.next) {
+ for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
+ for (SpaceLink *sl = sa->spacedata.first; sl; sl = sl->next) {
+ if (sl->spacetype == SPACE_VIEW3D) {
+ View3D *v3d = (View3D *)sl;
+ v3d->shading.cavity_valley_factor = 1.0f;
+ v3d->shading.cavity_ridge_factor = 1.0f;
+ }
+ }
+ }
+ }
+ }
+ if (!DNA_struct_elem_find(fd->filesdna, "View3DOverlay", "float", "bone_selection_alpha")) {
+ for (bScreen *screen = bmain->screen.first; screen; screen = screen->id.next) {
+ for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
+ for (SpaceLink *sl = sa->spacedata.first; sl; sl = sl->next) {
+ if (sl->spacetype == SPACE_VIEW3D) {
+ View3D *v3d = (View3D *)sl;
+ v3d->overlay.bone_selection_alpha = 0.5f;
+ }
+ }
+ }
+ }
+ }
}
}
diff --git a/source/blender/blenloader/intern/versioning_legacy.c b/source/blender/blenloader/intern/versioning_legacy.c
index a450c487dd9..bc69b1d99fc 100644
--- a/source/blender/blenloader/intern/versioning_legacy.c
+++ b/source/blender/blenloader/intern/versioning_legacy.c
@@ -483,13 +483,13 @@ void blo_do_version_old_trackto_to_constraints(Object *ob)
ob->track = NULL;
}
-void blo_do_versions_pre250(FileData *fd, Library *lib, Main *main)
+void blo_do_versions_pre250(FileData *fd, Library *lib, Main *bmain)
{
/* WATCH IT!!!: pointers from libdata have not been converted */
- if (main->versionfile == 100) {
+ if (bmain->versionfile == 100) {
/* tex->extend and tex->imageflag have changed: */
- Tex *tex = main->tex.first;
+ Tex *tex = bmain->tex.first;
while (tex) {
if (tex->id.tag & LIB_TAG_NEED_LINK) {
@@ -508,9 +508,9 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *main)
}
}
- if (main->versionfile <= 101) {
+ if (bmain->versionfile <= 101) {
/* frame mapping */
- Scene *sce = main->scene.first;
+ Scene *sce = bmain->scene.first;
while (sce) {
sce->r.framapto = 100;
sce->r.images = 100;
@@ -519,9 +519,9 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *main)
}
}
- if (main->versionfile <= 103) {
+ if (bmain->versionfile <= 103) {
/* new variable in object: colbits */
- Object *ob = main->object.first;
+ Object *ob = bmain->object.first;
int a;
while (ob) {
ob->colbits = 0;
@@ -535,9 +535,9 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *main)
}
}
- if (main->versionfile <= 104) {
+ if (bmain->versionfile <= 104) {
/* timeoffs moved */
- Object *ob = main->object.first;
+ Object *ob = bmain->object.first;
while (ob) {
if (ob->transflag & 1) {
ob->transflag -= 1;
@@ -546,8 +546,8 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *main)
}
}
- if (main->versionfile <= 105) {
- Object *ob = main->object.first;
+ if (bmain->versionfile <= 105) {
+ Object *ob = bmain->object.first;
while (ob) {
ob->dupon = 1;
ob->dupoff = 0;
@@ -557,9 +557,9 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *main)
}
}
- if (main->versionfile <= 106) {
+ if (bmain->versionfile <= 106) {
/* mcol changed */
- Mesh *me = main->mesh.first;
+ Mesh *me = bmain->mesh.first;
while (me) {
if (me->mcol)
vcol_to_fcol(me);
@@ -568,9 +568,9 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *main)
}
- if (main->versionfile <= 107) {
+ if (bmain->versionfile <= 107) {
Object *ob;
- ob = main->object.first;
+ ob = bmain->object.first;
while (ob) {
if (ob->dt == 0)
ob->dt = OB_SOLID;
@@ -579,9 +579,9 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *main)
}
- if (main->versionfile <= 109) {
+ if (bmain->versionfile <= 109) {
/* new variable: gridlines */
- bScreen *sc = main->screen.first;
+ bScreen *sc = bmain->screen.first;
while (sc) {
ScrArea *sa = sc->areabase.first;
while (sa) {
@@ -601,8 +601,8 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *main)
}
}
- if (main->versionfile <= 134) {
- Tex *tex = main->tex.first;
+ if (bmain->versionfile <= 134) {
+ Tex *tex = bmain->tex.first;
while (tex) {
if ((tex->rfac == 0.0f) &&
(tex->gfac == 0.0f) &&
@@ -617,9 +617,9 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *main)
}
}
- if (main->versionfile <= 140) {
+ if (bmain->versionfile <= 140) {
/* r-g-b-fac in texture */
- Tex *tex = main->tex.first;
+ Tex *tex = bmain->tex.first;
while (tex) {
if ((tex->rfac == 0.0f) &&
(tex->gfac == 0.0f) &&
@@ -634,8 +634,8 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *main)
}
}
- if (main->versionfile <= 153) {
- Scene *sce = main->scene.first;
+ if (bmain->versionfile <= 153) {
+ Scene *sce = bmain->scene.first;
while (sce) {
if (sce->r.blurfac == 0.0f)
sce->r.blurfac = 1.0f;
@@ -643,8 +643,8 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *main)
}
}
- if (main->versionfile <= 163) {
- Scene *sce = main->scene.first;
+ if (bmain->versionfile <= 163) {
+ Scene *sce = bmain->scene.first;
while (sce) {
if (sce->r.frs_sec == 0)
sce->r.frs_sec = 25;
@@ -652,16 +652,16 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *main)
}
}
- if (main->versionfile <= 164) {
- Mesh *me = main->mesh.first;
+ if (bmain->versionfile <= 164) {
+ Mesh *me = bmain->mesh.first;
while (me) {
me->smoothresh = 30;
me = me->id.next;
}
}
- if (main->versionfile <= 165) {
- Mesh *me = main->mesh.first;
+ if (bmain->versionfile <= 165) {
+ Mesh *me = bmain->mesh.first;
TFace *tface;
int nr;
char *cp;
@@ -687,8 +687,8 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *main)
}
}
- if (main->versionfile <= 169) {
- Mesh *me = main->mesh.first;
+ if (bmain->versionfile <= 169) {
+ Mesh *me = bmain->mesh.first;
while (me) {
if (me->subdiv == 0)
me->subdiv = 1;
@@ -696,8 +696,8 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *main)
}
}
- if (main->versionfile <= 169) {
- bScreen *sc = main->screen.first;
+ if (bmain->versionfile <= 169) {
+ bScreen *sc = bmain->screen.first;
while (sc) {
ScrArea *sa = sc->areabase.first;
while (sa) {
@@ -715,8 +715,8 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *main)
}
}
- if (main->versionfile <= 170) {
- Object *ob = main->object.first;
+ if (bmain->versionfile <= 170) {
+ Object *ob = bmain->object.first;
PartEff *paf;
while (ob) {
paf = blo_do_version_give_parteff_245(ob);
@@ -729,8 +729,8 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *main)
}
}
- if (main->versionfile <= 171) {
- bScreen *sc = main->screen.first;
+ if (bmain->versionfile <= 171) {
+ bScreen *sc = bmain->screen.first;
while (sc) {
ScrArea *sa = sc->areabase.first;
while (sa) {
@@ -748,9 +748,9 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *main)
}
}
- if (main->versionfile <= 173) {
+ if (bmain->versionfile <= 173) {
int a, b;
- Mesh *me = main->mesh.first;
+ Mesh *me = bmain->mesh.first;
while (me) {
if (me->tface) {
TFace *tface = me->tface;
@@ -765,10 +765,10 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *main)
}
}
- if (main->versionfile <= 204) {
+ if (bmain->versionfile <= 204) {
bSound *sound;
- sound = main->sound.first;
+ sound = bmain->sound.first;
while (sound) {
if (sound->volume < 0.01f) {
sound->volume = 1.0f;
@@ -777,11 +777,11 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *main)
}
}
- if (main->versionfile <= 212) {
+ if (bmain->versionfile <= 212) {
bSound *sound;
Mesh *me;
- sound = main->sound.first;
+ sound = bmain->sound.first;
while (sound) {
sound->max_gain = 1.0;
sound->min_gain = 0.0;
@@ -800,7 +800,7 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *main)
* it a subsurf, and reset the subdiv level because subsurf
* takes a lot more work to calculate.
*/
- for (me = main->mesh.first; me; me = me->id.next) {
+ for (me = bmain->mesh.first; me; me = me->id.next) {
if (me->flag & ME_SMESH) {
me->flag &= ~ME_SMESH;
me->flag |= ME_SUBSURF;
@@ -816,14 +816,14 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *main)
}
}
- if (main->versionfile <= 220) {
+ if (bmain->versionfile <= 220) {
Mesh *me;
/* Began using alpha component of vertex colors, but
* old file vertex colors are undefined, reset them
* to be fully opaque. -zr
*/
- for (me = main->mesh.first; me; me = me->id.next) {
+ for (me = bmain->mesh.first; me; me = me->id.next) {
if (me->mcol) {
int i;
@@ -848,22 +848,22 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *main)
}
}
- if (main->versionfile <= 223) {
+ if (bmain->versionfile <= 223) {
VFont *vf;
- for (vf = main->vfont.first; vf; vf = vf->id.next) {
+ for (vf = bmain->vfont.first; vf; vf = vf->id.next) {
if (STREQ(vf->name + strlen(vf->name) - 6, ".Bfont")) {
strcpy(vf->name, FO_BUILTIN_NAME);
}
}
}
- if (main->versionfile <= 224) {
+ if (bmain->versionfile <= 224) {
bSound *sound;
Scene *sce;
Mesh *me;
bScreen *sc;
- for (sound = main->sound.first; sound; sound = sound->id.next) {
+ for (sound = bmain->sound.first; sound; sound = sound->id.next) {
if (sound->packedfile) {
if (sound->newpackedfile == NULL) {
sound->newpackedfile = sound->packedfile;
@@ -872,17 +872,17 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *main)
}
}
/* Make sure that old subsurf meshes don't have zero subdivision level for rendering */
- for (me = main->mesh.first; me; me = me->id.next) {
+ for (me = bmain->mesh.first; me; me = me->id.next) {
if ((me->flag & ME_SUBSURF) && (me->subdivr == 0))
me->subdivr = me->subdiv;
}
- for (sce = main->scene.first; sce; sce = sce->id.next) {
+ for (sce = bmain->scene.first; sce; sce = sce->id.next) {
sce->r.stereomode = 1; // no stereo
}
/* some oldfile patch, moved from set_func_space */
- for (sc = main->screen.first; sc; sc = sc->id.next) {
+ for (sc = bmain->screen.first; sc; sc = sc->id.next) {
ScrArea *sa;
for (sa = sc->areabase.first; sa; sa = sa->next) {
@@ -898,7 +898,7 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *main)
}
}
- if (main->versionfile <= 227) {
+ if (bmain->versionfile <= 227) {
Scene *sce;
bScreen *sc;
Object *ob;
@@ -906,7 +906,7 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *main)
/* As of now, this insures that the transition from the old Track system
* to the new full constraint Track is painless for everyone. - theeth
*/
- ob = main->object.first;
+ ob = bmain->object.first;
while (ob) {
ListBase *list;
@@ -949,13 +949,13 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *main)
ob = ob->id.next;
}
- for (sce = main->scene.first; sce; sce = sce->id.next) {
+ for (sce = bmain->scene.first; sce; sce = sce->id.next) {
sce->audio.mixrate = 48000;
sce->audio.flag |= AUDIO_SCRUB;
}
/* patch for old wrong max view2d settings, allows zooming out more */
- for (sc = main->screen.first; sc; sc = sc->id.next) {
+ for (sc = bmain->screen.first; sc; sc = sc->id.next) {
ScrArea *sa;
for (sa = sc->areabase.first; sa; sa = sa->next) {
@@ -975,14 +975,14 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *main)
}
}
- if (main->versionfile <= 228) {
+ if (bmain->versionfile <= 228) {
bScreen *sc;
Object *ob;
/* As of now, this insures that the transition from the old Track system
* to the new full constraint Track is painless for everyone.
*/
- ob = main->object.first;
+ ob = bmain->object.first;
while (ob) {
ListBase *list;
@@ -1022,7 +1022,7 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *main)
}
/* convert old mainb values for new button panels */
- for (sc = main->screen.first; sc; sc = sc->id.next) {
+ for (sc = bmain->screen.first; sc; sc = sc->id.next) {
ScrArea *sa;
for (sa = sc->areabase.first; sa; sa = sa->next) {
@@ -1089,11 +1089,11 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *main)
* check apart from the do_versions()
*/
- if (main->versionfile <= 230) {
+ if (bmain->versionfile <= 230) {
bScreen *sc;
/* new variable blockscale, for panels in any area */
- for (sc = main->screen.first; sc; sc = sc->id.next) {
+ for (sc = bmain->screen.first; sc; sc = sc->id.next) {
ScrArea *sa;
for (sa = sc->areabase.first; sa; sa = sa->next) {
@@ -1110,9 +1110,9 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *main)
}
}
- if (main->versionfile <= 231) {
+ if (bmain->versionfile <= 231) {
/* new bit flags for showing/hiding grid floor and axes */
- bScreen *sc = main->screen.first;
+ bScreen *sc = bmain->screen.first;
while (sc) {
ScrArea *sa = sc->areabase.first;
@@ -1137,8 +1137,8 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *main)
}
}
- if (main->versionfile <= 231) {
- bScreen *sc = main->screen.first;
+ if (bmain->versionfile <= 231) {
+ bScreen *sc = bmain->screen.first;
/* new bit flags for showing/hiding grid floor and axes */
@@ -1165,9 +1165,9 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *main)
}
}
- if (main->versionfile <= 232) {
- Tex *tex = main->tex.first;
- World *wrld = main->world.first;
+ if (bmain->versionfile <= 232) {
+ Tex *tex = bmain->tex.first;
+ World *wrld = bmain->world.first;
bScreen *sc;
while (tex) {
@@ -1204,7 +1204,7 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *main)
/* new variable blockscale, for panels in any area, do again because new
* areas didnt initialize it to 0.7 yet
*/
- for (sc = main->screen.first; sc; sc = sc->id.next) {
+ for (sc = bmain->screen.first; sc; sc = sc->id.next) {
ScrArea *sa;
for (sa = sc->areabase.first; sa; sa = sa->next) {
SpaceLink *sl;
@@ -1219,10 +1219,10 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *main)
}
}
- if (main->versionfile <= 233) {
+ if (bmain->versionfile <= 233) {
bScreen *sc;
- Material *ma = main->mat.first;
- /* Object *ob = main->object.first; */
+ Material *ma = bmain->mat.first;
+ /* Object *ob = bmain->object.first; */
while (ma) {
if (ma->pr_lamp == 0)
@@ -1230,7 +1230,7 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *main)
ma = ma->id.next;
}
- for (sc = main->screen.first; sc; sc = sc->id.next) {
+ for (sc = bmain->screen.first; sc; sc = sc->id.next) {
ScrArea *sa;
for (sa = sc->areabase.first; sa; sa = sa->next) {
SpaceLink *sl;
@@ -1244,10 +1244,10 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *main)
}
}
- if (main->versionfile <= 234) {
+ if (bmain->versionfile <= 234) {
bScreen *sc;
- for (sc = main->screen.first; sc; sc = sc->id.next) {
+ for (sc = bmain->screen.first; sc; sc = sc->id.next) {
ScrArea *sa;
for (sa = sc->areabase.first; sa; sa = sa->next) {
SpaceLink *sl;
@@ -1266,9 +1266,9 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *main)
}
}
- if (main->versionfile <= 235) {
- Tex *tex = main->tex.first;
- Scene *sce = main->scene.first;
+ if (bmain->versionfile <= 235) {
+ Tex *tex = bmain->tex.first;
+ Scene *sce = bmain->scene.first;
Sequence *seq;
Editing *ed;
@@ -1292,9 +1292,9 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *main)
}
}
- if (main->versionfile <= 236) {
+ if (bmain->versionfile <= 236) {
Object *ob;
- Camera *cam = main->camera.first;
+ Camera *cam = bmain->camera.first;
while (cam) {
if (cam->ortho_scale == 0.0f) {
@@ -1308,7 +1308,7 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *main)
/* set time line var */
/* softbody init new vars */
- for (ob = main->object.first; ob; ob = ob->id.next) {
+ for (ob = bmain->object.first; ob; ob = ob->id.next) {
if (ob->soft) {
if (ob->soft->defgoal == 0.0f)
ob->soft->defgoal = 0.7f;
@@ -1331,20 +1331,20 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *main)
}
}
- if (main->versionfile <= 237) {
+ if (bmain->versionfile <= 237) {
bArmature *arm;
bConstraint *con;
Object *ob;
Bone *bone;
/* armature recode checks */
- for (arm = main->armature.first; arm; arm = arm->id.next) {
+ for (arm = bmain->armature.first; arm; arm = arm->id.next) {
BKE_armature_where_is(arm);
for (bone = arm->bonebase.first; bone; bone = bone->next)
do_version_bone_head_tail_237(bone);
}
- for (ob = main->object.first; ob; ob = ob->id.next) {
+ for (ob = bmain->object.first; ob; ob = ob->id.next) {
if (ob->parent) {
Object *parent = blo_do_versions_newlibadr(fd, lib, ob->parent);
if (parent && parent->type == OB_LATTICE)
@@ -1354,7 +1354,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)
- BKE_pose_tag_recalc(main, ob->pose);
+ BKE_pose_tag_recalc(bmain, ob->pose);
/* cannot call stuff now (pointers!), done in setup_app_data */
ob->id.recalc |= ID_RECALC_ALL;
@@ -1405,13 +1405,13 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *main)
}
}
- if (main->versionfile <= 238) {
+ if (bmain->versionfile <= 238) {
Lattice *lt;
Object *ob;
bArmature *arm;
Mesh *me;
Key *key;
- Scene *sce = main->scene.first;
+ Scene *sce = bmain->scene.first;
while (sce) {
if (sce->toolsettings == NULL) {
@@ -1421,7 +1421,7 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *main)
sce = sce->id.next;
}
- for (lt = main->latt.first; lt; lt = lt->id.next) {
+ for (lt = bmain->latt.first; lt; lt = lt->id.next) {
if (lt->fu == 0.0f && lt->fv == 0.0f && lt->fw == 0.0f) {
calc_lat_fudu(lt->flag, lt->pntsu, &lt->fu, &lt->du);
calc_lat_fudu(lt->flag, lt->pntsv, &lt->fv, &lt->dv);
@@ -1429,7 +1429,7 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *main)
}
}
- for (ob = main->object.first; ob; ob = ob->id.next) {
+ for (ob = bmain->object.first; ob; ob = ob->id.next) {
ModifierData *md;
PartEff *paf;
@@ -1478,7 +1478,7 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *main)
data->rootbone = -1;
/* update_pose_etc handles rootbone == -1 */
- BKE_pose_tag_recalc(main, ob->pose);
+ BKE_pose_tag_recalc(bmain, ob->pose);
}
}
}
@@ -1496,12 +1496,12 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *main)
}
}
- for (arm = main->armature.first; arm; arm = arm->id.next) {
+ for (arm = bmain->armature.first; arm; arm = arm->id.next) {
bone_version_238(&arm->bonebase);
arm->deformflag |= ARM_DEF_VGROUP;
}
- for (me = main->mesh.first; me; me = me->id.next) {
+ for (me = bmain->mesh.first; me; me = me->id.next) {
if (!me->medge) {
BKE_mesh_calc_edges_legacy(me, true); /* true = use mface->edcode */
}
@@ -1510,7 +1510,7 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *main)
}
}
- for (key = main->key.first; key; key = key->id.next) {
+ for (key = bmain->key.first; key; key = key->id.next) {
KeyBlock *kb;
int index = 1;
@@ -1529,15 +1529,15 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *main)
}
}
- if (main->versionfile <= 239) {
+ if (bmain->versionfile <= 239) {
bArmature *arm;
Object *ob;
- Scene *sce = main->scene.first;
- Camera *cam = main->camera.first;
+ Scene *sce = bmain->scene.first;
+ Camera *cam = bmain->camera.first;
int set_passepartout = 0;
/* deformflag is local in modifier now */
- for (ob = main->object.first; ob; ob = ob->id.next) {
+ for (ob = bmain->object.first; ob; ob = ob->id.next) {
ModifierData *md;
for (md = ob->modifiers.first; md; md = md->next) {
@@ -1553,7 +1553,7 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *main)
}
/* updating stepsize for ghost drawing */
- for (arm = main->armature.first; arm; arm = arm->id.next) {
+ for (arm = bmain->armature.first; arm; arm = arm->id.next) {
if (arm->ghostsize == 0)
arm->ghostsize = 1;
bone_version_239(&arm->bonebase);
@@ -1582,7 +1582,7 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *main)
}
}
- if (main->versionfile <= 241) {
+ if (bmain->versionfile <= 241) {
Object *ob;
Scene *sce;
Lamp *la;
@@ -1590,12 +1590,12 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *main)
bNodeTree *ntree;
/* updating layers still */
- for (arm = main->armature.first; arm; arm = arm->id.next) {
+ for (arm = bmain->armature.first; arm; arm = arm->id.next) {
bone_version_239(&arm->bonebase);
if (arm->layer == 0)
arm->layer = 1;
}
- for (sce = main->scene.first; sce; sce = sce->id.next) {
+ for (sce = bmain->scene.first; sce; sce = sce->id.next) {
if (sce->audio.mixrate == 0)
sce->audio.mixrate = 48000;
@@ -1622,15 +1622,15 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *main)
}
}
- for (ntree = main->nodetree.first; ntree; ntree = ntree->id.next)
+ for (ntree = bmain->nodetree.first; ntree; ntree = ntree->id.next)
ntree_version_241(ntree);
- for (la = main->lamp.first; la; la = la->id.next)
+ for (la = bmain->lamp.first; la; la = la->id.next)
if (la->buffers == 0)
la->buffers = 1;
/* for empty drawsize and drawtype */
- for (ob = main->object.first; ob; ob = ob->id.next) {
+ for (ob = bmain->object.first; ob; ob = ob->id.next) {
if (ob->empty_drawsize == 0.0f) {
ob->empty_drawtype = OB_ARROWS;
ob->empty_drawsize = 1.0;
@@ -1638,9 +1638,9 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *main)
}
/* during 2.41 images with this name were used for viewer node output, lets fix that */
- if (main->versionfile == 241) {
+ if (bmain->versionfile == 241) {
Image *ima;
- for (ima = main->image.first; ima; ima = ima->id.next) {
+ for (ima = bmain->image.first; ima; ima = ima->id.next) {
if (STREQ(ima->name, "Compositor")) {
strcpy(ima->id.name + 2, "Viewer Node");
strcpy(ima->name, "Viewer Node");
@@ -1649,7 +1649,7 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *main)
}
}
- if (main->versionfile <= 242) {
+ if (bmain->versionfile <= 242) {
Scene *sce;
bScreen *sc;
Object *ob;
@@ -1663,7 +1663,7 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *main)
bNodeTree *ntree;
int a;
- for (sc = main->screen.first; sc; sc = sc->id.next) {
+ for (sc = bmain->screen.first; sc; sc = sc->id.next) {
ScrArea *sa;
sa = sc->areabase.first;
while (sa) {
@@ -1680,7 +1680,7 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *main)
}
}
- for (sce = main->scene.first; sce; sce = sce->id.next) {
+ for (sce = bmain->scene.first; sce; sce = sce->id.next) {
if (sce->toolsettings->select_thresh == 0.0f)
sce->toolsettings->select_thresh = 0.01f;
@@ -1694,11 +1694,11 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *main)
ntree_version_242(sce->nodetree);
}
- for (ntree = main->nodetree.first; ntree; ntree = ntree->id.next)
+ for (ntree = bmain->nodetree.first; ntree; ntree = ntree->id.next)
ntree_version_242(ntree);
/* add default radius values to old curve points */
- for (cu = main->curve.first; cu; cu = cu->id.next) {
+ for (cu = bmain->curve.first; cu; cu = cu->id.next) {
for (nu = cu->nurb.first; nu; nu = nu->next) {
if (nu) {
if (nu->bezt) {
@@ -1717,7 +1717,7 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *main)
}
}
- for (ob = main->object.first; ob; ob = ob->id.next) {
+ for (ob = bmain->object.first; ob; ob = ob->id.next) {
ModifierData *md;
ListBase *list;
list = &ob->constraints;
@@ -1805,25 +1805,25 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *main)
}
- for (ma = main->mat.first; ma; ma = ma->id.next) {
+ for (ma = bmain->mat.first; ma; ma = ma->id.next) {
if (ma->nodetree)
ntree_version_242(ma->nodetree);
}
- for (me = main->mesh.first; me; me = me->id.next)
+ for (me = bmain->mesh.first; me; me = me->id.next)
customdata_version_242(me);
- for (collection = main->collection.first; collection; collection = collection->id.next)
+ for (collection = bmain->collection.first; collection; collection = collection->id.next)
if (collection->layer == 0)
collection->layer = (1 << 20) - 1;
/* now, subversion control! */
- if (main->subversionfile < 3) {
+ if (bmain->subversionfile < 3) {
Image *ima;
Tex *tex;
/* Image refactor initialize */
- for (ima = main->image.first; ima; ima = ima->id.next) {
+ for (ima = bmain->image.first; ima; ima = ima->id.next) {
ima->source = IMA_SRC_FILE;
ima->type = IMA_TYPE_IMAGE;
@@ -1840,7 +1840,7 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *main)
}
}
- for (tex = main->tex.first; tex; tex = tex->id.next) {
+ for (tex = bmain->tex.first; tex; tex = tex->id.next) {
if (tex->type == TEX_IMAGE && tex->ima) {
ima = blo_do_versions_newlibadr(fd, lib, tex->ima);
if (tex->imaflag & TEX_ANIM5_)
@@ -1856,17 +1856,17 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *main)
tex->iuser.sfra = tex->sfra;
tex->iuser.cycl = (tex->imaflag & TEX_ANIMCYCLIC_)!=0;
}
- for (sce = main->scene.first; sce; sce = sce->id.next) {
+ for (sce = bmain->scene.first; sce; sce = sce->id.next) {
if (sce->nodetree)
do_version_ntree_242_2(sce->nodetree);
}
- for (ntree = main->nodetree.first; ntree; ntree = ntree->id.next)
+ for (ntree = bmain->nodetree.first; ntree; ntree = ntree->id.next)
do_version_ntree_242_2(ntree);
- for (ma = main->mat.first; ma; ma = ma->id.next)
+ for (ma = bmain->mat.first; ma; ma = ma->id.next)
if (ma->nodetree)
do_version_ntree_242_2(ma->nodetree);
- for (sc = main->screen.first; sc; sc = sc->id.next) {
+ for (sc = bmain->screen.first; sc; sc = sc->id.next) {
ScrArea *sa;
for (sa = sc->areabase.first; sa; sa = sa->next) {
SpaceLink *sl;
@@ -1879,8 +1879,8 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *main)
}
}
- if (main->subversionfile < 4) {
- for (sce = main->scene.first; sce; sce = sce->id.next) {
+ if (bmain->subversionfile < 4) {
+ for (sce = bmain->scene.first; sce; sce = sce->id.next) {
sce->r.bake_mode = 1; /* prevent to include render stuff here */
sce->r.bake_filter = 16;
sce->r.bake_flag = R_BAKE_CLEAR;
@@ -1888,8 +1888,8 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *main)
}
}
- if (main->versionfile <= 243) {
- Object *ob = main->object.first;
+ if (bmain->versionfile <= 243) {
+ Object *ob = bmain->object.first;
for (; ob; ob = ob->id.next) {
bDeformGroup *curdef;
@@ -1901,7 +1901,7 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *main)
}
}
- if (main->versionfile < 243 || main->subversionfile < 1) {
+ if (bmain->versionfile < 243 || bmain->subversionfile < 1) {
ModifierData *md;
/* translate old mirror modifier axis values to new flags */
@@ -1928,20 +1928,20 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *main)
}
/* render layer added, this is not the active layer */
- if (main->versionfile <= 243 || main->subversionfile < 2) {
+ if (bmain->versionfile <= 243 || bmain->subversionfile < 2) {
Mesh *me;
- for (me = main->mesh.first; me; me = me->id.next)
+ for (me = bmain->mesh.first; me; me = me->id.next)
customdata_version_243(me);
}
}
- if (main->versionfile <= 244) {
+ if (bmain->versionfile <= 244) {
bScreen *sc;
- if (main->versionfile != 244 || main->subversionfile < 2) {
+ if (bmain->versionfile != 244 || bmain->subversionfile < 2) {
/* correct older action editors - incorrect scrolling */
- for (sc = main->screen.first; sc; sc = sc->id.next) {
+ for (sc = bmain->screen.first; sc; sc = sc->id.next) {
ScrArea *sa;
sa = sc->areabase.first;
while (sa) {
@@ -1964,7 +1964,7 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *main)
}
}
- if (main->versionfile <= 245) {
+ if (bmain->versionfile <= 245) {
Scene *sce;
Object *ob;
Image *ima;
@@ -1978,10 +1978,10 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *main)
ParticleSystem *psys;
/* unless the file was created 2.44.3 but not 2.45, update the constraints */
- if (!(main->versionfile == 244 && main->subversionfile == 3) &&
- ((main->versionfile < 245) || (main->versionfile == 245 && main->subversionfile == 0)) )
+ if (!(bmain->versionfile == 244 && bmain->subversionfile == 3) &&
+ ((bmain->versionfile < 245) || (bmain->versionfile == 245 && bmain->subversionfile == 0)) )
{
- for (ob = main->object.first; ob; ob = ob->id.next) {
+ for (ob = bmain->object.first; ob; ob = ob->id.next) {
ListBase *list;
list = &ob->constraints;
@@ -2048,16 +2048,16 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *main)
}
/* fix all versions before 2.45 */
- if (main->versionfile != 245) {
+ if (bmain->versionfile != 245) {
/* repair preview from 242 - 244*/
- for (ima = main->image.first; ima; ima = ima->id.next) {
+ for (ima = bmain->image.first; ima; ima = ima->id.next) {
ima->preview = NULL;
}
}
/* add point caches */
- for (ob = main->object.first; ob; ob = ob->id.next) {
+ for (ob = bmain->object.first; ob; ob = ob->id.next) {
if (ob->soft && !ob->soft->pointcache)
ob->soft->pointcache = BKE_ptcache_add(&ob->soft->ptcaches);
@@ -2085,7 +2085,7 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *main)
/* Copy over old per-level multires vertex data
* into a single vertex array in struct Multires */
- for (me = main->mesh.first; me; me = me->id.next) {
+ for (me = bmain->mesh.first; me; me = me->id.next) {
if (me->mr && !me->mr->verts) {
MultiresLevel *lvl = me->mr->levels.last;
if (lvl) {
@@ -2100,8 +2100,8 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *main)
}
}
- if (main->versionfile != 245 || main->subversionfile < 1) {
- for (la = main->lamp.first; la; la = la->id.next) {
+ if (bmain->versionfile != 245 || bmain->subversionfile < 1) {
+ for (la = bmain->lamp.first; la; la = la->id.next) {
la->falloff_type = LA_FALLOFF_INVLINEAR;
if (la->curfalloff == NULL) {
@@ -2111,18 +2111,18 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *main)
}
}
- for (ma = main->mat.first; ma; ma = ma->id.next) {
+ for (ma = bmain->mat.first; ma; ma = ma->id.next) {
if (ma->gloss_mir == 0.0f) {
ma->gloss_mir = 1.0f;
}
}
- for (part = main->particle.first; part; part = part->id.next) {
+ for (part = bmain->particle.first; part; part = part->id.next) {
if (part->ren_child_nbr == 0)
part->ren_child_nbr = part->child_nbr;
}
- for (sce = main->scene.first; sce; sce = sce->id.next) {
+ for (sce = bmain->scene.first; sce; sce = sce->id.next) {
if (sce->nodetree)
ntree_version_245(fd, lib, sce->nodetree);
@@ -2132,18 +2132,18 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *main)
}
}
- for (ntree = main->nodetree.first; ntree; ntree = ntree->id.next)
+ for (ntree = bmain->nodetree.first; ntree; ntree = ntree->id.next)
ntree_version_245(fd, lib, ntree);
/* fix for temporary flag changes during 245 cycle */
- for (ima = main->image.first; ima; ima = ima->id.next) {
+ for (ima = bmain->image.first; ima; ima = ima->id.next) {
if (ima->flag & IMA_OLD_PREMUL) {
ima->flag &= ~IMA_OLD_PREMUL;
ima->alpha_mode = IMA_ALPHA_STRAIGHT;
}
}
- for (tex = main->tex.first; tex; tex = tex->id.next) {
+ for (tex = bmain->tex.first; tex; tex = tex->id.next) {
if (tex->iuser.flag & IMA_OLD_PREMUL) {
tex->iuser.flag &= ~IMA_OLD_PREMUL;
}
@@ -2156,24 +2156,24 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *main)
}
}
- if ((main->versionfile < 245) || (main->versionfile == 245 && main->subversionfile < 2)) {
+ if ((bmain->versionfile < 245) || (bmain->versionfile == 245 && bmain->subversionfile < 2)) {
Image *ima;
/* initialize 1:1 Aspect */
- for (ima = main->image.first; ima; ima = ima->id.next) {
+ for (ima = bmain->image.first; ima; ima = ima->id.next) {
ima->aspx = ima->aspy = 1.0f;
}
}
- if ((main->versionfile < 245) || (main->versionfile == 245 && main->subversionfile < 4)) {
+ if ((bmain->versionfile < 245) || (bmain->versionfile == 245 && bmain->subversionfile < 4)) {
bArmature *arm;
ModifierData *md;
Object *ob;
- for (arm = main->armature.first; arm; arm = arm->id.next)
+ for (arm = bmain->armature.first; arm; arm = arm->id.next)
arm->deformflag |= ARM_DEF_B_BONE_REST;
- for (ob = main->object.first; ob; ob = ob->id.next) {
+ for (ob = bmain->object.first; ob; ob = ob->id.next) {
for (md = ob->modifiers.first; md; md = md->next) {
if (md->type == eModifierType_Armature)
((ArmatureModifierData*) md)->deformflag |= ARM_DEF_B_BONE_REST;
@@ -2181,10 +2181,10 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *main)
}
}
- if ((main->versionfile < 245) || (main->versionfile == 245 && main->subversionfile < 5)) {
+ if ((bmain->versionfile < 245) || (bmain->versionfile == 245 && bmain->subversionfile < 5)) {
/* foreground color needs to be something other then black */
Scene *sce;
- for (sce = main->scene.first; sce; sce = sce->id.next) {
+ for (sce = bmain->scene.first; sce; sce = sce->id.next) {
sce->r.fg_stamp[0] = sce->r.fg_stamp[1] = sce->r.fg_stamp[2] = 0.8f;
sce->r.fg_stamp[3] = 1.0f; /* don't use text alpha yet */
sce->r.bg_stamp[3] = 0.25f; /* make sure the background has full alpha */
@@ -2192,21 +2192,21 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *main)
}
- if ((main->versionfile < 245) || (main->versionfile == 245 && main->subversionfile < 6)) {
+ if ((bmain->versionfile < 245) || (bmain->versionfile == 245 && bmain->subversionfile < 6)) {
Scene *sce;
/* fix frs_sec_base */
- for (sce = main->scene.first; sce; sce = sce->id.next) {
+ for (sce = bmain->scene.first; sce; sce = sce->id.next) {
if (sce->r.frs_sec_base == 0) {
sce->r.frs_sec_base = 1;
}
}
}
- if ((main->versionfile < 245) || (main->versionfile == 245 && main->subversionfile < 7)) {
+ if ((bmain->versionfile < 245) || (bmain->versionfile == 245 && bmain->subversionfile < 7)) {
Object *ob;
bPoseChannel *pchan;
- for (ob = main->object.first; ob; ob = ob->id.next) {
+ for (ob = bmain->object.first; ob; ob = ob->id.next) {
if (ob->pose) {
for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
do_version_constraints_245(&pchan->constraints);
@@ -2231,12 +2231,12 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *main)
}
}
- if ((main->versionfile < 245) || (main->versionfile == 245 && main->subversionfile < 8)) {
+ if ((bmain->versionfile < 245) || (bmain->versionfile == 245 && bmain->subversionfile < 8)) {
Scene *sce;
Object *ob;
PartEff *paf = NULL;
- for (ob = main->object.first; ob; ob = ob->id.next) {
+ for (ob = bmain->object.first; ob; ob = ob->id.next) {
if (ob->soft && ob->soft->keys) {
SoftBody *sb = ob->soft;
int k;
@@ -2263,7 +2263,7 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *main)
psys = MEM_callocN(sizeof(ParticleSystem), "particle_system");
psys->pointcache = BKE_ptcache_add(&psys->ptcaches);
- part = psys->part = BKE_particlesettings_add(main, "ParticleSettings");
+ part = psys->part = BKE_particlesettings_add(bmain, "ParticleSettings");
/* needed for proper libdata lookup */
blo_do_versions_oldnewmap_insert(fd->libmap, psys->part, psys->part, 0);
@@ -2343,7 +2343,7 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *main)
/* dupliobjects */
if (ob->transflag & OB_DUPLIVERTS) {
- Object *dup = main->object.first;
+ Object *dup = bmain->object.first;
for (; dup; dup = dup->id.next) {
if (ob == blo_do_versions_newlibadr(fd, lib, dup->parent)) {
@@ -2371,7 +2371,7 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *main)
}
}
- for (sce = main->scene.first; sce; sce = sce->id.next) {
+ for (sce = bmain->scene.first; sce; sce = sce->id.next) {
ParticleEditSettings *pset = &sce->toolsettings->particle;
int a;
@@ -2393,20 +2393,20 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *main)
}
}
- if ((main->versionfile < 245) || (main->versionfile == 245 && main->subversionfile < 10)) {
+ if ((bmain->versionfile < 245) || (bmain->versionfile == 245 && bmain->subversionfile < 10)) {
Object *ob;
/* dupliface scale */
- for (ob = main->object.first; ob; ob = ob->id.next)
+ for (ob = bmain->object.first; ob; ob = ob->id.next)
ob->dupfacesca = 1.0f;
}
- if ((main->versionfile < 245) || (main->versionfile == 245 && main->subversionfile < 11)) {
+ if ((bmain->versionfile < 245) || (bmain->versionfile == 245 && bmain->subversionfile < 11)) {
Object *ob;
bActionStrip *strip;
/* nla-strips - scale */
- for (ob = main->object.first; ob; ob = ob->id.next) {
+ for (ob = bmain->object.first; ob; ob = ob->id.next) {
for (strip = ob->nlastrips.first; strip; strip = strip->next) {
float length, actlength, repeat;
@@ -2431,11 +2431,11 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *main)
}
}
- if ((main->versionfile < 245) || (main->versionfile == 245 && main->subversionfile < 14)) {
+ if ((bmain->versionfile < 245) || (bmain->versionfile == 245 && bmain->subversionfile < 14)) {
Scene *sce;
Sequence *seq;
- for (sce = main->scene.first; sce; sce = sce->id.next) {
+ for (sce = bmain->scene.first; sce; sce = sce->id.next) {
SEQ_BEGIN (sce->ed, seq)
{
if (seq->blend_mode == 0)
@@ -2446,39 +2446,39 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *main)
}
/* fix broken group lengths in id properties */
- if ((main->versionfile < 245) || (main->versionfile == 245 && main->subversionfile < 15)) {
- idproperties_fix_group_lengths(main->scene);
- idproperties_fix_group_lengths(main->library);
- idproperties_fix_group_lengths(main->object);
- idproperties_fix_group_lengths(main->mesh);
- idproperties_fix_group_lengths(main->curve);
- idproperties_fix_group_lengths(main->mball);
- idproperties_fix_group_lengths(main->mat);
- idproperties_fix_group_lengths(main->tex);
- idproperties_fix_group_lengths(main->image);
- idproperties_fix_group_lengths(main->latt);
- idproperties_fix_group_lengths(main->lamp);
- idproperties_fix_group_lengths(main->camera);
- idproperties_fix_group_lengths(main->ipo);
- idproperties_fix_group_lengths(main->key);
- idproperties_fix_group_lengths(main->world);
- idproperties_fix_group_lengths(main->screen);
- idproperties_fix_group_lengths(main->vfont);
- idproperties_fix_group_lengths(main->text);
- idproperties_fix_group_lengths(main->sound);
- idproperties_fix_group_lengths(main->collection);
- idproperties_fix_group_lengths(main->armature);
- idproperties_fix_group_lengths(main->action);
- idproperties_fix_group_lengths(main->nodetree);
- idproperties_fix_group_lengths(main->brush);
- idproperties_fix_group_lengths(main->particle);
+ if ((bmain->versionfile < 245) || (bmain->versionfile == 245 && bmain->subversionfile < 15)) {
+ idproperties_fix_group_lengths(bmain->scene);
+ idproperties_fix_group_lengths(bmain->library);
+ idproperties_fix_group_lengths(bmain->object);
+ idproperties_fix_group_lengths(bmain->mesh);
+ idproperties_fix_group_lengths(bmain->curve);
+ idproperties_fix_group_lengths(bmain->mball);
+ idproperties_fix_group_lengths(bmain->mat);
+ idproperties_fix_group_lengths(bmain->tex);
+ idproperties_fix_group_lengths(bmain->image);
+ idproperties_fix_group_lengths(bmain->latt);
+ idproperties_fix_group_lengths(bmain->lamp);
+ idproperties_fix_group_lengths(bmain->camera);
+ idproperties_fix_group_lengths(bmain->ipo);
+ idproperties_fix_group_lengths(bmain->key);
+ idproperties_fix_group_lengths(bmain->world);
+ idproperties_fix_group_lengths(bmain->screen);
+ idproperties_fix_group_lengths(bmain->vfont);
+ idproperties_fix_group_lengths(bmain->text);
+ idproperties_fix_group_lengths(bmain->sound);
+ idproperties_fix_group_lengths(bmain->collection);
+ idproperties_fix_group_lengths(bmain->armature);
+ idproperties_fix_group_lengths(bmain->action);
+ idproperties_fix_group_lengths(bmain->nodetree);
+ idproperties_fix_group_lengths(bmain->brush);
+ idproperties_fix_group_lengths(bmain->particle);
}
/* convert fluids to modifier */
- if (main->versionfile < 246 || (main->versionfile == 246 && main->subversionfile < 1)) {
+ if (bmain->versionfile < 246 || (bmain->versionfile == 246 && bmain->subversionfile < 1)) {
Object *ob;
- for (ob = main->object.first; ob; ob = ob->id.next) {
+ for (ob = bmain->object.first; ob; ob = ob->id.next) {
if (ob->fluidsimSettings) {
FluidsimModifierData *fluidmd = (FluidsimModifierData *)modifier_new(eModifierType_Fluidsim);
BLI_addhead(&ob->modifiers, (ModifierData *)fluidmd);
@@ -2495,20 +2495,20 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *main)
}
}
- if (main->versionfile < 246 || (main->versionfile == 246 && main->subversionfile < 1)) {
+ if (bmain->versionfile < 246 || (bmain->versionfile == 246 && bmain->subversionfile < 1)) {
Object *ob;
- for (ob = main->object.first; ob; ob = ob->id.next) {
+ for (ob = bmain->object.first; ob; ob = ob->id.next) {
if (ob->pd && (ob->pd->forcefield == PFIELD_WIND))
ob->pd->f_noise = 0.0f;
}
}
/* set the curve radius interpolation to 2.47 default - easy */
- if (main->versionfile < 247 || (main->versionfile == 247 && main->subversionfile < 6)) {
+ if (bmain->versionfile < 247 || (bmain->versionfile == 247 && bmain->subversionfile < 6)) {
Curve *cu;
Nurb *nu;
- for (cu = main->curve.first; cu; cu = cu->id.next) {
+ for (cu = bmain->curve.first; cu; cu = cu->id.next) {
for (nu = cu->nurb.first; nu; nu = nu->next) {
if (nu) {
nu->radius_interp = 3;
@@ -2526,21 +2526,21 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *main)
}
}
- if (main->versionfile < 248 || (main->versionfile == 248 && main->subversionfile < 2)) {
+ if (bmain->versionfile < 248 || (bmain->versionfile == 248 && bmain->subversionfile < 2)) {
Scene *sce;
/* Note, these will need to be added for painting */
- for (sce = main->scene.first; sce; sce = sce->id.next) {
+ for (sce = bmain->scene.first; sce; sce = sce->id.next) {
sce->toolsettings->imapaint.seam_bleed = 2;
sce->toolsettings->imapaint.normal_angle = 80;
}
}
- if (main->versionfile < 248 || (main->versionfile == 248 && main->subversionfile < 3)) {
+ if (bmain->versionfile < 248 || (bmain->versionfile == 248 && bmain->subversionfile < 3)) {
bScreen *sc;
/* adjust default settings for Animation Editors */
- for (sc = main->screen.first; sc; sc = sc->id.next) {
+ for (sc = bmain->screen.first; sc; sc = sc->id.next) {
ScrArea *sa;
for (sa = sc->areabase.first; sa; sa = sa->next) {
@@ -2575,17 +2575,17 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *main)
}
/* correct introduce of seed for wind force */
- if (main->versionfile < 249 && main->subversionfile < 1) {
+ if (bmain->versionfile < 249 && bmain->subversionfile < 1) {
Object *ob;
- for (ob = main->object.first; ob; ob = ob->id.next) {
+ for (ob = bmain->object.first; ob; ob = ob->id.next) {
if (ob->pd)
ob->pd->seed = ((unsigned int)(ceil(PIL_check_seconds_timer())) + 1) % 128;
}
}
- if (main->versionfile < 249 && main->subversionfile < 2) {
- Scene *sce = main->scene.first;
+ if (bmain->versionfile < 249 && bmain->subversionfile < 2) {
+ Scene *sce = bmain->scene.first;
Sequence *seq;
Editing *ed;
diff --git a/source/blender/blenloader/intern/writefile.c b/source/blender/blenloader/intern/writefile.c
index 743125382c4..ddb0a39dc9a 100644
--- a/source/blender/blenloader/intern/writefile.c
+++ b/source/blender/blenloader/intern/writefile.c
@@ -4118,7 +4118,7 @@ bool BLO_write_file(
* we should not have any relative paths, but if there
* is somehow, an invalid or empty G.main->name it will
* print an error, don't try make the absolute in this case. */
- BKE_bpath_absolute_convert(mainvar, G.main->name, NULL);
+ BKE_bpath_absolute_convert(mainvar, BKE_main_blendfile_path_from_global(), NULL);
}
}
}
diff --git a/source/blender/bmesh/intern/bmesh_log.c b/source/blender/bmesh/intern/bmesh_log.c
index 4e6fff03411..30ab0dd9459 100644
--- a/source/blender/bmesh/intern/bmesh_log.c
+++ b/source/blender/bmesh/intern/bmesh_log.c
@@ -654,17 +654,21 @@ void BM_log_mesh_elems_reorder(BMesh *bm, BMLog *log)
*/
BMLogEntry *BM_log_entry_add(BMLog *log)
{
- BMLogEntry *entry, *next;
-
+ /* WARNING: this is now handled by the UndoSystem: BKE_UNDOSYS_TYPE_SCULPT
+ * freeing here causes unnecesssary complications. */
+ BMLogEntry *entry;
+#if 0
/* Delete any entries after the current one */
entry = log->current_entry;
if (entry) {
+ BMLogEntry *next;
for (entry = entry->next; entry; entry = next) {
next = entry->next;
bm_log_entry_free(entry);
BLI_freelinkN(&log->entries, entry);
}
}
+#endif
/* Create and append the new entry */
entry = bm_log_entry_create();
diff --git a/source/blender/bmesh/intern/bmesh_mesh_conv.c b/source/blender/bmesh/intern/bmesh_mesh_conv.c
index cf6bc0e0bac..5ba3f149689 100644
--- a/source/blender/bmesh/intern/bmesh_mesh_conv.c
+++ b/source/blender/bmesh/intern/bmesh_mesh_conv.c
@@ -88,6 +88,7 @@
#include "BLI_math_vector.h"
#include "BKE_mesh.h"
+#include "BKE_mesh_runtime.h"
#include "BKE_customdata.h"
#include "BKE_multires.h"
diff --git a/source/blender/collada/AnimationExporter.cpp b/source/blender/collada/AnimationExporter.cpp
index fc4bbea108b..95298986f5a 100644
--- a/source/blender/collada/AnimationExporter.cpp
+++ b/source/blender/collada/AnimationExporter.cpp
@@ -270,7 +270,7 @@ void AnimationExporter::export_sampled_transrotloc_animation(Object *ob, std::ve
create_sampled_animation(3, ctimes, baked_curves[SCALE], ob_name, "scale", "", false);
create_sampled_animation(3, ctimes, baked_curves[LOC], ob_name, "location", "", false);
- /* Not sure how to export rotation as a 3channel animation,
+ /* Not sure how to export rotation as a 3channel animation,
* so separate into 3 single animations for now:
*/
@@ -314,7 +314,7 @@ void AnimationExporter::operator()(Object *ob)
//This needs to be handled by extra profiles, so postponed for now
//export_morph_animation(ob);
-
+
//Export Lamp parameter animations
if ( (ob->type == OB_LAMP) && ((Lamp *)ob->data)->adt && ((Lamp *)ob->data)->adt->action) {
FCurve *fcu = (FCurve *)(((Lamp *)ob->data)->adt->action->curves.first);
@@ -338,7 +338,7 @@ void AnimationExporter::operator()(Object *ob)
if ((STREQ(transformName, "lens")) ||
(STREQ(transformName, "ortho_scale")) ||
- (STREQ(transformName, "clip_end")) ||
+ (STREQ(transformName, "clip_end")) ||
(STREQ(transformName, "clip_start")))
{
create_keyframed_animation(ob, fcu, transformName, true);
@@ -380,7 +380,7 @@ void AnimationExporter::export_object_constraint_animation(Object *ob)
}
void AnimationExporter::export_morph_animation(Object *ob)
-{
+{
FCurve *fcu;
char *transformName;
Key *key = BKE_key_from_object(ob);
@@ -388,12 +388,12 @@ void AnimationExporter::export_morph_animation(Object *ob)
if (key->adt && key->adt->action) {
fcu = (FCurve *)key->adt->action->curves.first;
-
+
while (fcu) {
transformName = extract_transform_name(fcu->rna_path);
create_keyframed_animation(ob, fcu, transformName, true);
-
+
fcu = fcu->next;
}
}
@@ -407,17 +407,17 @@ void AnimationExporter::make_anim_frames_from_targets(Object *ob, std::vector<fl
bConstraint *con;
for (con = (bConstraint *)conlist->first; con; con = con->next) {
ListBase targets = {NULL, NULL};
-
+
const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
-
+
if (!validateConstraints(con)) continue;
if (cti && cti->get_constraint_targets) {
bConstraintTarget *ct;
Object *obtar;
- /* get targets
+ /* get targets
* - constraints should use ct->matrix, not directly accessing values
- * - ct->matrix members have not yet been calculated here!
+ * - ct->matrix members have not yet been calculated here!
*/
cti->get_constraint_targets(con, &targets);
@@ -438,7 +438,7 @@ void AnimationExporter::make_anim_frames_from_targets(Object *ob, std::vector<fl
float *AnimationExporter::get_eul_source_for_quat(Object *ob)
{
FCurve *fcu = (FCurve *)ob->adt->action->curves.first;
- const int keys = fcu->totvert;
+ const int keys = fcu->totvert;
float *quat = (float *)MEM_callocN(sizeof(float) * fcu->totvert * 4, "quat output source values");
float *eul = (float *)MEM_callocN(sizeof(float) * fcu->totvert * 3, "quat output source values");
float temp_quat[4];
@@ -520,11 +520,11 @@ void AnimationExporter::create_keyframed_animation(Object *ob, FCurve *fcu, char
/*
* Note: Handle transformation animations separately (to apply matrix inverse to fcurves)
- * We will use the object to evaluate the animation on all keyframes and calculate the
+ * We will use the object to evaluate the animation on all keyframes and calculate the
* resulting object matrix. We need this to incorporate the
* effects of the parent inverse matrix (when it contains a rotation component)
*
- * TODO: try to combine exported fcurves into 3 channel animations like done
+ * TODO: try to combine exported fcurves into 3 channel animations like done
* in export_sampled_animation(). For now each channel is exported as separate <Animation>.
*/
@@ -648,7 +648,7 @@ void AnimationExporter::create_keyframed_animation(Object *ob, FCurve *fcu, char
"/common/" /*profile common is only supported */ + get_transform_sid(fcu->rna_path, -1, axis_name, true);
//if shape key animation, this is the main problem, how to define the channel targets.
/*target = get_morph_id(ob) +
- "/value" +*/
+ "/value" +*/
}
addChannel(COLLADABU::URI(empty, sampler_id), target);
@@ -673,7 +673,7 @@ void AnimationExporter::write_bone_animation_matrix(Object *ob_arm, Bone *bone)
}
bool AnimationExporter::is_bone_deform_group(Bone *bone)
-{
+{
bool is_def;
//Check if current bone is deform
if ((bone->flag & BONE_NO_DEFORM) == 0) return true;
@@ -707,7 +707,7 @@ void AnimationExporter::sample_and_write_bone_animation_matrix(Object *ob_arm, B
fcu = fcu->next;
}
- if (!(fcu)) return;*/
+ if (!(fcu)) return;*/
bPoseChannel *pchan = BKE_pose_channel_find_name(ob_arm->pose, bone->name);
if (!pchan)
@@ -728,7 +728,7 @@ void AnimationExporter::sample_and_write_bone_animation_matrix(Object *ob_arm, B
dae_baked_animation(fra, ob_arm, bone);
}
- if (flag & ARM_RESTPOS)
+ if (flag & ARM_RESTPOS)
arm->flag = flag;
BKE_pose_where_is(depsgraph, scene, ob_arm);
}
@@ -921,7 +921,7 @@ void AnimationExporter::add_source_parameters(COLLADASW::SourceBase::ParameterNa
if (axis) {
param.push_back(axis);
}
- else
+ else
if (transform) {
param.push_back("TRANSFORM");
}
@@ -1307,7 +1307,7 @@ std::string AnimationExporter::create_4x4_source(std::vector<float> &frames, Obj
enable_fcurves(ob->adt->action, bone->name);
}
-
+
std::vector<float>::iterator it;
int j = 0;
for (it = frames.begin(); it != frames.end(); it++) {
@@ -1326,7 +1326,7 @@ std::string AnimationExporter::create_4x4_source(std::vector<float> &frames, Obj
else {
BKE_pose_where_is_bone(depsgraph, scene, ob, pchan, ctime, 1);
}
-
+
// compute bone local mat
if (bone->parent) {
invert_m4_m4(ipar, parchan->pose_mat);
@@ -1334,7 +1334,7 @@ std::string AnimationExporter::create_4x4_source(std::vector<float> &frames, Obj
}
else
copy_m4_m4(mat, pchan->pose_mat);
-
+
/* OPEN_SIM_COMPATIBILITY
* AFAIK animation to second life is via BVH, but no
* reason to not have the collada-animation be correct
@@ -1359,7 +1359,7 @@ std::string AnimationExporter::create_4x4_source(std::vector<float> &frames, Obj
else {
copy_m4_m4(mat, ob->obmat);
}
-
+
UnitConverter converter;
double outmat[4][4];
@@ -1515,7 +1515,7 @@ std::string AnimationExporter::get_light_param_sid(char *rna_path, int tm_type,
if (tm_name.size()) {
if (axis_name[0])
return tm_name + "." + std::string(axis_name);
- else
+ else
return tm_name;
}
@@ -1564,7 +1564,7 @@ std::string AnimationExporter::get_camera_param_sid(char *rna_path, int tm_type,
if (tm_name.size()) {
if (axis_name[0])
return tm_name + "." + std::string(axis_name);
- else
+ else
return tm_name;
}
@@ -1751,7 +1751,7 @@ void AnimationExporter::find_sampleframes(Object *ob, std::vector<float> &fra)
} while (true);
}
-/*
+/*
* find keyframes of all the objects animations
*/
void AnimationExporter::find_keyframes(Object *ob, std::vector<float> &fra)
@@ -1844,7 +1844,7 @@ void AnimationExporter::sample_and_write_bone_animation(Object *ob_arm, Bone *bo
arm->flag &= ~ARM_RESTPOS;
BKE_pose_where_is(depsgraph, scene, ob_arm);
}
- //v array will hold all values which will be exported.
+ //v array will hold all values which will be exported.
if (fra.size()) {
float *values = (float *)MEM_callocN(sizeof(float) * 3 * fra.size(), "temp. anim frames");
sample_animation(values, fra, transform_type, bone, ob_arm, pchan);
@@ -1870,7 +1870,7 @@ void AnimationExporter::sample_and_write_bone_animation(Object *ob_arm, Bone *bo
}
// restore restpos
- if (flag & ARM_RESTPOS)
+ if (flag & ARM_RESTPOS)
arm->flag = flag;
BKE_pose_where_is(depsgraph, scene, ob_arm);
}
diff --git a/source/blender/collada/AnimationExporter.h b/source/blender/collada/AnimationExporter.h
index 2ed0a92d89c..a50bcaf0ef4 100644
--- a/source/blender/collada/AnimationExporter.h
+++ b/source/blender/collada/AnimationExporter.h
@@ -23,7 +23,7 @@
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
-extern "C"
+extern "C"
{
#include "DNA_scene_types.h"
#include "DNA_object_types.h"
@@ -100,8 +100,8 @@ public:
bool exportAnimations(Scene *sce);
// called for each exported object
- void operator() (Object *ob);
-
+ void operator() (Object *ob);
+
protected:
const ExportSettings *export_settings;
@@ -127,7 +127,7 @@ protected:
// dae_bone_animation -> add_bone_animation
// (blend this into dae_bone_animation)
void dae_bone_animation(std::vector<float> &fra, float *v, int tm_type, int axis, std::string ob_name, std::string bone_name);
-
+
void dae_baked_animation(std::vector<float> &fra, Object *ob_arm, Bone *bone);
void dae_baked_object_animation(std::vector<float> &fra, Object *ob);
@@ -140,9 +140,9 @@ protected:
void add_source_parameters(COLLADASW::SourceBase::ParameterNameList& param,
COLLADASW::InputSemantic::Semantics semantic, bool is_rot, const char *axis, bool transform);
-
+
void get_source_values(BezTriple *bezt, COLLADASW::InputSemantic::Semantics semantic, bool is_angle, float *values, int *length);
-
+
float* get_eul_source_for_quat(Object *ob );
bool is_flat_line(std::vector<float> &values, int channel_count);
@@ -171,12 +171,12 @@ protected:
std::string create_interpolation_source(FCurve *fcu, const std::string& anim_id, const char *axis_name, bool *has_tangents);
std::string fake_interpolation_source(int tot, const std::string& anim_id, const char *axis_name);
-
+
// for rotation, axis name is always appended and the value of append_axis is ignored
std::string get_transform_sid(char *rna_path, int tm_type, const char *axis_name, bool append_axis);
std::string get_light_param_sid(char *rna_path, int tm_type, const char *axis_name, bool append_axis);
std::string get_camera_param_sid(char *rna_path, int tm_type, const char *axis_name, bool append_axis);
-
+
void find_keyframes(Object *ob, std::vector<float> &fra, const char *prefix, const char *tm_name);
void find_keyframes(Object *ob, std::vector<float> &fra);
void find_sampleframes(Object *ob, std::vector<float> &fra);
@@ -185,13 +185,13 @@ protected:
void make_anim_frames_from_targets(Object *ob, std::vector<float> &frames );
void find_rotation_frames(Object *ob, std::vector<float> &fra, const char *prefix, int rotmode);
-
+
// enable fcurves driving a specific bone, disable all the rest
// if bone_name = NULL enable all fcurves
void enable_fcurves(bAction *act, char *bone_name);
-
+
bool hasAnimations(Scene *sce);
-
+
char *extract_transform_name(char *rna_path);
std::string getObjectBoneName(Object *ob, const FCurve * fcu);
diff --git a/source/blender/collada/AnimationImporter.cpp b/source/blender/collada/AnimationImporter.cpp
index c9b2f6d6d55..e57f8c2f652 100644
--- a/source/blender/collada/AnimationImporter.cpp
+++ b/source/blender/collada/AnimationImporter.cpp
@@ -118,7 +118,7 @@ void AnimationImporter::animation_to_fcurves(COLLADAFW::AnimationCurve *curve)
// input, output
- bez.vec[1][0] = bc_get_float_value(input, j) * fps;
+ bez.vec[1][0] = bc_get_float_value(input, j) * fps;
bez.vec[1][1] = bc_get_float_value(output, j * dim + i);
@@ -135,14 +135,14 @@ void AnimationImporter::animation_to_fcurves(COLLADAFW::AnimationCurve *curve)
// outtangent
bez.vec[2][0] = bc_get_float_value(outtan, (j * 2 * dim) + (2 * i)) * fps;
bez.vec[2][1] = bc_get_float_value(outtan, (j * 2 * dim) + (2 * i) + 1);
- if (curve->getInterpolationType() == COLLADAFW::AnimationCurve::INTERPOLATION_BEZIER)
+ if (curve->getInterpolationType() == COLLADAFW::AnimationCurve::INTERPOLATION_BEZIER)
bez.ipo = BEZT_IPO_BEZ;
- else
+ else
bez.ipo = BEZT_IPO_CONST;
//bez.h1 = bez.h2 = HD_AUTO;
}
else {
- bez.h1 = bez.h2 = HD_AUTO;
+ bez.h1 = bez.h2 = HD_AUTO;
bez.ipo = BEZT_IPO_LIN;
}
// bez.ipo = U.ipo_new; /* use default interpolation mode here... */
@@ -180,13 +180,13 @@ void AnimationImporter::fcurve_is_used(FCurve *fcu)
}
-void AnimationImporter::add_fcurves_to_object(Object *ob, std::vector<FCurve *>& curves, char *rna_path, int array_index, Animation *animated)
+void AnimationImporter::add_fcurves_to_object(Main *bmain, Object *ob, std::vector<FCurve *>& curves, char *rna_path, int array_index, Animation *animated)
{
bAction *act;
-
- if (!ob->adt || !ob->adt->action) act = verify_adt_action((ID *)&ob->id, 1);
+
+ if (!ob->adt || !ob->adt->action) act = verify_adt_action(bmain, (ID *)&ob->id, 1);
else act = ob->adt->action;
-
+
std::vector<FCurve *>::iterator it;
int i;
@@ -198,39 +198,39 @@ void AnimationImporter::add_fcurves_to_object(Object *ob, std::vector<FCurve *>&
if (is_rotation)
fcurve_deg_to_rad(fcu);
#endif
-
+
for (it = curves.begin(), i = 0; it != curves.end(); it++, i++) {
FCurve *fcu = *it;
fcu->rna_path = BLI_strdupn(rna_path, strlen(rna_path));
-
+
if (array_index == -1) fcu->array_index = i;
else fcu->array_index = array_index;
-
+
if (ob->type == OB_ARMATURE) {
bActionGroup *grp = NULL;
const char *bone_name = bc_get_joint_name(animated->node);
-
+
if (bone_name) {
/* try to find group */
grp = BKE_action_group_find_name(act, bone_name);
-
+
/* no matching groups, so add one */
if (grp == NULL) {
/* Add a new group, and make it active */
grp = (bActionGroup *)MEM_callocN(sizeof(bActionGroup), "bActionGroup");
-
+
grp->flag = AGRP_SELECTED;
BLI_strncpy(grp->name, bone_name, sizeof(grp->name));
-
+
BLI_addtail(&act->groups, grp);
BLI_uniquename(&act->groups, grp, CTX_DATA_(BLT_I18NCONTEXT_ID_ACTION, "Group"), '.',
offsetof(bActionGroup, name), 64);
}
-
+
/* add F-Curve to group */
action_groups_add_channel(act, grp, fcu);
fcurve_is_used(fcu);
-
+
}
#if 0
if (is_rotation) {
@@ -263,7 +263,7 @@ bool AnimationImporter::write_animation(const COLLADAFW::Animation *anim)
{
if (anim->getAnimationType() == COLLADAFW::Animation::ANIMATION_CURVE) {
COLLADAFW::AnimationCurve *curve = (COLLADAFW::AnimationCurve *)anim;
-
+
// XXX Don't know if it's necessary
// Should we check outPhysicalDimension?
if (curve->getInPhysicalDimension() != COLLADAFW::PHYSICAL_DIMENSION_TIME) {
@@ -296,10 +296,10 @@ bool AnimationImporter::write_animation(const COLLADAFW::Animation *anim)
else {
fprintf(stderr, "FORMULA animation type is not supported yet.\n");
}
-
+
return true;
}
-
+
// called on post-process stage after writeVisualScenes
bool AnimationImporter::write_animation_list(const COLLADAFW::AnimationList *animlist)
{
@@ -340,16 +340,16 @@ virtual void AnimationImporter::change_eul_to_quat(Object *ob, bAction *act)
{
bActionGroup *grp;
int i;
-
+
for (grp = (bActionGroup *)act->groups.first; grp; grp = grp->next) {
FCurve *eulcu[3] = {NULL, NULL, NULL};
-
+
if (fcurves_actionGroup_map.find(grp) == fcurves_actionGroup_map.end())
continue;
std::vector<FCurve *> &rot_fcurves = fcurves_actionGroup_map[grp];
-
+
if (rot_fcurves.size() > 3) continue;
for (i = 0; i < rot_fcurves.size(); i++)
@@ -437,7 +437,7 @@ void AnimationImporter::modify_fcurve(std::vector<FCurve *> *curves, const char
for (it = curves->begin(), i = 0; it != curves->end(); it++, i++) {
FCurve *fcu = *it;
fcu->rna_path = BLI_strdup(rna_path);
-
+
if (array_index == -1) fcu->array_index = i;
else fcu->array_index = array_index;
@@ -674,7 +674,7 @@ void AnimationImporter:: Assign_float_animations(const COLLADAFW::UniqueId& list
}
}
}
-
+
}
float AnimationImporter::convert_to_focal_length(float in_xfov, int fov_type, float aspect, float sensorx)
@@ -711,7 +711,7 @@ void AnimationImporter::Assign_lens_animations(const COLLADAFW::UniqueId& listid
//Add the curves of the current animation to the object
for (iter = animcurves.begin(); iter != animcurves.end(); iter++) {
FCurve *fcu = *iter;
-
+
for (unsigned int i = 0; i < fcu->totvert; i++) {
fcu->bezt[i].vec[0][1] = convert_to_focal_length(fcu->bezt[i].vec[0][1], fov_type, aspect, cam->sensor_x);
fcu->bezt[i].vec[1][1] = convert_to_focal_length(fcu->bezt[i].vec[1][1], fov_type, aspect, cam->sensor_x);
@@ -725,7 +725,7 @@ void AnimationImporter::Assign_lens_animations(const COLLADAFW::UniqueId& listid
}
}
-void AnimationImporter::apply_matrix_curves(Object *ob, std::vector<FCurve *>& animcurves, COLLADAFW::Node *root, COLLADAFW::Node *node,
+void AnimationImporter::apply_matrix_curves(Main *bmain, Object *ob, std::vector<FCurve *>& animcurves, COLLADAFW::Node *root, COLLADAFW::Node *node,
COLLADAFW::Transformation *tm)
{
bool is_joint = node->getType() == COLLADAFW::Node::JOINT;
@@ -840,7 +840,7 @@ void AnimationImporter::apply_matrix_curves(Object *ob, std::vector<FCurve *>& a
add_bezt(newcu[i], fra, scale[i - 7]);
}
}
- verify_adt_action((ID *)&ob->id, 1);
+ verify_adt_action(bmain, (ID *)&ob->id, 1);
ListBase *curves = &ob->adt->action->curves;
@@ -897,18 +897,18 @@ static const double get_aspect_ratio(const COLLADAFW::Camera *camera)
return aspect;
}
-static ListBase &get_animation_curves(Material *ma)
+static ListBase &get_animation_curves(Main *bmain, Material *ma)
{
bAction *act;
if (!ma->adt || !ma->adt->action)
- act = verify_adt_action((ID *)&ma->id, 1);
+ act = verify_adt_action(bmain, (ID *)&ma->id, 1);
else
act = ma->adt->action;
return act->curves;
}
-void AnimationImporter::translate_Animations(COLLADAFW::Node *node,
+void AnimationImporter::translate_Animations(Main *bmain, COLLADAFW::Node *node,
std::map<COLLADAFW::UniqueId, COLLADAFW::Node *>& root_map,
std::multimap<COLLADAFW::UniqueId, Object *>& object_map,
std::map<COLLADAFW::UniqueId, const COLLADAFW::Object *> FW_object_map,
@@ -941,7 +941,7 @@ void AnimationImporter::translate_Animations(COLLADAFW::Node *node,
armature_importer->get_rna_path_for_joint(node, joint_path, sizeof(joint_path));
- if (!ob->adt || !ob->adt->action) act = verify_adt_action((ID *)&ob->id, 1);
+ if (!ob->adt || !ob->adt->action) act = verify_adt_action(bmain, (ID *)&ob->id, 1);
else act = ob->adt->action;
//Get the list of animation curves of the object
@@ -949,7 +949,7 @@ void AnimationImporter::translate_Animations(COLLADAFW::Node *node,
const COLLADAFW::TransformationPointerArray& nodeTransforms = node->getTransformations();
- //for each transformation in node
+ //for each transformation in node
for (unsigned int i = 0; i < nodeTransforms.getCount(); i++) {
COLLADAFW::Transformation *transform = nodeTransforms[i];
COLLADAFW::Transformation::TransformationType tm_type = transform->getTransformationType();
@@ -972,12 +972,11 @@ void AnimationImporter::translate_Animations(COLLADAFW::Node *node,
for (unsigned int j = 0; j < bindings.getCount(); j++) {
animcurves = curve_map[bindings[j].animation];
if (is_matrix) {
- apply_matrix_curves(ob, animcurves, root, node, transform);
+ apply_matrix_curves(bmain, ob, animcurves, root, node, transform);
}
- else {
-
+ else {
if (is_joint) {
- add_bone_animation_sampled(ob, animcurves, root, node, transform);
+ add_bone_animation_sampled(bmain, ob, animcurves, root, node, transform);
}
else {
//calculate rnapaths and array index of fcurves according to transformation and animation class
@@ -987,12 +986,12 @@ void AnimationImporter::translate_Animations(COLLADAFW::Node *node,
//Add the curves of the current animation to the object
for (iter = animcurves.begin(); iter != animcurves.end(); iter++) {
FCurve *fcu = *iter;
-
+
BLI_addtail(AnimCurves, fcu);
fcurve_is_used(fcu);
}
}
-
+
}
}
}
@@ -1005,7 +1004,7 @@ void AnimationImporter::translate_Animations(COLLADAFW::Node *node,
if ((animType->light) != 0) {
Lamp *lamp = (Lamp *) ob->data;
- if (!lamp->adt || !lamp->adt->action) act = verify_adt_action((ID *)&lamp->id, 1);
+ if (!lamp->adt || !lamp->adt->action) act = verify_adt_action(bmain, (ID *)&lamp->id, 1);
else act = lamp->adt->action;
ListBase *AnimCurves = &(act->curves);
@@ -1018,7 +1017,7 @@ void AnimationImporter::translate_Animations(COLLADAFW::Node *node,
const COLLADAFW::Color *col = &(light->getColor());
const COLLADAFW::UniqueId& listid = col->getAnimationList();
- Assign_color_animations(listid, AnimCurves, "color");
+ Assign_color_animations(listid, AnimCurves, "color");
}
if ((animType->light & LIGHT_FOA) != 0) {
const COLLADAFW::AnimatableFloat *foa = &(light->getFallOffAngle());
@@ -1039,7 +1038,7 @@ void AnimationImporter::translate_Animations(COLLADAFW::Node *node,
if (animType->camera != 0) {
Camera *cam = (Camera *) ob->data;
if (!cam->adt || !cam->adt->action)
- act = verify_adt_action((ID *)&cam->id, 1);
+ act = verify_adt_action(bmain, (ID *)&cam->id, 1);
else
act = cam->adt->action;
@@ -1052,14 +1051,14 @@ void AnimationImporter::translate_Animations(COLLADAFW::Node *node,
if ((animType->camera & CAMERA_XFOV) != 0) {
const COLLADAFW::AnimatableFloat *xfov = &(camera->getXFov());
const COLLADAFW::UniqueId& listid = xfov->getAnimationList();
- double aspect = get_aspect_ratio(camera);
+ double aspect = get_aspect_ratio(camera);
Assign_lens_animations(listid, AnimCurves, aspect, cam, "lens", CAMERA_XFOV);
}
else if ((animType->camera & CAMERA_YFOV) != 0) {
const COLLADAFW::AnimatableFloat *yfov = &(camera->getYFov());
const COLLADAFW::UniqueId& listid = yfov->getAnimationList();
- double aspect = get_aspect_ratio(camera);
+ double aspect = get_aspect_ratio(camera);
Assign_lens_animations(listid, AnimCurves, aspect, cam, "lens", CAMERA_YFOV);
}
@@ -1103,7 +1102,7 @@ void AnimationImporter::translate_Animations(COLLADAFW::Node *node,
fprintf(stderr, "Collada: Node %s refers to undefined material\n", node->getName().c_str());
continue;
}
- ListBase &AnimCurves = get_animation_curves(ma);
+ ListBase &AnimCurves = get_animation_curves(bmain, ma);
const COLLADAFW::CommonEffectPointerArray& commonEffects = ef->getCommonEffects();
COLLADAFW::EffectCommon *efc = commonEffects[0];
if ((animType->material & MATERIAL_SHININESS) != 0) {
@@ -1137,7 +1136,7 @@ void AnimationImporter::translate_Animations(COLLADAFW::Node *node,
delete animType;
}
-void AnimationImporter::add_bone_animation_sampled(Object *ob, std::vector<FCurve *>& animcurves, COLLADAFW::Node *root, COLLADAFW::Node *node, COLLADAFW::Transformation *tm)
+void AnimationImporter::add_bone_animation_sampled(Main *bmain, Object *ob, std::vector<FCurve *>& animcurves, COLLADAFW::Node *root, COLLADAFW::Node *node, COLLADAFW::Transformation *tm)
{
const char *bone_name = bc_get_joint_name(node);
char joint_path[200];
@@ -1260,7 +1259,7 @@ void AnimationImporter::add_bone_animation_sampled(Object *ob, std::vector<FCurv
add_bezt(newcu[i], fra, scale[i - 7]);
}
}
- verify_adt_action((ID *)&ob->id, 1);
+ verify_adt_action(bmain, (ID *)&ob->id, 1);
// add curves
for (int i = 0; i < totcu; i++) {
@@ -1282,7 +1281,7 @@ AnimationImporter::AnimMix *AnimationImporter::get_animation_type(const COLLADAF
const COLLADAFW::TransformationPointerArray& nodeTransforms = node->getTransformations();
- //for each transformation in node
+ //for each transformation in node
for (unsigned int i = 0; i < nodeTransforms.getCount(); i++) {
COLLADAFW::Transformation *transform = nodeTransforms[i];
const COLLADAFW::UniqueId& listid = transform->getAnimationList();
@@ -1370,7 +1369,7 @@ int AnimationImporter::setAnimType(const COLLADAFW::Animatable *prop, int types,
anim_type = types;
return anim_type;
-}
+}
// Is not used anymore.
void AnimationImporter::find_frames_old(std::vector<float> *frames, COLLADAFW::Node *node, COLLADAFW::Transformation::TransformationType tm_type)
@@ -1392,7 +1391,7 @@ void AnimationImporter::find_frames_old(std::vector<float> *frames, COLLADAFW::N
const COLLADAFW::UniqueId& listid = transform->getAnimationList();
//if transform is animated its animlist must exist.
if (animlist_map.find(listid) != animlist_map.end()) {
-
+
const COLLADAFW::AnimationList *animlist = animlist_map[listid];
const COLLADAFW::AnimationList::AnimationBindings& bindings = animlist->getAnimationBindings();
@@ -1436,17 +1435,17 @@ void AnimationImporter::find_frames_old(std::vector<float> *frames, COLLADAFW::N
// prerequisites:
// animlist_map - map animlist id -> animlist
// curve_map - map anim id -> curve(s)
-Object *AnimationImporter::translate_animation_OLD(COLLADAFW::Node *node,
+Object *AnimationImporter::translate_animation_OLD(Main *bmain, COLLADAFW::Node *node,
std::map<COLLADAFW::UniqueId, Object *>& object_map,
std::map<COLLADAFW::UniqueId, COLLADAFW::Node *>& root_map,
COLLADAFW::Transformation::TransformationType tm_type,
Object *par_job)
{
-
+
bool is_rotation = tm_type == COLLADAFW::Transformation::ROTATE;
bool is_matrix = tm_type == COLLADAFW::Transformation::MATRIX;
bool is_joint = node->getType() == COLLADAFW::Node::JOINT;
-
+
COLLADAFW::Node *root = root_map.find(node->getUniqueId()) == root_map.end() ? node : root_map[node->getUniqueId()];
Object *ob = is_joint ? armature_importer->get_armature_for_joint(node) : object_map[node->getUniqueId()];
const char *bone_name = is_joint ? bc_get_joint_name(node) : NULL;
@@ -1457,11 +1456,11 @@ Object *AnimationImporter::translate_animation_OLD(COLLADAFW::Node *node,
// frames at which to sample
std::vector<float> frames;
-
+
find_frames_old(&frames, node, tm_type);
-
+
unsigned int i;
-
+
float irest_dae[4][4];
float rest[4][4], irest[4][4];
@@ -1659,7 +1658,7 @@ Object *AnimationImporter::translate_animation_OLD(COLLADAFW::Node *node,
#endif
}
- verify_adt_action((ID *)&ob->id, 1);
+ verify_adt_action(bmain, (ID *)&ob->id, 1);
ListBase *curves = &ob->adt->action->curves;
@@ -1732,9 +1731,9 @@ void AnimationImporter::evaluate_transform_at_frame(float mat[4][4], COLLADAFW::
}
}
-static void report_class_type_unsupported(const char *path,
+static void report_class_type_unsupported(const char *path,
const COLLADAFW::AnimationList::AnimationClass animclass,
- const COLLADAFW::Transformation::TransformationType type)
+ const COLLADAFW::Transformation::TransformationType type)
{
if (animclass == COLLADAFW::AnimationList::UNKNOWN_CLASS) {
fprintf(stderr, "%s: UNKNOWN animation class\n", path);
@@ -1829,7 +1828,7 @@ bool AnimationImporter::evaluate_animation(COLLADAFW::Transformation *tm, float
fprintf(stderr, "%s: expected 1 curve, got %d\n", path, (int)curves.size());
return false;
}
-
+
switch (animclass) {
case COLLADAFW::AnimationList::POSITION_X:
vec[0] = evaluate_fcurve(curves[0], fra);
@@ -2011,7 +2010,7 @@ void AnimationImporter::add_bone_fcurve(Object *ob, COLLADAFW::Node *node, FCurv
{
const char *bone_name = bc_get_joint_name(node);
bAction *act = ob->adt->action;
-
+
/* try to find group */
bActionGroup *grp = BKE_action_group_find_name(act, bone_name);
diff --git a/source/blender/collada/AnimationImporter.h b/source/blender/collada/AnimationImporter.h
index e25116cac9f..f63329158f0 100644
--- a/source/blender/collada/AnimationImporter.h
+++ b/source/blender/collada/AnimationImporter.h
@@ -19,7 +19,7 @@
*
* ***** END GPL LICENSE BLOCK *****
*/
-
+
/** \file AnimationImporter.h
* \ingroup collada
*/
@@ -75,9 +75,9 @@ private:
std::map<COLLADAFW::UniqueId, const COLLADAFW::AnimationList*> animlist_map;
std::vector<FCurve*> unused_curves;
std::map<COLLADAFW::UniqueId, Object*> joint_objects;
-
+
FCurve *create_fcurve(int array_index, const char *rna_path);
-
+
void add_bezt(FCurve *fcu, float frame, float value, eBezTriple_Interpolation ipo=BEZT_IPO_LIN);
// create one or several fcurves depending on the number of parameters being animated
@@ -87,9 +87,9 @@ private:
void fcurve_is_used(FCurve *fcu);
- void add_fcurves_to_object(Object *ob, std::vector<FCurve*>& curves, char *rna_path, int array_index, Animation *animated);
+ void add_fcurves_to_object(Main *bmain, Object *ob, std::vector<FCurve*>& curves, char *rna_path, int array_index, Animation *animated);
+
-
int typeFlag;
std::string import_from_version;
@@ -121,7 +121,7 @@ private:
MATERIAL_TRANSPARENCY = 1 << 4,
MATERIAL_IOR = 1 << 5
};
-
+
enum AnimationType
{
INANIMATE = 0,
@@ -144,7 +144,7 @@ public:
void set_import_from_version(std::string import_from_version);
bool write_animation(const COLLADAFW::Animation* anim);
-
+
// called on post-process stage after writeVisualScenes
bool write_animation_list(const COLLADAFW::AnimationList* animlist);
@@ -153,7 +153,7 @@ public:
virtual void change_eul_to_quat(Object *ob, bAction *act);
#endif
- void translate_Animations(COLLADAFW::Node * Node,
+ void translate_Animations(Main *bmain, COLLADAFW::Node * Node,
std::map<COLLADAFW::UniqueId, COLLADAFW::Node*>& root_map,
std::multimap<COLLADAFW::UniqueId, Object*>& object_map,
std::map<COLLADAFW::UniqueId, const COLLADAFW::Object*> FW_object_map,
@@ -161,10 +161,10 @@ public:
AnimMix* get_animation_type( const COLLADAFW::Node * node, std::map<COLLADAFW::UniqueId, const COLLADAFW::Object*> FW_object_map );
- void apply_matrix_curves(Object *ob, std::vector<FCurve*>& animcurves, COLLADAFW::Node* root, COLLADAFW::Node* node,
+ void apply_matrix_curves(Main *bmain, Object *ob, std::vector<FCurve*>& animcurves, COLLADAFW::Node* root, COLLADAFW::Node* node,
COLLADAFW::Transformation * tm );
-
- void add_bone_animation_sampled(Object *ob, std::vector<FCurve*>& animcurves, COLLADAFW::Node* root, COLLADAFW::Node* node, COLLADAFW::Transformation * tm);
+
+ void add_bone_animation_sampled(Main *bmain, Object *ob, std::vector<FCurve*>& animcurves, COLLADAFW::Node* root, COLLADAFW::Node* node, COLLADAFW::Transformation * tm);
void Assign_transform_animations(COLLADAFW::Transformation* transform,
const COLLADAFW::AnimationList::AnimationBinding *binding,
@@ -175,18 +175,18 @@ public:
void Assign_lens_animations(const COLLADAFW::UniqueId& listid, ListBase *AnimCurves, const double aspect, Camera *cam, const char *anim_type, int fov_type);
int setAnimType ( const COLLADAFW::Animatable * prop, int type, int addition);
-
+
void modify_fcurve(std::vector<FCurve*>* curves, const char *rna_path, int array_index );
void unused_fcurve(std::vector<FCurve*>* curves );
// prerequisites:
// animlist_map - map animlist id -> animlist
// curve_map - map anim id -> curve(s)
- Object * translate_animation_OLD(COLLADAFW::Node *node,
+ Object * translate_animation_OLD(Main *bmain, COLLADAFW::Node *node,
std::map<COLLADAFW::UniqueId, Object*>& object_map,
std::map<COLLADAFW::UniqueId, COLLADAFW::Node*>& root_map,
COLLADAFW::Transformation::TransformationType tm_type,
Object *par_job = NULL);
-
+
void find_frames( std::vector<float>* frames, std::vector<FCurve*>* curves );
void find_frames_old( std::vector<float>* frames, COLLADAFW::Node * node, COLLADAFW::Transformation::TransformationType tm_type );
// internal, better make it private
diff --git a/source/blender/collada/ArmatureExporter.cpp b/source/blender/collada/ArmatureExporter.cpp
index 5e349535610..85b9d3297ca 100644
--- a/source/blender/collada/ArmatureExporter.cpp
+++ b/source/blender/collada/ArmatureExporter.cpp
@@ -62,10 +62,11 @@ ArmatureExporter::ArmatureExporter(COLLADASW::StreamWriter *sw, const ExportSett
}
// write bone nodes
-void ArmatureExporter::add_armature_bones(Depsgraph *depsgraph, Object *ob_arm,
+void ArmatureExporter::add_armature_bones(bContext *C, Depsgraph *depsgraph, Object *ob_arm,
Scene *sce, SceneExporter *se,
std::list<Object *>& child_objects)
{
+ Main *bmain = CTX_data_main(C);
// write bone nodes
bArmature * armature = (bArmature *)ob_arm->data;
@@ -77,11 +78,11 @@ void ArmatureExporter::add_armature_bones(Depsgraph *depsgraph, Object *ob_arm,
for (Bone *bone = (Bone *)armature->bonebase.first; bone; bone = bone->next) {
// start from root bones
if (!bone->parent)
- add_bone_node(depsgraph, bone, ob_arm, sce, se, child_objects);
+ add_bone_node(C, depsgraph, bone, ob_arm, sce, se, child_objects);
}
if (!is_edited) {
- ED_armature_from_edit(armature);
+ ED_armature_from_edit(bmain, armature);
ED_armature_edit_free(armature);
}
}
@@ -117,7 +118,7 @@ bool ArmatureExporter::add_instance_controller(Object *ob)
}
InstanceWriter::add_material_bindings(ins.getBindMaterial(), ob, this->export_settings->active_uv_only);
-
+
ins.add();
return true;
}
@@ -146,7 +147,7 @@ void ArmatureExporter::find_objects_using_armature(Object *ob_arm, std::vector<O
Base *base = (Base *) sce->base.first;
while (base) {
Object *ob = base->object;
-
+
if (ob->type == OB_MESH && get_assigned_armature(ob) == ob_arm) {
objects.push_back(ob);
}
@@ -157,7 +158,7 @@ void ArmatureExporter::find_objects_using_armature(Object *ob_arm, std::vector<O
#endif
// parent_mat is armature-space
-void ArmatureExporter::add_bone_node(Depsgraph *depsgraph, Bone *bone, Object *ob_arm, Scene *sce,
+void ArmatureExporter::add_bone_node(bContext *C, Depsgraph *depsgraph, Bone *bone, Object *ob_arm, Scene *sce,
SceneExporter *se,
std::list<Object *>& child_objects)
{
@@ -231,7 +232,7 @@ void ArmatureExporter::add_bone_node(Depsgraph *depsgraph, Bone *bone, Object *o
mul_m4_m4m4((*i)->parentinv, temp, (*i)->parentinv);
}
- se->writeNodes(depsgraph, *i, sce);
+ se->writeNodes(C, depsgraph, *i, sce);
copy_m4_m4((*i)->parentinv, backup_parinv);
child_objects.erase(i++);
@@ -240,13 +241,13 @@ void ArmatureExporter::add_bone_node(Depsgraph *depsgraph, Bone *bone, Object *o
}
for (Bone *child = (Bone *)bone->childbase.first; child; child = child->next) {
- add_bone_node(depsgraph, child, ob_arm, sce, se, child_objects);
+ add_bone_node(C, depsgraph, child, ob_arm, sce, se, child_objects);
}
node.end();
}
else {
for (Bone *child = (Bone *)bone->childbase.first; child; child = child->next) {
- add_bone_node(depsgraph, child, ob_arm, sce, se, child_objects);
+ add_bone_node(C, depsgraph, child, ob_arm, sce, se, child_objects);
}
}
}
@@ -264,7 +265,7 @@ void ArmatureExporter::add_bone_transform(Object *ob_arm, Bone *bone, COLLADASW:
if (!has_restmat) {
/* Have no restpose matrix stored, try old style <= Blender 2.78 */
-
+
bc_create_restpose_mat(this->export_settings, bone, bone_rest_mat, bone->arm_mat, true);
if (bone->parent) {
diff --git a/source/blender/collada/ArmatureExporter.h b/source/blender/collada/ArmatureExporter.h
index 17c02d637e8..7efa8b70e43 100644
--- a/source/blender/collada/ArmatureExporter.h
+++ b/source/blender/collada/ArmatureExporter.h
@@ -60,7 +60,7 @@ public:
ArmatureExporter(COLLADASW::StreamWriter *sw, const ExportSettings *export_settings);
// write bone nodes
- void add_armature_bones(struct Depsgraph *depsgraph, Object *ob_arm, Scene *sce, SceneExporter *se,
+ void add_armature_bones(bContext *C, struct Depsgraph *depsgraph, Object *ob_arm, Scene *sce, SceneExporter *se,
std::list<Object *>& child_objects);
bool add_instance_controller(Object *ob);
@@ -85,7 +85,7 @@ private:
// Scene, SceneExporter and the list of child_objects
// are required for writing bone parented objects
- void add_bone_node(struct Depsgraph *depsgraph, Bone *bone, Object *ob_arm, Scene *sce, SceneExporter *se,
+ void add_bone_node(bContext *C, struct Depsgraph *depsgraph, Bone *bone, Object *ob_arm, Scene *sce, SceneExporter *se,
std::list<Object *>& child_objects);
void add_bone_transform(Object *ob_arm, Bone *bone, COLLADASW::Node& node);
diff --git a/source/blender/collada/ArmatureImporter.cpp b/source/blender/collada/ArmatureImporter.cpp
index f24688479af..19f174d4840 100644
--- a/source/blender/collada/ArmatureImporter.cpp
+++ b/source/blender/collada/ArmatureImporter.cpp
@@ -61,7 +61,7 @@ ArmatureImporter::ArmatureImporter(UnitConverter *conv, MeshImporterBase *mesh,
view_layer(view_layer),
unit_converter(conv),
import_settings(import_settings),
- empty(NULL),
+ empty(NULL),
mesh_importer(mesh) {
}
@@ -103,7 +103,7 @@ int ArmatureImporter::create_bone(SkinInfo *skin, COLLADAFW::Node *node, EditBon
std::vector<COLLADAFW::Node *>::iterator it;
it = std::find(finished_joints.begin(), finished_joints.end(), node);
if (it != finished_joints.end()) return chain_length;
-
+
EditBone *bone = ED_armature_ebone_add(arm, bc_get_joint_name(node));
totbone++;
@@ -141,7 +141,7 @@ int ArmatureImporter::create_bone(SkinInfo *skin, COLLADAFW::Node *node, EditBon
if (parent) bone->parent = parent;
- float loc[3], size[3], rot[3][3];
+ float loc[3], size[3], rot[3][3];
BoneExtensionMap &extended_bones = bone_extension_manager.getExtensionMap(arm);
BoneExtended &be = add_bone_extended(bone, node, totchild, layer_labels, extended_bones);
int layer = be.get_bone_layers();
@@ -386,7 +386,7 @@ void ArmatureImporter::set_euler_rotmode()
COLLADAFW::Node *joint = it->second;
std::map<COLLADAFW::UniqueId, SkinInfo>::iterator sit;
-
+
for (sit = skin_by_data_uid.begin(); sit != skin_by_data_uid.end(); sit++) {
SkinInfo& skin = sit->second;
@@ -410,7 +410,7 @@ void ArmatureImporter::set_euler_rotmode()
Object *ArmatureImporter::get_empty_for_leaves()
{
if (empty) return empty;
-
+
empty = bc_add_object(scene, view_layer, OB_EMPTY, NULL);
empty->empty_drawtype = OB_EMPTY_SPHERE;
@@ -448,7 +448,7 @@ ArmatureJoints& ArmatureImporter::get_armature_joints(Object *ob_arm)
return armature_joints.back();
}
#endif
-void ArmatureImporter::create_armature_bones(std::vector<Object *> &ob_arms)
+void ArmatureImporter::create_armature_bones(Main *bmain, std::vector<Object *> &ob_arms)
{
std::vector<COLLADAFW::Node *>::iterator ri;
std::vector<std::string> layer_labels;
@@ -456,7 +456,7 @@ void ArmatureImporter::create_armature_bones(std::vector<Object *> &ob_arms)
//if there is an armature created for root_joint next root_joint
for (ri = root_joints.begin(); ri != root_joints.end(); ri++) {
if (get_armature_for_joint(*ri) != NULL) continue;
-
+
Object *ob_arm = joint_parent_map[(*ri)->getUniqueId()];
if (!ob_arm)
continue;
@@ -481,7 +481,7 @@ void ArmatureImporter::create_armature_bones(std::vector<Object *> &ob_arms)
}
/* exit armature edit mode to populate the Armature object */
- ED_armature_from_edit(armature);
+ ED_armature_from_edit(bmain, armature);
ED_armature_edit_free(armature);
ED_armature_to_edit(armature);
@@ -489,7 +489,7 @@ void ArmatureImporter::create_armature_bones(std::vector<Object *> &ob_arms)
fix_leaf_bone_hierarchy(armature, (Bone *)armature->bonebase.first, this->import_settings->fix_orientation);
unskinned_armature_map[(*ri)->getUniqueId()] = ob_arm;
- ED_armature_from_edit(armature);
+ ED_armature_from_edit(bmain, armature);
ED_armature_edit_free(armature);
int index = std::find(ob_arms.begin(), ob_arms.end(), ob_arm) - ob_arms.begin();
@@ -501,7 +501,7 @@ void ArmatureImporter::create_armature_bones(std::vector<Object *> &ob_arms)
}
}
-Object *ArmatureImporter::create_armature_bones(SkinInfo& skin)
+Object *ArmatureImporter::create_armature_bones(Main *bmain, SkinInfo& skin)
{
// just do like so:
// - get armature
@@ -572,8 +572,8 @@ Object *ArmatureImporter::create_armature_bones(SkinInfo& skin)
}
if (!shared && this->joint_parent_map.size() > 0) {
- // All armatures have been created while creating the Node tree.
- // The Collada exporter currently does not create a
+ // All armatures have been created while creating the Node tree.
+ // The Collada exporter currently does not create a
// strict relationship between geometries and armatures
// So when we reimport a Blender collada file, then we have
// to guess what is meant.
@@ -619,7 +619,7 @@ Object *ArmatureImporter::create_armature_bones(SkinInfo& skin)
}
/* exit armature edit mode to populate the Armature object */
- ED_armature_from_edit(armature);
+ ED_armature_from_edit(bmain, armature);
ED_armature_edit_free(armature);
ED_armature_to_edit(armature);
@@ -627,7 +627,7 @@ Object *ArmatureImporter::create_armature_bones(SkinInfo& skin)
connect_bone_chains(armature, (Bone *)armature->bonebase.first, UNLIMITED_CHAIN_MAX);
}
fix_leaf_bone_hierarchy(armature, (Bone *)armature->bonebase.first, this->import_settings->fix_orientation);
- ED_armature_from_edit(armature);
+ ED_armature_from_edit(bmain, armature);
ED_armature_edit_free(armature);
DEG_id_tag_update(&ob_arm->id, OB_RECALC_OB | OB_RECALC_DATA);
@@ -657,12 +657,12 @@ void ArmatureImporter::set_pose(Object *ob_arm, COLLADAFW::Node *root_node, con
}
else {
-
+
copy_m4_m4(mat, obmat);
float invObmat[4][4];
invert_m4_m4(invObmat, ob_arm->obmat);
mul_m4_m4m4(pchan->pose_mat, invObmat, mat);
-
+
}
//float angle = 0.0f;
@@ -709,6 +709,7 @@ void ArmatureImporter::add_root_joint(COLLADAFW::Node *node)
// here we add bones to armatures, having armatures previously created in write_controller
void ArmatureImporter::make_armatures(bContext *C, std::vector<Object *> &objects_to_scale)
{
+ Main *bmain = CTX_data_main(C);
std::vector<Object *> ob_arms;
std::map<COLLADAFW::UniqueId, SkinInfo>::iterator it;
@@ -718,7 +719,7 @@ void ArmatureImporter::make_armatures(bContext *C, std::vector<Object *> &object
SkinInfo& skin = it->second;
- Object *ob_arm = create_armature_bones(skin);
+ Object *ob_arm = create_armature_bones(bmain, skin);
// link armature with a mesh object
const COLLADAFW::UniqueId &uid = skin.get_controller_uid();
@@ -757,9 +758,9 @@ void ArmatureImporter::make_armatures(bContext *C, std::vector<Object *> &object
// free memory stolen from SkinControllerData
skin.free();
}
-
+
//for bones without skins
- create_armature_bones(ob_arms);
+ create_armature_bones(bmain, ob_arms);
// Fix bone relations
std::vector<Object *>::iterator ob_arm_it;
@@ -773,7 +774,7 @@ void ArmatureImporter::make_armatures(bContext *C, std::vector<Object *> &object
fix_parent_connect(armature, (Bone *)armature->bonebase.first);
- ED_armature_from_edit(armature);
+ ED_armature_from_edit(bmain, armature);
ED_armature_edit_free(armature);
}
}
@@ -807,9 +808,9 @@ bool ArmatureImporter::write_skin_controller_data(const COLLADAFW::SkinControlle
// don't forget to call defgroup_unique_name before we copy
- // controller data uid -> [armature] -> joint data,
+ // controller data uid -> [armature] -> joint data,
// [mesh object]
- //
+ //
SkinInfo skin(unit_converter);
skin.borrow_skin_controller_data(data);
@@ -867,7 +868,7 @@ void ArmatureImporter::make_shape_keys()
//Prereq: all the geometries must be imported and mesh objects must be made
Object *source_ob = this->mesh_importer->get_object_by_geom_uid((*mc)->getSource());
-
+
if (source_ob) {
Mesh *source_me = (Mesh *)source_ob->data;
@@ -875,7 +876,7 @@ void ArmatureImporter::make_shape_keys()
Key *key = source_me->key = BKE_key_add((ID *)source_me);
key->type = KEY_RELATIVE;
KeyBlock *kb;
-
+
//insert basis key
kb = BKE_keyblock_add_ctime(key, "Basis", false);
BKE_keyblock_convert_from_mesh(source_me, kb);
@@ -886,14 +887,14 @@ void ArmatureImporter::make_shape_keys()
//This'll do for now since only mesh morphing is imported
Mesh *me = this->mesh_importer->get_mesh_by_geom_uid(morphTargetIds[i]);
-
+
if (me) {
me->key = key;
std::string morph_name = *this->mesh_importer->get_geometry_name(me->id.name);
kb = BKE_keyblock_add_ctime(key, morph_name.c_str(), false);
BKE_keyblock_convert_from_mesh(me, kb);
-
+
//apply weights
weight = morphWeights.getFloatValues()->getData()[i];
kb->curval = weight;
@@ -989,14 +990,14 @@ BoneExtended &ArmatureImporter::add_bone_extended(EditBone *bone, COLLADAFW::Nod
has_connect = et->setData("connect", &connect_type);
bool has_roll = et->setData("roll", &roll);
-
+
layers = et->setData("layer", layers);
if (has_tail && !has_connect)
{
/* got a bone tail definition but no connect info -> bone is not connected */
has_connect = true;
- connect_type = 0;
+ connect_type = 0;
}
be->set_bone_layers(layers, layer_labels);
diff --git a/source/blender/collada/ArmatureImporter.h b/source/blender/collada/ArmatureImporter.h
index f260bb2307c..b13e40bf855 100644
--- a/source/blender/collada/ArmatureImporter.h
+++ b/source/blender/collada/ArmatureImporter.h
@@ -130,8 +130,8 @@ private:
ArmatureJoints& get_armature_joints(Object *ob_arm);
#endif
- Object *create_armature_bones(SkinInfo& skin);
- void create_armature_bones(std::vector<Object *> &arm_objs);
+ Object *create_armature_bones(Main *bmain, SkinInfo& skin);
+ void create_armature_bones(Main *bmain, std::vector<Object *> &arm_objs);
/** TagsMap typedef for uid_tags_map. */
typedef std::map<std::string, ExtraTags*> TagsMap;
@@ -158,16 +158,16 @@ public:
bool write_controller(const COLLADAFW::Controller* controller);
COLLADAFW::UniqueId *get_geometry_uid(const COLLADAFW::UniqueId& controller_uid);
-
+
Object *get_armature_for_joint(COLLADAFW::Node *node);
void get_rna_path_for_joint(COLLADAFW::Node *node, char *joint_path, size_t count);
-
+
// gives a world-space mat
bool get_joint_bind_mat(float m[4][4], COLLADAFW::Node *joint);
void set_tags_map( TagsMap& tags_map);
-
+
};
#endif
diff --git a/source/blender/collada/CameraExporter.cpp b/source/blender/collada/CameraExporter.cpp
index 649288c2db4..32bd24f1e0b 100644
--- a/source/blender/collada/CameraExporter.cpp
+++ b/source/blender/collada/CameraExporter.cpp
@@ -56,9 +56,9 @@ void forEachCameraObjectInExportSet(Scene *sce, Functor &f, LinkNode *export_set
void CamerasExporter::exportCameras(Scene *sce)
{
openLibrary();
-
+
forEachCameraObjectInExportSet(sce, *this, this->export_settings->export_set);
-
+
closeLibrary();
}
void CamerasExporter::operator()(Object *ob, Scene *sce)
diff --git a/source/blender/collada/ControllerExporter.cpp b/source/blender/collada/ControllerExporter.cpp
index f6dbc965b42..122094e33a6 100644
--- a/source/blender/collada/ControllerExporter.cpp
+++ b/source/blender/collada/ControllerExporter.cpp
@@ -99,7 +99,7 @@ bool ControllerExporter::add_instance_controller(Object *ob)
}
InstanceWriter::add_material_bindings(ins.getBindMaterial(), ob, this->export_settings->active_uv_only);
-
+
ins.add();
return true;
}
@@ -148,7 +148,7 @@ void ArmatureExporter::find_objects_using_armature(Object *ob_arm, std::vector<O
Base *base = (Base *) sce->base.first;
while (base) {
Object *ob = base->object;
-
+
if (ob->type == OB_MESH && get_assigned_armature(ob) == ob_arm) {
objects.push_back(ob);
}
@@ -203,7 +203,7 @@ void ControllerExporter::export_skin_controller(Object *ob, Object *ob_arm)
this->export_settings->export_mesh_type,
this->export_settings->apply_modifiers,
this->export_settings->triangulate);
-
+
if (!me->dvert) return;
std::string controller_name = id_name(ob_arm);
@@ -246,7 +246,7 @@ void ControllerExporter::export_skin_controller(Object *ob, Object *ob_arm)
for (j = 0; j < vert->totweight; j++) {
int idx = vert->dw[j].def_nr;
if (idx >= joint_index_by_def_index.size()) {
- // XXX: Maybe better find out where and
+ // XXX: Maybe better find out where and
// why the Out Of Bound indexes get created ?
oob_counter += 1;
}
@@ -314,7 +314,7 @@ void ControllerExporter::export_morph_controller(Object *ob, Key *key)
std::string targets_id = add_morph_targets(key, ob);
std::string morph_weights_id = add_morph_weights(key, ob);
-
+
COLLADASW::TargetsElement targets(mSW);
COLLADASW::InputList &input = targets.getInputList();
@@ -376,7 +376,7 @@ std::string ControllerExporter::add_morph_weights(Key *key, Object *ob)
COLLADASW::SourceBase::ParameterNameList &param = source.getParameterNameList();
param.push_back("MORPH_WEIGHT");
-
+
source.prepareToAppendValues();
KeyBlock *kb = (KeyBlock *)key->block.first;
@@ -396,7 +396,7 @@ void ControllerExporter::add_weight_extras(Key *key)
{
// can also try the base element and param alternative
COLLADASW::BaseExtraTechnique extra;
-
+
KeyBlock * kb = (KeyBlock *)key->block.first;
//skip the basis
kb = kb->next;
@@ -447,7 +447,7 @@ std::string ControllerExporter::add_joints_source(Object *ob_arm, ListBase *defb
source.setArrayId(source_id + ARRAY_ID_SUFFIX);
source.setAccessorCount(totjoint);
source.setAccessorStride(1);
-
+
COLLADASW::SourceBase::ParameterNameList &param = source.getParameterNameList();
param.push_back("JOINT");
@@ -480,7 +480,7 @@ std::string ControllerExporter::add_inv_bind_mats_source(Object *ob_arm, ListBas
source.setArrayId(source_id + ARRAY_ID_SUFFIX);
source.setAccessorCount(totjoint); //BLI_listbase_count(defbase));
source.setAccessorStride(16);
-
+
source.setParameterTypeName(&COLLADASW::CSWC::CSW_VALUE_TYPE_FLOAT4x4);
COLLADASW::SourceBase::ParameterNameList &param = source.getParameterNameList();
param.push_back("TRANSFORM");
@@ -509,7 +509,7 @@ std::string ControllerExporter::add_inv_bind_mats_source(Object *ob_arm, ListBas
float bind_mat[4][4]; /* derived from bone->arm_mat */
bool has_bindmat = bc_get_property_matrix(pchan->bone, "bind_mat", bind_mat);
-
+
if (!has_bindmat) {
/* Have no bind matrix stored, try old style <= Blender 2.78 */
@@ -571,7 +571,7 @@ std::string ControllerExporter::add_weights_source(Mesh *me, const std::string&
source.setArrayId(source_id + ARRAY_ID_SUFFIX);
source.setAccessorCount(weights.size());
source.setAccessorStride(1);
-
+
COLLADASW::SourceBase::ParameterNameList &param = source.getParameterNameList();
param.push_back("WEIGHT");
diff --git a/source/blender/collada/DocumentExporter.cpp b/source/blender/collada/DocumentExporter.cpp
index a66c4db7b4d..9e78c164dad 100644
--- a/source/blender/collada/DocumentExporter.cpp
+++ b/source/blender/collada/DocumentExporter.cpp
@@ -62,7 +62,7 @@
#include "COLLADASWInstanceNode.h"
#include "COLLADASWBaseInputElement.h"
-extern "C"
+extern "C"
{
#include "DNA_scene_types.h"
#include "DNA_object_types.h"
@@ -180,8 +180,7 @@ static COLLADABU::NativeString make_temp_filepath(const char *name, const char *
// COLLADA allows this through multiple <channel>s in <animation>.
// For this to work, we need to know objects that use a certain action.
-
-int DocumentExporter::exportCurrentScene(Scene *sce)
+int DocumentExporter::exportCurrentScene(bContext *C, Scene *sce)
{
PointerRNA sceneptr, unit_settings;
PropertyRNA *system; /* unused , *scale; */
@@ -258,14 +257,14 @@ int DocumentExporter::exportCurrentScene(Scene *sce)
#endif
asset.getContributor().mAuthoringTool = version_buf;
asset.add();
-
+
LinkNode *export_set = this->export_settings->export_set;
// <library_cameras>
if (bc_has_object_type(export_set, OB_CAMERA)) {
CamerasExporter ce(writer, this->export_settings);
ce.exportCameras(sce);
}
-
+
// <library_lights>
if (bc_has_object_type(export_set, OB_LAMP)) {
LightsExporter le(writer, this->export_settings);
@@ -275,11 +274,11 @@ int DocumentExporter::exportCurrentScene(Scene *sce)
// <library_images>
ImagesExporter ie(writer, this->export_settings);
ie.exportImages(sce);
-
+
// <library_effects>
EffectsExporter ee(writer, this->export_settings);
ee.exportEffects(sce);
-
+
// <library_materials>
MaterialsExporter me(writer, this->export_settings);
me.exportMaterials(sce);
@@ -293,7 +292,7 @@ int DocumentExporter::exportCurrentScene(Scene *sce)
// <library_controllers>
ArmatureExporter arm_exporter(writer, this->export_settings);
ControllerExporter controller_exporter(writer, this->export_settings);
- if (bc_has_object_type(export_set, OB_ARMATURE) || this->export_settings->include_shapekeys)
+ if (bc_has_object_type(export_set, OB_ARMATURE) || this->export_settings->include_shapekeys)
{
controller_exporter.export_controllers(depsgraph, sce);
}
@@ -307,14 +306,14 @@ int DocumentExporter::exportCurrentScene(Scene *sce)
AnimationExporter ae(depsgraph, writer, this->export_settings);
ae.exportAnimations(sce);
}
- se.exportScene(depsgraph, sce);
-
+ se.exportScene(C, depsgraph, sce);
+
// <scene>
std::string scene_name(translate_id(id_name(sce)));
COLLADASW::Scene scene(writer, COLLADASW::URI(COLLADABU::Utils::EMPTY_STRING,
scene_name));
scene.add();
-
+
// close <Collada>
writer->endDocument();
delete writer;
diff --git a/source/blender/collada/DocumentExporter.h b/source/blender/collada/DocumentExporter.h
index c98f82e68b4..8a48ca29090 100644
--- a/source/blender/collada/DocumentExporter.h
+++ b/source/blender/collada/DocumentExporter.h
@@ -40,7 +40,7 @@ class DocumentExporter
{
public:
DocumentExporter(Depsgraph *depsgraph, const ExportSettings *export_settings);
- int exportCurrentScene(Scene *sce);
+ int exportCurrentScene(bContext *C, Scene *sce);
void exportScenes(const char *filename);
private:
diff --git a/source/blender/collada/DocumentImporter.cpp b/source/blender/collada/DocumentImporter.cpp
index 47b720614ea..ae573fec0d8 100644
--- a/source/blender/collada/DocumentImporter.cpp
+++ b/source/blender/collada/DocumentImporter.cpp
@@ -130,7 +130,7 @@ bool DocumentImporter::import()
COLLADASaxFWL::Loader loader(&errorHandler);
COLLADAFW::Root root(&loader, this);
ExtraHandler *ehandler = new ExtraHandler(this, &(this->anim_importer));
-
+
loader.registerExtraDataCallbackHandler(ehandler);
// deselect all to select new objects
@@ -143,19 +143,19 @@ bool DocumentImporter::import()
delete ehandler;
return false;
}
-
+
if (errorHandler.hasError()) {
delete ehandler;
return false;
}
-
+
/** TODO set up scene graph and such here */
-
+
mImportStage = Controller;
-
+
COLLADASaxFWL::Loader loader2;
COLLADAFW::Root root2(&loader2, this);
-
+
if (!root2.loadDocument(encodedFilename)) {
fprintf(stderr, "COLLADAFW::Root::loadDocument() returned false on 2nd pass\n");
delete ehandler;
@@ -198,7 +198,7 @@ void DocumentImporter::finish()
for (sit = vscenes.begin(); sit != vscenes.end(); sit++) {
PointerRNA sceneptr, unit_settings;
PropertyRNA *system, *scale;
-
+
// for scene unit settings: system, scale_length
RNA_id_pointer_create(&sce->id, &sceneptr);
@@ -207,7 +207,7 @@ void DocumentImporter::finish()
scale = RNA_struct_find_property(&unit_settings, "scale_length");
if (this->import_settings->import_units) {
-
+
switch (unit_converter.isMetricSystem()) {
case UnitConverter::Metric:
RNA_property_enum_set(&unit_settings, system, USER_UNIT_METRIC);
@@ -272,7 +272,7 @@ void DocumentImporter::finish()
DEG_relations_tag_update(bmain);
}
-
+
bc_match_scale(objects_to_scale, unit_converter, !this->import_settings->import_units);
delete objects_to_scale;
@@ -281,7 +281,7 @@ void DocumentImporter::finish()
void DocumentImporter::translate_anim_recursive(COLLADAFW::Node *node, COLLADAFW::Node *par = NULL, Object *parob = NULL)
{
-
+ Main *bmain = CTX_data_main(mContext);
// The split in #29246, rootmap must point at actual root when
// calculating bones in apply_curves_as_matrix. - actual root is the root node.
// This has to do with inverse bind poses being world space
@@ -316,7 +316,7 @@ void DocumentImporter::translate_anim_recursive(COLLADAFW::Node *node, COLLADAFW
translate_anim_recursive(node, node, parob);
}
else {
- anim_importer.translate_Animations(node, root_map, object_map, FW_object_map, uid_material_map);
+ anim_importer.translate_Animations(bmain, node, root_map, object_map, FW_object_map, uid_material_map);
COLLADAFW::NodePointerArray &children = node->getChildNodes();
for (i = 0; i < children.getCount(); i++) {
translate_anim_recursive(children[i], node, NULL);
@@ -473,7 +473,7 @@ void DocumentImporter::create_constraints(ExtraTags *et, Object *ob)
short type = 0;
et->setData("type", &type);
BKE_constraint_add_for_object(ob, "Test_con", type);
-
+
}
}
@@ -634,7 +634,7 @@ std::vector<Object *> *DocumentImporter::write_node(COLLADAFW::Node *node, COLLA
root_objects->push_back(ob);
}
}
-
+
// XXX: if there're multiple instances, only one is stored
if (!ob) {
@@ -700,7 +700,7 @@ bool DocumentImporter::writeVisualScene(const COLLADAFW::VisualScene *visualScen
{
if (mImportStage != General)
return true;
-
+
// this method called on post process after writeGeometry, writeMaterial, etc.
// for each <node> in <visual_scene>:
@@ -712,18 +712,18 @@ bool DocumentImporter::writeVisualScene(const COLLADAFW::VisualScene *visualScen
// we link Objects with Meshes here
vscenes.push_back(visualScene);
-
+
return true;
}
-/** When this method is called, the writer must handle all nodes contained in the
+/** When this method is called, the writer must handle all nodes contained in the
* library nodes.
* \return The writer should return true, if writing succeeded, false otherwise.*/
bool DocumentImporter::writeLibraryNodes(const COLLADAFW::LibraryNodes *libraryNodes)
{
if (mImportStage != General)
return true;
-
+
Scene *sce = CTX_data_scene(mContext);
const COLLADAFW::NodePointerArray& nodes = libraryNodes->getNodes();
@@ -743,7 +743,7 @@ bool DocumentImporter::writeGeometry(const COLLADAFW::Geometry *geom)
{
if (mImportStage != General)
return true;
-
+
return mesh_importer.write_geometry(geom);
}
@@ -753,13 +753,13 @@ bool DocumentImporter::writeMaterial(const COLLADAFW::Material *cmat)
{
if (mImportStage != General)
return true;
-
+
const std::string& str_mat_id = cmat->getName().size() ? cmat->getName() : cmat->getOriginalId();
Material *ma = BKE_material_add(G.main, (char *)str_mat_id.c_str());
-
+
this->uid_effect_map[cmat->getInstantiatedEffect()] = ma;
this->uid_material_map[cmat->getUniqueId()] = ma;
-
+
return true;
}
@@ -768,7 +768,7 @@ void DocumentImporter::write_profile_COMMON(COLLADAFW::EffectCommon *ef, Materia
COLLADAFW::EffectCommon::ShaderType shader = ef->getShaderType();
// TODO: add back texture and extended material parameter support
-
+
// blinn
if (shader == COLLADAFW::EffectCommon::SHADER_BLINN) {
#if 0
@@ -802,9 +802,9 @@ void DocumentImporter::write_profile_COMMON(COLLADAFW::EffectCommon *ef, Materia
#if 0
ma->ang = ef->getIndexOfRefraction().getFloatValue();
#endif
-
+
COLLADAFW::Color col;
-
+
// DIFFUSE
// color
if (ef->getDiffuse().isColor()) {
@@ -816,7 +816,7 @@ void DocumentImporter::write_profile_COMMON(COLLADAFW::EffectCommon *ef, Materia
// texture
else if (ef->getDiffuse().isTexture()) {
#if 0
- COLLADAFW::Texture ctex = ef->getDiffuse().getTexture();
+ COLLADAFW::Texture ctex = ef->getDiffuse().getTexture();
#endif
}
// AMBIENT
@@ -829,7 +829,7 @@ void DocumentImporter::write_profile_COMMON(COLLADAFW::EffectCommon *ef, Materia
// texture
else if (ef->getAmbient().isTexture()) {
#if 0
- COLLADAFW::Texture ctex = ef->getAmbient().getTexture();
+ COLLADAFW::Texture ctex = ef->getAmbient().getTexture();
#endif
}
// SPECULAR
@@ -843,7 +843,7 @@ void DocumentImporter::write_profile_COMMON(COLLADAFW::EffectCommon *ef, Materia
// texture
else if (ef->getSpecular().isTexture()) {
#if 0
- COLLADAFW::Texture ctex = ef->getSpecular().getTexture();
+ COLLADAFW::Texture ctex = ef->getSpecular().getTexture();
#endif
}
// REFLECTIVE
@@ -856,7 +856,7 @@ void DocumentImporter::write_profile_COMMON(COLLADAFW::EffectCommon *ef, Materia
// texture
else if (ef->getReflective().isTexture()) {
#if 0
- COLLADAFW::Texture ctex = ef->getReflective().getTexture();
+ COLLADAFW::Texture ctex = ef->getReflective().getTexture();
#endif
}
@@ -869,7 +869,7 @@ void DocumentImporter::write_profile_COMMON(COLLADAFW::EffectCommon *ef, Materia
// texture
else if (ef->getEmission().isTexture()) {
#if 0
- COLLADAFW::Texture ctex = ef->getEmission().getTexture();
+ COLLADAFW::Texture ctex = ef->getEmission().getTexture();
#endif
}
@@ -902,14 +902,14 @@ bool DocumentImporter::writeEffect(const COLLADAFW::Effect *effect)
{
if (mImportStage != General)
return true;
-
+
const COLLADAFW::UniqueId& uid = effect->getUniqueId();
-
+
if (uid_effect_map.find(uid) == uid_effect_map.end()) {
fprintf(stderr, "Couldn't find a material by UID.\n");
return true;
}
-
+
Material *ma = uid_effect_map[uid];
std::map<COLLADAFW::UniqueId, Material *>::iterator iter;
for (iter = uid_material_map.begin(); iter != uid_material_map.end(); iter++) {
@@ -928,7 +928,7 @@ bool DocumentImporter::writeEffect(const COLLADAFW::Effect *effect)
COLLADAFW::EffectCommon *ef = common_efs[0];
write_profile_COMMON(ef, ma);
this->FW_object_map[effect->getUniqueId()] = effect;
-
+
return true;
}
@@ -939,16 +939,16 @@ bool DocumentImporter::writeCamera(const COLLADAFW::Camera *camera)
{
if (mImportStage != General)
return true;
-
+
Camera *cam = NULL;
std::string cam_id, cam_name;
-
+
ExtraTags *et=getExtraTags(camera->getUniqueId());
cam_id = camera->getOriginalId();
cam_name = camera->getName();
if (cam_name.size()) cam = (Camera *)BKE_camera_add(G.main, (char *)cam_name.c_str());
else cam = (Camera *)BKE_camera_add(G.main, (char *)cam_id.c_str());
-
+
if (!cam) {
fprintf(stderr, "Cannot create camera.\n");
return true;
@@ -961,7 +961,7 @@ bool DocumentImporter::writeCamera(const COLLADAFW::Camera *camera)
}
cam->clipsta = camera->getNearClippingPlane().getValue();
cam->clipend = camera->getFarClippingPlane().getValue();
-
+
COLLADAFW::Camera::CameraType type = camera->getCameraType();
switch (type) {
case COLLADAFW::Camera::ORTHOGRAPHIC:
@@ -981,7 +981,7 @@ bool DocumentImporter::writeCamera(const COLLADAFW::Camera *camera)
}
break;
}
-
+
switch (camera->getDescriptionType()) {
case COLLADAFW::Camera::ASPECTRATIO_AND_Y:
{
@@ -1051,7 +1051,7 @@ bool DocumentImporter::writeCamera(const COLLADAFW::Camera *camera)
// read nothing, use blender defaults.
break;
}
-
+
this->uid_camera_map[camera->getUniqueId()] = cam;
this->FW_object_map[camera->getUniqueId()] = camera;
// XXX import camera options
@@ -1064,7 +1064,7 @@ bool DocumentImporter::writeImage(const COLLADAFW::Image *image)
{
if (mImportStage != General)
return true;
-
+
const std::string& imagepath = image->getImageURI().toNativePath();
char dir[FILE_MAX];
@@ -1075,7 +1075,7 @@ bool DocumentImporter::writeImage(const COLLADAFW::Image *image)
BLI_join_dirfile(absolute_path, sizeof(absolute_path), dir, imagepath.c_str());
if (BLI_exists(absolute_path)) {
workpath = absolute_path;
- }
+ }
else {
// Maybe imagepath was already absolute ?
if (!BLI_exists(imagepath.c_str())) {
@@ -1091,7 +1091,7 @@ bool DocumentImporter::writeImage(const COLLADAFW::Image *image)
return true;
}
this->uid_image_map[image->getUniqueId()] = ima;
-
+
return true;
}
@@ -1185,7 +1185,7 @@ bool DocumentImporter::writeLight(const COLLADAFW::Light *light)
// assuming point light (const att = 1.0);
att1 = 1.0f;
}
-
+
d *= (1.0f / unit_converter.getLinearMeter());
lamp->energy = e;
@@ -1247,7 +1247,7 @@ bool DocumentImporter::writeAnimation(const COLLADAFW::Animation *anim)
{
if (mImportStage != General)
return true;
-
+
// return true;
return anim_importer.write_animation(anim);
}
@@ -1257,7 +1257,7 @@ bool DocumentImporter::writeAnimationList(const COLLADAFW::AnimationList *animat
{
if (mImportStage != General)
return true;
-
+
// return true;
return anim_importer.write_animation_list(animationList);
}
@@ -1274,7 +1274,7 @@ bool DocumentImporter::writeController(const COLLADAFW::Controller *controller)
{
if (mImportStage != General)
return true;
-
+
return armature_importer.write_controller(controller);
}
diff --git a/source/blender/collada/DocumentImporter.h b/source/blender/collada/DocumentImporter.h
index 758caef7e60..b31a086d710 100644
--- a/source/blender/collada/DocumentImporter.h
+++ b/source/blender/collada/DocumentImporter.h
@@ -78,7 +78,7 @@ public:
void create_constraints(ExtraTags *et, Object *ob);
std::vector<Object *> *write_node(COLLADAFW::Node*, COLLADAFW::Node*, Scene*, Object*, bool);
void write_profile_COMMON(COLLADAFW::EffectCommon*, Material*);
-
+
void translate_anim_recursive(COLLADAFW::Node*, COLLADAFW::Node*, Object*);
/**
@@ -149,7 +149,7 @@ private:
ArmatureImporter armature_importer;
MeshImporter mesh_importer;
AnimationImporter anim_importer;
-
+
/** TagsMap typedef for uid_tags_map. */
typedef std::map<std::string, ExtraTags*> TagsMap;
/** Tags map of unique id as a string and ExtraTags instance. */
@@ -165,7 +165,7 @@ private:
std::map<COLLADAFW::UniqueId, COLLADAFW::Node*> node_map;
std::vector<const COLLADAFW::VisualScene*> vscenes;
std::vector<Object*> libnode_ob;
-
+
std::map<COLLADAFW::UniqueId, COLLADAFW::Node*> root_map; // find root joint by child joint uid, for bone tree evaluation during resampling
std::map<COLLADAFW::UniqueId, const COLLADAFW::Object*> FW_object_map;
diff --git a/source/blender/collada/EffectExporter.cpp b/source/blender/collada/EffectExporter.cpp
index dbcdfd01a9c..271dab5deea 100644
--- a/source/blender/collada/EffectExporter.cpp
+++ b/source/blender/collada/EffectExporter.cpp
@@ -57,7 +57,7 @@ static std::string getActiveUVLayerName(Object *ob)
int num_layers = CustomData_number_of_layers(&me->fdata, CD_MTFACE);
if (num_layers)
return std::string(bc_CustomData_get_active_layer_name(&me->fdata, CD_MTFACE));
-
+
return "";
}
@@ -105,12 +105,12 @@ void EffectsExporter::operator()(Material *ma, Object *ob)
// TODO: add back texture and extended material parameter support
openEffect(translate_id(id_name(ma)) + "-effect");
-
+
COLLADASW::EffectProfile ep(mSW);
ep.setProfileType(COLLADASW::EffectProfile::COMMON);
ep.openProfile();
writeLambert(ep, ma);
-
+
COLLADASW::ColorOrTexture cot;
// transparency
@@ -144,7 +144,7 @@ void EffectsExporter::operator()(Material *ma, Object *ob)
//COLLADASW::Surface surfaces[MAX_MTEX];
//void *samp_surf[MAX_MTEX][2];
void *samp_surf[MAX_MTEX];
-
+
// image to index to samp_surf map
// samp_surf[index] stores 2 pointers, sampler and surface
std::map<std::string, int> im_samp_map;
@@ -153,10 +153,10 @@ void EffectsExporter::operator()(Material *ma, Object *ob)
for (a = 0, b = 0; a < tex_indices.size(); a++) {
MTex *t = ma->mtex[tex_indices[a]];
Image *ima = t->tex->ima;
-
+
// Image not set for texture
if (!ima) continue;
-
+
std::string key(id_name(ima));
key = translate_id(key);
@@ -171,7 +171,7 @@ void EffectsExporter::operator()(Material *ma, Object *ob)
// COLLADASW::NewParamSurface surface(mSW);
// surface->setParamType(COLLADASW::CSW_SURFACE_TYPE_2D);
-
+
//<newparam> <sampler> <source>
COLLADASW::Sampler sampler(COLLADASW::Sampler::SAMPLER_TYPE_2D,
key + COLLADASW::Sampler::SAMPLER_SID_SUFFIX,
@@ -180,11 +180,11 @@ void EffectsExporter::operator()(Material *ma, Object *ob)
// copy values to arrays since they will live longer
samplers[a] = sampler;
//surfaces[a] = surface;
-
+
// store pointers so they can be used later when we create <texture>s
samp_surf[b] = &samplers[a];
//samp_surf[b][1] = &surfaces[a];
-
+
im_samp_map[key] = b;
b++;
}
@@ -238,12 +238,12 @@ COLLADASW::ColorOrTexture EffectsExporter::createTexture(Image *ima,
COLLADASW::Sampler *sampler
/*COLLADASW::Surface *surface*/)
{
-
+
COLLADASW::Texture texture(translate_id(id_name(ima)));
texture.setTexcoord(uv_layer_name);
//texture.setSurface(*surface);
texture.setSampler(*sampler);
-
+
COLLADASW::ColorOrTexture cot(texture);
return cot;
}
diff --git a/source/blender/collada/EffectExporter.h b/source/blender/collada/EffectExporter.h
index eac428ae330..a1395bfde9f 100644
--- a/source/blender/collada/EffectExporter.h
+++ b/source/blender/collada/EffectExporter.h
@@ -50,25 +50,25 @@ public:
void exportEffects(Scene *sce);
void operator()(Material *ma, Object *ob);
-
+
COLLADASW::ColorOrTexture createTexture(Image *ima,
std::string& uv_layer_name,
COLLADASW::Sampler *sampler
/*COLLADASW::Surface *surface*/);
-
+
COLLADASW::ColorOrTexture getcol(float r, float g, float b, float a);
private:
void writeLambert(COLLADASW::EffectProfile &ep, Material *ma);
void writeTextures(COLLADASW::EffectProfile &ep,
std::string &key,
- COLLADASW::Sampler *sampler,
+ COLLADASW::Sampler *sampler,
MTex *t, Image *ima,
std::string &uvname );
bool hasEffects(Scene *sce);
-
+
const ExportSettings *export_settings;
-
+
Scene *scene;
};
diff --git a/source/blender/collada/ErrorHandler.cpp b/source/blender/collada/ErrorHandler.cpp
index 7e18328f000..26674445d98 100644
--- a/source/blender/collada/ErrorHandler.cpp
+++ b/source/blender/collada/ErrorHandler.cpp
@@ -53,7 +53,7 @@ bool ErrorHandler::handleError(const COLLADASaxFWL::IError *error)
See https://github.com/KhronosGroup/OpenCOLLADA/issues/442
*/
bool isWarning = false;
-
+
if (error->getErrorClass() == COLLADASaxFWL::IError::ERROR_SAXPARSER) {
COLLADASaxFWL::SaxParserError *saxParserError = (COLLADASaxFWL::SaxParserError *) error;
const GeneratedSaxParser::ParserError& parserError = saxParserError->getError();
diff --git a/source/blender/collada/ExtraHandler.cpp b/source/blender/collada/ExtraHandler.cpp
index bef7accd9f7..5d704bc9abc 100644
--- a/source/blender/collada/ExtraHandler.cpp
+++ b/source/blender/collada/ExtraHandler.cpp
@@ -54,9 +54,9 @@ bool ExtraHandler::elementEnd(const char *elementName)
bool ExtraHandler::textData(const char *text, size_t textLength)
{
char buf[1024];
-
+
if (currentElement.length() == 0 || currentExtraTags == 0) return false;
-
+
BLI_strncpy(buf, text, textLength + 1);
currentExtraTags->addTag(currentElement, std::string(buf));
return true;
diff --git a/source/blender/collada/ExtraHandler.h b/source/blender/collada/ExtraHandler.h
index f380c3d6871..4dda862b3cc 100644
--- a/source/blender/collada/ExtraHandler.h
+++ b/source/blender/collada/ExtraHandler.h
@@ -50,31 +50,31 @@ public:
/** Handle the beginning of an element. */
bool elementBegin( const char* elementName, const char** attributes);
-
+
/** Handle the end of an element. */
bool elementEnd(const char* elementName );
-
+
/** Receive the data in text format. */
bool textData(const char* text, size_t textLength);
/** Method to ask, if the current callback handler want to read the data of the given extra element. */
- bool parseElement (
- const char* profileName,
- const unsigned long& elementHash,
+ bool parseElement (
+ const char* profileName,
+ const unsigned long& elementHash,
const COLLADAFW::UniqueId& uniqueId,
COLLADAFW::Object* object);
/** For backwards compatibility with older OpenCollada, new version added object parameter */
- bool parseElement (
- const char* profileName,
- const unsigned long& elementHash,
+ bool parseElement (
+ const char* profileName,
+ const unsigned long& elementHash,
const COLLADAFW::UniqueId& uniqueId);
private:
/** Disable default copy constructor. */
ExtraHandler(const ExtraHandler& pre);
/** Disable default assignment operator. */
const ExtraHandler& operator= ( const ExtraHandler& pre );
-
+
/** Handle to DocumentImporter for interface to extra element data saving. */
DocumentImporter* dimp;
AnimationImporter* aimp;
diff --git a/source/blender/collada/ExtraTags.cpp b/source/blender/collada/ExtraTags.cpp
index ea225d8a4ae..fd249884c3f 100644
--- a/source/blender/collada/ExtraTags.cpp
+++ b/source/blender/collada/ExtraTags.cpp
@@ -50,7 +50,7 @@ bool ExtraTags::isProfile(std::string profile)
bool ExtraTags::addTag(std::string tag, std::string data)
{
tags[tag] = data;
-
+
return true;
}
diff --git a/source/blender/collada/ExtraTags.h b/source/blender/collada/ExtraTags.h
index ad272dcba65..84857622ee8 100644
--- a/source/blender/collada/ExtraTags.h
+++ b/source/blender/collada/ExtraTags.h
@@ -41,35 +41,35 @@ public:
/** Handle the beginning of an element. */
bool addTag(std::string tag, std::string data);
-
+
/** Set given short pointer to value of tag, if it exists. */
bool setData(std::string tag, short *data);
-
+
/** Set given int pointer to value of tag, if it exists. */
bool setData(std::string tag, int *data);
-
+
/** Set given float pointer to value of tag, if it exists. */
bool setData(std::string tag, float *data);
-
+
/** Set given char pointer to value of tag, if it exists. */
bool setData(std::string tag, char *data);
std::string setData(std::string tag, std::string &data);
/** Return true if the extra tags is for specified profile. */
bool isProfile(std::string profile);
-
+
private:
/** Disable default copy constructor. */
ExtraTags(const ExtraTags& pre);
/** Disable default assignment operator. */
const ExtraTags& operator= ( const ExtraTags& pre );
-
+
/** The profile for which the tags are. */
std::string profile;
-
+
/** Map of tag and text pairs. */
std::map<std::string, std::string> tags;
-
+
/** Get text data for tag as an int. */
int asInt(std::string tag, bool *ok);
/** Get text data for tag as a float. */
diff --git a/source/blender/collada/GeometryExporter.cpp b/source/blender/collada/GeometryExporter.cpp
index 87b47353596..65e844cbe50 100644
--- a/source/blender/collada/GeometryExporter.cpp
+++ b/source/blender/collada/GeometryExporter.cpp
@@ -70,14 +70,14 @@ void GeometryExporter::exportGeom(struct Depsgraph *depsgraph, Scene *sce)
}
void GeometryExporter::operator()(Object *ob)
-{
+{
// XXX don't use DerivedMesh, Mesh instead?
-#if 0
+#if 0
DerivedMesh *dm = mesh_get_derived_final(mScene, ob, CD_MASK_BAREMESH);
#endif
bool use_instantiation = this->export_settings->use_object_instantiation;
- Mesh *me = bc_get_mesh_copy(mDepsgraph, mScene,
+ Mesh *me = bc_get_mesh_copy(mDepsgraph, mScene,
ob,
this->export_settings->export_mesh_type,
this->export_settings->apply_modifiers,
@@ -88,7 +88,7 @@ void GeometryExporter::operator()(Object *ob)
std::vector<BCPolygonNormalsIndices> norind;
// Skip if linked geometry was already exported from another reference
- if (use_instantiation &&
+ if (use_instantiation &&
exportedGeometry.find(geom_id) != exportedGeometry.end())
{
return;
@@ -104,15 +104,15 @@ void GeometryExporter::operator()(Object *ob)
// openMesh(geoId, geoName, meshId)
openMesh(geom_id, geom_name);
-
+
// writes <source> for vertex coords
createVertsSource(geom_id, me);
-
+
// writes <source> for normal coords
createNormalsSource(geom_id, me, nor);
bool has_uvs = (bool)CustomData_has_layer(&me->fdata, CD_MTFACE);
-
+
// writes <source> for uv coords if mesh has uv coords
if (has_uvs) {
createTexcoordsSource(geom_id, me);
@@ -144,9 +144,9 @@ void GeometryExporter::operator()(Object *ob)
createPolylist(0, has_uvs, has_color, ob, me, geom_id, norind);
}
}
-
+
closeMesh();
-
+
if (me->flag & ME_TWOSIDED) {
mSW->appendTextBlock("<extra><technique profile=\"MAYA\"><double_sided>1</double_sided></technique></extra>");
}
@@ -175,7 +175,7 @@ void GeometryExporter::export_key_mesh(Object *ob, Mesh *me, KeyBlock *kb)
std::string geom_id = get_geometry_id(ob, false) + "_morph_" + translate_id(kb->name);
std::vector<Normal> nor;
std::vector<BCPolygonNormalsIndices> norind;
-
+
if (exportedGeometry.find(geom_id) != exportedGeometry.end())
{
return;
@@ -191,15 +191,15 @@ void GeometryExporter::export_key_mesh(Object *ob, Mesh *me, KeyBlock *kb)
// openMesh(geoId, geoName, meshId)
openMesh(geom_id, geom_name);
-
+
// writes <source> for vertex coords
createVertsSource(geom_id, me);
-
+
// writes <source> for normal coords
createNormalsSource(geom_id, me, nor);
bool has_uvs = (bool)CustomData_has_layer(&me->fdata, CD_MTFACE);
-
+
// writes <source> for uv coords if mesh has uv coords
if (has_uvs) {
createTexcoordsSource(geom_id, me);
@@ -220,7 +220,7 @@ void GeometryExporter::export_key_mesh(Object *ob, Mesh *me, KeyBlock *kb)
//createLooseEdgeList(ob, me, geom_id, norind);
- // XXX slow
+ // XXX slow
if (ob->totcol) {
for (int a = 0; a < ob->totcol; a++) {
createPolylist(a, has_uvs, has_color, ob, me, geom_id, norind);
@@ -229,9 +229,9 @@ void GeometryExporter::export_key_mesh(Object *ob, Mesh *me, KeyBlock *kb)
else {
createPolylist(0, has_uvs, has_color, ob, me, geom_id, norind);
}
-
+
closeMesh();
-
+
if (me->flag & ME_TWOSIDED) {
mSW->appendTextBlock("<extra><technique profile=\"MAYA\"><double_sided>1</double_sided></technique></extra>");
}
@@ -250,9 +250,9 @@ void GeometryExporter::createLooseEdgeList(Object *ob,
std::vector<unsigned int> edge_list;
int index;
- // Find all loose edges in Mesh
+ // Find all loose edges in Mesh
// and save vertex indices in edge_list
- for (index = 0; index < totedges; index++)
+ for (index = 0; index < totedges; index++)
{
MEdge *edge = &medges[index];
@@ -273,14 +273,14 @@ void GeometryExporter::createLooseEdgeList(Object *ob,
COLLADASW::InputList &til = lines.getInputList();
-
- // creates <input> in <lines> for vertices
+
+ // creates <input> in <lines> for vertices
COLLADASW::Input input1(COLLADASW::InputSemantic::VERTEX, getUrlBySemantics(geom_id, COLLADASW::InputSemantic::VERTEX), 0);
til.push_back(input1);
lines.prepareToAppendValues();
- for (index = 0; index < edges_in_linelist; index++)
+ for (index = 0; index < edges_in_linelist; index++)
{
lines.appendValues(edge_list[2 * index + 1]);
lines.appendValues(edge_list[2 * index]);
@@ -318,7 +318,7 @@ void GeometryExporter::createPolylist(short material_index,
// count faces with this material
for (i = 0; i < totpolys; i++) {
MPoly *p = &mpolys[i];
-
+
if (p->mat_nr == material_index) {
faces_in_polylist++;
vcount_list.push_back(p->totloop);
@@ -330,13 +330,13 @@ void GeometryExporter::createPolylist(short material_index,
fprintf(stderr, "%s: material with index %d is not used.\n", id_name(ob).c_str(), material_index);
return;
}
-
+
Material *ma = ob->totcol ? give_current_material(ob, material_index + 1) : NULL;
COLLADASW::Polylist polylist(mSW);
-
+
// sets count attribute in <polylist>
polylist.setCount(faces_in_polylist);
-
+
// sets material name
if (ma) {
std::string material_id = get_material_id(ma);
@@ -344,18 +344,18 @@ void GeometryExporter::createPolylist(short material_index,
ostr << translate_id(material_id);
polylist.setMaterial(ostr.str());
}
-
+
COLLADASW::InputList &til = polylist.getInputList();
-
- // creates <input> in <polylist> for vertices
+
+ // creates <input> in <polylist> for vertices
COLLADASW::Input input1(COLLADASW::InputSemantic::VERTEX, getUrlBySemantics(geom_id, COLLADASW::InputSemantic::VERTEX), 0);
-
+
// creates <input> in <polylist> for normals
COLLADASW::Input input2(COLLADASW::InputSemantic::NORMAL, getUrlBySemantics(geom_id, COLLADASW::InputSemantic::NORMAL), 1);
-
+
til.push_back(input1);
til.push_back(input2);
-
+
// if mesh has uv coords writes <input> for TEXCOORD
int num_layers = CustomData_number_of_layers(&me->fdata, CD_MTFACE);
int active_uv_index = CustomData_get_active_layer_index(&me->fdata, CD_MTFACE)-1;
@@ -387,13 +387,13 @@ void GeometryExporter::createPolylist(short material_index,
map_index++;
}
}
-
+
// sets <vcount>
polylist.setVCountList(vcount_list);
-
+
// performs the actual writing
polylist.prepareToAppendValues();
-
+
// <p>
int texindex = 0;
for (i = 0; i < totpolys; i++) {
@@ -417,7 +417,7 @@ void GeometryExporter::createPolylist(short material_index,
texindex += loop_count;
}
-
+
polylist.finish();
}
@@ -430,7 +430,7 @@ void GeometryExporter::createVertsSource(std::string geom_id, Mesh *me)
#endif
int totverts = me->totvert;
MVert *verts = me->mvert;
-
+
COLLADASW::FloatSourceF source(mSW);
source.setId(getIdBySemantics(geom_id, COLLADASW::InputSemantic::POSITION));
source.setArrayId(getIdBySemantics(geom_id, COLLADASW::InputSemantic::POSITION) +
@@ -450,7 +450,7 @@ void GeometryExporter::createVertsSource(std::string geom_id, Mesh *me)
for (i = 0; i < totverts; i++) {
source.appendValues(verts[i].co[0], verts[i].co[1], verts[i].co[2]);
}
-
+
source.finish();
}
@@ -502,7 +502,7 @@ void GeometryExporter::createVertexColorSource(std::string geom_id, Mesh *me)
);
}
}
-
+
source.finish();
}
}
@@ -537,20 +537,20 @@ void GeometryExporter::createTexcoordsSource(std::string geom_id, Mesh *me)
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);
std::string layer_id = makeTexcoordSourceId(geom_id, a, this->export_settings->active_uv_only);
source.setId(layer_id);
source.setArrayId(layer_id + ARRAY_ID_SUFFIX);
-
+
source.setAccessorCount(totuv);
source.setAccessorStride(2);
COLLADASW::SourceBase::ParameterNameList &param = source.getParameterNameList();
param.push_back("S");
param.push_back("T");
-
+
source.prepareToAppendValues();
-
+
for (int index = 0; index < totpoly; index++) {
MPoly *mpoly = mpolys+index;
MLoopUV *mloop = mloops+mpoly->loopstart;
@@ -559,7 +559,7 @@ void GeometryExporter::createTexcoordsSource(std::string geom_id, Mesh *me)
mloop[j].uv[1]);
}
}
-
+
source.finish();
}
}
@@ -589,7 +589,7 @@ void GeometryExporter::createNormalsSource(std::string geom_id, Mesh *me, std::v
param.push_back("X");
param.push_back("Y");
param.push_back("Z");
-
+
source.prepareToAppendValues();
std::vector<Normal>::iterator it;
@@ -674,10 +674,10 @@ std::string GeometryExporter::getIdBySemantics(std::string geom_id, COLLADASW::I
COLLADASW::URI GeometryExporter::getUrlBySemantics(std::string geom_id, COLLADASW::InputSemantic::Semantics type, std::string other_suffix)
{
-
+
std::string id(getIdBySemantics(geom_id, type, other_suffix));
return COLLADASW::URI(COLLADABU::Utils::EMPTY_STRING, id);
-
+
}
COLLADASW::URI GeometryExporter::makeUrl(std::string id)
diff --git a/source/blender/collada/GeometryExporter.h b/source/blender/collada/GeometryExporter.h
index 88420b4ad2f..b0cd650adcd 100644
--- a/source/blender/collada/GeometryExporter.h
+++ b/source/blender/collada/GeometryExporter.h
@@ -96,7 +96,7 @@ public:
Mesh *me,
std::string& geom_id,
std::vector<BCPolygonNormalsIndices>& norind);
-
+
// creates <source> for positions
void createVertsSource(std::string geom_id, Mesh *me);
@@ -112,7 +112,7 @@ public:
void createNormalsSource(std::string geom_id, Mesh *me, std::vector<Normal>& nor);
void create_normals(std::vector<Normal> &nor, std::vector<BCPolygonNormalsIndices> &ind, Mesh *me);
-
+
std::string getIdBySemantics(std::string geom_id, COLLADASW::InputSemantic::Semantics type, std::string other_suffix = "");
std::string makeVertexColorSourceId(std::string& geom_id, char *layer_name);
@@ -121,10 +121,10 @@ public:
COLLADASW::URI makeUrl(std::string id);
void export_key_mesh(Object *ob, Mesh *me, KeyBlock *kb);
-
+
private:
std::set<std::string> exportedGeometry;
-
+
const ExportSettings *export_settings;
Mesh * get_mesh(Scene *sce, Object *ob, int apply_modifiers);
diff --git a/source/blender/collada/ImageExporter.cpp b/source/blender/collada/ImageExporter.cpp
index 657037a869a..bb3cebf4cf0 100644
--- a/source/blender/collada/ImageExporter.cpp
+++ b/source/blender/collada/ImageExporter.cpp
@@ -34,7 +34,7 @@ extern "C" {
#include "DNA_image_types.h"
#include "DNA_meshdata_types.h"
-#include "BKE_customdata.h"
+#include "BKE_customdata.h"
#include "BKE_global.h"
#include "BKE_image.h"
#include "BKE_main.h"
@@ -53,7 +53,7 @@ ImagesExporter::ImagesExporter(COLLADASW::StreamWriter *sw, const ExportSettings
{
}
-void ImagesExporter::export_UV_Image(Image *image, bool use_copies)
+void ImagesExporter::export_UV_Image(Image *image, bool use_copies)
{
std::string name(id_name(image));
std::string translated_name(translate_id(name));
@@ -113,11 +113,11 @@ void ImagesExporter::export_UV_Image(Image *image, bool use_copies)
// make absolute source path
BLI_strncpy(source_path, image->name, sizeof(source_path));
- BLI_path_abs(source_path, G.main->name);
+ BLI_path_abs(source_path, BKE_main_blendfile_path_from_global());
BLI_cleanup_path(NULL, source_path);
if (use_copies) {
-
+
// This image is already located on the file system.
// But we want to create copies here.
// To move images into the same export directory.
@@ -155,7 +155,7 @@ void ImagesExporter::export_UV_Image(Image *image, bool use_copies)
bool ImagesExporter::hasImages(Scene *sce)
{
LinkNode *node;
-
+
for (node = this->export_settings->export_set; node; node = node->next) {
Object *ob = (Object *)node->link;
diff --git a/source/blender/collada/ImageExporter.h b/source/blender/collada/ImageExporter.h
index f3dd2b336e4..1867c44ac9c 100644
--- a/source/blender/collada/ImageExporter.h
+++ b/source/blender/collada/ImageExporter.h
@@ -45,7 +45,7 @@ class ImagesExporter: COLLADASW::LibraryImages
{
public:
ImagesExporter(COLLADASW::StreamWriter *sw, const ExportSettings *export_settings);
-
+
void exportImages(Scene *sce);
void operator()(Material *ma, Object *ob);
private:
diff --git a/source/blender/collada/InstanceWriter.cpp b/source/blender/collada/InstanceWriter.cpp
index d96d590597a..68842596550 100644
--- a/source/blender/collada/InstanceWriter.cpp
+++ b/source/blender/collada/InstanceWriter.cpp
@@ -45,7 +45,7 @@ void InstanceWriter::add_material_bindings(COLLADASW::BindMaterial& bind_materia
{
for (int a = 0; a < ob->totcol; a++) {
Material *ma = give_current_material(ob, a + 1);
-
+
COLLADASW::InstanceMaterialList& iml = bind_material.getInstanceMaterialList();
if (ma) {
@@ -54,11 +54,11 @@ void InstanceWriter::add_material_bindings(COLLADASW::BindMaterial& bind_materia
std::ostringstream ostr;
ostr << matid;
COLLADASW::InstanceMaterial im(ostr.str(), COLLADASW::URI(COLLADABU::Utils::EMPTY_STRING, matid));
-
+
// create <bind_vertex_input> for each uv map
Mesh *me = (Mesh *)ob->data;
int totlayer = CustomData_number_of_layers(&me->fdata, CD_MTFACE);
-
+
int map_index = 0;
int active_uv_index = CustomData_get_active_layer_index(&me->fdata, CD_MTFACE) -1;
for (int b = 0; b < totlayer; b++) {
@@ -67,7 +67,7 @@ void InstanceWriter::add_material_bindings(COLLADASW::BindMaterial& bind_materia
im.push_back(COLLADASW::BindVertexInput(name, "TEXCOORD", map_index++));
}
}
-
+
iml.push_back(im);
}
}
diff --git a/source/blender/collada/LightExporter.cpp b/source/blender/collada/LightExporter.cpp
index d17941574d7..11377e06ce8 100644
--- a/source/blender/collada/LightExporter.cpp
+++ b/source/blender/collada/LightExporter.cpp
@@ -54,9 +54,9 @@ LightsExporter::LightsExporter(COLLADASW::StreamWriter *sw, const ExportSettings
void LightsExporter::exportLights(Scene *sce)
{
openLibrary();
-
+
forEachLampObjectInExportSet(sce, *this, this->export_settings->export_set);
-
+
closeLibrary();
}
@@ -67,11 +67,11 @@ void LightsExporter::operator()(Object *ob)
std::string la_name(id_name(la));
COLLADASW::Color col(la->r * la->energy, la->g * la->energy, la->b * la->energy);
float d, constatt, linatt, quadatt;
-
+
d = la->dist;
-
+
constatt = 1.0f;
-
+
if (la->falloff_type == LA_FALLOFF_INVLINEAR) {
linatt = 1.0f / d;
quadatt = 0.0f;
@@ -80,7 +80,7 @@ void LightsExporter::operator()(Object *ob)
linatt = 0.0f;
quadatt = 1.0f / (d * d);
}
-
+
// sun
if (la->type == LA_SUN) {
COLLADASW::DirectionalLight cla(mSW, la_id, la_name);
@@ -130,7 +130,7 @@ void LightsExporter::operator()(Object *ob)
exportBlenderProfile(cla, la);
addLight(cla);
}
-
+
}
bool LightsExporter::exportBlenderProfile(COLLADASW::Light &cla, Lamp *la)
@@ -164,6 +164,6 @@ bool LightsExporter::exportBlenderProfile(COLLADASW::Light &cla, Lamp *la)
cla.addExtraTechniqueParameter("blender", "area_size", la->area_size);
cla.addExtraTechniqueParameter("blender", "area_sizey", la->area_sizey);
cla.addExtraTechniqueParameter("blender", "area_sizez", la->area_sizez);
-
+
return true;
}
diff --git a/source/blender/collada/MaterialExporter.h b/source/blender/collada/MaterialExporter.h
index ef44bf8a03e..e830a433432 100644
--- a/source/blender/collada/MaterialExporter.h
+++ b/source/blender/collada/MaterialExporter.h
@@ -65,7 +65,7 @@ class ForEachMaterialFunctor
Functor *f;
public:
ForEachMaterialFunctor(Functor*f) : f(f) {}
-
+
void operator ()(Object *ob)
{
int a;
diff --git a/source/blender/collada/MeshImporter.cpp b/source/blender/collada/MeshImporter.cpp
index add4a93bccd..e95f8ed0888 100644
--- a/source/blender/collada/MeshImporter.cpp
+++ b/source/blender/collada/MeshImporter.cpp
@@ -154,7 +154,7 @@ void UVDataWrapper::getUV(int uv_index, float *uv)
if (values->empty()) return;
uv[0] = (*values)[uv_index * stride];
uv[1] = (*values)[uv_index * stride + 1];
-
+
}
break;
case COLLADAFW::MeshVertexData::DATA_TYPE_DOUBLE:
@@ -163,7 +163,7 @@ void UVDataWrapper::getUV(int uv_index, float *uv)
if (values->empty()) return;
uv[0] = (float)(*values)[uv_index * stride];
uv[1] = (float)(*values)[uv_index * stride + 1];
-
+
}
break;
case COLLADAFW::MeshVertexData::DATA_TYPE_UNKNOWN:
@@ -208,7 +208,7 @@ void VCOLDataWrapper::get_vcol(int v_index, MLoopCol *mloopcol)
}
MeshImporter::MeshImporter(UnitConverter *unitconv, ArmatureImporter *arm, Scene *sce, ViewLayer *view_layer):
- unitconverter(unitconv),
+ unitconverter(unitconv),
scene(sce),
view_layer(view_layer),
armature_importer(arm) {
@@ -320,7 +320,7 @@ bool MeshImporter::is_nice_mesh(COLLADAFW::Mesh *mesh) // checks if mesh has su
return false;
}
}
-
+
return true;
}
@@ -360,7 +360,7 @@ bool MeshImporter::primitive_has_useable_normals(COLLADAFW::MeshPrimitive *mp) {
int normals_count = mp->getNormalIndices().getCount();
if (normals_count > 0) {
int index_count = mp->getPositionIndices().getCount();
- if (index_count == normals_count)
+ if (index_count == normals_count)
has_useable_normals = true;
else {
fprintf(stderr,
@@ -391,7 +391,7 @@ bool MeshImporter::primitive_has_faces(COLLADAFW::MeshPrimitive *mp) {
break;
}
default: {
- has_faces = false;
+ has_faces = false;
break;
}
}
@@ -435,7 +435,7 @@ void MeshImporter::allocate_poly_data(COLLADAFW::Mesh *collada_mesh, Mesh *me)
size_t prim_poly_count = mpvc->getFaceCount();
size_t prim_loop_count = 0;
- for (int index=0; index < prim_poly_count; index++)
+ for (int index=0; index < prim_poly_count; index++)
{
int vcount = get_vertex_count(mpvc, index);
if (vcount > 0) {
@@ -547,7 +547,7 @@ unsigned int MeshImporter::get_loose_edge_count(COLLADAFW::Mesh *mesh) {
// This functin is copied from source/blender/editors/mesh/mesh_data.c
//
// TODO: (As discussed with sergey-) :
-// Maybe move this function to blenderkernel/intern/mesh.c
+// Maybe move this function to blenderkernel/intern/mesh.c
// and add definition to BKE_mesh.c
// =================================================================
void MeshImporter::mesh_add_edges(Mesh *mesh, int len)
@@ -582,7 +582,7 @@ void MeshImporter::mesh_add_edges(Mesh *mesh, int len)
// =================================================================
// Read all loose edges.
-// Important: This function assumes that all edges from existing
+// Important: This function assumes that all edges from existing
// faces have allready been generated and added to me->medge
// So this function MUST be called after read_faces() (see below)
// =================================================================
@@ -593,21 +593,21 @@ void MeshImporter::read_lines(COLLADAFW::Mesh *mesh, Mesh *me)
unsigned int face_edge_count = me->totedge;
/* unsigned int total_edge_count = loose_edge_count + face_edge_count; */ /* UNUSED */
-
+
mesh_add_edges(me, loose_edge_count);
MEdge *med = me->medge + face_edge_count;
COLLADAFW::MeshPrimitiveArray& prim_arr = mesh->getMeshPrimitives();
for (int i = 0; i < prim_arr.getCount(); i++) {
-
+
COLLADAFW::MeshPrimitive *mp = prim_arr[i];
int type = mp->getPrimitiveType();
if (type == COLLADAFW::MeshPrimitive::LINES) {
unsigned int edge_count = mp->getFaceCount();
unsigned int *indices = mp->getPositionIndices().getData();
-
+
for (int j = 0; j < edge_count; j++, med++) {
med->bweight = 0;
med->crease = 0;
@@ -624,7 +624,7 @@ void MeshImporter::read_lines(COLLADAFW::Mesh *mesh, Mesh *me)
// =======================================================================
// Read all faces from TRIANGLES, TRIANGLE_FANS, POLYLIST, POLYGON
-// Important: This function MUST be called before read_lines()
+// Important: This function MUST be called before read_lines()
// Otherwise we will loose all edges from faces (see read_lines() above)
//
// TODO: import uv set names
@@ -632,7 +632,7 @@ void MeshImporter::read_lines(COLLADAFW::Mesh *mesh, Mesh *me)
void MeshImporter::read_polys(COLLADAFW::Mesh *collada_mesh, Mesh *me)
{
unsigned int i;
-
+
allocate_poly_data(collada_mesh, me);
UVDataWrapper uvs(collada_mesh->getUVCoords());
@@ -648,7 +648,7 @@ void MeshImporter::read_polys(COLLADAFW::Mesh *collada_mesh, Mesh *me)
COLLADAFW::MeshVertexData& nor = collada_mesh->getNormals();
for (i = 0; i < prim_arr.getCount(); i++) {
-
+
COLLADAFW::MeshPrimitive *mp = prim_arr[i];
// faces
@@ -661,7 +661,7 @@ void MeshImporter::read_polys(COLLADAFW::Mesh *collada_mesh, Mesh *me)
bool mp_has_faces = primitive_has_faces(mp);
int collada_meshtype = mp->getPrimitiveType();
-
+
// since we cannot set mpoly->mat_nr here, we store a portion of me->mpoly in Primitive
Primitive prim = {mpoly, 0};
@@ -688,7 +688,7 @@ void MeshImporter::read_polys(COLLADAFW::Mesh *collada_mesh, Mesh *me)
mpoly->flag |= ME_SMOOTH;
normal_indices++;
}
-
+
mpoly++;
mloop += 3;
loop_index += 3;
@@ -798,7 +798,7 @@ void MeshImporter::read_polys(COLLADAFW::Mesh *collada_mesh, Mesh *me)
void MeshImporter::get_vector(float v[3], COLLADAFW::MeshVertexData& arr, int i, int stride)
{
i *= stride;
-
+
switch (arr.getType()) {
case COLLADAFW::MeshVertexData::DATA_TYPE_FLOAT:
{
@@ -888,7 +888,7 @@ static bool bc_has_same_material_configuration(Object *ob1, Object *ob2)
{
if (ob1->totcol != ob2->totcol) return false; // not same number of materials
if (ob1->totcol == 0) return false; // no material at all
-
+
for (int index=0; index < ob1->totcol; index++) {
if (ob1->matbits[index] != ob2->matbits[index]) return false; // shouldn't happen
if (ob1->matbits[index] == 0) return false; // shouldn't happen
@@ -1019,34 +1019,34 @@ void MeshImporter::assign_material_to_geom(
short mat_index)
{
const COLLADAFW::UniqueId& ma_uid = cmaterial.getReferencedMaterial();
-
+
// do we know this material?
if (uid_material_map.find(ma_uid) == uid_material_map.end()) {
-
+
fprintf(stderr, "Cannot find material by UID.\n");
return;
}
// first time we get geom_uid, ma_uid pair. Save for later check.
materials_mapped_to_geom.insert(std::pair<COLLADAFW::UniqueId, COLLADAFW::UniqueId>(*geom_uid, ma_uid));
-
+
Material *ma = uid_material_map[ma_uid];
// Attention! This temporaly assigns material to object on purpose!
// See note above.
ob->actcol=0;
assign_material(G.main, ob, ma, mat_index + 1, BKE_MAT_ASSIGN_OBJECT);
-
+
MaterialIdPrimitiveArrayMap& mat_prim_map = geom_uid_mat_mapping_map[*geom_uid];
COLLADAFW::MaterialId mat_id = cmaterial.getMaterialId();
-
+
// assign material indices to mesh faces
if (mat_prim_map.find(mat_id) != mat_prim_map.end()) {
-
+
std::vector<Primitive>& prims = mat_prim_map[mat_id];
-
+
std::vector<Primitive>::iterator it;
-
+
for (it = prims.begin(); it != prims.end(); it++) {
Primitive& prim = *it;
MPoly *mpoly = prim.mpoly;
@@ -1055,7 +1055,7 @@ void MeshImporter::assign_material_to_geom(
mpoly->mat_nr = mat_index;
}
}
- }
+ }
}
Object *MeshImporter::create_mesh_object(COLLADAFW::Node *node, COLLADAFW::InstanceGeometry *geom,
@@ -1063,19 +1063,19 @@ Object *MeshImporter::create_mesh_object(COLLADAFW::Node *node, COLLADAFW::Insta
std::map<COLLADAFW::UniqueId, Material *>& uid_material_map)
{
const COLLADAFW::UniqueId *geom_uid = &geom->getInstanciatedObjectId();
-
+
// check if node instanciates controller or geometry
if (isController) {
-
+
geom_uid = armature_importer->get_geometry_uid(*geom_uid);
-
+
if (!geom_uid) {
fprintf(stderr, "Couldn't find a mesh UID by controller's UID.\n");
return NULL;
}
}
else {
-
+
if (uid_mesh_map.find(*geom_uid) == uid_mesh_map.end()) {
// this could happen if a mesh was not created
// (e.g. if it contains unsupported geometry)
@@ -1084,11 +1084,11 @@ Object *MeshImporter::create_mesh_object(COLLADAFW::Node *node, COLLADAFW::Insta
}
}
if (!uid_mesh_map[*geom_uid]) return NULL;
-
+
// name Object
const std::string& id = node->getName().size() ? node->getName() : node->getOriginalId();
const char *name = (id.length()) ? id.c_str() : NULL;
-
+
// add object
Object *ob = bc_add_object(scene, view_layer, OB_MESH, name);
bc_set_mark(ob); // used later for material assignement optimization
@@ -1097,7 +1097,7 @@ Object *MeshImporter::create_mesh_object(COLLADAFW::Node *node, COLLADAFW::Insta
// store object pointer for ArmatureImporter
uid_object_map[*geom_uid] = ob;
imported_objects.push_back(ob);
-
+
// replace ob->data freeing the old one
Mesh *old_mesh = (Mesh *)ob->data;
Mesh *new_mesh = uid_mesh_map[*geom_uid];
@@ -1110,10 +1110,10 @@ Object *MeshImporter::create_mesh_object(COLLADAFW::Node *node, COLLADAFW::Insta
COLLADAFW::MaterialBindingArray& mat_array =
geom->getMaterialBindings();
-
+
// loop through geom's materials
for (unsigned int i = 0; i < mat_array.getCount(); i++) {
-
+
if (mat_array[i].getReferencedMaterial().isValid()) {
assign_material_to_geom(
mat_array[i], uid_material_map, ob, geom_uid,
@@ -1136,14 +1136,14 @@ bool MeshImporter::write_geometry(const COLLADAFW::Geometry *geom)
fprintf(stderr, "Mesh type %s is not supported\n", bc_geomTypeToStr(geom->getType()));
return true;
}
-
+
COLLADAFW::Mesh *mesh = (COLLADAFW::Mesh *)geom;
-
+
if (!is_nice_mesh(mesh)) {
fprintf(stderr, "Ignoring mesh %s\n", bc_get_dae_name(mesh).c_str());
return true;
}
-
+
const std::string& str_geom_id = mesh->getName().size() ? mesh->getName() : mesh->getOriginalId();
Mesh *me = BKE_mesh_add(G.main, (char *)str_geom_id.c_str());
id_us_min(&me->id); // is already 1 here, but will be set later in BKE_mesh_assign_object
@@ -1152,7 +1152,7 @@ bool MeshImporter::write_geometry(const COLLADAFW::Geometry *geom)
// mesh_geom_map needed to map mesh to its geometry name (for shape key naming)
this->uid_mesh_map[mesh->getUniqueId()] = me;
this->mesh_geom_map[std::string(me->id.name)] = str_geom_id;
-
+
read_vertices(mesh, me);
read_polys(mesh, me);
diff --git a/source/blender/collada/MeshImporter.h b/source/blender/collada/MeshImporter.h
index 09b3005d795..c98126916d7 100644
--- a/source/blender/collada/MeshImporter.h
+++ b/source/blender/collada/MeshImporter.h
@@ -109,7 +109,7 @@ private:
typedef std::map<COLLADAFW::MaterialId, std::vector<Primitive> > MaterialIdPrimitiveArrayMap;
std::map<COLLADAFW::UniqueId, MaterialIdPrimitiveArrayMap> geom_uid_mat_mapping_map; // crazy name!
std::multimap<COLLADAFW::UniqueId, COLLADAFW::UniqueId> materials_mapped_to_geom; //< materials that have already been mapped to a geometry. A pair of geom uid and mat uid, one geometry can have several materials
-
+
bool set_poly_indices(MPoly *mpoly,
MLoop *mloop,
int loop_index,
@@ -135,7 +135,7 @@ private:
bool is_nice_mesh(COLLADAFW::Mesh *mesh);
void read_vertices(COLLADAFW::Mesh *mesh, Mesh *me);
-
+
bool primitive_has_useable_normals(COLLADAFW::MeshPrimitive *mp);
bool primitive_has_faces(COLLADAFW::MeshPrimitive *mp);
@@ -165,7 +165,7 @@ public:
virtual Object *get_object_by_geom_uid(const COLLADAFW::UniqueId& geom_uid);
virtual Mesh *get_mesh_by_geom_uid(const COLLADAFW::UniqueId& geom_uid);
-
+
void optimize_material_assignements();
void assign_material_to_geom(
@@ -173,8 +173,8 @@ public:
std::map<COLLADAFW::UniqueId, Material*>& uid_material_map,
Object *ob, const COLLADAFW::UniqueId *geom_uid,
short mat_index);
-
-
+
+
Object *create_mesh_object(COLLADAFW::Node *node, COLLADAFW::InstanceGeometry *geom,
bool isController,
std::map<COLLADAFW::UniqueId, Material*>& uid_material_map);
diff --git a/source/blender/collada/SceneExporter.cpp b/source/blender/collada/SceneExporter.cpp
index 5d1df800746..d909203488e 100644
--- a/source/blender/collada/SceneExporter.cpp
+++ b/source/blender/collada/SceneExporter.cpp
@@ -39,18 +39,18 @@ SceneExporter::SceneExporter(COLLADASW::StreamWriter *sw, ArmatureExporter *arm,
{
}
-void SceneExporter::exportScene(Depsgraph *depsgraph, Scene *sce)
+void SceneExporter::exportScene(bContext *C, Depsgraph *depsgraph, Scene *sce)
{
// <library_visual_scenes> <visual_scene>
std::string id_naming = id_name(sce);
openVisualScene(translate_id(id_naming), id_naming);
- exportHierarchy(depsgraph, sce);
+ exportHierarchy(C, depsgraph, sce);
closeVisualScene();
closeLibrary();
}
-void SceneExporter::exportHierarchy(Depsgraph *depsgraph, Scene *sce)
-{
+void SceneExporter::exportHierarchy(bContext *C, Depsgraph *depsgraph, Scene *sce)
+{
LinkNode *node;
std::vector<Object *> base_objects;
@@ -59,7 +59,7 @@ void SceneExporter::exportHierarchy(Depsgraph *depsgraph, Scene *sce)
Object *ob = (Object *) node->link;
ob->id.tag |= LIB_TAG_DOIT;
}
-
+
// Now find all exportable base ojects (highest in export hierarchy)
for (node = this->export_settings->export_set; node; node = node->next) {
Object *ob = (Object *) node->link;
@@ -81,13 +81,13 @@ void SceneExporter::exportHierarchy(Depsgraph *depsgraph, Scene *sce)
Object *ob = base_objects[index];
if (bc_is_marked(ob)) {
bc_remove_mark(ob);
- writeNodes(depsgraph, ob, sce);
+ writeNodes(C, depsgraph, ob, sce);
}
}
}
-void SceneExporter::writeNodes(Depsgraph *depsgraph, Object *ob, Scene *sce)
+void SceneExporter::writeNodes(bContext *C, Depsgraph *depsgraph, Object *ob, Scene *sce)
{
// Add associated armature first if available
bool armature_exported = false;
@@ -96,7 +96,7 @@ void SceneExporter::writeNodes(Depsgraph *depsgraph, Object *ob, Scene *sce)
armature_exported = bc_is_in_Export_set(this->export_settings->export_set, ob_arm);
if (armature_exported && bc_is_marked(ob_arm)) {
bc_remove_mark(ob_arm);
- writeNodes(depsgraph, ob_arm, sce);
+ writeNodes(C, depsgraph, ob_arm, sce);
armature_exported = true;
}
}
@@ -155,7 +155,7 @@ void SceneExporter::writeNodes(Depsgraph *depsgraph, Object *ob, Scene *sce)
// <instance_controller>
else if (ob->type == OB_ARMATURE) {
- arm_exporter->add_armature_bones(depsgraph, ob, sce, this, child_objects);
+ arm_exporter->add_armature_bones(C, depsgraph, ob, sce, this, child_objects);
}
// <instance_camera>
@@ -203,17 +203,17 @@ void SceneExporter::writeNodes(Depsgraph *depsgraph, Object *ob, Scene *sce)
colladaNode.addExtraTechniqueChildParameter("blender",con_tag,"rot_error",con->rot_error);
colladaNode.addExtraTechniqueChildParameter("blender",con_tag,"tar_space",con->tarspace);
colladaNode.addExtraTechniqueChildParameter("blender",con_tag,"lin_error",con->lin_error);
-
- //not ideal: add the target object name as another parameter.
+
+ //not ideal: add the target object name as another parameter.
//No real mapping in the .dae
//Need support for multiple target objects also.
const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
ListBase targets = {NULL, NULL};
if (cti && cti->get_constraint_targets) {
-
+
bConstraintTarget *ct;
Object *obtar;
-
+
cti->get_constraint_targets(con, &targets);
for (ct = (bConstraintTarget *)targets.first; ct; ct = ct->next) {
@@ -234,7 +234,7 @@ void SceneExporter::writeNodes(Depsgraph *depsgraph, Object *ob, Scene *sce)
for (std::list<Object *>::iterator i = child_objects.begin(); i != child_objects.end(); ++i) {
if (bc_is_marked(*i)) {
bc_remove_mark(*i);
- writeNodes(depsgraph, *i, sce);
+ writeNodes(C, depsgraph, *i, sce);
}
}
diff --git a/source/blender/collada/SceneExporter.h b/source/blender/collada/SceneExporter.h
index c330aa81e91..91f98063020 100644
--- a/source/blender/collada/SceneExporter.h
+++ b/source/blender/collada/SceneExporter.h
@@ -96,13 +96,13 @@ class SceneExporter: COLLADASW::LibraryVisualScenes, protected TransformWriter,
{
public:
SceneExporter(COLLADASW::StreamWriter *sw, ArmatureExporter *arm, const ExportSettings *export_settings);
- void exportScene(Depsgraph *depsgraph, Scene *sce);
+ void exportScene(bContext *C, Depsgraph *depsgraph, Scene *sce);
private:
friend class ArmatureExporter;
- void exportHierarchy(struct Depsgraph *depsgraph, Scene *sce);
- void writeNodes(struct Depsgraph *depsgraph, Object *ob, Scene *sce);
-
+ void exportHierarchy(bContext *C, struct Depsgraph *depsgraph, Scene *sce);
+ void writeNodes(bContext *C, struct Depsgraph *depsgraph, Object *ob, Scene *sce);
+
ArmatureExporter *arm_exporter;
const ExportSettings *export_settings;
};
diff --git a/source/blender/collada/SkinInfo.cpp b/source/blender/collada/SkinInfo.cpp
index a2cb8237d08..7ec3f04aabf 100644
--- a/source/blender/collada/SkinInfo.cpp
+++ b/source/blender/collada/SkinInfo.cpp
@@ -121,7 +121,7 @@ void SkinInfo::borrow_skin_controller_data(const COLLADAFW::SkinControllerData *
unit_converter->dae_matrix_to_mat4_(bind_shape_matrix, skin->getBindShapeMatrix());
}
-
+
void SkinInfo::free()
{
joints_per_vertex.releaseMemory();
@@ -199,7 +199,7 @@ const COLLADAFW::UniqueId& SkinInfo::get_controller_uid()
}
// check if this skin controller references a joint or any descendant of it
-//
+//
// some nodes may not be referenced by SkinController,
// in this case to determine if the node belongs to this armature,
// we need to search down the tree
@@ -259,9 +259,9 @@ void SkinInfo::link_armature(bContext *C, Object *ob, std::map<COLLADAFW::Unique
// skip joints that have invalid UID
if ((*it).joint_uid == COLLADAFW::UniqueId::INVALID) continue;
-
+
// name group by joint node name
-
+
if (joint_by_uid.find((*it).joint_uid) != joint_by_uid.end()) {
name = bc_get_joint_name(joint_by_uid[(*it).joint_uid]);
}
diff --git a/source/blender/collada/SkinInfo.h b/source/blender/collada/SkinInfo.h
index a399bff9e3c..fdfee0a943a 100644
--- a/source/blender/collada/SkinInfo.h
+++ b/source/blender/collada/SkinInfo.h
@@ -88,7 +88,7 @@ public:
void transfer_uint_array_data_const(const COLLADAFW::UIntValuesArray& src, COLLADAFW::UIntValuesArray& dest);
void borrow_skin_controller_data(const COLLADAFW::SkinControllerData* skin);
-
+
void free();
// using inverse bind matrices to construct armature
@@ -110,7 +110,7 @@ public:
const COLLADAFW::UniqueId& get_controller_uid();
// check if this skin controller references a joint or any descendant of it
- //
+ //
// some nodes may not be referenced by SkinController,
// in this case to determine if the node belongs to this armature,
// we need to search down the tree
diff --git a/source/blender/collada/TransformReader.cpp b/source/blender/collada/TransformReader.cpp
index 7f742be7e30..bf9c34153b7 100644
--- a/source/blender/collada/TransformReader.cpp
+++ b/source/blender/collada/TransformReader.cpp
@@ -54,7 +54,7 @@ void TransformReader::get_node_mat(
float copy[4][4];
unit_m4(mat);
-
+
for (unsigned int i = 0; i < node->getTransformations().getCount(); i++) {
COLLADAFW::Transformation *tm = node->getTransformations()[i];
@@ -87,11 +87,11 @@ void TransformReader::get_node_mat(
copy_m4_m4(copy, mat);
mul_m4_m4m4(mat, copy, cur);
-
+
if (animation_map) {
// AnimationList that drives this Transformation
const COLLADAFW::UniqueId& anim_list_id = tm->getAnimationList();
-
+
// store this so later we can link animation data with ob
Animation anim = {ob, node, tm};
(*animation_map)[anim_list_id] = anim;
diff --git a/source/blender/collada/TransformReader.h b/source/blender/collada/TransformReader.h
index 08bb17ccac1..6544aa1c040 100644
--- a/source/blender/collada/TransformReader.h
+++ b/source/blender/collada/TransformReader.h
@@ -19,7 +19,7 @@
*
* ***** END GPL LICENSE BLOCK *****
*/
-
+
/** \file TransformReader.h
* \ingroup collada
*/
diff --git a/source/blender/collada/TransformWriter.cpp b/source/blender/collada/TransformWriter.cpp
index 1fb54e99147..9f75a604f96 100644
--- a/source/blender/collada/TransformWriter.cpp
+++ b/source/blender/collada/TransformWriter.cpp
@@ -119,7 +119,7 @@ void TransformWriter::add_node_transform_ob(COLLADASW::Node& node, Object *ob,
{
float loc[3], rot[3], scale[3];
bc_decompose(f_obmat, loc, rot, NULL, scale);
- add_transform(node, loc, rot, scale);
+ add_transform(node, loc, rot, scale);
break;
}
}
diff --git a/source/blender/collada/collada.cpp b/source/blender/collada/collada.cpp
index 5def6638df6..bf310cb24d8 100644
--- a/source/blender/collada/collada.cpp
+++ b/source/blender/collada/collada.cpp
@@ -51,7 +51,8 @@ int collada_import(bContext *C, ImportSettings *import_settings)
return (imp.import())? 1:0;
}
-int collada_export(Depsgraph *depsgraph,
+int collada_export(bContext *C,
+ Depsgraph *depsgraph,
Scene *sce,
ExportSettings *export_settings)
{
@@ -80,7 +81,7 @@ int collada_export(Depsgraph *depsgraph,
}
DocumentExporter exporter(depsgraph, export_settings);
- int status = exporter.exportCurrentScene(sce);
+ int status = exporter.exportCurrentScene(C, sce);
BLI_linklist_free(export_settings->export_set, NULL);
diff --git a/source/blender/collada/collada.h b/source/blender/collada/collada.h
index 5cf526af1f2..a47463b5a7a 100644
--- a/source/blender/collada/collada.h
+++ b/source/blender/collada/collada.h
@@ -51,8 +51,8 @@ struct ViewLayer;
int collada_import(struct bContext *C,
ImportSettings *import_settings);
-
-int collada_export(struct Depsgraph *depsgraph,
+int collada_export(struct bContext *C,
+ struct Depsgraph *depsgraph,
struct Scene *sce,
ExportSettings *export_settings);
diff --git a/source/blender/collada/collada_internal.h b/source/blender/collada/collada_internal.h
index 299e13326ce..1eac5b68778 100644
--- a/source/blender/collada/collada_internal.h
+++ b/source/blender/collada/collada_internal.h
@@ -51,7 +51,7 @@ private:
float y_up_mat4[4][4];
float z_up_mat4[4][4];
float scale_mat4[4][4];
-
+
public:
enum UnitSystem {
@@ -66,11 +66,11 @@ public:
void read_asset(const COLLADAFW::FileInfo *asset);
void convertVector3(COLLADABU::Math::Vector3 &vec, float *v);
-
+
UnitConverter::UnitSystem isMetricSystem(void);
-
+
float getLinearMeter(void);
-
+
// TODO need also for angle conversion, time conversion...
void dae_matrix_to_mat4_(float out[4][4], const COLLADABU::Math::Matrix4& in);
diff --git a/source/blender/collada/collada_utils.cpp b/source/blender/collada/collada_utils.cpp
index bf441effc81..945dda68745 100644
--- a/source/blender/collada/collada_utils.cpp
+++ b/source/blender/collada/collada_utils.cpp
@@ -77,7 +77,7 @@ float bc_get_float_value(const COLLADAFW::FloatOrDoubleArray& array, unsigned in
if (array.getType() == COLLADAFW::MeshVertexData::DATA_TYPE_FLOAT)
return array.getFloatValues()->getData()[index];
- else
+ else
return array.getDoubleValues()->getData()[index];
}
@@ -85,10 +85,10 @@ float bc_get_float_value(const COLLADAFW::FloatOrDoubleArray& array, unsigned in
int bc_test_parent_loop(Object *par, Object *ob)
{
/* test if 'ob' is a parent somewhere in par's parents */
-
+
if (par == NULL) return 0;
if (ob == par) return 1;
-
+
return bc_test_parent_loop(par->parent, ob);
}
@@ -117,7 +117,7 @@ int bc_set_parent(Object *ob, Object *par, bContext *C, bool is_parent_space)
mul_m4_m4m4(mat, par->obmat, ob->obmat);
copy_m4_m4(ob->obmat, mat);
}
-
+
// apply child obmat (i.e. decompose it into rot/loc/size)
BKE_object_apply_mat4(ob, ob->obmat, 0, 0);
@@ -231,7 +231,7 @@ Object *bc_get_assigned_armature(Object *ob)
// IMPORTANT: This function expects that
// all exported objects have set:
// ob->id.tag & LIB_TAG_DOIT
-Object *bc_get_highest_selected_ancestor_or_self(LinkNode *export_set, Object *ob)
+Object *bc_get_highest_selected_ancestor_or_self(LinkNode *export_set, Object *ob)
{
Object *ancestor = ob;
while (ob->parent && bc_is_marked(ob->parent)) {
@@ -256,7 +256,7 @@ bool bc_is_in_Export_set(LinkNode *export_set, Object *ob)
bool bc_has_object_type(LinkNode *export_set, short obtype)
{
LinkNode *node;
-
+
for (node = export_set; node; node = node->next) {
Object *ob = (Object *)node->link;
/* XXX - why is this checking for ob->data? - we could be looking for empties */
@@ -290,7 +290,7 @@ void bc_bubble_sort_by_Object_name(LinkNode *export_set)
for (node = export_set; node->next && !sorted; node = node->next) {
sorted = true;
-
+
LinkNode *current;
for (current = export_set; current->next; current = current->next) {
Object *a = (Object *)current->link;
@@ -301,12 +301,12 @@ void bc_bubble_sort_by_Object_name(LinkNode *export_set)
current->next->link = a;
sorted = false;
}
-
+
}
}
}
-/* Check if a bone is the top most exportable bone in the bone hierarchy.
+/* Check if a bone is the top most exportable bone in the bone hierarchy.
* When deform_bones_only == false, then only bones with NO parent
* can be root bones. Otherwise the top most deform bones in the hierarchy
* are root bones.
@@ -367,13 +367,13 @@ void bc_match_scale(Object *ob, UnitConverter &bc_unit, bool scale_to_scene)
BKE_object_apply_mat4(ob, ob->obmat, 0, 0);
}
-void bc_match_scale(std::vector<Object *> *objects_done,
+void bc_match_scale(std::vector<Object *> *objects_done,
UnitConverter &bc_unit,
bool scale_to_scene)
{
for (std::vector<Object *>::iterator it = objects_done->begin();
it != objects_done->end();
- ++it)
+ ++it)
{
Object *ob = *it;
if (ob -> parent == NULL) {
@@ -781,7 +781,7 @@ float bc_get_property(Bone *bone, std::string key, float def)
/**
* Read a custom bone property and convert to matrix
* Return true if conversion was succesfull
-*
+*
* Return false if:
* - the property does not exist
* - is not an array of size 16
diff --git a/source/blender/collada/collada_utils.h b/source/blender/collada/collada_utils.h
index 89765375afb..20c569834d8 100644
--- a/source/blender/collada/collada_utils.h
+++ b/source/blender/collada/collada_utils.h
@@ -92,8 +92,8 @@ extern void bc_bubble_sort_by_Object_name(LinkNode *export_set);
extern bool bc_is_root_bone(Bone *aBone, bool deform_bones_only);
extern int bc_get_active_UVLayer(Object *ob);
-extern std::string bc_replace_string(std::string data, const std::string& pattern, const std::string& replacement);
-extern std::string bc_url_encode(std::string data);
+extern std::string bc_replace_string(std::string data, const std::string& pattern, const std::string& replacement);
+extern std::string bc_url_encode(std::string data);
extern void bc_match_scale(Object *ob, UnitConverter &bc_unit, bool scale_to_scene);
extern void bc_match_scale(std::vector<Object *> *objects_done, UnitConverter &unit_converter, bool scale_to_scene);
@@ -135,8 +135,8 @@ class BCPolygonNormalsIndices
normal_indices.push_back(index);
}
- unsigned int operator[](unsigned int i) {
- return normal_indices[i];
+ unsigned int operator[](unsigned int i) {
+ return normal_indices[i];
}
};
diff --git a/source/blender/compositor/operations/COM_OutputFileMultiViewOperation.cpp b/source/blender/compositor/operations/COM_OutputFileMultiViewOperation.cpp
index 7786359c06a..f7fcf63fabb 100644
--- a/source/blender/compositor/operations/COM_OutputFileMultiViewOperation.cpp
+++ b/source/blender/compositor/operations/COM_OutputFileMultiViewOperation.cpp
@@ -31,6 +31,7 @@
#include "BLI_string.h"
#include "BKE_image.h"
#include "BKE_global.h"
+#include "BKE_library.h"
#include "BKE_main.h"
#include "BKE_scene.h"
@@ -100,11 +101,10 @@ void OutputOpenExrSingleLayerMultiViewOperation::deinitExecution()
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,
+ filename, this->m_path, BKE_main_blendfile_path_from_global(), this->m_rd->cfra, R_IMF_IMTYPE_OPENEXR,
(this->m_rd->scemode & R_EXTENSION) != 0, true, NULL);
exrhandle = this->get_handle(filename);
@@ -190,11 +190,10 @@ void OutputOpenExrMultiLayerMultiViewOperation::deinitExecution()
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,
+ filename, this->m_path, BKE_main_blendfile_path_from_global(), this->m_rd->cfra, R_IMF_IMTYPE_MULTILAYER,
(this->m_rd->scemode & R_EXTENSION) != 0, true, NULL);
exrhandle = this->get_handle(filename);
@@ -283,7 +282,6 @@ void OutputStereoOperation::deinitExecution()
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;
@@ -307,7 +305,7 @@ void OutputStereoOperation::deinitExecution()
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,
+ filename, this->m_path, BKE_main_blendfile_path_from_global(), 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);
diff --git a/source/blender/compositor/operations/COM_OutputFileOperation.cpp b/source/blender/compositor/operations/COM_OutputFileOperation.cpp
index db816816034..39877e35605 100644
--- a/source/blender/compositor/operations/COM_OutputFileOperation.cpp
+++ b/source/blender/compositor/operations/COM_OutputFileOperation.cpp
@@ -28,6 +28,7 @@
#include "BLI_string.h"
#include "BKE_image.h"
#include "BKE_global.h"
+#include "BKE_library.h"
#include "BKE_main.h"
#include "BKE_scene.h"
@@ -185,7 +186,6 @@ void OutputSingleLayerOperation::deinitExecution()
int size = get_datatype_size(this->m_datatype);
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;
@@ -200,7 +200,7 @@ void OutputSingleLayerOperation::deinitExecution()
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,
+ filename, this->m_path, BKE_main_blendfile_path_from_global(), 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))
@@ -271,14 +271,13 @@ void OutputOpenExrMultiLayerOperation::deinitExecution()
unsigned int width = this->getWidth();
unsigned int height = this->getHeight();
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,
+ filename, this->m_path, BKE_main_blendfile_path_from_global(), this->m_rd->cfra, R_IMF_IMTYPE_MULTILAYER,
(this->m_rd->scemode & R_EXTENSION) != 0, true, suffix);
BLI_make_existing_file(filename);
diff --git a/source/blender/datatoc/datatoc_icon.c b/source/blender/datatoc/datatoc_icon.c
index 92048f32a28..e5f82ae09c8 100644
--- a/source/blender/datatoc/datatoc_icon.c
+++ b/source/blender/datatoc/datatoc_icon.c
@@ -386,7 +386,7 @@ int main(int argc, char **argv)
{
const char *path_src;
const char *file_dst;
-
+
if (argc < 3) {
printf("Usage: datatoc_icon <dir_icons> <data_icon_to.png>\n");
diff --git a/source/blender/depsgraph/DEG_depsgraph_query.h b/source/blender/depsgraph/DEG_depsgraph_query.h
index 7a4d9a19335..1c4e11d1197 100644
--- a/source/blender/depsgraph/DEG_depsgraph_query.h
+++ b/source/blender/depsgraph/DEG_depsgraph_query.h
@@ -107,14 +107,8 @@ enum {
DEG_ITER_OBJECT_FLAG_DUPLI = (1 << 4),
};
-typedef enum eDepsObjectIteratorMode {
- DEG_ITER_OBJECT_MODE_VIEWPORT = 0,
- DEG_ITER_OBJECT_MODE_RENDER = 1,
-} eDepsObjectIteratorMode;
-
typedef struct DEGObjectIterData {
struct Depsgraph *graph;
- eDepsObjectIteratorMode mode;
int flag;
struct Scene *scene;
@@ -152,11 +146,10 @@ void DEG_iterator_objects_end(struct BLI_Iterator *iter);
* Although they are available they have no overrides (collection_properties)
* and will crash if you try to access it.
*/
-#define DEG_OBJECT_ITER_BEGIN(graph_, instance_, mode_, flag_) \
+#define DEG_OBJECT_ITER_BEGIN(graph_, instance_, flag_) \
{ \
DEGObjectIterData data_ = { \
graph_, \
- mode_, \
flag_ \
}; \
\
@@ -172,8 +165,8 @@ void DEG_iterator_objects_end(struct BLI_Iterator *iter);
/**
* Depsgraph objects iterator for draw manager and final render
*/
-#define DEG_OBJECT_ITER_FOR_RENDER_ENGINE_BEGIN(graph_, instance_, mode_) \
- DEG_OBJECT_ITER_BEGIN(graph_, instance_, mode_, \
+#define DEG_OBJECT_ITER_FOR_RENDER_ENGINE_BEGIN(graph_, instance_) \
+ DEG_OBJECT_ITER_BEGIN(graph_, instance_, \
DEG_ITER_OBJECT_FLAG_LINKED_DIRECTLY | \
DEG_ITER_OBJECT_FLAG_LINKED_VIA_SET | \
DEG_ITER_OBJECT_FLAG_VISIBLE | \
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_cycle.cc b/source/blender/depsgraph/intern/builder/deg_builder_cycle.cc
index 026aa309b02..feaba1a4aa8 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_cycle.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder_cycle.cc
@@ -68,7 +68,9 @@ struct CyclesSolverState {
: graph(graph),
traversal_stack(BLI_stack_new(sizeof(StackEntry),
"DEG detect cycles stack")),
- num_cycles(0) {
+ num_cycles(0)
+ {
+ /* pass */
}
~CyclesSolverState() {
BLI_stack_free(traversal_stack);
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc b/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc
index f01baed06c3..aaf96a47711 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc
@@ -378,17 +378,32 @@ void DepsgraphNodeBuilder::end_build()
}
}
-void DepsgraphNodeBuilder::build_id(ID* id) {
+void DepsgraphNodeBuilder::build_id(ID *id) {
if (id == NULL) {
return;
}
switch (GS(id->name)) {
+ case ID_AR:
+ build_armature((bArmature *)id);
+ break;
+ case ID_CA:
+ build_camera((Camera *)id);
+ break;
case ID_GR:
- build_collection((Collection *)id);
+ build_collection(DEG_COLLECTION_OWNER_UNKNOWN, (Collection *)id);
break;
case ID_OB:
build_object(-1, (Object *)id, DEG_ID_LINKED_INDIRECTLY);
break;
+ case ID_KE:
+ build_shapekeys((Key *)id);
+ break;
+ case ID_LA:
+ build_lamp((Lamp *)id);
+ break;
+ case ID_LP:
+ build_lightprobe((LightProbe *)id);
+ break;
case ID_NT:
build_nodetree((bNodeTree *)id);
break;
@@ -410,33 +425,45 @@ void DepsgraphNodeBuilder::build_id(ID* id) {
case ID_MC:
build_movieclip((MovieClip *)id);
break;
+ case ID_ME:
+ case ID_CU:
+ case ID_MB:
+ case ID_LT:
+ build_object_data_geometry_datablock(id);
+ break;
default:
fprintf(stderr, "Unhandled ID %s\n", id->name);
+ BLI_assert(!"Should never happen");
+ break;
}
}
-void DepsgraphNodeBuilder::build_collection(Collection *collection)
+void DepsgraphNodeBuilder::build_collection(
+ eDepsNode_CollectionOwner owner_type,
+ Collection *collection)
{
if (built_map_.checkIsBuiltAndTag(collection)) {
return;
}
-
- const int restrict_flag = (graph_->mode == DAG_EVAL_VIEWPORT) ?
- COLLECTION_RESTRICT_VIEW : COLLECTION_RESTRICT_RENDER;
- if (collection->flag & restrict_flag) {
- return;
+ const bool allow_restrict_flags = (owner_type == DEG_COLLECTION_OWNER_SCENE);
+ if (allow_restrict_flags) {
+ const int restrict_flag = (graph_->mode == DAG_EVAL_VIEWPORT)
+ ? COLLECTION_RESTRICT_VIEW
+ : COLLECTION_RESTRICT_RENDER;
+ if (collection->flag & restrict_flag) {
+ return;
+ }
}
-
+ /* Collection itself. */
+ add_id_node(&collection->id);
/* Build collection objects. */
LISTBASE_FOREACH (CollectionObject *, cob, &collection->gobject) {
build_object(-1, cob->ob, DEG_ID_LINKED_INDIRECTLY);
}
/* Build child collections. */
LISTBASE_FOREACH (CollectionChild *, child, &collection->children) {
- build_collection(child->collection);
+ build_collection(owner_type, child->collection);
}
-
- add_id_node(&collection->id);
}
void DepsgraphNodeBuilder::build_object(int base_index,
@@ -508,7 +535,7 @@ void DepsgraphNodeBuilder::build_object(int base_index,
}
/* Object dupligroup. */
if (object->dup_group != NULL) {
- build_collection(object->dup_group);
+ build_collection(DEG_COLLECTION_OWNER_OBJECT, object->dup_group);
}
}
@@ -549,7 +576,7 @@ void DepsgraphNodeBuilder::build_object_data(Object *object)
case OB_SURF:
case OB_MBALL:
case OB_LATTICE:
- build_obdata_geom(object);
+ build_object_data_geometry(object);
/* TODO(sergey): Only for until we support granular
* update of curves.
*/
@@ -569,13 +596,13 @@ void DepsgraphNodeBuilder::build_object_data(Object *object)
}
break;
case OB_LAMP:
- build_lamp(object);
+ build_object_data_lamp(object);
break;
case OB_CAMERA:
- build_camera(object);
+ build_object_data_camera(object);
break;
case OB_LIGHTPROBE:
- build_lightprobe(object);
+ build_object_data_lightprobe(object);
break;
default:
{
@@ -588,6 +615,28 @@ void DepsgraphNodeBuilder::build_object_data(Object *object)
}
}
+void DepsgraphNodeBuilder::build_object_data_camera(Object *object)
+{
+ Camera *camera = (Camera *)object->data;
+ build_camera(camera);
+}
+
+void DepsgraphNodeBuilder::build_object_data_lamp(Object *object)
+{
+ Lamp *lamp = (Lamp *)object->data;
+ build_lamp(lamp);
+}
+
+void DepsgraphNodeBuilder::build_object_data_lightprobe(Object *object)
+{
+ LightProbe *probe = (LightProbe *)object->data;
+ build_lightprobe(probe);
+ add_operation_node(&object->id,
+ DEG_NODE_TYPE_PARAMETERS,
+ NULL,
+ DEG_OPCODE_LIGHT_PROBE_EVAL);
+}
+
void DepsgraphNodeBuilder::build_object_transform(Object *object)
{
OperationDepsNode *op_node;
@@ -923,7 +972,7 @@ void DepsgraphNodeBuilder::build_particles(Object *object)
break;
case PART_DRAW_GR:
if (part->dup_group != NULL) {
- build_collection(part->dup_group);
+ build_collection(DEG_COLLECTION_OWNER_OBJECT, part->dup_group);
}
break;
}
@@ -968,6 +1017,9 @@ void DepsgraphNodeBuilder::build_cloth(Object *object)
/* Shapekeys */
void DepsgraphNodeBuilder::build_shapekeys(Key *key)
{
+ if (built_map_.checkIsBuiltAndTag(key)) {
+ return;
+ }
build_animdata(&key->id);
add_operation_node(&key->id,
DEG_NODE_TYPE_GEOMETRY,
@@ -977,12 +1029,11 @@ void DepsgraphNodeBuilder::build_shapekeys(Key *key)
/* ObData Geometry Evaluation */
// XXX: what happens if the datablock is shared!
-void DepsgraphNodeBuilder::build_obdata_geom(Object *object)
+void DepsgraphNodeBuilder::build_object_data_geometry(Object *object)
{
OperationDepsNode *op_node;
Scene *scene_cow = get_cow_datablock(scene_);
Object *object_cow = get_cow_datablock(object);
-
/* Temporary uber-update node, which does everything.
* It is for the being we're porting old dependencies into the new system.
* We'll get rid of this node as soon as all the granular update functions
@@ -1005,17 +1056,14 @@ void DepsgraphNodeBuilder::build_obdata_geom(Object *object)
DEG_OPCODE_PLACEHOLDER,
"Eval Init");
op_node->set_as_entry();
-
// TODO: "Done" operation
-
/* Cloth modifier. */
LISTBASE_FOREACH (ModifierData *, md, &object->modifiers) {
if (md->type == eModifierType_Cloth) {
build_cloth(object);
}
}
-
- /* materials */
+ /* Materials. */
if (object->totcol != 0) {
if (object->type == OB_MESH) {
add_operation_node(&object->id,
@@ -1033,37 +1081,36 @@ void DepsgraphNodeBuilder::build_obdata_geom(Object *object)
}
}
}
-
- /* geometry collision */
+ /* Geometry collision. */
if (ELEM(object->type, OB_MESH, OB_CURVE, OB_LATTICE)) {
// add geometry collider relations
}
+ build_object_data_geometry_datablock((ID *)object->data);
+}
- ID *obdata = (ID *)object->data;
+void DepsgraphNodeBuilder::build_object_data_geometry_datablock(ID *obdata)
+{
if (built_map_.checkIsBuiltAndTag(obdata)) {
return;
}
+ OperationDepsNode *op_node;
/* Make sure we've got an ID node before requesting CoW pointer. */
(void) add_id_node((ID *)obdata);
ID *obdata_cow = get_cow_id(obdata);
-
+ /* Animation. */
+ build_animdata(obdata);
/* ShapeKeys */
- Key *key = BKE_key_from_object(object);
+ Key *key = BKE_key_from_id(obdata);
if (key) {
build_shapekeys(key);
}
-
- build_animdata(obdata);
-
/* Nodes for result of obdata's evaluation, and geometry
* evaluation on object.
*/
- switch (object->type) {
- case OB_MESH:
+ const ID_Type id_type = GS(obdata->name);
+ switch (id_type) {
+ case ID_ME:
{
- //Mesh *me = (Mesh *)object->data;
-
- /* evaluation operations */
op_node = add_operation_node(obdata,
DEG_NODE_TYPE_GEOMETRY,
function_bind(BKE_mesh_eval_geometry,
@@ -1074,41 +1121,18 @@ void DepsgraphNodeBuilder::build_obdata_geom(Object *object)
op_node->set_as_entry();
break;
}
-
- case OB_MBALL:
+ case ID_MB:
{
- Object *mom = BKE_mball_basis_find(scene_, object);
- /* NOTE: Only the motherball gets evaluated, it's children are
- * having empty placeholders for the correct relations being built.
- */
- if (mom == object) {
- /* metaball evaluation operations */
- op_node = add_operation_node(obdata,
- DEG_NODE_TYPE_GEOMETRY,
- function_bind(
- BKE_mball_eval_geometry,
- _1,
- (MetaBall *)obdata_cow),
- DEG_OPCODE_PLACEHOLDER,
- "Geometry Eval");
- }
- else {
- op_node = add_operation_node(obdata,
- DEG_NODE_TYPE_GEOMETRY,
- NULL,
- DEG_OPCODE_PLACEHOLDER,
- "Geometry Eval");
- op_node->set_as_entry();
- }
+ op_node = add_operation_node(obdata,
+ DEG_NODE_TYPE_GEOMETRY,
+ NULL,
+ DEG_OPCODE_PLACEHOLDER,
+ "Geometry Eval");
+ op_node->set_as_entry();
break;
}
-
- case OB_CURVE:
- case OB_SURF:
- case OB_FONT:
+ case ID_CU:
{
- /* Curve/nurms evaluation operations. */
- /* - calculate curve geometry (including path) */
op_node = add_operation_node(obdata,
DEG_NODE_TYPE_GEOMETRY,
function_bind(BKE_curve_eval_geometry,
@@ -1127,15 +1151,13 @@ void DepsgraphNodeBuilder::build_obdata_geom(Object *object)
if (cu->taperobj != NULL) {
build_object(-1, cu->taperobj, DEG_ID_LINKED_INDIRECTLY);
}
- if (object->type == OB_FONT && cu->textoncurve != NULL) {
+ if (cu->textoncurve != NULL) {
build_object(-1, cu->textoncurve, DEG_ID_LINKED_INDIRECTLY);
}
break;
}
-
- case OB_LATTICE:
+ case ID_LT:
{
- /* Lattice evaluation operations. */
op_node = add_operation_node(obdata,
DEG_NODE_TYPE_GEOMETRY,
function_bind(BKE_lattice_eval_geometry,
@@ -1146,18 +1168,18 @@ void DepsgraphNodeBuilder::build_obdata_geom(Object *object)
op_node->set_as_entry();
break;
}
+ default:
+ BLI_assert(!"Should not happen");
+ break;
}
-
op_node = add_operation_node(obdata, DEG_NODE_TYPE_GEOMETRY, NULL,
DEG_OPCODE_PLACEHOLDER, "Eval Done");
op_node->set_as_exit();
-
/* Parameters for driver sources. */
add_operation_node(obdata,
DEG_NODE_TYPE_PARAMETERS,
NULL,
DEG_OPCODE_PARAMETERS_EVAL);
-
/* Batch cache. */
add_operation_node(obdata,
DEG_NODE_TYPE_BATCH_CACHE,
@@ -1167,35 +1189,46 @@ void DepsgraphNodeBuilder::build_obdata_geom(Object *object)
DEG_OPCODE_GEOMETRY_SELECT_UPDATE);
}
-/* Cameras */
-void DepsgraphNodeBuilder::build_camera(Object *object)
+void DepsgraphNodeBuilder::build_armature(bArmature *armature)
{
- /* Object data. */
- /* TODO: Link scene-camera links in somehow... */
- Camera *camera = (Camera *)object->data;
- if (built_map_.checkIsBuiltAndTag(camera)) {
+ if (built_map_.checkIsBuiltAndTag(armature)) {
return;
}
- build_animdata(&camera->id);
- add_operation_node(&camera->id,
+ build_animdata(&armature->id);
+ /* Make sure pose is up-to-date with armature updates. */
+ add_operation_node(&armature->id,
DEG_NODE_TYPE_PARAMETERS,
NULL,
- DEG_OPCODE_PARAMETERS_EVAL);
+ DEG_OPCODE_PLACEHOLDER,
+ "Armature Eval");
}
-/* Lamps */
-void DepsgraphNodeBuilder::build_lamp(Object *object)
+void DepsgraphNodeBuilder::build_camera(Camera *camera)
+{
+ if (built_map_.checkIsBuiltAndTag(camera)) {
+ return;
+ }
+ OperationDepsNode *op_node;
+ build_animdata(&camera->id);
+ op_node = add_operation_node(&camera->id,
+ DEG_NODE_TYPE_PARAMETERS,
+ NULL,
+ DEG_OPCODE_PARAMETERS_EVAL);
+ op_node->set_as_exit();
+}
+
+void DepsgraphNodeBuilder::build_lamp(Lamp *lamp)
{
- /* Object data. */
- Lamp *lamp = (Lamp *)object->data;
if (built_map_.checkIsBuiltAndTag(lamp)) {
return;
}
+ OperationDepsNode *op_node;
build_animdata(&lamp->id);
- add_operation_node(&lamp->id,
- DEG_NODE_TYPE_PARAMETERS,
- NULL,
- DEG_OPCODE_PARAMETERS_EVAL);
+ op_node = add_operation_node(&lamp->id,
+ DEG_NODE_TYPE_PARAMETERS,
+ NULL,
+ DEG_OPCODE_PARAMETERS_EVAL);
+ op_node->set_as_exit();
/* lamp's nodetree */
build_nodetree(lamp->nodetree);
}
@@ -1405,9 +1438,8 @@ void DepsgraphNodeBuilder::build_movieclip(MovieClip *clip)
DEG_OPCODE_MOVIECLIP_EVAL);
}
-void DepsgraphNodeBuilder::build_lightprobe(Object *object)
+void DepsgraphNodeBuilder::build_lightprobe(LightProbe *probe)
{
- LightProbe *probe = (LightProbe *)object->data;
if (built_map_.checkIsBuiltAndTag(probe)) {
return;
}
@@ -1415,13 +1447,7 @@ void DepsgraphNodeBuilder::build_lightprobe(Object *object)
add_operation_node(&probe->id,
DEG_NODE_TYPE_PARAMETERS,
NULL,
- DEG_OPCODE_PLACEHOLDER,
- "LightProbe Eval");
- add_operation_node(&object->id,
- DEG_NODE_TYPE_PARAMETERS,
- NULL,
- DEG_OPCODE_PLACEHOLDER,
- "LightProbe Eval");
+ DEG_OPCODE_LIGHT_PROBE_EVAL);
build_animdata(&probe->id);
}
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes.h b/source/blender/depsgraph/intern/builder/deg_builder_nodes.h
index b7c5a33f2c0..72aa5dbe003 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_nodes.h
+++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes.h
@@ -36,7 +36,9 @@
#include "DEG_depsgraph.h"
struct Base;
+struct bArmature;
struct CacheFile;
+struct Camera;
struct bGPdata;
struct ListBase;
struct GHash;
@@ -45,7 +47,9 @@ struct Image;
struct FCurve;
struct Collection;
struct Key;
+struct Lamp;
struct LayerCollection;
+struct LightProbe;
struct Main;
struct Material;
struct Mask;
@@ -155,9 +159,10 @@ struct DepsgraphNodeBuilder {
void build_id(ID* id);
void build_layer_collections(ListBase *lb);
void build_view_layer(Scene *scene,
- ViewLayer *view_layer,
- eDepsNode_LinkedState_Type linked_state);
- void build_collection(Collection *collection);
+ ViewLayer *view_layer,
+ eDepsNode_LinkedState_Type linked_state);
+ void build_collection(eDepsNode_CollectionOwner owner_type,
+ Collection *collection);
void build_object(int base_index,
Object *object,
eDepsNode_LinkedState_Type linked_state);
@@ -165,6 +170,11 @@ struct DepsgraphNodeBuilder {
Object *object,
eDepsNode_LinkedState_Type linked_state);
void build_object_data(Object *object);
+ void build_object_data_camera(Object *object);
+ void build_object_data_geometry(Object *object);
+ void build_object_data_geometry_datablock(ID *obdata);
+ void build_object_data_lamp(Object *object);
+ void build_object_data_lightprobe(Object *object);
void build_object_transform(Object *object);
void build_object_constraints(Object *object);
void build_pose_constraints(Object *object, bPoseChannel *pchan, int pchan_index);
@@ -184,10 +194,10 @@ struct DepsgraphNodeBuilder {
bConstraint *con);
void build_rig(Object *object);
void build_proxy_rig(Object *object);
+ void build_armature(bArmature *armature);
void build_shapekeys(Key *key);
- void build_obdata_geom(Object *object);
- void build_camera(Object *object);
- void build_lamp(Object *object);
+ void build_camera(Camera *camera);
+ void build_lamp(Lamp *lamp);
void build_nodetree(bNodeTree *ntree);
void build_material(Material *ma);
void build_texture(Tex *tex);
@@ -198,7 +208,7 @@ struct DepsgraphNodeBuilder {
void build_cachefile(CacheFile *cache_file);
void build_mask(Mask *mask);
void build_movieclip(MovieClip *clip);
- void build_lightprobe(Object *object);
+ void build_lightprobe(LightProbe *probe);
protected:
struct SavedEntryTag {
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes_rig.cc b/source/blender/depsgraph/intern/builder/deg_builder_nodes_rig.cc
index d3c4ce01674..00d7a5da455 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_nodes_rig.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes_rig.cc
@@ -148,7 +148,6 @@ void DepsgraphNodeBuilder::build_rig(Object *object)
Scene *scene_cow = get_cow_datablock(scene_);
Object *object_cow = get_cow_datablock(object);
OperationDepsNode *op_node;
-
/* Animation and/or drivers linking posebones to base-armature used to
* define them.
*
@@ -158,16 +157,8 @@ void DepsgraphNodeBuilder::build_rig(Object *object)
* mechanism in-between here to ensure that we can use same rig
* multiple times in same scene.
*/
- if (!built_map_.checkIsBuiltAndTag(armature)) {
- build_animdata(&armature->id);
- /* Make sure pose is up-to-date with armature updates. */
- add_operation_node(&armature->id,
- DEG_NODE_TYPE_PARAMETERS,
- NULL,
- DEG_OPCODE_PLACEHOLDER,
- "Armature Eval");
- }
-
+ /* Armature. */
+ build_armature(armature);
/* Rebuild pose if not up to date. */
if (object->pose == NULL || (object->pose->flag & POSE_RECALC)) {
BKE_pose_rebuild(object, armature);
@@ -179,15 +170,13 @@ void DepsgraphNodeBuilder::build_rig(Object *object)
object->adt->recalc |= ADT_RECALC_ANIM;
}
}
-
- /* speed optimization for animation lookups */
+ /* Speed optimization for animation lookups. */
if (object->pose != NULL) {
BKE_pose_channels_hash_make(object->pose);
if (object->pose->flag & POSE_CONSTRAINTS_NEED_UPDATE_FLAGS) {
BKE_pose_update_constraint_flags(object->pose);
}
}
-
/**
* Pose Rig Graph
* ==============
@@ -209,8 +198,7 @@ void DepsgraphNodeBuilder::build_rig(Object *object)
* only so that we can redirect those to point at either the the post-IK/
* post-constraint/post-matrix steps, as needed.
*/
-
- /* pose eval context */
+ /* Pose eval context. */
op_node = add_operation_node(&object->id,
DEG_NODE_TYPE_EVAL_POSE,
function_bind(BKE_pose_eval_init,
@@ -236,8 +224,7 @@ void DepsgraphNodeBuilder::build_rig(Object *object)
object_cow),
DEG_OPCODE_POSE_DONE);
op_node->set_as_exit();
-
- /* bones */
+ /* Bones. */
int pchan_index = 0;
LISTBASE_FOREACH (bPoseChannel *, pchan, &object->pose->chanbase) {
/* Node for bone evaluation. */
@@ -302,25 +289,23 @@ void DepsgraphNodeBuilder::build_rig(Object *object)
break;
}
}
-
/* Custom shape. */
if (pchan->custom != NULL) {
build_object(-1, pchan->custom, DEG_ID_LINKED_INDIRECTLY);
}
-
pchan_index++;
}
}
void DepsgraphNodeBuilder::build_proxy_rig(Object *object)
{
- bArmature *arm = (bArmature *)object->data;
+ bArmature *armature = (bArmature *)object->data;
OperationDepsNode *op_node;
Object *object_cow = get_cow_datablock(object);
/* Sanity check. */
BLI_assert(object->pose != NULL);
- /* Animation. */
- build_animdata(&arm->id);
+ /* Armature. */
+ build_armature(armature);
/* speed optimization for animation lookups */
BKE_pose_channels_hash_make(object->pose);
if (object->pose->flag & POSE_CONSTRAINTS_NEED_UPDATE_FLAGS) {
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes_view_layer.cc b/source/blender/depsgraph/intern/builder/deg_builder_nodes_view_layer.cc
index 3fc97ee3fcf..e2526272570 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_nodes_view_layer.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes_view_layer.cc
@@ -71,13 +71,13 @@ void DepsgraphNodeBuilder::build_layer_collections(ListBase *lb)
COLLECTION_RESTRICT_VIEW : COLLECTION_RESTRICT_RENDER;
for (LayerCollection *lc = (LayerCollection *)lb->first; lc; lc = lc->next) {
- if (!(lc->collection->flag & restrict_flag)) {
- if (!(lc->flag & LAYER_COLLECTION_EXCLUDE)) {
- build_collection(lc->collection);
- }
-
- build_layer_collections(&lc->layer_collections);
+ if (lc->collection->flag & restrict_flag) {
+ continue;
+ }
+ if ((lc->flag & LAYER_COLLECTION_EXCLUDE) == 0) {
+ build_collection(DEG_COLLECTION_OWNER_SCENE, lc->collection);
}
+ build_layer_collections(&lc->layer_collections);
}
}
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc
index d5ea8103742..eb1ee0c1535 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc
@@ -161,6 +161,9 @@ static bool particle_system_depends_on_time(ParticleSystem *psys)
static bool object_particles_depends_on_time(Object *object)
{
+ if (object->type != OB_MESH) {
+ return false;
+ }
LISTBASE_FOREACH (ParticleSystem *, psys, &object->particlesystem) {
if (particle_system_depends_on_time(psys)) {
return true;
@@ -396,12 +399,27 @@ void DepsgraphRelationBuilder::build_id(ID *id)
return;
}
switch (GS(id->name)) {
+ case ID_AR:
+ build_armature((bArmature *)id);
+ break;
+ case ID_CA:
+ build_camera((Camera *)id);
+ break;
case ID_GR:
- build_collection(NULL, (Collection *)id);
+ build_collection(DEG_COLLECTION_OWNER_UNKNOWN, NULL, (Collection *)id);
break;
case ID_OB:
build_object(NULL, (Object *)id);
break;
+ case ID_KE:
+ build_shapekeys((Key *)id);
+ break;
+ case ID_LA:
+ build_lamp((Lamp *)id);
+ break;
+ case ID_LP:
+ build_lightprobe((LightProbe *)id);
+ break;
case ID_NT:
build_nodetree((bNodeTree *)id);
break;
@@ -420,19 +438,33 @@ void DepsgraphRelationBuilder::build_id(ID *id)
case ID_MC:
build_movieclip((MovieClip *)id);
break;
+ case ID_ME:
+ case ID_CU:
+ case ID_MB:
+ case ID_LT:
+ build_object_data_geometry_datablock(id);
+ break;
default:
fprintf(stderr, "Unhandled ID %s\n", id->name);
+ BLI_assert(!"Should never happen");
+ break;
}
}
-void DepsgraphRelationBuilder::build_collection(Object *object, Collection *collection)
+void DepsgraphRelationBuilder::build_collection(
+ eDepsNode_CollectionOwner owner_type,
+ Object *object,
+ Collection *collection)
{
- const int restrict_flag = (graph_->mode == DAG_EVAL_VIEWPORT) ?
- COLLECTION_RESTRICT_VIEW : COLLECTION_RESTRICT_RENDER;
- if (collection->flag & restrict_flag) {
- return;
+ const bool allow_restrict_flags = (owner_type == DEG_COLLECTION_OWNER_SCENE);
+ if (allow_restrict_flags) {
+ const int restrict_flag = (graph_->mode == DAG_EVAL_VIEWPORT)
+ ? COLLECTION_RESTRICT_VIEW
+ : COLLECTION_RESTRICT_RENDER;
+ if (collection->flag & restrict_flag) {
+ return;
+ }
}
-
const bool group_done = built_map_.checkIsBuiltAndTag(collection);
OperationKey object_local_transform_key(object != NULL ? &object->id : NULL,
DEG_NODE_TYPE_TRANSFORM,
@@ -442,12 +474,17 @@ void DepsgraphRelationBuilder::build_collection(Object *object, Collection *coll
build_object(NULL, cob->ob);
}
LISTBASE_FOREACH (CollectionChild *, child, &collection->children) {
- build_collection(NULL, child->collection);
+ build_collection(owner_type, NULL, child->collection);
}
}
if (object != NULL) {
const ListBase group_objects = BKE_collection_object_cache_get(collection);
+ const int base_flag = (graph_->mode == DAG_EVAL_VIEWPORT) ?
+ BASE_VISIBLE_VIEWPORT : BASE_VISIBLE_RENDER;
LISTBASE_FOREACH (Base *, base, &group_objects) {
+ if ((base->flag & base_flag) == 0) {
+ continue;
+ }
ComponentKey dupli_transform_key(&base->object->id, DEG_NODE_TYPE_TRANSFORM);
add_relation(dupli_transform_key, object_local_transform_key, "Dupligroup");
}
@@ -560,7 +597,7 @@ void DepsgraphRelationBuilder::build_object(Base *base, Object *object)
/* Object dupligroup. */
if (object->dup_group != NULL) {
- build_collection(object, object->dup_group);
+ build_collection(DEG_COLLECTION_OWNER_OBJECT, object, object->dup_group);
}
}
@@ -597,7 +634,7 @@ void DepsgraphRelationBuilder::build_object_data(Object *object)
case OB_MBALL:
case OB_LATTICE:
{
- build_obdata_geom(object);
+ build_object_data_geometry(object);
break;
}
case OB_ARMATURE:
@@ -609,13 +646,13 @@ void DepsgraphRelationBuilder::build_object_data(Object *object)
}
break;
case OB_LAMP:
- build_lamp(object);
+ build_object_data_lamp(object);
break;
case OB_CAMERA:
- build_camera(object);
+ build_object_data_camera(object);
break;
case OB_LIGHTPROBE:
- build_lightprobe(object);
+ build_object_data_lightprobe(object);
break;
}
Key *key = BKE_key_from_object(object);
@@ -627,6 +664,37 @@ void DepsgraphRelationBuilder::build_object_data(Object *object)
}
}
+void DepsgraphRelationBuilder::build_object_data_camera(Object *object)
+{
+ Camera *camera = (Camera *)object->data;
+ build_camera(camera);
+ ComponentKey object_parameters_key(&object->id, DEG_NODE_TYPE_PARAMETERS);
+ ComponentKey camera_parameters_key(&camera->id, DEG_NODE_TYPE_PARAMETERS);
+ add_relation(camera_parameters_key, object_parameters_key, "Camera -> Object");
+}
+
+void DepsgraphRelationBuilder::build_object_data_lamp(Object *object)
+{
+ Lamp *lamp = (Lamp *)object->data;
+ build_lamp(lamp);
+ ComponentKey object_parameters_key(&object->id, DEG_NODE_TYPE_PARAMETERS);
+ ComponentKey lamp_parameters_key(&lamp->id, DEG_NODE_TYPE_PARAMETERS);
+ add_relation(lamp_parameters_key, object_parameters_key, "Lamp -> Object");
+}
+
+void DepsgraphRelationBuilder::build_object_data_lightprobe(Object *object)
+{
+ LightProbe *probe = (LightProbe *)object->data;
+ build_lightprobe(probe);
+ OperationKey probe_key(&probe->id,
+ DEG_NODE_TYPE_PARAMETERS,
+ DEG_OPCODE_LIGHT_PROBE_EVAL);
+ OperationKey object_key(&object->id,
+ DEG_NODE_TYPE_PARAMETERS,
+ DEG_OPCODE_LIGHT_PROBE_EVAL);
+ add_relation(probe_key, object_key, "LightProbe Update");
+}
+
void DepsgraphRelationBuilder::build_object_parent(Object *object)
{
/* XXX: for now, need to use the component key (not just direct to the parent op),
@@ -1540,7 +1608,7 @@ void DepsgraphRelationBuilder::build_particles(Object *object)
break;
case PART_DRAW_GR:
if (part->dup_group != NULL) {
- build_collection(NULL, part->dup_group);
+ build_collection(DEG_COLLECTION_OWNER_OBJECT, NULL, part->dup_group);
LISTBASE_FOREACH (CollectionObject *, go, &part->dup_group->gobject) {
build_particles_visualization_object(object,
psys,
@@ -1612,27 +1680,13 @@ void DepsgraphRelationBuilder::build_cloth(Object *object,
}
/* Shapekeys */
-void DepsgraphRelationBuilder::build_shapekeys(ID *obdata, Key *key)
+void DepsgraphRelationBuilder::build_shapekeys(Key *key)
{
- ComponentKey obdata_key(obdata, DEG_NODE_TYPE_GEOMETRY);
-
+ if (built_map_.checkIsBuiltAndTag(key)) {
+ return;
+ }
/* attach animdata to geometry */
build_animdata(&key->id);
-
- if (key->adt) {
- // TODO: this should really be handled in build_animdata, since many of these cases will need it
- if (key->adt->action || key->adt->nla_tracks.first) {
- ComponentKey adt_key(&key->id, DEG_NODE_TYPE_ANIMATION);
- add_relation(adt_key, obdata_key, "Animation");
- }
-
- /* NOTE: individual shapekey drivers are handled above already */
- }
-
- /* attach to geometry */
- // XXX: aren't shapekeys now done as a pseudo-modifier on object?
- //ComponentKey key_key(&key->id, DEG_NODE_TYPE_GEOMETRY); // FIXME: this doesn't exist
- //add_relation(key_key, obdata_key, "Shapekeys");
}
/**
@@ -1640,56 +1694,53 @@ void DepsgraphRelationBuilder::build_shapekeys(ID *obdata, Key *key)
* ==========================
*
* The evaluation of geometry on objects is as follows:
- * - The actual evaluated of the derived geometry (e.g. DerivedMesh, DispList, etc.)
- * occurs in the Geometry component of the object which references this. This includes
- * modifiers, and the temporary "ubereval" for geometry.
- * - Therefore, each user of a piece of shared geometry data ends up evaluating its own
- * version of the stuff, complete with whatever modifiers it may use.
+ * - The actual evaluated of the derived geometry (e.g. DerivedMesh, DispList)
+ * occurs in the Geometry component of the object which references this.
+ * This includes modifiers, and the temporary "ubereval" for geometry.
+ * Therefore, each user of a piece of shared geometry data ends up evaluating
+ * its own version of the stuff, complete with whatever modifiers it may use.
*
- * - The datablocks for the geometry data - "obdata" (e.g. ID_ME, ID_CU, ID_LT, etc.) are used for
+ * - The datablocks for the geometry data - "obdata" (e.g. ID_ME, ID_CU, ID_LT.)
+ * are used for
* 1) calculating the bounding boxes of the geometry data,
- * 2) aggregating inward links from other objects (e.g. for text on curve, etc.)
+ * 2) aggregating inward links from other objects (e.g. for text on curve)
* and also for the links coming from the shapekey datablocks
- * - Animation/Drivers affecting the parameters of the geometry are made to trigger
- * updates on the obdata geometry component, which then trigger downstream
- * re-evaluation of the individual instances of this geometry.
+ * - Animation/Drivers affecting the parameters of the geometry are made to
+ * trigger updates on the obdata geometry component, which then trigger
+ * downstream re-evaluation of the individual instances of this geometry.
*/
-// TODO: Materials and lighting should probably get their own component, instead of being lumped under geometry?
-void DepsgraphRelationBuilder::build_obdata_geom(Object *object)
+void DepsgraphRelationBuilder::build_object_data_geometry(Object *object)
{
ID *obdata = (ID *)object->data;
-
/* Init operation of object-level geometry evaluation. */
- OperationKey geom_init_key(&object->id, DEG_NODE_TYPE_GEOMETRY, DEG_OPCODE_PLACEHOLDER, "Eval Init");
-
- /* get nodes for result of obdata's evaluation, and geometry evaluation on object */
+ OperationKey geom_init_key(&object->id,
+ DEG_NODE_TYPE_GEOMETRY,
+ DEG_OPCODE_PLACEHOLDER,
+ "Eval Init");
+ /* Get nodes for result of obdata's evaluation, and geometry evaluation
+ * on object.
+ */
ComponentKey obdata_geom_key(obdata, DEG_NODE_TYPE_GEOMETRY);
ComponentKey geom_key(&object->id, DEG_NODE_TYPE_GEOMETRY);
-
- /* link components to each other */
+ /* Link components to each other. */
add_relation(obdata_geom_key, geom_key, "Object Geometry Base Data");
-
OperationKey obdata_ubereval_key(&object->id,
DEG_NODE_TYPE_GEOMETRY,
DEG_OPCODE_GEOMETRY_UBEREVAL);
-
- /* Special case: modifiers and DerivedMesh creation queries scene for various
- * things like data mask to be used. We add relation here to ensure object is
- * never evaluated prior to Scene's CoW is ready.
+ /* Special case: modifiers evaluation queries scene for various things like
+ * data mask to be used. We add relation here to ensure object is never
+ * evaluated prior to Scene's CoW is ready.
*/
OperationKey scene_key(&scene_->id,
- DEG_NODE_TYPE_PARAMETERS,
- DEG_OPCODE_PLACEHOLDER,
- "Scene Eval");
+ DEG_NODE_TYPE_LAYER_COLLECTIONS,
+ DEG_OPCODE_VIEW_LAYER_EVAL);
DepsRelation *rel = add_relation(scene_key, obdata_ubereval_key, "CoW Relation");
rel->flag |= DEPSREL_FLAG_NO_FLUSH;
-
/* Modifiers */
if (object->modifiers.first != NULL) {
ModifierUpdateDepsgraphContext ctx = {};
ctx.scene = scene_;
ctx.object = object;
-
LISTBASE_FOREACH (ModifierData *, md, &object->modifiers) {
const ModifierTypeInfo *mti = modifierType_getInfo((ModifierType)md->type);
if (mti->updateDepsgraph) {
@@ -1706,8 +1757,7 @@ void DepsgraphRelationBuilder::build_obdata_geom(Object *object)
}
}
}
-
- /* materials */
+ /* Materials. */
if (object->totcol) {
for (int a = 1; a <= object->totcol; a++) {
Material *ma = give_current_material(object, a);
@@ -1718,179 +1768,183 @@ void DepsgraphRelationBuilder::build_obdata_geom(Object *object)
OperationKey material_key(&ma->id,
DEG_NODE_TYPE_SHADING,
DEG_OPCODE_MATERIAL_UPDATE);
- OperationKey shading_key(&object->id, DEG_NODE_TYPE_SHADING, DEG_OPCODE_SHADING);
+ OperationKey shading_key(&object->id,
+ DEG_NODE_TYPE_SHADING,
+ DEG_OPCODE_SHADING);
add_relation(material_key, shading_key, "Material Update");
}
}
}
}
-
- /* geometry collision */
+ /* Geometry collision. */
if (ELEM(object->type, OB_MESH, OB_CURVE, OB_LATTICE)) {
// add geometry collider relations
}
-
/* Make sure uber update is the last in the dependencies.
*
* TODO(sergey): Get rid of this node.
*/
if (object->type != OB_ARMATURE) {
/* Armatures does no longer require uber node. */
- OperationKey obdata_ubereval_key(&object->id, DEG_NODE_TYPE_GEOMETRY, DEG_OPCODE_GEOMETRY_UBEREVAL);
- add_relation(geom_init_key, obdata_ubereval_key, "Object Geometry UberEval");
+ OperationKey obdata_ubereval_key(&object->id,
+ DEG_NODE_TYPE_GEOMETRY,
+ DEG_OPCODE_GEOMETRY_UBEREVAL);
+ add_relation(geom_init_key,
+ obdata_ubereval_key,
+ "Object Geometry UberEval");
+ }
+ if (object->type == OB_MBALL) {
+ Object *mom = BKE_mball_basis_find(scene_, object);
+ ComponentKey mom_geom_key(&mom->id, DEG_NODE_TYPE_GEOMETRY);
+ /* motherball - mom depends on children! */
+ if (mom == object) {
+ ComponentKey mom_transform_key(&mom->id,
+ DEG_NODE_TYPE_TRANSFORM);
+ add_relation(mom_transform_key,
+ mom_geom_key,
+ "Metaball Motherball Transform -> Geometry");
+ }
+ else {
+ ComponentKey transform_key(&object->id, DEG_NODE_TYPE_TRANSFORM);
+ add_relation(geom_key, mom_geom_key, "Metaball Motherball");
+ add_relation(transform_key, mom_geom_key, "Metaball Motherball");
+ }
+ }
+ /* NOTE: This is compatibility code to support particle systems
+ *
+ * for viewport being properly rendered in final render mode.
+ * This relation is similar to what dag_object_time_update_flags()
+ * was doing for mesh objects with particle system.
+ *
+ * Ideally we need to get rid of this relation.
+ */
+ if (object_particles_depends_on_time(object)) {
+ TimeSourceKey time_key;
+ OperationKey obdata_ubereval_key(&object->id,
+ DEG_NODE_TYPE_GEOMETRY,
+ DEG_OPCODE_GEOMETRY_UBEREVAL);
+ add_relation(time_key, obdata_ubereval_key, "Legacy particle time");
+ }
+ /* Object data datablock. */
+ build_object_data_geometry_datablock((ID *)object->data);
+ Key *key = BKE_key_from_object(object);
+ if (key != NULL) {
+ if (key->adt != NULL) {
+ if (key->adt->action || key->adt->nla_tracks.first) {
+ ComponentKey obdata_key((ID *)object->data,
+ DEG_NODE_TYPE_GEOMETRY);
+ ComponentKey adt_key(&key->id, DEG_NODE_TYPE_ANIMATION);
+ add_relation(adt_key, obdata_key, "Animation");
+ }
+ }
}
+}
+void DepsgraphRelationBuilder::build_object_data_geometry_datablock(ID *obdata)
+{
if (built_map_.checkIsBuiltAndTag(obdata)) {
return;
}
-
+ /* Animation. */
+ build_animdata(obdata);
+ /* ShapeKeys. */
+ Key *key = BKE_key_from_id(obdata);
+ if (key != NULL) {
+ build_shapekeys(key);
+ }
/* Link object data evaluation node to exit operation. */
- OperationKey obdata_geom_eval_key(obdata, DEG_NODE_TYPE_GEOMETRY, DEG_OPCODE_PLACEHOLDER, "Geometry Eval");
- OperationKey obdata_geom_done_key(obdata, DEG_NODE_TYPE_GEOMETRY, DEG_OPCODE_PLACEHOLDER, "Eval Done");
- add_relation(obdata_geom_eval_key, obdata_geom_done_key, "ObData Geom Eval Done");
-
- /* type-specific node/links */
- switch (object->type) {
- case OB_MESH:
- /* NOTE: This is compatibility code to support particle systems
- *
- * for viewport being properly rendered in final render mode.
- * This relation is similar to what dag_object_time_update_flags()
- * was doing for mesh objects with particle system.
- *
- * Ideally we need to get rid of this relation.
- */
- if (object_particles_depends_on_time(object)) {
- TimeSourceKey time_key;
- OperationKey obdata_ubereval_key(&object->id,
- DEG_NODE_TYPE_GEOMETRY,
- DEG_OPCODE_GEOMETRY_UBEREVAL);
- add_relation(time_key, obdata_ubereval_key, "Legacy particle time");
- }
+ OperationKey obdata_geom_eval_key(obdata,
+ DEG_NODE_TYPE_GEOMETRY,
+ DEG_OPCODE_PLACEHOLDER,
+ "Geometry Eval");
+ OperationKey obdata_geom_done_key(obdata,
+ DEG_NODE_TYPE_GEOMETRY,
+ DEG_OPCODE_PLACEHOLDER,
+ "Eval Done");
+ add_relation(obdata_geom_eval_key,
+ obdata_geom_done_key,
+ "ObData Geom Eval Done");
+ /* Type-specific links. */
+ const ID_Type id_type = GS(obdata->name);
+ switch (id_type) {
+ case ID_ME:
break;
-
- case OB_MBALL:
- {
- Object *mom = BKE_mball_basis_find(scene_, object);
- ComponentKey mom_geom_key(&mom->id, DEG_NODE_TYPE_GEOMETRY);
- /* motherball - mom depends on children! */
- if (mom == object) {
- ComponentKey mom_transform_key(&mom->id,
- DEG_NODE_TYPE_TRANSFORM);
- add_relation(mom_transform_key,
- mom_geom_key,
- "Metaball Motherball Transform -> Geometry");
- }
- else {
- ComponentKey transform_key(&object->id, DEG_NODE_TYPE_TRANSFORM);
- add_relation(geom_key, mom_geom_key, "Metaball Motherball");
- add_relation(transform_key, mom_geom_key, "Metaball Motherball");
- }
+ case ID_MB:
break;
- }
-
- case OB_CURVE:
- case OB_FONT:
+ case ID_CU:
{
Curve *cu = (Curve *)obdata;
-
- /* curve's dependencies */
- // XXX: these needs geom data, but where is geom stored?
- if (cu->bevobj) {
- ComponentKey bevob_geom_key(&cu->bevobj->id, DEG_NODE_TYPE_GEOMETRY);
- add_relation(bevob_geom_key, obdata_geom_key, "Curve Bevel Geometry");
- /* We only need scale, but we can't tag individual TRANSFORM components. */
- ComponentKey bevob_key(&cu->bevobj->id, DEG_NODE_TYPE_TRANSFORM);
- add_relation(bevob_key, obdata_geom_key, "Curve Bevel Scale");
+ if (cu->bevobj != NULL) {
+ ComponentKey bevob_geom_key(&cu->bevobj->id,
+ DEG_NODE_TYPE_GEOMETRY);
+ add_relation(bevob_geom_key,
+ obdata_geom_eval_key,
+ "Curve Bevel Geometry");
+ ComponentKey bevob_key(&cu->bevobj->id,
+ DEG_NODE_TYPE_TRANSFORM);
+ add_relation(bevob_key,
+ obdata_geom_eval_key,
+ "Curve Bevel Transform");
build_object(NULL, cu->bevobj);
}
- if (cu->taperobj) {
- ComponentKey taperob_key(&cu->taperobj->id, DEG_NODE_TYPE_GEOMETRY);
+ if (cu->taperobj != NULL) {
+ ComponentKey taperob_key(&cu->taperobj->id,
+ DEG_NODE_TYPE_GEOMETRY);
+ add_relation(taperob_key, obdata_geom_eval_key, "Curve Taper");
build_object(NULL, cu->taperobj);
- add_relation(taperob_key, geom_key, "Curve Taper");
}
- if (object->type == OB_FONT) {
- if (cu->textoncurve) {
- ComponentKey textoncurve_key(&cu->textoncurve->id, DEG_NODE_TYPE_GEOMETRY);
- build_object(NULL, cu->textoncurve);
- add_relation(textoncurve_key, geom_key, "Text on Curve");
- }
+ if (cu->textoncurve != NULL) {
+ ComponentKey textoncurve_key(&cu->textoncurve->id,
+ DEG_NODE_TYPE_GEOMETRY);
+ add_relation(textoncurve_key,
+ obdata_geom_eval_key,
+ "Text on Curve");
+ build_object(NULL, cu->textoncurve);
}
break;
}
-
- case OB_SURF: /* Nurbs Surface */
- {
+ case ID_LT:
break;
- }
-
- case OB_LATTICE: /* Lattice */
- {
+ default:
+ BLI_assert(!"Should not happen");
break;
- }
}
+}
- /* ShapeKeys */
- Key *key = BKE_key_from_object(object);
- if (key) {
- build_shapekeys(obdata, key);
+void DepsgraphRelationBuilder::build_armature(bArmature *armature)
+{
+ if (built_map_.checkIsBuiltAndTag(armature)) {
+ return;
}
+ build_animdata(&armature->id);
}
-/* Cameras */
-// TODO: Link scene-camera links in somehow...
-void DepsgraphRelationBuilder::build_camera(Object *object)
+void DepsgraphRelationBuilder::build_camera(Camera *camera)
{
- Camera *camera = (Camera *)object->data;
if (built_map_.checkIsBuiltAndTag(camera)) {
return;
}
-
- ComponentKey object_parameters_key(&object->id, DEG_NODE_TYPE_PARAMETERS);
- ComponentKey camera_parameters_key(&camera->id, DEG_NODE_TYPE_PARAMETERS);
-
- add_relation(camera_parameters_key, object_parameters_key,
- "Camera -> Object");
-
- /* DOF */
if (camera->dof_ob != NULL) {
+ ComponentKey camera_parameters_key(&camera->id, DEG_NODE_TYPE_PARAMETERS);
ComponentKey dof_ob_key(&camera->dof_ob->id, DEG_NODE_TYPE_TRANSFORM);
- add_relation(dof_ob_key, object_parameters_key, "Camera DOF");
+ add_relation(dof_ob_key, camera_parameters_key, "Camera DOF");
}
}
/* Lamps */
-void DepsgraphRelationBuilder::build_lamp(Object *object)
+void DepsgraphRelationBuilder::build_lamp(Lamp *lamp)
{
- Lamp *lamp = (Lamp *)object->data;
if (built_map_.checkIsBuiltAndTag(lamp)) {
return;
}
-
- ComponentKey object_parameters_key(&object->id, DEG_NODE_TYPE_PARAMETERS);
- ComponentKey lamp_parameters_key(&lamp->id, DEG_NODE_TYPE_PARAMETERS);
-
- add_relation(lamp_parameters_key, object_parameters_key,
- "Lamp -> Object");
-
/* lamp's nodetree */
if (lamp->nodetree != NULL) {
build_nodetree(lamp->nodetree);
+ ComponentKey lamp_parameters_key(&lamp->id, DEG_NODE_TYPE_PARAMETERS);
ComponentKey nodetree_key(&lamp->nodetree->id, DEG_NODE_TYPE_SHADING);
add_relation(nodetree_key, lamp_parameters_key, "NTree->Lamp Parameters");
build_nested_nodetree(&lamp->id, lamp->nodetree);
}
-
- /* Make sure copy on write of lamp data is always properly updated for
- * visible lamps.
- */
- OperationKey ob_copy_on_write_key(&object->id,
- DEG_NODE_TYPE_COPY_ON_WRITE,
- DEG_OPCODE_COPY_ON_WRITE);
- OperationKey lamp_copy_on_write_key(&lamp->id,
- DEG_NODE_TYPE_COPY_ON_WRITE,
- DEG_OPCODE_COPY_ON_WRITE);
- add_relation(lamp_copy_on_write_key, ob_copy_on_write_key, "Eval Order");
}
void DepsgraphRelationBuilder::build_nodetree(bNodeTree *ntree)
@@ -1952,7 +2006,7 @@ void DepsgraphRelationBuilder::build_nodetree(bNodeTree *ntree)
if (check_id_has_anim_component(&ntree->id)) {
ComponentKey animation_key(&ntree->id, DEG_NODE_TYPE_ANIMATION);
- add_relation(shading_parameters_key, animation_key, "NTree Shading Parameters");
+ add_relation(animation_key, shading_parameters_key, "NTree Shading Parameters");
}
}
@@ -2045,23 +2099,12 @@ void DepsgraphRelationBuilder::build_movieclip(MovieClip *clip)
build_animdata(&clip->id);
}
-void DepsgraphRelationBuilder::build_lightprobe(Object *object)
+void DepsgraphRelationBuilder::build_lightprobe(LightProbe *probe)
{
- LightProbe *probe = (LightProbe *)object->data;
if (built_map_.checkIsBuiltAndTag(probe)) {
return;
}
build_animdata(&probe->id);
-
- OperationKey probe_key(&probe->id,
- DEG_NODE_TYPE_PARAMETERS,
- DEG_OPCODE_PLACEHOLDER,
- "LightProbe Eval");
- OperationKey object_key(&object->id,
- DEG_NODE_TYPE_PARAMETERS,
- DEG_OPCODE_PLACEHOLDER,
- "LightProbe Eval");
- add_relation(probe_key, object_key, "LightProbe Update");
}
void DepsgraphRelationBuilder::build_copy_on_write_relations()
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations.h b/source/blender/depsgraph/intern/builder/deg_builder_relations.h
index dbfaff4dc18..3d3a73b6551 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_relations.h
+++ b/source/blender/depsgraph/intern/builder/deg_builder_relations.h
@@ -49,15 +49,19 @@
#include "intern/nodes/deg_node_operation.h"
struct Base;
+struct bArmature;
struct bGPdata;
struct CacheFile;
+struct Camera;
struct ListBase;
struct GHash;
struct ID;
struct FCurve;
struct Collection;
struct Key;
+struct Lamp;
struct LayerCollection;
+struct LightProbe;
struct Main;
struct Mask;
struct Material;
@@ -197,10 +201,17 @@ struct DepsgraphRelationBuilder
void build_id(ID *id);
void build_layer_collections(ListBase *lb);
void build_view_layer(Scene *scene, ViewLayer *view_layer);
- void build_collection(Object *object, Collection *collection);
+ void build_collection(eDepsNode_CollectionOwner owner_type,
+ Object *object,
+ Collection *collection);
void build_object(Base *base, Object *object);
void build_object_flags(Base *base, Object *object);
void build_object_data(Object *object);
+ void build_object_data_camera(Object *object);
+ void build_object_data_geometry(Object *object);
+ void build_object_data_geometry_datablock(ID *obdata);
+ void build_object_data_lamp(Object *object);
+ void build_object_data_lightprobe(Object *object);
void build_object_parent(Object *object);
void build_constraints(ID *id,
eDepsNode_Type component_type,
@@ -239,10 +250,10 @@ struct DepsgraphRelationBuilder
RootPChanMap *root_map);
void build_rig(Object *object);
void build_proxy_rig(Object *object);
- void build_shapekeys(ID *obdata, Key *key);
- void build_obdata_geom(Object *object);
- void build_camera(Object *object);
- void build_lamp(Object *object);
+ void build_shapekeys(Key *key);
+ void build_armature(bArmature *armature);
+ void build_camera(Camera *camera);
+ void build_lamp(Lamp *lamp);
void build_nodetree(bNodeTree *ntree);
void build_material(Material *ma);
void build_texture(Tex *tex);
@@ -251,7 +262,7 @@ struct DepsgraphRelationBuilder
void build_cachefile(CacheFile *cache_file);
void build_mask(Mask *mask);
void build_movieclip(MovieClip *clip);
- void build_lightprobe(Object *object);
+ void build_lightprobe(LightProbe *probe);
void build_nested_datablock(ID *owner, ID *id);
void build_nested_nodetree(ID *owner, bNodeTree *ntree);
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations_rig.cc b/source/blender/depsgraph/intern/builder/deg_builder_relations_rig.cc
index a9895eb3af1..49c107c988f 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_relations_rig.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder_relations_rig.cc
@@ -304,27 +304,21 @@ void DepsgraphRelationBuilder::build_splineik_pose(Object *object,
void DepsgraphRelationBuilder::build_rig(Object *object)
{
/* Armature-Data */
- bArmature *arm = (bArmature *)object->data;
-
+ bArmature *armature = (bArmature *)object->data;
// TODO: selection status?
-
- /* attach links between pose operations */
+ /* Attach links between pose operations. */
OperationKey init_key(&object->id, DEG_NODE_TYPE_EVAL_POSE, DEG_OPCODE_POSE_INIT);
OperationKey init_ik_key(&object->id, DEG_NODE_TYPE_EVAL_POSE, DEG_OPCODE_POSE_INIT_IK);
OperationKey flush_key(&object->id, DEG_NODE_TYPE_EVAL_POSE, DEG_OPCODE_POSE_DONE);
-
add_relation(init_key, init_ik_key, "Pose Init -> Pose Init IK");
add_relation(init_ik_key, flush_key, "Pose Init IK -> Pose Cleanup");
-
/* Make sure pose is up-to-date with armature updates. */
- if (!built_map_.checkIsBuiltAndTag(arm)) {
- OperationKey armature_key(&arm->id,
- DEG_NODE_TYPE_PARAMETERS,
- DEG_OPCODE_PLACEHOLDER,
- "Armature Eval");
- add_relation(armature_key, init_key, "Data dependency");
- }
-
+ build_armature(armature);
+ OperationKey armature_key(&armature->id,
+ DEG_NODE_TYPE_PARAMETERS,
+ DEG_OPCODE_PLACEHOLDER,
+ "Armature Eval");
+ add_relation(armature_key, init_key, "Data dependency");
/* IK Solvers...
* - These require separate processing steps are pose-level
* to be executed between chains of bones (i.e. once the
@@ -337,7 +331,8 @@ void DepsgraphRelationBuilder::build_rig(Object *object)
* 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
+ * - 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;
@@ -372,7 +367,6 @@ void DepsgraphRelationBuilder::build_rig(Object *object)
}
}
//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.
@@ -381,8 +375,7 @@ void DepsgraphRelationBuilder::build_rig(Object *object)
ComponentKey local_transform_key(&object->id, DEG_NODE_TYPE_TRANSFORM);
add_relation(local_transform_key, pose_key, "Local Transforms");
}
-
- /* links between operations for each bone */
+ /* Links between operations for each bone. */
LISTBASE_FOREACH (bPoseChannel *, pchan, &object->pose->chanbase) {
OperationKey bone_local_key(&object->id, DEG_NODE_TYPE_BONE, pchan->name, DEG_OPCODE_BONE_LOCAL);
OperationKey bone_pose_key(&object->id, DEG_NODE_TYPE_BONE, pchan->name, DEG_OPCODE_BONE_POSE_PARENT);
@@ -397,7 +390,9 @@ void DepsgraphRelationBuilder::build_rig(Object *object)
if (pchan->parent != NULL) {
eDepsOperation_Code parent_key_opcode;
- /* NOTE: this difference in handling allows us to prevent lockups while ensuring correct poses for separate chains */
+ /* NOTE: this difference in handling allows us to prevent lockups
+ * while ensuring correct poses for separate chains.
+ */
if (root_map.has_common_root(pchan->name, pchan->parent->name)) {
parent_key_opcode = DEG_OPCODE_BONE_READY;
}
@@ -433,14 +428,15 @@ void DepsgraphRelationBuilder::build_rig(Object *object)
/* 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...
+ * For IK chains however, an additional rel is created from IK
+ * to done, with transitive reduction removing this one..
*/
add_relation(bone_ready_key, bone_done_key, "Ready -> Done");
- /* assume that all bones must be done for the pose to be ready (for deformers) */
+ /* assume that all bones must be done for the pose to be ready
+ * (for deformers)
+ */
add_relation(bone_done_key, flush_key, "PoseEval Result-Bone Link");
-
/* Custom shape. */
if (pchan->custom != NULL) {
build_object(NULL, pchan->custom);
@@ -450,7 +446,9 @@ void DepsgraphRelationBuilder::build_rig(Object *object)
void DepsgraphRelationBuilder::build_proxy_rig(Object *object)
{
+ bArmature *armature = (bArmature *)object->data;
Object *proxy_from = object->proxy_from;
+ build_armature(armature);
OperationKey pose_init_key(&object->id,
DEG_NODE_TYPE_EVAL_POSE,
DEG_OPCODE_POSE_INIT);
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations_view_layer.cc b/source/blender/depsgraph/intern/builder/deg_builder_relations_view_layer.cc
index 0f159248ff4..b940fc3035e 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_relations_view_layer.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder_relations_view_layer.cc
@@ -75,13 +75,13 @@ void DepsgraphRelationBuilder::build_layer_collections(ListBase *lb)
COLLECTION_RESTRICT_VIEW : COLLECTION_RESTRICT_RENDER;
for (LayerCollection *lc = (LayerCollection *)lb->first; lc; lc = lc->next) {
- if (!(lc->collection->flag & restrict_flag)) {
- if (!(lc->flag & LAYER_COLLECTION_EXCLUDE)) {
- build_collection(NULL, lc->collection);
- }
-
- build_layer_collections(&lc->layer_collections);
+ if ((lc->collection->flag & restrict_flag)) {
+ continue;
+ }
+ if ((lc->flag & LAYER_COLLECTION_EXCLUDE) == 0) {
+ build_collection(DEG_COLLECTION_OWNER_SCENE, NULL, lc->collection);
}
+ build_layer_collections(&lc->layer_collections);
}
}
diff --git a/source/blender/depsgraph/intern/depsgraph_query_iter.cc b/source/blender/depsgraph/intern/depsgraph_query_iter.cc
index 4f3769b6768..97a28038b7b 100644
--- a/source/blender/depsgraph/intern/depsgraph_query_iter.cc
+++ b/source/blender/depsgraph/intern/depsgraph_query_iter.cc
@@ -120,7 +120,7 @@ static bool deg_objects_dupli_iterator_next(BLI_Iterator *iter)
/* Duplicated elements shouldn't care whether their original collection is visible or not. */
temp_dupli_object->base_flag |= BASE_VISIBLED;
- if (BKE_object_is_visible(temp_dupli_object, (eObjectVisibilityCheck)data->visibility_check) == false) {
+ if (BKE_object_is_visible(temp_dupli_object, OB_VISIBILITY_CHECK_UNKNOWN_RENDER_MODE) == false) {
continue;
}
@@ -211,7 +211,9 @@ void DEG_iterator_objects_begin(BLI_Iterator *iter, DEGObjectIterData *data)
data->scene = DEG_get_evaluated_scene(depsgraph);
data->id_node_index = 0;
data->num_id_nodes = num_id_nodes;
- data->visibility_check = (data->mode == DEG_ITER_OBJECT_MODE_RENDER)
+ eEvaluationMode eval_mode = DEG_get_mode(depsgraph);
+ /* Viewport rendered mode is DAG_EVAL_PREVIEW but still treated as viewport. */
+ data->visibility_check = (eval_mode == DAG_EVAL_RENDER)
? OB_VISIBILITY_CHECK_FOR_RENDER
: OB_VISIBILITY_CHECK_FOR_VIEWPORT;
diff --git a/source/blender/depsgraph/intern/depsgraph_tag.cc b/source/blender/depsgraph/intern/depsgraph_tag.cc
index e772aefe8cb..437999a06a9 100644
--- a/source/blender/depsgraph/intern/depsgraph_tag.cc
+++ b/source/blender/depsgraph/intern/depsgraph_tag.cc
@@ -449,17 +449,7 @@ void deg_graph_node_tag_zero(Main *bmain, Depsgraph *graph, IDDepsNode *id_node)
GHASH_FOREACH_BEGIN(ComponentDepsNode *, comp_node, id_node->components)
{
if (comp_node->type == DEG_NODE_TYPE_ANIMATION) {
- AnimData *adt = BKE_animdata_from_id(id);
- /* NOTE: Animation data might be null if relations are tagged
- * for update.
- */
- if (adt == NULL || (adt->recalc & ADT_RECALC_ANIM) == 0) {
- /* If there is no animation, or animation is not tagged for
- * update yet, we don't force animation channel to be evaluated.
- */
- continue;
- }
- id->recalc |= ID_RECALC_ANIMATION;
+ continue;
}
comp_node->tag_update(graph);
}
@@ -520,7 +510,7 @@ void deg_graph_on_visible_update(Main *bmain, Depsgraph *graph)
/* Make sure objects are up to date. */
foreach (DEG::IDDepsNode *id_node, graph->id_nodes) {
const ID_Type id_type = GS(id_node->id_orig->name);
- int flag = DEG_TAG_TIME | DEG_TAG_COPY_ON_WRITE;
+ int flag = DEG_TAG_COPY_ON_WRITE;
/* We only tag components which needs an update. Tagging everything is
* not a good idea because that might reset particles cache (or any
* other type of cache).
diff --git a/source/blender/depsgraph/intern/depsgraph_type_defines.cc b/source/blender/depsgraph/intern/depsgraph_type_defines.cc
index 19cc82a6b10..79d29f72b8d 100644
--- a/source/blender/depsgraph/intern/depsgraph_type_defines.cc
+++ b/source/blender/depsgraph/intern/depsgraph_type_defines.cc
@@ -138,6 +138,8 @@ const char *operationCodeAsString(eDepsOperation_Code opcode)
STRINGIFY_OPCODE(GEOMETRY_UBEREVAL);
STRINGIFY_OPCODE(GEOMETRY_CLOTH_MODIFIER);
STRINGIFY_OPCODE(GEOMETRY_SHAPEKEY);
+ /* Object data. */
+ STRINGIFY_OPCODE(LIGHT_PROBE_EVAL);
/* Pose. */
STRINGIFY_OPCODE(POSE_INIT);
STRINGIFY_OPCODE(POSE_INIT_IK);
diff --git a/source/blender/depsgraph/intern/depsgraph_types.h b/source/blender/depsgraph/intern/depsgraph_types.h
index 14cd62e6cec..cec279a04bb 100644
--- a/source/blender/depsgraph/intern/depsgraph_types.h
+++ b/source/blender/depsgraph/intern/depsgraph_types.h
@@ -205,6 +205,9 @@ typedef enum eDepsOperation_Code {
DEG_OPCODE_GEOMETRY_CLOTH_MODIFIER,
DEG_OPCODE_GEOMETRY_SHAPEKEY,
+ /* Object data. ------------------------------------- */
+ DEG_OPCODE_LIGHT_PROBE_EVAL,
+
/* Pose. -------------------------------------------- */
/* Init pose, clear flags, etc. */
DEG_OPCODE_POSE_INIT,
@@ -269,7 +272,17 @@ typedef enum eDepsOperation_Code {
DEG_NUM_OPCODES,
} eDepsOperation_Code;
-
const char *operationCodeAsString(eDepsOperation_Code opcode);
+typedef enum eDepsNode_CollectionOwner {
+ /* Unknown owner of collection, collection is pulled directly, maybe
+ * via driver.
+ */
+ DEG_COLLECTION_OWNER_UNKNOWN,
+ /* Collection belongs to a scene. */
+ DEG_COLLECTION_OWNER_SCENE,
+ /* Collection is used by object, as a dupli-system. */
+ DEG_COLLECTION_OWNER_OBJECT,
+} eDepsNode_CollectionOwner;
+
} // namespace DEG
diff --git a/source/blender/draw/CMakeLists.txt b/source/blender/draw/CMakeLists.txt
index c7d3d935b26..6743bea350b 100644
--- a/source/blender/draw/CMakeLists.txt
+++ b/source/blender/draw/CMakeLists.txt
@@ -222,6 +222,8 @@ data_to_c_simple(engines/eevee/shaders/volumetric_scatter_frag.glsl SRC)
data_to_c_simple(engines/eevee/shaders/volumetric_integration_frag.glsl SRC)
data_to_c_simple(engines/workbench/shaders/workbench_background_lib.glsl SRC)
+data_to_c_simple(engines/workbench/shaders/workbench_cavity_lib.glsl SRC)
+data_to_c_simple(engines/workbench/shaders/workbench_cavity_frag.glsl SRC)
data_to_c_simple(engines/workbench/shaders/workbench_checkerboard_depth_frag.glsl SRC)
data_to_c_simple(engines/workbench/shaders/workbench_common_lib.glsl SRC)
data_to_c_simple(engines/workbench/shaders/workbench_data_lib.glsl SRC)
diff --git a/source/blender/draw/engines/basic/basic_engine.c b/source/blender/draw/engines/basic/basic_engine.c
index c86574f7557..2c771578514 100644
--- a/source/blender/draw/engines/basic/basic_engine.c
+++ b/source/blender/draw/engines/basic/basic_engine.c
@@ -155,7 +155,7 @@ static void basic_cache_populate(void *vedata, Object *ob)
continue;
}
if (!DRW_check_psys_visible_within_active_context(ob, psys)) {
- return;
+ continue;
}
ParticleSettings *part = psys->part;
const int draw_as = (part->draw_as == PART_DRAW_REND) ? part->ren_as : part->draw_as;
diff --git a/source/blender/draw/engines/clay/clay_engine.c b/source/blender/draw/engines/clay/clay_engine.c
index d08fee6039f..5d3717097b1 100644
--- a/source/blender/draw/engines/clay/clay_engine.c
+++ b/source/blender/draw/engines/clay/clay_engine.c
@@ -838,7 +838,7 @@ static void clay_cache_populate_particles(void *vedata, Object *ob)
continue;
}
if (!DRW_check_psys_visible_within_active_context(ob, psys)) {
- return;
+ continue;
}
ParticleSettings *part = psys->part;
const int draw_as = (part->draw_as == PART_DRAW_REND) ? part->ren_as : part->draw_as;
diff --git a/source/blender/draw/engines/eevee/eevee_lights.c b/source/blender/draw/engines/eevee/eevee_lights.c
index dd69e19e7c1..f5673d1a616 100644
--- a/source/blender/draw/engines/eevee/eevee_lights.c
+++ b/source/blender/draw/engines/eevee/eevee_lights.c
@@ -40,7 +40,9 @@
static struct {
struct GPUShader *shadow_sh;
struct GPUShader *shadow_store_cube_sh[SHADOW_METHOD_MAX];
+ struct GPUShader *shadow_store_cube_high_sh[SHADOW_METHOD_MAX];
struct GPUShader *shadow_store_cascade_sh[SHADOW_METHOD_MAX];
+ struct GPUShader *shadow_store_cascade_high_sh[SHADOW_METHOD_MAX];
struct GPUShader *shadow_copy_cube_sh[SHADOW_METHOD_MAX];
struct GPUShader *shadow_copy_cascade_sh[SHADOW_METHOD_MAX];
} e_data = {NULL}; /* Engine data */
@@ -172,22 +174,7 @@ void EEVEE_lights_init(EEVEE_ViewLayerData *sldata)
linfo->shadow_cascade_size = sh_cascade_size;
/* only compile the ones needed. reduce startup time. */
- if ((sh_method == SHADOW_ESM) && !e_data.shadow_store_cube_sh[SHADOW_ESM]) {
- DynStr *ds_frag = BLI_dynstr_new();
- BLI_dynstr_append(ds_frag, datatoc_concentric_samples_lib_glsl);
- BLI_dynstr_append(ds_frag, datatoc_shadow_store_frag_glsl);
- char *store_shadow_shader_str = BLI_dynstr_get_cstring(ds_frag);
- BLI_dynstr_free(ds_frag);
-
- e_data.shadow_store_cube_sh[SHADOW_ESM] = DRW_shader_create_fullscreen(
- store_shadow_shader_str,
- "#define ESM\n");
- e_data.shadow_store_cascade_sh[SHADOW_ESM] = DRW_shader_create_fullscreen(
- store_shadow_shader_str,
- "#define ESM\n"
- "#define CSM\n");
- MEM_freeN(store_shadow_shader_str);
-
+ if ((sh_method == SHADOW_ESM) && !e_data.shadow_copy_cube_sh[SHADOW_ESM]) {
e_data.shadow_copy_cube_sh[SHADOW_ESM] = DRW_shader_create_fullscreen(
datatoc_shadow_copy_frag_glsl,
"#define ESM\n"
@@ -198,22 +185,7 @@ void EEVEE_lights_init(EEVEE_ViewLayerData *sldata)
"#define COPY\n"
"#define CSM\n");
}
- else if ((sh_method == SHADOW_VSM) && !e_data.shadow_store_cube_sh[SHADOW_VSM]) {
- DynStr *ds_frag = BLI_dynstr_new();
- BLI_dynstr_append(ds_frag, datatoc_concentric_samples_lib_glsl);
- BLI_dynstr_append(ds_frag, datatoc_shadow_store_frag_glsl);
- char *store_shadow_shader_str = BLI_dynstr_get_cstring(ds_frag);
- BLI_dynstr_free(ds_frag);
-
- e_data.shadow_store_cube_sh[SHADOW_VSM] = DRW_shader_create_fullscreen(
- store_shadow_shader_str,
- "#define VSM\n");
- e_data.shadow_store_cascade_sh[SHADOW_VSM] = DRW_shader_create_fullscreen(
- store_shadow_shader_str,
- "#define VSM\n"
- "#define CSM\n");
- MEM_freeN(store_shadow_shader_str);
-
+ else if ((sh_method == SHADOW_VSM) && !e_data.shadow_copy_cube_sh[SHADOW_VSM]) {
e_data.shadow_copy_cube_sh[SHADOW_VSM] = DRW_shader_create_fullscreen(
datatoc_shadow_copy_frag_glsl,
"#define VSM\n"
@@ -226,6 +198,78 @@ void EEVEE_lights_init(EEVEE_ViewLayerData *sldata)
}
}
+static GPUShader *eevee_lights_get_store_sh(int shadow_method, bool high_blur, bool cascade)
+{
+ GPUShader **shader;
+
+ if (cascade) {
+ shader = (high_blur) ? &e_data.shadow_store_cascade_high_sh[shadow_method]
+ : &e_data.shadow_store_cascade_sh[shadow_method];
+ }
+ else {
+ shader = (high_blur) ? &e_data.shadow_store_cube_high_sh[shadow_method]
+ : &e_data.shadow_store_cube_sh[shadow_method];
+ }
+
+ if (*shader == NULL) {
+ DynStr *ds_frag = BLI_dynstr_new();
+ BLI_dynstr_append(ds_frag, datatoc_concentric_samples_lib_glsl);
+ BLI_dynstr_append(ds_frag, datatoc_shadow_store_frag_glsl);
+ char *store_shadow_shader_str = BLI_dynstr_get_cstring(ds_frag);
+ BLI_dynstr_free(ds_frag);
+
+ ds_frag = BLI_dynstr_new();
+ BLI_dynstr_append(ds_frag, (shadow_method == SHADOW_VSM) ? "#define VSM\n" : "#define ESM\n");
+ if (high_blur) BLI_dynstr_append(ds_frag, "#define HIGH_BLUR\n");
+ if (cascade) BLI_dynstr_append(ds_frag, "#define CSM\n");
+ char *define_str = BLI_dynstr_get_cstring(ds_frag);
+ BLI_dynstr_free(ds_frag);
+
+ *shader = DRW_shader_create_fullscreen(
+ store_shadow_shader_str, define_str);
+
+ MEM_freeN(store_shadow_shader_str);
+ MEM_freeN(define_str);
+ }
+
+ return *shader;
+}
+
+static DRWPass *eevee_lights_cube_store_pass_get(EEVEE_PassList *psl, EEVEE_ViewLayerData *sldata, int shadow_method, int shadow_samples_ct)
+{
+ bool high_blur = shadow_samples_ct > 16;
+ DRWPass **pass = (high_blur) ? &psl->shadow_cube_store_pass : &psl->shadow_cube_store_high_pass;
+ if (*pass == NULL) {
+ EEVEE_LampsInfo *linfo = sldata->lamps;
+ *pass = DRW_pass_create("Shadow Cube Storage Pass", DRW_STATE_WRITE_COLOR);
+ GPUShader *shader = eevee_lights_get_store_sh(shadow_method, high_blur, false);
+ DRWShadingGroup *grp = DRW_shgroup_create(shader, *pass);
+ DRW_shgroup_uniform_texture_ref(grp, "shadowTexture", &sldata->shadow_cube_blur);
+ DRW_shgroup_uniform_block(grp, "shadow_render_block", sldata->shadow_render_ubo);
+ DRW_shgroup_uniform_float(grp, "shadowFilterSize", &linfo->filter_size, 1);
+ DRW_shgroup_call_add(grp, DRW_cache_fullscreen_quad_get(), NULL);
+ }
+ return *pass;
+}
+
+static DRWPass *eevee_lights_cascade_store_pass_get(EEVEE_PassList *psl, EEVEE_ViewLayerData *sldata, int shadow_method, int shadow_samples_ct)
+{
+ bool high_blur = shadow_samples_ct > 16;
+ DRWPass **pass = (high_blur) ? &psl->shadow_cascade_store_pass : &psl->shadow_cascade_store_high_pass;
+ if (*pass == NULL) {
+ EEVEE_LampsInfo *linfo = sldata->lamps;
+ *pass = DRW_pass_create("Shadow Cascade Storage Pass", DRW_STATE_WRITE_COLOR);
+ GPUShader *shader = eevee_lights_get_store_sh(shadow_method, high_blur, true);
+ DRWShadingGroup *grp = DRW_shgroup_create(shader, *pass);
+ DRW_shgroup_uniform_texture_ref(grp, "shadowTexture", &sldata->shadow_cascade_blur);
+ DRW_shgroup_uniform_block(grp, "shadow_render_block", sldata->shadow_render_ubo);
+ DRW_shgroup_uniform_int(grp, "cascadeId", &linfo->current_shadow_cascade, 1);
+ DRW_shgroup_uniform_float(grp, "shadowFilterSize", &linfo->filter_size, 1);
+ DRW_shgroup_call_add(grp, DRW_cache_fullscreen_quad_get(), NULL);
+ }
+ return *pass;
+}
+
void EEVEE_lights_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata)
{
EEVEE_LampsInfo *linfo = sldata->lamps;
@@ -247,28 +291,10 @@ void EEVEE_lights_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata)
memset(linfo->shcaster_backbuffer->flags, (char)SHADOW_CASTER_PRUNED, linfo->shcaster_backbuffer->alloc_count);
memset(linfo->shcaster_frontbuffer->flags, 0x00, linfo->shcaster_frontbuffer->alloc_count);
- {
- psl->shadow_cube_store_pass = DRW_pass_create("Shadow Storage Pass", DRW_STATE_WRITE_COLOR);
-
- DRWShadingGroup *grp = DRW_shgroup_create(
- e_data.shadow_store_cube_sh[linfo->shadow_method], psl->shadow_cube_store_pass);
- DRW_shgroup_uniform_texture_ref(grp, "shadowTexture", &sldata->shadow_cube_blur);
- DRW_shgroup_uniform_block(grp, "shadow_render_block", sldata->shadow_render_ubo);
- DRW_shgroup_uniform_float(grp, "shadowFilterSize", &linfo->filter_size, 1);
- DRW_shgroup_call_add(grp, DRW_cache_fullscreen_quad_get(), NULL);
- }
-
- {
- psl->shadow_cascade_store_pass = DRW_pass_create("Shadow Cascade Storage Pass", DRW_STATE_WRITE_COLOR);
-
- DRWShadingGroup *grp = DRW_shgroup_create(
- e_data.shadow_store_cascade_sh[linfo->shadow_method], psl->shadow_cascade_store_pass);
- DRW_shgroup_uniform_texture_ref(grp, "shadowTexture", &sldata->shadow_cascade_blur);
- DRW_shgroup_uniform_block(grp, "shadow_render_block", sldata->shadow_render_ubo);
- DRW_shgroup_uniform_int(grp, "cascadeId", &linfo->current_shadow_cascade, 1);
- DRW_shgroup_uniform_float(grp, "shadowFilterSize", &linfo->filter_size, 1);
- DRW_shgroup_call_add(grp, DRW_cache_fullscreen_quad_get(), NULL);
- }
+ psl->shadow_cube_store_pass = NULL;
+ psl->shadow_cube_store_high_pass = NULL;
+ psl->shadow_cascade_store_pass = NULL;
+ psl->shadow_cascade_store_high_pass = NULL;
{
psl->shadow_cube_copy_pass = DRW_pass_create("Shadow Copy Pass", DRW_STATE_WRITE_COLOR);
@@ -1124,7 +1150,9 @@ void EEVEE_draw_shadows(EEVEE_ViewLayerData *sldata, EEVEE_PassList *psl)
GPU_framebuffer_texture_layer_attach(sldata->shadow_cube_store_fb, sldata->shadow_cube_pool, 0, evscd->layer_id, 0);
GPU_framebuffer_bind(sldata->shadow_cube_store_fb);
- DRW_draw_pass(psl->shadow_cube_store_pass);
+
+ DRWPass *store_pass = eevee_lights_cube_store_pass_get(psl, sldata, linfo->shadow_method, srd->shadow_samples_ct);
+ DRW_draw_pass(store_pass);
led->need_update = false;
}
@@ -1224,7 +1252,9 @@ void EEVEE_draw_shadows(EEVEE_ViewLayerData *sldata, EEVEE_PassList *psl)
int layer = evscd->layer_id + linfo->current_shadow_cascade;
GPU_framebuffer_texture_layer_attach(sldata->shadow_cascade_store_fb, sldata->shadow_cascade_pool, 0, layer, 0);
GPU_framebuffer_bind(sldata->shadow_cascade_store_fb);
- DRW_draw_pass(psl->shadow_cascade_store_pass);
+
+ DRWPass *store_pass = eevee_lights_cascade_store_pass_get(psl, sldata, linfo->shadow_method, srd->shadow_samples_ct);
+ DRW_draw_pass(store_pass);
}
}
@@ -1241,7 +1271,9 @@ void EEVEE_lights_free(void)
DRW_SHADER_FREE_SAFE(e_data.shadow_sh);
for (int i = 0; i < SHADOW_METHOD_MAX; ++i) {
DRW_SHADER_FREE_SAFE(e_data.shadow_store_cube_sh[i]);
+ DRW_SHADER_FREE_SAFE(e_data.shadow_store_cube_high_sh[i]);
DRW_SHADER_FREE_SAFE(e_data.shadow_store_cascade_sh[i]);
+ DRW_SHADER_FREE_SAFE(e_data.shadow_store_cascade_high_sh[i]);
DRW_SHADER_FREE_SAFE(e_data.shadow_copy_cube_sh[i]);
DRW_SHADER_FREE_SAFE(e_data.shadow_copy_cascade_sh[i]);
}
diff --git a/source/blender/draw/engines/eevee/eevee_lookdev.c b/source/blender/draw/engines/eevee/eevee_lookdev.c
index 8107aa33d2b..5c626b42ddd 100644
--- a/source/blender/draw/engines/eevee/eevee_lookdev.c
+++ b/source/blender/draw/engines/eevee/eevee_lookdev.c
@@ -42,7 +42,7 @@ void EEVEE_lookdev_cache_init(
const DRWContextState *draw_ctx = DRW_context_state_get();
View3D *v3d = draw_ctx->v3d;
if (LOOK_DEV_MODE_ENABLED(v3d)) {
- StudioLight *sl = BKE_studiolight_find(v3d->shading.studio_light, STUDIOLIGHT_ORIENTATION_WORLD);
+ StudioLight *sl = BKE_studiolight_find(v3d->shading.studio_light, STUDIOLIGHT_INTERNAL | STUDIOLIGHT_ORIENTATION_WORLD);
if ((sl->flag & STUDIOLIGHT_ORIENTATION_WORLD)) {
struct Gwn_Batch *geom = DRW_cache_fullscreen_quad_get();
GPUTexture *tex;
@@ -51,7 +51,9 @@ void EEVEE_lookdev_cache_init(
axis_angle_to_mat3_single(stl->g_data->studiolight_matrix, 'Z', v3d->shading.studiolight_rot_z);
DRW_shgroup_uniform_mat3(*grp, "StudioLightMatrix", stl->g_data->studiolight_matrix);
- DRW_shgroup_uniform_vec3(*grp, "color", &world->horr, 1);
+ if (world) {
+ DRW_shgroup_uniform_vec3(*grp, "color", &world->horr, 1);
+ }
DRW_shgroup_uniform_float(*grp, "backgroundAlpha", &stl->g_data->background_alpha, 1);
DRW_shgroup_call_add(*grp, geom, NULL);
if (!pinfo) {
diff --git a/source/blender/draw/engines/eevee/eevee_private.h b/source/blender/draw/engines/eevee/eevee_private.h
index 3963459b1d6..d0b7044a018 100644
--- a/source/blender/draw/engines/eevee/eevee_private.h
+++ b/source/blender/draw/engines/eevee/eevee_private.h
@@ -145,8 +145,10 @@ typedef struct EEVEE_PassList {
struct DRWPass *shadow_pass;
struct DRWPass *shadow_cube_copy_pass;
struct DRWPass *shadow_cube_store_pass;
+ struct DRWPass *shadow_cube_store_high_pass;
struct DRWPass *shadow_cascade_copy_pass;
struct DRWPass *shadow_cascade_store_pass;
+ struct DRWPass *shadow_cascade_store_high_pass;
/* Probes */
struct DRWPass *probe_background;
diff --git a/source/blender/draw/engines/eevee/eevee_render.c b/source/blender/draw/engines/eevee/eevee_render.c
index 6cb3fa259eb..76887145ad2 100644
--- a/source/blender/draw/engines/eevee/eevee_render.c
+++ b/source/blender/draw/engines/eevee/eevee_render.c
@@ -143,25 +143,26 @@ void EEVEE_render_cache(
char info[42];
BLI_snprintf(info, sizeof(info), "Syncing %s", ob->id.name + 2);
RE_engine_update_stats(engine, NULL, info);
+ bool cast_shadow = false;
- if (DRW_check_object_visible_within_active_context(ob) == false) {
- return;
+ if (ob->base_flag & BASE_VISIBLED) {
+ EEVEE_hair_cache_populate(vedata, sldata, ob, &cast_shadow);
}
- if (ELEM(ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_FONT)) {
- bool cast_shadow;
-
- EEVEE_materials_cache_populate(vedata, sldata, ob, &cast_shadow);
-
- if (cast_shadow) {
- EEVEE_lights_cache_shcaster_object_add(sldata, ob);
+ if (DRW_check_object_visible_within_active_context(ob)) {
+ if (ELEM(ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_FONT)) {
+ EEVEE_materials_cache_populate(vedata, sldata, ob, &cast_shadow);
+ }
+ else if (ob->type == OB_LIGHTPROBE) {
+ EEVEE_lightprobes_cache_add(sldata, ob);
+ }
+ else if (ob->type == OB_LAMP) {
+ EEVEE_lights_cache_add(sldata, ob);
}
}
- else if (ob->type == OB_LIGHTPROBE) {
- EEVEE_lightprobes_cache_add(sldata, ob);
- }
- else if (ob->type == OB_LAMP) {
- EEVEE_lights_cache_add(sldata, ob);
+
+ if (cast_shadow) {
+ EEVEE_lights_cache_shcaster_object_add(sldata, ob);
}
}
@@ -421,6 +422,9 @@ void EEVEE_render_draw(EEVEE_Data *vedata, RenderEngine *engine, RenderLayer *rl
/* Push instances attribs to the GPU. */
DRW_render_instance_buffer_finish();
+ /* Need to be called after DRW_render_instance_buffer_finish() */
+ DRW_hair_update();
+
if ((view_layer->passflag & (SCE_PASS_SUBSURFACE_COLOR |
SCE_PASS_SUBSURFACE_DIRECT |
SCE_PASS_SUBSURFACE_INDIRECT)) != 0)
diff --git a/source/blender/draw/engines/eevee/shaders/shadow_store_frag.glsl b/source/blender/draw/engines/eevee/shaders/shadow_store_frag.glsl
index b40155be454..d5ac821c3fa 100644
--- a/source/blender/draw/engines/eevee/shaders/shadow_store_frag.glsl
+++ b/source/blender/draw/engines/eevee/shaders/shadow_store_frag.glsl
@@ -165,6 +165,7 @@ void main() {
grouped_samples_accum(cos, concentric[28], concentric[29], concentric[30], concentric[31], accum);
grouped_samples_accum(cos, concentric[32], concentric[33], concentric[34], concentric[35], accum);
}
+#ifdef HIGH_BLUR
if (shadowSampleCount > 36) {
grouped_samples_accum(cos, concentric[36], concentric[37], concentric[38], concentric[39], accum);
grouped_samples_accum(cos, concentric[40], concentric[41], concentric[42], concentric[43], accum);
@@ -230,6 +231,7 @@ void main() {
grouped_samples_accum(cos, concentric[248], concentric[249], concentric[250], concentric[251], accum);
grouped_samples_accum(cos, concentric[252], concentric[253], concentric[254], concentric[255], accum);
}
+#endif
#ifdef ESM
accum.x = ln_space_prefilter(1.0, accum.x, 1.0, accum.y);
diff --git a/source/blender/draw/engines/workbench/shaders/workbench_cavity_frag.glsl b/source/blender/draw/engines/workbench/shaders/workbench_cavity_frag.glsl
new file mode 100644
index 00000000000..38f55015877
--- /dev/null
+++ b/source/blender/draw/engines/workbench/shaders/workbench_cavity_frag.glsl
@@ -0,0 +1,71 @@
+out vec4 fragColor;
+
+uniform sampler2D depthBuffer;
+uniform sampler2D colorBuffer;
+uniform sampler2D normalBuffer;
+uniform sampler2D positionBuffer;
+
+uniform vec2 invertedViewportSize;
+uniform mat4 WinMatrix; /* inverse WinMatrix */
+
+uniform vec4 viewvecs[3];
+uniform vec4 ssao_params;
+uniform vec4 ssao_settings;
+uniform sampler2D ssao_jitter;
+
+layout(std140) uniform samples_block {
+ vec4 ssao_samples[500];
+};
+
+#define ssao_samples_num ssao_params.x
+#define jitter_tilling ssao_params.yz
+#define dfdy_sign ssao_params.w
+
+#define ssao_distance ssao_settings.x
+#define ssao_factor_cavity ssao_settings.y
+#define ssao_factor_edge ssao_settings.z
+#define ssao_attenuation ssao_settings.a
+
+vec3 get_view_space_from_depth(in vec2 uvcoords, in float depth)
+{
+ if (WinMatrix[3][3] == 0.0) {
+ /* Perspective */
+ float d = 2.0 * depth - 1.0;
+
+ float zview = -WinMatrix[3][2] / (d + WinMatrix[2][2]);
+
+ return zview * (viewvecs[0].xyz + vec3(uvcoords, 0.0) * viewvecs[1].xyz);
+ }
+ else {
+ /* Orthographic */
+ vec3 offset = vec3(uvcoords, depth);
+
+ return viewvecs[0].xyz + offset * viewvecs[1].xyz;
+ }
+}
+
+/* forward declartion */
+void ssao_factors(
+ in float depth, in vec3 normal, in vec3 position, in vec2 screenco,
+ out float cavities, out float edges);
+
+
+void main()
+{
+ vec2 screenco = vec2(gl_FragCoord.xy) * invertedViewportSize;
+ ivec2 texel = ivec2(gl_FragCoord.xy);
+
+ float depth = texelFetch(depthBuffer, texel, 0).x;
+ vec3 position = get_view_space_from_depth(screenco, depth);
+
+ vec4 diffuse_color = texelFetch(colorBuffer, texel, 0);
+ vec3 normal_viewport = normal_decode(texelFetch(normalBuffer, texel, 0).rg);
+ if (diffuse_color.a == 0.0) {
+ normal_viewport = -normal_viewport;
+ }
+
+ float cavity = 0.0, edges = 0.0;
+ ssao_factors(depth, normal_viewport, position, screenco, cavity, edges);
+
+ fragColor = vec4(cavity, edges, 0.0, 1.0);
+}
diff --git a/source/blender/draw/engines/workbench/shaders/workbench_cavity_lib.glsl b/source/blender/draw/engines/workbench/shaders/workbench_cavity_lib.glsl
new file mode 100644
index 00000000000..da0198ab2e7
--- /dev/null
+++ b/source/blender/draw/engines/workbench/shaders/workbench_cavity_lib.glsl
@@ -0,0 +1,79 @@
+
+
+/* from The Alchemy screen-space ambient obscurance algorithm
+ * http://graphics.cs.williams.edu/papers/AlchemyHPG11/VV11AlchemyAO.pdf */
+
+void ssao_factors(
+ in float depth, in vec3 normal, in vec3 position, in vec2 screenco,
+ out float cavities, out float edges)
+{
+ cavities = edges = 0.0;
+ /* early out if there is no need for SSAO */
+ if (ssao_factor_cavity == 0.0 && ssao_factor_edge == 0.0)
+ return;
+
+ /* take the normalized ray direction here */
+ vec3 noise = texture(ssao_jitter, screenco.xy * jitter_tilling).rgb;
+
+ /* find the offset in screen space by multiplying a point
+ * in camera space at the depth of the point by the projection matrix. */
+ vec2 offset;
+ float homcoord = WinMatrix[2][3] * position.z + WinMatrix[3][3];
+ offset.x = WinMatrix[0][0] * ssao_distance / homcoord;
+ offset.y = WinMatrix[1][1] * ssao_distance / homcoord;
+ /* convert from -1.0...1.0 range to 0.0..1.0 for easy use with texture coordinates */
+ offset *= 0.5;
+
+ int num_samples = int(ssao_samples_num);
+
+ /* Note. Putting noise usage here to put some ALU after texture fetch. */
+ vec2 rotX = noise.rg;
+ vec2 rotY = vec2(-rotX.y, rotX.x);
+
+ for (int x = 0; x < num_samples && x < 500; x++) {
+ /* ssao_samples[x].xy is sample direction (normalized).
+ * ssao_samples[x].z is sample distance from disk center. */
+
+ /* Rotate with random direction to get jittered result. */
+ vec2 dir_jittered = vec2(dot(ssao_samples[x].xy, rotX), dot(ssao_samples[x].xy, rotY));
+ dir_jittered.xy *= ssao_samples[x].z + noise.b;
+
+ vec2 uvcoords = screenco.xy + dir_jittered * offset;
+
+ if (uvcoords.x > 1.0 || uvcoords.x < 0.0 || uvcoords.y > 1.0 || uvcoords.y < 0.0)
+ continue;
+
+ float depth_new = texture(depthBuffer, uvcoords).r;
+
+ /* Handle Background case */
+ bool is_background = (depth_new == 1.0);
+
+ /* This trick provide good edge effect even if no neighboor is found. */
+ vec3 pos_new = get_view_space_from_depth(uvcoords, (is_background) ? depth : depth_new);
+
+ if (is_background)
+ pos_new.z -= ssao_distance;
+
+ vec3 dir = pos_new - position;
+ float len = length(dir);
+ float f_cavities = dot(dir, normal);
+ float f_edge = -f_cavities;
+ float f_bias = 0.05 * len + 0.0001;
+
+ float attenuation = 1.0 / (len * (1.0 + len * len * ssao_attenuation));
+
+ /* use minor bias here to avoid self shadowing */
+ if (f_cavities > -f_bias)
+ cavities += f_cavities * attenuation;
+
+ if (f_edge > f_bias)
+ edges += f_edge * attenuation;
+ }
+
+ cavities /= ssao_samples_num;
+ edges /= ssao_samples_num;
+
+ /* don't let cavity wash out the surface appearance */
+ cavities = clamp(cavities * ssao_factor_cavity, 0.0, 1.0);
+ edges = edges * ssao_factor_edge;
+}
diff --git a/source/blender/draw/engines/workbench/shaders/workbench_data_lib.glsl b/source/blender/draw/engines/workbench/shaders/workbench_data_lib.glsl
index fc076ee8117..f67d2ff6745 100644
--- a/source/blender/draw/engines/workbench/shaders/workbench_data_lib.glsl
+++ b/source/blender/draw/engines/workbench/shaders/workbench_data_lib.glsl
@@ -16,7 +16,8 @@ struct WorldData {
vec4 light_direction_vs;
LightData lights[3];
int num_lights;
- int pad[3];
+ int matcap_orientation;
+ int pad[2];
};
struct MaterialData {
diff --git a/source/blender/draw/engines/workbench/shaders/workbench_deferred_composite_frag.glsl b/source/blender/draw/engines/workbench/shaders/workbench_deferred_composite_frag.glsl
index 5f37490603d..e5ee272e7fd 100644
--- a/source/blender/draw/engines/workbench/shaders/workbench_deferred_composite_frag.glsl
+++ b/source/blender/draw/engines/workbench/shaders/workbench_deferred_composite_frag.glsl
@@ -5,12 +5,17 @@ uniform sampler2D colorBuffer;
uniform sampler2D specularBuffer;
uniform sampler2D normalBuffer;
/* normalBuffer contains viewport normals */
+uniform sampler2D cavityBuffer;
+
uniform vec2 invertedViewportSize;
uniform float shadowMultiplier;
uniform float lightMultiplier;
uniform float shadowShift = 0.1;
uniform mat3 normalWorldMatrix;
+#ifdef STUDIOLIGHT_ORIENTATION_VIEWNORMAL
+uniform sampler2D matcapImage;
+#endif
layout(std140) uniform world_block {
WorldData world_data;
@@ -43,16 +48,25 @@ void main()
#endif /* !V3D_SHADING_OBJECT_OUTLINE */
vec4 diffuse_color = texelFetch(colorBuffer, texel, 0);
+
/* Do we need normals */
#ifdef NORMAL_VIEWPORT_PASS_ENABLED
-#ifdef WORKBENCH_ENCODE_NORMALS
+# ifdef WORKBENCH_ENCODE_NORMALS
vec3 normal_viewport = normal_decode(texelFetch(normalBuffer, texel, 0).rg);
if (diffuse_color.a == 0.0) {
normal_viewport = -normal_viewport;
}
-#else /* WORKBENCH_ENCODE_NORMALS */
+# else /* WORKBENCH_ENCODE_NORMALS */
vec3 normal_viewport = texelFetch(normalBuffer, texel, 0).rgb;
-#endif /* WORKBENCH_ENCODE_NORMALS */
+# endif /* WORKBENCH_ENCODE_NORMALS */
+#endif
+
+#ifdef STUDIOLIGHT_ORIENTATION_VIEWNORMAL
+ vec2 matcap_uv = normal_viewport.xy / 2.0 + 0.5;
+ if (world_data.matcap_orientation != 0) {
+ matcap_uv.x = 1.0 - matcap_uv.x;
+ }
+ diffuse_color = texture(matcapImage, matcap_uv);
#endif
#ifdef V3D_SHADING_SPECULAR_HIGHLIGHT
@@ -64,21 +78,31 @@ void main()
vec3 specular_color = vec3(0.0);
#endif
+#ifdef V3D_LIGHTING_FLAT
+ vec3 diffuse_light = vec3(1.0);
+#endif
+
+#ifdef V3D_LIGHTING_MATCAP
+ vec3 diffuse_light = texelFetch(specularBuffer, texel, 0).rgb;
+#endif
+
#ifdef V3D_LIGHTING_STUDIO
- #ifdef STUDIOLIGHT_ORIENTATION_CAMERA
+# ifdef STUDIOLIGHT_ORIENTATION_CAMERA
vec3 diffuse_light = get_camera_diffuse_light(world_data, normal_viewport);
- #endif
+# endif
- #ifdef STUDIOLIGHT_ORIENTATION_WORLD
+# ifdef STUDIOLIGHT_ORIENTATION_WORLD
vec3 normal_world = normalWorldMatrix * normal_viewport;
vec3 diffuse_light = get_world_diffuse_light(world_data, normal_world);
- #endif
+# endif
+#endif
vec3 shaded_color = diffuse_light * diffuse_color.rgb + specular_color;
-#else /* V3D_LIGHTING_STUDIO */
- vec3 shaded_color = diffuse_color.rgb + specular_color;
-
-#endif /* V3D_LIGHTING_STUDIO */
+#ifdef V3D_SHADING_CAVITY
+ vec2 cavity = texelFetch(cavityBuffer, texel, 0).rg;
+ shaded_color *= 1.0 - cavity.x;
+ shaded_color *= 1.0 + cavity.y;
+#endif
#ifdef V3D_SHADING_SHADOW
float light_factor = -dot(normal_viewport, world_data.light_direction_vs.xyz);
diff --git a/source/blender/draw/engines/workbench/shaders/workbench_forward_transparent_accum_frag.glsl b/source/blender/draw/engines/workbench/shaders/workbench_forward_transparent_accum_frag.glsl
index a9c84e11aa6..e04bffdeea5 100644
--- a/source/blender/draw/engines/workbench/shaders/workbench_forward_transparent_accum_frag.glsl
+++ b/source/blender/draw/engines/workbench/shaders/workbench_forward_transparent_accum_frag.glsl
@@ -10,6 +10,9 @@ in vec3 normal_viewport;
#ifdef OB_TEXTURE
in vec2 uv_interp;
#endif
+#ifdef STUDIOLIGHT_ORIENTATION_VIEWNORMAL
+uniform sampler2D matcapImage;
+#endif
layout(std140) uniform world_block {
WorldData world_data;
@@ -25,6 +28,7 @@ layout(location=0) out vec4 transparentAccum;
void main()
{
vec4 diffuse_color;
+ vec3 diffuse_light = vec3(1.0);
#ifdef OB_SOLID
diffuse_color = material_data.diffuse_color;
#endif /* OB_SOLID */
@@ -32,6 +36,10 @@ void main()
diffuse_color = texture(image, uv_interp);
#endif /* OB_TEXTURE */
+#ifdef V3D_LIGHTING_MATCAP
+ diffuse_light = texture(matcapImage, normal_viewport.xy / 2.0 + 0.5).rgb;
+#endif
+
#ifdef V3D_SHADING_SPECULAR_HIGHLIGHT
vec3 specular_color = get_world_specular_lights(world_data, vec4(material_data.specular_color.rgb, material_data.roughness), normal_viewport, vec3(0.0, 0.0, 1.0));
#else
@@ -40,17 +48,16 @@ void main()
#ifdef V3D_LIGHTING_STUDIO
# ifdef STUDIOLIGHT_ORIENTATION_CAMERA
- vec3 diffuse_light = get_camera_diffuse_light(world_data, normal_viewport);
+ diffuse_light = get_camera_diffuse_light(world_data, normal_viewport);
# endif
# ifdef STUDIOLIGHT_ORIENTATION_WORLD
vec3 normal_world = normalWorldMatrix * normal_viewport;
- vec3 diffuse_light = get_world_diffuse_light(world_data, normal_world);
+ diffuse_light = get_world_diffuse_light(world_data, normal_world);
# endif
- vec3 shaded_color = diffuse_light * diffuse_color.rgb + specular_color;
-#else
- vec3 shaded_color = diffuse_color.rgb + specular_color;
#endif
+ vec3 shaded_color = diffuse_light * diffuse_color.rgb + specular_color;
+
vec4 premultiplied = vec4(shaded_color.rgb * alpha, alpha);
transparentAccum = calculate_transparent_accum(premultiplied);
}
diff --git a/source/blender/draw/engines/workbench/shaders/workbench_prepass_frag.glsl b/source/blender/draw/engines/workbench/shaders/workbench_prepass_frag.glsl
index bc7741f853c..200850e3036 100644
--- a/source/blender/draw/engines/workbench/shaders/workbench_prepass_frag.glsl
+++ b/source/blender/draw/engines/workbench/shaders/workbench_prepass_frag.glsl
@@ -9,9 +9,9 @@ uniform sampler2D image;
#endif
#ifdef NORMAL_VIEWPORT_PASS_ENABLED
-in vec3 position_viewport;
in vec3 normal_viewport;
#endif /* NORMAL_VIEWPORT_PASS_ENABLED */
+
#ifdef OB_TEXTURE
in vec2 uv_interp;
#endif /* OB_TEXTURE */
@@ -24,19 +24,30 @@ layout(location=0) out uint objectId;
layout(location=1) out vec4 diffuseColor;
layout(location=2) out vec4 specularColor;
#ifdef NORMAL_VIEWPORT_PASS_ENABLED
- #ifdef WORKBENCH_ENCODE_NORMALS
+# ifdef WORKBENCH_ENCODE_NORMALS
layout(location=3) out vec2 normalViewport;
- #else /* WORKBENCH_ENCODE_NORMALS */
+# else /* WORKBENCH_ENCODE_NORMALS */
layout(location=3) out vec3 normalViewport;
- #endif /* WORKBENCH_ENCODE_NORMALS */
+# endif /* WORKBENCH_ENCODE_NORMALS */
#endif /* NORMAL_VIEWPORT_PASS_ENABLED */
void main()
{
objectId = uint(object_id);
+
+#ifdef NORMAL_VIEWPORT_PASS_ENABLED
+ vec3 n = (gl_FrontFacing) ? normal_viewport : -normal_viewport;
+ n = normalize(n);
+#endif
+
#ifdef OB_SOLID
diffuseColor = vec4(material_data.diffuse_color.rgb, 0.0);
+# ifdef STUDIOLIGHT_ORIENTATION_VIEWNORMAL
+
+ specularColor = vec4(material_data.diffuse_color.rgb, 0.0);
+# endif
#endif /* OB_SOLID */
+
#ifdef OB_TEXTURE
diffuseColor = texture(image, uv_interp);
#endif /* OB_TEXTURE */
@@ -47,14 +58,12 @@ void main()
#ifdef V3D_SHADING_SPECULAR_HIGHLIGHT
specularColor = vec4(material_data.specular_color.rgb, material_data.roughness);
-#ifdef HAIR_SHADER
+# ifdef HAIR_SHADER
specularColor.rgb = clamp(specularColor.rgb - hair_color_variation, 0.0, 1.0);
-#endif
+# endif
#endif
#ifdef NORMAL_VIEWPORT_PASS_ENABLED
- vec3 n = (gl_FrontFacing) ? normal_viewport : -normal_viewport;
- n = normalize(n);
# ifdef WORKBENCH_ENCODE_NORMALS
diffuseColor.a = float(gl_FrontFacing);
normalViewport = normal_encode(n);
diff --git a/source/blender/draw/engines/workbench/shaders/workbench_prepass_vert.glsl b/source/blender/draw/engines/workbench/shaders/workbench_prepass_vert.glsl
index 7da9c2644fe..82443e7336b 100644
--- a/source/blender/draw/engines/workbench/shaders/workbench_prepass_vert.glsl
+++ b/source/blender/draw/engines/workbench/shaders/workbench_prepass_vert.glsl
@@ -18,6 +18,7 @@ flat out float hair_rand;
#ifdef NORMAL_VIEWPORT_PASS_ENABLED
out vec3 normal_viewport;
#endif
+
#ifdef OB_TEXTURE
out vec2 uv_interp;
#endif
@@ -57,6 +58,7 @@ void main()
#ifdef OB_TEXTURE
uv_interp = uv;
#endif
+
#ifdef NORMAL_VIEWPORT_PASS_ENABLED
normal_viewport = NormalMatrix * nor;
# ifndef HAIR_SHADER
diff --git a/source/blender/draw/engines/workbench/shaders/workbench_world_light_lib.glsl b/source/blender/draw/engines/workbench/shaders/workbench_world_light_lib.glsl
index be124257c33..6f4237ebd0a 100644
--- a/source/blender/draw/engines/workbench/shaders/workbench_world_light_lib.glsl
+++ b/source/blender/draw/engines/workbench/shaders/workbench_world_light_lib.glsl
@@ -29,7 +29,7 @@ vec3 get_world_specular_light(vec4 specular_data, LightData light_data, vec3 N,
float shininess = exp2(10*(1.0-specular_data.a) + 1);
-#ifdef BLINN
+# ifdef BLINN
float normalization_factor = (shininess + 8) / (8 * M_PI);
vec3 L = -light_data.light_direction_vs.xyz;
vec3 halfDir = normalize(L + I);
@@ -37,11 +37,11 @@ vec3 get_world_specular_light(vec4 specular_data, LightData light_data, vec3 N,
float NL = max(dot(L, N), 0.0);
float specular_influence = pow(specAngle, shininess) * NL * normalization_factor;
-#else
+# else
vec3 reflection_vector = reflect(I, N);
float specAngle = max(dot(light_data.light_direction_vs.xyz, reflection_vector), 0.0);
float specular_influence = pow(specAngle, shininess);
-#endif
+# endif
vec3 specular_color = specular_light * specular_influence;
diff --git a/source/blender/draw/engines/workbench/workbench_data.c b/source/blender/draw/engines/workbench/workbench_data.c
index 4ee12a692f5..df0a2bf4684 100644
--- a/source/blender/draw/engines/workbench/workbench_data.c
+++ b/source/blender/draw/engines/workbench/workbench_data.c
@@ -15,7 +15,14 @@ void workbench_private_data_init(WORKBENCH_PrivateData *wpd)
if (v3d) {
wpd->shading = v3d->shading;
wpd->drawtype = v3d->drawtype;
- wpd->studio_light = BKE_studiolight_find(wpd->shading.studio_light, 0);
+ if (wpd->shading.light == V3D_LIGHTING_MATCAP) {
+ wpd->studio_light = BKE_studiolight_find(
+ wpd->shading.matcap, STUDIOLIGHT_ORIENTATION_VIEWNORMAL);
+ }
+ else {
+ wpd->studio_light = BKE_studiolight_find(
+ wpd->shading.studio_light, STUDIOLIGHT_ORIENTATION_CAMERA | STUDIOLIGHT_ORIENTATION_WORLD);
+ }
}
else {
memset(&wpd->shading, 0, sizeof(wpd->shading));
@@ -23,11 +30,12 @@ void workbench_private_data_init(WORKBENCH_PrivateData *wpd)
wpd->shading.shadow_intensity = 0.5;
copy_v3_fl(wpd->shading.single_color, 0.8f);
wpd->drawtype = OB_SOLID;
- wpd->studio_light = BKE_studiolight_findindex(0);
+ wpd->studio_light = BKE_studiolight_find_first(STUDIOLIGHT_INTERNAL);
}
wpd->shadow_multiplier = 1.0 - wpd->shading.shadow_intensity;
WORKBENCH_UBO_World *wd = &wpd->world_data;
+ wd->matcap_orientation = (wpd->shading.flag & V3D_SHADING_MATCAP_FLIP_X) > 0;
if ((v3d->flag3 & V3D_SHOW_WORLD) &&
(scene->world != NULL))
@@ -51,6 +59,64 @@ void workbench_private_data_init(WORKBENCH_PrivateData *wpd)
wd->object_outline_color[3] = 1.0f;
wpd->world_ubo = DRW_uniformbuffer_create(sizeof(WORKBENCH_UBO_World), &wpd->world_data);
+
+ /* Cavity settings */
+ {
+ const int ssao_samples = scene->display.matcap_ssao_samples;
+
+ float invproj[4][4];
+ float dfdyfacs[2];
+ const bool is_persp = DRW_viewport_is_persp_get();
+ /* view vectors for the corners of the view frustum.
+ * Can be used to recreate the world space position easily */
+ float viewvecs[3][4] = {
+ {-1.0f, -1.0f, -1.0f, 1.0f},
+ {1.0f, -1.0f, -1.0f, 1.0f},
+ {-1.0f, 1.0f, -1.0f, 1.0f}
+ };
+ int i;
+ const float *size = DRW_viewport_size_get();
+
+ DRW_state_dfdy_factors_get(dfdyfacs);
+
+ wpd->ssao_params[0] = ssao_samples;
+ wpd->ssao_params[1] = size[0] / 64.0;
+ wpd->ssao_params[2] = size[1] / 64.0;
+ wpd->ssao_params[3] = dfdyfacs[1]; /* dfdy sign for offscreen */
+
+ /* distance, factor, factor, attenuation */
+ copy_v4_fl4(wpd->ssao_settings, scene->display.matcap_ssao_distance, wpd->shading.cavity_valley_factor, wpd->shading.cavity_ridge_factor, scene->display.matcap_ssao_attenuation);
+
+ /* invert the view matrix */
+ DRW_viewport_matrix_get(wpd->winmat, DRW_MAT_WIN);
+ invert_m4_m4(invproj, wpd->winmat);
+
+ /* convert the view vectors to view space */
+ for (i = 0; i < 3; i++) {
+ mul_m4_v4(invproj, viewvecs[i]);
+ /* normalized trick see:
+ * http://www.derschmale.com/2014/01/26/reconstructing-positions-from-the-depth-buffer */
+ mul_v3_fl(viewvecs[i], 1.0f / viewvecs[i][3]);
+ if (is_persp)
+ mul_v3_fl(viewvecs[i], 1.0f / viewvecs[i][2]);
+ viewvecs[i][3] = 1.0;
+
+ copy_v4_v4(wpd->viewvecs[i], viewvecs[i]);
+ }
+
+ /* we need to store the differences */
+ wpd->viewvecs[1][0] -= wpd->viewvecs[0][0];
+ wpd->viewvecs[1][1] = wpd->viewvecs[2][1] - wpd->viewvecs[0][1];
+
+ /* calculate a depth offset as well */
+ if (!is_persp) {
+ float vec_far[] = {-1.0f, -1.0f, 1.0f, 1.0f};
+ mul_m4_v4(invproj, vec_far);
+ mul_v3_fl(vec_far, 1.0f / vec_far[3]);
+ wpd->viewvecs[1][2] = vec_far[2] - wpd->viewvecs[0][2];
+ }
+ }
+
}
void workbench_private_data_get_light_direction(WORKBENCH_PrivateData *wpd, float light_direction[3])
@@ -71,7 +137,7 @@ void workbench_private_data_get_light_direction(WORKBENCH_PrivateData *wpd, floa
wd->num_lights = 1;
}
- if (STUDIOLIGHT_ORIENTATION_CAMERA_ENABLED(wpd)) {
+ if (!STUDIOLIGHT_ORIENTATION_WORLD_ENABLED(wpd)) {
int light_index = 0;
for (int index = 0 ; index < 3; index++) {
SolidLight *sl = &U.light[index];
diff --git a/source/blender/draw/engines/workbench/workbench_deferred.c b/source/blender/draw/engines/workbench/workbench_deferred.c
index ba5ab7f1cc3..c4fa82d39b7 100644
--- a/source/blender/draw/engines/workbench/workbench_deferred.c
+++ b/source/blender/draw/engines/workbench/workbench_deferred.c
@@ -30,6 +30,7 @@
#include "BLI_alloca.h"
#include "BLI_dynstr.h"
#include "BLI_utildefines.h"
+#include "BLI_rand.h"
#include "BKE_node.h"
#include "BKE_particle.h"
@@ -44,6 +45,7 @@
#include "GPU_shader.h"
#include "GPU_texture.h"
+#include "../eevee/eevee_lut.h" /* TODO find somewhere to share blue noise Table */
/* *********** STATIC *********** */
@@ -56,6 +58,7 @@
static struct {
struct GPUShader *prepass_sh_cache[MAX_SHADERS];
struct GPUShader *composite_sh_cache[MAX_SHADERS];
+ struct GPUShader *cavity_sh;
struct GPUShader *shadow_fail_sh;
struct GPUShader *shadow_fail_manifold_sh;
struct GPUShader *shadow_pass_sh;
@@ -65,6 +68,7 @@ static struct {
struct GPUTexture *object_id_tx; /* ref only, not alloced */
struct GPUTexture *color_buffer_tx; /* ref only, not alloced */
+ struct GPUTexture *cavity_buffer_tx; /* ref only, not alloced */
struct GPUTexture *specular_buffer_tx; /* ref only, not alloced */
struct GPUTexture *normal_buffer_tx; /* ref only, not alloced */
struct GPUTexture *composite_buffer_tx; /* ref only, not alloced */
@@ -73,6 +77,10 @@ static struct {
float light_direction_vs[3];
int next_object_id;
float normal_world_matrix[3][3];
+
+ struct GPUUniformBuffer *sampling_ubo;
+ struct GPUTexture *jitter_tx;
+ int cached_sample_num;
} e_data = {{NULL}};
/* Shaders */
@@ -80,6 +88,7 @@ extern char datatoc_common_hair_lib_glsl[];
extern char datatoc_workbench_prepass_vert_glsl[];
extern char datatoc_workbench_prepass_frag_glsl[];
+extern char datatoc_workbench_cavity_frag_glsl[];
extern char datatoc_workbench_deferred_composite_frag_glsl[];
extern char datatoc_workbench_shadow_vert_glsl[];
@@ -88,6 +97,7 @@ extern char datatoc_workbench_shadow_caps_geom_glsl[];
extern char datatoc_workbench_shadow_debug_frag_glsl[];
extern char datatoc_workbench_background_lib_glsl[];
+extern char datatoc_workbench_cavity_lib_glsl[];
extern char datatoc_workbench_common_lib_glsl[];
extern char datatoc_workbench_data_lib_glsl[];
extern char datatoc_workbench_object_outline_lib_glsl[];
@@ -146,6 +156,21 @@ static char *workbench_build_prepass_vert(void)
return str;
}
+static char *workbench_build_cavity_frag(void)
+{
+ char *str = NULL;
+
+ DynStr *ds = BLI_dynstr_new();
+
+ BLI_dynstr_append(ds, datatoc_workbench_common_lib_glsl);
+ BLI_dynstr_append(ds, datatoc_workbench_cavity_frag_glsl);
+ BLI_dynstr_append(ds, datatoc_workbench_cavity_lib_glsl);
+
+ str = BLI_dynstr_get_cstring(ds);
+ BLI_dynstr_free(ds);
+ return str;
+}
+
static void ensure_deferred_shaders(WORKBENCH_PrivateData *wpd, int index, int drawtype, bool is_hair)
{
if (e_data.prepass_sh_cache[index] == NULL) {
@@ -185,13 +210,57 @@ static void select_deferred_shaders(WORKBENCH_PrivateData *wpd)
wpd->composite_sh = e_data.composite_sh_cache[index_solid];
}
+
+/* Using Hammersley distribution */
+static float *create_disk_samples(int num_samples)
+{
+ /* vec4 to ensure memory alignment. */
+ float (*texels)[4] = MEM_mallocN(sizeof(float[4]) * num_samples, "concentric_tex");
+ const float num_samples_inv = 1.0f / num_samples;
+
+ for (int i = 0; i < num_samples; i++) {
+ float r = (i + 0.5f) * num_samples_inv;
+ double dphi;
+ BLI_hammersley_1D(i, &dphi);
+
+ float phi = (float)dphi * 2.0f * M_PI;
+ texels[i][0] = cosf(phi);
+ texels[i][1] = sinf(phi);
+ /* This deliberatly distribute more samples
+ * at the center of the disk (and thus the shadow). */
+ texels[i][2] = r;
+ }
+
+ return (float *)texels;
+}
+
+static struct GPUTexture *create_jitter_texture(int num_samples)
+{
+ float jitter[64 * 64][3];
+ const float num_samples_inv = 1.0f / num_samples;
+
+ for (int i = 0; i < 64 * 64; i++) {
+ float phi = blue_noise[i][0] * 2.0f * M_PI;
+ /* This rotate the sample per pixels */
+ jitter[i][0] = cosf(phi);
+ jitter[i][1] = sinf(phi);
+ /* This offset the sample along it's direction axis (reduce banding) */
+ float bn = blue_noise[i][1] - 0.5f;
+ CLAMP(bn, -0.499f, 0.499f); /* fix fireflies */
+ jitter[i][2] = bn * num_samples_inv;
+ }
+
+ UNUSED_VARS(bsdf_split_sum_ggx, btdf_split_sum_ggx, ltc_mag_ggx, ltc_mat_ggx, ltc_disk_integral);
+
+ return DRW_texture_create_2D(64, 64, GPU_RGB16F, DRW_TEX_FILTER | DRW_TEX_WRAP, &jitter[0][0]);
+}
/* Functions */
static void workbench_init_object_data(ObjectEngineData *engine_data)
{
WORKBENCH_ObjectData *data = (WORKBENCH_ObjectData *)engine_data;
- data->object_id = e_data.next_object_id++;
+ data->object_id = ((e_data.next_object_id++) & 0xff) + 1;
data->shadow_bbox_dirty = true;
}
@@ -244,6 +313,10 @@ void workbench_deferred_engine_init(WORKBENCH_Data *vedata)
datatoc_workbench_shadow_caps_geom_glsl,
shadow_frag,
"#define SHADOW_FAIL\n");
+
+ char *cavity_frag = workbench_build_cavity_frag();
+ e_data.cavity_sh = DRW_shader_create_fullscreen(cavity_frag, NULL);
+ MEM_freeN(cavity_frag);
}
if (!stl->g_data) {
@@ -251,13 +324,15 @@ void workbench_deferred_engine_init(WORKBENCH_Data *vedata)
stl->g_data = MEM_mallocN(sizeof(*stl->g_data), __func__);
}
- workbench_private_data_init(stl->g_data);
+ WORKBENCH_PrivateData *wpd = stl->g_data;
+ workbench_private_data_init(wpd);
{
const float *viewport_size = DRW_viewport_size_get();
const int size[2] = {(int)viewport_size[0], (int)viewport_size[1]};
e_data.object_id_tx = DRW_texture_pool_query_2D(size[0], size[1], GPU_R32UI, &draw_engine_workbench_solid);
e_data.color_buffer_tx = DRW_texture_pool_query_2D(size[0], size[1], GPU_RGBA8, &draw_engine_workbench_solid);
+ e_data.cavity_buffer_tx = DRW_texture_pool_query_2D(size[0], size[1], GPU_RG16, &draw_engine_workbench_solid);
e_data.specular_buffer_tx = DRW_texture_pool_query_2D(size[0], size[1], GPU_RGBA8, &draw_engine_workbench_solid);
e_data.composite_buffer_tx = DRW_texture_pool_query_2D(
size[0], size[1], GPU_RGBA16F, &draw_engine_workbench_solid);
@@ -278,18 +353,59 @@ void workbench_deferred_engine_init(WORKBENCH_Data *vedata)
GPU_ATTACHMENT_TEXTURE(e_data.specular_buffer_tx),
GPU_ATTACHMENT_TEXTURE(e_data.normal_buffer_tx),
});
+ GPU_framebuffer_ensure_config(&fbl->cavity_fb, {
+ GPU_ATTACHMENT_NONE,
+ GPU_ATTACHMENT_TEXTURE(e_data.cavity_buffer_tx),
+ });
GPU_framebuffer_ensure_config(&fbl->composite_fb, {
GPU_ATTACHMENT_TEXTURE(dtxl->depth),
GPU_ATTACHMENT_TEXTURE(e_data.composite_buffer_tx),
});
}
+ {
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ Scene *scene = draw_ctx->scene;
+ /* AO Samples Tex */
+ const int ssao_samples = scene->display.matcap_ssao_samples;
+ if (e_data.sampling_ubo && (e_data.cached_sample_num != ssao_samples)) {
+ DRW_UBO_FREE_SAFE(e_data.sampling_ubo);
+ DRW_TEXTURE_FREE_SAFE(e_data.jitter_tx);
+ }
+
+ if (e_data.sampling_ubo == NULL) {
+ float *samples = create_disk_samples(ssao_samples);
+ e_data.jitter_tx = create_jitter_texture(ssao_samples);
+ e_data.sampling_ubo = DRW_uniformbuffer_create(sizeof(float[4]) * ssao_samples, samples);
+ e_data.cached_sample_num = ssao_samples;
+ MEM_freeN(samples);
+ }
+ }
+
/* Prepass */
{
int state = DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL;
psl->prepass_pass = DRW_pass_create("Prepass", state);
psl->prepass_hair_pass = DRW_pass_create("Prepass", state);
}
+
+ {
+ int state = DRW_STATE_WRITE_COLOR;
+ psl->cavity_pass = DRW_pass_create("Cavity", state);
+ DRWShadingGroup *grp = DRW_shgroup_create(e_data.cavity_sh, psl->cavity_pass);
+ DRW_shgroup_uniform_texture_ref(grp, "depthBuffer", &dtxl->depth);
+ DRW_shgroup_uniform_texture_ref(grp, "colorBuffer", &e_data.color_buffer_tx);
+ DRW_shgroup_uniform_texture_ref(grp, "normalBuffer", &e_data.normal_buffer_tx);
+
+ DRW_shgroup_uniform_vec2(grp, "invertedViewportSize", DRW_viewport_invert_size_get(), 1);
+ DRW_shgroup_uniform_vec4(grp, "viewvecs[0]", (float *)wpd->viewvecs, 3);
+ DRW_shgroup_uniform_vec4(grp, "ssao_params", wpd->ssao_params, 1);
+ DRW_shgroup_uniform_vec4(grp, "ssao_settings", wpd->ssao_settings, 1);
+ DRW_shgroup_uniform_mat4(grp, "WinMatrix", wpd->winmat);
+ DRW_shgroup_uniform_texture(grp, "ssao_jitter", e_data.jitter_tx);
+ DRW_shgroup_uniform_block(grp, "samples_block", e_data.sampling_ubo);
+ DRW_shgroup_call_add(grp, DRW_cache_fullscreen_quad_get(), NULL);
+ }
}
void workbench_deferred_engine_free()
@@ -298,22 +414,30 @@ void workbench_deferred_engine_free()
DRW_SHADER_FREE_SAFE(e_data.prepass_sh_cache[index]);
DRW_SHADER_FREE_SAFE(e_data.composite_sh_cache[index]);
}
+ DRW_SHADER_FREE_SAFE(e_data.cavity_sh);
+ DRW_UBO_FREE_SAFE(e_data.sampling_ubo);
+ DRW_TEXTURE_FREE_SAFE(e_data.jitter_tx);
+
DRW_SHADER_FREE_SAFE(e_data.shadow_pass_sh);
DRW_SHADER_FREE_SAFE(e_data.shadow_pass_manifold_sh);
DRW_SHADER_FREE_SAFE(e_data.shadow_fail_sh);
DRW_SHADER_FREE_SAFE(e_data.shadow_fail_manifold_sh);
DRW_SHADER_FREE_SAFE(e_data.shadow_caps_sh);
DRW_SHADER_FREE_SAFE(e_data.shadow_caps_manifold_sh);
+
}
static void workbench_composite_uniforms(WORKBENCH_PrivateData *wpd, DRWShadingGroup *grp)
{
DRW_shgroup_uniform_texture_ref(grp, "colorBuffer", &e_data.color_buffer_tx);
DRW_shgroup_uniform_texture_ref(grp, "objectId", &e_data.object_id_tx);
- if (NORMAL_VIEWPORT_PASS_ENABLED(wpd)) {
+ if (NORMAL_VIEWPORT_COMP_PASS_ENABLED(wpd)) {
DRW_shgroup_uniform_texture_ref(grp, "normalBuffer", &e_data.normal_buffer_tx);
}
- if (SPECULAR_HIGHLIGHT_ENABLED(wpd)) {
+ if (CAVITY_ENABLED(wpd)) {
+ DRW_shgroup_uniform_texture_ref(grp, "cavityBuffer", &e_data.cavity_buffer_tx);
+ }
+ if (SPECULAR_HIGHLIGHT_ENABLED(wpd) || MATCAP_ENABLED(wpd)) {
DRW_shgroup_uniform_texture_ref(grp, "specularBuffer", &e_data.specular_buffer_tx);
#if 0
@@ -338,6 +462,11 @@ static void workbench_composite_uniforms(WORKBENCH_PrivateData *wpd, DRWShadingG
DRW_shgroup_uniform_block(grp, "world_block", wpd->world_ubo);
DRW_shgroup_uniform_vec2(grp, "invertedViewportSize", DRW_viewport_invert_size_get(), 1);
+ if (STUDIOLIGHT_ORIENTATION_VIEWNORMAL_ENABLED(wpd)) {
+ BKE_studiolight_ensure_flag(wpd->studio_light, STUDIOLIGHT_EQUIRECTANGULAR_RADIANCE_GPUTEXTURE);
+ DRW_shgroup_uniform_texture(grp, "matcapImage", wpd->studio_light->equirectangular_radiance_gputexture); DRW_shgroup_uniform_texture(grp, "matcapImage", wpd->studio_light->equirectangular_radiance_gputexture);
+ }
+
workbench_material_set_normal_world_matrix(grp, wpd, e_data.normal_world_matrix);
}
@@ -436,7 +565,7 @@ static WORKBENCH_MaterialData *get_or_create_material_data(
/* Solid */
workbench_material_update_data(wpd, ob, mat, &material_template);
- material_template.object_id = engine_object_data->object_id;
+ material_template.object_id = OBJECT_ID_PASS_ENABLED(wpd) ? engine_object_data->object_id : 1;
material_template.drawtype = drawtype;
material_template.ima = ima;
uint hash = workbench_material_get_hash(&material_template);
@@ -447,7 +576,7 @@ static WORKBENCH_MaterialData *get_or_create_material_data(
material->shgrp = DRW_shgroup_create(
drawtype == OB_SOLID ? wpd->prepass_solid_sh : wpd->prepass_texture_sh, psl->prepass_pass);
DRW_shgroup_stencil_mask(material->shgrp, 0xFF);
- material->object_id = engine_object_data->object_id;
+ material->object_id = material_template.object_id;
copy_v4_v4(material->material_data.diffuse_color, material_template.material_data.diffuse_color);
copy_v4_v4(material->material_data.specular_color, material_template.material_data.specular_color);
material->material_data.roughness = material_template.material_data.roughness;
@@ -489,7 +618,7 @@ static void workbench_cache_populate_particles(WORKBENCH_Data *vedata, Object *o
continue;
}
if (!DRW_check_psys_visible_within_active_context(ob, psys)) {
- return;
+ continue;
}
ParticleSettings *part = psys->part;
const int draw_as = (part->draw_as == PART_DRAW_REND) ? part->ren_as : part->draw_as;
@@ -532,7 +661,6 @@ void workbench_deferred_solid_cache_populate(WORKBENCH_Data *vedata, Object *ob)
WORKBENCH_StorageList *stl = vedata->stl;
WORKBENCH_PassList *psl = vedata->psl;
WORKBENCH_PrivateData *wpd = stl->g_data;
-
if (!DRW_object_is_renderable(ob))
return;
@@ -540,6 +668,10 @@ void workbench_deferred_solid_cache_populate(WORKBENCH_Data *vedata, Object *ob)
workbench_cache_populate_particles(vedata, ob);
}
+ if (!DRW_check_object_visible_within_active_context(ob)) {
+ return;
+ }
+
WORKBENCH_MaterialData *material;
if (ELEM(ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_FONT)) {
const DRWContextState *draw_ctx = DRW_context_state_get();
@@ -710,6 +842,12 @@ void workbench_deferred_draw_scene(WORKBENCH_Data *vedata)
GPU_framebuffer_bind(fbl->prepass_fb);
DRW_draw_pass(psl->prepass_pass);
DRW_draw_pass(psl->prepass_hair_pass);
+
+ if (CAVITY_ENABLED(wpd)) {
+ GPU_framebuffer_bind(fbl->cavity_fb);
+ DRW_draw_pass(psl->cavity_pass);
+ }
+
if (SHADOW_ENABLED(wpd)) {
#ifdef DEBUG_SHADOW_VOLUME
GPU_framebuffer_bind(fbl->composite_fb);
diff --git a/source/blender/draw/engines/workbench/workbench_forward.c b/source/blender/draw/engines/workbench/workbench_forward.c
index 3ed0c207bec..8bd27e18da2 100644
--- a/source/blender/draw/engines/workbench/workbench_forward.c
+++ b/source/blender/draw/engines/workbench/workbench_forward.c
@@ -163,7 +163,7 @@ static char *workbench_build_forward_composite_frag(void)
static void workbench_init_object_data(ObjectEngineData *engine_data)
{
WORKBENCH_ObjectData *data = (WORKBENCH_ObjectData *)engine_data;
- data->object_id = e_data.next_object_id++;
+ data->object_id = ((e_data.next_object_id++) & 0xff) + 1;
}
static WORKBENCH_MaterialData *get_or_create_material_data(
@@ -180,7 +180,7 @@ static WORKBENCH_MaterialData *get_or_create_material_data(
/* Solid */
workbench_material_update_data(wpd, ob, mat, &material_template);
- material_template.object_id = engine_object_data->object_id;
+ material_template.object_id = OBJECT_ID_PASS_ENABLED(wpd) ? engine_object_data->object_id : 1;
material_template.drawtype = drawtype;
material_template.ima = ima;
uint hash = workbench_material_get_hash(&material_template);
@@ -202,7 +202,13 @@ static WORKBENCH_MaterialData *get_or_create_material_data(
material->material_data.roughness = material_template.material_data.roughness;
switch (drawtype) {
case OB_SOLID:
+ {
+ if (STUDIOLIGHT_ORIENTATION_VIEWNORMAL_ENABLED(wpd)) {
+ BKE_studiolight_ensure_flag(wpd->studio_light, STUDIOLIGHT_EQUIRECTANGULAR_RADIANCE_GPUTEXTURE);
+ DRW_shgroup_uniform_texture(grp, "matcapImage", wpd->studio_light->equirectangular_radiance_gputexture);
+ }
break;
+ }
case OB_TEXTURE:
{
@@ -451,7 +457,7 @@ static void workbench_forward_cache_populate_particles(WORKBENCH_Data *vedata, O
continue;
}
if (!DRW_check_psys_visible_within_active_context(ob, psys)) {
- return;
+ continue;
}
ParticleSettings *part = psys->part;
const int draw_as = (part->draw_as == PART_DRAW_REND) ? part->ren_as : part->draw_as;
@@ -511,6 +517,11 @@ void workbench_forward_cache_populate(WORKBENCH_Data *vedata, Object *ob)
if (ob->type == OB_MESH) {
workbench_forward_cache_populate_particles(vedata, ob);
}
+
+ if (!DRW_check_object_visible_within_active_context(ob)) {
+ return;
+ }
+
if (ELEM(ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_FONT)) {
const DRWContextState *draw_ctx = DRW_context_state_get();
const bool is_active = (ob == draw_ctx->obact);
diff --git a/source/blender/draw/engines/workbench/workbench_materials.c b/source/blender/draw/engines/workbench/workbench_materials.c
index 7c9c7b96b7b..b25938cd0e5 100644
--- a/source/blender/draw/engines/workbench/workbench_materials.c
+++ b/source/blender/draw/engines/workbench/workbench_materials.c
@@ -12,10 +12,10 @@ void workbench_material_update_data(WORKBENCH_PrivateData *wpd, Object *ob, Mate
/* When in OB_TEXTURE always uyse V3D_SHADING_MATERIAL_COLOR as fallback when no texture could be determined */
int color_type = wpd->drawtype == OB_SOLID ? wpd->shading.color_type : V3D_SHADING_MATERIAL_COLOR;
static float default_diffuse_color[] = {0.8f, 0.8f, 0.8f, 1.0f};
- static float default_specular_color[] = {1.0f, 1.0f, 1.0f, 1.0f};
+ static float default_specular_color[] = {0.5f, 0.5f, 0.5f, 0.5f};
copy_v4_v4(data->material_data.diffuse_color, default_diffuse_color);
copy_v4_v4(data->material_data.specular_color, default_specular_color);
- data->material_data.roughness = 0.25f;
+ data->material_data.roughness = 0.5f;
if (DRW_object_is_paint_mode(ob) || color_type == V3D_SHADING_SINGLE_COLOR) {
copy_v3_v3(data->material_data.diffuse_color, wpd->shading.single_color);
@@ -52,17 +52,29 @@ char *workbench_material_build_defines(WORKBENCH_PrivateData *wpd, int drawtype,
if (wpd->shading.flag & V3D_SHADING_SHADOW) {
BLI_dynstr_appendf(ds, "#define V3D_SHADING_SHADOW\n");
}
- if (wpd->shading.flag & V3D_SHADING_SPECULAR_HIGHLIGHT) {
+ if (CAVITY_ENABLED(wpd)) {
+ BLI_dynstr_appendf(ds, "#define V3D_SHADING_CAVITY\n");
+ }
+ if (SPECULAR_HIGHLIGHT_ENABLED(wpd)) {
BLI_dynstr_appendf(ds, "#define V3D_SHADING_SPECULAR_HIGHLIGHT\n");
}
- if (wpd->shading.light & V3D_LIGHTING_STUDIO) {
+ if (STUDIOLIGHT_ENABLED(wpd)) {
BLI_dynstr_appendf(ds, "#define V3D_LIGHTING_STUDIO\n");
- if (STUDIOLIGHT_ORIENTATION_WORLD_ENABLED(wpd)) {
- BLI_dynstr_appendf(ds, "#define STUDIOLIGHT_ORIENTATION_WORLD\n");
- }
- else {
- BLI_dynstr_appendf(ds, "#define STUDIOLIGHT_ORIENTATION_CAMERA\n");
- }
+ }
+ if (FLAT_ENABLED(wpd)) {
+ BLI_dynstr_appendf(ds, "#define V3D_LIGHTING_FLAT\n");
+ }
+ if (MATCAP_ENABLED(wpd)) {
+ BLI_dynstr_appendf(ds, "#define V3D_LIGHTING_MATCAP\n");
+ }
+ if (STUDIOLIGHT_ORIENTATION_WORLD_ENABLED(wpd)) {
+ BLI_dynstr_appendf(ds, "#define STUDIOLIGHT_ORIENTATION_WORLD\n");
+ }
+ if (STUDIOLIGHT_ORIENTATION_CAMERA_ENABLED(wpd)) {
+ BLI_dynstr_appendf(ds, "#define STUDIOLIGHT_ORIENTATION_CAMERA\n");
+ }
+ if (STUDIOLIGHT_ORIENTATION_VIEWNORMAL_ENABLED(wpd)) {
+ BLI_dynstr_appendf(ds, "#define STUDIOLIGHT_ORIENTATION_VIEWNORMAL\n");
}
if (NORMAL_VIEWPORT_PASS_ENABLED(wpd)) {
BLI_dynstr_appendf(ds, "#define NORMAL_VIEWPORT_PASS_ENABLED\n");
@@ -94,7 +106,6 @@ char *workbench_material_build_defines(WORKBENCH_PrivateData *wpd, int drawtype,
uint workbench_material_get_hash(WORKBENCH_MaterialData *material_template)
{
- /* TODO: make a C-string with settings and hash the string */
uint input[4];
uint result;
float *color = material_template->material_data.diffuse_color;
@@ -121,18 +132,21 @@ uint workbench_material_get_hash(WORKBENCH_MaterialData *material_template)
int workbench_material_get_shader_index(WORKBENCH_PrivateData *wpd, int drawtype, bool is_hair)
{
/* NOTE: change MAX_SHADERS accordingly when modifying this function. */
- const int DRAWOPTIONS_MASK = V3D_SHADING_OBJECT_OUTLINE | V3D_SHADING_SHADOW | V3D_SHADING_SPECULAR_HIGHLIGHT;
- int index = (wpd->shading.flag & DRAWOPTIONS_MASK);
- index = (index << 2) + wpd->shading.light;
- index = (index << 3);
- /* set the drawtype flag
- 0 = OB_SOLID,
- 1 = OB_TEXTURE
- 2 = STUDIOLIGHT_ORIENTATION_WORLD
- */
- SET_FLAG_FROM_TEST(index, wpd->studio_light->flag & STUDIOLIGHT_ORIENTATION_WORLD, 2);
- SET_FLAG_FROM_TEST(index, drawtype == OB_TEXTURE, 1);
- SET_FLAG_FROM_TEST(index, is_hair, 4);
+ int index = 0;
+ /* 1 bit OB_SOLID and OB_TEXTURE */
+ SET_FLAG_FROM_TEST(index, drawtype == OB_TEXTURE, 1 << 0);
+ /* 2 bits FLAT/STUDIO/MATCAP/SCENE */
+ SET_FLAG_FROM_TEST(index, wpd->shading.light, wpd->shading.light << 1);
+ /* 1 bit V3D_SHADING_SPECULAR_HIGHLIGHT */
+ SET_FLAG_FROM_TEST(index, wpd->shading.flag & V3D_SHADING_SPECULAR_HIGHLIGHT, 1 << 3);
+ SET_FLAG_FROM_TEST(index, wpd->shading.flag & V3D_SHADING_SHADOW, 1 << 4);
+ SET_FLAG_FROM_TEST(index, wpd->shading.flag & V3D_SHADING_CAVITY, 1 << 5);
+ SET_FLAG_FROM_TEST(index, wpd->shading.flag & V3D_SHADING_OBJECT_OUTLINE, 1 << 6);
+ /* 2 bits STUDIOLIGHT_ORIENTATION */
+ SET_FLAG_FROM_TEST(index, wpd->studio_light->flag & STUDIOLIGHT_ORIENTATION_WORLD, 1 << 7);
+ SET_FLAG_FROM_TEST(index, wpd->studio_light->flag & STUDIOLIGHT_ORIENTATION_VIEWNORMAL, 1 << 8);
+ /* 1 bit for hair */
+ SET_FLAG_FROM_TEST(index, is_hair, 1 << 9);
return index;
}
diff --git a/source/blender/draw/engines/workbench/workbench_private.h b/source/blender/draw/engines/workbench/workbench_private.h
index 00cb6666430..9c5f97729bf 100644
--- a/source/blender/draw/engines/workbench/workbench_private.h
+++ b/source/blender/draw/engines/workbench/workbench_private.h
@@ -40,20 +40,28 @@
#define M_GOLDEN_RATION_CONJUGATE 0.618033988749895
#define MAX_SHADERS (1 << 10)
-
-#define OBJECT_ID_PASS_ENABLED(wpd) (wpd->shading.flag & V3D_SHADING_OBJECT_OUTLINE)
+#define OB_SOLID_ENABLED(wpd) (wpd->drawtype & OB_SOLID)
+#define OB_TEXTURE_ENABLED(wpd) (wpd->drawtype & OB_TEXTURE)
+#define FLAT_ENABLED(wpd) (wpd->shading.light == V3D_LIGHTING_FLAT)
+#define STUDIOLIGHT_ENABLED(wpd) (wpd->shading.light == V3D_LIGHTING_STUDIO)
+#define MATCAP_ENABLED(wpd) (wpd->shading.light == V3D_LIGHTING_MATCAP && OB_SOLID_ENABLED(wpd))
+#define STUDIOLIGHT_ORIENTATION_WORLD_ENABLED(wpd) (STUDIOLIGHT_ENABLED(wpd) && (wpd->studio_light->flag & STUDIOLIGHT_ORIENTATION_WORLD))
+#define STUDIOLIGHT_ORIENTATION_CAMERA_ENABLED(wpd) (STUDIOLIGHT_ENABLED(wpd) && (wpd->studio_light->flag & STUDIOLIGHT_ORIENTATION_CAMERA))
+#define STUDIOLIGHT_ORIENTATION_VIEWNORMAL_ENABLED(wpd) (MATCAP_ENABLED(wpd) && (wpd->studio_light->flag & STUDIOLIGHT_ORIENTATION_VIEWNORMAL))
+#define CAVITY_ENABLED(wpd) (wpd->shading.flag & V3D_SHADING_CAVITY)
#define SHADOW_ENABLED(wpd) (wpd->shading.flag & V3D_SHADING_SHADOW)
-#define SPECULAR_HIGHLIGHT_ENABLED(wpd) (wpd->shading.flag & V3D_SHADING_SPECULAR_HIGHLIGHT)
-#define NORMAL_VIEWPORT_PASS_ENABLED(wpd) (wpd->shading.light & V3D_LIGHTING_STUDIO || SHADOW_ENABLED(wpd) || SPECULAR_HIGHLIGHT_ENABLED (wpd))
+#define SPECULAR_HIGHLIGHT_ENABLED(wpd) ((wpd->shading.flag & V3D_SHADING_SPECULAR_HIGHLIGHT) && (!STUDIOLIGHT_ORIENTATION_VIEWNORMAL_ENABLED(wpd)))
+#define OBJECT_ID_PASS_ENABLED(wpd) (wpd->shading.flag & V3D_SHADING_OBJECT_OUTLINE)
+#define NORMAL_VIEWPORT_COMP_PASS_ENABLED(wpd) (MATCAP_ENABLED(wpd) || STUDIOLIGHT_ENABLED(wpd) || SHADOW_ENABLED(wpd) || SPECULAR_HIGHLIGHT_ENABLED(wpd))
+#define NORMAL_VIEWPORT_PASS_ENABLED(wpd) (NORMAL_VIEWPORT_COMP_PASS_ENABLED(wpd) || CAVITY_ENABLED(wpd))
#define NORMAL_ENCODING_ENABLED() (true)
#define WORKBENCH_REVEALAGE_ENABLED
-#define STUDIOLIGHT_ORIENTATION_WORLD_ENABLED(wpd) (wpd->studio_light->flag & STUDIOLIGHT_ORIENTATION_WORLD)
-#define STUDIOLIGHT_ORIENTATION_CAMERA_ENABLED(wpd) (wpd->studio_light->flag & STUDIOLIGHT_ORIENTATION_CAMERA)
typedef struct WORKBENCH_FramebufferList {
/* Deferred render buffers */
struct GPUFrameBuffer *prepass_fb;
+ struct GPUFrameBuffer *cavity_fb;
struct GPUFrameBuffer *composite_fb;
/* Forward render buffers */
@@ -73,6 +81,7 @@ typedef struct WORKBENCH_PassList {
/* deferred rendering */
struct DRWPass *prepass_pass;
struct DRWPass *prepass_hair_pass;
+ struct DRWPass *cavity_pass;
struct DRWPass *shadow_depth_pass_pass;
struct DRWPass *shadow_depth_pass_mani_pass;
struct DRWPass *shadow_depth_fail_pass;
@@ -119,7 +128,8 @@ typedef struct WORKBENCH_UBO_World {
float light_direction_vs[4];
WORKBENCH_UBO_Light lights[3];
int num_lights;
- int pad[3];
+ int matcap_orientation;
+ int pad[2];
} WORKBENCH_UBO_World;
BLI_STATIC_ASSERT_ALIGN(WORKBENCH_UBO_World, 16)
@@ -162,6 +172,12 @@ typedef struct WORKBENCH_PrivateData {
float shadow_near_max[3];
float shadow_near_sides[2][4]; /* This is a parallelogram, so only 2 normal and distance to the edges. */
bool shadow_changed;
+
+ /* Ssao */
+ float winmat[4][4];
+ float viewvecs[3][4];
+ float ssao_params[4];
+ float ssao_settings[4];
} WORKBENCH_PrivateData; /* Transient data */
typedef struct WORKBENCH_MaterialData {
diff --git a/source/blender/draw/intern/DRW_render.h b/source/blender/draw/intern/DRW_render.h
index 935a6d362f1..b74e6ba9204 100644
--- a/source/blender/draw/intern/DRW_render.h
+++ b/source/blender/draw/intern/DRW_render.h
@@ -349,6 +349,7 @@ void DRW_shgroup_call_range_add(
void DRW_shgroup_call_procedural_points_add(DRWShadingGroup *shgroup, unsigned int point_count, float (*obmat)[4]);
void DRW_shgroup_call_procedural_lines_add(DRWShadingGroup *shgroup, unsigned int line_count, float (*obmat)[4]);
void DRW_shgroup_call_procedural_triangles_add(DRWShadingGroup *shgroup, unsigned int tria_count, float (*obmat)[4]);
+void DRW_shgroup_call_object_procedural_triangles_culled_add(DRWShadingGroup *shgroup, uint tria_count, struct Object *ob);
void DRW_shgroup_call_object_add_ex(DRWShadingGroup *shgroup, struct Gwn_Batch *geom, struct Object *ob, bool bypass_culling);
#define DRW_shgroup_call_object_add(shgroup, geom, ob) DRW_shgroup_call_object_add_ex(shgroup, geom, ob, false)
#define DRW_shgroup_call_object_add_no_cull(shgroup, geom, ob) DRW_shgroup_call_object_add_ex(shgroup, geom, ob, true)
@@ -523,8 +524,6 @@ bool DRW_state_show_text(void);
bool DRW_state_draw_support(void);
bool DRW_state_draw_background(void);
-enum eDepsObjectIteratorMode DRW_iterator_mode_get(void);
-
struct DRWTextStore *DRW_state_text_cache_get(void);
/* Avoid too many lookups while drawing */
diff --git a/source/blender/draw/intern/draw_armature.c b/source/blender/draw/intern/draw_armature.c
index ed9bb6f8ca9..a736f0a31fb 100644
--- a/source/blender/draw/intern/draw_armature.c
+++ b/source/blender/draw/intern/draw_armature.c
@@ -319,21 +319,32 @@ static void drw_shgroup_bone_custom_solid(
Object *custom)
{
/* grr, not re-using instances! */
- struct Gwn_Batch *geom = DRW_cache_object_surface_get(custom);
- if (geom) {
- DRWShadingGroup *shgrp_geom_solid = shgroup_instance_bone_shape_solid(g_data.passes.bone_solid, geom);
- float final_bonemat[4][4];
+ struct Gwn_Batch *surf = DRW_cache_object_surface_get(custom);
+ struct Gwn_Batch *edges = DRW_cache_object_edge_detection_get(custom, NULL);
+ struct Gwn_Batch *ledges = DRW_cache_object_loose_edges_get(custom);
+ float final_bonemat[4][4];
+
+ if (surf || edges || ledges) {
mul_m4_m4m4(final_bonemat, g_data.ob->obmat, bone_mat);
+ }
+
+ if (surf) {
+ DRWShadingGroup *shgrp_geom_solid = shgroup_instance_bone_shape_solid(g_data.passes.bone_solid, surf);
DRW_shgroup_call_dynamic_add(shgrp_geom_solid, final_bonemat, bone_color, hint_color);
}
- geom = DRW_cache_object_edge_detection_get(custom, NULL);
- if (geom && outline_color[3] > 0.0f) {
- DRWShadingGroup *shgrp_geom_wire = shgroup_instance_bone_shape_outline(g_data.passes.bone_outline, geom);
- float final_bonemat[4][4];
- mul_m4_m4m4(final_bonemat, g_data.ob->obmat, bone_mat);
+ if (edges && outline_color[3] > 0.0f) {
+ DRWShadingGroup *shgrp_geom_wire = shgroup_instance_bone_shape_outline(g_data.passes.bone_outline, edges);
DRW_shgroup_call_dynamic_add(shgrp_geom_wire, final_bonemat, outline_color);
}
+
+ if (ledges) {
+ DRWShadingGroup *shgrp_geom_ledges = shgroup_instance_wire(g_data.passes.bone_wire, ledges);
+ float final_color[4];
+ copy_v3_v3(final_color, outline_color);
+ final_color[3] = 1.0f; /* hack */
+ DRW_shgroup_call_dynamic_add(shgrp_geom_ledges, final_bonemat, final_color);
+ }
}
static void drw_shgroup_bone_custom_wire(
diff --git a/source/blender/draw/intern/draw_cache_impl_mesh.c b/source/blender/draw/intern/draw_cache_impl_mesh.c
index e6dde8adc97..c5d5eac51b7 100644
--- a/source/blender/draw/intern/draw_cache_impl_mesh.c
+++ b/source/blender/draw/intern/draw_cache_impl_mesh.c
@@ -112,6 +112,10 @@ typedef struct EdgeAdjacentPolys {
int face_index[2];
} EdgeAdjacentPolys;
+typedef struct EdgeAdjacentVerts {
+ int vert_index[2]; /* -1 if none */
+} EdgeAdjacentVerts;
+
typedef struct EdgeDrawAttr {
unsigned char v_flag;
unsigned char e_flag;
@@ -1589,7 +1593,7 @@ typedef struct MeshBatchCache {
Gwn_VertBuf *edges_face_overlay;
GPUTexture *edges_face_overlay_tx;
- int edges_face_overlay_tri_count; /* Number of tri in edges_face_overlay_tx */
+ int edges_face_overlay_tri_count; /* Number of tri in edges_face_overlay(_adj)_tx */
/* Maybe have shaded_triangles_data split into pos_nor and uv_tangent
* to minimise data transfer for skinned mesh. */
@@ -3341,29 +3345,66 @@ static Gwn_IndexBuf *mesh_batch_cache_get_edges_adjacency(MeshRenderData *rdata,
}
#undef NO_EDGE
-static GPUTexture *mesh_batch_cache_get_edges_overlay_texture_buf(MeshRenderData *rdata, MeshBatchCache *cache)
+static EdgeHash *create_looptri_edge_adjacency_hash(MeshRenderData *rdata)
{
- BLI_assert(rdata->types & (MR_DATATYPE_VERT | MR_DATATYPE_EDGE | MR_DATATYPE_LOOP | MR_DATATYPE_LOOPTRI));
-
- BLI_assert(rdata->edit_bmesh == NULL); /* Not supported in edit mode */
+ const int tri_len = mesh_render_data_looptri_len_get(rdata);
+ /* Create adjacency info in looptri */
+ EdgeHash *eh = BLI_edgehash_new_ex(__func__, tri_len * 3);
+ /* Create edges for each pair of triangles sharing an edge. */
+ for (int i = 0; i < tri_len; i++) {
+ for (int e = 0; e < 3; ++e) {
+ uint v0, v1, v2;
+ if (rdata->edit_bmesh) {
+ const BMLoop **bm_looptri = (const BMLoop **)rdata->edit_bmesh->looptris[i];
+ if (BM_elem_flag_test(bm_looptri[0]->f, BM_ELEM_HIDDEN)) {
+ break;
+ }
+ v0 = BM_elem_index_get(bm_looptri[e]->v);
+ v1 = BM_elem_index_get(bm_looptri[(e + 1) % 3]->v);
+ v2 = BM_elem_index_get(bm_looptri[(e + 2) % 3]->v);
+ }
+ else {
+ MLoop *mloop = rdata->mloop;
+ MLoopTri *mlt = rdata->mlooptri + i;
+ v0 = mloop[mlt->tri[e]].v;
+ v1 = mloop[mlt->tri[(e + 1) % 3]].v;
+ v2 = mloop[mlt->tri[(e + 2) % 3]].v;
+ }
- if (cache->edges_face_overlay_tx != NULL) {
- return cache->edges_face_overlay_tx;
+ EdgeAdjacentVerts **eav;
+ bool value_is_init = BLI_edgehash_ensure_p(eh, v1, v2, (void ***)&eav);
+ if (!value_is_init) {
+ *eav = MEM_mallocN(sizeof(**eav), "EdgeAdjacentVerts");
+ (*eav)->vert_index[0] = v0;
+ (*eav)->vert_index[1] = -1;
+ }
+ else {
+ if ((*eav)->vert_index[1] == -1) {
+ (*eav)->vert_index[1] = v0;
+ }
+ else {
+ /* Not a manifold edge. */
+ }
+ }
+ }
}
+ return eh;
+}
+static Gwn_VertBuf *mesh_batch_cache_create_edges_overlay_texture_buf(MeshRenderData *rdata)
+{
const int tri_len = mesh_render_data_looptri_len_get(rdata);
- cache->is_manifold = true;
-
Gwn_VertFormat format = {0};
- uint index_id = GWN_vertformat_attr_add(&format, "index", GWN_COMP_I32, 1, GWN_FETCH_INT);
+ uint index_id = GWN_vertformat_attr_add(&format, "index", GWN_COMP_U32, 1, GWN_FETCH_INT);
Gwn_VertBuf *vbo = GWN_vertbuf_create_with_format(&format);
- cache->edges_face_overlay = vbo;
int vbo_len_capacity = tri_len * 3;
GWN_vertbuf_data_alloc(vbo, vbo_len_capacity);
int vidx = 0;
+ EdgeHash *eh = NULL;
+ eh = create_looptri_edge_adjacency_hash(rdata);
for (int i = 0; i < tri_len; i++) {
bool edge_is_real[3] = {false, false, false};
@@ -3385,23 +3426,49 @@ static GPUTexture *mesh_batch_cache_get_edges_overlay_texture_buf(MeshRenderData
}
for (int e = 0; e < 3; ++e) {
- /* Save if there is an edge or not inside the sign bit. */
- int value = (int)mloop[mlt->tri[e]].v + 1; /* Int 0 cannot be signed */
- value = (edge_is_real[e]) ? -value : value;
+ int v0 = mloop[mlt->tri[e]].v;
+ int v1 = mloop[mlt->tri[(e + 1) % 3]].v;
+ EdgeAdjacentVerts *eav = BLI_edgehash_lookup(eh, v0, v1);
+ uint value = (uint)v0;
+ /* Real edge */
+ if (edge_is_real[e]) {
+ value |= (1 << 30);
+ }
+ /* Non-manifold edge */
+ if (eav->vert_index[1] == -1) {
+ value |= (1 << 31);
+ }
GWN_vertbuf_attr_set(vbo, index_id, vidx++, &value);
}
}
+ BLI_edgehash_free(eh, MEM_freeN);
+
int vbo_len_used = vidx;
if (vbo_len_capacity != vbo_len_used) {
GWN_vertbuf_data_resize(vbo, vbo_len_used);
}
+ return vbo;
+}
+
+static GPUTexture *mesh_batch_cache_get_edges_overlay_texture_buf(MeshRenderData *rdata, MeshBatchCache *cache)
+{
+ BLI_assert(rdata->types & (MR_DATATYPE_VERT | MR_DATATYPE_EDGE | MR_DATATYPE_LOOP | MR_DATATYPE_LOOPTRI));
+
+ BLI_assert(rdata->edit_bmesh == NULL); /* Not supported in edit mode */
+
+ if (cache->edges_face_overlay_tx != NULL) {
+ return cache->edges_face_overlay_tx;
+ }
+
+ Gwn_VertBuf *vbo = cache->edges_face_overlay = mesh_batch_cache_create_edges_overlay_texture_buf(rdata);
+
/* Upload data early because we need to create the texture for it. */
GWN_vertbuf_use(vbo);
cache->edges_face_overlay_tx = GPU_texture_create_from_vertbuf(vbo);
- cache->edges_face_overlay_tri_count = vbo_len_used / 3;
+ cache->edges_face_overlay_tri_count = vbo->vertex_alloc / 3;
return cache->edges_face_overlay_tx;
}
diff --git a/source/blender/draw/intern/draw_cache_impl_particles.c b/source/blender/draw/intern/draw_cache_impl_particles.c
index 1348968bad7..380cb089628 100644
--- a/source/blender/draw/intern/draw_cache_impl_particles.c
+++ b/source/blender/draw/intern/draw_cache_impl_particles.c
@@ -181,7 +181,7 @@ static void particle_batch_cache_clear_hair(ParticleHairCache *hair_cache)
for (int i = 0; i < MAX_HAIR_SUBDIV; ++i) {
GWN_VERTBUF_DISCARD_SAFE(hair_cache->final[i].proc_buf);
DRW_TEXTURE_FREE_SAFE(hair_cache->final[i].proc_tex);
- for (int j = 0; j < MAX_THICKRES - 1; ++j) {
+ for (int j = 0; j < MAX_THICKRES; ++j) {
GWN_BATCH_DISCARD_SAFE(hair_cache->final[i].proc_hairs[j]);
}
}
@@ -779,7 +779,7 @@ static void particle_batch_cache_ensure_procedural_strand_data(
ParticleSystemModifierData *psmd = (ParticleSystemModifierData *)md;
- if (psmd != NULL) {
+ if (psmd != NULL && psmd->mesh_final != NULL) {
if (CustomData_has_layer(&psmd->mesh_final->ldata, CD_MLOOPUV)) {
cache->num_uv_layers = CustomData_number_of_layers(&psmd->mesh_final->ldata, CD_MLOOPUV);
active_uv = CustomData_get_active_layer(&psmd->mesh_final->ldata, CD_MLOOPUV);
diff --git a/source/blender/draw/intern/draw_hair.c b/source/blender/draw/intern/draw_hair.c
index 2c03caf0ac3..d5923419b37 100644
--- a/source/blender/draw/intern/draw_hair.c
+++ b/source/blender/draw/intern/draw_hair.c
@@ -109,6 +109,7 @@ static DRWShadingGroup *drw_shgroup_create_hair_procedural_ex(
shgrp = DRW_shgroup_create(gpu_shader, hair_pass);
}
else {
+ shgrp = NULL;
BLI_assert(0);
}
diff --git a/source/blender/draw/intern/draw_instance_data.h b/source/blender/draw/intern/draw_instance_data.h
index 86c4429a091..0ea40a50a6b 100644
--- a/source/blender/draw/intern/draw_instance_data.h
+++ b/source/blender/draw/intern/draw_instance_data.h
@@ -31,7 +31,7 @@
#include "GPU_batch.h"
-#define MAX_INSTANCE_DATA_SIZE 48 /* Can be adjusted for more */
+#define MAX_INSTANCE_DATA_SIZE 64 /* Can be adjusted for more */
typedef struct DRWInstanceData DRWInstanceData;
typedef struct DRWInstanceDataList DRWInstanceDataList;
diff --git a/source/blender/draw/intern/draw_manager.c b/source/blender/draw/intern/draw_manager.c
index d54c943f736..a70f5f8a487 100644
--- a/source/blender/draw/intern/draw_manager.c
+++ b/source/blender/draw/intern/draw_manager.c
@@ -764,6 +764,7 @@ ObjectEngineData *DRW_object_engine_data_ensure(
const size_t t = sizeof(float) - 1;
size = (size + t) & ~t;
size_t fsize = size / sizeof(float);
+ BLI_assert(fsize < MAX_INSTANCE_DATA_SIZE);
if (DST.object_instance_data[fsize] == NULL) {
DST.object_instance_data[fsize] = DRW_instance_data_request(DST.idatalist, fsize);
}
@@ -1232,7 +1233,9 @@ void DRW_draw_view(const bContext *C)
/* Reset before using it. */
drw_state_prepare_clean_for_draw(&DST);
- DST.options.draw_text = (v3d->overlay.flag & V3D_OVERLAY_HIDE_TEXT) != 0;
+ DST.options.draw_text = (
+ (v3d->flag2 & V3D_RENDER_OVERRIDE) == 0 &&
+ (v3d->overlay.flag & V3D_OVERLAY_HIDE_TEXT) != 0);
DRW_draw_render_loop_ex(depsgraph, engine_type, ar, v3d, viewport, C);
}
@@ -1292,7 +1295,7 @@ void DRW_draw_render_loop_ex(
PROFILE_START(stime);
drw_engines_cache_init();
- DEG_OBJECT_ITER_FOR_RENDER_ENGINE_BEGIN(depsgraph, ob, DRW_iterator_mode_get())
+ DEG_OBJECT_ITER_FOR_RENDER_ENGINE_BEGIN(depsgraph, ob)
{
drw_engines_cache_populate(ob);
}
@@ -1544,14 +1547,12 @@ void DRW_render_object_iter(
{
DRW_hair_init();
- DEG_OBJECT_ITER_FOR_RENDER_ENGINE_BEGIN(depsgraph, ob, DRW_iterator_mode_get())
+ DEG_OBJECT_ITER_FOR_RENDER_ENGINE_BEGIN(depsgraph, ob)
{
DST.ob_state = NULL;
callback(vedata, ob, engine, depsgraph);
}
DEG_OBJECT_ITER_FOR_RENDER_ENGINE_END
-
- DRW_hair_update();
}
static struct DRWSelectBuffer {
@@ -1689,13 +1690,17 @@ void DRW_draw_select_loop(
}
else {
DEG_OBJECT_ITER_BEGIN(
- depsgraph, ob, DRW_iterator_mode_get(),
+ depsgraph, ob,
DEG_ITER_OBJECT_FLAG_LINKED_DIRECTLY |
DEG_ITER_OBJECT_FLAG_VISIBLE |
DEG_ITER_OBJECT_FLAG_DUPLI)
{
if ((ob->base_flag & BASE_SELECTABLED) != 0) {
- DRW_select_load_id(ob->select_color);
+ /* This relies on dupli instances being after their instancing object. */
+ if ((ob->base_flag & BASE_FROMDUPLI) == 0) {
+ Object *ob_orig = DEG_get_original_object(ob);
+ DRW_select_load_id(ob_orig->select_color);
+ }
drw_engines_cache_populate(ob);
}
}
@@ -1856,7 +1861,7 @@ void DRW_draw_depth_loop(
if (cache_is_dirty) {
drw_engines_cache_init();
- DEG_OBJECT_ITER_FOR_RENDER_ENGINE_BEGIN(depsgraph, ob, DRW_iterator_mode_get())
+ DEG_OBJECT_ITER_FOR_RENDER_ENGINE_BEGIN(depsgraph, ob)
{
drw_engines_cache_populate(ob);
}
@@ -1971,15 +1976,6 @@ bool DRW_state_is_opengl_render(void)
}
/**
- * Gives you the iterator mode to use for depsgraph.
- */
-eDepsObjectIteratorMode DRW_iterator_mode_get(void)
-{
- return DRW_state_is_scene_render() ? DEG_ITER_OBJECT_MODE_RENDER :
- DEG_ITER_OBJECT_MODE_VIEWPORT;
-}
-
-/**
* Should text draw in this mode?
*/
bool DRW_state_show_text(void)
diff --git a/source/blender/draw/intern/draw_manager_data.c b/source/blender/draw/intern/draw_manager_data.c
index c419e9e2535..b49af47223f 100644
--- a/source/blender/draw/intern/draw_manager_data.c
+++ b/source/blender/draw/intern/draw_manager_data.c
@@ -391,12 +391,17 @@ void DRW_shgroup_call_range_add(DRWShadingGroup *shgroup, Gwn_Batch *geom, float
}
static void drw_shgroup_call_procedural_add_ex(
- DRWShadingGroup *shgroup, Gwn_PrimType prim_type, uint vert_count, float (*obmat)[4])
+ DRWShadingGroup *shgroup, Gwn_PrimType prim_type, uint vert_count, float (*obmat)[4], Object *ob)
{
BLI_assert(ELEM(shgroup->type, DRW_SHG_NORMAL, DRW_SHG_FEEDBACK_TRANSFORM));
DRWCall *call = BLI_mempool_alloc(DST.vmempool->calls);
- call->state = drw_call_state_create(shgroup, obmat, NULL);
+ if (ob) {
+ call->state = drw_call_state_object(shgroup, ob->obmat, ob);
+ }
+ else {
+ call->state = drw_call_state_create(shgroup, obmat, NULL);
+ }
call->type = DRW_CALL_PROCEDURAL;
call->procedural.prim_type = prim_type;
call->procedural.vert_count = vert_count;
@@ -409,17 +414,24 @@ static void drw_shgroup_call_procedural_add_ex(
void DRW_shgroup_call_procedural_points_add(DRWShadingGroup *shgroup, uint point_count, float (*obmat)[4])
{
- drw_shgroup_call_procedural_add_ex(shgroup, GWN_PRIM_POINTS, point_count, obmat);
+ drw_shgroup_call_procedural_add_ex(shgroup, GWN_PRIM_POINTS, point_count, obmat, NULL);
}
void DRW_shgroup_call_procedural_lines_add(DRWShadingGroup *shgroup, uint line_count, float (*obmat)[4])
{
- drw_shgroup_call_procedural_add_ex(shgroup, GWN_PRIM_LINES, line_count * 2, obmat);
+ drw_shgroup_call_procedural_add_ex(shgroup, GWN_PRIM_LINES, line_count * 2, obmat, NULL);
}
void DRW_shgroup_call_procedural_triangles_add(DRWShadingGroup *shgroup, uint tria_count, float (*obmat)[4])
{
- drw_shgroup_call_procedural_add_ex(shgroup, GWN_PRIM_TRIS, tria_count * 3, obmat);
+ drw_shgroup_call_procedural_add_ex(shgroup, GWN_PRIM_TRIS, tria_count * 3, obmat, NULL);
+}
+
+/* TODO (fclem): this is a sign that the api is starting to be limiting.
+ * Maybe add special function that general purpose for special cases. */
+void DRW_shgroup_call_object_procedural_triangles_culled_add(DRWShadingGroup *shgroup, uint tria_count, Object *ob)
+{
+ drw_shgroup_call_procedural_add_ex(shgroup, GWN_PRIM_TRIS, tria_count * 3, NULL, ob);
}
/* These calls can be culled and are optimized for redraw */
@@ -732,7 +744,14 @@ static DRWShadingGroup *drw_shgroup_material_create_ex(GPUPass *gpupass, DRWPass
return NULL;
}
- DRWShadingGroup *grp = drw_shgroup_create_ex(GPU_pass_shader(gpupass), pass);
+ GPUShader *sh = GPU_pass_shader_get(gpupass);
+
+ if (!sh) {
+ /* Shader not yet compiled */
+ return NULL;
+ }
+
+ DRWShadingGroup *grp = drw_shgroup_create_ex(sh, pass);
return grp;
}
@@ -780,7 +799,7 @@ static DRWShadingGroup *drw_shgroup_material_inputs(DRWShadingGroup *grp, struct
}
}
- GPUUniformBuffer *ubo = GPU_material_get_uniform_buffer(material);
+ GPUUniformBuffer *ubo = GPU_material_uniform_buffer_get(material);
if (ubo != NULL) {
DRW_shgroup_uniform_block(grp, GPU_UBO_BLOCK_NAME, ubo);
}
@@ -808,7 +827,7 @@ DRWShadingGroup *DRW_shgroup_material_create(
DRWShadingGroup *shgroup = drw_shgroup_material_create_ex(gpupass, pass);
if (shgroup) {
- drw_shgroup_init(shgroup, GPU_pass_shader(gpupass));
+ drw_shgroup_init(shgroup, GPU_pass_shader_get(gpupass));
drw_shgroup_material_inputs(shgroup, material);
}
@@ -825,7 +844,7 @@ DRWShadingGroup *DRW_shgroup_material_instance_create(
shgroup->type = DRW_SHG_INSTANCE;
shgroup->instance_geom = geom;
drw_call_calc_orco(ob, shgroup->instance_orcofac);
- drw_shgroup_instance_init(shgroup, GPU_pass_shader(gpupass), geom, format);
+ drw_shgroup_instance_init(shgroup, GPU_pass_shader_get(gpupass), geom, format);
drw_shgroup_material_inputs(shgroup, material);
}
@@ -843,7 +862,7 @@ DRWShadingGroup *DRW_shgroup_material_empty_tri_batch_create(
if (shgroup) {
/* Calling drw_shgroup_init will cause it to call GWN_draw_primitive(). */
- drw_shgroup_init(shgroup, GPU_pass_shader(gpupass));
+ drw_shgroup_init(shgroup, GPU_pass_shader_get(gpupass));
shgroup->type = DRW_SHG_TRIANGLE_BATCH;
shgroup->instance_count = tri_count * 3;
drw_shgroup_material_inputs(shgroup, material);
diff --git a/source/blender/draw/intern/draw_manager_shader.c b/source/blender/draw/intern/draw_manager_shader.c
index 56a7c5db08e..0b6974b7b36 100644
--- a/source/blender/draw/intern/draw_manager_shader.c
+++ b/source/blender/draw/intern/draw_manager_shader.c
@@ -62,7 +62,6 @@ typedef struct DRWDeferredShader {
struct DRWDeferredShader *prev, *next;
GPUMaterial *mat;
- char *vert, *geom, *frag, *defs;
} DRWDeferredShader;
typedef struct DRWShaderCompiler {
@@ -80,11 +79,6 @@ typedef struct DRWShaderCompiler {
static void drw_deferred_shader_free(DRWDeferredShader *dsh)
{
/* Make sure it is not queued before freeing. */
- MEM_SAFE_FREE(dsh->vert);
- MEM_SAFE_FREE(dsh->geom);
- MEM_SAFE_FREE(dsh->frag);
- MEM_SAFE_FREE(dsh->defs);
-
MEM_freeN(dsh);
}
@@ -129,12 +123,7 @@ static void drw_deferred_shader_compilation_exec(void *custom_data, short *stop,
BLI_spin_unlock(&comp->list_lock);
/* Do the compilation. */
- GPU_material_generate_pass(
- comp->mat_compiling->mat,
- comp->mat_compiling->vert,
- comp->mat_compiling->geom,
- comp->mat_compiling->frag,
- comp->mat_compiling->defs);
+ GPU_material_compile(comp->mat_compiling->mat);
*progress = (float)comp->shaders_done / (float)total;
*do_update = true;
@@ -165,25 +154,20 @@ static void drw_deferred_shader_compilation_free(void *custom_data)
MEM_freeN(comp);
}
-static void drw_deferred_shader_add(
- GPUMaterial *mat, const char *vert, const char *geom, const char *frag_lib, const char *defines)
+static void drw_deferred_shader_add(GPUMaterial *mat)
{
/* Do not deferre the compilation if we are rendering for image. */
if (DRW_state_is_image_render() || !USE_DEFERRED_COMPILATION) {
/* Double checking that this GPUMaterial is not going to be
* compiled by another thread. */
DRW_deferred_shader_remove(mat);
- GPU_material_generate_pass(mat, vert, geom, frag_lib, defines);
+ GPU_material_compile(mat);
return;
}
DRWDeferredShader *dsh = MEM_callocN(sizeof(DRWDeferredShader), "Deferred Shader");
dsh->mat = mat;
- if (vert) dsh->vert = BLI_strdup(vert);
- if (geom) dsh->geom = BLI_strdup(geom);
- if (frag_lib) dsh->frag = BLI_strdup(frag_lib);
- if (defines) dsh->defs = BLI_strdup(defines);
BLI_assert(DST.draw_ctx.evil_C);
wmWindowManager *wm = CTX_wm_manager(DST.draw_ctx.evil_C);
@@ -361,10 +345,13 @@ GPUMaterial *DRW_shader_create_from_world(
if (mat == NULL) {
mat = GPU_material_from_nodetree(
- scene, wo->nodetree, &wo->gpumaterial, engine_type, options);
+ scene, wo->nodetree, &wo->gpumaterial, engine_type, options,
+ vert, geom, frag_lib, defines);
}
- drw_deferred_shader_add(mat, vert, geom, frag_lib, defines);
+ if (GPU_material_status(mat) == GPU_MAT_QUEUED) {
+ drw_deferred_shader_add(mat);
+ }
return mat;
}
@@ -380,10 +367,13 @@ GPUMaterial *DRW_shader_create_from_material(
if (mat == NULL) {
mat = GPU_material_from_nodetree(
- scene, ma->nodetree, &ma->gpumaterial, engine_type, options);
+ scene, ma->nodetree, &ma->gpumaterial, engine_type, options,
+ vert, geom, frag_lib, defines);
}
- drw_deferred_shader_add(mat, vert, geom, frag_lib, defines);
+ if (GPU_material_status(mat) == GPU_MAT_QUEUED) {
+ drw_deferred_shader_add(mat);
+ }
return mat;
}
diff --git a/source/blender/draw/modes/object_mode.c b/source/blender/draw/modes/object_mode.c
index 7762a6c5dc8..09ed4b96756 100644
--- a/source/blender/draw/modes/object_mode.c
+++ b/source/blender/draw/modes/object_mode.c
@@ -2017,16 +2017,12 @@ static void OBJECT_cache_populate_particles(Object *ob,
continue;
}
if (!DRW_check_psys_visible_within_active_context(ob, psys)) {
- return;
+ continue;
}
ParticleSettings *part = psys->part;
int draw_as = (part->draw_as == PART_DRAW_REND) ? part->ren_as : part->draw_as;
- if (draw_as == PART_DRAW_PATH && !psys->pathcache && !psys->childcache) {
- draw_as = PART_DRAW_DOT;
- }
-
static float mat[4][4];
unit_m4(mat);
diff --git a/source/blender/draw/modes/overlay_mode.c b/source/blender/draw/modes/overlay_mode.c
index 131a9bc10db..97403b14ac5 100644
--- a/source/blender/draw/modes/overlay_mode.c
+++ b/source/blender/draw/modes/overlay_mode.c
@@ -52,8 +52,10 @@ typedef struct OVERLAY_Data {
} OVERLAY_Data;
typedef struct OVERLAY_PrivateData {
+ GPUShader *wire_sh; /* reference */
DRWShadingGroup *face_orientation_shgrp;
View3DOverlay overlay;
+ float wire_step_param[2];
} OVERLAY_PrivateData; /* Transient data */
/* *********** STATIC *********** */
@@ -62,6 +64,7 @@ static struct {
struct GPUShader *face_orientation_sh;
/* Wireframe shader */
struct GPUShader *face_wireframe_sh;
+ struct GPUShader *face_wireframe_pretty_sh;
} e_data = {NULL};
/* Shaders */
@@ -93,14 +96,22 @@ static void overlay_engine_init(void *vedata)
}
if (!e_data.face_wireframe_sh) {
- char *wireframe_geom = NULL;
- if (GPU_type_matches(GPU_DEVICE_INTEL, GPU_OS_ANY, GPU_DRIVER_ANY)) {
- wireframe_geom = datatoc_overlay_face_wireframe_geom_glsl;
- }
+ bool use_geom = GPU_type_matches(GPU_DEVICE_INTEL, GPU_OS_ANY, GPU_DRIVER_ANY);
+
e_data.face_wireframe_sh = DRW_shader_create(
datatoc_overlay_face_wireframe_vert_glsl,
- wireframe_geom,
- datatoc_overlay_face_wireframe_frag_glsl, NULL);
+ use_geom ? datatoc_overlay_face_wireframe_geom_glsl : NULL,
+ datatoc_overlay_face_wireframe_frag_glsl,
+ use_geom ? "#define USE_GEOM_SHADER\n"
+ : NULL);
+
+ e_data.face_wireframe_pretty_sh = DRW_shader_create(
+ datatoc_overlay_face_wireframe_vert_glsl,
+ use_geom ? datatoc_overlay_face_wireframe_geom_glsl : NULL,
+ datatoc_overlay_face_wireframe_frag_glsl,
+ use_geom ? "#define USE_GEOM_SHADER\n"
+ "#define LIGHT_EDGES\n"
+ : "#define LIGHT_EDGES\n");
}
}
@@ -130,6 +141,25 @@ static void overlay_cache_init(void *vedata)
if (stl->g_data->overlay.flag & V3D_OVERLAY_WIREFRAMES) {
DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_LESS_EQUAL | DRW_STATE_BLEND;
psl->face_wireframe_pass = DRW_pass_create("Face Wires", state);
+ /* Sticky uniforms (don't need to respecify each time since shader does not change). */
+ stl->g_data->wire_sh = (stl->g_data->overlay.wireframe_threshold == 1.0f) ? e_data.face_wireframe_sh
+ : e_data.face_wireframe_pretty_sh;
+ DRWShadingGroup *shgrp = DRW_shgroup_create(stl->g_data->wire_sh, psl->face_wireframe_pass);
+ DRW_shgroup_uniform_vec2(shgrp, "viewportSize", DRW_viewport_size_get(), 1);
+ DRW_shgroup_uniform_vec2(shgrp, "wireStepParam", stl->g_data->wire_step_param, 1);
+
+ /**
+ * The wireframe threshold ranges from 0.0 to 1.0
+ * When 1.0 we show all the edges, when 0.5 we show as many as 2.7.
+ *
+ * If we wanted 0.0 to match 2.7, factor would need to be 0.003f.
+ * The range controls the falloff effect. If range was 0.0f we would get a hard cut (as in 2.7).
+ * That said we are using a different algorithm so the results will always differ.
+ */
+ const float factor = 0.0045f;
+ const float range = 0.00125f;
+ stl->g_data->wire_step_param[1] = (1.0f - factor) + stl->g_data->overlay.wireframe_threshold * factor;
+ stl->g_data->wire_step_param[0] = stl->g_data->wire_step_param[1] + range;
}
}
@@ -162,14 +192,12 @@ static void overlay_cache_populate(void *vedata, Object *ob)
if ((ob->base_flag & BASE_SELECTED) != 0) {
rim_col = (ob == draw_ctx->obact) ? ts.colorActive : ts.colorSelect;
}
- /* TODO(fclem): Compare performance with a geom shader based approach. */
- DRWShadingGroup *shgrp = DRW_shgroup_create(e_data.face_wireframe_sh, psl->face_wireframe_pass);
+ DRWShadingGroup *shgrp = DRW_shgroup_create(stl->g_data->wire_sh, psl->face_wireframe_pass);
DRW_shgroup_uniform_texture(shgrp, "vertData", verts);
DRW_shgroup_uniform_texture(shgrp, "faceIds", faceids);
DRW_shgroup_uniform_vec3(shgrp, "wireColor", ts.colorWire, 1);
DRW_shgroup_uniform_vec3(shgrp, "rimColor", rim_col, 1);
- DRW_shgroup_uniform_vec2(shgrp, "viewportSize", DRW_viewport_size_get(), 1);
- DRW_shgroup_call_procedural_triangles_add(shgrp, tri_count, ob->obmat);
+ DRW_shgroup_call_object_procedural_triangles_culled_add(shgrp, tri_count, ob);
}
}
}
@@ -198,6 +226,7 @@ static void overlay_engine_free(void)
{
DRW_SHADER_FREE_SAFE(e_data.face_orientation_sh);
DRW_SHADER_FREE_SAFE(e_data.face_wireframe_sh);
+ DRW_SHADER_FREE_SAFE(e_data.face_wireframe_pretty_sh);
}
static const DrawEngineDataSize overlay_data_size = DRW_VIEWPORT_DATA_SIZE(OVERLAY_Data);
diff --git a/source/blender/draw/modes/particle_mode.c b/source/blender/draw/modes/particle_mode.c
index dacd4b72834..19c3ddd4b50 100644
--- a/source/blender/draw/modes/particle_mode.c
+++ b/source/blender/draw/modes/particle_mode.c
@@ -183,6 +183,12 @@ static void particle_cache_populate(void *vedata, Object *object)
Object *object_orig = DEG_get_original_object(object);
PTCacheEdit *edit = PE_create_current(
draw_ctx->depsgraph, scene_orig, object_orig);
+ if (edit == NULL) {
+ /* Happens when trying to edit particles in EMITTER mode without
+ * having them cached.
+ */
+ return;
+ }
/* NOTE: We need to pass evaluated particle system, which we need
* to find first.
*/
diff --git a/source/blender/draw/modes/pose_mode.c b/source/blender/draw/modes/pose_mode.c
index 586fb590ebf..ad9567cd9c0 100644
--- a/source/blender/draw/modes/pose_mode.c
+++ b/source/blender/draw/modes/pose_mode.c
@@ -72,13 +72,15 @@ typedef struct POSE_Data {
typedef struct POSE_PrivateData {
DRWShadingGroup *bone_selection_shgrp;
+ DRWShadingGroup *bone_selection_invert_shgrp;
+ float blend_color[4];
+ float blend_color_invert[4];
} POSE_PrivateData; /* Transient data */
static struct {
struct GPUShader *bone_selection_sh;
} e_data = {NULL};
-static float blend_color[4] = {0.0, 0.0, 0.0, 0.5};
/* *********** FUNCTIONS *********** */
static bool POSE_is_bone_selection_overlay_active(void)
@@ -105,11 +107,14 @@ static void POSE_cache_init(void *vedata)
{
POSE_PassList *psl = ((POSE_Data *)vedata)->psl;
POSE_StorageList *stl = ((POSE_Data *)vedata)->stl;
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ View3D *v3d = draw_ctx->v3d;
if (!stl->g_data) {
/* Alloc transient pointers */
stl->g_data = MEM_mallocN(sizeof(*stl->g_data), __func__);
}
+ POSE_PrivateData *ppd = stl->g_data;
{
/* Solid bones */
@@ -150,13 +155,18 @@ static void POSE_cache_init(void *vedata)
{
if (POSE_is_bone_selection_overlay_active()) {
+ copy_v4_fl4(ppd->blend_color, 0.0f, 0.0f, 0.0f, v3d->overlay.bone_selection_alpha);
+ copy_v4_fl4(ppd->blend_color_invert, 0.0f, 0.0f, 0.0f, pow(v3d->overlay.bone_selection_alpha, 4));
DRWShadingGroup *grp;
psl->bone_selection = DRW_pass_create(
"Bone Selection",
DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_EQUAL | DRW_STATE_BLEND);
grp = DRW_shgroup_create(e_data.bone_selection_sh, psl->bone_selection);
- DRW_shgroup_uniform_vec4(grp, "color", blend_color, 1);
+ DRW_shgroup_uniform_vec4(grp, "color", ppd->blend_color, 1);
stl->g_data->bone_selection_shgrp = grp;
+ grp = DRW_shgroup_create(e_data.bone_selection_sh, psl->bone_selection);
+ DRW_shgroup_uniform_vec4(grp, "color", ppd->blend_color_invert, 1);
+ stl->g_data->bone_selection_invert_shgrp = grp;
}
}
}
@@ -206,12 +216,16 @@ static void POSE_cache_populate(void *vedata, Object *ob)
}
else if (ob->type == OB_MESH &&
!DRW_state_is_select() &&
- POSE_is_bone_selection_overlay_active() &&
- POSE_is_driven_by_active_armature(ob))
+ POSE_is_bone_selection_overlay_active())
{
struct Gwn_Batch *geom = DRW_cache_object_surface_get(ob);
if (geom) {
- DRW_shgroup_call_object_add(stl->g_data->bone_selection_shgrp, geom, ob);
+ if (POSE_is_driven_by_active_armature(ob)) {
+ DRW_shgroup_call_object_add(stl->g_data->bone_selection_shgrp, geom, ob);
+ }
+ else {
+ DRW_shgroup_call_object_add(stl->g_data->bone_selection_invert_shgrp, geom, ob);
+ }
}
}
}
diff --git a/source/blender/draw/modes/shaders/armature_shape_outline_geom.glsl b/source/blender/draw/modes/shaders/armature_shape_outline_geom.glsl
index 11924b19cf8..4d6f3e94693 100644
--- a/source/blender/draw/modes/shaders/armature_shape_outline_geom.glsl
+++ b/source/blender/draw/modes/shaders/armature_shape_outline_geom.glsl
@@ -69,7 +69,7 @@ void main(void)
return;
/* Don't outline if concave edge. */
- if (dot(n0, v13) > 0.0)
+ if (dot(n0, v13) > 0.0001)
return;
vec2 thick = vColSize[0].w * (lineThickness / viewportSize);
diff --git a/source/blender/draw/modes/shaders/overlay_face_wireframe_frag.glsl b/source/blender/draw/modes/shaders/overlay_face_wireframe_frag.glsl
index a714de9579a..00ababc624d 100644
--- a/source/blender/draw/modes/shaders/overlay_face_wireframe_frag.glsl
+++ b/source/blender/draw/modes/shaders/overlay_face_wireframe_frag.glsl
@@ -6,9 +6,14 @@ flat in vec3 ssVec1;
flat in vec3 ssVec2;
in float facing;
+#ifdef LIGHT_EDGES
+in float edgeSharpness;
+#endif
+
out vec4 fragColor;
float min_v3(vec3 v) { return min(v.x, min(v.y, v.z)); }
+float max_v3(vec3 v) { return max(v.x, max(v.y, v.z)); }
/* In pixels */
const float wire_size = 0.0; /* Expands the core of the wire (part that is 100% wire color) */
@@ -27,10 +32,22 @@ void main()
dot(ss_pos, ssVec2)
);
- float fac = smoothstep(wire_size, wire_size + wire_smooth, min_v3(abs(dist_to_edge)));
+#ifdef LIGHT_EDGES
+ vec3 fac = abs(dist_to_edge);
+#else
+ float fac = min_v3(abs(dist_to_edge));
+#endif
+
+ fac = smoothstep(wire_size + wire_smooth, wire_size, fac);
+
float facing_clamped = clamp((gl_FrontFacing) ? facing : -facing, 0.0, 1.0);
vec3 final_front_col = mix(rimColor, wireColor, 0.05);
fragColor = mix(vec4(rimColor, rim_alpha), vec4(final_front_col, front_alpha), facing_clamped);
- fragColor.a *= (1.0 - fac);
+
+#ifdef LIGHT_EDGES
+ fragColor.a *= max_v3(fac * edgeSharpness);
+#else
+ fragColor.a *= fac;
+#endif
}
diff --git a/source/blender/draw/modes/shaders/overlay_face_wireframe_geom.glsl b/source/blender/draw/modes/shaders/overlay_face_wireframe_geom.glsl
index 1cea418419e..6e833a4e16b 100644
--- a/source/blender/draw/modes/shaders/overlay_face_wireframe_geom.glsl
+++ b/source/blender/draw/modes/shaders/overlay_face_wireframe_geom.glsl
@@ -1,7 +1,12 @@
+/* This shader is only used for intel GPU where the Geom shader is faster
+ * than doing everything thrice in the vertex shader. */
+
layout(triangles) in;
layout(triangle_strip, max_vertices = 3) out;
+uniform vec2 wireStepParam;
+
in vec2 ssPos[];
in float facingOut[];
@@ -10,8 +15,17 @@ flat out vec3 ssVec1;
flat out vec3 ssVec2;
out float facing;
+#ifdef LIGHT_EDGES
+in vec3 obPos[];
+in vec3 vNor[];
+in float forceEdge[];
+
+out float edgeSharpness;
+#endif
+
#define NO_EDGE vec3(10000.0);
+/* TODO(fclem) remove code duplication. */
vec3 compute_vec(vec2 v0, vec2 v1)
{
vec2 v = normalize(v1 - v0);
@@ -19,6 +33,12 @@ vec3 compute_vec(vec2 v0, vec2 v1)
return vec3(v, -dot(v, v0));
}
+float get_edge_sharpness(vec3 fnor, vec3 vnor)
+{
+ float sharpness = abs(dot(fnor, vnor));
+ return smoothstep(wireStepParam.x, wireStepParam.y, sharpness);
+}
+
void main(void)
{
vec3 facings = vec3(facingOut[0], facingOut[1], facingOut[2]);
@@ -29,12 +49,28 @@ void main(void)
ssVec1 = do_edge.y ? compute_vec(ssPos[1], ssPos[2]) : NO_EDGE;
ssVec2 = do_edge.z ? compute_vec(ssPos[2], ssPos[0]) : NO_EDGE;
+#ifdef LIGHT_EDGES
+ vec3 fnor = normalize(cross(obPos[1] - obPos[0], obPos[2] - obPos[0]));
+
+ edgeSharpness = get_edge_sharpness(fnor, vNor[0]);
+ edgeSharpness = (forceEdge[0] == 1.0 || forceEdge[2] == 1.0) ? 1.0 : edgeSharpness;
+#endif
gl_Position = gl_in[0].gl_Position;
facing = facings.x;
EmitVertex();
+
+#ifdef LIGHT_EDGES
+ edgeSharpness = get_edge_sharpness(fnor, vNor[1]);
+ edgeSharpness = (forceEdge[1] == 1.0 || forceEdge[0] == 1.0) ? 1.0 : edgeSharpness;
+#endif
gl_Position = gl_in[1].gl_Position;
facing = facings.y;
EmitVertex();
+
+#ifdef LIGHT_EDGES
+ edgeSharpness = get_edge_sharpness(fnor, vNor[2]);
+ edgeSharpness = (forceEdge[2] == 1.0 || forceEdge[1] == 1.0) ? 1.0 : edgeSharpness;
+#endif
gl_Position = gl_in[2].gl_Position;
facing = facings.z;
EmitVertex();
diff --git a/source/blender/draw/modes/shaders/overlay_face_wireframe_vert.glsl b/source/blender/draw/modes/shaders/overlay_face_wireframe_vert.glsl
index 2cd888e7537..616cd5379e9 100644
--- a/source/blender/draw/modes/shaders/overlay_face_wireframe_vert.glsl
+++ b/source/blender/draw/modes/shaders/overlay_face_wireframe_vert.glsl
@@ -1,18 +1,15 @@
-#ifdef GPU_INTEL
-#define USE_GEOM_SHADER
-#endif
-
uniform mat4 ModelViewProjectionMatrix;
uniform mat4 ModelViewMatrix;
uniform mat4 ProjectionMatrix;
uniform mat3 NormalMatrix;
+uniform vec2 wireStepParam;
uniform vec2 viewportSize;
uniform float nearDist;
uniform samplerBuffer vertData;
-uniform isamplerBuffer faceIds;
+uniform usamplerBuffer faceIds;
#ifdef USE_GEOM_SHADER
out vec2 ssPos;
@@ -24,6 +21,16 @@ flat out vec3 ssVec2;
out float facing;
#endif
+#ifdef LIGHT_EDGES
+#ifdef USE_GEOM_SHADER
+out vec3 obPos;
+out vec3 vNor;
+out float forceEdge;
+#else
+out float edgeSharpness;
+#endif
+#endif
+
/* project to screen space */
vec2 proj(vec4 pos)
{
@@ -46,9 +53,9 @@ float short_to_unit_float(uint s)
return float(value) / float(0x7FFF);
}
-vec3 get_vertex_nor(int v_id)
+vec3 get_vertex_nor(uint id)
{
- v_id *= 5; /* See vertex format for explanation. */
+ int v_id = int(id) * 5; /* See vertex format for explanation. */
/* Fetch compressed normal as float and unpack them. */
vec2 data;
data.x = texelFetch(vertData, v_id + 3).r;
@@ -63,9 +70,9 @@ vec3 get_vertex_nor(int v_id)
return nor;
}
-vec3 get_vertex_pos(int v_id)
+vec3 get_vertex_pos(uint id)
{
- v_id *= 5; /* See vertex format for explanation. */
+ int v_id = int(id) * 5; /* See vertex format for explanation. */
vec3 pos;
pos.x = texelFetch(vertData, v_id).r;
pos.y = texelFetch(vertData, v_id + 1).r;
@@ -73,15 +80,22 @@ vec3 get_vertex_pos(int v_id)
return pos;
}
+float get_edge_sharpness(vec3 fnor, vec3 vnor)
+{
+ float sharpness = abs(dot(fnor, vnor));
+ return smoothstep(wireStepParam.x, wireStepParam.y, sharpness);
+}
+
#define NO_EDGE vec3(10000.0);
void main()
{
#ifdef USE_GEOM_SHADER
- int v_id = texelFetch(faceIds, gl_VertexID).r;
+ uint v_id = texelFetch(faceIds, gl_VertexID).r;
- bool do_edge = v_id < 0;
- v_id = abs(v_id) - 1;
+ bool do_edge = (v_id & (1u << 30u)) != 0u;
+ bool force_edge = (v_id & (1u << 31u)) != 0u;
+ v_id = (v_id << 2u) >> 2u;
vec3 pos = get_vertex_pos(v_id);
vec3 nor = get_vertex_nor(v_id);
@@ -91,18 +105,30 @@ void main()
gl_Position = ModelViewProjectionMatrix * vec4(pos, 1.0);
ssPos = proj(gl_Position);
-#else
+# ifdef LIGHT_EDGES
+ obPos = pos;
+ vNor = nor;
+ forceEdge = float(force_edge); /* meh, could try to also encode it in facingOut */
+# endif
+#else
int v_0 = (gl_VertexID / 3) * 3;
int v_n = gl_VertexID % 3;
+
/* Getting the same positions for each of the 3 verts. */
- ivec3 v_id;
+ uvec3 v_id;
v_id.x = texelFetch(faceIds, v_0).r;
v_id.y = texelFetch(faceIds, v_0 + 1).r;
v_id.z = texelFetch(faceIds, v_0 + 2).r;
- bvec3 do_edge = lessThan(v_id, ivec3(0));
- v_id = abs(v_id) - 1;
+ bvec3 do_edge, force_edge;
+ do_edge.x = (v_id.x & (1u << 30u)) != 0u;
+ do_edge.y = (v_id.y & (1u << 30u)) != 0u;
+ do_edge.z = (v_id.z & (1u << 30u)) != 0u;
+ force_edge.x = (v_id.x & (1u << 31u)) != 0u;
+ force_edge.y = (v_id.y & (1u << 31u)) != 0u;
+ force_edge.z = (v_id.z & (1u << 31u)) != 0u;
+ v_id = (v_id << 2u) >> 2u;
vec3 pos[3];
pos[0] = get_vertex_pos(v_id.x);
@@ -128,5 +154,22 @@ void main()
vec3 nor = get_vertex_nor(v_id[v_n]);
facing = normalize(NormalMatrix * nor).z;
+
+# ifdef LIGHT_EDGES
+ vec3 fnor = normalize(cross(pos[1] - pos[0], pos[2] - pos[0]));
+ edgeSharpness = get_edge_sharpness(fnor, nor);
+
+ /* Fix disapearing edges. */
+ if (v_n == 0) {
+ force_edge.xy = force_edge.xz;
+ }
+ else if (v_n == 2) {
+ force_edge.xy = force_edge.yz;
+ }
+ if (any(force_edge.xy)) {
+ edgeSharpness = 1.0;
+ }
+# endif
+
#endif
}
diff --git a/source/blender/editors/animation/anim_channels_defines.c b/source/blender/editors/animation/anim_channels_defines.c
index 5d5d8f10a88..e4213a8d907 100644
--- a/source/blender/editors/animation/anim_channels_defines.c
+++ b/source/blender/editors/animation/anim_channels_defines.c
@@ -65,6 +65,7 @@
#include "BKE_animsys.h"
#include "BKE_curve.h"
#include "BKE_key.h"
+#include "BKE_main.h"
#include "BKE_nla.h"
#include "BKE_context.h"
@@ -4144,6 +4145,7 @@ static void achannel_setting_slider_cb(bContext *C, void *id_poin, void *fcu_poi
/* callback for shapekey widget sliders - insert keyframes */
static void achannel_setting_slider_shapekey_cb(bContext *C, void *key_poin, void *kb_poin)
{
+ Main *bmain = CTX_data_main(C);
Key *key = (Key *)key_poin;
KeyBlock *kb = (KeyBlock *)kb_poin;
char *rna_path = BKE_keyblock_curval_rnapath_get(key, kb);
@@ -4171,7 +4173,7 @@ static void achannel_setting_slider_shapekey_cb(bContext *C, void *key_poin, voi
if (RNA_path_resolve_property(&id_ptr, rna_path, &ptr, &prop)) {
/* find or create new F-Curve */
// XXX is the group name for this ok?
- bAction *act = verify_adt_action((ID *)key, 1);
+ bAction *act = verify_adt_action(bmain, (ID *)key, 1);
FCurve *fcu = verify_fcurve(act, NULL, &ptr, rna_path, 0, 1);
/* set the special 'replace' flag if on a keyframe */
diff --git a/source/blender/editors/animation/anim_deps.c b/source/blender/editors/animation/anim_deps.c
index cfdbe87c8a1..adb5a10c19d 100644
--- a/source/blender/editors/animation/anim_deps.c
+++ b/source/blender/editors/animation/anim_deps.c
@@ -46,10 +46,10 @@
#include "BKE_animsys.h"
#include "BKE_action.h"
+#include "BKE_context.h"
#include "BKE_fcurve.h"
#include "BKE_gpencil.h"
-#include "BKE_context.h"
-#include "BKE_global.h"
+#include "BKE_main.h"
#include "BKE_node.h"
#include "BKE_sequencer.h"
@@ -64,7 +64,7 @@
/* tags the given anim list element for refreshes (if applicable)
* due to Animation Editor editing
*/
-void ANIM_list_elem_update(Scene *scene, bAnimListElem *ale)
+void ANIM_list_elem_update(Main *bmain, Scene *scene, bAnimListElem *ale)
{
ID *id;
FCurve *fcu;
@@ -97,7 +97,7 @@ void ANIM_list_elem_update(Scene *scene, bAnimListElem *ale)
RNA_id_pointer_create(id, &id_ptr);
if (RNA_path_resolve_property(&id_ptr, fcu->rna_path, &ptr, &prop))
- RNA_property_update_main(G.main, scene, &ptr, prop);
+ RNA_property_update_main(bmain, scene, &ptr, prop);
}
else {
/* in other case we do standard depsgraph update, ideally
@@ -406,7 +406,7 @@ void ANIM_animdata_update(bAnimContext *ac, ListBase *anim_data)
if (ale->update & ANIM_UPDATE_DEPS) {
ale->update &= ~ANIM_UPDATE_DEPS;
- ANIM_list_elem_update(ac->scene, ale);
+ ANIM_list_elem_update(ac->bmain, ac->scene, ale);
}
}
else if (ale->datatype == ALE_FCURVE) {
@@ -426,13 +426,13 @@ void ANIM_animdata_update(bAnimContext *ac, ListBase *anim_data)
if (ale->update & ANIM_UPDATE_DEPS) {
ale->update &= ~ANIM_UPDATE_DEPS;
- ANIM_list_elem_update(ac->scene, ale);
+ ANIM_list_elem_update(ac->bmain, ac->scene, ale);
}
}
else if (ale->datatype == ALE_NLASTRIP) {
if (ale->update & ANIM_UPDATE_DEPS) {
ale->update &= ~ANIM_UPDATE_DEPS;
- ANIM_list_elem_update(ac->scene, ale);
+ ANIM_list_elem_update(ac->bmain, ac->scene, ale);
}
}
diff --git a/source/blender/editors/animation/anim_filter.c b/source/blender/editors/animation/anim_filter.c
index 6f748725790..8892fed025a 100644
--- a/source/blender/editors/animation/anim_filter.c
+++ b/source/blender/editors/animation/anim_filter.c
@@ -378,6 +378,7 @@ bool ANIM_animdata_context_getdata(bAnimContext *ac)
*/
bool ANIM_animdata_get_context(const bContext *C, bAnimContext *ac)
{
+ Main *bmain = CTX_data_main(C);
ScrArea *sa = CTX_wm_area(C);
ARegion *ar = CTX_wm_region(C);
SpaceLink *sl = CTX_wm_space_data(C);
@@ -388,6 +389,7 @@ bool ANIM_animdata_get_context(const bContext *C, bAnimContext *ac)
memset(ac, 0, sizeof(bAnimContext));
/* get useful default context settings from context */
+ ac->bmain = bmain;
ac->scene = scene;
if (scene) {
ac->markers = ED_context_get_markers(C);
@@ -1742,7 +1744,7 @@ static size_t animdata_filter_gpencil(bAnimContext *ac, ListBase *anim_data, voi
bGPdata *gpd;
/* Grab all Grease Pencil datablocks directly from main, but only those that seem to be useful somewhere */
- for (gpd = G.main->gpencil.first; gpd; gpd = gpd->id.next) {
+ for (gpd = ac->bmain->gpencil.first; gpd; gpd = gpd->id.next) {
/* only show if gpd is used by something... */
if (ID_REAL_USERS(gpd) < 1)
continue;
@@ -1858,14 +1860,14 @@ static size_t animdata_filter_mask_data(ListBase *anim_data, Mask *mask, const i
}
/* Grab all mask data */
-static size_t animdata_filter_mask(ListBase *anim_data, void *UNUSED(data), int filter_mode)
+static size_t animdata_filter_mask(Main *bmain, ListBase *anim_data, void *UNUSED(data), int filter_mode)
{
Mask *mask;
size_t items = 0;
/* for now, grab mask datablocks directly from main */
// XXX: this is not good...
- for (mask = G.main->mask.first; mask; mask = mask->id.next) {
+ for (mask = bmain->mask.first; mask; mask = mask->id.next) {
ListBase tmp_data = {NULL, NULL};
size_t tmp_items = 0;
@@ -2820,7 +2822,7 @@ static size_t animdata_filter_dopesheet_movieclips(bAnimContext *ac, ListBase *a
{
size_t items = 0;
MovieClip *clip;
- for (clip = G.main->movieclip.first; clip != NULL; clip = clip->id.next) {
+ for (clip = ac->bmain->movieclip.first; clip != NULL; clip = clip->id.next) {
/* only show if gpd is used by something... */
if (ID_REAL_USERS(clip) < 1) {
continue;
@@ -2959,7 +2961,7 @@ static size_t animdata_filter_dopesheet(bAnimContext *ac, ListBase *anim_data, b
}
/* Cache files level animations (frame duration and such). */
- CacheFile *cache_file = G.main->cachefiles.first;
+ CacheFile *cache_file = ac->bmain->cachefiles.first;
for (; cache_file; cache_file = cache_file->id.next) {
items += animdata_filter_ds_cachefile(ac, anim_data, ads, cache_file, filter_mode);
}
@@ -3223,7 +3225,7 @@ size_t ANIM_animdata_filter(bAnimContext *ac, ListBase *anim_data, eAnimFilter_F
case ANIMCONT_MASK:
{
if (animdata_filter_dopesheet_summary(ac, anim_data, filter_mode, &items))
- items = animdata_filter_mask(anim_data, data, filter_mode);
+ items = animdata_filter_mask(ac->bmain, anim_data, data, filter_mode);
break;
}
diff --git a/source/blender/editors/animation/keyframes_general.c b/source/blender/editors/animation/keyframes_general.c
index f8af504f1ed..a6ed6643257 100644
--- a/source/blender/editors/animation/keyframes_general.c
+++ b/source/blender/editors/animation/keyframes_general.c
@@ -48,6 +48,7 @@
#include "BKE_fcurve.h"
#include "BKE_report.h"
#include "BKE_library.h"
+#include "BKE_main.h"
#include "BKE_global.h"
#include "BKE_deform.h"
@@ -729,7 +730,8 @@ static tAnimCopybufItem *pastebuf_match_path_full(FCurve *fcu, const short from_
}
/* medium match strictness: path match only (i.e. ignore ID) */
-static tAnimCopybufItem *pastebuf_match_path_property(FCurve *fcu, const short from_single, const short UNUSED(to_simple))
+static tAnimCopybufItem *pastebuf_match_path_property(
+ Main *bmain, FCurve *fcu, const short from_single, const short UNUSED(to_simple))
{
tAnimCopybufItem *aci;
@@ -742,7 +744,7 @@ static tAnimCopybufItem *pastebuf_match_path_property(FCurve *fcu, const short f
* resolve, or a bone could be renamed after copying for eg. but in normal copy & paste
* this should work out ok.
*/
- if (BLI_findindex(which_libbase(G.main, aci->id_type), aci->id) == -1) {
+ if (BLI_findindex(which_libbase(bmain, aci->id_type), aci->id) == -1) {
/* pedantic but the ID could have been removed, and beats crashing! */
printf("paste_animedit_keys: error ID has been removed!\n");
}
@@ -996,7 +998,7 @@ short paste_animedit_keys(bAnimContext *ac, ListBase *anim_data,
case 1:
/* less strict, just compare property names */
- aci = pastebuf_match_path_property(fcu, from_single, to_simple);
+ aci = pastebuf_match_path_property(ac->bmain, fcu, from_single, to_simple);
break;
case 2:
diff --git a/source/blender/editors/animation/keyframing.c b/source/blender/editors/animation/keyframing.c
index 25b3b4f58fa..1913eb944d9 100644
--- a/source/blender/editors/animation/keyframing.c
+++ b/source/blender/editors/animation/keyframing.c
@@ -53,17 +53,18 @@
#include "DNA_object_types.h"
#include "DNA_rigidbody_types.h"
-#include "BKE_animsys.h"
#include "BKE_action.h"
+#include "BKE_animsys.h"
#include "BKE_armature.h"
+#include "BKE_context.h"
#include "BKE_fcurve.h"
-#include "BKE_idcode.h"
-#include "BKE_nla.h"
#include "BKE_global.h"
-#include "BKE_context.h"
-#include "BKE_report.h"
+#include "BKE_idcode.h"
#include "BKE_key.h"
+#include "BKE_main.h"
#include "BKE_material.h"
+#include "BKE_nla.h"
+#include "BKE_report.h"
#include "DEG_depsgraph.h"
#include "DEG_depsgraph_build.h"
@@ -126,7 +127,7 @@ short ANIM_get_keyframing_flags(Scene *scene, short incl_mode)
/* Get (or add relevant data to be able to do so) the Active Action for the given
* Animation Data block, given an ID block where the Animation Data should reside.
*/
-bAction *verify_adt_action(ID *id, short add)
+bAction *verify_adt_action(Main *bmain, ID *id, short add)
{
AnimData *adt;
@@ -148,7 +149,7 @@ bAction *verify_adt_action(ID *id, short add)
BLI_snprintf(actname, sizeof(actname), "%sAction", id->name + 2);
/* create action */
- adt->action = BKE_action_add(G.main, actname);
+ adt->action = BKE_action_add(bmain, actname);
/* set ID-type from ID-block that this is going to be assigned to
* so that users can't accidentally break actions by assigning them
@@ -158,7 +159,7 @@ bAction *verify_adt_action(ID *id, short add)
/* tag depsgraph to be rebuilt to include time dependency */
/* XXX: we probably should have bmain passed down, but that involves altering too many API's */
- DEG_relations_tag_update(G.main);
+ DEG_relations_tag_update(bmain);
}
DEG_id_tag_update(&adt->action->id, DEG_TAG_COPY_ON_WRITE);
@@ -616,12 +617,14 @@ static short new_key_needed(FCurve *fcu, float cFrame, float nValue)
/* ------------------ RNA Data-Access Functions ------------------ */
/* Try to read value using RNA-properties obtained already */
-static float setting_get_rna_value(Depsgraph *depsgraph, PointerRNA *ptr, PropertyRNA *prop, int index)
+static float setting_get_rna_value(Depsgraph *depsgraph, PointerRNA *ptr, PropertyRNA *prop, int index, const bool get_evaluated)
{
- PointerRNA ptr_eval;
+ PointerRNA ptr_eval = *ptr;
float value = 0.0f;
- DEG_get_evaluated_rna_pointer(depsgraph, ptr, &ptr_eval);
+ if (get_evaluated) {
+ DEG_get_evaluated_rna_pointer(depsgraph, ptr, &ptr_eval);
+ }
switch (RNA_property_type(prop)) {
case PROP_BOOLEAN:
@@ -847,7 +850,7 @@ static float visualkey_get_value(Depsgraph *depsgraph, PointerRNA *ptr, Property
}
}
else {
- return setting_get_rna_value(depsgraph, ptr, prop, array_index);
+ return setting_get_rna_value(depsgraph, ptr, prop, array_index, true);
}
/* Rot/Scale code are common! */
@@ -885,7 +888,7 @@ static float visualkey_get_value(Depsgraph *depsgraph, PointerRNA *ptr, Property
}
/* as the function hasn't returned yet, read value from system in the default way */
- return setting_get_rna_value(depsgraph, ptr, prop, array_index);
+ return setting_get_rna_value(depsgraph, ptr, prop, array_index, true);
}
/* ------------------------- Insert Key API ------------------------- */
@@ -970,7 +973,7 @@ bool insert_keyframe_direct(Depsgraph *depsgraph, ReportList *reports, PointerRN
}
else {
/* read value from system */
- curval = setting_get_rna_value(depsgraph, &ptr, prop, fcu->array_index);
+ curval = setting_get_rna_value(depsgraph, &ptr, prop, fcu->array_index, false);
}
/* only insert keyframes where they are needed */
@@ -1019,7 +1022,9 @@ bool insert_keyframe_direct(Depsgraph *depsgraph, ReportList *reports, PointerRN
*
* index of -1 keys all array indices
*/
-short insert_keyframe(Depsgraph *depsgraph, ReportList *reports, ID *id, bAction *act, const char group[], const char rna_path[], int array_index, float cfra, eBezTriple_KeyframeType keytype, eInsertKeyFlags flag)
+short insert_keyframe(
+ Main *bmain, Depsgraph *depsgraph, ReportList *reports, ID *id, bAction *act,
+ const char group[], const char rna_path[], int array_index, float cfra, eBezTriple_KeyframeType keytype, eInsertKeyFlags flag)
{
PointerRNA id_ptr, ptr;
PropertyRNA *prop = NULL;
@@ -1045,7 +1050,7 @@ short insert_keyframe(Depsgraph *depsgraph, ReportList *reports, ID *id, bAction
/* if no action is provided, keyframe to the default one attached to this ID-block */
if (act == NULL) {
/* get action to add F-Curve+keyframe to */
- act = verify_adt_action(id, 1);
+ act = verify_adt_action(bmain, id, 1);
if (act == NULL) {
BKE_reportf(reports, RPT_ERROR,
@@ -1101,6 +1106,10 @@ short insert_keyframe(Depsgraph *depsgraph, ReportList *reports, ID *id, bAction
}
}
+ if (ret) {
+ DEG_id_tag_update(&adt->action->id, DEG_TAG_COPY_ON_WRITE);
+ }
+
return ret;
}
@@ -1771,6 +1780,7 @@ void ANIM_OT_keyframe_delete_v3d(wmOperatorType *ot)
static int insert_key_button_exec(bContext *C, wmOperator *op)
{
Depsgraph *depsgraph = CTX_data_depsgraph(C);
+ Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
ToolSettings *ts = scene->toolsettings;
PointerRNA ptr = {{NULL}};
@@ -1854,7 +1864,7 @@ static int insert_key_button_exec(bContext *C, wmOperator *op)
index = -1;
}
- success = insert_keyframe(depsgraph, op->reports, ptr.id.data, NULL, group, path, index, cfra, ts->keyframe_type, flag);
+ success = insert_keyframe(bmain, depsgraph, op->reports, ptr.id.data, NULL, group, path, index, cfra, ts->keyframe_type, flag);
MEM_freeN(path);
}
diff --git a/source/blender/editors/animation/keyingsets.c b/source/blender/editors/animation/keyingsets.c
index c443c66d0f5..5bf23a53819 100644
--- a/source/blender/editors/animation/keyingsets.c
+++ b/source/blender/editors/animation/keyingsets.c
@@ -959,6 +959,7 @@ static short keyingset_apply_keying_flags(const short base_flags, const short ov
int ANIM_apply_keyingset(bContext *C, ListBase *dsources, bAction *act, KeyingSet *ks, short mode, float cfra)
{
Depsgraph *depsgraph = CTX_data_depsgraph(C);
+ Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
ReportList *reports = CTX_wm_reports(C);
KS_Path *ksp;
@@ -1039,7 +1040,7 @@ int ANIM_apply_keyingset(bContext *C, ListBase *dsources, bAction *act, KeyingSe
for (; i < arraylen; i++) {
/* action to take depends on mode */
if (mode == MODIFYKEY_MODE_INSERT)
- success += insert_keyframe(depsgraph, reports, ksp->id, act, groupname, ksp->rna_path, i, cfra, keytype, kflag2);
+ success += insert_keyframe(bmain, depsgraph, reports, ksp->id, act, groupname, ksp->rna_path, i, cfra, keytype, kflag2);
else if (mode == MODIFYKEY_MODE_DELETE)
success += delete_keyframe(reports, ksp->id, act, groupname, ksp->rna_path, i, cfra, kflag2);
}
@@ -1051,7 +1052,7 @@ int ANIM_apply_keyingset(bContext *C, ListBase *dsources, bAction *act, KeyingSe
Object *ob = (Object *)ksp->id;
// XXX: only object transforms?
- DEG_id_tag_update(&ob->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME);
+ DEG_id_tag_update(&ob->id, OB_RECALC_OB | OB_RECALC_DATA);
break;
}
default:
diff --git a/source/blender/editors/armature/armature_edit.c b/source/blender/editors/armature/armature_edit.c
index 9fcf6ad4826..ccc1eefd9dc 100644
--- a/source/blender/editors/armature/armature_edit.c
+++ b/source/blender/editors/armature/armature_edit.c
@@ -50,6 +50,7 @@
#include "BKE_context.h"
#include "BKE_layer.h"
#include "BKE_global.h"
+#include "BKE_main.h"
#include "BKE_report.h"
#include "BKE_object.h"
@@ -68,7 +69,7 @@
/* ************************** Object Tools Exports ******************************* */
/* NOTE: these functions are exported to the Object module to be called from the tools there */
-void ED_armature_transform_apply(Object *ob, float mat[4][4], const bool do_props)
+void ED_armature_transform_apply(Main *bmain, Object *ob, float mat[4][4], const bool do_props)
{
bArmature *arm = ob->data;
@@ -79,7 +80,7 @@ void ED_armature_transform_apply(Object *ob, float mat[4][4], const bool do_prop
ED_armature_transform_bones(arm, mat, do_props);
/* Turn the list into an armature */
- ED_armature_from_edit(arm);
+ ED_armature_from_edit(bmain, arm);
ED_armature_edit_free(arm);
}
@@ -120,7 +121,7 @@ void ED_armature_transform_bones(struct bArmature *arm, float mat[4][4], const b
}
}
-void ED_armature_transform(struct bArmature *arm, float mat[4][4], const bool do_props)
+void ED_armature_transform(Main *bmain, bArmature *arm, float mat[4][4], const bool do_props)
{
if (arm->edbo) {
ED_armature_transform_bones(arm, mat, do_props);
@@ -133,14 +134,14 @@ void ED_armature_transform(struct bArmature *arm, float mat[4][4], const bool do
ED_armature_transform_bones(arm, mat, do_props);
/* Go back to object mode*/
- ED_armature_from_edit(arm);
+ ED_armature_from_edit(bmain, arm);
ED_armature_edit_free(arm);
}
}
/* exported for use in editors/object/ */
/* 0 == do center, 1 == center new, 2 == center cursor */
-void ED_armature_origin_set(Object *ob, float cursor[3], int centermode, int around)
+void ED_armature_origin_set(Main *bmain, Object *ob, float cursor[3], int centermode, int around)
{
const bool is_editmode = BKE_object_is_in_editmode(ob);
EditBone *ebone;
@@ -190,7 +191,7 @@ void ED_armature_origin_set(Object *ob, float cursor[3], int centermode, int aro
/* Turn the list into an armature */
if (is_editmode == false) {
- ED_armature_from_edit(arm);
+ ED_armature_from_edit(bmain, arm);
ED_armature_edit_free(arm);
}
diff --git a/source/blender/editors/armature/armature_naming.c b/source/blender/editors/armature/armature_naming.c
index 1a5e9e38099..a73e64af0ee 100644
--- a/source/blender/editors/armature/armature_naming.c
+++ b/source/blender/editors/armature/armature_naming.c
@@ -137,7 +137,7 @@ static void constraint_bone_name_fix(Object *ob, ListBase *conlist, const char *
/* called by UI for renaming a bone */
/* warning: make sure the original bone was not renamed yet! */
/* seems messy, but thats what you get with not using pointers but channel names :) */
-void ED_armature_bone_rename(bArmature *arm, const char *oldnamep, const char *newnamep)
+void ED_armature_bone_rename(Main *bmain, bArmature *arm, const char *oldnamep, const char *newnamep)
{
Object *ob;
char newname[MAXBONENAME];
@@ -176,7 +176,7 @@ void ED_armature_bone_rename(bArmature *arm, const char *oldnamep, const char *n
}
/* do entire dbase - objects */
- for (ob = G.main->object.first; ob; ob = ob->id.next) {
+ for (ob = bmain->object.first; ob; ob = ob->id.next) {
ModifierData *md;
/* we have the object using the armature */
@@ -206,7 +206,7 @@ void ED_armature_bone_rename(bArmature *arm, const char *oldnamep, const char *n
}
/* Update any object constraints to use the new bone name */
- for (cob = G.main->object.first; cob; cob = cob->id.next) {
+ for (cob = bmain->object.first; cob; cob = cob->id.next) {
if (cob->constraints.first)
constraint_bone_name_fix(ob, &cob->constraints, oldname, newname);
if (cob->pose) {
@@ -279,7 +279,7 @@ void ED_armature_bone_rename(bArmature *arm, const char *oldnamep, const char *n
/* correct view locking */
{
bScreen *screen;
- for (screen = G.main->screen.first; screen; screen = screen->id.next) {
+ for (screen = bmain->screen.first; screen; screen = screen->id.next) {
ScrArea *sa;
/* add regions */
for (sa = screen->areabase.first; sa; sa = sa->next) {
@@ -316,7 +316,7 @@ typedef struct BoneFlipNameData {
* \param bones_names: List of BoneConflict elems.
* \param do_strip_numbers: if set, try to get rid of dot-numbers at end of bone names.
*/
-void ED_armature_bones_flip_names(bArmature *arm, ListBase *bones_names, const bool do_strip_numbers)
+void ED_armature_bones_flip_names(Main *bmain, bArmature *arm, ListBase *bones_names, const bool do_strip_numbers)
{
ListBase bones_names_conflicts = {NULL};
BoneFlipNameData *bfn;
@@ -332,7 +332,7 @@ void ED_armature_bones_flip_names(bArmature *arm, ListBase *bones_names, const b
* Bone.R, Bone.R.001, Bone.R.002, etc. */
BLI_string_flip_side_name(name_flip, name, do_strip_numbers, sizeof(name_flip));
- ED_armature_bone_rename(arm, name, name_flip);
+ ED_armature_bone_rename(bmain, arm, name, name_flip);
if (!STREQ(name, name_flip)) {
bfn = alloca(sizeof(BoneFlipNameData));
@@ -346,7 +346,7 @@ void ED_armature_bones_flip_names(bArmature *arm, ListBase *bones_names, const b
* Note that if the other bone was not selected, its name was not flipped, so conflict remains and that second
* rename simply generates a new numbered alternative name. */
for (bfn = bones_names_conflicts.first; bfn; bfn = bfn->next) {
- ED_armature_bone_rename(arm, bfn->name, bfn->name_flip);
+ ED_armature_bone_rename(bmain, arm, bfn->name, bfn->name_flip);
}
}
@@ -355,6 +355,7 @@ void ED_armature_bones_flip_names(bArmature *arm, ListBase *bones_names, const b
static int armature_flip_names_exec(bContext *C, wmOperator *op)
{
+ Main *bmain = CTX_data_main(C);
Object *ob = CTX_data_edit_object(C);
bArmature *arm;
@@ -374,7 +375,7 @@ static int armature_flip_names_exec(bContext *C, wmOperator *op)
}
CTX_DATA_END;
- ED_armature_bones_flip_names(arm, &bones_names, do_strip_numbers);
+ ED_armature_bones_flip_names(bmain, arm, &bones_names, do_strip_numbers);
BLI_freelistN(&bones_names);
@@ -413,6 +414,7 @@ void ARMATURE_OT_flip_names(wmOperatorType *ot)
static int armature_autoside_names_exec(bContext *C, wmOperator *op)
{
+ Main *bmain = CTX_data_main(C);
Object *ob = CTX_data_edit_object(C);
bArmature *arm;
char newname[MAXBONENAME];
@@ -428,7 +430,7 @@ static int armature_autoside_names_exec(bContext *C, wmOperator *op)
{
BLI_strncpy(newname, ebone->name, sizeof(newname));
if (bone_autoside_name(newname, 1, axis, ebone->head[axis], ebone->tail[axis]))
- ED_armature_bone_rename(arm, ebone->name, newname);
+ ED_armature_bone_rename(bmain, arm, ebone->name, newname);
}
CTX_DATA_END;
diff --git a/source/blender/editors/armature/armature_relations.c b/source/blender/editors/armature/armature_relations.c
index 5d6c383b24b..9282148e857 100644
--- a/source/blender/editors/armature/armature_relations.c
+++ b/source/blender/editors/armature/armature_relations.c
@@ -400,7 +400,7 @@ int join_armature_exec(bContext *C, wmOperator *op)
DEG_relations_tag_update(bmain); /* because we removed object(s) */
- ED_armature_from_edit(arm);
+ ED_armature_from_edit(bmain, arm);
ED_armature_edit_free(arm);
WM_event_add_notifier(C, NC_SCENE | ND_OB_ACTIVE, scene);
@@ -411,7 +411,7 @@ int join_armature_exec(bContext *C, wmOperator *op)
/* *********************************** Separate *********************************************** */
/* Helper function for armature separating - link fixing */
-static void separated_armature_fix_links(Object *origArm, Object *newArm)
+static void separated_armature_fix_links(Main *bmain, Object *origArm, Object *newArm)
{
Object *ob;
bPoseChannel *pchan;
@@ -423,7 +423,7 @@ static void separated_armature_fix_links(Object *origArm, Object *newArm)
npchans = &newArm->pose->chanbase;
/* let's go through all objects in database */
- for (ob = G.main->object.first; ob; ob = ob->id.next) {
+ for (ob = bmain->object.first; ob; ob = ob->id.next) {
/* do some object-type specific things */
if (ob->type == OB_ARMATURE) {
for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
@@ -516,7 +516,7 @@ static void separated_armature_fix_links(Object *origArm, Object *newArm)
* sel: remove selected bones from the armature, otherwise the unselected bones are removed
* (ob is not in editmode)
*/
-static void separate_armature_bones(Object *ob, short sel)
+static void separate_armature_bones(Main *bmain, Object *ob, short sel)
{
bArmature *arm = (bArmature *)ob->data;
bPoseChannel *pchan, *pchann;
@@ -563,7 +563,7 @@ static void separate_armature_bones(Object *ob, short sel)
}
/* exit editmode (recalculates pchans too) */
- ED_armature_from_edit(ob->data);
+ ED_armature_from_edit(bmain, ob->data);
ED_armature_edit_free(ob->data);
}
@@ -611,7 +611,7 @@ static int separate_armature_exec(bContext *C, wmOperator *op)
oldob->mode &= ~OB_MODE_POSE;
//oldbase->flag &= ~OB_POSEMODE;
- ED_armature_from_edit(obedit->data);
+ ED_armature_from_edit(bmain, obedit->data);
ED_armature_edit_free(obedit->data);
/* 2) duplicate base */
@@ -623,12 +623,12 @@ static int separate_armature_exec(bContext *C, wmOperator *op)
/* 3) remove bones that shouldn't still be around on both armatures */
- separate_armature_bones(oldob, 1);
- separate_armature_bones(newob, 0);
+ separate_armature_bones(bmain, oldob, 1);
+ separate_armature_bones(bmain, newob, 0);
/* 4) fix links before depsgraph flushes */ // err... or after?
- separated_armature_fix_links(oldob, newob);
+ separated_armature_fix_links(bmain, oldob, newob);
DEG_id_tag_update(&oldob->id, OB_RECALC_DATA); /* this is the original one */
DEG_id_tag_update(&newob->id, OB_RECALC_DATA); /* this is the separated one */
diff --git a/source/blender/editors/armature/armature_skinning.c b/source/blender/editors/armature/armature_skinning.c
index 463e00957e6..87a66514417 100644
--- a/source/blender/editors/armature/armature_skinning.c
+++ b/source/blender/editors/armature/armature_skinning.c
@@ -45,6 +45,7 @@
#include "BKE_armature.h"
#include "BKE_context.h"
#include "BKE_deform.h"
+#include "BKE_mesh_runtime.h"
#include "BKE_object_deform.h"
#include "BKE_report.h"
#include "BKE_subsurf.h"
diff --git a/source/blender/editors/armature/armature_utils.c b/source/blender/editors/armature/armature_utils.c
index a8116ce26cf..02d45a4e041 100644
--- a/source/blender/editors/armature/armature_utils.c
+++ b/source/blender/editors/armature/armature_utils.c
@@ -585,7 +585,7 @@ static void armature_finalize_restpose(ListBase *bonelist, ListBase *editbonelis
}
/* put EditMode back in Object */
-void ED_armature_from_edit(bArmature *arm)
+void ED_armature_from_edit(Main *bmain, bArmature *arm)
{
EditBone *eBone, *neBone;
Bone *newBone;
@@ -679,7 +679,7 @@ void ED_armature_from_edit(bArmature *arm)
armature_finalize_restpose(&arm->bonebase, arm->edbo);
/* so all users of this armature should get rebuilt */
- for (obt = G.main->object.first; obt; obt = obt->id.next) {
+ for (obt = bmain->object.first; obt; obt = obt->id.next) {
if (obt->data == arm) {
BKE_pose_rebuild(obt, arm);
}
diff --git a/source/blender/editors/armature/editarmature_retarget.c b/source/blender/editors/armature/editarmature_retarget.c
new file mode 100644
index 00000000000..b74b515b37f
--- /dev/null
+++ b/source/blender/editors/armature/editarmature_retarget.c
@@ -0,0 +1,2644 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contributor(s): Martin Poirier
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ * autoarmature.c: Interface for automagically manipulating armature (retarget, created, ...)
+ */
+
+/** \file blender/editors/armature/editarmature_retarget.c
+ * \ingroup edarmature
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "PIL_time.h"
+
+#include "DNA_armature_types.h"
+#include "DNA_constraint_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_object_types.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_math.h"
+
+#include "BKE_constraint.h"
+#include "BKE_armature.h"
+#include "BKE_context.h"
+#include "BKE_main.h"
+
+#include "ED_armature.h"
+#include "ED_undo.h"
+
+#include "BIF_retarget.h"
+
+#include "armature_intern.h"
+
+/************ RIG RETARGET DATA STRUCTURES ***************/
+
+typedef struct MemoNode {
+ float weight;
+ int next;
+} MemoNode;
+
+typedef struct RetargetParam {
+ RigGraph *rigg;
+ RigArc *iarc;
+ RigNode *inode_start;
+ bContext *context;
+} RetargetParam;
+
+typedef enum {
+ RETARGET_LENGTH,
+ RETARGET_AGGRESSIVE
+} RetargetMode;
+
+typedef enum {
+ METHOD_BRUTE_FORCE = 0,
+ METHOD_MEMOIZE = 1
+} RetargetMethod;
+
+typedef enum {
+ ARC_FREE = 0,
+ ARC_TAKEN = 1,
+ ARC_USED = 2
+} ArcUsageFlags;
+
+static RigGraph *GLOBAL_RIGG = NULL;
+
+/*******************************************************************************************************/
+
+void exec_retargetArctoArc(TaskPool * __restrict pool, void *taskdata, int threadid);
+
+static void RIG_calculateEdgeAngles(RigEdge *edge_first, RigEdge *edge_second);
+float rollBoneByQuat(EditBone *bone, float old_up_axis[3], float qrot[4]);
+
+/* two levels */
+#define SHAPE_LEVELS (SHAPE_RADIX * SHAPE_RADIX)
+
+/*********************************** EDITBONE UTILS ****************************************************/
+
+static int countEditBoneChildren(ListBase *list, EditBone *parent)
+{
+ EditBone *ebone;
+ int count = 0;
+
+ for (ebone = list->first; ebone; ebone = ebone->next) {
+ if (ebone->parent == parent) {
+ count++;
+ }
+ }
+
+ return count;
+}
+
+static EditBone *nextEditBoneChild(ListBase *list, EditBone *parent, int n)
+{
+ EditBone *ebone;
+
+ for (ebone = list->first; ebone; ebone = ebone->next) {
+ if (ebone->parent == parent) {
+ if (n == 0) {
+ return ebone;
+ }
+ n--;
+ }
+ }
+
+ return NULL;
+}
+
+static void getEditBoneRollUpAxis(EditBone *bone, float roll, float up_axis[3])
+{
+ float mat[3][3], nor[3];
+
+ sub_v3_v3v3(nor, bone->tail, bone->head);
+
+ vec_roll_to_mat3(nor, roll, mat);
+ copy_v3_v3(up_axis, mat[2]);
+}
+
+static float rollBoneByQuatAligned(EditBone *bone, float old_up_axis[3], float qrot[4], float qroll[4], float aligned_axis[3])
+{
+ float nor[3], new_up_axis[3], x_axis[3], z_axis[3];
+
+ copy_v3_v3(new_up_axis, old_up_axis);
+ mul_qt_v3(qrot, new_up_axis);
+
+ sub_v3_v3v3(nor, bone->tail, bone->head);
+
+ cross_v3_v3v3(x_axis, nor, aligned_axis);
+ cross_v3_v3v3(z_axis, x_axis, nor);
+
+ normalize_v3(new_up_axis);
+ normalize_v3(x_axis);
+ normalize_v3(z_axis);
+
+ if (dot_v3v3(new_up_axis, x_axis) < 0) {
+ negate_v3(x_axis);
+ }
+
+ if (dot_v3v3(new_up_axis, z_axis) < 0) {
+ negate_v3(z_axis);
+ }
+
+ if (angle_normalized_v3v3(x_axis, new_up_axis) < angle_normalized_v3v3(z_axis, new_up_axis)) {
+ rotation_between_vecs_to_quat(qroll, new_up_axis, x_axis); /* set roll rotation quat */
+ return ED_armature_ebone_roll_to_vector(bone, x_axis, false);
+ }
+ else {
+ rotation_between_vecs_to_quat(qroll, new_up_axis, z_axis); /* set roll rotation quat */
+ return ED_armature_ebone_roll_to_vector(bone, z_axis, false);
+ }
+}
+
+static float rollBoneByQuatJoint(RigEdge *edge, RigEdge *previous, float qrot[4], float qroll[4], float up_axis[3])
+{
+ if (previous == NULL) {
+ /* default to up_axis if no previous */
+ return rollBoneByQuatAligned(edge->bone, edge->up_axis, qrot, qroll, up_axis);
+ }
+ else {
+ float new_up_axis[3];
+ float vec_first[3], vec_second[3], normal[3];
+
+ if (previous->bone) {
+ sub_v3_v3v3(vec_first, previous->bone->tail, previous->bone->head);
+ }
+ else if (previous->prev->bone) {
+ sub_v3_v3v3(vec_first, edge->bone->head, previous->prev->bone->tail);
+ }
+ else {
+ /* default to up_axis if first bone in the chain is an offset */
+ return rollBoneByQuatAligned(edge->bone, edge->up_axis, qrot, qroll, up_axis);
+ }
+
+ sub_v3_v3v3(vec_second, edge->bone->tail, edge->bone->head);
+
+ normalize_v3(vec_first);
+ normalize_v3(vec_second);
+
+ cross_v3_v3v3(normal, vec_first, vec_second);
+ normalize_v3(normal);
+
+ axis_angle_to_quat(qroll, vec_second, edge->up_angle);
+
+ mul_qt_v3(qroll, normal);
+
+ copy_v3_v3(new_up_axis, edge->up_axis);
+ mul_qt_v3(qrot, new_up_axis);
+
+ normalize_v3(new_up_axis);
+
+ /* real qroll between normal and up_axis */
+ rotation_between_vecs_to_quat(qroll, new_up_axis, normal);
+
+ return ED_armature_ebone_roll_to_vector(edge->bone, normal, false);
+ }
+}
+
+float rollBoneByQuat(EditBone *bone, float old_up_axis[3], float qrot[4])
+{
+ float new_up_axis[3];
+
+ copy_v3_v3(new_up_axis, old_up_axis);
+ mul_qt_v3(qrot, new_up_axis);
+
+ return ED_armature_ebone_roll_to_vector(bone, new_up_axis, false);
+}
+
+/************************************ DESTRUCTORS ******************************************************/
+
+static void RIG_freeRigArc(BArc *arc)
+{
+ BLI_freelistN(&((RigArc *)arc)->edges);
+}
+
+void RIG_freeRigGraph(BGraph *rg)
+{
+ RigGraph *rigg = (RigGraph *)rg;
+ BNode *node;
+ BArc *arc;
+
+ BLI_task_pool_free(rigg->task_pool);
+ BLI_task_scheduler_free(rigg->task_scheduler);
+
+ if (rigg->link_mesh) {
+ REEB_freeGraph(rigg->link_mesh);
+ }
+
+ for (arc = rg->arcs.first; arc; arc = arc->next) {
+ RIG_freeRigArc(arc);
+ }
+ BLI_freelistN(&rg->arcs);
+
+ for (node = rg->nodes.first; node; node = node->next) {
+ BLI_freeNode(rg, (BNode *)node);
+ }
+ BLI_freelistN(&rg->nodes);
+
+ BLI_freelistN(&rigg->controls);
+
+ BLI_ghash_free(rigg->bones_map, NULL, NULL);
+ BLI_ghash_free(rigg->controls_map, NULL, NULL);
+
+ if (rigg->flag & RIG_FREE_BONELIST) {
+ BLI_freelistN(rigg->editbones);
+ MEM_freeN(rigg->editbones);
+ }
+
+ MEM_freeN(rg);
+}
+
+/************************************* ALLOCATORS ******************************************************/
+
+static RigGraph *newRigGraph(void)
+{
+ RigGraph *rg;
+ int totthread;
+
+ rg = MEM_callocN(sizeof(RigGraph), "rig graph");
+
+ rg->head = NULL;
+
+ rg->bones_map = BLI_ghash_str_new("newRigGraph bones gh");
+ rg->controls_map = BLI_ghash_str_new("newRigGraph cont gh");
+
+ rg->free_arc = RIG_freeRigArc;
+ rg->free_node = NULL;
+
+#ifdef USE_THREADS
+ totthread = TASK_SCHEDULER_AUTO_THREADS;
+#else
+ totthread = TASK_SCHEDULER_SINGLE_THREAD;
+#endif
+
+ rg->task_scheduler = BLI_task_scheduler_create(totthread);
+ rg->task_pool = BLI_task_pool_create(rg->task_scheduler, NULL);
+
+ return rg;
+}
+
+static RigArc *newRigArc(RigGraph *rg)
+{
+ RigArc *arc;
+
+ arc = MEM_callocN(sizeof(RigArc), "rig arc");
+ arc->count = 0;
+ BLI_addtail(&rg->arcs, arc);
+
+ return arc;
+}
+
+static RigControl *newRigControl(RigGraph *rg)
+{
+ RigControl *ctrl;
+
+ ctrl = MEM_callocN(sizeof(RigControl), "rig control");
+
+ BLI_addtail(&rg->controls, ctrl);
+
+ return ctrl;
+}
+
+static RigNode *newRigNodeHead(RigGraph *rg, RigArc *arc, float p[3])
+{
+ RigNode *node;
+ node = MEM_callocN(sizeof(RigNode), "rig node");
+ BLI_addtail(&rg->nodes, node);
+
+ copy_v3_v3(node->p, p);
+ node->degree = 1;
+ node->arcs = NULL;
+
+ arc->head = node;
+
+ return node;
+}
+
+static void addRigNodeHead(RigGraph *UNUSED(rg), RigArc *arc, RigNode *node)
+{
+ node->degree++;
+
+ arc->head = node;
+}
+
+static RigNode *newRigNode(RigGraph *rg, float p[3])
+{
+ RigNode *node;
+ node = MEM_callocN(sizeof(RigNode), "rig node");
+ BLI_addtail(&rg->nodes, node);
+
+ copy_v3_v3(node->p, p);
+ node->degree = 0;
+ node->arcs = NULL;
+
+ return node;
+}
+
+static RigNode *newRigNodeTail(RigGraph *rg, RigArc *arc, float p[3])
+{
+ RigNode *node = newRigNode(rg, p);
+
+ node->degree = 1;
+ arc->tail = node;
+
+ return node;
+}
+
+static void RIG_appendEdgeToArc(RigArc *arc, RigEdge *edge)
+{
+ BLI_addtail(&arc->edges, edge);
+
+ if (edge->prev == NULL) {
+ copy_v3_v3(edge->head, arc->head->p);
+ }
+ else {
+ RigEdge *last_edge = edge->prev;
+ copy_v3_v3(edge->head, last_edge->tail);
+ RIG_calculateEdgeAngles(last_edge, edge);
+ }
+
+ edge->length = len_v3v3(edge->head, edge->tail);
+
+ arc->length += edge->length;
+
+ arc->count += 1;
+}
+
+static void RIG_addEdgeToArc(RigArc *arc, float tail[3], EditBone *bone)
+{
+ RigEdge *edge;
+
+ edge = MEM_callocN(sizeof(RigEdge), "rig edge");
+
+ copy_v3_v3(edge->tail, tail);
+ edge->bone = bone;
+
+ if (bone) {
+ getEditBoneRollUpAxis(bone, bone->roll, edge->up_axis);
+ }
+
+ RIG_appendEdgeToArc(arc, edge);
+}
+/************************************** CLONING TEMPLATES **********************************************/
+
+static void renameTemplateBone(char *name, char *template_name, ListBase *editbones, char *side_string, char *num_string)
+{
+ int i, j;
+
+ for (i = 0, j = 0; i < (MAXBONENAME - 1) && j < (MAXBONENAME - 1) && template_name[i] != '\0'; i++) {
+ if (template_name[i] == '&') {
+ if (template_name[i + 1] == 'S' || template_name[i + 1] == 's') {
+ j += BLI_strncpy_rlen(name + j, side_string, MAXBONENAME);
+ i++;
+ }
+ else if (template_name[i + 1] == 'N' || template_name[i + 1] == 'n') {
+ j += BLI_strncpy_rlen(name + j, num_string, MAXBONENAME);
+ i++;
+ }
+ else {
+ name[j] = template_name[i];
+ j++;
+ }
+ }
+ else {
+ name[j] = template_name[i];
+ j++;
+ }
+ }
+
+ name[j] = '\0';
+
+ ED_armature_ebone_unique_name(editbones, name, NULL);
+}
+
+static RigControl *cloneControl(RigGraph *rg, RigGraph *src_rg, RigControl *src_ctrl, GHash *ptr_hash, char *side_string, char *num_string)
+{
+ RigControl *ctrl;
+ char name[MAXBONENAME];
+
+ ctrl = newRigControl(rg);
+
+ copy_v3_v3(ctrl->head, src_ctrl->head);
+ copy_v3_v3(ctrl->tail, src_ctrl->tail);
+ copy_v3_v3(ctrl->up_axis, src_ctrl->up_axis);
+ copy_v3_v3(ctrl->offset, src_ctrl->offset);
+
+ ctrl->tail_mode = src_ctrl->tail_mode;
+ ctrl->flag = src_ctrl->flag;
+
+ renameTemplateBone(name, src_ctrl->bone->name, rg->editbones, side_string, num_string);
+ ctrl->bone = duplicateEditBoneObjects(src_ctrl->bone, name, rg->editbones, src_rg->ob, rg->ob);
+ ctrl->bone->flag &= ~(BONE_TIPSEL | BONE_SELECTED | BONE_ROOTSEL);
+ BLI_ghash_insert(ptr_hash, src_ctrl->bone, ctrl->bone);
+
+ ctrl->link = src_ctrl->link;
+ ctrl->link_tail = src_ctrl->link_tail;
+
+ return ctrl;
+}
+
+static RigArc *cloneArc(RigGraph *rg, RigGraph *src_rg, RigArc *src_arc, GHash *ptr_hash, char *side_string, char *num_string)
+{
+ RigEdge *src_edge;
+ RigArc *arc;
+
+ arc = newRigArc(rg);
+
+ arc->head = BLI_ghash_lookup(ptr_hash, src_arc->head);
+ arc->tail = BLI_ghash_lookup(ptr_hash, src_arc->tail);
+
+ arc->head->degree++;
+ arc->tail->degree++;
+
+ arc->length = src_arc->length;
+
+ arc->count = src_arc->count;
+
+ for (src_edge = src_arc->edges.first; src_edge; src_edge = src_edge->next) {
+ RigEdge *edge;
+
+ edge = MEM_callocN(sizeof(RigEdge), "rig edge");
+
+ copy_v3_v3(edge->head, src_edge->head);
+ copy_v3_v3(edge->tail, src_edge->tail);
+ copy_v3_v3(edge->up_axis, src_edge->up_axis);
+
+ edge->length = src_edge->length;
+ edge->angle = src_edge->angle;
+ edge->up_angle = src_edge->up_angle;
+
+ if (src_edge->bone != NULL) {
+ char name[MAXBONENAME];
+ renameTemplateBone(name, src_edge->bone->name, rg->editbones, side_string, num_string);
+ edge->bone = duplicateEditBoneObjects(src_edge->bone, name, rg->editbones, src_rg->ob, rg->ob);
+ edge->bone->flag &= ~(BONE_TIPSEL | BONE_SELECTED | BONE_ROOTSEL);
+ BLI_ghash_insert(ptr_hash, src_edge->bone, edge->bone);
+ }
+
+ BLI_addtail(&arc->edges, edge);
+ }
+
+ return arc;
+}
+
+static RigGraph *cloneRigGraph(RigGraph *src, ListBase *editbones, Object *ob, char *side_string, char *num_string)
+{
+ GHash *ptr_hash;
+ RigNode *node;
+ RigArc *arc;
+ RigControl *ctrl;
+ RigGraph *rg;
+
+ ptr_hash = BLI_ghash_ptr_new("cloneRigGraph gh");
+
+ rg = newRigGraph();
+
+ rg->ob = ob;
+ rg->editbones = editbones;
+
+ preEditBoneDuplicate(rg->editbones); /* prime bones for duplication */
+ preEditBoneDuplicate(src->editbones); /* prime bones for duplication */
+
+ /* Clone nodes */
+ for (node = src->nodes.first; node; node = node->next) {
+ RigNode *cloned_node = newRigNode(rg, node->p);
+ BLI_ghash_insert(ptr_hash, node, cloned_node);
+ }
+
+ rg->head = BLI_ghash_lookup(ptr_hash, src->head);
+
+ /* Clone arcs */
+ for (arc = src->arcs.first; arc; arc = arc->next) {
+ cloneArc(rg, src, arc, ptr_hash, side_string, num_string);
+ }
+
+ /* Clone controls */
+ for (ctrl = src->controls.first; ctrl; ctrl = ctrl->next) {
+ cloneControl(rg, src, ctrl, ptr_hash, side_string, num_string);
+ }
+
+ /* Relink bones properly */
+ for (arc = rg->arcs.first; arc; arc = arc->next) {
+ RigEdge *edge;
+
+ for (edge = arc->edges.first; edge; edge = edge->next) {
+ if (edge->bone != NULL) {
+ EditBone *bone;
+
+ updateDuplicateSubtargetObjects(edge->bone, src->editbones, src->ob, rg->ob);
+
+ if (edge->bone->parent) {
+ bone = BLI_ghash_lookup(ptr_hash, edge->bone->parent);
+
+ if (bone != NULL) {
+ edge->bone->parent = bone;
+ }
+ else {
+ /* disconnect since parent isn't cloned
+ * this will only happen when cloning from selected bones
+ * */
+ edge->bone->flag &= ~BONE_CONNECTED;
+ }
+ }
+ }
+ }
+ }
+
+ for (ctrl = rg->controls.first; ctrl; ctrl = ctrl->next) {
+ EditBone *bone;
+
+ updateDuplicateSubtargetObjects(ctrl->bone, src->editbones, src->ob, rg->ob);
+
+ if (ctrl->bone->parent) {
+ bone = BLI_ghash_lookup(ptr_hash, ctrl->bone->parent);
+
+ if (bone != NULL) {
+ ctrl->bone->parent = bone;
+ }
+ else {
+ /* disconnect since parent isn't cloned
+ * this will only happen when cloning from selected bones
+ * */
+ ctrl->bone->flag &= ~BONE_CONNECTED;
+ }
+ }
+
+ ctrl->link = BLI_ghash_lookup(ptr_hash, ctrl->link);
+ ctrl->link_tail = BLI_ghash_lookup(ptr_hash, ctrl->link_tail);
+ }
+
+ BLI_ghash_free(ptr_hash, NULL, NULL);
+
+ return rg;
+}
+
+
+/*******************************************************************************************************/
+
+static void RIG_calculateEdgeAngles(RigEdge *edge_first, RigEdge *edge_second)
+{
+ float vec_first[3], vec_second[3];
+
+ sub_v3_v3v3(vec_first, edge_first->tail, edge_first->head);
+ sub_v3_v3v3(vec_second, edge_second->tail, edge_second->head);
+
+ normalize_v3(vec_first);
+ normalize_v3(vec_second);
+
+ edge_first->angle = angle_normalized_v3v3(vec_first, vec_second);
+
+ if (edge_second->bone != NULL) {
+ float normal[3];
+
+ cross_v3_v3v3(normal, vec_first, vec_second);
+ normalize_v3(normal);
+
+ edge_second->up_angle = angle_normalized_v3v3(normal, edge_second->up_axis);
+ }
+}
+
+/************************************ CONTROL BONES ****************************************************/
+
+static void RIG_addControlBone(RigGraph *rg, EditBone *bone)
+{
+ RigControl *ctrl = newRigControl(rg);
+ ctrl->bone = bone;
+ copy_v3_v3(ctrl->head, bone->head);
+ copy_v3_v3(ctrl->tail, bone->tail);
+ getEditBoneRollUpAxis(bone, bone->roll, ctrl->up_axis);
+ ctrl->tail_mode = TL_NONE;
+
+ BLI_ghash_insert(rg->controls_map, bone->name, ctrl);
+}
+
+static int RIG_parentControl(RigControl *ctrl, EditBone *link)
+{
+ if (link) {
+ float offset[3];
+ int flag = 0;
+
+ sub_v3_v3v3(offset, ctrl->bone->head, link->head);
+
+ /* if root matches, check for direction too */
+ if (dot_v3v3(offset, offset) < 0.0001f) {
+ float vbone[3], vparent[3];
+
+ flag |= RIG_CTRL_FIT_ROOT;
+
+ sub_v3_v3v3(vbone, ctrl->bone->tail, ctrl->bone->head);
+ sub_v3_v3v3(vparent, link->tail, link->head);
+
+ /* test for opposite direction */
+ if (dot_v3v3(vbone, vparent) > 0) {
+ float nor[3];
+ float len;
+
+ cross_v3_v3v3(nor, vbone, vparent);
+
+ len = dot_v3v3(nor, nor);
+ if (len < 0.0001f) {
+ flag |= RIG_CTRL_FIT_BONE;
+ }
+ }
+ }
+
+ /* Bail out if old one is automatically better */
+ if (flag < ctrl->flag) {
+ return 0;
+ }
+
+ /* if there's already a link
+ * overwrite only if new link is higher in the chain */
+ if (ctrl->link && flag == ctrl->flag) {
+ EditBone *bone = NULL;
+
+ for (bone = ctrl->link; bone; bone = bone->parent) {
+ /* if link is in the chain, break and use that one */
+ if (bone == link) {
+ break;
+ }
+ }
+
+ /* not in chain, don't update link */
+ if (bone == NULL) {
+ return 0;
+ }
+ }
+
+
+ ctrl->link = link;
+ ctrl->flag = flag;
+
+ copy_v3_v3(ctrl->offset, offset);
+
+ return 1;
+ }
+
+ return 0;
+}
+
+static void RIG_reconnectControlBones(RigGraph *rg)
+{
+ RigControl *ctrl;
+ bool changed = true;
+
+ /* first pass, link to deform bones */
+ for (ctrl = rg->controls.first; ctrl; ctrl = ctrl->next) {
+ bPoseChannel *pchan;
+ bConstraint *con;
+ int found = 0;
+
+ /* DO SOME MAGIC HERE */
+ for (pchan = rg->ob->pose->chanbase.first; pchan; pchan = pchan->next) {
+ for (con = pchan->constraints.first; con; con = con->next) {
+ const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
+ ListBase targets = {NULL, NULL};
+ bConstraintTarget *ct;
+
+ /* constraint targets */
+ if (cti && cti->get_constraint_targets) {
+ int target_index;
+
+ cti->get_constraint_targets(con, &targets);
+
+ for (target_index = 0, ct = targets.first; ct; target_index++, ct = ct->next) {
+ if ((ct->tar == rg->ob) && STREQ(ct->subtarget, ctrl->bone->name)) {
+ /* SET bone link to bone corresponding to pchan */
+ EditBone *link = BLI_ghash_lookup(rg->bones_map, pchan->name);
+
+ /* Making sure bone is in this armature */
+ if (link != NULL) {
+ /* for pole targets, link to parent bone instead, if possible */
+ if (con->type == CONSTRAINT_TYPE_KINEMATIC && target_index == 1) {
+ if (link->parent && BLI_ghash_haskey(rg->bones_map, link->parent->name)) {
+ link = link->parent;
+ }
+ }
+
+ found = RIG_parentControl(ctrl, link);
+ }
+ }
+ }
+
+ if (cti->flush_constraint_targets)
+ cti->flush_constraint_targets(con, &targets, 0);
+ }
+ }
+ }
+
+ /* if not found yet, check parent */
+ if (found == 0) {
+ if (ctrl->bone->parent) {
+ /* make sure parent is a deforming bone
+ * NULL if not
+ * */
+ EditBone *link = BLI_ghash_lookup(rg->bones_map, ctrl->bone->parent->name);
+
+ found = RIG_parentControl(ctrl, link);
+ }
+
+ /* check if bone is not superposed on another one */
+ {
+ RigArc *arc;
+ RigArc *best_arc = NULL;
+ EditBone *link = NULL;
+
+ for (arc = rg->arcs.first; arc; arc = arc->next) {
+ RigEdge *edge;
+ for (edge = arc->edges.first; edge; edge = edge->next) {
+ if (edge->bone) {
+ int fit = 0;
+
+ fit = len_v3v3(ctrl->bone->head, edge->bone->head) < 0.0001f;
+ fit = fit || len_v3v3(ctrl->bone->tail, edge->bone->tail) < 0.0001f;
+
+ if (fit) {
+ /* pick the bone on the arc with the lowest symmetry level
+ * means you connect control to the trunk of the skeleton */
+ if (best_arc == NULL || arc->symmetry_level < best_arc->symmetry_level) {
+ best_arc = arc;
+ link = edge->bone;
+ }
+ }
+ }
+ }
+ }
+
+ found = RIG_parentControl(ctrl, link);
+ }
+ }
+
+ /* if not found yet, check child */
+ if (found == 0) {
+ RigArc *arc;
+ RigArc *best_arc = NULL;
+ EditBone *link = NULL;
+
+ for (arc = rg->arcs.first; arc; arc = arc->next) {
+ RigEdge *edge;
+ for (edge = arc->edges.first; edge; edge = edge->next) {
+ if (edge->bone && edge->bone->parent == ctrl->bone) {
+ /* pick the bone on the arc with the lowest symmetry level
+ * means you connect control to the trunk of the skeleton */
+ if (best_arc == NULL || arc->symmetry_level < best_arc->symmetry_level) {
+ best_arc = arc;
+ link = edge->bone;
+ }
+ }
+ }
+ }
+
+ found = RIG_parentControl(ctrl, link);
+ }
+
+ }
+
+
+ /* second pass, make chains in control bones */
+ while (changed) {
+ changed = false;
+
+ for (ctrl = rg->controls.first; ctrl; ctrl = ctrl->next) {
+ /* if control is not linked yet */
+ if (ctrl->link == NULL) {
+ bPoseChannel *pchan;
+ bConstraint *con;
+ RigControl *ctrl_parent = NULL;
+ RigControl *ctrl_child;
+ int found = 0;
+
+ if (ctrl->bone->parent) {
+ ctrl_parent = BLI_ghash_lookup(rg->controls_map, ctrl->bone->parent->name);
+ }
+
+ /* check constraints first */
+
+ /* DO SOME MAGIC HERE */
+ for (pchan = rg->ob->pose->chanbase.first; pchan; pchan = pchan->next) {
+ for (con = pchan->constraints.first; con; con = con->next) {
+ const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
+ ListBase targets = {NULL, NULL};
+ bConstraintTarget *ct;
+
+ /* constraint targets */
+ if (cti && cti->get_constraint_targets) {
+ cti->get_constraint_targets(con, &targets);
+
+ for (ct = targets.first; ct; ct = ct->next) {
+ if ((ct->tar == rg->ob) && STREQ(ct->subtarget, ctrl->bone->name)) {
+ /* SET bone link to ctrl corresponding to pchan */
+ RigControl *link = BLI_ghash_lookup(rg->controls_map, pchan->name);
+
+ /* if owner is a control bone, link with it */
+ if (link && link->link) {
+ RIG_parentControl(ctrl, link->bone);
+ found = 1;
+ break;
+ }
+ }
+ }
+
+ if (cti->flush_constraint_targets)
+ cti->flush_constraint_targets(con, &targets, 0);
+ }
+ }
+ }
+
+ if (found == 0) {
+ /* check if parent is already linked */
+ if (ctrl_parent && ctrl_parent->link) {
+ RIG_parentControl(ctrl, ctrl_parent->bone);
+ changed = true;
+ }
+ else {
+ /* check childs */
+ for (ctrl_child = rg->controls.first; ctrl_child; ctrl_child = ctrl_child->next) {
+ /* if a child is linked, link to that one */
+ if (ctrl_child->link && ctrl_child->bone->parent == ctrl->bone) {
+ RIG_parentControl(ctrl, ctrl_child->bone);
+ changed = true;
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ /* third pass, link control tails */
+ for (ctrl = rg->controls.first; ctrl; ctrl = ctrl->next) {
+ /* fit bone already means full match, so skip those */
+ if ((ctrl->flag & RIG_CTRL_FIT_BONE) == 0) {
+ GHashIterator ghi;
+
+ /* look on deform bones first */
+ BLI_ghashIterator_init(&ghi, rg->bones_map);
+
+ for (; !BLI_ghashIterator_done(&ghi); BLI_ghashIterator_step(&ghi)) {
+ EditBone *bone = (EditBone *)BLI_ghashIterator_getValue(&ghi);
+
+ /* don't link with parent */
+ if (bone->parent != ctrl->bone) {
+ if (len_v3v3(ctrl->bone->tail, bone->head) < 0.01f) {
+ ctrl->tail_mode = TL_HEAD;
+ ctrl->link_tail = bone;
+ break;
+ }
+ else if (len_v3v3(ctrl->bone->tail, bone->tail) < 0.01f) {
+ ctrl->tail_mode = TL_TAIL;
+ ctrl->link_tail = bone;
+ break;
+ }
+ }
+ }
+
+ /* if we haven't found one yet, look in control bones */
+ if (ctrl->tail_mode == TL_NONE) {
+ /* pass */
+ }
+ }
+ }
+
+}
+
+/*******************************************************************************************************/
+
+static void RIG_joinArcs(RigGraph *rg, RigNode *node, RigArc *joined_arc1, RigArc *joined_arc2)
+{
+ RigEdge *edge, *next_edge;
+
+ /* ignore cases where joint is at start or end */
+ if (joined_arc1->head == joined_arc2->head || joined_arc1->tail == joined_arc2->tail) {
+ return;
+ }
+
+ /* swap arcs to make sure arc1 is before arc2 */
+ if (joined_arc1->head == joined_arc2->tail) {
+ RigArc *tmp = joined_arc1;
+ joined_arc1 = joined_arc2;
+ joined_arc2 = tmp;
+ }
+
+ for (edge = joined_arc2->edges.first; edge; edge = next_edge) {
+ next_edge = edge->next;
+
+ RIG_appendEdgeToArc(joined_arc1, edge);
+ }
+
+ joined_arc1->tail = joined_arc2->tail;
+
+ BLI_listbase_clear(&joined_arc2->edges);
+
+ BLI_removeArc((BGraph *)rg, (BArc *)joined_arc2);
+
+ BLI_removeNode((BGraph *)rg, (BNode *)node);
+}
+
+static void RIG_removeNormalNodes(RigGraph *rg)
+{
+ RigNode *node, *next_node;
+
+ for (node = rg->nodes.first; node; node = next_node) {
+ next_node = node->next;
+
+ if (node->degree == 2) {
+ RigArc *arc, *joined_arc1 = NULL, *joined_arc2 = NULL;
+
+ for (arc = rg->arcs.first; arc; arc = arc->next) {
+ if (arc->head == node || arc->tail == node) {
+ if (joined_arc1 == NULL) {
+ joined_arc1 = arc;
+ }
+ else {
+ joined_arc2 = arc;
+ break;
+ }
+ }
+ }
+
+ RIG_joinArcs(rg, node, joined_arc1, joined_arc2);
+ }
+ }
+}
+
+static void RIG_removeUneededOffsets(RigGraph *rg)
+{
+ RigArc *arc;
+
+ for (arc = rg->arcs.first; arc; arc = arc->next) {
+ RigEdge *first_edge, *last_edge;
+
+ first_edge = arc->edges.first;
+ last_edge = arc->edges.last;
+
+ if (first_edge->bone == NULL) {
+ if (first_edge->bone == NULL && len_v3v3(first_edge->tail, arc->head->p) <= 0.001f) {
+ BLI_remlink(&arc->edges, first_edge);
+ MEM_freeN(first_edge);
+ }
+ else if (arc->head->degree == 1) {
+ RigNode *new_node = (RigNode *)BLI_FindNodeByPosition((BGraph *)rg, first_edge->tail, 0.001f);
+
+ if (new_node) {
+ BLI_remlink(&arc->edges, first_edge);
+ MEM_freeN(first_edge);
+ BLI_replaceNodeInArc((BGraph *)rg, (BArc *)arc, (BNode *)new_node, (BNode *)arc->head);
+ }
+ else {
+ RigEdge *next_edge = first_edge->next;
+
+ if (next_edge) {
+ BLI_remlink(&arc->edges, first_edge);
+ MEM_freeN(first_edge);
+
+ copy_v3_v3(arc->head->p, next_edge->head);
+ }
+ }
+ }
+ else {
+ /* check if all arc connected start with a null edge */
+ RigArc *other_arc;
+ for (other_arc = rg->arcs.first; other_arc; other_arc = other_arc->next) {
+ if (other_arc != arc) {
+ RigEdge *test_edge;
+ if (other_arc->head == arc->head) {
+ test_edge = other_arc->edges.first;
+
+ if (test_edge->bone != NULL) {
+ break;
+ }
+ }
+ else if (other_arc->tail == arc->head) {
+ test_edge = other_arc->edges.last;
+
+ if (test_edge->bone != NULL) {
+ break;
+ }
+ }
+ }
+ }
+
+ if (other_arc == NULL) {
+ RigNode *new_node = (RigNode *)BLI_FindNodeByPosition((BGraph *)rg, first_edge->tail, 0.001);
+
+ if (new_node) {
+ /* remove null edge in other arcs too */
+ for (other_arc = rg->arcs.first; other_arc; other_arc = other_arc->next) {
+ if (other_arc != arc) {
+ RigEdge *test_edge;
+ if (other_arc->head == arc->head) {
+ BLI_replaceNodeInArc((BGraph *)rg, (BArc *)other_arc, (BNode *)new_node, (BNode *)other_arc->head);
+ test_edge = other_arc->edges.first;
+ BLI_remlink(&other_arc->edges, test_edge);
+ MEM_freeN(test_edge);
+ }
+ else if (other_arc->tail == arc->head) {
+ BLI_replaceNodeInArc((BGraph *)rg, (BArc *)other_arc, (BNode *)new_node, (BNode *)other_arc->tail);
+ test_edge = other_arc->edges.last;
+ BLI_remlink(&other_arc->edges, test_edge);
+ MEM_freeN(test_edge);
+ }
+ }
+ }
+
+ BLI_remlink(&arc->edges, first_edge);
+ MEM_freeN(first_edge);
+ BLI_replaceNodeInArc((BGraph *)rg, (BArc *)arc, (BNode *)new_node, (BNode *)arc->head);
+ }
+ else {
+ RigEdge *next_edge = first_edge->next;
+
+ if (next_edge) {
+ BLI_remlink(&arc->edges, first_edge);
+ MEM_freeN(first_edge);
+
+ copy_v3_v3(arc->head->p, next_edge->head);
+
+ /* remove null edge in other arcs too */
+ for (other_arc = rg->arcs.first; other_arc; other_arc = other_arc->next) {
+ if (other_arc != arc) {
+ RigEdge *test_edge;
+ if (other_arc->head == arc->head) {
+ test_edge = other_arc->edges.first;
+ BLI_remlink(&other_arc->edges, test_edge);
+ MEM_freeN(test_edge);
+ }
+ else if (other_arc->tail == arc->head) {
+ test_edge = other_arc->edges.last;
+ BLI_remlink(&other_arc->edges, test_edge);
+ MEM_freeN(test_edge);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if (last_edge->bone == NULL) {
+ if (len_v3v3(last_edge->head, arc->tail->p) <= 0.001f) {
+ BLI_remlink(&arc->edges, last_edge);
+ MEM_freeN(last_edge);
+ }
+ else if (arc->tail->degree == 1) {
+ RigNode *new_node = (RigNode *)BLI_FindNodeByPosition((BGraph *)rg, last_edge->head, 0.001f);
+
+ if (new_node) {
+ RigEdge *previous_edge = last_edge->prev;
+
+ BLI_remlink(&arc->edges, last_edge);
+ MEM_freeN(last_edge);
+ BLI_replaceNodeInArc((BGraph *)rg, (BArc *)arc, (BNode *)new_node, (BNode *)arc->tail);
+
+ /* set previous angle to 0, since there's no following edges */
+ if (previous_edge) {
+ previous_edge->angle = 0;
+ }
+ }
+ else {
+ RigEdge *previous_edge = last_edge->prev;
+
+ if (previous_edge) {
+ BLI_remlink(&arc->edges, last_edge);
+ MEM_freeN(last_edge);
+
+ copy_v3_v3(arc->tail->p, previous_edge->tail);
+ previous_edge->angle = 0;
+ }
+ }
+ }
+ }
+ }
+}
+
+static void RIG_arcFromBoneChain(RigGraph *rg, ListBase *list, EditBone *root_bone, RigNode *starting_node, bool selected)
+{
+ EditBone *bone, *last_bone = root_bone;
+ RigArc *arc = NULL;
+ int contain_head = 0;
+
+ for (bone = root_bone; bone; bone = nextEditBoneChild(list, bone, 0)) {
+ int nb_children;
+
+ if (selected == 0 || (bone->flag & BONE_SELECTED)) {
+ if ((bone->flag & BONE_NO_DEFORM) == 0) {
+ BLI_ghash_insert(rg->bones_map, bone->name, bone);
+
+ if (arc == NULL) {
+ arc = newRigArc(rg);
+
+ if (starting_node == NULL) {
+ starting_node = newRigNodeHead(rg, arc, root_bone->head);
+ }
+ else {
+ addRigNodeHead(rg, arc, starting_node);
+ }
+ }
+
+ if (bone->parent && (bone->flag & BONE_CONNECTED) == 0) {
+ RIG_addEdgeToArc(arc, bone->head, NULL);
+ }
+
+ RIG_addEdgeToArc(arc, bone->tail, bone);
+
+ last_bone = bone;
+
+ if (STREQ(bone->name, "head")) {
+ contain_head = 1;
+ }
+ }
+ else if ((bone->flag & BONE_EDITMODE_LOCKED) == 0) { /* ignore locked bones */
+ RIG_addControlBone(rg, bone);
+ }
+ }
+
+ nb_children = countEditBoneChildren(list, bone);
+ if (nb_children > 1) {
+ RigNode *end_node = NULL;
+ int i;
+
+ if (arc != NULL) {
+ end_node = newRigNodeTail(rg, arc, bone->tail);
+ }
+ else {
+ end_node = newRigNode(rg, bone->tail);
+ }
+
+ for (i = 0; i < nb_children; i++) {
+ root_bone = nextEditBoneChild(list, bone, i);
+ RIG_arcFromBoneChain(rg, list, root_bone, end_node, selected);
+ }
+
+ /* arc ends here, break */
+ break;
+ }
+ }
+
+ /* If the loop exited without forking */
+ if (arc != NULL && bone == NULL) {
+ newRigNodeTail(rg, arc, last_bone->tail);
+ }
+
+ if (contain_head) {
+ rg->head = arc->tail;
+ }
+}
+
+/*******************************************************************************************************/
+static void RIG_findHead(RigGraph *rg)
+{
+ if (rg->head == NULL) {
+ if (BLI_listbase_is_single(&rg->arcs)) {
+ RigArc *arc = rg->arcs.first;
+
+ rg->head = (RigNode *)arc->head;
+ }
+ else {
+ RigArc *arc;
+
+ for (arc = rg->arcs.first; arc; arc = arc->next) {
+ RigEdge *edge = arc->edges.last;
+
+ if (edge->bone->flag & (BONE_TIPSEL | BONE_SELECTED)) {
+ rg->head = arc->tail;
+ break;
+ }
+ }
+ }
+
+ if (rg->head == NULL) {
+ rg->head = rg->nodes.first;
+ }
+ }
+}
+
+/*******************************************************************************************************/
+
+static void RIG_printNode(RigNode *node, const char name[])
+{
+ printf("%s %p %i <%0.3f, %0.3f, %0.3f>\n", name, (void *)node, node->degree, node->p[0], node->p[1], node->p[2]);
+
+ if (node->symmetry_flag & SYM_TOPOLOGICAL) {
+ if (node->symmetry_flag & SYM_AXIAL)
+ printf("Symmetry AXIAL\n");
+ else if (node->symmetry_flag & SYM_RADIAL)
+ printf("Symmetry RADIAL\n");
+
+ print_v3("symmetry axis", node->symmetry_axis);
+ }
+}
+
+void RIG_printArcBones(RigArc *arc)
+{
+ RigEdge *edge;
+
+ for (edge = arc->edges.first; edge; edge = edge->next) {
+ if (edge->bone)
+ printf("%s ", edge->bone->name);
+ else
+ printf("---- ");
+ }
+ printf("\n");
+}
+
+static void RIG_printCtrl(RigControl *ctrl, char *indent)
+{
+ char text[128];
+
+ printf("%sBone: %s\n", indent, ctrl->bone->name);
+ printf("%sLink: %s\n", indent, ctrl->link ? ctrl->link->name : "!NONE!");
+
+ BLI_snprintf(text, sizeof(text), "%soffset", indent);
+ print_v3(text, ctrl->offset);
+
+ printf("%sFlag: %i\n", indent, ctrl->flag);
+}
+
+static void RIG_printLinkedCtrl(RigGraph *rg, EditBone *bone, int tabs)
+{
+ RigControl *ctrl;
+ char indent[64];
+ char *s = indent;
+ int i;
+
+ for (i = 0; i < tabs; i++) {
+ s[0] = '\t';
+ s++;
+ }
+ s[0] = 0;
+
+ for (ctrl = rg->controls.first; ctrl; ctrl = ctrl->next) {
+ if (ctrl->link == bone) {
+ RIG_printCtrl(ctrl, indent);
+ RIG_printLinkedCtrl(rg, ctrl->bone, tabs + 1);
+ }
+ }
+}
+
+void RIG_printArc(RigGraph *rg, RigArc *arc)
+{
+ RigEdge *edge;
+
+ RIG_printNode((RigNode *)arc->head, "head");
+
+ for (edge = arc->edges.first; edge; edge = edge->next) {
+ printf("\tinner joints %0.3f %0.3f %0.3f\n", edge->tail[0], edge->tail[1], edge->tail[2]);
+ printf("\t\tlength %f\n", edge->length);
+ printf("\t\tangle %f\n", edge->angle * (float)(180 / M_PI));
+ if (edge->bone) {
+ printf("\t\t%s\n", edge->bone->name);
+ RIG_printLinkedCtrl(rg, edge->bone, 3);
+ }
+ }
+ printf("symmetry level: %i flag: %i group %i\n", arc->symmetry_level, arc->symmetry_flag, arc->symmetry_group);
+
+ RIG_printNode((RigNode *)arc->tail, "tail");
+}
+
+void RIG_printGraph(RigGraph *rg)
+{
+ RigArc *arc;
+
+ printf("---- ARCS ----\n");
+ for (arc = rg->arcs.first; arc; arc = arc->next) {
+ RIG_printArc(rg, arc);
+ printf("\n");
+ }
+
+ if (rg->head) {
+ RIG_printNode(rg->head, "HEAD NODE:");
+ }
+ else {
+ printf("HEAD NODE: NONE\n");
+ }
+}
+
+/*******************************************************************************************************/
+
+RigGraph *RIG_graphFromArmature(const bContext *C, Object *ob, bArmature *arm)
+{
+ Object *obedit = CTX_data_edit_object(C);
+ Scene *scene = CTX_data_scene(C);
+ EditBone *ebone;
+ RigGraph *rg;
+
+ rg = newRigGraph();
+
+ if (obedit == ob) {
+ rg->editbones = ((bArmature *)obedit->data)->edbo;
+ }
+ else {
+ rg->editbones = MEM_callocN(sizeof(ListBase), "EditBones");
+ make_boneList(rg->editbones, &arm->bonebase, NULL, NULL);
+ rg->flag |= RIG_FREE_BONELIST;
+ }
+
+ rg->ob = ob;
+
+ /* Do the rotations */
+ for (ebone = rg->editbones->first; ebone; ebone = ebone->next) {
+ if (ebone->parent == NULL) {
+ RIG_arcFromBoneChain(rg, rg->editbones, ebone, NULL, 0);
+ }
+ }
+
+ BLI_removeDoubleNodes((BGraph *)rg, 0.001);
+
+ RIG_removeNormalNodes(rg);
+
+ RIG_removeUneededOffsets(rg);
+
+ BLI_buildAdjacencyList((BGraph *)rg);
+
+ RIG_findHead(rg);
+
+ BLI_markdownSymmetry((BGraph *)rg, (BNode *)rg->head, scene->toolsettings->skgen_symmetry_limit);
+
+ RIG_reconnectControlBones(rg); /* after symmetry, because we use levels to find best match */
+
+ if (BLI_isGraphCyclic((BGraph *)rg)) {
+ printf("armature cyclic\n");
+ }
+
+ return rg;
+}
+
+static RigGraph *armatureSelectedToGraph(bContext *C, Object *ob, bArmature *arm)
+{
+ Object *obedit = CTX_data_edit_object(C);
+ Scene *scene = CTX_data_scene(C);
+ EditBone *ebone;
+ RigGraph *rg;
+
+ rg = newRigGraph();
+
+ if (obedit == ob) {
+ rg->editbones = arm->edbo;
+ }
+ else {
+ rg->editbones = MEM_callocN(sizeof(ListBase), "EditBones");
+ make_boneList(rg->editbones, &arm->bonebase, NULL, NULL);
+ rg->flag |= RIG_FREE_BONELIST;
+ }
+
+ rg->ob = ob;
+
+ /* Do the rotations */
+ for (ebone = rg->editbones->first; ebone; ebone = ebone->next) {
+ if (ebone->parent == NULL) {
+ RIG_arcFromBoneChain(rg, rg->editbones, ebone, NULL, 1);
+ }
+ }
+
+ BLI_removeDoubleNodes((BGraph *)rg, 0.001);
+
+ RIG_removeNormalNodes(rg);
+
+ RIG_removeUneededOffsets(rg);
+
+ BLI_buildAdjacencyList((BGraph *)rg);
+
+ RIG_findHead(rg);
+
+ BLI_markdownSymmetry((BGraph *)rg, (BNode *)rg->head, scene->toolsettings->skgen_symmetry_limit);
+
+ RIG_reconnectControlBones(rg); /* after symmetry, because we use levels to find best match */
+
+ if (BLI_isGraphCyclic((BGraph *)rg)) {
+ printf("armature cyclic\n");
+ }
+
+ return rg;
+}
+/************************************ GENERATING *****************************************************/
+
+#if 0
+static EditBone *add_editbonetolist(char *name, ListBase *list)
+{
+ EditBone *bone = MEM_callocN(sizeof(EditBone), "eBone");
+
+ BLI_strncpy(bone->name, name, sizeof(bone->name));
+ ED_armature_ebone_unique_name(list, bone->name, NULL);
+
+ BLI_addtail(list, bone);
+
+ bone->flag |= BONE_TIPSEL;
+ bone->weight = 1.0F;
+ bone->dist = 0.25F;
+ bone->xwidth = 0.1;
+ bone->zwidth = 0.1;
+ bone->rad_head = 0.10;
+ bone->rad_tail = 0.05;
+ bone->segments = 1;
+ bone->layer = 1; //arm->layer;
+
+ /* Bendy-Bone parameters */
+ bone->roll1 = 0.0f;
+ bone->roll2 = 0.0f;
+ bone->curveInX = 0.0f;
+ bone->curveInY = 0.0f;
+ bone->curveOutX = 0.0f;
+ bone->curveOutY = 0.0f;
+ bone->ease1 = 1.0f;
+ bone->ease2 = 1.0f;
+ bone->scaleIn = 1.0f;
+ bone->scaleOut = 1.0f;
+
+ return bone;
+}
+#endif
+
+#if 0 /* UNUSED */
+static void generateMissingArcsFromNode(RigGraph *rigg, ReebNode *node, int multi_level_limit)
+{
+ while (node->multi_level > multi_level_limit && node->link_up)
+ {
+ node = node->link_up;
+ }
+
+ while (node->multi_level < multi_level_limit && node->link_down)
+ {
+ node = node->link_down;
+ }
+
+ if (node->multi_level == multi_level_limit)
+ {
+ int i;
+
+ for (i = 0; i < node->degree; i++)
+ {
+ ReebArc *earc = node->arcs[i];
+
+ if (earc->flag == ARC_FREE && earc->head == node)
+ {
+ ReebNode *other = BIF_otherNodeFromIndex(earc, node);
+
+ earc->flag = ARC_USED;
+
+ //generateBonesForArc(rigg, earc, node, other);
+ generateMissingArcsFromNode(rigg, other, multi_level_limit);
+ }
+ }
+ }
+}
+
+static void generateMissingArcs(RigGraph *rigg)
+{
+ ReebGraph *reebg;
+ int multi_level_limit = 5;
+
+ for (reebg = rigg->link_mesh; reebg; reebg = reebg->link_up)
+ {
+ ReebArc *earc;
+
+ for (earc = reebg->arcs.first; earc; earc = earc->next)
+ {
+ if (earc->flag == ARC_USED)
+ {
+ generateMissingArcsFromNode(rigg, earc->head, multi_level_limit);
+ generateMissingArcsFromNode(rigg, earc->tail, multi_level_limit);
+ }
+ }
+ }
+}
+#endif
+
+/************************************ RETARGETTING *****************************************************/
+
+static void repositionControl(RigGraph *rigg, RigControl *ctrl, float head[3], float tail[3], float qrot[4], float resize);
+
+static void repositionTailControl(RigGraph *rigg, RigControl *ctrl);
+
+static void finalizeControl(RigGraph *rigg, RigControl *ctrl, float resize)
+{
+ if ((ctrl->flag & RIG_CTRL_DONE) == RIG_CTRL_DONE) {
+ RigControl *ctrl_child;
+
+#if 0
+ printf("CTRL: %s LINK: %s", ctrl->bone->name, ctrl->link->name);
+
+ if (ctrl->link_tail)
+ {
+ printf(" TAIL: %s", ctrl->link_tail->name);
+ }
+
+ printf("\n");
+#endif
+
+ /* if there was a tail link: apply link, recalc resize factor and qrot */
+ if (ctrl->tail_mode != TL_NONE) {
+ float *tail_vec = NULL;
+ float v1[3], v2[3], qtail[4];
+
+ if (ctrl->tail_mode == TL_TAIL) {
+ tail_vec = ctrl->link_tail->tail;
+ }
+ else if (ctrl->tail_mode == TL_HEAD) {
+ tail_vec = ctrl->link_tail->head;
+ }
+
+ sub_v3_v3v3(v1, ctrl->bone->tail, ctrl->bone->head);
+ sub_v3_v3v3(v2, tail_vec, ctrl->bone->head);
+
+ copy_v3_v3(ctrl->bone->tail, tail_vec);
+
+ rotation_between_vecs_to_quat(qtail, v1, v2);
+ mul_qt_qtqt(ctrl->qrot, qtail, ctrl->qrot);
+
+ resize = len_v3(v2) / len_v3v3(ctrl->head, ctrl->tail);
+ }
+
+ ctrl->bone->roll = rollBoneByQuat(ctrl->bone, ctrl->up_axis, ctrl->qrot);
+
+ /* Cascade to connected control bones */
+ for (ctrl_child = rigg->controls.first; ctrl_child; ctrl_child = ctrl_child->next) {
+ if (ctrl_child->link == ctrl->bone) {
+ repositionControl(rigg, ctrl_child, ctrl->bone->head, ctrl->bone->tail, ctrl->qrot, resize);
+ }
+ if (ctrl_child->link_tail == ctrl->bone) {
+ repositionTailControl(rigg, ctrl_child);
+ }
+ }
+ }
+}
+
+static void repositionTailControl(RigGraph *rigg, RigControl *ctrl)
+{
+ ctrl->flag |= RIG_CTRL_TAIL_DONE;
+
+ finalizeControl(rigg, ctrl, 1); /* resize will be recalculated anyway so we don't need it */
+}
+
+static void repositionControl(RigGraph *rigg, RigControl *ctrl, float head[3], float UNUSED(tail[3]), float qrot[4], float resize)
+{
+ float parent_offset[3], tail_offset[3];
+
+ copy_v3_v3(parent_offset, ctrl->offset);
+ mul_v3_fl(parent_offset, resize);
+ mul_qt_v3(qrot, parent_offset);
+
+ add_v3_v3v3(ctrl->bone->head, head, parent_offset);
+
+ ctrl->flag |= RIG_CTRL_HEAD_DONE;
+
+ copy_qt_qt(ctrl->qrot, qrot);
+
+ if (ctrl->tail_mode == TL_NONE) {
+ sub_v3_v3v3(tail_offset, ctrl->tail, ctrl->head);
+ mul_v3_fl(tail_offset, resize);
+ mul_qt_v3(qrot, tail_offset);
+
+ add_v3_v3v3(ctrl->bone->tail, ctrl->bone->head, tail_offset);
+
+ ctrl->flag |= RIG_CTRL_TAIL_DONE;
+ }
+
+ finalizeControl(rigg, ctrl, resize);
+}
+
+static void repositionBone(bContext *C, RigGraph *rigg, RigEdge *edge, float vec0[3], float vec1[3], float up_axis[3])
+{
+ Scene *scene = CTX_data_scene(C);
+ EditBone *bone;
+ RigControl *ctrl;
+ float qrot[4], resize;
+ float v1[3], v2[3];
+ float l1, l2;
+
+ bone = edge->bone;
+
+ sub_v3_v3v3(v1, edge->tail, edge->head);
+ sub_v3_v3v3(v2, vec1, vec0);
+
+ l1 = normalize_v3(v1);
+ l2 = normalize_v3(v2);
+
+ resize = l2 / l1;
+
+ rotation_between_vecs_to_quat(qrot, v1, v2);
+
+ copy_v3_v3(bone->head, vec0);
+ copy_v3_v3(bone->tail, vec1);
+
+ if (!is_zero_v3(up_axis)) {
+ float qroll[4];
+
+ if (scene->toolsettings->skgen_retarget_roll == SK_RETARGET_ROLL_VIEW) {
+ bone->roll = rollBoneByQuatAligned(bone, edge->up_axis, qrot, qroll, up_axis);
+ }
+ else if (scene->toolsettings->skgen_retarget_roll == SK_RETARGET_ROLL_JOINT) {
+ bone->roll = rollBoneByQuatJoint(edge, edge->prev, qrot, qroll, up_axis);
+ }
+ else {
+ unit_qt(qroll);
+ }
+
+ mul_qt_qtqt(qrot, qroll, qrot);
+ }
+ else {
+ bone->roll = rollBoneByQuat(bone, edge->up_axis, qrot);
+ }
+
+ for (ctrl = rigg->controls.first; ctrl; ctrl = ctrl->next) {
+ if (ctrl->link == bone) {
+ repositionControl(rigg, ctrl, vec0, vec1, qrot, resize);
+ }
+ if (ctrl->link_tail == bone) {
+ repositionTailControl(rigg, ctrl);
+ }
+ }
+}
+
+static RetargetMode detectArcRetargetMode(RigArc *arc);
+static void retargetArctoArcLength(bContext *C, RigGraph *rigg, RigArc *iarc, RigNode *inode_start);
+
+
+static RetargetMode detectArcRetargetMode(RigArc *iarc)
+{
+ RetargetMode mode = RETARGET_AGGRESSIVE;
+ ReebArc *earc = iarc->link_mesh;
+ RigEdge *edge;
+ int large_angle = 0;
+ float avg_angle = 0;
+ /* float avg_length = 0; */ /* UNUSED */
+ int nb_edges = 0;
+
+
+ for (edge = iarc->edges.first; edge; edge = edge->next) {
+ avg_angle += edge->angle;
+ nb_edges++;
+ }
+
+ avg_angle /= nb_edges - 1; /* -1 because last edge doesn't have an angle */
+
+ /* avg_length = iarc->length / nb_edges; */ /* UNUSED */
+
+
+ if (nb_edges > 2) {
+ for (edge = iarc->edges.first; edge; edge = edge->next) {
+ if (fabsf(edge->angle - avg_angle) > (float)(M_PI / 6)) {
+ large_angle = 1;
+ }
+ }
+ }
+ else if (nb_edges == 2 && avg_angle > 0) {
+ large_angle = 1;
+ }
+
+
+ if (large_angle == 0) {
+ mode = RETARGET_LENGTH;
+ }
+
+ if (earc->bcount <= (iarc->count - 1)) {
+ mode = RETARGET_LENGTH;
+ }
+
+ return mode;
+}
+
+#ifndef USE_THREADS
+static void printMovesNeeded(int *positions, int nb_positions)
+{
+ int moves = 0;
+ int i;
+
+ for (i = 0; i < nb_positions; i++) {
+ moves += positions[i] - (i + 1);
+ }
+
+ printf("%i moves needed\n", moves);
+}
+
+static void printPositions(int *positions, int nb_positions)
+{
+ int i;
+
+ for (i = 0; i < nb_positions; i++) {
+ printf("%i ", positions[i]);
+ }
+ printf("\n");
+}
+#endif
+
+#define MAX_COST FLT_MAX /* FIX ME */
+
+static float costDistance(BArcIterator *iter, float *vec0, float *vec1, int i0, int i1, float distance_weight)
+{
+ EmbedBucket *bucket = NULL;
+ float max_dist = 0;
+ float v1[3], v2[3], c[3];
+ float v1_inpf;
+
+ if (distance_weight > 0) {
+ sub_v3_v3v3(v1, vec0, vec1);
+
+ v1_inpf = dot_v3v3(v1, v1);
+
+ if (v1_inpf > 0) {
+ int j;
+ for (j = i0 + 1; j < i1 - 1; j++) {
+ float dist;
+
+ bucket = IT_peek(iter, j);
+
+ sub_v3_v3v3(v2, bucket->p, vec1);
+
+ cross_v3_v3v3(c, v1, v2);
+
+ dist = dot_v3v3(c, c) / v1_inpf;
+
+ max_dist = dist > max_dist ? dist : max_dist;
+ }
+
+ return distance_weight * max_dist;
+ }
+ else {
+ return MAX_COST;
+ }
+ }
+ else {
+ return 0;
+ }
+}
+
+static float costAngle(float original_angle, float vec_first[3], float vec_second[3], float angle_weight)
+{
+ if (angle_weight > 0) {
+ float current_angle;
+
+ if (!is_zero_v3(vec_first) && !is_zero_v3(vec_second)) {
+ current_angle = saacos(dot_v3v3(vec_first, vec_second));
+
+ return angle_weight * fabsf(current_angle - original_angle);
+ }
+ else {
+ return angle_weight * (float)M_PI;
+ }
+ }
+ else {
+ return 0;
+ }
+}
+
+static float costLength(float original_length, float current_length, float length_weight)
+{
+ if (current_length == 0) {
+ return MAX_COST;
+ }
+ else {
+ float length_ratio = fabsf((current_length - original_length) / original_length);
+ return length_weight * length_ratio * length_ratio;
+ }
+}
+
+#if 0
+static float calcCostLengthDistance(BArcIterator *iter, float **vec_cache, RigEdge *edge, float *vec1, float *vec2, int i1, int i2)
+{
+ float vec[3];
+ float length;
+
+ sub_v3_v3v3(vec, vec2, vec1);
+ length = normalize_v3(vec);
+
+ return costLength(edge->length, length) + costDistance(iter, vec1, vec2, i1, i2);
+}
+#endif
+
+static float calcCostAngleLengthDistance(BArcIterator *iter, float **UNUSED(vec_cache), RigEdge *edge,
+ float *vec0, float *vec1, float *vec2, int i1, int i2,
+ float angle_weight, float length_weight, float distance_weight)
+{
+ float vec_second[3], vec_first[3];
+ float length2;
+ float new_cost = 0;
+
+ sub_v3_v3v3(vec_second, vec2, vec1);
+ length2 = normalize_v3(vec_second);
+
+
+ /* Angle cost */
+ if (edge->prev) {
+ sub_v3_v3v3(vec_first, vec1, vec0);
+ normalize_v3(vec_first);
+
+ new_cost += costAngle(edge->prev->angle, vec_first, vec_second, angle_weight);
+ }
+
+ /* Length cost */
+ new_cost += costLength(edge->length, length2, length_weight);
+
+ /* Distance cost */
+ new_cost += costDistance(iter, vec1, vec2, i1, i2, distance_weight);
+
+ return new_cost;
+}
+
+static int indexMemoNode(int nb_positions, int previous, int current, int joints_left)
+{
+ return joints_left * nb_positions * nb_positions + current * nb_positions + previous;
+}
+
+static void copyMemoPositions(int *positions, MemoNode *table, int nb_positions, int joints_left)
+{
+ int previous = 0, current = 0;
+ int i = 0;
+
+ for (i = 0; joints_left > 0; joints_left--, i++) {
+ MemoNode *node;
+ node = table + indexMemoNode(nb_positions, previous, current, joints_left);
+
+ positions[i] = node->next;
+
+ previous = current;
+ current = node->next;
+ }
+}
+
+static MemoNode *solveJoints(MemoNode *table, BArcIterator *iter, float **vec_cache,
+ int nb_joints, int nb_positions, int previous, int current, RigEdge *edge,
+ int joints_left, float angle_weight, float length_weight, float distance_weight)
+{
+ MemoNode *node;
+ int index = indexMemoNode(nb_positions, previous, current, joints_left);
+
+ node = table + index;
+
+ if (node->weight != 0) {
+ return node;
+ }
+ else if (joints_left == 0) {
+ float *vec0 = vec_cache[previous];
+ float *vec1 = vec_cache[current];
+ float *vec2 = vec_cache[nb_positions + 1];
+
+ node->weight = calcCostAngleLengthDistance(iter, vec_cache, edge, vec0, vec1, vec2, current, iter->length, angle_weight, length_weight, distance_weight);
+
+ return node;
+ }
+ else {
+ MemoNode *min_node = NULL;
+ float *vec0 = vec_cache[previous];
+ float *vec1 = vec_cache[current];
+ float min_weight = 0.0f;
+ int min_next = 0;
+ int next;
+
+ for (next = current + 1; next <= nb_positions - (joints_left - 1); next++) {
+ MemoNode *next_node;
+ float *vec2 = vec_cache[next];
+ float weight = 0.0f;
+
+ /* ADD WEIGHT OF PREVIOUS - CURRENT - NEXT triple */
+ weight = calcCostAngleLengthDistance(iter, vec_cache, edge, vec0, vec1, vec2, current, next, angle_weight, length_weight, distance_weight);
+
+ if (weight >= MAX_COST) {
+ continue;
+ }
+
+ /* add node weight */
+ next_node = solveJoints(table, iter, vec_cache, nb_joints, nb_positions, current, next, edge->next, joints_left - 1, angle_weight, length_weight, distance_weight);
+ weight += next_node->weight;
+
+ if (min_node == NULL || weight < min_weight) {
+ min_weight = weight;
+ min_node = next_node;
+ min_next = next;
+ }
+ }
+
+ if (min_node) {
+ node->weight = min_weight;
+ node->next = min_next;
+ return node;
+ }
+ else {
+ node->weight = MAX_COST;
+ return node;
+ }
+ }
+
+}
+
+static int testFlipArc(RigArc *iarc, RigNode *inode_start)
+{
+ ReebArc *earc = iarc->link_mesh;
+ ReebNode *enode_start = BIF_NodeFromIndex(earc, inode_start->link_mesh);
+
+ /* no flip needed if both nodes are the same */
+ if ((enode_start == earc->head && inode_start == iarc->head) ||
+ (enode_start == earc->tail && inode_start == iarc->tail))
+ {
+ return 0;
+ }
+ else {
+ return 1;
+ }
+}
+
+static void retargetArctoArcAggresive(bContext *C, RigGraph *rigg, RigArc *iarc, RigNode *inode_start)
+{
+ ReebArcIterator arc_iter;
+ BArcIterator *iter = (BArcIterator *)&arc_iter;
+ RigEdge *edge;
+ ReebNode *node_start, *node_end;
+ ReebArc *earc = iarc->link_mesh;
+ float angle_weight = 1.0; // GET FROM CONTEXT
+ float length_weight = 1.0;
+ float distance_weight = 1.0;
+#ifndef USE_THREADS
+ float min_cost = FLT_MAX;
+#endif
+ float *vec0, *vec1;
+ int *best_positions;
+ int nb_edges = BLI_listbase_count(&iarc->edges);
+ int nb_joints = nb_edges - 1;
+ RetargetMethod method = METHOD_MEMOIZE;
+ int i;
+
+ if (nb_joints > earc->bcount) {
+ printf("NOT ENOUGH BUCKETS!\n");
+ return;
+ }
+
+ best_positions = MEM_callocN(sizeof(int) * nb_joints, "Best positions");
+
+ if (testFlipArc(iarc, inode_start)) {
+ node_start = earc->tail;
+ node_end = earc->head;
+ }
+ else {
+ node_start = earc->head;
+ node_end = earc->tail;
+ }
+
+ /* equal number of joints and potential position, just fill them in */
+ if (nb_joints == earc->bcount) {
+ /* init with first values */
+ for (i = 0; i < nb_joints; i++) {
+ best_positions[i] = i + 1;
+ }
+ }
+ if (method == METHOD_MEMOIZE) {
+ int nb_positions = earc->bcount;
+ int nb_memo_nodes = nb_positions * nb_positions * (nb_joints + 1);
+ MemoNode *table = MEM_callocN(nb_memo_nodes * sizeof(MemoNode), "memoization table");
+#ifndef USE_THREADS
+ MemoNode *result;
+#endif
+ float **positions_cache = MEM_callocN(sizeof(float *) * (nb_positions + 2), "positions cache");
+
+ positions_cache[0] = node_start->p;
+ positions_cache[nb_positions + 1] = node_end->p;
+
+ initArcIterator(iter, earc, node_start);
+
+ for (i = 1; i <= nb_positions; i++) {
+ EmbedBucket *bucket = IT_peek(iter, i);
+ positions_cache[i] = bucket->p;
+ }
+
+#ifndef USE_THREADS
+ result = solveJoints(table, iter, positions_cache, nb_joints, earc->bcount, 0, 0, iarc->edges.first, nb_joints, angle_weight, length_weight, distance_weight);
+ min_cost = result->weight;
+#else
+ solveJoints(table, iter, positions_cache, nb_joints, earc->bcount, 0, 0, iarc->edges.first, nb_joints, angle_weight, length_weight, distance_weight);
+#endif
+
+ copyMemoPositions(best_positions, table, earc->bcount, nb_joints);
+
+ MEM_freeN(table);
+ MEM_freeN(positions_cache);
+ }
+
+ vec0 = node_start->p;
+ initArcIterator(iter, earc, node_start);
+
+#ifndef USE_THREADS
+ printPositions(best_positions, nb_joints);
+ printMovesNeeded(best_positions, nb_joints);
+ printf("min_cost %f\n", min_cost);
+ printf("buckets: %i\n", earc->bcount);
+#endif
+
+ /* set joints to best position */
+ for (edge = iarc->edges.first, i = 0;
+ edge;
+ edge = edge->next, i++)
+ {
+ float *no = NULL;
+ if (i < nb_joints) {
+ EmbedBucket *bucket = IT_peek(iter, best_positions[i]);
+ vec1 = bucket->p;
+ no = bucket->no;
+ }
+ else {
+ vec1 = node_end->p;
+ no = node_end->no;
+ }
+
+ if (edge->bone) {
+ repositionBone(C, rigg, edge, vec0, vec1, no);
+ }
+
+ vec0 = vec1;
+ }
+
+ MEM_freeN(best_positions);
+}
+
+static void retargetArctoArcLength(bContext *C, RigGraph *rigg, RigArc *iarc, RigNode *inode_start)
+{
+ ReebArcIterator arc_iter;
+ BArcIterator *iter = (BArcIterator *)&arc_iter;
+ ReebArc *earc = iarc->link_mesh;
+ ReebNode *node_start, *node_end;
+ RigEdge *edge;
+ EmbedBucket *bucket = NULL;
+ float embedding_length = 0;
+ float *vec0 = NULL;
+ float *vec1 = NULL;
+ float *previous_vec = NULL;
+
+
+ if (testFlipArc(iarc, inode_start)) {
+ node_start = (ReebNode *)earc->tail;
+ node_end = (ReebNode *)earc->head;
+ }
+ else {
+ node_start = (ReebNode *)earc->head;
+ node_end = (ReebNode *)earc->tail;
+ }
+
+ initArcIterator(iter, earc, node_start);
+
+ bucket = IT_next(iter);
+
+ vec0 = node_start->p;
+
+ while (bucket != NULL) {
+ vec1 = bucket->p;
+
+ embedding_length += len_v3v3(vec0, vec1);
+
+ vec0 = vec1;
+ bucket = IT_next(iter);
+ }
+
+ embedding_length += len_v3v3(node_end->p, vec1);
+
+ /* fit bones */
+ initArcIterator(iter, earc, node_start);
+
+ bucket = IT_next(iter);
+
+ vec0 = node_start->p;
+ previous_vec = vec0;
+ vec1 = bucket->p;
+
+ for (edge = iarc->edges.first; edge; edge = edge->next) {
+ float new_bone_length = edge->length / iarc->length * embedding_length;
+ float *no = NULL;
+ float length = 0;
+
+ while (bucket && new_bone_length > length) {
+ length += len_v3v3(previous_vec, vec1);
+ bucket = IT_next(iter);
+ previous_vec = vec1;
+ vec1 = bucket->p;
+ no = bucket->no;
+ }
+
+ if (bucket == NULL) {
+ vec1 = node_end->p;
+ no = node_end->no;
+ }
+
+ /* no need to move virtual edges (space between unconnected bones) */
+ if (edge->bone) {
+ repositionBone(C, rigg, edge, vec0, vec1, no);
+ }
+
+ vec0 = vec1;
+ previous_vec = vec1;
+ }
+}
+
+static void retargetArctoArc(bContext *C, RigGraph *rigg, RigArc *iarc, RigNode *inode_start)
+{
+ RetargetParam *p = MEM_callocN(sizeof(RetargetParam), "RetargetParam");
+
+ p->rigg = rigg;
+ p->iarc = iarc;
+ p->inode_start = inode_start;
+ p->context = C;
+
+ BLI_task_pool_push(rigg->task_pool, exec_retargetArctoArc, p, true, TASK_PRIORITY_HIGH);
+}
+
+void exec_retargetArctoArc(TaskPool * __restrict UNUSED(pool), void *taskdata, int UNUSED(threadid))
+{
+ RetargetParam *p = (RetargetParam *)taskdata;
+ RigGraph *rigg = p->rigg;
+ RigArc *iarc = p->iarc;
+ bContext *C = p->context;
+ RigNode *inode_start = p->inode_start;
+ ReebArc *earc = iarc->link_mesh;
+
+ if (BLI_listbase_is_single(&iarc->edges)) {
+ RigEdge *edge = iarc->edges.first;
+
+ if (testFlipArc(iarc, inode_start)) {
+ repositionBone(C, rigg, edge, earc->tail->p, earc->head->p, earc->head->no);
+ }
+ else {
+ repositionBone(C, rigg, edge, earc->head->p, earc->tail->p, earc->tail->no);
+ }
+ }
+ else {
+ RetargetMode mode = detectArcRetargetMode(iarc);
+
+ if (mode == RETARGET_AGGRESSIVE) {
+ retargetArctoArcAggresive(C, rigg, iarc, inode_start);
+ }
+ else {
+ retargetArctoArcLength(C, rigg, iarc, inode_start);
+ }
+ }
+}
+
+static void matchMultiResolutionNode(RigGraph *rigg, RigNode *inode, ReebNode *top_node)
+{
+ ReebNode *enode = top_node;
+ ReebGraph *reebg = BIF_graphForMultiNode(rigg->link_mesh, enode);
+ int ishape, eshape;
+
+ ishape = BLI_subtreeShape((BGraph *)rigg, (BNode *)inode, NULL, 0) % SHAPE_LEVELS;
+ eshape = BLI_subtreeShape((BGraph *)reebg, (BNode *)enode, NULL, 0) % SHAPE_LEVELS;
+
+ inode->link_mesh = enode;
+
+ while (ishape == eshape && enode->link_down) {
+ inode->link_mesh = enode;
+
+ enode = enode->link_down;
+ reebg = BIF_graphForMultiNode(rigg->link_mesh, enode); /* replace with call to link_down once that exists */
+ eshape = BLI_subtreeShape((BGraph *)reebg, (BNode *)enode, NULL, 0) % SHAPE_LEVELS;
+ }
+}
+
+static void markMultiResolutionChildArc(ReebNode *end_enode, ReebNode *enode)
+{
+ int i;
+
+ for (i = 0; i < enode->degree; i++) {
+ ReebArc *earc = (ReebArc *)enode->arcs[i];
+
+ if (earc->flag == ARC_FREE) {
+ earc->flag = ARC_TAKEN;
+
+ if (earc->tail->degree > 1 && earc->tail != end_enode) {
+ markMultiResolutionChildArc(end_enode, earc->tail);
+ }
+ break;
+ }
+ }
+}
+
+static void markMultiResolutionArc(ReebArc *start_earc)
+{
+ if (start_earc->link_up) {
+ ReebArc *earc;
+ for (earc = start_earc->link_up; earc; earc = earc->link_up) {
+ earc->flag = ARC_TAKEN;
+
+ if (earc->tail->index != start_earc->tail->index) {
+ markMultiResolutionChildArc(earc->tail, earc->tail);
+ }
+ }
+ }
+}
+
+static void matchMultiResolutionArc(RigGraph *rigg, RigNode *start_node, RigArc *next_iarc, ReebArc *next_earc)
+{
+ ReebNode *enode = next_earc->head;
+ ReebGraph *reebg = BIF_graphForMultiNode(rigg->link_mesh, enode);
+ int ishape, eshape;
+
+ ishape = BLI_subtreeShape((BGraph *)rigg, (BNode *)start_node, (BArc *)next_iarc, 1) % SHAPE_LEVELS;
+ eshape = BLI_subtreeShape((BGraph *)reebg, (BNode *)enode, (BArc *)next_earc, 1) % SHAPE_LEVELS;
+
+ while (ishape != eshape && next_earc->link_up) {
+ next_earc->flag = ARC_TAKEN; // mark previous as taken, to prevent backtrack on lower levels
+
+ next_earc = next_earc->link_up;
+ reebg = reebg->link_up;
+ enode = next_earc->head;
+ eshape = BLI_subtreeShape((BGraph *)reebg, (BNode *)enode, (BArc *)next_earc, 1) % SHAPE_LEVELS;
+ }
+
+ next_earc->flag = ARC_USED;
+ next_iarc->link_mesh = next_earc;
+
+ /* mark all higher levels as taken too */
+ markMultiResolutionArc(next_earc);
+// while (next_earc->link_up)
+// {
+// next_earc = next_earc->link_up;
+// next_earc->flag = ARC_TAKEN;
+// }
+}
+
+static void matchMultiResolutionStartingNode(RigGraph *rigg, ReebGraph *reebg, RigNode *inode)
+{
+ ReebNode *enode;
+ int ishape, eshape;
+
+ enode = reebg->nodes.first;
+
+ ishape = BLI_subtreeShape((BGraph *)rigg, (BNode *)inode, NULL, 0) % SHAPE_LEVELS;
+ eshape = BLI_subtreeShape((BGraph *)rigg->link_mesh, (BNode *)enode, NULL, 0) % SHAPE_LEVELS;
+
+ while (ishape != eshape && reebg->link_up) {
+ reebg = reebg->link_up;
+
+ enode = reebg->nodes.first;
+
+ eshape = BLI_subtreeShape((BGraph *)reebg, (BNode *)enode, NULL, 0) % SHAPE_LEVELS;
+ }
+
+ inode->link_mesh = enode;
+}
+
+static void findCorrespondingArc(RigGraph *rigg, RigArc *start_arc, RigNode *start_node, RigArc *next_iarc, int root)
+{
+ ReebNode *enode = start_node->link_mesh;
+ ReebArc *next_earc;
+ int symmetry_level = next_iarc->symmetry_level;
+ int symmetry_group = next_iarc->symmetry_group;
+ int symmetry_flag = next_iarc->symmetry_flag;
+ int i;
+
+ next_iarc->link_mesh = NULL;
+
+// if (root)
+// {
+// printf("-----------------------\n");
+// printf("MATCHING LIMB\n");
+// RIG_printArcBones(next_iarc);
+// }
+
+ for (i = 0; i < enode->degree; i++) {
+ next_earc = (ReebArc *)enode->arcs[i];
+
+// if (next_earc->flag == ARC_FREE)
+// {
+// printf("candidate (level %i ?= %i) (flag %i ?= %i) (group %i ?= %i)\n",
+// symmetry_level, next_earc->symmetry_level,
+// symmetry_flag, next_earc->symmetry_flag,
+// symmetry_group, next_earc->symmetry_flag);
+// }
+
+ if (next_earc->flag == ARC_FREE &&
+ next_earc->symmetry_flag == symmetry_flag &&
+ next_earc->symmetry_group == symmetry_group &&
+ next_earc->symmetry_level == symmetry_level)
+ {
+// printf("CORRESPONDING ARC FOUND\n");
+// printf("flag %i -- level %i -- flag %i -- group %i\n", next_earc->flag, next_earc->symmetry_level, next_earc->symmetry_flag, next_earc->symmetry_group);
+
+ matchMultiResolutionArc(rigg, start_node, next_iarc, next_earc);
+ break;
+ }
+ }
+
+ /* not found, try at higher nodes (lower node might have filtered internal arcs, messing shape of tree */
+ if (next_iarc->link_mesh == NULL) {
+// printf("NO CORRESPONDING ARC FOUND - GOING TO HIGHER LEVELS\n");
+
+ if (enode->link_up) {
+ start_node->link_mesh = enode->link_up;
+ findCorrespondingArc(rigg, start_arc, start_node, next_iarc, 0);
+ }
+ }
+
+ /* still not found, print debug info */
+ if (root && next_iarc->link_mesh == NULL) {
+ start_node->link_mesh = enode; /* linking back with root node */
+
+// printf("NO CORRESPONDING ARC FOUND\n");
+// RIG_printArcBones(next_iarc);
+//
+// printf("ON NODE %i, multilevel %i\n", enode->index, enode->multi_level);
+//
+// printf("LOOKING FOR\n");
+// printf("flag %i -- level %i -- flag %i -- group %i\n", ARC_FREE, symmetry_level, symmetry_flag, symmetry_group);
+//
+// printf("CANDIDATES\n");
+// for (i = 0; i < enode->degree; i++)
+// {
+// next_earc = (ReebArc *)enode->arcs[i];
+// printf("flag %i -- level %i -- flag %i -- group %i\n", next_earc->flag, next_earc->symmetry_level, next_earc->symmetry_flag, next_earc->symmetry_group);
+// }
+
+ /* Emergency matching */
+ for (i = 0; i < enode->degree; i++) {
+ next_earc = (ReebArc *)enode->arcs[i];
+
+ if (next_earc->flag == ARC_FREE && next_earc->symmetry_level == symmetry_level) {
+// printf("USING:\n");
+// printf("flag %i -- level %i -- flag %i -- group %i\n", next_earc->flag, next_earc->symmetry_level, next_earc->symmetry_flag, next_earc->symmetry_group);
+ matchMultiResolutionArc(rigg, start_node, next_iarc, next_earc);
+ break;
+ }
+ }
+ }
+
+}
+
+static void retargetSubgraph(bContext *C, RigGraph *rigg, RigArc *start_arc, RigNode *start_node)
+{
+ RigNode *inode = start_node;
+ int i;
+
+ /* no start arc on first node */
+ if (start_arc) {
+ ReebNode *enode = start_node->link_mesh;
+ ReebArc *earc = start_arc->link_mesh;
+
+ retargetArctoArc(C, rigg, start_arc, start_node);
+
+ enode = BIF_otherNodeFromIndex(earc, enode);
+ inode = (RigNode *)BLI_otherNode((BArc *)start_arc, (BNode *)inode);
+
+ /* match with lowest node with correct shape */
+ matchMultiResolutionNode(rigg, inode, enode);
+ }
+
+ for (i = 0; i < inode->degree; i++) {
+ RigArc *next_iarc = (RigArc *)inode->arcs[i];
+
+ /* no back tracking */
+ if (next_iarc != start_arc) {
+ findCorrespondingArc(rigg, start_arc, inode, next_iarc, 1);
+ if (next_iarc->link_mesh) {
+ retargetSubgraph(C, rigg, next_iarc, inode);
+ }
+ }
+ }
+}
+
+static void finishRetarget(RigGraph *rigg)
+{
+ BLI_task_pool_work_and_wait(rigg->task_pool);
+}
+
+static void adjustGraphs(bContext *C, RigGraph *rigg)
+{
+ Main *bmain = CTX_data_main(C);
+ bArmature *arm = rigg->ob->data;
+ RigArc *arc;
+
+ for (arc = rigg->arcs.first; arc; arc = arc->next) {
+ if (arc->link_mesh) {
+ retargetArctoArc(C, rigg, arc, arc->head);
+ }
+ }
+
+ finishRetarget(rigg);
+
+ /* Turn the list into an armature */
+ arm->edbo = rigg->editbones;
+ ED_armature_from_edit(bmain, arm);
+
+ ED_undo_push(C, "Retarget Skeleton");
+}
+
+static void retargetGraphs(bContext *C, RigGraph *rigg)
+{
+ Main *bmain = CTX_data_main(C);
+ bArmature *arm = rigg->ob->data;
+ ReebGraph *reebg = rigg->link_mesh;
+ RigNode *inode;
+
+ /* flag all ReebArcs as free */
+ BIF_flagMultiArcs(reebg, ARC_FREE);
+
+ /* return to first level */
+ inode = rigg->head;
+
+ matchMultiResolutionStartingNode(rigg, reebg, inode);
+
+ retargetSubgraph(C, rigg, NULL, inode);
+
+ //generateMissingArcs(rigg);
+
+ finishRetarget(rigg);
+
+ /* Turn the list into an armature */
+ arm->edbo = rigg->editbones;
+ ED_armature_from_edit(bmain, arm);
+}
+
+const char *RIG_nameBone(RigGraph *rg, int arc_index, int bone_index)
+{
+ RigArc *arc = BLI_findlink(&rg->arcs, arc_index);
+ RigEdge *iedge;
+
+ if (arc == NULL) {
+ return "None";
+ }
+
+ if (bone_index == BLI_listbase_count(&arc->edges)) {
+ return "Last joint";
+ }
+
+ iedge = BLI_findlink(&arc->edges, bone_index);
+
+ if (iedge == NULL) {
+ return "Done";
+ }
+
+ if (iedge->bone == NULL) {
+ return "Bone offset";
+ }
+
+ return iedge->bone->name;
+}
+
+int RIG_nbJoints(RigGraph *rg)
+{
+ RigArc *arc;
+ int total = 0;
+
+ total += BLI_listbase_count(&rg->nodes);
+
+ for (arc = rg->arcs.first; arc; arc = arc->next) {
+ total += BLI_listbase_count(&arc->edges) - 1; /* -1 because end nodes are already counted */
+ }
+
+ return total;
+}
+
+static void BIF_freeRetarget(void)
+{
+ if (GLOBAL_RIGG) {
+ RIG_freeRigGraph((BGraph *)GLOBAL_RIGG);
+ GLOBAL_RIGG = NULL;
+ }
+}
+
+void BIF_retargetArmature(bContext *C)
+{
+ ReebGraph *reebg;
+ double start_time, end_time;
+ double gstart_time, gend_time;
+ double reeb_time, rig_time = 0.0, retarget_time = 0.0, total_time;
+
+ gstart_time = start_time = PIL_check_seconds_timer();
+
+ reebg = BIF_ReebGraphMultiFromEditMesh(C);
+
+ end_time = PIL_check_seconds_timer();
+ reeb_time = end_time - start_time;
+
+ printf("Reeb Graph created\n");
+
+ CTX_DATA_BEGIN (C, Base *, base, selected_editable_bases)
+ {
+ Object *ob = base->object;
+
+ if (ob->type == OB_ARMATURE) {
+ RigGraph *rigg;
+ bArmature *arm;
+
+ arm = ob->data;
+
+ /* Put the armature into editmode */
+
+
+ start_time = PIL_check_seconds_timer();
+
+ rigg = RIG_graphFromArmature(C, ob, arm);
+
+ end_time = PIL_check_seconds_timer();
+ rig_time = end_time - start_time;
+
+ printf("Armature graph created\n");
+
+ //RIG_printGraph(rigg);
+
+ rigg->link_mesh = reebg;
+
+ printf("retargetting %s\n", ob->id.name);
+
+ start_time = PIL_check_seconds_timer();
+
+ retargetGraphs(C, rigg);
+
+ end_time = PIL_check_seconds_timer();
+ retarget_time = end_time - start_time;
+
+ BIF_freeRetarget();
+
+ GLOBAL_RIGG = rigg;
+
+ break; /* only one armature at a time */
+ }
+ }
+ CTX_DATA_END;
+
+
+ gend_time = PIL_check_seconds_timer();
+
+ total_time = gend_time - gstart_time;
+
+ printf("-----------\n");
+ printf("runtime: \t%.3f\n", total_time);
+ printf("reeb: \t\t%.3f (%.1f%%)\n", reeb_time, reeb_time / total_time * 100);
+ printf("rig: \t\t%.3f (%.1f%%)\n", rig_time, rig_time / total_time * 100);
+ printf("retarget: \t%.3f (%.1f%%)\n", retarget_time, retarget_time / total_time * 100);
+ printf("-----------\n");
+
+ ED_undo_push(C, "Retarget Skeleton");
+
+ // XXX
+// allqueue(REDRAWVIEW3D, 0);
+}
+
+void BIF_retargetArc(bContext *C, ReebArc *earc, RigGraph *template_rigg)
+{
+ Object *obedit = CTX_data_edit_object(C);
+ Scene *scene = CTX_data_scene(C);
+ bArmature *armedit = obedit->data;
+ Object *ob;
+ RigGraph *rigg;
+ RigArc *iarc;
+ char *side_string = scene->toolsettings->skgen_side_string;
+ char *num_string = scene->toolsettings->skgen_num_string;
+ int free_template = 0;
+
+ if (template_rigg) {
+ ob = template_rigg->ob;
+ }
+ else {
+ free_template = 1;
+ ob = obedit;
+ template_rigg = armatureSelectedToGraph(C, ob, ob->data);
+ }
+
+ if (BLI_listbase_is_empty(&template_rigg->arcs)) {
+// XXX
+// error("No Template and no deforming bones selected");
+ return;
+ }
+
+ rigg = cloneRigGraph(template_rigg, armedit->edbo, obedit, side_string, num_string);
+
+ iarc = rigg->arcs.first;
+
+ iarc->link_mesh = earc;
+ iarc->head->link_mesh = earc->head;
+ iarc->tail->link_mesh = earc->tail;
+
+ retargetArctoArc(C, rigg, iarc, iarc->head);
+
+ finishRetarget(rigg);
+
+ /* free template if it comes from the edit armature */
+ if (free_template) {
+ RIG_freeRigGraph((BGraph *)template_rigg);
+ }
+ RIG_freeRigGraph((BGraph *)rigg);
+
+ ED_armature_edit_validate_active(armedit);
+
+// XXX
+// allqueue(REDRAWVIEW3D, 0);
+}
+
+void BIF_adjustRetarget(bContext *C)
+{
+ if (GLOBAL_RIGG) {
+ adjustGraphs(C, GLOBAL_RIGG);
+ }
+}
diff --git a/source/blender/editors/armature/meshlaplacian.c b/source/blender/editors/armature/meshlaplacian.c
index bc6d776911a..1f01def5133 100644
--- a/source/blender/editors/armature/meshlaplacian.c
+++ b/source/blender/editors/armature/meshlaplacian.c
@@ -42,6 +42,7 @@
#include "BKE_DerivedMesh.h"
#include "BKE_modifier.h"
#include "BKE_mesh.h"
+#include "BKE_mesh_runtime.h"
#include "ED_mesh.h"
#include "ED_armature.h"
diff --git a/source/blender/editors/armature/pose_edit.c b/source/blender/editors/armature/pose_edit.c
index fa9927419a0..ffe64cc24b0 100644
--- a/source/blender/editors/armature/pose_edit.c
+++ b/source/blender/editors/armature/pose_edit.c
@@ -46,6 +46,7 @@
#include "BKE_armature.h"
#include "BKE_context.h"
#include "BKE_deform.h"
+#include "BKE_main.h"
#include "BKE_object.h"
#include "BKE_report.h"
#include "BKE_layer.h"
@@ -622,6 +623,7 @@ static void pose_copy_menu(Scene *scene)
static int pose_flip_names_exec(bContext *C, wmOperator *op)
{
+ Main *bmain = CTX_data_main(C);
ViewLayer *view_layer = CTX_data_view_layer(C);
const bool do_strip_numbers = RNA_boolean_get(op->ptr, "do_strip_numbers");
@@ -636,7 +638,7 @@ static int pose_flip_names_exec(bContext *C, wmOperator *op)
}
FOREACH_PCHAN_SELECTED_IN_OBJECT_END;
- ED_armature_bones_flip_names(arm, &bones_names, do_strip_numbers);
+ ED_armature_bones_flip_names(bmain, arm, &bones_names, do_strip_numbers);
BLI_freelistN(&bones_names);
@@ -674,6 +676,7 @@ void POSE_OT_flip_names(wmOperatorType *ot)
static int pose_autoside_names_exec(bContext *C, wmOperator *op)
{
+ Main *bmain = CTX_data_main(C);
Object *ob = BKE_object_pose_armature_get(CTX_data_active_object(C));
bArmature *arm;
char newname[MAXBONENAME];
@@ -689,7 +692,7 @@ static int pose_autoside_names_exec(bContext *C, wmOperator *op)
{
BLI_strncpy(newname, pchan->name, sizeof(newname));
if (bone_autoside_name(newname, 1, axis, pchan->bone->head[axis], pchan->bone->tail[axis]))
- ED_armature_bone_rename(arm, pchan->name, newname);
+ ED_armature_bone_rename(bmain, arm, pchan->name, newname);
}
CTX_DATA_END;
diff --git a/source/blender/editors/armature/pose_lib.c b/source/blender/editors/armature/pose_lib.c
index 02a1e22dbba..b9c4584ff15 100644
--- a/source/blender/editors/armature/pose_lib.c
+++ b/source/blender/editors/armature/pose_lib.c
@@ -48,6 +48,7 @@
#include "BKE_armature.h"
#include "BKE_global.h"
#include "BKE_idprop.h"
+#include "BKE_main.h"
#include "BKE_library.h"
#include "BKE_object.h"
@@ -191,7 +192,7 @@ static int has_poselib_pose_data_for_editing_poll(bContext *C)
/* ----------------------------------- */
/* Initialize a new poselib (whether it is needed or not) */
-static bAction *poselib_init_new(Object *ob)
+static bAction *poselib_init_new(Main *bmain, Object *ob)
{
/* sanity checks - only for armatures */
if (ELEM(NULL, ob, ob->pose))
@@ -201,19 +202,19 @@ static bAction *poselib_init_new(Object *ob)
if (ob->poselib)
id_us_min(&ob->poselib->id);
- ob->poselib = BKE_action_add(G.main, "PoseLib");
+ ob->poselib = BKE_action_add(bmain, "PoseLib");
ob->poselib->idroot = ID_OB;
return ob->poselib;
}
/* Initialize a new poselib (checks if that needs to happen) */
-static bAction *poselib_validate(Object *ob)
+static bAction *poselib_validate(Main *bmain, Object *ob)
{
if (ELEM(NULL, ob, ob->pose))
return NULL;
else if (ob->poselib == NULL)
- return poselib_init_new(ob);
+ return poselib_init_new(bmain, ob);
else
return ob->poselib;
}
@@ -223,6 +224,7 @@ static bAction *poselib_validate(Object *ob)
static int poselib_new_exec(bContext *C, wmOperator *UNUSED(op))
{
+ Main *bmain = CTX_data_main(C);
Object *ob = get_poselib_object(C);
/* sanity checks */
@@ -230,7 +232,7 @@ static int poselib_new_exec(bContext *C, wmOperator *UNUSED(op))
return OPERATOR_CANCELLED;
/* new method here deals with the rest... */
- poselib_init_new(ob);
+ poselib_init_new(bmain, ob);
/* notifier here might evolve? */
WM_event_add_notifier(C, NC_OBJECT | ND_POSE, NULL);
@@ -458,8 +460,9 @@ static int poselib_add_menu_invoke(bContext *C, wmOperator *op, const wmEvent *U
static int poselib_add_exec(bContext *C, wmOperator *op)
{
+ Main *bmain = CTX_data_main(C);
Object *ob = get_poselib_object(C);
- bAction *act = poselib_validate(ob);
+ bAction *act = poselib_validate(bmain, ob);
bPose *pose = (ob) ? ob->pose : NULL;
TimeMarker *marker;
KeyingSet *ks;
diff --git a/source/blender/editors/armature/pose_transform.c b/source/blender/editors/armature/pose_transform.c
index de0612d840d..22c710dcda5 100644
--- a/source/blender/editors/armature/pose_transform.c
+++ b/source/blender/editors/armature/pose_transform.c
@@ -97,6 +97,7 @@ static void applyarmature_fix_boneparents(const bContext *C, Scene *scene, Objec
/* set the current pose as the restpose */
static int apply_armature_pose2bones_exec(bContext *C, wmOperator *op)
{
+ Main *bmain = CTX_data_main(C);
Depsgraph *depsgraph = CTX_data_depsgraph(C);
Scene *scene = CTX_data_scene(C);
Object *ob = BKE_object_pose_armature_get(CTX_data_active_object(C)); // must be active object, not edit-object
@@ -195,7 +196,7 @@ static int apply_armature_pose2bones_exec(bContext *C, wmOperator *op)
}
/* convert editbones back to bones, and then free the edit-data */
- ED_armature_from_edit(arm);
+ ED_armature_from_edit(bmain, arm);
ED_armature_edit_free(arm);
/* flush positions of posebones */
diff --git a/source/blender/editors/curve/editcurve.c b/source/blender/editors/curve/editcurve.c
index ab6586d2ab6..616017dac0a 100644
--- a/source/blender/editors/curve/editcurve.c
+++ b/source/blender/editors/curve/editcurve.c
@@ -1105,7 +1105,7 @@ static int *initialize_index_map(Object *obedit, int *r_old_totvert)
return old_to_new_map;
}
-static void remap_hooks_and_vertex_parents(Object *obedit)
+static void remap_hooks_and_vertex_parents(Main *bmain, Object *obedit)
{
Object *object;
Curve *curve = (Curve *) obedit->data;
@@ -1121,7 +1121,7 @@ static void remap_hooks_and_vertex_parents(Object *obedit)
return;
}
- for (object = G.main->object.first; object; object = object->id.next) {
+ for (object = bmain->object.first; object; object = object->id.next) {
ModifierData *md;
int index;
if ((object->parent) &&
@@ -1184,7 +1184,7 @@ static void remap_hooks_and_vertex_parents(Object *obedit)
}
/* load editNurb in object */
-void ED_curve_editnurb_load(Object *obedit)
+void ED_curve_editnurb_load(Main *bmain, Object *obedit)
{
ListBase *editnurb = object_editcurve_get(obedit);
@@ -1195,7 +1195,7 @@ void ED_curve_editnurb_load(Object *obedit)
Nurb *nu, *newnu;
ListBase newnurb = {NULL, NULL}, oldnurb = cu->nurb;
- remap_hooks_and_vertex_parents(obedit);
+ remap_hooks_and_vertex_parents(bmain, obedit);
for (nu = editnurb->first; nu; nu = nu->next) {
newnu = BKE_nurb_duplicate(nu);
@@ -1325,7 +1325,7 @@ static int separate_exec(bContext *C, wmOperator *op)
BLI_movelisttolist(&newedit->nurbs, &newnurb);
/* 4. put old object out of editmode and delete separated geometry */
- ED_curve_editnurb_load(newob);
+ ED_curve_editnurb_load(bmain, newob);
ED_curve_editnurb_free(newob);
curve_delete_segments(oldob, true);
@@ -5026,7 +5026,7 @@ static int add_vertex_invoke(bContext *C, wmOperator *op, const wmEvent *event)
const float mval[2] = {UNPACK2(event->mval)};
struct SnapObjectContext *snap_context = ED_transform_snap_object_context_create_view3d(
- vc.scene, CTX_data_depsgraph(C), 0, vc.ar, vc.v3d);
+ vc.bmain, vc.scene, vc.depsgraph, 0, vc.ar, vc.v3d);
ED_transform_snap_object_project_view3d(
snap_context,
diff --git a/source/blender/editors/curve/editcurve_paint.c b/source/blender/editors/curve/editcurve_paint.c
index e6f5f82f96a..887f3dd13da 100644
--- a/source/blender/editors/curve/editcurve_paint.c
+++ b/source/blender/editors/curve/editcurve_paint.c
@@ -34,6 +34,7 @@
#include "BKE_context.h"
#include "BKE_curve.h"
#include "BKE_fcurve.h"
+#include "BKE_main.h"
#include "BKE_report.h"
#include "DEG_depsgraph.h"
@@ -616,6 +617,7 @@ static bool curve_draw_init(bContext *C, wmOperator *op, bool is_invoke)
}
}
else {
+ cdd->vc.bmain = CTX_data_main(C);
cdd->vc.depsgraph = CTX_data_depsgraph(C);
cdd->vc.scene = CTX_data_scene(C);
cdd->vc.view_layer = CTX_data_view_layer(C);
diff --git a/source/blender/editors/gpencil/gpencil_convert.c b/source/blender/editors/gpencil/gpencil_convert.c
index 72331d9e588..dfaa1420d68 100644
--- a/source/blender/editors/gpencil/gpencil_convert.c
+++ b/source/blender/editors/gpencil/gpencil_convert.c
@@ -66,6 +66,7 @@
#include "BKE_gpencil.h"
#include "BKE_layer.h"
#include "BKE_library.h"
+#include "BKE_main.h"
#include "BKE_object.h"
#include "BKE_report.h"
#include "BKE_scene.h"
@@ -456,6 +457,7 @@ static void gp_stroke_path_animation_add_keyframes(Depsgraph *depsgraph, ReportL
static void gp_stroke_path_animation(bContext *C, ReportList *reports, Curve *cu, tGpTimingData *gtd)
{
Depsgraph *depsgraph = CTX_data_depsgraph(C);
+ Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
bAction *act;
FCurve *fcu;
@@ -479,7 +481,7 @@ static void gp_stroke_path_animation(bContext *C, ReportList *reports, Curve *cu
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);
+ act = verify_adt_action(bmain, (ID *)cu, true);
fcu = verify_fcurve(act, NULL, &ptr, "eval_time", 0, true);
if (G.debug & G_DEBUG) {
diff --git a/source/blender/editors/gpencil/gpencil_edit.c b/source/blender/editors/gpencil/gpencil_edit.c
index 9f01c1d0cd7..45caadf3742 100644
--- a/source/blender/editors/gpencil/gpencil_edit.c
+++ b/source/blender/editors/gpencil/gpencil_edit.c
@@ -57,6 +57,7 @@
#include "BKE_context.h"
#include "BKE_gpencil.h"
#include "BKE_library.h"
+#include "BKE_main.h"
#include "BKE_report.h"
#include "BKE_screen.h"
diff --git a/source/blender/editors/gpencil/gpencil_paint.c b/source/blender/editors/gpencil/gpencil_paint.c
index c28d80a801f..437d5cef6f8 100644
--- a/source/blender/editors/gpencil/gpencil_paint.c
+++ b/source/blender/editors/gpencil/gpencil_paint.c
@@ -46,14 +46,15 @@
#include "PIL_time.h"
-#include "BKE_paint.h"
-#include "BKE_gpencil.h"
+#include "BKE_colortools.h"
#include "BKE_context.h"
#include "BKE_global.h"
+#include "BKE_gpencil.h"
+#include "BKE_main.h"
+#include "BKE_paint.h"
#include "BKE_report.h"
#include "BKE_screen.h"
#include "BKE_tracking.h"
-#include "BKE_colortools.h"
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
@@ -115,6 +116,7 @@ typedef enum eGPencil_PaintFlags {
* "p" = op->customdata
*/
typedef struct tGPsdata {
+ Main *bmain;
Scene *scene; /* current scene from context */
struct Depsgraph *depsgraph;
@@ -1399,6 +1401,7 @@ static bool gp_session_initdata(bContext *C, tGPsdata *p)
}
/* pass on current scene and window */
+ p->bmain = CTX_data_main(C);
p->scene = CTX_data_scene(C);
p->depsgraph = CTX_data_depsgraph(C);
p->win = CTX_wm_window(C);
@@ -2511,7 +2514,7 @@ static int gpencil_draw_modal(bContext *C, wmOperator *op, const wmEvent *event)
* (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) && (event->val != KM_NOTHING)) {
+ if (ELEM(event->type, LEFTMOUSE, RIGHTMOUSE) && (ELEM(event->val, KM_PRESS, KM_RELEASE))) {
/* if painting, end stroke */
if (p->status == GP_STATUS_PAINTING) {
int sketch = 0;
@@ -2657,7 +2660,7 @@ static int gpencil_draw_modal(bContext *C, wmOperator *op, const wmEvent *event)
estate = OPERATOR_FINISHED;
}
}
- else {
+ else if (event->val == KM_RELEASE) {
p->status = GP_STATUS_IDLING;
op->flag |= OP_IS_MODAL_CURSOR_REGION;
}
diff --git a/source/blender/editors/gpencil/gpencil_utils.c b/source/blender/editors/gpencil/gpencil_utils.c
index 861fdcac080..f6d72d9e575 100644
--- a/source/blender/editors/gpencil/gpencil_utils.c
+++ b/source/blender/editors/gpencil/gpencil_utils.c
@@ -47,10 +47,11 @@
#include "DNA_space_types.h"
#include "DNA_view3d_types.h"
+#include "BKE_action.h"
#include "BKE_context.h"
#include "BKE_gpencil.h"
+#include "BKE_main.h"
#include "BKE_tracking.h"
-#include "BKE_action.h"
#include "WM_api.h"
diff --git a/source/blender/editors/include/ED_anim_api.h b/source/blender/editors/include/ED_anim_api.h
index 045d4281585..943191c8892 100644
--- a/source/blender/editors/include/ED_anim_api.h
+++ b/source/blender/editors/include/ED_anim_api.h
@@ -36,6 +36,7 @@ struct ListBase;
struct AnimData;
struct bContext;
+struct Main;
struct wmKeyConfig;
struct ReportList;
struct ScrArea;
@@ -82,6 +83,7 @@ typedef struct bAnimContext {
struct bDopeSheet *ads; /* dopesheet data for editor (or which is being used) */
struct Depsgraph *depsgraph; /* active dependency graph */
+ struct Main *bmain; /* Current Main */
struct Scene *scene; /* active scene */
struct ViewLayer *view_layer; /* active scene layer */
struct Object *obact; /* active object */
@@ -682,7 +684,7 @@ float ANIM_unit_mapping_get_factor(struct Scene *scene, struct ID *id, struct FC
/* --------- anim_deps.c, animation updates -------- */
void ANIM_id_update(struct Scene *scene, struct ID *id);
-void ANIM_list_elem_update(struct Scene *scene, bAnimListElem *ale);
+void ANIM_list_elem_update(struct Main *bmain, struct Scene *scene, bAnimListElem *ale);
/* data -> channels syncing */
void ANIM_sync_animchannels_to_data(const struct bContext *C);
diff --git a/source/blender/editors/include/ED_armature.h b/source/blender/editors/include/ED_armature.h
index 60374f87955..cb422c2fb95 100644
--- a/source/blender/editors/include/ED_armature.h
+++ b/source/blender/editors/include/ED_armature.h
@@ -42,6 +42,7 @@ struct bPoseChannel;
struct Depsgraph;
struct IDProperty;
struct ListBase;
+struct Main;
struct MeshDeformModifierData;
struct Mesh;
struct Object;
@@ -135,7 +136,7 @@ void ED_operatormacros_armature(void);
void ED_keymap_armature(struct wmKeyConfig *keyconf);
/* editarmature.c */
-void ED_armature_from_edit(struct bArmature *arm);
+void ED_armature_from_edit(struct Main *bmain, struct bArmature *arm);
void ED_armature_to_edit(struct bArmature *arm);
void ED_armature_edit_free(struct bArmature *arm);
@@ -181,11 +182,11 @@ void ED_armature_ebone_from_mat3(EditBone *ebone, float mat[3][3]);
void ED_armature_ebone_from_mat4(EditBone *ebone, float mat[4][4]);
void ED_armature_edit_transform_mirror_update(struct Object *obedit);
-void ED_armature_origin_set(struct Object *ob, float cursor[3], int centermode, int around);
+void ED_armature_origin_set(struct Main *bmain, struct Object *ob, float cursor[3], int centermode, int around);
void ED_armature_transform_bones(struct bArmature *arm, float mat[4][4], const bool do_props);
-void ED_armature_transform_apply(struct Object *ob, float mat[4][4], const bool do_props);
-void ED_armature_transform(struct bArmature *arm, float mat[4][4], const bool do_props);
+void ED_armature_transform_apply(struct Main *bmain, struct Object *ob, float mat[4][4], const bool do_props);
+void ED_armature_transform(struct Main *bmain, struct bArmature *arm, float mat[4][4], const bool do_props);
#define ARM_GROUPS_NAME 1
#define ARM_GROUPS_ENVELOPE 2
@@ -197,8 +198,8 @@ void ED_object_vgroup_calc_from_armature(
/* if bone is already in list, pass it as param to ignore it */
void ED_armature_ebone_unique_name(struct ListBase *ebones, char *name, EditBone *bone);
-void ED_armature_bone_rename(struct bArmature *arm, const char *oldnamep, const char *newnamep);
-void ED_armature_bones_flip_names(struct bArmature *arm, struct ListBase *bones_names, const bool do_strip_numbers);
+void ED_armature_bone_rename(struct Main *bmain, struct bArmature *arm, const char *oldnamep, const char *newnamep);
+void ED_armature_bones_flip_names(struct Main *bmain, struct bArmature *arm, struct ListBase *bones_names, const bool do_strip_numbers);
/* low level selection functions which handle */
int ED_armature_ebone_selectflag_get(const EditBone *ebone);
diff --git a/source/blender/editors/include/ED_curve.h b/source/blender/editors/include/ED_curve.h
index 74c8334322f..8fcfb4743d5 100644
--- a/source/blender/editors/include/ED_curve.h
+++ b/source/blender/editors/include/ED_curve.h
@@ -32,15 +32,16 @@
#define __ED_CURVE_H__
struct bContext;
+struct BezTriple;
+struct BPoint;
+struct Curve;
+struct EditNurb;
+struct Main;
struct Nurb;
struct Object;
struct Text;
struct wmOperator;
struct wmKeyConfig;
-struct Curve;
-struct EditNurb;
-struct BezTriple;
-struct BPoint;
struct UndoType;
/* curve_ops.c */
@@ -51,7 +52,7 @@ void ED_keymap_curve(struct wmKeyConfig *keyconf);
/* editcurve.c */
struct ListBase *object_editcurve_get(struct Object *ob);
-void ED_curve_editnurb_load(struct Object *obedit);
+void ED_curve_editnurb_load(struct Main *bmain, struct Object *obedit);
void ED_curve_editnurb_make(struct Object *obedit);
void ED_curve_editnurb_free(struct Object *obedit);
diff --git a/source/blender/editors/include/ED_keyframing.h b/source/blender/editors/include/ED_keyframing.h
index 9c33f835b74..5882c44a9b3 100644
--- a/source/blender/editors/include/ED_keyframing.h
+++ b/source/blender/editors/include/ED_keyframing.h
@@ -71,7 +71,7 @@ short ANIM_get_keyframing_flags(struct Scene *scene, short incl_mode);
/* Get (or add relevant data to be able to do so) the Active Action for the given
* Animation Data block, given an ID block where the Animation Data should reside.
*/
-struct bAction *verify_adt_action(struct ID *id, short add);
+struct bAction *verify_adt_action(struct Main *bmain, struct ID *id, short add);
/* Get (or add relevant data to be able to do so) F-Curve from the given Action.
* This assumes that all the destinations are valid.
@@ -117,7 +117,9 @@ bool insert_keyframe_direct(struct Depsgraph *depsgraph, struct ReportList *repo
* Use this to create any necessary animation data, and then insert a keyframe
* using the current value being keyframed, in the relevant place. Returns success.
*/
-short insert_keyframe(struct Depsgraph *depsgraph, struct ReportList *reports, struct ID *id, struct bAction *act, const char group[], const char rna_path[], int array_index, float cfra, eBezTriple_KeyframeType keytype, eInsertKeyFlags flag);
+short insert_keyframe(
+ struct Main *bmain, struct Depsgraph *depsgraph, struct ReportList *reports, struct ID *id, struct bAction *act,
+ const char group[], const char rna_path[], int array_index, float cfra, eBezTriple_KeyframeType keytype, eInsertKeyFlags flag);
/* Main Keyframing API call:
* Use this to delete keyframe on current frame for relevant channel. Will perform checks just in case.
diff --git a/source/blender/editors/include/ED_object.h b/source/blender/editors/include/ED_object.h
index c793c0aad2b..71b713da0d0 100644
--- a/source/blender/editors/include/ED_object.h
+++ b/source/blender/editors/include/ED_object.h
@@ -126,7 +126,7 @@ enum {
EM_NO_CONTEXT = (1 << 4),
};
bool ED_object_editmode_exit_ex(
- struct Scene *scene, struct Object *obedit, int flag);
+ struct Main *bmain, struct Scene *scene, struct Object *obedit, int flag);
bool ED_object_editmode_exit(struct bContext *C, int flag);
bool ED_object_editmode_enter_ex(struct Main *bmain, struct Scene *scene, struct Object *ob, int flag);
@@ -151,7 +151,7 @@ void ED_object_wpaintmode_exit_ex(struct Object *ob);
void ED_object_wpaintmode_exit(struct bContext *C);
void ED_object_sculptmode_enter_ex(
- struct Depsgraph *depsgraph,
+ struct Main *bmain, struct Depsgraph *depsgraph,
struct Scene *scene, struct Object *ob,
struct ReportList *reports);
void ED_object_sculptmode_enter(struct bContext *C, struct ReportList *reports);
diff --git a/source/blender/editors/include/ED_screen.h b/source/blender/editors/include/ED_screen.h
index 63485800a9b..cd1fb1f91d8 100644
--- a/source/blender/editors/include/ED_screen.h
+++ b/source/blender/editors/include/ED_screen.h
@@ -160,7 +160,7 @@ ScrArea *ED_screen_areas_iter_next(const bScreen *screen, const ScrArea *area);
vert_name = (vert_name == (win)->global_areas.vertbase.last) ? (screen)->vertbase.first : vert_name->next)
/* screens */
-void ED_screens_initialize(struct wmWindowManager *wm);
+void ED_screens_initialize(struct Main *bmain, struct wmWindowManager *wm);
void ED_screen_draw_edges(struct wmWindow *win);
void ED_screen_draw_join_shape(struct ScrArea *sa1, struct ScrArea *sa2);
void ED_screen_draw_split_preview(struct ScrArea *sa, const int dir, const float fac);
@@ -211,10 +211,12 @@ void ED_workspace_view_layer_unset(
const struct Main *bmain, struct Scene *scene,
const ViewLayer *layer_unset, ViewLayer *layer_new) ATTR_NONNULL(1, 2);
struct WorkSpaceLayout *ED_workspace_layout_add(
+ struct Main *bmain,
struct WorkSpace *workspace,
struct wmWindow *win,
const char *name) ATTR_NONNULL();
struct WorkSpaceLayout *ED_workspace_layout_duplicate(
+ struct Main *bmain,
struct WorkSpace *workspace, const struct WorkSpaceLayout *layout_old,
struct wmWindow *win) ATTR_NONNULL();
bool ED_workspace_layout_delete(
diff --git a/source/blender/editors/include/ED_transform_snap_object_context.h b/source/blender/editors/include/ED_transform_snap_object_context.h
index 18d5101ebf7..8ac7dfcf9d8 100644
--- a/source/blender/editors/include/ED_transform_snap_object_context.h
+++ b/source/blender/editors/include/ED_transform_snap_object_context.h
@@ -79,9 +79,9 @@ struct SnapObjectParams {
typedef struct SnapObjectContext SnapObjectContext;
SnapObjectContext *ED_transform_snap_object_context_create(
- struct Scene *scene, struct Depsgraph *depsgraph, int flag);
+ struct Main *bmain, struct Scene *scene, struct Depsgraph *depsgraph, int flag);
SnapObjectContext *ED_transform_snap_object_context_create_view3d(
- struct Scene *scene, struct Depsgraph *depsgraph, int flag,
+ struct Main *bmain, struct Scene *scene, struct Depsgraph *depsgraph, int flag,
/* extra args for view3d */
const struct ARegion *ar, const struct View3D *v3d);
void ED_transform_snap_object_context_destroy(SnapObjectContext *sctx);
diff --git a/source/blender/editors/include/ED_view3d.h b/source/blender/editors/include/ED_view3d.h
index f00982d4102..24e5b3e2662 100644
--- a/source/blender/editors/include/ED_view3d.h
+++ b/source/blender/editors/include/ED_view3d.h
@@ -75,6 +75,7 @@ enum eGPUFXFlags;
/* for derivedmesh drawing callbacks, for view3d_select, .... */
typedef struct ViewContext {
+ struct Main *bmain;
struct Depsgraph *depsgraph;
struct Scene *scene;
struct ViewLayer *view_layer;
@@ -331,7 +332,8 @@ bool ED_view3d_autodist(
const bool alphaoverride, const float fallback_depth_pt[3]);
/* only draw so ED_view3d_autodist_simple can be called many times after */
-void ED_view3d_autodist_init(struct Depsgraph *depsgraph, struct ARegion *ar, struct View3D *v3d, int mode);
+void ED_view3d_autodist_init(
+ struct Depsgraph *depsgraph, struct ARegion *ar, struct View3D *v3d, int mode);
bool ED_view3d_autodist_simple(struct ARegion *ar, const int mval[2], float mouse_worldloc[3], int margin, float *force_depth);
bool ED_view3d_autodist_depth(struct ARegion *ar, const int mval[2], int margin, float *depth);
bool ED_view3d_autodist_depth_seg(struct ARegion *ar, const int mval_sta[2], const int mval_end[2], int margin, float *depth);
diff --git a/source/blender/editors/include/UI_interface.h b/source/blender/editors/include/UI_interface.h
index 4d1f1350047..a283068853c 100644
--- a/source/blender/editors/include/UI_interface.h
+++ b/source/blender/editors/include/UI_interface.h
@@ -828,6 +828,7 @@ struct Panel *UI_panel_begin(struct ScrArea *sa, struct ARegion *ar, struct List
bool *r_open);
void UI_panel_end(uiBlock *block, int width, int height);
void UI_panels_scale(struct ARegion *ar, float new_width);
+void UI_panel_label_offset(struct uiBlock *block, int *x, int *y);
bool UI_panel_category_is_visible(struct ARegion *ar);
void UI_panel_category_add(struct ARegion *ar, const char *name);
@@ -859,7 +860,7 @@ void UI_popup_handlers_remove_all(struct bContext *C, struct ListBase *handlers)
* be used to reinitialize some internal state if user preferences change. */
void UI_init(void);
-void UI_init_userdef(void);
+void UI_init_userdef(struct Main *bmain);
void UI_reinit_font(void);
void UI_exit(void);
@@ -1244,10 +1245,10 @@ void UI_widgetbase_draw_cache_flush(void);
void UI_widgetbase_draw_cache_end(void);
/* Special drawing for toolbar, mainly workarounds for inflexible icon sizing. */
-#define USE_TOOLBAR_HACK
+#define USE_UI_TOOLBAR_HACK
/* Support click-drag motion which presses the button and closes a popover (like a menu). */
-#define USE_POPOVER_ONCE
+#define USE_UI_POPOVER_ONCE
bool UI_but_is_tool(const uiBut *but);
diff --git a/source/blender/editors/interface/interface.c b/source/blender/editors/interface/interface.c
index 6cb667cb9a8..28f4c40469a 100644
--- a/source/blender/editors/interface/interface.c
+++ b/source/blender/editors/interface/interface.c
@@ -53,10 +53,11 @@
#include "BKE_animsys.h"
#include "BKE_context.h"
-#include "BKE_unit.h"
+#include "BKE_idprop.h"
+#include "BKE_main.h"
#include "BKE_scene.h"
#include "BKE_screen.h"
-#include "BKE_idprop.h"
+#include "BKE_unit.h"
#include "GPU_glew.h"
#include "GPU_matrix.h"
@@ -4694,10 +4695,10 @@ void UI_init(void)
}
/* after reading userdef file */
-void UI_init_userdef(void)
+void UI_init_userdef(Main *bmain)
{
/* fix saved themes */
- init_userdef_do_versions();
+ init_userdef_do_versions(bmain);
uiStyleInit();
}
diff --git a/source/blender/editors/interface/interface_anim.c b/source/blender/editors/interface/interface_anim.c
index ea1b58107bd..fc0ad7e5dce 100644
--- a/source/blender/editors/interface/interface_anim.c
+++ b/source/blender/editors/interface/interface_anim.c
@@ -41,6 +41,7 @@
#include "BKE_context.h"
#include "BKE_fcurve.h"
#include "BKE_global.h"
+#include "BKE_main.h"
#include "BKE_nla.h"
#include "DEG_depsgraph.h"
@@ -226,6 +227,7 @@ bool ui_but_anim_expression_create(uiBut *but, const char *str)
void ui_but_anim_autokey(bContext *C, uiBut *but, Scene *scene, float cfra)
{
+ Main *bmain = CTX_data_main(C);
ID *id;
bAction *action;
FCurve *fcu;
@@ -277,7 +279,7 @@ void ui_but_anim_autokey(bContext *C, uiBut *but, Scene *scene, float cfra)
* because a button may control all items of an array at once.
* E.g., color wheels (see T42567). */
BLI_assert((fcu->array_index == but->rnaindex) || (but->rnaindex == -1));
- insert_keyframe(depsgraph, reports, id, action,
+ insert_keyframe(bmain, depsgraph, reports, id, action,
((fcu->grp) ? (fcu->grp->name) : (NULL)),
fcu->rna_path, but->rnaindex, cfra, ts->keyframe_type, flag);
diff --git a/source/blender/editors/interface/interface_eyedropper_depth.c b/source/blender/editors/interface/interface_eyedropper_depth.c
index bd23fbb961d..df09c327da1 100644
--- a/source/blender/editors/interface/interface_eyedropper_depth.c
+++ b/source/blender/editors/interface/interface_eyedropper_depth.c
@@ -41,6 +41,7 @@
#include "BLI_math_vector.h"
#include "BKE_context.h"
+#include "BKE_main.h"
#include "BKE_screen.h"
#include "BKE_unit.h"
diff --git a/source/blender/editors/interface/interface_handlers.c b/source/blender/editors/interface/interface_handlers.c
index 0ebe079703b..b05dbe9c3b0 100644
--- a/source/blender/editors/interface/interface_handlers.c
+++ b/source/blender/editors/interface/interface_handlers.c
@@ -506,7 +506,7 @@ bool ui_but_is_toggle(const uiBut *but)
);
}
-#ifdef USE_POPOVER_ONCE
+#ifdef USE_UI_POPOVER_ONCE
bool ui_but_is_popover_once_compat(const uiBut *but)
{
return (
@@ -1400,7 +1400,7 @@ static int ui_handler_region_drag_toggle(bContext *C, const wmEvent *event, void
switch (event->type) {
case LEFTMOUSE:
{
- if (event->val != KM_PRESS) {
+ if (event->val == KM_RELEASE) {
done = true;
}
break;
@@ -3594,7 +3594,7 @@ static int ui_do_but_BUT(
button_activate_state(C, but, BUTTON_STATE_WAIT_RELEASE);
return WM_UI_HANDLER_BREAK;
}
- else if (event->type == LEFTMOUSE && but->block->handle) {
+ else if (event->type == LEFTMOUSE && event->val == KM_RELEASE && but->block->handle) {
/* regular buttons will be 'UI_SELECT', menu items 'UI_ACTIVE' */
if (!(but->flag & (UI_SELECT | UI_ACTIVE)))
data->cancel = true;
@@ -3607,7 +3607,7 @@ static int ui_do_but_BUT(
}
}
else if (data->state == BUTTON_STATE_WAIT_RELEASE) {
- if (event->type == LEFTMOUSE && event->val != KM_PRESS) {
+ if (event->type == LEFTMOUSE && event->val == KM_RELEASE) {
if (!(but->flag & UI_SELECT))
data->cancel = true;
button_activate_state(C, but, BUTTON_STATE_EXIT);
@@ -4317,7 +4317,7 @@ static int ui_do_but_NUM(
button_activate_state(C, but, BUTTON_STATE_EXIT);
}
}
- else if (event->type == LEFTMOUSE && event->val != KM_PRESS) {
+ else if (event->type == LEFTMOUSE && event->val == KM_RELEASE) {
if (data->dragchange) {
#ifdef USE_DRAG_MULTINUM
/* if we started multibutton but didnt drag, then edit */
@@ -4625,7 +4625,7 @@ static int ui_do_but_SLI(
button_activate_state(C, but, BUTTON_STATE_EXIT);
}
}
- else if (event->type == LEFTMOUSE && event->val != KM_PRESS) {
+ else if (event->type == LEFTMOUSE && event->val == KM_RELEASE) {
if (data->dragchange) {
#ifdef USE_DRAG_MULTINUM
/* if we started multibutton but didnt drag, then edit */
@@ -4778,7 +4778,7 @@ static int ui_do_but_SCROLL(
button_activate_state(C, but, BUTTON_STATE_EXIT);
}
}
- else if (event->type == LEFTMOUSE && event->val != KM_PRESS) {
+ else if (event->type == LEFTMOUSE && event->val == KM_RELEASE) {
button_activate_state(C, but, BUTTON_STATE_EXIT);
}
else if (event->type == MOUSEMOVE) {
@@ -4830,7 +4830,7 @@ static int ui_do_but_GRIP(
button_activate_state(C, but, BUTTON_STATE_EXIT);
}
}
- else if (event->type == LEFTMOUSE && event->val != KM_PRESS) {
+ else if (event->type == LEFTMOUSE && event->val == KM_RELEASE) {
button_activate_state(C, but, BUTTON_STATE_EXIT);
}
else if (event->type == MOUSEMOVE) {
@@ -5216,7 +5216,7 @@ static int ui_do_but_UNITVEC(
ui_numedit_apply(C, block, but, data);
}
}
- else if (event->type == LEFTMOUSE && event->val != KM_PRESS) {
+ else if (event->type == LEFTMOUSE && event->val == KM_RELEASE) {
button_activate_state(C, but, BUTTON_STATE_EXIT);
}
@@ -5550,7 +5550,7 @@ static int ui_do_but_HSVCUBE(
ui_numedit_apply(C, block, but, data);
}
}
- else if (event->type == LEFTMOUSE && event->val != KM_PRESS) {
+ else if (event->type == LEFTMOUSE && event->val == KM_RELEASE) {
button_activate_state(C, but, BUTTON_STATE_EXIT);
}
@@ -5828,7 +5828,7 @@ static int ui_do_but_HSVCIRCLE(
}
}
}
- else if (event->type == LEFTMOUSE && event->val != KM_PRESS) {
+ else if (event->type == LEFTMOUSE && event->val == KM_RELEASE) {
button_activate_state(C, but, BUTTON_STATE_EXIT);
}
return WM_UI_HANDLER_BREAK;
@@ -5918,7 +5918,7 @@ static int ui_do_but_COLORBAND(
ui_numedit_apply(C, block, but, data);
}
}
- else if (event->type == LEFTMOUSE && event->val != KM_PRESS) {
+ else if (event->type == LEFTMOUSE && event->val == KM_RELEASE) {
button_activate_state(C, but, BUTTON_STATE_EXIT);
}
else if (ELEM(event->type, ESCKEY, RIGHTMOUSE)) {
@@ -6169,7 +6169,7 @@ static int ui_do_but_CURVE(
ui_numedit_apply(C, block, but, data);
}
}
- else if (event->type == LEFTMOUSE && event->val != KM_PRESS) {
+ else if (event->type == LEFTMOUSE && event->val == KM_RELEASE) {
if (data->dragsel != -1) {
CurveMapping *cumap = (CurveMapping *)but->poin;
CurveMap *cuma = cumap->cm + cumap->cur;
@@ -6267,7 +6267,7 @@ static int ui_do_but_HISTOGRAM(
ui_numedit_apply(C, block, but, data);
}
}
- else if (event->type == LEFTMOUSE && event->val != KM_PRESS) {
+ else if (event->type == LEFTMOUSE && event->val == KM_RELEASE) {
button_activate_state(C, but, BUTTON_STATE_EXIT);
}
return WM_UI_HANDLER_BREAK;
@@ -6342,7 +6342,7 @@ static int ui_do_but_WAVEFORM(
ui_numedit_apply(C, block, but, data);
}
}
- else if (event->type == LEFTMOUSE && event->val != KM_PRESS) {
+ else if (event->type == LEFTMOUSE && event->val == KM_RELEASE) {
button_activate_state(C, but, BUTTON_STATE_EXIT);
}
return WM_UI_HANDLER_BREAK;
@@ -6426,7 +6426,7 @@ static int ui_do_but_TRACKPREVIEW(
ui_numedit_apply(C, block, but, data);
}
}
- else if (event->type == LEFTMOUSE && event->val != KM_PRESS) {
+ else if (event->type == LEFTMOUSE && event->val == KM_RELEASE) {
button_activate_state(C, but, BUTTON_STATE_EXIT);
}
return WM_UI_HANDLER_BREAK;
@@ -8362,7 +8362,7 @@ static int ui_handle_button_event(bContext *C, const wmEvent *event, uiBut *but)
data->cancel = true;
button_activate_state(C, but, BUTTON_STATE_EXIT);
break;
-#ifdef USE_POPOVER_ONCE
+#ifdef USE_UI_POPOVER_ONCE
case LEFTMOUSE:
{
if (event->val == KM_RELEASE) {
@@ -9527,7 +9527,7 @@ static int ui_handle_menu_event(
retval = ui_handle_menu_button(C, event, menu);
}
-#ifdef USE_POPOVER_ONCE
+#ifdef USE_UI_POPOVER_ONCE
if (block->flag & UI_BLOCK_POPOVER_ONCE) {
if ((event->type == LEFTMOUSE) && (event->val == KM_RELEASE)) {
UI_popover_once_clear(menu->popup_create_vars.arg);
diff --git a/source/blender/editors/interface/interface_icons.c b/source/blender/editors/interface/interface_icons.c
index 2c813d152e9..c2ada1e3733 100644
--- a/source/blender/editors/interface/interface_icons.c
+++ b/source/blender/editors/interface/interface_icons.c
@@ -1252,7 +1252,7 @@ static void icon_draw_size(
/* We need to flush widget base first to ensure correct ordering. */
UI_widgetbase_draw_cache_flush();
-#ifdef USE_TOOLBAR_HACK
+#ifdef USE_UI_TOOLBAR_HACK
/* TODO(campbell): scale icons up for toolbar, we need a way to detect larger buttons and do this automatic. */
{
float scale = (float)ICON_DEFAULT_HEIGHT_TOOLBAR / (float)ICON_DEFAULT_HEIGHT;
diff --git a/source/blender/editors/interface/interface_intern.h b/source/blender/editors/interface/interface_intern.h
index c7cf03a44dd..b5bf9be737b 100644
--- a/source/blender/editors/interface/interface_intern.h
+++ b/source/blender/editors/interface/interface_intern.h
@@ -784,7 +784,7 @@ void ui_icon_ensure_deferred(const struct bContext *C, const int icon_id, const
int ui_id_icon_get(const struct bContext *C, struct ID *id, const bool big);
/* resources.c */
-void init_userdef_do_versions(void);
+void init_userdef_do_versions(struct Main *bmain);
void ui_theme_init_default(void);
void ui_style_init_default(void);
void ui_resources_init(void);
diff --git a/source/blender/editors/interface/interface_layout.c b/source/blender/editors/interface/interface_layout.c
index ea40c8e8fd8..b3bd98c7b94 100644
--- a/source/blender/editors/interface/interface_layout.c
+++ b/source/blender/editors/interface/interface_layout.c
@@ -701,6 +701,7 @@ static uiBut *ui_item_with_label(
PropertyType type;
PropertySubType subtype;
int prop_but_width = w_hint;
+ const bool use_prop_sep = ((layout->item.flag & UI_ITEM_PROP_SEP) != 0);
sub = uiLayoutRow(layout, layout->align);
UI_block_layout_set_current(block, sub);
@@ -708,15 +709,25 @@ static uiBut *ui_item_with_label(
if (name[0]) {
int w_label;
- if (ui_layout_vary_direction(layout) == UI_ITEM_VARY_X) {
- /* w_hint is width for label in this case. Use a default width for property button(s) */
- prop_but_width = UI_UNIT_X * 5;
- w_label = w_hint;
+ if (use_prop_sep) {
+ w_label = (int)((w_hint * 2) * UI_ITEM_PROP_SEP_DIVIDE);
}
else {
- w_label = w_hint / 3;
+ if (ui_layout_vary_direction(layout) == UI_ITEM_VARY_X) {
+ /* w_hint is width for label in this case. Use a default width for property button(s) */
+ prop_but_width = UI_UNIT_X * 5;
+ w_label = w_hint;
+ }
+ else {
+ w_label = w_hint / 3;
+ }
+ }
+
+ uiBut *but_label = uiDefBut(block, UI_BTYPE_LABEL, 0, name, x, y, w_label, h, NULL, 0.0, 0.0, 0, 0, "");
+ if (use_prop_sep) {
+ but_label->drawflag |= UI_BUT_TEXT_RIGHT;
+ but_label->drawflag &= ~UI_BUT_TEXT_LEFT;
}
- uiDefBut(block, UI_BTYPE_LABEL, 0, name, x, y, w_label, h, NULL, 0.0, 0.0, 0, 0, "");
}
type = RNA_property_type(prop);
@@ -1851,6 +1862,7 @@ void uiItemPointerR(uiLayout *layout, struct PointerRNA *ptr, const char *propna
StructRNA *icontype;
int w, h;
char namestr[UI_MAX_NAME_STR];
+ const bool use_prop_sep = ((layout->item.flag & UI_ITEM_PROP_SEP) != 0);
/* validate arguments */
prop = RNA_struct_find_property(ptr, propname);
@@ -1893,7 +1905,9 @@ void uiItemPointerR(uiLayout *layout, struct PointerRNA *ptr, const char *propna
if (!name)
name = RNA_property_ui_name(prop);
- name = ui_item_name_add_colon(name, namestr);
+ if (use_prop_sep == false) {
+ name = ui_item_name_add_colon(name, namestr);
+ }
/* create button */
block = uiLayoutGetBlock(layout);
diff --git a/source/blender/editors/interface/interface_ops.c b/source/blender/editors/interface/interface_ops.c
index 5c2fb0e7aaa..6fcede58737 100644
--- a/source/blender/editors/interface/interface_ops.c
+++ b/source/blender/editors/interface/interface_ops.c
@@ -957,7 +957,7 @@ static int editsource_text_edit(
}
if (text == NULL) {
- text = BKE_text_load(bmain, filepath, bmain->name);
+ text = BKE_text_load(bmain, filepath, BKE_main_blendfile_path(bmain));
id_us_ensure_real(&text->id);
}
diff --git a/source/blender/editors/interface/interface_panel.c b/source/blender/editors/interface/interface_panel.c
index 3847aa72519..dbdf2a0863c 100644
--- a/source/blender/editors/interface/interface_panel.c
+++ b/source/blender/editors/interface/interface_panel.c
@@ -612,6 +612,20 @@ static void ui_draw_panel_dragwidget(unsigned int pos, unsigned int col, const r
immEnd();
}
+/* For button layout next to label. */
+void UI_panel_label_offset(uiBlock *block, int *x, int *y)
+{
+ Panel *panel = block->panel;
+ uiStyle *style = UI_style_get_dpi();
+ const bool is_subpanel = (panel->type && panel->type->parent);
+
+ *x = UI_UNIT_X * 1.1f;
+ *y = (UI_UNIT_Y * 1.1f) + style->panelspace;
+
+ if (is_subpanel) {
+ *x += 5.0f / block->aspect;
+ }
+}
static void ui_draw_aligned_panel_header(uiStyle *style, uiBlock *block, const rcti *rect, char dir)
{
@@ -619,6 +633,8 @@ static void ui_draw_aligned_panel_header(uiStyle *style, uiBlock *block, const r
rcti hrect;
int pnl_icons;
const char *activename = panel->drawname[0] ? panel->drawname : panel->panelname;
+ const bool is_subpanel = (panel->type && panel->type->parent);
+ uiFontStyle *fontstyle = (is_subpanel) ? &style->widgetlabel : &style->paneltitle;
unsigned char col_title[4];
/* + 0.001f to avoid flirting with float inaccuracy */
@@ -635,14 +651,14 @@ static void ui_draw_aligned_panel_header(uiStyle *style, uiBlock *block, const r
if (dir == 'h') {
hrect.xmin = rect->xmin + pnl_icons;
hrect.ymin += 2.0f / block->aspect;
- UI_fontstyle_draw(&style->paneltitle, &hrect, activename, col_title);
+ UI_fontstyle_draw(fontstyle, &hrect, activename, col_title);
}
else {
/* ignore 'pnl_icons', otherwise the text gets offset horizontally
* + 0.001f to avoid flirting with float inaccuracy
*/
hrect.xmin = rect->xmin + (PNL_ICON + 5) / block->aspect + 0.001f;
- UI_fontstyle_draw_rotated(&style->paneltitle, &hrect, activename, col_title);
+ UI_fontstyle_draw_rotated(fontstyle, &hrect, activename, col_title);
}
}
@@ -667,6 +683,11 @@ void ui_draw_aligned_panel(uiStyle *style, uiBlock *block, const rcti *rect, con
headrect.ymin = headrect.ymax;
headrect.ymax = headrect.ymin + floor(PNL_HEADER / block->aspect + 0.001f);
+ rcti titlerect = headrect;
+ if (is_subpanel) {
+ titlerect.xmin += 5.0f / block->aspect;
+ }
+
unsigned int pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
@@ -738,7 +759,7 @@ void ui_draw_aligned_panel(uiStyle *style, uiBlock *block, const rcti *rect, con
/* horizontal title */
if (is_closed_x == false) {
- ui_draw_aligned_panel_header(style, block, &headrect, 'h');
+ ui_draw_aligned_panel_header(style, block, &titlerect, 'h');
if (show_drag) {
unsigned int col;
@@ -817,10 +838,10 @@ void ui_draw_aligned_panel(uiStyle *style, uiBlock *block, const rcti *rect, con
/* draw collapse icon */
/* itemrect smaller */
- itemrect.xmin = headrect.xmin + 3.0f / block->aspect;
- itemrect.xmax = itemrect.xmin + BLI_rcti_size_y(&headrect);
- itemrect.ymin = headrect.ymin;
- itemrect.ymax = headrect.ymax;
+ itemrect.xmin = titlerect.xmin + 3.0f / block->aspect;
+ itemrect.xmax = itemrect.xmin + BLI_rcti_size_y(&titlerect);
+ itemrect.ymin = titlerect.ymin;
+ itemrect.ymax = titlerect.ymax;
BLI_rctf_scale(&itemrect, 0.25f);
@@ -2284,7 +2305,7 @@ static int ui_handler_panel(bContext *C, const wmEvent *event, void *userdata)
uiHandlePanelData *data = panel->activedata;
/* verify if we can stop */
- if (event->type == LEFTMOUSE && event->val != KM_PRESS) {
+ if (event->type == LEFTMOUSE && event->val == KM_RELEASE) {
ScrArea *sa = CTX_wm_area(C);
ARegion *ar = CTX_wm_region(C);
int align = panel_aligned(sa, ar);
diff --git a/source/blender/editors/interface/interface_region_menu_pie.c b/source/blender/editors/interface/interface_region_menu_pie.c
index 0c43b787a84..504e1807a8f 100644
--- a/source/blender/editors/interface/interface_region_menu_pie.c
+++ b/source/blender/editors/interface/interface_region_menu_pie.c
@@ -150,8 +150,16 @@ uiPieMenu *UI_pie_menu_begin(struct bContext *C, const char *title, int icon, co
}
pie->layout = UI_block_layout(pie->block_radial, UI_LAYOUT_VERTICAL, UI_LAYOUT_PIEMENU, 0, 0, 200, 0, 0, style);
- pie->mx = event->x;
- pie->my = event->y;
+
+ /* Open from where we started dragging. */
+ if (event->val == KM_CLICK_DRAG) {
+ pie->mx = event->prevclickx;
+ pie->my = event->prevclicky;
+ }
+ else {
+ pie->mx = event->x;
+ pie->my = event->y;
+ }
/* create title button */
if (title[0]) {
diff --git a/source/blender/editors/interface/interface_region_popover.c b/source/blender/editors/interface/interface_region_popover.c
index 9d10713c868..c681cfe776f 100644
--- a/source/blender/editors/interface/interface_region_popover.c
+++ b/source/blender/editors/interface/interface_region_popover.c
@@ -87,7 +87,7 @@ struct uiPopover {
uiMenuCreateFunc menu_func;
void *menu_arg;
-#ifdef USE_POPOVER_ONCE
+#ifdef USE_UI_POPOVER_ONCE
bool is_once;
#endif
};
@@ -136,7 +136,7 @@ static uiBlock *ui_block_func_POPOVER(bContext *C, uiPopupBlockHandle *handle, v
UI_block_region_set(block, handle->region);
UI_block_layout_resolve(block, &width, &height);
UI_block_flag_enable(block, UI_BLOCK_MOVEMOUSE_QUIT | UI_BLOCK_KEEP_OPEN | UI_BLOCK_POPOVER);
-#ifdef USE_POPOVER_ONCE
+#ifdef USE_UI_POPOVER_ONCE
if (pup->is_once) {
UI_block_flag_enable(block, UI_BLOCK_POPOVER_ONCE);
}
@@ -231,7 +231,7 @@ uiPopupBlockHandle *ui_popover_panel_create(
pup->menu_func = menu_func;
pup->menu_arg = arg;
-#ifdef USE_POPOVER_ONCE
+#ifdef USE_UI_POPOVER_ONCE
pup->is_once = true;
#endif
@@ -365,7 +365,7 @@ uiLayout *UI_popover_layout(uiPopover *pup)
return pup->layout;
}
-#ifdef USE_POPOVER_ONCE
+#ifdef USE_UI_POPOVER_ONCE
void UI_popover_once_clear(uiPopover *pup)
{
pup->is_once = false;
diff --git a/source/blender/editors/interface/interface_templates.c b/source/blender/editors/interface/interface_templates.c
index d934d4dd1e4..9978726fa74 100644
--- a/source/blender/editors/interface/interface_templates.c
+++ b/source/blender/editors/interface/interface_templates.c
@@ -3970,7 +3970,9 @@ eAutoPropButsReturn uiTemplateOperatorPropertyButs(
#endif
/* set various special settings for buttons */
- {
+
+ /* Only do this if we're not refreshing an existing UI. */
+ if (block->oldblock == NULL) {
const bool is_popup = (block->flag & UI_BLOCK_KEEP_OPEN) != 0;
uiBut *but;
diff --git a/source/blender/editors/interface/interface_widgets.c b/source/blender/editors/interface/interface_widgets.c
index 928ac8c9171..3188bc847a7 100644
--- a/source/blender/editors/interface/interface_widgets.c
+++ b/source/blender/editors/interface/interface_widgets.c
@@ -2008,11 +2008,20 @@ static void widget_draw_text_icon(uiFontStyle *fstyle, uiWidgetColors *wcol, uiB
else if (but->flag & UI_HAS_ICON || show_menu_icon) {
const bool is_tool = UI_but_is_tool(but);
+ /* XXX add way to draw icons at a different size!
+ * Use small icons for popup. */
+#ifdef USE_UI_TOOLBAR_HACK
+ const float aspect_orig = but->block->aspect;
+ if (is_tool && (but->block->flag & UI_BLOCK_POPOVER)) {
+ but->block->aspect *= 2.0f;
+ }
+#endif
+
const BIFIconID icon = (but->flag & UI_HAS_ICON) ? but->icon + but->iconadd : ICON_NONE;
int icon_size_init = is_tool ? ICON_DEFAULT_HEIGHT_TOOLBAR : ICON_DEFAULT_HEIGHT;
const float icon_size = icon_size_init / (but->block->aspect / UI_DPI_FAC);
-#ifdef USE_TOOLBAR_HACK
+#ifdef USE_UI_TOOLBAR_HACK
if (is_tool) {
/* pass (even if its a menu toolbar) */
but->drawflag |= UI_BUT_TEXT_LEFT;
@@ -2034,6 +2043,10 @@ static void widget_draw_text_icon(uiFontStyle *fstyle, uiWidgetColors *wcol, uiB
widget_draw_icon(but, icon, alpha, rect, show_menu_icon);
+#ifdef USE_UI_TOOLBAR_HACK
+ but->block->aspect = aspect_orig;
+#endif
+
rect->xmin += icon_size;
/* without this menu keybindings will overlap the arrow icon [#38083] */
if (show_menu_icon) {
@@ -4359,7 +4372,7 @@ void ui_draw_but(const bContext *C, ARegion *ar, uiStyle *style, uiBut *but, rct
uiFontStyle *fstyle = &style->widget;
uiWidgetType *wt = NULL;
-#ifdef USE_POPOVER_ONCE
+#ifdef USE_UI_POPOVER_ONCE
const rcti rect_orig = *rect;
#endif
@@ -4413,7 +4426,7 @@ void ui_draw_but(const bContext *C, ARegion *ar, uiStyle *style, uiBut *but, rct
break;
case UI_BTYPE_BUT:
-#ifdef USE_TOOLBAR_HACK
+#ifdef USE_UI_TOOLBAR_HACK
if (UI_but_is_tool(but)) {
wt = widget_type(UI_WTYPE_TOOLBAR_ITEM);
}
@@ -4639,7 +4652,7 @@ void ui_draw_but(const bContext *C, ARegion *ar, uiStyle *style, uiBut *but, rct
if (disabled)
glEnable(GL_BLEND);
-#ifdef USE_POPOVER_ONCE
+#ifdef USE_UI_POPOVER_ONCE
if (but->block->flag & UI_BLOCK_POPOVER_ONCE) {
if ((state & UI_ACTIVE) && ui_but_is_popover_once_compat(but)) {
uiWidgetType wt_back = *wt;
diff --git a/source/blender/editors/interface/resources.c b/source/blender/editors/interface/resources.c
index 1bfb050563d..2a61be21589 100644
--- a/source/blender/editors/interface/resources.c
+++ b/source/blender/editors/interface/resources.c
@@ -1818,10 +1818,8 @@ void UI_make_axis_color(const unsigned char src_col[3], unsigned char dst_col[3]
/* ************************************************************* */
/* patching UserDef struct and Themes */
-void init_userdef_do_versions(void)
+void init_userdef_do_versions(Main *bmain)
{
- Main *bmain = G.main;
-
#define USER_VERSION_ATLEAST(ver, subver) MAIN_VERSION_ATLEAST(bmain, ver, subver)
/* the UserDef struct is not corrected with do_versions() .... ugh! */
diff --git a/source/blender/editors/io/io_alembic.c b/source/blender/editors/io/io_alembic.c
index b584782e183..4440b99f211 100644
--- a/source/blender/editors/io/io_alembic.c
+++ b/source/blender/editors/io/io_alembic.c
@@ -79,11 +79,11 @@ static int wm_alembic_export_invoke(bContext *C, wmOperator *op, const wmEvent *
Main *bmain = CTX_data_main(C);
char filepath[FILE_MAX];
- if (bmain->name[0] == '\0') {
+ if (BKE_main_blendfile_path(bmain)[0] == '\0') {
BLI_strncpy(filepath, "untitled", sizeof(filepath));
}
else {
- BLI_strncpy(filepath, bmain->name, sizeof(filepath));
+ BLI_strncpy(filepath, BKE_main_blendfile_path(bmain), sizeof(filepath));
}
BLI_replace_extension(filepath, sizeof(filepath), ".abc");
@@ -422,12 +422,12 @@ static int get_sequence_len(char *filename, int *ofs)
}
char path[FILE_MAX];
- BLI_path_abs(filename, G.main->name);
+ BLI_path_abs(filename, BKE_main_blendfile_path_from_global());
BLI_split_dir_part(filename, path, FILE_MAX);
if (path[0] == '\0') {
/* The filename had no path, so just use the blend file path. */
- BLI_split_dir_part(G.main->name, path, FILE_MAX);
+ BLI_split_dir_part(BKE_main_blendfile_path_from_global(), path, FILE_MAX);
}
DIR *dir = opendir(path);
diff --git a/source/blender/editors/io/io_cache.c b/source/blender/editors/io/io_cache.c
index eb79d0bec13..b13eaced843 100644
--- a/source/blender/editors/io/io_cache.c
+++ b/source/blender/editors/io/io_cache.c
@@ -60,7 +60,7 @@ static int cachefile_open_invoke(bContext *C, wmOperator *op, const wmEvent *eve
char filepath[FILE_MAX];
Main *bmain = CTX_data_main(C);
- BLI_strncpy(filepath, bmain->name, sizeof(filepath));
+ BLI_strncpy(filepath, BKE_main_blendfile_path(bmain), sizeof(filepath));
BLI_replace_extension(filepath, sizeof(filepath), ".abc");
RNA_string_set(op->ptr, "filepath", filepath);
}
diff --git a/source/blender/editors/io/io_collada.c b/source/blender/editors/io/io_collada.c
index bb0280875bd..aca380c3123 100644
--- a/source/blender/editors/io/io_collada.c
+++ b/source/blender/editors/io/io_collada.c
@@ -61,13 +61,16 @@
static int wm_collada_export_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
{
+ Main *bmain = CTX_data_main(C);
+
if (!RNA_struct_property_is_set(op->ptr, "filepath")) {
char filepath[FILE_MAX];
+ const char *blendfile_path = BKE_main_blendfile_path(bmain);
- if (G.main->name[0] == 0)
+ if (blendfile_path[0] == '\0')
BLI_strncpy(filepath, "untitled", sizeof(filepath));
else
- BLI_strncpy(filepath, G.main->name, sizeof(filepath));
+ BLI_strncpy(filepath, blendfile_path, sizeof(filepath));
BLI_replace_extension(filepath, sizeof(filepath), ".dae");
RNA_string_set(op->ptr, "filepath", filepath);
@@ -202,9 +205,11 @@ static int wm_collada_export_exec(bContext *C, wmOperator *op)
if (export_settings.include_armatures) includeFilter |= OB_REL_MOD_ARMATURE;
if (export_settings.include_children) includeFilter |= OB_REL_CHILDREN_RECURSIVE;
- export_count = collada_export(CTX_data_depsgraph(C),
- scene,
- &export_settings
+ export_count = collada_export(
+ C,
+ CTX_data_depsgraph(C),
+ scene,
+ &export_settings
);
if (export_count == 0) {
diff --git a/source/blender/editors/mesh/editmesh_knife_project.c b/source/blender/editors/mesh/editmesh_knife_project.c
index 5a61c5aab48..5ccbcf063ad 100644
--- a/source/blender/editors/mesh/editmesh_knife_project.c
+++ b/source/blender/editors/mesh/editmesh_knife_project.c
@@ -40,6 +40,7 @@
#include "BKE_curve.h"
#include "BKE_cdderivedmesh.h"
#include "BKE_editmesh.h"
+#include "BKE_mesh_runtime.h"
#include "BKE_report.h"
#include "DEG_depsgraph.h"
diff --git a/source/blender/editors/mesh/editmesh_tools.c b/source/blender/editors/mesh/editmesh_tools.c
index 5c6b6da54a6..17f643636cf 100644
--- a/source/blender/editors/mesh/editmesh_tools.c
+++ b/source/blender/editors/mesh/editmesh_tools.c
@@ -359,6 +359,7 @@ void MESH_OT_unsubdivide(wmOperatorType *ot)
void EMBM_project_snap_verts(bContext *C, ARegion *ar, BMEditMesh *em)
{
+ Main *bmain = CTX_data_main(C);
Object *obedit = em->ob;
BMIter iter;
BMVert *eve;
@@ -366,7 +367,7 @@ void EMBM_project_snap_verts(bContext *C, ARegion *ar, BMEditMesh *em)
ED_view3d_init_mats_rv3d(obedit, ar->regiondata);
struct SnapObjectContext *snap_context = ED_transform_snap_object_context_create_view3d(
- CTX_data_scene(C), CTX_data_depsgraph(C), 0,
+ bmain, CTX_data_scene(C), CTX_data_depsgraph(C), 0,
ar, CTX_wm_view3d(C));
BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) {
diff --git a/source/blender/editors/mesh/mesh_ops.c b/source/blender/editors/mesh/mesh_ops.c
index b3c507affb7..f5c5a85d5ca 100644
--- a/source/blender/editors/mesh/mesh_ops.c
+++ b/source/blender/editors/mesh/mesh_ops.c
@@ -335,6 +335,24 @@ void ED_keymap_mesh(wmKeyConfig *keyconf)
RNA_boolean_set(kmi->ptr, "vertex_only", true);
/* selecting */
+
+ kmi = WM_keymap_add_item(keymap, "MESH_OT_select_mode", ONEKEY, KM_PRESS, 0, 0);
+ RNA_enum_set(kmi->ptr, "type", SCE_SELECT_VERTEX);
+ kmi = WM_keymap_add_item(keymap, "MESH_OT_select_mode", TWOKEY, KM_PRESS, 0, 0);
+ RNA_enum_set(kmi->ptr, "type", SCE_SELECT_EDGE);
+ kmi = WM_keymap_add_item(keymap, "MESH_OT_select_mode", THREEKEY, KM_PRESS, 0, 0);
+ RNA_enum_set(kmi->ptr, "type", SCE_SELECT_FACE);
+
+ kmi = WM_keymap_add_item(keymap, "MESH_OT_select_mode", ONEKEY, KM_PRESS, KM_SHIFT, 0);
+ RNA_enum_set(kmi->ptr, "type", SCE_SELECT_VERTEX);
+ RNA_boolean_set(kmi->ptr, "use_extend", true);
+ kmi = WM_keymap_add_item(keymap, "MESH_OT_select_mode", TWOKEY, KM_PRESS, KM_SHIFT, 0);
+ RNA_enum_set(kmi->ptr, "type", SCE_SELECT_EDGE);
+ RNA_boolean_set(kmi->ptr, "use_extend", true);
+ kmi = WM_keymap_add_item(keymap, "MESH_OT_select_mode", THREEKEY, KM_PRESS, KM_SHIFT, 0);
+ RNA_enum_set(kmi->ptr, "type", SCE_SELECT_FACE);
+ RNA_boolean_set(kmi->ptr, "use_extend", true);
+
/* standard mouse selection goes via space_view3d */
kmi = WM_keymap_add_item(keymap, "MESH_OT_loop_select", SELECTMOUSE, KM_PRESS, KM_ALT, 0);
RNA_boolean_set(kmi->ptr, "extend", false);
diff --git a/source/blender/editors/mesh/meshtools.c b/source/blender/editors/mesh/meshtools.c
index 786b27ee816..41e1ca13b79 100644
--- a/source/blender/editors/mesh/meshtools.c
+++ b/source/blender/editors/mesh/meshtools.c
@@ -54,6 +54,7 @@
#include "BKE_library.h"
#include "BKE_main.h"
#include "BKE_mesh.h"
+#include "BKE_mesh_runtime.h"
#include "BKE_material.h"
#include "BKE_object.h"
#include "BKE_object_deform.h"
diff --git a/source/blender/editors/object/object_add.c b/source/blender/editors/object/object_add.c
index d66a176ddfc..37589177037 100644
--- a/source/blender/editors/object/object_add.c
+++ b/source/blender/editors/object/object_add.c
@@ -82,6 +82,7 @@
#include "BKE_material.h"
#include "BKE_mball.h"
#include "BKE_mesh.h"
+#include "BKE_mesh_runtime.h"
#include "BKE_nla.h"
#include "BKE_object.h"
#include "BKE_particle.h"
diff --git a/source/blender/editors/object/object_bake_api.c b/source/blender/editors/object/object_bake_api.c
index 677a98cf942..5210182510f 100644
--- a/source/blender/editors/object/object_bake_api.c
+++ b/source/blender/editors/object/object_bake_api.c
@@ -1021,7 +1021,8 @@ 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, NULL);
+ BKE_image_path_from_imtype(name, filepath, BKE_main_blendfile_path(bmain),
+ 0, bake->im_format.imtype, true, false, NULL);
if (is_automatic_name) {
BLI_path_suffix(name, FILE_MAX, ob_low->id.name + 2, "_");
diff --git a/source/blender/editors/object/object_constraint.c b/source/blender/editors/object/object_constraint.c
index 121a30c754a..3b5a8d190ff 100644
--- a/source/blender/editors/object/object_constraint.c
+++ b/source/blender/editors/object/object_constraint.c
@@ -152,7 +152,7 @@ bConstraint *get_active_constraint(Object *ob)
/* ------------- PyConstraints ------------------ */
/* this callback sets the text-file to be used for selected menu item */
-static void validate_pyconstraint_cb(void *arg1, void *arg2)
+static void validate_pyconstraint_cb(Main *bmain, void *arg1, void *arg2)
{
bPythonConstraint *data = arg1;
Text *text = NULL;
@@ -162,13 +162,13 @@ static void validate_pyconstraint_cb(void *arg1, void *arg2)
/* exception for no script */
if (index) {
/* innovative use of a for...loop to search */
- for (text = G.main->text.first, i = 1; text && index != i; i++, text = text->id.next) ;
+ for (text = bmain->text.first, i = 1; text && index != i; i++, text = text->id.next) ;
}
data->text = text;
}
/* this returns a string for the list of usable pyconstraint script names */
-static char *buildmenu_pyconstraints(Text *con_text, int *pyconindex)
+static char *buildmenu_pyconstraints(Main *bmain, Text *con_text, int *pyconindex)
{
DynStr *pupds = BLI_dynstr_new();
Text *text;
@@ -185,7 +185,7 @@ static char *buildmenu_pyconstraints(Text *con_text, int *pyconindex)
*pyconindex = 0;
/* loop through markers, adding them */
- for (text = G.main->text.first, i = 1; text; i++, text = text->id.next) {
+ for (text = bmain->text.first, i = 1; text; i++, text = text->id.next) {
/* this is important to ensure that right script is shown as active */
if (text == con_text) *pyconindex = i;
@@ -969,6 +969,7 @@ void CONSTRAINT_OT_childof_clear_inverse(wmOperatorType *ot)
static int followpath_path_animate_exec(bContext *C, wmOperator *op)
{
+ Main *bmain = CTX_data_main(C);
Object *ob = ED_object_active_context(C);
bConstraint *con = edit_constraint_property_get(op, ob, CONSTRAINT_TYPE_FOLLOWPATH);
bFollowPathConstraint *data = (con) ? (bFollowPathConstraint *)con->data : NULL;
@@ -993,7 +994,7 @@ static int followpath_path_animate_exec(bContext *C, wmOperator *op)
(list_find_fcurve(&cu->adt->action->curves, "eval_time", 0) == NULL))
{
/* create F-Curve for path animation */
- act = verify_adt_action(&cu->id, 1);
+ act = verify_adt_action(bmain, &cu->id, 1);
fcu = verify_fcurve(act, NULL, NULL, "eval_time", 0, 1);
/* standard vertical range - 1:1 = 100 frames */
@@ -1018,7 +1019,7 @@ static int followpath_path_animate_exec(bContext *C, wmOperator *op)
path = RNA_path_from_ID_to_property(&ptr, prop);
/* create F-Curve for constraint */
- act = verify_adt_action(&ob->id, 1);
+ act = verify_adt_action(bmain, &ob->id, 1);
fcu = verify_fcurve(act, NULL, NULL, path, 0, 1);
/* standard vertical range - 0.0 to 1.0 */
@@ -1798,14 +1799,14 @@ static int constraint_add_exec(bContext *C, wmOperator *op, Object *ob, ListBase
char *menustr;
int scriptint = 0;
/* popup a list of usable scripts */
- menustr = buildmenu_pyconstraints(NULL, &scriptint);
+ menustr = buildmenu_pyconstraints(bmain, NULL, &scriptint);
/* XXX scriptint = pupmenu(menustr); */
MEM_freeN(menustr);
/* only add constraint if a script was chosen */
if (scriptint) {
/* add constraint */
- validate_pyconstraint_cb(con->data, &scriptint);
+ validate_pyconstraint_cb(bmain, con->data, &scriptint);
/* make sure target allowance is set correctly */
BPY_pyconstraint_update(ob, con);
diff --git a/source/blender/editors/object/object_data_transfer.c b/source/blender/editors/object/object_data_transfer.c
index d4e8955b38e..db81c51cc90 100644
--- a/source/blender/editors/object/object_data_transfer.c
+++ b/source/blender/editors/object/object_data_transfer.c
@@ -43,6 +43,7 @@
#include "BKE_DerivedMesh.h"
#include "BKE_mesh_mapping.h"
#include "BKE_mesh_remap.h"
+#include "BKE_mesh_runtime.h"
#include "BKE_object.h"
#include "BKE_report.h"
diff --git a/source/blender/editors/object/object_edit.c b/source/blender/editors/object/object_edit.c
index 9bc01892ef0..d47a2576a8a 100644
--- a/source/blender/editors/object/object_edit.c
+++ b/source/blender/editors/object/object_edit.c
@@ -209,7 +209,7 @@ static bool ED_object_editmode_load_ex(Main *bmain, Object *obedit, const bool f
if (arm->edbo == NULL) {
return false;
}
- ED_armature_from_edit(obedit->data);
+ ED_armature_from_edit(bmain, obedit->data);
if (freedata) {
ED_armature_edit_free(obedit->data);
}
@@ -224,7 +224,7 @@ static bool ED_object_editmode_load_ex(Main *bmain, Object *obedit, const bool f
if (cu->editnurb == NULL) {
return false;
}
- ED_curve_editnurb_load(obedit);
+ ED_curve_editnurb_load(bmain, obedit);
if (freedata) {
ED_curve_editnurb_free(obedit);
}
@@ -272,13 +272,13 @@ bool ED_object_editmode_load(Main *bmain, Object *obedit)
* \param flag:
* - If #EM_FREEDATA isn't in the flag, use ED_object_editmode_load directly.
*/
-bool ED_object_editmode_exit_ex(Scene *scene, Object *obedit, int flag)
+bool ED_object_editmode_exit_ex(Main *bmain, Scene *scene, Object *obedit, int flag)
{
const bool freedata = (flag & EM_FREEDATA) != 0;
if (flag & EM_WAITCURSOR) waitcursor(1);
- if (ED_object_editmode_load_ex(G.main, obedit, freedata) == false) {
+ if (ED_object_editmode_load_ex(bmain, obedit, freedata) == false) {
/* in rare cases (background mode) its possible active object
* is flagged for editmode, without 'obedit' being set [#35489] */
if (UNLIKELY(obedit && obedit->mode & OB_MODE_EDIT)) {
@@ -318,9 +318,10 @@ bool ED_object_editmode_exit_ex(Scene *scene, Object *obedit, int flag)
bool ED_object_editmode_exit(bContext *C, int flag)
{
+ Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
Object *obedit = CTX_data_edit_object(C);
- return ED_object_editmode_exit_ex(scene, obedit, flag);
+ return ED_object_editmode_exit_ex(bmain, scene, obedit, flag);
}
bool ED_object_editmode_enter_ex(Main *bmain, Scene *scene, Object *ob, int flag)
@@ -465,7 +466,7 @@ static int editmode_toggle_exec(bContext *C, wmOperator *op)
FOREACH_OBJECT_BEGIN(view_layer, ob)
{
if ((ob != obact) && (ob->type == obact->type)) {
- ED_object_editmode_exit_ex(scene, ob, EM_FREEDATA | EM_WAITCURSOR);
+ ED_object_editmode_exit_ex(bmain, scene, ob, EM_FREEDATA | EM_WAITCURSOR);
}
}
FOREACH_OBJECT_END;
diff --git a/source/blender/editors/object/object_group.c b/source/blender/editors/object/object_group.c
index debbe4bd379..8a52b6c5ef5 100644
--- a/source/blender/editors/object/object_group.c
+++ b/source/blender/editors/object/object_group.c
@@ -361,6 +361,7 @@ static int collection_create_exec(bContext *C, wmOperator *op)
RNA_string_get(op->ptr, "name", name);
Collection *collection = BKE_collection_add(bmain, NULL, name);
+ id_fake_user_set(&collection->id);
CTX_DATA_BEGIN (C, Base *, base, selected_bases)
{
@@ -402,6 +403,7 @@ static int collection_add_exec(bContext *C, wmOperator *UNUSED(op))
return OPERATOR_CANCELLED;
Collection *collection = BKE_collection_add(bmain, NULL, "Collection");
+ id_fake_user_set(&collection->id);
BKE_collection_object_add(bmain, collection, ob);
WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);
diff --git a/source/blender/editors/object/object_hook.c b/source/blender/editors/object/object_hook.c
index 7687bd476b9..31e8685e323 100644
--- a/source/blender/editors/object/object_hook.c
+++ b/source/blender/editors/object/object_hook.c
@@ -304,7 +304,7 @@ static int return_editcurve_indexar(
return totvert;
}
-static bool object_hook_index_array(Scene *scene, Object *obedit,
+static bool object_hook_index_array(Main *bmain, Scene *scene, Object *obedit,
int *r_tot, int **r_indexar, char *r_name, float r_cent[3])
{
*r_indexar = NULL;
@@ -336,7 +336,7 @@ static bool object_hook_index_array(Scene *scene, Object *obedit,
}
case OB_CURVE:
case OB_SURF:
- ED_curve_editnurb_load(obedit);
+ ED_curve_editnurb_load(bmain, obedit);
ED_curve_editnurb_make(obedit);
return return_editcurve_indexar(obedit, r_tot, r_indexar, r_cent);
case OB_LATTICE:
@@ -476,7 +476,7 @@ static int add_hook_object(const bContext *C, Main *bmain, Scene *scene, ViewLay
int tot, ok, *indexar;
char name[MAX_NAME];
- ok = object_hook_index_array(scene, obedit, &tot, &indexar, name, cent);
+ ok = object_hook_index_array(bmain, scene, obedit, &tot, &indexar, name, cent);
if (!ok) {
BKE_report(reports, RPT_ERROR, "Requires selected vertices or active vertex group");
@@ -814,6 +814,7 @@ void OBJECT_OT_hook_recenter(wmOperatorType *ot)
static int object_hook_assign_exec(bContext *C, wmOperator *op)
{
+ Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
PointerRNA ptr = CTX_data_pointer_get_type(C, "modifier", &RNA_HookModifier);
int num = RNA_enum_get(op->ptr, "modifier");
@@ -831,7 +832,7 @@ static int object_hook_assign_exec(bContext *C, wmOperator *op)
/* assign functionality */
- if (!object_hook_index_array(scene, ob, &tot, &indexar, name, cent)) {
+ if (!object_hook_index_array(bmain, scene, ob, &tot, &indexar, name, cent)) {
BKE_report(op->reports, RPT_WARNING, "Requires selected vertices or active vertex group");
return OPERATOR_CANCELLED;
}
diff --git a/source/blender/editors/object/object_modes.c b/source/blender/editors/object/object_modes.c
index 66c2ad5fa9b..e9bd6fbce8f 100644
--- a/source/blender/editors/object/object_modes.c
+++ b/source/blender/editors/object/object_modes.c
@@ -209,7 +209,7 @@ static bool ed_object_mode_generic_exit_ex(
if (only_test) {
return true;
}
- ED_object_editmode_exit_ex(scene, ob, EM_FREEDATA);
+ ED_object_editmode_exit_ex(bmain, scene, ob, EM_FREEDATA);
}
}
else if (ob->mode & OB_MODE_VERTEX_PAINT) {
diff --git a/source/blender/editors/object/object_modifier.c b/source/blender/editors/object/object_modifier.c
index fb2884ea07f..71c9cb3eb69 100644
--- a/source/blender/editors/object/object_modifier.c
+++ b/source/blender/editors/object/object_modifier.c
@@ -64,6 +64,7 @@
#include "BKE_main.h"
#include "BKE_mesh.h"
#include "BKE_mesh_mapping.h"
+#include "BKE_mesh_runtime.h"
#include "BKE_mesh_sample.h"
#include "BKE_modifier.h"
#include "BKE_multires.h"
@@ -574,7 +575,7 @@ static int modifier_apply_shape(ReportList *reports, Depsgraph *depsgraph, Scene
}
kb = BKE_keyblock_add(key, md->name);
- BKE_nomain_mesh_to_meshkey(mesh_applied, me, kb);
+ BKE_mesh_nomain_to_meshkey(mesh_applied, me, kb);
BKE_id_free(NULL, mesh_applied);
}
@@ -623,7 +624,7 @@ static int modifier_apply_obdata(ReportList *reports, Depsgraph *depsgraph, Scen
return 0;
}
- BKE_nomain_mesh_to_mesh(mesh_applied, me, ob, CD_MASK_MESH, true);
+ BKE_mesh_nomain_to_mesh(mesh_applied, me, ob, CD_MASK_MESH, true);
if (md->type == eModifierType_Multires)
multires_customdata_delete(me);
@@ -1331,7 +1332,7 @@ static int multires_external_save_exec(bContext *C, wmOperator *op)
RNA_string_get(op->ptr, "filepath", path);
if (relative)
- BLI_path_rel(path, bmain->name);
+ BLI_path_rel(path, BKE_main_blendfile_path(bmain));
CustomData_external_add(&me->ldata, &me->id, CD_MDISPS, me->totloop, path);
CustomData_external_write(&me->ldata, &me->id, CD_MASK_MESH, me->totloop, 0);
@@ -1783,7 +1784,7 @@ static Object *modifier_skin_armature_create(Depsgraph *depsgraph, Main *bmain,
MEM_freeN(emap);
MEM_freeN(emap_mem);
- ED_armature_from_edit(arm);
+ ED_armature_from_edit(bmain, arm);
ED_armature_edit_free(arm);
return arm_ob;
diff --git a/source/blender/editors/object/object_ops.c b/source/blender/editors/object/object_ops.c
index e0d3ecaf561..93ac141e7d9 100644
--- a/source/blender/editors/object/object_ops.c
+++ b/source/blender/editors/object/object_ops.c
@@ -290,23 +290,11 @@ void ED_keymap_object(wmKeyConfig *keyconf)
keymap = WM_keymap_find(keyconf, "Object Non-modal", 0, 0);
/* modes */
- {
- short key_mode_pair[][2] = {
- {ONEKEY, OB_MODE_OBJECT},
- {TWOKEY, OB_MODE_EDIT},
- {THREEKEY, OB_MODE_POSE},
- {THREEKEY, OB_MODE_WEIGHT_PAINT},
- {FOURKEY, OB_MODE_VERTEX_PAINT},
- {FIVEKEY, OB_MODE_TEXTURE_PAINT},
- {SIXKEY, OB_MODE_SCULPT},
- {SEVENKEY, OB_MODE_PARTICLE_EDIT},
- };
-
- for (uint i = 0; i < ARRAY_SIZE(key_mode_pair); i++) {
- kmi = WM_keymap_add_item(keymap, "OBJECT_OT_mode_set_or_submode", key_mode_pair[i][0], KM_PRESS, 0, 0);
- RNA_enum_set(kmi->ptr, "mode", key_mode_pair[i][1]);
- }
- }
+ kmi = WM_keymap_add_item(keymap, "OBJECT_OT_mode_set", TABKEY, KM_RELEASE, 0, 0);
+ RNA_enum_set(kmi->ptr, "mode", OB_MODE_EDIT);
+ RNA_boolean_set(kmi->ptr, "toggle", true);
+
+ kmi = WM_keymap_add_menu_pie(keymap, "VIEW3D_PIE_object_mode", TABKEY, KM_CLICK_DRAG, 0, 0);
WM_keymap_add_item(keymap, "OBJECT_OT_origin_set", CKEY, KM_PRESS, KM_ALT | KM_SHIFT | KM_CTRL, 0);
diff --git a/source/blender/editors/object/object_relations.c b/source/blender/editors/object/object_relations.c
index d417437ad99..4f441826bfd 100644
--- a/source/blender/editors/object/object_relations.c
+++ b/source/blender/editors/object/object_relations.c
@@ -640,7 +640,7 @@ bool ED_object_parent_set(ReportList *reports, const bContext *C, Scene *scene,
/* if follow, add F-Curve for ctime (i.e. "eval_time") so that path-follow works */
if (partype == PAR_FOLLOW) {
/* get or create F-Curve */
- bAction *act = verify_adt_action(&cu->id, 1);
+ bAction *act = verify_adt_action(bmain, &cu->id, 1);
FCurve *fcu = verify_fcurve(act, NULL, NULL, "eval_time", 0, 1);
/* setup dummy 'generator' modifier here to get 1-1 correspondence still working */
diff --git a/source/blender/editors/object/object_transform.c b/source/blender/editors/object/object_transform.c
index cb609b2567b..721d248ae4c 100644
--- a/source/blender/editors/object/object_transform.c
+++ b/source/blender/editors/object/object_transform.c
@@ -553,7 +553,7 @@ static int apply_objects_internal(
BKE_mesh_calc_normals(me);
}
else if (ob->type == OB_ARMATURE) {
- ED_armature_transform_apply(ob, mat, do_props);
+ ED_armature_transform_apply(bmain, ob, mat, do_props);
}
else if (ob->type == OB_LATTICE) {
Lattice *lt = ob->data;
@@ -1006,7 +1006,7 @@ static int object_origin_set_exec(bContext *C, wmOperator *op)
/* Function to recenter armatures in editarmature.c
* Bone + object locations are handled there.
*/
- ED_armature_origin_set(ob, cursor, centermode, around);
+ ED_armature_origin_set(bmain, ob, cursor, centermode, around);
tot_change++;
arm->id.tag |= LIB_TAG_DOIT;
diff --git a/source/blender/editors/object/object_vgroup.c b/source/blender/editors/object/object_vgroup.c
index e39d889d9d9..84786024160 100644
--- a/source/blender/editors/object/object_vgroup.c
+++ b/source/blender/editors/object/object_vgroup.c
@@ -58,6 +58,7 @@
#include "BKE_customdata.h"
#include "BKE_deform.h"
#include "BKE_mesh_mapping.h"
+#include "BKE_mesh_runtime.h"
#include "BKE_editmesh.h"
#include "BKE_layer.h"
#include "BKE_modifier.h"
diff --git a/source/blender/editors/physics/particle_edit.c b/source/blender/editors/physics/particle_edit.c
index c705434c509..359e9365ea7 100644
--- a/source/blender/editors/physics/particle_edit.c
+++ b/source/blender/editors/physics/particle_edit.c
@@ -57,9 +57,11 @@
#include "BKE_object.h"
#include "BKE_library.h"
#include "BKE_mesh.h"
+#include "BKE_mesh_runtime.h"
#include "BKE_modifier.h"
#include "BKE_particle.h"
#include "BKE_report.h"
+#include "BKE_scene.h"
#include "BKE_bvhutils.h"
#include "BKE_pointcache.h"
@@ -260,8 +262,7 @@ static PTCacheEdit *pe_get_current(
}
else {
if (create && !psys->edit) {
- ParticleSystem *psys_eval = psys_eval_get(depsgraph, ob, psys);
- if (psys_eval->flag & PSYS_HAIR_DONE) {
+ if (psys->flag & PSYS_HAIR_DONE) {
PE_create_particle_edit(depsgraph, scene, ob, NULL, psys);
}
}
@@ -643,11 +644,9 @@ static void foreach_mouse_hit_point(PEData *data, ForPointFunc func, int selecte
static void foreach_mouse_hit_key(PEData *data, ForKeyMatFunc func, int selected)
{
- Object *ob_eval = DEG_get_evaluated_object(data->depsgraph, data->ob);
PTCacheEdit *edit = data->edit;
ParticleSystem *psys = edit->psys;
ParticleSystemModifierData *psmd = NULL;
- ParticleSystemModifierData *psmd_eval = NULL;
ParticleEditSettings *pset= PE_settings(data->scene);
POINT_P; KEY_K;
float mat[4][4], imat[4][4];
@@ -658,10 +657,6 @@ static void foreach_mouse_hit_key(PEData *data, ForKeyMatFunc func, int selected
if (edit->psys)
psmd= psys_get_modifier(data->ob, edit->psys);
- if (psmd != NULL) {
- psmd_eval = (ParticleSystemModifierData *)modifiers_findByName(ob_eval, psmd->modifier.name);
- }
-
/* all is selected in path mode */
if (pset->selectmode==SCE_SELECT_PATH)
selected= 0;
@@ -675,7 +670,7 @@ static void foreach_mouse_hit_key(PEData *data, ForKeyMatFunc func, int selected
if (selected==0 || key->flag & PEK_SELECT) {
if (key_inside_circle(data, data->rad, KEY_WCO, &data->dist)) {
if (edit->psys && !(edit->psys->flag & PSYS_GLOBAL_HAIR)) {
- psys_mat_hair_to_global(data->ob, psmd_eval->mesh_final, psys->part->from, psys->particles + p, mat);
+ psys_mat_hair_to_global(data->ob, psmd->mesh_final, psys->part->from, psys->particles + p, mat);
invert_m4_m4(imat, mat);
}
@@ -690,7 +685,7 @@ static void foreach_mouse_hit_key(PEData *data, ForKeyMatFunc func, int selected
if (selected==0 || key->flag & PEK_SELECT) {
if (key_inside_circle(data, data->rad, KEY_WCO, &data->dist)) {
if (edit->psys && !(edit->psys->flag & PSYS_GLOBAL_HAIR)) {
- psys_mat_hair_to_global(data->ob, psmd_eval->mesh_final, psys->part->from, psys->particles + p, mat);
+ psys_mat_hair_to_global(data->ob, psmd->mesh_final, psys->part->from, psys->particles + p, mat);
invert_m4_m4(imat, mat);
}
@@ -1109,11 +1104,9 @@ void recalc_lengths(PTCacheEdit *edit)
}
/* calculate a tree for finding nearest emitter's vertice */
-void recalc_emitter_field(Depsgraph *depsgraph, Object *ob, ParticleSystem *psys)
+void recalc_emitter_field(Depsgraph *UNUSED(depsgraph), Object *ob, ParticleSystem *psys)
{
- Object *object_eval = DEG_get_evaluated_object(depsgraph, ob);
- ParticleSystem *psys_eval = psys_eval_get(depsgraph, ob, psys);
- Mesh *mesh = psys_get_modifier(object_eval, psys_eval)->mesh_final;
+ Mesh *mesh = psys_get_modifier(ob, psys)->mesh_final;
PTCacheEdit *edit = psys->edit;
float *vec, *nor;
int i, totface /*, totvert*/;
@@ -1201,27 +1194,19 @@ static void PE_update_selection(Depsgraph *depsgraph, Scene *scene, Object *ob,
DEG_id_tag_update(&ob->id, DEG_TAG_SELECT_UPDATE);
}
-void update_world_cos(Depsgraph *depsgraph, Object *ob, PTCacheEdit *edit)
+void update_world_cos(Depsgraph *UNUSED(depsgraph), Object *ob, PTCacheEdit *edit)
{
- Object *ob_eval = DEG_get_evaluated_object(depsgraph, ob);
ParticleSystem *psys = edit->psys;
- ParticleSystem *psys_eval = NULL;
ParticleSystemModifierData *psmd = psys_get_modifier(ob, psys);
- ParticleSystemModifierData *psmd_eval = NULL;
POINT_P; KEY_K;
float hairmat[4][4];
- if (psmd != NULL) {
- psmd_eval = (ParticleSystemModifierData *)modifiers_findByName(ob_eval, psmd->modifier.name);
- psys_eval = psmd_eval->psys;
- }
-
- if (psys == 0 || psys->edit == 0 || psmd_eval->mesh_final == NULL)
+ if (psys == 0 || psys->edit == 0 || psmd->mesh_final == NULL)
return;
LOOP_POINTS {
if (!(psys->flag & PSYS_GLOBAL_HAIR))
- psys_mat_hair_to_global(ob_eval, psmd_eval->mesh_final, psys->part->from, psys_eval->particles+p, hairmat);
+ psys_mat_hair_to_global(ob, psmd->mesh_final, psys->part->from, psys->particles+p, hairmat);
LOOP_KEYS {
copy_v3_v3(key->world_co, key->co);
@@ -4362,20 +4347,14 @@ void PE_create_particle_edit(
Depsgraph *depsgraph, Scene *scene, Object *ob, PointCache *cache, ParticleSystem *psys)
{
PTCacheEdit *edit;
- Object *ob_eval = DEG_get_evaluated_object(depsgraph, ob);
ParticleSystemModifierData *psmd = (psys) ? psys_get_modifier(ob, psys) : NULL;
- ParticleSystemModifierData *psmd_eval = NULL;
POINT_P; KEY_K;
ParticleData *pa = NULL;
HairKey *hkey;
int totpoint;
- if (psmd != NULL) {
- psmd_eval = (ParticleSystemModifierData *)modifiers_findByName(ob_eval, psmd->modifier.name);
- }
-
/* no psmd->dm happens in case particle system modifier is not enabled */
- if (!(psys && psmd_eval && psmd_eval->mesh_final) && !cache)
+ if (!(psys && psmd && psmd->mesh_final) && !cache)
return;
if (cache && cache->flag & PTCACHE_DISK_CACHE)
@@ -4505,7 +4484,16 @@ static int particle_edit_toggle_exec(bContext *C, wmOperator *op)
if (!is_mode_set) {
PTCacheEdit *edit;
+ /* Particle edit mode requires original object to have all strands
+ * cached. A bit annoying to do update here, but is simpler than
+ * rewriting the while edit mode code.
+ */
+ ob->id.recalc |= (ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
+ BKE_scene_graph_update_tagged(depsgraph, CTX_data_main(C));
+ BKE_object_eval_transform_all(depsgraph, scene, ob);
+ BKE_object_handle_data_update(depsgraph, scene, ob);
ob->mode |= mode_flag;
+
edit= PE_create_current(depsgraph, scene, ob);
/* mesh may have changed since last entering editmode.
diff --git a/source/blender/editors/physics/particle_object.c b/source/blender/editors/physics/particle_object.c
index 48a80cbbc1f..fbccdcfcdba 100644
--- a/source/blender/editors/physics/particle_object.c
+++ b/source/blender/editors/physics/particle_object.c
@@ -50,6 +50,7 @@
#include "BKE_library.h"
#include "BKE_main.h"
#include "BKE_mesh.h"
+#include "BKE_mesh_runtime.h"
#include "BKE_modifier.h"
#include "BKE_object.h"
#include "BKE_particle.h"
diff --git a/source/blender/editors/render/render_opengl.c b/source/blender/editors/render/render_opengl.c
index bb979087400..7e33549c5ac 100644
--- a/source/blender/editors/render/render_opengl.c
+++ b/source/blender/editors/render/render_opengl.c
@@ -404,7 +404,7 @@ static void screen_opengl_render_write(OGLRender *oglrender)
rr = RE_AcquireResultRead(oglrender->re);
BKE_image_path_from_imformat(
- name, scene->r.pic, oglrender->bmain->name, scene->r.cfra,
+ name, scene->r.pic, BKE_main_blendfile_path(oglrender->bmain), scene->r.cfra,
&scene->r.im_format, (scene->r.scemode & R_EXTENSION) != 0, false, NULL);
/* write images as individual images or stereo */
@@ -943,7 +943,7 @@ static void write_result_func(TaskPool * __restrict pool,
char name[FILE_MAX];
BKE_image_path_from_imformat(name,
scene->r.pic,
- oglrender->bmain->name,
+ BKE_main_blendfile_path(oglrender->bmain),
cfra,
&scene->r.im_format,
(scene->r.scemode & R_EXTENSION) != 0,
@@ -1030,7 +1030,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,
+ name, scene->r.pic, BKE_main_blendfile_path(oglrender->bmain), scene->r.cfra,
&scene->r.im_format, (scene->r.scemode & R_EXTENSION) != 0, true, NULL);
if ((scene->r.mode & R_NO_OVERWRITE) && BLI_exists(name)) {
diff --git a/source/blender/editors/render/render_preview.c b/source/blender/editors/render/render_preview.c
index b3601226932..4a3c7a3fd4b 100644
--- a/source/blender/editors/render/render_preview.c
+++ b/source/blender/editors/render/render_preview.c
@@ -122,7 +122,7 @@ ImBuf *get_brush_icon(Brush *brush)
// first use the path directly to try and load the file
BLI_strncpy(path, brush->icon_filepath, sizeof(brush->icon_filepath));
- BLI_path_abs(path, G.main->name);
+ BLI_path_abs(path, BKE_main_blendfile_path_from_global());
/* use default colorspaces for brushes */
brush->icon_imbuf = IMB_loadiffname(path, flags, NULL);
@@ -131,7 +131,7 @@ ImBuf *get_brush_icon(Brush *brush)
if (!(brush->icon_imbuf)) {
folder = BKE_appdir_folder_id(BLENDER_DATAFILES, "brushicons");
- BLI_make_file_string(G.main->name, path, folder, brush->icon_filepath);
+ BLI_make_file_string(BKE_main_blendfile_path_from_global(), path, folder, brush->icon_filepath);
if (path[0]) {
/* use fefault color spaces */
@@ -319,7 +319,7 @@ static Scene *preview_prepare_scene(Main *bmain, Scene *scene, ID *id, int id_ty
Scene *sce;
Main *pr_main = sp->pr_main;
- memcpy(pr_main->name, bmain->name, sizeof(pr_main->name));
+ memcpy(pr_main->name, BKE_main_blendfile_path(bmain), sizeof(pr_main->name));
sce = preview_get_scene(pr_main);
if (sce) {
diff --git a/source/blender/editors/screen/area.c b/source/blender/editors/screen/area.c
index 9a70d6f23de..034ccdf2e7b 100644
--- a/source/blender/editors/screen/area.c
+++ b/source/blender/editors/screen/area.c
@@ -1825,19 +1825,21 @@ static void ed_panel_draw(const bContext *C,
panel = UI_panel_begin(sa, ar, lb, block, pt, panel, &open);
/* bad fixed values */
- int triangle = (int)(UI_UNIT_Y * 1.1f);
int xco, yco, h = 0;
if (pt->draw_header && !(pt->flag & PNL_NO_HEADER) && (open || vertical)) {
+ int labelx, labely;
+ UI_panel_label_offset(block, &labelx, &labely);
+
/* for enabled buttons */
panel->layout = UI_block_layout(
block, UI_LAYOUT_HORIZONTAL, UI_LAYOUT_HEADER,
- triangle, (UI_UNIT_Y * 1.1f) + style->panelspace, UI_UNIT_Y, 1, 0, style);
+ labelx, labely, UI_UNIT_Y, 1, 0, style);
pt->draw_header(C, panel);
UI_block_layout_resolve(block, &xco, &yco);
- panel->labelofs = xco - triangle;
+ panel->labelofs = xco - labelx;
panel->layout = NULL;
}
else {
diff --git a/source/blender/editors/screen/screen_edit.c b/source/blender/editors/screen/screen_edit.c
index 06735eb8689..ac4ab3461a3 100644
--- a/source/blender/editors/screen/screen_edit.c
+++ b/source/blender/editors/screen/screen_edit.c
@@ -340,12 +340,12 @@ ScrArea *area_split(bScreen *sc, ScrArea *sa, char dir, float fac, int merge)
/**
* Empty screen, with 1 dummy area without spacedata. Uses window size.
*/
-bScreen *screen_add(const char *name, const rcti *rect)
+bScreen *screen_add(Main *bmain, const char *name, const rcti *rect)
{
bScreen *sc;
ScrVert *sv1, *sv2, *sv3, *sv4;
- sc = BKE_libblock_alloc(G.main, ID_SCR, name, 0);
+ sc = BKE_libblock_alloc(bmain, ID_SCR, name, 0);
sc->do_refresh = true;
sc->redraws_flag = TIME_ALL_3D_WIN | TIME_ALL_ANIM_WIN;
@@ -832,7 +832,7 @@ void ED_screen_refresh(wmWindowManager *wm, wmWindow *win)
}
/* file read, set all screens, ... */
-void ED_screens_initialize(wmWindowManager *wm)
+void ED_screens_initialize(Main *UNUSED(bmain), wmWindowManager *wm)
{
wmWindow *win;
@@ -1399,6 +1399,7 @@ void ED_screen_full_restore(bContext *C, ScrArea *sa)
*/
ScrArea *ED_screen_state_toggle(bContext *C, wmWindow *win, ScrArea *sa, const short state)
{
+ Main *bmain = CTX_data_main(C);
wmWindowManager *wm = CTX_wm_manager(C);
WorkSpace *workspace = WM_window_get_active_workspace(win);
bScreen *sc, *oldscreen;
@@ -1489,7 +1490,7 @@ ScrArea *ED_screen_state_toggle(bContext *C, wmWindow *win, ScrArea *sa, const s
oldscreen->state = state;
BLI_snprintf(newname, sizeof(newname), "%s-%s", oldscreen->id.name + 2, "nonnormal");
- layout_new = ED_workspace_layout_add(workspace, win, newname);
+ layout_new = ED_workspace_layout_add(bmain, workspace, win, newname);
sc = BKE_workspace_layout_screen_get(layout_new);
sc->state = state;
@@ -1502,7 +1503,7 @@ ScrArea *ED_screen_state_toggle(bContext *C, wmWindow *win, ScrArea *sa, const s
/* use random area when we have no active one, e.g. when the
* mouse is outside of the window and we open a file browser */
- if (!sa) {
+ if (!sa || sa->global) {
sa = oldscreen->areabase.first;
}
diff --git a/source/blender/editors/screen/screen_intern.h b/source/blender/editors/screen/screen_intern.h
index adfd7b185ab..b02198764e0 100644
--- a/source/blender/editors/screen/screen_intern.h
+++ b/source/blender/editors/screen/screen_intern.h
@@ -48,7 +48,7 @@ void screen_area_update_region_sizes(wmWindowManager *wm, wmWindow *win,
void region_toggle_hidden(struct bContext *C, ARegion *ar, const bool do_fade);
/* screen_edit.c */
-bScreen *screen_add(const char *name, const rcti *rect);
+bScreen *screen_add(struct Main *bmain, const char *name, const rcti *rect);
void screen_data_copy(bScreen *to, bScreen *from);
void screen_new_activate_prepare(const wmWindow *win, bScreen *screen_new);
void screen_change_update(struct bContext *C, wmWindow *win, bScreen *sc);
diff --git a/source/blender/editors/screen/screen_ops.c b/source/blender/editors/screen/screen_ops.c
index e504a116384..f6bd238170d 100644
--- a/source/blender/editors/screen/screen_ops.c
+++ b/source/blender/editors/screen/screen_ops.c
@@ -1069,6 +1069,7 @@ static void SCREEN_OT_area_swap(wmOperatorType *ot)
/* operator callback */
static int area_dupli_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
+ Main *bmain = CTX_data_main(C);
wmWindow *newwin, *win = CTX_wm_window(C);
Scene *scene;
WorkSpace *workspace = WM_window_get_active_workspace(win);
@@ -1110,7 +1111,7 @@ static int area_dupli_invoke(bContext *C, wmOperator *op, const wmEvent *event)
WM_window_set_active_workspace(newwin, workspace);
/* allocs new screen and adds to newly created window, using window size */
- layout_new = ED_workspace_layout_add(workspace, newwin, BKE_workspace_layout_name_get(layout_old));
+ layout_new = ED_workspace_layout_add(bmain, workspace, newwin, BKE_workspace_layout_name_get(layout_old));
newsc = BKE_workspace_layout_screen_get(layout_new);
WM_window_set_active_layout(newwin, workspace, layout_new);
@@ -4301,12 +4302,13 @@ static void SCREEN_OT_drivers_editor_show(struct wmOperatorType *ot)
static int screen_new_exec(bContext *C, wmOperator *UNUSED(op))
{
+ Main *bmain = CTX_data_main(C);
wmWindow *win = CTX_wm_window(C);
WorkSpace *workspace = BKE_workspace_active_get(win->workspace_hook);
WorkSpaceLayout *layout_old = BKE_workspace_active_layout_get(win->workspace_hook);
WorkSpaceLayout *layout_new;
- layout_new = ED_workspace_layout_duplicate(workspace, layout_old, win);
+ layout_new = ED_workspace_layout_duplicate(bmain, workspace, layout_old, win);
WM_event_add_notifier(C, NC_SCREEN | ND_LAYOUTBROWSE, layout_new);
return OPERATOR_FINISHED;
diff --git a/source/blender/editors/screen/screendump.c b/source/blender/editors/screen/screendump.c
index 63b9fe4043c..7e50f8d41c4 100644
--- a/source/blender/editors/screen/screendump.c
+++ b/source/blender/editors/screen/screendump.c
@@ -194,7 +194,7 @@ static int screenshot_exec(bContext *C, wmOperator *op)
char path[FILE_MAX];
RNA_string_get(op->ptr, "filepath", path);
- BLI_path_abs(path, G.main->name);
+ BLI_path_abs(path, BKE_main_blendfile_path_from_global());
/* operator ensures the extension */
ibuf = IMB_allocImBuf(scd->dumpsx, scd->dumpsy, 24, 0);
@@ -233,7 +233,7 @@ static int screenshot_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(
/* extension is added by 'screenshot_check' after */
char filepath[FILE_MAX] = "//screen";
if (G.relbase_valid) {
- BLI_strncpy(filepath, G.main->name, sizeof(filepath));
+ BLI_strncpy(filepath, BKE_main_blendfile_path_from_global(), sizeof(filepath));
BLI_replace_extension(filepath, sizeof(filepath), ""); /* strip '.blend' */
}
RNA_string_set(op->ptr, "filepath", filepath);
@@ -409,7 +409,7 @@ static void screenshot_startjob(void *sjv, short *stop, short *do_update, float
int ok;
BKE_image_path_from_imformat(
- name, rd.pic, sj->bmain->name, rd.cfra,
+ name, rd.pic, BKE_main_blendfile_path(sj->bmain), rd.cfra,
&rd.im_format, (rd.scemode & R_EXTENSION) != 0, true, NULL);
ibuf->rect = sj->dumprect;
diff --git a/source/blender/editors/screen/workspace_edit.c b/source/blender/editors/screen/workspace_edit.c
index d54996bad59..a044a7d377a 100644
--- a/source/blender/editors/screen/workspace_edit.c
+++ b/source/blender/editors/screen/workspace_edit.c
@@ -131,7 +131,7 @@ static bool workspace_change_find_new_layout_cb(const WorkSpaceLayout *layout, v
}
static WorkSpaceLayout *workspace_change_get_new_layout(
- WorkSpace *workspace_new, wmWindow *win)
+ Main *bmain, WorkSpace *workspace_new, wmWindow *win)
{
/* ED_workspace_duplicate may have stored a layout to activate once the workspace gets activated. */
WorkSpaceLayout *layout_new;
@@ -155,7 +155,7 @@ static WorkSpaceLayout *workspace_change_get_new_layout(
NULL, false);
if (!layout_temp) {
/* fallback solution: duplicate layout */
- layout_temp = ED_workspace_layout_duplicate(workspace_new, layout_new, win);
+ layout_temp = ED_workspace_layout_duplicate(bmain, workspace_new, layout_new, win);
}
layout_new = layout_temp;
}
@@ -177,7 +177,7 @@ bool ED_workspace_change(
{
Main *bmain = CTX_data_main(C);
WorkSpace *workspace_old = WM_window_get_active_workspace(win);
- WorkSpaceLayout *layout_new = workspace_change_get_new_layout(workspace_new, win);
+ WorkSpaceLayout *layout_new = workspace_change_get_new_layout(bmain, workspace_new, win);
bScreen *screen_new = BKE_workspace_layout_screen_get(layout_new);
bScreen *screen_old = BKE_workspace_active_screen_get(win->workspace_hook);
@@ -228,7 +228,7 @@ WorkSpace *ED_workspace_duplicate(
/* TODO(campbell): tools */
for (WorkSpaceLayout *layout_old = layouts_old->first; layout_old; layout_old = layout_old->next) {
- WorkSpaceLayout *layout_new = ED_workspace_layout_duplicate(workspace_new, layout_old, win);
+ WorkSpaceLayout *layout_new = ED_workspace_layout_duplicate(bmain, workspace_new, layout_old, win);
if (layout_active_old == layout_old) {
win->workspace_hook->temp_layout_store = layout_new;
diff --git a/source/blender/editors/screen/workspace_layout_edit.c b/source/blender/editors/screen/workspace_layout_edit.c
index 6285f031836..0c7431cb2e7 100644
--- a/source/blender/editors/screen/workspace_layout_edit.c
+++ b/source/blender/editors/screen/workspace_layout_edit.c
@@ -46,6 +46,7 @@
* Empty screen, with 1 dummy area without spacedata. Uses window size.
*/
WorkSpaceLayout *ED_workspace_layout_add(
+ Main *bmain,
WorkSpace *workspace,
wmWindow *win,
const char *name)
@@ -54,12 +55,13 @@ WorkSpaceLayout *ED_workspace_layout_add(
rcti screen_rect;
WM_window_screen_rect_calc(win, &screen_rect);
- screen = screen_add(name, &screen_rect);
+ screen = screen_add(bmain, name, &screen_rect);
return BKE_workspace_layout_add(workspace, screen, name);
}
WorkSpaceLayout *ED_workspace_layout_duplicate(
+ Main *bmain,
WorkSpace *workspace, const WorkSpaceLayout *layout_old,
wmWindow *win)
{
@@ -72,7 +74,7 @@ WorkSpaceLayout *ED_workspace_layout_duplicate(
return NULL; /* XXX handle this case! */
}
- layout_new = ED_workspace_layout_add(workspace, win, name);
+ layout_new = ED_workspace_layout_add(bmain, workspace, win, name);
screen_new = BKE_workspace_layout_screen_get(layout_new);
screen_data_copy(screen_new, screen_old);
diff --git a/source/blender/editors/sculpt_paint/paint_hide.c b/source/blender/editors/sculpt_paint/paint_hide.c
index 3d4f6c05ff4..ac5b0624d56 100644
--- a/source/blender/editors/sculpt_paint/paint_hide.c
+++ b/source/blender/editors/sculpt_paint/paint_hide.c
@@ -48,6 +48,7 @@
#include "BKE_context.h"
#include "BKE_DerivedMesh.h"
#include "BKE_mesh.h"
+#include "BKE_mesh_runtime.h"
#include "BKE_multires.h"
#include "BKE_paint.h"
#include "BKE_subsurf.h"
@@ -368,7 +369,6 @@ static int hide_show_exec(bContext *C, wmOperator *op)
PartialVisArea area;
PBVH *pbvh;
PBVHNode **nodes;
- DerivedMesh *dm;
PBVHType pbvh_type;
float clip_planes[4][4];
rcti rect;
@@ -381,9 +381,9 @@ static int hide_show_exec(bContext *C, wmOperator *op)
clip_planes_from_rect(C, clip_planes, &rect);
- dm = mesh_get_derived_final(depsgraph, CTX_data_scene(C), ob, CD_MASK_BAREMESH);
- pbvh = dm->getPBVH(ob, dm);
- ob->sculpt->pbvh = pbvh;
+ Mesh *me_eval_deform = mesh_get_eval_deform(depsgraph, CTX_data_scene(C), ob, CD_MASK_BAREMESH);
+ pbvh = BKE_sculpt_object_pbvh_ensure(ob, me_eval_deform);
+ BLI_assert(ob->sculpt->pbvh == pbvh);
get_pbvh_nodes(pbvh, &nodes, &totnode, clip_planes, area);
pbvh_type = BKE_pbvh_type(pbvh);
diff --git a/source/blender/editors/sculpt_paint/paint_image_proj.c b/source/blender/editors/sculpt_paint/paint_image_proj.c
index 0e48596ca1a..32355d41ada 100644
--- a/source/blender/editors/sculpt_paint/paint_image_proj.c
+++ b/source/blender/editors/sculpt_paint/paint_image_proj.c
@@ -74,6 +74,7 @@
#include "BKE_material.h"
#include "BKE_mesh.h"
#include "BKE_mesh_mapping.h"
+#include "BKE_mesh_runtime.h"
#include "BKE_node.h"
#include "BKE_paint.h"
#include "BKE_report.h"
diff --git a/source/blender/editors/sculpt_paint/paint_vertex.c b/source/blender/editors/sculpt_paint/paint_vertex.c
index 53b73562322..02dae51c594 100644
--- a/source/blender/editors/sculpt_paint/paint_vertex.c
+++ b/source/blender/editors/sculpt_paint/paint_vertex.c
@@ -59,6 +59,7 @@
#include "BKE_main.h"
#include "BKE_mesh.h"
#include "BKE_mesh_mapping.h"
+#include "BKE_object.h"
#include "BKE_object_deform.h"
#include "BKE_paint.h"
#include "BKE_report.h"
@@ -974,7 +975,7 @@ static void vertex_paint_init_session(Depsgraph *depsgraph, Scene *scene, Object
if (ob->sculpt == NULL) {
ob->sculpt = MEM_callocN(sizeof(SculptSession), "sculpt session");
- BKE_sculpt_update_mesh_elements(depsgraph, scene, scene->toolsettings->sculpt, ob, 0, false);
+ BKE_sculpt_update_mesh_elements(depsgraph, scene, scene->toolsettings->sculpt, ob, false, false);
}
}
@@ -1067,6 +1068,11 @@ static void ed_vwpaintmode_enter_generic(
ob->mode |= mode_flag;
Mesh *me = BKE_mesh_from_object(ob);
+ /* Same as sculpt mode, make sure we don't have cached derived mesh which
+ * points to freed arrays.
+ */
+ BKE_object_free_derived_caches(ob);
+
if (mode_flag == OB_MODE_VERTEX_PAINT) {
const ePaintMode paint_mode = ePaintVertex;
ED_mesh_color_ensure(me, NULL);
@@ -1108,6 +1114,9 @@ static void ed_vwpaintmode_enter_generic(
}
vertex_paint_init_session(depsgraph, scene, ob);
+
+ /* Flush object mode. */
+ DEG_id_tag_update(&ob->id, DEG_TAG_COPY_ON_WRITE);
}
void ED_object_vpaintmode_enter_ex(
@@ -1189,6 +1198,10 @@ static void ed_vwpaintmode_exit_generic(
ED_mesh_mirror_topo_table(NULL, NULL, 'e');
}
+ /* Never leave derived meshes behind. */
+ BKE_object_free_derived_caches(ob);
+
+ /* Flush object mode. */
DEG_id_tag_update(&ob->id, DEG_TAG_COPY_ON_WRITE);
}
@@ -3139,6 +3152,10 @@ static void vpaint_stroke_update_step(bContext *C, struct PaintStroke *stroke, P
* avoid this if we can! */
DEG_id_tag_update(ob->data, 0);
}
+ else {
+ /* Flush changes through DEG. */
+ DEG_id_tag_update(ob->data, DEG_TAG_COPY_ON_WRITE);
+ }
}
static void vpaint_stroke_done(const bContext *C, struct PaintStroke *stroke)
diff --git a/source/blender/editors/sculpt_paint/paint_vertex_color_ops.c b/source/blender/editors/sculpt_paint/paint_vertex_color_ops.c
index d7668a48139..8516d92214d 100644
--- a/source/blender/editors/sculpt_paint/paint_vertex_color_ops.c
+++ b/source/blender/editors/sculpt_paint/paint_vertex_color_ops.c
@@ -152,6 +152,7 @@ static bool vertex_paint_from_weight(Object *ob)
}
/* TODO: respect selection. */
+ /* TODO: Do we want to take weights from evaluated mesh instead? 2.7x was not doing it anyway... */
mp = me->mpoly;
vgroup_active = ob->actdef - 1;
for (int i = 0; i < me->totpoly; i++, mp++) {
diff --git a/source/blender/editors/sculpt_paint/paint_vertex_proj.c b/source/blender/editors/sculpt_paint/paint_vertex_proj.c
index c5c9aa48760..cacfdc2dbba 100644
--- a/source/blender/editors/sculpt_paint/paint_vertex_proj.c
+++ b/source/blender/editors/sculpt_paint/paint_vertex_proj.c
@@ -41,6 +41,7 @@
#include "BKE_DerivedMesh.h"
#include "BKE_context.h"
+#include "BKE_mesh_runtime.h"
#include "DEG_depsgraph.h"
diff --git a/source/blender/editors/sculpt_paint/paint_vertex_weight_ops.c b/source/blender/editors/sculpt_paint/paint_vertex_weight_ops.c
index e560a4cddff..7c2977a0788 100644
--- a/source/blender/editors/sculpt_paint/paint_vertex_weight_ops.c
+++ b/source/blender/editors/sculpt_paint/paint_vertex_weight_ops.c
@@ -52,6 +52,7 @@
#include "BKE_deform.h"
#include "BKE_mesh.h"
#include "BKE_mesh_mapping.h"
+#include "BKE_mesh_runtime.h"
#include "BKE_modifier.h"
#include "BKE_object_deform.h"
#include "BKE_paint.h"
diff --git a/source/blender/editors/sculpt_paint/sculpt.c b/source/blender/editors/sculpt_paint/sculpt.c
index 5dd7f23864c..3475aadd171 100644
--- a/source/blender/editors/sculpt_paint/sculpt.c
+++ b/source/blender/editors/sculpt_paint/sculpt.c
@@ -5210,14 +5210,12 @@ static void sculpt_dynamic_topology_triangulate(BMesh *bm)
void sculpt_pbvh_clear(Object *ob)
{
SculptSession *ss = ob->sculpt;
- DerivedMesh *dm = ob->derivedFinal;
/* Clear out any existing DM and PBVH */
- if (ss->pbvh)
+ if (ss->pbvh) {
BKE_pbvh_free(ss->pbvh);
+ }
ss->pbvh = NULL;
- if (dm)
- dm->getPBVH(NULL, dm);
BKE_object_free_derived_caches(ob);
}
@@ -5629,7 +5627,7 @@ static void sculpt_init_session(Depsgraph *depsgraph, Scene *scene, Object *ob)
ob->sculpt = MEM_callocN(sizeof(SculptSession), "sculpt session");
ob->sculpt->mode_type = OB_MODE_SCULPT;
- BKE_sculpt_update_mesh_elements(depsgraph, scene, scene->toolsettings->sculpt, ob, 0, false);
+ BKE_sculpt_update_mesh_elements(depsgraph, scene, scene->toolsettings->sculpt, ob, false, false);
}
static int ed_object_sculptmode_flush_recalc_flag(Scene *scene, Object *ob, MultiresModifierData *mmd)
@@ -5643,7 +5641,7 @@ static int ed_object_sculptmode_flush_recalc_flag(Scene *scene, Object *ob, Mult
}
void ED_object_sculptmode_enter_ex(
- Depsgraph *depsgraph,
+ Main *bmain, Depsgraph *depsgraph,
Scene *scene, Object *ob,
ReportList *reports)
{
@@ -5665,6 +5663,11 @@ void ED_object_sculptmode_enter_ex(
BKE_sculptsession_free(ob);
}
+ /* Make sure derived final from original object does not reference possibly
+ * freed memory.
+ */
+ BKE_object_free_derived_mesh_caches(ob);
+
sculpt_init_session(depsgraph, scene, ob);
/* Mask layer is required */
@@ -5686,7 +5689,7 @@ void ED_object_sculptmode_enter_ex(
Paint *paint = BKE_paint_get_active_from_paintmode(scene, ePaintSculpt);
BKE_paint_init(scene, ePaintSculpt, PAINT_CURSOR_SCULPT);
- paint_cursor_start_explicit(paint, G.main->wm.first, sculpt_poll_view3d);
+ paint_cursor_start_explicit(paint, bmain->wm.first, sculpt_poll_view3d);
/* Check dynamic-topology flag; re-enter dynamic-topology mode when changing modes,
* As long as no data was added that is not supported. */
@@ -5735,14 +5738,18 @@ void ED_object_sculptmode_enter_ex(
}
// ED_workspace_object_mode_sync_from_object(G.main->wm.first, workspace, ob);
+
+ /* Flush object mode. */
+ DEG_id_tag_update(&ob->id, DEG_TAG_COPY_ON_WRITE);
}
void ED_object_sculptmode_enter(struct bContext *C, ReportList *reports)
{
+ Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
Object *ob = CTX_data_active_object(C);
Depsgraph *depsgraph = CTX_data_depsgraph(C);
- ED_object_sculptmode_enter_ex(depsgraph, scene, ob, reports);
+ ED_object_sculptmode_enter_ex(bmain, depsgraph, scene, ob, reports);
}
void ED_object_sculptmode_exit_ex(
@@ -5788,6 +5795,10 @@ void ED_object_sculptmode_exit_ex(
paint_cursor_delete_textures();
+ /* Never leave derived meshes behind. */
+ BKE_object_free_derived_mesh_caches(ob);
+
+ /* Flush object mode. */
DEG_id_tag_update(&ob->id, DEG_TAG_COPY_ON_WRITE);
}
@@ -5802,6 +5813,7 @@ void ED_object_sculptmode_exit(bContext *C)
static int sculpt_mode_toggle_exec(bContext *C, wmOperator *op)
{
struct wmMsgBus *mbus = CTX_wm_message_bus(C);
+ Main *bmain = CTX_data_main(C);
Depsgraph *depsgraph = CTX_data_depsgraph_on_load(C);
Scene *scene = CTX_data_scene(C);
Object *ob = CTX_data_active_object(C);
@@ -5818,7 +5830,7 @@ static int sculpt_mode_toggle_exec(bContext *C, wmOperator *op)
ED_object_sculptmode_exit_ex(depsgraph, scene, ob);
}
else {
- ED_object_sculptmode_enter_ex(depsgraph, scene, ob, op->reports);
+ ED_object_sculptmode_enter_ex(bmain, depsgraph, scene, ob, op->reports);
}
WM_event_add_notifier(C, NC_SCENE | ND_MODE, scene);
diff --git a/source/blender/editors/sculpt_paint/sculpt_undo.c b/source/blender/editors/sculpt_paint/sculpt_undo.c
index fbdca27b018..2872ad4fb9c 100644
--- a/source/blender/editors/sculpt_paint/sculpt_undo.c
+++ b/source/blender/editors/sculpt_paint/sculpt_undo.c
@@ -58,6 +58,7 @@
#include "BKE_paint.h"
#include "BKE_key.h"
#include "BKE_mesh.h"
+#include "BKE_mesh_runtime.h"
#include "BKE_subsurf.h"
#include "BKE_undo_system.h"
@@ -157,7 +158,7 @@ static bool sculpt_undo_restore_coords(bContext *C, DerivedMesh *dm, SculptUndoN
if (kb) {
ob->shapenr = BLI_findindex(&key->block, kb) + 1;
- BKE_sculpt_update_mesh_elements(depsgraph, scene, sd, ob, 0, false);
+ BKE_sculpt_update_mesh_elements(depsgraph, scene, sd, ob, false, false);
WM_event_add_notifier(C, NC_OBJECT | ND_DATA, ob);
}
else {
@@ -197,7 +198,7 @@ static bool sculpt_undo_restore_coords(bContext *C, DerivedMesh *dm, SculptUndoN
/* pbvh uses it's own mvert array, so coords should be */
/* propagated to pbvh here */
- BKE_pbvh_apply_vertCos(ss->pbvh, vertCos);
+ BKE_pbvh_apply_vertCos(ss->pbvh, vertCos, unode->totvert);
MEM_freeN(vertCos);
}
@@ -492,7 +493,9 @@ static void sculpt_undo_restore_list(bContext *C, ListBase *lb)
}
}
- BKE_sculpt_update_mesh_elements(depsgraph, scene, sd, ob, 0, need_mask);
+ DEG_id_tag_update(&ob->id, DEG_TAG_COPY_ON_WRITE);
+
+ BKE_sculpt_update_mesh_elements(depsgraph, scene, sd, ob, false, need_mask);
/* call _after_ sculpt_update_mesh_elements() which may update 'ob->derivedFinal' */
dm = mesh_get_derived_final(depsgraph, scene, ob, 0);
diff --git a/source/blender/editors/sound/sound_ops.c b/source/blender/editors/sound/sound_ops.c
index 07d12de3662..b7a80a92998 100644
--- a/source/blender/editors/sound/sound_ops.c
+++ b/source/blender/editors/sound/sound_ops.c
@@ -375,7 +375,7 @@ static int sound_mixdown_exec(bContext *C, wmOperator *op)
specs.rate = scene->r.ffcodecdata.audio_mixrate;
BLI_strncpy(filename, path, sizeof(filename));
- BLI_path_abs(filename, bmain->name);
+ BLI_path_abs(filename, BKE_main_blendfile_path(bmain));
if (split)
result = AUD_mixdown_per_channel(scene->sound_scene, SFRA * specs.rate / FPS, (EFRA - SFRA + 1) * specs.rate / FPS,
diff --git a/source/blender/editors/space_action/action_edit.c b/source/blender/editors/space_action/action_edit.c
index b3c1c536ad8..a9f9488d049 100644
--- a/source/blender/editors/space_action/action_edit.c
+++ b/source/blender/editors/space_action/action_edit.c
@@ -57,8 +57,9 @@
#include "BKE_fcurve.h"
#include "BKE_gpencil.h"
#include "BKE_global.h"
-#include "BKE_library.h"
#include "BKE_key.h"
+#include "BKE_library.h"
+#include "BKE_main.h"
#include "BKE_nla.h"
#include "BKE_context.h"
#include "BKE_report.h"
@@ -718,7 +719,8 @@ static void insert_action_keys(bAnimContext *ac, short mode)
* (TODO: add the full-blown PointerRNA relative parsing case here...)
*/
if (ale->id && !ale->owner) {
- insert_keyframe(depsgraph, reports, ale->id, NULL, ((fcu->grp) ? (fcu->grp->name) : (NULL)), fcu->rna_path, fcu->array_index, cfra, ts->keyframe_type, flag);
+ insert_keyframe(ac->bmain, depsgraph, reports, ale->id, NULL, ((fcu->grp) ? (fcu->grp->name) : (NULL)),
+ fcu->rna_path, fcu->array_index, cfra, ts->keyframe_type, flag);
}
else {
const float curval = evaluate_fcurve(fcu, cfra);
diff --git a/source/blender/editors/space_action/action_ops.c b/source/blender/editors/space_action/action_ops.c
index 25218358ed4..bf7f75db95c 100644
--- a/source/blender/editors/space_action/action_ops.c
+++ b/source/blender/editors/space_action/action_ops.c
@@ -216,6 +216,9 @@ static void action_keymap_keyframes(wmKeyConfig *keyconf, wmKeyMap *keymap)
WM_keymap_add_item(keymap, "ACTION_OT_extrapolation_type", EKEY, KM_PRESS, KM_SHIFT, 0);
WM_keymap_add_item(keymap, "ACTION_OT_keyframe_type", RKEY, KM_PRESS, 0, 0);
+ /* specials */
+ WM_keymap_add_menu(keymap, "DOPESHEET_MT_specials", WKEY, KM_PRESS, 0, 0);
+
/* destructive */
WM_keymap_add_item(keymap, "ACTION_OT_sample", OKEY, KM_PRESS, KM_SHIFT, 0);
@@ -289,4 +292,3 @@ void action_keymap(wmKeyConfig *keyconf)
keymap = WM_keymap_find(keyconf, "Dopesheet", SPACE_ACTION, 0);
action_keymap_keyframes(keyconf, keymap);
}
-
diff --git a/source/blender/editors/space_action/space_action.c b/source/blender/editors/space_action/space_action.c
index ffcaf53513a..e130ea9369c 100644
--- a/source/blender/editors/space_action/space_action.c
+++ b/source/blender/editors/space_action/space_action.c
@@ -295,6 +295,8 @@ static void action_channel_region_init(wmWindowManager *wm, ARegion *ar)
keymap = WM_keymap_find(wm->defaultconf, "Animation Channels", 0, 0);
WM_event_add_keymap_handler_bb(&ar->handlers, keymap, &ar->v2d.mask, &ar->winrct);
+ WM_keymap_add_menu(keymap, "DOPESHEET_MT_specials_channels", WKEY, KM_PRESS, 0, 0);
+
keymap = WM_keymap_find(wm->defaultconf, "Dopesheet Generic", SPACE_ACTION, 0);
WM_event_add_keymap_handler(&ar->handlers, keymap);
}
@@ -903,4 +905,3 @@ void ED_spacetype_action(void)
BKE_spacetype_register(st);
}
-
diff --git a/source/blender/editors/space_buttons/buttons_context.c b/source/blender/editors/space_buttons/buttons_context.c
index 9caf381c93d..dd943e7988d 100644
--- a/source/blender/editors/space_buttons/buttons_context.c
+++ b/source/blender/editors/space_buttons/buttons_context.c
@@ -489,7 +489,7 @@ static int buttons_context_path(const bContext *C, ButsContextPath *path, int ma
}
/* No pinned root, use scene as initial root. */
else {
- if (mainb == BCONTEXT_WORKSPACE) {
+ if (ELEM(mainb, BCONTEXT_WORKSPACE, BCONTEXT_TOOL)) {
RNA_id_pointer_create(&workspace->id, &path->ptr[0]);
path->len++;
}
@@ -525,6 +525,7 @@ static int buttons_context_path(const bContext *C, ButsContextPath *path, int ma
case BCONTEXT_WORLD:
found = buttons_context_path_world(path);
break;
+ case BCONTEXT_TOOL:
case BCONTEXT_WORKSPACE:
found = buttons_context_path_workspace(path);
break;
diff --git a/source/blender/editors/space_buttons/buttons_ops.c b/source/blender/editors/space_buttons/buttons_ops.c
index 813f4202a49..47f97b8087f 100644
--- a/source/blender/editors/space_buttons/buttons_ops.c
+++ b/source/blender/editors/space_buttons/buttons_ops.c
@@ -102,6 +102,7 @@ typedef struct FileBrowseOp {
static int file_browse_exec(bContext *C, wmOperator *op)
{
+ Main *bmain = CTX_data_main(C);
FileBrowseOp *fbo = op->customdata;
ID *id;
char *str, path[FILE_MAX];
@@ -118,14 +119,14 @@ static int file_browse_exec(bContext *C, wmOperator *op)
id = fbo->ptr.id.data;
BLI_strncpy(path, str, FILE_MAX);
- BLI_path_abs(path, id ? ID_BLEND_PATH(G.main, id) : G.main->name);
+ BLI_path_abs(path, id ? ID_BLEND_PATH(bmain, id) : BKE_main_blendfile_path(bmain));
if (BLI_is_dir(path)) {
/* do this first so '//' isnt converted to '//\' on windows */
BLI_add_slash(path);
if (is_relative) {
BLI_strncpy(path, str, FILE_MAX);
- BLI_path_rel(path, G.main->name);
+ BLI_path_rel(path, BKE_main_blendfile_path(bmain));
str = MEM_reallocN(str, strlen(path) + 2);
BLI_strncpy(str, path, FILE_MAX);
}
diff --git a/source/blender/editors/space_buttons/space_buttons.c b/source/blender/editors/space_buttons/space_buttons.c
index 11857dd0b27..be687d365f3 100644
--- a/source/blender/editors/space_buttons/space_buttons.c
+++ b/source/blender/editors/space_buttons/space_buttons.c
@@ -52,6 +52,8 @@
#include "UI_resources.h"
+#include "GPU_glew.h"
+
#include "buttons_intern.h" /* own include */
/* ******************** default callbacks for buttons space ***************** */
@@ -144,7 +146,6 @@ static void buttons_main_region_init(wmWindowManager *wm, ARegion *ar)
static void buttons_main_region_draw_properties(const bContext *C, SpaceButs *sbuts, ARegion *ar)
{
- BLI_assert(sbuts->space_subtype == SB_SUBTYPE_DATA);
const bool vertical = (sbuts->align == BUT_VERTICAL);
buttons_context_compute(C, sbuts);
@@ -197,6 +198,9 @@ static void buttons_main_region_draw_properties(const bContext *C, SpaceButs *sb
case BCONTEXT_BONE_CONSTRAINT:
contexts[0] = "bone_constraint";
break;
+ case BCONTEXT_TOOL:
+ contexts[0] = "tool";
+ break;
}
if (contexts[0]) {
@@ -206,13 +210,12 @@ static void buttons_main_region_draw_properties(const bContext *C, SpaceButs *sb
static void buttons_main_region_draw_tool(const bContext *C, SpaceButs *sbuts, ARegion *ar)
{
- BLI_assert(sbuts->space_subtype == SB_SUBTYPE_TOOL);
const bool vertical = (sbuts->align == BUT_VERTICAL);
+ const char *contexts[3] = {NULL};
const WorkSpace *workspace = CTX_wm_workspace(C);
if (workspace->tools_space_type == SPACE_VIEW3D) {
const int mode = CTX_data_mode_enum(C);
- const char *contexts[3] = {NULL};
switch (mode) {
case CTX_MODE_EDIT_MESH:
ARRAY_SET_ITEMS(contexts, ".mesh_edit");
@@ -264,6 +267,11 @@ static void buttons_main_region_draw_tool(const bContext *C, SpaceButs *sbuts, A
else if (workspace->tools_space_type == SPACE_IMAGE) {
/* TODO */
}
+
+ if (contexts[0] == NULL) {
+ UI_ThemeClearColor(TH_BACK);
+ glClear(GL_COLOR_BUFFER_BIT);
+ }
}
static void buttons_main_region_draw(const bContext *C, ARegion *ar)
@@ -271,12 +279,12 @@ static void buttons_main_region_draw(const bContext *C, ARegion *ar)
/* draw entirely, view changes should be handled here */
SpaceButs *sbuts = CTX_wm_space_buts(C);
- if (sbuts->space_subtype == SB_SUBTYPE_DATA) {
- buttons_main_region_draw_properties(C, sbuts, ar);
- }
- else if (sbuts->space_subtype == SB_SUBTYPE_TOOL) {
+ if (sbuts->mainb == BCONTEXT_TOOL) {
buttons_main_region_draw_tool(C, sbuts, ar);
}
+ else {
+ buttons_main_region_draw_properties(C, sbuts, ar);
+ }
sbuts->re_align = 0;
sbuts->mainbo = sbuts->mainb;
@@ -320,10 +328,8 @@ static void buttons_header_region_draw(const bContext *C, ARegion *ar)
{
SpaceButs *sbuts = CTX_wm_space_buts(C);
- if (sbuts->space_subtype == SB_SUBTYPE_DATA) {
- /* Needed for RNA to get the good values! */
- buttons_context_compute(C, sbuts);
- }
+ /* Needed for RNA to get the good values! */
+ buttons_context_compute(C, sbuts);
ED_region_header(C, ar);
}
@@ -590,24 +596,6 @@ static void buttons_id_remap(ScrArea *UNUSED(sa), SpaceLink *slink, ID *old_id,
}
}
-static int buttons_space_subtype_get(ScrArea *sa)
-{
- SpaceButs *sbuts = sa->spacedata.first;
- return sbuts->space_subtype;
-}
-
-static void buttons_space_subtype_set(ScrArea *sa, int value)
-{
- SpaceButs *sbuts = sa->spacedata.first;
- sbuts->space_subtype = value;
-}
-
-static void buttons_space_subtype_item_extend(
- bContext *UNUSED(C), EnumPropertyItem **item, int *totitem)
-{
- RNA_enum_items_add(item, totitem, rna_enum_space_button_mode_items);
-}
-
/* only called once, from space/spacetypes.c */
void ED_spacetype_buttons(void)
{
@@ -626,9 +614,6 @@ void ED_spacetype_buttons(void)
st->listener = buttons_area_listener;
st->context = buttons_context;
st->id_remap = buttons_id_remap;
- st->space_subtype_item_extend = buttons_space_subtype_item_extend;
- st->space_subtype_get = buttons_space_subtype_get;
- st->space_subtype_set = buttons_space_subtype_set;
/* regions: main window */
art = MEM_callocN(sizeof(ARegionType), "spacetype buttons region");
diff --git a/source/blender/editors/space_clip/clip_ops.c b/source/blender/editors/space_clip/clip_ops.c
index 0d9371a7784..498a4d6fbbd 100644
--- a/source/blender/editors/space_clip/clip_ops.c
+++ b/source/blender/editors/space_clip/clip_ops.c
@@ -318,7 +318,7 @@ static int reload_exec(bContext *C, wmOperator *UNUSED(op))
if (!clip)
return OPERATOR_CANCELLED;
- BKE_movieclip_reload(clip);
+ BKE_movieclip_reload(CTX_data_main(C), clip);
WM_event_add_notifier(C, NC_MOVIECLIP | NA_EDITED, clip);
@@ -1315,7 +1315,7 @@ static void proxy_endjob(void *pjv)
if (pj->clip->source == MCLIP_SRC_MOVIE) {
/* Timecode might have changed, so do a full reload to deal with this. */
- BKE_movieclip_reload(pj->clip);
+ BKE_movieclip_reload(pj->main, pj->clip);
}
else {
/* For image sequences we'll preserve original cache. */
diff --git a/source/blender/editors/space_file/file_draw.c b/source/blender/editors/space_file/file_draw.c
index fcfe745546e..360009d3ea4 100644
--- a/source/blender/editors/space_file/file_draw.c
+++ b/source/blender/editors/space_file/file_draw.c
@@ -424,6 +424,7 @@ static void file_draw_preview(
static void renamebutton_cb(bContext *C, void *UNUSED(arg1), char *oldname)
{
+ Main *bmain = CTX_data_main(C);
char newname[FILE_MAX + 12];
char orgname[FILE_MAX + 12];
char filename[FILE_MAX + 12];
@@ -432,10 +433,11 @@ static void renamebutton_cb(bContext *C, void *UNUSED(arg1), char *oldname)
ScrArea *sa = CTX_wm_area(C);
ARegion *ar = CTX_wm_region(C);
- BLI_make_file_string(G.main->name, orgname, sfile->params->dir, oldname);
+ const char *blendfile_path = BKE_main_blendfile_path(bmain);
+ BLI_make_file_string(blendfile_path, orgname, sfile->params->dir, oldname);
BLI_strncpy(filename, sfile->params->renameedit, sizeof(filename));
BLI_filename_make_safe(filename);
- BLI_make_file_string(G.main->name, newname, sfile->params->dir, filename);
+ BLI_make_file_string(blendfile_path, newname, sfile->params->dir, filename);
if (!STREQ(orgname, newname)) {
if (!BLI_exists(newname)) {
diff --git a/source/blender/editors/space_file/file_intern.h b/source/blender/editors/space_file/file_intern.h
index 977d9fe7f3a..742715039cf 100644
--- a/source/blender/editors/space_file/file_intern.h
+++ b/source/blender/editors/space_file/file_intern.h
@@ -109,9 +109,9 @@ void file_filename_enter_handle(bContext *C, void *arg_unused, void *arg_but);
int file_highlight_set(struct SpaceFile *sfile, struct ARegion *ar, int mx, int my);
void file_sfile_filepath_set(struct SpaceFile *sfile, const char *filepath);
-void file_sfile_to_operator_ex(struct wmOperator *op, struct SpaceFile *sfile, char *filepath);
-void file_sfile_to_operator(struct wmOperator *op, struct SpaceFile *sfile);
-void file_operator_to_sfile(struct SpaceFile *sfile, struct wmOperator *op);
+void file_sfile_to_operator_ex(bContext *C, struct wmOperator *op, struct SpaceFile *sfile, char *filepath);
+void file_sfile_to_operator(bContext *C, struct wmOperator *op, struct SpaceFile *sfile);
+void file_operator_to_sfile(bContext *C, struct SpaceFile *sfile, struct wmOperator *op);
/* filesel.c */
diff --git a/source/blender/editors/space_file/file_ops.c b/source/blender/editors/space_file/file_ops.c
index 828cca53012..0cd31ce7ca5 100644
--- a/source/blender/editors/space_file/file_ops.c
+++ b/source/blender/editors/space_file/file_ops.c
@@ -176,6 +176,7 @@ static FileSelection file_selection_get(bContext *C, const rcti *rect, bool fill
static FileSelect file_select_do(bContext *C, int selected_idx, bool do_diropen)
{
+ Main *bmain = CTX_data_main(C);
FileSelect retval = FILE_SELECT_NOTHING;
SpaceFile *sfile = CTX_wm_space_file(C);
FileSelectParams *params = ED_fileselect_get_params(sfile);
@@ -213,7 +214,7 @@ static FileSelect file_select_do(bContext *C, int selected_idx, bool do_diropen)
}
}
else {
- BLI_cleanup_dir(G.main->name, params->dir);
+ BLI_cleanup_dir(BKE_main_blendfile_path(bmain), params->dir);
strcat(params->dir, file->relpath);
BLI_add_slash(params->dir);
}
@@ -826,6 +827,7 @@ void FILE_OT_select_all_toggle(wmOperatorType *ot)
/* Note we could get rid of this one, but it's used by some addon so... Does not hurt keeping it around for now. */
static int bookmark_select_exec(bContext *C, wmOperator *op)
{
+ Main *bmain = CTX_data_main(C);
SpaceFile *sfile = CTX_wm_space_file(C);
PropertyRNA *prop;
@@ -835,7 +837,7 @@ static int bookmark_select_exec(bContext *C, wmOperator *op)
RNA_property_string_get(op->ptr, prop, entry);
BLI_strncpy(params->dir, entry, sizeof(params->dir));
- BLI_cleanup_dir(G.main->name, params->dir);
+ BLI_cleanup_dir(BKE_main_blendfile_path(bmain), params->dir);
ED_file_change_dir(C);
WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_LIST, NULL);
@@ -1200,15 +1202,16 @@ void FILE_OT_cancel(struct wmOperatorType *ot)
}
-void file_sfile_to_operator_ex(wmOperator *op, SpaceFile *sfile, char *filepath)
+void file_sfile_to_operator_ex(bContext *C, wmOperator *op, SpaceFile *sfile, char *filepath)
{
+ Main *bmain = CTX_data_main(C);
PropertyRNA *prop;
BLI_join_dirfile(filepath, FILE_MAX, sfile->params->dir, sfile->params->file); /* XXX, not real length */
if ((prop = RNA_struct_find_property(op->ptr, "relative_path"))) {
if (RNA_property_boolean_get(op->ptr, prop)) {
- BLI_path_rel(filepath, G.main->name);
+ BLI_path_rel(filepath, BKE_main_blendfile_path(bmain));
}
}
@@ -1270,15 +1273,16 @@ void file_sfile_to_operator_ex(wmOperator *op, SpaceFile *sfile, char *filepath)
}
}
-void file_sfile_to_operator(wmOperator *op, SpaceFile *sfile)
+void file_sfile_to_operator(bContext *C, wmOperator *op, SpaceFile *sfile)
{
char filepath[FILE_MAX];
- file_sfile_to_operator_ex(op, sfile, filepath);
+ file_sfile_to_operator_ex(C, op, sfile, filepath);
}
-void file_operator_to_sfile(SpaceFile *sfile, wmOperator *op)
+void file_operator_to_sfile(bContext *C, SpaceFile *sfile, wmOperator *op)
{
+ Main *bmain = CTX_data_main(C);
PropertyRNA *prop;
/* If neither of the above are set, split the filepath back */
@@ -1298,7 +1302,7 @@ void file_operator_to_sfile(SpaceFile *sfile, wmOperator *op)
/* we could check for relative_path property which is used when converting
* in the other direction but doesnt hurt to do this every time */
- BLI_path_abs(sfile->params->dir, G.main->name);
+ BLI_path_abs(sfile->params->dir, BKE_main_blendfile_path(bmain));
/* XXX, files and dirs updates missing, not really so important though */
}
@@ -1330,11 +1334,11 @@ void file_draw_check(bContext *C)
wmOperator *op = sfile->op;
if (op) { /* fail on reload */
if (op->type->check) {
- file_sfile_to_operator(op, sfile);
+ file_sfile_to_operator(C, op, sfile);
/* redraw */
if (op->type->check(C, op)) {
- file_operator_to_sfile(sfile, op);
+ file_operator_to_sfile(C, sfile, op);
/* redraw, else the changed settings wont get updated */
ED_area_tag_redraw(CTX_wm_area(C));
@@ -1369,6 +1373,7 @@ bool file_draw_check_exists(SpaceFile *sfile)
int file_exec(bContext *C, wmOperator *exec_op)
{
+ Main *bmain = CTX_data_main(C);
wmWindowManager *wm = CTX_wm_manager(C);
SpaceFile *sfile = CTX_wm_space_file(C);
const struct FileDirEntry *file = filelist_file(sfile->files, sfile->params->active_file);
@@ -1384,7 +1389,7 @@ int file_exec(bContext *C, wmOperator *exec_op)
BLI_parent_dir(sfile->params->dir);
}
else {
- BLI_cleanup_path(G.main->name, sfile->params->dir);
+ BLI_cleanup_path(BKE_main_blendfile_path(bmain), sfile->params->dir);
BLI_path_append(sfile->params->dir, sizeof(sfile->params->dir) - 1, file->relpath);
BLI_add_slash(sfile->params->dir);
}
@@ -1413,14 +1418,14 @@ int file_exec(bContext *C, wmOperator *exec_op)
sfile->op = NULL;
- file_sfile_to_operator_ex(op, sfile, filepath);
+ file_sfile_to_operator_ex(C, op, sfile, filepath);
if (BLI_exists(sfile->params->dir)) {
fsmenu_insert_entry(ED_fsmenu_get(), FS_CATEGORY_RECENT, sfile->params->dir, NULL,
FS_INSERT_SAVE | FS_INSERT_FIRST);
}
- BLI_make_file_string(G.main->name, filepath, BKE_appdir_folder_id_create(BLENDER_USER_CONFIG, NULL),
+ BLI_make_file_string(BKE_main_blendfile_path(bmain), filepath, BKE_appdir_folder_id_create(BLENDER_USER_CONFIG, NULL),
BLENDER_BOOKMARK_FILE);
fsmenu_write_file(ED_fsmenu_get(), filepath);
WM_event_fileselect_event(wm, op, EVT_FILESELECT_EXEC);
@@ -1452,11 +1457,12 @@ void FILE_OT_execute(struct wmOperatorType *ot)
int file_parent_exec(bContext *C, wmOperator *UNUSED(unused))
{
+ Main *bmain = CTX_data_main(C);
SpaceFile *sfile = CTX_wm_space_file(C);
if (sfile->params) {
if (BLI_parent_dir(sfile->params->dir)) {
- BLI_cleanup_dir(G.main->name, sfile->params->dir);
+ BLI_cleanup_dir(BKE_main_blendfile_path(bmain), sfile->params->dir);
ED_file_change_dir(C);
if (sfile->params->recursion_level > 1) {
/* Disable 'dirtree' recursion when going up in tree. */
@@ -1694,7 +1700,7 @@ static int filepath_drop_exec(bContext *C, wmOperator *op)
file_sfile_filepath_set(sfile, filepath);
if (sfile->op) {
- file_sfile_to_operator(sfile->op, sfile);
+ file_sfile_to_operator(C, sfile->op, sfile);
file_draw_check(C);
}
@@ -1840,12 +1846,13 @@ void FILE_OT_directory_new(struct wmOperatorType *ot)
/* TODO This should go to BLI_path_utils. */
static void file_expand_directory(bContext *C)
{
+ Main *bmain = CTX_data_main(C);
SpaceFile *sfile = CTX_wm_space_file(C);
if (sfile->params) {
if (BLI_path_is_rel(sfile->params->dir)) {
/* Use of 'default' folder here is just to avoid an error message on '//' prefix. */
- BLI_path_abs(sfile->params->dir, G.relbase_valid ? G.main->name : BKE_appdir_folder_default());
+ BLI_path_abs(sfile->params->dir, G.relbase_valid ? BKE_main_blendfile_path(bmain) : BKE_appdir_folder_default());
}
else if (sfile->params->dir[0] == '~') {
char tmpstr[sizeof(sfile->params->dir) - 1];
@@ -1898,6 +1905,7 @@ static bool can_create_dir(const char *dir)
void file_directory_enter_handle(bContext *C, void *UNUSED(arg_unused), void *UNUSED(arg_but))
{
+ Main *bmain = CTX_data_main(C);
SpaceFile *sfile = CTX_wm_space_file(C);
if (sfile->params) {
@@ -1928,7 +1936,7 @@ void file_directory_enter_handle(bContext *C, void *UNUSED(arg_unused), void *UN
}
}
- BLI_cleanup_dir(G.main->name, sfile->params->dir);
+ BLI_cleanup_dir(BKE_main_blendfile_path(bmain), sfile->params->dir);
if (filelist_is_dir(sfile->files, sfile->params->dir)) {
/* if directory exists, enter it immediately */
@@ -1975,6 +1983,7 @@ void file_directory_enter_handle(bContext *C, void *UNUSED(arg_unused), void *UN
void file_filename_enter_handle(bContext *C, void *UNUSED(arg_unused), void *arg_but)
{
+ Main *bmain = CTX_data_main(C);
SpaceFile *sfile = CTX_wm_space_file(C);
uiBut *but = arg_but;
char matched_file[FILE_MAX];
@@ -2004,7 +2013,7 @@ void file_filename_enter_handle(bContext *C, void *UNUSED(arg_unused), void *arg
/* if directory, open it and empty filename field */
if (filelist_is_dir(sfile->files, filepath)) {
- BLI_cleanup_dir(G.main->name, filepath);
+ BLI_cleanup_dir(BKE_main_blendfile_path(bmain), filepath);
BLI_strncpy(sfile->params->dir, filepath, sizeof(sfile->params->dir));
sfile->params->file[0] = '\0';
ED_file_change_dir(C);
@@ -2269,6 +2278,7 @@ static int file_delete_poll(bContext *C)
int file_delete_exec(bContext *C, wmOperator *op)
{
char str[FILE_MAX];
+ Main *bmain = CTX_data_main(C);
wmWindowManager *wm = CTX_wm_manager(C);
SpaceFile *sfile = CTX_wm_space_file(C);
ScrArea *sa = CTX_wm_area(C);
@@ -2281,7 +2291,7 @@ int file_delete_exec(bContext *C, wmOperator *op)
for (i = 0; i < numfiles; i++) {
if (filelist_entry_select_index_get(sfile->files, i, CHECK_FILES)) {
file = filelist_file(sfile->files, i);
- BLI_make_file_string(G.main->name, str, sfile->params->dir, file->relpath);
+ BLI_make_file_string(BKE_main_blendfile_path(bmain), str, sfile->params->dir, file->relpath);
if (BLI_delete(str, false, false) != 0 ||
BLI_exists(str))
{
diff --git a/source/blender/editors/space_file/filelist.c b/source/blender/editors/space_file/filelist.c
index c975479e402..8123bed541c 100644
--- a/source/blender/editors/space_file/filelist.c
+++ b/source/blender/editors/space_file/filelist.c
@@ -1419,7 +1419,7 @@ void filelist_setdir(struct FileList *filelist, char *r_dir)
{
BLI_assert(strlen(r_dir) < FILE_MAX_LIBEXTRA);
- BLI_cleanup_dir(G.main->name, r_dir);
+ BLI_cleanup_dir(BKE_main_blendfile_path_from_global(), r_dir);
const bool is_valid_path = filelist->checkdirf(filelist, r_dir, true);
BLI_assert(is_valid_path);
UNUSED_VARS_NDEBUG(is_valid_path);
@@ -2313,7 +2313,7 @@ static int filelist_readjob_list_lib(const char *root, ListBase *entries, const
#if 0
/* Kept for reference here, in case we want to add back that feature later. We do not need it currently. */
/* Code ***NOT*** updated for job stuff! */
-static void filelist_readjob_main_rec(struct FileList *filelist)
+static void filelist_readjob_main_rec(Main *bmain, FileList *filelist)
{
ID *id;
FileDirEntry *files, *firstlib = NULL;
@@ -2375,7 +2375,7 @@ static void filelist_readjob_main_rec(struct FileList *filelist)
/* make files */
idcode = groupname_to_code(filelist->filelist.root);
- lb = which_libbase(G.main, idcode);
+ lb = which_libbase(bmain, idcode);
if (lb == NULL) return;
filelist->filelist.nbr_entries = 0;
@@ -2700,13 +2700,14 @@ static void filelist_readjob_free(void *flrjv)
void filelist_readjob_start(FileList *filelist, const bContext *C)
{
+ Main *bmain = CTX_data_main(C);
wmJob *wm_job;
FileListReadJob *flrj;
/* prepare job data */
flrj = MEM_callocN(sizeof(*flrj), __func__);
flrj->filelist = filelist;
- BLI_strncpy(flrj->main_name, G.main->name, sizeof(flrj->main_name));
+ BLI_strncpy(flrj->main_name, BKE_main_blendfile_path(bmain), sizeof(flrj->main_name));
filelist->flags &= ~(FL_FORCE_RESET | FL_IS_READY);
filelist->flags |= FL_IS_PENDING;
diff --git a/source/blender/editors/space_file/filesel.c b/source/blender/editors/space_file/filesel.c
index 9ba3c788daf..418a9f8c16f 100644
--- a/source/blender/editors/space_file/filesel.c
+++ b/source/blender/editors/space_file/filesel.c
@@ -96,11 +96,13 @@ short ED_fileselect_set_params(SpaceFile *sfile)
FileSelectParams *params;
wmOperator *op = sfile->op;
+ const char *blendfile_path = BKE_main_blendfile_path_from_global();
+
/* create new parameters if necessary */
if (!sfile->params) {
sfile->params = MEM_callocN(sizeof(FileSelectParams), "fileselparams");
/* 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));
+ BLI_split_dirfile(blendfile_path, 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;
@@ -149,8 +151,8 @@ short ED_fileselect_set_params(SpaceFile *sfile)
}
if (params->dir[0]) {
- BLI_cleanup_dir(G.main->name, params->dir);
- BLI_path_abs(params->dir, G.main->name);
+ BLI_cleanup_dir(blendfile_path, params->dir);
+ BLI_path_abs(params->dir, blendfile_path);
}
if (is_directory == true && is_filename == false && is_filepath == false && is_files == false) {
@@ -283,8 +285,8 @@ short ED_fileselect_set_params(SpaceFile *sfile)
sfile->folders_prev = folderlist_new();
if (!sfile->params->dir[0]) {
- if (G.main->name[0]) {
- BLI_split_dir_part(G.main->name, sfile->params->dir, sizeof(sfile->params->dir));
+ if (blendfile_path[0] != '\0') {
+ BLI_split_dir_part(blendfile_path, sfile->params->dir, sizeof(sfile->params->dir));
}
else {
const char *doc_path = BKE_appdir_folder_default();
diff --git a/source/blender/editors/space_graph/graph_edit.c b/source/blender/editors/space_graph/graph_edit.c
index ef4bb917700..26a6e93ba57 100644
--- a/source/blender/editors/space_graph/graph_edit.c
+++ b/source/blender/editors/space_graph/graph_edit.c
@@ -54,10 +54,11 @@
#include "BLT_translation.h"
+#include "BKE_context.h"
#include "BKE_fcurve.h"
#include "BKE_global.h"
+#include "BKE_main.h"
#include "BKE_nla.h"
-#include "BKE_context.h"
#include "BKE_report.h"
#include "DEG_depsgraph_build.h"
@@ -609,7 +610,8 @@ static void insert_graph_keys(bAnimContext *ac, eGraphKeys_InsertKey_Types mode)
* up adding the keyframes on a new F-Curve in the action data instead.
*/
if (ale->id && !ale->owner && !fcu->driver) {
- insert_keyframe(depsgraph, reports, ale->id, NULL, ((fcu->grp) ? (fcu->grp->name) : (NULL)), fcu->rna_path, fcu->array_index, cfra, ts->keyframe_type, flag);
+ insert_keyframe(ac->bmain, depsgraph, reports, ale->id, NULL, ((fcu->grp) ? (fcu->grp->name) : (NULL)),
+ fcu->rna_path, fcu->array_index, cfra, ts->keyframe_type, flag);
}
else {
const float curval = evaluate_fcurve(fcu, cfra);
diff --git a/source/blender/editors/space_graph/graph_ops.c b/source/blender/editors/space_graph/graph_ops.c
index b90fdd9ac67..bae5798ca21 100644
--- a/source/blender/editors/space_graph/graph_ops.c
+++ b/source/blender/editors/space_graph/graph_ops.c
@@ -614,6 +614,8 @@ static void graphedit_keymap_keyframes(wmKeyConfig *keyconf, wmKeyMap *keymap)
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_menu(keymap, "GRAPH_MT_specials", WKEY, KM_PRESS, 0, 0);
+
WM_keymap_add_item(keymap, "GRAPH_OT_duplicate_move", DKEY, KM_PRESS, KM_SHIFT, 0);
/* insertkey */
@@ -715,4 +717,3 @@ void graphedit_keymap(wmKeyConfig *keyconf)
keymap = WM_keymap_find(keyconf, "Graph Editor", SPACE_IPO, 0);
graphedit_keymap_keyframes(keyconf, keymap);
}
-
diff --git a/source/blender/editors/space_image/image_ops.c b/source/blender/editors/space_image/image_ops.c
index 95cbc4fe4a2..d17eb357ff6 100644
--- a/source/blender/editors/space_image/image_ops.c
+++ b/source/blender/editors/space_image/image_ops.c
@@ -227,7 +227,7 @@ static int space_image_file_exists_poll(bContext *C)
ibuf = ED_space_image_acquire_buffer(sima, &lock);
if (ibuf) {
BLI_strncpy(name, ibuf->name, FILE_MAX);
- BLI_path_abs(name, bmain->name);
+ BLI_path_abs(name, BKE_main_blendfile_path(bmain));
if (BLI_exists(name) == false) {
CTX_wm_operator_poll_msg_set(C, "image file not found");
@@ -1263,11 +1263,11 @@ static int image_open_exec(bContext *C, wmOperator *op)
BLI_strncpy(filepath_range, frame_range->filepath, sizeof(filepath_range));
if (was_relative) {
- BLI_path_rel(filepath_range, bmain->name);
+ BLI_path_rel(filepath_range, BKE_main_blendfile_path(bmain));
}
Image *ima_range = image_open_single(
- op, filepath_range, bmain->name,
+ op, filepath_range, BKE_main_blendfile_path(bmain),
is_relative_path, use_multiview, frame_range_seq_len);
/* take the first image */
@@ -1282,7 +1282,7 @@ static int image_open_exec(bContext *C, wmOperator *op)
else {
/* for drag & drop etc. */
ima = image_open_single(
- op, filepath, bmain->name,
+ op, filepath, BKE_main_blendfile_path(bmain),
is_relative_path, use_multiview, 1);
}
@@ -1692,12 +1692,12 @@ static int save_image_options_init(Main *bmain, SaveImageOptions *simopts, Space
}
else {
BLI_strncpy(simopts->filepath, "//untitled", sizeof(simopts->filepath));
- BLI_path_abs(simopts->filepath, bmain->name);
+ BLI_path_abs(simopts->filepath, BKE_main_blendfile_path(bmain));
}
}
else {
BLI_snprintf(simopts->filepath, sizeof(simopts->filepath), "//%s", ima->id.name + 2);
- BLI_path_abs(simopts->filepath, is_prev_save ? G.ima : bmain->name);
+ BLI_path_abs(simopts->filepath, is_prev_save ? G.ima : BKE_main_blendfile_path(bmain));
}
}
@@ -1721,7 +1721,7 @@ static void save_image_options_from_op(Main *bmain, SaveImageOptions *simopts, w
if (RNA_struct_property_is_set(op->ptr, "filepath")) {
RNA_string_get(op->ptr, "filepath", simopts->filepath);
- BLI_path_abs(simopts->filepath, bmain->name);
+ BLI_path_abs(simopts->filepath, BKE_main_blendfile_path(bmain));
}
}
@@ -2302,7 +2302,7 @@ static int image_save_sequence_exec(bContext *C, wmOperator *op)
char name[FILE_MAX];
BLI_strncpy(name, ibuf->name, sizeof(name));
- BLI_path_abs(name, bmain->name);
+ BLI_path_abs(name, BKE_main_blendfile_path(bmain));
if (0 == IMB_saveiff(ibuf, name, IB_rect | IB_zbuf | IB_zbuffloat)) {
BKE_reportf(op->reports, RPT_ERROR, "Could not write image: %s", strerror(errno));
diff --git a/source/blender/editors/space_image/space_image.c b/source/blender/editors/space_image/space_image.c
index 28ce88b38f5..c143ebbcd67 100644
--- a/source/blender/editors/space_image/space_image.c
+++ b/source/blender/editors/space_image/space_image.c
@@ -302,6 +302,8 @@ static void image_keymap(struct wmKeyConfig *keyconf)
WM_keymap_add_item(keymap, "IMAGE_OT_properties", NKEY, KM_PRESS, 0, 0);
WM_keymap_add_item(keymap, "IMAGE_OT_toolshelf", TKEY, KM_PRESS, 0, 0);
+ WM_keymap_add_menu(keymap, "IMAGE_MT_specials", WKEY, KM_PRESS, 0, 0);
+
WM_keymap_add_item(keymap, "IMAGE_OT_cycle_render_slot", JKEY, KM_PRESS, 0, 0);
RNA_boolean_set(WM_keymap_add_item(keymap, "IMAGE_OT_cycle_render_slot", JKEY, KM_PRESS, KM_ALT, 0)->ptr, "reverse", true);
@@ -1134,4 +1136,3 @@ void ED_spacetype_image(void)
BKE_spacetype_register(st);
}
-
diff --git a/source/blender/editors/space_info/info_ops.c b/source/blender/editors/space_info/info_ops.c
index 981630e96f6..acd0a856f1a 100644
--- a/source/blender/editors/space_info/info_ops.c
+++ b/source/blender/editors/space_info/info_ops.c
@@ -364,7 +364,7 @@ static int make_paths_relative_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
- BKE_bpath_relative_convert(bmain, bmain->name, op->reports);
+ BKE_bpath_relative_convert(bmain, BKE_main_blendfile_path(bmain), op->reports);
/* redraw everything so any changed paths register */
WM_main_add_notifier(NC_WINDOW, NULL);
@@ -397,7 +397,7 @@ static int make_paths_absolute_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
- BKE_bpath_absolute_convert(bmain, bmain->name, op->reports);
+ BKE_bpath_absolute_convert(bmain, BKE_main_blendfile_path(bmain), op->reports);
/* redraw everything so any changed paths register */
WM_main_add_notifier(NC_WINDOW, NULL);
diff --git a/source/blender/editors/space_node/node_ops.c b/source/blender/editors/space_node/node_ops.c
index 6f37c32be40..3b6cc8a89cf 100644
--- a/source/blender/editors/space_node/node_ops.c
+++ b/source/blender/editors/space_node/node_ops.c
@@ -274,6 +274,8 @@ void node_keymap(struct wmKeyConfig *keyconf)
WM_keymap_add_item(keymap, "NODE_OT_backimage_fit", HOMEKEY, KM_PRESS, KM_ALT, 0);
WM_keymap_add_item(keymap, "NODE_OT_backimage_sample", ACTIONMOUSE, KM_PRESS, KM_ALT, 0);
+ WM_keymap_add_menu(keymap, "NODE_MT_specials", WKEY, KM_PRESS, 0, 0);
+
kmi = WM_keymap_add_item(keymap, "NODE_OT_link_make", FKEY, KM_PRESS, 0, 0);
RNA_boolean_set(kmi->ptr, "replace", false);
kmi = WM_keymap_add_item(keymap, "NODE_OT_link_make", FKEY, KM_PRESS, KM_SHIFT, 0);
diff --git a/source/blender/editors/space_node/node_relationships.c b/source/blender/editors/space_node/node_relationships.c
index b0d8b51f8e2..682174ebbed 100644
--- a/source/blender/editors/space_node/node_relationships.c
+++ b/source/blender/editors/space_node/node_relationships.c
@@ -726,11 +726,14 @@ static int node_link_modal(bContext *C, wmOperator *op, const wmEvent *event)
case RIGHTMOUSE:
case MIDDLEMOUSE:
{
- node_link_exit(C, op, true);
+ if (event->val == KM_RELEASE) {
+ node_link_exit(C, op, true);
- ED_area_headerprint(CTX_wm_area(C), NULL);
- ED_region_tag_redraw(ar);
- return OPERATOR_FINISHED;
+ ED_area_headerprint(CTX_wm_area(C), NULL);
+ ED_region_tag_redraw(ar);
+ return OPERATOR_FINISHED;
+ }
+ break;
}
}
diff --git a/source/blender/editors/space_node/node_templates.c b/source/blender/editors/space_node/node_templates.c
index bc9513a748d..5a2feacf20c 100644
--- a/source/blender/editors/space_node/node_templates.c
+++ b/source/blender/editors/space_node/node_templates.c
@@ -634,7 +634,7 @@ static void ui_node_draw_node(uiLayout *layout, bContext *C, bNodeTree *ntree, b
if (node->typeinfo->draw_buttons) {
if (node->type != NODE_GROUP) {
- split = uiLayoutSplit(layout, 0.35f, false);
+ split = uiLayoutSplit(layout, 0.5f, false);
col = uiLayoutColumn(split, false);
col = uiLayoutColumn(split, false);
@@ -677,10 +677,10 @@ static void ui_node_draw_input(uiLayout *layout, bContext *C, bNodeTree *ntree,
label[i] = ' ';
}
label[indent] = '\0';
- BLI_snprintf(label + indent, UI_MAX_NAME_STR - indent, "%s:", IFACE_(input->name));
+ BLI_snprintf(label + indent, UI_MAX_NAME_STR - indent, "%s", IFACE_(input->name));
/* split in label and value */
- split = uiLayoutSplit(layout, 0.35f, false);
+ split = uiLayoutSplit(layout, 0.5f, false);
row = uiLayoutRow(split, true);
@@ -702,7 +702,7 @@ static void ui_node_draw_input(uiLayout *layout, bContext *C, bNodeTree *ntree,
uiItemL(row, label, ICON_NONE);
bt = block->buttons.last;
- bt->drawflag = UI_BUT_TEXT_LEFT;
+ bt->drawflag = UI_BUT_TEXT_RIGHT;
if (dependency_loop) {
row = uiLayoutRow(split, false);
diff --git a/source/blender/editors/space_node/node_view.c b/source/blender/editors/space_node/node_view.c
index 1cf377643a3..d52a6a89413 100644
--- a/source/blender/editors/space_node/node_view.c
+++ b/source/blender/editors/space_node/node_view.c
@@ -225,11 +225,12 @@ static int snode_bg_viewmove_modal(bContext *C, wmOperator *op, const wmEvent *e
case LEFTMOUSE:
case MIDDLEMOUSE:
case RIGHTMOUSE:
-
- MEM_freeN(nvm);
- op->customdata = NULL;
-
- return OPERATOR_FINISHED;
+ if (event->val == KM_RELEASE) {
+ MEM_freeN(nvm);
+ op->customdata = NULL;
+ return OPERATOR_FINISHED;
+ }
+ break;
}
return OPERATOR_RUNNING_MODAL;
diff --git a/source/blender/editors/space_outliner/outliner_draw.c b/source/blender/editors/space_outliner/outliner_draw.c
index 454f7b0097f..3dea8dd8a9b 100644
--- a/source/blender/editors/space_outliner/outliner_draw.c
+++ b/source/blender/editors/space_outliner/outliner_draw.c
@@ -310,7 +310,7 @@ static void namebutton_cb(bContext *C, void *tsep, char *oldname)
BKE_library_filepath_set(bmain, lib, lib->name);
BLI_strncpy(expanded, lib->name, sizeof(expanded));
- BLI_path_abs(expanded, bmain->name);
+ BLI_path_abs(expanded, BKE_main_blendfile_path(bmain));
if (!BLI_exists(expanded)) {
BKE_reportf(CTX_wm_reports(C), RPT_ERROR,
"Library path '%s' does not exist, correct this before saving", expanded);
@@ -340,7 +340,7 @@ static void namebutton_cb(bContext *C, void *tsep, char *oldname)
/* restore bone name */
BLI_strncpy(newname, ebone->name, sizeof(ebone->name));
BLI_strncpy(ebone->name, oldname, sizeof(ebone->name));
- ED_armature_bone_rename(obedit->data, oldname, newname);
+ ED_armature_bone_rename(bmain, obedit->data, oldname, newname);
WM_event_add_notifier(C, NC_OBJECT | ND_POSE, NULL);
}
break;
@@ -360,7 +360,7 @@ static void namebutton_cb(bContext *C, void *tsep, char *oldname)
/* restore bone name */
BLI_strncpy(newname, bone->name, sizeof(bone->name));
BLI_strncpy(bone->name, oldname, sizeof(bone->name));
- ED_armature_bone_rename(arm, oldname, newname);
+ ED_armature_bone_rename(bmain, arm, oldname, newname);
WM_event_add_notifier(C, NC_OBJECT | ND_POSE, NULL);
break;
}
@@ -380,7 +380,7 @@ static void namebutton_cb(bContext *C, void *tsep, char *oldname)
/* restore bone name */
BLI_strncpy(newname, pchan->name, sizeof(pchan->name));
BLI_strncpy(pchan->name, oldname, sizeof(pchan->name));
- ED_armature_bone_rename(ob->data, oldname, newname);
+ ED_armature_bone_rename(bmain, ob->data, oldname, newname);
WM_event_add_notifier(C, NC_OBJECT | ND_POSE, NULL);
break;
}
diff --git a/source/blender/editors/space_outliner/outliner_select.c b/source/blender/editors/space_outliner/outliner_select.c
index 441765528d1..af1b11b28d2 100644
--- a/source/blender/editors/space_outliner/outliner_select.c
+++ b/source/blender/editors/space_outliner/outliner_select.c
@@ -47,6 +47,7 @@
#include "BKE_collection.h"
#include "BKE_context.h"
#include "BKE_layer.h"
+#include "BKE_main.h"
#include "BKE_object.h"
#include "BKE_scene.h"
#include "BKE_sequencer.h"
@@ -74,6 +75,7 @@
static void do_outliner_activate_obdata(bContext *C, Scene *scene, ViewLayer *view_layer, Base *base)
{
+ Main *bmain = CTX_data_main(C);
Object *obact = OBACT(view_layer);
bool use_all = false;
@@ -95,7 +97,7 @@ static void do_outliner_activate_obdata(bContext *C, Scene *scene, ViewLayer *vi
if (ob->type == obact->type) {
bool ok;
if (BKE_object_is_in_editmode(ob)) {
- ok = ED_object_editmode_exit_ex(scene, ob, EM_FREEDATA | EM_WAITCURSOR);
+ ok = ED_object_editmode_exit_ex(bmain, scene, ob, EM_FREEDATA | EM_WAITCURSOR);
}
else {
ok = ED_object_editmode_enter_ex(CTX_data_main(C), scene, ob, EM_WAITCURSOR | EM_NO_CONTEXT);
diff --git a/source/blender/editors/space_sequencer/sequencer_add.c b/source/blender/editors/space_sequencer/sequencer_add.c
index bf1ca68745f..a8688b26280 100644
--- a/source/blender/editors/space_sequencer/sequencer_add.c
+++ b/source/blender/editors/space_sequencer/sequencer_add.c
@@ -117,7 +117,7 @@ static void sequencer_generic_invoke_path__internal(bContext *C, wmOperator *op,
Main *bmain = CTX_data_main(C);
char path[FILE_MAX];
BLI_strncpy(path, last_seq->strip->dir, sizeof(path));
- BLI_path_abs(path, bmain->name);
+ BLI_path_abs(path, BKE_main_blendfile_path(bmain));
RNA_string_set(op->ptr, identifier, path);
}
}
@@ -199,7 +199,7 @@ static void seq_load_operator_info(SeqLoadInfo *seq_load, bContext *C, wmOperato
}
if ((is_file != -1) && relative)
- BLI_path_rel(seq_load->path, bmain->name);
+ BLI_path_rel(seq_load->path, BKE_main_blendfile_path(bmain));
if ((prop = RNA_struct_find_property(op->ptr, "frame_end"))) {
diff --git a/source/blender/editors/space_sequencer/sequencer_edit.c b/source/blender/editors/space_sequencer/sequencer_edit.c
index cc0f352a51e..b24817f2af8 100644
--- a/source/blender/editors/space_sequencer/sequencer_edit.c
+++ b/source/blender/editors/space_sequencer/sequencer_edit.c
@@ -3753,7 +3753,7 @@ static int sequencer_change_path_exec(bContext *C, wmOperator *op)
/* TODO, shouldn't this already be relative from the filesel?
* (as the 'filepath' is) for now just make relative here,
* but look into changing after 2.60 - campbell */
- BLI_path_rel(directory, bmain->name);
+ BLI_path_rel(directory, BKE_main_blendfile_path(bmain));
}
BLI_strncpy(seq->strip->dir, directory, sizeof(seq->strip->dir));
@@ -3869,10 +3869,10 @@ static int sequencer_export_subtitles_invoke(bContext *C, wmOperator *op, const
if (!RNA_struct_property_is_set(op->ptr, "filepath")) {
char filepath[FILE_MAX];
- if (bmain->name[0] == '\0')
+ if (BKE_main_blendfile_path(bmain)[0] == '\0')
BLI_strncpy(filepath, "untitled", sizeof(filepath));
else
- BLI_strncpy(filepath, bmain->name, sizeof(filepath));
+ BLI_strncpy(filepath, BKE_main_blendfile_path(bmain), sizeof(filepath));
BLI_replace_extension(filepath, sizeof(filepath), ".srt");
RNA_string_set(op->ptr, "filepath", filepath);
diff --git a/source/blender/editors/space_text/text_ops.c b/source/blender/editors/space_text/text_ops.c
index f7c3471f302..b3815d73c5c 100644
--- a/source/blender/editors/space_text/text_ops.c
+++ b/source/blender/editors/space_text/text_ops.c
@@ -234,7 +234,7 @@ static int text_open_exec(bContext *C, wmOperator *op)
RNA_string_get(op->ptr, "filepath", str);
- text = BKE_text_load_ex(bmain, str, bmain->name, internal);
+ text = BKE_text_load_ex(bmain, str, BKE_main_blendfile_path(bmain), internal);
if (!text) {
if (op->customdata) MEM_freeN(op->customdata);
@@ -274,7 +274,7 @@ static int text_open_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(e
{
Main *bmain = CTX_data_main(C);
Text *text = CTX_data_edit_text(C);
- const char *path = (text && text->name) ? text->name : bmain->name;
+ const char *path = (text && text->name) ? text->name : BKE_main_blendfile_path(bmain);
if (RNA_struct_property_is_set(op->ptr, "filepath"))
return text_open_exec(C, op);
@@ -465,7 +465,7 @@ static void txt_write_file(Main *bmain, Text *text, ReportList *reports)
char filepath[FILE_MAX];
BLI_strncpy(filepath, text->name, FILE_MAX);
- BLI_path_abs(filepath, bmain->name);
+ BLI_path_abs(filepath, BKE_main_blendfile_path(bmain));
fp = BLI_fopen(filepath, "w");
if (fp == NULL) {
@@ -562,7 +562,7 @@ static int text_save_as_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSE
else if (text->flags & TXT_ISMEM)
str = text->id.name + 2;
else
- str = bmain->name;
+ str = BKE_main_blendfile_path(bmain);
RNA_string_set(op->ptr, "filepath", str);
WM_event_add_fileselect(C, op);
diff --git a/source/blender/editors/space_view3d/drawobject.c b/source/blender/editors/space_view3d/drawobject.c
index 7de7aa77ba3..1224c284d5f 100644
--- a/source/blender/editors/space_view3d/drawobject.c
+++ b/source/blender/editors/space_view3d/drawobject.c
@@ -67,6 +67,7 @@
#include "BKE_lattice.h"
#include "BKE_main.h"
#include "BKE_mesh.h"
+#include "BKE_mesh_runtime.h"
#include "BKE_material.h"
#include "BKE_mball.h"
#include "BKE_modifier.h"
diff --git a/source/blender/editors/space_view3d/space_view3d.c b/source/blender/editors/space_view3d/space_view3d.c
index d4fa98cfc88..7b395153417 100644
--- a/source/blender/editors/space_view3d/space_view3d.c
+++ b/source/blender/editors/space_view3d/space_view3d.c
@@ -326,9 +326,13 @@ static SpaceLink *view3d_new(const ScrArea *UNUSED(sa), const Scene *scene)
v3d->shading.light = V3D_LIGHTING_STUDIO;
v3d->shading.shadow_intensity = 0.5f;
v3d->shading.xray_alpha = 0.5f;
+ v3d->shading.cavity_valley_factor = 1.0f;
+ v3d->shading.cavity_ridge_factor = 1.0f;
copy_v3_fl(v3d->shading.single_color, 0.8f);
v3d->overlay.flag = V3D_OVERLAY_LOOK_DEV;
+ v3d->overlay.wireframe_threshold = 0.5f;
+ v3d->overlay.bone_selection_alpha = 0.5f;
v3d->gridflag = V3D_SHOW_X | V3D_SHOW_Y | V3D_SHOW_FLOOR;
diff --git a/source/blender/editors/space_view3d/view3d_draw.c b/source/blender/editors/space_view3d/view3d_draw.c
index 5cd36cce31c..e199e84029e 100644
--- a/source/blender/editors/space_view3d/view3d_draw.c
+++ b/source/blender/editors/space_view3d/view3d_draw.c
@@ -1203,11 +1203,15 @@ void view3d_draw_region_info(const bContext *C, ARegion *ar, const int offset)
BLF_batch_draw_begin();
- if (U.uiflag & USER_SHOW_ROTVIEWICON) {
+ if (((U.uiflag & USER_SHOW_ROTVIEWICON) != 0) &&
+ (v3d->flag2 & V3D_RENDER_OVERRIDE) == 0)
+ {
draw_view_axis(rv3d, &rect);
}
- if ((v3d->overlay.flag & V3D_OVERLAY_HIDE_TEXT) == 0) {
+ if ((v3d->flag2 & V3D_RENDER_OVERRIDE) == 0 &&
+ (v3d->overlay.flag & V3D_OVERLAY_HIDE_TEXT) == 0)
+ {
if ((U.uiflag & USER_SHOW_FPS) && ED_screen_animation_no_scrub(wm)) {
ED_scene_draw_fps(scene, &rect);
}
diff --git a/source/blender/editors/space_view3d/view3d_edit.c b/source/blender/editors/space_view3d/view3d_edit.c
index e2ff809db36..cdf2106d8bf 100644
--- a/source/blender/editors/space_view3d/view3d_edit.c
+++ b/source/blender/editors/space_view3d/view3d_edit.c
@@ -131,6 +131,7 @@ static void view3d_operator_properties_common(wmOperatorType *ot, const enum eV3
typedef struct ViewOpsData {
/** Context pointers (assigned by #viewops_data_alloc). */
+ Main *bmain;
Scene *scene;
ScrArea *sa;
ARegion *ar;
@@ -221,6 +222,7 @@ static void viewops_data_alloc(bContext *C, wmOperator *op)
/* store data */
op->customdata = vod;
+ vod->bmain = CTX_data_main(C);
vod->depsgraph = CTX_data_depsgraph(C);
vod->scene = CTX_data_scene(C);
vod->sa = CTX_wm_area(C);
@@ -4592,6 +4594,7 @@ void ED_view3d_cursor3d_position(bContext *C, float fp[3], const int mval[2])
void ED_view3d_cursor3d_update(bContext *C, const int mval[2])
{
+ Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
View3D *v3d = CTX_wm_view3d(C);
ARegion *ar = CTX_wm_region(C);
@@ -4609,7 +4612,7 @@ void ED_view3d_cursor3d_update(bContext *C, const int mval[2])
float ray_no[3];
struct SnapObjectContext *snap_context = ED_transform_snap_object_context_create_view3d(
- scene, CTX_data_depsgraph(C), 0, ar, v3d);
+ bmain, scene, CTX_data_depsgraph(C), 0, ar, v3d);
float obmat[4][4];
Object *ob_dummy = NULL;
diff --git a/source/blender/editors/space_view3d/view3d_header.c b/source/blender/editors/space_view3d/view3d_header.c
index 5f07bb0fc3d..4f81fa7585c 100644
--- a/source/blender/editors/space_view3d/view3d_header.c
+++ b/source/blender/editors/space_view3d/view3d_header.c
@@ -259,6 +259,33 @@ void VIEW3D_OT_toggle_xray_draw_option(wmOperatorType *ot)
/** \} */
+/* -------------------------------------------------------------------- */
+/** \name Toggle Bone selection Overlay Operator
+ * \{ */
+
+static int toggle_matcap_flip(bContext *C, wmOperator *UNUSED(op))
+{
+ View3D *v3d = CTX_wm_view3d(C);
+ v3d->shading.flag ^= V3D_SHADING_MATCAP_FLIP_X;
+ ED_view3d_shade_update(CTX_data_main(C), v3d, CTX_wm_area(C));
+ WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, v3d);
+ return OPERATOR_FINISHED;
+}
+
+void VIEW3D_OT_toggle_matcap_flip(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Flip MatCap";
+ ot->description = "Flip MatCap";
+ ot->idname = "VIEW3D_OT_toggle_matcap_flip";
+
+ /* api callbacks */
+ ot->exec = toggle_matcap_flip;
+ // ot->poll = toggle_show_xray_poll;
+}
+
+/** \} */
+
static void do_view3d_header_buttons(bContext *C, void *UNUSED(arg), int event)
{
diff --git a/source/blender/editors/space_view3d/view3d_intern.h b/source/blender/editors/space_view3d/view3d_intern.h
index 6c9749e5eeb..017b31a0bf2 100644
--- a/source/blender/editors/space_view3d/view3d_intern.h
+++ b/source/blender/editors/space_view3d/view3d_intern.h
@@ -66,6 +66,7 @@ enum {
/* view3d_header.c */
void VIEW3D_OT_layers(struct wmOperatorType *ot);
void VIEW3D_OT_toggle_xray_draw_option(struct wmOperatorType *ot);
+void VIEW3D_OT_toggle_matcap_flip(struct wmOperatorType *ot);
/* view3d_ops.c */
void view3d_operatortypes(void);
@@ -134,7 +135,8 @@ void VIEW3D_OT_ruler(struct wmOperatorType *ot);
/* drawobject.c */
void draw_object_backbufsel(
- struct Depsgraph *depsgraph, Scene *scene, View3D *v3d, RegionView3D *rv3d, struct Object *ob,
+ struct Depsgraph *depsgraph, Scene *scene,
+ View3D *v3d, RegionView3D *rv3d, struct Object *ob,
short select_mode);
int view3d_effective_drawtype(const struct View3D *v3d);
diff --git a/source/blender/editors/space_view3d/view3d_iterators.c b/source/blender/editors/space_view3d/view3d_iterators.c
index 145f57174fd..eae0cf8e459 100644
--- a/source/blender/editors/space_view3d/view3d_iterators.c
+++ b/source/blender/editors/space_view3d/view3d_iterators.c
@@ -42,6 +42,7 @@
#include "BKE_displist.h"
#include "BKE_editmesh.h"
#include "BKE_context.h"
+#include "BKE_mesh_runtime.h"
#include "DEG_depsgraph.h"
#include "DEG_depsgraph_query.h"
diff --git a/source/blender/editors/space_view3d/view3d_manipulator_armature.c b/source/blender/editors/space_view3d/view3d_manipulator_armature.c
index 5d3d88ff2a2..abbd6c888b2 100644
--- a/source/blender/editors/space_view3d/view3d_manipulator_armature.c
+++ b/source/blender/editors/space_view3d/view3d_manipulator_armature.c
@@ -134,7 +134,10 @@ static bool WIDGETGROUP_armature_spline_poll(const bContext *C, wmManipulatorGro
const bArmature *arm = ob->data;
if (arm->drawtype == ARM_B_BONE) {
if (arm->act_bone && arm->act_bone->segments > 1) {
- return true;
+ View3D *v3d = CTX_wm_view3d(C);
+ if ((v3d->flag2 & V3D_RENDER_OVERRIDE) == 0) {
+ return true;
+ }
}
}
}
diff --git a/source/blender/editors/space_view3d/view3d_manipulator_camera.c b/source/blender/editors/space_view3d/view3d_manipulator_camera.c
index b680818dc14..49fa83e82fc 100644
--- a/source/blender/editors/space_view3d/view3d_manipulator_camera.c
+++ b/source/blender/editors/space_view3d/view3d_manipulator_camera.c
@@ -63,6 +63,11 @@ struct CameraWidgetGroup {
static bool WIDGETGROUP_camera_poll(const bContext *C, wmManipulatorGroupType *UNUSED(wgt))
{
+ View3D *v3d = CTX_wm_view3d(C);
+ if (v3d->flag2 & V3D_RENDER_OVERRIDE) {
+ return false;
+ }
+
Object *ob = CTX_data_active_object(C);
if (ob && ob->type == OB_CAMERA) {
Camera *camera = ob->data;
@@ -352,9 +357,13 @@ static bool WIDGETGROUP_camera_view_poll(const bContext *C, wmManipulatorGroupTy
}
}
+ View3D *v3d = CTX_wm_view3d(C);
+ if (v3d->flag2 & V3D_RENDER_OVERRIDE) {
+ return false;
+ }
+
ARegion *ar = CTX_wm_region(C);
RegionView3D *rv3d = ar->regiondata;
- View3D *v3d = CTX_wm_view3d(C);
if (rv3d->persp == RV3D_CAMOB) {
if (scene->r.mode & R_BORDER) {
/* TODO: support overrides. */
diff --git a/source/blender/editors/space_view3d/view3d_manipulator_empty.c b/source/blender/editors/space_view3d/view3d_manipulator_empty.c
index 1d56c5ee7f4..75e4a9e3314 100644
--- a/source/blender/editors/space_view3d/view3d_manipulator_empty.c
+++ b/source/blender/editors/space_view3d/view3d_manipulator_empty.c
@@ -106,6 +106,11 @@ static void manipulator_empty_image_prop_matrix_set(
static bool WIDGETGROUP_empty_image_poll(const bContext *C, wmManipulatorGroupType *UNUSED(wgt))
{
+ View3D *v3d = CTX_wm_view3d(C);
+ if (v3d->flag2 & V3D_RENDER_OVERRIDE) {
+ return false;
+ }
+
Object *ob = CTX_data_active_object(C);
if (ob && ob->type == OB_EMPTY) {
diff --git a/source/blender/editors/space_view3d/view3d_manipulator_forcefield.c b/source/blender/editors/space_view3d/view3d_manipulator_forcefield.c
index e76be448be4..2a1fdee8e8a 100644
--- a/source/blender/editors/space_view3d/view3d_manipulator_forcefield.c
+++ b/source/blender/editors/space_view3d/view3d_manipulator_forcefield.c
@@ -54,6 +54,11 @@
static bool WIDGETGROUP_forcefield_poll(const bContext *C, wmManipulatorGroupType *UNUSED(wgt))
{
+ View3D *v3d = CTX_wm_view3d(C);
+ if (v3d->flag2 & V3D_RENDER_OVERRIDE) {
+ return false;
+ }
+
Object *ob = CTX_data_active_object(C);
return (ob && ob->pd && ob->pd->forcefield);
diff --git a/source/blender/editors/space_view3d/view3d_manipulator_lamp.c b/source/blender/editors/space_view3d/view3d_manipulator_lamp.c
index 88c36fc2c0b..01c38cfd899 100644
--- a/source/blender/editors/space_view3d/view3d_manipulator_lamp.c
+++ b/source/blender/editors/space_view3d/view3d_manipulator_lamp.c
@@ -54,6 +54,11 @@
static bool WIDGETGROUP_lamp_spot_poll(const bContext *C, wmManipulatorGroupType *UNUSED(wgt))
{
+ View3D *v3d = CTX_wm_view3d(C);
+ if (v3d->flag2 & V3D_RENDER_OVERRIDE) {
+ return false;
+ }
+
Object *ob = CTX_data_active_object(C);
if (ob && ob->type == OB_LAMP) {
@@ -151,8 +156,12 @@ static void manipulator_area_lamp_prop_matrix_set(
static bool WIDGETGROUP_lamp_area_poll(const bContext *C, wmManipulatorGroupType *UNUSED(wgt))
{
- Object *ob = CTX_data_active_object(C);
+ View3D *v3d = CTX_wm_view3d(C);
+ if (v3d->flag2 & V3D_RENDER_OVERRIDE) {
+ return false;
+ }
+ Object *ob = CTX_data_active_object(C);
if (ob && ob->type == OB_LAMP) {
Lamp *la = ob->data;
return (la->type == LA_AREA);
@@ -226,6 +235,11 @@ void VIEW3D_WGT_lamp_area(wmManipulatorGroupType *wgt)
static bool WIDGETGROUP_lamp_target_poll(const bContext *C, wmManipulatorGroupType *UNUSED(wgt))
{
+ View3D *v3d = CTX_wm_view3d(C);
+ if (v3d->flag2 & V3D_RENDER_OVERRIDE) {
+ return false;
+ }
+
Object *ob = CTX_data_active_object(C);
if (ob != NULL) {
diff --git a/source/blender/editors/space_view3d/view3d_manipulator_navigate.c b/source/blender/editors/space_view3d/view3d_manipulator_navigate.c
index d86c6595bfa..c869e23d552 100644
--- a/source/blender/editors/space_view3d/view3d_manipulator_navigate.c
+++ b/source/blender/editors/space_view3d/view3d_manipulator_navigate.c
@@ -176,8 +176,13 @@ struct NavigateWidgetGroup {
int region_size[2];
};
-static bool WIDGETGROUP_navigate_poll(const bContext *UNUSED(C), wmManipulatorGroupType *UNUSED(wgt))
+static bool WIDGETGROUP_navigate_poll(const bContext *C, wmManipulatorGroupType *UNUSED(wgt))
{
+ View3D *v3d = CTX_wm_view3d(C);
+ if (v3d->flag2 & V3D_RENDER_OVERRIDE) {
+ return false;
+ }
+
if (U.manipulator_flag & USER_MANIPULATOR_DRAW_NAVIGATE) {
return true;
}
diff --git a/source/blender/editors/space_view3d/view3d_manipulator_ruler.c b/source/blender/editors/space_view3d/view3d_manipulator_ruler.c
index 9cde5ffc5e3..cd918695f60 100644
--- a/source/blender/editors/space_view3d/view3d_manipulator_ruler.c
+++ b/source/blender/editors/space_view3d/view3d_manipulator_ruler.c
@@ -31,8 +31,10 @@
#include "BLT_translation.h"
#include "BKE_context.h"
-#include "BKE_object.h"
#include "BKE_gpencil.h"
+#include "BKE_main.h"
+
+#include "BKE_object.h"
#include "BKE_unit.h"
#include "DNA_object_types.h"
@@ -263,6 +265,7 @@ static bool view3d_ruler_pick(
*/
static void ruler_state_set(bContext *C, RulerInfo *ruler_info, int state)
{
+ Main *bmain = CTX_data_main(C);
if (state == ruler_info->state) {
return;
}
@@ -278,7 +281,7 @@ static void ruler_state_set(bContext *C, RulerInfo *ruler_info, int state)
}
else if (state == RULER_STATE_DRAG) {
ruler_info->snap_context = ED_transform_snap_object_context_create_view3d(
- CTX_data_scene(C), CTX_data_depsgraph(C), 0,
+ bmain, CTX_data_scene(C), CTX_data_depsgraph(C), 0,
ruler_info->ar, CTX_wm_view3d(C));
}
else {
diff --git a/source/blender/editors/space_view3d/view3d_ops.c b/source/blender/editors/space_view3d/view3d_ops.c
index 3b800c20ed2..b3211ed1108 100644
--- a/source/blender/editors/space_view3d/view3d_ops.c
+++ b/source/blender/editors/space_view3d/view3d_ops.c
@@ -223,6 +223,7 @@ void view3d_operatortypes(void)
WM_operatortype_append(VIEW3D_OT_toggle_render);
WM_operatortype_append(VIEW3D_OT_toggle_xray_draw_option);
+ WM_operatortype_append(VIEW3D_OT_toggle_matcap_flip);
WM_operatortype_append(VIEW3D_OT_ruler_add);
@@ -301,6 +302,8 @@ void view3d_keymap(wmKeyConfig *keyconf)
kmi = WM_keymap_add_item(keymap, "VIEW3D_OT_view_all", CKEY, KM_PRESS, KM_SHIFT, 0);
RNA_boolean_set(kmi->ptr, "center", true);
+ WM_keymap_add_menu_pie(keymap, "VIEW3D_PIE_view", ACCENTGRAVEKEY, KM_CLICK_DRAG, 0, 0);
+
/* numpad view hotkeys*/
RNA_enum_set(WM_keymap_add_item(keymap, "VIEW3D_OT_viewnumpad", PAD0, KM_PRESS, 0, 0)->ptr, "type", RV3D_VIEW_CAMERA);
RNA_enum_set(WM_keymap_add_item(keymap, "VIEW3D_OT_viewnumpad", PAD1, KM_PRESS, 0, 0)->ptr, "type", RV3D_VIEW_FRONT);
diff --git a/source/blender/editors/space_view3d/view3d_ruler.c b/source/blender/editors/space_view3d/view3d_ruler.c
index 54579e93413..c30b72bfb95 100644
--- a/source/blender/editors/space_view3d/view3d_ruler.c
+++ b/source/blender/editors/space_view3d/view3d_ruler.c
@@ -38,8 +38,9 @@
#include "BLT_translation.h"
#include "BKE_context.h"
-#include "BKE_unit.h"
#include "BKE_gpencil.h"
+#include "BKE_main.h"
+#include "BKE_unit.h"
#include "BIF_gl.h"
@@ -267,6 +268,7 @@ static bool view3d_ruler_pick(RulerInfo *ruler_info, const float mval[2],
*/
static void ruler_state_set(bContext *C, RulerInfo *ruler_info, int state)
{
+ Main *bmain = CTX_data_main(C);
if (state == ruler_info->state) {
return;
}
@@ -282,7 +284,7 @@ static void ruler_state_set(bContext *C, RulerInfo *ruler_info, int state)
}
else if (state == RULER_STATE_DRAG) {
ruler_info->snap_context = ED_transform_snap_object_context_create_view3d(
- CTX_data_scene(C), CTX_data_depsgraph(C), 0,
+ bmain, CTX_data_scene(C), CTX_data_depsgraph(C), 0,
ruler_info->ar, CTX_wm_view3d(C));
}
else {
diff --git a/source/blender/editors/space_view3d/view3d_select.c b/source/blender/editors/space_view3d/view3d_select.c
index bb12c8236cf..f4e39c7a563 100644
--- a/source/blender/editors/space_view3d/view3d_select.c
+++ b/source/blender/editors/space_view3d/view3d_select.c
@@ -116,6 +116,7 @@ void ED_view3d_viewcontext_init(bContext *C, ViewContext *vc)
{
memset(vc, 0, sizeof(ViewContext));
vc->ar = CTX_wm_region(C);
+ vc->bmain = CTX_data_main(C);
vc->depsgraph = CTX_data_depsgraph(C);
vc->scene = CTX_data_scene(C);
vc->view_layer = CTX_data_view_layer(C);
diff --git a/source/blender/editors/space_view3d/view3d_utils.c b/source/blender/editors/space_view3d/view3d_utils.c
index 8b0b461d443..ca5375b6b54 100644
--- a/source/blender/editors/space_view3d/view3d_utils.c
+++ b/source/blender/editors/space_view3d/view3d_utils.c
@@ -46,6 +46,7 @@
#include "BKE_camera.h"
#include "BKE_context.h"
+#include "BKE_main.h"
#include "BKE_object.h"
#include "BKE_screen.h"
@@ -899,7 +900,7 @@ static float view_autodist_depth_margin(ARegion *ar, const int mval[2], int marg
* \param fallback_depth_pt: Use this points depth when no depth can be found.
*/
bool ED_view3d_autodist(
- struct Depsgraph *depsgraph, ARegion *ar, View3D *v3d,
+ Depsgraph *depsgraph, ARegion *ar, View3D *v3d,
const int mval[2], float mouse_worldloc[3],
const bool alphaoverride, const float fallback_depth_pt[3])
{
@@ -936,7 +937,7 @@ bool ED_view3d_autodist(
}
}
-void ED_view3d_autodist_init(struct Depsgraph *depsgraph,
+void ED_view3d_autodist_init(Depsgraph *depsgraph,
ARegion *ar, View3D *v3d, int mode)
{
/* Get Z Depths, needed for perspective, nice for ortho */
diff --git a/source/blender/editors/space_view3d/view3d_walk.c b/source/blender/editors/space_view3d/view3d_walk.c
index a7c97ba4d4a..352e85703bc 100644
--- a/source/blender/editors/space_view3d/view3d_walk.c
+++ b/source/blender/editors/space_view3d/view3d_walk.c
@@ -37,6 +37,7 @@
#include "BLI_utildefines.h"
#include "BKE_context.h"
+#include "BKE_main.h"
#include "BKE_report.h"
#include "BLT_translation.h"
@@ -507,6 +508,7 @@ static float userdef_speed = -1.f;
static bool initWalkInfo(bContext *C, WalkInfo *walk, wmOperator *op)
{
+ Main *bmain = CTX_data_main(C);
wmWindow *win = CTX_wm_window(C);
walk->rv3d = CTX_wm_region_view3d(C);
@@ -602,7 +604,7 @@ static bool initWalkInfo(bContext *C, WalkInfo *walk, wmOperator *op)
walk->rv3d->rflag |= RV3D_NAVIGATING;
walk->snap_context = ED_transform_snap_object_context_create_view3d(
- walk->scene, CTX_data_depsgraph(C), 0,
+ bmain, walk->scene, CTX_data_depsgraph(C), 0,
walk->ar, walk->v3d);
walk->v3d_camera_control = ED_view3d_cameracontrol_acquire(
diff --git a/source/blender/editors/transform/transform.c b/source/blender/editors/transform/transform.c
index a4d08b15a6d..b4f7e9256a3 100644
--- a/source/blender/editors/transform/transform.c
+++ b/source/blender/editors/transform/transform.c
@@ -1520,7 +1520,7 @@ int transformEvent(TransInfo *t, const wmEvent *event)
/* confirm transform if launch key is released after mouse move */
if (t->flag & T_RELEASE_CONFIRM) {
/* XXX Keyrepeat bug in Xorg messes this up, will test when fixed */
- if (event->type == t->launch_event && (t->launch_event == LEFTMOUSE || t->launch_event == RIGHTMOUSE)) {
+ if ((event->type == t->launch_event) && ISMOUSE(t->launch_event)) {
t->state = TRANS_CONFIRM;
}
}
@@ -2140,14 +2140,8 @@ bool initTransform(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
t->mode = mode;
- t->launch_event = event ? event->type : -1;
-
- if (t->launch_event == EVT_TWEAK_R) {
- t->launch_event = RIGHTMOUSE;
- }
- else if (t->launch_event == EVT_TWEAK_L) {
- t->launch_event = LEFTMOUSE;
- }
+ /* Needed to translate tweak events to mouse buttons. */
+ t->launch_event = event ? WM_userdef_event_type_from_keymap_type(event->type) : -1;
// XXX Remove this when wm_operator_call_internal doesn't use window->eventstate (which can have type = 0)
// For manipulator only, so assume LEFTMOUSE
diff --git a/source/blender/editors/transform/transform.h b/source/blender/editors/transform/transform.h
index b9f42a0d9fc..419f400df53 100644
--- a/source/blender/editors/transform/transform.h
+++ b/source/blender/editors/transform/transform.h
@@ -722,7 +722,7 @@ int special_transform_moving(TransInfo *t);
void transform_autoik_update(TransInfo *t, short mode);
bool transdata_check_local_islands(TransInfo *t, short around);
-int count_set_pose_transflags(int *out_mode, short around, struct Object *ob);
+int count_set_pose_transflags(struct Object *ob, const int mode, const short around, bool has_translate_rotate[2]);
/* auto-keying stuff used by special_aftertrans_update */
void autokeyframe_ob_cb_func(
diff --git a/source/blender/editors/transform/transform_conversions.c b/source/blender/editors/transform/transform_conversions.c
index 8bfe14dc6ea..45941ba6f39 100644
--- a/source/blender/editors/transform/transform_conversions.c
+++ b/source/blender/editors/transform/transform_conversions.c
@@ -574,17 +574,14 @@ static short apply_targetless_ik(Object *ob)
return apply;
}
-static void add_pose_transdata(
- TransInfo *t, Object *ob, bPoseChannel *pchan,
- Object *ob_eval, bPoseChannel *pchan_eval,
- TransDataContainer *tc, TransData *td)
+static void add_pose_transdata(TransInfo *t, bPoseChannel *pchan, Object *ob, TransDataContainer *tc, TransData *td)
{
- Bone *bone = pchan_eval->bone;
+ Bone *bone = pchan->bone;
float pmat[3][3], omat[3][3];
float cmat[3][3], tmat[3][3];
float vec[3];
- copy_v3_v3(vec, pchan_eval->pose_mat[3]);
+ copy_v3_v3(vec, pchan->pose_mat[3]);
copy_v3_v3(td->center, vec);
td->ob = ob;
@@ -601,10 +598,10 @@ static void add_pose_transdata(
td->protectflag = pchan->protectflag;
td->loc = pchan->loc;
- copy_v3_v3(td->iloc, pchan_eval->loc);
+ copy_v3_v3(td->iloc, pchan->loc);
td->ext->size = pchan->size;
- copy_v3_v3(td->ext->isize, pchan_eval->size);
+ copy_v3_v3(td->ext->isize, pchan->size);
if (pchan->rotmode > 0) {
td->ext->rot = pchan->eul;
@@ -612,7 +609,7 @@ static void add_pose_transdata(
td->ext->rotAngle = NULL;
td->ext->quat = NULL;
- copy_v3_v3(td->ext->irot, pchan_eval->eul);
+ copy_v3_v3(td->ext->irot, pchan->eul);
}
else if (pchan->rotmode == ROT_MODE_AXISANGLE) {
td->ext->rot = NULL;
@@ -620,8 +617,8 @@ static void add_pose_transdata(
td->ext->rotAngle = &pchan->rotAngle;
td->ext->quat = NULL;
- td->ext->irotAngle = pchan_eval->rotAngle;
- copy_v3_v3(td->ext->irotAxis, pchan_eval->rotAxis);
+ td->ext->irotAngle = pchan->rotAngle;
+ copy_v3_v3(td->ext->irotAxis, pchan->rotAxis);
}
else {
td->ext->rot = NULL;
@@ -629,20 +626,20 @@ static void add_pose_transdata(
td->ext->rotAngle = NULL;
td->ext->quat = pchan->quat;
- copy_qt_qt(td->ext->iquat, pchan_eval->quat);
+ copy_qt_qt(td->ext->iquat, pchan->quat);
}
td->ext->rotOrder = pchan->rotmode;
/* proper way to get parent transform + own transform + constraints transform */
- copy_m3_m4(omat, ob_eval->obmat);
+ copy_m3_m4(omat, ob->obmat);
/* New code, using "generic" BKE_pchan_to_pose_mat(). */
{
float rotscale_mat[4][4], loc_mat[4][4];
float rpmat[3][3];
- BKE_pchan_to_pose_mat(pchan_eval, rotscale_mat, loc_mat);
+ BKE_pchan_to_pose_mat(pchan, rotscale_mat, loc_mat);
if (t->mode == TFM_TRANSLATION)
copy_m3_m4(pmat, loc_mat);
else
@@ -655,7 +652,7 @@ static void add_pose_transdata(
copy_m3_m4(rpmat, rotscale_mat);
if (constraints_list_needinv(t, &pchan->constraints)) {
- copy_m3_m4(tmat, pchan_eval->constinv);
+ copy_m3_m4(tmat, pchan->constinv);
invert_m3_m3(cmat, tmat);
mul_m3_series(td->mtx, cmat, omat, pmat);
mul_m3_series(td->ext->r_mtx, cmat, omat, rpmat);
@@ -675,7 +672,7 @@ static void add_pose_transdata(
if (pchan->parent) {
/* same as td->smtx but without pchan->bone->bone_mat */
td->flag |= TD_PBONE_LOCAL_MTX_C;
- mul_m3_m3m3(td->ext->l_smtx, pchan_eval->bone->bone_mat, td->smtx);
+ mul_m3_m3m3(td->ext->l_smtx, pchan->bone->bone_mat, td->smtx);
}
else {
td->flag |= TD_PBONE_LOCAL_MTX_P;
@@ -683,7 +680,7 @@ static void add_pose_transdata(
}
/* for axismat we use bone's own transform */
- copy_m3_m4(pmat, pchan_eval->pose_mat);
+ copy_m3_m4(pmat, pchan->pose_mat);
mul_m3_m3m3(td->axismtx, omat, pmat);
normalize_m3(td->axismtx);
@@ -708,10 +705,10 @@ static void add_pose_transdata(
bKinematicConstraint *data = has_targetless_ik(pchan);
if (data) {
if (data->flag & CONSTRAINT_IK_TIP) {
- copy_v3_v3(data->grabtarget, pchan_eval->pose_tail);
+ copy_v3_v3(data->grabtarget, pchan->pose_tail);
}
else {
- copy_v3_v3(data->grabtarget, pchan_eval->pose_head);
+ copy_v3_v3(data->grabtarget, pchan->pose_head);
}
td->loc = data->grabtarget;
copy_v3_v3(td->iloc, td->loc);
@@ -751,12 +748,11 @@ static void bone_children_clear_transflag(int mode, short around, ListBase *lb)
/* sets transform flags in the bones
* returns total number of bones with BONE_TRANSFORM */
-int count_set_pose_transflags(int *out_mode, short around, Object *ob)
+int count_set_pose_transflags(Object *ob, const int mode, short around, bool has_translate_rotate[2])
{
bArmature *arm = ob->data;
bPoseChannel *pchan;
Bone *bone;
- int mode = *out_mode;
int total = 0;
for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
@@ -784,43 +780,30 @@ int count_set_pose_transflags(int *out_mode, short around, Object *ob)
}
}
/* now count, and check if we have autoIK or have to switch from translate to rotate */
- bool has_translation = false, has_rotation = false;
-
for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
bone = pchan->bone;
if (bone->flag & BONE_TRANSFORM) {
total++;
- if (mode == TFM_TRANSLATION) {
+ if (has_translate_rotate != NULL) {
if (has_targetless_ik(pchan) == NULL) {
if (pchan->parent && (pchan->bone->flag & BONE_CONNECTED)) {
- if (pchan->bone->flag & BONE_HINGE_CHILD_TRANSFORM)
- has_translation = true;
+ if (pchan->bone->flag & BONE_HINGE_CHILD_TRANSFORM) {
+ has_translate_rotate[0] = true;
+ }
}
else {
- if ((pchan->protectflag & OB_LOCK_LOC) != OB_LOCK_LOC)
- has_translation = true;
+ if ((pchan->protectflag & OB_LOCK_LOC) != OB_LOCK_LOC) {
+ has_translate_rotate[0] = true;
+ }
+ }
+ if ((pchan->protectflag & OB_LOCK_ROT) != OB_LOCK_ROT) {
+ has_translate_rotate[1] = true;
}
- if ((pchan->protectflag & OB_LOCK_ROT) != OB_LOCK_ROT)
- has_rotation = true;
}
- else
- has_translation = true;
- }
- }
- }
-
- /* only modify transform mode if there are bones here that do something...
- * otherwise we get problems when multiple objects are selected
- */
- if (total) {
- /* if there are no translatable bones, do rotation */
- if (mode == TFM_TRANSLATION && !has_translation) {
- if (has_rotation) {
- *out_mode = TFM_ROTATION;
- }
- else {
- *out_mode = TFM_RESIZE;
+ else {
+ has_translate_rotate[1] = true;
+ }
}
}
}
@@ -868,6 +851,8 @@ static bool pchan_autoik_adjust(bPoseChannel *pchan, short chainlen)
/* change the chain-length of auto-ik */
void transform_autoik_update(TransInfo *t, short mode)
{
+ Main *bmain = CTX_data_main(t->context);
+
short *chainlen = &t->settings->autoik_chainlen;
bPoseChannel *pchan;
@@ -904,12 +889,12 @@ void transform_autoik_update(TransInfo *t, short mode)
if (changed) {
/* TODO(sergey): Consider doing partial update only. */
- DEG_relations_tag_update(G.main);
+ DEG_relations_tag_update(bmain);
}
}
/* frees temporal IKs */
-static void pose_grab_with_ik_clear(Object *ob)
+static void pose_grab_with_ik_clear(Main *bmain, Object *ob)
{
bKinematicConstraint *data;
bPoseChannel *pchan;
@@ -947,7 +932,7 @@ static void pose_grab_with_ik_clear(Object *ob)
if (relations_changed) {
/* TODO(sergey): Consider doing partial update only. */
- DEG_relations_tag_update(G.main);
+ DEG_relations_tag_update(bmain);
}
}
@@ -1055,7 +1040,7 @@ static short pose_grab_with_ik_children(bPose *pose, Bone *bone)
}
/* main call which adds temporal IK chains */
-static short pose_grab_with_ik(Object *ob)
+static short pose_grab_with_ik(Main *bmain, Object *ob)
{
bArmature *arm;
bPoseChannel *pchan, *parent;
@@ -1101,8 +1086,8 @@ static short pose_grab_with_ik(Object *ob)
/* iTaSC needs clear for new IK constraints */
if (tot_ik) {
BIK_clear_data(ob->pose);
- /* TODO(sergey): Consuder doing partial update only. */
- DEG_relations_tag_update(G.main);
+ /* TODO(sergey): Consider doing partial update only. */
+ DEG_relations_tag_update(bmain);
}
return (tot_ik) ? 1 : 0;
@@ -1125,18 +1110,18 @@ static void createTransPose(TransInfo *t, Object **objects, uint objects_len)
tc->poseobj = objects[th_index];
}
}
+ Main *bmain = CTX_data_main(t->context);
t->data_len_all = 0;
+ bool has_translate_rotate_buf[2] = {false, false};
+ bool *has_translate_rotate = (t->mode == TFM_TRANSLATION) ? has_translate_rotate_buf : NULL;
+
FOREACH_TRANS_DATA_CONTAINER (t, tc) {
Object *ob = tc->poseobj;
bArmature *arm;
- TransData *td;
- TransDataExtension *tdx;
short ik_on = 0;
- int i;
-
/* check validity of state */
arm = BKE_armature_from_object(tc->poseobj);
@@ -1153,16 +1138,34 @@ static void createTransPose(TransInfo *t, Object **objects, uint objects_len)
/* do we need to add temporal IK chains? */
if ((arm->flag & ARM_AUTO_IK) && t->mode == TFM_TRANSLATION) {
- ik_on = pose_grab_with_ik(ob);
+ ik_on = pose_grab_with_ik(bmain, ob);
if (ik_on) t->flag |= T_AUTOIK;
}
/* set flags and count total (warning, can change transform to rotate) */
- tc->data_len = count_set_pose_transflags(&t->mode, t->around, ob);
+ tc->data_len = count_set_pose_transflags(ob, t->mode, t->around, has_translate_rotate);
+ /* len may be zero, skip next iteration. */
+ }
+
+ /* if there are no translatable bones, do rotation */
+ if ((t->mode == TFM_TRANSLATION) && !has_translate_rotate[0]) {
+ if (has_translate_rotate[1]) {
+ t->mode = TFM_ROTATION;
+ }
+ else {
+ t->mode = TFM_RESIZE;
+ }
+ }
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
if (tc->data_len == 0) {
continue;
}
+ Object *ob = tc->poseobj;
+ TransData *td;
+ TransDataExtension *tdx;
+ short ik_on = 0;
+ int i;
tc->poseobj = ob; /* we also allow non-active objects to be transformed, in weightpaint */
@@ -1178,7 +1181,7 @@ static void createTransPose(TransInfo *t, Object **objects, uint objects_len)
td = tc->data;
for (bPoseChannel *pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
if (pchan->bone->flag & BONE_TRANSFORM) {
- add_pose_transdata(t, ob, pchan, ob, pchan, tc, td);
+ add_pose_transdata(t, pchan, ob, tc, td);
td++;
}
}
@@ -5619,18 +5622,17 @@ static bool constraints_list_needinv(TransInfo *t, ListBase *list)
/* transcribe given object into TransData for Transforming */
static void ObjectToTransData(TransInfo *t, TransData *td, Object *ob)
{
- Depsgraph *depsgraph = t->depsgraph;
Scene *scene = t->scene;
bool constinv;
bool skip_invert = false;
if (t->mode != TFM_DUMMY && ob->rigidbody_object) {
float rot[3][3], scale[3];
- float ctime = DEG_get_ctime(depsgraph);
+ float ctime = BKE_scene_frame_get(scene);
/* only use rigid body transform if simulation is running, avoids problems with initial setup of rigid bodies */
- // XXX: This needs fixing for COW. May need rigidbody_world from scene
if (BKE_rigidbody_check_sim_running(scene->rigidbody_world, ctime)) {
+
/* save original object transform */
copy_v3_v3(td->ext->oloc, ob->loc);
@@ -5665,26 +5667,21 @@ static void ObjectToTransData(TransInfo *t, TransData *td, Object *ob)
constinv = constraints_list_needinv(t, &ob->constraints);
/* disable constraints inversion for dummy pass */
- // XXX: Should this use ob or ob_eval?! It's not clear!
if (t->mode == TFM_DUMMY)
skip_invert = true;
- Scene *scene_eval = DEG_get_evaluated_scene(t->depsgraph);
if (skip_invert == false && constinv == false) {
- Object *ob_eval = DEG_get_evaluated_object(depsgraph, ob);
- ob_eval->transflag |= OB_NO_CONSTRAINTS; /* BKE_object_where_is_calc_time checks this */
- BKE_object_where_is_calc(t->depsgraph, scene_eval, ob_eval);
- ob_eval->transflag &= ~OB_NO_CONSTRAINTS;
- }
- else {
- Object *ob_eval = DEG_get_evaluated_object(depsgraph, ob);
- BKE_object_where_is_calc(t->depsgraph, scene_eval, ob_eval);
+ ob->transflag |= OB_NO_CONSTRAINTS; /* BKE_object_where_is_calc_time checks this */
+ BKE_object_where_is_calc(t->depsgraph, t->scene, ob);
+ ob->transflag &= ~OB_NO_CONSTRAINTS;
}
+ else
+ BKE_object_where_is_calc(t->depsgraph, t->scene, ob);
td->ob = ob;
td->loc = ob->loc;
- copy_v3_v3(td->iloc, ob->loc);
+ copy_v3_v3(td->iloc, td->loc);
if (ob->rotmode > 0) {
td->ext->rot = ob->rot;
@@ -5782,8 +5779,7 @@ static void trans_object_base_deps_flag_finish(ViewLayer *view_layer)
/* it deselects Bases, so we have to call the clear function always after */
static void set_trans_object_base_flags(TransInfo *t)
{
- /* TODO(sergey): Get rid of global, use explicit main. */
- Main *bmain = G.main;
+ Main *bmain = CTX_data_main(t->context);
ViewLayer *view_layer = t->view_layer;
Scene *scene = t->scene;
Depsgraph *depsgraph = BKE_scene_get_depsgraph(scene, view_layer, true);
@@ -5929,6 +5925,7 @@ static void clear_trans_object_base_flags(TransInfo *t)
// NOTE: context may not always be available, so must check before using it as it's a luxury for a few cases
void autokeyframe_ob_cb_func(bContext *C, Scene *scene, ViewLayer *view_layer, Object *ob, int tmode)
{
+ Main *bmain = CTX_data_main(C);
ID *id = &ob->id;
FCurve *fcu;
@@ -5961,7 +5958,7 @@ void autokeyframe_ob_cb_func(bContext *C, Scene *scene, ViewLayer *view_layer, O
if (adt && adt->action) {
for (fcu = adt->action->curves.first; fcu; fcu = fcu->next) {
fcu->flag &= ~FCURVE_SELECTED;
- insert_keyframe(depsgraph, reports, id, adt->action,
+ insert_keyframe(bmain, depsgraph, reports, id, adt->action,
(fcu->grp ? fcu->grp->name : NULL),
fcu->rna_path, fcu->array_index, cfra,
ts->keyframe_type, flag);
@@ -6050,6 +6047,7 @@ void autokeyframe_ob_cb_func(bContext *C, Scene *scene, ViewLayer *view_layer, O
// NOTE: context may not always be available, so must check before using it as it's a luxury for a few cases
void autokeyframe_pose_cb_func(bContext *C, Scene *scene, Object *ob, int tmode, short targetless_ik)
{
+ Main *bmain = CTX_data_main(C);
ID *id = &ob->id;
AnimData *adt = ob->adt;
bAction *act = (adt) ? adt->action : NULL;
@@ -6103,7 +6101,7 @@ void autokeyframe_pose_cb_func(bContext *C, Scene *scene, Object *ob, int tmode,
* NOTE: this will do constraints too, but those are ok to do here too?
*/
if (pchanName && STREQ(pchanName, pchan->name)) {
- insert_keyframe(depsgraph, reports, id, act,
+ insert_keyframe(bmain, depsgraph, reports, id, act,
((fcu->grp) ? (fcu->grp->name) : (NULL)),
fcu->rna_path, fcu->array_index, cfra,
ts->keyframe_type, flag);
@@ -6333,6 +6331,9 @@ static void special_aftertrans_update__mesh(bContext *UNUSED(C), TransInfo *t)
* */
void special_aftertrans_update(bContext *C, TransInfo *t)
{
+ Main *bmain = CTX_data_main(t->context);
+ BLI_assert(bmain == CTX_data_main(C));
+
Object *ob;
// short redrawipo=0, resetslowpar=1;
const bool canceled = (t->state == TRANS_CANCEL);
@@ -6521,7 +6522,7 @@ void special_aftertrans_update(bContext *C, TransInfo *t)
// XXX: BAD! this get gpencil datablocks directly from main db...
// but that's how this currently works :/
- for (gpd = G.main->gpencil.first; gpd; gpd = gpd->id.next) {
+ for (gpd = bmain->gpencil.first; gpd; gpd = gpd->id.next) {
if (ID_REAL_USERS(gpd))
posttrans_gpd_clean(gpd);
}
@@ -6541,7 +6542,7 @@ void special_aftertrans_update(bContext *C, TransInfo *t)
// XXX: BAD! this get gpencil datablocks directly from main db...
// but that's how this currently works :/
- for (mask = G.main->mask.first; mask; mask = mask->id.next) {
+ for (mask = bmain->mask.first; mask; mask = mask->id.next) {
if (ID_REAL_USERS(mask))
posttrans_mask_clean(mask);
}
@@ -6690,8 +6691,9 @@ void special_aftertrans_update(bContext *C, TransInfo *t)
}
/* set BONE_TRANSFORM flags for autokey, manipulator draw might have changed them */
- if (!canceled && (t->mode != TFM_DUMMY))
- count_set_pose_transflags(&t->mode, t->around, ob);
+ if (!canceled && (t->mode != TFM_DUMMY)) {
+ count_set_pose_transflags(ob, t->mode, t->around, NULL);
+ }
/* if target-less IK grabbing, we calculate the pchan transforms and clear flag */
if (!canceled && t->mode == TFM_TRANSLATION)
@@ -6705,7 +6707,7 @@ void special_aftertrans_update(bContext *C, TransInfo *t)
}
if (t->mode == TFM_TRANSLATION)
- pose_grab_with_ik_clear(ob);
+ pose_grab_with_ik_clear(bmain, ob);
/* automatic inserting of keys and unkeyed tagging - only if transform wasn't canceled (or TFM_DUMMY) */
if (!canceled && (t->mode != TFM_DUMMY)) {
@@ -8451,6 +8453,7 @@ void createTransData(bContext *C, TransInfo *t)
}
else if (t->spacetype == SPACE_ACTION) {
t->flag |= T_POINTS | T_2D_EDIT;
+ t->obedit_type = -1;
createTransActionData(C, t);
countAndCleanTransDataContainer(t);
@@ -8463,17 +8466,23 @@ void createTransData(bContext *C, TransInfo *t)
}
else if (t->spacetype == SPACE_NLA) {
t->flag |= T_POINTS | T_2D_EDIT;
+ t->obedit_type = -1;
+
createTransNlaData(C, t);
countAndCleanTransDataContainer(t);
}
else if (t->spacetype == SPACE_SEQ) {
t->flag |= T_POINTS | T_2D_EDIT;
+ t->obedit_type = -1;
+
t->num.flag |= NUM_NO_FRACTION; /* sequencer has no use for floating point transformations */
createTransSeqData(C, t);
countAndCleanTransDataContainer(t);
}
else if (t->spacetype == SPACE_IPO) {
t->flag |= T_POINTS | T_2D_EDIT;
+ t->obedit_type = -1;
+
createTransGraphEditData(C, t);
countAndCleanTransDataContainer(t);
@@ -8485,6 +8494,7 @@ void createTransData(bContext *C, TransInfo *t)
}
else if (t->spacetype == SPACE_NODE) {
t->flag |= T_POINTS | T_2D_EDIT;
+ t->obedit_type = -1;
createTransNodeData(C, t);
countAndCleanTransDataContainer(t);
@@ -8497,6 +8507,8 @@ void createTransData(bContext *C, TransInfo *t)
}
else if (t->spacetype == SPACE_CLIP) {
t->flag |= T_POINTS | T_2D_EDIT;
+ t->obedit_type = -1;
+
if (t->options & CTX_MOVIECLIP) {
createTransTrackingData(C, t);
countAndCleanTransDataContainer(t);
@@ -8598,7 +8610,10 @@ void createTransData(bContext *C, TransInfo *t)
countAndCleanTransDataContainer(t);
}
}
-
+ }
+ /* Mark as initialized if above checks fail. */
+ if (t->data_len_all == -1) {
+ t->data_len_all = 0;
}
}
else if (ob && (ob->mode & OB_MODE_PARTICLE_EDIT) && PE_start_edit(PE_get_current(scene, ob))) {
diff --git a/source/blender/editors/transform/transform_generics.c b/source/blender/editors/transform/transform_generics.c
index 576bfddd28c..d3fcd5e5911 100644
--- a/source/blender/editors/transform/transform_generics.c
+++ b/source/blender/editors/transform/transform_generics.c
@@ -359,6 +359,7 @@ static void recalcData_actedit(TransInfo *t)
/* initialize relevant anim-context 'context' data from TransInfo data */
/* NOTE: sync this with the code in ANIM_animdata_get_context() */
+ ac.bmain = CTX_data_main(t->context);
ac.scene = t->scene;
ac.view_layer = t->view_layer;
ac.obact = OBACT(view_layer);
@@ -386,7 +387,7 @@ static void recalcData_actedit(TransInfo *t)
if ((saction->flag & SACTION_NOREALTIMEUPDATES) == 0) {
for (ale = anim_data.first; ale; ale = ale->next) {
/* set refresh tags for objects using this animation */
- ANIM_list_elem_update(t->scene, ale);
+ ANIM_list_elem_update(CTX_data_main(t->context), t->scene, ale);
}
}
@@ -409,6 +410,7 @@ static void recalcData_graphedit(TransInfo *t)
/* initialize relevant anim-context 'context' data from TransInfo data */
/* NOTE: sync this with the code in ANIM_animdata_get_context() */
+ ac.bmain = CTX_data_main(t->context);
ac.scene = t->scene;
ac.view_layer = t->view_layer;
ac.obact = OBACT(view_layer);
@@ -445,7 +447,7 @@ static void recalcData_graphedit(TransInfo *t)
* BUT only if realtime updates are enabled
*/
if ((sipo->flag & SIPO_NOREALTIMEUPDATES) == 0)
- ANIM_list_elem_update(t->scene, ale);
+ ANIM_list_elem_update(CTX_data_main(t->context), t->scene, ale);
}
/* do resort and other updates? */
diff --git a/source/blender/editors/transform/transform_manipulator_3d.c b/source/blender/editors/transform/transform_manipulator_3d.c
index b94ccf42325..b6782470f96 100644
--- a/source/blender/editors/transform/transform_manipulator_3d.c
+++ b/source/blender/editors/transform/transform_manipulator_3d.c
@@ -586,7 +586,6 @@ int ED_transform_calc_manipulator_stats(
const struct TransformCalcParams *params,
struct TransformBounds *tbounds)
{
- const Depsgraph *depsgraph = CTX_data_depsgraph(C);
ScrArea *sa = CTX_wm_area(C);
ARegion *ar = CTX_wm_region(C);
Scene *scene = CTX_data_scene(C);
@@ -596,8 +595,6 @@ int ED_transform_calc_manipulator_stats(
RegionView3D *rv3d = ar->regiondata;
Base *base;
Object *ob = OBACT(view_layer);
- Object *ob_eval = NULL;
- Object *obedit_eval = NULL;
bGPdata *gpd = CTX_data_gpencil_data(C);
const bool is_gp_edit = ((gpd) && (gpd->flag & GP_DATA_STROKE_EDITMODE));
int a, totsel = 0;
@@ -612,9 +609,6 @@ int ED_transform_calc_manipulator_stats(
rv3d->twdrawflag = 0xFFFF;
- ob_eval = DEG_get_evaluated_object(depsgraph, ob);
- obedit_eval = DEG_get_evaluated_object(depsgraph, obedit);
-
/* global, local or normal orientation?
* if we could check 'totsel' now, this should be skipped with no selection. */
if (ob && !is_gp_edit) {
@@ -629,7 +623,7 @@ int ED_transform_calc_manipulator_stats(
case V3D_MANIP_GIMBAL:
{
float mat[3][3];
- if (gimbal_axis(ob_eval, mat)) {
+ if (gimbal_axis(ob, mat)) {
copy_m4_m3(rv3d->twmat, mat);
break;
}
@@ -659,7 +653,7 @@ int ED_transform_calc_manipulator_stats(
copy_m4_m3(rv3d->twmat, mat);
break;
}
- copy_m4_m4(rv3d->twmat, ob_eval->obmat);
+ copy_m4_m4(rv3d->twmat, ob->obmat);
normalize_m4(rv3d->twmat);
break;
}
@@ -699,7 +693,7 @@ int ED_transform_calc_manipulator_stats(
copy_m3_m4(tbounds->axis, rv3d->twmat);
if (params->use_local_axis && (ob && ob->mode & OB_MODE_EDIT)) {
float diff_mat[3][3];
- copy_m3_m4(diff_mat, ob_eval->obmat);
+ copy_m3_m4(diff_mat, ob->obmat);
normalize_m3(diff_mat);
invert_m3(diff_mat);
mul_m3_m3m3(tbounds->axis, tbounds->axis, diff_mat);
@@ -762,7 +756,6 @@ int ED_transform_calc_manipulator_stats(
}
else if (obedit) {
ob = obedit;
- ob_eval = obedit_eval;
if (obedit->type == OB_MESH) {
BMEditMesh *em = BKE_editmesh_from_object(obedit);
BMEditSelection ese;
@@ -937,9 +930,9 @@ int ED_transform_calc_manipulator_stats(
/* selection center */
if (totsel) {
mul_v3_fl(tbounds->center, 1.0f / (float)totsel); // centroid!
- mul_m4_v3(obedit_eval->obmat, tbounds->center);
- mul_m4_v3(obedit_eval->obmat, tbounds->min);
- mul_m4_v3(obedit_eval->obmat, tbounds->max);
+ mul_m4_v3(obedit->obmat, tbounds->center);
+ mul_m4_v3(obedit->obmat, tbounds->min);
+ mul_m4_v3(obedit->obmat, tbounds->max);
}
}
else if (ob && (ob->mode & OB_MODE_POSE)) {
@@ -947,7 +940,7 @@ int ED_transform_calc_manipulator_stats(
int mode = TFM_ROTATION; // mislead counting bones... bah. We don't know the manipulator mode, could be mixed
bool ok = false;
- if ((pivot_point == V3D_AROUND_ACTIVE) && (pchan = BKE_pose_channel_active(ob_eval))) {
+ if ((pivot_point == V3D_AROUND_ACTIVE) && (pchan = BKE_pose_channel_active(ob))) {
/* doesn't check selection or visibility intentionally */
Bone *bone = pchan->bone;
if (bone) {
@@ -958,11 +951,11 @@ int ED_transform_calc_manipulator_stats(
}
}
else {
- totsel = count_set_pose_transflags(&mode, 0, ob_eval);
+ totsel = count_set_pose_transflags(ob, mode, V3D_AROUND_CENTER_BOUNDS, NULL);
if (totsel) {
/* use channels to get stats */
- for (pchan = ob_eval->pose->chanbase.first; pchan; pchan = pchan->next) {
+ for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
Bone *bone = pchan->bone;
if (bone && (bone->flag & BONE_TRANSFORM)) {
calc_tw_center(tbounds, pchan->pose_head);
@@ -975,9 +968,9 @@ int ED_transform_calc_manipulator_stats(
if (ok) {
mul_v3_fl(tbounds->center, 1.0f / (float)totsel); // centroid!
- mul_m4_v3(ob_eval->obmat, tbounds->center);
- mul_m4_v3(ob_eval->obmat, tbounds->min);
- mul_m4_v3(ob_eval->obmat, tbounds->max);
+ mul_m4_v3(ob->obmat, tbounds->center);
+ mul_m4_v3(ob->obmat, tbounds->min);
+ mul_m4_v3(ob->obmat, tbounds->max);
}
}
else if (ob && (ob->mode & OB_MODE_ALL_PAINT)) {
@@ -1018,18 +1011,16 @@ int ED_transform_calc_manipulator_stats(
if (!TESTBASELIB(base)) {
continue;
}
- Object *base_object_eval = DEG_get_evaluated_object(depsgraph, base->object);
if (ob == NULL) {
ob = base->object;
- ob_eval = base_object_eval;
}
- if (params->use_only_center || base_object_eval->bb == NULL) {
- calc_tw_center(tbounds, base_object_eval->obmat[3]);
+ if (params->use_only_center || base->object->bb == NULL) {
+ calc_tw_center(tbounds, base->object->obmat[3]);
}
else {
for (uint j = 0; j < 8; j++) {
float co[3];
- mul_v3_m4v3(co, base_object_eval->obmat, base_object_eval->bb->vec[j]);
+ mul_v3_m4v3(co, base->object->obmat, base->object->bb->vec[j]);
calc_tw_center(tbounds, co);
}
}
@@ -1547,12 +1538,6 @@ static void WIDGETGROUP_manipulator_draw_prepare(const bContext *C, wmManipulato
static bool WIDGETGROUP_manipulator_poll(const struct bContext *C, struct wmManipulatorGroupType *wgt)
{
/* it's a given we only use this in 3D view */
- ScrArea *sa = CTX_wm_area(C);
- View3D *v3d = sa->spacedata.first;
- if (v3d && ((v3d->twflag & V3D_MANIPULATOR_DRAW)) == 0) {
- return false;
- }
-
bToolRef_Runtime *tref_rt = WM_toolsystem_runtime_from_context((bContext *)C);
if ((tref_rt == NULL) ||
!STREQ(wgt->idname, tref_rt->manipulator_group))
@@ -1593,12 +1578,6 @@ struct XFormCageWidgetGroup {
static bool WIDGETGROUP_xform_cage_poll(const bContext *C, wmManipulatorGroupType *wgt)
{
- ScrArea *sa = CTX_wm_area(C);
- View3D *v3d = sa->spacedata.first;
- if (v3d && ((v3d->twflag & V3D_MANIPULATOR_DRAW)) == 0) {
- return false;
- }
-
bToolRef_Runtime *tref_rt = WM_toolsystem_runtime_from_context((bContext *)C);
if (!STREQ(wgt->idname, tref_rt->manipulator_group)) {
WM_manipulator_group_type_unlink_delayed_ptr(wgt);
diff --git a/source/blender/editors/transform/transform_orientations.c b/source/blender/editors/transform/transform_orientations.c
index 3065007ea6b..19df46455d7 100644
--- a/source/blender/editors/transform/transform_orientations.c
+++ b/source/blender/editors/transform/transform_orientations.c
@@ -56,8 +56,6 @@
#include "BKE_scene.h"
#include "BKE_workspace.h"
-#include "DEG_depsgraph_query.h"
-
#include "BLT_translation.h"
#include "ED_armature.h"
@@ -1016,14 +1014,12 @@ int getTransformOrientation_ex(const bContext *C, float normal[3], float plane[3
}
}
else if (ob && (ob->mode & OB_MODE_POSE)) {
- const Depsgraph *depsgraph = CTX_data_depsgraph(C);
- Object *ob_eval = DEG_get_evaluated_object(depsgraph, ob);
- bArmature *arm = ob_eval->data;
+ bArmature *arm = ob->data;
bPoseChannel *pchan;
float imat[3][3], mat[3][3];
bool ok = false;
- if (activeOnly && (pchan = BKE_pose_channel_active(ob_eval))) {
+ if (activeOnly && (pchan = BKE_pose_channel_active(ob))) {
add_v3_v3(normal, pchan->pose_mat[2]);
add_v3_v3(plane, pchan->pose_mat[1]);
ok = true;
@@ -1034,7 +1030,7 @@ int getTransformOrientation_ex(const bContext *C, float normal[3], float plane[3
totsel = count_bone_select(arm, &arm->bonebase, true);
if (totsel) {
/* use channels to get stats */
- for (pchan = ob_eval->pose->chanbase.first; pchan; pchan = pchan->next) {
+ for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
if (pchan->bone && pchan->bone->flag & BONE_TRANSFORM) {
add_v3_v3(normal, pchan->pose_mat[2]);
add_v3_v3(plane, pchan->pose_mat[1]);
@@ -1047,7 +1043,7 @@ int getTransformOrientation_ex(const bContext *C, float normal[3], float plane[3
/* use for both active & all */
if (ok) {
/* we need the transpose of the inverse for a normal... */
- copy_m3_m4(imat, ob_eval->obmat);
+ copy_m3_m4(imat, ob->obmat);
invert_m3_m3(mat, imat);
transpose_m3(mat);
diff --git a/source/blender/editors/transform/transform_snap.c b/source/blender/editors/transform/transform_snap.c
index 10de7f3ea36..704582deaca 100644
--- a/source/blender/editors/transform/transform_snap.c
+++ b/source/blender/editors/transform/transform_snap.c
@@ -406,6 +406,11 @@ void applyGridAbsolute(TransInfo *t)
void applySnapping(TransInfo *t, float *vec)
{
+ if (t->tsnap.project && t->tsnap.mode == SCE_SNAP_MODE_FACE) {
+ /* Each Trans Data already makes the snap to face */
+ return;
+ }
+
if (t->tsnap.status & SNAP_FORCED) {
t->tsnap.targetSnap(t);
@@ -495,6 +500,7 @@ static bool bm_face_is_snap_target(BMFace *f, void *UNUSED(user_data))
static void initSnappingMode(TransInfo *t)
{
+ Main *bmain = CTX_data_main(t->context);
ToolSettings *ts = t->settings;
/* All obedit types will match. */
const int obedit_type = t->data_container->obedit ? t->data_container->obedit->type : -1;
@@ -582,7 +588,7 @@ static void initSnappingMode(TransInfo *t)
if (t->spacetype == SPACE_VIEW3D) {
if (t->tsnap.object_context == NULL) {
t->tsnap.object_context = ED_transform_snap_object_context_create_view3d(
- t->scene, t->depsgraph, 0, t->ar, t->view);
+ bmain, t->scene, t->depsgraph, 0, t->ar, t->view);
ED_transform_snap_object_context_set_editmesh_callbacks(
t->tsnap.object_context,
diff --git a/source/blender/editors/transform/transform_snap_object.c b/source/blender/editors/transform/transform_snap_object.c
index 5932a35bf2b..e19320fa220 100644
--- a/source/blender/editors/transform/transform_snap_object.c
+++ b/source/blender/editors/transform/transform_snap_object.c
@@ -56,6 +56,7 @@
#include "BKE_tracking.h"
#include "BKE_context.h"
#include "BKE_mesh.h"
+#include "BKE_mesh_runtime.h"
#include "DEG_depsgraph.h"
#include "DEG_depsgraph_query.h"
@@ -113,6 +114,7 @@ typedef struct SnapObjectData_EditMesh {
} SnapObjectData_EditMesh;
struct SnapObjectContext {
+ Main *bmain;
Scene *scene;
Depsgraph *depsgraph;
@@ -2269,12 +2271,13 @@ static short snapObjectsRay(
* \{ */
SnapObjectContext *ED_transform_snap_object_context_create(
- Scene *scene, Depsgraph *depsgraph, int flag)
+ Main *bmain, Scene *scene, Depsgraph *depsgraph, int flag)
{
SnapObjectContext *sctx = MEM_callocN(sizeof(*sctx), __func__);
sctx->flag = flag;
+ sctx->bmain = bmain;
sctx->scene = scene;
sctx->depsgraph = depsgraph;
@@ -2285,11 +2288,11 @@ SnapObjectContext *ED_transform_snap_object_context_create(
}
SnapObjectContext *ED_transform_snap_object_context_create_view3d(
- Scene *scene, Depsgraph *depsgraph, int flag,
+ Main *bmain, Scene *scene, Depsgraph *depsgraph, int flag,
/* extra args for view3d */
const ARegion *ar, const View3D *v3d)
{
- SnapObjectContext *sctx = ED_transform_snap_object_context_create(scene, depsgraph, flag);
+ SnapObjectContext *sctx = ED_transform_snap_object_context_create(bmain, scene, depsgraph, flag);
sctx->use_v3d = true;
sctx->v3d_data.ar = ar;
diff --git a/source/blender/editors/util/ed_util.c b/source/blender/editors/util/ed_util.c
index 44e2fa98f53..447cff065b7 100644
--- a/source/blender/editors/util/ed_util.c
+++ b/source/blender/editors/util/ed_util.c
@@ -263,7 +263,7 @@ void unpack_menu(bContext *C, const char *opname, const char *id_name, const cha
BLI_split_file_part(abs_name, fi, sizeof(fi));
BLI_snprintf(local_name, sizeof(local_name), "//%s/%s", folder, fi);
if (!STREQ(abs_name, local_name)) {
- switch (checkPackedFile(bmain->name, local_name, pf)) {
+ switch (checkPackedFile(BKE_main_blendfile_path(bmain), local_name, pf)) {
case PF_NOFILE:
BLI_snprintf(line, sizeof(line), IFACE_("Create %s"), local_name);
uiItemFullO_ptr(layout, ot, line, ICON_NONE, NULL, WM_OP_EXEC_DEFAULT, 0, &props_ptr);
@@ -296,7 +296,7 @@ void unpack_menu(bContext *C, const char *opname, const char *id_name, const cha
}
}
- switch (checkPackedFile(bmain->name, abs_name, pf)) {
+ switch (checkPackedFile(BKE_main_blendfile_path(bmain), abs_name, pf)) {
case PF_NOFILE:
BLI_snprintf(line, sizeof(line), IFACE_("Create %s"), abs_name);
//uiItemEnumO_ptr(layout, ot, line, 0, "method", PF_WRITE_ORIGINAL);
diff --git a/source/blender/editors/uvedit/uvedit_draw.c b/source/blender/editors/uvedit/uvedit_draw.c
index e467c61609d..4473922841f 100644
--- a/source/blender/editors/uvedit/uvedit_draw.c
+++ b/source/blender/editors/uvedit/uvedit_draw.c
@@ -87,6 +87,8 @@ void ED_image_draw_cursor(ARegion *ar, const float cursor[2])
x_fac = zoom[0];
y_fac = zoom[1];
+ glLineWidth(1.0f);
+
gpuTranslate2fv(cursor);
const uint shdr_pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
diff --git a/source/blender/editors/uvedit/uvedit_ops.c b/source/blender/editors/uvedit/uvedit_ops.c
index 6d5a1925dd5..45a6ccfe28b 100644
--- a/source/blender/editors/uvedit/uvedit_ops.c
+++ b/source/blender/editors/uvedit/uvedit_ops.c
@@ -4437,7 +4437,7 @@ void ED_keymap_uvedit(wmKeyConfig *keyconf)
WM_keymap_add_item(keymap, "UV_OT_select_pinned", PKEY, KM_PRESS, KM_SHIFT, 0);
- WM_keymap_add_menu(keymap, "IMAGE_MT_uvs_weldalign", WKEY, KM_PRESS, 0, 0);
+ WM_keymap_add_menu(keymap, "IMAGE_MT_uvs_weldalign", WKEY, KM_PRESS, KM_SHIFT, 0);
/* uv operations */
WM_keymap_add_item(keymap, "UV_OT_stitch", VKEY, KM_PRESS, 0, 0);
diff --git a/source/blender/freestyle/intern/blender_interface/BlenderFileLoader.cpp b/source/blender/freestyle/intern/blender_interface/BlenderFileLoader.cpp
index 6cbdca756d5..f41a9b58085 100644
--- a/source/blender/freestyle/intern/blender_interface/BlenderFileLoader.cpp
+++ b/source/blender/freestyle/intern/blender_interface/BlenderFileLoader.cpp
@@ -95,7 +95,7 @@ NodeGroup *BlenderFileLoader::Load()
int id = 0;
DEG_OBJECT_ITER_BEGIN(
- depsgraph, ob, DEG_ITER_OBJECT_MODE_RENDER,
+ depsgraph, ob,
DEG_ITER_OBJECT_FLAG_LINKED_DIRECTLY |
DEG_ITER_OBJECT_FLAG_LINKED_VIA_SET |
DEG_ITER_OBJECT_FLAG_VISIBLE |
diff --git a/source/blender/gpu/GPU_material.h b/source/blender/gpu/GPU_material.h
index 95492016f25..0805cc25d04 100644
--- a/source/blender/gpu/GPU_material.h
+++ b/source/blender/gpu/GPU_material.h
@@ -238,7 +238,7 @@ GPUNodeLink *GPU_uniformbuffer_link_out(
void GPU_material_output_link(GPUMaterial *material, GPUNodeLink *link);
GPUBuiltin GPU_get_material_builtins(GPUMaterial *material);
-void GPU_material_sss_profile_create(GPUMaterial *material, float *radii, short *falloff_type, float *sharpness);
+void GPU_material_sss_profile_create(GPUMaterial *material, float radii[3], short *falloff_type, float *sharpness);
struct GPUUniformBuffer *GPU_material_sss_profile_get(
GPUMaterial *material, int sample_ct, struct GPUTexture **tex_profile);
@@ -246,22 +246,26 @@ struct GPUUniformBuffer *GPU_material_sss_profile_get(
GPUMaterial *GPU_material_from_nodetree_find(
struct ListBase *gpumaterials, const void *engine_type, int options);
GPUMaterial *GPU_material_from_nodetree(
- struct Scene *scene, struct bNodeTree *ntree, struct ListBase *gpumaterials, const void *engine_type, int options);
-void GPU_material_generate_pass(
- GPUMaterial *mat, const char *vert_code, const char *geom_code, const char *frag_lib, const char *defines);
+ struct Scene *scene, struct bNodeTree *ntree, struct ListBase *gpumaterials, const void *engine_type, int options,
+ const char *vert_code, const char *geom_code, const char *frag_lib, const char *defines);
+void GPU_material_compile(GPUMaterial *mat);
void GPU_material_free(struct ListBase *gpumaterial);
void GPU_materials_free(void);
+void GPU_material_orphans_init(void);
+void GPU_material_orphans_exit(void);
+/* This has to be called from a thread with an ogl context bound. */
+void GPU_material_orphans_delete(void);
+
struct Scene *GPU_material_scene(GPUMaterial *material);
GPUMatType GPU_Material_get_type(GPUMaterial *material);
struct GPUPass *GPU_material_get_pass(GPUMaterial *material);
struct ListBase *GPU_material_get_inputs(GPUMaterial *material);
GPUMaterialStatus GPU_material_status(GPUMaterial *mat);
-struct GPUUniformBuffer *GPU_material_get_uniform_buffer(GPUMaterial *material);
-void GPU_material_create_uniform_buffer(GPUMaterial *material, struct ListBase *inputs);
-void GPU_material_uniform_buffer_tag_dirty(struct ListBase *gpumaterials);
+struct GPUUniformBuffer *GPU_material_uniform_buffer_get(GPUMaterial *material);
+void GPU_material_uniform_buffer_create(GPUMaterial *material, ListBase *inputs);
void GPU_material_vertex_attributes(GPUMaterial *material,
struct GPUVertexAttribs *attrib);
@@ -270,6 +274,7 @@ bool GPU_material_do_color_management(GPUMaterial *mat);
bool GPU_material_use_domain_surface(GPUMaterial *mat);
bool GPU_material_use_domain_volume(GPUMaterial *mat);
+void GPU_pass_cache_init(void);
void GPU_pass_cache_garbage_collect(void);
void GPU_pass_cache_free(void);
diff --git a/source/blender/gpu/GPU_texture.h b/source/blender/gpu/GPU_texture.h
index 5b125951d9d..3b4cdc21b9d 100644
--- a/source/blender/gpu/GPU_texture.h
+++ b/source/blender/gpu/GPU_texture.h
@@ -173,10 +173,10 @@ void GPU_invalid_tex_free(void);
void GPU_texture_free(GPUTexture *tex);
-void GPU_texture_init_orphans(void);
-void GPU_texture_exit_orphans(void);
+void GPU_texture_orphans_init(void);
+void GPU_texture_orphans_exit(void);
/* This has to be called from a thread with an ogl context bound. */
-void GPU_texture_delete_orphans(void);
+void GPU_texture_orphans_delete(void);
void GPU_texture_ref(GPUTexture *tex);
void GPU_texture_bind(GPUTexture *tex, int number);
diff --git a/source/blender/gpu/GPU_uniformbuffer.h b/source/blender/gpu/GPU_uniformbuffer.h
index c2480f8ba03..2f422fa1a92 100644
--- a/source/blender/gpu/GPU_uniformbuffer.h
+++ b/source/blender/gpu/GPU_uniformbuffer.h
@@ -35,7 +35,6 @@
struct ListBase;
typedef struct GPUUniformBuffer GPUUniformBuffer;
-typedef struct GPUUniformBufferDynamicItem GPUUniformBufferDynamicItem;
GPUUniformBuffer *GPU_uniformbuffer_create(int size, const void *data, char err_out[256]);
GPUUniformBuffer *GPU_uniformbuffer_dynamic_create(struct ListBase *inputs, char err_out[256]);
@@ -52,7 +51,6 @@ int GPU_uniformbuffer_bindpoint(GPUUniformBuffer *ubo);
bool GPU_uniformbuffer_is_empty(GPUUniformBuffer *ubo);
bool GPU_uniformbuffer_is_dirty(GPUUniformBuffer *ubo);
-void GPU_uniformbuffer_tag_dirty(GPUUniformBuffer *ubo);
#define GPU_UBO_BLOCK_NAME "nodeTree"
diff --git a/source/blender/gpu/intern/gpu_codegen.c b/source/blender/gpu/intern/gpu_codegen.c
index 22665e2c0bf..0dd9d1f0908 100644
--- a/source/blender/gpu/intern/gpu_codegen.c
+++ b/source/blender/gpu/intern/gpu_codegen.c
@@ -40,10 +40,11 @@
#include "BLI_blenlib.h"
#include "BLI_hash_mm2a.h"
-#include "BLI_linklist.h"
+#include "BLI_link_utils.h"
#include "BLI_utildefines.h"
#include "BLI_dynstr.h"
#include "BLI_ghash.h"
+#include "BLI_threads.h"
#include "PIL_time.h"
@@ -75,39 +76,54 @@ static char *glsl_material_library = NULL;
* same for 2 different Materials. Unused GPUPasses are free by Garbage collection.
**/
-static LinkNode *pass_cache = NULL; /* GPUPass */
+/* Only use one linklist that contains the GPUPasses grouped by hash. */
+static GPUPass *pass_cache = NULL;
+static SpinLock pass_cache_spin;
-static uint32_t gpu_pass_hash(const char *vert, const char *geom, const char *frag, const char *defs)
+static uint32_t gpu_pass_hash(const char *frag_gen, const char *defs)
{
BLI_HashMurmur2A hm2a;
BLI_hash_mm2a_init(&hm2a, 0);
- BLI_hash_mm2a_add(&hm2a, (unsigned char *)frag, strlen(frag));
- BLI_hash_mm2a_add(&hm2a, (unsigned char *)vert, strlen(vert));
+ BLI_hash_mm2a_add(&hm2a, (unsigned char *)frag_gen, strlen(frag_gen));
if (defs)
BLI_hash_mm2a_add(&hm2a, (unsigned char *)defs, strlen(defs));
- if (geom)
- BLI_hash_mm2a_add(&hm2a, (unsigned char *)geom, strlen(geom));
return BLI_hash_mm2a_end(&hm2a);
}
-/* Search by hash then by exact string match. */
-static GPUPass *gpu_pass_cache_lookup(
- const char *vert, const char *geom, const char *frag, const char *defs, uint32_t hash)
+/* Search by hash only. Return first pass with the same hash.
+ * There is hash collision if (pass->next && pass->next->hash == hash) */
+static GPUPass *gpu_pass_cache_lookup(uint32_t hash)
{
- for (LinkNode *ln = pass_cache; ln; ln = ln->next) {
- GPUPass *pass = (GPUPass *)ln->link;
+ BLI_spin_lock(&pass_cache_spin);
+ /* Could be optimized with a Lookup table. */
+ for (GPUPass *pass = pass_cache; pass; pass = pass->next) {
if (pass->hash == hash) {
- /* Note: Could be made faster if that becomes a real bottleneck. */
- if ((defs != NULL) && (strcmp(pass->defines, defs) != 0)) { /* Pass */ }
- else if ((geom != NULL) && (strcmp(pass->geometrycode, geom) != 0)) { /* Pass */ }
- else if ((strcmp(pass->fragmentcode, frag) == 0) &&
- (strcmp(pass->vertexcode, vert) == 0))
- {
- return pass;
- }
+ BLI_spin_unlock(&pass_cache_spin);
+ return pass;
}
}
+ BLI_spin_unlock(&pass_cache_spin);
+ return NULL;
+}
+
+/* Check all possible passes with the same hash. */
+static GPUPass *gpu_pass_cache_resolve_collision(
+ GPUPass *pass, const char *vert, const char *geom, const char *frag, const char *defs, uint32_t hash)
+{
+ BLI_spin_lock(&pass_cache_spin);
+ /* Collision, need to strcmp the whole shader. */
+ for (; pass && (pass->hash == hash); pass = pass->next) {
+ if ((defs != NULL) && (strcmp(pass->defines, defs) != 0)) { /* Pass */ }
+ else if ((geom != NULL) && (strcmp(pass->geometrycode, geom) != 0)) { /* Pass */ }
+ else if ((strcmp(pass->fragmentcode, frag) == 0) &&
+ (strcmp(pass->vertexcode, vert) == 0))
+ {
+ BLI_spin_unlock(&pass_cache_spin);
+ return pass;
+ }
+ }
+ BLI_spin_unlock(&pass_cache_spin);
return NULL;
}
@@ -656,7 +672,7 @@ static int codegen_process_uniforms_functions(GPUMaterial *material, DynStr *ds,
/* Handle the UBO block separately. */
if ((material != NULL) && !BLI_listbase_is_empty(&ubo_inputs)) {
- GPU_material_create_uniform_buffer(material, &ubo_inputs);
+ GPU_material_uniform_buffer_create(material, &ubo_inputs);
/* Inputs are sorted */
BLI_dynstr_appendf(ds, "\nlayout (std140) uniform %s {\n", GPU_UBO_BLOCK_NAME);
@@ -1099,12 +1115,12 @@ void GPU_code_generate_glsl_lib(void)
/* GPU pass binding/unbinding */
-GPUShader *GPU_pass_shader(GPUPass *pass)
+GPUShader *GPU_pass_shader_get(GPUPass *pass)
{
return pass->shader;
}
-static void gpu_nodes_extract_dynamic_inputs(GPUShader *shader, ListBase *inputs, ListBase *nodes)
+void GPU_nodes_extract_dynamic_inputs(GPUShader *shader, ListBase *inputs, ListBase *nodes)
{
GPUNode *node;
GPUInput *next, *input;
@@ -1146,8 +1162,12 @@ static void gpu_nodes_extract_dynamic_inputs(GPUShader *shader, ListBase *inputs
if (input->bindtex)
extract = 1;
}
- else if (input->dynamicvec)
+ else if (input->dynamictype == GPU_DYNAMIC_UBO) {
+ /* Don't extract UBOs */
+ }
+ else if (input->dynamicvec) {
extract = 1;
+ }
if (extract)
input->shaderloc = GPU_shader_get_uniform(shader, input->shadername);
@@ -1896,16 +1916,25 @@ void GPU_nodes_prune(ListBase *nodes, GPUNodeLink *outlink)
}
}
+static bool gpu_pass_is_valid(GPUPass *pass)
+{
+ /* Shader is not null if compilation is successful,
+ * refcount is positive if compilation as not yet been done. */
+ return (pass->shader != NULL || pass->refcount > 0);
+}
+
GPUPass *GPU_generate_pass_new(
GPUMaterial *material,
- GPUNodeLink *frag_outlink, struct GPUVertexAttribs *attribs,
- ListBase *nodes, ListBase *inputs,
- const char *vert_code, const char *geom_code,
- const char *frag_lib, const char *defines)
+ GPUNodeLink *frag_outlink,
+ struct GPUVertexAttribs *attribs,
+ ListBase *nodes,
+ const char *vert_code,
+ const char *geom_code,
+ const char *frag_lib,
+ const char *defines)
{
char *vertexcode, *geometrycode, *fragmentcode;
- GPUShader *shader;
- GPUPass *pass;
+ GPUPass *pass = NULL, *pass_hash = NULL;
/* prune unused nodes */
GPU_nodes_prune(nodes, frag_outlink);
@@ -1914,6 +1943,24 @@ GPUPass *GPU_generate_pass_new(
/* generate code */
char *fragmentgen = code_generate_fragment(material, nodes, frag_outlink->output);
+
+ /* Cache lookup: Reuse shaders already compiled */
+ uint32_t hash = gpu_pass_hash(fragmentgen, defines);
+ pass_hash = gpu_pass_cache_lookup(hash);
+
+ if (pass_hash && (pass_hash->next == NULL || pass_hash->next->hash != hash)) {
+ /* No collision, just return the pass. */
+ MEM_freeN(fragmentgen);
+ if (!gpu_pass_is_valid(pass_hash)) {
+ /* Shader has already been created but failed to compile. */
+ return NULL;
+ }
+ pass_hash->refcount += 1;
+ return pass_hash;
+ }
+
+ /* Either the shader is not compiled or there is a hash collision...
+ * continue generating the shader strings. */
char *tmp = BLI_strdupcat(frag_lib, glsl_material_library);
vertexcode = code_generate_vertex(nodes, vert_code, (geom_code != NULL));
@@ -1923,51 +1970,62 @@ GPUPass *GPU_generate_pass_new(
MEM_freeN(fragmentgen);
MEM_freeN(tmp);
- /* Cache lookup: Reuse shaders already compiled */
- uint32_t hash = gpu_pass_hash(vertexcode, geometrycode, fragmentcode, defines);
- pass = gpu_pass_cache_lookup(vertexcode, geometrycode, fragmentcode, defines, hash);
+ if (pass_hash) {
+ /* Cache lookup: Reuse shaders already compiled */
+ pass = gpu_pass_cache_resolve_collision(pass_hash, vertexcode, geometrycode, fragmentcode, defines, hash);
+ }
+
if (pass) {
/* Cache hit. Reuse the same GPUPass and GPUShader. */
- shader = pass->shader;
- pass->refcount += 1;
+ if (!gpu_pass_is_valid(pass)) {
+ /* Shader has already been created but failed to compile. */
+ return NULL;
+ }
MEM_SAFE_FREE(vertexcode);
MEM_SAFE_FREE(fragmentcode);
MEM_SAFE_FREE(geometrycode);
+
+ pass->refcount += 1;
}
else {
- /* Cache miss. (Re)compile the shader. */
- shader = GPU_shader_create(vertexcode,
- fragmentcode,
- geometrycode,
- NULL,
- defines);
-
/* We still create a pass even if shader compilation
* fails to avoid trying to compile again and again. */
pass = MEM_callocN(sizeof(GPUPass), "GPUPass");
- pass->shader = shader;
+ pass->shader = NULL;
pass->refcount = 1;
pass->hash = hash;
pass->vertexcode = vertexcode;
pass->fragmentcode = fragmentcode;
pass->geometrycode = geometrycode;
- pass->libcode = glsl_material_library;
pass->defines = (defines) ? BLI_strdup(defines) : NULL;
+ pass->compiled = false;
- BLI_linklist_prepend(&pass_cache, pass);
+ BLI_spin_lock(&pass_cache_spin);
+ if (pass_hash != NULL) {
+ /* Add after the first pass having the same hash. */
+ pass->next = pass_hash->next;
+ pass_hash->next = pass;
+ }
+ else {
+ /* No other pass have same hash, just prepend to the list. */
+ BLI_LINKS_PREPEND(pass_cache, pass);
+ }
+ BLI_spin_unlock(&pass_cache_spin);
}
- /* did compilation failed ? */
- if (!shader) {
- gpu_nodes_free(nodes);
- /* Pass will not be used. Don't increment refcount. */
- pass->refcount--;
- return NULL;
- }
- else {
- gpu_nodes_extract_dynamic_inputs(shader, inputs, nodes);
- return pass;
+ return pass;
+}
+
+void GPU_pass_compile(GPUPass *pass)
+{
+ if (!pass->compiled) {
+ pass->shader = GPU_shader_create(pass->vertexcode,
+ pass->fragmentcode,
+ pass->geometrycode,
+ NULL,
+ pass->defines);
+ pass->compiled = true;
}
}
@@ -2006,23 +2064,36 @@ void GPU_pass_cache_garbage_collect(void)
lasttime = ctime;
- LinkNode *next, **prev_ln = &pass_cache;
- for (LinkNode *ln = pass_cache; ln; ln = next) {
- GPUPass *pass = (GPUPass *)ln->link;
- next = ln->next;
+ BLI_spin_lock(&pass_cache_spin);
+ GPUPass *next, **prev_pass = &pass_cache;
+ for (GPUPass *pass = pass_cache; pass; pass = next) {
+ next = pass->next;
if (pass->refcount == 0) {
- gpu_pass_free(pass);
/* Remove from list */
- MEM_freeN(ln);
- *prev_ln = next;
+ *prev_pass = next;
+ gpu_pass_free(pass);
}
else {
- prev_ln = &ln->next;
+ prev_pass = &pass->next;
}
}
+ BLI_spin_unlock(&pass_cache_spin);
+}
+
+void GPU_pass_cache_init(void)
+{
+ BLI_spin_init(&pass_cache_spin);
}
void GPU_pass_cache_free(void)
{
- BLI_linklist_free(pass_cache, (LinkNodeFreeFP)gpu_pass_free);
+ BLI_spin_lock(&pass_cache_spin);
+ while (pass_cache) {
+ GPUPass *next = pass_cache->next;
+ gpu_pass_free(pass_cache);
+ pass_cache = next;
+ }
+ BLI_spin_unlock(&pass_cache_spin);
+
+ BLI_spin_end(&pass_cache_spin);
}
diff --git a/source/blender/gpu/intern/gpu_codegen.h b/source/blender/gpu/intern/gpu_codegen.h
index 328da36c3de..04bee545a7e 100644
--- a/source/blender/gpu/intern/gpu_codegen.h
+++ b/source/blender/gpu/intern/gpu_codegen.h
@@ -157,33 +157,30 @@ typedef struct GPUInput {
} GPUInput;
struct GPUPass {
+ struct GPUPass *next;
+
struct GPUShader *shader;
char *fragmentcode;
char *geometrycode;
char *vertexcode;
char *defines;
- const char *libcode;
unsigned int refcount; /* Orphaned GPUPasses gets freed by the garbage collector. */
uint32_t hash; /* Identity hash generated from all GLSL code. */
+ bool compiled; /* Did we already tried to compile the attached GPUShader. */
};
-
typedef struct GPUPass GPUPass;
GPUPass *GPU_generate_pass_new(
GPUMaterial *material,
GPUNodeLink *frag_outlink, struct GPUVertexAttribs *attribs,
- ListBase *nodes, ListBase *inputs,
+ ListBase *nodes,
const char *vert_code, const char *geom_code,
const char *frag_lib, const char *defines);
-GPUPass *GPU_generate_pass(
- ListBase *nodes, ListBase *inputs, struct GPUNodeLink *outlink,
- struct GPUVertexAttribs *attribs, int *builtin,
- const GPUMatType type, const char *name,
- const bool use_opensubdiv);
-struct GPUShader *GPU_pass_shader(GPUPass *pass);
+struct GPUShader *GPU_pass_shader_get(GPUPass *pass);
+void GPU_nodes_extract_dynamic_inputs(struct GPUShader *shader, ListBase *inputs, ListBase *nodes);
void GPU_nodes_get_vertex_attributes(ListBase *nodes, struct GPUVertexAttribs *attribs);
void GPU_nodes_prune(ListBase *nodes, struct GPUNodeLink *outlink);
@@ -191,6 +188,7 @@ void GPU_pass_bind(GPUPass *pass, ListBase *inputs, double time, int mipmap);
void GPU_pass_update_uniforms(GPUPass *pass, ListBase *inputs);
void GPU_pass_unbind(GPUPass *pass, ListBase *inputs);
+void GPU_pass_compile(GPUPass *pass);
void GPU_pass_release(GPUPass *pass);
void GPU_pass_free_nodes(ListBase *nodes);
diff --git a/source/blender/gpu/intern/gpu_init_exit.c b/source/blender/gpu/intern/gpu_init_exit.c
index 7b596e6d76b..92ad9d81b6c 100644
--- a/source/blender/gpu/intern/gpu_init_exit.c
+++ b/source/blender/gpu/intern/gpu_init_exit.c
@@ -57,7 +57,8 @@ void GPU_init(void)
gpu_extensions_init(); /* must come first */
- GPU_texture_init_orphans();
+ GPU_texture_orphans_init();
+ GPU_material_orphans_init();
gpu_codegen_init();
if (G.debug & G_DEBUG_GPU)
@@ -82,7 +83,8 @@ void GPU_exit(void)
gpu_batch_exit();
- GPU_texture_exit_orphans();
+ GPU_texture_orphans_exit();
+ GPU_material_orphans_exit();
if (G.debug & G_DEBUG_GPU)
gpu_debug_exit();
diff --git a/source/blender/gpu/intern/gpu_material.c b/source/blender/gpu/intern/gpu_material.c
index 7b3750c970b..302ddc62188 100644
--- a/source/blender/gpu/intern/gpu_material.c
+++ b/source/blender/gpu/intern/gpu_material.c
@@ -46,6 +46,7 @@
#include "BLI_blenlib.h"
#include "BLI_utildefines.h"
#include "BLI_rand.h"
+#include "BLI_threads.h"
#include "BKE_anim.h"
#include "BKE_colorband.h"
@@ -74,6 +75,9 @@
# include "BKE_DerivedMesh.h"
#endif
+static ListBase g_orphaned_mat = {NULL, NULL};
+static ThreadMutex g_orphan_lock;
+
/* Structs */
struct GPUMaterial {
@@ -127,10 +131,11 @@ struct GPUMaterial {
/* Eevee SSS */
GPUUniformBuffer *sss_profile; /* UBO containing SSS profile. */
GPUTexture *sss_tex_profile; /* Texture containing SSS profile. */
- float *sss_radii; /* UBO containing SSS profile. */
+ float sss_enabled;
+ float sss_radii[3];
int sss_samples;
- short int *sss_falloff;
- float *sss_sharpness;
+ short int sss_falloff;
+ float sss_sharpness;
bool sss_dirty;
};
@@ -142,36 +147,70 @@ enum {
/* Functions */
-void GPU_material_free(ListBase *gpumaterial)
+static void gpu_material_free_single(GPUMaterial *material)
{
- for (LinkData *link = gpumaterial->first; link; link = link->next) {
- GPUMaterial *material = link->data;
+ /* Cancel / wait any pending lazy compilation. */
+ DRW_deferred_shader_remove(material);
- /* Cancel / wait any pending lazy compilation. */
- DRW_deferred_shader_remove(material);
+ GPU_pass_free_nodes(&material->nodes);
+ GPU_inputs_free(&material->inputs);
- GPU_pass_free_nodes(&material->nodes);
- GPU_inputs_free(&material->inputs);
+ if (material->pass)
+ GPU_pass_release(material->pass);
- if (material->pass)
- GPU_pass_release(material->pass);
+ if (material->ubo != NULL) {
+ GPU_uniformbuffer_free(material->ubo);
+ }
- if (material->ubo != NULL) {
- GPU_uniformbuffer_free(material->ubo);
- }
+ if (material->sss_tex_profile != NULL) {
+ GPU_texture_free(material->sss_tex_profile);
+ }
- if (material->sss_tex_profile != NULL) {
- GPU_texture_free(material->sss_tex_profile);
- }
+ if (material->sss_profile != NULL) {
+ GPU_uniformbuffer_free(material->sss_profile);
+ }
+}
- if (material->sss_profile != NULL) {
- GPU_uniformbuffer_free(material->sss_profile);
+void GPU_material_free(ListBase *gpumaterial)
+{
+ for (LinkData *link = gpumaterial->first; link; link = link->next) {
+ GPUMaterial *material = link->data;
+
+ /* TODO(fclem): Check if the thread has an ogl context. */
+ if (BLI_thread_is_main()) {
+ gpu_material_free_single(material);
+ MEM_freeN(material);
+ }
+ else {
+ BLI_mutex_lock(&g_orphan_lock);
+ BLI_addtail(&g_orphaned_mat, BLI_genericNodeN(material));
+ BLI_mutex_unlock(&g_orphan_lock);
}
+ }
+ BLI_freelistN(gpumaterial);
+}
- MEM_freeN(material);
+void GPU_material_orphans_init(void)
+{
+ BLI_mutex_init(&g_orphan_lock);
+}
+
+void GPU_material_orphans_delete(void)
+{
+ BLI_mutex_lock(&g_orphan_lock);
+ LinkData *link;
+ while ((link = BLI_pophead(&g_orphaned_mat))) {
+ gpu_material_free_single((GPUMaterial *)link->data);
+ MEM_freeN(link->data);
+ MEM_freeN(link);
}
+ BLI_mutex_unlock(&g_orphan_lock);
+}
- BLI_freelistN(gpumaterial);
+void GPU_material_orphans_exit(void)
+{
+ GPU_material_orphans_delete();
+ BLI_mutex_end(&g_orphan_lock);
}
GPUBuiltin GPU_get_material_builtins(GPUMaterial *material)
@@ -199,7 +238,7 @@ ListBase *GPU_material_get_inputs(GPUMaterial *material)
return &material->inputs;
}
-GPUUniformBuffer *GPU_material_get_uniform_buffer(GPUMaterial *material)
+GPUUniformBuffer *GPU_material_uniform_buffer_get(GPUMaterial *material)
{
return material->ubo;
}
@@ -208,24 +247,11 @@ GPUUniformBuffer *GPU_material_get_uniform_buffer(GPUMaterial *material)
* Create dynamic UBO from parameters
* \param ListBase of BLI_genericNodeN(GPUInput)
*/
-void GPU_material_create_uniform_buffer(GPUMaterial *material, ListBase *inputs)
+void GPU_material_uniform_buffer_create(GPUMaterial *material, ListBase *inputs)
{
material->ubo = GPU_uniformbuffer_dynamic_create(inputs, NULL);
}
-void GPU_material_uniform_buffer_tag_dirty(ListBase *gpumaterials)
-{
- for (LinkData *link = gpumaterials->first; link; link = link->next) {
- GPUMaterial *material = link->data;
- if (material->ubo != NULL) {
- GPU_uniformbuffer_tag_dirty(material->ubo);
- }
- if (material->sss_profile != NULL) {
- material->sss_dirty = true;
- }
- }
-}
-
/* Eevee Subsurface scattering. */
/* Based on Separable SSS. by Jorge Jimenez and Diego Gutierrez */
@@ -328,7 +354,7 @@ static float eval_integral(float x0, float x1, short falloff_type, float sharpne
#undef INTEGRAL_RESOLUTION
static void compute_sss_kernel(
- GPUSssKernelData *kd, float *radii, int sample_ct, int falloff_type, float sharpness)
+ GPUSssKernelData *kd, float radii[3], int sample_ct, int falloff_type, float sharpness)
{
float rad[3];
/* Minimum radius */
@@ -483,12 +509,13 @@ static void compute_sss_translucence_kernel(
}
#undef INTEGRAL_RESOLUTION
-void GPU_material_sss_profile_create(GPUMaterial *material, float *radii, short *falloff_type, float *sharpness)
+void GPU_material_sss_profile_create(GPUMaterial *material, float radii[3], short *falloff_type, float *sharpness)
{
- material->sss_radii = radii;
- material->sss_falloff = falloff_type;
- material->sss_sharpness = sharpness;
+ copy_v3_v3(material->sss_radii, radii);
+ material->sss_falloff = (falloff_type) ? *falloff_type : 0.0;
+ material->sss_sharpness = (sharpness) ? *sharpness : 0.0;
material->sss_dirty = true;
+ material->sss_enabled = true;
/* Update / Create UBO */
if (material->sss_profile == NULL) {
@@ -498,25 +525,25 @@ void GPU_material_sss_profile_create(GPUMaterial *material, float *radii, short
struct GPUUniformBuffer *GPU_material_sss_profile_get(GPUMaterial *material, int sample_ct, GPUTexture **tex_profile)
{
- if (material->sss_radii == NULL)
+ if (!material->sss_enabled)
return NULL;
if (material->sss_dirty || (material->sss_samples != sample_ct)) {
GPUSssKernelData kd;
- float sharpness = (material->sss_sharpness != NULL) ? *material->sss_sharpness : 0.0f;
+ float sharpness = material->sss_sharpness;
/* XXX Black magic but it seems to fit. Maybe because we integrate -1..1 */
sharpness *= 0.5f;
- compute_sss_kernel(&kd, material->sss_radii, sample_ct, *material->sss_falloff, sharpness);
+ compute_sss_kernel(&kd, material->sss_radii, sample_ct, material->sss_falloff, sharpness);
/* Update / Create UBO */
GPU_uniformbuffer_update(material->sss_profile, &kd);
/* Update / Create Tex */
float *translucence_profile;
- compute_sss_translucence_kernel(&kd, 64, *material->sss_falloff, sharpness, &translucence_profile);
+ compute_sss_translucence_kernel(&kd, 64, material->sss_falloff, sharpness, &translucence_profile);
if (material->sss_tex_profile != NULL) {
GPU_texture_free(material->sss_tex_profile);
@@ -602,7 +629,8 @@ GPUMaterial *GPU_material_from_nodetree_find(
* so only do this when they are needed.
*/
GPUMaterial *GPU_material_from_nodetree(
- Scene *scene, struct bNodeTree *ntree, ListBase *gpumaterials, const void *engine_type, int options)
+ Scene *scene, struct bNodeTree *ntree, ListBase *gpumaterials, const void *engine_type, int options,
+ const char *vert_code, const char *geom_code, const char *frag_lib, const char *defines)
{
LinkData *link;
bool has_volume_output, has_surface_output;
@@ -631,11 +659,38 @@ GPUMaterial *GPU_material_from_nodetree(
* generated VBOs are ready to accept the future shader. */
GPU_nodes_prune(&mat->nodes, mat->outlink);
GPU_nodes_get_vertex_attributes(&mat->nodes, &mat->attribs);
- mat->status = GPU_MAT_QUEUED;
+ /* Create source code and search pass cache for an already compiled version. */
+ mat->pass = GPU_generate_pass_new(mat,
+ mat->outlink,
+ &mat->attribs,
+ &mat->nodes,
+ vert_code,
+ geom_code,
+ frag_lib,
+ defines);
+
+ if (mat->pass == NULL) {
+ /* We had a cache hit and the shader has already failed to compile. */
+ mat->status = GPU_MAT_FAILED;
+ }
+ else {
+ GPUShader *sh = GPU_pass_shader_get(mat->pass);
+ if (sh != NULL) {
+ /* We had a cache hit and the shader is already compiled. */
+ mat->status = GPU_MAT_SUCCESS;
+ GPU_nodes_extract_dynamic_inputs(sh, &mat->inputs, &mat->nodes);
+ }
+ else {
+ mat->status = GPU_MAT_QUEUED;
+ }
+ }
+ }
+ else {
+ mat->status = GPU_MAT_FAILED;
}
/* note that even if building the shader fails in some way, we still keep
- * it to avoid trying to compile again and again, and simple do not use
+ * it to avoid trying to compile again and again, and simply do not use
* the actual shader on drawing */
link = MEM_callocN(sizeof(LinkData), "GPUMaterialLink");
@@ -645,17 +700,26 @@ GPUMaterial *GPU_material_from_nodetree(
return mat;
}
-void GPU_material_generate_pass(
- GPUMaterial *mat, const char *vert_code, const char *geom_code, const char *frag_lib, const char *defines)
+void GPU_material_compile(GPUMaterial *mat)
{
- BLI_assert(mat->pass == NULL); /* Only run once! */
- if (mat->outlink) {
- mat->pass = GPU_generate_pass_new(
- mat, mat->outlink, &mat->attribs, &mat->nodes, &mat->inputs, vert_code, geom_code, frag_lib, defines);
- mat->status = (mat->pass) ? GPU_MAT_SUCCESS : GPU_MAT_FAILED;
+ /* Only run once! */
+ BLI_assert(mat->status == GPU_MAT_QUEUED);
+ BLI_assert(mat->pass);
+
+ /* NOTE: The shader may have already been compiled here since we are
+ * sharing GPUShader across GPUMaterials. In this case it's a no-op. */
+ GPU_pass_compile(mat->pass);
+ GPUShader *sh = GPU_pass_shader_get(mat->pass);
+
+ if (sh != NULL) {
+ mat->status = GPU_MAT_SUCCESS;
+ GPU_nodes_extract_dynamic_inputs(sh, &mat->inputs, &mat->nodes);
}
else {
mat->status = GPU_MAT_FAILED;
+ GPU_pass_free_nodes(&mat->nodes);
+ GPU_pass_release(mat->pass);
+ mat->pass = NULL;
}
}
diff --git a/source/blender/gpu/intern/gpu_texture.c b/source/blender/gpu/intern/gpu_texture.c
index dadd8c441f4..aac75014b3e 100644
--- a/source/blender/gpu/intern/gpu_texture.c
+++ b/source/blender/gpu/intern/gpu_texture.c
@@ -1124,12 +1124,12 @@ void GPU_texture_free(GPUTexture *tex)
}
}
-void GPU_texture_init_orphans(void)
+void GPU_texture_orphans_init(void)
{
BLI_mutex_init(&g_orphan_lock);
}
-void GPU_texture_delete_orphans(void)
+void GPU_texture_orphans_delete(void)
{
BLI_mutex_lock(&g_orphan_lock);
LinkData *link;
@@ -1140,9 +1140,9 @@ void GPU_texture_delete_orphans(void)
BLI_mutex_unlock(&g_orphan_lock);
}
-void GPU_texture_exit_orphans(void)
+void GPU_texture_orphans_exit(void)
{
- GPU_texture_delete_orphans();
+ GPU_texture_orphans_delete();
BLI_mutex_end(&g_orphan_lock);
}
diff --git a/source/blender/gpu/intern/gpu_uniformbuffer.c b/source/blender/gpu/intern/gpu_uniformbuffer.c
index afd43600d9b..1e39b2ea5b7 100644
--- a/source/blender/gpu/intern/gpu_uniformbuffer.c
+++ b/source/blender/gpu/intern/gpu_uniformbuffer.c
@@ -62,26 +62,14 @@ struct GPUUniformBuffer {
typedef struct GPUUniformBufferDynamic {
GPUUniformBuffer buffer;
- ListBase items; /* GPUUniformBufferDynamicItem */
- void *data;
+ void *data; /* Continuous memory block to copy to GPU. */
char flag;
} GPUUniformBufferDynamic;
-struct GPUUniformBufferDynamicItem {
- struct GPUUniformBufferDynamicItem *next, *prev;
- GPUType gputype;
- float *data;
- int size;
-};
-
-
/* Prototypes */
static GPUType get_padded_gpu_type(struct LinkData *link);
static void gpu_uniformbuffer_inputs_sort(struct ListBase *inputs);
-static GPUUniformBufferDynamicItem *gpu_uniformbuffer_populate(
- GPUUniformBufferDynamic *ubo, const GPUType gputype, float *num);
-
/* Only support up to this type, if you want to extend it, make sure the
* padding logic is correct for the new types. */
#define MAX_UBO_GPU_TYPE GPU_VEC4
@@ -159,34 +147,47 @@ GPUUniformBuffer *GPU_uniformbuffer_dynamic_create(ListBase *inputs, char err_ou
gpu_uniformbuffer_inputs_sort(inputs);
for (LinkData *link = inputs->first; link; link = link->next) {
- GPUInput *input = link->data;
- GPUType gputype = get_padded_gpu_type(link);
- gpu_uniformbuffer_populate(ubo, gputype, input->dynamicvec);
+ const GPUType gputype = get_padded_gpu_type(link);
+ ubo->buffer.size += gputype * sizeof(float);
}
+ /* Allocate the data. */
ubo->data = MEM_mallocN(ubo->buffer.size, __func__);
- /* Initialize buffer data. */
- GPU_uniformbuffer_dynamic_update(&ubo->buffer);
+ /* Now that we know the total ubo size we can start populating it. */
+ float *offset = ubo->data;
+ for (LinkData *link = inputs->first; link; link = link->next) {
+ GPUInput *input = link->data;
+ const GPUType gputype = get_padded_gpu_type(link);
+ memcpy(offset, input->dynamicvec, gputype * sizeof(float));
+ offset += gputype;
+ }
+
+ /* Note since we may create the UBOs in the CPU in a different thread than the main drawing one,
+ * we don't create the UBO in the GPU here. This will happen when we first bind the UBO.
+ */
+
return &ubo->buffer;
}
/**
- * Free the data, and clean the items list.
+ * Free the data
*/
-static void gpu_uniformbuffer_dynamic_reset(GPUUniformBufferDynamic *ubo)
+static void gpu_uniformbuffer_dynamic_free(GPUUniformBuffer *ubo_)
{
+ BLI_assert(ubo_->type == GPU_UBO_DYNAMIC);
+ GPUUniformBufferDynamic *ubo = (GPUUniformBufferDynamic *)ubo_;
+
ubo->buffer.size = 0;
if (ubo->data) {
MEM_freeN(ubo->data);
}
- BLI_freelistN(&ubo->items);
}
void GPU_uniformbuffer_free(GPUUniformBuffer *ubo)
{
if (ubo->type == GPU_UBO_DYNAMIC) {
- gpu_uniformbuffer_dynamic_reset((GPUUniformBufferDynamic *)ubo);
+ gpu_uniformbuffer_dynamic_free(ubo);
}
glDeleteBuffers(1, &ubo->bindcode);
@@ -215,12 +216,6 @@ void GPU_uniformbuffer_dynamic_update(GPUUniformBuffer *ubo_)
BLI_assert(ubo_->type == GPU_UBO_DYNAMIC);
GPUUniformBufferDynamic *ubo = (GPUUniformBufferDynamic *)ubo_;
- float *offset = ubo->data;
- for (GPUUniformBufferDynamicItem *item = ubo->items.first; item; item = item->next) {
- memcpy(offset, item->data, item->size);
- offset += item->gputype;
- }
-
if (ubo->flag & GPU_UBO_FLAG_INITIALIZED) {
gpu_uniformbuffer_update(ubo_, ubo->data);
}
@@ -316,27 +311,6 @@ static void gpu_uniformbuffer_inputs_sort(ListBase *inputs)
}
}
-/**
- * This may now happen from the main thread, so we can't update the UBO
- * We simply flag it as dirty
- */
-static GPUUniformBufferDynamicItem *gpu_uniformbuffer_populate(
- GPUUniformBufferDynamic *ubo, const GPUType gputype, float *num)
-{
- BLI_assert(gputype <= MAX_UBO_GPU_TYPE);
- GPUUniformBufferDynamicItem *item = MEM_callocN(sizeof(GPUUniformBufferDynamicItem), __func__);
-
- item->gputype = gputype;
- item->data = num;
- item->size = gputype * sizeof(float);
- ubo->buffer.size += item->size;
-
- ubo->flag |= GPU_UBO_FLAG_DIRTY;
- BLI_addtail(&ubo->items, item);
-
- return item;
-}
-
void GPU_uniformbuffer_bind(GPUUniformBuffer *ubo, int number)
{
if (number >= GPU_max_ubo_binds()) {
@@ -368,11 +342,4 @@ int GPU_uniformbuffer_bindpoint(GPUUniformBuffer *ubo)
return ubo->bindpoint;
}
-void GPU_uniformbuffer_tag_dirty(GPUUniformBuffer *ubo_)
-{
- BLI_assert(ubo_->type == GPU_UBO_DYNAMIC);
- GPUUniformBufferDynamic *ubo = (GPUUniformBufferDynamic *)ubo_;
- ubo->flag |= GPU_UBO_FLAG_DIRTY;
-}
-
#undef MAX_UBO_GPU_TYPE
diff --git a/source/blender/ikplugin/CMakeLists.txt b/source/blender/ikplugin/CMakeLists.txt
index 8991e113410..eb34e50715e 100644
--- a/source/blender/ikplugin/CMakeLists.txt
+++ b/source/blender/ikplugin/CMakeLists.txt
@@ -25,7 +25,7 @@
remove_extra_strict_flags()
-set(INC
+set(INC
.
../blenkernel
../blenlib
diff --git a/source/blender/ikplugin/intern/ikplugin_api.c b/source/blender/ikplugin/intern/ikplugin_api.c
index 216e60f5c5c..791b74e4bc9 100644
--- a/source/blender/ikplugin/intern/ikplugin_api.c
+++ b/source/blender/ikplugin/intern/ikplugin_api.c
@@ -105,7 +105,7 @@ void BIK_execute_tree(struct Depsgraph *depsgraph, struct Scene *scene, Object *
plugin->execute_tree_func(depsgraph, scene, ob, pchan, ctime);
}
-void BIK_release_tree(struct Scene *scene, Object *ob, float ctime)
+void BIK_release_tree(struct Scene *scene, Object *ob, float ctime)
{
IKPlugin *plugin = get_plugin(ob->pose);
diff --git a/source/blender/ikplugin/intern/itasc_plugin.cpp b/source/blender/ikplugin/intern/itasc_plugin.cpp
index af303556090..9ad98755be1 100644
--- a/source/blender/ikplugin/intern/itasc_plugin.cpp
+++ b/source/blender/ikplugin/intern/itasc_plugin.cpp
@@ -881,7 +881,7 @@ static int convert_channels(struct Depsgraph *depsgraph, IK_Scene *ikscene, Pose
ikchan->owner = ikscene->blArmature;
// the constraint and channels must be applied before we build the iTaSC scene,
- // this is because some of the pose data (e.g. pose head) don't have corresponding
+ // this is because some of the pose data (e.g. pose head) don't have corresponding
// joint angles and can't be applied to the iTaSC armature dynamically
if (!(pchan->flag & POSE_DONE))
BKE_pose_where_is_bone(depsgraph, ikscene->blscene, ikscene->blArmature, pchan, ctime, 1);
diff --git a/source/blender/makesdna/DNA_ID.h b/source/blender/makesdna/DNA_ID.h
index 6ce0c94d884..f79d3259244 100644
--- a/source/blender/makesdna/DNA_ID.h
+++ b/source/blender/makesdna/DNA_ID.h
@@ -381,7 +381,7 @@ typedef enum ID_Type {
#define ID_CHECK_UNDO(id) ((GS((id)->name) != ID_SCR) && (GS((id)->name) != ID_WM) && (GS((id)->name) != ID_WS))
-#define ID_BLEND_PATH(_bmain, _id) ((_id)->lib ? (_id)->lib->filepath : (_bmain)->name)
+#define ID_BLEND_PATH(_bmain, _id) ((_id)->lib ? (_id)->lib->filepath : BKE_main_blendfile_path((_bmain)))
#define ID_MISSING(_id) (((_id)->tag & LIB_TAG_MISSING) != 0)
diff --git a/source/blender/makesdna/DNA_object_types.h b/source/blender/makesdna/DNA_object_types.h
index c9db5fbbdfb..f37bccbfe4e 100644
--- a/source/blender/makesdna/DNA_object_types.h
+++ b/source/blender/makesdna/DNA_object_types.h
@@ -147,7 +147,7 @@ typedef struct ObjectDisplay {
typedef struct Object_Runtime {
/* Original mesh pointer, before object->data was changed to point
* to mesh_eval.
- * Is assigned by dependency craph's copy-on-write evaluation.
+ * Is assigned by dependency graph's copy-on-write evaluation.
*/
struct Mesh *mesh_orig;
/* Mesh structure created during object evaluation.
@@ -342,26 +342,6 @@ typedef struct ObHook {
float force;
} ObHook;
-/* runtime only, but include here for rna access */
-typedef struct DupliObject {
- struct DupliObject *next, *prev;
- struct Object *ob;
- float mat[4][4];
- float orco[3], uv[2];
-
- short type; /* from Object.transflag */
- char no_draw, animated;
-
- /* persistent identifier for a dupli object, for inter-frame matching of
- * objects with motion blur, or inter-update matching for syncing */
- int persistent_id[16]; /* 2*MAX_DUPLI_RECUR */
-
- /* particle this dupli was generated from */
- struct ParticleSystem *particle_system;
- unsigned int random_id;
- unsigned int pad;
-} DupliObject;
-
/* **************** OBJECT ********************* */
/* used many places... should be specialized */
diff --git a/source/blender/makesdna/DNA_space_types.h b/source/blender/makesdna/DNA_space_types.h
index d867e05f209..18fd17c006e 100644
--- a/source/blender/makesdna/DNA_space_types.h
+++ b/source/blender/makesdna/DNA_space_types.h
@@ -196,6 +196,7 @@ typedef enum eSpaceButtons_Context {
BCONTEXT_CONSTRAINT = 11,
BCONTEXT_BONE_CONSTRAINT = 12,
BCONTEXT_VIEW_LAYER = 13,
+ BCONTEXT_TOOL = 14,
BCONTEXT_WORKSPACE = 15,
/* always as last... */
@@ -220,12 +221,6 @@ typedef enum eSpaceButtons_Align {
BUT_AUTO = 3,
} eSpaceButtons_Align;
-/* SpaceButs.flag */
-typedef enum eSpaceButtons_SubType {
- SB_SUBTYPE_DATA = 0,
- SB_SUBTYPE_TOOL = 1,
-} eSpaceButtons_SubType;
-
/** \} */
/* -------------------------------------------------------------------- */
diff --git a/source/blender/makesdna/DNA_userdef_types.h b/source/blender/makesdna/DNA_userdef_types.h
index 468436668b7..17f520fdfa9 100644
--- a/source/blender/makesdna/DNA_userdef_types.h
+++ b/source/blender/makesdna/DNA_userdef_types.h
@@ -617,6 +617,7 @@ typedef enum eUserPref_Section {
USER_SECTION_THEME = 4,
USER_SECTION_INPUT = 5,
USER_SECTION_ADDONS = 6,
+ USER_SECTION_LIGHT = 7,
} eUserPref_Section;
/* UserDef.flag */
diff --git a/source/blender/makesdna/DNA_view3d_types.h b/source/blender/makesdna/DNA_view3d_types.h
index be980b4fead..9794a1efbf5 100644
--- a/source/blender/makesdna/DNA_view3d_types.h
+++ b/source/blender/makesdna/DNA_view3d_types.h
@@ -140,6 +140,7 @@ typedef struct View3DShading {
short light;
char pad[2];
char studio_light[256]; /* FILE_MAXFILE */
+ char matcap[256]; /* FILE_MAXFILE */
float shadow_intensity;
float single_color[3];
@@ -149,6 +150,9 @@ typedef struct View3DShading {
float object_outline_color[3];
float xray_alpha;
+
+ float cavity_valley_factor;
+ float cavity_ridge_factor;
} View3DShading;
/* 3D Viewport Overlay setings */
@@ -165,6 +169,10 @@ typedef struct View3DOverlay {
/* Armature edit/pose mode settings */
int arm_flag;
+ float bone_selection_alpha;
+
+ /* Other settings */
+ float wireframe_threshold;
} View3DOverlay;
/* 3D ViewPort Struct */
@@ -333,7 +341,7 @@ typedef struct View3D {
enum {
V3D_LIGHTING_FLAT = 0,
V3D_LIGHTING_STUDIO = 1,
- V3D_LIGHTING_SCENE = 2
+ V3D_LIGHTING_MATCAP = 2,
};
/* View3DShading->flag */
@@ -343,6 +351,8 @@ enum {
V3D_SHADING_SHADOW = (1 << 2),
V3D_SHADING_SCENE_LIGHT = (1 << 3),
V3D_SHADING_SPECULAR_HIGHLIGHT = (1 << 4),
+ V3D_SHADING_CAVITY = (1 << 5),
+ V3D_SHADING_MATCAP_FLIP_X = (1 << 6),
};
/* View3DShading->single_color_type */
diff --git a/source/blender/makesrna/RNA_access.h b/source/blender/makesrna/RNA_access.h
index 193c5a77794..125264ca03c 100644
--- a/source/blender/makesrna/RNA_access.h
+++ b/source/blender/makesrna/RNA_access.h
@@ -809,6 +809,7 @@ PropertyType RNA_property_type(PropertyRNA *prop);
PropertySubType RNA_property_subtype(PropertyRNA *prop);
PropertyUnit RNA_property_unit(PropertyRNA *prop);
int RNA_property_flag(PropertyRNA *prop);
+int RNA_property_override_flag(PropertyRNA *prop);
int RNA_property_tags(PropertyRNA *prop);
bool RNA_property_builtin(PropertyRNA *prop);
void *RNA_property_py_data_get(PropertyRNA *prop);
diff --git a/source/blender/makesrna/RNA_define.h b/source/blender/makesrna/RNA_define.h
index 4e32651d356..d56ccbcfa01 100644
--- a/source/blender/makesrna/RNA_define.h
+++ b/source/blender/makesrna/RNA_define.h
@@ -149,6 +149,8 @@ void RNA_def_property_collection_sdna(PropertyRNA *prop, const char *structname,
void RNA_def_property_flag(PropertyRNA *prop, PropertyFlag flag);
void RNA_def_property_clear_flag(PropertyRNA *prop, PropertyFlag flag);
+void RNA_def_property_override_flag(PropertyRNA *prop, PropertyOverrideFlag flag);
+void RNA_def_property_override_clear_flag(PropertyRNA *prop, PropertyOverrideFlag flag);
void RNA_def_property_tags(PropertyRNA *prop, int tags);
void RNA_def_property_subtype(PropertyRNA *prop, PropertySubType subtype);
void RNA_def_property_array(PropertyRNA *prop, int length);
diff --git a/source/blender/makesrna/RNA_enum_types.h b/source/blender/makesrna/RNA_enum_types.h
index 788b1372fc8..da2705d4660 100644
--- a/source/blender/makesrna/RNA_enum_types.h
+++ b/source/blender/makesrna/RNA_enum_types.h
@@ -57,7 +57,6 @@ extern const EnumPropertyItem rna_enum_mesh_select_mode_items[];
extern const EnumPropertyItem rna_enum_mesh_delimit_mode_items[];
extern const EnumPropertyItem rna_enum_space_type_items[];
extern const EnumPropertyItem rna_enum_space_image_mode_items[];
-extern const EnumPropertyItem rna_enum_space_button_mode_items[];
extern const EnumPropertyItem rna_enum_region_type_items[];
extern const EnumPropertyItem rna_enum_object_modifier_type_items[];
extern const EnumPropertyItem rna_enum_constraint_type_items[];
diff --git a/source/blender/makesrna/RNA_types.h b/source/blender/makesrna/RNA_types.h
index 5d6f309ad65..9d304018990 100644
--- a/source/blender/makesrna/RNA_types.h
+++ b/source/blender/makesrna/RNA_types.h
@@ -158,7 +158,7 @@ typedef enum PropertySubType {
/* Make sure enums are updated with these */
/* HIGHEST FLAG IN USE: 1 << 31
- * FREE FLAGS: 11, 13, 14, 15, 30 */
+ * FREE FLAGS: 2, 9, 11, 13, 14, 15, 30 */
typedef enum PropertyFlag {
/* editable means the property is editable in the user
* interface, properties are editable by default except
@@ -176,15 +176,6 @@ typedef enum PropertyFlag {
* and collections */
PROP_ANIMATABLE = (1 << 1),
- /* Means the property can be overriden by a local 'proxy' of some linked datablock. */
- PROP_OVERRIDABLE_STATIC = (1 << 2),
- /* The property supports insertion (collections only). */
- PROP_OVERRIDABLE_STATIC_INSERTION = (1 << 9),
-
- /* Forbid usage of this property in comparison (& hence override) code.
- * Useful e.g. for collections of data like mesh's geometry, particles, etc. */
- PROP_NO_COMPARISON = (1 << 3),
-
/* This flag means when the property's widget is in 'textedit' mode, it will be updated
* after every typed char, instead of waiting final validation. Used e.g. for text searchbox.
* It will also cause UI_BUT_VALUE_CLEAR to be set for text buttons. We could add an own flag
@@ -253,6 +244,27 @@ typedef enum PropertyFlag {
PROP_ENUM_NO_TRANSLATE = (1 << 29), /* for enums not to be translated (e.g. viewlayers' names in nodes) */
} PropertyFlag;
+/* Flags related to comparing and overriding RNA properties. Make sure enums are updated with these */
+/* FREE FLAGS: 2, 3, 4, 5, 6, 7, 8, 9, 12 and above. */
+typedef enum PropertyOverrideFlag {
+ /* Means the property can be overriden by a local 'proxy' of some linked datablock. */
+ PROPOVERRIDE_OVERRIDABLE_STATIC = (1 << 0),
+
+ /* Forbid usage of this property in comparison (& hence override) code.
+ * Useful e.g. for collections of data like mesh's geometry, particles, etc. */
+ PROPOVERRIDE_NO_COMPARISON = (1 << 1),
+
+ /*** Collections-related ***/
+
+ /* The property supports insertion (collections only). */
+ PROPOVERRIDE_STATIC_INSERTION = (1 << 10),
+
+ /* Only use indices to compare items in the property, never names (collections only). */
+ /* Useful when nameprop of the items is generated from other data
+ * (e.g. name of material slots is actually name of assigned material). */
+ PROPOVERRIDE_NO_PROP_NAME = (1 << 11),
+} PropertyOverrideFlag;
+
/* Function parameters flags.
* WARNING: 16bits only. */
typedef enum ParameterFlag {
diff --git a/source/blender/makesrna/intern/makesrna.c b/source/blender/makesrna/intern/makesrna.c
index d3301eaf90e..8a50da27144 100644
--- a/source/blender/makesrna/intern/makesrna.c
+++ b/source/blender/makesrna/intern/makesrna.c
@@ -3056,7 +3056,7 @@ static void rna_generate_property(FILE *f, StructRNA *srna, const char *nest, Pr
else fprintf(f, "NULL,\n");
fprintf(f, "\t%d, ", prop->magic);
rna_print_c_string(f, prop->identifier);
- fprintf(f, ", %d, %d, %d, %d, ", prop->flag, prop->flag_parameter, prop->flag_internal, prop->tags);
+ fprintf(f, ", %d, %d, %d, %d, %d, ", prop->flag, prop->flag_override, prop->flag_parameter, prop->flag_internal, prop->tags);
rna_print_c_string(f, prop->name); fprintf(f, ",\n\t");
rna_print_c_string(f, prop->description); fprintf(f, ",\n\t");
fprintf(f, "%d, ", prop->icon);
diff --git a/source/blender/makesrna/intern/rna_access.c b/source/blender/makesrna/intern/rna_access.c
index 5a0dec28324..df09e5c68b5 100644
--- a/source/blender/makesrna/intern/rna_access.c
+++ b/source/blender/makesrna/intern/rna_access.c
@@ -1005,6 +1005,11 @@ int RNA_property_flag(PropertyRNA *prop)
return rna_ensure_property(prop)->flag;
}
+int RNA_property_override_flag(PropertyRNA *prop)
+{
+ return rna_ensure_property(prop)->flag_override;
+}
+
/**
* Get the tags set for \a prop as int bitfield.
* \note Doesn't perform any validity check on the set bits. #RNA_def_property_tags does this
@@ -1976,11 +1981,11 @@ bool RNA_property_overridable_get(PointerRNA *ptr, PropertyRNA *prop)
}
}
/* If this is a RNA-defined property (real or 'virtual' IDProp), we want to use RNA prop flag. */
- return !(prop->flag & PROP_NO_COMPARISON) && (prop->flag & PROP_OVERRIDABLE_STATIC);
+ return !(prop->flag_override & PROPOVERRIDE_NO_COMPARISON) && (prop->flag_override & PROPOVERRIDE_OVERRIDABLE_STATIC);
}
else {
/* If this is a real 'pure' IDProp (aka custom property), we want to use the IDProp flag. */
- return !(prop->flag & PROP_NO_COMPARISON) && (((IDProperty *)prop)->flag & IDP_FLAG_OVERRIDABLE_STATIC);
+ return !(prop->flag_override & PROPOVERRIDE_NO_COMPARISON) && (((IDProperty *)prop)->flag & IDP_FLAG_OVERRIDABLE_STATIC);
}
}
@@ -2016,7 +2021,7 @@ bool RNA_property_comparable(PointerRNA *UNUSED(ptr), PropertyRNA *prop)
{
prop = rna_ensure_property(prop);
- return !(prop->flag & PROP_NO_COMPARISON);
+ return !(prop->flag_override & PROPOVERRIDE_NO_COMPARISON);
}
/* this function is to check if its possible to create a valid path from the ID
diff --git a/source/blender/makesrna/intern/rna_animation.c b/source/blender/makesrna/intern/rna_animation.c
index 84764187b62..d2c719ac5d1 100644
--- a/source/blender/makesrna/intern/rna_animation.c
+++ b/source/blender/makesrna/intern/rna_animation.c
@@ -1027,7 +1027,7 @@ void rna_def_animdata_common(StructRNA *srna)
prop = RNA_def_property(srna, "animation_data", PROP_POINTER, PROP_NONE);
RNA_def_property_pointer_sdna(prop, NULL, "adt");
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
- RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC);
RNA_def_property_override_funcs(prop, NULL, NULL, "rna_AnimaData_override_apply");
RNA_def_property_ui_text(prop, "Animation Data", "Animation data for this data-block");
}
@@ -1052,7 +1052,8 @@ static void rna_def_animdata(BlenderRNA *brna)
/* Active Action */
prop = RNA_def_property(srna, "action", PROP_POINTER, PROP_NONE);
/* this flag as well as the dynamic test must be defined for this to be editable... */
- RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_REFCOUNT | PROP_OVERRIDABLE_STATIC);
+ RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_REFCOUNT);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC);
RNA_def_property_pointer_funcs(prop, NULL, "rna_AnimData_action_set", NULL, "rna_Action_id_poll");
RNA_def_property_editable_func(prop, "rna_AnimData_action_editable");
RNA_def_property_ui_text(prop, "Action", "Active Action for this data-block");
@@ -1073,7 +1074,7 @@ static void rna_def_animdata(BlenderRNA *brna)
"Method used for combining Active Action's result with result of NLA stack");
RNA_def_property_update(prop, NC_ANIMATION | ND_NLA, NULL); /* this will do? */
- prop = RNA_def_property(srna, "action_influence", PROP_FLOAT, PROP_NONE);
+ prop = RNA_def_property(srna, "action_influence", PROP_FLOAT, PROP_FACTOR);
RNA_def_property_float_sdna(prop, NULL, "act_influence");
RNA_def_property_float_default(prop, 1.0f);
RNA_def_property_range(prop, 0.0f, 1.0f);
@@ -1085,7 +1086,7 @@ static void rna_def_animdata(BlenderRNA *brna)
prop = RNA_def_property(srna, "drivers", PROP_COLLECTION, PROP_NONE);
RNA_def_property_collection_sdna(prop, NULL, "drivers", NULL);
RNA_def_property_struct_type(prop, "FCurve");
- RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC);
RNA_def_property_ui_text(prop, "Drivers", "The Drivers/Expressions for this data-block");
rna_api_animdata_drivers(brna, prop);
diff --git a/source/blender/makesrna/intern/rna_armature.c b/source/blender/makesrna/intern/rna_armature.c
index 30c643388af..69a5cc2d6b1 100644
--- a/source/blender/makesrna/intern/rna_armature.c
+++ b/source/blender/makesrna/intern/rna_armature.c
@@ -44,6 +44,7 @@
#ifdef RNA_RUNTIME
#include "BKE_context.h"
+#include "BKE_global.h"
#include "BKE_idprop.h"
#include "BKE_main.h"
@@ -340,7 +341,7 @@ static void rna_EditBone_name_set(PointerRNA *ptr, const char *value)
BLI_strncpy_utf8(newname, value, sizeof(ebone->name));
BLI_strncpy(oldname, ebone->name, sizeof(ebone->name));
- ED_armature_bone_rename(arm, oldname, newname);
+ ED_armature_bone_rename(G.main, arm, oldname, newname);
}
static void rna_Bone_name_set(PointerRNA *ptr, const char *value)
@@ -353,7 +354,7 @@ static void rna_Bone_name_set(PointerRNA *ptr, const char *value)
BLI_strncpy_utf8(newname, value, sizeof(bone->name));
BLI_strncpy(oldname, bone->name, sizeof(bone->name));
- ED_armature_bone_rename(arm, oldname, newname);
+ ED_armature_bone_rename(G.main, arm, oldname, newname);
}
static void rna_EditBone_layer_set(PointerRNA *ptr, const int values[])
@@ -504,9 +505,9 @@ static int rna_Armature_is_editmode_get(PointerRNA *ptr)
return (arm->edbo != NULL);
}
-static void rna_Armature_transform(struct bArmature *arm, float *mat)
+static void rna_Armature_transform(struct bArmature *arm, Main *bmain, float *mat)
{
- ED_armature_transform(arm, (float (*)[4])mat, true);
+ ED_armature_transform(bmain, arm, (float (*)[4])mat, true);
}
#else
@@ -1034,6 +1035,7 @@ static void rna_def_armature(BlenderRNA *brna)
RNA_def_struct_sdna(srna, "bArmature");
func = RNA_def_function(srna, "transform", "rna_Armature_transform");
+ RNA_def_function_flag(func, FUNC_USE_MAIN);
RNA_def_function_ui_description(func, "Transform armature bones by a matrix");
parm = RNA_def_float_matrix(func, "matrix", 4, 4, NULL, 0.0f, 0.0f, "", "Matrix", 0.0f, 0.0f);
RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
diff --git a/source/blender/makesrna/intern/rna_color.c b/source/blender/makesrna/intern/rna_color.c
index f895cfbbf0c..8e090937605 100644
--- a/source/blender/makesrna/intern/rna_color.c
+++ b/source/blender/makesrna/intern/rna_color.c
@@ -548,7 +548,7 @@ static const EnumPropertyItem *rna_ColorManagedColorspaceSettings_colorspace_ite
return items;
}
-static void rna_ColorManagedColorspaceSettings_reload_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr)
+static void rna_ColorManagedColorspaceSettings_reload_update(Main *bmain, Scene *UNUSED(scene), PointerRNA *ptr)
{
ID *id = ptr->id.data;
@@ -565,7 +565,7 @@ static void rna_ColorManagedColorspaceSettings_reload_update(Main *UNUSED(bmain)
else if (GS(id->name) == ID_MC) {
MovieClip *clip = (MovieClip *) id;
- BKE_movieclip_reload(clip);
+ BKE_movieclip_reload(bmain, clip);
/* all sequencers for now, we don't know which scenes are using this clip as a strip */
BKE_sequencer_cache_cleanup();
diff --git a/source/blender/makesrna/intern/rna_constraint.c b/source/blender/makesrna/intern/rna_constraint.c
index 7c53a3b54c0..e01ca97dfac 100644
--- a/source/blender/makesrna/intern/rna_constraint.c
+++ b/source/blender/makesrna/intern/rna_constraint.c
@@ -2361,12 +2361,12 @@ void RNA_def_constraint(BlenderRNA *brna)
/* flags */
prop = RNA_def_property(srna, "mute", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", CONSTRAINT_OFF);
- RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC);
RNA_def_property_ui_text(prop, "Disable", "Enable/Disable Constraint");
prop = RNA_def_property(srna, "show_expanded", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", CONSTRAINT_EXPAND);
- RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC);
RNA_def_property_ui_text(prop, "Expanded", "Constraint's panel is expanded in UI");
RNA_def_property_ui_icon(prop, ICON_TRIA_RIGHT, 1);
diff --git a/source/blender/makesrna/intern/rna_define.c b/source/blender/makesrna/intern/rna_define.c
index 03e58f8f78e..b8387263932 100644
--- a/source/blender/makesrna/intern/rna_define.c
+++ b/source/blender/makesrna/intern/rna_define.c
@@ -1293,6 +1293,16 @@ void RNA_def_property_clear_flag(PropertyRNA *prop, PropertyFlag flag)
prop->flag &= ~flag;
}
+void RNA_def_property_override_flag(PropertyRNA *prop, PropertyOverrideFlag flag)
+{
+ prop->flag_override |= flag;
+}
+
+void RNA_def_property_override_clear_flag(PropertyRNA *prop, PropertyOverrideFlag flag)
+{
+ prop->flag_override &= ~flag;
+}
+
/**
* Add the property-tags passed as \a tags to \a prop (if valid).
*
diff --git a/source/blender/makesrna/intern/rna_depsgraph.c b/source/blender/makesrna/intern/rna_depsgraph.c
index 8bfa8b7d551..f904d4c06b1 100644
--- a/source/blender/makesrna/intern/rna_depsgraph.c
+++ b/source/blender/makesrna/intern/rna_depsgraph.c
@@ -44,6 +44,8 @@
#include "BLI_iterator.h"
+#include "BKE_anim.h"
+
#include "DEG_depsgraph_build.h"
#include "DEG_depsgraph_debug.h"
#include "DEG_depsgraph_query.h"
@@ -126,6 +128,14 @@ static int rna_DepsgraphObjectInstance_is_instance_get(PointerRNA *ptr)
return (deg_iter->dupli_object_current != NULL);
}
+/* ******************** Sorted ***************** */
+
+static int rna_Depsgraph_mode_get(PointerRNA *ptr)
+{
+ Depsgraph *depsgraph = ptr->data;
+ return DEG_get_mode(depsgraph);
+}
+
/* ******************** Updates ***************** */
static PointerRNA rna_DepsgraphUpdate_id_get(PointerRNA *ptr)
@@ -206,7 +216,6 @@ static void rna_Depsgraph_objects_begin(CollectionPropertyIterator *iter, Pointe
data->flag = DEG_ITER_OBJECT_FLAG_LINKED_DIRECTLY |
DEG_ITER_OBJECT_FLAG_VISIBLE |
DEG_ITER_OBJECT_FLAG_LINKED_VIA_SET;
- data->mode = DEG_ITER_OBJECT_MODE_RENDER;
((BLI_Iterator *)iter->internal.custom)->valid = true;
DEG_iterator_objects_begin(iter->internal.custom, data);
@@ -247,7 +256,6 @@ static void rna_Depsgraph_object_instances_begin(CollectionPropertyIterator *ite
DEG_ITER_OBJECT_FLAG_LINKED_VIA_SET |
DEG_ITER_OBJECT_FLAG_VISIBLE |
DEG_ITER_OBJECT_FLAG_DUPLI;
- data->mode = DEG_ITER_OBJECT_MODE_RENDER;
((BLI_Iterator *)iter->internal.custom)->valid = true;
DEG_iterator_objects_begin(iter->internal.custom, data);
@@ -464,9 +472,20 @@ static void rna_def_depsgraph(BlenderRNA *brna)
PropertyRNA *parm;
PropertyRNA *prop;
+ static EnumPropertyItem enum_depsgraph_mode_items[] = {
+ {DAG_EVAL_VIEWPORT, "VIEWPORT", 0, "Viewport", "Viewport non-rendered mode"},
+ {DAG_EVAL_PREVIEW, "PREVIEW", 0, "Preview", "Viewport rendered draw mode"},
+ {DAG_EVAL_RENDER, "RENDER", 0, "Render", "Render"},
+ {0, NULL, 0, NULL, NULL}
+ };
+
srna = RNA_def_struct(brna, "Depsgraph", NULL);
RNA_def_struct_ui_text(srna, "Dependency Graph", "");
+ prop = RNA_def_enum(srna, "mode", enum_depsgraph_mode_items, 0, "Mode", "Evaluation mode");
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_enum_funcs(prop, "rna_Depsgraph_mode_get", NULL, NULL);
+
/* Debug helpers. */
func = RNA_def_function(srna, "debug_relations_graphviz", "rna_Depsgraph_debug_relations_graphviz");
diff --git a/source/blender/makesrna/intern/rna_fcurve.c b/source/blender/makesrna/intern/rna_fcurve.c
index 61fcc0e6654..0e382248542 100644
--- a/source/blender/makesrna/intern/rna_fcurve.c
+++ b/source/blender/makesrna/intern/rna_fcurve.c
@@ -1497,7 +1497,7 @@ static void rna_def_drivertarget(BlenderRNA *brna)
prop = RNA_def_property(srna, "id", PROP_POINTER, PROP_NONE);
RNA_def_property_struct_type(prop, "ID");
RNA_def_property_flag(prop, PROP_EDITABLE);
- RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC);
RNA_def_property_editable_func(prop, "rna_DriverTarget_id_editable");
/* note: custom set function is ONLY to avoid rna setting a user for this. */
RNA_def_property_pointer_funcs(prop, NULL, "rna_DriverTarget_id_set", "rna_DriverTarget_id_typef", NULL);
@@ -1582,7 +1582,7 @@ static void rna_def_drivervar(BlenderRNA *brna)
prop = RNA_def_property(srna, "targets", PROP_COLLECTION, PROP_NONE);
RNA_def_property_collection_sdna(prop, NULL, "targets", "num_targets");
RNA_def_property_struct_type(prop, "DriverTarget");
- RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC);
RNA_def_property_ui_text(prop, "Targets", "Sources of input data for evaluating this variable");
/* Name Validity Flags */
@@ -1659,7 +1659,7 @@ static void rna_def_channeldriver(BlenderRNA *brna)
prop = RNA_def_property(srna, "variables", PROP_COLLECTION, PROP_NONE);
RNA_def_property_collection_sdna(prop, NULL, "variables", NULL);
RNA_def_property_struct_type(prop, "DriverVariable");
- RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC);
RNA_def_property_ui_text(prop, "Variables", "Properties acting as inputs for this driver");
rna_def_channeldriver_variables(brna, prop);
@@ -1939,7 +1939,7 @@ static void rna_def_fcurve(BlenderRNA *brna)
/* Pointers */
prop = RNA_def_property(srna, "driver", PROP_POINTER, PROP_NONE);
- RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC);
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_def_property_ui_text(prop, "Driver", "Channel Driver (only set for Driver F-Curves)");
diff --git a/source/blender/makesrna/intern/rna_group.c b/source/blender/makesrna/intern/rna_group.c
index 116c0bc4a26..f064e3eb630 100644
--- a/source/blender/makesrna/intern/rna_group.c
+++ b/source/blender/makesrna/intern/rna_group.c
@@ -227,6 +227,7 @@ void RNA_def_collections(BlenderRNA *brna)
prop = RNA_def_property(srna, "objects", PROP_COLLECTION, PROP_NONE);
RNA_def_property_struct_type(prop, "Object");
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC);
RNA_def_property_ui_text(prop, "Objects", "Objects that are directly in this collection");
RNA_def_property_collection_funcs(prop, "rna_Collection_objects_begin",
"rna_iterator_listbase_next",
@@ -257,21 +258,21 @@ void RNA_def_collections(BlenderRNA *brna)
/* Flags */
prop = RNA_def_property(srna, "hide_select", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", COLLECTION_RESTRICT_SELECT);
- RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC);
RNA_def_property_ui_icon(prop, ICON_RESTRICT_SELECT_OFF, 1);
RNA_def_property_ui_text(prop, "Restrict Select", "Disable collection object selection in the 3D viewport");
RNA_def_property_update(prop, NC_SCENE | ND_LAYER_CONTENT, "rna_Collection_flag_update");
prop = RNA_def_property(srna, "hide_viewport", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", COLLECTION_RESTRICT_VIEW);
- RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC);
RNA_def_property_ui_icon(prop, ICON_RESTRICT_VIEW_OFF, 1);
RNA_def_property_ui_text(prop, "Restrict Viewport", "Hide collection objects in the 3D viewport");
RNA_def_property_update(prop, NC_SCENE | ND_LAYER_CONTENT, "rna_Collection_flag_update");
prop = RNA_def_property(srna, "hide_render", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", COLLECTION_RESTRICT_RENDER);
- RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC);
RNA_def_property_ui_icon(prop, ICON_RESTRICT_RENDER_OFF, 1);
RNA_def_property_ui_text(prop, "Restrict Render", "Hide collection objects in renders");
RNA_def_property_update(prop, NC_SCENE | ND_LAYER_CONTENT, "rna_Collection_flag_update");
diff --git a/source/blender/makesrna/intern/rna_image.c b/source/blender/makesrna/intern/rna_image.c
index c554ab8e0fd..cd0824733b9 100644
--- a/source/blender/makesrna/intern/rna_image.c
+++ b/source/blender/makesrna/intern/rna_image.c
@@ -652,7 +652,7 @@ static void rna_def_image(BlenderRNA *brna)
RNA_def_struct_ui_icon(srna, ICON_IMAGE_DATA);
prop = RNA_def_property(srna, "filepath", PROP_STRING, PROP_FILEPATH);
- RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC);
RNA_def_property_string_sdna(prop, NULL, "name");
RNA_def_property_ui_text(prop, "File Name", "Image/Movie file name");
RNA_def_property_update(prop, NC_IMAGE | ND_DISPLAY, "rna_Image_reload_update");
@@ -692,7 +692,7 @@ static void rna_def_image(BlenderRNA *brna)
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_flag(prop, PROP_OVERRIDABLE_STATIC);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC);
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)");
@@ -700,7 +700,7 @@ static void rna_def_image(BlenderRNA *brna)
/* booleans */
prop = RNA_def_property(srna, "use_fields", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC);
RNA_def_property_boolean_sdna(prop, NULL, "flag", IMA_FIELDS);
RNA_def_property_ui_text(prop, "Fields", "Use fields of the image");
RNA_def_property_update(prop, NC_IMAGE | ND_DISPLAY, "rna_Image_fields_update");
@@ -708,43 +708,43 @@ static void rna_def_image(BlenderRNA *brna)
prop = RNA_def_property(srna, "use_view_as_render", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC);
RNA_def_property_boolean_sdna(prop, NULL, "flag", IMA_VIEW_AS_RENDER);
RNA_def_property_ui_text(prop, "View as Render", "Apply render part of display transformation when displaying this image on the screen");
RNA_def_property_update(prop, NC_IMAGE | ND_DISPLAY, NULL);
prop = RNA_def_property(srna, "use_alpha", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC);
RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", IMA_IGNORE_ALPHA);
RNA_def_property_ui_text(prop, "Use Alpha", "Use the alpha channel information from the image or make image fully opaque");
RNA_def_property_update(prop, NC_IMAGE | ND_DISPLAY, "rna_Image_colormanage_update");
prop = RNA_def_property(srna, "use_deinterlace", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC);
RNA_def_property_boolean_sdna(prop, NULL, "flag", IMA_DEINTERLACE);
RNA_def_property_ui_text(prop, "Deinterlace", "Deinterlace movie file on load");
RNA_def_property_update(prop, NC_IMAGE | ND_DISPLAY, "rna_Image_reload_update");
prop = RNA_def_property(srna, "use_multiview", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC);
RNA_def_property_boolean_sdna(prop, NULL, "flag", IMA_USE_VIEWS);
RNA_def_property_ui_text(prop, "Use Multi-View", "Use Multiple Views (when available)");
RNA_def_property_update(prop, NC_IMAGE | ND_DISPLAY, "rna_Image_views_format_update");
prop = RNA_def_property(srna, "is_stereo_3d", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC);
RNA_def_property_boolean_funcs(prop, "rna_Image_is_stereo_3d_get", NULL);
RNA_def_property_ui_text(prop, "Stereo 3D", "Image has left and right views");
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
prop = RNA_def_property(srna, "is_multiview", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC);
RNA_def_property_boolean_funcs(prop, "rna_Image_is_multiview_get", NULL);
RNA_def_property_ui_text(prop, "Multiple Views", "Image has more than one view");
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
prop = RNA_def_property(srna, "is_dirty", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC);
RNA_def_property_boolean_funcs(prop, "rna_Image_dirty_get", NULL);
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_def_property_ui_text(prop, "Dirty", "Image has changed and is not saved");
@@ -787,7 +787,7 @@ static void rna_def_image(BlenderRNA *brna)
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
prop = RNA_def_property(srna, "display_aspect", PROP_FLOAT, PROP_XYZ);
- RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC);
RNA_def_property_float_sdna(prop, NULL, "aspx");
RNA_def_property_array(prop, 2);
RNA_def_property_range(prop, 0.1f, FLT_MAX);
@@ -829,7 +829,7 @@ static void rna_def_image(BlenderRNA *brna)
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
prop = RNA_def_float_vector(srna, "resolution", 2, NULL, 0, 0, "Resolution", "X/Y pixels per meter", 0, 0);
- RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC);
RNA_def_property_float_funcs(prop, "rna_Image_resolution_get", "rna_Image_resolution_set", NULL);
prop = RNA_def_property(srna, "frame_duration", PROP_INT, PROP_UNSIGNED);
@@ -864,14 +864,14 @@ static void rna_def_image(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Color Space Settings", "Input color space settings");
prop = RNA_def_property(srna, "alpha_mode", PROP_ENUM, PROP_NONE);
- RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC);
RNA_def_property_enum_items(prop, alpha_mode_items);
RNA_def_property_ui_text(prop, "Alpha Mode", "Representation of alpha information in the RGBA pixels");
RNA_def_property_update(prop, NC_IMAGE | ND_DISPLAY, "rna_Image_colormanage_update");
/* multiview */
prop = RNA_def_property(srna, "views_format", PROP_ENUM, PROP_NONE);
- RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC);
RNA_def_property_enum_sdna(prop, NULL, "views_format");
RNA_def_property_enum_items(prop, rna_enum_views_format_items);
RNA_def_property_ui_text(prop, "Views Format", "Mode to load image views");
diff --git a/source/blender/makesrna/intern/rna_image_api.c b/source/blender/makesrna/intern/rna_image_api.c
index bcac4b7e9a6..2070ea0a559 100644
--- a/source/blender/makesrna/intern/rna_image_api.c
+++ b/source/blender/makesrna/intern/rna_image_api.c
@@ -63,7 +63,7 @@
static void rna_ImagePackedFile_save(ImagePackedFile *imapf, Main *bmain, ReportList *reports)
{
- if (writePackedFile(reports, bmain->name, imapf->filepath, imapf->packedfile, 0) != RET_OK) {
+ if (writePackedFile(reports, BKE_main_blendfile_path(bmain), imapf->filepath, imapf->packedfile, 0) != RET_OK) {
BKE_reportf(reports, RPT_ERROR, "Could not save packed file to disk as '%s'",
imapf->filepath);
}
diff --git a/source/blender/makesrna/intern/rna_internal_types.h b/source/blender/makesrna/intern/rna_internal_types.h
index 88efff30481..4536b970f91 100644
--- a/source/blender/makesrna/intern/rna_internal_types.h
+++ b/source/blender/makesrna/intern/rna_internal_types.h
@@ -206,6 +206,8 @@ struct PropertyRNA {
const char *identifier;
/* various options */
int flag;
+ /* various override options */
+ int flag_override;
/* Function parameters flags. */
short flag_parameter;
/* Internal ("private") flags. */
diff --git a/source/blender/makesrna/intern/rna_layer.c b/source/blender/makesrna/intern/rna_layer.c
index e7efdc27647..060b075cb29 100644
--- a/source/blender/makesrna/intern/rna_layer.c
+++ b/source/blender/makesrna/intern/rna_layer.c
@@ -49,6 +49,10 @@
#ifdef RNA_RUNTIME
+#ifdef WITH_PYTHON
+# include "BPY_extern.h"
+#endif
+
#include "DNA_group_types.h"
#include "DNA_object_types.h"
@@ -163,22 +167,20 @@ static void rna_LayerObjects_selected_begin(CollectionPropertyIterator *iter, Po
rna_iterator_listbase_begin(iter, &view_layer->object_bases, rna_ViewLayer_objects_selected_skip);
}
-static void rna_ViewLayer_update_tagged(ViewLayer *UNUSED(view_layer), bContext *C)
+static void rna_ViewLayer_update_tagged(ID *id_ptr, ViewLayer *view_layer, Main *bmain)
{
- Depsgraph *depsgraph = CTX_data_depsgraph(C);
- DEG_OBJECT_ITER_BEGIN(
- depsgraph, ob, DEG_ITER_OBJECT_MODE_VIEWPORT,
- DEG_ITER_OBJECT_FLAG_LINKED_DIRECTLY |
- DEG_ITER_OBJECT_FLAG_LINKED_VIA_SET |
- DEG_ITER_OBJECT_FLAG_LINKED_INDIRECTLY |
- DEG_ITER_OBJECT_FLAG_VISIBLE |
- DEG_ITER_OBJECT_FLAG_DUPLI)
- {
- /* Don't do anything, we just need to run the iterator to flush
- * the base info to the objects. */
- UNUSED_VARS(ob);
- }
- DEG_OBJECT_ITER_END;
+#ifdef WITH_PYTHON
+ /* Allow drivers to be evaluated */
+ BPy_BEGIN_ALLOW_THREADS;
+#endif
+
+ Scene *scene = (Scene *)id_ptr;
+ Depsgraph *depsgraph = BKE_scene_get_depsgraph(scene, view_layer, true);
+ BKE_scene_graph_update_tagged(depsgraph, bmain);
+
+#ifdef WITH_PYTHON
+ BPy_END_ALLOW_THREADS;
+#endif
}
static void rna_ObjectBase_select_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr)
@@ -351,7 +353,7 @@ void RNA_def_view_layer(BlenderRNA *brna)
/* debug update routine */
func = RNA_def_function(srna, "update", "rna_ViewLayer_update_tagged");
- RNA_def_function_flag(func, FUNC_USE_CONTEXT);
+ RNA_def_function_flag(func, FUNC_USE_SELF_ID | FUNC_USE_MAIN);
RNA_def_function_ui_description(func,
"Update data tagged to be updated from previous access to data or operators");
diff --git a/source/blender/makesrna/intern/rna_main_api.c b/source/blender/makesrna/intern/rna_main_api.c
index 1aa6bdf9465..9b4d6ead53c 100644
--- a/source/blender/makesrna/intern/rna_main_api.c
+++ b/source/blender/makesrna/intern/rna_main_api.c
@@ -489,7 +489,7 @@ static Text *rna_Main_texts_load(Main *bmain, ReportList *reports, const char *f
Text *txt;
errno = 0;
- txt = BKE_text_load_ex(bmain, filepath, bmain->name, is_internal);
+ txt = BKE_text_load_ex(bmain, filepath, BKE_main_blendfile_path(bmain), is_internal);
if (!txt)
BKE_reportf(reports, RPT_ERROR, "Cannot read '%s': %s", filepath,
diff --git a/source/blender/makesrna/intern/rna_modifier.c b/source/blender/makesrna/intern/rna_modifier.c
index b8fdf4fd4b6..f0013eba1dc 100644
--- a/source/blender/makesrna/intern/rna_modifier.c
+++ b/source/blender/makesrna/intern/rna_modifier.c
@@ -1918,7 +1918,8 @@ static void rna_def_modifier_armature(BlenderRNA *brna)
prop = RNA_def_property(srna, "object", PROP_POINTER, PROP_NONE);
RNA_def_property_ui_text(prop, "Object", "Armature object to deform with");
RNA_def_property_pointer_funcs(prop, NULL, "rna_ArmatureModifier_object_set", NULL, "rna_Armature_object_poll");
- RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_SELF_CHECK | PROP_OVERRIDABLE_STATIC);
+ RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_SELF_CHECK);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC);
RNA_def_property_update(prop, 0, "rna_Modifier_dependency_update");
prop = RNA_def_property(srna, "use_bone_envelopes", PROP_BOOLEAN, PROP_NONE);
@@ -5069,13 +5070,14 @@ void RNA_def_modifier(BlenderRNA *brna)
prop = RNA_def_property(srna, "show_viewport", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "mode", eModifierMode_Realtime);
RNA_def_property_ui_text(prop, "Realtime", "Display modifier in viewport");
- RNA_def_property_flag(prop, PROP_LIB_EXCEPTION | PROP_OVERRIDABLE_STATIC);
+ RNA_def_property_flag(prop, PROP_LIB_EXCEPTION);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC);
RNA_def_property_update(prop, 0, "rna_Modifier_update");
RNA_def_property_ui_icon(prop, ICON_RESTRICT_VIEW_OFF, 0);
prop = RNA_def_property(srna, "show_render", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "mode", eModifierMode_Render);
- RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC);
RNA_def_property_ui_text(prop, "Render", "Use modifier during render");
RNA_def_property_ui_icon(prop, ICON_SCENE, 0);
RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, NULL);
@@ -5094,7 +5096,7 @@ void RNA_def_modifier(BlenderRNA *brna)
prop = RNA_def_property(srna, "show_expanded", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "mode", eModifierMode_Expanded);
- RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC);
RNA_def_property_ui_text(prop, "Expanded", "Set modifier expanded in the user interface");
RNA_def_property_ui_icon(prop, ICON_TRIA_RIGHT, 1);
diff --git a/source/blender/makesrna/intern/rna_movieclip.c b/source/blender/makesrna/intern/rna_movieclip.c
index c663119eb42..aa976775ad1 100644
--- a/source/blender/makesrna/intern/rna_movieclip.c
+++ b/source/blender/makesrna/intern/rna_movieclip.c
@@ -56,11 +56,11 @@
#include "DNA_screen_types.h"
#include "DNA_space_types.h"
-static void rna_MovieClip_reload_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr)
+static void rna_MovieClip_reload_update(Main *bmain, Scene *UNUSED(scene), PointerRNA *ptr)
{
MovieClip *clip = (MovieClip *)ptr->id.data;
- BKE_movieclip_reload(clip);
+ BKE_movieclip_reload(bmain, clip);
DEG_id_tag_update(&clip->id, 0);
}
diff --git a/source/blender/makesrna/intern/rna_nla.c b/source/blender/makesrna/intern/rna_nla.c
index 1301762a4bc..38086a47c51 100644
--- a/source/blender/makesrna/intern/rna_nla.c
+++ b/source/blender/makesrna/intern/rna_nla.c
@@ -655,7 +655,7 @@ static void rna_def_nlastrip(BlenderRNA *brna)
"NLA Strips that this strip acts as a container for (if it is of type Meta)");
/* Settings - Values necessary for evaluation */
- prop = RNA_def_property(srna, "influence", PROP_FLOAT, PROP_NONE);
+ prop = RNA_def_property(srna, "influence", PROP_FLOAT, PROP_FACTOR);
RNA_def_property_range(prop, 0.0f, 1.0f);
RNA_def_property_ui_text(prop, "Influence", "Amount the strip contributes to the current result");
/* XXX: Update temporarily disabled so that the property can be edited at all!
diff --git a/source/blender/makesrna/intern/rna_nodetree.c b/source/blender/makesrna/intern/rna_nodetree.c
index d2fb9d19acc..4f928a9a831 100644
--- a/source/blender/makesrna/intern/rna_nodetree.c
+++ b/source/blender/makesrna/intern/rna_nodetree.c
@@ -2307,31 +2307,13 @@ static void rna_NodeSocketStandard_vector_range(PointerRNA *ptr, float *min, flo
*softmax = dval->max;
}
-static void rna_NodeSocket_value_update(Main *bmain, Scene *scene, PointerRNA *ptr)
-{
- bNodeTree *ntree = (bNodeTree *)ptr->id.data;
- bNodeSocket *sock = ptr->data;
-
- if (ntree->type == NTREE_SHADER) {
- DEG_id_tag_update_ex(bmain, &ntree->id, DEG_TAG_SHADING_UPDATE);
- WM_main_add_notifier(NC_MATERIAL | ND_SHADING, NULL);
-
- if (sock->type == SOCK_STRING) {
- rna_NodeSocket_update(bmain, scene, ptr);
- }
- }
- else {
- rna_NodeSocket_update(bmain, scene, ptr);
- }
-}
-
/* using a context update function here, to avoid searching the node if possible */
static void rna_NodeSocketStandard_value_update(struct bContext *C, PointerRNA *ptr)
{
bNode *node;
/* default update */
- rna_NodeSocket_value_update(CTX_data_main(C), CTX_data_scene(C), ptr);
+ rna_NodeSocket_update(CTX_data_main(C), CTX_data_scene(C), ptr);
/* try to use node from context, faster */
node = CTX_data_pointer_get(C, "node").data;
@@ -2967,7 +2949,7 @@ static void rna_ShaderNodeTexIES_mode_set(PointerRNA *ptr, int value)
if (value == NODE_IES_EXTERNAL && text->name) {
BLI_strncpy(nss->filepath, text->name, sizeof(nss->filepath));
- BLI_path_rel(nss->filepath, G.main->name);
+ BLI_path_rel(nss->filepath, BKE_main_blendfile_path_from_global());
}
id_us_min(node->id);
@@ -2992,7 +2974,7 @@ static void rna_ShaderNodeScript_mode_set(PointerRNA *ptr, int value)
if (value == NODE_SCRIPT_EXTERNAL && text->name) {
BLI_strncpy(nss->filepath, text->name, sizeof(nss->filepath));
- BLI_path_rel(nss->filepath, G.main->name);
+ BLI_path_rel(nss->filepath, BKE_main_blendfile_path_from_global());
}
id_us_min(node->id);
diff --git a/source/blender/makesrna/intern/rna_object.c b/source/blender/makesrna/intern/rna_object.c
index 10a31c9c070..9214f8530b8 100644
--- a/source/blender/makesrna/intern/rna_object.c
+++ b/source/blender/makesrna/intern/rna_object.c
@@ -300,7 +300,7 @@ static void rna_Object_active_shape_update(bContext *C, PointerRNA *ptr)
break;
case OB_CURVE:
case OB_SURF:
- ED_curve_editnurb_load(ob);
+ ED_curve_editnurb_load(bmain, ob);
ED_curve_editnurb_make(ob);
break;
case OB_LATTICE:
@@ -1566,19 +1566,23 @@ static void rna_def_material_slot(BlenderRNA *brna)
RNA_def_struct_ui_text(srna, "Material Slot", "Material slot in an object");
RNA_def_struct_ui_icon(srna, ICON_MATERIAL_DATA);
+ /* WARNING! Order is crucial for override to work properly here... :/
+ * 'link' must come before material pointer, since it defines where (in object or obdata) that one is set! */
+ prop = RNA_def_property(srna, "link", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_items(prop, link_items);
+ RNA_def_property_enum_funcs(prop, "rna_MaterialSlot_link_get", "rna_MaterialSlot_link_set", NULL);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC);
+ RNA_def_property_ui_text(prop, "Link", "Link material to object or the object's data");
+ RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, "rna_MaterialSlot_update");
+
prop = RNA_def_property(srna, "material", PROP_POINTER, PROP_NONE);
RNA_def_property_struct_type(prop, "Material");
RNA_def_property_flag(prop, PROP_EDITABLE);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC);
RNA_def_property_pointer_funcs(prop, "rna_MaterialSlot_material_get", "rna_MaterialSlot_material_set", NULL, NULL);
RNA_def_property_ui_text(prop, "Material", "Material data-block used by this material slot");
RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, "rna_MaterialSlot_update");
- prop = RNA_def_property(srna, "link", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_items(prop, link_items);
- RNA_def_property_enum_funcs(prop, "rna_MaterialSlot_link_get", "rna_MaterialSlot_link_set", NULL);
- RNA_def_property_ui_text(prop, "Link", "Link material to object or the object's data");
- RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, "rna_MaterialSlot_update");
-
prop = RNA_def_property(srna, "name", PROP_STRING, PROP_NONE);
RNA_def_property_string_funcs(prop, "rna_MaterialSlot_name_get", "rna_MaterialSlot_name_length", NULL);
RNA_def_property_ui_text(prop, "Name", "Material slot name");
@@ -1895,6 +1899,7 @@ static void rna_def_object(BlenderRNA *brna)
RNA_def_property_struct_type(prop, "ID");
RNA_def_property_pointer_funcs(prop, NULL, "rna_Object_data_set", "rna_Object_data_typef", NULL);
RNA_def_property_flag(prop, PROP_EDITABLE | PROP_NEVER_UNLINK);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC);
RNA_def_property_ui_text(prop, "Data", "Object data");
RNA_def_property_update(prop, 0, "rna_Object_internal_update_data");
@@ -1928,7 +1933,8 @@ static void rna_def_object(BlenderRNA *brna)
/* parent */
prop = RNA_def_property(srna, "parent", PROP_POINTER, PROP_NONE);
RNA_def_property_pointer_funcs(prop, NULL, "rna_Object_parent_set", NULL, NULL);
- RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_SELF_CHECK | PROP_OVERRIDABLE_STATIC);
+ RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_SELF_CHECK);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC);
RNA_def_property_ui_text(prop, "Parent", "Parent Object");
RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, "rna_Object_dependency_update");
@@ -1981,6 +1987,7 @@ static void rna_def_object(BlenderRNA *brna)
prop = RNA_def_property(srna, "material_slots", PROP_COLLECTION, PROP_NONE);
RNA_def_property_collection_sdna(prop, NULL, "mat", "totcol");
RNA_def_property_struct_type(prop, "MaterialSlot");
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC | PROPOVERRIDE_NO_PROP_NAME);
/* don't dereference pointer! */
RNA_def_property_collection_funcs(prop, NULL, NULL, NULL, "rna_iterator_array_get", NULL, NULL, NULL, NULL);
RNA_def_property_ui_text(prop, "Material Slots", "Material slots in the object");
@@ -1997,6 +2004,7 @@ static void rna_def_object(BlenderRNA *brna)
prop = RNA_def_property(srna, "active_material_index", PROP_INT, PROP_UNSIGNED);
RNA_def_property_int_sdna(prop, NULL, "actcol");
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC);
RNA_def_property_int_funcs(prop, "rna_Object_active_material_index_get", "rna_Object_active_material_index_set",
"rna_Object_active_material_index_range");
RNA_def_property_ui_text(prop, "Active Material Index", "Index of active material slot");
@@ -2006,7 +2014,7 @@ static void rna_def_object(BlenderRNA *brna)
prop = RNA_def_property(srna, "location", PROP_FLOAT, PROP_TRANSLATION);
RNA_def_property_float_sdna(prop, NULL, "loc");
RNA_def_property_editable_array_func(prop, "rna_Object_location_editable");
- RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC);
RNA_def_property_ui_text(prop, "Location", "Location of the object");
RNA_def_property_ui_range(prop, -FLT_MAX, FLT_MAX, 1, RNA_TRANSLATION_PREC_DEFAULT);
RNA_def_property_update(prop, NC_OBJECT | ND_TRANSFORM, "rna_Object_internal_update");
@@ -2014,7 +2022,7 @@ static void rna_def_object(BlenderRNA *brna)
prop = RNA_def_property(srna, "rotation_quaternion", PROP_FLOAT, PROP_QUATERNION);
RNA_def_property_float_sdna(prop, NULL, "quat");
RNA_def_property_editable_array_func(prop, "rna_Object_rotation_4d_editable");
- RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC);
RNA_def_property_float_array_default(prop, default_quat);
RNA_def_property_ui_text(prop, "Quaternion Rotation", "Rotation in Quaternions");
RNA_def_property_update(prop, NC_OBJECT | ND_TRANSFORM, "rna_Object_internal_update");
@@ -2028,14 +2036,14 @@ static void rna_def_object(BlenderRNA *brna)
"rna_Object_rotation_axis_angle_set", NULL);
RNA_def_property_editable_array_func(prop, "rna_Object_rotation_4d_editable");
RNA_def_property_float_array_default(prop, default_axisAngle);
- RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC);
RNA_def_property_ui_text(prop, "Axis-Angle Rotation", "Angle of Rotation for Axis-Angle rotation representation");
RNA_def_property_update(prop, NC_OBJECT | ND_TRANSFORM, "rna_Object_internal_update");
prop = RNA_def_property(srna, "rotation_euler", PROP_FLOAT, PROP_EULER);
RNA_def_property_float_sdna(prop, NULL, "rot");
RNA_def_property_editable_array_func(prop, "rna_Object_rotation_euler_editable");
- RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC);
RNA_def_property_ui_text(prop, "Euler Rotation", "Rotation in Eulers");
RNA_def_property_update(prop, NC_OBJECT | ND_TRANSFORM, "rna_Object_internal_update");
@@ -2048,7 +2056,8 @@ static void rna_def_object(BlenderRNA *brna)
prop = RNA_def_property(srna, "scale", PROP_FLOAT, PROP_XYZ);
RNA_def_property_float_sdna(prop, NULL, "size");
- RNA_def_property_flag(prop, PROP_PROPORTIONAL | PROP_OVERRIDABLE_STATIC);
+ RNA_def_property_flag(prop, PROP_PROPORTIONAL);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC);
RNA_def_property_editable_array_func(prop, "rna_Object_scale_editable");
RNA_def_property_ui_range(prop, -FLT_MAX, FLT_MAX, 1, 3);
RNA_def_property_float_array_default(prop, default_scale);
@@ -2176,13 +2185,13 @@ static void rna_def_object(BlenderRNA *brna)
RNA_def_property_struct_type(prop, "Modifier");
RNA_def_property_ui_text(prop, "Modifiers", "Modifiers affecting the geometric data of the object");
RNA_def_property_override_funcs(prop, NULL, NULL, "rna_Object_modifiers_override_apply");
- RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC | PROP_OVERRIDABLE_STATIC_INSERTION);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC | PROPOVERRIDE_STATIC_INSERTION);
rna_def_object_modifiers(brna, prop);
/* constraints */
prop = RNA_def_property(srna, "constraints", PROP_COLLECTION, PROP_NONE);
RNA_def_property_struct_type(prop, "Constraint");
- RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC | PROP_OVERRIDABLE_STATIC_INSERTION);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC | PROPOVERRIDE_STATIC_INSERTION);
RNA_def_property_ui_text(prop, "Constraints", "Constraints affecting the transformation of the object");
RNA_def_property_override_funcs(prop, NULL, NULL, "rna_Object_constraints_override_apply");
/* RNA_def_property_collection_funcs(prop, NULL, NULL, NULL, NULL, NULL, NULL, NULL, "constraints__add", "constraints__remove"); */
@@ -2460,7 +2469,7 @@ static void rna_def_object(BlenderRNA *brna)
prop = RNA_def_property(srna, "pose", PROP_POINTER, PROP_NONE);
RNA_def_property_pointer_sdna(prop, NULL, "pose");
RNA_def_property_struct_type(prop, "Pose");
- RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC);
RNA_def_property_ui_text(prop, "Pose", "Current pose for armatures");
/* shape keys */
diff --git a/source/blender/makesrna/intern/rna_particle.c b/source/blender/makesrna/intern/rna_particle.c
index 4f9ac94dec1..844e61966bb 100644
--- a/source/blender/makesrna/intern/rna_particle.c
+++ b/source/blender/makesrna/intern/rna_particle.c
@@ -642,7 +642,7 @@ static void rna_Particle_change_type(Main *bmain, Scene *UNUSED(scene), PointerR
static void rna_Particle_change_physics_type(Main *bmain, Scene *scene, PointerRNA *ptr)
{
particle_recalc(bmain, scene, ptr, PSYS_RECALC_RESET | PSYS_RECALC_PHYS);
-
+
ParticleSettings *part = (ParticleSettings *)ptr->data;
if (part->phystype == PART_PHYS_BOIDS && part->boids == NULL) {
@@ -655,7 +655,7 @@ static void rna_Particle_change_physics_type(Main *bmain, Scene *scene, PointerR
BLI_addtail(&state->rules, boid_new_rule(eBoidRuleType_Separate));
BLI_addtail(&state->rules, boid_new_rule(eBoidRuleType_Flock));
- ((BoidRule*)state->rules.first)->flag |= BOIDRULE_CURRENT;
+ ((BoidRule *)state->rules.first)->flag |= BOIDRULE_CURRENT;
state->flag |= BOIDSTATE_CURRENT;
BLI_addtail(&part->boids->states, state);
@@ -3295,13 +3295,13 @@ static void rna_def_particle_system(BlenderRNA *brna)
prop = RNA_def_property(srna, "particles", PROP_COLLECTION, PROP_NONE);
RNA_def_property_collection_sdna(prop, NULL, "particles", "totpart");
RNA_def_property_struct_type(prop, "Particle");
- RNA_def_property_flag(prop, PROP_NO_COMPARISON);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_NO_COMPARISON);
RNA_def_property_ui_text(prop, "Particles", "Particles generated by the particle system");
prop = RNA_def_property(srna, "child_particles", PROP_COLLECTION, PROP_NONE);
RNA_def_property_collection_sdna(prop, NULL, "child", "totchild");
RNA_def_property_struct_type(prop, "ChildParticle");
- RNA_def_property_flag(prop, PROP_NO_COMPARISON);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_NO_COMPARISON);
RNA_def_property_ui_text(prop, "Child Particles", "Child particles generated by the particle system");
prop = RNA_def_property(srna, "seed", PROP_INT, PROP_UNSIGNED);
diff --git a/source/blender/makesrna/intern/rna_pose.c b/source/blender/makesrna/intern/rna_pose.c
index c25601a25fe..fb0f59a7977 100644
--- a/source/blender/makesrna/intern/rna_pose.c
+++ b/source/blender/makesrna/intern/rna_pose.c
@@ -106,6 +106,7 @@ const EnumPropertyItem rna_enum_color_sets_items[] = {
#include "BKE_context.h"
#include "BKE_constraint.h"
+#include "BKE_global.h"
#include "BKE_idprop.h"
#include "DEG_depsgraph.h"
@@ -291,7 +292,7 @@ static void rna_PoseChannel_name_set(PointerRNA *ptr, const char *value)
BLI_strncpy_utf8(newname, value, sizeof(pchan->name));
BLI_strncpy(oldname, pchan->name, sizeof(pchan->name));
- ED_armature_bone_rename(ob->data, oldname, newname);
+ ED_armature_bone_rename(G.main, ob->data, oldname, newname);
}
static int rna_PoseChannel_has_ik_get(PointerRNA *ptr)
@@ -857,7 +858,7 @@ static void rna_def_pose_channel(BlenderRNA *brna)
/* Bone Constraints */
prop = RNA_def_property(srna, "constraints", PROP_COLLECTION, PROP_NONE);
RNA_def_property_struct_type(prop, "Constraint");
- RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC | PROP_OVERRIDABLE_STATIC_INSERTION);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC | PROPOVERRIDE_STATIC_INSERTION);
RNA_def_property_ui_text(prop, "Constraints", "Constraints that act on this PoseChannel");
RNA_def_property_override_funcs(prop, NULL, NULL, "rna_PoseChannel_constraints_override_apply");
@@ -896,7 +897,7 @@ static void rna_def_pose_channel(BlenderRNA *brna)
/* Transformation settings */
prop = RNA_def_property(srna, "location", PROP_FLOAT, PROP_TRANSLATION);
RNA_def_property_float_sdna(prop, NULL, "loc");
- RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC);
RNA_def_property_editable_array_func(prop, "rna_PoseChannel_location_editable");
RNA_def_property_ui_text(prop, "Location", "");
RNA_def_property_ui_range(prop, -FLT_MAX, FLT_MAX, 1, RNA_TRANSLATION_PREC_DEFAULT);
@@ -904,7 +905,8 @@ static void rna_def_pose_channel(BlenderRNA *brna)
prop = RNA_def_property(srna, "scale", PROP_FLOAT, PROP_XYZ);
RNA_def_property_float_sdna(prop, NULL, "size");
- RNA_def_property_flag(prop, PROP_PROPORTIONAL | PROP_OVERRIDABLE_STATIC);
+ RNA_def_property_flag(prop, PROP_PROPORTIONAL);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC);
RNA_def_property_editable_array_func(prop, "rna_PoseChannel_scale_editable");
RNA_def_property_float_array_default(prop, default_scale);
RNA_def_property_ui_text(prop, "Scale", "");
@@ -912,7 +914,7 @@ static void rna_def_pose_channel(BlenderRNA *brna)
prop = RNA_def_property(srna, "rotation_quaternion", PROP_FLOAT, PROP_QUATERNION);
RNA_def_property_float_sdna(prop, NULL, "quat");
- RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC);
RNA_def_property_editable_array_func(prop, "rna_PoseChannel_rotation_4d_editable");
RNA_def_property_float_array_default(prop, default_quat);
RNA_def_property_ui_text(prop, "Quaternion Rotation", "Rotation in Quaternions");
@@ -922,7 +924,7 @@ static void rna_def_pose_channel(BlenderRNA *brna)
* having a single one is better for Keyframing and other property-management situations...
*/
prop = RNA_def_property(srna, "rotation_axis_angle", PROP_FLOAT, PROP_AXISANGLE);
- RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC);
RNA_def_property_array(prop, 4);
RNA_def_property_float_funcs(prop, "rna_PoseChannel_rotation_axis_angle_get",
"rna_PoseChannel_rotation_axis_angle_set", NULL);
@@ -933,7 +935,7 @@ static void rna_def_pose_channel(BlenderRNA *brna)
prop = RNA_def_property(srna, "rotation_euler", PROP_FLOAT, PROP_EULER);
RNA_def_property_float_sdna(prop, NULL, "eul");
- RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC);
RNA_def_property_editable_array_func(prop, "rna_PoseChannel_rotation_euler_editable");
RNA_def_property_ui_text(prop, "Euler Rotation", "Rotation in Eulers");
RNA_def_property_update(prop, NC_OBJECT | ND_POSE, "rna_Pose_update");
@@ -1460,7 +1462,7 @@ static void rna_def_pose(BlenderRNA *brna)
prop = RNA_def_property(srna, "bones", PROP_COLLECTION, PROP_NONE);
RNA_def_property_collection_sdna(prop, NULL, "chanbase", NULL);
RNA_def_property_struct_type(prop, "PoseBone");
- RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC);
RNA_def_property_ui_text(prop, "Pose Bones", "Individual pose bones for the armature");
/* can be removed, only for fast lookup */
RNA_def_property_collection_funcs(prop, NULL, NULL, NULL, NULL, NULL, NULL, "rna_PoseBones_lookup_string", NULL);
diff --git a/source/blender/makesrna/intern/rna_rna.c b/source/blender/makesrna/intern/rna_rna.c
index f42bc1e1923..1a66174d8ce 100644
--- a/source/blender/makesrna/intern/rna_rna.c
+++ b/source/blender/makesrna/intern/rna_rna.c
@@ -595,7 +595,7 @@ static int rna_Property_overridable_get(PointerRNA *ptr)
{
PropertyRNA *prop = (PropertyRNA *)ptr->data;
- return (prop->flag & PROP_OVERRIDABLE_STATIC) != 0;
+ return (prop->flag_override & PROPOVERRIDE_OVERRIDABLE_STATIC) != 0;
}
static int rna_Property_use_output_get(PointerRNA *ptr)
@@ -1121,7 +1121,7 @@ static int rna_BlenderRNA_structs_lookup_string(PointerRNA *ptr, const char *key
/* Ensures it makes sense to go inside the pointers to compare their content
* (if they are IDs, or have different names or RNA type, then this would be meaningless). */
static bool rna_property_override_diff_propptr_validate_diffing(
- PointerRNA *propptr_a, PointerRNA *propptr_b,
+ PointerRNA *propptr_a, PointerRNA *propptr_b, const bool no_prop_name,
bool *r_is_id, bool *r_is_null, bool *r_is_type_diff,
char **r_propname_a, char *propname_a_buff, size_t propname_a_buff_size,
char **r_propname_b, char *propname_b_buff, size_t propname_b_buff_size)
@@ -1129,7 +1129,7 @@ static bool rna_property_override_diff_propptr_validate_diffing(
BLI_assert(propptr_a != NULL);
bool is_valid_for_diffing = true;
- const bool do_force_name = r_propname_a != NULL;
+ const bool do_force_name = !no_prop_name && r_propname_a != NULL;
if (do_force_name) {
BLI_assert(r_propname_a != NULL);
@@ -1165,7 +1165,7 @@ static bool rna_property_override_diff_propptr_validate_diffing(
/* We do a generic quick first comparison checking for "name" and/or "type" properties.
* We assume that is any of those are false, then we are not handling the same data.
* This helps a lot in static override case, especially to detect inserted items in collections. */
- if (is_valid_for_diffing || do_force_name) {
+ if (!no_prop_name && (is_valid_for_diffing || do_force_name)) {
PropertyRNA *nameprop_a = RNA_struct_name_property(propptr_a->type);
PropertyRNA *nameprop_b = (propptr_b != NULL) ? RNA_struct_name_property(propptr_b->type) : NULL;
@@ -1222,7 +1222,8 @@ static bool rna_property_override_diff_propptr_validate_diffing(
/* Used for both Pointer and Collection properties. */
static int rna_property_override_diff_propptr(
- PointerRNA *propptr_a, PointerRNA *propptr_b, eRNACompareMode mode, const bool no_ownership,
+ PointerRNA *propptr_a, PointerRNA *propptr_b,
+ eRNACompareMode mode, const bool no_ownership, const bool no_prop_name,
IDOverrideStatic *override, const char *rna_path, const int flags, bool *r_override_changed)
{
const bool do_create = override != NULL && (flags & RNA_OVERRIDE_COMPARE_CREATE) != 0 && rna_path != NULL;
@@ -1232,7 +1233,7 @@ static int rna_property_override_diff_propptr(
bool is_type_diff = false;
/* If false, it means that the whole data itself is different, so no point in going inside of it at all! */
bool is_valid_for_diffing = rna_property_override_diff_propptr_validate_diffing(
- propptr_a, propptr_b, &is_id, &is_null, &is_type_diff,
+ propptr_a, propptr_b, no_prop_name, &is_id, &is_null, &is_type_diff,
NULL, NULL, 0, NULL, NULL, 0);
if (is_id) {
@@ -1538,8 +1539,9 @@ int rna_property_override_diff_default(PointerRNA *ptr_a, PointerRNA *ptr_b,
PointerRNA propptr_a = RNA_property_pointer_get(ptr_a, prop_a);
PointerRNA propptr_b = RNA_property_pointer_get(ptr_b, prop_b);
const bool no_ownership = (RNA_property_flag(prop_a) & PROP_PTR_NO_OWNERSHIP) != 0;
+ const bool no_prop_name = (RNA_property_override_flag(prop_a) & PROPOVERRIDE_NO_PROP_NAME) != 0;
return rna_property_override_diff_propptr(
- &propptr_a, &propptr_b, mode, no_ownership,
+ &propptr_a, &propptr_b, mode, no_ownership, no_prop_name,
override, rna_path, flags, r_override_changed);
}
break;
@@ -1549,7 +1551,8 @@ int rna_property_override_diff_default(PointerRNA *ptr_a, PointerRNA *ptr_b,
{
/* Note: we assume we only insert in ptr_a (i.e. we can only get new items in ptr_a),
* and that we never remove anything. */
- const bool use_insertion = (RNA_property_flag(prop_a) & PROP_OVERRIDABLE_STATIC_INSERTION) && do_create;
+ const bool use_insertion = (RNA_property_override_flag(prop_a) & PROPOVERRIDE_STATIC_INSERTION) && do_create;
+ const bool no_prop_name = (RNA_property_override_flag(prop_a) & PROPOVERRIDE_NO_PROP_NAME) != 0;
bool equals = true;
bool abort = false;
bool is_first_insert = true;
@@ -1590,16 +1593,18 @@ int rna_property_override_diff_default(PointerRNA *ptr_a, PointerRNA *ptr_b,
/* If false, it means that the whole data itself is different, so no point in going inside of it at all! */
if (iter_b.valid) {
is_valid_for_diffing = rna_property_override_diff_propptr_validate_diffing(
- &iter_a.ptr, &iter_b.ptr, &is_id, &is_null, &is_type_diff,
- &propname_a, buff_a, sizeof(buff_a),
- &propname_b, buff_b, sizeof(buff_b));
+ &iter_a.ptr, &iter_b.ptr, no_prop_name,
+ &is_id, &is_null, &is_type_diff,
+ &propname_a, buff_a, sizeof(buff_a),
+ &propname_b, buff_b, sizeof(buff_b));
}
else {
is_valid_for_diffing = false;
if (is_valid_for_insertion) {
/* We still need propname from 'a' item... */
rna_property_override_diff_propptr_validate_diffing(
- &iter_a.ptr, NULL, &is_id, &is_null, &is_type_diff,
+ &iter_a.ptr, NULL, no_prop_name,
+ &is_id, &is_null, &is_type_diff,
&propname_a, buff_a, sizeof(buff_a),
&propname_b, buff_b, sizeof(buff_b));
}
@@ -1615,7 +1620,7 @@ int rna_property_override_diff_default(PointerRNA *ptr_a, PointerRNA *ptr_b,
printf("Checking %s, %s [%d] vs %s [%d]; diffing: %d; insert: %d (could be used: %d, do_create: %d)\n",
rna_path, propname_a ? propname_a : "", idx_a, propname_b ? propname_b : "", idx_b,
is_valid_for_diffing, is_valid_for_insertion,
- (RNA_property_flag(prop_a) & PROP_OVERRIDABLE_STATIC_INSERTION) != 0, do_create);
+ (RNA_property_override_flag(prop_a) & PROPOVERRIDE_STATIC_INSERTION) != 0, do_create);
}
#endif
@@ -1685,7 +1690,7 @@ int rna_property_override_diff_default(PointerRNA *ptr_a, PointerRNA *ptr_b,
if (equals || do_create) {
const bool no_ownership = (RNA_property_flag(prop_a) & PROP_PTR_NO_OWNERSHIP) != 0;
const int eq = rna_property_override_diff_propptr(
- &iter_a.ptr, &iter_b.ptr, mode, no_ownership,
+ &iter_a.ptr, &iter_b.ptr, mode, no_ownership, no_prop_name,
override, extended_rna_path, flags, r_override_changed);
equals = equals && eq;
}
diff --git a/source/blender/makesrna/intern/rna_scene.c b/source/blender/makesrna/intern/rna_scene.c
index 1530c7fc483..8055c8fe4d6 100644
--- a/source/blender/makesrna/intern/rna_scene.c
+++ b/source/blender/makesrna/intern/rna_scene.c
@@ -5759,7 +5759,7 @@ static void rna_def_scene_display(BlenderRNA *brna)
RNA_def_property_range(prop, 0.0f, 250.0f);
prop = RNA_def_property(srna, "matcap_ssao_factor_edge", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_default(prop, 1.0f);
+ RNA_def_property_float_default(prop, 1.0f);
RNA_def_property_ui_text(prop, "Edge Strength", "Strength of the Edge effect");
RNA_def_property_range(prop, 0.0f, 250.0f);
@@ -5837,337 +5837,337 @@ static void rna_def_scene_eevee(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Diffuse Bounces", "Number of time the light is reinjected inside light grids, "
"0 disable indirect diffuse light");
RNA_def_property_range(prop, 0, INT_MAX);
- RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC);
prop = RNA_def_property(srna, "gi_cubemap_resolution", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_items(prop, eevee_shadow_size_items);
RNA_def_property_enum_default(prop, 512);
RNA_def_property_ui_text(prop, "Cubemap Size", "Size of every cubemaps");
- RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC);
prop = RNA_def_property(srna, "gi_visibility_resolution", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_items(prop, eevee_gi_visibility_size_items);
RNA_def_property_enum_default(prop, 32);
RNA_def_property_ui_text(prop, "Irradiance Visibility Size",
"Size of the shadow map applied to each irradiance sample");
- RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC);
/* Temporal Anti-Aliasing (super sampling) */
prop = RNA_def_property(srna, "taa_samples", PROP_INT, PROP_NONE);
RNA_def_property_int_default(prop, 16);
RNA_def_property_ui_text(prop, "Viewport Samples", "Number of samples, unlimited if 0");
RNA_def_property_range(prop, 0, INT_MAX);
- RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC);
prop = RNA_def_property(srna, "taa_render_samples", PROP_INT, PROP_NONE);
RNA_def_property_int_default(prop, 64);
RNA_def_property_ui_text(prop, "Render Samples", "Number of samples per pixels for rendering");
RNA_def_property_range(prop, 1, INT_MAX);
- RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC);
prop = RNA_def_property(srna, "use_taa_reprojection", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", SCE_EEVEE_TAA_REPROJECTION);
RNA_def_property_boolean_default(prop, 1);
RNA_def_property_ui_text(prop, "Viewport Denoising", "Denoise image using temporal reprojection "
"(can leave some ghosting)");
- RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC);
/* Screen Space Subsurface Scattering */
prop = RNA_def_property(srna, "use_sss", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", SCE_EEVEE_SSS_ENABLED);
RNA_def_property_boolean_default(prop, 0);
RNA_def_property_ui_text(prop, "Subsurface Scattering", "Enable screen space subsurface scattering");
- RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC);
prop = RNA_def_property(srna, "sss_samples", PROP_INT, PROP_NONE);
RNA_def_property_int_default(prop, 7);
RNA_def_property_ui_text(prop, "Samples", "Number of samples to compute the scattering effect");
RNA_def_property_range(prop, 1, 32);
- RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC);
prop = RNA_def_property(srna, "sss_jitter_threshold", PROP_FLOAT, PROP_FACTOR);
RNA_def_property_float_default(prop, 0.3f);
RNA_def_property_ui_text(prop, "Jitter Threshold", "Rotate samples that are below this threshold");
RNA_def_property_range(prop, 0.0f, 1.0f);
- RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC);
prop = RNA_def_property(srna, "use_sss_separate_albedo", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", SCE_EEVEE_SSS_SEPARATE_ALBEDO);
RNA_def_property_boolean_default(prop, 0);
RNA_def_property_ui_text(prop, "Separate Albedo", "Avoid albedo being blured by the subsurface scattering "
"but uses more video memory");
- RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC);
/* Screen Space Reflection */
prop = RNA_def_property(srna, "use_ssr", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", SCE_EEVEE_SSR_ENABLED);
RNA_def_property_boolean_default(prop, 0);
RNA_def_property_ui_text(prop, "Screen Space Reflections", "Enable screen space reflection");
- RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC);
prop = RNA_def_property(srna, "use_ssr_refraction", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", SCE_EEVEE_SSR_REFRACTION);
RNA_def_property_boolean_default(prop, 0);
RNA_def_property_ui_text(prop, "Screen Space Refractions", "Enable screen space Refractions");
- RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC);
prop = RNA_def_property(srna, "use_ssr_halfres", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", SCE_EEVEE_SSR_HALF_RESOLUTION);
RNA_def_property_boolean_default(prop, 1);
RNA_def_property_ui_text(prop, "Half Res Trace", "Raytrace at a lower resolution");
- RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC);
prop = RNA_def_property(srna, "ssr_quality", PROP_FLOAT, PROP_FACTOR);
RNA_def_property_float_default(prop, 0.25f);
RNA_def_property_ui_text(prop, "Trace Quality", "Quality of the screen space raytracing");
RNA_def_property_range(prop, 0.0f, 1.0f);
- RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC);
prop = RNA_def_property(srna, "ssr_max_roughness", PROP_FLOAT, PROP_FACTOR);
RNA_def_property_float_default(prop, 0.5f);
RNA_def_property_ui_text(prop, "Max Roughness", "Do not raytrace reflections for roughness above this value");
RNA_def_property_range(prop, 0.0f, 1.0f);
- RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC);
prop = RNA_def_property(srna, "ssr_thickness", PROP_FLOAT, PROP_DISTANCE);
RNA_def_property_float_default(prop, 0.2f);
RNA_def_property_ui_text(prop, "Thickness", "Pixel thickness used to detect intersection");
RNA_def_property_range(prop, 1e-6f, FLT_MAX);
RNA_def_property_ui_range(prop, 0.001f, FLT_MAX, 5, 3);
- RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC);
prop = RNA_def_property(srna, "ssr_border_fade", PROP_FLOAT, PROP_FACTOR);
RNA_def_property_float_default(prop, 0.075f);
RNA_def_property_ui_text(prop, "Edge Fading", "Screen percentage used to fade the SSR");
RNA_def_property_range(prop, 0.0f, 0.5f);
- RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC);
prop = RNA_def_property(srna, "ssr_firefly_fac", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_default(prop, 10.0f);
RNA_def_property_ui_text(prop, "Clamp", "Clamp pixel intensity to remove noise (0 to disabled)");
RNA_def_property_range(prop, 0.0f, FLT_MAX);
- RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC);
/* Volumetrics */
prop = RNA_def_property(srna, "use_volumetric", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", SCE_EEVEE_VOLUMETRIC_ENABLED);
RNA_def_property_boolean_default(prop, 0);
RNA_def_property_ui_text(prop, "Volumetrics", "Enable scattering and absorbance of volumetric material");
- RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC);
prop = RNA_def_property(srna, "volumetric_start", PROP_FLOAT, PROP_DISTANCE);
RNA_def_property_float_default(prop, 0.1f);
RNA_def_property_ui_text(prop, "Start", "Start distance of the volumetric effect");
RNA_def_property_range(prop, 1e-6f, FLT_MAX);
RNA_def_property_ui_range(prop, 0.001f, FLT_MAX, 10, 3);
- RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC);
prop = RNA_def_property(srna, "volumetric_end", PROP_FLOAT, PROP_DISTANCE);
RNA_def_property_float_default(prop, 100.0f);
RNA_def_property_ui_text(prop, "End", "End distance of the volumetric effect");
RNA_def_property_range(prop, 1e-6f, FLT_MAX);
RNA_def_property_ui_range(prop, 0.001f, FLT_MAX, 10, 3);
- RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC);
prop = RNA_def_property(srna, "volumetric_tile_size", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_default(prop, 8);
RNA_def_property_enum_items(prop, eevee_volumetric_tile_size_items);
RNA_def_property_ui_text(prop, "Tile Size", "Control the quality of the volumetric effects "
"(lower size increase vram usage and quality)");
- RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC);
prop = RNA_def_property(srna, "volumetric_samples", PROP_INT, PROP_NONE);
RNA_def_property_int_default(prop, 64);
RNA_def_property_ui_text(prop, "Samples", "Number of samples to compute volumetric effects");
RNA_def_property_range(prop, 1, 256);
- RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC);
prop = RNA_def_property(srna, "volumetric_sample_distribution", PROP_FLOAT, PROP_FACTOR);
RNA_def_property_float_default(prop, 0.8f);
RNA_def_property_ui_text(prop, "Exponential Sampling", "Distribute more samples closer to the camera");
- RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC);
prop = RNA_def_property(srna, "use_volumetric_lights", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", SCE_EEVEE_VOLUMETRIC_LIGHTS);
RNA_def_property_boolean_default(prop, 1);
RNA_def_property_ui_text(prop, "Volumetric Lighting", "Enable scene lamps interactions with volumetrics");
- RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC);
prop = RNA_def_property(srna, "volumetric_light_clamp", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_default(prop, 0.0f);
RNA_def_property_range(prop, 0.0f, FLT_MAX);
RNA_def_property_ui_text(prop, "Clamp", "Maximum light contribution, reducing noise");
- RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC);
prop = RNA_def_property(srna, "use_volumetric_shadows", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", SCE_EEVEE_VOLUMETRIC_SHADOWS);
RNA_def_property_boolean_default(prop, 0);
RNA_def_property_ui_text(prop, "Volumetric Shadows", "Generate shadows from volumetric material (Very expensive)");
- RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC);
prop = RNA_def_property(srna, "volumetric_shadow_samples", PROP_INT, PROP_NONE);
RNA_def_property_int_default(prop, 16);
RNA_def_property_range(prop, 1, 128);
RNA_def_property_ui_text(prop, "Volumetric Shadow Samples", "Number of samples to compute volumetric shadowing");
- RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC);
prop = RNA_def_property(srna, "use_volumetric_colored_transmittance", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", SCE_EEVEE_VOLUMETRIC_COLORED);
RNA_def_property_boolean_default(prop, 1);
RNA_def_property_ui_text(prop, "Colored Transmittance", "Enable wavelength dependent volumetric transmittance");
- RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC);
/* Ambient Occlusion */
prop = RNA_def_property(srna, "use_gtao", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", SCE_EEVEE_GTAO_ENABLED);
RNA_def_property_boolean_default(prop, 0);
RNA_def_property_ui_text(prop, "Ambient Occlusion", "Enable ambient occlusion to simulate medium scale indirect shadowing");
- RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC);
prop = RNA_def_property(srna, "use_gtao_bent_normals", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", SCE_EEVEE_GTAO_BENT_NORMALS);
RNA_def_property_boolean_default(prop, 1);
RNA_def_property_ui_text(prop, "Bent Normals", "Compute main non occluded direction to sample the environment");
- RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC);
prop = RNA_def_property(srna, "use_gtao_bounce", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", SCE_EEVEE_GTAO_BOUNCE);
RNA_def_property_boolean_default(prop, 1);
RNA_def_property_ui_text(prop, "Bounces Approximation", "An approximation to simulate light bounces "
"giving less occlusion on brighter objects");
- RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC);
prop = RNA_def_property(srna, "gtao_factor", PROP_FLOAT, PROP_FACTOR);
RNA_def_property_float_default(prop, 1.0f);
RNA_def_property_ui_text(prop, "Factor", "Factor for ambient occlusion blending");
RNA_def_property_range(prop, 0.0f, FLT_MAX);
RNA_def_property_ui_range(prop, 0.0f, 1.0f, 0.1f, 2);
- RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC);
prop = RNA_def_property(srna, "gtao_quality", PROP_FLOAT, PROP_FACTOR);
RNA_def_property_float_default(prop, 0.25f);
RNA_def_property_ui_text(prop, "Trace Quality", "Quality of the horizon search");
RNA_def_property_range(prop, 0.0f, 1.0f);
- RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC);
prop = RNA_def_property(srna, "gtao_distance", PROP_FLOAT, PROP_DISTANCE);
RNA_def_property_float_default(prop, 0.2f);
RNA_def_property_ui_text(prop, "Distance", "Distance of object that contribute to the ambient occlusion effect");
RNA_def_property_range(prop, 0.0f, 100000.0f);
RNA_def_property_ui_range(prop, 0.0f, 100.0f, 1, 3);
- RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC);
/* Depth of Field */
prop = RNA_def_property(srna, "use_dof", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", SCE_EEVEE_DOF_ENABLED);
RNA_def_property_boolean_default(prop, 0);
RNA_def_property_ui_text(prop, "Depth of Field", "Enable depth of field using the values from the active camera");
- RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC);
prop = RNA_def_property(srna, "bokeh_max_size", PROP_FLOAT, PROP_FACTOR);
RNA_def_property_float_default(prop, 100.0f);
RNA_def_property_ui_text(prop, "Max Size", "Max size of the bokeh shape for the depth of field (lower is faster)");
RNA_def_property_range(prop, 0.0f, 2000.0f);
RNA_def_property_ui_range(prop, 2.0f, 200.0f, 1, 3);
- RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC);
prop = RNA_def_property(srna, "bokeh_threshold", PROP_FLOAT, PROP_FACTOR);
RNA_def_property_float_default(prop, 1.0f);
RNA_def_property_ui_text(prop, "Sprite Threshold", "Brightness threshold for using sprite base depth of field");
RNA_def_property_range(prop, 0.0f, 100000.0f);
RNA_def_property_ui_range(prop, 0.0f, 10.0f, 1, 3);
- RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC);
/* Bloom */
prop = RNA_def_property(srna, "use_bloom", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", SCE_EEVEE_BLOOM_ENABLED);
RNA_def_property_boolean_default(prop, 0);
RNA_def_property_ui_text(prop, "Bloom", "High brighness pixels generate a glowing effect");
- RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC);
prop = RNA_def_property(srna, "bloom_threshold", PROP_FLOAT, PROP_FACTOR);
RNA_def_property_float_default(prop, 0.8f);
RNA_def_property_ui_text(prop, "Threshold", "Filters out pixels under this level of brightness");
RNA_def_property_range(prop, 0.0f, 100000.0f);
RNA_def_property_ui_range(prop, 0.0f, 10.0f, 1, 3);
- RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC);
prop = RNA_def_property(srna, "bloom_color", PROP_FLOAT, PROP_COLOR);
RNA_def_property_float_array_default(prop, default_bloom_color);
RNA_def_property_array(prop, 3);
RNA_def_property_ui_text(prop, "Color", "Color applied to the bloom effect");
- RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC);
prop = RNA_def_property(srna, "bloom_knee", PROP_FLOAT, PROP_FACTOR);
RNA_def_property_float_default(prop, 0.5f);
RNA_def_property_ui_text(prop, "Knee", "Makes transition between under/over-threshold gradual");
RNA_def_property_range(prop, 0.0f, 1.0f);
- RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC);
prop = RNA_def_property(srna, "bloom_radius", PROP_FLOAT, PROP_FACTOR);
RNA_def_property_float_default(prop, 6.5f);
RNA_def_property_ui_text(prop, "Radius", "Bloom spread distance");
RNA_def_property_range(prop, 0.0f, 100.0f);
RNA_def_property_ui_range(prop, 0.0f, 10.0f, 1, 3);
- RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC);
prop = RNA_def_property(srna, "bloom_clamp", PROP_FLOAT, PROP_FACTOR);
RNA_def_property_float_default(prop, 1.0f);
RNA_def_property_ui_text(prop, "Clamp", "Maximum intensity a bloom pixel can have");
RNA_def_property_range(prop, 0.0f, 1000.0f);
RNA_def_property_ui_range(prop, 0.0f, 10.0f, 1, 3);
- RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC);
prop = RNA_def_property(srna, "bloom_intensity", PROP_FLOAT, PROP_UNSIGNED);
RNA_def_property_float_default(prop, 0.8f);
RNA_def_property_ui_text(prop, "Intensity", "Blend factor");
RNA_def_property_range(prop, 0.0f, 10000.0f);
RNA_def_property_ui_range(prop, 0.0f, 10.0f, 1, 3);
- RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC);
/* Motion blur */
prop = RNA_def_property(srna, "use_motion_blur", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", SCE_EEVEE_MOTION_BLUR_ENABLED);
RNA_def_property_boolean_default(prop, 0);
RNA_def_property_ui_text(prop, "Motion Blur", "Enable motion blur effect (only in camera view)");
- RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC);
prop = RNA_def_property(srna, "motion_blur_samples", PROP_INT, PROP_UNSIGNED);
RNA_def_property_int_default(prop, 8);
RNA_def_property_ui_text(prop, "Samples", "Number of samples to take with motion blur");
RNA_def_property_range(prop, 1, 64);
- RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC);
prop = RNA_def_property(srna, "motion_blur_shutter", PROP_FLOAT, PROP_UNSIGNED);
RNA_def_property_float_default(prop, 1.0f);
RNA_def_property_ui_text(prop, "Shutter", "Time taken in frames between shutter open and close");
RNA_def_property_ui_range(prop, 0.01f, 2.0f, 1, 2);
- RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC);
/* Shadows */
prop = RNA_def_property(srna, "shadow_method", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_default(prop, SHADOW_ESM);
RNA_def_property_enum_items(prop, eevee_shadow_method_items);
RNA_def_property_ui_text(prop, "Method", "Technique use to compute the shadows");
- RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC);
prop = RNA_def_property(srna, "shadow_cube_size", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_default(prop, 512);
RNA_def_property_enum_items(prop, eevee_shadow_size_items);
RNA_def_property_ui_text(prop, "Cube Shadows Resolution", "Size of point and area lamps shadow maps");
- RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC);
prop = RNA_def_property(srna, "shadow_cascade_size", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_default(prop, 1024);
RNA_def_property_enum_items(prop, eevee_shadow_size_items);
RNA_def_property_ui_text(prop, "Directional Shadows Resolution", "Size of sun lamps shadow maps");
- RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC);
prop = RNA_def_property(srna, "use_shadow_high_bitdepth", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", SCE_EEVEE_SHADOW_HIGH_BITDEPTH);
RNA_def_property_boolean_default(prop, 0);
RNA_def_property_ui_text(prop, "High Bitdepth", "Use 32bit shadows");
- RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC);
}
void RNA_def_scene(BlenderRNA *brna)
diff --git a/source/blender/makesrna/intern/rna_scene_api.c b/source/blender/makesrna/intern/rna_scene_api.c
index a307aff6e96..ba03472d8d5 100644
--- a/source/blender/makesrna/intern/rna_scene_api.c
+++ b/source/blender/makesrna/intern/rna_scene_api.c
@@ -158,13 +158,13 @@ static void rna_SceneRender_get_frame_path(
}
else {
BKE_image_path_from_imformat(
- name, rd->pic, bmain->name, (frame == INT_MIN) ? rd->cfra : frame,
+ name, rd->pic, BKE_main_blendfile_path(bmain), (frame == INT_MIN) ? rd->cfra : frame,
&rd->im_format, (rd->scemode & R_EXTENSION) != 0, true, suffix);
}
}
static void rna_Scene_ray_cast(
- Scene *scene, ViewLayer *view_layer,
+ Scene *scene, Main *bmain, ViewLayer *view_layer,
float origin[3], float direction[3], float ray_dist,
int *r_success, float r_location[3], float r_normal[3], int *r_index,
Object **r_ob, float r_obmat[16])
@@ -172,8 +172,7 @@ static void rna_Scene_ray_cast(
normalize_v3(direction);
Depsgraph *depsgraph = BKE_scene_get_depsgraph(scene, view_layer, true);
- SnapObjectContext *sctx = ED_transform_snap_object_context_create(
- scene, depsgraph, 0);
+ SnapObjectContext *sctx = ED_transform_snap_object_context_create(bmain, scene, depsgraph, 0);
bool ret = ED_transform_snap_object_project_ray_ex(
sctx,
@@ -309,6 +308,7 @@ void RNA_api_scene(StructRNA *srna)
/* Ray Cast */
func = RNA_def_function(srna, "ray_cast", "rna_Scene_ray_cast");
+ RNA_def_function_flag(func, FUNC_USE_MAIN);
RNA_def_function_ui_description(func, "Cast a ray onto in object space");
parm = RNA_def_pointer(func, "view_layer", "ViewLayer", "", "Scene Layer");
RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
diff --git a/source/blender/makesrna/intern/rna_sculpt_paint.c b/source/blender/makesrna/intern/rna_sculpt_paint.c
index 12b080a9284..a26aceda3b9 100644
--- a/source/blender/makesrna/intern/rna_sculpt_paint.c
+++ b/source/blender/makesrna/intern/rna_sculpt_paint.c
@@ -162,6 +162,8 @@ static void rna_ParticleEdit_redo(bContext *C, PointerRNA *UNUSED(ptr))
if (!edit)
return;
+ if (ob) DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
+
BKE_particle_batch_cache_dirty(edit->psys, BKE_PARTICLE_BATCH_DIRTY_ALL);
psys_free_path_cache(edit->psys, edit);
DEG_id_tag_update(&CTX_data_scene(C)->id, DEG_TAG_COPY_ON_WRITE);
diff --git a/source/blender/makesrna/intern/rna_space.c b/source/blender/makesrna/intern/rna_space.c
index b36014370f6..3daf4ca6fe0 100644
--- a/source/blender/makesrna/intern/rna_space.c
+++ b/source/blender/makesrna/intern/rna_space.c
@@ -114,13 +114,6 @@ const EnumPropertyItem rna_enum_space_image_mode_items[] = {
{0, NULL, 0, NULL, NULL}
};
-/* Expanded into the Space.ui_type enum. */
-const EnumPropertyItem rna_enum_space_button_mode_items[] = {
- {SB_SUBTYPE_DATA, "DATA_PROPERTIES", ICON_BUTS, "Data Properties", "Edit properties of active object and related data-blocks"},
- {SB_SUBTYPE_TOOL, "TOOL_PROPERTIES", ICON_PREFERENCES, "Tool Properties", "Edit tool settings"},
- {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", ""},
@@ -194,46 +187,21 @@ const EnumPropertyItem rna_enum_shading_type_items[] = {
};
const EnumPropertyItem rna_enum_viewport_lighting_items[] = {
- {V3D_LIGHTING_FLAT, "FLAT", 0, "Flat Lighting", "Display using flat lighting"},
- {V3D_LIGHTING_STUDIO, "STUDIO", 0, "Studio Lighting", "Display using studio lighting"},
- /* {V3D_LIGHTING_SCENE, "SCENE", 0, "Scene Lighting", "Display using scene lighting"}, */
+ {V3D_LIGHTING_FLAT, "FLAT", 0, "Flat", "Display using flat lighting"},
+ {V3D_LIGHTING_STUDIO, "STUDIO", 0, "Studio", "Display using studio lighting"},
+ {V3D_LIGHTING_MATCAP, "MATCAP", 0, "MatCap", "Display using matcap material and lighting"},
{0, NULL, 0, NULL, NULL}
};
static const EnumPropertyItem rna_enum_studio_light_items[] = {
- {0, "STUDIOLIGHT_00", 0, "", ""},
- {1, "STUDIOLIGHT_01", 0, "", ""},
- {2, "STUDIOLIGHT_02", 0, "", ""},
- {3, "STUDIOLIGHT_03", 0, "", ""},
- {4, "STUDIOLIGHT_04", 0, "", ""},
- {5, "STUDIOLIGHT_05", 0, "", ""},
- {6, "STUDIOLIGHT_06", 0, "", ""},
- {7, "STUDIOLIGHT_07", 0, "", ""},
- {8, "STUDIOLIGHT_08", 0, "", ""},
- {9, "STUDIOLIGHT_09", 0, "", ""},
- {10, "STUDIOLIGHT_10", 0, "", ""},
- {11, "STUDIOLIGHT_11", 0, "", ""},
- {12, "STUDIOLIGHT_12", 0, "", ""},
- {13, "STUDIOLIGHT_13", 0, "", ""},
- {14, "STUDIOLIGHT_14", 0, "", ""},
- {15, "STUDIOLIGHT_15", 0, "", ""},
- {16, "STUDIOLIGHT_16", 0, "", ""},
- {17, "STUDIOLIGHT_17", 0, "", ""},
- {18, "STUDIOLIGHT_18", 0, "", ""},
- {19, "STUDIOLIGHT_19", 0, "", ""},
- {20, "STUDIOLIGHT_20", 0, "", ""},
- {21, "STUDIOLIGHT_21", 0, "", ""},
- {22, "STUDIOLIGHT_22", 0, "", ""},
- {23, "STUDIOLIGHT_23", 0, "", ""},
- {24, "STUDIOLIGHT_24", 0, "", ""},
- {25, "STUDIOLIGHT_25", 0, "", ""},
- {26, "STUDIOLIGHT_26", 0, "", ""},
- {27, "STUDIOLIGHT_27", 0, "", ""},
- {28, "STUDIOLIGHT_28", 0, "", ""},
- {29, "STUDIOLIGHT_29", 0, "", ""},
+ {0, "DEFAULT", 0, "Default", ""},
+ {0, NULL, 0, NULL, NULL}
+};
+
+static const EnumPropertyItem rna_enum_matcap_items[] = {
+ {0, "DEFAULT", 0, "Default", ""},
{0, NULL, 0, NULL, NULL}
};
-#define NUM_STUDIOLIGHT_ITEMS 30
const EnumPropertyItem rna_enum_clip_editor_mode_items[] = {
{SC_MODE_TRACKING, "TRACKING", ICON_ANIM_DATA, "Tracking", "Show tracking and solving tools"},
@@ -243,6 +211,7 @@ const EnumPropertyItem rna_enum_clip_editor_mode_items[] = {
/* Actually populated dynamically trough a function, but helps for context-less access (e.g. doc, i18n...). */
static const EnumPropertyItem buttons_context_items[] = {
+ {BCONTEXT_TOOL, "TOOL", ICON_PREFERENCES, "Tool", "Tool settings"},
{BCONTEXT_SCENE, "SCENE", ICON_SCENE_DATA, "Scene", "Scene"},
{BCONTEXT_RENDER, "RENDER", ICON_SCENE, "Render", "Render"},
{BCONTEXT_VIEW_LAYER, "VIEW_LAYER", ICON_RENDER_RESULT, "View Layer", "View layer"},
@@ -547,17 +516,6 @@ static void rna_3DViewShading_type_update(Main *bmain, Scene *UNUSED(scene), Poi
ED_view3d_shade_update(bmain, v3d, sa);
}
-static void rna_SpaceView3D_matcap_enable(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr)
-{
- View3D *v3d = (View3D *)(ptr->data);
-
- if (v3d->matcap_icon < ICON_MATCAP_01 ||
- v3d->matcap_icon > ICON_MATCAP_24)
- {
- v3d->matcap_icon = ICON_MATCAP_01;
- }
-}
-
static PointerRNA rna_SpaceView3D_region_3d_get(PointerRNA *ptr)
{
View3D *v3d = (View3D *)(ptr->data);
@@ -676,6 +634,9 @@ static void rna_3DViewShading_type_set(PointerRNA *ptr, int value)
if (value != v3d->drawtype && value == OB_RENDER) {
v3d->prev_drawtype = v3d->drawtype;
}
+ if (value == OB_TEXTURE && v3d->shading.light == V3D_LIGHTING_MATCAP) {
+ v3d->shading.light = V3D_LIGHTING_STUDIO;
+ }
v3d->drawtype = value;
}
@@ -713,17 +674,56 @@ static const EnumPropertyItem *rna_3DViewShading_type_itemf(
static int rna_View3DShading_studio_light_orientation_get(PointerRNA *ptr)
{
View3D *v3d = (View3D *)ptr->data;
- StudioLight *sl = BKE_studiolight_find(v3d->shading.studio_light, 0);
- return sl->flag & (STUDIOLIGHT_ORIENTATION_WORLD | STUDIOLIGHT_ORIENTATION_CAMERA);
+ StudioLight *sl = BKE_studiolight_find(v3d->shading.studio_light, STUDIOLIGHT_FLAG_ALL);
+ return sl->flag & STUDIOLIGHT_FLAG_ORIENTATIONS;
}
static void rna_View3DShading_studio_light_orientation_set(PointerRNA *UNUSED(ptr), int UNUSED(value))
{
}
+/* shading.light */
+static int rna_View3DShading_light_get(PointerRNA *ptr)
+{
+ View3D *v3d = (View3D *)ptr->data;
+ return v3d->shading.light;
+}
+
+static void rna_View3DShading_light_set(PointerRNA *ptr, int value)
+{
+ View3D *v3d = (View3D *)ptr->data;
+ v3d->shading.light = value;
+}
+
+static const EnumPropertyItem *rna_View3DShading_light_itemf(
+ bContext *UNUSED(C), PointerRNA *ptr,
+ PropertyRNA *UNUSED(prop), bool *r_free)
+{
+ View3D *v3d = (View3D *)ptr->data;
+
+ int totitem = 0;
+ EnumPropertyItem *item = NULL;
+
+ if (v3d->drawtype == OB_SOLID || v3d->drawtype == OB_TEXTURE) {
+ RNA_enum_items_add_value(&item, &totitem, rna_enum_viewport_lighting_items, V3D_LIGHTING_FLAT);
+ RNA_enum_items_add_value(&item, &totitem, rna_enum_viewport_lighting_items, V3D_LIGHTING_STUDIO);
+ }
+
+ if (v3d->drawtype == OB_SOLID) {
+ RNA_enum_items_add_value(&item, &totitem, rna_enum_viewport_lighting_items, V3D_LIGHTING_MATCAP);
+ }
+ RNA_enum_item_end(&item, &totitem);
+ *r_free = true;
+ return item;
+}
+
+/* Studio light */
static int rna_View3DShading_studio_light_get(PointerRNA *ptr)
{
View3D *v3d = (View3D *)ptr->data;
- const int flag = (v3d->drawtype == OB_MATERIAL) ? STUDIOLIGHT_ORIENTATION_WORLD : 0;
+ int flag = STUDIOLIGHT_ORIENTATIONS_SOLID;
+ if (v3d->drawtype == OB_MATERIAL) {
+ flag = STUDIOLIGHT_ORIENTATIONS_MATERIAL_MODE;
+ }
StudioLight *sl = BKE_studiolight_find(v3d->shading.studio_light, flag);
BLI_strncpy(v3d->shading.studio_light, sl->name, FILE_MAXFILE);
return sl->index;
@@ -732,7 +732,7 @@ static int rna_View3DShading_studio_light_get(PointerRNA *ptr)
static void rna_View3DShading_studio_light_set(PointerRNA *ptr, int value)
{
View3D *v3d = (View3D *)ptr->data;
- StudioLight *sl = BKE_studiolight_findindex(value);
+ StudioLight *sl = BKE_studiolight_findindex(value, STUDIOLIGHT_FLAG_ALL);
BLI_strncpy(v3d->shading.studio_light, sl->name, FILE_MAXFILE);
}
@@ -742,15 +742,13 @@ static const EnumPropertyItem *rna_View3DShading_studio_light_itemf(
{
View3D *v3d = (View3D *)ptr->data;
EnumPropertyItem *item = NULL;
- EnumPropertyItem *lastitem;
int totitem = 0;
- bool show_studiolight;
LISTBASE_FOREACH(StudioLight *, sl, BKE_studiolight_listbase()) {
- show_studiolight = false;
int icon_id = sl->irradiance_icon_id;
+ bool show_studiolight = false;
- if ((sl->flag & STUDIOLIGHT_EXTERNAL_FILE) == 0) {
+ if ((sl->flag & STUDIOLIGHT_INTERNAL)) {
/* always show internal lights */
show_studiolight = true;
}
@@ -758,8 +756,9 @@ static const EnumPropertyItem *rna_View3DShading_studio_light_itemf(
switch (v3d->drawtype) {
case OB_SOLID:
case OB_TEXTURE:
- show_studiolight = true;
+ show_studiolight = (sl->flag & (STUDIOLIGHT_ORIENTATION_WORLD | STUDIOLIGHT_ORIENTATION_CAMERA)) > 0;
break;
+
case OB_MATERIAL:
show_studiolight = (sl->flag & STUDIOLIGHT_ORIENTATION_WORLD) > 0;
icon_id = sl->radiance_icon_id;
@@ -767,12 +766,48 @@ static const EnumPropertyItem *rna_View3DShading_studio_light_itemf(
}
}
- if (show_studiolight && totitem < NUM_STUDIOLIGHT_ITEMS) {
- RNA_enum_items_add_value(&item, &totitem, rna_enum_studio_light_items, sl->index);
- lastitem = &item[totitem - 1];
- lastitem->value = sl->index;
- lastitem->icon = icon_id;
- lastitem->name = sl->name;
+ if (show_studiolight) {
+ EnumPropertyItem tmp = {sl->index, sl->name, icon_id, sl->name, ""};
+ RNA_enum_item_add(&item, &totitem, &tmp);
+ }
+ }
+
+ RNA_enum_item_end(&item, &totitem);
+ *r_free = true;
+ return item;
+}
+/* Matcap studiolight */
+static int rna_View3DShading_matcap_get(PointerRNA *ptr)
+{
+ View3D *v3d = (View3D *)ptr->data;
+ StudioLight *sl = BKE_studiolight_find(v3d->shading.matcap, STUDIOLIGHT_ORIENTATION_VIEWNORMAL);
+ BLI_strncpy(v3d->shading.matcap, sl->name, FILE_MAXFILE);
+ return sl->index;
+}
+
+static void rna_View3DShading_matcap_set(PointerRNA *ptr, int value)
+{
+ View3D *v3d = (View3D *)ptr->data;
+ StudioLight *sl = BKE_studiolight_findindex(value, STUDIOLIGHT_ORIENTATION_VIEWNORMAL);
+ BLI_strncpy(v3d->shading.matcap, sl->name, FILE_MAXFILE);
+}
+
+static const EnumPropertyItem *rna_View3DShading_matcap_itemf(
+ bContext *UNUSED(C), PointerRNA *UNUSED(ptr),
+ PropertyRNA *UNUSED(prop), bool *r_free)
+{
+ EnumPropertyItem *item = NULL;
+ int totitem = 0;
+
+ const int flags = (STUDIOLIGHT_EXTERNAL_FILE | STUDIOLIGHT_ORIENTATION_VIEWNORMAL);
+
+ LISTBASE_FOREACH(StudioLight *, sl, BKE_studiolight_listbase()) {
+ int icon_id = sl->irradiance_icon_id;
+ bool show_studiolight = (sl->flag & flags) == flags;
+
+ if (show_studiolight) {
+ EnumPropertyItem tmp = {sl->index, sl->name, icon_id, sl->name, ""};
+ RNA_enum_item_add(&item, &totitem, &tmp);
}
}
@@ -1141,6 +1176,10 @@ static const EnumPropertyItem *rna_SpaceProperties_context_itemf(
EnumPropertyItem *item = NULL;
int totitem = 0;
+ if (sbuts->pathflag & (1 << BCONTEXT_TOOL)) {
+ RNA_enum_items_add_value(&item, &totitem, buttons_context_items, BCONTEXT_TOOL);
+ }
+
if (sbuts->pathflag & (1 << BCONTEXT_RENDER)) {
RNA_enum_items_add_value(&item, &totitem, buttons_context_items, BCONTEXT_RENDER);
}
@@ -2261,9 +2300,10 @@ static void rna_def_space_view3d_shading(BlenderRNA *brna)
};
static const EnumPropertyItem studio_light_orientation_items[] = {
- {0, "UNKNOWN", 0, "Unknown", "Studio light has no orientation"},
- {STUDIOLIGHT_ORIENTATION_CAMERA, "CAMERA", 0, "Camera", "Studio light is camera based"},
- {STUDIOLIGHT_ORIENTATION_WORLD, "WORLD", 0, "World", "Studio light is world based"},
+ {0, "UNKNOWN", 0, "Unknown", "Studio light has no orientation"},
+ {STUDIOLIGHT_ORIENTATION_CAMERA, "CAMERA", 0, "Camera", "Studio light is camera based"},
+ {STUDIOLIGHT_ORIENTATION_WORLD, "WORLD", 0, "World", "Studio light is world based"},
+ {STUDIOLIGHT_ORIENTATION_VIEWNORMAL, "VIEWNORMAL", 0, "Matcap", "Studio light is a matcap"},
{0, NULL, 0, NULL, NULL}
};
@@ -2284,6 +2324,7 @@ static void rna_def_space_view3d_shading(BlenderRNA *brna)
prop = RNA_def_property(srna, "light", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "shading.light");
RNA_def_property_enum_items(prop, rna_enum_viewport_lighting_items);
+ RNA_def_property_enum_funcs(prop, "rna_View3DShading_light_get", "rna_View3DShading_light_set", "rna_View3DShading_light_itemf");
RNA_def_property_ui_text(prop, "Lighting", "Lighting Method for Solid/Texture Viewport Shading");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
@@ -2300,6 +2341,37 @@ static void rna_def_space_view3d_shading(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Studiolight", "Studio lighting setup");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
+ prop = RNA_def_property(srna, "matcap", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_items(prop, rna_enum_matcap_items);
+ RNA_def_property_enum_default(prop, 0);
+ RNA_def_property_enum_funcs(prop, "rna_View3DShading_matcap_get", "rna_View3DShading_matcap_set", "rna_View3DShading_matcap_itemf");
+ RNA_def_property_ui_text(prop, "Matcap", "Matcap material and lighting");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
+
+ prop = RNA_def_property(srna, "show_cavity", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "shading.flag", V3D_SHADING_CAVITY);
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+ RNA_def_property_ui_text(prop, "Cavity", "Show Cavity");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
+
+ prop = RNA_def_property(srna, "cavity_ridge_factor", PROP_FLOAT, PROP_FACTOR);
+ RNA_def_property_float_sdna(prop, NULL, "shading.cavity_ridge_factor");
+ RNA_def_property_float_default(prop, 1.0f);
+ RNA_def_property_ui_text(prop, "Ridge", "Factor for the ridges");
+ RNA_def_property_range(prop, 0.0f, 250.0f);
+ RNA_def_property_ui_range(prop, 0.00f, 2.5f, 1, 3);
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
+
+ prop = RNA_def_property(srna, "cavity_valley_factor", PROP_FLOAT, PROP_FACTOR);
+ RNA_def_property_float_sdna(prop, NULL, "shading.cavity_valley_factor");
+ RNA_def_property_float_default(prop, 1.0);
+ RNA_def_property_ui_text(prop, "Valley", "Factor for the valleys");
+ RNA_def_property_range(prop, 0.0f, 250.0f);
+ RNA_def_property_ui_range(prop, 0.00f, 2.5f, 1, 3);
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
+
prop = RNA_def_property(srna, "studio_light_orientation", PROP_ENUM, PROP_NONE);
RNA_define_verify_sdna(0);
RNA_def_property_enum_sdna(prop, NULL, "shading.flag");
@@ -2347,7 +2419,6 @@ static void rna_def_space_view3d_shading(BlenderRNA *brna)
RNA_def_property_float_default(prop, 0.5);
RNA_def_property_ui_text(prop, "X-Ray Alpha", "Amount of alpha to use");
RNA_def_property_range(prop, 0.0f, 1.0f);
- RNA_def_property_ui_range(prop, 0.04f, 1.0f, 1, 1);
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
@@ -2498,6 +2569,14 @@ static void rna_def_space_view3d_overlay(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Bone Selection", "Show the Bone Selection Overlay");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
+ prop = RNA_def_property(srna, "bone_selection_alpha", PROP_FLOAT, PROP_FACTOR);
+ RNA_def_property_float_sdna(prop, NULL, "overlay.bone_selection_alpha");
+ RNA_def_property_float_default(prop, 0.5f);
+ RNA_def_property_ui_text(prop, "Opacity", "Opacity to use for bone selection");
+ RNA_def_property_range(prop, 0.0f, 1.0f);
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
+
prop = RNA_def_property(srna, "show_motion_paths", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_negative_sdna(prop, NULL, "overlay.flag", V3D_OVERLAY_HIDE_MOTION_PATHS);
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
@@ -2516,6 +2595,14 @@ static void rna_def_space_view3d_overlay(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Wireframes", "Show face edges wires");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
+ prop = RNA_def_property(srna, "wireframe_threshold", PROP_FLOAT, PROP_FACTOR);
+ RNA_def_property_float_sdna(prop, NULL, "overlay.wireframe_threshold");
+ RNA_def_property_float_default(prop, 0.5f);
+ RNA_def_property_ui_text(prop, "Wireframe Threshold", "Adjust the number of wires displayed (1 for all wires)");
+ RNA_def_property_range(prop, 0.0f, 1.0f);
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
+
prop = RNA_def_property(srna, "show_paint_wire", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "overlay.paint_flag", V3D_OVERLAY_PAINT_WIRE);
RNA_def_property_ui_text(prop, "Show Wire", "Use wireframe display in painting modes");
@@ -2588,34 +2675,6 @@ static void rna_def_space_view3d(BlenderRNA *brna)
{0, NULL, 0, NULL, NULL}
};
- static const EnumPropertyItem view3d_matcap_items[] = {
- {ICON_MATCAP_01, "01", ICON_MATCAP_01, "", ""},
- {ICON_MATCAP_02, "02", ICON_MATCAP_02, "", ""},
- {ICON_MATCAP_03, "03", ICON_MATCAP_03, "", ""},
- {ICON_MATCAP_04, "04", ICON_MATCAP_04, "", ""},
- {ICON_MATCAP_05, "05", ICON_MATCAP_05, "", ""},
- {ICON_MATCAP_06, "06", ICON_MATCAP_06, "", ""},
- {ICON_MATCAP_07, "07", ICON_MATCAP_07, "", ""},
- {ICON_MATCAP_08, "08", ICON_MATCAP_08, "", ""},
- {ICON_MATCAP_09, "09", ICON_MATCAP_09, "", ""},
- {ICON_MATCAP_10, "10", ICON_MATCAP_10, "", ""},
- {ICON_MATCAP_11, "11", ICON_MATCAP_11, "", ""},
- {ICON_MATCAP_12, "12", ICON_MATCAP_12, "", ""},
- {ICON_MATCAP_13, "13", ICON_MATCAP_13, "", ""},
- {ICON_MATCAP_14, "14", ICON_MATCAP_14, "", ""},
- {ICON_MATCAP_15, "15", ICON_MATCAP_15, "", ""},
- {ICON_MATCAP_16, "16", ICON_MATCAP_16, "", ""},
- {ICON_MATCAP_17, "17", ICON_MATCAP_17, "", ""},
- {ICON_MATCAP_18, "18", ICON_MATCAP_18, "", ""},
- {ICON_MATCAP_19, "19", ICON_MATCAP_19, "", ""},
- {ICON_MATCAP_20, "20", ICON_MATCAP_20, "", ""},
- {ICON_MATCAP_21, "21", ICON_MATCAP_21, "", ""},
- {ICON_MATCAP_22, "22", ICON_MATCAP_22, "", ""},
- {ICON_MATCAP_23, "23", ICON_MATCAP_23, "", ""},
- {ICON_MATCAP_24, "24", ICON_MATCAP_24, "", ""},
- {0, NULL, 0, NULL, NULL}
- };
-
srna = RNA_def_struct(brna, "SpaceView3D", "Space");
RNA_def_struct_sdna(srna, "View3D");
RNA_def_struct_ui_text(srna, "3D View Space", "3D View space data");
@@ -2832,17 +2891,6 @@ static void rna_def_space_view3d(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Show 3D Marker Names", "Show names for reconstructed tracks objects");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
- prop = RNA_def_property(srna, "use_matcap", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag2", V3D_SOLID_MATCAP);
- RNA_def_property_ui_text(prop, "Matcap", "Active Objects draw images mapped on normals, enhancing Solid Draw Mode");
- RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, "rna_SpaceView3D_matcap_enable");
-
- prop = RNA_def_property(srna, "matcap_icon", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_sdna(prop, NULL, "matcap_icon");
- RNA_def_property_enum_items(prop, view3d_matcap_items);
- RNA_def_property_ui_text(prop, "Matcap", "Image to use for Material Capture, active objects only");
- RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
-
prop = RNA_def_property(srna, "fx_settings", PROP_POINTER, PROP_NONE);
RNA_def_property_ui_text(prop, "FX Options", "Options used for real time compositing");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
@@ -3026,13 +3074,6 @@ static void rna_def_space_buttons(BlenderRNA *brna)
RNA_def_struct_sdna(srna, "SpaceButs");
RNA_def_struct_ui_text(srna, "Properties Space", "Properties space data");
- /* Not exposed to the UI (access via space-type selector). */
- prop = RNA_def_property(srna, "mode", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_sdna(prop, NULL, "space_subtype");
- RNA_def_property_enum_items(prop, rna_enum_space_button_mode_items);
- RNA_def_property_ui_text(prop, "Mode", "Arrangement of the panels");
- RNA_def_property_update(prop, NC_SPACE | ND_SPACE_PROPERTIES, NULL);
-
prop = RNA_def_property(srna, "context", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "mainb");
RNA_def_property_enum_items(prop, buttons_context_items);
diff --git a/source/blender/makesrna/intern/rna_ui.c b/source/blender/makesrna/intern/rna_ui.c
index 354fa43367e..ce1f9efcf63 100644
--- a/source/blender/makesrna/intern/rna_ui.c
+++ b/source/blender/makesrna/intern/rna_ui.c
@@ -302,8 +302,8 @@ static StructRNA *rna_Panel_register(
static StructRNA *rna_Panel_refine(PointerRNA *ptr)
{
- Panel *hdr = (Panel *)ptr->data;
- return (hdr->type && hdr->type->ext.srna) ? hdr->type->ext.srna : &RNA_Panel;
+ Panel *menu = (Panel *)ptr->data;
+ return (menu->type && menu->type->ext.srna) ? menu->type->ext.srna : &RNA_Panel;
}
/* UIList */
@@ -696,7 +696,7 @@ static int menu_poll(const bContext *C, MenuType *pt)
return visible;
}
-static void menu_draw(const bContext *C, Menu *hdr)
+static void menu_draw(const bContext *C, Menu *menu)
{
extern FunctionRNA rna_Menu_draw_func;
@@ -704,12 +704,12 @@ static void menu_draw(const bContext *C, Menu *hdr)
ParameterList list;
FunctionRNA *func;
- RNA_pointer_create(&CTX_wm_screen(C)->id, hdr->type->ext.srna, hdr, &mtr);
+ RNA_pointer_create(&CTX_wm_screen(C)->id, menu->type->ext.srna, menu, &mtr);
func = &rna_Menu_draw_func; /* RNA_struct_find_function(&mtr, "draw"); */
RNA_parameter_list_create(&list, &mtr, func);
RNA_parameter_set_lookup(&list, "context", &C);
- hdr->type->ext.call((bContext *)C, &mtr, func, &list);
+ menu->type->ext.call((bContext *)C, &mtr, func, &list);
RNA_parameter_list_free(&list);
}
@@ -818,8 +818,8 @@ static StructRNA *rna_Menu_register(
static StructRNA *rna_Menu_refine(PointerRNA *mtr)
{
- Menu *hdr = (Menu *)mtr->data;
- return (hdr->type && hdr->type->ext.srna) ? hdr->type->ext.srna : &RNA_Menu;
+ Menu *menu = (Menu *)mtr->data;
+ return (menu->type && menu->type->ext.srna) ? menu->type->ext.srna : &RNA_Menu;
}
static void rna_Menu_bl_description_set(PointerRNA *ptr, const char *value)
diff --git a/source/blender/makesrna/intern/rna_userdef.c b/source/blender/makesrna/intern/rna_userdef.c
index fc7a0ca6301..1cd3a8b83d7 100644
--- a/source/blender/makesrna/intern/rna_userdef.c
+++ b/source/blender/makesrna/intern/rna_userdef.c
@@ -41,6 +41,7 @@
#include "BKE_DerivedMesh.h"
#include "BKE_sound.h"
#include "BKE_addon.h"
+#include "BKE_studiolight.h"
#include "RNA_access.h"
#include "RNA_define.h"
@@ -77,6 +78,12 @@ const EnumPropertyItem rna_enum_navigation_mode_items[] = {
{0, NULL, 0, NULL, NULL}
};
+static const EnumPropertyItem rna_enum_studio_light_icons_id_items[] = {
+ {0, "DEFAULT", 0, "Default", ""},
+ {0, NULL, 0, NULL, NULL}
+};
+
+
#if defined(WITH_INTERNATIONAL) || !defined(RNA_RUNTIME)
static const EnumPropertyItem rna_enum_language_default_items[] = {
{0, "DEFAULT", 0, "Default (Default)", ""},
@@ -653,6 +660,117 @@ static void rna_ThemeUI_roundness_set(PointerRNA *ptr, float value)
tui->roundness = value * 0.5f;
}
+/* Studio Light */
+static void rna_UserDef_studiolight_begin(CollectionPropertyIterator *iter, PointerRNA *UNUSED(ptr))
+{
+ rna_iterator_listbase_begin(iter, BKE_studiolight_listbase(), NULL);
+}
+
+static void rna_UserDef_studiolight_refresh(UserDef *UNUSED(userdef))
+{
+ BKE_studiolight_refresh();
+}
+
+/* StudioLight.name */
+static void rna_UserDef_studiolight_name_get(PointerRNA *ptr, char *value)
+{
+ StudioLight *sl = (StudioLight *)ptr->data;
+ BLI_strncpy(value, sl->name, FILE_MAXFILE);
+}
+
+static int rna_UserDef_studiolight_name_length(PointerRNA *ptr)
+{
+ StudioLight *sl = (StudioLight *)ptr->data;
+ return strlen(sl->name);
+}
+
+/* StudioLight.path */
+static void rna_UserDef_studiolight_path_get(PointerRNA *ptr, char *value)
+{
+ StudioLight *sl = (StudioLight *)ptr->data;
+ BLI_strncpy(value, sl->path, FILE_MAX);
+}
+
+static int rna_UserDef_studiolight_path_length(PointerRNA *ptr)
+{
+ StudioLight *sl = (StudioLight *)ptr->data;
+ return strlen(sl->path);
+}
+
+/* StudioLight.index */
+static int rna_UserDef_studiolight_index_get(PointerRNA *ptr)
+{
+ StudioLight *sl = (StudioLight *)ptr->data;
+ return sl->index;
+}
+
+/* StudioLight.icon_id */
+static int rna_UserDef_studiolight_icon_id_get(PointerRNA *ptr)
+{
+ StudioLight *sl = (StudioLight *)ptr->data;
+ if (sl->flag & (STUDIOLIGHT_ORIENTATION_VIEWNORMAL | STUDIOLIGHT_ORIENTATION_CAMERA)) {
+ return 1;
+ }
+ return 0;
+}
+
+static const EnumPropertyItem *rna_UserDef_studiolight_icon_id_itemf(
+ bContext *UNUSED(C), PointerRNA *ptr,
+ PropertyRNA *UNUSED(prop), bool *r_free)
+{
+ EnumPropertyItem *item = NULL;
+ int totitem = 0;
+ StudioLight *sl = (StudioLight *)ptr->data;
+
+ if ((sl->flag & (STUDIOLIGHT_ORIENTATION_VIEWNORMAL | STUDIOLIGHT_ORIENTATION_CAMERA)) == 0)
+ {
+ EnumPropertyItem tmp = {0, sl->name, sl->radiance_icon_id, sl->name, ""};
+ RNA_enum_item_add(&item, &totitem, &tmp);
+ }
+ {
+ EnumPropertyItem tmp = {1, sl->name, sl->irradiance_icon_id, sl->name, ""};
+ RNA_enum_item_add(&item, &totitem, &tmp);
+ }
+ RNA_enum_item_end(&item, &totitem);
+ *r_free = true;
+ return item;
+}
+
+/* StudioLight.is_user_defined */
+static int rna_UserDef_studiolight_is_user_defined_get(PointerRNA *ptr)
+{
+ StudioLight *sl = (StudioLight *)ptr->data;
+ return (sl->flag & STUDIOLIGHT_USER_DEFINED) > 0;
+}
+
+/* StudioLight.show_expanded */
+static int rna_UserDef_studiolight_show_expanded_get(PointerRNA *ptr)
+{
+ StudioLight *sl = (StudioLight *)ptr->data;
+ return (sl->flag & STUDIOLIGHT_UI_EXPANDED) > 0;
+}
+
+static void rna_UserDef_studiolight_show_expanded_set(PointerRNA *ptr, const bool value)
+{
+ StudioLight *sl = (StudioLight *)ptr->data;
+ sl->flag ^= STUDIOLIGHT_UI_EXPANDED;
+ sl->flag |= value?STUDIOLIGHT_UI_EXPANDED: 0;
+}
+
+
+/* StudioLight.orientation */
+
+static int rna_UserDef_studiolight_orientation_get(PointerRNA *ptr)
+{
+ StudioLight *sl = (StudioLight *)ptr->data;
+ return sl->flag & STUDIOLIGHT_FLAG_ORIENTATIONS;
+}
+
+static void rna_UserDef_studiolight_orientation_set(PointerRNA *UNUSED(ptr), const int UNUSED(value))
+{
+}
+
+
#else
/* TODO(sergey): This technically belongs to blenlib, but we don't link
@@ -3161,6 +3279,63 @@ static void rna_def_userdef_addon(BlenderRNA *brna)
RNA_def_property_pointer_funcs(prop, "rna_Addon_preferences_get", NULL, NULL, NULL);
}
+static void rna_def_userdef_studiolight(BlenderRNA *brna)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ static const EnumPropertyItem rna_enum_studio_light_orientation_items[] = {
+ {STUDIOLIGHT_ORIENTATION_CAMERA, "CAMERA", 0, "Camera", ""},
+ {STUDIOLIGHT_ORIENTATION_WORLD, "WORLD", 0, "World", ""},
+ {STUDIOLIGHT_ORIENTATION_VIEWNORMAL, "MATCAP", 0, "MatCap", ""},
+ {0, NULL, 0, NULL, NULL}
+ };
+
+ RNA_define_verify_sdna(false);
+ srna = RNA_def_struct(brna, "StudioLight", NULL);
+ RNA_def_struct_clear_flag(srna, STRUCT_UNDO);
+ RNA_def_struct_ui_text(srna, "Studio Light", "Studio light");
+
+ prop = RNA_def_property(srna, "index", PROP_INT, PROP_NONE);
+ RNA_def_property_int_funcs(prop, "rna_UserDef_studiolight_index_get", NULL, NULL);
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_ui_text(prop, "Index", "");
+
+ prop = RNA_def_property(srna, "is_user_defined", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_funcs(prop, "rna_UserDef_studiolight_is_user_defined_get", NULL);
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_ui_text(prop, "User Defined", "");
+
+ prop = RNA_def_property(srna, "show_expanded", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_funcs(prop, "rna_UserDef_studiolight_show_expanded_get", "rna_UserDef_studiolight_show_expanded_set");
+ RNA_def_property_ui_text(prop, "Show Expanded", "");
+
+ prop = RNA_def_property(srna, "orientation", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_items(prop, rna_enum_studio_light_orientation_items);
+ RNA_def_property_enum_funcs(prop, "rna_UserDef_studiolight_orientation_get", "rna_UserDef_studiolight_orientation_set", NULL);
+ RNA_def_property_ui_text(prop, "Orientation", "");
+
+ prop = RNA_def_property(srna, "icon_id", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_funcs(prop, "rna_UserDef_studiolight_icon_id_get", NULL, "rna_UserDef_studiolight_icon_id_itemf");
+ RNA_def_property_enum_items(prop, rna_enum_studio_light_icons_id_items);
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_ui_text(prop, "Preview", "Preview of the studiolight");
+
+ prop = RNA_def_property(srna, "name", PROP_STRING, PROP_NONE);
+ RNA_def_property_string_funcs(prop, "rna_UserDef_studiolight_name_get", "rna_UserDef_studiolight_name_length", NULL);
+ RNA_def_property_ui_text(prop, "Name", "");
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_struct_name_property(srna, prop);
+
+ prop = RNA_def_property(srna, "path", PROP_STRING, PROP_DIRPATH);
+ RNA_def_property_string_funcs(prop, "rna_UserDef_studiolight_path_get", "rna_UserDef_studiolight_path_length", NULL);
+ RNA_def_property_ui_text(prop, "Path", "");
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+
+ RNA_define_verify_sdna(true);
+
+}
+
static void rna_def_userdef_pathcompare(BlenderRNA *brna)
{
StructRNA *srna;
@@ -4665,6 +4840,7 @@ void RNA_def_userdef(BlenderRNA *brna)
{
StructRNA *srna;
PropertyRNA *prop;
+ FunctionRNA *func;
static const EnumPropertyItem user_pref_sections[] = {
{USER_SECTION_INTERFACE, "INTERFACE", 0, "Interface", ""},
@@ -4672,6 +4848,7 @@ void RNA_def_userdef(BlenderRNA *brna)
{USER_SECTION_INPUT, "INPUT", 0, "Input", ""},
{USER_SECTION_ADDONS, "ADDONS", 0, "Add-ons", ""},
{USER_SECTION_THEME, "THEMES", 0, "Themes", ""},
+ {USER_SECTION_LIGHT, "LIGHTS", 0, "Lights", ""},
{USER_SECTION_FILE, "FILES", 0, "File", ""},
{USER_SECTION_SYSTEM, "SYSTEM", 0, "System", ""},
{0, NULL, 0, NULL, NULL}
@@ -4757,6 +4934,17 @@ void RNA_def_userdef(BlenderRNA *brna)
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_def_property_flag(prop, PROP_THICK_WRAP);
+ prop = RNA_def_property(srna, "studio_lights", PROP_COLLECTION, PROP_NONE);
+ RNA_def_property_struct_type(prop, "StudioLight");
+ RNA_def_property_collection_funcs(prop, "rna_UserDef_studiolight_begin", "rna_iterator_listbase_next",
+ "rna_iterator_listbase_end", "rna_iterator_listbase_get",
+ NULL, NULL, NULL, NULL);
+
+ func = RNA_def_function(srna, "studio_lights_refresh", "rna_UserDef_studiolight_refresh");
+ RNA_def_function_ui_description(func, "Refresh Studio Lights");
+
+ RNA_def_property_ui_text(prop, "Studio Lights", "");
+
rna_def_userdef_view(brna);
rna_def_userdef_edit(brna);
rna_def_userdef_input(brna);
@@ -4764,6 +4952,7 @@ void RNA_def_userdef(BlenderRNA *brna)
rna_def_userdef_system(brna);
rna_def_userdef_addon(brna);
rna_def_userdef_addon_pref(brna);
+ rna_def_userdef_studiolight(brna);
rna_def_userdef_pathcompare(brna);
}
diff --git a/source/blender/makesrna/intern/rna_wm.c b/source/blender/makesrna/intern/rna_wm.c
index 0fa7f53da9b..3aa59ca564f 100644
--- a/source/blender/makesrna/intern/rna_wm.c
+++ b/source/blender/makesrna/intern/rna_wm.c
@@ -53,6 +53,7 @@ static const EnumPropertyItem event_keymouse_value_items[] = {
{KM_RELEASE, "RELEASE", 0, "Release", ""},
{KM_CLICK, "CLICK", 0, "Click", ""},
{KM_DBL_CLICK, "DOUBLE_CLICK", 0, "Double Click", ""},
+ {KM_CLICK_DRAG, "CLICK_DRAG", 0, "Click Drag", ""},
{0, NULL, 0, NULL, NULL}
};
@@ -391,6 +392,7 @@ const EnumPropertyItem rna_enum_event_value_items[] = {
{KM_RELEASE, "RELEASE", 0, "Release", ""},
{KM_CLICK, "CLICK", 0, "Click", ""},
{KM_DBL_CLICK, "DOUBLE_CLICK", 0, "Double Click", ""},
+ {KM_CLICK_DRAG, "CLICK_DRAG", 0, "Click Drag", ""},
{EVT_GESTURE_N, "NORTH", 0, "North", ""},
{EVT_GESTURE_NE, "NORTH_EAST", 0, "North-East", ""},
{EVT_GESTURE_E, "EAST", 0, "East", ""},
diff --git a/source/blender/modifiers/intern/MOD_collision.c b/source/blender/modifiers/intern/MOD_collision.c
index 036954a2774..71022f8a4ab 100644
--- a/source/blender/modifiers/intern/MOD_collision.c
+++ b/source/blender/modifiers/intern/MOD_collision.c
@@ -45,6 +45,7 @@
#include "BKE_global.h"
#include "BKE_library.h"
#include "BKE_mesh.h"
+#include "BKE_mesh_runtime.h"
#include "BKE_modifier.h"
#include "BKE_pointcache.h"
#include "BKE_scene.h"
diff --git a/source/blender/modifiers/intern/MOD_laplaciandeform.c b/source/blender/modifiers/intern/MOD_laplaciandeform.c
index ae4eb042444..63b4e950697 100644
--- a/source/blender/modifiers/intern/MOD_laplaciandeform.c
+++ b/source/blender/modifiers/intern/MOD_laplaciandeform.c
@@ -38,8 +38,8 @@
#include "BKE_deform.h"
#include "BKE_editmesh.h"
#include "BKE_library.h"
-#include "BKE_mesh.h"
#include "BKE_mesh_mapping.h"
+#include "BKE_mesh_runtime.h"
#include "BKE_particle.h"
#include "DNA_mesh_types.h"
diff --git a/source/blender/modifiers/intern/MOD_meshsequencecache.c b/source/blender/modifiers/intern/MOD_meshsequencecache.c
index 595b91f25a2..abd84799457 100644
--- a/source/blender/modifiers/intern/MOD_meshsequencecache.c
+++ b/source/blender/modifiers/intern/MOD_meshsequencecache.c
@@ -31,13 +31,13 @@
#include "DNA_scene_types.h"
#include "BKE_cachefile.h"
-#include "BKE_DerivedMesh.h"
#include "BKE_cdderivedmesh.h"
#include "BKE_library.h"
#include "BKE_library_query.h"
#include "BKE_scene.h"
#include "DEG_depsgraph_build.h"
+#include "DEG_depsgraph_query.h"
#include "MOD_modifiertypes.h"
@@ -87,23 +87,23 @@ static bool isDisabled(ModifierData *md, int UNUSED(useRenderParams))
return (mcmd->cache_file == NULL) || (mcmd->object_path[0] == '\0');
}
-static DerivedMesh *applyModifier(
+static Mesh *applyModifier(
ModifierData *md, const ModifierEvalContext *ctx,
- DerivedMesh *dm)
+ Mesh *mesh)
{
#ifdef WITH_ALEMBIC
MeshSeqCacheModifierData *mcmd = (MeshSeqCacheModifierData *) md;
/* Only used to check whether we are operating on org data or not... */
Mesh *me = (ctx->object->type == OB_MESH) ? ctx->object->data : NULL;
- DerivedMesh *org_dm = dm;
+ Mesh *org_mesh = mesh;
- Scene *scene = md->scene;
- const float frame = BKE_scene_frame_get(scene);
+ Scene *scene = md->scene; /* for FPS macro */
+ const float frame = DEG_get_ctime(ctx->depsgraph);
const float time = BKE_cachefile_time_offset(mcmd->cache_file, frame, FPS);
const char *err_str = NULL;
- CacheFile *cache_file = mcmd->cache_file;
+ CacheFile *cache_file = (CacheFile *)DEG_get_original_id(&mcmd->cache_file->id);
BKE_cachefile_ensure_handle(G.main, cache_file);
@@ -114,39 +114,44 @@ static DerivedMesh *applyModifier(
mcmd->object_path);
if (!mcmd->reader) {
modifier_setError(md, "Could not create Alembic reader for file %s", cache_file->filepath);
- return dm;
+ return mesh;
}
}
if (me != NULL) {
- MVert *mvert = dm->getVertArray(dm);
- MEdge *medge = dm->getEdgeArray(dm);
- MPoly *mpoly = dm->getPolyArray(dm);
+ MVert *mvert = mesh->mvert;
+ MEdge *medge = mesh->medge;
+ MPoly *mpoly = mesh->mpoly;
if ((me->mvert == mvert) || (me->medge == medge) || (me->mpoly == mpoly)) {
/* We need to duplicate data here, otherwise we'll modify org mesh, see T51701. */
- dm = CDDM_copy(dm);
+ BKE_id_copy_ex(NULL, &mesh->id, (ID **)&mesh,
+ LIB_ID_CREATE_NO_MAIN |
+ LIB_ID_CREATE_NO_USER_REFCOUNT |
+ LIB_ID_CREATE_NO_DEG_TAG |
+ LIB_ID_COPY_NO_PREVIEW,
+ false);
}
}
- DerivedMesh *result = ABC_read_mesh(mcmd->reader,
- ctx->object,
- dm,
- time,
- &err_str,
- mcmd->read_flag);
+ Mesh *result = ABC_read_mesh(mcmd->reader,
+ ctx->object,
+ mesh,
+ time,
+ &err_str,
+ mcmd->read_flag);
if (err_str) {
modifier_setError(md, "%s", err_str);
}
- if (!ELEM(result, NULL, dm) && (dm != org_dm)) {
- dm->release(dm);
- dm = org_dm;
+ if (!ELEM(result, NULL, mesh) && (mesh != org_mesh)) {
+ BKE_id_free(NULL, mesh);
+ mesh = org_mesh;
}
- return result ? result : dm;
+ return result ? result : mesh;
#else
- return dm;
+ return mesh;
UNUSED_VARS(ctx, md);
#endif
}
@@ -190,14 +195,14 @@ ModifierTypeInfo modifierType_MeshSequenceCache = {
/* deformMatrices_DM */ NULL,
/* deformVertsEM_DM */ NULL,
/* deformMatricesEM_DM*/NULL,
- /* applyModifier_DM */ applyModifier,
+ /* applyModifier_DM */ NULL,
/* applyModifierEM_DM */NULL,
/* deformVerts */ NULL,
/* deformMatrices */ NULL,
/* deformVertsEM */ NULL,
/* deformMatricesEM */ NULL,
- /* applyModifier */ NULL,
+ /* applyModifier */ applyModifier,
/* applyModifierEM */ NULL,
/* initData */ initData,
diff --git a/source/blender/modifiers/intern/MOD_particleinstance.c b/source/blender/modifiers/intern/MOD_particleinstance.c
index eee7f0c5561..0aafcf33202 100644
--- a/source/blender/modifiers/intern/MOD_particleinstance.c
+++ b/source/blender/modifiers/intern/MOD_particleinstance.c
@@ -149,7 +149,7 @@ static bool particle_skip(ParticleInstanceModifierData *pimd, ParticleSystem *ps
if (p >= psys->totpart) {
ChildParticle *cpa = psys->child + (p - psys->totpart);
- pa = psys->particles + (between? cpa->pa[0]: cpa->parent);
+ pa = psys->particles + (between ? cpa->pa[0] : cpa->parent);
}
else {
pa = psys->particles + p;
@@ -173,8 +173,8 @@ static bool particle_skip(ParticleInstanceModifierData *pimd, ParticleSystem *ps
/* TODO make randomization optional? */
randp = (int)(psys_frand(psys, 3578 + p) * totpart) % totpart;
- minp = (int)(totpart * pimd->particle_offset) % (totpart+1);
- maxp = (int)(totpart * (pimd->particle_offset + pimd->particle_amount)) % (totpart+1);
+ minp = (int)(totpart * pimd->particle_offset) % (totpart + 1);
+ maxp = (int)(totpart * (pimd->particle_offset + pimd->particle_amount)) % (totpart + 1);
if (maxp > minp) {
return randp < minp || randp >= maxp;
@@ -340,7 +340,7 @@ static Mesh *applyModifier(
for (p = part_start, p_skip = 0; p < part_end; p++) {
float prev_dir[3];
float frame[4]; /* frame orientation quaternion */
- float p_random = psys_frand(psys, 77091 + 283*p);
+ float p_random = psys_frand(psys, 77091 + 283 * p);
/* skip particle? */
if (particle_skip(pimd, psys, p))
@@ -404,7 +404,7 @@ static Mesh *applyModifier(
pa = psys->particles + p;
else {
ChildParticle *cpa = psys->child + (p - psys->totpart);
- pa = psys->particles + (between? cpa->pa[0]: cpa->parent);
+ pa = psys->particles + (between ? cpa->pa[0] : cpa->parent);
}
psys_mat_hair_to_global(sim.ob, sim.psmd->mesh_final, sim.psys->part->from, pa, hairmat);
copy_m3_m4(mat, hairmat);
@@ -412,7 +412,7 @@ static Mesh *applyModifier(
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 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];
diff --git a/source/blender/modifiers/intern/MOD_remesh.c b/source/blender/modifiers/intern/MOD_remesh.c
index eff343a4906..df607c04164 100644
--- a/source/blender/modifiers/intern/MOD_remesh.c
+++ b/source/blender/modifiers/intern/MOD_remesh.c
@@ -38,6 +38,7 @@
#include "MOD_modifiertypes.h"
#include "BKE_mesh.h"
+#include "BKE_mesh_runtime.h"
#include <assert.h>
#include <stdlib.h>
diff --git a/source/blender/modifiers/intern/MOD_surfacedeform.c b/source/blender/modifiers/intern/MOD_surfacedeform.c
index c75f317e3bc..e964da0a8d1 100644
--- a/source/blender/modifiers/intern/MOD_surfacedeform.c
+++ b/source/blender/modifiers/intern/MOD_surfacedeform.c
@@ -9,7 +9,7 @@
#include "BLI_task.h"
#include "BKE_bvhutils.h"
-#include "BKE_mesh.h"
+#include "BKE_mesh_runtime.h"
#include "BKE_editmesh.h"
#include "BKE_library.h"
#include "BKE_library_query.h"
diff --git a/source/blender/nodes/composite/node_composite_tree.c b/source/blender/nodes/composite/node_composite_tree.c
index 87b60543853..2c123fdbf7e 100644
--- a/source/blender/nodes/composite/node_composite_tree.c
+++ b/source/blender/nodes/composite/node_composite_tree.c
@@ -59,7 +59,7 @@
static void composite_get_from_context(const bContext *C, bNodeTreeType *UNUSED(treetype), bNodeTree **r_ntree, ID **r_id, ID **r_from)
{
Scene *scene = CTX_data_scene(C);
-
+
*r_from = NULL;
*r_id = &scene->id;
*r_ntree = scene->nodetree;
@@ -83,7 +83,7 @@ static void foreach_nodeclass(Scene *UNUSED(scene), void *calldata, bNodeClassCa
static void free_node_cache(bNodeTree *UNUSED(ntree), bNode *node)
{
bNodeSocket *sock;
-
+
for (sock = node->outputs.first; sock; sock = sock->next) {
if (sock->cache) {
sock->cache = NULL;
@@ -103,15 +103,15 @@ static void localize(bNodeTree *UNUSED(localtree), bNodeTree *ntree)
{
bNode *node;
bNodeSocket *sock;
-
+
for (node = ntree->nodes.first; node; node = node->next) {
/* ensure new user input gets handled ok */
node->need_exec = 0;
node->new_node->original = node;
-
+
/* move over the compbufs */
/* right after ntreeCopyTree() oldsock pointers are valid */
-
+
if (ELEM(node->type, CMP_NODE_VIEWER, CMP_NODE_SPLITVIEWER)) {
if (node->id) {
if (node->flag & NODE_DO_OUTPUT)
@@ -120,7 +120,7 @@ static void localize(bNodeTree *UNUSED(localtree), bNodeTree *ntree)
node->new_node->id = NULL;
}
}
-
+
for (sock = node->outputs.first; sock; sock = sock->next) {
sock->new_sock->cache = sock->cache;
sock->cache = NULL;
@@ -138,10 +138,10 @@ static void local_merge(bNodeTree *localtree, bNodeTree *ntree)
{
bNode *lnode;
bNodeSocket *lsock;
-
+
/* move over the compbufs and previews */
BKE_node_preview_merge_tree(ntree, localtree, true);
-
+
for (lnode = localtree->nodes.first; lnode; lnode = lnode->next) {
if (ntreeNodeExists(ntree, lnode->new_node)) {
if (ELEM(lnode->type, CMP_NODE_VIEWER, CMP_NODE_SPLITVIEWER)) {
@@ -161,7 +161,7 @@ static void local_merge(bNodeTree *localtree, bNodeTree *ntree)
lnode->new_node->storage = BKE_tracking_distortion_copy(lnode->storage);
}
}
-
+
for (lsock = lnode->outputs.first; lsock; lsock = lsock->next) {
if (ntreeOutputExists(lnode->new_node, lsock->new_sock)) {
lsock->new_sock->cache = lsock->cache;
@@ -176,9 +176,9 @@ static void local_merge(bNodeTree *localtree, bNodeTree *ntree)
static void update(bNodeTree *ntree)
{
ntreeSetOutput(ntree);
-
+
ntree_update_reroute_nodes(ntree);
-
+
if (ntree->update & NTREE_UPDATE_NODES) {
/* clean up preview cache, in case nodes have been removed */
BKE_node_preview_remove_unused(ntree);
@@ -187,12 +187,12 @@ static void update(bNodeTree *ntree)
static void composite_node_add_init(bNodeTree *UNUSED(bnodetree), bNode *bnode)
{
- /* Composite node will only show previews for input classes
- * by default, other will be hidden
+ /* Composite node will only show previews for input classes
+ * by default, other will be hidden
* but can be made visible with the show_preview option */
if (bnode->typeinfo->nclass != NODE_CLASS_INPUT) {
bnode->flag &= ~NODE_PREVIEW;
- }
+ }
}
bNodeTreeType *ntreeType_Composite;
@@ -200,13 +200,13 @@ bNodeTreeType *ntreeType_Composite;
void register_node_tree_type_cmp(void)
{
bNodeTreeType *tt = ntreeType_Composite = MEM_callocN(sizeof(bNodeTreeType), "compositor node tree type");
-
+
tt->type = NTREE_COMPOSIT;
strcpy(tt->idname, "CompositorNodeTree");
strcpy(tt->ui_name, "Compositing");
tt->ui_icon = 0; /* defined in drawnode.c */
strcpy(tt->ui_description, "Compositing nodes");
-
+
tt->free_cache = free_cache;
tt->free_node_cache = free_node_cache;
tt->foreach_nodeclass = foreach_nodeclass;
@@ -216,9 +216,9 @@ void register_node_tree_type_cmp(void)
tt->update = update;
tt->get_from_context = composite_get_from_context;
tt->node_add_init = composite_node_add_init;
-
+
tt->ext.srna = &RNA_CompositorNodeTree;
-
+
ntreeTypeAdd(tt);
}
diff --git a/source/blender/nodes/composite/node_composite_util.c b/source/blender/nodes/composite/node_composite_util.c
index faf3d994bf9..022794e8d42 100644
--- a/source/blender/nodes/composite/node_composite_util.c
+++ b/source/blender/nodes/composite/node_composite_util.c
@@ -52,7 +52,7 @@ void cmp_node_update_default(bNodeTree *UNUSED(ntree), bNode *node)
void cmp_node_type_base(bNodeType *ntype, int type, const char *name, short nclass, short flag)
{
node_type_base(ntype, type, name, nclass, flag);
-
+
ntype->poll = cmp_node_poll_default;
ntype->updatefunc = cmp_node_update_default;
ntype->insert_link = node_insert_link_default;
diff --git a/source/blender/nodes/composite/nodes/node_composite_bokehblur.c b/source/blender/nodes/composite/nodes/node_composite_bokehblur.c
index 503d1ad9a9d..acb5d100b0a 100644
--- a/source/blender/nodes/composite/nodes/node_composite_bokehblur.c
+++ b/source/blender/nodes/composite/nodes/node_composite_bokehblur.c
@@ -60,6 +60,6 @@ void register_node_type_cmp_bokehblur(void)
cmp_node_type_base(&ntype, CMP_NODE_BOKEHBLUR, "Bokeh Blur", NODE_CLASS_OP_FILTER, 0);
node_type_socket_templates(&ntype, cmp_node_bokehblur_in, cmp_node_bokehblur_out);
node_type_init(&ntype, node_composit_init_bokehblur);
-
+
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/composite/nodes/node_composite_bokehimage.c b/source/blender/nodes/composite/nodes/node_composite_bokehimage.c
index 1473212f8e1..04cdd3367e6 100644
--- a/source/blender/nodes/composite/nodes/node_composite_bokehimage.c
+++ b/source/blender/nodes/composite/nodes/node_composite_bokehimage.c
@@ -54,7 +54,7 @@ static void node_composit_init_bokehimage(bNodeTree *UNUSED(ntree), bNode *node)
void register_node_type_cmp_bokehimage(void)
{
static bNodeType ntype;
-
+
cmp_node_type_base(&ntype, CMP_NODE_BOKEHIMAGE, "Bokeh Image", NODE_CLASS_INPUT, NODE_PREVIEW);
node_type_socket_templates(&ntype, NULL, cmp_node_bokehimage_out);
node_type_init(&ntype, node_composit_init_bokehimage);
diff --git a/source/blender/nodes/composite/nodes/node_composite_boxmask.c b/source/blender/nodes/composite/nodes/node_composite_boxmask.c
index 2a47c58c33f..611cf323873 100644
--- a/source/blender/nodes/composite/nodes/node_composite_boxmask.c
+++ b/source/blender/nodes/composite/nodes/node_composite_boxmask.c
@@ -32,7 +32,7 @@
#include "../node_composite_util.h"
-/* **************** SCALAR MATH ******************** */
+/* **************** SCALAR MATH ******************** */
static bNodeSocketTemplate cmp_node_boxmask_in[] = {
{ SOCK_FLOAT, 1, N_("Mask"), 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
{ SOCK_FLOAT, 1, N_("Value"), 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
diff --git a/source/blender/nodes/composite/nodes/node_composite_brightness.c b/source/blender/nodes/composite/nodes/node_composite_brightness.c
index 845e9e20c81..d44b8cd63cb 100644
--- a/source/blender/nodes/composite/nodes/node_composite_brightness.c
+++ b/source/blender/nodes/composite/nodes/node_composite_brightness.c
@@ -54,7 +54,7 @@ static void node_composit_init_brightcontrast(bNodeTree *UNUSED(ntree), bNode *n
void register_node_type_cmp_brightcontrast(void)
{
static bNodeType ntype;
-
+
cmp_node_type_base(&ntype, CMP_NODE_BRIGHTCONTRAST, "Bright/Contrast", NODE_CLASS_OP_COLOR, 0);
node_type_socket_templates(&ntype, cmp_node_brightcontrast_in, cmp_node_brightcontrast_out);
node_type_init(&ntype, node_composit_init_brightcontrast);
diff --git a/source/blender/nodes/composite/nodes/node_composite_colorSpill.c b/source/blender/nodes/composite/nodes/node_composite_colorSpill.c
index a6a7f3aa5a3..641026c3aad 100644
--- a/source/blender/nodes/composite/nodes/node_composite_colorSpill.c
+++ b/source/blender/nodes/composite/nodes/node_composite_colorSpill.c
@@ -57,7 +57,7 @@ static void node_composit_init_color_spill(bNodeTree *UNUSED(ntree), bNode *node
void register_node_type_cmp_color_spill(void)
{
static bNodeType ntype;
-
+
cmp_node_type_base(&ntype, CMP_NODE_COLOR_SPILL, "Color Spill", NODE_CLASS_MATTE, 0);
node_type_socket_templates(&ntype, cmp_node_color_spill_in, cmp_node_color_spill_out);
node_type_init(&ntype, node_composit_init_color_spill);
diff --git a/source/blender/nodes/composite/nodes/node_composite_colorbalance.c b/source/blender/nodes/composite/nodes/node_composite_colorbalance.c
index 8370ace8cb3..f9ad8c0ea5f 100644
--- a/source/blender/nodes/composite/nodes/node_composite_colorbalance.c
+++ b/source/blender/nodes/composite/nodes/node_composite_colorbalance.c
@@ -52,7 +52,7 @@ void ntreeCompositColorBalanceSyncFromLGG(bNodeTree *UNUSED(ntree), bNode *node)
{
NodeColorBalance *n = node->storage;
int c;
-
+
for (c = 0; c < 3; ++c) {
n->slope[c] = (2.0f - n->lift[c]) * n->gain[c];
n->offset[c] = (n->lift[c] - 1.0f) * n->gain[c];
@@ -64,7 +64,7 @@ void ntreeCompositColorBalanceSyncFromCDL(bNodeTree *UNUSED(ntree), bNode *node)
{
NodeColorBalance *n = node->storage;
int c;
-
+
for (c = 0; c < 3; ++c) {
float d = n->slope[c] + n->offset[c];
n->lift[c] = (d != 0.0f ? n->slope[c] + 2.0f * n->offset[c] / d : 0.0f);
diff --git a/source/blender/nodes/composite/nodes/node_composite_common.c b/source/blender/nodes/composite/nodes/node_composite_common.c
index 57ec0f1c7ad..de97a5beac3 100644
--- a/source/blender/nodes/composite/nodes/node_composite_common.c
+++ b/source/blender/nodes/composite/nodes/node_composite_common.c
@@ -43,7 +43,7 @@
void register_node_type_cmp_group(void)
{
static bNodeType ntype;
-
+
/* NB: cannot use sh_node_type_base for node group, because it would map the node type
* to the shared NODE_GROUP integer type id.
*/
@@ -56,7 +56,7 @@ void register_node_type_cmp_group(void)
ntype.ext.srna = RNA_struct_find("CompositorNodeGroup");
BLI_assert(ntype.ext.srna != NULL);
RNA_struct_blender_type_set(ntype.ext.srna, &ntype);
-
+
node_type_socket_templates(&ntype, NULL, NULL);
node_type_size(&ntype, 140, 60, 400);
node_type_label(&ntype, node_group_label);
diff --git a/source/blender/nodes/composite/nodes/node_composite_dilate.c b/source/blender/nodes/composite/nodes/node_composite_dilate.c
index 4efee112438..72d12e0a643 100644
--- a/source/blender/nodes/composite/nodes/node_composite_dilate.c
+++ b/source/blender/nodes/composite/nodes/node_composite_dilate.c
@@ -54,7 +54,7 @@ static void node_composit_init_dilateerode(bNodeTree *UNUSED(ntree), bNode *node
void register_node_type_cmp_dilateerode(void)
{
static bNodeType ntype;
-
+
cmp_node_type_base(&ntype, CMP_NODE_DILATEERODE, "Dilate/Erode", NODE_CLASS_OP_FILTER, 0);
node_type_socket_templates(&ntype, cmp_node_dilateerode_in, cmp_node_dilateerode_out);
node_type_init(&ntype, node_composit_init_dilateerode);
diff --git a/source/blender/nodes/composite/nodes/node_composite_ellipsemask.c b/source/blender/nodes/composite/nodes/node_composite_ellipsemask.c
index df8ae4931e5..b72a0fb82ae 100644
--- a/source/blender/nodes/composite/nodes/node_composite_ellipsemask.c
+++ b/source/blender/nodes/composite/nodes/node_composite_ellipsemask.c
@@ -32,7 +32,7 @@
#include "../node_composite_util.h"
-/* **************** SCALAR MATH ******************** */
+/* **************** SCALAR MATH ******************** */
static bNodeSocketTemplate cmp_node_ellipsemask_in[] = {
{ SOCK_FLOAT, 1, N_("Mask"), 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
{ SOCK_FLOAT, 1, N_("Value"), 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
diff --git a/source/blender/nodes/composite/nodes/node_composite_gamma.c b/source/blender/nodes/composite/nodes/node_composite_gamma.c
index 81764c97aac..30d399d3f73 100644
--- a/source/blender/nodes/composite/nodes/node_composite_gamma.c
+++ b/source/blender/nodes/composite/nodes/node_composite_gamma.c
@@ -47,9 +47,9 @@ static bNodeSocketTemplate cmp_node_gamma_out[] = {
void register_node_type_cmp_gamma(void)
{
static bNodeType ntype;
-
+
cmp_node_type_base(&ntype, CMP_NODE_GAMMA, "Gamma", NODE_CLASS_OP_COLOR, 0);
node_type_socket_templates(&ntype, cmp_node_gamma_in, cmp_node_gamma_out);
-
+
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/composite/nodes/node_composite_huecorrect.c b/source/blender/nodes/composite/nodes/node_composite_huecorrect.c
index 4ee1bccd726..70c73bcb46a 100644
--- a/source/blender/nodes/composite/nodes/node_composite_huecorrect.c
+++ b/source/blender/nodes/composite/nodes/node_composite_huecorrect.c
@@ -47,14 +47,14 @@ static void node_composit_init_huecorrect(bNodeTree *UNUSED(ntree), bNode *node)
{
CurveMapping *cumapping = node->storage = curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f);
int c;
-
+
cumapping->preset = CURVE_PRESET_MID9;
-
+
for (c = 0; c < 3; c++) {
CurveMap *cuma = &cumapping->cm[c];
curvemap_reset(cuma, &cumapping->clipr, cumapping->preset, CURVEMAP_SLOPE_POSITIVE);
}
-
+
/* default to showing Saturation */
cumapping->cur = 1;
}
diff --git a/source/blender/nodes/composite/nodes/node_composite_image.c b/source/blender/nodes/composite/nodes/node_composite_image.c
index 6a5458d6045..124b2fa72b9 100644
--- a/source/blender/nodes/composite/nodes/node_composite_image.c
+++ b/source/blender/nodes/composite/nodes/node_composite_image.c
@@ -150,10 +150,10 @@ static void cmp_node_image_create_outputs(bNodeTree *ntree, bNode *node, LinkNod
/* make sure ima->type is correct */
ibuf = BKE_image_acquire_ibuf(ima, &load_iuser, NULL);
-
+
if (ima->rr) {
RenderLayer *rl = BLI_findlink(&ima->rr->layers, iuser->layer);
-
+
if (rl) {
RenderPass *rpass;
for (rpass = rl->passes.first; rpass; rpass = rpass->next) {
@@ -251,7 +251,7 @@ static void cmp_node_image_verify_outputs(bNodeTree *ntree, bNode *node, bool rl
bNodeSocket *sock, *sock_next;
LinkNodePair available_sockets = {NULL, NULL};
int sock_index;
-
+
/* XXX make callback */
if (rlayer)
cmp_node_rlayer_create_outputs(ntree, node, &available_sockets);
@@ -307,7 +307,7 @@ static void node_composit_init_image(bNodeTree *ntree, bNode *node)
iuser->fie_ima = 2;
iuser->ok = 1;
iuser->flag |= IMA_ANIM_ALWAYS;
-
+
/* setup initial outputs */
cmp_node_image_verify_outputs(ntree, node, false);
}
@@ -315,20 +315,20 @@ static void node_composit_init_image(bNodeTree *ntree, bNode *node)
static void node_composit_free_image(bNode *node)
{
bNodeSocket *sock;
-
+
/* free extra socket info */
for (sock = node->outputs.first; sock; sock = sock->next)
MEM_freeN(sock->storage);
-
+
MEM_freeN(node->storage);
}
static void node_composit_copy_image(bNodeTree *UNUSED(dest_ntree), bNode *dest_node, bNode *src_node)
{
bNodeSocket *sock;
-
+
dest_node->storage = MEM_dupallocN(src_node->storage);
-
+
/* copy extra socket info */
for (sock = src_node->outputs.first; sock; sock = sock->next)
sock->new_sock->storage = MEM_dupallocN(sock->storage);
@@ -394,7 +394,7 @@ static int node_composit_poll_rlayers(bNodeType *UNUSED(ntype), bNodeTree *ntree
{
if (STREQ(ntree->idname, "CompositorNodeTree")) {
Scene *scene;
-
+
/* XXX ugly: check if ntree is a local scene node tree.
* Render layers node can only be used in local scene->nodetree,
* since it directly links to the scene.
@@ -402,7 +402,7 @@ static int node_composit_poll_rlayers(bNodeType *UNUSED(ntype), bNodeTree *ntree
for (scene = G.main->scene.first; scene; scene = scene->id.next)
if (scene->nodetree == ntree)
break;
-
+
return (scene != NULL);
}
return false;
diff --git a/source/blender/nodes/composite/nodes/node_composite_inpaint.c b/source/blender/nodes/composite/nodes/node_composite_inpaint.c
index a0d3531dabf..f97f366d0c4 100644
--- a/source/blender/nodes/composite/nodes/node_composite_inpaint.c
+++ b/source/blender/nodes/composite/nodes/node_composite_inpaint.c
@@ -47,7 +47,7 @@ static bNodeSocketTemplate cmp_node_inpaint_out[] = {
void register_node_type_cmp_inpaint(void)
{
static bNodeType ntype;
-
+
cmp_node_type_base(&ntype, CMP_NODE_INPAINT, "Inpaint", NODE_CLASS_OP_FILTER, 0);
node_type_socket_templates(&ntype, cmp_node_inpaint_in, cmp_node_inpaint_out);
diff --git a/source/blender/nodes/composite/nodes/node_composite_math.c b/source/blender/nodes/composite/nodes/node_composite_math.c
index 276dab27f76..e40621d3210 100644
--- a/source/blender/nodes/composite/nodes/node_composite_math.c
+++ b/source/blender/nodes/composite/nodes/node_composite_math.c
@@ -32,7 +32,7 @@
#include "node_composite_util.h"
-/* **************** SCALAR MATH ******************** */
+/* **************** SCALAR MATH ******************** */
static bNodeSocketTemplate cmp_node_math_in[] = {
{ SOCK_FLOAT, 1, N_("Value"), 0.5f, 0.5f, 0.5f, 1.0f, -10000.0f, 10000.0f, PROP_NONE},
{ SOCK_FLOAT, 1, N_("Value"), 0.5f, 0.5f, 0.5f, 1.0f, -10000.0f, 10000.0f, PROP_NONE},
diff --git a/source/blender/nodes/composite/nodes/node_composite_moviedistortion.c b/source/blender/nodes/composite/nodes/node_composite_moviedistortion.c
index 9c54009d2f1..4149a0eec9d 100644
--- a/source/blender/nodes/composite/nodes/node_composite_moviedistortion.c
+++ b/source/blender/nodes/composite/nodes/node_composite_moviedistortion.c
@@ -58,7 +58,7 @@ static void init(const bContext *C, PointerRNA *ptr)
{
bNode *node = ptr->data;
Scene *scene = CTX_data_scene(C);
-
+
node->id = (ID *)scene->clip;
}
diff --git a/source/blender/nodes/composite/nodes/node_composite_normalize.c b/source/blender/nodes/composite/nodes/node_composite_normalize.c
index d93c62f8229..9a5cc84797e 100644
--- a/source/blender/nodes/composite/nodes/node_composite_normalize.c
+++ b/source/blender/nodes/composite/nodes/node_composite_normalize.c
@@ -46,9 +46,9 @@ static bNodeSocketTemplate cmp_node_normalize_out[] = {
void register_node_type_cmp_normalize(void)
{
static bNodeType ntype;
-
+
cmp_node_type_base(&ntype, CMP_NODE_NORMALIZE, "Normalize", NODE_CLASS_OP_VECTOR, 0);
node_type_socket_templates(&ntype, cmp_node_normalize_in, cmp_node_normalize_out);
-
+
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/composite/nodes/node_composite_outputFile.c b/source/blender/nodes/composite/nodes/node_composite_outputFile.c
index 8b349ea8779..a2a25d5c515 100644
--- a/source/blender/nodes/composite/nodes/node_composite_outputFile.c
+++ b/source/blender/nodes/composite/nodes/node_composite_outputFile.c
@@ -107,16 +107,16 @@ bNodeSocket *ntreeCompositOutputFileAddSocket(bNodeTree *ntree, bNode *node, con
{
NodeImageMultiFile *nimf = node->storage;
bNodeSocket *sock = nodeAddStaticSocket(ntree, node, SOCK_IN, SOCK_RGBA, PROP_NONE, NULL, name);
-
+
/* create format data for the input socket */
NodeImageMultiFileSocket *sockdata = MEM_callocN(sizeof(NodeImageMultiFileSocket), "socket image format");
sock->storage = sockdata;
-
+
BLI_strncpy_utf8(sockdata->path, name, sizeof(sockdata->path));
ntreeCompositOutputFileUniquePath(&node->inputs, sock, name, '_');
BLI_strncpy_utf8(sockdata->layer, name, sizeof(sockdata->layer));
ntreeCompositOutputFileUniqueLayer(&node->inputs, sock, name, '_');
-
+
if (im_format) {
sockdata->format = *im_format;
if (BKE_imtype_is_movie(sockdata->format.imtype)) {
@@ -129,7 +129,7 @@ bNodeSocket *ntreeCompositOutputFileAddSocket(bNodeTree *ntree, bNode *node, con
sockdata->use_node_format = true;
nimf->active_input = BLI_findindex(&node->inputs, sock);
-
+
return sock;
}
@@ -138,16 +138,16 @@ int ntreeCompositOutputFileRemoveActiveSocket(bNodeTree *ntree, bNode *node)
NodeImageMultiFile *nimf = node->storage;
bNodeSocket *sock = BLI_findlink(&node->inputs, nimf->active_input);
int totinputs = BLI_listbase_count(&node->inputs);
-
+
if (!sock)
return 0;
-
+
if (nimf->active_input == totinputs - 1)
--nimf->active_input;
-
+
/* free format data */
MEM_freeN(sock->storage);
-
+
nodeRemoveSocket(ntree, node, sock);
return 1;
}
@@ -175,7 +175,7 @@ static void init_output_file(const bContext *C, PointerRNA *ptr)
NodeImageMultiFile *nimf = MEM_callocN(sizeof(NodeImageMultiFile), "node image multi file");
ImageFormatData *format = NULL;
node->storage = nimf;
-
+
if (scene) {
RenderData *rd = &scene->r;
@@ -184,7 +184,7 @@ static void init_output_file(const bContext *C, PointerRNA *ptr)
if (BKE_imtype_is_movie(nimf->format.imtype)) {
nimf->format.imtype = R_IMF_IMTYPE_OPENEXR;
}
-
+
format = &nimf->format;
}
else
@@ -197,21 +197,21 @@ static void init_output_file(const bContext *C, PointerRNA *ptr)
static void free_output_file(bNode *node)
{
bNodeSocket *sock;
-
+
/* free storage data in sockets */
for (sock = node->inputs.first; sock; sock = sock->next) {
MEM_freeN(sock->storage);
}
-
+
MEM_freeN(node->storage);
}
static void copy_output_file(bNodeTree *UNUSED(dest_ntree), bNode *dest_node, bNode *src_node)
{
bNodeSocket *src_sock, *dest_sock;
-
+
dest_node->storage = MEM_dupallocN(src_node->storage);
-
+
/* duplicate storage data in sockets */
for (src_sock = src_node->inputs.first, dest_sock = dest_node->inputs.first; src_sock && dest_sock; src_sock = src_sock->next, dest_sock = dest_sock->next) {
dest_sock->storage = MEM_dupallocN(src_sock->storage);
@@ -222,7 +222,7 @@ static void update_output_file(bNodeTree *ntree, bNode *node)
{
bNodeSocket *sock, *sock_next;
PointerRNA ptr;
-
+
/* XXX fix for #36706: remove invalid sockets added with bpy API.
* This is not ideal, but prevents crashes from missing storage.
* FileOutput node needs a redesign to support this properly.
@@ -237,9 +237,9 @@ static void update_output_file(bNodeTree *ntree, bNode *node)
sock_next = sock->next;
nodeRemoveSocket(ntree, node, sock);
}
-
+
cmp_node_update_default(ntree, node);
-
+
/* automatically update the socket type based on linked input */
for (sock = node->inputs.first; sock; sock = sock->next) {
if (sock->link) {
diff --git a/source/blender/nodes/composite/nodes/node_composite_splitViewer.c b/source/blender/nodes/composite/nodes/node_composite_splitViewer.c
index 780ec1592bf..dbe47066f66 100644
--- a/source/blender/nodes/composite/nodes/node_composite_splitViewer.c
+++ b/source/blender/nodes/composite/nodes/node_composite_splitViewer.c
@@ -49,7 +49,7 @@ static void node_composit_init_splitviewer(bNodeTree *UNUSED(ntree), bNode *node
iuser->fie_ima = 2;
iuser->ok = 1;
node->custom1 = 50; /* default 50% split */
-
+
node->id = (ID *)BKE_image_verify_viewer(IMA_TYPE_COMPOSITE, "Viewer Node");
}
diff --git a/source/blender/nodes/composite/nodes/node_composite_stabilize2d.c b/source/blender/nodes/composite/nodes/node_composite_stabilize2d.c
index 93ae6b6c4a4..16f5d340ddd 100644
--- a/source/blender/nodes/composite/nodes/node_composite_stabilize2d.c
+++ b/source/blender/nodes/composite/nodes/node_composite_stabilize2d.c
@@ -50,9 +50,9 @@ static void init(const bContext *C, PointerRNA *ptr)
{
bNode *node = ptr->data;
Scene *scene = CTX_data_scene(C);
-
+
node->id = (ID *)scene->clip;
-
+
/* default to bilinear, see node_sampler_type_items in rna_nodetree.c */
node->custom1 = 1;
}
diff --git a/source/blender/nodes/composite/nodes/node_composite_valToRgb.c b/source/blender/nodes/composite/nodes/node_composite_valToRgb.c
index 1b62f4e77d4..16fc98a5e85 100644
--- a/source/blender/nodes/composite/nodes/node_composite_valToRgb.c
+++ b/source/blender/nodes/composite/nodes/node_composite_valToRgb.c
@@ -77,10 +77,10 @@ static bNodeSocketTemplate cmp_node_rgbtobw_out[] = {
void register_node_type_cmp_rgbtobw(void)
{
static bNodeType ntype;
-
+
cmp_node_type_base(&ntype, CMP_NODE_RGBTOBW, "RGB to BW", NODE_CLASS_CONVERTOR, 0);
node_type_socket_templates(&ntype, cmp_node_rgbtobw_in, cmp_node_rgbtobw_out);
node_type_size_preset(&ntype, NODE_SIZE_SMALL);
-
+
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/composite/nodes/node_composite_viewer.c b/source/blender/nodes/composite/nodes/node_composite_viewer.c
index 66f2e2bacbc..a10ba02b38e 100644
--- a/source/blender/nodes/composite/nodes/node_composite_viewer.c
+++ b/source/blender/nodes/composite/nodes/node_composite_viewer.c
@@ -52,7 +52,7 @@ static void node_composit_init_viewer(bNodeTree *UNUSED(ntree), bNode *node)
iuser->ok = 1;
node->custom3 = 0.5f;
node->custom4 = 0.5f;
-
+
node->id = (ID *)BKE_image_verify_viewer(IMA_TYPE_COMPOSITE, "Viewer Node");
}
diff --git a/source/blender/nodes/intern/node_common.c b/source/blender/nodes/intern/node_common.c
index c465f7a9be5..4a47bf7035c 100644
--- a/source/blender/nodes/intern/node_common.c
+++ b/source/blender/nodes/intern/node_common.c
@@ -98,16 +98,16 @@ int nodeGroupPoll(bNodeTree *nodetree, bNodeTree *grouptree)
{
bNode *node;
int valid = 1;
-
+
/* unspecified node group, generally allowed
* (if anything, should be avoided on operator level)
*/
if (grouptree == NULL)
return 1;
-
+
if (nodetree == grouptree)
return 0;
-
+
for (node = grouptree->nodes.first; node; node = node->next) {
if (node->typeinfo->poll_instance && !node->typeinfo->poll_instance(node, nodetree)) {
valid = 0;
@@ -121,27 +121,27 @@ int nodeGroupPoll(bNodeTree *nodetree, bNodeTree *grouptree)
static bNodeSocket *group_verify_socket(bNodeTree *ntree, bNode *gnode, bNodeSocket *iosock, ListBase *verify_lb, int in_out)
{
bNodeSocket *sock;
-
+
for (sock = verify_lb->first; sock; sock = sock->next) {
if (STREQ(sock->identifier, iosock->identifier))
break;
}
if (sock) {
strcpy(sock->name, iosock->name);
-
+
if (iosock->typeinfo->interface_verify_socket)
iosock->typeinfo->interface_verify_socket(ntree, iosock, gnode, sock, "interface");
}
else {
sock = nodeAddSocket(ntree, gnode, in_out, iosock->idname, iosock->identifier, iosock->name);
-
+
if (iosock->typeinfo->interface_init_socket)
iosock->typeinfo->interface_init_socket(ntree, iosock, gnode, sock, "interface");
}
-
+
/* remove from list temporarily, to distinguish from orphaned sockets */
BLI_remlink(verify_lb, sock);
-
+
return sock;
}
@@ -150,9 +150,9 @@ static void group_verify_socket_list(bNodeTree *ntree, bNode *gnode,
ListBase *iosock_lb, ListBase *verify_lb, int in_out)
{
bNodeSocket *iosock, *sock, *nextsock;
-
+
/* step by step compare */
-
+
iosock = iosock_lb->first;
for (; iosock; iosock = iosock->next) {
/* abusing new_sock pointer for verification here! only used inside this function */
@@ -195,9 +195,9 @@ static void node_frame_init(bNodeTree *UNUSED(ntree), bNode *node)
{
NodeFrame *data = (NodeFrame *)MEM_callocN(sizeof(NodeFrame), "frame node storage");
node->storage = data;
-
+
data->flag |= NODE_FRAME_SHRINK;
-
+
data->label_size = 20;
}
@@ -211,7 +211,7 @@ void register_node_type_frame(void)
node_type_storage(ntype, "NodeFrame", node_free_standard_storage, node_copy_standard_storage);
node_type_size(ntype, 150, 100, 0);
node_type_compatibility(ntype, NODE_OLD_SHADING | NODE_NEW_SHADING);
-
+
ntype->needs_free = 1;
nodeRegisterType(ntype);
}
@@ -251,11 +251,11 @@ void register_node_type_reroute(void)
{
/* frame type is used for all tree types, needs dynamic allocation */
bNodeType *ntype = MEM_callocN(sizeof(bNodeType), "frame node type");
-
+
node_type_base(ntype, NODE_REROUTE, "Reroute", NODE_CLASS_LAYOUT, 0);
node_type_init(ntype, node_reroute_init);
node_type_internal_links(ntype, node_reroute_update_internal_links);
-
+
ntype->needs_free = 1;
nodeRegisterType(ntype);
}
@@ -267,14 +267,14 @@ static void node_reroute_inherit_type_recursive(bNodeTree *ntree, bNode *node, i
bNodeLink *link;
int type = SOCK_FLOAT;
const char *type_idname = nodeStaticSocketType(type, PROP_NONE);
-
+
/* XXX it would be a little bit more efficient to restrict actual updates
* to rerout nodes connected to an updated node, but there's no reliable flag
* to indicate updated nodes (node->update is not set on linking).
*/
-
+
node->done = 1;
-
+
/* recursive update */
for (link = ntree->links.first; link; link = link->next) {
bNode *fromnode = link->fromnode;
@@ -283,7 +283,7 @@ static void node_reroute_inherit_type_recursive(bNodeTree *ntree, bNode *node, i
continue;
if (nodeLinkIsHidden(link))
continue;
-
+
if (flag & REFINE_FORWARD) {
if (tonode == node && fromnode->type == NODE_REROUTE && !fromnode->done)
node_reroute_inherit_type_recursive(ntree, fromnode, REFINE_FORWARD);
@@ -293,7 +293,7 @@ static void node_reroute_inherit_type_recursive(bNodeTree *ntree, bNode *node, i
node_reroute_inherit_type_recursive(ntree, tonode, REFINE_BACKWARD);
}
}
-
+
/* determine socket type from unambiguous input/output connection if possible */
if (input->limit == 1 && input->link) {
type = input->link->fromsock->type;
@@ -303,7 +303,7 @@ static void node_reroute_inherit_type_recursive(bNodeTree *ntree, bNode *node, i
type = output->link->tosock->type;
type_idname = nodeStaticSocketType(type, PROP_NONE);
}
-
+
if (input->type != type) {
bNodeSocket *ninput = nodeAddSocket(ntree, node, SOCK_IN, type_idname, "input", "Input");
for (link = ntree->links.first; link; link = link->next) {
@@ -314,7 +314,7 @@ static void node_reroute_inherit_type_recursive(bNodeTree *ntree, bNode *node, i
}
nodeRemoveSocket(ntree, node, input);
}
-
+
if (output->type != type) {
bNodeSocket *noutput = nodeAddSocket(ntree, node, SOCK_OUT, type_idname, "output", "Output");
for (link = ntree->links.first; link; link = link->next) {
@@ -324,7 +324,7 @@ static void node_reroute_inherit_type_recursive(bNodeTree *ntree, bNode *node, i
}
nodeRemoveSocket(ntree, node, output);
}
-
+
nodeUpdateInternalLinks(ntree, node);
}
@@ -334,11 +334,11 @@ static void node_reroute_inherit_type_recursive(bNodeTree *ntree, bNode *node, i
void ntree_update_reroute_nodes(bNodeTree *ntree)
{
bNode *node;
-
+
/* clear tags */
for (node = ntree->nodes.first; node; node = node->next)
node->done = 0;
-
+
for (node = ntree->nodes.first; node; node = node->next)
if (node->type == NODE_REROUTE && !node->done)
node_reroute_inherit_type_recursive(ntree, node, REFINE_FORWARD | REFINE_BACKWARD);
@@ -411,7 +411,7 @@ void node_group_input_verify(bNodeTree *ntree, bNode *node, ID *id)
if (id == (ID *)ntree) {
/* value_in_out inverted for interface nodes to get correct socket value_property */
group_verify_socket_list(ntree, node, &ntree->inputs, &node->outputs, SOCK_OUT);
-
+
/* add virtual extension socket */
nodeAddSocket(ntree, node, SOCK_OUT, "NodeSocketVirtual", "__extend__", "");
}
@@ -426,23 +426,23 @@ static void node_group_input_update(bNodeTree *ntree, bNode *node)
* so they can be recreated after verification.
*/
ListBase tmplinks;
-
+
/* find links from the extension socket and store them */
BLI_listbase_clear(&tmplinks);
for (link = ntree->links.first; link; link = linknext) {
linknext = link->next;
if (nodeLinkIsHidden(link))
continue;
-
+
if (link->fromsock == extsock) {
bNodeLink *tlink = MEM_callocN(sizeof(bNodeLink), "temporary link");
*tlink = *link;
BLI_addtail(&tmplinks, tlink);
-
+
nodeRemLink(ntree, link);
}
}
-
+
/* find valid link to expose */
exposelink = NULL;
for (link = tmplinks.first; link; link = link->next) {
@@ -456,22 +456,22 @@ static void node_group_input_update(bNodeTree *ntree, bNode *node)
break;
}
}
-
+
if (exposelink) {
bNodeSocket *gsock, *newsock;
-
+
gsock = ntreeAddSocketInterfaceFromSocket(ntree, exposelink->tonode, exposelink->tosock);
-
+
node_group_input_verify(ntree, node, (ID *)ntree);
newsock = node_group_input_find_socket(node, gsock->identifier);
-
+
/* redirect links from the extension socket */
for (link = tmplinks.first; link; link = link->next) {
nodeAddLink(ntree, node, newsock, link->tonode, link->tosock);
}
-
+
}
-
+
BLI_freelistN(&tmplinks);
}
@@ -479,13 +479,13 @@ void register_node_type_group_input(void)
{
/* used for all tree types, needs dynamic allocation */
bNodeType *ntype = MEM_callocN(sizeof(bNodeType), "node type");
-
+
node_type_base(ntype, NODE_GROUP_INPUT, "Group Input", NODE_CLASS_INTERFACE, 0);
node_type_size(ntype, 140, 80, 400);
node_type_init(ntype, node_group_input_init);
node_type_update(ntype, node_group_input_update, node_group_input_verify);
node_type_compatibility(ntype, NODE_OLD_SHADING | NODE_NEW_SHADING);
-
+
ntype->needs_free = 1;
nodeRegisterType(ntype);
}
@@ -510,7 +510,7 @@ void node_group_output_verify(bNodeTree *ntree, bNode *node, ID *id)
if (id == (ID *)ntree) {
/* value_in_out inverted for interface nodes to get correct socket value_property */
group_verify_socket_list(ntree, node, &ntree->outputs, &node->inputs, SOCK_IN);
-
+
/* add virtual extension socket */
nodeAddSocket(ntree, node, SOCK_IN, "NodeSocketVirtual", "__extend__", "");
}
@@ -525,23 +525,23 @@ static void node_group_output_update(bNodeTree *ntree, bNode *node)
* so they can be recreated after verification.
*/
ListBase tmplinks;
-
+
/* find links to the extension socket and store them */
BLI_listbase_clear(&tmplinks);
for (link = ntree->links.first; link; link = linknext) {
linknext = link->next;
if (nodeLinkIsHidden(link))
continue;
-
+
if (link->tosock == extsock) {
bNodeLink *tlink = MEM_callocN(sizeof(bNodeLink), "temporary link");
*tlink = *link;
BLI_addtail(&tmplinks, tlink);
-
+
nodeRemLink(ntree, link);
}
}
-
+
/* find valid link to expose */
exposelink = NULL;
for (link = tmplinks.first; link; link = link->next) {
@@ -555,22 +555,22 @@ static void node_group_output_update(bNodeTree *ntree, bNode *node)
break;
}
}
-
+
if (exposelink) {
bNodeSocket *gsock, *newsock;
-
+
/* XXX what if connecting virtual to virtual socket?? */
gsock = ntreeAddSocketInterfaceFromSocket(ntree, exposelink->fromnode, exposelink->fromsock);
-
+
node_group_output_verify(ntree, node, (ID *)ntree);
newsock = node_group_output_find_socket(node, gsock->identifier);
-
+
/* redirect links to the extension socket */
for (link = tmplinks.first; link; link = link->next) {
nodeAddLink(ntree, link->fromnode, link->fromsock, node, newsock);
}
}
-
+
BLI_freelistN(&tmplinks);
}
@@ -578,13 +578,13 @@ void register_node_type_group_output(void)
{
/* used for all tree types, needs dynamic allocation */
bNodeType *ntype = MEM_callocN(sizeof(bNodeType), "node type");
-
+
node_type_base(ntype, NODE_GROUP_OUTPUT, "Group Output", NODE_CLASS_INTERFACE, 0);
node_type_size(ntype, 140, 80, 400);
node_type_init(ntype, node_group_output_init);
node_type_update(ntype, node_group_output_update, node_group_output_verify);
node_type_compatibility(ntype, NODE_OLD_SHADING | NODE_NEW_SHADING);
-
+
ntype->needs_free = 1;
nodeRegisterType(ntype);
}
diff --git a/source/blender/nodes/intern/node_exec.c b/source/blender/nodes/intern/node_exec.c
index 5b97685fc54..3708a7663ed 100644
--- a/source/blender/nodes/intern/node_exec.c
+++ b/source/blender/nodes/intern/node_exec.c
@@ -61,14 +61,14 @@ bNodeStack *node_get_socket_stack(bNodeStack *stack, bNodeSocket *sock)
void node_get_stack(bNode *node, bNodeStack *stack, bNodeStack **in, bNodeStack **out)
{
bNodeSocket *sock;
-
+
/* build pointer stack */
if (in) {
for (sock = node->inputs.first; sock; sock = sock->next) {
*(in++) = node_get_socket_stack(stack, sock);
}
}
-
+
if (out) {
for (sock = node->outputs.first; sock; sock = sock->next) {
*(out++) = node_get_socket_stack(stack, sock);
@@ -127,13 +127,13 @@ static struct bNodeStack *setup_stack(bNodeStack *stack, bNodeTree *ntree, bNode
bNodeStack *ns = node_get_socket_stack(stack, sock);
if (!ns)
return NULL;
-
+
/* don't mess with remote socket stacks, these are initialized by other nodes! */
if (sock->link)
return ns;
-
+
ns->sockettype = sock->type;
-
+
switch (sock->type) {
case SOCK_FLOAT:
ns->vec[0] = node_socket_get_float(ntree, node, sock);
@@ -145,7 +145,7 @@ static struct bNodeStack *setup_stack(bNodeStack *stack, bNodeTree *ntree, bNode
node_socket_get_color(ntree, node, sock, ns->vec);
break;
}
-
+
return ns;
}
@@ -161,29 +161,29 @@ bNodeTreeExec *ntree_exec_begin(bNodeExecContext *context, bNodeTree *ntree, bNo
bNode **nodelist;
int totnodes, n;
/* XXX texnodes have threading issues with muting, have to disable it there ... */
-
+
/* ensure all sock->link pointers and node levels are correct */
ntreeUpdateTree(G.main, ntree);
-
+
/* get a dependency-sorted list of nodes */
ntreeGetDependencyList(ntree, &nodelist, &totnodes);
-
+
/* XXX could let callbacks do this for specialized data */
exec = MEM_callocN(sizeof(bNodeTreeExec), "node tree execution data");
/* backpointer to node tree */
exec->nodetree = ntree;
-
+
/* set stack indices */
index = 0;
for (n = 0; n < totnodes; ++n) {
node = nodelist[n];
-
+
node->stack_index = index;
-
+
/* init node socket stack indexes */
for (sock = node->inputs.first; sock; sock = sock->next)
node_init_input_index(sock, &index);
-
+
if (node->flag & NODE_MUTED || node->type == NODE_REROUTE) {
for (sock = node->outputs.first; sock; sock = sock->next)
node_init_output_index(sock, &index, &node->internal_links);
@@ -193,48 +193,48 @@ bNodeTreeExec *ntree_exec_begin(bNodeExecContext *context, bNodeTree *ntree, bNo
node_init_output_index(sock, &index, NULL);
}
}
-
+
/* allocated exec data pointers for nodes */
exec->totnodes = totnodes;
exec->nodeexec = MEM_callocN(exec->totnodes * sizeof(bNodeExec), "node execution data");
/* allocate data pointer for node stack */
exec->stacksize = index;
exec->stack = MEM_callocN(exec->stacksize * sizeof(bNodeStack), "bNodeStack");
-
+
/* all non-const results are considered inputs */
for (n = 0; n < exec->stacksize; ++n)
exec->stack[n].hasinput = 1;
-
+
/* prepare all nodes for execution */
for (n = 0, nodeexec = exec->nodeexec; n < totnodes; ++n, ++nodeexec) {
node = nodeexec->node = nodelist[n];
nodeexec->freeexecfunc = node->typeinfo->freeexecfunc;
-
+
/* tag inputs */
for (sock = node->inputs.first; sock; sock = sock->next) {
/* disable the node if an input link is invalid */
if (sock->link && !(sock->link->flag & NODE_LINK_VALID))
node->need_exec = 0;
-
+
ns = setup_stack(exec->stack, ntree, node, sock);
if (ns)
ns->hasoutput = 1;
}
-
+
/* tag all outputs */
for (sock = node->outputs.first; sock; sock = sock->next) {
/* ns = */ setup_stack(exec->stack, ntree, node, sock);
}
-
+
nodekey = BKE_node_instance_key(parent_key, ntree, node);
nodeexec->data.preview = context->previews ? BKE_node_instance_hash_lookup(context->previews, nodekey) : NULL;
if (node->typeinfo->initexecfunc)
nodeexec->data.data = node->typeinfo->initexecfunc(context, node, nodekey);
}
-
+
if (nodelist)
MEM_freeN(nodelist);
-
+
return exec;
}
@@ -242,18 +242,18 @@ void ntree_exec_end(bNodeTreeExec *exec)
{
bNodeExec *nodeexec;
int n;
-
+
if (exec->stack)
MEM_freeN(exec->stack);
-
+
for (n = 0, nodeexec = exec->nodeexec; n < exec->totnodes; ++n, ++nodeexec) {
if (nodeexec->freeexecfunc)
nodeexec->freeexecfunc(nodeexec->data.data);
}
-
+
if (exec->nodeexec)
MEM_freeN(exec->nodeexec);
-
+
MEM_freeN(exec);
}
@@ -263,14 +263,14 @@ bNodeThreadStack *ntreeGetThreadStack(bNodeTreeExec *exec, int thread)
{
ListBase *lb = &exec->threadstack[thread];
bNodeThreadStack *nts;
-
+
for (nts = lb->first; nts; nts = nts->next) {
if (!nts->used) {
nts->used = true;
break;
}
}
-
+
if (!nts) {
nts = MEM_callocN(sizeof(bNodeThreadStack), "bNodeThreadStack");
nts->stack = MEM_dupallocN(exec->stack);
@@ -293,9 +293,9 @@ bool ntreeExecThreadNodes(bNodeTreeExec *exec, bNodeThreadStack *nts, void *call
bNodeExec *nodeexec;
bNode *node;
int n;
-
+
/* nodes are presorted, so exec is in order of list */
-
+
for (n = 0, nodeexec = exec->nodeexec; n < exec->totnodes; ++n, ++nodeexec) {
node = nodeexec->node;
if (node->need_exec) {
@@ -308,7 +308,7 @@ bool ntreeExecThreadNodes(bNodeTreeExec *exec, bNodeThreadStack *nts, void *call
node->typeinfo->execfunc(callerdata, thread, node, &nodeexec->data, nsin, nsout);
}
}
-
+
/* signal to that all went OK, for render */
return true;
}
diff --git a/source/blender/nodes/intern/node_exec.h b/source/blender/nodes/intern/node_exec.h
index bf4c29bad8e..6771df76bf9 100644
--- a/source/blender/nodes/intern/node_exec.h
+++ b/source/blender/nodes/intern/node_exec.h
@@ -51,17 +51,17 @@ struct bNodeStack;
typedef struct bNodeExec {
struct bNode *node; /* backpointer to node */
bNodeExecData data;
-
+
NodeFreeExecFunction freeexecfunc; /* free function, stored in exec itself to avoid dangling node pointer access */
} bNodeExec;
/* Execution Data for each instance of node tree execution */
typedef struct bNodeTreeExec {
struct bNodeTree *nodetree; /* backpointer to node tree */
-
+
int totnodes; /* total node count */
struct bNodeExec *nodeexec; /* per-node execution data */
-
+
int stacksize;
struct bNodeStack *stack; /* socket data stack */
/* only used by material and texture trees to keep one stack for each thread */
diff --git a/source/blender/nodes/intern/node_socket.c b/source/blender/nodes/intern/node_socket.c
index e1e1e2f0854..23ba51bbe10 100644
--- a/source/blender/nodes/intern/node_socket.c
+++ b/source/blender/nodes/intern/node_socket.c
@@ -52,9 +52,9 @@ struct Main;
struct bNodeSocket *node_add_socket_from_template(struct bNodeTree *ntree, struct bNode *node, struct bNodeSocketTemplate *stemp, int in_out)
{
bNodeSocket *sock = nodeAddStaticSocket(ntree, node, in_out, stemp->type, stemp->subtype, stemp->identifier, stemp->name);
-
+
sock->flag |= stemp->flag;
-
+
/* initialize default_value */
switch (stemp->type) {
case SOCK_FLOAT:
@@ -99,14 +99,14 @@ struct bNodeSocket *node_add_socket_from_template(struct bNodeTree *ntree, struc
break;
}
}
-
+
return sock;
}
static bNodeSocket *verify_socket_template(bNodeTree *ntree, bNode *node, int in_out, ListBase *socklist, bNodeSocketTemplate *stemp)
{
bNodeSocket *sock;
-
+
for (sock = socklist->first; sock; sock = sock->next) {
if (STREQLEN(sock->name, stemp->name, NODE_MAXSTR))
break;
@@ -127,7 +127,7 @@ static bNodeSocket *verify_socket_template(bNodeTree *ntree, bNode *node, int in
/* remove the new socket from the node socket list first,
* will be added back after verification. */
BLI_remlink(socklist, sock);
-
+
return sock;
}
@@ -135,7 +135,7 @@ static void verify_socket_template_list(bNodeTree *ntree, bNode *node, int in_ou
{
bNodeSocket *sock, *nextsock;
bNodeSocketTemplate *stemp;
-
+
/* no inputs anymore? */
if (stemp_first == NULL) {
for (sock = (bNodeSocket *)socklist->first; sock; sock = nextsock) {
@@ -155,7 +155,7 @@ static void verify_socket_template_list(bNodeTree *ntree, bNode *node, int in_ou
nextsock = sock->next;
nodeRemoveSocket(ntree, node, sock);
}
-
+
/* and we put back the verified sockets */
stemp = stemp_first;
if (socklist->first) {
@@ -199,10 +199,10 @@ void node_socket_init_default_value(bNodeSocket *sock)
{
int type = sock->typeinfo->type;
int subtype = sock->typeinfo->subtype;
-
+
if (sock->default_value)
return; /* already initialized */
-
+
switch (type) {
case SOCK_FLOAT:
{
@@ -211,7 +211,7 @@ void node_socket_init_default_value(bNodeSocket *sock)
dval->value = 0.0f;
dval->min = -FLT_MAX;
dval->max = FLT_MAX;
-
+
sock->default_value = dval;
break;
}
@@ -222,7 +222,7 @@ void node_socket_init_default_value(bNodeSocket *sock)
dval->value = 0;
dval->min = INT_MIN;
dval->max = INT_MAX;
-
+
sock->default_value = dval;
break;
}
@@ -230,7 +230,7 @@ void node_socket_init_default_value(bNodeSocket *sock)
{
bNodeSocketValueBoolean *dval = MEM_callocN(sizeof(bNodeSocketValueBoolean), "node socket value bool");
dval->value = false;
-
+
sock->default_value = dval;
break;
}
@@ -242,7 +242,7 @@ void node_socket_init_default_value(bNodeSocket *sock)
copy_v3_v3(dval->value, default_value);
dval->min = -FLT_MAX;
dval->max = FLT_MAX;
-
+
sock->default_value = dval;
break;
}
@@ -251,7 +251,7 @@ void node_socket_init_default_value(bNodeSocket *sock)
static float default_value[] = { 0.0f, 0.0f, 0.0f, 1.0f };
bNodeSocketValueRGBA *dval = MEM_callocN(sizeof(bNodeSocketValueRGBA), "node socket value color");
copy_v4_v4(dval->value, default_value);
-
+
sock->default_value = dval;
break;
}
@@ -260,7 +260,7 @@ void node_socket_init_default_value(bNodeSocket *sock)
bNodeSocketValueString *dval = MEM_callocN(sizeof(bNodeSocketValueString), "node socket value string");
dval->subtype = subtype;
dval->value[0] = '\0';
-
+
sock->default_value = dval;
break;
}
@@ -272,12 +272,12 @@ void node_socket_copy_default_value(bNodeSocket *to, const bNodeSocket *from)
/* sanity check */
if (to->type != from->type)
return;
-
+
/* make sure both exist */
if (!from->default_value)
return;
node_socket_init_default_value(to);
-
+
switch (from->typeinfo->type) {
case SOCK_FLOAT:
{
@@ -330,7 +330,7 @@ static void standard_node_socket_interface_init_socket(bNodeTree *UNUSED(ntree),
{
/* initialize the type value */
sock->type = sock->typeinfo->type;
-
+
/* XXX socket interface 'type' value is not used really,
* but has to match or the copy function will bail out
*/
@@ -345,12 +345,12 @@ static void standard_node_socket_interface_verify_socket(bNodeTree *UNUSED(ntree
/* sanity check */
if (sock->type != stemp->typeinfo->type)
return;
-
+
/* make sure both exist */
if (!stemp->default_value)
return;
node_socket_init_default_value(sock);
-
+
switch (stemp->typeinfo->type) {
case SOCK_FLOAT:
{
@@ -389,65 +389,65 @@ static void standard_node_socket_interface_from_socket(bNodeTree *UNUSED(ntree),
static bNodeSocketType *make_standard_socket_type(int type, int subtype)
{
extern void ED_init_standard_node_socket_type(bNodeSocketType *);
-
+
const char *socket_idname = nodeStaticSocketType(type, subtype);
const char *interface_idname = nodeStaticSocketInterfaceType(type, subtype);
bNodeSocketType *stype;
StructRNA *srna;
-
+
stype = MEM_callocN(sizeof(bNodeSocketType), "node socket C type");
BLI_strncpy(stype->idname, socket_idname, sizeof(stype->idname));
-
+
/* set the RNA type
* uses the exact same identifier as the socket type idname */
srna = stype->ext_socket.srna = RNA_struct_find(socket_idname);
BLI_assert(srna != NULL);
/* associate the RNA type with the socket type */
RNA_struct_blender_type_set(srna, stype);
-
+
/* set the interface RNA type */
srna = stype->ext_interface.srna = RNA_struct_find(interface_idname);
BLI_assert(srna != NULL);
/* associate the RNA type with the socket type */
RNA_struct_blender_type_set(srna, stype);
-
+
/* extra type info for standard socket types */
stype->type = type;
stype->subtype = subtype;
-
+
/* XXX bad-level call! needed for setting draw callbacks */
ED_init_standard_node_socket_type(stype);
-
+
stype->interface_init_socket = standard_node_socket_interface_init_socket;
stype->interface_from_socket = standard_node_socket_interface_from_socket;
stype->interface_verify_socket = standard_node_socket_interface_verify_socket;
-
+
return stype;
}
static bNodeSocketType *make_socket_type_virtual(void)
{
extern void ED_init_node_socket_type_virtual(bNodeSocketType *);
-
+
const char *socket_idname = "NodeSocketVirtual";
bNodeSocketType *stype;
StructRNA *srna;
-
+
stype = MEM_callocN(sizeof(bNodeSocketType), "node socket C type");
BLI_strncpy(stype->idname, socket_idname, sizeof(stype->idname));
-
+
/* set the RNA type
* uses the exact same identifier as the socket type idname */
srna = stype->ext_socket.srna = RNA_struct_find(socket_idname);
BLI_assert(srna != NULL);
/* associate the RNA type with the socket type */
RNA_struct_blender_type_set(srna, stype);
-
+
/* extra type info for standard socket types */
stype->type = SOCK_CUSTOM;
-
+
ED_init_node_socket_type_virtual(stype);
-
+
return stype;
}
@@ -455,21 +455,21 @@ static bNodeSocketType *make_socket_type_virtual(void)
void register_standard_node_socket_types(void)
{
/* draw callbacks are set in drawnode.c to avoid bad-level calls */
-
+
nodeRegisterSocketType(make_standard_socket_type(SOCK_FLOAT, PROP_NONE));
nodeRegisterSocketType(make_standard_socket_type(SOCK_FLOAT, PROP_UNSIGNED));
nodeRegisterSocketType(make_standard_socket_type(SOCK_FLOAT, PROP_PERCENTAGE));
nodeRegisterSocketType(make_standard_socket_type(SOCK_FLOAT, PROP_FACTOR));
nodeRegisterSocketType(make_standard_socket_type(SOCK_FLOAT, PROP_ANGLE));
nodeRegisterSocketType(make_standard_socket_type(SOCK_FLOAT, PROP_TIME));
-
+
nodeRegisterSocketType(make_standard_socket_type(SOCK_INT, PROP_NONE));
nodeRegisterSocketType(make_standard_socket_type(SOCK_INT, PROP_UNSIGNED));
nodeRegisterSocketType(make_standard_socket_type(SOCK_INT, PROP_PERCENTAGE));
nodeRegisterSocketType(make_standard_socket_type(SOCK_INT, PROP_FACTOR));
-
+
nodeRegisterSocketType(make_standard_socket_type(SOCK_BOOLEAN, PROP_NONE));
-
+
nodeRegisterSocketType(make_standard_socket_type(SOCK_VECTOR, PROP_NONE));
nodeRegisterSocketType(make_standard_socket_type(SOCK_VECTOR, PROP_TRANSLATION));
nodeRegisterSocketType(make_standard_socket_type(SOCK_VECTOR, PROP_DIRECTION));
@@ -477,12 +477,12 @@ void register_standard_node_socket_types(void)
nodeRegisterSocketType(make_standard_socket_type(SOCK_VECTOR, PROP_ACCELERATION));
nodeRegisterSocketType(make_standard_socket_type(SOCK_VECTOR, PROP_EULER));
nodeRegisterSocketType(make_standard_socket_type(SOCK_VECTOR, PROP_XYZ));
-
+
nodeRegisterSocketType(make_standard_socket_type(SOCK_RGBA, PROP_NONE));
-
+
nodeRegisterSocketType(make_standard_socket_type(SOCK_STRING, PROP_NONE));
-
+
nodeRegisterSocketType(make_standard_socket_type(SOCK_SHADER, PROP_NONE));
-
+
nodeRegisterSocketType(make_socket_type_virtual());
}
diff --git a/source/blender/nodes/intern/node_util.c b/source/blender/nodes/intern/node_util.c
index 45409a2dfad..19529794c7c 100644
--- a/source/blender/nodes/intern/node_util.c
+++ b/source/blender/nodes/intern/node_util.c
@@ -165,10 +165,10 @@ static int node_count_links(bNodeTree *ntree, bNodeSocket *sock)
static bNodeSocket *node_find_linkable_socket(bNodeTree *ntree, bNode *node, bNodeSocket *cur)
{
/* link swapping: try to find a free slot with a matching name */
-
+
bNodeSocket *first = cur->in_out == SOCK_IN ? node->inputs.first : node->outputs.first;
bNodeSocket *sock;
-
+
sock = cur->next ? cur->next : first; /* wrap around the list end */
while (sock != cur) {
if (!nodeSocketIsHidden(sock) && node_link_socket_match(sock, cur)) {
@@ -177,7 +177,7 @@ static bNodeSocket *node_find_linkable_socket(bNodeTree *ntree, bNode *node, bNo
if (link_count + 1 <= sock->limit)
return sock; /* found a valid free socket we can swap to */
}
-
+
sock = sock->next ? sock->next : first; /* wrap around the list end */
}
return NULL;
@@ -187,18 +187,18 @@ void node_insert_link_default(bNodeTree *ntree, bNode *node, bNodeLink *link)
{
bNodeSocket *sock = link->tosock;
bNodeLink *tlink, *tlink_next;
-
+
/* inputs can have one link only, outputs can have unlimited links */
if (node != link->tonode)
return;
-
+
for (tlink = ntree->links.first; tlink; tlink = tlink_next) {
bNodeSocket *new_sock;
tlink_next = tlink->next;
-
+
if (sock != tlink->tosock)
continue;
-
+
new_sock = node_find_linkable_socket(ntree, node, sock);
if (new_sock && new_sock != sock) {
/* redirect existing link */
@@ -287,12 +287,12 @@ static bNodeSocket *select_internal_link_input(bNode *node, bNodeSocket *output)
int i;
int sel_priority = -1;
bool sel_is_linked = false;
-
+
for (input = node->inputs.first, i = 0; input; input = input->next, ++i) {
int priority = node_datatype_priority(input->type, output->type);
bool is_linked = (input->link != NULL);
bool preferred;
-
+
if (nodeSocketIsHidden(input) || /* ignore hidden sockets */
input->flag & SOCK_NO_INTERNAL_LINK || /* ignore if input is not allowed for internal connections */
priority < 0 || /* ignore incompatible types */
@@ -300,18 +300,18 @@ static bNodeSocket *select_internal_link_input(bNode *node, bNodeSocket *output)
{
continue;
}
-
+
/* determine if this input is preferred over the currently selected */
preferred = (priority > sel_priority) || /* prefer higher datatype priority */
(is_linked && !sel_is_linked); /* prefer linked over unlinked */
-
+
if (preferred) {
selected = input;
sel_is_linked = is_linked;
sel_priority = priority;
}
}
-
+
return selected;
}
@@ -319,29 +319,29 @@ void node_update_internal_links_default(bNodeTree *ntree, bNode *node)
{
bNodeLink *link;
bNodeSocket *output, *input;
-
+
/* sanity check */
if (!ntree)
return;
-
+
/* use link pointer as a tag for handled sockets (for outputs is unused anyway) */
for (output = node->outputs.first; output; output = output->next)
output->link = NULL;
-
+
for (link = ntree->links.first; link; link = link->next) {
if (nodeLinkIsHidden(link))
continue;
-
+
output = link->fromsock;
if (link->fromnode != node || output->link)
continue;
if (nodeSocketIsHidden(output) || output->flag & SOCK_NO_INTERNAL_LINK)
continue;
output->link = link; /* not really used, just for tagging handled sockets */
-
+
/* look for suitable input */
input = select_internal_link_input(node, output);
-
+
if (input) {
bNodeLink *ilink = MEM_callocN(sizeof(bNodeLink), "internal node link");
ilink->fromnode = node;
@@ -353,7 +353,7 @@ void node_update_internal_links_default(bNodeTree *ntree, bNode *node)
BLI_addtail(&node->internal_links, ilink);
}
}
-
+
/* clean up */
for (output = node->outputs.first; output; output = output->next)
output->link = NULL;
diff --git a/source/blender/nodes/shader/node_shader_tree.c b/source/blender/nodes/shader/node_shader_tree.c
index a5d8031f2f3..fcb21982661 100644
--- a/source/blender/nodes/shader/node_shader_tree.c
+++ b/source/blender/nodes/shader/node_shader_tree.c
@@ -82,7 +82,7 @@ static void shader_get_from_context(const bContext *C, bNodeTreeType *UNUSED(tre
Scene *scene = CTX_data_scene(C);
ViewLayer *view_layer = CTX_data_view_layer(C);
Object *ob = OBACT(view_layer);
-
+
if (snode->shaderfrom == SNODE_SHADER_OBJECT) {
if (ob) {
*r_from = &ob->id;
@@ -136,11 +136,11 @@ static void foreach_nodeclass(Scene *UNUSED(scene), void *calldata, bNodeClassCa
static void localize(bNodeTree *localtree, bNodeTree *UNUSED(ntree))
{
bNode *node, *node_next;
-
+
/* replace muted nodes and reroute nodes by internal links */
for (node = localtree->nodes.first; node; node = node_next) {
node_next = node->next;
-
+
if (node->flag & NODE_MUTED || node->type == NODE_REROUTE) {
nodeInternalRelink(localtree, node);
nodeFreeNode(localtree, node);
@@ -161,9 +161,9 @@ static void local_merge(bNodeTree *localtree, bNodeTree *ntree)
static void update(bNodeTree *ntree)
{
ntreeSetOutput(ntree);
-
+
ntree_update_reroute_nodes(ntree);
-
+
if (ntree->update & NTREE_UPDATE_NODES) {
/* clean up preview cache, in case nodes have been removed */
BKE_node_preview_remove_unused(ntree);
@@ -175,13 +175,13 @@ bNodeTreeType *ntreeType_Shader;
void register_node_tree_type_sh(void)
{
bNodeTreeType *tt = ntreeType_Shader = MEM_callocN(sizeof(bNodeTreeType), "shader node tree type");
-
+
tt->type = NTREE_SHADER;
strcpy(tt->idname, "ShaderNodeTree");
strcpy(tt->ui_name, "Shader Editor");
tt->ui_icon = 0; /* defined in drawnode.c */
strcpy(tt->ui_description, "Shader nodes");
-
+
tt->foreach_nodeclass = foreach_nodeclass;
tt->localize = localize;
tt->local_sync = local_sync;
@@ -189,9 +189,9 @@ void register_node_tree_type_sh(void)
tt->update = update;
tt->poll = shader_tree_poll;
tt->get_from_context = shader_get_from_context;
-
+
tt->ext.srna = &RNA_ShaderNodeTree;
-
+
ntreeTypeAdd(tt);
}
@@ -622,19 +622,19 @@ bNodeTreeExec *ntreeShaderBeginExecTree_internal(bNodeExecContext *context, bNod
{
bNodeTreeExec *exec;
bNode *node;
-
+
/* ensures only a single output node is enabled */
ntreeSetOutput(ntree);
-
+
/* common base initialization */
exec = ntree_exec_begin(context, ntree, parent_key);
-
+
/* allocate the thread stack listbase array */
exec->threadstack = MEM_callocN(BLENDER_MAX_THREADS * sizeof(ListBase), "thread stack array");
-
+
for (node = exec->nodetree->nodes.first; node; node = node->next)
node->need_exec = 1;
-
+
return exec;
}
@@ -642,22 +642,22 @@ bNodeTreeExec *ntreeShaderBeginExecTree(bNodeTree *ntree)
{
bNodeExecContext context;
bNodeTreeExec *exec;
-
+
/* XXX hack: prevent exec data from being generated twice.
* this should be handled by the renderer!
*/
if (ntree->execdata)
return ntree->execdata;
-
+
context.previews = ntree->previews;
-
+
exec = ntreeShaderBeginExecTree_internal(&context, ntree, NODE_INSTANCE_KEY_BASE);
-
+
/* XXX this should not be necessary, but is still used for cmp/sha/tex nodes,
* which only store the ntree pointer. Should be fixed at some point!
*/
ntree->execdata = exec;
-
+
return exec;
}
@@ -665,18 +665,18 @@ void ntreeShaderEndExecTree_internal(bNodeTreeExec *exec)
{
bNodeThreadStack *nts;
int a;
-
+
if (exec->threadstack) {
for (a = 0; a < BLENDER_MAX_THREADS; a++) {
for (nts = exec->threadstack[a].first; nts; nts = nts->next)
if (nts->stack) MEM_freeN(nts->stack);
BLI_freelistN(&exec->threadstack[a]);
}
-
+
MEM_freeN(exec->threadstack);
exec->threadstack = NULL;
}
-
+
ntree_exec_end(exec);
}
@@ -686,7 +686,7 @@ void ntreeShaderEndExecTree(bNodeTreeExec *exec)
/* exec may get freed, so assign ntree */
bNodeTree *ntree = exec->nodetree;
ntreeShaderEndExecTree_internal(exec);
-
+
/* XXX clear nodetree backpointer to exec data, same problem as noted in ntreeBeginExecTree */
ntree->execdata = NULL;
}
@@ -699,7 +699,7 @@ bool ntreeShaderExecTree(bNodeTree *ntree, int thread)
bNodeThreadStack *nts = NULL;
bNodeTreeExec *exec = ntree->execdata;
int compat;
-
+
/* ensure execdata is only initialized once */
if (!exec) {
BLI_thread_lock(LOCK_NODES);
@@ -709,11 +709,11 @@ bool ntreeShaderExecTree(bNodeTree *ntree, int thread)
exec = ntree->execdata;
}
-
+
nts = ntreeGetThreadStack(exec, thread);
compat = ntreeExecThreadNodes(exec, nts, &scd, thread);
ntreeReleaseThreadStack(nts);
-
+
/* if compat is zero, it has been using non-compatible nodes */
return compat;
}
diff --git a/source/blender/nodes/shader/node_shader_util.c b/source/blender/nodes/shader/node_shader_util.c
index 43e940d6d0a..a4b2c155675 100644
--- a/source/blender/nodes/shader/node_shader_util.c
+++ b/source/blender/nodes/shader/node_shader_util.c
@@ -45,7 +45,7 @@ int sh_node_poll_default(bNodeType *UNUSED(ntype), bNodeTree *ntree)
void sh_node_type_base(struct bNodeType *ntype, int type, const char *name, short nclass, short flag)
{
node_type_base(ntype, type, name, nclass, flag);
-
+
ntype->poll = sh_node_poll_default;
ntype->insert_link = node_insert_link_default;
ntype->update_internal_links = node_update_internal_links_default;
@@ -56,11 +56,11 @@ void sh_node_type_base(struct bNodeType *ntype, int type, const char *name, shor
void nodestack_get_vec(float *in, short type_in, bNodeStack *ns)
{
const float *from = ns->vec;
-
+
if (type_in == SOCK_FLOAT) {
if (ns->sockettype == SOCK_FLOAT)
*in = *from;
- else
+ else
*in = (from[0] + from[1] + from[2]) / 3.0f;
}
else if (type_in == SOCK_VECTOR) {
@@ -94,7 +94,7 @@ void nodestack_get_vec(float *in, short type_in, bNodeStack *ns)
void node_gpu_stack_from_data(struct GPUNodeStack *gs, int type, bNodeStack *ns)
{
memset(gs, 0, sizeof(*gs));
-
+
if (ns == NULL) {
/* node_get_stack() will generate NULL bNodeStack pointers for unknown/unsuported types of sockets... */
zero_v4(gs->vec);
@@ -107,7 +107,7 @@ void node_gpu_stack_from_data(struct GPUNodeStack *gs, int type, bNodeStack *ns)
else {
nodestack_get_vec(gs->vec, type, ns);
gs->link = ns->data;
-
+
if (type == SOCK_FLOAT)
gs->type = GPU_FLOAT;
else if (type == SOCK_VECTOR)
@@ -140,10 +140,10 @@ static void gpu_stack_from_data_list(GPUNodeStack *gs, ListBase *sockets, bNodeS
{
bNodeSocket *sock;
int i;
-
+
for (sock = sockets->first, i = 0; sock; sock = sock->next, i++)
node_gpu_stack_from_data(&gs[i], sock->type, ns[i]);
-
+
gs[i].end = true;
}
@@ -192,7 +192,7 @@ bNode *nodeGetActiveTexture(bNodeTree *ntree)
if (activetexnode)
return activetexnode;
-
+
if (hasgroup) {
/* node active texture node in this tree, look inside groups */
for (node = ntree->nodes.first; node; node = node->next) {
@@ -203,7 +203,7 @@ bNode *nodeGetActiveTexture(bNodeTree *ntree)
}
}
}
-
+
return inactivenode;
}
@@ -222,7 +222,7 @@ void ntreeExecGPUNodes(bNodeTreeExec *exec, GPUMaterial *mat, int do_outputs, sh
for (n = 0, nodeexec = exec->nodeexec; n < exec->totnodes; ++n, ++nodeexec) {
node = nodeexec->node;
-
+
do_it = false;
/* for groups, only execute outputs for edited group */
if (node->typeinfo->nclass == NODE_CLASS_OUTPUT) {
diff --git a/source/blender/nodes/shader/nodes/node_shader_brightness.c b/source/blender/nodes/shader/nodes/node_shader_brightness.c
index d795575c86a..bb95ed2d32c 100644
--- a/source/blender/nodes/shader/nodes/node_shader_brightness.c
+++ b/source/blender/nodes/shader/nodes/node_shader_brightness.c
@@ -50,13 +50,13 @@ static int gpu_shader_brightcontrast(GPUMaterial *mat, bNode *node, bNodeExecDat
void register_node_type_sh_brightcontrast(void)
{
static bNodeType ntype;
-
+
sh_node_type_base(&ntype, SH_NODE_BRIGHTCONTRAST, "Bright/Contrast", NODE_CLASS_OP_COLOR, 0);
node_type_compatibility(&ntype, NODE_NEW_SHADING);
node_type_socket_templates(&ntype, sh_node_brightcontrast_in, sh_node_brightcontrast_out);
node_type_init(&ntype, NULL);
node_type_storage(&ntype, "", NULL, NULL);
node_type_gpu(&ntype, gpu_shader_brightcontrast);
-
+
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_bump.c b/source/blender/nodes/shader/nodes/node_shader_bump.c
index 6098aefc5e1..6274d132bc7 100644
--- a/source/blender/nodes/shader/nodes/node_shader_bump.c
+++ b/source/blender/nodes/shader/nodes/node_shader_bump.c
@@ -31,7 +31,7 @@
#include "node_shader_util.h"
-/* **************** BUMP ******************** */
+/* **************** BUMP ******************** */
static bNodeSocketTemplate sh_node_bump_in[] = {
{ SOCK_FLOAT, 1, N_("Strength"), 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
{ SOCK_FLOAT, 1, N_("Distance"), 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1000.0f},
diff --git a/source/blender/nodes/shader/nodes/node_shader_common.c b/source/blender/nodes/shader/nodes/node_shader_common.c
index 134319cb352..24de03dbda4 100644
--- a/source/blender/nodes/shader/nodes/node_shader_common.c
+++ b/source/blender/nodes/shader/nodes/node_shader_common.c
@@ -50,7 +50,7 @@ static void copy_stack(bNodeStack *to, bNodeStack *from)
copy_v4_v4(to->vec, from->vec);
to->data = from->data;
to->datatype = from->datatype;
-
+
/* tag as copy to prevent freeing */
to->is_copy = 1;
}
@@ -63,7 +63,7 @@ static void move_stack(bNodeStack *to, bNodeStack *from)
to->data = from->data;
to->datatype = from->datatype;
to->is_copy = from->is_copy;
-
+
from->data = NULL;
from->is_copy = 0;
}
@@ -75,20 +75,20 @@ static void *group_initexec(bNodeExecContext *context, bNode *node, bNodeInstanc
{
bNodeTree *ngroup = (bNodeTree *)node->id;
bNodeTreeExec *exec;
-
+
if (!ngroup)
return NULL;
-
+
/* initialize the internal node tree execution */
exec = ntreeShaderBeginExecTree_internal(context, ngroup, key);
-
+
return exec;
}
static void group_freeexec(void *nodedata)
{
bNodeTreeExec *gexec = (bNodeTreeExec *)nodedata;
-
+
if (gexec)
ntreeShaderEndExecTree_internal(gexec);
}
@@ -102,7 +102,7 @@ static void group_copy_inputs(bNode *gnode, bNodeStack **in, bNodeStack *gstack)
bNodeSocket *sock;
bNodeStack *ns;
int a;
-
+
for (node = ngroup->nodes.first; node; node = node->next) {
if (node->type == NODE_GROUP_INPUT) {
for (sock = node->outputs.first, a = 0; sock; sock = sock->next, ++a) {
@@ -123,7 +123,7 @@ static void group_move_outputs(bNode *gnode, bNodeStack **out, bNodeStack *gstac
bNodeSocket *sock;
bNodeStack *ns;
int a;
-
+
for (node = ngroup->nodes.first; node; node = node->next) {
if (node->type == NODE_GROUP_OUTPUT && (node->flag & NODE_DO_OUTPUT)) {
for (sock = node->inputs.first, a = 0; sock; sock = sock->next, ++a) {
@@ -140,10 +140,10 @@ static void group_execute(void *data, int thread, struct bNode *node, bNodeExecD
{
bNodeTreeExec *exec = execdata->data;
bNodeThreadStack *nts;
-
+
if (!exec)
return;
-
+
/* XXX same behavior as trunk: all nodes inside group are executed.
* it's stupid, but just makes it work. compo redesign will do this better.
*/
@@ -152,13 +152,13 @@ static void group_execute(void *data, int thread, struct bNode *node, bNodeExecD
for (inode = exec->nodetree->nodes.first; inode; inode = inode->next)
inode->need_exec = 1;
}
-
+
nts = ntreeGetThreadStack(exec, thread);
-
+
group_copy_inputs(node, in, nts->stack);
ntreeExecThreadNodes(exec, nts, data, thread);
group_move_outputs(node, out, nts->stack);
-
+
ntreeReleaseThreadStack(nts);
}
@@ -169,7 +169,7 @@ static void group_gpu_copy_inputs(bNode *gnode, GPUNodeStack *in, bNodeStack *gs
bNodeSocket *sock;
bNodeStack *ns;
int a;
-
+
for (node = ngroup->nodes.first; node; node = node->next) {
if (node->type == NODE_GROUP_INPUT) {
for (sock = node->outputs.first, a = 0; sock; sock = sock->next, ++a) {
@@ -192,7 +192,7 @@ static void group_gpu_move_outputs(bNode *gnode, GPUNodeStack *out, bNodeStack *
bNodeSocket *sock;
bNodeStack *ns;
int a;
-
+
for (node = ngroup->nodes.first; node; node = node->next) {
if (node->type == NODE_GROUP_OUTPUT && (node->flag & NODE_DO_OUTPUT)) {
for (sock = node->inputs.first, a = 0; sock; sock = sock->next, ++a) {
@@ -210,10 +210,10 @@ static void group_gpu_move_outputs(bNode *gnode, GPUNodeStack *out, bNodeStack *
static int gpu_group_execute(GPUMaterial *mat, bNode *node, bNodeExecData *execdata, GPUNodeStack *in, GPUNodeStack *out)
{
bNodeTreeExec *exec = execdata->data;
-
+
if (!node->id)
return 0;
-
+
group_gpu_copy_inputs(node, in, exec->stack);
#if 0 /* XXX NODE_GROUP_EDIT is deprecated, depends on node space */
ntreeExecGPUNodes(exec, mat, (node->flag & NODE_GROUP_EDIT));
@@ -221,14 +221,14 @@ static int gpu_group_execute(GPUMaterial *mat, bNode *node, bNodeExecData *execd
ntreeExecGPUNodes(exec, mat, 0, NODE_NEW_SHADING | NODE_OLD_SHADING);
#endif
group_gpu_move_outputs(node, out, exec->stack);
-
+
return 1;
}
void register_node_type_sh_group(void)
{
static bNodeType ntype;
-
+
/* NB: cannot use sh_node_type_base for node group, because it would map the node type
* to the shared NODE_GROUP integer type id.
*/
@@ -241,7 +241,7 @@ void register_node_type_sh_group(void)
ntype.ext.srna = RNA_struct_find("ShaderNodeGroup");
BLI_assert(ntype.ext.srna != NULL);
RNA_struct_blender_type_set(ntype.ext.srna, &ntype);
-
+
node_type_compatibility(&ntype, NODE_OLD_SHADING | NODE_NEW_SHADING);
node_type_socket_templates(&ntype, NULL, NULL);
node_type_size(&ntype, 140, 60, 400);
@@ -249,6 +249,6 @@ void register_node_type_sh_group(void)
node_type_update(&ntype, NULL, node_group_verify);
node_type_exec(&ntype, group_initexec, group_freeexec, group_execute);
node_type_gpu(&ntype, gpu_group_execute);
-
+
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_curves.c b/source/blender/nodes/shader/nodes/node_shader_curves.c
index 5dfeb883915..4f3dc92ad02 100644
--- a/source/blender/nodes/shader/nodes/node_shader_curves.c
+++ b/source/blender/nodes/shader/nodes/node_shader_curves.c
@@ -48,7 +48,7 @@ static bNodeSocketTemplate sh_node_curve_vec_out[] = {
static void node_shader_exec_curve_vec(void *UNUSED(data), int UNUSED(thread), bNode *node, bNodeExecData *UNUSED(execdata), bNodeStack **in, bNodeStack **out)
{
float vec[3];
-
+
/* stack order input: vec */
/* stack order output: vec */
nodestack_get_vec(vec, SOCK_VECTOR, in[1]);
@@ -102,7 +102,7 @@ static void node_shader_exec_curve_rgb(void *UNUSED(data), int UNUSED(thread), b
{
float vec[3];
float fac;
-
+
/* stack order input: vec */
/* stack order output: vec */
nodestack_get_vec(&fac, SOCK_FLOAT, in[0]);
diff --git a/source/blender/nodes/shader/nodes/node_shader_fresnel.c b/source/blender/nodes/shader/nodes/node_shader_fresnel.c
index 599d0533c27..072abed6c16 100644
--- a/source/blender/nodes/shader/nodes/node_shader_fresnel.c
+++ b/source/blender/nodes/shader/nodes/node_shader_fresnel.c
@@ -47,7 +47,7 @@ static int node_shader_gpu_fresnel(GPUMaterial *mat, bNode *node, bNodeExecData
else {
GPU_link(mat, "direction_transform_m4v3", in[1].link, GPU_builtin(GPU_VIEW_MATRIX), &in[1].link);
}
-
+
return GPU_stack_link(mat, node, "node_fresnel", in, out, GPU_builtin(GPU_VIEW_POSITION));
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_gamma.c b/source/blender/nodes/shader/nodes/node_shader_gamma.c
index 2aedba58f2c..e536d198ed0 100644
--- a/source/blender/nodes/shader/nodes/node_shader_gamma.c
+++ b/source/blender/nodes/shader/nodes/node_shader_gamma.c
@@ -60,7 +60,7 @@ static int node_shader_gpu_gamma(GPUMaterial *mat, bNode *node, bNodeExecData *U
void register_node_type_sh_gamma(void)
{
static bNodeType ntype;
-
+
sh_node_type_base(&ntype, SH_NODE_GAMMA, "Gamma", NODE_CLASS_OP_COLOR, 0);
node_type_compatibility(&ntype, NODE_OLD_SHADING | NODE_NEW_SHADING);
node_type_socket_templates(&ntype, sh_node_gamma_in, sh_node_gamma_out);
@@ -68,6 +68,6 @@ void register_node_type_sh_gamma(void)
node_type_storage(&ntype, "", NULL, NULL);
node_type_exec(&ntype, NULL, NULL, node_shader_exec_gamma);
node_type_gpu(&ntype, node_shader_gpu_gamma);
-
+
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_geom.c b/source/blender/nodes/shader/nodes/node_shader_geom.c
new file mode 100644
index 00000000000..0a51ee8dc68
--- /dev/null
+++ b/source/blender/nodes/shader/nodes/node_shader_geom.c
@@ -0,0 +1,163 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2005 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/nodes/shader/nodes/node_shader_geom.c
+ * \ingroup shdnodes
+ */
+
+
+#include "node_shader_util.h"
+
+#include "DNA_customdata_types.h"
+
+/* **************** GEOMETRY ******************** */
+
+/* output socket type definition */
+static bNodeSocketTemplate sh_node_geom_out[] = {
+ { SOCK_VECTOR, 0, N_("Global")},
+ { SOCK_VECTOR, 0, N_("Local")},
+ { SOCK_VECTOR, 0, N_("View")},
+ { SOCK_VECTOR, 0, N_("Orco")},
+ { SOCK_VECTOR, 0, N_("UV")},
+ { SOCK_VECTOR, 0, N_("Normal")},
+ { SOCK_RGBA, 0, N_("Vertex Color")},
+ { SOCK_FLOAT, 0, N_("Vertex Alpha")},
+ { SOCK_FLOAT, 0, N_("Front/Back")},
+ { -1, 0, "" }
+};
+
+/* node execute callback */
+static void node_shader_exec_geom(void *data, int UNUSED(thread), bNode *node, bNodeExecData *UNUSED(execdata), bNodeStack **UNUSED(in), bNodeStack **out)
+{
+ if (data) {
+ ShadeInput *shi = ((ShaderCallData *)data)->shi;
+ NodeGeometry *ngeo = (NodeGeometry *)node->storage;
+ ShadeInputUV *suv = &shi->uv[shi->actuv];
+ static float defaultvcol[4] = {1.0f, 1.0f, 1.0f, 1.0f};
+ int i;
+
+ if (ngeo->uvname[0]) {
+ /* find uv map by name */
+ for (i = 0; i < shi->totuv; i++) {
+ if (STREQ(shi->uv[i].name, ngeo->uvname)) {
+ suv = &shi->uv[i];
+ break;
+ }
+ }
+ }
+
+ /* out: global, local, view, orco, uv, normal, vertex color */
+ copy_v3_v3(out[GEOM_OUT_GLOB]->vec, shi->gl);
+ copy_v3_v3(out[GEOM_OUT_LOCAL]->vec, shi->co);
+ copy_v3_v3(out[GEOM_OUT_VIEW]->vec, shi->view);
+ copy_v3_v3(out[GEOM_OUT_ORCO]->vec, shi->lo);
+ copy_v3_v3(out[GEOM_OUT_UV]->vec, suv->uv);
+ copy_v3_v3(out[GEOM_OUT_NORMAL]->vec, shi->vno);
+
+ if (shi->use_world_space_shading) {
+ negate_v3(out[GEOM_OUT_NORMAL]->vec);
+ mul_mat3_m4_v3((float (*)[4])RE_render_current_get_matrix(RE_VIEWINV_MATRIX), out[GEOM_OUT_NORMAL]->vec);
+ }
+ if (shi->totcol) {
+ /* find vertex color layer by name */
+ ShadeInputCol *scol = &shi->col[0];
+
+ if (ngeo->colname[0]) {
+ for (i = 0; i < shi->totcol; i++) {
+ if (STREQ(shi->col[i].name, ngeo->colname)) {
+ scol = &shi->col[i];
+ break;
+ }
+ }
+ }
+
+ srgb_to_linearrgb_v3_v3(out[GEOM_OUT_VCOL]->vec, scol->col);
+ out[GEOM_OUT_VCOL]->vec[3] = scol->col[3];
+ out[GEOM_OUT_VCOL_ALPHA]->vec[0] = scol->col[3];
+ }
+ else {
+ memcpy(out[GEOM_OUT_VCOL]->vec, defaultvcol, sizeof(defaultvcol));
+ out[GEOM_OUT_VCOL_ALPHA]->vec[0] = 1.0f;
+ }
+
+ if (shi->osatex) {
+ out[GEOM_OUT_GLOB]->data = shi->dxgl;
+ out[GEOM_OUT_GLOB]->datatype = NS_OSA_VECTORS;
+ out[GEOM_OUT_LOCAL]->data = shi->dxco;
+ out[GEOM_OUT_LOCAL]->datatype = NS_OSA_VECTORS;
+ out[GEOM_OUT_VIEW]->data = &shi->dxview;
+ out[GEOM_OUT_VIEW]->datatype = NS_OSA_VALUES;
+ out[GEOM_OUT_ORCO]->data = shi->dxlo;
+ out[GEOM_OUT_ORCO]->datatype = NS_OSA_VECTORS;
+ out[GEOM_OUT_UV]->data = suv->dxuv;
+ out[GEOM_OUT_UV]->datatype = NS_OSA_VECTORS;
+ out[GEOM_OUT_NORMAL]->data = shi->dxno;
+ out[GEOM_OUT_NORMAL]->datatype = NS_OSA_VECTORS;
+ }
+
+ /* front/back, normal flipping was stored */
+ out[GEOM_OUT_FRONTBACK]->vec[0] = (shi->flippednor) ? 0.0f : 1.0f;
+ }
+}
+
+static void node_shader_init_geometry(bNodeTree *UNUSED(ntree), bNode *node)
+{
+ node->storage = MEM_callocN(sizeof(NodeGeometry), "NodeGeometry");
+}
+
+static int gpu_shader_geom(GPUMaterial *mat, bNode *node, bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out)
+{
+ NodeGeometry *ngeo = (NodeGeometry *)node->storage;
+ GPUNodeLink *orco = GPU_attribute(CD_ORCO, "");
+ GPUNodeLink *mtface = GPU_attribute(CD_MTFACE, ngeo->uvname);
+ GPUNodeLink *mcol = GPU_attribute(CD_MCOL, ngeo->colname);
+
+ bool ret = GPU_stack_link(mat, "geom", in, out,
+ GPU_builtin(GPU_VIEW_POSITION), GPU_builtin(GPU_VIEW_NORMAL),
+ GPU_builtin(GPU_INVERSE_VIEW_MATRIX), orco, mtface, mcol);
+ if (GPU_material_use_world_space_shading(mat)) {
+ GPU_link(mat, "vec_math_negate", out[5].link, &out[5].link);
+ ret &= GPU_link(mat, "direction_transform_m4v3", out[5].link, GPU_builtin(GPU_INVERSE_VIEW_MATRIX), &out[5].link);
+ }
+ return ret;
+}
+
+/* node type definition */
+void register_node_type_sh_geom(void)
+{
+ static bNodeType ntype;
+
+ sh_node_type_base(&ntype, SH_NODE_GEOMETRY, "Geometry", NODE_CLASS_INPUT, 0);
+ node_type_compatibility(&ntype, NODE_OLD_SHADING);
+ node_type_socket_templates(&ntype, NULL, sh_node_geom_out);
+ node_type_init(&ntype, node_shader_init_geometry);
+ node_type_storage(&ntype, "NodeGeometry", node_free_standard_storage, node_copy_standard_storage);
+ node_type_exec(&ntype, NULL, NULL, node_shader_exec_geom);
+ node_type_gpu(&ntype, gpu_shader_geom);
+
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/shader/nodes/node_shader_hueSatVal.c b/source/blender/nodes/shader/nodes/node_shader_hueSatVal.c
index 0e82c962f53..07f1e9e3233 100644
--- a/source/blender/nodes/shader/nodes/node_shader_hueSatVal.c
+++ b/source/blender/nodes/shader/nodes/node_shader_hueSatVal.c
@@ -52,7 +52,7 @@ static void do_hue_sat_fac(bNode *UNUSED(node), float *out, float hue, float sat
{
if (fac != 0.0f && (hue != 0.5f || sat != 1.0f || val != 1.0f)) {
float col[3], hsv[3], mfac = 1.0f - fac;
-
+
rgb_to_hsv(in[0], in[1], in[2], hsv, hsv + 1, hsv + 2);
hsv[0] += (hue - 0.5f);
if (hsv[0] > 1.0f) hsv[0] -= 1.0f; else if (hsv[0] < 0.0f) hsv[0] += 1.0f;
diff --git a/source/blender/nodes/shader/nodes/node_shader_invert.c b/source/blender/nodes/shader/nodes/node_shader_invert.c
index c5765ae492b..b1805946f65 100644
--- a/source/blender/nodes/shader/nodes/node_shader_invert.c
+++ b/source/blender/nodes/shader/nodes/node_shader_invert.c
@@ -34,7 +34,7 @@
-/* **************** INVERT ******************** */
+/* **************** INVERT ******************** */
static bNodeSocketTemplate sh_node_invert_in[] = {
{ SOCK_FLOAT, 1, N_("Fac"), 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
{ SOCK_RGBA, 1, N_("Color"), 0.0f, 0.0f, 0.0f, 1.0f},
@@ -46,18 +46,18 @@ static bNodeSocketTemplate sh_node_invert_out[] = {
{ -1, 0, "" }
};
-static void node_shader_exec_invert(void *UNUSED(data), int UNUSED(thread), bNode *UNUSED(node), bNodeExecData *UNUSED(execdata), bNodeStack **in,
+static void node_shader_exec_invert(void *UNUSED(data), int UNUSED(thread), bNode *UNUSED(node), bNodeExecData *UNUSED(execdata), bNodeStack **in,
bNodeStack **out)
{
float col[3], icol[3], fac;
nodestack_get_vec(&fac, SOCK_FLOAT, in[0]);
nodestack_get_vec(col, SOCK_VECTOR, in[1]);
-
+
icol[0] = 1.0f - col[0];
icol[1] = 1.0f - col[1];
icol[2] = 1.0f - col[2];
-
+
/* if fac, blend result against original input */
if (fac < 1.0f)
interp_v3_v3v3(out[0]->vec, col, icol, fac);
diff --git a/source/blender/nodes/shader/nodes/node_shader_mapping.c b/source/blender/nodes/shader/nodes/node_shader_mapping.c
index 42d957977e3..fdbf23618ef 100644
--- a/source/blender/nodes/shader/nodes/node_shader_mapping.c
+++ b/source/blender/nodes/shader/nodes/node_shader_mapping.c
@@ -56,7 +56,7 @@ static void node_shader_exec_mapping(void *UNUSED(data), int UNUSED(thread), bNo
{
TexMapping *texmap = node->storage;
float *vec = out[0]->vec;
-
+
/* stack order input: vector */
/* stack order output: vector */
nodestack_get_vec(vec, SOCK_VECTOR, in[0]);
@@ -105,7 +105,7 @@ static int gpu_shader_mapping(GPUMaterial *mat, bNode *node, bNodeExecData *UNUS
void register_node_type_sh_mapping(void)
{
static bNodeType ntype;
-
+
sh_node_type_base(&ntype, SH_NODE_MAPPING, "Mapping", NODE_CLASS_OP_VECTOR, 0);
node_type_compatibility(&ntype, NODE_OLD_SHADING | NODE_NEW_SHADING);
node_type_socket_templates(&ntype, sh_node_mapping_in, sh_node_mapping_out);
@@ -114,6 +114,6 @@ void register_node_type_sh_mapping(void)
node_type_storage(&ntype, "TexMapping", node_free_standard_storage, node_copy_standard_storage);
node_type_exec(&ntype, node_shader_initexec_mapping, NULL, node_shader_exec_mapping);
node_type_gpu(&ntype, gpu_shader_mapping);
-
+
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_material.c b/source/blender/nodes/shader/nodes/node_shader_material.c
new file mode 100644
index 00000000000..8a73ddc1194
--- /dev/null
+++ b/source/blender/nodes/shader/nodes/node_shader_material.c
@@ -0,0 +1,374 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2005 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/nodes/shader/nodes/node_shader_material.c
+ * \ingroup shdnodes
+ */
+
+#include "node_shader_util.h"
+
+/* **************** MATERIAL ******************** */
+
+static bNodeSocketTemplate sh_node_material_in[] = {
+ { SOCK_RGBA, 1, N_("Color"), 0.0f, 0.0f, 0.0f, 1.0f},
+ { SOCK_RGBA, 1, N_("Spec"), 0.0f, 0.0f, 0.0f, 1.0f},
+ { SOCK_FLOAT, 1, N_("DiffuseIntensity"), 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, PROP_NONE},
+ { SOCK_VECTOR, 1, N_("Normal"), 0.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f, PROP_DIRECTION},
+ { -1, 0, "" }
+};
+
+static bNodeSocketTemplate sh_node_material_out[] = {
+ { SOCK_RGBA, 0, N_("Color")},
+ { SOCK_FLOAT, 0, N_("Alpha")},
+ { SOCK_VECTOR, 0, N_("Normal")},
+ { -1, 0, "" }
+};
+
+/* **************** EXTENDED MATERIAL ******************** */
+
+static bNodeSocketTemplate sh_node_material_ext_in[] = {
+ { SOCK_RGBA, 1, N_("Color"), 0.0f, 0.0f, 0.0f, 1.0f},
+ { SOCK_RGBA, 1, N_("Spec"), 0.0f, 0.0f, 0.0f, 1.0f},
+ { SOCK_FLOAT, 1, N_("DiffuseIntensity"), 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, PROP_NONE},
+ { SOCK_VECTOR, 1, N_("Normal"), 0.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f, PROP_DIRECTION},
+ { SOCK_RGBA, 1, N_("Mirror"), 0.0f, 0.0f, 0.0f, 1.0f},
+ { SOCK_FLOAT, 1, N_("Ambient"), 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, PROP_NONE},
+ { SOCK_FLOAT, 1, N_("Emit"), 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, PROP_UNSIGNED},
+ { SOCK_FLOAT, 1, N_("SpecTra"), 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, PROP_NONE},
+ { SOCK_FLOAT, 1, N_("Reflectivity"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_NONE},
+ { SOCK_FLOAT, 1, N_("Alpha"), 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, PROP_UNSIGNED},
+ { SOCK_FLOAT, 1, N_("Translucency"), 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, PROP_NONE},
+ { -1, 0, "" }
+};
+
+static bNodeSocketTemplate sh_node_material_ext_out[] = {
+ { SOCK_RGBA, 0, N_("Color")},
+ { SOCK_FLOAT, 0, N_("Alpha")},
+ { SOCK_VECTOR, 0, N_("Normal")},
+ { SOCK_RGBA, 0, N_("Diffuse")},
+ { SOCK_RGBA, 0, N_("Spec")},
+ { SOCK_RGBA, 0, N_("AO")},
+ { -1, 0, "" }
+};
+
+static void node_shader_exec_material(void *data, int UNUSED(thread), bNode *node, bNodeExecData *execdata, bNodeStack **in, bNodeStack **out)
+{
+ if (data && node->id) {
+ ShadeResult shrnode;
+ ShadeInput *shi;
+ ShaderCallData *shcd = data;
+ float col[4];
+ bNodeSocket *sock;
+ char hasinput[NUM_MAT_IN] = {'\0'};
+ int i, mode;
+
+ /* note: cannot use the in[]->hasinput flags directly, as these are not necessarily
+ * the constant input stack values (e.g. in case material node is inside a group).
+ * we just want to know if a node input uses external data or the material setting.
+ * this is an ugly hack, but so is this node as a whole.
+ */
+ for (sock = node->inputs.first, i = 0; sock; sock = sock->next, ++i)
+ hasinput[i] = (sock->link != NULL);
+
+ shi = shcd->shi;
+ shi->mat = (Material *)node->id;
+
+ /* copy all relevant material vars, note, keep this synced with render_types.h */
+ memcpy(&shi->r, &shi->mat->r, 23 * sizeof(float));
+ shi->har = shi->mat->har;
+
+ /* write values */
+ if (hasinput[MAT_IN_COLOR])
+ nodestack_get_vec(&shi->r, SOCK_VECTOR, in[MAT_IN_COLOR]);
+
+ if (hasinput[MAT_IN_SPEC])
+ nodestack_get_vec(&shi->specr, SOCK_VECTOR, in[MAT_IN_SPEC]);
+
+ if (hasinput[MAT_IN_REFL])
+ nodestack_get_vec(&shi->refl, SOCK_FLOAT, in[MAT_IN_REFL]);
+
+ /* retrieve normal */
+ if (hasinput[MAT_IN_NORMAL]) {
+ nodestack_get_vec(shi->vn, SOCK_VECTOR, in[MAT_IN_NORMAL]);
+ if (shi->use_world_space_shading) {
+ negate_v3(shi->vn);
+ mul_mat3_m4_v3((float (*)[4])RE_render_current_get_matrix(RE_VIEW_MATRIX), shi->vn);
+ }
+ normalize_v3(shi->vn);
+ }
+ else
+ copy_v3_v3(shi->vn, shi->vno);
+
+ /* custom option to flip normal */
+ if (node->custom1 & SH_NODE_MAT_NEG) {
+ negate_v3(shi->vn);
+ }
+
+ if (node->type == SH_NODE_MATERIAL_EXT) {
+ if (hasinput[MAT_IN_MIR])
+ nodestack_get_vec(&shi->mirr, SOCK_VECTOR, in[MAT_IN_MIR]);
+ if (hasinput[MAT_IN_AMB])
+ nodestack_get_vec(&shi->amb, SOCK_FLOAT, in[MAT_IN_AMB]);
+ if (hasinput[MAT_IN_EMIT])
+ nodestack_get_vec(&shi->emit, SOCK_FLOAT, in[MAT_IN_EMIT]);
+ if (hasinput[MAT_IN_SPECTRA])
+ nodestack_get_vec(&shi->spectra, SOCK_FLOAT, in[MAT_IN_SPECTRA]);
+ if (hasinput[MAT_IN_RAY_MIRROR])
+ nodestack_get_vec(&shi->ray_mirror, SOCK_FLOAT, in[MAT_IN_RAY_MIRROR]);
+ if (hasinput[MAT_IN_ALPHA])
+ nodestack_get_vec(&shi->alpha, SOCK_FLOAT, in[MAT_IN_ALPHA]);
+ if (hasinput[MAT_IN_TRANSLUCENCY])
+ nodestack_get_vec(&shi->translucency, SOCK_FLOAT, in[MAT_IN_TRANSLUCENCY]);
+ }
+
+ /* make alpha output give results even if transparency is only enabled on
+ * the material linked in this not and not on the parent material */
+ mode = shi->mode;
+ if (shi->mat->mode & MA_TRANSP)
+ shi->mode |= MA_TRANSP;
+
+ shi->nodes = 1; /* temp hack to prevent trashadow recursion */
+ node_shader_lamp_loop(shi, &shrnode); /* clears shrnode */
+ shi->nodes = 0;
+
+ shi->mode = mode;
+
+ /* write to outputs */
+ if (node->custom1 & SH_NODE_MAT_DIFF) {
+ copy_v3_v3(col, shrnode.combined);
+ if (!(node->custom1 & SH_NODE_MAT_SPEC)) {
+ sub_v3_v3(col, shrnode.spec);
+ }
+ }
+ else if (node->custom1 & SH_NODE_MAT_SPEC) {
+ copy_v3_v3(col, shrnode.spec);
+ }
+ else
+ col[0] = col[1] = col[2] = 0.0f;
+
+ col[3] = shrnode.alpha;
+
+ if (shi->do_preview)
+ BKE_node_preview_set_pixel(execdata->preview, col, shi->xs, shi->ys, shi->do_manage);
+
+ copy_v3_v3(out[MAT_OUT_COLOR]->vec, col);
+ out[MAT_OUT_ALPHA]->vec[0] = shrnode.alpha;
+
+ if (node->custom1 & SH_NODE_MAT_NEG) {
+ shi->vn[0] = -shi->vn[0];
+ shi->vn[1] = -shi->vn[1];
+ shi->vn[2] = -shi->vn[2];
+ }
+
+ copy_v3_v3(out[MAT_OUT_NORMAL]->vec, shi->vn);
+
+ if (shi->use_world_space_shading) {
+ negate_v3(out[MAT_OUT_NORMAL]->vec);
+ mul_mat3_m4_v3((float (*)[4])RE_render_current_get_matrix(RE_VIEWINV_MATRIX), out[MAT_OUT_NORMAL]->vec);
+ }
+ /* Extended material options */
+ if (node->type == SH_NODE_MATERIAL_EXT) {
+ /* Shadow, Reflect, Refract, Radiosity, Speed seem to cause problems inside
+ * a node tree :( */
+ copy_v3_v3(out[MAT_OUT_DIFFUSE]->vec, shrnode.diffshad);
+ copy_v3_v3(out[MAT_OUT_SPEC]->vec, shrnode.spec);
+ copy_v3_v3(out[MAT_OUT_AO]->vec, shrnode.ao);
+ }
+
+ /* copy passes, now just active node */
+ if (node->flag & NODE_ACTIVE_ID) {
+ float combined[4], alpha;
+
+ copy_v4_v4(combined, shcd->shr->combined);
+ alpha = shcd->shr->alpha;
+
+ *(shcd->shr) = shrnode;
+
+ copy_v4_v4(shcd->shr->combined, combined);
+ shcd->shr->alpha = alpha;
+ }
+ }
+}
+
+
+static void node_shader_init_material(bNodeTree *UNUSED(ntree), bNode *node)
+{
+ node->custom1 = SH_NODE_MAT_DIFF | SH_NODE_MAT_SPEC;
+}
+
+/* XXX this is also done as a local static function in gpu_codegen.c,
+ * but we need this to hack around the crappy material node.
+ */
+static GPUNodeLink *gpu_get_input_link(GPUMaterial *mat, GPUNodeStack *in)
+{
+ if (in->link) {
+ return in->link;
+ }
+ else {
+ GPUNodeLink *result = NULL;
+
+ /* note GPU_uniform() is only intended to be used as a parameter to
+ * GPU_link(), returning it directly results in leaks or double frees */
+ if (in->type == GPU_FLOAT)
+ GPU_link(mat, "set_value", GPU_uniform(in->vec), &result);
+ else if (in->type == GPU_VEC3)
+ GPU_link(mat, "set_rgb", GPU_uniform(in->vec), &result);
+ else if (in->type == GPU_VEC4)
+ GPU_link(mat, "set_rgba", GPU_uniform(in->vec), &result);
+ else
+ BLI_assert(0);
+
+ return result;
+ }
+}
+
+static int gpu_shader_material(GPUMaterial *mat, bNode *node, bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out)
+{
+ if (node->id) {
+ GPUShadeInput shi;
+ GPUShadeResult shr;
+ bNodeSocket *sock;
+ char hasinput[NUM_MAT_IN] = {'\0'};
+ int i;
+
+ /* note: cannot use the in[]->hasinput flags directly, as these are not necessarily
+ * the constant input stack values (e.g. in case material node is inside a group).
+ * we just want to know if a node input uses external data or the material setting.
+ */
+ for (sock = node->inputs.first, i = 0; sock; sock = sock->next, ++i)
+ hasinput[i] = (sock->link != NULL);
+
+ GPU_shadeinput_set(mat, (Material *)node->id, &shi);
+
+ /* write values */
+ if (hasinput[MAT_IN_COLOR])
+ shi.rgb = gpu_get_input_link(mat, &in[MAT_IN_COLOR]);
+
+ if (hasinput[MAT_IN_SPEC])
+ shi.specrgb = gpu_get_input_link(mat, &in[MAT_IN_SPEC]);
+
+ if (hasinput[MAT_IN_REFL])
+ shi.refl = gpu_get_input_link(mat, &in[MAT_IN_REFL]);
+
+ /* retrieve normal */
+ if (hasinput[MAT_IN_NORMAL]) {
+ GPUNodeLink *tmp;
+ shi.vn = gpu_get_input_link(mat, &in[MAT_IN_NORMAL]);
+ if (GPU_material_use_world_space_shading(mat)) {
+ GPU_link(mat, "vec_math_negate", shi.vn, &shi.vn);
+ GPU_link(mat, "direction_transform_m4v3", shi.vn, GPU_builtin(GPU_VIEW_MATRIX), &shi.vn);
+ }
+ GPU_link(mat, "vec_math_normalize", shi.vn, &shi.vn, &tmp);
+ }
+
+ /* custom option to flip normal */
+ if (node->custom1 & SH_NODE_MAT_NEG)
+ GPU_link(mat, "vec_math_negate", shi.vn, &shi.vn);
+
+ if (node->type == SH_NODE_MATERIAL_EXT) {
+ if (hasinput[MAT_IN_MIR])
+ shi.mir = gpu_get_input_link(mat, &in[MAT_IN_MIR]);
+ if (hasinput[MAT_IN_AMB])
+ shi.amb = gpu_get_input_link(mat, &in[MAT_IN_AMB]);
+ if (hasinput[MAT_IN_EMIT])
+ shi.emit = gpu_get_input_link(mat, &in[MAT_IN_EMIT]);
+ if (hasinput[MAT_IN_SPECTRA])
+ shi.spectra = gpu_get_input_link(mat, &in[MAT_IN_SPECTRA]);
+ if (hasinput[MAT_IN_ALPHA])
+ shi.alpha = gpu_get_input_link(mat, &in[MAT_IN_ALPHA]);
+ }
+
+ GPU_shaderesult_set(&shi, &shr); /* clears shr */
+
+ /* write to outputs */
+ if (node->custom1 & SH_NODE_MAT_DIFF) {
+ out[MAT_OUT_COLOR].link = shr.combined;
+
+ if (!(node->custom1 & SH_NODE_MAT_SPEC)) {
+ GPUNodeLink *link;
+ GPU_link(mat, "vec_math_sub", shr.combined, shr.spec, &out[MAT_OUT_COLOR].link, &link);
+ }
+ }
+ else if (node->custom1 & SH_NODE_MAT_SPEC) {
+ out[MAT_OUT_COLOR].link = shr.spec;
+ }
+ else
+ GPU_link(mat, "set_rgb_zero", &out[MAT_OUT_COLOR].link);
+
+ GPU_link(mat, "mtex_alpha_to_col", out[MAT_OUT_COLOR].link, shr.alpha, &out[MAT_OUT_COLOR].link);
+
+ out[MAT_OUT_ALPHA].link = shr.alpha; //
+
+ if (node->custom1 & SH_NODE_MAT_NEG)
+ GPU_link(mat, "vec_math_negate", shi.vn, &shi.vn);
+ out[MAT_OUT_NORMAL].link = shi.vn;
+ if (GPU_material_use_world_space_shading(mat)) {
+ GPU_link(mat, "vec_math_negate", out[MAT_OUT_NORMAL].link, &out[MAT_OUT_NORMAL].link);
+ GPU_link(mat, "direction_transform_m4v3", out[MAT_OUT_NORMAL].link, GPU_builtin(GPU_INVERSE_VIEW_MATRIX), &out[MAT_OUT_NORMAL].link);
+ }
+
+ if (node->type == SH_NODE_MATERIAL_EXT) {
+ out[MAT_OUT_DIFFUSE].link = shr.diff;
+ out[MAT_OUT_SPEC].link = shr.spec;
+ GPU_link(mat, "set_rgb_one", &out[MAT_OUT_AO].link);
+ }
+
+ return 1;
+ }
+
+ return 0;
+}
+
+void register_node_type_sh_material(void)
+{
+ static bNodeType ntype;
+
+ sh_node_type_base(&ntype, SH_NODE_MATERIAL, "Material", NODE_CLASS_INPUT, NODE_PREVIEW);
+ node_type_compatibility(&ntype, NODE_OLD_SHADING);
+ node_type_socket_templates(&ntype, sh_node_material_in, sh_node_material_out);
+ node_type_init(&ntype, node_shader_init_material);
+ node_type_exec(&ntype, NULL, NULL, node_shader_exec_material);
+ node_type_gpu(&ntype, gpu_shader_material);
+
+ nodeRegisterType(&ntype);
+}
+
+
+void register_node_type_sh_material_ext(void)
+{
+ static bNodeType ntype;
+
+ sh_node_type_base(&ntype, SH_NODE_MATERIAL_EXT, "Extended Material", NODE_CLASS_INPUT, NODE_PREVIEW);
+ node_type_compatibility(&ntype, NODE_OLD_SHADING);
+ node_type_socket_templates(&ntype, sh_node_material_ext_in, sh_node_material_ext_out);
+ node_type_init(&ntype, node_shader_init_material);
+ node_type_size_preset(&ntype, NODE_SIZE_MIDDLE);
+ node_type_exec(&ntype, NULL, NULL, node_shader_exec_material);
+ node_type_gpu(&ntype, gpu_shader_material);
+
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/shader/nodes/node_shader_math.c b/source/blender/nodes/shader/nodes/node_shader_math.c
index 2be70b66b36..bf594325119 100644
--- a/source/blender/nodes/shader/nodes/node_shader_math.c
+++ b/source/blender/nodes/shader/nodes/node_shader_math.c
@@ -33,7 +33,7 @@
#include "node_shader_util.h"
-/* **************** SCALAR MATH ******************** */
+/* **************** SCALAR MATH ******************** */
static bNodeSocketTemplate sh_node_math_in[] = {
{ SOCK_FLOAT, 1, N_("Value"), 0.5f, 0.5f, 0.5f, 1.0f, -10000.0f, 10000.0f, PROP_NONE},
{ SOCK_FLOAT, 1, N_("Value"), 0.5f, 0.5f, 0.5f, 1.0f, -10000.0f, 10000.0f, PROP_NONE},
@@ -45,15 +45,15 @@ static bNodeSocketTemplate sh_node_math_out[] = {
{ -1, 0, "" }
};
-static void node_shader_exec_math(void *UNUSED(data), int UNUSED(thread), bNode *node, bNodeExecData *UNUSED(execdata), bNodeStack **in, bNodeStack **out)
+static void node_shader_exec_math(void *UNUSED(data), int UNUSED(thread), bNode *node, bNodeExecData *UNUSED(execdata), bNodeStack **in, bNodeStack **out)
{
float a, b, r = 0.0f;
-
+
nodestack_get_vec(&a, SOCK_FLOAT, in[0]);
nodestack_get_vec(&b, SOCK_FLOAT, in[1]);
-
+
switch (node->custom1) {
-
+
case NODE_MATH_ADD:
r = a + b;
break;
@@ -147,7 +147,7 @@ static void node_shader_exec_math(void *UNUSED(data), int UNUSED(thread), bNode
}
else {
float y_mod_1 = fabsf(fmodf(b, 1.0f));
-
+
/* if input value is not nearly an integer, fall back to zero, nicer than straight rounding */
if (y_mod_1 > 0.999f || y_mod_1 < 0.001f) {
r = powf(a, floorf(b + 0.5f));
diff --git a/source/blender/nodes/shader/nodes/node_shader_mixRgb.c b/source/blender/nodes/shader/nodes/node_shader_mixRgb.c
index 37ec4d46226..054b02b220d 100644
--- a/source/blender/nodes/shader/nodes/node_shader_mixRgb.c
+++ b/source/blender/nodes/shader/nodes/node_shader_mixRgb.c
@@ -54,7 +54,7 @@ static void node_shader_exec_mix_rgb(void *UNUSED(data), int UNUSED(thread), bNo
nodestack_get_vec(&fac, SOCK_FLOAT, in[0]);
CLAMP(fac, 0.0f, 1.0f);
-
+
nodestack_get_vec(col, SOCK_VECTOR, in[1]);
nodestack_get_vec(vec, SOCK_VECTOR, in[2]);
diff --git a/source/blender/nodes/shader/nodes/node_shader_normal.c b/source/blender/nodes/shader/nodes/node_shader_normal.c
index 4bca5add106..265f6ac6fab 100644
--- a/source/blender/nodes/shader/nodes/node_shader_normal.c
+++ b/source/blender/nodes/shader/nodes/node_shader_normal.c
@@ -48,12 +48,12 @@ static bNodeSocketTemplate sh_node_normal_out[] = {
static void node_shader_exec_normal(void *UNUSED(data), int UNUSED(thread), bNode *UNUSED(node), bNodeExecData *UNUSED(execdata), bNodeStack **in, bNodeStack **out)
{
float vec[3];
-
+
/* stack order input: normal */
/* stack order output: normal, value */
-
+
nodestack_get_vec(vec, SOCK_VECTOR, in[0]);
-
+
/* render normals point inside... the widget points outside */
out[1]->vec[0] = -dot_v3v3(vec, out[0]->vec);
}
@@ -67,12 +67,12 @@ static int gpu_shader_normal(GPUMaterial *mat, bNode *node, bNodeExecData *UNUSE
void register_node_type_sh_normal(void)
{
static bNodeType ntype;
-
+
sh_node_type_base(&ntype, SH_NODE_NORMAL, "Normal", NODE_CLASS_OP_VECTOR, 0);
node_type_compatibility(&ntype, NODE_OLD_SHADING | NODE_NEW_SHADING);
node_type_socket_templates(&ntype, sh_node_normal_in, sh_node_normal_out);
node_type_exec(&ntype, NULL, NULL, node_shader_exec_normal);
node_type_gpu(&ntype, gpu_shader_normal);
-
+
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_output.c b/source/blender/nodes/shader/nodes/node_shader_output.c
new file mode 100644
index 00000000000..5b1a68b4bf9
--- /dev/null
+++ b/source/blender/nodes/shader/nodes/node_shader_output.c
@@ -0,0 +1,97 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2005 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/nodes/shader/nodes/node_shader_output.c
+ * \ingroup shdnodes
+ */
+
+
+#include "node_shader_util.h"
+
+/* **************** OUTPUT ******************** */
+static bNodeSocketTemplate sh_node_output_in[] = {
+ { SOCK_RGBA, 1, N_("Color"), 0.0f, 0.0f, 0.0f, 1.0f},
+ { SOCK_FLOAT, 1, N_("Alpha"), 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_NONE},
+ { -1, 0, "" }
+};
+
+static void node_shader_exec_output(void *data, int UNUSED(thread), bNode *node, bNodeExecData *execdata, bNodeStack **in, bNodeStack **UNUSED(out))
+{
+ if (data) {
+ ShadeInput *shi = ((ShaderCallData *)data)->shi;
+ float col[4];
+
+ /* stack order input sockets: col, alpha, normal */
+ nodestack_get_vec(col, SOCK_VECTOR, in[0]);
+ nodestack_get_vec(col + 3, SOCK_FLOAT, in[1]);
+
+ if (shi->do_preview) {
+ BKE_node_preview_set_pixel(execdata->preview, col, shi->xs, shi->ys, shi->do_manage);
+ node->lasty = shi->ys;
+ }
+
+ if (node->flag & NODE_DO_OUTPUT) {
+ ShadeResult *shr = ((ShaderCallData *)data)->shr;
+
+ copy_v4_v4(shr->combined, col);
+ shr->alpha = col[3];
+
+ // copy_v3_v3(shr->nor, in[3]->vec);
+ }
+ }
+}
+
+static int gpu_shader_output(GPUMaterial *mat, bNode *UNUSED(node), bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out)
+{
+ GPUNodeLink *outlink;
+
+#if 0
+ if (in[1].hasinput)
+ GPU_material_enable_alpha(mat);
+#endif
+
+ GPU_stack_link(mat, "output_node", in, out, &outlink);
+ GPU_material_output_link(mat, outlink);
+
+ return 1;
+}
+
+void register_node_type_sh_output(void)
+{
+ static bNodeType ntype;
+
+ sh_node_type_base(&ntype, SH_NODE_OUTPUT, "Output", NODE_CLASS_OUTPUT, NODE_PREVIEW);
+ node_type_compatibility(&ntype, NODE_OLD_SHADING);
+ node_type_socket_templates(&ntype, sh_node_output_in, NULL);
+ node_type_exec(&ntype, NULL, NULL, node_shader_exec_output);
+ node_type_gpu(&ntype, gpu_shader_output);
+
+ /* Do not allow muting output node. */
+ node_type_internal_links(&ntype, NULL);
+
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/shader/nodes/node_shader_output_world.c b/source/blender/nodes/shader/nodes/node_shader_output_world.c
index 17b4bfb6de6..2c115bdda20 100644
--- a/source/blender/nodes/shader/nodes/node_shader_output_world.c
+++ b/source/blender/nodes/shader/nodes/node_shader_output_world.c
@@ -56,7 +56,7 @@ void register_node_type_sh_output_world(void)
node_type_init(&ntype, NULL);
node_type_storage(&ntype, "", NULL, NULL);
node_type_gpu(&ntype, node_shader_gpu_output_world);
-
+
/* Do not allow muting output node. */
node_type_internal_links(&ntype, NULL);
diff --git a/source/blender/nodes/shader/nodes/node_shader_sepcombHSV.c b/source/blender/nodes/shader/nodes/node_shader_sepcombHSV.c
index 19f31f77989..148f8e99c8f 100644
--- a/source/blender/nodes/shader/nodes/node_shader_sepcombHSV.c
+++ b/source/blender/nodes/shader/nodes/node_shader_sepcombHSV.c
@@ -48,7 +48,7 @@ static void node_shader_exec_sephsv(void *UNUSED(data), int UNUSED(thread), bNod
{
float col[3];
nodestack_get_vec(col, SOCK_VECTOR, in[0]);
-
+
rgb_to_hsv(col[0], col[1], col[2],
&out[0]->vec[0], &out[1]->vec[0], &out[2]->vec[0]);
}
@@ -90,7 +90,7 @@ static void node_shader_exec_combhsv(void *UNUSED(data), int UNUSED(thread), bNo
nodestack_get_vec(&h, SOCK_FLOAT, in[0]);
nodestack_get_vec(&s, SOCK_FLOAT, in[1]);
nodestack_get_vec(&v, SOCK_FLOAT, in[2]);
-
+
hsv_to_rgb(h, s, v, &out[0]->vec[0], &out[0]->vec[1], &out[0]->vec[2]);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_sepcombRGB.c b/source/blender/nodes/shader/nodes/node_shader_sepcombRGB.c
index 3f866af5de4..bd914399a28 100644
--- a/source/blender/nodes/shader/nodes/node_shader_sepcombRGB.c
+++ b/source/blender/nodes/shader/nodes/node_shader_sepcombRGB.c
@@ -48,7 +48,7 @@ static void node_shader_exec_seprgb(void *UNUSED(data), int UNUSED(thread), bNod
{
float col[3];
nodestack_get_vec(col, SOCK_VECTOR, in[0]);
-
+
out[0]->vec[0] = col[0];
out[1]->vec[0] = col[1];
out[2]->vec[0] = col[2];
@@ -92,7 +92,7 @@ static void node_shader_exec_combrgb(void *UNUSED(data), int UNUSED(thread), bNo
nodestack_get_vec(&r, SOCK_FLOAT, in[0]);
nodestack_get_vec(&g, SOCK_FLOAT, in[1]);
nodestack_get_vec(&b, SOCK_FLOAT, in[2]);
-
+
out[0]->vec[0] = r;
out[0]->vec[1] = g;
out[0]->vec[2] = b;
diff --git a/source/blender/nodes/shader/nodes/node_shader_squeeze.c b/source/blender/nodes/shader/nodes/node_shader_squeeze.c
index 2175a7c564f..e46494efd34 100644
--- a/source/blender/nodes/shader/nodes/node_shader_squeeze.c
+++ b/source/blender/nodes/shader/nodes/node_shader_squeeze.c
@@ -32,7 +32,7 @@
#include "node_shader_util.h"
-/* **************** VALUE SQUEEZE ******************** */
+/* **************** VALUE SQUEEZE ******************** */
static bNodeSocketTemplate sh_node_squeeze_in[] = {
{ SOCK_FLOAT, 1, N_("Value"), 0.0f, 0.0f, 0.0f, 0.0f, -100.0f, 100.0f, PROP_NONE},
{ SOCK_FLOAT, 1, N_("Width"), 1.0f, 0.0f, 0.0f, 0.0f, -100.0f, 100.0f, PROP_NONE},
@@ -48,7 +48,7 @@ static bNodeSocketTemplate sh_node_squeeze_out[] = {
static void node_shader_exec_squeeze(void *UNUSED(data), int UNUSED(thread), bNode *UNUSED(node), bNodeExecData *UNUSED(execdata), bNodeStack **in, bNodeStack **out)
{
float vec[3];
-
+
nodestack_get_vec(vec, SOCK_FLOAT, in[0]);
nodestack_get_vec(vec + 1, SOCK_FLOAT, in[1]);
nodestack_get_vec(vec + 2, SOCK_FLOAT, in[2]);
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 c919f8efa4e..67fe6d08ffd 100644
--- a/source/blender/nodes/shader/nodes/node_shader_tex_brick.c
+++ b/source/blender/nodes/shader/nodes/node_shader_tex_brick.c
@@ -54,7 +54,7 @@ static void node_shader_init_tex_brick(bNodeTree *UNUSED(ntree), bNode *node)
NodeTexBrick *tex = MEM_callocN(sizeof(NodeTexBrick), "NodeTexBrick");
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;
tex->offset_freq = 2;
diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_coord.c b/source/blender/nodes/shader/nodes/node_shader_tex_coord.c
index 111a9cbfbc0..360b28d768a 100644
--- a/source/blender/nodes/shader/nodes/node_shader_tex_coord.c
+++ b/source/blender/nodes/shader/nodes/node_shader_tex_coord.c
@@ -49,7 +49,7 @@ static int node_shader_gpu_tex_coord(GPUMaterial *mat, bNode *node, bNodeExecDat
GPUMatType type = GPU_Material_get_type(mat);
GPU_link(mat, "generated_from_orco", orco, &orco);
-
+
if (type == GPU_MATERIAL_TYPE_WORLD) {
return GPU_stack_link(mat, node, "node_tex_coord_background", in, out,
GPU_builtin(GPU_VIEW_POSITION), GPU_builtin(GPU_VIEW_NORMAL),
@@ -59,7 +59,7 @@ static int node_shader_gpu_tex_coord(GPUMaterial *mat, bNode *node, bNodeExecDat
else {
return GPU_stack_link(mat, node, "node_tex_coord", in, out,
GPU_builtin(GPU_VIEW_POSITION), GPU_builtin(GPU_VIEW_NORMAL),
- GPU_builtin(GPU_INVERSE_VIEW_MATRIX), GPU_builtin(GPU_INVERSE_OBJECT_MATRIX),
+ GPU_builtin(GPU_INVERSE_VIEW_MATRIX), GPU_builtin(GPU_INVERSE_OBJECT_MATRIX),
GPU_builtin(GPU_CAMERA_TEXCO_FACTORS), orco, mtface);
}
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_environment.c b/source/blender/nodes/shader/nodes/node_shader_tex_environment.c
index 378da163f64..d441a674838 100644
--- a/source/blender/nodes/shader/nodes/node_shader_tex_environment.c
+++ b/source/blender/nodes/shader/nodes/node_shader_tex_environment.c
@@ -66,20 +66,20 @@ static int node_shader_gpu_tex_environment(GPUMaterial *mat, bNode *node, bNodeE
if (!in[0].link) {
GPUMatType type = GPU_Material_get_type(mat);
-
+
if (type == GPU_MATERIAL_TYPE_MESH)
in[0].link = GPU_builtin(GPU_VIEW_POSITION);
else
GPU_link(mat, "background_transform_to_world", GPU_builtin(GPU_VIEW_POSITION), &in[0].link);
}
-
+
node_shader_gpu_tex_mapping(mat, node, in, out);
if (tex->projection == SHD_PROJ_EQUIRECTANGULAR)
GPU_stack_link(mat, node, "node_tex_environment_equirectangular", in, out, GPU_image(ima, iuser, isdata));
else
GPU_stack_link(mat, node, "node_tex_environment_mirror_ball", in, out, GPU_image(ima, iuser, isdata));
-
+
ImBuf *ibuf = BKE_image_acquire_ibuf(ima, iuser, NULL);
if (ibuf && (ibuf->colormanage_flag & IMB_COLORMANAGE_IS_DATA) == 0 &&
GPU_material_do_color_management(mat))
diff --git a/source/blender/nodes/shader/nodes/node_shader_texture.c b/source/blender/nodes/shader/nodes/node_shader_texture.c
new file mode 100644
index 00000000000..737ec7d1c4b
--- /dev/null
+++ b/source/blender/nodes/shader/nodes/node_shader_texture.c
@@ -0,0 +1,166 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2005 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/nodes/shader/nodes/node_shader_texture.c
+ * \ingroup shdnodes
+ */
+
+#include "DNA_texture_types.h"
+
+#include "node_shader_util.h"
+
+#include "GPU_material.h"
+
+/* **************** TEXTURE ******************** */
+static bNodeSocketTemplate sh_node_texture_in[] = {
+ { SOCK_VECTOR, 1, "Vector", 0.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f, PROP_NONE, SOCK_HIDE_VALUE}, /* no limit */
+ { -1, 0, "" }
+};
+static bNodeSocketTemplate sh_node_texture_out[] = {
+ { SOCK_FLOAT, 0, N_("Value"), 0, 0, 0, 0, 0, 0, PROP_NONE, SOCK_NO_INTERNAL_LINK},
+ { SOCK_RGBA, 0, N_("Color"), 0, 0, 0, 0, 0, 0, PROP_NONE, SOCK_NO_INTERNAL_LINK},
+ { SOCK_VECTOR, 0, N_("Normal"), 0, 0, 0, 0, 0, 0, PROP_NONE, SOCK_NO_INTERNAL_LINK},
+ { -1, 0, "" }
+};
+
+static void node_shader_exec_texture(void *data, int UNUSED(thread), bNode *node, bNodeExecData *execdata, bNodeStack **in, bNodeStack **out)
+{
+ if (data && node->id) {
+ ShadeInput *shi = ((ShaderCallData *)data)->shi;
+ TexResult texres;
+ bNodeSocket *sock_vector = node->inputs.first;
+ float vec[3], nor[3] = {0.0f, 0.0f, 0.0f};
+ int retval;
+ short which_output = node->custom1;
+
+ short thread = shi->thread;
+
+ /* out: value, color, normal */
+
+ /* we should find out if a normal as output is needed, for now we do all */
+ texres.nor = nor;
+ texres.tr = texres.tg = texres.tb = 0.0f;
+
+ /* don't use in[0]->hasinput, see material node for explanation */
+ if (sock_vector->link) {
+ nodestack_get_vec(vec, SOCK_VECTOR, in[0]);
+
+ if (in[0]->datatype == NS_OSA_VECTORS) {
+ float *fp = in[0]->data;
+ retval = multitex_nodes((Tex *)node->id, vec, fp, fp + 3, shi->osatex, &texres, thread, which_output, NULL, NULL, NULL);
+ }
+ else if (in[0]->datatype == NS_OSA_VALUES) {
+ const float *fp = in[0]->data;
+ float dxt[3], dyt[3];
+
+ dxt[0] = fp[0]; dxt[1] = dxt[2] = 0.0f;
+ dyt[0] = fp[1]; dyt[1] = dyt[2] = 0.0f;
+ retval = multitex_nodes((Tex *)node->id, vec, dxt, dyt, shi->osatex, &texres, thread, which_output, NULL, NULL, NULL);
+ }
+ else
+ retval = multitex_nodes((Tex *)node->id, vec, NULL, NULL, 0, &texres, thread, which_output, NULL, NULL, NULL);
+ }
+ else {
+ copy_v3_v3(vec, shi->lo);
+ retval = multitex_nodes((Tex *)node->id, vec, NULL, NULL, 0, &texres, thread, which_output, NULL, NULL, NULL);
+ }
+
+ /* stupid exception */
+ if ( ((Tex *)node->id)->type == TEX_STUCCI) {
+ texres.tin = 0.5f + 0.7f * texres.nor[0];
+ CLAMP(texres.tin, 0.0f, 1.0f);
+ }
+
+ /* intensity and color need some handling */
+ if (texres.talpha)
+ out[0]->vec[0] = texres.ta;
+ else
+ out[0]->vec[0] = texres.tin;
+
+ if ((retval & TEX_RGB) == 0) {
+ copy_v3_fl(out[1]->vec, out[0]->vec[0]);
+ out[1]->vec[3] = 1.0f;
+ }
+ else {
+ copy_v3_v3(out[1]->vec, &texres.tr);
+ out[1]->vec[3] = 1.0f;
+ }
+
+ copy_v3_v3(out[2]->vec, nor);
+
+ if (shi->do_preview) {
+ BKE_node_preview_set_pixel(execdata->preview, out[1]->vec, shi->xs, shi->ys, shi->do_manage);
+ }
+
+ }
+}
+
+static int gpu_shader_texture(GPUMaterial *mat, bNode *node, bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out)
+{
+ Tex *tex = (Tex *)node->id;
+
+ if (tex && tex->ima && (tex->type == TEX_IMAGE || tex->type == TEX_ENVMAP)) {
+ if (tex->type == TEX_IMAGE) {
+ GPUNodeLink *texlink = GPU_image(tex->ima, &tex->iuser, false);
+ GPU_stack_link(mat, "texture_image", in, out, texlink);
+ }
+ else { /* TEX_ENVMAP */
+ if (!in[0].link)
+ in[0].link = GPU_uniform(in[0].vec);
+ if (!GPU_material_use_world_space_shading(mat))
+ GPU_link(mat, "direction_transform_m4v3", in[0].link, GPU_builtin(GPU_INVERSE_VIEW_MATRIX), &in[0].link);
+ GPU_link(mat, "mtex_cube_map_refl_from_refldir",
+ GPU_cube_map(tex->ima, &tex->iuser, false), in[0].link, &out[0].link, &out[1].link);
+ GPU_link(mat, "color_to_normal", out[1].link, &out[2].link);
+ }
+
+ ImBuf *ibuf = BKE_image_acquire_ibuf(tex->ima, &tex->iuser, NULL);
+ if (ibuf && (ibuf->colormanage_flag & IMB_COLORMANAGE_IS_DATA) == 0 &&
+ GPU_material_do_color_management(mat))
+ {
+ GPU_link(mat, "srgb_to_linearrgb", out[1].link, &out[1].link);
+ }
+ BKE_image_release_ibuf(tex->ima, ibuf, NULL);
+
+ return true;
+ }
+
+ return false;
+}
+
+void register_node_type_sh_texture(void)
+{
+ static bNodeType ntype;
+
+ sh_node_type_base(&ntype, SH_NODE_TEXTURE, "Texture", NODE_CLASS_INPUT, NODE_PREVIEW);
+ node_type_compatibility(&ntype, NODE_OLD_SHADING);
+ node_type_socket_templates(&ntype, sh_node_texture_in, sh_node_texture_out);
+ node_type_exec(&ntype, NULL, NULL, node_shader_exec_texture);
+ node_type_gpu(&ntype, gpu_shader_texture);
+
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/shader/nodes/node_shader_valToRgb.c b/source/blender/nodes/shader/nodes/node_shader_valToRgb.c
index 5041741beb1..a1879df3a18 100644
--- a/source/blender/nodes/shader/nodes/node_shader_valToRgb.c
+++ b/source/blender/nodes/shader/nodes/node_shader_valToRgb.c
@@ -48,7 +48,7 @@ static void node_shader_exec_valtorgb(void *UNUSED(data), int UNUSED(thread), bN
{
/* stack order in: fac */
/* stack order out: col, alpha */
-
+
if (node->storage) {
float fac;
nodestack_get_vec(&fac, SOCK_FLOAT, in[0]);
diff --git a/source/blender/nodes/shader/nodes/node_shader_vectMath.c b/source/blender/nodes/shader/nodes/node_shader_vectMath.c
index 2b060806819..ca5291e6041 100644
--- a/source/blender/nodes/shader/nodes/node_shader_vectMath.c
+++ b/source/blender/nodes/shader/nodes/node_shader_vectMath.c
@@ -31,7 +31,7 @@
#include "node_shader_util.h"
-/* **************** VECTOR MATH ******************** */
+/* **************** VECTOR MATH ******************** */
static bNodeSocketTemplate sh_node_vect_math_in[] = {
{ SOCK_VECTOR, 1, N_("Vector"), 0.5f, 0.5f, 0.5f, 1.0f, -10000.0f, 10000.0f, PROP_NONE},
{ SOCK_VECTOR, 1, N_("Vector"), 0.5f, 0.5f, 0.5f, 1.0f, -10000.0f, 10000.0f, PROP_NONE},
@@ -44,32 +44,32 @@ static bNodeSocketTemplate sh_node_vect_math_out[] = {
{ -1, 0, "" }
};
-static void node_shader_exec_vect_math(void *UNUSED(data), int UNUSED(thread), bNode *node, bNodeExecData *UNUSED(execdata), bNodeStack **in, bNodeStack **out)
-{
+static void node_shader_exec_vect_math(void *UNUSED(data), int UNUSED(thread), bNode *node, bNodeExecData *UNUSED(execdata), bNodeStack **in, bNodeStack **out)
+{
float vec1[3], vec2[3];
-
+
nodestack_get_vec(vec1, SOCK_VECTOR, in[0]);
nodestack_get_vec(vec2, SOCK_VECTOR, in[1]);
-
+
if (node->custom1 == 0) { /* Add */
out[0]->vec[0] = vec1[0] + vec2[0];
out[0]->vec[1] = vec1[1] + vec2[1];
out[0]->vec[2] = vec1[2] + vec2[2];
-
+
out[1]->vec[0] = (fabsf(out[0]->vec[0]) + fabsf(out[0]->vec[1]) + fabsf(out[0]->vec[2])) / 3.0f;
}
else if (node->custom1 == 1) { /* Subtract */
out[0]->vec[0] = vec1[0] - vec2[0];
out[0]->vec[1] = vec1[1] - vec2[1];
out[0]->vec[2] = vec1[2] - vec2[2];
-
+
out[1]->vec[0] = (fabsf(out[0]->vec[0]) + fabsf(out[0]->vec[1]) + fabsf(out[0]->vec[2])) / 3.0f;
}
else if (node->custom1 == 2) { /* Average */
out[0]->vec[0] = vec1[0] + vec2[0];
out[0]->vec[1] = vec1[1] + vec2[1];
out[0]->vec[2] = vec1[2] + vec2[2];
-
+
out[1]->vec[0] = normalize_v3(out[0]->vec);
}
else if (node->custom1 == 3) { /* Dot product */
@@ -79,7 +79,7 @@ static void node_shader_exec_vect_math(void *UNUSED(data), int UNUSED(thread), b
out[0]->vec[0] = (vec1[1] * vec2[2]) - (vec1[2] * vec2[1]);
out[0]->vec[1] = (vec1[2] * vec2[0]) - (vec1[0] * vec2[2]);
out[0]->vec[2] = (vec1[0] * vec2[1]) - (vec1[1] * vec2[0]);
-
+
out[1]->vec[0] = normalize_v3(out[0]->vec);
}
else if (node->custom1 == 5) { /* Normalize */
@@ -93,10 +93,10 @@ static void node_shader_exec_vect_math(void *UNUSED(data), int UNUSED(thread), b
out[0]->vec[1] = vec2[1];
out[0]->vec[2] = vec2[2];
}
-
+
out[1]->vec[0] = normalize_v3(out[0]->vec);
}
-
+
}
static int gpu_shader_vect_math(GPUMaterial *mat, bNode *node, bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out)
@@ -132,7 +132,7 @@ static int gpu_shader_vect_math(GPUMaterial *mat, bNode *node, bNodeExecData *UN
default:
return false;
}
-
+
return true;
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_vectTransform.c b/source/blender/nodes/shader/nodes/node_shader_vectTransform.c
index 8183b6c45cb..d0b16dd5886 100644
--- a/source/blender/nodes/shader/nodes/node_shader_vectTransform.c
+++ b/source/blender/nodes/shader/nodes/node_shader_vectTransform.c
@@ -28,10 +28,10 @@
/** \file blender/nodes/shader/nodes/node_shader_vectTransform.c
* \ingroup shdnodes
*/
-
+
#include "../node_shader_util.h"
-/* **************** Vector Transform ******************** */
+/* **************** Vector Transform ******************** */
static bNodeSocketTemplate sh_node_vect_transform_in[] = {
{ SOCK_VECTOR, 1, N_("Vector"), 0.5f, 0.5f, 0.5f, 1.0f, -10000.0f, 10000.0f, PROP_NONE},
{ -1, 0, "" }
@@ -45,10 +45,10 @@ static bNodeSocketTemplate sh_node_vect_transform_out[] = {
static void node_shader_init_vect_transform(bNodeTree *UNUSED(ntree), bNode *node)
{
NodeShaderVectTransform *vect = MEM_callocN(sizeof(NodeShaderVectTransform), "NodeShaderVectTransform");
-
+
/* Convert World into Object Space per default */
vect->convert_to = 1;
-
+
node->storage = vect;
}
diff --git a/source/blender/nodes/texture/node_texture_tree.c b/source/blender/nodes/texture/node_texture_tree.c
index 0d3d3f261de..5dbcece0a84 100644
--- a/source/blender/nodes/texture/node_texture_tree.c
+++ b/source/blender/nodes/texture/node_texture_tree.c
@@ -70,7 +70,7 @@ static void texture_get_from_context(
if (snode->texfrom == SNODE_TEX_BRUSH) {
struct Brush *brush = NULL;
-
+
if (ob && (ob->mode & OB_MODE_SCULPT))
brush = BKE_paint_brush(&scene->toolsettings->sculpt->paint);
else
@@ -119,11 +119,11 @@ static void foreach_nodeclass(Scene *UNUSED(scene), void *calldata, bNodeClassCa
static void localize(bNodeTree *localtree, bNodeTree *UNUSED(ntree))
{
bNode *node, *node_next;
-
+
/* replace muted nodes and reroute nodes by internal links */
for (node = localtree->nodes.first; node; node = node_next) {
node_next = node->next;
-
+
if (node->flag & NODE_MUTED || node->type == NODE_REROUTE) {
nodeInternalRelink(localtree, node);
nodeFreeNode(localtree, node);
@@ -149,7 +149,7 @@ static void local_merge(bNodeTree *localtree, bNodeTree *ntree)
static void update(bNodeTree *ntree)
{
ntree_update_reroute_nodes(ntree);
-
+
if (ntree->update & NTREE_UPDATE_NODES) {
/* clean up preview cache, in case nodes have been removed */
BKE_node_preview_remove_unused(ntree);
@@ -161,31 +161,31 @@ bNodeTreeType *ntreeType_Texture;
void register_node_tree_type_tex(void)
{
bNodeTreeType *tt = ntreeType_Texture = MEM_callocN(sizeof(bNodeTreeType), "texture node tree type");
-
+
tt->type = NTREE_TEXTURE;
strcpy(tt->idname, "TextureNodeTree");
strcpy(tt->ui_name, "Texture Editor");
tt->ui_icon = 0; /* defined in drawnode.c */
strcpy(tt->ui_description, "Texture nodes");
-
+
tt->foreach_nodeclass = foreach_nodeclass;
tt->update = update;
tt->localize = localize;
tt->local_sync = local_sync;
tt->local_merge = local_merge;
tt->get_from_context = texture_get_from_context;
-
+
tt->ext.srna = &RNA_TextureNodeTree;
-
+
ntreeTypeAdd(tt);
}
int ntreeTexTagAnimated(bNodeTree *ntree)
{
bNode *node;
-
+
if (ntree == NULL) return 0;
-
+
for (node = ntree->nodes.first; node; node = node->next) {
if (node->type == TEX_NODE_CURVE_TIME) {
nodeUpdate(ntree, node);
@@ -197,7 +197,7 @@ int ntreeTexTagAnimated(bNodeTree *ntree)
}
}
}
-
+
return 0;
}
@@ -205,16 +205,16 @@ bNodeTreeExec *ntreeTexBeginExecTree_internal(bNodeExecContext *context, bNodeTr
{
bNodeTreeExec *exec;
bNode *node;
-
+
/* common base initialization */
exec = ntree_exec_begin(context, ntree, parent_key);
-
+
/* allocate the thread stack listbase array */
exec->threadstack = MEM_callocN(BLENDER_MAX_THREADS * sizeof(ListBase), "thread stack array");
-
+
for (node = exec->nodetree->nodes.first; node; node = node->next)
node->need_exec = 1;
-
+
return exec;
}
@@ -222,22 +222,22 @@ bNodeTreeExec *ntreeTexBeginExecTree(bNodeTree *ntree)
{
bNodeExecContext context;
bNodeTreeExec *exec;
-
+
/* XXX hack: prevent exec data from being generated twice.
* this should be handled by the renderer!
*/
if (ntree->execdata)
return ntree->execdata;
-
+
context.previews = ntree->previews;
-
+
exec = ntreeTexBeginExecTree_internal(&context, ntree, NODE_INSTANCE_KEY_BASE);
-
+
/* XXX this should not be necessary, but is still used for cmp/sha/tex nodes,
* which only store the ntree pointer. Should be fixed at some point!
*/
ntree->execdata = exec;
-
+
return exec;
}
@@ -247,7 +247,7 @@ static void tex_free_delegates(bNodeTreeExec *exec)
bNodeThreadStack *nts;
bNodeStack *ns;
int th, a;
-
+
for (th = 0; th < BLENDER_MAX_THREADS; th++)
for (nts = exec->threadstack[th].first; nts; nts = nts->next)
for (ns = nts->stack, a = 0; a < exec->stacksize; a++, ns++)
@@ -259,20 +259,20 @@ void ntreeTexEndExecTree_internal(bNodeTreeExec *exec)
{
bNodeThreadStack *nts;
int a;
-
+
if (exec->threadstack) {
tex_free_delegates(exec);
-
+
for (a = 0; a < BLENDER_MAX_THREADS; a++) {
for (nts = exec->threadstack[a].first; nts; nts = nts->next)
if (nts->stack) MEM_freeN(nts->stack);
BLI_freelistN(&exec->threadstack[a]);
}
-
+
MEM_freeN(exec->threadstack);
exec->threadstack = NULL;
}
-
+
ntree_exec_end(exec);
}
@@ -282,7 +282,7 @@ void ntreeTexEndExecTree(bNodeTreeExec *exec)
/* exec may get freed, so assign ntree */
bNodeTree *ntree = exec->nodetree;
ntreeTexEndExecTree_internal(exec);
-
+
/* XXX clear nodetree backpointer to exec data, same problem as noted in ntreeBeginExecTree */
ntree->execdata = NULL;
}
@@ -318,7 +318,7 @@ int ntreeTexExecTree(
data.which_output = which_output;
data.cfra = cfra;
data.mtex = mtex;
-
+
/* ensure execdata is only initialized once */
if (!exec) {
BLI_thread_lock(LOCK_NODES);
@@ -328,7 +328,7 @@ int ntreeTexExecTree(
exec = nodes->execdata;
}
-
+
nts = ntreeGetThreadStack(exec, thread);
ntreeExecThreadNodes(exec, nts, &data, thread);
ntreeReleaseThreadStack(nts);
diff --git a/source/blender/nodes/texture/node_texture_util.c b/source/blender/nodes/texture/node_texture_util.c
index 8cb61478c41..a6b0d060d93 100644
--- a/source/blender/nodes/texture/node_texture_util.c
+++ b/source/blender/nodes/texture/node_texture_util.c
@@ -58,7 +58,7 @@ int tex_node_poll_default(bNodeType *UNUSED(ntype), bNodeTree *ntree)
void tex_node_type_base(struct bNodeType *ntype, int type, const char *name, short nclass, short flag)
{
node_type_base(ntype, type, name, nclass, flag);
-
+
ntype->poll = tex_node_poll_default;
ntype->insert_link = node_insert_link_default;
ntype->update_internal_links = node_update_internal_links_default;
@@ -80,7 +80,7 @@ static void tex_input(float *out, int sz, bNodeStack *in, TexParams *params, sho
TexDelegate *dg = in->data;
if (dg) {
tex_call_delegate(dg, in->vec, params, thread);
-
+
if (in->hasoutput && in->sockettype == SOCK_FLOAT)
in->vec[1] = in->vec[2] = in->vec[0];
}
@@ -95,12 +95,12 @@ void tex_input_vec(float *out, bNodeStack *in, TexParams *params, short thread)
void tex_input_rgba(float *out, bNodeStack *in, TexParams *params, short thread)
{
tex_input(out, 4, in, params, thread);
-
+
if (in->hasoutput && in->sockettype == SOCK_FLOAT) {
out[1] = out[2] = out[0];
out[3] = 1;
}
-
+
if (in->hasoutput && in->sockettype == SOCK_VECTOR) {
out[0] = out[0] * 0.5f + 0.5f;
out[1] = out[1] * 0.5f + 0.5f;
@@ -132,7 +132,7 @@ void tex_do_preview(bNodePreview *preview, const float coord[2], const float col
if (preview) {
int xs = ((coord[0] + 1.0f) * 0.5f) * preview->xsize;
int ys = ((coord[1] + 1.0f) * 0.5f) * preview->ysize;
-
+
BKE_node_preview_set_pixel(preview, col, xs, ys, do_manage);
}
}
@@ -140,7 +140,7 @@ void tex_do_preview(bNodePreview *preview, const float coord[2], const float col
void tex_output(bNode *node, bNodeExecData *execdata, bNodeStack **in, bNodeStack *out, TexFn texfn, TexCallData *cdata)
{
TexDelegate *dg;
-
+
if (node->flag & NODE_MUTED) {
/* do not add a delegate if the node is muted */
return;
@@ -175,9 +175,9 @@ void ntreeTexCheckCyclics(struct bNodeTree *ntree)
}
else {
Tex *tex = (Tex *)node->id;
-
+
node->custom2 = 0;
-
+
node->custom1 = 1;
if (tex->use_nodes && tex->nodetree) {
ntreeTexCheckCyclics(tex->nodetree);
diff --git a/source/blender/nodes/texture/nodes/node_texture_at.c b/source/blender/nodes/texture/nodes/node_texture_at.c
index bd37a73c776..690d87b42a9 100644
--- a/source/blender/nodes/texture/nodes/node_texture_at.c
+++ b/source/blender/nodes/texture/nodes/node_texture_at.c
@@ -48,7 +48,7 @@ static void colorfn(float *out, TexParams *p, bNode *UNUSED(node), bNodeStack **
TexParams np = *p;
float new_co[3];
np.co = new_co;
-
+
tex_input_vec(new_co, in[1], p, thread);
tex_input_rgba(out, in[0], &np, thread);
}
@@ -61,11 +61,11 @@ static void exec(void *data, int UNUSED(thread), bNode *node, bNodeExecData *exe
void register_node_type_tex_at(void)
{
static bNodeType ntype;
-
+
tex_node_type_base(&ntype, TEX_NODE_AT, "At", NODE_CLASS_DISTORT, 0);
node_type_socket_templates(&ntype, inputs, outputs);
node_type_size(&ntype, 140, 100, 320);
node_type_exec(&ntype, NULL, NULL, exec);
-
+
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/texture/nodes/node_texture_bricks.c b/source/blender/nodes/texture/nodes/node_texture_bricks.c
index 802cfb97533..43af02acdf2 100644
--- a/source/blender/nodes/texture/nodes/node_texture_bricks.c
+++ b/source/blender/nodes/texture/nodes/node_texture_bricks.c
@@ -67,43 +67,43 @@ static float noise(int n) /* fast integer noise */
static void colorfn(float *out, TexParams *p, bNode *node, bNodeStack **in, short thread)
{
const float *co = p->co;
-
+
float x = co[0];
float y = co[1];
-
+
int bricknum, rownum;
float offset = 0;
float ins_x, ins_y;
float tint;
-
+
float bricks1[4];
float bricks2[4];
float mortar[4];
-
+
float mortar_thickness = tex_input_value(in[3], p, thread);
float bias = tex_input_value(in[4], p, thread);
float brick_width = tex_input_value(in[5], p, thread);
float row_height = tex_input_value(in[6], p, thread);
-
+
tex_input_rgba(bricks1, in[0], p, thread);
tex_input_rgba(bricks2, in[1], p, thread);
tex_input_rgba(mortar, in[2], p, thread);
-
+
rownum = (int)floor(y / row_height);
-
+
if (node->custom1 && node->custom2) {
brick_width *= ((int)(rownum) % node->custom2) ? 1.0f : node->custom4; /* squash */
offset = ((int)(rownum) % node->custom1) ? 0 : (brick_width * node->custom3); /* offset */
}
-
+
bricknum = (int)floor((x + offset) / brick_width);
-
+
ins_x = (x + offset) - brick_width * bricknum;
ins_y = y - row_height * rownum;
-
+
tint = noise((rownum << 16) + (bricknum & 0xFFFF)) + bias;
CLAMP(tint, 0.0f, 1.0f);
-
+
if (ins_x < mortar_thickness || ins_y < mortar_thickness ||
ins_x > (brick_width - mortar_thickness) ||
ins_y > (row_height - mortar_thickness))
@@ -124,12 +124,12 @@ static void exec(void *data, int UNUSED(thread), bNode *node, bNodeExecData *exe
void register_node_type_tex_bricks(void)
{
static bNodeType ntype;
-
+
tex_node_type_base(&ntype, TEX_NODE_BRICKS, "Bricks", NODE_CLASS_PATTERN, NODE_PREVIEW);
node_type_socket_templates(&ntype, inputs, outputs);
node_type_size_preset(&ntype, NODE_SIZE_MIDDLE);
node_type_init(&ntype, init);
node_type_exec(&ntype, NULL, NULL, exec);
-
+
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/texture/nodes/node_texture_checker.c b/source/blender/nodes/texture/nodes/node_texture_checker.c
index b38c883e3b8..d7ad642d474 100644
--- a/source/blender/nodes/texture/nodes/node_texture_checker.c
+++ b/source/blender/nodes/texture/nodes/node_texture_checker.c
@@ -51,12 +51,12 @@ static void colorfn(float *out, TexParams *p, bNode *UNUSED(node), bNodeStack **
float y = p->co[1];
float z = p->co[2];
float sz = tex_input_value(in[2], p, thread);
-
+
/* 0.00001 because of unit sized stuff */
int xi = (int)fabs(floor(0.00001f + x / sz));
int yi = (int)fabs(floor(0.00001f + y / sz));
int zi = (int)fabs(floor(0.00001f + z / sz));
-
+
if ( (xi % 2 == yi % 2) == (zi % 2) ) {
tex_input_rgba(out, in[0], p, thread);
}
@@ -73,10 +73,10 @@ static void exec(void *data, int UNUSED(thread), bNode *node, bNodeExecData *exe
void register_node_type_tex_checker(void)
{
static bNodeType ntype;
-
+
tex_node_type_base(&ntype, TEX_NODE_CHECKER, "Checker", NODE_CLASS_PATTERN, NODE_PREVIEW);
node_type_socket_templates(&ntype, inputs, outputs);
node_type_exec(&ntype, NULL, NULL, exec);
-
+
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/texture/nodes/node_texture_common.c b/source/blender/nodes/texture/nodes/node_texture_common.c
index 6f9a39d7524..20b1815e436 100644
--- a/source/blender/nodes/texture/nodes/node_texture_common.c
+++ b/source/blender/nodes/texture/nodes/node_texture_common.c
@@ -50,7 +50,7 @@ static void copy_stack(bNodeStack *to, bNodeStack *from)
copy_v4_v4(to->vec, from->vec);
to->data = from->data;
to->datatype = from->datatype;
-
+
/* tag as copy to prevent freeing */
to->is_copy = 1;
}
@@ -62,20 +62,20 @@ static void *group_initexec(bNodeExecContext *context, bNode *node, bNodeInstanc
{
bNodeTree *ngroup = (bNodeTree *)node->id;
void *exec;
-
+
if (!ngroup)
return NULL;
-
+
/* initialize the internal node tree execution */
exec = ntreeTexBeginExecTree_internal(context, ngroup, key);
-
+
return exec;
}
static void group_freeexec(void *nodedata)
{
bNodeTreeExec *gexec = (bNodeTreeExec *)nodedata;
-
+
ntreeTexEndExecTree_internal(gexec);
}
@@ -89,7 +89,7 @@ static void group_copy_inputs(bNode *gnode, bNodeStack **in, bNodeStack *gstack)
bNodeSocket *sock;
bNodeStack *ns;
int a;
-
+
for (node = ngroup->nodes.first; node; node = node->next) {
if (node->type == NODE_GROUP_INPUT) {
for (sock = node->outputs.first, a = 0; sock; sock = sock->next, ++a) {
@@ -113,7 +113,7 @@ static void group_copy_outputs(bNode *gnode, bNodeStack **out, bNodeStack *gstac
bNodeSocket *sock;
bNodeStack *ns;
int a;
-
+
for (node = ngroup->nodes.first; node; node = node->next) {
if (node->type == NODE_GROUP_OUTPUT && (node->flag & NODE_DO_OUTPUT)) {
for (sock = node->inputs.first, a = 0; sock; sock = sock->next, ++a) {
@@ -133,10 +133,10 @@ static void group_execute(void *data, int thread, struct bNode *node, bNodeExecD
{
bNodeTreeExec *exec = execdata->data;
bNodeThreadStack *nts;
-
+
if (!exec)
return;
-
+
/* XXX same behavior as trunk: all nodes inside group are executed.
* it's stupid, but just makes it work. compo redesign will do this better.
*/
@@ -145,13 +145,13 @@ static void group_execute(void *data, int thread, struct bNode *node, bNodeExecD
for (inode = exec->nodetree->nodes.first; inode; inode = inode->next)
inode->need_exec = 1;
}
-
+
nts = ntreeGetThreadStack(exec, thread);
-
+
group_copy_inputs(node, in, nts->stack);
ntreeExecThreadNodes(exec, nts, data, thread);
group_copy_outputs(node, out, nts->stack);
-
+
ntreeReleaseThreadStack(nts);
}
@@ -171,12 +171,12 @@ void register_node_type_tex_group(void)
ntype.ext.srna = RNA_struct_find("TextureNodeGroup");
BLI_assert(ntype.ext.srna != NULL);
RNA_struct_blender_type_set(ntype.ext.srna, &ntype);
-
+
node_type_socket_templates(&ntype, NULL, NULL);
node_type_size(&ntype, 140, 60, 400);
node_type_label(&ntype, node_group_label);
node_type_update(&ntype, NULL, node_group_verify);
node_type_exec(&ntype, group_initexec, group_freeexec, group_execute);
-
+
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/texture/nodes/node_texture_compose.c b/source/blender/nodes/texture/nodes/node_texture_compose.c
index 092bf919a67..002da4428cc 100644
--- a/source/blender/nodes/texture/nodes/node_texture_compose.c
+++ b/source/blender/nodes/texture/nodes/node_texture_compose.c
@@ -30,7 +30,7 @@
*/
-#include "node_texture_util.h"
+#include "node_texture_util.h"
#include "NOD_texture.h"
static bNodeSocketTemplate inputs[] = {
@@ -60,10 +60,10 @@ static void exec(void *data, int UNUSED(thread), bNode *node, bNodeExecData *exe
void register_node_type_tex_compose(void)
{
static bNodeType ntype;
-
+
tex_node_type_base(&ntype, TEX_NODE_COMPOSE, "Combine RGBA", NODE_CLASS_OP_COLOR, 0);
node_type_socket_templates(&ntype, inputs, outputs);
node_type_exec(&ntype, NULL, NULL, exec);
-
+
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/texture/nodes/node_texture_coord.c b/source/blender/nodes/texture/nodes/node_texture_coord.c
index e76987da61b..e698ffd0a54 100644
--- a/source/blender/nodes/texture/nodes/node_texture_coord.c
+++ b/source/blender/nodes/texture/nodes/node_texture_coord.c
@@ -51,11 +51,11 @@ static void exec(void *data, int UNUSED(thread), bNode *node, bNodeExecData *exe
void register_node_type_tex_coord(void)
{
static bNodeType ntype;
-
+
tex_node_type_base(&ntype, TEX_NODE_COORD, "Coordinates", NODE_CLASS_INPUT, 0);
node_type_socket_templates(&ntype, NULL, outputs);
node_type_storage(&ntype, "", NULL, NULL);
node_type_exec(&ntype, NULL, NULL, exec);
-
+
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/texture/nodes/node_texture_curves.c b/source/blender/nodes/texture/nodes/node_texture_curves.c
index c25c312626e..cc734df9586 100644
--- a/source/blender/nodes/texture/nodes/node_texture_curves.c
+++ b/source/blender/nodes/texture/nodes/node_texture_curves.c
@@ -45,10 +45,10 @@ static void time_colorfn(float *out, TexParams *p, bNode *node, bNodeStack **UNU
{
/* stack order output: fac */
float fac = 0.0f;
-
+
if (node->custom1 < node->custom2)
fac = (p->cfra - node->custom1) / (float)(node->custom2 - node->custom1);
-
+
curvemapping_initialize(node->storage);
fac = curvemapping_evaluateF(node->storage, 0, fac);
out[0] = CLAMPIS(fac, 0.0f, 1.0f);
@@ -70,14 +70,14 @@ static void time_init(bNodeTree *UNUSED(ntree), bNode *node)
void register_node_type_tex_curve_time(void)
{
static bNodeType ntype;
-
+
tex_node_type_base(&ntype, TEX_NODE_CURVE_TIME, "Time", NODE_CLASS_INPUT, 0);
node_type_socket_templates(&ntype, NULL, time_outputs);
node_type_size_preset(&ntype, NODE_SIZE_LARGE);
node_type_init(&ntype, time_init);
node_type_storage(&ntype, "CurveMapping", node_free_curves, node_copy_curves);
node_type_exec(&ntype, node_initexec_curves, NULL, time_exec);
-
+
nodeRegisterType(&ntype);
}
@@ -96,7 +96,7 @@ static void rgb_colorfn(float *out, TexParams *p, bNode *node, bNodeStack **in,
{
float cin[4];
tex_input_rgba(cin, in[0], p, thread);
-
+
curvemapping_evaluateRGBF(node->storage, out, cin);
out[3] = cin[3];
}
@@ -114,13 +114,13 @@ static void rgb_init(bNodeTree *UNUSED(ntree), bNode *node)
void register_node_type_tex_curve_rgb(void)
{
static bNodeType ntype;
-
+
tex_node_type_base(&ntype, TEX_NODE_CURVE_RGB, "RGB Curves", NODE_CLASS_OP_COLOR, 0);
node_type_socket_templates(&ntype, rgb_inputs, rgb_outputs);
node_type_size_preset(&ntype, NODE_SIZE_LARGE);
node_type_init(&ntype, rgb_init);
node_type_storage(&ntype, "CurveMapping", node_free_curves, node_copy_curves);
node_type_exec(&ntype, node_initexec_curves, NULL, rgb_exec);
-
+
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/texture/nodes/node_texture_decompose.c b/source/blender/nodes/texture/nodes/node_texture_decompose.c
index 16938bee8e4..392cff970e7 100644
--- a/source/blender/nodes/texture/nodes/node_texture_decompose.c
+++ b/source/blender/nodes/texture/nodes/node_texture_decompose.c
@@ -30,7 +30,7 @@
*/
-#include "node_texture_util.h"
+#include "node_texture_util.h"
#include "NOD_texture.h"
#include <math.h>
@@ -81,10 +81,10 @@ static void exec(void *data, int UNUSED(thread), bNode *node, bNodeExecData *exe
void register_node_type_tex_decompose(void)
{
static bNodeType ntype;
-
+
tex_node_type_base(&ntype, TEX_NODE_DECOMPOSE, "Separate RGBA", NODE_CLASS_OP_COLOR, 0);
node_type_socket_templates(&ntype, inputs, outputs);
node_type_exec(&ntype, NULL, NULL, exec);
-
+
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/texture/nodes/node_texture_distance.c b/source/blender/nodes/texture/nodes/node_texture_distance.c
index 3fdcbe870a9..7cd032f7d59 100644
--- a/source/blender/nodes/texture/nodes/node_texture_distance.c
+++ b/source/blender/nodes/texture/nodes/node_texture_distance.c
@@ -64,11 +64,11 @@ static void exec(void *data, int UNUSED(thread), bNode *node, bNodeExecData *exe
void register_node_type_tex_distance(void)
{
static bNodeType ntype;
-
+
tex_node_type_base(&ntype, TEX_NODE_DISTANCE, "Distance", NODE_CLASS_CONVERTOR, 0);
node_type_socket_templates(&ntype, inputs, outputs);
node_type_storage(&ntype, "", NULL, NULL);
node_type_exec(&ntype, NULL, NULL, exec);
-
+
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/texture/nodes/node_texture_hueSatVal.c b/source/blender/nodes/texture/nodes/node_texture_hueSatVal.c
index 9c86f2d0a4c..8316579af93 100644
--- a/source/blender/nodes/texture/nodes/node_texture_hueSatVal.c
+++ b/source/blender/nodes/texture/nodes/node_texture_hueSatVal.c
@@ -51,7 +51,7 @@ static void do_hue_sat_fac(bNode *UNUSED(node), float *out, float hue, float sat
{
if (fac != 0 && (hue != 0.5f || sat != 1 || val != 1)) {
float col[3], hsv[3], mfac = 1.0f - fac;
-
+
rgb_to_hsv(in[0], in[1], in[2], hsv, hsv + 1, hsv + 2);
hsv[0] += (hue - 0.5f);
if (hsv[0] > 1.0f) hsv[0] -= 1.0f; else if (hsv[0] < 0.0f) hsv[0] += 1.0f;
@@ -71,19 +71,19 @@ static void do_hue_sat_fac(bNode *UNUSED(node), float *out, float hue, float sat
}
static void colorfn(float *out, TexParams *p, bNode *node, bNodeStack **in, short thread)
-{
+{
float hue = tex_input_value(in[0], p, thread);
float sat = tex_input_value(in[1], p, thread);
float val = tex_input_value(in[2], p, thread);
float fac = tex_input_value(in[3], p, thread);
-
+
float col[4];
tex_input_rgba(col, in[4], p, thread);
-
+
hue += 0.5f; /* [-0.5, 0.5] -> [0, 1] */
-
+
do_hue_sat_fac(node, out, hue, sat, val, col, fac);
-
+
out[3] = col[3];
}
@@ -95,11 +95,11 @@ static void exec(void *data, int UNUSED(thread), bNode *node, bNodeExecData *exe
void register_node_type_tex_hue_sat(void)
{
static bNodeType ntype;
-
+
tex_node_type_base(&ntype, TEX_NODE_HUE_SAT, "Hue Saturation Value", NODE_CLASS_OP_COLOR, 0);
node_type_socket_templates(&ntype, inputs, outputs);
node_type_size_preset(&ntype, NODE_SIZE_MIDDLE);
node_type_exec(&ntype, NULL, NULL, exec);
-
+
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/texture/nodes/node_texture_image.c b/source/blender/nodes/texture/nodes/node_texture_image.c
index e36df01f489..0d70eff15e3 100644
--- a/source/blender/nodes/texture/nodes/node_texture_image.c
+++ b/source/blender/nodes/texture/nodes/node_texture_image.c
@@ -44,37 +44,37 @@ static void colorfn(float *out, TexParams *p, bNode *node, bNodeStack **UNUSED(i
float y = p->co[1];
Image *ima = (Image *)node->id;
ImageUser *iuser = (ImageUser *)node->storage;
-
+
if (ima) {
ImBuf *ibuf = BKE_image_acquire_ibuf(ima, iuser, NULL);
if (ibuf) {
float xsize, ysize;
float xoff, yoff;
int px, py;
-
+
const float *result;
xsize = ibuf->x / 2;
ysize = ibuf->y / 2;
xoff = yoff = -1;
-
+
px = (int)( (x - xoff) * xsize);
py = (int)( (y - yoff) * ysize);
-
+
if ( (!xsize) || (!ysize) ) return;
-
+
if (!ibuf->rect_float) {
BLI_thread_lock(LOCK_IMAGE);
if (!ibuf->rect_float)
IMB_float_from_rect(ibuf);
BLI_thread_unlock(LOCK_IMAGE);
}
-
+
while (px < 0) px += ibuf->x;
while (py < 0) py += ibuf->y;
while (px >= ibuf->x) px -= ibuf->x;
while (py >= ibuf->y) py -= ibuf->y;
-
+
result = ibuf->rect_float + py * ibuf->x * 4 + px * 4;
copy_v4_v4(out, result);
@@ -101,7 +101,7 @@ static void init(bNodeTree *UNUSED(ntree), bNode *node)
void register_node_type_tex_image(void)
{
static bNodeType ntype;
-
+
tex_node_type_base(&ntype, TEX_NODE_IMAGE, "Image", NODE_CLASS_INPUT, NODE_PREVIEW);
node_type_socket_templates(&ntype, NULL, outputs);
node_type_init(&ntype, init);
diff --git a/source/blender/nodes/texture/nodes/node_texture_invert.c b/source/blender/nodes/texture/nodes/node_texture_invert.c
index 35f5072d8a2..8ef7a7a6ad2 100644
--- a/source/blender/nodes/texture/nodes/node_texture_invert.c
+++ b/source/blender/nodes/texture/nodes/node_texture_invert.c
@@ -33,7 +33,7 @@
#include "node_texture_util.h"
#include "NOD_texture.h"
-/* **************** INVERT ******************** */
+/* **************** INVERT ******************** */
static bNodeSocketTemplate inputs[] = {
{ SOCK_RGBA, 1, N_("Color"), 0.0f, 0.0f, 0.0f, 1.0f},
{ -1, 0, "" }
@@ -47,13 +47,13 @@ static bNodeSocketTemplate outputs[] = {
static void colorfn(float *out, TexParams *p, bNode *UNUSED(node), bNodeStack **in, short thread)
{
float col[4];
-
+
tex_input_rgba(col, in[0], p, thread);
col[0] = 1.0f - col[0];
col[1] = 1.0f - col[1];
col[2] = 1.0f - col[2];
-
+
copy_v3_v3(out, col);
out[3] = col[3];
}
@@ -66,10 +66,10 @@ static void exec(void *data, int UNUSED(thread), bNode *node, bNodeExecData *exe
void register_node_type_tex_invert(void)
{
static bNodeType ntype;
-
+
tex_node_type_base(&ntype, TEX_NODE_INVERT, "Invert", NODE_CLASS_OP_COLOR, 0);
node_type_socket_templates(&ntype, inputs, outputs);
node_type_exec(&ntype, NULL, NULL, exec);
-
+
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/texture/nodes/node_texture_mixRgb.c b/source/blender/nodes/texture/nodes/node_texture_mixRgb.c
index 835a49c24d4..9fb8332c61a 100644
--- a/source/blender/nodes/texture/nodes/node_texture_mixRgb.c
+++ b/source/blender/nodes/texture/nodes/node_texture_mixRgb.c
@@ -49,16 +49,16 @@ static void colorfn(float *out, TexParams *p, bNode *node, bNodeStack **in, shor
{
float fac = tex_input_value(in[0], p, thread);
float col1[4], col2[4];
-
+
tex_input_rgba(col1, in[1], p, thread);
tex_input_rgba(col2, in[2], p, thread);
/* use alpha */
if (node->custom2 & 1)
fac *= col2[3];
-
+
CLAMP(fac, 0.0f, 1.0f);
-
+
copy_v4_v4(out, col1);
ramp_blend(node->custom1, out, fac, col2);
}
@@ -71,11 +71,11 @@ static void exec(void *data, int UNUSED(thread), bNode *node, bNodeExecData *exe
void register_node_type_tex_mix_rgb(void)
{
static bNodeType ntype;
-
+
tex_node_type_base(&ntype, TEX_NODE_MIX_RGB, "Mix", NODE_CLASS_OP_COLOR, 0);
node_type_socket_templates(&ntype, inputs, outputs);
node_type_label(&ntype, node_blend_label);
node_type_exec(&ntype, NULL, NULL, exec);
-
+
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/texture/nodes/node_texture_output.c b/source/blender/nodes/texture/nodes/node_texture_output.c
index 664b7e4f507..412e3ffb56c 100644
--- a/source/blender/nodes/texture/nodes/node_texture_output.c
+++ b/source/blender/nodes/texture/nodes/node_texture_output.c
@@ -45,7 +45,7 @@ static void exec(void *data, int UNUSED(thread), bNode *node, bNodeExecData *exe
{
TexCallData *cdata = (TexCallData *)data;
TexResult *target = cdata->target;
-
+
if (cdata->do_preview) {
TexParams params;
params_from_cdata(&params, cdata);
@@ -61,12 +61,12 @@ static void exec(void *data, int UNUSED(thread), bNode *node, bNodeExecData *exe
if (cdata->which_output == node->custom1 || (cdata->which_output == 0 && node->custom1 == 1)) {
TexParams params;
params_from_cdata(&params, cdata);
-
+
tex_input_rgba(&target->tr, in[0], &params, cdata->thread);
-
+
target->tin = (target->tr + target->tg + target->tb) / 3.0f;
target->talpha = true;
-
+
if (target->nor) {
if (in[1] && in[1]->hasinput)
tex_input_vec(target->nor, in[1], &params, cdata->thread);
@@ -85,7 +85,7 @@ static void unique_name(bNode *node)
int suffix;
bNode *i;
const char *name = tno->name;
-
+
new_name[0] = '\0';
i = node;
while (i->prev) i = i->prev;
@@ -114,7 +114,7 @@ static void unique_name(bNode *node)
}
sprintf(new_name + new_len - 4, ".%03d", ++suffix);
}
-
+
if (new_name[0] != '\0') {
BLI_strncpy(tno->name, new_name, sizeof(tno->name));
}
@@ -124,11 +124,11 @@ static void assign_index(struct bNode *node)
{
bNode *tnode;
int index = 1;
-
+
tnode = node;
while (tnode->prev)
tnode = tnode->prev;
-
+
check_index:
for (; tnode; tnode = tnode->next)
if (tnode->type == TEX_NODE_OUTPUT && tnode != node)
@@ -136,7 +136,7 @@ check_index:
index++;
goto check_index;
}
-
+
node->custom1 = index;
}
@@ -144,7 +144,7 @@ static void init(bNodeTree *UNUSED(ntree), bNode *node)
{
TexNodeOutput *tno = MEM_callocN(sizeof(TexNodeOutput), "TEX_output");
node->storage = tno;
-
+
strcpy(tno->name, "Default");
unique_name(node);
assign_index(node);
@@ -160,16 +160,16 @@ static void copy(bNodeTree *dest_ntree, bNode *dest_node, bNode *src_node)
void register_node_type_tex_output(void)
{
static bNodeType ntype;
-
+
tex_node_type_base(&ntype, TEX_NODE_OUTPUT, "Output", NODE_CLASS_OUTPUT, NODE_PREVIEW);
node_type_socket_templates(&ntype, inputs, NULL);
node_type_size_preset(&ntype, NODE_SIZE_MIDDLE);
node_type_init(&ntype, init);
node_type_storage(&ntype, "TexNodeOutput", node_free_standard_storage, copy);
node_type_exec(&ntype, NULL, NULL, exec);
-
+
/* Do not allow muting output. */
node_type_internal_links(&ntype, NULL);
-
+
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/texture/nodes/node_texture_proc.c b/source/blender/nodes/texture/nodes/node_texture_proc.c
index 2461a53ca2a..47f4683549f 100644
--- a/source/blender/nodes/texture/nodes/node_texture_proc.c
+++ b/source/blender/nodes/texture/nodes/node_texture_proc.c
@@ -35,7 +35,7 @@
#include "RE_shader_ext.h"
-/*
+/*
* In this file: wrappers to use procedural textures as nodes
*/
@@ -61,19 +61,19 @@ static void do_proc(float *result, TexParams *p, const float col1[4], const floa
{
TexResult texres;
int textype;
-
+
if (is_normal) {
texres.nor = result;
}
else
texres.nor = NULL;
-
+
textype = multitex_nodes(tex, p->co, p->dxt, p->dyt, p->osatex,
&texres, thread, 0, p->mtex, NULL);
-
+
if (is_normal)
return;
-
+
if (textype & TEX_RGB) {
copy_v4_v4(result, &texres.tr);
}
@@ -86,11 +86,11 @@ static void do_proc(float *result, TexParams *p, const float col1[4], const floa
typedef void (*MapFn) (Tex *tex, bNodeStack **in, TexParams *p, const short thread);
static void texfn(
- float *result,
+ float *result,
TexParams *p,
- bNode *node,
+ bNode *node,
bNodeStack **in,
- char is_normal,
+ char is_normal,
MapFn map_inputs,
short thread)
{
@@ -98,9 +98,9 @@ static void texfn(
float col1[4], col2[4];
tex_input_rgba(col1, in[0], p, thread);
tex_input_rgba(col2, in[1], p, thread);
-
+
map_inputs(&tex, in, p, thread);
-
+
do_proc(result, p, col1, col2, is_normal, &tex, thread);
}
@@ -144,10 +144,10 @@ static bNodeSocketTemplate voronoi_inputs[] = {
{ SOCK_FLOAT, 1, N_("W2"), 0.0f, 0.0f, 0.0f, 0.0f, -2.0f, 2.0f, PROP_NONE },
{ SOCK_FLOAT, 1, N_("W3"), 0.0f, 0.0f, 0.0f, 0.0f, -2.0f, 2.0f, PROP_NONE },
{ SOCK_FLOAT, 1, N_("W4"), 0.0f, 0.0f, 0.0f, 0.0f, -2.0f, 2.0f, PROP_NONE },
-
+
{ SOCK_FLOAT, 1, N_("iScale"), 1.0f, 0.0f, 0.0f, 0.0f, 0.01f, 10.0f, PROP_UNSIGNED },
{ SOCK_FLOAT, 1, N_("Size"), 0.25f, 0.0f, 0.0f, 0.0f, 0.0001f, 4.0f, PROP_UNSIGNED },
-
+
{ -1, 0, "" }
};
static void voronoi_map_inputs(Tex *tex, bNodeStack **in, TexParams *p, short thread)
@@ -156,7 +156,7 @@ static void voronoi_map_inputs(Tex *tex, bNodeStack **in, TexParams *p, short th
tex->vn_w2 = tex_input_value(in[I + 1], p, thread);
tex->vn_w3 = tex_input_value(in[I + 2], p, thread);
tex->vn_w4 = tex_input_value(in[I + 3], p, thread);
-
+
tex->ns_outscale = tex_input_value(in[I + 4], p, thread);
tex->noisesize = tex_input_value(in[I + 5], p, thread);
}
@@ -242,7 +242,7 @@ static bNodeSocketTemplate musgrave_inputs[] = {
{ SOCK_FLOAT, 1, N_("H"), 1.0f, 0.0f, 0.0f, 0.0f, 0.0001f, 2.0f, PROP_UNSIGNED },
{ SOCK_FLOAT, 1, N_("Lacunarity"), 2.0f, 0.0f, 0.0f, 0.0f, 0.0f, 6.0f, PROP_UNSIGNED },
{ SOCK_FLOAT, 1, N_("Octaves"), 2.0f, 0.0f, 0.0f, 0.0f, 0.0f, 8.0f, PROP_UNSIGNED },
-
+
{ SOCK_FLOAT, 1, N_("iScale"), 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 10.0f, PROP_UNSIGNED },
{ SOCK_FLOAT, 1, N_("Size"), 0.25f, 0.0f, 0.0f, 0.0f, 0.0001f, 2.0f, PROP_UNSIGNED },
{ -1, 0, "" }
@@ -285,13 +285,13 @@ static void init(bNodeTree *UNUSED(ntree), bNode *node)
{
Tex *tex = MEM_callocN(sizeof(Tex), "Tex");
node->storage = tex;
-
+
BKE_texture_default(tex);
tex->type = node->type - TEX_NODE_PROC;
-
+
if (tex->type == TEX_WOOD)
tex->stype = TEX_BANDNOISE;
-
+
}
/* Node type definitions */
@@ -309,10 +309,10 @@ void register_node_type_tex_proc_##name(void) \
\
nodeRegisterType(&ntype); \
}
-
+
#define C outputs_color_only
#define CV outputs_both
-
+
TexDef(TEX_VORONOI, CV, voronoi, "Voronoi" )
TexDef(TEX_BLEND, C, blend, "Blend" )
TexDef(TEX_MAGIC, C, magic, "Magic" )
diff --git a/source/blender/nodes/texture/nodes/node_texture_rotate.c b/source/blender/nodes/texture/nodes/node_texture_rotate.c
index 99648ec323f..bc4e56ea81d 100644
--- a/source/blender/nodes/texture/nodes/node_texture_rotate.c
+++ b/source/blender/nodes/texture/nodes/node_texture_rotate.c
@@ -52,18 +52,18 @@ static void rotate(float new_co[3], float a, float ax[3], const float co[3])
float para[3];
float perp[3];
float cp[3];
-
+
float cos_a = cosf(a * (float)(2 * M_PI));
float sin_a = sinf(a * (float)(2 * M_PI));
-
+
// x' = xcosa + n(n.x)(1-cosa) + (x*n)sina
-
+
mul_v3_v3fl(perp, co, cos_a);
mul_v3_v3fl(para, ax, dot_v3v3(co, ax) * (1 - cos_a));
-
+
cross_v3_v3v3(cp, ax, co);
mul_v3_fl(cp, sin_a);
-
+
new_co[0] = para[0] + perp[0] + cp[0];
new_co[1] = para[1] + perp[1] + cp[1];
new_co[2] = para[2] + perp[2] + cp[2];
@@ -72,7 +72,7 @@ static void rotate(float new_co[3], float a, float ax[3], const float co[3])
static void colorfn(float *out, TexParams *p, bNode *UNUSED(node), bNodeStack **in, short thread)
{
float new_co[3], new_dxt[3], new_dyt[3], a, ax[3];
-
+
a = tex_input_value(in[1], p, thread);
tex_input_vec(ax, in[2], p, thread);
@@ -81,7 +81,7 @@ static void colorfn(float *out, TexParams *p, bNode *UNUSED(node), bNodeStack **
rotate(new_dxt, a, ax, p->dxt);
rotate(new_dyt, a, ax, p->dyt);
}
-
+
{
TexParams np = *p;
np.co = new_co;
@@ -90,7 +90,7 @@ static void colorfn(float *out, TexParams *p, bNode *UNUSED(node), bNodeStack **
tex_input_rgba(out, in[0], &np, thread);
}
}
-static void exec(void *data, int UNUSED(thread), bNode *node, bNodeExecData *execdata, bNodeStack **in, bNodeStack **out)
+static void exec(void *data, int UNUSED(thread), bNode *node, bNodeExecData *execdata, bNodeStack **in, bNodeStack **out)
{
tex_output(node, execdata, in, out[0], &colorfn, data);
}
@@ -98,10 +98,10 @@ static void exec(void *data, int UNUSED(thread), bNode *node, bNodeExecData *exe
void register_node_type_tex_rotate(void)
{
static bNodeType ntype;
-
+
tex_node_type_base(&ntype, TEX_NODE_ROTATE, "Rotate", NODE_CLASS_DISTORT, 0);
node_type_socket_templates(&ntype, inputs, outputs);
node_type_exec(&ntype, NULL, NULL, exec);
-
+
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/texture/nodes/node_texture_scale.c b/source/blender/nodes/texture/nodes/node_texture_scale.c
index d623e8e159a..94ccfd01357 100644
--- a/source/blender/nodes/texture/nodes/node_texture_scale.c
+++ b/source/blender/nodes/texture/nodes/node_texture_scale.c
@@ -52,7 +52,7 @@ static void colorfn(float *out, TexParams *p, bNode *UNUSED(node), bNodeStack **
np.co = new_co;
np.dxt = new_dxt;
np.dyt = new_dyt;
-
+
tex_input_vec(scale, in[1], p, thread);
mul_v3_v3v3(new_co, p->co, scale);
@@ -60,10 +60,10 @@ static void colorfn(float *out, TexParams *p, bNode *UNUSED(node), bNodeStack **
mul_v3_v3v3(new_dxt, p->dxt, scale);
mul_v3_v3v3(new_dyt, p->dyt, scale);
}
-
+
tex_input_rgba(out, in[0], &np, thread);
}
-static void exec(void *data, int UNUSED(thread), bNode *node, bNodeExecData *execdata, bNodeStack **in, bNodeStack **out)
+static void exec(void *data, int UNUSED(thread), bNode *node, bNodeExecData *execdata, bNodeStack **in, bNodeStack **out)
{
tex_output(node, execdata, in, out[0], &colorfn, data);
}
@@ -71,10 +71,10 @@ static void exec(void *data, int UNUSED(thread), bNode *node, bNodeExecData *exe
void register_node_type_tex_scale(void)
{
static bNodeType ntype;
-
+
tex_node_type_base(&ntype, TEX_NODE_SCALE, "Scale", NODE_CLASS_DISTORT, 0);
node_type_socket_templates(&ntype, inputs, outputs);
node_type_exec(&ntype, NULL, NULL, exec);
-
+
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/texture/nodes/node_texture_texture.c b/source/blender/nodes/texture/nodes/node_texture_texture.c
index f77234ae1ae..ff405cc9f3e 100644
--- a/source/blender/nodes/texture/nodes/node_texture_texture.c
+++ b/source/blender/nodes/texture/nodes/node_texture_texture.c
@@ -52,7 +52,7 @@ static void colorfn(float *out, TexParams *p, bNode *node, bNodeStack **in, shor
static float red[] = {1, 0, 0, 1};
static float white[] = {1, 1, 1, 1};
float co[3], dxt[3], dyt[3];
-
+
copy_v3_v3(co, p->co);
if (p->osatex) {
copy_v3_v3(dxt, p->dxt);
@@ -62,7 +62,7 @@ static void colorfn(float *out, TexParams *p, bNode *node, bNodeStack **in, shor
zero_v3(dxt);
zero_v3(dyt);
}
-
+
if (node->custom2 || node->need_exec == 0) {
/* this node refers to its own texture tree! */
copy_v4_v4(out, (fabsf(co[0] - co[1]) < 0.01f) ? white : red);
@@ -72,14 +72,14 @@ static void colorfn(float *out, TexParams *p, bNode *node, bNodeStack **in, shor
int textype;
float nor[] = {0, 0, 0};
float col1[4], col2[4];
-
+
tex_input_rgba(col1, in[0], p, thread);
tex_input_rgba(col2, in[1], p, thread);
-
+
texres.nor = nor;
textype = multitex_nodes(nodetex, co, dxt, dyt, p->osatex,
&texres, thread, 0, p->mtex, NULL);
-
+
if (textype & TEX_RGB) {
copy_v4_v4(out, &texres.tr);
}
@@ -98,10 +98,10 @@ static void exec(void *data, int UNUSED(thread), bNode *node, bNodeExecData *exe
void register_node_type_tex_texture(void)
{
static bNodeType ntype;
-
+
tex_node_type_base(&ntype, TEX_NODE_TEXTURE, "Texture", NODE_CLASS_INPUT, NODE_PREVIEW);
node_type_socket_templates(&ntype, inputs, outputs);
node_type_exec(&ntype, NULL, NULL, exec);
-
+
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/texture/nodes/node_texture_translate.c b/source/blender/nodes/texture/nodes/node_texture_translate.c
index ec90029c0bf..fa8319d077b 100644
--- a/source/blender/nodes/texture/nodes/node_texture_translate.c
+++ b/source/blender/nodes/texture/nodes/node_texture_translate.c
@@ -50,16 +50,16 @@ static void colorfn(float *out, TexParams *p, bNode *UNUSED(node), bNodeStack **
float offset[3], new_co[3];
TexParams np = *p;
np.co = new_co;
-
+
tex_input_vec(offset, in[1], p, thread);
-
+
new_co[0] = p->co[0] + offset[0];
new_co[1] = p->co[1] + offset[1];
new_co[2] = p->co[2] + offset[2];
-
+
tex_input_rgba(out, in[0], &np, thread);
}
-static void exec(void *data, int UNUSED(thread), bNode *node, bNodeExecData *execdata, bNodeStack **in, bNodeStack **out)
+static void exec(void *data, int UNUSED(thread), bNode *node, bNodeExecData *execdata, bNodeStack **in, bNodeStack **out)
{
tex_output(node, execdata, in, out[0], &colorfn, data);
}
@@ -67,10 +67,10 @@ static void exec(void *data, int UNUSED(thread), bNode *node, bNodeExecData *exe
void register_node_type_tex_translate(void)
{
static bNodeType ntype;
-
+
tex_node_type_base(&ntype, TEX_NODE_TRANSLATE, "Translate", NODE_CLASS_DISTORT, 0);
node_type_socket_templates(&ntype, inputs, outputs);
node_type_exec(&ntype, NULL, NULL, exec);
-
+
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/texture/nodes/node_texture_valToNor.c b/source/blender/nodes/texture/nodes/node_texture_valToNor.c
index 995fb6c1782..b7d57b4d4cf 100644
--- a/source/blender/nodes/texture/nodes/node_texture_valToNor.c
+++ b/source/blender/nodes/texture/nodes/node_texture_valToNor.c
@@ -52,7 +52,7 @@ static void normalfn(float *out, TexParams *p, bNode *UNUSED(node), bNodeStack *
float nabla = tex_input_value(in[1], p, thread);
float val;
float nor[3];
-
+
TexParams np = *p;
np.co = new_co;
@@ -66,7 +66,7 @@ static void normalfn(float *out, TexParams *p, bNode *UNUSED(node), bNodeStack *
new_co[0] = co[0];
new_co[1] = co[1] + nabla;
nor[1] = tex_input_value(in[0], &np, thread);
-
+
new_co[1] = co[1];
new_co[2] = co[2] + nabla;
nor[2] = tex_input_value(in[0], &np, thread);
@@ -75,7 +75,7 @@ static void normalfn(float *out, TexParams *p, bNode *UNUSED(node), bNodeStack *
out[1] = val - nor[1];
out[2] = val - nor[2];
}
-static void exec(void *data, int UNUSED(thread), bNode *node, bNodeExecData *execdata, bNodeStack **in, bNodeStack **out)
+static void exec(void *data, int UNUSED(thread), bNode *node, bNodeExecData *execdata, bNodeStack **in, bNodeStack **out)
{
tex_output(node, execdata, in, out[0], &normalfn, data);
}
@@ -83,10 +83,10 @@ static void exec(void *data, int UNUSED(thread), bNode *node, bNodeExecData *exe
void register_node_type_tex_valtonor(void)
{
static bNodeType ntype;
-
+
tex_node_type_base(&ntype, TEX_NODE_VALTONOR, "Value to Normal", NODE_CLASS_CONVERTOR, 0);
node_type_socket_templates(&ntype, inputs, outputs);
node_type_exec(&ntype, NULL, NULL, exec);
-
+
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/texture/nodes/node_texture_valToRgb.c b/source/blender/nodes/texture/nodes/node_texture_valToRgb.c
index 4041d666811..ad3c4344f34 100644
--- a/source/blender/nodes/texture/nodes/node_texture_valToRgb.c
+++ b/source/blender/nodes/texture/nodes/node_texture_valToRgb.c
@@ -53,7 +53,7 @@ static void valtorgb_colorfn(float *out, TexParams *p, bNode *node, bNodeStack *
}
}
-static void valtorgb_exec(void *data, int UNUSED(thread), bNode *node, bNodeExecData *execdata, bNodeStack **in, bNodeStack **out)
+static void valtorgb_exec(void *data, int UNUSED(thread), bNode *node, bNodeExecData *execdata, bNodeStack **in, bNodeStack **out)
{
tex_output(node, execdata, in, out[0], &valtorgb_colorfn, data);
}
@@ -66,14 +66,14 @@ static void valtorgb_init(bNodeTree *UNUSED(ntree), bNode *node)
void register_node_type_tex_valtorgb(void)
{
static bNodeType ntype;
-
+
tex_node_type_base(&ntype, TEX_NODE_VALTORGB, "ColorRamp", NODE_CLASS_CONVERTOR, 0);
node_type_socket_templates(&ntype, valtorgb_in, valtorgb_out);
node_type_size_preset(&ntype, NODE_SIZE_LARGE);
node_type_init(&ntype, valtorgb_init);
node_type_storage(&ntype, "ColorBand", node_free_standard_storage, node_copy_standard_storage);
node_type_exec(&ntype, NULL, NULL, valtorgb_exec);
-
+
nodeRegisterType(&ntype);
}
@@ -103,10 +103,10 @@ static void rgbtobw_exec(void *data, int UNUSED(thread), bNode *node, bNodeExecD
void register_node_type_tex_rgbtobw(void)
{
static bNodeType ntype;
-
+
tex_node_type_base(&ntype, TEX_NODE_RGBTOBW, "RGB to BW", NODE_CLASS_CONVERTOR, 0);
node_type_socket_templates(&ntype, rgbtobw_in, rgbtobw_out);
node_type_exec(&ntype, NULL, NULL, rgbtobw_exec);
-
+
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/texture/nodes/node_texture_viewer.c b/source/blender/nodes/texture/nodes/node_texture_viewer.c
index fefa06b0078..69f4d3ca086 100644
--- a/source/blender/nodes/texture/nodes/node_texture_viewer.c
+++ b/source/blender/nodes/texture/nodes/node_texture_viewer.c
@@ -59,13 +59,13 @@ static void exec(void *data, int UNUSED(thread), bNode *UNUSED(node), bNodeExecD
void register_node_type_tex_viewer(void)
{
static bNodeType ntype;
-
+
tex_node_type_base(&ntype, TEX_NODE_VIEWER, "Viewer", NODE_CLASS_OUTPUT, NODE_PREVIEW);
node_type_socket_templates(&ntype, inputs, outputs);
node_type_exec(&ntype, NULL, NULL, exec);
-
+
/* Do not allow muting viewer node. */
node_type_internal_links(&ntype, NULL);
-
+
nodeRegisterType(&ntype);
}
diff --git a/source/blender/physics/intern/BPH_mass_spring.cpp b/source/blender/physics/intern/BPH_mass_spring.cpp
index e5724c97bbc..c8932045c52 100644
--- a/source/blender/physics/intern/BPH_mass_spring.cpp
+++ b/source/blender/physics/intern/BPH_mass_spring.cpp
@@ -60,7 +60,7 @@ static int cloth_count_nondiag_blocks(Cloth *cloth)
{
LinkNode *link;
int nondiag = 0;
-
+
for (link = cloth->springs; link; link = link->next) {
ClothSpring *spring = (ClothSpring *)link->link;
switch (spring->type) {
@@ -68,14 +68,14 @@ static int cloth_count_nondiag_blocks(Cloth *cloth)
/* angular bending combines 3 vertices */
nondiag += 3;
break;
-
+
default:
/* all other springs depend on 2 vertices only */
nondiag += 1;
break;
}
}
-
+
return nondiag;
}
@@ -86,25 +86,25 @@ int BPH_cloth_solver_init(Object *UNUSED(ob), ClothModifierData *clmd)
const float ZERO[3] = {0.0f, 0.0f, 0.0f};
Implicit_Data *id;
unsigned int i, nondiag;
-
+
nondiag = cloth_count_nondiag_blocks(cloth);
cloth->implicit = id = BPH_mass_spring_solver_create(cloth->mvert_num, nondiag);
-
+
for (i = 0; i < cloth->mvert_num; i++) {
BPH_mass_spring_set_vertex_mass(id, i, verts[i].mass);
}
-
+
for (i = 0; i < cloth->mvert_num; i++) {
BPH_mass_spring_set_motion_state(id, i, verts[i].x, ZERO);
}
-
+
return 1;
}
void BPH_cloth_solver_free(ClothModifierData *clmd)
{
Cloth *cloth = clmd->clothObject;
-
+
if (cloth->implicit) {
BPH_mass_spring_solver_free(cloth->implicit);
cloth->implicit = NULL;
@@ -118,7 +118,7 @@ void BKE_cloth_solver_set_positions(ClothModifierData *clmd)
unsigned int mvert_num = cloth->mvert_num, i;
ClothHairData *cloth_hairdata = clmd->hairdata;
Implicit_Data *id = cloth->implicit;
-
+
for (i = 0; i < mvert_num; i++) {
if (cloth_hairdata) {
ClothHairData *root = &cloth_hairdata[i];
@@ -126,7 +126,7 @@ void BKE_cloth_solver_set_positions(ClothModifierData *clmd)
}
else
BPH_mass_spring_set_rest_transform(id, i, I3);
-
+
BPH_mass_spring_set_motion_state(id, i, verts[i].x, verts[i].v);
}
}
@@ -136,22 +136,22 @@ static bool collision_response(ClothModifierData *clmd, CollisionModifierData *c
Cloth *cloth = clmd->clothObject;
int index = collpair->ap1;
bool result = false;
-
+
float v1[3], v2_old[3], v2_new[3], v_rel_old[3], v_rel_new[3];
float epsilon2 = BLI_bvhtree_get_epsilon(collmd->bvhtree);
float margin_distance = (float)collpair->distance - epsilon2;
float mag_v_rel;
-
+
zero_v3(r_impulse);
-
+
if (margin_distance > 0.0f)
return false; /* XXX tested before already? */
-
+
/* only handle static collisions here */
if ( collpair->flag & COLLISION_IN_FUTURE )
return false;
-
+
/* velocity */
copy_v3_v3(v1, cloth->verts[index].v);
collision_get_collider_velocity(v2_old, v2_new, collmd, collpair);
@@ -160,32 +160,32 @@ static bool collision_response(ClothModifierData *clmd, CollisionModifierData *c
sub_v3_v3v3(v_rel_new, v1, v2_new);
/* normal component of the relative velocity */
mag_v_rel = dot_v3v3(v_rel_old, collpair->normal);
-
+
/* only valid when moving toward the collider */
if (mag_v_rel < -ALMOST_ZERO) {
float v_nor_old, v_nor_new;
float v_tan_old[3], v_tan_new[3];
float bounce, repulse;
-
+
/* Collision response based on
* "Simulating Complex Hair with Robust Collision Handling" (Choe, Choi, Ko, ACM SIGGRAPH 2005)
* http://graphics.snu.ac.kr/publications/2005-choe-HairSim/Choe_2005_SCA.pdf
*/
-
+
v_nor_old = mag_v_rel;
v_nor_new = dot_v3v3(v_rel_new, collpair->normal);
-
+
madd_v3_v3v3fl(v_tan_old, v_rel_old, collpair->normal, -v_nor_old);
madd_v3_v3v3fl(v_tan_new, v_rel_new, collpair->normal, -v_nor_new);
-
+
bounce = -v_nor_old * restitution;
-
+
repulse = -margin_distance / dt; /* base repulsion velocity in normal direction */
/* XXX this clamping factor is quite arbitrary ...
* not sure if there is a more scientific approach, but seems to give good results
*/
CLAMP(repulse, 0.0f, 4.0f * bounce);
-
+
if (margin_distance < -epsilon2) {
mul_v3_v3fl(r_impulse, collpair->normal, max_ff(repulse, bounce) - v_nor_new);
}
@@ -193,10 +193,10 @@ static bool collision_response(ClothModifierData *clmd, CollisionModifierData *c
bounce = 0.0f;
mul_v3_v3fl(r_impulse, collpair->normal, repulse - v_nor_new);
}
-
+
result = true;
}
-
+
return result;
}
@@ -211,17 +211,17 @@ static void cloth_setup_constraints(ClothModifierData *clmd, ColliderContacts *c
ClothVertex *verts = cloth->verts;
int mvert_num = cloth->mvert_num;
int i, j, v;
-
+
const float ZERO[3] = {0.0f, 0.0f, 0.0f};
-
+
BPH_mass_spring_clear_constraints(data);
-
+
for (v = 0; v < mvert_num; v++) {
if (verts[v].flags & CLOTH_VERT_FLAG_PINNED) {
/* pinned vertex constraints */
BPH_mass_spring_add_constraint_ndof0(data, v, ZERO); /* velocity is defined externally */
}
-
+
verts[v].impulse_count = 0;
}
@@ -233,21 +233,21 @@ static void cloth_setup_constraints(ClothModifierData *clmd, ColliderContacts *c
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;
}
@@ -267,11 +267,11 @@ static int UNUSED_FUNCTION(cloth_calc_helper_forces)(Object *UNUSED(ob), ClothMo
ClothSpring *spring;
ClothVertex *cv;
int i, steps;
-
+
cv = cloth->verts;
for (i = 0; i < cloth->mvert_num; i++, cv++) {
copy_v3_v3(cos[i], cv->tx);
-
+
if (cv->goal == 1.0f || len_squared_v3v3(initial_cos[i], cv->tx) != 0.0f) {
masses[i] = 1e+10;
}
@@ -279,57 +279,57 @@ static int UNUSED_FUNCTION(cloth_calc_helper_forces)(Object *UNUSED(ob), ClothMo
masses[i] = cv->mass;
}
}
-
+
steps = 55;
for (i=0; i<steps; i++) {
for (node=cloth->springs; node; node=node->next) {
/* ClothVertex *cv1, *cv2; */ /* UNUSED */
int v1, v2;
float len, c, l, vec[3];
-
+
spring = (ClothSpring *)node->link;
- if (spring->type != CLOTH_SPRING_TYPE_STRUCTURAL && spring->type != CLOTH_SPRING_TYPE_SHEAR)
+ if (spring->type != CLOTH_SPRING_TYPE_STRUCTURAL && spring->type != CLOTH_SPRING_TYPE_SHEAR)
continue;
-
+
v1 = spring->ij; v2 = spring->kl;
/* cv1 = cloth->verts + v1; */ /* UNUSED */
/* cv2 = cloth->verts + v2; */ /* UNUSED */
len = len_v3v3(cos[v1], cos[v2]);
-
+
sub_v3_v3v3(vec, cos[v1], cos[v2]);
normalize_v3(vec);
-
+
c = (len - spring->restlen);
if (c == 0.0f)
continue;
-
+
l = c / ((1.0f / masses[v1]) + (1.0f / masses[v2]));
-
+
mul_v3_fl(vec, -(1.0f / masses[v1]) * l);
add_v3_v3(cos[v1], vec);
-
+
sub_v3_v3v3(vec, cos[v2], cos[v1]);
normalize_v3(vec);
-
+
mul_v3_fl(vec, -(1.0f / masses[v2]) * l);
add_v3_v3(cos[v2], vec);
}
}
-
+
cv = cloth->verts;
for (i = 0; i < cloth->mvert_num; i++, cv++) {
float vec[3];
-
+
/*compute forces*/
sub_v3_v3v3(vec, cos[i], cv->tx);
mul_v3_fl(vec, cv->mass*dt*20.0f);
add_v3_v3(cv->tv, vec);
//copy_v3_v3(cv->tx, cos[i]);
}
-
+
MEM_freeN(cos);
MEM_freeN(masses);
-
+
return 1;
}
@@ -338,21 +338,21 @@ BLI_INLINE void cloth_calc_spring_force(ClothModifierData *clmd, ClothSpring *s)
Cloth *cloth = clmd->clothObject;
ClothSimSettings *parms = clmd->sim_parms;
Implicit_Data *data = cloth->implicit;
-
+
bool no_compress = parms->flags & CLOTH_SIMSETTINGS_FLAG_NO_SPRING_COMPRESS;
-
+
s->flags &= ~CLOTH_SPRING_FLAG_NEEDED;
-
+
// calculate force of structural + shear springs
if ((s->type & CLOTH_SPRING_TYPE_STRUCTURAL) || (s->type & CLOTH_SPRING_TYPE_SHEAR) || (s->type & CLOTH_SPRING_TYPE_SEWING) ) {
#ifdef CLOTH_FORCE_SPRING_STRUCTURAL
float k, scaling;
-
+
s->flags |= CLOTH_SPRING_FLAG_NEEDED;
-
+
scaling = parms->structural + s->stiffness * fabsf(parms->max_struct - parms->structural);
k = scaling / (parms->avg_spring_len + FLT_EPSILON);
-
+
if (s->type & CLOTH_SPRING_TYPE_SEWING) {
// TODO: verify, half verified (couldn't see error)
// sewing springs usually have a large distance at first so clamp the force so we don't get tunnelling through colission objects
@@ -366,50 +366,50 @@ BLI_INLINE void cloth_calc_spring_force(ClothModifierData *clmd, ClothSpring *s)
else if (s->type & CLOTH_SPRING_TYPE_BENDING) { /* calculate force of bending springs */
#ifdef CLOTH_FORCE_SPRING_BEND
float kb, cb, scaling;
-
+
s->flags |= CLOTH_SPRING_FLAG_NEEDED;
-
+
scaling = parms->bending + s->stiffness * fabsf(parms->max_bend - parms->bending);
kb = scaling / (20.0f * (parms->avg_spring_len + FLT_EPSILON));
-
+
// Fix for [#45084] for cloth stiffness must have cb proportional to kb
cb = kb * parms->bending_damping;
-
+
BPH_mass_spring_force_spring_bending(data, s->ij, s->kl, s->restlen, kb, cb);
#endif
}
else if (s->type & CLOTH_SPRING_TYPE_BENDING_ANG) {
#ifdef CLOTH_FORCE_SPRING_BEND
float kb, cb, scaling;
-
+
s->flags |= CLOTH_SPRING_FLAG_NEEDED;
-
+
/* XXX WARNING: angular bending springs for hair apply stiffness factor as an overall factor, unlike cloth springs!
* this is crap, but needed due to cloth/hair mixing ...
* max_bend factor is not even used for hair, so ...
*/
scaling = s->stiffness * parms->bending;
kb = scaling / (20.0f * (parms->avg_spring_len + FLT_EPSILON));
-
+
// Fix for [#45084] for cloth stiffness must have cb proportional to kb
cb = kb * parms->bending_damping;
-
+
/* XXX assuming same restlen for ij and jk segments here, this can be done correctly for hair later */
BPH_mass_spring_force_spring_bending_angular(data, s->ij, s->kl, s->mn, s->target, kb, cb);
-
+
#if 0
{
float x_kl[3], x_mn[3], v[3], d[3];
-
+
BPH_mass_spring_get_motion_state(data, s->kl, x_kl, v);
BPH_mass_spring_get_motion_state(data, s->mn, x_mn, v);
-
+
BKE_sim_debug_data_add_dot(clmd->debug_data, x_kl, 0.9, 0.9, 0.9, "target", 7980, s->kl);
BKE_sim_debug_data_add_line(clmd->debug_data, x_kl, x_mn, 0.8, 0.8, 0.8, "target", 7981, s->kl);
-
+
copy_v3_v3(d, s->target);
BKE_sim_debug_data_add_vector(clmd->debug_data, x_kl, d, 0.8, 0.8, 0.2, "target", 7982, s->kl);
-
+
// copy_v3_v3(d, s->target_ij);
// BKE_sim_debug_data_add_vector(clmd->debug_data, x, d, 1, 0.4, 0.4, "target", 7983, s->kl);
}
@@ -424,7 +424,7 @@ static void hair_get_boundbox(ClothModifierData *clmd, float gmin[3], float gmax
Implicit_Data *data = cloth->implicit;
unsigned int mvert_num = cloth->mvert_num;
int i;
-
+
INIT_MINMAX(gmin, gmax);
for (i = 0; i < mvert_num; i++) {
float x[3];
@@ -444,7 +444,7 @@ static void cloth_calc_force(ClothModifierData *clmd, float UNUSED(frame), ListB
const MVertTri *tri = cloth->tri;
unsigned int mvert_num = cloth->mvert_num;
ClothVertex *vert;
-
+
#ifdef CLOTH_FORCE_GRAVITY
/* global acceleration (gravitation) */
if (clmd->scene->physics_settings.flag & PHYS_GLOBAL_GRAVITY) {
@@ -477,7 +477,7 @@ static void cloth_calc_force(ClothModifierData *clmd, float UNUSED(frame), ListB
#ifdef CLOTH_FORCE_DRAG
BPH_mass_spring_force_drag(data, drag);
#endif
-
+
/* handle external forces like wind */
if (effectors) {
/* cache per-vertex forces to avoid redundant calculation */
@@ -485,12 +485,12 @@ static void cloth_calc_force(ClothModifierData *clmd, float UNUSED(frame), ListB
for (i = 0; i < cloth->mvert_num; i++) {
float x[3], v[3];
EffectedPoint epoint;
-
+
BPH_mass_spring_get_motion_state(data, i, x, v);
pd_point_from_loc(clmd->scene, x, v, i, &epoint);
pdDoEffectors(effectors, NULL, clmd->sim_parms->effector_weights, &epoint, winvec[i], NULL);
}
-
+
for (i = 0; i < cloth->tri_num; i++) {
const MVertTri *vt = &tri[i];
BPH_mass_spring_force_face_wind(data, vt->tri[0], vt->tri[1], vt->tri[2], winvec);
@@ -501,7 +501,7 @@ static void cloth_calc_force(ClothModifierData *clmd, float UNUSED(frame), ListB
#if 0
ClothHairData *hairdata = clmd->hairdata;
ClothHairData *hair_ij, *hair_kl;
-
+
for (LinkNode *link = cloth->springs; link; link = link->next) {
ClothSpring *spring = (ClothSpring *)link->link;
if (spring->type == CLOTH_SPRING_TYPE_STRUCTURAL) {
@@ -516,7 +516,7 @@ static void cloth_calc_force(ClothModifierData *clmd, float UNUSED(frame), ListB
}
#else
ClothHairData *hairdata = clmd->hairdata;
-
+
vert = cloth->verts;
for (i = 0; i < cloth->mvert_num; i++, vert++) {
if (hairdata) {
@@ -531,7 +531,7 @@ static void cloth_calc_force(ClothModifierData *clmd, float UNUSED(frame), ListB
MEM_freeN(winvec);
}
-
+
// calculate spring forces
for (LinkNode *link = cloth->springs; link; link = link->next) {
ClothSpring *spring = (ClothSpring *)link->link;
@@ -548,7 +548,7 @@ BLI_INLINE void cloth_get_grid_location(Implicit_Data *data, float cell_scale, c
{
BPH_mass_spring_get_position(data, index, x);
BPH_mass_spring_get_new_velocity(data, index, v);
-
+
mul_v3_fl(x, cell_scale);
add_v3_v3(x, cell_offset);
}
@@ -582,41 +582,41 @@ static LinkNode *cloth_continuum_add_hair_segments(HairGrid *grid, const float c
// ClothVertex *vert3, *vert4;
float x1[3], v1[3], x2[3], v2[3], x3[3], v3[3], x4[3], v4[3];
float dir1[3], dir2[3], dir3[3];
-
+
spring1 = NULL;
spring2 = NULL;
spring3 = (ClothSpring *)spring_link->link;
-
+
zero_v3(x1); zero_v3(v1);
zero_v3(dir1);
zero_v3(x2); zero_v3(v2);
zero_v3(dir2);
-
+
// vert3 = &verts[spring3->kl];
cloth_get_grid_location(data, cell_scale, cell_offset, spring3->kl, x3, v3);
// vert4 = &verts[spring3->ij];
cloth_get_grid_location(data, cell_scale, cell_offset, spring3->ij, x4, v4);
sub_v3_v3v3(dir3, x4, x3);
normalize_v3(dir3);
-
+
while (spring_link) {
/* move on */
spring1 = spring2;
spring2 = spring3;
-
+
// vert3 = vert4;
-
+
copy_v3_v3(x1, x2); copy_v3_v3(v1, v2);
copy_v3_v3(x2, x3); copy_v3_v3(v2, v3);
copy_v3_v3(x3, x4); copy_v3_v3(v3, v4);
-
+
copy_v3_v3(dir1, dir2);
copy_v3_v3(dir2, dir3);
-
+
/* read next segment */
next_spring_link = spring_link->next;
spring_link = hair_spring_next(spring_link);
-
+
if (spring_link) {
spring3 = (ClothSpring *)spring_link->link;
// vert4 = &verts[spring3->ij];
@@ -630,13 +630,13 @@ static LinkNode *cloth_continuum_add_hair_segments(HairGrid *grid, const float c
zero_v3(x4); zero_v3(v4);
zero_v3(dir3);
}
-
+
BPH_hair_volume_add_segment(grid, x1, v1, x2, v2, x3, v3, x4, v4,
spring1 ? dir1 : NULL,
dir2,
spring3 ? dir3 : NULL);
}
-
+
return next_spring_link;
}
@@ -647,17 +647,17 @@ static void cloth_continuum_fill_grid(HairGrid *grid, Cloth *cloth)
int mvert_num = cloth->mvert_num;
ClothVertex *vert;
int i;
-
+
for (i = 0, vert = cloth->verts; i < mvert_num; i++, vert++) {
float x[3], v[3];
-
+
cloth_get_vertex_motion_state(data, vert, x, v);
BPH_hair_volume_add_vertex(grid, x, v);
}
#else
LinkNode *link;
float cellsize, gmin[3], cell_scale, cell_offset[3];
-
+
/* scale and offset for transforming vertex locations into grid space
* (cell size is 0..1, gmin becomes origin)
*/
@@ -665,7 +665,7 @@ static void cloth_continuum_fill_grid(HairGrid *grid, Cloth *cloth)
cell_scale = cellsize > 0.0f ? 1.0f / cellsize : 0.0f;
mul_v3_v3fl(cell_offset, gmin, cell_scale);
negate_v3(cell_offset);
-
+
link = cloth->springs;
while (link) {
ClothSpring *spring = (ClothSpring *)link->link;
@@ -685,7 +685,7 @@ static void cloth_continuum_step(ClothModifierData *clmd, float dt)
Implicit_Data *data = cloth->implicit;
int mvert_num = cloth->mvert_num;
ClothVertex *vert;
-
+
const float fluid_factor = 0.95f; /* blend between PIC and FLIP methods */
float smoothfac = parms->velocity_smooth;
/* XXX FIXME arbitrary factor!!! this should be based on some intuitive value instead,
@@ -695,42 +695,42 @@ static void cloth_continuum_step(ClothModifierData *clmd, float dt)
float density_strength = parms->density_strength;
float gmin[3], gmax[3];
int i;
-
+
/* clear grid info */
zero_v3_int(clmd->hair_grid_res);
zero_v3(clmd->hair_grid_min);
zero_v3(clmd->hair_grid_max);
clmd->hair_grid_cellsize = 0.0f;
-
+
hair_get_boundbox(clmd, gmin, gmax);
-
+
/* gather velocities & density */
if (smoothfac > 0.0f || density_strength > 0.0f) {
HairGrid *grid = BPH_hair_volume_create_vertex_grid(clmd->sim_parms->voxel_cell_size, gmin, gmax);
-
+
cloth_continuum_fill_grid(grid, cloth);
-
+
/* main hair continuum solver */
BPH_hair_volume_solve_divergence(grid, dt, density_target, density_strength);
-
+
for (i = 0, vert = cloth->verts; i < mvert_num; i++, vert++) {
float x[3], v[3], nv[3];
-
+
/* calculate volumetric velocity influence */
BPH_mass_spring_get_position(data, i, x);
BPH_mass_spring_get_new_velocity(data, i, v);
-
+
BPH_hair_volume_grid_velocity(grid, x, v, fluid_factor, nv);
-
+
interp_v3_v3v3(nv, v, nv, smoothfac);
-
+
/* apply on hair data */
BPH_mass_spring_set_new_velocity(data, i, nv);
}
-
+
/* store basic grid info in the modifier data */
BPH_hair_volume_grid_geometry(grid, &clmd->hair_grid_cellsize, clmd->hair_grid_res, clmd->hair_grid_min, clmd->hair_grid_max);
-
+
#if 0 /* DEBUG hair velocity vector field */
{
const int size = 64;
@@ -738,26 +738,26 @@ static void cloth_continuum_step(ClothModifierData *clmd, float dt)
float offset[3], a[3], b[3];
const int axis = 0;
const float shift = 0.0f;
-
+
copy_v3_v3(offset, clmd->hair_grid_min);
zero_v3(a);
zero_v3(b);
-
+
offset[axis] = shift * clmd->hair_grid_cellsize;
a[(axis+1) % 3] = clmd->hair_grid_max[(axis+1) % 3] - clmd->hair_grid_min[(axis+1) % 3];
b[(axis+2) % 3] = clmd->hair_grid_max[(axis+2) % 3] - clmd->hair_grid_min[(axis+2) % 3];
-
+
BKE_sim_debug_data_clear_category(clmd->debug_data, "grid velocity");
for (j = 0; j < size; ++j) {
for (i = 0; i < size; ++i) {
float x[3], v[3], gvel[3], gvel_smooth[3], gdensity;
-
+
madd_v3_v3v3fl(x, offset, a, (float)i / (float)(size-1));
madd_v3_v3fl(x, b, (float)j / (float)(size-1));
zero_v3(v);
-
+
BPH_hair_volume_grid_interpolate(grid, x, &gdensity, gvel, gvel_smooth, NULL, NULL);
-
+
// BKE_sim_debug_data_add_circle(clmd->debug_data, x, gdensity, 0.7, 0.3, 1, "grid density", i, j, 3111);
if (!is_zero_v3(gvel) || !is_zero_v3(gvel_smooth)) {
float dvel[3];
@@ -770,7 +770,7 @@ static void cloth_continuum_step(ClothModifierData *clmd, float dt)
float col0[3] = {0.0, 0.0, 0.0};
float col1[3] = {0.0, 1.0, 0.0};
float col[3];
-
+
interp_v3_v3v3(col, col0, col1, CLAMPIS(gdensity * clmd->sim_parms->density_strength, 0.0, 1.0));
// BKE_sim_debug_data_add_circle(clmd->debug_data, x, gdensity * clmd->sim_parms->density_strength, 0, 1, 0.4, "grid velocity", i, j, 3115);
// BKE_sim_debug_data_add_dot(clmd->debug_data, x, col[0], col[1], col[2], "grid velocity", i, j, 3115);
@@ -782,7 +782,7 @@ static void cloth_continuum_step(ClothModifierData *clmd, float dt)
}
}
#endif
-
+
BPH_hair_volume_free_vertex_grid(grid);
}
}
@@ -795,7 +795,7 @@ static void cloth_calc_volume_force(ClothModifierData *clmd)
Implicit_Data *data = cloth->implicit;
int mvert_num = cloth->mvert_num;
ClothVertex *vert;
-
+
/* 2.0f is an experimental value that seems to give good results */
float smoothfac = 2.0f * parms->velocity_smooth;
float collfac = 2.0f * parms->collider_friction;
@@ -803,17 +803,17 @@ static void cloth_calc_volume_force(ClothModifierData *clmd)
float minpress = parms->pressure_threshold;
float gmin[3], gmax[3];
int i;
-
+
hair_get_boundbox(clmd, gmin, gmax);
-
+
/* gather velocities & density */
if (smoothfac > 0.0f || pressfac > 0.0f) {
HairVertexGrid *vertex_grid = BPH_hair_volume_create_vertex_grid(clmd->sim_parms->voxel_res, gmin, gmax);
-
+
vert = cloth->verts;
for (i = 0; i < mvert_num; i++, vert++) {
float x[3], v[3];
-
+
if (vert->solver_index < 0) {
copy_v3_v3(x, vert->x);
copy_v3_v3(v, vert->v);
@@ -824,21 +824,21 @@ static void cloth_calc_volume_force(ClothModifierData *clmd)
BPH_hair_volume_add_vertex(vertex_grid, x, v);
}
BPH_hair_volume_normalize_vertex_grid(vertex_grid);
-
+
vert = cloth->verts;
for (i = 0; i < mvert_num; i++, vert++) {
float x[3], v[3], f[3], dfdx[3][3], dfdv[3][3];
-
+
if (vert->solver_index < 0)
continue;
-
+
/* calculate volumetric forces */
BPH_mass_spring_get_motion_state(data, vert->solver_index, x, v);
BPH_hair_volume_vertex_grid_forces(vertex_grid, x, v, smoothfac, pressfac, minpress, f, dfdx, dfdv);
/* apply on hair data */
BPH_mass_spring_force_extern(data, vert->solver_index, f, dfdx, dfdv);
}
-
+
BPH_hair_volume_free_vertex_grid(vertex_grid);
}
}
@@ -854,33 +854,33 @@ static void cloth_collision_solve_extra(Object *ob, ClothModifierData *clmd, Lis
ClothVertex *verts = cloth->verts;
int mvert_num = cloth->mvert_num;
const float spf = (float)clmd->sim_parms->stepsPerFrame / clmd->sim_parms->timescale;
-
+
bool do_extra_solve;
int i;
-
+
if (!(clmd->coll_parms->flags & CLOTH_COLLSETTINGS_FLAG_ENABLED))
return;
if (!clmd->clothObject->bvhtree)
return;
-
+
// update verts to current positions
for (i = 0; i < mvert_num; i++) {
BPH_mass_spring_get_new_position(id, i, verts[i].tx);
-
+
sub_v3_v3v3(verts[i].tv, verts[i].tx, verts[i].txold);
copy_v3_v3(verts[i].v, verts[i].tv);
}
-
+
#if 0 /* unused */
for (i=0, cv=cloth->verts; i<cloth->mvert_num; i++, cv++) {
copy_v3_v3(initial_cos[i], cv->tx);
}
#endif
-
+
// call collision function
// TODO: check if "step" or "step+dt" is correct - dg
do_extra_solve = cloth_bvh_objcollision(ob, clmd, step / clmd->sim_parms->timescale, dt / clmd->sim_parms->timescale);
-
+
// copy corrected positions back to simulation
for (i = 0; i < mvert_num; i++) {
float curx[3];
@@ -888,41 +888,41 @@ static void cloth_collision_solve_extra(Object *ob, ClothModifierData *clmd, Lis
// correct velocity again, just to be sure we had to change it due to adaptive collisions
sub_v3_v3v3(verts[i].tv, verts[i].tx, curx);
}
-
+
if (do_extra_solve) {
// cloth_calc_helper_forces(ob, clmd, initial_cos, step/clmd->sim_parms->timescale, dt/clmd->sim_parms->timescale);
-
+
for (i = 0; i < mvert_num; i++) {
-
+
float newv[3];
-
+
if ((clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_GOAL) && (verts [i].flags & CLOTH_VERT_FLAG_PINNED))
continue;
-
+
BPH_mass_spring_set_new_position(id, i, verts[i].tx);
mul_v3_v3fl(newv, verts[i].tv, spf);
BPH_mass_spring_set_new_velocity(id, i, newv);
}
}
-
+
// X = Xnew;
BPH_mass_spring_apply_result(id);
-
+
if (do_extra_solve) {
ImplicitSolverResult result;
-
+
/* initialize forces to zero */
BPH_mass_spring_clear_forces(id);
-
+
// calculate forces
cloth_calc_force(clmd, frame, effectors, step);
-
+
// calculate new velocity and position
BPH_mass_spring_solve_velocities(id, dt, &result);
// cloth_record_result(clmd, &result, clmd->sim_parms->stepsPerFrame);
-
+
/* note: positions are advanced only once in the main solver step! */
-
+
BPH_mass_spring_apply_result(id);
}
}
@@ -930,7 +930,7 @@ static void cloth_collision_solve_extra(Object *ob, ClothModifierData *clmd, Lis
static void cloth_clear_result(ClothModifierData *clmd)
{
ClothSolverResult *sres = clmd->solver_result;
-
+
sres->status = 0;
sres->max_error = sres->min_error = sres->avg_error = 0.0f;
sres->max_iterations = sres->min_iterations = 0;
@@ -940,7 +940,7 @@ static void cloth_clear_result(ClothModifierData *clmd)
static void cloth_record_result(ClothModifierData *clmd, ImplicitSolverResult *result, int steps)
{
ClothSolverResult *sres = clmd->solver_result;
-
+
if (sres->status) { /* already initialized ? */
/* error only makes sense for successful iterations */
if (result->status == BPH_SOLVER_SUCCESS) {
@@ -948,7 +948,7 @@ static void cloth_record_result(ClothModifierData *clmd, ImplicitSolverResult *r
sres->max_error = max_ff(sres->max_error, result->error);
sres->avg_error += result->error / (float)steps;
}
-
+
sres->min_iterations = min_ii(sres->min_iterations, result->iterations);
sres->max_iterations = max_ii(sres->max_iterations, result->iterations);
sres->avg_iterations += (float)result->iterations / (float)steps;
@@ -959,11 +959,11 @@ static void cloth_record_result(ClothModifierData *clmd, ImplicitSolverResult *r
sres->min_error = sres->max_error = result->error;
sres->avg_error += result->error / (float)steps;
}
-
+
sres->min_iterations = sres->max_iterations = result->iterations;
sres->avg_iterations += (float)result->iterations / (float)steps;
}
-
+
sres->status |= result->status;
}
@@ -974,7 +974,7 @@ int BPH_cloth_solve(Object *ob, float frame, ClothModifierData *clmd, ListBase *
* Bad design, TODO
*/
const bool is_hair = (clmd->hairdata != NULL);
-
+
unsigned int i=0;
float step=0.0f, tf=clmd->sim_parms->timescale;
Cloth *cloth = clmd->clothObject;
@@ -984,13 +984,13 @@ int BPH_cloth_solve(Object *ob, float frame, ClothModifierData *clmd, ListBase *
Implicit_Data *id = cloth->implicit;
ColliderContacts *contacts = NULL;
int totcolliders = 0;
-
+
BKE_sim_debug_data_clear_category("collision");
-
+
if (!clmd->solver_result)
clmd->solver_result = (ClothSolverResult *)MEM_callocN(sizeof(ClothSolverResult), "cloth solver result");
cloth_clear_result(clmd);
-
+
if (clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_GOAL) { /* do goal stuff */
for (i = 0; i < mvert_num; i++) {
// update velocities with constrained velocities from pinned verts
@@ -1004,22 +1004,22 @@ int BPH_cloth_solve(Object *ob, float frame, ClothModifierData *clmd, ListBase *
}
}
}
-
+
while (step < tf) {
ImplicitSolverResult result;
-
+
/* copy velocities for collision */
for (i = 0; i < mvert_num; i++) {
BPH_mass_spring_get_motion_state(id, i, NULL, verts[i].tv);
copy_v3_v3(verts[i].v, verts[i].tv);
}
-
+
if (is_hair) {
/* determine contact points */
if (clmd->coll_parms->flags & CLOTH_COLLSETTINGS_FLAG_ENABLED) {
cloth_find_point_contacts(ob, clmd, 0.0f, tf, &contacts, &totcolliders);
}
-
+
/* setup vertex constraints for pinned vertices and contacts */
cloth_setup_constraints(clmd, contacts, totcolliders, dt);
}
@@ -1027,10 +1027,10 @@ int BPH_cloth_solve(Object *ob, float frame, ClothModifierData *clmd, ListBase *
/* setup vertex constraints for pinned vertices */
cloth_setup_constraints(clmd, NULL, 0, dt);
}
-
+
/* initialize forces to zero */
BPH_mass_spring_clear_forces(id);
-
+
// damping velocity for artistic reasons
// this is a bad way to do it, should be removed imo - lukas_t
if (clmd->sim_parms->vel_damping != 1.0f) {
@@ -1041,26 +1041,26 @@ int BPH_cloth_solve(Object *ob, float frame, ClothModifierData *clmd, ListBase *
BPH_mass_spring_set_velocity(id, i, v);
}
}
-
+
// calculate forces
cloth_calc_force(clmd, frame, effectors, step);
-
+
// calculate new velocity and position
BPH_mass_spring_solve_velocities(id, dt, &result);
cloth_record_result(clmd, &result, clmd->sim_parms->stepsPerFrame);
-
+
if (is_hair) {
cloth_continuum_step(clmd, dt);
}
-
+
BPH_mass_spring_solve_positions(id, dt);
-
+
if (!is_hair) {
cloth_collision_solve_extra(ob, clmd, effectors, frame, step, dt);
}
-
+
BPH_mass_spring_apply_result(id);
-
+
/* move pinned verts to correct position */
for (i = 0; i < mvert_num; i++) {
if (clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_GOAL) {
@@ -1071,23 +1071,23 @@ int BPH_cloth_solve(Object *ob, float frame, ClothModifierData *clmd, ListBase *
BPH_mass_spring_set_position(id, i, x);
}
}
-
+
BPH_mass_spring_get_motion_state(id, i, verts[i].txold, NULL);
}
-
+
/* free contact points */
if (contacts) {
cloth_free_contacts(contacts, totcolliders);
}
-
+
step += dt;
}
-
+
/* copy results back to cloth data */
for (i = 0; i < mvert_num; i++) {
BPH_mass_spring_get_motion_state(id, i, verts[i].x, verts[i].v);
copy_v3_v3(verts[i].txold, verts[i].x);
}
-
+
return 1;
}
diff --git a/source/blender/physics/intern/ConstrainedConjugateGradient.h b/source/blender/physics/intern/ConstrainedConjugateGradient.h
index f9c6931fe8c..2d5fb41cc73 100644
--- a/source/blender/physics/intern/ConstrainedConjugateGradient.h
+++ b/source/blender/physics/intern/ConstrainedConjugateGradient.h
@@ -4,7 +4,7 @@
#include <Eigen/Core>
-namespace Eigen {
+namespace Eigen {
namespace internal {
@@ -29,16 +29,16 @@ void constrained_conjugate_gradient(const MatrixType& mat, const Rhs& rhs, Dest&
typedef typename Dest::RealScalar RealScalar;
typedef typename Dest::Scalar Scalar;
typedef Matrix<Scalar,Dynamic,1> VectorType;
-
+
RealScalar tol = tol_error;
int maxIters = iters;
-
+
int n = mat.cols();
VectorType residual = filter * (rhs - mat * x); //initial residual
RealScalar rhsNorm2 = (filter * rhs).squaredNorm();
- if(rhsNorm2 == 0)
+ if(rhsNorm2 == 0)
{
/* XXX TODO set constrained result here */
x.setZero();
@@ -54,7 +54,7 @@ void constrained_conjugate_gradient(const MatrixType& mat, const Rhs& rhs, Dest&
tol_error = sqrt(residualNorm2 / rhsNorm2);
return;
}
-
+
VectorType p(n);
p = filter * precond.solve(residual); //initial search direction
@@ -68,11 +68,11 @@ void constrained_conjugate_gradient(const MatrixType& mat, const Rhs& rhs, Dest&
Scalar alpha = absNew / p.dot(tmp); // the amount we travel on dir
x += alpha * p; // update solution
residual -= alpha * tmp; // update residue
-
+
residualNorm2 = residual.squaredNorm();
if(residualNorm2 < threshold)
break;
-
+
z = precond.solve(residual); // approximately solve for "A z = residual"
RealScalar absOld = absNew;
@@ -95,20 +95,20 @@ struct MatrixFilter
m_cmat(NULL)
{
}
-
+
MatrixFilter(const MatrixType &cmat) :
m_cmat(&cmat)
{
}
-
+
void setMatrix(const MatrixType &cmat) { m_cmat = &cmat; }
-
+
template <typename VectorType>
void apply(VectorType v) const
{
v = (*m_cmat) * v;
}
-
+
protected:
const MatrixType *m_cmat;
};
@@ -145,7 +145,7 @@ struct traits<ConstrainedConjugateGradient<_MatrixType,_UpLo,_FilterMatrixType,_
* The maximal number of iterations and tolerance value can be controlled via the setMaxIterations()
* and setTolerance() methods. The defaults are the size of the problem for the maximal number of iterations
* and NumTraits<Scalar>::epsilon() for the tolerance.
- *
+ *
* This class can be used as the direct solver classes. Here is a typical usage example:
* \code
* int n = 10000;
@@ -160,7 +160,7 @@ struct traits<ConstrainedConjugateGradient<_MatrixType,_UpLo,_FilterMatrixType,_
* // update b, and solve again
* x = cg.solve(b);
* \endcode
- *
+ *
* By default the iterations start with x=0 as an initial guess of the solution.
* One can control the start using the solveWithGuess() method. Here is a step by
* step execution example starting with a random guess and printing the evolution
@@ -176,7 +176,7 @@ struct traits<ConstrainedConjugateGradient<_MatrixType,_UpLo,_FilterMatrixType,_
* } while (cg.info()!=Success && i<100);
* \endcode
* Note that such a step by step excution is slightly slower.
- *
+ *
* \sa class SimplicialCholesky, DiagonalPreconditioner, IdentityPreconditioner
*/
template< typename _MatrixType, int _UpLo, typename _FilterMatrixType, typename _Preconditioner>
@@ -206,10 +206,10 @@ public:
ConstrainedConjugateGradient() : Base() {}
/** Initialize the solver with matrix \a A for further \c Ax=b solving.
- *
+ *
* This constructor is a shortcut for the default constructor followed
* by a call to compute().
- *
+ *
* \warning this class stores a reference to the matrix A as well as some
* precomputed values that depend on it. Therefore, if \a A is changed
* this class becomes invalid. Call compute() to update it with the new
@@ -258,7 +258,7 @@ public:
m_isInitialized = true;
m_info = m_error <= Base::m_tolerance ? Success : NoConvergence;
}
-
+
/** \internal */
template<typename Rhs,typename Dest>
void _solve(const Rhs& b, Dest& x) const
diff --git a/source/blender/physics/intern/eigen_utils.h b/source/blender/physics/intern/eigen_utils.h
index 8a5a9dbf5e9..4598d3ad3a7 100644
--- a/source/blender/physics/intern/eigen_utils.h
+++ b/source/blender/physics/intern/eigen_utils.h
@@ -56,24 +56,24 @@ typedef float Scalar;
class Vector3 : public Eigen::Vector3f {
public:
typedef float *ctype;
-
+
Vector3()
{
}
-
+
Vector3(const ctype &v)
{
for (int k = 0; k < 3; ++k)
coeffRef(k) = v[k];
}
-
+
Vector3& operator = (const ctype &v)
{
for (int k = 0; k < 3; ++k)
coeffRef(k) = v[k];
return *this;
}
-
+
operator ctype()
{
return data();
@@ -86,18 +86,18 @@ public:
class Matrix3 : public Eigen::Matrix3f {
public:
typedef float (*ctype)[3];
-
+
Matrix3()
{
}
-
+
Matrix3(const ctype &v)
{
for (int k = 0; k < 3; ++k)
for (int l = 0; l < 3; ++l)
coeffRef(l, k) = v[k][l];
}
-
+
Matrix3& operator = (const ctype &v)
{
for (int k = 0; k < 3; ++k)
@@ -105,7 +105,7 @@ public:
coeffRef(l, k) = v[k][l];
return *this;
}
-
+
operator ctype()
{
return (ctype)data();
@@ -120,23 +120,23 @@ typedef Eigen::VectorXf lVector;
class lVector3f : public Eigen::VectorXf {
public:
typedef Eigen::VectorXf base_t;
-
+
lVector3f()
{
}
-
+
template <typename T>
lVector3f& operator = (T rhs)
{
base_t::operator=(rhs);
return *this;
}
-
+
float* v3(int vertex)
{
return &coeffRef(3 * vertex);
}
-
+
const float* v3(int vertex) const
{
return &coeffRef(3 * vertex);
@@ -157,18 +157,18 @@ struct lMatrix3fCtor {
lMatrix3fCtor()
{
}
-
+
void reset()
{
m_trips.clear();
}
-
+
void reserve(int numverts)
{
/* reserve for diagonal entries */
m_trips.reserve(numverts * 9);
}
-
+
void add(int i, int j, const Matrix3 &m)
{
i *= 3;
@@ -177,7 +177,7 @@ struct lMatrix3fCtor {
for (int l = 0; l < 3; ++l)
m_trips.push_back(Triplet(i + k, j + l, m.coeff(l, k)));
}
-
+
void sub(int i, int j, const Matrix3 &m)
{
i *= 3;
@@ -186,13 +186,13 @@ struct lMatrix3fCtor {
for (int l = 0; l < 3; ++l)
m_trips.push_back(Triplet(i + k, j + l, -m.coeff(l, k)));
}
-
+
inline void construct(lMatrix &m)
{
m.setFromTriplets(m_trips.begin(), m_trips.end());
m_trips.clear();
}
-
+
private:
TripletList m_trips;
};
@@ -206,7 +206,7 @@ BLI_INLINE void print_lvector(const lVector3f &v)
for (int i = 0; i < v.rows(); ++i) {
if (i > 0 && i % 3 == 0)
printf("\n");
-
+
printf("%f,\n", v[i]);
}
}
@@ -216,11 +216,11 @@ BLI_INLINE void print_lmatrix(const lMatrix &m)
for (int j = 0; j < m.rows(); ++j) {
if (j > 0 && j % 3 == 0)
printf("\n");
-
+
for (int i = 0; i < m.cols(); ++i) {
if (i > 0 && i % 3 == 0)
printf(" ");
-
+
implicit_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 6ab69a0050c..b59ac46abbc 100644
--- a/source/blender/physics/intern/hair_volume.cpp
+++ b/source/blender/physics/intern/hair_volume.cpp
@@ -82,7 +82,7 @@ typedef struct HairGridVert {
int samples;
float velocity[3];
float density;
-
+
float velocity_smooth[3];
} HairGridVert;
@@ -107,20 +107,20 @@ BLI_INLINE int hair_grid_offset(const float vec[3], const int res[3], const floa
BLI_INLINE int hair_grid_interp_weights(const int res[3], const float gmin[3], float scale, const float vec[3], float uvw[3])
{
int i, j, k, offset;
-
+
i = HAIR_GRID_INDEX_AXIS(vec, res, gmin, scale, 0);
j = HAIR_GRID_INDEX_AXIS(vec, res, gmin, scale, 1);
k = HAIR_GRID_INDEX_AXIS(vec, res, gmin, scale, 2);
offset = i + (j + k*res[1])*res[0];
-
+
uvw[0] = (vec[0] - gmin[0]) * scale - (float)i;
uvw[1] = (vec[1] - gmin[1]) * scale - (float)j;
uvw[2] = (vec[2] - gmin[2]) * scale - (float)k;
-
+
// BLI_assert(0.0f <= uvw[0] && uvw[0] <= 1.0001f);
// BLI_assert(0.0f <= uvw[1] && uvw[1] <= 1.0001f);
// BLI_assert(0.0f <= uvw[2] && uvw[2] <= 1.0001f);
-
+
return offset;
}
@@ -131,12 +131,12 @@ BLI_INLINE void hair_grid_interpolate(const HairGridVert *grid, const int res[3]
float uvw[3], muvw[3];
int res2 = res[1] * res[0];
int offset;
-
+
offset = hair_grid_interp_weights(res, gmin, scale, vec, uvw);
muvw[0] = 1.0f - uvw[0];
muvw[1] = 1.0f - uvw[1];
muvw[2] = 1.0f - uvw[2];
-
+
data[0] = grid[offset ];
data[1] = grid[offset +1];
data[2] = grid[offset +res[0] ];
@@ -145,14 +145,14 @@ BLI_INLINE void hair_grid_interpolate(const HairGridVert *grid, const int res[3]
data[5] = grid[offset+res2 +1];
data[6] = grid[offset+res2+res[0] ];
data[7] = grid[offset+res2+res[0]+1];
-
+
if (density) {
*density = muvw[2]*( muvw[1]*( muvw[0]*data[0].density + uvw[0]*data[1].density ) +
uvw[1]*( muvw[0]*data[2].density + uvw[0]*data[3].density ) ) +
uvw[2]*( muvw[1]*( muvw[0]*data[4].density + uvw[0]*data[5].density ) +
uvw[1]*( muvw[0]*data[6].density + uvw[0]*data[7].density ) );
}
-
+
if (velocity) {
int k;
for (k = 0; k < 3; ++k) {
@@ -162,7 +162,7 @@ BLI_INLINE void hair_grid_interpolate(const HairGridVert *grid, const int res[3]
uvw[1]*( muvw[0]*data[6].velocity[k] + uvw[0]*data[7].velocity[k] ) );
}
}
-
+
if (vel_smooth) {
int k;
for (k = 0; k < 3; ++k) {
@@ -172,24 +172,24 @@ BLI_INLINE void hair_grid_interpolate(const HairGridVert *grid, const int res[3]
uvw[1]*( muvw[0]*data[6].velocity_smooth[k] + uvw[0]*data[7].velocity_smooth[k] ) );
}
}
-
+
if (density_gradient) {
density_gradient[0] = muvw[1] * muvw[2] * ( data[0].density - data[1].density ) +
uvw[1] * muvw[2] * ( data[2].density - data[3].density ) +
muvw[1] * uvw[2] * ( data[4].density - data[5].density ) +
uvw[1] * uvw[2] * ( data[6].density - data[7].density );
-
+
density_gradient[1] = muvw[2] * muvw[0] * ( data[0].density - data[2].density ) +
uvw[2] * muvw[0] * ( data[4].density - data[6].density ) +
muvw[2] * uvw[0] * ( data[1].density - data[3].density ) +
uvw[2] * uvw[0] * ( data[5].density - data[7].density );
-
+
density_gradient[2] = muvw[2] * muvw[0] * ( data[0].density - data[4].density ) +
uvw[2] * muvw[0] * ( data[1].density - data[5].density ) +
muvw[2] * uvw[0] * ( data[2].density - data[6].density ) +
uvw[2] * uvw[0] * ( data[3].density - data[7].density );
}
-
+
if (velocity_gradient) {
/* XXX TODO */
zero_m3(velocity_gradient);
@@ -201,21 +201,21 @@ void BPH_hair_volume_vertex_grid_forces(HairGrid *grid, const float x[3], const
float f[3], float dfdx[3][3], float dfdv[3][3])
{
float gdensity, gvelocity[3], ggrad[3], gvelgrad[3][3], gradlen;
-
+
hair_grid_interpolate(grid->verts, grid->res, grid->gmin, grid->inv_cellsize, x, &gdensity, gvelocity, NULL, ggrad, gvelgrad);
-
+
zero_v3(f);
sub_v3_v3(gvelocity, v);
mul_v3_v3fl(f, gvelocity, smoothfac);
-
+
gradlen = normalize_v3(ggrad) - minpressure;
if (gradlen > 0.0f) {
mul_v3_fl(ggrad, gradlen);
madd_v3_v3fl(f, ggrad, pressurefac);
}
-
+
zero_m3(dfdx);
-
+
sub_m3_m3m3(dfdv, gvelgrad, I);
mul_m3_fl(dfdv, smoothfac);
}
@@ -232,16 +232,16 @@ void BPH_hair_volume_grid_velocity(HairGrid *grid, const float x[3], const float
{
float gdensity, gvelocity[3], gvel_smooth[3], ggrad[3], gvelgrad[3][3];
float v_pic[3], v_flip[3];
-
+
hair_grid_interpolate(grid->verts, grid->res, grid->gmin, grid->inv_cellsize, x, &gdensity, gvelocity, gvel_smooth, ggrad, gvelgrad);
-
+
/* velocity according to PIC method (Particle-in-Cell) */
copy_v3_v3(v_pic, gvel_smooth);
-
+
/* velocity according to FLIP method (Fluid-Implicit-Particle) */
sub_v3_v3v3(v_flip, gvel_smooth, gvelocity);
add_v3_v3(v_flip, v);
-
+
interp_v3_v3v3(r_v, v_pic, v_flip, fluid_factor);
}
@@ -283,16 +283,16 @@ BLI_INLINE int hair_grid_weights(const int res[3], const float gmin[3], float sc
{
int i, j, k, offset;
float uvw[3];
-
+
i = HAIR_GRID_INDEX_AXIS(vec, res, gmin, scale, 0);
j = HAIR_GRID_INDEX_AXIS(vec, res, gmin, scale, 1);
k = HAIR_GRID_INDEX_AXIS(vec, res, gmin, scale, 2);
offset = i + (j + k*res[1])*res[0];
-
+
uvw[0] = (vec[0] - gmin[0]) * scale;
uvw[1] = (vec[1] - gmin[1]) * scale;
uvw[2] = (vec[2] - gmin[2]) * scale;
-
+
weights[0] = dist_tent_v3f3(uvw, (float)i , (float)j , (float)k );
weights[1] = dist_tent_v3f3(uvw, (float)(i+1), (float)j , (float)k );
weights[2] = dist_tent_v3f3(uvw, (float)i , (float)(j+1), (float)k );
@@ -301,9 +301,9 @@ BLI_INLINE int hair_grid_weights(const int res[3], const float gmin[3], float sc
weights[5] = dist_tent_v3f3(uvw, (float)(i+1), (float)j , (float)(k+1));
weights[6] = dist_tent_v3f3(uvw, (float)i , (float)(j+1), (float)(k+1));
weights[7] = dist_tent_v3f3(uvw, (float)(i+1), (float)(j+1), (float)(k+1));
-
+
// BLI_assert(fabsf(weights_sum(weights) - 1.0f) < 0.0001f);
-
+
return offset;
}
@@ -320,18 +320,18 @@ void BPH_hair_volume_add_vertex(HairGrid *grid, const float x[3], const float v[
float weights[8];
int di, dj, dk;
int offset;
-
+
if (!hair_grid_point_valid(x, grid->gmin, grid->gmax))
return;
-
+
offset = hair_grid_weights(res, grid->gmin, grid->inv_cellsize, x, weights);
-
+
for (di = 0; di < 2; ++di) {
for (dj = 0; dj < 2; ++dj) {
for (dk = 0; dk < 2; ++dk) {
int voffset = offset + di + (dj + dk*res[1])*res[0];
int iw = di + dj*2 + dk*4;
-
+
grid->verts[voffset].density += weights[iw];
madd_v3_v3fl(grid->verts[voffset].velocity, v, weights[iw]);
}
@@ -344,15 +344,15 @@ BLI_INLINE void hair_volume_eval_grid_vertex(HairGridVert *vert, const float loc
const float x2[3], const float v2[3], const float x3[3], const float v3[3])
{
float closest[3], lambda, dist, weight;
-
+
lambda = closest_to_line_v3(closest, loc, x2, x3);
dist = len_v3v3(closest, loc);
-
+
weight = (radius - dist) * dist_scale;
-
+
if (weight > 0.0f) {
float vel[3];
-
+
interp_v3_v3v3(vel, v2, v3, lambda);
madd_v3_v3fl(vert->velocity, vel, weight);
vert->density += weight;
@@ -378,37 +378,37 @@ BLI_INLINE void hair_volume_add_segment_2D(HairGrid *grid,
{
const float radius = 1.5f;
const float dist_scale = grid->inv_cellsize;
-
+
int j, k;
-
+
/* boundary checks to be safe */
CLAMP_MIN(jmin, 0);
CLAMP_MAX(jmax, resj-1);
CLAMP_MIN(kmin, 0);
CLAMP_MAX(kmax, resk-1);
-
+
HairGridVert *vert_j = vert + jmin * stride_j;
float loc_j[3] = { loc[0], loc[1], loc[2] };
loc_j[axis_j] += (float)jmin;
for (j = jmin; j <= jmax; ++j, vert_j += stride_j, loc_j[axis_j] += 1.0f) {
-
+
HairGridVert *vert_k = vert_j + kmin * stride_k;
float loc_k[3] = { loc_j[0], loc_j[1], loc_j[2] };
loc_k[axis_k] += (float)kmin;
for (k = kmin; k <= kmax; ++k, vert_k += stride_k, loc_k[axis_k] += 1.0f) {
-
+
hair_volume_eval_grid_vertex(vert_k, loc_k, radius, dist_scale, x2, v2, x3, v3);
-
+
#if 0
{
float wloc[3], x2w[3], x3w[3];
grid_to_world(grid, wloc, loc_k);
grid_to_world(grid, x2w, x2);
grid_to_world(grid, x3w, x3);
-
+
if (vert_k->samples > 0)
BKE_sim_debug_data_add_circle(wloc, 0.01f, 1.0, 1.0, 0.3, "grid", 2525, debug_i, j, k);
-
+
if (grid->debug_value) {
BKE_sim_debug_data_add_dot(wloc, 1, 0, 0, "grid", 93, debug_i, j, k);
BKE_sim_debug_data_add_dot(x2w, 0.1, 0.1, 0.7, "grid", 649, debug_i, j, k);
@@ -435,55 +435,55 @@ void BPH_hair_volume_add_segment(HairGrid *grid,
const float dir1[3], const float dir2[3], const float dir3[3])
{
const int res[3] = { grid->res[0], grid->res[1], grid->res[2] };
-
+
/* find the primary direction from the major axis of the direction vector */
const int axis0 = major_axis_v3(dir2);
const int axis1 = (axis0 + 1) % 3;
const int axis2 = (axis0 + 2) % 3;
-
+
/* vertex buffer offset factors along cardinal axes */
const int strides[3] = { 1, res[0], res[0] * res[1] };
const int stride0 = strides[axis0];
const int stride1 = strides[axis1];
const int stride2 = strides[axis2];
-
+
/* increment of secondary directions per step in the primary direction
* note: we always go in the positive direction along axis0, so the sign can be inverted
*/
const float inc1 = dir2[axis1] / dir2[axis0];
const float inc2 = dir2[axis2] / dir2[axis0];
-
+
/* start/end points, so increment along axis0 is always positive */
const float *start = x2[axis0] < x3[axis0] ? x2 : x3;
const float *end = x2[axis0] < x3[axis0] ? x3 : x2;
const float start0 = start[axis0], start1 = start[axis1], start2 = start[axis2];
const float end0 = end[axis0];
-
+
/* range along primary direction */
const int imin = max_ii(floor_int(start[axis0]) - 1, 0);
const int imax = min_ii(floor_int(end[axis0]) + 2, res[axis0]-1);
-
+
float h = 0.0f;
HairGridVert *vert0;
float loc0[3];
int j0, k0, j0_prev, k0_prev;
int i;
-
+
for (i = imin; i <= imax; ++i) {
float shift1, shift2; /* fraction of a full cell shift [0.0, 1.0) */
int jmin, jmax, kmin, kmax;
-
+
h = CLAMPIS((float)i, start0, end0);
-
+
shift1 = start1 + (h - start0) * inc1;
shift2 = start2 + (h - start0) * inc2;
-
+
j0_prev = j0;
j0 = floor_int(shift1);
-
+
k0_prev = k0;
k0 = floor_int(shift2);
-
+
if (i > imin) {
jmin = min_ii(j0, j0_prev);
jmax = max_ii(j0, j0_prev);
@@ -494,12 +494,12 @@ void BPH_hair_volume_add_segment(HairGrid *grid,
jmin = jmax = j0;
kmin = kmax = k0;
}
-
+
vert0 = grid->verts + i * stride0;
loc0[axis0] = (float)i;
loc0[axis1] = 0.0f;
loc0[axis2] = 0.0f;
-
+
hair_volume_add_segment_2D(grid, x1, v1, x2, v2, x3, v3, x4, v4, dir1, dir2, dir3,
res[axis1], res[axis2], jmin-1, jmax+2, kmin-1, kmax+2,
vert0, stride1, stride2, loc0, axis1, axis2,
@@ -511,11 +511,11 @@ BLI_INLINE void hair_volume_eval_grid_vertex_sample(HairGridVert *vert, const fl
const float x[3], const float v[3])
{
float dist, weight;
-
+
dist = len_v3v3(x, loc);
-
+
weight = (radius - dist) * dist_scale;
-
+
if (weight > 0.0f) {
madd_v3_v3fl(vert->velocity, v, weight);
vert->density += weight;
@@ -533,34 +533,34 @@ void BPH_hair_volume_add_segment(HairGrid *grid,
{
const float radius = 1.5f;
const float dist_scale = grid->inv_cellsize;
-
+
const int res[3] = { grid->res[0], grid->res[1], grid->res[2] };
const int stride[3] = { 1, res[0], res[0] * res[1] };
const int num_samples = 10;
-
+
int s;
-
+
for (s = 0; s < num_samples; ++s) {
float x[3], v[3];
int i, j, k;
-
+
float f = (float)s / (float)(num_samples-1);
interp_v3_v3v3(x, x2, x3, f);
interp_v3_v3v3(v, v2, v3, f);
-
+
int imin = max_ii(floor_int(x[0]) - 2, 0);
int imax = min_ii(floor_int(x[0]) + 2, res[0]-1);
int jmin = max_ii(floor_int(x[1]) - 2, 0);
int jmax = min_ii(floor_int(x[1]) + 2, res[1]-1);
int kmin = max_ii(floor_int(x[2]) - 2, 0);
int kmax = min_ii(floor_int(x[2]) + 2, res[2]-1);
-
+
for (k = kmin; k <= kmax; ++k) {
for (j = jmin; j <= jmax; ++j) {
for (i = imin; i <= imax; ++i) {
float loc[3] = { (float)i, (float)j, (float)k };
HairGridVert *vert = grid->verts + i * stride[0] + j * stride[1] + k * stride[2];
-
+
hair_volume_eval_grid_vertex_sample(vert, loc, radius, dist_scale, x, v);
}
}
@@ -598,25 +598,25 @@ bool BPH_hair_volume_solve_divergence(HairGrid *grid, float /*dt*/, float target
{
const float flowfac = grid->cellsize;
const float inv_flowfac = 1.0f / grid->cellsize;
-
+
/*const int num_cells = hair_grid_size(grid->res);*/
const int res[3] = { grid->res[0], grid->res[1], grid->res[2] };
const int resA[3] = { grid->res[0] + 2, grid->res[1] + 2, grid->res[2] + 2 };
-
+
const int stride0 = 1;
const int stride1 = grid->res[0];
const int stride2 = grid->res[1] * grid->res[0];
const int strideA0 = 1;
const int strideA1 = grid->res[0] + 2;
const int strideA2 = (grid->res[1] + 2) * (grid->res[0] + 2);
-
+
const int num_cells = res[0] * res[1] * res[2];
const int num_cellsA = (res[0] + 2) * (res[1] + 2) * (res[2] + 2);
-
+
HairGridVert *vert_start = grid->verts - (stride0 + stride1 + stride2);
HairGridVert *vert;
int i, j, k;
-
+
#define MARGIN_i0 (i < 1)
#define MARGIN_j0 (j < 1)
#define MARGIN_k0 (k < 1)
@@ -630,9 +630,9 @@ bool BPH_hair_volume_solve_divergence(HairGrid *grid, float /*dt*/, float target
#define NEIGHBOR_MARGIN_i1 (i >= resA[0]-2)
#define NEIGHBOR_MARGIN_j1 (j >= resA[1]-2)
#define NEIGHBOR_MARGIN_k1 (k >= resA[2]-2)
-
+
BLI_assert(num_cells >= 1);
-
+
/* Calculate divergence */
lVector B(num_cellsA);
for (k = 0; k < resA[2]; ++k) {
@@ -640,14 +640,14 @@ bool BPH_hair_volume_solve_divergence(HairGrid *grid, float /*dt*/, float target
for (i = 0; i < resA[0]; ++i) {
int u = i * strideA0 + j * strideA1 + k * strideA2;
bool is_margin = MARGIN_i0 || MARGIN_i1 || MARGIN_j0 || MARGIN_j1 || MARGIN_k0 || MARGIN_k1;
-
+
if (is_margin) {
B[u] = 0.0f;
continue;
}
-
+
vert = vert_start + i * stride0 + j * stride1 + k * stride2;
-
+
const float *v0 = vert->velocity;
float dx = 0.0f, dy = 0.0f, dz = 0.0f;
if (!NEIGHBOR_MARGIN_i0)
@@ -662,19 +662,19 @@ bool BPH_hair_volume_solve_divergence(HairGrid *grid, float /*dt*/, float target
dz += v0[2] - (vert - stride2)->velocity[2];
if (!NEIGHBOR_MARGIN_k1)
dz += (vert + stride2)->velocity[2] - v0[2];
-
+
float divergence = -0.5f * flowfac * (dx + dy + dz);
-
+
/* adjustment term for target density */
float target = hair_volume_density_divergence(vert->density, target_density, target_strength);
-
+
/* B vector contains the finite difference approximation of the velocity divergence.
* Note: according to the discretized Navier-Stokes equation the rhs vector
* and resulting pressure gradient should be multiplied by the (inverse) density;
* however, this is already included in the weighting of hair velocities on the grid!
*/
B[u] = divergence - target;
-
+
#if 0
{
float wloc[3], loc[3];
@@ -683,12 +683,12 @@ bool BPH_hair_volume_solve_divergence(HairGrid *grid, float /*dt*/, float target
float coln[3] = {1.0, 0.0, 1.0};
float col[3];
float fac;
-
+
loc[0] = (float)(i - 1);
loc[1] = (float)(j - 1);
loc[2] = (float)(k - 1);
grid_to_world(grid, wloc, loc);
-
+
if (divergence > 0.0f) {
fac = CLAMPIS(divergence * target_strength, 0.0, 1.0);
interp_v3_v3v3(col, col0, colp, fac);
@@ -704,11 +704,11 @@ bool BPH_hair_volume_solve_divergence(HairGrid *grid, float /*dt*/, float target
}
}
}
-
+
/* Main Poisson equation system:
* This is derived from the discretezation of the Poisson equation
* div(grad(p)) = div(v)
- *
+ *
* The finite difference approximation yields the linear equation system described here:
* https://en.wikipedia.org/wiki/Discrete_Poisson_equation
*/
@@ -718,13 +718,13 @@ bool BPH_hair_volume_solve_divergence(HairGrid *grid, float /*dt*/, float target
* and up to 6 factors -1 on other places.
*/
A.reserve(Eigen::VectorXi::Constant(num_cellsA, 7));
-
+
for (k = 0; k < resA[2]; ++k) {
for (j = 0; j < resA[1]; ++j) {
for (i = 0; i < resA[0]; ++i) {
int u = i * strideA0 + j * strideA1 + k * strideA2;
bool is_margin = MARGIN_i0 || MARGIN_i1 || MARGIN_j0 || MARGIN_j1 || MARGIN_k0 || MARGIN_k1;
-
+
vert = vert_start + i * stride0 + j * stride1 + k * stride2;
if (!is_margin && vert->density > density_threshold) {
int neighbors_lo = 0;
@@ -733,7 +733,7 @@ bool BPH_hair_volume_solve_divergence(HairGrid *grid, float /*dt*/, float target
int neighbor_lo_index[3];
int neighbor_hi_index[3];
int n;
-
+
/* check for upper bounds in advance
* to get the correct number of neighbors,
* needed for the diagonal element
@@ -750,10 +750,10 @@ bool BPH_hair_volume_solve_divergence(HairGrid *grid, float /*dt*/, float target
neighbor_hi_index[neighbors_hi++] = u + strideA1;
if (!NEIGHBOR_MARGIN_k1 && (vert + stride2)->density > density_threshold)
neighbor_hi_index[neighbors_hi++] = u + strideA2;
-
+
/*int liquid_neighbors = neighbors_lo + neighbors_hi;*/
non_solid_neighbors = 6;
-
+
for (n = 0; n < neighbors_lo; ++n)
A.insert(neighbor_lo_index[n], u) = -1.0f;
A.insert(u, u) = (float)non_solid_neighbors;
@@ -766,15 +766,15 @@ bool BPH_hair_volume_solve_divergence(HairGrid *grid, float /*dt*/, float target
}
}
}
-
+
ConjugateGradient cg;
cg.setMaxIterations(100);
cg.setTolerance(0.01f);
-
+
cg.compute(A);
-
+
lVector p = cg.solve(B);
-
+
if (cg.info() == Eigen::Success) {
/* Calculate velocity = grad(p) */
for (k = 0; k < resA[2]; ++k) {
@@ -784,7 +784,7 @@ bool BPH_hair_volume_solve_divergence(HairGrid *grid, float /*dt*/, float target
bool is_margin = MARGIN_i0 || MARGIN_i1 || MARGIN_j0 || MARGIN_j1 || MARGIN_k0 || MARGIN_k1;
if (is_margin)
continue;
-
+
vert = vert_start + i * stride0 + j * stride1 + k * stride2;
if (vert->density > density_threshold) {
float p_left = p[u - strideA0];
@@ -793,14 +793,14 @@ bool BPH_hair_volume_solve_divergence(HairGrid *grid, float /*dt*/, float target
float p_up = p[u + strideA1];
float p_bottom = p[u - strideA2];
float p_top = p[u + strideA2];
-
+
/* finite difference estimate of pressure gradient */
float dvel[3];
dvel[0] = p_right - p_left;
dvel[1] = p_up - p_down;
dvel[2] = p_top - p_bottom;
mul_v3_fl(dvel, -0.5f * inv_flowfac);
-
+
/* pressure gradient describes velocity delta */
add_v3_v3v3(vert->velocity_smooth, vert->velocity, dvel);
}
@@ -810,14 +810,14 @@ bool BPH_hair_volume_solve_divergence(HairGrid *grid, float /*dt*/, float target
}
}
}
-
+
#if 0
{
int axis = 0;
float offset = 0.0f;
-
+
int slice = (offset - grid->gmin[axis]) / grid->cellsize;
-
+
for (k = 0; k < resA[2]; ++k) {
for (j = 0; j < resA[1]; ++j) {
for (i = 0; i < resA[0]; ++i) {
@@ -825,21 +825,21 @@ bool BPH_hair_volume_solve_divergence(HairGrid *grid, float /*dt*/, float target
bool is_margin = MARGIN_i0 || MARGIN_i1 || MARGIN_j0 || MARGIN_j1 || MARGIN_k0 || MARGIN_k1;
if (i != slice)
continue;
-
+
vert = vert_start + i * stride0 + j * stride1 + k * stride2;
-
+
float wloc[3], loc[3];
float col0[3] = {0.0, 0.0, 0.0};
float colp[3] = {0.0, 1.0, 1.0};
float coln[3] = {1.0, 0.0, 1.0};
float col[3];
float fac;
-
+
loc[0] = (float)(i - 1);
loc[1] = (float)(j - 1);
loc[2] = (float)(k - 1);
grid_to_world(grid, wloc, loc);
-
+
float pressure = p[u];
if (pressure > 0.0f) {
fac = CLAMPIS(pressure * grid->debug1, 0.0, 1.0);
@@ -851,19 +851,19 @@ bool BPH_hair_volume_solve_divergence(HairGrid *grid, float /*dt*/, float target
}
if (fac > 0.05f)
BKE_sim_debug_data_add_circle(grid->debug_data, wloc, 0.01f, col[0], col[1], col[2], "grid", 5533, i, j, k);
-
+
if (!is_margin) {
float dvel[3];
sub_v3_v3v3(dvel, vert->velocity_smooth, vert->velocity);
// BKE_sim_debug_data_add_vector(grid->debug_data, wloc, dvel, 1, 1, 1, "grid", 5566, i, j, k);
}
-
+
if (!is_margin) {
float d = CLAMPIS(vert->density * grid->debug2, 0.0f, 1.0f);
float col0[3] = {0.3, 0.3, 0.3};
float colp[3] = {0.0, 0.0, 1.0};
float col[3];
-
+
interp_v3_v3v3(col, col0, colp, d);
// if (d > 0.05f)
// BKE_sim_debug_data_add_dot(grid->debug_data, wloc, col[0], col[1], col[2], "grid", 5544, i, j, k);
@@ -873,7 +873,7 @@ bool BPH_hair_volume_solve_divergence(HairGrid *grid, float /*dt*/, float target
}
}
#endif
-
+
return true;
}
else {
@@ -881,7 +881,7 @@ bool BPH_hair_volume_solve_divergence(HairGrid *grid, float /*dt*/, float target
for (i = 0, vert = grid->verts; i < num_cells; ++i, ++vert) {
zero_v3(vert->velocity_smooth);
}
-
+
return false;
}
}
@@ -901,20 +901,20 @@ BLI_INLINE void hair_volume_filter_box_convolute(HairVertexGrid *grid, float inv
int offset, kernel_offset, kernel_dq, kernel_dr;
HairGridVert *verts;
float *vel_smooth;
-
+
offset = i + (j + k*res)*res;
verts = grid->verts;
vel_smooth = verts[offset].velocity_smooth;
-
+
kernel_offset = minp + (minq + minr*res)*res;
kernel_dq = res;
kernel_dr = res * res;
for (r = minr; r <= maxr; ++r) {
for (q = minq; q <= maxq; ++q) {
for (p = minp; p <= maxp; ++p) {
-
+
madd_v3_v3fl(vel_smooth, verts[kernel_offset].velocity, invD);
-
+
kernel_offset += 1;
}
kernel_offset += kernel_dq;
@@ -930,18 +930,18 @@ void BPH_hair_volume_vertex_grid_filter_box(HairVertexGrid *grid, int kernel_siz
int tot;
float invD;
int i, j, k;
-
+
if (kernel_size <= 0)
return;
-
+
tot = kernel_size * 2 + 1;
invD = 1.0f / (float)(tot*tot*tot);
-
+
/* clear values for convolution */
for (i = 0; i < size; ++i) {
zero_v3(grid->verts[i].velocity_smooth);
}
-
+
for (i = 0; i < grid->res; ++i) {
for (j = 0; j < grid->res; ++j) {
for (k = 0; k < grid->res; ++k) {
@@ -949,7 +949,7 @@ void BPH_hair_volume_vertex_grid_filter_box(HairVertexGrid *grid, int kernel_siz
}
}
}
-
+
/* apply as new velocity */
for (i = 0; i < size; ++i) {
copy_v3_v3(grid->verts[i].velocity, grid->verts[i].velocity_smooth);
@@ -966,21 +966,21 @@ HairGrid *BPH_hair_volume_create_vertex_grid(float cellsize, const float gmin[3]
int size;
HairGrid *grid;
int i;
-
+
/* sanity check */
if (cellsize <= 0.0f)
cellsize = 1.0f;
scale = 1.0f / cellsize;
-
+
sub_v3_v3v3(extent, gmax, gmin);
for (i = 0; i < 3; ++i) {
resmin[i] = floor_int(gmin[i] * scale);
resmax[i] = floor_int(gmax[i] * scale) + 1;
-
+
/* add margin of 1 cell */
resmin[i] -= 1;
resmax[i] += 1;
-
+
res[i] = resmax[i] - resmin[i] + 1;
/* sanity check: avoid null-sized grid */
if (res[i] < 4) {
@@ -992,12 +992,12 @@ HairGrid *BPH_hair_volume_create_vertex_grid(float cellsize, const float gmin[3]
res[i] = MAX_HAIR_GRID_RES;
resmax[i] = resmin[i] + MAX_HAIR_GRID_RES;
}
-
+
gmin_margin[i] = (float)resmin[i] * cellsize;
gmax_margin[i] = (float)resmax[i] * cellsize;
}
size = hair_grid_size(res);
-
+
grid = (HairGrid *)MEM_callocN(sizeof(HairGrid), "hair grid");
grid->res[0] = res[0];
grid->res[1] = res[1];
@@ -1062,23 +1062,23 @@ static HairGridVert *hair_volume_create_collision_grid(ClothModifierData *clmd,
float vel[3];
float weights[8];
int di, dj, dk;
-
+
for (v=0; v < col->collmd->numverts; v++, loc0++, loc1++) {
int offset;
-
+
if (!hair_grid_point_valid(loc1->co, gmin, gmax))
continue;
-
+
offset = hair_grid_weights(res, gmin, scale, lX[v], weights);
-
+
sub_v3_v3v3(vel, loc1->co, loc0->co);
-
+
for (di = 0; di < 2; ++di) {
for (dj = 0; dj < 2; ++dj) {
for (dk = 0; dk < 2; ++dk) {
int voffset = offset + di + (dj + dk*res)*res;
int iw = di + dj*2 + dk*4;
-
+
collgrid[voffset].density += weights[iw];
madd_v3_v3fl(collgrid[voffset].velocity, vel, weights[iw]);
}
@@ -1095,7 +1095,7 @@ static HairGridVert *hair_volume_create_collision_grid(ClothModifierData *clmd,
if (density > 0.0f)
mul_v3_fl(collgrid[i].velocity, 1.0f/density);
}
-
+
return collgrid;
}
#endif
diff --git a/source/blender/physics/intern/implicit.h b/source/blender/physics/intern/implicit.h
index d6bf5c6b7bf..2eadd3171b0 100644
--- a/source/blender/physics/intern/implicit.h
+++ b/source/blender/physics/intern/implicit.h
@@ -62,7 +62,7 @@ struct Implicit_Data;
typedef struct ImplicitSolverResult {
int status;
-
+
int iterations;
float error;
} ImplicitSolverResult;
diff --git a/source/blender/physics/intern/implicit_blender.c b/source/blender/physics/intern/implicit_blender.c
index 49798081cff..5fd9c6b50de 100644
--- a/source/blender/physics/intern/implicit_blender.c
+++ b/source/blender/physics/intern/implicit_blender.c
@@ -71,9 +71,9 @@ static float ZERO[3][3] = {{0, 0, 0}, {0, 0, 0}, {0, 0, 0}};
/*
#define C99
#ifdef C99
-#defineDO_INLINE inline
-#else
-#defineDO_INLINE static
+#defineDO_INLINE inline
+#else
+#defineDO_INLINE static
#endif
*/
struct Cloth;
@@ -90,7 +90,7 @@ typedef struct fmatrix3x3 {
/* int pinned; // is this vertex allowed to move? */
float n1, n2, n3; /* three normal vectors for collision constrains */
unsigned int vcount; /* vertex count */
- unsigned int scount; /* spring count */
+ unsigned int scount; /* spring count */
} fmatrix3x3;
///////////////////////////
@@ -115,9 +115,9 @@ DO_INLINE void mul_fvectorT_fvector(float to[3][3], float vectorA[3], float vect
/* simple v^T * v product with scalar ("outer product") */
/* STATUS: HAS TO BE verified (*should* work) */
DO_INLINE void mul_fvectorT_fvectorS(float to[3][3], float vectorA[3], float vectorB[3], float aS)
-{
+{
mul_fvectorT_fvector(to, vectorA, vectorB);
-
+
mul_fvector_S(to[0], to[0], aS);
mul_fvector_S(to[1], to[1], aS);
mul_fvector_S(to[2], to[2], aS);
@@ -288,7 +288,7 @@ static void print_lvector(lfVector *v, int numverts)
for (i = 0; i < numverts; ++i) {
if (i > 0)
printf("\n");
-
+
printf("%f,\n", v[i][0]);
printf("%f,\n", v[i][1]);
printf("%f,\n", v[i][2]);
@@ -303,11 +303,11 @@ static void print_bfmatrix(fmatrix3x3 *m)
int size = m[0].vcount * 3;
float *t = MEM_callocN(sizeof(float) * size*size, "bfmatrix");
int q, i, j;
-
+
for (q = 0; q < tot; ++q) {
int k = 3 * m[q].r;
int l = 3 * m[q].c;
-
+
for (j = 0; j < 3; ++j) {
for (i = 0; i < 3; ++i) {
// if (t[k + i + (l + j) * size] != 0.0f) {
@@ -323,20 +323,20 @@ static void print_bfmatrix(fmatrix3x3 *m)
}
}
}
-
+
for (j = 0; j < size; ++j) {
if (j > 0 && j % 3 == 0)
printf("\n");
-
+
for (i = 0; i < size; ++i) {
if (i > 0 && i % 3 == 0)
printf(" ");
-
+
implicit_print_matrix_elem(t[i + j * size]);
}
printf("\n");
}
-
+
MEM_freeN(t);
}
#endif
@@ -354,7 +354,7 @@ DO_INLINE void cp_fmatrix(float to[3][3], float from[3][3])
DO_INLINE void initdiag_fmatrixS(float to[3][3], float aS)
{
cp_fmatrix(to, ZERO);
-
+
to[0][0] = aS;
to[1][1] = aS;
to[2][2] = aS;
@@ -532,15 +532,15 @@ DO_INLINE fmatrix3x3 *create_bfmatrix(unsigned int verts, unsigned int springs)
// TODO: check if memory allocation was successful */
fmatrix3x3 *temp = (fmatrix3x3 *)MEM_callocN(sizeof(fmatrix3x3) * (verts + springs), "cloth_implicit_alloc_matrix");
int i;
-
+
temp[0].vcount = verts;
temp[0].scount = springs;
-
+
/* vertex part of the matrix is diagonal blocks */
for (i = 0; i < verts; ++i) {
init_fmatrix(temp + i, i, i);
}
-
+
return temp;
}
/* delete big matrix */
@@ -565,7 +565,7 @@ DO_INLINE void init_bfmatrix(fmatrix3x3 *matrix, float m3[3][3])
unsigned int i;
for (i = 0; i < matrix[0].vcount+matrix[0].scount; i++) {
- cp_fmatrix(matrix[i].m, m3);
+ cp_fmatrix(matrix[i].m, m3);
}
}
@@ -577,10 +577,10 @@ DO_INLINE void initdiag_bfmatrix(fmatrix3x3 *matrix, float m3[3][3])
float tmatrix[3][3] = {{0, 0, 0}, {0, 0, 0}, {0, 0, 0}};
for (i = 0; i < matrix[0].vcount; i++) {
- cp_fmatrix(matrix[i].m, m3);
+ cp_fmatrix(matrix[i].m, m3);
}
for (j = matrix[0].vcount; j < matrix[0].vcount+matrix[0].scount; j++) {
- cp_fmatrix(matrix[j].m, tmatrix);
+ cp_fmatrix(matrix[j].m, tmatrix);
}
}
@@ -591,7 +591,7 @@ DO_INLINE void mul_bfmatrix_lfvector( float (*to)[3], fmatrix3x3 *from, lfVector
unsigned int i = 0;
unsigned int vcount = from[0].vcount;
lfVector *temp = create_lfvector(vcount);
-
+
zero_lfvector(to, vcount);
#pragma omp parallel sections private(i) if (vcount > CLOTH_OPENMP_LIMIT)
@@ -610,10 +610,10 @@ DO_INLINE void mul_bfmatrix_lfvector( float (*to)[3], fmatrix3x3 *from, lfVector
}
}
add_lfvector_lfvector(to, to, temp, from[0].vcount);
-
+
del_lfvector(temp);
-
-
+
+
}
/* SPARSE SYMMETRIC sub big matrix with big matrix*/
@@ -642,15 +642,15 @@ typedef struct Implicit_Data {
lfVector *F; /* forces */
fmatrix3x3 *dFdV, *dFdX; /* force jacobians */
int num_blocks; /* number of off-diagonal blocks (springs) */
-
+
/* motion state data */
lfVector *X, *Xnew; /* positions */
lfVector *V, *Vnew; /* velocities */
-
+
/* internal solver data */
lfVector *B; /* B for A*dV = B */
fmatrix3x3 *A; /* A for A*dV = B */
-
+
lfVector *dV; /* velocity change (solution of A*dV = B) */
lfVector *z; /* target velocity in constrained directions */
fmatrix3x3 *S; /* filtering matrix for constraints */
@@ -660,7 +660,7 @@ typedef struct Implicit_Data {
Implicit_Data *BPH_mass_spring_solver_create(int numverts, int numsprings)
{
Implicit_Data *id = (Implicit_Data *)MEM_callocN(sizeof(Implicit_Data), "implicit vecmat");
-
+
/* process diagonal elements */
id->tfm = create_bfmatrix(numverts, 0);
id->A = create_bfmatrix(numverts, numsprings);
@@ -696,7 +696,7 @@ void BPH_mass_spring_solver_free(Implicit_Data *id)
del_bfmatrix(id->Pinv);
del_bfmatrix(id->bigI);
del_bfmatrix(id->M);
-
+
del_lfvector(id->X);
del_lfvector(id->Xnew);
del_lfvector(id->V);
@@ -705,7 +705,7 @@ void BPH_mass_spring_solver_free(Implicit_Data *id)
del_lfvector(id->B);
del_lfvector(id->dV);
del_lfvector(id->z);
-
+
MEM_freeN(id);
}
@@ -752,7 +752,7 @@ static int cg_filtered(lfVector *ldV, fmatrix3x3 *lA, lfVector *lB, lfVector *z
// Solves for unknown X in equation AX=B
unsigned int conjgrad_loopcount=0, conjgrad_looplimit=100;
float conjgrad_epsilon=0.0001f /* , conjgrad_lasterror=0 */ /* UNUSED */;
- lfVector *q, *d, *tmp, *r;
+ lfVector *q, *d, *tmp, *r;
float s, starget, a, s_prev;
unsigned int numverts = lA[0].vcount;
q = create_lfvector(numverts);
@@ -818,7 +818,7 @@ static int cg_filtered(lfVector *ldV, fmatrix3x3 *lA, lfVector *lB, lfVector *z,
// Solves for unknown X in equation AX=B
unsigned int conjgrad_loopcount=0, conjgrad_looplimit=100;
float conjgrad_epsilon=0.01f;
-
+
unsigned int numverts = lA[0].vcount;
lfVector *fB = create_lfvector(numverts);
lfVector *AdV = create_lfvector(numverts);
@@ -827,27 +827,27 @@ static int cg_filtered(lfVector *ldV, fmatrix3x3 *lA, lfVector *lB, lfVector *z,
lfVector *q = create_lfvector(numverts);
lfVector *s = create_lfvector(numverts);
float bnorm2, delta_new, delta_old, delta_target, alpha;
-
+
cp_lfvector(ldV, z, numverts);
-
+
/* d0 = filter(B)^T * P * filter(B) */
cp_lfvector(fB, lB, numverts);
filter(fB, S);
bnorm2 = dot_lfvector(fB, fB, numverts);
delta_target = conjgrad_epsilon*conjgrad_epsilon * bnorm2;
-
+
/* r = filter(B - A * dV) */
mul_bfmatrix_lfvector(AdV, lA, ldV);
sub_lfvector_lfvector(r, lB, AdV, numverts);
filter(r, S);
-
+
/* c = filter(P^-1 * r) */
cp_lfvector(c, r, numverts);
filter(c, S);
-
+
/* delta = r^T * c */
delta_new = dot_lfvector(r, c, numverts);
-
+
#ifdef IMPLICIT_PRINT_SOLVER_INPUT_OUTPUT
printf("==== A ====\n");
print_bfmatrix(lA);
@@ -858,25 +858,25 @@ static int cg_filtered(lfVector *ldV, fmatrix3x3 *lA, lfVector *lB, lfVector *z,
printf("==== S ====\n");
print_bfmatrix(S);
#endif
-
+
while (delta_new > delta_target && conjgrad_loopcount < conjgrad_looplimit) {
mul_bfmatrix_lfvector(q, lA, c);
filter(q, S);
-
+
alpha = delta_new / dot_lfvector(c, q, numverts);
-
+
add_lfvector_lfvectorS(ldV, ldV, c, alpha, numverts);
-
+
add_lfvector_lfvectorS(r, r, q, -alpha, numverts);
-
+
/* s = P^-1 * r */
cp_lfvector(s, r, numverts);
delta_old = delta_new;
delta_new = dot_lfvector(r, s, numverts);
-
+
add_lfvector_lfvectorS(c, s, c, delta_new / delta_old, numverts);
filter(c, S);
-
+
conjgrad_loopcount++;
}
@@ -885,7 +885,7 @@ static int cg_filtered(lfVector *ldV, fmatrix3x3 *lA, lfVector *lB, lfVector *z,
print_lvector(ldV, numverts);
printf("========\n");
#endif
-
+
del_lfvector(fB);
del_lfvector(AdV);
del_lfvector(r);
@@ -906,14 +906,14 @@ static int cg_filtered(lfVector *ldV, fmatrix3x3 *lA, lfVector *lB, lfVector *z,
DO_INLINE void BuildPPinv(fmatrix3x3 *lA, fmatrix3x3 *P, fmatrix3x3 *Pinv)
{
unsigned int i = 0;
-
+
// Take only the diagonal blocks of A
// #pragma omp parallel for private(i) if (lA[0].vcount > CLOTH_OPENMP_LIMIT)
for (i = 0; i<lA[0].vcount; i++) {
// block diagonalizer
cp_fmatrix(P[i].m, lA[i].m);
inverse_fmatrix(Pinv[i].m, P[i].m);
-
+
}
}
/*
@@ -927,65 +927,65 @@ static int cg_filtered_pre(lfVector *dv, fmatrix3x3 *lA, lfVector *lB, lfVector
lfVector *p = create_lfvector(numverts);
lfVector *s = create_lfvector(numverts);
lfVector *h = create_lfvector(numverts);
-
+
BuildPPinv(lA, P, Pinv);
-
+
filter(dv, S);
add_lfvector_lfvector(dv, dv, z, numverts);
-
+
mul_bfmatrix_lfvector(r, lA, dv);
sub_lfvector_lfvector(r, lB, r, numverts);
filter(r, S);
-
+
mul_prevfmatrix_lfvector(p, Pinv, r);
filter(p, S);
-
+
deltaNew = dot_lfvector(r, p, numverts);
-
+
delta0 = deltaNew * sqrt(conjgrad_epsilon);
-
+
#ifdef DEBUG_TIME
double start = PIL_check_seconds_timer();
#endif
-
+
while ((deltaNew > delta0) && (iterations < conjgrad_looplimit))
{
iterations++;
-
+
mul_bfmatrix_lfvector(s, lA, p);
filter(s, S);
-
+
alpha = deltaNew / dot_lfvector(p, s, numverts);
-
+
add_lfvector_lfvectorS(dv, dv, p, alpha, numverts);
-
+
add_lfvector_lfvectorS(r, r, s, -alpha, numverts);
-
+
mul_prevfmatrix_lfvector(h, Pinv, r);
filter(h, S);
-
+
deltaOld = deltaNew;
-
+
deltaNew = dot_lfvector(r, h, numverts);
-
+
add_lfvector_lfvectorS(p, h, p, deltaNew / deltaOld, numverts);
-
+
filter(p, S);
-
+
}
#ifdef DEBUG_TIME
double end = PIL_check_seconds_timer();
printf("cg_filtered_pre time: %f\n", (float)(end - start));
#endif
-
+
del_lfvector(h);
del_lfvector(s);
del_lfvector(p);
del_lfvector(r);
-
+
printf("iterations: %d\n", iterations);
-
+
return iterations<conjgrad_looplimit;
}
*/
@@ -1000,83 +1000,83 @@ static int cg_filtered_pre(lfVector *dv, fmatrix3x3 *lA, lfVector *lB, lfVector
lfVector *h = create_lfvector(numverts);
lfVector *bhat = create_lfvector(numverts);
lfVector *btemp = create_lfvector(numverts);
-
+
BuildPPinv(lA, P, Pinv);
-
+
initdiag_bfmatrix(bigI, I);
sub_bfmatrix_Smatrix(bigI, bigI, S);
-
+
// x = Sx_0+(I-S)z
filter(dv, S);
add_lfvector_lfvector(dv, dv, z, numverts);
-
+
// b_hat = S(b-A(I-S)z)
mul_bfmatrix_lfvector(r, lA, z);
mul_bfmatrix_lfvector(bhat, bigI, r);
sub_lfvector_lfvector(bhat, lB, bhat, numverts);
-
+
// r = S(b-Ax)
mul_bfmatrix_lfvector(r, lA, dv);
sub_lfvector_lfvector(r, lB, r, numverts);
filter(r, S);
-
+
// p = SP^-1r
mul_prevfmatrix_lfvector(p, Pinv, r);
filter(p, S);
-
+
// delta0 = bhat^TP^-1bhat
mul_prevfmatrix_lfvector(btemp, Pinv, bhat);
delta0 = dot_lfvector(bhat, btemp, numverts);
-
+
// deltaNew = r^TP
deltaNew = dot_lfvector(r, p, numverts);
-
+
/*
filter(dv, S);
add_lfvector_lfvector(dv, dv, z, numverts);
-
+
mul_bfmatrix_lfvector(r, lA, dv);
sub_lfvector_lfvector(r, lB, r, numverts);
filter(r, S);
-
+
mul_prevfmatrix_lfvector(p, Pinv, r);
filter(p, S);
-
+
deltaNew = dot_lfvector(r, p, numverts);
-
+
delta0 = deltaNew * sqrt(conjgrad_epsilon);
*/
#ifdef DEBUG_TIME
double start = PIL_check_seconds_timer();
#endif
-
+
tol = (0.01*0.2);
-
+
while ((deltaNew > delta0*tol*tol) && (iterations < conjgrad_looplimit))
{
iterations++;
-
+
mul_bfmatrix_lfvector(s, lA, p);
filter(s, S);
-
+
alpha = deltaNew / dot_lfvector(p, s, numverts);
-
+
add_lfvector_lfvectorS(dv, dv, p, alpha, numverts);
-
+
add_lfvector_lfvectorS(r, r, s, -alpha, numverts);
-
+
mul_prevfmatrix_lfvector(h, Pinv, r);
filter(h, S);
-
+
deltaOld = deltaNew;
-
+
deltaNew = dot_lfvector(r, h, numverts);
-
+
add_lfvector_lfvectorS(p, h, p, deltaNew / deltaOld, numverts);
-
+
filter(p, S);
-
+
}
#ifdef DEBUG_TIME
@@ -1090,9 +1090,9 @@ static int cg_filtered_pre(lfVector *dv, fmatrix3x3 *lA, lfVector *lB, lfVector
del_lfvector(s);
del_lfvector(p);
del_lfvector(r);
-
+
// printf("iterations: %d\n", iterations);
-
+
return iterations<conjgrad_looplimit;
}
#endif
@@ -1128,17 +1128,17 @@ bool BPH_mass_spring_solve_velocities(Implicit_Data *data, float dt, ImplicitSol
add_lfvector_lfvector(data->Vnew, data->V, data->dV, numverts);
del_lfvector(dFdXmV);
-
+
return result->status == BPH_SOLVER_SUCCESS;
}
bool BPH_mass_spring_solve_positions(Implicit_Data *data, float dt)
{
int numverts = data->M[0].vcount;
-
+
// advance positions
add_lfvector_lfvectorS(data->Xnew, data->X, data->Vnew, dt, numverts);
-
+
return true;
}
@@ -1219,7 +1219,7 @@ static int BPH_mass_spring_add_block(Implicit_Data *data, int v1, int v2)
int s = data->M[0].vcount + data->num_blocks; /* index from array start */
BLI_assert(s < data->M[0].vcount + data->M[0].scount);
++data->num_blocks;
-
+
/* tfm and S don't have spring entries (diagonal blocks only) */
init_fmatrix(data->bigI + s, v1, v2);
init_fmatrix(data->M + s, v1, v2);
@@ -1228,7 +1228,7 @@ static int BPH_mass_spring_add_block(Implicit_Data *data, int v1, int v2)
init_fmatrix(data->A + s, v1, v2);
init_fmatrix(data->P + s, v1, v2);
init_fmatrix(data->Pinv + s, v1, v2);
-
+
return s;
}
@@ -1244,26 +1244,26 @@ void BPH_mass_spring_clear_constraints(Implicit_Data *data)
void BPH_mass_spring_add_constraint_ndof0(Implicit_Data *data, int index, const float dV[3])
{
zero_m3(data->S[index].m);
-
+
world_to_root_v3(data, index, data->z[index], dV);
}
void BPH_mass_spring_add_constraint_ndof1(Implicit_Data *data, int index, const float c1[3], const float c2[3], const float dV[3])
{
float m[3][3], p[3], q[3], u[3], cmat[3][3];
-
+
world_to_root_v3(data, index, p, c1);
mul_fvectorT_fvector(cmat, p, p);
sub_m3_m3m3(m, I, cmat);
-
+
world_to_root_v3(data, index, q, c2);
mul_fvectorT_fvector(cmat, q, q);
sub_m3_m3m3(m, m, cmat);
-
+
/* XXX not sure but multiplication should work here */
copy_m3_m3(data->S[index].m, m);
// mul_m3_m3m3(data->S[index].m, data->S[index].m, m);
-
+
world_to_root_v3(data, index, u, dV);
add_v3_v3(data->z[index], u);
}
@@ -1271,14 +1271,14 @@ void BPH_mass_spring_add_constraint_ndof1(Implicit_Data *data, int index, const
void BPH_mass_spring_add_constraint_ndof2(Implicit_Data *data, int index, const float c1[3], const float dV[3])
{
float m[3][3], p[3], u[3], cmat[3][3];
-
+
world_to_root_v3(data, index, p, c1);
mul_fvectorT_fvector(cmat, p, p);
sub_m3_m3m3(m, I, cmat);
-
+
copy_m3_m3(data->S[index].m, m);
// mul_m3_m3m3(data->S[index].m, data->S[index].m, m);
-
+
world_to_root_v3(data, index, u, dV);
add_v3_v3(data->z[index], u);
}
@@ -1289,7 +1289,7 @@ void BPH_mass_spring_clear_forces(Implicit_Data *data)
zero_lfvector(data->F, numverts);
init_bfmatrix(data->dFdX, ZERO);
init_bfmatrix(data->dFdV, ZERO);
-
+
data->num_blocks = 0;
}
@@ -1300,37 +1300,37 @@ void BPH_mass_spring_force_reference_frame(Implicit_Data *data, int index, const
float f[3], dfdx[3][3], dfdv[3][3];
float euler[3], coriolis[3], centrifugal[3], rotvel[3];
float deuler[3][3], dcoriolis[3][3], dcentrifugal[3][3], drotvel[3][3];
-
+
world_to_root_v3(data, index, acc, acceleration);
world_to_root_v3(data, index, w, omega);
world_to_root_v3(data, index, dwdt, domega_dt);
-
+
cross_v3_v3v3(euler, dwdt, data->X[index]);
cross_v3_v3v3(coriolis, w, data->V[index]);
mul_v3_fl(coriolis, 2.0f);
cross_v3_v3v3(rotvel, w, data->X[index]);
cross_v3_v3v3(centrifugal, w, rotvel);
-
+
sub_v3_v3v3(f, acc, euler);
sub_v3_v3(f, coriolis);
sub_v3_v3(f, centrifugal);
-
+
mul_v3_fl(f, mass); /* F = m * a */
-
+
cross_v3_identity(deuler, dwdt);
cross_v3_identity(dcoriolis, w);
mul_m3_fl(dcoriolis, 2.0f);
cross_v3_identity(drotvel, w);
cross_m3_v3m3(dcentrifugal, w, drotvel);
-
+
add_m3_m3m3(dfdx, deuler, dcentrifugal);
negate_m3(dfdx);
mul_m3_fl(dfdx, mass);
-
+
copy_m3_m3(dfdv, dcoriolis);
negate_m3(dfdv);
mul_m3_fl(dfdv, mass);
-
+
add_v3_v3(data->F[index], f);
add_m3_m3m3(data->dFdX[index].m, data->dFdX[index].m, dfdx);
add_m3_m3m3(data->dFdV[index].m, data->dFdV[index].m, dfdv);
@@ -1349,7 +1349,7 @@ void BPH_mass_spring_force_gravity(Implicit_Data *data, int index, float mass, c
float f[3];
world_to_root_v3(data, index, f, g);
mul_v3_fl(f, mass);
-
+
add_v3_v3(data->F[index], f);
}
@@ -1358,10 +1358,10 @@ void BPH_mass_spring_force_drag(Implicit_Data *data, float drag)
int i, numverts = data->M[0].vcount;
for (i = 0; i < numverts; i++) {
float tmp[3][3];
-
+
/* NB: uses root space velocity, no need to transform */
madd_v3_v3fl(data->F[i], data->V[i], -drag);
-
+
copy_m3_m3(tmp, I);
mul_m3_fl(tmp, -drag);
add_m3_m3m3(data->dFdV[i].m, data->dFdV[i].m, tmp);
@@ -1374,7 +1374,7 @@ void BPH_mass_spring_force_extern(struct Implicit_Data *data, int i, const float
world_to_root_v3(data, i, tf, f);
world_to_root_m3(data, i, tdfdx, dfdx);
world_to_root_m3(data, i, tdfdv, dfdv);
-
+
add_v3_v3(data->F[i], tf);
add_m3_m3m3(data->dFdX[i].m, data->dFdX[i].m, tdfdx);
add_m3_m3m3(data->dFdV[i].m, data->dFdV[i].m, tdfdv);
@@ -1383,10 +1383,10 @@ void BPH_mass_spring_force_extern(struct Implicit_Data *data, int i, const float
static float calc_nor_area_tri(float nor[3], const float v1[3], const float v2[3], const float v3[3])
{
float n1[3], n2[3];
-
+
sub_v3_v3v3(n1, v1, v2);
sub_v3_v3v3(n2, v2, v3);
-
+
cross_v3_v3v3(nor, n1, n2);
return normalize_v3(nor);
}
@@ -1397,17 +1397,17 @@ void BPH_mass_spring_force_face_wind(Implicit_Data *data, int v1, int v2, int v3
const float effector_scale = 0.02f;
float win[3], nor[3], area;
float factor;
-
+
/* calculate face normal and area */
area = calc_nor_area_tri(nor, data->X[v1], data->X[v2], data->X[v3]);
factor = effector_scale * area / 3.0f;
-
+
world_to_root_v3(data, v1, win, winvec[v1]);
madd_v3_v3fl(data->F[v1], nor, factor * dot_v3v3(win, nor));
-
+
world_to_root_v3(data, v2, win, winvec[v2]);
madd_v3_v3fl(data->F[v2], nor, factor * dot_v3v3(win, nor));
-
+
world_to_root_v3(data, v3, win, winvec[v3]);
madd_v3_v3fl(data->F[v3], nor, factor * dot_v3v3(win, nor));
}
@@ -1417,17 +1417,17 @@ static void edge_wind_vertex(const float dir[3], float length, float radius, con
const float density = 0.01f; /* XXX arbitrary value, corresponds to effect of air density */
float cos_alpha, sin_alpha, cross_section;
float windlen = len_v3(wind);
-
+
if (windlen == 0.0f) {
zero_v3(f);
return;
}
-
+
/* angle of wind direction to edge */
cos_alpha = dot_v3v3(wind, dir) / windlen;
sin_alpha = sqrtf(1.0f - cos_alpha * cos_alpha);
cross_section = radius * ((float)M_PI * radius * sin_alpha + length * cos_alpha);
-
+
mul_v3_v3fl(f, wind, density * cross_section);
}
@@ -1435,14 +1435,14 @@ void BPH_mass_spring_force_edge_wind(Implicit_Data *data, int v1, int v2, float
{
float win[3], dir[3], length;
float f[3], dfdx[3][3], dfdv[3][3];
-
+
sub_v3_v3v3(dir, data->X[v1], data->X[v2]);
length = normalize_v3(dir);
-
+
world_to_root_v3(data, v1, win, winvec[v1]);
edge_wind_vertex(dir, length, radius1, win, f, dfdx, dfdv);
add_v3_v3(data->F[v1], f);
-
+
world_to_root_v3(data, v2, win, winvec[v2]);
edge_wind_vertex(dir, length, radius2, win, f, dfdx, dfdv);
add_v3_v3(data->F[v2], f);
@@ -1451,10 +1451,10 @@ void BPH_mass_spring_force_edge_wind(Implicit_Data *data, int v1, int v2, float
void BPH_mass_spring_force_vertex_wind(Implicit_Data *data, int v, float UNUSED(radius), 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);
add_v3_v3(data->F[v], f);
@@ -1466,8 +1466,8 @@ BLI_INLINE void dfdx_spring(float to[3][3], const float dir[3], float length, fl
//return ( (I-outerprod(dir, dir))*Min(1.0f, rest/length) - I) * -k;
outerproduct(to, dir, dir);
sub_m3_m3m3(to, I, to);
-
- mul_m3_fl(to, (L/length));
+
+ mul_m3_fl(to, (L/length));
sub_m3_m3m3(to, to, I);
mul_m3_fl(to, k);
}
@@ -1476,7 +1476,7 @@ BLI_INLINE void dfdx_spring(float to[3][3], const float dir[3], float length, fl
#if 0
BLI_INLINE void dfdx_damp(float to[3][3], const float dir[3], float length, const float vel[3], float rest, float damping)
{
- // inner spring damping vel is the relative velocity of the endpoints.
+ // inner spring damping vel is the relative velocity of the endpoints.
// return (I-outerprod(dir, dir)) * (-damping * -(dot(dir, vel)/Max(length, rest)));
mul_fvectorT_fvector(to, dir, dir);
sub_fmatrix_fmatrix(to, I, to);
@@ -1512,7 +1512,7 @@ BLI_INLINE float fbstar(float length, float L, float kb, float cb)
{
float tempfb_fl = kb * fb(length, L);
float fbstar_fl = cb * (length - L);
-
+
if (tempfb_fl < fbstar_fl)
return fbstar_fl;
else
@@ -1539,7 +1539,7 @@ BLI_INLINE bool spring_length(Implicit_Data *data, int i, int j, float r_extent[
sub_v3_v3v3(r_extent, data->X[j], data->X[i]);
sub_v3_v3v3(r_vel, data->V[j], data->V[i]);
*r_length = len_v3(r_extent);
-
+
if (*r_length > ALMOST_ZERO) {
/*
if (length>L) {
@@ -1557,21 +1557,21 @@ BLI_INLINE bool spring_length(Implicit_Data *data, int i, int j, float r_extent[
else {
zero_v3(r_dir);
}
-
+
return true;
}
BLI_INLINE void apply_spring(Implicit_Data *data, int i, int j, const float f[3], float dfdx[3][3], float dfdv[3][3])
{
int block_ij = BPH_mass_spring_add_block(data, i, j);
-
+
add_v3_v3(data->F[i], f);
sub_v3_v3(data->F[j], f);
-
+
add_m3_m3m3(data->dFdX[i].m, data->dFdX[i].m, dfdx);
add_m3_m3m3(data->dFdX[j].m, data->dFdX[j].m, dfdx);
sub_m3_m3m3(data->dFdX[block_ij].m, data->dFdX[block_ij].m, dfdx);
-
+
add_m3_m3m3(data->dFdV[i].m, data->dFdV[i].m, dfdv);
add_m3_m3m3(data->dFdV[j].m, data->dFdV[j].m, dfdv);
sub_m3_m3m3(data->dFdV[block_ij].m, data->dFdV[block_ij].m, dfdv);
@@ -1581,7 +1581,7 @@ bool BPH_mass_spring_force_spring_linear(Implicit_Data *data, int i, int j, floa
float stiffness, float damping, bool no_compress, float clamp_force)
{
float extent[3], length, dir[3], vel[3];
-
+
// calculate elonglation
spring_length(data, i, j, extent, dir, &length, vel);
@@ -1590,22 +1590,22 @@ bool BPH_mass_spring_force_spring_linear(Implicit_Data *data, int i, int j, floa
Thus length > restlen makes cloth unconstrained at the start of simulation. */
if ((length >= restlen && length > 0) || no_compress) {
float stretch_force, f[3], dfdx[3][3], dfdv[3][3];
-
+
stretch_force = stiffness * (length - restlen);
if (clamp_force > 0.0f && stretch_force > clamp_force) {
stretch_force = clamp_force;
}
mul_v3_v3fl(f, dir, stretch_force);
-
+
// Ascher & Boxman, p.21: Damping only during elonglation
// something wrong with it...
madd_v3_v3fl(f, dir, damping * dot_v3v3(vel, dir));
-
+
dfdx_spring(dfdx, dir, length, restlen, stiffness);
dfdv_damp(dfdv, dir, damping);
-
+
apply_spring(data, i, j, f, dfdx, dfdv);
-
+
return true;
}
else {
@@ -1617,23 +1617,23 @@ bool BPH_mass_spring_force_spring_linear(Implicit_Data *data, int i, int j, floa
bool BPH_mass_spring_force_spring_bending(Implicit_Data *data, int i, int j, float restlen, float kb, float cb)
{
float extent[3], length, dir[3], vel[3];
-
+
// calculate elonglation
spring_length(data, i, j, extent, dir, &length, vel);
-
+
if (length < restlen) {
float f[3], dfdx[3][3], dfdv[3][3];
-
+
mul_v3_v3fl(f, dir, fbstar(length, restlen, kb, cb));
-
+
outerproduct(dfdx, dir, dir);
mul_m3_fl(dfdx, fbstar_jacobi(length, restlen, kb, cb));
-
+
/* XXX damping not supported */
zero_m3(dfdv);
-
+
apply_spring(data, i, j, f, dfdx, dfdv);
-
+
return true;
}
else {
@@ -1650,10 +1650,10 @@ bool BPH_mass_spring_force_spring_bending(Implicit_Data *data, int i, int j, flo
BLI_INLINE void spring_grad_dir(Implicit_Data *data, int i, int j, float edge[3], float dir[3], float grad_dir[3][3])
{
float length;
-
+
sub_v3_v3v3(edge, data->X[j], data->X[i]);
length = normalize_v3_v3(dir, edge);
-
+
if (length > ALMOST_ZERO) {
outerproduct(grad_dir, dir, dir);
sub_m3_m3m3(grad_dir, I, grad_dir);
@@ -1676,39 +1676,39 @@ BLI_INLINE void spring_angbend_forces(Implicit_Data *data, int i, int j, int k,
float f_bend[3], f_damp[3];
float fk[3];
float dist[3];
-
+
zero_v3(fk);
-
+
sub_v3_v3v3(edge_ij, data->X[j], data->X[i]);
if (q == i) sub_v3_v3(edge_ij, dx);
if (q == j) add_v3_v3(edge_ij, dx);
normalize_v3_v3(dir_ij, edge_ij);
-
+
sub_v3_v3v3(edge_jk, data->X[k], data->X[j]);
if (q == j) sub_v3_v3(edge_jk, dx);
if (q == k) add_v3_v3(edge_jk, dx);
normalize_v3_v3(dir_jk, edge_jk);
-
+
sub_v3_v3v3(vel_ij, data->V[j], data->V[i]);
if (q == i) sub_v3_v3(vel_ij, dv);
if (q == j) add_v3_v3(vel_ij, dv);
-
+
sub_v3_v3v3(vel_jk, data->V[k], data->V[j]);
if (q == j) sub_v3_v3(vel_jk, dv);
if (q == k) add_v3_v3(vel_jk, dv);
-
+
/* bending force */
sub_v3_v3v3(dist, goal, edge_jk);
mul_v3_v3fl(f_bend, dist, stiffness);
-
+
add_v3_v3(fk, f_bend);
-
+
/* damping force */
madd_v3_v3v3fl(vel_ortho, vel_jk, dir_jk, -dot_v3v3(vel_jk, dir_jk));
mul_v3_v3fl(f_damp, vel_ortho, damping);
-
+
sub_v3_v3(fk, f_damp);
-
+
copy_v3_v3(r_f, fk);
}
@@ -1722,24 +1722,24 @@ BLI_INLINE void spring_angbend_estimate_dfdx(Implicit_Data *data, int i, int j,
float dvec_null[3][3], dvec_pos[3][3], dvec_neg[3][3];
float f[3];
int a, b;
-
+
zero_m3(dvec_null);
unit_m3(dvec_pos);
mul_m3_fl(dvec_pos, delta * 0.5f);
copy_m3_m3(dvec_neg, dvec_pos);
negate_m3(dvec_neg);
-
+
/* XXX TODO offset targets to account for position dependency */
-
+
for (a = 0; a < 3; ++a) {
spring_angbend_forces(data, i, j, k, goal, stiffness, damping,
q, dvec_pos[a], dvec_null[a], f);
copy_v3_v3(dfdx[a], f);
-
+
spring_angbend_forces(data, i, j, k, goal, stiffness, damping,
q, dvec_neg[a], dvec_null[a], f);
sub_v3_v3(dfdx[a], f);
-
+
for (b = 0; b < 3; ++b) {
dfdx[a][b] /= delta;
}
@@ -1756,24 +1756,24 @@ BLI_INLINE void spring_angbend_estimate_dfdv(Implicit_Data *data, int i, int j,
float dvec_null[3][3], dvec_pos[3][3], dvec_neg[3][3];
float f[3];
int a, b;
-
+
zero_m3(dvec_null);
unit_m3(dvec_pos);
mul_m3_fl(dvec_pos, delta * 0.5f);
copy_m3_m3(dvec_neg, dvec_pos);
negate_m3(dvec_neg);
-
+
/* XXX TODO offset targets to account for position dependency */
-
+
for (a = 0; a < 3; ++a) {
spring_angbend_forces(data, i, j, k, goal, stiffness, damping,
q, dvec_null[a], dvec_pos[a], f);
copy_v3_v3(dfdv[a], f);
-
+
spring_angbend_forces(data, i, j, k, goal, stiffness, damping,
q, dvec_null[a], dvec_neg[a], f);
sub_v3_v3(dfdv[a], f);
-
+
for (b = 0; b < 3; ++b) {
dfdv[a][b] /= delta;
}
@@ -1790,45 +1790,45 @@ bool BPH_mass_spring_force_spring_bending_angular(Implicit_Data *data, int i, in
float fj[3], fk[3];
float dfj_dxi[3][3], dfj_dxj[3][3], dfk_dxi[3][3], dfk_dxj[3][3], dfk_dxk[3][3];
float dfj_dvi[3][3], dfj_dvj[3][3], dfk_dvi[3][3], dfk_dvj[3][3], dfk_dvk[3][3];
-
+
const float vecnull[3] = {0.0f, 0.0f, 0.0f};
-
+
int block_ij = BPH_mass_spring_add_block(data, i, j);
int block_jk = BPH_mass_spring_add_block(data, j, k);
int block_ik = BPH_mass_spring_add_block(data, i, k);
-
+
world_to_root_v3(data, j, goal, target);
-
+
spring_angbend_forces(data, i, j, k, goal, stiffness, damping, k, vecnull, vecnull, fk);
negate_v3_v3(fj, fk); /* counterforce */
-
+
spring_angbend_estimate_dfdx(data, i, j, k, goal, stiffness, damping, i, dfk_dxi);
spring_angbend_estimate_dfdx(data, i, j, k, goal, stiffness, damping, j, dfk_dxj);
spring_angbend_estimate_dfdx(data, i, j, k, goal, stiffness, damping, k, dfk_dxk);
copy_m3_m3(dfj_dxi, dfk_dxi); negate_m3(dfj_dxi);
copy_m3_m3(dfj_dxj, dfk_dxj); negate_m3(dfj_dxj);
-
+
spring_angbend_estimate_dfdv(data, i, j, k, goal, stiffness, damping, i, dfk_dvi);
spring_angbend_estimate_dfdv(data, i, j, k, goal, stiffness, damping, j, dfk_dvj);
spring_angbend_estimate_dfdv(data, i, j, k, goal, stiffness, damping, k, dfk_dvk);
copy_m3_m3(dfj_dvi, dfk_dvi); negate_m3(dfj_dvi);
copy_m3_m3(dfj_dvj, dfk_dvj); negate_m3(dfj_dvj);
-
+
/* add forces and jacobians to the solver data */
-
+
add_v3_v3(data->F[j], fj);
add_v3_v3(data->F[k], fk);
-
+
add_m3_m3m3(data->dFdX[j].m, data->dFdX[j].m, dfj_dxj);
add_m3_m3m3(data->dFdX[k].m, data->dFdX[k].m, dfk_dxk);
-
+
add_m3_m3m3(data->dFdX[block_ij].m, data->dFdX[block_ij].m, dfj_dxi);
add_m3_m3m3(data->dFdX[block_jk].m, data->dFdX[block_jk].m, dfk_dxj);
add_m3_m3m3(data->dFdX[block_ik].m, data->dFdX[block_ik].m, dfk_dxi);
-
+
add_m3_m3m3(data->dFdV[j].m, data->dFdV[j].m, dfj_dvj);
add_m3_m3m3(data->dFdV[k].m, data->dFdV[k].m, dfk_dvk);
-
+
add_m3_m3m3(data->dFdV[block_ij].m, data->dFdV[block_ij].m, dfj_dvi);
add_m3_m3m3(data->dFdV[block_jk].m, data->dFdV[block_jk].m, dfk_dvj);
add_m3_m3m3(data->dFdV[block_ik].m, data->dFdV[block_ik].m, dfk_dvi);
@@ -1847,10 +1847,10 @@ bool BPH_mass_spring_force_spring_bending_angular(Implicit_Data *data, int i, in
float fi[3], fj[3], fk[3];
float dfi_dxi[3][3], dfj_dxi[3][3], dfj_dxj[3][3], dfk_dxi[3][3], dfk_dxj[3][3], dfk_dxk[3][3];
float dfdvi[3][3];
-
+
// TESTING
damping = 0.0f;
-
+
zero_v3(fi);
zero_v3(fj);
zero_v3(fk);
@@ -1859,68 +1859,68 @@ bool BPH_mass_spring_force_spring_bending_angular(Implicit_Data *data, int i, in
zero_m3(dfk_dxi);
zero_m3(dfk_dxj);
zero_m3(dfk_dxk);
-
+
/* jacobian of direction vectors */
spring_grad_dir(data, i, j, edge_ij, dir_ij, grad_dir_ij);
spring_grad_dir(data, j, k, edge_jk, dir_jk, grad_dir_jk);
-
+
sub_v3_v3v3(vel_jk, data->V[k], data->V[j]);
-
+
/* bending force */
mul_v3_v3fl(target, dir_ij, restlen);
sub_v3_v3v3(dist, target, edge_jk);
mul_v3_v3fl(fk, dist, stiffness);
-
+
/* damping force */
madd_v3_v3v3fl(vel_jk_ortho, vel_jk, dir_jk, -dot_v3v3(vel_jk, dir_jk));
madd_v3_v3fl(fk, vel_jk_ortho, damping);
-
+
/* XXX this only holds true as long as we assume straight rest shape!
* eventually will become a bit more involved since the opposite segment
* gets its own target, under condition of having equal torque on both sides.
*/
copy_v3_v3(fi, fk);
-
+
/* counterforce on the middle point */
sub_v3_v3(fj, fi);
sub_v3_v3(fj, fk);
-
+
/* === derivatives === */
-
+
madd_m3_m3fl(dfk_dxi, grad_dir_ij, stiffness * restlen);
-
+
madd_m3_m3fl(dfk_dxj, grad_dir_ij, -stiffness * restlen);
madd_m3_m3fl(dfk_dxj, I, stiffness);
-
+
madd_m3_m3fl(dfk_dxk, I, -stiffness);
-
+
copy_m3_m3(dfi_dxi, dfk_dxk);
negate_m3(dfi_dxi);
-
+
/* dfj_dfi == dfi_dfj due to symmetry,
* dfi_dfj == dfk_dfj due to fi == fk
* XXX see comment above on future bent rest shapes
*/
copy_m3_m3(dfj_dxi, dfk_dxj);
-
+
/* dfj_dxj == -(dfi_dxj + dfk_dxj) due to fj == -(fi + fk) */
sub_m3_m3m3(dfj_dxj, dfj_dxj, dfj_dxi);
sub_m3_m3m3(dfj_dxj, dfj_dxj, dfk_dxj);
-
+
/* add forces and jacobians to the solver data */
add_v3_v3(data->F[i], fi);
add_v3_v3(data->F[j], fj);
add_v3_v3(data->F[k], fk);
-
+
add_m3_m3m3(data->dFdX[i].m, data->dFdX[i].m, dfi_dxi);
add_m3_m3m3(data->dFdX[j].m, data->dFdX[j].m, dfj_dxj);
add_m3_m3m3(data->dFdX[k].m, data->dFdX[k].m, dfk_dxk);
-
+
add_m3_m3m3(data->dFdX[block_ij].m, data->dFdX[block_ij].m, dfj_dxi);
add_m3_m3m3(data->dFdX[block_jk].m, data->dFdX[block_jk].m, dfk_dxj);
add_m3_m3m3(data->dFdX[block_ik].m, data->dFdX[block_ik].m, dfk_dxi);
#endif
-
+
return true;
}
@@ -1929,29 +1929,29 @@ bool BPH_mass_spring_force_spring_goal(Implicit_Data *data, int i, const float g
{
float root_goal_x[3], root_goal_v[3], extent[3], length, dir[3], vel[3];
float f[3], dfdx[3][3], dfdv[3][3];
-
+
/* goal is in world space */
world_to_root_v3(data, i, root_goal_x, goal_x);
world_to_root_v3(data, i, root_goal_v, goal_v);
-
+
sub_v3_v3v3(extent, root_goal_x, data->X[i]);
sub_v3_v3v3(vel, root_goal_v, data->V[i]);
length = normalize_v3_v3(dir, extent);
-
+
if (length > ALMOST_ZERO) {
mul_v3_v3fl(f, dir, stiffness * length);
-
+
// Ascher & Boxman, p.21: Damping only during elonglation
// something wrong with it...
madd_v3_v3fl(f, dir, damping * dot_v3v3(vel, dir));
-
+
dfdx_spring(dfdx, dir, length, 0.0f, stiffness);
dfdv_damp(dfdv, dir, damping);
-
+
add_v3_v3(data->F[i], f);
add_m3_m3m3(data->dFdX[i].m, data->dFdX[i].m, dfdx);
add_m3_m3m3(data->dFdV[i].m, data->dFdV[i].m, dfdv);
-
+
return true;
}
else {
diff --git a/source/blender/physics/intern/implicit_eigen.cpp b/source/blender/physics/intern/implicit_eigen.cpp
index d56525f2e93..eaac63893a6 100644
--- a/source/blender/physics/intern/implicit_eigen.cpp
+++ b/source/blender/physics/intern/implicit_eigen.cpp
@@ -99,24 +99,24 @@ static float I[3][3] = {{1, 0, 0}, {0, 1, 0}, {0, 0, 1}};
class fVector : public Eigen::Vector3f {
public:
typedef float *ctype;
-
+
fVector()
{
}
-
+
fVector(const ctype &v)
{
for (int k = 0; k < 3; ++k)
coeffRef(k) = v[k];
}
-
+
fVector& operator = (const ctype &v)
{
for (int k = 0; k < 3; ++k)
coeffRef(k) = v[k];
return *this;
}
-
+
operator ctype()
{
return data();
@@ -129,18 +129,18 @@ public:
class fMatrix : public Eigen::Matrix3f {
public:
typedef float (*ctype)[3];
-
+
fMatrix()
{
}
-
+
fMatrix(const ctype &v)
{
for (int k = 0; k < 3; ++k)
for (int l = 0; l < 3; ++l)
coeffRef(l, k) = v[k][l];
}
-
+
fMatrix& operator = (const ctype &v)
{
for (int k = 0; k < 3; ++k)
@@ -148,7 +148,7 @@ public:
coeffRef(l, k) = v[k][l];
return *this;
}
-
+
operator ctype()
{
return (ctype)data();
@@ -161,23 +161,23 @@ public:
class lVector : public Eigen::VectorXf {
public:
typedef Eigen::VectorXf base_t;
-
+
lVector()
{
}
-
+
template <typename T>
lVector& operator = (T rhs)
{
base_t::operator=(rhs);
return *this;
}
-
+
float* v3(int vertex)
{
return &coeffRef(3 * vertex);
}
-
+
const float* v3(int vertex) const
{
return &coeffRef(3 * vertex);
@@ -198,18 +198,18 @@ struct lMatrixCtor {
lMatrixCtor()
{
}
-
+
void reset()
{
m_trips.clear();
}
-
+
void reserve(int numverts)
{
/* reserve for diagonal entries */
m_trips.reserve(numverts * 9);
}
-
+
void add(int i, int j, const fMatrix &m)
{
i *= 3;
@@ -218,7 +218,7 @@ struct lMatrixCtor {
for (int l = 0; l < 3; ++l)
m_trips.push_back(Triplet(i + k, j + l, m.coeff(l, k)));
}
-
+
void sub(int i, int j, const fMatrix &m)
{
i *= 3;
@@ -227,13 +227,13 @@ struct lMatrixCtor {
for (int l = 0; l < 3; ++l)
m_trips.push_back(Triplet(i + k, j + l, -m.coeff(l, k)));
}
-
+
inline void construct(lMatrix &m)
{
m.setFromTriplets(m_trips.begin(), m_trips.end());
m_trips.clear();
}
-
+
private:
TripletList m_trips;
};
@@ -253,7 +253,7 @@ static void print_lvector(const lVector &v)
for (int i = 0; i < v.rows(); ++i) {
if (i > 0 && i % 3 == 0)
printf("\n");
-
+
printf("%f,\n", v[i]);
}
}
@@ -263,11 +263,11 @@ static void print_lmatrix(const lMatrix &m)
for (int j = 0; j < m.rows(); ++j) {
if (j > 0 && j % 3 == 0)
printf("\n");
-
+
for (int i = 0; i < m.cols(); ++i) {
if (i > 0 && i % 3 == 0)
printf(" ");
-
+
implicit_print_matrix_elem(m.coeff(j, i));
}
printf("\n");
@@ -383,63 +383,63 @@ BLI_INLINE void madd_m3_m3m3fl(float r[3][3], float a[3][3], float b[3][3], floa
struct Implicit_Data {
typedef std::vector<fMatrix> fMatrixVector;
-
+
Implicit_Data(int numverts)
{
resize(numverts);
}
-
+
void resize(int numverts)
{
this->numverts = numverts;
int tot = 3 * numverts;
-
+
M.resize(tot, tot);
F.resize(tot);
dFdX.resize(tot, tot);
dFdV.resize(tot, tot);
-
+
tfm.resize(numverts, I);
-
+
X.resize(tot);
Xnew.resize(tot);
V.resize(tot);
Vnew.resize(tot);
-
+
A.resize(tot, tot);
B.resize(tot);
-
+
dV.resize(tot);
z.resize(tot);
S.resize(tot, tot);
-
+
iM.reserve(numverts);
idFdX.reserve(numverts);
idFdV.reserve(numverts);
iS.reserve(numverts);
}
-
+
int numverts;
-
+
/* inputs */
lMatrix M; /* masses */
lVector F; /* forces */
lMatrix dFdX, dFdV; /* force jacobians */
-
+
fMatrixVector tfm; /* local coordinate transform */
-
+
/* motion state data */
lVector X, Xnew; /* positions */
lVector V, Vnew; /* velocities */
-
+
/* internal solver data */
lVector B; /* B for A*dV = B */
lMatrix A; /* A for A*dV = B */
-
+
lVector dV; /* velocity change (solution of A*dV = B) */
lVector z; /* target velocity in constrained directions */
lMatrix S; /* filtering matrix for constraints */
-
+
/* temporary constructors */
lMatrixCtor iM; /* masses */
lMatrixCtor idFdX, idFdV; /* force jacobians */
@@ -502,25 +502,25 @@ bool BPH_mass_spring_solve_velocities(Implicit_Data *data, float dt, ImplicitSol
#ifdef USE_EIGEN_CONSTRAINED_CG
typedef ConstraintConjGrad solver_t;
#endif
-
+
data->iM.construct(data->M);
data->idFdX.construct(data->dFdX);
data->idFdV.construct(data->dFdV);
data->iS.construct(data->S);
-
+
solver_t cg;
cg.setMaxIterations(100);
cg.setTolerance(0.01f);
-
+
#ifdef USE_EIGEN_CONSTRAINED_CG
cg.filter() = data->S;
#endif
-
+
data->A = data->M - dt * data->dFdV - dt*dt * data->dFdX;
cg.compute(data->A);
-
+
data->B = dt * data->F + dt*dt * data->dFdX * data->V;
-
+
#ifdef IMPLICIT_PRINT_SOLVER_INPUT_OUTPUT
printf("==== A ====\n");
print_lmatrix(id->A);
@@ -531,22 +531,22 @@ bool BPH_mass_spring_solve_velocities(Implicit_Data *data, float dt, ImplicitSol
printf("==== S ====\n");
print_lmatrix(id->S);
#endif
-
+
#ifdef USE_EIGEN_CORE
data->dV = cg.solve(data->B);
#endif
#ifdef USE_EIGEN_CONSTRAINED_CG
data->dV = cg.solveWithGuess(data->B, data->z);
#endif
-
+
#ifdef IMPLICIT_PRINT_SOLVER_INPUT_OUTPUT
printf("==== dV ====\n");
print_lvector(id->dV);
printf("========\n");
#endif
-
+
data->Vnew = data->V + data->dV;
-
+
switch (cg.info()) {
case Eigen::Success: result->status = BPH_SOLVER_SUCCESS; break;
case Eigen::NoConvergence: result->status = BPH_SOLVER_NO_CONVERGENCE; break;
@@ -556,7 +556,7 @@ bool BPH_mass_spring_solve_velocities(Implicit_Data *data, float dt, ImplicitSol
result->iterations = cg.iterations();
result->error = cg.error();
-
+
return cg.info() == Eigen::Success;
}
@@ -641,26 +641,26 @@ void BPH_mass_spring_clear_constraints(Implicit_Data *data)
void BPH_mass_spring_add_constraint_ndof0(Implicit_Data *data, int index, const float dV[3])
{
data->iS.sub(index, index, I);
-
+
world_to_root_v3(data, index, data->z.v3(index), dV);
}
void BPH_mass_spring_add_constraint_ndof1(Implicit_Data *data, int index, const float c1[3], const float c2[3], const float dV[3])
{
float m[3][3], p[3], q[3], u[3], cmat[3][3];
-
+
world_to_root_v3(data, index, p, c1);
outerproduct(cmat, p, p);
copy_m3_m3(m, cmat);
-
+
world_to_root_v3(data, index, q, c2);
outerproduct(cmat, q, q);
add_m3_m3m3(m, m, cmat);
-
+
/* XXX not sure but multiplication should work here */
data->iS.sub(index, index, m);
// mul_m3_m3m3(data->S[index].m, data->S[index].m, m);
-
+
world_to_root_v3(data, index, u, dV);
add_v3_v3(data->z.v3(index), u);
}
@@ -668,14 +668,14 @@ void BPH_mass_spring_add_constraint_ndof1(Implicit_Data *data, int index, const
void BPH_mass_spring_add_constraint_ndof2(Implicit_Data *data, int index, const float c1[3], const float dV[3])
{
float m[3][3], p[3], u[3], cmat[3][3];
-
+
world_to_root_v3(data, index, p, c1);
outerproduct(cmat, p, p);
copy_m3_m3(m, cmat);
-
+
data->iS.sub(index, index, m);
// mul_m3_m3m3(data->S[index].m, data->S[index].m, m);
-
+
world_to_root_v3(data, index, u, dV);
add_v3_v3(data->z.v3(index), u);
}
@@ -694,37 +694,37 @@ void BPH_mass_spring_force_reference_frame(Implicit_Data *data, int index, const
float f[3], dfdx[3][3], dfdv[3][3];
float euler[3], coriolis[3], centrifugal[3], rotvel[3];
float deuler[3][3], dcoriolis[3][3], dcentrifugal[3][3], drotvel[3][3];
-
+
world_to_root_v3(data, index, acc, acceleration);
world_to_root_v3(data, index, w, omega);
world_to_root_v3(data, index, dwdt, domega_dt);
-
+
cross_v3_v3v3(euler, dwdt, data->X.v3(index));
cross_v3_v3v3(coriolis, w, data->V.v3(index));
mul_v3_fl(coriolis, 2.0f);
cross_v3_v3v3(rotvel, w, data->X.v3(index));
cross_v3_v3v3(centrifugal, w, rotvel);
-
+
sub_v3_v3v3(f, acc, euler);
sub_v3_v3(f, coriolis);
sub_v3_v3(f, centrifugal);
-
+
mul_v3_fl(f, mass); /* F = m * a */
-
+
cross_v3_identity(deuler, dwdt);
cross_v3_identity(dcoriolis, w);
mul_m3_fl(dcoriolis, 2.0f);
cross_v3_identity(drotvel, w);
cross_m3_v3m3(dcentrifugal, w, drotvel);
-
+
add_m3_m3m3(dfdx, deuler, dcentrifugal);
negate_m3(dfdx);
mul_m3_fl(dfdx, mass);
-
+
copy_m3_m3(dfdv, dcoriolis);
negate_m3(dfdv);
mul_m3_fl(dfdv, mass);
-
+
add_v3_v3(data->F.v3(index), f);
data->idFdX.add(index, index, dfdx);
data->idFdV.add(index, index, dfdv);
@@ -743,7 +743,7 @@ void BPH_mass_spring_force_gravity(Implicit_Data *data, int index, float mass, c
float f[3];
world_to_root_v3(data, index, f, g);
mul_v3_fl(f, mass);
-
+
add_v3_v3(data->F.v3(index), f);
}
@@ -752,10 +752,10 @@ void BPH_mass_spring_force_drag(Implicit_Data *data, float drag)
int numverts = data->numverts;
for (int i = 0; i < numverts; i++) {
float tmp[3][3];
-
+
/* NB: uses root space velocity, no need to transform */
madd_v3_v3fl(data->F.v3(i), data->V.v3(i), -drag);
-
+
copy_m3_m3(tmp, I);
mul_m3_fl(tmp, -drag);
data->idFdV.add(i, i, tmp);
@@ -768,7 +768,7 @@ void BPH_mass_spring_force_extern(struct Implicit_Data *data, int i, const float
world_to_root_v3(data, i, tf, f);
world_to_root_m3(data, i, tdfdx, dfdx);
world_to_root_m3(data, i, tdfdv, dfdv);
-
+
add_v3_v3(data->F.v3(i), tf);
data->idFdX.add(i, i, tdfdx);
data->idFdV.add(i, i, tdfdv);
@@ -777,10 +777,10 @@ void BPH_mass_spring_force_extern(struct Implicit_Data *data, int i, const float
static float calc_nor_area_tri(float nor[3], const float v1[3], const float v2[3], const float v3[3])
{
float n1[3], n2[3];
-
+
sub_v3_v3v3(n1, v1, v2);
sub_v3_v3v3(n2, v2, v3);
-
+
cross_v3_v3v3(nor, n1, n2);
return normalize_v3(nor);
}
@@ -791,17 +791,17 @@ void BPH_mass_spring_force_face_wind(Implicit_Data *data, int v1, int v2, int v3
const float effector_scale = 0.02f;
float win[3], nor[3], area;
float factor;
-
+
// calculate face normal and area
area = calc_nor_area_tri(nor, data->X.v3(v1), data->X.v3(v2), data->X.v3(v3));
factor = effector_scale * area / 3.0f;
-
+
world_to_root_v3(data, v1, win, winvec[v1]);
madd_v3_v3fl(data->F.v3(v1), nor, factor * dot_v3v3(win, nor));
-
+
world_to_root_v3(data, v2, win, winvec[v2]);
madd_v3_v3fl(data->F.v3(v2), nor, factor * dot_v3v3(win, nor));
-
+
world_to_root_v3(data, v3, win, winvec[v3]);
madd_v3_v3fl(data->F.v3(v3), nor, factor * dot_v3v3(win, nor));
}
@@ -810,14 +810,14 @@ void BPH_mass_spring_force_edge_wind(Implicit_Data *data, int v1, int v2, const
{
const float effector_scale = 0.01;
float win[3], dir[3], nor[3], length;
-
+
sub_v3_v3v3(dir, data->X.v3(v1), data->X.v3(v2));
length = normalize_v3(dir);
-
+
world_to_root_v3(data, v1, win, winvec[v1]);
madd_v3_v3v3fl(nor, win, dir, -dot_v3v3(win, dir));
madd_v3_v3fl(data->F.v3(v1), nor, effector_scale * length);
-
+
world_to_root_v3(data, v2, win, winvec[v2]);
madd_v3_v3v3fl(nor, win, dir, -dot_v3v3(win, dir));
madd_v3_v3fl(data->F.v3(v2), nor, effector_scale * length);
@@ -829,8 +829,8 @@ BLI_INLINE void dfdx_spring(float to[3][3], const float dir[3], float length, fl
//return ( (I-outerprod(dir, dir))*Min(1.0f, rest/length) - I) * -k;
outerproduct(to, dir, dir);
sub_m3_m3m3(to, I, to);
-
- mul_m3_fl(to, (L/length));
+
+ mul_m3_fl(to, (L/length));
sub_m3_m3m3(to, to, I);
mul_m3_fl(to, k);
}
@@ -839,7 +839,7 @@ BLI_INLINE void dfdx_spring(float to[3][3], const float dir[3], float length, fl
#if 0
BLI_INLINE void dfdx_damp(float to[3][3], const float dir[3], float length, const float vel[3], float rest, float damping)
{
- // inner spring damping vel is the relative velocity of the endpoints.
+ // inner spring damping vel is the relative velocity of the endpoints.
// return (I-outerprod(dir, dir)) * (-damping * -(dot(dir, vel)/Max(length, rest)));
mul_fvectorT_fvector(to, dir, dir);
sub_fmatrix_fmatrix(to, I, to);
@@ -871,7 +871,7 @@ BLI_INLINE float fbstar(float length, float L, float kb, float cb)
{
float tempfb_fl = kb * fb(length, L);
float fbstar_fl = cb * (length - L);
-
+
if (tempfb_fl < fbstar_fl)
return fbstar_fl;
else
@@ -898,7 +898,7 @@ BLI_INLINE bool spring_length(Implicit_Data *data, int i, int j, float r_extent[
sub_v3_v3v3(r_extent, data->X.v3(j), data->X.v3(i));
sub_v3_v3v3(r_vel, data->V.v3(j), data->V.v3(i));
*r_length = len_v3(r_extent);
-
+
if (*r_length > ALMOST_ZERO) {
/*
if (length>L) {
@@ -916,7 +916,7 @@ BLI_INLINE bool spring_length(Implicit_Data *data, int i, int j, float r_extent[
else {
zero_v3(r_dir);
}
-
+
return true;
}
@@ -924,12 +924,12 @@ BLI_INLINE void apply_spring(Implicit_Data *data, int i, int j, const float f[3]
{
add_v3_v3(data->F.v3(i), f);
sub_v3_v3(data->F.v3(j), f);
-
+
data->idFdX.add(i, i, dfdx);
data->idFdX.add(j, j, dfdx);
data->idFdX.sub(i, j, dfdx);
data->idFdX.sub(j, i, dfdx);
-
+
data->idFdV.add(i, i, dfdv);
data->idFdV.add(j, j, dfdv);
data->idFdV.sub(i, j, dfdv);
@@ -941,39 +941,39 @@ bool BPH_mass_spring_force_spring_linear(Implicit_Data *data, int i, int j, floa
float r_f[3], float r_dfdx[3][3], float r_dfdv[3][3])
{
float extent[3], length, dir[3], vel[3];
-
+
// calculate elonglation
spring_length(data, i, j, extent, dir, &length, vel);
-
+
if (length > restlen || no_compress) {
float stretch_force, f[3], dfdx[3][3], dfdv[3][3];
-
+
stretch_force = stiffness * (length - restlen);
if (clamp_force > 0.0f && stretch_force > clamp_force) {
stretch_force = clamp_force;
}
mul_v3_v3fl(f, dir, stretch_force);
-
+
// Ascher & Boxman, p.21: Damping only during elonglation
// something wrong with it...
madd_v3_v3fl(f, dir, damping * dot_v3v3(vel, dir));
-
+
dfdx_spring(dfdx, dir, length, restlen, stiffness);
dfdv_damp(dfdv, dir, damping);
-
+
apply_spring(data, i, j, f, dfdx, dfdv);
-
+
if (r_f) copy_v3_v3(r_f, f);
if (r_dfdx) copy_m3_m3(r_dfdx, dfdx);
if (r_dfdv) copy_m3_m3(r_dfdv, dfdv);
-
+
return true;
}
else {
if (r_f) zero_v3(r_f);
if (r_dfdx) zero_m3(r_dfdx);
if (r_dfdv) zero_m3(r_dfdv);
-
+
return false;
}
}
@@ -984,34 +984,34 @@ bool BPH_mass_spring_force_spring_bending(Implicit_Data *data, int i, int j, flo
float r_f[3], float r_dfdx[3][3], float r_dfdv[3][3])
{
float extent[3], length, dir[3], vel[3];
-
+
// calculate elonglation
spring_length(data, i, j, extent, dir, &length, vel);
-
+
if (length < restlen) {
float f[3], dfdx[3][3], dfdv[3][3];
-
+
mul_v3_v3fl(f, dir, fbstar(length, restlen, kb, cb));
-
+
outerproduct(dfdx, dir, dir);
mul_m3_fl(dfdx, fbstar_jacobi(length, restlen, kb, cb));
-
+
/* XXX damping not supported */
zero_m3(dfdv);
-
+
apply_spring(data, i, j, f, dfdx, dfdv);
-
+
if (r_f) copy_v3_v3(r_f, f);
if (r_dfdx) copy_m3_m3(r_dfdx, dfdx);
if (r_dfdv) copy_m3_m3(r_dfdv, dfdv);
-
+
return true;
}
else {
if (r_f) zero_v3(r_f);
if (r_dfdx) zero_m3(r_dfdx);
if (r_dfdv) zero_m3(r_dfdv);
-
+
return false;
}
}
@@ -1025,10 +1025,10 @@ bool BPH_mass_spring_force_spring_bending(Implicit_Data *data, int i, int j, flo
BLI_INLINE void spring_grad_dir(Implicit_Data *data, int i, int j, float edge[3], float dir[3], float grad_dir[3][3])
{
float length;
-
+
sub_v3_v3v3(edge, data->X.v3(j), data->X.v3(i));
length = normalize_v3_v3(dir, edge);
-
+
if (length > ALMOST_ZERO) {
outerproduct(grad_dir, dir, dir);
sub_m3_m3m3(grad_dir, I, grad_dir);
@@ -1051,39 +1051,39 @@ BLI_INLINE void spring_angbend_forces(Implicit_Data *data, int i, int j, int k,
float f_bend[3], f_damp[3];
float fk[3];
float dist[3];
-
+
zero_v3(fk);
-
+
sub_v3_v3v3(edge_ij, data->X.v3(j), data->X.v3(i));
if (q == i) sub_v3_v3(edge_ij, dx);
if (q == j) add_v3_v3(edge_ij, dx);
normalize_v3_v3(dir_ij, edge_ij);
-
+
sub_v3_v3v3(edge_jk, data->X.v3(k), data->X.v3(j));
if (q == j) sub_v3_v3(edge_jk, dx);
if (q == k) add_v3_v3(edge_jk, dx);
normalize_v3_v3(dir_jk, edge_jk);
-
+
sub_v3_v3v3(vel_ij, data->V.v3(j), data->V.v3(i));
if (q == i) sub_v3_v3(vel_ij, dv);
if (q == j) add_v3_v3(vel_ij, dv);
-
+
sub_v3_v3v3(vel_jk, data->V.v3(k), data->V.v3(j));
if (q == j) sub_v3_v3(vel_jk, dv);
if (q == k) add_v3_v3(vel_jk, dv);
-
+
/* bending force */
sub_v3_v3v3(dist, goal, edge_jk);
mul_v3_v3fl(f_bend, dist, stiffness);
-
+
add_v3_v3(fk, f_bend);
-
+
/* damping force */
madd_v3_v3v3fl(vel_ortho, vel_jk, dir_jk, -dot_v3v3(vel_jk, dir_jk));
mul_v3_v3fl(f_damp, vel_ortho, damping);
-
+
sub_v3_v3(fk, f_damp);
-
+
copy_v3_v3(r_f, fk);
}
@@ -1097,24 +1097,24 @@ BLI_INLINE void spring_angbend_estimate_dfdx(Implicit_Data *data, int i, int j,
float dvec_null[3][3], dvec_pos[3][3], dvec_neg[3][3];
float f[3];
int a, b;
-
+
zero_m3(dvec_null);
unit_m3(dvec_pos);
mul_m3_fl(dvec_pos, delta * 0.5f);
copy_m3_m3(dvec_neg, dvec_pos);
negate_m3(dvec_neg);
-
+
/* XXX TODO offset targets to account for position dependency */
-
+
for (a = 0; a < 3; ++a) {
spring_angbend_forces(data, i, j, k, goal, stiffness, damping,
q, dvec_pos[a], dvec_null[a], f);
copy_v3_v3(dfdx[a], f);
-
+
spring_angbend_forces(data, i, j, k, goal, stiffness, damping,
q, dvec_neg[a], dvec_null[a], f);
sub_v3_v3(dfdx[a], f);
-
+
for (b = 0; b < 3; ++b) {
dfdx[a][b] /= delta;
}
@@ -1131,24 +1131,24 @@ BLI_INLINE void spring_angbend_estimate_dfdv(Implicit_Data *data, int i, int j,
float dvec_null[3][3], dvec_pos[3][3], dvec_neg[3][3];
float f[3];
int a, b;
-
+
zero_m3(dvec_null);
unit_m3(dvec_pos);
mul_m3_fl(dvec_pos, delta * 0.5f);
copy_m3_m3(dvec_neg, dvec_pos);
negate_m3(dvec_neg);
-
+
/* XXX TODO offset targets to account for position dependency */
-
+
for (a = 0; a < 3; ++a) {
spring_angbend_forces(data, i, j, k, goal, stiffness, damping,
q, dvec_null[a], dvec_pos[a], f);
copy_v3_v3(dfdv[a], f);
-
+
spring_angbend_forces(data, i, j, k, goal, stiffness, damping,
q, dvec_null[a], dvec_neg[a], f);
sub_v3_v3(dfdv[a], f);
-
+
for (b = 0; b < 3; ++b) {
dfdv[a][b] /= delta;
}
@@ -1165,44 +1165,44 @@ bool BPH_mass_spring_force_spring_bending_angular(Implicit_Data *data, int i, in
float fj[3], fk[3];
float dfj_dxi[3][3], dfj_dxj[3][3], dfk_dxi[3][3], dfk_dxj[3][3], dfk_dxk[3][3];
float dfj_dvi[3][3], dfj_dvj[3][3], dfk_dvi[3][3], dfk_dvj[3][3], dfk_dvk[3][3];
-
+
const float vecnull[3] = {0.0f, 0.0f, 0.0f};
-
+
world_to_root_v3(data, j, goal, target);
-
+
spring_angbend_forces(data, i, j, k, goal, stiffness, damping, k, vecnull, vecnull, fk);
negate_v3_v3(fj, fk); /* counterforce */
-
+
spring_angbend_estimate_dfdx(data, i, j, k, goal, stiffness, damping, i, dfk_dxi);
spring_angbend_estimate_dfdx(data, i, j, k, goal, stiffness, damping, j, dfk_dxj);
spring_angbend_estimate_dfdx(data, i, j, k, goal, stiffness, damping, k, dfk_dxk);
copy_m3_m3(dfj_dxi, dfk_dxi); negate_m3(dfj_dxi);
copy_m3_m3(dfj_dxj, dfk_dxj); negate_m3(dfj_dxj);
-
+
spring_angbend_estimate_dfdv(data, i, j, k, goal, stiffness, damping, i, dfk_dvi);
spring_angbend_estimate_dfdv(data, i, j, k, goal, stiffness, damping, j, dfk_dvj);
spring_angbend_estimate_dfdv(data, i, j, k, goal, stiffness, damping, k, dfk_dvk);
copy_m3_m3(dfj_dvi, dfk_dvi); negate_m3(dfj_dvi);
copy_m3_m3(dfj_dvj, dfk_dvj); negate_m3(dfj_dvj);
-
+
/* add forces and jacobians to the solver data */
-
+
add_v3_v3(data->F.v3(j), fj);
add_v3_v3(data->F.v3(k), fk);
-
+
data->idFdX.add(j, j, dfj_dxj);
data->idFdX.add(k, k, dfk_dxk);
-
+
data->idFdX.add(i, j, dfj_dxi);
data->idFdX.add(j, i, dfj_dxi);
data->idFdX.add(j, k, dfk_dxj);
data->idFdX.add(k, j, dfk_dxj);
data->idFdX.add(i, k, dfk_dxi);
data->idFdX.add(k, i, dfk_dxi);
-
+
data->idFdV.add(j, j, dfj_dvj);
data->idFdV.add(k, k, dfk_dvk);
-
+
data->idFdV.add(i, j, dfj_dvi);
data->idFdV.add(j, i, dfj_dvi);
data->idFdV.add(j, k, dfk_dvj);
@@ -1223,10 +1223,10 @@ bool BPH_mass_spring_force_spring_bending_angular(Implicit_Data *data, int i, in
float fi[3], fj[3], fk[3];
float dfi_dxi[3][3], dfj_dxi[3][3], dfj_dxj[3][3], dfk_dxi[3][3], dfk_dxj[3][3], dfk_dxk[3][3];
float dfdvi[3][3];
-
+
// TESTING
damping = 0.0f;
-
+
zero_v3(fi);
zero_v3(fj);
zero_v3(fk);
@@ -1235,68 +1235,68 @@ bool BPH_mass_spring_force_spring_bending_angular(Implicit_Data *data, int i, in
zero_m3(dfk_dxi);
zero_m3(dfk_dxj);
zero_m3(dfk_dxk);
-
+
/* jacobian of direction vectors */
spring_grad_dir(data, i, j, edge_ij, dir_ij, grad_dir_ij);
spring_grad_dir(data, j, k, edge_jk, dir_jk, grad_dir_jk);
-
+
sub_v3_v3v3(vel_jk, data->V[k], data->V[j]);
-
+
/* bending force */
mul_v3_v3fl(target, dir_ij, restlen);
sub_v3_v3v3(dist, target, edge_jk);
mul_v3_v3fl(fk, dist, stiffness);
-
+
/* damping force */
madd_v3_v3v3fl(vel_jk_ortho, vel_jk, dir_jk, -dot_v3v3(vel_jk, dir_jk));
madd_v3_v3fl(fk, vel_jk_ortho, damping);
-
+
/* XXX this only holds true as long as we assume straight rest shape!
* eventually will become a bit more involved since the opposite segment
* gets its own target, under condition of having equal torque on both sides.
*/
copy_v3_v3(fi, fk);
-
+
/* counterforce on the middle point */
sub_v3_v3(fj, fi);
sub_v3_v3(fj, fk);
-
+
/* === derivatives === */
-
+
madd_m3_m3fl(dfk_dxi, grad_dir_ij, stiffness * restlen);
-
+
madd_m3_m3fl(dfk_dxj, grad_dir_ij, -stiffness * restlen);
madd_m3_m3fl(dfk_dxj, I, stiffness);
-
+
madd_m3_m3fl(dfk_dxk, I, -stiffness);
-
+
copy_m3_m3(dfi_dxi, dfk_dxk);
negate_m3(dfi_dxi);
-
+
/* dfj_dfi == dfi_dfj due to symmetry,
* dfi_dfj == dfk_dfj due to fi == fk
* XXX see comment above on future bent rest shapes
*/
copy_m3_m3(dfj_dxi, dfk_dxj);
-
+
/* dfj_dxj == -(dfi_dxj + dfk_dxj) due to fj == -(fi + fk) */
sub_m3_m3m3(dfj_dxj, dfj_dxj, dfj_dxi);
sub_m3_m3m3(dfj_dxj, dfj_dxj, dfk_dxj);
-
+
/* add forces and jacobians to the solver data */
add_v3_v3(data->F[i], fi);
add_v3_v3(data->F[j], fj);
add_v3_v3(data->F[k], fk);
-
+
add_m3_m3m3(data->dFdX[i].m, data->dFdX[i].m, dfi_dxi);
add_m3_m3m3(data->dFdX[j].m, data->dFdX[j].m, dfj_dxj);
add_m3_m3m3(data->dFdX[k].m, data->dFdX[k].m, dfk_dxk);
-
+
add_m3_m3m3(data->dFdX[block_ij].m, data->dFdX[block_ij].m, dfj_dxi);
add_m3_m3m3(data->dFdX[block_jk].m, data->dFdX[block_jk].m, dfk_dxj);
add_m3_m3m3(data->dFdX[block_ik].m, data->dFdX[block_ik].m, dfk_dxi);
#endif
-
+
return true;
}
@@ -1306,40 +1306,40 @@ bool BPH_mass_spring_force_spring_goal(Implicit_Data *data, int i, const float g
{
float root_goal_x[3], root_goal_v[3], extent[3], length, dir[3], vel[3];
float f[3], dfdx[3][3], dfdv[3][3];
-
+
/* goal is in world space */
world_to_root_v3(data, i, root_goal_x, goal_x);
world_to_root_v3(data, i, root_goal_v, goal_v);
-
+
sub_v3_v3v3(extent, root_goal_x, data->X.v3(i));
sub_v3_v3v3(vel, root_goal_v, data->V.v3(i));
length = normalize_v3_v3(dir, extent);
-
+
if (length > ALMOST_ZERO) {
mul_v3_v3fl(f, dir, stiffness * length);
-
+
// Ascher & Boxman, p.21: Damping only during elonglation
// something wrong with it...
madd_v3_v3fl(f, dir, damping * dot_v3v3(vel, dir));
-
+
dfdx_spring(dfdx, dir, length, 0.0f, stiffness);
dfdv_damp(dfdv, dir, damping);
-
+
add_v3_v3(data->F.v3(i), f);
data->idFdX.add(i, i, dfdx);
data->idFdV.add(i, i, dfdv);
-
+
if (r_f) copy_v3_v3(r_f, f);
if (r_dfdx) copy_m3_m3(r_dfdx, dfdx);
if (r_dfdv) copy_m3_m3(r_dfdv, dfdv);
-
+
return true;
}
else {
if (r_f) zero_v3(r_f);
if (r_dfdx) zero_m3(r_dfdx);
if (r_dfdv) zero_m3(r_dfdv);
-
+
return false;
}
}
diff --git a/source/blender/python/generic/CMakeLists.txt b/source/blender/python/generic/CMakeLists.txt
index 77214322b88..9a5a3fddff0 100644
--- a/source/blender/python/generic/CMakeLists.txt
+++ b/source/blender/python/generic/CMakeLists.txt
@@ -39,12 +39,14 @@ set(SRC
bpy_internal_import.c
bpy_threads.c
idprop_py_api.c
+ imbuf_py_api.c
py_capi_utils.c
bgl.h
blf_py_api.h
bpy_internal_import.h
idprop_py_api.h
+ imbuf_py_api.h
py_capi_utils.h
# header-only
diff --git a/source/blender/python/generic/imbuf_py_api.c b/source/blender/python/generic/imbuf_py_api.c
new file mode 100644
index 00000000000..2e32829bf6c
--- /dev/null
+++ b/source/blender/python/generic/imbuf_py_api.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.
+ *
+ * Contributor(s): Campbell Barton
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/python/generic/imbuf_py_api.c
+ * \ingroup pygen
+ *
+ * This file defines the 'imbuf' image manipulation module.
+ */
+
+#include <Python.h>
+
+#include "BLI_utildefines.h"
+#include "BLI_string.h"
+
+#include "py_capi_utils.h"
+
+#include "python_utildefines.h"
+
+#include "imbuf_py_api.h" /* own include */
+
+#include "../../imbuf/IMB_imbuf.h"
+#include "../../imbuf/IMB_imbuf_types.h"
+
+/* File IO */
+#include <fcntl.h>
+#include <errno.h>
+#include "BLI_fileops.h"
+
+/* -------------------------------------------------------------------- */
+/** \name Type & Utilities
+ * \{ */
+
+typedef struct Py_ImBuf {
+ PyObject_VAR_HEAD
+ /* can be NULL */
+ ImBuf *ibuf;
+} Py_ImBuf;
+
+static int py_imbuf_valid_check(Py_ImBuf *self)
+{
+ if (LIKELY(self->ibuf)) {
+ return 0;
+ }
+ else {
+ PyErr_Format(PyExc_ReferenceError,
+ "ImBuf data of type %.200s has been freed",
+ Py_TYPE(self)->tp_name);
+ return -1;
+ }
+}
+
+#define PY_IMBUF_CHECK_OBJ(obj) \
+ if (UNLIKELY(py_imbuf_valid_check(obj) == -1)) { return NULL; } ((void)0)
+#define PY_IMBUF_CHECK_INT(obj) \
+ if (UNLIKELY(py_imbuf_valid_check(obj) == -1)) { return -1; } ((void)0)
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Methods
+ * \{ */
+
+PyDoc_STRVAR(py_imbuf_resize_doc,
+".. method:: resize(size, method='FAST')\n"
+"\n"
+" Resize the image.\n"
+"\n"
+" :arg size: New size.\n"
+" :type size: pair of ints\n"
+" :arg method: Method of resizing (TODO)\n"
+" :type method: str\n"
+);
+static PyObject *py_imbuf_resize(Py_ImBuf *self, PyObject *args, PyObject *kw)
+{
+ PY_IMBUF_CHECK_OBJ(self);
+
+ uint size[2];
+ char *method = NULL;
+
+ static const char *_keywords[] = {"size", "method", NULL};
+ static _PyArg_Parser _parser = {"(II)|s:resize", _keywords, 0};
+ if (!_PyArg_ParseTupleAndKeywordsFast(
+ args, kw, &_parser,
+ &size[0], &size[1],
+ &method))
+ {
+ return NULL;
+ }
+ IMB_scaleImBuf(self->ibuf, UNPACK2(size));
+ Py_RETURN_NONE;
+}
+
+PyDoc_STRVAR(py_imbuf_free_doc,
+".. method:: free()\n"
+"\n"
+" Clear image data immediately (causing an error on re-use).\n"
+);
+static PyObject *py_imbuf_free(Py_ImBuf *self)
+{
+ if (self->ibuf) {
+ IMB_freeImBuf(self->ibuf);
+ self->ibuf = NULL;
+ }
+ Py_RETURN_NONE;
+}
+
+static struct PyMethodDef Py_ImBuf_methods[] = {
+ {"resize", (PyCFunction)py_imbuf_resize, METH_VARARGS | METH_KEYWORDS, (char *)py_imbuf_resize_doc},
+ {"free", (PyCFunction)py_imbuf_free, METH_NOARGS, (char *)py_imbuf_free_doc},
+ {NULL, NULL, 0, NULL}
+};
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Attributes
+ * \{ */
+
+PyDoc_STRVAR(py_imbuf_size_doc,
+"size of the image in pixels.\n\n:type: pair of ints"
+);
+static PyObject *py_imbuf_size_get(Py_ImBuf *self, void *UNUSED(closure))
+{
+ PY_IMBUF_CHECK_OBJ(self);
+ ImBuf *ibuf = self->ibuf;
+ return PyC_Tuple_Pack_I32(ibuf->x, ibuf->y);
+}
+
+PyDoc_STRVAR(py_imbuf_ppm_doc,
+"pixels per meter.\n\n:type: pair of floats"
+);
+static PyObject *py_imbuf_ppm_get(Py_ImBuf *self, void *UNUSED(closure))
+{
+ PY_IMBUF_CHECK_OBJ(self);
+ ImBuf *ibuf = self->ibuf;
+ return PyC_Tuple_Pack_F64(ibuf->ppm[0], ibuf->ppm[1]);
+}
+
+static int py_imbuf_ppm_set(Py_ImBuf *self, PyObject *value, void *UNUSED(closure))
+{
+ PY_IMBUF_CHECK_INT(self);
+ double ppm[2];
+
+ if (PyC_AsArray(ppm, value, 2, &PyFloat_Type, true, "ppm") == -1) {
+ return -1;
+ }
+
+ if (ppm[0] <= 0.0 || ppm[1] <= 0.0) {
+ PyErr_SetString(PyExc_ValueError, "invalid ppm value");
+ return -1;
+ }
+
+ ImBuf *ibuf = self->ibuf;
+ ibuf->ppm[0] = ppm[0];
+ ibuf->ppm[1] = ppm[1];
+ return 0;
+}
+
+static PyGetSetDef Py_ImBuf_getseters[] = {
+ {(char *)"size", (getter)py_imbuf_size_get, (setter)NULL, (char *)py_imbuf_size_doc, NULL},
+ {(char *)"ppm", (getter)py_imbuf_ppm_get, (setter)py_imbuf_ppm_set, (char *)py_imbuf_ppm_doc, NULL},
+ {NULL, NULL, NULL, NULL, NULL} /* Sentinel */
+};
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Type & Implementation
+ * \{ */
+
+static void py_imbuf_dealloc(Py_ImBuf *self)
+{
+ ImBuf *ibuf = self->ibuf;
+ if (ibuf != NULL) {
+ IMB_freeImBuf(self->ibuf);
+ self->ibuf = NULL;
+ }
+ PyObject_DEL(self);
+}
+
+static PyObject *py_imbuf_repr(Py_ImBuf *self)
+{
+ const ImBuf *ibuf = self->ibuf;
+ if (ibuf != NULL) {
+ return PyUnicode_FromFormat(
+ "<imbuf: address=%p, filename='%s', size=(%d, %d)>",
+ ibuf, ibuf->name, ibuf->x, ibuf->y);
+ }
+ else {
+ return PyUnicode_FromString(
+ "<imbuf: address=0x0>");
+ }
+}
+
+static Py_hash_t py_imbuf_hash(Py_ImBuf *self)
+{
+ return _Py_HashPointer(self->ibuf);
+}
+
+PyTypeObject Py_ImBuf_Type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ /* For printing, in format "<module>.<name>" */
+ "ImBuf", /* tp_name */
+ sizeof(Py_ImBuf), /* int tp_basicsize; */
+ 0, /* tp_itemsize; For allocation */
+
+ /* Methods to implement standard operations */
+
+ (destructor)py_imbuf_dealloc, /* destructor tp_dealloc; */
+ NULL, /* printfunc tp_print; */
+ NULL, /* getattrfunc tp_getattr; */
+ NULL, /* setattrfunc tp_setattr; */
+ NULL, /* cmpfunc tp_compare; */
+ (reprfunc)py_imbuf_repr, /* reprfunc tp_repr; */
+
+ /* Method suites for standard classes */
+
+ NULL, /* PyNumberMethods *tp_as_number; */
+ NULL, /* PySequenceMethods *tp_as_sequence; */
+ NULL, /* PyMappingMethods *tp_as_mapping; */
+
+ /* More standard operations (here for binary compatibility) */
+
+ (hashfunc)py_imbuf_hash, /* hashfunc tp_hash; */
+ NULL, /* ternaryfunc tp_call; */
+ NULL, /* reprfunc tp_str; */
+ NULL, /* getattrofunc tp_getattro; */
+ NULL, /* setattrofunc tp_setattro; */
+
+ /* Functions to access object as input/output buffer */
+ NULL, /* PyBufferProcs *tp_as_buffer; */
+
+ /*** Flags to define presence of optional/expanded features ***/
+ Py_TPFLAGS_DEFAULT, /* long tp_flags; */
+
+ NULL, /* char *tp_doc; Documentation string */
+ /*** Assigned meaning in release 2.0 ***/
+ /* call function for all accessible objects */
+ NULL, /* traverseproc tp_traverse; */
+
+ /* delete references to contained objects */
+ NULL, /* inquiry tp_clear; */
+
+ /*** Assigned meaning in release 2.1 ***/
+ /*** rich comparisons ***/
+ NULL, /* richcmpfunc tp_richcompare; */
+
+ /*** weak reference enabler ***/
+ 0, /* long tp_weaklistoffset; */
+
+ /*** Added in release 2.2 ***/
+ /* Iterators */
+ NULL, /* getiterfunc tp_iter; */
+ NULL, /* iternextfunc tp_iternext; */
+ /*** Attribute descriptor and subclassing stuff ***/
+ Py_ImBuf_methods, /* struct PyMethodDef *tp_methods; */
+ NULL, /* struct PyMemberDef *tp_members; */
+ Py_ImBuf_getseters, /* struct PyGetSetDef *tp_getset; */
+};
+
+static PyObject *Py_ImBuf_CreatePyObject(ImBuf *ibuf)
+{
+ Py_ImBuf *self = PyObject_New(Py_ImBuf, &Py_ImBuf_Type);
+ self->ibuf = ibuf;
+ return (PyObject *)self;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Module Functions
+ * \{ */
+
+PyDoc_STRVAR(M_imbuf_new_doc,
+".. function:: new(size)\n"
+"\n"
+" Load a new image.\n"
+"\n"
+" :arg size: The size of the image in pixels.\n"
+" :type size: pair of ints\n"
+" :return: the newly loaded image.\n"
+" :rtype: :class:`ImBuf`\n"
+);
+static PyObject *M_imbuf_new(PyObject *UNUSED(self), PyObject *args, PyObject *kw)
+{
+ int size[2];
+ static const char *_keywords[] = {"size", NULL};
+ static _PyArg_Parser _parser = {"(ii)|i:new", _keywords, 0};
+ if (!_PyArg_ParseTupleAndKeywordsFast(
+ args, kw, &_parser,
+ &size[0], &size[1]))
+ {
+ return NULL;
+ }
+
+ /* TODO, make options */
+ uchar planes = 4;
+ uint flags = IB_rect;
+
+ ImBuf *ibuf = IMB_allocImBuf(UNPACK2(size), planes, flags);
+ if (ibuf == NULL) {
+ PyErr_Format(PyExc_ValueError, "new: Unable to create image (%d, %d)", UNPACK2(size));
+ return NULL;
+ }
+ return Py_ImBuf_CreatePyObject(ibuf);
+}
+
+PyDoc_STRVAR(M_imbuf_load_doc,
+".. function:: load(filename)\n"
+"\n"
+" Load an image from a file.\n"
+"\n"
+" :arg filename: the filename of the image.\n"
+" :type filename: string\n"
+" :return: the newly loaded image.\n"
+" :rtype: :class:`ImBuf`\n"
+);
+static PyObject *M_imbuf_load(PyObject *UNUSED(self), PyObject *args, PyObject *kw)
+{
+ const char *filename;
+
+ static const char *_keywords[] = {"filename", NULL};
+ static _PyArg_Parser _parser = {"s:load", _keywords, 0};
+ if (!_PyArg_ParseTupleAndKeywordsFast(
+ args, kw, &_parser,
+ &filename))
+ {
+ return NULL;
+ }
+
+ const int file = BLI_open(filename, O_BINARY | O_RDONLY, 0);
+ if (file == -1) {
+ PyErr_Format(PyExc_IOError, "load: %s, failed to open file '%s'", strerror(errno));
+ return NULL;
+ }
+
+ ImBuf *ibuf = IMB_loadifffile(file, filename, IB_rect, NULL, filename);
+
+ close(file);
+
+ if (ibuf == NULL) {
+ PyErr_Format(PyExc_ValueError, "load: Unable to recognize image format for file '%s'", filename);
+ return NULL;
+ }
+
+ BLI_strncpy(ibuf->name, filename, sizeof(ibuf->name));
+
+ return Py_ImBuf_CreatePyObject(ibuf);
+}
+
+PyDoc_STRVAR(M_imbuf_write_doc,
+".. function:: write(image, filename)\n"
+"\n"
+" Write an image.\n"
+"\n"
+" :arg image: the image to write.\n"
+" :type image: :class:`ImBuf`\n"
+" :arg filename: the filename of the image.\n"
+" :type filename: string\n"
+);
+static PyObject *M_imbuf_write(PyObject *UNUSED(self), PyObject *args, PyObject *kw)
+{
+ Py_ImBuf *py_imb;
+ const char *filename = NULL;
+
+ static const char *_keywords[] = {"image", "filename", NULL};
+ static _PyArg_Parser _parser = {"O!|s:write", _keywords, 0};
+ if (!_PyArg_ParseTupleAndKeywordsFast(
+ args, kw, &_parser,
+ &Py_ImBuf_Type, &py_imb,
+ &filename))
+ {
+ return NULL;
+ }
+
+ if (filename == NULL) {
+ filename = py_imb->ibuf->name;
+ }
+
+ bool ok = IMB_saveiff(py_imb->ibuf, filename, IB_rect);
+ if (ok == false) {
+ PyErr_Format(PyExc_IOError, "write: Unable to write image file (%s) '%s'", strerror(errno), filename);
+ return NULL;
+ }
+
+ Py_RETURN_NONE;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Module Definition
+ * \{ */
+
+static PyMethodDef IMB_methods[] = {
+ {"new", (PyCFunction) M_imbuf_new, METH_VARARGS | METH_KEYWORDS, M_imbuf_new_doc},
+ {"load", (PyCFunction) M_imbuf_load, METH_VARARGS | METH_KEYWORDS, M_imbuf_load_doc},
+ {"write", (PyCFunction) M_imbuf_write, METH_VARARGS | METH_KEYWORDS, M_imbuf_write_doc},
+ {NULL, NULL, 0, NULL}
+};
+
+PyDoc_STRVAR(IMB_doc,
+"This module provides access to Blender's image manipulation API."
+);
+static struct PyModuleDef IMB_module_def = {
+ PyModuleDef_HEAD_INIT,
+ "imbuf", /* m_name */
+ IMB_doc, /* m_doc */
+ 0, /* m_size */
+ IMB_methods, /* m_methods */
+ NULL, /* m_reload */
+ NULL, /* m_traverse */
+ NULL, /* m_clear */
+ NULL, /* m_free */
+};
+
+PyObject *BPyInit_imbuf(void)
+{
+ PyObject *submodule;
+
+ submodule = PyModule_Create(&IMB_module_def);
+
+ PyType_Ready(&Py_ImBuf_Type);
+
+ return submodule;
+}
+
+/** \} */
diff --git a/source/blender/python/generic/imbuf_py_api.h b/source/blender/python/generic/imbuf_py_api.h
new file mode 100644
index 00000000000..92c1732a9c9
--- /dev/null
+++ b/source/blender/python/generic/imbuf_py_api.h
@@ -0,0 +1,30 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __IMBUF_PY_API_H__
+#define __IMBUF_PY_API_H__
+
+/** \file blender/python/generic/imbuf_py_api.h
+ * \ingroup pygen
+ */
+
+PyObject *BPyInit_imbuf(void);
+
+#endif /* __IMBUF_PY_API_H__ */
diff --git a/source/blender/python/intern/bpy_interface.c b/source/blender/python/intern/bpy_interface.c
index d0678911c0e..5f51f2ac152 100644
--- a/source/blender/python/intern/bpy_interface.c
+++ b/source/blender/python/intern/bpy_interface.c
@@ -74,6 +74,7 @@
#include "../generic/bgl.h"
#include "../generic/blf_py_api.h"
#include "../generic/idprop_py_api.h"
+#include "../generic/imbuf_py_api.h"
#include "../gawain/gwn_py_api.h"
#include "../bmesh/bmesh_py_api.h"
#include "../mathutils/mathutils.h"
@@ -221,6 +222,7 @@ static struct _inittab bpy_internal_modules[] = {
{"_gawain", BPyInit_gawain},
{"bgl", BPyInit_bgl},
{"blf", BPyInit_blf},
+ {"imbuf", BPyInit_imbuf},
{"bmesh", BPyInit_bmesh},
#if 0
{"bmesh.types", BPyInit_bmesh_types},
@@ -730,7 +732,7 @@ void BPY_modules_load_user(bContext *C)
G.f |= G_SCRIPT_AUTOEXEC_FAIL;
BLI_snprintf(G.autoexec_fail, sizeof(G.autoexec_fail), "Text '%s'", text->id.name + 2);
- printf("scripts disabled for \"%s\", skipping '%s'\n", bmain->name, text->id.name + 2);
+ printf("scripts disabled for \"%s\", skipping '%s'\n", BKE_main_blendfile_path(bmain), text->id.name + 2);
}
}
else {
diff --git a/source/blender/python/intern/bpy_library_load.c b/source/blender/python/intern/bpy_library_load.c
index 0ca46f9b20e..d60c44e702a 100644
--- a/source/blender/python/intern/bpy_library_load.c
+++ b/source/blender/python/intern/bpy_library_load.c
@@ -205,7 +205,7 @@ static PyObject *bpy_lib_load(PyObject *UNUSED(self), PyObject *args, PyObject *
BLI_strncpy(ret->relpath, filename, sizeof(ret->relpath));
BLI_strncpy(ret->abspath, filename, sizeof(ret->abspath));
- BLI_path_abs(ret->abspath, bmain->name);
+ BLI_path_abs(ret->abspath, BKE_main_blendfile_path(bmain));
ret->blo_handle = NULL;
ret->flag = ((is_link ? FILE_LINK : 0) |
diff --git a/source/blender/python/intern/bpy_library_write.c b/source/blender/python/intern/bpy_library_write.c
index 9ca6092eab3..ead10efb212 100644
--- a/source/blender/python/intern/bpy_library_write.c
+++ b/source/blender/python/intern/bpy_library_write.c
@@ -107,7 +107,7 @@ static PyObject *bpy_lib_write(PyObject *UNUSED(self), PyObject *args, PyObject
}
BLI_strncpy(filepath_abs, filepath, FILE_MAX);
- BLI_path_abs(filepath_abs, G.main->name);
+ BLI_path_abs(filepath_abs, BKE_main_blendfile_path_from_global());
BKE_blendfile_write_partial_begin(bmain_src);
diff --git a/source/blender/python/intern/bpy_rna_anim.c b/source/blender/python/intern/bpy_rna_anim.c
index 192738535b4..7903f92265b 100644
--- a/source/blender/python/intern/bpy_rna_anim.c
+++ b/source/blender/python/intern/bpy_rna_anim.c
@@ -40,11 +40,12 @@
#include "ED_keyframing.h"
#include "ED_keyframes_edit.h"
-#include "BKE_report.h"
-#include "BKE_context.h"
#include "BKE_animsys.h"
+#include "BKE_context.h"
#include "BKE_fcurve.h"
+#include "BKE_global.h"
#include "BKE_idcode.h"
+#include "BKE_report.h"
#include "RNA_access.h"
#include "RNA_enum_types.h"
@@ -272,7 +273,7 @@ PyObject *pyrna_struct_keyframe_insert(BPy_StructRNA *self, PyObject *args, PyOb
BKE_reports_init(&reports, RPT_STORE);
- result = insert_keyframe(depsgraph, &reports, (ID *)self->ptr.id.data, NULL, group_name, path_full, index, cfra, keytype, options);
+ result = insert_keyframe(G.main, depsgraph, &reports, (ID *)self->ptr.id.data, NULL, group_name, path_full, index, cfra, keytype, options);
MEM_freeN((void *)path_full);
if (BPy_reports_to_error(&reports, PyExc_RuntimeError, true) == -1)
diff --git a/source/blender/python/intern/gpu_offscreen.c b/source/blender/python/intern/gpu_offscreen.c
index a8ec828c13f..a65469ea739 100644
--- a/source/blender/python/intern/gpu_offscreen.c
+++ b/source/blender/python/intern/gpu_offscreen.c
@@ -35,6 +35,8 @@
#include "WM_types.h"
+#include "BKE_global.h"
+
#include "ED_screen.h"
#include "GPU_framebuffer.h"
diff --git a/source/blender/render/CMakeLists.txt b/source/blender/render/CMakeLists.txt
index 0f0060c7578..359369228f8 100644
--- a/source/blender/render/CMakeLists.txt
+++ b/source/blender/render/CMakeLists.txt
@@ -24,7 +24,7 @@
# ***** END GPL LICENSE BLOCK *****
-set(INC
+set(INC
extern/include
intern/include
../blenkernel
diff --git a/source/blender/render/extern/include/RE_pipeline.h b/source/blender/render/extern/include/RE_pipeline.h
index 1b0707bafc0..660e81eb022 100644
--- a/source/blender/render/extern/include/RE_pipeline.h
+++ b/source/blender/render/extern/include/RE_pipeline.h
@@ -103,11 +103,11 @@ typedef struct RenderPass {
/* 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;
-
+
/* copy of RenderData */
char name[RE_MAXNAME];
int layflag, passflag, pass_xor;
-
+
/* MULTIVIEW_TODO: acolrect and scolrect are not supported by multiview at the moment.
* If they are really required they should be in RenderView instead */
@@ -121,16 +121,16 @@ typedef struct RenderLayer {
void *exrhandle;
ListBase passes;
-
+
} RenderLayer;
typedef struct RenderResult {
struct RenderResult *next, *prev;
-
+
/* target image size */
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 */
@@ -140,25 +140,25 @@ typedef struct RenderResult {
float *rectf;
/* if this exists, a copy of one of layers, or result of composited layers */
float *rectz;
-
+
/* coordinates within final image (after cropping) */
rcti tilerect;
/* offset to apply to get a border render in full image */
int xof, yof;
-
+
/* the main buffers */
ListBase layers;
-
+
/* multiView maps to a StringVector in OpenEXR */
ListBase views; /* RenderView */
/* allowing live updates: */
volatile rcti renrect;
volatile RenderLayer *renlay;
-
+
/* optional saved endresult on disk */
int do_exr_tile;
-
+
/* for render results in Image, verify validity for sequences */
int framenr;
diff --git a/source/blender/render/intern/include/envmap.h b/source/blender/render/intern/include/envmap.h
new file mode 100644
index 00000000000..c66427ae788
--- /dev/null
+++ b/source/blender/render/intern/include/envmap.h
@@ -0,0 +1,54 @@
+/*
+ * envmap_ext.h
+ *
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/render/intern/include/envmap.h
+ * \ingroup render
+ */
+
+
+#ifndef __ENVMAP_H__
+#define __ENVMAP_H__
+
+/**
+ * Make environment maps for all objects in the scene that have an
+ * environment map as texture.
+ * (initrender.c)
+ */
+
+struct Render;
+struct TexResult;
+struct ImagePool;
+
+void make_envmaps(struct Render *re);
+int envmaptex(struct Tex *tex, const float texvec[3], float dxt[3], float dyt[3], int osatex, struct TexResult *texres, struct ImagePool *pool, const bool skip_image_load);
+void env_rotate_scene(struct Render *re, float mat[4][4], int do_rotate);
+
+#endif /* __ENVMAP_H__ */
+
diff --git a/source/blender/render/intern/include/initrender.h b/source/blender/render/intern/include/initrender.h
index e7ff3c7097c..b8732e7cc5c 100644
--- a/source/blender/render/intern/include/initrender.h
+++ b/source/blender/render/intern/include/initrender.h
@@ -31,7 +31,7 @@
#ifndef __INITRENDER_H__
-#define __INITRENDER_H__
+#define __INITRENDER_H__
/* Functions */
diff --git a/source/blender/render/intern/include/pixelblending.h b/source/blender/render/intern/include/pixelblending.h
new file mode 100644
index 00000000000..022510c7132
--- /dev/null
+++ b/source/blender/render/intern/include/pixelblending.h
@@ -0,0 +1,65 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * Contributor(s): 2004-2006 Blender Foundation, full recode
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+/** \file blender/render/intern/include/pixelblending.h
+ * \ingroup render
+ */
+
+
+#ifndef __PIXELBLENDING_H__
+#define __PIXELBLENDING_H__
+
+
+/**
+ * add 1 pixel to into filtered three lines
+ * (float vecs to float vec)
+ */
+void add_filt_fmask(unsigned int mask, const float col[4], float *rowbuf, int row_w);
+void add_filt_fmask_pixsize(unsigned int mask, float *in, float *rowbuf, int row_w, int pixsize);
+void add_filt_fmask_coord(float filt[3][3], const float col[4], float *rowbuf, int row_stride, int x, int y, rcti *mask);
+void mask_array(unsigned int mask, float filt[3][3]);
+
+/**
+ * Alpha-over blending for floats.
+ */
+void addAlphaOverFloat(float dest[4], const float source[4]);
+
+/**
+ * Alpha-under blending for floats.
+ */
+void addAlphaUnderFloat(float dest[4], const float source[4]);
+
+
+/**
+ * Same for floats
+ */
+void addalphaAddfacFloat(float dest[4], const float source[4], char addfac);
+
+/**
+ * dest = dest + source
+ */
+void addalphaAddFloat(float dest[4], const float source[4]);
+
+#endif /* __PIXELBLENDING_H__ */
diff --git a/source/blender/render/intern/include/pixelshading.h b/source/blender/render/intern/include/pixelshading.h
new file mode 100644
index 00000000000..0e630eda475
--- /dev/null
+++ b/source/blender/render/intern/include/pixelshading.h
@@ -0,0 +1,62 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * Contributor(s): 2004-2006, Blender Foundation, full recode
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/render/intern/include/pixelshading.h
+ * \ingroup render
+ *
+ * These functions determine what actual color a pixel will have.
+ */
+
+#ifndef __PIXELSHADING_H__
+#define __PIXELSHADING_H__
+
+
+/**
+ * Render the pixel at (x,y) for object ap. Apply the jitter mask.
+ * Output is given in float collector[4]. The type vector:
+ * t[0] - min. distance
+ * t[1] - face/halo index
+ * t[2] - jitter mask
+ * t[3] - type ZB_POLY or ZB_HALO
+ * t[4] - max. distance
+ * mask is pixel coverage in bits
+ * \return pointer to the object
+ */
+int shadeHaloFloat(HaloRen *har,
+ float *col, int zz,
+ float dist, float xn,
+ float yn, short flarec);
+
+/**
+ * Render the sky at pixel (x, y).
+ */
+void shadeSkyPixel(float collector[4], float fx, float fy, short thread);
+void shadeSkyView(float col_r[3], const float rco[3], const float view[3], const float dxyview[2], short thread);
+void shadeAtmPixel(struct SunSky *sunsky, float *collector, float fx, float fy, float distance);
+void shadeSunView(float col_r[3], const float view[3]);
+/* ------------------------------------------------------------------------- */
+
+#endif
+
diff --git a/source/blender/render/intern/include/pointdensity.h b/source/blender/render/intern/include/pointdensity.h
new file mode 100644
index 00000000000..eadf714c1ba
--- /dev/null
+++ b/source/blender/render/intern/include/pointdensity.h
@@ -0,0 +1,51 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): Matt Ebb
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/render/intern/include/pointdensity.h
+ * \ingroup render
+ */
+
+
+#ifndef __POINTDENSITY_H__
+#define __POINTDENSITY_H__
+
+/**
+ * Make point density kd-trees for all point density textures in the scene
+ */
+
+struct PointDensity;
+struct Render;
+struct TexResult;
+
+void free_pointdensity(struct PointDensity *pd);
+void cache_pointdensity(struct Render *re, struct PointDensity *pd);
+void make_pointdensities(struct Render *re);
+void free_pointdensities(struct Render *re);
+int pointdensitytex(struct Tex *tex, const float texvec[3], struct TexResult *texres);
+
+#endif /* __POINTDENSITY_H__ */
+
diff --git a/source/blender/render/intern/include/raycounter.h b/source/blender/render/intern/include/raycounter.h
new file mode 100644
index 00000000000..e16c6e13c7e
--- /dev/null
+++ b/source/blender/render/intern/include/raycounter.h
@@ -0,0 +1,74 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2009 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): André Pinto.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/render/intern/include/raycounter.h
+ * \ingroup render
+ */
+
+
+#ifndef __RAYCOUNTER_H__
+#define __RAYCOUNTER_H__
+
+//#define RE_RAYCOUNTER /* enable counters per ray, useful for measuring raytrace structures performance */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef RE_RAYCOUNTER
+
+/* ray counter functions */
+
+typedef struct RayCounter {
+ struct {
+ unsigned long long test, hit;
+ } faces, bb, simd_bb, raycast, raytrace_hint, rayshadow_last_hit;
+} RayCounter;
+
+#define RE_RC_INIT(isec, shi) (isec).raycounter = &((shi).shading.raycounter)
+void RE_RC_INFO(RayCounter *rc);
+void RE_RC_MERGE(RayCounter *rc, RayCounter *tmp);
+#define RE_RC_COUNT(var) (var)++
+
+extern RayCounter re_rc_counter[];
+
+#else
+
+/* ray counter stubs */
+
+#define RE_RC_INIT(isec,shi)
+#define RE_RC_INFO(rc)
+#define RE_RC_MERGE(dest,src)
+#define RE_RC_COUNT(var)
+
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/source/blender/render/intern/include/rayintersection.h b/source/blender/render/intern/include/rayintersection.h
new file mode 100644
index 00000000000..a303301ad3b
--- /dev/null
+++ b/source/blender/render/intern/include/rayintersection.h
@@ -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) 2007 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): André Pinto.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ * RE_raytrace.h: ray tracing api, can be used independently from the renderer.
+ */
+
+/** \file blender/render/intern/include/rayintersection.h
+ * \ingroup render
+ */
+
+
+#ifndef __RAYINTERSECTION_H__
+#define __RAYINTERSECTION_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "BLI_math_geom.h"
+
+struct RayObject;
+
+/* Ray Hints */
+
+#define RE_RAY_LCTS_MAX_SIZE 256
+#define RT_USE_LAST_HIT /* last shadow hit is reused before raycasting on whole tree */
+//#define RT_USE_HINT /* last hit object is reused before raycasting on whole tree */
+
+typedef struct LCTSHint {
+ int size;
+ struct RayObject *stack[RE_RAY_LCTS_MAX_SIZE];
+} LCTSHint;
+
+typedef struct RayHint {
+ union { LCTSHint lcts; } data;
+} RayHint;
+
+/* Ray Intersection */
+
+typedef struct Isect {
+ /* ray start, direction (normalized vector), and max distance. on hit,
+ * the distance is modified to be the distance to the hit point. */
+ float start[3];
+ float dir[3];
+ float dist;
+
+ /* for envmap and incremental view update renders */
+ float origstart[3];
+ float origdir[3];
+
+ /* precomputed values to accelerate bounding box intersection */
+ int bv_index[6];
+ float idot_axis[3];
+
+ /* intersection options */
+ int mode; /* RE_RAY_SHADOW, RE_RAY_MIRROR, RE_RAY_SHADOW_TRA */
+ int lay; /* -1 default, set for layer lamps */
+ int skip; /* skip flags */
+ int check; /* check flags */
+ void *userdata; /* used by bake check */
+
+ /* hit information */
+ float u, v;
+ int isect; /* which half of quad */
+
+ struct {
+ void *ob;
+ void *face;
+ } hit, orig;
+
+ /* last hit optimization */
+ struct RayObject *last_hit;
+
+ /* hints */
+#ifdef RT_USE_HINT
+ RayTraceHint *hint, *hit_hint;
+#endif
+ RayHint *hint;
+
+ /* ray counter */
+#ifdef RE_RAYCOUNTER
+ RayCounter *raycounter;
+#endif
+
+ /* Precalculated coefficients for watertight intersection check. */
+ struct IsectRayPrecalc isect_precalc;
+} Isect;
+
+/* ray types */
+#define RE_RAY_SHADOW 0
+#define RE_RAY_MIRROR 1
+#define RE_RAY_SHADOW_TRA 2
+
+/* skip options */
+#define RE_SKIP_CULLFACE (1 << 0)
+/* if using this flag then *face should be a pointer to a VlakRen */
+#define RE_SKIP_VLR_NEIGHBOUR (1 << 1)
+
+/* check options */
+#define RE_CHECK_VLR_NONE 0
+#define RE_CHECK_VLR_RENDER 1
+#define RE_CHECK_VLR_NON_SOLID_MATERIAL 2
+#define RE_CHECK_VLR_BAKE 3
+
+/* arbitrary, but can't use e.g. FLT_MAX because of precision issues */
+#define RE_RAYTRACE_MAXDIST 1e15f
+#define RE_RAYTRACE_EPSILON 0.0f
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __RAYINTERSECTION_H__ */
+
diff --git a/source/blender/render/intern/include/render_types.h b/source/blender/render/intern/include/render_types.h
index 8308b5e76e4..fd24f4eb053 100644
--- a/source/blender/render/intern/include/render_types.h
+++ b/source/blender/render/intern/include/render_types.h
@@ -52,10 +52,10 @@ struct Main;
/* this is handed over to threaded hiding/passes/shading engine */
typedef struct RenderPart {
struct RenderPart *next, *prev;
-
+
RenderResult *result; /* result of part rendering */
ListBase fullresult; /* optional full sample buffers */
-
+
rcti disprect; /* part coordinates within total picture */
int rectx, recty; /* the size */
int nr; /* nr is partnr */
@@ -74,10 +74,10 @@ struct Render {
struct Render *next, *prev;
char name[RE_MAXNAME];
int slot;
-
+
/* state settings */
short flag, ok, result_ok;
-
+
/* result of rendering */
RenderResult *result;
/* if render with single-layer option, other rendered layers are stored here */
@@ -88,29 +88,29 @@ struct Render {
* write lock, all external code must use a read lock. internal code is assumed
* to not conflict with writes, so no lock used for that */
ThreadRWMutex resultmutex;
-
+
/* window size, display rect, viewplane */
int winx, winy; /* buffer width and height with percentage applied
* without border & crop. convert to long before multiplying together to avoid overflow. */
rcti disprect; /* part within winx winy */
rctf viewplane; /* mapped on winx winy */
-
+
/* final picture width and height (within disprect) */
int rectx, recty;
-
- /* real maximum size of parts after correction for minimum
+
+ /* real maximum size of parts after correction for minimum
* partx*xparts can be larger than rectx, in that case last part is smaller */
int partx, party;
-
+
/* Camera transform, only used by Freestyle. */
float viewmat[4][4], viewinv[4][4];
float viewmat_orig[4][4]; /* for incremental render */
float winmat[4][4];
-
+
/* clippping */
float clipsta;
float clipend;
-
+
/* main, scene, and its full copy of renderdata and world */
struct Main *main;
Scene *scene;
@@ -119,13 +119,13 @@ struct Render {
int active_view_layer;
struct Object *camera_override;
unsigned int lay, layer_override;
-
+
ThreadRWMutex partsmutex;
ListBase parts;
-
+
/* render engine */
struct RenderEngine *engine;
-
+
#ifdef WITH_FREESTYLE
struct Main *freestyle_bmain;
ListBase freestyle_renders;
@@ -140,17 +140,17 @@ struct Render {
void *duh;
void (*current_scene_update)(void *handle, struct Scene *scene);
void *suh;
-
+
void (*stats_draw)(void *handle, RenderStats *ri);
void *sdh;
void (*progress)(void *handle, float i);
void *prh;
-
+
void (*draw_lock)(void *handle, int i);
void *dlh;
int (*test_break)(void *handle);
void *tbh;
-
+
RenderStats i;
struct ReportList *reports;
diff --git a/source/blender/render/intern/include/rendercore.h b/source/blender/render/intern/include/rendercore.h
new file mode 100644
index 00000000000..aa3efca9e5b
--- /dev/null
+++ b/source/blender/render/intern/include/rendercore.h
@@ -0,0 +1,105 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __RENDERCORE_H__
+#define __RENDERCORE_H__
+
+/** \file blender/render/intern/include/rendercore.h
+ * \ingroup render
+ */
+
+#include "render_types.h"
+
+#include "RE_engine.h"
+
+#include "DNA_node_types.h"
+
+#include "NOD_composite.h"
+
+struct ShadeInput;
+struct ShadeResult;
+struct World;
+struct RenderPart;
+struct RenderLayer;
+struct RayObject;
+
+/* ------------------------------------------------------------------------- */
+
+typedef struct PixStr {
+ struct PixStr *next;
+ int obi, facenr, z, maskz;
+ unsigned short mask;
+ short shadfac;
+} PixStr;
+
+typedef struct PixStrMain {
+ struct PixStrMain *next, *prev;
+ struct PixStr *ps;
+ int counter;
+} PixStrMain;
+
+/* ------------------------------------------------------------------------- */
+
+
+void calc_view_vector(float view[3], float x, float y);
+float mistfactor(float zcor, const float co[3]); /* dist and height, return alpha */
+
+void renderspothalo(struct ShadeInput *shi, float col[4], float alpha);
+void add_halo_flare(Render *re);
+
+void calc_renderco_zbuf(float co[3], const float view[3], int z);
+void calc_renderco_ortho(float co[3], float x, float y, int z);
+
+int count_mask(unsigned short mask);
+
+void zbufshade_tile(struct RenderPart *pa);
+void zbufshadeDA_tile(struct RenderPart *pa);
+
+void zbufshade_sss_tile(struct RenderPart *pa);
+
+int get_sample_layers(struct RenderPart *pa, struct RenderLayer *rl, struct RenderLayer **rlpp);
+
+void render_internal_update_passes(struct RenderEngine *engine, struct Scene *scene, struct SceneRenderLayer *srl);
+
+
+/* -------- ray.c ------- */
+
+struct RayObject *RE_rayobject_create(int type, int size, int octree_resolution);
+
+extern void freeraytree(Render *re);
+extern void makeraytree(Render *re);
+struct RayObject* makeraytree_object(Render *re, ObjectInstanceRen *obi);
+
+extern void ray_shadow(ShadeInput *shi, LampRen *lar, float shadfac[4]);
+extern void ray_trace(ShadeInput *shi, ShadeResult *);
+extern void ray_ao(ShadeInput *shi, float ao[3], float env[3]);
+extern void init_jitter_plane(LampRen *lar);
+extern void init_ao_sphere(Render *re, struct World *wrld);
+extern void init_render_qmcsampler(Render *re);
+extern void free_render_qmcsampler(Render *re);
+
+#endif /* __RENDERCORE_H__ */
diff --git a/source/blender/render/intern/include/shading.h b/source/blender/render/intern/include/shading.h
new file mode 100644
index 00000000000..e306c3c075c
--- /dev/null
+++ b/source/blender/render/intern/include/shading.h
@@ -0,0 +1,105 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2006 Blender Foundation
+ * All rights reserved.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/render/intern/include/shading.h
+ * \ingroup render
+ */
+
+
+struct ShadeInput;
+struct ShadeResult;
+struct RenderPart;
+struct RenderLayer;
+struct PixStr;
+struct LampRen;
+struct VlakRen;
+struct StrandPoint;
+struct ObjectInstanceRen;
+struct Isect;
+
+/* shadeinput.c */
+
+#define RE_MAX_OSA 16
+
+/* needed to calculate shadow and AO for an entire pixel */
+typedef struct ShadeSample {
+ int tot; /* amount of shi in use, can be 1 for not FULL_OSA */
+
+ RenderLayer *rlpp[RE_MAX_OSA]; /* fast lookup from sample to renderlayer (fullsample buf) */
+
+ /* could be malloced once */
+ ShadeInput shi[RE_MAX_OSA];
+ ShadeResult shr[RE_MAX_OSA];
+} ShadeSample;
+
+
+ /* also the node shader callback */
+void shade_material_loop(struct ShadeInput *shi, struct ShadeResult *shr);
+
+void shade_input_set_triangle_i(struct ShadeInput *shi, struct ObjectInstanceRen *obi, struct VlakRen *vlr, short i1, short i2, short i3);
+void shade_input_set_triangle(struct ShadeInput *shi, int obi, int facenr, int normal_flip);
+void shade_input_copy_triangle(struct ShadeInput *shi, struct ShadeInput *from);
+void shade_input_calc_viewco(struct ShadeInput *shi, float x, float y, float z, float view[3], float dxyview[2], float co[3], float dxco[3], float dyco[3]);
+void shade_input_set_viewco(struct ShadeInput *shi, float x, float y, float sx, float sy, float z);
+void shade_input_set_uv(struct ShadeInput *shi);
+void shade_input_set_normals(struct ShadeInput *shi);
+void shade_input_set_vertex_normals(struct ShadeInput *shi);
+void shade_input_flip_normals(struct ShadeInput *shi);
+void shade_input_set_shade_texco(struct ShadeInput *shi);
+void shade_input_set_strand(struct ShadeInput *shi, struct StrandRen *strand, struct StrandPoint *spoint);
+void shade_input_set_strand_texco(struct ShadeInput *shi, struct StrandRen *strand, struct StrandVert *svert, struct StrandPoint *spoint);
+void shade_input_do_shade(struct ShadeInput *shi, struct ShadeResult *shr);
+
+void shade_input_init_material(struct ShadeInput *shi);
+void shade_input_initialize(struct ShadeInput *shi, struct RenderPart *pa, struct RenderLayer *rl, int sample);
+
+void shade_sample_initialize(struct ShadeSample *ssamp, struct RenderPart *pa, struct RenderLayer *rl);
+void shade_samples_do_AO(struct ShadeSample *ssamp);
+void shade_samples_fill_with_ps(struct ShadeSample *ssamp, struct PixStr *ps, int x, int y);
+int shade_samples(struct ShadeSample *ssamp, struct PixStr *ps, int x, int y);
+
+void vlr_set_uv_indices(struct VlakRen *vlr, int *i1, int *i2, int *i3);
+
+void calc_R_ref(struct ShadeInput *shi);
+
+void barycentric_differentials_from_position(
+ const float co[3], const float v1[3], const float v2[3], const float v3[3],
+ const float dxco[3], const float dyco[3], const float facenor[3], const bool differentials,
+ float *u, float *v, float *dx_u, float *dx_v, float *dy_u, float *dy_v);
+
+/* shadeoutput. */
+void shade_lamp_loop(struct ShadeInput *shi, struct ShadeResult *shr);
+
+void shade_color(struct ShadeInput *shi, ShadeResult *shr);
+
+void ambient_occlusion(struct ShadeInput *shi);
+void environment_lighting_apply(struct ShadeInput *shi, struct ShadeResult *shr);
+
+ListBase *get_lights(struct ShadeInput *shi);
+float lamp_get_visibility(struct LampRen *lar, const float co[3], float lv[3], float *dist);
+void lamp_get_shadow(struct LampRen *lar, ShadeInput *shi, float inp, float shadfac[4], int do_real);
+
+float fresnel_fac(const float view[3], const float vn[3], float fresnel, float fac);
+
+/* rayshade.c */
+extern void shade_ray(struct Isect *is, struct ShadeInput *shi, struct ShadeResult *shr);
diff --git a/source/blender/render/intern/include/strand.h b/source/blender/render/intern/include/strand.h
new file mode 100644
index 00000000000..f4e22c78b42
--- /dev/null
+++ b/source/blender/render/intern/include/strand.h
@@ -0,0 +1,99 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contributor(s): Brecht Van Lommel.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/render/intern/include/strand.h
+ * \ingroup render
+ */
+
+
+#ifndef __STRAND_H__
+#define __STRAND_H__
+
+struct StrandVert;
+struct StrandRen;
+struct StrandBuffer;
+struct ShadeSample;
+struct StrandPart;
+struct Render;
+struct ZSpan;
+struct ObjectInstanceRen;
+struct StrandSurface;
+struct DerivedMesh;
+struct ObjectRen;
+
+typedef struct StrandPoint {
+ /* position within segment */
+ float t;
+
+ /* camera space */
+ float co[3];
+ float nor[3];
+ float tan[3];
+ float strandco;
+ float width;
+
+ /* derivatives */
+ float dtco[3], dsco[3];
+ float dtstrandco;
+
+ /* outer points */
+ float co1[3], co2[3];
+ float hoco1[4], hoco2[4];
+ float zco1[3], zco2[3];
+ int clip1, clip2;
+
+ /* screen space */
+ float hoco[4];
+ float x, y;
+
+ /* simplification */
+ float alpha;
+} StrandPoint;
+
+typedef struct StrandSegment {
+ struct StrandVert *v[4];
+ struct StrandRen *strand;
+ struct StrandBuffer *buffer;
+ struct ObjectInstanceRen *obi;
+ float sqadaptcos;
+
+ StrandPoint point1, point2;
+ int shaded;
+} StrandSegment;
+
+struct StrandShadeCache;
+typedef struct StrandShadeCache StrandShadeCache;
+
+void strand_eval_point(StrandSegment *sseg, StrandPoint *spoint);
+void render_strand_segment(struct Render *re, float winmat[4][4], struct StrandPart *spart, struct ZSpan *zspan, int totzspan, StrandSegment *sseg);
+void strand_minmax(struct StrandRen *strand, float min[3], float max[3], const float width);
+
+struct StrandSurface *cache_strand_surface(struct Render *re, struct ObjectRen *obr, struct DerivedMesh *dm, float mat[4][4], int timeoffset);
+void free_strand_surface(struct Render *re);
+
+struct StrandShadeCache *strand_shade_cache_create(void);
+void strand_shade_cache_free(struct StrandShadeCache *cache);
+void strand_shade_segment(struct Render *re, struct StrandShadeCache *cache, struct StrandSegment *sseg, struct ShadeSample *ssamp, float t, float s, int addpassflag);
+void strand_shade_unref(struct StrandShadeCache *cache, struct ObjectInstanceRen *obi, struct StrandVert *svert);
+
+#endif
+
diff --git a/source/blender/render/intern/include/sunsky.h b/source/blender/render/intern/include/sunsky.h
new file mode 100644
index 00000000000..c608f9fc48c
--- /dev/null
+++ b/source/blender/render/intern/include/sunsky.h
@@ -0,0 +1,81 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contributor(s): zaghaghi
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/render/intern/include/sunsky.h
+ * \ingroup render
+ */
+
+#ifndef __SUNSKY_H__
+#define __SUNSKY_H__
+
+// #define SPECTRUM_MAX_COMPONENTS 100
+
+typedef struct SunSky {
+ short effect_type, skyblendtype, sky_colorspace;
+ float turbidity;
+ float theta, phi;
+
+ float toSun[3];
+
+ /*float sunSpectralRaddata[SPECTRUM_MAX_COMPONENTS];*/
+ float sunSolidAngle;
+
+ float zenith_Y, zenith_x, zenith_y;
+
+ float perez_Y[5], perez_x[5], perez_y[5];
+
+ /* suggested by glome in patch [#8063] */
+ float horizon_brightness;
+ float spread;
+ float sun_brightness;
+ float sun_size;
+ float backscattered_light;
+ float skyblendfac;
+ float sky_exposure;
+
+ float atm_HGg;
+
+ float atm_SunIntensity;
+ float atm_InscatteringMultiplier;
+ float atm_ExtinctionMultiplier;
+ float atm_BetaRayMultiplier;
+ float atm_BetaMieMultiplier;
+ float atm_DistanceMultiplier;
+
+ float atm_BetaRay[3];
+ float atm_BetaDashRay[3];
+ float atm_BetaMie[3];
+ float atm_BetaDashMie[3];
+ float atm_BetaRM[3];
+} SunSky;
+
+void InitSunSky(struct SunSky *sunsky, float turb, const float toSun[3], float horizon_brightness,
+ float spread, float sun_brightness, float sun_size, float back_scatter,
+ float skyblendfac, short skyblendtype, float sky_exposure, float sky_colorspace);
+
+void GetSkyXYZRadiance(struct SunSky *sunsky, float theta, float phi, float color_out[3]);
+void GetSkyXYZRadiancef(struct SunSky *sunsky, const float varg[3], float color_out[3]);
+void InitAtmosphere(struct SunSky *sunSky, float sun_intens, float mief, float rayf, float inscattf, float extincf, float disf);
+void AtmospherePixleShader(struct SunSky *sunSky, float view[3], float s, float rgb[3]);
+void ClipColor(float c[3]);
+
+#endif /*__SUNSKY_H__*/
diff --git a/source/blender/render/intern/include/texture_ocean.h b/source/blender/render/intern/include/texture_ocean.h
new file mode 100644
index 00000000000..6d7bc6fe7b0
--- /dev/null
+++ b/source/blender/render/intern/include/texture_ocean.h
@@ -0,0 +1,35 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * Contributors: Matt Ebb
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __TEXTURE_OCEAN_H__
+#define __TEXTURE_OCEAN_H__
+
+/** \file blender/render/intern/include/texture_ocean.h
+ * \ingroup render
+ */
+
+int ocean_texture(struct Tex *tex, const float texvec[2], struct TexResult *texres);
+
+#endif /* __TEXTURE_OCEAN_H__ */
diff --git a/source/blender/render/intern/include/voxeldata.h b/source/blender/render/intern/include/voxeldata.h
new file mode 100644
index 00000000000..041ca78a799
--- /dev/null
+++ b/source/blender/render/intern/include/voxeldata.h
@@ -0,0 +1,47 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): Raul Fernandez Hernandez (Farsthary), Matt Ebb.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/render/intern/include/voxeldata.h
+ * \ingroup render
+ */
+
+#ifndef __VOXELDATA_H__
+#define __VOXELDATA_H__
+
+struct Render;
+struct TexResult;
+
+typedef struct VoxelDataHeader {
+ int resolX, resolY, resolZ;
+ int frames;
+} VoxelDataHeader;
+
+void cache_voxeldata(Tex *tex, int scene_frame);
+void make_voxeldata(struct Render *re);
+int voxeldatatex(struct Tex *tex, const float texvec[3], struct TexResult *texres);
+
+#endif /* __VOXELDATA_H__ */
diff --git a/source/blender/render/intern/include/zbuf.h b/source/blender/render/intern/include/zbuf.h
index 3dfcbc355c4..0654a4f8df6 100644
--- a/source/blender/render/intern/include/zbuf.h
+++ b/source/blender/render/intern/include/zbuf.h
@@ -36,7 +36,7 @@
/* span fill in method, is also used to localize data for zbuffering */
typedef struct ZSpan {
int rectx, recty; /* range for clipping */
-
+
int miny1, maxy1, miny2, maxy2; /* actual filled in range */
const float *minp1, *maxp1, *minp2, *maxp2; /* vertex pointers detect min/max range in */
float *span1, *span2;
diff --git a/source/blender/render/intern/raytrace/bvh.h b/source/blender/render/intern/raytrace/bvh.h
new file mode 100644
index 00000000000..0f9a506762b
--- /dev/null
+++ b/source/blender/render/intern/raytrace/bvh.h
@@ -0,0 +1,407 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2009 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): André Pinto.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/render/intern/raytrace/bvh.h
+ * \ingroup render
+ */
+
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_math.h"
+
+#include "raycounter.h"
+#include "rayintersection.h"
+#include "rayobject.h"
+#include "rayobject_hint.h"
+#include "rayobject_rtbuild.h"
+
+#include <assert.h>
+
+#ifdef __SSE__
+#include <xmmintrin.h>
+#endif
+
+#ifndef __BVH_H__
+#define __BVH_H__
+
+#ifdef __SSE__
+inline int test_bb_group4(__m128 *bb_group, const Isect *isec)
+{
+ const __m128 tmin0 = _mm_setzero_ps();
+ const __m128 tmax0 = _mm_set_ps1(isec->dist);
+
+ float start[3], idot_axis[3];
+ copy_v3_v3(start, isec->start);
+ copy_v3_v3(idot_axis, isec->idot_axis);
+
+ const __m128 tmin1 = _mm_max_ps(tmin0, _mm_mul_ps(_mm_sub_ps(bb_group[isec->bv_index[0]], _mm_set_ps1(start[0]) ), _mm_set_ps1(idot_axis[0])) );
+ const __m128 tmax1 = _mm_min_ps(tmax0, _mm_mul_ps(_mm_sub_ps(bb_group[isec->bv_index[1]], _mm_set_ps1(start[0]) ), _mm_set_ps1(idot_axis[0])) );
+ const __m128 tmin2 = _mm_max_ps(tmin1, _mm_mul_ps(_mm_sub_ps(bb_group[isec->bv_index[2]], _mm_set_ps1(start[1]) ), _mm_set_ps1(idot_axis[1])) );
+ const __m128 tmax2 = _mm_min_ps(tmax1, _mm_mul_ps(_mm_sub_ps(bb_group[isec->bv_index[3]], _mm_set_ps1(start[1]) ), _mm_set_ps1(idot_axis[1])) );
+ const __m128 tmin3 = _mm_max_ps(tmin2, _mm_mul_ps(_mm_sub_ps(bb_group[isec->bv_index[4]], _mm_set_ps1(start[2]) ), _mm_set_ps1(idot_axis[2])) );
+ const __m128 tmax3 = _mm_min_ps(tmax2, _mm_mul_ps(_mm_sub_ps(bb_group[isec->bv_index[5]], _mm_set_ps1(start[2]) ), _mm_set_ps1(idot_axis[2])) );
+
+ return _mm_movemask_ps(_mm_cmpge_ps(tmax3, tmin3));
+}
+#endif
+
+/*
+ * Determines the distance that the ray must travel to hit the bounding volume of the given node
+ * Based on Tactical Optimization of Ray/Box Intersection, by Graham Fyffe
+ * [http://tog.acm.org/resources/RTNews/html/rtnv21n1.html#art9]
+ */
+static inline int rayobject_bb_intersect_test(const Isect *isec, const float *_bb)
+{
+ const float *bb = _bb;
+
+ float t1x = (bb[isec->bv_index[0]] - isec->start[0]) * isec->idot_axis[0];
+ float t2x = (bb[isec->bv_index[1]] - isec->start[0]) * isec->idot_axis[0];
+ float t1y = (bb[isec->bv_index[2]] - isec->start[1]) * isec->idot_axis[1];
+ float t2y = (bb[isec->bv_index[3]] - isec->start[1]) * isec->idot_axis[1];
+ float t1z = (bb[isec->bv_index[4]] - isec->start[2]) * isec->idot_axis[2];
+ float t2z = (bb[isec->bv_index[5]] - isec->start[2]) * isec->idot_axis[2];
+
+ RE_RC_COUNT(isec->raycounter->bb.test);
+
+ if (t1x > t2y || t2x < t1y || t1x > t2z || t2x < t1z || t1y > t2z || t2y < t1z) return 0;
+ if (t2x < 0.0f || t2y < 0.0f || t2z < 0.0f) return 0;
+ if (t1x > isec->dist || t1y > isec->dist || t1z > isec->dist) return 0;
+ RE_RC_COUNT(isec->raycounter->bb.hit);
+
+ return 1;
+}
+
+/* bvh tree generics */
+template<class Tree> static void bvh_add(Tree *obj, RayObject *ob)
+{
+ rtbuild_add(obj->builder, ob);
+}
+
+template<class Node>
+inline bool is_leaf(Node *node)
+{
+ return !RE_rayobject_isAligned(node);
+}
+
+template<class Tree> static void bvh_done(Tree *obj);
+
+template<class Tree>
+static void bvh_free(Tree *obj)
+{
+ if (obj->builder)
+ rtbuild_free(obj->builder);
+
+ if (obj->node_arena)
+ BLI_memarena_free(obj->node_arena);
+
+ MEM_freeN(obj);
+}
+
+template<class Tree>
+static void bvh_bb(Tree *obj, float *min, float *max)
+{
+ if (obj->root)
+ bvh_node_merge_bb(obj->root, min, max);
+}
+
+
+template<class Tree>
+static float bvh_cost(Tree *obj)
+{
+ assert(obj->cost >= 0.0f);
+ return obj->cost;
+}
+
+
+
+/* bvh tree nodes generics */
+template<class Node> static inline int bvh_node_hit_test(Node *node, Isect *isec)
+{
+ return rayobject_bb_intersect_test(isec, (const float *)node->bb);
+}
+
+
+template<class Node>
+static inline void bvh_node_merge_bb(Node *node, float min[3], float max[3])
+{
+ if (is_leaf(node)) {
+ RE_rayobject_merge_bb((RayObject *)node, min, max);
+ }
+ else {
+ DO_MIN(node->bb, min);
+ DO_MAX(node->bb + 3, max);
+ }
+}
+
+
+
+/*
+ * recursively transverse a BVH looking for a rayhit using a local stack
+ */
+template<class Node> static inline void bvh_node_push_childs(Node *node, Isect *isec, Node **stack, int &stack_pos);
+
+template<class Node, int MAX_STACK_SIZE, bool TEST_ROOT, bool SHADOW>
+static int bvh_node_stack_raycast(Node *root, Isect *isec)
+{
+ Node *stack[MAX_STACK_SIZE];
+ int hit = 0, stack_pos = 0;
+
+ if (!TEST_ROOT && !is_leaf(root))
+ bvh_node_push_childs(root, isec, stack, stack_pos);
+ else
+ stack[stack_pos++] = root;
+
+ while (stack_pos) {
+ Node *node = stack[--stack_pos];
+ if (!is_leaf(node)) {
+ if (bvh_node_hit_test(node, isec)) {
+ bvh_node_push_childs(node, isec, stack, stack_pos);
+ assert(stack_pos <= MAX_STACK_SIZE);
+ }
+ }
+ else {
+ hit |= RE_rayobject_intersect( (RayObject *)node, isec);
+ if (SHADOW && hit) return hit;
+ }
+ }
+ return hit;
+}
+
+
+#ifdef __SSE__
+/*
+ * Generic SIMD bvh recursion
+ * this was created to be able to use any simd (with the cost of some memmoves)
+ * it can take advantage of any SIMD width and doens't needs any special tree care
+ */
+template<class Node, int MAX_STACK_SIZE, bool TEST_ROOT>
+static int bvh_node_stack_raycast_simd(Node *root, Isect *isec)
+{
+ Node *stack[MAX_STACK_SIZE];
+
+ int hit = 0, stack_pos = 0;
+
+ if (!TEST_ROOT) {
+ if (!is_leaf(root)) {
+ if (!is_leaf(root->child))
+ bvh_node_push_childs(root, isec, stack, stack_pos);
+ else
+ return RE_rayobject_intersect( (RayObject *)root->child, isec);
+ }
+ else
+ return RE_rayobject_intersect( (RayObject *)root, isec);
+ }
+ else {
+ if (!is_leaf(root))
+ stack[stack_pos++] = root;
+ else
+ return RE_rayobject_intersect( (RayObject *)root, isec);
+ }
+
+ while (true) {
+ //Use SIMD 4
+ if (stack_pos >= 4) {
+ __m128 t_bb[6];
+ Node *t_node[4];
+
+ stack_pos -= 4;
+
+ /* prepare the 4BB for SIMD */
+ t_node[0] = stack[stack_pos + 0]->child;
+ t_node[1] = stack[stack_pos + 1]->child;
+ t_node[2] = stack[stack_pos + 2]->child;
+ t_node[3] = stack[stack_pos + 3]->child;
+
+ const float *bb0 = stack[stack_pos + 0]->bb;
+ const float *bb1 = stack[stack_pos + 1]->bb;
+ const float *bb2 = stack[stack_pos + 2]->bb;
+ const float *bb3 = stack[stack_pos + 3]->bb;
+
+ const __m128 x0y0x1y1 = _mm_shuffle_ps(_mm_load_ps(bb0), _mm_load_ps(bb1), _MM_SHUFFLE(1, 0, 1, 0) );
+ const __m128 x2y2x3y3 = _mm_shuffle_ps(_mm_load_ps(bb2), _mm_load_ps(bb3), _MM_SHUFFLE(1, 0, 1, 0) );
+ t_bb[0] = _mm_shuffle_ps(x0y0x1y1, x2y2x3y3, _MM_SHUFFLE(2, 0, 2, 0) );
+ t_bb[1] = _mm_shuffle_ps(x0y0x1y1, x2y2x3y3, _MM_SHUFFLE(3, 1, 3, 1) );
+
+ const __m128 z0X0z1X1 = _mm_shuffle_ps(_mm_load_ps(bb0), _mm_load_ps(bb1), _MM_SHUFFLE(3, 2, 3, 2) );
+ const __m128 z2X2z3X3 = _mm_shuffle_ps(_mm_load_ps(bb2), _mm_load_ps(bb3), _MM_SHUFFLE(3, 2, 3, 2) );
+ t_bb[2] = _mm_shuffle_ps(z0X0z1X1, z2X2z3X3, _MM_SHUFFLE(2, 0, 2, 0) );
+ t_bb[3] = _mm_shuffle_ps(z0X0z1X1, z2X2z3X3, _MM_SHUFFLE(3, 1, 3, 1) );
+
+ const __m128 Y0Z0Y1Z1 = _mm_shuffle_ps(_mm_load_ps(bb0 + 4), _mm_load_ps(bb1 + 4), _MM_SHUFFLE(1, 0, 1, 0) );
+ const __m128 Y2Z2Y3Z3 = _mm_shuffle_ps(_mm_load_ps(bb2 + 4), _mm_load_ps(bb3 + 4), _MM_SHUFFLE(1, 0, 1, 0) );
+ t_bb[4] = _mm_shuffle_ps(Y0Z0Y1Z1, Y2Z2Y3Z3, _MM_SHUFFLE(2, 0, 2, 0) );
+ t_bb[5] = _mm_shuffle_ps(Y0Z0Y1Z1, Y2Z2Y3Z3, _MM_SHUFFLE(3, 1, 3, 1) );
+#if 0
+ for (int i = 0; i < 4; i++)
+ {
+ Node *t = stack[stack_pos + i];
+ assert(!is_leaf(t));
+
+ float *bb = ((float *)t_bb) + i;
+ bb[4 * 0] = t->bb[0];
+ bb[4 * 1] = t->bb[1];
+ bb[4 * 2] = t->bb[2];
+ bb[4 * 3] = t->bb[3];
+ bb[4 * 4] = t->bb[4];
+ bb[4 * 5] = t->bb[5];
+ t_node[i] = t->child;
+ }
+#endif
+ RE_RC_COUNT(isec->raycounter->simd_bb.test);
+ int res = test_bb_group4(t_bb, isec);
+
+ for (int i = 0; i < 4; i++)
+ if (res & (1 << i)) {
+ RE_RC_COUNT(isec->raycounter->simd_bb.hit);
+ if (!is_leaf(t_node[i])) {
+ for (Node *t = t_node[i]; t; t = t->sibling) {
+ assert(stack_pos < MAX_STACK_SIZE);
+ stack[stack_pos++] = t;
+ }
+ }
+ else {
+ hit |= RE_rayobject_intersect( (RayObject *)t_node[i], isec);
+ if (hit && isec->mode == RE_RAY_SHADOW) return hit;
+ }
+ }
+ }
+ else if (stack_pos > 0) {
+ Node *node = stack[--stack_pos];
+ assert(!is_leaf(node));
+
+ if (bvh_node_hit_test(node, isec)) {
+ if (!is_leaf(node->child)) {
+ bvh_node_push_childs(node, isec, stack, stack_pos);
+ assert(stack_pos <= MAX_STACK_SIZE);
+ }
+ else {
+ hit |= RE_rayobject_intersect( (RayObject *)node->child, isec);
+ if (hit && isec->mode == RE_RAY_SHADOW) return hit;
+ }
+ }
+ }
+ else break;
+ }
+ return hit;
+}
+#endif
+
+/*
+ * recursively transverse a BVH looking for a rayhit using system stack
+ */
+#if 0
+template<class Node>
+static int bvh_node_raycast(Node *node, Isect *isec)
+{
+ int hit = 0;
+ if (bvh_test_node(node, isec))
+ {
+ if (isec->idot_axis[node->split_axis] > 0.0f)
+ {
+ int i;
+ for (i = 0; i < BVH_NCHILDS; i++)
+ if (!is_leaf(node->child[i]))
+ {
+ if (node->child[i] == 0) break;
+
+ hit |= bvh_node_raycast(node->child[i], isec);
+ if (hit && isec->mode == RE_RAY_SHADOW) return hit;
+ }
+ else {
+ hit |= RE_rayobject_intersect( (RayObject *)node->child[i], isec);
+ if (hit && isec->mode == RE_RAY_SHADOW) return hit;
+ }
+ }
+ else {
+ int i;
+ for (i = BVH_NCHILDS - 1; i >= 0; i--)
+ if (!is_leaf(node->child[i]))
+ {
+ if (node->child[i])
+ {
+ hit |= dfs_raycast(node->child[i], isec);
+ if (hit && isec->mode == RE_RAY_SHADOW) return hit;
+ }
+ }
+ else {
+ hit |= RE_rayobject_intersect( (RayObject *)node->child[i], isec);
+ if (hit && isec->mode == RE_RAY_SHADOW) return hit;
+ }
+ }
+ }
+ return hit;
+}
+#endif
+
+template<class Node, class HintObject>
+static void bvh_dfs_make_hint(Node *node, LCTSHint *hint, int reserve_space, HintObject *hintObject)
+{
+ assert(hint->size + reserve_space + 1 <= RE_RAY_LCTS_MAX_SIZE);
+
+ if (is_leaf(node)) {
+ hint->stack[hint->size++] = (RayObject *)node;
+ }
+ else {
+ int childs = count_childs(node);
+ if (hint->size + reserve_space + childs <= RE_RAY_LCTS_MAX_SIZE) {
+ int result = hint_test_bb(hintObject, node->bb, node->bb + 3);
+ if (result == HINT_RECURSE) {
+ /* We are 100% sure the ray will be pass inside this node */
+ bvh_dfs_make_hint_push_siblings(node->child, hint, reserve_space, hintObject);
+ }
+ else if (result == HINT_ACCEPT) {
+ hint->stack[hint->size++] = (RayObject *)node;
+ }
+ }
+ else {
+ hint->stack[hint->size++] = (RayObject *)node;
+ }
+ }
+}
+
+
+template<class Tree>
+static RayObjectAPI *bvh_get_api(int maxstacksize);
+
+
+template<class Tree, int DFS_STACK_SIZE>
+static inline RayObject *bvh_create_tree(int size)
+{
+ Tree *obj = (Tree *)MEM_callocN(sizeof(Tree), "BVHTree");
+ assert(RE_rayobject_isAligned(obj)); /* RayObject API assumes real data to be 4-byte aligned */
+
+ obj->rayobj.api = bvh_get_api<Tree>(DFS_STACK_SIZE);
+ obj->root = NULL;
+
+ obj->node_arena = NULL;
+ obj->builder = rtbuild_create(size);
+
+ return RE_rayobject_unalignRayAPI((RayObject *) obj);
+}
+
+#endif
diff --git a/source/blender/render/intern/raytrace/rayobject.cpp b/source/blender/render/intern/raytrace/rayobject.cpp
new file mode 100644
index 00000000000..fee877b311d
--- /dev/null
+++ b/source/blender/render/intern/raytrace/rayobject.cpp
@@ -0,0 +1,534 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2009 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): André Pinto.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/render/intern/raytrace/rayobject.cpp
+ * \ingroup render
+ */
+
+
+#include <assert.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_math.h"
+#include "BLI_utildefines.h"
+
+#include "DNA_material_types.h"
+
+#include "rayintersection.h"
+#include "rayobject.h"
+#include "raycounter.h"
+#include "render_types.h"
+#include "renderdatabase.h"
+
+/* RayFace
+ *
+ * note we force always inline here, because compiler refuses to otherwise
+ * because function is too long. Since this is code that is called billions
+ * of times we really do want to inline. */
+
+MALWAYS_INLINE RayObject *rayface_from_coords(RayFace *rayface, void *ob, void *face,
+ float *v1, float *v2, float *v3, float *v4)
+{
+ rayface->ob = ob;
+ rayface->face = face;
+
+ copy_v3_v3(rayface->v1, v1);
+ copy_v3_v3(rayface->v2, v2);
+ copy_v3_v3(rayface->v3, v3);
+
+ if (v4) {
+ copy_v3_v3(rayface->v4, v4);
+ rayface->quad = 1;
+ }
+ else {
+ rayface->quad = 0;
+ }
+
+ return RE_rayobject_unalignRayFace(rayface);
+}
+
+MALWAYS_INLINE void rayface_from_vlak(RayFace *rayface, ObjectInstanceRen *obi, VlakRen *vlr)
+{
+ rayface_from_coords(rayface, obi, vlr, vlr->v1->co, vlr->v2->co, vlr->v3->co, vlr->v4 ? vlr->v4->co : NULL);
+
+ if (obi->transform_primitives) {
+ mul_m4_v3(obi->mat, rayface->v1);
+ mul_m4_v3(obi->mat, rayface->v2);
+ mul_m4_v3(obi->mat, rayface->v3);
+
+ if (RE_rayface_isQuad(rayface))
+ mul_m4_v3(obi->mat, rayface->v4);
+ }
+}
+
+RayObject *RE_rayface_from_vlak(RayFace *rayface, ObjectInstanceRen *obi, VlakRen *vlr)
+{
+ return rayface_from_coords(rayface, obi, vlr, vlr->v1->co, vlr->v2->co, vlr->v3->co, vlr->v4 ? vlr->v4->co : NULL);
+}
+
+RayObject *RE_rayface_from_coords(RayFace *rayface, void *ob, void *face, float *v1, float *v2, float *v3, float *v4)
+{
+ return rayface_from_coords(rayface, ob, face, v1, v2, v3, v4);
+}
+
+/* VlakPrimitive */
+
+RayObject *RE_vlakprimitive_from_vlak(VlakPrimitive *face, struct ObjectInstanceRen *obi, struct VlakRen *vlr)
+{
+ face->ob = obi;
+ face->face = vlr;
+
+ return RE_rayobject_unalignVlakPrimitive(face);
+}
+
+/* Checks for ignoring faces or materials */
+
+MALWAYS_INLINE int vlr_check_intersect(Isect *is, ObjectInstanceRen *obi, VlakRen *vlr)
+{
+ /* for baking selected to active non-traceable materials might still
+ * be in the raytree */
+ if (!(vlr->flag & R_TRACEBLE))
+ return 0;
+
+ /* I know... cpu cycle waste, might do smarter once */
+ if (is->mode == RE_RAY_MIRROR)
+ return !(vlr->mat->mode & MA_ONLYCAST);
+ else
+ return (vlr->mat->mode2 & MA_CASTSHADOW) && (is->lay & obi->lay);
+}
+
+MALWAYS_INLINE int vlr_check_intersect_solid(Isect *UNUSED(is), ObjectInstanceRen *UNUSED(obi), VlakRen *vlr)
+{
+ /* solid material types only */
+ if (vlr->mat->material_type == MA_TYPE_SURFACE)
+ return 1;
+ else
+ return 0;
+}
+
+MALWAYS_INLINE int vlr_check_bake(Isect *is, ObjectInstanceRen *obi, VlakRen *UNUSED(vlr))
+{
+ return (obi->obr->ob != is->userdata) && (obi->obr->ob->flag & SELECT);
+}
+
+/* Ray Triangle/Quad Intersection */
+
+static bool isect_ray_tri_watertight_no_sign_check_v3(
+ const float ray_origin[3], const struct IsectRayPrecalc *isect_precalc,
+ const float v0[3], const float v1[3], const float v2[3],
+ float *r_lambda, float r_uv[2])
+{
+ const int kx = isect_precalc->kx;
+ const int ky = isect_precalc->ky;
+ const int kz = isect_precalc->kz;
+ const float sx = isect_precalc->sx;
+ const float sy = isect_precalc->sy;
+ const float sz = isect_precalc->sz;
+
+ /* Calculate vertices relative to ray origin. */
+ const float a[3] = {v0[0] - ray_origin[0], v0[1] - ray_origin[1], v0[2] - ray_origin[2]};
+ const float b[3] = {v1[0] - ray_origin[0], v1[1] - ray_origin[1], v1[2] - ray_origin[2]};
+ const float c[3] = {v2[0] - ray_origin[0], v2[1] - ray_origin[1], v2[2] - ray_origin[2]};
+
+ const float a_kx = a[kx], a_ky = a[ky], a_kz = a[kz];
+ const float b_kx = b[kx], b_ky = b[ky], b_kz = b[kz];
+ const float c_kx = c[kx], c_ky = c[ky], c_kz = c[kz];
+
+ /* Perform shear and scale of vertices. */
+ const float ax = a_kx - sx * a_kz;
+ const float ay = a_ky - sy * a_kz;
+ const float bx = b_kx - sx * b_kz;
+ const float by = b_ky - sy * b_kz;
+ const float cx = c_kx - sx * c_kz;
+ const float cy = c_ky - sy * c_kz;
+
+ /* Calculate scaled barycentric coordinates. */
+ const float u = cx * by - cy * bx;
+ const float v = ax * cy - ay * cx;
+ const float w = bx * ay - by * ax;
+ float det;
+
+ if ((u < 0.0f || v < 0.0f || w < 0.0f) &&
+ (u > 0.0f || v > 0.0f || w > 0.0f))
+ {
+ return false;
+ }
+
+ /* Calculate determinant. */
+ det = u + v + w;
+ if (UNLIKELY(det == 0.0f)) {
+ return false;
+ }
+ else {
+ /* Calculate scaled z-coordinates of vertices and use them to calculate
+ * the hit distance.
+ */
+ const float t = (u * a_kz + v * b_kz + w * c_kz) * sz;
+ /* Normalize u, v and t. */
+ const float inv_det = 1.0f / det;
+ if (r_uv) {
+ r_uv[0] = u * inv_det;
+ r_uv[1] = v * inv_det;
+ }
+ *r_lambda = t * inv_det;
+ return true;
+ }
+}
+
+MALWAYS_INLINE int isec_tri_quad(const float start[3],
+ const struct IsectRayPrecalc *isect_precalc,
+ const RayFace *face,
+ float r_uv[2], float *r_lambda)
+{
+ float uv[2], l;
+
+ if (isect_ray_tri_watertight_v3(start, isect_precalc, face->v1, face->v2, face->v3, &l, uv)) {
+ /* check if intersection is within ray length */
+ if (l > -RE_RAYTRACE_EPSILON && l < *r_lambda) {
+ r_uv[0] = -uv[0];
+ r_uv[1] = -uv[1];
+ *r_lambda = l;
+ return 1;
+ }
+ }
+
+ /* intersect second triangle in quad */
+ if (RE_rayface_isQuad(face)) {
+ if (isect_ray_tri_watertight_v3(start, isect_precalc, face->v1, face->v3, face->v4, &l, uv)) {
+ /* check if intersection is within ray length */
+ if (l > -RE_RAYTRACE_EPSILON && l < *r_lambda) {
+ r_uv[0] = -uv[0];
+ r_uv[1] = -uv[1];
+ *r_lambda = l;
+ return 2;
+ }
+ }
+ }
+
+ return 0;
+}
+
+/* Simpler yes/no Ray Triangle/Quad Intersection */
+
+MALWAYS_INLINE int isec_tri_quad_neighbour(const float start[3],
+ const float dir[3],
+ const RayFace *face)
+{
+ float r[3];
+ struct IsectRayPrecalc isect_precalc;
+ float uv[2], l;
+
+ negate_v3_v3(r, dir); /* note, different than above function */
+
+ isect_ray_tri_watertight_v3_precalc(&isect_precalc, r);
+
+ if (isect_ray_tri_watertight_no_sign_check_v3(start, &isect_precalc, face->v1, face->v2, face->v3, &l, uv)) {
+ return 1;
+ }
+
+ /* intersect second triangle in quad */
+ if (RE_rayface_isQuad(face)) {
+ if (isect_ray_tri_watertight_no_sign_check_v3(start, &isect_precalc, face->v1, face->v3, face->v4, &l, uv)) {
+ return 2;
+ }
+ }
+
+ return 0;
+}
+
+/* RayFace intersection with checks and neighbor verifaction included,
+ * Isect is modified if the face is hit. */
+
+MALWAYS_INLINE int intersect_rayface(RayObject *hit_obj, RayFace *face, Isect *is)
+{
+ float dist, uv[2];
+ int ok = 0;
+
+ /* avoid self-intersection */
+ if (is->orig.ob == face->ob && is->orig.face == face->face)
+ return 0;
+
+ /* check if we should intersect this face */
+ if (is->check == RE_CHECK_VLR_RENDER) {
+ if (vlr_check_intersect(is, (ObjectInstanceRen *)face->ob, (VlakRen *)face->face) == 0)
+ return 0;
+ }
+ else if (is->check == RE_CHECK_VLR_NON_SOLID_MATERIAL) {
+ if (vlr_check_intersect(is, (ObjectInstanceRen *)face->ob, (VlakRen *)face->face) == 0)
+ return 0;
+ if (vlr_check_intersect_solid(is, (ObjectInstanceRen *)face->ob, (VlakRen *)face->face) == 0)
+ return 0;
+ }
+ else if (is->check == RE_CHECK_VLR_BAKE) {
+ if (vlr_check_bake(is, (ObjectInstanceRen *)face->ob, (VlakRen *)face->face) == 0)
+ return 0;
+ }
+
+ /* ray counter */
+ RE_RC_COUNT(is->raycounter->faces.test);
+
+ dist = is->dist;
+ ok = isec_tri_quad(is->start, &is->isect_precalc, face, uv, &dist);
+
+ if (ok) {
+
+ /* when a shadow ray leaves a face, it can be little outside the edges
+ * of it, causing intersection to be detected in its neighbor face */
+ if (is->skip & RE_SKIP_VLR_NEIGHBOUR) {
+ if (dist < 0.1f && is->orig.ob == face->ob) {
+ VlakRen *a = (VlakRen *)is->orig.face;
+ VlakRen *b = (VlakRen *)face->face;
+ ObjectRen *obr = ((ObjectInstanceRen *)face->ob)->obr;
+
+ VertRen **va, **vb;
+ int *org_idx_a, *org_idx_b;
+ int i, j;
+ bool is_neighbor = false;
+
+ /* "same" vertex means either the actual same VertRen, or the same 'final org index', if available
+ * (autosmooth only, currently). */
+ for (i = 0, va = &a->v1; !is_neighbor && i < 4 && *va; ++i, ++va) {
+ org_idx_a = RE_vertren_get_origindex(obr, *va, false);
+ for (j = 0, vb = &b->v1; !is_neighbor && j < 4 && *vb; ++j, ++vb) {
+ if (*va == *vb) {
+ is_neighbor = true;
+ }
+ else if (org_idx_a) {
+ org_idx_b = RE_vertren_get_origindex(obr, *vb, 0);
+ if (org_idx_b && *org_idx_a == *org_idx_b) {
+ is_neighbor = true;
+ }
+ }
+ }
+ }
+
+ /* So there's a shared edge or vertex, let's intersect ray with self, if that's true
+ * we can safely return 1, otherwise we assume the intersection is invalid, 0 */
+ if (is_neighbor) {
+ /* create RayFace from original face, transformed if necessary */
+ RayFace origface;
+ ObjectInstanceRen *ob = (ObjectInstanceRen *)is->orig.ob;
+ rayface_from_vlak(&origface, ob, (VlakRen *)is->orig.face);
+
+ if (!isec_tri_quad_neighbour(is->start, is->dir, &origface)) {
+ return 0;
+ }
+ }
+ }
+ }
+
+ RE_RC_COUNT(is->raycounter->faces.hit);
+
+ is->isect = ok; // which half of the quad
+ is->dist = dist;
+ is->u = uv[0]; is->v = uv[1];
+
+ is->hit.ob = face->ob;
+ is->hit.face = face->face;
+#ifdef RT_USE_LAST_HIT
+ is->last_hit = hit_obj;
+#endif
+ return 1;
+ }
+
+ return 0;
+}
+
+/* Intersection */
+
+int RE_rayobject_raycast(RayObject *r, Isect *isec)
+{
+ int i;
+
+ /* Pre-calculate orientation for watertight intersection checks. */
+ isect_ray_tri_watertight_v3_precalc(&isec->isect_precalc, isec->dir);
+
+ RE_RC_COUNT(isec->raycounter->raycast.test);
+
+ /* setup vars used on raycast */
+ for (i = 0; i < 3; i++) {
+ isec->idot_axis[i] = 1.0f / isec->dir[i];
+
+ isec->bv_index[2 * i] = isec->idot_axis[i] < 0.0f ? 1 : 0;
+ isec->bv_index[2 * i + 1] = 1 - isec->bv_index[2 * i];
+
+ isec->bv_index[2 * i] = i + 3 * isec->bv_index[2 * i];
+ isec->bv_index[2 * i + 1] = i + 3 * isec->bv_index[2 * i + 1];
+ }
+
+#ifdef RT_USE_LAST_HIT
+ /* last hit heuristic */
+ if (isec->mode == RE_RAY_SHADOW && isec->last_hit) {
+ RE_RC_COUNT(isec->raycounter->rayshadow_last_hit.test);
+
+ if (RE_rayobject_intersect(isec->last_hit, isec)) {
+ RE_RC_COUNT(isec->raycounter->raycast.hit);
+ RE_RC_COUNT(isec->raycounter->rayshadow_last_hit.hit);
+ return 1;
+ }
+ }
+#endif
+
+#ifdef RT_USE_HINT
+ isec->hit_hint = 0;
+#endif
+
+ if (RE_rayobject_intersect(r, isec)) {
+ RE_RC_COUNT(isec->raycounter->raycast.hit);
+
+#ifdef RT_USE_HINT
+ isec->hint = isec->hit_hint;
+#endif
+ return 1;
+ }
+
+ return 0;
+}
+
+int RE_rayobject_intersect(RayObject *r, Isect *i)
+{
+ if (RE_rayobject_isRayFace(r)) {
+ return intersect_rayface(r, (RayFace *) RE_rayobject_align(r), i);
+ }
+ else if (RE_rayobject_isVlakPrimitive(r)) {
+ //TODO optimize (useless copy to RayFace to avoid duplicate code)
+ VlakPrimitive *face = (VlakPrimitive *) RE_rayobject_align(r);
+ RayFace nface;
+ rayface_from_vlak(&nface, face->ob, face->face);
+
+ return intersect_rayface(r, &nface, i);
+ }
+ else if (RE_rayobject_isRayAPI(r)) {
+ r = RE_rayobject_align(r);
+ return r->api->raycast(r, i);
+ }
+ else {
+ assert(0);
+ return 0;
+ }
+}
+
+/* Building */
+
+void RE_rayobject_add(RayObject *r, RayObject *o)
+{
+ r = RE_rayobject_align(r);
+ return r->api->add(r, o);
+}
+
+void RE_rayobject_done(RayObject *r)
+{
+ r = RE_rayobject_align(r);
+ r->api->done(r);
+}
+
+void RE_rayobject_free(RayObject *r)
+{
+ r = RE_rayobject_align(r);
+ r->api->free(r);
+}
+
+float RE_rayobject_cost(RayObject *r)
+{
+ if (RE_rayobject_isRayFace(r) || RE_rayobject_isVlakPrimitive(r)) {
+ return 1.0f;
+ }
+ else if (RE_rayobject_isRayAPI(r)) {
+ r = RE_rayobject_align(r);
+ return r->api->cost(r);
+ }
+ else {
+ assert(0);
+ return 1.0f;
+ }
+}
+
+/* Bounding Boxes */
+
+void RE_rayobject_merge_bb(RayObject *r, float min[3], float max[3])
+{
+ if (RE_rayobject_isRayFace(r)) {
+ RayFace *face = (RayFace *) RE_rayobject_align(r);
+
+ DO_MINMAX(face->v1, min, max);
+ DO_MINMAX(face->v2, min, max);
+ DO_MINMAX(face->v3, min, max);
+ if (RE_rayface_isQuad(face)) DO_MINMAX(face->v4, min, max);
+ }
+ else if (RE_rayobject_isVlakPrimitive(r)) {
+ VlakPrimitive *face = (VlakPrimitive *) RE_rayobject_align(r);
+ RayFace nface;
+ rayface_from_vlak(&nface, face->ob, face->face);
+
+ DO_MINMAX(nface.v1, min, max);
+ DO_MINMAX(nface.v2, min, max);
+ DO_MINMAX(nface.v3, min, max);
+ if (RE_rayface_isQuad(&nface)) DO_MINMAX(nface.v4, min, max);
+ }
+ else if (RE_rayobject_isRayAPI(r)) {
+ r = RE_rayobject_align(r);
+ r->api->bb(r, min, max);
+ }
+ else
+ assert(0);
+}
+
+/* Hints */
+
+void RE_rayobject_hint_bb(RayObject *r, RayHint *hint, float *min, float *max)
+{
+ if (RE_rayobject_isRayFace(r) || RE_rayobject_isVlakPrimitive(r)) {
+ return;
+ }
+ else if (RE_rayobject_isRayAPI(r)) {
+ r = RE_rayobject_align(r);
+ return r->api->hint_bb(r, hint, min, max);
+ }
+ else
+ assert(0);
+}
+
+/* RayObjectControl */
+
+int RE_rayobjectcontrol_test_break(RayObjectControl *control)
+{
+ if (control->test_break)
+ return control->test_break(control->data);
+
+ return 0;
+}
+
+void RE_rayobject_set_control(RayObject *r, void *data, RE_rayobjectcontrol_test_break_callback test_break)
+{
+ if (RE_rayobject_isRayAPI(r)) {
+ r = RE_rayobject_align(r);
+ r->control.data = data;
+ r->control.test_break = test_break;
+ }
+}
+
diff --git a/source/blender/render/intern/raytrace/rayobject_hint.h b/source/blender/render/intern/raytrace/rayobject_hint.h
new file mode 100644
index 00000000000..88a32819bd2
--- /dev/null
+++ b/source/blender/render/intern/raytrace/rayobject_hint.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) 2009 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): André Pinto.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/render/intern/raytrace/rayobject_hint.h
+ * \ingroup render
+ */
+
+
+#ifndef __RAYOBJECT_HINT_H__
+#define __RAYOBJECT_HINT_H__
+
+#define HINT_RECURSE 1
+#define HINT_ACCEPT 0
+#define HINT_DISCARD -1
+
+struct HintBB {
+ float bb[6];
+};
+
+inline int hint_test_bb(HintBB *obj, float *Nmin, float *Nmax)
+{
+ if (bb_fits_inside(Nmin, Nmax, obj->bb, obj->bb + 3) )
+ return HINT_RECURSE;
+ else
+ return HINT_ACCEPT;
+}
+#if 0
+struct HintFrustum {
+ float co[3];
+ float no[4][3];
+};
+
+inline int hint_test_bb(HintFrustum &obj, float *Nmin, float *Nmax)
+{
+ //if frustum inside BB
+ {
+ return HINT_RECURSE;
+ }
+ //if BB outside frustum
+ {
+ return HINT_DISCARD;
+ }
+
+ return HINT_ACCEPT;
+}
+#endif
+
+#endif /* __RAYOBJECT_HINT_H__ */
diff --git a/source/blender/render/intern/raytrace/rayobject_instance.cpp b/source/blender/render/intern/raytrace/rayobject_instance.cpp
new file mode 100644
index 00000000000..361e7963d96
--- /dev/null
+++ b/source/blender/render/intern/raytrace/rayobject_instance.cpp
@@ -0,0 +1,211 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2009 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): André Pinto.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/render/intern/raytrace/rayobject_instance.cpp
+ * \ingroup render
+ */
+
+
+#include <assert.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_math.h"
+#include "BLI_utildefines.h"
+
+#include "rayintersection.h"
+#include "rayobject.h"
+
+#define RE_COST_INSTANCE (1.0f)
+
+static int RE_rayobject_instance_intersect(RayObject *o, Isect *isec);
+static void RE_rayobject_instance_free(RayObject *o);
+static void RE_rayobject_instance_bb(RayObject *o, float *min, float *max);
+static float RE_rayobject_instance_cost(RayObject *o);
+
+static void RE_rayobject_instance_hint_bb(RayObject *UNUSED(o), RayHint *UNUSED(hint),
+ float *UNUSED(min), float *UNUSED(max))
+{}
+
+static RayObjectAPI instance_api =
+{
+ RE_rayobject_instance_intersect,
+ NULL, //static void RE_rayobject_instance_add(RayObject *o, RayObject *ob);
+ NULL, //static void RE_rayobject_instance_done(RayObject *o);
+ RE_rayobject_instance_free,
+ RE_rayobject_instance_bb,
+ RE_rayobject_instance_cost,
+ RE_rayobject_instance_hint_bb
+};
+
+typedef struct InstanceRayObject {
+ RayObject rayobj;
+ RayObject *target;
+
+ void *ob; //Object represented by this instance
+ void *target_ob; //Object represented by the inner RayObject, needed to handle self-intersection
+
+ float global2target[4][4];
+ float target2global[4][4];
+
+} InstanceRayObject;
+
+
+RayObject *RE_rayobject_instance_create(RayObject *target, float transform[4][4], void *ob, void *target_ob)
+{
+ InstanceRayObject *obj = (InstanceRayObject *)MEM_callocN(sizeof(InstanceRayObject), "InstanceRayObject");
+ assert(RE_rayobject_isAligned(obj) ); /* RayObject API assumes real data to be 4-byte aligned */
+
+ obj->rayobj.api = &instance_api;
+ obj->target = target;
+ obj->ob = ob;
+ obj->target_ob = target_ob;
+
+ copy_m4_m4(obj->target2global, transform);
+ invert_m4_m4(obj->global2target, obj->target2global);
+
+ return RE_rayobject_unalignRayAPI((RayObject *) obj);
+}
+
+static int RE_rayobject_instance_intersect(RayObject *o, Isect *isec)
+{
+ InstanceRayObject *obj = (InstanceRayObject *)o;
+ float start[3], dir[3], idot_axis[3], dist;
+ int changed = 0, i, res;
+
+ // TODO - this is disabling self intersection on instances
+ if (isec->orig.ob == obj->ob && obj->ob) {
+ changed = 1;
+ isec->orig.ob = obj->target_ob;
+ }
+
+ // backup old values
+ copy_v3_v3(start, isec->start);
+ copy_v3_v3(dir, isec->dir);
+ copy_v3_v3(idot_axis, isec->idot_axis);
+ dist = isec->dist;
+
+ // transform to target coordinates system
+ mul_m4_v3(obj->global2target, isec->start);
+ mul_mat3_m4_v3(obj->global2target, isec->dir);
+ isec->dist *= normalize_v3(isec->dir);
+
+ // update idot_axis and bv_index
+ for (i = 0; i < 3; i++) {
+ isec->idot_axis[i] = 1.0f / isec->dir[i];
+
+ isec->bv_index[2 * i] = isec->idot_axis[i] < 0.0f ? 1 : 0;
+ isec->bv_index[2 * i + 1] = 1 - isec->bv_index[2 * i];
+
+ isec->bv_index[2 * i] = i + 3 * isec->bv_index[2 * i];
+ isec->bv_index[2 * i + 1] = i + 3 * isec->bv_index[2 * i + 1];
+ }
+
+ // Pre-calculate orientation for watertight intersection checks.
+ isect_ray_tri_watertight_v3_precalc(&isec->isect_precalc, isec->dir);
+
+ // raycast
+ res = RE_rayobject_intersect(obj->target, isec);
+
+ // map dist into original coordinate space
+ if (res == 0) {
+ isec->dist = dist;
+ }
+ else {
+ // note we don't just multiply dist, because of possible
+ // non-uniform scaling in the transform matrix
+ float vec[3];
+
+ mul_v3_v3fl(vec, isec->dir, isec->dist);
+ mul_mat3_m4_v3(obj->target2global, vec);
+
+ isec->dist = len_v3(vec);
+ isec->hit.ob = obj->ob;
+
+#ifdef RT_USE_LAST_HIT
+ // TODO support for last hit optimization in instances that can jump
+ // directly to the last hit face.
+ // For now it jumps directly to the last-hit instance root node.
+ isec->last_hit = RE_rayobject_unalignRayAPI((RayObject *) obj);
+#endif
+ }
+
+ // restore values
+ copy_v3_v3(isec->start, start);
+ copy_v3_v3(isec->dir, dir);
+ copy_v3_v3(isec->idot_axis, idot_axis);
+
+ if (changed)
+ isec->orig.ob = obj->ob;
+
+ // restore bv_index
+ for (i = 0; i < 3; i++) {
+ isec->bv_index[2 * i] = isec->idot_axis[i] < 0.0f ? 1 : 0;
+ isec->bv_index[2 * i + 1] = 1 - isec->bv_index[2 * i];
+
+ isec->bv_index[2 * i] = i + 3 * isec->bv_index[2 * i];
+ isec->bv_index[2 * i + 1] = i + 3 * isec->bv_index[2 * i + 1];
+ }
+
+ // Pre-calculate orientation for watertight intersection checks.
+ isect_ray_tri_watertight_v3_precalc(&isec->isect_precalc, isec->dir);
+
+ return res;
+}
+
+static void RE_rayobject_instance_free(RayObject *o)
+{
+ InstanceRayObject *obj = (InstanceRayObject *)o;
+ MEM_freeN(obj);
+}
+
+static float RE_rayobject_instance_cost(RayObject *o)
+{
+ InstanceRayObject *obj = (InstanceRayObject *)o;
+ return RE_rayobject_cost(obj->target) + RE_COST_INSTANCE;
+}
+
+static void RE_rayobject_instance_bb(RayObject *o, float *min, float *max)
+{
+ //TODO:
+ // *better bb.. calculated without rotations of bb
+ // *maybe cache that better-fitted-BB at the InstanceRayObject
+ InstanceRayObject *obj = (InstanceRayObject *)o;
+
+ float m[3], M[3], t[3];
+ int i, j;
+ INIT_MINMAX(m, M);
+ RE_rayobject_merge_bb(obj->target, m, M);
+
+ //There must be a faster way than rotating all the 8 vertexs of the BB
+ for (i = 0; i < 8; i++) {
+ for (j = 0; j < 3; j++) t[j] = (i & (1 << j)) ? M[j] : m[j];
+ mul_m4_v3(obj->target2global, t);
+ DO_MINMAX(t, min, max);
+ }
+}
+
diff --git a/source/blender/render/intern/raytrace/rayobject_octree.cpp b/source/blender/render/intern/raytrace/rayobject_octree.cpp
new file mode 100644
index 00000000000..4b73e64ca45
--- /dev/null
+++ b/source/blender/render/intern/raytrace/rayobject_octree.cpp
@@ -0,0 +1,1101 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 1990-1998 NeoGeo BV.
+ * All rights reserved.
+ *
+ * Contributors: 2004/2005 Blender Foundation, full recode
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/render/intern/raytrace/rayobject_octree.cpp
+ * \ingroup render
+ */
+
+
+/* IMPORTANT NOTE: this code must be independent of any other render code
+ * to use it outside the renderer! */
+
+#include <math.h>
+#include <string.h>
+#include <stdlib.h>
+#include <float.h>
+#include <assert.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_material_types.h"
+
+#include "BLI_math.h"
+#include "BLI_utildefines.h"
+
+#include "rayintersection.h"
+#include "rayobject.h"
+
+/* ********** structs *************** */
+#define BRANCH_ARRAY 1024
+#define NODE_ARRAY 4096
+
+typedef struct Branch {
+ struct Branch *b[8];
+} Branch;
+
+typedef struct OcVal {
+ short ocx, ocy, ocz;
+} OcVal;
+
+typedef struct Node {
+ struct RayFace *v[8];
+ struct OcVal ov[8];
+ struct Node *next;
+} Node;
+
+typedef struct Octree {
+ RayObject rayobj;
+
+ struct Branch **adrbranch;
+ struct Node **adrnode;
+ float ocsize; /* ocsize: mult factor, max size octree */
+ float ocfacx, ocfacy, ocfacz;
+ float min[3], max[3];
+ int ocres;
+ int branchcount, nodecount;
+
+ /* during building only */
+ char *ocface;
+
+ RayFace **ro_nodes;
+ int ro_nodes_size, ro_nodes_used;
+
+} Octree;
+
+static int RE_rayobject_octree_intersect(RayObject *o, Isect *isec);
+static void RE_rayobject_octree_add(RayObject *o, RayObject *ob);
+static void RE_rayobject_octree_done(RayObject *o);
+static void RE_rayobject_octree_free(RayObject *o);
+static void RE_rayobject_octree_bb(RayObject *o, float *min, float *max);
+
+/*
+ * This function is not expected to be called by current code state.
+ */
+static float RE_rayobject_octree_cost(RayObject *UNUSED(o))
+{
+ return 1.0;
+}
+
+static void RE_rayobject_octree_hint_bb(RayObject *UNUSED(o), RayHint *UNUSED(hint),
+ float *UNUSED(min), float *UNUSED(max))
+{
+ return;
+}
+
+static RayObjectAPI octree_api =
+{
+ RE_rayobject_octree_intersect,
+ RE_rayobject_octree_add,
+ RE_rayobject_octree_done,
+ RE_rayobject_octree_free,
+ RE_rayobject_octree_bb,
+ RE_rayobject_octree_cost,
+ RE_rayobject_octree_hint_bb
+};
+
+/* **************** ocval method ******************* */
+/* within one octree node, a set of 3x15 bits defines a 'boundbox' to OR with */
+
+#define OCVALRES 15
+#define BROW16(min, max) \
+ (((max) >= OCVALRES ? 0xFFFF : (1 << ((max) + 1)) - 1) - (((min) > 0) ? ((1 << (min)) - 1) : 0))
+
+static void calc_ocval_face(float *v1, float *v2, float *v3, float *v4, short x, short y, short z, OcVal *ov)
+{
+ float min[3], max[3];
+ int ocmin, ocmax;
+
+ copy_v3_v3(min, v1);
+ copy_v3_v3(max, v1);
+ DO_MINMAX(v2, min, max);
+ DO_MINMAX(v3, min, max);
+ if (v4) {
+ DO_MINMAX(v4, min, max);
+ }
+
+ ocmin = OCVALRES * (min[0] - x);
+ ocmax = OCVALRES * (max[0] - x);
+ ov->ocx = BROW16(ocmin, ocmax);
+
+ ocmin = OCVALRES * (min[1] - y);
+ ocmax = OCVALRES * (max[1] - y);
+ ov->ocy = BROW16(ocmin, ocmax);
+
+ ocmin = OCVALRES * (min[2] - z);
+ ocmax = OCVALRES * (max[2] - z);
+ ov->ocz = BROW16(ocmin, ocmax);
+
+}
+
+static void calc_ocval_ray(OcVal *ov, float xo, float yo, float zo, float *vec1, float *vec2)
+{
+ int ocmin, ocmax;
+
+ if (vec1[0] < vec2[0]) {
+ ocmin = OCVALRES * (vec1[0] - xo);
+ ocmax = OCVALRES * (vec2[0] - xo);
+ }
+ else {
+ ocmin = OCVALRES * (vec2[0] - xo);
+ ocmax = OCVALRES * (vec1[0] - xo);
+ }
+ ov->ocx = BROW16(ocmin, ocmax);
+
+ if (vec1[1] < vec2[1]) {
+ ocmin = OCVALRES * (vec1[1] - yo);
+ ocmax = OCVALRES * (vec2[1] - yo);
+ }
+ else {
+ ocmin = OCVALRES * (vec2[1] - yo);
+ ocmax = OCVALRES * (vec1[1] - yo);
+ }
+ ov->ocy = BROW16(ocmin, ocmax);
+
+ if (vec1[2] < vec2[2]) {
+ ocmin = OCVALRES * (vec1[2] - zo);
+ ocmax = OCVALRES * (vec2[2] - zo);
+ }
+ else {
+ ocmin = OCVALRES * (vec2[2] - zo);
+ ocmax = OCVALRES * (vec1[2] - zo);
+ }
+ ov->ocz = BROW16(ocmin, ocmax);
+}
+
+/* ************* octree ************** */
+
+static Branch *addbranch(Octree *oc, Branch *br, short ocb)
+{
+ int index;
+
+ if (br->b[ocb]) return br->b[ocb];
+
+ oc->branchcount++;
+ index = oc->branchcount >> 12;
+
+ if (oc->adrbranch[index] == NULL)
+ oc->adrbranch[index] = (Branch *)MEM_callocN(4096 * sizeof(Branch), "new oc branch");
+
+ if (oc->branchcount >= BRANCH_ARRAY * 4096) {
+ printf("error; octree branches full\n");
+ oc->branchcount = 0;
+ }
+
+ return br->b[ocb] = oc->adrbranch[index] + (oc->branchcount & 4095);
+}
+
+static Node *addnode(Octree *oc)
+{
+ int index;
+
+ oc->nodecount++;
+ index = oc->nodecount >> 12;
+
+ if (oc->adrnode[index] == NULL)
+ oc->adrnode[index] = (Node *)MEM_callocN(4096 * sizeof(Node), "addnode");
+
+ if (oc->nodecount > NODE_ARRAY * NODE_ARRAY) {
+ printf("error; octree nodes full\n");
+ oc->nodecount = 0;
+ }
+
+ return oc->adrnode[index] + (oc->nodecount & 4095);
+}
+
+static bool face_in_node(RayFace *face, short x, short y, short z, float rtf[4][3])
+{
+ static float nor[3], d;
+ float fx, fy, fz;
+
+ // init static vars
+ if (face) {
+ normal_tri_v3(nor, rtf[0], rtf[1], rtf[2]);
+ d = -nor[0] * rtf[0][0] - nor[1] * rtf[0][1] - nor[2] * rtf[0][2];
+ return 0;
+ }
+
+ fx = x;
+ fy = y;
+ fz = z;
+
+ if ((fx) * nor[0] + (fy) * nor[1] + (fz) * nor[2] + d > 0.0f) {
+ if ((fx + 1) * nor[0] + (fy ) * nor[1] + (fz ) * nor[2] + d < 0.0f) return 1;
+ if ((fx ) * nor[0] + (fy + 1) * nor[1] + (fz ) * nor[2] + d < 0.0f) return 1;
+ if ((fx + 1) * nor[0] + (fy + 1) * nor[1] + (fz ) * nor[2] + d < 0.0f) return 1;
+
+ if ((fx ) * nor[0] + (fy ) * nor[1] + (fz + 1) * nor[2] + d < 0.0f) return 1;
+ if ((fx + 1) * nor[0] + (fy ) * nor[1] + (fz + 1) * nor[2] + d < 0.0f) return 1;
+ if ((fx ) * nor[0] + (fy + 1) * nor[1] + (fz + 1) * nor[2] + d < 0.0f) return 1;
+ if ((fx + 1) * nor[0] + (fy + 1) * nor[1] + (fz + 1) * nor[2] + d < 0.0f) return 1;
+ }
+ else {
+ if ((fx + 1) * nor[0] + (fy ) * nor[1] + (fz ) * nor[2] + d > 0.0f) return 1;
+ if ((fx ) * nor[0] + (fy + 1) * nor[1] + (fz ) * nor[2] + d > 0.0f) return 1;
+ if ((fx + 1) * nor[0] + (fy + 1) * nor[1] + (fz ) * nor[2] + d > 0.0f) return 1;
+
+ if ((fx ) * nor[0] + (fy ) * nor[1] + (fz + 1) * nor[2] + d > 0.0f) return 1;
+ if ((fx + 1) * nor[0] + (fy ) * nor[1] + (fz + 1) * nor[2] + d > 0.0f) return 1;
+ if ((fx ) * nor[0] + (fy + 1) * nor[1] + (fz + 1) * nor[2] + d > 0.0f) return 1;
+ if ((fx + 1) * nor[0] + (fy + 1) * nor[1] + (fz + 1) * nor[2] + d > 0.0f) return 1;
+ }
+
+ return 0;
+}
+
+static void ocwrite(Octree *oc, RayFace *face, int quad, short x, short y, short z, float rtf[4][3])
+{
+ Branch *br;
+ Node *no;
+ short a, oc0, oc1, oc2, oc3, oc4, oc5;
+
+ x <<= 2;
+ y <<= 1;
+
+ br = oc->adrbranch[0];
+
+ if (oc->ocres == 512) {
+ oc0 = ((x & 1024) + (y & 512) + (z & 256)) >> 8;
+ br = addbranch(oc, br, oc0);
+ }
+ if (oc->ocres >= 256) {
+ oc0 = ((x & 512) + (y & 256) + (z & 128)) >> 7;
+ br = addbranch(oc, br, oc0);
+ }
+ if (oc->ocres >= 128) {
+ oc0 = ((x & 256) + (y & 128) + (z & 64)) >> 6;
+ br = addbranch(oc, br, oc0);
+ }
+
+ oc0 = ((x & 128) + (y & 64) + (z & 32)) >> 5;
+ oc1 = ((x & 64) + (y & 32) + (z & 16)) >> 4;
+ oc2 = ((x & 32) + (y & 16) + (z & 8)) >> 3;
+ oc3 = ((x & 16) + (y & 8) + (z & 4)) >> 2;
+ oc4 = ((x & 8) + (y & 4) + (z & 2)) >> 1;
+ oc5 = ((x & 4) + (y & 2) + (z & 1));
+
+ br = addbranch(oc, br, oc0);
+ br = addbranch(oc, br, oc1);
+ br = addbranch(oc, br, oc2);
+ br = addbranch(oc, br, oc3);
+ br = addbranch(oc, br, oc4);
+ no = (Node *)br->b[oc5];
+ if (no == NULL) br->b[oc5] = (Branch *)(no = addnode(oc));
+
+ while (no->next) no = no->next;
+
+ a = 0;
+ if (no->v[7]) { /* node full */
+ no->next = addnode(oc);
+ no = no->next;
+ }
+ else {
+ while (no->v[a] != NULL) a++;
+ }
+
+ no->v[a] = (RayFace *) RE_rayobject_align(face);
+
+ if (quad)
+ calc_ocval_face(rtf[0], rtf[1], rtf[2], rtf[3], x >> 2, y >> 1, z, &no->ov[a]);
+ else
+ calc_ocval_face(rtf[0], rtf[1], rtf[2], NULL, x >> 2, y >> 1, z, &no->ov[a]);
+}
+
+static void d2dda(Octree *oc, short b1, short b2, short c1, short c2, char *ocface, short rts[4][3], float rtf[4][3])
+{
+ int ocx1, ocx2, ocy1, ocy2;
+ int x, y, dx = 0, dy = 0;
+ float ox1, ox2, oy1, oy2;
+ float lambda, lambda_o, lambda_x, lambda_y, ldx, ldy;
+
+ ocx1 = rts[b1][c1];
+ ocy1 = rts[b1][c2];
+ ocx2 = rts[b2][c1];
+ ocy2 = rts[b2][c2];
+
+ if (ocx1 == ocx2 && ocy1 == ocy2) {
+ ocface[oc->ocres * ocx1 + ocy1] = 1;
+ return;
+ }
+
+ ox1 = rtf[b1][c1];
+ oy1 = rtf[b1][c2];
+ ox2 = rtf[b2][c1];
+ oy2 = rtf[b2][c2];
+
+ if (ox1 != ox2) {
+ if (ox2 - ox1 > 0.0f) {
+ lambda_x = (ox1 - ocx1 - 1.0f) / (ox1 - ox2);
+ ldx = -1.0f / (ox1 - ox2);
+ dx = 1;
+ }
+ else {
+ lambda_x = (ox1 - ocx1) / (ox1 - ox2);
+ ldx = 1.0f / (ox1 - ox2);
+ dx = -1;
+ }
+ }
+ else {
+ lambda_x = 1.0f;
+ ldx = 0;
+ }
+
+ if (oy1 != oy2) {
+ if (oy2 - oy1 > 0.0f) {
+ lambda_y = (oy1 - ocy1 - 1.0f) / (oy1 - oy2);
+ ldy = -1.0f / (oy1 - oy2);
+ dy = 1;
+ }
+ else {
+ lambda_y = (oy1 - ocy1) / (oy1 - oy2);
+ ldy = 1.0f / (oy1 - oy2);
+ dy = -1;
+ }
+ }
+ else {
+ lambda_y = 1.0f;
+ ldy = 0;
+ }
+
+ x = ocx1; y = ocy1;
+ lambda = MIN2(lambda_x, lambda_y);
+
+ while (true) {
+
+ if (x < 0 || y < 0 || x >= oc->ocres || y >= oc->ocres) {
+ /* pass*/
+ }
+ else {
+ ocface[oc->ocres * x + y] = 1;
+ }
+
+ lambda_o = lambda;
+ if (lambda_x == lambda_y) {
+ lambda_x += ldx;
+ x += dx;
+ lambda_y += ldy;
+ y += dy;
+ }
+ else {
+ if (lambda_x < lambda_y) {
+ lambda_x += ldx;
+ x += dx;
+ }
+ else {
+ lambda_y += ldy;
+ y += dy;
+ }
+ }
+ lambda = MIN2(lambda_x, lambda_y);
+ if (lambda == lambda_o) break;
+ if (lambda >= 1.0f) break;
+ }
+ ocface[oc->ocres * ocx2 + ocy2] = 1;
+}
+
+static void filltriangle(Octree *oc, short c1, short c2, char *ocface, short *ocmin, short *ocmax)
+{
+ int a, x, y, y1, y2;
+
+ for (x = ocmin[c1]; x <= ocmax[c1]; x++) {
+ a = oc->ocres * x;
+ for (y = ocmin[c2]; y <= ocmax[c2]; y++) {
+ if (ocface[a + y]) {
+ y++;
+ while (ocface[a + y] && y != ocmax[c2]) y++;
+ for (y1 = ocmax[c2]; y1 > y; y1--) {
+ if (ocface[a + y1]) {
+ for (y2 = y; y2 <= y1; y2++) ocface[a + y2] = 1;
+ y1 = 0;
+ }
+ }
+ y = ocmax[c2];
+ }
+ }
+ }
+}
+
+static void RE_rayobject_octree_free(RayObject *tree)
+{
+ Octree *oc = (Octree *)tree;
+
+#if 0
+ printf("branches %d nodes %d\n", oc->branchcount, oc->nodecount);
+ printf("raycount %d\n", raycount);
+ printf("ray coherent %d\n", coherent_ray);
+ printf("accepted %d rejected %d\n", accepted, rejected);
+#endif
+ if (oc->ocface)
+ MEM_freeN(oc->ocface);
+
+ if (oc->adrbranch) {
+ int a = 0;
+ while (oc->adrbranch[a]) {
+ MEM_freeN(oc->adrbranch[a]);
+ oc->adrbranch[a] = NULL;
+ a++;
+ }
+ MEM_freeN(oc->adrbranch);
+ oc->adrbranch = NULL;
+ }
+ oc->branchcount = 0;
+
+ if (oc->adrnode) {
+ int a = 0;
+ while (oc->adrnode[a]) {
+ MEM_freeN(oc->adrnode[a]);
+ oc->adrnode[a] = NULL;
+ a++;
+ }
+ MEM_freeN(oc->adrnode);
+ oc->adrnode = NULL;
+ }
+ oc->nodecount = 0;
+
+ MEM_freeN(oc);
+}
+
+
+RayObject *RE_rayobject_octree_create(int ocres, int size)
+{
+ Octree *oc = (Octree *)MEM_callocN(sizeof(Octree), "Octree");
+ assert(RE_rayobject_isAligned(oc) ); /* RayObject API assumes real data to be 4-byte aligned */
+
+ oc->rayobj.api = &octree_api;
+
+ oc->ocres = ocres;
+
+ oc->ro_nodes = (RayFace **)MEM_callocN(sizeof(RayFace *) * size, "octree rayobject nodes");
+ oc->ro_nodes_size = size;
+ oc->ro_nodes_used = 0;
+
+
+ return RE_rayobject_unalignRayAPI((RayObject *) oc);
+}
+
+
+static void RE_rayobject_octree_add(RayObject *tree, RayObject *node)
+{
+ Octree *oc = (Octree *)tree;
+
+ assert(RE_rayobject_isRayFace(node) );
+ assert(oc->ro_nodes_used < oc->ro_nodes_size);
+ oc->ro_nodes[oc->ro_nodes_used++] = (RayFace *)RE_rayobject_align(node);
+}
+
+static void octree_fill_rayface(Octree *oc, RayFace *face)
+{
+ float ocfac[3], rtf[4][3];
+ float co1[3], co2[3], co3[3], co4[3];
+ short rts[4][3];
+ short ocmin[3], ocmax[3];
+ char *ocface = oc->ocface; // front, top, size view of face, to fill in
+ int a, b, c, oc1, oc2, oc3, oc4, x, y, z, ocres2;
+
+ ocfac[0] = oc->ocfacx;
+ ocfac[1] = oc->ocfacy;
+ ocfac[2] = oc->ocfacz;
+
+ ocres2 = oc->ocres * oc->ocres;
+
+ copy_v3_v3(co1, face->v1);
+ copy_v3_v3(co2, face->v2);
+ copy_v3_v3(co3, face->v3);
+ if (RE_rayface_isQuad(face))
+ copy_v3_v3(co4, face->v4);
+
+ for (c = 0; c < 3; c++) {
+ rtf[0][c] = (co1[c] - oc->min[c]) * ocfac[c];
+ rts[0][c] = (short)rtf[0][c];
+ rtf[1][c] = (co2[c] - oc->min[c]) * ocfac[c];
+ rts[1][c] = (short)rtf[1][c];
+ rtf[2][c] = (co3[c] - oc->min[c]) * ocfac[c];
+ rts[2][c] = (short)rtf[2][c];
+ if (RE_rayface_isQuad(face)) {
+ rtf[3][c] = (co4[c] - oc->min[c]) * ocfac[c];
+ rts[3][c] = (short)rtf[3][c];
+ }
+ }
+
+ for (c = 0; c < 3; c++) {
+ oc1 = rts[0][c];
+ oc2 = rts[1][c];
+ oc3 = rts[2][c];
+ if (!RE_rayface_isQuad(face)) {
+ ocmin[c] = min_iii(oc1, oc2, oc3);
+ ocmax[c] = max_iii(oc1, oc2, oc3);
+ }
+ else {
+ oc4 = rts[3][c];
+ ocmin[c] = min_iiii(oc1, oc2, oc3, oc4);
+ ocmax[c] = max_iiii(oc1, oc2, oc3, oc4);
+ }
+ if (ocmax[c] > oc->ocres - 1) ocmax[c] = oc->ocres - 1;
+ if (ocmin[c] < 0) ocmin[c] = 0;
+ }
+
+ if (ocmin[0] == ocmax[0] && ocmin[1] == ocmax[1] && ocmin[2] == ocmax[2]) {
+ ocwrite(oc, face, RE_rayface_isQuad(face), ocmin[0], ocmin[1], ocmin[2], rtf);
+ }
+ else {
+
+ d2dda(oc, 0, 1, 0, 1, ocface + ocres2, rts, rtf);
+ d2dda(oc, 0, 1, 0, 2, ocface, rts, rtf);
+ d2dda(oc, 0, 1, 1, 2, ocface + 2 * ocres2, rts, rtf);
+ d2dda(oc, 1, 2, 0, 1, ocface + ocres2, rts, rtf);
+ d2dda(oc, 1, 2, 0, 2, ocface, rts, rtf);
+ d2dda(oc, 1, 2, 1, 2, ocface + 2 * ocres2, rts, rtf);
+ if (!RE_rayface_isQuad(face)) {
+ d2dda(oc, 2, 0, 0, 1, ocface + ocres2, rts, rtf);
+ d2dda(oc, 2, 0, 0, 2, ocface, rts, rtf);
+ d2dda(oc, 2, 0, 1, 2, ocface + 2 * ocres2, rts, rtf);
+ }
+ else {
+ d2dda(oc, 2, 3, 0, 1, ocface + ocres2, rts, rtf);
+ d2dda(oc, 2, 3, 0, 2, ocface, rts, rtf);
+ d2dda(oc, 2, 3, 1, 2, ocface + 2 * ocres2, rts, rtf);
+ d2dda(oc, 3, 0, 0, 1, ocface + ocres2, rts, rtf);
+ d2dda(oc, 3, 0, 0, 2, ocface, rts, rtf);
+ d2dda(oc, 3, 0, 1, 2, ocface + 2 * ocres2, rts, rtf);
+ }
+ /* nothing todo with triangle..., just fills :) */
+ filltriangle(oc, 0, 1, ocface + ocres2, ocmin, ocmax);
+ filltriangle(oc, 0, 2, ocface, ocmin, ocmax);
+ filltriangle(oc, 1, 2, ocface + 2 * ocres2, ocmin, ocmax);
+
+ /* init static vars here */
+ face_in_node(face, 0, 0, 0, rtf);
+
+ for (x = ocmin[0]; x <= ocmax[0]; x++) {
+ a = oc->ocres * x;
+ for (y = ocmin[1]; y <= ocmax[1]; y++) {
+ if (ocface[a + y + ocres2]) {
+ b = oc->ocres * y + 2 * ocres2;
+ for (z = ocmin[2]; z <= ocmax[2]; z++) {
+ if (ocface[b + z] && ocface[a + z]) {
+ if (face_in_node(NULL, x, y, z, rtf))
+ ocwrite(oc, face, RE_rayface_isQuad(face), x, y, z, rtf);
+ }
+ }
+ }
+ }
+ }
+
+ /* same loops to clear octree, doubt it can be done smarter */
+ for (x = ocmin[0]; x <= ocmax[0]; x++) {
+ a = oc->ocres * x;
+ for (y = ocmin[1]; y <= ocmax[1]; y++) {
+ /* x-y */
+ ocface[a + y + ocres2] = 0;
+
+ b = oc->ocres * y + 2 * ocres2;
+ for (z = ocmin[2]; z <= ocmax[2]; z++) {
+ /* y-z */
+ ocface[b + z] = 0;
+ /* x-z */
+ ocface[a + z] = 0;
+ }
+ }
+ }
+ }
+}
+
+static void RE_rayobject_octree_done(RayObject *tree)
+{
+ Octree *oc = (Octree *)tree;
+ int c;
+ float t00, t01, t02;
+ int ocres2 = oc->ocres * oc->ocres;
+
+ INIT_MINMAX(oc->min, oc->max);
+
+ /* Calculate Bounding Box */
+ for (c = 0; c < oc->ro_nodes_used; c++)
+ RE_rayobject_merge_bb(RE_rayobject_unalignRayFace(oc->ro_nodes[c]), oc->min, oc->max);
+
+ /* Alloc memory */
+ oc->adrbranch = (Branch **)MEM_callocN(sizeof(void *) * BRANCH_ARRAY, "octree branches");
+ oc->adrnode = (Node **)MEM_callocN(sizeof(void *) * NODE_ARRAY, "octree nodes");
+
+ oc->adrbranch[0] = (Branch *)MEM_callocN(4096 * sizeof(Branch), "makeoctree");
+
+ /* the lookup table, per face, for which nodes to fill in */
+ oc->ocface = (char *)MEM_callocN(3 * ocres2 + 8, "ocface");
+ memset(oc->ocface, 0, 3 * ocres2);
+
+ for (c = 0; c < 3; c++) { /* octree enlarge, still needed? */
+ oc->min[c] -= 0.01f;
+ oc->max[c] += 0.01f;
+ }
+
+ t00 = oc->max[0] - oc->min[0];
+ t01 = oc->max[1] - oc->min[1];
+ t02 = oc->max[2] - oc->min[2];
+
+ /* this minus 0.1 is old safety... seems to be needed? */
+ oc->ocfacx = (oc->ocres - 0.1f) / t00;
+ oc->ocfacy = (oc->ocres - 0.1f) / t01;
+ oc->ocfacz = (oc->ocres - 0.1f) / t02;
+
+ oc->ocsize = sqrtf(t00 * t00 + t01 * t01 + t02 * t02); /* global, max size octree */
+
+ for (c = 0; c < oc->ro_nodes_used; c++) {
+ octree_fill_rayface(oc, oc->ro_nodes[c]);
+ }
+
+ MEM_freeN(oc->ocface);
+ oc->ocface = NULL;
+ MEM_freeN(oc->ro_nodes);
+ oc->ro_nodes = NULL;
+
+#if 0
+ printf("%f %f - %f\n", oc->min[0], oc->max[0], oc->ocfacx);
+ printf("%f %f - %f\n", oc->min[1], oc->max[1], oc->ocfacy);
+ printf("%f %f - %f\n", oc->min[2], oc->max[2], oc->ocfacz);
+#endif
+}
+
+static void RE_rayobject_octree_bb(RayObject *tree, float *min, float *max)
+{
+ Octree *oc = (Octree *)tree;
+ DO_MINMAX(oc->min, min, max);
+ DO_MINMAX(oc->max, min, max);
+}
+
+/* check all faces in this node */
+static int testnode(Octree *UNUSED(oc), Isect *is, Node *no, OcVal ocval)
+{
+ short nr = 0;
+
+ /* return on any first hit */
+ if (is->mode == RE_RAY_SHADOW) {
+
+ for (; no; no = no->next) {
+ for (nr = 0; nr < 8; nr++) {
+ RayFace *face = no->v[nr];
+ OcVal *ov = no->ov + nr;
+
+ if (!face) break;
+
+ if ( (ov->ocx & ocval.ocx) && (ov->ocy & ocval.ocy) && (ov->ocz & ocval.ocz) ) {
+ if (RE_rayobject_intersect(RE_rayobject_unalignRayFace(face), is) )
+ return 1;
+ }
+ }
+ }
+ }
+ else {
+ /* else mirror or glass or shadowtra, return closest face */
+ int found = 0;
+
+ for (; no; no = no->next) {
+ for (nr = 0; nr < 8; nr++) {
+ RayFace *face = no->v[nr];
+ OcVal *ov = no->ov + nr;
+
+ if (!face) break;
+
+ if ( (ov->ocx & ocval.ocx) && (ov->ocy & ocval.ocy) && (ov->ocz & ocval.ocz) ) {
+ if (RE_rayobject_intersect(RE_rayobject_unalignRayFace(face), is) ) {
+ found = 1;
+ }
+ }
+ }
+ }
+
+ return found;
+ }
+
+ return 0;
+}
+
+/* find the Node for the octree coord x y z */
+static Node *ocread(Octree *oc, int x, int y, int z)
+{
+ Branch *br;
+ int oc1;
+
+ x <<= 2;
+ y <<= 1;
+
+ br = oc->adrbranch[0];
+
+ if (oc->ocres == 512) {
+ oc1 = ((x & 1024) + (y & 512) + (z & 256)) >> 8;
+ br = br->b[oc1];
+ if (br == NULL) {
+ return NULL;
+ }
+ }
+ if (oc->ocres >= 256) {
+ oc1 = ((x & 512) + (y & 256) + (z & 128)) >> 7;
+ br = br->b[oc1];
+ if (br == NULL) {
+ return NULL;
+ }
+ }
+ if (oc->ocres >= 128) {
+ oc1 = ((x & 256) + (y & 128) + (z & 64)) >> 6;
+ br = br->b[oc1];
+ if (br == NULL) {
+ return NULL;
+ }
+ }
+
+ oc1 = ((x & 128) + (y & 64) + (z & 32)) >> 5;
+ br = br->b[oc1];
+ if (br) {
+ oc1 = ((x & 64) + (y & 32) + (z & 16)) >> 4;
+ br = br->b[oc1];
+ if (br) {
+ oc1 = ((x & 32) + (y & 16) + (z & 8)) >> 3;
+ br = br->b[oc1];
+ if (br) {
+ oc1 = ((x & 16) + (y & 8) + (z & 4)) >> 2;
+ br = br->b[oc1];
+ if (br) {
+ oc1 = ((x & 8) + (y & 4) + (z & 2)) >> 1;
+ br = br->b[oc1];
+ if (br) {
+ oc1 = ((x & 4) + (y & 2) + (z & 1));
+ return (Node *)br->b[oc1];
+ }
+ }
+ }
+ }
+ }
+
+ return NULL;
+}
+
+static int cliptest(float p, float q, float *u1, float *u2)
+{
+ float r;
+
+ if (p < 0.0f) {
+ if (q < p) return 0;
+ else if (q < 0.0f) {
+ r = q / p;
+ if (r > *u2) return 0;
+ else if (r > *u1) *u1 = r;
+ }
+ }
+ else {
+ if (p > 0.0f) {
+ if (q < 0.0f) return 0;
+ else if (q < p) {
+ r = q / p;
+ if (r < *u1) return 0;
+ else if (r < *u2) *u2 = r;
+ }
+ }
+ else if (q < 0.0f) return 0;
+ }
+ return 1;
+}
+
+/* extensive coherence checks/storage cancels out the benefit of it, and gives errors... we
+ * need better methods, sample code commented out below (ton) */
+
+#if 0
+
+in top : static int coh_nodes[16 * 16 * 16][6];
+in makeoctree : memset(coh_nodes, 0, sizeof(coh_nodes));
+
+static void add_coherence_test(int ocx1, int ocx2, int ocy1, int ocy2, int ocz1, int ocz2)
+{
+ short *sp;
+
+ sp = coh_nodes[(ocx2 & 15) + 16 * (ocy2 & 15) + 256 * (ocz2 & 15)];
+ sp[0] = ocx1; sp[1] = ocy1; sp[2] = ocz1;
+ sp[3] = ocx2; sp[4] = ocy2; sp[5] = ocz2;
+
+}
+
+static int do_coherence_test(int ocx1, int ocx2, int ocy1, int ocy2, int ocz1, int ocz2)
+{
+ short *sp;
+
+ sp = coh_nodes[(ocx2 & 15) + 16 * (ocy2 & 15) + 256 * (ocz2 & 15)];
+ if (sp[0] == ocx1 && sp[1] == ocy1 && sp[2] == ocz1 &&
+ sp[3] == ocx2 && sp[4] == ocy2 && sp[5] == ocz2) return 1;
+ return 0;
+}
+
+#endif
+
+/* return 1: found valid intersection */
+/* starts with is->orig.face */
+static int RE_rayobject_octree_intersect(RayObject *tree, Isect *is)
+{
+ Octree *oc = (Octree *)tree;
+ Node *no;
+ OcVal ocval;
+ float vec1[3], vec2[3], start[3], end[3];
+ float u1, u2, ox1, ox2, oy1, oy2, oz1, oz2;
+ float lambda_o, lambda_x, ldx, lambda_y, ldy, lambda_z, ldz, dda_lambda;
+ float o_lambda = 0;
+ int dx, dy, dz;
+ int xo, yo, zo, c1 = 0;
+ int ocx1, ocx2, ocy1, ocy2, ocz1, ocz2;
+
+ /* clip with octree */
+ if (oc->branchcount == 0) return 0;
+
+ /* do this before intersect calls */
+#if 0
+ is->facecontr = NULL; /* to check shared edge */
+ is->obcontr = 0;
+ is->faceisect = is->isect = 0; /* shared edge, quad half flag */
+ is->userdata = oc->userdata;
+#endif
+
+ copy_v3_v3(start, is->start);
+ madd_v3_v3v3fl(end, is->start, is->dir, is->dist);
+ ldx = is->dir[0] * is->dist;
+ o_lambda = is->dist;
+ u1 = 0.0f;
+ u2 = 1.0f;
+
+ /* clip with octree cube */
+ if (cliptest(-ldx, start[0] - oc->min[0], &u1, &u2)) {
+ if (cliptest(ldx, oc->max[0] - start[0], &u1, &u2)) {
+ ldy = is->dir[1] * is->dist;
+ if (cliptest(-ldy, start[1] - oc->min[1], &u1, &u2)) {
+ if (cliptest(ldy, oc->max[1] - start[1], &u1, &u2)) {
+ ldz = is->dir[2] * is->dist;
+ if (cliptest(-ldz, start[2] - oc->min[2], &u1, &u2)) {
+ if (cliptest(ldz, oc->max[2] - start[2], &u1, &u2)) {
+ c1 = 1;
+ if (u2 < 1.0f) {
+ end[0] = start[0] + u2 * ldx;
+ end[1] = start[1] + u2 * ldy;
+ end[2] = start[2] + u2 * ldz;
+ }
+
+ if (u1 > 0.0f) {
+ start[0] += u1 * ldx;
+ start[1] += u1 * ldy;
+ start[2] += u1 * ldz;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if (c1 == 0) return 0;
+
+ /* reset static variables in ocread */
+ //ocread(oc, oc->ocres, 0, 0);
+
+ /* setup 3dda to traverse octree */
+ ox1 = (start[0] - oc->min[0]) * oc->ocfacx;
+ oy1 = (start[1] - oc->min[1]) * oc->ocfacy;
+ oz1 = (start[2] - oc->min[2]) * oc->ocfacz;
+ ox2 = (end[0] - oc->min[0]) * oc->ocfacx;
+ oy2 = (end[1] - oc->min[1]) * oc->ocfacy;
+ oz2 = (end[2] - oc->min[2]) * oc->ocfacz;
+
+ ocx1 = (int)ox1;
+ ocy1 = (int)oy1;
+ ocz1 = (int)oz1;
+ ocx2 = (int)ox2;
+ ocy2 = (int)oy2;
+ ocz2 = (int)oz2;
+
+ if (ocx1 == ocx2 && ocy1 == ocy2 && ocz1 == ocz2) {
+ no = ocread(oc, ocx1, ocy1, ocz1);
+ if (no) {
+ /* exact intersection with node */
+ vec1[0] = ox1; vec1[1] = oy1; vec1[2] = oz1;
+ vec2[0] = ox2; vec2[1] = oy2; vec2[2] = oz2;
+ calc_ocval_ray(&ocval, (float)ocx1, (float)ocy1, (float)ocz1, vec1, vec2);
+ if (testnode(oc, is, no, ocval) ) return 1;
+ }
+ }
+ else {
+ int found = 0;
+ //static int coh_ocx1, coh_ocx2, coh_ocy1, coh_ocy2, coh_ocz1, coh_ocz2;
+ float dox, doy, doz;
+ int eqval;
+
+ /* calc lambda en ld */
+ dox = ox1 - ox2;
+ doy = oy1 - oy2;
+ doz = oz1 - oz2;
+
+ if (dox < -FLT_EPSILON) {
+ ldx = -1.0f / dox;
+ lambda_x = (ocx1 - ox1 + 1.0f) * ldx;
+ dx = 1;
+ }
+ else if (dox > FLT_EPSILON) {
+ ldx = 1.0f / dox;
+ lambda_x = (ox1 - ocx1) * ldx;
+ dx = -1;
+ }
+ else {
+ lambda_x = 1.0f;
+ ldx = 0;
+ dx = 0;
+ }
+
+ if (doy < -FLT_EPSILON) {
+ ldy = -1.0f / doy;
+ lambda_y = (ocy1 - oy1 + 1.0f) * ldy;
+ dy = 1;
+ }
+ else if (doy > FLT_EPSILON) {
+ ldy = 1.0f / doy;
+ lambda_y = (oy1 - ocy1) * ldy;
+ dy = -1;
+ }
+ else {
+ lambda_y = 1.0f;
+ ldy = 0;
+ dy = 0;
+ }
+
+ if (doz < -FLT_EPSILON) {
+ ldz = -1.0f / doz;
+ lambda_z = (ocz1 - oz1 + 1.0f) * ldz;
+ dz = 1;
+ }
+ else if (doz > FLT_EPSILON) {
+ ldz = 1.0f / doz;
+ lambda_z = (oz1 - ocz1) * ldz;
+ dz = -1;
+ }
+ else {
+ lambda_z = 1.0f;
+ ldz = 0;
+ dz = 0;
+ }
+
+ xo = ocx1; yo = ocy1; zo = ocz1;
+ dda_lambda = min_fff(lambda_x, lambda_y, lambda_z);
+
+ vec2[0] = ox1;
+ vec2[1] = oy1;
+ vec2[2] = oz1;
+
+ /* this loop has been constructed to make sure the first and last node of ray
+ * are always included, even when dda_lambda==1.0f or larger */
+
+ while (true) {
+
+ no = ocread(oc, xo, yo, zo);
+ if (no) {
+
+ /* calculate ray intersection with octree node */
+ copy_v3_v3(vec1, vec2);
+ // dox, y, z is negative
+ vec2[0] = ox1 - dda_lambda * dox;
+ vec2[1] = oy1 - dda_lambda * doy;
+ vec2[2] = oz1 - dda_lambda * doz;
+ calc_ocval_ray(&ocval, (float)xo, (float)yo, (float)zo, vec1, vec2);
+
+ //is->dist = (u1 + dda_lambda * (u2 - u1)) * o_lambda;
+ if (testnode(oc, is, no, ocval) )
+ found = 1;
+
+ if (is->dist < (u1 + dda_lambda * (u2 - u1)) * o_lambda)
+ return found;
+ }
+
+
+ lambda_o = dda_lambda;
+
+ /* traversing octree nodes need careful detection of smallest values, with proper
+ * exceptions for equal lambdas */
+ eqval = (lambda_x == lambda_y);
+ if (lambda_y == lambda_z) eqval += 2;
+ if (lambda_x == lambda_z) eqval += 4;
+
+ if (eqval) { // only 4 cases exist!
+ if (eqval == 7) { // x=y=z
+ xo += dx; lambda_x += ldx;
+ yo += dy; lambda_y += ldy;
+ zo += dz; lambda_z += ldz;
+ }
+ else if (eqval == 1) { // x=y
+ if (lambda_y < lambda_z) {
+ xo += dx; lambda_x += ldx;
+ yo += dy; lambda_y += ldy;
+ }
+ else {
+ zo += dz; lambda_z += ldz;
+ }
+ }
+ else if (eqval == 2) { // y=z
+ if (lambda_x < lambda_y) {
+ xo += dx; lambda_x += ldx;
+ }
+ else {
+ yo += dy; lambda_y += ldy;
+ zo += dz; lambda_z += ldz;
+ }
+ }
+ else { // x=z
+ if (lambda_y < lambda_x) {
+ yo += dy; lambda_y += ldy;
+ }
+ else {
+ xo += dx; lambda_x += ldx;
+ zo += dz; lambda_z += ldz;
+ }
+ }
+ }
+ else { // all three different, just three cases exist
+ eqval = (lambda_x < lambda_y);
+ if (lambda_y < lambda_z) eqval += 2;
+ if (lambda_x < lambda_z) eqval += 4;
+
+ if (eqval == 7 || eqval == 5) { // x smallest
+ xo += dx; lambda_x += ldx;
+ }
+ else if (eqval == 2 || eqval == 6) { // y smallest
+ yo += dy; lambda_y += ldy;
+ }
+ else { // z smallest
+ zo += dz; lambda_z += ldz;
+ }
+
+ }
+
+ dda_lambda = min_fff(lambda_x, lambda_y, lambda_z);
+ if (dda_lambda == lambda_o) break;
+ /* to make sure the last node is always checked */
+ if (lambda_o >= 1.0f) break;
+ }
+ }
+
+ /* reached end, no intersections found */
+ return 0;
+}
+
+
+
diff --git a/source/blender/render/intern/raytrace/rayobject_qbvh.cpp b/source/blender/render/intern/raytrace/rayobject_qbvh.cpp
new file mode 100644
index 00000000000..8e3dd87efd1
--- /dev/null
+++ b/source/blender/render/intern/raytrace/rayobject_qbvh.cpp
@@ -0,0 +1,160 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2009 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): André Pinto.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/render/intern/raytrace/rayobject_qbvh.cpp
+ * \ingroup render
+ */
+
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_utildefines.h"
+
+#include "vbvh.h"
+#include "svbvh.h"
+#include "reorganize.h"
+
+#ifdef __SSE__
+
+#define DFS_STACK_SIZE 256
+
+struct QBVHTree {
+ RayObject rayobj;
+
+ SVBVHNode *root;
+ MemArena *node_arena;
+
+ float cost;
+ RTBuilder *builder;
+};
+
+
+template<>
+void bvh_done<QBVHTree>(QBVHTree *obj)
+{
+ rtbuild_done(obj->builder, &obj->rayobj.control);
+
+ //TODO find a away to exactly calculate the needed memory
+ MemArena *arena1 = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, "qbvh arena");
+ BLI_memarena_use_malloc(arena1);
+
+ MemArena *arena2 = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, "qbvh arena 2");
+ BLI_memarena_use_malloc(arena2);
+ BLI_memarena_use_align(arena2, 16);
+
+ //Build and optimize the tree
+ //TODO do this in 1 pass (half memory usage during building)
+ VBVHNode *root = BuildBinaryVBVH<VBVHNode>(arena1, &obj->rayobj.control).transform(obj->builder);
+
+ if (RE_rayobjectcontrol_test_break(&obj->rayobj.control)) {
+ BLI_memarena_free(arena1);
+ BLI_memarena_free(arena2);
+ return;
+ }
+
+ if (root) {
+ pushup_simd<VBVHNode, 4>(root);
+ obj->root = Reorganize_SVBVH<VBVHNode>(arena2).transform(root);
+ }
+ else
+ obj->root = NULL;
+
+ //Free data
+ BLI_memarena_free(arena1);
+
+ obj->node_arena = arena2;
+ obj->cost = 1.0;
+
+ rtbuild_free(obj->builder);
+ obj->builder = NULL;
+}
+
+template<int StackSize>
+static int intersect(QBVHTree *obj, Isect *isec)
+{
+ //TODO renable hint support
+ if (RE_rayobject_isAligned(obj->root)) {
+ if (isec->mode == RE_RAY_SHADOW)
+ return svbvh_node_stack_raycast<StackSize, true>(obj->root, isec);
+ else
+ return svbvh_node_stack_raycast<StackSize, false>(obj->root, isec);
+ }
+ else
+ return RE_rayobject_intersect((RayObject *)obj->root, isec);
+}
+
+template<class Tree>
+static void bvh_hint_bb(Tree *tree, LCTSHint *hint, float *UNUSED(min), float *UNUSED(max))
+{
+ //TODO renable hint support
+ {
+ hint->size = 0;
+ hint->stack[hint->size++] = (RayObject *)tree->root;
+ }
+}
+/* the cast to pointer function is needed to workarround gcc bug: http://gcc.gnu.org/bugzilla/show_bug.cgi?id=11407 */
+template<class Tree, int STACK_SIZE>
+static RayObjectAPI make_api()
+{
+ static RayObjectAPI api =
+ {
+ (RE_rayobject_raycast_callback) ((int (*)(Tree *, Isect *)) & intersect<STACK_SIZE>),
+ (RE_rayobject_add_callback) ((void (*)(Tree *, RayObject *)) & bvh_add<Tree>),
+ (RE_rayobject_done_callback) ((void (*)(Tree *)) & bvh_done<Tree>),
+ (RE_rayobject_free_callback) ((void (*)(Tree *)) & bvh_free<Tree>),
+ (RE_rayobject_merge_bb_callback)((void (*)(Tree *, float *, float *)) & bvh_bb<Tree>),
+ (RE_rayobject_cost_callback) ((float (*)(Tree *)) & bvh_cost<Tree>),
+ (RE_rayobject_hint_bb_callback) ((void (*)(Tree *, LCTSHint *, float *, float *)) & bvh_hint_bb<Tree>)
+ };
+
+ return api;
+}
+
+template<class Tree>
+RayObjectAPI *bvh_get_api(int maxstacksize)
+{
+ static RayObjectAPI bvh_api256 = make_api<Tree, 1024>();
+
+ if (maxstacksize <= 1024) return &bvh_api256;
+ assert(maxstacksize <= 256);
+ return NULL;
+}
+
+RayObject *RE_rayobject_qbvh_create(int size)
+{
+ return bvh_create_tree<QBVHTree, DFS_STACK_SIZE>(size);
+}
+
+#else
+
+RayObject *RE_rayobject_qbvh_create(int UNUSED(size))
+{
+ puts("WARNING: SSE disabled at compile time\n");
+ return NULL;
+}
+
+#endif
diff --git a/source/blender/render/intern/raytrace/rayobject_raycounter.cpp b/source/blender/render/intern/raytrace/rayobject_raycounter.cpp
new file mode 100644
index 00000000000..429c47f1c0f
--- /dev/null
+++ b/source/blender/render/intern/raytrace/rayobject_raycounter.cpp
@@ -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) 2009 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): André Pinto.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/render/intern/raytrace/rayobject_raycounter.cpp
+ * \ingroup render
+ */
+
+
+#include "rayobject.h"
+#include "raycounter.h"
+
+#ifdef RE_RAYCOUNTER
+
+void RE_RC_INFO(RayCounter *info)
+{
+ printf("----------- Raycast counter --------\n");
+ printf("Rays total: %llu\n", info->raycast.test );
+ printf("Rays hit: %llu\n", info->raycast.hit );
+ printf("\n");
+ printf("BB tests: %llu\n", info->bb.test );
+ printf("BB hits: %llu\n", info->bb.hit );
+ printf("\n");
+ printf("SIMD BB tests: %llu\n", info->simd_bb.test );
+ printf("SIMD BB hits: %llu\n", info->simd_bb.hit );
+ printf("\n");
+ printf("Primitives tests: %llu\n", info->faces.test );
+ printf("Primitives hits: %llu\n", info->faces.hit );
+ printf("------------------------------------\n");
+ printf("Shadow last-hit tests per ray: %f\n", info->rayshadow_last_hit.test / ((float)info->raycast.test) );
+ printf("Shadow last-hit hits per ray: %f\n", info->rayshadow_last_hit.hit / ((float)info->raycast.test) );
+ printf("\n");
+ printf("Hint tests per ray: %f\n", info->raytrace_hint.test / ((float)info->raycast.test) );
+ printf("Hint hits per ray: %f\n", info->raytrace_hint.hit / ((float)info->raycast.test) );
+ printf("\n");
+ printf("BB tests per ray: %f\n", info->bb.test / ((float)info->raycast.test) );
+ printf("BB hits per ray: %f\n", info->bb.hit / ((float)info->raycast.test) );
+ printf("\n");
+ printf("SIMD tests per ray: %f\n", info->simd_bb.test / ((float)info->raycast.test) );
+ printf("SIMD hits per ray: %f\n", info->simd_bb.hit / ((float)info->raycast.test) );
+ printf("\n");
+ printf("Primitives tests per ray: %f\n", info->faces.test / ((float)info->raycast.test) );
+ printf("Primitives hits per ray: %f\n", info->faces.hit / ((float)info->raycast.test) );
+ printf("------------------------------------\n");
+}
+
+void RE_RC_MERGE(RayCounter *dest, RayCounter *tmp)
+{
+ dest->faces.test += tmp->faces.test;
+ dest->faces.hit += tmp->faces.hit;
+
+ dest->bb.test += tmp->bb.test;
+ dest->bb.hit += tmp->bb.hit;
+
+ dest->simd_bb.test += tmp->simd_bb.test;
+ dest->simd_bb.hit += tmp->simd_bb.hit;
+
+ dest->raycast.test += tmp->raycast.test;
+ dest->raycast.hit += tmp->raycast.hit;
+
+ dest->rayshadow_last_hit.test += tmp->rayshadow_last_hit.test;
+ dest->rayshadow_last_hit.hit += tmp->rayshadow_last_hit.hit;
+
+ dest->raytrace_hint.test += tmp->raytrace_hint.test;
+ dest->raytrace_hint.hit += tmp->raytrace_hint.hit;
+}
+
+#endif
diff --git a/source/blender/render/intern/raytrace/rayobject_rtbuild.cpp b/source/blender/render/intern/raytrace/rayobject_rtbuild.cpp
new file mode 100644
index 00000000000..51f89784674
--- /dev/null
+++ b/source/blender/render/intern/raytrace/rayobject_rtbuild.cpp
@@ -0,0 +1,531 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2009 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): André Pinto.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/render/intern/raytrace/rayobject_rtbuild.cpp
+ * \ingroup render
+ */
+
+
+#include <assert.h>
+#include <stdlib.h>
+#include <algorithm>
+
+#if __cplusplus >= 201103L
+#include <cmath>
+using std::isfinite;
+#else
+#include <math.h>
+#endif
+
+#include "rayobject_rtbuild.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_math.h"
+#include "BLI_utildefines.h"
+
+static bool selected_node(RTBuilder::Object *node)
+{
+ return node->selected;
+}
+
+static void rtbuild_init(RTBuilder *b)
+{
+ b->split_axis = -1;
+ b->primitives.begin = NULL;
+ b->primitives.end = NULL;
+ b->primitives.maxsize = 0;
+ b->depth = 0;
+
+ for (int i = 0; i < RTBUILD_MAX_CHILDS; i++)
+ b->child_offset[i] = 0;
+
+ for (int i = 0; i < 3; i++)
+ b->sorted_begin[i] = b->sorted_end[i] = NULL;
+
+ INIT_MINMAX(b->bb, b->bb + 3);
+}
+
+RTBuilder *rtbuild_create(int size)
+{
+ RTBuilder *builder = (RTBuilder *) MEM_mallocN(sizeof(RTBuilder), "RTBuilder");
+ RTBuilder::Object *memblock = (RTBuilder::Object *)MEM_mallocN(sizeof(RTBuilder::Object) * size, "RTBuilder.objects");
+
+
+ rtbuild_init(builder);
+
+ builder->primitives.begin = builder->primitives.end = memblock;
+ builder->primitives.maxsize = size;
+
+ for (int i = 0; i < 3; i++) {
+ builder->sorted_begin[i] = (RTBuilder::Object **)MEM_mallocN(sizeof(RTBuilder::Object *) * size, "RTBuilder.sorted_objects");
+ builder->sorted_end[i] = builder->sorted_begin[i];
+ }
+
+
+ return builder;
+}
+
+void rtbuild_free(RTBuilder *b)
+{
+ if (b->primitives.begin) MEM_freeN(b->primitives.begin);
+
+ for (int i = 0; i < 3; i++)
+ if (b->sorted_begin[i])
+ MEM_freeN(b->sorted_begin[i]);
+
+ MEM_freeN(b);
+}
+
+void rtbuild_add(RTBuilder *b, RayObject *o)
+{
+ float bb[6];
+
+ assert(b->primitives.begin + b->primitives.maxsize != b->primitives.end);
+
+ INIT_MINMAX(bb, bb + 3);
+ RE_rayobject_merge_bb(o, bb, bb + 3);
+
+ /* skip objects with invalid bounding boxes, nan causes DO_MINMAX
+ * to do nothing, so we get these invalid values. this shouldn't
+ * happen usually, but bugs earlier in the pipeline can cause it. */
+ if (bb[0] > bb[3] || bb[1] > bb[4] || bb[2] > bb[5])
+ return;
+ /* skip objects with inf bounding boxes */
+ if (!isfinite(bb[0]) || !isfinite(bb[1]) || !isfinite(bb[2]))
+ return;
+ if (!isfinite(bb[3]) || !isfinite(bb[4]) || !isfinite(bb[5]))
+ return;
+ /* skip objects with zero bounding box, they are of no use, and
+ * will give problems in rtbuild_heuristic_object_split later */
+ if (bb[0] == bb[3] && bb[1] == bb[4] && bb[2] == bb[5])
+ return;
+
+ copy_v3_v3(b->primitives.end->bb, bb);
+ copy_v3_v3(b->primitives.end->bb + 3, bb + 3);
+ b->primitives.end->obj = o;
+ b->primitives.end->cost = RE_rayobject_cost(o);
+
+ for (int i = 0; i < 3; i++) {
+ *(b->sorted_end[i]) = b->primitives.end;
+ b->sorted_end[i]++;
+ }
+ b->primitives.end++;
+}
+
+int rtbuild_size(RTBuilder *b)
+{
+ return b->sorted_end[0] - b->sorted_begin[0];
+}
+
+
+template<class Obj, int Axis>
+static bool obj_bb_compare(const Obj &a, const Obj &b)
+{
+ if (a->bb[Axis] != b->bb[Axis])
+ return a->bb[Axis] < b->bb[Axis];
+ return a->obj < b->obj;
+}
+
+template<class Item>
+static void object_sort(Item *begin, Item *end, int axis)
+{
+ if (axis == 0) return std::sort(begin, end, obj_bb_compare<Item, 0> );
+ if (axis == 1) return std::sort(begin, end, obj_bb_compare<Item, 1> );
+ if (axis == 2) return std::sort(begin, end, obj_bb_compare<Item, 2> );
+ assert(false);
+}
+
+void rtbuild_done(RTBuilder *b, RayObjectControl *ctrl)
+{
+ for (int i = 0; i < 3; i++) {
+ if (b->sorted_begin[i]) {
+ if (RE_rayobjectcontrol_test_break(ctrl)) break;
+ object_sort(b->sorted_begin[i], b->sorted_end[i], i);
+ }
+ }
+}
+
+RayObject *rtbuild_get_primitive(RTBuilder *b, int index)
+{
+ return b->sorted_begin[0][index]->obj;
+}
+
+RTBuilder *rtbuild_get_child(RTBuilder *b, int child, RTBuilder *tmp)
+{
+ rtbuild_init(tmp);
+
+ tmp->depth = b->depth + 1;
+
+ for (int i = 0; i < 3; i++)
+ if (b->sorted_begin[i]) {
+ tmp->sorted_begin[i] = b->sorted_begin[i] + b->child_offset[child];
+ tmp->sorted_end[i] = b->sorted_begin[i] + b->child_offset[child + 1];
+ }
+ else {
+ tmp->sorted_begin[i] = NULL;
+ tmp->sorted_end[i] = NULL;
+ }
+
+ return tmp;
+}
+
+static void rtbuild_calc_bb(RTBuilder *b)
+{
+ if (b->bb[0] == 1.0e30f) {
+ for (RTBuilder::Object **index = b->sorted_begin[0]; index != b->sorted_end[0]; index++)
+ RE_rayobject_merge_bb( (*index)->obj, b->bb, b->bb + 3);
+ }
+}
+
+void rtbuild_merge_bb(RTBuilder *b, float min[3], float max[3])
+{
+ rtbuild_calc_bb(b);
+ DO_MIN(b->bb, min);
+ DO_MAX(b->bb + 3, max);
+}
+
+#if 0
+int rtbuild_get_largest_axis(RTBuilder *b)
+{
+ rtbuild_calc_bb(b);
+ return bb_largest_axis(b->bb, b->bb + 3);
+}
+
+//Left balanced tree
+int rtbuild_mean_split(RTBuilder *b, int nchilds, int axis)
+{
+ int i;
+ int mleafs_per_child, Mleafs_per_child;
+ int tot_leafs = rtbuild_size(b);
+ int missing_leafs;
+
+ long long s;
+
+ assert(nchilds <= RTBUILD_MAX_CHILDS);
+
+ //TODO optimize calc of leafs_per_child
+ for (s = nchilds; s < tot_leafs; s *= nchilds) ;
+ Mleafs_per_child = s / nchilds;
+ mleafs_per_child = Mleafs_per_child / nchilds;
+
+ //split min leafs per child
+ b->child_offset[0] = 0;
+ for (i = 1; i <= nchilds; i++)
+ b->child_offset[i] = mleafs_per_child;
+
+ //split remaining leafs
+ missing_leafs = tot_leafs - mleafs_per_child * nchilds;
+ for (i = 1; i <= nchilds; i++)
+ {
+ if (missing_leafs > Mleafs_per_child - mleafs_per_child)
+ {
+ b->child_offset[i] += Mleafs_per_child - mleafs_per_child;
+ missing_leafs -= Mleafs_per_child - mleafs_per_child;
+ }
+ else {
+ b->child_offset[i] += missing_leafs;
+ missing_leafs = 0;
+ break;
+ }
+ }
+
+ //adjust for accumulative offsets
+ for (i = 1; i <= nchilds; i++)
+ b->child_offset[i] += b->child_offset[i - 1];
+
+ //Count created childs
+ for (i = nchilds; b->child_offset[i] == b->child_offset[i - 1]; i--) ;
+ split_leafs(b, b->child_offset, i, axis);
+
+ assert(b->child_offset[0] == 0 && b->child_offset[i] == tot_leafs);
+ return i;
+}
+
+
+int rtbuild_mean_split_largest_axis(RTBuilder *b, int nchilds)
+{
+ int axis = rtbuild_get_largest_axis(b);
+ return rtbuild_mean_split(b, nchilds, axis);
+}
+#endif
+
+/*
+ * "separators" is an array of dim NCHILDS-1
+ * and indicates where to cut the childs
+ */
+#if 0
+int rtbuild_median_split(RTBuilder *b, float *separators, int nchilds, int axis)
+{
+ int size = rtbuild_size(b);
+
+ assert(nchilds <= RTBUILD_MAX_CHILDS);
+ if (size <= nchilds)
+ {
+ return rtbuild_mean_split(b, nchilds, axis);
+ }
+ else {
+ int i;
+
+ b->split_axis = axis;
+
+ //Calculate child offsets
+ b->child_offset[0] = 0;
+ for (i = 0; i < nchilds - 1; i++)
+ b->child_offset[i + 1] = split_leafs_by_plane(b, b->child_offset[i], size, separators[i]);
+ b->child_offset[nchilds] = size;
+
+ for (i = 0; i < nchilds; i++)
+ if (b->child_offset[i + 1] - b->child_offset[i] == size)
+ return rtbuild_mean_split(b, nchilds, axis);
+
+ return nchilds;
+ }
+}
+
+int rtbuild_median_split_largest_axis(RTBuilder *b, int nchilds)
+{
+ int la, i;
+ float separators[RTBUILD_MAX_CHILDS];
+
+ rtbuild_calc_bb(b);
+
+ la = bb_largest_axis(b->bb, b->bb + 3);
+ for (i = 1; i < nchilds; i++)
+ separators[i - 1] = (b->bb[la + 3] - b->bb[la]) * i / nchilds;
+
+ return rtbuild_median_split(b, separators, nchilds, la);
+}
+#endif
+
+//Heuristics Object Splitter
+
+
+struct SweepCost {
+ float bb[6];
+ float cost;
+};
+
+/* Object Surface Area Heuristic splitter */
+int rtbuild_heuristic_object_split(RTBuilder *b, int nchilds)
+{
+ int size = rtbuild_size(b);
+ assert(nchilds == 2);
+ assert(size > 1);
+ int baxis = -1, boffset = 0;
+
+ if (size > nchilds) {
+ if (b->depth > RTBUILD_MAX_SAH_DEPTH) {
+ // for degenerate cases we avoid running out of stack space
+ // by simply splitting the children in the middle
+ b->child_offset[0] = 0;
+ b->child_offset[1] = (size+1)/2;
+ b->child_offset[2] = size;
+ return 2;
+ }
+
+ float bcost = FLT_MAX;
+ baxis = -1;
+ boffset = size / 2;
+
+ SweepCost *sweep = (SweepCost *)MEM_mallocN(sizeof(SweepCost) * size, "RTBuilder.HeuristicSweep");
+
+ for (int axis = 0; axis < 3; axis++) {
+ SweepCost sweep_left;
+
+ RTBuilder::Object **obj = b->sorted_begin[axis];
+
+// float right_cost = 0;
+ for (int i = size - 1; i >= 0; i--) {
+ if (i == size - 1) {
+ copy_v3_v3(sweep[i].bb, obj[i]->bb);
+ copy_v3_v3(sweep[i].bb + 3, obj[i]->bb + 3);
+ sweep[i].cost = obj[i]->cost;
+ }
+ else {
+ sweep[i].bb[0] = min_ff(obj[i]->bb[0], sweep[i + 1].bb[0]);
+ sweep[i].bb[1] = min_ff(obj[i]->bb[1], sweep[i + 1].bb[1]);
+ sweep[i].bb[2] = min_ff(obj[i]->bb[2], sweep[i + 1].bb[2]);
+ sweep[i].bb[3] = max_ff(obj[i]->bb[3], sweep[i + 1].bb[3]);
+ sweep[i].bb[4] = max_ff(obj[i]->bb[4], sweep[i + 1].bb[4]);
+ sweep[i].bb[5] = max_ff(obj[i]->bb[5], sweep[i + 1].bb[5]);
+ sweep[i].cost = obj[i]->cost + sweep[i + 1].cost;
+ }
+// right_cost += obj[i]->cost;
+ }
+
+ sweep_left.bb[0] = obj[0]->bb[0];
+ sweep_left.bb[1] = obj[0]->bb[1];
+ sweep_left.bb[2] = obj[0]->bb[2];
+ sweep_left.bb[3] = obj[0]->bb[3];
+ sweep_left.bb[4] = obj[0]->bb[4];
+ sweep_left.bb[5] = obj[0]->bb[5];
+ sweep_left.cost = obj[0]->cost;
+
+// right_cost -= obj[0]->cost; if (right_cost < 0) right_cost = 0;
+
+ for (int i = 1; i < size; i++) {
+ //Worst case heuristic (cost of each child is linear)
+ float hcost, left_side, right_side;
+
+ // not using log seems to have no impact on raytracing perf, but
+ // makes tree construction quicker, left out for now to test (brecht)
+ // left_side = bb_area(sweep_left.bb, sweep_left.bb + 3) * (sweep_left.cost + logf((float)i));
+ // right_side = bb_area(sweep[i].bb, sweep[i].bb + 3) * (sweep[i].cost + logf((float)size - i));
+ left_side = bb_area(sweep_left.bb, sweep_left.bb + 3) * (sweep_left.cost);
+ right_side = bb_area(sweep[i].bb, sweep[i].bb + 3) * (sweep[i].cost);
+ hcost = left_side + right_side;
+
+ assert(left_side >= 0);
+ assert(right_side >= 0);
+
+ if (left_side > bcost) break; //No way we can find a better heuristic in this axis
+
+ assert(hcost >= 0);
+ // this makes sure the tree built is the same whatever is the order of the sorting axis
+ if (hcost < bcost || (hcost == bcost && axis < baxis)) {
+ bcost = hcost;
+ baxis = axis;
+ boffset = i;
+ }
+ DO_MIN(obj[i]->bb, sweep_left.bb);
+ DO_MAX(obj[i]->bb + 3, sweep_left.bb + 3);
+
+ sweep_left.cost += obj[i]->cost;
+// right_cost -= obj[i]->cost; if (right_cost < 0) right_cost = 0;
+ }
+
+ //assert(baxis >= 0 && baxis < 3);
+ if (!(baxis >= 0 && baxis < 3))
+ baxis = 0;
+ }
+
+
+ MEM_freeN(sweep);
+ }
+ else if (size == 2) {
+ baxis = 0;
+ boffset = 1;
+ }
+ else if (size == 1) {
+ b->child_offset[0] = 0;
+ b->child_offset[1] = 1;
+ return 1;
+ }
+
+ b->child_offset[0] = 0;
+ b->child_offset[1] = boffset;
+ b->child_offset[2] = size;
+
+
+ /* Adjust sorted arrays for childs */
+ for (int i = 0; i < boffset; i++) b->sorted_begin[baxis][i]->selected = true;
+ for (int i = boffset; i < size; i++) b->sorted_begin[baxis][i]->selected = false;
+ for (int i = 0; i < 3; i++)
+ std::stable_partition(b->sorted_begin[i], b->sorted_end[i], selected_node);
+
+ return nchilds;
+}
+
+/*
+ * Helper code
+ * PARTITION code / used on mean-split
+ * basically this a std::nth_element (like on C++ STL algorithm)
+ */
+#if 0
+static void split_leafs(RTBuilder *b, int *nth, int partitions, int split_axis)
+{
+ int i;
+ b->split_axis = split_axis;
+
+ for (i = 0; i < partitions - 1; i++)
+ {
+ assert(nth[i] < nth[i + 1] && nth[i + 1] < nth[partitions]);
+
+ if (split_axis == 0) std::nth_element(b, nth[i], nth[i + 1], nth[partitions], obj_bb_compare<RTBuilder::Object, 0>);
+ if (split_axis == 1) std::nth_element(b, nth[i], nth[i + 1], nth[partitions], obj_bb_compare<RTBuilder::Object, 1>);
+ if (split_axis == 2) std::nth_element(b, nth[i], nth[i + 1], nth[partitions], obj_bb_compare<RTBuilder::Object, 2>);
+ }
+}
+#endif
+
+/*
+ * Bounding Box utils
+ */
+float bb_volume(const float min[3], const float max[3])
+{
+ return (max[0] - min[0]) * (max[1] - min[1]) * (max[2] - min[2]);
+}
+
+float bb_area(const float min[3], const float max[3])
+{
+ float sub[3], a;
+ sub[0] = max[0] - min[0];
+ sub[1] = max[1] - min[1];
+ sub[2] = max[2] - min[2];
+
+ a = (sub[0] * sub[1] + sub[0] * sub[2] + sub[1] * sub[2]) * 2.0f;
+ /* used to have an assert() here on negative results
+ * however, in this case its likely some overflow or ffast math error.
+ * so just return 0.0f instead. */
+ return a < 0.0f ? 0.0f : a;
+}
+
+int bb_largest_axis(const float min[3], const float max[3])
+{
+ float sub[3];
+
+ sub[0] = max[0] - min[0];
+ sub[1] = max[1] - min[1];
+ sub[2] = max[2] - min[2];
+ if (sub[0] > sub[1]) {
+ if (sub[0] > sub[2])
+ return 0;
+ else
+ return 2;
+ }
+ else {
+ if (sub[1] > sub[2])
+ return 1;
+ else
+ return 2;
+ }
+}
+
+/* only returns 0 if merging inner and outerbox would create a box larger than outer box */
+int bb_fits_inside(const float outer_min[3], const float outer_max[3],
+ const float inner_min[3], const float inner_max[3])
+{
+ int i;
+ for (i = 0; i < 3; i++)
+ if (outer_min[i] > inner_min[i]) return 0;
+
+ for (i = 0; i < 3; i++)
+ if (outer_max[i] < inner_max[i]) return 0;
+
+ return 1;
+}
diff --git a/source/blender/render/intern/raytrace/rayobject_rtbuild.h b/source/blender/render/intern/raytrace/rayobject_rtbuild.h
new file mode 100644
index 00000000000..fc42bc36d92
--- /dev/null
+++ b/source/blender/render/intern/raytrace/rayobject_rtbuild.h
@@ -0,0 +1,125 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2009 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): André Pinto.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/render/intern/raytrace/rayobject_rtbuild.h
+ * \ingroup render
+ */
+
+#ifndef __RAYOBJECT_RTBUILD_H__
+#define __RAYOBJECT_RTBUILD_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "rayobject.h"
+
+
+/*
+ * Ray Tree Builder
+ * this structs helps building any type of tree
+ * it contains several methods to organize/split nodes
+ * allowing to create a given tree on the fly.
+ *
+ * Idea is that other trees BVH, BIH can use this code to
+ * generate with simple calls, and then convert to the theirs
+ * specific structure on the fly.
+ */
+#define RTBUILD_MAX_CHILDS 32
+#define RTBUILD_MAX_SAH_DEPTH 256
+
+
+typedef struct RTBuilder {
+ struct Object {
+ RayObject *obj;
+ float cost;
+ float bb[6];
+ int selected;
+ };
+
+ /* list to all primitives added in this tree */
+ struct {
+ Object *begin, *end;
+ int maxsize;
+ } primitives;
+
+ /* sorted list of rayobjects */
+ struct Object **sorted_begin[3], **sorted_end[3];
+
+ /* axis used (if any) on the split method */
+ int split_axis;
+
+ /* child partitions calculated during splitting */
+ int child_offset[RTBUILD_MAX_CHILDS + 1];
+
+// int child_sorted_axis; /* -1 if not sorted */
+
+ float bb[6];
+
+ /* current depth */
+ int depth;
+} RTBuilder;
+
+/* used during creation */
+RTBuilder *rtbuild_create(int size);
+void rtbuild_free(RTBuilder *b);
+void rtbuild_add(RTBuilder *b, RayObject *o);
+void rtbuild_done(RTBuilder *b, RayObjectControl *c);
+void rtbuild_merge_bb(RTBuilder *b, float min[3], float max[3]);
+int rtbuild_size(RTBuilder *b);
+
+RayObject *rtbuild_get_primitive(RTBuilder *b, int offset);
+
+/* used during tree reorganization */
+RTBuilder *rtbuild_get_child(RTBuilder *b, int child, RTBuilder *tmp);
+
+/* Calculates child partitions and returns number of efectively needed partitions */
+int rtbuild_get_largest_axis(RTBuilder *b);
+
+//Object partition
+int rtbuild_mean_split(RTBuilder *b, int nchilds, int axis);
+int rtbuild_mean_split_largest_axis(RTBuilder *b, int nchilds);
+
+int rtbuild_heuristic_object_split(RTBuilder *b, int nchilds);
+
+//Space partition
+int rtbuild_median_split(RTBuilder *b, float *separators, int nchilds, int axis);
+int rtbuild_median_split_largest_axis(RTBuilder *b, int nchilds);
+
+
+/* bb utils */
+float bb_area(const float min[3], const float max[3]);
+float bb_volume(const float min[3], const float max[3]);
+int bb_largest_axis(const float min[3], const float max[3]);
+int bb_fits_inside(const float outer_min[3], const float outer_max[3],
+ const float inner_min[3], const float inner_max[3]);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __RAYOBJECT_RTBUILD_H__ */
diff --git a/source/blender/render/intern/raytrace/rayobject_svbvh.cpp b/source/blender/render/intern/raytrace/rayobject_svbvh.cpp
new file mode 100644
index 00000000000..fcd692fac02
--- /dev/null
+++ b/source/blender/render/intern/raytrace/rayobject_svbvh.cpp
@@ -0,0 +1,192 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2009 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): André Pinto.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/render/intern/raytrace/rayobject_svbvh.cpp
+ * \ingroup render
+ */
+
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_utildefines.h"
+
+#include "vbvh.h"
+#include "svbvh.h"
+#include "reorganize.h"
+
+#ifdef __SSE__
+
+#define DFS_STACK_SIZE 256
+
+struct SVBVHTree {
+ RayObject rayobj;
+
+ SVBVHNode *root;
+ MemArena *node_arena;
+
+ float cost;
+ RTBuilder *builder;
+};
+
+/*
+ * Cost to test N childs
+ */
+struct PackCost {
+ float operator()(int n)
+ {
+ return (n / 4) + ((n % 4) > 2 ? 1 : n % 4);
+ }
+};
+
+
+template<>
+void bvh_done<SVBVHTree>(SVBVHTree *obj)
+{
+ rtbuild_done(obj->builder, &obj->rayobj.control);
+
+ //TODO find a away to exactly calculate the needed memory
+ MemArena *arena1 = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, "svbvh arena");
+ BLI_memarena_use_malloc(arena1);
+
+ MemArena *arena2 = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, "svbvh arena2");
+ BLI_memarena_use_malloc(arena2);
+ BLI_memarena_use_align(arena2, 16);
+
+ //Build and optimize the tree
+ if (0) {
+ VBVHNode *root = BuildBinaryVBVH<VBVHNode>(arena1, &obj->rayobj.control).transform(obj->builder);
+
+ if (RE_rayobjectcontrol_test_break(&obj->rayobj.control)) {
+ BLI_memarena_free(arena1);
+ BLI_memarena_free(arena2);
+ return;
+ }
+
+ reorganize(root);
+ remove_useless(root, &root);
+ bvh_refit(root);
+
+ pushup(root);
+ pushdown(root);
+ pushup_simd<VBVHNode, 4>(root);
+
+ obj->root = Reorganize_SVBVH<VBVHNode>(arena2).transform(root);
+ }
+ else {
+ //Finds the optimal packing of this tree using a given cost model
+ //TODO this uses quite a lot of memory, find ways to reduce memory usage during building
+ OVBVHNode *root = BuildBinaryVBVH<OVBVHNode>(arena1, &obj->rayobj.control).transform(obj->builder);
+
+ if (RE_rayobjectcontrol_test_break(&obj->rayobj.control)) {
+ BLI_memarena_free(arena1);
+ BLI_memarena_free(arena2);
+ return;
+ }
+
+ if (root) {
+ VBVH_optimalPackSIMD<OVBVHNode, PackCost>(PackCost()).transform(root);
+ obj->root = Reorganize_SVBVH<OVBVHNode>(arena2).transform(root);
+ }
+ else
+ obj->root = NULL;
+ }
+
+ //Free data
+ BLI_memarena_free(arena1);
+
+ obj->node_arena = arena2;
+ obj->cost = 1.0;
+
+ rtbuild_free(obj->builder);
+ obj->builder = NULL;
+}
+
+template<int StackSize>
+static int intersect(SVBVHTree *obj, Isect *isec)
+{
+ //TODO renable hint support
+ if (RE_rayobject_isAligned(obj->root)) {
+ if (isec->mode == RE_RAY_SHADOW)
+ return svbvh_node_stack_raycast<StackSize, true>(obj->root, isec);
+ else
+ return svbvh_node_stack_raycast<StackSize, false>(obj->root, isec);
+ }
+ else
+ return RE_rayobject_intersect( (RayObject *) obj->root, isec);
+}
+
+template<class Tree>
+static void bvh_hint_bb(Tree *tree, LCTSHint *hint, float *UNUSED(min), float *UNUSED(max))
+{
+ //TODO renable hint support
+ {
+ hint->size = 0;
+ hint->stack[hint->size++] = (RayObject *)tree->root;
+ }
+}
+/* the cast to pointer function is needed to workarround gcc bug: http://gcc.gnu.org/bugzilla/show_bug.cgi?id=11407 */
+template<class Tree, int STACK_SIZE>
+static RayObjectAPI make_api()
+{
+ static RayObjectAPI api =
+ {
+ (RE_rayobject_raycast_callback) ((int (*)(Tree *, Isect *)) & intersect<STACK_SIZE>),
+ (RE_rayobject_add_callback) ((void (*)(Tree *, RayObject *)) & bvh_add<Tree>),
+ (RE_rayobject_done_callback) ((void (*)(Tree *)) & bvh_done<Tree>),
+ (RE_rayobject_free_callback) ((void (*)(Tree *)) & bvh_free<Tree>),
+ (RE_rayobject_merge_bb_callback)((void (*)(Tree *, float *, float *)) & bvh_bb<Tree>),
+ (RE_rayobject_cost_callback) ((float (*)(Tree *)) & bvh_cost<Tree>),
+ (RE_rayobject_hint_bb_callback) ((void (*)(Tree *, LCTSHint *, float *, float *)) & bvh_hint_bb<Tree>)
+ };
+
+ return api;
+}
+
+template<class Tree>
+static RayObjectAPI *bvh_get_api(int maxstacksize)
+{
+ static RayObjectAPI bvh_api256 = make_api<Tree, 1024>();
+
+ if (maxstacksize <= 1024) return &bvh_api256;
+ assert(maxstacksize <= 256);
+ return NULL;
+}
+
+RayObject *RE_rayobject_svbvh_create(int size)
+{
+ return bvh_create_tree<SVBVHTree, DFS_STACK_SIZE>(size);
+}
+
+#else
+
+RayObject *RE_rayobject_svbvh_create(int UNUSED(size))
+{
+ puts("WARNING: SSE disabled at compile time\n");
+ return NULL;
+}
+
+#endif
diff --git a/source/blender/render/intern/raytrace/rayobject_vbvh.cpp b/source/blender/render/intern/raytrace/rayobject_vbvh.cpp
new file mode 100644
index 00000000000..b63a11047dd
--- /dev/null
+++ b/source/blender/render/intern/raytrace/rayobject_vbvh.cpp
@@ -0,0 +1,206 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2009 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): André Pinto.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/render/intern/raytrace/rayobject_vbvh.cpp
+ * \ingroup render
+ */
+
+
+int tot_pushup = 0;
+int tot_pushdown = 0;
+int tot_hints = 0;
+
+#include <assert.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_math.h"
+#include "BLI_memarena.h"
+#include "BLI_utildefines.h"
+
+#include "BKE_global.h"
+
+#include "rayintersection.h"
+#include "rayobject.h"
+#include "rayobject_rtbuild.h"
+
+#include "reorganize.h"
+#include "bvh.h"
+#include "vbvh.h"
+
+#include <queue>
+#include <algorithm>
+
+#define DFS_STACK_SIZE 256
+
+struct VBVHTree {
+ RayObject rayobj;
+ VBVHNode *root;
+ MemArena *node_arena;
+ float cost;
+ RTBuilder *builder;
+};
+
+/*
+ * Cost to test N childs
+ */
+struct PackCost {
+ float operator()(int n)
+ {
+ return n;
+ }
+};
+
+template<>
+void bvh_done<VBVHTree>(VBVHTree *obj)
+{
+ rtbuild_done(obj->builder, &obj->rayobj.control);
+
+ //TODO find a away to exactly calculate the needed memory
+ MemArena *arena1 = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, "vbvh arena");
+ BLI_memarena_use_malloc(arena1);
+
+ //Build and optimize the tree
+ if (1) {
+ VBVHNode *root = BuildBinaryVBVH<VBVHNode>(arena1, &obj->rayobj.control).transform(obj->builder);
+ if (RE_rayobjectcontrol_test_break(&obj->rayobj.control)) {
+ BLI_memarena_free(arena1);
+ return;
+ }
+
+ if (root) {
+ reorganize(root);
+ remove_useless(root, &root);
+ bvh_refit(root);
+
+ pushup(root);
+ pushdown(root);
+ obj->root = root;
+ }
+ else
+ obj->root = NULL;
+ }
+ else {
+ /* TODO */
+#if 0
+ MemArena *arena2 = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, "vbvh arena2");
+ BLI_memarena_use_malloc(arena2);
+
+ //Finds the optimal packing of this tree using a given cost model
+ //TODO this uses quite a lot of memory, find ways to reduce memory usage during building
+ OVBVHNode *root = BuildBinaryVBVH<OVBVHNode>(arena2).transform(obj->builder);
+ VBVH_optimalPackSIMD<OVBVHNode, PackCost>(PackCost()).transform(root);
+ obj->root = Reorganize_VBVH<OVBVHNode>(arena1).transform(root);
+
+ BLI_memarena_free(arena2);
+#endif
+ }
+
+ //Cleanup
+ rtbuild_free(obj->builder);
+ obj->builder = NULL;
+
+ obj->node_arena = arena1;
+ obj->cost = 1.0;
+}
+
+template<int StackSize>
+static int intersect(VBVHTree *obj, Isect *isec)
+{
+ //TODO renable hint support
+ if (RE_rayobject_isAligned(obj->root)) {
+ if (isec->mode == RE_RAY_SHADOW)
+ return bvh_node_stack_raycast<VBVHNode, StackSize, false, true>(obj->root, isec);
+ else
+ return bvh_node_stack_raycast<VBVHNode, StackSize, false, false>(obj->root, isec);
+ }
+ else
+ return RE_rayobject_intersect( (RayObject *) obj->root, isec);
+}
+
+template<class Tree>
+static void bvh_hint_bb(Tree *tree, LCTSHint *hint, float *UNUSED(min), float *UNUSED(max))
+{
+ //TODO renable hint support
+ {
+ hint->size = 0;
+ hint->stack[hint->size++] = (RayObject *)tree->root;
+ }
+}
+
+#if 0 /* UNUSED */
+static void bfree(VBVHTree *tree)
+{
+ if (tot_pushup + tot_pushdown + tot_hints + tot_moves) {
+ if (G.debug & G_DEBUG) {
+ printf("tot pushups: %d\n", tot_pushup);
+ printf("tot pushdowns: %d\n", tot_pushdown);
+ printf("tot moves: %d\n", tot_moves);
+ printf("tot hints created: %d\n", tot_hints);
+ }
+
+ tot_pushup = 0;
+ tot_pushdown = 0;
+ tot_hints = 0;
+ tot_moves = 0;
+ }
+ bvh_free(tree);
+}
+#endif
+
+/* the cast to pointer function is needed to workarround gcc bug: http://gcc.gnu.org/bugzilla/show_bug.cgi?id=11407 */
+template<class Tree, int STACK_SIZE>
+static RayObjectAPI make_api()
+{
+ static RayObjectAPI api =
+ {
+ (RE_rayobject_raycast_callback) ((int (*)(Tree *, Isect *)) & intersect<STACK_SIZE>),
+ (RE_rayobject_add_callback) ((void (*)(Tree *, RayObject *)) & bvh_add<Tree>),
+ (RE_rayobject_done_callback) ((void (*)(Tree *)) & bvh_done<Tree>),
+ (RE_rayobject_free_callback) ((void (*)(Tree *)) & bvh_free<Tree>),
+ (RE_rayobject_merge_bb_callback)((void (*)(Tree *, float *, float *)) & bvh_bb<Tree>),
+ (RE_rayobject_cost_callback) ((float (*)(Tree *)) & bvh_cost<Tree>),
+ (RE_rayobject_hint_bb_callback) ((void (*)(Tree *, LCTSHint *, float *, float *)) & bvh_hint_bb<Tree>)
+ };
+
+ return api;
+}
+
+template<class Tree>
+RayObjectAPI *bvh_get_api(int maxstacksize)
+{
+ static RayObjectAPI bvh_api256 = make_api<Tree, 1024>();
+
+ if (maxstacksize <= 1024) return &bvh_api256;
+ assert(maxstacksize <= 256);
+ return 0;
+}
+
+RayObject *RE_rayobject_vbvh_create(int size)
+{
+ return bvh_create_tree<VBVHTree, DFS_STACK_SIZE>(size);
+}
diff --git a/source/blender/render/intern/raytrace/reorganize.h b/source/blender/render/intern/raytrace/reorganize.h
new file mode 100644
index 00000000000..3fdd3363edb
--- /dev/null
+++ b/source/blender/render/intern/raytrace/reorganize.h
@@ -0,0 +1,513 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2009 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): André Pinto.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/render/intern/raytrace/reorganize.h
+ * \ingroup render
+ */
+
+
+#include <float.h>
+#include <math.h>
+#include <stdio.h>
+
+#include <algorithm>
+#include <queue>
+#include <vector>
+
+#include "BKE_global.h"
+
+#ifdef _WIN32
+# ifdef INFINITY
+# undef INFINITY
+# endif
+# define INFINITY FLT_MAX // in mingw math.h: (1.0F/0.0F). This generates compile error, though.
+#endif
+
+extern int tot_pushup;
+extern int tot_pushdown;
+
+#if !defined(INFINITY) && defined(HUGE_VAL)
+#define INFINITY HUGE_VAL
+#endif
+
+template<class Node>
+static bool node_fits_inside(Node *a, Node *b)
+{
+ return bb_fits_inside(b->bb, b->bb + 3, a->bb, a->bb + 3);
+}
+
+template<class Node>
+static void reorganize_find_fittest_parent(Node *tree, Node *node, std::pair<float, Node *> &cost)
+{
+ std::queue<Node *> q;
+ q.push(tree);
+
+ while (!q.empty()) {
+ Node *parent = q.front();
+ q.pop();
+
+ if (parent == node) continue;
+ if (node_fits_inside(node, parent) && RE_rayobject_isAligned(parent->child) ) {
+ float pcost = bb_area(parent->bb, parent->bb + 3);
+ cost = std::min(cost, std::make_pair(pcost, parent) );
+ for (Node *child = parent->child; child; child = child->sibling)
+ q.push(child);
+ }
+ }
+}
+
+template<class Node>
+static void reorganize(Node *root)
+{
+ std::queue<Node *> q;
+
+ q.push(root);
+ while (!q.empty()) {
+ Node *node = q.front();
+ q.pop();
+
+ if (RE_rayobject_isAligned(node->child)) {
+ for (Node **prev = &node->child; *prev; ) {
+ assert(RE_rayobject_isAligned(*prev));
+ q.push(*prev);
+
+ std::pair<float, Node *> best(FLT_MAX, root);
+ reorganize_find_fittest_parent(root, *prev, best);
+
+ if (best.second == node) {
+ //Already inside the fitnest BB
+ prev = &(*prev)->sibling;
+ }
+ else {
+ Node *tmp = *prev;
+ *prev = (*prev)->sibling;
+
+ tmp->sibling = best.second->child;
+ best.second->child = tmp;
+ }
+
+
+ }
+ }
+ if (node != root) {
+ }
+ }
+}
+
+/*
+ * Prunes useless nodes from trees:
+ * erases nodes with total amount of primitives = 0
+ * prunes nodes with only one child (except if that child is a primitive)
+ */
+template<class Node>
+static void remove_useless(Node *node, Node **new_node)
+{
+ if (RE_rayobject_isAligned(node->child) ) {
+
+ for (Node **prev = &node->child; *prev; ) {
+ Node *next = (*prev)->sibling;
+ remove_useless(*prev, prev);
+ if (*prev == NULL)
+ *prev = next;
+ else {
+ (*prev)->sibling = next;
+ prev = &((*prev)->sibling);
+ }
+ }
+ }
+ if (node->child) {
+ if (RE_rayobject_isAligned(node->child) && node->child->sibling == 0)
+ *new_node = node->child;
+ }
+ else if (node->child == NULL) {
+ *new_node = NULL;
+ }
+}
+
+/*
+ * Minimizes expected number of BBtest by colapsing nodes
+ * it uses surface area heuristic for determining whether a node should be colapsed
+ */
+template<class Node>
+static void pushup(Node *parent)
+{
+ if (is_leaf(parent)) return;
+
+ float p_area = bb_area(parent->bb, parent->bb + 3);
+ Node **prev = &parent->child;
+ for (Node *child = parent->child; RE_rayobject_isAligned(child) && child; ) {
+ const float c_area = bb_area(child->bb, child->bb + 3);
+ const int nchilds = count_childs(child);
+ float original_cost = ((p_area != 0.0f) ? (c_area / p_area) * nchilds : 1.0f) + 1;
+ float flatten_cost = nchilds;
+ if (flatten_cost < original_cost && nchilds >= 2) {
+ append_sibling(child, child->child);
+ child = child->sibling;
+ *prev = child;
+
+// *prev = child->child;
+// append_sibling( *prev, child->sibling );
+// child = *prev;
+ tot_pushup++;
+ }
+ else {
+ *prev = child;
+ prev = &(*prev)->sibling;
+ child = *prev;
+ }
+ }
+
+ for (Node *child = parent->child; RE_rayobject_isAligned(child) && child; child = child->sibling)
+ pushup(child);
+}
+
+/*
+ * try to optimize number of childs to be a multiple of SSize
+ */
+template<class Node, int SSize>
+static void pushup_simd(Node *parent)
+{
+ if (is_leaf(parent)) return;
+
+ int n = count_childs(parent);
+
+ Node **prev = &parent->child;
+ for (Node *child = parent->child; RE_rayobject_isAligned(child) && child; ) {
+ int cn = count_childs(child);
+ if (cn - 1 <= (SSize - (n % SSize) ) % SSize && RE_rayobject_isAligned(child->child) ) {
+ n += (cn - 1);
+ append_sibling(child, child->child);
+ child = child->sibling;
+ *prev = child;
+ }
+ else {
+ *prev = child;
+ prev = &(*prev)->sibling;
+ child = *prev;
+ }
+ }
+
+ for (Node *child = parent->child; RE_rayobject_isAligned(child) && child; child = child->sibling)
+ pushup_simd<Node, SSize>(child);
+}
+
+
+/*
+ * Pushdown
+ * makes sure no child fits inside any of its sibling
+ */
+template<class Node>
+static void pushdown(Node *parent)
+{
+ Node **s_child = &parent->child;
+ Node *child = parent->child;
+
+ while (child && RE_rayobject_isAligned(child)) {
+ Node *next = child->sibling;
+ Node **next_s_child = &child->sibling;
+
+ //assert(bb_fits_inside(parent->bb, parent->bb+3, child->bb, child->bb+3));
+
+ for (Node *i = parent->child; RE_rayobject_isAligned(i) && i; i = i->sibling)
+ if (child != i && bb_fits_inside(i->bb, i->bb + 3, child->bb, child->bb + 3) && RE_rayobject_isAligned(i->child)) {
+// todo optimize (should the one with the smallest area?)
+// float ia = bb_area(i->bb, i->bb+3)
+// if (child->i)
+ *s_child = child->sibling;
+ child->sibling = i->child;
+ i->child = child;
+ next_s_child = s_child;
+
+ tot_pushdown++;
+ break;
+ }
+ child = next;
+ s_child = next_s_child;
+ }
+
+ for (Node *i = parent->child; RE_rayobject_isAligned(i) && i; i = i->sibling) {
+ pushdown(i);
+ }
+}
+
+
+/*
+ * BVH refit
+ * readjust nodes BB (useful if nodes childs where modified)
+ */
+template<class Node>
+static float bvh_refit(Node *node)
+{
+ if (is_leaf(node)) return 0;
+ if (is_leaf(node->child)) return 0;
+
+ float total = 0;
+
+ for (Node *child = node->child; child; child = child->sibling)
+ total += bvh_refit(child);
+
+ float old_area = bb_area(node->bb, node->bb + 3);
+ INIT_MINMAX(node->bb, node->bb + 3);
+ for (Node *child = node->child; child; child = child->sibling) {
+ DO_MIN(child->bb, node->bb);
+ DO_MAX(child->bb + 3, node->bb + 3);
+ }
+ total += old_area - bb_area(node->bb, node->bb + 3);
+ return total;
+}
+
+
+/*
+ * this finds the best way to packing a tree according to a given test cost function
+ * with the purpose to reduce the expected cost (eg.: number of BB tests).
+ */
+#include <vector>
+#define MAX_CUT_SIZE 4 /* svbvh assumes max 4 children! */
+#define MAX_OPTIMIZE_CHILDS MAX_CUT_SIZE
+
+#define CUT_SIZE_IS_VALID(cut_size) ((cut_size) < MAX_CUT_SIZE && (cut_size) >= 0)
+#define CUT_SIZE_INVALID -1
+
+
+struct OVBVHNode {
+ float bb[6];
+
+ OVBVHNode *child;
+ OVBVHNode *sibling;
+
+ /*
+ * Returns min cost to represent the subtree starting at the given node,
+ * allowing it to have a given cutsize
+ */
+ float cut_cost[MAX_CUT_SIZE];
+ float get_cost(int cutsize)
+ {
+ assert(CUT_SIZE_IS_VALID(cutsize - 1));
+ return cut_cost[cutsize - 1];
+ }
+
+ /*
+ * This saves the cut size of this child, when parent is reaching
+ * its minimum cut with the given cut size
+ */
+ int cut_size[MAX_CUT_SIZE];
+ int get_cut_size(int parent_cut_size)
+ {
+ assert(CUT_SIZE_IS_VALID(parent_cut_size - 1));
+ return cut_size[parent_cut_size - 1];
+ }
+
+ /*
+ * Reorganize the node based on calculated cut costs
+ */
+ int best_cutsize;
+ void set_cut(int cutsize, OVBVHNode ***cut)
+ {
+ if (cutsize == 1) {
+ **cut = this;
+ *cut = &(**cut)->sibling;
+ }
+ else {
+ if (cutsize > MAX_CUT_SIZE) {
+ for (OVBVHNode *child = this->child; child && RE_rayobject_isAligned(child); child = child->sibling) {
+ child->set_cut(1, cut);
+ cutsize--;
+ }
+ assert(cutsize == 0);
+ }
+ else {
+ for (OVBVHNode *child = this->child; child && RE_rayobject_isAligned(child); child = child->sibling) {
+ child->set_cut(child->get_cut_size(cutsize), cut);
+ }
+ }
+ }
+ }
+
+ void optimize()
+ {
+ if (RE_rayobject_isAligned(this->child)) {
+ //Calc new childs
+ if (this->best_cutsize != CUT_SIZE_INVALID) {
+ OVBVHNode **cut = &(this->child);
+ set_cut(this->best_cutsize, &cut);
+ *cut = NULL;
+ }
+
+ //Optimize new childs
+ for (OVBVHNode *child = this->child; child && RE_rayobject_isAligned(child); child = child->sibling)
+ child->optimize();
+ }
+ }
+};
+
+/*
+ * Calculates an optimal SIMD packing
+ *
+ */
+template<class Node, class TestCost>
+struct VBVH_optimalPackSIMD {
+ TestCost testcost;
+
+ VBVH_optimalPackSIMD(TestCost testcost)
+ {
+ this->testcost = testcost;
+ }
+
+ /*
+ * calc best cut on a node
+ */
+ struct calc_best {
+ Node *child[MAX_OPTIMIZE_CHILDS];
+ float child_hit_prob[MAX_OPTIMIZE_CHILDS];
+
+ calc_best(Node *node)
+ {
+ int nchilds = 0;
+ //Fetch childs and needed data
+ {
+ float parent_area = bb_area(node->bb, node->bb + 3);
+ for (Node *child = node->child; child && RE_rayobject_isAligned(child); child = child->sibling) {
+ this->child[nchilds] = child;
+ this->child_hit_prob[nchilds] = (parent_area != 0.0f) ? bb_area(child->bb, child->bb + 3) / parent_area : 1.0f;
+ nchilds++;
+ }
+
+ assert(nchilds >= 2 && nchilds <= MAX_OPTIMIZE_CHILDS);
+ }
+
+
+ //Build DP table to find minimum cost to represent this node with a given cutsize
+ int bt[MAX_OPTIMIZE_CHILDS + 1][MAX_CUT_SIZE + 1]; //backtrace table
+ float cost[MAX_OPTIMIZE_CHILDS + 1][MAX_CUT_SIZE + 1]; //cost table (can be reduced to float[2][MAX_CUT_COST])
+
+ for (int i = 0; i <= nchilds; i++) {
+ for (int j = 0; j <= MAX_CUT_SIZE; j++) {
+ cost[i][j] = INFINITY;
+ }
+ }
+
+ cost[0][0] = 0;
+
+ for (int i = 1; i <= nchilds; i++) {
+ for (int size = i - 1; size /*+(nchilds-i)*/ <= MAX_CUT_SIZE; size++) {
+ for (int cut = 1; cut + size /*+(nchilds-i)*/ <= MAX_CUT_SIZE; cut++) {
+ float new_cost = cost[i - 1][size] + child_hit_prob[i - 1] * child[i - 1]->get_cost(cut);
+ if (new_cost < cost[i][size + cut]) {
+ cost[i][size + cut] = new_cost;
+ bt[i][size + cut] = cut;
+ }
+ }
+ }
+ }
+
+ /* Save the ways to archive the minimum cost with a given cutsize */
+ for (int i = nchilds; i <= MAX_CUT_SIZE; i++) {
+ node->cut_cost[i - 1] = cost[nchilds][i];
+ if (cost[nchilds][i] < INFINITY) {
+ int current_size = i;
+ for (int j = nchilds; j > 0; j--) {
+ child[j - 1]->cut_size[i - 1] = bt[j][current_size];
+ current_size -= bt[j][current_size];
+ }
+ }
+ }
+ }
+ };
+
+ void calc_costs(Node *node)
+ {
+
+ if (RE_rayobject_isAligned(node->child) ) {
+ int nchilds = 0;
+ for (Node *child = node->child; child && RE_rayobject_isAligned(child); child = child->sibling) {
+ calc_costs(child);
+ nchilds++;
+ }
+
+ for (int i = 0; i < MAX_CUT_SIZE; i++)
+ node->cut_cost[i] = INFINITY;
+
+ //We are not allowed to look on nodes with with so many childs
+ if (nchilds > MAX_CUT_SIZE) {
+ float cost = 0;
+
+ float parent_area = bb_area(node->bb, node->bb + 3);
+ for (Node *child = node->child; child && RE_rayobject_isAligned(child); child = child->sibling) {
+ cost += ((parent_area != 0.0f) ? (bb_area(child->bb, child->bb + 3) / parent_area) : 1.0f) * child->get_cost(1);
+ }
+
+ cost += testcost(nchilds);
+ node->cut_cost[0] = cost;
+ node->best_cutsize = nchilds;
+ }
+ else {
+ calc_best calc(node);
+
+ //calc expected cost if we optimaly pack this node
+ for (int cutsize = nchilds; cutsize <= MAX_CUT_SIZE; cutsize++) {
+ float m = node->get_cost(cutsize) + testcost(cutsize);
+ if (m < node->cut_cost[0]) {
+ node->cut_cost[0] = m;
+ node->best_cutsize = cutsize;
+ }
+ }
+ }
+
+ if (node->cut_cost[0] == INFINITY) {
+ node->best_cutsize = CUT_SIZE_INVALID;
+ }
+ }
+ else {
+ node->cut_cost[0] = 1.0f;
+ for (int i = 1; i < MAX_CUT_SIZE; i++)
+ node->cut_cost[i] = INFINITY;
+
+ /* node->best_cutsize can remain unset here */
+ }
+ }
+
+ Node *transform(Node *node)
+ {
+ if (RE_rayobject_isAligned(node->child)) {
+#ifdef DEBUG
+ static int num = 0;
+ bool first = false;
+ if (num == 0) { num++; first = true; }
+#endif
+
+ calc_costs(node);
+
+#ifdef DEBUG
+ if (first && G.debug) {
+ printf("expected cost = %f (%d)\n", node->cut_cost[0], node->best_cutsize);
+ }
+#endif
+ node->optimize();
+ }
+ return node;
+ }
+};
diff --git a/source/blender/render/intern/raytrace/svbvh.h b/source/blender/render/intern/raytrace/svbvh.h
new file mode 100644
index 00000000000..0a5690deb46
--- /dev/null
+++ b/source/blender/render/intern/raytrace/svbvh.h
@@ -0,0 +1,317 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2009 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): André Pinto.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/render/intern/raytrace/svbvh.h
+ * \ingroup render
+ */
+
+#ifndef __SVBVH_H__
+#define __SVBVH_H__
+
+#ifdef __SSE__
+
+#include "bvh.h"
+#include "BLI_memarena.h"
+#include <algorithm>
+
+struct SVBVHNode {
+ float child_bb[24];
+ SVBVHNode *child[4];
+ int nchilds;
+};
+
+static int svbvh_bb_intersect_test_simd4(const Isect *isec, const __m128 *bb_group)
+{
+ const __m128 tmin0 = _mm_setzero_ps();
+ const __m128 tmax0 = _mm_set_ps1(isec->dist);
+
+ const __m128 start0 = _mm_set_ps1(isec->start[0]);
+ const __m128 start1 = _mm_set_ps1(isec->start[1]);
+ const __m128 start2 = _mm_set_ps1(isec->start[2]);
+ const __m128 sub0 = _mm_sub_ps(bb_group[isec->bv_index[0]], start0);
+ const __m128 sub1 = _mm_sub_ps(bb_group[isec->bv_index[1]], start0);
+ const __m128 sub2 = _mm_sub_ps(bb_group[isec->bv_index[2]], start1);
+ const __m128 sub3 = _mm_sub_ps(bb_group[isec->bv_index[3]], start1);
+ const __m128 sub4 = _mm_sub_ps(bb_group[isec->bv_index[4]], start2);
+ const __m128 sub5 = _mm_sub_ps(bb_group[isec->bv_index[5]], start2);
+ const __m128 idot_axis0 = _mm_set_ps1(isec->idot_axis[0]);
+ const __m128 idot_axis1 = _mm_set_ps1(isec->idot_axis[1]);
+ const __m128 idot_axis2 = _mm_set_ps1(isec->idot_axis[2]);
+ const __m128 mul0 = _mm_mul_ps(sub0, idot_axis0);
+ const __m128 mul1 = _mm_mul_ps(sub1, idot_axis0);
+ const __m128 mul2 = _mm_mul_ps(sub2, idot_axis1);
+ const __m128 mul3 = _mm_mul_ps(sub3, idot_axis1);
+ const __m128 mul4 = _mm_mul_ps(sub4, idot_axis2);
+ const __m128 mul5 = _mm_mul_ps(sub5, idot_axis2);
+ const __m128 tmin1 = _mm_max_ps(tmin0, mul0);
+ const __m128 tmax1 = _mm_min_ps(tmax0, mul1);
+ const __m128 tmin2 = _mm_max_ps(tmin1, mul2);
+ const __m128 tmax2 = _mm_min_ps(tmax1, mul3);
+ const __m128 tmin3 = _mm_max_ps(tmin2, mul4);
+ const __m128 tmax3 = _mm_min_ps(tmax2, mul5);
+
+ return _mm_movemask_ps(_mm_cmpge_ps(tmax3, tmin3));
+}
+
+static int svbvh_bb_intersect_test(const Isect *isec, const float *_bb)
+{
+ const float *bb = _bb;
+
+ float t1x = (bb[isec->bv_index[0]] - isec->start[0]) * isec->idot_axis[0];
+ float t2x = (bb[isec->bv_index[1]] - isec->start[0]) * isec->idot_axis[0];
+ float t1y = (bb[isec->bv_index[2]] - isec->start[1]) * isec->idot_axis[1];
+ float t2y = (bb[isec->bv_index[3]] - isec->start[1]) * isec->idot_axis[1];
+ float t1z = (bb[isec->bv_index[4]] - isec->start[2]) * isec->idot_axis[2];
+ float t2z = (bb[isec->bv_index[5]] - isec->start[2]) * isec->idot_axis[2];
+
+ RE_RC_COUNT(isec->raycounter->bb.test);
+
+ if (t1x > t2y || t2x < t1y || t1x > t2z || t2x < t1z || t1y > t2z || t2y < t1z) return 0;
+ if (t2x < 0.0f || t2y < 0.0f || t2z < 0.0f) return 0;
+ if (t1x > isec->dist || t1y > isec->dist || t1z > isec->dist) return 0;
+
+ RE_RC_COUNT(isec->raycounter->bb.hit);
+
+ return 1;
+}
+
+static bool svbvh_node_is_leaf(const SVBVHNode *node)
+{
+ return !RE_rayobject_isAligned(node);
+}
+
+template<int MAX_STACK_SIZE, bool SHADOW>
+static int svbvh_node_stack_raycast(SVBVHNode *root, Isect *isec)
+{
+ SVBVHNode *stack[MAX_STACK_SIZE], *node;
+ int hit = 0, stack_pos = 0;
+
+ stack[stack_pos++] = root;
+
+ while (stack_pos) {
+ node = stack[--stack_pos];
+
+ if (!svbvh_node_is_leaf(node)) {
+ int nchilds = node->nchilds;
+
+ if (nchilds == 4) {
+ float *child_bb = node->child_bb;
+ int res = svbvh_bb_intersect_test_simd4(isec, ((__m128 *) (child_bb)));
+ SVBVHNode **child = node->child;
+
+ RE_RC_COUNT(isec->raycounter->simd_bb.test);
+
+ if (res & 1) { stack[stack_pos++] = child[0]; RE_RC_COUNT(isec->raycounter->simd_bb.hit); }
+ if (res & 2) { stack[stack_pos++] = child[1]; RE_RC_COUNT(isec->raycounter->simd_bb.hit); }
+ if (res & 4) { stack[stack_pos++] = child[2]; RE_RC_COUNT(isec->raycounter->simd_bb.hit); }
+ if (res & 8) { stack[stack_pos++] = child[3]; RE_RC_COUNT(isec->raycounter->simd_bb.hit); }
+ }
+ else {
+ float *child_bb = node->child_bb;
+ SVBVHNode **child = node->child;
+ int i;
+
+ for (i = 0; i < nchilds; i++) {
+ if (svbvh_bb_intersect_test(isec, (float *)child_bb + 6 * i)) {
+ stack[stack_pos++] = child[i];
+ }
+ }
+ }
+ }
+ else {
+ hit |= RE_rayobject_intersect((RayObject *)node, isec);
+ if (SHADOW && hit) break;
+ }
+ }
+
+ return hit;
+}
+
+
+template<>
+inline void bvh_node_merge_bb<SVBVHNode>(SVBVHNode *node, float min[3], float max[3])
+{
+ if (is_leaf(node)) {
+ RE_rayobject_merge_bb((RayObject *)node, min, max);
+ }
+ else {
+ int i;
+ for (i = 0; i + 4 <= node->nchilds; i += 4) {
+ float *res = node->child_bb + 6 * i;
+ for (int j = 0; j < 3; j++) {
+ min[j] = min_ff(min[j],
+ min_ffff(res[4 * j + 0],
+ res[4 * j + 1],
+ res[4 * j + 2],
+ res[4 * j + 3]));
+ }
+ for (int j = 0; j < 3; j++) {
+ max[j] = max_ff(max[j],
+ max_ffff(res[4 * (j + 3) + 0],
+ res[4 * (j + 3) + 1],
+ res[4 * (j + 3) + 2],
+ res[4 * (j + 3) + 3]));
+ }
+ }
+
+ for (; i < node->nchilds; i++) {
+ DO_MIN(node->child_bb + 6 * i, min);
+ DO_MAX(node->child_bb + 3 + 6 * i, max);
+ }
+ }
+}
+
+
+
+/*
+ * Builds a SVBVH tree form a VBVHTree
+ */
+template<class OldNode>
+struct Reorganize_SVBVH {
+ MemArena *arena;
+
+ float childs_per_node;
+ int nodes_with_childs[16];
+ int useless_bb;
+ int nodes;
+
+ Reorganize_SVBVH(MemArena *a)
+ {
+ arena = a;
+ nodes = 0;
+ childs_per_node = 0;
+ useless_bb = 0;
+
+ for (int i = 0; i < 16; i++) {
+ nodes_with_childs[i] = 0;
+ }
+ }
+
+ ~Reorganize_SVBVH()
+ {
+#if 0
+ {
+ printf("%f childs per node\n", childs_per_node / nodes);
+ printf("%d childs BB are useless\n", useless_bb);
+ for (int i = 0; i < 16; i++) {
+ printf("%i childs per node: %d/%d = %f\n", i, nodes_with_childs[i], nodes, nodes_with_childs[i] / float(nodes));
+ }
+ }
+#endif
+ }
+
+ SVBVHNode *create_node(int nchilds)
+ {
+ SVBVHNode *node = (SVBVHNode *)BLI_memarena_alloc(arena, sizeof(SVBVHNode));
+ node->nchilds = nchilds;
+
+ return node;
+ }
+
+ void copy_bb(float bb[6], const float old_bb[6])
+ {
+ std::copy(old_bb, old_bb + 6, bb);
+ }
+
+ void prepare_for_simd(SVBVHNode *node)
+ {
+ int i = 0;
+ while (i + 4 <= node->nchilds) {
+ float vec_tmp[4 * 6];
+ float *res = node->child_bb + 6 * i;
+ std::copy(res, res + 6 * 4, vec_tmp);
+
+ for (int j = 0; j < 6; j++) {
+ res[4 * j + 0] = vec_tmp[6 * 0 + j];
+ res[4 * j + 1] = vec_tmp[6 * 1 + j];
+ res[4 * j + 2] = vec_tmp[6 * 2 + j];
+ res[4 * j + 3] = vec_tmp[6 * 3 + j];
+ }
+
+ i += 4;
+ }
+ }
+
+ /* amt must be power of two */
+ inline int padup(int num, int amt)
+ {
+ return ((num + (amt - 1)) & ~(amt - 1));
+ }
+
+ SVBVHNode *transform(OldNode *old)
+ {
+ if (is_leaf(old))
+ return (SVBVHNode *)old;
+ if (is_leaf(old->child))
+ return (SVBVHNode *)old->child;
+
+ int nchilds = count_childs(old);
+ int alloc_childs = nchilds;
+ if (nchilds % 4 > 2)
+ alloc_childs = padup(nchilds, 4);
+
+ SVBVHNode *node = create_node(alloc_childs);
+
+ childs_per_node += nchilds;
+ nodes++;
+ if (nchilds < 16)
+ nodes_with_childs[nchilds]++;
+
+ useless_bb += alloc_childs - nchilds;
+ while (alloc_childs > nchilds) {
+ const static float def_bb[6] = {FLT_MAX, FLT_MAX, FLT_MAX, -FLT_MAX, -FLT_MAX, -FLT_MAX};
+ alloc_childs--;
+ node->child[alloc_childs] = NULL;
+ copy_bb(node->child_bb + alloc_childs * 6, def_bb);
+ }
+
+ int i = nchilds;
+ for (OldNode *o_child = old->child; o_child; o_child = o_child->sibling) {
+ i--;
+ node->child[i] = transform(o_child);
+ if (is_leaf(o_child)) {
+ float bb[6];
+ INIT_MINMAX(bb, bb + 3);
+ RE_rayobject_merge_bb((RayObject *)o_child, bb, bb + 3);
+ copy_bb(node->child_bb + i * 6, bb);
+ break;
+ }
+ else {
+ copy_bb(node->child_bb + i * 6, o_child->bb);
+ }
+ }
+ assert(i == 0);
+
+ prepare_for_simd(node);
+
+ return node;
+ }
+};
+
+#endif /* __SSE__ */
+
+#endif /* __SVBVH_H__ */
diff --git a/source/blender/render/intern/raytrace/vbvh.h b/source/blender/render/intern/raytrace/vbvh.h
new file mode 100644
index 00000000000..0b0bbd19116
--- /dev/null
+++ b/source/blender/render/intern/raytrace/vbvh.h
@@ -0,0 +1,238 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2009 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): André Pinto.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/render/intern/raytrace/vbvh.h
+ * \ingroup render
+ */
+
+
+#include <assert.h>
+#include <algorithm>
+
+#include "BLI_memarena.h"
+
+#include "rayobject_rtbuild.h"
+
+/*
+ * VBVHNode represents a BVHNode with support for a variable number of childrens
+ */
+struct VBVHNode {
+ float bb[6];
+
+ VBVHNode *child;
+ VBVHNode *sibling;
+};
+
+
+/*
+ * Push nodes (used on dfs)
+ */
+template<class Node>
+inline static void bvh_node_push_childs(Node *node, Isect *UNUSED(isec), Node **stack, int &stack_pos)
+{
+ Node *child = node->child;
+
+ if (is_leaf(child)) {
+ stack[stack_pos++] = child;
+ }
+ else {
+ while (child) {
+ /* Skips BB tests on primitives */
+#if 0
+ if (is_leaf(child->child)) {
+ stack[stack_pos++] = child->child;
+ }
+ else
+#endif
+ {
+ stack[stack_pos++] = child;
+ }
+
+ child = child->sibling;
+ }
+ }
+}
+
+
+template<class Node>
+static int count_childs(Node *parent)
+{
+ int n = 0;
+ for (Node *i = parent->child; i; i = i->sibling) {
+ n++;
+ if (is_leaf(i))
+ break;
+ }
+
+ return n;
+}
+
+
+template<class Node>
+static void append_sibling(Node *node, Node *sibling)
+{
+ while (node->sibling)
+ node = node->sibling;
+
+ node->sibling = sibling;
+}
+
+
+/*
+ * Builds a binary VBVH from a rtbuild
+ */
+template<class Node>
+struct BuildBinaryVBVH {
+ MemArena *arena;
+ RayObjectControl *control;
+
+ void test_break()
+ {
+ if (RE_rayobjectcontrol_test_break(control))
+ throw "Stop";
+ }
+
+ BuildBinaryVBVH(MemArena *a, RayObjectControl *c)
+ {
+ arena = a;
+ control = c;
+ }
+
+ Node *create_node()
+ {
+ Node *node = (Node *)BLI_memarena_alloc(arena, sizeof(Node) );
+ assert(RE_rayobject_isAligned(node));
+
+ node->sibling = NULL;
+ node->child = NULL;
+
+ return node;
+ }
+
+ int rtbuild_split(RTBuilder *builder)
+ {
+ return ::rtbuild_heuristic_object_split(builder, 2);
+ }
+
+ Node *transform(RTBuilder *builder)
+ {
+ try
+ {
+ return _transform(builder);
+
+ } catch (...)
+ {
+ }
+ return NULL;
+ }
+
+ Node *_transform(RTBuilder *builder)
+ {
+ int size = rtbuild_size(builder);
+
+ if (size == 0) {
+ return NULL;
+ }
+ else if (size == 1) {
+ Node *node = create_node();
+ INIT_MINMAX(node->bb, node->bb + 3);
+ rtbuild_merge_bb(builder, node->bb, node->bb + 3);
+ node->child = (Node *) rtbuild_get_primitive(builder, 0);
+ return node;
+ }
+ else {
+ test_break();
+
+ Node *node = create_node();
+
+ Node **child = &node->child;
+
+ int nc = rtbuild_split(builder);
+ INIT_MINMAX(node->bb, node->bb + 3);
+
+ assert(nc == 2);
+ for (int i = 0; i < nc; i++) {
+ RTBuilder tmp;
+ rtbuild_get_child(builder, i, &tmp);
+
+ *child = _transform(&tmp);
+ DO_MIN((*child)->bb, node->bb);
+ DO_MAX((*child)->bb + 3, node->bb + 3);
+ child = &((*child)->sibling);
+ }
+
+ *child = NULL;
+ return node;
+ }
+ }
+};
+
+#if 0
+template<class Tree, class OldNode>
+struct Reorganize_VBVH {
+ Tree *tree;
+
+ Reorganize_VBVH(Tree *t)
+ {
+ tree = t;
+ }
+
+ VBVHNode *create_node()
+ {
+ VBVHNode *node = (VBVHNode *)BLI_memarena_alloc(tree->node_arena, sizeof(VBVHNode));
+ return node;
+ }
+
+ void copy_bb(VBVHNode *node, OldNode *old)
+ {
+ std::copy(old->bb, old->bb + 6, node->bb);
+ }
+
+ VBVHNode *transform(OldNode *old)
+ {
+ if (is_leaf(old))
+ return (VBVHNode *)old;
+
+ VBVHNode *node = create_node();
+ VBVHNode **child_ptr = &node->child;
+ node->sibling = 0;
+
+ copy_bb(node, old);
+
+ for (OldNode *o_child = old->child; o_child; o_child = o_child->sibling)
+ {
+ VBVHNode *n_child = transform(o_child);
+ *child_ptr = n_child;
+ if (is_leaf(n_child)) return node;
+ child_ptr = &n_child->sibling;
+ }
+ *child_ptr = 0;
+
+ return node;
+ }
+};
+#endif
diff --git a/source/blender/render/intern/source/bake.c b/source/blender/render/intern/source/bake.c
new file mode 100644
index 00000000000..4a7962b1776
--- /dev/null
+++ b/source/blender/render/intern/source/bake.c
@@ -0,0 +1,1342 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contributors: 2004/2005/2006 Blender Foundation, full recode
+ * Contributors: Vertex color baking, Copyright 2011 AutoCRC
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/render/intern/source/bake.c
+ * \ingroup render
+ */
+
+
+/* system includes */
+#include <stdio.h>
+#include <string.h>
+
+/* External modules: */
+#include "MEM_guardedalloc.h"
+
+#include "BLI_math.h"
+#include "BLI_rand.h"
+#include "BLI_threads.h"
+#include "BLI_utildefines.h"
+
+#include "DNA_image_types.h"
+#include "DNA_material_types.h"
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+
+#include "BKE_customdata.h"
+#include "BKE_global.h"
+#include "BKE_image.h"
+#include "BKE_main.h"
+#include "BKE_node.h"
+#include "BKE_scene.h"
+#include "BKE_library.h"
+
+#include "IMB_imbuf_types.h"
+#include "IMB_imbuf.h"
+#include "IMB_colormanagement.h"
+
+/* local include */
+#include "rayintersection.h"
+#include "rayobject.h"
+#include "render_types.h"
+#include "renderdatabase.h"
+#include "shading.h"
+#include "zbuf.h"
+
+#include "PIL_time.h"
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+/* defined in pipeline.c, is hardcopy of active dynamic allocated Render */
+/* only to be used here in this file, it's for speed */
+extern struct Render R;
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+
+/* ************************* bake ************************ */
+
+
+typedef struct BakeShade {
+ int thread;
+
+ ShadeSample ssamp;
+ ObjectInstanceRen *obi;
+ VlakRen *vlr;
+
+ ZSpan *zspan;
+ Image *ima;
+ ImBuf *ibuf;
+
+ int rectx, recty, quad, type, vdone;
+ bool ready;
+
+ float dir[3];
+ Object *actob;
+
+ /* Output: vertex color or image data. If vcol is not NULL, rect and
+ * rect_float should be NULL. */
+ MPoly *mpoly;
+ MLoop *mloop;
+ MLoopCol *vcol;
+
+ unsigned int *rect;
+ float *rect_float;
+
+ /* displacement buffer used for normalization with unknown maximal distance */
+ bool use_displacement_buffer;
+ float *displacement_buffer;
+ float displacement_min, displacement_max;
+
+ bool use_mask;
+ char *rect_mask; /* bake pixel mask */
+
+ float dxco[3], dyco[3];
+
+ short *do_update;
+
+ struct ColorSpace *rect_colorspace;
+} BakeShade;
+
+static void bake_set_shade_input(ObjectInstanceRen *obi, VlakRen *vlr, ShadeInput *shi, int quad, int UNUSED(isect), int x, int y, float u, float v)
+{
+ if (quad)
+ shade_input_set_triangle_i(shi, obi, vlr, 0, 2, 3);
+ else
+ shade_input_set_triangle_i(shi, obi, vlr, 0, 1, 2);
+
+ /* cache for shadow */
+ shi->samplenr = R.shadowsamplenr[shi->thread]++;
+
+ shi->mask = 0xFFFF; /* all samples */
+
+ shi->u = -u;
+ shi->v = -v;
+ shi->xs = x;
+ shi->ys = y;
+
+ shade_input_set_uv(shi);
+ shade_input_set_normals(shi);
+
+ /* no normal flip */
+ if (shi->flippednor)
+ shade_input_flip_normals(shi);
+
+ /* set up view vector to look right at the surface (note that the normal
+ * is negated in the renderer so it does not need to be done here) */
+ shi->view[0] = shi->vn[0];
+ shi->view[1] = shi->vn[1];
+ shi->view[2] = shi->vn[2];
+}
+
+static void bake_shade(void *handle, Object *ob, ShadeInput *shi, int UNUSED(quad), int x, int y, float UNUSED(u), float UNUSED(v), float *tvn, float *ttang)
+{
+ BakeShade *bs = handle;
+ ShadeSample *ssamp = &bs->ssamp;
+ ShadeResult shr;
+ VlakRen *vlr = shi->vlr;
+
+ shade_input_init_material(shi);
+
+ if (bs->type == RE_BAKE_AO) {
+ ambient_occlusion(shi);
+
+ if (R.r.bake_flag & R_BAKE_NORMALIZE) {
+ copy_v3_v3(shr.combined, shi->ao);
+ }
+ else {
+ zero_v3(shr.combined);
+ environment_lighting_apply(shi, &shr);
+ }
+ }
+ else {
+ if (bs->type == RE_BAKE_SHADOW) /* Why do shadows set the color anyhow?, ignore material color for baking */
+ shi->r = shi->g = shi->b = 1.0f;
+
+ shade_input_set_shade_texco(shi);
+
+ /* only do AO for a full bake (and obviously AO bakes)
+ * AO for light bakes is a leftover and might not be needed */
+ if (ELEM(bs->type, RE_BAKE_ALL, RE_BAKE_AO, RE_BAKE_LIGHT))
+ shade_samples_do_AO(ssamp);
+
+ if (shi->mat->nodetree && shi->mat->use_nodes) {
+ ntreeShaderExecTree(shi->mat->nodetree, shi, &shr);
+ shi->mat = vlr->mat; /* shi->mat is being set in nodetree */
+ }
+ else
+ shade_material_loop(shi, &shr);
+
+ if (bs->type == RE_BAKE_NORMALS) {
+ float nor[3];
+
+ copy_v3_v3(nor, shi->vn);
+
+ if (R.r.bake_normal_space == R_BAKE_SPACE_CAMERA) {
+ /* pass */
+ }
+ else if (R.r.bake_normal_space == R_BAKE_SPACE_TANGENT) {
+ float mat[3][3], imat[3][3];
+
+ /* bitangent */
+ if (tvn && ttang) {
+ copy_v3_v3(mat[0], ttang);
+ cross_v3_v3v3(mat[1], tvn, ttang);
+ mul_v3_fl(mat[1], ttang[3]);
+ copy_v3_v3(mat[2], tvn);
+ }
+ else {
+ copy_v3_v3(mat[0], shi->nmaptang);
+ cross_v3_v3v3(mat[1], shi->nmapnorm, shi->nmaptang);
+ mul_v3_fl(mat[1], shi->nmaptang[3]);
+ copy_v3_v3(mat[2], shi->nmapnorm);
+ }
+
+ invert_m3_m3(imat, mat);
+ mul_m3_v3(imat, nor);
+ }
+ else if (R.r.bake_normal_space == R_BAKE_SPACE_OBJECT)
+ mul_mat3_m4_v3(ob->imat_ren, nor); /* ob->imat_ren includes viewinv! */
+ else if (R.r.bake_normal_space == R_BAKE_SPACE_WORLD)
+ mul_mat3_m4_v3(R.viewinv, nor);
+
+ normalize_v3(nor); /* in case object has scaling */
+
+ /* The invert of the red channel is to make
+ * the normal map compliant with the outside world.
+ * It needs to be done because in Blender
+ * the normal used in the renderer points inward. It is generated
+ * this way in calc_vertexnormals(). Should this ever change
+ * this negate must be removed.
+ *
+ * there is also a small 1e-5f bias for precision issues. otherwise
+ * we randomly get 127 or 128 for neutral colors. we choose 128
+ * because it is the convention flat color. * */
+ shr.combined[0] = (-nor[0]) / 2.0f + 0.5f + 1e-5f;
+ shr.combined[1] = nor[1] / 2.0f + 0.5f + 1e-5f;
+ shr.combined[2] = nor[2] / 2.0f + 0.5f + 1e-5f;
+ }
+ else if (bs->type == RE_BAKE_TEXTURE) {
+ copy_v3_v3(shr.combined, &shi->r);
+ shr.alpha = shi->alpha;
+ }
+ else if (bs->type == RE_BAKE_SHADOW) {
+ copy_v3_v3(shr.combined, shr.shad);
+ shr.alpha = shi->alpha;
+ }
+ else if (bs->type == RE_BAKE_SPEC_COLOR) {
+ copy_v3_v3(shr.combined, &shi->specr);
+ shr.alpha = 1.0f;
+ }
+ else if (bs->type == RE_BAKE_SPEC_INTENSITY) {
+ copy_v3_fl(shr.combined, shi->spec);
+ shr.alpha = 1.0f;
+ }
+ else if (bs->type == RE_BAKE_MIRROR_COLOR) {
+ copy_v3_v3(shr.combined, &shi->mirr);
+ shr.alpha = 1.0f;
+ }
+ else if (bs->type == RE_BAKE_MIRROR_INTENSITY) {
+ copy_v3_fl(shr.combined, shi->ray_mirror);
+ shr.alpha = 1.0f;
+ }
+ else if (bs->type == RE_BAKE_ALPHA) {
+ copy_v3_fl(shr.combined, shi->alpha);
+ shr.alpha = 1.0f;
+ }
+ else if (bs->type == RE_BAKE_EMIT) {
+ copy_v3_fl(shr.combined, shi->emit);
+ shr.alpha = 1.0f;
+ }
+ else if (bs->type == RE_BAKE_VERTEX_COLORS) {
+ copy_v3_v3(shr.combined, shi->vcol);
+ shr.alpha = shi->vcol[3];
+ }
+ }
+
+ if (bs->rect_float && !bs->vcol) {
+ float *col = bs->rect_float + 4 * (bs->rectx * y + x);
+ copy_v3_v3(col, shr.combined);
+ if (bs->type == RE_BAKE_ALL || bs->type == RE_BAKE_TEXTURE || bs->type == RE_BAKE_VERTEX_COLORS) {
+ col[3] = shr.alpha;
+ }
+ else {
+ col[3] = 1.0;
+ }
+ }
+ else {
+ /* Target is char (LDR). */
+ unsigned char col[4];
+
+ if (ELEM(bs->type, RE_BAKE_ALL, RE_BAKE_TEXTURE)) {
+ float rgb[3];
+
+ copy_v3_v3(rgb, shr.combined);
+ if (R.scene_color_manage) {
+ /* Vertex colors have no way to specify color space, so they
+ * default to sRGB. */
+ if (!bs->vcol)
+ IMB_colormanagement_scene_linear_to_colorspace_v3(rgb, bs->rect_colorspace);
+ else
+ linearrgb_to_srgb_v3_v3(rgb, rgb);
+ }
+ rgb_float_to_uchar(col, rgb);
+ }
+ else {
+ rgb_float_to_uchar(col, shr.combined);
+ }
+
+ if (ELEM(bs->type, RE_BAKE_ALL, RE_BAKE_TEXTURE, RE_BAKE_VERTEX_COLORS)) {
+ col[3] = unit_float_to_uchar_clamp(shr.alpha);
+ }
+ else {
+ col[3] = 255;
+ }
+
+ if (bs->vcol) {
+ /* Vertex color baking. Vcol has no useful alpha channel (it exists
+ * but is used only for vertex painting). */
+ bs->vcol->r = col[0];
+ bs->vcol->g = col[1];
+ bs->vcol->b = col[2];
+ }
+ else {
+ unsigned char *imcol = (unsigned char *)(bs->rect + bs->rectx * y + x);
+ copy_v4_v4_uchar(imcol, col);
+ }
+
+ }
+
+ if (bs->rect_mask) {
+ bs->rect_mask[bs->rectx * y + x] = FILTER_MASK_USED;
+ }
+
+ if (bs->do_update) {
+ *bs->do_update = true;
+ }
+}
+
+static void bake_displacement(void *handle, ShadeInput *UNUSED(shi), float dist, int x, int y)
+{
+ BakeShade *bs = handle;
+ float disp;
+
+ if (R.r.bake_flag & R_BAKE_NORMALIZE) {
+ if (R.r.bake_maxdist)
+ disp = (dist + R.r.bake_maxdist) / (R.r.bake_maxdist * 2); /* alter the range from [-bake_maxdist, bake_maxdist] to [0, 1]*/
+ else
+ disp = dist;
+ }
+ else {
+ disp = 0.5f + dist; /* alter the range from [-0.5,0.5] to [0,1]*/
+ }
+
+ if (bs->displacement_buffer) {
+ float *displacement = bs->displacement_buffer + (bs->rectx * y + x);
+ *displacement = disp;
+ bs->displacement_min = min_ff(bs->displacement_min, disp);
+ bs->displacement_max = max_ff(bs->displacement_max, disp);
+ }
+
+ if (bs->rect_float && !bs->vcol) {
+ float *col = bs->rect_float + 4 * (bs->rectx * y + x);
+ col[0] = col[1] = col[2] = disp;
+ col[3] = 1.0f;
+ }
+ else {
+ /* Target is char (LDR). */
+ unsigned char col[4];
+ col[0] = col[1] = col[2] = unit_float_to_uchar_clamp(disp);
+ col[3] = 255;
+
+ if (bs->vcol) {
+ /* Vertex color baking. Vcol has no useful alpha channel (it exists
+ * but is used only for vertex painting). */
+ bs->vcol->r = col[0];
+ bs->vcol->g = col[1];
+ bs->vcol->b = col[2];
+ }
+ else {
+ unsigned char *imcol = (unsigned char *)(bs->rect + bs->rectx * y + x);
+ copy_v4_v4_uchar(imcol, col);
+ }
+ }
+ if (bs->rect_mask) {
+ bs->rect_mask[bs->rectx * y + x] = FILTER_MASK_USED;
+ }
+}
+
+static int bake_intersect_tree(RayObject *raytree, Isect *isect, float *start, float *dir, float sign, float *hitco, float *dist)
+{
+ float maxdist;
+ int hit;
+
+ /* might be useful to make a user setting for maxsize*/
+ if (R.r.bake_maxdist > 0.0f)
+ maxdist = R.r.bake_maxdist;
+ else
+ maxdist = RE_RAYTRACE_MAXDIST + R.r.bake_biasdist;
+
+ /* 'dir' is always normalized */
+ madd_v3_v3v3fl(isect->start, start, dir, -R.r.bake_biasdist);
+
+ mul_v3_v3fl(isect->dir, dir, sign);
+
+ isect->dist = maxdist;
+
+ hit = RE_rayobject_raycast(raytree, isect);
+ if (hit) {
+ madd_v3_v3v3fl(hitco, isect->start, isect->dir, isect->dist);
+
+ *dist = isect->dist;
+ }
+
+ return hit;
+}
+
+static void bake_set_vlr_dxyco(BakeShade *bs, float *uv1, float *uv2, float *uv3)
+{
+ VlakRen *vlr = bs->vlr;
+ float A, d1, d2, d3, *v1, *v2, *v3;
+
+ if (bs->quad) {
+ v1 = vlr->v1->co;
+ v2 = vlr->v3->co;
+ v3 = vlr->v4->co;
+ }
+ else {
+ v1 = vlr->v1->co;
+ v2 = vlr->v2->co;
+ v3 = vlr->v3->co;
+ }
+
+ /* formula derived from barycentric coordinates:
+ * (uvArea1*v1 + uvArea2*v2 + uvArea3*v3)/uvArea
+ * then taking u and v partial derivatives to get dxco and dyco */
+ A = (uv2[0] - uv1[0]) * (uv3[1] - uv1[1]) - (uv3[0] - uv1[0]) * (uv2[1] - uv1[1]);
+
+ if (fabsf(A) > FLT_EPSILON) {
+ A = 0.5f / A;
+
+ d1 = uv2[1] - uv3[1];
+ d2 = uv3[1] - uv1[1];
+ d3 = uv1[1] - uv2[1];
+ bs->dxco[0] = (v1[0] * d1 + v2[0] * d2 + v3[0] * d3) * A;
+ bs->dxco[1] = (v1[1] * d1 + v2[1] * d2 + v3[1] * d3) * A;
+ bs->dxco[2] = (v1[2] * d1 + v2[2] * d2 + v3[2] * d3) * A;
+
+ d1 = uv3[0] - uv2[0];
+ d2 = uv1[0] - uv3[0];
+ d3 = uv2[0] - uv1[0];
+ bs->dyco[0] = (v1[0] * d1 + v2[0] * d2 + v3[0] * d3) * A;
+ bs->dyco[1] = (v1[1] * d1 + v2[1] * d2 + v3[1] * d3) * A;
+ bs->dyco[2] = (v1[2] * d1 + v2[2] * d2 + v3[2] * d3) * A;
+ }
+ else {
+ bs->dxco[0] = bs->dxco[1] = bs->dxco[2] = 0.0f;
+ bs->dyco[0] = bs->dyco[1] = bs->dyco[2] = 0.0f;
+ }
+
+ if (bs->obi->flag & R_TRANSFORMED) {
+ mul_m3_v3(bs->obi->nmat, bs->dxco);
+ mul_m3_v3(bs->obi->nmat, bs->dyco);
+ }
+}
+
+static void do_bake_shade(void *handle, int x, int y, float u, float v)
+{
+ BakeShade *bs = handle;
+ VlakRen *vlr = bs->vlr;
+ ObjectInstanceRen *obi = bs->obi;
+ Object *ob = obi->obr->ob;
+ float l, *v1, *v2, *v3, tvn[3], ttang[4];
+ int quad;
+ ShadeSample *ssamp = &bs->ssamp;
+ ShadeInput *shi = ssamp->shi;
+
+ /* fast threadsafe break test */
+ if (R.test_break(R.tbh))
+ return;
+
+ /* setup render coordinates */
+ if (bs->quad) {
+ v1 = vlr->v1->co;
+ v2 = vlr->v3->co;
+ v3 = vlr->v4->co;
+ }
+ else {
+ v1 = vlr->v1->co;
+ v2 = vlr->v2->co;
+ v3 = vlr->v3->co;
+ }
+
+ l = 1.0f - u - v;
+
+ /* shrink barycentric coordinates inwards slightly to avoid some issues
+ * where baking selected to active might just miss the other face at the
+ * near the edge of a face */
+ if (bs->actob) {
+ const float eps = 1.0f - 1e-4f;
+ float invsum;
+
+ u = (u - 0.5f) * eps + 0.5f;
+ v = (v - 0.5f) * eps + 0.5f;
+ l = (l - 0.5f) * eps + 0.5f;
+
+ invsum = 1.0f / (u + v + l);
+
+ u *= invsum;
+ v *= invsum;
+ l *= invsum;
+ }
+
+ /* renderco */
+ shi->co[0] = l * v3[0] + u * v1[0] + v * v2[0];
+ shi->co[1] = l * v3[1] + u * v1[1] + v * v2[1];
+ shi->co[2] = l * v3[2] + u * v1[2] + v * v2[2];
+
+ /* avoid self shadow with vertex bake from adjacent faces [#33729] */
+ if ((bs->vcol != NULL) && (bs->actob == NULL)) {
+ madd_v3_v3fl(shi->co, vlr->n, 0.0001f);
+ }
+
+ if (obi->flag & R_TRANSFORMED)
+ mul_m4_v3(obi->mat, shi->co);
+
+ copy_v3_v3(shi->dxco, bs->dxco);
+ copy_v3_v3(shi->dyco, bs->dyco);
+
+ quad = bs->quad;
+ bake_set_shade_input(obi, vlr, shi, quad, 0, x, y, u, v);
+
+ if (bs->type == RE_BAKE_NORMALS && R.r.bake_normal_space == R_BAKE_SPACE_TANGENT) {
+ shade_input_set_shade_texco(shi);
+ copy_v3_v3(tvn, shi->nmapnorm);
+ copy_v4_v4(ttang, shi->nmaptang);
+ }
+
+ /* if we are doing selected to active baking, find point on other face */
+ if (bs->actob) {
+ Isect isec, minisec;
+ float co[3], minco[3], dist, mindist = 0.0f;
+ int hit, sign, dir = 1;
+
+ /* intersect with ray going forward and backward*/
+ hit = 0;
+ memset(&minisec, 0, sizeof(minisec));
+ minco[0] = minco[1] = minco[2] = 0.0f;
+
+ copy_v3_v3(bs->dir, shi->vn);
+
+ for (sign = -1; sign <= 1; sign += 2) {
+ memset(&isec, 0, sizeof(isec));
+ isec.mode = RE_RAY_MIRROR;
+
+ isec.orig.ob = obi;
+ isec.orig.face = vlr;
+ isec.userdata = bs->actob;
+ isec.check = RE_CHECK_VLR_BAKE;
+ isec.skip = RE_SKIP_VLR_NEIGHBOUR;
+
+ if (bake_intersect_tree(R.raytree, &isec, shi->co, shi->vn, sign, co, &dist)) {
+ if (!hit || len_squared_v3v3(shi->co, co) < len_squared_v3v3(shi->co, minco)) {
+ minisec = isec;
+ mindist = dist;
+ copy_v3_v3(minco, co);
+ hit = 1;
+ dir = sign;
+ }
+ }
+ }
+
+ if (ELEM(bs->type, RE_BAKE_DISPLACEMENT, RE_BAKE_DERIVATIVE)) {
+ if (hit)
+ bake_displacement(handle, shi, (dir == -1) ? mindist : -mindist, x, y);
+ else
+ bake_displacement(handle, shi, 0.0f, x, y);
+ return;
+ }
+
+ /* if hit, we shade from the new point, otherwise from point one starting face */
+ if (hit) {
+ obi = (ObjectInstanceRen *)minisec.hit.ob;
+ vlr = (VlakRen *)minisec.hit.face;
+ quad = (minisec.isect == 2);
+ copy_v3_v3(shi->co, minco);
+
+ u = -minisec.u;
+ v = -minisec.v;
+ bake_set_shade_input(obi, vlr, shi, quad, 1, x, y, u, v);
+ }
+ }
+
+ if (bs->type == RE_BAKE_NORMALS && R.r.bake_normal_space == R_BAKE_SPACE_TANGENT)
+ bake_shade(handle, ob, shi, quad, x, y, u, v, tvn, ttang);
+ else
+ bake_shade(handle, ob, shi, quad, x, y, u, v, NULL, NULL);
+}
+
+static int get_next_bake_face(BakeShade *bs)
+{
+ ObjectRen *obr;
+ VlakRen *vlr;
+ MTFace *tface;
+ static int v = 0, vdone = false;
+ static ObjectInstanceRen *obi = NULL;
+
+ if (bs == NULL) {
+ vlr = NULL;
+ v = vdone = false;
+ obi = R.instancetable.first;
+ return 0;
+ }
+
+ BLI_thread_lock(LOCK_CUSTOM1);
+
+ for (; obi; obi = obi->next, v = 0) {
+ obr = obi->obr;
+
+ /* only allow non instances here */
+ if (obr->flag & R_INSTANCEABLE)
+ continue;
+
+ for (; v < obr->totvlak; v++) {
+ vlr = RE_findOrAddVlak(obr, v);
+
+ if ((bs->actob && bs->actob == obr->ob) || (!bs->actob && (obr->ob->flag & SELECT))) {
+ if (R.r.bake_flag & R_BAKE_VCOL) {
+ /* Gather face data for vertex color bake */
+ Mesh *me;
+ int *origindex, vcollayer;
+ CustomDataLayer *cdl;
+
+ if (obr->ob->type != OB_MESH)
+ continue;
+ me = obr->ob->data;
+
+ origindex = RE_vlakren_get_origindex(obr, vlr, 0);
+ if (origindex == NULL)
+ continue;
+ if (*origindex >= me->totpoly) {
+ /* Small hack for Array modifier, which gives false
+ * original indices - z0r */
+ continue;
+ }
+#if 0
+ /* Only shade selected faces. */
+ if ((me->mface[*origindex].flag & ME_FACE_SEL) == 0)
+ continue;
+#endif
+
+ vcollayer = CustomData_get_render_layer_index(&me->ldata, CD_MLOOPCOL);
+ if (vcollayer == -1)
+ continue;
+
+ cdl = &me->ldata.layers[vcollayer];
+ bs->mpoly = me->mpoly + *origindex;
+ bs->vcol = ((MLoopCol *)cdl->data) + bs->mpoly->loopstart;
+ bs->mloop = me->mloop + bs->mpoly->loopstart;
+
+ /* Tag mesh for reevaluation. */
+ me->id.tag |= LIB_TAG_DOIT;
+ }
+ else {
+ Image *ima = NULL;
+ ImBuf *ibuf = NULL;
+ const float vec_alpha[4] = {0.0f, 0.0f, 0.0f, 0.0f};
+ const float vec_solid[4] = {0.0f, 0.0f, 0.0f, 1.0f};
+ const float nor_alpha[4] = {0.5f, 0.5f, 1.0f, 0.0f};
+ const float nor_solid[4] = {0.5f, 0.5f, 1.0f, 1.0f};
+ const float disp_alpha[4] = {0.5f, 0.5f, 0.5f, 0.0f};
+ const float disp_solid[4] = {0.5f, 0.5f, 0.5f, 1.0f};
+
+ tface = RE_vlakren_get_tface(obr, vlr, obr->bakemtface, NULL, 0);
+
+ if (!tface || !tface->tpage)
+ continue;
+
+ ima = tface->tpage;
+ ibuf = BKE_image_acquire_ibuf(ima, NULL, NULL);
+
+ if (ibuf == NULL)
+ continue;
+
+ if (ibuf->rect == NULL && ibuf->rect_float == NULL) {
+ BKE_image_release_ibuf(ima, ibuf, NULL);
+ continue;
+ }
+
+ if (ibuf->rect_float && !(ibuf->channels == 0 || ibuf->channels == 4)) {
+ BKE_image_release_ibuf(ima, ibuf, NULL);
+ continue;
+ }
+
+ if (ima->flag & IMA_USED_FOR_RENDER) {
+ ima->id.tag &= ~LIB_TAG_DOIT;
+ BKE_image_release_ibuf(ima, ibuf, NULL);
+ continue;
+ }
+
+ /* find the image for the first time? */
+ if (ima->id.tag & LIB_TAG_DOIT) {
+ ima->id.tag &= ~LIB_TAG_DOIT;
+
+ /* we either fill in float or char, this ensures things go fine */
+ if (ibuf->rect_float)
+ imb_freerectImBuf(ibuf);
+ /* clear image */
+ if (R.r.bake_flag & R_BAKE_CLEAR) {
+ if (R.r.bake_mode == RE_BAKE_NORMALS && R.r.bake_normal_space == R_BAKE_SPACE_TANGENT)
+ IMB_rectfill(ibuf, (ibuf->planes == R_IMF_PLANES_RGBA) ? nor_alpha : nor_solid);
+ else if (ELEM(R.r.bake_mode, RE_BAKE_DISPLACEMENT, RE_BAKE_DERIVATIVE))
+ IMB_rectfill(ibuf, (ibuf->planes == R_IMF_PLANES_RGBA) ? disp_alpha : disp_solid);
+ else
+ IMB_rectfill(ibuf, (ibuf->planes == R_IMF_PLANES_RGBA) ? vec_alpha : vec_solid);
+ }
+ /* might be read by UI to set active image for display */
+ R.bakebuf = ima;
+ }
+
+ /* Tag image for redraw. */
+ ibuf->userflags |= IB_DISPLAY_BUFFER_INVALID;
+ BKE_image_release_ibuf(ima, ibuf, NULL);
+ }
+
+ bs->obi = obi;
+ bs->vlr = vlr;
+ bs->vdone++; /* only for error message if nothing was rendered */
+ v++;
+ BLI_thread_unlock(LOCK_CUSTOM1);
+ return 1;
+ }
+ }
+ }
+
+ BLI_thread_unlock(LOCK_CUSTOM1);
+ return 0;
+}
+
+static void bake_single_vertex(BakeShade *bs, VertRen *vert, float u, float v)
+{
+ int *origindex, i;
+ MLoopCol *basevcol;
+ MLoop *mloop;
+
+ /* per vertex fixed seed */
+ BLI_thread_srandom(bs->thread, vert->index);
+
+ origindex = RE_vertren_get_origindex(bs->obi->obr, vert, 0);
+ if (!origindex || *origindex == ORIGINDEX_NONE)
+ return;
+
+ /* Search for matching vertex index and apply shading. */
+ for (i = 0; i < bs->mpoly->totloop; i++) {
+ mloop = bs->mloop + i;
+ if (mloop->v != *origindex)
+ continue;
+ basevcol = bs->vcol;
+ bs->vcol = basevcol + i;
+ do_bake_shade(bs, 0, 0, u, v);
+ bs->vcol = basevcol;
+ break;
+ }
+}
+
+/* Bake all vertices of a face. Actually, this still works on a face-by-face
+ * basis, and each vertex on each face is shaded. Vertex colors are a property
+ * of loops, not vertices. */
+static void shade_verts(BakeShade *bs)
+{
+ VlakRen *vlr = bs->vlr;
+
+ /* Disable baking to image; write to vcol instead. vcol pointer is set in
+ * bake_single_vertex. */
+ bs->ima = NULL;
+ bs->rect = NULL;
+ bs->rect_float = NULL;
+ bs->displacement_buffer = NULL;
+ bs->displacement_min = FLT_MAX;
+ bs->displacement_max = -FLT_MAX;
+
+ bs->quad = 0;
+
+ /* No anti-aliasing for vertices. */
+ zero_v3(bs->dxco);
+ zero_v3(bs->dyco);
+
+ /* Shade each vertex of the face. u and v are barycentric coordinates; since
+ * we're only interested in vertices, these will be 0 or 1. */
+ if ((vlr->flag & R_FACE_SPLIT) == 0) {
+ /* Processing triangle face, whole quad, or first half of split quad. */
+
+ bake_single_vertex(bs, bs->vlr->v1, 1.0f, 0.0f);
+ bake_single_vertex(bs, bs->vlr->v2, 0.0f, 1.0f);
+ bake_single_vertex(bs, bs->vlr->v3, 0.0f, 0.0f);
+
+ if (vlr->v4) {
+ bs->quad = 1;
+ bake_single_vertex(bs, bs->vlr->v4, 0.0f, 0.0f);
+ }
+ }
+ else {
+ /* Processing second half of split quad. Only one vertex to go. */
+ if (vlr->flag & R_DIVIDE_24) {
+ bake_single_vertex(bs, bs->vlr->v2, 0.0f, 1.0f);
+ }
+ else {
+ bake_single_vertex(bs, bs->vlr->v3, 0.0f, 0.0f);
+ }
+ }
+}
+
+/* already have tested for tface and ima and zspan */
+static void shade_tface(BakeShade *bs)
+{
+ VlakRen *vlr = bs->vlr;
+ ObjectInstanceRen *obi = bs->obi;
+ ObjectRen *obr = obi->obr;
+ MTFace *tface = RE_vlakren_get_tface(obr, vlr, obr->bakemtface, NULL, 0);
+ Image *ima = tface->tpage;
+ float vec[4][2];
+ int a, i1, i2, i3;
+
+ /* per face fixed seed */
+ BLI_thread_srandom(bs->thread, vlr->index);
+
+ /* check valid zspan */
+ if (ima != bs->ima) {
+ BKE_image_release_ibuf(bs->ima, bs->ibuf, NULL);
+
+ bs->ima = ima;
+ bs->ibuf = BKE_image_acquire_ibuf(ima, NULL, NULL);
+ /* note, these calls only free/fill contents of zspan struct, not zspan itself */
+ zbuf_free_span(bs->zspan);
+ zbuf_alloc_span(bs->zspan, bs->ibuf->x, bs->ibuf->y, R.clipcrop);
+ }
+
+ bs->rectx = bs->ibuf->x;
+ bs->recty = bs->ibuf->y;
+ bs->rect = bs->ibuf->rect;
+ bs->rect_colorspace = bs->ibuf->rect_colorspace;
+ bs->rect_float = bs->ibuf->rect_float;
+ bs->vcol = NULL;
+ bs->quad = 0;
+ bs->rect_mask = NULL;
+ bs->displacement_buffer = NULL;
+
+ if (bs->use_mask || bs->use_displacement_buffer) {
+ BakeImBufuserData *userdata = bs->ibuf->userdata;
+ if (userdata == NULL) {
+ BLI_thread_lock(LOCK_CUSTOM1);
+ userdata = bs->ibuf->userdata;
+ if (userdata == NULL) /* since the thread was locked, its possible another thread alloced the value */
+ userdata = MEM_callocN(sizeof(BakeImBufuserData), "BakeImBufuserData");
+
+ if (bs->use_mask) {
+ if (userdata->mask_buffer == NULL) {
+ userdata->mask_buffer = MEM_callocN(sizeof(char) * bs->rectx * bs->recty, "BakeMask");
+ }
+ }
+
+ if (bs->use_displacement_buffer) {
+ if (userdata->displacement_buffer == NULL) {
+ userdata->displacement_buffer = MEM_callocN(sizeof(float) * bs->rectx * bs->recty, "BakeDisp");
+ }
+ }
+
+ bs->ibuf->userdata = userdata;
+
+ BLI_thread_unlock(LOCK_CUSTOM1);
+ }
+
+ bs->rect_mask = userdata->mask_buffer;
+ bs->displacement_buffer = userdata->displacement_buffer;
+ }
+
+ /* get pixel level vertex coordinates */
+ for (a = 0; a < 4; a++) {
+ /* Note, workaround for pixel aligned UVs which are common and can screw up our intersection tests
+ * where a pixel gets in between 2 faces or the middle of a quad,
+ * camera aligned quads also have this problem but they are less common.
+ * Add a small offset to the UVs, fixes bug #18685 - Campbell */
+ vec[a][0] = tface->uv[a][0] * (float)bs->rectx - (0.5f + 0.001f);
+ vec[a][1] = tface->uv[a][1] * (float)bs->recty - (0.5f + 0.002f);
+ }
+
+ /* UV indices have to be corrected for possible quad->tria splits */
+ i1 = 0; i2 = 1; i3 = 2;
+ vlr_set_uv_indices(vlr, &i1, &i2, &i3);
+ bake_set_vlr_dxyco(bs, vec[i1], vec[i2], vec[i3]);
+ zspan_scanconvert(bs->zspan, bs, vec[i1], vec[i2], vec[i3], do_bake_shade);
+
+ if (vlr->v4) {
+ bs->quad = 1;
+ bake_set_vlr_dxyco(bs, vec[0], vec[2], vec[3]);
+ zspan_scanconvert(bs->zspan, bs, vec[0], vec[2], vec[3], do_bake_shade);
+ }
+}
+
+static void *do_bake_thread(void *bs_v)
+{
+ BakeShade *bs = bs_v;
+
+ while (get_next_bake_face(bs)) {
+ if (R.r.bake_flag & R_BAKE_VCOL) {
+ shade_verts(bs);
+ }
+ else {
+ shade_tface(bs);
+ }
+
+ /* fast threadsafe break test */
+ if (R.test_break(R.tbh))
+ break;
+
+ /* access is not threadsafe but since its just true/false probably ok
+ * only used for interactive baking */
+ if (bs->do_update) {
+ *bs->do_update = true;
+ }
+ }
+ bs->ready = true;
+
+ BKE_image_release_ibuf(bs->ima, bs->ibuf, NULL);
+
+ return NULL;
+}
+
+void RE_bake_ibuf_filter(ImBuf *ibuf, char *mask, const int filter)
+{
+ /* must check before filtering */
+ const bool is_new_alpha = (ibuf->planes != R_IMF_PLANES_RGBA) && BKE_imbuf_alpha_test(ibuf);
+
+ /* Margin */
+ if (filter) {
+ IMB_filter_extend(ibuf, mask, filter);
+ }
+
+ /* if the bake results in new alpha then change the image setting */
+ if (is_new_alpha) {
+ ibuf->planes = R_IMF_PLANES_RGBA;
+ }
+ else {
+ if (filter && ibuf->planes != R_IMF_PLANES_RGBA) {
+ /* clear alpha added by filtering */
+ IMB_rectfill_alpha(ibuf, 1.0f);
+ }
+ }
+}
+
+void RE_bake_ibuf_normalize_displacement(ImBuf *ibuf, float *displacement, char *mask, float displacement_min, float displacement_max)
+{
+ int i;
+ const float *current_displacement = displacement;
+ const char *current_mask = mask;
+ float max_distance;
+
+ max_distance = max_ff(fabsf(displacement_min), fabsf(displacement_max));
+
+ for (i = 0; i < ibuf->x * ibuf->y; i++) {
+ if (*current_mask == FILTER_MASK_USED) {
+ float normalized_displacement;
+
+ if (max_distance > 1e-5f)
+ normalized_displacement = (*current_displacement + max_distance) / (max_distance * 2);
+ else
+ normalized_displacement = 0.5f;
+
+ if (ibuf->rect_float) {
+ /* currently baking happens to RGBA only */
+ float *fp = ibuf->rect_float + i * 4;
+ fp[0] = fp[1] = fp[2] = normalized_displacement;
+ fp[3] = 1.0f;
+ }
+
+ if (ibuf->rect) {
+ unsigned char *cp = (unsigned char *) (ibuf->rect + i);
+ cp[0] = cp[1] = cp[2] = unit_float_to_uchar_clamp(normalized_displacement);
+ cp[3] = 255;
+ }
+ }
+
+ current_displacement++;
+ current_mask++;
+ }
+}
+
+/* using object selection tags, the faces with UV maps get baked */
+/* render should have been setup */
+/* returns 0 if nothing was handled */
+int RE_bake_shade_all_selected(Render *re, int type, Object *actob, short *do_update, float *progress)
+{
+ BakeShade *handles;
+ ListBase threads;
+ Image *ima;
+ int a, vdone = false, result = BAKE_RESULT_OK;
+ bool use_mask = false;
+ bool use_displacement_buffer = false;
+ bool do_manage = false;
+
+ if (ELEM(type, RE_BAKE_ALL, RE_BAKE_TEXTURE)) {
+ do_manage = BKE_scene_check_color_management_enabled(re->scene);
+ }
+
+ re->scene_color_manage = BKE_scene_check_color_management_enabled(re->scene);
+
+ /* initialize render global */
+ R = *re;
+ R.bakebuf = NULL;
+
+ /* initialize static vars */
+ get_next_bake_face(NULL);
+
+ /* do we need a mask? */
+ if (re->r.bake_filter)
+ use_mask = true;
+
+ /* do we need buffer to store displacements */
+ if (ELEM(type, RE_BAKE_DISPLACEMENT, RE_BAKE_DERIVATIVE)) {
+ if (((R.r.bake_flag & R_BAKE_NORMALIZE) && R.r.bake_maxdist == 0.0f) ||
+ (type == RE_BAKE_DERIVATIVE))
+ {
+ use_displacement_buffer = true;
+ use_mask = true;
+ }
+ }
+
+ /* baker uses this flag to detect if image was initialized */
+ if ((R.r.bake_flag & R_BAKE_VCOL) == 0) {
+ for (ima = G.main->image.first; ima; ima = ima->id.next) {
+ ImBuf *ibuf = BKE_image_acquire_ibuf(ima, NULL, NULL);
+ ima->id.tag |= LIB_TAG_DOIT;
+ ima->flag &= ~IMA_USED_FOR_RENDER;
+ if (ibuf) {
+ ibuf->userdata = NULL; /* use for masking if needed */
+ }
+ BKE_image_release_ibuf(ima, ibuf, NULL);
+ }
+ }
+
+ if (R.r.bake_flag & R_BAKE_VCOL) {
+ /* untag all meshes */
+ BKE_main_id_tag_listbase(&G.main->mesh, LIB_TAG_DOIT, false);
+ }
+
+ BLI_threadpool_init(&threads, do_bake_thread, re->r.threads);
+
+ handles = MEM_callocN(sizeof(BakeShade) * re->r.threads, "BakeShade");
+
+ /* get the threads running */
+ for (a = 0; a < re->r.threads; a++) {
+ handles[a].thread = a;
+
+ /* set defaults in handles */
+ handles[a].ssamp.shi[0].lay = re->lay;
+
+ if (type == RE_BAKE_SHADOW) {
+ handles[a].ssamp.shi[0].passflag = SCE_PASS_SHADOW;
+ }
+ else {
+ handles[a].ssamp.shi[0].passflag = SCE_PASS_COMBINED;
+ }
+ handles[a].ssamp.shi[0].combinedflag = ~(SCE_PASS_SPEC);
+ handles[a].ssamp.shi[0].thread = a;
+ handles[a].ssamp.shi[0].do_manage = do_manage;
+ handles[a].ssamp.tot = 1;
+
+ handles[a].type = type;
+ handles[a].actob = actob;
+ if (R.r.bake_flag & R_BAKE_VCOL)
+ handles[a].zspan = NULL;
+ else
+ handles[a].zspan = MEM_callocN(sizeof(ZSpan), "zspan for bake");
+
+ handles[a].use_mask = use_mask;
+ handles[a].use_displacement_buffer = use_displacement_buffer;
+
+ handles[a].do_update = do_update; /* use to tell the view to update */
+
+ handles[a].displacement_min = FLT_MAX;
+ handles[a].displacement_max = -FLT_MAX;
+
+ BLI_threadpool_insert(&threads, &handles[a]);
+ }
+
+ /* wait for everything to be done */
+ a = 0;
+ while (a != re->r.threads) {
+ PIL_sleep_ms(50);
+
+ /* calculate progress */
+ for (vdone = false, a = 0; a < re->r.threads; a++)
+ vdone += handles[a].vdone;
+ if (progress)
+ *progress = (float)(vdone / (float)re->totvlak);
+
+ for (a = 0; a < re->r.threads; a++) {
+ if (handles[a].ready == false) {
+ break;
+ }
+ }
+ }
+
+ /* filter and refresh images */
+ if ((R.r.bake_flag & R_BAKE_VCOL) == 0) {
+ float displacement_min = FLT_MAX, displacement_max = -FLT_MAX;
+
+ if (use_displacement_buffer) {
+ for (a = 0; a < re->r.threads; a++) {
+ displacement_min = min_ff(displacement_min, handles[a].displacement_min);
+ displacement_max = max_ff(displacement_max, handles[a].displacement_max);
+ }
+ }
+
+ for (ima = G.main->image.first; ima; ima = ima->id.next) {
+ if ((ima->id.tag & LIB_TAG_DOIT) == 0) {
+ ImBuf *ibuf = BKE_image_acquire_ibuf(ima, NULL, NULL);
+ BakeImBufuserData *userdata;
+
+ if (ima->flag & IMA_USED_FOR_RENDER)
+ result = BAKE_RESULT_FEEDBACK_LOOP;
+
+ if (!ibuf)
+ continue;
+
+ userdata = (BakeImBufuserData *)ibuf->userdata;
+ if (userdata) {
+ if (use_displacement_buffer) {
+ if (type == RE_BAKE_DERIVATIVE) {
+ float user_scale = (R.r.bake_flag & R_BAKE_USERSCALE) ? R.r.bake_user_scale : -1.0f;
+ RE_bake_make_derivative(ibuf, userdata->displacement_buffer, userdata->mask_buffer,
+ displacement_min, displacement_max, user_scale);
+ }
+ else {
+ RE_bake_ibuf_normalize_displacement(ibuf, userdata->displacement_buffer, userdata->mask_buffer,
+ displacement_min, displacement_max);
+ }
+ }
+
+ RE_bake_ibuf_filter(ibuf, userdata->mask_buffer, re->r.bake_filter);
+ }
+
+ ibuf->userflags |= IB_BITMAPDIRTY;
+ BKE_image_release_ibuf(ima, ibuf, NULL);
+ }
+ }
+
+ /* calculate return value */
+ for (a = 0; a < re->r.threads; a++) {
+ zbuf_free_span(handles[a].zspan);
+ MEM_freeN(handles[a].zspan);
+ }
+ }
+
+ MEM_freeN(handles);
+
+ BLI_threadpool_end(&threads);
+
+ if (vdone == 0) {
+ result = BAKE_RESULT_NO_OBJECTS;
+ }
+
+ return result;
+}
+
+struct Image *RE_bake_shade_get_image(void)
+{
+ return R.bakebuf;
+}
+
+/* **************** Derivative Maps Baker **************** */
+
+static void add_single_heights_margin(const ImBuf *ibuf, const char *mask, float *heights_buffer)
+{
+ int x, y;
+
+ for (y = 0; y < ibuf->y; y++) {
+ for (x = 0; x < ibuf->x; x++) {
+ int index = ibuf->x * y + x;
+
+ /* If unassigned pixel, look for neighbors. */
+ if (mask[index] != FILTER_MASK_USED) {
+ float height_acc = 0;
+ int denom = 0;
+ int i, j;
+
+ for (j = -1; j <= 1; j++)
+ for (i = -1; i <= 1; i++) {
+ int w = (i == 0 ? 1 : 0) + (j == 0 ? 1 : 0) + 1;
+
+ if (i != 0 || j != 0) {
+ int index2 = 0;
+ int x0 = x + i;
+ int y0 = y + j;
+
+ CLAMP(x0, 0, ibuf->x - 1);
+ CLAMP(y0, 0, ibuf->y - 1);
+
+ index2 = ibuf->x * y0 + x0;
+
+ if (mask[index2] == FILTER_MASK_USED) {
+ height_acc += w * heights_buffer[index2];
+ denom += w;
+ }
+ }
+ }
+
+ /* Insert final value. */
+ if (denom > 0) {
+ heights_buffer[index] = height_acc / denom;
+ }
+ }
+ }
+ }
+}
+
+/* returns user-scale */
+float RE_bake_make_derivative(ImBuf *ibuf, float *heights_buffer, const char *mask,
+ const float height_min, const float height_max,
+ const float fmult)
+{
+ const float delta_height = height_max - height_min;
+ const float denom = delta_height > 0.0f ? (8 * delta_height) : 1.0f;
+ bool auto_range_fit = fmult <= 0.0f;
+ float max_num_deriv = -1.0f;
+ int x, y, index;
+
+ /* Need a single margin to calculate good derivatives. */
+ add_single_heights_margin(ibuf, mask, heights_buffer);
+
+ if (auto_range_fit) {
+ /* If automatic range fitting is enabled. */
+ for (y = 0; y < ibuf->y; y++) {
+ const int Yu = y == (ibuf->y - 1) ? (ibuf->y - 1) : (y + 1);
+ const int Yc = y;
+ const int Yd = y == 0 ? 0 : (y - 1);
+
+ for (x = 0; x < ibuf->x; x++) {
+ const int Xl = x == 0 ? 0 : (x - 1);
+ const int Xc = x;
+ const int Xr = x == (ibuf->x - 1) ? (ibuf->x - 1) : (x + 1);
+
+ const float Hcy = heights_buffer[Yc * ibuf->x + Xr] - heights_buffer[Yc * ibuf->x + Xl];
+ const float Hu = heights_buffer[Yu * ibuf->x + Xr] - heights_buffer[Yu * ibuf->x + Xl];
+ const float Hd = heights_buffer[Yd * ibuf->x + Xr] - heights_buffer[Yd * ibuf->x + Xl];
+
+ const float Hl = heights_buffer[Yu * ibuf->x + Xl] - heights_buffer[Yd * ibuf->x + Xl];
+ const float Hcx = heights_buffer[Yu * ibuf->x + Xc] - heights_buffer[Yd * ibuf->x + Xc];
+ const float Hr = heights_buffer[Yu * ibuf->x + Xr] - heights_buffer[Yd * ibuf->x + Xr];
+
+ /* This corresponds to using the sobel kernel on the heights buffer
+ * to obtain the derivative multiplied by 8.
+ */
+ const float deriv_x = Hu + 2 * Hcy + Hd;
+ const float deriv_y = Hr + 2 * Hcx + Hl;
+
+ /* early out */
+ index = ibuf->x * y + x;
+ if (mask[index] != FILTER_MASK_USED) {
+ continue;
+ }
+
+ /* Widen bound. */
+ if (fabsf(deriv_x) > max_num_deriv) {
+ max_num_deriv = fabsf(deriv_x);
+ }
+
+ if (fabsf(deriv_y) > max_num_deriv) {
+ max_num_deriv = fabsf(deriv_y);
+ }
+ }
+ }
+ }
+
+ /* Output derivatives. */
+ auto_range_fit &= (max_num_deriv > 0);
+ for (y = 0; y < ibuf->y; y++) {
+ const int Yu = y == (ibuf->y - 1) ? (ibuf->y - 1) : (y + 1);
+ const int Yc = y;
+ const int Yd = y == 0 ? 0 : (y - 1);
+
+ for (x = 0; x < ibuf->x; x++) {
+ const int Xl = x == 0 ? 0 : (x - 1);
+ const int Xc = x;
+ const int Xr = x == (ibuf->x - 1) ? (ibuf->x - 1) : (x + 1);
+
+ const float Hcy = heights_buffer[Yc * ibuf->x + Xr] - heights_buffer[Yc * ibuf->x + Xl];
+ const float Hu = heights_buffer[Yu * ibuf->x + Xr] - heights_buffer[Yu * ibuf->x + Xl];
+ const float Hd = heights_buffer[Yd * ibuf->x + Xr] - heights_buffer[Yd * ibuf->x + Xl];
+
+ const float Hl = heights_buffer[Yu * ibuf->x + Xl] - heights_buffer[Yd * ibuf->x + Xl];
+ const float Hcx = heights_buffer[Yu * ibuf->x + Xc] - heights_buffer[Yd * ibuf->x + Xc];
+ const float Hr = heights_buffer[Yu * ibuf->x + Xr] - heights_buffer[Yd * ibuf->x + Xr];
+
+ /* This corresponds to using the sobel kernel on the heights buffer
+ * to obtain the derivative multiplied by 8.
+ */
+ float deriv_x = Hu + 2 * Hcy + Hd;
+ float deriv_y = Hr + 2 * Hcx + Hl;
+
+ /* Early out. */
+ index = ibuf->x * y + x;
+ if (mask[index] != FILTER_MASK_USED) {
+ continue;
+ }
+
+ if (auto_range_fit) {
+ deriv_x /= max_num_deriv;
+ deriv_y /= max_num_deriv;
+ }
+ else {
+ deriv_x *= (fmult / denom);
+ deriv_y *= (fmult / denom);
+ }
+
+ deriv_x = deriv_x * 0.5f + 0.5f;
+ deriv_y = deriv_y * 0.5f + 0.5f;
+
+ /* Clamp. */
+ CLAMP(deriv_x, 0.0f, 1.0f);
+ CLAMP(deriv_y, 0.0f, 1.0f);
+
+ /* Write out derivatives. */
+ if (ibuf->rect_float) {
+ float *rrgbf = ibuf->rect_float + index * 4;
+
+ rrgbf[0] = deriv_x;
+ rrgbf[1] = deriv_y;
+ rrgbf[2] = 0.0f;
+ rrgbf[3] = 1.0f;
+ }
+ else {
+ char *rrgb = (char *)ibuf->rect + index * 4;
+
+ rrgb[0] = unit_float_to_uchar_clamp(deriv_x);
+ rrgb[1] = unit_float_to_uchar_clamp(deriv_y);
+ rrgb[2] = 0;
+ rrgb[3] = 255;
+ }
+ }
+ }
+
+ /* Eeturn user-scale (for rendering). */
+ return auto_range_fit ? (max_num_deriv / denom) : (fmult > 0.0f ? (1.0f / fmult) : 0.0f);
+}
diff --git a/source/blender/render/intern/source/convertblender.c b/source/blender/render/intern/source/convertblender.c
new file mode 100644
index 00000000000..8675ffec313
--- /dev/null
+++ b/source/blender/render/intern/source/convertblender.c
@@ -0,0 +1,6014 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * Contributors: 2004/2005/2006 Blender Foundation, full recode
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/render/intern/source/convertblender.c
+ * \ingroup render
+ */
+
+#include <math.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <limits.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_math.h"
+#include "BLI_blenlib.h"
+#include "BLI_utildefines.h"
+#include "BLI_rand.h"
+#include "BLI_memarena.h"
+#ifdef WITH_FREESTYLE
+# include "BLI_edgehash.h"
+#endif
+
+#include "BLT_translation.h"
+
+#include "DNA_material_types.h"
+#include "DNA_curve_types.h"
+#include "DNA_group_types.h"
+#include "DNA_lamp_types.h"
+#include "DNA_image_types.h"
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_modifier_types.h"
+#include "DNA_node_types.h"
+#include "DNA_object_types.h"
+#include "DNA_object_fluidsim_types.h"
+#include "DNA_particle_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_texture_types.h"
+
+#include "BKE_anim.h"
+#include "BKE_curve.h"
+#include "BKE_customdata.h"
+#include "BKE_colortools.h"
+#include "BKE_displist.h"
+#include "BKE_depsgraph.h"
+#include "BKE_DerivedMesh.h"
+#include "BKE_global.h"
+#include "BKE_key.h"
+#include "BKE_image.h"
+#include "BKE_lattice.h"
+#include "BKE_material.h"
+#include "BKE_main.h"
+#include "BKE_mball.h"
+#include "BKE_mesh.h"
+#include "BKE_modifier.h"
+#include "BKE_node.h"
+#include "BKE_object.h"
+#include "BKE_particle.h"
+#include "BKE_scene.h"
+
+#include "PIL_time.h"
+
+#include "envmap.h"
+#include "occlusion.h"
+#include "pointdensity.h"
+#include "voxeldata.h"
+#include "render_types.h"
+#include "rendercore.h"
+#include "renderdatabase.h"
+#include "renderpipeline.h"
+#include "shadbuf.h"
+#include "shading.h"
+#include "strand.h"
+#include "texture.h"
+#include "volume_precache.h"
+#include "sss.h"
+#include "zbuf.h"
+#include "sunsky.h"
+
+/* 10 times larger than normal epsilon, test it on default nurbs sphere with ray_transp (for quad detection) */
+/* or for checking vertex normal flips */
+#define FLT_EPSILON10 1.19209290e-06F
+
+/* could enable at some point but for now there are far too many conversions */
+#ifdef __GNUC__
+# pragma GCC diagnostic ignored "-Wdouble-promotion"
+#endif
+
+/* ------------------------------------------------------------------------- */
+/* tool functions/defines for ad hoc simplification and possible future
+ * cleanup */
+/* ------------------------------------------------------------------------- */
+
+#define UVTOINDEX(u, v) (startvlak + (u) * sizev + (v))
+/*
+ *
+ * NOTE THAT U/V COORDINATES ARE SOMETIMES SWAPPED !!
+ *
+ * ^ ()----p4----p3----()
+ * | | | | |
+ * u | | F1 | F2 |
+ * | | | |
+ * ()----p1----p2----()
+ * v ->
+ */
+
+/* ------------------------------------------------------------------------- */
+
+#define CD_MASK_RENDER_INTERNAL \
+ (CD_MASK_BAREMESH | CD_MASK_MFACE | CD_MASK_MTFACE | CD_MASK_MCOL)
+
+static void split_v_renderfaces(ObjectRen *obr, int startvlak, int UNUSED(startvert), int UNUSED(usize), int vsize, int uIndex, int UNUSED(cyclu), int cyclv)
+{
+ int vLen = vsize-1+(!!cyclv);
+ int v;
+
+ for (v=0; v<vLen; v++) {
+ VlakRen *vlr = RE_findOrAddVlak(obr, startvlak + vLen*uIndex + v);
+ VlakRen *vlr_other;
+ VertRen *vert = RE_vertren_copy(obr, vlr->v2);
+
+ if (cyclv) {
+ vlr->v2 = vert;
+
+ if (v == vLen - 1) {
+ vlr_other = RE_findOrAddVlak(obr, startvlak + vLen*uIndex + 0);
+ vlr_other->v1 = vert;
+ }
+ else {
+ vlr_other = RE_findOrAddVlak(obr, startvlak + vLen*uIndex + v+1);
+ vlr_other->v1 = vert;
+ }
+ }
+ else {
+ vlr->v2 = vert;
+
+ if (v < vLen - 1) {
+ vlr_other = RE_findOrAddVlak(obr, startvlak + vLen*uIndex + v+1);
+ vlr_other->v1 = vert;
+ }
+
+ if (v == 0) {
+ vlr->v1 = RE_vertren_copy(obr, vlr->v1);
+ }
+ }
+ }
+}
+
+/* ------------------------------------------------------------------------- */
+/* Stress, tangents and normals */
+/* ------------------------------------------------------------------------- */
+
+static void calc_edge_stress_add(float *accum, VertRen *v1, VertRen *v2)
+{
+ float len= len_v3v3(v1->co, v2->co)/len_v3v3(v1->orco, v2->orco);
+ float *acc;
+
+ acc= accum + 2*v1->index;
+ acc[0]+= len;
+ acc[1]+= 1.0f;
+
+ acc= accum + 2*v2->index;
+ acc[0]+= len;
+ acc[1]+= 1.0f;
+}
+
+static void calc_edge_stress(Render *UNUSED(re), ObjectRen *obr, Mesh *me)
+{
+ float loc[3], size[3], *accum, *acc, *accumoffs, *stress;
+ int a;
+
+ if (obr->totvert==0) return;
+
+ BKE_mesh_texspace_get(me, loc, NULL, size);
+
+ accum= MEM_callocN(2*sizeof(float)*obr->totvert, "temp accum for stress");
+
+ /* de-normalize orco */
+ for (a=0; a<obr->totvert; a++) {
+ VertRen *ver= RE_findOrAddVert(obr, a);
+ if (ver->orco) {
+ ver->orco[0]= ver->orco[0]*size[0] +loc[0];
+ ver->orco[1]= ver->orco[1]*size[1] +loc[1];
+ ver->orco[2]= ver->orco[2]*size[2] +loc[2];
+ }
+ }
+
+ /* add stress values */
+ accumoffs= accum; /* so we can use vertex index */
+ for (a=0; a<obr->totvlak; a++) {
+ VlakRen *vlr= RE_findOrAddVlak(obr, a);
+
+ if (vlr->v1->orco && vlr->v4) {
+ calc_edge_stress_add(accumoffs, vlr->v1, vlr->v2);
+ calc_edge_stress_add(accumoffs, vlr->v2, vlr->v3);
+ calc_edge_stress_add(accumoffs, vlr->v3, vlr->v1);
+ if (vlr->v4) {
+ calc_edge_stress_add(accumoffs, vlr->v3, vlr->v4);
+ calc_edge_stress_add(accumoffs, vlr->v4, vlr->v1);
+ calc_edge_stress_add(accumoffs, vlr->v2, vlr->v4);
+ }
+ }
+ }
+
+ for (a=0; a<obr->totvert; a++) {
+ VertRen *ver= RE_findOrAddVert(obr, a);
+ if (ver->orco) {
+ /* find stress value */
+ acc= accumoffs + 2*ver->index;
+ if (acc[1]!=0.0f)
+ acc[0]/= acc[1];
+ stress= RE_vertren_get_stress(obr, ver, 1);
+ *stress= *acc;
+
+ /* restore orcos */
+ ver->orco[0] = (ver->orco[0]-loc[0])/size[0];
+ ver->orco[1] = (ver->orco[1]-loc[1])/size[1];
+ ver->orco[2] = (ver->orco[2]-loc[2])/size[2];
+ }
+ }
+
+ MEM_freeN(accum);
+}
+
+/* gets tangent from tface or orco */
+static void calc_tangent_vector(ObjectRen *obr, VlakRen *vlr, int do_tangent)
+{
+ MTFace *tface= RE_vlakren_get_tface(obr, vlr, obr->actmtface, NULL, 0);
+ VertRen *v1=vlr->v1, *v2=vlr->v2, *v3=vlr->v3, *v4=vlr->v4;
+ float tang[3], *tav;
+ float *uv1, *uv2, *uv3, *uv4;
+ float uv[4][2];
+
+ if (tface) {
+ uv1= tface->uv[0];
+ uv2= tface->uv[1];
+ uv3= tface->uv[2];
+ uv4= tface->uv[3];
+ }
+ else if (v1->orco) {
+ uv1= uv[0]; uv2= uv[1]; uv3= uv[2]; uv4= uv[3];
+ map_to_sphere(&uv[0][0], &uv[0][1], v1->orco[0], v1->orco[1], v1->orco[2]);
+ map_to_sphere(&uv[1][0], &uv[1][1], v2->orco[0], v2->orco[1], v2->orco[2]);
+ map_to_sphere(&uv[2][0], &uv[2][1], v3->orco[0], v3->orco[1], v3->orco[2]);
+ if (v4)
+ map_to_sphere(&uv[3][0], &uv[3][1], v4->orco[0], v4->orco[1], v4->orco[2]);
+ }
+ else return;
+
+ tangent_from_uv_v3(uv1, uv2, uv3, v1->co, v2->co, v3->co, vlr->n, tang);
+
+ if (do_tangent) {
+ tav= RE_vertren_get_tangent(obr, v1, 1);
+ add_v3_v3(tav, tang);
+ tav= RE_vertren_get_tangent(obr, v2, 1);
+ add_v3_v3(tav, tang);
+ tav= RE_vertren_get_tangent(obr, v3, 1);
+ add_v3_v3(tav, tang);
+ }
+
+ if (v4) {
+ tangent_from_uv_v3(uv1, uv3, uv4, v1->co, v3->co, v4->co, vlr->n, tang);
+
+ if (do_tangent) {
+ tav= RE_vertren_get_tangent(obr, v1, 1);
+ add_v3_v3(tav, tang);
+ tav= RE_vertren_get_tangent(obr, v3, 1);
+ add_v3_v3(tav, tang);
+ tav= RE_vertren_get_tangent(obr, v4, 1);
+ add_v3_v3(tav, tang);
+ }
+ }
+}
+
+
+
+/****************************************************************
+ ************ tangent space generation interface ****************
+ ****************************************************************/
+
+typedef struct {
+ ObjectRen *obr;
+ int mtface_index;
+} SRenderMeshToTangent;
+
+/* interface */
+#include "mikktspace.h"
+
+static int GetNumFaces(const SMikkTSpaceContext *pContext)
+{
+ SRenderMeshToTangent *pMesh = (SRenderMeshToTangent *) pContext->m_pUserData;
+ return pMesh->obr->totvlak;
+}
+
+static int GetNumVertsOfFace(const SMikkTSpaceContext *pContext, const int face_num)
+{
+ SRenderMeshToTangent *pMesh = (SRenderMeshToTangent *) pContext->m_pUserData;
+ VlakRen *vlr= RE_findOrAddVlak(pMesh->obr, face_num);
+ return vlr->v4!=NULL ? 4 : 3;
+}
+
+static void GetPosition(const SMikkTSpaceContext *pContext, float r_co[3], const int face_num, const int vert_index)
+{
+ //assert(vert_index>=0 && vert_index<4);
+ SRenderMeshToTangent *pMesh = (SRenderMeshToTangent *) pContext->m_pUserData;
+ VlakRen *vlr= RE_findOrAddVlak(pMesh->obr, face_num);
+ const float *co = (&vlr->v1)[vert_index]->co;
+ copy_v3_v3(r_co, co);
+}
+
+static void GetTextureCoordinate(const SMikkTSpaceContext *pContext, float r_uv[2], const int face_num, const int vert_index)
+{
+ //assert(vert_index>=0 && vert_index<4);
+ SRenderMeshToTangent *pMesh = (SRenderMeshToTangent *) pContext->m_pUserData;
+ VlakRen *vlr= RE_findOrAddVlak(pMesh->obr, face_num);
+ MTFace *tface= RE_vlakren_get_tface(pMesh->obr, vlr, pMesh->mtface_index, NULL, 0);
+ const float *coord;
+
+ if (tface != NULL) {
+ coord= tface->uv[vert_index];
+ copy_v2_v2(r_uv, coord);
+ }
+ else if ((coord = (&vlr->v1)[vert_index]->orco)) {
+ map_to_sphere(&r_uv[0], &r_uv[1], coord[0], coord[1], coord[2]);
+ }
+ else { /* else we get un-initialized value, 0.0 ok default? */
+ zero_v2(r_uv);
+ }
+}
+
+static void GetNormal(const SMikkTSpaceContext *pContext, float r_no[3], const int face_num, const int vert_index)
+{
+ //assert(vert_index>=0 && vert_index<4);
+ SRenderMeshToTangent *pMesh = (SRenderMeshToTangent *) pContext->m_pUserData;
+ VlakRen *vlr= RE_findOrAddVlak(pMesh->obr, face_num);
+
+ if (vlr->flag & ME_SMOOTH) {
+ const float *n = (&vlr->v1)[vert_index]->n;
+ copy_v3_v3(r_no, n);
+ }
+ else {
+ negate_v3_v3(r_no, vlr->n);
+ }
+}
+static void SetTSpace(const SMikkTSpaceContext *pContext, const float fvTangent[3], const float fSign, const int face_num, const int iVert)
+{
+ //assert(vert_index>=0 && vert_index<4);
+ SRenderMeshToTangent *pMesh = (SRenderMeshToTangent *) pContext->m_pUserData;
+ VlakRen *vlr = RE_findOrAddVlak(pMesh->obr, face_num);
+ float *ftang = RE_vlakren_get_nmap_tangent(pMesh->obr, vlr, pMesh->mtface_index, true);
+ if (ftang!=NULL) {
+ copy_v3_v3(&ftang[iVert*4+0], fvTangent);
+ ftang[iVert*4+3]=fSign;
+ }
+}
+
+static void calc_vertexnormals(Render *UNUSED(re), ObjectRen *obr, bool do_vertex_normal, bool do_tangent, bool do_nmap_tangent)
+{
+ int a;
+
+ /* clear all vertex normals */
+ if (do_vertex_normal) {
+ for (a=0; a<obr->totvert; a++) {
+ VertRen *ver= RE_findOrAddVert(obr, a);
+ ver->n[0]=ver->n[1]=ver->n[2]= 0.0f;
+ }
+ }
+
+ /* calculate cos of angles and point-masses, use as weight factor to
+ * add face normal to vertex */
+ for (a=0; a<obr->totvlak; a++) {
+ VlakRen *vlr= RE_findOrAddVlak(obr, a);
+ if (do_vertex_normal && vlr->flag & ME_SMOOTH) {
+ float *n4= (vlr->v4)? vlr->v4->n: NULL;
+ const float *c4= (vlr->v4)? vlr->v4->co: NULL;
+
+ accumulate_vertex_normals_v3(vlr->v1->n, vlr->v2->n, vlr->v3->n, n4,
+ vlr->n, vlr->v1->co, vlr->v2->co, vlr->v3->co, c4);
+ }
+ if (do_tangent) {
+ /* tangents still need to be calculated for flat faces too */
+ /* weighting removed, they are not vertexnormals */
+ calc_tangent_vector(obr, vlr, do_tangent);
+ }
+ }
+
+ /* do solid faces */
+ for (a=0; a<obr->totvlak; a++) {
+ VlakRen *vlr= RE_findOrAddVlak(obr, a);
+
+ if (do_vertex_normal && (vlr->flag & ME_SMOOTH)==0) {
+ if (is_zero_v3(vlr->v1->n)) copy_v3_v3(vlr->v1->n, vlr->n);
+ if (is_zero_v3(vlr->v2->n)) copy_v3_v3(vlr->v2->n, vlr->n);
+ if (is_zero_v3(vlr->v3->n)) copy_v3_v3(vlr->v3->n, vlr->n);
+ if (vlr->v4 && is_zero_v3(vlr->v4->n)) copy_v3_v3(vlr->v4->n, vlr->n);
+ }
+ }
+
+ /* normalize vertex normals */
+ for (a=0; a<obr->totvert; a++) {
+ VertRen *ver= RE_findOrAddVert(obr, a);
+ normalize_v3(ver->n);
+ if (do_tangent) {
+ float *tav= RE_vertren_get_tangent(obr, ver, 0);
+ if (tav) {
+ /* orthonorm. */
+ const float tdn = dot_v3v3(tav, ver->n);
+ tav[0] -= ver->n[0]*tdn;
+ tav[1] -= ver->n[1]*tdn;
+ tav[2] -= ver->n[2]*tdn;
+ normalize_v3(tav);
+ }
+ }
+ }
+
+ /* normal mapping tangent with mikktspace */
+ if (do_nmap_tangent != false) {
+ SRenderMeshToTangent mesh2tangent;
+ SMikkTSpaceContext sContext;
+ SMikkTSpaceInterface sInterface;
+ memset(&mesh2tangent, 0, sizeof(SRenderMeshToTangent));
+ memset(&sContext, 0, sizeof(SMikkTSpaceContext));
+ memset(&sInterface, 0, sizeof(SMikkTSpaceInterface));
+
+ mesh2tangent.obr = obr;
+
+ sContext.m_pUserData = &mesh2tangent;
+ sContext.m_pInterface = &sInterface;
+ sInterface.m_getNumFaces = GetNumFaces;
+ sInterface.m_getNumVerticesOfFace = GetNumVertsOfFace;
+ sInterface.m_getPosition = GetPosition;
+ sInterface.m_getTexCoord = GetTextureCoordinate;
+ sInterface.m_getNormal = GetNormal;
+ sInterface.m_setTSpaceBasic = SetTSpace;
+
+ for (a = 0; a < MAX_MTFACE; a++) {
+ if (obr->tangent_mask & 1 << a) {
+ mesh2tangent.mtface_index = a;
+ genTangSpaceDefault(&sContext);
+ }
+ }
+ }
+}
+
+/* ------------------------------------------------------------------------- */
+/* Autosmoothing: */
+/* ------------------------------------------------------------------------- */
+
+typedef struct ASvert {
+ int totface;
+ ListBase faces;
+} ASvert;
+
+typedef struct ASface {
+ struct ASface *next, *prev;
+ VlakRen *vlr[4];
+ VertRen *nver[4];
+} ASface;
+
+static int as_addvert(ASvert *asv, VertRen *v1, VlakRen *vlr)
+{
+ ASface *asf;
+ int a = -1;
+
+ if (v1 == NULL)
+ return a;
+
+ asf = asv->faces.last;
+ if (asf) {
+ for (a = 0; a < 4 && asf->vlr[a]; a++) {
+ }
+ }
+ else {
+ a = 4;
+ }
+
+ /* new face struct */
+ if (a == 4) {
+ a = 0;
+ asf = MEM_callocN(sizeof(ASface), "asface");
+ BLI_addtail(&asv->faces, asf);
+ }
+
+ asf->vlr[a] = vlr;
+ asv->totface++;
+
+ return a;
+}
+
+static VertRen *as_findvertex_lnor(VlakRen *vlr, VertRen *ver, ASvert *asv, const float lnor[3])
+{
+ /* return when new vertex already was made, or existing one is OK */
+ ASface *asf;
+ int a;
+
+ /* First face, we can use existing vert and assign it current lnor! */
+ if (asv->totface == 1) {
+ copy_v3_v3(ver->n, lnor);
+ return ver;
+ }
+
+ /* In case existing ver has same normal as current lnor, we can simply use it! */
+ if (equals_v3v3(lnor, ver->n)) {
+ return ver;
+ }
+
+ asf = asv->faces.first;
+ while (asf) {
+ for (a = 0; a < 4; a++) {
+ if (asf->vlr[a] && asf->vlr[a] != vlr) {
+ /* this face already made a copy for this vertex! */
+ if (asf->nver[a]) {
+ if (equals_v3v3(lnor, asf->nver[a]->n)) {
+ return asf->nver[a];
+ }
+ }
+ }
+ }
+ asf = asf->next;
+ }
+
+ return NULL;
+}
+
+static void as_addvert_lnor(ObjectRen *obr, ASvert *asv, VertRen *ver, VlakRen *vlr, const short _lnor[3])
+{
+ VertRen *v1;
+ ASface *asf;
+ int asf_idx;
+ float lnor[3];
+
+ normal_short_to_float_v3(lnor, _lnor);
+
+ asf_idx = as_addvert(asv, ver, vlr);
+ if (asf_idx < 0) {
+ return;
+ }
+ asf = asv->faces.last;
+
+ /* already made a new vertex within threshold? */
+ v1 = as_findvertex_lnor(vlr, ver, asv, lnor);
+ if (v1 == NULL) {
+ /* make a new vertex */
+ v1 = RE_vertren_copy(obr, ver);
+ copy_v3_v3(v1->n, lnor);
+ }
+ if (v1 != ver) {
+ asf->nver[asf_idx] = v1;
+ if (vlr->v1 == ver) vlr->v1 = v1;
+ if (vlr->v2 == ver) vlr->v2 = v1;
+ if (vlr->v3 == ver) vlr->v3 = v1;
+ if (vlr->v4 == ver) vlr->v4 = v1;
+ }
+}
+
+/* note; autosmooth happens in object space still, after applying autosmooth we rotate */
+/* note2; actually, when original mesh and displist are equal sized, face normals are from original mesh */
+static void autosmooth(Render *UNUSED(re), ObjectRen *obr, float mat[4][4], short (*lnors)[4][3])
+{
+ ASvert *asverts;
+ VertRen *ver;
+ VlakRen *vlr;
+ int a, totvert;
+
+ float rot[3][3];
+
+ /* Note: For normals, we only want rotation, not scaling component.
+ * Negative scales (aka mirroring) give wrong results, see T44102. */
+ if (lnors) {
+ float mat3[3][3], size[3];
+
+ copy_m3_m4(mat3, mat);
+ mat3_to_rot_size(rot, size, mat3);
+ }
+
+ if (obr->totvert == 0)
+ return;
+
+ totvert = obr->totvert;
+ asverts = MEM_callocN(sizeof(ASvert) * totvert, "all smooth verts");
+
+ if (lnors) {
+ /* We construct listbase of all vertices and pointers to faces, and add new verts when needed
+ * (i.e. when existing ones do not share the same (loop)normal).
+ */
+ for (a = 0; a < obr->totvlak; a++, lnors++) {
+ vlr = RE_findOrAddVlak(obr, a);
+ /* skip wire faces */
+ if (vlr->v2 != vlr->v3) {
+ as_addvert_lnor(obr, asverts+vlr->v1->index, vlr->v1, vlr, (const short*)lnors[0][0]);
+ as_addvert_lnor(obr, asverts+vlr->v2->index, vlr->v2, vlr, (const short*)lnors[0][1]);
+ as_addvert_lnor(obr, asverts+vlr->v3->index, vlr->v3, vlr, (const short*)lnors[0][2]);
+ if (vlr->v4)
+ as_addvert_lnor(obr, asverts+vlr->v4->index, vlr->v4, vlr, (const short*)lnors[0][3]);
+ }
+ }
+ }
+
+ /* free */
+ for (a = 0; a < totvert; a++) {
+ BLI_freelistN(&asverts[a].faces);
+ }
+ MEM_freeN(asverts);
+
+ /* rotate vertices and calculate normal of faces */
+ for (a = 0; a < obr->totvert; a++) {
+ ver = RE_findOrAddVert(obr, a);
+ mul_m4_v3(mat, ver->co);
+ if (lnors) {
+ mul_m3_v3(rot, ver->n);
+ negate_v3(ver->n);
+ }
+ }
+ for (a = 0; a < obr->totvlak; a++) {
+ vlr = RE_findOrAddVlak(obr, a);
+
+ /* skip wire faces */
+ if (vlr->v2 != vlr->v3) {
+ if (vlr->v4)
+ normal_quad_v3(vlr->n, vlr->v4->co, vlr->v3->co, vlr->v2->co, vlr->v1->co);
+ else
+ normal_tri_v3(vlr->n, vlr->v3->co, vlr->v2->co, vlr->v1->co);
+ }
+ }
+}
+
+/* ------------------------------------------------------------------------- */
+/* Orco hash and Materials */
+/* ------------------------------------------------------------------------- */
+
+static float *get_object_orco(Render *re, void *ob)
+{
+ if (!re->orco_hash) {
+ return NULL;
+ }
+
+ return BLI_ghash_lookup(re->orco_hash, ob);
+}
+
+static void set_object_orco(Render *re, void *ob, float *orco)
+{
+ if (!re->orco_hash)
+ re->orco_hash = BLI_ghash_ptr_new("set_object_orco gh");
+
+ BLI_ghash_insert(re->orco_hash, ob, orco);
+}
+
+static void free_mesh_orco_hash(Render *re)
+{
+ if (re->orco_hash) {
+ BLI_ghash_free(re->orco_hash, NULL, MEM_freeN);
+ re->orco_hash = NULL;
+ }
+}
+
+static void check_material_mapto(Material *ma)
+{
+ int a;
+ ma->mapto_textured = 0;
+
+ /* cache which inputs are actually textured.
+ * this can avoid a bit of time spent iterating through all the texture slots, map inputs and map tos
+ * every time a property which may or may not be textured is accessed */
+
+ for (a=0; a<MAX_MTEX; a++) {
+ if (ma->mtex[a] && ma->mtex[a]->tex) {
+ /* currently used only in volume render, so we'll check for those flags */
+ if (ma->mtex[a]->mapto & MAP_DENSITY) ma->mapto_textured |= MAP_DENSITY;
+ if (ma->mtex[a]->mapto & MAP_EMISSION) ma->mapto_textured |= MAP_EMISSION;
+ if (ma->mtex[a]->mapto & MAP_EMISSION_COL) ma->mapto_textured |= MAP_EMISSION_COL;
+ if (ma->mtex[a]->mapto & MAP_SCATTERING) ma->mapto_textured |= MAP_SCATTERING;
+ if (ma->mtex[a]->mapto & MAP_TRANSMISSION_COL) ma->mapto_textured |= MAP_TRANSMISSION_COL;
+ if (ma->mtex[a]->mapto & MAP_REFLECTION) ma->mapto_textured |= MAP_REFLECTION;
+ if (ma->mtex[a]->mapto & MAP_REFLECTION_COL) ma->mapto_textured |= MAP_REFLECTION_COL;
+ }
+ }
+}
+static void flag_render_node_material(Render *re, bNodeTree *ntree)
+{
+ bNode *node;
+
+ for (node = ntree->nodes.first; node; node = node->next) {
+ if (node->id) {
+ if (GS(node->id->name)==ID_MA) {
+ Material *ma= (Material *)node->id;
+
+ if ((ma->mode & MA_TRANSP) && (ma->mode & MA_ZTRANSP))
+ re->flag |= R_ZTRA;
+
+ ma->flag |= MA_IS_USED;
+ }
+ else if (node->type==NODE_GROUP)
+ flag_render_node_material(re, (bNodeTree *)node->id);
+ }
+ }
+}
+
+static Material *give_render_material(Render *re, Object *ob, short nr)
+{
+ extern Material defmaterial; /* material.c */
+ Material *ma;
+
+ ma= give_current_material(ob, nr);
+ if (ma==NULL)
+ ma= &defmaterial;
+
+ if (re->r.mode & R_SPEED) ma->texco |= NEED_UV;
+
+ if (ma->material_type == MA_TYPE_VOLUME) {
+ ma->mode |= MA_TRANSP;
+ ma->mode &= ~MA_SHADBUF;
+ }
+ if ((ma->mode & MA_TRANSP) && (ma->mode & MA_ZTRANSP))
+ re->flag |= R_ZTRA;
+
+ /* for light groups and SSS */
+ ma->flag |= MA_IS_USED;
+
+ if (ma->nodetree && ma->use_nodes)
+ flag_render_node_material(re, ma->nodetree);
+
+ check_material_mapto(ma);
+
+ return ma;
+}
+
+/* ------------------------------------------------------------------------- */
+/* Particles */
+/* ------------------------------------------------------------------------- */
+typedef struct ParticleStrandData {
+ struct MCol *mcol;
+ float *orco, *uvco, *surfnor;
+ float time, adapt_angle, adapt_pix, size;
+ int totuv, totcol;
+ int first, line, adapt, override_uv;
+}
+ParticleStrandData;
+/* future thread problem... */
+static void static_particle_strand(Render *re, ObjectRen *obr, Material *ma, ParticleStrandData *sd, const float vec[3], const float vec1[3])
+{
+ static VertRen *v1= NULL, *v2= NULL;
+ VlakRen *vlr= NULL;
+ float nor[3], cross[3], crosslen, w, dx, dy, width;
+ static float anor[3], avec[3];
+ int flag, i;
+ static int second=0;
+
+ sub_v3_v3v3(nor, vec, vec1);
+ normalize_v3(nor); /* nor needed as tangent */
+ cross_v3_v3v3(cross, vec, nor);
+
+ /* turn cross in pixelsize */
+ w= vec[2]*re->winmat[2][3] + re->winmat[3][3];
+ dx= re->winx*cross[0]*re->winmat[0][0];
+ dy= re->winy*cross[1]*re->winmat[1][1];
+ w = sqrtf(dx * dx + dy * dy) / w;
+
+ if (w!=0.0f) {
+ float fac;
+ if (ma->strand_ease!=0.0f) {
+ if (ma->strand_ease<0.0f)
+ fac= pow(sd->time, 1.0f+ma->strand_ease);
+ else
+ fac= pow(sd->time, 1.0f/(1.0f-ma->strand_ease));
+ }
+ else fac= sd->time;
+
+ width= ((1.0f-fac)*ma->strand_sta + (fac)*ma->strand_end);
+
+ /* use actual Blender units for strand width and fall back to minimum width */
+ if (ma->mode & MA_STR_B_UNITS) {
+ crosslen= len_v3(cross);
+ w= 2.0f*crosslen*ma->strand_min/w;
+
+ if (width < w)
+ width= w;
+
+ /*cross is the radius of the strand so we want it to be half of full width */
+ mul_v3_fl(cross, 0.5f/crosslen);
+ }
+ else
+ width/=w;
+
+ mul_v3_fl(cross, width);
+ }
+
+ if (ma->mode & MA_TANGENT_STR)
+ flag= R_SMOOTH|R_TANGENT;
+ else
+ flag= R_SMOOTH;
+
+ /* only 1 pixel wide strands filled in as quads now, otherwise zbuf errors */
+ if (ma->strand_sta==1.0f)
+ flag |= R_STRAND;
+
+ /* single face line */
+ if (sd->line) {
+ vlr= RE_findOrAddVlak(obr, obr->totvlak++);
+ vlr->flag= flag;
+ vlr->v1= RE_findOrAddVert(obr, obr->totvert++);
+ vlr->v2= RE_findOrAddVert(obr, obr->totvert++);
+ vlr->v3= RE_findOrAddVert(obr, obr->totvert++);
+ vlr->v4= RE_findOrAddVert(obr, obr->totvert++);
+
+ copy_v3_v3(vlr->v1->co, vec);
+ add_v3_v3(vlr->v1->co, cross);
+ copy_v3_v3(vlr->v1->n, nor);
+ vlr->v1->orco= sd->orco;
+ vlr->v1->accum = -1.0f; /* accum abuse for strand texco */
+
+ copy_v3_v3(vlr->v2->co, vec);
+ sub_v3_v3v3(vlr->v2->co, vlr->v2->co, cross);
+ copy_v3_v3(vlr->v2->n, nor);
+ vlr->v2->orco= sd->orco;
+ vlr->v2->accum= vlr->v1->accum;
+
+ copy_v3_v3(vlr->v4->co, vec1);
+ add_v3_v3(vlr->v4->co, cross);
+ copy_v3_v3(vlr->v4->n, nor);
+ vlr->v4->orco= sd->orco;
+ vlr->v4->accum = 1.0f; /* accum abuse for strand texco */
+
+ copy_v3_v3(vlr->v3->co, vec1);
+ sub_v3_v3v3(vlr->v3->co, vlr->v3->co, cross);
+ copy_v3_v3(vlr->v3->n, nor);
+ vlr->v3->orco= sd->orco;
+ vlr->v3->accum= vlr->v4->accum;
+
+ normal_quad_v3(vlr->n, vlr->v4->co, vlr->v3->co, vlr->v2->co, vlr->v1->co);
+
+ vlr->mat= ma;
+ vlr->ec= ME_V2V3;
+
+ if (sd->surfnor) {
+ float *snor= RE_vlakren_get_surfnor(obr, vlr, 1);
+ copy_v3_v3(snor, sd->surfnor);
+ }
+
+ if (sd->uvco) {
+ for (i=0; i<sd->totuv; i++) {
+ MTFace *mtf;
+ mtf=RE_vlakren_get_tface(obr, vlr, i, NULL, 1);
+ mtf->uv[0][0]=mtf->uv[1][0]=
+ mtf->uv[2][0]=mtf->uv[3][0]=(sd->uvco+2*i)[0];
+ mtf->uv[0][1]=mtf->uv[1][1]=
+ mtf->uv[2][1]=mtf->uv[3][1]=(sd->uvco+2*i)[1];
+ }
+ if (sd->override_uv>=0) {
+ MTFace *mtf;
+ mtf=RE_vlakren_get_tface(obr, vlr, sd->override_uv, NULL, 0);
+
+ mtf->uv[0][0]=mtf->uv[3][0]=0.0f;
+ mtf->uv[1][0]=mtf->uv[2][0]=1.0f;
+
+ mtf->uv[0][1]=mtf->uv[1][1]=0.0f;
+ mtf->uv[2][1]=mtf->uv[3][1]=1.0f;
+ }
+ }
+ if (sd->mcol) {
+ for (i=0; i<sd->totcol; i++) {
+ MCol *mc;
+ mc=RE_vlakren_get_mcol(obr, vlr, i, NULL, 1);
+ mc[0]=mc[1]=mc[2]=mc[3]=sd->mcol[i];
+ mc[0]=mc[1]=mc[2]=mc[3]=sd->mcol[i];
+ }
+ }
+ }
+ /* first two vertices of a strand */
+ else if (sd->first) {
+ if (sd->adapt) {
+ copy_v3_v3(anor, nor);
+ copy_v3_v3(avec, vec);
+ second=1;
+ }
+
+ v1= RE_findOrAddVert(obr, obr->totvert++);
+ v2= RE_findOrAddVert(obr, obr->totvert++);
+
+ copy_v3_v3(v1->co, vec);
+ add_v3_v3(v1->co, cross);
+ copy_v3_v3(v1->n, nor);
+ v1->orco= sd->orco;
+ v1->accum = -1.0f; /* accum abuse for strand texco */
+
+ copy_v3_v3(v2->co, vec);
+ sub_v3_v3v3(v2->co, v2->co, cross);
+ copy_v3_v3(v2->n, nor);
+ v2->orco= sd->orco;
+ v2->accum= v1->accum;
+ }
+ /* more vertices & faces to strand */
+ else {
+ if (sd->adapt==0 || second) {
+ vlr= RE_findOrAddVlak(obr, obr->totvlak++);
+ vlr->flag= flag;
+ vlr->v1= v1;
+ vlr->v2= v2;
+ vlr->v3= RE_findOrAddVert(obr, obr->totvert++);
+ vlr->v4= RE_findOrAddVert(obr, obr->totvert++);
+
+ v1= vlr->v4; /* cycle */
+ v2= vlr->v3; /* cycle */
+
+
+ if (sd->adapt) {
+ second=0;
+ copy_v3_v3(anor, nor);
+ copy_v3_v3(avec, vec);
+ }
+
+ }
+ else if (sd->adapt) {
+ float dvec[3], pvec[3];
+ sub_v3_v3v3(dvec, avec, vec);
+ project_v3_v3v3(pvec, dvec, vec);
+ sub_v3_v3v3(dvec, dvec, pvec);
+
+ w= vec[2]*re->winmat[2][3] + re->winmat[3][3];
+ dx= re->winx*dvec[0]*re->winmat[0][0]/w;
+ dy= re->winy*dvec[1]*re->winmat[1][1]/w;
+ w = sqrtf(dx * dx + dy * dy);
+ if (dot_v3v3(anor, nor)<sd->adapt_angle && w>sd->adapt_pix) {
+ vlr= RE_findOrAddVlak(obr, obr->totvlak++);
+ vlr->flag= flag;
+ vlr->v1= v1;
+ vlr->v2= v2;
+ vlr->v3= RE_findOrAddVert(obr, obr->totvert++);
+ vlr->v4= RE_findOrAddVert(obr, obr->totvert++);
+
+ v1= vlr->v4; /* cycle */
+ v2= vlr->v3; /* cycle */
+
+ copy_v3_v3(anor, nor);
+ copy_v3_v3(avec, vec);
+ }
+ else {
+ vlr= RE_findOrAddVlak(obr, obr->totvlak-1);
+ }
+ }
+
+ copy_v3_v3(vlr->v4->co, vec);
+ add_v3_v3(vlr->v4->co, cross);
+ copy_v3_v3(vlr->v4->n, nor);
+ vlr->v4->orco= sd->orco;
+ vlr->v4->accum= -1.0f + 2.0f * sd->time; /* accum abuse for strand texco */
+
+ copy_v3_v3(vlr->v3->co, vec);
+ sub_v3_v3v3(vlr->v3->co, vlr->v3->co, cross);
+ copy_v3_v3(vlr->v3->n, nor);
+ vlr->v3->orco= sd->orco;
+ vlr->v3->accum= vlr->v4->accum;
+
+ normal_quad_v3(vlr->n, vlr->v4->co, vlr->v3->co, vlr->v2->co, vlr->v1->co);
+
+ vlr->mat= ma;
+ vlr->ec= ME_V2V3;
+
+ if (sd->surfnor) {
+ float *snor= RE_vlakren_get_surfnor(obr, vlr, 1);
+ copy_v3_v3(snor, sd->surfnor);
+ }
+
+ if (sd->uvco) {
+ for (i=0; i<sd->totuv; i++) {
+ MTFace *mtf;
+ mtf=RE_vlakren_get_tface(obr, vlr, i, NULL, 1);
+ mtf->uv[0][0]=mtf->uv[1][0]=
+ mtf->uv[2][0]=mtf->uv[3][0]=(sd->uvco+2*i)[0];
+ mtf->uv[0][1]=mtf->uv[1][1]=
+ mtf->uv[2][1]=mtf->uv[3][1]=(sd->uvco+2*i)[1];
+ }
+ if (sd->override_uv>=0) {
+ MTFace *mtf;
+ mtf=RE_vlakren_get_tface(obr, vlr, sd->override_uv, NULL, 0);
+
+ mtf->uv[0][0]=mtf->uv[3][0]=0.0f;
+ mtf->uv[1][0]=mtf->uv[2][0]=1.0f;
+
+ mtf->uv[0][1]=mtf->uv[1][1]=(vlr->v1->accum+1.0f)/2.0f;
+ mtf->uv[2][1]=mtf->uv[3][1]=(vlr->v3->accum+1.0f)/2.0f;
+ }
+ }
+ if (sd->mcol) {
+ for (i=0; i<sd->totcol; i++) {
+ MCol *mc;
+ mc=RE_vlakren_get_mcol(obr, vlr, i, NULL, 1);
+ mc[0]=mc[1]=mc[2]=mc[3]=sd->mcol[i];
+ mc[0]=mc[1]=mc[2]=mc[3]=sd->mcol[i];
+ }
+ }
+ }
+}
+
+static void static_particle_wire(ObjectRen *obr, Material *ma, const float vec[3], const float vec1[3], int first, int line)
+{
+ VlakRen *vlr;
+ static VertRen *v1;
+
+ if (line) {
+ vlr= RE_findOrAddVlak(obr, obr->totvlak++);
+ vlr->v1= RE_findOrAddVert(obr, obr->totvert++);
+ vlr->v2= RE_findOrAddVert(obr, obr->totvert++);
+ vlr->v3= vlr->v2;
+ vlr->v4= NULL;
+
+ copy_v3_v3(vlr->v1->co, vec);
+ copy_v3_v3(vlr->v2->co, vec1);
+
+ sub_v3_v3v3(vlr->n, vec, vec1);
+ normalize_v3(vlr->n);
+ copy_v3_v3(vlr->v1->n, vlr->n);
+ copy_v3_v3(vlr->v2->n, vlr->n);
+
+ vlr->mat= ma;
+ vlr->ec= ME_V1V2;
+
+ }
+ else if (first) {
+ v1= RE_findOrAddVert(obr, obr->totvert++);
+ copy_v3_v3(v1->co, vec);
+ }
+ else {
+ vlr= RE_findOrAddVlak(obr, obr->totvlak++);
+ vlr->v1= v1;
+ vlr->v2= RE_findOrAddVert(obr, obr->totvert++);
+ vlr->v3= vlr->v2;
+ vlr->v4= NULL;
+
+ v1= vlr->v2; /* cycle */
+ copy_v3_v3(v1->co, vec);
+
+ sub_v3_v3v3(vlr->n, vec, vec1);
+ normalize_v3(vlr->n);
+ copy_v3_v3(v1->n, vlr->n);
+
+ vlr->mat= ma;
+ vlr->ec= ME_V1V2;
+ }
+
+}
+
+static void particle_curve(Render *re, ObjectRen *obr, DerivedMesh *dm, Material *ma, ParticleStrandData *sd,
+ const float loc[3], const float loc1[3], int seed, float *pa_co)
+{
+ HaloRen *har = NULL;
+
+ if (ma->material_type == MA_TYPE_WIRE)
+ static_particle_wire(obr, ma, loc, loc1, sd->first, sd->line);
+ else if (ma->material_type == MA_TYPE_HALO) {
+ har= RE_inithalo_particle(re, obr, dm, ma, loc, loc1, sd->orco, sd->uvco, sd->size, 1.0, seed, pa_co);
+ if (har) har->lay= obr->ob->lay;
+ }
+ else
+ static_particle_strand(re, obr, ma, sd, loc, loc1);
+}
+static void particle_billboard(Render *re, ObjectRen *obr, Material *ma, ParticleBillboardData *bb)
+{
+ VlakRen *vlr;
+ MTFace *mtf;
+ float xvec[3], yvec[3], zvec[3], bb_center[3];
+ /* Number of tiles */
+ int totsplit = bb->uv_split * bb->uv_split;
+ int tile, x, y;
+ /* Tile offsets */
+ float uvx = 0.0f, uvy = 0.0f, uvdx = 1.0f, uvdy = 1.0f, time = 0.0f;
+
+ vlr= RE_findOrAddVlak(obr, obr->totvlak++);
+ vlr->v1= RE_findOrAddVert(obr, obr->totvert++);
+ vlr->v2= RE_findOrAddVert(obr, obr->totvert++);
+ vlr->v3= RE_findOrAddVert(obr, obr->totvert++);
+ vlr->v4= RE_findOrAddVert(obr, obr->totvert++);
+
+ psys_make_billboard(bb, xvec, yvec, zvec, bb_center);
+
+ add_v3_v3v3(vlr->v1->co, bb_center, xvec);
+ add_v3_v3(vlr->v1->co, yvec);
+ mul_m4_v3(re->viewmat, vlr->v1->co);
+
+ sub_v3_v3v3(vlr->v2->co, bb_center, xvec);
+ add_v3_v3(vlr->v2->co, yvec);
+ mul_m4_v3(re->viewmat, vlr->v2->co);
+
+ sub_v3_v3v3(vlr->v3->co, bb_center, xvec);
+ sub_v3_v3v3(vlr->v3->co, vlr->v3->co, yvec);
+ mul_m4_v3(re->viewmat, vlr->v3->co);
+
+ add_v3_v3v3(vlr->v4->co, bb_center, xvec);
+ sub_v3_v3(vlr->v4->co, yvec);
+ mul_m4_v3(re->viewmat, vlr->v4->co);
+
+ normal_quad_v3(vlr->n, vlr->v4->co, vlr->v3->co, vlr->v2->co, vlr->v1->co);
+ copy_v3_v3(vlr->v1->n, vlr->n);
+ copy_v3_v3(vlr->v2->n, vlr->n);
+ copy_v3_v3(vlr->v3->n, vlr->n);
+ copy_v3_v3(vlr->v4->n, vlr->n);
+
+ vlr->mat= ma;
+ vlr->ec= ME_V2V3;
+
+ if (bb->uv_split > 1) {
+ uvdx = uvdy = 1.0f / (float)bb->uv_split;
+
+ if (ELEM(bb->anim, PART_BB_ANIM_AGE, PART_BB_ANIM_FRAME)) {
+ if (bb->anim == PART_BB_ANIM_FRAME)
+ time = ((int)(bb->time * bb->lifetime) % totsplit)/(float)totsplit;
+ else
+ time = bb->time;
+ }
+ else if (bb->anim == PART_BB_ANIM_ANGLE) {
+ if (bb->align == PART_BB_VIEW) {
+ time = (float)fmod((bb->tilt + 1.0f) / 2.0f, 1.0);
+ }
+ else {
+ float axis1[3] = {0.0f, 0.0f, 0.0f};
+ float axis2[3] = {0.0f, 0.0f, 0.0f};
+
+ axis1[(bb->align + 1) % 3] = 1.0f;
+ axis2[(bb->align + 2) % 3] = 1.0f;
+
+ if (bb->lock == 0) {
+ zvec[bb->align] = 0.0f;
+ normalize_v3(zvec);
+ }
+
+ time = saacos(dot_v3v3(zvec, axis1)) / (float)M_PI;
+
+ if (dot_v3v3(zvec, axis2) < 0.0f)
+ time = 1.0f - time / 2.0f;
+ else
+ time /= 2.0f;
+ }
+ }
+
+ if (bb->split_offset == PART_BB_OFF_LINEAR)
+ time = (float)fmod(time + (float)bb->num / (float)totsplit, 1.0f);
+ else if (bb->split_offset==PART_BB_OFF_RANDOM)
+ time = (float)fmod(time + bb->random, 1.0f);
+
+ /* Find the coordinates in tile space (integer), then convert to UV
+ * space (float). Note that Y is flipped. */
+ tile = (int)((time + FLT_EPSILON10) * totsplit);
+ x = tile % bb->uv_split;
+ y = tile / bb->uv_split;
+ y = (bb->uv_split - 1) - y;
+ uvx = uvdx * x;
+ uvy = uvdy * y;
+ }
+
+ /* normal UVs */
+ if (bb->uv[0] >= 0) {
+ mtf = RE_vlakren_get_tface(obr, vlr, bb->uv[0], NULL, 1);
+ mtf->uv[0][0] = 1.0f;
+ mtf->uv[0][1] = 1.0f;
+ mtf->uv[1][0] = 0.0f;
+ mtf->uv[1][1] = 1.0f;
+ mtf->uv[2][0] = 0.0f;
+ mtf->uv[2][1] = 0.0f;
+ mtf->uv[3][0] = 1.0f;
+ mtf->uv[3][1] = 0.0f;
+ }
+
+ /* time-index UVs */
+ if (bb->uv[1] >= 0) {
+ mtf = RE_vlakren_get_tface(obr, vlr, bb->uv[1], NULL, 1);
+ mtf->uv[0][0] = mtf->uv[1][0] = mtf->uv[2][0] = mtf->uv[3][0] = bb->time;
+ mtf->uv[0][1] = mtf->uv[1][1] = mtf->uv[2][1] = mtf->uv[3][1] = (float)bb->num/(float)bb->totnum;
+ }
+
+ /* split UVs */
+ if (bb->uv_split > 1 && bb->uv[2] >= 0) {
+ mtf = RE_vlakren_get_tface(obr, vlr, bb->uv[2], NULL, 1);
+ mtf->uv[0][0] = uvx + uvdx;
+ mtf->uv[0][1] = uvy + uvdy;
+ mtf->uv[1][0] = uvx;
+ mtf->uv[1][1] = uvy + uvdy;
+ mtf->uv[2][0] = uvx;
+ mtf->uv[2][1] = uvy;
+ mtf->uv[3][0] = uvx + uvdx;
+ mtf->uv[3][1] = uvy;
+ }
+}
+static void particle_normal_ren(short ren_as, ParticleSettings *part, Render *re, ObjectRen *obr, DerivedMesh *dm, Material *ma, ParticleStrandData *sd, ParticleBillboardData *bb, ParticleKey *state, int seed, float hasize, float *pa_co)
+{
+ float loc[3], loc0[3], loc1[3], vel[3];
+
+ copy_v3_v3(loc, state->co);
+
+ if (ren_as != PART_DRAW_BB)
+ mul_m4_v3(re->viewmat, loc);
+
+ switch (ren_as) {
+ case PART_DRAW_LINE:
+ sd->line = 1;
+ sd->time = 0.0f;
+ sd->size = hasize;
+
+ mul_v3_mat3_m4v3(vel, re->viewmat, state->vel);
+ normalize_v3(vel);
+
+ if (part->draw & PART_DRAW_VEL_LENGTH)
+ mul_v3_fl(vel, len_v3(state->vel));
+
+ madd_v3_v3v3fl(loc0, loc, vel, -part->draw_line[0]);
+ madd_v3_v3v3fl(loc1, loc, vel, part->draw_line[1]);
+
+ particle_curve(re, obr, dm, ma, sd, loc0, loc1, seed, pa_co);
+
+ break;
+
+ case PART_DRAW_BB:
+
+ copy_v3_v3(bb->vec, loc);
+ copy_v3_v3(bb->vel, state->vel);
+
+ particle_billboard(re, obr, ma, bb);
+
+ break;
+
+ default:
+ {
+ HaloRen *har = NULL;
+
+ har = RE_inithalo_particle(re, obr, dm, ma, loc, NULL, sd->orco, sd->uvco, hasize, 0.0, seed, pa_co);
+
+ if (har) har->lay= obr->ob->lay;
+
+ break;
+ }
+ }
+}
+static void get_particle_uvco_mcol(short from, DerivedMesh *dm, float *fuv, int num, ParticleStrandData *sd)
+{
+ int i;
+
+ /* get uvco */
+ if (sd->uvco && ELEM(from, PART_FROM_FACE, PART_FROM_VOLUME)) {
+ for (i=0; i<sd->totuv; i++) {
+ if (!ELEM(num, DMCACHE_NOTFOUND, DMCACHE_ISCHILD)) {
+ MFace *mface = dm->getTessFaceData(dm, num, CD_MFACE);
+ MTFace *mtface = (MTFace*)CustomData_get_layer_n(&dm->faceData, CD_MTFACE, i);
+ mtface += num;
+
+ psys_interpolate_uvs(mtface, mface->v4, fuv, sd->uvco + 2 * i);
+ }
+ else {
+ sd->uvco[2*i] = 0.0f;
+ sd->uvco[2*i + 1] = 0.0f;
+ }
+ }
+ }
+
+ /* get mcol */
+ if (sd->mcol && ELEM(from, PART_FROM_FACE, PART_FROM_VOLUME)) {
+ for (i=0; i<sd->totcol; i++) {
+ if (!ELEM(num, DMCACHE_NOTFOUND, DMCACHE_ISCHILD)) {
+ MFace *mface = dm->getTessFaceData(dm, num, CD_MFACE);
+ MCol *mc = (MCol*)CustomData_get_layer_n(&dm->faceData, CD_MCOL, i);
+ mc += num * 4;
+
+ psys_interpolate_mcol(mc, mface->v4, fuv, sd->mcol + i);
+ }
+ else
+ memset(&sd->mcol[i], 0, sizeof(MCol));
+ }
+ }
+}
+static int render_new_particle_system(Render *re, ObjectRen *obr, ParticleSystem *psys, int timeoffset)
+{
+ Object *ob= obr->ob;
+// Object *tob=0;
+ Material *ma = NULL;
+ ParticleSystemModifierData *psmd;
+ ParticleSystem *tpsys = NULL;
+ ParticleSettings *part, *tpart = NULL;
+ ParticleData *pars, *pa = NULL, *tpa = NULL;
+ ParticleKey *states = NULL;
+ ParticleKey state;
+ ParticleCacheKey *cache = NULL;
+ ParticleBillboardData bb;
+ ParticleSimulationData sim = {NULL};
+ ParticleStrandData sd;
+ StrandBuffer *strandbuf = NULL;
+ StrandVert *svert = NULL;
+ StrandBound *sbound = NULL;
+ StrandRen *strand = NULL;
+ RNG *rng = NULL;
+ float loc[3], loc1[3], loc0[3], mat[4][4], nmat[3][3], co[3], nor[3], duplimat[4][4];
+ float strandlen=0.0f, curlen=0.0f;
+ float hasize, pa_size, r_tilt, r_length;
+ float pa_time, pa_birthtime, pa_dietime;
+ float random, simplify[2], pa_co[3];
+ const float cfra= BKE_scene_frame_get(re->scene);
+ int i, a, k, max_k=0, totpart;
+ bool do_simplify = false, do_surfacecache = false, use_duplimat = false;
+ int totchild=0, step_nbr;
+ int seed, path_nbr=0, orco1=0, num;
+ int totface;
+
+ const int *index_mf_to_mpoly = NULL;
+ const int *index_mp_to_orig = NULL;
+
+/* 1. check that everything is ok & updated */
+ if (psys==NULL)
+ return 0;
+
+ part=psys->part;
+ pars=psys->particles;
+
+ if (part==NULL || pars==NULL || !psys_check_enabled(ob, psys, G.is_rendering))
+ return 0;
+
+ if (part->ren_as==PART_DRAW_OB || part->ren_as==PART_DRAW_GR || part->ren_as==PART_DRAW_NOT)
+ return 1;
+
+ if ((re->r.scemode & R_VIEWPORT_PREVIEW) && (ob->mode & OB_MODE_PARTICLE_EDIT))
+ return 0;
+
+ if (part->ren_as == PART_DRAW_BB && part->bb_ob == NULL && RE_GetCamera(re) == NULL)
+ return 0;
+
+/* 2. start initializing things */
+
+ /* last possibility to bail out! */
+ psmd = psys_get_modifier(ob, psys);
+ if (!(psmd->modifier.mode & eModifierMode_Render))
+ return 0;
+
+ sim.scene= re->scene;
+ sim.ob= ob;
+ sim.psys= psys;
+ sim.psmd= psmd;
+
+ if (part->phystype==PART_PHYS_KEYED)
+ psys_count_keyed_targets(&sim);
+
+ totchild=psys->totchild;
+
+ /* can happen for disconnected/global hair */
+ if (part->type==PART_HAIR && !psys->childcache)
+ totchild= 0;
+
+ if (re->r.scemode & R_VIEWPORT_PREVIEW) { /* preview render */
+ totchild = (int)((float)totchild * (float)part->disp / 100.0f);
+ step_nbr = 1 << part->draw_step;
+ }
+ else {
+ step_nbr = 1 << part->ren_step;
+ }
+ if (ELEM(part->kink, PART_KINK_SPIRAL))
+ step_nbr += part->kink_extra_steps;
+
+ psys->flag |= PSYS_DRAWING;
+
+ rng= BLI_rng_new(psys->seed);
+
+ totpart=psys->totpart;
+
+ memset(&sd, 0, sizeof(ParticleStrandData));
+ sd.override_uv = -1;
+
+/* 2.1 setup material stff */
+ ma= give_render_material(re, ob, part->omat);
+
+#if 0 /* XXX old animation system */
+ if (ma->ipo) {
+ calc_ipo(ma->ipo, cfra);
+ execute_ipo((ID *)ma, ma->ipo);
+ }
+#endif /* XXX old animation system */
+
+ hasize = ma->hasize;
+ seed = ma->seed1;
+
+ re->flag |= R_HALO;
+
+ RE_set_customdata_names(obr, &psmd->dm_final->faceData);
+ sd.totuv = CustomData_number_of_layers(&psmd->dm_final->faceData, CD_MTFACE);
+ sd.totcol = CustomData_number_of_layers(&psmd->dm_final->faceData, CD_MCOL);
+
+ if (ma->texco & TEXCO_UV && sd.totuv) {
+ sd.uvco = MEM_callocN(sd.totuv * 2 * sizeof(float), "particle_uvs");
+
+ if (ma->strand_uvname[0]) {
+ sd.override_uv = CustomData_get_named_layer_index(&psmd->dm_final->faceData, CD_MTFACE, ma->strand_uvname);
+ sd.override_uv -= CustomData_get_layer_index(&psmd->dm_final->faceData, CD_MTFACE);
+ }
+ }
+ else
+ sd.uvco = NULL;
+
+ if (sd.totcol)
+ sd.mcol = MEM_callocN(sd.totcol * sizeof(MCol), "particle_mcols");
+
+/* 2.2 setup billboards */
+ if (part->ren_as == PART_DRAW_BB) {
+ int first_uv = CustomData_get_layer_index(&psmd->dm_final->faceData, CD_MTFACE);
+
+ bb.uv[0] = CustomData_get_named_layer_index(&psmd->dm_final->faceData, CD_MTFACE, psys->bb_uvname[0]);
+ if (bb.uv[0] < 0)
+ bb.uv[0] = CustomData_get_active_layer_index(&psmd->dm_final->faceData, CD_MTFACE);
+
+ bb.uv[1] = CustomData_get_named_layer_index(&psmd->dm_final->faceData, CD_MTFACE, psys->bb_uvname[1]);
+
+ bb.uv[2] = CustomData_get_named_layer_index(&psmd->dm_final->faceData, CD_MTFACE, psys->bb_uvname[2]);
+
+ if (first_uv >= 0) {
+ bb.uv[0] -= first_uv;
+ bb.uv[1] -= first_uv;
+ bb.uv[2] -= first_uv;
+ }
+
+ bb.align = part->bb_align;
+ bb.anim = part->bb_anim;
+ bb.lock = part->draw & PART_DRAW_BB_LOCK;
+ bb.ob = (part->bb_ob ? part->bb_ob : RE_GetCamera(re));
+ bb.split_offset = part->bb_split_offset;
+ bb.totnum = totpart+totchild;
+ bb.uv_split = part->bb_uv_split;
+ }
+
+/* 2.5 setup matrices */
+ mul_m4_m4m4(mat, re->viewmat, ob->obmat);
+ invert_m4_m4(ob->imat, mat); /* need to be that way, for imat texture */
+ transpose_m3_m4(nmat, ob->imat);
+
+ if (psys->flag & PSYS_USE_IMAT) {
+ /* psys->imat is the original emitter's inverse matrix, ob->obmat is the duplicated object's matrix */
+ mul_m4_m4m4(duplimat, ob->obmat, psys->imat);
+ use_duplimat = true;
+ }
+
+/* 2.6 setup strand rendering */
+ if (part->ren_as == PART_DRAW_PATH && psys->pathcache) {
+ path_nbr = step_nbr;
+
+ if (path_nbr) {
+ if (!ELEM(ma->material_type, MA_TYPE_HALO, MA_TYPE_WIRE)) {
+ sd.orco = get_object_orco(re, psys);
+ if (!sd.orco) {
+ sd.orco = MEM_mallocN(3*sizeof(float)*(totpart+totchild), "particle orcos");
+ set_object_orco(re, psys, sd.orco);
+ }
+ }
+ }
+
+ if (part->draw & PART_DRAW_REN_ADAPT) {
+ sd.adapt = 1;
+ sd.adapt_pix = (float)part->adapt_pix;
+ sd.adapt_angle = cosf(DEG2RADF((float)part->adapt_angle));
+ }
+
+ if (part->draw & PART_DRAW_REN_STRAND) {
+ strandbuf= RE_addStrandBuffer(obr, (totpart+totchild)*(path_nbr+1));
+ strandbuf->ma= ma;
+ strandbuf->lay= ob->lay;
+ copy_m4_m4(strandbuf->winmat, re->winmat);
+ strandbuf->winx= re->winx;
+ strandbuf->winy= re->winy;
+ strandbuf->maxdepth= 2;
+ strandbuf->adaptcos= cosf(DEG2RADF((float)part->adapt_angle));
+ strandbuf->overrideuv= sd.override_uv;
+ strandbuf->minwidth= ma->strand_min;
+
+ if (ma->strand_widthfade == 0.0f)
+ strandbuf->widthfade= -1.0f;
+ else if (ma->strand_widthfade >= 1.0f)
+ strandbuf->widthfade= 2.0f - ma->strand_widthfade;
+ else
+ strandbuf->widthfade= 1.0f/MAX2(ma->strand_widthfade, 1e-5f);
+
+ if (part->flag & PART_HAIR_BSPLINE)
+ strandbuf->flag |= R_STRAND_BSPLINE;
+ if (ma->mode & MA_STR_B_UNITS)
+ strandbuf->flag |= R_STRAND_B_UNITS;
+
+ svert= strandbuf->vert;
+
+ if (re->r.mode & R_SPEED)
+ do_surfacecache = true;
+ else if ((re->wrld.mode & (WO_AMB_OCC|WO_ENV_LIGHT|WO_INDIRECT_LIGHT)) && (re->wrld.ao_gather_method == WO_AOGATHER_APPROX))
+ if (ma->amb != 0.0f)
+ do_surfacecache = true;
+
+ totface= psmd->dm_final->getNumTessFaces(psmd->dm_final);
+ index_mf_to_mpoly = psmd->dm_final->getTessFaceDataArray(psmd->dm_final, CD_ORIGINDEX);
+ index_mp_to_orig = psmd->dm_final->getPolyDataArray(psmd->dm_final, CD_ORIGINDEX);
+ if (index_mf_to_mpoly == NULL) {
+ index_mp_to_orig = NULL;
+ }
+ for (a=0; a<totface; a++)
+ strandbuf->totbound = max_ii(strandbuf->totbound, (index_mf_to_mpoly) ? DM_origindex_mface_mpoly(index_mf_to_mpoly, index_mp_to_orig, a): a);
+
+ strandbuf->totbound++;
+ strandbuf->bound= MEM_callocN(sizeof(StrandBound)*strandbuf->totbound, "StrandBound");
+ sbound= strandbuf->bound;
+ sbound->start= sbound->end= 0;
+ }
+ }
+
+ if (sd.orco == NULL) {
+ sd.orco = MEM_mallocN(3 * sizeof(float), "particle orco");
+ orco1 = 1;
+ }
+
+ if (path_nbr == 0)
+ psys->lattice_deform_data = psys_create_lattice_deform_data(&sim);
+
+/* 3. start creating renderable things */
+ for (a=0, pa=pars; a<totpart+totchild; a++, pa++, seed++) {
+ random = BLI_rng_get_float(rng);
+ /* setup per particle individual stuff */
+ if (a<totpart) {
+ if (pa->flag & PARS_UNEXIST) continue;
+
+ pa_time=(cfra-pa->time)/pa->lifetime;
+ pa_birthtime = pa->time;
+ pa_dietime = pa->dietime;
+
+ hasize = ma->hasize;
+
+ /* XXX 'tpsys' is alwyas NULL, this code won't run! */
+ /* get orco */
+ if (tpsys && part->phystype == PART_PHYS_NO) {
+ tpa = tpsys->particles + pa->num;
+ psys_particle_on_emitter(
+ psmd,
+ tpart->from, tpa->num, pa->num_dmcache, tpa->fuv,
+ tpa->foffset, co, nor, NULL, NULL, sd.orco, NULL);
+ }
+ else {
+ psys_particle_on_emitter(
+ psmd,
+ part->from, pa->num, pa->num_dmcache,
+ pa->fuv, pa->foffset, co, nor, NULL, NULL, sd.orco, NULL);
+ }
+
+ /* get uvco & mcol */
+ num= pa->num_dmcache;
+
+ if (num == DMCACHE_NOTFOUND)
+ if (pa->num < psmd->dm_final->getNumTessFaces(psmd->dm_final))
+ num= pa->num;
+
+ get_particle_uvco_mcol(part->from, psmd->dm_final, pa->fuv, num, &sd);
+
+ pa_size = pa->size;
+
+ r_tilt = 2.0f*(psys_frand(psys, a) - 0.5f);
+ r_length = psys_frand(psys, a+1);
+
+ if (path_nbr) {
+ cache = psys->pathcache[a];
+ max_k = (int)cache->segments;
+ }
+
+ if (totchild && (part->draw&PART_DRAW_PARENT)==0) continue;
+ }
+ else {
+ ChildParticle *cpa= psys->child+a-totpart;
+
+ if (path_nbr) {
+ cache = psys->childcache[a-totpart];
+
+ if (cache->segments < 0)
+ continue;
+
+ max_k = (int)cache->segments;
+ }
+
+ pa_time = psys_get_child_time(psys, cpa, cfra, &pa_birthtime, &pa_dietime);
+ pa_size = psys_get_child_size(psys, cpa, cfra, &pa_time);
+
+ r_tilt = 2.0f*(psys_frand(psys, a + 21) - 0.5f);
+ r_length = psys_frand(psys, a + 22);
+
+ num = cpa->num;
+
+ /* get orco */
+ if (part->childtype == PART_CHILD_FACES) {
+ psys_particle_on_emitter(
+ psmd,
+ PART_FROM_FACE, cpa->num, DMCACHE_ISCHILD,
+ cpa->fuv, cpa->foffset, co, nor, NULL, NULL, sd.orco, NULL);
+ }
+ else {
+ ParticleData *par = psys->particles + cpa->parent;
+ psys_particle_on_emitter(
+ psmd,
+ part->from, par->num, DMCACHE_ISCHILD, par->fuv,
+ par->foffset, co, nor, NULL, NULL, sd.orco, NULL);
+ }
+
+ /* get uvco & mcol */
+ if (part->childtype==PART_CHILD_FACES) {
+ get_particle_uvco_mcol(PART_FROM_FACE, psmd->dm_final, cpa->fuv, cpa->num, &sd);
+ }
+ else {
+ ParticleData *parent = psys->particles + cpa->parent;
+ num = parent->num_dmcache;
+
+ if (num == DMCACHE_NOTFOUND)
+ if (parent->num < psmd->dm_final->getNumTessFaces(psmd->dm_final))
+ num = parent->num;
+
+ get_particle_uvco_mcol(part->from, psmd->dm_final, parent->fuv, num, &sd);
+ }
+
+ do_simplify = psys_render_simplify_params(psys, cpa, simplify);
+
+ if (strandbuf) {
+ int orignum = (index_mf_to_mpoly) ? DM_origindex_mface_mpoly(index_mf_to_mpoly, index_mp_to_orig, cpa->num) : cpa->num;
+
+ if ((orignum > sbound - strandbuf->bound) &&
+ (orignum < strandbuf->totbound))
+ {
+ sbound = &strandbuf->bound[orignum];
+ sbound->start = sbound->end = obr->totstrand;
+ }
+ }
+ }
+
+ /* TEXCO_PARTICLE */
+ pa_co[0] = pa_time;
+ pa_co[1] = 0.f;
+ pa_co[2] = 0.f;
+
+ /* surface normal shading setup */
+ if (ma->mode_l & MA_STR_SURFDIFF) {
+ mul_m3_v3(nmat, nor);
+ sd.surfnor= nor;
+ }
+ else
+ sd.surfnor= NULL;
+
+ /* strand render setup */
+ if (strandbuf) {
+ strand= RE_findOrAddStrand(obr, obr->totstrand++);
+ strand->buffer= strandbuf;
+ strand->vert= svert;
+ copy_v3_v3(strand->orco, sd.orco);
+
+ if (do_simplify) {
+ float *ssimplify= RE_strandren_get_simplify(obr, strand, 1);
+ ssimplify[0]= simplify[0];
+ ssimplify[1]= simplify[1];
+ }
+
+ if (sd.surfnor) {
+ float *snor= RE_strandren_get_surfnor(obr, strand, 1);
+ copy_v3_v3(snor, sd.surfnor);
+ }
+
+ if (do_surfacecache && num >= 0) {
+ int *facenum= RE_strandren_get_face(obr, strand, 1);
+ *facenum= num;
+ }
+
+ if (sd.uvco) {
+ for (i=0; i<sd.totuv; i++) {
+ if (i != sd.override_uv) {
+ float *uv= RE_strandren_get_uv(obr, strand, i, NULL, 1);
+
+ uv[0]= sd.uvco[2*i];
+ uv[1]= sd.uvco[2*i+1];
+ }
+ }
+ }
+ if (sd.mcol) {
+ for (i=0; i<sd.totcol; i++) {
+ MCol *mc= RE_strandren_get_mcol(obr, strand, i, NULL, 1);
+ *mc = sd.mcol[i];
+ }
+ }
+
+ sbound->end++;
+ }
+
+ /* strandco computation setup */
+ if (path_nbr) {
+ strandlen= 0.0f;
+ curlen= 0.0f;
+ for (k=1; k<=path_nbr; k++)
+ if (k<=max_k)
+ strandlen += len_v3v3((cache+k-1)->co, (cache+k)->co);
+ }
+
+ if (path_nbr) {
+ /* render strands */
+ for (k=0; k<=path_nbr; k++) {
+ float time;
+
+ if (k<=max_k) {
+ copy_v3_v3(state.co, (cache+k)->co);
+ copy_v3_v3(state.vel, (cache+k)->vel);
+ }
+ else
+ continue;
+
+ if (k > 0)
+ curlen += len_v3v3((cache+k-1)->co, (cache+k)->co);
+ time= curlen/strandlen;
+
+ copy_v3_v3(loc, state.co);
+ mul_m4_v3(re->viewmat, loc);
+
+ if (strandbuf) {
+ copy_v3_v3(svert->co, loc);
+ svert->strandco= -1.0f + 2.0f*time;
+ svert++;
+ strand->totvert++;
+ }
+ else {
+ sd.size = hasize;
+
+ if (k==1) {
+ sd.first = 1;
+ sd.time = 0.0f;
+ sub_v3_v3v3(loc0, loc1, loc);
+ add_v3_v3v3(loc0, loc1, loc0);
+
+ particle_curve(re, obr, psmd->dm_final, ma, &sd, loc1, loc0, seed, pa_co);
+ }
+
+ sd.first = 0;
+ sd.time = time;
+
+ if (k)
+ particle_curve(re, obr, psmd->dm_final, ma, &sd, loc, loc1, seed, pa_co);
+
+ copy_v3_v3(loc1, loc);
+ }
+ }
+
+ }
+ else {
+ /* render normal particles */
+ if (part->trail_count > 1) {
+ float length = part->path_end * (1.0f - part->randlength * r_length);
+ int trail_count = part->trail_count * (1.0f - part->randlength * r_length);
+ float ct = (part->draw & PART_ABS_PATH_TIME) ? cfra : pa_time;
+ float dt = length / (trail_count ? (float)trail_count : 1.0f);
+
+ /* make sure we have pointcache in memory before getting particle on path */
+ psys_make_temp_pointcache(ob, psys);
+
+ for (i=0; i < trail_count; i++, ct -= dt) {
+ if (part->draw & PART_ABS_PATH_TIME) {
+ if (ct < pa_birthtime || ct > pa_dietime)
+ continue;
+ }
+ else if (ct < 0.0f || ct > 1.0f)
+ continue;
+
+ state.time = (part->draw & PART_ABS_PATH_TIME) ? -ct : ct;
+ psys_get_particle_on_path(&sim, a, &state, 1);
+
+ if (psys->parent)
+ mul_m4_v3(psys->parent->obmat, state.co);
+
+ if (use_duplimat)
+ mul_m4_v4(duplimat, state.co);
+
+ if (part->ren_as == PART_DRAW_BB) {
+ bb.random = random;
+ bb.offset[0] = part->bb_offset[0];
+ bb.offset[1] = part->bb_offset[1];
+ bb.size[0] = part->bb_size[0] * pa_size;
+ if (part->bb_align==PART_BB_VEL) {
+ float pa_vel = len_v3(state.vel);
+ float head = part->bb_vel_head*pa_vel;
+ float tail = part->bb_vel_tail*pa_vel;
+ bb.size[1] = part->bb_size[1]*pa_size + head + tail;
+ /* use offset to adjust the particle center. this is relative to size, so need to divide! */
+ if (bb.size[1] > 0.0f)
+ bb.offset[1] += (head-tail) / bb.size[1];
+ }
+ else
+ bb.size[1] = part->bb_size[1] * pa_size;
+ bb.tilt = part->bb_tilt * (1.0f - part->bb_rand_tilt * r_tilt);
+ bb.time = ct;
+ bb.num = a;
+ }
+
+ pa_co[0] = (part->draw & PART_ABS_PATH_TIME) ? (ct-pa_birthtime)/(pa_dietime-pa_birthtime) : ct;
+ pa_co[1] = (float)i/(float)(trail_count-1);
+
+ particle_normal_ren(part->ren_as, part, re, obr, psmd->dm_final, ma, &sd, &bb, &state, seed, hasize, pa_co);
+ }
+ }
+ else {
+ state.time=cfra;
+ if (psys_get_particle_state(&sim, a, &state, 0)==0)
+ continue;
+
+ if (psys->parent)
+ mul_m4_v3(psys->parent->obmat, state.co);
+
+ if (use_duplimat)
+ mul_m4_v3(duplimat, state.co);
+
+ if (part->ren_as == PART_DRAW_BB) {
+ bb.random = random;
+ bb.offset[0] = part->bb_offset[0];
+ bb.offset[1] = part->bb_offset[1];
+ bb.size[0] = part->bb_size[0] * pa_size;
+ if (part->bb_align==PART_BB_VEL) {
+ float pa_vel = len_v3(state.vel);
+ float head = part->bb_vel_head*pa_vel;
+ float tail = part->bb_vel_tail*pa_vel;
+ bb.size[1] = part->bb_size[1]*pa_size + head + tail;
+ /* use offset to adjust the particle center. this is relative to size, so need to divide! */
+ if (bb.size[1] > 0.0f)
+ bb.offset[1] += (head-tail) / bb.size[1];
+ }
+ else
+ bb.size[1] = part->bb_size[1] * pa_size;
+ bb.tilt = part->bb_tilt * (1.0f - part->bb_rand_tilt * r_tilt);
+ bb.time = pa_time;
+ bb.num = a;
+ bb.lifetime = pa_dietime-pa_birthtime;
+ }
+
+ particle_normal_ren(part->ren_as, part, re, obr, psmd->dm_final, ma, &sd, &bb, &state, seed, hasize, pa_co);
+ }
+ }
+
+ if (orco1==0)
+ sd.orco+=3;
+
+ if (re->test_break(re->tbh))
+ break;
+ }
+
+ if (do_surfacecache)
+ strandbuf->surface= cache_strand_surface(re, obr, psmd->dm_final, mat, timeoffset);
+
+/* 4. clean up */
+#if 0 /* XXX old animation system */
+ if (ma) do_mat_ipo(re->scene, ma);
+#endif /* XXX old animation system */
+
+ if (orco1)
+ MEM_freeN(sd.orco);
+
+ if (sd.uvco)
+ MEM_freeN(sd.uvco);
+
+ if (sd.mcol)
+ MEM_freeN(sd.mcol);
+
+ if (states)
+ MEM_freeN(states);
+
+ BLI_rng_free(rng);
+
+ psys->flag &= ~PSYS_DRAWING;
+
+ if (psys->lattice_deform_data) {
+ end_latt_deform(psys->lattice_deform_data);
+ psys->lattice_deform_data = NULL;
+ }
+
+ if (path_nbr && (ma->mode_l & MA_TANGENT_STR)==0)
+ calc_vertexnormals(re, obr, 1, 0, 0);
+
+ return 1;
+}
+
+/* ------------------------------------------------------------------------- */
+/* Halo's */
+/* ------------------------------------------------------------------------- */
+
+static void make_render_halos(Render *re, ObjectRen *obr, Mesh *UNUSED(me), int totvert, MVert *mvert, Material *ma, float *orco)
+{
+ Object *ob= obr->ob;
+ HaloRen *har;
+ float xn, yn, zn, nor[3], view[3];
+ float vec[3], hasize, mat[4][4], imat[3][3];
+ int a, ok, seed= ma->seed1;
+
+ mul_m4_m4m4(mat, re->viewmat, ob->obmat);
+ copy_m3_m4(imat, ob->imat);
+
+ re->flag |= R_HALO;
+
+ for (a=0; a<totvert; a++, mvert++) {
+ ok= 1;
+
+ if (ok) {
+ hasize= ma->hasize;
+
+ copy_v3_v3(vec, mvert->co);
+ mul_m4_v3(mat, vec);
+
+ if (ma->mode & MA_HALOPUNO) {
+ xn= mvert->no[0];
+ yn= mvert->no[1];
+ zn= mvert->no[2];
+
+ /* transpose ! */
+ nor[0]= imat[0][0]*xn+imat[0][1]*yn+imat[0][2]*zn;
+ nor[1]= imat[1][0]*xn+imat[1][1]*yn+imat[1][2]*zn;
+ nor[2]= imat[2][0]*xn+imat[2][1]*yn+imat[2][2]*zn;
+ normalize_v3(nor);
+
+ copy_v3_v3(view, vec);
+ normalize_v3(view);
+
+ zn = dot_v3v3(nor, view);
+ if (zn>=0.0f) hasize= 0.0f;
+ else hasize*= zn*zn*zn*zn;
+ }
+
+ if (orco) har= RE_inithalo(re, obr, ma, vec, NULL, orco, hasize, 0.0, seed);
+ else har= RE_inithalo(re, obr, ma, vec, NULL, mvert->co, hasize, 0.0, seed);
+ if (har) har->lay= ob->lay;
+ }
+ if (orco) orco+= 3;
+ seed++;
+ }
+}
+
+static int verghalo(const void *a1, const void *a2)
+{
+ const HaloRen *har1= *(const HaloRen**)a1;
+ const HaloRen *har2= *(const HaloRen**)a2;
+
+ if (har1->zs < har2->zs) return 1;
+ else if (har1->zs > har2->zs) return -1;
+ return 0;
+}
+
+static void sort_halos(Render *re, int totsort)
+{
+ ObjectRen *obr;
+ HaloRen *har= NULL, **haso;
+ int a;
+
+ if (re->tothalo==0) return;
+
+ re->sortedhalos= MEM_callocN(sizeof(HaloRen*)*re->tothalo, "sorthalos");
+ haso= re->sortedhalos;
+
+ for (obr=re->objecttable.first; obr; obr=obr->next) {
+ for (a=0; a<obr->tothalo; a++) {
+ if ((a & 255)==0) har= obr->bloha[a>>8];
+ else har++;
+
+ *(haso++)= har;
+ }
+ }
+
+ qsort(re->sortedhalos, totsort, sizeof(HaloRen*), verghalo);
+}
+
+/* ------------------------------------------------------------------------- */
+/* Displacement Mapping */
+/* ------------------------------------------------------------------------- */
+
+static short test_for_displace(Render *re, Object *ob)
+{
+ /* return 1 when this object uses displacement textures. */
+ Material *ma;
+ int i;
+
+ for (i=1; i<=ob->totcol; i++) {
+ ma=give_render_material(re, ob, i);
+ /* ma->mapto is ORed total of all mapto channels */
+ if (ma && (ma->mapto & MAP_DISPLACE)) return 1;
+ }
+ return 0;
+}
+
+static void displace_render_vert(Render *re, ObjectRen *obr, ShadeInput *shi, VertRen *vr, int vindex, float *scale)
+{
+ MTFace *tface;
+ short texco= shi->mat->texco;
+ float sample=0, displace[3];
+ char *name;
+ int i;
+
+ /* shi->co is current render coord, just make sure at least some vector is here */
+ copy_v3_v3(shi->co, vr->co);
+ /* vertex normal is used for textures type 'col' and 'var' */
+ copy_v3_v3(shi->vn, vr->n);
+
+ if (texco & TEXCO_UV) {
+ shi->totuv= 0;
+ shi->actuv= obr->actmtface;
+
+ for (i=0; (tface=RE_vlakren_get_tface(obr, shi->vlr, i, &name, 0)); i++) {
+ ShadeInputUV *suv= &shi->uv[i];
+
+ /* shi.uv needs scale correction from tface uv */
+ suv->uv[0]= 2*tface->uv[vindex][0]-1.0f;
+ suv->uv[1]= 2*tface->uv[vindex][1]-1.0f;
+ suv->uv[2]= 0.0f;
+ suv->name= name;
+ shi->totuv++;
+ }
+ }
+
+ /* set all rendercoords, 'texco' is an ORed value for all textures needed */
+ if ((texco & TEXCO_ORCO) && (vr->orco)) {
+ copy_v3_v3(shi->lo, vr->orco);
+ }
+ if (texco & TEXCO_GLOB) {
+ copy_v3_v3(shi->gl, shi->co);
+ mul_m4_v3(re->viewinv, shi->gl);
+ }
+ if (texco & TEXCO_NORM) {
+ copy_v3_v3(shi->orn, shi->vn);
+ }
+ if (texco & TEXCO_REFL) {
+ /* not (yet?) */
+ }
+ if (texco & TEXCO_STRESS) {
+ const float *s= RE_vertren_get_stress(obr, vr, 0);
+
+ if (s) {
+ shi->stress= *s;
+ if (shi->stress<1.0f) shi->stress-= 1.0f;
+ else shi->stress= (shi->stress-1.0f)/shi->stress;
+ }
+ else
+ shi->stress= 0.0f;
+ }
+
+ shi->displace[0]= shi->displace[1]= shi->displace[2]= 0.0;
+
+ do_material_tex(shi, re);
+
+ //printf("no=%f, %f, %f\nbefore co=%f, %f, %f\n", vr->n[0], vr->n[1], vr->n[2],
+ //vr->co[0], vr->co[1], vr->co[2]);
+
+ displace[0]= shi->displace[0] * scale[0];
+ displace[1]= shi->displace[1] * scale[1];
+ displace[2]= shi->displace[2] * scale[2];
+
+ /* 0.5 could become button once? */
+ vr->co[0] += displace[0];
+ vr->co[1] += displace[1];
+ vr->co[2] += displace[2];
+
+ //printf("after co=%f, %f, %f\n", vr->co[0], vr->co[1], vr->co[2]);
+
+ /* we just don't do this vertex again, bad luck for other face using same vertex with
+ * different material... */
+ vr->flag |= 1;
+
+ /* Pass sample back so displace_face can decide which way to split the quad */
+ sample = shi->displace[0]*shi->displace[0];
+ sample += shi->displace[1]*shi->displace[1];
+ sample += shi->displace[2]*shi->displace[2];
+
+ vr->accum=sample;
+ /* Should be sqrt(sample), but I'm only looking for "bigger". Save the cycles. */
+ return;
+}
+
+static void displace_render_face(Render *re, ObjectRen *obr, VlakRen *vlr, float *scale)
+{
+ ShadeInput shi;
+
+ /* Warning, This is not that nice, and possibly a bit slow,
+ * however some variables were not initialized properly in, unless using shade_input_initialize(...), we need to do a memset */
+ memset(&shi, 0, sizeof(ShadeInput));
+ /* end warning! - Campbell */
+
+ /* set up shadeinput struct for multitex() */
+
+ /* memset above means we don't need this */
+ /*shi.osatex= 0;*/ /* signal not to use dx[] and dy[] texture AA vectors */
+
+ shi.obr= obr;
+ shi.vlr= vlr; /* current render face */
+ shi.mat= vlr->mat; /* current input material */
+ shi.thread= 0;
+
+ /* TODO, assign these, displacement with new bumpmap is skipped without - campbell */
+#if 0
+ /* order is not known ? */
+ shi.v1= vlr->v1;
+ shi.v2= vlr->v2;
+ shi.v3= vlr->v3;
+#endif
+
+ /* Displace the verts, flag is set when done */
+ if (!vlr->v1->flag)
+ displace_render_vert(re, obr, &shi, vlr->v1, 0, scale);
+
+ if (!vlr->v2->flag)
+ displace_render_vert(re, obr, &shi, vlr->v2, 1, scale);
+
+ if (!vlr->v3->flag)
+ displace_render_vert(re, obr, &shi, vlr->v3, 2, scale);
+
+ if (vlr->v4) {
+ if (!vlr->v4->flag)
+ displace_render_vert(re, obr, &shi, vlr->v4, 3, scale);
+
+ /* closest in displace value. This will help smooth edges. */
+ if (fabsf(vlr->v1->accum - vlr->v3->accum) > fabsf(vlr->v2->accum - vlr->v4->accum)) vlr->flag |= R_DIVIDE_24;
+ else vlr->flag &= ~R_DIVIDE_24;
+ }
+
+ /* Recalculate the face normal - if flipped before, flip now */
+ if (vlr->v4) {
+ normal_quad_v3(vlr->n, vlr->v4->co, vlr->v3->co, vlr->v2->co, vlr->v1->co);
+ }
+ else {
+ normal_tri_v3(vlr->n, vlr->v3->co, vlr->v2->co, vlr->v1->co);
+ }
+}
+
+static void displace(Render *re, ObjectRen *obr)
+{
+ VertRen *vr;
+ VlakRen *vlr;
+// float min[3]={1e30, 1e30, 1e30}, max[3]={-1e30, -1e30, -1e30};
+ float scale[3]={1.0f, 1.0f, 1.0f}, temp[3];//, xn
+ int i; //, texflag=0;
+ Object *obt;
+
+ /* Object Size with parenting */
+ obt=obr->ob;
+ while (obt) {
+ mul_v3_v3v3(temp, obt->size, obt->dscale);
+ scale[0]*=temp[0]; scale[1]*=temp[1]; scale[2]*=temp[2];
+ obt=obt->parent;
+ }
+
+ /* Clear all flags */
+ for (i=0; i<obr->totvert; i++) {
+ vr= RE_findOrAddVert(obr, i);
+ vr->flag= 0;
+ }
+
+ for (i=0; i<obr->totvlak; i++) {
+ vlr=RE_findOrAddVlak(obr, i);
+ displace_render_face(re, obr, vlr, scale);
+ }
+
+ /* Recalc vertex normals */
+ calc_vertexnormals(re, obr, 1, 0, 0);
+}
+
+/* ------------------------------------------------------------------------- */
+/* Metaball */
+/* ------------------------------------------------------------------------- */
+
+static void init_render_mball(Render *re, ObjectRen *obr)
+{
+ Object *ob= obr->ob;
+ DispList *dl;
+ VertRen *ver;
+ VlakRen *vlr, *vlr1;
+ Material *ma;
+ float *data, *nors, *orco=NULL, mat[4][4], imat[3][3], xn, yn, zn;
+ int a, need_orco, vlakindex, *index, negative_scale;
+ ListBase dispbase= {NULL, NULL};
+
+ if (ob!=BKE_mball_basis_find(re->eval_ctx, re->scene, ob))
+ return;
+
+ mul_m4_m4m4(mat, re->viewmat, ob->obmat);
+ invert_m4_m4(ob->imat, mat);
+ copy_m3_m4(imat, ob->imat);
+ negative_scale = is_negative_m4(mat);
+
+ ma= give_render_material(re, ob, 1);
+
+ need_orco= 0;
+ if (ma->texco & TEXCO_ORCO) {
+ need_orco= 1;
+ }
+
+ BKE_displist_make_mball_forRender(re->eval_ctx, re->scene, ob, &dispbase);
+ dl= dispbase.first;
+ if (dl == NULL) return;
+
+ data= dl->verts;
+ nors= dl->nors;
+ if (need_orco) {
+ orco= get_object_orco(re, ob);
+
+ if (!orco) {
+ /* orco hasn't been found in cache - create new one and add to cache */
+ orco= BKE_mball_make_orco(ob, &dispbase);
+ set_object_orco(re, ob, orco);
+ }
+ }
+
+ for (a=0; a<dl->nr; a++, data+=3, nors+=3) {
+
+ ver= RE_findOrAddVert(obr, obr->totvert++);
+ copy_v3_v3(ver->co, data);
+ mul_m4_v3(mat, ver->co);
+
+ /* render normals are inverted */
+ xn= -nors[0];
+ yn= -nors[1];
+ zn= -nors[2];
+
+ /* transpose ! */
+ ver->n[0]= imat[0][0]*xn+imat[0][1]*yn+imat[0][2]*zn;
+ ver->n[1]= imat[1][0]*xn+imat[1][1]*yn+imat[1][2]*zn;
+ ver->n[2]= imat[2][0]*xn+imat[2][1]*yn+imat[2][2]*zn;
+ normalize_v3(ver->n);
+ //if (ob->transflag & OB_NEG_SCALE) negate_v3(ver->n);
+
+ if (need_orco) {
+ ver->orco= orco;
+ orco+=3;
+ }
+ }
+
+ index= dl->index;
+ for (a=0; a<dl->parts; a++, index+=4) {
+
+ vlr= RE_findOrAddVlak(obr, obr->totvlak++);
+ vlr->v1= RE_findOrAddVert(obr, index[0]);
+ vlr->v2= RE_findOrAddVert(obr, index[1]);
+ vlr->v3= RE_findOrAddVert(obr, index[2]);
+ vlr->v4 = NULL;
+
+ if (negative_scale)
+ normal_tri_v3(vlr->n, vlr->v1->co, vlr->v2->co, vlr->v3->co);
+ else
+ normal_tri_v3(vlr->n, vlr->v3->co, vlr->v2->co, vlr->v1->co);
+
+ vlr->mat= ma;
+ vlr->flag= ME_SMOOTH;
+ vlr->ec= 0;
+
+ /* mball -too bad- always has triangles, because quads can be non-planar */
+ if (index[3] && index[3]!=index[2]) {
+ vlr1= RE_findOrAddVlak(obr, obr->totvlak++);
+ vlakindex= vlr1->index;
+ *vlr1= *vlr;
+ vlr1->index= vlakindex;
+ vlr1->v2= vlr1->v3;
+ vlr1->v3= RE_findOrAddVert(obr, index[3]);
+ if (negative_scale)
+ normal_tri_v3(vlr1->n, vlr1->v1->co, vlr1->v2->co, vlr1->v3->co);
+ else
+ normal_tri_v3(vlr1->n, vlr1->v3->co, vlr1->v2->co, vlr1->v1->co);
+ }
+ }
+
+ /* enforce display lists remade */
+ BKE_displist_free(&dispbase);
+}
+
+/* ------------------------------------------------------------------------- */
+/* Surfaces and Curves */
+/* ------------------------------------------------------------------------- */
+
+/* returns amount of vertices added for orco */
+static int dl_surf_to_renderdata(ObjectRen *obr, DispList *dl, Material **matar, float *orco, float mat[4][4])
+{
+ VertRen *v1, *v2, *v3, *v4, *ver;
+ VlakRen *vlr, *vlr1, *vlr2, *vlr3;
+ float *data, n1[3];
+ int u, v, orcoret= 0;
+ int p1, p2, p3, p4, a;
+ int sizeu, nsizeu, sizev, nsizev;
+ int startvert, startvlak;
+
+ startvert= obr->totvert;
+ nsizeu = sizeu = dl->parts; nsizev = sizev = dl->nr;
+
+ data= dl->verts;
+ for (u = 0; u < sizeu; u++) {
+ v1 = RE_findOrAddVert(obr, obr->totvert++); /* save this for possible V wrapping */
+ copy_v3_v3(v1->co, data); data += 3;
+ if (orco) {
+ v1->orco= orco; orco+= 3; orcoret++;
+ }
+ mul_m4_v3(mat, v1->co);
+
+ for (v = 1; v < sizev; v++) {
+ ver= RE_findOrAddVert(obr, obr->totvert++);
+ copy_v3_v3(ver->co, data); data += 3;
+ if (orco) {
+ ver->orco= orco; orco+= 3; orcoret++;
+ }
+ mul_m4_v3(mat, ver->co);
+ }
+ /* if V-cyclic, add extra vertices at end of the row */
+ if (dl->flag & DL_CYCL_U) {
+ ver= RE_findOrAddVert(obr, obr->totvert++);
+ copy_v3_v3(ver->co, v1->co);
+ if (orco) {
+ ver->orco= orco; orco+=3; orcoret++; //orcobase + 3*(u*sizev + 0);
+ }
+ }
+ }
+
+ /* Done before next loop to get corner vert */
+ if (dl->flag & DL_CYCL_U) nsizev++;
+ if (dl->flag & DL_CYCL_V) nsizeu++;
+
+ /* if U cyclic, add extra row at end of column */
+ if (dl->flag & DL_CYCL_V) {
+ for (v = 0; v < nsizev; v++) {
+ v1= RE_findOrAddVert(obr, startvert + v);
+ ver= RE_findOrAddVert(obr, obr->totvert++);
+ copy_v3_v3(ver->co, v1->co);
+ if (orco) {
+ ver->orco= orco; orco+=3; orcoret++; //ver->orco= orcobase + 3*(0*sizev + v);
+ }
+ }
+ }
+
+ sizeu = nsizeu;
+ sizev = nsizev;
+
+ startvlak= obr->totvlak;
+
+ for (u = 0; u < sizeu - 1; u++) {
+ p1 = startvert + u * sizev; /* walk through face list */
+ p2 = p1 + 1;
+ p3 = p2 + sizev;
+ p4 = p3 - 1;
+
+ for (v = 0; v < sizev - 1; v++) {
+ v1= RE_findOrAddVert(obr, p1);
+ v2= RE_findOrAddVert(obr, p2);
+ v3= RE_findOrAddVert(obr, p3);
+ v4= RE_findOrAddVert(obr, p4);
+
+ vlr= RE_findOrAddVlak(obr, obr->totvlak++);
+ vlr->v1= v1; vlr->v2= v2; vlr->v3= v3; vlr->v4= v4;
+
+ normal_quad_v3(n1, vlr->v4->co, vlr->v3->co, vlr->v2->co, vlr->v1->co);
+
+ copy_v3_v3(vlr->n, n1);
+
+ vlr->mat= matar[ dl->col];
+ vlr->ec= ME_V1V2+ME_V2V3;
+ vlr->flag= dl->rt;
+
+ add_v3_v3(v1->n, n1);
+ add_v3_v3(v2->n, n1);
+ add_v3_v3(v3->n, n1);
+ add_v3_v3(v4->n, n1);
+
+ p1++; p2++; p3++; p4++;
+ }
+ }
+ /* fix normals for U resp. V cyclic faces */
+ sizeu--; sizev--; /* dec size for face array */
+ if (dl->flag & DL_CYCL_V) {
+
+ for (v = 0; v < sizev; v++) {
+ /* optimize! :*/
+ vlr= RE_findOrAddVlak(obr, UVTOINDEX(sizeu - 1, v));
+ vlr1= RE_findOrAddVlak(obr, UVTOINDEX(0, v));
+ add_v3_v3(vlr1->v1->n, vlr->n);
+ add_v3_v3(vlr1->v2->n, vlr->n);
+ add_v3_v3(vlr->v3->n, vlr1->n);
+ add_v3_v3(vlr->v4->n, vlr1->n);
+ }
+ }
+ if (dl->flag & DL_CYCL_U) {
+
+ for (u = 0; u < sizeu; u++) {
+ /* optimize! :*/
+ vlr= RE_findOrAddVlak(obr, UVTOINDEX(u, 0));
+ vlr1= RE_findOrAddVlak(obr, UVTOINDEX(u, sizev-1));
+ add_v3_v3(vlr1->v2->n, vlr->n);
+ add_v3_v3(vlr1->v3->n, vlr->n);
+ add_v3_v3(vlr->v1->n, vlr1->n);
+ add_v3_v3(vlr->v4->n, vlr1->n);
+ }
+ }
+
+ /* last vertex is an extra case:
+ *
+ * ^ ()----()----()----()
+ * | | | || |
+ * u | |(0,n)||(0,0)|
+ * | | || |
+ * ()====()====[]====()
+ * | | || |
+ * | |(m,n)||(m,0)|
+ * | | || |
+ * ()----()----()----()
+ * v ->
+ *
+ * vertex [] is no longer shared, therefore distribute
+ * normals of the surrounding faces to all of the duplicates of []
+ */
+
+ if ((dl->flag & DL_CYCL_V) && (dl->flag & DL_CYCL_U)) {
+ vlr= RE_findOrAddVlak(obr, UVTOINDEX(sizeu - 1, sizev - 1)); /* (m, n) */
+ vlr1= RE_findOrAddVlak(obr, UVTOINDEX(0, 0)); /* (0, 0) */
+ add_v3_v3v3(n1, vlr->n, vlr1->n);
+ vlr2= RE_findOrAddVlak(obr, UVTOINDEX(0, sizev-1)); /* (0, n) */
+ add_v3_v3(n1, vlr2->n);
+ vlr3= RE_findOrAddVlak(obr, UVTOINDEX(sizeu-1, 0)); /* (m, 0) */
+ add_v3_v3(n1, vlr3->n);
+ copy_v3_v3(vlr->v3->n, n1);
+ copy_v3_v3(vlr1->v1->n, n1);
+ copy_v3_v3(vlr2->v2->n, n1);
+ copy_v3_v3(vlr3->v4->n, n1);
+ }
+ for (a = startvert; a < obr->totvert; a++) {
+ ver= RE_findOrAddVert(obr, a);
+ normalize_v3(ver->n);
+ }
+
+
+ return orcoret;
+}
+
+static void init_render_dm(DerivedMesh *dm, Render *re, ObjectRen *obr,
+ int timeoffset, float *orco, float mat[4][4])
+{
+ Object *ob= obr->ob;
+ int a, end, totvert, vertofs;
+ short mat_iter;
+ VertRen *ver;
+ VlakRen *vlr;
+ MVert *mvert = NULL;
+ MFace *mface;
+ Material *ma;
+#ifdef WITH_FREESTYLE
+ const int *index_mf_to_mpoly = NULL;
+ const int *index_mp_to_orig = NULL;
+ FreestyleFace *ffa = NULL;
+#endif
+ /* Curve *cu= ELEM(ob->type, OB_FONT, OB_CURVE) ? ob->data : NULL; */
+
+ mvert= dm->getVertArray(dm);
+ totvert= dm->getNumVerts(dm);
+
+ for (a=0; a<totvert; a++, mvert++) {
+ ver= RE_findOrAddVert(obr, obr->totvert++);
+ copy_v3_v3(ver->co, mvert->co);
+ mul_m4_v3(mat, ver->co);
+
+ if (orco) {
+ ver->orco= orco;
+ orco+=3;
+ }
+ }
+
+ if (!timeoffset) {
+ /* store customdata names, because DerivedMesh is freed */
+ RE_set_customdata_names(obr, &dm->faceData);
+
+ /* still to do for keys: the correct local texture coordinate */
+
+ /* faces in order of color blocks */
+ vertofs= obr->totvert - totvert;
+ for (mat_iter= 0; (mat_iter < ob->totcol || (mat_iter==0 && ob->totcol==0)); mat_iter++) {
+
+ ma= give_render_material(re, ob, mat_iter+1);
+ end= dm->getNumTessFaces(dm);
+ mface= dm->getTessFaceArray(dm);
+
+#ifdef WITH_FREESTYLE
+ if (ob->type == OB_MESH) {
+ Mesh *me= ob->data;
+ index_mf_to_mpoly= dm->getTessFaceDataArray(dm, CD_ORIGINDEX);
+ index_mp_to_orig= dm->getPolyDataArray(dm, CD_ORIGINDEX);
+ ffa= CustomData_get_layer(&me->pdata, CD_FREESTYLE_FACE);
+ }
+#endif
+
+ for (a=0; a<end; a++, mface++) {
+ int v1, v2, v3, v4, flag;
+
+ if (mface->mat_nr == mat_iter) {
+ float len;
+
+ v1= mface->v1;
+ v2= mface->v2;
+ v3= mface->v3;
+ v4= mface->v4;
+ flag= mface->flag & ME_SMOOTH;
+
+ vlr= RE_findOrAddVlak(obr, obr->totvlak++);
+ vlr->v1= RE_findOrAddVert(obr, vertofs+v1);
+ vlr->v2= RE_findOrAddVert(obr, vertofs+v2);
+ vlr->v3= RE_findOrAddVert(obr, vertofs+v3);
+ if (v4) vlr->v4= RE_findOrAddVert(obr, vertofs+v4);
+ else vlr->v4 = NULL;
+
+ /* render normals are inverted in render */
+ if (vlr->v4)
+ len= normal_quad_v3(vlr->n, vlr->v4->co, vlr->v3->co, vlr->v2->co, vlr->v1->co);
+ else
+ len= normal_tri_v3(vlr->n, vlr->v3->co, vlr->v2->co, vlr->v1->co);
+
+ vlr->mat= ma;
+ vlr->flag= flag;
+ vlr->ec= 0; /* mesh edges rendered separately */
+#ifdef WITH_FREESTYLE
+ if (ffa) {
+ int index = (index_mf_to_mpoly) ? DM_origindex_mface_mpoly(index_mf_to_mpoly, index_mp_to_orig, a) : a;
+ vlr->freestyle_face_mark= (ffa[index].flag & FREESTYLE_FACE_MARK) ? 1 : 0;
+ }
+ else {
+ vlr->freestyle_face_mark= 0;
+ }
+#endif
+
+ if (len==0) obr->totvlak--;
+ else {
+ CustomDataLayer *layer;
+ MTFace *mtface, *mtf;
+ MCol *mcol, *mc;
+ int index, mtfn= 0, mcn= 0;
+ char *name;
+
+ for (index=0; index<dm->faceData.totlayer; index++) {
+ layer= &dm->faceData.layers[index];
+ name= layer->name;
+
+ if (layer->type == CD_MTFACE && mtfn < MAX_MTFACE) {
+ mtf= RE_vlakren_get_tface(obr, vlr, mtfn++, &name, 1);
+ mtface= (MTFace*)layer->data;
+ *mtf= mtface[a];
+ }
+ else if (layer->type == CD_MCOL && mcn < MAX_MCOL) {
+ mc= RE_vlakren_get_mcol(obr, vlr, mcn++, &name, 1);
+ mcol= (MCol*)layer->data;
+ memcpy(mc, &mcol[a*4], sizeof(MCol)*4);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ /* Normals */
+ calc_vertexnormals(re, obr, 1, 0, 0);
+ }
+
+}
+
+static void init_render_surf(Render *re, ObjectRen *obr, int timeoffset)
+{
+ Object *ob= obr->ob;
+ Nurb *nu = NULL;
+ Curve *cu;
+ ListBase displist= {NULL, NULL};
+ DispList *dl;
+ Material **matar;
+ float *orco=NULL, mat[4][4];
+ int a, totmat;
+ bool need_orco = false;
+ DerivedMesh *dm= NULL;
+
+ cu= ob->data;
+ nu= cu->nurb.first;
+ if (nu == NULL) return;
+
+ mul_m4_m4m4(mat, re->viewmat, ob->obmat);
+ invert_m4_m4(ob->imat, mat);
+
+ /* material array */
+ totmat= ob->totcol+1;
+ matar= MEM_callocN(sizeof(Material*)*totmat, "init_render_surf matar");
+
+ for (a=0; a<totmat; a++) {
+ matar[a]= give_render_material(re, ob, a+1);
+
+ if (matar[a] && matar[a]->texco & TEXCO_ORCO)
+ need_orco= 1;
+ }
+
+ if (ob->parent && (ob->parent->type==OB_LATTICE)) need_orco= 1;
+
+ BKE_displist_make_surf(re->scene, ob, &displist, &dm, 1, 0, 1);
+
+ if (dm) {
+ if (need_orco) {
+ orco = get_object_orco(re, ob);
+ if (!orco) {
+ orco= BKE_displist_make_orco(re->scene, ob, dm, true, true);
+ if (orco) {
+ set_object_orco(re, ob, orco);
+ }
+ }
+ }
+
+ init_render_dm(dm, re, obr, timeoffset, orco, mat);
+ dm->release(dm);
+ }
+ else {
+ if (need_orco) {
+ orco = get_object_orco(re, ob);
+ if (!orco) {
+ orco = BKE_curve_surf_make_orco(ob);
+ set_object_orco(re, ob, orco);
+ }
+ }
+
+ /* walk along displaylist and create rendervertices/-faces */
+ for (dl=displist.first; dl; dl=dl->next) {
+ /* watch out: u ^= y, v ^= x !! */
+ if (dl->type==DL_SURF)
+ orco+= 3*dl_surf_to_renderdata(obr, dl, matar, orco, mat);
+ }
+ }
+
+ BKE_displist_free(&displist);
+
+ MEM_freeN(matar);
+}
+
+static void init_render_curve(Render *re, ObjectRen *obr, int timeoffset)
+{
+ Object *ob= obr->ob;
+ Curve *cu;
+ VertRen *ver;
+ VlakRen *vlr;
+ DispList *dl;
+ DerivedMesh *dm = NULL;
+ ListBase disp={NULL, NULL};
+ Material **matar;
+ float *data, *fp, *orco=NULL;
+ float n[3], mat[4][4], nmat[4][4];
+ int nr, startvert, a, b, negative_scale;
+ bool need_orco = false;
+ int totmat;
+
+ cu= ob->data;
+ if (ob->type==OB_FONT && cu->str==NULL) return;
+ else if (ob->type==OB_CURVE && cu->nurb.first==NULL) return;
+
+ BKE_displist_make_curveTypes_forRender(re->scene, ob, &disp, &dm, false, true);
+ dl= disp.first;
+ if (dl==NULL) return;
+
+ mul_m4_m4m4(mat, re->viewmat, ob->obmat);
+ invert_m4_m4(ob->imat, mat);
+ negative_scale = is_negative_m4(mat);
+
+ /* local object -> world space transform for normals */
+ transpose_m4_m4(nmat, mat);
+ invert_m4(nmat);
+
+ /* material array */
+ totmat= ob->totcol+1;
+ matar= MEM_callocN(sizeof(Material*)*totmat, "init_render_surf matar");
+
+ for (a=0; a<totmat; a++) {
+ matar[a]= give_render_material(re, ob, a+1);
+
+ if (matar[a] && matar[a]->texco & TEXCO_ORCO)
+ need_orco= 1;
+ }
+
+ if (dm) {
+ if (need_orco) {
+ orco = get_object_orco(re, ob);
+ if (!orco) {
+ orco = BKE_displist_make_orco(re->scene, ob, dm, true, true);
+ if (orco) {
+ set_object_orco(re, ob, orco);
+ }
+ }
+ }
+
+ init_render_dm(dm, re, obr, timeoffset, orco, mat);
+ dm->release(dm);
+ }
+ else {
+ if (need_orco) {
+ orco = get_object_orco(re, ob);
+ if (!orco) {
+ orco = BKE_curve_make_orco(re->scene, ob, NULL);
+ set_object_orco(re, ob, orco);
+ }
+ }
+
+ while (dl) {
+ if (dl->col > ob->totcol) {
+ /* pass */
+ }
+ else if (dl->type==DL_INDEX3) {
+ const int *index;
+
+ startvert= obr->totvert;
+ data= dl->verts;
+
+ for (a=0; a<dl->nr; a++, data+=3) {
+ ver= RE_findOrAddVert(obr, obr->totvert++);
+ copy_v3_v3(ver->co, data);
+
+ mul_m4_v3(mat, ver->co);
+
+ if (orco) {
+ ver->orco = orco;
+ orco += 3;
+ }
+ }
+
+ if (timeoffset==0) {
+ float tmp[3];
+ const int startvlak= obr->totvlak;
+
+ zero_v3(n);
+ index= dl->index;
+ for (a=0; a<dl->parts; a++, index+=3) {
+ int v1 = index[0], v2 = index[2], v3 = index[1];
+ float *co1 = &dl->verts[v1 * 3],
+ *co2 = &dl->verts[v2 * 3],
+ *co3 = &dl->verts[v3 * 3];
+
+ vlr= RE_findOrAddVlak(obr, obr->totvlak++);
+ vlr->v1= RE_findOrAddVert(obr, startvert + v1);
+ vlr->v2= RE_findOrAddVert(obr, startvert + v2);
+ vlr->v3= RE_findOrAddVert(obr, startvert + v3);
+ vlr->v4= NULL;
+
+ /* to prevent float accuracy issues, we calculate normal in local object space (not world) */
+ if (normal_tri_v3(tmp, co1, co2, co3) > FLT_EPSILON) {
+ if (negative_scale == false) {
+ add_v3_v3(n, tmp);
+ }
+ else {
+ sub_v3_v3(n, tmp);
+ }
+ }
+
+ vlr->mat= matar[ dl->col ];
+ vlr->flag= 0;
+ vlr->ec= 0;
+ }
+
+ /* transform normal to world space */
+ mul_m4_v3(nmat, n);
+ normalize_v3(n);
+
+ /* vertex normals */
+ for (a= startvlak; a<obr->totvlak; a++) {
+ vlr= RE_findOrAddVlak(obr, a);
+
+ copy_v3_v3(vlr->n, n);
+ add_v3_v3(vlr->v1->n, vlr->n);
+ add_v3_v3(vlr->v3->n, vlr->n);
+ add_v3_v3(vlr->v2->n, vlr->n);
+ }
+ for (a=startvert; a<obr->totvert; a++) {
+ ver= RE_findOrAddVert(obr, a);
+ normalize_v3(ver->n);
+ }
+ }
+ }
+ else if (dl->type==DL_SURF) {
+
+ /* cyclic U means an extruded full circular curve, we skip bevel splitting then */
+ if (dl->flag & DL_CYCL_U) {
+ orco+= 3*dl_surf_to_renderdata(obr, dl, matar, orco, mat);
+ }
+ else {
+ int p1, p2, p3, p4;
+
+ fp= dl->verts;
+ startvert= obr->totvert;
+ nr= dl->nr*dl->parts;
+
+ while (nr--) {
+ ver= RE_findOrAddVert(obr, obr->totvert++);
+
+ copy_v3_v3(ver->co, fp);
+ mul_m4_v3(mat, ver->co);
+ fp+= 3;
+
+ if (orco) {
+ ver->orco = orco;
+ orco += 3;
+ }
+ }
+
+ if (dl->flag & DL_CYCL_V && orco) {
+ fp = dl->verts;
+ nr = dl->nr;
+ while (nr--) {
+ ver = RE_findOrAddVert(obr, obr->totvert++);
+ copy_v3_v3(ver->co, fp);
+ mul_m4_v3(mat, ver->co);
+ ver->orco = orco;
+ fp += 3;
+ orco += 3;
+ }
+ }
+
+ if (dl->bevel_split || timeoffset == 0) {
+ const int startvlak= obr->totvlak;
+
+ for (a=0; a<dl->parts; a++) {
+
+ if (BKE_displist_surfindex_get(dl, a, &b, &p1, &p2, &p3, &p4)==0)
+ break;
+
+ p1+= startvert;
+ p2+= startvert;
+ p3+= startvert;
+ p4+= startvert;
+
+ if (dl->flag & DL_CYCL_V && orco && a == dl->parts - 1) {
+ p3 = p1 + dl->nr;
+ p4 = p2 + dl->nr;
+ }
+
+ for (; b<dl->nr; b++) {
+ vlr= RE_findOrAddVlak(obr, obr->totvlak++);
+ /* important 1 offset in order is kept [#24913] */
+ vlr->v1= RE_findOrAddVert(obr, p2);
+ vlr->v2= RE_findOrAddVert(obr, p1);
+ vlr->v3= RE_findOrAddVert(obr, p3);
+ vlr->v4= RE_findOrAddVert(obr, p4);
+ vlr->ec= ME_V2V3+ME_V3V4;
+ if (a==0) vlr->ec+= ME_V1V2;
+
+ vlr->flag= dl->rt;
+
+ normal_quad_v3(vlr->n, vlr->v4->co, vlr->v3->co, vlr->v2->co, vlr->v1->co);
+ vlr->mat= matar[ dl->col ];
+
+ p4= p3;
+ p3++;
+ p2= p1;
+ p1++;
+ }
+ }
+
+ if (dl->bevel_split) {
+ for (a = 0; a < dl->parts - 1 + !!(dl->flag & DL_CYCL_V); a++) {
+ if (BLI_BITMAP_TEST(dl->bevel_split, a)) {
+ split_v_renderfaces(
+ obr, startvlak, startvert, dl->parts, dl->nr, a,
+ /* intentionally swap (v, u) --> (u, v) */
+ dl->flag & DL_CYCL_V, dl->flag & DL_CYCL_U);
+ }
+ }
+ }
+
+ /* vertex normals */
+ for (a= startvlak; a<obr->totvlak; a++) {
+ vlr= RE_findOrAddVlak(obr, a);
+
+ add_v3_v3(vlr->v1->n, vlr->n);
+ add_v3_v3(vlr->v3->n, vlr->n);
+ add_v3_v3(vlr->v2->n, vlr->n);
+ add_v3_v3(vlr->v4->n, vlr->n);
+ }
+ for (a=startvert; a<obr->totvert; a++) {
+ ver= RE_findOrAddVert(obr, a);
+ normalize_v3(ver->n);
+ }
+ }
+ }
+ }
+
+ dl= dl->next;
+ }
+ }
+
+ BKE_displist_free(&disp);
+
+ MEM_freeN(matar);
+}
+
+/* ------------------------------------------------------------------------- */
+/* Mesh */
+/* ------------------------------------------------------------------------- */
+
+struct edgesort {
+ unsigned int v1, v2;
+ int f;
+ unsigned int i1, i2;
+};
+
+/* edges have to be added with lowest index first for sorting */
+static void to_edgesort(struct edgesort *ed,
+ unsigned int i1, unsigned int i2,
+ unsigned int v1, unsigned int v2, int f)
+{
+ if (v1 > v2) {
+ SWAP(unsigned int, v1, v2);
+ SWAP(unsigned int, i1, i2);
+ }
+
+ ed->v1= v1;
+ ed->v2= v2;
+ ed->i1= i1;
+ ed->i2= i2;
+ ed->f = f;
+}
+
+static int vergedgesort(const void *v1, const void *v2)
+{
+ const struct edgesort *x1=v1, *x2=v2;
+
+ if ( x1->v1 > x2->v1) return 1;
+ else if ( x1->v1 < x2->v1) return -1;
+ else if ( x1->v2 > x2->v2) return 1;
+ else if ( x1->v2 < x2->v2) return -1;
+
+ return 0;
+}
+
+static struct edgesort *make_mesh_edge_lookup(DerivedMesh *dm, int *totedgesort)
+{
+ MFace *mf, *mface;
+ MTFace *tface=NULL;
+ struct edgesort *edsort, *ed;
+ unsigned int *mcol=NULL;
+ int a, totedge=0, totface;
+
+ mface= dm->getTessFaceArray(dm);
+ totface= dm->getNumTessFaces(dm);
+ tface= dm->getTessFaceDataArray(dm, CD_MTFACE);
+ mcol= dm->getTessFaceDataArray(dm, CD_MCOL);
+
+ if (mcol==NULL && tface==NULL) return NULL;
+
+ /* make sorted table with edges and face indices in it */
+ for (a= totface, mf= mface; a>0; a--, mf++) {
+ totedge += mf->v4 ? 4 : 3;
+ }
+
+ if (totedge==0)
+ return NULL;
+
+ ed= edsort= MEM_callocN(totedge*sizeof(struct edgesort), "edgesort");
+
+ for (a=0, mf=mface; a<totface; a++, mf++) {
+ to_edgesort(ed++, 0, 1, mf->v1, mf->v2, a);
+ to_edgesort(ed++, 1, 2, mf->v2, mf->v3, a);
+ if (mf->v4) {
+ to_edgesort(ed++, 2, 3, mf->v3, mf->v4, a);
+ to_edgesort(ed++, 3, 0, mf->v4, mf->v1, a);
+ }
+ else {
+ to_edgesort(ed++, 2, 3, mf->v3, mf->v1, a);
+ }
+ }
+
+ qsort(edsort, totedge, sizeof(struct edgesort), vergedgesort);
+
+ *totedgesort= totedge;
+
+ return edsort;
+}
+
+static void use_mesh_edge_lookup(ObjectRen *obr, DerivedMesh *dm, MEdge *medge, VlakRen *vlr, struct edgesort *edgetable, int totedge)
+{
+ struct edgesort ed, *edp;
+ CustomDataLayer *layer;
+ MTFace *mtface, *mtf;
+ MCol *mcol, *mc;
+ int index, mtfn, mcn;
+ char *name;
+
+ if (medge->v1 < medge->v2) {
+ ed.v1= medge->v1;
+ ed.v2= medge->v2;
+ }
+ else {
+ ed.v1= medge->v2;
+ ed.v2= medge->v1;
+ }
+
+ edp= bsearch(&ed, edgetable, totedge, sizeof(struct edgesort), vergedgesort);
+
+ /* since edges have different index ordering, we have to duplicate mcol and tface */
+ if (edp) {
+ mtfn= mcn= 0;
+
+ for (index=0; index<dm->faceData.totlayer; index++) {
+ layer= &dm->faceData.layers[index];
+ name= layer->name;
+
+ if (layer->type == CD_MTFACE && mtfn < MAX_MTFACE) {
+ mtface= &((MTFace*)layer->data)[edp->f];
+ mtf= RE_vlakren_get_tface(obr, vlr, mtfn++, &name, 1);
+
+ *mtf= *mtface;
+
+ memcpy(mtf->uv[0], mtface->uv[edp->i1], sizeof(float)*2);
+ memcpy(mtf->uv[1], mtface->uv[edp->i2], sizeof(float)*2);
+ memcpy(mtf->uv[2], mtface->uv[1], sizeof(float)*2);
+ memcpy(mtf->uv[3], mtface->uv[1], sizeof(float)*2);
+ }
+ else if (layer->type == CD_MCOL && mcn < MAX_MCOL) {
+ mcol= &((MCol*)layer->data)[edp->f*4];
+ mc= RE_vlakren_get_mcol(obr, vlr, mcn++, &name, 1);
+
+ mc[0]= mcol[edp->i1];
+ mc[1]= mc[2]= mc[3]= mcol[edp->i2];
+ }
+ }
+ }
+}
+
+static void free_camera_inside_volumes(Render *re)
+{
+ BLI_freelistN(&re->render_volumes_inside);
+}
+
+static void init_camera_inside_volumes(Render *re)
+{
+ ObjectInstanceRen *obi;
+ VolumeOb *vo;
+ /* coordinates are all in camera space, so camera coordinate is zero. we also
+ * add an offset for the clip start, however note that with clip start it's
+ * actually impossible to do a single 'inside' test, since there will not be
+ * a single point where all camera rays start from, though for small clip start
+ * they will be close together. */
+ float co[3] = {0.f, 0.f, -re->clipsta};
+
+ for (vo= re->volumes.first; vo; vo= vo->next) {
+ for (obi= re->instancetable.first; obi; obi= obi->next) {
+ if (obi->obr == vo->obr) {
+ if (point_inside_volume_objectinstance(re, obi, co)) {
+ MatInside *mi;
+
+ mi = MEM_mallocN(sizeof(MatInside), "camera inside material");
+ mi->ma = vo->ma;
+ mi->obi = obi;
+
+ BLI_addtail(&(re->render_volumes_inside), mi);
+ }
+ }
+ }
+ }
+
+
+#if 0 /* debug */
+ {
+ MatInside *m;
+ for (m = re->render_volumes_inside.first; m; m = m->next) {
+ printf("matinside: ma: %s\n", m->ma->id.name + 2);
+ }
+ }
+#endif
+}
+
+static void add_volume(Render *re, ObjectRen *obr, Material *ma)
+{
+ struct VolumeOb *vo;
+
+ vo = MEM_mallocN(sizeof(VolumeOb), "volume object");
+
+ vo->ma = ma;
+ vo->obr = obr;
+
+ BLI_addtail(&re->volumes, vo);
+}
+
+#ifdef WITH_FREESTYLE
+static EdgeHash *make_freestyle_edge_mark_hash(DerivedMesh *dm)
+{
+ EdgeHash *edge_hash= NULL;
+ FreestyleEdge *fed;
+ MEdge *medge;
+ int totedge, a;
+
+ medge = dm->getEdgeArray(dm);
+ totedge = dm->getNumEdges(dm);
+ fed = dm->getEdgeDataArray(dm, CD_FREESTYLE_EDGE);
+ if (fed) {
+ edge_hash = BLI_edgehash_new(__func__);
+ for (a = 0; a < totedge; a++) {
+ if (fed[a].flag & FREESTYLE_EDGE_MARK)
+ BLI_edgehash_insert(edge_hash, medge[a].v1, medge[a].v2, medge+a);
+ }
+ }
+ return edge_hash;
+}
+
+static bool has_freestyle_edge_mark(EdgeHash *edge_hash, int v1, int v2)
+{
+ MEdge *medge= BLI_edgehash_lookup(edge_hash, v1, v2);
+ return (!medge) ? 0 : 1;
+}
+#endif
+
+static void init_render_mesh(Render *re, ObjectRen *obr, int timeoffset)
+{
+ Object *ob= obr->ob;
+ Mesh *me;
+ MVert *mvert = NULL;
+ MFace *mface;
+ VlakRen *vlr; //, *vlr1;
+ VertRen *ver;
+ Material *ma;
+ DerivedMesh *dm;
+ CustomDataMask mask;
+ float xn, yn, zn, imat[3][3], mat[4][4]; //nor[3],
+ float *orco = NULL;
+ short (*loop_nors)[4][3] = NULL;
+ bool need_orco = false, need_stress = false, need_tangent = false, need_origindex = false;
+ bool need_nmap_tangent_concrete = false;
+ int a, a1, ok, vertofs;
+ int end, totvert = 0;
+ bool do_autosmooth = false, do_displace = false;
+ bool use_original_normals = false;
+ int recalc_normals = 0; /* false by default */
+ int negative_scale;
+#ifdef WITH_FREESTYLE
+ FreestyleFace *ffa;
+#endif
+
+ me= ob->data;
+
+ mul_m4_m4m4(mat, re->viewmat, ob->obmat);
+ invert_m4_m4(ob->imat, mat);
+ copy_m3_m4(imat, ob->imat);
+ negative_scale= is_negative_m4(mat);
+
+ need_orco= 0;
+ for (a=1; a<=ob->totcol; a++) {
+ ma= give_render_material(re, ob, a);
+ if (ma) {
+ if (ma->texco & (TEXCO_ORCO|TEXCO_STRESS))
+ need_orco= 1;
+ if (ma->texco & TEXCO_STRESS)
+ need_stress= 1;
+ /* normalmaps, test if tangents needed, separated from shading */
+ if (ma->mode_l & MA_TANGENT_V) {
+ need_tangent= 1;
+ if (me->mtpoly==NULL)
+ need_orco= 1;
+ }
+ if (ma->mode_l & MA_NORMAP_TANG) {
+ if (me->mtpoly==NULL) {
+ need_orco= 1;
+ }
+ need_tangent= 1;
+ }
+ if (ma->mode2_l & MA_TANGENT_CONCRETE) {
+ need_nmap_tangent_concrete = true;
+ }
+ }
+ }
+
+ if (re->flag & R_NEED_TANGENT) {
+ /* exception for tangent space baking */
+ if (me->mtpoly==NULL) {
+ need_orco= 1;
+ }
+ need_tangent= 1;
+ }
+
+ /* check autosmooth and displacement, we then have to skip only-verts optimize
+ * Note: not sure what we want to give higher priority, currently do_displace
+ * takes precedence over do_autosmooth.
+ */
+ do_displace = test_for_displace(re, ob);
+ do_autosmooth = ((me->flag & ME_AUTOSMOOTH) != 0) && !do_displace;
+ if (do_autosmooth || do_displace)
+ timeoffset = 0;
+
+ /* origindex currently used when using autosmooth, or baking to vertex colors. */
+ need_origindex = (do_autosmooth || ((re->flag & R_BAKING) && (re->r.bake_flag & R_BAKE_VCOL)));
+
+ mask = CD_MASK_RENDER_INTERNAL;
+ if (!timeoffset)
+ if (need_orco)
+ mask |= CD_MASK_ORCO;
+
+#ifdef WITH_FREESTYLE
+ mask |= CD_MASK_ORIGINDEX | CD_MASK_FREESTYLE_EDGE | CD_MASK_FREESTYLE_FACE;
+#endif
+
+ if (re->r.scemode & R_VIEWPORT_PREVIEW)
+ dm= mesh_create_derived_view(re->scene, ob, mask);
+ else
+ dm= mesh_create_derived_render(re->scene, ob, mask);
+ if (dm==NULL) return; /* in case duplicated object fails? */
+
+ mvert= dm->getVertArray(dm);
+ totvert= dm->getNumVerts(dm);
+
+ if (totvert == 0) {
+ dm->release(dm);
+ return;
+ }
+
+ if (mask & CD_MASK_ORCO) {
+ orco = get_object_orco(re, ob);
+ if (!orco) {
+ orco= dm->getVertDataArray(dm, CD_ORCO);
+ if (orco) {
+ orco= MEM_dupallocN(orco);
+ set_object_orco(re, ob, orco);
+ }
+ }
+ }
+
+ /* attempt to autsmooth on original mesh, only without subsurf */
+ if (do_autosmooth && me->totvert==totvert && me->totface==dm->getNumTessFaces(dm))
+ use_original_normals= true;
+
+ ma= give_render_material(re, ob, 1);
+
+
+ if (ma->material_type == MA_TYPE_HALO) {
+ make_render_halos(re, obr, me, totvert, mvert, ma, orco);
+ }
+ else {
+ const int *index_vert_orig = NULL;
+ const int *index_mf_to_mpoly = NULL;
+ const int *index_mp_to_orig = NULL;
+ if (need_origindex) {
+ index_vert_orig = dm->getVertDataArray(dm, CD_ORIGINDEX);
+ /* double lookup for faces -> polys */
+#ifdef WITH_FREESTYLE
+ index_mf_to_mpoly = dm->getTessFaceDataArray(dm, CD_ORIGINDEX);
+ index_mp_to_orig = dm->getPolyDataArray(dm, CD_ORIGINDEX);
+#endif
+ }
+
+ for (a=0; a<totvert; a++, mvert++) {
+ ver= RE_findOrAddVert(obr, obr->totvert++);
+ copy_v3_v3(ver->co, mvert->co);
+ if (do_autosmooth == false) { /* autosmooth on original unrotated data to prevent differences between frames */
+ normal_short_to_float_v3(ver->n, mvert->no);
+ mul_m4_v3(mat, ver->co);
+ mul_transposed_m3_v3(imat, ver->n);
+ normalize_v3(ver->n);
+ negate_v3(ver->n);
+ }
+
+ if (orco) {
+ ver->orco= orco;
+ orco+=3;
+ }
+
+ if (need_origindex) {
+ int *origindex;
+ origindex = RE_vertren_get_origindex(obr, ver, 1);
+
+ /* Use orig index array if it's available (e.g. in the presence
+ * of modifiers). */
+ if (index_vert_orig)
+ *origindex = index_vert_orig[a];
+ else
+ *origindex = a;
+ }
+ }
+
+ if (!timeoffset) {
+ short (*lnp)[4][3] = NULL;
+#ifdef WITH_FREESTYLE
+ EdgeHash *edge_hash;
+
+ /* create a hash table of Freestyle edge marks */
+ edge_hash = make_freestyle_edge_mark_hash(dm);
+#endif
+
+ /* store customdata names, because DerivedMesh is freed */
+ RE_set_customdata_names(obr, &dm->faceData);
+
+ /* add tangent layers if we need */
+ if ((ma->nmap_tangent_names_count && need_nmap_tangent_concrete) || need_tangent) {
+ dm->calcLoopTangents(
+ dm, need_tangent,
+ (const char (*)[MAX_NAME])ma->nmap_tangent_names, ma->nmap_tangent_names_count);
+ obr->tangent_mask = dm->tangent_mask;
+ DM_generate_tangent_tessface_data(dm, need_nmap_tangent_concrete || need_tangent);
+ }
+
+ /* still to do for keys: the correct local texture coordinate */
+
+ /* faces in order of color blocks */
+ vertofs= obr->totvert - totvert;
+ for (a1=0; (a1<ob->totcol || (a1==0 && ob->totcol==0)); a1++) {
+
+ ma= give_render_material(re, ob, a1+1);
+
+ /* test for 100% transparent */
+ ok = 1;
+ if ((ma->alpha == 0.0f) &&
+ (ma->spectra == 0.0f) &&
+ /* No need to test filter here, it's only active with MA_RAYTRANSP and we check against it below. */
+ /* (ma->filter == 0.0f) && */
+ (ma->mode & MA_TRANSP) &&
+ (ma->mode & (MA_RAYTRANSP | MA_RAYMIRROR)) == 0)
+ {
+ ok = 0;
+ /* texture on transparency? */
+ for (a=0; a<MAX_MTEX; a++) {
+ if (ma->mtex[a] && ma->mtex[a]->tex) {
+ if (ma->mtex[a]->mapto & MAP_ALPHA) ok= 1;
+ }
+ }
+ }
+
+ /* if wire material, and we got edges, don't do the faces */
+ if (ma->material_type == MA_TYPE_WIRE) {
+ end= dm->getNumEdges(dm);
+ if (end) ok= 0;
+ }
+
+ if (ok) {
+ end= dm->getNumTessFaces(dm);
+ mface= dm->getTessFaceArray(dm);
+ if (!loop_nors && do_autosmooth &&
+ (dm->getTessFaceDataArray(dm, CD_TESSLOOPNORMAL) != NULL))
+ {
+ lnp = loop_nors = MEM_mallocN(sizeof(*loop_nors) * end, __func__);
+ }
+#ifdef WITH_FREESTYLE
+ index_mf_to_mpoly= dm->getTessFaceDataArray(dm, CD_ORIGINDEX);
+ index_mp_to_orig= dm->getPolyDataArray(dm, CD_ORIGINDEX);
+ ffa= CustomData_get_layer(&me->pdata, CD_FREESTYLE_FACE);
+#endif
+
+ for (a=0; a<end; a++, mface++) {
+ int v1, v2, v3, v4, flag;
+
+ if ( mface->mat_nr==a1 ) {
+ float len;
+ bool reverse_verts = (negative_scale != 0 && do_autosmooth == false);
+ int rev_tab[] = {reverse_verts==0 ? 0 : 2, 1, reverse_verts==0 ? 2 : 0, 3};
+ v1= reverse_verts==0 ? mface->v1 : mface->v3;
+ v2= mface->v2;
+ v3= reverse_verts==0 ? mface->v3 : mface->v1;
+ v4= mface->v4;
+ flag = do_autosmooth ? ME_SMOOTH : mface->flag & ME_SMOOTH;
+
+ vlr= RE_findOrAddVlak(obr, obr->totvlak++);
+ vlr->v1= RE_findOrAddVert(obr, vertofs+v1);
+ vlr->v2= RE_findOrAddVert(obr, vertofs+v2);
+ vlr->v3= RE_findOrAddVert(obr, vertofs+v3);
+ if (v4) vlr->v4 = RE_findOrAddVert(obr, vertofs+v4);
+ else vlr->v4 = NULL;
+
+#ifdef WITH_FREESTYLE
+ /* Freestyle edge/face marks */
+ if (edge_hash) {
+ int edge_mark = 0;
+
+ if (has_freestyle_edge_mark(edge_hash, v1, v2)) edge_mark |= R_EDGE_V1V2;
+ if (has_freestyle_edge_mark(edge_hash, v2, v3)) edge_mark |= R_EDGE_V2V3;
+ if (!v4) {
+ if (has_freestyle_edge_mark(edge_hash, v3, v1)) edge_mark |= R_EDGE_V3V1;
+ }
+ else {
+ if (has_freestyle_edge_mark(edge_hash, v3, v4)) edge_mark |= R_EDGE_V3V4;
+ if (has_freestyle_edge_mark(edge_hash, v4, v1)) edge_mark |= R_EDGE_V4V1;
+ }
+ vlr->freestyle_edge_mark= edge_mark;
+ }
+ if (ffa) {
+ int index = (index_mf_to_mpoly) ? DM_origindex_mface_mpoly(index_mf_to_mpoly, index_mp_to_orig, a) : a;
+ vlr->freestyle_face_mark= (ffa[index].flag & FREESTYLE_FACE_MARK) ? 1 : 0;
+ }
+ else {
+ vlr->freestyle_face_mark= 0;
+ }
+#endif
+
+ /* render normals are inverted in render */
+ if (use_original_normals) {
+ MFace *mf= me->mface+a;
+ MVert *mv= me->mvert;
+
+ if (vlr->v4)
+ len= normal_quad_v3(vlr->n, mv[mf->v4].co, mv[mf->v3].co, mv[mf->v2].co, mv[mf->v1].co);
+ else
+ len= normal_tri_v3(vlr->n, mv[mf->v3].co, mv[mf->v2].co, mv[mf->v1].co);
+ }
+ else {
+ if (vlr->v4)
+ len= normal_quad_v3(vlr->n, vlr->v4->co, vlr->v3->co, vlr->v2->co, vlr->v1->co);
+ else
+ len= normal_tri_v3(vlr->n, vlr->v3->co, vlr->v2->co, vlr->v1->co);
+ }
+
+ vlr->mat= ma;
+ vlr->flag= flag;
+ vlr->ec= 0; /* mesh edges rendered separately */
+
+ if (len==0) obr->totvlak--;
+ else {
+ CustomDataLayer *layer;
+ MTFace *mtface, *mtf;
+ MCol *mcol, *mc;
+ int index, mtfn= 0, mcn= 0, mln = 0, vindex;
+ char *name;
+ int nr_verts = v4!=0 ? 4 : 3;
+
+ for (index=0; index<dm->faceData.totlayer; index++) {
+ layer= &dm->faceData.layers[index];
+ name= layer->name;
+
+ if (layer->type == CD_MTFACE && mtfn < MAX_MTFACE) {
+ int t;
+ mtf= RE_vlakren_get_tface(obr, vlr, mtfn++, &name, 1);
+ mtface= (MTFace*)layer->data;
+ *mtf = mtface[a]; /* copy face info */
+ for (vindex=0; vindex<nr_verts; vindex++)
+ for (t=0; t<2; t++)
+ mtf->uv[vindex][t]=mtface[a].uv[rev_tab[vindex]][t];
+ }
+ else if (layer->type == CD_MCOL && mcn < MAX_MCOL) {
+ mc= RE_vlakren_get_mcol(obr, vlr, mcn++, &name, 1);
+ mcol= (MCol*)layer->data;
+ for (vindex=0; vindex<nr_verts; vindex++)
+ mc[vindex]=mcol[a*4+rev_tab[vindex]];
+ }
+ else if (layer->type == CD_TANGENT) {
+ if (need_nmap_tangent_concrete || need_tangent) {
+ int uv_start = CustomData_get_layer_index(&dm->faceData, CD_MTFACE);
+ int uv_index = CustomData_get_named_layer_index(&dm->faceData, CD_MTFACE, layer->name);
+
+ /* if there are no UVs, orco tangents are in first slot */
+ int n = (uv_start >= 0 && uv_index >= 0) ? uv_index - uv_start : 0;
+
+ const float *tangent = (const float *) layer->data;
+ float *ftang = RE_vlakren_get_nmap_tangent(obr, vlr, n, true);
+
+ for (vindex=0; vindex<nr_verts; vindex++) {
+ copy_v4_v4(ftang+vindex*4, tangent+a*16+rev_tab[vindex]*4);
+ mul_mat3_m4_v3(mat, ftang+vindex*4);
+ normalize_v3(ftang+vindex*4);
+ }
+ }
+ }
+ else if (layer->type == CD_TESSLOOPNORMAL && mln < 1) {
+ if (loop_nors) {
+ const short (*lnors)[4][3] = (const short (*)[4][3])layer->data;
+ for (vindex = 0; vindex < 4; vindex++) {
+ //print_v3("lnors[a][rev_tab[vindex]]", lnors[a][rev_tab[vindex]]);
+ copy_v3_v3_short((short *)lnp[0][vindex], lnors[a][rev_tab[vindex]]);
+ /* If we copy loop normals, we are doing autosmooth, so we are still
+ * in object space, no need to multiply with mat!
+ */
+ }
+ lnp++;
+ }
+ mln++;
+ }
+ }
+
+ if (need_origindex) {
+ /* Find original index of mpoly for this tessface. Options:
+ * - Modified mesh; two-step look up from tessface -> modified mpoly -> original mpoly
+ * - OR Tesselated mesh; look up from tessface -> mpoly
+ * - OR Failsafe; tessface == mpoly. Could probably assert(false) in this case? */
+ int *origindex;
+ origindex = RE_vlakren_get_origindex(obr, vlr, 1);
+ if (index_mf_to_mpoly && index_mp_to_orig)
+ *origindex = DM_origindex_mface_mpoly(index_mf_to_mpoly, index_mp_to_orig, a);
+ else if (index_mf_to_mpoly)
+ *origindex = index_mf_to_mpoly[a];
+ else
+ *origindex = a;
+ }
+ }
+ }
+ }
+ }
+ }
+
+#ifdef WITH_FREESTYLE
+ /* release the hash table of Freestyle edge marks */
+ if (edge_hash)
+ BLI_edgehash_free(edge_hash, NULL);
+#endif
+
+ /* exception... we do edges for wire mode. potential conflict when faces exist... */
+ end= dm->getNumEdges(dm);
+ mvert= dm->getVertArray(dm);
+ ma= give_render_material(re, ob, 1);
+ if (end && (ma->material_type == MA_TYPE_WIRE)) {
+ MEdge *medge;
+ struct edgesort *edgetable;
+ int totedge= 0;
+ recalc_normals= 1;
+
+ medge= dm->getEdgeArray(dm);
+
+ /* we want edges to have UV and vcol too... */
+ edgetable= make_mesh_edge_lookup(dm, &totedge);
+
+ for (a1=0; a1<end; a1++, medge++) {
+ if (medge->flag&ME_EDGERENDER) {
+ MVert *v0 = &mvert[medge->v1];
+ MVert *v1 = &mvert[medge->v2];
+
+ vlr= RE_findOrAddVlak(obr, obr->totvlak++);
+ vlr->v1= RE_findOrAddVert(obr, vertofs+medge->v1);
+ vlr->v2= RE_findOrAddVert(obr, vertofs+medge->v2);
+ vlr->v3= vlr->v2;
+ vlr->v4= NULL;
+
+ if (edgetable)
+ use_mesh_edge_lookup(obr, dm, medge, vlr, edgetable, totedge);
+
+ xn= -(v0->no[0]+v1->no[0]);
+ yn= -(v0->no[1]+v1->no[1]);
+ zn= -(v0->no[2]+v1->no[2]);
+ /* transpose ! */
+ vlr->n[0]= imat[0][0]*xn+imat[0][1]*yn+imat[0][2]*zn;
+ vlr->n[1]= imat[1][0]*xn+imat[1][1]*yn+imat[1][2]*zn;
+ vlr->n[2]= imat[2][0]*xn+imat[2][1]*yn+imat[2][2]*zn;
+ normalize_v3(vlr->n);
+
+ vlr->mat= ma;
+ vlr->flag= 0;
+ vlr->ec= ME_V1V2;
+ }
+ }
+ if (edgetable)
+ MEM_freeN(edgetable);
+ }
+ }
+ }
+
+ if (!timeoffset) {
+ if (need_stress)
+ calc_edge_stress(re, obr, me);
+
+ if (do_displace) {
+ calc_vertexnormals(re, obr, 1, 0, 0);
+ displace(re, obr);
+ recalc_normals = 0; /* Already computed by displace! */
+ }
+ else if (do_autosmooth) {
+ recalc_normals = (loop_nors == NULL); /* Should never happen, but better be safe than sorry. */
+ autosmooth(re, obr, mat, loop_nors);
+ }
+
+ if (recalc_normals!=0 || need_tangent!=0)
+ calc_vertexnormals(re, obr, recalc_normals, need_tangent, need_nmap_tangent_concrete);
+ }
+
+ MEM_SAFE_FREE(loop_nors);
+
+ dm->release(dm);
+}
+
+/* ------------------------------------------------------------------------- */
+/* Lamps and Shadowbuffers */
+/* ------------------------------------------------------------------------- */
+
+static void initshadowbuf(Render *re, LampRen *lar, float mat[4][4])
+{
+ struct ShadBuf *shb;
+ float viewinv[4][4];
+
+ /* if (la->spsi<16) return; */
+
+ /* memory alloc */
+ shb= (struct ShadBuf *)MEM_callocN(sizeof(struct ShadBuf), "initshadbuf");
+ lar->shb= shb;
+
+ if (shb==NULL) return;
+
+ VECCOPY(shb->co, lar->co); /* int copy */
+
+ /* percentage render: keep track of min and max */
+ shb->size= (lar->bufsize*re->r.size)/100;
+
+ if (shb->size<512) shb->size= 512;
+ else if (shb->size > lar->bufsize) shb->size= lar->bufsize;
+
+ shb->size &= ~15; /* make sure its multiples of 16 */
+
+ shb->samp= lar->samp;
+ shb->soft= lar->soft;
+ shb->shadhalostep= lar->shadhalostep;
+
+ normalize_m4(mat);
+ invert_m4_m4(shb->winmat, mat); /* winmat is temp */
+
+ /* matrix: combination of inverse view and lampmat */
+ /* calculate again: the ortho-render has no correct viewinv */
+ invert_m4_m4(viewinv, re->viewmat);
+ mul_m4_m4m4(shb->viewmat, shb->winmat, viewinv);
+
+ /* projection */
+ shb->d= lar->clipsta;
+ shb->clipend= lar->clipend;
+
+ /* bias is percentage, made 2x larger because of correction for angle of incidence */
+ /* when a ray is closer to parallel of a face, bias value is increased during render */
+ shb->bias= (0.02f*lar->bias)*0x7FFFFFFF;
+
+ /* halfway method (average of first and 2nd z) reduces bias issues */
+ if (ELEM(lar->buftype, LA_SHADBUF_HALFWAY, LA_SHADBUF_DEEP))
+ shb->bias= 0.1f*shb->bias;
+
+ shb->compressthresh= lar->compressthresh;
+}
+
+void area_lamp_vectors(LampRen *lar)
+{
+ float xsize= 0.5f*lar->area_size, ysize= 0.5f*lar->area_sizey, multifac;
+
+ /* make it smaller, so area light can be multisampled */
+ multifac= 1.0f/sqrtf((float)lar->ray_totsamp);
+ xsize *= multifac;
+ ysize *= multifac;
+
+ /* corner vectors */
+ lar->area[0][0]= lar->co[0] - xsize*lar->mat[0][0] - ysize*lar->mat[1][0];
+ lar->area[0][1]= lar->co[1] - xsize*lar->mat[0][1] - ysize*lar->mat[1][1];
+ lar->area[0][2]= lar->co[2] - xsize*lar->mat[0][2] - ysize*lar->mat[1][2];
+
+ /* corner vectors */
+ lar->area[1][0]= lar->co[0] - xsize*lar->mat[0][0] + ysize*lar->mat[1][0];
+ lar->area[1][1]= lar->co[1] - xsize*lar->mat[0][1] + ysize*lar->mat[1][1];
+ lar->area[1][2]= lar->co[2] - xsize*lar->mat[0][2] + ysize*lar->mat[1][2];
+
+ /* corner vectors */
+ lar->area[2][0]= lar->co[0] + xsize*lar->mat[0][0] + ysize*lar->mat[1][0];
+ lar->area[2][1]= lar->co[1] + xsize*lar->mat[0][1] + ysize*lar->mat[1][1];
+ lar->area[2][2]= lar->co[2] + xsize*lar->mat[0][2] + ysize*lar->mat[1][2];
+
+ /* corner vectors */
+ lar->area[3][0]= lar->co[0] + xsize*lar->mat[0][0] - ysize*lar->mat[1][0];
+ lar->area[3][1]= lar->co[1] + xsize*lar->mat[0][1] - ysize*lar->mat[1][1];
+ lar->area[3][2]= lar->co[2] + xsize*lar->mat[0][2] - ysize*lar->mat[1][2];
+ /* only for correction button size, matrix size works on energy */
+ lar->areasize= lar->dist*lar->dist/(4.0f*xsize*ysize);
+}
+
+/* If lar takes more lamp data, the decoupling will be better. */
+static GroupObject *add_render_lamp(Render *re, Object *ob)
+{
+ Lamp *la= ob->data;
+ LampRen *lar;
+ GroupObject *go;
+ float mat[4][4], angle, xn, yn;
+ float vec[3];
+ int c;
+
+ /* previewrender sets this to zero... prevent accidents */
+ if (la==NULL) return NULL;
+
+ /* prevent only shadow from rendering light */
+ if (la->mode & LA_ONLYSHADOW)
+ if ((re->r.mode & R_SHADOW)==0)
+ return NULL;
+
+ re->totlamp++;
+
+ /* groups is used to unify support for lightgroups, this is the global lightgroup */
+ go= MEM_callocN(sizeof(GroupObject), "groupobject");
+ BLI_addtail(&re->lights, go);
+ go->ob= ob;
+ /* lamprens are in own list, for freeing */
+ lar= (LampRen *)MEM_callocN(sizeof(LampRen), "lampren");
+ BLI_addtail(&re->lampren, lar);
+ go->lampren= lar;
+
+ mul_m4_m4m4(mat, re->viewmat, ob->obmat);
+ invert_m4_m4(ob->imat, mat);
+
+ copy_m4_m4(lar->lampmat, ob->obmat);
+ copy_m3_m4(lar->mat, mat);
+ copy_m3_m4(lar->imat, ob->imat);
+
+ lar->bufsize = la->bufsize;
+ lar->samp = la->samp;
+ lar->buffers= la->buffers;
+ if (lar->buffers==0) lar->buffers= 1;
+ lar->buftype= la->buftype;
+ lar->filtertype= la->filtertype;
+ lar->soft = la->soft;
+ lar->shadhalostep = la->shadhalostep;
+ lar->clipsta = la->clipsta;
+ lar->clipend = la->clipend;
+
+ lar->bias = la->bias;
+ lar->compressthresh = la->compressthresh;
+
+ lar->type= la->type;
+ lar->mode= la->mode;
+
+ lar->energy= la->energy;
+ if (la->mode & LA_NEG) lar->energy= -lar->energy;
+
+ lar->vec[0]= -mat[2][0];
+ lar->vec[1]= -mat[2][1];
+ lar->vec[2]= -mat[2][2];
+ normalize_v3(lar->vec);
+ lar->co[0]= mat[3][0];
+ lar->co[1]= mat[3][1];
+ lar->co[2]= mat[3][2];
+ lar->dist= la->dist;
+ lar->haint= la->haint;
+ lar->distkw= lar->dist*lar->dist;
+ lar->r= lar->energy*la->r;
+ lar->g= lar->energy*la->g;
+ lar->b= lar->energy*la->b;
+ lar->shdwr= la->shdwr;
+ lar->shdwg= la->shdwg;
+ lar->shdwb= la->shdwb;
+ lar->k= la->k;
+
+ /* area */
+ lar->ray_samp= la->ray_samp;
+ lar->ray_sampy= la->ray_sampy;
+ lar->ray_sampz= la->ray_sampz;
+
+ lar->area_size= la->area_size;
+ lar->area_sizey= la->area_sizey;
+ lar->area_sizez= la->area_sizez;
+
+ lar->area_shape= la->area_shape;
+
+ /* Annoying, lamp UI does this, but the UI might not have been used? - add here too.
+ * make sure this matches buttons_shading.c's logic */
+ if (ELEM(la->type, LA_AREA, LA_SPOT, LA_SUN, LA_LOCAL) && (la->mode & LA_SHAD_RAY))
+ if (ELEM(la->type, LA_SPOT, LA_SUN, LA_LOCAL))
+ if (la->ray_samp_method == LA_SAMP_CONSTANT) la->ray_samp_method = LA_SAMP_HALTON;
+
+ lar->ray_samp_method= la->ray_samp_method;
+ lar->ray_samp_type= la->ray_samp_type;
+
+ lar->adapt_thresh= la->adapt_thresh;
+ lar->sunsky = NULL;
+
+ if ( ELEM(lar->type, LA_SPOT, LA_LOCAL)) {
+ lar->ray_totsamp= lar->ray_samp*lar->ray_samp;
+ lar->area_shape = LA_AREA_SQUARE;
+ lar->area_sizey= lar->area_size;
+ }
+ else if (lar->type==LA_AREA) {
+ switch (lar->area_shape) {
+ case LA_AREA_SQUARE:
+ lar->ray_totsamp= lar->ray_samp*lar->ray_samp;
+ lar->ray_sampy= lar->ray_samp;
+ lar->area_sizey= lar->area_size;
+ break;
+ case LA_AREA_RECT:
+ lar->ray_totsamp= lar->ray_samp*lar->ray_sampy;
+ break;
+ case LA_AREA_CUBE:
+ lar->ray_totsamp= lar->ray_samp*lar->ray_samp*lar->ray_samp;
+ lar->ray_sampy= lar->ray_samp;
+ lar->ray_sampz= lar->ray_samp;
+ lar->area_sizey= lar->area_size;
+ lar->area_sizez= lar->area_size;
+ break;
+ case LA_AREA_BOX:
+ lar->ray_totsamp= lar->ray_samp*lar->ray_sampy*lar->ray_sampz;
+ break;
+ }
+
+ area_lamp_vectors(lar);
+ init_jitter_plane(lar); /* subsamples */
+ }
+ else if (lar->type==LA_SUN) {
+ lar->ray_totsamp= lar->ray_samp*lar->ray_samp;
+ lar->area_shape = LA_AREA_SQUARE;
+ lar->area_sizey= lar->area_size;
+
+ if ((la->sun_effect_type & LA_SUN_EFFECT_SKY) ||
+ (la->sun_effect_type & LA_SUN_EFFECT_AP))
+ {
+ lar->sunsky = (struct SunSky*)MEM_callocN(sizeof(struct SunSky), "sunskyren");
+ lar->sunsky->effect_type = la->sun_effect_type;
+
+ copy_v3_v3(vec, ob->obmat[2]);
+ normalize_v3(vec);
+
+ InitSunSky(
+ lar->sunsky, la->atm_turbidity, vec, la->horizon_brightness,
+ la->spread, la->sun_brightness, la->sun_size, la->backscattered_light,
+ la->skyblendfac, la->skyblendtype, la->sky_exposure, la->sky_colorspace);
+ InitAtmosphere(
+ lar->sunsky, la->sun_intensity, 1.0, 1.0, la->atm_inscattering_factor, la->atm_extinction_factor,
+ la->atm_distance_factor);
+ }
+ }
+ else lar->ray_totsamp= 0;
+
+ lar->spotsi= la->spotsize;
+ if (lar->mode & LA_HALO) {
+ if (lar->spotsi > DEG2RADF(170.0f)) lar->spotsi = DEG2RADF(170.0f);
+ }
+ lar->spotsi= cosf(lar->spotsi * 0.5f);
+ lar->spotbl= (1.0f-lar->spotsi)*la->spotblend;
+
+ memcpy(lar->mtex, la->mtex, MAX_MTEX*sizeof(void *));
+
+ lar->lay = ob->lay & 0xFFFFFF; /* higher 8 bits are localview layers */
+
+ lar->falloff_type = la->falloff_type;
+ lar->ld1= la->att1;
+ lar->ld2= la->att2;
+ lar->coeff_const= la->coeff_const;
+ lar->coeff_lin= la->coeff_lin;
+ lar->coeff_quad= la->coeff_quad;
+ lar->curfalloff = curvemapping_copy(la->curfalloff);
+
+ if (lar->curfalloff) {
+ /* so threads don't conflict on init */
+ curvemapping_initialize(lar->curfalloff);
+ }
+
+ if (lar->type==LA_SPOT) {
+
+ normalize_v3(lar->imat[0]);
+ normalize_v3(lar->imat[1]);
+ normalize_v3(lar->imat[2]);
+
+ xn = saacos(lar->spotsi);
+ xn = sinf(xn) / cosf(xn);
+ lar->spottexfac= 1.0f/(xn);
+
+ if (lar->mode & LA_ONLYSHADOW) {
+ if ((lar->mode & (LA_SHAD_BUF|LA_SHAD_RAY))==0) lar->mode -= LA_ONLYSHADOW;
+ }
+
+ }
+
+ /* set flag for spothalo en initvars */
+ if ((la->type == LA_SPOT) && (la->mode & LA_HALO) &&
+ (!(la->mode & LA_SHAD_BUF) || la->buftype != LA_SHADBUF_DEEP))
+ {
+ if (la->haint>0.0f) {
+ re->flag |= R_LAMPHALO;
+
+ /* camera position (0, 0, 0) rotate around lamp */
+ lar->sh_invcampos[0]= -lar->co[0];
+ lar->sh_invcampos[1]= -lar->co[1];
+ lar->sh_invcampos[2]= -lar->co[2];
+ mul_m3_v3(lar->imat, lar->sh_invcampos);
+
+ /* z factor, for a normalized volume */
+ angle= saacos(lar->spotsi);
+ xn= lar->spotsi;
+ yn = sinf(angle);
+ lar->sh_zfac= yn/xn;
+ /* pre-scale */
+ lar->sh_invcampos[2]*= lar->sh_zfac;
+
+ /* halfway shadow buffer doesn't work for volumetric effects */
+ if (ELEM(lar->buftype, LA_SHADBUF_HALFWAY, LA_SHADBUF_DEEP))
+ lar->buftype = LA_SHADBUF_REGULAR;
+
+ }
+ }
+ else if (la->type==LA_HEMI) {
+ lar->mode &= ~(LA_SHAD_RAY|LA_SHAD_BUF);
+ }
+
+ for (c=0; c<MAX_MTEX; c++) {
+ if (la->mtex[c] && la->mtex[c]->tex) {
+ if (la->mtex[c]->mapto & LAMAP_COL)
+ lar->mode |= LA_TEXTURE;
+ if (la->mtex[c]->mapto & LAMAP_SHAD)
+ lar->mode |= LA_SHAD_TEX;
+
+ if (G.is_rendering) {
+ if (re->osa) {
+ if (la->mtex[c]->tex->type==TEX_IMAGE) lar->mode |= LA_OSATEX;
+ }
+ }
+ }
+ }
+
+ /* old code checked for internal render (aka not yafray) */
+ {
+ /* to make sure we can check ray shadow easily in the render code */
+ if (lar->mode & LA_SHAD_RAY) {
+ if ( (re->r.mode & R_RAYTRACE)==0)
+ lar->mode &= ~LA_SHAD_RAY;
+ }
+
+
+ if (re->r.mode & R_SHADOW) {
+
+ if (la->type==LA_AREA && (lar->mode & LA_SHAD_RAY) && (lar->ray_samp_method == LA_SAMP_CONSTANT)) {
+ init_jitter_plane(lar);
+ }
+ else if (la->type==LA_SPOT && (lar->mode & LA_SHAD_BUF) ) {
+ /* Per lamp, one shadow buffer is made. */
+ lar->bufflag= la->bufflag;
+ copy_m4_m4(mat, ob->obmat);
+ initshadowbuf(re, lar, mat); /* mat is altered */
+ }
+
+
+ /* this is the way used all over to check for shadow */
+ if (lar->shb || (lar->mode & LA_SHAD_RAY)) {
+ LampShadowSample *ls;
+ LampShadowSubSample *lss;
+ int a, b;
+
+ memset(re->shadowsamplenr, 0, sizeof(re->shadowsamplenr));
+
+ lar->shadsamp= MEM_mallocN(re->r.threads*sizeof(LampShadowSample), "lamp shadow sample");
+ ls= lar->shadsamp;
+
+ /* shadfacs actually mean light, let's put them to 1 to prevent unitialized accidents */
+ for (a=0; a<re->r.threads; a++, ls++) {
+ lss= ls->s;
+ for (b=0; b<re->r.osa; b++, lss++) {
+ lss->samplenr= -1; /* used to detect whether we store or read */
+ lss->shadfac[0]= 1.0f;
+ lss->shadfac[1]= 1.0f;
+ lss->shadfac[2]= 1.0f;
+ lss->shadfac[3]= 1.0f;
+ }
+ }
+ }
+ }
+ }
+
+ return go;
+}
+
+static bool is_object_restricted(Render *re, Object *ob)
+{
+ if (re->r.scemode & R_VIEWPORT_PREVIEW)
+ return (ob->restrictflag & OB_RESTRICT_VIEW) != 0;
+ else
+ return (ob->restrictflag & OB_RESTRICT_RENDER) != 0;
+}
+
+static bool is_object_hidden(Render *re, Object *ob)
+{
+ if (is_object_restricted(re, ob))
+ return true;
+
+ if (re->r.scemode & R_VIEWPORT_PREVIEW) {
+ /* Mesh deform cages and so on mess up the preview. To avoid the problem,
+ * viewport doesn't show mesh object if its draw type is bounding box or wireframe.
+ * Unless it's an active smoke domain!
+ */
+ ModifierData *md = NULL;
+
+ if ((md = modifiers_findByType(ob, eModifierType_Smoke)) &&
+ (modifier_isEnabled(re->scene, md, eModifierMode_Realtime)))
+ {
+ return false;
+ }
+ return ELEM(ob->dt, OB_BOUNDBOX, OB_WIRE);
+ }
+ else {
+ return false;
+ }
+}
+
+/* layflag: allows material group to ignore layerflag */
+static void add_lightgroup(Render *re, Group *group, int exclusive)
+{
+ GroupObject *go, *gol;
+
+ group->id.tag &= ~LIB_TAG_DOIT;
+
+ /* it's a bit too many loops in loops... but will survive */
+ /* note that 'exclusive' will remove it from the global list */
+ for (go= group->gobject.first; go; go= go->next) {
+ go->lampren= NULL;
+
+ if (is_object_hidden(re, go->ob))
+ continue;
+
+ if (go->ob->lay & re->lay) {
+ if (go->ob && go->ob->type==OB_LAMP) {
+ for (gol= re->lights.first; gol; gol= gol->next) {
+ if (gol->ob==go->ob) {
+ go->lampren= gol->lampren;
+ break;
+ }
+ }
+ if (go->lampren==NULL)
+ gol= add_render_lamp(re, go->ob);
+ if (gol && exclusive) {
+ BLI_remlink(&re->lights, gol);
+ MEM_freeN(gol);
+ }
+ }
+ }
+ }
+}
+
+static void set_material_lightgroups(Render *re)
+{
+ Group *group;
+ Material *ma;
+
+ /* not for preview render */
+ if (re->scene->r.scemode & (R_BUTS_PREVIEW|R_VIEWPORT_PREVIEW))
+ return;
+
+ for (group= re->main->group.first; group; group=group->id.next)
+ group->id.tag |= LIB_TAG_DOIT;
+
+ /* it's a bit too many loops in loops... but will survive */
+ /* hola! materials not in use...? */
+ for (ma= re->main->mat.first; ma; ma=ma->id.next) {
+ if (ma->group && (ma->group->id.tag & LIB_TAG_DOIT))
+ add_lightgroup(re, ma->group, ma->mode & MA_GROUP_NOLAY);
+ }
+}
+
+static void set_renderlayer_lightgroups(Render *re, Scene *sce)
+{
+ SceneRenderLayer *srl;
+
+ for (srl= sce->r.layers.first; srl; srl= srl->next) {
+ if (srl->light_override)
+ add_lightgroup(re, srl->light_override, 0);
+ }
+}
+
+/* ------------------------------------------------------------------------- */
+/* World */
+/* ------------------------------------------------------------------------- */
+
+void init_render_world(Render *re)
+{
+ void *wrld_prev[2] = {
+ re->wrld.aotables,
+ re->wrld.aosphere,
+ };
+
+ int a;
+
+ if (re->scene && re->scene->world) {
+ re->wrld = *(re->scene->world);
+
+ copy_v3_v3(re->grvec, re->viewmat[2]);
+ normalize_v3(re->grvec);
+ copy_m3_m4(re->imat, re->viewinv);
+
+ for (a=0; a<MAX_MTEX; a++)
+ if (re->wrld.mtex[a] && re->wrld.mtex[a]->tex) re->wrld.skytype |= WO_SKYTEX;
+
+ /* AO samples should be OSA minimum */
+ if (re->osa)
+ while (re->wrld.aosamp*re->wrld.aosamp < re->osa)
+ re->wrld.aosamp++;
+ if (!(re->r.mode & R_RAYTRACE) && (re->wrld.ao_gather_method == WO_AOGATHER_RAYTRACE))
+ re->wrld.mode &= ~(WO_AMB_OCC|WO_ENV_LIGHT|WO_INDIRECT_LIGHT);
+ }
+ else {
+ memset(&re->wrld, 0, sizeof(World));
+ re->wrld.exp= 0.0f;
+ re->wrld.range= 1.0f;
+
+ /* for mist pass */
+ re->wrld.miststa= re->clipsta;
+ re->wrld.mistdist= re->clipend-re->clipsta;
+ re->wrld.misi= 1.0f;
+ }
+
+ re->wrld.linfac= 1.0f + powf((2.0f*re->wrld.exp + 0.5f), -10);
+ re->wrld.logfac= logf((re->wrld.linfac-1.0f)/re->wrld.linfac) / re->wrld.range;
+
+ /* restore runtime vars, needed for viewport rendering [#36005] */
+ re->wrld.aotables = wrld_prev[0];
+ re->wrld.aosphere = wrld_prev[1];
+}
+
+
+
+/* ------------------------------------------------------------------------- */
+/* Object Finalization */
+/* ------------------------------------------------------------------------- */
+
+/* prevent phong interpolation for giving ray shadow errors (terminator problem) */
+static void set_phong_threshold(ObjectRen *obr)
+{
+// VertRen *ver;
+ VlakRen *vlr;
+ float thresh= 0.0, dot;
+ int tot=0, i;
+
+ /* Added check for 'pointy' situations, only dotproducts of 0.9 and larger
+ * are taken into account. This threshold is meant to work on smooth geometry, not
+ * for extreme cases (ton) */
+
+ for (i=0; i<obr->totvlak; i++) {
+ vlr= RE_findOrAddVlak(obr, i);
+ if ((vlr->flag & R_SMOOTH) && (vlr->flag & R_STRAND)==0) {
+ dot= dot_v3v3(vlr->n, vlr->v1->n);
+ dot= ABS(dot);
+ if (dot>0.9f) {
+ thresh+= dot; tot++;
+ }
+ dot= dot_v3v3(vlr->n, vlr->v2->n);
+ dot= ABS(dot);
+ if (dot>0.9f) {
+ thresh+= dot; tot++;
+ }
+
+ dot= dot_v3v3(vlr->n, vlr->v3->n);
+ dot= ABS(dot);
+ if (dot>0.9f) {
+ thresh+= dot; tot++;
+ }
+
+ if (vlr->v4) {
+ dot= dot_v3v3(vlr->n, vlr->v4->n);
+ dot= ABS(dot);
+ if (dot>0.9f) {
+ thresh+= dot; tot++;
+ }
+ }
+ }
+ }
+
+ if (tot) {
+ thresh/= (float)tot;
+ obr->ob->smoothresh= cosf(0.5f*(float)M_PI-saacos(thresh));
+ }
+}
+
+/* per face check if all samples should be taken.
+ * if raytrace or multisample, do always for raytraced material, or when material full_osa set */
+static void set_fullsample_trace_flag(Render *re, ObjectRen *obr)
+{
+ VlakRen *vlr;
+ int a, trace, mode, osa;
+
+ osa= re->osa;
+ trace= re->r.mode & R_RAYTRACE;
+
+ for (a=obr->totvlak-1; a>=0; a--) {
+ vlr= RE_findOrAddVlak(obr, a);
+ mode= vlr->mat->mode;
+
+ if (trace && (mode & MA_TRACEBLE))
+ vlr->flag |= R_TRACEBLE;
+
+ if (osa) {
+ if (mode & MA_FULL_OSA) {
+ vlr->flag |= R_FULL_OSA;
+ }
+ else if (trace) {
+ if (mode & MA_SHLESS) {
+ /* pass */
+ }
+ else if (vlr->mat->material_type == MA_TYPE_VOLUME) {
+ /* pass */
+ }
+ else if ((mode & MA_RAYMIRROR) || ((mode & MA_TRANSP) && (mode & MA_RAYTRANSP))) {
+ /* for blurry reflect/refract, better to take more samples
+ * inside the raytrace than as OSA samples */
+ if ((vlr->mat->gloss_mir == 1.0f) && (vlr->mat->gloss_tra == 1.0f))
+ vlr->flag |= R_FULL_OSA;
+ }
+ }
+ }
+ }
+}
+
+/* split quads for predictable baking
+ * dir 1 == (0, 1, 2) (0, 2, 3), 2 == (1, 3, 0) (1, 2, 3)
+ */
+static void split_quads(ObjectRen *obr, int dir)
+{
+ VlakRen *vlr, *vlr1;
+ int a;
+
+ for (a=obr->totvlak-1; a>=0; a--) {
+ vlr= RE_findOrAddVlak(obr, a);
+
+ /* test if rendering as a quad or triangle, skip wire */
+ if ((vlr->flag & R_STRAND)==0 && (vlr->mat->material_type != MA_TYPE_WIRE)) {
+
+ if (vlr->v4) {
+
+ vlr1= RE_vlakren_copy(obr, vlr);
+ vlr1->flag |= R_FACE_SPLIT;
+
+ if ( dir==2 ) vlr->flag |= R_DIVIDE_24;
+ else vlr->flag &= ~R_DIVIDE_24;
+
+ /* new vertex pointers */
+ if (vlr->flag & R_DIVIDE_24) {
+ vlr1->v1= vlr->v2;
+ vlr1->v2= vlr->v3;
+ vlr1->v3= vlr->v4;
+
+ vlr->v3 = vlr->v4;
+
+ vlr1->flag |= R_DIVIDE_24;
+ }
+ else {
+ vlr1->v1= vlr->v1;
+ vlr1->v2= vlr->v3;
+ vlr1->v3= vlr->v4;
+
+ vlr1->flag &= ~R_DIVIDE_24;
+ }
+ vlr->v4 = vlr1->v4 = NULL;
+
+#ifdef WITH_FREESTYLE
+ /* Freestyle edge marks */
+ if (vlr->flag & R_DIVIDE_24) {
+ vlr1->freestyle_edge_mark=
+ ((vlr->freestyle_edge_mark & R_EDGE_V2V3) ? R_EDGE_V1V2 : 0) |
+ ((vlr->freestyle_edge_mark & R_EDGE_V3V4) ? R_EDGE_V2V3 : 0);
+ vlr->freestyle_edge_mark=
+ ((vlr->freestyle_edge_mark & R_EDGE_V1V2) ? R_EDGE_V1V2 : 0) |
+ ((vlr->freestyle_edge_mark & R_EDGE_V4V1) ? R_EDGE_V3V1 : 0);
+ }
+ else {
+ vlr1->freestyle_edge_mark=
+ ((vlr->freestyle_edge_mark & R_EDGE_V3V4) ? R_EDGE_V2V3 : 0) |
+ ((vlr->freestyle_edge_mark & R_EDGE_V4V1) ? R_EDGE_V3V1 : 0);
+ vlr->freestyle_edge_mark=
+ ((vlr->freestyle_edge_mark & R_EDGE_V1V2) ? R_EDGE_V1V2 : 0) |
+ ((vlr->freestyle_edge_mark & R_EDGE_V2V3) ? R_EDGE_V2V3 : 0);
+ }
+#endif
+
+ /* new normals */
+ normal_tri_v3(vlr->n, vlr->v3->co, vlr->v2->co, vlr->v1->co);
+ normal_tri_v3(vlr1->n, vlr1->v3->co, vlr1->v2->co, vlr1->v1->co);
+ }
+ /* clear the flag when not divided */
+ else vlr->flag &= ~R_DIVIDE_24;
+ }
+ }
+}
+
+static void check_non_flat_quads(ObjectRen *obr)
+{
+ VlakRen *vlr, *vlr1;
+ VertRen *v1, *v2, *v3, *v4;
+ float nor[3], xn, flen;
+ int a;
+
+ for (a=obr->totvlak-1; a>=0; a--) {
+ vlr= RE_findOrAddVlak(obr, a);
+
+ /* test if rendering as a quad or triangle, skip wire */
+ if (vlr->v4 && (vlr->flag & R_STRAND)==0 && (vlr->mat->material_type != MA_TYPE_WIRE)) {
+
+ /* check if quad is actually triangle */
+ v1= vlr->v1;
+ v2= vlr->v2;
+ v3= vlr->v3;
+ v4= vlr->v4;
+ sub_v3_v3v3(nor, v1->co, v2->co);
+ if ( ABS(nor[0])<FLT_EPSILON10 && ABS(nor[1])<FLT_EPSILON10 && ABS(nor[2])<FLT_EPSILON10 ) {
+ vlr->v1= v2;
+ vlr->v2= v3;
+ vlr->v3= v4;
+ vlr->v4= NULL;
+ vlr->flag |= (R_DIVIDE_24 | R_FACE_SPLIT);
+ }
+ else {
+ sub_v3_v3v3(nor, v2->co, v3->co);
+ if ( ABS(nor[0])<FLT_EPSILON10 && ABS(nor[1])<FLT_EPSILON10 && ABS(nor[2])<FLT_EPSILON10 ) {
+ vlr->v2= v3;
+ vlr->v3= v4;
+ vlr->v4= NULL;
+ vlr->flag |= R_FACE_SPLIT;
+ }
+ else {
+ sub_v3_v3v3(nor, v3->co, v4->co);
+ if ( ABS(nor[0])<FLT_EPSILON10 && ABS(nor[1])<FLT_EPSILON10 && ABS(nor[2])<FLT_EPSILON10 ) {
+ vlr->v4= NULL;
+ }
+ else {
+ sub_v3_v3v3(nor, v4->co, v1->co);
+ if ( ABS(nor[0])<FLT_EPSILON10 && ABS(nor[1])<FLT_EPSILON10 && ABS(nor[2])<FLT_EPSILON10 ) {
+ vlr->v4= NULL;
+ }
+ }
+ }
+ }
+
+ if (vlr->v4) {
+
+ /* Face is divided along edge with the least gradient */
+ /* Flagged with R_DIVIDE_24 if divide is from vert 2 to 4 */
+ /* 4---3 4---3 */
+ /* |\ 1| or |1 /| */
+ /* |0\ | |/ 0| */
+ /* 1---2 1---2 0 = orig face, 1 = new face */
+
+ /* render normals are inverted in render! we calculate normal of single tria here */
+ flen= normal_tri_v3(nor, vlr->v4->co, vlr->v3->co, vlr->v1->co);
+ if (flen==0.0f) normal_tri_v3(nor, vlr->v4->co, vlr->v2->co, vlr->v1->co);
+
+ xn = dot_v3v3(nor, vlr->n);
+
+ if (ABS(xn) < 0.999995f ) { /* checked on noisy fractal grid */
+
+ float d1, d2;
+
+ vlr1= RE_vlakren_copy(obr, vlr);
+ vlr1->flag |= R_FACE_SPLIT;
+
+ /* split direction based on vnorms */
+ normal_tri_v3(nor, vlr->v1->co, vlr->v2->co, vlr->v3->co);
+ d1 = dot_v3v3(nor, vlr->v1->n);
+
+ normal_tri_v3(nor, vlr->v2->co, vlr->v3->co, vlr->v4->co);
+ d2 = dot_v3v3(nor, vlr->v2->n);
+
+ if (fabsf(d1) < fabsf(d2) ) vlr->flag |= R_DIVIDE_24;
+ else vlr->flag &= ~R_DIVIDE_24;
+
+ /* new vertex pointers */
+ if (vlr->flag & R_DIVIDE_24) {
+ vlr1->v1= vlr->v2;
+ vlr1->v2= vlr->v3;
+ vlr1->v3= vlr->v4;
+
+ vlr->v3 = vlr->v4;
+
+ vlr1->flag |= R_DIVIDE_24;
+ }
+ else {
+ vlr1->v1= vlr->v1;
+ vlr1->v2= vlr->v3;
+ vlr1->v3= vlr->v4;
+
+ vlr1->flag &= ~R_DIVIDE_24;
+ }
+ vlr->v4 = vlr1->v4 = NULL;
+
+ /* new normals */
+ normal_tri_v3(vlr->n, vlr->v3->co, vlr->v2->co, vlr->v1->co);
+ normal_tri_v3(vlr1->n, vlr1->v3->co, vlr1->v2->co, vlr1->v1->co);
+
+#ifdef WITH_FREESTYLE
+ /* Freestyle edge marks */
+ if (vlr->flag & R_DIVIDE_24) {
+ vlr1->freestyle_edge_mark=
+ ((vlr->freestyle_edge_mark & R_EDGE_V2V3) ? R_EDGE_V1V2 : 0) |
+ ((vlr->freestyle_edge_mark & R_EDGE_V3V4) ? R_EDGE_V2V3 : 0);
+ vlr->freestyle_edge_mark=
+ ((vlr->freestyle_edge_mark & R_EDGE_V1V2) ? R_EDGE_V1V2 : 0) |
+ ((vlr->freestyle_edge_mark & R_EDGE_V4V1) ? R_EDGE_V3V1 : 0);
+ }
+ else {
+ vlr1->freestyle_edge_mark=
+ ((vlr->freestyle_edge_mark & R_EDGE_V3V4) ? R_EDGE_V2V3 : 0) |
+ ((vlr->freestyle_edge_mark & R_EDGE_V4V1) ? R_EDGE_V3V1 : 0);
+ vlr->freestyle_edge_mark=
+ ((vlr->freestyle_edge_mark & R_EDGE_V1V2) ? R_EDGE_V1V2 : 0) |
+ ((vlr->freestyle_edge_mark & R_EDGE_V2V3) ? R_EDGE_V2V3 : 0);
+ }
+#endif
+ }
+ /* clear the flag when not divided */
+ else vlr->flag &= ~R_DIVIDE_24;
+ }
+ }
+ }
+}
+
+static void finalize_render_object(Render *re, ObjectRen *obr, int timeoffset)
+{
+ Object *ob= obr->ob;
+ VertRen *ver= NULL;
+ StrandRen *strand= NULL;
+ StrandBound *sbound= NULL;
+ float min[3], max[3], smin[3], smax[3];
+ int a, b;
+
+ if (obr->totvert || obr->totvlak || obr->tothalo || obr->totstrand) {
+ /* the exception below is because displace code now is in init_render_mesh call,
+ * I will look at means to have autosmooth enabled for all object types
+ * and have it as general postprocess, like displace */
+ if (ob->type!=OB_MESH && test_for_displace(re, ob))
+ displace(re, obr);
+
+ if (!timeoffset) {
+ /* phong normal interpolation can cause error in tracing
+ * (terminator problem) */
+ ob->smoothresh= 0.0;
+ if ((re->r.mode & R_RAYTRACE) && (re->r.mode & R_SHADOW))
+ set_phong_threshold(obr);
+
+ if (re->flag & R_BAKING && re->r.bake_quad_split != 0) {
+ /* Baking lets us define a quad split order */
+ split_quads(obr, re->r.bake_quad_split);
+ }
+ else if (BKE_object_is_animated(re->scene, ob))
+ split_quads(obr, 1);
+ else {
+ if ((re->r.mode & R_SIMPLIFY && re->r.simplify_flag & R_SIMPLE_NO_TRIANGULATE) == 0)
+ check_non_flat_quads(obr);
+ }
+
+ set_fullsample_trace_flag(re, obr);
+
+ /* compute bounding boxes for clipping */
+ INIT_MINMAX(min, max);
+ for (a=0; a<obr->totvert; a++) {
+ if ((a & 255)==0) ver= obr->vertnodes[a>>8].vert;
+ else ver++;
+
+ minmax_v3v3_v3(min, max, ver->co);
+ }
+
+ if (obr->strandbuf) {
+ float width;
+
+ /* compute average bounding box of strandpoint itself (width) */
+ if (obr->strandbuf->flag & R_STRAND_B_UNITS)
+ obr->strandbuf->maxwidth = max_ff(obr->strandbuf->ma->strand_sta, obr->strandbuf->ma->strand_end);
+ else
+ obr->strandbuf->maxwidth= 0.0f;
+
+ width= obr->strandbuf->maxwidth;
+ sbound= obr->strandbuf->bound;
+ for (b=0; b<obr->strandbuf->totbound; b++, sbound++) {
+
+ INIT_MINMAX(smin, smax);
+
+ for (a=sbound->start; a<sbound->end; a++) {
+ strand= RE_findOrAddStrand(obr, a);
+ strand_minmax(strand, smin, smax, width);
+ }
+
+ copy_v3_v3(sbound->boundbox[0], smin);
+ copy_v3_v3(sbound->boundbox[1], smax);
+
+ minmax_v3v3_v3(min, max, smin);
+ minmax_v3v3_v3(min, max, smax);
+ }
+ }
+
+ copy_v3_v3(obr->boundbox[0], min);
+ copy_v3_v3(obr->boundbox[1], max);
+ }
+ }
+}
+
+/* ------------------------------------------------------------------------- */
+/* Database */
+/* ------------------------------------------------------------------------- */
+
+static int render_object_type(short type)
+{
+ return OB_TYPE_SUPPORT_MATERIAL(type);
+}
+
+static void find_dupli_instances(Render *re, ObjectRen *obr, DupliObject *dob)
+{
+ ObjectInstanceRen *obi;
+ float imat[4][4], obmat[4][4], obimat[4][4], nmat[3][3];
+ int first = 1;
+
+ mul_m4_m4m4(obmat, re->viewmat, obr->obmat);
+ invert_m4_m4(imat, obmat);
+
+ /* for objects instanced by dupliverts/faces/particles, we go over the
+ * list of instances to find ones that instance obr, and setup their
+ * matrices and obr pointer */
+ for (obi=re->instancetable.last; obi; obi=obi->prev) {
+ if (!obi->obr && obi->ob == obr->ob && obi->psysindex == obr->psysindex) {
+ obi->obr= obr;
+
+ /* compute difference between object matrix and
+ * object matrix with dupli transform, in viewspace */
+ copy_m4_m4(obimat, obi->mat);
+ mul_m4_m4m4(obi->mat, obimat, imat);
+
+ copy_m3_m4(nmat, obi->mat);
+ invert_m3_m3(obi->nmat, nmat);
+ transpose_m3(obi->nmat);
+
+ if (dob) {
+ copy_v3_v3(obi->dupliorco, dob->orco);
+ obi->dupliuv[0]= dob->uv[0];
+ obi->dupliuv[1]= dob->uv[1];
+ }
+
+ if (!first) {
+ re->totvert += obr->totvert;
+ re->totvlak += obr->totvlak;
+ re->tothalo += obr->tothalo;
+ re->totstrand += obr->totstrand;
+ }
+ else
+ first= 0;
+ }
+ }
+}
+
+static void assign_dupligroup_dupli(Render *re, ObjectInstanceRen *obi, ObjectRen *obr, DupliObject *dob)
+{
+ float imat[4][4], obmat[4][4], obimat[4][4], nmat[3][3];
+
+ mul_m4_m4m4(obmat, re->viewmat, obr->obmat);
+ invert_m4_m4(imat, obmat);
+
+ obi->obr= obr;
+
+ /* compute difference between object matrix and
+ * object matrix with dupli transform, in viewspace */
+ copy_m4_m4(obimat, obi->mat);
+ mul_m4_m4m4(obi->mat, obimat, imat);
+
+ copy_m3_m4(nmat, obi->mat);
+ invert_m3_m3(obi->nmat, nmat);
+ transpose_m3(obi->nmat);
+
+ if (dob) {
+ copy_v3_v3(obi->dupliorco, dob->orco);
+ obi->dupliuv[0]= dob->uv[0];
+ obi->dupliuv[1]= dob->uv[1];
+ }
+
+ re->totvert += obr->totvert;
+ re->totvlak += obr->totvlak;
+ re->tothalo += obr->tothalo;
+ re->totstrand += obr->totstrand;
+}
+
+static ObjectRen *find_dupligroup_dupli(Render *re, Object *ob, int psysindex)
+{
+ ObjectRen *obr;
+
+ /* if the object is itself instanced, we don't want to create an instance
+ * for it */
+ if (ob->transflag & OB_RENDER_DUPLI)
+ return NULL;
+
+ /* try to find an object that was already created so we can reuse it
+ * and save memory */
+ for (obr=re->objecttable.first; obr; obr=obr->next)
+ if (obr->ob == ob && obr->psysindex == psysindex && (obr->flag & R_INSTANCEABLE))
+ return obr;
+
+ return NULL;
+}
+
+static void set_dupli_tex_mat(Render *re, ObjectInstanceRen *obi, DupliObject *dob, float omat[4][4])
+{
+ /* For duplis we need to have a matrix that transform the coordinate back
+ * to it's original position, without the dupli transforms. We also check
+ * the matrix is actually needed, to save memory on lots of dupliverts for
+ * example */
+ static Object *lastob= NULL;
+ static int needtexmat= 0;
+
+ /* init */
+ if (!re) {
+ lastob= NULL;
+ needtexmat= 0;
+ return;
+ }
+
+ /* check if we actually need it */
+ if (lastob != dob->ob) {
+ Material ***material;
+ short a, *totmaterial;
+
+ lastob= dob->ob;
+ needtexmat= 0;
+
+ totmaterial= give_totcolp(dob->ob);
+ material= give_matarar(dob->ob);
+
+ if (totmaterial && material)
+ for (a= 0; a<*totmaterial; a++)
+ if ((*material)[a] && (*material)[a]->texco & TEXCO_OBJECT)
+ needtexmat= 1;
+ }
+
+ if (needtexmat) {
+ float imat[4][4];
+
+ obi->duplitexmat= BLI_memarena_alloc(re->memArena, sizeof(float)*4*4);
+ invert_m4_m4(imat, dob->mat);
+ mul_m4_series(obi->duplitexmat, re->viewmat, omat, imat, re->viewinv);
+ }
+
+ copy_v3_v3(obi->dupliorco, dob->orco);
+ copy_v2_v2(obi->dupliuv, dob->uv);
+}
+
+static void init_render_object_data(Render *re, ObjectRen *obr, int timeoffset)
+{
+ Object *ob= obr->ob;
+ ParticleSystem *psys;
+ int i;
+
+ if (obr->psysindex) {
+ if ((!obr->prev || obr->prev->ob != ob || (obr->prev->flag & R_INSTANCEABLE)==0) && ob->type==OB_MESH) {
+ /* the emitter mesh wasn't rendered so the modifier stack wasn't
+ * evaluated with render settings */
+ DerivedMesh *dm;
+ const CustomDataMask mask = CD_MASK_RENDER_INTERNAL;
+
+ if (re->r.scemode & R_VIEWPORT_PREVIEW)
+ dm = mesh_create_derived_view(re->scene, ob, mask);
+ else
+ dm = mesh_create_derived_render(re->scene, ob, mask);
+ dm->release(dm);
+ }
+
+ for (psys=ob->particlesystem.first, i=0; i<obr->psysindex-1; i++)
+ psys= psys->next;
+
+ render_new_particle_system(re, obr, psys, timeoffset);
+ }
+ else {
+ if (ELEM(ob->type, OB_FONT, OB_CURVE))
+ init_render_curve(re, obr, timeoffset);
+ else if (ob->type==OB_SURF)
+ init_render_surf(re, obr, timeoffset);
+ else if (ob->type==OB_MESH)
+ init_render_mesh(re, obr, timeoffset);
+ else if (ob->type==OB_MBALL)
+ init_render_mball(re, obr);
+ }
+
+ finalize_render_object(re, obr, timeoffset);
+
+ re->totvert += obr->totvert;
+ re->totvlak += obr->totvlak;
+ re->tothalo += obr->tothalo;
+ re->totstrand += obr->totstrand;
+}
+
+static void add_render_object(Render *re, Object *ob, Object *par, DupliObject *dob, float omat[4][4], int timeoffset)
+{
+ ObjectRen *obr;
+ ObjectInstanceRen *obi;
+ ParticleSystem *psys;
+ int show_emitter, allow_render= 1, index, psysindex, i;
+
+ index= (dob)? dob->persistent_id[0]: 0;
+
+ /* It seems that we may generate psys->renderdata recursively in some nasty intricated cases of
+ * several levels of bupliobject (see T51524).
+ * For now, basic rule is, do not restore psys if it was already in 'render state'.
+ * Another, more robust solution could be to add some reference counting to that renderdata... */
+ bool psys_has_renderdata = false;
+
+ /* the emitter has to be processed first (render levels of modifiers) */
+ /* so here we only check if the emitter should be rendered */
+ if (ob->particlesystem.first) {
+ show_emitter= 0;
+ for (psys=ob->particlesystem.first; psys; psys=psys->next) {
+ show_emitter += psys->part->draw & PART_DRAW_EMITTER;
+ if (!(re->r.scemode & R_VIEWPORT_PREVIEW)) {
+ psys_has_renderdata |= (psys->renderdata != NULL);
+ psys_render_set(ob, psys, re->viewmat, re->winmat, re->winx, re->winy, timeoffset);
+ }
+ }
+
+ /* if no psys has "show emitter" selected don't render emitter */
+ if (show_emitter == 0)
+ allow_render= 0;
+ }
+
+ /* one render object for the data itself */
+ if (allow_render) {
+ obr= RE_addRenderObject(re, ob, par, index, 0, ob->lay);
+ if ((dob && !dob->animated) || (ob->transflag & OB_RENDER_DUPLI)) {
+ obr->flag |= R_INSTANCEABLE;
+ copy_m4_m4(obr->obmat, ob->obmat);
+ }
+ init_render_object_data(re, obr, timeoffset);
+
+ /* only add instance for objects that have not been used for dupli */
+ if (!(ob->transflag & OB_RENDER_DUPLI)) {
+ obi = RE_addRenderInstance(re, obr, ob, par, index, 0, NULL, ob->lay, dob);
+ if (dob) set_dupli_tex_mat(re, obi, dob, omat);
+ }
+ else
+ find_dupli_instances(re, obr, dob);
+
+ for (i=1; i<=ob->totcol; i++) {
+ Material* ma = give_render_material(re, ob, i);
+ if (ma && ma->material_type == MA_TYPE_VOLUME)
+ add_volume(re, obr, ma);
+ }
+ }
+
+ /* and one render object per particle system */
+ if (ob->particlesystem.first) {
+ psysindex= 1;
+ for (psys=ob->particlesystem.first; psys; psys=psys->next, psysindex++) {
+ if (!psys_check_enabled(ob, psys, G.is_rendering))
+ continue;
+
+ obr= RE_addRenderObject(re, ob, par, index, psysindex, ob->lay);
+ if ((dob && !dob->animated) || (ob->transflag & OB_RENDER_DUPLI)) {
+ obr->flag |= R_INSTANCEABLE;
+ copy_m4_m4(obr->obmat, ob->obmat);
+ }
+ if (dob)
+ psys->flag |= PSYS_USE_IMAT;
+ init_render_object_data(re, obr, timeoffset);
+ if (!(re->r.scemode & R_VIEWPORT_PREVIEW) && !psys_has_renderdata) {
+ psys_render_restore(ob, psys);
+ }
+ psys->flag &= ~PSYS_USE_IMAT;
+
+ /* only add instance for objects that have not been used for dupli */
+ if (!(ob->transflag & OB_RENDER_DUPLI)) {
+ obi = RE_addRenderInstance(re, obr, ob, par, index, psysindex, NULL, ob->lay, dob);
+ if (dob) set_dupli_tex_mat(re, obi, dob, omat);
+ }
+ else
+ find_dupli_instances(re, obr, dob);
+ }
+ }
+}
+
+/* par = pointer to duplicator parent, needed for object lookup table */
+/* index = when duplicater copies same object (particle), the counter */
+static void init_render_object(Render *re, Object *ob, Object *par, DupliObject *dob, float omat[4][4], int timeoffset)
+{
+ static double lasttime= 0.0;
+ double time;
+ float mat[4][4];
+
+ if (ob->type==OB_LAMP)
+ add_render_lamp(re, ob);
+ else if (render_object_type(ob->type))
+ add_render_object(re, ob, par, dob, omat, timeoffset);
+ else {
+ mul_m4_m4m4(mat, re->viewmat, ob->obmat);
+ invert_m4_m4(ob->imat, mat);
+ }
+
+ time= PIL_check_seconds_timer();
+ if (time - lasttime > 1.0) {
+ lasttime= time;
+ /* clumsy copying still */
+ re->i.totvert= re->totvert;
+ re->i.totface= re->totvlak;
+ re->i.totstrand= re->totstrand;
+ re->i.tothalo= re->tothalo;
+ re->i.totlamp= re->totlamp;
+ re->stats_draw(re->sdh, &re->i);
+ }
+
+ ob->flag |= OB_DONE;
+}
+
+void RE_Database_Free(Render *re)
+{
+ LampRen *lar;
+
+ /* will crash if we try to free empty database */
+ if (!re->i.convertdone)
+ return;
+
+ /* statistics for debugging render memory usage */
+ if ((G.debug & G_DEBUG) && (G.is_rendering)) {
+ if ((re->r.scemode & (R_BUTS_PREVIEW|R_VIEWPORT_PREVIEW))==0) {
+ BKE_image_print_memlist();
+ MEM_printmemlist_stats();
+ }
+ }
+
+ /* FREE */
+
+ for (lar= re->lampren.first; lar; lar= lar->next) {
+ freeshadowbuf(lar);
+ if (lar->jitter) MEM_freeN(lar->jitter);
+ if (lar->shadsamp) MEM_freeN(lar->shadsamp);
+ if (lar->sunsky) MEM_freeN(lar->sunsky);
+ curvemapping_free(lar->curfalloff);
+ }
+
+ free_volume_precache(re);
+
+ BLI_freelistN(&re->lampren);
+ BLI_freelistN(&re->lights);
+
+ free_renderdata_tables(re);
+
+ /* free orco */
+ free_mesh_orco_hash(re);
+
+ if (re->main) {
+ end_render_materials(re->main);
+ end_render_textures(re);
+ free_pointdensities(re);
+ }
+
+ free_camera_inside_volumes(re);
+
+ if (re->wrld.aosphere) {
+ MEM_freeN(re->wrld.aosphere);
+ re->wrld.aosphere= NULL;
+ if (re->scene && re->scene->world)
+ re->scene->world->aosphere= NULL;
+ }
+ if (re->wrld.aotables) {
+ MEM_freeN(re->wrld.aotables);
+ re->wrld.aotables= NULL;
+ if (re->scene && re->scene->world)
+ re->scene->world->aotables= NULL;
+ }
+ if (re->r.mode & R_RAYTRACE)
+ free_render_qmcsampler(re);
+
+ if (re->r.mode & R_RAYTRACE) freeraytree(re);
+
+ free_sss(re);
+ free_occ(re);
+ free_strand_surface(re);
+
+ re->totvlak=re->totvert=re->totstrand=re->totlamp=re->tothalo= 0;
+ re->i.convertdone = false;
+
+ re->bakebuf= NULL;
+
+ if (re->scene)
+ if (re->scene->r.scemode & R_FREE_IMAGE)
+ if ((re->r.scemode & (R_BUTS_PREVIEW|R_VIEWPORT_PREVIEW))==0)
+ BKE_image_free_all_textures();
+
+ if (re->memArena) {
+ BLI_memarena_free(re->memArena);
+ re->memArena = NULL;
+ }
+}
+
+static int allow_render_object(Render *re, Object *ob, int nolamps, int onlyselected, Object *actob)
+{
+ if (is_object_hidden(re, ob))
+ return 0;
+
+ /* Only handle dupli-hiding here if there is no particle systems. Else, let those handle show/noshow. */
+ if (!ob->particlesystem.first) {
+ if ((ob->transflag & OB_DUPLI) && !(ob->transflag & OB_DUPLIFRAMES)) {
+ return 0;
+ }
+ }
+
+ /* don't add non-basic meta objects, ends up having renderobjects with no geometry */
+ if (ob->type == OB_MBALL && ob!=BKE_mball_basis_find(re->eval_ctx, re->scene, ob))
+ return 0;
+
+ if (nolamps && (ob->type==OB_LAMP))
+ return 0;
+
+ if (onlyselected && (ob!=actob && !(ob->flag & SELECT)))
+ return 0;
+
+ return 1;
+}
+
+static int allow_render_dupli_instance(Render *UNUSED(re), DupliObject *dob, Object *obd)
+{
+ ParticleSystem *psys;
+ Material *ma;
+ short a, *totmaterial;
+
+ /* don't allow objects with halos. we need to have
+ * all halo's to sort them globally in advance */
+ totmaterial= give_totcolp(obd);
+
+ if (totmaterial) {
+ for (a= 0; a<*totmaterial; a++) {
+ ma= give_current_material(obd, a + 1);
+ if (ma && (ma->material_type == MA_TYPE_HALO))
+ return 0;
+ }
+ }
+
+ for (psys=obd->particlesystem.first; psys; psys=psys->next)
+ if (!ELEM(psys->part->ren_as, PART_DRAW_BB, PART_DRAW_LINE, PART_DRAW_PATH, PART_DRAW_OB, PART_DRAW_GR))
+ return 0;
+
+ /* don't allow lamp, animated duplis, or radio render */
+ return (render_object_type(obd->type) &&
+ (!(dob->type == OB_DUPLIGROUP) || !dob->animated));
+}
+
+static void dupli_render_particle_set(Render *re, Object *ob, int timeoffset, int level, int enable)
+{
+ /* ugly function, but we need to set particle systems to their render
+ * settings before calling object_duplilist, to get render level duplis */
+ Group *group;
+ GroupObject *go;
+ ParticleSystem *psys;
+ DerivedMesh *dm;
+
+ if (re->r.scemode & R_VIEWPORT_PREVIEW)
+ return;
+
+ if (level >= MAX_DUPLI_RECUR)
+ return;
+
+ if (ob->transflag & OB_DUPLIPARTS) {
+ for (psys=ob->particlesystem.first; psys; psys=psys->next) {
+ if (ELEM(psys->part->ren_as, PART_DRAW_OB, PART_DRAW_GR)) {
+ if (enable)
+ psys_render_set(ob, psys, re->viewmat, re->winmat, re->winx, re->winy, timeoffset);
+ else
+ psys_render_restore(ob, psys);
+ }
+ }
+
+ if (enable) {
+ /* this is to make sure we get render level duplis in groups:
+ * the derivedmesh must be created before init_render_mesh,
+ * since object_duplilist does dupliparticles before that */
+ dm = mesh_create_derived_render(re->scene, ob, CD_MASK_RENDER_INTERNAL);
+ dm->release(dm);
+
+ for (psys=ob->particlesystem.first; psys; psys=psys->next)
+ psys_get_modifier(ob, psys)->flag &= ~eParticleSystemFlag_psys_updated;
+ }
+ }
+
+ if (ob->dup_group==NULL) return;
+ group= ob->dup_group;
+
+ for (go= group->gobject.first; go; go= go->next)
+ dupli_render_particle_set(re, go->ob, timeoffset, level+1, enable);
+}
+
+static int get_vector_renderlayers(Scene *sce)
+{
+ SceneRenderLayer *srl;
+ unsigned int lay= 0;
+
+ for (srl= sce->r.layers.first; srl; srl= srl->next)
+ if (srl->passflag & SCE_PASS_VECTOR)
+ lay |= srl->lay;
+
+ return lay;
+}
+
+static void add_group_render_dupli_obs(Render *re, Group *group, int nolamps, int onlyselected, Object *actob, int timeoffset, int level)
+{
+ GroupObject *go;
+ Object *ob;
+
+ /* simple preventing of too deep nested groups */
+ if (level>MAX_DUPLI_RECUR) return;
+
+ /* recursively go into dupligroups to find objects with OB_RENDER_DUPLI
+ * that were not created yet */
+ for (go= group->gobject.first; go; go= go->next) {
+ ob= go->ob;
+
+ if (ob->flag & OB_DONE) {
+ if (ob->transflag & OB_RENDER_DUPLI) {
+ if (allow_render_object(re, ob, nolamps, onlyselected, actob)) {
+ init_render_object(re, ob, NULL, NULL, NULL, timeoffset);
+ ob->transflag &= ~OB_RENDER_DUPLI;
+
+ if (ob->dup_group)
+ add_group_render_dupli_obs(re, ob->dup_group, nolamps, onlyselected, actob, timeoffset, level+1);
+ }
+ }
+ }
+ }
+}
+
+static void database_init_objects(Render *re, unsigned int renderlay, int nolamps, int onlyselected, Object *actob, int timeoffset)
+{
+ Base *base;
+ Object *ob;
+ Group *group;
+ ObjectInstanceRen *obi;
+ Scene *sce_iter;
+ int lay, vectorlay;
+
+ /* for duplis we need the Object texture mapping to work as if
+ * untransformed, set_dupli_tex_mat sets the matrix to allow that
+ * NULL is just for init */
+ set_dupli_tex_mat(NULL, NULL, NULL, NULL);
+
+ /* loop over all objects rather then using SETLOOPER because we may
+ * reference an mtex-mapped object which isn't rendered or is an
+ * empty in a dupli group. We could scan all render material/lamp/world
+ * mtex's for mapto objects but its easier just to set the
+ * 'imat' / 'imat_ren' on all and unlikely to be a performance hit
+ * See bug: [#28744] - campbell */
+ for (ob= re->main->object.first; ob; ob= ob->id.next) {
+ float mat[4][4];
+
+ /* imat objects has to be done here, since displace can have texture using Object map-input */
+ mul_m4_m4m4(mat, re->viewmat, ob->obmat);
+ invert_m4_m4(ob->imat_ren, mat);
+ copy_m4_m4(ob->imat, ob->imat_ren);
+ /* each object should only be rendered once */
+ ob->flag &= ~OB_DONE;
+ ob->transflag &= ~OB_RENDER_DUPLI;
+ }
+
+ for (SETLOOPER(re->scene, sce_iter, base)) {
+ ob= base->object;
+
+ /* in the prev/next pass for making speed vectors, avoid creating
+ * objects that are not on a renderlayer with a vector pass, can
+ * save a lot of time in complex scenes */
+ vectorlay= get_vector_renderlayers(re->scene);
+ lay= (timeoffset)? renderlay & vectorlay: renderlay;
+
+ /* if the object has been restricted from rendering in the outliner, ignore it */
+ if (is_object_restricted(re, ob)) continue;
+
+ /* OB_DONE means the object itself got duplicated, so was already converted */
+ if (ob->flag & OB_DONE) {
+ /* OB_RENDER_DUPLI means instances for it were already created, now
+ * it still needs to create the ObjectRen containing the data */
+ if (ob->transflag & OB_RENDER_DUPLI) {
+ if (allow_render_object(re, ob, nolamps, onlyselected, actob)) {
+ init_render_object(re, ob, NULL, NULL, NULL, timeoffset);
+ ob->transflag &= ~OB_RENDER_DUPLI;
+ }
+ }
+ }
+ else if ((base->lay & lay) || (ob->type==OB_LAMP && (base->lay & re->lay)) ) {
+ if ((ob->transflag & OB_DUPLI) && (ob->type!=OB_MBALL)) {
+ DupliObject *dob;
+ ListBase *duplilist;
+ DupliApplyData *duplilist_apply_data = NULL;
+ int i;
+
+ /* create list of duplis generated by this object, particle
+ * system need to have render settings set for dupli particles */
+ dupli_render_particle_set(re, ob, timeoffset, 0, 1);
+ duplilist = object_duplilist(re->eval_ctx, re->scene, ob);
+ duplilist_apply_data = duplilist_apply(ob, NULL, duplilist);
+ /* postpone 'dupli_render_particle_set', since RE_addRenderInstance reads
+ * index values from 'dob->persistent_id[0]', referencing 'psys->child' which
+ * may be smaller once the particle system is restored, see: T45563. */
+
+ for (dob= duplilist->first, i = 0; dob; dob= dob->next, ++i) {
+ DupliExtraData *dob_extra = &duplilist_apply_data->extra[i];
+ Object *obd= dob->ob;
+
+ copy_m4_m4(obd->obmat, dob->mat);
+
+ /* group duplis need to set ob matrices correct, for deform. so no_draw is part handled */
+ if (!(obd->transflag & OB_RENDER_DUPLI) && dob->no_draw)
+ continue;
+
+ if (is_object_hidden(re, obd))
+ continue;
+
+ if (obd->type==OB_MBALL)
+ continue;
+
+ if (!allow_render_object(re, obd, nolamps, onlyselected, actob))
+ continue;
+
+ if (allow_render_dupli_instance(re, dob, obd)) {
+ ParticleSystem *psys;
+ ObjectRen *obr = NULL;
+ int psysindex;
+ float mat[4][4];
+
+ obi=NULL;
+
+ /* instances instead of the actual object are added in two cases, either
+ * this is a duplivert/face/particle, or it is a non-animated object in
+ * a dupligroup that has already been created before */
+ if (dob->type != OB_DUPLIGROUP || (obr=find_dupligroup_dupli(re, obd, 0))) {
+ mul_m4_m4m4(mat, re->viewmat, dob->mat);
+ /* ob = particle system, use that layer */
+ obi = RE_addRenderInstance(re, NULL, obd, ob, dob->persistent_id[0], 0, mat, ob->lay, dob);
+
+ /* fill in instance variables for texturing */
+ set_dupli_tex_mat(re, obi, dob, dob_extra->obmat);
+ if (dob->type != OB_DUPLIGROUP) {
+ copy_v3_v3(obi->dupliorco, dob->orco);
+ obi->dupliuv[0]= dob->uv[0];
+ obi->dupliuv[1]= dob->uv[1];
+ }
+ else {
+ /* for the second case, setup instance to point to the already
+ * created object, and possibly setup instances if this object
+ * itself was duplicated. for the first case find_dupli_instances
+ * will be called later. */
+ assign_dupligroup_dupli(re, obi, obr, dob);
+ if (obd->transflag & OB_RENDER_DUPLI)
+ find_dupli_instances(re, obr, dob);
+ }
+ }
+
+ /* same logic for particles, each particle system has it's own object, so
+ * need to go over them separately */
+ psysindex= 1;
+ for (psys=obd->particlesystem.first; psys; psys=psys->next) {
+ if (dob->type != OB_DUPLIGROUP || (obr=find_dupligroup_dupli(re, obd, psysindex))) {
+ if (obi == NULL)
+ mul_m4_m4m4(mat, re->viewmat, dob->mat);
+ obi = RE_addRenderInstance(re, NULL, obd, ob, dob->persistent_id[0], psysindex++, mat, obd->lay, dob);
+
+ set_dupli_tex_mat(re, obi, dob, dob_extra->obmat);
+ if (dob->type != OB_DUPLIGROUP) {
+ copy_v3_v3(obi->dupliorco, dob->orco);
+ obi->dupliuv[0]= dob->uv[0];
+ obi->dupliuv[1]= dob->uv[1];
+ }
+ else {
+ assign_dupligroup_dupli(re, obi, obr, dob);
+ if (obd->transflag & OB_RENDER_DUPLI)
+ find_dupli_instances(re, obr, dob);
+ }
+ }
+ }
+
+ if (obi==NULL)
+ /* can't instance, just create the object */
+ init_render_object(re, obd, ob, dob, dob_extra->obmat, timeoffset);
+
+ if (dob->type != OB_DUPLIGROUP) {
+ obd->flag |= OB_DONE;
+ obd->transflag |= OB_RENDER_DUPLI;
+ }
+ }
+ else
+ init_render_object(re, obd, ob, dob, dob_extra->obmat, timeoffset);
+
+ if (re->test_break(re->tbh)) break;
+ }
+
+ /* restore particle system */
+ dupli_render_particle_set(re, ob, timeoffset, 0, false);
+
+ if (duplilist_apply_data) {
+ duplilist_restore(duplilist, duplilist_apply_data);
+ duplilist_free_apply_data(duplilist_apply_data);
+ }
+ free_object_duplilist(duplilist);
+
+ if (allow_render_object(re, ob, nolamps, onlyselected, actob))
+ init_render_object(re, ob, NULL, NULL, NULL, timeoffset);
+ }
+ else if (allow_render_object(re, ob, nolamps, onlyselected, actob))
+ init_render_object(re, ob, NULL, NULL, NULL, timeoffset);
+ }
+
+ if (re->test_break(re->tbh)) break;
+ }
+
+ /* objects in groups with OB_RENDER_DUPLI set still need to be created,
+ * since they may not be part of the scene */
+ for (group= re->main->group.first; group; group=group->id.next)
+ add_group_render_dupli_obs(re, group, nolamps, onlyselected, actob, timeoffset, 0);
+
+ if (!re->test_break(re->tbh))
+ RE_makeRenderInstances(re);
+}
+
+/* used to be 'rotate scene' */
+void RE_Database_FromScene(Render *re, Main *bmain, Scene *scene, unsigned int lay, int use_camera_view)
+{
+ Scene *sce;
+ Object *camera;
+ float mat[4][4];
+ float amb[3];
+
+ re->main= bmain;
+ re->scene= scene;
+ re->lay= lay;
+
+ if (re->r.scemode & R_VIEWPORT_PREVIEW)
+ re->scene_color_manage = BKE_scene_check_color_management_enabled(scene);
+
+ /* scene needs to be set to get camera */
+ camera= RE_GetCamera(re);
+
+ /* per second, per object, stats print this */
+ re->i.infostr= "Preparing Scene data";
+ re->i.cfra= scene->r.cfra;
+ BLI_strncpy(re->i.scene_name, scene->id.name + 2, sizeof(re->i.scene_name));
+
+ /* XXX add test if dbase was filled already? */
+
+ re->memArena = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, "render db arena");
+ re->totvlak=re->totvert=re->totstrand=re->totlamp=re->tothalo= 0;
+ re->lights.first= re->lights.last= NULL;
+ re->lampren.first= re->lampren.last= NULL;
+
+ re->i.partsdone = false; /* signal now in use for previewrender */
+
+ /* in localview, lamps are using normal layers, objects only local bits */
+ if (re->lay & 0xFF000000)
+ lay &= 0xFF000000;
+
+ /* applies changes fully */
+ if ((re->r.scemode & (R_NO_FRAME_UPDATE|R_BUTS_PREVIEW|R_VIEWPORT_PREVIEW))==0) {
+ BKE_scene_update_for_newframe(re->eval_ctx, re->main, re->scene, lay);
+ render_update_anim_renderdata(re, &re->scene->r);
+ }
+
+ /* if no camera, viewmat should have been set! */
+ if (use_camera_view && camera) {
+ /* called before but need to call again in case of lens animation from the
+ * above call to BKE_scene_update_for_newframe, fixes bug. [#22702].
+ * following calls don't depend on 'RE_SetCamera' */
+ RE_SetCamera(re, camera);
+ RE_GetCameraModelMatrix(re, camera, mat);
+ invert_m4(mat);
+ RE_SetView(re, mat);
+
+ /* force correct matrix for scaled cameras */
+ DAG_id_tag_update_ex(re->main, &camera->id, OB_RECALC_OB);
+ }
+
+ /* store for incremental render, viewmat rotates dbase */
+ copy_m4_m4(re->viewmat_orig, re->viewmat);
+
+ init_render_world(re); /* do first, because of ambient. also requires re->osa set correct */
+ if (re->r.mode & R_RAYTRACE) {
+ init_render_qmcsampler(re);
+
+ if (re->wrld.mode & (WO_AMB_OCC|WO_ENV_LIGHT|WO_INDIRECT_LIGHT))
+ if (re->wrld.ao_samp_method == WO_AOSAMP_CONSTANT)
+ init_ao_sphere(re, &re->wrld);
+ }
+
+ /* still bad... doing all */
+ init_render_textures(re);
+ copy_v3_v3(amb, &re->wrld.ambr);
+ init_render_materials(re->main, re->r.mode, amb, (re->r.scemode & R_BUTS_PREVIEW) == 0);
+ set_node_shader_lamp_loop(shade_material_loop);
+
+ /* MAKE RENDER DATA */
+ database_init_objects(re, lay, 0, 0, NULL, 0);
+
+ if (!re->test_break(re->tbh)) {
+ set_material_lightgroups(re);
+ for (sce= re->scene; sce; sce= sce->set)
+ set_renderlayer_lightgroups(re, sce);
+
+ /* for now some clumsy copying still */
+ re->i.totvert= re->totvert;
+ re->i.totface= re->totvlak;
+ re->i.totstrand= re->totstrand;
+ re->i.tothalo= re->tothalo;
+ re->i.totlamp= re->totlamp;
+ re->stats_draw(re->sdh, &re->i);
+ }
+}
+
+void RE_Database_Preprocess(Render *re)
+{
+ if (!re->test_break(re->tbh)) {
+ int tothalo;
+
+ tothalo= re->tothalo;
+ sort_halos(re, tothalo);
+
+ init_camera_inside_volumes(re);
+
+ re->i.infostr = IFACE_("Creating Shadowbuffers");
+ re->stats_draw(re->sdh, &re->i);
+
+ /* SHADOW BUFFER */
+ threaded_makeshadowbufs(re);
+
+ /* old code checked for internal render (aka not yafray) */
+ {
+ /* raytree */
+ if (!re->test_break(re->tbh)) {
+ if (re->r.mode & R_RAYTRACE) {
+ makeraytree(re);
+ }
+ }
+ /* ENVIRONMENT MAPS */
+ if (!re->test_break(re->tbh))
+ make_envmaps(re);
+
+ /* point density texture */
+ if (!re->test_break(re->tbh))
+ make_pointdensities(re);
+ /* voxel data texture */
+ if (!re->test_break(re->tbh))
+ make_voxeldata(re);
+ }
+
+ if (!re->test_break(re->tbh))
+ project_renderdata(re, projectverto, (re->r.mode & R_PANORAMA) != 0, 0, 1);
+
+ /* Occlusion */
+ if ((re->wrld.mode & (WO_AMB_OCC|WO_ENV_LIGHT|WO_INDIRECT_LIGHT)) && !re->test_break(re->tbh))
+ if (re->wrld.ao_gather_method == WO_AOGATHER_APPROX)
+ if (re->r.mode & R_SHADOW)
+ make_occ_tree(re);
+
+ /* SSS */
+ if ((re->r.mode & R_SSS) && !re->test_break(re->tbh))
+ make_sss_tree(re);
+
+ if (!re->test_break(re->tbh))
+ if (re->r.mode & R_RAYTRACE)
+ volume_precache(re);
+ }
+
+ re->i.convertdone = true;
+
+ if (re->test_break(re->tbh))
+ RE_Database_Free(re);
+
+ re->i.infostr = NULL;
+ re->stats_draw(re->sdh, &re->i);
+}
+
+/* exported call to recalculate hoco for vertices, when winmat changed */
+void RE_DataBase_ApplyWindow(Render *re)
+{
+ project_renderdata(re, projectverto, 0, 0, 0);
+}
+
+/* exported call to rotate render data again, when viewmat changed */
+void RE_DataBase_IncrementalView(Render *re, float viewmat[4][4], int restore)
+{
+ float oldviewinv[4][4], tmat[4][4];
+
+ invert_m4_m4(oldviewinv, re->viewmat_orig);
+
+ /* we have to correct for the already rotated vertexcoords */
+ mul_m4_m4m4(tmat, viewmat, oldviewinv);
+
+ copy_m4_m4(re->viewmat, viewmat);
+ invert_m4_m4(re->viewinv, re->viewmat);
+
+ init_camera_inside_volumes(re);
+
+ env_rotate_scene(re, tmat, !restore);
+
+ /* SSS points distribution depends on view */
+ if ((re->r.mode & R_SSS) && !re->test_break(re->tbh))
+ make_sss_tree(re);
+}
+
+
+void RE_DataBase_GetView(Render *re, float mat[4][4])
+{
+ copy_m4_m4(mat, re->viewmat);
+}
+
+/* ------------------------------------------------------------------------- */
+/* Speed Vectors */
+/* ------------------------------------------------------------------------- */
+
+static void database_fromscene_vectors(Render *re, Scene *scene, unsigned int lay, int timeoffset)
+{
+ Object *camera= RE_GetCamera(re);
+ float mat[4][4];
+
+ re->scene= scene;
+ re->lay= lay;
+
+ /* XXX add test if dbase was filled already? */
+
+ re->memArena = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, "vector render db arena");
+ re->totvlak=re->totvert=re->totstrand=re->totlamp=re->tothalo= 0;
+ re->i.totface=re->i.totvert=re->i.totstrand=re->i.totlamp=re->i.tothalo= 0;
+ re->lights.first= re->lights.last= NULL;
+
+ /* in localview, lamps are using normal layers, objects only local bits */
+ if (re->lay & 0xFF000000)
+ lay &= 0xFF000000;
+
+ /* applies changes fully */
+ scene->r.cfra += timeoffset;
+ BKE_scene_update_for_newframe(re->eval_ctx, re->main, re->scene, lay);
+
+ /* if no camera, viewmat should have been set! */
+ if (camera) {
+ RE_GetCameraModelMatrix(re, camera, mat);
+ normalize_m4(mat);
+ invert_m4(mat);
+ RE_SetView(re, mat);
+ }
+
+ /* MAKE RENDER DATA */
+ database_init_objects(re, lay, 0, 0, NULL, timeoffset);
+
+ if (!re->test_break(re->tbh))
+ project_renderdata(re, projectverto, (re->r.mode & R_PANORAMA) != 0, 0, 1);
+
+ /* do this in end, particles for example need cfra */
+ scene->r.cfra -= timeoffset;
+}
+
+/* choose to use static, to prevent giving too many args to this call */
+static void speedvector_project(Render *re, float zco[2], const float co[3], const float ho[4])
+{
+ static float pixelphix=0.0f, pixelphiy=0.0f, zmulx=0.0f, zmuly=0.0f;
+ static int pano= 0;
+ float div;
+
+ /* initialize */
+ if (re) {
+ pano= re->r.mode & R_PANORAMA;
+
+ /* precalculate amount of radians 1 pixel rotates */
+ if (pano) {
+ /* size of 1 pixel mapped to viewplane coords */
+ float psize;
+
+ psize = BLI_rctf_size_x(&re->viewplane) / (float)re->winx;
+ /* x angle of a pixel */
+ pixelphix = atan(psize / re->clipsta);
+
+ psize = BLI_rctf_size_y(&re->viewplane) / (float)re->winy;
+ /* y angle of a pixel */
+ pixelphiy = atan(psize / re->clipsta);
+ }
+ zmulx= re->winx/2;
+ zmuly= re->winy/2;
+
+ return;
+ }
+
+ /* now map hocos to screenspace, uses very primitive clip still */
+ if (ho[3]<0.1f) div= 10.0f;
+ else div= 1.0f/ho[3];
+
+ /* use cylinder projection */
+ if (pano) {
+ float vec[3], ang;
+ /* angle between (0, 0, -1) and (co) */
+ copy_v3_v3(vec, co);
+
+ ang= saacos(-vec[2]/sqrtf(vec[0]*vec[0] + vec[2]*vec[2]));
+ if (vec[0]<0.0f) ang= -ang;
+ zco[0]= ang/pixelphix + zmulx;
+
+ ang= 0.5f*(float)M_PI - saacos(vec[1] / len_v3(vec));
+ zco[1]= ang/pixelphiy + zmuly;
+
+ }
+ else {
+ zco[0]= zmulx*(1.0f+ho[0]*div);
+ zco[1]= zmuly*(1.0f+ho[1]*div);
+ }
+}
+
+static void calculate_speedvector(const float vectors[2], int step, float winsq, float winroot, const float co[3], const float ho[4], float speed[4])
+{
+ float zco[2], len;
+
+ speedvector_project(NULL, zco, co, ho);
+
+ zco[0]= vectors[0] - zco[0];
+ zco[1]= vectors[1] - zco[1];
+
+ /* enable nice masks for hardly moving stuff or float inaccuracy */
+ if (zco[0]<0.1f && zco[0]>-0.1f && zco[1]<0.1f && zco[1]>-0.1f ) {
+ zco[0]= 0.0f;
+ zco[1]= 0.0f;
+ }
+
+ /* maximize speed for image width, otherwise it never looks good */
+ len= zco[0]*zco[0] + zco[1]*zco[1];
+ if (len > winsq) {
+ len= winroot/sqrtf(len);
+ zco[0]*= len;
+ zco[1]*= len;
+ }
+
+ /* note; in main vecblur loop speedvec is negated again */
+ if (step) {
+ speed[2]= -zco[0];
+ speed[3]= -zco[1];
+ }
+ else {
+ speed[0]= zco[0];
+ speed[1]= zco[1];
+ }
+}
+
+static float *calculate_strandsurface_speedvectors(Render *re, ObjectInstanceRen *obi, StrandSurface *mesh)
+{
+ if (mesh->co && mesh->prevco && mesh->nextco) {
+ float winsq= (float)re->winx*(float)re->winy; /* int's can wrap on large images */
+ float winroot= sqrtf(winsq);
+ float (*winspeed)[4];
+ float ho[4], prevho[4], nextho[4], winmat[4][4], vec[2];
+ int a;
+
+ if (obi->flag & R_TRANSFORMED)
+ mul_m4_m4m4(winmat, re->winmat, obi->mat);
+ else
+ copy_m4_m4(winmat, re->winmat);
+
+ winspeed= MEM_callocN(sizeof(float)*4*mesh->totvert, "StrandSurfWin");
+
+ for (a=0; a<mesh->totvert; a++) {
+ projectvert(mesh->co[a], winmat, ho);
+
+ projectvert(mesh->prevco[a], winmat, prevho);
+ speedvector_project(NULL, vec, mesh->prevco[a], prevho);
+ calculate_speedvector(vec, 0, winsq, winroot, mesh->co[a], ho, winspeed[a]);
+
+ projectvert(mesh->nextco[a], winmat, nextho);
+ speedvector_project(NULL, vec, mesh->nextco[a], nextho);
+ calculate_speedvector(vec, 1, winsq, winroot, mesh->co[a], ho, winspeed[a]);
+ }
+
+ return (float *)winspeed;
+ }
+
+ return NULL;
+}
+
+static void calculate_speedvectors(Render *re, ObjectInstanceRen *obi, float *vectors, int step)
+{
+ ObjectRen *obr= obi->obr;
+ VertRen *ver= NULL;
+ StrandRen *strand= NULL;
+ StrandBuffer *strandbuf;
+ StrandSurface *mesh= NULL;
+ float *speed, (*winspeed)[4]=NULL, ho[4], winmat[4][4];
+ float *co1, *co2, *co3, *co4, w[4];
+ float winsq = (float)re->winx * (float)re->winy, winroot = sqrtf(winsq); /* int's can wrap on large images */
+ int a, *face, *index;
+
+ if (obi->flag & R_TRANSFORMED)
+ mul_m4_m4m4(winmat, re->winmat, obi->mat);
+ else
+ copy_m4_m4(winmat, re->winmat);
+
+ if (obr->vertnodes) {
+ for (a=0; a<obr->totvert; a++, vectors+=2) {
+ if ((a & 255)==0) ver= obr->vertnodes[a>>8].vert;
+ else ver++;
+
+ speed= RE_vertren_get_winspeed(obi, ver, 1);
+ projectvert(ver->co, winmat, ho);
+ calculate_speedvector(vectors, step, winsq, winroot, ver->co, ho, speed);
+ }
+ }
+
+ if (obr->strandnodes) {
+ strandbuf= obr->strandbuf;
+ mesh= (strandbuf)? strandbuf->surface: NULL;
+
+ /* compute speed vectors at surface vertices */
+ if (mesh)
+ winspeed= (float(*)[4])calculate_strandsurface_speedvectors(re, obi, mesh);
+
+ if (winspeed) {
+ for (a=0; a<obr->totstrand; a++, vectors+=2) {
+ if ((a & 255)==0) strand= obr->strandnodes[a>>8].strand;
+ else strand++;
+
+ index= RE_strandren_get_face(obr, strand, 0);
+ if (index && *index < mesh->totface) {
+ speed= RE_strandren_get_winspeed(obi, strand, 1);
+
+ /* interpolate speed vectors from strand surface */
+ face= mesh->face[*index];
+
+ co1 = mesh->co[face[0]];
+ co2 = mesh->co[face[1]];
+ co3 = mesh->co[face[2]];
+
+ if (face[3]) {
+ co4 = mesh->co[face[3]];
+ interp_weights_quad_v3(w, co1, co2, co3, co4, strand->vert->co);
+ }
+ else {
+ interp_weights_tri_v3(w, co1, co2, co3, strand->vert->co);
+ }
+
+ zero_v4(speed);
+ madd_v4_v4fl(speed, winspeed[face[0]], w[0]);
+ madd_v4_v4fl(speed, winspeed[face[1]], w[1]);
+ madd_v4_v4fl(speed, winspeed[face[2]], w[2]);
+ if (face[3])
+ madd_v4_v4fl(speed, winspeed[face[3]], w[3]);
+ }
+ }
+
+ MEM_freeN(winspeed);
+ }
+ }
+}
+
+static int load_fluidsimspeedvectors(Render *re, ObjectInstanceRen *obi, float *vectors, int step)
+{
+ ObjectRen *obr= obi->obr;
+ Object *fsob= obr->ob;
+ VertRen *ver= NULL;
+ float *speed, div, zco[2], avgvel[4] = {0.0, 0.0, 0.0, 0.0};
+ float zmulx= re->winx/2, zmuly= re->winy/2, len;
+ float winsq = (float)re->winx * (float)re->winy, winroot= sqrtf(winsq); /* int's can wrap on large images */
+ int a, j;
+ float hoco[4], ho[4], fsvec[4], camco[4];
+ float mat[4][4], winmat[4][4];
+ float imat[4][4];
+ FluidsimModifierData *fluidmd = (FluidsimModifierData *)modifiers_findByType(fsob, eModifierType_Fluidsim);
+ FluidsimSettings *fss;
+ FluidVertexVelocity *velarray = NULL;
+
+ /* only one step needed */
+ if (step) return 1;
+
+ if (fluidmd)
+ fss = fluidmd->fss;
+ else
+ return 0;
+
+ copy_m4_m4(mat, re->viewmat);
+ invert_m4_m4(imat, mat);
+
+ /* set first vertex OK */
+ if (!fss->meshVelocities) return 0;
+
+ if ( obr->totvert != fss->totvert) {
+ //fprintf(stderr, "load_fluidsimspeedvectors - modified fluidsim mesh, not using speed vectors (%d,%d)...\n", obr->totvert, fsob->fluidsimSettings->meshSurface->totvert); // DEBUG
+ return 0;
+ }
+
+ velarray = fss->meshVelocities;
+
+ if (obi->flag & R_TRANSFORMED)
+ mul_m4_m4m4(winmat, re->winmat, obi->mat);
+ else
+ copy_m4_m4(winmat, re->winmat);
+
+ /* (bad) HACK calculate average velocity */
+ /* better solution would be fixing getVelocityAt() in intern/elbeem/intern/solver_util.cpp
+ * so that also small drops/little water volumes return a velocity != 0.
+ * But I had no luck in fixing that function - DG */
+ for (a=0; a<obr->totvert; a++) {
+ for (j=0;j<3;j++) avgvel[j] += velarray[a].vel[j];
+
+ }
+ for (j=0;j<3;j++) avgvel[j] /= (float)(obr->totvert);
+
+
+ for (a=0; a<obr->totvert; a++, vectors+=2) {
+ if ((a & 255)==0)
+ ver= obr->vertnodes[a>>8].vert;
+ else
+ ver++;
+
+ /* get fluid velocity */
+ fsvec[3] = 0.0f;
+ //fsvec[0] = fsvec[1] = fsvec[2] = fsvec[3] = 0.0; fsvec[2] = 2.0f; // NT fixed test
+ for (j=0;j<3;j++) fsvec[j] = velarray[a].vel[j];
+
+ /* (bad) HACK insert average velocity if none is there (see previous comment) */
+ if ((fsvec[0] == 0.0f) && (fsvec[1] == 0.0f) && (fsvec[2] == 0.0f)) {
+ fsvec[0] = avgvel[0];
+ fsvec[1] = avgvel[1];
+ fsvec[2] = avgvel[2];
+ }
+
+ /* transform (=rotate) to cam space */
+ camco[0] = dot_v3v3(imat[0], fsvec);
+ camco[1] = dot_v3v3(imat[1], fsvec);
+ camco[2] = dot_v3v3(imat[2], fsvec);
+
+ /* get homogeneous coordinates */
+ projectvert(camco, winmat, hoco);
+ projectvert(ver->co, winmat, ho);
+
+ /* now map hocos to screenspace, uses very primitive clip still */
+ /* use ho[3] of original vertex, xy component of vel. direction */
+ if (ho[3]<0.1f) div= 10.0f;
+ else div= 1.0f/ho[3];
+ zco[0]= zmulx*hoco[0]*div;
+ zco[1]= zmuly*hoco[1]*div;
+
+ /* maximize speed as usual */
+ len= zco[0]*zco[0] + zco[1]*zco[1];
+ if (len > winsq) {
+ len= winroot/sqrtf(len);
+ zco[0]*= len; zco[1]*= len;
+ }
+
+ speed= RE_vertren_get_winspeed(obi, ver, 1);
+ /* set both to the same value */
+ speed[0]= speed[2]= zco[0];
+ speed[1]= speed[3]= zco[1];
+ //if (a < 20) fprintf(stderr,"speed %d %f,%f | camco %f,%f,%f | hoco %f,%f,%f,%f\n", a, speed[0], speed[1], camco[0],camco[1], camco[2], hoco[0],hoco[1], hoco[2],hoco[3]); // NT DEBUG
+ }
+
+ return 1;
+}
+
+/* makes copy per object of all vectors */
+/* result should be that we can free entire database */
+static void copy_dbase_object_vectors(Render *re, ListBase *lb)
+{
+ ObjectInstanceRen *obi, *obilb;
+ ObjectRen *obr;
+ VertRen *ver= NULL;
+ float *vec, ho[4], winmat[4][4];
+ int a, totvector;
+
+ for (obi= re->instancetable.first; obi; obi= obi->next) {
+ obr= obi->obr;
+
+ obilb= MEM_mallocN(sizeof(ObjectInstanceRen), "ObInstanceVector");
+ memcpy(obilb, obi, sizeof(ObjectInstanceRen));
+ BLI_addtail(lb, obilb);
+
+ obilb->totvector= totvector= obr->totvert;
+
+ if (totvector > 0) {
+ vec= obilb->vectors= MEM_mallocN(2*sizeof(float)*totvector, "vector array");
+
+ if (obi->flag & R_TRANSFORMED)
+ mul_m4_m4m4(winmat, re->winmat, obi->mat);
+ else
+ copy_m4_m4(winmat, re->winmat);
+
+ for (a=0; a<obr->totvert; a++, vec+=2) {
+ if ((a & 255)==0) ver= obr->vertnodes[a>>8].vert;
+ else ver++;
+
+ projectvert(ver->co, winmat, ho);
+ speedvector_project(NULL, vec, ver->co, ho);
+ }
+ }
+ }
+}
+
+static void free_dbase_object_vectors(ListBase *lb)
+{
+ ObjectInstanceRen *obi;
+
+ for (obi= lb->first; obi; obi= obi->next)
+ if (obi->vectors)
+ MEM_freeN(obi->vectors);
+ BLI_freelistN(lb);
+}
+
+void RE_Database_FromScene_Vectors(Render *re, Main *bmain, Scene *sce, unsigned int lay)
+{
+ ObjectInstanceRen *obi, *oldobi;
+ StrandSurface *mesh;
+ ListBase *table;
+ ListBase oldtable= {NULL, NULL}, newtable= {NULL, NULL};
+ ListBase strandsurface;
+ int step;
+
+ re->i.infostr = IFACE_("Calculating previous frame vectors");
+ re->r.mode |= R_SPEED;
+
+ speedvector_project(re, NULL, NULL, NULL); /* initializes projection code */
+
+ /* creates entire dbase */
+ database_fromscene_vectors(re, sce, lay, -1);
+
+ /* copy away vertex info */
+ copy_dbase_object_vectors(re, &oldtable);
+
+ /* free dbase and make the future one */
+ strandsurface= re->strandsurface;
+ memset(&re->strandsurface, 0, sizeof(ListBase));
+ re->i.convertdone = true;
+ RE_Database_Free(re);
+ re->strandsurface= strandsurface;
+
+ if (!re->test_break(re->tbh)) {
+ /* creates entire dbase */
+ re->i.infostr = IFACE_("Calculating next frame vectors");
+
+ database_fromscene_vectors(re, sce, lay, +1);
+ }
+ /* copy away vertex info */
+ copy_dbase_object_vectors(re, &newtable);
+
+ /* free dbase and make the real one */
+ strandsurface= re->strandsurface;
+ memset(&re->strandsurface, 0, sizeof(ListBase));
+ re->i.convertdone = true;
+ RE_Database_Free(re);
+ re->strandsurface= strandsurface;
+
+ if (!re->test_break(re->tbh)) {
+ RE_Database_FromScene(re, bmain, sce, lay, 1);
+ RE_Database_Preprocess(re);
+ }
+
+ if (!re->test_break(re->tbh)) {
+ int vectorlay= get_vector_renderlayers(re->scene);
+
+ for (step= 0; step<2; step++) {
+
+ if (step)
+ table= &newtable;
+ else
+ table= &oldtable;
+
+ oldobi= table->first;
+ for (obi= re->instancetable.first; obi && oldobi; obi= obi->next) {
+ int ok= 1;
+ FluidsimModifierData *fluidmd;
+
+ if (!(obi->lay & vectorlay))
+ continue;
+
+ obi->totvector= obi->obr->totvert;
+
+ /* find matching object in old table */
+ if (oldobi->ob!=obi->ob || oldobi->par!=obi->par || oldobi->index!=obi->index || oldobi->psysindex!=obi->psysindex) {
+ ok= 0;
+ for (oldobi= table->first; oldobi; oldobi= oldobi->next)
+ if (oldobi->ob==obi->ob && oldobi->par==obi->par && oldobi->index==obi->index && oldobi->psysindex==obi->psysindex)
+ break;
+ if (oldobi==NULL)
+ oldobi= table->first;
+ else
+ ok= 1;
+ }
+ if (ok==0) {
+ printf("speed table: missing object %s\n", obi->ob->id.name + 2);
+ continue;
+ }
+
+ /* NT check for fluidsim special treatment */
+ fluidmd = (FluidsimModifierData *)modifiers_findByType(obi->ob, eModifierType_Fluidsim);
+ if (fluidmd && fluidmd->fss && (fluidmd->fss->type & OB_FLUIDSIM_DOMAIN)) {
+ /* use preloaded per vertex simulation data, only does calculation for step=1 */
+ /* NOTE/FIXME - velocities and meshes loaded unnecessarily often during the database_fromscene_vectors calls... */
+ load_fluidsimspeedvectors(re, obi, oldobi->vectors, step);
+ }
+ else {
+ /* check if both have same amounts of vertices */
+ if (obi->totvector==oldobi->totvector)
+ calculate_speedvectors(re, obi, oldobi->vectors, step);
+ else
+ printf("Warning: object %s has different amount of vertices or strands on other frame\n", obi->ob->id.name + 2);
+ } /* not fluidsim */
+
+ oldobi= oldobi->next;
+ }
+ }
+ }
+
+ free_dbase_object_vectors(&oldtable);
+ free_dbase_object_vectors(&newtable);
+
+ for (mesh=re->strandsurface.first; mesh; mesh=mesh->next) {
+ if (mesh->prevco) {
+ MEM_freeN(mesh->prevco);
+ mesh->prevco= NULL;
+ }
+ if (mesh->nextco) {
+ MEM_freeN(mesh->nextco);
+ mesh->nextco= NULL;
+ }
+ }
+
+ re->i.infostr = NULL;
+ re->stats_draw(re->sdh, &re->i);
+}
+
+
+/* ------------------------------------------------------------------------- */
+/* Baking */
+/* ------------------------------------------------------------------------- */
+
+/* setup for shaded view or bake, so only lamps and materials are initialized */
+/* type:
+ * RE_BAKE_LIGHT: for shaded view, only add lamps
+ * RE_BAKE_ALL: for baking, all lamps and objects
+ * RE_BAKE_NORMALS:for baking, no lamps and only selected objects
+ * RE_BAKE_AO: for baking, no lamps, but all objects
+ * RE_BAKE_TEXTURE:for baking, no lamps, only selected objects
+ * RE_BAKE_VERTEX_COLORS:for baking, no lamps, only selected objects
+ * RE_BAKE_DISPLACEMENT:for baking, no lamps, only selected objects
+ * RE_BAKE_DERIVATIVE:for baking, no lamps, only selected objects
+ * RE_BAKE_SHADOW: for baking, only shadows, but all objects
+ */
+void RE_Database_Baking(Render *re, Main *bmain, Scene *scene, unsigned int lay, const int type, Object *actob)
+{
+ Object *camera;
+ float mat[4][4];
+ float amb[3];
+ const short onlyselected= !ELEM(type, RE_BAKE_LIGHT, RE_BAKE_ALL, RE_BAKE_SHADOW, RE_BAKE_AO, RE_BAKE_VERTEX_COLORS);
+ const short nolamps= ELEM(type, RE_BAKE_NORMALS, RE_BAKE_TEXTURE, RE_BAKE_DISPLACEMENT, RE_BAKE_DERIVATIVE, RE_BAKE_VERTEX_COLORS);
+
+ re->main= bmain;
+ re->scene= scene;
+ re->lay= lay;
+
+ /* renderdata setup and exceptions */
+ render_copy_renderdata(&re->r, &scene->r);
+
+ RE_init_threadcount(re);
+
+ re->flag |= R_BAKING;
+ re->excludeob= actob;
+ if (actob)
+ re->flag |= R_BAKE_TRACE;
+
+ if (type==RE_BAKE_NORMALS && re->r.bake_normal_space==R_BAKE_SPACE_TANGENT)
+ re->flag |= R_NEED_TANGENT;
+
+ if (type==RE_BAKE_VERTEX_COLORS)
+ re->flag |= R_NEED_VCOL;
+
+ if (!actob && ELEM(type, RE_BAKE_LIGHT, RE_BAKE_NORMALS, RE_BAKE_TEXTURE, RE_BAKE_DISPLACEMENT, RE_BAKE_DERIVATIVE, RE_BAKE_VERTEX_COLORS)) {
+ re->r.mode &= ~R_SHADOW;
+ re->r.mode &= ~R_RAYTRACE;
+ }
+
+ if (!actob && (type==RE_BAKE_SHADOW)) {
+ re->r.mode |= R_SHADOW;
+ }
+
+ /* setup render stuff */
+ re->memArena = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, "bake db arena");
+
+ re->totvlak=re->totvert=re->totstrand=re->totlamp=re->tothalo= 0;
+ re->lights.first= re->lights.last= NULL;
+ re->lampren.first= re->lampren.last= NULL;
+
+ /* in localview, lamps are using normal layers, objects only local bits */
+ if (re->lay & 0xFF000000)
+ lay &= 0xFF000000;
+
+ camera= RE_GetCamera(re);
+
+ /* if no camera, set unit */
+ if (camera) {
+ normalize_m4_m4(mat, camera->obmat);
+ invert_m4(mat);
+ RE_SetView(re, mat);
+ }
+ else {
+ unit_m4(mat);
+ RE_SetView(re, mat);
+ }
+ copy_m3_m4(re->imat, re->viewinv);
+
+ /* TODO: deep shadow maps + baking + strands */
+ /* strands use the window matrix and view size, there is to correct
+ * window matrix but at least avoids malloc and crash loop [#27807] */
+ unit_m4(re->winmat);
+ re->winx= re->winy= 256;
+ /* done setting dummy values */
+
+ init_render_world(re); /* do first, because of ambient. also requires re->osa set correct */
+ if (re->r.mode & R_RAYTRACE) {
+ init_render_qmcsampler(re);
+
+ if (re->wrld.mode & (WO_AMB_OCC|WO_ENV_LIGHT|WO_INDIRECT_LIGHT))
+ if (re->wrld.ao_samp_method == WO_AOSAMP_CONSTANT)
+ init_ao_sphere(re, &re->wrld);
+ }
+
+ /* still bad... doing all */
+ init_render_textures(re);
+
+ copy_v3_v3(amb, &re->wrld.ambr);
+ init_render_materials(re->main, re->r.mode, amb, true);
+
+ set_node_shader_lamp_loop(shade_material_loop);
+
+ /* MAKE RENDER DATA */
+ database_init_objects(re, lay, nolamps, onlyselected, actob, 0);
+
+ set_material_lightgroups(re);
+
+ /* SHADOW BUFFER */
+ if (type!=RE_BAKE_LIGHT)
+ if (re->r.mode & R_SHADOW)
+ threaded_makeshadowbufs(re);
+
+ /* raytree */
+ if (!re->test_break(re->tbh))
+ if (re->r.mode & R_RAYTRACE)
+ makeraytree(re);
+
+ /* point density texture */
+ if (!re->test_break(re->tbh))
+ make_pointdensities(re);
+
+ /* voxel data texture */
+ if (!re->test_break(re->tbh))
+ make_voxeldata(re);
+
+ /* occlusion */
+ if ((re->wrld.mode & (WO_AMB_OCC|WO_ENV_LIGHT|WO_INDIRECT_LIGHT)) && !re->test_break(re->tbh))
+ if (re->wrld.ao_gather_method == WO_AOGATHER_APPROX)
+ if (re->r.mode & R_SHADOW)
+ make_occ_tree(re);
+
+ re->i.convertdone = true;
+}
diff --git a/source/blender/render/intern/source/envmap.c b/source/blender/render/intern/source/envmap.c
new file mode 100644
index 00000000000..85a6af92a28
--- /dev/null
+++ b/source/blender/render/intern/source/envmap.c
@@ -0,0 +1,822 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * Contributors: 2004/2005/2006 Blender Foundation, full recode
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/render/intern/source/envmap.c
+ * \ingroup render
+ */
+
+#include <math.h>
+#include <string.h>
+
+/* external modules: */
+
+#include "BLI_math.h"
+#include "BLI_blenlib.h"
+#include "BLI_threads.h"
+#include "BLI_utildefines.h"
+
+#include "BLT_translation.h"
+
+#include "IMB_imbuf_types.h"
+#include "IMB_imbuf.h" /* for rectcpy */
+
+#include "DNA_group_types.h"
+#include "DNA_image_types.h"
+#include "DNA_lamp_types.h"
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_texture_types.h"
+
+#include "BKE_main.h"
+#include "BKE_image.h" /* BKE_imbuf_write */
+#include "BKE_texture.h"
+#include "BKE_scene.h"
+
+/* this module */
+#include "render_types.h"
+#include "envmap.h"
+#include "renderdatabase.h"
+#include "renderpipeline.h"
+#include "texture.h"
+#include "zbuf.h"
+#include "render_result.h"
+
+/* ------------------------------------------------------------------------- */
+
+static void envmap_split_ima(EnvMap *env, ImBuf *ibuf)
+{
+ int dx, part;
+
+ /* after lock we test cube[1], if set the other thread has done it fine */
+ BLI_thread_lock(LOCK_IMAGE);
+ if (env->cube[1] == NULL) {
+
+ BKE_texture_envmap_free_data(env);
+
+ dx = ibuf->y;
+ dx /= 2;
+ if (3 * dx == ibuf->x) {
+ env->type = ENV_CUBE;
+ env->ok = ENV_OSA;
+ }
+ else if (ibuf->x == ibuf->y) {
+ env->type = ENV_PLANE;
+ env->ok = ENV_OSA;
+ }
+ else {
+ printf("Incorrect envmap size\n");
+ env->ok = 0;
+ env->ima->ok = 0;
+ }
+
+ if (env->ok) {
+ if (env->type == ENV_CUBE) {
+ for (part = 0; part < 6; part++) {
+ env->cube[part] = IMB_allocImBuf(dx, dx, 24, IB_rect | IB_rectfloat);
+ }
+ IMB_float_from_rect(ibuf);
+
+ IMB_rectcpy(env->cube[0], ibuf,
+ 0, 0, 0, 0, dx, dx);
+ IMB_rectcpy(env->cube[1], ibuf,
+ 0, 0, dx, 0, dx, dx);
+ IMB_rectcpy(env->cube[2], ibuf,
+ 0, 0, 2 * dx, 0, dx, dx);
+ IMB_rectcpy(env->cube[3], ibuf,
+ 0, 0, 0, dx, dx, dx);
+ IMB_rectcpy(env->cube[4], ibuf,
+ 0, 0, dx, dx, dx, dx);
+ IMB_rectcpy(env->cube[5], ibuf,
+ 0, 0, 2 * dx, dx, dx, dx);
+
+ }
+ else { /* ENV_PLANE */
+ env->cube[1] = IMB_dupImBuf(ibuf);
+ IMB_float_from_rect(env->cube[1]);
+ }
+ }
+ }
+ BLI_thread_unlock(LOCK_IMAGE);
+}
+
+/* ------------------------------------------------------------------------- */
+/* ****************** RENDER ********************** */
+
+/* copy current render */
+static Render *envmap_render_copy(Render *re, EnvMap *env)
+{
+ Render *envre;
+ float viewscale;
+ int cuberes;
+
+ envre = RE_NewRender("Envmap");
+
+ env->lastsize = re->r.size;
+ cuberes = (env->cuberes * re->r.size) / 100;
+ cuberes &= 0xFFFC;
+
+ /* this flag has R_ZTRA in it for example */
+ envre->flag = re->flag;
+
+ /* set up renderdata */
+ render_copy_renderdata(&envre->r, &re->r);
+ envre->r.mode &= ~(R_BORDER | R_PANORAMA | R_ORTHO | R_MBLUR);
+ BLI_freelistN(&envre->r.layers);
+ BLI_freelistN(&envre->r.views);
+ envre->r.filtertype = 0;
+ envre->r.tilex = envre->r.xsch / 2;
+ envre->r.tiley = envre->r.ysch / 2;
+ envre->r.size = 100;
+ envre->r.yasp = envre->r.xasp = 1;
+
+ RE_InitState(envre, NULL, &envre->r, NULL, cuberes, cuberes, NULL);
+ envre->main = re->main;
+ envre->scene = re->scene; /* unsure about this... */
+ envre->scene_color_manage = re->scene_color_manage;
+ envre->lay = re->lay;
+
+ /* view stuff in env render */
+ viewscale = (env->type == ENV_PLANE) ? env->viewscale : 1.0f;
+ RE_SetEnvmapCamera(envre, env->object, viewscale, env->clipsta, env->clipend);
+ copy_m4_m4(envre->viewmat_orig, re->viewmat_orig);
+
+ /* callbacks */
+ envre->display_update = re->display_update;
+ envre->duh = re->duh;
+ envre->test_break = re->test_break;
+ envre->tbh = re->tbh;
+ envre->current_scene_update = re->current_scene_update;
+ envre->suh = re->suh;
+
+ /* and for the evil stuff; copy the database... */
+ envre->totvlak = re->totvlak;
+ envre->totvert = re->totvert;
+ envre->tothalo = re->tothalo;
+ envre->totstrand = re->totstrand;
+ envre->totlamp = re->totlamp;
+ envre->sortedhalos = re->sortedhalos;
+ envre->lights = re->lights;
+ envre->objecttable = re->objecttable;
+ envre->customdata_names = re->customdata_names;
+ envre->raytree = re->raytree;
+ envre->totinstance = re->totinstance;
+ envre->instancetable = re->instancetable;
+ envre->objectinstance = re->objectinstance;
+ envre->qmcsamplers = re->qmcsamplers;
+
+ return envre;
+}
+
+static void envmap_free_render_copy(Render *envre)
+{
+
+ envre->totvlak = 0;
+ envre->totvert = 0;
+ envre->tothalo = 0;
+ envre->totstrand = 0;
+ envre->totlamp = 0;
+ envre->totinstance = 0;
+ envre->sortedhalos = NULL;
+ BLI_listbase_clear(&envre->lights);
+ BLI_listbase_clear(&envre->objecttable);
+ BLI_listbase_clear(&envre->customdata_names);
+ envre->raytree = NULL;
+ BLI_listbase_clear(&envre->instancetable);
+ envre->objectinstance = NULL;
+ envre->qmcsamplers = NULL;
+
+ RE_FreeRender(envre);
+}
+
+/* ------------------------------------------------------------------------- */
+
+static void envmap_transmatrix(float mat[4][4], int part)
+{
+ float tmat[4][4], eul[3], rotmat[4][4];
+
+ eul[0] = eul[1] = eul[2] = 0.0;
+
+ if (part == 0) { /* neg z */
+ /* pass */
+ }
+ else if (part == 1) { /* pos z */
+ eul[0] = M_PI;
+ }
+ else if (part == 2) { /* pos y */
+ eul[0] = M_PI / 2.0;
+ }
+ else if (part == 3) { /* neg x */
+ eul[0] = M_PI / 2.0;
+ eul[2] = M_PI / 2.0;
+ }
+ else if (part == 4) { /* neg y */
+ eul[0] = M_PI / 2.0;
+ eul[2] = M_PI;
+ }
+ else { /* pos x */
+ eul[0] = M_PI / 2.0;
+ eul[2] = -M_PI / 2.0;
+ }
+
+ copy_m4_m4(tmat, mat);
+ eul_to_mat4(rotmat, eul);
+ mul_m4_m4m4(mat, tmat, rotmat);
+}
+/* ------------------------------------------------------------------------- */
+
+static void env_set_imats(Render *re)
+{
+ Base *base;
+ float mat[4][4];
+
+ base = re->scene->base.first;
+ while (base) {
+ mul_m4_m4m4(mat, re->viewmat, base->object->obmat);
+ invert_m4_m4(base->object->imat, mat);
+
+ base = base->next;
+ }
+
+}
+
+/* ------------------------------------------------------------------------- */
+
+void env_rotate_scene(Render *re, float mat[4][4], int do_rotate)
+{
+ ObjectRen *obr;
+ ObjectInstanceRen *obi;
+ LampRen *lar = NULL;
+ HaloRen *har = NULL;
+ float imat[3][3], mat_inverse[4][4], smat[4][4], tmat[4][4], cmat[3][3], tmpmat[4][4];
+ int a;
+
+ if (do_rotate == 0) {
+ invert_m4_m4(tmat, mat);
+ copy_m3_m4(imat, tmat);
+
+ copy_m4_m4(mat_inverse, mat);
+ }
+ else {
+ copy_m4_m4(tmat, mat);
+ copy_m3_m4(imat, mat);
+
+ invert_m4_m4(mat_inverse, tmat);
+ }
+
+ for (obi = re->instancetable.first; obi; obi = obi->next) {
+ /* append or set matrix depending on dupli */
+ if (obi->flag & R_DUPLI_TRANSFORMED) {
+ copy_m4_m4(tmpmat, obi->mat);
+ mul_m4_m4m4(obi->mat, tmat, tmpmat);
+ }
+ else if (do_rotate == 1)
+ copy_m4_m4(obi->mat, tmat);
+ else
+ unit_m4(obi->mat);
+
+ copy_m3_m4(cmat, obi->mat);
+ invert_m3_m3(obi->nmat, cmat);
+ transpose_m3(obi->nmat);
+
+ /* indicate the renderer has to use transform matrices */
+ if (do_rotate == 0)
+ obi->flag &= ~R_ENV_TRANSFORMED;
+ else {
+ obi->flag |= R_ENV_TRANSFORMED;
+ copy_m4_m4(obi->imat, mat_inverse);
+ }
+ }
+
+
+ for (obr = re->objecttable.first; obr; obr = obr->next) {
+ for (a = 0; a < obr->tothalo; a++) {
+ if ((a & 255) == 0) har = obr->bloha[a >> 8];
+ else har++;
+
+ mul_m4_v3(tmat, har->co);
+ }
+
+ /* imat_ren is needed for correct texture coordinates */
+ mul_m4_m4m4(obr->ob->imat_ren, re->viewmat, obr->ob->obmat);
+ invert_m4(obr->ob->imat_ren);
+ }
+
+ for (lar = re->lampren.first; lar; lar = lar->next) {
+ float lamp_imat[4][4];
+
+ /* copy from add_render_lamp */
+ if (do_rotate == 1)
+ mul_m4_m4m4(tmpmat, re->viewmat, lar->lampmat);
+ else
+ mul_m4_m4m4(tmpmat, re->viewmat_orig, lar->lampmat);
+
+ invert_m4_m4(lamp_imat, tmpmat);
+ copy_m3_m4(lar->mat, tmpmat);
+ copy_m3_m4(lar->imat, lamp_imat);
+
+ lar->vec[0]= -tmpmat[2][0];
+ lar->vec[1]= -tmpmat[2][1];
+ lar->vec[2]= -tmpmat[2][2];
+ normalize_v3(lar->vec);
+ lar->co[0]= tmpmat[3][0];
+ lar->co[1]= tmpmat[3][1];
+ lar->co[2]= tmpmat[3][2];
+
+ if (lar->type == LA_AREA) {
+ area_lamp_vectors(lar);
+ }
+ else if (lar->type == LA_SPOT) {
+ normalize_v3(lar->imat[0]);
+ normalize_v3(lar->imat[1]);
+ normalize_v3(lar->imat[2]);
+
+ lar->sh_invcampos[0] = -lar->co[0];
+ lar->sh_invcampos[1] = -lar->co[1];
+ lar->sh_invcampos[2] = -lar->co[2];
+ mul_m3_v3(lar->imat, lar->sh_invcampos);
+ lar->sh_invcampos[2] *= lar->sh_zfac;
+
+ if (lar->shb) {
+ if (do_rotate == 1) {
+ mul_m4_m4m4(smat, lar->shb->viewmat, mat_inverse);
+ mul_m4_m4m4(lar->shb->persmat, lar->shb->winmat, smat);
+ }
+ else mul_m4_m4m4(lar->shb->persmat, lar->shb->winmat, lar->shb->viewmat);
+ }
+ }
+ }
+
+ if (do_rotate) {
+ init_render_world(re);
+ env_set_imats(re);
+ }
+}
+
+/* ------------------------------------------------------------------------- */
+
+static void env_layerflags(Render *re, unsigned int notlay)
+{
+ ObjectRen *obr;
+ VlakRen *vlr = NULL;
+ int a;
+
+ /* invert notlay, so if face is in multiple layers it will still be visible,
+ * unless all 'notlay' bits match the face bits.
+ * face: 0110
+ * not: 0100
+ * ~not: 1011
+ * now (face & ~not) is true
+ */
+
+ notlay = ~notlay;
+
+ for (obr = re->objecttable.first; obr; obr = obr->next) {
+ if ((obr->lay & notlay) == 0) {
+ for (a = 0; a < obr->totvlak; a++) {
+ if ((a & 255) == 0) vlr = obr->vlaknodes[a >> 8].vlak;
+ else vlr++;
+
+ vlr->flag |= R_HIDDEN;
+ }
+ }
+ }
+}
+
+static void env_hideobject(Render *re, Object *ob)
+{
+ ObjectRen *obr;
+ VlakRen *vlr = NULL;
+ int a;
+
+ for (obr = re->objecttable.first; obr; obr = obr->next) {
+ for (a = 0; a < obr->totvlak; a++) {
+ if ((a & 255) == 0) vlr = obr->vlaknodes[a >> 8].vlak;
+ else vlr++;
+
+ if (obr->ob == ob)
+ vlr->flag |= R_HIDDEN;
+ }
+ }
+}
+
+static void env_showobjects(Render *re)
+{
+ ObjectRen *obr;
+ VlakRen *vlr = NULL;
+ int a;
+
+ for (obr = re->objecttable.first; obr; obr = obr->next) {
+ for (a = 0; a < obr->totvlak; a++) {
+ if ((a & 255) == 0) vlr = obr->vlaknodes[a >> 8].vlak;
+ else vlr++;
+
+ vlr->flag &= ~R_HIDDEN;
+ }
+ }
+}
+
+/* ------------------------------------------------------------------------- */
+
+static void render_envmap(Render *re, EnvMap *env)
+{
+ /* only the cubemap and planar map is implemented */
+ Render *envre;
+ ImBuf *ibuf;
+ float orthmat[4][4];
+ float oldviewinv[4][4], mat[4][4], tmat[4][4];
+ short part;
+
+ /* need a recalc: ortho-render has no correct viewinv */
+ invert_m4_m4(oldviewinv, re->viewmat);
+
+ envre = envmap_render_copy(re, env);
+
+ /* precalc orthmat for object */
+ copy_m4_m4(orthmat, env->object->obmat);
+ normalize_m4(orthmat);
+
+ /* need imat later for texture imat */
+ mul_m4_m4m4(mat, re->viewmat, orthmat);
+ invert_m4_m4(tmat, mat);
+ copy_m3_m4(env->obimat, tmat);
+
+ for (part = 0; part < 6; part++) {
+ if (env->type == ENV_PLANE && part != 1)
+ continue;
+
+ re->display_clear(re->dch, envre->result);
+
+ copy_m4_m4(tmat, orthmat);
+ envmap_transmatrix(tmat, part);
+ invert_m4_m4(mat, tmat);
+ /* mat now is the camera 'viewmat' */
+
+ copy_m4_m4(envre->viewmat, mat);
+ copy_m4_m4(envre->viewinv, tmat);
+
+ /* we have to correct for the already rotated vertexcoords */
+ mul_m4_m4m4(tmat, envre->viewmat, oldviewinv);
+ invert_m4_m4(env->imat, tmat);
+
+ env_rotate_scene(envre, tmat, 1);
+ project_renderdata(envre, projectverto, 0, 0, 1);
+ env_layerflags(envre, env->notlay);
+ env_hideobject(envre, env->object);
+
+ if (re->test_break(re->tbh) == 0) {
+ RE_TileProcessor(envre);
+ }
+
+ /* rotate back */
+ env_showobjects(envre);
+ env_rotate_scene(envre, tmat, 0);
+
+ if (re->test_break(re->tbh) == 0) {
+ int y;
+ float *alpha;
+ float *rect;
+
+ if (envre->result->do_exr_tile) {
+ BLI_rw_mutex_lock(&envre->resultmutex, THREAD_LOCK_WRITE);
+ render_result_exr_file_end(envre);
+ BLI_rw_mutex_unlock(&envre->resultmutex);
+ }
+
+ RenderLayer *rl = envre->result->layers.first;
+
+ /* envmap is rendered independently of multiview */
+ rect = RE_RenderLayerGetPass(rl, RE_PASSNAME_COMBINED, "");
+ ibuf = IMB_allocImBuf(envre->rectx, envre->recty, 24, IB_rect | IB_rectfloat);
+ memcpy(ibuf->rect_float, rect, ibuf->channels * ibuf->x * ibuf->y * sizeof(float));
+
+ /* envmap renders without alpha */
+ alpha = ibuf->rect_float + 3;
+ for (y = ibuf->x * ibuf->y - 1; y >= 0; y--, alpha += 4)
+ *alpha = 1.0;
+
+ env->cube[part] = ibuf;
+ }
+
+ if (re->test_break(re->tbh)) break;
+
+ }
+
+ if (re->test_break(re->tbh)) BKE_texture_envmap_free_data(env);
+ else {
+ if (envre->r.mode & R_OSA) env->ok = ENV_OSA;
+ else env->ok = ENV_NORMAL;
+ env->lastframe = re->scene->r.cfra;
+ }
+
+ /* restore */
+ envmap_free_render_copy(envre);
+ env_set_imats(re);
+
+}
+
+/* ------------------------------------------------------------------------- */
+
+void make_envmaps(Render *re)
+{
+ Tex *tex;
+ bool do_init = false;
+ int depth = 0, trace;
+
+ if (!(re->r.mode & R_ENVMAP)) return;
+
+ /* we don't raytrace, disabling the flag will cause ray_transp render solid */
+ trace = (re->r.mode & R_RAYTRACE);
+ re->r.mode &= ~R_RAYTRACE;
+
+ re->i.infostr = IFACE_("Creating Environment maps");
+ re->stats_draw(re->sdh, &re->i);
+
+ /* 5 = hardcoded max recursion level */
+ while (depth < 5) {
+ tex = re->main->tex.first;
+ while (tex) {
+ if (tex->id.us && tex->type == TEX_ENVMAP) {
+ if (tex->env && tex->env->object) {
+ EnvMap *env = tex->env;
+
+ if (env->object->lay & re->lay) {
+ if (env->stype == ENV_LOAD) {
+ float orthmat[4][4], mat[4][4], tmat[4][4];
+
+ /* precalc orthmat for object */
+ copy_m4_m4(orthmat, env->object->obmat);
+ normalize_m4(orthmat);
+
+ /* need imat later for texture imat */
+ mul_m4_m4m4(mat, re->viewmat, orthmat);
+ invert_m4_m4(tmat, mat);
+ copy_m3_m4(env->obimat, tmat);
+ }
+ else {
+
+ /* decide if to render an envmap (again) */
+ if (env->depth >= depth) {
+
+ /* set 'recalc' to make sure it does an entire loop of recalcs */
+
+ if (env->ok) {
+ /* free when OSA, and old one isn't OSA */
+ if ((re->r.mode & R_OSA) && env->ok == ENV_NORMAL)
+ BKE_texture_envmap_free_data(env);
+ /* free when size larger */
+ else if (env->lastsize < re->r.size)
+ BKE_texture_envmap_free_data(env);
+ /* free when env is in recalcmode */
+ else if (env->recalc)
+ BKE_texture_envmap_free_data(env);
+ }
+
+ if (env->ok == 0 && depth == 0) env->recalc = 1;
+
+ if (env->ok == 0) {
+ do_init = true;
+ render_envmap(re, env);
+
+ if (depth == env->depth) env->recalc = 0;
+ }
+ }
+ }
+ }
+ }
+ }
+ tex = tex->id.next;
+ }
+ depth++;
+ }
+
+ if (do_init) {
+ re->display_init(re->dih, re->result);
+ re->display_clear(re->dch, re->result);
+ // re->flag |= R_REDRAW_PRV;
+ }
+ /* restore */
+ re->r.mode |= trace;
+
+}
+
+/* ------------------------------------------------------------------------- */
+
+static int envcube_isect(EnvMap *env, const float vec[3], float answ[2])
+{
+ float lambda;
+ int face;
+
+ if (env->type == ENV_PLANE) {
+ face = 1;
+
+ lambda = 1.0f / vec[2];
+ answ[0] = env->viewscale * lambda * vec[0];
+ answ[1] = -env->viewscale * lambda * vec[1];
+ }
+ else {
+ /* which face */
+ if (vec[2] <= -fabsf(vec[0]) && vec[2] <= -fabsf(vec[1]) ) {
+ face = 0;
+ lambda = -1.0f / vec[2];
+ answ[0] = lambda * vec[0];
+ answ[1] = lambda * vec[1];
+ }
+ else if (vec[2] >= fabsf(vec[0]) && vec[2] >= fabsf(vec[1])) {
+ face = 1;
+ lambda = 1.0f / vec[2];
+ answ[0] = lambda * vec[0];
+ answ[1] = -lambda * vec[1];
+ }
+ else if (vec[1] >= fabsf(vec[0])) {
+ face = 2;
+ lambda = 1.0f / vec[1];
+ answ[0] = lambda * vec[0];
+ answ[1] = lambda * vec[2];
+ }
+ else if (vec[0] <= -fabsf(vec[1])) {
+ face = 3;
+ lambda = -1.0f / vec[0];
+ answ[0] = lambda * vec[1];
+ answ[1] = lambda * vec[2];
+ }
+ else if (vec[1] <= -fabsf(vec[0])) {
+ face = 4;
+ lambda = -1.0f / vec[1];
+ answ[0] = -lambda * vec[0];
+ answ[1] = lambda * vec[2];
+ }
+ else {
+ face = 5;
+ lambda = 1.0f / vec[0];
+ answ[0] = -lambda * vec[1];
+ answ[1] = lambda * vec[2];
+ }
+ }
+
+ answ[0] = 0.5f + 0.5f * answ[0];
+ answ[1] = 0.5f + 0.5f * answ[1];
+ return face;
+}
+
+/* ------------------------------------------------------------------------- */
+
+static void set_dxtdyt(float r_dxt[3], float r_dyt[3], const float dxt[3], const float dyt[3], int face)
+{
+ if (face == 2 || face == 4) {
+ r_dxt[0] = dxt[0];
+ r_dyt[0] = dyt[0];
+ r_dxt[1] = dxt[2];
+ r_dyt[1] = dyt[2];
+ }
+ else if (face == 3 || face == 5) {
+ r_dxt[0] = dxt[1];
+ r_dxt[1] = dxt[2];
+ r_dyt[0] = dyt[1];
+ r_dyt[1] = dyt[2];
+ }
+ else {
+ r_dxt[0] = dxt[0];
+ r_dyt[0] = dyt[0];
+ r_dxt[1] = dxt[1];
+ r_dyt[1] = dyt[1];
+ }
+}
+
+/* ------------------------------------------------------------------------- */
+
+int envmaptex(Tex *tex, const float texvec[3], float dxt[3], float dyt[3], int osatex, TexResult *texres, struct ImagePool *pool, const bool skip_load_image)
+{
+ extern Render R; /* only in this call */
+ /* texvec should be the already reflected normal */
+ EnvMap *env;
+ ImBuf *ibuf;
+ float fac, vec[3], sco[3], dxts[3], dyts[3];
+ int face, face1;
+
+ env = tex->env;
+ if (env == NULL || (env->stype != ENV_LOAD && env->object == NULL)) {
+ texres->tin = 0.0;
+ return 0;
+ }
+
+ if (env->stype == ENV_LOAD) {
+ env->ima = tex->ima;
+ if (env->ima && env->ima->ok) {
+ if (env->cube[1] == NULL) {
+ ImBuf *ibuf_ima = BKE_image_pool_acquire_ibuf(env->ima, NULL, pool);
+ if (ibuf_ima)
+ envmap_split_ima(env, ibuf_ima);
+ else
+ env->ok = 0;
+
+ if (env->type == ENV_PLANE)
+ tex->extend = TEX_EXTEND;
+
+ BKE_image_pool_release_ibuf(env->ima, ibuf_ima, pool);
+ }
+ }
+ }
+
+ if (env->ok == 0) {
+ texres->tin = 0.0;
+ return 0;
+ }
+
+ /* rotate to envmap space, if object is set */
+ copy_v3_v3(vec, texvec);
+ if (env->object) {
+ mul_m3_v3(env->obimat, vec);
+ if (osatex) {
+ mul_m3_v3(env->obimat, dxt);
+ mul_m3_v3(env->obimat, dyt);
+ }
+ }
+ else {
+ if (!BKE_scene_use_world_space_shading(R.scene)) {
+ // texvec is in view space
+ mul_mat3_m4_v3(R.viewinv, vec);
+ if (osatex) {
+ mul_mat3_m4_v3(R.viewinv, dxt);
+ mul_mat3_m4_v3(R.viewinv, dyt);
+ }
+ }
+ }
+
+ face = envcube_isect(env, vec, sco);
+ ibuf = env->cube[face];
+
+ if (osatex) {
+ set_dxtdyt(dxts, dyts, dxt, dyt, face);
+ imagewraposa(tex, NULL, ibuf, sco, dxts, dyts, texres, pool, skip_load_image);
+
+ /* edges? */
+
+ if (texres->ta < 1.0f) {
+ TexResult texr1, texr2;
+
+ texr1.nor = texr2.nor = NULL;
+ texr1.talpha = texr2.talpha = texres->talpha; /* boxclip expects this initialized */
+
+ add_v3_v3(vec, dxt);
+ face1 = envcube_isect(env, vec, sco);
+ sub_v3_v3(vec, dxt);
+
+ if (face != face1) {
+ ibuf = env->cube[face1];
+ set_dxtdyt(dxts, dyts, dxt, dyt, face1);
+ imagewraposa(tex, NULL, ibuf, sco, dxts, dyts, &texr1, pool, skip_load_image);
+ }
+ else texr1.tr = texr1.tg = texr1.tb = texr1.ta = 0.0;
+
+ /* here was the nasty bug! results were not zero-ed. FPE! */
+
+ add_v3_v3(vec, dyt);
+ face1 = envcube_isect(env, vec, sco);
+ sub_v3_v3(vec, dyt);
+
+ if (face != face1) {
+ ibuf = env->cube[face1];
+ set_dxtdyt(dxts, dyts, dxt, dyt, face1);
+ imagewraposa(tex, NULL, ibuf, sco, dxts, dyts, &texr2, pool, skip_load_image);
+ }
+ else texr2.tr = texr2.tg = texr2.tb = texr2.ta = 0.0;
+
+ fac = (texres->ta + texr1.ta + texr2.ta);
+ if (fac != 0.0f) {
+ fac = 1.0f / fac;
+
+ texres->tr = fac * (texres->ta * texres->tr + texr1.ta * texr1.tr + texr2.ta * texr2.tr);
+ texres->tg = fac * (texres->ta * texres->tg + texr1.ta * texr1.tg + texr2.ta * texr2.tg);
+ texres->tb = fac * (texres->ta * texres->tb + texr1.ta * texr1.tb + texr2.ta * texr2.tb);
+ }
+ texres->ta = 1.0;
+ }
+ }
+ else {
+ imagewrap(tex, NULL, ibuf, sco, texres, pool, skip_load_image);
+ }
+
+ return 1;
+}
diff --git a/source/blender/render/intern/source/external_engine.c b/source/blender/render/intern/source/external_engine.c
index b541c993bc7..6e4336f80ea 100644
--- a/source/blender/render/intern/source/external_engine.c
+++ b/source/blender/render/intern/source/external_engine.c
@@ -112,11 +112,11 @@ void RE_engines_register(RenderEngineType *render_type)
RenderEngineType *RE_engines_find(const char *idname)
{
RenderEngineType *type;
-
+
type = BLI_findstring(&R_engines, idname, offsetof(RenderEngineType, idname));
if (!type)
type = BLI_findstring(&R_engines, "BLENDER_EEVEE", offsetof(RenderEngineType, idname));
-
+
return type;
}
@@ -320,7 +320,7 @@ int RE_engine_test_break(RenderEngine *engine)
if (re)
return re->test_break(re->tbh);
-
+
return 0;
}
@@ -497,7 +497,7 @@ static void engine_depsgraph_init(RenderEngine *engine, ViewLayer *view_layer)
engine->depsgraph = DEG_graph_new(scene, view_layer, DAG_EVAL_RENDER);
DEG_debug_name_set(engine->depsgraph, "RENDER");
- BKE_scene_graph_update_tagged(engine->depsgraph, bmain);
+ BKE_scene_graph_update_for_newframe(engine->depsgraph, bmain);
}
static void engine_depsgraph_free(RenderEngine *engine)
@@ -776,7 +776,7 @@ int RE_engine_render(Render *re, int do_all)
if (BKE_reports_contain(re->reports, RPT_ERROR))
G.is_break = true;
-
+
#ifdef WITH_FREESTYLE
if (re->r.mode & R_EDGE_FRS)
RE_RenderFreestyleExternal(re);
diff --git a/source/blender/render/intern/source/imagetexture.c b/source/blender/render/intern/source/imagetexture.c
index b9d55916f51..1e9ad79e599 100644
--- a/source/blender/render/intern/source/imagetexture.c
+++ b/source/blender/render/intern/source/imagetexture.c
@@ -32,7 +32,7 @@
#include <fcntl.h>
#include <math.h>
#include <float.h>
-#ifndef WIN32
+#ifndef WIN32
#include <unistd.h>
#else
#include <io.h>
@@ -67,7 +67,7 @@ static void boxsample(ImBuf *ibuf, float minx, float miny, float maxx, float max
static void ibuf_get_color(float col[4], struct ImBuf *ibuf, int x, int y)
{
int ofs = y * ibuf->x + x;
-
+
if (ibuf->rect_float) {
if (ibuf->channels==4) {
const float *fp= ibuf->rect_float + 4*ofs;
@@ -105,15 +105,15 @@ int imagewrap(Tex *tex, Image *ima, ImBuf *ibuf, const float texvec[3], TexResul
int xi, yi; /* original values */
texres->tin= texres->ta= texres->tr= texres->tg= texres->tb= 0.0f;
-
+
/* we need to set retval OK, otherwise texture code generates normals itself... */
retval= texres->nor ? 3 : 1;
-
+
/* quick tests */
if (ibuf==NULL && ima==NULL)
return retval;
if (ima) {
-
+
/* hack for icon render */
if (skip_load_image && !BKE_image_has_loaded_ibuf(ima))
return retval;
@@ -127,7 +127,7 @@ int imagewrap(Tex *tex, Image *ima, ImBuf *ibuf, const float texvec[3], TexResul
BKE_image_pool_release_ibuf(ima, ibuf, pool);
return retval;
}
-
+
/* setup mapping */
if (tex->imaflag & TEX_IMAROT) {
fy= texvec[0];
@@ -137,10 +137,10 @@ int imagewrap(Tex *tex, Image *ima, ImBuf *ibuf, const float texvec[3], TexResul
fx= texvec[0];
fy= texvec[1];
}
-
+
if (tex->extend == TEX_CHECKER) {
int xs, ys;
-
+
xs= (int)floor(fx);
ys= (int)floor(fy);
fx-= xs;
@@ -205,7 +205,7 @@ int imagewrap(Tex *tex, Image *ima, ImBuf *ibuf, const float texvec[3], TexResul
if (y<0) y+= ibuf->y;
}
}
-
+
/* keep this before interpolation [#29761] */
if (ima) {
if ((tex->imaflag & TEX_USEALPHA) && (ima->flag & IMA_IGNORE_ALPHA) == 0) {
@@ -232,7 +232,7 @@ int imagewrap(Tex *tex, Image *ima, ImBuf *ibuf, const float texvec[3], TexResul
else { /* no filtering */
ibuf_get_color(&texres->tr, ibuf, x, y);
}
-
+
if (texres->nor) {
if (tex->imaflag & TEX_NORMALMAP) {
/* qdn: normal from color
@@ -283,7 +283,7 @@ int imagewrap(Tex *tex, Image *ima, ImBuf *ibuf, const float texvec[3], TexResul
else {
texres->ta = texres->tin = 1.0;
}
-
+
if (tex->flag & TEX_NEGALPHA) {
texres->ta = 1.0f - texres->ta;
}
@@ -301,7 +301,7 @@ int imagewrap(Tex *tex, Image *ima, ImBuf *ibuf, const float texvec[3], TexResul
BKE_image_pool_release_ibuf(ima, ibuf, pool);
BRICONTRGB;
-
+
return retval;
}
@@ -327,9 +327,9 @@ static void clipx_rctf_swap(rctf *stack, short *count, float x1, float x2)
newrct->xmin = rf->xmin+(x2-x1);
newrct->ymin = rf->ymin;
newrct->ymax = rf->ymax;
-
+
if (newrct->xmin ==newrct->xmax) (*count)--;
-
+
rf->xmin = x1;
}
}
@@ -489,7 +489,7 @@ static void boxsampleclip(struct ImBuf *ibuf, rctf *rf, TexResult *texres)
else {
div= texres->tr= texres->tg= texres->tb= texres->ta= 0.0;
for (y=starty; y<=endy; y++) {
-
+
muly= 1.0;
if (starty==endy) {
@@ -499,10 +499,10 @@ static void boxsampleclip(struct ImBuf *ibuf, rctf *rf, TexResult *texres)
if (y==starty) muly= 1.0f-(rf->ymin - y);
if (y==endy) muly= (rf->ymax - y);
}
-
+
if (startx==endx) {
mulx= muly;
-
+
ibuf_get_color(col, ibuf, startx, y);
texres->ta+= mulx*col[3];
@@ -518,7 +518,7 @@ static void boxsampleclip(struct ImBuf *ibuf, rctf *rf, TexResult *texres)
if (x==endx) mulx*= (rf->xmax - x);
ibuf_get_color(col, ibuf, x, y);
-
+
if (mulx==1.0f) {
texres->ta+= col[3];
texres->tr+= col[0];
@@ -573,7 +573,7 @@ static void boxsample(ImBuf *ibuf, float minx, float miny, float maxx, float max
rf->ymax = maxy*(ibuf->y);
texr.talpha= texres->talpha; /* is read by boxsample_clip */
-
+
if (imapextend) {
CLAMP(rf->xmin, 0.0f, ibuf->x-1);
CLAMP(rf->xmax, 0.0f, ibuf->x-1);
@@ -608,7 +608,7 @@ static void boxsample(ImBuf *ibuf, float minx, float miny, float maxx, float max
tot= texres->tr= texres->tb= texres->tg= texres->ta= 0.0;
while (count--) {
boxsampleclip(ibuf, rf, &texr);
-
+
opp= square_rctf(rf);
tot+= opp;
@@ -629,7 +629,7 @@ static void boxsample(ImBuf *ibuf, float minx, float miny, float maxx, float max
boxsampleclip(ibuf, rf, texres);
if (texres->talpha==0) texres->ta= 1.0;
-
+
if (alphaclip!=1.0f) {
/* premul it all */
texres->tr*= alphaclip;
@@ -637,7 +637,7 @@ static void boxsample(ImBuf *ibuf, float minx, float miny, float maxx, float max
texres->tb*= alphaclip;
texres->ta*= alphaclip;
}
-}
+}
/*-----------------------------------------------------------------------------------------------------------------
* from here, some functions only used for the new filtering */
@@ -874,7 +874,7 @@ static void image_mipmap_test(Tex *tex, ImBuf *ibuf)
{
if (tex->imaflag & TEX_MIPMAP) {
if ((ibuf->flags & IB_fields) == 0) {
-
+
if (ibuf->mipmap[0] && (ibuf->userflags & IB_MIPMAP_INVALID)) {
BLI_thread_lock(LOCK_IMAGE);
if (ibuf->userflags & IB_MIPMAP_INVALID) {
@@ -885,7 +885,7 @@ static void image_mipmap_test(Tex *tex, ImBuf *ibuf)
}
if (ibuf->mipmap[0] == NULL) {
BLI_thread_lock(LOCK_IMAGE);
- if (ibuf->mipmap[0] == NULL)
+ if (ibuf->mipmap[0] == NULL)
IMB_makemipmap(ibuf, tex->imaflag & TEX_GAUSS_MIP);
BLI_thread_unlock(LOCK_IMAGE);
}
@@ -895,7 +895,7 @@ static void image_mipmap_test(Tex *tex, ImBuf *ibuf)
}
}
}
-
+
}
static int imagewraposa_aniso(Tex *tex, Image *ima, ImBuf *ibuf, const float texvec[3], float dxt[2], float dyt[2], TexResult *texres, struct ImagePool *pool, const bool skip_load_image)
@@ -946,7 +946,7 @@ static int imagewraposa_aniso(Tex *tex, Image *ima, ImBuf *ibuf, const float tex
/* mipmap test */
image_mipmap_test(tex, ibuf);
-
+
if (ima) {
if ((tex->imaflag & TEX_USEALPHA) && (ima->flag & IMA_IGNORE_ALPHA) == 0) {
if ((tex->imaflag & TEX_CALCALPHA) == 0) {
@@ -1281,7 +1281,7 @@ static int imagewraposa_aniso(Tex *tex, Image *ima, ImBuf *ibuf, const float tex
else
texres->tin = texres->ta;
if (tex->flag & TEX_NEGALPHA) texres->ta = 1.f - texres->ta;
-
+
if (texres->nor && (tex->imaflag & TEX_NORMALMAP)) { /* normal from color */
/* The invert of the red channel is to make
* the normal map compliant with the outside world.
@@ -1312,7 +1312,7 @@ static int imagewraposa_aniso(Tex *tex, Image *ima, ImBuf *ibuf, const float tex
BKE_image_pool_release_ibuf(ima, ibuf, pool);
BRICONTRGB;
-
+
return retval;
}
@@ -1334,10 +1334,10 @@ int imagewraposa(Tex *tex, Image *ima, ImBuf *ibuf, const float texvec[3], const
return imagewraposa_aniso(tex, ima, ibuf, texvec, dxt, dyt, texres, pool, skip_load_image);
texres->tin= texres->ta= texres->tr= texres->tg= texres->tb= 0.0f;
-
+
/* we need to set retval OK, otherwise texture code generates normals itself... */
retval = texres->nor ? 3 : 1;
-
+
/* quick tests */
if (ibuf==NULL && ima==NULL)
return retval;
@@ -1346,7 +1346,7 @@ int imagewraposa(Tex *tex, Image *ima, ImBuf *ibuf, const float texvec[3], const
/* hack for icon render */
if (skip_load_image && !BKE_image_has_loaded_ibuf(ima))
return retval;
-
+
ibuf = BKE_image_pool_acquire_ibuf(ima, &tex->iuser, pool);
ima->flag|= IMA_USED_FOR_RENDER;
@@ -1356,7 +1356,7 @@ int imagewraposa(Tex *tex, Image *ima, ImBuf *ibuf, const float texvec[3], const
BKE_image_pool_release_ibuf(ima, ibuf, pool);
return retval;
}
-
+
/* mipmap test */
image_mipmap_test(tex, ibuf);
@@ -1367,9 +1367,9 @@ int imagewraposa(Tex *tex, Image *ima, ImBuf *ibuf, const float texvec[3], const
}
}
}
-
+
texr.talpha= texres->talpha;
-
+
if (tex->imaflag & TEX_IMAROT) {
fy= texvec[0];
fx= texvec[1];
@@ -1378,7 +1378,7 @@ int imagewraposa(Tex *tex, Image *ima, ImBuf *ibuf, const float texvec[3], const
fx= texvec[0];
fy= texvec[1];
}
-
+
/* pixel coordinates */
minx = min_fff(dxt[0], dyt[0], dxt[0] + dyt[0]);
@@ -1389,7 +1389,7 @@ int imagewraposa(Tex *tex, Image *ima, ImBuf *ibuf, const float texvec[3], const
/* tex_sharper has been removed */
minx= (maxx-minx)/2.0f;
miny= (maxy-miny)/2.0f;
-
+
if (tex->imaflag & TEX_FILTER_MIN) {
/* make sure the filtersize is minimal in pixels (normal, ref map can have miniature pixel dx/dy) */
float addval= (0.5f * tex->filtersize) / (float) MIN2(ibuf->x, ibuf->y);
@@ -1402,7 +1402,7 @@ int imagewraposa(Tex *tex, Image *ima, ImBuf *ibuf, const float texvec[3], const
else if (tex->filtersize!=1.0f) {
minx*= tex->filtersize;
miny*= tex->filtersize;
-
+
dxt[0]*= tex->filtersize;
dxt[1]*= tex->filtersize;
dyt[0]*= tex->filtersize;
@@ -1410,13 +1410,13 @@ int imagewraposa(Tex *tex, Image *ima, ImBuf *ibuf, const float texvec[3], const
}
if (tex->imaflag & TEX_IMAROT) SWAP(float, minx, miny);
-
+
if (minx>0.25f) minx= 0.25f;
else if (minx<0.00001f) minx= 0.00001f; /* side faces of unit-cube */
if (miny>0.25f) miny= 0.25f;
else if (miny<0.00001f) miny= 0.00001f;
-
+
/* repeat and clip */
imaprepeat= (tex->extend==TEX_REPEAT);
imapextend= (tex->extend==TEX_EXTEND);
@@ -1430,10 +1430,10 @@ int imagewraposa(Tex *tex, Image *ima, ImBuf *ibuf, const float texvec[3], const
if (tex->extend == TEX_CHECKER) {
int xs, ys, xs1, ys1, xs2, ys2, boundary;
-
+
xs= (int)floor(fx);
ys= (int)floor(fy);
-
+
/* both checkers available, no boundary exceptions, checkerdist will eat aliasing */
if ( (tex->flag & TEX_CHECKER_ODD) && (tex->flag & TEX_CHECKER_EVEN) ) {
fx-= xs;
@@ -1447,7 +1447,7 @@ int imagewraposa(Tex *tex, Image *ima, ImBuf *ibuf, const float texvec[3], const
return retval;
}
else {
-
+
xs1= (int)floor(fx-minx);
ys1= (int)floor(fy-miny);
xs2= (int)floor(fx+minx);
@@ -1479,14 +1479,14 @@ int imagewraposa(Tex *tex, Image *ima, ImBuf *ibuf, const float texvec[3], const
if (tex->flag & TEX_CHECKER_ODD) {
if ((xs1+ys) & 1) fx-= xs2;
else fx-= xs1;
-
+
if ((ys1+xs) & 1) fy-= ys2;
else fy-= ys1;
}
if (tex->flag & TEX_CHECKER_EVEN) {
if ((xs1+ys) & 1) fx-= xs1;
else fx-= xs2;
-
+
if ((ys1+xs) & 1) fy-= ys1;
else fy-= ys2;
}
@@ -1525,7 +1525,7 @@ int imagewraposa(Tex *tex, Image *ima, ImBuf *ibuf, const float texvec[3], const
if (fx>1.0f) fx -= (int)(fx);
else if (fx<0.0f) fx+= 1-(int)(fx);
}
-
+
if (imapextend) {
if (fy>1.0f) fy = 1.0f;
else if (fy<0.0f) fy= 0.0f;
@@ -1540,18 +1540,18 @@ int imagewraposa(Tex *tex, Image *ima, ImBuf *ibuf, const float texvec[3], const
if (tex->imaflag & TEX_MIPMAP) {
ImBuf *previbuf, *curibuf;
float bumpscale;
-
+
dx = minx;
dy = miny;
maxd = max_ff(dx, dy);
if (maxd > 0.5f) maxd = 0.5f;
pixsize = 1.0f / (float) MIN2(ibuf->x, ibuf->y);
-
+
bumpscale= pixsize/maxd;
if (bumpscale>1.0f) bumpscale= 1.0f;
else bumpscale*=bumpscale;
-
+
curmap= 0;
previbuf= curibuf= ibuf;
while (curmap < IMB_MIPMAP_LEVELS && ibuf->mipmap[curmap]) {
@@ -1567,12 +1567,12 @@ int imagewraposa(Tex *tex, Image *ima, ImBuf *ibuf, const float texvec[3], const
if (minx < 0.5f / ibuf->x) minx = 0.5f / ibuf->x;
if (miny < 0.5f / ibuf->y) miny = 0.5f / ibuf->y;
}
-
+
if (texres->nor && (tex->imaflag & TEX_NORMALMAP)==0) {
/* a bit extra filter */
//minx*= 1.35f;
//miny*= 1.35f;
-
+
boxsample(curibuf, fx-minx, fy-miny, fx+minx, fy+miny, texres, imaprepeat, imapextend);
val1= texres->tr+texres->tg+texres->tb;
boxsample(curibuf, fx-minx+dxt[0], fy-miny+dxt[1], fx+minx+dxt[0], fy+miny+dxt[1], &texr, imaprepeat, imapextend);
@@ -1583,11 +1583,11 @@ int imagewraposa(Tex *tex, Image *ima, ImBuf *ibuf, const float texvec[3], const
/* don't switch x or y! */
texres->nor[0]= (val1-val2);
texres->nor[1]= (val1-val3);
-
+
if (previbuf!=curibuf) { /* interpolate */
-
+
boxsample(previbuf, fx-minx, fy-miny, fx+minx, fy+miny, &texr, imaprepeat, imapextend);
-
+
/* calc rgb */
dx= 2.0f*(pixsize-maxd)/pixsize;
if (dx>=1.0f) {
@@ -1601,16 +1601,16 @@ int imagewraposa(Tex *tex, Image *ima, ImBuf *ibuf, const float texvec[3], const
texres->tr= dy*texres->tr+ dx*texr.tr;
texres->ta= dy*texres->ta+ dx*texr.ta;
}
-
+
val1= dy*val1+ dx*(texr.tr + texr.tg + texr.tb);
boxsample(previbuf, fx-minx+dxt[0], fy-miny+dxt[1], fx+minx+dxt[0], fy+miny+dxt[1], &texr, imaprepeat, imapextend);
val2= dy*val2+ dx*(texr.tr + texr.tg + texr.tb);
boxsample(previbuf, fx-minx+dyt[0], fy-miny+dyt[1], fx+minx+dyt[0], fy+miny+dyt[1], &texr, imaprepeat, imapextend);
val3= dy*val3+ dx*(texr.tr + texr.tg + texr.tb);
-
+
texres->nor[0]= (val1-val2); /* vals have been interpolated above! */
texres->nor[1]= (val1-val3);
-
+
if (dx<1.0f) {
dy= 1.0f-dx;
texres->tb= dy*texres->tb+ dx*texr.tb;
@@ -1632,9 +1632,9 @@ int imagewraposa(Tex *tex, Image *ima, ImBuf *ibuf, const float texvec[3], const
if (previbuf!=curibuf) { /* interpolate */
boxsample(previbuf, minx, miny, maxx, maxy, &texr, imaprepeat, imapextend);
-
+
fx= 2.0f*(pixsize-maxd)/pixsize;
-
+
if (fx>=1.0f) {
texres->ta= texr.ta; texres->tb= texr.tb;
texres->tg= texr.tg; texres->tr= texr.tr;
@@ -1672,7 +1672,7 @@ int imagewraposa(Tex *tex, Image *ima, ImBuf *ibuf, const float texvec[3], const
else
boxsample(ibuf, fx-minx, fy-miny, fx+minx, fy+miny, texres, imaprepeat, imapextend);
}
-
+
if (tex->imaflag & TEX_CALCALPHA) {
texres->ta = texres->tin = texres->ta * max_fff(texres->tr, texres->tg, texres->tb);
}
@@ -1681,7 +1681,7 @@ int imagewraposa(Tex *tex, Image *ima, ImBuf *ibuf, const float texvec[3], const
}
if (tex->flag & TEX_NEGALPHA) texres->ta= 1.0f-texres->ta;
-
+
if (texres->nor && (tex->imaflag & TEX_NORMALMAP)) {
/* qdn: normal from color
* The invert of the red channel is to make
@@ -1705,7 +1705,7 @@ int imagewraposa(Tex *tex, Image *ima, ImBuf *ibuf, const float texvec[3], const
BKE_image_pool_release_ibuf(ima, ibuf, pool);
BRICONTRGB;
-
+
return retval;
}
@@ -1713,16 +1713,16 @@ void image_sample(Image *ima, float fx, float fy, float dx, float dy, float resu
{
TexResult texres;
ImBuf *ibuf = BKE_image_pool_acquire_ibuf(ima, NULL, pool);
-
+
if (UNLIKELY(ibuf == NULL)) {
zero_v4(result);
return;
}
-
+
texres.talpha = true; /* boxsample expects to be initialized */
boxsample(ibuf, fx, fy, fx + dx, fy + dy, &texres, 0, 1);
copy_v4_v4(result, &texres.tr);
-
+
ima->flag|= IMA_USED_FOR_RENDER;
BKE_image_pool_release_ibuf(ima, ibuf, pool);
@@ -1737,11 +1737,11 @@ void ibuf_sample(ImBuf *ibuf, float fx, float fy, float dx, float dy, float resu
AFD.dyt[0] = dy; AFD.dyt[1] = dy;
//copy_v2_v2(AFD.dxt, dx);
//copy_v2_v2(AFD.dyt, dy);
-
+
AFD.intpol = 1;
AFD.extflag = TXC_EXTD;
ewa_eval(&texres, ibuf, fx, fy, &AFD);
-
+
copy_v4_v4(result, &texres.tr);
}
diff --git a/source/blender/render/intern/source/initrender.c b/source/blender/render/intern/source/initrender.c
index 4274d641674..9611a8a7452 100644
--- a/source/blender/render/intern/source/initrender.c
+++ b/source/blender/render/intern/source/initrender.c
@@ -66,9 +66,9 @@ static float filt_quadratic(float x)
static float filt_cubic(float x)
{
float x2 = x * x;
-
+
if (x < 0.0f) x = -x;
-
+
if (x < 1.0f) return 0.5f * x * x2 - x2 + 2.0f / 3.0f;
if (x < 2.0f) return (2.0f - x) * (2.0f - x) * (2.0f - x) / 6.0f;
return 0.0f;
@@ -78,7 +78,7 @@ static float filt_cubic(float x)
static float filt_catrom(float x)
{
float x2 = x * x;
-
+
if (x < 0.0f) x = -x;
if (x < 1.0f) return 1.5f * x2 * x - 2.5f * x2 + 1.0f;
if (x < 2.0f) return -0.5f * x2 * x + 2.5f * x2 - 4.0f * x + 2.0f;
@@ -108,34 +108,34 @@ static float filt_mitchell(float x) /* Mitchell & Netravali's two-param cubic */
float RE_filter_value(int type, float x)
{
float gaussfac = 1.6f;
-
+
x = ABS(x);
-
+
switch (type) {
case R_FILTER_BOX:
if (x > 1.0f) return 0.0f;
return 1.0f;
-
+
case R_FILTER_TENT:
if (x > 1.0f) return 0.0f;
return 1.0f - x;
-
+
case R_FILTER_GAUSS:
{
const float two_gaussfac2 = 2.0f * gaussfac * gaussfac;
x *= 3.0f * gaussfac;
return 1.0f / sqrtf((float)M_PI * two_gaussfac2) * expf(-x*x / two_gaussfac2);
}
-
+
case R_FILTER_MITCH:
return filt_mitchell(x * gaussfac);
-
+
case R_FILTER_QUAD:
return filt_quadratic(x * gaussfac);
-
+
case R_FILTER_CUBIC:
return filt_cubic(x * gaussfac);
-
+
case R_FILTER_CATROM:
return filt_catrom(x * gaussfac);
}
@@ -221,20 +221,20 @@ void RE_parts_init(Render *re)
{
int nr, xd, yd, partx, party, xparts, yparts;
int xminb, xmaxb, yminb, ymaxb;
-
+
RE_parts_free(re);
-
+
/* this is render info for caller, is not reset when parts are freed! */
re->i.totpart = 0;
re->i.curpart = 0;
re->i.partsdone = 0;
-
+
/* just for readable code.. */
xminb = re->disprect.xmin;
yminb = re->disprect.ymin;
xmaxb = re->disprect.xmax;
ymaxb = re->disprect.ymax;
-
+
RE_parts_clamp(re);
partx = re->partx;
@@ -242,17 +242,17 @@ void RE_parts_init(Render *re)
/* part count */
xparts = (re->rectx + partx - 1) / partx;
yparts = (re->recty + party - 1) / party;
-
+
for (nr = 0; nr < xparts * yparts; nr++) {
rcti disprect;
int rectx, recty;
-
+
xd = (nr % xparts);
yd = (nr - xd) / xparts;
-
+
disprect.xmin = xminb + xd * partx;
disprect.ymin = yminb + yd * party;
-
+
/* ensure we cover the entire picture, so last parts go to end */
if (xd < xparts - 1) {
disprect.xmax = disprect.xmin + partx;
@@ -260,21 +260,21 @@ void RE_parts_init(Render *re)
disprect.xmax = xmaxb;
}
else disprect.xmax = xmaxb;
-
+
if (yd < yparts - 1) {
disprect.ymax = disprect.ymin + party;
if (disprect.ymax > ymaxb)
disprect.ymax = ymaxb;
}
else disprect.ymax = ymaxb;
-
+
rectx = BLI_rcti_size_x(&disprect);
recty = BLI_rcti_size_y(&disprect);
-
+
/* so, now can we add this part? */
if (rectx > 0 && recty > 0) {
RenderPart *pa = MEM_callocN(sizeof(RenderPart), "new part");
-
+
pa->disprect = disprect;
pa->rectx = rectx;
pa->recty = recty;
diff --git a/source/blender/render/intern/source/occlusion.c b/source/blender/render/intern/source/occlusion.c
new file mode 100644
index 00000000000..8aa90a390b3
--- /dev/null
+++ b/source/blender/render/intern/source/occlusion.c
@@ -0,0 +1,1533 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2008 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): Brecht Van Lommel.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/render/intern/source/occlusion.c
+ * \ingroup render
+ */
+
+#include <math.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_material_types.h"
+
+#include "BLI_math.h"
+#include "BLI_memarena.h"
+#include "BLI_threads.h"
+#include "BLI_utildefines.h"
+
+#include "BLT_translation.h"
+
+#include "BKE_node.h"
+#include "BKE_scene.h"
+
+
+#include "RE_shader_ext.h"
+
+/* local includes */
+#include "occlusion.h"
+#include "render_types.h"
+#include "rendercore.h"
+#include "renderdatabase.h"
+#include "shading.h"
+
+/* ------------------------- Declarations --------------------------- */
+
+#define INVPI ((float)M_1_PI)
+#define TOTCHILD 8
+#define CACHE_STEP 3
+
+typedef struct OcclusionCacheSample {
+ float co[3], n[3], ao[3], env[3], indirect[3], intensity, dist2;
+ int x, y, filled;
+} OcclusionCacheSample;
+
+typedef struct OcclusionCache {
+ OcclusionCacheSample *sample;
+ int x, y, w, h, step;
+} OcclusionCache;
+
+typedef struct OccFace {
+ int obi;
+ int facenr;
+} OccFace;
+
+typedef struct OccNode {
+ float co[3], area;
+ float sh[9], dco;
+ float occlusion, rad[3];
+ int childflag;
+ union {
+ //OccFace face;
+ int face;
+ struct OccNode *node;
+ } child[TOTCHILD];
+} OccNode;
+
+typedef struct OcclusionTree {
+ MemArena *arena;
+
+ float (*co)[3]; /* temporary during build */
+
+ OccFace *face; /* instance and face indices */
+ float *occlusion; /* occlusion for faces */
+ float (*rad)[3]; /* radiance for faces */
+
+ OccNode *root;
+
+ OccNode **stack[BLENDER_MAX_THREADS];
+ int maxdepth;
+
+ int totface;
+
+ float error;
+ float distfac;
+
+ int dothreadedbuild;
+ int totbuildthread;
+ int doindirect;
+
+ OcclusionCache *cache;
+
+ int num_threads;
+} OcclusionTree;
+
+typedef struct OcclusionThread {
+ Render *re;
+ StrandSurface *mesh;
+ float (*faceao)[3];
+ float (*faceenv)[3];
+ float (*faceindirect)[3];
+ int begin, end;
+ int thread;
+} OcclusionThread;
+
+typedef struct OcclusionBuildThread {
+ OcclusionTree *tree;
+ int begin, end, depth;
+ OccNode *node;
+} OcclusionBuildThread;
+
+/* ------------------------- Shading --------------------------- */
+
+extern Render R; /* meh */
+
+static void occ_shade(ShadeSample *ssamp, ObjectInstanceRen *obi, VlakRen *vlr, float *rad)
+{
+ ShadeInput *shi = ssamp->shi;
+ ShadeResult *shr = ssamp->shr;
+ float l, u, v, *v1, *v2, *v3;
+
+ /* init */
+ if (vlr->v4) {
+ shi->u = u = 0.5f;
+ shi->v = v = 0.5f;
+ }
+ else {
+ shi->u = u = 1.0f / 3.0f;
+ shi->v = v = 1.0f / 3.0f;
+ }
+
+ /* setup render coordinates */
+ v1 = vlr->v1->co;
+ v2 = vlr->v2->co;
+ v3 = vlr->v3->co;
+
+ /* renderco */
+ l = 1.0f - u - v;
+
+ shi->co[0] = l * v3[0] + u * v1[0] + v * v2[0];
+ shi->co[1] = l * v3[1] + u * v1[1] + v * v2[1];
+ shi->co[2] = l * v3[2] + u * v1[2] + v * v2[2];
+
+ shade_input_set_triangle_i(shi, obi, vlr, 0, 1, 2);
+
+ /* set up view vector */
+ copy_v3_v3(shi->view, shi->co);
+ normalize_v3(shi->view);
+
+ /* cache for shadow */
+ shi->samplenr++;
+
+ shi->xs = 0; /* TODO */
+ shi->ys = 0;
+
+ shade_input_set_normals(shi);
+
+ /* no normal flip */
+ if (shi->flippednor)
+ shade_input_flip_normals(shi);
+
+ madd_v3_v3fl(shi->co, shi->facenor, -0.0001f); /* ugly.. */
+
+ /* not a pretty solution, but fixes common cases */
+ if (shi->obr->ob && shi->obr->ob->transflag & OB_NEG_SCALE) {
+ negate_v3(shi->vn);
+ negate_v3(shi->vno);
+ negate_v3(shi->nmapnorm);
+ }
+
+ /* init material vars */
+ shade_input_init_material(shi);
+
+ /* render */
+ shade_input_set_shade_texco(shi);
+
+ if (shi->mat->nodetree && shi->mat->use_nodes) {
+ ntreeShaderExecTree(shi->mat->nodetree, shi, shr);
+ shi->mat = vlr->mat; /* shi->mat is being set in nodetree */
+ }
+ else {
+ shade_material_loop(shi, shr);
+ }
+
+ copy_v3_v3(rad, shr->combined);
+}
+
+static void occ_build_shade(Render *re, OcclusionTree *tree)
+{
+ ShadeSample ssamp;
+ ObjectInstanceRen *obi;
+ VlakRen *vlr;
+ int a;
+
+ R = *re;
+
+ /* setup shade sample with correct passes */
+ memset(&ssamp, 0, sizeof(ShadeSample));
+ ssamp.shi[0].lay = re->lay;
+ ssamp.shi[0].passflag = SCE_PASS_DIFFUSE | SCE_PASS_RGBA;
+ ssamp.shi[0].combinedflag = ~(SCE_PASS_SPEC);
+ ssamp.tot = 1;
+
+ for (a = 0; a < tree->totface; a++) {
+ obi = &R.objectinstance[tree->face[a].obi];
+ vlr = RE_findOrAddVlak(obi->obr, tree->face[a].facenr);
+
+ occ_shade(&ssamp, obi, vlr, tree->rad[a]);
+
+ if (re->test_break(re->tbh))
+ break;
+ }
+}
+
+/* ------------------------- Spherical Harmonics --------------------------- */
+
+/* Use 2nd order SH => 9 coefficients, stored in this order:
+ * 0 = (0,0),
+ * 1 = (1,-1), 2 = (1,0), 3 = (1,1),
+ * 4 = (2,-2), 5 = (2,-1), 6 = (2,0), 7 = (2,1), 8 = (2,2) */
+
+static void sh_copy(float *shresult, float *sh)
+{
+ memcpy(shresult, sh, sizeof(float) * 9);
+}
+
+static void sh_mul(float *sh, float f)
+{
+ int i;
+
+ for (i = 0; i < 9; i++)
+ sh[i] *= f;
+}
+
+static void sh_add(float *shresult, float *sh1, float *sh2)
+{
+ int i;
+
+ for (i = 0; i < 9; i++)
+ shresult[i] = sh1[i] + sh2[i];
+}
+
+static void sh_from_disc(float *n, float area, float *shresult)
+{
+ /* See formula (3) in:
+ * "An Efficient Representation for Irradiance Environment Maps" */
+ float sh[9], x, y, z;
+
+ x = n[0];
+ y = n[1];
+ z = n[2];
+
+ sh[0] = 0.282095f;
+
+ sh[1] = 0.488603f * y;
+ sh[2] = 0.488603f * z;
+ sh[3] = 0.488603f * x;
+
+ sh[4] = 1.092548f * x * y;
+ sh[5] = 1.092548f * y * z;
+ sh[6] = 0.315392f * (3.0f * z * z - 1.0f);
+ sh[7] = 1.092548f * x * z;
+ sh[8] = 0.546274f * (x * x - y * y);
+
+ sh_mul(sh, area);
+ sh_copy(shresult, sh);
+}
+
+static float sh_eval(float *sh, float *v)
+{
+ /* See formula (13) in:
+ * "An Efficient Representation for Irradiance Environment Maps" */
+ static const float c1 = 0.429043f, c2 = 0.511664f, c3 = 0.743125f;
+ static const float c4 = 0.886227f, c5 = 0.247708f;
+ float x, y, z, sum;
+
+ x = v[0];
+ y = v[1];
+ z = v[2];
+
+ sum = c1 * sh[8] * (x * x - y * y);
+ sum += c3 * sh[6] * z * z;
+ sum += c4 * sh[0];
+ sum += -c5 * sh[6];
+ sum += 2.0f * c1 * (sh[4] * x * y + sh[7] * x * z + sh[5] * y * z);
+ sum += 2.0f * c2 * (sh[3] * x + sh[1] * y + sh[2] * z);
+
+ return sum;
+}
+
+/* ------------------------------ Building --------------------------------- */
+
+static void occ_face(const OccFace *face, float co[3], float normal[3], float *area)
+{
+ ObjectInstanceRen *obi;
+ VlakRen *vlr;
+ float v1[3], v2[3], v3[3], v4[3];
+
+ obi = &R.objectinstance[face->obi];
+ vlr = RE_findOrAddVlak(obi->obr, face->facenr);
+
+ if (co) {
+ if (vlr->v4)
+ mid_v3_v3v3(co, vlr->v1->co, vlr->v3->co);
+ else
+ mid_v3_v3v3v3(co, vlr->v1->co, vlr->v2->co, vlr->v3->co);
+
+ if (obi->flag & R_TRANSFORMED)
+ mul_m4_v3(obi->mat, co);
+ }
+
+ if (normal) {
+ normal[0] = -vlr->n[0];
+ normal[1] = -vlr->n[1];
+ normal[2] = -vlr->n[2];
+
+ if (obi->flag & R_TRANSFORMED)
+ mul_m3_v3(obi->nmat, normal);
+ }
+
+ if (area) {
+ copy_v3_v3(v1, vlr->v1->co);
+ copy_v3_v3(v2, vlr->v2->co);
+ copy_v3_v3(v3, vlr->v3->co);
+ if (vlr->v4) copy_v3_v3(v4, vlr->v4->co);
+
+ if (obi->flag & R_TRANSFORMED) {
+ mul_m4_v3(obi->mat, v1);
+ mul_m4_v3(obi->mat, v2);
+ mul_m4_v3(obi->mat, v3);
+ if (vlr->v4) mul_m4_v3(obi->mat, v4);
+ }
+
+ /* todo: correct area for instances */
+ if (vlr->v4)
+ *area = area_quad_v3(v1, v2, v3, v4);
+ else
+ *area = area_tri_v3(v1, v2, v3);
+ }
+}
+
+static void occ_sum_occlusion(OcclusionTree *tree, OccNode *node)
+{
+ OccNode *child;
+ float occ, area, totarea, rad[3];
+ int a, b, indirect = tree->doindirect;
+
+ occ = 0.0f;
+ totarea = 0.0f;
+ if (indirect) zero_v3(rad);
+
+ for (b = 0; b < TOTCHILD; b++) {
+ if (node->childflag & (1 << b)) {
+ a = node->child[b].face;
+ occ_face(&tree->face[a], NULL, NULL, &area);
+ occ += area * tree->occlusion[a];
+ if (indirect) madd_v3_v3fl(rad, tree->rad[a], area);
+ totarea += area;
+ }
+ else if (node->child[b].node) {
+ child = node->child[b].node;
+ occ_sum_occlusion(tree, child);
+
+ occ += child->area * child->occlusion;
+ if (indirect) madd_v3_v3fl(rad, child->rad, child->area);
+ totarea += child->area;
+ }
+ }
+
+ if (totarea != 0.0f) {
+ occ /= totarea;
+ if (indirect) mul_v3_fl(rad, 1.0f / totarea);
+ }
+
+ node->occlusion = occ;
+ if (indirect) copy_v3_v3(node->rad, rad);
+}
+
+static int occ_find_bbox_axis(OcclusionTree *tree, int begin, int end, float *min, float *max)
+{
+ float len, maxlen = -1.0f;
+ int a, axis = 0;
+
+ INIT_MINMAX(min, max);
+
+ for (a = begin; a < end; a++) {
+ minmax_v3v3_v3(min, max, tree->co[a]);
+ }
+
+ for (a = 0; a < 3; a++) {
+ len = max[a] - min[a];
+
+ if (len > maxlen) {
+ maxlen = len;
+ axis = a;
+ }
+ }
+
+ return axis;
+}
+
+static void occ_node_from_face(OccFace *face, OccNode *node)
+{
+ float n[3];
+
+ occ_face(face, node->co, n, &node->area);
+ node->dco = 0.0f;
+ sh_from_disc(n, node->area, node->sh);
+}
+
+static void occ_build_dco(OcclusionTree *tree, OccNode *node, const float co[3], float *dco)
+{
+ int b;
+ for (b = 0; b < TOTCHILD; b++) {
+ float dist, d[3], nco[3];
+
+ if (node->childflag & (1 << b)) {
+ occ_face(tree->face + node->child[b].face, nco, NULL, NULL);
+ }
+ else if (node->child[b].node) {
+ OccNode *child = node->child[b].node;
+ occ_build_dco(tree, child, co, dco);
+ copy_v3_v3(nco, child->co);
+ }
+ else {
+ continue;
+ }
+
+ sub_v3_v3v3(d, nco, co);
+ dist = dot_v3v3(d, d);
+ if (dist > *dco)
+ *dco = dist;
+ }
+}
+
+static void occ_build_split(OcclusionTree *tree, int begin, int end, int *split)
+{
+ float min[3], max[3], mid;
+ int axis, a, enda;
+
+ /* split in middle of boundbox. this seems faster than median split
+ * on complex scenes, possibly since it avoids two distant faces to
+ * be in the same node better? */
+ axis = occ_find_bbox_axis(tree, begin, end, min, max);
+ mid = 0.5f * (min[axis] + max[axis]);
+
+ a = begin;
+ enda = end;
+ while (a < enda) {
+ if (tree->co[a][axis] > mid) {
+ enda--;
+ SWAP(OccFace, tree->face[a], tree->face[enda]);
+ swap_v3_v3(tree->co[a], tree->co[enda]);
+ }
+ else
+ a++;
+ }
+
+ *split = enda;
+}
+
+static void occ_build_8_split(OcclusionTree *tree, int begin, int end, int *offset, int *count)
+{
+ /* split faces into eight groups */
+ int b, splitx, splity[2], splitz[4];
+
+ occ_build_split(tree, begin, end, &splitx);
+
+ /* force split if none found, to deal with degenerate geometry */
+ if (splitx == begin || splitx == end)
+ splitx = (begin + end) / 2;
+
+ occ_build_split(tree, begin, splitx, &splity[0]);
+ occ_build_split(tree, splitx, end, &splity[1]);
+
+ occ_build_split(tree, begin, splity[0], &splitz[0]);
+ occ_build_split(tree, splity[0], splitx, &splitz[1]);
+ occ_build_split(tree, splitx, splity[1], &splitz[2]);
+ occ_build_split(tree, splity[1], end, &splitz[3]);
+
+ offset[0] = begin;
+ offset[1] = splitz[0];
+ offset[2] = splity[0];
+ offset[3] = splitz[1];
+ offset[4] = splitx;
+ offset[5] = splitz[2];
+ offset[6] = splity[1];
+ offset[7] = splitz[3];
+
+ for (b = 0; b < 7; b++)
+ count[b] = offset[b + 1] - offset[b];
+ count[7] = end - offset[7];
+}
+
+static void occ_build_recursive(OcclusionTree *tree, OccNode *node, int begin, int end, int depth);
+
+static void *exec_occ_build(void *data)
+{
+ OcclusionBuildThread *othread = (OcclusionBuildThread *)data;
+
+ occ_build_recursive(othread->tree, othread->node, othread->begin, othread->end, othread->depth);
+
+ return NULL;
+}
+
+static void occ_build_recursive(OcclusionTree *tree, OccNode *node, int begin, int end, int depth)
+{
+ ListBase threads;
+ OcclusionBuildThread othreads[BLENDER_MAX_THREADS];
+ OccNode *child, tmpnode;
+ /* OccFace *face; */
+ int a, b, totthread = 0, offset[TOTCHILD], count[TOTCHILD];
+
+ /* add a new node */
+ node->occlusion = 1.0f;
+
+ /* leaf node with only children */
+ if (end - begin <= TOTCHILD) {
+ for (a = begin, b = 0; a < end; a++, b++) {
+ /* face= &tree->face[a]; */
+ node->child[b].face = a;
+ node->childflag |= (1 << b);
+ }
+ }
+ else {
+ /* order faces */
+ occ_build_8_split(tree, begin, end, offset, count);
+
+ if (depth == 1 && tree->dothreadedbuild)
+ BLI_threadpool_init(&threads, exec_occ_build, tree->totbuildthread);
+
+ for (b = 0; b < TOTCHILD; b++) {
+ if (count[b] == 0) {
+ node->child[b].node = NULL;
+ }
+ else if (count[b] == 1) {
+ /* face= &tree->face[offset[b]]; */
+ node->child[b].face = offset[b];
+ node->childflag |= (1 << b);
+ }
+ else {
+ if (tree->dothreadedbuild)
+ BLI_thread_lock(LOCK_CUSTOM1);
+
+ child = BLI_memarena_alloc(tree->arena, sizeof(OccNode));
+ node->child[b].node = child;
+
+ /* keep track of maximum depth for stack */
+ if (depth >= tree->maxdepth)
+ tree->maxdepth = depth + 1;
+
+ if (tree->dothreadedbuild)
+ BLI_thread_unlock(LOCK_CUSTOM1);
+
+ if (depth == 1 && tree->dothreadedbuild) {
+ othreads[totthread].tree = tree;
+ othreads[totthread].node = child;
+ othreads[totthread].begin = offset[b];
+ othreads[totthread].end = offset[b] + count[b];
+ othreads[totthread].depth = depth + 1;
+ BLI_threadpool_insert(&threads, &othreads[totthread]);
+ totthread++;
+ }
+ else
+ occ_build_recursive(tree, child, offset[b], offset[b] + count[b], depth + 1);
+ }
+ }
+
+ if (depth == 1 && tree->dothreadedbuild)
+ BLI_threadpool_end(&threads);
+ }
+
+ /* combine area, position and sh */
+ for (b = 0; b < TOTCHILD; b++) {
+ if (node->childflag & (1 << b)) {
+ child = &tmpnode;
+ occ_node_from_face(tree->face + node->child[b].face, &tmpnode);
+ }
+ else {
+ child = node->child[b].node;
+ }
+
+ if (child) {
+ node->area += child->area;
+ sh_add(node->sh, node->sh, child->sh);
+ madd_v3_v3fl(node->co, child->co, child->area);
+ }
+ }
+
+ if (node->area != 0.0f)
+ mul_v3_fl(node->co, 1.0f / node->area);
+
+ /* compute maximum distance from center */
+ node->dco = 0.0f;
+ if (node->area > 0.0f)
+ occ_build_dco(tree, node, node->co, &node->dco);
+}
+
+static void occ_build_sh_normalize(OccNode *node)
+{
+ /* normalize spherical harmonics to not include area, so
+ * we can clamp the dot product and then multiply by area */
+ int b;
+
+ if (node->area != 0.0f)
+ sh_mul(node->sh, 1.0f / node->area);
+
+ for (b = 0; b < TOTCHILD; b++) {
+ if (node->childflag & (1 << b)) {
+ /* pass */
+ }
+ else if (node->child[b].node) {
+ occ_build_sh_normalize(node->child[b].node);
+ }
+ }
+}
+
+static OcclusionTree *occ_tree_build(Render *re)
+{
+ const int num_threads = re->r.threads;
+ OcclusionTree *tree;
+ ObjectInstanceRen *obi;
+ ObjectRen *obr;
+ Material *ma;
+ VlakRen *vlr = NULL;
+ int a, b, c, totface;
+
+ /* count */
+ totface = 0;
+ for (obi = re->instancetable.first; obi; obi = obi->next) {
+ obr = obi->obr;
+ for (a = 0; a < obr->totvlak; a++) {
+ if ((a & 255) == 0) vlr = obr->vlaknodes[a >> 8].vlak;
+ else vlr++;
+
+ ma = vlr->mat;
+
+ if ((ma->shade_flag & MA_APPROX_OCCLUSION) && (ma->material_type == MA_TYPE_SURFACE))
+ totface++;
+ }
+ }
+
+ if (totface == 0)
+ return NULL;
+
+ tree = MEM_callocN(sizeof(OcclusionTree), "OcclusionTree");
+ tree->totface = totface;
+
+ /* parameters */
+ tree->error = get_render_aosss_error(&re->r, re->wrld.ao_approx_error);
+ tree->distfac = (re->wrld.aomode & WO_AODIST) ? re->wrld.aodistfac : 0.0f;
+ tree->doindirect = (re->wrld.ao_indirect_energy > 0.0f && re->wrld.ao_indirect_bounces > 0);
+
+ /* allocation */
+ tree->arena = BLI_memarena_new(0x8000 * sizeof(OccNode), "occ tree arena");
+ BLI_memarena_use_calloc(tree->arena);
+
+ if (re->wrld.aomode & WO_AOCACHE)
+ tree->cache = MEM_callocN(sizeof(OcclusionCache) * num_threads, "OcclusionCache");
+
+ tree->face = MEM_callocN(sizeof(OccFace) * totface, "OcclusionFace");
+ tree->co = MEM_callocN(sizeof(float) * 3 * totface, "OcclusionCo");
+ tree->occlusion = MEM_callocN(sizeof(float) * totface, "OcclusionOcclusion");
+
+ if (tree->doindirect)
+ tree->rad = MEM_callocN(sizeof(float) * 3 * totface, "OcclusionRad");
+
+ /* make array of face pointers */
+ for (b = 0, c = 0, obi = re->instancetable.first; obi; obi = obi->next, c++) {
+ obr = obi->obr;
+ for (a = 0; a < obr->totvlak; a++) {
+ if ((a & 255) == 0) vlr = obr->vlaknodes[a >> 8].vlak;
+ else vlr++;
+
+ ma = vlr->mat;
+
+ if ((ma->shade_flag & MA_APPROX_OCCLUSION) && (ma->material_type == MA_TYPE_SURFACE)) {
+ tree->face[b].obi = c;
+ tree->face[b].facenr = a;
+ tree->occlusion[b] = 1.0f;
+ occ_face(&tree->face[b], tree->co[b], NULL, NULL);
+ b++;
+ }
+ }
+ }
+
+ /* threads */
+ tree->totbuildthread = (re->r.threads > 1 && totface > 10000) ? 8 : 1;
+ tree->dothreadedbuild = (tree->totbuildthread > 1);
+
+ /* recurse */
+ tree->root = BLI_memarena_alloc(tree->arena, sizeof(OccNode));
+ tree->maxdepth = 1;
+ occ_build_recursive(tree, tree->root, 0, totface, 1);
+
+ if (tree->doindirect) {
+ if (!(re->test_break(re->tbh)))
+ occ_build_shade(re, tree);
+
+ if (!(re->test_break(re->tbh)))
+ occ_sum_occlusion(tree, tree->root);
+ }
+
+ MEM_freeN(tree->co);
+ tree->co = NULL;
+
+ if (!(re->test_break(re->tbh)))
+ occ_build_sh_normalize(tree->root);
+
+ for (a = 0; a < num_threads; a++)
+ tree->stack[a] = MEM_callocN(sizeof(OccNode) * TOTCHILD * (tree->maxdepth + 1), "OccStack");
+
+ tree->num_threads = num_threads;
+
+ return tree;
+}
+
+static void occ_free_tree(OcclusionTree *tree)
+{
+ int a;
+
+ if (tree) {
+ if (tree->arena) BLI_memarena_free(tree->arena);
+ for (a = 0; a < tree->num_threads; a++)
+ if (tree->stack[a])
+ MEM_freeN(tree->stack[a]);
+ if (tree->occlusion) MEM_freeN(tree->occlusion);
+ if (tree->cache) MEM_freeN(tree->cache);
+ if (tree->face) MEM_freeN(tree->face);
+ if (tree->rad) MEM_freeN(tree->rad);
+ MEM_freeN(tree);
+ }
+}
+
+/* ------------------------- Traversal --------------------------- */
+
+static float occ_solid_angle(OccNode *node, const float v[3], float d2, float invd2, const float receivenormal[3])
+{
+ float dotreceive, dotemit;
+ float ev[3];
+
+ ev[0] = -v[0] * invd2;
+ ev[1] = -v[1] * invd2;
+ ev[2] = -v[2] * invd2;
+ dotemit = sh_eval(node->sh, ev);
+ dotreceive = dot_v3v3(receivenormal, v) * invd2;
+
+ CLAMP(dotemit, 0.0f, 1.0f);
+ CLAMP(dotreceive, 0.0f, 1.0f);
+
+ return ((node->area * dotemit * dotreceive) / (d2 + node->area * INVPI)) * INVPI;
+}
+
+static float occ_form_factor(OccFace *face, float *p, float *n)
+{
+ ObjectInstanceRen *obi;
+ VlakRen *vlr;
+ float v1[3], v2[3], v3[3], v4[3], q0[3], q1[3], q2[3], q3[3], contrib = 0.0f;
+
+ obi = &R.objectinstance[face->obi];
+ vlr = RE_findOrAddVlak(obi->obr, face->facenr);
+
+ copy_v3_v3(v1, vlr->v1->co);
+ copy_v3_v3(v2, vlr->v2->co);
+ copy_v3_v3(v3, vlr->v3->co);
+
+ if (obi->flag & R_TRANSFORMED) {
+ mul_m4_v3(obi->mat, v1);
+ mul_m4_v3(obi->mat, v2);
+ mul_m4_v3(obi->mat, v3);
+ }
+
+ if (form_factor_visible_quad(p, n, v1, v2, v3, q0, q1, q2, q3))
+ contrib += form_factor_quad(p, n, q0, q1, q2, q3);
+
+ if (vlr->v4) {
+ copy_v3_v3(v4, vlr->v4->co);
+ if (obi->flag & R_TRANSFORMED)
+ mul_m4_v3(obi->mat, v4);
+
+ if (form_factor_visible_quad(p, n, v1, v3, v4, q0, q1, q2, q3))
+ contrib += form_factor_quad(p, n, q0, q1, q2, q3);
+ }
+
+ return contrib;
+}
+
+static void occ_lookup(OcclusionTree *tree, int thread, OccFace *exclude,
+ const float pp[3], const float pn[3], float *occ, float rad[3], float bentn[3])
+{
+ OccNode *node, **stack;
+ OccFace *face;
+ float resultocc, resultrad[3], v[3], p[3], n[3], co[3], invd2;
+ float distfac, fac, error, d2, weight, emitarea;
+ int b, f, totstack;
+
+ /* init variables */
+ copy_v3_v3(p, pp);
+ copy_v3_v3(n, pn);
+ madd_v3_v3fl(p, n, 1e-4f);
+
+ if (bentn)
+ copy_v3_v3(bentn, n);
+
+ error = tree->error;
+ distfac = tree->distfac;
+
+ resultocc = 0.0f;
+ zero_v3(resultrad);
+
+ /* init stack */
+ stack = tree->stack[thread];
+ stack[0] = tree->root;
+ totstack = 1;
+
+ while (totstack) {
+ /* pop point off the stack */
+ node = stack[--totstack];
+
+ sub_v3_v3v3(v, node->co, p);
+ d2 = dot_v3v3(v, v) + 1e-16f;
+ emitarea = MAX2(node->area, node->dco);
+
+ if (d2 * error > emitarea) {
+ if (distfac != 0.0f) {
+ fac = 1.0f / (1.0f + distfac * d2);
+ if (fac < 0.01f)
+ continue;
+ }
+ else
+ fac = 1.0f;
+
+ /* accumulate occlusion from spherical harmonics */
+ invd2 = 1.0f / sqrtf(d2);
+ weight = occ_solid_angle(node, v, d2, invd2, n);
+
+ if (rad)
+ madd_v3_v3fl(resultrad, node->rad, weight * fac);
+
+ weight *= node->occlusion;
+
+ if (bentn) {
+ bentn[0] -= weight * invd2 * v[0];
+ bentn[1] -= weight * invd2 * v[1];
+ bentn[2] -= weight * invd2 * v[2];
+ }
+
+ resultocc += weight * fac;
+ }
+ else {
+ /* traverse into children */
+ for (b = 0; b < TOTCHILD; b++) {
+ if (node->childflag & (1 << b)) {
+ f = node->child[b].face;
+ face = &tree->face[f];
+
+ /* accumulate occlusion with face form factor */
+ if (!exclude || !(face->obi == exclude->obi && face->facenr == exclude->facenr)) {
+ if (bentn || distfac != 0.0f) {
+ occ_face(face, co, NULL, NULL);
+ sub_v3_v3v3(v, co, p);
+ d2 = dot_v3v3(v, v) + 1e-16f;
+
+ fac = (distfac == 0.0f) ? 1.0f : 1.0f / (1.0f + distfac * d2);
+ if (fac < 0.01f)
+ continue;
+ }
+ else
+ fac = 1.0f;
+
+ weight = occ_form_factor(face, p, n);
+
+ if (rad)
+ madd_v3_v3fl(resultrad, tree->rad[f], weight * fac);
+
+ weight *= tree->occlusion[f];
+
+ if (bentn) {
+ invd2 = 1.0f / sqrtf(d2);
+ bentn[0] -= weight * invd2 * v[0];
+ bentn[1] -= weight * invd2 * v[1];
+ bentn[2] -= weight * invd2 * v[2];
+ }
+
+ resultocc += weight * fac;
+ }
+ }
+ else if (node->child[b].node) {
+ /* push child on the stack */
+ stack[totstack++] = node->child[b].node;
+ }
+ }
+ }
+ }
+
+ if (occ) *occ = resultocc;
+ if (rad) copy_v3_v3(rad, resultrad);
+#if 0
+ if (rad && exclude) {
+ int a;
+ for (a = 0; a < tree->totface; a++)
+ if ((tree->face[a].obi == exclude->obi && tree->face[a].facenr == exclude->facenr))
+ copy_v3_v3(rad, tree->rad[a]);
+ }
+#endif
+ if (bentn) normalize_v3(bentn);
+}
+
+static void occ_compute_bounces(Render *re, OcclusionTree *tree, int totbounce)
+{
+ float (*rad)[3], (*sum)[3], (*tmp)[3], co[3], n[3], occ;
+ int bounce, i;
+
+ rad = MEM_callocN(sizeof(float) * 3 * tree->totface, "OcclusionBounceRad");
+ sum = MEM_dupallocN(tree->rad);
+
+ for (bounce = 1; bounce < totbounce; bounce++) {
+ for (i = 0; i < tree->totface; i++) {
+ occ_face(&tree->face[i], co, n, NULL);
+ madd_v3_v3fl(co, n, 1e-8f);
+
+ occ_lookup(tree, 0, &tree->face[i], co, n, &occ, rad[i], NULL);
+ rad[i][0] = MAX2(rad[i][0], 0.0f);
+ rad[i][1] = MAX2(rad[i][1], 0.0f);
+ rad[i][2] = MAX2(rad[i][2], 0.0f);
+ add_v3_v3(sum[i], rad[i]);
+
+ if (re->test_break(re->tbh))
+ break;
+ }
+
+ if (re->test_break(re->tbh))
+ break;
+
+ tmp = tree->rad;
+ tree->rad = rad;
+ rad = tmp;
+
+ occ_sum_occlusion(tree, tree->root);
+ }
+
+ MEM_freeN(rad);
+ MEM_freeN(tree->rad);
+ tree->rad = sum;
+
+ if (!re->test_break(re->tbh))
+ occ_sum_occlusion(tree, tree->root);
+}
+
+static void occ_compute_passes(Render *re, OcclusionTree *tree, int totpass)
+{
+ float *occ, co[3], n[3];
+ int pass, i;
+
+ occ = MEM_callocN(sizeof(float) * tree->totface, "OcclusionPassOcc");
+
+ for (pass = 0; pass < totpass; pass++) {
+ for (i = 0; i < tree->totface; i++) {
+ occ_face(&tree->face[i], co, n, NULL);
+ negate_v3(n);
+ madd_v3_v3fl(co, n, 1e-8f);
+
+ occ_lookup(tree, 0, &tree->face[i], co, n, &occ[i], NULL, NULL);
+ if (re->test_break(re->tbh))
+ break;
+ }
+
+ if (re->test_break(re->tbh))
+ break;
+
+ for (i = 0; i < tree->totface; i++) {
+ tree->occlusion[i] -= occ[i]; //MAX2(1.0f-occ[i], 0.0f);
+ if (tree->occlusion[i] < 0.0f)
+ tree->occlusion[i] = 0.0f;
+ }
+
+ occ_sum_occlusion(tree, tree->root);
+ }
+
+ MEM_freeN(occ);
+}
+
+static void sample_occ_tree(Render *re, OcclusionTree *tree, OccFace *exclude,
+ const float co[3], const float n[3], int thread, int onlyshadow,
+ float *ao, float *env, float *indirect)
+{
+ float nn[3], bn[3], fac, occ, occlusion, correction, rad[3];
+ int envcolor;
+
+ envcolor = re->wrld.aocolor;
+ if (onlyshadow)
+ envcolor = WO_AOPLAIN;
+
+ negate_v3_v3(nn, n);
+
+ occ_lookup(tree, thread, exclude, co, nn, &occ, (tree->doindirect) ? rad : NULL, (env && envcolor) ? bn : NULL);
+
+ correction = re->wrld.ao_approx_correction;
+
+ occlusion = (1.0f - correction) * (1.0f - occ);
+ CLAMP(occlusion, 0.0f, 1.0f);
+ if (correction != 0.0f)
+ occlusion += correction * expf(-occ);
+
+ if (env) {
+ /* sky shading using bent normal */
+ if (ELEM(envcolor, WO_AOSKYCOL, WO_AOSKYTEX)) {
+ fac = 0.5f * (1.0f + dot_v3v3(bn, re->grvec));
+ env[0] = (1.0f - fac) * re->wrld.horr + fac * re->wrld.zenr;
+ env[1] = (1.0f - fac) * re->wrld.horg + fac * re->wrld.zeng;
+ env[2] = (1.0f - fac) * re->wrld.horb + fac * re->wrld.zenb;
+
+ mul_v3_fl(env, occlusion);
+ }
+ else {
+ env[0] = occlusion;
+ env[1] = occlusion;
+ env[2] = occlusion;
+ }
+#if 0
+ else { /* WO_AOSKYTEX */
+ float dxyview[3];
+ bn[0] = -bn[0];
+ bn[1] = -bn[1];
+ bn[2] = -bn[2];
+ dxyview[0] = 1.0f;
+ dxyview[1] = 1.0f;
+ dxyview[2] = 0.0f;
+ shadeSkyView(ao, co, bn, dxyview);
+ }
+#endif
+ }
+
+ if (ao) {
+ ao[0] = occlusion;
+ ao[1] = occlusion;
+ ao[2] = occlusion;
+ }
+
+ if (tree->doindirect) copy_v3_v3(indirect, rad);
+ else zero_v3(indirect);
+}
+
+/* ---------------------------- Caching ------------------------------- */
+
+static OcclusionCacheSample *find_occ_sample(OcclusionCache *cache, int x, int y)
+{
+ x -= cache->x;
+ y -= cache->y;
+
+ x /= cache->step;
+ y /= cache->step;
+ x *= cache->step;
+ y *= cache->step;
+
+ if (x < 0 || x >= cache->w || y < 0 || y >= cache->h)
+ return NULL;
+ else
+ return &cache->sample[y * cache->w + x];
+}
+
+static int sample_occ_cache(OcclusionTree *tree, float *co, float *n, int x, int y, int thread, float *ao, float *env, float *indirect)
+{
+ OcclusionCache *cache;
+ OcclusionCacheSample *samples[4], *sample;
+ float wn[4], wz[4], wb[4], tx, ty, w, totw, mino, maxo;
+ float d[3], dist2;
+ int i, x1, y1, x2, y2;
+
+ if (!tree->cache)
+ return 0;
+
+ /* first try to find a sample in the same pixel */
+ cache = &tree->cache[thread];
+
+ if (cache->sample && cache->step) {
+ sample = &cache->sample[(y - cache->y) * cache->w + (x - cache->x)];
+ if (sample->filled) {
+ sub_v3_v3v3(d, sample->co, co);
+ dist2 = dot_v3v3(d, d);
+ if (dist2 < 0.5f * sample->dist2 && dot_v3v3(sample->n, n) > 0.98f) {
+ copy_v3_v3(ao, sample->ao);
+ copy_v3_v3(env, sample->env);
+ copy_v3_v3(indirect, sample->indirect);
+ return 1;
+ }
+ }
+ }
+ else
+ return 0;
+
+ /* try to interpolate between 4 neighboring pixels */
+ samples[0] = find_occ_sample(cache, x, y);
+ samples[1] = find_occ_sample(cache, x + cache->step, y);
+ samples[2] = find_occ_sample(cache, x, y + cache->step);
+ samples[3] = find_occ_sample(cache, x + cache->step, y + cache->step);
+
+ for (i = 0; i < 4; i++)
+ if (!samples[i] || !samples[i]->filled)
+ return 0;
+
+ /* require intensities not being too different */
+ mino = min_ffff(samples[0]->intensity, samples[1]->intensity, samples[2]->intensity, samples[3]->intensity);
+ maxo = max_ffff(samples[0]->intensity, samples[1]->intensity, samples[2]->intensity, samples[3]->intensity);
+
+ if (maxo - mino > 0.05f)
+ return 0;
+
+ /* compute weighted interpolation between samples */
+ zero_v3(ao);
+ zero_v3(env);
+ zero_v3(indirect);
+ totw = 0.0f;
+
+ x1 = samples[0]->x;
+ y1 = samples[0]->y;
+ x2 = samples[3]->x;
+ y2 = samples[3]->y;
+
+ tx = (float)(x2 - x) / (float)(x2 - x1);
+ ty = (float)(y2 - y) / (float)(y2 - y1);
+
+ wb[3] = (1.0f - tx) * (1.0f - ty);
+ wb[2] = (tx) * (1.0f - ty);
+ wb[1] = (1.0f - tx) * (ty);
+ wb[0] = tx * ty;
+
+ for (i = 0; i < 4; i++) {
+ sub_v3_v3v3(d, samples[i]->co, co);
+ //dist2 = dot_v3v3(d, d);
+
+ wz[i] = 1.0f; //(samples[i]->dist2/(1e-4f + dist2));
+ wn[i] = pow(dot_v3v3(samples[i]->n, n), 32.0f);
+
+ w = wb[i] * wn[i] * wz[i];
+
+ totw += w;
+ madd_v3_v3fl(ao, samples[i]->ao, w);
+ madd_v3_v3fl(env, samples[i]->env, w);
+ madd_v3_v3fl(indirect, samples[i]->indirect, w);
+ }
+
+ if (totw >= 0.9f) {
+ totw = 1.0f / totw;
+ mul_v3_fl(ao, totw);
+ mul_v3_fl(env, totw);
+ mul_v3_fl(indirect, totw);
+ return 1;
+ }
+
+ return 0;
+}
+
+static void sample_occ_surface(ShadeInput *shi)
+{
+ StrandRen *strand = shi->strand;
+ StrandSurface *mesh = strand->buffer->surface;
+ const int *face, *index = RE_strandren_get_face(shi->obr, strand, 0);
+ float w[4], *co1, *co2, *co3, *co4;
+
+ if (mesh && mesh->face && mesh->co && mesh->ao && index) {
+ face = mesh->face[*index];
+
+ co1 = mesh->co[face[0]];
+ co2 = mesh->co[face[1]];
+ co3 = mesh->co[face[2]];
+
+ if (face[3]) {
+ co4 = mesh->co[face[3]];
+ interp_weights_quad_v3(w, co1, co2, co3, co4, strand->vert->co);
+ }
+ else {
+ interp_weights_tri_v3(w, co1, co2, co3, strand->vert->co);
+ }
+
+ zero_v3(shi->ao);
+ zero_v3(shi->env);
+ zero_v3(shi->indirect);
+
+ madd_v3_v3fl(shi->ao, mesh->ao[face[0]], w[0]);
+ madd_v3_v3fl(shi->env, mesh->env[face[0]], w[0]);
+ madd_v3_v3fl(shi->indirect, mesh->indirect[face[0]], w[0]);
+ madd_v3_v3fl(shi->ao, mesh->ao[face[1]], w[1]);
+ madd_v3_v3fl(shi->env, mesh->env[face[1]], w[1]);
+ madd_v3_v3fl(shi->indirect, mesh->indirect[face[1]], w[1]);
+ madd_v3_v3fl(shi->ao, mesh->ao[face[2]], w[2]);
+ madd_v3_v3fl(shi->env, mesh->env[face[2]], w[2]);
+ madd_v3_v3fl(shi->indirect, mesh->indirect[face[2]], w[2]);
+ if (face[3]) {
+ madd_v3_v3fl(shi->ao, mesh->ao[face[3]], w[3]);
+ madd_v3_v3fl(shi->env, mesh->env[face[3]], w[3]);
+ madd_v3_v3fl(shi->indirect, mesh->indirect[face[3]], w[3]);
+ }
+ }
+ else {
+ shi->ao[0] = 1.0f;
+ shi->ao[1] = 1.0f;
+ shi->ao[2] = 1.0f;
+ zero_v3(shi->env);
+ zero_v3(shi->indirect);
+ }
+}
+
+/* ------------------------- External Functions --------------------------- */
+
+static void *exec_strandsurface_sample(void *data)
+{
+ OcclusionThread *othread = (OcclusionThread *)data;
+ Render *re = othread->re;
+ StrandSurface *mesh = othread->mesh;
+ float ao[3], env[3], indirect[3], co[3], n[3], *co1, *co2, *co3, *co4;
+ int a, *face;
+
+ for (a = othread->begin; a < othread->end; a++) {
+ face = mesh->face[a];
+ co1 = mesh->co[face[0]];
+ co2 = mesh->co[face[1]];
+ co3 = mesh->co[face[2]];
+
+ if (face[3]) {
+ co4 = mesh->co[face[3]];
+
+ mid_v3_v3v3(co, co1, co3);
+ normal_quad_v3(n, co1, co2, co3, co4);
+ }
+ else {
+ mid_v3_v3v3v3(co, co1, co2, co3);
+ normal_tri_v3(n, co1, co2, co3);
+ }
+ negate_v3(n);
+
+ sample_occ_tree(re, re->occlusiontree, NULL, co, n, othread->thread, 0, ao, env, indirect);
+ copy_v3_v3(othread->faceao[a], ao);
+ copy_v3_v3(othread->faceenv[a], env);
+ copy_v3_v3(othread->faceindirect[a], indirect);
+ }
+
+ return NULL;
+}
+
+void make_occ_tree(Render *re)
+{
+ OcclusionThread othreads[BLENDER_MAX_THREADS];
+ OcclusionTree *tree;
+ StrandSurface *mesh;
+ ListBase threads;
+ float ao[3], env[3], indirect[3], (*faceao)[3], (*faceenv)[3], (*faceindirect)[3];
+ int a, totface, totthread, *face, *count;
+
+ /* ugly, needed for occ_face */
+ R = *re;
+
+ re->i.infostr = IFACE_("Occlusion preprocessing");
+ re->stats_draw(re->sdh, &re->i);
+
+ re->occlusiontree = tree = occ_tree_build(re);
+
+ if (tree && !re->test_break(re->tbh)) {
+ if (re->wrld.ao_approx_passes > 0)
+ occ_compute_passes(re, tree, re->wrld.ao_approx_passes);
+ if (tree->doindirect && (re->wrld.mode & WO_INDIRECT_LIGHT))
+ occ_compute_bounces(re, tree, re->wrld.ao_indirect_bounces);
+
+ for (mesh = re->strandsurface.first; mesh; mesh = mesh->next) {
+ if (!mesh->face || !mesh->co || !mesh->ao)
+ continue;
+
+ count = MEM_callocN(sizeof(int) * mesh->totvert, "OcclusionCount");
+ faceao = MEM_callocN(sizeof(float) * 3 * mesh->totface, "StrandSurfFaceAO");
+ faceenv = MEM_callocN(sizeof(float) * 3 * mesh->totface, "StrandSurfFaceEnv");
+ faceindirect = MEM_callocN(sizeof(float) * 3 * mesh->totface, "StrandSurfFaceIndirect");
+
+ totthread = (mesh->totface > 10000) ? re->r.threads : 1;
+ totface = mesh->totface / totthread;
+ for (a = 0; a < totthread; a++) {
+ othreads[a].re = re;
+ othreads[a].faceao = faceao;
+ othreads[a].faceenv = faceenv;
+ othreads[a].faceindirect = faceindirect;
+ othreads[a].thread = a;
+ othreads[a].mesh = mesh;
+ othreads[a].begin = a * totface;
+ othreads[a].end = (a == totthread - 1) ? mesh->totface : (a + 1) * totface;
+ }
+
+ if (totthread == 1) {
+ exec_strandsurface_sample(&othreads[0]);
+ }
+ else {
+ BLI_threadpool_init(&threads, exec_strandsurface_sample, totthread);
+
+ for (a = 0; a < totthread; a++)
+ BLI_threadpool_insert(&threads, &othreads[a]);
+
+ BLI_threadpool_end(&threads);
+ }
+
+ for (a = 0; a < mesh->totface; a++) {
+ face = mesh->face[a];
+
+ copy_v3_v3(ao, faceao[a]);
+ copy_v3_v3(env, faceenv[a]);
+ copy_v3_v3(indirect, faceindirect[a]);
+
+ add_v3_v3(mesh->ao[face[0]], ao);
+ add_v3_v3(mesh->env[face[0]], env);
+ add_v3_v3(mesh->indirect[face[0]], indirect);
+ count[face[0]]++;
+ add_v3_v3(mesh->ao[face[1]], ao);
+ add_v3_v3(mesh->env[face[1]], env);
+ add_v3_v3(mesh->indirect[face[1]], indirect);
+ count[face[1]]++;
+ add_v3_v3(mesh->ao[face[2]], ao);
+ add_v3_v3(mesh->env[face[2]], env);
+ add_v3_v3(mesh->indirect[face[2]], indirect);
+ count[face[2]]++;
+
+ if (face[3]) {
+ add_v3_v3(mesh->ao[face[3]], ao);
+ add_v3_v3(mesh->env[face[3]], env);
+ add_v3_v3(mesh->indirect[face[3]], indirect);
+ count[face[3]]++;
+ }
+ }
+
+ for (a = 0; a < mesh->totvert; a++) {
+ if (count[a]) {
+ mul_v3_fl(mesh->ao[a], 1.0f / count[a]);
+ mul_v3_fl(mesh->env[a], 1.0f / count[a]);
+ mul_v3_fl(mesh->indirect[a], 1.0f / count[a]);
+ }
+ }
+
+ MEM_freeN(count);
+ MEM_freeN(faceao);
+ MEM_freeN(faceenv);
+ MEM_freeN(faceindirect);
+ }
+ }
+}
+
+void free_occ(Render *re)
+{
+ if (re->occlusiontree) {
+ occ_free_tree(re->occlusiontree);
+ re->occlusiontree = NULL;
+ }
+}
+
+void sample_occ(Render *re, ShadeInput *shi)
+{
+ OcclusionTree *tree = re->occlusiontree;
+ OcclusionCache *cache;
+ OcclusionCacheSample *sample;
+ OccFace exclude;
+ int onlyshadow;
+
+ if (tree) {
+ if (shi->strand) {
+ sample_occ_surface(shi);
+ }
+ /* try to get result from the cache if possible */
+ else if (shi->depth != 0 || !sample_occ_cache(tree, shi->co, shi->vno, shi->xs, shi->ys, shi->thread, shi->ao, shi->env, shi->indirect)) {
+ /* no luck, let's sample the occlusion */
+ exclude.obi = shi->obi - re->objectinstance;
+ exclude.facenr = shi->vlr->index;
+ onlyshadow = (shi->mat->mode & MA_ONLYSHADOW);
+ sample_occ_tree(re, tree, &exclude, shi->co, shi->vno, shi->thread, onlyshadow, shi->ao, shi->env, shi->indirect);
+
+ /* fill result into sample, each time */
+ if (tree->cache) {
+ cache = &tree->cache[shi->thread];
+
+ if (cache->sample && cache->step) {
+ sample = &cache->sample[(shi->ys - cache->y) * cache->w + (shi->xs - cache->x)];
+ copy_v3_v3(sample->co, shi->co);
+ copy_v3_v3(sample->n, shi->vno);
+ copy_v3_v3(sample->ao, shi->ao);
+ copy_v3_v3(sample->env, shi->env);
+ copy_v3_v3(sample->indirect, shi->indirect);
+ sample->intensity = max_fff(sample->ao[0], sample->ao[1], sample->ao[2]);
+ sample->intensity = max_ff(sample->intensity, max_fff(sample->env[0], sample->env[1], sample->env[2]));
+ sample->intensity = max_ff(sample->intensity, max_fff(sample->indirect[0], sample->indirect[1], sample->indirect[2]));
+ sample->dist2 = dot_v3v3(shi->dxco, shi->dxco) + dot_v3v3(shi->dyco, shi->dyco);
+ sample->filled = 1;
+ }
+ }
+ }
+ }
+ else {
+ shi->ao[0] = 1.0f;
+ shi->ao[1] = 1.0f;
+ shi->ao[2] = 1.0f;
+
+ shi->env[0] = 0.0f;
+ shi->env[1] = 0.0f;
+ shi->env[2] = 0.0f;
+
+ shi->indirect[0] = 0.0f;
+ shi->indirect[1] = 0.0f;
+ shi->indirect[2] = 0.0f;
+ }
+}
+
+void cache_occ_samples(Render *re, RenderPart *pa, ShadeSample *ssamp)
+{
+ OcclusionTree *tree = re->occlusiontree;
+ PixStr ps;
+ OcclusionCache *cache;
+ OcclusionCacheSample *sample;
+ OccFace exclude;
+ ShadeInput *shi;
+ intptr_t *rd = NULL;
+ int *ro = NULL, *rp = NULL, *rz = NULL, onlyshadow;
+ int x, y, step = CACHE_STEP;
+
+ if (!tree->cache)
+ return;
+
+ cache = &tree->cache[pa->thread];
+ cache->w = pa->rectx;
+ cache->h = pa->recty;
+ cache->x = pa->disprect.xmin;
+ cache->y = pa->disprect.ymin;
+ cache->step = step;
+ cache->sample = MEM_callocN(sizeof(OcclusionCacheSample) * cache->w * cache->h, "OcclusionCacheSample");
+ sample = cache->sample;
+
+ if (re->osa) {
+ rd = pa->rectdaps;
+ }
+ else {
+ /* fake pixel struct for non-osa */
+ ps.next = NULL;
+ ps.mask = 0xFFFF;
+
+ ro = pa->recto;
+ rp = pa->rectp;
+ rz = pa->rectz;
+ }
+
+ /* compute a sample at every step pixels */
+ for (y = pa->disprect.ymin; y < pa->disprect.ymax; y++) {
+ for (x = pa->disprect.xmin; x < pa->disprect.xmax; x++, sample++, rd++, ro++, rp++, rz++) {
+ if (!(((x - pa->disprect.xmin + step) % step) == 0 || x == pa->disprect.xmax - 1))
+ continue;
+ if (!(((y - pa->disprect.ymin + step) % step) == 0 || y == pa->disprect.ymax - 1))
+ continue;
+
+ if (re->osa) {
+ if (!*rd) continue;
+
+ shade_samples_fill_with_ps(ssamp, (PixStr *)(*rd), x, y);
+ }
+ else {
+ if (!*rp) continue;
+
+ ps.obi = *ro;
+ ps.facenr = *rp;
+ ps.z = *rz;
+ shade_samples_fill_with_ps(ssamp, &ps, x, y);
+ }
+
+ shi = ssamp->shi;
+ if (shi->vlr) {
+ onlyshadow = (shi->mat->mode & MA_ONLYSHADOW);
+ exclude.obi = shi->obi - re->objectinstance;
+ exclude.facenr = shi->vlr->index;
+ sample_occ_tree(re, tree, &exclude, shi->co, shi->vno, shi->thread, onlyshadow, shi->ao, shi->env, shi->indirect);
+
+ copy_v3_v3(sample->co, shi->co);
+ copy_v3_v3(sample->n, shi->vno);
+ copy_v3_v3(sample->ao, shi->ao);
+ copy_v3_v3(sample->env, shi->env);
+ copy_v3_v3(sample->indirect, shi->indirect);
+ sample->intensity = max_fff(sample->ao[0], sample->ao[1], sample->ao[2]);
+ sample->intensity = max_ff(sample->intensity, max_fff(sample->env[0], sample->env[1], sample->env[2]));
+ sample->intensity = max_ff(sample->intensity, max_fff(sample->indirect[0], sample->indirect[1], sample->indirect[2]));
+ sample->dist2 = dot_v3v3(shi->dxco, shi->dxco) + dot_v3v3(shi->dyco, shi->dyco);
+ sample->x = shi->xs;
+ sample->y = shi->ys;
+ sample->filled = 1;
+ }
+
+ if (re->test_break(re->tbh))
+ break;
+ }
+ }
+}
+
+void free_occ_samples(Render *re, RenderPart *pa)
+{
+ OcclusionTree *tree = re->occlusiontree;
+ OcclusionCache *cache;
+
+ if (tree->cache) {
+ cache = &tree->cache[pa->thread];
+
+ if (cache->sample)
+ MEM_freeN(cache->sample);
+
+ cache->w = 0;
+ cache->h = 0;
+ cache->step = 0;
+ }
+}
+
diff --git a/source/blender/render/intern/source/pipeline.c b/source/blender/render/intern/source/pipeline.c
index 595640489c8..c9f13004836 100644
--- a/source/blender/render/intern/source/pipeline.c
+++ b/source/blender/render/intern/source/pipeline.c
@@ -137,7 +137,7 @@
/* here we store all renders */
static struct {
ListBase renderlist;
-} RenderGlobal = {{NULL, NULL}};
+} RenderGlobal = {{NULL, NULL}};
/* ********* alloc and free ******** */
@@ -424,10 +424,10 @@ void RE_AcquireResultImage(Render *re, RenderResult *rr, const int view_id)
if (re->result) {
RenderLayer *rl;
RenderView *rv;
-
+
rr->rectx = re->result->rectx;
rr->recty = re->result->recty;
-
+
/* actview view */
rv = RE_RenderViewGetById(re->result, view_id);
rr->have_combined = (rv->rectf != NULL);
@@ -494,7 +494,7 @@ Render *RE_NewRender(const char *name)
/* only one render per name exists */
re = RE_GetRender(name);
if (re == NULL) {
-
+
/* new render data struct */
re = MEM_callocN(sizeof(Render), "new render");
BLI_addtail(&RenderGlobal.renderlist, re);
@@ -502,7 +502,7 @@ Render *RE_NewRender(const char *name)
BLI_rw_mutex_init(&re->resultmutex);
BLI_rw_mutex_init(&re->partsmutex);
}
-
+
RE_InitRenderCB(re);
return re;
@@ -574,10 +574,10 @@ void RE_FreeRender(Render *re)
/* main dbase can already be invalid now, some database-free code checks it */
re->main = NULL;
re->scene = NULL;
-
+
render_result_free(re->result);
render_result_free(re->pushedresult);
-
+
BLI_remlink(&RenderGlobal.renderlist, re);
MEM_freeN(re);
}
@@ -715,7 +715,7 @@ void RE_InitState(Render *re, Render *source, RenderData *rd,
bool had_freestyle = (re->r.mode & R_EDGE_FRS) != 0;
re->ok = true; /* maybe flag */
-
+
re->i.starttime = PIL_check_seconds_timer();
/* copy render data and render layers for thread safety */
@@ -753,7 +753,7 @@ void RE_InitState(Render *re, Render *source, RenderData *rd,
}
re->r.scemode = check_mode_full_sample(&re->r);
-
+
if (single_layer) {
int index = BLI_findindex(render_layers, single_layer);
if (index != -1) {
@@ -761,7 +761,7 @@ void RE_InitState(Render *re, Render *source, RenderData *rd,
re->r.scemode |= R_SINGLE_LAYER;
}
}
-
+
/* if preview render, we try to keep old result */
BLI_rw_mutex_lock(&re->resultmutex, THREAD_LOCK_WRITE);
@@ -794,7 +794,7 @@ void RE_InitState(Render *re, Render *source, RenderData *rd,
}
}
else {
-
+
/* make empty render result, so display callbacks can initialize */
render_result_free(re->result);
re->result = MEM_callocN(sizeof(RenderResult), "new render result");
@@ -811,7 +811,7 @@ void RE_InitState(Render *re, Render *source, RenderData *rd,
RE_parts_clamp(re);
BLI_rw_mutex_unlock(&re->resultmutex);
-
+
RE_init_threadcount(re);
RE_point_density_fix_linking();
@@ -925,7 +925,7 @@ void render_update_anim_renderdata(Render *re, RenderData *rd, ListBase *render_
void RE_SetWindow(Render *re, const rctf *viewplane, float clipsta, float clipend)
{
/* re->ok flag? */
-
+
re->viewplane = *viewplane;
re->clipsta = clipsta;
re->clipend = clipend;
@@ -934,13 +934,13 @@ void RE_SetWindow(Render *re, const rctf *viewplane, float clipsta, float clipen
perspective_m4(re->winmat,
re->viewplane.xmin, re->viewplane.xmax,
re->viewplane.ymin, re->viewplane.ymax, re->clipsta, re->clipend);
-
+
}
void RE_SetOrtho(Render *re, const rctf *viewplane, float clipsta, float clipend)
{
/* re->ok flag? */
-
+
re->viewplane = *viewplane;
re->clipsta = clipsta;
re->clipend = clipend;
@@ -961,7 +961,7 @@ void RE_SetView(Render *re, float mat[4][4])
void RE_GetViewPlane(Render *re, rctf *r_viewplane, rcti *r_disprect)
{
*r_viewplane = re->viewplane;
-
+
/* make disprect zero when no border render, is needed to detect changes in 3d view render */
if (re->r.mode & R_BORDER) {
*r_disprect = re->disprect;
@@ -1028,7 +1028,7 @@ void RE_test_break_cb(Render *re, void *handle, int (*f)(void *handle))
#if 0
void RE_AddObject(Render *UNUSED(re), Object *UNUSED(ob))
{
-
+
}
#endif
@@ -1121,9 +1121,9 @@ static void do_render(Render *re)
/* now use renderdata and camera to set viewplane */
RE_SetCamera(re, camera);
-
+
do_render_3d(re);
-
+
/* when border render, check if we have to insert it in black */
render_result_uncrop(re);
}
@@ -1136,7 +1136,7 @@ static void render_scene(Render *re, Scene *sce, int cfra)
{
Render *resc = RE_NewSceneRender(sce);
int winx = re->winx, winy = re->winy;
-
+
sce->r.cfra = cfra;
BKE_scene_camera_switch_update(sce);
@@ -1146,7 +1146,7 @@ static void render_scene(Render *re, Scene *sce, int cfra)
winx = (sce->r.size * sce->r.xsch) / 100;
winy = (sce->r.size * sce->r.ysch) / 100;
}
-
+
/* initial setup */
RE_InitState(resc, re, &sce->r, &sce->view_layers, NULL, winx, winy, &re->disprect);
@@ -1157,7 +1157,7 @@ static void render_scene(Render *re, Scene *sce, int cfra)
resc->main = re->main;
resc->scene = sce;
resc->lay = sce->lay;
-
+
/* ensure scene has depsgraph, base flags etc OK */
BKE_scene_set_background(re->main, sce);
@@ -1170,7 +1170,7 @@ static void render_scene(Render *re, Scene *sce, int cfra)
resc->sdh = re->sdh;
resc->current_scene_update = re->current_scene_update;
resc->suh = re->suh;
-
+
do_render(resc);
}
@@ -1179,11 +1179,11 @@ static int composite_needs_render(Scene *sce, int this_scene)
{
bNodeTree *ntree = sce->nodetree;
bNode *node;
-
+
if (ntree == NULL) return 1;
if (sce->use_nodes == false) return 1;
if ((sce->r.scemode & R_DOCOMP) == 0) return 1;
-
+
for (node = ntree->nodes.first; node; node = node->next) {
if (node->type == CMP_NODE_R_LAYERS && (node->flag & NODE_MUTED) == 0)
if (this_scene == 0 || node->id == NULL || node->id == &sce->id)
@@ -1334,14 +1334,14 @@ static void tag_scenes_for_render(Render *re)
{
bNode *node;
Scene *sce;
-
+
for (sce = re->main->scene.first; sce; sce = sce->id.next) {
sce->id.tag &= ~LIB_TAG_DOIT;
#ifdef DEPSGRAPH_WORKAROUND_HACK
tag_dependend_objects_for_render(re->main, sce);
#endif
}
-
+
#ifdef WITH_FREESTYLE
if (re->freestyle_bmain) {
for (sce = re->freestyle_bmain->scene.first; sce; sce = sce->id.next) {
@@ -1359,9 +1359,9 @@ static void tag_scenes_for_render(Render *re)
tag_dependend_objects_for_render(re->main, re->scene);
#endif
}
-
+
if (re->scene->nodetree == NULL) return;
-
+
/* check for render-layers nodes using other scenes, we tag them LIB_TAG_DOIT */
for (node = re->scene->nodetree->nodes.first; node; node = node->next) {
node->flag &= ~NODE_TEST;
@@ -1397,7 +1397,7 @@ static void tag_scenes_for_render(Render *re)
}
}
}
-
+
}
static void ntree_render_scenes(Render *re)
@@ -1406,15 +1406,15 @@ static void ntree_render_scenes(Render *re)
int cfra = re->scene->r.cfra;
Scene *restore_scene = re->scene;
bool scene_changed = false;
-
+
if (re->scene->nodetree == NULL) return;
-
+
tag_scenes_for_render(re);
#ifdef DEPSGRAPH_WORKAROUND_GROUP_HACK
tag_collections_for_render(re);
#endif
-
+
/* now foreach render-result node tagged we do a full render */
/* results are stored in a way compisitor will find it */
for (node = re->scene->nodetree->nodes.first; node; node = node->next) {
@@ -1426,7 +1426,7 @@ static void ntree_render_scenes(Render *re)
scene_changed |= scene != restore_scene;
render_scene(re, scene, cfra);
node->flag &= ~NODE_TEST;
-
+
nodeUpdate(restore_scene->nodetree, node);
}
}
@@ -1531,10 +1531,10 @@ static void do_render_composite(Render *re)
{
bNodeTree *ntree = re->scene->nodetree;
int update_newframe = 0;
-
+
/* INIT seeding, compositor can use random texture */
BLI_srandom(re->r.cfra);
-
+
if (composite_needs_render(re->scene, 1)) {
/* save memory... free all cached images */
ntreeFreeCache(ntree);
@@ -1550,7 +1550,7 @@ static void do_render_composite(Render *re)
/* ensure new result gets added, like for regular renders */
BLI_rw_mutex_lock(&re->resultmutex, THREAD_LOCK_WRITE);
-
+
render_result_free(re->result);
if ((re->r.mode & R_CROP) == 0) {
render_result_disprect_to_full_resolution(re);
@@ -1558,30 +1558,30 @@ static void do_render_composite(Render *re)
re->result = render_result_new(re, &re->disprect, 0, RR_USE_MEM, RR_ALL_LAYERS, RR_ALL_VIEWS);
BLI_rw_mutex_unlock(&re->resultmutex);
-
+
/* scene render process already updates animsys */
update_newframe = 1;
}
-
+
/* swap render result */
if (re->r.scemode & R_SINGLE_LAYER) {
BLI_rw_mutex_lock(&re->resultmutex, THREAD_LOCK_WRITE);
render_result_single_layer_end(re);
BLI_rw_mutex_unlock(&re->resultmutex);
}
-
+
if (!re->test_break(re->tbh)) {
-
+
if (ntree) {
ntreeCompositTagRender(re->scene);
ntreeCompositTagAnimated(ntree);
}
-
+
if (ntree && re->scene->use_nodes && re->r.scemode & R_DOCOMP) {
/* checks if there are render-result nodes that need scene */
if ((re->r.scemode & R_SINGLE_LAYER) == 0)
ntree_render_scenes(re);
-
+
if (!re->test_break(re->tbh)) {
ntree->stats_draw = render_composit_stats;
ntree->test_break = re->test_break;
@@ -1589,16 +1589,16 @@ static void do_render_composite(Render *re)
ntree->sdh = re;
ntree->tbh = re->tbh;
ntree->prh = re->prh;
-
+
if (update_newframe) {
/* If we have consistent depsgraph now would be a time to update them. */
}
-
+
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;
ntree->test_break = NULL;
ntree->progress = NULL;
@@ -1651,15 +1651,15 @@ int RE_seq_render_active(Scene *scene, RenderData *rd)
Sequence *seq;
ed = scene->ed;
-
+
if (!(rd->scemode & R_DOSEQ) || !ed || !ed->seqbase.first)
return 0;
-
+
for (seq = ed->seqbase.first; seq; seq = seq->next) {
if (seq->type != SEQ_TYPE_SOUND_RAM)
return 1;
}
-
+
return 0;
}
@@ -1810,18 +1810,18 @@ static void do_render_all_options(Render *re)
do_render_seq(re);
render_seq = true;
}
-
+
re->stats_draw(re->sdh, &re->i);
re->display_update(re->duh, re->result, NULL);
}
else {
do_render_composite(re);
}
-
+
re->i.lastframetime = PIL_check_seconds_timer() - re->i.starttime;
-
+
re->stats_draw(re->sdh, &re->i);
-
+
/* save render result stamp if needed */
if (re->result != NULL) {
camera = RE_GetCamera(re);
@@ -1975,7 +1975,7 @@ static int check_composite_output(Scene *scene)
bool RE_is_rendering_allowed(Scene *scene, ViewLayer *single_layer, Object *camera_override, ReportList *reports)
{
int scemode = check_mode_full_sample(&scene->r);
-
+
if (scene->r.mode & R_BORDER) {
if (scene->r.border.xmax <= scene->r.border.xmin ||
scene->r.border.ymax <= scene->r.border.ymin)
@@ -1984,30 +1984,30 @@ bool RE_is_rendering_allowed(Scene *scene, ViewLayer *single_layer, Object *came
return 0;
}
}
-
+
if (scemode & (R_EXR_TILE_FILE | R_FULL_SAMPLE)) {
char str[FILE_MAX];
-
+
render_result_exr_file_path(scene, "", 0, str);
-
+
if (!BLI_file_is_writable(str)) {
BKE_report(reports, RPT_ERROR, "Cannot save render buffers, check the temp default path");
return 0;
}
}
-
+
if (scemode & R_DOCOMP) {
if (scene->use_nodes) {
if (!scene->nodetree) {
BKE_report(reports, RPT_ERROR, "No node tree in scene");
return 0;
}
-
+
if (!check_composite_output(scene)) {
BKE_report(reports, RPT_ERROR, "No render output node in scene");
return 0;
}
-
+
if (scemode & R_FULL_SAMPLE) {
if (composite_needs_render(scene, 0) == 0) {
BKE_report(reports, RPT_ERROR, "Full sample AA not supported without 3D rendering");
@@ -2016,12 +2016,12 @@ bool RE_is_rendering_allowed(Scene *scene, ViewLayer *single_layer, Object *came
}
}
}
-
+
/* check valid camera, without camera render is OK (compo, seq) */
if (!check_valid_camera(scene, camera_override, reports)) {
return 0;
}
-
+
/* get panorama & ortho, only after camera is set */
BKE_camera_object_mode(&scene->r, camera_override ? camera_override : scene->camera);
@@ -2098,19 +2098,19 @@ static int render_initialize_from_main(Render *re, RenderData *rd, Main *bmain,
{
int winx, winy;
rcti disprect;
-
+
/* r.xsch and r.ysch has the actual view window size
* r.border is the clipping rect */
-
+
/* calculate actual render result and display size */
winx = (rd->size * rd->xsch) / 100;
winy = (rd->size * rd->ysch) / 100;
-
+
/* we always render smaller part, inserting it in larger image is compositor bizz, it uses disprect for it */
if (scene->r.mode & R_BORDER) {
disprect.xmin = rd->border.xmin * winx;
disprect.xmax = rd->border.xmax * winx;
-
+
disprect.ymin = rd->border.ymin * winy;
disprect.ymax = rd->border.ymax * winy;
}
@@ -2119,7 +2119,7 @@ static int render_initialize_from_main(Render *re, RenderData *rd, Main *bmain,
disprect.xmax = winx;
disprect.ymax = winy;
}
-
+
re->main = bmain;
re->scene = scene;
re->camera_override = camera_override;
@@ -2134,7 +2134,7 @@ static int render_initialize_from_main(Render *re, RenderData *rd, Main *bmain,
re->disprect = disprect;
return 1;
}
-
+
/* check all scenes involved */
tag_scenes_for_render(re);
@@ -2153,17 +2153,17 @@ static int render_initialize_from_main(Render *re, RenderData *rd, Main *bmain,
ViewLayer *view_layer = BKE_view_layer_context_active_PLACEHOLDER(scene);
update_physics_cache(re, scene, view_layer, anim_init);
}
-
+
if (single_layer || scene->r.scemode & R_SINGLE_LAYER) {
BLI_rw_mutex_lock(&re->resultmutex, THREAD_LOCK_WRITE);
render_result_single_layer_begin(re);
BLI_rw_mutex_unlock(&re->resultmutex);
}
-
+
RE_InitState(re, NULL, &scene->r, &scene->view_layers, single_layer, winx, winy, &disprect);
if (!re->ok) /* if an error was printed, abort */
return 0;
-
+
/* initstate makes new result, have to send changed tags around */
ntreeCompositTagRender(re->scene);
@@ -2171,7 +2171,7 @@ static int render_initialize_from_main(Render *re, RenderData *rd, Main *bmain,
re->display_init(re->dih, re->result);
re->display_clear(re->dch, re->result);
-
+
return 1;
}
@@ -2188,9 +2188,9 @@ void RE_BlenderFrame(Render *re, Main *bmain, Scene *scene, ViewLayer *single_la
/* ugly global still... is to prevent preview events and signal subsurfs etc to make full resol */
G.is_rendering = true;
-
+
scene->r.cfra = frame;
-
+
if (render_initialize_from_main(re, &scene->r, bmain, scene, single_layer,
camera_override, lay_override, 0, 0))
{
@@ -2208,7 +2208,7 @@ void RE_BlenderFrame(Render *re, Main *bmain, Scene *scene, ViewLayer *single_la
else {
char name[FILE_MAX];
BKE_image_path_from_imformat(
- name, scene->r.pic, bmain->name, scene->r.cfra,
+ name, scene->r.pic, BKE_main_blendfile_path(bmain), scene->r.cfra,
&scene->r.im_format, (scene->r.scemode & R_EXTENSION) != 0, false, NULL);
/* reports only used for Movie */
@@ -2467,18 +2467,18 @@ static int do_write_image_or_movie(Render *re, Main *bmain, Scene *scene, bMovie
BLI_strncpy(name, name_override, sizeof(name));
else
BKE_image_path_from_imformat(
- name, scene->r.pic, bmain->name, scene->r.cfra,
+ name, scene->r.pic, BKE_main_blendfile_path(bmain), 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_ReleaseResultImageViews(re, &rres);
render_time = re->i.lastframetime;
re->i.lastframetime = PIL_check_seconds_timer() - re->i.starttime;
-
+
BLI_timecode_string_from_time_simple(name, sizeof(name), re->i.lastframetime);
printf(" Time: %s", name);
@@ -2489,7 +2489,7 @@ static int do_write_image_or_movie(Render *re, Main *bmain, Scene *scene, bMovie
BLI_timecode_string_from_time_simple(name, sizeof(name), re->i.lastframetime - render_time);
printf(" (Saving: %s)\n", name);
-
+
fputc('\n', stdout);
fflush(stdout); /* needed for renderd !! (not anymore... (ton)) */
@@ -2647,7 +2647,7 @@ void RE_BlenderAnim(Render *re, Main *bmain, Scene *scene, Object *camera_overri
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,
+ name, scene->r.pic, BKE_main_blendfile_path(bmain), scene->r.cfra,
&scene->r.im_format, (scene->r.scemode & R_EXTENSION) != 0, true, NULL);
if (scene->r.mode & R_NO_OVERWRITE) {
@@ -2713,10 +2713,10 @@ void RE_BlenderAnim(Render *re, Main *bmain, Scene *scene, Object *camera_overri
/* run callbacs before rendering, before the scene is updated */
BLI_callback_exec(re->main, (ID *)scene, BLI_CB_EVT_RENDER_PRE);
-
+
do_render_all_options(re);
totrendered++;
-
+
if (re->test_break(re->tbh) == 0) {
if (!G.is_break)
if (!do_write_image_or_movie(re, bmain, scene, mh, totvideos, NULL))
@@ -2724,7 +2724,7 @@ void RE_BlenderAnim(Render *re, Main *bmain, Scene *scene, Object *camera_overri
}
else
G.is_break = true;
-
+
if (G.is_break == true) {
/* remove touched file */
if (is_movie == false) {
@@ -2753,7 +2753,7 @@ void RE_BlenderAnim(Render *re, Main *bmain, Scene *scene, Object *camera_overri
}
}
}
-
+
break;
}
@@ -2763,12 +2763,12 @@ void RE_BlenderAnim(Render *re, Main *bmain, Scene *scene, Object *camera_overri
}
}
}
-
+
/* end movie */
if (is_movie) {
re_movie_free_all(re, mh, totvideos);
}
-
+
if (totskipped && totrendered == 0)
BKE_report(re->reports, RPT_INFO, "No frames rendered, skipped to not overwrite");
@@ -2812,16 +2812,16 @@ bool RE_ReadRenderResult(Scene *scene, Scene *scenode)
int winx, winy;
bool success;
rcti disprect;
-
+
/* calculate actual render result and display size */
winx = (scene->r.size * scene->r.xsch) / 100;
winy = (scene->r.size * scene->r.ysch) / 100;
-
+
/* only in movie case we render smaller part */
if (scene->r.mode & R_BORDER) {
disprect.xmin = scene->r.border.xmin * winx;
disprect.xmax = scene->r.border.xmax * winx;
-
+
disprect.ymin = scene->r.border.ymin * winy;
disprect.ymax = scene->r.border.ymax * winy;
}
@@ -2830,17 +2830,17 @@ bool RE_ReadRenderResult(Scene *scene, Scene *scenode)
disprect.xmax = winx;
disprect.ymax = winy;
}
-
+
if (scenode)
scene = scenode;
-
+
/* get render: it can be called from UI with draw callbacks */
re = RE_GetSceneRender(scene);
if (re == NULL)
re = RE_NewSceneRender(scene);
RE_InitState(re, NULL, &scene->r, &scene->view_layers, NULL, winx, winy, &disprect);
re->scene = scene;
-
+
BLI_rw_mutex_lock(&re->resultmutex, THREAD_LOCK_WRITE);
success = render_result_exr_file_cache_read(re);
BLI_rw_mutex_unlock(&re->resultmutex);
@@ -2850,7 +2850,7 @@ bool RE_ReadRenderResult(Scene *scene, Scene *scenode)
return success;
}
-void RE_init_threadcount(Render *re)
+void RE_init_threadcount(Render *re)
{
re->r.threads = BKE_render_num_threads(&re->r);
}
@@ -3014,7 +3014,7 @@ RenderPass *RE_create_gp_pass(RenderResult *rr, const char *layername, const cha
rl->rectx = rr->rectx;
rl->recty = rr->recty;
}
-
+
/* clear previous pass if exist or the new image will be over previous one*/
RenderPass *rp = RE_pass_find_by_name(rl, RE_PASSNAME_COMBINED, viewname);
if (rp) {
diff --git a/source/blender/render/intern/source/pixelblending.c b/source/blender/render/intern/source/pixelblending.c
new file mode 100644
index 00000000000..c7cfe765f5b
--- /dev/null
+++ b/source/blender/render/intern/source/pixelblending.c
@@ -0,0 +1,400 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * Contributor(s): Full recode, 2004-2006 Blender Foundation
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/render/intern/source/pixelblending.c
+ * \ingroup render
+ *
+ * Functions to blend pixels with or without alpha, in various formats
+ * nzc - June 2000
+ */
+
+
+#include <math.h>
+#include <string.h>
+
+/* global includes */
+
+/* own includes */
+#include "render_types.h"
+#include "pixelblending.h"
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+/* defined in pipeline.c, is hardcopy of active dynamic allocated Render */
+/* only to be used here in this file, it's for speed */
+extern struct Render R;
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+
+/* ------------------------------------------------------------------------- */
+/* Debug/behavior defines */
+/* if defined: alpha blending with floats clips color, as with shorts */
+/* #define RE_FLOAT_COLOR_CLIPPING */
+/* if defined: alpha values are clipped */
+/* For now, we just keep alpha clipping. We run into thresholding and */
+/* blending difficulties otherwise. Be careful here. */
+#define RE_ALPHA_CLIPPING
+
+
+
+/* Threshold for a 'full' pixel: pixels with alpha above this level are */
+/* considered opaque This is the decimal value for 0xFFF0 / 0xFFFF */
+#define RE_FULL_COLOR_FLOAT 0.9998f
+/* Threshold for an 'empty' pixel: pixels with alpha above this level are */
+/* considered completely transparent. This is the decimal value */
+/* for 0x000F / 0xFFFF */
+#define RE_EMPTY_COLOR_FLOAT 0.0002f
+
+
+/* ------------------------------------------------------------------------- */
+
+void addAlphaOverFloat(float dest[4], const float source[4])
+{
+ /* d = s + (1-alpha_s)d*/
+ float mul;
+
+ mul = 1.0f - source[3];
+
+ dest[0] = (mul * dest[0]) + source[0];
+ dest[1] = (mul * dest[1]) + source[1];
+ dest[2] = (mul * dest[2]) + source[2];
+ dest[3] = (mul * dest[3]) + source[3];
+
+}
+
+
+/* ------------------------------------------------------------------------- */
+
+void addAlphaUnderFloat(float dest[4], const float source[4])
+{
+ float mul;
+
+ mul = 1.0f - dest[3];
+
+ dest[0] += (mul * source[0]);
+ dest[1] += (mul * source[1]);
+ dest[2] += (mul * source[2]);
+ dest[3] += (mul * source[3]);
+}
+
+
+/* ------------------------------------------------------------------------- */
+void addalphaAddfacFloat(float dest[4], const float source[4], char addfac)
+{
+ float m; /* weiging factor of destination */
+ float c; /* intermediate color */
+
+ /* Addfac is a number between 0 and 1: rescale */
+ /* final target is to diminish the influence of dest when addfac rises */
+ m = 1.0f - (source[3] * ((255 - addfac) / 255.0f));
+
+ /* blend colors*/
+ c = (m * dest[0]) + source[0];
+#ifdef RE_FLOAT_COLOR_CLIPPING
+ if (c >= RE_FULL_COLOR_FLOAT) dest[0] = RE_FULL_COLOR_FLOAT;
+ else
+#endif
+ dest[0] = c;
+
+ c = (m * dest[1]) + source[1];
+#ifdef RE_FLOAT_COLOR_CLIPPING
+ if (c >= RE_FULL_COLOR_FLOAT) dest[1] = RE_FULL_COLOR_FLOAT;
+ else
+#endif
+ dest[1] = c;
+
+ c = (m * dest[2]) + source[2];
+#ifdef RE_FLOAT_COLOR_CLIPPING
+ if (c >= RE_FULL_COLOR_FLOAT) dest[2] = RE_FULL_COLOR_FLOAT;
+ else
+#endif
+ dest[2] = c;
+
+ c = (m * dest[3]) + source[3];
+#ifdef RE_ALPHA_CLIPPING
+ if (c >= RE_FULL_COLOR_FLOAT) dest[3] = RE_FULL_COLOR_FLOAT;
+ else
+#endif
+ dest[3] = c;
+
+}
+
+
+/* ------------------------------------------------------------------------- */
+
+/* filtered adding to scanlines */
+void add_filt_fmask(unsigned int mask, const float col[4], float *rowbuf, int row_w)
+{
+ /* calc the value of mask */
+ float **fmask1 = R.samples->fmask1, **fmask2 = R.samples->fmask2;
+ float *rb1, *rb2, *rb3;
+ float val, r, g, b, al;
+ unsigned int a, maskand, maskshift;
+ int j;
+
+ r = col[0];
+ g = col[1];
+ b = col[2];
+ al = col[3];
+
+ rb2 = rowbuf - 4;
+ rb3 = rb2 - 4 * row_w;
+ rb1 = rb2 + 4 * row_w;
+
+ maskand = (mask & 255);
+ maskshift = (mask >> 8);
+
+ for (j = 2; j >= 0; j--) {
+
+ a = j;
+
+ val = *(fmask1[a] + maskand) + *(fmask2[a] + maskshift);
+ if (val != 0.0f) {
+ rb1[0] += val * r;
+ rb1[1] += val * g;
+ rb1[2] += val * b;
+ rb1[3] += val * al;
+ }
+ a += 3;
+
+ val = *(fmask1[a] + maskand) + *(fmask2[a] + maskshift);
+ if (val != 0.0f) {
+ rb2[0] += val * r;
+ rb2[1] += val * g;
+ rb2[2] += val * b;
+ rb2[3] += val * al;
+ }
+ a += 3;
+
+ val = *(fmask1[a] + maskand) + *(fmask2[a] + maskshift);
+ if (val != 0.0f) {
+ rb3[0] += val * r;
+ rb3[1] += val * g;
+ rb3[2] += val * b;
+ rb3[3] += val * al;
+ }
+
+ rb1 += 4;
+ rb2 += 4;
+ rb3 += 4;
+ }
+}
+
+
+void mask_array(unsigned int mask, float filt[3][3])
+{
+ float **fmask1 = R.samples->fmask1, **fmask2 = R.samples->fmask2;
+ unsigned int maskand = (mask & 255);
+ unsigned int maskshift = (mask >> 8);
+ int a, j;
+
+ for (j = 2; j >= 0; j--) {
+
+ a = j;
+
+ filt[2][2 - j] = *(fmask1[a] + maskand) + *(fmask2[a] + maskshift);
+
+ a += 3;
+
+ filt[1][2 - j] = *(fmask1[a] + maskand) + *(fmask2[a] + maskshift);
+
+ a += 3;
+
+ filt[0][2 - j] = *(fmask1[a] + maskand) + *(fmask2[a] + maskshift);
+ }
+}
+
+
+/**
+ * Index ordering, scanline based:
+ *
+ * <pre>
+ * --- --- ---
+ * | 2,0 | 2,1 | 2,2 |
+ * --- --- ---
+ * | 1,0 | 1,1 | 1,2 |
+ * --- --- ---
+ * | 0,0 | 0,1 | 0,2 |
+ * --- --- ---
+ * </pre>
+ */
+
+void add_filt_fmask_coord(float filt[3][3], const float col[4], float *rowbuf, int row_stride, int x, int y, rcti *mask)
+{
+ float *fpoin[3][3];
+ float val, r, g, b, al, lfilt[3][3];
+
+ r = col[0];
+ g = col[1];
+ b = col[2];
+ al = col[3];
+
+ memcpy(lfilt, filt, sizeof(lfilt));
+
+ fpoin[0][1] = rowbuf - 4 * row_stride;
+ fpoin[1][1] = rowbuf;
+ fpoin[2][1] = rowbuf + 4 * row_stride;
+
+ fpoin[0][0] = fpoin[0][1] - 4;
+ fpoin[1][0] = fpoin[1][1] - 4;
+ fpoin[2][0] = fpoin[2][1] - 4;
+
+ fpoin[0][2] = fpoin[0][1] + 4;
+ fpoin[1][2] = fpoin[1][1] + 4;
+ fpoin[2][2] = fpoin[2][1] + 4;
+
+ /* limit filtering to withing a mask for border rendering, so pixels don't
+ * leak outside of the border */
+ if (y <= mask->ymin) {
+ fpoin[0][0] = fpoin[1][0];
+ fpoin[0][1] = fpoin[1][1];
+ fpoin[0][2] = fpoin[1][2];
+ /* filter needs the opposite value yes! */
+ lfilt[0][0] = filt[2][0];
+ lfilt[0][1] = filt[2][1];
+ lfilt[0][2] = filt[2][2];
+ }
+ else if (y >= mask->ymax - 1) {
+ fpoin[2][0] = fpoin[1][0];
+ fpoin[2][1] = fpoin[1][1];
+ fpoin[2][2] = fpoin[1][2];
+
+ lfilt[2][0] = filt[0][0];
+ lfilt[2][1] = filt[0][1];
+ lfilt[2][2] = filt[0][2];
+ }
+
+ if (x <= mask->xmin) {
+ fpoin[2][0] = fpoin[2][1];
+ fpoin[1][0] = fpoin[1][1];
+ fpoin[0][0] = fpoin[0][1];
+
+ lfilt[2][0] = filt[2][2];
+ lfilt[1][0] = filt[1][2];
+ lfilt[0][0] = filt[0][2];
+ }
+ else if (x >= mask->xmax - 1) {
+ fpoin[2][2] = fpoin[2][1];
+ fpoin[1][2] = fpoin[1][1];
+ fpoin[0][2] = fpoin[0][1];
+
+ lfilt[2][2] = filt[2][0];
+ lfilt[1][2] = filt[1][0];
+ lfilt[0][2] = filt[0][0];
+ }
+
+
+ /* loop unroll */
+#define MASKFILT(i, j) \
+ val = lfilt[i][j]; \
+ if (val != 0.0f) { \
+ float *fp = fpoin[i][j]; \
+ fp[0] += val * r; \
+ fp[1] += val * g; \
+ fp[2] += val * b; \
+ fp[3] += val * al; \
+ } (void)0
+
+ MASKFILT(0, 0);
+ MASKFILT(0, 1);
+ MASKFILT(0, 2);
+ MASKFILT(1, 0);
+ MASKFILT(1, 1);
+ MASKFILT(1, 2);
+ MASKFILT(2, 0);
+ MASKFILT(2, 1);
+ MASKFILT(2, 2);
+
+#undef MASKFILT
+}
+
+void add_filt_fmask_pixsize(unsigned int mask, float *in, float *rowbuf, int row_w, int pixsize)
+{
+ /* calc the value of mask */
+ float **fmask1 = R.samples->fmask1, **fmask2 = R.samples->fmask2;
+ float *rb1, *rb2, *rb3;
+ float val;
+ unsigned int a, maskand, maskshift;
+ int i, j;
+
+ rb2 = rowbuf - pixsize;
+ rb3 = rb2 - pixsize * row_w;
+ rb1 = rb2 + pixsize * row_w;
+
+ maskand = (mask & 255);
+ maskshift = (mask >> 8);
+
+ for (j = 2; j >= 0; j--) {
+
+ a = j;
+
+ val = *(fmask1[a] + maskand) + *(fmask2[a] + maskshift);
+ if (val != 0.0f) {
+ for (i = 0; i < pixsize; i++)
+ rb1[i] += val * in[i];
+ }
+ a += 3;
+
+ val = *(fmask1[a] + maskand) + *(fmask2[a] + maskshift);
+ if (val != 0.0f) {
+ for (i = 0; i < pixsize; i++)
+ rb2[i] += val * in[i];
+ }
+ a += 3;
+
+ val = *(fmask1[a] + maskand) + *(fmask2[a] + maskshift);
+ if (val != 0.0f) {
+ for (i = 0; i < pixsize; i++)
+ rb3[i] += val * in[i];
+ }
+
+ rb1 += pixsize;
+ rb2 += pixsize;
+ rb3 += pixsize;
+ }
+}
+
+/* ------------------------------------------------------------------------- */
+void addalphaAddFloat(float dest[4], const float source[4])
+{
+
+ /* Makes me wonder whether this is required... */
+ if (dest[3] < RE_EMPTY_COLOR_FLOAT) {
+ dest[0] = source[0];
+ dest[1] = source[1];
+ dest[2] = source[2];
+ dest[3] = source[3];
+ return;
+ }
+
+ /* no clipping! */
+ dest[0] = dest[0] + source[0];
+ dest[1] = dest[1] + source[1];
+ dest[2] = dest[2] + source[2];
+ dest[3] = dest[3] + source[3];
+
+}
+
+
+/* ---------------------------------------------------------------------------- */
diff --git a/source/blender/render/intern/source/pixelshading.c b/source/blender/render/intern/source/pixelshading.c
new file mode 100644
index 00000000000..7f202629ce4
--- /dev/null
+++ b/source/blender/render/intern/source/pixelshading.c
@@ -0,0 +1,650 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * Contributor(s): 2004-2006, Blender Foundation, full recode
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/render/intern/source/pixelshading.c
+ * \ingroup render
+ */
+
+
+#include <float.h>
+#include <math.h>
+#include <string.h>
+
+#include "BLI_math.h"
+#include "BLI_utildefines.h"
+
+/* External modules: */
+
+#include "DNA_group_types.h"
+#include "DNA_material_types.h"
+#include "DNA_object_types.h"
+#include "DNA_image_types.h"
+#include "DNA_texture_types.h"
+#include "DNA_lamp_types.h"
+
+#include "BKE_material.h"
+
+
+/* own module */
+#include "render_types.h"
+#include "renderdatabase.h"
+#include "texture.h"
+#include "rendercore.h"
+#include "shadbuf.h"
+#include "pixelshading.h"
+#include "sunsky.h"
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+/* defined in pipeline.c, is hardcopy of active dynamic allocated Render */
+/* only to be used here in this file, it's for speed */
+extern struct Render R;
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+
+extern const float hashvectf[];
+
+static void render_lighting_halo(HaloRen *har, float col_r[3])
+{
+ GroupObject *go;
+ LampRen *lar;
+ float i, inp, inpr, rco[3], dco[3], lv[3], lampdist, ld, t, *vn;
+ float ir, ig, ib, shadfac, soft, lacol[3];
+
+ ir= ig= ib= 0.0;
+
+ copy_v3_v3(rco, har->co);
+ dco[0]=dco[1]=dco[2]= 1.0f/har->rad;
+
+ vn= har->no;
+
+ for (go=R.lights.first; go; go= go->next) {
+ lar= go->lampren;
+
+ /* test for lamplayer */
+ if (lar->mode & LA_LAYER) if ((lar->lay & har->lay)==0) continue;
+
+ /* lampdist cacluation */
+ if (lar->type==LA_SUN || lar->type==LA_HEMI) {
+ copy_v3_v3(lv, lar->vec);
+ lampdist= 1.0;
+ }
+ else {
+ lv[0]= rco[0]-lar->co[0];
+ lv[1]= rco[1]-lar->co[1];
+ lv[2]= rco[2]-lar->co[2];
+ ld = len_v3(lv);
+ lv[0]/= ld;
+ lv[1]/= ld;
+ lv[2]/= ld;
+
+ /* ld is re-used further on (texco's) */
+
+ if (lar->mode & LA_QUAD) {
+ t= 1.0;
+ if (lar->ld1>0.0f)
+ t= lar->dist/(lar->dist+lar->ld1*ld);
+ if (lar->ld2>0.0f)
+ t*= lar->distkw/(lar->distkw+lar->ld2*ld*ld);
+
+ lampdist= t;
+ }
+ else {
+ lampdist= (lar->dist/(lar->dist+ld));
+ }
+
+ if (lar->mode & LA_SPHERE) {
+ t= lar->dist - ld;
+ if (t<0.0f) continue;
+
+ t/= lar->dist;
+ lampdist*= (t);
+ }
+
+ }
+
+ lacol[0]= lar->r;
+ lacol[1]= lar->g;
+ lacol[2]= lar->b;
+
+ if (lar->mode & LA_TEXTURE) {
+ ShadeInput shi;
+
+ /* Warning, This is not that nice, and possibly a bit slow,
+ * however some variables were not initialized properly in, unless using shade_input_initialize(...),
+ * we need to do a memset */
+ memset(&shi, 0, sizeof(ShadeInput));
+ /* end warning! - Campbell */
+
+ copy_v3_v3(shi.co, rco);
+ shi.osatex= 0;
+ do_lamp_tex(lar, lv, &shi, lacol, LA_TEXTURE);
+ }
+
+ if (lar->type==LA_SPOT) {
+
+ if (lar->mode & LA_SQUARE) {
+ if (lv[0]*lar->vec[0]+lv[1]*lar->vec[1]+lv[2]*lar->vec[2]>0.0f) {
+ float x, lvrot[3];
+
+ /* rotate view to lampspace */
+ copy_v3_v3(lvrot, lv);
+ mul_m3_v3(lar->imat, lvrot);
+
+ x = max_ff(fabsf(lvrot[0]/lvrot[2]), fabsf(lvrot[1]/lvrot[2]));
+ /* 1.0/(sqrt(1+x*x)) is equivalent to cos(atan(x)) */
+
+ inpr = 1.0f / (sqrtf(1.0f + x * x));
+ }
+ else inpr= 0.0;
+ }
+ else {
+ inpr= lv[0]*lar->vec[0]+lv[1]*lar->vec[1]+lv[2]*lar->vec[2];
+ }
+
+ t= lar->spotsi;
+ if (inpr<t) continue;
+ else {
+ t= inpr-t;
+ soft= 1.0;
+ if (t<lar->spotbl && lar->spotbl!=0.0f) {
+ /* soft area */
+ i= t/lar->spotbl;
+ t= i*i;
+ soft= (3.0f*t-2.0f*t*i);
+ inpr*= soft;
+ }
+ if (lar->mode & LA_ONLYSHADOW) {
+ /* if (ma->mode & MA_SHADOW) { */
+ /* dot product positive: front side face! */
+ inp= vn[0]*lv[0] + vn[1]*lv[1] + vn[2]*lv[2];
+ if (inp>0.0f) {
+ /* testshadowbuf==0.0 : 100% shadow */
+ shadfac = testshadowbuf(&R, lar->shb, rco, dco, dco, inp, 0.0f);
+ if ( shadfac>0.0f ) {
+ shadfac*= inp*soft*lar->energy;
+ ir -= shadfac;
+ ig -= shadfac;
+ ib -= shadfac;
+
+ continue;
+ }
+ }
+ /* } */
+ }
+ lampdist*=inpr;
+ }
+ if (lar->mode & LA_ONLYSHADOW) continue;
+
+ }
+
+ /* dot product and reflectivity*/
+
+ inp = 1.0f - fabsf(dot_v3v3(vn, lv));
+
+ /* inp= cos(0.5*M_PI-acos(inp)); */
+
+ i= inp;
+
+ if (lar->type==LA_HEMI) {
+ i= 0.5f*i+0.5f;
+ }
+ if (i>0.0f) {
+ i*= lampdist;
+ }
+
+ /* shadow */
+ if (i> -0.41f) { /* heuristic valua! */
+ if (lar->shb) {
+ shadfac = testshadowbuf(&R, lar->shb, rco, dco, dco, inp, 0.0f);
+ if (shadfac==0.0f) continue;
+ i*= shadfac;
+ }
+ }
+
+ if (i>0.0f) {
+ ir+= i*lacol[0];
+ ig+= i*lacol[1];
+ ib+= i*lacol[2];
+ }
+ }
+
+ if (ir<0.0f) ir= 0.0f;
+ if (ig<0.0f) ig= 0.0f;
+ if (ib<0.0f) ib= 0.0f;
+
+ col_r[0]*= ir;
+ col_r[1]*= ig;
+ col_r[2]*= ib;
+
+}
+
+
+/**
+ * Converts a halo z-buffer value to distance from the camera's near plane
+ * \param z The z-buffer value to convert
+ * \return a distance from the camera's near plane in blender units
+ */
+static float haloZtoDist(int z)
+{
+ float zco = 0;
+
+ if (z >= 0x7FFFFF)
+ return 10e10;
+ else {
+ zco = (float)z/(float)0x7FFFFF;
+ if (R.r.mode & R_ORTHO)
+ return (R.winmat[3][2] - zco*R.winmat[3][3])/(R.winmat[2][2]);
+ else
+ return (R.winmat[3][2])/(R.winmat[2][2] - R.winmat[2][3]*zco);
+ }
+}
+
+/**
+ * \param col (float[4]) Store the rgb color here (with alpha)
+ * The alpha is used to blend the color to the background
+ * color_new = (1-alpha)*color_background + color
+ * \param zz The current zbuffer value at the place of this pixel
+ * \param dist Distance of the pixel from the center of the halo squared. Given in pixels
+ * \param xn The x coordinate of the pixel relaticve to the center of the halo. given in pixels
+ * \param yn The y coordinate of the pixel relaticve to the center of the halo. given in pixels
+ */
+int shadeHaloFloat(HaloRen *har, float col[4], int zz,
+ float dist, float xn, float yn, short flarec)
+{
+ /* fill in col */
+ float t, zn, radist, ringf=0.0f, linef=0.0f, alpha, si, co;
+ int a;
+
+ if (R.wrld.mode & WO_MIST) {
+ if (har->type & HA_ONLYSKY) {
+ alpha= har->alfa;
+ }
+ else {
+ /* a bit patchy... */
+ alpha= mistfactor(-har->co[2], har->co)*har->alfa;
+ }
+ }
+ else alpha= har->alfa;
+
+ if (alpha==0.0f)
+ return 0;
+
+ /* soften the halo if it intersects geometry */
+ if (har->mat && har->mat->mode & MA_HALO_SOFT) {
+ float segment_length, halo_depth, distance_from_z /* , visible_depth */ /* UNUSED */, soften;
+
+ /* calculate halo depth */
+ segment_length= har->hasize*sasqrt(1.0f - dist/(har->rad*har->rad));
+ halo_depth= 2.0f*segment_length;
+
+ if (halo_depth < FLT_EPSILON)
+ return 0;
+
+ /* calculate how much of this depth is visible */
+ distance_from_z = haloZtoDist(zz) - haloZtoDist(har->zs);
+ /* visible_depth = halo_depth; */ /* UNUSED */
+ if (distance_from_z < segment_length) {
+ soften= (segment_length + distance_from_z)/halo_depth;
+
+ /* apply softening to alpha */
+ if (soften < 1.0f)
+ alpha *= soften;
+ if (alpha <= 0.0f)
+ return 0;
+ }
+ }
+ else {
+ /* not a soft halo. use the old softening code */
+ /* halo being intersected? */
+ if (har->zs> zz-har->zd) {
+ t= ((float)(zz-har->zs))/(float)har->zd;
+ alpha*= sqrtf(sqrtf(t));
+ }
+ }
+
+ radist = sqrtf(dist);
+
+ /* watch it: not used nicely: flarec is set at zero in pixstruct */
+ if (flarec) har->pixels+= (int)(har->rad-radist);
+
+ if (har->ringc) {
+ const float *rc;
+ float fac;
+ int ofs;
+
+ /* per ring an antialised circle */
+ ofs= har->seed;
+
+ for (a= har->ringc; a>0; a--, ofs+=2) {
+
+ rc= hashvectf + (ofs % 768);
+
+ fac = fabsf(rc[1] * (har->rad * fabsf(rc[0]) - radist));
+
+ if (fac< 1.0f) {
+ ringf+= (1.0f-fac);
+ }
+ }
+ }
+
+ if (har->type & HA_VECT) {
+ dist= fabsf(har->cos * (yn) - har->sin * (xn)) / har->rad;
+ if (dist>1.0f) dist= 1.0f;
+ if (har->tex) {
+ zn= har->sin*xn - har->cos*yn;
+ yn= har->cos*xn + har->sin*yn;
+ xn= zn;
+ }
+ }
+ else dist= dist/har->radsq;
+
+ if (har->type & HA_FLARECIRC) {
+ dist = 0.5f + fabsf(dist - 0.5f);
+ }
+
+ if (har->hard>=30) {
+ dist = sqrtf(dist);
+ if (har->hard>=40) {
+ dist = sinf(dist*(float)M_PI_2);
+ if (har->hard>=50) {
+ dist = sqrtf(dist);
+ }
+ }
+ }
+ else if (har->hard<20) dist*=dist;
+
+ if (dist < 1.0f)
+ dist= (1.0f-dist);
+ else
+ dist= 0.0f;
+
+ if (har->linec) {
+ const float *rc;
+ float fac;
+ int ofs;
+
+ /* per starpoint an antialiased line */
+ ofs= har->seed;
+
+ for (a= har->linec; a>0; a--, ofs+=3) {
+
+ rc= hashvectf + (ofs % 768);
+
+ fac = fabsf((xn) * rc[0] + (yn) * rc[1]);
+
+ if (fac< 1.0f )
+ linef+= (1.0f-fac);
+ }
+
+ linef*= dist;
+ }
+
+ if (har->starpoints) {
+ float ster, angle;
+ /* rotation */
+ angle = atan2f(yn, xn);
+ angle *= (1.0f+0.25f*har->starpoints);
+
+ co= cosf(angle);
+ si= sinf(angle);
+
+ angle= (co*xn+si*yn)*(co*yn-si*xn);
+
+ ster = fabsf(angle);
+ if (ster>1.0f) {
+ ster= (har->rad)/(ster);
+
+ if (ster<1.0f) dist*= sqrtf(ster);
+ }
+ }
+
+ /* disputable optimize... (ton) */
+ if (dist<=0.00001f)
+ return 0;
+
+ dist*= alpha;
+ ringf*= dist;
+ linef*= alpha;
+
+ /* The color is either the rgb spec-ed by the user, or extracted from */
+ /* the texture */
+ if (har->tex) {
+ col[0]= har->r;
+ col[1]= har->g;
+ col[2]= har->b;
+ col[3]= dist;
+
+ do_halo_tex(har, xn, yn, col);
+
+ col[0]*= col[3];
+ col[1]*= col[3];
+ col[2]*= col[3];
+
+ }
+ else {
+ col[0]= dist*har->r;
+ col[1]= dist*har->g;
+ col[2]= dist*har->b;
+ if (har->type & HA_XALPHA) col[3]= dist*dist;
+ else col[3]= dist;
+ }
+
+ if (har->mat) {
+ if (har->mat->mode & MA_HALO_SHADE) {
+ /* we test for lights because of preview... */
+ if (R.lights.first) render_lighting_halo(har, col);
+ }
+
+ /* Next, we do the line and ring factor modifications. */
+ if (linef!=0.0f) {
+ Material *ma= har->mat;
+
+ col[0]+= linef * ma->specr;
+ col[1]+= linef * ma->specg;
+ col[2]+= linef * ma->specb;
+
+ if (har->type & HA_XALPHA) col[3]+= linef*linef;
+ else col[3]+= linef;
+ }
+ if (ringf!=0.0f) {
+ Material *ma= har->mat;
+
+ col[0]+= ringf * ma->mirr;
+ col[1]+= ringf * ma->mirg;
+ col[2]+= ringf * ma->mirb;
+
+ if (har->type & HA_XALPHA) col[3]+= ringf*ringf;
+ else col[3]+= ringf;
+ }
+ }
+
+ /* alpha requires clip, gives black dots */
+ if (col[3] > 1.0f)
+ col[3]= 1.0f;
+
+ return 1;
+}
+
+/* ------------------------------------------------------------------------- */
+
+/* Only view vector is important here. Result goes to col_r[3] */
+void shadeSkyView(float col_r[3], const float rco[3], const float view[3], const float dxyview[2], short thread)
+{
+ float zen[3], hor[3], blend, blendm;
+ int skyflag;
+
+ /* flag indicating if we render the top hemisphere */
+ skyflag = WO_ZENUP;
+
+ /* Some view vector stuff. */
+ if (R.wrld.skytype & WO_SKYREAL) {
+
+ blend = dot_v3v3(view, R.grvec);
+
+ if (blend<0.0f) skyflag= 0;
+
+ blend = fabsf(blend);
+ }
+ else if (R.wrld.skytype & WO_SKYPAPER) {
+ blend= 0.5f + 0.5f * view[1];
+ }
+ else {
+ /* the fraction of how far we are above the bottom of the screen */
+ blend = fabsf(0.5f + view[1]);
+ }
+
+ copy_v3_v3(hor, &R.wrld.horr);
+ copy_v3_v3(zen, &R.wrld.zenr);
+
+ /* Careful: SKYTEX and SKYBLEND are NOT mutually exclusive! If */
+ /* SKYBLEND is active, the texture and color blend are added. */
+ if (R.wrld.skytype & WO_SKYTEX) {
+ float lo[3];
+ copy_v3_v3(lo, view);
+ if (R.wrld.skytype & WO_SKYREAL) {
+
+ mul_m3_v3(R.imat, lo);
+
+ SWAP(float, lo[1], lo[2]);
+
+ }
+ do_sky_tex(rco, view, lo, dxyview, hor, zen, &blend, skyflag, thread);
+ }
+
+ if (blend>1.0f) blend= 1.0f;
+ blendm= 1.0f-blend;
+
+ /* No clipping, no conversion! */
+ if (R.wrld.skytype & WO_SKYBLEND) {
+ col_r[0] = (blendm*hor[0] + blend*zen[0]);
+ col_r[1] = (blendm*hor[1] + blend*zen[1]);
+ col_r[2] = (blendm*hor[2] + blend*zen[2]);
+ }
+ else {
+ /* Done when a texture was grabbed. */
+ col_r[0]= hor[0];
+ col_r[1]= hor[1];
+ col_r[2]= hor[2];
+ }
+}
+
+/* shade sky according to sun lamps, all parameters are like shadeSkyView except sunsky*/
+void shadeSunView(float col_r[3], const float view[3])
+{
+ GroupObject *go;
+ LampRen *lar;
+ float sview[3];
+ bool do_init = true;
+
+ for (go=R.lights.first; go; go= go->next) {
+ lar= go->lampren;
+ if (lar->type==LA_SUN && lar->sunsky && (lar->sunsky->effect_type & LA_SUN_EFFECT_SKY)) {
+ float sun_collector[3];
+ float colorxyz[3];
+
+ if (do_init) {
+
+ normalize_v3_v3(sview, view);
+ mul_m3_v3(R.imat, sview);
+ if (sview[2] < 0.0f)
+ sview[2] = 0.0f;
+ normalize_v3(sview);
+ do_init = false;
+ }
+
+ GetSkyXYZRadiancef(lar->sunsky, sview, colorxyz);
+ xyz_to_rgb(colorxyz[0], colorxyz[1], colorxyz[2], &sun_collector[0], &sun_collector[1], &sun_collector[2],
+ lar->sunsky->sky_colorspace);
+
+ ramp_blend(lar->sunsky->skyblendtype, col_r, lar->sunsky->skyblendfac, sun_collector);
+ }
+ }
+}
+
+
+/*
+ * Stuff the sky color into the collector.
+ */
+void shadeSkyPixel(float collector[4], float fx, float fy, short thread)
+{
+ float view[3], dxyview[2];
+
+ /*
+ * The rules for sky:
+ * 1. Draw an image, if a background image was provided. Stop
+ * 2. get texture and color blend, and combine these.
+ */
+
+ float fac;
+
+ if ((R.wrld.skytype & (WO_SKYBLEND+WO_SKYTEX))==0) {
+ /* 1. solid color */
+ copy_v3_v3(collector, &R.wrld.horr);
+
+ collector[3] = 0.0f;
+ }
+ else {
+ /* 2. */
+
+ /* This one true because of the context of this routine */
+ if (R.wrld.skytype & WO_SKYPAPER) {
+ view[0]= -1.0f + 2.0f*(fx/(float)R.winx);
+ view[1]= -1.0f + 2.0f*(fy/(float)R.winy);
+ view[2]= 0.0;
+
+ dxyview[0]= 1.0f/(float)R.winx;
+ dxyview[1]= 1.0f/(float)R.winy;
+ }
+ else {
+ calc_view_vector(view, fx, fy);
+ fac= normalize_v3(view);
+
+ if (R.wrld.skytype & WO_SKYTEX) {
+ dxyview[0]= -R.viewdx/fac;
+ dxyview[1]= -R.viewdy/fac;
+ }
+ }
+
+ /* get sky color in the collector */
+ shadeSkyView(collector, NULL, view, dxyview, thread);
+ collector[3] = 0.0f;
+ }
+
+ calc_view_vector(view, fx, fy);
+ shadeSunView(collector, view);
+}
+
+/* aerial perspective */
+void shadeAtmPixel(struct SunSky *sunsky, float collector[3], float fx, float fy, float distance)
+{
+ float view[3];
+
+ calc_view_vector(view, fx, fy);
+ normalize_v3(view);
+ /*mul_m3_v3(R.imat, view);*/
+ AtmospherePixleShader(sunsky, view, distance, collector);
+}
+
+/* eof */
diff --git a/source/blender/render/intern/source/pointdensity.c b/source/blender/render/intern/source/pointdensity.c
index 53359c305dc..c025a1fdef7 100644
--- a/source/blender/render/intern/source/pointdensity.c
+++ b/source/blender/render/intern/source/pointdensity.c
@@ -102,7 +102,7 @@ static void point_data_pointers(PointDensity *pd,
const int totpoint = pd->totpoints;
float *data = pd->point_data;
int offset = 0;
-
+
if (data_used & POINT_DATA_VEL) {
if (r_data_velocity)
*r_data_velocity = data + offset;
@@ -112,7 +112,7 @@ static void point_data_pointers(PointDensity *pd,
if (r_data_velocity)
*r_data_velocity = NULL;
}
-
+
if (data_used & POINT_DATA_LIFE) {
if (r_data_life)
*r_data_life = data + offset;
@@ -122,7 +122,7 @@ static void point_data_pointers(PointDensity *pd,
if (r_data_life)
*r_data_life = NULL;
}
-
+
if (data_used & POINT_DATA_COLOR) {
if (r_data_color)
*r_data_color = data + offset;
@@ -283,19 +283,19 @@ static void pointdensity_cache_vertex_color(PointDensity *pd, Object *UNUSED(ob)
const MLoopCol *mcol;
char layername[MAX_CUSTOMDATA_LAYER_NAME];
int i;
-
+
BLI_assert(data_color);
-
+
if (!CustomData_has_layer(&mesh->ldata, CD_MLOOPCOL))
return;
CustomData_validate_layer_name(&mesh->ldata, CD_MLOOPCOL, pd->vertex_attribute_name, layername);
mcol = CustomData_get_layer_named(&mesh->ldata, CD_MLOOPCOL, layername);
if (!mcol)
return;
-
+
/* Stores the number of MLoops using the same vertex, so we can normalize colors. */
int *mcorners = MEM_callocN(sizeof(int) * pd->totpoints, "point density corner count");
-
+
for (i = 0; i < totloop; i++) {
int v = mloop[i].v;
@@ -310,7 +310,7 @@ static void pointdensity_cache_vertex_color(PointDensity *pd, Object *UNUSED(ob)
++mcorners[v];
}
-
+
/* Normalize colors by averaging over mcorners.
* All the corners share the same vertex, ie. occupy the same point in space.
*/
@@ -318,7 +318,7 @@ static void pointdensity_cache_vertex_color(PointDensity *pd, Object *UNUSED(ob)
if (mcorners[i] > 0)
mul_v3_fl(&data_color[i*3], 1.0f / mcorners[i]);
}
-
+
MEM_freeN(mcorners);
}
@@ -328,9 +328,9 @@ static void pointdensity_cache_vertex_weight(PointDensity *pd, Object *ob, Mesh
const MDeformVert *mdef, *dv;
int mdef_index;
int i;
-
+
BLI_assert(data_color);
-
+
mdef = CustomData_get_layer(&mesh->vdata, CD_MDEFORMVERT);
if (!mdef)
return;
@@ -339,11 +339,11 @@ static void pointdensity_cache_vertex_weight(PointDensity *pd, Object *ob, Mesh
mdef_index = ob->actdef - 1;
if (mdef_index < 0)
return;
-
+
for (i = 0, dv = mdef; i < totvert; ++i, ++dv, data_color += 3) {
MDeformWeight *dw;
int j;
-
+
for (j = 0, dw = dv->dw; j < dv->totweight; ++j, ++dw) {
if (dw->def_nr == mdef_index) {
copy_v3_fl(data_color, dw->weight);
@@ -357,9 +357,9 @@ static void pointdensity_cache_vertex_normal(PointDensity *pd, Object *UNUSED(ob
{
MVert *mvert = mesh->mvert, *mv;
int i;
-
+
BLI_assert(data_color);
-
+
for (i = 0, mv = mvert; i < pd->totpoints; i++, mv++, data_color += 3) {
normal_short_to_float_v3(data_color, mv->no);
}
@@ -413,7 +413,7 @@ static void pointdensity_cache_object(PointDensity *pd,
BLI_bvhtree_insert(pd->point_tree, i, co, 1);
}
-
+
switch (pd->ob_color_source) {
case TEX_PD_COLOR_VERTCOL:
pointdensity_cache_vertex_color(pd, ob, mesh, data_color);
@@ -506,7 +506,7 @@ static float density_falloff(PointDensityRangeData *pdr, int index, float square
{
const float dist = (pdr->squared_radius - squared_dist) / pdr->squared_radius * 0.5f;
float density = 0.0f;
-
+
switch (pdr->falloff_type) {
case TEX_PD_FALLOFF_STD:
density = dist;
@@ -536,12 +536,12 @@ static float density_falloff(PointDensityRangeData *pdr, int index, float square
density = dist;
break;
}
-
+
if (pdr->density_curve && dist != 0.0f) {
curvemapping_initialize(pdr->density_curve);
density = curvemapping_evaluateF(pdr->density_curve, 0, density / dist) * dist;
}
-
+
return density;
}
@@ -666,7 +666,7 @@ static void pointdensity_color(PointDensity *pd, TexResult *texres, float age, c
if (pd->source == TEX_PD_PSYS) {
float rgba[4];
-
+
switch (pd->color_source) {
case TEX_PD_COLOR_PARTAGE:
if (pd->coba) {
@@ -681,7 +681,7 @@ static void pointdensity_color(PointDensity *pd, TexResult *texres, float age, c
case TEX_PD_COLOR_PARTSPEED:
{
float speed = len_v3(vec) * pd->speed_scale;
-
+
if (pd->coba) {
if (BKE_colorband_evaluate(pd->coba, speed, rgba)) {
texres->talpha = true;
@@ -704,7 +704,7 @@ static void pointdensity_color(PointDensity *pd, TexResult *texres, float age, c
}
else {
float rgba[4];
-
+
switch (pd->ob_color_source) {
case TEX_PD_COLOR_VERTCOL:
texres->talpha = true;
diff --git a/source/blender/render/intern/source/rayshade.c b/source/blender/render/intern/source/rayshade.c
new file mode 100644
index 00000000000..df1cb868230
--- /dev/null
+++ b/source/blender/render/intern/source/rayshade.c
@@ -0,0 +1,2503 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 1990-1998 NeoGeo BV.
+ * All rights reserved.
+ *
+ * Contributors: 2004/2005 Blender Foundation, full recode
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/render/intern/source/rayshade.c
+ * \ingroup render
+ */
+
+#include <stdio.h>
+#include <math.h>
+#include <string.h>
+#include <stdlib.h>
+#include <float.h>
+#include <assert.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_material_types.h"
+#include "DNA_lamp_types.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_system.h"
+#include "BLI_math.h"
+#include "BLI_rand.h"
+#include "BLI_utildefines.h"
+
+#include "BLT_translation.h"
+
+#include "BKE_node.h"
+
+#include "render_result.h"
+#include "render_types.h"
+#include "rendercore.h"
+#include "renderdatabase.h"
+#include "pixelshading.h"
+#include "shading.h"
+#include "volumetric.h"
+
+#include "rayintersection.h"
+#include "rayobject.h"
+#include "raycounter.h"
+
+#define RAY_TRA 1
+#define RAY_INSIDE 2
+
+#define DEPTH_SHADOW_TRA 10
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+/* defined in pipeline.c, is hardcopy of active dynamic allocated Render */
+/* only to be used here in this file, it's for speed */
+extern struct Render R;
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+static int test_break(void *data)
+{
+ Render *re = (Render *)data;
+ return re->test_break(re->tbh);
+}
+
+static void RE_rayobject_config_control(RayObject *r, Render *re)
+{
+ if (RE_rayobject_isRayAPI(r)) {
+ r = RE_rayobject_align(r);
+ r->control.data = re;
+ r->control.test_break = test_break;
+ }
+}
+
+RayObject *RE_rayobject_create(int type, int size, int octree_resolution)
+{
+ RayObject * res = NULL;
+
+ if (type == R_RAYSTRUCTURE_AUTO) {
+ /* TODO */
+ //if (detect_simd())
+#ifdef __SSE__
+ type = BLI_cpu_support_sse2()? R_RAYSTRUCTURE_SIMD_SVBVH: R_RAYSTRUCTURE_VBVH;
+#else
+ type = R_RAYSTRUCTURE_VBVH;
+#endif
+ }
+
+#ifndef __SSE__
+ if (type == R_RAYSTRUCTURE_SIMD_SVBVH || type == R_RAYSTRUCTURE_SIMD_QBVH) {
+ puts("Warning: Using VBVH (SSE was disabled at compile time)");
+ type = R_RAYSTRUCTURE_VBVH;
+ }
+#endif
+
+
+ if (type == R_RAYSTRUCTURE_OCTREE) //TODO dynamic ocres
+ res = RE_rayobject_octree_create(octree_resolution, size);
+ else if (type == R_RAYSTRUCTURE_VBVH)
+ res = RE_rayobject_vbvh_create(size);
+ else if (type == R_RAYSTRUCTURE_SIMD_SVBVH)
+ res = RE_rayobject_svbvh_create(size);
+ else if (type == R_RAYSTRUCTURE_SIMD_QBVH)
+ res = RE_rayobject_qbvh_create(size);
+ else
+ res = RE_rayobject_vbvh_create(size); //Fallback
+
+ return res;
+}
+
+static RayObject* rayobject_create(Render *re, int type, int size)
+{
+ RayObject * res = NULL;
+
+ res = RE_rayobject_create(type, size, re->r.ocres);
+
+ if (res)
+ RE_rayobject_config_control(res, re);
+
+ return res;
+}
+
+#ifdef RE_RAYCOUNTER
+RayCounter re_rc_counter[BLENDER_MAX_THREADS];
+#endif
+
+
+void freeraytree(Render *re)
+{
+ ObjectInstanceRen *obi;
+
+ if (re->raytree) {
+ RE_rayobject_free(re->raytree);
+ re->raytree = NULL;
+ }
+ if (re->rayfaces) {
+ MEM_freeN(re->rayfaces);
+ re->rayfaces = NULL;
+ }
+ if (re->rayprimitives) {
+ MEM_freeN(re->rayprimitives);
+ re->rayprimitives = NULL;
+ }
+
+ for (obi=re->instancetable.first; obi; obi=obi->next) {
+ ObjectRen *obr = obi->obr;
+ if (obr->raytree) {
+ RE_rayobject_free(obr->raytree);
+ obr->raytree = NULL;
+ }
+ if (obr->rayfaces) {
+ MEM_freeN(obr->rayfaces);
+ obr->rayfaces = NULL;
+ }
+ if (obi->raytree) {
+ RE_rayobject_free(obi->raytree);
+ obi->raytree = NULL;
+ }
+ }
+
+#ifdef RE_RAYCOUNTER
+ {
+ const int num_threads = re->r.threads;
+ RayCounter sum;
+ memset(&sum, 0, sizeof(sum));
+ int i;
+ for (i=0; i<num_threads; i++)
+ RE_RC_MERGE(&sum, re_rc_counter+i);
+ RE_RC_INFO(&sum);
+ }
+#endif
+}
+
+static bool is_raytraceable_vlr(Render *re, VlakRen *vlr)
+{
+ /* note: volumetric must be tracable, wire must not */
+ if ((re->flag & R_BAKE_TRACE) || (vlr->flag & R_TRACEBLE) || (vlr->mat->material_type == MA_TYPE_VOLUME))
+ if (vlr->mat->material_type != MA_TYPE_WIRE)
+ return 1;
+ return 0;
+}
+
+static bool is_raytraceable(Render *re, ObjectInstanceRen *obi)
+{
+ int v;
+ ObjectRen *obr = obi->obr;
+
+ if (re->excludeob && obr->ob == re->excludeob)
+ return 0;
+
+ for (v=0;v<obr->totvlak;v++) {
+ VlakRen *vlr = obr->vlaknodes[v>>8].vlak + (v&255);
+
+ if (is_raytraceable_vlr(re, vlr))
+ return 1;
+ }
+
+ return 0;
+}
+
+
+RayObject* makeraytree_object(Render *re, ObjectInstanceRen *obi)
+{
+ /*TODO
+ * out-of-memory safeproof
+ * break render
+ * update render stats */
+ ObjectRen *obr = obi->obr;
+
+ if (obr->raytree == NULL) {
+ RayObject *raytree;
+ RayFace *face = NULL;
+ VlakPrimitive *vlakprimitive = NULL;
+ int v;
+
+ //Count faces
+ int faces = 0;
+ for (v=0;v<obr->totvlak;v++) {
+ VlakRen *vlr = obr->vlaknodes[v>>8].vlak + (v&255);
+ if (is_raytraceable_vlr(re, vlr))
+ faces++;
+ }
+
+ if (faces == 0)
+ return NULL;
+
+ //Create Ray cast accelaration structure
+ raytree = rayobject_create( re, re->r.raytrace_structure, faces );
+ if ( (re->r.raytrace_options & R_RAYTRACE_USE_LOCAL_COORDS) )
+ vlakprimitive = obr->rayprimitives = (VlakPrimitive *)MEM_callocN(faces * sizeof(VlakPrimitive), "ObjectRen primitives");
+ else
+ face = obr->rayfaces = (RayFace *)MEM_callocN(faces * sizeof(RayFace), "ObjectRen faces");
+
+ obr->rayobi = obi;
+
+ for (v=0;v<obr->totvlak;v++) {
+ VlakRen *vlr = obr->vlaknodes[v>>8].vlak + (v&255);
+ if (is_raytraceable_vlr(re, vlr)) {
+ if ((re->r.raytrace_options & R_RAYTRACE_USE_LOCAL_COORDS)) {
+ RE_rayobject_add(raytree, RE_vlakprimitive_from_vlak(vlakprimitive, obi, vlr));
+ vlakprimitive++;
+ }
+ else {
+ RE_rayface_from_vlak(face, obi, vlr);
+ RE_rayobject_add(raytree, RE_rayobject_unalignRayFace(face));
+ face++;
+ }
+ }
+ }
+ RE_rayobject_done(raytree);
+
+ /* in case of cancel during build, raytree is not usable */
+ if (test_break(re))
+ RE_rayobject_free(raytree);
+ else
+ obr->raytree= raytree;
+ }
+
+ if (obr->raytree) {
+ if ((obi->flag & R_TRANSFORMED) && obi->raytree == NULL) {
+ obi->transform_primitives = 0;
+ obi->raytree = RE_rayobject_instance_create( obr->raytree, obi->mat, obi, obi->obr->rayobi );
+ }
+ }
+
+ if (obi->raytree) return obi->raytree;
+ return obi->obr->raytree;
+}
+
+static bool has_special_rayobject(Render *re, ObjectInstanceRen *obi)
+{
+ if ( (obi->flag & R_TRANSFORMED) && (re->r.raytrace_options & R_RAYTRACE_USE_INSTANCES) ) {
+ ObjectRen *obr = obi->obr;
+ int v, faces = 0;
+
+ for (v=0;v<obr->totvlak;v++) {
+ VlakRen *vlr = obr->vlaknodes[v>>8].vlak + (v&255);
+ if (is_raytraceable_vlr(re, vlr)) {
+ faces++;
+ if (faces > 4)
+ return 1;
+ }
+ }
+ }
+ return 0;
+}
+/*
+ * create a single raytrace structure with all faces
+ */
+static void makeraytree_single(Render *re)
+{
+ ObjectInstanceRen *obi;
+ RayObject *raytree;
+ RayFace *face = NULL;
+ VlakPrimitive *vlakprimitive = NULL;
+ int faces = 0, special = 0;
+
+ for (obi = re->instancetable.first; obi; obi = obi->next) {
+ if (is_raytraceable(re, obi)) {
+ ObjectRen *obr = obi->obr;
+
+ if (has_special_rayobject(re, obi)) {
+ special++;
+ }
+ else {
+ int v;
+ for (v = 0;v < obr->totvlak; v++) {
+ VlakRen *vlr = obr->vlaknodes[v >> 8].vlak + (v&255);
+ if (is_raytraceable_vlr(re, vlr)) {
+ faces++;
+ }
+ }
+ }
+ }
+ }
+
+ if (faces + special == 0) {
+ re->raytree = RE_rayobject_empty_create();
+ return;
+ }
+
+ //Create raytree
+ raytree = re->raytree = rayobject_create( re, re->r.raytrace_structure, faces+special );
+
+ if ( (re->r.raytrace_options & R_RAYTRACE_USE_LOCAL_COORDS) ) {
+ vlakprimitive = re->rayprimitives = (VlakPrimitive *)MEM_callocN(faces * sizeof(VlakPrimitive), "Raytrace vlak-primitives");
+ }
+ else {
+ face = re->rayfaces = (RayFace *)MEM_callocN(faces * sizeof(RayFace), "Render ray faces");
+ }
+
+ for (obi=re->instancetable.first; obi; obi=obi->next)
+ if (is_raytraceable(re, obi)) {
+ if (test_break(re))
+ break;
+
+ if (has_special_rayobject(re, obi)) {
+ RayObject *obj = makeraytree_object(re, obi);
+
+ if (test_break(re))
+ break;
+
+ if (obj)
+ RE_rayobject_add(re->raytree, obj);
+ }
+ else {
+ int v;
+ ObjectRen *obr = obi->obr;
+
+ if (obi->flag & R_TRANSFORMED) {
+ obi->transform_primitives = 1;
+ }
+
+ for (v=0;v<obr->totvlak;v++) {
+ VlakRen *vlr = obr->vlaknodes[v>>8].vlak + (v&255);
+ if (is_raytraceable_vlr(re, vlr)) {
+ if ((re->r.raytrace_options & R_RAYTRACE_USE_LOCAL_COORDS)) {
+ RayObject *obj = RE_vlakprimitive_from_vlak( vlakprimitive, obi, vlr );
+ RE_rayobject_add(raytree, obj);
+ vlakprimitive++;
+ }
+ else {
+ RE_rayface_from_vlak(face, obi, vlr);
+ if ((obi->flag & R_TRANSFORMED)) {
+ mul_m4_v3(obi->mat, face->v1);
+ mul_m4_v3(obi->mat, face->v2);
+ mul_m4_v3(obi->mat, face->v3);
+ if (RE_rayface_isQuad(face))
+ mul_m4_v3(obi->mat, face->v4);
+ }
+
+ RE_rayobject_add(raytree, RE_rayobject_unalignRayFace(face));
+ face++;
+ }
+ }
+ }
+ }
+ }
+
+ if (!test_break(re)) {
+ re->i.infostr = IFACE_("Raytree.. building");
+ re->stats_draw(re->sdh, &re->i);
+
+ RE_rayobject_done(raytree);
+ }
+}
+
+void makeraytree(Render *re)
+{
+ float min[3], max[3], sub[3];
+ int i;
+
+ re->i.infostr = IFACE_("Raytree.. preparing");
+ re->stats_draw(re->sdh, &re->i);
+
+ /* disable options not yet supported by octree,
+ * they might actually never be supported (unless people really need it) */
+ if (re->r.raytrace_structure == R_RAYSTRUCTURE_OCTREE)
+ re->r.raytrace_options &= ~( R_RAYTRACE_USE_INSTANCES | R_RAYTRACE_USE_LOCAL_COORDS);
+
+ makeraytree_single(re);
+
+ if (test_break(re)) {
+ freeraytree(re);
+
+ re->i.infostr = IFACE_("Raytree building canceled");
+ re->stats_draw(re->sdh, &re->i);
+ }
+ else {
+ /* Calculate raytree max_size
+ * This is ONLY needed to kept a bogus behavior of SUN and HEMI lights */
+ INIT_MINMAX(min, max);
+ RE_rayobject_merge_bb(re->raytree, min, max);
+ if (min[0] > max[0]) { /* empty raytree */
+ zero_v3(min);
+ zero_v3(max);
+ }
+ for (i=0; i<3; i++) {
+ /* TODO: explain why add top both min and max??? */
+ min[i] += 0.01f;
+ max[i] += 0.01f;
+ sub[i] = max[i]-min[i];
+ }
+
+ re->maxdist = len_v3(sub);
+
+ re->i.infostr = IFACE_("Raytree finished");
+ re->stats_draw(re->sdh, &re->i);
+ }
+
+#ifdef RE_RAYCOUNTER
+ memset(re_rc_counter, 0, sizeof(re_rc_counter));
+#endif
+}
+
+/* if (shi->osatex) */
+static void shade_ray_set_derivative(ShadeInput *shi)
+{
+ float detsh, t00, t10, t01, t11;
+ int axis1, axis2;
+
+ /* find most stable axis to project */
+ axis_dominant_v3(&axis1, &axis2, shi->facenor);
+
+ /* compute u,v and derivatives */
+ if (shi->obi->flag & R_TRANSFORMED) {
+ float v1[3], v2[3], v3[3];
+
+ mul_v3_m3v3(v1, shi->obi->nmat, shi->v1->co);
+ mul_v3_m3v3(v2, shi->obi->nmat, shi->v2->co);
+ mul_v3_m3v3(v3, shi->obi->nmat, shi->v3->co);
+
+ /* same as below */
+ t00= v3[axis1]-v1[axis1]; t01= v3[axis2]-v1[axis2];
+ t10= v3[axis1]-v2[axis1]; t11= v3[axis2]-v2[axis2];
+ }
+ else {
+ const float *v1= shi->v1->co;
+ const float *v2= shi->v2->co;
+ const float *v3= shi->v3->co;
+
+ /* same as above */
+ t00= v3[axis1]-v1[axis1]; t01= v3[axis2]-v1[axis2];
+ t10= v3[axis1]-v2[axis1]; t11= v3[axis2]-v2[axis2];
+ }
+
+ detsh= 1.0f/(t00*t11-t10*t01);
+ t00*= detsh; t01*=detsh;
+ t10*=detsh; t11*=detsh;
+
+ shi->dx_u= shi->dxco[axis1]*t11- shi->dxco[axis2]*t10;
+ shi->dx_v= shi->dxco[axis2]*t00- shi->dxco[axis1]*t01;
+ shi->dy_u= shi->dyco[axis1]*t11- shi->dyco[axis2]*t10;
+ shi->dy_v= shi->dyco[axis2]*t00- shi->dyco[axis1]*t01;
+
+}
+
+/* main ray shader */
+void shade_ray(Isect *is, ShadeInput *shi, ShadeResult *shr)
+{
+ ObjectInstanceRen *obi = (ObjectInstanceRen *)is->hit.ob;
+ VlakRen *vlr = (VlakRen *)is->hit.face;
+
+ /* set up view vector */
+ copy_v3_v3(shi->view, is->dir);
+
+ /* render co */
+ shi->co[0]= is->start[0]+is->dist*(shi->view[0]);
+ shi->co[1]= is->start[1]+is->dist*(shi->view[1]);
+ shi->co[2]= is->start[2]+is->dist*(shi->view[2]);
+
+ normalize_v3(shi->view);
+
+ shi->obi= obi;
+ shi->obr= obi->obr;
+ shi->vlr= vlr;
+ shi->mat= vlr->mat;
+ shade_input_init_material(shi);
+
+ if (is->isect==2)
+ shade_input_set_triangle_i(shi, obi, vlr, 0, 2, 3);
+ else
+ shade_input_set_triangle_i(shi, obi, vlr, 0, 1, 2);
+
+ shi->u= is->u;
+ shi->v= is->v;
+ shi->dx_u= shi->dx_v= shi->dy_u= shi->dy_v= 0.0f;
+
+ if (shi->osatex)
+ shade_ray_set_derivative(shi);
+ shade_input_set_normals(shi);
+
+ shade_input_set_shade_texco(shi);
+ if (shi->mat->material_type == MA_TYPE_VOLUME) {
+ if (ELEM(is->mode, RE_RAY_SHADOW, RE_RAY_SHADOW_TRA)) {
+ shade_volume_shadow(shi, shr, is);
+ }
+ else {
+ shade_volume_outside(shi, shr);
+ }
+ }
+ else if (is->mode==RE_RAY_SHADOW_TRA) {
+ /* temp hack to prevent recursion */
+ if (shi->nodes==0 && shi->mat->nodetree && shi->mat->use_nodes) {
+ ntreeShaderExecTree(shi->mat->nodetree, shi, shr);
+ shi->mat= vlr->mat; /* shi->mat is being set in nodetree */
+ }
+ else
+ shade_color(shi, shr);
+ }
+ else {
+ if (shi->mat->nodetree && shi->mat->use_nodes) {
+ ntreeShaderExecTree(shi->mat->nodetree, shi, shr);
+ shi->mat= vlr->mat; /* shi->mat is being set in nodetree */
+ }
+ else {
+ shade_material_loop(shi, shr);
+ }
+
+ /* raytrace likes to separate the spec color */
+ sub_v3_v3v3(shr->diff, shr->combined, shr->spec);
+ copy_v3_v3(shr->diffshad, shr->diff);
+ }
+
+}
+
+static int refraction(float refract[3], const float n[3], const float view[3], float index)
+{
+ float dot, fac;
+
+ copy_v3_v3(refract, view);
+
+ dot = dot_v3v3(view, n);
+
+ if (dot>0.0f) {
+ index = 1.0f/index;
+ fac= 1.0f - (1.0f - dot*dot)*index*index;
+ if (fac <= 0.0f) return 0;
+ fac= -dot*index + sqrtf(fac);
+ }
+ else {
+ fac= 1.0f - (1.0f - dot*dot)*index*index;
+ if (fac <= 0.0f) return 0;
+ fac= -dot*index - sqrtf(fac);
+ }
+
+ refract[0]= index*view[0] + fac*n[0];
+ refract[1]= index*view[1] + fac*n[1];
+ refract[2]= index*view[2] + fac*n[2];
+
+ return 1;
+}
+
+static void reflection_simple(float ref[3], float n[3], const float view[3])
+{
+ const float f1= -2.0f * dot_v3v3(n, view);
+ madd_v3_v3v3fl(ref, view, n, f1);
+}
+
+/* orn = original face normal */
+static void reflection(float ref[3], float n[3], const float view[3], const float orn[3])
+{
+ float f1;
+
+ reflection_simple(ref, n, view);
+
+ /* test phong normals, then we should prevent vector going to the back */
+ f1= dot_v3v3(ref, orn);
+ if (f1>0.0f) {
+ f1+= 0.01f;
+ ref[0]-= f1*orn[0];
+ ref[1]-= f1*orn[1];
+ ref[2]-= f1*orn[2];
+ }
+}
+
+#if 0
+static void color_combine(float *result, float fac1, float fac2, float col1[3], float col2[3])
+{
+ float col1t[3], col2t[3];
+
+ col1t[0]= sqrt(col1[0]);
+ col1t[1]= sqrt(col1[1]);
+ col1t[2]= sqrt(col1[2]);
+ col2t[0]= sqrt(col2[0]);
+ col2t[1]= sqrt(col2[1]);
+ col2t[2]= sqrt(col2[2]);
+
+ result[0]= (fac1*col1t[0] + fac2*col2t[0]);
+ result[0]*= result[0];
+ result[1]= (fac1*col1t[1] + fac2*col2t[1]);
+ result[1]*= result[1];
+ result[2]= (fac1*col1t[2] + fac2*col2t[2]);
+ result[2]*= result[2];
+}
+#endif
+
+static float shade_by_transmission(Isect *is, ShadeInput *shi, ShadeResult *shr)
+{
+ float d;
+ if (0 == (shi->mat->mode & MA_TRANSP))
+ return -1;
+
+ if (shi->mat->tx_limit <= 0.0f) {
+ d= 1.0f;
+ }
+ else {
+ float p;
+
+ /* shi.co[] calculated by shade_ray() */
+ const float dx= shi->co[0] - is->start[0];
+ const float dy= shi->co[1] - is->start[1];
+ const float dz= shi->co[2] - is->start[2];
+ d = sqrtf(dx * dx + dy * dy + dz * dz);
+ if (d > shi->mat->tx_limit)
+ d= shi->mat->tx_limit;
+
+ p = shi->mat->tx_falloff;
+ if (p < 0.0f) p= 0.0f;
+ else if (p > 10.0f) p= 10.0f;
+
+ shr->alpha *= powf(d, p);
+ if (shr->alpha > 1.0f)
+ shr->alpha= 1.0f;
+ }
+
+ return d;
+}
+
+static void ray_fadeout_endcolor(float col[3], ShadeInput *origshi, ShadeInput *shi, ShadeResult *shr, Isect *isec, const float vec[3])
+{
+ /* un-intersected rays get either rendered material color or sky color */
+ if (origshi->mat->fadeto_mir == MA_RAYMIR_FADETOMAT) {
+ copy_v3_v3(col, shr->combined);
+ }
+ else if (origshi->mat->fadeto_mir == MA_RAYMIR_FADETOSKY) {
+ copy_v3_v3(shi->view, vec);
+ normalize_v3(shi->view);
+
+ shadeSkyView(col, isec->start, shi->view, NULL, shi->thread);
+ shadeSunView(col, shi->view);
+ }
+}
+
+static void ray_fadeout(Isect *is, ShadeInput *shi, float col[3], const float blendcol[3], float dist_mir)
+{
+ /* if fading out, linear blend against fade color */
+ float blendfac;
+
+ blendfac = 1.0f - len_v3v3(shi->co, is->start)/dist_mir;
+
+ col[0] = col[0]*blendfac + (1.0f - blendfac)*blendcol[0];
+ col[1] = col[1]*blendfac + (1.0f - blendfac)*blendcol[1];
+ col[2] = col[2]*blendfac + (1.0f - blendfac)*blendcol[2];
+}
+
+/* the main recursive tracer itself
+ * note: 'col' must be initialized */
+static void traceray(ShadeInput *origshi, ShadeResult *origshr, short depth, const float start[3], const float dir[3], float col[4], ObjectInstanceRen *obi, VlakRen *vlr, int traflag)
+{
+ ShadeInput shi = {NULL};
+ Isect isec;
+ float dist_mir = origshi->mat->dist_mir;
+
+ /* with high depth the number of rays can explode due to the path splitting
+ * in two each time, giving 2^depth rays. we need to be able to cancel such
+ * a render to avoid hanging, a better solution would be random picking
+ * between directions and russian roulette termination */
+ if (R.test_break(R.tbh)) {
+ zero_v4(col);
+ return;
+ }
+
+ copy_v3_v3(isec.start, start);
+ copy_v3_v3(isec.dir, dir);
+ isec.dist = dist_mir > 0 ? dist_mir : RE_RAYTRACE_MAXDIST;
+ isec.mode= RE_RAY_MIRROR;
+ isec.check = RE_CHECK_VLR_RENDER;
+ isec.skip = RE_SKIP_VLR_NEIGHBOUR;
+ isec.hint = NULL;
+
+ isec.orig.ob = obi;
+ isec.orig.face = vlr;
+ RE_RC_INIT(isec, shi);
+
+ /* database is in original view, obi->imat transforms current position back to original */
+ RE_instance_rotate_ray(origshi->obi, &isec);
+
+ if (RE_rayobject_raycast(R.raytree, &isec)) {
+ ShadeResult shr= {{0}};
+ float d= 1.0f;
+
+ RE_instance_rotate_ray_restore(origshi->obi, &isec);
+
+ /* for as long we don't have proper dx/dy transform for rays we copy over original */
+ copy_v3_v3(shi.dxco, origshi->dxco);
+ copy_v3_v3(shi.dyco, origshi->dyco);
+
+ shi.mask= origshi->mask;
+ shi.osatex= origshi->osatex;
+ shi.depth= origshi->depth + 1; /* only used to indicate tracing */
+ shi.thread= origshi->thread;
+ //shi.sample= 0; // memset above, so don't need this
+ shi.xs= origshi->xs;
+ shi.ys= origshi->ys;
+ shi.do_manage= origshi->do_manage;
+ shi.lay= origshi->lay;
+ shi.passflag= SCE_PASS_COMBINED; /* result of tracing needs no pass info */
+ shi.combinedflag= 0xFFFFFF; /* ray trace does all options */
+ //shi.do_preview = false; // memset above, so don't need this
+ shi.light_override= origshi->light_override;
+ shi.mat_override= origshi->mat_override;
+
+ shade_ray(&isec, &shi, &shr);
+ /* ray has traveled inside the material, so shade by transmission */
+ if (traflag & RAY_INSIDE)
+ d= shade_by_transmission(&isec, &shi, &shr);
+
+ if (depth>0) {
+ float fr, fg, fb, f1;
+
+ if ((shi.mat->mode_l & MA_TRANSP) && shr.alpha < 1.0f && (shi.mat->mode_l & (MA_ZTRANSP | MA_RAYTRANSP))) {
+ float nf, f, refract[3], tracol[4];
+
+ tracol[0]= shi.r;
+ tracol[1]= shi.g;
+ tracol[2]= shi.b;
+ tracol[3]= col[3]; /* we pass on and accumulate alpha */
+
+ if ((shi.mat->mode & MA_TRANSP) && (shi.mat->mode & MA_RAYTRANSP)) {
+ /* don't overwrite traflag, it's value is used in mirror reflection */
+ int new_traflag = traflag;
+
+ if (new_traflag & RAY_INSIDE) {
+ /* inside the material, so use inverse normal */
+ float norm[3];
+ norm[0]= - shi.vn[0];
+ norm[1]= - shi.vn[1];
+ norm[2]= - shi.vn[2];
+
+ if (refraction(refract, norm, shi.view, shi.ang)) {
+ /* ray comes out from the material into air */
+ new_traflag &= ~RAY_INSIDE;
+ }
+ else {
+ /* total internal reflection (ray stays inside the material) */
+ reflection(refract, norm, shi.view, shi.vn);
+ }
+ }
+ else {
+ if (refraction(refract, shi.vn, shi.view, shi.ang)) {
+ /* ray goes in to the material from air */
+ new_traflag |= RAY_INSIDE;
+ }
+ else {
+ /* total external reflection (ray doesn't enter the material) */
+ reflection(refract, shi.vn, shi.view, shi.vn);
+ }
+ }
+ traceray(origshi, origshr, depth-1, shi.co, refract, tracol, shi.obi, shi.vlr, new_traflag);
+ }
+ else
+ traceray(origshi, origshr, depth-1, shi.co, shi.view, tracol, shi.obi, shi.vlr, 0);
+
+ f= shr.alpha; f1= 1.0f-f;
+ nf= (shi.mat->mode & MA_RAYTRANSP) ? d * shi.mat->filter : 0.0f;
+ fr= 1.0f+ nf*(shi.r-1.0f);
+ fg= 1.0f+ nf*(shi.g-1.0f);
+ fb= 1.0f+ nf*(shi.b-1.0f);
+ shr.diff[0]= f*shr.diff[0] + f1*fr*tracol[0];
+ shr.diff[1]= f*shr.diff[1] + f1*fg*tracol[1];
+ shr.diff[2]= f*shr.diff[2] + f1*fb*tracol[2];
+
+ shr.spec[0] *=f;
+ shr.spec[1] *=f;
+ shr.spec[2] *=f;
+
+ col[3]= f1*tracol[3] + f;
+ }
+ else {
+ col[3]= 1.0f;
+ }
+
+ float f;
+ if (shi.mat->mode_l & MA_RAYMIRROR) {
+ f= shi.ray_mirror;
+ if (f!=0.0f) f*= fresnel_fac(shi.view, shi.vn, shi.mat->fresnel_mir_i, shi.mat->fresnel_mir);
+ }
+ else f= 0.0f;
+
+ if (f!=0.0f) {
+ float mircol[4];
+ float ref[3];
+
+ reflection_simple(ref, shi.vn, shi.view);
+ traceray(origshi, origshr, depth-1, shi.co, ref, mircol, shi.obi, shi.vlr, traflag);
+
+ f1= 1.0f-f;
+
+ /* combine */
+ //color_combine(col, f*fr*(1.0f-shr.spec[0]), f1, col, shr.diff);
+ //col[0]+= shr.spec[0];
+ //col[1]+= shr.spec[1];
+ //col[2]+= shr.spec[2];
+
+ fr= shi.mirr;
+ fg= shi.mirg;
+ fb= shi.mirb;
+
+ col[0]= f*fr*(1.0f-shr.spec[0])*mircol[0] + f1*shr.diff[0] + shr.spec[0];
+ col[1]= f*fg*(1.0f-shr.spec[1])*mircol[1] + f1*shr.diff[1] + shr.spec[1];
+ col[2]= f*fb*(1.0f-shr.spec[2])*mircol[2] + f1*shr.diff[2] + shr.spec[2];
+ }
+ else {
+ col[0]= shr.diff[0] + shr.spec[0];
+ col[1]= shr.diff[1] + shr.spec[1];
+ col[2]= shr.diff[2] + shr.spec[2];
+ }
+
+ if (dist_mir > 0.0f) {
+ float blendcol[3];
+
+ /* max ray distance set, but found an intersection, so fade this color
+ * out towards the sky/material color for a smooth transition */
+ ray_fadeout_endcolor(blendcol, origshi, &shi, origshr, &isec, dir);
+ ray_fadeout(&isec, &shi, col, blendcol, dist_mir);
+ }
+ }
+ else {
+ col[0]= shr.diff[0] + shr.spec[0];
+ col[1]= shr.diff[1] + shr.spec[1];
+ col[2]= shr.diff[2] + shr.spec[2];
+ }
+
+ }
+ else {
+ ray_fadeout_endcolor(col, origshi, &shi, origshr, &isec, dir);
+ }
+ RE_RC_MERGE(&origshi->raycounter, &shi.raycounter);
+}
+
+/* **************** jitter blocks ********** */
+
+/* calc distributed planar energy */
+
+static void DP_energy(float *table, float vec[2], int tot, float xsize, float ysize)
+{
+ int x, y, a;
+ float *fp, force[3], result[3];
+ float dx, dy, dist, min;
+
+ min= MIN2(xsize, ysize);
+ min*= min;
+ result[0]= result[1]= 0.0f;
+
+ for (y= -1; y<2; y++) {
+ dy= ysize*y;
+ for (x= -1; x<2; x++) {
+ dx= xsize*x;
+ fp= table;
+ for (a=0; a<tot; a++, fp+= 2) {
+ force[0]= vec[0] - fp[0]-dx;
+ force[1]= vec[1] - fp[1]-dy;
+ dist= force[0]*force[0] + force[1]*force[1];
+ if (dist < min && dist>0.0f) {
+ result[0]+= force[0]/dist;
+ result[1]+= force[1]/dist;
+ }
+ }
+ }
+ }
+ vec[0] += 0.1f*min*result[0]/(float)tot;
+ vec[1] += 0.1f*min*result[1]/(float)tot;
+ /* cyclic clamping */
+ vec[0]= vec[0] - xsize*floorf(vec[0]/xsize + 0.5f);
+ vec[1]= vec[1] - ysize*floorf(vec[1]/ysize + 0.5f);
+}
+
+/* random offset of 1 in 2 */
+static void jitter_plane_offset(float *jitter1, float *jitter2, int tot, float sizex, float sizey, float ofsx, float ofsy)
+{
+ float dsizex= sizex*ofsx;
+ float dsizey= sizey*ofsy;
+ float hsizex= 0.5f*sizex, hsizey= 0.5f*sizey;
+ int x;
+
+ for (x=tot; x>0; x--, jitter1+=2, jitter2+=2) {
+ jitter2[0]= jitter1[0] + dsizex;
+ jitter2[1]= jitter1[1] + dsizey;
+ if (jitter2[0] > hsizex) jitter2[0]-= sizex;
+ if (jitter2[1] > hsizey) jitter2[1]-= sizey;
+ }
+}
+
+/* called from convertBlenderScene.c */
+/* we do this in advance to get consistent random, not alter the render seed, and be threadsafe */
+void init_jitter_plane(LampRen *lar)
+{
+ float *fp;
+ int x, tot= lar->ray_totsamp;
+
+ /* test if already initialized */
+ if (lar->jitter) return;
+
+ /* at least 4, or max threads+1 tables */
+ if (BLENDER_MAX_THREADS < 4) x= 4;
+ else x= BLENDER_MAX_THREADS+1;
+ fp= lar->jitter= MEM_callocN(x*tot*2*sizeof(float), "lamp jitter tab");
+
+ /* if 1 sample, we leave table to be zero's */
+ if (tot>1) {
+ /* set per-lamp fixed seed */
+ RNG *rng = BLI_rng_new_srandom(tot);
+ int iter=12;
+
+ /* fill table with random locations, area_size large */
+ for (x=0; x<tot; x++, fp+=2) {
+ fp[0]= (BLI_rng_get_float(rng)-0.5f)*lar->area_size;
+ fp[1]= (BLI_rng_get_float(rng)-0.5f)*lar->area_sizey;
+ }
+
+ while (iter--) {
+ fp= lar->jitter;
+ for (x=tot; x>0; x--, fp+=2) {
+ DP_energy(lar->jitter, fp, tot, lar->area_size, lar->area_sizey);
+ }
+ }
+
+ BLI_rng_free(rng);
+ }
+ /* create the dithered tables (could just check lamp type!) */
+ jitter_plane_offset(lar->jitter, lar->jitter+2*tot, tot, lar->area_size, lar->area_sizey, 0.5f, 0.0f);
+ jitter_plane_offset(lar->jitter, lar->jitter+4*tot, tot, lar->area_size, lar->area_sizey, 0.5f, 0.5f);
+ jitter_plane_offset(lar->jitter, lar->jitter+6*tot, tot, lar->area_size, lar->area_sizey, 0.0f, 0.5f);
+}
+
+/* table around origin, -0.5*size to 0.5*size */
+static float *give_jitter_plane(LampRen *lar, int thread, int xs, int ys)
+{
+ int tot;
+
+ tot= lar->ray_totsamp;
+
+ if (lar->ray_samp_type & LA_SAMP_JITTER) {
+ /* made it threadsafe */
+
+ if (lar->xold[thread]!=xs || lar->yold[thread]!=ys) {
+ jitter_plane_offset(lar->jitter, lar->jitter+2*(thread+1)*tot, tot, lar->area_size, lar->area_sizey, BLI_thread_frand(thread), BLI_thread_frand(thread));
+ lar->xold[thread]= xs;
+ lar->yold[thread]= ys;
+ }
+ return lar->jitter+2*(thread+1)*tot;
+ }
+ if (lar->ray_samp_type & LA_SAMP_DITHER) {
+ return lar->jitter + 2*tot*((xs & 1)+2*(ys & 1));
+ }
+
+ return lar->jitter;
+}
+
+
+/* **************** QMC sampling *************** */
+
+static void halton_sample(double *ht_invprimes, double *ht_nums, double *v)
+{
+ /* incremental halton sequence generator, from:
+ * "Instant Radiosity", Keller A. */
+ unsigned int i;
+
+ for (i = 0; i < 2; i++) {
+ double r = fabs((1.0 - ht_nums[i]) - 1e-10);
+
+ if (ht_invprimes[i] >= r) {
+ double lasth;
+ double h = ht_invprimes[i];
+
+ do {
+ lasth = h;
+ h *= ht_invprimes[i];
+ } while (h >= r);
+
+ ht_nums[i] += ((lasth + h) - 1.0);
+ }
+ else
+ ht_nums[i] += ht_invprimes[i];
+
+ v[i] = (float)ht_nums[i];
+ }
+}
+
+/* Generate Hammersley points in [0,1)^2
+ * From Lucille renderer */
+static void hammersley_create(double *out, int n)
+{
+ double p, t;
+ int k, kk;
+
+ for (k = 0; k < n; k++) {
+ t = 0;
+ for (p = 0.5, kk = k; kk; p *= 0.5, kk >>= 1) {
+ if (kk & 1) { /* kk mod 2 = 1 */
+ t += p;
+ }
+ }
+
+ out[2 * k + 0] = (double)k / (double)n;
+ out[2 * k + 1] = t;
+ }
+}
+
+static struct QMCSampler *QMC_initSampler(int type, int tot)
+{
+ QMCSampler *qsa = MEM_callocN(sizeof(QMCSampler), "qmc sampler");
+ qsa->samp2d = MEM_callocN(2*sizeof(double)*tot, "qmc sample table");
+
+ qsa->tot = tot;
+ qsa->type = type;
+
+ if (qsa->type==SAMP_TYPE_HAMMERSLEY)
+ hammersley_create(qsa->samp2d, qsa->tot);
+
+ return qsa;
+}
+
+static void QMC_initPixel(QMCSampler *qsa, int thread)
+{
+ if (qsa->type==SAMP_TYPE_HAMMERSLEY) {
+ /* hammersley sequence is fixed, already created in QMCSampler init.
+ * per pixel, gets a random offset. We create separate offsets per thread, for write-safety */
+ qsa->offs[thread][0] = 0.5f * BLI_thread_frand(thread);
+ qsa->offs[thread][1] = 0.5f * BLI_thread_frand(thread);
+ }
+ else { /* SAMP_TYPE_HALTON */
+
+ /* generate a new randomized halton sequence per pixel
+ * to alleviate qmc artifacts and make it reproducible
+ * between threads/frames */
+ double ht_invprimes[2], ht_nums[2];
+ double r[2];
+ int i;
+
+ ht_nums[0] = BLI_thread_frand(thread);
+ ht_nums[1] = BLI_thread_frand(thread);
+ ht_invprimes[0] = 0.5;
+ ht_invprimes[1] = 1.0/3.0;
+
+ for (i=0; i< qsa->tot; i++) {
+ halton_sample(ht_invprimes, ht_nums, r);
+ qsa->samp2d[2*i+0] = r[0];
+ qsa->samp2d[2*i+1] = r[1];
+ }
+ }
+}
+
+static void QMC_freeSampler(QMCSampler *qsa)
+{
+ MEM_freeN(qsa->samp2d);
+ MEM_freeN(qsa);
+}
+
+static void QMC_getSample(double *s, QMCSampler *qsa, int thread, int num)
+{
+ if (qsa->type == SAMP_TYPE_HAMMERSLEY) {
+ s[0] = fmod(qsa->samp2d[2*num+0] + qsa->offs[thread][0], 1.0f);
+ s[1] = fmod(qsa->samp2d[2*num+1] + qsa->offs[thread][1], 1.0f);
+ }
+ else { /* SAMP_TYPE_HALTON */
+ s[0] = qsa->samp2d[2*num+0];
+ s[1] = qsa->samp2d[2*num+1];
+ }
+}
+
+/* phong weighted disc using 'blur' for exponent, centred on 0,0 */
+static void QMC_samplePhong(float vec[3], QMCSampler *qsa, int thread, int num, float blur)
+{
+ double s[2];
+ float phi, pz, sqr;
+
+ QMC_getSample(s, qsa, thread, num);
+
+ phi = s[0]*2*M_PI;
+ pz = pow(s[1], blur);
+ sqr = sqrtf(1.0f - pz * pz);
+
+ vec[0] = (float)(cosf(phi)*sqr);
+ vec[1] = (float)(sinf(phi)*sqr);
+ vec[2] = 0.0f;
+}
+
+/* rect of edge lengths sizex, sizey, centred on 0.0,0.0 i.e. ranging from -sizex/2 to +sizey/2 */
+static void QMC_sampleRect(float vec[3], QMCSampler *qsa, int thread, int num, float sizex, float sizey)
+{
+ double s[2];
+
+ QMC_getSample(s, qsa, thread, num);
+
+ vec[0] = (float)(s[0] - 0.5) * sizex;
+ vec[1] = (float)(s[1] - 0.5) * sizey;
+ vec[2] = 0.0f;
+}
+
+/* disc of radius 'radius', centred on 0,0 */
+static void QMC_sampleDisc(float vec[3], QMCSampler *qsa, int thread, int num, float radius)
+{
+ double s[2];
+ float phi, sqr;
+
+ QMC_getSample(s, qsa, thread, num);
+
+ phi = s[0]*2*M_PI;
+ sqr = sqrt(s[1]);
+
+ vec[0] = cosf(phi)*sqr* radius/2.0f;
+ vec[1] = sinf(phi)*sqr* radius/2.0f;
+ vec[2] = 0.0f;
+}
+
+/* uniform hemisphere sampling */
+static void QMC_sampleHemi(float vec[3], QMCSampler *qsa, int thread, int num)
+{
+ double s[2];
+ float phi, sqr;
+
+ QMC_getSample(s, qsa, thread, num);
+
+ phi = s[0]*2.0*M_PI;
+ sqr = sqrt(s[1]);
+
+ vec[0] = cosf(phi)*sqr;
+ vec[1] = sinf(phi)*sqr;
+ vec[2] = (float)(1.0 - s[1]*s[1]);
+}
+
+#if 0 /* currently not used */
+/* cosine weighted hemisphere sampling */
+static void QMC_sampleHemiCosine(float vec[3], QMCSampler *qsa, int thread, int num)
+{
+ double s[2];
+ float phi, sqr;
+
+ QMC_getSample(s, qsa, thread, num);
+
+ phi = s[0]*2.f*M_PI;
+ sqr = s[1]*sqrt(2-s[1]*s[1]);
+
+ vec[0] = cos(phi)*sqr;
+ vec[1] = sin(phi)*sqr;
+ vec[2] = 1.f - s[1]*s[1];
+
+}
+#endif
+
+/* called from convertBlenderScene.c */
+void init_render_qmcsampler(Render *re)
+{
+ const int num_threads = re->r.threads;
+ re->qmcsamplers= MEM_callocN(sizeof(ListBase)*num_threads, "QMCListBase");
+ re->num_qmc_samplers = num_threads;
+}
+
+static QMCSampler *get_thread_qmcsampler(Render *re, int thread, int type, int tot)
+{
+ QMCSampler *qsa;
+
+ /* create qmc samplers as needed, since recursion makes it hard to
+ * predict how many are needed */
+
+ for (qsa=re->qmcsamplers[thread].first; qsa; qsa=qsa->next) {
+ if (qsa->type == type && qsa->tot == tot && !qsa->used) {
+ qsa->used = true;
+ return qsa;
+ }
+ }
+
+ qsa= QMC_initSampler(type, tot);
+ qsa->used = true;
+ BLI_addtail(&re->qmcsamplers[thread], qsa);
+
+ return qsa;
+}
+
+static void release_thread_qmcsampler(Render *UNUSED(re), int UNUSED(thread), QMCSampler *qsa)
+{
+ qsa->used= 0;
+}
+
+void free_render_qmcsampler(Render *re)
+{
+ if (re->qmcsamplers) {
+ QMCSampler *qsa, *next;
+ int a;
+ for (a = 0; a < re->num_qmc_samplers; a++) {
+ for (qsa=re->qmcsamplers[a].first; qsa; qsa=next) {
+ next= qsa->next;
+ QMC_freeSampler(qsa);
+ }
+
+ re->qmcsamplers[a].first= re->qmcsamplers[a].last= NULL;
+ }
+
+ MEM_freeN(re->qmcsamplers);
+ re->qmcsamplers= NULL;
+ }
+}
+
+static int adaptive_sample_variance(int samples, const float col[3], const float colsq[3], float thresh)
+{
+ float var[3], mean[3];
+
+ /* scale threshold just to give a bit more precision in input rather than dealing with
+ * tiny tiny numbers in the UI */
+ thresh /= 2;
+
+ mean[0] = col[0] / (float)samples;
+ mean[1] = col[1] / (float)samples;
+ mean[2] = col[2] / (float)samples;
+
+ var[0] = (colsq[0] / (float)samples) - (mean[0]*mean[0]);
+ var[1] = (colsq[1] / (float)samples) - (mean[1]*mean[1]);
+ var[2] = (colsq[2] / (float)samples) - (mean[2]*mean[2]);
+
+ if ((var[0] * 0.4f < thresh) && (var[1] * 0.3f < thresh) && (var[2] * 0.6f < thresh))
+ return 1;
+ else
+ return 0;
+}
+
+static int adaptive_sample_contrast_val(int samples, float prev, float val, float thresh)
+{
+ /* if the last sample's contribution to the total value was below a small threshold
+ * (i.e. the samples taken are very similar), then taking more samples that are probably
+ * going to be the same is wasting effort */
+ if (fabsf(prev / (float)(samples - 1) - val / (float)samples ) < thresh) {
+ return 1;
+ }
+ else
+ return 0;
+}
+
+static float get_avg_speed(ShadeInput *shi)
+{
+ float pre_x, pre_y, post_x, post_y, speedavg;
+
+ pre_x = (shi->winspeed[0] == PASS_VECTOR_MAX)?0.0f:shi->winspeed[0];
+ pre_y = (shi->winspeed[1] == PASS_VECTOR_MAX)?0.0f:shi->winspeed[1];
+ post_x = (shi->winspeed[2] == PASS_VECTOR_MAX)?0.0f:shi->winspeed[2];
+ post_y = (shi->winspeed[3] == PASS_VECTOR_MAX)?0.0f:shi->winspeed[3];
+
+ speedavg = (sqrtf(pre_x * pre_x + pre_y * pre_y) + sqrtf(post_x * post_x + post_y * post_y)) / 2.0f;
+
+ return speedavg;
+}
+
+/* ***************** main calls ************** */
+
+
+static void trace_refract(float col[4], ShadeInput *shi, ShadeResult *shr)
+{
+ QMCSampler *qsa=NULL;
+ int samp_type;
+ int traflag=0;
+
+ float samp3d[3], orthx[3], orthy[3];
+ float v_refract[3], v_refract_new[3];
+ float sampcol[4], colsq[4];
+
+ float blur = pow3f(1.0f - shi->mat->gloss_tra);
+ short max_samples = shi->mat->samp_gloss_tra;
+ float adapt_thresh = shi->mat->adapt_thresh_tra;
+
+ int samples=0;
+
+ colsq[0] = colsq[1] = colsq[2] = 0.0;
+ col[0] = col[1] = col[2] = 0.0;
+ col[3]= shr->alpha;
+
+ if (blur > 0.0f) {
+ if (adapt_thresh != 0.0f) samp_type = SAMP_TYPE_HALTON;
+ else samp_type = SAMP_TYPE_HAMMERSLEY;
+
+ /* all samples are generated per pixel */
+ qsa = get_thread_qmcsampler(&R, shi->thread, samp_type, max_samples);
+ QMC_initPixel(qsa, shi->thread);
+ }
+ else
+ max_samples = 1;
+
+
+ while (samples < max_samples) {
+ if (refraction(v_refract, shi->vn, shi->view, shi->ang)) {
+ traflag |= RAY_INSIDE;
+ }
+ else {
+ /* total external reflection can happen for materials with IOR < 1.0 */
+ if ((shi->vlr->flag & R_SMOOTH))
+ reflection(v_refract, shi->vn, shi->view, shi->facenor);
+ else
+ reflection_simple(v_refract, shi->vn, shi->view);
+
+ /* can't blur total external reflection */
+ max_samples = 1;
+ }
+
+ if (max_samples > 1) {
+ /* get a quasi-random vector from a phong-weighted disc */
+ QMC_samplePhong(samp3d, qsa, shi->thread, samples, blur);
+
+ ortho_basis_v3v3_v3(orthx, orthy, v_refract);
+ mul_v3_fl(orthx, samp3d[0]);
+ mul_v3_fl(orthy, samp3d[1]);
+
+ /* and perturb the refraction vector in it */
+ add_v3_v3v3(v_refract_new, v_refract, orthx);
+ add_v3_v3(v_refract_new, orthy);
+
+ normalize_v3(v_refract_new);
+ }
+ else {
+ /* no blurriness, use the original normal */
+ copy_v3_v3(v_refract_new, v_refract);
+ }
+
+ sampcol[0]= sampcol[1]= sampcol[2]= sampcol[3]= 0.0f;
+
+ traceray(shi, shr, shi->mat->ray_depth_tra, shi->co, v_refract_new, sampcol, shi->obi, shi->vlr, traflag);
+
+ col[0] += sampcol[0];
+ col[1] += sampcol[1];
+ col[2] += sampcol[2];
+ col[3] += sampcol[3];
+
+ /* for variance calc */
+ colsq[0] += sampcol[0]*sampcol[0];
+ colsq[1] += sampcol[1]*sampcol[1];
+ colsq[2] += sampcol[2]*sampcol[2];
+
+ samples++;
+
+ /* adaptive sampling */
+ if (adapt_thresh < 1.0f && samples > max_samples/2) {
+ if (adaptive_sample_variance(samples, col, colsq, adapt_thresh))
+ break;
+
+ /* if the pixel so far is very dark, we can get away with less samples */
+ if ( (col[0] + col[1] + col[2])/3.0f/(float)samples < 0.01f )
+ max_samples--;
+ }
+ }
+
+ col[0] /= (float)samples;
+ col[1] /= (float)samples;
+ col[2] /= (float)samples;
+ col[3] /= (float)samples;
+
+ if (qsa)
+ release_thread_qmcsampler(&R, shi->thread, qsa);
+}
+
+static void trace_reflect(float col[3], ShadeInput *shi, ShadeResult *shr, float fresnelfac)
+{
+ QMCSampler *qsa=NULL;
+ int samp_type;
+
+ float samp3d[3], orthx[3], orthy[3];
+ float v_nor_new[3], v_reflect[3];
+ float sampcol[4], colsq[4];
+
+ float blur = pow3f(1.0f - shi->mat->gloss_mir);
+ short max_samples = shi->mat->samp_gloss_mir;
+ float adapt_thresh = shi->mat->adapt_thresh_mir;
+ float aniso = 1.0f - shi->mat->aniso_gloss_mir;
+
+ int samples=0;
+
+ col[0] = col[1] = col[2] = 0.0;
+ colsq[0] = colsq[1] = colsq[2] = 0.0;
+
+ if (blur > 0.0f) {
+ if (adapt_thresh != 0.0f) samp_type = SAMP_TYPE_HALTON;
+ else samp_type = SAMP_TYPE_HAMMERSLEY;
+
+ /* all samples are generated per pixel */
+ qsa = get_thread_qmcsampler(&R, shi->thread, samp_type, max_samples);
+ QMC_initPixel(qsa, shi->thread);
+ }
+ else
+ max_samples = 1;
+
+ while (samples < max_samples) {
+
+ if (max_samples > 1) {
+ /* get a quasi-random vector from a phong-weighted disc */
+ QMC_samplePhong(samp3d, qsa, shi->thread, samples, blur);
+
+ /* find the normal's perpendicular plane, blurring along tangents
+ * if tangent shading enabled */
+ if (shi->mat->mode & (MA_TANGENT_V)) {
+ cross_v3_v3v3(orthx, shi->vn, shi->tang); // bitangent
+ copy_v3_v3(orthy, shi->tang);
+ mul_v3_fl(orthx, samp3d[0]);
+ mul_v3_fl(orthy, samp3d[1]*aniso);
+ }
+ else {
+ ortho_basis_v3v3_v3(orthx, orthy, shi->vn);
+ mul_v3_fl(orthx, samp3d[0]);
+ mul_v3_fl(orthy, samp3d[1]);
+ }
+
+ /* and perturb the normal in it */
+ add_v3_v3v3(v_nor_new, shi->vn, orthx);
+ add_v3_v3(v_nor_new, orthy);
+ normalize_v3(v_nor_new);
+ }
+ else {
+ /* no blurriness, use the original normal */
+ copy_v3_v3(v_nor_new, shi->vn);
+ }
+
+ if ((shi->vlr->flag & R_SMOOTH))
+ reflection(v_reflect, v_nor_new, shi->view, shi->facenor);
+ else
+ reflection_simple(v_reflect, v_nor_new, shi->view);
+
+ sampcol[0]= sampcol[1]= sampcol[2]= sampcol[3]= 0.0f;
+
+ traceray(shi, shr, shi->mat->ray_depth, shi->co, v_reflect, sampcol, shi->obi, shi->vlr, 0);
+
+
+ col[0] += sampcol[0];
+ col[1] += sampcol[1];
+ col[2] += sampcol[2];
+
+ /* for variance calc */
+ colsq[0] += sampcol[0]*sampcol[0];
+ colsq[1] += sampcol[1]*sampcol[1];
+ colsq[2] += sampcol[2]*sampcol[2];
+
+ samples++;
+
+ /* adaptive sampling */
+ if (adapt_thresh > 0.0f && samples > max_samples/3) {
+ if (adaptive_sample_variance(samples, col, colsq, adapt_thresh))
+ break;
+
+ /* if the pixel so far is very dark, we can get away with less samples */
+ if ( (col[0] + col[1] + col[2])/3.0f/(float)samples < 0.01f )
+ max_samples--;
+
+ /* reduce samples when reflection is dim due to low ray mirror blend value or fresnel factor
+ * and when reflection is blurry */
+ if (fresnelfac < 0.1f * (blur+1)) {
+ max_samples--;
+
+ /* even more for very dim */
+ if (fresnelfac < 0.05f * (blur+1))
+ max_samples--;
+ }
+ }
+ }
+
+ col[0] /= (float)samples;
+ col[1] /= (float)samples;
+ col[2] /= (float)samples;
+
+ if (qsa)
+ release_thread_qmcsampler(&R, shi->thread, qsa);
+}
+
+/* extern call from render loop */
+void ray_trace(ShadeInput *shi, ShadeResult *shr)
+{
+ float f1, fr, fg, fb;
+ float mircol[4], tracol[4];
+ float diff[3];
+ int do_tra, do_mir;
+
+ do_tra = ((shi->mode & MA_TRANSP) && (shi->mode & MA_RAYTRANSP) && shr->alpha != 1.0f && (shi->depth <= shi->mat->ray_depth_tra));
+ do_mir = ((shi->mat->mode & MA_RAYMIRROR) && shi->ray_mirror != 0.0f && (shi->depth <= shi->mat->ray_depth));
+
+ /* raytrace mirror and refract like to separate the spec color */
+ if (shi->combinedflag & SCE_PASS_SPEC)
+ sub_v3_v3v3(diff, shr->combined, shr->spec);
+ else
+ copy_v3_v3(diff, shr->combined);
+
+ if (do_tra) {
+ float olddiff[3], f;
+
+ trace_refract(tracol, shi, shr);
+
+ f= shr->alpha; f1= 1.0f-f;
+ fr= 1.0f+ shi->mat->filter*(shi->r-1.0f);
+ fg= 1.0f+ shi->mat->filter*(shi->g-1.0f);
+ fb= 1.0f+ shi->mat->filter*(shi->b-1.0f);
+
+ /* for refract pass */
+ copy_v3_v3(olddiff, diff);
+
+ diff[0]= f*diff[0] + f1*fr*tracol[0];
+ diff[1]= f*diff[1] + f1*fg*tracol[1];
+ diff[2]= f*diff[2] + f1*fb*tracol[2];
+
+ if (shi->passflag & SCE_PASS_REFRACT)
+ sub_v3_v3v3(shr->refr, diff, olddiff);
+
+ if (!(shi->combinedflag & SCE_PASS_REFRACT))
+ sub_v3_v3v3(diff, diff, shr->refr);
+
+ shr->alpha = min_ff(1.0f, tracol[3]);
+ }
+
+ if (do_mir) {
+ const float i= shi->ray_mirror*fresnel_fac(shi->view, shi->vn, shi->mat->fresnel_mir_i, shi->mat->fresnel_mir);
+ if (i!=0.0f) {
+
+ trace_reflect(mircol, shi, shr, i);
+
+ fr= i*shi->mirr;
+ fg= i*shi->mirg;
+ fb= i*shi->mirb;
+
+ if (shi->passflag & SCE_PASS_REFLECT) {
+ /* mirror pass is not blocked out with spec */
+ shr->refl[0]= fr*mircol[0] - fr*diff[0];
+ shr->refl[1]= fg*mircol[1] - fg*diff[1];
+ shr->refl[2]= fb*mircol[2] - fb*diff[2];
+ }
+
+ if (shi->combinedflag & SCE_PASS_REFLECT) {
+ /* values in shr->spec can be greater than 1.0.
+ * In this case the mircol uses a zero blending factor, so ignoring it is ok.
+ * Fixes bug #18837 - when the spec is higher then 1.0,
+ * diff can become a negative color - Campbell */
+
+ f1= 1.0f-i;
+
+ diff[0] *= f1;
+ diff[1] *= f1;
+ diff[2] *= f1;
+
+ if (shr->spec[0]<1.0f) diff[0] += mircol[0] * (fr*(1.0f-shr->spec[0]));
+ if (shr->spec[1]<1.0f) diff[1] += mircol[1] * (fg*(1.0f-shr->spec[1]));
+ if (shr->spec[2]<1.0f) diff[2] += mircol[2] * (fb*(1.0f-shr->spec[2]));
+ }
+ }
+ }
+ /* put back together */
+ if (shi->combinedflag & SCE_PASS_SPEC)
+ add_v3_v3v3(shr->combined, diff, shr->spec);
+ else
+ copy_v3_v3(shr->combined, diff);
+}
+
+/* color 'shadfac' passes through 'col' with alpha and filter */
+/* filter is only applied on alpha defined transparent part */
+static void addAlphaLight(float shadfac[4], const float col[3], float alpha, float filter)
+{
+ float fr, fg, fb;
+
+ fr= 1.0f+ filter*(col[0]-1.0f);
+ fg= 1.0f+ filter*(col[1]-1.0f);
+ fb= 1.0f+ filter*(col[2]-1.0f);
+
+ shadfac[0]= alpha*col[0] + fr*(1.0f-alpha)*shadfac[0];
+ shadfac[1]= alpha*col[1] + fg*(1.0f-alpha)*shadfac[1];
+ shadfac[2]= alpha*col[2] + fb*(1.0f-alpha)*shadfac[2];
+
+ shadfac[3]= (1.0f-alpha)*shadfac[3];
+}
+
+static void ray_trace_shadow_tra(Isect *is, ShadeInput *origshi, int depth, int traflag, float col[4])
+{
+ /* ray to lamp, find first face that intersects, check alpha properties,
+ * if it has col[3]>0.0f continue. so exit when alpha is full */
+ const float initial_dist = is->dist;
+
+ if (RE_rayobject_raycast(R.raytree, is)) {
+ /* Warning regarding initializing to zero's, This is not that nice,
+ * and possibly a bit slow for every ray, however some variables were
+ * not initialized properly in, unless using
+ * shade_input_initialize(...), we need to zero them. */
+ ShadeInput shi= {NULL};
+ /* end warning! - Campbell */
+
+ ShadeResult shr;
+
+ /* we got a face */
+
+ shi.depth= origshi->depth + 1; /* only used to indicate tracing */
+ shi.mask= origshi->mask;
+ shi.thread= origshi->thread;
+ shi.passflag= SCE_PASS_COMBINED;
+ shi.combinedflag= 0xFFFFFF; /* ray trace does all options */
+
+ shi.xs= origshi->xs;
+ shi.ys= origshi->ys;
+ shi.do_manage= origshi->do_manage;
+ shi.lay= origshi->lay;
+ shi.nodes= origshi->nodes;
+
+ RE_instance_rotate_ray_restore(origshi->obi, is);
+
+ shade_ray(is, &shi, &shr);
+ if (shi.mat->material_type == MA_TYPE_SURFACE) {
+ const float d = (shi.mat->mode & MA_RAYTRANSP) ?
+ ((traflag & RAY_TRA) ? shade_by_transmission(is, &shi, &shr) : 1.0f) :
+ 0.0f;
+ /* mix colors based on shadfac (rgb + amount of light factor) */
+ addAlphaLight(col, shr.diff, shr.alpha, d*shi.mat->filter);
+ }
+ else if (shi.mat->material_type == MA_TYPE_VOLUME) {
+ const float a = col[3];
+
+ col[0] = a*col[0] + shr.alpha*shr.combined[0];
+ col[1] = a*col[1] + shr.alpha*shr.combined[1];
+ col[2] = a*col[2] + shr.alpha*shr.combined[2];
+
+ col[3] = (1.0f - shr.alpha)*a;
+ }
+
+ if (depth>0 && col[3]>0.0f) {
+
+ /* adapt isect struct */
+ copy_v3_v3(is->start, shi.co);
+ is->dist = initial_dist-is->dist;
+ is->orig.ob = shi.obi;
+ is->orig.face = shi.vlr;
+
+ ray_trace_shadow_tra(is, origshi, depth-1, traflag | RAY_TRA, col);
+ }
+
+ RE_RC_MERGE(&origshi->raycounter, &shi.raycounter);
+ }
+}
+
+
+/* aolight: function to create random unit sphere vectors for total random sampling */
+
+/* calc distributed spherical energy */
+static void DS_energy(float *sphere, int tot, float vec[3])
+{
+ float *fp, fac, force[3], res[3];
+ int a;
+
+ res[0]= res[1]= res[2]= 0.0f;
+
+ for (a=0, fp=sphere; a<tot; a++, fp+=3) {
+ sub_v3_v3v3(force, vec, fp);
+ fac = dot_v3v3(force, force);
+ if (fac!=0.0f) {
+ fac= 1.0f/fac;
+ res[0]+= fac*force[0];
+ res[1]+= fac*force[1];
+ res[2]+= fac*force[2];
+ }
+ }
+
+ mul_v3_fl(res, 0.5);
+ add_v3_v3(vec, res);
+ normalize_v3(vec);
+
+}
+
+/* called from convertBlenderScene.c */
+/* creates an equally distributed spherical sample pattern */
+/* and allocates threadsafe memory */
+void init_ao_sphere(Render *re, World *wrld)
+{
+ /* fixed random */
+ const int num_threads = re->r.threads;
+ RNG *rng;
+ float *fp;
+ int a, tot, iter= 16;
+
+ /* we make twice the amount of samples, because only a hemisphere is used */
+ tot= 2*wrld->aosamp*wrld->aosamp;
+
+ wrld->aosphere= MEM_mallocN(3*tot*sizeof(float), "AO sphere");
+ rng = BLI_rng_new_srandom(tot);
+
+ /* init */
+ fp= wrld->aosphere;
+ for (a=0; a<tot; a++, fp+= 3) {
+ BLI_rng_get_float_unit_v3(rng, fp);
+ }
+
+ while (iter--) {
+ for (a=0, fp= wrld->aosphere; a<tot; a++, fp+= 3) {
+ DS_energy(wrld->aosphere, tot, fp);
+ }
+ }
+
+ /* tables */
+ wrld->aotables= MEM_mallocN(num_threads*3*tot*sizeof(float), "AO tables");
+
+ BLI_rng_free(rng);
+}
+
+/* give per thread a table, we have to compare xs ys because of way OSA works... */
+static float *threadsafe_table_sphere(int test, int thread, int xs, int ys, int tot)
+{
+ static int xso[BLENDER_MAX_THREADS], yso[BLENDER_MAX_THREADS];
+ static int firsttime= 1;
+
+ if (firsttime) {
+ memset(xso, 255, sizeof(xso));
+ memset(yso, 255, sizeof(yso));
+ firsttime= 0;
+ }
+
+ if (xs==xso[thread] && ys==yso[thread]) return R.wrld.aotables+ thread*tot*3;
+ if (test) return NULL;
+ xso[thread]= xs; yso[thread]= ys;
+ return R.wrld.aotables+ thread*tot*3;
+}
+
+static float *sphere_sampler(int type, int resol, int thread, int xs, int ys, int reset)
+{
+ int tot;
+ float *vec;
+
+ tot= 2*resol*resol;
+
+ if (type & WO_AORNDSMP) {
+ /* total random sampling. NOT THREADSAFE! (should be removed, is not useful) */
+ RNG *rng = BLI_rng_new(BLI_thread_rand(thread));
+ float *sphere;
+ int a;
+
+ /* always returns table */
+ sphere= threadsafe_table_sphere(0, thread, xs, ys, tot);
+
+ vec= sphere;
+ for (a=0; a<tot; a++, vec+=3) {
+ BLI_rng_get_float_unit_v3(rng, vec);
+ }
+
+ BLI_rng_free(rng);
+
+ return sphere;
+ }
+ else {
+ float *sphere;
+ float *vec1;
+
+ /* returns table if xs and ys were equal to last call, and not resetting */
+ sphere= (reset)? NULL: threadsafe_table_sphere(1, thread, xs, ys, tot);
+ if (sphere==NULL) {
+ float cosfi, sinfi, cost, sint;
+ float ang;
+ int a;
+
+ sphere= threadsafe_table_sphere(0, thread, xs, ys, tot);
+
+ /* random rotation */
+ ang = BLI_thread_frand(thread);
+ sinfi = sinf(ang); cosfi = cosf(ang);
+ ang = BLI_thread_frand(thread);
+ sint = sinf(ang); cost = cosf(ang);
+
+ vec= R.wrld.aosphere;
+ vec1= sphere;
+ for (a=0; a<tot; a++, vec+=3, vec1+=3) {
+ vec1[0]= cost*cosfi*vec[0] - sinfi*vec[1] + sint*cosfi*vec[2];
+ vec1[1]= cost*sinfi*vec[0] + cosfi*vec[1] + sint*sinfi*vec[2];
+ vec1[2]= -sint*vec[0] + cost*vec[2];
+ }
+ }
+ return sphere;
+ }
+}
+
+static void ray_ao_qmc(ShadeInput *shi, float ao[3], float env[3])
+{
+ Isect isec;
+ RayHint point_hint;
+ QMCSampler *qsa=NULL;
+ float samp3d[3];
+ float up[3], side[3], dir[3], nrm[3];
+
+ float maxdist = R.wrld.aodist;
+ float fac=0.0f, prev=0.0f;
+ float adapt_thresh = R.wrld.ao_adapt_thresh;
+ float adapt_speed_fac = R.wrld.ao_adapt_speed_fac;
+
+ int samples=0;
+ int max_samples = R.wrld.aosamp*R.wrld.aosamp;
+
+ float dxyview[3], skyadded=0;
+ int envcolor;
+
+ RE_RC_INIT(isec, *shi);
+ isec.orig.ob = shi->obi;
+ isec.orig.face = shi->vlr;
+ isec.check = RE_CHECK_VLR_NON_SOLID_MATERIAL;
+ isec.skip = RE_SKIP_VLR_NEIGHBOUR;
+ isec.hint = NULL;
+
+ isec.hit.ob = NULL;
+ isec.hit.face = NULL;
+
+ isec.last_hit = NULL;
+
+ isec.mode= (R.wrld.aomode & WO_AODIST)?RE_RAY_SHADOW_TRA:RE_RAY_SHADOW;
+ isec.lay= -1;
+
+ copy_v3_v3(isec.start, shi->co);
+
+ RE_instance_rotate_ray_start(shi->obi, &isec);
+
+ RE_rayobject_hint_bb(R.raytree, &point_hint, isec.start, isec.start);
+ isec.hint = &point_hint;
+
+ zero_v3(ao);
+ zero_v3(env);
+
+ /* prevent sky colors to be added for only shadow (shadow becomes alpha) */
+ envcolor= R.wrld.aocolor;
+ if (shi->mat->mode & MA_ONLYSHADOW)
+ envcolor= WO_AOPLAIN;
+
+ if (envcolor == WO_AOSKYTEX) {
+ dxyview[0]= 1.0f/(float)R.wrld.aosamp;
+ dxyview[1]= 1.0f/(float)R.wrld.aosamp;
+ dxyview[2]= 0.0f;
+ }
+
+ if (shi->vlr->flag & R_SMOOTH) {
+ copy_v3_v3(nrm, shi->vn);
+ }
+ else {
+ copy_v3_v3(nrm, shi->facenor);
+ }
+
+ ortho_basis_v3v3_v3(up, side, nrm);
+
+ /* sampling init */
+ if (R.wrld.ao_samp_method==WO_AOSAMP_HALTON) {
+ float speedfac;
+
+ speedfac = get_avg_speed(shi) * adapt_speed_fac;
+ CLAMP(speedfac, 1.0f, 1000.0f);
+ max_samples /= speedfac;
+ if (max_samples < 5) max_samples = 5;
+
+ qsa = get_thread_qmcsampler(&R, shi->thread, SAMP_TYPE_HALTON, max_samples);
+ }
+ else if (R.wrld.ao_samp_method==WO_AOSAMP_HAMMERSLEY)
+ qsa = get_thread_qmcsampler(&R, shi->thread, SAMP_TYPE_HAMMERSLEY, max_samples);
+
+ QMC_initPixel(qsa, shi->thread);
+
+ while (samples < max_samples) {
+
+ /* sampling, returns quasi-random vector in unit hemisphere */
+ QMC_sampleHemi(samp3d, qsa, shi->thread, samples);
+
+ dir[0] = (samp3d[0]*up[0] + samp3d[1]*side[0] + samp3d[2]*nrm[0]);
+ dir[1] = (samp3d[0]*up[1] + samp3d[1]*side[1] + samp3d[2]*nrm[1]);
+ dir[2] = (samp3d[0]*up[2] + samp3d[1]*side[2] + samp3d[2]*nrm[2]);
+
+ normalize_v3(dir);
+
+ isec.dir[0] = -dir[0];
+ isec.dir[1] = -dir[1];
+ isec.dir[2] = -dir[2];
+ isec.dist = maxdist;
+
+ RE_instance_rotate_ray_dir(shi->obi, &isec);
+
+ prev = fac;
+
+ if (RE_rayobject_raycast(R.raytree, &isec)) {
+ if (R.wrld.aomode & WO_AODIST) fac+= expf(-isec.dist*R.wrld.aodistfac);
+ else fac+= 1.0f;
+ }
+ else if (envcolor!=WO_AOPLAIN) {
+ float skycol[4];
+ float view[3];
+
+ view[0]= -dir[0];
+ view[1]= -dir[1];
+ view[2]= -dir[2];
+ normalize_v3(view);
+
+ if (envcolor==WO_AOSKYCOL) {
+ const float skyfac= 0.5f * (1.0f + dot_v3v3(view, R.grvec));
+ env[0]+= (1.0f-skyfac)*R.wrld.horr + skyfac*R.wrld.zenr;
+ env[1]+= (1.0f-skyfac)*R.wrld.horg + skyfac*R.wrld.zeng;
+ env[2]+= (1.0f-skyfac)*R.wrld.horb + skyfac*R.wrld.zenb;
+ }
+ else { /* WO_AOSKYTEX */
+ shadeSkyView(skycol, isec.start, view, dxyview, shi->thread);
+ shadeSunView(skycol, shi->view);
+ env[0]+= skycol[0];
+ env[1]+= skycol[1];
+ env[2]+= skycol[2];
+ }
+ skyadded++;
+ }
+
+ samples++;
+
+ if (qsa && qsa->type == SAMP_TYPE_HALTON) {
+ /* adaptive sampling - consider samples below threshold as in shadow (or vice versa) and exit early */
+ if (adapt_thresh > 0.0f && (samples > max_samples/2) ) {
+
+ if (adaptive_sample_contrast_val(samples, prev, fac, adapt_thresh)) {
+ break;
+ }
+ }
+ }
+ }
+
+ /* average color times distances/hits formula */
+ ao[0]= ao[1]= ao[2]= 1.0f - fac/(float)samples;
+
+ if (envcolor!=WO_AOPLAIN && skyadded)
+ mul_v3_fl(env, (1.0f - fac/(float)samples)/((float)skyadded));
+ else
+ copy_v3_v3(env, ao);
+
+ if (qsa)
+ release_thread_qmcsampler(&R, shi->thread, qsa);
+}
+
+/* extern call from shade_lamp_loop, ambient occlusion calculus */
+static void ray_ao_spheresamp(ShadeInput *shi, float ao[3], float env[3])
+{
+ Isect isec;
+ RayHint point_hint;
+ float *vec, *nrm, bias, sh=0.0f;
+ float maxdist = R.wrld.aodist;
+ float dxyview[3];
+ int j= -1, tot, actual=0, skyadded=0, envcolor, resol= R.wrld.aosamp;
+
+ RE_RC_INIT(isec, *shi);
+ isec.orig.ob = shi->obi;
+ isec.orig.face = shi->vlr;
+ isec.check = RE_CHECK_VLR_RENDER;
+ isec.skip = RE_SKIP_VLR_NEIGHBOUR;
+ isec.hint = NULL;
+
+ isec.hit.ob = NULL;
+ isec.hit.face = NULL;
+
+ isec.last_hit = NULL;
+
+ isec.mode= (R.wrld.aomode & WO_AODIST)?RE_RAY_SHADOW_TRA:RE_RAY_SHADOW;
+ isec.lay= -1;
+
+ copy_v3_v3(isec.start, shi->co);
+ RE_instance_rotate_ray_start(shi->obi, &isec);
+
+ RE_rayobject_hint_bb(R.raytree, &point_hint, isec.start, isec.start);
+ isec.hint = &point_hint;
+
+ zero_v3(ao);
+ zero_v3(env);
+
+ /* bias prevents smoothed faces to appear flat */
+ if (shi->vlr->flag & R_SMOOTH) {
+ bias= R.wrld.aobias;
+ nrm= shi->vn;
+ }
+ else {
+ bias= 0.0f;
+ nrm= shi->facenor;
+ }
+
+ /* prevent sky colors to be added for only shadow (shadow becomes alpha) */
+ envcolor= R.wrld.aocolor;
+ if (shi->mat->mode & MA_ONLYSHADOW)
+ envcolor= WO_AOPLAIN;
+
+ if (resol>32) resol= 32;
+
+ /* get sphere samples. for faces we get the same samples for sample x/y values,
+ * for strand render we always require a new sampler because x/y are not set */
+ vec= sphere_sampler(R.wrld.aomode, resol, shi->thread, shi->xs, shi->ys, shi->strand != NULL);
+
+ /* warning: since we use full sphere now, and dotproduct is below, we do twice as much */
+ tot= 2*resol*resol;
+
+ if (envcolor == WO_AOSKYTEX) {
+ dxyview[0]= 1.0f/(float)resol;
+ dxyview[1]= 1.0f/(float)resol;
+ dxyview[2]= 0.0f;
+ }
+
+ while (tot--) {
+
+ if (dot_v3v3(vec, nrm) > bias) {
+ /* only ao samples for mask */
+ if (R.r.mode & R_OSA) {
+ j++;
+ if (j==R.osa) j= 0;
+ if (!(shi->mask & (1<<j))) {
+ vec+=3;
+ continue;
+ }
+ }
+
+ actual++;
+
+ /* always set start/vec/dist */
+ isec.dir[0] = -vec[0];
+ isec.dir[1] = -vec[1];
+ isec.dir[2] = -vec[2];
+ isec.dist = maxdist;
+
+ RE_instance_rotate_ray_dir(shi->obi, &isec);
+
+ /* do the trace */
+ if (RE_rayobject_raycast(R.raytree, &isec)) {
+ if (R.wrld.aomode & WO_AODIST) sh+= expf(-isec.dist*R.wrld.aodistfac);
+ else sh+= 1.0f;
+ }
+ else if (envcolor!=WO_AOPLAIN) {
+ float skycol[4];
+ float view[3];
+
+ view[0]= -vec[0];
+ view[1]= -vec[1];
+ view[2]= -vec[2];
+ normalize_v3(view);
+
+ if (envcolor==WO_AOSKYCOL) {
+ const float fac = 0.5f * (1.0f + dot_v3v3(view, R.grvec));
+ env[0]+= (1.0f-fac)*R.wrld.horr + fac*R.wrld.zenr;
+ env[1]+= (1.0f-fac)*R.wrld.horg + fac*R.wrld.zeng;
+ env[2]+= (1.0f-fac)*R.wrld.horb + fac*R.wrld.zenb;
+ }
+ else { /* WO_AOSKYTEX */
+ shadeSkyView(skycol, isec.start, view, dxyview, shi->thread);
+ shadeSunView(skycol, shi->view);
+ env[0]+= skycol[0];
+ env[1]+= skycol[1];
+ env[2]+= skycol[2];
+ }
+ skyadded++;
+ }
+ }
+ /* samples */
+ vec+= 3;
+ }
+
+ if (actual==0) sh= 1.0f;
+ else sh = 1.0f - sh/((float)actual);
+
+ /* average color times distances/hits formula */
+ ao[0]= ao[1]= ao[2]= sh;
+
+ if (envcolor!=WO_AOPLAIN && skyadded)
+ mul_v3_fl(env, sh/((float)skyadded));
+ else
+ copy_v3_v3(env, ao);
+}
+
+void ray_ao(ShadeInput *shi, float ao[3], float env[3])
+{
+ /* Unfortunately, the unusual way that the sphere sampler calculates roughly twice as many
+ * samples as are actually traced, and skips them based on bias and OSA settings makes it very difficult
+ * to reuse code between these two functions. This is the easiest way I can think of to do it
+ * --broken */
+ if (ELEM(R.wrld.ao_samp_method, WO_AOSAMP_HAMMERSLEY, WO_AOSAMP_HALTON))
+ ray_ao_qmc(shi, ao, env);
+ else if (R.wrld.ao_samp_method == WO_AOSAMP_CONSTANT)
+ ray_ao_spheresamp(shi, ao, env);
+}
+
+static void ray_shadow_jittered_coords(ShadeInput *shi, int max, float jitco[RE_MAX_OSA][3], int *totjitco)
+{
+ /* magic numbers for reordering sample positions to give better
+ * results with adaptive sample, when it usually only takes 4 samples */
+ int order8[8] = {0, 1, 5, 6, 2, 3, 4, 7};
+ int order11[11] = {1, 3, 8, 10, 0, 2, 4, 5, 6, 7, 9};
+ int order16[16] = {1, 3, 9, 12, 0, 6, 7, 8, 13, 2, 4, 5, 10, 11, 14, 15};
+ int count = count_mask(shi->mask);
+
+ /* for better antialising shadow samples are distributed over the subpixel
+ * sample coordinates, this only works for raytracing depth 0 though */
+ if (!shi->strand && shi->depth == 0 && count > 1 && count <= max) {
+ float xs, ys, zs, view[3];
+ int samp, ordsamp, tot= 0;
+
+ for (samp=0; samp<R.osa; samp++) {
+ if (R.osa == 8) ordsamp = order8[samp];
+ else if (R.osa == 11) ordsamp = order11[samp];
+ else if (R.osa == 16) ordsamp = order16[samp];
+ else ordsamp = samp;
+
+ if (shi->mask & (1<<ordsamp)) {
+ /* zbuffer has this inverse corrected, ensures xs,ys are inside pixel */
+ xs= (float)shi->scanco[0] + R.jit[ordsamp][0] + 0.5f;
+ ys= (float)shi->scanco[1] + R.jit[ordsamp][1] + 0.5f;
+ zs= shi->scanco[2];
+
+ shade_input_calc_viewco(shi, xs, ys, zs, view, NULL, jitco[tot], NULL, NULL);
+ tot++;
+ }
+ }
+
+ *totjitco= tot;
+ }
+ else {
+ copy_v3_v3(jitco[0], shi->co);
+ *totjitco= 1;
+ }
+}
+
+static void ray_shadow_qmc(ShadeInput *shi, LampRen *lar, const float lampco[3], float shadfac[4], Isect *isec)
+{
+ QMCSampler *qsa=NULL;
+ int samples=0;
+ float samp3d[3];
+
+ float fac=0.0f, vec[3], end[3];
+ float colsq[4];
+ float adapt_thresh = lar->adapt_thresh;
+ int min_adapt_samples=4, max_samples = lar->ray_totsamp;
+ float start[3];
+ bool do_soft = true, full_osa = false;
+ int i;
+
+ float min[3], max[3];
+ RayHint bb_hint;
+
+ float jitco[RE_MAX_OSA][3];
+ int totjitco;
+
+ colsq[0] = colsq[1] = colsq[2] = 0.0;
+ if (isec->mode==RE_RAY_SHADOW_TRA) {
+ shadfac[0]= shadfac[1]= shadfac[2]= shadfac[3]= 0.0f;
+ }
+ else
+ shadfac[3]= 1.0f;
+
+ if (lar->ray_totsamp < 2) do_soft = false;
+ if ((R.r.mode & R_OSA) && (R.osa > 0) && (shi->vlr->flag & R_FULL_OSA)) full_osa = true;
+
+ if (full_osa) {
+ if (do_soft) max_samples = max_samples/R.osa + 1;
+ else max_samples = 1;
+ }
+ else {
+ if (do_soft) max_samples = lar->ray_totsamp;
+ else if (shi->depth == 0) max_samples = (R.osa > 4)?R.osa:5;
+ else max_samples = 1;
+ }
+
+ ray_shadow_jittered_coords(shi, max_samples, jitco, &totjitco);
+
+ /* sampling init */
+ if (lar->ray_samp_method==LA_SAMP_HALTON)
+ qsa = get_thread_qmcsampler(&R, shi->thread, SAMP_TYPE_HALTON, max_samples);
+ else if (lar->ray_samp_method==LA_SAMP_HAMMERSLEY)
+ qsa = get_thread_qmcsampler(&R, shi->thread, SAMP_TYPE_HAMMERSLEY, max_samples);
+
+ QMC_initPixel(qsa, shi->thread);
+
+ INIT_MINMAX(min, max);
+ for (i = 0; i < totjitco; i++) {
+ minmax_v3v3_v3(min, max, jitco[i]);
+ }
+ if (shi->obi->flag & R_ENV_TRANSFORMED) {
+ mul_m4_v3(shi->obi->imat, min);
+ mul_m4_v3(shi->obi->imat, max);
+ }
+ RE_rayobject_hint_bb(R.raytree, &bb_hint, min, max);
+
+ isec->hint = &bb_hint;
+ isec->check = RE_CHECK_VLR_RENDER;
+ isec->skip = RE_SKIP_VLR_NEIGHBOUR;
+ copy_v3_v3(vec, lampco);
+
+ while (samples < max_samples) {
+
+ isec->orig.ob = shi->obi;
+ isec->orig.face = shi->vlr;
+
+ /* manually jitter the start shading co-ord per sample
+ * based on the pre-generated OSA texture sampling offsets,
+ * for anti-aliasing sharp shadow edges. */
+ copy_v3_v3(start, jitco[samples % totjitco]);
+
+ if (do_soft) {
+ /* sphere shadow source */
+ if (lar->type == LA_LOCAL) {
+ float ru[3], rv[3], v[3], s[3];
+
+ /* calc tangent plane vectors */
+ sub_v3_v3v3(v, start, lampco);
+ normalize_v3(v);
+ ortho_basis_v3v3_v3(ru, rv, v);
+
+ /* sampling, returns quasi-random vector in area_size disc */
+ QMC_sampleDisc(samp3d, qsa, shi->thread, samples, lar->area_size);
+
+ /* distribute disc samples across the tangent plane */
+ s[0] = samp3d[0]*ru[0] + samp3d[1]*rv[0];
+ s[1] = samp3d[0]*ru[1] + samp3d[1]*rv[1];
+ s[2] = samp3d[0]*ru[2] + samp3d[1]*rv[2];
+
+ copy_v3_v3(samp3d, s);
+ }
+ else {
+ /* sampling, returns quasi-random vector in [sizex,sizey]^2 plane */
+ QMC_sampleRect(samp3d, qsa, shi->thread, samples, lar->area_size, lar->area_sizey);
+
+ /* align samples to lamp vector */
+ mul_m3_v3(lar->mat, samp3d);
+ }
+ end[0] = vec[0]+samp3d[0];
+ end[1] = vec[1]+samp3d[1];
+ end[2] = vec[2]+samp3d[2];
+ }
+ else {
+ copy_v3_v3(end, vec);
+ }
+
+ if (shi->strand) {
+ /* bias away somewhat to avoid self intersection */
+ float jitbias= 0.5f*(len_v3(shi->dxco) + len_v3(shi->dyco));
+ float v[3];
+
+ sub_v3_v3v3(v, start, end);
+ normalize_v3(v);
+
+ start[0] -= jitbias*v[0];
+ start[1] -= jitbias*v[1];
+ start[2] -= jitbias*v[2];
+ }
+
+ copy_v3_v3(isec->start, start);
+ sub_v3_v3v3(isec->dir, end, start);
+ isec->dist = normalize_v3(isec->dir);
+
+ RE_instance_rotate_ray(shi->obi, isec);
+
+ /* trace the ray */
+ if (isec->mode==RE_RAY_SHADOW_TRA) {
+ float col[4] = {1.0f, 1.0f, 1.0f, 1.0f};
+
+ ray_trace_shadow_tra(isec, shi, DEPTH_SHADOW_TRA, 0, col);
+ shadfac[0] += col[0];
+ shadfac[1] += col[1];
+ shadfac[2] += col[2];
+ shadfac[3] += col[3];
+
+ /* for variance calc */
+ colsq[0] += col[0]*col[0];
+ colsq[1] += col[1]*col[1];
+ colsq[2] += col[2]*col[2];
+ }
+ else {
+ if ( RE_rayobject_raycast(R.raytree, isec) ) fac+= 1.0f;
+ }
+
+ samples++;
+
+ if (lar->ray_samp_method == LA_SAMP_HALTON) {
+
+ /* adaptive sampling - consider samples below threshold as in shadow (or vice versa) and exit early */
+ if ((max_samples > min_adapt_samples) && (adapt_thresh > 0.0f) && (samples > max_samples / 3)) {
+ if (isec->mode==RE_RAY_SHADOW_TRA) {
+ if ((shadfac[3] / samples > (1.0f-adapt_thresh)) || (shadfac[3] / samples < adapt_thresh))
+ break;
+ else if (adaptive_sample_variance(samples, shadfac, colsq, adapt_thresh))
+ break;
+ }
+ else {
+ if ((fac / samples > (1.0f-adapt_thresh)) || (fac / samples < adapt_thresh))
+ break;
+ }
+ }
+ }
+ }
+
+ if (isec->mode==RE_RAY_SHADOW_TRA) {
+ shadfac[0] /= samples;
+ shadfac[1] /= samples;
+ shadfac[2] /= samples;
+ shadfac[3] /= samples;
+ }
+ else
+ shadfac[3]= 1.0f-fac/samples;
+
+ if (qsa)
+ release_thread_qmcsampler(&R, shi->thread, qsa);
+}
+
+static void ray_shadow_jitter(ShadeInput *shi, LampRen *lar, const float lampco[3], float shadfac[4], Isect *isec)
+{
+ /* area soft shadow */
+ const float *jitlamp;
+ float fac=0.0f, div=0.0f, vec[3];
+ int a, j= -1, mask;
+ RayHint point_hint;
+
+ if (isec->mode==RE_RAY_SHADOW_TRA) {
+ shadfac[0]= shadfac[1]= shadfac[2]= shadfac[3]= 0.0f;
+ }
+ else shadfac[3]= 1.0f;
+
+ fac= 0.0f;
+ jitlamp= give_jitter_plane(lar, shi->thread, shi->xs, shi->ys);
+
+ a= lar->ray_totsamp;
+
+ /* this correction to make sure we always take at least 1 sample */
+ mask= shi->mask;
+ if (a==4) mask |= (mask>>4)|(mask>>8);
+ else if (a==9) mask |= (mask>>9);
+
+ copy_v3_v3(isec->start, shi->co);
+ RE_instance_rotate_ray_start(shi->obi, isec);
+
+ isec->orig.ob = shi->obi;
+ isec->orig.face = shi->vlr;
+ RE_rayobject_hint_bb(R.raytree, &point_hint, isec->start, isec->start);
+ isec->hint = &point_hint;
+
+ while (a--) {
+
+ if (R.r.mode & R_OSA) {
+ j++;
+ if (j>=R.osa) j= 0;
+ if (!(mask & (1<<j))) {
+ jitlamp+= 2;
+ continue;
+ }
+ }
+
+ vec[0]= jitlamp[0];
+ vec[1]= jitlamp[1];
+ vec[2]= 0.0f;
+ mul_m3_v3(lar->mat, vec);
+
+ /* set start and vec */
+ isec->dir[0] = vec[0]+lampco[0]-shi->co[0];
+ isec->dir[1] = vec[1]+lampco[1]-shi->co[1];
+ isec->dir[2] = vec[2]+lampco[2]-shi->co[2];
+
+ RE_instance_rotate_ray_dir(shi->obi, isec);
+
+ isec->dist = 1.0f;
+ isec->check = RE_CHECK_VLR_RENDER;
+ isec->skip = RE_SKIP_VLR_NEIGHBOUR;
+
+ if (isec->mode==RE_RAY_SHADOW_TRA) {
+ /* isec.col is like shadfac, so defines amount of light (0.0 is full shadow) */
+ float col[4] = {1.0f, 1.0f, 1.0f, 1.0f};
+
+ ray_trace_shadow_tra(isec, shi, DEPTH_SHADOW_TRA, 0, col);
+ shadfac[0] += col[0];
+ shadfac[1] += col[1];
+ shadfac[2] += col[2];
+ shadfac[3] += col[3];
+ }
+ else if ( RE_rayobject_raycast(R.raytree, isec) ) fac+= 1.0f;
+
+ div+= 1.0f;
+ jitlamp+= 2;
+ }
+
+ if (isec->mode==RE_RAY_SHADOW_TRA) {
+ shadfac[0] /= div;
+ shadfac[1] /= div;
+ shadfac[2] /= div;
+ shadfac[3] /= div;
+ }
+ else {
+ /* sqrt makes nice umbra effect */
+ if (lar->ray_samp_type & LA_SAMP_UMBRA)
+ shadfac[3] = sqrtf(1.0f - fac / div);
+ else
+ shadfac[3] = 1.0f - fac / div;
+ }
+}
+/* extern call from shade_lamp_loop */
+void ray_shadow(ShadeInput *shi, LampRen *lar, float shadfac[4])
+{
+ Isect isec;
+ float lampco[3];
+
+ /* setup isec */
+ RE_RC_INIT(isec, *shi);
+ if (shi->mat->mode & MA_SHADOW_TRA) isec.mode= RE_RAY_SHADOW_TRA;
+ else isec.mode= RE_RAY_SHADOW;
+ isec.hint = NULL;
+
+ if (lar->mode & (LA_LAYER|LA_LAYER_SHADOW))
+ isec.lay= lar->lay;
+ else
+ isec.lay= -1;
+
+ /* only when not mir tracing, first hit optimm */
+ if (shi->depth==0) {
+ isec.last_hit = lar->last_hit[shi->thread];
+ }
+ else {
+ isec.last_hit = NULL;
+ }
+
+ if (lar->type==LA_SUN || lar->type==LA_HEMI) {
+ /* jitter and QMC sampling add a displace vector to the lamp position
+ * that's incorrect because a SUN lamp does not has an exact position
+ * and the displace should be done at the ray vector instead of the
+ * lamp position.
+ * This is easily verified by noticing that shadows of SUN lights change
+ * with the scene BB.
+ *
+ * This was detected during SoC 2009 - Raytrace Optimization, but to keep
+ * consistency with older render code it wasn't removed.
+ *
+ * If the render code goes through some recode/serious bug-fix then this
+ * is something to consider!
+ */
+ lampco[0]= shi->co[0] - R.maxdist*lar->vec[0];
+ lampco[1]= shi->co[1] - R.maxdist*lar->vec[1];
+ lampco[2]= shi->co[2] - R.maxdist*lar->vec[2];
+ }
+ else {
+ copy_v3_v3(lampco, lar->co);
+ }
+
+ if (ELEM(lar->ray_samp_method, LA_SAMP_HALTON, LA_SAMP_HAMMERSLEY)) {
+
+ ray_shadow_qmc(shi, lar, lampco, shadfac, &isec);
+
+ }
+ else {
+ if (lar->ray_totsamp<2) {
+
+ isec.orig.ob = shi->obi;
+ isec.orig.face = shi->vlr;
+
+ shadfac[3]= 1.0f; /* 1.0=full light */
+
+ /* set up isec.dir */
+ copy_v3_v3(isec.start, shi->co);
+ sub_v3_v3v3(isec.dir, lampco, isec.start);
+ isec.dist = normalize_v3(isec.dir);
+
+ RE_instance_rotate_ray(shi->obi, &isec);
+
+ if (isec.mode==RE_RAY_SHADOW_TRA) {
+ /* isec.col is like shadfac, so defines amount of light (0.0 is full shadow) */
+ float col[4] = {1.0f, 1.0f, 1.0f, 1.0f};
+
+ ray_trace_shadow_tra(&isec, shi, DEPTH_SHADOW_TRA, 0, col);
+ copy_v4_v4(shadfac, col);
+ }
+ else if (RE_rayobject_raycast(R.raytree, &isec))
+ shadfac[3]= 0.0f;
+ }
+ else {
+ ray_shadow_jitter(shi, lar, lampco, shadfac, &isec);
+ }
+ }
+
+ /* for first hit optim, set last interesected shadow face */
+ if (shi->depth==0) {
+ lar->last_hit[shi->thread] = isec.last_hit;
+ }
+
+}
+
diff --git a/source/blender/render/intern/source/render_result.c b/source/blender/render/intern/source/render_result.c
index a6f1ecd5405..e0cacdf4b8f 100644
--- a/source/blender/render/intern/source/render_result.c
+++ b/source/blender/render/intern/source/render_result.c
@@ -95,7 +95,7 @@ void render_result_free(RenderResult *res)
if (rl->acolrect) MEM_freeN(rl->acolrect);
if (rl->scolrect) MEM_freeN(rl->scolrect);
if (rl->display_buffer) MEM_freeN(rl->display_buffer);
-
+
while (rl->passes.first) {
RenderPass *rpass = rl->passes.first;
if (rpass->rect) MEM_freeN(rpass->rect);
@@ -128,13 +128,13 @@ void render_result_free(RenderResult *res)
void render_result_free_list(ListBase *lb, RenderResult *rr)
{
RenderResult *rrnext;
-
+
for (; rr; rr = rrnext) {
rrnext = rr->next;
-
+
if (lb && lb->first)
BLI_remlink(lb, rr);
-
+
render_result_free(rr);
}
}
@@ -206,7 +206,7 @@ static RenderPass *render_layer_add_pass(RenderResult *rr, RenderLayer *rl, int
const int view_id = BLI_findstringindex(&rr->views, viewname, offsetof(RenderView, name));
RenderPass *rpass = MEM_callocN(sizeof(RenderPass), name);
size_t rectsize = ((size_t)rr->rectx) * rr->recty * channels;
-
+
rpass->channels = channels;
rpass->rectx = rl->rectx;
rpass->recty = rl->recty;
@@ -216,7 +216,7 @@ static RenderPass *render_layer_add_pass(RenderResult *rr, RenderLayer *rl, int
BLI_strncpy(rpass->chan_id, chan_id, sizeof(rpass->chan_id));
BLI_strncpy(rpass->view, viewname, sizeof(rpass->view));
set_pass_full_name(rpass->fullname, rpass->name, -1, rpass->view, rpass->chan_id);
-
+
if (rl->exrhandle) {
int a;
for (a = 0; a < channels; a++) {
@@ -227,13 +227,13 @@ static RenderPass *render_layer_add_pass(RenderResult *rr, RenderLayer *rl, int
else {
float *rect;
int x;
-
+
rpass->rect = MEM_mapallocN(sizeof(float) * rectsize, name);
if (rpass->rect == NULL) {
MEM_freeN(rpass);
return NULL;
}
-
+
if (STREQ(rpass->name, RE_PASSNAME_VECTOR)) {
/* initialize to max speed */
rect = rpass->rect;
@@ -267,13 +267,13 @@ RenderResult *render_result_new(Render *re, rcti *partrct, int crop, int savebuf
RenderLayer *rl;
RenderView *rv;
int rectx, recty;
-
+
rectx = BLI_rcti_size_x(partrct);
recty = BLI_rcti_size_y(partrct);
-
+
if (rectx <= 0 || recty <= 0)
return NULL;
-
+
rr = MEM_callocN(sizeof(RenderResult), "new render result");
rr->rectx = rectx;
rr->recty = recty;
@@ -286,7 +286,7 @@ RenderResult *render_result_new(Render *re, rcti *partrct, int crop, int savebuf
rr->tilerect.xmax = partrct->xmax - re->disprect.xmin;
rr->tilerect.ymin = partrct->ymin - re->disprect.ymin;
rr->tilerect.ymax = partrct->ymax - re->disprect.ymin;
-
+
if (savebuffers) {
rr->do_exr_tile = true;
}
@@ -304,14 +304,14 @@ RenderResult *render_result_new(Render *re, rcti *partrct, int crop, int savebuf
rl = MEM_callocN(sizeof(RenderLayer), "new render layer");
BLI_addtail(&rr->layers, rl);
-
+
BLI_strncpy(rl->name, view_layer->name, sizeof(rl->name));
rl->layflag = view_layer->layflag;
rl->passflag = view_layer->passflag; /* for debugging: view_layer->passflag | SCE_PASS_RAYHITS; */
rl->pass_xor = view_layer->pass_xor;
rl->rectx = rectx;
rl->recty = recty;
-
+
if (rr->do_exr_tile) {
rl->display_buffer = MEM_mapallocN((size_t)rectx * recty * sizeof(unsigned int),
"Combined display space rgba");
@@ -412,7 +412,7 @@ RenderResult *render_result_new(Render *re, rcti *partrct, int crop, int savebuf
if (BLI_listbase_is_empty(&rr->layers) && !(layername && layername[0])) {
rl = MEM_callocN(sizeof(RenderLayer), "new render layer");
BLI_addtail(&rr->layers, rl);
-
+
rl->rectx = rectx;
rl->recty = recty;
@@ -439,15 +439,15 @@ RenderResult *render_result_new(Render *re, rcti *partrct, int crop, int savebuf
/* note, this has to be in sync with scene.c */
rl->layflag = 0x7FFF; /* solid ztra halo strand */
rl->passflag = SCE_PASS_COMBINED;
-
+
re->active_view_layer = 0;
}
-
+
/* border render; calculate offset for use in compositor. compo is centralized coords */
/* XXX obsolete? I now use it for drawing border render offset (ton) */
rr->xof = re->disprect.xmin + BLI_rcti_cent_x(&re->disprect) - (re->winx / 2);
rr->yof = re->disprect.ymin + BLI_rcti_cent_y(&re->disprect) - (re->winy / 2);
-
+
return rr;
}
@@ -554,7 +554,7 @@ static void *ml_addlayer_cb(void *base, const char *str)
{
RenderResult *rr = base;
RenderLayer *rl;
-
+
rl = MEM_callocN(sizeof(RenderLayer), "new render layer");
BLI_addtail(&rr->layers, rl);
@@ -676,7 +676,7 @@ RenderResult *render_result_new_from_exr(void *exrhandle, const char *colorspace
rr->rectx = rectx;
rr->recty = recty;
-
+
IMB_exr_multilayer_convert(exrhandle, rr, ml_addview_cb, ml_addlayer_cb, ml_addpass_cb);
for (rl = rr->layers.first; rl; rl = rl->next) {
@@ -695,7 +695,7 @@ RenderResult *render_result_new_from_exr(void *exrhandle, const char *colorspace
}
}
}
-
+
return rr;
}
@@ -740,16 +740,16 @@ static void do_merge_tile(RenderResult *rr, RenderResult *rrpart, float *target,
{
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 + ((size_t)rrpart->crop) * tilex);
-
+
copylen = tilex - 2 * rrpart->crop;
tiley -= 2 * rrpart->crop;
-
+
ofs = (((size_t)rrpart->tilerect.ymin) + rrpart->crop) * rr->rectx + (rrpart->tilerect.xmin + rrpart->crop);
target += pixsize * ofs;
}
@@ -776,7 +776,7 @@ void render_result_merge(RenderResult *rr, RenderResult *rrpart)
{
RenderLayer *rl, *rlp;
RenderPass *rpass, *rpassp;
-
+
for (rl = rr->layers.first; rl; rl = rl->next) {
rlp = RE_GetRenderLayer(rrpart, rl->name);
if (rlp) {
@@ -956,7 +956,7 @@ void render_result_single_layer_begin(Render *re)
/* officially pushed result should be NULL... error can happen with do_seq */
RE_FreeRenderResult(re->pushedresult);
-
+
re->pushedresult = re->result;
re->result = NULL;
}
@@ -980,10 +980,10 @@ void render_result_single_layer_end(Render *re)
if (re->pushedresult->rectx == re->result->rectx && re->pushedresult->recty == re->result->recty) {
/* find which layer in re->pushedresult should be replaced */
rl = re->result->layers.first;
-
+
/* render result should be empty after this */
BLI_remlink(&re->result->layers, rl);
-
+
/* reconstruct render result layers */
for (nr = 0, view_layer = re->view_layers.first; view_layer; view_layer = view_layer->next, nr++) {
if (nr == re->active_view_layer) {
@@ -1010,9 +1010,9 @@ static void save_render_result_tile(RenderResult *rr, RenderResult *rrpart, cons
RenderLayer *rlp, *rl;
RenderPass *rpassp;
int offs, partx, party;
-
+
BLI_thread_lock(LOCK_IMAGE);
-
+
for (rlp = rrpart->layers.first; rlp; rlp = rlp->next) {
rl = RE_GetRenderLayer(rr, rlp->name);
@@ -1042,7 +1042,7 @@ static void save_render_result_tile(RenderResult *rr, RenderResult *rrpart, cons
xstride, xstride * rrpart->rectx, rpassp->rect + a + xstride * offs);
}
}
-
+
}
party = rrpart->tilerect.ymin + rrpart->crop;
@@ -1068,7 +1068,7 @@ void render_result_save_empty_result_tiles(Render *re)
RenderPart *pa;
RenderResult *rr;
RenderLayer *rl;
-
+
for (rr = re->result; rr; rr = rr->next) {
for (rl = rr->layers.first; rl; rl = rl->next) {
for (pa = re->parts.first; pa; pa = pa->next) {
@@ -1112,7 +1112,7 @@ void render_result_exr_file_end(Render *re)
rr->do_exr_tile = false;
}
-
+
render_result_free_list(&re->fullresult, re->result);
re->result = NULL;
@@ -1130,8 +1130,8 @@ void render_result_exr_file_merge(RenderResult *rr, RenderResult *rrpart, const
void render_result_exr_file_path(Scene *scene, const char *layname, int sample, char *filepath)
{
char name[FILE_MAXFILE + MAX_ID_NAME + MAX_ID_NAME + 100];
- const char *fi = BLI_path_basename(G.main->name);
-
+ const char *fi = BLI_path_basename(BKE_main_blendfile_path_from_global());
+
if (sample == 0) {
BLI_snprintf(name, sizeof(name), "%s_%s_%s.exr", fi, scene->id.name + 2, layname);
}
@@ -1194,7 +1194,7 @@ 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;
-
+
/* passes are allocated in sync */
for (rpass = rl->passes.first; rpass; rpass = rpass->next) {
const int xstride = rpass->channels;
@@ -1224,10 +1224,11 @@ static void render_result_exr_file_cache_path(Scene *sce, const char *root, char
char path_hexdigest[33];
/* If root is relative, use either current .blend file dir, or temp one if not saved. */
- if (G.main->name[0]) {
- BLI_split_dirfile(G.main->name, dirname, filename, sizeof(dirname), sizeof(filename));
+ const char *blendfile_path = BKE_main_blendfile_path_from_global();
+ if (blendfile_path[0] != '\0') {
+ BLI_split_dirfile(blendfile_path, dirname, filename, sizeof(dirname), sizeof(filename));
BLI_replace_extension(filename, sizeof(filename), ""); /* strip '.blend' */
- BLI_hash_md5_buffer(G.main->name, strlen(G.main->name), path_digest);
+ BLI_hash_md5_buffer(blendfile_path, strlen(blendfile_path), path_digest);
}
else {
BLI_strncpy(dirname, BKE_tempdir_base(), sizeof(dirname));
@@ -1291,7 +1292,7 @@ ImBuf *render_result_rect_to_ibuf(RenderResult *rr, RenderData *rd, const int vi
/* float factor for random dither, imbuf takes care of it */
ibuf->dither = rd->dither_intensity;
-
+
/* prepare to gamma correct to sRGB color space
* note that sequence editor can generate 8bpc render buffers
*/
@@ -1332,7 +1333,7 @@ void RE_render_result_rect_from_ibuf(RenderResult *rr, RenderData *UNUSED(rd), I
if (!rv->rectf)
rv->rectf = MEM_mallocN(4 * sizeof(float) * rr->rectx * rr->recty, "render_seq rectf");
-
+
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
diff --git a/source/blender/render/intern/source/render_texture.c b/source/blender/render/intern/source/render_texture.c
index 79d13ecab5b..99da5b3ca01 100644
--- a/source/blender/render/intern/source/render_texture.c
+++ b/source/blender/render/intern/source/render_texture.c
@@ -95,7 +95,7 @@ static void tex_normal_derivate(Tex *tex, TexResult *texres)
float col[4];
if (BKE_colorband_evaluate(tex->coba, texres->tin, col)) {
float fac0, fac1, fac2, fac3;
-
+
fac0= (col[0]+col[1]+col[2]);
BKE_colorband_evaluate(tex->coba, texres->nor[0], col);
fac1= (col[0]+col[1]+col[2]);
@@ -103,11 +103,11 @@ static void tex_normal_derivate(Tex *tex, TexResult *texres)
fac2= (col[0]+col[1]+col[2]);
BKE_colorband_evaluate(tex->coba, texres->nor[2], col);
fac3= (col[0]+col[1]+col[2]);
-
+
texres->nor[0]= (fac0 - fac1) / 3.0f;
texres->nor[1]= (fac0 - fac2) / 3.0f;
texres->nor[2]= (fac0 - fac3) / 3.0f;
-
+
return;
}
}
@@ -173,7 +173,7 @@ static int blend(Tex *tex, const float texvec[3], TexResult *texres)
static int clouds(Tex *tex, const float texvec[3], TexResult *texres)
{
int rv = TEX_INT;
-
+
texres->tin = BLI_gTurbulence(tex->noisesize, texvec[0], texvec[1], texvec[2], tex->noisedepth, (tex->noisetype!=TEX_NOISESOFT), tex->noisebasis);
if (texres->nor!=NULL) {
@@ -181,7 +181,7 @@ static int clouds(Tex *tex, const float texvec[3], TexResult *texres)
texres->nor[0] = BLI_gTurbulence(tex->noisesize, texvec[0] + tex->nabla, texvec[1], texvec[2], tex->noisedepth, (tex->noisetype!=TEX_NOISESOFT), tex->noisebasis);
texres->nor[1] = BLI_gTurbulence(tex->noisesize, texvec[0], texvec[1] + tex->nabla, texvec[2], tex->noisedepth, (tex->noisetype!=TEX_NOISESOFT), tex->noisebasis);
texres->nor[2] = BLI_gTurbulence(tex->noisesize, texvec[0], texvec[1], texvec[2] + tex->nabla, tex->noisedepth, (tex->noisetype!=TEX_NOISESOFT), tex->noisebasis);
-
+
tex_normal_derivate(tex, texres);
rv |= TEX_NOR;
}
@@ -215,7 +215,7 @@ static float tex_sin(float a)
static float tex_saw(float a)
{
const float b = 2*M_PI;
-
+
int n = (int)(a / b);
a -= n*b;
if (a < 0) a += b;
@@ -227,9 +227,9 @@ static float tex_tri(float a)
{
const float b = 2*M_PI;
const float rmax = 1.0;
-
+
a = rmax - 2.0f*fabsf(floorf((a*(1.0f/b))+0.5f) - (a*(1.0f/b)));
-
+
return a;
}
@@ -244,9 +244,9 @@ static float wood_int(Tex *tex, float x, float y, float z)
waveform[0] = tex_sin; /* assign address of tex_sin() function to pointer array */
waveform[1] = tex_saw;
waveform[2] = tex_tri;
-
+
if ((wf>TEX_TRI) || (wf<TEX_SIN)) wf=0; /* check to be sure noisebasis2 is initialized ahead of time */
-
+
if (wt==TEX_BAND) {
wi = waveform[wf]((x + y + z)*10.0f);
}
@@ -261,7 +261,7 @@ static float wood_int(Tex *tex, float x, float y, float z)
wi = tex->turbul*BLI_gNoise(tex->noisesize, x, y, z, (tex->noisetype!=TEX_NOISESOFT), tex->noisebasis);
wi = waveform[wf](sqrtf(x*x + y*y + z*z)*20.0f + wi);
}
-
+
return wi;
}
@@ -275,7 +275,7 @@ static int wood(Tex *tex, const float texvec[3], TexResult *texres)
texres->nor[0] = wood_int(tex, texvec[0] + tex->nabla, texvec[1], texvec[2]);
texres->nor[1] = wood_int(tex, texvec[0], texvec[1] + tex->nabla, texvec[2]);
texres->nor[2] = wood_int(tex, texvec[0], texvec[1], texvec[2] + tex->nabla);
-
+
tex_normal_derivate(tex, texres);
rv |= TEX_NOR;
}
@@ -291,16 +291,16 @@ static float marble_int(Tex *tex, float x, float y, float z)
float n, mi;
short wf = tex->noisebasis2; /* wave form: TEX_SIN=0, TEX_SAW=1, TEX_TRI=2 */
short mt = tex->stype; /* marble type: TEX_SOFT=0, TEX_SHARP=1,TEX_SHAPER=2 */
-
+
float (*waveform[3])(float); /* create array of pointers to waveform functions */
waveform[0] = tex_sin; /* assign address of tex_sin() function to pointer array */
waveform[1] = tex_saw;
waveform[2] = tex_tri;
-
+
if ((wf>TEX_TRI) || (wf<TEX_SIN)) wf=0; /* check to be sure noisebasis2 isn't initialized ahead of time */
-
+
n = 5.0f * (x + y + z);
-
+
mi = n + tex->turbul * BLI_gTurbulence(tex->noisesize, x, y, z, tex->noisedepth, (tex->noisetype!=TEX_NOISESOFT), tex->noisebasis);
if (mt>=TEX_SOFT) { /* TEX_SOFT always true */
@@ -327,9 +327,9 @@ static int marble(Tex *tex, const float texvec[3], TexResult *texres)
texres->nor[0] = marble_int(tex, texvec[0] + tex->nabla, texvec[1], texvec[2]);
texres->nor[1] = marble_int(tex, texvec[0], texvec[1] + tex->nabla, texvec[2]);
texres->nor[2] = marble_int(tex, texvec[0], texvec[1], texvec[2] + tex->nabla);
-
+
tex_normal_derivate(tex, texres);
-
+
rv |= TEX_NOR;
}
@@ -397,8 +397,8 @@ static int magic(Tex *tex, const float texvec[3], TexResult *texres)
if (turb!=0.0f) {
turb*= 2.0f;
- x/= turb;
- y/= turb;
+ x/= turb;
+ y/= turb;
z/= turb;
}
texres->tr = 0.5f - x;
@@ -406,10 +406,10 @@ static int magic(Tex *tex, const float texvec[3], TexResult *texres)
texres->tb = 0.5f - z;
texres->tin= (1.0f / 3.0f) * (texres->tr + texres->tg + texres->tb);
-
+
BRICONTRGB;
texres->ta = 1.0f;
-
+
return TEX_RGB;
}
@@ -420,9 +420,9 @@ static int stucci(Tex *tex, const float texvec[3], TexResult *texres)
{
float nor[3], b2, ofs;
int retval= TEX_INT;
-
+
b2= BLI_gNoise(tex->noisesize, texvec[0], texvec[1], texvec[2], (tex->noisetype!=TEX_NOISESOFT), tex->noisebasis);
-
+
ofs= tex->turbul/200.0f;
if (tex->stype) ofs*=(b2*b2);
@@ -431,27 +431,27 @@ static int stucci(Tex *tex, const float texvec[3], TexResult *texres)
nor[2] = BLI_gNoise(tex->noisesize, texvec[0], texvec[1], texvec[2]+ofs, (tex->noisetype!=TEX_NOISESOFT), tex->noisebasis);
texres->tin= nor[2];
-
+
if (texres->nor) {
-
+
copy_v3_v3(texres->nor, nor);
tex_normal_derivate(tex, texres);
-
+
if (tex->stype==TEX_WALLOUT) {
texres->nor[0]= -texres->nor[0];
texres->nor[1]= -texres->nor[1];
texres->nor[2]= -texres->nor[2];
}
-
+
retval |= TEX_NOR;
}
-
+
if (tex->stype==TEX_WALLOUT)
texres->tin= 1.0f-texres->tin;
-
+
if (texres->tin<0.0f)
texres->tin= 0.0f;
-
+
return retval;
}
@@ -477,7 +477,7 @@ static float mg_mFractalOrfBmTex(Tex *tex, const float texvec[3], TexResult *tex
texres->nor[0] = tex->ns_outscale*mgravefunc(texvec[0] + offs, texvec[1], texvec[2], tex->mg_H, tex->mg_lacunarity, tex->mg_octaves, tex->noisebasis);
texres->nor[1] = tex->ns_outscale*mgravefunc(texvec[0], texvec[1] + offs, texvec[2], tex->mg_H, tex->mg_lacunarity, tex->mg_octaves, tex->noisebasis);
texres->nor[2] = tex->ns_outscale*mgravefunc(texvec[0], texvec[1], texvec[2] + offs, tex->mg_H, tex->mg_lacunarity, tex->mg_octaves, tex->noisebasis);
-
+
tex_normal_derivate(tex, texres);
rv |= TEX_NOR;
}
@@ -507,7 +507,7 @@ static float mg_ridgedOrHybridMFTex(Tex *tex, const float texvec[3], TexResult *
texres->nor[0] = tex->ns_outscale*mgravefunc(texvec[0] + offs, texvec[1], texvec[2], tex->mg_H, tex->mg_lacunarity, tex->mg_octaves, tex->mg_offset, tex->mg_gain, tex->noisebasis);
texres->nor[1] = tex->ns_outscale*mgravefunc(texvec[0], texvec[1] + offs, texvec[2], tex->mg_H, tex->mg_lacunarity, tex->mg_octaves, tex->mg_offset, tex->mg_gain, tex->noisebasis);
texres->nor[2] = tex->ns_outscale*mgravefunc(texvec[0], texvec[1], texvec[2] + offs, tex->mg_H, tex->mg_lacunarity, tex->mg_octaves, tex->mg_offset, tex->mg_gain, tex->noisebasis);
-
+
tex_normal_derivate(tex, texres);
rv |= TEX_NOR;
}
@@ -532,7 +532,7 @@ static float mg_HTerrainTex(Tex *tex, const float texvec[3], TexResult *texres)
texres->nor[0] = tex->ns_outscale*mg_HeteroTerrain(texvec[0] + offs, texvec[1], texvec[2], tex->mg_H, tex->mg_lacunarity, tex->mg_octaves, tex->mg_offset, tex->noisebasis);
texres->nor[1] = tex->ns_outscale*mg_HeteroTerrain(texvec[0], texvec[1] + offs, texvec[2], tex->mg_H, tex->mg_lacunarity, tex->mg_octaves, tex->mg_offset, tex->noisebasis);
texres->nor[2] = tex->ns_outscale*mg_HeteroTerrain(texvec[0], texvec[1], texvec[2] + offs, tex->mg_H, tex->mg_lacunarity, tex->mg_octaves, tex->mg_offset, tex->noisebasis);
-
+
tex_normal_derivate(tex, texres);
rv |= TEX_NOR;
}
@@ -630,7 +630,7 @@ static float voronoiTex(Tex *tex, const float texvec[3], TexResult *texres)
texres->nor[1] = sc * fabsf(tex->vn_w1*da[0] + tex->vn_w2*da[1] + tex->vn_w3*da[2] + tex->vn_w4*da[3]);
voronoi(texvec[0], texvec[1], texvec[2] + offs, da, pa, tex->vn_mexp, tex->vn_distm);
texres->nor[2] = sc * fabsf(tex->vn_w1*da[0] + tex->vn_w2*da[1] + tex->vn_w3*da[2] + tex->vn_w4*da[3]);
-
+
tex_normal_derivate(tex, texres);
rv |= TEX_NOR;
}
@@ -640,7 +640,7 @@ static float voronoiTex(Tex *tex, const float texvec[3], TexResult *texres)
texres->ta = 1.0;
return (rv | TEX_RGB);
}
-
+
BRICONT;
return rv;
@@ -653,20 +653,20 @@ static int texnoise(Tex *tex, TexResult *texres, int thread)
{
float div=3.0;
int val, ran, loop, shift = 29;
-
+
ran= BLI_rng_thread_rand(random_tex_array, thread);
-
+
loop= tex->noisedepth;
/* start from top bits since they have more variance */
val= ((ran >> shift) & 3);
-
+
while (loop--) {
- shift -= 2;
+ shift -= 2;
val *= ((ran >> shift) & 3);
div *= 3.0f;
}
-
+
texres->tin= ((float)val)/div;
BRICONT;
@@ -679,7 +679,7 @@ static int cubemap_glob(const float n[3], float x, float y, float z, float *adr1
{
float x1, y1, z1, nor[3];
int ret;
-
+
if (n==NULL) {
nor[0]= x; nor[1]= y; nor[2]= z; /* use local render coord */
}
@@ -690,7 +690,7 @@ static int cubemap_glob(const float n[3], float x, float y, float z, float *adr1
x1 = fabsf(nor[0]);
y1 = fabsf(nor[1]);
z1 = fabsf(nor[2]);
-
+
if (z1>=x1 && z1>=y1) {
*adr1 = (x + 1.0f) / 2.0f;
*adr2 = (y + 1.0f) / 2.0f;
@@ -719,13 +719,13 @@ static void do_2d_mapping(
Tex *tex;
float fx, fy, fac1, area[8];
int ok, proj, areaflag= 0, wrap;
-
+
/* mtex variables localized, only cubemap doesn't cooperate yet... */
wrap= mtex->mapping;
tex= mtex->tex;
if (!(dxt && dyt)) {
-
+
if (wrap==MTEX_FLAT) {
fx = (texvec[0] + 1.0f) / 2.0f;
fy = (texvec[1] + 1.0f) / 2.0f;
@@ -735,15 +735,15 @@ static void do_2d_mapping(
else {
cubemap_glob(n, texvec[0], texvec[1], texvec[2], &fx, &fy);
}
-
+
/* repeat */
if (tex->extend==TEX_REPEAT) {
if (tex->xrepeat>1) {
float origf= fx *= tex->xrepeat;
-
+
if (fx>1.0f) fx -= (int)(fx);
else if (fx<0.0f) fx+= 1-(int)(fx);
-
+
if (tex->flag & TEX_REPEAT_XMIR) {
int orig= (int)floor(origf);
if (orig & 1)
@@ -752,10 +752,10 @@ static void do_2d_mapping(
}
if (tex->yrepeat>1) {
float origf= fy *= tex->yrepeat;
-
+
if (fy>1.0f) fy -= (int)(fy);
else if (fy<0.0f) fy+= 1-(int)(fy);
-
+
if (tex->flag & TEX_REPEAT_YMIR) {
int orig= (int)floor(origf);
if (orig & 1)
@@ -777,7 +777,7 @@ static void do_2d_mapping(
texvec[1]= fy;
}
else {
-
+
if (wrap==MTEX_FLAT) {
fx= (texvec[0] + 1.0f) / 2.0f;
fy= (texvec[1] + 1.0f) / 2.0f;
@@ -854,55 +854,55 @@ static void do_2d_mapping(
dyt[2] *= 0.5f;
}
-
+
/* if area, then reacalculate dxt[] and dyt[] */
if (areaflag) {
- fx= area[0];
+ fx= area[0];
fy= area[1];
dxt[0]= area[2]-fx;
dxt[1]= area[3]-fy;
dyt[0]= area[4]-fx;
dyt[1]= area[5]-fy;
}
-
+
/* repeat */
if (tex->extend==TEX_REPEAT) {
float max= 1.0f;
if (tex->xrepeat>1) {
float origf= fx *= tex->xrepeat;
-
+
/* TXF: omit mirror here, see comments in do_material_tex() after do_2d_mapping() call */
if (tex->texfilter == TXF_BOX) {
if (fx>1.0f) fx -= (int)(fx);
else if (fx<0.0f) fx+= 1-(int)(fx);
-
+
if (tex->flag & TEX_REPEAT_XMIR) {
int orig= (int)floor(origf);
if (orig & 1)
fx= 1.0f-fx;
}
}
-
+
max= tex->xrepeat;
-
+
dxt[0]*= tex->xrepeat;
dyt[0]*= tex->xrepeat;
}
if (tex->yrepeat>1) {
float origf= fy *= tex->yrepeat;
-
+
/* TXF: omit mirror here, see comments in do_material_tex() after do_2d_mapping() call */
if (tex->texfilter == TXF_BOX) {
if (fy>1.0f) fy -= (int)(fy);
else if (fy<0.0f) fy+= 1-(int)(fy);
-
+
if (tex->flag & TEX_REPEAT_YMIR) {
int orig= (int)floor(origf);
if (orig & 1)
fy= 1.0f-fy;
}
}
-
+
if (max<tex->yrepeat)
max= tex->yrepeat;
@@ -913,7 +913,7 @@ static void do_2d_mapping(
dxt[2]*= max;
dyt[2]*= max;
}
-
+
}
/* crop */
if (tex->cropxmin!=0.0f || tex->cropxmax!=1.0f) {
@@ -928,7 +928,7 @@ static void do_2d_mapping(
dxt[1]*= fac1;
dyt[1]*= fac1;
}
-
+
texvec[0]= fx;
texvec[1]= fy;
@@ -953,7 +953,7 @@ static int multitex(Tex *tex,
int retval = 0; /* return value, int:0, col:1, nor:2, everything:3 */
texres->talpha = false; /* is set when image texture returns alpha (considered premul) */
-
+
if (use_nodes && tex->use_nodes && tex->nodetree) {
const float cfra = 1.0f; /* This was only set for Blender Internal render before. */
retval = ntreeTexExecTree(tex->nodetree, texres, texvec, dxt, dyt, osatex, thread,
@@ -1072,7 +1072,7 @@ static int multitex_nodes_intern(Tex *tex,
if (mtex)
which_output= mtex->which_output;
-
+
if (tex->type==TEX_IMAGE) {
int rgbnor;
@@ -1093,7 +1093,7 @@ static int multitex_nodes_intern(Tex *tex,
if (mtex->mapto & (MAP_COL)) {
ImBuf *ibuf = BKE_image_pool_acquire_ibuf(tex->ima, &tex->iuser, pool);
-
+
/* don't linearize float buffers, assumed to be linear */
if (ibuf != NULL &&
ibuf->rect_float == NULL &&
@@ -1110,12 +1110,12 @@ static int multitex_nodes_intern(Tex *tex,
/* we don't have mtex, do default flat 2d projection */
MTex localmtex;
float texvec_l[3], dxt_l[3], dyt_l[3];
-
+
localmtex.mapping= MTEX_FLAT;
localmtex.tex= tex;
localmtex.object= NULL;
localmtex.texco= TEXCO_ORCO;
-
+
copy_v3_v3(texvec_l, texvec);
if (dxt && dyt) {
copy_v3_v3(dxt_l, dxt);
@@ -1125,7 +1125,7 @@ static int multitex_nodes_intern(Tex *tex,
zero_v3(dxt_l);
zero_v3(dyt_l);
}
-
+
do_2d_mapping(&localmtex, texvec_l, NULL, dxt_l, dyt_l);
rgbnor = multitex(tex,
texvec_l,
@@ -1244,7 +1244,7 @@ int multitex_ext_safe(Tex *tex, float texvec[3], TexResult *texres, struct Image
void texture_rgb_blend(float in[3], const float tex[3], const float out[3], float fact, float facg, int blendtype)
{
float facm;
-
+
switch (blendtype) {
case MTEX_BLEND:
fact*= facg;
@@ -1254,7 +1254,7 @@ void texture_rgb_blend(float in[3], const float tex[3], const float out[3], floa
in[1]= (fact*tex[1] + facm*out[1]);
in[2]= (fact*tex[2] + facm*out[2]);
break;
-
+
case MTEX_MUL:
fact*= facg;
facm= 1.0f-fact;
@@ -1274,7 +1274,7 @@ void texture_rgb_blend(float in[3], const float tex[3], const float out[3], floa
case MTEX_OVERLAY:
fact*= facg;
facm= 1.0f-fact;
-
+
if (out[0] < 0.5f)
in[0] = out[0] * (facm + 2.0f*fact*tex[0]);
else
@@ -1288,7 +1288,7 @@ void texture_rgb_blend(float in[3], const float tex[3], const float out[3], floa
else
in[2] = 1.0f - (facm + 2.0f*fact*(1.0f - tex[2])) * (1.0f - out[2]);
break;
-
+
case MTEX_SUB:
fact= -fact;
ATTR_FALLTHROUGH;
@@ -1302,7 +1302,7 @@ void texture_rgb_blend(float in[3], const float tex[3], const float out[3], floa
case MTEX_DIV:
fact*= facg;
facm= 1.0f-fact;
-
+
if (tex[0]!=0.0f)
in[0]= facm*out[0] + fact*out[0]/tex[0];
if (tex[1]!=0.0f)
@@ -1323,7 +1323,7 @@ void texture_rgb_blend(float in[3], const float tex[3], const float out[3], floa
case MTEX_DARK:
fact*= facg;
facm= 1.0f-fact;
-
+
in[0] = min_ff(out[0], tex[0])*fact + out[0]*facm;
in[1] = min_ff(out[1], tex[1])*fact + out[1]*facm;
in[2] = min_ff(out[2], tex[2])*fact + out[2]*facm;
@@ -1336,7 +1336,7 @@ void texture_rgb_blend(float in[3], const float tex[3], const float out[3], floa
in[1] = max_ff(fact * tex[1], out[1]);
in[2] = max_ff(fact * tex[2], out[2]);
break;
-
+
case MTEX_BLEND_HUE:
fact*= facg;
copy_v3_v3(in, out);
@@ -1357,16 +1357,16 @@ void texture_rgb_blend(float in[3], const float tex[3], const float out[3], floa
copy_v3_v3(in, out);
ramp_blend(MA_RAMP_COLOR, in, fact, tex);
break;
- case MTEX_SOFT_LIGHT:
- fact*= facg;
+ case MTEX_SOFT_LIGHT:
+ fact*= facg;
copy_v3_v3(in, out);
ramp_blend(MA_RAMP_SOFT, in, fact, tex);
- break;
- case MTEX_LIN_LIGHT:
- fact*= facg;
+ break;
+ case MTEX_LIN_LIGHT:
+ fact*= facg;
copy_v3_v3(in, out);
ramp_blend(MA_RAMP_LINEAR, in, fact, tex);
- break;
+ break;
}
}
@@ -1376,7 +1376,7 @@ float texture_value_blend(float tex, float out, float fact, float facg, int blen
int flip= (facg < 0.0f);
facg= fabsf(facg);
-
+
fact*= facg;
facm= 1.0f-fact;
if (flip) SWAP(float, fact, facm);
@@ -1429,19 +1429,19 @@ float texture_value_blend(float tex, float out, float fact, float facg, int blen
if (col > out) in= col; else in= out;
break;
- case MTEX_SOFT_LIGHT:
+ case MTEX_SOFT_LIGHT:
scf=1.0f - (1.0f - tex) * (1.0f - out);
in= facm*out + fact * ((1.0f - out) * tex * out) + (out * scf);
- break;
+ break;
- case MTEX_LIN_LIGHT:
+ case MTEX_LIN_LIGHT:
if (tex > 0.5f)
in = out + fact*(2.0f*(tex - 0.5f));
- else
+ else
in = out + fact*(2.0f*tex - 1.0f);
break;
}
-
+
return in;
}
@@ -1459,26 +1459,26 @@ int externtex(const MTex *mtex,
TexResult texr;
float dxt[3], dyt[3], texvec[3];
int rgb;
-
+
tex= mtex->tex;
if (tex==NULL) return 0;
texr.nor= NULL;
-
+
/* placement */
if (mtex->projx) texvec[0]= mtex->size[0]*(vec[mtex->projx-1]+mtex->ofs[0]);
else texvec[0]= mtex->size[0]*(mtex->ofs[0]);
-
+
if (mtex->projy) texvec[1]= mtex->size[1]*(vec[mtex->projy-1]+mtex->ofs[1]);
else texvec[1]= mtex->size[1]*(mtex->ofs[1]);
-
+
if (mtex->projz) texvec[2]= mtex->size[2]*(vec[mtex->projz-1]+mtex->ofs[2]);
else texvec[2]= mtex->size[2]*(mtex->ofs[2]);
-
+
/* texture */
if (tex->type==TEX_IMAGE) {
do_2d_mapping(mtex, texvec, NULL, dxt, dyt);
}
-
+
rgb = multitex(tex,
texvec,
dxt, dyt,
@@ -1489,7 +1489,7 @@ int externtex(const MTex *mtex,
skip_load_image,
texnode_preview,
true);
-
+
if (rgb) {
texr.tin = IMB_colormanagement_get_luminance(&texr.tr);
}
@@ -1498,7 +1498,7 @@ int externtex(const MTex *mtex,
texr.tg= mtex->g;
texr.tb= mtex->b;
}
-
+
*tin= texr.tin;
*tr= texr.tr;
*tg= texr.tg;
diff --git a/source/blender/render/intern/source/rendercore.c b/source/blender/render/intern/source/rendercore.c
new file mode 100644
index 00000000000..99d2436d4bc
--- /dev/null
+++ b/source/blender/render/intern/source/rendercore.c
@@ -0,0 +1,2030 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * Contributors: Hos, Robert Wenzlaff.
+ * Contributors: 2004/2005/2006 Blender Foundation, full recode
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/render/intern/source/rendercore.c
+ * \ingroup render
+ */
+
+
+/* system includes */
+#include <stdio.h>
+#include <math.h>
+#include <float.h>
+#include <string.h>
+#include <assert.h>
+
+/* External modules: */
+#include "MEM_guardedalloc.h"
+
+#include "BLI_math.h"
+#include "BLI_blenlib.h"
+#include "BLI_rand.h"
+#include "BLI_threads.h"
+#include "BLI_utildefines.h"
+
+#include "DNA_image_types.h"
+#include "DNA_lamp_types.h"
+#include "DNA_material_types.h"
+#include "DNA_group_types.h"
+
+/* local include */
+#include "renderpipeline.h"
+#include "render_result.h"
+#include "render_types.h"
+#include "renderdatabase.h"
+#include "occlusion.h"
+#include "pixelblending.h"
+#include "pixelshading.h"
+#include "shadbuf.h"
+#include "shading.h"
+#include "sss.h"
+#include "zbuf.h"
+
+/* own include */
+#include "rendercore.h"
+
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+/* defined in pipeline.c, is hardcopy of active dynamic allocated Render */
+/* only to be used here in this file, it's for speed */
+extern struct Render R;
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+/* x and y are current pixels in rect to be rendered */
+/* do not normalize! */
+void calc_view_vector(float view[3], float x, float y)
+{
+
+ view[2]= -ABS(R.clipsta);
+
+ if (R.r.mode & R_ORTHO) {
+ view[0]= view[1]= 0.0f;
+ }
+ else {
+
+ if (R.r.mode & R_PANORAMA) {
+ x-= R.panodxp;
+ }
+
+ /* move x and y to real viewplane coords */
+ x = (x / (float)R.winx);
+ view[0] = R.viewplane.xmin + x * BLI_rctf_size_x(&R.viewplane);
+
+ y = (y / (float)R.winy);
+ view[1] = R.viewplane.ymin + y * BLI_rctf_size_y(&R.viewplane);
+
+// if (R.flag & R_SEC_FIELD) {
+// if (R.r.mode & R_ODDFIELD) view[1]= (y+R.ystart)*R.ycor;
+// else view[1]= (y+R.ystart+1.0)*R.ycor;
+// }
+// else view[1]= (y+R.ystart+R.bluroffsy+0.5)*R.ycor;
+
+ if (R.r.mode & R_PANORAMA) {
+ float u= view[0] + R.panodxv; float v= view[2];
+ view[0]= R.panoco*u + R.panosi*v;
+ view[2]= -R.panosi*u + R.panoco*v;
+ }
+ }
+}
+
+void calc_renderco_ortho(float co[3], float x, float y, int z)
+{
+ /* x and y 3d coordinate can be derived from pixel coord and winmat */
+ float fx= 2.0f/(R.winx*R.winmat[0][0]);
+ float fy= 2.0f/(R.winy*R.winmat[1][1]);
+ float zco;
+
+ co[0]= (x - 0.5f*R.winx)*fx - R.winmat[3][0]/R.winmat[0][0];
+ co[1]= (y - 0.5f*R.winy)*fy - R.winmat[3][1]/R.winmat[1][1];
+
+ zco= ((float)z)/2147483647.0f;
+ co[2]= R.winmat[3][2]/( R.winmat[2][3]*zco - R.winmat[2][2] );
+}
+
+void calc_renderco_zbuf(float co[3], const float view[3], int z)
+{
+ float fac, zco;
+
+ /* inverse of zbuf calc: zbuf = MAXZ*hoco_z/hoco_w */
+ zco= ((float)z)/2147483647.0f;
+ co[2]= R.winmat[3][2]/( R.winmat[2][3]*zco - R.winmat[2][2] );
+
+ fac= co[2]/view[2];
+ co[0]= fac*view[0];
+ co[1]= fac*view[1];
+}
+
+/* also used in zbuf.c and shadbuf.c */
+int count_mask(unsigned short mask)
+{
+ if (R.samples)
+ return (R.samples->cmask[mask & 255]+R.samples->cmask[mask>>8]);
+ return 0;
+}
+
+static int calchalo_z(HaloRen *har, int zz)
+{
+
+ if (har->type & HA_ONLYSKY) {
+ if (zz < 0x7FFFFFF0) zz= - 0x7FFFFF; /* edge render messes zvalues */
+ }
+ else {
+ zz= (zz>>8);
+ }
+ return zz;
+}
+
+
+
+static void halo_pixelstruct(HaloRen *har, RenderLayer **rlpp, int totsample, int od, float dist, float xn, float yn, PixStr *ps)
+{
+ float col[4], accol[4], fac;
+ int amount, amountm, zz, flarec, sample, fullsample, mask=0;
+
+ fullsample= (totsample > 1);
+ amount= 0;
+ accol[0] = accol[1] = accol[2] = accol[3]= 0.0f;
+ col[0] = col[1] = col[2] = col[3]= 0.0f;
+ flarec= har->flarec;
+
+ while (ps) {
+ amountm= count_mask(ps->mask);
+ amount+= amountm;
+
+ zz= calchalo_z(har, ps->z);
+ if ((zz> har->zs) || (har->mat && (har->mat->mode & MA_HALO_SOFT))) {
+ if (shadeHaloFloat(har, col, zz, dist, xn, yn, flarec)) {
+ flarec= 0;
+
+ if (fullsample) {
+ for (sample=0; sample<totsample; sample++) {
+ if (ps->mask & (1 << sample)) {
+ float *pass = RE_RenderLayerGetPass(rlpp[sample], RE_PASSNAME_COMBINED, R.viewname);
+ addalphaAddfacFloat(pass + od*4, col, har->add);
+ }
+ }
+ }
+ else {
+ fac= ((float)amountm)/(float)R.osa;
+ accol[0]+= fac*col[0];
+ accol[1]+= fac*col[1];
+ accol[2]+= fac*col[2];
+ accol[3]+= fac*col[3];
+ }
+ }
+ }
+
+ mask |= ps->mask;
+ ps= ps->next;
+ }
+
+ /* now do the sky sub-pixels */
+ amount= R.osa-amount;
+ if (amount) {
+ if (shadeHaloFloat(har, col, 0x7FFFFF, dist, xn, yn, flarec)) {
+ if (!fullsample) {
+ fac= ((float)amount)/(float)R.osa;
+ accol[0]+= fac*col[0];
+ accol[1]+= fac*col[1];
+ accol[2]+= fac*col[2];
+ accol[3]+= fac*col[3];
+ }
+ }
+ }
+
+ if (fullsample) {
+ for (sample=0; sample<totsample; sample++) {
+ if (!(mask & (1 << sample))) {
+ float *pass = RE_RenderLayerGetPass(rlpp[sample], RE_PASSNAME_COMBINED, R.viewname);
+ addalphaAddfacFloat(pass + od*4, col, har->add);
+ }
+ }
+ }
+ else {
+ col[0]= accol[0];
+ col[1]= accol[1];
+ col[2]= accol[2];
+ col[3]= accol[3];
+
+ for (sample=0; sample<totsample; sample++) {
+ float *pass = RE_RenderLayerGetPass(rlpp[sample], RE_PASSNAME_COMBINED, R.viewname);
+ addalphaAddfacFloat(pass + od*4, col, har->add);
+ }
+ }
+}
+
+static void halo_tile(RenderPart *pa, RenderLayer *rl)
+{
+ RenderLayer *rlpp[RE_MAX_OSA];
+ HaloRen *har;
+ rcti disprect= pa->disprect, testrect= pa->disprect;
+ float dist, xsq, ysq, xn, yn;
+ float col[4];
+ intptr_t *rd= NULL;
+ int a, *rz, zz, y, sample, totsample, od;
+ short minx, maxx, miny, maxy, x;
+ unsigned int lay= rl->lay;
+
+ /* we don't render halos in the cropped area, gives errors in flare counter */
+ if (pa->crop) {
+ testrect.xmin+= pa->crop;
+ testrect.xmax-= pa->crop;
+ testrect.ymin+= pa->crop;
+ testrect.ymax-= pa->crop;
+ }
+
+ totsample= get_sample_layers(pa, rl, rlpp);
+
+ for (a=0; a<R.tothalo; a++) {
+ har= R.sortedhalos[a];
+
+ /* layer test, clip halo with y */
+ if ((har->lay & lay) == 0) {
+ /* pass */
+ }
+ else if (testrect.ymin > har->maxy) {
+ /* pass */
+ }
+ else if (testrect.ymax < har->miny) {
+ /* pass */
+ }
+ else {
+
+ minx= floor(har->xs-har->rad);
+ maxx= ceil(har->xs+har->rad);
+
+ if (testrect.xmin > maxx) {
+ /* pass */
+ }
+ else if (testrect.xmax < minx) {
+ /* pass */
+ }
+ else {
+
+ minx = max_ii(minx, testrect.xmin);
+ maxx = min_ii(maxx, testrect.xmax);
+
+ miny = max_ii(har->miny, testrect.ymin);
+ maxy = min_ii(har->maxy, testrect.ymax);
+
+ for (y=miny; y<maxy; y++) {
+ int rectofs= (y-disprect.ymin)*pa->rectx + (minx - disprect.xmin);
+ rz= pa->rectz + rectofs;
+ od= rectofs;
+
+ if (pa->rectdaps)
+ rd= pa->rectdaps + rectofs;
+
+ yn= (y-har->ys)*R.ycor;
+ ysq= yn*yn;
+
+ for (x=minx; x<maxx; x++, rz++, od++) {
+ xn= x- har->xs;
+ xsq= xn*xn;
+ dist= xsq+ysq;
+ if (dist<har->radsq) {
+ if (rd && *rd) {
+ halo_pixelstruct(har, rlpp, totsample, od, dist, xn, yn, (PixStr *)*rd);
+ }
+ else {
+ zz= calchalo_z(har, *rz);
+ if ((zz> har->zs) || (har->mat && (har->mat->mode & MA_HALO_SOFT))) {
+ if (shadeHaloFloat(har, col, zz, dist, xn, yn, har->flarec)) {
+ for (sample=0; sample<totsample; sample++) {
+ float * rect= RE_RenderLayerGetPass(rlpp[sample], RE_PASSNAME_COMBINED, R.viewname);
+ addalphaAddfacFloat(rect + od*4, col, har->add);
+ }
+ }
+ }
+ }
+ }
+ if (rd) rd++;
+ }
+ }
+ }
+ }
+ if (R.test_break(R.tbh) ) break;
+ }
+}
+
+static void lamphalo_tile(RenderPart *pa, RenderLayer *rl)
+{
+ RenderLayer *rlpp[RE_MAX_OSA];
+ ShadeInput shi;
+ float *pass;
+ float fac, col[4];
+ intptr_t *rd= pa->rectdaps;
+ const int *rz= pa->rectz;
+ int x, y, sample, totsample, fullsample, od;
+
+ totsample= get_sample_layers(pa, rl, rlpp);
+ fullsample= (totsample > 1);
+
+ shade_input_initialize(&shi, pa, rl, 0); /* this zero's ShadeInput for us */
+
+ for (od=0, y=pa->disprect.ymin; y<pa->disprect.ymax; y++) {
+ for (x=pa->disprect.xmin; x<pa->disprect.xmax; x++, rz++, od++) {
+
+ calc_view_vector(shi.view, x, y);
+
+ if (rd && *rd) {
+ PixStr *ps= (PixStr *)*rd;
+ int count, totsamp= 0, mask= 0;
+
+ while (ps) {
+ if (R.r.mode & R_ORTHO)
+ calc_renderco_ortho(shi.co, (float)x, (float)y, ps->z);
+ else
+ calc_renderco_zbuf(shi.co, shi.view, ps->z);
+
+ totsamp+= count= count_mask(ps->mask);
+ mask |= ps->mask;
+
+ col[0]= col[1]= col[2]= col[3]= 0.0f;
+ renderspothalo(&shi, col, 1.0f);
+
+ if (fullsample) {
+ for (sample=0; sample<totsample; sample++) {
+ if (ps->mask & (1 << sample)) {
+ pass = RE_RenderLayerGetPass(rlpp[sample], RE_PASSNAME_COMBINED, R.viewname);
+ pass += od * 4;
+ pass[0]+= col[0];
+ pass[1]+= col[1];
+ pass[2]+= col[2];
+ pass[3]+= col[3];
+ if (pass[3]>1.0f) pass[3]= 1.0f;
+ }
+ }
+ }
+ else {
+ fac= ((float)count)/(float)R.osa;
+ pass = RE_RenderLayerGetPass(rl, RE_PASSNAME_COMBINED, R.viewname);
+ pass += od * 4;
+ pass[0]+= fac*col[0];
+ pass[1]+= fac*col[1];
+ pass[2]+= fac*col[2];
+ pass[3]+= fac*col[3];
+ if (pass[3]>1.0f) pass[3]= 1.0f;
+ }
+
+ ps= ps->next;
+ }
+
+ if (totsamp<R.osa) {
+ shi.co[2]= 0.0f;
+
+ col[0]= col[1]= col[2]= col[3]= 0.0f;
+ renderspothalo(&shi, col, 1.0f);
+
+ if (fullsample) {
+ for (sample=0; sample<totsample; sample++) {
+ if (!(mask & (1 << sample))) {
+
+ pass = RE_RenderLayerGetPass(rlpp[sample], RE_PASSNAME_COMBINED, R.viewname);
+ pass += od * 4;
+ pass[0]+= col[0];
+ pass[1]+= col[1];
+ pass[2]+= col[2];
+ pass[3]+= col[3];
+ if (pass[3]>1.0f) pass[3]= 1.0f;
+ }
+ }
+ }
+ else {
+ fac= ((float)R.osa-totsamp)/(float)R.osa;
+ pass = RE_RenderLayerGetPass(rl, RE_PASSNAME_COMBINED, R.viewname);
+ pass += od * 4;
+ pass[0]+= fac*col[0];
+ pass[1]+= fac*col[1];
+ pass[2]+= fac*col[2];
+ pass[3]+= fac*col[3];
+ if (pass[3]>1.0f) pass[3]= 1.0f;
+ }
+ }
+ }
+ else {
+ if (R.r.mode & R_ORTHO)
+ calc_renderco_ortho(shi.co, (float)x, (float)y, *rz);
+ else
+ calc_renderco_zbuf(shi.co, shi.view, *rz);
+
+ col[0]= col[1]= col[2]= col[3]= 0.0f;
+ renderspothalo(&shi, col, 1.0f);
+
+ for (sample=0; sample<totsample; sample++) {
+ pass = RE_RenderLayerGetPass(rlpp[sample], RE_PASSNAME_COMBINED, R.viewname);
+ pass += od * 4;
+ pass[0]+= col[0];
+ pass[1]+= col[1];
+ pass[2]+= col[2];
+ pass[3]+= col[3];
+ if (pass[3]>1.0f) pass[3]= 1.0f;
+ }
+ }
+
+ if (rd) rd++;
+ }
+ if (y&1)
+ if (R.test_break(R.tbh)) break;
+ }
+}
+
+
+/* ********************* MAINLOOPS ******************** */
+
+/* osa version */
+static void add_filt_passes(RenderLayer *rl, int curmask, int rectx, int offset, ShadeInput *shi, ShadeResult *shr)
+{
+ RenderPass *rpass;
+
+ for (rpass= rl->passes.first; rpass; rpass= rpass->next) {
+ float *fp, *col= NULL;
+ int pixsize= 3;
+
+ if (STREQ(rpass->name, RE_PASSNAME_COMBINED)) {
+ add_filt_fmask(curmask, shr->combined, rpass->rect + 4*offset, rectx);
+ }
+ else if (STREQ(rpass->name, RE_PASSNAME_Z)) {
+ fp = rpass->rect + offset;
+ *fp = shr->z;
+ }
+ else if (STREQ(rpass->name, RE_PASSNAME_RGBA)) {
+ col = shr->col;
+ pixsize = 4;
+ }
+ else if (STREQ(rpass->name, RE_PASSNAME_EMIT)) {
+ col = shr->emit;
+ }
+ else if (STREQ(rpass->name, RE_PASSNAME_DIFFUSE)) {
+ col = shr->diff;
+ }
+ else if (STREQ(rpass->name, RE_PASSNAME_SPEC)) {
+ col = shr->spec;
+ }
+ else if (STREQ(rpass->name, RE_PASSNAME_SHADOW)) {
+ col = shr->shad;
+ }
+ else if (STREQ(rpass->name, RE_PASSNAME_AO)) {
+ col = shr->ao;
+ }
+ else if (STREQ(rpass->name, RE_PASSNAME_ENVIRONMENT)) {
+ col = shr->env;
+ }
+ else if (STREQ(rpass->name, RE_PASSNAME_INDIRECT)) {
+ col = shr->indirect;
+ }
+ else if (STREQ(rpass->name, RE_PASSNAME_REFLECT)) {
+ col = shr->refl;
+ }
+ else if (STREQ(rpass->name, RE_PASSNAME_REFRACT)) {
+ col = shr->refr;
+ }
+ else if (STREQ(rpass->name, RE_PASSNAME_NORMAL)) {
+ col = shr->nor;
+ }
+ else if (STREQ(rpass->name, RE_PASSNAME_UV)) {
+ /* box filter only, gauss will screwup UV too much */
+ if (shi->totuv) {
+ float mult = (float)count_mask(curmask)/(float)R.osa;
+ fp = rpass->rect + 3*offset;
+ fp[0]+= mult*(0.5f + 0.5f*shi->uv[shi->actuv].uv[0]);
+ fp[1]+= mult*(0.5f + 0.5f*shi->uv[shi->actuv].uv[1]);
+ fp[2]+= mult;
+ }
+ }
+ else if (STREQ(rpass->name, RE_PASSNAME_INDEXOB)) {
+ /* no filter */
+ if (shi->vlr) {
+ fp = rpass->rect + offset;
+ if (*fp==0.0f)
+ *fp = (float)shi->obr->ob->index;
+ }
+ }
+ else if (STREQ(rpass->name, RE_PASSNAME_INDEXMA)) {
+ /* no filter */
+ if (shi->vlr) {
+ fp = rpass->rect + offset;
+ if (*fp==0.0f)
+ *fp = (float)shi->mat->index;
+ }
+ }
+ else if (STREQ(rpass->name, RE_PASSNAME_MIST)) {
+ /* */
+ col = &shr->mist;
+ pixsize = 1;
+ }
+ else if (STREQ(rpass->name, RE_PASSNAME_VECTOR)) {
+ /* add minimum speed in pixel, no filter */
+ fp = rpass->rect + 4*offset;
+ if ( (ABS(shr->winspeed[0]) + ABS(shr->winspeed[1]))< (ABS(fp[0]) + ABS(fp[1])) ) {
+ fp[0] = shr->winspeed[0];
+ fp[1] = shr->winspeed[1];
+ }
+ if ( (ABS(shr->winspeed[2]) + ABS(shr->winspeed[3]))< (ABS(fp[2]) + ABS(fp[3])) ) {
+ fp[2] = shr->winspeed[2];
+ fp[3] = shr->winspeed[3];
+ }
+ }
+ else if (STREQ(rpass->name, RE_PASSNAME_RAYHITS)) {
+ /* */
+ col = shr->rayhits;
+ pixsize= 4;
+ }
+
+ if (col) {
+ fp= rpass->rect + pixsize*offset;
+ add_filt_fmask_pixsize(curmask, col, fp, rectx, pixsize);
+ }
+ }
+}
+
+/* non-osa version */
+static void add_passes(RenderLayer *rl, int offset, ShadeInput *shi, ShadeResult *shr)
+{
+ RenderPass *rpass;
+ float *fp;
+
+ for (rpass= rl->passes.first; rpass; rpass= rpass->next) {
+ float *col= NULL, uvcol[3];
+ int a, pixsize= 3;
+
+ if (STREQ(rpass->name, RE_PASSNAME_COMBINED)) {
+ /* copy combined to use for preview */
+ copy_v4_v4(rpass->rect + 4*offset, shr->combined);
+ }
+ else if (STREQ(rpass->name, RE_PASSNAME_Z)) {
+ fp = rpass->rect + offset;
+ *fp = shr->z;
+ }
+ else if (STREQ(rpass->name, RE_PASSNAME_RGBA)) {
+ col = shr->col;
+ pixsize = 4;
+ }
+ else if (STREQ(rpass->name, RE_PASSNAME_EMIT)) {
+ col = shr->emit;
+ }
+ else if (STREQ(rpass->name, RE_PASSNAME_DIFFUSE)) {
+ col = shr->diff;
+ }
+ else if (STREQ(rpass->name, RE_PASSNAME_SPEC)) {
+ col = shr->spec;
+ }
+ else if (STREQ(rpass->name, RE_PASSNAME_SHADOW)) {
+ col = shr->shad;
+ }
+ else if (STREQ(rpass->name, RE_PASSNAME_AO)) {
+ col = shr->ao;
+ }
+ else if (STREQ(rpass->name, RE_PASSNAME_ENVIRONMENT)) {
+ col = shr->env;
+ }
+ else if (STREQ(rpass->name, RE_PASSNAME_INDIRECT)) {
+ col = shr->indirect;
+ }
+ else if (STREQ(rpass->name, RE_PASSNAME_REFLECT)) {
+ col = shr->refl;
+ }
+ else if (STREQ(rpass->name, RE_PASSNAME_REFRACT)) {
+ col = shr->refr;
+ }
+ else if (STREQ(rpass->name, RE_PASSNAME_NORMAL)) {
+ col = shr->nor;
+ }
+ else if (STREQ(rpass->name, RE_PASSNAME_UV)) {
+ if (shi->totuv) {
+ uvcol[0] = 0.5f + 0.5f*shi->uv[shi->actuv].uv[0];
+ uvcol[1] = 0.5f + 0.5f*shi->uv[shi->actuv].uv[1];
+ uvcol[2] = 1.0f;
+ col = uvcol;
+ }
+ }
+ else if (STREQ(rpass->name, RE_PASSNAME_VECTOR)) {
+ col = shr->winspeed;
+ pixsize = 4;
+ }
+ else if (STREQ(rpass->name, RE_PASSNAME_INDEXOB)) {
+ if (shi->vlr) {
+ fp = rpass->rect + offset;
+ *fp = (float)shi->obr->ob->index;
+ }
+ }
+ else if (STREQ(rpass->name, RE_PASSNAME_INDEXMA)) {
+ if (shi->vlr) {
+ fp = rpass->rect + offset;
+ *fp = (float)shi->mat->index;
+ }
+ }
+ else if (STREQ(rpass->name, RE_PASSNAME_MIST)) {
+ fp = rpass->rect + offset;
+ *fp = shr->mist;
+ }
+ else if (STREQ(rpass->name, RE_PASSNAME_RAYHITS)) {
+ col = shr->rayhits;
+ pixsize = 4;
+ }
+
+ if (col) {
+ fp = rpass->rect + pixsize*offset;
+ for (a=0; a<pixsize; a++)
+ fp[a] = col[a];
+ }
+ }
+}
+
+int get_sample_layers(RenderPart *pa, RenderLayer *rl, RenderLayer **rlpp)
+{
+
+ if (pa->fullresult.first) {
+ int sample, nr= BLI_findindex(&pa->result->layers, rl);
+
+ for (sample=0; sample<R.osa; sample++) {
+ RenderResult *rr= BLI_findlink(&pa->fullresult, sample);
+
+ rlpp[sample]= BLI_findlink(&rr->layers, nr);
+ }
+ return R.osa;
+ }
+ else {
+ rlpp[0]= rl;
+ return 1;
+ }
+}
+
+
+/* only do sky, is default in the solid layer (shade_tile) btw */
+static void sky_tile(RenderPart *pa, RenderLayer *rl)
+{
+ RenderLayer *rlpp[RE_MAX_OSA];
+ int x, y, od=0, totsample;
+
+ if (R.r.alphamode!=R_ADDSKY)
+ return;
+
+ totsample= get_sample_layers(pa, rl, rlpp);
+
+ for (y=pa->disprect.ymin; y<pa->disprect.ymax; y++) {
+ for (x=pa->disprect.xmin; x<pa->disprect.xmax; x++, od+=4) {
+ float col[4];
+ int sample;
+ bool done = false;
+
+ for (sample= 0; sample<totsample; sample++) {
+ float *pass = RE_RenderLayerGetPass(rlpp[sample], RE_PASSNAME_COMBINED, R.viewname);
+ pass += od;
+
+ if (pass[3]<1.0f) {
+
+ if (done==0) {
+ shadeSkyPixel(col, x, y, pa->thread);
+ done = true;
+ }
+
+ if (pass[3]==0.0f) {
+ copy_v4_v4(pass, col);
+ pass[3] = 1.0f;
+ }
+ else {
+ addAlphaUnderFloat(pass, col);
+ pass[3] = 1.0f;
+ }
+ }
+ }
+ }
+
+ if (y&1)
+ if (R.test_break(R.tbh)) break;
+ }
+}
+
+static void atm_tile(RenderPart *pa, RenderLayer *rl)
+{
+ RenderPass *zpass;
+ GroupObject *go;
+ LampRen *lar;
+ RenderLayer *rlpp[RE_MAX_OSA];
+ int totsample;
+ int x, y, od= 0;
+
+ totsample= get_sample_layers(pa, rl, rlpp);
+
+ /* check that z pass is enabled */
+ if (pa->rectz==NULL) return;
+ for (zpass= rl->passes.first; zpass; zpass= zpass->next)
+ if (STREQ(zpass->name, RE_PASSNAME_Z))
+ break;
+
+ if (zpass==NULL) return;
+
+ /* check for at least one sun lamp that its atmosphere flag is enabled */
+ for (go=R.lights.first; go; go= go->next) {
+ lar= go->lampren;
+ if (lar->type==LA_SUN && lar->sunsky && (lar->sunsky->effect_type & LA_SUN_EFFECT_AP))
+ break;
+ }
+ /* do nothign and return if there is no sun lamp */
+ if (go==NULL)
+ return;
+
+ /* for each x,y and each sample, and each sun lamp*/
+ for (y=pa->disprect.ymin; y<pa->disprect.ymax; y++) {
+ for (x=pa->disprect.xmin; x<pa->disprect.xmax; x++, od++) {
+ int sample;
+
+ for (sample=0; sample<totsample; sample++) {
+ const float *zrect = RE_RenderLayerGetPass(rlpp[sample], RE_PASSNAME_Z, R.viewname) + od;
+ float *rgbrect = RE_RenderLayerGetPass(rlpp[sample], RE_PASSNAME_COMBINED, R.viewname) + 4*od;
+ float rgb[3] = {0};
+ bool done = false;
+
+ for (go=R.lights.first; go; go= go->next) {
+
+
+ lar= go->lampren;
+ if (lar->type==LA_SUN && lar->sunsky) {
+
+ /* if it's sky continue and don't apply atmosphere effect on it */
+ if (*zrect >= 9.9e10f || rgbrect[3]==0.0f) {
+ continue;
+ }
+
+ if ((lar->sunsky->effect_type & LA_SUN_EFFECT_AP)) {
+ float tmp_rgb[3];
+
+ /* skip if worldspace lamp vector is below horizon */
+ if (go->ob->obmat[2][2] < 0.f) {
+ continue;
+ }
+
+ copy_v3_v3(tmp_rgb, rgbrect);
+ if (rgbrect[3]!=1.0f) { /* de-premul */
+ mul_v3_fl(tmp_rgb, 1.0f/rgbrect[3]);
+ }
+ shadeAtmPixel(lar->sunsky, tmp_rgb, x, y, *zrect);
+ if (rgbrect[3]!=1.0f) { /* premul */
+ mul_v3_fl(tmp_rgb, rgbrect[3]);
+ }
+
+ if (done==0) {
+ copy_v3_v3(rgb, tmp_rgb);
+ done = true;
+ }
+ else {
+ rgb[0] = 0.5f*rgb[0] + 0.5f*tmp_rgb[0];
+ rgb[1] = 0.5f*rgb[1] + 0.5f*tmp_rgb[1];
+ rgb[2] = 0.5f*rgb[2] + 0.5f*tmp_rgb[2];
+ }
+ }
+ }
+ }
+
+ /* if at least for one sun lamp aerial perspective was applied*/
+ if (done) {
+ copy_v3_v3(rgbrect, rgb);
+ }
+ }
+ }
+ }
+}
+
+static void shadeDA_tile(RenderPart *pa, RenderLayer *rl)
+{
+ RenderResult *rr= pa->result;
+ ShadeSample ssamp;
+ intptr_t *rd, *rectdaps= pa->rectdaps;
+ int samp;
+ int x, y, seed, crop=0, offs=0, od;
+
+ if (R.test_break(R.tbh)) return;
+
+ /* irregular shadowb buffer creation */
+ if (R.r.mode & R_SHADOW)
+ ISB_create(pa, NULL);
+
+ /* we set per pixel a fixed seed, for random AO and shadow samples */
+ seed= pa->rectx*pa->disprect.ymin;
+
+ /* general shader info, passes */
+ shade_sample_initialize(&ssamp, pa, rl);
+
+ /* occlusion caching */
+ if (R.occlusiontree)
+ cache_occ_samples(&R, pa, &ssamp);
+
+ /* filtered render, for now we assume only 1 filter size */
+ if (pa->crop) {
+ crop= 1;
+ rectdaps+= pa->rectx + 1;
+ offs= pa->rectx + 1;
+ }
+
+ /* scanline updates have to be 2 lines behind */
+ rr->renrect.ymin = 0;
+ rr->renrect.ymax = -2*crop;
+ rr->renlay= rl;
+
+ for (y=pa->disprect.ymin+crop; y<pa->disprect.ymax-crop; y++, rr->renrect.ymax++) {
+ rd= rectdaps;
+ od= offs;
+
+ for (x=pa->disprect.xmin+crop; x<pa->disprect.xmax-crop; x++, rd++, od++) {
+ BLI_thread_srandom(pa->thread, seed++);
+
+ if (*rd) {
+ if (shade_samples(&ssamp, (PixStr *)(*rd), x, y)) {
+
+ /* multisample buffers or filtered mask filling? */
+ if (pa->fullresult.first) {
+ int a;
+ for (samp=0; samp<ssamp.tot; samp++) {
+ int smask= ssamp.shi[samp].mask;
+ for (a=0; a<R.osa; a++) {
+ int mask= 1<<a;
+ if (smask & mask)
+ add_passes(ssamp.rlpp[a], od, &ssamp.shi[samp], &ssamp.shr[samp]);
+ }
+ }
+ }
+ else {
+ for (samp=0; samp<ssamp.tot; samp++)
+ add_filt_passes(rl, ssamp.shi[samp].mask, pa->rectx, od, &ssamp.shi[samp], &ssamp.shr[samp]);
+ }
+ }
+ }
+ }
+
+ rectdaps+= pa->rectx;
+ offs+= pa->rectx;
+
+ if (y&1) if (R.test_break(R.tbh)) break;
+ }
+
+ /* disable scanline updating */
+ rr->renlay= NULL;
+
+ if (R.r.mode & R_SHADOW)
+ ISB_free(pa);
+
+ if (R.occlusiontree)
+ free_occ_samples(&R, pa);
+}
+
+/* ************* pixel struct ******** */
+
+
+static PixStrMain *addpsmain(ListBase *lb)
+{
+ PixStrMain *psm;
+
+ psm= (PixStrMain *)MEM_mallocN(sizeof(PixStrMain), "pixstrMain");
+ BLI_addtail(lb, psm);
+
+ psm->ps= (PixStr *)MEM_mallocN(4096*sizeof(PixStr), "pixstr");
+ psm->counter= 0;
+
+ return psm;
+}
+
+static void freeps(ListBase *lb)
+{
+ PixStrMain *psm, *psmnext;
+
+ for (psm= lb->first; psm; psm= psmnext) {
+ psmnext= psm->next;
+ if (psm->ps)
+ MEM_freeN(psm->ps);
+ MEM_freeN(psm);
+ }
+ BLI_listbase_clear(lb);
+}
+
+static void addps(ListBase *lb, intptr_t *rd, int obi, int facenr, int z, int maskz, unsigned short mask)
+{
+ PixStrMain *psm;
+ PixStr *ps, *last= NULL;
+
+ if (*rd) {
+ ps= (PixStr *)(*rd);
+
+ while (ps) {
+ if ( ps->obi == obi && ps->facenr == facenr ) {
+ ps->mask |= mask;
+ return;
+ }
+ last= ps;
+ ps= ps->next;
+ }
+ }
+
+ /* make new PS (pixel struct) */
+ psm= lb->last;
+
+ if (psm->counter==4095)
+ psm= addpsmain(lb);
+
+ ps= psm->ps + psm->counter++;
+
+ if (last) last->next= ps;
+ else *rd= (intptr_t)ps;
+
+ ps->next= NULL;
+ ps->obi= obi;
+ ps->facenr= facenr;
+ ps->z= z;
+ ps->maskz= maskz;
+ ps->mask = mask;
+ ps->shadfac= 0;
+}
+
+static void edge_enhance_add(RenderPart *pa, float *rectf, float *arect)
+{
+ float addcol[4];
+ int pix;
+
+ if (arect==NULL)
+ return;
+
+ for (pix= pa->rectx*pa->recty; pix>0; pix--, arect++, rectf+=4) {
+ if (*arect != 0.0f) {
+ addcol[0]= *arect * R.r.edgeR;
+ addcol[1]= *arect * R.r.edgeG;
+ addcol[2]= *arect * R.r.edgeB;
+ addcol[3]= *arect;
+ addAlphaOverFloat(rectf, addcol);
+ }
+ }
+}
+
+/* clamp alpha and RGB to 0..1 and 0..inf, can go outside due to filter */
+static void clamp_alpha_rgb_range(RenderPart *pa, RenderLayer *rl)
+{
+ RenderLayer *rlpp[RE_MAX_OSA];
+ int y, sample, totsample;
+
+ totsample= get_sample_layers(pa, rl, rlpp);
+
+ /* not for full sample, there we clamp after compositing */
+ if (totsample > 1)
+ return;
+
+ for (sample= 0; sample<totsample; sample++) {
+ float *rectf = RE_RenderLayerGetPass(rlpp[sample], RE_PASSNAME_COMBINED, R.viewname);
+
+ for (y= pa->rectx*pa->recty; y>0; y--, rectf+=4) {
+ rectf[0] = MAX2(rectf[0], 0.0f);
+ rectf[1] = MAX2(rectf[1], 0.0f);
+ rectf[2] = MAX2(rectf[2], 0.0f);
+ CLAMP(rectf[3], 0.0f, 1.0f);
+ }
+ }
+}
+
+/* adds only alpha values */
+static void edge_enhance_tile(RenderPart *pa, float *rectf, int *rectz)
+{
+ /* use zbuffer to define edges, add it to the image */
+ int y, x, col, *rz, *rz1, *rz2, *rz3;
+ int zval1, zval2, zval3;
+ float *rf;
+
+ /* shift values in zbuffer 4 to the right (anti overflows), for filter we need multiplying with 12 max */
+ rz= rectz;
+ if (rz==NULL) return;
+
+ for (y=0; y<pa->recty; y++)
+ for (x=0; x<pa->rectx; x++, rz++) (*rz)>>= 4;
+
+ rz1= rectz;
+ rz2= rz1+pa->rectx;
+ rz3= rz2+pa->rectx;
+
+ rf= rectf+pa->rectx+1;
+
+ for (y=0; y<pa->recty-2; y++) {
+ for (x=0; x<pa->rectx-2; x++, rz1++, rz2++, rz3++, rf++) {
+
+ /* prevent overflow with sky z values */
+ zval1= rz1[0] + 2*rz1[1] + rz1[2];
+ zval2= 2*rz2[0] + 2*rz2[2];
+ zval3= rz3[0] + 2*rz3[1] + rz3[2];
+
+ col= ( 4*rz2[1] - (zval1 + zval2 + zval3)/3 );
+ if (col<0) col= -col;
+
+ col >>= 5;
+ if (col > (1<<16)) col= (1<<16);
+ else col= (R.r.edgeint*col)>>8;
+
+ if (col>0) {
+ float fcol;
+
+ if (col>255) fcol= 1.0f;
+ else fcol= (float)col/255.0f;
+
+ if (R.osa)
+ *rf+= fcol/(float)R.osa;
+ else
+ *rf= fcol;
+ }
+ }
+ rz1+= 2;
+ rz2+= 2;
+ rz3+= 2;
+ rf+= 2;
+ }
+
+ /* shift back zbuf values, we might need it still */
+ rz= rectz;
+ for (y=0; y<pa->recty; y++)
+ for (x=0; x<pa->rectx; x++, rz++) (*rz)<<= 4;
+
+}
+
+static void reset_sky_speed(RenderPart *pa, RenderLayer *rl)
+{
+ /* for all pixels with max speed, set to zero */
+ RenderLayer *rlpp[RE_MAX_OSA];
+ float *fp;
+ int a, sample, totsample;
+
+ totsample= get_sample_layers(pa, rl, rlpp);
+
+ for (sample= 0; sample<totsample; sample++) {
+ fp= RE_RenderLayerGetPass(rlpp[sample], RE_PASSNAME_VECTOR, R.viewname);
+ if (fp==NULL) break;
+
+ for (a= 4*pa->rectx*pa->recty - 1; a>=0; a--)
+ if (fp[a] == PASS_VECTOR_MAX) fp[a]= 0.0f;
+ }
+}
+
+static unsigned short *make_solid_mask(RenderPart *pa)
+{
+ intptr_t *rd= pa->rectdaps;
+ unsigned short *solidmask, *sp;
+ int x;
+
+ if (rd==NULL) return NULL;
+
+ sp=solidmask= MEM_mallocN(sizeof(short)*pa->rectx*pa->recty, "solidmask");
+
+ for (x=pa->rectx*pa->recty; x>0; x--, rd++, sp++) {
+ if (*rd) {
+ PixStr *ps= (PixStr *)*rd;
+
+ *sp= ps->mask;
+ for (ps= ps->next; ps; ps= ps->next)
+ *sp |= ps->mask;
+ }
+ else
+ *sp= 0;
+ }
+
+ return solidmask;
+}
+
+static void addAlphaOverFloatMask(float *dest, float *source, unsigned short dmask, unsigned short smask)
+{
+ unsigned short shared= dmask & smask;
+ float mul= 1.0f - source[3];
+
+ if (shared) { /* overlapping masks */
+
+ /* masks differ, we make a mixture of 'add' and 'over' */
+ if (shared!=dmask) {
+ float shared_bits= (float)count_mask(shared); /* alpha over */
+ float tot_bits= (float)count_mask(smask|dmask); /* alpha add */
+
+ float add= (tot_bits - shared_bits)/tot_bits; /* add level */
+ mul= add + (1.0f-add)*mul;
+ }
+ }
+ else if (dmask && smask) {
+ /* works for premul only, of course */
+ dest[0]+= source[0];
+ dest[1]+= source[1];
+ dest[2]+= source[2];
+ dest[3]+= source[3];
+
+ return;
+ }
+
+ dest[0]= (mul*dest[0]) + source[0];
+ dest[1]= (mul*dest[1]) + source[1];
+ dest[2]= (mul*dest[2]) + source[2];
+ dest[3]= (mul*dest[3]) + source[3];
+}
+
+typedef struct ZbufSolidData {
+ RenderLayer *rl;
+ ListBase *psmlist;
+ float *edgerect;
+} ZbufSolidData;
+
+static void make_pixelstructs(RenderPart *pa, ZSpan *zspan, int sample, void *data)
+{
+ ZbufSolidData *sdata = (ZbufSolidData *)data;
+ ListBase *lb= sdata->psmlist;
+ intptr_t *rd= pa->rectdaps;
+ const int *ro= zspan->recto;
+ const int *rp= zspan->rectp;
+ const int *rz= zspan->rectz;
+ const int *rm= zspan->rectmask;
+ int x, y;
+ int mask= 1<<sample;
+
+ for (y=0; y<pa->recty; y++) {
+ for (x=0; x<pa->rectx; x++, rd++, rp++, ro++, rz++, rm++) {
+ if (*rp) {
+ addps(lb, rd, *ro, *rp, *rz, (zspan->rectmask)? *rm: 0, mask);
+ }
+ }
+ }
+
+ if (sdata->rl->layflag & SCE_LAY_EDGE)
+ if (R.r.mode & R_EDGE)
+ edge_enhance_tile(pa, sdata->edgerect, zspan->rectz);
+}
+
+/* main call for shading Delta Accum, for OSA */
+/* supposed to be fully threadable! */
+void zbufshadeDA_tile(RenderPart *pa)
+{
+ RenderResult *rr= pa->result;
+ RenderLayer *rl;
+ ListBase psmlist= {NULL, NULL};
+ float *edgerect= NULL;
+
+ /* allocate the necessary buffers */
+ /* zbuffer inits these rects */
+ pa->recto= MEM_mallocN(sizeof(int)*pa->rectx*pa->recty, "recto");
+ pa->rectp= MEM_mallocN(sizeof(int)*pa->rectx*pa->recty, "rectp");
+ pa->rectz= MEM_mallocN(sizeof(int)*pa->rectx*pa->recty, "rectz");
+ for (rl= rr->layers.first; rl; rl= rl->next) {
+ float *rect = RE_RenderLayerGetPass(rl, RE_PASSNAME_COMBINED, R.viewname);
+
+ if ((rl->layflag & SCE_LAY_ZMASK) && (rl->layflag & SCE_LAY_NEG_ZMASK))
+ pa->rectmask= MEM_mallocN(sizeof(int)*pa->rectx*pa->recty, "rectmask");
+
+ /* initialize pixelstructs and edge buffer */
+ addpsmain(&psmlist);
+ pa->rectdaps= MEM_callocN(sizeof(intptr_t)*pa->rectx*pa->recty+4, "zbufDArectd");
+
+ if (rl->layflag & SCE_LAY_EDGE)
+ if (R.r.mode & R_EDGE)
+ edgerect= MEM_callocN(sizeof(float)*pa->rectx*pa->recty, "rectedge");
+
+ /* always fill visibility */
+ for (pa->sample=0; pa->sample<R.osa; pa->sample+=4) {
+ ZbufSolidData sdata;
+
+ sdata.rl= rl;
+ sdata.psmlist= &psmlist;
+ sdata.edgerect= edgerect;
+ zbuffer_solid(pa, rl, make_pixelstructs, &sdata);
+ if (R.test_break(R.tbh)) break;
+ }
+
+ /* shades solid */
+ if (rl->layflag & SCE_LAY_SOLID)
+ shadeDA_tile(pa, rl);
+
+ /* lamphalo after solid, before ztra, looks nicest because ztra does own halo */
+ if (R.flag & R_LAMPHALO)
+ if (rl->layflag & SCE_LAY_HALO)
+ lamphalo_tile(pa, rl);
+
+ /* halo before ztra, because ztra fills in zbuffer now */
+ if (R.flag & R_HALO)
+ if (rl->layflag & SCE_LAY_HALO)
+ halo_tile(pa, rl);
+
+ /* transp layer */
+ if (R.flag & R_ZTRA || R.totstrand) {
+ if (rl->layflag & (SCE_LAY_ZTRA|SCE_LAY_STRAND)) {
+ if (pa->fullresult.first) {
+ zbuffer_transp_shade(pa, rl, rect, &psmlist);
+ }
+ else {
+ unsigned short *ztramask, *solidmask= NULL; /* 16 bits, MAX_OSA */
+
+ /* allocate, but not free here, for asynchronous display of this rect in main thread */
+ rl->acolrect= MEM_callocN(4*sizeof(float)*pa->rectx*pa->recty, "alpha layer");
+
+ /* swap for live updates, and it is used in zbuf.c!!! */
+ SWAP(float *, rl->acolrect, rect);
+ ztramask = zbuffer_transp_shade(pa, rl, rect, &psmlist);
+ SWAP(float *, rl->acolrect, rect);
+
+ /* zbuffer transp only returns ztramask if there's solid rendered */
+ if (ztramask)
+ solidmask= make_solid_mask(pa);
+
+ if (ztramask && solidmask) {
+ unsigned short *sps= solidmask, *spz= ztramask;
+ unsigned short fullmask= (1<<R.osa)-1;
+ float *fcol= rect;
+ float *acol= rl->acolrect;
+ int x;
+
+ for (x=pa->rectx*pa->recty; x>0; x--, acol+=4, fcol+=4, sps++, spz++) {
+ if (*sps == fullmask)
+ addAlphaOverFloat(fcol, acol);
+ else
+ addAlphaOverFloatMask(fcol, acol, *sps, *spz);
+ }
+ }
+ else {
+ float *fcol= rect;
+ float *acol= rl->acolrect;
+ int x;
+ for (x=pa->rectx*pa->recty; x>0; x--, acol+=4, fcol+=4) {
+ addAlphaOverFloat(fcol, acol);
+ }
+ }
+ if (solidmask) MEM_freeN(solidmask);
+ if (ztramask) MEM_freeN(ztramask);
+ }
+ }
+ }
+
+ /* sun/sky */
+ if (rl->layflag & SCE_LAY_SKY)
+ atm_tile(pa, rl);
+
+ /* sky before edge */
+ if (rl->layflag & SCE_LAY_SKY)
+ sky_tile(pa, rl);
+
+ /* extra layers */
+ if (rl->layflag & SCE_LAY_EDGE)
+ if (R.r.mode & R_EDGE)
+ edge_enhance_add(pa, rect, edgerect);
+
+ if (rl->passflag & SCE_PASS_VECTOR)
+ reset_sky_speed(pa, rl);
+
+ /* clamp alpha to 0..1 range, can go outside due to filter */
+ clamp_alpha_rgb_range(pa, rl);
+
+ /* free stuff within loop! */
+ MEM_freeN(pa->rectdaps); pa->rectdaps= NULL;
+ freeps(&psmlist);
+
+ if (edgerect) MEM_freeN(edgerect);
+ edgerect= NULL;
+
+ if (pa->rectmask) {
+ MEM_freeN(pa->rectmask);
+ pa->rectmask= NULL;
+ }
+ }
+
+ /* free all */
+ MEM_freeN(pa->recto); pa->recto= NULL;
+ MEM_freeN(pa->rectp); pa->rectp= NULL;
+ MEM_freeN(pa->rectz); pa->rectz= NULL;
+
+ /* display active layer */
+ rr->renrect.ymin=rr->renrect.ymax = 0;
+ rr->renlay= render_get_active_layer(&R, rr);
+}
+
+
+/* ------------------------------------------------------------------------ */
+
+/* non OSA case, full tile render */
+/* supposed to be fully threadable! */
+void zbufshade_tile(RenderPart *pa)
+{
+ ShadeSample ssamp;
+ RenderResult *rr= pa->result;
+ RenderLayer *rl;
+ PixStr ps;
+ float *edgerect= NULL;
+
+ /* fake pixel struct, to comply to osa render */
+ ps.next= NULL;
+ ps.mask= 0xFFFF;
+
+ /* zbuffer code clears/inits rects */
+ pa->recto= MEM_mallocN(sizeof(int)*pa->rectx*pa->recty, "recto");
+ pa->rectp= MEM_mallocN(sizeof(int)*pa->rectx*pa->recty, "rectp");
+ pa->rectz= MEM_mallocN(sizeof(int)*pa->rectx*pa->recty, "rectz");
+
+ for (rl= rr->layers.first; rl; rl= rl->next) {
+ float *rect= RE_RenderLayerGetPass(rl, RE_PASSNAME_COMBINED, R.viewname);
+ if ((rl->layflag & SCE_LAY_ZMASK) && (rl->layflag & SCE_LAY_NEG_ZMASK))
+ pa->rectmask= MEM_mallocN(sizeof(int)*pa->rectx*pa->recty, "rectmask");
+
+ /* general shader info, passes */
+ shade_sample_initialize(&ssamp, pa, rl);
+
+ zbuffer_solid(pa, rl, NULL, NULL);
+
+ if (!R.test_break(R.tbh)) { /* NOTE: this if () is not consistent */
+
+ /* edges only for solid part, ztransp doesn't support it yet anti-aliased */
+ if (rl->layflag & SCE_LAY_EDGE) {
+ if (R.r.mode & R_EDGE) {
+ edgerect= MEM_callocN(sizeof(float)*pa->rectx*pa->recty, "rectedge");
+ edge_enhance_tile(pa, edgerect, pa->rectz);
+ }
+ }
+
+ /* initialize scanline updates for main thread */
+ rr->renrect.ymin = 0;
+ rr->renlay= rl;
+
+ if (rl->layflag & SCE_LAY_SOLID) {
+ const float *fcol = rect;
+ const int *ro= pa->recto, *rp= pa->rectp, *rz= pa->rectz;
+ int x, y, offs=0, seed;
+
+ /* we set per pixel a fixed seed, for random AO and shadow samples */
+ seed= pa->rectx*pa->disprect.ymin;
+
+ /* irregular shadowb buffer creation */
+ if (R.r.mode & R_SHADOW)
+ ISB_create(pa, NULL);
+
+ if (R.occlusiontree)
+ cache_occ_samples(&R, pa, &ssamp);
+
+ for (y=pa->disprect.ymin; y<pa->disprect.ymax; y++, rr->renrect.ymax++) {
+ for (x=pa->disprect.xmin; x<pa->disprect.xmax; x++, ro++, rz++, rp++, fcol+=4, offs++) {
+ /* per pixel fixed seed */
+ BLI_thread_srandom(pa->thread, seed++);
+
+ if (*rp) {
+ ps.obi= *ro;
+ ps.facenr= *rp;
+ ps.z= *rz;
+ if (shade_samples(&ssamp, &ps, x, y)) {
+ /* combined and passes */
+ add_passes(rl, offs, ssamp.shi, ssamp.shr);
+ }
+ }
+ }
+ if (y&1)
+ if (R.test_break(R.tbh)) break;
+ }
+
+ if (R.occlusiontree)
+ free_occ_samples(&R, pa);
+
+ if (R.r.mode & R_SHADOW)
+ ISB_free(pa);
+ }
+
+ /* disable scanline updating */
+ rr->renlay= NULL;
+ }
+
+ /* lamphalo after solid, before ztra, looks nicest because ztra does own halo */
+ if (R.flag & R_LAMPHALO)
+ if (rl->layflag & SCE_LAY_HALO)
+ lamphalo_tile(pa, rl);
+
+ /* halo before ztra, because ztra fills in zbuffer now */
+ if (R.flag & R_HALO)
+ if (rl->layflag & SCE_LAY_HALO)
+ halo_tile(pa, rl);
+
+ if (R.flag & R_ZTRA || R.totstrand) {
+ if (rl->layflag & (SCE_LAY_ZTRA|SCE_LAY_STRAND)) {
+ float *fcol, *acol;
+ int x;
+
+ /* allocate, but not free here, for asynchronous display of this rect in main thread */
+ rl->acolrect= MEM_callocN(4*sizeof(float)*pa->rectx*pa->recty, "alpha layer");
+
+ /* swap for live updates */
+ SWAP(float *, rl->acolrect, rect);
+ zbuffer_transp_shade(pa, rl, rect, NULL);
+ SWAP(float *, rl->acolrect, rect);
+
+ fcol= rect; acol= rl->acolrect;
+ for (x=pa->rectx*pa->recty; x>0; x--, acol+=4, fcol+=4) {
+ addAlphaOverFloat(fcol, acol);
+ }
+ }
+ }
+
+ /* sun/sky */
+ if (rl->layflag & SCE_LAY_SKY)
+ atm_tile(pa, rl);
+
+ /* sky before edge */
+ if (rl->layflag & SCE_LAY_SKY)
+ sky_tile(pa, rl);
+
+ if (!R.test_break(R.tbh)) {
+ if (rl->layflag & SCE_LAY_EDGE)
+ if (R.r.mode & R_EDGE)
+ edge_enhance_add(pa, rect, edgerect);
+ }
+
+ if (rl->passflag & SCE_PASS_VECTOR)
+ reset_sky_speed(pa, rl);
+
+ if (edgerect) MEM_freeN(edgerect);
+ edgerect= NULL;
+
+ if (pa->rectmask) {
+ MEM_freeN(pa->rectmask);
+ pa->rectmask= NULL;
+ }
+ }
+
+ /* display active layer */
+ rr->renrect.ymin=rr->renrect.ymax = 0;
+ rr->renlay= render_get_active_layer(&R, rr);
+
+ MEM_freeN(pa->recto); pa->recto= NULL;
+ MEM_freeN(pa->rectp); pa->rectp= NULL;
+ MEM_freeN(pa->rectz); pa->rectz= NULL;
+}
+
+/* SSS preprocess tile render, fully threadable */
+typedef struct ZBufSSSHandle {
+ RenderPart *pa;
+ ListBase psmlist;
+ int totps;
+} ZBufSSSHandle;
+
+static void addps_sss(void *cb_handle, int obi, int facenr, int x, int y, int z)
+{
+ ZBufSSSHandle *handle = cb_handle;
+ RenderPart *pa= handle->pa;
+
+ /* extra border for filter gives double samples on part edges,
+ * don't use those */
+ if (x<pa->crop || x>=pa->rectx-pa->crop)
+ return;
+ if (y<pa->crop || y>=pa->recty-pa->crop)
+ return;
+
+ if (pa->rectall) {
+ intptr_t *rs= pa->rectall + pa->rectx*y + x;
+
+ addps(&handle->psmlist, rs, obi, facenr, z, 0, 0);
+ handle->totps++;
+ }
+ if (pa->rectz) {
+ int *rz= pa->rectz + pa->rectx*y + x;
+ int *rp= pa->rectp + pa->rectx*y + x;
+ int *ro= pa->recto + pa->rectx*y + x;
+
+ if (z < *rz) {
+ if (*rp == 0)
+ handle->totps++;
+ *rz= z;
+ *rp= facenr;
+ *ro= obi;
+ }
+ }
+ if (pa->rectbackz) {
+ int *rz= pa->rectbackz + pa->rectx*y + x;
+ int *rp= pa->rectbackp + pa->rectx*y + x;
+ int *ro= pa->rectbacko + pa->rectx*y + x;
+
+ if (z >= *rz) {
+ if (*rp == 0)
+ handle->totps++;
+ *rz= z;
+ *rp= facenr;
+ *ro= obi;
+ }
+ }
+}
+
+static void shade_sample_sss(ShadeSample *ssamp, Material *mat, ObjectInstanceRen *obi, VlakRen *vlr, int quad, float x, float y, float z, float *co, float color[3], float *area)
+{
+ ShadeInput *shi= ssamp->shi;
+ ShadeResult shr;
+ float /* texfac,*/ /* UNUSED */ orthoarea, nor[3], alpha, sx, sy;
+
+ /* cache for shadow */
+ shi->samplenr= R.shadowsamplenr[shi->thread]++;
+
+ if (quad)
+ shade_input_set_triangle_i(shi, obi, vlr, 0, 2, 3);
+ else
+ shade_input_set_triangle_i(shi, obi, vlr, 0, 1, 2);
+
+ /* center pixel */
+ sx = x + 0.5f;
+ sy = y + 0.5f;
+
+ /* we estimate the area here using shi->dxco and shi->dyco. we need to
+ * enabled shi->osatex these are filled. we compute two areas, one with
+ * the normal pointed at the camera and one with the original normal, and
+ * then clamp to avoid a too large contribution from a single pixel */
+ shi->osatex= 1;
+
+ copy_v3_v3(nor, shi->facenor);
+ calc_view_vector(shi->facenor, sx, sy);
+ normalize_v3(shi->facenor);
+ shade_input_set_viewco(shi, x, y, sx, sy, z);
+ orthoarea= len_v3(shi->dxco)*len_v3(shi->dyco);
+
+ copy_v3_v3(shi->facenor, nor);
+ shade_input_set_viewco(shi, x, y, sx, sy, z);
+ *area = min_ff(len_v3(shi->dxco) * len_v3(shi->dyco), 2.0f * orthoarea);
+
+ shade_input_set_uv(shi);
+ shade_input_set_normals(shi);
+
+ /* we don't want flipped normals, they screw up back scattering */
+ if (shi->flippednor)
+ shade_input_flip_normals(shi);
+
+ /* not a pretty solution, but fixes common cases */
+ if (shi->obr->ob && shi->obr->ob->transflag & OB_NEG_SCALE) {
+ negate_v3(shi->vn);
+ negate_v3(shi->vno);
+ negate_v3(shi->nmapnorm);
+ }
+
+ /* if nodetree, use the material that we are currently preprocessing
+ * instead of the node material */
+ if (shi->mat->nodetree && shi->mat->use_nodes)
+ shi->mat= mat;
+
+ /* init material vars */
+ shade_input_init_material(shi);
+
+ /* render */
+ shade_input_set_shade_texco(shi);
+
+ shade_samples_do_AO(ssamp);
+ shade_material_loop(shi, &shr);
+
+ copy_v3_v3(co, shi->co);
+ copy_v3_v3(color, shr.combined);
+
+ /* texture blending */
+ /* texfac= shi->mat->sss_texfac; */ /* UNUSED */
+
+ alpha= shr.combined[3];
+ *area *= alpha;
+}
+
+static void zbufshade_sss_free(RenderPart *pa)
+{
+#if 0
+ MEM_freeN(pa->rectall); pa->rectall= NULL;
+ freeps(&handle.psmlist);
+#else
+ MEM_freeN(pa->rectz); pa->rectz= NULL;
+ MEM_freeN(pa->rectp); pa->rectp= NULL;
+ MEM_freeN(pa->recto); pa->recto= NULL;
+ MEM_freeN(pa->rectbackz); pa->rectbackz= NULL;
+ MEM_freeN(pa->rectbackp); pa->rectbackp= NULL;
+ MEM_freeN(pa->rectbacko); pa->rectbacko= NULL;
+#endif
+}
+
+void zbufshade_sss_tile(RenderPart *pa)
+{
+ Render *re= &R;
+ ShadeSample ssamp;
+ ZBufSSSHandle handle;
+ RenderResult *rr= pa->result;
+ RenderLayer *rl;
+ VlakRen *vlr;
+ Material *mat= re->sss_mat;
+ float (*co)[3], (*color)[3], *area, *fcol;
+ int x, y, seed, quad, totpoint;
+ const bool display = (re->r.scemode & (R_BUTS_PREVIEW | R_VIEWPORT_PREVIEW)) == 0;
+ int *ro, *rz, *rp, *rbo, *rbz, *rbp, lay;
+#if 0
+ PixStr *ps;
+ intptr_t *rs;
+ int z;
+#endif
+
+ /* setup pixelstr list and buffer for zbuffering */
+ handle.pa= pa;
+ handle.totps= 0;
+
+#if 0
+ handle.psmlist.first= handle.psmlist.last= NULL;
+ addpsmain(&handle.psmlist);
+
+ pa->rectall= MEM_callocN(sizeof(intptr_t)*pa->rectx*pa->recty+4, "rectall");
+#else
+ pa->recto= MEM_mallocN(sizeof(int)*pa->rectx*pa->recty, "recto");
+ pa->rectp= MEM_mallocN(sizeof(int)*pa->rectx*pa->recty, "rectp");
+ pa->rectz= MEM_mallocN(sizeof(int)*pa->rectx*pa->recty, "rectz");
+ pa->rectbacko= MEM_mallocN(sizeof(int)*pa->rectx*pa->recty, "rectbacko");
+ pa->rectbackp= MEM_mallocN(sizeof(int)*pa->rectx*pa->recty, "rectbackp");
+ pa->rectbackz= MEM_mallocN(sizeof(int)*pa->rectx*pa->recty, "rectbackz");
+#endif
+
+ /* setup shade sample with correct passes */
+ memset(&ssamp, 0, sizeof(ssamp));
+ shade_sample_initialize(&ssamp, pa, rr->layers.first);
+ ssamp.tot= 1;
+
+ for (rl=rr->layers.first; rl; rl=rl->next) {
+ ssamp.shi[0].lay |= rl->lay;
+ ssamp.shi[0].layflag |= rl->layflag;
+ ssamp.shi[0].passflag |= rl->passflag;
+ ssamp.shi[0].combinedflag |= ~rl->pass_xor;
+ }
+
+ rl= rr->layers.first;
+ ssamp.shi[0].passflag |= SCE_PASS_RGBA|SCE_PASS_COMBINED;
+ ssamp.shi[0].combinedflag &= ~(SCE_PASS_SPEC);
+ ssamp.shi[0].mat_override= NULL;
+ ssamp.shi[0].light_override= NULL;
+ lay= ssamp.shi[0].lay;
+
+ /* create the pixelstrs to be used later */
+ zbuffer_sss(pa, lay, &handle, addps_sss);
+
+ if (handle.totps==0) {
+ zbufshade_sss_free(pa);
+ return;
+ }
+
+ fcol= RE_RenderLayerGetPass(rl, RE_PASSNAME_COMBINED, R.viewname);
+
+ co= MEM_mallocN(sizeof(float)*3*handle.totps, "SSSCo");
+ color= MEM_mallocN(sizeof(float)*3*handle.totps, "SSSColor");
+ area= MEM_mallocN(sizeof(float)*handle.totps, "SSSArea");
+
+#if 0
+ /* create ISB (does not work currently!) */
+ if (re->r.mode & R_SHADOW)
+ ISB_create(pa, NULL);
+#endif
+
+ if (display) {
+ /* initialize scanline updates for main thread */
+ rr->renrect.ymin = 0;
+ rr->renlay= rl;
+ }
+
+ seed= pa->rectx*pa->disprect.ymin;
+#if 0
+ rs= pa->rectall;
+#else
+ rz= pa->rectz;
+ rp= pa->rectp;
+ ro= pa->recto;
+ rbz= pa->rectbackz;
+ rbp= pa->rectbackp;
+ rbo= pa->rectbacko;
+#endif
+ totpoint= 0;
+
+ for (y=pa->disprect.ymin; y<pa->disprect.ymax; y++, rr->renrect.ymax++) {
+ for (x=pa->disprect.xmin; x<pa->disprect.xmax; x++, fcol+=4) {
+ /* per pixel fixed seed */
+ BLI_thread_srandom(pa->thread, seed++);
+
+#if 0
+ if (rs) {
+ /* for each sample in this pixel, shade it */
+ for (ps = (PixStr *)(*rs); ps; ps=ps->next) {
+ ObjectInstanceRen *obi= &re->objectinstance[ps->obi];
+ ObjectRen *obr= obi->obr;
+ vlr= RE_findOrAddVlak(obr, (ps->facenr-1) & RE_QUAD_MASK);
+ quad= (ps->facenr & RE_QUAD_OFFS);
+ z= ps->z;
+
+ shade_sample_sss(&ssamp, mat, obi, vlr, quad, x, y, z,
+ co[totpoint], color[totpoint], &area[totpoint]);
+
+ totpoint++;
+
+ add_v3_v3(fcol, color);
+ fcol[3]= 1.0f;
+ }
+
+ rs++;
+ }
+#else
+ if (rp) {
+ if (*rp != 0) {
+ ObjectInstanceRen *obi= &re->objectinstance[*ro];
+ ObjectRen *obr= obi->obr;
+
+ /* shade front */
+ vlr= RE_findOrAddVlak(obr, (*rp-1) & RE_QUAD_MASK);
+ quad= ((*rp) & RE_QUAD_OFFS);
+
+ shade_sample_sss(&ssamp, mat, obi, vlr, quad, x, y, *rz,
+ co[totpoint], color[totpoint], &area[totpoint]);
+
+ add_v3_v3(fcol, color[totpoint]);
+ fcol[3]= 1.0f;
+ totpoint++;
+ }
+
+ rp++; rz++; ro++;
+ }
+
+ if (rbp) {
+ if (*rbp != 0 && !(*rbp == *(rp-1) && *rbo == *(ro-1))) {
+ ObjectInstanceRen *obi= &re->objectinstance[*rbo];
+ ObjectRen *obr= obi->obr;
+
+ /* shade back */
+ vlr= RE_findOrAddVlak(obr, (*rbp-1) & RE_QUAD_MASK);
+ quad= ((*rbp) & RE_QUAD_OFFS);
+
+ shade_sample_sss(&ssamp, mat, obi, vlr, quad, x, y, *rbz,
+ co[totpoint], color[totpoint], &area[totpoint]);
+
+ /* to indicate this is a back sample */
+ area[totpoint]= -area[totpoint];
+
+ add_v3_v3(fcol, color[totpoint]);
+ fcol[3]= 1.0f;
+ totpoint++;
+ }
+
+ rbz++; rbp++; rbo++;
+ }
+#endif
+ }
+
+ if (y&1)
+ if (re->test_break(re->tbh)) break;
+ }
+
+ /* note: after adding we do not free these arrays, sss keeps them */
+ if (totpoint > 0) {
+ sss_add_points(re, co, color, area, totpoint);
+ }
+ else {
+ MEM_freeN(co);
+ MEM_freeN(color);
+ MEM_freeN(area);
+ }
+
+#if 0
+ if (re->r.mode & R_SHADOW)
+ ISB_free(pa);
+#endif
+
+ if (display) {
+ /* display active layer */
+ rr->renrect.ymin=rr->renrect.ymax = 0;
+ rr->renlay= render_get_active_layer(&R, rr);
+ }
+
+ zbufshade_sss_free(pa);
+}
+
+/* ------------------------------------------------------------------------ */
+
+static void renderhalo_post(RenderResult *rr, float *rectf, HaloRen *har) /* postprocess version */
+{
+ float dist, xsq, ysq, xn, yn, colf[4], *rectft, *rtf;
+ float haloxs, haloys;
+ int minx, maxx, miny, maxy, x, y;
+
+ /* calculate the disprect mapped coordinate for halo. note: rectx is disprect corrected */
+ haloxs= har->xs - R.disprect.xmin;
+ haloys= har->ys - R.disprect.ymin;
+
+ har->miny= miny= haloys - har->rad/R.ycor;
+ har->maxy= maxy= haloys + har->rad/R.ycor;
+
+ if (maxy < 0) {
+ /* pass */
+ }
+ else if (rr->recty < miny) {
+ /* pass */
+ }
+ else {
+ minx = floor(haloxs - har->rad);
+ maxx = ceil(haloxs + har->rad);
+
+ if (maxx < 0) {
+ /* pass */
+ }
+ else if (rr->rectx < minx) {
+ /* pass */
+ }
+ else {
+ if (minx<0) minx= 0;
+ if (maxx>=rr->rectx) maxx= rr->rectx-1;
+ if (miny<0) miny= 0;
+ if (maxy>rr->recty) maxy= rr->recty;
+
+ rectft= rectf+ 4*rr->rectx*miny;
+
+ for (y=miny; y<maxy; y++) {
+
+ rtf= rectft+4*minx;
+
+ yn= (y - haloys)*R.ycor;
+ ysq= yn*yn;
+
+ for (x=minx; x<=maxx; x++) {
+ xn= x - haloxs;
+ xsq= xn*xn;
+ dist= xsq+ysq;
+ if (dist<har->radsq) {
+
+ if (shadeHaloFloat(har, colf, 0x7FFFFF, dist, xn, yn, har->flarec))
+ addalphaAddfacFloat(rtf, colf, har->add);
+ }
+ rtf+=4;
+ }
+
+ rectft+= 4*rr->rectx;
+
+ if (R.test_break(R.tbh)) break;
+ }
+ }
+ }
+}
+/* ------------------------------------------------------------------------ */
+
+static void renderflare(RenderResult *rr, float *rectf, HaloRen *har)
+{
+ extern const float hashvectf[];
+ HaloRen fla;
+ Material *ma;
+ const float *rc;
+ float rad, alfa, visifac, vec[3];
+ int b, type;
+
+ fla= *har;
+ fla.linec= fla.ringc= fla.flarec= 0;
+
+ rad= har->rad;
+ alfa= har->alfa;
+
+ visifac= R.ycor*(har->pixels);
+ /* all radials added / r^3 == 1.0f! */
+ visifac /= (har->rad*har->rad*har->rad);
+ visifac*= visifac;
+
+ ma= har->mat;
+
+ /* first halo: just do */
+
+ har->rad= rad*ma->flaresize*visifac;
+ har->radsq= har->rad*har->rad;
+ har->zs= fla.zs= 0;
+
+ har->alfa= alfa*visifac;
+
+ renderhalo_post(rr, rectf, har);
+
+ /* next halo's: the flares */
+ rc= hashvectf + ma->seed2;
+
+ for (b=1; b<har->flarec; b++) {
+
+ fla.r = fabsf(rc[0]);
+ fla.g = fabsf(rc[1]);
+ fla.b = fabsf(rc[2]);
+ fla.alfa= ma->flareboost*fabsf(alfa*visifac*rc[3]);
+ fla.hard= 20.0f + fabsf(70.0f*rc[7]);
+ fla.tex= 0;
+
+ type= (int)(fabsf(3.9f*rc[6]));
+
+ fla.rad = ma->subsize * sqrtf(fabsf(2.0f * har->rad * rc[4]));
+
+ if (type==3) {
+ fla.rad*= 3.0f;
+ fla.rad+= R.rectx/10;
+ }
+
+ fla.radsq= fla.rad*fla.rad;
+
+ vec[0]= 1.4f*rc[5]*(har->xs-R.winx/2);
+ vec[1]= 1.4f*rc[5]*(har->ys-R.winy/2);
+ vec[2]= 32.0f*sqrtf(vec[0]*vec[0] + vec[1]*vec[1] + 1.0f);
+
+ fla.xs= R.winx/2 + vec[0] + (1.2f+rc[8])*R.rectx*vec[0]/vec[2];
+ fla.ys= R.winy/2 + vec[1] + (1.2f+rc[8])*R.rectx*vec[1]/vec[2];
+
+ if (R.flag & R_SEC_FIELD) {
+ if (R.r.mode & R_ODDFIELD) fla.ys += 0.5f;
+ else fla.ys -= 0.5f;
+ }
+ if (type & 1) fla.type= HA_FLARECIRC;
+ else fla.type= 0;
+ renderhalo_post(rr, rectf, &fla);
+
+ fla.alfa*= 0.5f;
+ if (type & 2) fla.type= HA_FLARECIRC;
+ else fla.type= 0;
+ renderhalo_post(rr, rectf, &fla);
+
+ rc+= 7;
+ }
+}
+
+/* needs recode... integrate this better! */
+void add_halo_flare(Render *re)
+{
+ RenderResult *rr= re->result;
+ RenderLayer *rl;
+ HaloRen *har;
+ int a, mode;
+ float *rect;
+
+ /* for now, we get the first renderlayer in list with halos set */
+ for (rl= rr->layers.first; rl; rl= rl->next) {
+ bool do_draw = false;
+
+ if ((rl->layflag & SCE_LAY_HALO) == 0)
+ continue;
+
+ rect = RE_RenderLayerGetPass(rl, RE_PASSNAME_COMBINED, re->viewname);
+
+ if (rect==NULL)
+ continue;
+
+ mode= R.r.mode;
+ R.r.mode &= ~R_PANORAMA;
+
+ project_renderdata(&R, projectverto, 0, 0, 0);
+
+ for (a=0; a<R.tothalo; a++) {
+ har= R.sortedhalos[a];
+
+ if (har->flarec && (har->lay & rl->lay)) {
+ do_draw = true;
+ renderflare(rr, rect, har);
+ }
+ }
+
+ if (do_draw) {
+ /* weak... the display callback wants an active renderlayer pointer... */
+ rr->renlay= rl;
+ re->display_update(re->duh, rr, NULL);
+ }
+
+ R.r.mode= mode;
+ }
+}
+
+void render_internal_update_passes(RenderEngine *engine, Scene *scene, SceneRenderLayer *srl)
+{
+ int type;
+
+ RE_engine_register_pass(engine, scene, srl, RE_PASSNAME_COMBINED, 4, "RGBA", SOCK_RGBA);
+
+#define CHECK_PASS(name, channels, chanid) \
+ if (srl->passflag & (SCE_PASS_ ## name)) { \
+ if (channels == 4) type = SOCK_RGBA; \
+ else if (channels == 3) type = SOCK_VECTOR; \
+ else type = SOCK_FLOAT; \
+ RE_engine_register_pass(engine, scene, srl, RE_PASSNAME_ ## name, channels, chanid, type); \
+ }
+
+ CHECK_PASS(Z, 1, "Z");
+ CHECK_PASS(VECTOR, 4, "XYZW");
+ CHECK_PASS(NORMAL, 3, "XYZ");
+ CHECK_PASS(UV, 3, "UVA");
+ CHECK_PASS(RGBA, 4, "RGBA");
+ CHECK_PASS(EMIT, 3, "RGB");
+ CHECK_PASS(DIFFUSE, 3, "RGB");
+ CHECK_PASS(SPEC, 3, "RGB");
+ CHECK_PASS(AO, 3, "RGB");
+ CHECK_PASS(ENVIRONMENT, 3, "RGB");
+ CHECK_PASS(INDIRECT, 3, "RGB");
+ CHECK_PASS(SHADOW, 3, "RGB");
+ CHECK_PASS(REFLECT, 3, "RGB");
+ CHECK_PASS(REFRACT, 3, "RGB");
+ CHECK_PASS(INDEXOB, 1, "X");
+ CHECK_PASS(INDEXMA, 1, "X");
+ CHECK_PASS(MIST, 1, "Z");
+
+#undef CHECK_PASS
+}
diff --git a/source/blender/render/intern/source/renderdatabase.c b/source/blender/render/intern/source/renderdatabase.c
new file mode 100644
index 00000000000..67bfd1bfdc7
--- /dev/null
+++ b/source/blender/render/intern/source/renderdatabase.c
@@ -0,0 +1,1603 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * Contributor(s): 2004-2006, Blender Foundation, full recode
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+/** \file blender/render/intern/source/renderdatabase.c
+ * \ingroup render
+ */
+
+
+/*
+ * Storage, retrieval and query of render specific data.
+ *
+ * All data from a Blender scene is converted by the renderconverter/
+ * into a special format that is used by the render module to make
+ * images out of. These functions interface to the render-specific
+ * database.
+ *
+ * The blo{ha/ve/vl} arrays store pointers to blocks of 256 data
+ * entries each.
+ *
+ * The index of an entry is >>8 (the highest 24 * bits), to find an
+ * offset in a 256-entry block.
+ *
+ * - If the 256-entry block entry has an entry in the
+ * vertnodes/vlaknodes/bloha array of the current block, the i-th entry in
+ * that block is allocated to this entry.
+ *
+ * - If the entry has no block allocated for it yet, memory is
+ * allocated.
+ *
+ * The pointer to the correct entry is returned. Memory is guaranteed
+ * to exist (as long as the malloc does not break). Since guarded
+ * allocation is used, memory _must_ be available. Otherwise, an
+ * exit(0) would occur.
+ *
+ */
+
+#include <limits.h>
+#include <math.h>
+#include <string.h>
+
+#include "MEM_guardedalloc.h"
+
+
+#include "BLI_math.h"
+#include "BLI_blenlib.h"
+#include "BLI_utildefines.h"
+#include "BLI_hash.h"
+
+#include "DNA_material_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_texture_types.h"
+#include "DNA_listBase.h"
+#include "DNA_particle_types.h"
+
+#include "BKE_customdata.h"
+#include "BKE_DerivedMesh.h"
+
+#include "RE_render_ext.h" /* externtex */
+
+#include "rayintersection.h"
+#include "rayobject.h"
+#include "render_types.h"
+#include "renderdatabase.h"
+#include "zbuf.h"
+
+/* ------------------------------------------------------------------------- */
+
+/* More dynamic allocation of options for render vertices and faces, so we don't
+ * have to reserve this space inside vertices.
+ * Important; vertices and faces, should have been created already (to get tables
+ * checked) that's a reason why the calls demand VertRen/VlakRen * as arg, not
+ * the index */
+
+/* NOTE! the hardcoded table size 256 is used still in code for going quickly over vertices/faces */
+#define RE_STRESS_ELEMS 1
+#define RE_RAD_ELEMS 4
+#define RE_STRAND_ELEMS 1
+#define RE_TANGENT_ELEMS 3
+#define RE_WINSPEED_ELEMS 4
+#define RE_MTFACE_ELEMS 1
+#define RE_MCOL_ELEMS 4
+#define RE_UV_ELEMS 2
+#define RE_VLAK_ORIGINDEX_ELEMS 1
+#define RE_VERT_ORIGINDEX_ELEMS 1
+#define RE_SURFNOR_ELEMS 3
+#define RE_RADFACE_ELEMS 1
+#define RE_SIMPLIFY_ELEMS 2
+#define RE_FACE_ELEMS 1
+#define RE_NMAP_TANGENT_ELEMS 16
+
+float *RE_vertren_get_stress(ObjectRen *obr, VertRen *ver, int verify)
+{
+ float *stress;
+ int nr= ver->index>>8;
+
+ stress= obr->vertnodes[nr].stress;
+ if (stress==NULL) {
+ if (verify)
+ stress= obr->vertnodes[nr].stress= MEM_mallocN(256*RE_STRESS_ELEMS*sizeof(float), "stress table");
+ else
+ return NULL;
+ }
+ return stress + (ver->index & 255)*RE_STRESS_ELEMS;
+}
+
+/* this one callocs! */
+float *RE_vertren_get_rad(ObjectRen *obr, VertRen *ver, int verify)
+{
+ float *rad;
+ int nr= ver->index>>8;
+
+ rad= obr->vertnodes[nr].rad;
+ if (rad==NULL) {
+ if (verify)
+ rad= obr->vertnodes[nr].rad= MEM_callocN(256*RE_RAD_ELEMS*sizeof(float), "rad table");
+ else
+ return NULL;
+ }
+ return rad + (ver->index & 255)*RE_RAD_ELEMS;
+}
+
+float *RE_vertren_get_strand(ObjectRen *obr, VertRen *ver, int verify)
+{
+ float *strand;
+ int nr= ver->index>>8;
+
+ strand= obr->vertnodes[nr].strand;
+ if (strand==NULL) {
+ if (verify)
+ strand= obr->vertnodes[nr].strand= MEM_mallocN(256*RE_STRAND_ELEMS*sizeof(float), "strand table");
+ else
+ return NULL;
+ }
+ return strand + (ver->index & 255)*RE_STRAND_ELEMS;
+}
+
+/* needs calloc */
+float *RE_vertren_get_tangent(ObjectRen *obr, VertRen *ver, int verify)
+{
+ float *tangent;
+ int nr= ver->index>>8;
+
+ tangent= obr->vertnodes[nr].tangent;
+ if (tangent==NULL) {
+ if (verify)
+ tangent= obr->vertnodes[nr].tangent= MEM_callocN(256*RE_TANGENT_ELEMS*sizeof(float), "tangent table");
+ else
+ return NULL;
+ }
+ return tangent + (ver->index & 255)*RE_TANGENT_ELEMS;
+}
+
+/* needs calloc! not all renderverts have them */
+/* also winspeed is exception, it is stored per instance */
+float *RE_vertren_get_winspeed(ObjectInstanceRen *obi, VertRen *ver, int verify)
+{
+ float *winspeed;
+ int totvector;
+
+ winspeed= obi->vectors;
+ if (winspeed==NULL) {
+ if (verify) {
+ totvector= obi->obr->totvert + obi->obr->totstrand;
+ winspeed= obi->vectors= MEM_callocN(totvector*RE_WINSPEED_ELEMS*sizeof(float), "winspeed table");
+ }
+ else
+ return NULL;
+ }
+ return winspeed + ver->index*RE_WINSPEED_ELEMS;
+}
+
+int *RE_vertren_get_origindex(ObjectRen *obr, VertRen *ver, int verify)
+{
+ int *origindex;
+ int nr= ver->index>>8;
+
+ origindex= obr->vertnodes[nr].origindex;
+ if (origindex==NULL) {
+ if (verify)
+ origindex= obr->vertnodes[nr].origindex= MEM_mallocN(256*RE_VERT_ORIGINDEX_ELEMS*sizeof(int), "origindex table");
+ else
+ return NULL;
+ }
+ return origindex + (ver->index & 255)*RE_VERT_ORIGINDEX_ELEMS;
+}
+
+VertRen *RE_vertren_copy(ObjectRen *obr, VertRen *ver)
+{
+ VertRen *v1= RE_findOrAddVert(obr, obr->totvert++);
+ float *fp1, *fp2;
+ int *int1, *int2;
+ int index= v1->index;
+
+ *v1= *ver;
+ v1->index= index;
+
+ fp1= RE_vertren_get_stress(obr, ver, 0);
+ if (fp1) {
+ fp2= RE_vertren_get_stress(obr, v1, 1);
+ memcpy(fp2, fp1, RE_STRESS_ELEMS*sizeof(float));
+ }
+ fp1= RE_vertren_get_rad(obr, ver, 0);
+ if (fp1) {
+ fp2= RE_vertren_get_rad(obr, v1, 1);
+ memcpy(fp2, fp1, RE_RAD_ELEMS*sizeof(float));
+ }
+ fp1= RE_vertren_get_strand(obr, ver, 0);
+ if (fp1) {
+ fp2= RE_vertren_get_strand(obr, v1, 1);
+ memcpy(fp2, fp1, RE_STRAND_ELEMS*sizeof(float));
+ }
+ fp1= RE_vertren_get_tangent(obr, ver, 0);
+ if (fp1) {
+ fp2= RE_vertren_get_tangent(obr, v1, 1);
+ memcpy(fp2, fp1, RE_TANGENT_ELEMS*sizeof(float));
+ }
+ int1= RE_vertren_get_origindex(obr, ver, 0);
+ if (int1) {
+ int2= RE_vertren_get_origindex(obr, v1, 1);
+ memcpy(int2, int1, RE_VERT_ORIGINDEX_ELEMS*sizeof(int));
+ }
+ return v1;
+}
+
+VertRen *RE_findOrAddVert(ObjectRen *obr, int nr)
+{
+ VertTableNode *temp;
+ VertRen *v;
+ int a;
+
+ if (nr<0) {
+ printf("error in findOrAddVert: %d\n", nr);
+ return NULL;
+ }
+ a= nr>>8;
+
+ if (a>=obr->vertnodeslen-1) { /* Need to allocate more columns..., and keep last element NULL for free loop */
+ temp= obr->vertnodes;
+
+ obr->vertnodes= MEM_mallocN(sizeof(VertTableNode)*(obr->vertnodeslen+TABLEINITSIZE), "vertnodes");
+ if (temp) memcpy(obr->vertnodes, temp, obr->vertnodeslen*sizeof(VertTableNode));
+ memset(obr->vertnodes+obr->vertnodeslen, 0, TABLEINITSIZE*sizeof(VertTableNode));
+
+ obr->vertnodeslen+=TABLEINITSIZE;
+ if (temp) MEM_freeN(temp);
+ }
+
+ v= obr->vertnodes[a].vert;
+ if (v==NULL) {
+ int i;
+
+ v= (VertRen *)MEM_callocN(256*sizeof(VertRen), "findOrAddVert");
+ obr->vertnodes[a].vert= v;
+
+ for (i= (nr & 0xFFFFFF00), a=0; a<256; a++, i++) {
+ v[a].index= i;
+ }
+ }
+ v+= (nr & 255);
+ return v;
+}
+
+/* ------------------------------------------------------------------------ */
+
+MTFace *RE_vlakren_get_tface(ObjectRen *obr, VlakRen *vlr, int n, char **name, int verify)
+{
+ VlakTableNode *node;
+ int nr= vlr->index>>8, vlakindex= (vlr->index&255);
+ int index= (n<<8) + vlakindex;
+
+ node= &obr->vlaknodes[nr];
+
+ if (verify) {
+ if (n>=node->totmtface) {
+ MTFace *mtface= node->mtface;
+ int size= (n+1)*256;
+
+ node->mtface= MEM_callocN(size*sizeof(MTFace), "Vlak mtface");
+
+ if (mtface) {
+ size= node->totmtface*256;
+ memcpy(node->mtface, mtface, size*sizeof(MTFace));
+ MEM_freeN(mtface);
+ }
+
+ node->totmtface= n+1;
+ }
+ }
+ else {
+ if (n>=node->totmtface)
+ return NULL;
+
+ if (name) *name= obr->mtface[n];
+ }
+
+ return node->mtface + index;
+}
+
+MCol *RE_vlakren_get_mcol(ObjectRen *obr, VlakRen *vlr, int n, char **name, int verify)
+{
+ VlakTableNode *node;
+ int nr= vlr->index>>8, vlakindex= (vlr->index&255);
+ int index= (n<<8) + vlakindex;
+
+ node= &obr->vlaknodes[nr];
+
+ if (verify) {
+ if (n>=node->totmcol) {
+ MCol *mcol= node->mcol;
+ int size= (n+1)*256;
+
+ node->mcol= MEM_callocN(size*sizeof(MCol)*RE_MCOL_ELEMS, "Vlak mcol");
+
+ if (mcol) {
+ size= node->totmcol*256;
+ memcpy(node->mcol, mcol, size*sizeof(MCol)*RE_MCOL_ELEMS);
+ MEM_freeN(mcol);
+ }
+
+ node->totmcol= n+1;
+ }
+ }
+ else {
+ if (n>=node->totmcol)
+ return NULL;
+
+ if (name) *name= obr->mcol[n];
+ }
+
+ return node->mcol + index*RE_MCOL_ELEMS;
+}
+
+int *RE_vlakren_get_origindex(ObjectRen *obr, VlakRen *vlak, int verify)
+{
+ int *origindex;
+ int nr= vlak->index>>8;
+
+ origindex= obr->vlaknodes[nr].origindex;
+ if (origindex==NULL) {
+ if (verify)
+ origindex= obr->vlaknodes[nr].origindex= MEM_callocN(256*RE_VLAK_ORIGINDEX_ELEMS*sizeof(int), "origindex table");
+ else
+ return NULL;
+ }
+ return origindex + (vlak->index & 255)*RE_VLAK_ORIGINDEX_ELEMS;
+}
+
+float *RE_vlakren_get_surfnor(ObjectRen *obr, VlakRen *vlak, int verify)
+{
+ float *surfnor;
+ int nr= vlak->index>>8;
+
+ surfnor= obr->vlaknodes[nr].surfnor;
+ if (surfnor==NULL) {
+ if (verify)
+ surfnor= obr->vlaknodes[nr].surfnor= MEM_callocN(256*RE_SURFNOR_ELEMS*sizeof(float), "surfnor table");
+ else
+ return NULL;
+ }
+ return surfnor + (vlak->index & 255)*RE_SURFNOR_ELEMS;
+}
+
+float *RE_vlakren_get_nmap_tangent(ObjectRen *obr, VlakRen *vlak, int index, bool verify)
+{
+ float **tangents;
+ int nr= vlak->index>>8;
+
+ tangents = obr->vlaknodes[nr].tangent_arrays;
+
+ if (index + 1 > 8) {
+ return NULL;
+ }
+
+ index = index < 0 ? 0: index;
+
+ if (tangents[index] == NULL) {
+ if (verify) {
+ tangents[index] = MEM_callocN(256*RE_NMAP_TANGENT_ELEMS*sizeof(float), "tangent table");
+ }
+ else
+ return NULL;
+ }
+
+ return tangents[index] + (vlak->index & 255)*RE_NMAP_TANGENT_ELEMS;
+}
+
+RadFace **RE_vlakren_get_radface(ObjectRen *obr, VlakRen *vlak, int verify)
+{
+ RadFace **radface;
+ int nr= vlak->index>>8;
+
+ radface= obr->vlaknodes[nr].radface;
+ if (radface==NULL) {
+ if (verify)
+ radface = obr->vlaknodes[nr].radface= MEM_callocN(256 * RE_RADFACE_ELEMS * sizeof(void *), "radface table");
+ else
+ return NULL;
+ }
+ return radface + (vlak->index & 255)*RE_RADFACE_ELEMS;
+}
+
+VlakRen *RE_vlakren_copy(ObjectRen *obr, VlakRen *vlr)
+{
+ VlakRen *vlr1 = RE_findOrAddVlak(obr, obr->totvlak++);
+ MTFace *mtface, *mtface1;
+ MCol *mcol, *mcol1;
+ float *surfnor, *surfnor1;
+ float *tangent, *tangent1;
+ int *origindex, *origindex1;
+ RadFace **radface, **radface1;
+ int i, index = vlr1->index;
+ char *name;
+
+ *vlr1= *vlr;
+ vlr1->index= index;
+
+ for (i=0; (mtface=RE_vlakren_get_tface(obr, vlr, i, &name, 0)) != NULL; i++) {
+ mtface1= RE_vlakren_get_tface(obr, vlr1, i, &name, 1);
+ memcpy(mtface1, mtface, sizeof(MTFace)*RE_MTFACE_ELEMS);
+ }
+
+ for (i=0; (mcol=RE_vlakren_get_mcol(obr, vlr, i, &name, 0)) != NULL; i++) {
+ mcol1= RE_vlakren_get_mcol(obr, vlr1, i, &name, 1);
+ memcpy(mcol1, mcol, sizeof(MCol)*RE_MCOL_ELEMS);
+ }
+
+ origindex= RE_vlakren_get_origindex(obr, vlr, 0);
+ if (origindex) {
+ origindex1= RE_vlakren_get_origindex(obr, vlr1, 1);
+ /* Just an int, but memcpy for consistency. */
+ memcpy(origindex1, origindex, sizeof(int)*RE_VLAK_ORIGINDEX_ELEMS);
+ }
+
+ surfnor= RE_vlakren_get_surfnor(obr, vlr, 0);
+ if (surfnor) {
+ surfnor1= RE_vlakren_get_surfnor(obr, vlr1, 1);
+ copy_v3_v3(surfnor1, surfnor);
+ }
+
+ for (i=0; i < MAX_MTFACE; i++) {
+ tangent = RE_vlakren_get_nmap_tangent(obr, vlr, i, false);
+ if (!tangent)
+ continue;
+ tangent1 = RE_vlakren_get_nmap_tangent(obr, vlr1, i, true);
+ memcpy(tangent1, tangent, sizeof(float)*RE_NMAP_TANGENT_ELEMS);
+ }
+
+ radface= RE_vlakren_get_radface(obr, vlr, 0);
+ if (radface) {
+ radface1= RE_vlakren_get_radface(obr, vlr1, 1);
+ *radface1= *radface;
+ }
+
+ return vlr1;
+}
+
+void RE_vlakren_get_normal(Render *UNUSED(re), ObjectInstanceRen *obi, VlakRen *vlr, float r_nor[3])
+{
+ float (*nmat)[3]= obi->nmat;
+
+ if (obi->flag & R_TRANSFORMED) {
+ mul_v3_m3v3(r_nor, nmat, vlr->n);
+ normalize_v3(r_nor);
+ }
+ else {
+ copy_v3_v3(r_nor, vlr->n);
+ }
+}
+
+void RE_set_customdata_names(ObjectRen *obr, CustomData *data)
+{
+ /* CustomData layer names are stored per object here, because the
+ * DerivedMesh which stores the layers is freed */
+
+ CustomDataLayer *layer;
+ int numtf = 0, numcol = 0, i, mtfn, mcn;
+
+ if (CustomData_has_layer(data, CD_MTFACE)) {
+ numtf= CustomData_number_of_layers(data, CD_MTFACE);
+ obr->mtface= MEM_callocN(sizeof(*obr->mtface)*numtf, "mtfacenames");
+ }
+
+ if (CustomData_has_layer(data, CD_MCOL)) {
+ numcol= CustomData_number_of_layers(data, CD_MCOL);
+ obr->mcol= MEM_callocN(sizeof(*obr->mcol)*numcol, "mcolnames");
+ }
+
+ for (i=0, mtfn=0, mcn=0; i < data->totlayer; i++) {
+ layer= &data->layers[i];
+
+ if (layer->type == CD_MTFACE) {
+ BLI_strncpy(obr->mtface[mtfn++], layer->name, sizeof(layer->name));
+ obr->actmtface= CLAMPIS(layer->active_rnd, 0, numtf);
+ obr->bakemtface= layer->active;
+ }
+ else if (layer->type == CD_MCOL) {
+ BLI_strncpy(obr->mcol[mcn++], layer->name, sizeof(layer->name));
+ obr->actmcol= CLAMPIS(layer->active_rnd, 0, numcol);
+ }
+ }
+}
+
+VlakRen *RE_findOrAddVlak(ObjectRen *obr, int nr)
+{
+ VlakTableNode *temp;
+ VlakRen *v;
+ int a;
+
+ if (nr<0) {
+ printf("error in findOrAddVlak: %d\n", nr);
+ return obr->vlaknodes[0].vlak;
+ }
+ a= nr>>8;
+
+ if (a>=obr->vlaknodeslen-1) { /* Need to allocate more columns..., and keep last element NULL for free loop */
+ temp= obr->vlaknodes;
+
+ obr->vlaknodes= MEM_mallocN(sizeof(VlakTableNode)*(obr->vlaknodeslen+TABLEINITSIZE), "vlaknodes");
+ if (temp) memcpy(obr->vlaknodes, temp, obr->vlaknodeslen*sizeof(VlakTableNode));
+ memset(obr->vlaknodes+obr->vlaknodeslen, 0, TABLEINITSIZE*sizeof(VlakTableNode));
+
+ obr->vlaknodeslen+=TABLEINITSIZE; /*Does this really need to be power of 2?*/
+ if (temp) MEM_freeN(temp);
+ }
+
+ v= obr->vlaknodes[a].vlak;
+
+ if (v==NULL) {
+ int i;
+
+ v= (VlakRen *)MEM_callocN(256*sizeof(VlakRen), "findOrAddVlak");
+ obr->vlaknodes[a].vlak= v;
+
+ for (i= (nr & 0xFFFFFF00), a=0; a<256; a++, i++)
+ v[a].index= i;
+ }
+ v+= (nr & 255);
+ return v;
+}
+
+/* ------------------------------------------------------------------------ */
+
+float *RE_strandren_get_surfnor(ObjectRen *obr, StrandRen *strand, int verify)
+{
+ float *surfnor;
+ int nr= strand->index>>8;
+
+ surfnor= obr->strandnodes[nr].surfnor;
+ if (surfnor==NULL) {
+ if (verify)
+ surfnor= obr->strandnodes[nr].surfnor= MEM_callocN(256*RE_SURFNOR_ELEMS*sizeof(float), "surfnor strand table");
+ else
+ return NULL;
+ }
+ return surfnor + (strand->index & 255)*RE_SURFNOR_ELEMS;
+}
+
+float *RE_strandren_get_uv(ObjectRen *obr, StrandRen *strand, int n, char **name, int verify)
+{
+ StrandTableNode *node;
+ int nr= strand->index>>8, strandindex= (strand->index&255);
+ int index= (n<<8) + strandindex;
+
+ node= &obr->strandnodes[nr];
+
+ if (verify) {
+ if (n>=node->totuv) {
+ float *uv= node->uv;
+ int size= (n+1)*256;
+
+ node->uv= MEM_callocN(size*sizeof(float)*RE_UV_ELEMS, "strand uv table");
+
+ if (uv) {
+ size= node->totuv*256;
+ memcpy(node->uv, uv, size*sizeof(float)*RE_UV_ELEMS);
+ MEM_freeN(uv);
+ }
+
+ node->totuv= n+1;
+ }
+ }
+ else {
+ if (n>=node->totuv)
+ return NULL;
+
+ if (name) *name= obr->mtface[n];
+ }
+
+ return node->uv + index*RE_UV_ELEMS;
+}
+
+MCol *RE_strandren_get_mcol(ObjectRen *obr, StrandRen *strand, int n, char **name, int verify)
+{
+ StrandTableNode *node;
+ int nr= strand->index>>8, strandindex= (strand->index&255);
+ int index= (n<<8) + strandindex;
+
+ node= &obr->strandnodes[nr];
+
+ if (verify) {
+ if (n>=node->totmcol) {
+ MCol *mcol= node->mcol;
+ int size= (n+1)*256;
+
+ node->mcol= MEM_callocN(size*sizeof(MCol)*RE_MCOL_ELEMS, "strand mcol table");
+
+ if (mcol) {
+ size= node->totmcol*256;
+ memcpy(node->mcol, mcol, size*sizeof(MCol)*RE_MCOL_ELEMS);
+ MEM_freeN(mcol);
+ }
+
+ node->totmcol= n+1;
+ }
+ }
+ else {
+ if (n>=node->totmcol)
+ return NULL;
+
+ if (name) *name= obr->mcol[n];
+ }
+
+ return node->mcol + index*RE_MCOL_ELEMS;
+}
+
+float *RE_strandren_get_simplify(struct ObjectRen *obr, struct StrandRen *strand, int verify)
+{
+ float *simplify;
+ int nr= strand->index>>8;
+
+ simplify= obr->strandnodes[nr].simplify;
+ if (simplify==NULL) {
+ if (verify)
+ simplify= obr->strandnodes[nr].simplify= MEM_callocN(256*RE_SIMPLIFY_ELEMS*sizeof(float), "simplify strand table");
+ else
+ return NULL;
+ }
+ return simplify + (strand->index & 255)*RE_SIMPLIFY_ELEMS;
+}
+
+int *RE_strandren_get_face(ObjectRen *obr, StrandRen *strand, int verify)
+{
+ int *face;
+ int nr= strand->index>>8;
+
+ face= obr->strandnodes[nr].face;
+ if (face==NULL) {
+ if (verify)
+ face= obr->strandnodes[nr].face= MEM_callocN(256*RE_FACE_ELEMS*sizeof(int), "face strand table");
+ else
+ return NULL;
+ }
+ return face + (strand->index & 255)*RE_FACE_ELEMS;
+}
+
+/* winspeed is exception, it is stored per instance */
+float *RE_strandren_get_winspeed(ObjectInstanceRen *obi, StrandRen *strand, int verify)
+{
+ float *winspeed;
+ int totvector;
+
+ winspeed= obi->vectors;
+ if (winspeed==NULL) {
+ if (verify) {
+ totvector= obi->obr->totvert + obi->obr->totstrand;
+ winspeed= obi->vectors= MEM_callocN(totvector*RE_WINSPEED_ELEMS*sizeof(float), "winspeed strand table");
+ }
+ else
+ return NULL;
+ }
+ return winspeed + (obi->obr->totvert + strand->index)*RE_WINSPEED_ELEMS;
+}
+
+StrandRen *RE_findOrAddStrand(ObjectRen *obr, int nr)
+{
+ StrandTableNode *temp;
+ StrandRen *v;
+ int a;
+
+ if (nr<0) {
+ printf("error in findOrAddStrand: %d\n", nr);
+ return obr->strandnodes[0].strand;
+ }
+ a= nr>>8;
+
+ if (a>=obr->strandnodeslen-1) { /* Need to allocate more columns..., and keep last element NULL for free loop */
+ temp= obr->strandnodes;
+
+ obr->strandnodes= MEM_mallocN(sizeof(StrandTableNode)*(obr->strandnodeslen+TABLEINITSIZE), "strandnodes");
+ if (temp) memcpy(obr->strandnodes, temp, obr->strandnodeslen*sizeof(StrandTableNode));
+ memset(obr->strandnodes+obr->strandnodeslen, 0, TABLEINITSIZE*sizeof(StrandTableNode));
+
+ obr->strandnodeslen+=TABLEINITSIZE; /*Does this really need to be power of 2?*/
+ if (temp) MEM_freeN(temp);
+ }
+
+ v= obr->strandnodes[a].strand;
+
+ if (v==NULL) {
+ int i;
+
+ v= (StrandRen *)MEM_callocN(256*sizeof(StrandRen), "findOrAddStrand");
+ obr->strandnodes[a].strand= v;
+
+ for (i= (nr & 0xFFFFFF00), a=0; a<256; a++, i++)
+ v[a].index= i;
+ }
+ v+= (nr & 255);
+ return v;
+}
+
+StrandBuffer *RE_addStrandBuffer(ObjectRen *obr, int totvert)
+{
+ StrandBuffer *strandbuf;
+
+ strandbuf= MEM_callocN(sizeof(StrandBuffer), "StrandBuffer");
+ strandbuf->vert= MEM_callocN(sizeof(StrandVert)*totvert, "StrandVert");
+ strandbuf->totvert= totvert;
+ strandbuf->obr= obr;
+
+ obr->strandbuf= strandbuf;
+
+ return strandbuf;
+}
+
+/* ------------------------------------------------------------------------ */
+
+ObjectRen *RE_addRenderObject(Render *re, Object *ob, Object *par, int index, int psysindex, int lay)
+{
+ ObjectRen *obr= MEM_callocN(sizeof(ObjectRen), "object render struct");
+
+ BLI_addtail(&re->objecttable, obr);
+ obr->ob= ob;
+ obr->par= par;
+ obr->index= index;
+ obr->psysindex= psysindex;
+ obr->lay= lay;
+
+ return obr;
+}
+
+void free_renderdata_vertnodes(VertTableNode *vertnodes)
+{
+ int a;
+
+ if (vertnodes==NULL) return;
+
+ for (a=0; vertnodes[a].vert; a++) {
+ MEM_freeN(vertnodes[a].vert);
+
+ if (vertnodes[a].rad)
+ MEM_freeN(vertnodes[a].rad);
+ if (vertnodes[a].strand)
+ MEM_freeN(vertnodes[a].strand);
+ if (vertnodes[a].tangent)
+ MEM_freeN(vertnodes[a].tangent);
+ if (vertnodes[a].stress)
+ MEM_freeN(vertnodes[a].stress);
+ if (vertnodes[a].winspeed)
+ MEM_freeN(vertnodes[a].winspeed);
+ if (vertnodes[a].origindex)
+ MEM_freeN(vertnodes[a].origindex);
+ }
+
+ MEM_freeN(vertnodes);
+}
+
+void free_renderdata_vlaknodes(VlakTableNode *vlaknodes)
+{
+ int a;
+
+ if (vlaknodes==NULL) return;
+
+ for (a=0; vlaknodes[a].vlak; a++) {
+ MEM_freeN(vlaknodes[a].vlak);
+
+ if (vlaknodes[a].mtface)
+ MEM_freeN(vlaknodes[a].mtface);
+ if (vlaknodes[a].mcol)
+ MEM_freeN(vlaknodes[a].mcol);
+ if (vlaknodes[a].origindex)
+ MEM_freeN(vlaknodes[a].origindex);
+ if (vlaknodes[a].surfnor)
+ MEM_freeN(vlaknodes[a].surfnor);
+ for (int b = 0; b < MAX_MTFACE; b++) {
+ if (vlaknodes[a].tangent_arrays[b])
+ MEM_freeN(vlaknodes[a].tangent_arrays[b]);
+ }
+ if (vlaknodes[a].radface)
+ MEM_freeN(vlaknodes[a].radface);
+ }
+
+ MEM_freeN(vlaknodes);
+}
+
+static void free_renderdata_strandnodes(StrandTableNode *strandnodes)
+{
+ int a;
+
+ if (strandnodes==NULL) return;
+
+ for (a=0; strandnodes[a].strand; a++) {
+ MEM_freeN(strandnodes[a].strand);
+
+ if (strandnodes[a].uv)
+ MEM_freeN(strandnodes[a].uv);
+ if (strandnodes[a].mcol)
+ MEM_freeN(strandnodes[a].mcol);
+ if (strandnodes[a].winspeed)
+ MEM_freeN(strandnodes[a].winspeed);
+ if (strandnodes[a].surfnor)
+ MEM_freeN(strandnodes[a].surfnor);
+ if (strandnodes[a].simplify)
+ MEM_freeN(strandnodes[a].simplify);
+ if (strandnodes[a].face)
+ MEM_freeN(strandnodes[a].face);
+ }
+
+ MEM_freeN(strandnodes);
+}
+
+void free_renderdata_tables(Render *re)
+{
+ ObjectInstanceRen *obi;
+ ObjectRen *obr;
+ StrandBuffer *strandbuf;
+ int a=0;
+
+ for (obr=re->objecttable.first; obr; obr=obr->next) {
+ if (obr->vertnodes) {
+ free_renderdata_vertnodes(obr->vertnodes);
+ obr->vertnodes= NULL;
+ obr->vertnodeslen= 0;
+ }
+
+ if (obr->vlaknodes) {
+ free_renderdata_vlaknodes(obr->vlaknodes);
+ obr->vlaknodes= NULL;
+ obr->vlaknodeslen= 0;
+ obr->totvlak= 0;
+ }
+
+ if (obr->bloha) {
+ for (a=0; obr->bloha[a]; a++)
+ MEM_freeN(obr->bloha[a]);
+
+ MEM_freeN(obr->bloha);
+ obr->bloha= NULL;
+ obr->blohalen= 0;
+ }
+
+ if (obr->strandnodes) {
+ free_renderdata_strandnodes(obr->strandnodes);
+ obr->strandnodes= NULL;
+ obr->strandnodeslen= 0;
+ }
+
+ strandbuf= obr->strandbuf;
+ if (strandbuf) {
+ if (strandbuf->vert) MEM_freeN(strandbuf->vert);
+ if (strandbuf->bound) MEM_freeN(strandbuf->bound);
+ MEM_freeN(strandbuf);
+ }
+
+ if (obr->mtface)
+ MEM_freeN(obr->mtface);
+
+ if (obr->mcol)
+ MEM_freeN(obr->mcol);
+
+ if (obr->rayfaces) {
+ MEM_freeN(obr->rayfaces);
+ obr->rayfaces = NULL;
+ }
+
+ if (obr->rayprimitives) {
+ MEM_freeN(obr->rayprimitives);
+ obr->rayprimitives = NULL;
+ }
+
+ if (obr->raytree) {
+ RE_rayobject_free(obr->raytree);
+ obr->raytree = NULL;
+ }
+ }
+
+ if (re->objectinstance) {
+ for (obi=re->instancetable.first; obi; obi=obi->next) {
+ if (obi->vectors)
+ MEM_freeN(obi->vectors);
+
+ if (obi->raytree)
+ RE_rayobject_free(obi->raytree);
+ }
+
+ MEM_freeN(re->objectinstance);
+ re->objectinstance= NULL;
+ re->totinstance= 0;
+ re->instancetable.first= re->instancetable.last= NULL;
+ }
+
+ if (re->sortedhalos) {
+ MEM_freeN(re->sortedhalos);
+ re->sortedhalos= NULL;
+ }
+
+ BLI_freelistN(&re->customdata_names);
+ BLI_freelistN(&re->objecttable);
+ BLI_freelistN(&re->instancetable);
+}
+
+/* ------------------------------------------------------------------------ */
+
+HaloRen *RE_findOrAddHalo(ObjectRen *obr, int nr)
+{
+ HaloRen *h, **temp;
+ int a;
+
+ if (nr<0) {
+ printf("error in findOrAddHalo: %d\n", nr);
+ return NULL;
+ }
+ a= nr>>8;
+
+ if (a>=obr->blohalen-1) { /* Need to allocate more columns..., and keep last element NULL for free loop */
+ //printf("Allocating %i more halo groups. %i total.\n",
+ // TABLEINITSIZE, obr->blohalen+TABLEINITSIZE );
+ temp=obr->bloha;
+
+ obr->bloha = (HaloRen **)MEM_callocN(sizeof(void *) * (obr->blohalen + TABLEINITSIZE), "Bloha");
+ if (temp) memcpy(obr->bloha, temp, obr->blohalen*sizeof(void *));
+ memset(&(obr->bloha[obr->blohalen]), 0, TABLEINITSIZE * sizeof(void *));
+ obr->blohalen+=TABLEINITSIZE; /*Does this really need to be power of 2?*/
+ if (temp) MEM_freeN(temp);
+ }
+
+ h= obr->bloha[a];
+ if (h==NULL) {
+ h= (HaloRen *)MEM_callocN(256*sizeof(HaloRen), "findOrAdHalo");
+ obr->bloha[a]= h;
+ }
+ h+= (nr & 255);
+ return h;
+}
+
+/* ------------------------------------------------------------------------- */
+
+HaloRen *RE_inithalo(Render *re, ObjectRen *obr, Material *ma,
+ const float vec[3], const float vec1[3],
+ const float *orco, float hasize, float vectsize, int seed)
+{
+ const bool skip_load_image = (re->r.scemode & R_NO_IMAGE_LOAD) != 0;
+ const bool texnode_preview = (re->r.scemode & R_TEXNODE_PREVIEW) != 0;
+ HaloRen *har;
+ MTex *mtex;
+ float tin, tr, tg, tb, ta;
+ float xn, yn, zn, texvec[3], hoco[4], hoco1[4];
+
+ if (hasize==0.0f) return NULL;
+
+ projectverto(vec, re->winmat, hoco);
+ if (hoco[3]==0.0f) return NULL;
+ if (vec1) {
+ projectverto(vec1, re->winmat, hoco1);
+ if (hoco1[3]==0.0f) return NULL;
+ }
+
+ har= RE_findOrAddHalo(obr, obr->tothalo++);
+ copy_v3_v3(har->co, vec);
+ har->hasize= hasize;
+
+ /* actual projectvert is done in function project_renderdata() because of parts/border/pano */
+ /* we do it here for sorting of halos */
+ zn= hoco[3];
+ har->xs= 0.5f*re->winx*(hoco[0]/zn);
+ har->ys= 0.5f*re->winy*(hoco[1]/zn);
+ har->zs= 0x7FFFFF*(hoco[2]/zn);
+
+ har->zBufDist = 0x7FFFFFFF*(hoco[2]/zn);
+
+ /* halovect */
+ if (vec1) {
+
+ har->type |= HA_VECT;
+
+ xn= har->xs - 0.5f*re->winx*(hoco1[0]/hoco1[3]);
+ yn= har->ys - 0.5f*re->winy*(hoco1[1]/hoco1[3]);
+ if (yn == 0.0f && xn >= 0.0f) zn = 0.0f;
+ else zn = atan2f(yn, xn);
+
+ har->sin = sinf(zn);
+ har->cos = cosf(zn);
+ zn= len_v3v3(vec1, vec);
+
+ har->hasize= vectsize*zn + (1.0f-vectsize)*hasize;
+
+ sub_v3_v3v3(har->no, vec, vec1);
+ normalize_v3(har->no);
+ }
+
+ if (ma->mode & MA_HALO_XALPHA) har->type |= HA_XALPHA;
+
+ har->alfa= ma->alpha;
+ har->r= ma->r;
+ har->g= ma->g;
+ har->b= ma->b;
+ har->add= (255.0f*ma->add);
+ har->mat= ma;
+ har->hard= ma->har;
+ har->seed= seed % 256;
+
+ if (ma->mode & MA_STAR) har->starpoints= ma->starc;
+ if (ma->mode & MA_HALO_LINES) har->linec= ma->linec;
+ if (ma->mode & MA_HALO_RINGS) har->ringc= ma->ringc;
+ if (ma->mode & MA_HALO_FLARE) har->flarec= ma->flarec;
+
+
+ if (ma->mtex[0]) {
+
+ if (ma->mode & MA_HALOTEX) {
+ har->tex = 1;
+ }
+ else if (har->mat->septex & (1 << 0)) {
+ /* only 1 level textures */
+ }
+ else {
+ mtex= ma->mtex[0];
+ copy_v3_v3(texvec, vec);
+
+ if (mtex->texco & TEXCO_NORM) {
+ ;
+ }
+ else if (mtex->texco & TEXCO_OBJECT) {
+ /* texvec[0]+= imatbase->ivec[0]; */
+ /* texvec[1]+= imatbase->ivec[1]; */
+ /* texvec[2]+= imatbase->ivec[2]; */
+ /* mul_m3_v3(imatbase->imat, texvec); */
+ }
+ else {
+ if (orco) {
+ copy_v3_v3(texvec, orco);
+ }
+ }
+
+ externtex(mtex,
+ texvec,
+ &tin, &tr, &tg, &tb, &ta,
+ 0,
+ re->pool,
+ skip_load_image,
+ texnode_preview);
+
+ yn= tin*mtex->colfac;
+ //zn= tin*mtex->alphafac;
+
+ if (mtex->mapto & MAP_COL) {
+ zn= 1.0f-yn;
+ har->r= (yn*tr+ zn*ma->r);
+ har->g= (yn*tg+ zn*ma->g);
+ har->b= (yn*tb+ zn*ma->b);
+ }
+ if (mtex->texco & TEXCO_UV) {
+ har->alfa= tin;
+ }
+ if (mtex->mapto & MAP_ALPHA)
+ har->alfa= tin;
+ }
+ }
+
+ har->pool = re->pool;
+ har->skip_load_image = skip_load_image;
+ har->texnode_preview = texnode_preview;
+
+ return har;
+}
+
+HaloRen *RE_inithalo_particle(Render *re, ObjectRen *obr, DerivedMesh *dm, Material *ma,
+ const float vec[3], const float vec1[3],
+ const float *orco, const float *uvco, float hasize, float vectsize, int seed, const float pa_co[3])
+{
+ const bool skip_load_image = (re->r.scemode & R_NO_IMAGE_LOAD) != 0;
+ const bool texnode_preview = (re->r.scemode & R_TEXNODE_PREVIEW) != 0;
+ HaloRen *har;
+ MTex *mtex;
+ float tin, tr, tg, tb, ta;
+ float xn, yn, zn, texvec[3], hoco[4], hoco1[4], in[3], tex[3], out[3];
+ int i, hasrgb;
+
+ if (hasize==0.0f) return NULL;
+
+ projectverto(vec, re->winmat, hoco);
+ if (hoco[3]==0.0f) return NULL;
+ if (vec1) {
+ projectverto(vec1, re->winmat, hoco1);
+ if (hoco1[3]==0.0f) return NULL;
+ }
+
+ har= RE_findOrAddHalo(obr, obr->tothalo++);
+ copy_v3_v3(har->co, vec);
+ har->hasize= hasize;
+
+ /* actual projectvert is done in function project_renderdata() because of parts/border/pano */
+ /* we do it here for sorting of halos */
+ zn= hoco[3];
+ har->xs= 0.5f*re->winx*(hoco[0]/zn);
+ har->ys= 0.5f*re->winy*(hoco[1]/zn);
+ har->zs= 0x7FFFFF*(hoco[2]/zn);
+
+ har->zBufDist = 0x7FFFFFFF*(hoco[2]/zn);
+
+ /* halovect */
+ if (vec1) {
+
+ har->type |= HA_VECT;
+
+ xn= har->xs - 0.5f*re->winx*(hoco1[0]/hoco1[3]);
+ yn= har->ys - 0.5f*re->winy*(hoco1[1]/hoco1[3]);
+ if (yn == 0.0f && xn >= 0.0f) zn = 0.0f;
+ else zn = atan2f(yn, xn);
+
+ har->sin = sinf(zn);
+ har->cos = cosf(zn);
+ zn= len_v3v3(vec1, vec)*0.5f;
+
+ har->hasize= vectsize*zn + (1.0f-vectsize)*hasize;
+
+ sub_v3_v3v3(har->no, vec, vec1);
+ normalize_v3(har->no);
+ }
+
+ if (ma->mode & MA_HALO_XALPHA) har->type |= HA_XALPHA;
+
+ har->alfa= ma->alpha;
+ har->r= ma->r;
+ har->g= ma->g;
+ har->b= ma->b;
+ har->add= (255.0f*ma->add);
+ har->mat= ma;
+ har->hard= ma->har;
+ har->seed= seed % 256;
+
+ if (ma->mode & MA_STAR) har->starpoints= ma->starc;
+ if (ma->mode & MA_HALO_LINES) har->linec= ma->linec;
+ if (ma->mode & MA_HALO_RINGS) har->ringc= ma->ringc;
+ if (ma->mode & MA_HALO_FLARE) har->flarec= ma->flarec;
+
+ if ((ma->mode & MA_HALOTEX) && ma->mtex[0])
+ har->tex= 1;
+
+ for (i=0; i<MAX_MTEX; i++)
+ if (ma->mtex[i] && (ma->septex & (1<<i))==0) {
+ mtex= ma->mtex[i];
+ copy_v3_v3(texvec, vec);
+
+ if (mtex->texco & TEXCO_NORM) {
+ ;
+ }
+ else if (mtex->texco & TEXCO_OBJECT) {
+ if (mtex->object)
+ mul_m4_v3(mtex->object->imat_ren, texvec);
+ }
+ else if (mtex->texco & TEXCO_GLOB) {
+ copy_v3_v3(texvec, vec);
+ }
+ else if (mtex->texco & TEXCO_UV && uvco) {
+ int uv_index=CustomData_get_named_layer_index(&dm->faceData, CD_MTFACE, mtex->uvname);
+ if (uv_index<0)
+ uv_index=CustomData_get_active_layer_index(&dm->faceData, CD_MTFACE);
+
+ uv_index-=CustomData_get_layer_index(&dm->faceData, CD_MTFACE);
+
+ texvec[0]=2.0f*uvco[2*uv_index]-1.0f;
+ texvec[1]=2.0f*uvco[2*uv_index+1]-1.0f;
+ texvec[2]=0.0f;
+ }
+ else if (mtex->texco & TEXCO_PARTICLE) {
+ /* particle coordinates in range [0, 1] */
+ texvec[0] = 2.f * pa_co[0] - 1.f;
+ texvec[1] = 2.f * pa_co[1] - 1.f;
+ texvec[2] = pa_co[2];
+ }
+ else if (orco) {
+ copy_v3_v3(texvec, orco);
+ }
+
+ hasrgb = externtex(mtex,
+ texvec,
+ &tin, &tr, &tg, &tb, &ta,
+ 0,
+ re->pool,
+ skip_load_image,
+ texnode_preview);
+
+ //yn= tin*mtex->colfac;
+ //zn= tin*mtex->alphafac;
+ if (mtex->mapto & MAP_COL) {
+ tex[0]=tr;
+ tex[1]=tg;
+ tex[2]=tb;
+ out[0]=har->r;
+ out[1]=har->g;
+ out[2]=har->b;
+
+ texture_rgb_blend(in, tex, out, tin, mtex->colfac, mtex->blendtype);
+ // zn= 1.0-yn;
+ //har->r= (yn*tr+ zn*ma->r);
+ //har->g= (yn*tg+ zn*ma->g);
+ //har->b= (yn*tb+ zn*ma->b);
+ har->r= in[0];
+ har->g= in[1];
+ har->b= in[2];
+ }
+
+ /* alpha returned, so let's use it instead of intensity */
+ if (hasrgb)
+ tin = ta;
+
+ if (mtex->mapto & MAP_ALPHA)
+ har->alfa = texture_value_blend(mtex->def_var, har->alfa, tin, mtex->alphafac, mtex->blendtype);
+ if (mtex->mapto & MAP_HAR)
+ har->hard = 1.0f+126.0f*texture_value_blend(mtex->def_var, ((float)har->hard)/127.0f, tin, mtex->hardfac, mtex->blendtype);
+ if (mtex->mapto & MAP_RAYMIRR)
+ har->hasize = 100.0f*texture_value_blend(mtex->def_var, har->hasize/100.0f, tin, mtex->raymirrfac, mtex->blendtype);
+ if (mtex->mapto & MAP_TRANSLU) {
+ float add = texture_value_blend(mtex->def_var, (float)har->add/255.0f, tin, mtex->translfac, mtex->blendtype);
+ CLAMP(add, 0.f, 1.f);
+ har->add = 255.0f*add;
+ }
+ /* now what on earth is this good for?? */
+ //if (mtex->texco & 16) {
+ // har->alfa= tin;
+ //}
+ }
+
+ har->pool = re->pool;
+ har->skip_load_image = (re->r.scemode & R_NO_IMAGE_LOAD) != 0;
+ har->texnode_preview = (re->r.scemode & R_TEXNODE_PREVIEW) != 0;
+
+ return har;
+}
+
+/* -------------------------- operations on entire database ----------------------- */
+
+/* ugly function for halos in panorama */
+static int panotestclip(Render *re, bool do_pano, float v[4])
+{
+ /* part size (ensure we run RE_parts_clamp first) */
+ BLI_assert(re->partx == min_ii(re->r.tilex, re->rectx));
+ BLI_assert(re->party == min_ii(re->r.tiley, re->recty));
+
+ if (do_pano == false) {
+ return testclip(v);
+ }
+ else {
+ /* to be used for halos en infos */
+ float abs4;
+ short c = 0;
+
+ int xparts = (re->rectx + re->partx - 1) / re->partx;
+
+ abs4= fabsf(v[3]);
+
+ if (v[2]< -abs4) c=16; /* this used to be " if (v[2]<0) ", see clippz() */
+ else if (v[2]> abs4) c+= 32;
+
+ if ( v[1]>abs4) c+=4;
+ else if ( v[1]< -abs4) c+=8;
+
+ abs4*= xparts;
+ if ( v[0]>abs4) c+=2;
+ else if ( v[0]< -abs4) c+=1;
+
+ return c;
+ }
+}
+
+/**
+ * This adds the hcs coordinates to vertices. It iterates over all
+ * vertices, halos and faces. After the conversion, we clip in hcs.
+ *
+ * Elsewhere, all primites are converted to vertices.
+ * Called in
+ * - envmapping (envmap.c)
+ * - shadow buffering (shadbuf.c)
+ */
+
+void project_renderdata(Render *re,
+ void (*projectfunc)(const float *, float mat[4][4], float *),
+ bool do_pano, float xoffs, bool UNUSED(do_buckets))
+{
+ ObjectRen *obr;
+ HaloRen *har = NULL;
+ float zn, vec[3], hoco[4];
+ int a;
+
+ if (do_pano) {
+ float panophi= xoffs;
+
+ re->panosi = sinf(panophi);
+ re->panoco = cosf(panophi);
+ }
+
+ for (obr=re->objecttable.first; obr; obr=obr->next) {
+ /* calculate view coordinates (and zbuffer value) */
+ for (a=0; a<obr->tothalo; a++) {
+ if ((a & 255)==0) har= obr->bloha[a>>8];
+ else har++;
+
+ if (do_pano) {
+ vec[0]= re->panoco*har->co[0] + re->panosi*har->co[2];
+ vec[1]= har->co[1];
+ vec[2]= -re->panosi*har->co[0] + re->panoco*har->co[2];
+ }
+ else {
+ copy_v3_v3(vec, har->co);
+ }
+
+ projectfunc(vec, re->winmat, hoco);
+
+ /* we clip halos less critical, but not for the Z */
+ hoco[0]*= 0.5f;
+ hoco[1]*= 0.5f;
+
+ if ( panotestclip(re, do_pano, hoco) ) {
+ har->miny= har->maxy= -10000; /* that way render clips it */
+ }
+ else if (hoco[3]<0.0f) {
+ har->miny= har->maxy= -10000; /* render clips it */
+ }
+ else { /* do the projection...*/
+ /* bring back hocos */
+ hoco[0]*= 2.0f;
+ hoco[1]*= 2.0f;
+
+ zn= hoco[3];
+ har->xs= 0.5f*re->winx*(1.0f+hoco[0]/zn); /* the 0.5 negates the previous 2...*/
+ har->ys= 0.5f*re->winy*(1.0f+hoco[1]/zn);
+
+ /* this should be the zbuffer coordinate */
+ har->zs= 0x7FFFFF*(hoco[2]/zn);
+ /* taking this from the face clip functions? seems ok... */
+ har->zBufDist = 0x7FFFFFFF*(hoco[2]/zn);
+
+ vec[0]+= har->hasize;
+ projectfunc(vec, re->winmat, hoco);
+ vec[0]-= har->hasize;
+ zn= hoco[3];
+ har->rad= fabsf(har->xs- 0.5f*re->winx*(1.0f+hoco[0]/zn));
+
+ /* this clip is not really OK, to prevent stars to become too large */
+ if (har->type & HA_ONLYSKY) {
+ if (har->rad>3.0f) har->rad= 3.0f;
+ }
+
+ har->radsq= har->rad*har->rad;
+
+ har->miny= har->ys - har->rad/re->ycor;
+ har->maxy= har->ys + har->rad/re->ycor;
+
+ /* the Zd value is still not really correct for pano */
+
+ vec[2] -= har->hasize; /* z negative, otherwise it's clipped */
+ projectfunc(vec, re->winmat, hoco);
+ zn = hoco[3];
+ zn = fabsf((float)har->zs - 0x7FFFFF * (hoco[2] / zn));
+ har->zd = CLAMPIS(zn, 0, INT_MAX);
+
+ }
+
+ }
+ }
+}
+
+/* ------------------------------------------------------------------------- */
+
+void RE_updateRenderInstance(Render *re, ObjectInstanceRen *obi, int flag)
+{
+ /* flag specifies what things have changed. */
+ if (flag & RE_OBJECT_INSTANCES_UPDATE_OBMAT) {
+ copy_m4_m4(obi->obmat, obi->ob->obmat);
+ invert_m4_m4(obi->obinvmat, obi->obmat);
+ }
+ if (flag & RE_OBJECT_INSTANCES_UPDATE_VIEW) {
+ mul_m4_m4m4(obi->localtoviewmat, re->viewmat, obi->obmat);
+ mul_m4_m4m4(obi->localtoviewinvmat, obi->obinvmat, re->viewinv);
+ }
+}
+
+void RE_updateRenderInstances(Render *re, int flag)
+{
+ int i = 0;
+ for (i = 0; i < re->totinstance; i++)
+ RE_updateRenderInstance(re, &re->objectinstance[i], flag);
+}
+
+ObjectInstanceRen *RE_addRenderInstance(
+ Render *re, ObjectRen *obr, Object *ob, Object *par,
+ int index, int psysindex, float mat[4][4], int lay, const DupliObject *dob)
+{
+ ObjectInstanceRen *obi;
+ float mat3[3][3];
+
+ obi= MEM_callocN(sizeof(ObjectInstanceRen), "ObjectInstanceRen");
+ obi->obr= obr;
+ obi->ob= ob;
+ obi->par= par;
+ obi->index= index;
+ obi->psysindex= psysindex;
+ obi->lay= lay;
+
+ /* Fill particle info */
+ if (par && dob) {
+ const ParticleSystem *psys = dob->particle_system;
+ if (psys) {
+ int part_index;
+ if (obi->index < psys->totpart) {
+ part_index = obi->index;
+ }
+ else if (psys->child) {
+ part_index = psys->child[obi->index - psys->totpart].parent;
+ }
+ else {
+ part_index = -1;
+ }
+
+ if (part_index >= 0) {
+ const ParticleData *p = &psys->particles[part_index];
+ obi->part_index = part_index;
+ obi->part_size = p->size;
+ obi->part_age = RE_GetStats(re)->cfra - p->time;
+ obi->part_lifetime = p->lifetime;
+
+ copy_v3_v3(obi->part_co, p->state.co);
+ copy_v3_v3(obi->part_vel, p->state.vel);
+ copy_v3_v3(obi->part_avel, p->state.ave);
+ }
+ }
+ }
+
+ /* Fill object info */
+ if (dob) {
+ obi->random_id = dob->random_id;
+ }
+ else {
+ obi->random_id = BLI_hash_int_2d(BLI_hash_string(obi->ob->id.name + 2), 0);
+ }
+
+ RE_updateRenderInstance(re, obi, RE_OBJECT_INSTANCES_UPDATE_OBMAT | RE_OBJECT_INSTANCES_UPDATE_VIEW);
+
+ if (mat) {
+ copy_m4_m4(obi->mat, mat);
+ copy_m3_m4(mat3, mat);
+ invert_m3_m3(obi->nmat, mat3);
+ transpose_m3(obi->nmat);
+ obi->flag |= R_DUPLI_TRANSFORMED;
+ }
+
+ BLI_addtail(&re->instancetable, obi);
+
+ return obi;
+}
+
+void RE_instance_get_particle_info(struct ObjectInstanceRen *obi, float *index, float *random, float *age, float *lifetime, float co[3], float *size, float vel[3], float angvel[3])
+{
+ *index = obi->part_index;
+ *random = BLI_hash_int_01(obi->part_index);
+ *age = obi->part_age;
+ *lifetime = obi->part_lifetime;
+ copy_v3_v3(co, obi->part_co);
+ *size = obi->part_size;
+ copy_v3_v3(vel, obi->part_vel);
+ copy_v3_v3(angvel, obi->part_avel);
+}
+
+
+void RE_makeRenderInstances(Render *re)
+{
+ ObjectInstanceRen *obi, *oldobi;
+ ListBase newlist;
+ int tot;
+
+ /* convert list of object instances to an array for index based lookup */
+ tot= BLI_listbase_count(&re->instancetable);
+ re->objectinstance= MEM_callocN(sizeof(ObjectInstanceRen)*tot, "ObjectInstance");
+ re->totinstance= tot;
+ newlist.first= newlist.last= NULL;
+
+ obi= re->objectinstance;
+ for (oldobi=re->instancetable.first; oldobi; oldobi=oldobi->next) {
+ *obi= *oldobi;
+
+ if (obi->obr) {
+ obi->prev= obi->next= NULL;
+ BLI_addtail(&newlist, obi);
+ obi++;
+ }
+ else
+ re->totinstance--;
+ }
+
+ BLI_freelistN(&re->instancetable);
+ re->instancetable= newlist;
+}
+
+/* four functions to facilitate envmap rotation for raytrace */
+void RE_instance_rotate_ray_start(ObjectInstanceRen *obi, Isect *is)
+{
+ if (obi && (obi->flag & R_ENV_TRANSFORMED)) {
+ copy_v3_v3(is->origstart, is->start);
+ mul_m4_v3(obi->imat, is->start);
+ }
+}
+
+void RE_instance_rotate_ray_dir(ObjectInstanceRen *obi, Isect *is)
+{
+ if (obi && (obi->flag & R_ENV_TRANSFORMED)) {
+ float end[3];
+
+ copy_v3_v3(is->origdir, is->dir);
+ add_v3_v3v3(end, is->origstart, is->dir);
+
+ mul_m4_v3(obi->imat, end);
+ sub_v3_v3v3(is->dir, end, is->start);
+ }
+}
+
+void RE_instance_rotate_ray(ObjectInstanceRen *obi, Isect *is)
+{
+ RE_instance_rotate_ray_start(obi, is);
+ RE_instance_rotate_ray_dir(obi, is);
+}
+
+void RE_instance_rotate_ray_restore(ObjectInstanceRen *obi, Isect *is)
+{
+ if (obi && (obi->flag & R_ENV_TRANSFORMED)) {
+ copy_v3_v3(is->start, is->origstart);
+ copy_v3_v3(is->dir, is->origdir);
+ }
+}
+
+int clip_render_object(float boundbox[2][3], float bounds[4], float winmat[4][4])
+{
+ float mat[4][4], vec[4];
+ int a, fl, flag = -1;
+
+ copy_m4_m4(mat, winmat);
+
+ for (a=0; a < 8; a++) {
+ vec[0]= (a & 1)? boundbox[0][0]: boundbox[1][0];
+ vec[1]= (a & 2)? boundbox[0][1]: boundbox[1][1];
+ vec[2]= (a & 4)? boundbox[0][2]: boundbox[1][2];
+ vec[3]= 1.0;
+ mul_m4_v4(mat, vec);
+
+ fl = 0;
+ if (bounds) {
+ if (vec[0] < bounds[0] * vec[3]) fl |= 1;
+ else if (vec[0] > bounds[1] * vec[3]) fl |= 2;
+
+ if (vec[1] > bounds[3] * vec[3]) fl |= 4;
+ else if (vec[1] < bounds[2] * vec[3]) fl |= 8;
+ }
+ else {
+ if (vec[0] < -vec[3]) fl |= 1;
+ else if (vec[0] > vec[3]) fl |= 2;
+
+ if (vec[1] > vec[3]) fl |= 4;
+ else if (vec[1] < -vec[3]) fl |= 8;
+ }
+ if (vec[2] < -vec[3]) fl |= 16;
+ else if (vec[2] > vec[3]) fl |= 32;
+
+ flag &= fl;
+ if (flag == 0) {
+ return 0;
+ }
+ }
+
+ return flag;
+}
+
diff --git a/source/blender/render/intern/source/shadbuf.c b/source/blender/render/intern/source/shadbuf.c
new file mode 100644
index 00000000000..04e9177241b
--- /dev/null
+++ b/source/blender/render/intern/source/shadbuf.c
@@ -0,0 +1,2647 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * Contributor(s): 2004-2006, Blender Foundation
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/render/intern/source/shadbuf.c
+ * \ingroup render
+ */
+
+
+#include <math.h>
+#include <string.h>
+
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_group_types.h"
+#include "DNA_lamp_types.h"
+#include "DNA_material_types.h"
+
+#include "BLI_math.h"
+#include "BLI_blenlib.h"
+#include "BLI_jitter_2d.h"
+#include "BLI_memarena.h"
+#include "BLI_rand.h"
+#include "BLI_utildefines.h"
+
+#include "BKE_global.h"
+#include "BKE_scene.h"
+
+#include "PIL_time.h"
+
+#include "render_types.h"
+#include "renderdatabase.h"
+#include "rendercore.h"
+#include "shadbuf.h"
+#include "shading.h"
+#include "zbuf.h"
+
+/* XXX, could be better implemented... this is for endian issues */
+#ifdef __BIG_ENDIAN__
+//# define RCOMP 3
+# define GCOMP 2
+# define BCOMP 1
+# define ACOMP 0
+#else
+//# define RCOMP 0
+# define GCOMP 1
+# define BCOMP 2
+# define ACOMP 3
+#endif
+
+#define RCT_SIZE_X(rct) ((rct)->xmax - (rct)->xmin)
+#define RCT_SIZE_Y(rct) ((rct)->ymax - (rct)->ymin)
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+/* defined in pipeline.c, is hardcopy of active dynamic allocated Render */
+/* only to be used here in this file, it's for speed */
+extern struct Render R;
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+/* ------------------------------------------------------------------------- */
+
+/* initshadowbuf() in convertBlenderScene.c */
+
+/* ------------------------------------------------------------------------- */
+
+static void copy_to_ztile(int *rectz, int size, int x1, int y1, int tile, char *r1)
+{
+ int len4, *rz;
+ int x2, y2;
+
+ x2= x1+tile;
+ y2= y1+tile;
+ if (x2>=size) x2= size-1;
+ if (y2>=size) y2= size-1;
+
+ if (x1>=x2 || y1>=y2) return;
+
+ len4= 4*(x2- x1);
+ rz= rectz + size*y1 + x1;
+ for (; y1<y2; y1++) {
+ memcpy(r1, rz, len4);
+ rz+= size;
+ r1+= len4;
+ }
+}
+
+#if 0
+static int sizeoflampbuf(ShadBuf *shb)
+{
+ int num, count=0;
+ char *cp;
+
+ cp= shb->cbuf;
+ num= (shb->size*shb->size)/256;
+
+ while (num--) count+= *(cp++);
+
+ return 256*count;
+}
+#endif
+
+/* not threadsafe... */
+static float *give_jitter_tab(int samp)
+{
+ /* these are all possible jitter tables, takes up some
+ * 12k, not really bad!
+ * For soft shadows, it saves memory and render time
+ */
+ static int tab[17]={1, 4, 9, 16, 25, 36, 49, 64, 81, 100, 121, 144, 169, 196, 225, 256};
+ static float jit[1496][2];
+ static char ctab[17]= {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+ int a, offset=0;
+
+ if (samp<2) samp= 2;
+ else if (samp>16) samp= 16;
+
+ for (a=0; a<samp-1; a++) offset+= tab[a];
+
+ if (ctab[samp]==0) {
+ ctab[samp]= 1;
+ BLI_jitter_init((float (*)[2])jit[offset], samp*samp);
+ }
+
+ return jit[offset];
+
+}
+
+static void make_jitter_weight_tab(Render *re, ShadBuf *shb, short filtertype)
+{
+ float *jit, totw= 0.0f;
+ int samp= get_render_shadow_samples(&re->r, shb->samp);
+ int a, tot=samp*samp;
+
+ shb->weight= MEM_mallocN(sizeof(float)*tot, "weight tab lamp");
+
+ for (jit= shb->jit, a=0; a<tot; a++, jit+=2) {
+ if (filtertype==LA_SHADBUF_TENT)
+ shb->weight[a] = 0.71f - sqrtf(jit[0] * jit[0] + jit[1] * jit[1]);
+ else if (filtertype==LA_SHADBUF_GAUSS)
+ shb->weight[a] = RE_filter_value(R_FILTER_GAUSS, 1.8f * sqrtf(jit[0] * jit[0] + jit[1] * jit[1]));
+ else
+ shb->weight[a]= 1.0f;
+
+ totw+= shb->weight[a];
+ }
+
+ totw= 1.0f/totw;
+ for (a=0; a<tot; a++) {
+ shb->weight[a]*= totw;
+ }
+}
+
+static int verg_deepsample(const void *poin1, const void *poin2)
+{
+ const DeepSample *ds1= (const DeepSample*)poin1;
+ const DeepSample *ds2= (const DeepSample*)poin2;
+
+ if (ds1->z < ds2->z) return -1;
+ else if (ds1->z == ds2->z) return 0;
+ else return 1;
+}
+
+static int compress_deepsamples(DeepSample *dsample, int tot, float epsilon)
+{
+ /* uses doubles to avoid overflows and other numerical issues,
+ * could be improved */
+ DeepSample *ds, *newds;
+ float v;
+ double slope, slopemin, slopemax, min, max, div, newmin, newmax;
+ int a, first, z, newtot= 0;
+
+#if 0
+ if (print) {
+ for (a=0, ds=dsample; a<tot; a++, ds++)
+ printf("%lf, %f ", ds->z/(double)0x7FFFFFFF, ds->v);
+ printf("\n");
+ }
+#endif
+
+ /* read from and write into same array */
+ ds= dsample;
+ newds= dsample;
+ a= 0;
+
+ /* as long as we are not at the end of the array */
+ for (a++, ds++; a<tot; a++, ds++) {
+ slopemin= 0.0f;
+ slopemax= 0.0f;
+ first= 1;
+
+ for (; a<tot; a++, ds++) {
+ //dz= ds->z - newds->z;
+ if (ds->z == newds->z) {
+ /* still in same z position, simply check
+ * visibility difference against epsilon */
+ if (!(fabsf(newds->v - ds->v) <= epsilon)) {
+ break;
+ }
+ }
+ else {
+ /* compute slopes */
+ div= (double)0x7FFFFFFF / ((double)ds->z - (double)newds->z);
+ min= (double)((ds->v - epsilon) - newds->v) * div;
+ max= (double)((ds->v + epsilon) - newds->v) * div;
+
+ /* adapt existing slopes */
+ if (first) {
+ newmin= min;
+ newmax= max;
+ first= 0;
+ }
+ else {
+ newmin= MAX2(slopemin, min);
+ newmax= MIN2(slopemax, max);
+
+ /* verify if there is still space between the slopes */
+ if (newmin > newmax) {
+ ds--;
+ a--;
+ break;
+ }
+ }
+
+ slopemin= newmin;
+ slopemax= newmax;
+ }
+ }
+
+ if (a == tot) {
+ ds--;
+ a--;
+ }
+
+ /* always previous z */
+ z= ds->z;
+
+ if (first || a==tot-1) {
+ /* if slopes were not initialized, use last visibility */
+ v= ds->v;
+ }
+ else {
+ /* compute visibility at center between slopes at z */
+ slope = (slopemin + slopemax) * 0.5;
+ v = (double)newds->v + slope * ((double)(z - newds->z) / (double)0x7FFFFFFF);
+ }
+
+ newds++;
+ newtot++;
+
+ newds->z= z;
+ newds->v= v;
+ }
+
+ if (newtot == 0 || (newds->v != (newds-1)->v))
+ newtot++;
+
+#if 0
+ if (print) {
+ for (a=0, ds=dsample; a<newtot; a++, ds++)
+ printf("%lf, %f ", ds->z/(double)0x7FFFFFFF, ds->v);
+ printf("\n");
+ }
+#endif
+
+ return newtot;
+}
+
+static float deep_alpha(Render *re, int obinr, int facenr, bool use_strand)
+{
+ ObjectInstanceRen *obi= &re->objectinstance[obinr];
+ Material *ma;
+
+ if (use_strand) {
+ StrandRen *strand= RE_findOrAddStrand(obi->obr, facenr-1);
+ ma= strand->buffer->ma;
+ }
+ else {
+ VlakRen *vlr= RE_findOrAddVlak(obi->obr, (facenr-1) & RE_QUAD_MASK);
+ ma= vlr->mat;
+ }
+
+ return ma->shad_alpha;
+}
+
+static void compress_deepshadowbuf(Render *re, ShadBuf *shb, APixstr *apixbuf, APixstrand *apixbufstrand)
+{
+ ShadSampleBuf *shsample;
+ DeepSample *ds[RE_MAX_OSA], *sampleds[RE_MAX_OSA], *dsb, *newbuf;
+ APixstr *ap, *apn;
+ APixstrand *aps, *apns;
+ float visibility;
+
+ const int totbuf= shb->totbuf;
+ const float totbuf_f= (float)shb->totbuf;
+ const float totbuf_f_inv= 1.0f/totbuf_f;
+ const int size= shb->size;
+
+ int a, b, c, tot, minz, found, prevtot, newtot;
+ int sampletot[RE_MAX_OSA], totsample = 0, totsamplec = 0;
+
+ shsample= MEM_callocN(sizeof(ShadSampleBuf), "shad sample buf");
+ BLI_addtail(&shb->buffers, shsample);
+
+ shsample->totbuf = MEM_callocN(sizeof(int) * size * size, "deeptotbuf");
+ shsample->deepbuf = MEM_callocN(sizeof(DeepSample *) * size * size, "deepbuf");
+
+ ap= apixbuf;
+ aps= apixbufstrand;
+ for (a=0; a<size*size; a++, ap++, aps++) {
+ /* count number of samples */
+ for (c=0; c<totbuf; c++)
+ sampletot[c]= 0;
+
+ tot= 0;
+ for (apn=ap; apn; apn=apn->next)
+ for (b=0; b<4; b++)
+ if (apn->p[b])
+ for (c=0; c<totbuf; c++)
+ if (apn->mask[b] & (1<<c))
+ sampletot[c]++;
+
+ if (apixbufstrand) {
+ for (apns=aps; apns; apns=apns->next)
+ for (b=0; b<4; b++)
+ if (apns->p[b])
+ for (c=0; c<totbuf; c++)
+ if (apns->mask[b] & (1<<c))
+ sampletot[c]++;
+ }
+
+ for (c=0; c<totbuf; c++)
+ tot += sampletot[c];
+
+ if (tot == 0) {
+ shsample->deepbuf[a]= NULL;
+ shsample->totbuf[a]= 0;
+ continue;
+ }
+
+ /* fill samples */
+ ds[0]= sampleds[0]= MEM_callocN(sizeof(DeepSample)*tot*2, "deepsample");
+ for (c=1; c<totbuf; c++)
+ ds[c]= sampleds[c]= sampleds[c-1] + sampletot[c-1]*2;
+
+ for (apn=ap; apn; apn=apn->next) {
+ for (b=0; b<4; b++) {
+ if (apn->p[b]) {
+ for (c=0; c<totbuf; c++) {
+ if (apn->mask[b] & (1<<c)) {
+ /* two entries to create step profile */
+ ds[c]->z= apn->z[b];
+ ds[c]->v= 1.0f; /* not used */
+ ds[c]++;
+ ds[c]->z= apn->z[b];
+ ds[c]->v= deep_alpha(re, apn->obi[b], apn->p[b], 0);
+ ds[c]++;
+ }
+ }
+ }
+ }
+ }
+
+ if (apixbufstrand) {
+ for (apns=aps; apns; apns=apns->next) {
+ for (b=0; b<4; b++) {
+ if (apns->p[b]) {
+ for (c=0; c<totbuf; c++) {
+ if (apns->mask[b] & (1<<c)) {
+ /* two entries to create step profile */
+ ds[c]->z= apns->z[b];
+ ds[c]->v= 1.0f; /* not used */
+ ds[c]++;
+ ds[c]->z= apns->z[b];
+ ds[c]->v= deep_alpha(re, apns->obi[b], apns->p[b], 1);
+ ds[c]++;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ for (c=0; c<totbuf; c++) {
+ /* sort by increasing z */
+ qsort(sampleds[c], sampletot[c], sizeof(DeepSample)*2, verg_deepsample);
+
+ /* sum visibility, replacing alpha values */
+ visibility= 1.0f;
+ ds[c]= sampleds[c];
+
+ for (b=0; b<sampletot[c]; b++) {
+ /* two entries creating step profile */
+ ds[c]->v= visibility;
+ ds[c]++;
+
+ visibility *= 1.0f-ds[c]->v;
+ ds[c]->v= visibility;
+ ds[c]++;
+ }
+
+ /* halfway trick, probably won't work well for volumes? */
+ ds[c]= sampleds[c];
+ for (b=0; b<sampletot[c]; b++) {
+ if (b+1 < sampletot[c]) {
+ ds[c]->z= (ds[c]->z>>1) + ((ds[c]+2)->z>>1);
+ ds[c]++;
+ ds[c]->z= (ds[c]->z>>1) + ((ds[c]+2)->z>>1);
+ ds[c]++;
+ }
+ else {
+ ds[c]->z= (ds[c]->z>>1) + (0x7FFFFFFF>>1);
+ ds[c]++;
+ ds[c]->z= (ds[c]->z>>1) + (0x7FFFFFFF>>1);
+ ds[c]++;
+ }
+ }
+
+ /* init for merge loop */
+ ds[c]= sampleds[c];
+ sampletot[c] *= 2;
+ }
+
+ shsample->deepbuf[a]= MEM_callocN(sizeof(DeepSample)*tot*2, "deepsample");
+ shsample->totbuf[a]= 0;
+
+ /* merge buffers */
+ dsb= shsample->deepbuf[a];
+ while (1) {
+ minz= 0;
+ found= 0;
+
+ for (c=0; c<totbuf; c++) {
+ if (sampletot[c] && (!found || ds[c]->z < minz)) {
+ minz= ds[c]->z;
+ found= 1;
+ }
+ }
+
+ if (!found)
+ break;
+
+ dsb->z= minz;
+ dsb->v= 0.0f;
+
+ visibility= 0.0f;
+ for (c=0; c<totbuf; c++) {
+ if (sampletot[c] && ds[c]->z == minz) {
+ ds[c]++;
+ sampletot[c]--;
+ }
+
+ if (sampleds[c] == ds[c])
+ visibility += totbuf_f_inv;
+ else
+ visibility += (ds[c]-1)->v / totbuf_f;
+ }
+
+ dsb->v= visibility;
+ dsb++;
+ shsample->totbuf[a]++;
+ }
+
+ prevtot= shsample->totbuf[a];
+ totsample += prevtot;
+
+ newtot= compress_deepsamples(shsample->deepbuf[a], prevtot, shb->compressthresh);
+ shsample->totbuf[a]= newtot;
+ totsamplec += newtot;
+
+ if (newtot < prevtot) {
+ newbuf= MEM_mallocN(sizeof(DeepSample)*newtot, "cdeepsample");
+ memcpy(newbuf, shsample->deepbuf[a], sizeof(DeepSample)*newtot);
+ MEM_freeN(shsample->deepbuf[a]);
+ shsample->deepbuf[a]= newbuf;
+ }
+
+ MEM_freeN(sampleds[0]);
+ }
+
+ //printf("%d -> %d, ratio %f\n", totsample, totsamplec, (float)totsamplec/(float)totsample);
+}
+
+/* create Z tiles (for compression): this system is 24 bits!!! */
+static void compress_shadowbuf(ShadBuf *shb, int *rectz, int square)
+{
+ ShadSampleBuf *shsample;
+ float dist;
+ uintptr_t *ztile;
+ int *rz, *rz1, verg, verg1, size= shb->size;
+ int a, x, y, minx, miny, byt1, byt2;
+ char *rc, *rcline, *ctile, *zt;
+
+ shsample= MEM_callocN(sizeof(ShadSampleBuf), "shad sample buf");
+ BLI_addtail(&shb->buffers, shsample);
+
+ shsample->zbuf= MEM_mallocN(sizeof(uintptr_t)*(size*size)/256, "initshadbuf2");
+ shsample->cbuf= MEM_callocN((size*size)/256, "initshadbuf3");
+
+ ztile= (uintptr_t *)shsample->zbuf;
+ ctile= shsample->cbuf;
+
+ /* help buffer */
+ rcline= MEM_mallocN(256*4+sizeof(int), "makeshadbuf2");
+
+ for (y=0; y<size; y+=16) {
+ if (y< size/2) miny= y+15-size/2;
+ else miny= y-size/2;
+
+ for (x=0; x<size; x+=16) {
+
+ /* is tile within spotbundle? */
+ a= size/2;
+ if (x< a) minx= x+15-a;
+ else minx= x-a;
+
+ dist = sqrtf((float)(minx * minx + miny * miny));
+
+ if (square==0 && dist>(float)(a+12)) { /* 12, tested with a onlyshadow lamp */
+ a= 256; verg= 0; /* 0x80000000; */ /* 0x7FFFFFFF; */
+ rz1= (&verg)+1;
+ }
+ else {
+ copy_to_ztile(rectz, size, x, y, 16, rcline);
+ rz1= (int *)rcline;
+
+ verg= (*rz1 & 0xFFFFFF00);
+
+ for (a=0;a<256;a++, rz1++) {
+ if ( (*rz1 & 0xFFFFFF00) !=verg) break;
+ }
+ }
+ if (a==256) { /* complete empty tile */
+ *ctile= 0;
+ *ztile= *(rz1-1);
+ }
+ else {
+
+ /* ACOMP etc. are defined to work L/B endian */
+
+ rc= rcline;
+ rz1= (int *)rcline;
+ verg= rc[ACOMP];
+ verg1= rc[BCOMP];
+ rc+= 4;
+ byt1= 1; byt2= 1;
+ for (a=1;a<256;a++, rc+=4) {
+ byt1 &= (verg==rc[ACOMP]);
+ byt2 &= (verg1==rc[BCOMP]);
+
+ if (byt1==0) break;
+ }
+ if (byt1 && byt2) { /* only store byte */
+ *ctile= 1;
+ *ztile= (uintptr_t)MEM_mallocN(256+4, "tile1");
+ rz= (int *)*ztile;
+ *rz= *rz1;
+
+ zt= (char *)(rz+1);
+ rc= rcline;
+ for (a=0; a<256; a++, zt++, rc+=4) *zt= rc[GCOMP];
+ }
+ else if (byt1) { /* only store short */
+ *ctile= 2;
+ *ztile= (uintptr_t)MEM_mallocN(2*256+4, "Tile2");
+ rz= (int *)*ztile;
+ *rz= *rz1;
+
+ zt= (char *)(rz+1);
+ rc= rcline;
+ for (a=0; a<256; a++, zt+=2, rc+=4) {
+ zt[0]= rc[BCOMP];
+ zt[1]= rc[GCOMP];
+ }
+ }
+ else { /* store triple */
+ *ctile= 3;
+ *ztile= (uintptr_t)MEM_mallocN(3*256, "Tile3");
+
+ zt= (char *)*ztile;
+ rc= rcline;
+ for (a=0; a<256; a++, zt+=3, rc+=4) {
+ zt[0]= rc[ACOMP];
+ zt[1]= rc[BCOMP];
+ zt[2]= rc[GCOMP];
+ }
+ }
+ }
+ ztile++;
+ ctile++;
+ }
+ }
+
+ MEM_freeN(rcline);
+}
+
+/* sets start/end clipping. lar->shb should be initialized */
+static void shadowbuf_autoclip(Render *re, LampRen *lar)
+{
+ ObjectInstanceRen *obi;
+ ObjectRen *obr;
+ VlakRen *vlr= NULL;
+ VertRen *ver= NULL;
+ Material *ma= NULL;
+ float minz, maxz, vec[3], viewmat[4][4], obviewmat[4][4];
+ unsigned int lay = -1;
+ int i, a, maxtotvert, ok= 1;
+ char *clipflag;
+
+ minz= 1.0e30f; maxz= -1.0e30f;
+ copy_m4_m4(viewmat, lar->shb->viewmat);
+
+ if (lar->mode & (LA_LAYER|LA_LAYER_SHADOW)) lay= lar->lay;
+
+ maxtotvert= 0;
+ for (obr=re->objecttable.first; obr; obr=obr->next)
+ maxtotvert = max_ii(obr->totvert, maxtotvert);
+
+ clipflag= MEM_callocN(sizeof(char)*maxtotvert, "autoclipflag");
+
+ /* set clip in vertices when face visible */
+ for (i=0, obi=re->instancetable.first; obi; i++, obi=obi->next) {
+ obr= obi->obr;
+
+ if (obi->flag & R_TRANSFORMED)
+ mul_m4_m4m4(obviewmat, viewmat, obi->mat);
+ else
+ copy_m4_m4(obviewmat, viewmat);
+
+ memset(clipflag, 0, sizeof(char)*obr->totvert);
+
+ /* clear clip, is being set if face is visible (clip is calculated for real later) */
+ for (a=0; a<obr->totvlak; a++) {
+ if ((a & 255)==0) vlr= obr->vlaknodes[a>>8].vlak;
+ else vlr++;
+
+ /* note; these conditions are copied from zbuffer_shadow() */
+ if (vlr->mat!= ma) {
+ ma= vlr->mat;
+ ok= 1;
+ if ((ma->mode2 & MA_CASTSHADOW)==0 || (ma->mode & MA_SHADBUF)==0) ok= 0;
+ }
+
+ if (ok && (obi->lay & lay)) {
+ clipflag[vlr->v1->index]= 1;
+ clipflag[vlr->v2->index]= 1;
+ clipflag[vlr->v3->index]= 1;
+ if (vlr->v4) clipflag[vlr->v4->index]= 1;
+ }
+ }
+
+ /* calculate min and max */
+ for (a=0; a< obr->totvert;a++) {
+ if ((a & 255)==0) ver= RE_findOrAddVert(obr, a);
+ else ver++;
+
+ if (clipflag[a]) {
+ copy_v3_v3(vec, ver->co);
+ mul_m4_v3(obviewmat, vec);
+ /* Z on visible side of lamp space */
+ if (vec[2] < 0.0f) {
+ float inpr, z= -vec[2];
+
+ /* since vec is rotated in lampspace, this is how to get the cosine of angle */
+ /* precision is set 20% larger */
+ vec[2]*= 1.2f;
+ normalize_v3(vec);
+ inpr= - vec[2];
+
+ if (inpr>=lar->spotsi) {
+ if (z<minz) minz= z;
+ if (z>maxz) maxz= z;
+ }
+ }
+ }
+ }
+ }
+
+ MEM_freeN(clipflag);
+
+ /* set clipping min and max */
+ if (minz < maxz) {
+ float delta= (maxz - minz); /* threshold to prevent precision issues */
+
+ //printf("minz %f maxz %f delta %f\n", minz, maxz, delta);
+ if (lar->bufflag & LA_SHADBUF_AUTO_START)
+ lar->shb->d= minz - delta*0.02f; /* 0.02 is arbitrary... needs more thinking! */
+ if (lar->bufflag & LA_SHADBUF_AUTO_END)
+ lar->shb->clipend= maxz + delta*0.1f;
+
+ /* bias was calculated as percentage, we scale it to prevent animation issues */
+ delta= (lar->clipend-lar->clipsta)/(lar->shb->clipend-lar->shb->d);
+ //printf("bias delta %f\n", delta);
+ lar->shb->bias= (int) (delta*(float)lar->shb->bias);
+ }
+}
+
+static void makeflatshadowbuf(Render *re, LampRen *lar, float *jitbuf)
+{
+ ShadBuf *shb= lar->shb;
+ int *rectz, samples;
+
+ /* zbuffering */
+ rectz= MEM_mapallocN(sizeof(int)*shb->size*shb->size, "makeshadbuf");
+
+ for (samples=0; samples<shb->totbuf; samples++) {
+ zbuffer_shadow(re, shb->persmat, lar, rectz, shb->size, jitbuf[2*samples], jitbuf[2*samples+1]);
+ /* create Z tiles (for compression): this system is 24 bits!!! */
+ compress_shadowbuf(shb, rectz, lar->mode & LA_SQUARE);
+
+ if (re->test_break(re->tbh))
+ break;
+ }
+
+ MEM_freeN(rectz);
+}
+
+static void makedeepshadowbuf(Render *re, LampRen *lar, float *jitbuf)
+{
+ ShadBuf *shb= lar->shb;
+ APixstr *apixbuf;
+ APixstrand *apixbufstrand= NULL;
+ ListBase apsmbase= {NULL, NULL};
+
+ /* zbuffering */
+ apixbuf= MEM_callocN(sizeof(APixstr)*shb->size*shb->size, "APixbuf");
+ if (re->totstrand)
+ apixbufstrand= MEM_callocN(sizeof(APixstrand)*shb->size*shb->size, "APixbufstrand");
+
+ zbuffer_abuf_shadow(re, lar, shb->persmat, apixbuf, apixbufstrand, &apsmbase, shb->size,
+ shb->totbuf, (float(*)[2])jitbuf);
+
+ /* create Z tiles (for compression): this system is 24 bits!!! */
+ compress_deepshadowbuf(re, shb, apixbuf, apixbufstrand);
+
+ MEM_freeN(apixbuf);
+ if (apixbufstrand)
+ MEM_freeN(apixbufstrand);
+ freepsA(&apsmbase);
+}
+
+void makeshadowbuf(Render *re, LampRen *lar)
+{
+ ShadBuf *shb= lar->shb;
+ float wsize, *jitbuf, twozero[2]= {0.0f, 0.0f}, angle, temp;
+
+ if (lar->bufflag & (LA_SHADBUF_AUTO_START|LA_SHADBUF_AUTO_END))
+ shadowbuf_autoclip(re, lar);
+
+ /* just to enforce identical behavior of all irregular buffers */
+ if (lar->buftype==LA_SHADBUF_IRREGULAR)
+ shb->size= 1024;
+
+ /* matrices and window: in winmat the transformation is being put,
+ * transforming from observer view to lamp view, including lamp window matrix */
+
+ angle= saacos(lar->spotsi);
+ temp = 0.5f * shb->size * cosf(angle) / sinf(angle);
+ shb->pixsize= (shb->d)/temp;
+ wsize= shb->pixsize*(shb->size/2.0f);
+
+ perspective_m4(shb->winmat, -wsize, wsize, -wsize, wsize, shb->d, shb->clipend);
+ mul_m4_m4m4(shb->persmat, shb->winmat, shb->viewmat);
+
+ if (ELEM(lar->buftype, LA_SHADBUF_REGULAR, LA_SHADBUF_HALFWAY, LA_SHADBUF_DEEP)) {
+ shb->totbuf= lar->buffers;
+
+ /* jitter, weights - not threadsafe! */
+ BLI_thread_lock(LOCK_CUSTOM1);
+ shb->jit= give_jitter_tab(get_render_shadow_samples(&re->r, shb->samp));
+ make_jitter_weight_tab(re, shb, lar->filtertype);
+ BLI_thread_unlock(LOCK_CUSTOM1);
+
+ if (shb->totbuf==4) jitbuf= give_jitter_tab(2);
+ else if (shb->totbuf==9) jitbuf= give_jitter_tab(3);
+ else jitbuf= twozero;
+
+ /* zbuffering */
+ if (lar->buftype == LA_SHADBUF_DEEP) {
+ makedeepshadowbuf(re, lar, jitbuf);
+ shb->totbuf= 1;
+ }
+ else
+ makeflatshadowbuf(re, lar, jitbuf);
+
+ /* printf("lampbuf %d\n", sizeoflampbuf(shb)); */
+ }
+}
+
+static void *do_shadow_thread(void *re_v)
+{
+ Render *re = (Render *)re_v;
+ LampRen *lar;
+
+ do {
+ BLI_thread_lock(LOCK_CUSTOM1);
+ for (lar=re->lampren.first; lar; lar=lar->next) {
+ if (lar->shb && !lar->thread_assigned) {
+ lar->thread_assigned= 1;
+ break;
+ }
+ }
+ BLI_thread_unlock(LOCK_CUSTOM1);
+
+ /* if type is irregular, this only sets the perspective matrix and autoclips */
+ if (lar) {
+ makeshadowbuf(re, lar);
+ BLI_thread_lock(LOCK_CUSTOM1);
+ lar->thread_ready= 1;
+ BLI_thread_unlock(LOCK_CUSTOM1);
+ }
+ } while (lar && !re->test_break(re->tbh));
+
+ return NULL;
+}
+
+static volatile int g_break= 0;
+static int thread_break(void *UNUSED(arg))
+{
+ return g_break;
+}
+
+void threaded_makeshadowbufs(Render *re)
+{
+ ListBase threads;
+ LampRen *lar;
+ int a, totthread= 0;
+ int (*test_break)(void *);
+
+ /* count number of threads to use */
+ if (G.is_rendering) {
+ for (lar=re->lampren.first; lar; lar= lar->next)
+ if (lar->shb)
+ totthread++;
+
+ totthread = min_ii(totthread, re->r.threads);
+ }
+ else
+ totthread = 1; /* preview render */
+
+ if (totthread <= 1) {
+ for (lar=re->lampren.first; lar; lar= lar->next) {
+ if (re->test_break(re->tbh)) break;
+ if (lar->shb) {
+ /* if type is irregular, this only sets the perspective matrix and autoclips */
+ makeshadowbuf(re, lar);
+ }
+ }
+ }
+ else {
+ /* swap test break function */
+ test_break= re->test_break;
+ re->test_break= thread_break;
+
+ for (lar=re->lampren.first; lar; lar= lar->next) {
+ lar->thread_assigned= 0;
+ lar->thread_ready= 0;
+ }
+
+ BLI_threadpool_init(&threads, do_shadow_thread, totthread);
+
+ for (a=0; a<totthread; a++)
+ BLI_threadpool_insert(&threads, re);
+
+ /* keep rendering as long as there are shadow buffers not ready */
+ do {
+ if ((g_break=test_break(re->tbh)))
+ break;
+
+ PIL_sleep_ms(50);
+
+ BLI_thread_lock(LOCK_CUSTOM1);
+ for (lar=re->lampren.first; lar; lar= lar->next)
+ if (lar->shb && !lar->thread_ready)
+ break;
+ BLI_thread_unlock(LOCK_CUSTOM1);
+ } while (lar);
+
+ BLI_threadpool_end(&threads);
+
+ /* unset threadsafety */
+ re->test_break= test_break;
+ g_break= 0;
+ }
+}
+
+void freeshadowbuf(LampRen *lar)
+{
+ if (lar->shb) {
+ ShadBuf *shb= lar->shb;
+ ShadSampleBuf *shsample;
+ int b, v;
+
+ for (shsample= shb->buffers.first; shsample; shsample= shsample->next) {
+ if (shsample->deepbuf) {
+ v= shb->size*shb->size;
+ for (b=0; b<v; b++)
+ if (shsample->deepbuf[b])
+ MEM_freeN(shsample->deepbuf[b]);
+
+ MEM_freeN(shsample->deepbuf);
+ MEM_freeN(shsample->totbuf);
+ }
+ else {
+ intptr_t *ztile= shsample->zbuf;
+ const char *ctile= shsample->cbuf;
+
+ v= (shb->size*shb->size)/256;
+ for (b=0; b<v; b++, ztile++, ctile++)
+ if (*ctile) MEM_freeN((void *) *ztile);
+
+ MEM_freeN(shsample->zbuf);
+ MEM_freeN(shsample->cbuf);
+ }
+ }
+ BLI_freelistN(&shb->buffers);
+
+ if (shb->weight) MEM_freeN(shb->weight);
+ MEM_freeN(lar->shb);
+
+ lar->shb= NULL;
+ }
+}
+
+
+static int firstreadshadbuf(ShadBuf *shb, ShadSampleBuf *shsample, int **rz, int xs, int ys, int nr)
+{
+ /* return a 1 if fully compressed shadbuf-tile && z==const */
+ int ofs;
+ const char *ct;
+
+ if (shsample->deepbuf)
+ return 0;
+
+ /* always test borders of shadowbuffer */
+ if (xs<0) xs= 0; else if (xs>=shb->size) xs= shb->size-1;
+ if (ys<0) ys= 0; else if (ys>=shb->size) ys= shb->size-1;
+
+ /* calc z */
+ ofs= (ys>>4)*(shb->size>>4) + (xs>>4);
+ ct= shsample->cbuf+ofs;
+ if (*ct==0) {
+ if (nr==0) {
+ *rz= *( (int **)(shsample->zbuf+ofs) );
+ return 1;
+ }
+ else if (*rz!= *( (int **)(shsample->zbuf+ofs) )) return 0;
+
+ return 1;
+ }
+
+ return 0;
+}
+
+static float readdeepvisibility(DeepSample *dsample, int tot, int z, int bias, float *biast)
+{
+ DeepSample *ds, *prevds;
+ float t;
+ int a;
+
+ /* tricky stuff here; we use ints which can overflow easily with bias values */
+
+ ds= dsample;
+ for (a=0; a<tot && (z-bias > ds->z); a++, ds++) {}
+
+ if (a == tot) {
+ if (biast)
+ *biast= 0.0f;
+ return (ds-1)->v; /* completely behind all samples */
+ }
+
+ /* check if this read needs bias blending */
+ if (biast) {
+ if (z > ds->z)
+ *biast= (float)(z - ds->z)/(float)bias;
+ else
+ *biast= 0.0f;
+ }
+
+ if (a == 0)
+ return 1.0f; /* completely in front of all samples */
+
+ /* converting to float early here because ds->z - prevds->z can overflow */
+ prevds= ds-1;
+ t= ((float)(z-bias) - (float)prevds->z)/((float)ds->z - (float)prevds->z);
+ return t*ds->v + (1.0f-t)*prevds->v;
+}
+
+static float readdeepshadowbuf(ShadBuf *shb, ShadSampleBuf *shsample, int bias, int xs, int ys, int zs)
+{
+ float v, biasv, biast;
+ int ofs, tot;
+
+ if (zs < - 0x7FFFFE00 + bias)
+ return 1.0; /* extreme close to clipstart */
+
+ /* calc z */
+ ofs= ys*shb->size + xs;
+ tot= shsample->totbuf[ofs];
+ if (tot == 0)
+ return 1.0f;
+
+ v= readdeepvisibility(shsample->deepbuf[ofs], tot, zs, bias, &biast);
+
+ if (biast != 0.0f) {
+ /* in soft bias area */
+ biasv = readdeepvisibility(shsample->deepbuf[ofs], tot, zs, 0, NULL);
+
+ biast= biast*biast;
+ return (1.0f-biast)*v + biast*biasv;
+ }
+
+ return v;
+}
+
+/* return 1.0 : fully in light */
+static float readshadowbuf(ShadBuf *shb, ShadSampleBuf *shsample, int bias, int xs, int ys, int zs)
+{
+ float temp;
+ int *rz, ofs;
+ int zsamp=0;
+ char *ct, *cz;
+
+ /* simpleclip */
+ /* if (xs<0 || ys<0) return 1.0; */
+ /* if (xs>=shb->size || ys>=shb->size) return 1.0; */
+
+ /* always test borders of shadowbuffer */
+ if (xs<0) xs= 0; else if (xs>=shb->size) xs= shb->size-1;
+ if (ys<0) ys= 0; else if (ys>=shb->size) ys= shb->size-1;
+
+ if (shsample->deepbuf)
+ return readdeepshadowbuf(shb, shsample, bias, xs, ys, zs);
+
+ /* calc z */
+ ofs= (ys>>4)*(shb->size>>4) + (xs>>4);
+ ct= shsample->cbuf+ofs;
+ rz= *( (int **)(shsample->zbuf+ofs) );
+
+ if (*ct==3) {
+ ct= ((char *)rz)+3*16*(ys & 15)+3*(xs & 15);
+ cz= (char *)&zsamp;
+ cz[ACOMP]= ct[0];
+ cz[BCOMP]= ct[1];
+ cz[GCOMP]= ct[2];
+ }
+ else if (*ct==2) {
+ ct= ((char *)rz);
+ ct+= 4+2*16*(ys & 15)+2*(xs & 15);
+ zsamp= *rz;
+
+ cz= (char *)&zsamp;
+ cz[BCOMP]= ct[0];
+ cz[GCOMP]= ct[1];
+ }
+ else if (*ct==1) {
+ ct= ((char *)rz);
+ ct+= 4+16*(ys & 15)+(xs & 15);
+ zsamp= *rz;
+
+ cz= (char *)&zsamp;
+ cz[GCOMP]= ct[0];
+
+ }
+ else {
+ /* got warning on this for 64 bits.... */
+ /* but it's working code! in this case rz is not a pointer but zvalue (ton) */
+ zsamp= GET_INT_FROM_POINTER(rz);
+ }
+
+ /* tricky stuff here; we use ints which can overflow easily with bias values */
+
+ if (zsamp > zs) return 1.0; /* absolute no shadow */
+ else if (zs < - 0x7FFFFE00 + bias) return 1.0; /* extreme close to clipstart */
+ else if (zsamp < zs-bias) return 0.0; /* absolute in shadow */
+ else { /* soft area */
+
+ temp= ( (float)(zs- zsamp) )/(float)bias;
+ return 1.0f - temp*temp;
+
+ }
+}
+
+static void shadowbuf_project_co(float *x, float *y, float *z, ShadBuf *shb, const float co[3])
+{
+ float hco[4], size= 0.5f*(float)shb->size;
+
+ copy_v3_v3(hco, co);
+ hco[3]= 1.0f;
+
+ mul_m4_v4(shb->persmat, hco);
+
+ *x= size*(1.0f+hco[0]/hco[3]);
+ *y= size*(1.0f+hco[1]/hco[3]);
+ if (z) *z= (hco[2]/hco[3]);
+}
+
+/* the externally called shadow testing (reading) function */
+/* return 1.0: no shadow at all */
+float testshadowbuf(Render *re, ShadBuf *shb, const float co[3], const float dxco[3], const float dyco[3], float inp, float mat_bias)
+{
+ ShadSampleBuf *shsample;
+ float fac, dco[3], dx[3], dy[3], shadfac=0.0f;
+ float xs1, ys1, zs1, *jit, *weight, xres, yres, biasf;
+ int xs, ys, zs, bias, *rz;
+ short a, num;
+
+ /* crash preventer */
+ if (shb->buffers.first==NULL)
+ return 1.0f;
+
+ /* when facing away, assume fully in shadow */
+ if (inp <= 0.0f)
+ return 0.0f;
+
+ /* project coordinate to pixel space */
+ shadowbuf_project_co(&xs1, &ys1, &zs1, shb, co);
+
+ /* clip z coordinate, z is projected so that (-1.0, 1.0) matches
+ * (clipstart, clipend), so we can do this simple test */
+ if (zs1>=1.0f)
+ return 0.0f;
+ else if (zs1<= -1.0f)
+ return 1.0f;
+
+ zs= ((float)0x7FFFFFFF)*zs1;
+
+ /* take num*num samples, increase area with fac */
+ num= get_render_shadow_samples(&re->r, shb->samp);
+ num= num*num;
+ fac= shb->soft;
+
+ /* compute z bias */
+ if (mat_bias!=0.0f) biasf= shb->bias*mat_bias;
+ else biasf= shb->bias;
+ /* with inp==1.0, bias is half the size. correction value was 1.1, giving errors
+ * on cube edges, with one side being almost frontal lighted (ton) */
+ bias= (1.5f-inp*inp)*biasf;
+
+ /* in case of no filtering we can do things simpler */
+ if (num==1) {
+ for (shsample= shb->buffers.first; shsample; shsample= shsample->next)
+ shadfac += readshadowbuf(shb, shsample, bias, (int)xs1, (int)ys1, zs);
+
+ return shadfac/(float)shb->totbuf;
+ }
+
+ /* calculate filter size */
+ add_v3_v3v3(dco, co, dxco);
+ shadowbuf_project_co(&dx[0], &dx[1], NULL, shb, dco);
+ dx[0]= xs1 - dx[0];
+ dx[1]= ys1 - dx[1];
+
+ add_v3_v3v3(dco, co, dyco);
+ shadowbuf_project_co(&dy[0], &dy[1], NULL, shb, dco);
+ dy[0]= xs1 - dy[0];
+ dy[1]= ys1 - dy[1];
+
+ xres = fac * (fabsf(dx[0]) + fabsf(dy[0]));
+ yres = fac * (fabsf(dx[1]) + fabsf(dy[1]));
+ if (xres<1.0f) xres= 1.0f;
+ if (yres<1.0f) yres= 1.0f;
+
+ /* make xs1/xs1 corner of sample area */
+ xs1 -= xres*0.5f;
+ ys1 -= yres*0.5f;
+
+ /* in case we have a constant value in a tile, we can do quicker lookup */
+ if (xres<16.0f && yres<16.0f) {
+ shsample= shb->buffers.first;
+ if (firstreadshadbuf(shb, shsample, &rz, (int)xs1, (int)ys1, 0)) {
+ if (firstreadshadbuf(shb, shsample, &rz, (int)(xs1+xres), (int)ys1, 1)) {
+ if (firstreadshadbuf(shb, shsample, &rz, (int)xs1, (int)(ys1+yres), 1)) {
+ if (firstreadshadbuf(shb, shsample, &rz, (int)(xs1+xres), (int)(ys1+yres), 1)) {
+ return readshadowbuf(shb, shsample, bias, (int)xs1, (int)ys1, zs);
+ }
+ }
+ }
+ }
+ }
+
+ /* full jittered shadow buffer lookup */
+ for (shsample= shb->buffers.first; shsample; shsample= shsample->next) {
+ jit= shb->jit;
+ weight= shb->weight;
+
+ for (a=num; a>0; a--, jit+=2, weight++) {
+ /* instead of jit i tried random: ugly! */
+ /* note: the plus 0.5 gives best sampling results, jit goes from -0.5 to 0.5 */
+ /* xs1 and ys1 are already corrected to be corner of sample area */
+ xs= xs1 + xres*(jit[0] + 0.5f);
+ ys= ys1 + yres*(jit[1] + 0.5f);
+
+ shadfac+= *weight * readshadowbuf(shb, shsample, bias, xs, ys, zs);
+ }
+ }
+
+ /* Renormalizes for the sample number: */
+ return shadfac/(float)shb->totbuf;
+}
+
+/* different function... sampling behind clipend can be LIGHT, bias is negative! */
+/* return: light */
+static float readshadowbuf_halo(ShadBuf *shb, ShadSampleBuf *shsample, int xs, int ys, int zs)
+{
+ float temp;
+ int *rz, ofs;
+ int bias, zbias, zsamp;
+ char *ct, *cz;
+
+ /* negative! The other side is more important */
+ bias= -shb->bias;
+
+ /* simpleclip */
+ if (xs<0 || ys<0) return 0.0;
+ if (xs>=shb->size || ys>=shb->size) return 0.0;
+
+ /* calc z */
+ ofs= (ys>>4)*(shb->size>>4) + (xs>>4);
+ ct= shsample->cbuf+ofs;
+ rz= *( (int **)(shsample->zbuf+ofs) );
+
+ if (*ct==3) {
+ ct= ((char *)rz)+3*16*(ys & 15)+3*(xs & 15);
+ cz= (char *)&zsamp;
+ zsamp= 0;
+ cz[ACOMP]= ct[0];
+ cz[BCOMP]= ct[1];
+ cz[GCOMP]= ct[2];
+ }
+ else if (*ct==2) {
+ ct= ((char *)rz);
+ ct+= 4+2*16*(ys & 15)+2*(xs & 15);
+ zsamp= *rz;
+
+ cz= (char *)&zsamp;
+ cz[BCOMP]= ct[0];
+ cz[GCOMP]= ct[1];
+ }
+ else if (*ct==1) {
+ ct= ((char *)rz);
+ ct+= 4+16*(ys & 15)+(xs & 15);
+ zsamp= *rz;
+
+ cz= (char *)&zsamp;
+ cz[GCOMP]= ct[0];
+
+ }
+ else {
+ /* same as before */
+ /* still working code! (ton) */
+ zsamp= GET_INT_FROM_POINTER(rz);
+ }
+
+ /* NO schadow when sampled at 'eternal' distance */
+
+ if (zsamp >= 0x7FFFFE00) return 1.0;
+
+ if (zsamp > zs) return 1.0; /* absolute no shadww */
+ else {
+ /* bias is negative, so the (zs-bias) can be beyond 0x7fffffff */
+ zbias= 0x7fffffff - zs;
+ if (zbias > -bias) {
+ if ( zsamp < zs-bias) return 0.0; /* absolute in shadow */
+ }
+ else return 0.0; /* absolute shadow */
+ }
+
+ /* soft area */
+
+ temp= ( (float)(zs- zsamp) )/(float)bias;
+ return 1.0f - temp*temp;
+}
+
+
+float shadow_halo(LampRen *lar, const float p1[3], const float p2[3])
+{
+ /* p1 p2 already are rotated in spot-space */
+ ShadBuf *shb= lar->shb;
+ ShadSampleBuf *shsample;
+ float co[4], siz;
+ float lambda, lambda_o, lambda_x, lambda_y, ldx, ldy;
+ float zf, xf1, yf1, zf1, xf2, yf2, zf2;
+ float count, lightcount;
+ int x, y, z, xs1, ys1;
+ int dx = 0, dy = 0;
+
+ siz= 0.5f*(float)shb->size;
+
+ co[0]= p1[0];
+ co[1]= p1[1];
+ co[2]= p1[2]/lar->sh_zfac;
+ co[3]= 1.0;
+ mul_m4_v4(shb->winmat, co); /* rational hom co */
+ xf1= siz*(1.0f+co[0]/co[3]);
+ yf1= siz*(1.0f+co[1]/co[3]);
+ zf1= (co[2]/co[3]);
+
+
+ co[0]= p2[0];
+ co[1]= p2[1];
+ co[2]= p2[2]/lar->sh_zfac;
+ co[3]= 1.0;
+ mul_m4_v4(shb->winmat, co); /* rational hom co */
+ xf2= siz*(1.0f+co[0]/co[3]);
+ yf2= siz*(1.0f+co[1]/co[3]);
+ zf2= (co[2]/co[3]);
+
+ /* the 2dda (a pixel line formula) */
+
+ xs1= (int)xf1;
+ ys1= (int)yf1;
+
+ if (xf1 != xf2) {
+ if (xf2-xf1 > 0.0f) {
+ lambda_x= (xf1-xs1-1.0f)/(xf1-xf2);
+ ldx= -shb->shadhalostep/(xf1-xf2);
+ dx= shb->shadhalostep;
+ }
+ else {
+ lambda_x= (xf1-xs1)/(xf1-xf2);
+ ldx= shb->shadhalostep/(xf1-xf2);
+ dx= -shb->shadhalostep;
+ }
+ }
+ else {
+ lambda_x= 1.0;
+ ldx= 0.0;
+ }
+
+ if (yf1 != yf2) {
+ if (yf2-yf1 > 0.0f) {
+ lambda_y= (yf1-ys1-1.0f)/(yf1-yf2);
+ ldy= -shb->shadhalostep/(yf1-yf2);
+ dy= shb->shadhalostep;
+ }
+ else {
+ lambda_y= (yf1-ys1)/(yf1-yf2);
+ ldy= shb->shadhalostep/(yf1-yf2);
+ dy= -shb->shadhalostep;
+ }
+ }
+ else {
+ lambda_y= 1.0;
+ ldy= 0.0;
+ }
+
+ x= xs1;
+ y= ys1;
+ lambda= count= lightcount= 0.0;
+
+/* printf("start %x %x \n", (int)(0x7FFFFFFF*zf1), (int)(0x7FFFFFFF*zf2)); */
+
+ do {
+ lambda_o= lambda;
+
+ if (lambda_x==lambda_y) {
+ lambda_x+= ldx;
+ x+= dx;
+ lambda_y+= ldy;
+ y+= dy;
+ }
+ else {
+ if (lambda_x<lambda_y) {
+ lambda_x+= ldx;
+ x+= dx;
+ }
+ else {
+ lambda_y+= ldy;
+ y+= dy;
+ }
+ }
+
+ lambda = min_ff(lambda_x, lambda_y);
+
+ /* not making any progress? */
+ if (lambda==lambda_o) break;
+
+ /* clip to end of volume */
+ lambda = min_ff(lambda, 1.0f);
+
+ zf= zf1 + lambda*(zf2-zf1);
+ count+= (float)shb->totbuf;
+
+ if (zf<= -1.0f) lightcount += 1.0f; /* close to the spot */
+ else {
+
+ /* make sure, behind the clipend we extend halolines. */
+ if (zf>=1.0f) z= 0x7FFFF000;
+ else z= (int)(0x7FFFF000*zf);
+
+ for (shsample= shb->buffers.first; shsample; shsample= shsample->next)
+ lightcount+= readshadowbuf_halo(shb, shsample, x, y, z);
+
+ }
+ }
+ while (lambda < 1.0f);
+
+ if (count!=0.0f) return (lightcount/count);
+ return 0.0f;
+
+}
+
+
+/* ********************* Irregular Shadow Buffer (ISB) ************* */
+/* ********** storage of all view samples in a raster of lists ***** */
+
+/* based on several articles describing this method, like:
+ * The Irregular Z-Buffer and its Application to Shadow Mapping
+ * Gregory S. Johnson - William R. Mark - Christopher A. Burns
+ * and
+ * Alias-Free Shadow Maps
+ * Timo Aila and Samuli Laine
+ */
+
+/* bsp structure (actually kd tree) */
+
+#define BSPMAX_SAMPLE 128
+#define BSPMAX_DEPTH 32
+
+/* aligned with struct rctf */
+typedef struct Boxf {
+ float xmin, xmax;
+ float ymin, ymax;
+ float zmin, zmax;
+} Boxf;
+
+typedef struct ISBBranch {
+ struct ISBBranch *left, *right;
+ float divider[2];
+ Boxf box;
+ short totsamp, index, full, unused;
+ ISBSample **samples;
+} ISBBranch;
+
+typedef struct BSPFace {
+ Boxf box;
+ const float *v1, *v2, *v3, *v4;
+ int obi; /* object for face lookup */
+ int facenr; /* index to retrieve VlakRen */
+ int type; /* only for strand now */
+ short shad_alpha, is_full;
+
+ /* strand caching data, optimize for point_behind_strand() */
+ float radline, radline_end, len;
+ float vec1[3], vec2[3], rc[3];
+} BSPFace;
+
+/* boxes are in lamp projection */
+static void init_box(Boxf *box)
+{
+ box->xmin = 1000000.0f;
+ box->xmax = 0;
+ box->ymin = 1000000.0f;
+ box->ymax = 0;
+ box->zmin= 0x7FFFFFFF;
+ box->zmax= - 0x7FFFFFFF;
+}
+
+/* use v1 to calculate boundbox */
+static void bound_boxf(Boxf *box, const float v1[3])
+{
+ if (v1[0] < box->xmin) box->xmin = v1[0];
+ if (v1[0] > box->xmax) box->xmax = v1[0];
+ if (v1[1] < box->ymin) box->ymin = v1[1];
+ if (v1[1] > box->ymax) box->ymax = v1[1];
+ if (v1[2] < box->zmin) box->zmin= v1[2];
+ if (v1[2] > box->zmax) box->zmax= v1[2];
+}
+
+/* use v1 to calculate boundbox */
+static void bound_rectf(rctf *box, const float v1[2])
+{
+ if (v1[0] < box->xmin) box->xmin = v1[0];
+ if (v1[0] > box->xmax) box->xmax = v1[0];
+ if (v1[1] < box->ymin) box->ymin = v1[1];
+ if (v1[1] > box->ymax) box->ymax = v1[1];
+}
+
+
+/* halfway splitting, for initializing a more regular tree */
+static void isb_bsp_split_init(ISBBranch *root, MemArena *mem, int level)
+{
+
+ /* if level > 0 we create new branches and go deeper */
+ if (level > 0) {
+ ISBBranch *left, *right;
+ int i;
+
+ /* splitpoint */
+ root->divider[0]= 0.5f*(root->box.xmin+root->box.xmax);
+ root->divider[1]= 0.5f*(root->box.ymin+root->box.ymax);
+
+ /* find best splitpoint */
+ if (RCT_SIZE_X(&root->box) > RCT_SIZE_Y(&root->box))
+ i = root->index = 0;
+ else
+ i = root->index = 1;
+
+ left= root->left= BLI_memarena_alloc(mem, sizeof(ISBBranch));
+ right= root->right= BLI_memarena_alloc(mem, sizeof(ISBBranch));
+
+ /* box info */
+ left->box= root->box;
+ right->box= root->box;
+ if (i==0) {
+ left->box.xmax = root->divider[0];
+ right->box.xmin = root->divider[0];
+ }
+ else {
+ left->box.ymax = root->divider[1];
+ right->box.ymin = root->divider[1];
+ }
+ isb_bsp_split_init(left, mem, level-1);
+ isb_bsp_split_init(right, mem, level-1);
+ }
+ else {
+ /* we add sample array */
+ root->samples= BLI_memarena_alloc(mem, BSPMAX_SAMPLE*sizeof(void *));
+ }
+}
+
+/* note; if all samples on same location we just spread them over 2 new branches */
+static void isb_bsp_split(ISBBranch *root, MemArena *mem)
+{
+ ISBBranch *left, *right;
+ ISBSample *samples[BSPMAX_SAMPLE];
+ int a, i;
+
+ /* splitpoint */
+ root->divider[0]= root->divider[1]= 0.0f;
+ for (a=BSPMAX_SAMPLE-1; a>=0; a--) {
+ root->divider[0]+= root->samples[a]->zco[0];
+ root->divider[1]+= root->samples[a]->zco[1];
+ }
+ root->divider[0]/= BSPMAX_SAMPLE;
+ root->divider[1]/= BSPMAX_SAMPLE;
+
+ /* find best splitpoint */
+ if (RCT_SIZE_X(&root->box) > RCT_SIZE_Y(&root->box))
+ i = root->index = 0;
+ else
+ i = root->index = 1;
+
+ /* new branches */
+ left= root->left= BLI_memarena_alloc(mem, sizeof(ISBBranch));
+ right= root->right= BLI_memarena_alloc(mem, sizeof(ISBBranch));
+
+ /* new sample array */
+ left->samples = BLI_memarena_alloc(mem, BSPMAX_SAMPLE*sizeof(void *));
+ right->samples = samples; /* tmp */
+
+ /* split samples */
+ for (a=BSPMAX_SAMPLE-1; a>=0; a--) {
+ int comp= 0;
+ /* this prevents adding samples all to 1 branch when divider is equal to samples */
+ if (root->samples[a]->zco[i] == root->divider[i])
+ comp= a & 1;
+ else if (root->samples[a]->zco[i] < root->divider[i])
+ comp= 1;
+
+ if (comp==1) {
+ left->samples[left->totsamp]= root->samples[a];
+ left->totsamp++;
+ }
+ else {
+ right->samples[right->totsamp]= root->samples[a];
+ right->totsamp++;
+ }
+ }
+
+ /* copy samples from tmp */
+ memcpy(root->samples, samples, right->totsamp*(sizeof(void *)));
+ right->samples= root->samples;
+ root->samples= NULL;
+
+ /* box info */
+ left->box= root->box;
+ right->box= root->box;
+ if (i==0) {
+ left->box.xmax = root->divider[0];
+ right->box.xmin = root->divider[0];
+ }
+ else {
+ left->box.ymax = root->divider[1];
+ right->box.ymin = root->divider[1];
+ }
+}
+
+/* inserts sample in main tree, also splits on threshold */
+/* returns 1 if error */
+static int isb_bsp_insert(ISBBranch *root, MemArena *memarena, ISBSample *sample)
+{
+ ISBBranch *bspn= root;
+ const float *zco= sample->zco;
+ int i= 0;
+
+ /* debug counter, also used to check if something was filled in ever */
+ root->totsamp++;
+
+ /* going over branches until last one found */
+ while (bspn->left) {
+ if (zco[bspn->index] <= bspn->divider[bspn->index])
+ bspn= bspn->left;
+ else
+ bspn= bspn->right;
+ i++;
+ }
+ /* bspn now is the last branch */
+
+ if (bspn->totsamp==BSPMAX_SAMPLE) {
+ printf("error in bsp branch\n"); /* only for debug, cannot happen */
+ return 1;
+ }
+
+ /* insert */
+ bspn->samples[bspn->totsamp]= sample;
+ bspn->totsamp++;
+
+ /* split if allowed and needed */
+ if (bspn->totsamp==BSPMAX_SAMPLE) {
+ if (i==BSPMAX_DEPTH) {
+ bspn->totsamp--; /* stop filling in... will give errors */
+ return 1;
+ }
+ isb_bsp_split(bspn, memarena);
+ }
+ return 0;
+}
+
+/* initialize vars in face, for optimal point-in-face test */
+static void bspface_init_strand(BSPFace *face)
+{
+
+ face->radline= 0.5f* len_v2v2(face->v1, face->v2);
+
+ mid_v3_v3v3(face->vec1, face->v1, face->v2);
+ if (face->v4)
+ mid_v3_v3v3(face->vec2, face->v3, face->v4);
+ else
+ copy_v3_v3(face->vec2, face->v3);
+
+ face->rc[0]= face->vec2[0]-face->vec1[0];
+ face->rc[1]= face->vec2[1]-face->vec1[1];
+ face->rc[2]= face->vec2[2]-face->vec1[2];
+
+ face->len= face->rc[0]*face->rc[0]+ face->rc[1]*face->rc[1];
+
+ if (face->len != 0.0f) {
+ face->radline_end = face->radline / sqrtf(face->len);
+ face->len = 1.0f / face->len;
+ }
+}
+
+/* brought back to a simple 2d case */
+static int point_behind_strand(const float p[3], BSPFace *face)
+{
+ /* v1 - v2 is radius, v1 - v3 length */
+ float dist, rc[2], pt[2];
+
+ /* using code from dist_to_line_segment_v2(), distance vec to line-piece */
+
+ if (face->len==0.0f) {
+ rc[0]= p[0]-face->vec1[0];
+ rc[1]= p[1]-face->vec1[1];
+ dist = len_v2(rc);
+
+ if (dist < face->radline)
+ return 1;
+ }
+ else {
+ float lambda= ( face->rc[0]*(p[0]-face->vec1[0]) + face->rc[1]*(p[1]-face->vec1[1]) )*face->len;
+
+ if (lambda > -face->radline_end && lambda < 1.0f+face->radline_end) {
+ /* hesse for dist: */
+ //dist= (float)(fabs( (p[0]-vec2[0])*rc[1] + (p[1]-vec2[1])*rc[0])/len);
+
+ pt[0]= lambda*face->rc[0]+face->vec1[0];
+ pt[1]= lambda*face->rc[1]+face->vec1[1];
+
+ rc[0]= pt[0]-p[0];
+ rc[1]= pt[1]-p[1];
+ dist = len_v2(rc);
+
+ if (dist < face->radline) {
+ float zval= face->vec1[2] + lambda*face->rc[2];
+ if (p[2] > zval)
+ return 1;
+ }
+ }
+ }
+ return 0;
+}
+
+
+/* return 1 if inside. code derived from src/parametrizer.c */
+static int point_behind_tria2d(const float p[3], const float v1[3], const float v2[3], const float v3[3])
+{
+ float a[2], c[2], h[2], div;
+ float u, v;
+
+ a[0] = v2[0] - v1[0];
+ a[1] = v2[1] - v1[1];
+ c[0] = v3[0] - v1[0];
+ c[1] = v3[1] - v1[1];
+
+ div = a[0]*c[1] - a[1]*c[0];
+ if (div==0.0f)
+ return 0;
+
+ h[0] = p[0] - v1[0];
+ h[1] = p[1] - v1[1];
+
+ div = 1.0f/div;
+
+ u = (h[0]*c[1] - h[1]*c[0])*div;
+ if (u >= 0.0f) {
+ v = (a[0]*h[1] - a[1]*h[0])*div;
+ if (v >= 0.0f) {
+ if ( u + v <= 1.0f) {
+ /* inside, now check if point p is behind */
+ float z= (1.0f-u-v)*v1[2] + u*v2[2] + v*v3[2];
+ if (z <= p[2])
+ return 1;
+ }
+ }
+ }
+
+ return 0;
+}
+
+#if 0
+/* tested these calls, but it gives inaccuracy, 'side' cannot be found reliably using v3 */
+
+/* check if line v1-v2 has all rect points on other side of point v3 */
+static int rect_outside_line(rctf *rect, const float v1[3], const float v2[3], const float v3[3])
+{
+ float a, b, c;
+ int side;
+
+ /* line formula for v1-v2 */
+ a= v2[1]-v1[1];
+ b= v1[0]-v2[0];
+ c= -a*v1[0] - b*v1[1];
+ side= a*v3[0] + b*v3[1] + c < 0.0f;
+
+ /* the four quad points */
+ if ( side==(rect->xmin*a + rect->ymin*b + c >= 0.0f) )
+ if ( side==(rect->xmax*a + rect->ymin*b + c >= 0.0f) )
+ if ( side==(rect->xmax*a + rect->ymax*b + c >= 0.0f) )
+ if ( side==(rect->xmin*a + rect->ymax*b + c >= 0.0f) )
+ return 1;
+ return 0;
+}
+
+/* check if one of the triangle edges separates all rect points on 1 side */
+static int rect_isect_tria(rctf *rect, const float v1[3], const float v2[3], const float v3[3])
+{
+ if (rect_outside_line(rect, v1, v2, v3))
+ return 0;
+ if (rect_outside_line(rect, v2, v3, v1))
+ return 0;
+ if (rect_outside_line(rect, v3, v1, v2))
+ return 0;
+ return 1;
+}
+#endif
+
+/* if face overlaps a branch, it executes func. recursive */
+static void isb_bsp_face_inside(ISBBranch *bspn, BSPFace *face)
+{
+
+ /* are we descending? */
+ if (bspn->left) {
+ /* hrmf, the box struct cannot be addressed with index */
+ if (bspn->index==0) {
+ if (face->box.xmin <= bspn->divider[0])
+ isb_bsp_face_inside(bspn->left, face);
+ if (face->box.xmax > bspn->divider[0])
+ isb_bsp_face_inside(bspn->right, face);
+ }
+ else {
+ if (face->box.ymin <= bspn->divider[1])
+ isb_bsp_face_inside(bspn->left, face);
+ if (face->box.ymax > bspn->divider[1])
+ isb_bsp_face_inside(bspn->right, face);
+ }
+ }
+ else {
+ /* else: end branch reached */
+ int a;
+
+ if (bspn->totsamp==0) return;
+
+ /* check for nodes entirely in shadow, can be skipped */
+ if (bspn->totsamp==bspn->full)
+ return;
+
+ /* if bsp node is entirely in front of face, give up */
+ if (bspn->box.zmax < face->box.zmin)
+ return;
+
+ /* if face boundbox is outside of branch rect, give up */
+ if (0==BLI_rctf_isect((rctf *)&face->box, (rctf *)&bspn->box, NULL))
+ return;
+
+ /* test all points inside branch */
+ for (a=bspn->totsamp-1; a>=0; a--) {
+ ISBSample *samp= bspn->samples[a];
+
+ if ((samp->facenr!=face->facenr || samp->obi!=face->obi) && samp->shadfac) {
+ if (face->box.zmin < samp->zco[2]) {
+ if (BLI_rctf_isect_pt_v((rctf *)&face->box, samp->zco)) {
+ int inshadow= 0;
+
+ if (face->type) {
+ if (point_behind_strand(samp->zco, face))
+ inshadow= 1;
+ }
+ else if ( point_behind_tria2d(samp->zco, face->v1, face->v2, face->v3))
+ inshadow= 1;
+ else if (face->v4 && point_behind_tria2d(samp->zco, face->v1, face->v3, face->v4))
+ inshadow= 1;
+
+ if (inshadow) {
+ *(samp->shadfac) += face->shad_alpha;
+ /* optimize; is_full means shad_alpha==4096 */
+ if (*(samp->shadfac) >= 4096 || face->is_full) {
+ bspn->full++;
+ samp->shadfac= NULL;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+/* based on available samples, recalculate the bounding box for bsp nodes, recursive */
+static void isb_bsp_recalc_box(ISBBranch *root)
+{
+ if (root->left) {
+ isb_bsp_recalc_box(root->left);
+ isb_bsp_recalc_box(root->right);
+ }
+ else if (root->totsamp) {
+ int a;
+
+ init_box(&root->box);
+ for (a=root->totsamp-1; a>=0; a--)
+ bound_boxf(&root->box, root->samples[a]->zco);
+ }
+}
+
+/* callback function for zbuf clip */
+static void isb_bsp_test_strand(ZSpan *zspan, int obi, int zvlnr,
+ const float *v1, const float *v2, const float *v3, const float *v4)
+{
+ BSPFace face;
+
+ face.v1= v1;
+ face.v2= v2;
+ face.v3= v3;
+ face.v4= v4;
+ face.obi= obi;
+ face.facenr= zvlnr & ~RE_QUAD_OFFS;
+ face.type= R_STRAND;
+ if (R.osa)
+ face.shad_alpha= (short)ceil(4096.0f*zspan->shad_alpha/(float)R.osa);
+ else
+ face.shad_alpha= (short)ceil(4096.0f*zspan->shad_alpha);
+
+ face.is_full= (zspan->shad_alpha==1.0f);
+
+ /* setup boundbox */
+ init_box(&face.box);
+ bound_boxf(&face.box, v1);
+ bound_boxf(&face.box, v2);
+ bound_boxf(&face.box, v3);
+ if (v4)
+ bound_boxf(&face.box, v4);
+
+ /* optimize values */
+ bspface_init_strand(&face);
+
+ isb_bsp_face_inside((ISBBranch *)zspan->rectz, &face);
+
+}
+
+/* callback function for zbuf clip */
+static void isb_bsp_test_face(ZSpan *zspan, int obi, int zvlnr,
+ const float *v1, const float *v2, const float *v3, const float *v4)
+{
+ BSPFace face;
+
+ face.v1= v1;
+ face.v2= v2;
+ face.v3= v3;
+ face.v4= v4;
+ face.obi= obi;
+ face.facenr= zvlnr & ~RE_QUAD_OFFS;
+ face.type= 0;
+ if (R.osa)
+ face.shad_alpha= (short)ceil(4096.0f*zspan->shad_alpha/(float)R.osa);
+ else
+ face.shad_alpha= (short)ceil(4096.0f*zspan->shad_alpha);
+
+ face.is_full= (zspan->shad_alpha==1.0f);
+
+ /* setup boundbox */
+ init_box(&face.box);
+ bound_boxf(&face.box, v1);
+ bound_boxf(&face.box, v2);
+ bound_boxf(&face.box, v3);
+ if (v4)
+ bound_boxf(&face.box, v4);
+
+ isb_bsp_face_inside((ISBBranch *)zspan->rectz, &face);
+}
+
+static int testclip_minmax(const float ho[4], const float minmax[4])
+{
+ float wco= ho[3];
+ int flag= 0;
+
+ if ( ho[0] > minmax[1]*wco) flag = 1;
+ else if ( ho[0]< minmax[0]*wco) flag = 2;
+
+ if ( ho[1] > minmax[3]*wco) flag |= 4;
+ else if ( ho[1]< minmax[2]*wco) flag |= 8;
+
+ return flag;
+}
+
+/* main loop going over all faces and check in bsp overlaps, fill in shadfac values */
+static void isb_bsp_fillfaces(Render *re, LampRen *lar, ISBBranch *root)
+{
+ ObjectInstanceRen *obi;
+ ObjectRen *obr;
+ ShadBuf *shb= lar->shb;
+ ZSpan zspan, zspanstrand;
+ VlakRen *vlr= NULL;
+ Material *ma= NULL;
+ float minmaxf[4], winmat[4][4];
+ int size= shb->size;
+ int i, a, ok=1, lay= -1;
+
+ /* further optimize, also sets minz maxz */
+ isb_bsp_recalc_box(root);
+
+ /* extra clipping for minmax */
+ minmaxf[0]= (2.0f*root->box.xmin - size-2.0f)/size;
+ minmaxf[1]= (2.0f*root->box.xmax - size+2.0f)/size;
+ minmaxf[2]= (2.0f*root->box.ymin - size-2.0f)/size;
+ minmaxf[3]= (2.0f*root->box.ymax - size+2.0f)/size;
+
+ if (lar->mode & (LA_LAYER|LA_LAYER_SHADOW)) lay= lar->lay;
+
+ /* (ab)use zspan, since we use zbuffer clipping code */
+ zbuf_alloc_span(&zspan, size, size, re->clipcrop);
+
+ zspan.zmulx= ((float)size)/2.0f;
+ zspan.zmuly= ((float)size)/2.0f;
+ zspan.zofsx= -0.5f;
+ zspan.zofsy= -0.5f;
+
+ /* pass on bsp root to zspan */
+ zspan.rectz= (int *)root;
+
+ /* filling methods */
+ zspanstrand= zspan;
+ // zspan.zbuflinefunc= zbufline_onlyZ;
+ zspan.zbuffunc= isb_bsp_test_face;
+ zspanstrand.zbuffunc= isb_bsp_test_strand;
+
+ for (i=0, obi=re->instancetable.first; obi; i++, obi=obi->next) {
+ obr= obi->obr;
+
+ if (obi->flag & R_TRANSFORMED)
+ mul_m4_m4m4(winmat, shb->persmat, obi->mat);
+ else
+ copy_m4_m4(winmat, shb->persmat);
+
+ for (a=0; a<obr->totvlak; a++) {
+
+ if ((a & 255)==0) vlr= obr->vlaknodes[a>>8].vlak;
+ else vlr++;
+
+ /* note, these conditions are copied in shadowbuf_autoclip() */
+ if (vlr->mat!= ma) {
+ ma= vlr->mat;
+ ok= 1;
+ if ((ma->mode2 & MA_CASTSHADOW)==0 || (ma->mode & MA_SHADBUF)==0) ok= 0;
+ if (ma->material_type == MA_TYPE_WIRE) ok= 0;
+ zspanstrand.shad_alpha= zspan.shad_alpha= ma->shad_alpha;
+ }
+
+ if (ok && (obi->lay & lay)) {
+ float hoco[4][4];
+ int c1, c2, c3, c4=0;
+ int d1, d2, d3, d4=0;
+ int partclip;
+
+ /* create hocos per face, it is while render */
+ projectvert(vlr->v1->co, winmat, hoco[0]); d1= testclip_minmax(hoco[0], minmaxf);
+ projectvert(vlr->v2->co, winmat, hoco[1]); d2= testclip_minmax(hoco[1], minmaxf);
+ projectvert(vlr->v3->co, winmat, hoco[2]); d3= testclip_minmax(hoco[2], minmaxf);
+ if (vlr->v4) {
+ projectvert(vlr->v4->co, winmat, hoco[3]); d4= testclip_minmax(hoco[3], minmaxf);
+ }
+
+ /* minmax clipping */
+ if (vlr->v4) partclip= d1 & d2 & d3 & d4;
+ else partclip= d1 & d2 & d3;
+
+ if (partclip==0) {
+
+ /* window clipping */
+ c1= testclip(hoco[0]);
+ c2= testclip(hoco[1]);
+ c3= testclip(hoco[2]);
+ if (vlr->v4)
+ c4= testclip(hoco[3]);
+
+ /* ***** NO WIRE YET */
+ if (ma->material_type == MA_TYPE_WIRE) {
+ if (vlr->v4)
+ zbufclipwire(&zspan, i, a+1, vlr->ec, hoco[0], hoco[1], hoco[2], hoco[3], c1, c2, c3, c4);
+ else
+ zbufclipwire(&zspan, i, a+1, vlr->ec, hoco[0], hoco[1], hoco[2], NULL, c1, c2, c3, 0);
+ }
+ else if (vlr->v4) {
+ if (vlr->flag & R_STRAND)
+ zbufclip4(&zspanstrand, i, a+1, hoco[0], hoco[1], hoco[2], hoco[3], c1, c2, c3, c4);
+ else
+ zbufclip4(&zspan, i, a+1, hoco[0], hoco[1], hoco[2], hoco[3], c1, c2, c3, c4);
+ }
+ else
+ zbufclip(&zspan, i, a+1, hoco[0], hoco[1], hoco[2], c1, c2, c3);
+
+ }
+ }
+ }
+ }
+
+ zbuf_free_span(&zspan);
+}
+
+/* returns 1 when the viewpixel is visible in lampbuffer */
+static int viewpixel_to_lampbuf(ShadBuf *shb, ObjectInstanceRen *obi, VlakRen *vlr, float x, float y, float co_r[3])
+{
+ float hoco[4], v1[3], nor[3];
+ float dface, fac, siz;
+
+ RE_vlakren_get_normal(&R, obi, vlr, nor);
+ copy_v3_v3(v1, vlr->v1->co);
+ if (obi->flag & R_TRANSFORMED)
+ mul_m4_v3(obi->mat, v1);
+
+ /* from shadepixel() */
+ dface = dot_v3v3(v1, nor);
+ hoco[3]= 1.0f;
+
+ /* ortho viewplane cannot intersect using view vector originating in (0, 0, 0) */
+ if (R.r.mode & R_ORTHO) {
+ /* x and y 3d coordinate can be derived from pixel coord and winmat */
+ float fx= 2.0f/(R.winx*R.winmat[0][0]);
+ float fy= 2.0f/(R.winy*R.winmat[1][1]);
+
+ hoco[0]= (x - 0.5f*R.winx)*fx - R.winmat[3][0]/R.winmat[0][0];
+ hoco[1]= (y - 0.5f*R.winy)*fy - R.winmat[3][1]/R.winmat[1][1];
+
+ /* using a*x + b*y + c*z = d equation, (a b c) is normal */
+ if (nor[2]!=0.0f)
+ hoco[2]= (dface - nor[0]*hoco[0] - nor[1]*hoco[1])/nor[2];
+ else
+ hoco[2]= 0.0f;
+ }
+ else {
+ float div, view[3];
+
+ calc_view_vector(view, x, y);
+
+ div = dot_v3v3(nor, view);
+ if (div==0.0f)
+ return 0;
+
+ fac= dface/div;
+
+ hoco[0]= fac*view[0];
+ hoco[1]= fac*view[1];
+ hoco[2]= fac*view[2];
+ }
+
+ /* move 3d vector to lampbuf */
+ mul_m4_v4(shb->persmat, hoco); /* rational hom co */
+
+ /* clip We can test for -1.0/1.0 because of the properties of the
+ * coordinate transformations. */
+ fac = fabsf(hoco[3]);
+ if (hoco[0]<-fac || hoco[0]>fac)
+ return 0;
+ if (hoco[1]<-fac || hoco[1]>fac)
+ return 0;
+ if (hoco[2]<-fac || hoco[2]>fac)
+ return 0;
+
+ siz= 0.5f*(float)shb->size;
+ co_r[0]= siz*(1.0f+hoco[0]/hoco[3]) -0.5f;
+ co_r[1]= siz*(1.0f+hoco[1]/hoco[3]) -0.5f;
+ co_r[2]= ((float)0x7FFFFFFF)*(hoco[2]/hoco[3]);
+
+ /* XXXX bias, much less than normal shadbuf, or do we need a constant? */
+ co_r[2] -= 0.05f*shb->bias;
+
+ return 1;
+}
+
+/* storage of shadow results, solid osa and transp case */
+static void isb_add_shadfac(ISBShadfacA **isbsapp, MemArena *mem, int obi, int facenr, short shadfac, short samples)
+{
+ ISBShadfacA *new;
+ float shadfacf;
+
+ /* in osa case, the samples were filled in with factor 1.0/R.osa. if fewer samples we have to correct */
+ if (R.osa)
+ shadfacf= ((float)shadfac*R.osa)/(4096.0f*samples);
+ else
+ shadfacf= ((float)shadfac)/(4096.0f);
+
+ new= BLI_memarena_alloc(mem, sizeof(ISBShadfacA));
+ new->obi= obi;
+ new->facenr= facenr & ~RE_QUAD_OFFS;
+ new->shadfac= shadfacf;
+ if (*isbsapp)
+ new->next= (*isbsapp);
+ else
+ new->next= NULL;
+
+ *isbsapp= new;
+}
+
+/* adding samples, solid case */
+static int isb_add_samples(RenderPart *pa, ISBBranch *root, MemArena *memarena, ISBSample **samplebuf)
+{
+ int xi, yi, *xcos, *ycos;
+ int sample, bsp_err= 0;
+
+ /* bsp split doesn't like to handle regular sequences */
+ xcos= MEM_mallocN(pa->rectx*sizeof(int), "xcos");
+ ycos= MEM_mallocN(pa->recty*sizeof(int), "ycos");
+ for (xi=0; xi<pa->rectx; xi++)
+ xcos[xi]= xi;
+ for (yi=0; yi<pa->recty; yi++)
+ ycos[yi]= yi;
+ BLI_array_randomize(xcos, sizeof(int), pa->rectx, 12345);
+ BLI_array_randomize(ycos, sizeof(int), pa->recty, 54321);
+
+ for (sample=0; sample<(R.osa?R.osa:1); sample++) {
+ ISBSample *samp= samplebuf[sample], *samp1;
+
+ for (yi=0; yi<pa->recty; yi++) {
+ int y= ycos[yi];
+ for (xi=0; xi<pa->rectx; xi++) {
+ int x= xcos[xi];
+ samp1= samp + y*pa->rectx + x;
+ if (samp1->facenr)
+ bsp_err |= isb_bsp_insert(root, memarena, samp1);
+ }
+ if (bsp_err) break;
+ }
+ }
+
+ MEM_freeN(xcos);
+ MEM_freeN(ycos);
+
+ return bsp_err;
+}
+
+/* solid version */
+/* lar->shb, pa->rectz and pa->rectp should exist */
+static void isb_make_buffer(RenderPart *pa, LampRen *lar)
+{
+ ShadBuf *shb= lar->shb;
+ ISBData *isbdata;
+ ISBSample *samp, *samplebuf[16]; /* should be RE_MAX_OSA */
+ ISBBranch root;
+ MemArena *memarena;
+ intptr_t *rd;
+ int *recto, *rectp, x, y, sindex, sample, bsp_err=0;
+
+ /* storage for shadow, per thread */
+ isbdata= shb->isb_result[pa->thread];
+
+ /* to map the shi->xs and ys coordinate */
+ isbdata->minx= pa->disprect.xmin;
+ isbdata->miny= pa->disprect.ymin;
+ isbdata->rectx= pa->rectx;
+ isbdata->recty= pa->recty;
+
+ /* branches are added using memarena (32k branches) */
+ memarena = BLI_memarena_new(0x8000 * sizeof(ISBBranch), "isb arena");
+ BLI_memarena_use_calloc(memarena);
+
+ /* samplebuf is in camera view space (pixels) */
+ for (sample=0; sample<(R.osa?R.osa:1); sample++)
+ samplebuf[sample]= MEM_callocN(sizeof(ISBSample)*pa->rectx*pa->recty, "isb samplebuf");
+
+ /* for end result, ISBSamples point to this in non OSA case, otherwise to pixstruct->shadfac */
+ if (R.osa==0)
+ isbdata->shadfacs= MEM_callocN(pa->rectx*pa->recty*sizeof(short), "isb shadfacs");
+
+ /* setup bsp root */
+ memset(&root, 0, sizeof(ISBBranch));
+ root.box.xmin = (float)shb->size;
+ root.box.ymin = (float)shb->size;
+
+ /* create the sample buffers */
+ for (sindex=0, y=0; y<pa->recty; y++) {
+ for (x=0; x<pa->rectx; x++, sindex++) {
+
+ /* this makes it a long function, but splitting it out would mean 10+ arguments */
+ /* first check OSA case */
+ if (R.osa) {
+ rd= pa->rectdaps + sindex;
+ if (*rd) {
+ float xs= (float)(x + pa->disprect.xmin);
+ float ys= (float)(y + pa->disprect.ymin);
+
+ for (sample=0; sample<R.osa; sample++) {
+ PixStr *ps= (PixStr *)(*rd);
+ int mask= (1<<sample);
+
+ while (ps) {
+ if (ps->mask & mask)
+ break;
+ ps= ps->next;
+ }
+ if (ps && ps->facenr>0) {
+ ObjectInstanceRen *obi= &R.objectinstance[ps->obi];
+ ObjectRen *obr= obi->obr;
+ VlakRen *vlr= RE_findOrAddVlak(obr, (ps->facenr-1) & RE_QUAD_MASK);
+
+ samp= samplebuf[sample] + sindex;
+ /* convert image plane pixel location to lamp buffer space */
+ if (viewpixel_to_lampbuf(shb, obi, vlr, xs + R.jit[sample][0], ys + R.jit[sample][1], samp->zco)) {
+ samp->obi= ps->obi;
+ samp->facenr= ps->facenr & ~RE_QUAD_OFFS;
+ ps->shadfac= 0;
+ samp->shadfac= &ps->shadfac;
+ bound_rectf((rctf *)&root.box, samp->zco);
+ }
+ }
+ }
+ }
+ }
+ else {
+ rectp= pa->rectp + sindex;
+ recto= pa->recto + sindex;
+ if (*rectp>0) {
+ ObjectInstanceRen *obi= &R.objectinstance[*recto];
+ ObjectRen *obr= obi->obr;
+ VlakRen *vlr= RE_findOrAddVlak(obr, (*rectp-1) & RE_QUAD_MASK);
+ float xs= (float)(x + pa->disprect.xmin);
+ float ys= (float)(y + pa->disprect.ymin);
+
+ samp= samplebuf[0] + sindex;
+ /* convert image plane pixel location to lamp buffer space */
+ if (viewpixel_to_lampbuf(shb, obi, vlr, xs, ys, samp->zco)) {
+ samp->obi= *recto;
+ samp->facenr= *rectp & ~RE_QUAD_OFFS;
+ samp->shadfac= isbdata->shadfacs + sindex;
+ bound_rectf((rctf *)&root.box, samp->zco);
+ }
+ }
+ }
+ }
+ }
+
+ /* simple method to see if we have samples */
+ if (root.box.xmin != (float)shb->size) {
+ /* now create a regular split, root.box has the initial bounding box of all pixels */
+ /* split bsp 8 levels deep, in regular grid (16 x 16) */
+ isb_bsp_split_init(&root, memarena, 8);
+
+ /* insert all samples in BSP now */
+ bsp_err= isb_add_samples(pa, &root, memarena, samplebuf);
+
+ if (bsp_err==0) {
+ /* go over all faces and fill in shadow values */
+
+ isb_bsp_fillfaces(&R, lar, &root); /* shb->persmat should have been calculated */
+
+ /* copy shadow samples to persistent buffer, reduce memory overhead */
+ if (R.osa) {
+ ISBShadfacA **isbsa= isbdata->shadfaca= MEM_callocN(pa->rectx*pa->recty*sizeof(void *), "isb shadfacs");
+
+ isbdata->memarena = BLI_memarena_new(0x8000 * sizeof(ISBSampleA), "isb arena");
+ BLI_memarena_use_calloc(isbdata->memarena);
+
+ for (rd= pa->rectdaps, x=pa->rectx*pa->recty; x>0; x--, rd++, isbsa++) {
+
+ if (*rd) {
+ PixStr *ps= (PixStr *)(*rd);
+ while (ps) {
+ if (ps->shadfac)
+ isb_add_shadfac(isbsa, isbdata->memarena, ps->obi, ps->facenr, ps->shadfac, count_mask(ps->mask));
+ ps= ps->next;
+ }
+ }
+ }
+ }
+ }
+ }
+ else {
+ if (isbdata->shadfacs) {
+ MEM_freeN(isbdata->shadfacs);
+ isbdata->shadfacs= NULL;
+ }
+ }
+
+ /* free BSP */
+ BLI_memarena_free(memarena);
+
+ /* free samples */
+ for (x=0; x<(R.osa?R.osa:1); x++)
+ MEM_freeN(samplebuf[x]);
+
+ if (bsp_err) printf("error in filling bsp\n");
+}
+
+/* add sample to buffer, isbsa is the root sample in a buffer */
+static ISBSampleA *isb_alloc_sample_transp(ISBSampleA **isbsa, MemArena *mem)
+{
+ ISBSampleA *new;
+
+ new= BLI_memarena_alloc(mem, sizeof(ISBSampleA));
+ if (*isbsa)
+ new->next= (*isbsa);
+ else
+ new->next= NULL;
+
+ *isbsa= new;
+ return new;
+}
+
+/* adding samples in BSP, transparent case */
+static int isb_add_samples_transp(RenderPart *pa, ISBBranch *root, MemArena *memarena, ISBSampleA ***samplebuf)
+{
+ int xi, yi, *xcos, *ycos;
+ int sample, bsp_err= 0;
+
+ /* bsp split doesn't like to handle regular sequences */
+ xcos= MEM_mallocN(pa->rectx*sizeof(int), "xcos");
+ ycos= MEM_mallocN(pa->recty*sizeof(int), "ycos");
+ for (xi=0; xi<pa->rectx; xi++)
+ xcos[xi]= xi;
+ for (yi=0; yi<pa->recty; yi++)
+ ycos[yi]= yi;
+ BLI_array_randomize(xcos, sizeof(int), pa->rectx, 12345);
+ BLI_array_randomize(ycos, sizeof(int), pa->recty, 54321);
+
+ for (sample=0; sample<(R.osa?R.osa:1); sample++) {
+ ISBSampleA **samp= samplebuf[sample], *samp1;
+
+ for (yi=0; yi<pa->recty; yi++) {
+ int y= ycos[yi];
+ for (xi=0; xi<pa->rectx; xi++) {
+ int x= xcos[xi];
+
+ samp1= *(samp + y*pa->rectx + x);
+ while (samp1) {
+ bsp_err |= isb_bsp_insert(root, memarena, (ISBSample *)samp1);
+ samp1= samp1->next;
+ }
+ }
+ if (bsp_err) break;
+ }
+ }
+
+ MEM_freeN(xcos);
+ MEM_freeN(ycos);
+
+ return bsp_err;
+}
+
+
+/* Ztransp version */
+/* lar->shb, pa->rectz and pa->rectp should exist */
+static void isb_make_buffer_transp(RenderPart *pa, APixstr *apixbuf, LampRen *lar)
+{
+ ShadBuf *shb= lar->shb;
+ ISBData *isbdata;
+ ISBSampleA *samp, **samplebuf[16]; /* MAX_OSA */
+ ISBBranch root;
+ MemArena *memarena;
+ APixstr *ap;
+ int x, y, sindex, sample, bsp_err=0;
+
+ /* storage for shadow, per thread */
+ isbdata= shb->isb_result[pa->thread];
+
+ /* to map the shi->xs and ys coordinate */
+ isbdata->minx= pa->disprect.xmin;
+ isbdata->miny= pa->disprect.ymin;
+ isbdata->rectx= pa->rectx;
+ isbdata->recty= pa->recty;
+
+ /* branches are added using memarena (32k branches) */
+ memarena = BLI_memarena_new(0x8000 * sizeof(ISBBranch), "isb arena");
+ BLI_memarena_use_calloc(memarena);
+
+ /* samplebuf is in camera view space (pixels) */
+ for (sample=0; sample<(R.osa?R.osa:1); sample++)
+ samplebuf[sample]= MEM_callocN(sizeof(void *)*pa->rectx*pa->recty, "isb alpha samplebuf");
+
+ /* setup bsp root */
+ memset(&root, 0, sizeof(ISBBranch));
+ root.box.xmin = (float)shb->size;
+ root.box.ymin = (float)shb->size;
+
+ /* create the sample buffers */
+ for (ap= apixbuf, sindex=0, y=0; y<pa->recty; y++) {
+ for (x=0; x<pa->rectx; x++, sindex++, ap++) {
+
+ if (ap->p[0]) {
+ APixstr *apn;
+ float xs= (float)(x + pa->disprect.xmin);
+ float ys= (float)(y + pa->disprect.ymin);
+
+ for (apn=ap; apn; apn= apn->next) {
+ int a;
+ for (a=0; a<4; a++) {
+ if (apn->p[a]) {
+ ObjectInstanceRen *obi= &R.objectinstance[apn->obi[a]];
+ ObjectRen *obr= obi->obr;
+ VlakRen *vlr= RE_findOrAddVlak(obr, (apn->p[a]-1) & RE_QUAD_MASK);
+ float zco[3];
+
+ /* here we store shadfac, easier to create the end storage buffer. needs zero'ed, multiple shadowbufs use it */
+ apn->shadfac[a]= 0;
+
+ if (R.osa) {
+ for (sample=0; sample<R.osa; sample++) {
+ int mask= (1<<sample);
+
+ if (apn->mask[a] & mask) {
+
+ /* convert image plane pixel location to lamp buffer space */
+ if (viewpixel_to_lampbuf(shb, obi, vlr, xs + R.jit[sample][0], ys + R.jit[sample][1], zco)) {
+ samp= isb_alloc_sample_transp(samplebuf[sample] + sindex, memarena);
+ samp->obi= apn->obi[a];
+ samp->facenr= apn->p[a] & ~RE_QUAD_OFFS;
+ samp->shadfac= &apn->shadfac[a];
+
+ copy_v3_v3(samp->zco, zco);
+ bound_rectf((rctf *)&root.box, samp->zco);
+ }
+ }
+ }
+ }
+ else {
+
+ /* convert image plane pixel location to lamp buffer space */
+ if (viewpixel_to_lampbuf(shb, obi, vlr, xs, ys, zco)) {
+
+ samp= isb_alloc_sample_transp(samplebuf[0] + sindex, memarena);
+ samp->obi= apn->obi[a];
+ samp->facenr= apn->p[a] & ~RE_QUAD_OFFS;
+ samp->shadfac= &apn->shadfac[a];
+
+ copy_v3_v3(samp->zco, zco);
+ bound_rectf((rctf *)&root.box, samp->zco);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ /* simple method to see if we have samples */
+ if (root.box.xmin != (float)shb->size) {
+ /* now create a regular split, root.box has the initial bounding box of all pixels */
+ /* split bsp 8 levels deep, in regular grid (16 x 16) */
+ isb_bsp_split_init(&root, memarena, 8);
+
+ /* insert all samples in BSP now */
+ bsp_err= isb_add_samples_transp(pa, &root, memarena, samplebuf);
+
+ if (bsp_err==0) {
+ ISBShadfacA **isbsa;
+
+ /* go over all faces and fill in shadow values */
+ isb_bsp_fillfaces(&R, lar, &root); /* shb->persmat should have been calculated */
+
+ /* copy shadow samples to persistent buffer, reduce memory overhead */
+ isbsa= isbdata->shadfaca= MEM_callocN(pa->rectx*pa->recty*sizeof(void *), "isb shadfacs");
+
+ isbdata->memarena = BLI_memarena_new(0x8000 * sizeof(ISBSampleA), "isb arena");
+
+ for (ap= apixbuf, x=pa->rectx*pa->recty; x>0; x--, ap++, isbsa++) {
+
+ if (ap->p[0]) {
+ APixstr *apn;
+ for (apn=ap; apn; apn= apn->next) {
+ int a;
+ for (a=0; a<4; a++) {
+ if (apn->p[a] && apn->shadfac[a]) {
+ if (R.osa)
+ isb_add_shadfac(isbsa, isbdata->memarena, apn->obi[a], apn->p[a], apn->shadfac[a], count_mask(apn->mask[a]));
+ else
+ isb_add_shadfac(isbsa, isbdata->memarena, apn->obi[a], apn->p[a], apn->shadfac[a], 0);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ /* free BSP */
+ BLI_memarena_free(memarena);
+
+ /* free samples */
+ for (x=0; x<(R.osa?R.osa:1); x++)
+ MEM_freeN(samplebuf[x]);
+
+ if (bsp_err) printf("error in filling bsp\n");
+}
+
+
+
+/* exported */
+
+/* returns amount of light (1.0 = no shadow) */
+/* note, shadepixel() rounds the coordinate, not the real sample info */
+float ISB_getshadow(ShadeInput *shi, ShadBuf *shb)
+{
+ /* if raytracing, we can't accept irregular shadow */
+ if (shi->depth==0) {
+ ISBData *isbdata= shb->isb_result[shi->thread];
+
+ if (isbdata) {
+ if (isbdata->shadfacs || isbdata->shadfaca) {
+ int x= shi->xs - isbdata->minx;
+
+ if (x >= 0 && x < isbdata->rectx) {
+ int y= shi->ys - isbdata->miny;
+
+ if (y >= 0 && y < isbdata->recty) {
+ if (isbdata->shadfacs) {
+ const short *sp= isbdata->shadfacs + y*isbdata->rectx + x;
+ return *sp>=4096?0.0f:1.0f - ((float)*sp)/4096.0f;
+ }
+ else {
+ int sindex= y*isbdata->rectx + x;
+ int obi= shi->obi - R.objectinstance;
+ ISBShadfacA *isbsa= *(isbdata->shadfaca + sindex);
+
+ while (isbsa) {
+ if (isbsa->facenr==shi->facenr+1 && isbsa->obi==obi)
+ return isbsa->shadfac>=1.0f?0.0f:1.0f - isbsa->shadfac;
+ isbsa= isbsa->next;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ return 1.0f;
+}
+
+/* part is supposed to be solid zbuffered (apixbuf==NULL) or transparent zbuffered */
+void ISB_create(RenderPart *pa, APixstr *apixbuf)
+{
+ GroupObject *go;
+
+ /* go over all lamps, and make the irregular buffers */
+ for (go=R.lights.first; go; go= go->next) {
+ LampRen *lar= go->lampren;
+
+ if (lar->type==LA_SPOT && lar->shb && lar->buftype==LA_SHADBUF_IRREGULAR) {
+
+ /* create storage for shadow, per thread */
+ lar->shb->isb_result[pa->thread]= MEM_callocN(sizeof(ISBData), "isb data");
+
+ if (apixbuf)
+ isb_make_buffer_transp(pa, apixbuf, lar);
+ else
+ isb_make_buffer(pa, lar);
+ }
+ }
+}
+
+
+/* end of part rendering, free stored shadow data for this thread from all lamps */
+void ISB_free(RenderPart *pa)
+{
+ GroupObject *go;
+
+ /* go over all lamps, and free the irregular buffers */
+ for (go=R.lights.first; go; go= go->next) {
+ LampRen *lar= go->lampren;
+
+ if (lar->type==LA_SPOT && lar->shb && lar->buftype==LA_SHADBUF_IRREGULAR) {
+ ISBData *isbdata= lar->shb->isb_result[pa->thread];
+
+ if (isbdata) {
+ if (isbdata->shadfacs)
+ MEM_freeN(isbdata->shadfacs);
+ if (isbdata->shadfaca)
+ MEM_freeN(isbdata->shadfaca);
+
+ if (isbdata->memarena)
+ BLI_memarena_free(isbdata->memarena);
+
+ MEM_freeN(isbdata);
+ lar->shb->isb_result[pa->thread]= NULL;
+ }
+ }
+ }
+}
diff --git a/source/blender/render/intern/source/shadeinput.c b/source/blender/render/intern/source/shadeinput.c
new file mode 100644
index 00000000000..d79749871c3
--- /dev/null
+++ b/source/blender/render/intern/source/shadeinput.c
@@ -0,0 +1,1490 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2006 Blender Foundation
+ * All rights reserved.
+ *
+ * Contributors: Hos, Robert Wenzlaff.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/render/intern/source/shadeinput.c
+ * \ingroup render
+ */
+
+
+#include <stdio.h>
+#include <math.h>
+#include <string.h>
+
+
+#include "BLI_math.h"
+#include "BLI_utildefines.h"
+
+#include "DNA_lamp_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_material_types.h"
+#include "DNA_particle_types.h"
+
+#include "BKE_scene.h"
+
+#include "BKE_node.h"
+
+/* local include */
+#include "raycounter.h"
+#include "render_types.h"
+#include "renderdatabase.h"
+#include "rendercore.h"
+#include "shading.h"
+#include "strand.h"
+#include "texture.h"
+#include "volumetric.h"
+#include "zbuf.h"
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+/* defined in pipeline.c, is hardcopy of active dynamic allocated Render */
+/* only to be used here in this file, it's for speed */
+extern struct Render R;
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+/* Shade Sample order:
+ *
+ * - shade_samples_fill_with_ps()
+ * - for each sample
+ * - shade_input_set_triangle() <- if prev sample-face is same, use shade_input_copy_triangle()
+ * - if vlr
+ * - shade_input_set_viewco() <- not for ray or bake
+ * - shade_input_set_uv() <- not for ray or bake
+ * - shade_input_set_normals()
+ * - shade_samples()
+ * - if AO
+ * - shade_samples_do_AO()
+ * - if shading happens
+ * - for each sample
+ * - shade_input_set_shade_texco()
+ * - shade_samples_do_shade()
+ * - OSA: distribute sample result with filter masking
+ *
+ */
+
+/* initialize material variables in shadeinput,
+ * doing inverse gamma correction where applicable */
+void shade_input_init_material(ShadeInput *shi)
+{
+ /* note, keep this synced with render_types.h */
+ memcpy(&shi->r, &shi->mat->r, 23 * sizeof(float));
+ shi->har = shi->mat->har;
+}
+
+/* also used as callback for nodes */
+/* delivers a fully filled in ShadeResult, for all passes */
+void shade_material_loop(ShadeInput *shi, ShadeResult *shr)
+{
+
+ shade_lamp_loop(shi, shr); /* clears shr */
+
+ if (shi->translucency != 0.0f) {
+ ShadeResult shr_t;
+ float fac = shi->translucency;
+
+ shade_input_init_material(shi);
+ negate_v3_v3(shi->vn, shi->vno);
+ negate_v3(shi->facenor);
+ shi->depth++; /* hack to get real shadow now */
+ shade_lamp_loop(shi, &shr_t);
+ shi->depth--;
+
+ /* a couple of passes */
+ madd_v3_v3fl(shr->combined, shr_t.combined, fac);
+ if (shi->passflag & SCE_PASS_SPEC)
+ madd_v3_v3fl(shr->spec, shr_t.spec, fac);
+ if (shi->passflag & SCE_PASS_DIFFUSE) {
+ madd_v3_v3fl(shr->diff, shr_t.diff, fac);
+ madd_v3_v3fl(shr->diffshad, shr_t.diffshad, fac);
+ }
+ if (shi->passflag & SCE_PASS_SHADOW)
+ madd_v3_v3fl(shr->shad, shr_t.shad, fac);
+
+ negate_v3(shi->vn);
+ negate_v3(shi->facenor);
+ }
+
+ /* depth >= 1 when ray-shading */
+ if (shi->depth == 0 || shi->volume_depth > 0) {
+ if (R.r.mode & R_RAYTRACE) {
+ if (shi->ray_mirror != 0.0f || ((shi->mode & MA_TRANSP) && (shi->mode & MA_RAYTRANSP) && shr->alpha != 1.0f)) {
+ /* ray trace works on combined, but gives pass info */
+ ray_trace(shi, shr);
+ }
+ }
+ /* disable adding of sky for raytransp */
+ if ((shi->mode & MA_TRANSP) && (shi->mode & MA_RAYTRANSP))
+ if ((shi->layflag & SCE_LAY_SKY) && (R.r.alphamode == R_ADDSKY))
+ shr->alpha = 1.0f;
+ }
+
+ if (R.r.mode & R_RAYTRACE) {
+ if (R.render_volumes_inside.first)
+ shade_volume_inside(shi, shr);
+ }
+}
+
+
+/* do a shade, finish up some passes, apply mist */
+void shade_input_do_shade(ShadeInput *shi, ShadeResult *shr)
+{
+ bool compat = false;
+ float alpha;
+
+ /* ------ main shading loop -------- */
+#ifdef RE_RAYCOUNTER
+ memset(&shi->raycounter, 0, sizeof(shi->raycounter));
+#endif
+
+ if (shi->mat->nodetree && shi->mat->use_nodes) {
+ compat = ntreeShaderExecTree(shi->mat->nodetree, shi, shr);
+ }
+
+ /* also run this when node shaders fail, due to incompatible shader nodes */
+ if (compat == false) {
+ /* copy all relevant material vars, note, keep this synced with render_types.h */
+ shade_input_init_material(shi);
+
+ if (shi->mat->material_type == MA_TYPE_VOLUME) {
+ if (R.r.mode & R_RAYTRACE) {
+ shade_volume_outside(shi, shr);
+ }
+ }
+ else { /* MA_TYPE_SURFACE, MA_TYPE_WIRE */
+ shade_material_loop(shi, shr);
+ }
+ }
+
+ /* copy additional passes */
+ if (shi->passflag & (SCE_PASS_VECTOR | SCE_PASS_NORMAL)) {
+ copy_v4_v4(shr->winspeed, shi->winspeed);
+ copy_v3_v3(shr->nor, shi->vn);
+ }
+
+ /* MIST */
+ if ((shi->passflag & SCE_PASS_MIST) || ((R.wrld.mode & WO_MIST) && (shi->mat->mode & MA_NOMIST) == 0)) {
+ if (R.r.mode & R_ORTHO)
+ shr->mist = mistfactor(-shi->co[2], shi->co);
+ else
+ shr->mist = mistfactor(len_v3(shi->co), shi->co);
+ }
+ else shr->mist = 0.0f;
+
+ if ((R.wrld.mode & WO_MIST) && (shi->mat->mode & MA_NOMIST) == 0) {
+ alpha = shr->mist;
+ }
+ else alpha = 1.0f;
+
+ /* add mist and premul color */
+ if (shr->alpha != 1.0f || alpha != 1.0f) {
+ float fac = alpha * (shr->alpha);
+ shr->combined[3] = fac;
+
+ if (shi->mat->material_type != MA_TYPE_VOLUME)
+ mul_v3_fl(shr->combined, fac);
+ }
+ else
+ shr->combined[3] = 1.0f;
+
+ /* add z */
+ shr->z = -shi->co[2];
+
+ /* RAYHITS */
+#if 0
+ if (1 || shi->passflag & SCE_PASS_RAYHITS) {
+ shr->rayhits[0] = (float)shi->raycounter.faces.test;
+ shr->rayhits[1] = (float)shi->raycounter.bb.hit;
+ shr->rayhits[2] = 0.0;
+ shr->rayhits[3] = 1.0;
+ }
+#endif
+
+ RE_RC_MERGE(&re_rc_counter[shi->thread], &shi->raycounter);
+}
+
+/* **************************************************************************** */
+/* ShadeInput */
+/* **************************************************************************** */
+
+
+void vlr_set_uv_indices(VlakRen *vlr, int *i1, int *i2, int *i3)
+{
+ /* to prevent storing new tfaces or vcols, we check a split runtime */
+ /* 4---3 4---3 */
+ /* |\ 1| or |1 /| */
+ /* |0\ | |/ 0| */
+ /* 1---2 1---2 0 = orig face, 1 = new face */
+
+ /* Update vert nums to point to correct verts of original face */
+ if (vlr->flag & R_DIVIDE_24) {
+ if (vlr->flag & R_FACE_SPLIT) {
+ (*i1)++; (*i2)++; (*i3)++;
+ }
+ else {
+ (*i3)++;
+ }
+ }
+ else if (vlr->flag & R_FACE_SPLIT) {
+ (*i2)++; (*i3)++;
+ }
+}
+
+/* copy data from face to ShadeInput, general case */
+/* indices 0 1 2 3 only */
+void shade_input_set_triangle_i(ShadeInput *shi, ObjectInstanceRen *obi, VlakRen *vlr, short i1, short i2, short i3)
+{
+ VertRen **vpp = &vlr->v1;
+
+ shi->vlr = vlr;
+ shi->obi = obi;
+ shi->obr = obi->obr;
+
+ shi->v1 = vpp[i1];
+ shi->v2 = vpp[i2];
+ shi->v3 = vpp[i3];
+
+ shi->i1 = i1;
+ shi->i2 = i2;
+ shi->i3 = i3;
+
+ /* note, shi->mat is set in node shaders */
+ shi->mat = shi->mat_override ? shi->mat_override : vlr->mat;
+
+ shi->osatex = (shi->mat->texco & TEXCO_OSA);
+ shi->mode = shi->mat->mode_l; /* or-ed result for all nodes */
+ shi->mode2 = shi->mat->mode2_l;
+
+ /* facenormal copy, can get flipped */
+ shi->flippednor = 0;
+ RE_vlakren_get_normal(&R, obi, vlr, shi->facenor);
+
+ /* calculate vertexnormals */
+ if (vlr->flag & R_SMOOTH) {
+ copy_v3_v3(shi->n1, shi->v1->n);
+ copy_v3_v3(shi->n2, shi->v2->n);
+ copy_v3_v3(shi->n3, shi->v3->n);
+
+ if (obi->flag & R_TRANSFORMED) {
+ mul_m3_v3(obi->nmat, shi->n1); normalize_v3(shi->n1);
+ mul_m3_v3(obi->nmat, shi->n2); normalize_v3(shi->n2);
+ mul_m3_v3(obi->nmat, shi->n3); normalize_v3(shi->n3);
+ }
+ }
+}
+
+/* copy data from face to ShadeInput, scanline case */
+void shade_input_set_triangle(ShadeInput *shi, int obi, int facenr, int UNUSED(normal_flip))
+{
+ if (facenr > 0) {
+ shi->obi = &R.objectinstance[obi];
+ shi->obr = shi->obi->obr;
+ shi->facenr = (facenr - 1) & RE_QUAD_MASK;
+ if (shi->facenr < shi->obr->totvlak) {
+ VlakRen *vlr = RE_findOrAddVlak(shi->obr, shi->facenr);
+
+ if (facenr & RE_QUAD_OFFS)
+ shade_input_set_triangle_i(shi, shi->obi, vlr, 0, 2, 3);
+ else
+ shade_input_set_triangle_i(shi, shi->obi, vlr, 0, 1, 2);
+ }
+ else
+ shi->vlr = NULL; /* general signal we got sky */
+ }
+ else
+ shi->vlr = NULL; /* general signal we got sky */
+}
+
+/* full osa case: copy static info */
+void shade_input_copy_triangle(ShadeInput *shi, ShadeInput *from)
+{
+ /* not so nice, but works... warning is in RE_shader_ext.h */
+ memcpy(shi, from, sizeof(struct ShadeInputCopy));
+}
+
+/* copy data from strand to shadeinput */
+void shade_input_set_strand(ShadeInput *shi, StrandRen *strand, StrandPoint *spoint)
+{
+ /* note, shi->mat is set in node shaders */
+ shi->mat = shi->mat_override ? shi->mat_override : strand->buffer->ma;
+
+ shi->osatex = (shi->mat->texco & TEXCO_OSA);
+ shi->mode = shi->mat->mode_l; /* or-ed result for all nodes */
+
+ /* shade_input_set_viewco equivalent */
+ copy_v3_v3(shi->co, spoint->co);
+ copy_v3_v3(shi->view, shi->co);
+ normalize_v3(shi->view);
+
+ shi->xs = (int)spoint->x;
+ shi->ys = (int)spoint->y;
+
+ if (shi->osatex || (R.r.mode & R_SHADOW)) {
+ copy_v3_v3(shi->dxco, spoint->dtco);
+ copy_v3_v3(shi->dyco, spoint->dsco);
+ }
+
+ /* dxview, dyview, not supported */
+
+ /* facenormal, simply viewco flipped */
+ copy_v3_v3(shi->facenor, spoint->nor);
+
+ /* shade_input_set_normals equivalent */
+ if (shi->mat->mode & MA_TANGENT_STR) {
+ copy_v3_v3(shi->vn, spoint->tan);
+ }
+ else {
+ float cross[3];
+
+ cross_v3_v3v3(cross, spoint->co, spoint->tan);
+ cross_v3_v3v3(shi->vn, cross, spoint->tan);
+ normalize_v3(shi->vn);
+
+ if (dot_v3v3(shi->vn, shi->view) < 0.0f)
+ negate_v3(shi->vn);
+ }
+
+ copy_v3_v3(shi->vno, shi->vn);
+}
+
+void shade_input_set_strand_texco(ShadeInput *shi, StrandRen *strand, StrandVert *svert, StrandPoint *spoint)
+{
+ StrandBuffer *strandbuf = strand->buffer;
+ ObjectRen *obr = strandbuf->obr;
+ StrandVert *sv;
+ int mode = shi->mode; /* or-ed result for all nodes */
+ short texco = shi->mat->texco;
+
+ if ((shi->mat->texco & TEXCO_REFL)) {
+ /* shi->dxview, shi->dyview, not supported */
+ }
+
+ if (shi->osatex && (texco & (TEXCO_NORM | TEXCO_REFL))) {
+ /* not supported */
+ }
+
+ if (mode & (MA_TANGENT_V | MA_NORMAP_TANG)) {
+ copy_v3_v3(shi->tang, spoint->tan);
+ copy_v3_v3(shi->nmaptang, spoint->tan);
+ }
+
+ if (mode & MA_STR_SURFDIFF) {
+ const float *surfnor = RE_strandren_get_surfnor(obr, strand, 0);
+
+ if (surfnor)
+ copy_v3_v3(shi->surfnor, surfnor);
+ else
+ copy_v3_v3(shi->surfnor, shi->vn);
+
+ if (shi->mat->strand_surfnor > 0.0f) {
+ shi->surfdist = 0.0f;
+ for (sv = strand->vert; sv != svert; sv++)
+ shi->surfdist += len_v3v3(sv->co, (sv + 1)->co);
+ shi->surfdist += spoint->t * len_v3v3(sv->co, (sv + 1)->co);
+ }
+ }
+
+ if (R.r.mode & R_SPEED) {
+ const float *speed;
+
+ speed = RE_strandren_get_winspeed(shi->obi, strand, 0);
+ if (speed)
+ copy_v4_v4(shi->winspeed, speed);
+ else
+ shi->winspeed[0] = shi->winspeed[1] = shi->winspeed[2] = shi->winspeed[3] = 0.0f;
+ }
+
+ /* shade_input_set_shade_texco equivalent */
+ if (texco & NEED_UV) {
+ if (texco & TEXCO_ORCO) {
+ copy_v3_v3(shi->lo, strand->orco);
+ /* no shi->osatex, orco derivatives are zero */
+ }
+
+ if (texco & TEXCO_GLOB) {
+ mul_v3_m4v3(shi->gl, R.viewinv, shi->co);
+
+ if (shi->osatex) {
+ mul_v3_mat3_m4v3(shi->dxgl, R.viewinv, shi->dxco);
+ mul_v3_mat3_m4v3(shi->dygl, R.viewinv, shi->dyco);
+ }
+ }
+
+ if (texco & TEXCO_STRAND) {
+ shi->strandco = spoint->strandco;
+
+ if (shi->osatex) {
+ shi->dxstrand = spoint->dtstrandco;
+ shi->dystrand = 0.0f;
+ }
+ }
+
+ if ((texco & TEXCO_UV) || (mode & (MA_VERTEXCOL | MA_VERTEXCOLP | MA_FACETEXTURE))) {
+ MCol *mcol;
+ const float *uv;
+ char *name;
+ int i;
+
+ shi->totuv = 0;
+ shi->totcol = 0;
+ shi->actuv = obr->actmtface;
+ shi->actcol = obr->actmcol;
+
+ if (mode & (MA_VERTEXCOL | MA_VERTEXCOLP)) {
+ for (i = 0; (mcol = RE_strandren_get_mcol(obr, strand, i, &name, 0)); i++) {
+ ShadeInputCol *scol = &shi->col[i];
+ const char *cp = (char *)mcol;
+
+ shi->totcol++;
+ scol->name = name;
+
+ scol->col[0] = cp[3] / 255.0f;
+ scol->col[1] = cp[2] / 255.0f;
+ scol->col[2] = cp[1] / 255.0f;
+ scol->col[3] = cp[0] / 255.0f;
+ }
+
+ if (shi->totcol) {
+ shi->vcol[0] = shi->col[shi->actcol].col[0];
+ shi->vcol[1] = shi->col[shi->actcol].col[1];
+ shi->vcol[2] = shi->col[shi->actcol].col[2];
+ shi->vcol[3] = shi->col[shi->actcol].col[3];
+ }
+ else {
+ shi->vcol[0] = 0.0f;
+ shi->vcol[1] = 0.0f;
+ shi->vcol[2] = 0.0f;
+ shi->vcol[3] = 0.0f;
+ }
+ }
+
+ for (i = 0; (uv = RE_strandren_get_uv(obr, strand, i, &name, 0)); i++) {
+ ShadeInputUV *suv = &shi->uv[i];
+
+ shi->totuv++;
+ suv->name = name;
+
+ if (strandbuf->overrideuv == i) {
+ suv->uv[0] = -1.0f;
+ suv->uv[1] = spoint->strandco;
+ suv->uv[2] = 0.0f;
+ }
+ else {
+ suv->uv[0] = -1.0f + 2.0f * uv[0];
+ suv->uv[1] = -1.0f + 2.0f * uv[1];
+ suv->uv[2] = 0.0f; /* texture.c assumes there are 3 coords */
+ }
+
+ if (shi->osatex) {
+ suv->dxuv[0] = 0.0f;
+ suv->dxuv[1] = 0.0f;
+ suv->dyuv[0] = 0.0f;
+ suv->dyuv[1] = 0.0f;
+ }
+
+ if ((mode & MA_FACETEXTURE) && i == obr->actmtface) {
+ if ((mode & (MA_VERTEXCOL | MA_VERTEXCOLP)) == 0) {
+ shi->vcol[0] = 1.0f;
+ shi->vcol[1] = 1.0f;
+ shi->vcol[2] = 1.0f;
+ shi->vcol[3] = 1.0f;
+ }
+ }
+ }
+
+ if (shi->totuv == 0) {
+ ShadeInputUV *suv = &shi->uv[0];
+
+ suv->uv[0] = 0.0f;
+ suv->uv[1] = spoint->strandco;
+ suv->uv[2] = 0.0f; /* texture.c assumes there are 3 coords */
+
+ if (mode & MA_FACETEXTURE) {
+ /* no tface? set at 1.0f */
+ shi->vcol[0] = 1.0f;
+ shi->vcol[1] = 1.0f;
+ shi->vcol[2] = 1.0f;
+ shi->vcol[3] = 1.0f;
+ }
+ }
+
+ }
+
+ if (texco & TEXCO_NORM) {
+ shi->orn[0] = -shi->vn[0];
+ shi->orn[1] = -shi->vn[1];
+ shi->orn[2] = -shi->vn[2];
+ }
+
+ if (texco & TEXCO_STRESS) {
+ /* not supported */
+ }
+
+ if (texco & TEXCO_TANGENT) {
+ if ((mode & MA_TANGENT_V) == 0) {
+ /* just prevent surprises */
+ shi->tang[0] = shi->tang[1] = shi->tang[2] = 0.0f;
+ shi->nmaptang[0] = shi->nmaptang[1] = shi->nmaptang[2] = 0.0f;
+ }
+ }
+ }
+
+ /* this only avalailable for scanline renders */
+ if (shi->depth == 0) {
+ if (texco & TEXCO_WINDOW) {
+ shi->winco[0] = -1.0f + 2.0f * spoint->x / (float)R.winx;
+ shi->winco[1] = -1.0f + 2.0f * spoint->y / (float)R.winy;
+ shi->winco[2] = 0.0f;
+
+ /* not supported */
+ if (shi->osatex) {
+ shi->dxwin[0] = 0.0f;
+ shi->dywin[1] = 0.0f;
+ shi->dxwin[0] = 0.0f;
+ shi->dywin[1] = 0.0f;
+ }
+ }
+ }
+
+ if (shi->do_manage) {
+ if (mode & (MA_VERTEXCOL | MA_VERTEXCOLP | MA_FACETEXTURE)) {
+ srgb_to_linearrgb_v3_v3(shi->vcol, shi->vcol);
+ }
+ }
+
+}
+
+/* from scanline pixel coordinates to 3d coordinates, requires set_triangle */
+void shade_input_calc_viewco(ShadeInput *shi, float x, float y, float z, float view[3], float dxyview[2], float co[3], float dxco[3], float dyco[3])
+{
+ /* returns not normalized, so is in viewplane coords */
+ calc_view_vector(view, x, y);
+
+ if (shi->mat->material_type == MA_TYPE_WIRE) {
+ /* wire cannot use normal for calculating shi->co, so
+ * we reconstruct the coordinate less accurate */
+ if (R.r.mode & R_ORTHO)
+ calc_renderco_ortho(co, x, y, z);
+ else
+ calc_renderco_zbuf(co, view, z);
+ }
+ else {
+ /* for non-wire, intersect with the triangle to get the exact coord */
+ float fac, dface, v1[3];
+
+ copy_v3_v3(v1, shi->v1->co);
+ if (shi->obi->flag & R_TRANSFORMED)
+ mul_m4_v3(shi->obi->mat, v1);
+
+ dface = dot_v3v3(v1, shi->facenor);
+
+ /* ortho viewplane cannot intersect using view vector originating in (0,0,0) */
+ if (R.r.mode & R_ORTHO) {
+ /* x and y 3d coordinate can be derived from pixel coord and winmat */
+ float fx = 2.0f / (R.winx * R.winmat[0][0]);
+ float fy = 2.0f / (R.winy * R.winmat[1][1]);
+
+ co[0] = (x - 0.5f * R.winx) * fx - R.winmat[3][0] / R.winmat[0][0];
+ co[1] = (y - 0.5f * R.winy) * fy - R.winmat[3][1] / R.winmat[1][1];
+
+ /* using a*x + b*y + c*z = d equation, (a b c) is normal */
+ if (shi->facenor[2] != 0.0f)
+ co[2] = (dface - shi->facenor[0] * co[0] - shi->facenor[1] * co[1]) / shi->facenor[2];
+ else
+ co[2] = 0.0f;
+
+ if (dxco && dyco) {
+ dxco[0] = fx;
+ dxco[1] = 0.0f;
+ if (shi->facenor[2] != 0.0f)
+ dxco[2] = -(shi->facenor[0] * fx) / shi->facenor[2];
+ else
+ dxco[2] = 0.0f;
+
+ dyco[0] = 0.0f;
+ dyco[1] = fy;
+ if (shi->facenor[2] != 0.0f)
+ dyco[2] = -(shi->facenor[1] * fy) / shi->facenor[2];
+ else
+ dyco[2] = 0.0f;
+
+ if (dxyview) {
+ fac = (co[2] != 0.0f) ? (1.0f / co[2]) : 0.0f;
+ dxyview[0] = -R.viewdx * fac;
+ dxyview[1] = -R.viewdy * fac;
+ }
+ }
+ }
+ else {
+ float div;
+
+ div = dot_v3v3(shi->facenor, view);
+ if (div != 0.0f) fac = dface / div;
+ else fac = 0.0f;
+
+ co[0] = fac * view[0];
+ co[1] = fac * view[1];
+ co[2] = fac * view[2];
+
+ /* pixel dx/dy for render coord */
+ if (dxco && dyco) {
+ float u = dface / (div - R.viewdx * shi->facenor[0]);
+ float v = dface / (div - R.viewdy * shi->facenor[1]);
+
+ dxco[0] = co[0] - (view[0] - R.viewdx) * u;
+ dxco[1] = co[1] - (view[1]) * u;
+ dxco[2] = co[2] - (view[2]) * u;
+
+ dyco[0] = co[0] - (view[0]) * v;
+ dyco[1] = co[1] - (view[1] - R.viewdy) * v;
+ dyco[2] = co[2] - (view[2]) * v;
+
+ if (dxyview) {
+ if (fac != 0.0f) fac = 1.0f / fac;
+ dxyview[0] = -R.viewdx * fac;
+ dxyview[1] = -R.viewdy * fac;
+ }
+ }
+ }
+ }
+
+ /* set camera coords - for scanline, it's always 0.0,0.0,0.0 (render is in camera space)
+ * however for raytrace it can be different - the position of the last intersection */
+ shi->camera_co[0] = shi->camera_co[1] = shi->camera_co[2] = 0.0f;
+
+ /* cannot normalize earlier, code above needs it at viewplane level */
+ normalize_v3(view);
+}
+
+/* from scanline pixel coordinates to 3d coordinates, requires set_triangle */
+void shade_input_set_viewco(ShadeInput *shi, float x, float y, float xs, float ys, float z)
+{
+ float *dxyview = NULL, *dxco = NULL, *dyco = NULL;
+
+ /* currently in use for dithering (soft shadow), node preview, irregular shad */
+ shi->xs = (int)xs;
+ shi->ys = (int)ys;
+
+ /* original scanline coordinate without jitter */
+ shi->scanco[0] = x;
+ shi->scanco[1] = y;
+ shi->scanco[2] = z;
+
+ /* check if we need derivatives */
+ if (shi->osatex || (R.r.mode & R_SHADOW)) {
+ dxco = shi->dxco;
+ dyco = shi->dyco;
+
+ if ((shi->mat->texco & TEXCO_REFL))
+ dxyview = &shi->dxview;
+ }
+
+ shade_input_calc_viewco(shi, xs, ys, z, shi->view, dxyview, shi->co, dxco, dyco);
+}
+
+void barycentric_differentials_from_position(
+ const float co[3], const float v1[3], const float v2[3], const float v3[3],
+ const float dxco[3], const float dyco[3], const float facenor[3], const bool differentials,
+ float *u, float *v, float *dx_u, float *dx_v, float *dy_u, float *dy_v)
+{
+ /* find most stable axis to project */
+ int axis1, axis2;
+ axis_dominant_v3(&axis1, &axis2, facenor);
+
+ /* compute u,v and derivatives */
+ float t00 = v3[axis1] - v1[axis1];
+ float t01 = v3[axis2] - v1[axis2];
+ float t10 = v3[axis1] - v2[axis1];
+ float t11 = v3[axis2] - v2[axis2];
+
+ float detsh = (t00 * t11 - t10 * t01);
+ detsh = (detsh != 0.0f) ? 1.0f / detsh : 0.0f;
+ t00 *= detsh; t01 *= detsh;
+ t10 *= detsh; t11 *= detsh;
+
+ *u = (v3[axis1] - co[axis1]) * t11 - (v3[axis2] - co[axis2]) * t10;
+ *v = (v3[axis2] - co[axis2]) * t00 - (v3[axis1] - co[axis1]) * t01;
+ if (differentials) {
+ *dx_u = dxco[axis1] * t11 - dxco[axis2] * t10;
+ *dx_v = dxco[axis2] * t00 - dxco[axis1] * t01;
+ *dy_u = dyco[axis1] * t11 - dyco[axis2] * t10;
+ *dy_v = dyco[axis2] * t00 - dyco[axis1] * t01;
+ }
+}
+/* calculate U and V, for scanline (silly render face u and v are in range -1 to 0) */
+void shade_input_set_uv(ShadeInput *shi)
+{
+ VlakRen *vlr = shi->vlr;
+
+ if ((vlr->flag & R_SMOOTH) || (shi->mat->texco & NEED_UV) || (shi->passflag & SCE_PASS_UV)) {
+ float v1[3], v2[3], v3[3];
+
+ copy_v3_v3(v1, shi->v1->co);
+ copy_v3_v3(v2, shi->v2->co);
+ copy_v3_v3(v3, shi->v3->co);
+
+ if (shi->obi->flag & R_TRANSFORMED) {
+ mul_m4_v3(shi->obi->mat, v1);
+ mul_m4_v3(shi->obi->mat, v2);
+ mul_m4_v3(shi->obi->mat, v3);
+ }
+
+ /* exception case for wire render of edge */
+ if (vlr->v2 == vlr->v3) {
+ float lend, lenc;
+
+ lend = len_v3v3(v2, v1);
+ lenc = len_v3v3(shi->co, v1);
+
+ if (lend == 0.0f) {
+ shi->u = shi->v = 0.0f;
+ }
+ else {
+ shi->u = -(1.0f - lenc / lend);
+ shi->v = 0.0f;
+ }
+
+ if (shi->osatex) {
+ shi->dx_u = 0.0f;
+ shi->dx_v = 0.0f;
+ shi->dy_u = 0.0f;
+ shi->dy_v = 0.0f;
+ }
+ }
+ else {
+ barycentric_differentials_from_position(
+ shi->co, v1, v2, v3, shi->dxco, shi->dyco, shi->facenor, shi->osatex,
+ &shi->u, &shi->v, &shi->dx_u, &shi->dx_v, &shi->dy_u, &shi->dy_v);
+
+ shi->u = -shi->u;
+ shi->v = -shi->v;
+
+ /* u and v are in range -1 to 0, we allow a little bit extra but not too much, screws up speedvectors */
+ CLAMP(shi->u, -2.0f, 1.0f);
+ CLAMP(shi->v, -2.0f, 1.0f);
+ }
+ }
+}
+
+void shade_input_set_normals(ShadeInput *shi)
+{
+ float u = shi->u, v = shi->v;
+ float l = 1.0f + u + v;
+
+ shi->flippednor = 0;
+
+ /* test flip normals to viewing direction */
+ if (!(shi->vlr->flag & R_TANGENT)) {
+ if (dot_v3v3(shi->facenor, shi->view) < 0.0f) {
+ negate_v3(shi->facenor);
+ shi->flippednor = 1;
+ }
+ }
+
+ /* calculate vertexnormals */
+ if (shi->vlr->flag & R_SMOOTH) {
+ float *n1 = shi->n1, *n2 = shi->n2, *n3 = shi->n3;
+
+ if (shi->flippednor) {
+ negate_v3(n1);
+ negate_v3(n2);
+ negate_v3(n3);
+ }
+
+ shi->vn[0] = l * n3[0] - u * n1[0] - v * n2[0];
+ shi->vn[1] = l * n3[1] - u * n1[1] - v * n2[1];
+ shi->vn[2] = l * n3[2] - u * n1[2] - v * n2[2];
+
+ /* use unnormalized normal (closer to games) */
+ copy_v3_v3(shi->nmapnorm, shi->vn);
+
+ normalize_v3(shi->vn);
+ }
+ else {
+ copy_v3_v3(shi->vn, shi->facenor);
+ copy_v3_v3(shi->nmapnorm, shi->vn);
+ }
+
+ /* used in nodes */
+ copy_v3_v3(shi->vno, shi->vn);
+
+ /* flip normals to viewing direction */
+ if (!(shi->vlr->flag & R_TANGENT))
+ if (dot_v3v3(shi->facenor, shi->view) < 0.0f)
+ shade_input_flip_normals(shi);
+}
+
+/* XXX shi->flippednor messes up otherwise */
+void shade_input_set_vertex_normals(ShadeInput *shi)
+{
+ float u = shi->u, v = shi->v;
+ float l = 1.0f + u + v;
+
+ /* calculate vertexnormals */
+ if (shi->vlr->flag & R_SMOOTH) {
+ const float *n1 = shi->n1, *n2 = shi->n2, *n3 = shi->n3;
+
+ shi->vn[0] = l * n3[0] - u * n1[0] - v * n2[0];
+ shi->vn[1] = l * n3[1] - u * n1[1] - v * n2[1];
+ shi->vn[2] = l * n3[2] - u * n1[2] - v * n2[2];
+
+ /* use unnormalized normal (closer to games) */
+ copy_v3_v3(shi->nmapnorm, shi->vn);
+
+ normalize_v3(shi->vn);
+ }
+ else {
+ copy_v3_v3(shi->vn, shi->facenor);
+ copy_v3_v3(shi->nmapnorm, shi->vn);
+ }
+
+ /* used in nodes */
+ copy_v3_v3(shi->vno, shi->vn);
+}
+
+
+/* use by raytrace, sss, bake to flip into the right direction */
+void shade_input_flip_normals(ShadeInput *shi)
+{
+ negate_v3(shi->facenor);
+ negate_v3(shi->vn);
+ negate_v3(shi->vno);
+ negate_v3(shi->nmapnorm);
+ shi->flippednor = !shi->flippednor;
+}
+
+void shade_input_set_shade_texco(ShadeInput *shi)
+{
+ ObjectInstanceRen *obi = shi->obi;
+ ObjectRen *obr = shi->obr;
+ VertRen *v1 = shi->v1, *v2 = shi->v2, *v3 = shi->v3;
+ float u = shi->u, v = shi->v;
+ float l = 1.0f + u + v, dl;
+ int mode = shi->mode; /* or-ed result for all nodes */
+ int mode2 = shi->mode2;
+ short texco = shi->mat->texco;
+ const bool need_mikk_tangent = (mode & MA_NORMAP_TANG || R.flag & R_NEED_TANGENT);
+ const bool need_mikk_tangent_concrete = (mode2 & MA_TANGENT_CONCRETE) != 0;
+
+ /* calculate dxno */
+ if (shi->vlr->flag & R_SMOOTH) {
+
+ if (shi->osatex && (texco & (TEXCO_NORM | TEXCO_REFL)) ) {
+ const float *n1 = shi->n1, *n2 = shi->n2, *n3 = shi->n3;
+
+ dl = shi->dx_u + shi->dx_v;
+ shi->dxno[0] = dl * n3[0] - shi->dx_u * n1[0] - shi->dx_v * n2[0];
+ shi->dxno[1] = dl * n3[1] - shi->dx_u * n1[1] - shi->dx_v * n2[1];
+ shi->dxno[2] = dl * n3[2] - shi->dx_u * n1[2] - shi->dx_v * n2[2];
+ dl = shi->dy_u + shi->dy_v;
+ shi->dyno[0] = dl * n3[0] - shi->dy_u * n1[0] - shi->dy_v * n2[0];
+ shi->dyno[1] = dl * n3[1] - shi->dy_u * n1[1] - shi->dy_v * n2[1];
+ shi->dyno[2] = dl * n3[2] - shi->dy_u * n1[2] - shi->dy_v * n2[2];
+
+ }
+ }
+
+ /* calc tangents */
+ if (mode & (MA_TANGENT_V | MA_NORMAP_TANG) || mode2 & MA_TANGENT_CONCRETE || R.flag & R_NEED_TANGENT) {
+ const float *s1, *s2, *s3;
+ float tl, tu, tv;
+
+ if (shi->vlr->flag & R_SMOOTH) {
+ tl = l;
+ tu = u;
+ tv = v;
+ }
+ else {
+ /* qdn: flat faces have tangents too,
+ * could pick either one, using average here */
+ tl = 1.0f / 3.0f;
+ tu = -1.0f / 3.0f;
+ tv = -1.0f / 3.0f;
+ }
+
+ shi->tang[0] = shi->tang[1] = shi->tang[2] = 0.0f;
+ shi->nmaptang[0] = shi->nmaptang[1] = shi->nmaptang[2] = 0.0f;
+
+ if (mode & MA_TANGENT_V) {
+ s1 = RE_vertren_get_tangent(obr, v1, 0);
+ s2 = RE_vertren_get_tangent(obr, v2, 0);
+ s3 = RE_vertren_get_tangent(obr, v3, 0);
+
+ if (s1 && s2 && s3) {
+ shi->tang[0] = (tl * s3[0] - tu * s1[0] - tv * s2[0]);
+ shi->tang[1] = (tl * s3[1] - tu * s1[1] - tv * s2[1]);
+ shi->tang[2] = (tl * s3[2] - tu * s1[2] - tv * s2[2]);
+
+ if (obi->flag & R_TRANSFORMED)
+ mul_m3_v3(obi->nmat, shi->tang);
+
+ normalize_v3(shi->tang);
+ copy_v3_v3(shi->nmaptang, shi->tang);
+ }
+ }
+
+ if (need_mikk_tangent || need_mikk_tangent_concrete) {
+ int j1 = shi->i1, j2 = shi->i2, j3 = shi->i3;
+ float c0[3], c1[3], c2[3];
+ int acttang = obr->actmtface;
+
+ vlr_set_uv_indices(shi->vlr, &j1, &j2, &j3);
+
+ /* cycle through all tangent in vlakren */
+ for (int i = 0; i < MAX_MTFACE; i++) {
+ const float *tangent = RE_vlakren_get_nmap_tangent(obr, shi->vlr, i, false);
+ if (!tangent)
+ continue;
+
+ copy_v3_v3(c0, &tangent[j1 * 4]);
+ copy_v3_v3(c1, &tangent[j2 * 4]);
+ copy_v3_v3(c2, &tangent[j3 * 4]);
+
+ /* keeping tangents normalized at vertex level
+ * corresponds better to how it's done in game engines */
+ if (obi->flag & R_TRANSFORMED) {
+ mul_mat3_m4_v3(obi->mat, c0); normalize_v3(c0);
+ mul_mat3_m4_v3(obi->mat, c1); normalize_v3(c1);
+ mul_mat3_m4_v3(obi->mat, c2); normalize_v3(c2);
+ }
+
+ /* we don't normalize the interpolated TBN tangent
+ * corresponds better to how it's done in game engines */
+ shi->tangents[i][0] = (tl * c2[0] - tu * c0[0] - tv * c1[0]);
+ shi->tangents[i][1] = (tl * c2[1] - tu * c0[1] - tv * c1[1]);
+ shi->tangents[i][2] = (tl * c2[2] - tu * c0[2] - tv * c1[2]);
+
+ /* the sign is the same for all 3 vertices of any
+ * non degenerate triangle. */
+ shi->tangents[i][3] = tangent[j1 * 4 + 3];
+
+ if (acttang == i && need_mikk_tangent) {
+ for (int m = 0; m < 4; m++) {
+ shi->nmaptang[m] = shi->tangents[i][m];
+ }
+ }
+ }
+ }
+ }
+
+ if (mode & MA_STR_SURFDIFF) {
+ const float *surfnor = RE_vlakren_get_surfnor(obr, shi->vlr, 0);
+
+ if (surfnor) {
+ copy_v3_v3(shi->surfnor, surfnor);
+ if (obi->flag & R_TRANSFORMED)
+ mul_m3_v3(obi->nmat, shi->surfnor);
+ }
+ else
+ copy_v3_v3(shi->surfnor, shi->vn);
+
+ shi->surfdist = 0.0f;
+ }
+
+ if (R.r.mode & R_SPEED) {
+ const float *s1, *s2, *s3;
+
+ s1 = RE_vertren_get_winspeed(obi, v1, 0);
+ s2 = RE_vertren_get_winspeed(obi, v2, 0);
+ s3 = RE_vertren_get_winspeed(obi, v3, 0);
+ if (s1 && s2 && s3) {
+ shi->winspeed[0] = (l * s3[0] - u * s1[0] - v * s2[0]);
+ shi->winspeed[1] = (l * s3[1] - u * s1[1] - v * s2[1]);
+ shi->winspeed[2] = (l * s3[2] - u * s1[2] - v * s2[2]);
+ shi->winspeed[3] = (l * s3[3] - u * s1[3] - v * s2[3]);
+ }
+ else {
+ shi->winspeed[0] = shi->winspeed[1] = shi->winspeed[2] = shi->winspeed[3] = 0.0f;
+ }
+ }
+
+ /* pass option forces UV calc */
+ if ((shi->passflag & SCE_PASS_UV) || (R.flag & R_NEED_VCOL))
+ texco |= (NEED_UV | TEXCO_UV);
+
+ /* texture coordinates. shi->dxuv shi->dyuv have been set */
+ if (texco & NEED_UV) {
+
+ if (texco & TEXCO_ORCO) {
+ if (v1->orco) {
+ const float *o1, *o2, *o3;
+
+ o1 = v1->orco;
+ o2 = v2->orco;
+ o3 = v3->orco;
+
+ shi->lo[0] = l * o3[0] - u * o1[0] - v * o2[0];
+ shi->lo[1] = l * o3[1] - u * o1[1] - v * o2[1];
+ shi->lo[2] = l * o3[2] - u * o1[2] - v * o2[2];
+
+ if (shi->osatex) {
+ dl = shi->dx_u + shi->dx_v;
+ shi->dxlo[0] = dl * o3[0] - shi->dx_u * o1[0] - shi->dx_v * o2[0];
+ shi->dxlo[1] = dl * o3[1] - shi->dx_u * o1[1] - shi->dx_v * o2[1];
+ shi->dxlo[2] = dl * o3[2] - shi->dx_u * o1[2] - shi->dx_v * o2[2];
+ dl = shi->dy_u + shi->dy_v;
+ shi->dylo[0] = dl * o3[0] - shi->dy_u * o1[0] - shi->dy_v * o2[0];
+ shi->dylo[1] = dl * o3[1] - shi->dy_u * o1[1] - shi->dy_v * o2[1];
+ shi->dylo[2] = dl * o3[2] - shi->dy_u * o1[2] - shi->dy_v * o2[2];
+ }
+ }
+
+ copy_v3_v3(shi->duplilo, obi->dupliorco);
+ }
+
+ if (texco & TEXCO_GLOB) {
+ copy_v3_v3(shi->gl, shi->co);
+ mul_m4_v3(R.viewinv, shi->gl);
+ if (shi->osatex) {
+ copy_v3_v3(shi->dxgl, shi->dxco);
+ mul_mat3_m4_v3(R.viewinv, shi->dxgl);
+ copy_v3_v3(shi->dygl, shi->dyco);
+ mul_mat3_m4_v3(R.viewinv, shi->dygl);
+ }
+ }
+
+ if (texco & TEXCO_STRAND) {
+ shi->strandco = (l * v3->accum - u * v1->accum - v * v2->accum);
+ if (shi->osatex) {
+ dl = shi->dx_u + shi->dx_v;
+ shi->dxstrand = dl * v3->accum - shi->dx_u * v1->accum - shi->dx_v * v2->accum;
+ dl = shi->dy_u + shi->dy_v;
+ shi->dystrand = dl * v3->accum - shi->dy_u * v1->accum - shi->dy_v * v2->accum;
+ }
+ }
+
+ if ((texco & TEXCO_UV) || (mode & (MA_VERTEXCOL | MA_VERTEXCOLP | MA_FACETEXTURE)) || (R.flag & R_NEED_VCOL)) {
+ VlakRen *vlr = shi->vlr;
+ MTFace *tface;
+ MCol *mcol;
+ char *name;
+ int i, j1 = shi->i1, j2 = shi->i2, j3 = shi->i3;
+
+ /* uv and vcols are not copied on split, so set them according vlr divide flag */
+ vlr_set_uv_indices(vlr, &j1, &j2, &j3);
+
+ shi->totuv = 0;
+ shi->totcol = 0;
+ shi->actuv = obr->actmtface;
+ shi->actcol = obr->actmcol;
+
+ if ((mode & (MA_VERTEXCOL | MA_VERTEXCOLP)) || (R.flag & R_NEED_VCOL)) {
+ for (i = 0; (mcol = RE_vlakren_get_mcol(obr, vlr, i, &name, 0)); i++) {
+ ShadeInputCol *scol = &shi->col[i];
+ const char *cp1, *cp2, *cp3;
+ float a[3];
+
+ shi->totcol++;
+ scol->name = name;
+
+ cp1 = (char *)(mcol + j1);
+ cp2 = (char *)(mcol + j2);
+ cp3 = (char *)(mcol + j3);
+
+ /* alpha values */
+ a[0] = ((float)cp1[0]) / 255.f;
+ a[1] = ((float)cp2[0]) / 255.f;
+ a[2] = ((float)cp3[0]) / 255.f;
+ scol->col[3] = l * a[2] - u * a[0] - v * a[1];
+
+ /* sample premultiplied color value */
+ scol->col[0] = (l * ((float)cp3[3]) * a[2] - u * ((float)cp1[3]) * a[0] - v * ((float)cp2[3]) * a[1]) / 255.f;
+ scol->col[1] = (l * ((float)cp3[2]) * a[2] - u * ((float)cp1[2]) * a[0] - v * ((float)cp2[2]) * a[1]) / 255.f;
+ scol->col[2] = (l * ((float)cp3[1]) * a[2] - u * ((float)cp1[1]) * a[0] - v * ((float)cp2[1]) * a[1]) / 255.f;
+
+ /* if not zero alpha, restore non-multiplied color */
+ if (scol->col[3]) {
+ mul_v3_fl(scol->col, 1.0f / scol->col[3]);
+ }
+ }
+
+ if (shi->totcol) {
+ shi->vcol[0] = shi->col[shi->actcol].col[0];
+ shi->vcol[1] = shi->col[shi->actcol].col[1];
+ shi->vcol[2] = shi->col[shi->actcol].col[2];
+ shi->vcol[3] = shi->col[shi->actcol].col[3];
+ }
+ else {
+ shi->vcol[0] = 0.0f;
+ shi->vcol[1] = 0.0f;
+ shi->vcol[2] = 0.0f;
+ shi->vcol[3] = 1.0f;
+ }
+ }
+
+ for (i = 0; (tface = RE_vlakren_get_tface(obr, vlr, i, &name, 0)); i++) {
+ ShadeInputUV *suv = &shi->uv[i];
+ const float *uv1 = tface->uv[j1];
+ const float *uv2 = tface->uv[j2];
+ const float *uv3 = tface->uv[j3];
+
+ shi->totuv++;
+ suv->name = name;
+
+ if ((shi->mat->mapflag & MA_MAPFLAG_UVPROJECT) && (shi->depth == 0)) {
+ float x = shi->xs;
+ float y = shi->ys;
+
+ float s1[2] = {-1.0f + 2.0f * uv1[0], -1.0f + 2.0f * uv1[1]};
+ float s2[2] = {-1.0f + 2.0f * uv2[0], -1.0f + 2.0f * uv2[1]};
+ float s3[2] = {-1.0f + 2.0f * uv3[0], -1.0f + 2.0f * uv3[1]};
+
+
+ float obwinmat[4][4], winmat[4][4], ho1[4], ho2[4], ho3[4];
+ float Zmulx, Zmuly;
+ float hox, hoy, l_proj, dl_proj, u_proj, v_proj;
+ float s00, s01, s10, s11, detsh;
+
+ /* old globals, localized now */
+ Zmulx = ((float)R.winx) / 2.0f;
+ Zmuly = ((float)R.winy) / 2.0f;
+
+ zbuf_make_winmat(&R, winmat);
+ if (shi->obi->flag & R_TRANSFORMED)
+ mul_m4_m4m4(obwinmat, winmat, obi->mat);
+ else
+ copy_m4_m4(obwinmat, winmat);
+
+ zbuf_render_project(obwinmat, v1->co, ho1);
+ zbuf_render_project(obwinmat, v2->co, ho2);
+ zbuf_render_project(obwinmat, v3->co, ho3);
+
+ s00 = ho3[0] / ho3[3] - ho1[0] / ho1[3];
+ s01 = ho3[1] / ho3[3] - ho1[1] / ho1[3];
+ s10 = ho3[0] / ho3[3] - ho2[0] / ho2[3];
+ s11 = ho3[1] / ho3[3] - ho2[1] / ho2[3];
+
+ detsh = s00 * s11 - s10 * s01;
+ detsh = (detsh != 0.0f) ? 1.0f / detsh : 0.0f;
+ s00 *= detsh; s01 *= detsh;
+ s10 *= detsh; s11 *= detsh;
+
+ /* recalc u and v again */
+ hox = x / Zmulx - 1.0f;
+ hoy = y / Zmuly - 1.0f;
+ u_proj = (hox - ho3[0] / ho3[3]) * s11 - (hoy - ho3[1] / ho3[3]) * s10;
+ v_proj = (hoy - ho3[1] / ho3[3]) * s00 - (hox - ho3[0] / ho3[3]) * s01;
+ l_proj = 1.0f + u_proj + v_proj;
+
+ suv->uv[0] = l_proj * s3[0] - u_proj * s1[0] - v_proj * s2[0];
+ suv->uv[1] = l_proj * s3[1] - u_proj * s1[1] - v_proj * s2[1];
+ suv->uv[2] = 0.0f;
+
+ if (shi->osatex) {
+ float dxuv[2], dyuv[2];
+ dxuv[0] = s11 / Zmulx;
+ dxuv[1] = -s01 / Zmulx;
+ dyuv[0] = -s10 / Zmuly;
+ dyuv[1] = s00 / Zmuly;
+
+ dl_proj = dxuv[0] + dxuv[1];
+ suv->dxuv[0] = dl_proj * s3[0] - dxuv[0] * s1[0] - dxuv[1] * s2[0];
+ suv->dxuv[1] = dl_proj * s3[1] - dxuv[0] * s1[1] - dxuv[1] * s2[1];
+ dl_proj = dyuv[0] + dyuv[1];
+ suv->dyuv[0] = dl_proj * s3[0] - dyuv[0] * s1[0] - dyuv[1] * s2[0];
+ suv->dyuv[1] = dl_proj * s3[1] - dyuv[0] * s1[1] - dyuv[1] * s2[1];
+ }
+ }
+ else {
+
+ suv->uv[0] = -1.0f + 2.0f * (l * uv3[0] - u * uv1[0] - v * uv2[0]);
+ suv->uv[1] = -1.0f + 2.0f * (l * uv3[1] - u * uv1[1] - v * uv2[1]);
+ suv->uv[2] = 0.0f; /* texture.c assumes there are 3 coords */
+
+ if (shi->osatex) {
+ float duv[2];
+
+ dl = shi->dx_u + shi->dx_v;
+ duv[0] = shi->dx_u;
+ duv[1] = shi->dx_v;
+
+ suv->dxuv[0] = 2.0f * (dl * uv3[0] - duv[0] * uv1[0] - duv[1] * uv2[0]);
+ suv->dxuv[1] = 2.0f * (dl * uv3[1] - duv[0] * uv1[1] - duv[1] * uv2[1]);
+
+ dl = shi->dy_u + shi->dy_v;
+ duv[0] = shi->dy_u;
+ duv[1] = shi->dy_v;
+
+ suv->dyuv[0] = 2.0f * (dl * uv3[0] - duv[0] * uv1[0] - duv[1] * uv2[0]);
+ suv->dyuv[1] = 2.0f * (dl * uv3[1] - duv[0] * uv1[1] - duv[1] * uv2[1]);
+ }
+
+ if ((mode & MA_FACETEXTURE) && i == obr->actmtface) {
+ if (((mode & (MA_VERTEXCOL | MA_VERTEXCOLP)) == 0) && ((R.flag & R_NEED_VCOL) == 0)) {
+ shi->vcol[0] = 1.0f;
+ shi->vcol[1] = 1.0f;
+ shi->vcol[2] = 1.0f;
+ shi->vcol[3] = 1.0f;
+ }
+ if (tface->tpage) {
+ render_realtime_texture(shi, tface->tpage);
+ }
+ }
+ }
+ }
+
+ shi->dupliuv[0] = -1.0f + 2.0f * obi->dupliuv[0];
+ shi->dupliuv[1] = -1.0f + 2.0f * obi->dupliuv[1];
+ shi->dupliuv[2] = 0.0f;
+
+ if (shi->totuv == 0) {
+ ShadeInputUV *suv = &shi->uv[0];
+
+ suv->uv[0] = 2.0f * (u + .5f);
+ suv->uv[1] = 2.0f * (v + .5f);
+ suv->uv[2] = 0.0f; /* texture.c assumes there are 3 coords */
+
+ if (mode & MA_FACETEXTURE) {
+ /* no tface? set at 1.0f */
+ shi->vcol[0] = 1.0f;
+ shi->vcol[1] = 1.0f;
+ shi->vcol[2] = 1.0f;
+ shi->vcol[3] = 1.0f;
+ }
+ }
+ }
+
+ if (texco & TEXCO_NORM) {
+ shi->orn[0] = -shi->vn[0];
+ shi->orn[1] = -shi->vn[1];
+ shi->orn[2] = -shi->vn[2];
+ }
+
+ if (texco & TEXCO_STRESS) {
+ const float *s1, *s2, *s3;
+
+ s1 = RE_vertren_get_stress(obr, v1, 0);
+ s2 = RE_vertren_get_stress(obr, v2, 0);
+ s3 = RE_vertren_get_stress(obr, v3, 0);
+ if (s1 && s2 && s3) {
+ shi->stress = l * s3[0] - u * s1[0] - v * s2[0];
+ if (shi->stress < 1.0f) shi->stress -= 1.0f;
+ else shi->stress = (shi->stress - 1.0f) / shi->stress;
+ }
+ else shi->stress = 0.0f;
+ }
+
+ if (texco & TEXCO_TANGENT) {
+ if ((mode & MA_TANGENT_V) == 0) {
+ /* just prevent surprises */
+ shi->tang[0] = shi->tang[1] = shi->tang[2] = 0.0f;
+ shi->nmaptang[0] = shi->nmaptang[1] = shi->nmaptang[2] = 0.0f;
+ }
+ }
+ }
+
+ /* this only avalailable for scanline renders */
+ if (shi->depth == 0) {
+ float x = shi->xs;
+ float y = shi->ys;
+
+ if (texco & TEXCO_WINDOW) {
+ shi->winco[0] = -1.0f + 2.0f * x / (float)R.winx;
+ shi->winco[1] = -1.0f + 2.0f * y / (float)R.winy;
+ shi->winco[2] = 0.0f;
+ if (shi->osatex) {
+ shi->dxwin[0] = 2.0f / (float)R.winx;
+ shi->dywin[1] = 2.0f / (float)R.winy;
+ shi->dxwin[1] = shi->dxwin[2] = 0.0f;
+ shi->dywin[0] = shi->dywin[2] = 0.0f;
+ }
+ }
+ }
+ /* else {
+ * Note! For raytracing winco is not set,
+ * important because thus means all shader input's need to have their variables set to zero
+ * else un-initialized values are used
+ */
+ if (shi->do_manage) {
+ if ((mode & (MA_VERTEXCOL | MA_VERTEXCOLP | MA_FACETEXTURE)) || (R.flag & R_NEED_VCOL)) {
+ srgb_to_linearrgb_v3_v3(shi->vcol, shi->vcol);
+ }
+ }
+
+}
+
+/* ****************** ShadeSample ************************************** */
+
+/* initialize per part, not per pixel! */
+void shade_input_initialize(ShadeInput *shi, RenderPart *pa, RenderLayer *rl, int sample)
+{
+
+ memset(shi, 0, sizeof(ShadeInput));
+
+ shi->sample = sample;
+ shi->thread = pa->thread;
+ shi->do_preview = (R.r.scemode & R_MATNODE_PREVIEW) != 0;
+
+ shi->do_manage = BKE_scene_check_color_management_enabled(R.scene);
+ shi->use_world_space_shading = BKE_scene_use_world_space_shading(R.scene);
+
+ shi->lay = rl->lay;
+ shi->layflag = rl->layflag;
+ shi->passflag = rl->passflag;
+ shi->combinedflag = ~rl->pass_xor;
+ shi->mat_override = rl->mat_override;
+ shi->light_override = rl->light_override;
+// shi->rl= rl;
+ /* note shi.depth==0 means first hit, not raytracing */
+
+}
+
+/* initialize per part, not per pixel! */
+void shade_sample_initialize(ShadeSample *ssamp, RenderPart *pa, RenderLayer *rl)
+{
+ int a, tot;
+
+ tot = R.osa == 0 ? 1 : R.osa;
+
+ for (a = 0; a < tot; a++) {
+ shade_input_initialize(&ssamp->shi[a], pa, rl, a);
+ memset(&ssamp->shr[a], 0, sizeof(ShadeResult));
+ }
+
+ get_sample_layers(pa, rl, ssamp->rlpp);
+}
+
+/* Do AO or (future) GI */
+void shade_samples_do_AO(ShadeSample *ssamp)
+{
+ if (!(R.r.mode & R_SHADOW))
+ return;
+ if (!(R.r.mode & R_RAYTRACE) && !(R.wrld.ao_gather_method == WO_AOGATHER_APPROX))
+ return;
+
+ if (R.wrld.mode & (WO_AMB_OCC | WO_ENV_LIGHT | WO_INDIRECT_LIGHT)) {
+ ShadeInput *shi = &ssamp->shi[0];
+ int sample;
+
+ if (((shi->passflag & SCE_PASS_COMBINED) && (shi->combinedflag & (SCE_PASS_AO | SCE_PASS_ENVIRONMENT | SCE_PASS_INDIRECT))) ||
+ (shi->passflag & (SCE_PASS_AO | SCE_PASS_ENVIRONMENT | SCE_PASS_INDIRECT)))
+ {
+ for (sample = 0; sample < ssamp->tot; shi++, sample++)
+ if (!(shi->mode & MA_SHLESS))
+ ambient_occlusion(shi); /* stores in shi->ao[] */
+ }
+ }
+}
+
+
+void shade_samples_fill_with_ps(ShadeSample *ssamp, PixStr *ps, int x, int y)
+{
+ ShadeInput *shi;
+ float xs, ys;
+
+ ssamp->tot = 0;
+
+ for (shi = ssamp->shi; ps; ps = ps->next) {
+ shade_input_set_triangle(shi, ps->obi, ps->facenr, 1);
+
+ if (shi->vlr) { /* NULL happens for env material or for 'all z' */
+ unsigned short curmask = ps->mask;
+
+ /* full osa is only set for OSA renders */
+ if (shi->vlr->flag & R_FULL_OSA) {
+ short shi_cp = 0, samp;
+
+ for (samp = 0; samp < R.osa; samp++) {
+ if (curmask & (1 << samp)) {
+ /* zbuffer has this inverse corrected, ensures xs,ys are inside pixel */
+ xs = (float)x + R.jit[samp][0] + 0.5f;
+ ys = (float)y + R.jit[samp][1] + 0.5f;
+
+ if (shi_cp)
+ shade_input_copy_triangle(shi, shi - 1);
+
+ shi->mask = (1 << samp);
+// shi->rl= ssamp->rlpp[samp];
+ shi->samplenr = R.shadowsamplenr[shi->thread]++; /* this counter is not being reset per pixel */
+ shade_input_set_viewco(shi, x, y, xs, ys, (float)ps->z);
+ shade_input_set_uv(shi);
+ if (shi_cp == 0)
+ shade_input_set_normals(shi);
+ else /* XXX shi->flippednor messes up otherwise */
+ shade_input_set_vertex_normals(shi);
+
+ shi_cp = 1;
+ shi++;
+ }
+ }
+ }
+ else {
+ if (R.osa) {
+ short b = R.samples->centmask[curmask];
+ xs = (float)x + R.samples->centLut[b & 15] + 0.5f;
+ ys = (float)y + R.samples->centLut[b >> 4] + 0.5f;
+ }
+ else if (R.i.curblur) {
+ xs= (float)x + R.mblur_jit[R.i.curblur-1][0] + 0.5f;
+ ys= (float)y + R.mblur_jit[R.i.curblur-1][1] + 0.5f;
+ }
+ else {
+ xs = (float)x + 0.5f;
+ ys = (float)y + 0.5f;
+ }
+
+ shi->mask = curmask;
+ shi->samplenr = R.shadowsamplenr[shi->thread]++;
+ shade_input_set_viewco(shi, x, y, xs, ys, (float)ps->z);
+ shade_input_set_uv(shi);
+ shade_input_set_normals(shi);
+ shi++;
+ }
+
+ /* total sample amount, shi->sample is static set in initialize */
+ if (shi != ssamp->shi)
+ ssamp->tot = (shi - 1)->sample + 1;
+ }
+ }
+}
+
+/* shades samples, returns true if anything happened */
+int shade_samples(ShadeSample *ssamp, PixStr *ps, int x, int y)
+{
+ shade_samples_fill_with_ps(ssamp, ps, x, y);
+
+ if (ssamp->tot) {
+ ShadeInput *shi = ssamp->shi;
+ ShadeResult *shr = ssamp->shr;
+ int samp;
+
+ /* if shadow or AO? */
+ shade_samples_do_AO(ssamp);
+
+ /* if shade (all shadepinputs have same passflag) */
+ if (ssamp->shi[0].passflag & ~(SCE_PASS_Z | SCE_PASS_INDEXOB | SCE_PASS_INDEXMA)) {
+
+ for (samp = 0; samp < ssamp->tot; samp++, shi++, shr++) {
+ shade_input_set_shade_texco(shi);
+ shade_input_do_shade(shi, shr);
+ }
+ }
+ else if (shi->passflag & SCE_PASS_Z) {
+ for (samp = 0; samp < ssamp->tot; samp++, shi++, shr++)
+ shr->z = -shi->co[2];
+ }
+
+ return 1;
+ }
+ return 0;
+}
+
diff --git a/source/blender/render/intern/source/shadeoutput.c b/source/blender/render/intern/source/shadeoutput.c
new file mode 100644
index 00000000000..090c249defb
--- /dev/null
+++ b/source/blender/render/intern/source/shadeoutput.c
@@ -0,0 +1,2182 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2006 Blender Foundation
+ * All rights reserved.
+ *
+ * Contributors: Hos, Robert Wenzlaff.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/render/intern/source/shadeoutput.c
+ * \ingroup render
+ */
+
+#include <stdio.h>
+#include <float.h>
+#include <math.h>
+#include <string.h>
+
+#include "BLI_math.h"
+#include "BLI_utildefines.h"
+
+#include "BKE_colorband.h"
+#include "BKE_colortools.h"
+#include "BKE_material.h"
+
+#include "DNA_group_types.h"
+#include "DNA_lamp_types.h"
+#include "DNA_material_types.h"
+
+/* local include */
+#include "occlusion.h"
+#include "render_types.h"
+#include "rendercore.h"
+#include "shadbuf.h"
+#include "sss.h"
+#include "texture.h"
+
+#include "shading.h" /* own include */
+
+#include "IMB_colormanagement.h"
+
+/* could enable at some point but for now there are far too many conversions */
+#ifdef __GNUC__
+# pragma GCC diagnostic ignored "-Wdouble-promotion"
+#endif
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+/* defined in pipeline.c, is hardcopy of active dynamic allocated Render */
+/* only to be used here in this file, it's for speed */
+extern struct Render R;
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+ListBase *get_lights(ShadeInput *shi)
+{
+
+ if (R.r.scemode & R_BUTS_PREVIEW)
+ return &R.lights;
+ if (shi->light_override)
+ return &shi->light_override->gobject;
+ if (shi->mat && shi->mat->group)
+ return &shi->mat->group->gobject;
+
+ return &R.lights;
+}
+
+#if 0
+static void fogcolor(const float colf[3], float *rco, float *view)
+{
+ float alpha, stepsize, startdist, dist, hor[4], zen[3], vec[3], dview[3];
+ float div=0.0f, distfac;
+
+ hor[0]= R.wrld.horr; hor[1]= R.wrld.horg; hor[2]= R.wrld.horb;
+ zen[0]= R.wrld.zenr; zen[1]= R.wrld.zeng; zen[2]= R.wrld.zenb;
+
+ copy_v3_v3(vec, rco);
+
+ /* we loop from cur coord to mist start in steps */
+ stepsize= 1.0f;
+
+ div= ABS(view[2]);
+ dview[0]= view[0]/(stepsize*div);
+ dview[1]= view[1]/(stepsize*div);
+ dview[2]= -stepsize;
+
+ startdist= -rco[2] + BLI_frand();
+ for (dist= startdist; dist>R.wrld.miststa; dist-= stepsize) {
+
+ hor[0]= R.wrld.horr; hor[1]= R.wrld.horg; hor[2]= R.wrld.horb;
+ alpha= 1.0f;
+ do_sky_tex(vec, vec, NULL, hor, zen, &alpha);
+
+ distfac= (dist-R.wrld.miststa)/R.wrld.mistdist;
+
+ hor[3]= hor[0]*distfac*distfac;
+
+ /* premul! */
+ alpha= hor[3];
+ hor[0]= hor[0]*alpha;
+ hor[1]= hor[1]*alpha;
+ hor[2]= hor[2]*alpha;
+ addAlphaOverFloat(colf, hor);
+
+ sub_v3_v3(vec, dview);
+ }
+}
+#endif
+
+/* zcor is distance, co the 3d coordinate in eye space, return alpha */
+float mistfactor(float zcor, float const co[3])
+{
+ float fac, hi;
+
+ fac = zcor - R.wrld.miststa; /* zcor is calculated per pixel */
+
+ /* fac= -co[2]-R.wrld.miststa; */
+
+ if (fac > 0.0f) {
+ if (fac < R.wrld.mistdist) {
+
+ fac = (fac / R.wrld.mistdist);
+
+ if (R.wrld.mistype == 0) {
+ fac *= fac;
+ }
+ else if (R.wrld.mistype == 1) {
+ /* pass */
+ }
+ else {
+ fac = sqrtf(fac);
+ }
+ }
+ else {
+ fac = 1.0f;
+ }
+ }
+ else {
+ fac = 0.0f;
+ }
+
+ /* height switched off mist */
+ if (R.wrld.misthi!=0.0f && fac!=0.0f) {
+ /* at height misthi the mist is completely gone */
+
+ hi = R.viewinv[0][2] * co[0] +
+ R.viewinv[1][2] * co[1] +
+ R.viewinv[2][2] * co[2] +
+ R.viewinv[3][2];
+
+ if (hi > R.wrld.misthi) {
+ fac = 0.0f;
+ }
+ else if (hi>0.0f) {
+ hi= (R.wrld.misthi-hi)/R.wrld.misthi;
+ fac*= hi*hi;
+ }
+ }
+
+ return (1.0f-fac)* (1.0f-R.wrld.misi);
+}
+
+static void spothalo(struct LampRen *lar, ShadeInput *shi, float *intens)
+{
+ double a, b, c, disc, nray[3], npos[3];
+ double t0, t1 = 0.0f, t2= 0.0f, t3;
+ float p1[3], p2[3], ladist, maxz = 0.0f, maxy = 0.0f, haint;
+ int cuts;
+ bool do_clip = true, use_yco = false;
+
+ *intens= 0.0f;
+ haint= lar->haint;
+
+ if (R.r.mode & R_ORTHO) {
+ /* camera pos (view vector) cannot be used... */
+ /* camera position (cox,coy,0) rotate around lamp */
+ p1[0]= shi->co[0]-lar->co[0];
+ p1[1]= shi->co[1]-lar->co[1];
+ p1[2]= -lar->co[2];
+ mul_m3_v3(lar->imat, p1);
+ copy_v3db_v3fl(npos, p1); /* npos is double! */
+
+ /* pre-scale */
+ npos[2] *= (double)lar->sh_zfac;
+ }
+ else {
+ copy_v3db_v3fl(npos, lar->sh_invcampos); /* in initlamp calculated */
+ }
+
+ /* rotate view */
+ copy_v3db_v3fl(nray, shi->view);
+ mul_m3_v3_double(lar->imat, nray);
+
+ if (R.wrld.mode & WO_MIST) {
+ /* patchy... */
+ haint *= mistfactor(-lar->co[2], lar->co);
+ if (haint==0.0f) {
+ return;
+ }
+ }
+
+
+ /* rotate maxz */
+ if (shi->co[2]==0.0f) {
+ do_clip = false; /* for when halo at sky */
+ }
+ else {
+ p1[0]= shi->co[0]-lar->co[0];
+ p1[1]= shi->co[1]-lar->co[1];
+ p1[2]= shi->co[2]-lar->co[2];
+
+ maxz= lar->imat[0][2]*p1[0]+lar->imat[1][2]*p1[1]+lar->imat[2][2]*p1[2];
+ maxz*= lar->sh_zfac;
+ maxy= lar->imat[0][1]*p1[0]+lar->imat[1][1]*p1[1]+lar->imat[2][1]*p1[2];
+
+ if (fabs(nray[2]) < FLT_EPSILON) {
+ use_yco = true;
+ }
+ }
+
+ /* scale z to make sure volume is normalized */
+ nray[2] *= (double)lar->sh_zfac;
+ /* nray does not need normalization */
+
+ ladist= lar->sh_zfac*lar->dist;
+
+ /* solve */
+ a = nray[0] * nray[0] + nray[1] * nray[1] - nray[2]*nray[2];
+ b = nray[0] * npos[0] + nray[1] * npos[1] - nray[2]*npos[2];
+ c = npos[0] * npos[0] + npos[1] * npos[1] - npos[2]*npos[2];
+
+ cuts= 0;
+ if (fabs(a) < DBL_EPSILON) {
+ /*
+ * Only one intersection point...
+ */
+ return;
+ }
+ else {
+ disc = b*b - a*c;
+
+ if (disc==0.0) {
+ t1=t2= (-b)/ a;
+ cuts= 2;
+ }
+ else if (disc > 0.0) {
+ disc = sqrt(disc);
+ t1 = (-b + disc) / a;
+ t2 = (-b - disc) / a;
+ cuts= 2;
+ }
+ }
+ if (cuts==2) {
+ int ok1=0, ok2=0;
+
+ /* sort */
+ if (t1>t2) {
+ a= t1; t1= t2; t2= a;
+ }
+
+ /* z of intersection points with diabolo */
+ p1[2]= npos[2] + t1*nray[2];
+ p2[2]= npos[2] + t2*nray[2];
+
+ /* evaluate both points */
+ if (p1[2]<=0.0f) ok1= 1;
+ if (p2[2]<=0.0f && t1!=t2) ok2= 1;
+
+ /* at least 1 point with negative z */
+ if (ok1==0 && ok2==0) return;
+
+ /* intersction point with -ladist, the bottom of the cone */
+ if (use_yco == false) {
+ t3= ((double)(-ladist)-npos[2])/nray[2];
+
+ /* de we have to replace one of the intersection points? */
+ if (ok1) {
+ if (p1[2]<-ladist) t1= t3;
+ }
+ else {
+ t1= t3;
+ }
+ if (ok2) {
+ if (p2[2]<-ladist) t2= t3;
+ }
+ else {
+ t2= t3;
+ }
+ }
+ else if (ok1==0 || ok2==0) return;
+
+ /* at least 1 visible interesction point */
+ if (t1<0.0 && t2<0.0) return;
+
+ if (t1<0.0) t1= 0.0;
+ if (t2<0.0) t2= 0.0;
+
+ if (t1==t2) return;
+
+ /* sort again to be sure */
+ if (t1>t2) {
+ a= t1; t1= t2; t2= a;
+ }
+
+ /* calculate t0: is the maximum visible z (when halo is intersected by face) */
+ if (do_clip) {
+ if (use_yco == false) t0 = ((double)maxz - npos[2]) / nray[2];
+ else t0 = ((double)maxy - npos[1]) / nray[1];
+
+ if (t0 < t1) return;
+ if (t0 < t2) t2= t0;
+ }
+
+ /* calc points */
+ p1[0]= npos[0] + t1*nray[0];
+ p1[1]= npos[1] + t1*nray[1];
+ p1[2]= npos[2] + t1*nray[2];
+ p2[0]= npos[0] + t2*nray[0];
+ p2[1]= npos[1] + t2*nray[1];
+ p2[2]= npos[2] + t2*nray[2];
+
+
+ /* now we have 2 points, make three lengths with it */
+
+ a = len_v3(p1);
+ b = len_v3(p2);
+ c = len_v3v3(p1, p2);
+
+ a/= ladist;
+ a= sqrt(a);
+ b/= ladist;
+ b= sqrt(b);
+ c/= ladist;
+
+ *intens= c*( (1.0-a)+(1.0-b) );
+
+ /* WATCH IT: do not clip a,b en c at 1.0, this gives nasty little overflows
+ * at the edges (especially with narrow halos) */
+ if (*intens<=0.0f) return;
+
+ /* soft area */
+ /* not needed because t0 has been used for p1/p2 as well */
+ /* if (doclip && t0<t2) { */
+ /* *intens *= (t0-t1)/(t2-t1); */
+ /* } */
+
+ *intens *= haint;
+
+ if (lar->shb && lar->shb->shadhalostep) {
+ *intens *= shadow_halo(lar, p1, p2);
+ }
+
+ }
+}
+
+void renderspothalo(ShadeInput *shi, float col[4], float alpha)
+{
+ ListBase *lights;
+ GroupObject *go;
+ LampRen *lar;
+ float i;
+
+ if (alpha==0.0f) return;
+
+ lights= get_lights(shi);
+ for (go=lights->first; go; go= go->next) {
+ lar= go->lampren;
+ if (lar==NULL) continue;
+
+ if (lar->type==LA_SPOT && (lar->mode & LA_HALO) && (lar->buftype != LA_SHADBUF_DEEP) && lar->haint>0) {
+
+ if (lar->mode & LA_LAYER)
+ if (shi->vlr && (lar->lay & shi->obi->lay)==0)
+ continue;
+ if ((lar->lay & shi->lay)==0)
+ continue;
+
+ spothalo(lar, shi, &i);
+ if (i > 0.0f) {
+ const float i_alpha = i * alpha;
+ col[0] += i_alpha * lar->r;
+ col[1] += i_alpha * lar->g;
+ col[2] += i_alpha * lar->b;
+ col[3] += i_alpha; /* all premul */
+ }
+ }
+ }
+ /* clip alpha, is needed for unified 'alpha threshold' (vanillaRenderPipe.c) */
+ if (col[3]>1.0f) col[3]= 1.0f;
+}
+
+
+
+/* ---------------- shaders ----------------------- */
+
+static double Normalize_d(double *n)
+{
+ double d;
+
+ d= n[0]*n[0]+n[1]*n[1]+n[2]*n[2];
+
+ if (d>0.00000000000000001) {
+ d= sqrt(d);
+
+ n[0]/=d;
+ n[1]/=d;
+ n[2]/=d;
+ }
+ else {
+ n[0]=n[1]=n[2]= 0.0;
+ d= 0.0;
+ }
+ return d;
+}
+
+/* mix of 'real' fresnel and allowing control. grad defines blending gradient */
+float fresnel_fac(const float view[3], const float vn[3], float grad, float fac)
+{
+ float t1, t2;
+
+ if (fac==0.0f) return 1.0f;
+
+ t1 = dot_v3v3(view, vn);
+ if (t1>0.0f) t2= 1.0f+t1;
+ else t2= 1.0f-t1;
+
+ t2= grad + (1.0f-grad)*powf(t2, fac);
+
+ if (t2<0.0f) return 0.0f;
+ else if (t2>1.0f) return 1.0f;
+ return t2;
+}
+
+static double saacos_d(double fac)
+{
+ if (fac<= -1.0) return M_PI;
+ else if (fac>=1.0) return 0.0;
+ else return acos(fac);
+}
+
+/* Stoke's form factor. Need doubles here for extreme small area sizes */
+static float area_lamp_energy(float (*area)[3], const float co[3], const float vn[3])
+{
+ double fac;
+ double vec[4][3]; /* vectors of rendered co to vertices lamp */
+ double cross[4][3]; /* cross products of this */
+ double rad[4]; /* angles between vecs */
+
+ VECSUB(vec[0], co, area[0]);
+ VECSUB(vec[1], co, area[1]);
+ VECSUB(vec[2], co, area[2]);
+ VECSUB(vec[3], co, area[3]);
+
+ Normalize_d(vec[0]);
+ Normalize_d(vec[1]);
+ Normalize_d(vec[2]);
+ Normalize_d(vec[3]);
+
+ /* cross product */
+#define CROSS(dest, a, b) \
+ { \
+ dest[0]= a[1] * b[2] - a[2] * b[1]; \
+ dest[1]= a[2] * b[0] - a[0] * b[2]; \
+ dest[2]= a[0] * b[1] - a[1] * b[0]; \
+ } (void)0
+
+ CROSS(cross[0], vec[0], vec[1]);
+ CROSS(cross[1], vec[1], vec[2]);
+ CROSS(cross[2], vec[2], vec[3]);
+ CROSS(cross[3], vec[3], vec[0]);
+
+#undef CROSS
+
+ Normalize_d(cross[0]);
+ Normalize_d(cross[1]);
+ Normalize_d(cross[2]);
+ Normalize_d(cross[3]);
+
+ /* angles */
+ rad[0]= vec[0][0]*vec[1][0]+ vec[0][1]*vec[1][1]+ vec[0][2]*vec[1][2];
+ rad[1]= vec[1][0]*vec[2][0]+ vec[1][1]*vec[2][1]+ vec[1][2]*vec[2][2];
+ rad[2]= vec[2][0]*vec[3][0]+ vec[2][1]*vec[3][1]+ vec[2][2]*vec[3][2];
+ rad[3]= vec[3][0]*vec[0][0]+ vec[3][1]*vec[0][1]+ vec[3][2]*vec[0][2];
+
+ rad[0]= saacos_d(rad[0]);
+ rad[1]= saacos_d(rad[1]);
+ rad[2]= saacos_d(rad[2]);
+ rad[3]= saacos_d(rad[3]);
+
+ /* Stoke formula */
+ fac= rad[0]*(vn[0]*cross[0][0]+ vn[1]*cross[0][1]+ vn[2]*cross[0][2]);
+ fac+= rad[1]*(vn[0]*cross[1][0]+ vn[1]*cross[1][1]+ vn[2]*cross[1][2]);
+ fac+= rad[2]*(vn[0]*cross[2][0]+ vn[1]*cross[2][1]+ vn[2]*cross[2][2]);
+ fac+= rad[3]*(vn[0]*cross[3][0]+ vn[1]*cross[3][1]+ vn[2]*cross[3][2]);
+
+ if (fac<=0.0) return 0.0;
+ return fac;
+}
+
+static float area_lamp_energy_multisample(LampRen *lar, const float co[3], float *vn)
+{
+ /* corner vectors are moved around according lamp jitter */
+ float *jitlamp= lar->jitter, vec[3];
+ float area[4][3], intens= 0.0f;
+ int a= lar->ray_totsamp;
+
+ /* test if co is behind lamp */
+ sub_v3_v3v3(vec, co, lar->co);
+ if (dot_v3v3(vec, lar->vec) < 0.0f)
+ return 0.0f;
+
+ while (a--) {
+ vec[0]= jitlamp[0];
+ vec[1]= jitlamp[1];
+ vec[2]= 0.0f;
+ mul_m3_v3(lar->mat, vec);
+
+ add_v3_v3v3(area[0], lar->area[0], vec);
+ add_v3_v3v3(area[1], lar->area[1], vec);
+ add_v3_v3v3(area[2], lar->area[2], vec);
+ add_v3_v3v3(area[3], lar->area[3], vec);
+
+ intens+= area_lamp_energy(area, co, vn);
+
+ jitlamp+= 2;
+ }
+ intens /= (float)lar->ray_totsamp;
+
+ return pow(intens * lar->areasize, lar->k); /* corrected for buttons size and lar->dist^2 */
+}
+
+static float spec(float inp, int hard)
+{
+ float b1;
+
+ if (inp>=1.0f) return 1.0f;
+ else if (inp<=0.0f) return 0.0f;
+
+ b1= inp*inp;
+ /* avoid FPE */
+ if (b1<0.01f) b1= 0.01f;
+
+ if ((hard & 1)==0) inp= 1.0f;
+ if (hard & 2) inp*= b1;
+ b1*= b1;
+ if (hard & 4) inp*= b1;
+ b1*= b1;
+ if (hard & 8) inp*= b1;
+ b1*= b1;
+ if (hard & 16) inp*= b1;
+ b1*= b1;
+
+ /* avoid FPE */
+ if (b1<0.001f) b1= 0.0f;
+
+ if (hard & 32) inp*= b1;
+ b1*= b1;
+ if (hard & 64) inp*=b1;
+ b1*= b1;
+ if (hard & 128) inp*=b1;
+
+ if (b1<0.001f) b1= 0.0f;
+
+ if (hard & 256) {
+ b1*= b1;
+ inp*=b1;
+ }
+
+ return inp;
+}
+
+static float Phong_Spec(const float n[3], const float l[3], const float v[3], int hard, int tangent )
+{
+ float h[3];
+ float rslt;
+
+ h[0] = l[0] + v[0];
+ h[1] = l[1] + v[1];
+ h[2] = l[2] + v[2];
+ normalize_v3(h);
+
+ rslt = h[0]*n[0] + h[1]*n[1] + h[2]*n[2];
+ if (tangent) rslt= sasqrt(1.0f - rslt*rslt);
+
+ if ( rslt > 0.0f ) rslt= spec(rslt, hard);
+ else rslt = 0.0f;
+
+ return rslt;
+}
+
+
+/* reduced cook torrance spec (for off-specular peak) */
+static float CookTorr_Spec(const float n[3], const float l[3], const float v[3], int hard, int tangent)
+{
+ float i, nh, nv, h[3];
+
+ h[0]= v[0]+l[0];
+ h[1]= v[1]+l[1];
+ h[2]= v[2]+l[2];
+ normalize_v3(h);
+
+ nh= n[0]*h[0]+n[1]*h[1]+n[2]*h[2];
+ if (tangent) nh= sasqrt(1.0f - nh*nh);
+ else if (nh<0.0f) return 0.0f;
+
+ nv= n[0]*v[0]+n[1]*v[1]+n[2]*v[2];
+ if (tangent) nv= sasqrt(1.0f - nv*nv);
+ else if (nv<0.0f) nv= 0.0f;
+
+ i= spec(nh, hard);
+
+ i= i/(0.1f+nv);
+ return i;
+}
+
+/* Blinn spec */
+static float Blinn_Spec(const float n[3], const float l[3], const float v[3], float refrac, float spec_power, int tangent)
+{
+ float i, nh, nv, nl, vh, h[3];
+ float a, b, c, g=0.0f, p, f, ang;
+
+ if (refrac < 1.0f) return 0.0f;
+ if (spec_power == 0.0f) return 0.0f;
+
+ /* conversion from 'hardness' (1-255) to 'spec_power' (50 maps at 0.1) */
+ if (spec_power<100.0f)
+ spec_power = sqrtf(1.0f / spec_power);
+ else spec_power= 10.0f/spec_power;
+
+ h[0]= v[0]+l[0];
+ h[1]= v[1]+l[1];
+ h[2]= v[2]+l[2];
+ normalize_v3(h);
+
+ nh= n[0]*h[0]+n[1]*h[1]+n[2]*h[2]; /* Dot product between surface normal and half-way vector */
+ if (tangent) nh= sasqrt(1.0f - nh*nh);
+ else if (nh<0.0f) return 0.0f;
+
+ nv= n[0]*v[0]+n[1]*v[1]+n[2]*v[2]; /* Dot product between surface normal and view vector */
+ if (tangent) nv= sasqrt(1.0f - nv*nv);
+ if (nv<=0.01f) nv= 0.01f; /* hrms... */
+
+ nl= n[0]*l[0]+n[1]*l[1]+n[2]*l[2]; /* Dot product between surface normal and light vector */
+ if (tangent) nl= sasqrt(1.0f - nl*nl);
+ if (nl<=0.01f) {
+ return 0.0f;
+ }
+
+ vh= v[0]*h[0]+v[1]*h[1]+v[2]*h[2]; /* Dot product between view vector and half-way vector */
+ if (vh<=0.0f) vh= 0.01f;
+
+ a = 1.0f;
+ b = (2.0f*nh*nv)/vh;
+ c = (2.0f*nh*nl)/vh;
+
+ if ( a < b && a < c ) g = a;
+ else if ( b < a && b < c ) g = b;
+ else if ( c < a && c < b ) g = c;
+
+ p = sqrt((double)((refrac * refrac)+(vh * vh) - 1.0f));
+ f = (((p-vh)*(p-vh))/((p+vh)*(p+vh)))*(1+((((vh*(p+vh))-1.0f)*((vh*(p+vh))-1.0f))/(((vh*(p-vh))+1.0f)*((vh*(p-vh))+1.0f))));
+ ang = saacos(nh);
+
+ i= f * g * exp((double)(-(ang*ang) / (2.0f*spec_power*spec_power)));
+ if (i<0.0f) i= 0.0f;
+
+ return i;
+}
+
+/* cartoon render spec */
+static float Toon_Spec(const float n[3], const float l[3], const float v[3], float size, float smooth, int tangent)
+{
+ float h[3];
+ float ang;
+ float rslt;
+
+ h[0] = l[0] + v[0];
+ h[1] = l[1] + v[1];
+ h[2] = l[2] + v[2];
+ normalize_v3(h);
+
+ rslt = h[0]*n[0] + h[1]*n[1] + h[2]*n[2];
+ if (tangent) rslt = sasqrt(1.0f - rslt*rslt);
+
+ ang = saacos( rslt );
+
+ if ( ang < size ) rslt = 1.0f;
+ else if ( ang >= (size + smooth) || smooth == 0.0f ) rslt = 0.0f;
+ else rslt = 1.0f - ((ang - size) / smooth);
+
+ return rslt;
+}
+
+/* Ward isotropic gaussian spec */
+static float WardIso_Spec(const float n[3], const float l[3], const float v[3], float rms, int tangent)
+{
+ float i, nh, nv, nl, h[3], angle, alpha;
+
+
+ /* half-way vector */
+ h[0] = l[0] + v[0];
+ h[1] = l[1] + v[1];
+ h[2] = l[2] + v[2];
+ normalize_v3(h);
+
+ nh = n[0]*h[0]+n[1]*h[1]+n[2]*h[2]; /* Dot product between surface normal and half-way vector */
+ if (tangent) nh = sasqrt(1.0f - nh*nh);
+ if (nh<=0.0f) nh = 0.001f;
+
+ nv = n[0]*v[0]+n[1]*v[1]+n[2]*v[2]; /* Dot product between surface normal and view vector */
+ if (tangent) nv = sasqrt(1.0f - nv*nv);
+ if (nv<=0.0f) nv = 0.001f;
+
+ nl = n[0]*l[0]+n[1]*l[1]+n[2]*l[2]; /* Dot product between surface normal and light vector */
+ if (tangent) nl = sasqrt(1.0f - nl*nl);
+ if (nl<=0.0f) nl = 0.001f;
+
+ angle = tanf(saacos(nh));
+ alpha = MAX2(rms, 0.001f);
+
+ i= nl * (1.0f/(4.0f*(float)M_PI*alpha*alpha)) * (expf( -(angle*angle)/(alpha*alpha))/(sqrtf(nv*nl)));
+
+ return i;
+}
+
+/* cartoon render diffuse */
+static float Toon_Diff(const float n[3], const float l[3], const float UNUSED(v[3]), float size, float smooth)
+{
+ float rslt, ang;
+
+ rslt = n[0]*l[0] + n[1]*l[1] + n[2]*l[2];
+
+ ang = saacos(rslt);
+
+ if ( ang < size ) rslt = 1.0f;
+ else if ( ang >= (size + smooth) || smooth == 0.0f ) rslt = 0.0f;
+ else rslt = 1.0f - ((ang - size) / smooth);
+
+ return rslt;
+}
+
+/* Oren Nayar diffuse */
+
+/* 'nl' is either dot product, or return value of area light */
+/* in latter case, only last multiplication uses 'nl' */
+static float OrenNayar_Diff(float nl, const float n[3], const float l[3], const float v[3], float rough )
+{
+ float i/*, nh*/, nv /*, vh */, realnl, h[3];
+ float a, b, t, A, B;
+ float Lit_A, View_A, Lit_B[3], View_B[3];
+
+ h[0]= v[0]+l[0];
+ h[1]= v[1]+l[1];
+ h[2]= v[2]+l[2];
+ normalize_v3(h);
+
+ /* nh= n[0]*h[0]+n[1]*h[1]+n[2]*h[2]; */ /* Dot product between surface normal and half-way vector */
+ /* if (nh<0.0f) nh = 0.0f; */
+
+ nv= n[0]*v[0]+n[1]*v[1]+n[2]*v[2]; /* Dot product between surface normal and view vector */
+ if (nv<=0.0f) nv= 0.0f;
+
+ realnl= n[0]*l[0]+n[1]*l[1]+n[2]*l[2]; /* Dot product between surface normal and light vector */
+ if (realnl<=0.0f) return 0.0f;
+ if (nl<0.0f) return 0.0f; /* value from area light */
+
+ /* vh= v[0]*h[0]+v[1]*h[1]+v[2]*h[2]; */ /* Dot product between view vector and halfway vector */
+ /* if (vh<=0.0f) vh= 0.0f; */
+
+ Lit_A = saacos(realnl);
+ View_A = saacos( nv );
+
+ Lit_B[0] = l[0] - (realnl * n[0]);
+ Lit_B[1] = l[1] - (realnl * n[1]);
+ Lit_B[2] = l[2] - (realnl * n[2]);
+ normalize_v3(Lit_B);
+
+ View_B[0] = v[0] - (nv * n[0]);
+ View_B[1] = v[1] - (nv * n[1]);
+ View_B[2] = v[2] - (nv * n[2]);
+ normalize_v3(View_B);
+
+ t = Lit_B[0]*View_B[0] + Lit_B[1]*View_B[1] + Lit_B[2]*View_B[2];
+ if ( t < 0 ) t = 0;
+
+ if ( Lit_A > View_A ) {
+ a = Lit_A;
+ b = View_A;
+ }
+ else {
+ a = View_A;
+ b = Lit_A;
+ }
+
+ A = 1.0f - (0.5f * ((rough * rough) / ((rough * rough) + 0.33f)));
+ B = 0.45f * ((rough * rough) / ((rough * rough) + 0.09f));
+
+ b*= 0.95f; /* prevent tangens from shooting to inf, 'nl' can be not a dot product here. */
+ /* overflow only happens with extreme size area light, and higher roughness */
+ i = nl * ( A + ( B * t * sinf(a) * tanf(b) ) );
+
+ return i;
+}
+
+/* Minnaert diffuse */
+static float Minnaert_Diff(float nl, const float n[3], const float v[3], float darkness)
+{
+ float i, nv;
+
+ /* nl = dot product between surface normal and light vector */
+ if (nl <= 0.0f)
+ return 0.0f;
+
+ /* nv = dot product between surface normal and view vector */
+ nv = dot_v3v3(n, v);
+ if (nv < 0.0f)
+ nv = 0.0f;
+
+ if (darkness <= 1.0f)
+ i = nl * pow(max_ff(nv * nl, 0.1f), (darkness - 1.0f) ); /*The Real model*/
+ else
+ i = nl * pow( (1.001f - nv), (darkness - 1.0f) ); /*Nvidia model*/
+
+ return i;
+}
+
+static float Fresnel_Diff(float *vn, float *lv, float *UNUSED(view), float fac_i, float fac)
+{
+ return fresnel_fac(lv, vn, fac_i, fac);
+}
+
+/* --------------------------------------------- */
+/* also called from texture.c */
+void calc_R_ref(ShadeInput *shi)
+{
+ float i;
+
+ /* shi->vn dot shi->view */
+ i= -2*(shi->vn[0]*shi->view[0]+shi->vn[1]*shi->view[1]+shi->vn[2]*shi->view[2]);
+
+ shi->ref[0]= (shi->view[0]+i*shi->vn[0]);
+ shi->ref[1]= (shi->view[1]+i*shi->vn[1]);
+ shi->ref[2]= (shi->view[2]+i*shi->vn[2]);
+ if (shi->osatex) {
+ if (shi->vlr->flag & R_SMOOTH) {
+ i= -2*( (shi->vn[0]+shi->dxno[0])*(shi->view[0]+shi->dxview) +
+ (shi->vn[1]+shi->dxno[1])*shi->view[1]+ (shi->vn[2]+shi->dxno[2])*shi->view[2] );
+
+ shi->dxref[0]= shi->ref[0]- ( shi->view[0]+shi->dxview+i*(shi->vn[0]+shi->dxno[0]));
+ shi->dxref[1]= shi->ref[1]- (shi->view[1]+ i*(shi->vn[1]+shi->dxno[1]));
+ shi->dxref[2]= shi->ref[2]- (shi->view[2]+ i*(shi->vn[2]+shi->dxno[2]));
+
+ i= -2*( (shi->vn[0]+shi->dyno[0])*shi->view[0]+
+ (shi->vn[1]+shi->dyno[1])*(shi->view[1]+shi->dyview)+ (shi->vn[2]+shi->dyno[2])*shi->view[2] );
+
+ shi->dyref[0]= shi->ref[0]- (shi->view[0]+ i*(shi->vn[0]+shi->dyno[0]));
+ shi->dyref[1]= shi->ref[1]- (shi->view[1]+shi->dyview+i*(shi->vn[1]+shi->dyno[1]));
+ shi->dyref[2]= shi->ref[2]- (shi->view[2]+ i*(shi->vn[2]+shi->dyno[2]));
+
+ }
+ else {
+
+ i= -2*( shi->vn[0]*(shi->view[0]+shi->dxview) +
+ shi->vn[1]*shi->view[1]+ shi->vn[2]*shi->view[2] );
+
+ shi->dxref[0]= shi->ref[0]- (shi->view[0]+shi->dxview+i*shi->vn[0]);
+ shi->dxref[1]= shi->ref[1]- (shi->view[1]+ i*shi->vn[1]);
+ shi->dxref[2]= shi->ref[2]- (shi->view[2]+ i*shi->vn[2]);
+
+ i= -2*( shi->vn[0]*shi->view[0]+
+ shi->vn[1]*(shi->view[1]+shi->dyview)+ shi->vn[2]*shi->view[2] );
+
+ shi->dyref[0]= shi->ref[0]- (shi->view[0]+ i*shi->vn[0]);
+ shi->dyref[1]= shi->ref[1]- (shi->view[1]+shi->dyview+i*shi->vn[1]);
+ shi->dyref[2]= shi->ref[2]- (shi->view[2]+ i*shi->vn[2]);
+ }
+ }
+
+}
+
+/* called from rayshade.c */
+void shade_color(ShadeInput *shi, ShadeResult *shr)
+{
+ Material *ma= shi->mat;
+
+ if (ma->mode & (MA_FACETEXTURE)) {
+ shi->r= shi->vcol[0];
+ shi->g= shi->vcol[1];
+ shi->b= shi->vcol[2];
+ if (ma->mode & (MA_FACETEXTURE_ALPHA))
+ shi->alpha= shi->vcol[3];
+ }
+ else if (ma->mode & (MA_VERTEXCOLP)) {
+ float neg_alpha = 1.0f - shi->vcol[3];
+ shi->r= shi->r*neg_alpha + shi->vcol[0]*shi->vcol[3];
+ shi->g= shi->g*neg_alpha + shi->vcol[1]*shi->vcol[3];
+ shi->b= shi->b*neg_alpha + shi->vcol[2]*shi->vcol[3];
+ }
+
+ if (ma->texco)
+ do_material_tex(shi, &R);
+
+ if (ma->fresnel_tra!=0.0f)
+ shi->alpha*= fresnel_fac(shi->view, shi->vn, ma->fresnel_tra_i, ma->fresnel_tra);
+
+ if (!(shi->mode & MA_TRANSP)) shi->alpha= 1.0f;
+
+ shr->diff[0]= shi->r;
+ shr->diff[1]= shi->g;
+ shr->diff[2]= shi->b;
+ shr->alpha= shi->alpha;
+
+ /* modulate by the object color */
+ if ((ma->shade_flag & MA_OBCOLOR) && shi->obr->ob) {
+ float obcol[4];
+
+ copy_v4_v4(obcol, shi->obr->ob->col);
+ CLAMP(obcol[3], 0.0f, 1.0f);
+
+ shr->diff[0] *= obcol[0];
+ shr->diff[1] *= obcol[1];
+ shr->diff[2] *= obcol[2];
+ if (shi->mode & MA_TRANSP) shr->alpha *= obcol[3];
+ }
+
+ copy_v3_v3(shr->diffshad, shr->diff);
+}
+
+/* ramp for at end of shade */
+static void ramp_diffuse_result(float *diff, ShadeInput *shi)
+{
+ Material *ma= shi->mat;
+ float col[4];
+
+ if (ma->ramp_col) {
+ if (ma->rampin_col==MA_RAMP_IN_RESULT) {
+ float fac = IMB_colormanagement_get_luminance(diff);
+ BKE_colorband_evaluate(ma->ramp_col, fac, col);
+
+ /* blending method */
+ fac= col[3]*ma->rampfac_col;
+
+ ramp_blend(ma->rampblend_col, diff, fac, col);
+ }
+ }
+}
+
+/* r,g,b denote energy, ramp is used with different values to make new material color */
+static void add_to_diffuse(float diff[3], const ShadeInput *shi, const float is, const float rgb[3])
+{
+ Material *ma= shi->mat;
+
+ if (ma->ramp_col && (ma->mode & MA_RAMP_COL)) {
+
+ /* MA_RAMP_IN_RESULT is exceptional */
+ if (ma->rampin_col==MA_RAMP_IN_RESULT) {
+ /* normal add */
+ diff[0] += rgb[0] * shi->r;
+ diff[1] += rgb[1] * shi->g;
+ diff[2] += rgb[2] * shi->b;
+ }
+ else {
+ float colt[3], col[4];
+ float fac;
+
+ /* input */
+ switch (ma->rampin_col) {
+ case MA_RAMP_IN_ENERGY:
+ fac = IMB_colormanagement_get_luminance(rgb);
+ break;
+ case MA_RAMP_IN_SHADER:
+ fac = is;
+ break;
+ case MA_RAMP_IN_NOR:
+ fac = dot_v3v3(shi->view, shi->vn);
+ break;
+ default:
+ fac = 0.0f;
+ break;
+ }
+
+ BKE_colorband_evaluate(ma->ramp_col, fac, col);
+
+ /* blending method */
+ fac = col[3] * ma->rampfac_col;
+ copy_v3_v3(colt, &shi->r);
+
+ ramp_blend(ma->rampblend_col, colt, fac, col);
+
+ /* output to */
+ diff[0] += rgb[0] * colt[0];
+ diff[1] += rgb[1] * colt[1];
+ diff[2] += rgb[2] * colt[2];
+ }
+ }
+ else {
+ diff[0] += rgb[0] * shi->r;
+ diff[1] += rgb[1] * shi->g;
+ diff[2] += rgb[2] * shi->b;
+ }
+}
+
+static void ramp_spec_result(float spec_col[3], ShadeInput *shi)
+{
+ Material *ma= shi->mat;
+
+ if (ma->ramp_spec && (ma->rampin_spec==MA_RAMP_IN_RESULT)) {
+ float col[4];
+ float fac = IMB_colormanagement_get_luminance(spec_col);
+
+ BKE_colorband_evaluate(ma->ramp_spec, fac, col);
+
+ /* blending method */
+ fac= col[3]*ma->rampfac_spec;
+
+ ramp_blend(ma->rampblend_spec, spec_col, fac, col);
+
+ }
+}
+
+/* is = dot product shade, t = spec energy */
+static void do_specular_ramp(ShadeInput *shi, float is, float t, float spec[3])
+{
+ Material *ma= shi->mat;
+
+ spec[0]= shi->specr;
+ spec[1]= shi->specg;
+ spec[2]= shi->specb;
+
+ /* MA_RAMP_IN_RESULT is exception */
+ if (ma->ramp_spec && (ma->rampin_spec!=MA_RAMP_IN_RESULT)) {
+ float fac;
+ float col[4];
+
+ /* input */
+ switch (ma->rampin_spec) {
+ case MA_RAMP_IN_ENERGY:
+ fac= t;
+ break;
+ case MA_RAMP_IN_SHADER:
+ fac= is;
+ break;
+ case MA_RAMP_IN_NOR:
+ fac= shi->view[0]*shi->vn[0] + shi->view[1]*shi->vn[1] + shi->view[2]*shi->vn[2];
+ break;
+ default:
+ fac= 0.0f;
+ break;
+ }
+
+ BKE_colorband_evaluate(ma->ramp_spec, fac, col);
+
+ /* blending method */
+ fac= col[3]*ma->rampfac_spec;
+
+ ramp_blend(ma->rampblend_spec, spec, fac, col);
+ }
+}
+
+/* pure AO, check for raytrace and world should have been done */
+/* preprocess, textures were not done, don't use shi->amb for that reason */
+void ambient_occlusion(ShadeInput *shi)
+{
+ if ((R.wrld.ao_gather_method == WO_AOGATHER_APPROX) && shi->mat->amb!=0.0f) {
+ sample_occ(&R, shi);
+ }
+ else if ((R.r.mode & R_RAYTRACE) && shi->mat->amb!=0.0f) {
+ ray_ao(shi, shi->ao, shi->env);
+ }
+ else {
+ shi->ao[0]= shi->ao[1]= shi->ao[2]= 1.0f;
+ zero_v3(shi->env);
+ zero_v3(shi->indirect);
+ }
+}
+
+
+/* wrld mode was checked for */
+static void ambient_occlusion_apply(ShadeInput *shi, ShadeResult *shr)
+{
+ float f= R.wrld.aoenergy;
+ float tmp[3], tmpspec[3];
+
+ if (!((R.r.mode & R_RAYTRACE) || R.wrld.ao_gather_method == WO_AOGATHER_APPROX))
+ return;
+ if (f == 0.0f)
+ return;
+
+ if (R.wrld.aomix==WO_AOADD) {
+ shr->combined[0] += shi->ao[0]*shi->r*shi->refl*f;
+ shr->combined[1] += shi->ao[1]*shi->g*shi->refl*f;
+ shr->combined[2] += shi->ao[2]*shi->b*shi->refl*f;
+ }
+ else if (R.wrld.aomix==WO_AOMUL) {
+ mul_v3_v3v3(tmp, shr->combined, shi->ao);
+ mul_v3_v3v3(tmpspec, shr->spec, shi->ao);
+
+ if (f == 1.0f) {
+ copy_v3_v3(shr->combined, tmp);
+ copy_v3_v3(shr->spec, tmpspec);
+ }
+ else {
+ interp_v3_v3v3(shr->combined, shr->combined, tmp, f);
+ interp_v3_v3v3(shr->spec, shr->spec, tmpspec, f);
+ }
+ }
+}
+
+void environment_lighting_apply(ShadeInput *shi, ShadeResult *shr)
+{
+ float f= R.wrld.ao_env_energy*shi->amb;
+
+ if (!((R.r.mode & R_RAYTRACE) || R.wrld.ao_gather_method == WO_AOGATHER_APPROX))
+ return;
+ if (f == 0.0f)
+ return;
+
+ shr->combined[0] += shi->env[0]*shi->r*shi->refl*f;
+ shr->combined[1] += shi->env[1]*shi->g*shi->refl*f;
+ shr->combined[2] += shi->env[2]*shi->b*shi->refl*f;
+}
+
+static void indirect_lighting_apply(ShadeInput *shi, ShadeResult *shr)
+{
+ float f= R.wrld.ao_indirect_energy;
+
+ if (!((R.r.mode & R_RAYTRACE) || R.wrld.ao_gather_method == WO_AOGATHER_APPROX))
+ return;
+ if (f == 0.0f)
+ return;
+
+ shr->combined[0] += shi->indirect[0]*shi->r*shi->refl*f;
+ shr->combined[1] += shi->indirect[1]*shi->g*shi->refl*f;
+ shr->combined[2] += shi->indirect[2]*shi->b*shi->refl*f;
+}
+
+/* result written in shadfac */
+void lamp_get_shadow(LampRen *lar, ShadeInput *shi, float inp, float shadfac[4], int do_real)
+{
+ LampShadowSubSample *lss= &(lar->shadsamp[shi->thread].s[shi->sample]);
+
+ if (do_real || lss->samplenr!=shi->samplenr) {
+
+ shadfac[0]= shadfac[1]= shadfac[2]= shadfac[3]= 1.0f;
+
+ if (lar->shb) {
+ if (lar->buftype==LA_SHADBUF_IRREGULAR)
+ shadfac[3]= ISB_getshadow(shi, lar->shb);
+ else
+ shadfac[3] = testshadowbuf(&R, lar->shb, shi->co, shi->dxco, shi->dyco, inp, shi->mat->lbias);
+ }
+ else if (lar->mode & LA_SHAD_RAY) {
+ ray_shadow(shi, lar, shadfac);
+ }
+
+ if (shi->depth==0) {
+ copy_v4_v4(lss->shadfac, shadfac);
+ lss->samplenr= shi->samplenr;
+ }
+ }
+ else {
+ copy_v4_v4(shadfac, lss->shadfac);
+ }
+}
+
+/* lampdistance and spot angle, writes in lv and dist */
+float lamp_get_visibility(LampRen *lar, const float co[3], float lv[3], float *dist)
+{
+ if (lar->type==LA_SUN || lar->type==LA_HEMI) {
+ *dist= 1.0f;
+ copy_v3_v3(lv, lar->vec);
+ return 1.0f;
+ }
+ else {
+ float visifac= 1.0f, visifac_r;
+
+ sub_v3_v3v3(lv, co, lar->co);
+ mul_v3_fl(lv, 1.0f / (*dist = len_v3(lv)));
+
+ /* area type has no quad or sphere option */
+ if (lar->type==LA_AREA) {
+ /* area is single sided */
+ //if (dot_v3v3(lv, lar->vec) > 0.0f)
+ // visifac= 1.0f;
+ //else
+ // visifac= 0.0f;
+ }
+ else {
+ switch (lar->falloff_type) {
+ case LA_FALLOFF_CONSTANT:
+ visifac = 1.0f;
+ break;
+ case LA_FALLOFF_INVLINEAR:
+ visifac = lar->dist/(lar->dist + dist[0]);
+ break;
+ case LA_FALLOFF_INVSQUARE:
+ /* NOTE: This seems to be a hack since commit r12045 says this
+ * option is similar to old Quad, but with slight changes.
+ * Correct inv square would be (which would be old Quad):
+ * visifac = lar->distkw / (lar->distkw + dist[0]*dist[0]);
+ */
+ visifac = lar->dist / (lar->dist + dist[0]*dist[0]);
+ break;
+ case LA_FALLOFF_SLIDERS:
+ if (lar->ld1>0.0f)
+ visifac= lar->dist/(lar->dist+lar->ld1*dist[0]);
+ if (lar->ld2>0.0f)
+ visifac*= lar->distkw/(lar->distkw+lar->ld2*dist[0]*dist[0]);
+ break;
+ case LA_FALLOFF_INVCOEFFICIENTS:
+ visifac_r = lar->coeff_const +
+ lar->coeff_lin * dist[0] +
+ lar->coeff_quad * dist[0] * dist[0];
+ if (visifac_r > 0.0)
+ visifac = 1.0 / visifac_r;
+ else
+ visifac = 0.0;
+ break;
+ case LA_FALLOFF_CURVE:
+ /* curvemapping_initialize is called from #add_render_lamp */
+ visifac = curvemapping_evaluateF(lar->curfalloff, 0, dist[0]/lar->dist);
+ break;
+ }
+
+ if (lar->mode & LA_SPHERE) {
+ float t= lar->dist - dist[0];
+ if (t<=0.0f)
+ visifac= 0.0f;
+ else
+ visifac*= t/lar->dist;
+ }
+
+ if (visifac > 0.0f) {
+ if (lar->type==LA_SPOT) {
+ float inpr, t;
+
+ if (lar->mode & LA_SQUARE) {
+ if (dot_v3v3(lv, lar->vec) > 0.0f) {
+ float lvrot[3], x;
+
+ /* rotate view to lampspace */
+ copy_v3_v3(lvrot, lv);
+ mul_m3_v3(lar->imat, lvrot);
+
+ x = max_ff(fabsf(lvrot[0]/lvrot[2]), fabsf(lvrot[1]/lvrot[2]));
+ /* 1.0f/(sqrt(1+x*x)) is equivalent to cos(atan(x)) */
+
+ inpr = 1.0f / (sqrtf(1.0f + x * x));
+ }
+ else inpr= 0.0f;
+ }
+ else {
+ inpr= lv[0]*lar->vec[0]+lv[1]*lar->vec[1]+lv[2]*lar->vec[2];
+ }
+
+ t= lar->spotsi;
+ if (inpr<=t)
+ visifac= 0.0f;
+ else {
+ t= inpr-t;
+ if (t<lar->spotbl && lar->spotbl!=0.0f) {
+ /* soft area */
+ float i= t/lar->spotbl;
+ t= i*i;
+ inpr*= (3.0f*t-2.0f*t*i);
+ }
+ visifac*= inpr;
+ }
+ }
+ }
+ }
+ if (visifac <= 0.001f) visifac = 0.0f;
+ return visifac;
+ }
+}
+
+/* function returns raw diff, spec and full shadowed diff in the 'shad' pass */
+static void shade_one_light(LampRen *lar, ShadeInput *shi, ShadeResult *shr, int passflag)
+{
+ Material *ma= shi->mat;
+ VlakRen *vlr= shi->vlr;
+ float lv[3], lampdist, lacol[3], shadfac[4], lashdw[3];
+ float i, is, i_noshad, inp, *vn, *view, vnor[3], phongcorr=1.0f;
+ float visifac;
+
+ vn= shi->vn;
+ view= shi->view;
+
+
+ if (lar->energy == 0.0f) return;
+ /* only shadow lamps shouldn't affect shadow-less materials at all */
+ if ((lar->mode & LA_ONLYSHADOW) && (!(ma->mode & MA_SHADOW) || !(R.r.mode & R_SHADOW)))
+ return;
+ /* optimization, don't render fully black lamps */
+ if (!(lar->mode & LA_TEXTURE) && (lar->r + lar->g + lar->b == 0.0f))
+ return;
+
+ /* lampdist, spot angle, area side, ... */
+ visifac= lamp_get_visibility(lar, shi->co, lv, &lampdist);
+ if (visifac==0.0f)
+ return;
+
+ if (lar->type==LA_SPOT) {
+ if (lar->mode & LA_OSATEX) {
+ shi->osatex= 1; /* signal for multitex() */
+
+ shi->dxlv[0]= lv[0] - (shi->co[0]-lar->co[0]+shi->dxco[0])/lampdist;
+ shi->dxlv[1]= lv[1] - (shi->co[1]-lar->co[1]+shi->dxco[1])/lampdist;
+ shi->dxlv[2]= lv[2] - (shi->co[2]-lar->co[2]+shi->dxco[2])/lampdist;
+
+ shi->dylv[0]= lv[0] - (shi->co[0]-lar->co[0]+shi->dyco[0])/lampdist;
+ shi->dylv[1]= lv[1] - (shi->co[1]-lar->co[1]+shi->dyco[1])/lampdist;
+ shi->dylv[2]= lv[2] - (shi->co[2]-lar->co[2]+shi->dyco[2])/lampdist;
+ }
+ }
+
+ /* lamp color texture */
+ lacol[0]= lar->r;
+ lacol[1]= lar->g;
+ lacol[2]= lar->b;
+
+ lashdw[0]= lar->shdwr;
+ lashdw[1]= lar->shdwg;
+ lashdw[2]= lar->shdwb;
+
+ if (lar->mode & LA_TEXTURE) do_lamp_tex(lar, lv, shi, lacol, LA_TEXTURE);
+ if (lar->mode & LA_SHAD_TEX) do_lamp_tex(lar, lv, shi, lashdw, LA_SHAD_TEX);
+
+ /* tangent case; calculate fake face normal, aligned with lampvector */
+ /* note, vnor==vn is used as tangent trigger for buffer shadow */
+ if (vlr->flag & R_TANGENT) {
+ float cross[3], nstrand[3], blend;
+
+ if (ma->mode & MA_STR_SURFDIFF) {
+ cross_v3_v3v3(cross, shi->surfnor, vn);
+ cross_v3_v3v3(nstrand, vn, cross);
+
+ blend= dot_v3v3(nstrand, shi->surfnor);
+ blend= 1.0f - blend;
+ CLAMP(blend, 0.0f, 1.0f);
+
+ interp_v3_v3v3(vnor, nstrand, shi->surfnor, blend);
+ normalize_v3(vnor);
+ }
+ else {
+ cross_v3_v3v3(cross, lv, vn);
+ cross_v3_v3v3(vnor, cross, vn);
+ normalize_v3(vnor);
+ }
+
+ if (ma->strand_surfnor > 0.0f) {
+ if (ma->strand_surfnor > shi->surfdist) {
+ blend= (ma->strand_surfnor - shi->surfdist)/ma->strand_surfnor;
+ interp_v3_v3v3(vnor, vnor, shi->surfnor, blend);
+ normalize_v3(vnor);
+ }
+ }
+
+ vnor[0]= -vnor[0];vnor[1]= -vnor[1];vnor[2]= -vnor[2];
+ vn= vnor;
+ }
+ else if (ma->mode & MA_TANGENT_V) {
+ float cross[3];
+ cross_v3_v3v3(cross, lv, shi->tang);
+ cross_v3_v3v3(vnor, cross, shi->tang);
+ normalize_v3(vnor);
+ vnor[0]= -vnor[0];vnor[1]= -vnor[1];vnor[2]= -vnor[2];
+ vn= vnor;
+ }
+
+ /* dot product and reflectivity */
+ /* inp = dotproduct, is = shader result, i = lamp energy (with shadow), i_noshad = i without shadow */
+ inp= dot_v3v3(vn, lv);
+
+ /* phong threshold to prevent backfacing faces having artifacts on ray shadow (terminator problem) */
+ /* this complex construction screams for a nicer implementation! (ton) */
+ if (R.r.mode & R_SHADOW) {
+ if (ma->mode & MA_SHADOW) {
+ if (lar->type == LA_HEMI || lar->type == LA_AREA) {
+ /* pass */
+ }
+ else if ((ma->mode & MA_RAYBIAS) && (lar->mode & LA_SHAD_RAY) && (vlr->flag & R_SMOOTH)) {
+ float thresh= shi->obr->ob->smoothresh;
+ if (inp>thresh)
+ phongcorr= (inp-thresh)/(inp*(1.0f-thresh));
+ else
+ phongcorr= 0.0f;
+ }
+ else if (ma->sbias!=0.0f && ((lar->mode & LA_SHAD_RAY) || lar->shb)) {
+ if (inp>ma->sbias)
+ phongcorr= (inp-ma->sbias)/(inp*(1.0f-ma->sbias));
+ else
+ phongcorr= 0.0f;
+ }
+ }
+ }
+
+ /* diffuse shaders */
+ if (lar->mode & LA_NO_DIFF) {
+ is = 0.0f; /* skip shaders */
+ }
+ else if (lar->type==LA_HEMI) {
+ is = 0.5f * inp + 0.5f;
+ }
+ else {
+
+ if (lar->type==LA_AREA)
+ inp= area_lamp_energy_multisample(lar, shi->co, vn);
+
+ /* diffuse shaders (oren nayer gets inp from area light) */
+ if (ma->diff_shader==MA_DIFF_ORENNAYAR) is= OrenNayar_Diff(inp, vn, lv, view, ma->roughness);
+ else if (ma->diff_shader==MA_DIFF_TOON) is= Toon_Diff(vn, lv, view, ma->param[0], ma->param[1]);
+ else if (ma->diff_shader==MA_DIFF_MINNAERT) is= Minnaert_Diff(inp, vn, view, ma->darkness);
+ else if (ma->diff_shader==MA_DIFF_FRESNEL) is= Fresnel_Diff(vn, lv, view, ma->param[0], ma->param[1]);
+ else is= inp; /* Lambert */
+ }
+
+ /* 'is' is diffuse */
+ if ((ma->shade_flag & MA_CUBIC) && is > 0.0f && is < 1.0f) {
+ is= 3.0f * is * is - 2.0f * is * is * is; /* nicer termination of shades */
+ }
+
+ i= is*phongcorr;
+
+ if (i>0.0f) {
+ i*= visifac*shi->refl;
+ }
+ i_noshad= i;
+
+ vn = shi->vn; /* bring back original vector, we use special specular shaders for tangent */
+ if (ma->mode & MA_TANGENT_V)
+ vn= shi->tang;
+
+ /* init transp shadow */
+ shadfac[0]= shadfac[1]= shadfac[2]= shadfac[3]= 1.0f;
+
+ /* shadow and spec, (visifac==0 outside spot) */
+ if (visifac> 0.0f) {
+
+ if ((R.r.mode & R_SHADOW)) {
+ if (ma->mode & MA_SHADOW) {
+ if (lar->shb || (lar->mode & LA_SHAD_RAY)) {
+
+ if (vn==vnor) /* tangent trigger */
+ lamp_get_shadow(lar, shi, dot_v3v3(shi->vn, lv), shadfac, shi->depth);
+ else
+ lamp_get_shadow(lar, shi, inp, shadfac, shi->depth);
+
+ /* warning, here it skips the loop */
+ if ((lar->mode & LA_ONLYSHADOW) && i>0.0f) {
+
+ shadfac[3]= i*lar->energy*(1.0f-shadfac[3]);
+ shr->shad[0] -= shadfac[3]*shi->r*(1.0f-lashdw[0]);
+ shr->shad[1] -= shadfac[3]*shi->g*(1.0f-lashdw[1]);
+ shr->shad[2] -= shadfac[3]*shi->b*(1.0f-lashdw[2]);
+
+ if (!(lar->mode & LA_NO_SPEC)) {
+ shr->spec[0] -= shadfac[3]*shi->specr*(1.0f-lashdw[0]);
+ shr->spec[1] -= shadfac[3]*shi->specg*(1.0f-lashdw[1]);
+ shr->spec[2] -= shadfac[3]*shi->specb*(1.0f-lashdw[2]);
+ }
+
+ return;
+ }
+
+ i*= shadfac[3];
+ shr->shad[3] = shadfac[3]; /* store this for possible check in troublesome cases */
+ }
+ else {
+ shr->shad[3] = 1.0f; /* No shadow at all! */
+ }
+ }
+ }
+
+ /* in case 'no diffuse' we still do most calculus, spec can be in shadow.*/
+ if (!(lar->mode & LA_NO_DIFF)) {
+ if (i>0.0f) {
+ if (ma->mode & MA_SHADOW_TRA) {
+ const float tcol[3] = {
+ i * shadfac[0] * lacol[0],
+ i * shadfac[1] * lacol[1],
+ i * shadfac[2] * lacol[2],
+ };
+ add_to_diffuse(shr->shad, shi, is, tcol);
+ }
+ else {
+ const float tcol[3] = {
+ i * lacol[0],
+ i * lacol[1],
+ i * lacol[2],
+ };
+ add_to_diffuse(shr->shad, shi, is, tcol);
+ }
+ }
+ /* add light for colored shadow */
+ if (i_noshad>i && !(lashdw[0]==0 && lashdw[1]==0 && lashdw[2]==0)) {
+ const float tcol[3] = {
+ lashdw[0] * (i_noshad - i) * lacol[0],
+ lashdw[1] * (i_noshad - i) * lacol[1],
+ lashdw[2] * (i_noshad - i) * lacol[2],
+ };
+ add_to_diffuse(shr->shad, shi, is, tcol);
+ }
+ if (i_noshad>0.0f) {
+ if (passflag & (SCE_PASS_DIFFUSE|SCE_PASS_SHADOW) ||
+ ((passflag & SCE_PASS_COMBINED) && !(shi->combinedflag & SCE_PASS_SHADOW)))
+ {
+ const float tcol[3] = {
+ i_noshad * lacol[0],
+ i_noshad * lacol[1],
+ i_noshad * lacol[2]
+ };
+ add_to_diffuse(shr->diff, shi, is, tcol);
+ }
+ else {
+ copy_v3_v3(shr->diff, shr->shad);
+ }
+ }
+ }
+
+ /* specularity */
+ shadfac[3]*= phongcorr; /* note, shadfac not allowed to be stored nonlocal */
+
+ if (shadfac[3]>0.0f && shi->spec!=0.0f && !(lar->mode & LA_NO_SPEC) && !(lar->mode & LA_ONLYSHADOW)) {
+
+ if (!(passflag & (SCE_PASS_COMBINED | SCE_PASS_SPEC))) {
+ /* pass */
+ }
+ else if (lar->type == LA_HEMI) {
+ float t;
+ /* hemi uses no spec shaders (yet) */
+
+ lv[0]+= view[0];
+ lv[1]+= view[1];
+ lv[2]+= view[2];
+
+ normalize_v3(lv);
+
+ t= vn[0]*lv[0]+vn[1]*lv[1]+vn[2]*lv[2];
+
+ if (lar->type==LA_HEMI) {
+ t= 0.5f*t+0.5f;
+ }
+
+ t= shadfac[3]*shi->spec*spec(t, shi->har);
+
+ shr->spec[0]+= t*(lacol[0] * shi->specr);
+ shr->spec[1]+= t*(lacol[1] * shi->specg);
+ shr->spec[2]+= t*(lacol[2] * shi->specb);
+ }
+ else {
+ /* specular shaders */
+ float specfac, t;
+
+ if (ma->spec_shader==MA_SPEC_PHONG)
+ specfac= Phong_Spec(vn, lv, view, shi->har, (vlr->flag & R_TANGENT) || (ma->mode & MA_TANGENT_V));
+ else if (ma->spec_shader==MA_SPEC_COOKTORR)
+ specfac= CookTorr_Spec(vn, lv, view, shi->har, (vlr->flag & R_TANGENT) || (ma->mode & MA_TANGENT_V));
+ else if (ma->spec_shader==MA_SPEC_BLINN)
+ specfac= Blinn_Spec(vn, lv, view, ma->refrac, (float)shi->har, (vlr->flag & R_TANGENT) || (ma->mode & MA_TANGENT_V));
+ else if (ma->spec_shader==MA_SPEC_WARDISO)
+ specfac= WardIso_Spec( vn, lv, view, ma->rms, (vlr->flag & R_TANGENT) || (ma->mode & MA_TANGENT_V));
+ else
+ specfac= Toon_Spec(vn, lv, view, ma->param[2], ma->param[3], (vlr->flag & R_TANGENT) || (ma->mode & MA_TANGENT_V));
+
+ /* area lamp correction */
+ if (lar->type==LA_AREA) specfac*= inp;
+
+ t= shadfac[3]*shi->spec*visifac*specfac;
+
+ if (ma->mode & MA_RAMP_SPEC) {
+ float spec[3];
+ do_specular_ramp(shi, specfac, t, spec);
+ shr->spec[0]+= t*(lacol[0] * spec[0]);
+ shr->spec[1]+= t*(lacol[1] * spec[1]);
+ shr->spec[2]+= t*(lacol[2] * spec[2]);
+ }
+ else {
+ shr->spec[0]+= t*(lacol[0] * shi->specr);
+ shr->spec[1]+= t*(lacol[1] * shi->specg);
+ shr->spec[2]+= t*(lacol[2] * shi->specb);
+ }
+ }
+ }
+ }
+}
+
+static void shade_lamp_loop_only_shadow(ShadeInput *shi, ShadeResult *shr)
+{
+
+ if (R.r.mode & R_SHADOW) {
+ ListBase *lights;
+ LampRen *lar;
+ GroupObject *go;
+ float inpr, lv[3];
+ float /* *view, */ shadfac[4];
+ float ir, accum, visifac, lampdist;
+ float shaded = 0.0f, lightness = 0.0f;
+
+
+ /* view= shi->view; */ /* UNUSED */
+ accum= ir= 0.0f;
+
+ lights= get_lights(shi);
+ for (go=lights->first; go; go= go->next) {
+ lar= go->lampren;
+ if (lar==NULL) continue;
+
+ if (lar->mode & LA_LAYER) if ((lar->lay & shi->obi->lay)==0) continue;
+ if ((lar->lay & shi->lay)==0) continue;
+
+ if (lar->shb || (lar->mode & LA_SHAD_RAY)) {
+ visifac= lamp_get_visibility(lar, shi->co, lv, &lampdist);
+ ir+= 1.0f;
+
+ if (visifac <= 0.0f) {
+ if (shi->mat->shadowonly_flag == MA_SO_OLD)
+ accum+= 1.0f;
+
+ continue;
+ }
+ inpr= dot_v3v3(shi->vn, lv);
+ if (inpr <= 0.0f) {
+ if (shi->mat->shadowonly_flag == MA_SO_OLD)
+ accum+= 1.0f;
+
+ continue;
+ }
+
+ lamp_get_shadow(lar, shi, inpr, shadfac, shi->depth);
+
+ if (shi->mat->shadowonly_flag == MA_SO_OLD) {
+ /* Old "Shadows Only" */
+ accum+= (1.0f-visifac) + (visifac)*IMB_colormanagement_get_luminance(shadfac)*shadfac[3];
+ }
+ else {
+ shaded += IMB_colormanagement_get_luminance(shadfac)*shadfac[3] * visifac * lar->energy;
+
+ if (shi->mat->shadowonly_flag == MA_SO_SHADOW) {
+ lightness += visifac * lar->energy;
+ }
+ }
+ }
+ }
+
+ /* Apply shadows as alpha */
+ if (ir>0.0f) {
+ if (shi->mat->shadowonly_flag == MA_SO_OLD) {
+ accum = 1.0f - accum/ir;
+ }
+ else {
+ if (shi->mat->shadowonly_flag == MA_SO_SHADOW) {
+ if (lightness > 0.0f) {
+ /* Get shadow value from between 0.0f and non-shadowed lightness */
+ accum = (lightness - shaded) / (lightness);
+ }
+ else {
+ accum = 0.0f;
+ }
+ }
+ else { /* shadowonly_flag == MA_SO_SHADED */
+ /* Use shaded value */
+ accum = 1.0f - shaded;
+ }
+ }
+
+ shr->alpha= (shi->alpha)*(accum);
+ if (shr->alpha<0.0f) shr->alpha=0.0f;
+ }
+ else {
+ /* If "fully shaded", use full alpha even on areas that have no lights */
+ if (shi->mat->shadowonly_flag == MA_SO_SHADED) shr->alpha=shi->alpha;
+ else shr->alpha= 0.f;
+ }
+ }
+
+ /* quite disputable this... also note it doesn't mirror-raytrace */
+ if ((R.wrld.mode & (WO_AMB_OCC|WO_ENV_LIGHT)) && shi->amb!=0.0f) {
+ float f;
+
+ if (R.wrld.mode & WO_AMB_OCC) {
+ f= R.wrld.aoenergy*shi->amb;
+
+ if (R.wrld.aomix==WO_AOADD) {
+ if (shi->mat->shadowonly_flag == MA_SO_OLD) {
+ f= f*(1.0f - IMB_colormanagement_get_luminance(shi->ao));
+ shr->alpha= (shr->alpha + f)*f;
+ }
+ else {
+ shr->alpha -= f*IMB_colormanagement_get_luminance(shi->ao);
+ if (shr->alpha<0.0f) shr->alpha=0.0f;
+ }
+ }
+ else /* AO Multiply */
+ shr->alpha= (1.0f - f)*shr->alpha + f*(1.0f - (1.0f - shr->alpha)*IMB_colormanagement_get_luminance(shi->ao));
+ }
+
+ if (R.wrld.mode & WO_ENV_LIGHT) {
+ if (shi->mat->shadowonly_flag == MA_SO_OLD) {
+ f= R.wrld.ao_env_energy*shi->amb*(1.0f - IMB_colormanagement_get_luminance(shi->env));
+ shr->alpha= (shr->alpha + f)*f;
+ }
+ else {
+ f= R.wrld.ao_env_energy*shi->amb;
+ shr->alpha -= f*IMB_colormanagement_get_luminance(shi->env);
+ if (shr->alpha<0.0f) shr->alpha=0.0f;
+ }
+ }
+ }
+}
+
+/* let's map negative light as if it mirrors positive light, otherwise negative values disappear */
+static void wrld_exposure_correct(float diff[3])
+{
+
+ diff[0]= R.wrld.linfac*(1.0f-expf( diff[0]*R.wrld.logfac) );
+ diff[1]= R.wrld.linfac*(1.0f-expf( diff[1]*R.wrld.logfac) );
+ diff[2]= R.wrld.linfac*(1.0f-expf( diff[2]*R.wrld.logfac) );
+}
+
+void shade_lamp_loop(ShadeInput *shi, ShadeResult *shr)
+{
+ /* Passes which might need to know material color.
+ *
+ * It seems to be faster to just calculate material color
+ * even if the pass doesn't really need it than trying to
+ * figure out whether color is really needed or not.
+ */
+ const int color_passes =
+ SCE_PASS_COMBINED | SCE_PASS_RGBA | SCE_PASS_DIFFUSE | SCE_PASS_SPEC |
+ SCE_PASS_REFLECT | SCE_PASS_NORMAL | SCE_PASS_REFRACT | SCE_PASS_EMIT | SCE_PASS_SHADOW;
+
+ Material *ma= shi->mat;
+ int passflag= shi->passflag;
+
+ memset(shr, 0, sizeof(ShadeResult));
+
+ if (!(shi->mode & MA_TRANSP)) shi->alpha = 1.0f;
+
+ /* separate loop */
+ if (ma->mode & MA_ONLYSHADOW) {
+ shade_lamp_loop_only_shadow(shi, shr);
+ return;
+ }
+
+ /* envmap hack, always reset */
+ shi->refcol[0]= shi->refcol[1]= shi->refcol[2]= shi->refcol[3]= 0.0f;
+
+ /* material color itself */
+ if (passflag & color_passes) {
+ if (ma->mode & (MA_FACETEXTURE)) {
+ shi->r= shi->vcol[0];
+ shi->g= shi->vcol[1];
+ shi->b= shi->vcol[2];
+ if (ma->mode & (MA_FACETEXTURE_ALPHA))
+ shi->alpha= shi->vcol[3];
+ }
+#ifdef WITH_FREESTYLE
+ else if (ma->vcol_alpha) {
+ shi->r= shi->vcol[0];
+ shi->g= shi->vcol[1];
+ shi->b= shi->vcol[2];
+ shi->alpha= shi->vcol[3];
+ }
+#endif
+ else if (ma->mode & (MA_VERTEXCOLP)) {
+ float neg_alpha = 1.0f - shi->vcol[3];
+ shi->r= shi->r*neg_alpha + shi->vcol[0]*shi->vcol[3];
+ shi->g= shi->g*neg_alpha + shi->vcol[1]*shi->vcol[3];
+ shi->b= shi->b*neg_alpha + shi->vcol[2]*shi->vcol[3];
+ }
+ if (ma->texco) {
+ do_material_tex(shi, &R);
+ if (!(shi->mode & MA_TRANSP)) shi->alpha = 1.0f;
+ }
+
+ shr->col[0]= shi->r*shi->alpha;
+ shr->col[1]= shi->g*shi->alpha;
+ shr->col[2]= shi->b*shi->alpha;
+ shr->col[3]= shi->alpha;
+
+ if ((ma->sss_flag & MA_DIFF_SSS) && !sss_pass_done(&R, ma)) {
+ if (ma->sss_texfac == 0.0f) {
+ shi->r= shi->g= shi->b= shi->alpha= 1.0f;
+ shr->col[0]= shr->col[1]= shr->col[2]= shr->col[3]= 1.0f;
+ }
+ else {
+ shi->r= pow(max_ff(shi->r, 0.0f), ma->sss_texfac);
+ shi->g= pow(max_ff(shi->g, 0.0f), ma->sss_texfac);
+ shi->b= pow(max_ff(shi->b, 0.0f), ma->sss_texfac);
+ shi->alpha= pow(max_ff(shi->alpha, 0.0f), ma->sss_texfac);
+
+ shr->col[0]= pow(max_ff(shr->col[0], 0.0f), ma->sss_texfac);
+ shr->col[1]= pow(max_ff(shr->col[1], 0.0f), ma->sss_texfac);
+ shr->col[2]= pow(max_ff(shr->col[2], 0.0f), ma->sss_texfac);
+ shr->col[3]= pow(max_ff(shr->col[3], 0.0f), ma->sss_texfac);
+ }
+ }
+ }
+
+ if (ma->mode & MA_SHLESS) {
+ shr->combined[0]= shi->r;
+ shr->combined[1]= shi->g;
+ shr->combined[2]= shi->b;
+ shr->alpha= shi->alpha;
+ goto finally_shadeless;
+ }
+
+ if ( (ma->mode & (MA_VERTEXCOL|MA_VERTEXCOLP))== MA_VERTEXCOL ) { /* vertexcolor light */
+ shr->emit[0]= shi->r*(shi->emit+shi->vcol[0]*shi->vcol[3]);
+ shr->emit[1]= shi->g*(shi->emit+shi->vcol[1]*shi->vcol[3]);
+ shr->emit[2]= shi->b*(shi->emit+shi->vcol[2]*shi->vcol[3]);
+ }
+ else {
+ shr->emit[0]= shi->r*shi->emit;
+ shr->emit[1]= shi->g*shi->emit;
+ shr->emit[2]= shi->b*shi->emit;
+ }
+
+ /* AO pass */
+ if (((passflag & SCE_PASS_COMBINED) && (shi->combinedflag & (SCE_PASS_AO|SCE_PASS_ENVIRONMENT|SCE_PASS_INDIRECT))) ||
+ (passflag & (SCE_PASS_AO|SCE_PASS_ENVIRONMENT|SCE_PASS_INDIRECT))) {
+ if ((R.wrld.mode & (WO_AMB_OCC|WO_ENV_LIGHT|WO_INDIRECT_LIGHT)) && (R.r.mode & R_SHADOW)) {
+ /* AO was calculated for scanline already */
+ if (shi->depth || shi->volume_depth)
+ ambient_occlusion(shi);
+ copy_v3_v3(shr->ao, shi->ao);
+ copy_v3_v3(shr->env, shi->env); /* XXX multiply */
+ copy_v3_v3(shr->indirect, shi->indirect); /* XXX multiply */
+ }
+ else {
+ shr->ao[0]= shr->ao[1]= shr->ao[2]= 1.0f;
+ zero_v3(shr->env);
+ zero_v3(shr->indirect);
+ }
+ }
+
+ /* lighting pass */
+ if (passflag & (SCE_PASS_COMBINED|SCE_PASS_DIFFUSE|SCE_PASS_SPEC|SCE_PASS_SHADOW)) {
+ GroupObject *go;
+ ListBase *lights;
+ LampRen *lar;
+
+ lights= get_lights(shi);
+ for (go=lights->first; go; go= go->next) {
+ lar= go->lampren;
+ if (lar==NULL) continue;
+
+ /* test for lamp layer */
+ if (lar->mode & LA_LAYER) if ((lar->lay & shi->obi->lay)==0) continue;
+ if ((lar->lay & shi->lay)==0) continue;
+
+ /* accumulates in shr->diff and shr->spec and shr->shad (diffuse with shadow!) */
+ shade_one_light(lar, shi, shr, passflag);
+ }
+
+ /* this check is to prevent only shadow lamps from producing negative
+ * colors.*/
+ if (shr->spec[0] < 0) shr->spec[0] = 0;
+ if (shr->spec[1] < 0) shr->spec[1] = 0;
+ if (shr->spec[2] < 0) shr->spec[2] = 0;
+
+ if (shr->shad[0] < 0) shr->shad[0] = 0;
+ if (shr->shad[1] < 0) shr->shad[1] = 0;
+ if (shr->shad[2] < 0) shr->shad[2] = 0;
+
+ if (ma->sss_flag & MA_DIFF_SSS) {
+ float sss[3], col[3], invalpha, texfac= ma->sss_texfac;
+
+ /* this will return false in the preprocess stage */
+ if (sample_sss(&R, ma, shi->co, sss)) {
+ invalpha= (shr->col[3] > FLT_EPSILON)? 1.0f/shr->col[3]: 1.0f;
+
+ if (texfac==0.0f) {
+ copy_v3_v3(col, shr->col);
+ mul_v3_fl(col, invalpha);
+ }
+ else if (texfac==1.0f) {
+ col[0]= col[1]= col[2]= 1.0f;
+ mul_v3_fl(col, invalpha);
+ }
+ else {
+ copy_v3_v3(col, shr->col);
+ mul_v3_fl(col, invalpha);
+ col[0]= pow(max_ff(col[0], 0.0f), 1.0f-texfac);
+ col[1]= pow(max_ff(col[1], 0.0f), 1.0f-texfac);
+ col[2]= pow(max_ff(col[2], 0.0f), 1.0f-texfac);
+ }
+
+ shr->diff[0]= sss[0]*col[0];
+ shr->diff[1]= sss[1]*col[1];
+ shr->diff[2]= sss[2]*col[2];
+
+ if (shi->combinedflag & SCE_PASS_SHADOW) {
+ shr->shad[0]= shr->diff[0];
+ shr->shad[1]= shr->diff[1];
+ shr->shad[2]= shr->diff[2];
+ }
+ }
+ }
+
+ if (shi->combinedflag & SCE_PASS_SHADOW)
+ copy_v3_v3(shr->diffshad, shr->shad);
+ else
+ copy_v3_v3(shr->diffshad, shr->diff);
+
+ copy_v3_v3(shr->combined, shr->diffshad);
+
+ /* calculate shadow pass, we use a multiplication mask */
+ /* Even if diff = 0,0,0, it does matter what the shadow pass is, since we may want it 'for itself'! */
+ if (passflag & SCE_PASS_SHADOW) {
+ if (shr->diff[0]!=0.0f) shr->shad[0]= shr->shad[0]/shr->diff[0];
+ /* can't determine proper shadow from shad/diff (0/0), so use shadow intensity */
+ else if (shr->shad[0]==0.0f) shr->shad[0]= shr->shad[3];
+
+ if (shr->diff[1]!=0.0f) shr->shad[1]= shr->shad[1]/shr->diff[1];
+ else if (shr->shad[1]==0.0f) shr->shad[1]= shr->shad[3];
+
+ if (shr->diff[2]!=0.0f) shr->shad[2]= shr->shad[2]/shr->diff[2];
+ else if (shr->shad[2]==0.0f) shr->shad[2]= shr->shad[3];
+ }
+
+ /* exposure correction */
+ if ((R.wrld.exp!=0.0f || R.wrld.range!=1.0f) && !R.sss_points) {
+ wrld_exposure_correct(shr->combined); /* has no spec! */
+ wrld_exposure_correct(shr->spec);
+ }
+ }
+
+ /* alpha in end, spec can influence it */
+ if (passflag & (SCE_PASS_COMBINED)) {
+ if ((ma->fresnel_tra!=0.0f) && (shi->mode & MA_TRANSP))
+ shi->alpha*= fresnel_fac(shi->view, shi->vn, ma->fresnel_tra_i, ma->fresnel_tra);
+
+ /* note: shi->mode! */
+ if (shi->mode & MA_TRANSP && (shi->mode & (MA_ZTRANSP|MA_RAYTRANSP))) {
+ if (shi->spectra!=0.0f) {
+ float t = max_fff(shr->spec[0], shr->spec[1], shr->spec[2]);
+ t *= shi->spectra;
+ if (t>1.0f) t= 1.0f;
+ shi->alpha= (1.0f-t)*shi->alpha+t;
+ }
+ }
+ }
+ shr->alpha= shi->alpha;
+
+ /* from now stuff everything in shr->combined: ambient, AO, ramps, exposure */
+ if (!(ma->sss_flag & MA_DIFF_SSS) || !sss_pass_done(&R, ma)) {
+ if (R.r.mode & R_SHADOW) {
+ /* add AO in combined? */
+ if (R.wrld.mode & WO_AMB_OCC)
+ if (shi->combinedflag & SCE_PASS_AO)
+ ambient_occlusion_apply(shi, shr);
+
+ if (R.wrld.mode & WO_ENV_LIGHT)
+ if (shi->combinedflag & SCE_PASS_ENVIRONMENT)
+ environment_lighting_apply(shi, shr);
+
+ if (R.wrld.mode & WO_INDIRECT_LIGHT)
+ if (shi->combinedflag & SCE_PASS_INDIRECT)
+ indirect_lighting_apply(shi, shr);
+ }
+
+ shr->combined[0]+= shi->ambr;
+ shr->combined[1]+= shi->ambg;
+ shr->combined[2]+= shi->ambb;
+
+ if (ma->mode & MA_RAMP_COL) ramp_diffuse_result(shr->combined, shi);
+ }
+
+ if (ma->mode & MA_RAMP_SPEC) ramp_spec_result(shr->spec, shi);
+
+ /* refcol is for envmap only */
+ if (shi->refcol[0]!=0.0f) {
+ float result[3];
+
+ result[0]= shi->mirr*shi->refcol[1] + (1.0f - shi->mirr*shi->refcol[0])*shr->combined[0];
+ result[1]= shi->mirg*shi->refcol[2] + (1.0f - shi->mirg*shi->refcol[0])*shr->combined[1];
+ result[2]= shi->mirb*shi->refcol[3] + (1.0f - shi->mirb*shi->refcol[0])*shr->combined[2];
+
+ if (passflag & SCE_PASS_REFLECT)
+ sub_v3_v3v3(shr->refl, result, shr->combined);
+
+ if (shi->combinedflag & SCE_PASS_REFLECT)
+ copy_v3_v3(shr->combined, result);
+
+ }
+
+ /* and add emit and spec */
+ if (shi->combinedflag & SCE_PASS_EMIT)
+ add_v3_v3(shr->combined, shr->emit);
+ if (shi->combinedflag & SCE_PASS_SPEC)
+ add_v3_v3(shr->combined, shr->spec);
+
+
+ /* Last section of this function applies to shadeless colors too */
+finally_shadeless:
+
+ /* modulate by the object color */
+ if ((ma->shade_flag & MA_OBCOLOR) && shi->obr->ob) {
+ if (!(ma->sss_flag & MA_DIFF_SSS) || !sss_pass_done(&R, ma)) {
+ float obcol[4];
+
+ copy_v4_v4(obcol, shi->obr->ob->col);
+ CLAMP(obcol[3], 0.0f, 1.0f);
+
+ shr->combined[0] *= obcol[0];
+ shr->combined[1] *= obcol[1];
+ shr->combined[2] *= obcol[2];
+ if (shi->mode & MA_TRANSP) shr->alpha *= obcol[3];
+ }
+ }
+
+ shr->combined[3]= shr->alpha;
+}
+
+/* used for "Lamp Data" shader node */
+static float lamp_get_data_internal(ShadeInput *shi, GroupObject *go, float col[4], float lv[3], float *dist, float shadow[4])
+{
+ LampRen *lar = go->lampren;
+ float visifac, inp;
+
+ if (!lar
+ || ((lar->mode & LA_LAYER) && (lar->lay & shi->obi->lay) == 0)
+ || (lar->lay & shi->lay) == 0)
+ return 0.0f;
+
+ if (lar->mode & LA_TEXTURE)
+ do_lamp_tex(lar, lv, shi, col, LA_TEXTURE);
+
+ visifac = lamp_get_visibility(lar, shi->co, lv, dist);
+
+ if (visifac == 0.0f
+ || lar->type == LA_HEMI
+ || (lar->type != LA_SPOT && !(lar->mode & LA_SHAD_RAY))
+ || (R.r.scemode & R_BUTS_PREVIEW))
+ return visifac;
+
+ inp = dot_v3v3(shi->vn, lv);
+
+ if (inp > 0.0f) {
+ float shadfac[4];
+
+ shadow[0] = lar->shdwr;
+ shadow[1] = lar->shdwg;
+ shadow[2] = lar->shdwb;
+
+ if (lar->mode & LA_SHAD_TEX)
+ do_lamp_tex(lar, lv, shi, shadow, LA_SHAD_TEX);
+
+ if (R.r.mode & R_SHADOW) {
+ lamp_get_shadow(lar, shi, inp, shadfac, shi->depth);
+
+ shadow[0] = 1.0f - ((1.0f - shadfac[0] * shadfac[3]) * (1.0f - shadow[0]));
+ shadow[1] = 1.0f - ((1.0f - shadfac[1] * shadfac[3]) * (1.0f - shadow[1]));
+ shadow[2] = 1.0f - ((1.0f - shadfac[2] * shadfac[3]) * (1.0f - shadow[2]));
+ }
+ }
+
+ return visifac;
+}
+
+float RE_lamp_get_data(ShadeInput *shi, Object *lamp_obj, float col[4], float lv[3], float *dist, float shadow[4])
+{
+ col[0] = col[1] = col[2] = 0.0f;
+ col[3] = 1.0f;
+ copy_v3_v3(lv, shi->vn);
+ *dist = 1.0f;
+ shadow[0] = shadow[1] = shadow[2] = shadow[3] = 1.0f;
+
+ if (lamp_obj->type == OB_LAMP) {
+ GroupObject *go;
+ Lamp *lamp = (Lamp *)lamp_obj->data;
+
+ col[0] = lamp->r * lamp->energy;
+ col[1] = lamp->g * lamp->energy;
+ col[2] = lamp->b * lamp->energy;
+
+ if (R.r.scemode & R_BUTS_PREVIEW) {
+ for (go = R.lights.first; go; go = go->next) {
+ /* "Lamp.002" is main key light of material preview */
+ if (STREQ(go->ob->id.name + 2, "Lamp.002"))
+ return lamp_get_data_internal(shi, go, col, lv, dist, shadow);
+ }
+ return 0.0f;
+ }
+
+ if (shi->light_override) {
+ for (go = shi->light_override->gobject.first; go; go = go->next) {
+ if (go->ob == lamp_obj)
+ return lamp_get_data_internal(shi, go, col, lv, dist, shadow);
+ }
+ }
+
+ if (shi->mat && shi->mat->group) {
+ for (go = shi->mat->group->gobject.first; go; go = go->next) {
+ if (go->ob == lamp_obj)
+ return lamp_get_data_internal(shi, go, col, lv, dist, shadow);
+ }
+ }
+
+ for (go = R.lights.first; go; go = go->next) {
+ if (go->ob == lamp_obj)
+ return lamp_get_data_internal(shi, go, col, lv, dist, shadow);
+ }
+ }
+
+ return 0.0f;
+}
+
+const float (*RE_object_instance_get_matrix(struct ObjectInstanceRen *obi, int matrix_id))[4]
+{
+ if (obi) {
+ switch (matrix_id) {
+ case RE_OBJECT_INSTANCE_MATRIX_OB:
+ return (const float(*)[4])obi->obmat;
+ case RE_OBJECT_INSTANCE_MATRIX_OBINV:
+ return (const float(*)[4])obi->obinvmat;
+ case RE_OBJECT_INSTANCE_MATRIX_LOCALTOVIEW:
+ return (const float(*)[4])obi->localtoviewmat;
+ case RE_OBJECT_INSTANCE_MATRIX_LOCALTOVIEWINV:
+ return (const float(*)[4])obi->localtoviewinvmat;
+ }
+ }
+ return NULL;
+}
+
+float RE_object_instance_get_object_pass_index(struct ObjectInstanceRen *obi)
+{
+ return obi->ob->index;
+}
+
+float RE_object_instance_get_random_id(struct ObjectInstanceRen *obi)
+{
+ return obi->random_id;
+}
+
+const float (*RE_render_current_get_matrix(int matrix_id))[4]
+{
+ switch (matrix_id) {
+ case RE_VIEW_MATRIX:
+ return (const float(*)[4])R.viewmat;
+ case RE_VIEWINV_MATRIX:
+ return (const float(*)[4])R.viewinv;
+ }
+ return NULL;
+}
+
+float RE_fresnel_dielectric(float incoming[3], float normal[3], float eta)
+{
+ /* compute fresnel reflectance without explicitly computing
+ * the refracted direction */
+ float c = fabs(dot_v3v3(incoming, normal));
+ float g = eta * eta - 1.0 + c * c;
+ float result;
+
+ if (g > 0.0) {
+ g = sqrtf(g);
+ float A = (g - c) / (g + c);
+ float B = (c * (g + c) - 1.0) / (c * (g - c) + 1.0);
+ result = 0.5 * A * A * (1.0 + B * B);
+ }
+ else {
+ result = 1.0; /* TIR (no refracted component) */
+ }
+
+ return result;
+}
diff --git a/source/blender/render/intern/source/sss.c b/source/blender/render/intern/source/sss.c
new file mode 100644
index 00000000000..5919b8130d7
--- /dev/null
+++ b/source/blender/render/intern/source/sss.c
@@ -0,0 +1,1074 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2007 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/render/intern/source/sss.c
+ * \ingroup render
+ */
+
+/* Possible Improvements:
+ * - add fresnel terms
+ * - adapt Rd table to scale, now with small scale there are a lot of misses?
+ * - possible interesting method: perform sss on all samples in the tree,
+ * and then use those values interpolated somehow later. can also do this
+ * filtering on demand for speed. since we are doing things in screen
+ * space now there is an exact correspondence
+ * - avoid duplicate shading (filtering points in advance, irradiance cache
+ * like lookup?)
+ * - lower resolution samples
+ */
+
+#include <math.h>
+#include <string.h>
+#include <stdio.h>
+#include <string.h>
+
+/* external modules: */
+#include "MEM_guardedalloc.h"
+
+#include "BLI_math.h"
+#include "BLI_blenlib.h"
+#include "BLI_utildefines.h"
+#include "BLI_ghash.h"
+#include "BLI_memarena.h"
+
+#include "BLT_translation.h"
+
+
+#include "DNA_material_types.h"
+
+#include "BKE_global.h"
+#include "BKE_main.h"
+#include "BKE_scene.h"
+
+
+/* this module */
+#include "render_types.h"
+#include "sss.h"
+
+/* Generic Multiple Scattering API */
+
+/* Relevant papers:
+ * [1] A Practical Model for Subsurface Light Transport
+ * [2] A Rapid Hierarchical Rendering Technique for Translucent Materials
+ * [3] Efficient Rendering of Local Subsurface Scattering
+ * [4] Implementing a skin BSSRDF (or several...)
+ */
+
+/* Defines */
+
+#define RD_TABLE_RANGE 100.0f
+#define RD_TABLE_RANGE_2 10000.0f
+#define RD_TABLE_SIZE 10000
+
+#define MAX_OCTREE_NODE_POINTS 8
+#define MAX_OCTREE_DEPTH 15
+
+/* Struct Definitions */
+
+struct ScatterSettings {
+ float eta; /* index of refraction */
+ float sigma_a; /* absorption coefficient */
+ float sigma_s_; /* reduced scattering coefficient */
+ float sigma_t_; /* reduced extinction coefficient */
+ float sigma; /* effective extinction coefficient */
+ float Fdr; /* diffuse fresnel reflectance */
+ float D; /* diffusion constant */
+ float A;
+ float alpha_; /* reduced albedo */
+ float zr; /* distance of virtual lightsource above surface */
+ float zv; /* distance of virtual lightsource below surface */
+ float ld; /* mean free path */
+ float ro; /* diffuse reflectance */
+ float color;
+ float invsigma_t_;
+ float frontweight;
+ float backweight;
+
+ float *tableRd; /* lookup table to avoid computing Rd */
+ float *tableRd2; /* lookup table to avoid computing Rd for bigger values */
+};
+
+typedef struct ScatterPoint {
+ float co[3];
+ float rad[3];
+ float area;
+ int back;
+} ScatterPoint;
+
+typedef struct ScatterNode {
+ float co[3];
+ float rad[3];
+ float backrad[3];
+ float area, backarea;
+
+ int totpoint;
+ ScatterPoint *points;
+
+ float split[3];
+ struct ScatterNode *child[8];
+} ScatterNode;
+
+struct ScatterTree {
+ MemArena *arena;
+
+ ScatterSettings *ss[3];
+ float error, scale;
+
+ ScatterNode *root;
+ ScatterPoint *points;
+ ScatterPoint **refpoints;
+ ScatterPoint **tmppoints;
+ int totpoint;
+ float min[3], max[3];
+};
+
+typedef struct ScatterResult {
+ float rad[3];
+ float backrad[3];
+ float rdsum[3];
+ float backrdsum[3];
+} ScatterResult;
+
+/* Functions for BSSRDF reparametrization in to more intuitive parameters,
+ * see [2] section 4 for more info. */
+
+static float f_Rd(float alpha_, float A, float ro)
+{
+ float sq;
+
+ sq = sqrtf(3.0f * (1.0f - alpha_));
+ return (alpha_/2.0f)*(1.0f + expf((-4.0f/3.0f)*A*sq))*expf(-sq) - ro;
+}
+
+static float compute_reduced_albedo(ScatterSettings *ss)
+{
+ const float tolerance= 1e-8;
+ const int max_iteration_count= 20;
+ float d, fsub, xn_1= 0.0f, xn= 1.0f, fxn, fxn_1;
+ int i;
+
+ /* use secant method to compute reduced albedo using Rd function inverse
+ * with a given reflectance */
+ fxn= f_Rd(xn, ss->A, ss->ro);
+ fxn_1= f_Rd(xn_1, ss->A, ss->ro);
+
+ for (i= 0; i < max_iteration_count; i++) {
+ fsub= (fxn - fxn_1);
+ if (fabsf(fsub) < tolerance)
+ break;
+ d= ((xn - xn_1)/fsub)*fxn;
+ if (fabsf(d) < tolerance)
+ break;
+
+ xn_1= xn;
+ fxn_1= fxn;
+ xn= xn - d;
+
+ if (xn > 1.0f) xn= 1.0f;
+ if (xn_1 > 1.0f) xn_1= 1.0f;
+
+ fxn= f_Rd(xn, ss->A, ss->ro);
+ }
+
+ /* avoid division by zero later */
+ if (xn <= 0.0f)
+ xn= 0.00001f;
+
+ return xn;
+}
+
+/* Exponential falloff functions */
+
+static float Rd_rsquare(ScatterSettings *ss, float rr)
+{
+ float sr, sv, Rdr, Rdv;
+
+ sr = sqrtf(rr + ss->zr * ss->zr);
+ sv = sqrtf(rr + ss->zv * ss->zv);
+
+ Rdr= ss->zr*(1.0f + ss->sigma*sr)*expf(-ss->sigma*sr)/(sr*sr*sr);
+ Rdv= ss->zv*(1.0f + ss->sigma*sv)*expf(-ss->sigma*sv)/(sv*sv*sv);
+
+ return /*ss->alpha_*/(1.0f/(4.0f*(float)M_PI))*(Rdr + Rdv);
+}
+
+static float Rd(ScatterSettings *ss, float r)
+{
+ return Rd_rsquare(ss, r*r);
+}
+
+/* table lookups for Rd. this avoids expensive exp calls. we use two
+ * separate tables as well for lower and higher numbers to improve
+ * precision, since the number are poorly distributed because we do
+ * a lookup with the squared distance for smaller distances, saving
+ * another sqrt. */
+
+static void approximate_Rd_rgb(ScatterSettings **ss, float rr, float *rd)
+{
+ float indexf, t, idxf;
+ int index;
+
+ if (rr > (RD_TABLE_RANGE_2 * RD_TABLE_RANGE_2)) {
+ /* pass */
+ }
+ else if (rr > RD_TABLE_RANGE) {
+ rr = sqrtf(rr);
+ indexf= rr*(RD_TABLE_SIZE/RD_TABLE_RANGE_2);
+ index= (int)indexf;
+ idxf= (float)index;
+ t= indexf - idxf;
+
+ if (index >= 0 && index < RD_TABLE_SIZE) {
+ rd[0]= (ss[0]->tableRd2[index]*(1-t) + ss[0]->tableRd2[index+1]*t);
+ rd[1]= (ss[1]->tableRd2[index]*(1-t) + ss[1]->tableRd2[index+1]*t);
+ rd[2]= (ss[2]->tableRd2[index]*(1-t) + ss[2]->tableRd2[index+1]*t);
+ return;
+ }
+ }
+ else {
+ indexf= rr*(RD_TABLE_SIZE/RD_TABLE_RANGE);
+ index= (int)indexf;
+ idxf= (float)index;
+ t= indexf - idxf;
+
+ if (index >= 0 && index < RD_TABLE_SIZE) {
+ rd[0]= (ss[0]->tableRd[index]*(1-t) + ss[0]->tableRd[index+1]*t);
+ rd[1]= (ss[1]->tableRd[index]*(1-t) + ss[1]->tableRd[index+1]*t);
+ rd[2]= (ss[2]->tableRd[index]*(1-t) + ss[2]->tableRd[index+1]*t);
+ return;
+ }
+ }
+
+ /* fallback to slow Rd computation */
+ rd[0]= Rd_rsquare(ss[0], rr);
+ rd[1]= Rd_rsquare(ss[1], rr);
+ rd[2]= Rd_rsquare(ss[2], rr);
+}
+
+static void build_Rd_table(ScatterSettings *ss)
+{
+ float r;
+ int i, size = RD_TABLE_SIZE+1;
+
+ ss->tableRd= MEM_mallocN(sizeof(float)*size, "scatterTableRd");
+ ss->tableRd2= MEM_mallocN(sizeof(float)*size, "scatterTableRd");
+
+ for (i= 0; i < size; i++) {
+ r= i*(RD_TABLE_RANGE/RD_TABLE_SIZE);
+#if 0
+ if (r < ss->invsigma_t_*ss->invsigma_t_) {
+ r= ss->invsigma_t_*ss->invsigma_t_;
+ }
+#endif
+ ss->tableRd[i]= Rd(ss, sqrtf(r));
+
+ r= i*(RD_TABLE_RANGE_2/RD_TABLE_SIZE);
+#if 0
+ if (r < ss->invsigma_t_) {
+ r= ss->invsigma_t_;
+ }
+#endif
+ ss->tableRd2[i]= Rd(ss, r);
+ }
+}
+
+ScatterSettings *scatter_settings_new(float refl, float radius, float ior, float reflfac, float frontweight, float backweight)
+{
+ ScatterSettings *ss;
+
+ ss= MEM_callocN(sizeof(ScatterSettings), "ScatterSettings");
+
+ /* see [1] and [3] for these formulas */
+ ss->eta= ior;
+ ss->Fdr= -1.440f/ior*ior + 0.710f/ior + 0.668f + 0.0636f*ior;
+ ss->A= (1.0f + ss->Fdr)/(1.0f - ss->Fdr);
+ ss->ld= radius;
+ ss->ro= min_ff(refl, 0.99f);
+ ss->color= ss->ro*reflfac + (1.0f-reflfac);
+
+ ss->alpha_= compute_reduced_albedo(ss);
+
+ ss->sigma= 1.0f/ss->ld;
+ ss->sigma_t_= ss->sigma/sqrtf(3.0f*(1.0f - ss->alpha_));
+ ss->sigma_s_= ss->alpha_*ss->sigma_t_;
+ ss->sigma_a= ss->sigma_t_ - ss->sigma_s_;
+
+ ss->D= 1.0f/(3.0f*ss->sigma_t_);
+
+ ss->zr= 1.0f/ss->sigma_t_;
+ ss->zv= ss->zr + 4.0f*ss->A*ss->D;
+
+ ss->invsigma_t_= 1.0f/ss->sigma_t_;
+
+ ss->frontweight= frontweight;
+ ss->backweight= backweight;
+
+ /* precompute a table of Rd values for quick lookup */
+ build_Rd_table(ss);
+
+ return ss;
+}
+
+void scatter_settings_free(ScatterSettings *ss)
+{
+ MEM_freeN(ss->tableRd);
+ MEM_freeN(ss->tableRd2);
+ MEM_freeN(ss);
+}
+
+/* Hierarchical method as in [2]. */
+
+/* traversal */
+
+#define SUBNODE_INDEX(co, split) \
+ ((co[0]>=split[0]) + (co[1]>=split[1])*2 + (co[2]>=split[2])*4)
+
+static void add_radiance(ScatterTree *tree, float *frontrad, float *backrad, float area, float backarea, float rr, ScatterResult *result)
+{
+ float rd[3], frontrd[3], backrd[3];
+
+ approximate_Rd_rgb(tree->ss, rr, rd);
+
+ if (frontrad && area) {
+ frontrd[0] = rd[0]*area;
+ frontrd[1] = rd[1]*area;
+ frontrd[2] = rd[2]*area;
+
+ result->rad[0] += frontrad[0]*frontrd[0];
+ result->rad[1] += frontrad[1]*frontrd[1];
+ result->rad[2] += frontrad[2]*frontrd[2];
+
+ result->rdsum[0] += frontrd[0];
+ result->rdsum[1] += frontrd[1];
+ result->rdsum[2] += frontrd[2];
+ }
+ if (backrad && backarea) {
+ backrd[0] = rd[0]*backarea;
+ backrd[1] = rd[1]*backarea;
+ backrd[2] = rd[2]*backarea;
+
+ result->backrad[0] += backrad[0]*backrd[0];
+ result->backrad[1] += backrad[1]*backrd[1];
+ result->backrad[2] += backrad[2]*backrd[2];
+
+ result->backrdsum[0] += backrd[0];
+ result->backrdsum[1] += backrd[1];
+ result->backrdsum[2] += backrd[2];
+ }
+}
+
+static void traverse_octree(ScatterTree *tree, ScatterNode *node, const float co[3], int self, ScatterResult *result)
+{
+ float sub[3], dist;
+ int i, index = 0;
+
+ if (node->totpoint > 0) {
+ /* leaf - add radiance from all samples */
+ for (i=0; i<node->totpoint; i++) {
+ ScatterPoint *p= &node->points[i];
+
+ sub_v3_v3v3(sub, co, p->co);
+ dist= dot_v3v3(sub, sub);
+
+ if (p->back)
+ add_radiance(tree, NULL, p->rad, 0.0f, p->area, dist, result);
+ else
+ add_radiance(tree, p->rad, NULL, p->area, 0.0f, dist, result);
+ }
+ }
+ else {
+ /* branch */
+ if (self)
+ index = SUBNODE_INDEX(co, node->split);
+
+ for (i=0; i<8; i++) {
+ if (node->child[i]) {
+ ScatterNode *subnode= node->child[i];
+
+ if (self && index == i) {
+ /* always traverse node containing the point */
+ traverse_octree(tree, subnode, co, 1, result);
+ }
+ else {
+ /* decide subnode traversal based on maximum solid angle */
+ sub_v3_v3v3(sub, co, subnode->co);
+ dist= dot_v3v3(sub, sub);
+
+ /* actually area/dist > error, but this avoids division */
+ if (subnode->area+subnode->backarea>tree->error*dist) {
+ traverse_octree(tree, subnode, co, 0, result);
+ }
+ else {
+ add_radiance(tree, subnode->rad, subnode->backrad,
+ subnode->area, subnode->backarea, dist, result);
+ }
+ }
+ }
+ }
+ }
+}
+
+static void compute_radiance(ScatterTree *tree, const float co[3], float *rad)
+{
+ ScatterResult result;
+ float rdsum[3], backrad[3], backrdsum[3];
+
+ memset(&result, 0, sizeof(result));
+
+ traverse_octree(tree, tree->root, co, 1, &result);
+
+ /* the original paper doesn't do this, but we normalize over the
+ * sampled area and multiply with the reflectance. this is because
+ * our point samples are incomplete, there are no samples on parts
+ * of the mesh not visible from the camera. this can not only make
+ * it darker, but also lead to ugly color shifts */
+
+ mul_v3_fl(result.rad, tree->ss[0]->frontweight);
+ mul_v3_fl(result.backrad, tree->ss[0]->backweight);
+
+ copy_v3_v3(rad, result.rad);
+ add_v3_v3v3(backrad, result.rad, result.backrad);
+
+ copy_v3_v3(rdsum, result.rdsum);
+ add_v3_v3v3(backrdsum, result.rdsum, result.backrdsum);
+
+ if (rdsum[0] > 1e-16f) rad[0]= tree->ss[0]->color*rad[0]/rdsum[0];
+ if (rdsum[1] > 1e-16f) rad[1]= tree->ss[1]->color*rad[1]/rdsum[1];
+ if (rdsum[2] > 1e-16f) rad[2]= tree->ss[2]->color*rad[2]/rdsum[2];
+
+ if (backrdsum[0] > 1e-16f) backrad[0]= tree->ss[0]->color*backrad[0]/backrdsum[0];
+ if (backrdsum[1] > 1e-16f) backrad[1]= tree->ss[1]->color*backrad[1]/backrdsum[1];
+ if (backrdsum[2] > 1e-16f) backrad[2]= tree->ss[2]->color*backrad[2]/backrdsum[2];
+
+ rad[0]= MAX2(rad[0], backrad[0]);
+ rad[1]= MAX2(rad[1], backrad[1]);
+ rad[2]= MAX2(rad[2], backrad[2]);
+}
+
+/* building */
+
+static void sum_leaf_radiance(ScatterTree *UNUSED(tree), ScatterNode *node)
+{
+ ScatterPoint *p;
+ float rad, totrad= 0.0f, inv;
+ int i;
+
+ node->co[0]= node->co[1]= node->co[2]= 0.0;
+ node->rad[0]= node->rad[1]= node->rad[2]= 0.0;
+ node->backrad[0]= node->backrad[1]= node->backrad[2]= 0.0;
+
+ /* compute total rad, rad weighted average position,
+ * and total area */
+ for (i=0; i<node->totpoint; i++) {
+ p= &node->points[i];
+
+ rad= p->area*fabsf(p->rad[0] + p->rad[1] + p->rad[2]);
+ totrad += rad;
+
+ node->co[0] += rad*p->co[0];
+ node->co[1] += rad*p->co[1];
+ node->co[2] += rad*p->co[2];
+
+ if (p->back) {
+ node->backrad[0] += p->rad[0]*p->area;
+ node->backrad[1] += p->rad[1]*p->area;
+ node->backrad[2] += p->rad[2]*p->area;
+
+ node->backarea += p->area;
+ }
+ else {
+ node->rad[0] += p->rad[0]*p->area;
+ node->rad[1] += p->rad[1]*p->area;
+ node->rad[2] += p->rad[2]*p->area;
+
+ node->area += p->area;
+ }
+ }
+
+ if (node->area > 1e-16f) {
+ inv= 1.0f/node->area;
+ node->rad[0] *= inv;
+ node->rad[1] *= inv;
+ node->rad[2] *= inv;
+ }
+ if (node->backarea > 1e-16f) {
+ inv= 1.0f/node->backarea;
+ node->backrad[0] *= inv;
+ node->backrad[1] *= inv;
+ node->backrad[2] *= inv;
+ }
+
+ if (totrad > 1e-16f) {
+ inv= 1.0f/totrad;
+ node->co[0] *= inv;
+ node->co[1] *= inv;
+ node->co[2] *= inv;
+ }
+ else {
+ /* make sure that if radiance is 0.0f, we still have these points in
+ * the tree at a good position, they count for rdsum too */
+ for (i=0; i<node->totpoint; i++) {
+ p= &node->points[i];
+
+ node->co[0] += p->co[0];
+ node->co[1] += p->co[1];
+ node->co[2] += p->co[2];
+ }
+
+ node->co[0] /= node->totpoint;
+ node->co[1] /= node->totpoint;
+ node->co[2] /= node->totpoint;
+ }
+}
+
+static void sum_branch_radiance(ScatterTree *UNUSED(tree), ScatterNode *node)
+{
+ ScatterNode *subnode;
+ float rad, totrad= 0.0f, inv;
+ int i, totnode;
+
+ node->co[0]= node->co[1]= node->co[2]= 0.0;
+ node->rad[0]= node->rad[1]= node->rad[2]= 0.0;
+ node->backrad[0]= node->backrad[1]= node->backrad[2]= 0.0;
+
+ /* compute total rad, rad weighted average position,
+ * and total area */
+ for (i=0; i<8; i++) {
+ if (node->child[i] == NULL)
+ continue;
+
+ subnode= node->child[i];
+
+ rad= subnode->area*fabsf(subnode->rad[0] + subnode->rad[1] + subnode->rad[2]);
+ rad += subnode->backarea*fabsf(subnode->backrad[0] + subnode->backrad[1] + subnode->backrad[2]);
+ totrad += rad;
+
+ node->co[0] += rad*subnode->co[0];
+ node->co[1] += rad*subnode->co[1];
+ node->co[2] += rad*subnode->co[2];
+
+ node->rad[0] += subnode->rad[0]*subnode->area;
+ node->rad[1] += subnode->rad[1]*subnode->area;
+ node->rad[2] += subnode->rad[2]*subnode->area;
+
+ node->backrad[0] += subnode->backrad[0]*subnode->backarea;
+ node->backrad[1] += subnode->backrad[1]*subnode->backarea;
+ node->backrad[2] += subnode->backrad[2]*subnode->backarea;
+
+ node->area += subnode->area;
+ node->backarea += subnode->backarea;
+ }
+
+ if (node->area > 1e-16f) {
+ inv= 1.0f/node->area;
+ node->rad[0] *= inv;
+ node->rad[1] *= inv;
+ node->rad[2] *= inv;
+ }
+ if (node->backarea > 1e-16f) {
+ inv= 1.0f/node->backarea;
+ node->backrad[0] *= inv;
+ node->backrad[1] *= inv;
+ node->backrad[2] *= inv;
+ }
+
+ if (totrad > 1e-16f) {
+ inv= 1.0f/totrad;
+ node->co[0] *= inv;
+ node->co[1] *= inv;
+ node->co[2] *= inv;
+ }
+ else {
+ /* make sure that if radiance is 0.0f, we still have these points in
+ * the tree at a good position, they count for rdsum too */
+ totnode= 0;
+
+ for (i=0; i<8; i++) {
+ if (node->child[i]) {
+ subnode= node->child[i];
+
+ node->co[0] += subnode->co[0];
+ node->co[1] += subnode->co[1];
+ node->co[2] += subnode->co[2];
+
+ totnode++;
+ }
+ }
+
+ node->co[0] /= totnode;
+ node->co[1] /= totnode;
+ node->co[2] /= totnode;
+ }
+}
+
+static void sum_radiance(ScatterTree *tree, ScatterNode *node)
+{
+ if (node->totpoint > 0) {
+ sum_leaf_radiance(tree, node);
+ }
+ else {
+ int i;
+
+ for (i=0; i<8; i++)
+ if (node->child[i])
+ sum_radiance(tree, node->child[i]);
+
+ sum_branch_radiance(tree, node);
+ }
+}
+
+static void subnode_middle(int i, float *mid, float *subsize, float *submid)
+{
+ int x= i & 1, y= i & 2, z= i & 4;
+
+ submid[0]= mid[0] + ((x)? subsize[0]: -subsize[0]);
+ submid[1]= mid[1] + ((y)? subsize[1]: -subsize[1]);
+ submid[2]= mid[2] + ((z)? subsize[2]: -subsize[2]);
+}
+
+static void create_octree_node(ScatterTree *tree, ScatterNode *node, float *mid, float *size, ScatterPoint **refpoints, int depth)
+{
+ ScatterNode *subnode;
+ ScatterPoint **subrefpoints, **tmppoints= tree->tmppoints;
+ int index, nsize[8], noffset[8], i, subco, used_nodes, usedi;
+ float submid[3], subsize[3];
+
+ /* stopping condition */
+ if (node->totpoint <= MAX_OCTREE_NODE_POINTS || depth == MAX_OCTREE_DEPTH) {
+ for (i=0; i<node->totpoint; i++)
+ node->points[i]= *(refpoints[i]);
+
+ return;
+ }
+
+ subsize[0]= size[0]*0.5f;
+ subsize[1]= size[1]*0.5f;
+ subsize[2]= size[2]*0.5f;
+
+ node->split[0]= mid[0];
+ node->split[1]= mid[1];
+ node->split[2]= mid[2];
+
+ memset(nsize, 0, sizeof(nsize));
+ memset(noffset, 0, sizeof(noffset));
+
+ /* count points in subnodes */
+ for (i=0; i<node->totpoint; i++) {
+ index= SUBNODE_INDEX(refpoints[i]->co, node->split);
+ tmppoints[i]= refpoints[i];
+ nsize[index]++;
+ }
+
+ /* here we check if only one subnode is used. if this is the case, we don't
+ * create a new node, but rather call this function again, with different
+ * size and middle position for the same node. */
+ for (usedi=0, used_nodes=0, i=0; i<8; i++) {
+ if (nsize[i]) {
+ used_nodes++;
+ usedi = i;
+ }
+ if (i != 0)
+ noffset[i]= noffset[i-1]+nsize[i-1];
+ }
+
+ if (used_nodes <= 1) {
+ subnode_middle(usedi, mid, subsize, submid);
+ create_octree_node(tree, node, submid, subsize, refpoints, depth+1);
+ return;
+ }
+
+ /* reorder refpoints by subnode */
+ for (i=0; i<node->totpoint; i++) {
+ index= SUBNODE_INDEX(tmppoints[i]->co, node->split);
+ refpoints[noffset[index]]= tmppoints[i];
+ noffset[index]++;
+ }
+
+ /* create subnodes */
+ for (subco=0, i=0; i<8; subco+=nsize[i], i++) {
+ if (nsize[i] > 0) {
+ subnode= BLI_memarena_alloc(tree->arena, sizeof(ScatterNode));
+ node->child[i]= subnode;
+ subnode->points= node->points + subco;
+ subnode->totpoint= nsize[i];
+ subrefpoints= refpoints + subco;
+
+ subnode_middle(i, mid, subsize, submid);
+
+ create_octree_node(tree, subnode, submid, subsize, subrefpoints,
+ depth+1);
+ }
+ else
+ node->child[i]= NULL;
+ }
+
+ node->points= NULL;
+ node->totpoint= 0;
+}
+
+/* public functions */
+
+ScatterTree *scatter_tree_new(ScatterSettings *ss[3], float scale, float error,
+ float (*co)[3], float (*color)[3], float *area, int totpoint)
+{
+ ScatterTree *tree;
+ ScatterPoint *points, **refpoints;
+ int i;
+
+ /* allocate tree */
+ tree= MEM_callocN(sizeof(ScatterTree), "ScatterTree");
+ tree->scale= scale;
+ tree->error= error;
+ tree->totpoint= totpoint;
+
+ tree->ss[0]= ss[0];
+ tree->ss[1]= ss[1];
+ tree->ss[2]= ss[2];
+
+ points = MEM_callocN(sizeof(ScatterPoint) * totpoint, "ScatterPoints");
+ refpoints = MEM_callocN(sizeof(ScatterPoint *) * totpoint, "ScatterRefPoints");
+
+ tree->points= points;
+ tree->refpoints= refpoints;
+
+ /* build points */
+ INIT_MINMAX(tree->min, tree->max);
+
+ for (i=0; i<totpoint; i++) {
+ copy_v3_v3(points[i].co, co[i]);
+ copy_v3_v3(points[i].rad, color[i]);
+ points[i].area= fabsf(area[i])/(tree->scale*tree->scale);
+ points[i].back= (area[i] < 0.0f);
+
+ mul_v3_fl(points[i].co, 1.0f / tree->scale);
+ minmax_v3v3_v3(tree->min, tree->max, points[i].co);
+
+ refpoints[i]= points + i;
+ }
+
+ return tree;
+}
+
+void scatter_tree_build(ScatterTree *tree)
+{
+ ScatterPoint *newpoints, **tmppoints;
+ float mid[3], size[3];
+ int totpoint= tree->totpoint;
+
+ newpoints = MEM_callocN(sizeof(ScatterPoint) * totpoint, "ScatterPoints");
+ tmppoints = MEM_callocN(sizeof(ScatterPoint *) * totpoint, "ScatterTmpPoints");
+ tree->tmppoints= tmppoints;
+
+ tree->arena= BLI_memarena_new(0x8000 * sizeof(ScatterNode), "sss tree arena");
+ BLI_memarena_use_calloc(tree->arena);
+
+ /* build tree */
+ tree->root= BLI_memarena_alloc(tree->arena, sizeof(ScatterNode));
+ tree->root->points= newpoints;
+ tree->root->totpoint= totpoint;
+
+ mid[0]= (tree->min[0]+tree->max[0])*0.5f;
+ mid[1]= (tree->min[1]+tree->max[1])*0.5f;
+ mid[2]= (tree->min[2]+tree->max[2])*0.5f;
+
+ size[0]= (tree->max[0]-tree->min[0])*0.5f;
+ size[1]= (tree->max[1]-tree->min[1])*0.5f;
+ size[2]= (tree->max[2]-tree->min[2])*0.5f;
+
+ create_octree_node(tree, tree->root, mid, size, tree->refpoints, 0);
+
+ MEM_freeN(tree->points);
+ MEM_freeN(tree->refpoints);
+ MEM_freeN(tree->tmppoints);
+ tree->refpoints= NULL;
+ tree->tmppoints= NULL;
+ tree->points= newpoints;
+
+ /* sum radiance at nodes */
+ sum_radiance(tree, tree->root);
+}
+
+void scatter_tree_sample(ScatterTree *tree, const float co[3], float color[3])
+{
+ float sco[3];
+
+ copy_v3_v3(sco, co);
+ mul_v3_fl(sco, 1.0f / tree->scale);
+
+ compute_radiance(tree, sco, color);
+}
+
+void scatter_tree_free(ScatterTree *tree)
+{
+ if (tree->arena) BLI_memarena_free(tree->arena);
+ if (tree->points) MEM_freeN(tree->points);
+ if (tree->refpoints) MEM_freeN(tree->refpoints);
+
+ MEM_freeN(tree);
+}
+
+/* Internal Renderer API */
+
+/* sss tree building */
+
+typedef struct SSSData {
+ ScatterTree *tree;
+ ScatterSettings *ss[3];
+} SSSData;
+
+typedef struct SSSPoints {
+ struct SSSPoints *next, *prev;
+
+ float (*co)[3];
+ float (*color)[3];
+ float *area;
+ int totpoint;
+} SSSPoints;
+
+static void sss_create_tree_mat(Render *re, Material *mat)
+{
+ SSSPoints *p;
+ RenderResult *rr;
+ ListBase points;
+ float (*co)[3] = NULL, (*color)[3] = NULL, *area = NULL;
+ int totpoint = 0, osa, osaflag, frsflag, partsdone;
+
+ if (re->test_break(re->tbh))
+ return;
+
+ points.first= points.last= NULL;
+
+ /* TODO: this is getting a bit ugly, copying all those variables and
+ * setting them back, maybe we need to create our own Render? */
+
+ /* do SSS preprocessing render */
+ BLI_rw_mutex_lock(&re->resultmutex, THREAD_LOCK_WRITE);
+ rr= re->result;
+ osa= re->osa;
+ osaflag= re->r.mode & R_OSA;
+ frsflag= re->r.mode & R_EDGE_FRS;
+ partsdone= re->i.partsdone;
+
+ re->osa= 0;
+ re->r.mode &= ~(R_OSA | R_EDGE_FRS);
+ re->sss_points= &points;
+ re->sss_mat= mat;
+ re->i.partsdone = 0;
+
+ if (!(re->r.scemode & (R_BUTS_PREVIEW|R_VIEWPORT_PREVIEW)))
+ re->result= NULL;
+ BLI_rw_mutex_unlock(&re->resultmutex);
+
+ RE_TileProcessor(re);
+
+ BLI_rw_mutex_lock(&re->resultmutex, THREAD_LOCK_WRITE);
+ if (!(re->r.scemode & (R_BUTS_PREVIEW|R_VIEWPORT_PREVIEW))) {
+ RE_FreeRenderResult(re->result);
+ re->result= rr;
+ }
+ BLI_rw_mutex_unlock(&re->resultmutex);
+
+ re->i.partsdone= partsdone;
+ re->sss_mat= NULL;
+ re->sss_points= NULL;
+ re->osa= osa;
+ if (osaflag) re->r.mode |= R_OSA;
+ if (frsflag) re->r.mode |= R_EDGE_FRS;
+
+ /* no points? no tree */
+ if (!points.first)
+ return;
+
+ /* merge points together into a single buffer */
+ if (!re->test_break(re->tbh)) {
+ for (totpoint=0, p=points.first; p; p=p->next)
+ totpoint += p->totpoint;
+
+ co= MEM_mallocN(sizeof(*co)*totpoint, "SSSCo");
+ color= MEM_mallocN(sizeof(*color)*totpoint, "SSSColor");
+ area= MEM_mallocN(sizeof(*area)*totpoint, "SSSArea");
+
+ for (totpoint=0, p=points.first; p; p=p->next) {
+ memcpy(co+totpoint, p->co, sizeof(*co)*p->totpoint);
+ memcpy(color+totpoint, p->color, sizeof(*color)*p->totpoint);
+ memcpy(area+totpoint, p->area, sizeof(*area)*p->totpoint);
+ totpoint += p->totpoint;
+ }
+ }
+
+ /* free points */
+ for (p=points.first; p; p=p->next) {
+ MEM_freeN(p->co);
+ MEM_freeN(p->color);
+ MEM_freeN(p->area);
+ }
+ BLI_freelistN(&points);
+
+ /* build tree */
+ if (!re->test_break(re->tbh)) {
+ SSSData *sss= MEM_callocN(sizeof(*sss), "SSSData");
+ float ior= mat->sss_ior, cfac= mat->sss_colfac;
+ const float *radius = mat->sss_radius;
+ float fw= mat->sss_front, bw= mat->sss_back;
+ float error = mat->sss_error;
+
+ error= get_render_aosss_error(&re->r, error);
+ if ((re->r.scemode & (R_BUTS_PREVIEW|R_VIEWPORT_PREVIEW)) && error < 0.5f)
+ error= 0.5f;
+
+ sss->ss[0]= scatter_settings_new(mat->sss_col[0], radius[0], ior, cfac, fw, bw);
+ sss->ss[1]= scatter_settings_new(mat->sss_col[1], radius[1], ior, cfac, fw, bw);
+ sss->ss[2]= scatter_settings_new(mat->sss_col[2], radius[2], ior, cfac, fw, bw);
+ sss->tree= scatter_tree_new(sss->ss, mat->sss_scale, error,
+ co, color, area, totpoint);
+
+ MEM_freeN(co);
+ MEM_freeN(color);
+ MEM_freeN(area);
+
+ scatter_tree_build(sss->tree);
+
+ BLI_ghash_insert(re->sss_hash, mat, sss);
+ }
+ else {
+ if (co) MEM_freeN(co);
+ if (color) MEM_freeN(color);
+ if (area) MEM_freeN(area);
+ }
+}
+
+void sss_add_points(Render *re, float (*co)[3], float (*color)[3], float *area, int totpoint)
+{
+ SSSPoints *p;
+
+ if (totpoint > 0) {
+ p= MEM_callocN(sizeof(SSSPoints), "SSSPoints");
+
+ p->co= co;
+ p->color= color;
+ p->area= area;
+ p->totpoint= totpoint;
+
+ BLI_thread_lock(LOCK_CUSTOM1);
+ BLI_addtail(re->sss_points, p);
+ BLI_thread_unlock(LOCK_CUSTOM1);
+ }
+}
+
+static void sss_free_tree(SSSData *sss)
+{
+ scatter_tree_free(sss->tree);
+ scatter_settings_free(sss->ss[0]);
+ scatter_settings_free(sss->ss[1]);
+ scatter_settings_free(sss->ss[2]);
+ MEM_freeN(sss);
+}
+
+/* public functions */
+
+void make_sss_tree(Render *re)
+{
+ Material *mat;
+ bool infostr_set = false;
+ const char *prevstr = NULL;
+
+ free_sss(re);
+
+ re->sss_hash= BLI_ghash_ptr_new("make_sss_tree gh");
+
+ re->stats_draw(re->sdh, &re->i);
+
+ for (mat= re->main->mat.first; mat; mat= mat->id.next) {
+ if (mat->id.us && (mat->flag & MA_IS_USED) && (mat->sss_flag & MA_DIFF_SSS)) {
+ if (!infostr_set) {
+ prevstr = re->i.infostr;
+ re->i.infostr = IFACE_("SSS preprocessing");
+ infostr_set = true;
+ }
+
+ sss_create_tree_mat(re, mat);
+ }
+ }
+
+ /* XXX preview exception */
+ /* localizing preview render data is not fun for node trees :( */
+ if (re->main!=G.main) {
+ for (mat= G.main->mat.first; mat; mat= mat->id.next) {
+ if (mat->id.us && (mat->flag & MA_IS_USED) && (mat->sss_flag & MA_DIFF_SSS)) {
+ if (!infostr_set) {
+ prevstr = re->i.infostr;
+ re->i.infostr = IFACE_("SSS preprocessing");
+ infostr_set = true;
+ }
+
+ sss_create_tree_mat(re, mat);
+ }
+ }
+ }
+
+ if (infostr_set)
+ re->i.infostr = prevstr;
+}
+
+void free_sss(Render *re)
+{
+ if (re->sss_hash) {
+ GHashIterator gh_iter;
+
+ GHASH_ITER (gh_iter, re->sss_hash) {
+ sss_free_tree(BLI_ghashIterator_getValue(&gh_iter));
+ }
+
+ BLI_ghash_free(re->sss_hash, NULL, NULL);
+ re->sss_hash= NULL;
+ }
+}
+
+int sample_sss(Render *re, Material *mat, const float co[3], float color[3])
+{
+ if (re->sss_hash) {
+ SSSData *sss= BLI_ghash_lookup(re->sss_hash, mat);
+
+ if (sss) {
+ scatter_tree_sample(sss->tree, co, color);
+ return 1;
+ }
+ else {
+ color[0]= 0.0f;
+ color[1]= 0.0f;
+ color[2]= 0.0f;
+ }
+ }
+
+ return 0;
+}
+
+int sss_pass_done(struct Render *re, struct Material *mat)
+{
+ return ((re->flag & R_BAKING) || !(re->r.mode & R_SSS) || (re->sss_hash && BLI_ghash_lookup(re->sss_hash, mat)));
+}
+
diff --git a/source/blender/render/intern/source/strand.c b/source/blender/render/intern/source/strand.c
new file mode 100644
index 00000000000..5fde688481a
--- /dev/null
+++ b/source/blender/render/intern/source/strand.c
@@ -0,0 +1,1069 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contributors: Brecht Van Lommel.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/render/intern/source/strand.c
+ * \ingroup render
+ */
+
+
+#include <math.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_key_types.h"
+#include "DNA_material_types.h"
+#include "DNA_meshdata_types.h"
+
+#include "BLI_math.h"
+#include "BLI_blenlib.h"
+#include "BLI_utildefines.h"
+#include "BLI_ghash.h"
+#include "BLI_memarena.h"
+#include "BLI_rand.h"
+
+#include "BKE_DerivedMesh.h"
+#include "BKE_key.h"
+
+
+#include "render_types.h"
+#include "rendercore.h"
+#include "renderdatabase.h"
+#include "shading.h"
+#include "strand.h"
+#include "zbuf.h"
+
+/* *************** */
+
+static float strand_eval_width(Material *ma, float strandco)
+{
+ float fac;
+
+ strandco= 0.5f*(strandco + 1.0f);
+
+ if (ma->strand_ease!=0.0f) {
+ if (ma->strand_ease<0.0f)
+ fac= pow(strandco, 1.0f+ma->strand_ease);
+ else
+ fac= pow(strandco, 1.0f/(1.0f-ma->strand_ease));
+ }
+ else fac= strandco;
+
+ return ((1.0f-fac)*ma->strand_sta + (fac)*ma->strand_end);
+}
+
+void strand_eval_point(StrandSegment *sseg, StrandPoint *spoint)
+{
+ Material *ma;
+ StrandBuffer *strandbuf;
+ const float *simplify;
+ float p[4][3], data[4], cross[3], w, dx, dy, t;
+ int type;
+
+ strandbuf= sseg->buffer;
+ ma= sseg->buffer->ma;
+ t= spoint->t;
+ type= (strandbuf->flag & R_STRAND_BSPLINE)? KEY_BSPLINE: KEY_CARDINAL;
+
+ copy_v3_v3(p[0], sseg->v[0]->co);
+ copy_v3_v3(p[1], sseg->v[1]->co);
+ copy_v3_v3(p[2], sseg->v[2]->co);
+ copy_v3_v3(p[3], sseg->v[3]->co);
+
+ if (sseg->obi->flag & R_TRANSFORMED) {
+ mul_m4_v3(sseg->obi->mat, p[0]);
+ mul_m4_v3(sseg->obi->mat, p[1]);
+ mul_m4_v3(sseg->obi->mat, p[2]);
+ mul_m4_v3(sseg->obi->mat, p[3]);
+ }
+
+ if (t == 0.0f) {
+ copy_v3_v3(spoint->co, p[1]);
+ spoint->strandco= sseg->v[1]->strandco;
+
+ spoint->dtstrandco= (sseg->v[2]->strandco - sseg->v[0]->strandco);
+ if (sseg->v[0] != sseg->v[1])
+ spoint->dtstrandco *= 0.5f;
+ }
+ else if (t == 1.0f) {
+ copy_v3_v3(spoint->co, p[2]);
+ spoint->strandco= sseg->v[2]->strandco;
+
+ spoint->dtstrandco= (sseg->v[3]->strandco - sseg->v[1]->strandco);
+ if (sseg->v[3] != sseg->v[2])
+ spoint->dtstrandco *= 0.5f;
+ }
+ else {
+ key_curve_position_weights(t, data, type);
+ spoint->co[0]= data[0]*p[0][0] + data[1]*p[1][0] + data[2]*p[2][0] + data[3]*p[3][0];
+ spoint->co[1]= data[0]*p[0][1] + data[1]*p[1][1] + data[2]*p[2][1] + data[3]*p[3][1];
+ spoint->co[2]= data[0]*p[0][2] + data[1]*p[1][2] + data[2]*p[2][2] + data[3]*p[3][2];
+ spoint->strandco= (1.0f-t)*sseg->v[1]->strandco + t*sseg->v[2]->strandco;
+ }
+
+ key_curve_tangent_weights(t, data, type);
+ spoint->dtco[0]= data[0]*p[0][0] + data[1]*p[1][0] + data[2]*p[2][0] + data[3]*p[3][0];
+ spoint->dtco[1]= data[0]*p[0][1] + data[1]*p[1][1] + data[2]*p[2][1] + data[3]*p[3][1];
+ spoint->dtco[2]= data[0]*p[0][2] + data[1]*p[1][2] + data[2]*p[2][2] + data[3]*p[3][2];
+
+ normalize_v3_v3(spoint->tan, spoint->dtco);
+ normalize_v3_v3(spoint->nor, spoint->co);
+ negate_v3(spoint->nor);
+
+ spoint->width= strand_eval_width(ma, spoint->strandco);
+
+ /* simplification */
+ simplify= RE_strandren_get_simplify(strandbuf->obr, sseg->strand, 0);
+ spoint->alpha= (simplify)? simplify[1]: 1.0f;
+
+ /* outer points */
+ cross_v3_v3v3(cross, spoint->co, spoint->tan);
+
+ w= spoint->co[2]*strandbuf->winmat[2][3] + strandbuf->winmat[3][3];
+ dx= strandbuf->winx*cross[0]*strandbuf->winmat[0][0]/w;
+ dy= strandbuf->winy*cross[1]*strandbuf->winmat[1][1]/w;
+ w = sqrtf(dx * dx + dy * dy);
+
+ if (w > 0.0f) {
+ if (strandbuf->flag & R_STRAND_B_UNITS) {
+ const float crosslen= len_v3(cross);
+ w= 2.0f*crosslen*strandbuf->minwidth/w;
+
+ if (spoint->width < w) {
+ spoint->alpha= spoint->width/w;
+ spoint->width= w;
+ }
+
+ if (simplify)
+ /* squared because we only change width, not length */
+ spoint->width *= simplify[0]*simplify[0];
+
+ mul_v3_fl(cross, spoint->width*0.5f/crosslen);
+ }
+ else
+ mul_v3_fl(cross, spoint->width/w);
+ }
+
+ sub_v3_v3v3(spoint->co1, spoint->co, cross);
+ add_v3_v3v3(spoint->co2, spoint->co, cross);
+
+ copy_v3_v3(spoint->dsco, cross);
+}
+
+/* *************** */
+
+static void interpolate_vec1(float *v1, float *v2, float t, float negt, float *v)
+{
+ v[0]= negt*v1[0] + t*v2[0];
+}
+
+static void interpolate_vec3(float *v1, float *v2, float t, float negt, float *v)
+{
+ v[0]= negt*v1[0] + t*v2[0];
+ v[1]= negt*v1[1] + t*v2[1];
+ v[2]= negt*v1[2] + t*v2[2];
+}
+
+static void interpolate_vec4(float *v1, float *v2, float t, float negt, float *v)
+{
+ v[0]= negt*v1[0] + t*v2[0];
+ v[1]= negt*v1[1] + t*v2[1];
+ v[2]= negt*v1[2] + t*v2[2];
+ v[3]= negt*v1[3] + t*v2[3];
+}
+
+static void interpolate_shade_result(ShadeResult *shr1, ShadeResult *shr2, float t, ShadeResult *shr, int addpassflag)
+{
+ float negt= 1.0f - t;
+
+ interpolate_vec4(shr1->combined, shr2->combined, t, negt, shr->combined);
+
+ if (addpassflag & SCE_PASS_VECTOR) {
+ interpolate_vec4(shr1->winspeed, shr2->winspeed, t, negt, shr->winspeed);
+ }
+ /* optim... */
+ if (addpassflag & ~(SCE_PASS_VECTOR)) {
+ if (addpassflag & SCE_PASS_Z)
+ interpolate_vec1(&shr1->z, &shr2->z, t, negt, &shr->z);
+ if (addpassflag & SCE_PASS_RGBA)
+ interpolate_vec4(shr1->col, shr2->col, t, negt, shr->col);
+ if (addpassflag & SCE_PASS_NORMAL) {
+ interpolate_vec3(shr1->nor, shr2->nor, t, negt, shr->nor);
+ normalize_v3(shr->nor);
+ }
+ if (addpassflag & SCE_PASS_EMIT)
+ interpolate_vec3(shr1->emit, shr2->emit, t, negt, shr->emit);
+ if (addpassflag & SCE_PASS_DIFFUSE) {
+ interpolate_vec3(shr1->diff, shr2->diff, t, negt, shr->diff);
+ interpolate_vec3(shr1->diffshad, shr2->diffshad, t, negt, shr->diffshad);
+ }
+ if (addpassflag & SCE_PASS_SPEC)
+ interpolate_vec3(shr1->spec, shr2->spec, t, negt, shr->spec);
+ if (addpassflag & SCE_PASS_SHADOW)
+ interpolate_vec3(shr1->shad, shr2->shad, t, negt, shr->shad);
+ if (addpassflag & SCE_PASS_AO)
+ interpolate_vec3(shr1->ao, shr2->ao, t, negt, shr->ao);
+ if (addpassflag & SCE_PASS_ENVIRONMENT)
+ interpolate_vec3(shr1->env, shr2->env, t, negt, shr->env);
+ if (addpassflag & SCE_PASS_INDIRECT)
+ interpolate_vec3(shr1->indirect, shr2->indirect, t, negt, shr->indirect);
+ if (addpassflag & SCE_PASS_REFLECT)
+ interpolate_vec3(shr1->refl, shr2->refl, t, negt, shr->refl);
+ if (addpassflag & SCE_PASS_REFRACT)
+ interpolate_vec3(shr1->refr, shr2->refr, t, negt, shr->refr);
+ if (addpassflag & SCE_PASS_MIST)
+ interpolate_vec1(&shr1->mist, &shr2->mist, t, negt, &shr->mist);
+ }
+}
+
+static void strand_apply_shaderesult_alpha(ShadeResult *shr, float alpha)
+{
+ if (alpha < 1.0f) {
+ shr->combined[0] *= alpha;
+ shr->combined[1] *= alpha;
+ shr->combined[2] *= alpha;
+ shr->combined[3] *= alpha;
+
+ shr->col[0] *= alpha;
+ shr->col[1] *= alpha;
+ shr->col[2] *= alpha;
+ shr->col[3] *= alpha;
+
+ shr->alpha *= alpha;
+ }
+}
+
+static void strand_shade_point(Render *re, ShadeSample *ssamp, StrandSegment *sseg, StrandVert *svert, StrandPoint *spoint)
+{
+ ShadeInput *shi= ssamp->shi;
+ ShadeResult *shr= ssamp->shr;
+ VlakRen vlr;
+ int seed;
+
+ memset(&vlr, 0, sizeof(vlr));
+ vlr.flag= R_SMOOTH;
+ if (sseg->buffer->ma->mode & MA_TANGENT_STR)
+ vlr.flag |= R_TANGENT;
+
+ shi->vlr= &vlr;
+ shi->v1= NULL;
+ shi->v2= NULL;
+ shi->v3= NULL;
+ shi->strand= sseg->strand;
+ shi->obi= sseg->obi;
+ shi->obr= sseg->obi->obr;
+
+ /* cache for shadow */
+ shi->samplenr= re->shadowsamplenr[shi->thread]++;
+
+ /* all samples */
+ shi->mask= 0xFFFF;
+
+ /* seed RNG for consistent results across tiles */
+ seed = shi->strand->index + (svert - shi->strand->vert);
+ BLI_thread_srandom(shi->thread, seed);
+
+ shade_input_set_strand(shi, sseg->strand, spoint);
+ shade_input_set_strand_texco(shi, sseg->strand, sseg->v[1], spoint);
+
+ /* init material vars */
+ shade_input_init_material(shi);
+
+ /* shade */
+ shade_samples_do_AO(ssamp);
+ shade_input_do_shade(shi, shr);
+
+ /* apply simplification */
+ strand_apply_shaderesult_alpha(shr, spoint->alpha);
+
+ /* include lamphalos for strand, since halo layer was added already */
+ if (re->flag & R_LAMPHALO)
+ if (shi->layflag & SCE_LAY_HALO)
+ renderspothalo(shi, shr->combined, shr->combined[3]);
+
+ shi->strand= NULL;
+}
+
+/* *************** */
+
+struct StrandShadeCache {
+ GHash *resulthash;
+ GHash *refcounthash;
+ MemArena *memarena;
+};
+
+typedef struct StrandCacheEntry {
+ GHashPair pair;
+ ShadeResult shr;
+} StrandCacheEntry;
+
+StrandShadeCache *strand_shade_cache_create(void)
+{
+ StrandShadeCache *cache;
+
+ cache= MEM_callocN(sizeof(StrandShadeCache), "StrandShadeCache");
+ cache->resulthash= BLI_ghash_pair_new("strand_shade_cache_create1 gh");
+ cache->refcounthash= BLI_ghash_pair_new("strand_shade_cache_create2 gh");
+ cache->memarena= BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, "strand shade cache arena");
+
+ return cache;
+}
+
+void strand_shade_cache_free(StrandShadeCache *cache)
+{
+ BLI_ghash_free(cache->refcounthash, NULL, NULL);
+ BLI_ghash_free(cache->resulthash, MEM_freeN, NULL);
+ BLI_memarena_free(cache->memarena);
+ MEM_freeN(cache);
+}
+
+static GHashPair strand_shade_hash_pair(ObjectInstanceRen *obi, StrandVert *svert)
+{
+ GHashPair pair = {obi, svert};
+ return pair;
+}
+
+static void strand_shade_get(Render *re, StrandShadeCache *cache, ShadeSample *ssamp, StrandSegment *sseg, StrandVert *svert)
+{
+ StrandCacheEntry *entry;
+ StrandPoint p;
+ int *refcount;
+ GHashPair pair = strand_shade_hash_pair(sseg->obi, svert);
+
+ entry= BLI_ghash_lookup(cache->resulthash, &pair);
+ refcount= BLI_ghash_lookup(cache->refcounthash, &pair);
+
+ if (!entry) {
+ /* not shaded yet, shade and insert into hash */
+ p.t= (sseg->v[1] == svert)? 0.0f: 1.0f;
+ strand_eval_point(sseg, &p);
+ strand_shade_point(re, ssamp, sseg, svert, &p);
+
+ entry= MEM_callocN(sizeof(StrandCacheEntry), "StrandCacheEntry");
+ entry->pair = pair;
+ entry->shr = ssamp->shr[0];
+ BLI_ghash_insert(cache->resulthash, entry, entry);
+ }
+ else
+ /* already shaded, just copy previous result from hash */
+ ssamp->shr[0]= entry->shr;
+
+ /* lower reference count and remove if not needed anymore by any samples */
+ (*refcount)--;
+ if (*refcount == 0) {
+ BLI_ghash_remove(cache->resulthash, &pair, MEM_freeN, NULL);
+ BLI_ghash_remove(cache->refcounthash, &pair, NULL, NULL);
+ }
+}
+
+void strand_shade_segment(Render *re, StrandShadeCache *cache, StrandSegment *sseg, ShadeSample *ssamp, float t, float s, int addpassflag)
+{
+ ShadeResult shr1, shr2;
+
+ /* get shading for two endpoints and interpolate */
+ strand_shade_get(re, cache, ssamp, sseg, sseg->v[1]);
+ shr1= ssamp->shr[0];
+ strand_shade_get(re, cache, ssamp, sseg, sseg->v[2]);
+ shr2= ssamp->shr[0];
+
+ interpolate_shade_result(&shr1, &shr2, t, ssamp->shr, addpassflag);
+
+ /* apply alpha along width */
+ if (sseg->buffer->widthfade != -1.0f) {
+ s = 1.0f - powf(fabsf(s), sseg->buffer->widthfade);
+
+ strand_apply_shaderesult_alpha(ssamp->shr, s);
+ }
+}
+
+void strand_shade_unref(StrandShadeCache *cache, ObjectInstanceRen *obi, StrandVert *svert)
+{
+ GHashPair pair = strand_shade_hash_pair(obi, svert);
+ int *refcount;
+
+ /* lower reference count and remove if not needed anymore by any samples */
+ refcount= BLI_ghash_lookup(cache->refcounthash, &pair);
+
+ (*refcount)--;
+ if (*refcount == 0) {
+ BLI_ghash_remove(cache->resulthash, &pair, MEM_freeN, NULL);
+ BLI_ghash_remove(cache->refcounthash, &pair, NULL, NULL);
+ }
+}
+
+static void strand_shade_refcount(StrandShadeCache *cache, StrandSegment *sseg, StrandVert *svert)
+{
+ GHashPair pair = strand_shade_hash_pair(sseg->obi, svert);
+ GHashPair *key;
+ int *refcount= BLI_ghash_lookup(cache->refcounthash, &pair);
+
+ if (!refcount) {
+ key= BLI_memarena_alloc(cache->memarena, sizeof(GHashPair));
+ *key = pair;
+ refcount= BLI_memarena_alloc(cache->memarena, sizeof(int));
+ *refcount= 1;
+ BLI_ghash_insert(cache->refcounthash, key, refcount);
+ }
+ else
+ (*refcount)++;
+}
+
+/* *************** */
+
+typedef struct StrandPart {
+ Render *re;
+ ZSpan *zspan;
+
+ APixstrand *apixbuf;
+ int *totapixbuf;
+ int *rectz;
+ int *rectmask;
+ intptr_t *rectdaps;
+ int rectx, recty;
+ int sample;
+ int shadow;
+ float (*jit)[2];
+ int samples;
+
+ StrandSegment *segment;
+ float t[3], s[3];
+
+ StrandShadeCache *cache;
+} StrandPart;
+
+typedef struct StrandSortSegment {
+ struct StrandSortSegment *next;
+ int obi, strand, segment;
+ float z;
+} StrandSortSegment;
+
+static int compare_strand_segment(const void *poin1, const void *poin2)
+{
+ const StrandSortSegment *seg1= (const StrandSortSegment*)poin1;
+ const StrandSortSegment *seg2= (const StrandSortSegment*)poin2;
+
+ if (seg1->z < seg2->z)
+ return -1;
+ else if (seg1->z == seg2->z)
+ return 0;
+ else
+ return 1;
+}
+
+static void do_strand_point_project(float winmat[4][4], ZSpan *zspan, float *co, float *hoco, float *zco)
+{
+ projectvert(co, winmat, hoco);
+ hoco_to_zco(zspan, zco, hoco);
+}
+
+static void strand_project_point(float winmat[4][4], float winx, float winy, StrandPoint *spoint)
+{
+ float div;
+
+ projectvert(spoint->co, winmat, spoint->hoco);
+
+ div= 1.0f/spoint->hoco[3];
+ spoint->x= spoint->hoco[0]*div*winx*0.5f;
+ spoint->y= spoint->hoco[1]*div*winy*0.5f;
+}
+
+static APixstrand *addpsmainAstrand(ListBase *lb)
+{
+ APixstrMain *psm;
+
+ psm= MEM_mallocN(sizeof(APixstrMain), "addpsmainA");
+ BLI_addtail(lb, psm);
+ psm->ps = MEM_callocN(4096 * sizeof(APixstrand), "pixstr");
+
+ return psm->ps;
+}
+
+static APixstrand *addpsAstrand(ZSpan *zspan)
+{
+ /* make new PS */
+ if (zspan->apstrandmcounter==0) {
+ zspan->curpstrand= addpsmainAstrand(zspan->apsmbase);
+ zspan->apstrandmcounter= 4095;
+ }
+ else {
+ zspan->curpstrand++;
+ zspan->apstrandmcounter--;
+ }
+ return zspan->curpstrand;
+}
+
+#define MAX_ZROW 2000
+
+static void do_strand_fillac(void *handle, int x, int y, float u, float v, float z)
+{
+ StrandPart *spart= (StrandPart *)handle;
+ StrandShadeCache *cache= spart->cache;
+ StrandSegment *sseg= spart->segment;
+ APixstrand *apn, *apnew;
+ float t, s;
+ int offset, mask, obi, strnr, seg, zverg, bufferz, maskz=0;
+
+ offset = y*spart->rectx + x;
+ obi= sseg->obi - spart->re->objectinstance;
+ strnr= sseg->strand->index + 1;
+ seg= sseg->v[1] - sseg->strand->vert;
+ mask= (1<<spart->sample);
+
+ /* check against solid z-buffer */
+ zverg= (int)z;
+
+ if (spart->rectdaps) {
+ /* find the z of the sample */
+ PixStr *ps;
+ intptr_t *rd= spart->rectdaps + offset;
+
+ bufferz= 0x7FFFFFFF;
+ if (spart->rectmask) maskz= 0x7FFFFFFF;
+
+ if (*rd) {
+ for (ps= (PixStr *)(*rd); ps; ps= ps->next) {
+ if (mask & ps->mask) {
+ bufferz= ps->z;
+ if (spart->rectmask)
+ maskz= ps->maskz;
+ break;
+ }
+ }
+ }
+ }
+ else {
+ bufferz= (spart->rectz)? spart->rectz[offset]: 0x7FFFFFFF;
+ if (spart->rectmask)
+ maskz= spart->rectmask[offset];
+ }
+
+#define CHECK_ADD(n) \
+ if (apn->p[n]==strnr && apn->obi[n]==obi && apn->seg[n]==seg) \
+ { if (!(apn->mask[n] & mask)) { apn->mask[n] |= mask; apn->v[n] += t; apn->u[n] += s; } break; } (void)0
+#define CHECK_ASSIGN(n) \
+ if (apn->p[n]==0) \
+ {apn->obi[n]= obi; apn->p[n]= strnr; apn->z[n]= zverg; apn->mask[n]= mask; apn->v[n]= t; apn->u[n]= s; apn->seg[n]= seg; break; } (void)0
+
+ /* add to pixel list */
+ if (zverg < bufferz && (spart->totapixbuf[offset] < MAX_ZROW)) {
+ if (!spart->rectmask || zverg > maskz) {
+ t = u * spart->t[0] + v * spart->t[1] + (1.0f - u - v) * spart->t[2];
+ s = fabsf(u * spart->s[0] + v * spart->s[1] + (1.0f - u - v) * spart->s[2]);
+
+ apn= spart->apixbuf + offset;
+ while (apn) {
+ CHECK_ADD(0);
+ CHECK_ADD(1);
+ CHECK_ADD(2);
+ CHECK_ADD(3);
+ CHECK_ASSIGN(0);
+ CHECK_ASSIGN(1);
+ CHECK_ASSIGN(2);
+ CHECK_ASSIGN(3);
+
+ apnew= addpsAstrand(spart->zspan);
+ SWAP(APixstrand, *apnew, *apn);
+ apn->next= apnew;
+ CHECK_ASSIGN(0);
+ }
+
+ if (cache) {
+ strand_shade_refcount(cache, sseg, sseg->v[1]);
+ strand_shade_refcount(cache, sseg, sseg->v[2]);
+ }
+ spart->totapixbuf[offset]++;
+ }
+ }
+}
+
+/* width is calculated in hoco space, to ensure strands are visible */
+static int strand_test_clip(float winmat[4][4], ZSpan *UNUSED(zspan), float *bounds, float *co, float *zcomp, float widthx, float widthy)
+{
+ float hoco[4];
+ int clipflag= 0;
+
+ projectvert(co, winmat, hoco);
+
+ /* we compare z without perspective division for segment sorting */
+ *zcomp= hoco[2];
+
+ if (hoco[0]+widthx < bounds[0]*hoco[3]) clipflag |= 1;
+ else if (hoco[0]-widthx > bounds[1]*hoco[3]) clipflag |= 2;
+
+ if (hoco[1]-widthy > bounds[3]*hoco[3]) clipflag |= 4;
+ else if (hoco[1]+widthy < bounds[2]*hoco[3]) clipflag |= 8;
+
+ clipflag |= testclip(hoco);
+
+ return clipflag;
+}
+
+static void do_scanconvert_strand(Render *UNUSED(re), StrandPart *spart, ZSpan *zspan, float t, float dt, float *co1, float *co2, float *co3, float *co4, int sample)
+{
+ float jco1[3], jco2[3], jco3[3], jco4[3], jx, jy;
+
+ copy_v3_v3(jco1, co1);
+ copy_v3_v3(jco2, co2);
+ copy_v3_v3(jco3, co3);
+ copy_v3_v3(jco4, co4);
+
+ if (spart->jit) {
+ jx= -spart->jit[sample][0];
+ jy= -spart->jit[sample][1];
+
+ jco1[0] += jx; jco1[1] += jy;
+ jco2[0] += jx; jco2[1] += jy;
+ jco3[0] += jx; jco3[1] += jy;
+ jco4[0] += jx; jco4[1] += jy;
+
+ /* XXX mblur? */
+ }
+
+ spart->sample= sample;
+
+ spart->t[0]= t-dt;
+ spart->s[0]= -1.0f;
+ spart->t[1]= t-dt;
+ spart->s[1]= 1.0f;
+ spart->t[2]= t;
+ spart->s[2]= 1.0f;
+ zspan_scanconvert_strand(zspan, spart, jco1, jco2, jco3, do_strand_fillac);
+ spart->t[0]= t-dt;
+ spart->s[0]= -1.0f;
+ spart->t[1]= t;
+ spart->s[1]= 1.0f;
+ spart->t[2]= t;
+ spart->s[2]= -1.0f;
+ zspan_scanconvert_strand(zspan, spart, jco1, jco3, jco4, do_strand_fillac);
+}
+
+static void strand_render(Render *re, StrandSegment *sseg, float winmat[4][4], StrandPart *spart, ZSpan *zspan, int totzspan, StrandPoint *p1, StrandPoint *p2)
+{
+ if (spart) {
+ float t= p2->t;
+ float dt= p2->t - p1->t;
+ int a;
+
+ for (a=0; a<spart->samples; a++)
+ do_scanconvert_strand(re, spart, zspan, t, dt, p1->zco2, p1->zco1, p2->zco1, p2->zco2, a);
+ }
+ else {
+ float hoco1[4], hoco2[4];
+ int a, obi, index;
+
+ obi= sseg->obi - re->objectinstance;
+ index= sseg->strand->index;
+
+ projectvert(p1->co, winmat, hoco1);
+ projectvert(p2->co, winmat, hoco2);
+
+
+ for (a=0; a<totzspan; a++) {
+#if 0
+ /* render both strand and single pixel wire to counter aliasing */
+ zbufclip4(re, &zspan[a], obi, index, p1->hoco2, p1->hoco1, p2->hoco1, p2->hoco2, p1->clip2, p1->clip1, p2->clip1, p2->clip2);
+#endif
+ /* only render a line for now, which makes the shadow map more
+ * similar across frames, and so reduces flicker */
+ zbufsinglewire(&zspan[a], obi, index, hoco1, hoco2);
+ }
+ }
+}
+
+static int strand_segment_recursive(Render *re, float winmat[4][4], StrandPart *spart, ZSpan *zspan, int totzspan, StrandSegment *sseg, StrandPoint *p1, StrandPoint *p2, int depth)
+{
+ StrandPoint p;
+ StrandBuffer *buffer= sseg->buffer;
+ float dot, d1[2], d2[2], len1, len2;
+
+ if (depth == buffer->maxdepth)
+ return 0;
+
+ p.t= (p1->t + p2->t)*0.5f;
+ strand_eval_point(sseg, &p);
+ strand_project_point(buffer->winmat, buffer->winx, buffer->winy, &p);
+
+ d1[0]= (p.x - p1->x);
+ d1[1]= (p.y - p1->y);
+ len1= d1[0]*d1[0] + d1[1]*d1[1];
+
+ d2[0]= (p2->x - p.x);
+ d2[1]= (p2->y - p.y);
+ len2= d2[0]*d2[0] + d2[1]*d2[1];
+
+ if (len1 == 0.0f || len2 == 0.0f)
+ return 0;
+
+ dot= d1[0]*d2[0] + d1[1]*d2[1];
+ if (dot*dot > sseg->sqadaptcos*len1*len2)
+ return 0;
+
+ if (spart) {
+ do_strand_point_project(winmat, zspan, p.co1, p.hoco1, p.zco1);
+ do_strand_point_project(winmat, zspan, p.co2, p.hoco2, p.zco2);
+ }
+ else {
+#if 0
+ projectvert(p.co1, winmat, p.hoco1);
+ projectvert(p.co2, winmat, p.hoco2);
+ p.clip1= testclip(p.hoco1);
+ p.clip2= testclip(p.hoco2);
+#endif
+ }
+
+ if (!strand_segment_recursive(re, winmat, spart, zspan, totzspan, sseg, p1, &p, depth+1))
+ strand_render(re, sseg, winmat, spart, zspan, totzspan, p1, &p);
+ if (!strand_segment_recursive(re, winmat, spart, zspan, totzspan, sseg, &p, p2, depth+1))
+ strand_render(re, sseg, winmat, spart, zspan, totzspan, &p, p2);
+
+ return 1;
+}
+
+void render_strand_segment(Render *re, float winmat[4][4], StrandPart *spart, ZSpan *zspan, int totzspan, StrandSegment *sseg)
+{
+ StrandBuffer *buffer= sseg->buffer;
+ StrandPoint *p1= &sseg->point1;
+ StrandPoint *p2= &sseg->point2;
+
+ p1->t= 0.0f;
+ p2->t= 1.0f;
+
+ strand_eval_point(sseg, p1);
+ strand_project_point(buffer->winmat, buffer->winx, buffer->winy, p1);
+ strand_eval_point(sseg, p2);
+ strand_project_point(buffer->winmat, buffer->winx, buffer->winy, p2);
+
+ if (spart) {
+ do_strand_point_project(winmat, zspan, p1->co1, p1->hoco1, p1->zco1);
+ do_strand_point_project(winmat, zspan, p1->co2, p1->hoco2, p1->zco2);
+ do_strand_point_project(winmat, zspan, p2->co1, p2->hoco1, p2->zco1);
+ do_strand_point_project(winmat, zspan, p2->co2, p2->hoco2, p2->zco2);
+ }
+ else {
+#if 0
+ projectvert(p1->co1, winmat, p1->hoco1);
+ projectvert(p1->co2, winmat, p1->hoco2);
+ projectvert(p2->co1, winmat, p2->hoco1);
+ projectvert(p2->co2, winmat, p2->hoco2);
+ p1->clip1= testclip(p1->hoco1);
+ p1->clip2= testclip(p1->hoco2);
+ p2->clip1= testclip(p2->hoco1);
+ p2->clip2= testclip(p2->hoco2);
+#endif
+ }
+
+ if (!strand_segment_recursive(re, winmat, spart, zspan, totzspan, sseg, p1, p2, 0))
+ strand_render(re, sseg, winmat, spart, zspan, totzspan, p1, p2);
+}
+
+/* render call to fill in strands */
+int zbuffer_strands_abuf(Render *re, RenderPart *pa, APixstrand *apixbuf, ListBase *apsmbase, unsigned int lay, int UNUSED(negzmask), float winmat[4][4], int winx, int winy, int samples, float (*jit)[2], float clipcrop, int shadow, StrandShadeCache *cache)
+{
+ ObjectRen *obr;
+ ObjectInstanceRen *obi;
+ ZSpan zspan;
+ StrandRen *strand = NULL;
+ StrandVert *svert;
+ StrandBound *sbound;
+ StrandPart spart;
+ StrandSegment sseg;
+ StrandSortSegment *sortsegments = NULL, *sortseg, *firstseg;
+ MemArena *memarena;
+ float z[4], bounds[4], obwinmat[4][4];
+ int a, b, c, i, totsegment, clip[4];
+
+ if (re->test_break(re->tbh))
+ return 0;
+ if (re->totstrand == 0)
+ return 0;
+
+ /* setup StrandPart */
+ memset(&spart, 0, sizeof(spart));
+
+ spart.re= re;
+ spart.rectx= pa->rectx;
+ spart.recty= pa->recty;
+ spart.apixbuf= apixbuf;
+ spart.zspan= &zspan;
+ spart.rectdaps= pa->rectdaps;
+ spart.rectz= pa->rectz;
+ spart.rectmask= pa->rectmask;
+ spart.cache= cache;
+ spart.shadow= shadow;
+ spart.jit= jit;
+ spart.samples= samples;
+
+ zbuf_alloc_span(&zspan, pa->rectx, pa->recty, clipcrop);
+
+ /* needed for transform from hoco to zbuffer co */
+ zspan.zmulx= ((float)winx)/2.0f;
+ zspan.zmuly= ((float)winy)/2.0f;
+
+ zspan.zofsx= -pa->disprect.xmin;
+ zspan.zofsy= -pa->disprect.ymin;
+
+ /* to center the sample position */
+ if (!shadow) {
+ zspan.zofsx -= 0.5f;
+ zspan.zofsy -= 0.5f;
+ }
+
+ zspan.apsmbase= apsmbase;
+
+ /* clipping setup */
+ bounds[0]= (2*pa->disprect.xmin - winx-1)/(float)winx;
+ bounds[1]= (2*pa->disprect.xmax - winx+1)/(float)winx;
+ bounds[2]= (2*pa->disprect.ymin - winy-1)/(float)winy;
+ bounds[3]= (2*pa->disprect.ymax - winy+1)/(float)winy;
+
+ memarena= BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, "strand sort arena");
+ firstseg= NULL;
+ totsegment= 0;
+
+ /* for all object instances */
+ for (obi=re->instancetable.first, i=0; obi; obi=obi->next, i++) {
+ Material *ma;
+ float widthx, widthy;
+
+ obr= obi->obr;
+
+ if (!obr->strandbuf || !(obr->strandbuf->lay & lay))
+ continue;
+
+ /* compute matrix and try clipping whole object */
+ if (obi->flag & R_TRANSFORMED)
+ mul_m4_m4m4(obwinmat, winmat, obi->mat);
+ else
+ copy_m4_m4(obwinmat, winmat);
+
+ /* test if we should skip it */
+ ma = obr->strandbuf->ma;
+
+ if (shadow && (!(ma->mode2 & MA_CASTSHADOW) || !(ma->mode & MA_SHADBUF)))
+ continue;
+ else if (!shadow && (ma->mode & MA_ONLYCAST))
+ continue;
+
+ if (clip_render_object(obi->obr->boundbox, bounds, obwinmat))
+ continue;
+
+ widthx= obr->strandbuf->maxwidth*obwinmat[0][0];
+ widthy= obr->strandbuf->maxwidth*obwinmat[1][1];
+
+ /* for each bounding box containing a number of strands */
+ sbound= obr->strandbuf->bound;
+ for (c=0; c<obr->strandbuf->totbound; c++, sbound++) {
+ if (clip_render_object(sbound->boundbox, bounds, obwinmat))
+ continue;
+
+ /* for each strand in this bounding box */
+ for (a=sbound->start; a<sbound->end; a++) {
+ strand= RE_findOrAddStrand(obr, a);
+ svert= strand->vert;
+
+ /* keep clipping and z depth for 4 control points */
+ clip[1]= strand_test_clip(obwinmat, &zspan, bounds, svert->co, &z[1], widthx, widthy);
+ clip[2]= strand_test_clip(obwinmat, &zspan, bounds, (svert+1)->co, &z[2], widthx, widthy);
+ clip[0]= clip[1]; z[0]= z[1];
+
+ for (b=0; b<strand->totvert-1; b++, svert++) {
+ /* compute 4th point clipping and z depth */
+ if (b < strand->totvert-2) {
+ clip[3]= strand_test_clip(obwinmat, &zspan, bounds, (svert+2)->co, &z[3], widthx, widthy);
+ }
+ else {
+ clip[3]= clip[2]; z[3]= z[2];
+ }
+
+ /* check clipping and add to sortsegments buffer */
+ if (!(clip[0] & clip[1] & clip[2] & clip[3])) {
+ sortseg= BLI_memarena_alloc(memarena, sizeof(StrandSortSegment));
+ sortseg->obi= i;
+ sortseg->strand= strand->index;
+ sortseg->segment= b;
+
+ sortseg->z= 0.5f*(z[1] + z[2]);
+
+ sortseg->next= firstseg;
+ firstseg= sortseg;
+ totsegment++;
+ }
+
+ /* shift clipping and z depth */
+ clip[0]= clip[1]; z[0]= z[1];
+ clip[1]= clip[2]; z[1]= z[2];
+ clip[2]= clip[3]; z[2]= z[3];
+ }
+ }
+ }
+ }
+
+ if (!re->test_break(re->tbh)) {
+ /* convert list to array and sort */
+ sortsegments= MEM_mallocN(sizeof(StrandSortSegment)*totsegment, "StrandSortSegment");
+ for (a=0, sortseg=firstseg; a<totsegment; a++, sortseg=sortseg->next)
+ sortsegments[a]= *sortseg;
+ qsort(sortsegments, totsegment, sizeof(StrandSortSegment), compare_strand_segment);
+ }
+
+ BLI_memarena_free(memarena);
+
+ spart.totapixbuf= MEM_callocN(sizeof(int)*pa->rectx*pa->recty, "totapixbuf");
+
+ if (!re->test_break(re->tbh)) {
+ /* render segments in sorted order */
+ sortseg= sortsegments;
+ for (a=0; a<totsegment; a++, sortseg++) {
+ if (re->test_break(re->tbh))
+ break;
+
+ obi= &re->objectinstance[sortseg->obi];
+ obr= obi->obr;
+
+ sseg.obi= obi;
+ sseg.strand= RE_findOrAddStrand(obr, sortseg->strand);
+ sseg.buffer= sseg.strand->buffer;
+ sseg.sqadaptcos= sseg.buffer->adaptcos;
+ sseg.sqadaptcos *= sseg.sqadaptcos;
+
+ svert= sseg.strand->vert + sortseg->segment;
+ sseg.v[0]= (sortseg->segment > 0)? (svert-1): svert;
+ sseg.v[1]= svert;
+ sseg.v[2]= svert+1;
+ sseg.v[3]= (sortseg->segment < sseg.strand->totvert-2)? svert+2: svert+1;
+ sseg.shaded= 0;
+
+ spart.segment= &sseg;
+
+ render_strand_segment(re, winmat, &spart, &zspan, 1, &sseg);
+ }
+ }
+
+ if (sortsegments)
+ MEM_freeN(sortsegments);
+ MEM_freeN(spart.totapixbuf);
+
+ zbuf_free_span(&zspan);
+
+ return totsegment;
+}
+
+/* *************** */
+
+StrandSurface *cache_strand_surface(Render *re, ObjectRen *obr, DerivedMesh *dm, float mat[4][4], int timeoffset)
+{
+ StrandSurface *mesh;
+ MFace *mface;
+ MVert *mvert;
+ float (*co)[3];
+ int a, totvert, totface;
+
+ totvert= dm->getNumVerts(dm);
+ totface= dm->getNumTessFaces(dm);
+
+ for (mesh = re->strandsurface.first; mesh; mesh = mesh->next) {
+ if ((mesh->obr.ob == obr->ob) &&
+ (mesh->obr.par == obr->par) &&
+ (mesh->obr.index == obr->index) &&
+ (mesh->totvert == totvert) &&
+ (mesh->totface == totface))
+ {
+ break;
+ }
+ }
+
+ if (!mesh) {
+ mesh= MEM_callocN(sizeof(StrandSurface), "StrandSurface");
+ mesh->obr= *obr;
+ mesh->totvert= totvert;
+ mesh->totface= totface;
+ mesh->face= MEM_callocN(sizeof(int)*4*mesh->totface, "StrandSurfFaces");
+ mesh->ao= MEM_callocN(sizeof(float)*3*mesh->totvert, "StrandSurfAO");
+ mesh->env= MEM_callocN(sizeof(float)*3*mesh->totvert, "StrandSurfEnv");
+ mesh->indirect= MEM_callocN(sizeof(float)*3*mesh->totvert, "StrandSurfIndirect");
+ BLI_addtail(&re->strandsurface, mesh);
+ }
+
+ if (timeoffset == -1 && !mesh->prevco)
+ mesh->prevco= co= MEM_callocN(sizeof(float)*3*mesh->totvert, "StrandSurfCo");
+ else if (timeoffset == 0 && !mesh->co)
+ mesh->co= co= MEM_callocN(sizeof(float)*3*mesh->totvert, "StrandSurfCo");
+ else if (timeoffset == 1 && !mesh->nextco)
+ mesh->nextco= co= MEM_callocN(sizeof(float)*3*mesh->totvert, "StrandSurfCo");
+ else
+ return mesh;
+
+ mvert= dm->getVertArray(dm);
+ for (a=0; a<mesh->totvert; a++, mvert++) {
+ copy_v3_v3(co[a], mvert->co);
+ mul_m4_v3(mat, co[a]);
+ }
+
+ mface= dm->getTessFaceArray(dm);
+ for (a=0; a<mesh->totface; a++, mface++) {
+ mesh->face[a][0]= mface->v1;
+ mesh->face[a][1]= mface->v2;
+ mesh->face[a][2]= mface->v3;
+ mesh->face[a][3]= mface->v4;
+ }
+
+ return mesh;
+}
+
+void free_strand_surface(Render *re)
+{
+ StrandSurface *mesh;
+
+ for (mesh=re->strandsurface.first; mesh; mesh=mesh->next) {
+ if (mesh->co) MEM_freeN(mesh->co);
+ if (mesh->prevco) MEM_freeN(mesh->prevco);
+ if (mesh->nextco) MEM_freeN(mesh->nextco);
+ if (mesh->ao) MEM_freeN(mesh->ao);
+ if (mesh->env) MEM_freeN(mesh->env);
+ if (mesh->indirect) MEM_freeN(mesh->indirect);
+ if (mesh->face) MEM_freeN(mesh->face);
+ }
+
+ BLI_freelistN(&re->strandsurface);
+}
+
+void strand_minmax(StrandRen *strand, float min[3], float max[3], const float width)
+{
+ StrandVert *svert;
+ const float width2 = width * 2.0f;
+ float vec[3];
+ int a;
+
+ for (a=0, svert=strand->vert; a<strand->totvert; a++, svert++) {
+ copy_v3_v3(vec, svert->co);
+ minmax_v3v3_v3(min, max, vec);
+
+ if (width!=0.0f) {
+ add_v3_fl(vec, width);
+ minmax_v3v3_v3(min, max, vec);
+ add_v3_fl(vec, -width2);
+ minmax_v3v3_v3(min, max, vec);
+ }
+ }
+}
+
diff --git a/source/blender/render/intern/source/sunsky.c b/source/blender/render/intern/source/sunsky.c
new file mode 100644
index 00000000000..80dd52c220c
--- /dev/null
+++ b/source/blender/render/intern/source/sunsky.c
@@ -0,0 +1,506 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/render/intern/source/sunsky.c
+ * \ingroup render
+ *
+ * This feature comes from Preetham paper on "A Practical Analytic Model for Daylight"
+ * and example code from Brian Smits, another author of that paper in
+ * http://www.cs.utah.edu/vissim/papers/sunsky/code/
+ */
+
+#include "sunsky.h"
+#include "BLI_math.h"
+
+/**
+ * These macros are defined for vector operations
+ * */
+
+/**
+ * compute v1 = v2 op v3
+ * v1, v2 and v3 are vectors contains 3 float
+ * */
+#define VEC3OPV(v1, v2, op, v3) \
+ { \
+ v1[0] = (v2[0] op v3[0]); \
+ v1[1] = (v2[1] op v3[1]); \
+ v1[2] = (v2[2] op v3[2]); \
+ } (void)0
+
+/**
+ * compute v1 = v2 op f1
+ * v1, v2 are vectors contains 3 float
+ * and f1 is a float
+ * */
+#define VEC3OPF(v1, v2, op, f1) \
+ { \
+ v1[0] = (v2[0] op(f1)); \
+ v1[1] = (v2[1] op(f1)); \
+ v1[2] = (v2[2] op(f1)); \
+ } (void)0
+
+/**
+ * compute v1 = f1 op v2
+ * v1, v2 are vectors contains 3 float
+ * and f1 is a float
+ * */
+#define FOPVEC3(v1, f1, op, v2) \
+ { \
+ v1[0] = ((f1) op v2[0]); \
+ v1[1] = ((f1) op v2[1]); \
+ v1[2] = ((f1) op v2[2]); \
+ } (void)0
+
+/**
+ * ClipColor:
+ * clip a color to range [0, 1];
+ * */
+void ClipColor(float c[3])
+{
+ if (c[0] > 1.0f) c[0] = 1.0f;
+ if (c[0] < 0.0f) c[0] = 0.0f;
+ if (c[1] > 1.0f) c[1] = 1.0f;
+ if (c[1] < 0.0f) c[1] = 0.0f;
+ if (c[2] > 1.0f) c[2] = 1.0f;
+ if (c[2] < 0.0f) c[2] = 0.0f;
+}
+
+/**
+ * AngleBetween:
+ * compute angle between to direction
+ * all angles are in radians
+ * */
+static float AngleBetween(float thetav, float phiv, float theta, float phi)
+{
+ float cospsi = sinf(thetav) * sinf(theta) * cosf(phi - phiv) + cosf(thetav) * cosf(theta);
+
+ if (cospsi > 1.0f)
+ return 0;
+ if (cospsi < -1.0f)
+ return M_PI;
+
+ return acosf(cospsi);
+}
+
+/**
+ * DirectionToThetaPhi:
+ * this function convert a direction to it's theta and phi value
+ * parameters:
+ * toSun: contains direction information
+ * theta, phi, are return values from this conversion
+ * */
+static void DirectionToThetaPhi(float *toSun, float *theta, float *phi)
+{
+ *theta = acosf(toSun[2]);
+ if (fabsf(*theta) < 1e-5f)
+ *phi = 0;
+ else
+ *phi = atan2f(toSun[1], toSun[0]);
+}
+
+/**
+ * PerezFunction:
+ * compute perez function value based on input parameters
+ */
+static float PerezFunction(struct SunSky *sunsky, const float *lam, float theta, float gamma, float lvz)
+{
+ float den, num;
+
+ den = ((1 + lam[0] * expf(lam[1])) *
+ (1 + lam[2] * expf(lam[3] * sunsky->theta) + lam[4] * cosf(sunsky->theta) * cosf(sunsky->theta)));
+
+ num = ((1 + lam[0] * expf(lam[1] / cosf(theta))) *
+ (1 + lam[2] * expf(lam[3] * gamma) + lam[4] * cosf(gamma) * cosf(gamma)));
+
+ return(lvz * num / den);
+}
+
+/**
+ * InitSunSky:
+ * this function compute some sun,sky parameters according to input parameters and also initiate some other sun, sky parameters
+ * parameters:
+ * sunSky, is a structure that contains information about sun, sky and atmosphere, in this function, most of its values initiated
+ * turb, is atmosphere turbidity
+ * toSun, contains sun direction
+ * horizon_brighness, controls the brightness of the horizon colors
+ * spread, controls colors spreed at horizon
+ * sun_brightness, controls sun's brightness
+ * sun_size, controls sun's size
+ * back_scatter, controls back scatter light
+ * */
+void InitSunSky(struct SunSky *sunsky, float turb, const float toSun[3], float horizon_brightness,
+ float spread, float sun_brightness, float sun_size, float back_scatter,
+ float skyblendfac, short skyblendtype, float sky_exposure, float sky_colorspace)
+{
+ float theta2;
+ float theta3;
+ float T;
+ float T2;
+ float chi;
+
+ sunsky->turbidity = turb;
+
+ sunsky->horizon_brightness = horizon_brightness;
+ sunsky->spread = spread;
+ sunsky->sun_brightness = sun_brightness;
+ sunsky->sun_size = sun_size;
+ sunsky->backscattered_light = back_scatter;
+ sunsky->skyblendfac = skyblendfac;
+ sunsky->skyblendtype = skyblendtype;
+ sunsky->sky_exposure = -sky_exposure;
+ sunsky->sky_colorspace = sky_colorspace;
+
+ sunsky->toSun[0] = toSun[0];
+ sunsky->toSun[1] = toSun[1];
+ sunsky->toSun[2] = toSun[2];
+
+ DirectionToThetaPhi(sunsky->toSun, &sunsky->theta, &sunsky->phi);
+
+ sunsky->sunSolidAngle = 0.25 * M_PI * 1.39 * 1.39 / (150 * 150); /* = 6.7443e-05 */
+
+ theta2 = sunsky->theta * sunsky->theta;
+ theta3 = theta2 * sunsky->theta;
+ T = turb;
+ T2 = turb * turb;
+
+ chi = (4.0f / 9.0f - T / 120.0f) * ((float)M_PI - 2.0f * sunsky->theta);
+ sunsky->zenith_Y = (4.0453f * T - 4.9710f) * tanf(chi) - 0.2155f * T + 2.4192f;
+ sunsky->zenith_Y *= 1000; /* conversion from kcd/m^2 to cd/m^2 */
+
+ if (sunsky->zenith_Y <= 0)
+ sunsky->zenith_Y = 1e-6;
+
+ sunsky->zenith_x =
+ (+0.00165f * theta3 - 0.00374f * theta2 + 0.00208f * sunsky->theta + 0.0f) * T2 +
+ (-0.02902f * theta3 + 0.06377f * theta2 - 0.03202f * sunsky->theta + 0.00394f) * T +
+ (+0.11693f * theta3 - 0.21196f * theta2 + 0.06052f * sunsky->theta + 0.25885f);
+
+ sunsky->zenith_y =
+ (+0.00275f * theta3 - 0.00610f * theta2 + 0.00316f * sunsky->theta + 0.0f) * T2 +
+ (-0.04214f * theta3 + 0.08970f * theta2 - 0.04153f * sunsky->theta + 0.00515f) * T +
+ (+0.15346f * theta3 - 0.26756f * theta2 + 0.06669f * sunsky->theta + 0.26688f);
+
+
+ sunsky->perez_Y[0] = 0.17872f * T - 1.46303f;
+ sunsky->perez_Y[1] = -0.35540f * T + 0.42749f;
+ sunsky->perez_Y[2] = -0.02266f * T + 5.32505f;
+ sunsky->perez_Y[3] = 0.12064f * T - 2.57705f;
+ sunsky->perez_Y[4] = -0.06696f * T + 0.37027f;
+
+ sunsky->perez_x[0] = -0.01925f * T - 0.25922f;
+ sunsky->perez_x[1] = -0.06651f * T + 0.00081f;
+ sunsky->perez_x[2] = -0.00041f * T + 0.21247f;
+ sunsky->perez_x[3] = -0.06409f * T - 0.89887f;
+ sunsky->perez_x[4] = -0.00325f * T + 0.04517f;
+
+ sunsky->perez_y[0] = -0.01669f * T - 0.26078f;
+ sunsky->perez_y[1] = -0.09495f * T + 0.00921f;
+ sunsky->perez_y[2] = -0.00792f * T + 0.21023f;
+ sunsky->perez_y[3] = -0.04405f * T - 1.65369f;
+ sunsky->perez_y[4] = -0.01092f * T + 0.05291f;
+
+ /* suggested by glome in patch [#8063] */
+ sunsky->perez_Y[0] *= sunsky->horizon_brightness;
+ sunsky->perez_x[0] *= sunsky->horizon_brightness;
+ sunsky->perez_y[0] *= sunsky->horizon_brightness;
+
+ sunsky->perez_Y[1] *= sunsky->spread;
+ sunsky->perez_x[1] *= sunsky->spread;
+ sunsky->perez_y[1] *= sunsky->spread;
+
+ sunsky->perez_Y[2] *= sunsky->sun_brightness;
+ sunsky->perez_x[2] *= sunsky->sun_brightness;
+ sunsky->perez_y[2] *= sunsky->sun_brightness;
+
+ sunsky->perez_Y[3] *= sunsky->sun_size;
+ sunsky->perez_x[3] *= sunsky->sun_size;
+ sunsky->perez_y[3] *= sunsky->sun_size;
+
+ sunsky->perez_Y[4] *= sunsky->backscattered_light;
+ sunsky->perez_x[4] *= sunsky->backscattered_light;
+ sunsky->perez_y[4] *= sunsky->backscattered_light;
+}
+
+/**
+ * GetSkyXYZRadiance:
+ * this function compute sky radiance according to a view parameters `theta' and `phi'and sunSky values
+ * parameters:
+ * sunSky, sontains sun and sky parameters
+ * theta, is sun's theta
+ * phi, is sun's phi
+ * color_out, is computed color that shows sky radiance in XYZ color format
+ * */
+void GetSkyXYZRadiance(struct SunSky *sunsky, float theta, float phi, float color_out[3])
+{
+ float gamma;
+ float x, y, Y, X, Z;
+ float hfade = 1, nfade = 1;
+
+
+ if (theta > (float)M_PI_2) {
+ hfade = 1.0f - (theta * (float)M_1_PI - 0.5f) * 2.0f;
+ hfade = hfade * hfade * (3.0f - 2.0f * hfade);
+ theta = M_PI_2;
+ }
+
+ if (sunsky->theta > (float)M_PI_2) {
+ if (theta <= (float)M_PI_2) {
+ nfade = 1.0f - (0.5f - theta * (float)M_1_PI) * 2.0f;
+ nfade *= 1.0f - (sunsky->theta * (float)M_1_PI - 0.5f) * 2.0f;
+ nfade = nfade * nfade * (3.0f - 2.0f * nfade);
+ }
+ }
+
+ gamma = AngleBetween(theta, phi, sunsky->theta, sunsky->phi);
+
+ /* Compute xyY values */
+ x = PerezFunction(sunsky, sunsky->perez_x, theta, gamma, sunsky->zenith_x);
+ y = PerezFunction(sunsky, sunsky->perez_y, theta, gamma, sunsky->zenith_y);
+ Y = 6.666666667e-5f * nfade * hfade * PerezFunction(sunsky, sunsky->perez_Y, theta, gamma, sunsky->zenith_Y);
+
+ if (sunsky->sky_exposure != 0.0f)
+ Y = 1.0 - exp(Y * sunsky->sky_exposure);
+
+ X = (x / y) * Y;
+ Z = ((1 - x - y) / y) * Y;
+
+ color_out[0] = X;
+ color_out[1] = Y;
+ color_out[2] = Z;
+}
+
+/**
+ * GetSkyXYZRadiancef:
+ * this function compute sky radiance according to a view direction `varg' and sunSky values
+ * parameters:
+ * sunSky, sontains sun and sky parameters
+ * varg, shows direction
+ * color_out, is computed color that shows sky radiance in XYZ color format
+ * */
+void GetSkyXYZRadiancef(struct SunSky *sunsky, const float varg[3], float color_out[3])
+{
+ float theta, phi;
+ float v[3];
+
+ normalize_v3_v3(v, varg);
+
+ if (v[2] < 0.001f) {
+ v[2] = 0.001f;
+ normalize_v3(v);
+ }
+
+ DirectionToThetaPhi(v, &theta, &phi);
+ GetSkyXYZRadiance(sunsky, theta, phi, color_out);
+}
+
+/**
+ * ComputeAttenuatedSunlight:
+ * this function compute attenuated sun light based on sun's theta and atmosphere turbidity
+ * parameters:
+ * theta, is sun's theta
+ * turbidity: is atmosphere turbidity
+ * fTau: contains computed attenuated sun light
+ * */
+static void ComputeAttenuatedSunlight(float theta, int turbidity, float fTau[3])
+{
+ float fBeta;
+ float fTauR, fTauA;
+ float m;
+ float fAlpha;
+
+ int i;
+ float fLambda[3];
+ fLambda[0] = 0.65f;
+ fLambda[1] = 0.57f;
+ fLambda[2] = 0.475f;
+
+ fAlpha = 1.3f;
+ fBeta = 0.04608365822050f * turbidity - 0.04586025928522f;
+
+ m = 1.0f / (cosf(theta) + 0.15f * powf(93.885f - theta / (float)M_PI * 180.0f, -1.253f));
+
+ for (i = 0; i < 3; i++) {
+ /* Rayleigh Scattering */
+ fTauR = expf(-m * 0.008735f * powf(fLambda[i], (float)(-4.08f)));
+
+ /* Aerosal (water + dust) attenuation */
+ fTauA = exp(-m * fBeta * powf(fLambda[i], -fAlpha));
+
+ fTau[i] = fTauR * fTauA;
+ }
+}
+
+/**
+ * InitAtmosphere:
+ * this function initiate sunSky structure with user input parameters.
+ * parameters:
+ * sunSky, contains information about sun, and in this function some atmosphere parameters will initiated
+ * sun_intens, shows sun intensity value
+ * mief, Mie scattering factor this factor currently call with 1.0
+ * rayf, Rayleigh scattering factor, this factor currently call with 1.0
+ * inscattf, inscatter light factor that range from 0.0 to 1.0, 0.0 means no inscatter light and 1.0 means full inscatter light
+ * extincf, extinction light factor that range from 0.0 to 1.0, 0.0 means no extinction and 1.0 means full extinction
+ * disf, is distance factor, multiplied to pixle's z value to compute each pixle's distance to camera,
+ * */
+void InitAtmosphere(struct SunSky *sunSky, float sun_intens, float mief, float rayf,
+ float inscattf, float extincf, float disf)
+{
+ const float pi = M_PI;
+ const float n = 1.003f; /* refractive index */
+ const float N = 2.545e25;
+ const float pn = 0.035f;
+ const float T = 2.0f;
+ float fTemp, fTemp2, fTemp3, fBeta, fBetaDash;
+ float c = (6.544f * T - 6.51f) * 1e-17f;
+ float K[3] = {0.685f, 0.679f, 0.670f};
+ float vBetaMieTemp[3];
+
+ float fLambda[3], fLambda2[3], fLambda4[3];
+ float vLambda2[3];
+ float vLambda4[3];
+
+ int i;
+
+ sunSky->atm_SunIntensity = sun_intens;
+ sunSky->atm_BetaMieMultiplier = mief;
+ sunSky->atm_BetaRayMultiplier = rayf;
+ sunSky->atm_InscatteringMultiplier = inscattf;
+ sunSky->atm_ExtinctionMultiplier = extincf;
+ sunSky->atm_DistanceMultiplier = disf;
+
+ sunSky->atm_HGg = 0.8;
+
+ fLambda[0] = 1 / 650e-9f;
+ fLambda[1] = 1 / 570e-9f;
+ fLambda[2] = 1 / 475e-9f;
+ for (i = 0; i < 3; i++) {
+ fLambda2[i] = fLambda[i] * fLambda[i];
+ fLambda4[i] = fLambda2[i] * fLambda2[i];
+ }
+
+ vLambda2[0] = fLambda2[0];
+ vLambda2[1] = fLambda2[1];
+ vLambda2[2] = fLambda2[2];
+
+ vLambda4[0] = fLambda4[0];
+ vLambda4[1] = fLambda4[1];
+ vLambda4[2] = fLambda4[2];
+
+ /* Rayleigh scattering constants. */
+ fTemp = pi * pi * (n * n - 1) * (n * n - 1) * (6 + 3 * pn) / (6 - 7 * pn) / N;
+ fBeta = 8 * fTemp * pi / 3;
+
+ VEC3OPF(sunSky->atm_BetaRay, vLambda4, *, fBeta);
+ fBetaDash = fTemp / 2;
+ VEC3OPF(sunSky->atm_BetaDashRay, vLambda4, *, fBetaDash);
+
+
+ /* Mie scattering constants. */
+ fTemp2 = 0.434f * c * (2 * pi) * (2 * pi) * 0.5f;
+ VEC3OPF(sunSky->atm_BetaDashMie, vLambda2, *, fTemp2);
+
+ fTemp3 = 0.434f * c * pi * (2 * pi) * (2 * pi);
+
+ VEC3OPV(vBetaMieTemp, K, *, fLambda);
+ VEC3OPF(sunSky->atm_BetaMie, vBetaMieTemp, *, fTemp3);
+
+}
+
+/**
+ * AtmospherePixleShader:
+ * this function apply atmosphere effect on a pixle color `rgb' at distance `s'
+ * parameters:
+ * sunSky, contains information about sun parameters and user values
+ * view, is camera view vector
+ * s, is distance
+ * rgb, contains rendered color value for a pixle
+ * */
+void AtmospherePixleShader(struct SunSky *sunSky, float view[3], float s, float rgb[3])
+{
+ float costheta;
+ float Phase_1;
+ float Phase_2;
+ float sunColor[3];
+
+ float E[3];
+ float E1[3];
+
+
+ float I[3];
+ float fTemp;
+ float vTemp1[3], vTemp2[3];
+
+ float sunDirection[3];
+
+ s *= sunSky->atm_DistanceMultiplier;
+
+ sunDirection[0] = sunSky->toSun[0];
+ sunDirection[1] = sunSky->toSun[1];
+ sunDirection[2] = sunSky->toSun[2];
+
+ costheta = dot_v3v3(view, sunDirection); /* cos(theta) */
+ Phase_1 = 1 + (costheta * costheta); /* Phase_1 */
+
+ VEC3OPF(sunSky->atm_BetaRay, sunSky->atm_BetaRay, *, sunSky->atm_BetaRayMultiplier);
+ VEC3OPF(sunSky->atm_BetaMie, sunSky->atm_BetaMie, *, sunSky->atm_BetaMieMultiplier);
+ VEC3OPV(sunSky->atm_BetaRM, sunSky->atm_BetaRay, +, sunSky->atm_BetaMie);
+
+ /* e^(-(beta_1 + beta_2) * s) = E1 */
+ VEC3OPF(E1, sunSky->atm_BetaRM, *, -s / (float)M_LN2);
+ E1[0] = exp(E1[0]);
+ E1[1] = exp(E1[1]);
+ E1[2] = exp(E1[2]);
+
+ copy_v3_v3(E, E1);
+
+ /* Phase2(theta) = (1-g^2)/(1+g-2g*cos(theta))^(3/2) */
+ fTemp = 1 + sunSky->atm_HGg - 2 * sunSky->atm_HGg * costheta;
+ fTemp = fTemp * sqrtf(fTemp);
+ Phase_2 = (1 - sunSky->atm_HGg * sunSky->atm_HGg) / fTemp;
+
+ VEC3OPF(vTemp1, sunSky->atm_BetaDashRay, *, Phase_1);
+ VEC3OPF(vTemp2, sunSky->atm_BetaDashMie, *, Phase_2);
+
+ VEC3OPV(vTemp1, vTemp1, +, vTemp2);
+ FOPVEC3(vTemp2, 1.0f, -, E1);
+ VEC3OPV(vTemp1, vTemp1, *, vTemp2);
+
+ FOPVEC3(vTemp2, 1.0f, /, sunSky->atm_BetaRM);
+
+ VEC3OPV(I, vTemp1, *, vTemp2);
+
+ VEC3OPF(I, I, *, sunSky->atm_InscatteringMultiplier);
+ VEC3OPF(E, E, *, sunSky->atm_ExtinctionMultiplier);
+
+ /* scale to color sun */
+ ComputeAttenuatedSunlight(sunSky->theta, sunSky->turbidity, sunColor);
+ VEC3OPV(E, E, *, sunColor);
+
+ VEC3OPF(I, I, *, sunSky->atm_SunIntensity);
+
+ VEC3OPV(rgb, rgb, *, E);
+ VEC3OPV(rgb, rgb, +, I);
+}
+
+#undef VEC3OPV
+#undef VEC3OPF
+#undef FOPVEC3
+
+/* EOF */
diff --git a/source/blender/render/intern/source/volume_precache.c b/source/blender/render/intern/source/volume_precache.c
new file mode 100644
index 00000000000..8e79f309814
--- /dev/null
+++ b/source/blender/render/intern/source/volume_precache.c
@@ -0,0 +1,855 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): Matt Ebb, Ra˙l Fern·ndez Hern·ndez (Farsthary).
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/render/intern/source/volume_precache.c
+ * \ingroup render
+ */
+
+
+#include <math.h>
+#include <stdlib.h>
+#include <string.h>
+#include <float.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_math.h"
+#include "BLI_task.h"
+#include "BLI_threads.h"
+#include "BLI_voxel.h"
+#include "BLI_utildefines.h"
+
+#include "BLT_translation.h"
+
+#include "PIL_time.h"
+
+#include "RE_shader_ext.h"
+
+#include "DNA_material_types.h"
+
+#include "rayintersection.h"
+#include "rayobject.h"
+#include "render_types.h"
+#include "rendercore.h"
+#include "renderdatabase.h"
+#include "volumetric.h"
+#include "volume_precache.h"
+
+#include "atomic_ops.h"
+
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+/* defined in pipeline.c, is hardcopy of active dynamic allocated Render */
+/* only to be used here in this file, it's for speed */
+extern struct Render R;
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+/* *** utility code to set up an individual raytree for objectinstance, for checking inside/outside *** */
+
+/* Recursive test for intersections, from a point inside the mesh, to outside
+ * Number of intersections (depth) determine if a point is inside or outside the mesh */
+static int intersect_outside_volume(RayObject *tree, Isect *isect, float *offset, int limit, int depth)
+{
+ if (limit == 0) return depth;
+
+ if (RE_rayobject_raycast(tree, isect)) {
+
+ isect->start[0] = isect->start[0] + isect->dist*isect->dir[0];
+ isect->start[1] = isect->start[1] + isect->dist*isect->dir[1];
+ isect->start[2] = isect->start[2] + isect->dist*isect->dir[2];
+
+ isect->dist = FLT_MAX;
+ isect->skip = RE_SKIP_VLR_NEIGHBOUR;
+ isect->orig.face= isect->hit.face;
+ isect->orig.ob= isect->hit.ob;
+
+ return intersect_outside_volume(tree, isect, offset, limit-1, depth+1);
+ }
+ else {
+ return depth;
+ }
+}
+
+/* Uses ray tracing to check if a point is inside or outside an ObjectInstanceRen */
+static int point_inside_obi(RayObject *tree, ObjectInstanceRen *obi, const float co[3])
+{
+ Isect isect= {{0}};
+ float dir[3] = {0.0f, 0.0f, 1.0f};
+ int final_depth=0, depth=0, limit=20;
+
+ /* set up the isect */
+ copy_v3_v3(isect.start, co);
+ copy_v3_v3(isect.dir, dir);
+ isect.mode= RE_RAY_MIRROR;
+ isect.last_hit= NULL;
+ isect.lay= -1;
+
+ isect.dist = FLT_MAX;
+ isect.orig.face= NULL;
+ isect.orig.ob = NULL;
+
+ RE_instance_rotate_ray(obi, &isect);
+ final_depth = intersect_outside_volume(tree, &isect, dir, limit, depth);
+ RE_instance_rotate_ray_restore(obi, &isect);
+
+ /* even number of intersections: point is outside
+ * odd number: point is inside */
+ if (final_depth % 2 == 0) return 0;
+ else return 1;
+}
+
+/* find the bounding box of an objectinstance in global space */
+void global_bounds_obi(Render *re, ObjectInstanceRen *obi, float bbmin[3], float bbmax[3])
+{
+ ObjectRen *obr = obi->obr;
+ VolumePrecache *vp = obi->volume_precache;
+ VertRen *ver= NULL;
+ float co[3];
+ int a;
+
+ if (vp->bbmin != NULL && vp->bbmax != NULL) {
+ copy_v3_v3(bbmin, vp->bbmin);
+ copy_v3_v3(bbmax, vp->bbmax);
+ return;
+ }
+
+ vp->bbmin = MEM_callocN(sizeof(float)*3, "volume precache min boundbox corner");
+ vp->bbmax = MEM_callocN(sizeof(float)*3, "volume precache max boundbox corner");
+
+ INIT_MINMAX(bbmin, bbmax);
+
+ for (a=0; a<obr->totvert; a++) {
+ if ((a & 255)==0) ver= obr->vertnodes[a>>8].vert;
+ else ver++;
+
+ copy_v3_v3(co, ver->co);
+
+ /* transformed object instance in camera space */
+ if (obi->flag & R_TRANSFORMED)
+ mul_m4_v3(obi->mat, co);
+
+ /* convert to global space */
+ mul_m4_v3(re->viewinv, co);
+
+ minmax_v3v3_v3(vp->bbmin, vp->bbmax, co);
+ }
+
+ copy_v3_v3(bbmin, vp->bbmin);
+ copy_v3_v3(bbmax, vp->bbmax);
+
+}
+
+/* *** light cache filtering *** */
+
+static float get_avg_surrounds(float *cache, int *res, int xx, int yy, int zz)
+{
+ int x, y, z, x_, y_, z_;
+ int added=0;
+ float tot=0.0f;
+
+ for (z=-1; z <= 1; z++) {
+ z_ = zz+z;
+ if (z_ >= 0 && z_ <= res[2]-1) {
+
+ for (y=-1; y <= 1; y++) {
+ y_ = yy+y;
+ if (y_ >= 0 && y_ <= res[1]-1) {
+
+ for (x=-1; x <= 1; x++) {
+ x_ = xx+x;
+ if (x_ >= 0 && x_ <= res[0]-1) {
+ const int64_t i = BLI_VOXEL_INDEX(x_, y_, z_, res);
+
+ if (cache[i] > 0.0f) {
+ tot += cache[i];
+ added++;
+ }
+
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if (added > 0) tot /= added;
+
+ return tot;
+}
+
+/* function to filter the edges of the light cache, where there was no volume originally.
+ * For each voxel which was originally external to the mesh, it finds the average values of
+ * the surrounding internal voxels and sets the original external voxel to that average amount.
+ * Works almost a bit like a 'dilate' filter */
+static void lightcache_filter(VolumePrecache *vp)
+{
+ int x, y, z;
+
+ for (z=0; z < vp->res[2]; z++) {
+ for (y=0; y < vp->res[1]; y++) {
+ for (x=0; x < vp->res[0]; x++) {
+ /* trigger for outside mesh */
+ const int64_t i = BLI_VOXEL_INDEX(x, y, z, vp->res);
+
+ if (vp->data_r[i] < -0.f)
+ vp->data_r[i] = get_avg_surrounds(vp->data_r, vp->res, x, y, z);
+ if (vp->data_g[i] < -0.f)
+ vp->data_g[i] = get_avg_surrounds(vp->data_g, vp->res, x, y, z);
+ if (vp->data_b[i] < -0.f)
+ vp->data_b[i] = get_avg_surrounds(vp->data_b, vp->res, x, y, z);
+ }
+ }
+ }
+}
+
+#if 0
+static void lightcache_filter2(VolumePrecache *vp)
+{
+ int x, y, z;
+ float *new_r, *new_g, *new_b;
+ int field_size = vp->res[0]*vp->res[1]*vp->res[2]*sizeof(float);
+
+ new_r = MEM_mallocN(field_size, "temp buffer for light cache filter r channel");
+ new_g = MEM_mallocN(field_size, "temp buffer for light cache filter g channel");
+ new_b = MEM_mallocN(field_size, "temp buffer for light cache filter b channel");
+
+ memcpy(new_r, vp->data_r, field_size);
+ memcpy(new_g, vp->data_g, field_size);
+ memcpy(new_b, vp->data_b, field_size);
+
+ for (z=0; z < vp->res[2]; z++) {
+ for (y=0; y < vp->res[1]; y++) {
+ for (x=0; x < vp->res[0]; x++) {
+ /* trigger for outside mesh */
+ const int64_t i = BLI_VOXEL_INDEX(x, y, z, vp->res);
+ if (vp->data_r[i] < -0.f)
+ new_r[i] = get_avg_surrounds(vp->data_r, vp->res, x, y, z);
+ if (vp->data_g[i] < -0.f)
+ new_g[i] = get_avg_surrounds(vp->data_g, vp->res, x, y, z);
+ if (vp->data_b[i] < -0.f)
+ new_b[i] = get_avg_surrounds(vp->data_b, vp->res, x, y, z);
+ }
+ }
+ }
+
+ SWAP(float *, vp->data_r, new_r);
+ SWAP(float *, vp->data_g, new_g);
+ SWAP(float *, vp->data_b, new_b);
+
+ if (new_r) { MEM_freeN(new_r); new_r=NULL; }
+ if (new_g) { MEM_freeN(new_g); new_g=NULL; }
+ if (new_b) { MEM_freeN(new_b); new_b=NULL; }
+}
+#endif
+
+/* has a pad of 1 voxel surrounding the core for boundary simulation */
+BLI_INLINE int64_t ms_I(int x, int y, int z, const int *n)
+{
+ /* different ordering to light cache */
+ return ((int64_t)x * (int64_t)(n[1] + 2) * (int64_t)(n[2] + 2) +
+ (int64_t)y * (int64_t)(n[2] + 2) +
+ (int64_t)z);
+}
+
+/* has a pad of 1 voxel surrounding the core for boundary simulation */
+BLI_INLINE int64_t v_I_pad(int x, int y, int z, const int *n)
+{
+ /* same ordering to light cache, with padding */
+ return ((int64_t)z * (int64_t)(n[1] + 2) * (int64_t)(n[0] + 2) +
+ (int64_t)y * (int64_t)(n[0] + 2) +
+ (int64_t)x);
+}
+
+BLI_INLINE int64_t lc_to_ms_I(int x, int y, int z, const int *n)
+{
+ /* converting light cache index to multiple scattering index */
+ return ((int64_t)(x - 1) * ((int64_t)n[1] * (int64_t)n[2]) +
+ (int64_t)(y - 1) * ((int64_t)n[2]) +
+ (int64_t)(z - 1));
+}
+
+/* *** multiple scattering approximation *** */
+
+/* get the total amount of light energy in the light cache. used to normalize after multiple scattering */
+static float total_ss_energy(Render *re, int do_test_break, VolumePrecache *vp)
+{
+ int x, y, z;
+ const int *res = vp->res;
+ float energy=0.f;
+
+ for (z=0; z < res[2]; z++) {
+ for (y=0; y < res[1]; y++) {
+ for (x=0; x < res[0]; x++) {
+ const int64_t i = BLI_VOXEL_INDEX(x, y, z, res);
+
+ if (vp->data_r[i] > 0.f) energy += vp->data_r[i];
+ if (vp->data_g[i] > 0.f) energy += vp->data_g[i];
+ if (vp->data_b[i] > 0.f) energy += vp->data_b[i];
+ }
+ }
+
+ if (do_test_break && re->test_break(re->tbh)) break;
+ }
+
+ return energy;
+}
+
+static float total_ms_energy(Render *re, int do_test_break, float *sr, float *sg, float *sb, const int res[3])
+{
+ int x, y, z;
+ float energy=0.f;
+
+ for (z=1;z<=res[2];z++) {
+ for (y=1;y<=res[1];y++) {
+ for (x=1;x<=res[0];x++) {
+ const int64_t i = ms_I(x, y, z, res);
+
+ if (sr[i] > 0.f) energy += sr[i];
+ if (sg[i] > 0.f) energy += sg[i];
+ if (sb[i] > 0.f) energy += sb[i];
+ }
+ }
+
+ if (do_test_break && re->test_break(re->tbh)) break;
+ }
+
+ return energy;
+}
+
+/**
+ * \param n: the unpadded resolution
+ */
+static void ms_diffuse(Render *re, int do_test_break, const float *x0, float *x, float diff, const int n[3])
+{
+ int i, j, k, l;
+ const float dt = VOL_MS_TIMESTEP;
+ int64_t size = (int64_t)n[0] * (int64_t)n[1] * (int64_t)n[2];
+ const float a = dt * diff * size;
+
+ for (l=0; l<20; l++) {
+ for (k=1; k<=n[2]; k++) {
+ for (j=1; j<=n[1]; j++) {
+ for (i=1; i<=n[0]; i++) {
+ x[v_I_pad(i, j, k, n)] =
+ ((x0[v_I_pad(i, j, k, n)]) + (
+ (x0[v_I_pad(i - 1, j, k, n)] +
+ x0[v_I_pad(i + 1, j, k, n)] +
+ x0[v_I_pad(i, j - 1, k, n)] +
+ x0[v_I_pad(i, j + 1, k, n)] +
+ x0[v_I_pad(i, j, k - 1, n)] +
+ x0[v_I_pad(i, j, k + 1, n)]) * a) / (1 + 6 * a));
+ }
+ }
+
+ if (do_test_break && re->test_break(re->tbh)) break;
+ }
+
+ if (re->test_break(re->tbh)) break;
+ }
+}
+
+static void multiple_scattering_diffusion(Render *re, VolumePrecache *vp, Material *ma)
+{
+ const float diff = ma->vol.ms_diff * 0.001f; /* compensate for scaling for a nicer UI range */
+ const int simframes = (int)(ma->vol.ms_spread * (float)max_iii(vp->res[0], vp->res[1], vp->res[2]));
+ const int shade_type = ma->vol.shade_type;
+ float fac = ma->vol.ms_intensity;
+
+ int x, y, z, m;
+ const int *n = vp->res;
+ const int size = (n[0]+2)*(n[1]+2)*(n[2]+2);
+ const int do_test_break = (size > 100000);
+ double time, lasttime= PIL_check_seconds_timer();
+ float total;
+ float c=1.0f;
+ float origf; /* factor for blending in original light cache */
+ float energy_ss, energy_ms;
+
+ float *sr0=(float *)MEM_callocN(size*sizeof(float), "temporary multiple scattering buffer");
+ float *sr=(float *)MEM_callocN(size*sizeof(float), "temporary multiple scattering buffer");
+ float *sg0=(float *)MEM_callocN(size*sizeof(float), "temporary multiple scattering buffer");
+ float *sg=(float *)MEM_callocN(size*sizeof(float), "temporary multiple scattering buffer");
+ float *sb0=(float *)MEM_callocN(size*sizeof(float), "temporary multiple scattering buffer");
+ float *sb=(float *)MEM_callocN(size*sizeof(float), "temporary multiple scattering buffer");
+
+ total = (float)(n[0]*n[1]*n[2]*simframes);
+
+ energy_ss = total_ss_energy(re, do_test_break, vp);
+
+ /* Scattering as diffusion pass */
+ for (m=0; m<simframes; m++) {
+ /* add sources */
+ for (z=1; z<=n[2]; z++) {
+ for (y=1; y<=n[1]; y++) {
+ for (x=1; x<=n[0]; x++) {
+ const int64_t i = lc_to_ms_I(x, y, z, n); //lc index
+ const int64_t j = ms_I(x, y, z, n); //ms index
+
+ time= PIL_check_seconds_timer();
+ c++;
+ if (vp->data_r[i] > 0.0f)
+ sr[j] += vp->data_r[i];
+ if (vp->data_g[i] > 0.0f)
+ sg[j] += vp->data_g[i];
+ if (vp->data_b[i] > 0.0f)
+ sb[j] += vp->data_b[i];
+
+ /* Displays progress every second */
+ if (time-lasttime>1.0) {
+ char str[64];
+ BLI_snprintf(str, sizeof(str), IFACE_("Simulating multiple scattering: %d%%"),
+ (int)(100.0f * (c / total)));
+ re->i.infostr = str;
+ re->stats_draw(re->sdh, &re->i);
+ re->i.infostr = NULL;
+ lasttime= time;
+ }
+ }
+ }
+
+ if (do_test_break && re->test_break(re->tbh)) break;
+ }
+
+ if (re->test_break(re->tbh)) break;
+
+ SWAP(float *, sr, sr0);
+ SWAP(float *, sg, sg0);
+ SWAP(float *, sb, sb0);
+
+ /* main diffusion simulation */
+ ms_diffuse(re, do_test_break, sr0, sr, diff, n);
+ ms_diffuse(re, do_test_break, sg0, sg, diff, n);
+ ms_diffuse(re, do_test_break, sb0, sb, diff, n);
+
+ if (re->test_break(re->tbh)) break;
+ }
+
+ /* normalization factor to conserve energy */
+ energy_ms = total_ms_energy(re, do_test_break, sr, sg, sb, n);
+ fac *= (energy_ss / energy_ms);
+
+ /* blend multiple scattering back in the light cache */
+ if (shade_type == MA_VOL_SHADE_SHADEDPLUSMULTIPLE) {
+ /* conserve energy - half single, half multiple */
+ origf = 0.5f;
+ fac *= 0.5f;
+ }
+ else {
+ origf = 0.0f;
+ }
+
+ for (z=1;z<=n[2];z++) {
+ for (y=1;y<=n[1];y++) {
+ for (x=1;x<=n[0];x++) {
+ const int64_t i = lc_to_ms_I(x, y, z, n); //lc index
+ const int64_t j = ms_I(x, y, z, n); //ms index
+
+ vp->data_r[i] = origf * vp->data_r[i] + fac * sr[j];
+ vp->data_g[i] = origf * vp->data_g[i] + fac * sg[j];
+ vp->data_b[i] = origf * vp->data_b[i] + fac * sb[j];
+ }
+ }
+
+ if (do_test_break && re->test_break(re->tbh)) break;
+ }
+
+ MEM_freeN(sr0);
+ MEM_freeN(sr);
+ MEM_freeN(sg0);
+ MEM_freeN(sg);
+ MEM_freeN(sb0);
+ MEM_freeN(sb);
+}
+
+
+
+#if 0 /* debug stuff */
+static void *vol_precache_part_test(void *data)
+{
+ VolPrecachePart *pa = data;
+
+ printf("part number: %d\n", pa->num);
+ printf("done: %d\n", pa->done);
+ printf("x min: %d x max: %d\n", pa->minx, pa->maxx);
+ printf("y min: %d y max: %d\n", pa->miny, pa->maxy);
+ printf("z min: %d z max: %d\n", pa->minz, pa->maxz);
+
+ return NULL;
+}
+#endif
+
+/* Iterate over the 3d voxel grid, and fill the voxels with scattering information
+ *
+ * It's stored in memory as 3 big float grids next to each other, one for each RGB channel.
+ * I'm guessing the memory alignment may work out better this way for the purposes
+ * of doing linear interpolation, but I haven't actually tested this theory! :)
+ */
+typedef struct VolPrecacheState {
+ double lasttime;
+ unsigned int doneparts;
+ unsigned int totparts;
+} VolPrecacheState;
+
+static void vol_precache_part(TaskPool * __restrict pool, void *taskdata, int UNUSED(threadid))
+{
+ VolPrecacheState *state = (VolPrecacheState *)BLI_task_pool_userdata(pool);
+ VolPrecachePart *pa = (VolPrecachePart *)taskdata;
+ Render *re = pa->re;
+
+ ObjectInstanceRen *obi = pa->obi;
+ RayObject *tree = pa->tree;
+ ShadeInput *shi = pa->shi;
+ float scatter_col[3] = {0.f, 0.f, 0.f};
+ float co[3], cco[3], view[3];
+ int x, y, z;
+ int res[3];
+ double time;
+
+ if (re->test_break && re->test_break(re->tbh))
+ return;
+
+ //printf("thread id %d\n", threadid);
+
+ res[0]= pa->res[0];
+ res[1]= pa->res[1];
+ res[2]= pa->res[2];
+
+ for (z= pa->minz; z < pa->maxz; z++) {
+ co[2] = pa->bbmin[2] + (pa->voxel[2] * (z + 0.5f));
+
+ for (y= pa->miny; y < pa->maxy; y++) {
+ co[1] = pa->bbmin[1] + (pa->voxel[1] * (y + 0.5f));
+
+ for (x=pa->minx; x < pa->maxx; x++) {
+ int64_t i;
+ co[0] = pa->bbmin[0] + (pa->voxel[0] * (x + 0.5f));
+
+ if (re->test_break && re->test_break(re->tbh))
+ break;
+
+ /* convert from world->camera space for shading */
+ mul_v3_m4v3(cco, pa->viewmat, co);
+
+ i = BLI_VOXEL_INDEX(x, y, z, res);
+
+ /* don't bother if the point is not inside the volume mesh */
+ if (!point_inside_obi(tree, obi, cco)) {
+ obi->volume_precache->data_r[i] = -1.0f;
+ obi->volume_precache->data_g[i] = -1.0f;
+ obi->volume_precache->data_b[i] = -1.0f;
+ continue;
+ }
+
+ copy_v3_v3(view, cco);
+ normalize_v3(view);
+ vol_get_scattering(shi, scatter_col, cco, view);
+
+ obi->volume_precache->data_r[i] = scatter_col[0];
+ obi->volume_precache->data_g[i] = scatter_col[1];
+ obi->volume_precache->data_b[i] = scatter_col[2];
+
+ }
+ }
+ }
+
+ unsigned int doneparts = atomic_add_and_fetch_u(&state->doneparts, 1);
+
+ time = PIL_check_seconds_timer();
+ if (time - state->lasttime > 1.0) {
+ ThreadMutex *mutex = BLI_task_pool_user_mutex(pool);
+
+ if (BLI_mutex_trylock(mutex)) {
+ char str[64];
+ float ratio = (float)doneparts/(float)state->totparts;
+ BLI_snprintf(str, sizeof(str), IFACE_("Precaching volume: %d%%"), (int)(100.0f * ratio));
+ re->i.infostr = str;
+ re->stats_draw(re->sdh, &re->i);
+ re->i.infostr = NULL;
+ state->lasttime = time;
+
+ BLI_mutex_unlock(mutex);
+ }
+ }
+}
+
+static void precache_setup_shadeinput(Render *re, ObjectInstanceRen *obi, Material *ma, ShadeInput *shi)
+{
+ memset(shi, 0, sizeof(ShadeInput));
+ shi->depth= 1;
+ shi->mask= 1;
+ shi->mat = ma;
+ shi->vlr = NULL;
+ memcpy(&shi->r, &shi->mat->r, 23*sizeof(float)); /* note, keep this synced with render_types.h */
+ shi->har= shi->mat->har;
+ shi->obi= obi;
+ shi->obr= obi->obr;
+ shi->lay = re->lay;
+}
+
+static void precache_launch_parts(Render *re, RayObject *tree, ShadeInput *shi, ObjectInstanceRen *obi)
+{
+ TaskScheduler *task_scheduler;
+ TaskPool *task_pool;
+ VolumePrecache *vp = obi->volume_precache;
+ VolPrecacheState state;
+ int i=0, x, y, z;
+ float voxel[3];
+ int sizex, sizey, sizez;
+ float bbmin[3], bbmax[3];
+ const int *res;
+ int minx, maxx;
+ int miny, maxy;
+ int minz, maxz;
+ int totthread = re->r.threads;
+ int parts[3];
+
+ if (!vp) return;
+
+ /* currently we just subdivide the box, number of threads per side */
+ parts[0] = parts[1] = parts[2] = totthread;
+ res = vp->res;
+
+ /* setup task scheduler */
+ memset(&state, 0, sizeof(state));
+ state.doneparts = 0;
+ state.totparts = parts[0]*parts[1]*parts[2];
+ state.lasttime = PIL_check_seconds_timer();
+
+ task_scheduler = BLI_task_scheduler_create(totthread);
+ task_pool = BLI_task_pool_create(task_scheduler, &state);
+
+ /* using boundbox in worldspace */
+ global_bounds_obi(re, obi, bbmin, bbmax);
+ sub_v3_v3v3(voxel, bbmax, bbmin);
+
+ voxel[0] /= (float)res[0];
+ voxel[1] /= (float)res[1];
+ voxel[2] /= (float)res[2];
+
+ for (x=0; x < parts[0]; x++) {
+ sizex = ceil(res[0] / (float)parts[0]);
+ minx = x * sizex;
+ maxx = minx + sizex;
+ maxx = (maxx>res[0])?res[0]:maxx;
+
+ for (y=0; y < parts[1]; y++) {
+ sizey = ceil(res[1] / (float)parts[1]);
+ miny = y * sizey;
+ maxy = miny + sizey;
+ maxy = (maxy>res[1])?res[1]:maxy;
+
+ for (z=0; z < parts[2]; z++) {
+ VolPrecachePart *pa= MEM_callocN(sizeof(VolPrecachePart), "new precache part");
+
+ sizez = ceil(res[2] / (float)parts[2]);
+ minz = z * sizez;
+ maxz = minz + sizez;
+ maxz = (maxz>res[2])?res[2]:maxz;
+
+ pa->re = re;
+ pa->num = i;
+ pa->tree = tree;
+ pa->shi = shi;
+ pa->obi = obi;
+ copy_m4_m4(pa->viewmat, re->viewmat);
+
+ copy_v3_v3(pa->bbmin, bbmin);
+ copy_v3_v3(pa->voxel, voxel);
+ copy_v3_v3_int(pa->res, res);
+
+ pa->minx = minx; pa->maxx = maxx;
+ pa->miny = miny; pa->maxy = maxy;
+ pa->minz = minz; pa->maxz = maxz;
+
+ BLI_task_pool_push(task_pool, vol_precache_part, pa, true, TASK_PRIORITY_HIGH);
+
+ i++;
+ }
+ }
+ }
+
+ /* work and wait until tasks are done */
+ BLI_task_pool_work_and_wait(task_pool);
+
+ /* free */
+ BLI_task_pool_free(task_pool);
+ BLI_task_scheduler_free(task_scheduler);
+}
+
+/* calculate resolution from bounding box in world space */
+static int precache_resolution(Render *re, VolumePrecache *vp, ObjectInstanceRen *obi, int res)
+{
+ float dim[3], div;
+ float bbmin[3], bbmax[3];
+
+ /* bound box in global space */
+ global_bounds_obi(re, obi, bbmin, bbmax);
+ sub_v3_v3v3(dim, bbmax, bbmin);
+
+ div = max_fff(dim[0], dim[1], dim[2]);
+ dim[0] /= div;
+ dim[1] /= div;
+ dim[2] /= div;
+
+ vp->res[0] = ceil(dim[0] * res);
+ vp->res[1] = ceil(dim[1] * res);
+ vp->res[2] = ceil(dim[2] * res);
+
+ if ((vp->res[0] < 1) || (vp->res[1] < 1) || (vp->res[2] < 1))
+ return 0;
+
+ return 1;
+}
+
+/* Precache a volume into a 3D voxel grid.
+ * The voxel grid is stored in the ObjectInstanceRen,
+ * in camera space, aligned with the ObjectRen's bounding box.
+ * Resolution is defined by the user.
+ */
+static void vol_precache_objectinstance_threads(Render *re, ObjectInstanceRen *obi, Material *ma)
+{
+ VolumePrecache *vp;
+ RayObject *tree;
+ ShadeInput shi;
+
+ R = *re;
+
+ /* create a raytree with just the faces of the instanced ObjectRen,
+ * used for checking if the cached point is inside or outside. */
+ tree = makeraytree_object(&R, obi);
+ if (!tree) return;
+
+ vp = MEM_callocN(sizeof(VolumePrecache), "volume light cache");
+ obi->volume_precache = vp;
+
+ if (!precache_resolution(re, vp, obi, ma->vol.precache_resolution)) {
+ MEM_freeN(vp);
+ vp = NULL;
+ return;
+ }
+
+ vp->data_r = MEM_callocN(sizeof(float)*vp->res[0]*vp->res[1]*vp->res[2], "volume light cache data red channel");
+ vp->data_g = MEM_callocN(sizeof(float)*vp->res[0]*vp->res[1]*vp->res[2], "volume light cache data green channel");
+ vp->data_b = MEM_callocN(sizeof(float)*vp->res[0]*vp->res[1]*vp->res[2], "volume light cache data blue channel");
+ if (vp->data_r==NULL || vp->data_g==NULL || vp->data_b==NULL) {
+ MEM_freeN(vp);
+ return;
+ }
+
+ /* Need a shadeinput to calculate scattering */
+ precache_setup_shadeinput(re, obi, ma, &shi);
+
+ precache_launch_parts(re, tree, &shi, obi);
+
+ if (tree) {
+ /* TODO: makeraytree_object creates a tree and saves it on OBI,
+ * if we free this tree we should also clear other pointers to it */
+ //RE_rayobject_free(tree);
+ //tree= NULL;
+ }
+
+ if (ELEM(ma->vol.shade_type, MA_VOL_SHADE_MULTIPLE, MA_VOL_SHADE_SHADEDPLUSMULTIPLE)) {
+ /* this should be before the filtering */
+ multiple_scattering_diffusion(re, obi->volume_precache, ma);
+ }
+
+ lightcache_filter(obi->volume_precache);
+}
+
+static int using_lightcache(Material *ma)
+{
+ return (((ma->vol.shadeflag & MA_VOL_PRECACHESHADING) && (ma->vol.shade_type == MA_VOL_SHADE_SHADED)) ||
+ (ELEM(ma->vol.shade_type, MA_VOL_SHADE_MULTIPLE, MA_VOL_SHADE_SHADEDPLUSMULTIPLE)));
+}
+
+/* loop through all objects (and their associated materials)
+ * marked for pre-caching in convertblender.c, and pre-cache them */
+void volume_precache(Render *re)
+{
+ ObjectInstanceRen *obi;
+ VolumeOb *vo;
+
+ re->i.infostr = IFACE_("Volume preprocessing");
+ re->stats_draw(re->sdh, &re->i);
+
+ for (vo= re->volumes.first; vo; vo= vo->next) {
+ if (using_lightcache(vo->ma)) {
+ for (obi= re->instancetable.first; obi; obi= obi->next) {
+ if (obi->obr == vo->obr) {
+ vol_precache_objectinstance_threads(re, obi, vo->ma);
+
+ if (re->test_break && re->test_break(re->tbh))
+ break;
+ }
+ }
+
+ if (re->test_break && re->test_break(re->tbh))
+ break;
+ }
+ }
+
+ re->i.infostr = NULL;
+ re->stats_draw(re->sdh, &re->i);
+}
+
+void free_volume_precache(Render *re)
+{
+ ObjectInstanceRen *obi;
+
+ for (obi= re->instancetable.first; obi; obi= obi->next) {
+ if (obi->volume_precache != NULL) {
+ MEM_freeN(obi->volume_precache->data_r);
+ MEM_freeN(obi->volume_precache->data_g);
+ MEM_freeN(obi->volume_precache->data_b);
+ MEM_freeN(obi->volume_precache->bbmin);
+ MEM_freeN(obi->volume_precache->bbmax);
+ MEM_freeN(obi->volume_precache);
+ obi->volume_precache = NULL;
+ }
+ }
+
+ BLI_freelistN(&re->volumes);
+}
+
+int point_inside_volume_objectinstance(Render *re, ObjectInstanceRen *obi, const float co[3])
+{
+ RayObject *tree;
+ int inside=0;
+
+ tree = makeraytree_object(re, obi);
+ if (!tree) return 0;
+
+ inside = point_inside_obi(tree, obi, co);
+
+ //TODO: makeraytree_object creates a tree and saves it on OBI, if we free this tree we should also clear other pointers to it
+ //RE_rayobject_free(tree);
+ //tree= NULL;
+
+ return inside;
+}
+
diff --git a/source/blender/render/intern/source/volumetric.c b/source/blender/render/intern/source/volumetric.c
new file mode 100644
index 00000000000..583353ed8cf
--- /dev/null
+++ b/source/blender/render/intern/source/volumetric.c
@@ -0,0 +1,836 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): Matt Ebb, Raul Fernandez Hernandez (Farsthary)
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/render/intern/source/volumetric.c
+ * \ingroup render
+ */
+
+#include <math.h>
+#include <stdlib.h>
+#include <string.h>
+#include <float.h>
+
+#include "BLI_math.h"
+#include "BLI_rand.h"
+#include "BLI_voxel.h"
+#include "BLI_utildefines.h"
+
+#include "RE_shader_ext.h"
+
+#include "IMB_colormanagement.h"
+
+#include "DNA_material_types.h"
+#include "DNA_group_types.h"
+#include "DNA_lamp_types.h"
+#include "DNA_meta_types.h"
+
+
+#include "render_types.h"
+#include "pixelshading.h"
+#include "rayintersection.h"
+#include "rayobject.h"
+#include "renderdatabase.h"
+#include "shading.h"
+#include "shadbuf.h"
+#include "texture.h"
+#include "volumetric.h"
+#include "volume_precache.h"
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+/* defined in pipeline.c, is hardcopy of active dynamic allocated Render */
+/* only to be used here in this file, it's for speed */
+extern struct Render R;
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+/* tracing */
+static float vol_get_shadow(ShadeInput *shi, LampRen *lar, const float co[3])
+{
+ float visibility = 1.f;
+
+ if (lar->shb) {
+ float dxco[3] = {0.f, 0.f, 0.f}, dyco[3] = {0.f, 0.f, 0.f};
+
+ visibility = testshadowbuf(&R, lar->shb, co, dxco, dyco, 1.0, 0.0);
+ }
+ else if (lar->mode & LA_SHAD_RAY) {
+ /* trace shadow manually, no good lamp api atm */
+ Isect is;
+
+ copy_v3_v3(is.start, co);
+ if (lar->type == LA_SUN || lar->type == LA_HEMI) {
+ is.dir[0] = -lar->vec[0];
+ is.dir[1] = -lar->vec[1];
+ is.dir[2] = -lar->vec[2];
+ is.dist = R.maxdist;
+ }
+ else {
+ sub_v3_v3v3(is.dir, lar->co, is.start);
+ is.dist = normalize_v3(is.dir);
+ }
+
+ is.mode = RE_RAY_MIRROR;
+ is.check = RE_CHECK_VLR_NON_SOLID_MATERIAL;
+ is.skip = 0;
+
+ if (lar->mode & (LA_LAYER | LA_LAYER_SHADOW))
+ is.lay = lar->lay;
+ else
+ is.lay = -1;
+
+ is.orig.ob = NULL;
+ is.orig.face = NULL;
+ is.last_hit = lar->last_hit[shi->thread];
+
+ RE_instance_rotate_ray(shi->obi, &is);
+
+ if (RE_rayobject_raycast(R.raytree, &is)) {
+ RE_instance_rotate_ray_restore(shi->obi, &is);
+
+ visibility = 0.f;
+ }
+
+ lar->last_hit[shi->thread] = is.last_hit;
+ }
+ return visibility;
+}
+
+static int vol_get_bounds(ShadeInput *shi, const float co[3], const float vec[3], float hitco[3], Isect *isect, int intersect_type)
+{
+
+ copy_v3_v3(isect->start, co);
+ copy_v3_v3(isect->dir, vec);
+ isect->dist = FLT_MAX;
+ isect->mode = RE_RAY_MIRROR;
+ isect->last_hit = NULL;
+ isect->lay = -1;
+ isect->check = RE_CHECK_VLR_NONE;
+
+ if (intersect_type == VOL_BOUNDS_DEPTH) {
+ isect->skip = RE_SKIP_VLR_NEIGHBOUR;
+ isect->orig.face = (void *)shi->vlr;
+ isect->orig.ob = (void *)shi->obi;
+ }
+ else { // if (intersect_type == VOL_BOUNDS_SS) {
+ isect->skip = 0;
+ isect->orig.face = NULL;
+ isect->orig.ob = NULL;
+ }
+
+ RE_instance_rotate_ray(shi->obi, isect);
+
+ if (RE_rayobject_raycast(R.raytree, isect)) {
+ RE_instance_rotate_ray_restore(shi->obi, isect);
+
+ hitco[0] = isect->start[0] + isect->dist * isect->dir[0];
+ hitco[1] = isect->start[1] + isect->dist * isect->dir[1];
+ hitco[2] = isect->start[2] + isect->dist * isect->dir[2];
+ return 1;
+ }
+ else {
+ return 0;
+ }
+}
+
+static void shade_intersection(ShadeInput *shi, float col_r[4], Isect *is)
+{
+ ShadeInput shi_new;
+ ShadeResult shr_new;
+
+ memset(&shi_new, 0, sizeof(ShadeInput));
+
+ shi_new.mask = shi->mask;
+ shi_new.osatex = shi->osatex;
+ shi_new.thread = shi->thread;
+ shi_new.depth = shi->depth + 1;
+ shi_new.volume_depth = shi->volume_depth + 1;
+ shi_new.xs = shi->xs;
+ shi_new.ys = shi->ys;
+ shi_new.lay = shi->lay;
+ shi_new.passflag = SCE_PASS_COMBINED; /* result of tracing needs no pass info */
+ shi_new.combinedflag = 0xFFFFFF; /* ray trace does all options */
+ shi_new.light_override = shi->light_override;
+ shi_new.mat_override = shi->mat_override;
+
+ copy_v3_v3(shi_new.camera_co, is->start);
+
+ memset(&shr_new, 0, sizeof(ShadeResult));
+
+ /* hardcoded limit of 100 for now - prevents problems in weird geometry */
+ if (shi->volume_depth < 100) {
+ shade_ray(is, &shi_new, &shr_new);
+ }
+
+ copy_v3_v3(col_r, shr_new.combined);
+ col_r[3] = shr_new.alpha;
+}
+
+static void vol_trace_behind(ShadeInput *shi, VlakRen *vlr, const float co[3], float col_r[4])
+{
+ Isect isect;
+
+ copy_v3_v3(isect.start, co);
+ copy_v3_v3(isect.dir, shi->view);
+ isect.dist = FLT_MAX;
+
+ isect.mode = RE_RAY_MIRROR;
+ isect.check = RE_CHECK_VLR_NONE;
+ isect.skip = RE_SKIP_VLR_NEIGHBOUR;
+ isect.orig.ob = (void *) shi->obi;
+ isect.orig.face = (void *)vlr;
+ isect.last_hit = NULL;
+ isect.lay = -1;
+
+ /* check to see if there's anything behind the volume, otherwise shade the sky */
+ RE_instance_rotate_ray(shi->obi, &isect);
+
+ if (RE_rayobject_raycast(R.raytree, &isect)) {
+ RE_instance_rotate_ray_restore(shi->obi, &isect);
+
+ shade_intersection(shi, col_r, &isect);
+ }
+ else {
+ shadeSkyView(col_r, co, shi->view, NULL, shi->thread);
+ shadeSunView(col_r, shi->view);
+ }
+}
+
+
+/* trilinear interpolation */
+static void vol_get_precached_scattering(Render *re, ShadeInput *shi, float scatter_col[3], const float co[3])
+{
+ VolumePrecache *vp = shi->obi->volume_precache;
+ float bbmin[3], bbmax[3], dim[3];
+ float world_co[3], sample_co[3];
+
+ if (!vp) return;
+
+ /* find sample point in global space bounding box 0.0-1.0 */
+ global_bounds_obi(re, shi->obi, bbmin, bbmax);
+ sub_v3_v3v3(dim, bbmax, bbmin);
+ mul_v3_m4v3(world_co, re->viewinv, co);
+
+ /* sample_co in 0.0-1.0 */
+ sample_co[0] = (world_co[0] - bbmin[0]) / dim[0];
+ sample_co[1] = (world_co[1] - bbmin[1]) / dim[1];
+ sample_co[2] = (world_co[2] - bbmin[2]) / dim[2];
+
+ scatter_col[0] = BLI_voxel_sample_triquadratic(vp->data_r, vp->res, sample_co);
+ scatter_col[1] = BLI_voxel_sample_triquadratic(vp->data_g, vp->res, sample_co);
+ scatter_col[2] = BLI_voxel_sample_triquadratic(vp->data_b, vp->res, sample_co);
+}
+
+/* Meta object density, brute force for now
+ * (might be good enough anyway, don't need huge number of metaobs to model volumetric objects */
+static float metadensity(Object *ob, const float co[3])
+{
+ float mat[4][4], imat[4][4], dens = 0.f;
+ MetaBall *mb = (MetaBall *)ob->data;
+ MetaElem *ml;
+
+ /* transform co to meta-element */
+ float tco[3] = {co[0], co[1], co[2]};
+ mul_m4_m4m4(mat, R.viewmat, ob->obmat);
+ invert_m4_m4(imat, mat);
+ mul_m4_v3(imat, tco);
+
+ for (ml = mb->elems.first; ml; ml = ml->next) {
+ float bmat[3][3], dist2;
+
+ /* element rotation transform */
+ float tp[3] = {ml->x - tco[0], ml->y - tco[1], ml->z - tco[2]};
+ quat_to_mat3(bmat, ml->quat);
+ transpose_m3(bmat); /* rot.only, so inverse == transpose */
+ mul_m3_v3(bmat, tp);
+
+ /* MB_BALL default */
+ switch (ml->type) {
+ case MB_ELIPSOID:
+ tp[0] /= ml->expx;
+ tp[1] /= ml->expy;
+ tp[2] /= ml->expz;
+ break;
+ case MB_CUBE:
+ tp[2] = (tp[2] > ml->expz) ? (tp[2] - ml->expz) : ((tp[2] < -ml->expz) ? (tp[2] + ml->expz) : 0.f);
+ /* no break, xy as plane */
+ ATTR_FALLTHROUGH;
+ case MB_PLANE:
+ tp[1] = (tp[1] > ml->expy) ? (tp[1] - ml->expy) : ((tp[1] < -ml->expy) ? (tp[1] + ml->expy) : 0.f);
+ /* no break, x as tube */
+ ATTR_FALLTHROUGH;
+ case MB_TUBE:
+ tp[0] = (tp[0] > ml->expx) ? (tp[0] - ml->expx) : ((tp[0] < -ml->expx) ? (tp[0] + ml->expx) : 0.f);
+ }
+
+ /* ml->rad2 is not set */
+ dist2 = 1.0f - (dot_v3v3(tp, tp) / (ml->rad * ml->rad));
+ if (dist2 > 0.f)
+ dens += (ml->flag & MB_NEGATIVE) ? -ml->s * dist2 * dist2 * dist2 : ml->s * dist2 * dist2 * dist2;
+ }
+
+ dens -= mb->thresh;
+ return (dens < 0.f) ? 0.f : dens;
+}
+
+float vol_get_density(struct ShadeInput *shi, const float co[3])
+{
+ float density = shi->mat->vol.density;
+ float density_scale = shi->mat->vol.density_scale;
+
+ if (shi->mat->mapto_textured & MAP_DENSITY)
+ do_volume_tex(shi, co, MAP_DENSITY, NULL, &density, &R);
+
+ /* if meta-object, modulate by metadensity without increasing it */
+ if (shi->obi->obr->ob->type == OB_MBALL) {
+ const float md = metadensity(shi->obi->obr->ob, co);
+ if (md < 1.f) density *= md;
+ }
+
+ return density * density_scale;
+}
+
+
+/* Color of light that gets scattered out by the volume */
+/* Uses same physically based scattering parameter as in transmission calculations,
+ * along with artificial reflection scale/reflection color tint */
+static void vol_get_reflection_color(ShadeInput *shi, float ref_col[3], const float co[3])
+{
+ float scatter = shi->mat->vol.scattering;
+ float reflection = shi->mat->vol.reflection;
+ copy_v3_v3(ref_col, shi->mat->vol.reflection_col);
+
+ if (shi->mat->mapto_textured & (MAP_SCATTERING + MAP_REFLECTION_COL))
+ do_volume_tex(shi, co, MAP_SCATTERING + MAP_REFLECTION_COL, ref_col, &scatter, &R);
+
+ /* only one single float parameter at a time... :s */
+ if (shi->mat->mapto_textured & (MAP_REFLECTION))
+ do_volume_tex(shi, co, MAP_REFLECTION, NULL, &reflection, &R);
+
+ ref_col[0] = reflection * ref_col[0] * scatter;
+ ref_col[1] = reflection * ref_col[1] * scatter;
+ ref_col[2] = reflection * ref_col[2] * scatter;
+}
+
+/* compute emission component, amount of radiance to add per segment
+ * can be textured with 'emit' */
+static void vol_get_emission(ShadeInput *shi, float emission_col[3], const float co[3])
+{
+ float emission = shi->mat->vol.emission;
+ copy_v3_v3(emission_col, shi->mat->vol.emission_col);
+
+ if (shi->mat->mapto_textured & (MAP_EMISSION + MAP_EMISSION_COL))
+ do_volume_tex(shi, co, MAP_EMISSION + MAP_EMISSION_COL, emission_col, &emission, &R);
+
+ emission_col[0] = emission_col[0] * emission;
+ emission_col[1] = emission_col[1] * emission;
+ emission_col[2] = emission_col[2] * emission;
+}
+
+
+/* A combination of scattering and absorption -> known as sigma T.
+ * This can possibly use a specific scattering color,
+ * and absorption multiplier factor too, but these parameters are left out for simplicity.
+ * It's easy enough to get a good wide range of results with just these two parameters. */
+static void vol_get_sigma_t(ShadeInput *shi, float sigma_t[3], const float co[3])
+{
+ /* technically absorption, but named transmission color
+ * since it describes the effect of the coloring *after* absorption */
+ float transmission_col[3] = {shi->mat->vol.transmission_col[0], shi->mat->vol.transmission_col[1], shi->mat->vol.transmission_col[2]};
+ float scattering = shi->mat->vol.scattering;
+
+ if (shi->mat->mapto_textured & (MAP_SCATTERING + MAP_TRANSMISSION_COL))
+ do_volume_tex(shi, co, MAP_SCATTERING + MAP_TRANSMISSION_COL, transmission_col, &scattering, &R);
+
+ sigma_t[0] = (1.0f - transmission_col[0]) + scattering;
+ sigma_t[1] = (1.0f - transmission_col[1]) + scattering;
+ sigma_t[2] = (1.0f - transmission_col[2]) + scattering;
+}
+
+/* phase function - determines in which directions the light
+ * is scattered in the volume relative to incoming direction
+ * and view direction */
+static float vol_get_phasefunc(ShadeInput *UNUSED(shi), float g, const float w[3], const float wp[3])
+{
+ const float normalize = 0.25f; // = 1.f/4.f = M_PI/(4.f*M_PI)
+
+ /* normalization constant is 1/4 rather than 1/4pi, since
+ * Blender's shading system doesn't normalize for
+ * energy conservation - eg. multiplying by pdf ( 1/pi for a lambert brdf ).
+ * This means that lambert surfaces in Blender are pi times brighter than they 'should be'
+ * and therefore, with correct energy conservation, volumes will darker than other solid objects,
+ * for the same lighting intensity.
+ * To correct this, scale up the phase function values by pi
+ * until Blender's shading system supports this better. --matt
+ */
+
+ if (g == 0.f) { /* isotropic */
+ return normalize * 1.f;
+ }
+ else { /* schlick */
+ const float k = 1.55f * g - 0.55f * g * g * g;
+ const float kcostheta = k * dot_v3v3(w, wp);
+ return normalize * (1.f - k * k) / ((1.f - kcostheta) * (1.f - kcostheta));
+ }
+
+ /* not used, but here for reference: */
+#if 0
+ switch (phasefunc_type) {
+ case MA_VOL_PH_MIEHAZY:
+ return normalize * (0.5f + 4.5f * powf(0.5 * (1.f + costheta), 8.f));
+ case MA_VOL_PH_MIEMURKY:
+ return normalize * (0.5f + 16.5f * powf(0.5 * (1.f + costheta), 32.f));
+ case MA_VOL_PH_RAYLEIGH:
+ return normalize * 3.f / 4.f * (1 + costheta * costheta);
+ case MA_VOL_PH_HG:
+ return normalize * (1.f - g * g) / powf(1.f + g * g - 2.f * g * costheta, 1.5f);
+ case MA_VOL_PH_SCHLICK:
+ {
+ const float k = 1.55f * g - 0.55f * g * g * g;
+ const float kcostheta = k * costheta;
+ return normalize * (1.f - k * k) / ((1.f - kcostheta) * (1.f - kcostheta));
+ }
+ case MA_VOL_PH_ISOTROPIC:
+ default:
+ return normalize * 1.f;
+ }
+#endif
+}
+
+/* Compute transmittance = e^(-attenuation) */
+static void vol_get_transmittance_seg(ShadeInput *shi, float tr[3], float stepsize, const float co[3], float density)
+{
+ /* input density = density at co */
+ float tau[3] = {0.f, 0.f, 0.f};
+ const float stepd = density * stepsize;
+ float sigma_t[3];
+
+ vol_get_sigma_t(shi, sigma_t, co);
+
+ /* homogeneous volume within the sampled distance */
+ tau[0] += stepd * sigma_t[0];
+ tau[1] += stepd * sigma_t[1];
+ tau[2] += stepd * sigma_t[2];
+
+ tr[0] *= expf(-tau[0]);
+ tr[1] *= expf(-tau[1]);
+ tr[2] *= expf(-tau[2]);
+}
+
+/* Compute transmittance = e^(-attenuation) */
+static void vol_get_transmittance(ShadeInput *shi, float tr[3], const float co[3], const float endco[3])
+{
+ float p[3] = {co[0], co[1], co[2]};
+ float step_vec[3] = {endco[0] - co[0], endco[1] - co[1], endco[2] - co[2]};
+ float tau[3] = {0.f, 0.f, 0.f};
+
+ float t0 = 0.f;
+ float t1 = normalize_v3(step_vec);
+ float pt0 = t0;
+
+ t0 += shi->mat->vol.stepsize * ((shi->mat->vol.stepsize_type == MA_VOL_STEP_CONSTANT) ? 0.5f : BLI_thread_frand(shi->thread));
+ p[0] += t0 * step_vec[0];
+ p[1] += t0 * step_vec[1];
+ p[2] += t0 * step_vec[2];
+ mul_v3_fl(step_vec, shi->mat->vol.stepsize);
+
+ for (; t0 < t1; pt0 = t0, t0 += shi->mat->vol.stepsize) {
+ const float d = vol_get_density(shi, p);
+ const float stepd = (t0 - pt0) * d;
+ float sigma_t[3];
+
+ vol_get_sigma_t(shi, sigma_t, p);
+
+ tau[0] += stepd * sigma_t[0];
+ tau[1] += stepd * sigma_t[1];
+ tau[2] += stepd * sigma_t[2];
+
+ add_v3_v3(p, step_vec);
+ }
+
+ /* return transmittance */
+ tr[0] = expf(-tau[0]);
+ tr[1] = expf(-tau[1]);
+ tr[2] = expf(-tau[2]);
+}
+
+static void vol_shade_one_lamp(struct ShadeInput *shi, const float co[3], const float view[3], LampRen *lar, float lacol[3])
+{
+ float visifac, lv[3], lampdist;
+ float tr[3] = {1.0, 1.0, 1.0};
+ float hitco[3], *atten_co;
+ float p, ref_col[3];
+
+ if (lar->mode & LA_LAYER) if ((lar->lay & shi->obi->lay) == 0) return;
+ if ((lar->lay & shi->lay) == 0) return;
+ if (lar->energy == 0.0f) return;
+
+ if ((visifac = lamp_get_visibility(lar, co, lv, &lampdist)) == 0.f) return;
+
+ copy_v3_v3(lacol, &lar->r);
+
+ if (lar->mode & LA_TEXTURE) {
+ shi->osatex = 0;
+ do_lamp_tex(lar, lv, shi, lacol, LA_TEXTURE);
+ }
+
+ mul_v3_fl(lacol, visifac);
+
+ if (ELEM(lar->type, LA_SUN, LA_HEMI))
+ copy_v3_v3(lv, lar->vec);
+ negate_v3(lv);
+
+ if (shi->mat->vol.shade_type == MA_VOL_SHADE_SHADOWED) {
+ mul_v3_fl(lacol, vol_get_shadow(shi, lar, co));
+ }
+ else if (ELEM(shi->mat->vol.shade_type, MA_VOL_SHADE_SHADED, MA_VOL_SHADE_MULTIPLE, MA_VOL_SHADE_SHADEDPLUSMULTIPLE)) {
+ Isect is;
+
+ if (shi->mat->vol.shadeflag & MA_VOL_RECV_EXT_SHADOW) {
+ mul_v3_fl(lacol, vol_get_shadow(shi, lar, co));
+ if (IMB_colormanagement_get_luminance(lacol) < 0.001f) return;
+ }
+
+ /* find minimum of volume bounds, or lamp coord */
+ if (vol_get_bounds(shi, co, lv, hitco, &is, VOL_BOUNDS_SS)) {
+ float dist = len_v3v3(co, hitco);
+ VlakRen *vlr = (VlakRen *)is.hit.face;
+
+ /* simple internal shadowing */
+ if (vlr->mat->material_type == MA_TYPE_SURFACE) {
+ lacol[0] = lacol[1] = lacol[2] = 0.0f;
+ return;
+ }
+
+ if (ELEM(lar->type, LA_SUN, LA_HEMI))
+ /* infinite lights, can never be inside volume */
+ atten_co = hitco;
+ else if (lampdist < dist) {
+ atten_co = lar->co;
+ }
+ else
+ atten_co = hitco;
+
+ vol_get_transmittance(shi, tr, co, atten_co);
+
+ mul_v3_v3v3(lacol, lacol, tr);
+ }
+ else {
+ /* Point is on the outside edge of the volume,
+ * therefore no attenuation, full transmission.
+ * Radiance from lamp remains unchanged */
+ }
+ }
+
+ if (IMB_colormanagement_get_luminance(lacol) < 0.001f) return;
+
+ normalize_v3(lv);
+ p = vol_get_phasefunc(shi, shi->mat->vol.asymmetry, view, lv);
+
+ /* physically based scattering with non-physically based RGB gain */
+ vol_get_reflection_color(shi, ref_col, co);
+
+ lacol[0] *= p * ref_col[0];
+ lacol[1] *= p * ref_col[1];
+ lacol[2] *= p * ref_col[2];
+}
+
+/* single scattering only for now */
+void vol_get_scattering(ShadeInput *shi, float scatter_col[3], const float co[3], const float view[3])
+{
+ ListBase *lights;
+ GroupObject *go;
+ LampRen *lar;
+
+ zero_v3(scatter_col);
+
+ lights = get_lights(shi);
+ for (go = lights->first; go; go = go->next) {
+ float lacol[3] = {0.f, 0.f, 0.f};
+ lar = go->lampren;
+
+ if (lar) {
+ vol_shade_one_lamp(shi, co, view, lar, lacol);
+ add_v3_v3(scatter_col, lacol);
+ }
+ }
+}
+
+
+/*
+ * The main volumetric integrator, using an emission/absorption/scattering model.
+ *
+ * Incoming radiance =
+ *
+ * outgoing radiance from behind surface * beam transmittance/attenuation
+ * + added radiance from all points along the ray due to participating media
+ * --> radiance for each segment =
+ * (radiance added by scattering + radiance added by emission) * beam transmittance/attenuation
+ */
+
+/* For ease of use, I've also introduced a 'reflection' and 'reflection color' parameter, which isn't
+ * physically correct. This works as an RGB tint/gain on out-scattered light, but doesn't affect the light
+ * that is transmitted through the volume. While having wavelength dependent absorption/scattering is more correct,
+ * it also makes it harder to control the overall look of the volume since coloring the outscattered light results
+ * in the inverse color being transmitted through the rest of the volume.
+ */
+static void volumeintegrate(struct ShadeInput *shi, float col[4], const float co[3], const float endco[3])
+{
+ float radiance[3] = {0.f, 0.f, 0.f};
+ float tr[3] = {1.f, 1.f, 1.f};
+ float p[3] = {co[0], co[1], co[2]};
+ float step_vec[3] = {endco[0] - co[0], endco[1] - co[1], endco[2] - co[2]};
+ const float stepsize = shi->mat->vol.stepsize;
+
+ float t0 = 0.f;
+ float pt0 = t0;
+ float t1 = normalize_v3(step_vec); /* returns vector length */
+
+ t0 += stepsize * ((shi->mat->vol.stepsize_type == MA_VOL_STEP_CONSTANT) ? 0.5f : BLI_thread_frand(shi->thread));
+ p[0] += t0 * step_vec[0];
+ p[1] += t0 * step_vec[1];
+ p[2] += t0 * step_vec[2];
+ mul_v3_fl(step_vec, stepsize);
+
+ for (; t0 < t1; pt0 = t0, t0 += stepsize) {
+ const float density = vol_get_density(shi, p);
+
+ if (density > 0.00001f) {
+ float scatter_col[3] = {0.f, 0.f, 0.f}, emit_col[3];
+ const float stepd = (t0 - pt0) * density;
+
+ /* transmittance component (alpha) */
+ vol_get_transmittance_seg(shi, tr, stepsize, co, density);
+
+ if (t0 > t1 * 0.25f) {
+ /* only use depth cutoff after we've traced a little way into the volume */
+ if (IMB_colormanagement_get_luminance(tr) < shi->mat->vol.depth_cutoff) break;
+ }
+
+ vol_get_emission(shi, emit_col, p);
+
+ if (shi->obi->volume_precache) {
+ float p2[3];
+
+ p2[0] = p[0] + (step_vec[0] * 0.5f);
+ p2[1] = p[1] + (step_vec[1] * 0.5f);
+ p2[2] = p[2] + (step_vec[2] * 0.5f);
+
+ vol_get_precached_scattering(&R, shi, scatter_col, p2);
+ }
+ else
+ vol_get_scattering(shi, scatter_col, p, shi->view);
+
+ radiance[0] += stepd * tr[0] * (emit_col[0] + scatter_col[0]);
+ radiance[1] += stepd * tr[1] * (emit_col[1] + scatter_col[1]);
+ radiance[2] += stepd * tr[2] * (emit_col[2] + scatter_col[2]);
+ }
+ add_v3_v3(p, step_vec);
+ }
+
+ /* multiply original color (from behind volume) with transmittance over entire distance */
+ mul_v3_v3v3(col, tr, col);
+ add_v3_v3(col, radiance);
+
+ /* alpha <-- transmission luminance */
+ col[3] = 1.0f - IMB_colormanagement_get_luminance(tr);
+}
+
+/* the main entry point for volume shading */
+static void volume_trace(struct ShadeInput *shi, struct ShadeResult *shr, int inside_volume)
+{
+ float hitco[3], col[4] = {0.f, 0.f, 0.f, 0.f};
+ const float *startco, *endco;
+ int trace_behind = 1;
+ const int ztransp = ((shi->depth == 0) && (shi->mat->mode & MA_TRANSP) && (shi->mat->mode & MA_ZTRANSP));
+ Isect is;
+
+ /* check for shading an internal face a volume object directly */
+ if (inside_volume == VOL_SHADE_INSIDE)
+ trace_behind = 0;
+ else if (inside_volume == VOL_SHADE_OUTSIDE) {
+ if (shi->flippednor)
+ inside_volume = VOL_SHADE_INSIDE;
+ }
+
+ if (ztransp && inside_volume == VOL_SHADE_INSIDE) {
+ MatInside *mi;
+ int render_this = 0;
+
+ /* don't render the backfaces of ztransp volume materials.
+ *
+ * volume shading renders the internal volume from between the
+ * ' view intersection of the solid volume to the
+ * intersection on the other side, as part of the shading of
+ * the front face.
+ *
+ * Because ztransp renders both front and back faces independently
+ * this will double up, so here we prevent rendering the backface as well,
+ * which would otherwise render the volume in between the camera and the backface
+ * --matt */
+
+ for (mi = R.render_volumes_inside.first; mi; mi = mi->next) {
+ /* weak... */
+ if (mi->ma == shi->mat) render_this = 1;
+ }
+ if (!render_this) return;
+ }
+
+
+ if (inside_volume == VOL_SHADE_INSIDE) {
+ startco = shi->camera_co;
+ endco = shi->co;
+
+ if (trace_behind) {
+ if (!ztransp)
+ /* trace behind the volume object */
+ vol_trace_behind(shi, shi->vlr, endco, col);
+ }
+ else {
+ /* we're tracing through the volume between the camera
+ * and a solid surface, so use that pre-shaded radiance */
+ copy_v4_v4(col, shr->combined);
+ }
+
+ /* shade volume from 'camera' to 1st hit point */
+ volumeintegrate(shi, col, startco, endco);
+ }
+ /* trace to find a backface, the other side bounds of the volume */
+ /* (ray intersect ignores front faces here) */
+ else if (vol_get_bounds(shi, shi->co, shi->view, hitco, &is, VOL_BOUNDS_DEPTH)) {
+ VlakRen *vlr = (VlakRen *)is.hit.face;
+
+ startco = shi->co;
+ endco = hitco;
+
+ if (!ztransp) {
+ /* if it's another face in the same material */
+ if (vlr->mat == shi->mat) {
+ /* trace behind the 2nd (raytrace) hit point */
+ vol_trace_behind(shi, (VlakRen *)is.hit.face, endco, col);
+ }
+ else {
+ shade_intersection(shi, col, &is);
+ }
+ }
+
+ /* shade volume from 1st hit point to 2nd hit point */
+ volumeintegrate(shi, col, startco, endco);
+ }
+
+ if (ztransp)
+ col[3] = col[3] > 1.f ? 1.f : col[3];
+ else
+ col[3] = 1.f;
+
+ copy_v3_v3(shr->combined, col);
+ shr->alpha = col[3];
+
+ copy_v3_v3(shr->diff, shr->combined);
+ copy_v3_v3(shr->diffshad, shr->diff);
+}
+
+/* Traces a shadow through the object,
+ * pretty much gets the transmission over a ray path */
+void shade_volume_shadow(struct ShadeInput *shi, struct ShadeResult *shr, struct Isect *last_is)
+{
+ float hitco[3];
+ float tr[3] = {1.0, 1.0, 1.0};
+ Isect is = {{0}};
+ const float *startco, *endco;
+
+ memset(shr, 0, sizeof(ShadeResult));
+
+ /* if 1st hit normal is facing away from the camera,
+ * then we're inside the volume already. */
+ if (shi->flippednor) {
+ startco = last_is->start;
+ endco = shi->co;
+ }
+
+ /* trace to find a backface, the other side bounds of the volume */
+ /* (ray intersect ignores front faces here) */
+ else if (vol_get_bounds(shi, shi->co, shi->view, hitco, &is, VOL_BOUNDS_DEPTH)) {
+ startco = shi->co;
+ endco = hitco;
+ }
+ else {
+ shr->combined[0] = shr->combined[1] = shr->combined[2] = 0.f;
+ shr->alpha = shr->combined[3] = 1.f;
+ return;
+ }
+
+ vol_get_transmittance(shi, tr, startco, endco);
+
+
+ /* if we hit another face in the same volume bounds */
+ /* shift raytrace coordinates to the hit point, to avoid shading volume twice */
+ /* due to idiosyncracy in ray_trace_shadow_tra() */
+ if (is.hit.ob == shi->obi) {
+ copy_v3_v3(shi->co, hitco);
+ last_is->dist += is.dist;
+ shi->vlr = (VlakRen *)is.hit.face;
+ }
+
+
+ copy_v3_v3(shr->combined, tr);
+ shr->combined[3] = 1.0f - IMB_colormanagement_get_luminance(tr);
+ shr->alpha = shr->combined[3];
+}
+
+
+/* delivers a fully filled in ShadeResult, for all passes */
+void shade_volume_outside(ShadeInput *shi, ShadeResult *shr)
+{
+ memset(shr, 0, sizeof(ShadeResult));
+ volume_trace(shi, shr, VOL_SHADE_OUTSIDE);
+}
+
+
+void shade_volume_inside(ShadeInput *shi, ShadeResult *shr)
+{
+ MatInside *m;
+ Material *mat_backup;
+ ObjectInstanceRen *obi_backup;
+ float prev_alpha = shr->alpha;
+
+ /* XXX: extend to multiple volumes perhaps later */
+ mat_backup = shi->mat;
+ obi_backup = shi->obi;
+
+ m = R.render_volumes_inside.first;
+ shi->mat = m->ma;
+ shi->obi = m->obi;
+ shi->obr = m->obi->obr;
+
+ volume_trace(shi, shr, VOL_SHADE_INSIDE);
+
+ shr->alpha = shr->alpha + prev_alpha;
+ CLAMP(shr->alpha, 0.0f, 1.0f);
+
+ shi->mat = mat_backup;
+ shi->obi = obi_backup;
+ shi->obr = obi_backup->obr;
+}
diff --git a/source/blender/render/intern/source/voxeldata.c b/source/blender/render/intern/source/voxeldata.c
new file mode 100644
index 00000000000..2daa4123536
--- /dev/null
+++ b/source/blender/render/intern/source/voxeldata.c
@@ -0,0 +1,571 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): Raul Fernandez Hernandez (Farsthary), Matt Ebb.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/render/intern/source/voxeldata.c
+ * \ingroup render
+ */
+
+
+#include <math.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#ifdef WIN32
+#include "BLI_winstuff.h"
+#endif
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_math.h"
+#include "BLI_blenlib.h"
+#include "BLI_threads.h"
+#include "BLI_voxel.h"
+#include "BLI_utildefines.h"
+
+#include "BLT_translation.h"
+
+#include "IMB_imbuf.h"
+#include "IMB_imbuf_types.h"
+
+#include "BKE_cloth.h"
+#include "BKE_global.h"
+#include "BKE_image.h"
+#include "BKE_main.h"
+#include "BKE_modifier.h"
+
+#include "smoke_API.h"
+#include "BPH_mass_spring.h"
+
+#include "DNA_texture_types.h"
+#include "DNA_object_force_types.h"
+#include "DNA_object_types.h"
+#include "DNA_particle_types.h"
+#include "DNA_modifier_types.h"
+#include "DNA_smoke_types.h"
+
+
+#include "render_types.h"
+#include "texture.h"
+#include "voxeldata.h"
+
+static bool is_vd_res_ok(VoxelData *vd)
+{
+ /* arbitrary large value so corrupt headers don't break */
+ const int min = 1, max = 100000;
+ return (vd->resol[0] >= min && vd->resol[0] <= max) &&
+ (vd->resol[1] >= min && vd->resol[1] <= max) &&
+ (vd->resol[2] >= min && vd->resol[2] <= max);
+}
+
+/* use size_t because the result may exceed INT_MAX */
+static size_t vd_resol_size(VoxelData *vd)
+{
+ return (size_t)vd->resol[0] * (size_t)vd->resol[1] * (size_t)vd->resol[2];
+}
+
+static int load_frame_blendervoxel(VoxelData *vd, FILE *fp, int frame)
+{
+ const size_t size = vd_resol_size(vd);
+ size_t offset = sizeof(VoxelDataHeader);
+
+ if (is_vd_res_ok(vd) == false)
+ return 0;
+
+ vd->dataset = MEM_mapallocN(sizeof(float) * size, "voxel dataset");
+ if (vd->dataset == NULL) return 0;
+
+ if (fseek(fp, frame * size * sizeof(float) + offset, 0) == -1)
+ return 0;
+ if (fread(vd->dataset, sizeof(float), size, fp) != size)
+ return 0;
+
+ vd->cachedframe = frame;
+ vd->ok = 1;
+ return 1;
+}
+
+static int load_frame_raw8(VoxelData *vd, FILE *fp, int frame)
+{
+ const size_t size = vd_resol_size(vd);
+ size_t i;
+ char *data_c;
+
+ if (is_vd_res_ok(vd) == false)
+ return 0;
+
+ vd->dataset = MEM_mapallocN(sizeof(float) * size, "voxel dataset");
+ if (vd->dataset == NULL) return 0;
+ data_c = (char *)MEM_mallocN(sizeof(char) * size, "temporary voxel file reading storage");
+ if (data_c == NULL) {
+ MEM_freeN(vd->dataset);
+ vd->dataset = NULL;
+ return 0;
+ }
+
+ if (fseek(fp, (frame - 1) * size * sizeof(char), 0) == -1) {
+ MEM_freeN(data_c);
+ MEM_freeN(vd->dataset);
+ vd->dataset = NULL;
+ return 0;
+ }
+ if (fread(data_c, sizeof(char), size, fp) != size) {
+ MEM_freeN(data_c);
+ MEM_freeN(vd->dataset);
+ vd->dataset = NULL;
+ return 0;
+ }
+
+ for (i = 0; i < size; i++) {
+ vd->dataset[i] = (float)data_c[i] / 255.f;
+ }
+ MEM_freeN(data_c);
+
+ vd->cachedframe = frame;
+ vd->ok = 1;
+ return 1;
+}
+
+static void load_frame_image_sequence(VoxelData *vd, Tex *tex)
+{
+ ImBuf *ibuf;
+ Image *ima = tex->ima;
+ ImageUser *tiuser = &tex->iuser;
+ ImageUser iuser = *(tiuser);
+ int x = 0, y = 0, z = 0;
+ const float *rf;
+
+ if (!ima) return;
+ if (iuser.frames == 0) return;
+
+ ima->source = IMA_SRC_SEQUENCE;
+ iuser.framenr = 1 + iuser.offset;
+
+ /* find the first valid ibuf and use it to initialize the resolution of the data set */
+ /* need to do this in advance so we know how much memory to allocate */
+ ibuf = BKE_image_acquire_ibuf(ima, &iuser, NULL);
+ while (!ibuf && (iuser.framenr < iuser.frames)) {
+ iuser.framenr++;
+ ibuf = BKE_image_acquire_ibuf(ima, &iuser, NULL);
+ }
+ if (!ibuf) return;
+ if (!ibuf->rect_float) IMB_float_from_rect(ibuf);
+
+ vd->flag |= TEX_VD_STILL;
+ vd->resol[0] = ibuf->x;
+ vd->resol[1] = ibuf->y;
+ vd->resol[2] = iuser.frames;
+ vd->dataset = MEM_mapallocN(sizeof(float) * vd_resol_size(vd), "voxel dataset");
+
+ for (z = 0; z < iuser.frames; z++) {
+ /* get a new ibuf for each frame */
+ if (z > 0) {
+ iuser.framenr++;
+ BKE_image_release_ibuf(ima, ibuf, NULL);
+ ibuf = BKE_image_acquire_ibuf(ima, &iuser, NULL);
+ if (!ibuf) break;
+ if (!ibuf->rect_float) IMB_float_from_rect(ibuf);
+ }
+ rf = ibuf->rect_float;
+
+ for (y = 0; y < ibuf->y; y++) {
+ for (x = 0; x < ibuf->x; x++) {
+ /* currently averaged to monchrome */
+ vd->dataset[BLI_VOXEL_INDEX(x, y, z, vd->resol)] = (rf[0] + rf[1] + rf[2]) / 3.0f;
+ rf += 4;
+ }
+ }
+
+ BKE_image_free_anim_ibufs(ima, iuser.framenr);
+ }
+
+ BKE_image_release_ibuf(ima, ibuf, NULL);
+
+ vd->ok = 1;
+ return;
+}
+
+static int read_voxeldata_header(FILE *fp, struct VoxelData *vd)
+{
+ VoxelDataHeader *h = (VoxelDataHeader *)MEM_mallocN(sizeof(VoxelDataHeader), "voxel data header");
+
+ rewind(fp);
+ if (fread(h, sizeof(VoxelDataHeader), 1, fp) != 1) {
+ MEM_freeN(h);
+ return 0;
+ }
+
+ vd->resol[0] = h->resolX;
+ vd->resol[1] = h->resolY;
+ vd->resol[2] = h->resolZ;
+
+ MEM_freeN(h);
+ return 1;
+}
+
+static void init_frame_smoke(VoxelData *vd, int cfra)
+{
+#ifdef WITH_SMOKE
+ Object *ob;
+ ModifierData *md;
+
+ vd->dataset = NULL;
+ if (vd->object == NULL) return;
+ ob = vd->object;
+
+ /* draw code for smoke */
+ if ((md = (ModifierData *)modifiers_findByType(ob, eModifierType_Smoke))) {
+ SmokeModifierData *smd = (SmokeModifierData *)md;
+ SmokeDomainSettings *sds = smd->domain;
+
+ if (sds && sds->fluid) {
+ BLI_rw_mutex_lock(sds->fluid_mutex, THREAD_LOCK_READ);
+
+ if (!sds->fluid) {
+ BLI_rw_mutex_unlock(sds->fluid_mutex);
+ return;
+ }
+
+ if (cfra < sds->point_cache[0]->startframe)
+ ; /* don't show smoke before simulation starts, this could be made an option in the future */
+ else if (vd->smoked_type == TEX_VD_SMOKEHEAT) {
+ size_t totRes;
+ size_t i;
+ float *heat;
+
+ if (!smoke_has_heat(sds->fluid)) {
+ BLI_rw_mutex_unlock(sds->fluid_mutex);
+ return;
+ }
+
+ copy_v3_v3_int(vd->resol, sds->res);
+ totRes = vd_resol_size(vd);
+ vd->dataset = MEM_mapallocN(sizeof(float) * (totRes), "smoke data");
+ /* get heat data */
+ heat = smoke_get_heat(sds->fluid);
+
+ /* scale heat values from -2.0-2.0 to 0.0-1.0 */
+ for (i = 0; i < totRes; i++) {
+ vd->dataset[i] = (heat[i] + 2.0f) / 4.0f;
+ }
+ }
+ else if (vd->smoked_type == TEX_VD_SMOKEVEL) {
+ size_t totRes;
+ size_t i;
+ float *xvel, *yvel, *zvel;
+
+ copy_v3_v3_int(vd->resol, sds->res);
+ totRes = vd_resol_size(vd);
+ vd->dataset = MEM_mapallocN(sizeof(float) * (totRes), "smoke data");
+ /* get velocity data */
+ xvel = smoke_get_velocity_x(sds->fluid);
+ yvel = smoke_get_velocity_y(sds->fluid);
+ zvel = smoke_get_velocity_z(sds->fluid);
+
+ /* map velocities between 0 and 0.3f */
+ for (i = 0; i < totRes; i++) {
+ vd->dataset[i] = sqrtf(xvel[i] * xvel[i] + yvel[i] * yvel[i] + zvel[i] * zvel[i]) * 3.0f;
+ }
+
+ }
+ else if (vd->smoked_type == TEX_VD_SMOKEFLAME) {
+ size_t totRes;
+ float *flame;
+
+ if (sds->flags & MOD_SMOKE_HIGHRES) {
+ if (!smoke_turbulence_has_fuel(sds->wt)) {
+ BLI_rw_mutex_unlock(sds->fluid_mutex);
+ return;
+ }
+ smoke_turbulence_get_res(sds->wt, vd->resol);
+ flame = smoke_turbulence_get_flame(sds->wt);
+ }
+ else {
+ if (!smoke_has_fuel(sds->fluid)) {
+ BLI_rw_mutex_unlock(sds->fluid_mutex);
+ return;
+ }
+ copy_v3_v3_int(vd->resol, sds->res);
+ flame = smoke_get_flame(sds->fluid);
+ }
+
+ /* always store copy, as smoke internal data can change */
+ totRes = vd_resol_size(vd);
+ vd->dataset = MEM_mapallocN(sizeof(float)*(totRes), "smoke data");
+ memcpy(vd->dataset, flame, sizeof(float)*totRes);
+ }
+ else {
+ size_t totCells;
+ int depth = 4;
+ vd->data_type = TEX_VD_RGBA_PREMUL;
+
+ /* data resolution */
+ if (sds->flags & MOD_SMOKE_HIGHRES) {
+ smoke_turbulence_get_res(sds->wt, vd->resol);
+ }
+ else {
+ copy_v3_v3_int(vd->resol, sds->res);
+ }
+
+ /* TODO: is_vd_res_ok(rvd) doesnt check this resolution */
+ totCells = vd_resol_size(vd) * depth;
+ /* always store copy, as smoke internal data can change */
+ vd->dataset = MEM_mapallocN(sizeof(float) * totCells, "smoke data");
+
+ if (sds->flags & MOD_SMOKE_HIGHRES) {
+ if (smoke_turbulence_has_colors(sds->wt)) {
+ smoke_turbulence_get_rgba(sds->wt, vd->dataset, 1);
+ }
+ else {
+ smoke_turbulence_get_rgba_from_density(sds->wt, sds->active_color, vd->dataset, 1);
+ }
+ }
+ else {
+ if (smoke_has_colors(sds->fluid)) {
+ smoke_get_rgba(sds->fluid, vd->dataset, 1);
+ }
+ else {
+ smoke_get_rgba_from_density(sds->fluid, sds->active_color, vd->dataset, 1);
+ }
+ }
+ } /* end of fluid condition */
+
+ BLI_rw_mutex_unlock(sds->fluid_mutex);
+ }
+ }
+
+ vd->ok = 1;
+
+#else // WITH_SMOKE
+ (void)vd;
+ (void)cfra;
+
+ vd->dataset = NULL;
+#endif
+}
+
+static void init_frame_hair(VoxelData *vd, int UNUSED(cfra))
+{
+ Object *ob;
+ ModifierData *md;
+
+ vd->dataset = NULL;
+ if (vd->object == NULL) return;
+ ob = vd->object;
+
+ if ((md = (ModifierData *)modifiers_findByType(ob, eModifierType_ParticleSystem))) {
+ ParticleSystemModifierData *pmd = (ParticleSystemModifierData *)md;
+
+ if (pmd->psys && pmd->psys->clmd) {
+ vd->ok |= BPH_cloth_solver_get_texture_data(ob, pmd->psys->clmd, vd);
+ }
+ }
+}
+
+void cache_voxeldata(Tex *tex, int scene_frame)
+{
+ VoxelData *vd = tex->vd;
+ FILE *fp;
+ int curframe;
+ char path[sizeof(vd->source_path)];
+
+ /* only re-cache if dataset needs updating */
+ if ((vd->flag & TEX_VD_STILL) || (vd->cachedframe == scene_frame))
+ if (vd->ok) return;
+
+ /* clear out old cache, ready for new */
+ if (vd->dataset) {
+ MEM_freeN(vd->dataset);
+ vd->dataset = NULL;
+ }
+ /* reset data_type */
+ vd->data_type = TEX_VD_INTENSITY;
+
+ if (vd->flag & TEX_VD_STILL)
+ curframe = vd->still_frame;
+ else
+ curframe = scene_frame;
+
+ BLI_strncpy(path, vd->source_path, sizeof(path));
+
+ /* each type is responsible for setting to true */
+ vd->ok = false;
+
+ switch (vd->file_format) {
+ case TEX_VD_IMAGE_SEQUENCE:
+ load_frame_image_sequence(vd, tex);
+ return;
+ case TEX_VD_SMOKE:
+ init_frame_smoke(vd, scene_frame);
+ return;
+ case TEX_VD_HAIR:
+ init_frame_hair(vd, scene_frame);
+ return;
+ case TEX_VD_BLENDERVOXEL:
+ BLI_path_abs(path, BKE_main_blendfile_path_from_global());
+ fp = BLI_fopen(path, "rb");
+ if (!fp) return;
+
+ if (read_voxeldata_header(fp, vd))
+ load_frame_blendervoxel(vd, fp, curframe - 1);
+
+ fclose(fp);
+ return;
+ case TEX_VD_RAW_8BIT:
+ BLI_path_abs(path, BKE_main_blendfile_path_from_global());
+ fp = BLI_fopen(path, "rb");
+ if (!fp) return;
+
+ load_frame_raw8(vd, fp, curframe);
+ fclose(fp);
+ return;
+ }
+}
+
+void make_voxeldata(struct Render *re)
+{
+ Tex *tex;
+
+ re->i.infostr = IFACE_("Loading voxel datasets");
+ re->stats_draw(re->sdh, &re->i);
+
+ /* XXX: should be doing only textures used in this render */
+ for (tex = re->main->tex.first; tex; tex = tex->id.next) {
+ if (tex->id.us && tex->type == TEX_VOXELDATA) {
+ cache_voxeldata(tex, re->r.cfra);
+ }
+ }
+
+ re->i.infostr = NULL;
+ re->stats_draw(re->sdh, &re->i);
+
+}
+
+int voxeldatatex(struct Tex *tex, const float texvec[3], struct TexResult *texres)
+{
+ VoxelData *vd = tex->vd;
+ float co[3], offset[3] = {0.5, 0.5, 0.5}, a;
+ int retval = (vd->data_type == TEX_VD_RGBA_PREMUL) ? TEX_RGB : TEX_INT;
+ int depth = (vd->data_type == TEX_VD_RGBA_PREMUL) ? 4 : 1;
+ int ch;
+
+ if (vd->dataset == NULL) {
+ texres->tin = 0.0f;
+ return 0;
+ }
+
+ /* scale lookup from 0.0-1.0 (original location) to -1.0, 1.0, consistent with image texture tex coords */
+ /* in implementation this works backwards, bringing sample locations from -1.0, 1.0
+ * to the range 0.0, 1.0, before looking up in the voxel structure. */
+ copy_v3_v3(co, texvec);
+ mul_v3_fl(co, 0.5f);
+ add_v3_v3(co, offset);
+
+ /* co is now in the range 0.0, 1.0 */
+ switch (vd->extend) {
+ case TEX_CLIP:
+ {
+ if ((co[0] < 0.f || co[0] > 1.f) || (co[1] < 0.f || co[1] > 1.f) || (co[2] < 0.f || co[2] > 1.f)) {
+ texres->tin = 0.f;
+ return retval;
+ }
+ break;
+ }
+ case TEX_REPEAT:
+ {
+ co[0] = co[0] - floorf(co[0]);
+ co[1] = co[1] - floorf(co[1]);
+ co[2] = co[2] - floorf(co[2]);
+ break;
+ }
+ case TEX_EXTEND:
+ {
+ CLAMP(co[0], 0.f, 1.f);
+ CLAMP(co[1], 0.f, 1.f);
+ CLAMP(co[2], 0.f, 1.f);
+ break;
+ }
+ }
+
+ for (ch = 0; ch < depth; ch++) {
+ float *dataset = vd->dataset + ch*vd->resol[0]*vd->resol[1]*vd->resol[2];
+ float *result = &texres->tin;
+
+ if (vd->data_type == TEX_VD_RGBA_PREMUL) {
+ switch (ch) {
+ case 0:
+ result = &texres->tr;
+ break;
+ case 1:
+ result = &texres->tg;
+ break;
+ case 2:
+ result = &texres->tb;
+ break;
+ }
+ }
+
+ switch (vd->interp_type) {
+ case TEX_VD_NEARESTNEIGHBOR:
+ *result = BLI_voxel_sample_nearest(dataset, vd->resol, co);
+ break;
+ case TEX_VD_LINEAR:
+ *result = BLI_voxel_sample_trilinear(dataset, vd->resol, co);
+ break;
+ case TEX_VD_QUADRATIC:
+ *result = BLI_voxel_sample_triquadratic(dataset, vd->resol, co);
+ break;
+ case TEX_VD_TRICUBIC_CATROM:
+ case TEX_VD_TRICUBIC_BSPLINE:
+ *result = BLI_voxel_sample_tricubic(dataset, vd->resol, co, (vd->interp_type == TEX_VD_TRICUBIC_BSPLINE));
+ break;
+ }
+ }
+
+ a = texres->tin;
+ texres->tin *= vd->int_multiplier;
+ BRICONT;
+
+ if (vd->data_type == TEX_VD_RGBA_PREMUL) {
+ /* unmultiply */
+ if (a>0.001f) {
+ texres->tr /= a;
+ texres->tg /= a;
+ texres->tb /= a;
+ }
+ texres->talpha = 1;
+ }
+ else {
+ texres->tr = texres->tin;
+ texres->tg = texres->tin;
+ texres->tb = texres->tin;
+ }
+
+ texres->ta = texres->tin;
+ BRICONTRGB;
+
+ return retval;
+}
diff --git a/source/blender/render/intern/source/zbuf.c b/source/blender/render/intern/source/zbuf.c
index 3837383c4c7..436ee590f5c 100644
--- a/source/blender/render/intern/source/zbuf.c
+++ b/source/blender/render/intern/source/zbuf.c
@@ -54,10 +54,10 @@
void zbuf_alloc_span(ZSpan *zspan, int rectx, int recty)
{
memset(zspan, 0, sizeof(ZSpan));
-
+
zspan->rectx= rectx;
zspan->recty= recty;
-
+
zspan->span1= MEM_mallocN(recty*sizeof(float), "zspan");
zspan->span2= MEM_mallocN(recty*sizeof(float), "zspan");
}
@@ -85,27 +85,27 @@ static void zbuf_add_to_span(ZSpan *zspan, const float v1[2], const float v2[2])
float *span;
float xx1, dx0, xs0;
int y, my0, my2;
-
+
if (v1[1]<v2[1]) {
minv= v1; maxv= v2;
}
else {
minv= v2; maxv= v1;
}
-
+
my0= ceil(minv[1]);
my2= floor(maxv[1]);
-
+
if (my2<0 || my0>= zspan->recty) return;
-
+
/* clip top */
if (my2>=zspan->recty) my2= zspan->recty-1;
/* clip bottom */
if (my0<0) my0= 0;
-
+
if (my0>my2) return;
/* if (my0>my2) should still fill in, that way we get spans that skip nicely */
-
+
xx1= maxv[1]-minv[1];
if (xx1>FLT_EPSILON) {
dx0= (minv[0]-maxv[0])/xx1;
@@ -115,7 +115,7 @@ static void zbuf_add_to_span(ZSpan *zspan, const float v1[2], const float v2[2])
dx0 = 0.0f;
xs0 = min_ff(minv[0], maxv[0]);
}
-
+
/* empty span */
if (zspan->maxp1 == NULL) {
span= zspan->span1;
@@ -158,9 +158,9 @@ static void zbuf_add_to_span(ZSpan *zspan, const float v1[2], const float v2[2])
}
}
-/*-----------------------------------------------------------*/
+/*-----------------------------------------------------------*/
/* Functions */
-/*-----------------------------------------------------------*/
+/*-----------------------------------------------------------*/
/* scanconvert for strand triangles, calls func for each x, y coordinate and gives UV barycentrics and z */
@@ -170,30 +170,30 @@ void zspan_scanconvert(ZSpan *zspan, void *handle, float *v1, float *v2, float *
float u, v, uxd, uyd, vxd, vyd, uy0, vy0, xx1;
const float *span1, *span2;
int i, j, x, y, sn1, sn2, rectx = zspan->rectx, my0, my2;
-
+
/* init */
zbuf_init_span(zspan);
-
+
/* set spans */
zbuf_add_to_span(zspan, v1, v2);
zbuf_add_to_span(zspan, v2, v3);
zbuf_add_to_span(zspan, v3, v1);
-
+
/* clipped */
if (zspan->minp2==NULL || zspan->maxp2==NULL) return;
-
+
my0 = max_ii(zspan->miny1, zspan->miny2);
my2 = min_ii(zspan->maxy1, zspan->maxy2);
-
+
// printf("my %d %d\n", my0, my2);
if (my2<my0) return;
-
+
/* ZBUF DX DY, in floats still */
x1= v1[0]- v2[0];
x2= v2[0]- v3[0];
y1= v1[1]- v2[1];
y2= v2[1]- v3[1];
-
+
z1= 1.0f; /* (u1 - u2) */
z2= 0.0f; /* (u2 - u3) */
@@ -213,28 +213,28 @@ void zspan_scanconvert(ZSpan *zspan, void *handle, float *v1, float *v2, float *
x0= y1*z2-z1*y2;
y0= z1*x2-x1*z2;
-
+
xx1= (x0*v1[0] + y0*v1[1])/z0;
vxd= -(double)x0/(double)z0;
vyd= -(double)y0/(double)z0;
vy0= ((double)my2)*vyd + (double)xx1;
-
+
/* correct span */
span1= zspan->span1+my2;
span2= zspan->span2+my2;
-
+
for (i = 0, y = my2; y >= my0; i++, y--, span1--, span2--) {
-
+
sn1= floor(min_ff(*span1, *span2));
sn2= floor(max_ff(*span1, *span2));
- sn1++;
-
+ sn1++;
+
if (sn2>=rectx) sn2= rectx-1;
if (sn1<0) sn1= 0;
-
+
u = (((double)sn1 * uxd) + uy0) - (i * uyd);
v = (((double)sn1 * vxd) + vy0) - (i * vyd);
-
+
for (j = 0, x = sn1; x <= sn2; j++, x++) {
func(handle, x, y, u + (j * uxd), v + (j * vxd));
}
diff --git a/source/blender/windowmanager/WM_api.h b/source/blender/windowmanager/WM_api.h
index 21e050e8e14..267aa448dc3 100644
--- a/source/blender/windowmanager/WM_api.h
+++ b/source/blender/windowmanager/WM_api.h
@@ -142,7 +142,7 @@ enum {
struct wmWindow *WM_window_open(struct bContext *C, const struct rcti *rect);
struct wmWindow *WM_window_open_temp(struct bContext *C, int x, int y, int sizex, int sizey, int type);
void WM_window_set_dpi(wmWindow *win);
-
+
bool WM_stereo3d_enabled(struct wmWindow *win, bool only_fullscreen_test);
diff --git a/source/blender/windowmanager/WM_keymap.h b/source/blender/windowmanager/WM_keymap.h
index 04ea8611dcc..9390db400d2 100644
--- a/source/blender/windowmanager/WM_keymap.h
+++ b/source/blender/windowmanager/WM_keymap.h
@@ -58,9 +58,9 @@ void WM_keyconfig_update_operatortype(void);
void WM_keymap_init (struct bContext *C);
void WM_keymap_free (struct wmKeyMap *keymap);
-wmKeyMapItem *WM_keymap_verify_item(struct wmKeyMap *keymap, const char *idname, int type,
+wmKeyMapItem *WM_keymap_verify_item(struct wmKeyMap *keymap, const char *idname, int type,
int val, int modifier, int keymodifier);
-wmKeyMapItem *WM_keymap_add_item(struct wmKeyMap *keymap, const char *idname, int type,
+wmKeyMapItem *WM_keymap_add_item(struct wmKeyMap *keymap, const char *idname, int type,
int val, int modifier, int keymodifier);
wmKeyMapItem *WM_keymap_add_menu(struct wmKeyMap *keymap, const char *idname, int type,
int val, int modifier, int keymodifier);
@@ -79,7 +79,7 @@ wmKeyMap *WM_keymap_active(struct wmWindowManager *wm, struct wmKeyMap *keymap);
wmKeyMap *WM_keymap_guess_opname(const struct bContext *C, const char *opname);
bool WM_keymap_remove(struct wmKeyConfig *keyconfig, struct wmKeyMap *keymap);
bool WM_keymap_poll(struct bContext *C, struct wmKeyMap *keymap);
-
+
wmKeyMapItem *WM_keymap_item_find_id(struct wmKeyMap *keymap, int id);
int WM_keymap_item_compare(struct wmKeyMapItem *k1, struct wmKeyMapItem *k2);
diff --git a/source/blender/windowmanager/WM_types.h b/source/blender/windowmanager/WM_types.h
index 81018348ca0..929617aab04 100644
--- a/source/blender/windowmanager/WM_types.h
+++ b/source/blender/windowmanager/WM_types.h
@@ -200,6 +200,7 @@ typedef enum eOperatorPropTags {
#define KM_RELEASE 2
#define KM_CLICK 3
#define KM_DBL_CLICK 4
+#define KM_CLICK_DRAG 5
/* ************** UI Handler ***************** */
@@ -211,14 +212,14 @@ typedef enum eOperatorPropTags {
typedef struct wmNotifier {
struct wmNotifier *next, *prev;
-
+
struct wmWindowManager *wm;
struct wmWindow *window;
-
+
unsigned int category, data, subtype, action;
-
+
void *reference;
-
+
} wmNotifier;
@@ -335,7 +336,7 @@ typedef struct wmNotifier {
/* NC_TEXT Text */
#define ND_CURSOR (50<<16)
#define ND_DISPLAY (51<<16)
-
+
/* NC_ANIMATION Animato */
#define ND_KEYFRAME (70<<16)
#define ND_KEYFRAME_PROP (71<<16)
@@ -433,7 +434,7 @@ typedef struct wmGesture {
uint is_active : 1;
/* Use for gestures that support both immediate or delayed activation. */
uint wait_for_input : 1;
-
+
void *customdata;
/* customdata for border is a recti */
/* customdata for circle is recti, (xmin, ymin) is center, xmax radius */
@@ -451,7 +452,7 @@ typedef struct wmGesture {
/* event comes from eventmanager and from keymap */
typedef struct wmEvent {
struct wmEvent *next, *prev;
-
+
short type; /* event code itself (short, is also in keymap) */
short val; /* press, release, scrollvalue */
int x, y; /* mouse pointer position, screen coord */
@@ -468,13 +469,14 @@ typedef struct wmEvent {
int prevx, prevy;
double prevclicktime;
int prevclickx, prevclicky;
-
+
/* modifier states */
short shift, ctrl, alt, oskey; /* oskey is apple or windowskey, value denotes order of pressed */
short keymodifier; /* rawkey modifier */
-
+
/* set in case a KM_PRESS went by unhandled */
char check_click;
+ char check_drag;
char is_motion_absolute;
/* keymap item, set by handler (weak?) */
@@ -488,7 +490,7 @@ typedef struct wmEvent {
short customdatafree;
int pad2;
void *customdata; /* ascii, unicode, mouse coords, angles, vectors, dragdrop info */
-
+
} wmEvent;
/* ************** custom wmEvent data ************** */
@@ -527,17 +529,17 @@ typedef enum { /* Timer flags */
typedef struct wmTimer {
struct wmTimer *next, *prev;
-
+
struct wmWindow *win; /* window this timer is attached to (optional) */
double timestep; /* set by timer user */
int event_type; /* set by timer user, goes to event system */
wmTimerFlags flags; /* Various flags controlling timer options, see below. */
void *customdata; /* set by timer user, to allow custom values */
-
+
double duration; /* total running time in seconds */
double delta; /* time since previous step in seconds */
-
+
double ltime; /* internal, last time timer was activated */
double ntime; /* internal, next time we want to activate the timer */
double stime; /* internal, when the timer started */
@@ -653,16 +655,16 @@ typedef enum wmDragFlags {
typedef struct wmDrag {
struct wmDrag *next, *prev;
-
+
int icon, type; /* type, see WM_DRAG defines above */
void *poin;
char path[1024]; /* FILE_MAX */
double value;
-
+
struct ImBuf *imb; /* if no icon but imbuf should be drawn around cursor */
float scale;
int sx, sy;
-
+
char opname[200]; /* if set, draws operator name*/
unsigned int flags;
} wmDrag;
@@ -671,13 +673,13 @@ typedef struct wmDrag {
/* allocation and free is on startup and exit */
typedef struct wmDropBox {
struct wmDropBox *next, *prev;
-
+
/* test if the dropbox is active, then can print optype name */
int (*poll)(struct bContext *, struct wmDrag *, const wmEvent *);
/* before exec, this copies drag info to wmDrop properties */
void (*copy)(struct wmDrag *, struct wmDropBox *);
-
+
/* if poll survives, operator is called */
wmOperatorType *ot; /* not saved in file, so can be pointer */
diff --git a/source/blender/windowmanager/intern/wm.c b/source/blender/windowmanager/intern/wm.c
index b6a12acd57d..6a42bf26a97 100644
--- a/source/blender/windowmanager/intern/wm.c
+++ b/source/blender/windowmanager/intern/wm.c
@@ -106,7 +106,7 @@ void WM_operator_free(wmOperator *op)
WM_operator_free(opm);
}
}
-
+
MEM_freeN(op);
}
@@ -192,11 +192,11 @@ void wm_operator_register(bContext *C, wmOperator *op)
void WM_operator_stack_clear(wmWindowManager *wm)
{
wmOperator *op;
-
+
while ((op = BLI_pophead(&wm->operators))) {
WM_operator_free(op);
}
-
+
WM_main_add_notifier(NC_WM | ND_HISTORY, NULL);
}
@@ -372,7 +372,7 @@ void WM_keymap_init(bContext *C)
wm->addonconf = WM_keyconfig_new(wm, "Blender Addon");
if (!wm->userconf)
wm->userconf = WM_keyconfig_new(wm, "Blender User");
-
+
/* initialize only after python init is done, for keymaps that
* use python operators */
if (CTX_py_init_get(C) && (wm->initialized & WM_KEYMAP_IS_INITIALIZED) == 0) {
@@ -394,8 +394,9 @@ void WM_keymap_init(bContext *C)
void WM_check(bContext *C)
{
+ Main *bmain = CTX_data_main(C);
wmWindowManager *wm = CTX_wm_manager(C);
-
+
/* wm context */
if (wm == NULL) {
wm = CTX_data_main(C)->wm.first;
@@ -424,7 +425,7 @@ void WM_check(bContext *C)
/* case: fileread */
/* note: this runs in bg mode to set the screen context cb */
if ((wm->initialized & WM_WINDOW_IS_INITIALIZED) == 0) {
- ED_screens_initialize(wm);
+ ED_screens_initialize(bmain, wm);
wm->initialized |= WM_WINDOW_IS_INITIALIZED;
}
}
@@ -433,7 +434,7 @@ void wm_clear_default_size(bContext *C)
{
wmWindowManager *wm = CTX_wm_manager(C);
wmWindow *win;
-
+
/* wm context */
if (wm == NULL) {
wm = CTX_data_main(C)->wm.first;
@@ -443,7 +444,7 @@ void wm_clear_default_size(bContext *C)
if (wm == NULL || BLI_listbase_is_empty(&wm->windows)) {
return;
}
-
+
for (win = wm->windows.first; win; win = win->next) {
win->sizex = 0;
win->sizey = 0;
@@ -489,7 +490,7 @@ void wm_close_and_free(bContext *C, wmWindowManager *wm)
WM_window_set_active_workspace(win, NULL); /* prevent draw clear to use screen */
wm_window_free(C, wm, win);
}
-
+
while ((op = BLI_pophead(&wm->operators))) {
WM_operator_free(op);
}
@@ -507,7 +508,7 @@ void wm_close_and_free(bContext *C, wmWindowManager *wm)
BLI_freelistN(&wm->paintcursors);
WM_drag_free_list(&wm->drags);
-
+
wm_reports_free(wm);
if (wm->undo_stack) {
@@ -537,16 +538,16 @@ void WM_main(bContext *C)
wm_event_do_refresh_wm_and_depsgraph(C);
while (1) {
-
+
/* get events from ghost, handle window events, add to window queues */
- wm_window_process_events(C);
-
+ wm_window_process_events(C);
+
/* per window, all events to the window, screen, area and region handlers */
wm_event_do_handlers(C);
-
+
/* events have left notes about changes, we handle and cache it */
wm_event_do_notifiers(C);
-
+
/* execute cached changes draw */
wm_draw_update(C);
}
diff --git a/source/blender/windowmanager/intern/wm_cursors.c b/source/blender/windowmanager/intern/wm_cursors.c
index 67b04662154..f13dac9cb4c 100644
--- a/source/blender/windowmanager/intern/wm_cursors.c
+++ b/source/blender/windowmanager/intern/wm_cursors.c
@@ -41,7 +41,7 @@
#include "BLI_sys_types.h"
#include "DNA_listBase.h"
-#include "DNA_userdef_types.h"
+#include "DNA_userdef_types.h"
#include "DNA_workspace_types.h"
#include "BKE_context.h"
@@ -58,7 +58,7 @@
/* Some simple ghost <-> blender conversions */
-static GHOST_TStandardCursor convert_cursor(int curs)
+static GHOST_TStandardCursor convert_cursor(int curs)
{
switch (curs) {
default:
@@ -79,23 +79,23 @@ static GHOST_TStandardCursor convert_cursor(int curs)
}
}
-static void window_set_custom_cursor(wmWindow *win, unsigned char mask[16][2],
+static void window_set_custom_cursor(wmWindow *win, unsigned char mask[16][2],
unsigned char bitmap[16][2], int hotx, int hoty)
{
GHOST_SetCustomCursorShape(win->ghostwin, bitmap, mask, hotx, hoty);
}
-static void window_set_custom_cursor_ex(wmWindow *win, BCursor *cursor, int useBig)
+static void window_set_custom_cursor_ex(wmWindow *win, BCursor *cursor, int useBig)
{
if (useBig) {
- GHOST_SetCustomCursorShapeEx(win->ghostwin,
+ GHOST_SetCustomCursorShapeEx(win->ghostwin,
(GHOST_TUns8 *)cursor->big_bm, (GHOST_TUns8 *)cursor->big_mask,
cursor->big_sizex, cursor->big_sizey,
cursor->big_hotx, cursor->big_hoty,
cursor->fg_color, cursor->bg_color);
}
else {
- GHOST_SetCustomCursorShapeEx(win->ghostwin,
+ GHOST_SetCustomCursorShapeEx(win->ghostwin,
(GHOST_TUns8 *)cursor->small_bm, (GHOST_TUns8 *)cursor->small_mask,
cursor->small_sizex, cursor->small_sizey,
cursor->small_hotx, cursor->small_hoty,
@@ -132,12 +132,12 @@ void WM_cursor_set(wmWindow *win, int curs)
#endif
GHOST_SetCursorVisibility(win->ghostwin, 1);
-
+
if (curs == CURSOR_STD && win->modalcursor)
curs = win->modalcursor;
-
+
win->cursor = curs;
-
+
/* detect if we use system cursor or Blender cursor */
if (curs >= BC_GHOST_CURSORS) {
GHOST_SetCursorShape(win->ghostwin, convert_cursor(curs));
@@ -196,7 +196,7 @@ void WM_cursor_wait(bool val)
if (!G.background) {
wmWindowManager *wm = G.main->wm.first;
wmWindow *win = wm ? wm->windows.first : NULL;
-
+
for (; win; win = win->next) {
if (val) {
WM_cursor_modal_set(win, BC_WAITCURSOR);
@@ -214,7 +214,7 @@ void WM_cursor_wait(bool val)
void WM_cursor_grab_enable(wmWindow *win, bool wrap, bool hide, int bounds[4])
{
/* Only grab cursor when not running debug.
- * It helps not to get a stuck WM when hitting a breakpoint
+ * It helps not to get a stuck WM when hitting a breakpoint
* */
GHOST_TGrabCursorMode mode = GHOST_kGrabNormal;
@@ -222,7 +222,7 @@ void WM_cursor_grab_enable(wmWindow *win, bool wrap, bool hide, int bounds[4])
wm_cursor_position_to_ghost(win, &bounds[0], &bounds[1]);
wm_cursor_position_to_ghost(win, &bounds[2], &bounds[3]);
}
-
+
if (hide) {
mode = GHOST_kGrabHide;
}
@@ -311,12 +311,12 @@ void WM_cursor_time(wmWindow *win, int nr)
unsigned char mask[16][2];
unsigned char bitmap[16][2] = {{0}};
int i, idx;
-
+
if (win->lastcursor == 0)
win->lastcursor = win->cursor;
-
+
memset(&mask, 0xFF, sizeof(mask));
-
+
/* print number bottom right justified */
for (idx = 3; nr && idx >= 0; idx--) {
const char *digit = number_bitmaps[nr % 10];
@@ -327,7 +327,7 @@ void WM_cursor_time(wmWindow *win, int nr)
bitmap[i + y * 8][x] = digit[i];
nr /= 10;
}
-
+
window_set_custom_cursor(win, mask, bitmap, 7, 7);
}
@@ -441,7 +441,7 @@ BEGIN_CURSOR_BLOCK
};
BlenderCursor[BC_NS_ARROWCURSOR] = &NSArrowCursor;
-
+
END_CURSOR_BLOCK
/********************** EW_ARROW Cursor *************************/
BEGIN_CURSOR_BLOCK
@@ -462,7 +462,7 @@ BEGIN_CURSOR_BLOCK
static BCursor EWArrowCursor = {
/*small*/
ew_sbm, ew_smsk,
- 16, 16,
+ 16, 16,
7, 6,
/*big*/
NULL, NULL,
@@ -532,7 +532,7 @@ BEGIN_CURSOR_BLOCK
static BCursor WaitCursor = {
/*small*/
wait_sbm, wait_smsk,
- 16, 16,
+ 16, 16,
7, 7,
/*big*/
wait_lbm, wait_lmsk,
@@ -601,7 +601,7 @@ BEGIN_CURSOR_BLOCK
static BCursor CrossCursor = {
/*small*/
cross_sbm, cross_smsk,
- 16, 16,
+ 16, 16,
7, 7,
/*big*/
cross_lbm, cross_lmsk,
@@ -633,7 +633,7 @@ BEGIN_CURSOR_BLOCK
static BCursor EditCrossCursor = {
/*small*/
editcross_sbm, editcross_smsk,
- 16, 16,
+ 16, 16,
9, 8,
/*big*/
NULL, NULL,
@@ -666,7 +666,7 @@ BEGIN_CURSOR_BLOCK
static BCursor BoxSelCursor = {
/*small*/
box_sbm, box_smsk,
- 16, 16,
+ 16, 16,
9, 8,
/*big*/
NULL, NULL,
@@ -738,7 +738,7 @@ BEGIN_CURSOR_BLOCK
static BCursor KnifeCursor = {
/*small*/
knife_sbm, knife_smsk,
- 16, 16,
+ 16, 16,
0, 15,
/*big*/
knife_lbm, knife_lmsk,
@@ -751,7 +751,7 @@ BEGIN_CURSOR_BLOCK
BlenderCursor[BC_KNIFECURSOR] = &KnifeCursor;
END_CURSOR_BLOCK
-
+
/********************** Loop Select Cursor ***********************/
BEGIN_CURSOR_BLOCK
@@ -814,7 +814,7 @@ BEGIN_CURSOR_BLOCK
static BCursor VLoopCursor = {
/*small*/
vloop_sbm, vloop_smsk,
- 16, 16,
+ 16, 16,
0, 0,
/*big*/
vloop_lbm, vloop_lmsk,
@@ -827,7 +827,7 @@ BEGIN_CURSOR_BLOCK
BlenderCursor[BC_VLOOPCURSOR] = &VLoopCursor;
END_CURSOR_BLOCK
-
+
/********************** TextEdit Cursor ***********************/
BEGIN_CURSOR_BLOCK
@@ -848,7 +848,7 @@ BEGIN_CURSOR_BLOCK
static BCursor TextEditCursor = {
/*small*/
textedit_sbm, textedit_smsk,
- 16, 16,
+ 16, 16,
9, 8,
/*big*/
NULL, NULL,
@@ -887,7 +887,7 @@ BEGIN_CURSOR_BLOCK
static BCursor PaintBrushCursor = {
/*small*/
paintbrush_sbm, paintbrush_smsk,
- 16, 16,
+ 16, 16,
0, 15,
/*big*/
NULL, NULL,
@@ -1060,7 +1060,7 @@ BEGIN_CURSOR_BLOCK
0x7e, 0x00, 0x3f, 0x00, 0x0c, 0x00, 0x04, 0x00,
};
-
+
static BCursor EyedropperCursor = {
/*small*/
eyedropper_sbm, eyedropper_smsk,
diff --git a/source/blender/windowmanager/intern/wm_dragdrop.c b/source/blender/windowmanager/intern/wm_dragdrop.c
index 319ce99f700..16ed51cbd80 100644
--- a/source/blender/windowmanager/intern/wm_dragdrop.c
+++ b/source/blender/windowmanager/intern/wm_dragdrop.c
@@ -69,29 +69,29 @@ static ListBase dropboxes = {NULL, NULL};
typedef struct wmDropBoxMap {
struct wmDropBoxMap *next, *prev;
-
+
ListBase dropboxes;
short spaceid, regionid;
char idname[KMAP_MAX_NAME];
-
+
} wmDropBoxMap;
/* spaceid/regionid is zero for window drop maps */
ListBase *WM_dropboxmap_find(const char *idname, int spaceid, int regionid)
{
wmDropBoxMap *dm;
-
+
for (dm = dropboxes.first; dm; dm = dm->next)
if (dm->spaceid == spaceid && dm->regionid == regionid)
if (STREQLEN(idname, dm->idname, KMAP_MAX_NAME))
return &dm->dropboxes;
-
+
dm = MEM_callocN(sizeof(struct wmDropBoxMap), "dropmap list");
BLI_strncpy(dm->idname, idname, KMAP_MAX_NAME);
dm->spaceid = spaceid;
dm->regionid = regionid;
BLI_addtail(&dropboxes, dm);
-
+
return &dm->dropboxes;
}
@@ -101,31 +101,31 @@ wmDropBox *WM_dropbox_add(ListBase *lb, const char *idname, int (*poll)(bContext
void (*copy)(wmDrag *, wmDropBox *))
{
wmDropBox *drop = MEM_callocN(sizeof(wmDropBox), "wmDropBox");
-
+
drop->poll = poll;
drop->copy = copy;
drop->ot = WM_operatortype_find(idname, 0);
drop->opcontext = WM_OP_INVOKE_DEFAULT;
-
+
if (drop->ot == NULL) {
MEM_freeN(drop);
printf("Error: dropbox with unknown operator: %s\n", idname);
return NULL;
}
WM_operator_properties_alloc(&(drop->ptr), &(drop->properties), idname);
-
+
BLI_addtail(lb, drop);
-
+
return drop;
}
void wm_dropbox_free(void)
{
wmDropBoxMap *dm;
-
+
for (dm = dropboxes.first; dm; dm = dm->next) {
wmDropBox *drop;
-
+
for (drop = dm->dropboxes.first; drop; drop = drop->next) {
if (drop->ptr) {
WM_operator_properties_free(drop->ptr);
@@ -134,7 +134,7 @@ void wm_dropbox_free(void)
}
BLI_freelistN(&dm->dropboxes);
}
-
+
BLI_freelistN(&dropboxes);
}
@@ -145,10 +145,10 @@ wmDrag *WM_event_start_drag(struct bContext *C, int icon, int type, void *poin,
{
wmWindowManager *wm = CTX_wm_manager(C);
wmDrag *drag = MEM_callocN(sizeof(struct wmDrag), "new drag");
-
+
/* keep track of future multitouch drag too, add a mousepointer id or so */
/* if multiple drags are added, they're drawn as list */
-
+
BLI_addtail(&wm->drags, drag);
drag->flags = flags;
drag->icon = icon;
@@ -158,7 +158,7 @@ wmDrag *WM_event_start_drag(struct bContext *C, int icon, int type, void *poin,
else
drag->poin = poin;
drag->value = value;
-
+
return drag;
}
@@ -211,13 +211,13 @@ static const char *wm_dropbox_active(bContext *C, wmDrag *drag, const wmEvent *e
ScrArea *sa = CTX_wm_area(C);
ARegion *ar = CTX_wm_region(C);
const char *name;
-
+
name = dropbox_active(C, &win->handlers, drag, event);
if (name) return name;
-
+
name = dropbox_active(C, &sa->handlers, drag, event);
if (name) return name;
-
+
name = dropbox_active(C, &ar->handlers, drag, event);
if (name) return name;
@@ -234,16 +234,16 @@ static void wm_drop_operator_options(bContext *C, wmDrag *drag, const wmEvent *e
/* for multiwin drags, we only do this if mouse inside */
if (event->x < 0 || event->y < 0 || event->x > winsize_x || event->y > winsize_y)
return;
-
+
drag->opname[0] = 0;
-
+
/* check buttons (XXX todo rna and value) */
if (UI_but_active_drop_name(C)) {
BLI_strncpy(drag->opname, IFACE_("Paste name"), sizeof(drag->opname));
}
else {
const char *opname = wm_dropbox_active(C, drag, event);
-
+
if (opname) {
BLI_strncpy(drag->opname, opname, sizeof(drag->opname));
// WM_cursor_modal_set(win, CURSOR_COPY);
@@ -259,7 +259,7 @@ void wm_drags_check_ops(bContext *C, const wmEvent *event)
{
wmWindowManager *wm = CTX_wm_manager(C);
wmDrag *drag;
-
+
for (drag = wm->drags.first; drag; drag = drag->next) {
wm_drop_operator_options(C, drag, event);
}
@@ -312,25 +312,25 @@ void wm_drags_draw(bContext *C, wmWindow *win, rcti *rect)
wmDrag *drag;
const int winsize_y = WM_window_pixels_y(win);
int cursorx, cursory, x, y;
-
+
cursorx = win->eventstate->x;
cursory = win->eventstate->y;
if (rect) {
rect->xmin = rect->xmax = cursorx;
rect->ymin = rect->ymax = cursory;
}
-
+
/* XXX todo, multiline drag draws... but maybe not, more types mixed wont work well */
glEnable(GL_BLEND);
for (drag = wm->drags.first; drag; drag = drag->next) {
int iconsize = UI_DPI_ICON_SIZE;
int padding = 4 * UI_DPI_FAC;
-
+
/* image or icon */
if (drag->imb) {
x = cursorx - drag->sx / 2;
y = cursory - drag->sy / 2;
-
+
if (rect)
drag_rect_minmax(rect, x, y, x + drag->sx, y + drag->sy);
else {
@@ -343,13 +343,13 @@ void wm_drags_draw(bContext *C, wmWindow *win, rcti *rect)
else {
x = cursorx - 2 * padding;
y = cursory - 2 * UI_DPI_FAC;
-
+
if (rect)
drag_rect_minmax(rect, x, y, x + iconsize, y + iconsize);
else
UI_icon_draw_aspect(x, y, drag->icon, 1.0f / UI_DPI_FAC, 0.8);
}
-
+
/* item name */
if (drag->imb) {
x = cursorx - drag->sx / 2;
@@ -359,7 +359,7 @@ void wm_drags_draw(bContext *C, wmWindow *win, rcti *rect)
x = cursorx + 10 * UI_DPI_FAC;
y = cursory + 1 * UI_DPI_FAC;
}
-
+
if (rect) {
int w = UI_fontstyle_string_width(fstyle, wm_drag_name(drag));
drag_rect_minmax(rect, x, y, x + w, y + iconsize);
@@ -368,7 +368,7 @@ void wm_drags_draw(bContext *C, wmWindow *win, rcti *rect)
const unsigned char col[] = {255, 255, 255, 255};
UI_fontstyle_draw_simple(fstyle, x, y, wm_drag_name(drag), col);
}
-
+
/* operator name with roundbox */
if (drag->opname[0]) {
if (drag->imb) {
@@ -389,14 +389,14 @@ void wm_drags_draw(bContext *C, wmWindow *win, rcti *rect)
y = (cursory - iconsize) - padding;
}
}
-
+
if (rect) {
int w = UI_fontstyle_string_width(fstyle, wm_drag_name(drag));
drag_rect_minmax(rect, x, y, x + w, y + iconsize);
}
- else
+ else
wm_drop_operator_draw(drag->opname, x, y);
-
+
}
}
glDisable(GL_BLEND);
diff --git a/source/blender/windowmanager/intern/wm_draw.c b/source/blender/windowmanager/intern/wm_draw.c
index 3ce64926a95..df958f35e91 100644
--- a/source/blender/windowmanager/intern/wm_draw.c
+++ b/source/blender/windowmanager/intern/wm_draw.c
@@ -755,7 +755,7 @@ static bool wm_draw_update_test_window(wmWindow *win)
if (do_draw)
return true;
-
+
if (screen->do_refresh)
return true;
if (screen->do_draw)
@@ -766,7 +766,7 @@ static bool wm_draw_update_test_window(wmWindow *win)
return true;
if (screen->do_draw_drag)
return true;
-
+
return false;
}
@@ -788,7 +788,7 @@ void wm_draw_update(bContext *C)
#endif
GPU_free_unused_buffers();
-
+
for (win = wm->windows.first; win; win = win->next) {
#ifdef WIN32
GHOST_TWindowState state = GHOST_GetWindowState(win->ghostwin);
@@ -806,7 +806,7 @@ void wm_draw_update(bContext *C)
bScreen *screen = WM_window_get_active_screen(win);
CTX_wm_window_set(C, win);
-
+
/* sets context window+screen */
wm_window_make_drawable(wm, win);
@@ -818,7 +818,7 @@ void wm_draw_update(bContext *C)
screen->do_draw_gesture = false;
screen->do_draw_paintcursor = false;
screen->do_draw_drag = false;
-
+
wm_window_swap_buffers(win);
CTX_wm_window_set(C, NULL);
diff --git a/source/blender/windowmanager/intern/wm_event_system.c b/source/blender/windowmanager/intern/wm_event_system.c
index 31b51fce858..1e3a08bdcbc 100644
--- a/source/blender/windowmanager/intern/wm_event_system.c
+++ b/source/blender/windowmanager/intern/wm_event_system.c
@@ -105,7 +105,7 @@ static int wm_operator_call_internal(bContext *C, wmOperatorType *ot, PointerRNA
wmEvent *wm_event_add_ex(wmWindow *win, const wmEvent *event_to_add, const wmEvent *event_to_add_after)
{
wmEvent *event = MEM_mallocN(sizeof(wmEvent), "wmEvent");
-
+
*event = *event_to_add;
update_tablet_data(win, event);
@@ -157,7 +157,7 @@ void wm_event_free(wmEvent *event)
void wm_event_free_all(wmWindow *win)
{
wmEvent *event;
-
+
while ((event = BLI_pophead(&win->queue))) {
wm_event_free(event);
}
@@ -180,7 +180,7 @@ static bool wm_test_duplicate_notifier(wmWindowManager *wm, unsigned int type, v
for (note = wm->queue.first; note; note = note->next)
if ((note->category | note->data | note->subtype | note->action) == type && note->reference == reference)
return 1;
-
+
return 0;
}
@@ -194,17 +194,17 @@ void WM_event_add_notifier(const bContext *C, unsigned int type, void *reference
return;
note = MEM_callocN(sizeof(wmNotifier), "notifier");
-
+
note->wm = wm;
BLI_addtail(&note->wm->queue, note);
-
+
note->window = CTX_wm_window(C);
-
+
note->category = type & NOTE_CATEGORY;
note->data = type & NOTE_DATA;
note->subtype = type & NOTE_SUBTYPE;
note->action = type & NOTE_ACTION;
-
+
note->reference = reference;
}
@@ -218,15 +218,15 @@ void WM_main_add_notifier(unsigned int type, void *reference)
return;
note = MEM_callocN(sizeof(wmNotifier), "notifier");
-
+
note->wm = wm;
BLI_addtail(&note->wm->queue, note);
-
+
note->category = type & NOTE_CATEGORY;
note->data = type & NOTE_DATA;
note->subtype = type & NOTE_SUBTYPE;
note->action = type & NOTE_ACTION;
-
+
note->reference = reference;
}
@@ -353,7 +353,7 @@ void wm_event_do_notifiers(bContext *C)
wmWindowManager *wm = CTX_wm_manager(C);
wmNotifier *note, *next;
wmWindow *win;
-
+
if (wm == NULL)
return;
@@ -363,9 +363,9 @@ void wm_event_do_notifiers(bContext *C)
for (win = wm->windows.first; win; win = win->next) {
Scene *scene = WM_window_get_active_scene(win);
bool do_anim = false;
-
+
CTX_wm_window_set(C, win);
-
+
for (note = wm->queue.first; note; note = next) {
next = note->next;
@@ -443,7 +443,7 @@ void wm_event_do_notifiers(bContext *C)
}
}
}
-
+
/* the notifiers are sent without context, to keep it clean */
while ((note = BLI_pophead(&wm->queue))) {
for (win = wm->windows.first; win; win = win->next) {
@@ -484,7 +484,7 @@ void wm_event_do_notifiers(bContext *C)
}
}
}
-
+
MEM_freeN(note);
}
#endif /* if 1 (postpone disabling for in favor of message-bus), eventually. */
@@ -517,8 +517,8 @@ static int wm_handler_ui_call(bContext *C, wmEventHandler *handler, const wmEven
static bool do_wheel_ui = true;
const bool is_wheel = ELEM(event->type, WHEELUPMOUSE, WHEELDOWNMOUSE, MOUSEPAN);
int retval;
-
- /* UI code doesn't handle return values - it just always returns break.
+
+ /* UI code doesn't handle return values - it just always returns break.
* to make the DBL_CLICK conversion work, we just don't send this to UI, except mouse clicks */
if (((handler->flag & WM_HANDLER_ACCEPT_DBL_CLICK) == 0) &&
(event->type != LEFTMOUSE) &&
@@ -526,7 +526,7 @@ static int wm_handler_ui_call(bContext *C, wmEventHandler *handler, const wmEven
{
return WM_HANDLER_CONTINUE;
}
-
+
/* UI is quite aggressive with swallowing events, like scrollwheel */
/* I realize this is not extremely nice code... when UI gets keymaps it can be maybe smarter */
if (do_wheel_ui == false) {
@@ -535,7 +535,7 @@ static int wm_handler_ui_call(bContext *C, wmEventHandler *handler, const wmEven
else if (wm_event_always_pass(event) == 0)
do_wheel_ui = true;
}
-
+
/* we set context to where ui handler came from */
if (handler->ui_area) CTX_wm_area_set(C, handler->ui_area);
if (handler->ui_region) CTX_wm_region_set(C, handler->ui_region);
@@ -555,14 +555,14 @@ static int wm_handler_ui_call(bContext *C, wmEventHandler *handler, const wmEven
CTX_wm_region_set(C, NULL);
CTX_wm_menu_set(C, NULL);
}
-
+
if (retval == WM_UI_HANDLER_BREAK)
return WM_HANDLER_BREAK;
-
+
/* event not handled in UI, if wheel then we temporarily disable it */
if (is_wheel)
do_wheel_ui = false;
-
+
return WM_HANDLER_CONTINUE;
}
@@ -593,14 +593,14 @@ static void wm_handler_ui_cancel(bContext *C)
int WM_operator_poll(bContext *C, wmOperatorType *ot)
{
wmOperatorTypeMacro *otmacro;
-
+
for (otmacro = ot->macro.first; otmacro; otmacro = otmacro->next) {
wmOperatorType *ot_macro = WM_operatortype_find(otmacro->idname, 0);
-
+
if (0 == WM_operator_poll(C, ot_macro))
return 0;
}
-
+
/* python needs operator type, so we added exception for it */
if (ot->pyop_poll)
return ot->pyop_poll(C, ot);
@@ -807,7 +807,7 @@ static void wm_operator_reports(bContext *C, wmOperator *op, int retval, bool ca
CTX_wm_region_set(C, ar_prev);
}
}
-
+
if (retval & OPERATOR_FINISHED) {
CLOG_STR_INFO_N(WM_LOG_OPERATORS, 1, WM_operator_pystring(C, op, false, true));
@@ -885,15 +885,15 @@ static int wm_operator_exec(bContext *C, wmOperator *op, const bool repeat, cons
{
wmWindowManager *wm = CTX_wm_manager(C);
int retval = OPERATOR_CANCELLED;
-
+
CTX_wm_operator_poll_msg_set(C, NULL);
-
+
if (op == NULL || op->type == NULL)
return retval;
-
+
if (0 == WM_operator_poll(C, op->type))
return retval;
-
+
if (op->type->exec) {
if (op->type->flag & OPTYPE_UNDO) {
wm->op_undo_depth++;
@@ -912,13 +912,13 @@ static int wm_operator_exec(bContext *C, wmOperator *op, const bool repeat, cons
wm->op_undo_depth--;
}
}
-
+
/* XXX Disabled the repeat check to address part 2 of #31840.
* Carefully checked all calls to wm_operator_exec and WM_operator_repeat, don't see any reason
* why this was needed, but worth to note it in case something turns bad. (mont29) */
if (retval & (OPERATOR_FINISHED | OPERATOR_CANCELLED) /* && repeat == 0 */)
wm_operator_reports(C, op, retval, false);
-
+
if (retval & OPERATOR_FINISHED) {
wm_operator_finished(C, op, repeat, store && wm->op_undo_depth == 0);
}
@@ -928,9 +928,9 @@ static int wm_operator_exec(bContext *C, wmOperator *op, const bool repeat, cons
WM_operator_free(op);
}
}
-
+
return retval | OPERATOR_HANDLED;
-
+
}
/* simply calls exec with basic checks */
@@ -1033,11 +1033,11 @@ static wmOperator *wm_operator_create(wmWindowManager *wm, wmOperatorType *ot,
{
/* XXX operatortype names are static still. for debug */
wmOperator *op = MEM_callocN(sizeof(wmOperator), ot->idname);
-
+
/* XXX adding new operator could be function, only happens here now */
op->type = ot;
BLI_strncpy(op->idname, ot->idname, OP_MAX_TYPENAME);
-
+
/* initialize properties, either copy or create */
op->ptr = MEM_callocN(sizeof(PointerRNA), "wmOperatorPtrRNA");
if (properties && properties->data) {
@@ -1057,20 +1057,20 @@ static wmOperator *wm_operator_create(wmWindowManager *wm, wmOperatorType *ot,
op->reports = MEM_mallocN(sizeof(ReportList), "wmOperatorReportList");
BKE_reports_init(op->reports, RPT_STORE | RPT_FREE);
}
-
+
/* recursive filling of operator macro list */
if (ot->macro.first) {
static wmOperator *motherop = NULL;
wmOperatorTypeMacro *otmacro;
int root = 0;
-
+
/* ensure all ops are in execution order in 1 list */
if (motherop == NULL) {
motherop = op;
root = 1;
}
-
+
/* if properties exist, it will contain everything needed */
if (properties) {
otmacro = ot->macro.first;
@@ -1106,11 +1106,11 @@ static wmOperator *wm_operator_create(wmWindowManager *wm, wmOperatorType *ot,
opm->opm = motherop; /* pointer to mom, for modal() */
}
}
-
+
if (root)
motherop = NULL;
}
-
+
WM_operator_properties_sanitize(op->ptr, 0);
return op;
@@ -1250,7 +1250,7 @@ static int wm_operator_invoke(
wmWindowManager *wm = CTX_wm_manager(C);
wmOperator *op = wm_operator_create(wm, ot, properties, reports); /* if reports == NULL, they'll be initialized */
const bool is_nested_call = (wm->op_undo_depth != 0);
-
+
if (event != NULL) {
op->flag |= OP_IS_INVOKE;
}
@@ -1388,7 +1388,7 @@ static int wm_operator_call_internal(
const short context, const bool poll_only)
{
wmEvent *event;
-
+
int retval;
CTX_wm_operator_poll_msg_set(C, NULL);
@@ -1421,39 +1421,39 @@ static int wm_operator_call_internal(
}
switch (context) {
-
+
case WM_OP_EXEC_REGION_WIN:
- case WM_OP_INVOKE_REGION_WIN:
+ case WM_OP_INVOKE_REGION_WIN:
case WM_OP_EXEC_REGION_CHANNELS:
case WM_OP_INVOKE_REGION_CHANNELS:
case WM_OP_EXEC_REGION_PREVIEW:
case WM_OP_INVOKE_REGION_PREVIEW:
{
/* forces operator to go to the region window/channels/preview, for header menus
- * but we stay in the same region if we are already in one
+ * but we stay in the same region if we are already in one
*/
ARegion *ar = CTX_wm_region(C);
ScrArea *area = CTX_wm_area(C);
int type = RGN_TYPE_WINDOW;
-
+
switch (context) {
case WM_OP_EXEC_REGION_CHANNELS:
case WM_OP_INVOKE_REGION_CHANNELS:
type = RGN_TYPE_CHANNELS;
break;
-
+
case WM_OP_EXEC_REGION_PREVIEW:
case WM_OP_INVOKE_REGION_PREVIEW:
type = RGN_TYPE_PREVIEW;
break;
-
+
case WM_OP_EXEC_REGION_WIN:
- case WM_OP_INVOKE_REGION_WIN:
+ case WM_OP_INVOKE_REGION_WIN:
default:
type = RGN_TYPE_WINDOW;
break;
}
-
+
if (!(ar && ar->regiontype == type) && area) {
ARegion *ar1;
if (type == RGN_TYPE_WINDOW) {
@@ -1466,12 +1466,12 @@ static int wm_operator_call_internal(
if (ar1)
CTX_wm_region_set(C, ar1);
}
-
+
retval = wm_operator_invoke(C, ot, event, properties, reports, poll_only, true);
-
+
/* set region back */
CTX_wm_region_set(C, ar);
-
+
return retval;
}
case WM_OP_EXEC_AREA:
@@ -1506,7 +1506,7 @@ static int wm_operator_call_internal(
return wm_operator_invoke(C, ot, event, properties, reports, poll_only, true);
}
}
-
+
return 0;
}
@@ -1582,7 +1582,7 @@ int WM_operator_call_py(
if (!is_undo && wm) wm->op_undo_depth++;
retval = wm_operator_call_internal(C, ot, properties, reports, context, false);
-
+
if (!is_undo && wm && (wm == CTX_wm_manager(C))) wm->op_undo_depth--;
return retval;
@@ -1602,7 +1602,7 @@ static void wm_handler_op_context(bContext *C, wmEventHandler *handler, const wm
{
wmWindow *win = CTX_wm_window(C);
bScreen *screen = CTX_wm_screen(C);
-
+
if (screen && handler->op) {
if (handler->op_area == NULL)
CTX_wm_area_set(C, NULL);
@@ -1659,7 +1659,7 @@ void WM_event_remove_handlers(bContext *C, ListBase *handlers)
{
wmEventHandler *handler;
wmWindowManager *wm = CTX_wm_manager(C);
-
+
/* C is zero on freeing database, modal handlers then already were freed */
while ((handler = BLI_pophead(handlers))) {
if (handler->op) {
@@ -1667,7 +1667,7 @@ void WM_event_remove_handlers(bContext *C, ListBase *handlers)
if (handler->op->type->cancel) {
ScrArea *area = CTX_wm_area(C);
ARegion *region = CTX_wm_region(C);
-
+
wm_handler_op_context(C, handler, win->eventstate);
if (handler->op->type->flag & OPTYPE_UNDO)
@@ -1689,7 +1689,7 @@ void WM_event_remove_handlers(bContext *C, ListBase *handlers)
ScrArea *area = CTX_wm_area(C);
ARegion *region = CTX_wm_region(C);
ARegion *menu = CTX_wm_menu(C);
-
+
if (handler->ui_area) CTX_wm_area_set(C, handler->ui_area);
if (handler->ui_region) CTX_wm_region_set(C, handler->ui_region);
if (handler->ui_menu) CTX_wm_menu_set(C, handler->ui_menu);
@@ -1722,7 +1722,7 @@ int WM_userdef_event_map(int kmitype)
case WHEELINMOUSE:
return (U.uiflag & USER_WHEELZOOMDIR) ? WHEELDOWNMOUSE : WHEELUPMOUSE;
}
-
+
return kmitype;
}
@@ -1768,13 +1768,13 @@ static int wm_eventmatch(const wmEvent *winevent, wmKeyMapItem *kmi)
if (winevent->val == KM_PRESS) { /* prevent double clicks */
/* NOT using ISTEXTINPUT anymore because (at least on Windows) some key codes above 255
* could have printable ascii keys - BUG [#30479] */
- if (ISKEYBOARD(winevent->type) && (winevent->ascii || winevent->utf8_buf[0])) return 1;
+ if (ISKEYBOARD(winevent->type) && (winevent->ascii || winevent->utf8_buf[0])) return 1;
}
if (kmitype != KM_ANY) {
if (ELEM(kmitype, TABLET_STYLUS, TABLET_ERASER)) {
const wmTabletData *wmtab = winevent->tablet_data;
-
+
if (wmtab == NULL)
return 0;
else if (winevent->type != LEFTMOUSE) /* tablet events can occur on hover + keypress */
@@ -1789,10 +1789,10 @@ static int wm_eventmatch(const wmEvent *winevent, wmKeyMapItem *kmi)
return 0;
}
}
-
+
if (kmi->val != KM_ANY)
if (winevent->val != kmi->val) return 0;
-
+
/* modifiers also check bits, so it allows modifier order */
if (kmi->shift != KM_ANY)
if (winevent->shift != kmi->shift && !(winevent->shift & kmi->shift)) return 0;
@@ -1802,12 +1802,12 @@ static int wm_eventmatch(const wmEvent *winevent, wmKeyMapItem *kmi)
if (winevent->alt != kmi->alt && !(winevent->alt & kmi->alt)) return 0;
if (kmi->oskey != KM_ANY)
if (winevent->oskey != kmi->oskey && !(winevent->oskey & kmi->oskey)) return 0;
-
+
/* only keymap entry with keymodifier is checked, means all keys without modifier get handled too. */
/* that is currently needed to make overlapping events work (when you press A - G fast or so). */
if (kmi->keymodifier)
if (winevent->keymodifier != kmi->keymodifier) return 0;
-
+
return 1;
}
@@ -1825,12 +1825,12 @@ static void wm_event_modalkeymap(const bContext *C, wmOperator *op, wmEvent *eve
for (kmi = keymap->items.first; kmi; kmi = kmi->next) {
if (wm_eventmatch(event, kmi)) {
-
+
event->prevtype = event->type;
event->prevval = event->val;
event->type = EVT_MODAL_MAP;
event->val = kmi->propvalue;
-
+
break;
}
}
@@ -1883,7 +1883,7 @@ static int wm_handler_operator_call(bContext *C, ListBase *handlers, wmEventHand
wmEvent *event, PointerRNA *properties)
{
int retval = OPERATOR_PASS_THROUGH;
-
+
/* derived, modal or blocking operator */
if (handler->op) {
wmOperator *op = handler->op;
@@ -1911,7 +1911,7 @@ static int wm_handler_operator_call(bContext *C, ListBase *handlers, wmEventHand
/* warning, after this call all context data and 'event' may be freed. see check below */
retval = ot->modal(C, op, event);
OPERATOR_RETVAL_CHECK(retval);
-
+
/* when this is _not_ the case the modal modifier may have loaded
* a new blend file (demo mode does this), so we have to assume
* the event, operator etc have all been freed. - campbell */
@@ -1979,7 +1979,7 @@ static int wm_handler_operator_call(bContext *C, ListBase *handlers, wmEventHand
bool use_last_properties = true;
PointerRNA tool_properties = {{0}};
bool use_tool_properties = (handler->keymap_tool != NULL);
-
+
if (use_tool_properties) {
WM_toolsystem_ref_properties_init_for_keymap(handler->keymap_tool, &tool_properties, properties, ot);
properties = &tool_properties;
@@ -2058,11 +2058,11 @@ static int wm_handler_fileselect_do(bContext *C, ListBase *handlers, wmEventHand
sfile->op = handler->op;
ED_fileselect_set_params(sfile);
-
+
action = WM_HANDLER_BREAK;
break;
}
-
+
case EVT_FILESELECT_EXEC:
case EVT_FILESELECT_CANCEL:
case EVT_FILESELECT_EXTERNAL_CANCEL:
@@ -2150,11 +2150,11 @@ static int wm_handler_fileselect_do(bContext *C, ListBase *handlers, wmEventHand
wm->op_undo_depth++;
handler->op->type->cancel(C, handler->op);
-
+
if (handler->op->type->flag & OPTYPE_UNDO)
wm->op_undo_depth--;
}
-
+
WM_operator_free(handler->op);
}
@@ -2166,19 +2166,19 @@ static int wm_handler_fileselect_do(bContext *C, ListBase *handlers, wmEventHand
break;
}
}
-
+
return action;
}
static int wm_handler_fileselect_call(bContext *C, ListBase *handlers, wmEventHandler *handler, const wmEvent *event)
{
int action = WM_HANDLER_CONTINUE;
-
+
if (event->type != EVT_FILESELECT)
return action;
if (handler->op != (wmOperator *)event->customdata)
return action;
-
+
return wm_handler_fileselect_do(C, handlers, handler, event->val);
}
@@ -2239,7 +2239,7 @@ static int wm_handlers_do_intern(bContext *C, wmEvent *event, ListBase *handlers
for (handler = handlers->first; handler && handlers->first; handler = nexthandler) {
nexthandler = handler->next;
-
+
/* during this loop, ui handlers for nested menus can tag multiple handlers free */
if (handler->flag & WM_HANDLER_DO_FREE) {
/* pass */
@@ -2247,7 +2247,7 @@ static int wm_handlers_do_intern(bContext *C, wmEvent *event, ListBase *handlers
else if (handler_boundbox_test(handler, event)) { /* optional boundbox */
/* in advance to avoid access to freed event on window close */
always_pass = wm_event_always_pass(event);
-
+
/* modal+blocking handler */
if (handler->flag & WM_HANDLER_BLOCKING)
action |= WM_HANDLER_BREAK;
@@ -2272,7 +2272,7 @@ static int wm_handlers_do_intern(bContext *C, wmEvent *event, ListBase *handlers
event->keymap_idname = kmi->idname;
action |= wm_handler_operator_call(C, handlers, handler, event, kmi->ptr);
-
+
if (action & WM_HANDLER_BREAK) {
/* not always_pass here, it denotes removed handler */
CLOG_INFO(WM_LOG_HANDLERS, 2, "handled! '%s'", kmi->idname);
@@ -2315,24 +2315,24 @@ static int wm_handlers_do_intern(bContext *C, wmEvent *event, ListBase *handlers
if (event->custom == EVT_DATA_DRAGDROP) {
ListBase *lb = (ListBase *)event->customdata;
wmDrag *drag;
-
+
for (drag = lb->first; drag; drag = drag->next) {
if (drop->poll(C, drag, event)) {
drop->copy(drag, drop);
-
+
/* free the drags before calling operator */
WM_drag_free_list(lb);
event->customdata = NULL;
event->custom = 0;
-
+
WM_operator_name_call_ptr(C, drop->ot, drop->opcontext, drop->ptr);
action |= WM_HANDLER_BREAK;
-
+
/* XXX fileread case */
if (CTX_wm_window(C) == NULL)
return action;
-
+
/* escape from drag loop, got freed */
break;
}
@@ -2491,7 +2491,7 @@ static int wm_handlers_do_intern(bContext *C, wmEvent *event, ListBase *handlers
break;
}
}
-
+
/* XXX fileread case, if the wm is freed then the handler's
* will have been too so the code below need not run. */
if (CTX_wm_window(C) == NULL) {
@@ -2499,8 +2499,8 @@ static int wm_handlers_do_intern(bContext *C, wmEvent *event, ListBase *handlers
}
/* XXX code this for all modal ops, and ensure free only happens here */
-
- /* modal ui handler can be tagged to be freed */
+
+ /* modal ui handler can be tagged to be freed */
if (BLI_findindex(handlers, handler) != -1) { /* could be freed already by regular modal ops */
if (handler->flag & WM_HANDLER_DO_FREE) {
BLI_remlink(handlers, handler);
@@ -2521,26 +2521,56 @@ static int wm_handlers_do_intern(bContext *C, wmEvent *event, ListBase *handlers
static int wm_handlers_do(bContext *C, wmEvent *event, ListBase *handlers)
{
int action = wm_handlers_do_intern(C, event, handlers);
-
+
/* fileread case */
if (CTX_wm_window(C) == NULL)
return action;
- if (!ELEM(event->type, MOUSEMOVE, INBETWEEN_MOUSEMOVE, EVENT_NONE) && !ISTIMER(event->type)) {
+ if (ELEM(event->type, MOUSEMOVE, INBETWEEN_MOUSEMOVE)) {
+ if (event->check_drag) {
+ wmWindow *win = CTX_wm_window(C);
+ if ((abs(event->x - win->eventstate->prevclickx)) >= U.tweak_threshold ||
+ (abs(event->y - win->eventstate->prevclicky)) >= U.tweak_threshold)
+ {
+ short val = event->val;
+ short type = event->type;
+ event->val = KM_CLICK_DRAG;
+ event->type = win->eventstate->type;
+
+ CLOG_INFO(WM_LOG_HANDLERS, 1, "handling PRESS_DRAG");
+
+ action |= wm_handlers_do_intern(C, event, handlers);
+
+ event->val = val;
+ event->type = type;
+
+ win->eventstate->check_click = 0;
+ win->eventstate->check_drag = 0;
+ }
+ }
+ }
+ else if (ISMOUSE(event->type) || ISKEYBOARD(event->type)) {
+ /* All events that don't set wmEvent.prevtype must be ignored. */
/* test for CLICK events */
if (wm_action_not_handled(action)) {
wmWindow *win = CTX_wm_window(C);
-
- /* eventstate stores if previous event was a KM_PRESS, in case that
+
+ /* eventstate stores if previous event was a KM_PRESS, in case that
* wasn't handled, the KM_RELEASE will become a KM_CLICK */
-
- if (win && event->val == KM_PRESS) {
- win->eventstate->check_click = true;
+
+ if (win != NULL) {
+ if (event->val == KM_PRESS) {
+ win->eventstate->check_click = true;
+ win->eventstate->check_drag = true;
+ }
+ else if (event->val == KM_RELEASE) {
+ win->eventstate->check_drag = false;
+ }
}
-
+
if (win && win->eventstate->prevtype == event->type) {
-
+
if ((event->val == KM_RELEASE) &&
(win->eventstate->prevval == KM_PRESS) &&
(win->eventstate->check_click == true))
@@ -2551,19 +2581,20 @@ static int wm_handlers_do(bContext *C, wmEvent *event, ListBase *handlers)
event->val = KM_CLICK;
CLOG_INFO(WM_LOG_HANDLERS, 1, "handling CLICK");
-
+
action |= wm_handlers_do_intern(C, event, handlers);
event->val = KM_RELEASE;
}
else {
win->eventstate->check_click = 0;
+ win->eventstate->check_drag = 0;
}
}
else if (event->val == KM_DBL_CLICK) {
event->val = KM_PRESS;
action |= wm_handlers_do_intern(C, event, handlers);
-
+
/* revert value if not handled */
if (wm_action_not_handled(action)) {
event->val = KM_DBL_CLICK;
@@ -2578,7 +2609,7 @@ static int wm_handlers_do(bContext *C, wmEvent *event, ListBase *handlers)
win->eventstate->check_click = 0;
}
}
-
+
return action;
}
@@ -2595,7 +2626,7 @@ static ScrArea *area_event_inside(bContext *C, const int xy[2])
{
wmWindow *win = CTX_wm_window(C);
bScreen *screen = CTX_wm_screen(C);
-
+
if (screen) {
ED_screen_areas_iter(win, screen, sa) {
if (BLI_rcti_isect_pt_v(&sa->totrct, xy))
@@ -2610,7 +2641,7 @@ static ARegion *region_event_inside(bContext *C, const int xy[2])
bScreen *screen = CTX_wm_screen(C);
ScrArea *area = CTX_wm_area(C);
ARegion *ar;
-
+
if (screen && area)
for (ar = area->regionbase.first; ar; ar = ar->next)
if (BLI_rcti_isect_pt_v(&ar->winrct, xy))
@@ -2635,22 +2666,22 @@ static void wm_paintcursor_tag(bContext *C, wmPaintCursor *pc, ARegion *ar)
static void wm_paintcursor_test(bContext *C, const wmEvent *event)
{
wmWindowManager *wm = CTX_wm_manager(C);
-
+
if (wm->paintcursors.first) {
ARegion *ar = CTX_wm_region(C);
-
+
if (ar)
wm_paintcursor_tag(C, wm->paintcursors.first, ar);
-
+
/* if previous position was not in current region, we have to set a temp new context */
if (ar == NULL || !BLI_rcti_isect_pt_v(&ar->winrct, &event->prevx)) {
ScrArea *sa = CTX_wm_area(C);
-
+
CTX_wm_area_set(C, area_event_inside(C, &event->prevx));
CTX_wm_region_set(C, region_event_inside(C, &event->prevx));
wm_paintcursor_tag(C, wm->paintcursors.first, CTX_wm_region(C));
-
+
CTX_wm_area_set(C, sa);
CTX_wm_region_set(C, ar);
}
@@ -2664,7 +2695,7 @@ static void wm_event_drag_test(wmWindowManager *wm, wmWindow *win, wmEvent *even
if (BLI_listbase_is_empty(&wm->drags)) {
return;
}
-
+
if (event->type == MOUSEMOVE || ISKEYMODIFIER(event->type)) {
screen->do_draw_drag = true;
}
@@ -2675,20 +2706,20 @@ static void wm_event_drag_test(wmWindowManager *wm, wmWindow *win, wmEvent *even
}
else if (event->type == LEFTMOUSE && event->val == KM_RELEASE) {
event->type = EVT_DROP;
-
+
/* create customdata, first free existing */
if (event->customdata) {
if (event->customdatafree)
MEM_freeN(event->customdata);
}
-
+
event->custom = EVT_DATA_DRAGDROP;
event->customdata = &wm->drags;
event->customdatafree = 1;
-
+
/* clear drop icon */
screen->do_draw_drag = true;
-
+
/* restore cursor (disabled, see wm_dragdrop.c) */
// WM_cursor_modal_restore(win);
}
@@ -2738,12 +2769,12 @@ void wm_event_do_handlers(bContext *C)
if (scene) {
int is_playing_sound = BKE_sound_scene_playing(scene);
-
+
if (is_playing_sound != -1) {
bool is_playing_screen;
CTX_wm_window_set(C, win);
CTX_data_scene_set(C, scene);
-
+
is_playing_screen = (ED_screen_animation_playing(wm) != NULL);
if (((is_playing_sound == 1) && (is_playing_screen == 0)) ||
@@ -2751,7 +2782,7 @@ void wm_event_do_handlers(bContext *C)
{
ED_screen_animation_play(C, -1, 1);
}
-
+
if (is_playing_sound == 0) {
const float time = BKE_sound_sync_scene(scene);
if (isfinite(time)) {
@@ -2764,14 +2795,14 @@ void wm_event_do_handlers(bContext *C)
}
}
}
-
+
CTX_data_scene_set(C, NULL);
CTX_wm_screen_set(C, NULL);
CTX_wm_window_set(C, NULL);
}
}
}
-
+
while ( (event = win->queue.first) ) {
int action = WM_HANDLER_CONTINUE;
@@ -2805,16 +2836,16 @@ void wm_event_do_handlers(bContext *C)
/* we let modal handlers get active area/region, also wm_paintcursor_test needs it */
CTX_wm_area_set(C, area_event_inside(C, &event->x));
CTX_wm_region_set(C, region_event_inside(C, &event->x));
-
+
/* MVC demands to not draw in event handlers... but we need to leave it for ogl selecting etc */
wm_window_make_drawable(wm, win);
-
+
wm_region_mouse_co(C, event);
/* first we do priority handlers, modal + some limited keymaps */
action |= wm_handlers_do(C, event, &win->modalhandlers);
-
+
/* fileread case */
if (CTX_wm_window(C) == NULL)
return;
@@ -2830,13 +2861,13 @@ void wm_event_do_handlers(bContext *C)
/* check dragging, creates new event or frees, adds draw tag */
wm_event_drag_test(wm, win, event);
-
+
/* builtin tweak, if action is break it removes tweak */
wm_tweakevent_test(C, event, action);
if ((action & WM_HANDLER_BREAK) == 0) {
ARegion *ar;
-
+
/* Note: setting subwin active should be done here, after modal handlers have been done */
if (event->type == MOUSEMOVE) {
/* state variables in screen, cursors. Also used in wm_draw.c, fails for modal handlers though */
@@ -2871,7 +2902,7 @@ void wm_event_do_handlers(bContext *C)
for (ar = sa->regionbase.first; ar; ar = ar->next) {
if (wm_event_inside_i(event, &ar->winrct)) {
CTX_wm_region_set(C, ar);
-
+
/* call even on non mouse events, since the */
wm_region_mouse_co(C, event);
@@ -2945,7 +2976,7 @@ void wm_event_do_handlers(bContext *C)
/* NOTE: do not escape on WM_HANDLER_BREAK, mousemove needs handled for previous area */
}
}
-
+
if ((action & WM_HANDLER_BREAK) == 0) {
/* also some non-modal handlers need active area/region */
CTX_wm_area_set(C, area_event_inside(C, &event->x));
@@ -2969,9 +3000,9 @@ void wm_event_do_handlers(bContext *C)
/* unlink and free here, blender-quit then frees all */
BLI_remlink(&win->queue, event);
wm_event_free(event);
-
+
}
-
+
/* only add mousemove when queue was read entirely */
if (win->addmousemove && win->eventstate) {
wmEvent tevent = *(win->eventstate);
@@ -2982,7 +3013,7 @@ void wm_event_do_handlers(bContext *C)
wm_event_add(win, &tevent);
win->addmousemove = 0;
}
-
+
CTX_wm_window_set(C, NULL);
}
@@ -2997,10 +3028,10 @@ void WM_event_fileselect_event(wmWindowManager *wm, void *ophandle, int eventval
{
/* add to all windows! */
wmWindow *win;
-
+
for (win = wm->windows.first; win; win = win->next) {
wmEvent event = *win->eventstate;
-
+
event.type = EVT_FILESELECT;
event.val = eventval;
event.customdata = ophandle; // only as void pointer type check
@@ -3027,7 +3058,7 @@ void WM_event_add_fileselect(bContext *C, wmOperator *op)
/* only allow 1 file selector open per window */
for (handler = win->modalhandlers.first; handler; handler = handlernext) {
handlernext = handler->next;
-
+
if (handler->type == WM_HANDLER_FILESELECT) {
bScreen *screen = CTX_wm_screen(C);
bool cancel_handler = true;
@@ -3052,16 +3083,16 @@ void WM_event_add_fileselect(bContext *C, wmOperator *op)
}
}
}
-
+
handler = MEM_callocN(sizeof(wmEventHandler), "fileselect handler");
-
+
handler->type = WM_HANDLER_FILESELECT;
handler->op = op;
handler->op_area = CTX_wm_area(C);
handler->op_region = CTX_wm_region(C);
-
+
BLI_addhead(&win->modalhandlers, handler);
-
+
/* check props once before invoking if check is available
* ensures initial properties are valid */
if (op->type->check) {
@@ -3083,7 +3114,7 @@ wmEventHandler *WM_event_add_modal_handler(bContext *C, wmOperator *op)
{
wmEventHandler *handler = MEM_callocN(sizeof(wmEventHandler), "event modal handler");
wmWindow *win = CTX_wm_window(C);
-
+
/* operator was part of macro */
if (op->opm) {
/* give the mother macro to the handler */
@@ -3093,11 +3124,11 @@ wmEventHandler *WM_event_add_modal_handler(bContext *C, wmOperator *op)
}
else
handler->op = 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);
return handler;
@@ -3144,7 +3175,7 @@ wmEventHandler *WM_event_add_keymap_handler(ListBase *handlers, wmKeyMap *keymap
for (handler = handlers->first; handler; handler = handler->next)
if (handler->keymap == keymap)
return handler;
-
+
handler = MEM_callocN(sizeof(wmEventHandler), "event keymap handler");
BLI_addtail(handlers, handler);
handler->keymap = keymap;
@@ -3156,20 +3187,20 @@ wmEventHandler *WM_event_add_keymap_handler(ListBase *handlers, wmKeyMap *keymap
wmEventHandler *WM_event_add_keymap_handler_priority(ListBase *handlers, wmKeyMap *keymap, int UNUSED(priority))
{
wmEventHandler *handler;
-
+
WM_event_remove_keymap_handler(handlers, keymap);
-
+
handler = MEM_callocN(sizeof(wmEventHandler), "event keymap handler");
BLI_addhead(handlers, handler);
handler->keymap = keymap;
-
+
return handler;
}
wmEventHandler *WM_event_add_keymap_handler_bb(ListBase *handlers, wmKeyMap *keymap, const rcti *bblocal, const rcti *bbwin)
{
wmEventHandler *handler = WM_event_add_keymap_handler(handlers, keymap);
-
+
if (handler) {
handler->bblocal = bblocal;
handler->bbwin = bbwin;
@@ -3180,7 +3211,7 @@ wmEventHandler *WM_event_add_keymap_handler_bb(ListBase *handlers, wmKeyMap *key
void WM_event_remove_keymap_handler(ListBase *handlers, wmKeyMap *keymap)
{
wmEventHandler *handler;
-
+
for (handler = handlers->first; handler; handler = handler->next) {
if (handler->keymap == keymap) {
BLI_remlink(handlers, handler);
@@ -3221,9 +3252,9 @@ wmEventHandler *WM_event_add_ui_handler(
BLI_assert((flag & WM_HANDLER_DO_FREE) == 0);
handler->flag = flag;
-
+
BLI_addhead(handlers, handler);
-
+
return handler;
}
@@ -3234,7 +3265,7 @@ void WM_event_remove_ui_handler(
void *userdata, const bool postpone)
{
wmEventHandler *handler;
-
+
for (handler = handlers->first; handler; handler = handler->next) {
if ((handler->ui_handle == ui_handle) &&
(handler->ui_remove == ui_remove) &&
@@ -3279,13 +3310,13 @@ wmEventHandler *WM_event_add_dropbox_handler(ListBase *handlers, ListBase *dropb
for (handler = handlers->first; handler; handler = handler->next)
if (handler->dropboxes == dropboxes)
return handler;
-
+
handler = MEM_callocN(sizeof(wmEventHandler), "dropbox handler");
-
+
/* dropbox stored static, no free or copy */
handler->dropboxes = dropboxes;
BLI_addhead(handlers, handler);
-
+
return handler;
}
@@ -3316,7 +3347,7 @@ static void WM_event_remove_handler(ListBase *handlers, wmEventHandler *handler)
void WM_event_add_mousemove(const bContext *C)
{
wmWindow *window = CTX_wm_window(C);
-
+
window->addmousemove = 1;
}
@@ -3324,7 +3355,7 @@ void WM_event_add_mousemove(const bContext *C)
/* for modal callbacks, check configuration for how to interpret exit with tweaks */
bool WM_event_is_modal_tweak_exit(const wmEvent *event, int tweak_event)
{
- /* if the release-confirm userpref setting is enabled,
+ /* if the release-confirm userpref setting is enabled,
* tweak events can be canceled when mouse is released
*/
if (U.flag & USER_RELEASECONFIRM) {
@@ -3353,13 +3384,13 @@ bool WM_event_is_modal_tweak_exit(const wmEvent *event, int tweak_event)
if (event->val != KM_RELEASE)
return 1;
}
-
+
return 0;
}
/* ********************* ghost stuff *************** */
-static int convert_key(GHOST_TKey key)
+static int convert_key(GHOST_TKey key)
{
if (key >= GHOST_kKeyA && key <= GHOST_kKeyZ) {
return (AKEY + ((int) key - GHOST_kKeyA));
@@ -3438,7 +3469,7 @@ static int convert_key(GHOST_TKey key)
case GHOST_kKeyMediaStop: return MEDIASTOP;
case GHOST_kKeyMediaFirst: return MEDIAFIRST;
case GHOST_kKeyMediaLast: return MEDIALAST;
-
+
default:
return UNKNOWNKEY; /* GHOST_kKeyUnknown */
}
@@ -3450,11 +3481,11 @@ static void wm_eventemulation(wmEvent *event)
/* 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 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;
@@ -3480,9 +3511,9 @@ static void wm_eventemulation(wmEvent *event)
emulating_event = EVENT_NONE;
}
}
-
+
}
-
+
/* numpad emulation */
if (U.flag & USER_NONUMPAD) {
switch (event->type) {
@@ -3507,16 +3538,16 @@ static void wm_eventemulation(wmEvent *event)
static void update_tablet_data(wmWindow *win, wmEvent *event)
{
const GHOST_TabletData *td = GHOST_GetTabletData(win->ghostwin);
-
+
/* if there's tablet data from an active tablet device then add it */
if ((td != NULL) && td->Active != GHOST_kTabletModeNone) {
struct wmTabletData *wmtab = MEM_mallocN(sizeof(wmTabletData), "customdata tablet");
-
+
wmtab->Active = (int)td->Active;
wmtab->Pressure = td->Pressure;
wmtab->Xtilt = td->Xtilt;
wmtab->Ytilt = td->Ytilt;
-
+
event->tablet_data = wmtab;
// printf("%s: using tablet %.5f\n", __func__, wmtab->Pressure);
}
@@ -3559,40 +3590,40 @@ static void attach_ndof_data(wmEvent *event, const GHOST_TEventNDOFMotionData *g
static wmWindow *wm_event_cursor_other_windows(wmWindowManager *wm, wmWindow *win, wmEvent *event)
{
int mx = event->x, my = event->y;
-
+
if (wm->windows.first == wm->windows.last)
return NULL;
-
+
/* in order to use window size and mouse position (pixels), we have to use a WM function */
-
+
/* check if outside, include top window bar... */
if (mx < 0 || my < 0 || mx > WM_window_pixels_x(win) || my > WM_window_pixels_y(win) + 30) {
wmWindow *owin;
wmEventHandler *handler;
-
+
/* let's skip windows having modal handlers now */
/* potential XXX ugly... I wouldn't have added a modalhandlers list (introduced in rev 23331, ton) */
for (handler = win->modalhandlers.first; handler; handler = handler->next)
if (handler->ui_handle || handler->op)
return NULL;
-
+
/* to desktop space */
mx += (int) (U.pixelsize * win->posx);
my += (int) (U.pixelsize * win->posy);
-
+
/* check other windows to see if it has mouse inside */
for (owin = wm->windows.first; owin; owin = owin->next) {
-
+
if (owin != win) {
int posx = (int) (U.pixelsize * owin->posx);
int posy = (int) (U.pixelsize * owin->posy);
-
+
if (mx - posx >= 0 && owin->posy >= 0 &&
mx - posx <= WM_window_pixels_x(owin) && my - posy <= WM_window_pixels_y(owin))
{
event->x = mx - (int)(U.pixelsize * owin->posx);
event->y = my - (int)(U.pixelsize * owin->posy);
-
+
return owin;
}
}
@@ -3671,7 +3702,7 @@ void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, int U
copy_v2_v2_int(&evt->x, &event_new->x);
evt->is_motion_absolute = event_new->is_motion_absolute;
}
-
+
/* also add to other window if event is there, this makes overdraws disappear nicely */
/* it remaps mousecoord to other window in event */
owin = wm_event_cursor_other_windows(wm, win, &event);
@@ -3688,7 +3719,7 @@ void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, int U
oevt->is_motion_absolute = event_new->is_motion_absolute;
}
}
-
+
break;
}
case GHOST_kEventTrackpad:
@@ -3712,11 +3743,11 @@ 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 = KM_NOTHING;
-
+
/* Use prevx/prevy so we can calculate the delta later */
event.prevx = event.x - pd->deltaX;
event.prevy = event.y - (-pd->deltaY);
-
+
wm_event_add(win, &event);
break;
}
@@ -3725,10 +3756,10 @@ void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, int U
case GHOST_kEventButtonUp:
{
GHOST_TEventButtonData *bd = customdata;
-
+
/* get value and type from ghost */
event.val = (type == GHOST_kEventButtonDown) ? KM_PRESS : KM_RELEASE;
-
+
if (bd->button == GHOST_kButtonMaskLeft)
event.type = LEFTMOUSE;
else if (bd->button == GHOST_kButtonMaskRight)
@@ -3743,9 +3774,9 @@ void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, int U
event.type = BUTTON7MOUSE;
else
event.type = MIDDLEMOUSE;
-
+
wm_eventemulation(&event);
-
+
/* copy previous state to prev event state (two old!) */
evt->prevval = evt->val;
evt->prevtype = evt->type;
@@ -3756,14 +3787,14 @@ void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, int U
if (win->active == 0) {
int cx, cy;
-
+
/* entering window, update mouse pos. (ghost sends win-activate *after* the mouseclick in window!) */
wm_get_cursor_position(win, &cx, &cy);
event.x = evt->x = cx;
event.y = evt->y = cy;
}
-
+
/* double click test */
if (wm_event_is_double_click(&event, evt)) {
CLOG_INFO(WM_LOG_HANDLERS, 1, "Send double click");
@@ -3774,23 +3805,23 @@ void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, int U
evt->prevclickx = event.x;
evt->prevclicky = event.y;
}
-
+
/* add to other window if event is there (not to both!) */
owin = wm_event_cursor_other_windows(wm, win, &event);
if (owin) {
wmEvent oevent = *(owin->eventstate);
-
+
oevent.x = event.x;
oevent.y = event.y;
oevent.type = event.type;
oevent.val = event.val;
-
+
wm_event_add(owin, &oevent);
}
else {
wm_event_add(win, &event);
}
-
+
break;
}
/* keyboard */
@@ -3803,9 +3834,9 @@ void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, int U
event.ascii = kd->ascii;
memcpy(event.utf8_buf, kd->utf8_buf, sizeof(event.utf8_buf)); /* might be not null terminated*/
event.val = (type == GHOST_kEventKeyDown) ? KM_PRESS : KM_RELEASE;
-
+
wm_eventemulation(&event);
-
+
/* copy previous state to prev event state (two old!) */
evt->prevval = evt->val;
evt->prevtype = evt->type;
@@ -3813,7 +3844,7 @@ void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, int U
/* copy to event state */
evt->val = event.val;
evt->type = event.type;
-
+
/* exclude arrow keys, esc, etc from text input */
if (type == GHOST_kEventKeyUp) {
event.ascii = '\0';
@@ -3887,19 +3918,19 @@ void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, int U
CLOG_INFO(WM_LOG_HANDLERS, 1, "Send double click");
evt->val = event.val = KM_DBL_CLICK;
}
-
+
/* this case happens on holding a key pressed, it should not generate
* press events events with the same key as modifier */
if (event.keymodifier == event.type)
event.keymodifier = 0;
-
+
/* this case happens with an external numpad, and also when using 'dead keys' (to compose complex latin
* characters e.g.), it's not really clear why.
* Since it's impossible to map a key modifier to an unknown key, it shouldn't harm to clear it. */
if (event.keymodifier == UNKNOWNKEY) {
evt->keymodifier = event.keymodifier = 0;
}
-
+
/* if test_break set, it catches this. Do not set with modifier presses. XXX Keep global for now? */
if ((event.type == ESCKEY && event.val == KM_PRESS) &&
/* check other modifiers because ms-windows uses these to bring up the task manager */
@@ -3907,31 +3938,34 @@ void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, int U
{
G.is_break = true;
}
-
+
/* double click test - only for press */
if (event.val == KM_PRESS) {
- evt->prevclicktime = PIL_check_seconds_timer();
- evt->prevclickx = event.x;
- evt->prevclicky = event.y;
+ /* Don't reset timer & location when holding the key generates repeat events. */
+ if ((evt->prevtype != event.type) || (evt->prevval != KM_PRESS)) {
+ evt->prevclicktime = PIL_check_seconds_timer();
+ evt->prevclickx = event.x;
+ evt->prevclicky = event.y;
+ }
}
-
+
wm_event_add(win, &event);
-
+
break;
}
-
+
case GHOST_kEventWheel:
{
GHOST_TEventWheelData *wheelData = customdata;
-
+
if (wheelData->z > 0)
event.type = WHEELUPMOUSE;
else
event.type = WHEELDOWNMOUSE;
-
+
event.val = KM_PRESS;
wm_event_add(win, &event);
-
+
break;
}
case GHOST_kEventTimer:
diff --git a/source/blender/windowmanager/intern/wm_files.c b/source/blender/windowmanager/intern/wm_files.c
index 68be37ef709..3aaec875627 100644
--- a/source/blender/windowmanager/intern/wm_files.c
+++ b/source/blender/windowmanager/intern/wm_files.c
@@ -152,27 +152,27 @@ static void wm_window_match_init(bContext *C, ListBase *wmlist)
{
wmWindowManager *wm;
wmWindow *win, *active_win;
-
+
*wmlist = G.main->wm;
BLI_listbase_clear(&G.main->wm);
-
+
active_win = CTX_wm_window(C);
/* first wrap up running stuff */
/* code copied from wm_init_exit.c */
for (wm = wmlist->first; wm; wm = wm->id.next) {
-
+
WM_jobs_kill_all(wm);
-
+
for (win = wm->windows.first; win; win = win->next) {
-
+
CTX_wm_window_set(C, win); /* needed by operator close callbacks */
WM_event_remove_handlers(C, &win->handlers);
WM_event_remove_handlers(C, &win->modalhandlers);
ED_screen_exit(C, win, WM_window_get_active_screen(win));
}
}
-
+
/* reset active window */
CTX_wm_window_set(C, active_win);
@@ -215,6 +215,7 @@ static void wm_window_match_keep_current_wm(
const bool load_ui,
ListBase *r_new_wm_list)
{
+ Main *bmain = CTX_data_main(C);
wmWindowManager *wm = current_wm_list->first;
bScreen *screen = NULL;
@@ -236,7 +237,7 @@ static void wm_window_match_keep_current_wm(
}
else {
WorkSpaceLayout *layout_old = WM_window_get_active_layout(win);
- WorkSpaceLayout *layout_new = ED_workspace_layout_duplicate(workspace, layout_old, win);
+ WorkSpaceLayout *layout_new = ED_workspace_layout_duplicate(bmain, workspace, layout_old, win);
WM_window_set_active_layout(win, workspace, layout_new);
}
@@ -339,8 +340,8 @@ static void wm_window_match_do(
static void wm_init_userdef(Main *bmain, const bool read_userdef_from_memory)
{
/* versioning is here */
- UI_init_userdef();
-
+ UI_init_userdef(bmain);
+
MEM_CacheLimiter_set_maximum(((size_t)U.memcachelimit) * 1024 * 1024);
BKE_sound_init(bmain);
@@ -569,7 +570,7 @@ bool WM_file_read(bContext *C, const char *filepath, ReportList *reports)
/* it throws error box when file doesn't exist and returns -1 */
/* note; it should set some error message somewhere... (ton) */
retval = wm_read_exotic(filepath);
-
+
/* we didn't succeed, now try to read Blender file */
if (retval == BKE_READ_EXOTIC_OK_BLEND) {
int G_f = G.f;
@@ -578,12 +579,16 @@ bool WM_file_read(bContext *C, const char *filepath, ReportList *reports)
/* put aside screens to match with persistent windows later */
/* also exit screens and editors */
wm_window_match_init(C, &wmbase);
-
+
/* confusing this global... */
G.relbase_valid = 1;
retval = BKE_blendfile_read(C, filepath, reports, 0);
+
+ /* BKE_file_read sets new Main into context. */
+ Main *bmain = CTX_data_main(C);
+
/* when loading startup.blend's, we can be left with a blank path */
- if (G.main->name[0]) {
+ if (BKE_main_blendfile_path(bmain)) {
G.save_over = 1;
}
else {
@@ -599,14 +604,14 @@ bool WM_file_read(bContext *C, const char *filepath, ReportList *reports)
}
/* match the read WM with current WM */
- wm_window_match_do(C, &wmbase, &G.main->wm, &G.main->wm);
+ wm_window_match_do(C, &wmbase, &bmain->wm, &bmain->wm);
WM_check(C); /* opens window(s), checks keymaps */
if (retval == BKE_BLENDFILE_READ_OK_USERPREFS) {
/* in case a userdef is read from regular .blend */
- wm_init_userdef(G.main, false);
+ wm_init_userdef(bmain, false);
}
-
+
if (retval != BKE_BLENDFILE_READ_FAIL) {
if (do_history) {
wm_history_file_update();
@@ -672,6 +677,7 @@ int wm_homefile_read(
bool use_factory_settings, bool use_empty_data, bool use_userdef,
const char *filepath_startup_override, const char *app_template_override)
{
+ Main *bmain = G.main; /* Context does not always have valid main pointer here... */
ListBase wmbase;
bool success = false;
@@ -863,16 +869,18 @@ int wm_homefile_read(
* can remove this eventually, only in a 2.53 and older, now its not written */
G.fileflags &= ~G_FILE_RELATIVE_REMAP;
- if (use_userdef) {
+ bmain = CTX_data_main(C);
+
+ if (use_userdef) {
/* check userdef before open window, keymaps etc */
- wm_init_userdef(CTX_data_main(C), read_userdef_from_memory);
+ wm_init_userdef(bmain, read_userdef_from_memory);
}
-
+
/* match the read WM with current WM */
- wm_window_match_do(C, &wmbase, &G.main->wm, &G.main->wm);
+ wm_window_match_do(C, &wmbase, &bmain->wm, &bmain->wm);
WM_check(C); /* opens window(s), checks keymaps */
- G.main->name[0] = '\0';
+ bmain->name[0] = '\0';
/* start with save preference untitled.blend */
G.save_over = 0;
@@ -913,7 +921,7 @@ void wm_history_file_read(void)
num++;
}
}
-
+
BLI_file_free_lines(lines);
}
@@ -969,16 +977,18 @@ static void wm_history_file_write(void)
static void wm_history_file_update(void)
{
RecentFile *recent;
+ const char *blendfile_name = BKE_main_blendfile_path_from_global();
/* no write history for recovered startup files */
- if (G.main->name[0] == 0)
+ if (blendfile_name[0] == '\0') {
return;
+ }
recent = G.recent_files.first;
/* refresh recent-files.txt of recent opened files, when current file was changed */
- if (!(recent) || (BLI_path_cmp(recent->filepath, G.main->name) != 0)) {
+ if (!(recent) || (BLI_path_cmp(recent->filepath, blendfile_name) != 0)) {
- recent = wm_file_history_find(G.main->name);
+ recent = wm_file_history_find(blendfile_name);
if (recent) {
BLI_remlink(&G.recent_files, recent);
}
@@ -988,7 +998,7 @@ static void wm_history_file_update(void)
recent_next = recent->next;
wm_history_file_free(recent);
}
- recent = wm_history_file_new(G.main->name);
+ recent = wm_history_file_new(blendfile_name);
}
/* add current file to the beginning of list */
@@ -998,7 +1008,7 @@ static void wm_history_file_update(void)
wm_history_file_write();
/* also update most recent files on System */
- GHOST_addToSystemRecentFiles(G.main->name);
+ GHOST_addToSystemRecentFiles(blendfile_name);
}
}
@@ -1066,7 +1076,7 @@ static ImBuf *blend_file_thumb(const bContext *C, Scene *scene, bScreen *screen,
/* add pretty overlay */
IMB_thumb_overlay_blend(ibuf->rect, ibuf->x, ibuf->y, aspect);
-
+
thumb = BKE_main_thumbnail_from_imbuf(NULL, ibuf);
}
else {
@@ -1074,10 +1084,10 @@ static ImBuf *blend_file_thumb(const bContext *C, Scene *scene, bScreen *screen,
fprintf(stderr, "blend_file_thumb failed to create thumbnail: %s\n", err_out);
thumb = NULL;
}
-
+
/* must be freed by caller */
*thumb_pt = thumb;
-
+
return ibuf;
}
@@ -1087,7 +1097,7 @@ bool write_crash_blend(void)
char path[FILE_MAX];
int fileflags = G.fileflags & ~(G_FILE_HISTORY); /* don't do file history on crash file */
- BLI_strncpy(path, G.main->name, sizeof(path));
+ BLI_strncpy(path, BKE_main_blendfile_path_from_global(), sizeof(path));
BLI_replace_extension(path, sizeof(path), "_crash.blend");
if (BLO_write_file(G.main, path, fileflags, NULL, NULL)) {
printf("written: %s\n", path);
@@ -1104,6 +1114,7 @@ bool write_crash_blend(void)
*/
static int wm_file_write(bContext *C, const char *filepath, int fileflags, ReportList *reports)
{
+ Main *bmain = CTX_data_main(C);
Library *li;
int len;
int ret = -1;
@@ -1111,7 +1122,7 @@ static int wm_file_write(bContext *C, const char *filepath, int fileflags, Repor
ImBuf *ibuf_thumb = NULL;
len = strlen(filepath);
-
+
if (len == 0) {
BKE_report(reports, RPT_ERROR, "Path is empty, cannot save");
return ret;
@@ -1121,7 +1132,7 @@ static int wm_file_write(bContext *C, const char *filepath, int fileflags, Repor
BKE_report(reports, RPT_ERROR, "Path too long, cannot save");
return ret;
}
-
+
/* Check if file write permission is ok */
if (BLI_exists(filepath) && !BLI_file_is_writable(filepath)) {
BKE_reportf(reports, RPT_ERROR, "Cannot save blend file, path '%s' is not writable", filepath);
@@ -1131,9 +1142,9 @@ static int wm_file_write(bContext *C, const char *filepath, int fileflags, Repor
/* note: used to replace the file extension (to ensure '.blend'),
* no need to now because the operator ensures,
* its handy for scripts to save to a predefined name without blender editing it */
-
+
/* send the OnSave event */
- for (li = G.main->library.first; li; li = li->id.next) {
+ for (li = bmain->library.first; li; li = li->id.next) {
if (BLI_path_cmp(li->filepath, filepath) == 0) {
BKE_reportf(reports, RPT_ERROR, "Cannot overwrite used library '%.240s'", filepath);
return ret;
@@ -1141,12 +1152,12 @@ static int wm_file_write(bContext *C, const char *filepath, int fileflags, Repor
}
/* Call pre-save callbacks befores writing preview, that way you can generate custom file thumbnail... */
- BLI_callback_exec(G.main, NULL, BLI_CB_EVT_SAVE_PRE);
+ BLI_callback_exec(bmain, NULL, BLI_CB_EVT_SAVE_PRE);
/* blend file thumbnail */
/* save before exit_editmode, otherwise derivedmeshes for shared data corrupt #27765) */
/* Main now can store a .blend thumbnail, usefull for background mode or thumbnail customization. */
- main_thumb = thumb = CTX_data_main(C)->blen_thumb;
+ main_thumb = thumb = bmain->blen_thumb;
if ((U.flag & USER_SAVE_PREVIEWS) && BLI_thread_is_main()) {
ibuf_thumb = blend_file_thumb(C, CTX_data_scene(C), CTX_wm_screen(C), &thumb);
}
@@ -1154,32 +1165,32 @@ static int wm_file_write(bContext *C, const char *filepath, int fileflags, Repor
/* operator now handles overwrite checks */
if (G.fileflags & G_AUTOPACK) {
- packAll(G.main, reports, false);
+ packAll(bmain, reports, false);
}
/* don't forget not to return without! */
WM_cursor_wait(1);
-
+
ED_editors_flush_edits(C, false);
fileflags |= G_FILE_HISTORY; /* write file history */
/* first time saving */
/* XXX temp solution to solve bug, real fix coming (ton) */
- if ((G.main->name[0] == '\0') && !(fileflags & G_FILE_SAVE_COPY)) {
- BLI_strncpy(G.main->name, filepath, sizeof(G.main->name));
+ if ((BKE_main_blendfile_path(bmain)[0] == '\0') && !(fileflags & G_FILE_SAVE_COPY)) {
+ BLI_strncpy(bmain->name, filepath, sizeof(bmain->name));
}
/* XXX temp solution to solve bug, real fix coming (ton) */
- G.main->recovered = 0;
-
+ bmain->recovered = 0;
+
if (BLO_write_file(CTX_data_main(C), filepath, fileflags, reports, thumb)) {
const bool do_history = (G.background == false) && (CTX_wm_manager(C)->op_undo_depth == 0);
if (!(fileflags & G_FILE_SAVE_COPY)) {
G.relbase_valid = 1;
- BLI_strncpy(G.main->name, filepath, sizeof(G.main->name)); /* is guaranteed current file */
-
+ BLI_strncpy(bmain->name, filepath, sizeof(bmain->name)); /* is guaranteed current file */
+
G.save_over = 1; /* disable untitled.blend convention */
}
@@ -1190,7 +1201,7 @@ static int wm_file_write(bContext *C, const char *filepath, int fileflags, Repor
wm_history_file_update();
}
- BLI_callback_exec(G.main, NULL, BLI_CB_EVT_SAVE_POST);
+ BLI_callback_exec(bmain, NULL, BLI_CB_EVT_SAVE_POST);
/* run this function after because the file cant be written before the blend is */
if (ibuf_thumb) {
@@ -1224,7 +1235,7 @@ void wm_autosave_location(char *filepath)
#endif
if (G.main && G.relbase_valid) {
- const char *basename = BLI_path_basename(G.main->name);
+ const char *basename = BLI_path_basename(BKE_main_blendfile_path_from_global());
int len = strlen(basename) - 6;
BLI_snprintf(path, sizeof(path), "%.*s.blend", len, basename);
}
@@ -1264,7 +1275,7 @@ void wm_autosave_timer(const bContext *C, wmWindowManager *wm, wmTimer *UNUSED(w
wmWindow *win;
wmEventHandler *handler;
char filepath[FILE_MAX];
-
+
WM_event_remove_timer(wm, NULL, wm->autosavetimer);
/* if a modal operator is running, don't autosave, but try again in 10 seconds */
@@ -1313,7 +1324,7 @@ void wm_autosave_timer_ended(wmWindowManager *wm)
void wm_autosave_delete(void)
{
char filename[FILE_MAX];
-
+
wm_autosave_location(filename);
if (BLI_exists(filename)) {
@@ -1754,7 +1765,8 @@ struct FileRuntime {
static int wm_open_mainfile_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
{
- const char *openname = G.main->name;
+ Main *bmain = CTX_data_main(C);
+ const char *openname = BKE_main_blendfile_path(bmain);
if (CTX_wm_window(C) == NULL) {
/* in rare cases this could happen, when trying to invoke in background
@@ -1893,6 +1905,7 @@ void WM_OT_open_mainfile(wmOperatorType *ot)
static int wm_revert_mainfile_exec(bContext *C, wmOperator *op)
{
+ Main *bmain = CTX_data_main(C);
bool success;
char filepath[FILE_MAX];
@@ -1903,7 +1916,7 @@ static int wm_revert_mainfile_exec(bContext *C, wmOperator *op)
else
G.f &= ~G_SCRIPT_AUTOEXEC;
- BLI_strncpy(filepath, G.main->name, sizeof(filepath));
+ BLI_strncpy(filepath, BKE_main_blendfile_path(bmain), sizeof(filepath));
success = wm_file_read_opwrap(C, filepath, op->reports, !(G.f & G_SCRIPT_AUTOEXEC));
if (success) {
@@ -1941,6 +1954,7 @@ void WM_OT_revert_mainfile(wmOperatorType *ot)
void WM_recover_last_session(bContext *C, ReportList *reports)
{
+ Main *bmain = CTX_data_main(C);
char filepath[FILE_MAX];
BLI_make_file_string("/", filepath, BKE_tempdir_base(), BLENDER_QUIT_FILE);
@@ -1953,8 +1967,9 @@ void WM_recover_last_session(bContext *C, ReportList *reports)
G.fileflags &= ~G_FILE_RECOVER;
/* XXX bad global... fixme */
- if (G.main->name[0])
+ if (BKE_main_blendfile_path(bmain)[0] != '\0') {
G.file_loaded = 1; /* prevents splash to show */
+ }
else {
G.relbase_valid = 0;
G.save_over = 0; /* start with save preference untitled.blend */
@@ -2053,20 +2068,21 @@ static void save_set_compress(wmOperator *op)
}
}
-static void save_set_filepath(wmOperator *op)
+static void save_set_filepath(bContext *C, wmOperator *op)
{
+ Main *bmain = CTX_data_main(C);
PropertyRNA *prop;
char name[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) {
+ if (BKE_main_blendfile_path(bmain)[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);
+ BLI_strncpy(name, bmain->name, FILE_MAX);
}
wm_filepath_default(name);
@@ -2078,7 +2094,7 @@ static int wm_save_as_mainfile_invoke(bContext *C, wmOperator *op, const wmEvent
{
save_set_compress(op);
- save_set_filepath(op);
+ save_set_filepath(C, op);
WM_event_add_fileselect(C, op);
@@ -2088,6 +2104,7 @@ static int wm_save_as_mainfile_invoke(bContext *C, wmOperator *op, const wmEvent
/* function used for WM_OT_save_mainfile too */
static int wm_save_as_mainfile_exec(bContext *C, wmOperator *op)
{
+ Main *bmain = CTX_data_main(C);
char path[FILE_MAX];
int fileflags;
@@ -2097,7 +2114,7 @@ static int wm_save_as_mainfile_exec(bContext *C, wmOperator *op)
RNA_string_get(op->ptr, "filepath", path);
}
else {
- BLI_strncpy(path, G.main->name, FILE_MAX);
+ BLI_strncpy(path, BKE_main_blendfile_path(bmain), FILE_MAX);
wm_filepath_default(path);
}
@@ -2193,7 +2210,7 @@ static int wm_save_mainfile_invoke(bContext *C, wmOperator *op, const wmEvent *U
return OPERATOR_CANCELLED;
save_set_compress(op);
- save_set_filepath(op);
+ save_set_filepath(C, 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] */
diff --git a/source/blender/windowmanager/intern/wm_files_link.c b/source/blender/windowmanager/intern/wm_files_link.c
index 0f2da2e8f36..c7d55b290f5 100644
--- a/source/blender/windowmanager/intern/wm_files_link.c
+++ b/source/blender/windowmanager/intern/wm_files_link.c
@@ -115,7 +115,7 @@ static int wm_link_append_invoke(bContext *C, wmOperator *op, const wmEvent *UNU
}
else if (G.relbase_valid) {
char path[FILE_MAX];
- BLI_strncpy(path, G.main->name, sizeof(G.main->name));
+ BLI_strncpy(path, BKE_main_blendfile_path_from_global(), sizeof(path));
BLI_parent_dir(path);
RNA_string_set(op->ptr, "filepath", path);
}
@@ -333,7 +333,7 @@ static int wm_link_append_exec(bContext *C, wmOperator *op)
BKE_reportf(op->reports, RPT_ERROR, "'%s': nothing indicated", path);
return OPERATOR_CANCELLED;
}
- else if (BLI_path_cmp(bmain->name, libname) == 0) {
+ else if (BLI_path_cmp(BKE_main_blendfile_path(bmain), libname) == 0) {
BKE_reportf(op->reports, RPT_ERROR, "'%s': cannot use current file as library", path);
return OPERATOR_CANCELLED;
}
@@ -372,7 +372,7 @@ static int wm_link_append_exec(bContext *C, wmOperator *op)
if (view_layer && RNA_boolean_get(op->ptr, "autoselect")) {
BKE_view_layer_base_deselect_all(view_layer);
}
-
+
/* tag everything, all untagged data can be made local
* its also generally useful to know what is new
*
@@ -531,18 +531,18 @@ void WM_OT_link(wmOperatorType *ot)
ot->name = "Link from Library";
ot->idname = "WM_OT_link";
ot->description = "Link from a Library .blend file";
-
+
ot->invoke = wm_link_append_invoke;
ot->exec = wm_link_append_exec;
ot->poll = wm_link_append_poll;
-
+
ot->flag |= OPTYPE_UNDO;
WM_operator_properties_filesel(
ot, FILE_TYPE_FOLDER | FILE_TYPE_BLENDER | FILE_TYPE_BLENDERLIB, FILE_LOADLIB, FILE_OPENFILE,
WM_FILESEL_FILEPATH | WM_FILESEL_DIRECTORY | WM_FILESEL_FILENAME | WM_FILESEL_RELPATH | WM_FILESEL_FILES,
FILE_DEFAULTDISPLAY, FILE_SORT_ALPHA);
-
+
wm_link_append_properties_common(ot, true);
}
diff --git a/source/blender/windowmanager/intern/wm_gesture.c b/source/blender/windowmanager/intern/wm_gesture.c
index 2c3583a9f02..144bb38ae76 100644
--- a/source/blender/windowmanager/intern/wm_gesture.c
+++ b/source/blender/windowmanager/intern/wm_gesture.c
@@ -63,20 +63,20 @@ wmGesture *WM_gesture_new(bContext *C, const wmEvent *event, int type)
wmGesture *gesture = MEM_callocN(sizeof(wmGesture), "new gesture");
wmWindow *window = CTX_wm_window(C);
ARegion *ar = CTX_wm_region(C);
-
+
BLI_addtail(&window->gesture, gesture);
-
+
gesture->type = type;
gesture->event_type = event->type;
gesture->winrct = ar->winrct;
gesture->userdata_free = true; /* Free if userdata is set. */
gesture->modal_state = GESTURE_MODAL_NOP;
-
+
if (ELEM(type, WM_GESTURE_RECT, WM_GESTURE_CROSS_RECT, WM_GESTURE_TWEAK,
WM_GESTURE_CIRCLE, WM_GESTURE_STRAIGHTLINE))
{
rcti *rect = MEM_callocN(sizeof(rcti), "gesture rect new");
-
+
gesture->customdata = rect;
rect->xmin = event->x - gesture->winrct.xmin;
rect->ymin = event->y - gesture->winrct.ymin;
@@ -96,14 +96,14 @@ wmGesture *WM_gesture_new(bContext *C, const wmEvent *event, int type)
lasso[1] = event->y - gesture->winrct.ymin;
gesture->points = 1;
}
-
+
return gesture;
}
void WM_gesture_end(bContext *C, wmGesture *gesture)
{
wmWindow *win = CTX_wm_window(C);
-
+
if (win->tweak == gesture)
win->tweak = NULL;
BLI_remlink(&win->gesture, gesture);
@@ -117,7 +117,7 @@ void WM_gesture_end(bContext *C, wmGesture *gesture)
void WM_gestures_remove(bContext *C)
{
wmWindow *win = CTX_wm_window(C);
-
+
while (win->gesture.first)
WM_gesture_end(C, win->gesture.first);
}
@@ -141,7 +141,7 @@ int wm_gesture_evaluate(wmGesture *gesture)
else if (theta == -1) val = EVT_GESTURE_SE;
else if (theta == -2) val = EVT_GESTURE_S;
else if (theta == -3) val = EVT_GESTURE_SW;
-
+
#if 0
/* debug */
if (val == 1) printf("tweak north\n");
@@ -421,7 +421,7 @@ void wm_gesture_draw(wmWindow *win)
for (; gt; gt = gt->next) {
/* all in subwindow space */
wmViewport(&gt->winrct);
-
+
if (gt->type == WM_GESTURE_RECT)
wm_gesture_draw_rect(gt);
// else if (gt->type == WM_GESTURE_TWEAK)
@@ -448,7 +448,7 @@ void wm_gesture_draw(wmWindow *win)
void wm_gesture_tag_redraw(bContext *C)
{
bScreen *screen = CTX_wm_screen(C);
-
+
if (screen)
screen->do_draw_gesture = true;
}
diff --git a/source/blender/windowmanager/intern/wm_init_exit.c b/source/blender/windowmanager/intern/wm_init_exit.c
index 480287ce6b1..c5a57147dd6 100644
--- a/source/blender/windowmanager/intern/wm_init_exit.c
+++ b/source/blender/windowmanager/intern/wm_init_exit.c
@@ -186,6 +186,8 @@ void WM_init_opengl(void)
GPU_set_anisotropic(U.anisotropic_filter);
GPU_set_gpu_mipmapping(U.use_gpu_mipmap);
+ GPU_pass_cache_init();
+
#ifdef WITH_OPENSUBDIV
BKE_subsurf_osd_init();
#endif
@@ -195,7 +197,7 @@ void WM_init_opengl(void)
/* only called once, for startup */
void WM_init(bContext *C, int argc, const char **argv)
{
-
+
if (!G.background) {
wm_ghost_init(C); /* note: it assigns C to ghost! */
wm_init_cursor_data();
@@ -222,12 +224,12 @@ void WM_init(bContext *C, int argc, const char **argv)
BKE_spacedata_callback_id_remap_set(ED_spacedata_id_remap); /* screen.c */
DEG_editors_set_update_cb(ED_render_id_flush_update,
ED_render_scene_update);
-
+
ED_spacetypes_init(); /* editors/space_api/spacetype.c */
-
+
ED_file_init(); /* for fsmenu */
ED_node_init_butfuncs();
-
+
BLF_init();
BLT_lang_init();
@@ -293,11 +295,11 @@ void WM_init(bContext *C, int argc, const char **argv)
/* allow a path of "", this is what happens when making a new file */
#if 0
- if (G.main->name[0] == 0)
+ if (BKE_main_blendfile_path_from_global()[0] == '\0')
BLI_make_file_string("/", G.main->name, BKE_appdir_folder_default(), "untitled.blend");
#endif
- BLI_strncpy(G.lib, G.main->name, FILE_MAX);
+ BLI_strncpy(G.lib, BKE_main_blendfile_path_from_global(), sizeof(G.lib));
#ifdef WITH_COMPOSITOR
if (1) {
@@ -305,7 +307,7 @@ void WM_init(bContext *C, int argc, const char **argv)
COM_linker_hack = COM_execute;
}
#endif
-
+
/* load last session, uses regular file reading so it has to be in end (after init py etc) */
if (U.uiflag2 & USER_KEEP_SESSION) {
/* calling WM_recover_last_session(C, NULL) has been moved to creator.c */
@@ -338,7 +340,7 @@ void WM_init_splash(bContext *C)
if ((U.uiflag & USER_SPLASH_DISABLE) == 0) {
wmWindowManager *wm = CTX_wm_manager(C);
wmWindow *prevwin = CTX_wm_window(C);
-
+
if (wm->windows.first) {
CTX_wm_window_set(C, wm->windows.first);
WM_operator_name_call(C, "WM_OT_splash", WM_OP_INVOKE_DEFAULT, NULL);
@@ -351,10 +353,10 @@ void WM_init_splash(bContext *C)
static void free_openrecent(void)
{
struct RecentFile *recent;
-
+
for (recent = G.recent_files.first; recent; recent = recent->next)
MEM_freeN(recent->filepath);
-
+
BLI_freelistN(&(G.recent_files));
}
@@ -437,11 +439,11 @@ void WM_exit_ext(bContext *C, const bool do_python)
}
}
}
-
+
WM_jobs_kill_all(wm);
for (win = wm->windows.first; win; win = win->next) {
-
+
CTX_wm_window_set(C, win); /* needed by operator close callbacks */
WM_event_remove_handlers(C, &win->handlers);
WM_event_remove_handlers(C, &win->modalhandlers);
@@ -462,13 +464,13 @@ void WM_exit_ext(bContext *C, const bool do_python)
ED_undosys_type_free();
free_openrecent();
-
+
BKE_mball_cubeTable_free();
-
+
/* render code might still access databases */
RE_FreeAllRender();
RE_engines_exit();
-
+
ED_preview_free_dbase(); /* frees a Main dbase, before BKE_blender_free! */
if (C && wm)
@@ -478,7 +480,7 @@ void WM_exit_ext(bContext *C, const bool do_python)
BKE_tracking_clipboard_free();
BKE_mask_clipboard_free();
BKE_vfont_clipboard_free();
-
+
#ifdef WITH_COMPOSITOR
COM_deinitialize();
#endif
@@ -492,7 +494,7 @@ void WM_exit_ext(bContext *C, const bool do_python)
GPU_exit();
}
-
+
BKE_blender_free(); /* blender.c, does entire library and spacetypes */
// free_matcopybuf();
ANIM_fcurves_copybuf_free();
@@ -521,11 +523,11 @@ void WM_exit_ext(bContext *C, const bool do_python)
BLF_free_unifont_mono();
BLT_lang_free();
#endif
-
+
ANIM_keyingset_infos_exit();
-
+
// free_txt_data();
-
+
#ifdef WITH_PYTHON
/* option not to close python so we can use 'atexit' */
@@ -549,11 +551,11 @@ void WM_exit_ext(bContext *C, const bool do_python)
BKE_blender_userdef_data_free(&U, false);
RNA_exit(); /* should be after BPY_python_end so struct python slots are cleared */
-
+
wm_ghost_exit();
CTX_free(C);
-
+
GHOST_DisposeSystemPaths();
DNA_sdna_current_free();
diff --git a/source/blender/windowmanager/intern/wm_jobs.c b/source/blender/windowmanager/intern/wm_jobs.c
index 28f978909f7..3a4195ae1ae 100644
--- a/source/blender/windowmanager/intern/wm_jobs.c
+++ b/source/blender/windowmanager/intern/wm_jobs.c
@@ -78,10 +78,10 @@
struct wmJob {
struct wmJob *next, *prev;
-
+
/* job originating from, keep track of this when deleting windows */
wmWindow *win;
-
+
/* should store entire own context, for start, update, free */
void *customdata;
/* to prevent cpu overhead, use this one which only gets called when job really starts, not in thread */
@@ -95,14 +95,14 @@ struct wmJob {
void (*free)(void *);
/* gets called when job is stopped, not in thread */
void (*endjob)(void *);
-
+
/* running jobs each have own timer */
double timestep;
wmTimer *wt;
/* the notifier event timers should send */
unsigned int note, endnote;
-
-
+
+
/* internal */
void *owner;
int flag;
@@ -115,7 +115,7 @@ struct wmJob {
/* once running, we store this separately */
void *run_customdata;
void (*run_free)(void *);
-
+
/* we use BLI_threads api, but per job only 1 thread runs */
ListBase threads;
@@ -152,7 +152,7 @@ static void wm_job_main_thread_yield(wmJob *wm_job)
static wmJob *wm_job_find(wmWindowManager *wm, void *owner, const int job_type)
{
wmJob *wm_job;
-
+
if (owner && job_type) {
for (wm_job = wm->jobs.first; wm_job; wm_job = wm_job->next)
if (wm_job->owner == owner && wm_job->job_type == job_type)
@@ -168,7 +168,7 @@ static wmJob *wm_job_find(wmWindowManager *wm, void *owner, const int job_type)
if (wm_job->job_type == job_type)
return wm_job;
}
-
+
return NULL;
}
@@ -183,7 +183,7 @@ static wmJob *wm_job_find(wmWindowManager *wm, void *owner, const int job_type)
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);
-
+
if (wm_job == NULL) {
wm_job = MEM_callocN(sizeof(wmJob), "new job");
@@ -198,7 +198,7 @@ wmJob *WM_jobs_get(wmWindowManager *wm, wmWindow *win, void *owner, const char *
WM_job_main_thread_lock_acquire(wm_job);
}
/* else: a running job, be careful */
-
+
/* prevent creating a job with an invalid type */
BLI_assert(wm_job->job_type != WM_JOB_TYPE_ANY);
@@ -209,7 +209,7 @@ wmJob *WM_jobs_get(wmWindowManager *wm, wmWindow *win, void *owner, const char *
bool WM_jobs_test(wmWindowManager *wm, void *owner, int job_type)
{
wmJob *wm_job;
-
+
/* job can be running or about to run (suspended) */
for (wm_job = wm->jobs.first; wm_job; wm_job = wm_job->next) {
if (wm_job->owner == owner) {
@@ -227,10 +227,10 @@ bool WM_jobs_test(wmWindowManager *wm, void *owner, int job_type)
float WM_jobs_progress(wmWindowManager *wm, void *owner)
{
wmJob *wm_job = wm_job_find(wm, owner, WM_JOB_TYPE_ANY);
-
+
if (wm_job && wm_job->flag & WM_JOB_PROGRESS)
return wm_job->progress;
-
+
return 0.0;
}
@@ -248,30 +248,30 @@ double WM_jobs_starttime(wmWindowManager *wm, void *owner)
char *WM_jobs_name(wmWindowManager *wm, void *owner)
{
wmJob *wm_job = wm_job_find(wm, owner, WM_JOB_TYPE_ANY);
-
+
if (wm_job)
return wm_job->name;
-
+
return NULL;
}
void *WM_jobs_customdata(wmWindowManager *wm, void *owner)
{
wmJob *wm_job = wm_job_find(wm, owner, WM_JOB_TYPE_ANY);
-
+
if (wm_job)
return WM_jobs_customdata_get(wm_job);
-
+
return NULL;
}
void *WM_jobs_customdata_from_type(wmWindowManager *wm, int job_type)
{
wmJob *wm_job = wm_job_find(wm, NULL, job_type);
-
+
if (wm_job)
return WM_jobs_customdata_get(wm_job);
-
+
return NULL;
}
@@ -301,7 +301,7 @@ void WM_jobs_customdata_set(wmJob *wm_job, void *customdata, void (*free)(void *
/* pending job? just free */
if (wm_job->customdata)
wm_job->free(wm_job->customdata);
-
+
wm_job->customdata = customdata;
wm_job->free = free;
@@ -333,10 +333,10 @@ void WM_jobs_callbacks(wmJob *wm_job,
static void *do_job_thread(void *job_v)
{
wmJob *wm_job = job_v;
-
+
wm_job->startjob(wm_job->run_customdata, &wm_job->stop, &wm_job->do_update, &wm_job->progress);
wm_job->ready = true;
-
+
return NULL;
}
@@ -345,7 +345,7 @@ static void wm_jobs_test_suspend_stop(wmWindowManager *wm, wmJob *test)
{
wmJob *wm_job;
bool suspend = false;
-
+
/* job added with suspend flag, we wait 1 timer step before activating it */
if (test->flag & WM_JOB_SUSPEND) {
suspend = true;
@@ -358,12 +358,12 @@ static void wm_jobs_test_suspend_stop(wmWindowManager *wm, wmJob *test)
if (wm_job == test || !wm_job->running) {
continue;
}
-
+
/* if new job is not render, then check for same startjob */
if (0 == (test->flag & WM_JOB_EXCL_RENDER))
if (wm_job->startjob != test->startjob)
continue;
-
+
/* if new job is render, any render job should be stopped */
if (test->flag & WM_JOB_EXCL_RENDER)
if (0 == (wm_job->flag & WM_JOB_EXCL_RENDER))
@@ -378,7 +378,7 @@ static void wm_jobs_test_suspend_stop(wmWindowManager *wm, wmJob *test)
}
}
}
-
+
/* Possible suspend ourselves, waiting for other jobs, or de-suspend. */
test->suspended = suspend;
// if (suspend) printf("job suspended: %s\n", test->name);
@@ -396,11 +396,11 @@ void WM_jobs_start(wmWindowManager *wm, wmJob *wm_job)
// printf("job started a running job, ending... %s\n", wm_job->name);
}
else {
-
+
if (wm_job->customdata && wm_job->startjob) {
-
+
wm_jobs_test_suspend_stop(wm, wm_job);
-
+
if (wm_job->suspended == false) {
/* copy to ensure proper free in end */
wm_job->run_customdata = wm_job->customdata;
@@ -408,20 +408,20 @@ void WM_jobs_start(wmWindowManager *wm, wmJob *wm_job)
wm_job->free = NULL;
wm_job->customdata = NULL;
wm_job->running = true;
-
+
if (wm_job->initjob)
wm_job->initjob(wm_job->run_customdata);
-
+
wm_job->stop = false;
wm_job->ready = false;
wm_job->progress = 0.0;
// printf("job started: %s\n", wm_job->name);
-
+
BLI_threadpool_init(&wm_job->threads, do_job_thread, 1);
BLI_threadpool_insert(&wm_job->threads, wm_job);
}
-
+
/* restarted job has timer already */
if (wm_job->wt == NULL)
wm_job->wt = WM_event_add_timer(wm, wm_job->win, TIMERJOBS, wm_job->timestep);
@@ -456,14 +456,14 @@ static void wm_jobs_kill_job(wmWindowManager *wm, wmJob *wm_job)
if (wm_job->endjob)
wm_job->endjob(wm_job->run_customdata);
}
-
+
if (wm_job->wt)
WM_event_remove_timer(wm, wm_job->win, wm_job->wt);
if (wm_job->customdata)
wm_job->free(wm_job->customdata);
if (wm_job->run_customdata)
wm_job->run_free(wm_job->run_customdata);
-
+
/* remove wm_job */
wm_job_free(wm, wm_job);
}
@@ -472,17 +472,17 @@ static void wm_jobs_kill_job(wmWindowManager *wm, wmJob *wm_job)
void WM_jobs_kill_all(wmWindowManager *wm)
{
wmJob *wm_job;
-
+
while ((wm_job = wm->jobs.first))
wm_jobs_kill_job(wm, wm_job);
-
+
}
/* wait until every job ended, except for one owner (used in undo to keep screen job alive) */
void WM_jobs_kill_all_except(wmWindowManager *wm, void *owner)
{
wmJob *wm_job, *next_job;
-
+
for (wm_job = wm->jobs.first; wm_job; wm_job = next_job) {
next_job = wm_job->next;
@@ -495,7 +495,7 @@ void WM_jobs_kill_all_except(wmWindowManager *wm, void *owner)
void WM_jobs_kill_type(struct wmWindowManager *wm, void *owner, int job_type)
{
wmJob *wm_job, *next_job;
-
+
for (wm_job = wm->jobs.first; wm_job; wm_job = next_job) {
next_job = wm_job->next;
@@ -509,7 +509,7 @@ void WM_jobs_kill_type(struct wmWindowManager *wm, void *owner, int job_type)
void WM_jobs_stop(wmWindowManager *wm, void *owner, void *startjob)
{
wmJob *wm_job;
-
+
for (wm_job = wm->jobs.first; wm_job; wm_job = wm_job->next) {
if (wm_job->owner == owner || wm_job->startjob == startjob) {
if (wm_job->running) {
@@ -523,7 +523,7 @@ void WM_jobs_stop(wmWindowManager *wm, void *owner, void *startjob)
void WM_jobs_kill(wmWindowManager *wm, void *owner, void (*startjob)(void *, short int *, short int *, float *))
{
wmJob *wm_job;
-
+
wm_job = wm->jobs.first;
while (wm_job) {
if (wm_job->owner == owner || wm_job->startjob == startjob) {
@@ -542,7 +542,7 @@ void WM_jobs_kill(wmWindowManager *wm, void *owner, void (*startjob)(void *, sho
void wm_jobs_timer_ended(wmWindowManager *wm, wmTimer *wt)
{
wmJob *wm_job;
-
+
for (wm_job = wm->jobs.first; wm_job; wm_job = wm_job->next) {
if (wm_job->wt == wt) {
wm_jobs_kill_job(wm, wm_job);
@@ -557,18 +557,18 @@ void wm_jobs_timer(const bContext *C, wmWindowManager *wm, wmTimer *wt)
wmJob *wm_job, *wm_jobnext;
float total_progress = 0.f;
float jobs_progress = 0;
-
+
for (wm_job = wm->jobs.first; wm_job; wm_job = wm_jobnext) {
wm_jobnext = wm_job->next;
-
+
if (wm_job->wt == wt) {
-
+
/* running threads */
if (wm_job->threads.first) {
/* let threads get temporary lock over main thread if needed */
wm_job_main_thread_yield(wm_job);
-
+
/* always call note and update when ready */
if (wm_job->do_update || wm_job->ready) {
if (wm_job->update)
@@ -580,7 +580,7 @@ void wm_jobs_timer(const bContext *C, wmWindowManager *wm, wmTimer *wt)
WM_event_add_notifier(C, NC_WM | ND_JOB, NULL);
wm_job->do_update = false;
}
-
+
if (wm_job->ready) {
if (wm_job->endjob)
wm_job->endjob(wm_job->run_customdata);
@@ -589,7 +589,7 @@ void wm_jobs_timer(const bContext *C, wmWindowManager *wm, wmTimer *wt)
wm_job->run_free(wm_job->run_customdata);
wm_job->run_customdata = NULL;
wm_job->run_free = NULL;
-
+
// if (wm_job->stop) printf("job ready but stopped %s\n", wm_job->name);
// else printf("job finished %s\n", wm_job->name);
@@ -603,10 +603,10 @@ void wm_jobs_timer(const bContext *C, wmWindowManager *wm, wmTimer *wt)
WM_job_main_thread_lock_release(wm_job);
BLI_threadpool_end(&wm_job->threads);
WM_job_main_thread_lock_acquire(wm_job);
-
+
if (wm_job->endnote)
WM_event_add_notifier(C, wm_job->endnote, NULL);
-
+
WM_event_add_notifier(C, NC_WM | ND_JOB, NULL);
/* new job added for wm_job? */
@@ -617,7 +617,7 @@ void wm_jobs_timer(const bContext *C, wmWindowManager *wm, wmTimer *wt)
else {
WM_event_remove_timer(wm, wm_job->win, wm_job->wt);
wm_job->wt = NULL;
-
+
/* remove wm_job */
wm_job_free(wm, wm_job);
}
@@ -640,8 +640,8 @@ void wm_jobs_timer(const bContext *C, wmWindowManager *wm, wmTimer *wt)
}
}
}
-
-
+
+
/* if there are running jobs, set the global progress indicator */
if (jobs_progress > 0) {
wmWindow *win;
@@ -656,7 +656,7 @@ void wm_jobs_timer(const bContext *C, wmWindowManager *wm, wmTimer *wt)
for (win = wm->windows.first; win; win = win->next)
WM_progress_clear(win);
}
-
+
}
bool WM_jobs_has_running(wmWindowManager *wm)
diff --git a/source/blender/windowmanager/intern/wm_keymap.c b/source/blender/windowmanager/intern/wm_keymap.c
index 1fcfcee0a4c..67493454e8f 100644
--- a/source/blender/windowmanager/intern/wm_keymap.c
+++ b/source/blender/windowmanager/intern/wm_keymap.c
@@ -238,7 +238,7 @@ static wmKeyMapDiffItem *wm_keymap_diff_item_copy(wmKeyMapDiffItem *kmdi)
kmdin->add_item = wm_keymap_item_copy(kmdi->add_item);
if (kmdi->remove_item)
kmdin->remove_item = wm_keymap_item_copy(kmdi->remove_item);
-
+
return kmdin;
}
@@ -261,7 +261,7 @@ static void wm_keymap_diff_item_free(wmKeyMapDiffItem *kmdi)
wmKeyConfig *WM_keyconfig_new(wmWindowManager *wm, const char *idname)
{
wmKeyConfig *keyconf;
-
+
keyconf = MEM_callocN(sizeof(wmKeyConfig), "wmKeyConfig");
BLI_strncpy(keyconf->idname, idname, sizeof(keyconf->idname));
BLI_addtail(&wm->keyconfigs, keyconf);
@@ -316,7 +316,7 @@ static wmKeyConfig *WM_keyconfig_active(wmWindowManager *wm)
keyconf = BLI_findstring(&wm->keyconfigs, U.keyconfigstr, offsetof(wmKeyConfig, idname));
if (keyconf)
return keyconf;
-
+
/* otherwise use default */
return wm->defaultconf;
}
@@ -457,16 +457,16 @@ static void keymap_item_set_id(wmKeyMap *keymap, wmKeyMapItem *kmi)
wmKeyMapItem *WM_keymap_verify_item(wmKeyMap *keymap, const char *idname, int type, int val, int modifier, int keymodifier)
{
wmKeyMapItem *kmi;
-
+
for (kmi = keymap->items.first; kmi; kmi = kmi->next)
if (STREQLEN(kmi->idname, idname, OP_MAX_TYPENAME))
break;
if (kmi == NULL) {
kmi = MEM_callocN(sizeof(wmKeyMapItem), "keymap entry");
-
+
BLI_addtail(&keymap->items, kmi);
BLI_strncpy(kmi->idname, idname, OP_MAX_TYPENAME);
-
+
keymap_item_set_id(keymap, kmi);
keymap_event_set(kmi, type, val, modifier, keymodifier);
@@ -479,7 +479,7 @@ wmKeyMapItem *WM_keymap_verify_item(wmKeyMap *keymap, const char *idname, int ty
wmKeyMapItem *WM_keymap_add_item(wmKeyMap *keymap, const char *idname, int type, int val, int modifier, int keymodifier)
{
wmKeyMapItem *kmi = MEM_callocN(sizeof(wmKeyMapItem), "keymap entry");
-
+
BLI_addtail(&keymap->items, kmi);
BLI_strncpy(kmi->idname, idname, OP_MAX_TYPENAME);
@@ -557,7 +557,7 @@ static wmKeyMapItem *wm_keymap_find_item_equals(wmKeyMap *km, wmKeyMapItem *need
for (kmi = km->items.first; kmi; kmi = kmi->next)
if (wm_keymap_item_equals(kmi, needle))
return kmi;
-
+
return NULL;
}
@@ -568,7 +568,7 @@ static wmKeyMapItem *wm_keymap_find_item_equals_result(wmKeyMap *km, wmKeyMapIte
for (kmi = km->items.first; kmi; kmi = kmi->next)
if (wm_keymap_item_equals_result(kmi, needle))
return kmi;
-
+
return NULL;
}
@@ -731,7 +731,7 @@ static wmKeyMap *wm_keymap_patch_update(ListBase *lb, wmKeyMap *defaultmap, wmKe
/* add to list */
BLI_addtail(lb, km);
-
+
return km;
}
@@ -779,7 +779,7 @@ static void wm_keymap_diff_update(ListBase *lb, wmKeyMap *defaultmap, wmKeyMap *
/* ****************** storage in WM ************ */
-/* name id's are for storing general or multiple keymaps,
+/* name id's are for storing general or multiple keymaps,
* space/region ids are same as DNA_space_types.h */
/* gets freed in wm.c */
@@ -791,21 +791,21 @@ wmKeyMap *WM_keymap_list_find(ListBase *lb, const char *idname, int spaceid, int
if (km->spaceid == spaceid && km->regionid == regionid)
if (STREQLEN(idname, km->idname, KMAP_MAX_NAME))
return km;
-
+
return NULL;
}
wmKeyMap *WM_keymap_find(wmKeyConfig *keyconf, const char *idname, int spaceid, int regionid)
{
wmKeyMap *km = WM_keymap_list_find(&keyconf->keymaps, idname, spaceid, regionid);
-
+
if (km == NULL) {
km = wm_keymap_new(idname, spaceid, regionid);
BLI_addtail(&keyconf->keymaps, km);
WM_keyconfig_update_tag(km, NULL);
}
-
+
return km;
}
@@ -838,19 +838,19 @@ wmKeyMap *WM_modalkeymap_add(wmKeyConfig *keyconf, const char *idname, const Enu
}
}
}
-
+
return km;
}
wmKeyMap *WM_modalkeymap_get(wmKeyConfig *keyconf, const char *idname)
{
wmKeyMap *km;
-
+
for (km = keyconf->keymaps.first; km; km = km->next)
if (km->flag & KEYMAP_MODAL)
if (STREQLEN(idname, km->idname, KMAP_MAX_NAME))
break;
-
+
return km;
}
@@ -858,10 +858,10 @@ wmKeyMap *WM_modalkeymap_get(wmKeyConfig *keyconf, const char *idname)
wmKeyMapItem *WM_modalkeymap_add_item(wmKeyMap *km, int type, int val, int modifier, int keymodifier, int value)
{
wmKeyMapItem *kmi = MEM_callocN(sizeof(wmKeyMapItem), "keymap entry");
-
+
BLI_addtail(&km->items, kmi);
kmi->propvalue = value;
-
+
keymap_event_set(kmi, type, val, modifier, keymodifier);
keymap_item_set_id(km, kmi);
@@ -1129,7 +1129,7 @@ static wmKeyMapItem *wm_keymap_item_find_handlers(
/* skip disabled keymap items [T38447] */
if (kmi->flag & KMI_INACTIVE)
continue;
-
+
if (STREQ(kmi->idname, opname) && WM_key_event_string(kmi->type, false)[0]) {
if (is_hotkey) {
if (!ISHOTKEY(kmi->type))
@@ -1197,7 +1197,7 @@ static wmKeyMapItem *wm_keymap_item_find_handlers(
}
}
}
-
+
/* ensure un-initialized keymap is never used */
if (r_keymap) *r_keymap = NULL;
return NULL;
@@ -1231,7 +1231,7 @@ static wmKeyMapItem *wm_keymap_item_find_props(
if (sa) {
if (!(ar && ar->regiontype == RGN_TYPE_WINDOW))
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, r_keymap);
}
@@ -1447,7 +1447,7 @@ static bool wm_keymap_test_and_clear_update(wmKeyMap *km)
{
wmKeyMapItem *kmi;
int update;
-
+
update = (km->flag & KEYMAP_UPDATE);
km->flag &= ~KEYMAP_UPDATE;
@@ -1455,7 +1455,7 @@ static bool wm_keymap_test_and_clear_update(wmKeyMap *km)
update = update || (kmi->flag & KMI_UPDATE);
kmi->flag &= ~KMI_UPDATE;
}
-
+
return (update != 0);
}
@@ -1513,7 +1513,7 @@ void WM_keyconfig_update(wmWindowManager *wm)
if (wm_keymap_update_flag == 0)
return;
-
+
/* update operator properties for non-modal user keymaps */
for (km = U.user_keymaps.first; km; km = km->next) {
if ((km->flag & KEYMAP_MODAL) == 0) {
@@ -1586,7 +1586,7 @@ wmKeyMap *WM_keymap_active(wmWindowManager *wm, wmKeyMap *keymap)
if (!keymap)
return NULL;
-
+
/* first user defined keymaps */
km = WM_keymap_list_find(&wm->userconf->keymaps, keymap->idname, keymap->spaceid, keymap->regionid);
@@ -1678,13 +1678,13 @@ void WM_keymap_restore_to_default(wmKeyMap *keymap, bContext *C)
wmKeyMapItem *WM_keymap_item_find_id(wmKeyMap *keymap, int id)
{
wmKeyMapItem *kmi;
-
+
for (kmi = keymap->items.first; kmi; kmi = kmi->next) {
if (kmi->id == id) {
return kmi;
}
}
-
+
return NULL;
}
@@ -1708,7 +1708,7 @@ wmKeyMap *WM_keymap_guess_opname(const bContext *C, const char *opname)
wmKeyMap *km = NULL;
SpaceLink *sl = CTX_wm_space_data(C);
-
+
/* Window */
if (STRPREFIX(opname, "WM_OT")) {
km = WM_keymap_find_all(C, "Window", 0, 0);
@@ -1735,8 +1735,8 @@ wmKeyMap *WM_keymap_guess_opname(const bContext *C, const char *opname)
{
km = WM_keymap_find_all(C, "Window", 0, 0);
}
-
-
+
+
/* 3D View */
else if (STRPREFIX(opname, "VIEW3D_OT")) {
km = WM_keymap_find_all(C, "3D View", sl->spacetype, 0);
@@ -1756,11 +1756,11 @@ wmKeyMap *WM_keymap_guess_opname(const bContext *C, const char *opname)
{
km = WM_keymap_find_all(C, "Object Mode", 0, 0);
}
-
+
/* Editing Modes */
else if (STRPREFIX(opname, "MESH_OT")) {
km = WM_keymap_find_all(C, "Mesh", 0, 0);
-
+
/* some mesh operators are active in object mode too, like add-prim */
if (km && !WM_keymap_poll((bContext *)C, km)) {
km = WM_keymap_find_all(C, "Object Mode", 0, 0);
@@ -1770,7 +1770,7 @@ wmKeyMap *WM_keymap_guess_opname(const bContext *C, const char *opname)
STRPREFIX(opname, "SURFACE_OT"))
{
km = WM_keymap_find_all(C, "Curve", 0, 0);
-
+
/* some curve operators are active in object mode too, like add-prim */
if (km && !WM_keymap_poll((bContext *)C, km)) {
km = WM_keymap_find_all(C, "Object Mode", 0, 0);
@@ -1798,7 +1798,7 @@ wmKeyMap *WM_keymap_guess_opname(const bContext *C, const char *opname)
}
else if (STRPREFIX(opname, "MBALL_OT")) {
km = WM_keymap_find_all(C, "Metaball", 0, 0);
-
+
/* some mball operators are active in object mode too, like add-prim */
if (km && !WM_keymap_poll((bContext *)C, km)) {
km = WM_keymap_find_all(C, "Object Mode", 0, 0);
@@ -1939,7 +1939,7 @@ wmKeyMap *WM_keymap_guess_opname(const bContext *C, const char *opname)
break;
}
}
-
+
return km;
}
diff --git a/source/blender/windowmanager/intern/wm_operators.c b/source/blender/windowmanager/intern/wm_operators.c
index 965c3115199..926e87cc3b4 100644
--- a/source/blender/windowmanager/intern/wm_operators.c
+++ b/source/blender/windowmanager/intern/wm_operators.c
@@ -252,15 +252,15 @@ static int wm_macro_exec(bContext *C, wmOperator *op)
{
wmOperator *opm;
int retval = OPERATOR_FINISHED;
-
+
wm_macro_start(op);
for (opm = op->macro.first; opm; opm = opm->next) {
-
+
if (opm->type->exec) {
retval = opm->type->exec(C, opm);
OPERATOR_RETVAL_CHECK(retval);
-
+
if (retval & OPERATOR_FINISHED) {
MacroData *md = op->customdata;
md->retval = OPERATOR_FINISHED; /* keep in mind that at least one operator finished */
@@ -273,7 +273,7 @@ static int wm_macro_exec(bContext *C, wmOperator *op)
CLOG_WARN(WM_LOG_OPERATORS, "'%s' cant exec macro", opm->type->idname);
}
}
-
+
return wm_macro_end(op, retval);
}
@@ -291,7 +291,7 @@ static int wm_macro_invoke_internal(bContext *C, wmOperator *op, const wmEvent *
OPERATOR_RETVAL_CHECK(retval);
BLI_movelisttolist(&op->reports->list, &opm->reports->list);
-
+
if (retval & OPERATOR_FINISHED) {
MacroData *md = op->customdata;
md->retval = OPERATOR_FINISHED; /* keep in mind that at least one operator finished */
@@ -314,7 +314,7 @@ static int wm_macro_modal(bContext *C, wmOperator *op, const wmEvent *event)
{
wmOperator *opm = op->opm;
int retval = OPERATOR_FINISHED;
-
+
if (opm == NULL) {
CLOG_ERROR(WM_LOG_OPERATORS, "macro error, calling NULL modal()");
}
@@ -389,20 +389,20 @@ wmOperatorType *WM_operatortype_append_macro(const char *idname, const char *nam
{
wmOperatorType *ot;
const char *i18n_context;
-
+
if (WM_operatortype_find(idname, true)) {
CLOG_ERROR(WM_LOG_OPERATORS, "operator %s exists, cannot create macro", idname);
return NULL;
}
-
+
ot = MEM_callocN(sizeof(wmOperatorType), "operatortype");
ot->srna = RNA_def_struct_ptr(&BLENDER_RNA, "", &RNA_OperatorProperties);
-
+
ot->idname = idname;
ot->name = name;
ot->description = description;
ot->flag = OPTYPE_MACRO | flag;
-
+
ot->exec = wm_macro_exec;
ot->invoke = wm_macro_invoke;
ot->modal = wm_macro_modal;
@@ -411,7 +411,7 @@ wmOperatorType *WM_operatortype_append_macro(const char *idname, const char *nam
if (!ot->description) /* XXX All ops should have a description but for now allow them not to. */
ot->description = UNDOCUMENTED_OPERATOR_TIP;
-
+
RNA_def_struct_ui_text(ot->srna, ot->name, ot->description);
RNA_def_struct_identifier(&BLENDER_RNA, ot->srna, ot->idname);
/* Use i18n context from ext.srna if possible (py operators). */
@@ -479,7 +479,7 @@ wmOperatorTypeMacro *WM_operatortype_macro_define(wmOperatorType *ot, const char
static void wm_operatortype_free_macro(wmOperatorType *ot)
{
wmOperatorTypeMacro *otmacro;
-
+
for (otmacro = ot->macro.first; otmacro; otmacro = otmacro->next) {
if (otmacro->ptr) {
WM_operator_properties_free(otmacro->ptr);
@@ -598,7 +598,7 @@ void WM_operator_py_idname(char *to, const char *from)
const char *sep = strstr(from, "_OT_");
if (sep) {
int ofs = (sep - from);
-
+
/* note, we use ascii tolower instead of system tolower, because the
* latter depends on the locale, and can lead to idname mismatch */
memcpy(to, from, sizeof(char) * ofs);
@@ -1317,7 +1317,7 @@ int WM_operator_confirm_message_ex(bContext *C, wmOperator *op,
layout = UI_popup_menu_layout(pup);
uiItemFullO_ptr(layout, op->type, message, ICON_NONE, properties, WM_OP_EXEC_REGION_WIN, 0, NULL);
UI_popup_menu_end(C, pup);
-
+
return OPERATOR_INTERFACE;
}
@@ -1437,7 +1437,7 @@ ID *WM_operator_drop_load_path(struct bContext *C, wmOperator *op, const short i
if (is_relative_path ) {
if (exists == false) {
if (idcode == ID_IM) {
- BLI_path_rel(((Image *)id)->name, bmain->name);
+ BLI_path_rel(((Image *)id)->name, BKE_main_blendfile_path(bmain));
}
else {
BLI_assert(0);
@@ -1522,7 +1522,7 @@ static uiBlock *wm_block_create_redo(bContext *C, ARegion *ar, void *arg_op)
uiTemplateOperatorPropertyButs(C, layout, op, NULL, UI_BUT_LABEL_ALIGN_SPLIT_COLUMN,
UI_TEMPLATE_OP_PROPS_SHOW_TITLE);
}
-
+
UI_block_bounds_set_popup(block, 4, 0, 0);
return block;
@@ -1588,10 +1588,10 @@ static uiBlock *wm_block_dialog_create(bContext *C, ARegion *ar, void *userData)
UI_block_flag_enable(block, UI_BLOCK_KEEP_OPEN | UI_BLOCK_NUMSELECT);
layout = UI_block_layout(block, UI_LAYOUT_VERTICAL, UI_LAYOUT_PANEL, 0, 0, data->width, data->height, 0, style);
-
+
uiTemplateOperatorPropertyButs(C, layout, op, NULL, UI_BUT_LABEL_ALIGN_SPLIT_COLUMN,
UI_TEMPLATE_OP_PROPS_SHOW_TITLE);
-
+
/* clear so the OK button is left alone */
UI_block_func_set(block, NULL, NULL, NULL);
@@ -1663,7 +1663,7 @@ static void wm_operator_ui_popup_ok(struct bContext *C, void *arg, int retval)
if (op && retval > 0)
WM_operator_call_ex(C, op, true);
-
+
MEM_freeN(data);
}
@@ -1739,7 +1739,7 @@ int WM_operator_props_popup(bContext *C, wmOperator *op, const wmEvent *UNUSED(e
int WM_operator_props_dialog_popup(bContext *C, wmOperator *op, int width, int height)
{
wmOpPopUp *data = MEM_callocN(sizeof(wmOpPopUp), "WM_operator_props_dialog_popup");
-
+
data->op = op;
data->width = width;
data->height = height;
@@ -1763,7 +1763,7 @@ int WM_operator_redo_popup(bContext *C, wmOperator *op)
BKE_reportf(CTX_wm_reports(C), RPT_ERROR, "Operator redo '%s': wrong context", op->type->idname);
return OPERATOR_CANCELLED;
}
-
+
UI_popup_block_invoke(C, wm_block_create_redo, op);
return OPERATOR_CANCELLED;
@@ -1791,11 +1791,11 @@ static void WM_OT_debug_menu(wmOperatorType *ot)
ot->name = "Debug Menu";
ot->idname = "WM_OT_debug_menu";
ot->description = "Open a popup to set the debug level";
-
+
ot->invoke = wm_debug_menu_invoke;
ot->exec = wm_debug_menu_exec;
ot->poll = WM_operator_winactive;
-
+
RNA_def_int(ot->srna, "debug_value", 0, SHRT_MIN, SHRT_MAX, "Debug Value", "", -10000, 10000);
}
@@ -1898,7 +1898,7 @@ static uiBlock *wm_block_create_splash(bContext *C, ARegion *ar, void *UNUSED(ar
/* Builds made from tag only shows tag sha */
BLI_snprintf(hash_buf, sizeof(hash_buf), "Hash: %s", build_hash);
BLI_snprintf(date_buf, sizeof(date_buf), "Date: %s %s", build_commit_date, build_commit_time);
-
+
BLF_size(style->widgetlabel.uifont_id, style->widgetlabel.points, U.pixelsize * U.dpi);
hash_width = (int)BLF_width(style->widgetlabel.uifont_id, hash_buf, sizeof(hash_buf)) + U.widget_unit;
date_width = (int)BLF_width(style->widgetlabel.uifont_id, date_buf, sizeof(date_buf)) + U.widget_unit;
@@ -2011,9 +2011,9 @@ static uiBlock *wm_block_create_splash(bContext *C, ARegion *ar, void *UNUSED(ar
UI_but_flag_enable(but, 1);
}
#endif /* WITH_BUILDINFO */
-
+
layout = UI_block_layout(block, UI_LAYOUT_VERTICAL, UI_LAYOUT_PANEL, 10, 2, U.pixelsize * 480, U.pixelsize * 110, 0, style);
-
+
UI_block_emboss_set(block, UI_EMBOSS);
/* show the splash menu (containing interaction presets), using python */
if (mt) {
@@ -2022,10 +2022,10 @@ static uiBlock *wm_block_create_splash(bContext *C, ARegion *ar, void *UNUSED(ar
// wmWindowManager *wm = CTX_wm_manager(C);
// uiItemM(layout, C, "USERPREF_MT_keyconfigs", U.keyconfigstr, ICON_NONE);
}
-
+
UI_block_emboss_set(block, UI_EMBOSS_PULLDOWN);
uiLayoutSetOperatorContext(layout, WM_OP_EXEC_REGION_WIN);
-
+
split = uiLayoutSplit(layout, 0.0f, false);
col = uiLayoutColumn(split, false);
uiItemL(col, IFACE_("Links"), ICON_NONE);
@@ -2071,21 +2071,21 @@ static uiBlock *wm_block_create_splash(bContext *C, ARegion *ar, void *UNUSED(ar
uiItemS(col);
uiItemO(col, NULL, ICON_RECOVER_LAST, "WM_OT_recover_last_session");
uiItemL(col, "", ICON_NONE);
-
+
mt = WM_menutype_find("USERPREF_MT_splash_footer", false);
if (mt) {
UI_menutype_draw(C, mt, uiLayoutColumn(layout, false));
}
UI_block_bounds_set_centered(block, 0);
-
+
return block;
}
static int wm_splash_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *UNUSED(event))
{
UI_popup_block_invoke(C, wm_block_create_splash, NULL);
-
+
return OPERATOR_FINISHED;
}
@@ -2094,7 +2094,7 @@ static void WM_OT_splash(wmOperatorType *ot)
ot->name = "Splash Screen";
ot->idname = "WM_OT_splash";
ot->description = "Open the splash screen with release info";
-
+
ot->invoke = wm_splash_invoke;
ot->poll = WM_operator_winactive;
}
@@ -2114,26 +2114,26 @@ static uiBlock *wm_block_search_menu(bContext *C, ARegion *ar, void *userdata)
wmWindow *win = CTX_wm_window(C);
uiBlock *block;
uiBut *but;
-
+
block = UI_block_begin(C, ar, "_popup", UI_EMBOSS);
UI_block_flag_enable(block, UI_BLOCK_LOOP | UI_BLOCK_MOVEMOUSE_QUIT | UI_BLOCK_SEARCH_MENU);
-
+
but = uiDefSearchBut(block, search, 0, ICON_VIEWZOOM, sizeof(search), 10, 10, init_data->size[0], UI_UNIT_Y, 0, 0, "");
UI_but_func_operator_search(but);
-
+
/* fake button, it holds space for search items */
uiDefBut(block, UI_BTYPE_LABEL, 0, "", 10, 10 - init_data->size[1],
init_data->size[0], init_data->size[1], NULL, 0, 0, 0, 0, NULL);
-
+
UI_block_bounds_set_popup(block, 6, 0, -UI_UNIT_Y); /* move it downwards, mouse over button */
-
+
wm_event_init_from_window(win, &event);
event.type = EVT_BUT_OPEN;
event.val = KM_PRESS;
event.customdata = but;
event.customdatafree = false;
wm_event_add(win, &event);
-
+
return block;
}
@@ -2152,7 +2152,7 @@ static int wm_search_menu_invoke(bContext *C, wmOperator *UNUSED(op), const wmEv
};
UI_popup_block_invoke(C, wm_block_search_menu, &data);
-
+
return OPERATOR_INTERFACE;
}
@@ -2181,7 +2181,7 @@ static void WM_OT_search_menu(wmOperatorType *ot)
ot->name = "Search Menu";
ot->idname = "WM_OT_search_menu";
ot->description = "Pop-up a search menu over all available operators in current context";
-
+
ot->invoke = wm_search_menu_invoke;
ot->exec = wm_search_menu_exec;
ot->poll = wm_search_menu_poll;
@@ -2246,8 +2246,9 @@ static int wm_call_panel_exec(bContext *C, wmOperator *op)
RNA_string_get(op->ptr, "name", idname);
const int space_type = RNA_enum_get(op->ptr, "space_type");
const int region_type = RNA_enum_get(op->ptr, "region_type");
+ const bool keep_open = RNA_boolean_get(op->ptr, "keep_open");
- return UI_popover_panel_invoke(C, space_type, region_type, idname, true, op->reports);
+ return UI_popover_panel_invoke(C, space_type, region_type, idname, keep_open, op->reports);
}
static void WM_OT_call_panel(wmOperatorType *ot)
@@ -2261,9 +2262,16 @@ static void WM_OT_call_panel(wmOperatorType *ot)
ot->flag = OPTYPE_INTERNAL;
- RNA_def_string(ot->srna, "name", NULL, BKE_ST_MAXNAME, "Name", "Name of the menu");
- RNA_def_enum(ot->srna, "space_type", rna_enum_space_type_items, SPACE_EMPTY, "Space Type", "");
- RNA_def_enum(ot->srna, "region_type", rna_enum_region_type_items, RGN_TYPE_WINDOW, "Region Type", "");
+ PropertyRNA *prop;
+
+ prop = RNA_def_string(ot->srna, "name", NULL, BKE_ST_MAXNAME, "Name", "Name of the menu");
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE);
+ prop = RNA_def_enum(ot->srna, "space_type", rna_enum_space_type_items, SPACE_EMPTY, "Space Type", "");
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE);
+ prop = RNA_def_enum(ot->srna, "region_type", rna_enum_region_type_items, RGN_TYPE_WINDOW, "Region Type", "");
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE);
+ prop = RNA_def_boolean(ot->srna, "keep_open", true, "Keep Open", "");
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE);
}
/* ************ window / screen operator definitions ************** */
@@ -2364,7 +2372,7 @@ static void WM_OT_console_toggle(wmOperatorType *ot)
ot->name = CTX_N_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Toggle System Console");
ot->idname = "WM_OT_console_toggle";
ot->description = N_("Toggle System Console");
-
+
ot->exec = wm_console_toggle_exec;
ot->poll = WM_operator_winactive;
}
@@ -2382,20 +2390,20 @@ void *WM_paint_cursor_activate(wmWindowManager *wm, int (*poll)(bContext *C),
wmPaintCursorDraw draw, void *customdata)
{
wmPaintCursor *pc = MEM_callocN(sizeof(wmPaintCursor), "paint cursor");
-
+
BLI_addtail(&wm->paintcursors, pc);
-
+
pc->customdata = customdata;
pc->poll = poll;
pc->draw = draw;
-
+
return pc;
}
void WM_paint_cursor_end(wmWindowManager *wm, void *handle)
{
wmPaintCursor *pc;
-
+
for (pc = wm->paintcursors.first; pc; pc = pc->next) {
if (pc == (wmPaintCursor *)handle) {
BLI_remlink(&wm->paintcursors, pc);
@@ -2438,7 +2446,7 @@ static void radial_control_update_header(wmOperator *op, bContext *C)
char msg[UI_MAX_DRAW_STR];
ScrArea *sa = CTX_wm_area(C);
Scene *scene = CTX_data_scene(C);
-
+
if (sa) {
if (hasNumInput(&rc->num_input)) {
char num_str[NUM_STR_REP_LEN];
@@ -2555,7 +2563,7 @@ static void radial_control_paint_tex(RadialControl *rc, float radius, float alph
RNA_property_float_get_array(fill_ptr, fill_prop, col);
}
-
+
Gwn_VertFormat *format = immVertexFormat();
unsigned int pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
@@ -2592,10 +2600,10 @@ static void radial_control_paint_tex(RadialControl *rc, float radius, float alph
immAttrib2f(texCoord, 1, 0);
immVertex2f(pos, radius, -radius);
-
+
immAttrib2f(texCoord, 1, 1);
immVertex2f(pos, radius, radius);
-
+
immAttrib2f(texCoord, 0, 1);
immVertex2f(pos, -radius, radius);
@@ -2611,7 +2619,7 @@ static void radial_control_paint_tex(RadialControl *rc, float radius, float alph
immUniformColor3fvAlpha(col, alpha);
imm_draw_circle_fill_2d(pos, 0.0f, 0.0f, radius, 40);
}
-
+
immUnbindProgram();
}
@@ -2626,7 +2634,7 @@ static void radial_control_paint_cursor(bContext *UNUSED(C), int x, int y, void
short strdrawlen = 0;
float strwidth, strheight;
float r1 = 0.0f, r2 = 0.0f, rmin = 0.0, tex_radius, alpha;
- float zoom[2], col[3] = {1, 1, 1};
+ float zoom[2], col[3] = {1, 1, 1};
switch (rc->subtype) {
case PROP_NONE:
@@ -2800,7 +2808,7 @@ static int radial_control_get_path(
return 0;
}
}
-
+
/* check property's array length */
if (*r_prop && (len = RNA_property_array_length(r_ptr, *r_prop)) != req_length) {
MEM_freeN(str);
@@ -2849,7 +2857,7 @@ static int radial_control_get_properties(bContext *C, wmOperator *op)
/* data path is required */
if (!rc->prop)
return 0;
-
+
if (!radial_control_get_path(&ctx_ptr, op, "rotation_path", &rc->rot_ptr, &rc->rot_prop, 0, RC_PROP_REQUIRE_FLOAT))
return 0;
if (!radial_control_get_path(&ctx_ptr, op, "color_path", &rc->col_ptr, &rc->col_prop, 3, RC_PROP_REQUIRE_FLOAT))
@@ -2884,7 +2892,7 @@ static int radial_control_get_properties(bContext *C, wmOperator *op)
{
return 0;
}
-
+
if (!radial_control_get_path(&ctx_ptr, op, "image_id", &rc->image_id_ptr, NULL, 0, 0))
return 0;
else if (rc->image_id_ptr.data) {
@@ -3007,7 +3015,7 @@ static void radial_control_cancel(bContext *C, wmOperator *op)
if (sa) {
ED_area_headerprint(sa, NULL);
}
-
+
WM_paint_cursor_end(wm, rc->cursor);
/* restore original paint cursors */
@@ -3048,10 +3056,10 @@ static int radial_control_modal(bContext *C, wmOperator *op, const wmEvent *even
if (numValue < 0.0f)
numValue += 2.0f * (float)M_PI;
}
-
+
CLAMP(numValue, rc->min_value, rc->max_value);
new_value = numValue;
-
+
radial_control_set_value(rc, new_value);
rc->current_value = new_value;
radial_control_update_header(op, C);
@@ -3202,9 +3210,9 @@ static int radial_control_modal(bContext *C, wmOperator *op, const wmEvent *even
CLAMP(numValue, rc->min_value, rc->max_value);
new_value = numValue;
-
+
radial_control_set_value(rc, new_value);
-
+
rc->current_value = new_value;
radial_control_update_header(op, C);
return OPERATOR_RUNNING_MODAL;
@@ -3408,7 +3416,7 @@ static int redraw_timer_exec(bContext *C, wmOperator *op)
a = 0;
}
}
-
+
time_delta = (PIL_check_seconds_timer() - time_start) * 1000;
RNA_enum_description(redraw_timer_type_items, type, &infostr);
@@ -3418,7 +3426,7 @@ static int redraw_timer_exec(bContext *C, wmOperator *op)
BKE_reportf(op->reports, RPT_WARNING,
"%d x %s: %.4f ms, average: %.8f ms",
iter_steps, infostr, time_delta, time_delta / iter_steps);
-
+
return OPERATOR_FINISHED;
}
@@ -3452,7 +3460,7 @@ static void WM_OT_memory_statistics(wmOperatorType *ot)
ot->name = "Memory Statistics";
ot->idname = "WM_OT_memory_statistics";
ot->description = "Print memory statistics to the console";
-
+
ot->exec = memory_statistics_exec;
}
@@ -3817,21 +3825,21 @@ static void gesture_straightline_modal_keymap(wmKeyConfig *keyconf)
{GESTURE_MODAL_BEGIN, "BEGIN", 0, "Begin", ""},
{0, NULL, 0, NULL, NULL}
};
-
+
wmKeyMap *keymap = WM_modalkeymap_get(keyconf, "Gesture Straight Line");
-
+
/* this function is called for each spacetype, only needs to add map once */
if (keymap && keymap->modal_items) return;
-
+
keymap = WM_modalkeymap_add(keyconf, "Gesture Straight Line", modal_items);
-
+
/* items for modal map */
WM_modalkeymap_add_item(keymap, ESCKEY, KM_PRESS, KM_ANY, 0, GESTURE_MODAL_CANCEL);
WM_modalkeymap_add_item(keymap, RIGHTMOUSE, KM_ANY, KM_ANY, 0, GESTURE_MODAL_CANCEL);
-
+
WM_modalkeymap_add_item(keymap, LEFTMOUSE, KM_PRESS, 0, 0, GESTURE_MODAL_BEGIN);
WM_modalkeymap_add_item(keymap, LEFTMOUSE, KM_RELEASE, KM_ANY, 0, GESTURE_MODAL_SELECT);
-
+
/* assign map to operators */
WM_modalkeymap_assign(keymap, "IMAGE_OT_sample_line");
WM_modalkeymap_assign(keymap, "PAINT_OT_weight_gradient");
@@ -3859,7 +3867,7 @@ static void gesture_border_modal_keymap(wmKeyConfig *keyconf)
/* items for modal map */
WM_modalkeymap_add_item(keymap, ESCKEY, KM_PRESS, KM_ANY, 0, GESTURE_MODAL_CANCEL);
-
+
/* Note: cancel only on press otherwise you cannot map this to RMB-gesture */
WM_modalkeymap_add_item(keymap, RIGHTMOUSE, KM_PRESS, KM_ANY, 0, GESTURE_MODAL_CANCEL);
WM_modalkeymap_add_item(keymap, RIGHTMOUSE, KM_RELEASE, KM_ANY, 0, GESTURE_MODAL_SELECT);
@@ -3871,10 +3879,10 @@ static void gesture_border_modal_keymap(wmKeyConfig *keyconf)
/* any unhandled leftclick release handles select */
WM_modalkeymap_add_item(keymap, LEFTMOUSE, KM_PRESS, 0, 0, GESTURE_MODAL_BEGIN);
WM_modalkeymap_add_item(keymap, LEFTMOUSE, KM_RELEASE, KM_ANY, 0, GESTURE_MODAL_SELECT);
-
+
WM_modalkeymap_add_item(keymap, MIDDLEMOUSE, KM_PRESS, 0, 0, GESTURE_MODAL_BEGIN);
WM_modalkeymap_add_item(keymap, MIDDLEMOUSE, KM_RELEASE, 0, 0, GESTURE_MODAL_DESELECT);
-
+
/* assign map to operators */
WM_modalkeymap_assign(keymap, "ACTION_OT_select_border");
WM_modalkeymap_assign(keymap, "ANIM_OT_channels_select_border");
@@ -3928,7 +3936,7 @@ static void gesture_zoom_border_modal_keymap(wmKeyConfig *keyconf)
WM_modalkeymap_add_item(keymap, RIGHTMOUSE, KM_ANY, KM_ANY, 0, GESTURE_MODAL_CANCEL);
WM_modalkeymap_add_item(keymap, LEFTMOUSE, KM_PRESS, 0, 0, GESTURE_MODAL_BEGIN);
- WM_modalkeymap_add_item(keymap, LEFTMOUSE, KM_RELEASE, 0, 0, GESTURE_MODAL_IN);
+ WM_modalkeymap_add_item(keymap, LEFTMOUSE, KM_RELEASE, 0, 0, GESTURE_MODAL_IN);
WM_modalkeymap_add_item(keymap, MIDDLEMOUSE, KM_PRESS, 0, 0, GESTURE_MODAL_BEGIN);
WM_modalkeymap_add_item(keymap, MIDDLEMOUSE, KM_RELEASE, 0, 0, GESTURE_MODAL_OUT);
@@ -3944,7 +3952,7 @@ void wm_window_keymap(wmKeyConfig *keyconf)
{
wmKeyMap *keymap = WM_keymap_find(keyconf, "Window", 0, 0);
wmKeyMapItem *kmi;
-
+
/* note, this doesn't replace existing keymap items */
WM_keymap_verify_item(keymap, "WM_OT_window_new", WKEY, KM_PRESS, KM_CTRL | KM_ALT, 0);
#ifdef __APPLE__
@@ -3956,7 +3964,7 @@ void wm_window_keymap(wmKeyConfig *keyconf)
WM_keymap_add_item(keymap, "WM_OT_quit_blender", QKEY, KM_PRESS, KM_OSKEY, 0);
#endif
WM_keymap_add_item(keymap, "WM_OT_read_homefile", NKEY, KM_PRESS, KM_CTRL, 0);
- WM_keymap_add_item(keymap, "WM_OT_save_homefile", UKEY, KM_PRESS, KM_CTRL, 0);
+ WM_keymap_add_item(keymap, "WM_OT_save_homefile", UKEY, KM_PRESS, KM_CTRL, 0);
WM_keymap_add_menu(keymap, "INFO_MT_file_open_recent", OKEY, KM_PRESS, KM_SHIFT | KM_CTRL, 0);
WM_keymap_add_item(keymap, "WM_OT_open_mainfile", OKEY, KM_PRESS, KM_CTRL, 0);
WM_keymap_add_item(keymap, "WM_OT_open_mainfile", F1KEY, KM_PRESS, 0, 0);
@@ -3981,7 +3989,7 @@ void wm_window_keymap(wmKeyConfig *keyconf)
/* menus that can be accessed anywhere in blender */
- WM_keymap_verify_item(keymap, "WM_OT_search_menu", TABKEY, KM_PRESS, 0, 0);
+ WM_keymap_verify_item(keymap, "WM_OT_search_menu", ACCENTGRAVEKEY, KM_RELEASE, 0, 0);
#ifdef WITH_INPUT_NDOF
WM_keymap_add_menu(keymap, "USERPREF_MT_ndof_settings", NDOF_BUTTON_MENU, KM_PRESS, 0, 0);
@@ -4029,7 +4037,7 @@ void wm_window_keymap(wmKeyConfig *keyconf)
kmi = WM_keymap_add_item(keymap, "WM_OT_context_set_enum", F12KEY, KM_PRESS, KM_SHIFT, 0);
RNA_string_set(kmi->ptr, "data_path", "area.type");
RNA_string_set(kmi->ptr, "value", "DOPESHEET_EDITOR");
-
+
#ifdef WITH_INPUT_NDOF
/* ndof speed */
const char *data_path = "user_preferences.inputs.ndof_sensitivity";
diff --git a/source/blender/windowmanager/intern/wm_playanim.c b/source/blender/windowmanager/intern/wm_playanim.c
index d6a1eb81981..d93d51df105 100644
--- a/source/blender/windowmanager/intern/wm_playanim.c
+++ b/source/blender/windowmanager/intern/wm_playanim.c
@@ -101,7 +101,7 @@ typedef struct PlayState {
/* window and viewport size */
int win_x, win_y;
-
+
/* current zoom level */
float zoom;
@@ -122,7 +122,7 @@ typedef struct PlayState {
bool loading;
/* x/y image flip */
bool draw_flip[2];
-
+
int fstep;
/* current picture */
@@ -134,7 +134,7 @@ typedef struct PlayState {
/* saves passing args */
struct ImBuf *curframe_ibuf;
-
+
/* restarts player for file drop */
char dropped_file[FILE_MAX];
} PlayState;
@@ -946,13 +946,13 @@ static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr ps_void)
{
GHOST_TEventButtonData *bd = GHOST_GetEventData(evt);
int cx, cy, sizex, sizey, inside_window;
-
+
GHOST_GetCursorPosition(g_WS.ghost_system, &cx, &cy);
GHOST_ScreenToClient(g_WS.ghost_window, cx, cy, &cx, &cy);
playanim_window_get_size(&sizex, &sizey);
inside_window = (cx >= 0 && cx < sizex && cy >= 0 && cy <= sizey);
-
+
if (bd->button == GHOST_kButtonMaskLeft) {
if (type == GHOST_kEventButtonDown) {
if (inside_window) {
@@ -1016,23 +1016,23 @@ static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr ps_void)
case GHOST_kEventWindowMove:
{
float zoomx, zoomy;
-
+
playanim_window_get_size(&ps->win_x, &ps->win_y);
GHOST_ActivateWindowDrawingContext(g_WS.ghost_window);
zoomx = (float) ps->win_x / ps->ibufx;
zoomy = (float) ps->win_y / ps->ibufy;
-
+
/* zoom always show entire image */
ps->zoom = MIN2(zoomx, zoomy);
-
+
/* zoom steps of 2 for speed */
ps->zoom = floor(ps->zoom + 0.5f);
if (ps->zoom < 1.0f) ps->zoom = 1.0f;
-
+
glViewport(0, 0, ps->win_x, ps->win_y);
glScissor(0, 0, ps->win_x, ps->win_y);
-
+
playanim_gl_matrix();
ptottime = 0.0;
@@ -1049,11 +1049,11 @@ static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr ps_void)
case GHOST_kEventDraggingDropDone:
{
GHOST_TEventDragnDropData *ddd = GHOST_GetEventData(evt);
-
+
if (ddd->dataType == GHOST_kDragnDropTypeFilenames) {
GHOST_TStringArray *stra = ddd->data;
int a;
-
+
for (a = 0; a < stra->count; a++) {
BLI_strncpy(ps->dropped_file, (char *)stra->strings[a], sizeof(ps->dropped_file));
ps->go = false;
@@ -1120,7 +1120,7 @@ static char *wm_main_playanim_intern(int argc, const char **argv)
int sfra = -1;
int efra = -1;
int totblock;
-
+
PlayState ps = {0};
/* ps.doubleb = true;*/ /* UNUSED */
@@ -1271,14 +1271,14 @@ static char *wm_main_playanim_intern(int argc, const char **argv)
ps.ibufx = ibuf->x;
ps.ibufy = ibuf->y;
-
+
ps.win_x = ps.ibufx;
ps.win_y = ps.ibufy;
if (maxwinx % ibuf->x) maxwinx = ibuf->x * (1 + (maxwinx / ibuf->x));
if (maxwiny % ibuf->y) maxwiny = ibuf->y * (1 + (maxwiny / ibuf->y));
-
+
glClearColor(0.1, 0.1, 0.1, 0.0);
glClear(GL_COLOR_BUFFER_BIT);
@@ -1547,7 +1547,7 @@ static char *wm_main_playanim_intern(int argc, const char **argv)
BLI_strncpy(filepath, ps.dropped_file, sizeof(filepath));
return filepath;
}
-
+
IMB_exit();
BKE_images_exit();
DEG_free_node_types();
@@ -1560,7 +1560,7 @@ static char *wm_main_playanim_intern(int argc, const char **argv)
MEM_printmemlist();
#endif
}
-
+
return NULL;
}
diff --git a/source/blender/windowmanager/intern/wm_window.c b/source/blender/windowmanager/intern/wm_window.c
index ca5f95909f8..e1528551c12 100644
--- a/source/blender/windowmanager/intern/wm_window.c
+++ b/source/blender/windowmanager/intern/wm_window.c
@@ -35,7 +35,7 @@
#include <stdio.h>
#include <string.h>
-#include "DNA_listBase.h"
+#include "DNA_listBase.h"
#include "DNA_screen_types.h"
#include "DNA_windowmanager_types.h"
#include "DNA_workspace_types.h"
@@ -85,6 +85,7 @@
#include "GPU_framebuffer.h"
#include "GPU_init_exit.h"
#include "GPU_immediate.h"
+#include "GPU_material.h"
#include "GPU_texture.h"
#include "BLF_api.h"
@@ -113,7 +114,7 @@ static struct WMInitStruct {
int windowstate;
WinOverrideFlag override_flag;
-
+
bool native_pixels;
} wm_init_state = {0, 0, 0, 0, GHOST_kWindowStateNormal, 0, true};
@@ -125,7 +126,7 @@ void wm_get_screensize(int *r_width, int *r_height)
{
unsigned int uiwidth;
unsigned int uiheight;
-
+
GHOST_GetMainDisplayDimensions(g_system, &uiwidth, &uiheight);
*r_width = uiwidth;
*r_height = uiheight;
@@ -147,9 +148,9 @@ void wm_get_desktopsize(int *r_width, int *r_height)
static void wm_window_check_position(rcti *rect)
{
int width, height, d;
-
+
wm_get_screensize(&width, &height);
-
+
if (rect->xmin < 0) {
rect->xmax -= rect->xmin;
rect->xmin = 0;
@@ -168,7 +169,7 @@ static void wm_window_check_position(rcti *rect)
rect->ymax -= d;
rect->ymin -= d;
}
-
+
if (rect->xmin < 0) rect->xmin = 0;
if (rect->ymin < 0) rect->ymin = 0;
}
@@ -194,12 +195,12 @@ static void wm_ghostwindow_destroy(wmWindowManager *wm, wmWindow *win)
}
}
-/* including window itself, C can be NULL.
+/* including window itself, C can be NULL.
* ED_screen_exit should have been called */
void wm_window_free(bContext *C, wmWindowManager *wm, wmWindow *win)
{
wmTimer *wt, *wtnext;
-
+
/* update context */
if (C) {
WM_event_remove_handlers(C, &win->handlers);
@@ -217,7 +218,7 @@ void wm_window_free(bContext *C, wmWindowManager *wm, wmWindow *win)
if (wt->win == win && wt->event_type == TIMERJOBS)
wm_jobs_timer_ended(wm, wt);
}
-
+
/* timer removing, need to call this api function */
for (wt = wm->timers.first; wt; wt = wtnext) {
wtnext = wt->next;
@@ -226,7 +227,7 @@ void wm_window_free(bContext *C, wmWindowManager *wm, wmWindow *win)
}
if (win->eventstate) MEM_freeN(win->eventstate);
-
+
wm_event_free_all(win);
wm_ghostwindow_destroy(wm, win);
@@ -241,11 +242,11 @@ static int find_free_winid(wmWindowManager *wm)
{
wmWindow *win;
int id = 1;
-
+
for (win = wm->windows.first; win; win = win->next)
if (id <= win->winid)
id = win->winid + 1;
-
+
return id;
}
@@ -288,6 +289,7 @@ static wmWindow *wm_window_new_test(bContext *C)
/* part of wm_window.c api */
wmWindow *wm_window_copy(bContext *C, wmWindow *win_src, const bool duplicate_layout)
{
+ Main *bmain = CTX_data_main(C);
wmWindow *win_dst = wm_window_new(C);
WorkSpace *workspace = WM_window_get_active_workspace(win_src);
WorkSpaceLayout *layout_old = WM_window_get_active_layout(win_src);
@@ -301,7 +303,7 @@ wmWindow *wm_window_copy(bContext *C, wmWindow *win_src, const bool duplicate_la
win_dst->scene = scene;
WM_window_set_active_workspace(win_dst, workspace);
- layout_new = duplicate_layout ? ED_workspace_layout_duplicate(workspace, layout_old, win_dst) : layout_old;
+ layout_new = duplicate_layout ? ED_workspace_layout_duplicate(bmain, workspace, layout_old, win_dst) : layout_old;
WM_window_set_active_layout(win_dst, workspace, layout_new);
*win_dst->stereo3d_format = *win_src->stereo3d_format;
@@ -374,6 +376,7 @@ static void wm_block_confirm_quit_save(bContext *C, void *arg_block, void *UNUSE
/* Build the confirm dialog UI */
static uiBlock *block_create_confirm_quit(struct bContext *C, struct ARegion *ar, void *UNUSED(arg1))
{
+ Main *bmain = CTX_data_main(C);
uiStyle *style = UI_style_get();
uiBlock *block = UI_block_begin(C, ar, "confirm_quit_popup", UI_EMBOSS);
@@ -387,11 +390,11 @@ static uiBlock *block_create_confirm_quit(struct bContext *C, struct ARegion *ar
/* Text and some vertical space */
{
char *message;
- if (G.main->name[0] == '\0') {
+ if (BKE_main_blendfile_path(bmain)[0] == '\0') {
message = BLI_strdup(IFACE_("This file has not been saved yet. Save before closing?"));
}
else {
- const char *basename = BLI_path_basename(G.main->name);
+ const char *basename = BLI_path_basename(BKE_main_blendfile_path(bmain));
message = BLI_sprintfN(IFACE_("Save changes to \"%s\" before closing?"), basename);
}
uiItemL(layout, message, ICON_ERROR);
@@ -484,7 +487,7 @@ void wm_quit_with_optional_confirmation_prompt(bContext *C, wmWindow *win)
void wm_window_close(bContext *C, wmWindowManager *wm, wmWindow *win)
{
wmWindow *tmpwin;
-
+
/* first check if we have to quit (there are non-temp remaining windows) */
for (tmpwin = wm->windows.first; tmpwin; tmpwin = tmpwin->next) {
if (tmpwin == win)
@@ -502,7 +505,7 @@ void wm_window_close(bContext *C, wmWindowManager *wm, wmWindow *win)
WorkSpaceLayout *layout = BKE_workspace_active_layout_get(win->workspace_hook);
BLI_remlink(&wm->windows, win);
-
+
CTX_wm_window_set(C, win); /* needed by handlers */
WM_event_remove_handlers(C, &win->handlers);
WM_event_remove_handlers(C, &win->modalhandlers);
@@ -546,9 +549,10 @@ void wm_window_title(wmWindowManager *wm, wmWindow *win)
}
else if (win->ghostwin) {
/* this is set to 1 if you don't have startup.blend open */
- if (G.save_over && G.main->name[0]) {
- char str[sizeof(G.main->name) + 24];
- BLI_snprintf(str, sizeof(str), "Blender%s [%s%s]", wm->file_saved ? "" : "*", G.main->name,
+ if (G.save_over && BKE_main_blendfile_path_from_global()[0]) {
+ char str[sizeof(((Main *)NULL)->name) + 24];
+ BLI_snprintf(str, sizeof(str), "Blender%s [%s%s]", wm->file_saved ? "" : "*",
+ BKE_main_blendfile_path_from_global(),
G.main->recovered ? " (Recovered)" : "");
GHOST_SetTitle(win->ghostwin, str);
}
@@ -559,7 +563,7 @@ void wm_window_title(wmWindowManager *wm, wmWindow *win)
* and to give hint of unsaved changes for a user warning mechanism
* in case of OS application terminate request (e.g. OS Shortcut Alt+F4, Cmd+Q, (...), or session end) */
GHOST_SetWindowModifiedState(win->ghostwin, (GHOST_TUns8) !wm->file_saved);
-
+
}
}
@@ -625,7 +629,7 @@ static void wm_window_ghostwindow_add(wmWindowManager *wm, const char *title, wm
GHOST_WindowHandle ghostwin;
GHOST_GLSettings glSettings = {0};
int scr_w, scr_h, posy;
-
+
/* 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;
@@ -636,7 +640,7 @@ static void wm_window_ghostwindow_add(wmWindowManager *wm, const char *title, wm
wm_get_screensize(&scr_w, &scr_h);
posy = (scr_h - win->posy - win->sizey);
-
+
ghostwin = GHOST_CreateWindow(g_system, title,
win->posx, posy, win->sizex, win->sizey,
(GHOST_TWindowState)win->windowstate,
@@ -652,16 +656,16 @@ static void wm_window_ghostwindow_add(wmWindowManager *wm, const char *title, wm
gpu_batch_presets_reset();
win->gwnctx = GWN_context_create();
-
+
/* the new window has already been made drawable upon creation */
wm->windrawable = win;
/* needed so we can detect the graphics card below */
GPU_init();
-
+
win->ghostwin = ghostwin;
GHOST_SetWindowUserData(ghostwin, win); /* pointer back */
-
+
wm_window_ensure_eventstate(win);
/* store actual window size in blender window */
@@ -673,7 +677,7 @@ static void wm_window_ghostwindow_add(wmWindowManager *wm, const char *title, wm
win->sizey = GHOST_GetHeightRectangle(bounds);
}
GHOST_DisposeRectangle(bounds);
-
+
#ifndef __APPLE__
/* set the state here, so minimized state comes up correct on windows */
GHOST_SetWindowState(ghostwin, (GHOST_TWindowState)win->windowstate);
@@ -684,14 +688,14 @@ static void wm_window_ghostwindow_add(wmWindowManager *wm, const char *title, wm
if (!GPU_type_matches(GPU_DEVICE_ATI, GPU_OS_UNIX, GPU_DRIVER_OPENSOURCE)) {
glClear(GL_COLOR_BUFFER_BIT);
}
-
+
/* needed here, because it's used before it reads userdef */
WM_window_set_dpi(win);
-
+
wm_window_swap_buffers(win);
-
+
//GHOST_SetWindowState(ghostwin, GHOST_kWindowStateModified);
-
+
/* standard state vars for window */
GPU_state_init();
}
@@ -714,7 +718,7 @@ void wm_window_ghostwindows_ensure(wmWindowManager *wm)
{
wmKeyMap *keymap;
wmWindow *win;
-
+
BLI_assert(G.background == false);
/* no commandline prefsize? then we set this.
@@ -723,7 +727,7 @@ void wm_window_ghostwindows_ensure(wmWindowManager *wm)
*/
if (wm_init_state.size_x == 0) {
wm_get_screensize(&wm_init_state.size_x, &wm_init_state.size_y);
-
+
/* note!, this isnt quite correct, active screen maybe offset 1000s if PX,
* we'd need a wm_get_screensize like function that gives offset,
* in practice the window manager will likely move to the correct monitor */
@@ -741,7 +745,7 @@ void wm_window_ghostwindows_ensure(wmWindowManager *wm)
wm_init_state.size_y -= WM_WIN_INIT_PAD * 2;
#endif
}
-
+
for (win = wm->windows.first; win; win = win->next) {
if (win->ghostwin == NULL) {
if ((win->sizex == 0) || (wm_init_state.override_flag & WIN_OVERRIDE_GEOM)) {
@@ -772,13 +776,13 @@ void wm_window_ghostwindows_ensure(wmWindowManager *wm)
/* add keymap handlers (1 handler for all keys in map!) */
keymap = WM_keymap_find(wm->defaultconf, "Window", 0, 0);
WM_event_add_keymap_handler(&win->handlers, keymap);
-
+
keymap = WM_keymap_find(wm->defaultconf, "Screen", 0, 0);
WM_event_add_keymap_handler(&win->handlers, keymap);
keymap = WM_keymap_find(wm->defaultconf, "Screen Editing", 0, 0);
WM_event_add_keymap_handler(&win->modalhandlers, keymap);
-
+
/* add drop boxes */
{
ListBase *lb = WM_dropboxmap_find("Window", 0, 0);
@@ -821,7 +825,7 @@ wmWindow *WM_window_open(bContext *C, const rcti *rect)
{
wmWindow *win_prev = CTX_wm_window(C);
wmWindow *win = wm_window_new(C);
-
+
win->posx = rect->xmin;
win->posy = rect->ymin;
win->sizex = BLI_rcti_size_x(rect);
@@ -872,16 +876,16 @@ wmWindow *WM_window_open_temp(bContext *C, int x, int y, int sizex, int sizey, i
/* changes rect to fit within desktop */
wm_window_check_position(&rect);
-
+
/* test if we have a temp screen already */
for (win = CTX_wm_manager(C)->windows.first; win; win = win->next)
if (WM_window_is_temp_screen(win))
break;
-
+
/* add new window? */
if (win == NULL) {
win = wm_window_new(C);
-
+
win->posx = rect.xmin;
win->posy = rect.ymin;
}
@@ -904,7 +908,7 @@ wmWindow *WM_window_open_temp(bContext *C, int x, int y, int sizex, int sizey, i
if (screen == NULL) {
/* add new screen layout */
WorkSpace *workspace = WM_window_get_active_workspace(win);
- WorkSpaceLayout *layout = ED_workspace_layout_add(workspace, win, "temp");
+ WorkSpaceLayout *layout = ED_workspace_layout_add(bmain, workspace, win, "temp");
screen = BKE_workspace_layout_screen_get(layout);
WM_window_set_active_layout(win, workspace, layout);
@@ -933,7 +937,7 @@ wmWindow *WM_window_open_temp(bContext *C, int x, int y, int sizex, int sizey, i
/* ensure it shows the right spacetype editor */
sa = screen->areabase.first;
CTX_wm_area_set(C, sa);
-
+
if (type == WM_WINDOW_RENDER) {
ED_area_newspace(C, sa, SPACE_IMAGE, false);
}
@@ -943,26 +947,26 @@ wmWindow *WM_window_open_temp(bContext *C, int x, int y, int sizex, int sizey, i
else {
ED_area_newspace(C, sa, SPACE_USERPREF, false);
}
-
+
ED_screen_change(C, screen);
ED_screen_refresh(CTX_wm_manager(C), win); /* test scale */
-
+
/* do additional setup for specific editor type */
if (type == WM_WINDOW_DRIVERS) {
/* Configure editor - mode, tabs, framing */
SpaceIpo *sipo = (SpaceIpo *)sa->spacedata.first;
sipo->mode = SIPO_MODE_DRIVERS;
-
+
ARegion *ar_props = BKE_area_find_region_type(sa, RGN_TYPE_UI);
if (ar_props) {
UI_panel_category_active_set(ar_props, "Drivers");
-
+
ar_props->flag &= ~RGN_FLAG_HIDDEN;
/* XXX: Adjust width of this too? */
-
+
ED_region_visibility_change_update(C, ar_props);
}
-
+
ARegion *ar_main = BKE_area_find_region_type(sa, RGN_TYPE_WINDOW);
if (ar_main) {
/* XXX: Ideally we recenter based on the range instead... */
@@ -970,11 +974,11 @@ wmWindow *WM_window_open_temp(bContext *C, int x, int y, int sizex, int sizey, i
ar_main->v2d.tot.ymin = -2.0f;
ar_main->v2d.tot.xmax = 2.0f;
ar_main->v2d.tot.ymax = 2.0f;
-
+
ar_main->v2d.cur = ar_main->v2d.tot;
}
}
-
+
if (sa->spacetype == SPACE_IMAGE)
title = IFACE_("Blender Render");
else if (ELEM(sa->spacetype, SPACE_OUTLINER, SPACE_USERPREF))
@@ -1029,6 +1033,7 @@ static WorkSpaceLayout *wm_window_new_find_layout(wmOperator *op, WorkSpace *wor
/* new window operator callback */
int wm_window_new_exec(bContext *C, wmOperator *op)
{
+ Main *bmain = CTX_data_main(C);
wmWindow *win_src = CTX_wm_window(C);
WorkSpace *workspace = WM_window_get_active_workspace(win_src);
WorkSpaceLayout *layout_new = wm_window_new_find_layout(op, workspace);
@@ -1038,7 +1043,7 @@ int wm_window_new_exec(bContext *C, wmOperator *op)
if ((win_dst = wm_window_new_test(C))) {
if (screen_new->winid) {
/* layout/screen is already used, duplicate it */
- layout_new = ED_workspace_layout_duplicate(workspace, layout_new, win_dst);
+ layout_new = ED_workspace_layout_duplicate(bmain, workspace, layout_new, win_dst);
screen_new = BKE_workspace_layout_screen_get(layout_new);
}
/* New window with a different screen but same workspace */
@@ -1129,7 +1134,7 @@ int wm_window_fullscreen_toggle_exec(bContext *C, wmOperator *UNUSED(op))
GHOST_SetWindowState(window->ghostwin, GHOST_kWindowStateNormal);
return OPERATOR_FINISHED;
-
+
}
@@ -1138,10 +1143,10 @@ int wm_window_fullscreen_toggle_exec(bContext *C, wmOperator *UNUSED(op))
void wm_cursor_position_from_ghost(wmWindow *win, int *x, int *y)
{
float fac = GHOST_GetNativePixelSize(win->ghostwin);
-
+
GHOST_ScreenToClient(win->ghostwin, *x, *y, x, y);
*x *= fac;
-
+
*y = (win->sizey - 1) - *y;
*y *= fac;
}
@@ -1171,11 +1176,11 @@ typedef enum {
} modifierKeyType;
/* check if specified modifier key type is pressed */
-static int query_qual(modifierKeyType qual)
+static int query_qual(modifierKeyType qual)
{
GHOST_TModifierKeyMask left, right;
int val = 0;
-
+
switch (qual) {
case SHIFT:
left = GHOST_kModifierKeyLeftShift;
@@ -1194,15 +1199,15 @@ static int query_qual(modifierKeyType qual)
right = GHOST_kModifierKeyRightAlt;
break;
}
-
+
GHOST_GetModifierKeyState(g_system, left, &val);
if (!val)
GHOST_GetModifierKeyState(g_system, right, &val);
-
+
return val;
}
-void wm_window_make_drawable(wmWindowManager *wm, wmWindow *win)
+void wm_window_make_drawable(wmWindowManager *wm, wmWindow *win)
{
BLI_assert(GPU_framebuffer_current_get() == 0);
@@ -1256,7 +1261,7 @@ static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr C_void_ptr
wmWindowManager *wm = CTX_wm_manager(C);
GHOST_TEventType type = GHOST_GetEventType(evt);
int time = GHOST_GetEventTime(evt);
-
+
if (type == GHOST_kEventQuit) {
WM_exit(C);
}
@@ -1264,7 +1269,7 @@ static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr C_void_ptr
GHOST_WindowHandle ghostwin = GHOST_GetEventWindow(evt);
GHOST_TEventDataPtr data = GHOST_GetEventData(evt);
wmWindow *win;
-
+
/* Ghost now can call this function for life resizes, but it should return if WM didn't initialize yet.
* Can happen on file read (especially full size window) */
if ((wm->initialized & WM_WINDOW_IS_INITIALIZED) == 0) {
@@ -1285,12 +1290,12 @@ static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr C_void_ptr
else {
win = GHOST_GetWindowUserData(ghostwin);
}
-
+
switch (type) {
case GHOST_kEventWindowDeactivate:
wm_event_add_ghostevent(wm, win, type, time, data);
win->active = 0; /* XXX */
-
+
/* clear modifiers for inactive windows */
win->eventstate->alt = 0;
win->eventstate->ctrl = 0;
@@ -1299,7 +1304,7 @@ static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr C_void_ptr
win->eventstate->keymodifier = 0;
break;
- case GHOST_kEventWindowActivate:
+ case GHOST_kEventWindowActivate:
{
GHOST_TEventKeyData kdata;
wmEvent event;
@@ -1315,10 +1320,10 @@ static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr C_void_ptr
#endif
wm->winactive = win; /* no context change! c->wm->windrawable is drawable, or for area queues */
-
+
win->active = 1;
// window_handle(win, INPUTCHANGE, win->active);
-
+
/* bad ghost support for modifier keys... so on activate we set the modifiers again */
/* TODO: This is not correct since a modifier may be held when a window is activated...
@@ -1387,15 +1392,15 @@ static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr C_void_ptr
/* keymodifier zero, it hangs on hotkeys that open windows otherwise */
win->eventstate->keymodifier = 0;
-
+
/* entering window, update mouse pos. but no event */
wm_get_cursor_position(win, &wx, &wy);
win->eventstate->x = wx;
win->eventstate->y = wy;
-
+
win->addmousemove = 1; /* enables highlighted buttons */
-
+
wm_window_make_drawable(wm, win);
/* window might be focused by mouse click in configuration of window manager
@@ -1426,7 +1431,7 @@ static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr C_void_ptr
if (G.debug & G_DEBUG_EVENTS) {
printf("%s: ghost redraw %d\n", __func__, win->winid);
}
-
+
wm_window_make_drawable(wm, win);
WM_event_add_notifier(C, NC_WINDOW, NULL);
@@ -1445,18 +1450,18 @@ static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr C_void_ptr
}
WM_window_set_dpi(win);
-
+
/* win32: gives undefined window size when minimized */
if (state != GHOST_kWindowStateMinimized) {
GHOST_RectangleHandle client_rect;
int l, t, r, b, scr_w, scr_h;
int sizex, sizey, posx, posy;
-
+
client_rect = GHOST_GetClientBounds(win->ghostwin);
GHOST_GetRectangle(client_rect, &l, &t, &r, &b);
-
+
GHOST_DisposeRectangle(client_rect);
-
+
wm_get_desktopsize(&scr_w, &scr_h);
sizex = r - l;
sizey = b - t;
@@ -1467,8 +1472,8 @@ static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr C_void_ptr
* Ghost sometimes send size or move events when the window hasn't changed.
* One case of this is using compiz on linux. To alleviate the problem
* we ignore all such event here.
- *
- * It might be good to eventually do that at Ghost level, but that is for
+ *
+ * It might be good to eventually do that at Ghost level, but that is for
* another time.
*/
if (win->sizex != sizex ||
@@ -1511,12 +1516,12 @@ static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr C_void_ptr
win->posx, win->posy, win->sizex, win->sizey);
}
}
-
+
wm_window_make_drawable(wm, win);
BKE_icon_changed(screen->id.icon_id);
WM_event_add_notifier(C, NC_SCREEN | NA_EDITED, NULL);
WM_event_add_notifier(C, NC_WINDOW | NA_EDITED, NULL);
-
+
#if defined(__APPLE__) || defined(WIN32)
/* OSX and Win32 don't return to the mainloop while resize */
wm_event_do_notifiers(C);
@@ -1547,19 +1552,19 @@ static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr C_void_ptr
PointerRNA props_ptr;
wmWindow *oldWindow;
const char *path = GHOST_GetEventData(evt);
-
+
if (path) {
wmOperatorType *ot = WM_operatortype_find("WM_OT_open_mainfile", false);
/* operator needs a valid window in context, ensures
* it is correctly set */
oldWindow = CTX_wm_window(C);
CTX_wm_window_set(C, win);
-
+
WM_operator_properties_create_ptr(&props_ptr, ot);
RNA_string_set(&props_ptr, "filepath", path);
WM_operator_name_call_ptr(C, ot, WM_OP_EXEC_DEFAULT, &props_ptr);
WM_operator_properties_free(&props_ptr);
-
+
CTX_wm_window_set(C, oldWindow);
}
break;
@@ -1569,53 +1574,53 @@ static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr C_void_ptr
wmEvent event;
GHOST_TEventDragnDropData *ddd = GHOST_GetEventData(evt);
int wx, wy;
-
+
/* entering window, update mouse pos */
wm_get_cursor_position(win, &wx, &wy);
win->eventstate->x = wx;
win->eventstate->y = wy;
-
+
wm_event_init_from_window(win, &event); /* copy last state, like mouse coords */
-
+
/* activate region */
event.type = MOUSEMOVE;
event.prevx = event.x;
event.prevy = event.y;
-
+
wm->winactive = win; /* no context change! c->wm->windrawable is drawable, or for area queues */
win->active = 1;
-
+
wm_event_add(win, &event);
-
-
+
+
/* make blender drop event with custom data pointing to wm drags */
event.type = EVT_DROP;
event.val = KM_RELEASE;
event.custom = EVT_DATA_DRAGDROP;
event.customdata = &wm->drags;
event.customdatafree = 1;
-
+
wm_event_add(win, &event);
-
+
/* printf("Drop detected\n"); */
-
+
/* add drag data to wm for paths: */
-
+
if (ddd->dataType == GHOST_kDragnDropTypeFilenames) {
GHOST_TStringArray *stra = ddd->data;
int a, icon;
-
+
for (a = 0; a < stra->count; a++) {
printf("drop file %s\n", stra->strings[a]);
/* try to get icon type from extension */
icon = ED_file_extension_icon((char *)stra->strings[a]);
-
+
WM_event_start_drag(C, icon, WM_DRAG_PATH, stra->strings[a], 0.0, WM_DRAG_NOP);
/* void poin should point to string, it makes a copy */
break; /* only one drop element supported now */
}
}
-
+
break;
}
case GHOST_kEventNativeResolutionChange:
@@ -1645,7 +1650,7 @@ static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr C_void_ptr
case GHOST_kEventTrackpad:
{
GHOST_TEventTrackpadData *pd = data;
-
+
wm_cursor_position_from_ghost(win, &pd->x, &pd->y);
wm_event_add_ghostevent(wm, win, type, time, data);
break;
@@ -1653,7 +1658,7 @@ static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr C_void_ptr
case GHOST_kEventCursorMove:
{
GHOST_TEventCursorData *cd = data;
-
+
wm_cursor_position_from_ghost(win, &cd->x, &cd->y);
wm_event_add_ghostevent(wm, win, type, time, data);
break;
@@ -1681,7 +1686,7 @@ static int wm_window_timer(const bContext *C)
wmWindow *win;
double time = PIL_check_seconds_timer();
int retval = 0;
-
+
for (wt = wm->timers.first; wt; wt = wtnext) {
wtnext = wt->next; /* in case timer gets removed */
win = wt->win;
@@ -1702,7 +1707,7 @@ static int wm_window_timer(const bContext *C)
else if (win) {
wmEvent event;
wm_event_init_from_window(win, &event);
-
+
event.type = wt->event_type;
event.val = KM_NOTHING;
event.keymodifier = 0;
@@ -1718,7 +1723,7 @@ static int wm_window_timer(const bContext *C)
return retval;
}
-void wm_window_process_events(const bContext *C)
+void wm_window_process_events(const bContext *C)
{
int hasevent;
@@ -1728,7 +1733,7 @@ void wm_window_process_events(const bContext *C)
if (hasevent)
GHOST_DispatchEvents(g_system);
-
+
hasevent |= wm_window_timer(C);
/* no event, we sleep 5 milliseconds */
@@ -1736,7 +1741,7 @@ void wm_window_process_events(const bContext *C)
PIL_sleep_ms(5);
}
-void wm_window_process_events_nosleep(void)
+void wm_window_process_events_nosleep(void)
{
if (GHOST_ProcessEvents(g_system, 0))
GHOST_DispatchEvents(g_system);
@@ -1755,10 +1760,10 @@ void wm_window_testbreak(void)
*/
if ((curtime - ltime) > 0.05) {
int hasevent = GHOST_ProcessEvents(g_system, 0); /* 0 is no wait */
-
+
if (hasevent)
GHOST_DispatchEvents(g_system);
-
+
ltime = curtime;
}
}
@@ -1775,13 +1780,13 @@ void wm_ghost_init(bContext *C)
if (C != NULL) {
consumer = GHOST_CreateEventConsumer(ghost_event_proc, C);
}
-
+
g_system = GHOST_CreateSystem();
if (C != NULL) {
GHOST_AddEventConsumer(g_system, consumer);
}
-
+
if (wm_init_state.native_pixels) {
GHOST_UseNativePixels();
}
@@ -1802,7 +1807,7 @@ void wm_ghost_exit(void)
void WM_event_timer_sleep(wmWindowManager *wm, wmWindow *UNUSED(win), wmTimer *timer, bool do_sleep)
{
wmTimer *wt;
-
+
for (wt = wm->timers.first; wt; wt = wt->next)
if (wt == timer)
break;
@@ -1821,9 +1826,9 @@ wmTimer *WM_event_add_timer(wmWindowManager *wm, wmWindow *win, int event_type,
wt->stime = wt->ltime;
wt->timestep = timestep;
wt->win = win;
-
+
BLI_addtail(&wm->timers, wt);
-
+
return wt;
}
@@ -1848,23 +1853,23 @@ wmTimer *WM_event_add_timer_notifier(wmWindowManager *wm, wmWindow *win, unsigne
void WM_event_remove_timer(wmWindowManager *wm, wmWindow *UNUSED(win), wmTimer *timer)
{
wmTimer *wt;
-
+
/* extra security check */
for (wt = wm->timers.first; wt; wt = wt->next)
if (wt == timer)
break;
if (wt) {
wmWindow *win;
-
+
if (wm->reports.reporttimer == wt)
wm->reports.reporttimer = NULL;
-
+
BLI_remlink(&wm->timers, wt);
if (wt->customdata != NULL && (wt->flags & WM_TIMER_NO_FREE_CUSTOM_DATA) == 0) {
MEM_freeN(wt->customdata);
}
MEM_freeN(wt);
-
+
/* there might be events in queue with this timer as customdata */
for (win = wm->windows.first; win; win = win->next) {
wmEvent *event;
@@ -1901,7 +1906,7 @@ static char *wm_clipboard_text_get_ex(bool selection, int *r_len,
*r_len = 0;
return NULL;
}
-
+
/* always convert from \r\n to \n */
p2 = newbuf = MEM_mallocN(strlen(buf) + 1, __func__);
@@ -1927,7 +1932,7 @@ static char *wm_clipboard_text_get_ex(bool selection, int *r_len,
*p2 = '\0';
free(buf); /* ghost uses regular malloc */
-
+
*r_len = (p2 - newbuf);
return newbuf;
@@ -1959,16 +1964,16 @@ void WM_clipboard_text_set(const char *buf, bool selection)
const char *p;
char *p2, *newbuf;
int newlen = 0;
-
+
for (p = buf; *p; p++) {
if (*p == '\n')
newlen += 2;
else
newlen++;
}
-
+
newbuf = MEM_callocN(newlen + 1, "WM_clipboard_text_set");
-
+
for (p = buf, p2 = newbuf; *p; p++, p2++) {
if (*p == '\n') {
*(p2++) = '\r'; *p2 = '\n';
@@ -1978,7 +1983,7 @@ void WM_clipboard_text_set(const char *buf, bool selection)
}
}
*p2 = '\0';
-
+
GHOST_putClipboard((GHOST_TInt8 *)newbuf, selection);
MEM_freeN(newbuf);
#else
@@ -2007,24 +2012,25 @@ void wm_window_get_position(wmWindow *win, int *r_pos_x, int *r_pos_y)
*r_pos_y = win->posy;
}
-void wm_window_set_size(wmWindow *win, int width, int height)
+void wm_window_set_size(wmWindow *win, int width, int height)
{
GHOST_SetClientSize(win->ghostwin, width, height);
}
-void wm_window_lower(wmWindow *win)
+void wm_window_lower(wmWindow *win)
{
GHOST_SetWindowOrder(win->ghostwin, GHOST_kWindowOrderBottom);
}
-void wm_window_raise(wmWindow *win)
+void wm_window_raise(wmWindow *win)
{
GHOST_SetWindowOrder(win->ghostwin, GHOST_kWindowOrderTop);
}
void wm_window_swap_buffers(wmWindow *win)
{
- GPU_texture_delete_orphans(); /* XXX should be done elsewhere. */
+ GPU_texture_orphans_delete(); /* XXX should be done elsewhere. */
+ GPU_material_orphans_delete(); /* XXX Amen to that. */
GHOST_SwapWindowBuffers(win->ghostwin);
}
@@ -2119,13 +2125,13 @@ float WM_cursor_pressure(const struct wmWindow *win)
int WM_window_pixels_x(const wmWindow *win)
{
float f = GHOST_GetNativePixelSize(win->ghostwin);
-
+
return (int)(f * (float)win->sizex);
}
int WM_window_pixels_y(const wmWindow *win)
{
float f = GHOST_GetNativePixelSize(win->ghostwin);
-
+
return (int)(f * (float)win->sizey);
}
diff --git a/source/blender/windowmanager/wm.h b/source/blender/windowmanager/wm.h
index 33ca415b664..c92691eb65e 100644
--- a/source/blender/windowmanager/wm.h
+++ b/source/blender/windowmanager/wm.h
@@ -41,7 +41,7 @@ typedef struct wmPaintCursor {
struct wmPaintCursor *next, *prev;
void *customdata;
-
+
int (*poll)(struct bContext *C);
void (*draw)(bContext *C, int, int, void *customdata);
} wmPaintCursor;
@@ -54,7 +54,7 @@ extern void wm_close_and_free_all(bContext *C, ListBase *);
extern void wm_add_default(struct Main *bmain, bContext *C);
extern void wm_clear_default_size(bContext *C);
-
+
/* register to windowmanager for redo or macro */
void wm_operator_register(bContext *C, wmOperator *op);
diff --git a/source/blender/windowmanager/wm_cursors.h b/source/blender/windowmanager/wm_cursors.h
index c695a12f52c..939409f9511 100644
--- a/source/blender/windowmanager/wm_cursors.h
+++ b/source/blender/windowmanager/wm_cursors.h
@@ -39,12 +39,12 @@ void wm_init_cursor_data(void);
/* old cursors */
enum {
CURSOR_FACESEL = BC_GHOST_CURSORS,
- CURSOR_WAIT,
- CURSOR_EDIT,
- CURSOR_X_MOVE,
- CURSOR_Y_MOVE,
- CURSOR_HELP,
- CURSOR_STD,
+ CURSOR_WAIT,
+ CURSOR_EDIT,
+ CURSOR_X_MOVE,
+ CURSOR_Y_MOVE,
+ CURSOR_HELP,
+ CURSOR_STD,
CURSOR_NONE,
CURSOR_PENCIL,
CURSOR_COPY
@@ -57,21 +57,21 @@ typedef struct BCursor {
char *small_bm;
char *small_mask;
- char small_sizex;
- char small_sizey;
- char small_hotx;
- char small_hoty;
+ char small_sizex;
+ char small_sizey;
+ char small_hotx;
+ char small_hoty;
- char *big_bm;
+ char *big_bm;
char *big_mask;
- char big_sizex;
- char big_sizey;
- char big_hotx;
- char big_hoty;
+ char big_sizex;
+ char big_sizey;
+ char big_hotx;
+ char big_hoty;
- char fg_color;
- char bg_color;
+ char fg_color;
+ char bg_color;
} BCursor;
@@ -101,7 +101,7 @@ enum {
enum {
BC_BLACK = 0,
- BC_WHITE,
+ BC_WHITE,
BC_RED,
BC_BLUE,
BC_GREEN,
diff --git a/source/blender/windowmanager/wm_event_types.h b/source/blender/windowmanager/wm_event_types.h
index 5edd4a76127..db2fd5ce7f2 100644
--- a/source/blender/windowmanager/wm_event_types.h
+++ b/source/blender/windowmanager/wm_event_types.h
@@ -92,7 +92,7 @@ enum {
WM_IME_COMPOSITE_EVENT = 0x0015,
/* IME event, GHOST_kEventImeCompositionEnd in ghost */
WM_IME_COMPOSITE_END = 0x0016,
-
+
/* Tablet/Pen Specific Events */
TABLET_STYLUS = 0x001a,
TABLET_ERASER = 0x001b,
diff --git a/source/tools b/source/tools
-Subproject 6bcd05cf6aaafae07b8a15313d7fdda1471ff59
+Subproject fca325137b6ee2dfd0930ca87684ccf30703554
diff --git a/tests/gtests/alembic/abc_export_test.cc b/tests/gtests/alembic/abc_export_test.cc
index dab1e3ae040..c950084ef64 100644
--- a/tests/gtests/alembic/abc_export_test.cc
+++ b/tests/gtests/alembic/abc_export_test.cc
@@ -16,9 +16,8 @@ extern "C" {
class TestableAbcExporter : public AbcExporter {
public:
TestableAbcExporter(Main *bmain,
- Scene *scene, Depsgraph *depsgraph,
const char *filename, ExportSettings &settings)
- : AbcExporter(bmain, scene, depsgraph, filename, settings)
+ : AbcExporter(bmain, filename, settings)
{
}
@@ -57,7 +56,10 @@ protected:
/* TODO(sergey): Pass scene layer somehow? */
ViewLayer *view_layer = (ViewLayer *)scene.view_layers.first;
- depsgraph = DEG_graph_new(&scene, view_layer, DAG_EVAL_VIEWPORT);
+ settings.depsgraph = depsgraph = DEG_graph_new(&scene, view_layer, DAG_EVAL_VIEWPORT);
+
+ settings.scene = &scene;
+ settings.view_layer = view_layer;
exporter = NULL;
}
@@ -72,7 +74,7 @@ protected:
// Call after setting up the settings.
void createExporter()
{
- exporter = new TestableAbcExporter(bmain, &scene, depsgraph, "somefile.abc", settings);
+ exporter = new TestableAbcExporter(bmain, "somefile.abc", settings);
}
};
diff --git a/tests/gtests/blenlib/BLI_heap_test.cc b/tests/gtests/blenlib/BLI_heap_test.cc
index 82acdabd7eb..dd0bc3451ce 100644
--- a/tests/gtests/blenlib/BLI_heap_test.cc
+++ b/tests/gtests/blenlib/BLI_heap_test.cc
@@ -40,7 +40,7 @@ TEST(heap, One)
const char *in = "test";
heap = BLI_heap_new();
-
+
BLI_heap_insert(heap, 0.0f, (void *)in);
EXPECT_FALSE(BLI_heap_is_empty(heap));
EXPECT_EQ(BLI_heap_len(heap), 1);
diff --git a/tests/python/bl_pyapi_mathutils.py b/tests/python/bl_pyapi_mathutils.py
index 9ca0376192a..b2d3d79fd56 100644
--- a/tests/python/bl_pyapi_mathutils.py
+++ b/tests/python/bl_pyapi_mathutils.py
@@ -127,7 +127,7 @@ class MatrixTesting(unittest.TestCase):
(0, 0, 0, 1)))
vec = Vector((1, 2, 3))
-
+
prod_mat_vec = Vector((7, 12, 4))
prod_vec_mat = Vector((1, 12, 5))
diff --git a/tests/python/collada/animation/test_animation_simple.py b/tests/python/collada/animation/test_animation_simple.py
index 6686d429261..bdfae03aafb 100644
--- a/tests/python/collada/animation/test_animation_simple.py
+++ b/tests/python/collada/animation/test_animation_simple.py
@@ -113,37 +113,37 @@ class MeshExportTest4(AbstractColladaTest):
test = "suzannes_parent_inverse_sample_10_matrix"
reference_dae = self.testdir / Path("%s.dae" % test)
outfile = tempdir / Path("%s_out.dae" % test)
-
+
bpy.ops.wm.collada_export(filepath="%s" % str(outfile),
- check_existing=True,
- filemode=8,
- display_type='DEFAULT',
- sort_method='FILE_SORT_ALPHA',
- apply_modifiers=True,
- export_mesh_type=0,
- export_mesh_type_selection='view',
- selected=True,
- include_children=True,
- include_armatures=True,
- include_shapekeys=False,
- deform_bones_only=False,
- include_animations=True,
- sample_animations=True,
- sampling_rate=10,
- active_uv_only=False,
- use_texture_copies=True,
- triangulate=False,
- use_object_instantiation=True,
- use_blender_profile=True,
- sort_by_name=False,
- export_transformation_type=0,
- export_transformation_type_selection='matrix',
- export_texture_type=0,
- export_texture_type_selection='mat',
- open_sim=False,
- limit_precision=True,
+ check_existing=True,
+ filemode=8,
+ display_type='DEFAULT',
+ sort_method='FILE_SORT_ALPHA',
+ apply_modifiers=True,
+ export_mesh_type=0,
+ export_mesh_type_selection='view',
+ selected=True,
+ include_children=True,
+ include_armatures=True,
+ include_shapekeys=False,
+ deform_bones_only=False,
+ include_animations=True,
+ sample_animations=True,
+ sampling_rate=10,
+ active_uv_only=False,
+ use_texture_copies=True,
+ triangulate=False,
+ use_object_instantiation=True,
+ use_blender_profile=True,
+ sort_by_name=False,
+ export_transformation_type=0,
+ export_transformation_type_selection='matrix',
+ export_texture_type=0,
+ export_texture_type_selection='mat',
+ open_sim=False,
+ limit_precision=True,
keep_bind_info=False)
-
+
# Now check the resulting Collada file.
if not self.checkdae(reference_dae, outfile):
self.fail()
@@ -154,37 +154,37 @@ class MeshExportTest3(AbstractColladaTest):
test = "suzannes_parent_inverse_sample_10_channels"
reference_dae = self.testdir / Path("%s.dae" % test)
outfile = tempdir / Path("%s_out.dae" % test)
-
+
bpy.ops.wm.collada_export(filepath="%s" % str(outfile),
- check_existing=True,
- filemode=8,
- display_type='DEFAULT',
- sort_method='FILE_SORT_ALPHA',
- apply_modifiers=True,
- export_mesh_type=0,
- export_mesh_type_selection='view',
- selected=True,
- include_children=True,
- include_armatures=True,
- include_shapekeys=False,
- deform_bones_only=False,
- include_animations=True,
- sample_animations=True,
- sampling_rate=10,
- active_uv_only=False,
- use_texture_copies=True,
- triangulate=False,
- use_object_instantiation=True,
- use_blender_profile=True,
- sort_by_name=False,
- export_transformation_type=0,
- export_transformation_type_selection='transrotloc',
- export_texture_type=0,
- export_texture_type_selection='mat',
- open_sim=False,
- limit_precision=True,
+ check_existing=True,
+ filemode=8,
+ display_type='DEFAULT',
+ sort_method='FILE_SORT_ALPHA',
+ apply_modifiers=True,
+ export_mesh_type=0,
+ export_mesh_type_selection='view',
+ selected=True,
+ include_children=True,
+ include_armatures=True,
+ include_shapekeys=False,
+ deform_bones_only=False,
+ include_animations=True,
+ sample_animations=True,
+ sampling_rate=10,
+ active_uv_only=False,
+ use_texture_copies=True,
+ triangulate=False,
+ use_object_instantiation=True,
+ use_blender_profile=True,
+ sort_by_name=False,
+ export_transformation_type=0,
+ export_transformation_type_selection='transrotloc',
+ export_texture_type=0,
+ export_texture_type_selection='mat',
+ open_sim=False,
+ limit_precision=True,
keep_bind_info=False)
-
+
# Now check the resulting Collada file.
if not self.checkdae(reference_dae, outfile):
self.fail()
@@ -195,37 +195,37 @@ class MeshExportTest2(AbstractColladaTest):
test = "suzannes_parent_inverse_keyframes_matrix"
reference_dae = self.testdir / Path("%s.dae" % test)
outfile = tempdir / Path("%s_out.dae" % test)
-
+
bpy.ops.wm.collada_export(filepath="%s" % str(outfile),
- check_existing=True,
- filemode=8,
- display_type='DEFAULT',
- sort_method='FILE_SORT_ALPHA',
- apply_modifiers=True,
- export_mesh_type=0,
- export_mesh_type_selection='view',
- selected=True,
- include_children=True,
- include_armatures=True,
- include_shapekeys=False,
- deform_bones_only=False,
- include_animations=True,
- sample_animations=False,
- sampling_rate=1,
- active_uv_only=False,
- use_texture_copies=True,
- triangulate=False,
- use_object_instantiation=True,
- use_blender_profile=True,
- sort_by_name=False,
- export_transformation_type=0,
- export_transformation_type_selection='matrix',
- export_texture_type=0,
- export_texture_type_selection='mat',
- open_sim=False,
- limit_precision=True,
+ check_existing=True,
+ filemode=8,
+ display_type='DEFAULT',
+ sort_method='FILE_SORT_ALPHA',
+ apply_modifiers=True,
+ export_mesh_type=0,
+ export_mesh_type_selection='view',
+ selected=True,
+ include_children=True,
+ include_armatures=True,
+ include_shapekeys=False,
+ deform_bones_only=False,
+ include_animations=True,
+ sample_animations=False,
+ sampling_rate=1,
+ active_uv_only=False,
+ use_texture_copies=True,
+ triangulate=False,
+ use_object_instantiation=True,
+ use_blender_profile=True,
+ sort_by_name=False,
+ export_transformation_type=0,
+ export_transformation_type_selection='matrix',
+ export_texture_type=0,
+ export_texture_type_selection='mat',
+ open_sim=False,
+ limit_precision=True,
keep_bind_info=False)
-
+
# Now check the resulting Collada file.
if not self.checkdae(reference_dae, outfile):
self.fail()
@@ -236,45 +236,45 @@ class MeshExportTest1(AbstractColladaTest):
test = "suzannes_parent_inverse_keyframes_channels"
reference_dae = self.testdir / Path("%s.dae" % test)
outfile = tempdir / Path("%s_out.dae" % test)
-
+
bpy.ops.wm.collada_export(filepath="%s" % str(outfile),
- check_existing=True,
- filemode=8,
- display_type='DEFAULT',
- sort_method='FILE_SORT_ALPHA',
- apply_modifiers=True,
- export_mesh_type=0,
- export_mesh_type_selection='view',
- selected=True,
- include_children=True,
- include_armatures=True,
- include_shapekeys=False,
- deform_bones_only=False,
- include_animations=True,
- sample_animations=False,
- sampling_rate=1,
- active_uv_only=False,
- use_texture_copies=True,
- triangulate=False,
- use_object_instantiation=True,
- use_blender_profile=True,
- sort_by_name=False,
- export_transformation_type=0,
- export_transformation_type_selection='transrotloc',
- export_texture_type=0,
- export_texture_type_selection='mat',
- open_sim=False,
- limit_precision=True,
+ check_existing=True,
+ filemode=8,
+ display_type='DEFAULT',
+ sort_method='FILE_SORT_ALPHA',
+ apply_modifiers=True,
+ export_mesh_type=0,
+ export_mesh_type_selection='view',
+ selected=True,
+ include_children=True,
+ include_armatures=True,
+ include_shapekeys=False,
+ deform_bones_only=False,
+ include_animations=True,
+ sample_animations=False,
+ sampling_rate=1,
+ active_uv_only=False,
+ use_texture_copies=True,
+ triangulate=False,
+ use_object_instantiation=True,
+ use_blender_profile=True,
+ sort_by_name=False,
+ export_transformation_type=0,
+ export_transformation_type_selection='transrotloc',
+ export_texture_type=0,
+ export_texture_type_selection='mat',
+ open_sim=False,
+ limit_precision=True,
keep_bind_info=False)
-
+
# Now check the resulting Collada file.
if not self.checkdae(reference_dae, outfile):
self.fail()
-
+
if __name__ == '__main__':
sys.argv = [__file__] + (sys.argv[sys.argv.index("--") + 1:] if "--" in sys.argv else [])
parser = argparse.ArgumentParser()
parser.add_argument('--testdir', required=True)
args, remaining = parser.parse_known_args()
- unittest.main(argv=sys.argv[0:1]+remaining) \ No newline at end of file
+ unittest.main(argv=sys.argv[0:1]+remaining)
diff --git a/tests/python/collada/mesh/test_mesh_simple.py b/tests/python/collada/mesh/test_mesh_simple.py
index f592160f6aa..213c6177fde 100644
--- a/tests/python/collada/mesh/test_mesh_simple.py
+++ b/tests/python/collada/mesh/test_mesh_simple.py
@@ -113,7 +113,7 @@ class MeshExportTest(AbstractColladaTest):
test = "mesh_simple_001"
reference_dae = self.testdir / Path("%s.dae" % test)
outfile = tempdir / Path("%s_out.dae" % test)
-
+
bpy.ops.wm.collada_export(filepath="%s" % str(outfile),
check_existing=True,
filemode=8,
@@ -141,7 +141,7 @@ class MeshExportTest(AbstractColladaTest):
open_sim=False,
limit_precision=False,
keep_bind_info=False)
-
+
# Now check the resulting Collada file.
if not self.checkdae(reference_dae, outfile):
self.fail()
@@ -151,4 +151,4 @@ if __name__ == '__main__':
parser = argparse.ArgumentParser()
parser.add_argument('--testdir', required=True)
args, remaining = parser.parse_known_args()
- unittest.main(argv=sys.argv[0:1]+remaining) \ No newline at end of file
+ unittest.main(argv=sys.argv[0:1]+remaining)
diff --git a/tests/python/ffmpeg_tests.py b/tests/python/ffmpeg_tests.py
index 9493d6f7a17..70677677667 100755
--- a/tests/python/ffmpeg_tests.py
+++ b/tests/python/ffmpeg_tests.py
@@ -60,7 +60,7 @@ class AbstractFFmpegSequencerTest(AbstractFFmpegTest):
class FPSDetectionTest(AbstractFFmpegSequencerTest):
def test_T51153(self):
self.assertAlmostEqual(
- self.get_movie_file_fps('T51153_bad_clip_2.mts'),
+ self.get_movie_file_fps('T51153_bad_clip_2.mts'),
29.97,
places=2)
diff --git a/tests/python/modules/test_utils.py b/tests/python/modules/test_utils.py
index 55ef882c49c..c4496c3e3ac 100755
--- a/tests/python/modules/test_utils.py
+++ b/tests/python/modules/test_utils.py
@@ -61,7 +61,7 @@ class AbstractBlenderRunnerTest(unittest.TestCase):
# Set in a subclass
blender: pathlib.Path = None
testdir: pathlib.Path = None
-
+
def run_blender(self, filepath: str, python_script: str, timeout: int=300) -> str:
"""Runs Blender by opening a blendfile and executing a script.
diff --git a/tests/python/rna_array.py b/tests/python/rna_array.py
index f9777a5b438..dda13d2c3ae 100644
--- a/tests/python/rna_array.py
+++ b/tests/python/rna_array.py
@@ -23,7 +23,7 @@ class TestArray(unittest.TestCase):
test.farr= (1.0, 2.0, 3.0)
test.iarr= (7, 8, 9)
test.barr= (False, True, False)
-
+
# test access
# test slice access, negative indices
def test_access(self):
@@ -40,7 +40,7 @@ class TestArray(unittest.TestCase):
def test_access_fail(self):
for arr in (test.farr, test.iarr, test.barr):
self.assertRaises(IndexError, lambda : arr[4])
-
+
# test assignment of a whole array
def test_assign_array(self):
# should accept int as float
@@ -83,7 +83,7 @@ class TestArray(unittest.TestCase):
for i in range(len(arr)):
val= rand_func()
arr[i] = val
-
+
self.assertEqual(arr[i], val)
# float prop should accept also int
@@ -92,7 +92,7 @@ class TestArray(unittest.TestCase):
test.farr[i] = val
self.assertEqual(test.farr[i], float(val))
- #
+ #
def test_assign_item_fail(self):
def assign_bad_index(arr):
@@ -100,12 +100,12 @@ class TestArray(unittest.TestCase):
def assign_bad_type(arr):
arr[1] = "123"
-
+
for arr in [test.farr, test.iarr, test.barr]:
self.assertRaises(IndexError, assign_bad_index, arr)
# not testing bool because bool allows not only (True|False)
- for arr in [test.farr, test.iarr]:
+ for arr in [test.farr, test.iarr]:
self.assertRaises(TypeError, assign_bad_type, arr)
def test_dynamic_assign_array(self):
@@ -118,7 +118,7 @@ class TestArray(unittest.TestCase):
def test_dynamic_assign_array_fail(self):
# could also test too big length here
-
+
def assign_empty_list(arr):
setattr(test, arr, ())
@@ -236,7 +236,7 @@ def make_random_array(len, rand_func):
arr= []
for i in range(len):
arr.append(rand_func())
-
+
return arr
def make_random_2d_array(dimsize, rand_func):
diff --git a/tests/python/view_layer/CMakeLists.txt b/tests/python/view_layer/CMakeLists.txt
index 69f7af20ad2..cec839a3efc 100644
--- a/tests/python/view_layer/CMakeLists.txt
+++ b/tests/python/view_layer/CMakeLists.txt
@@ -18,7 +18,7 @@
#
# ***** END GPL LICENSE BLOCK *****
-# --env-system-scripts allows to run without the install target.
+# --env-system-scripts allows to run without the install target.
# Use '--write-blend=/tmp/test.blend' to view output
@@ -43,7 +43,7 @@ else()
set(TEST_BLENDER_EXE ${EXECUTABLE_OUTPUT_PATH}/blender)
endif()
-# for testing with valgrind prefix: valgrind --track-origins=yes --error-limit=no
+# for testing with valgrind prefix: valgrind --track-origins=yes --error-limit=no
set(TEST_BLENDER_EXE ${TEST_BLENDER_EXE} --background -noaudio --factory-startup --env-system-scripts ${CMAKE_SOURCE_DIR}/release/scripts)