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:
authorBenoit Bolsee <benoit.bolsee@online.be>2016-06-08 00:30:03 +0300
committerBenoit Bolsee <benoit.bolsee@online.be>2016-06-08 00:30:03 +0300
commit324bee2c3fc06b8d1a64cd49601adfb11227d4de (patch)
treeb948cd004aad3b40d42121a76157d126c249d0c5
parentd48c71b3b1f1fc686c2887c3d594a57711a20664 (diff)
parenta506f4c74eb60a5b9fc9c6dadaab34d40a806191 (diff)
Merge remote-tracking branch 'origin/master' into decklink
-rw-r--r--CMakeLists.txt11
-rw-r--r--build_files/buildbot/slave_compile.py11
-rw-r--r--build_files/cmake/macros.cmake23
-rwxr-xr-xdoc/python_api/sphinx_doc_gen.sh2
-rw-r--r--extern/Eigen3/README.blender6
-rw-r--r--extern/binreloc/README.blender6
-rw-r--r--extern/carve/README.blender4
-rw-r--r--extern/ceres/README.blender4
-rw-r--r--extern/clew/README.blender5
-rw-r--r--extern/cuew/README.blender5
-rw-r--r--extern/gflags/README.blender (renamed from extern/gflags/README.libmv)6
-rw-r--r--extern/glog/README.blender (renamed from extern/glog/README.libmv)2
-rw-r--r--extern/gtest/README.blender (renamed from extern/gtest/README)6
-rw-r--r--extern/libopenjpeg/README.blender5
-rw-r--r--extern/rangetree/README.blender5
-rw-r--r--extern/sdlew/README.blender5
-rw-r--r--extern/wcwidth/README.blender5
-rw-r--r--extern/xdnd/README.blender8
-rw-r--r--intern/cycles/app/cycles_xml.cpp228
-rw-r--r--intern/cycles/blender/addon/properties.py2
-rw-r--r--intern/cycles/blender/addon/ui.py5
-rw-r--r--intern/cycles/blender/blender_camera.cpp12
-rw-r--r--intern/cycles/blender/blender_curves.cpp87
-rw-r--r--intern/cycles/blender/blender_mesh.cpp41
-rw-r--r--intern/cycles/blender/blender_particles.cpp2
-rw-r--r--intern/cycles/blender/blender_shader.cpp209
-rw-r--r--intern/cycles/blender/blender_util.h3
-rw-r--r--intern/cycles/bvh/bvh.cpp28
-rw-r--r--intern/cycles/bvh/bvh_build.cpp36
-rw-r--r--intern/cycles/bvh/bvh_split.cpp21
-rw-r--r--intern/cycles/device/device_cpu.cpp4
-rw-r--r--intern/cycles/device/device_cuda.cpp5
-rw-r--r--intern/cycles/device/device_multi.cpp4
-rw-r--r--intern/cycles/device/device_network.cpp4
-rw-r--r--intern/cycles/device/device_opencl.cpp85
-rw-r--r--intern/cycles/graph/node.cpp127
-rw-r--r--intern/cycles/graph/node.h10
-rw-r--r--intern/cycles/graph/node_type.cpp38
-rw-r--r--intern/cycles/graph/node_type.h20
-rw-r--r--intern/cycles/graph/node_xml.cpp28
-rw-r--r--intern/cycles/kernel/CMakeLists.txt1
-rw-r--r--intern/cycles/kernel/geom/geom_bvh.h22
-rw-r--r--intern/cycles/kernel/geom/geom_bvh_traversal.h26
-rw-r--r--intern/cycles/kernel/geom/geom_qbvh_traversal.h25
-rw-r--r--intern/cycles/kernel/geom/geom_triangle_intersect.h9
-rw-r--r--intern/cycles/kernel/kernel_bake.h31
-rw-r--r--intern/cycles/kernel/kernel_emission.h41
-rw-r--r--intern/cycles/kernel/kernel_globals.h8
-rw-r--r--intern/cycles/kernel/kernel_light.h17
-rw-r--r--intern/cycles/kernel/kernel_path.h109
-rw-r--r--intern/cycles/kernel/kernel_path_branched.h69
-rw-r--r--intern/cycles/kernel/kernel_path_state.h9
-rw-r--r--intern/cycles/kernel/kernel_path_surface.h22
-rw-r--r--intern/cycles/kernel/kernel_path_volume.h20
-rw-r--r--intern/cycles/kernel/kernel_shadow.h48
-rw-r--r--intern/cycles/kernel/kernel_types.h4
-rw-r--r--intern/cycles/kernel/kernel_volume.h60
-rw-r--r--intern/cycles/kernel/kernels/cpu/kernel.cpp14
-rw-r--r--intern/cycles/kernel/kernels/cpu/kernel_cpu_image.h36
-rw-r--r--intern/cycles/kernel/shaders/node_brick_texture.osl10
-rw-r--r--intern/cycles/kernel/shaders/node_convert_from_color.osl24
-rw-r--r--intern/cycles/kernel/shaders/node_convert_from_float.osl24
-rw-r--r--intern/cycles/kernel/shaders/node_convert_from_int.osl26
-rw-r--r--intern/cycles/kernel/shaders/node_convert_from_normal.osl24
-rw-r--r--intern/cycles/kernel/shaders/node_convert_from_point.osl24
-rw-r--r--intern/cycles/kernel/shaders/node_convert_from_string.osl14
-rw-r--r--intern/cycles/kernel/shaders/node_convert_from_vector.osl24
-rw-r--r--intern/cycles/kernel/shaders/node_gradient_texture.osl4
-rw-r--r--intern/cycles/kernel/shaders/node_image_texture.osl4
-rw-r--r--intern/cycles/kernel/shaders/node_magic_texture.osl4
-rw-r--r--intern/cycles/kernel/shaders/node_math.osl4
-rw-r--r--intern/cycles/kernel/shaders/node_mix.osl4
-rw-r--r--intern/cycles/kernel/shaders/node_musgrave_texture.osl12
-rw-r--r--intern/cycles/kernel/shaders/node_normal.osl4
-rw-r--r--intern/cycles/kernel/shaders/node_rgb_ramp.osl4
-rw-r--r--intern/cycles/kernel/shaders/node_subsurface_scattering.osl6
-rw-r--r--intern/cycles/kernel/shaders/node_voronoi_texture.osl4
-rw-r--r--intern/cycles/kernel/shaders/node_wave_texture.osl6
-rw-r--r--intern/cycles/kernel/split/kernel_background_buffer_update.h4
-rw-r--r--intern/cycles/kernel/split/kernel_data_init.h1
-rw-r--r--intern/cycles/kernel/split/kernel_direct_lighting.h2
-rw-r--r--intern/cycles/kernel/split/kernel_lamp_emission.h2
-rw-r--r--intern/cycles/kernel/split/kernel_shadow_blocked.h1
-rw-r--r--intern/cycles/kernel/svm/svm_closure.h8
-rw-r--r--intern/cycles/kernel/svm/svm_image.h8
-rw-r--r--intern/cycles/kernel/svm/svm_types.h13
-rw-r--r--intern/cycles/render/attribute.cpp20
-rw-r--r--intern/cycles/render/attribute.h6
-rw-r--r--intern/cycles/render/background.cpp5
-rw-r--r--intern/cycles/render/background.h1
-rw-r--r--intern/cycles/render/bake.cpp2
-rw-r--r--intern/cycles/render/camera.cpp184
-rw-r--r--intern/cycles/render/camera.h8
-rw-r--r--intern/cycles/render/curves.h34
-rw-r--r--intern/cycles/render/film.cpp2
-rw-r--r--intern/cycles/render/graph.cpp168
-rw-r--r--intern/cycles/render/graph.h115
-rw-r--r--intern/cycles/render/image.cpp361
-rw-r--r--intern/cycles/render/image.h15
-rw-r--r--intern/cycles/render/integrator.cpp5
-rw-r--r--intern/cycles/render/integrator.h1
-rw-r--r--intern/cycles/render/light.cpp8
-rw-r--r--intern/cycles/render/mesh.cpp232
-rw-r--r--intern/cycles/render/mesh.h61
-rw-r--r--intern/cycles/render/mesh_displace.cpp9
-rw-r--r--intern/cycles/render/nodes.cpp1325
-rw-r--r--intern/cycles/render/nodes.h171
-rw-r--r--intern/cycles/render/object.cpp54
-rw-r--r--intern/cycles/render/object.h11
-rw-r--r--intern/cycles/render/osl.cpp186
-rw-r--r--intern/cycles/render/osl.h7
-rw-r--r--intern/cycles/render/particles.cpp11
-rw-r--r--intern/cycles/render/particles.h2
-rw-r--r--intern/cycles/render/scene.cpp9
-rw-r--r--intern/cycles/render/scene.h8
-rw-r--r--intern/cycles/render/session.cpp14
-rw-r--r--intern/cycles/render/shader.cpp6
-rw-r--r--intern/cycles/render/svm.cpp54
-rw-r--r--intern/cycles/render/svm.h6
-rw-r--r--intern/cycles/subd/subd_dice.cpp23
-rw-r--r--intern/cycles/subd/subd_dice.h2
-rw-r--r--intern/cycles/util/CMakeLists.txt2
-rw-r--r--intern/cycles/util/util_math.h28
-rw-r--r--intern/cycles/util/util_string.cpp40
-rw-r--r--intern/cycles/util/util_string.h5
-rw-r--r--intern/cycles/util/util_system.cpp52
-rw-r--r--intern/cycles/util/util_system.h8
-rw-r--r--intern/cycles/util/util_task.cpp23
-rw-r--r--intern/cycles/util/util_texture.h66
-rw-r--r--intern/cycles/util/util_thread.cpp66
-rw-r--r--intern/cycles/util/util_thread.h36
-rw-r--r--intern/cycles/util/util_windows.cpp88
-rw-r--r--intern/cycles/util/util_windows.h19
-rw-r--r--intern/ghost/intern/GHOST_ContextSDL.cpp2
-rw-r--r--intern/ghost/intern/GHOST_DropTargetWin32.cpp5
-rw-r--r--intern/ghost/intern/GHOST_ISystem.cpp6
-rw-r--r--intern/ghost/intern/GHOST_ISystemPaths.cpp9
-rw-r--r--intern/ghost/intern/GHOST_NDOFManager.cpp6
-rw-r--r--intern/ghost/intern/GHOST_NDOFManager.h1
-rw-r--r--intern/ghost/intern/GHOST_System.cpp37
-rw-r--r--intern/ghost/intern/GHOST_SystemCocoa.mm4
-rw-r--r--intern/ghost/intern/GHOST_SystemWin32.cpp6
-rw-r--r--intern/ghost/intern/GHOST_SystemX11.cpp4
-rw-r--r--intern/ghost/intern/GHOST_Window.h2
-rw-r--r--intern/ghost/intern/GHOST_WindowCocoa.mm2
-rw-r--r--intern/ghost/intern/GHOST_WindowManager.cpp8
-rw-r--r--intern/ghost/intern/GHOST_WindowWin32.cpp3
-rw-r--r--intern/opencolorio/gpu_shader_display_transform.glsl2
-rw-r--r--intern/opensubdiv/gpu_shader_opensubd_display.glsl10
-rw-r--r--release/scripts/modules/bl_i18n_utils/utils_spell_check.py8
-rw-r--r--release/scripts/modules/bpy_types.py8
-rw-r--r--release/scripts/presets/interface_theme/blender_24x.xml4
-rw-r--r--release/scripts/presets/keyconfig/maya.py2
-rw-r--r--release/scripts/startup/bl_operators/wm.py5
-rw-r--r--release/scripts/startup/bl_ui/__init__.py2
-rw-r--r--release/scripts/startup/bl_ui/properties_data_modifier.py1
-rw-r--r--release/scripts/startup/bl_ui/properties_render.py1
-rw-r--r--source/blender/blenkernel/BKE_DerivedMesh.h8
-rw-r--r--source/blender/blenkernel/BKE_animsys.h2
-rw-r--r--source/blender/blenkernel/BKE_fcurve.h2
-rw-r--r--source/blender/blenkernel/BKE_library_idmap.h50
-rw-r--r--source/blender/blenkernel/BKE_mesh.h2
-rw-r--r--source/blender/blenkernel/BKE_object.h2
-rw-r--r--source/blender/blenkernel/BKE_scene.h1
-rw-r--r--source/blender/blenkernel/CMakeLists.txt2
-rw-r--r--source/blender/blenkernel/intern/DerivedMesh.c104
-rw-r--r--source/blender/blenkernel/intern/anim_sys.c28
-rw-r--r--source/blender/blenkernel/intern/armature.c23
-rw-r--r--source/blender/blenkernel/intern/autoexec.c5
-rw-r--r--source/blender/blenkernel/intern/brush.c2
-rw-r--r--source/blender/blenkernel/intern/cdderivedmesh.c7
-rw-r--r--source/blender/blenkernel/intern/colortools.c301
-rw-r--r--source/blender/blenkernel/intern/customdata.c2
-rw-r--r--source/blender/blenkernel/intern/editderivedmesh.c28
-rw-r--r--source/blender/blenkernel/intern/effect.c4
-rw-r--r--source/blender/blenkernel/intern/fcurve.c9
-rw-r--r--source/blender/blenkernel/intern/idcode.c9
-rw-r--r--source/blender/blenkernel/intern/image.c4
-rw-r--r--source/blender/blenkernel/intern/library_idmap.c174
-rw-r--r--source/blender/blenkernel/intern/material.c3
-rw-r--r--source/blender/blenkernel/intern/mesh_evaluate.c13
-rw-r--r--source/blender/blenkernel/intern/object_update.c7
-rw-r--r--source/blender/blenkernel/intern/particle.c15
-rw-r--r--source/blender/blenkernel/intern/pbvh.c3
-rw-r--r--source/blender/blenkernel/intern/pbvh_intern.h5
-rw-r--r--source/blender/blenkernel/intern/scene.c7
-rw-r--r--source/blender/blenkernel/intern/shrinkwrap.c471
-rw-r--r--source/blender/blenkernel/intern/subsurf_ccg.c4
-rw-r--r--source/blender/blenlib/BLI_array_store.h66
-rw-r--r--source/blender/blenlib/BLI_math_geom.h4
-rw-r--r--source/blender/blenlib/BLI_stackdefines.h12
-rw-r--r--source/blender/blenlib/CMakeLists.txt2
-rw-r--r--source/blender/blenlib/intern/BLI_mempool.c42
-rw-r--r--source/blender/blenlib/intern/array_store.c1812
-rw-r--r--source/blender/blenlib/intern/math_geom.c34
-rw-r--r--source/blender/blenlib/intern/noise.c4
-rw-r--r--source/blender/blenloader/intern/readfile.c290
-rw-r--r--source/blender/blenloader/intern/readfile.h6
-rw-r--r--source/blender/blenloader/intern/versioning_270.c16
-rw-r--r--source/blender/bmesh/intern/bmesh_mesh_conv.c8
-rw-r--r--source/blender/bmesh/tools/bmesh_bevel.c477
-rw-r--r--source/blender/collada/ArmatureExporter.cpp54
-rw-r--r--source/blender/collada/ArmatureExporter.h2
-rw-r--r--source/blender/collada/ArmatureImporter.cpp336
-rw-r--r--source/blender/collada/ArmatureImporter.h30
-rw-r--r--source/blender/collada/DocumentImporter.cpp4
-rw-r--r--source/blender/collada/ExportSettings.h1
-rw-r--r--source/blender/collada/ExtraTags.cpp23
-rw-r--r--source/blender/collada/ExtraTags.h11
-rw-r--r--source/blender/collada/ImportSettings.h1
-rw-r--r--source/blender/collada/MeshImporter.cpp67
-rw-r--r--source/blender/collada/MeshImporter.h2
-rw-r--r--source/blender/collada/SkinInfo.cpp1
-rw-r--r--source/blender/collada/collada.cpp8
-rw-r--r--source/blender/collada/collada.h2
-rw-r--r--source/blender/collada/collada_utils.cpp211
-rw-r--r--source/blender/collada/collada_utils.h51
-rw-r--r--source/blender/compositor/operations/COM_ImageOperation.cpp4
-rw-r--r--source/blender/depsgraph/CMakeLists.txt53
-rw-r--r--source/blender/depsgraph/DEG_depsgraph.h8
-rw-r--r--source/blender/depsgraph/DEG_depsgraph_build.h3
-rw-r--r--source/blender/depsgraph/DEG_depsgraph_debug.h3
-rw-r--r--source/blender/depsgraph/DEG_depsgraph_query.h143
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder.cc129
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder.h46
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_cycle.cc (renamed from source/blender/depsgraph/util/depsgraph_util_cycle.cc)42
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_cycle.h (renamed from source/blender/depsgraph/util/depsgraph_util_cycle.h)11
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_nodes.cc (renamed from source/blender/depsgraph/intern/depsgraph_build_nodes.cc)56
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_nodes.h153
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_pchanmap.cc (renamed from source/blender/depsgraph/util/depsgraph_util_pchanmap.cc)28
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_pchanmap.h (renamed from source/blender/depsgraph/util/depsgraph_util_pchanmap.h)15
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_relations.cc (renamed from source/blender/depsgraph/intern/depsgraph_build_relations.cc)80
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_relations.h (renamed from source/blender/depsgraph/intern/depsgraph_build.h)170
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_transitive.cc (renamed from source/blender/depsgraph/util/depsgraph_util_transitive.cc)58
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_transitive.h (renamed from source/blender/depsgraph/util/depsgraph_util_transitive.h)10
-rw-r--r--source/blender/depsgraph/intern/debug/deg_debug_graphviz.cc588
-rw-r--r--source/blender/depsgraph/intern/depsgraph.cc115
-rw-r--r--source/blender/depsgraph/intern/depsgraph.h47
-rw-r--r--source/blender/depsgraph/intern/depsgraph_build.cc316
-rw-r--r--source/blender/depsgraph/intern/depsgraph_debug.cc1054
-rw-r--r--source/blender/depsgraph/intern/depsgraph_eval.cc380
-rw-r--r--source/blender/depsgraph/intern/depsgraph_intern.h95
-rw-r--r--source/blender/depsgraph/intern/depsgraph_query.cc156
-rw-r--r--source/blender/depsgraph/intern/depsgraph_queue.cc177
-rw-r--r--source/blender/depsgraph/intern/depsgraph_queue.h91
-rw-r--r--source/blender/depsgraph/intern/depsgraph_tag.cc194
-rw-r--r--source/blender/depsgraph/intern/depsgraph_type_defines.cc123
-rw-r--r--source/blender/depsgraph/intern/depsgraph_types.h252
-rw-r--r--source/blender/depsgraph/intern/depsnode_opcodes.h145
-rw-r--r--source/blender/depsgraph/intern/eval/deg_eval.cc409
-rw-r--r--source/blender/depsgraph/intern/eval/deg_eval.h52
-rw-r--r--source/blender/depsgraph/intern/eval/deg_eval_debug.cc249
-rw-r--r--source/blender/depsgraph/intern/eval/deg_eval_debug.h (renamed from source/blender/depsgraph/intern/depsgraph_debug.h)28
-rw-r--r--source/blender/depsgraph/intern/eval/deg_eval_flush.cc227
-rw-r--r--source/blender/depsgraph/intern/eval/deg_eval_flush.h49
-rw-r--r--source/blender/depsgraph/intern/nodes/deg_node.cc (renamed from source/blender/depsgraph/intern/depsnode.cc)158
-rw-r--r--source/blender/depsgraph/intern/nodes/deg_node.h (renamed from source/blender/depsgraph/intern/depsnode.h)41
-rw-r--r--source/blender/depsgraph/intern/nodes/deg_node_component.cc (renamed from source/blender/depsgraph/intern/depsnode_component.cc)216
-rw-r--r--source/blender/depsgraph/intern/nodes/deg_node_component.h (renamed from source/blender/depsgraph/intern/depsnode_component.h)85
-rw-r--r--source/blender/depsgraph/intern/nodes/deg_node_operation.cc (renamed from source/blender/depsgraph/intern/depsnode_operation.cc)31
-rw-r--r--source/blender/depsgraph/intern/nodes/deg_node_operation.h (renamed from source/blender/depsgraph/intern/depsnode_operation.h)42
-rw-r--r--source/blender/depsgraph/util/deg_util_foreach.h68
-rw-r--r--source/blender/depsgraph/util/deg_util_function.h (renamed from source/blender/depsgraph/util/depsgraph_util_function.h)8
-rw-r--r--source/blender/depsgraph/util/deg_util_hash.h (renamed from source/blender/depsgraph/util/depsgraph_util_set.h)43
-rw-r--r--source/blender/depsgraph/util/depsgraph_util_hash.h72
-rw-r--r--source/blender/depsgraph/util/depsgraph_util_map.h67
-rw-r--r--source/blender/editors/animation/anim_deps.c8
-rw-r--r--source/blender/editors/animation/drivers.c7
-rw-r--r--source/blender/editors/animation/keyframing.c24
-rw-r--r--source/blender/editors/armature/armature_utils.c9
-rw-r--r--source/blender/editors/armature/editarmature_sketch.c9
-rw-r--r--source/blender/editors/curve/editcurve.c5
-rw-r--r--source/blender/editors/include/ED_physics.h8
-rw-r--r--source/blender/editors/include/ED_screen_types.h1
-rw-r--r--source/blender/editors/include/ED_transform.h13
-rw-r--r--source/blender/editors/include/ED_transform_snap_object_context.h19
-rw-r--r--source/blender/editors/interface/interface_handlers.c16
-rw-r--r--source/blender/editors/interface/interface_icons.c5
-rw-r--r--source/blender/editors/interface/interface_ops.c2
-rw-r--r--source/blender/editors/interface/interface_regions.c8
-rw-r--r--source/blender/editors/io/io_collada.c20
-rw-r--r--source/blender/editors/mesh/CMakeLists.txt1
-rw-r--r--source/blender/editors/mesh/editmesh_bevel.c51
-rw-r--r--source/blender/editors/mesh/editmesh_tools.c5
-rw-r--r--source/blender/editors/mesh/editmesh_undo.c726
-rw-r--r--source/blender/editors/mesh/editmesh_utils.c136
-rw-r--r--source/blender/editors/object/object_add.c2
-rw-r--r--source/blender/editors/physics/rigidbody_constraint.c15
-rw-r--r--source/blender/editors/physics/rigidbody_object.c21
-rw-r--r--source/blender/editors/screen/glutil.c6
-rw-r--r--source/blender/editors/screen/screen_edit.c5
-rw-r--r--source/blender/editors/screen/screen_ops.c16
-rw-r--r--source/blender/editors/sculpt_paint/paint_cursor.c2
-rw-r--r--source/blender/editors/space_action/action_edit.c9
-rw-r--r--source/blender/editors/space_graph/graph_edit.c9
-rw-r--r--source/blender/editors/space_sequencer/CMakeLists.txt1
-rw-r--r--source/blender/editors/space_sequencer/sequencer_scopes.c117
-rw-r--r--source/blender/editors/space_sequencer/sequencer_select.c3
-rw-r--r--source/blender/editors/space_view3d/view3d_draw.c8
-rw-r--r--source/blender/editors/space_view3d/view3d_ruler.c10
-rw-r--r--source/blender/editors/space_view3d/view3d_walk.c7
-rw-r--r--source/blender/editors/transform/transform.c2
-rw-r--r--source/blender/editors/transform/transform.h13
-rw-r--r--source/blender/editors/transform/transform_generics.c61
-rw-r--r--source/blender/editors/transform/transform_snap.c51
-rw-r--r--source/blender/editors/transform/transform_snap_object.c149
-rw-r--r--source/blender/gpu/GPU_basic_shader.h28
-rw-r--r--source/blender/gpu/GPU_buffers.h15
-rw-r--r--source/blender/gpu/GPU_material.h1
-rw-r--r--source/blender/gpu/GPU_shader.h1
-rw-r--r--source/blender/gpu/intern/gpu_basic_shader.c67
-rw-r--r--source/blender/gpu/intern/gpu_buffers.c132
-rw-r--r--source/blender/gpu/intern/gpu_codegen.c4
-rw-r--r--source/blender/gpu/intern/gpu_framebuffer.c8
-rw-r--r--source/blender/gpu/intern/gpu_init_exit.c1
-rw-r--r--source/blender/gpu/intern/gpu_material.c8
-rw-r--r--source/blender/gpu/shaders/gpu_shader_basic_frag.glsl187
-rw-r--r--source/blender/gpu/shaders/gpu_shader_basic_geom.glsl130
-rw-r--r--source/blender/gpu/shaders/gpu_shader_basic_vert.glsl2
-rw-r--r--source/blender/gpu/shaders/gpu_shader_fx_dof_frag.glsl10
-rw-r--r--source/blender/gpu/shaders/gpu_shader_fx_dof_hq_frag.glsl3
-rw-r--r--source/blender/gpu/shaders/gpu_shader_fx_dof_vert.glsl8
-rw-r--r--source/blender/gpu/shaders/gpu_shader_fx_ssao_frag.glsl5
-rw-r--r--source/blender/gpu/shaders/gpu_shader_geometry.glsl4
-rw-r--r--source/blender/gpu/shaders/gpu_shader_material.glsl1447
-rw-r--r--source/blender/gpu/shaders/gpu_shader_sep_gaussian_blur_frag.glsl14
-rw-r--r--source/blender/gpu/shaders/gpu_shader_sep_gaussian_blur_vert.glsl4
-rw-r--r--source/blender/gpu/shaders/gpu_shader_vertex.glsl64
-rw-r--r--source/blender/gpu/shaders/gpu_shader_vsm_store_frag.glsl2
-rw-r--r--source/blender/imbuf/intern/IMB_anim.h8
-rw-r--r--source/blender/makesdna/DNA_ID.h4
-rw-r--r--source/blender/makesdna/DNA_anim_types.h2
-rw-r--r--source/blender/makesdna/DNA_customdata_types.h6
-rw-r--r--source/blender/makesdna/DNA_modifier_types.h2
-rw-r--r--source/blender/makesdna/DNA_scene_types.h1
-rw-r--r--source/blender/makesdna/DNA_view3d_types.h2
-rw-r--r--source/blender/makesrna/RNA_access.h1
-rw-r--r--source/blender/makesrna/intern/rna_access.c66
-rw-r--r--source/blender/makesrna/intern/rna_camera.c4
-rw-r--r--source/blender/makesrna/intern/rna_curve.c18
-rw-r--r--source/blender/makesrna/intern/rna_modifier.c5
-rw-r--r--source/blender/makesrna/intern/rna_nodetree.c1
-rw-r--r--source/blender/makesrna/intern/rna_object.c2
-rw-r--r--source/blender/makesrna/intern/rna_object_api.c2
-rw-r--r--source/blender/makesrna/intern/rna_object_force.c2
-rw-r--r--source/blender/makesrna/intern/rna_scene.c5
-rw-r--r--source/blender/makesrna/intern/rna_scene_api.c6
-rw-r--r--source/blender/makesrna/intern/rna_sequencer.c1
-rw-r--r--source/blender/makesrna/intern/rna_userdef.c14
-rw-r--r--source/blender/modifiers/intern/MOD_normal_edit.c27
-rw-r--r--source/blender/modifiers/intern/MOD_screw.c2
-rw-r--r--source/blender/modifiers/intern/MOD_shapekey.c1
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_attribute.c4
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_camera.c10
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_geom.c11
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_lamp.c7
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_material.c18
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_normal_map.c79
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_tex_image.c36
-rw-r--r--source/blender/python/intern/bpy_rna.c18
-rw-r--r--source/blender/python/mathutils/mathutils_Matrix.h2
-rw-r--r--source/blender/render/extern/include/RE_shader_ext.h1
-rw-r--r--source/blender/render/intern/include/rayintersection.h5
-rw-r--r--source/blender/render/intern/raytrace/rayobject.cpp149
-rw-r--r--source/blender/render/intern/source/render_result.c76
-rw-r--r--source/blender/render/intern/source/shadeinput.c1
-rw-r--r--source/blender/windowmanager/WM_api.h1
-rw-r--r--source/blender/windowmanager/intern/wm_draw.c7
-rw-r--r--source/blender/windowmanager/intern/wm_files.c3
-rw-r--r--source/blender/windowmanager/intern/wm_gesture.c5
-rw-r--r--source/blender/windowmanager/intern/wm_operators.c11
-rw-r--r--source/blender/windowmanager/wm_event_types.h30
-rw-r--r--source/blenderplayer/CMakeLists.txt1
-rw-r--r--source/blenderplayer/bad_level_call_stubs/stubs.c2
-rw-r--r--source/creator/CMakeLists.txt8
-rw-r--r--source/creator/creator_args.c31
-rw-r--r--tests/gtests/blenlib/BLI_array_store_test.cc815
-rw-r--r--tests/gtests/blenlib/BLI_ghash_performance_test.cc111
-rw-r--r--tests/gtests/blenlib/CMakeLists.txt1
379 files changed, 14079 insertions, 8386 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index db733d4a8f6..dcdbfd88eac 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -172,7 +172,6 @@ if(UNIX AND NOT APPLE)
set(_init_CODEC_FFMPEG OFF)
set(_init_CYCLES_OSL OFF)
set(_init_IMAGE_OPENEXR OFF)
- set(_init_INPUT_NDOF OFF)
set(_init_JACK OFF)
set(_init_OPENCOLLADA OFF)
set(_init_OPENCOLORIO OFF)
@@ -1047,14 +1046,12 @@ if(UNIX AND NOT APPLE)
if(WITH_INPUT_NDOF)
find_package_wrapper(Spacenav)
- if(NOT SPACENAV_FOUND)
- set(WITH_INPUT_NDOF OFF)
- endif()
-
- # use generic names within blenders buildsystem.
if(SPACENAV_FOUND)
+ # use generic names within blenders buildsystem.
set(NDOF_INCLUDE_DIRS ${SPACENAV_INCLUDE_DIRS})
set(NDOF_LIBRARIES ${SPACENAV_LIBRARIES})
+ else()
+ set(WITH_INPUT_NDOF OFF)
endif()
endif()
@@ -1975,7 +1972,7 @@ elseif(WIN32)
set(OPENAL ${LIBDIR}/openal)
set(OPENALDIR ${LIBDIR}/openal)
set(OPENAL_INCLUDE_DIR ${OPENAL}/include)
- if(MSVC12)
+ if(MSVC)
set(OPENAL_LIBRARY openal32)
else()
set(OPENAL_LIBRARY wrap_oal)
diff --git a/build_files/buildbot/slave_compile.py b/build_files/buildbot/slave_compile.py
index 5e25d9f3f04..0e7218405d8 100644
--- a/build_files/buildbot/slave_compile.py
+++ b/build_files/buildbot/slave_compile.py
@@ -75,11 +75,18 @@ if 'cmake' in builder:
cmake_extra_options.append('-DCUDA_NVCC_EXECUTABLE=/usr/local/cuda-hack/bin/nvcc')
elif builder.startswith('win'):
+ if builder.endswith('_vc2015'):
if builder.startswith('win64'):
- cmake_options.append(['-G', '"Visual Studio 12 2013 Win64"'])
+ cmake_options.extend(['-G', 'Visual Studio 14 2015 Win64', '-DWITH_CYCLES_CUDA_BINARIES=0'])
elif builder.startswith('win32'):
bits = 32
- cmake_options.append(['-G', '"Visual Studio 12 2013"'])
+ cmake_options.extend(['-G', 'Visual Studio 14 2015', '-DWITH_CYCLES_CUDA_BINARIES=0'])
+ else:
+ if builder.startswith('win64'):
+ cmake_options.extend(['-G', 'Visual Studio 12 2013 Win64'])
+ elif builder.startswith('win32'):
+ bits = 32
+ cmake_options.extend(['-G', 'Visual Studio 12 2013'])
elif builder.startswith('linux'):
tokens = builder.split("_")
diff --git a/build_files/cmake/macros.cmake b/build_files/cmake/macros.cmake
index 53247bfb33e..15bee2a59ac 100644
--- a/build_files/cmake/macros.cmake
+++ b/build_files/cmake/macros.cmake
@@ -435,9 +435,6 @@ function(setup_liblinks
if(WITH_MEM_JEMALLOC)
target_link_libraries(${target} ${JEMALLOC_LIBRARIES})
endif()
- if(WITH_INPUT_NDOF)
- target_link_libraries(${target} ${NDOF_LIBRARIES})
- endif()
if(WITH_MOD_CLOTH_ELTOPO)
target_link_libraries(${target} ${LAPACK_LIBRARIES})
endif()
@@ -451,6 +448,9 @@ function(setup_liblinks
if(WITH_OPENMP_STATIC)
target_link_libraries(${target} ${OpenMP_LIBRARIES})
endif()
+ if(WITH_INPUT_NDOF)
+ target_link_libraries(${target} ${NDOF_LIBRARIES})
+ endif()
endif()
# We put CLEW and CUEW here because OPENSUBDIV_LIBRARIES dpeends on them..
@@ -552,11 +552,11 @@ function(SETUP_BLENDER_SORTED_LIBS)
bf_modifiers
bf_bmesh
bf_gpu
+ bf_blenloader
bf_blenkernel
bf_physics
bf_nodes
bf_rna
- bf_blenloader
bf_imbuf
bf_blenlib
bf_depsgraph
@@ -661,10 +661,6 @@ function(SETUP_BLENDER_SORTED_LIBS)
list(APPEND BLENDER_SORTED_LIBS bf_quicktime)
endif()
- if(WITH_INPUT_NDOF)
- list(APPEND BLENDER_SORTED_LIBS bf_intern_ghostndof3dconnexion)
- endif()
-
if(WITH_MOD_BOOLEAN)
list(APPEND BLENDER_SORTED_LIBS extern_carve)
endif()
@@ -891,8 +887,16 @@ macro(TEST_SHARED_PTR_SUPPORT)
# otherwise it's assumed to be defined in std namespace.
include(CheckIncludeFileCXX)
+ include(CheckCXXSourceCompiles)
set(SHARED_PTR_FOUND FALSE)
- CHECK_INCLUDE_FILE_CXX(memory HAVE_STD_MEMORY_HEADER)
+ # Workaround for newer GCC (6.x+) where C++11 was enabled by default, which lead us
+ # to a situation when there is <unordered_map> include but which can't be used uless
+ # C++11 is enabled.
+ if(CMAKE_COMPILER_IS_GNUCC AND (NOT "${CMAKE_C_COMPILER_VERSION}" VERSION_LESS "6.0") AND (NOT WITH_CXX11))
+ set(HAVE_STD_MEMORY_HEADER False)
+ else()
+ CHECK_INCLUDE_FILE_CXX(memory HAVE_STD_MEMORY_HEADER)
+ endif()
if(HAVE_STD_MEMORY_HEADER)
# Finding the memory header doesn't mean that shared_ptr is in std
# namespace.
@@ -900,7 +904,6 @@ macro(TEST_SHARED_PTR_SUPPORT)
# In particular, MSVC 2008 has shared_ptr declared in std::tr1. In
# order to support this, we do an extra check to see which namespace
# should be used.
- include(CheckCXXSourceCompiles)
CHECK_CXX_SOURCE_COMPILES("#include <memory>
int main() {
std::shared_ptr<int> int_ptr;
diff --git a/doc/python_api/sphinx_doc_gen.sh b/doc/python_api/sphinx_doc_gen.sh
index 7095808f251..1ab6bd5afc7 100755
--- a/doc/python_api/sphinx_doc_gen.sh
+++ b/doc/python_api/sphinx_doc_gen.sh
@@ -61,7 +61,7 @@ if $DO_EXE_BLENDER ; then
--python-exit-code 1 \
--python $SPHINXBASE/sphinx_doc_gen.py
- if (($? == 1)) ; then
+ if (($? != 0)) ; then
echo "Generating documentation failed, aborting"
exit 1
fi
diff --git a/extern/Eigen3/README.blender b/extern/Eigen3/README.blender
new file mode 100644
index 00000000000..8ccc46ac344
--- /dev/null
+++ b/extern/Eigen3/README.blender
@@ -0,0 +1,6 @@
+Project: Eigen, template library for linear algebra: matrices, vectors, numerical solvers, and related algorithms
+URL: http://eigen.tuxfamily.org/index.php?title=Main_Page
+License: GPLv3+
+Upstream version: 3.2.7
+Local modifications:
+- OpenMP fix for MSVC2015, see http://eigen.tuxfamily.org/bz/show_bug.cgi?id=1131
diff --git a/extern/binreloc/README.blender b/extern/binreloc/README.blender
new file mode 100644
index 00000000000..a90b44216a4
--- /dev/null
+++ b/extern/binreloc/README.blender
@@ -0,0 +1,6 @@
+Project: AutoPackage
+URL: http://autopackage.org/docs/binreloc (original, defunct)
+ http://alien.cern.ch/cache/autopackage-1.0/site/docs/binreloc/ (cache)
+License: Public Domain
+Upstream version: Unknown (Last Release)
+Local modifications: None
diff --git a/extern/carve/README.blender b/extern/carve/README.blender
new file mode 100644
index 00000000000..80be40ae558
--- /dev/null
+++ b/extern/carve/README.blender
@@ -0,0 +1,4 @@
+Project: Carve, CSG library
+URL: https://code.google.com/archive/p/carve/
+Upstream version 9a85d733a43d
+Local modifications: See patches/ folder
diff --git a/extern/ceres/README.blender b/extern/ceres/README.blender
new file mode 100644
index 00000000000..44c389a42d9
--- /dev/null
+++ b/extern/ceres/README.blender
@@ -0,0 +1,4 @@
+Project: Ceres Solver
+URL: http://ceres-solver.org/
+Upstream version 1.11 (aef9c9563b08d5f39eee1576af133a84749d1b48)
+Local modifications: None
diff --git a/extern/clew/README.blender b/extern/clew/README.blender
new file mode 100644
index 00000000000..e500a1bef7d
--- /dev/null
+++ b/extern/clew/README.blender
@@ -0,0 +1,5 @@
+Project: OpenCL Wrangler
+URL: https://github.com/OpenCLWrangler/clew
+License: Apache 2.0
+Upstream version: 277db43
+Local modifications: None
diff --git a/extern/cuew/README.blender b/extern/cuew/README.blender
new file mode 100644
index 00000000000..7e0523eda28
--- /dev/null
+++ b/extern/cuew/README.blender
@@ -0,0 +1,5 @@
+Project: Cuda Wrangler
+URL: https://github.com/CudaWrangler/cuew
+License: Apache 2.0
+Upstream version: e2e0315
+Local modifications: None
diff --git a/extern/gflags/README.libmv b/extern/gflags/README.blender
index bf58ccb5fd2..0c8ea9a2be3 100644
--- a/extern/gflags/README.libmv
+++ b/extern/gflags/README.blender
@@ -1,5 +1,5 @@
Project: Google Flags
-URL: http://code.google.com/p/google-gflags/
+URL: https://github.com/gflags/gflags
License: New BSD
Upstream version: 2.2.0 (9db82895)
Local modifications:
@@ -17,3 +17,7 @@ Local modifications:
- Applied some modifications from fork https://github.com/Nazg-Gul/gflags.git
(see https://github.com/gflags/gflags/pull/129)
+
+- Avoid attemot of acquiring mutex lock in FlagRegistry::GlobalRegistry when
+ doing static flags initialization. See d81dd2d in Blender repository.
+
diff --git a/extern/glog/README.libmv b/extern/glog/README.blender
index 6e82cbbacdf..288e78b3259 100644
--- a/extern/glog/README.libmv
+++ b/extern/glog/README.blender
@@ -1,5 +1,5 @@
Project: Google Logging
-URL: http://code.google.com/p/google-glog/
+URL: https://github.com/google/glog
License: New BSD
Upstream version: 0.3.4, 4d391fe
Local modifications:
diff --git a/extern/gtest/README b/extern/gtest/README.blender
index 27e4eff92c9..81c04ad3f3c 100644
--- a/extern/gtest/README
+++ b/extern/gtest/README.blender
@@ -1,7 +1,5 @@
Project: Google C++ Testing Framework
-URL: http://code.google.com/p/googletest
+URL: https://github.com/google/googletest
License: New BSD
Upstream version: 1.7.0
-Local modifications:
-
-None.
+Local modifications:None
diff --git a/extern/libopenjpeg/README.blender b/extern/libopenjpeg/README.blender
new file mode 100644
index 00000000000..5aa213c7707
--- /dev/null
+++ b/extern/libopenjpeg/README.blender
@@ -0,0 +1,5 @@
+Project: OpenJPEG
+URL: http://www.openjpeg.org
+License: BSD 2-Clause
+Upstream version: 1.5.2
+Local modifications:
diff --git a/extern/rangetree/README.blender b/extern/rangetree/README.blender
new file mode 100644
index 00000000000..cb5967137ac
--- /dev/null
+++ b/extern/rangetree/README.blender
@@ -0,0 +1,5 @@
+Project: RangeTree
+URL: https://github.com/nicholasbishop/RangeTree
+License: GPLv2+
+Upstream version: c4ecf6bb7dfd
+Local modifications: None
diff --git a/extern/sdlew/README.blender b/extern/sdlew/README.blender
new file mode 100644
index 00000000000..773f03737c7
--- /dev/null
+++ b/extern/sdlew/README.blender
@@ -0,0 +1,5 @@
+Project: SDL Extension Wrangler
+URL: https://github.com/SDLWrangler/sdlew
+License: Apache 2.0
+Upstream version: 15edf8e
+Local modifications: None
diff --git a/extern/wcwidth/README.blender b/extern/wcwidth/README.blender
new file mode 100644
index 00000000000..27c8574d1d7
--- /dev/null
+++ b/extern/wcwidth/README.blender
@@ -0,0 +1,5 @@
+Project: WC Width
+URL: http://www.cl.cam.ac.uk/~mgk25/ucs/wcwidth.c
+License: ICS
+Upstream version: 2007-05-26
+Local modifications: None
diff --git a/extern/xdnd/README.blender b/extern/xdnd/README.blender
new file mode 100644
index 00000000000..05afe566bba
--- /dev/null
+++ b/extern/xdnd/README.blender
@@ -0,0 +1,8 @@
+Project: X Drag and Drop
+URL: http://www.newplanetsoftware.com/xdnd/ (defunct)
+ https://freedesktop.org/wiki/Specifications/XDND/ (cache)
+License: GPLv2+
+Upstream version: 2000-08-08
+Local modifications:
+* Fix T33192
+ Opening Blender breaks drag-and-drop support on the KDE desktop.
diff --git a/intern/cycles/app/cycles_xml.cpp b/intern/cycles/app/cycles_xml.cpp
index dc0c4f68898..9f967a4bde9 100644
--- a/intern/cycles/app/cycles_xml.cpp
+++ b/intern/cycles/app/cycles_xml.cpp
@@ -31,6 +31,7 @@
#include "mesh.h"
#include "nodes.h"
#include "object.h"
+#include "osl.h"
#include "shader.h"
#include "scene.h"
@@ -214,25 +215,7 @@ static bool xml_equal_string(pugi::xml_node node, const char *name, const char *
return false;
}
-static bool xml_read_enum(ustring *str, ShaderEnum& enm, pugi::xml_node node, const char *name)
-{
- pugi::xml_attribute attr = node.attribute(name);
-
- if(attr) {
- ustring ustr(attr.value());
-
- if(enm.exists(ustr)) {
- *str = ustr;
- return true;
- }
- else
- fprintf(stderr, "Unknown value \"%s\" for attribute \"%s\".\n", ustr.c_str(), name);
- }
-
- return false;
-}
-
-static bool xml_read_enum_value(int *value, ShaderEnum& enm, pugi::xml_node node, const char *name)
+static bool xml_read_enum_value(int *value, NodeEnum& enm, pugi::xml_node node, const char *name)
{
pugi::xml_attribute attr = node.attribute(name);
@@ -250,77 +233,16 @@ static bool xml_read_enum_value(int *value, ShaderEnum& enm, pugi::xml_node node
return false;
}
-static ShaderSocketType xml_read_socket_type(pugi::xml_node node, const char *name)
-{
- pugi::xml_attribute attr = node.attribute(name);
-
- if(attr) {
- string value = attr.value();
- if(string_iequals(value, "float"))
- return SHADER_SOCKET_FLOAT;
- else if(string_iequals(value, "int"))
- return SHADER_SOCKET_INT;
- else if(string_iequals(value, "color"))
- return SHADER_SOCKET_COLOR;
- else if(string_iequals(value, "vector"))
- return SHADER_SOCKET_VECTOR;
- else if(string_iequals(value, "point"))
- return SHADER_SOCKET_POINT;
- else if(string_iequals(value, "normal"))
- return SHADER_SOCKET_NORMAL;
- else if(string_iequals(value, "closure color"))
- return SHADER_SOCKET_CLOSURE;
- else if(string_iequals(value, "string"))
- return SHADER_SOCKET_STRING;
- else
- fprintf(stderr, "Unknown shader socket type \"%s\" for attribute \"%s\".\n", value.c_str(), name);
- }
-
- return SHADER_SOCKET_UNDEFINED;
-}
-
/* Camera */
-static void xml_read_camera(const XMLReadState& state, pugi::xml_node node)
+static void xml_read_camera(XMLReadState& state, pugi::xml_node node)
{
Camera *cam = state.scene->camera;
xml_read_int(&cam->width, node, "width");
xml_read_int(&cam->height, node, "height");
- if(xml_read_float(&cam->fov, node, "fov"))
- cam->fov = DEG2RADF(cam->fov);
-
- xml_read_float(&cam->nearclip, node, "nearclip");
- xml_read_float(&cam->farclip, node, "farclip");
- xml_read_float(&cam->aperturesize, node, "aperturesize"); // 0.5*focallength/fstop
- xml_read_float(&cam->focaldistance, node, "focaldistance");
- xml_read_float(&cam->shuttertime, node, "shuttertime");
- xml_read_float(&cam->aperture_ratio, node, "aperture_ratio");
-
- if(xml_equal_string(node, "type", "orthographic"))
- cam->type = CAMERA_ORTHOGRAPHIC;
- else if(xml_equal_string(node, "type", "perspective"))
- cam->type = CAMERA_PERSPECTIVE;
- else if(xml_equal_string(node, "type", "panorama"))
- cam->type = CAMERA_PANORAMA;
-
- if(xml_equal_string(node, "panorama_type", "equirectangular"))
- cam->panorama_type = PANORAMA_EQUIRECTANGULAR;
- else if(xml_equal_string(node, "panorama_type", "fisheye_equidistant"))
- cam->panorama_type = PANORAMA_FISHEYE_EQUIDISTANT;
- else if(xml_equal_string(node, "panorama_type", "fisheye_equisolid"))
- cam->panorama_type = PANORAMA_FISHEYE_EQUISOLID;
-
- xml_read_float(&cam->fisheye_fov, node, "fisheye_fov");
- xml_read_float(&cam->fisheye_lens, node, "fisheye_lens");
-
- xml_read_bool(&cam->use_spherical_stereo, node, "use_spherical_stereo");
- xml_read_float(&cam->interocular_distance, node, "interocular_distance");
- xml_read_float(&cam->convergence_distance, node, "convergence_distance");
-
- xml_read_float(&cam->sensorwidth, node, "sensorwidth");
- xml_read_float(&cam->sensorheight, node, "sensorheight");
+ xml_read_node(state, cam, node);
cam->matrix = state.tfm;
@@ -345,6 +267,7 @@ static void xml_read_shader_graph(XMLReadState& state, Shader *shader, pugi::xml
{
xml_read_node(state, shader, graph_node);
+ ShaderManager *manager = state.scene->shader_manager;
ShaderGraph *graph = new ShaderGraph();
map<string, ShaderNode*> nodemap;
@@ -364,8 +287,8 @@ static void xml_read_shader_graph(XMLReadState& state, Shader *shader, pugi::xml
xml_read_string(&img->filename, node, "src");
img->filename = path_join(state.base, img->filename);
- xml_read_enum(&img->color_space, ImageTextureNode::color_space_enum, node, "color_space");
- xml_read_enum(&img->projection, ImageTextureNode::projection_enum, node, "projection");
+ xml_read_enum_value((int*)&img->color_space, ImageTextureNode::color_space_enum, node, "color_space");
+ xml_read_enum_value((int*)&img->projection, ImageTextureNode::projection_enum, node, "projection");
xml_read_float(&img->projection_blend, node, "projection_blend");
/* ToDo: Interpolation */
@@ -378,56 +301,40 @@ static void xml_read_shader_graph(XMLReadState& state, Shader *shader, pugi::xml
xml_read_string(&env->filename, node, "src");
env->filename = path_join(state.base, env->filename);
- xml_read_enum(&env->color_space, EnvironmentTextureNode::color_space_enum, node, "color_space");
- xml_read_enum(&env->projection, EnvironmentTextureNode::projection_enum, node, "projection");
+ xml_read_enum_value((int*)&env->color_space, EnvironmentTextureNode::color_space_enum, node, "color_space");
+ xml_read_enum_value((int*)&env->projection, EnvironmentTextureNode::projection_enum, node, "projection");
snode = env;
}
+#ifdef WITH_OSL
else if(string_iequals(node.name(), "osl_shader")) {
- OSLScriptNode *osl = new OSLScriptNode();
+ if(manager->use_osl()) {
+ std::string filepath;
- /* Source */
- xml_read_string(&osl->filepath, node, "src");
- if(path_is_relative(osl->filepath)) {
- osl->filepath = path_join(state.base, osl->filepath);
- }
+ if(xml_read_string(&filepath, node, "src")) {
+ if(path_is_relative(filepath)) {
+ filepath = path_join(state.base, filepath);
+ }
- /* Generate inputs/outputs from node sockets
- *
- * Note: ShaderInput/ShaderOutput store shallow string copies only!
- * So we register them as ustring to ensure the pointer stays valid. */
- /* read input values */
- for(pugi::xml_node param = node.first_child(); param; param = param.next_sibling()) {
- if(string_iequals(param.name(), "input")) {
- string name;
- if(!xml_read_string(&name, param, "name"))
- continue;
-
- ShaderSocketType type = xml_read_socket_type(param, "type");
- if(type == SHADER_SOCKET_UNDEFINED)
- continue;
-
- osl->add_input(ustring(name).c_str(), type);
+ snode = ((OSLShaderManager*)manager)->osl_node(filepath);
+
+ if(!snode) {
+ fprintf(stderr, "Failed to create OSL node from \"%s\".\n", filepath.c_str());
+ }
}
- else if(string_iequals(param.name(), "output")) {
- string name;
- if(!xml_read_string(&name, param, "name"))
- continue;
-
- ShaderSocketType type = xml_read_socket_type(param, "type");
- if(type == SHADER_SOCKET_UNDEFINED)
- continue;
-
- osl->add_output(ustring(name).c_str(), type);
+ else {
+ fprintf(stderr, "OSL node missing \"src\" attribute.\n");
}
}
-
- snode = osl;
+ else {
+ fprintf(stderr, "OSL node without using --shadingsys osl.\n");
+ }
}
+#endif
else if(string_iequals(node.name(), "sky_texture")) {
SkyTextureNode *sky = new SkyTextureNode();
- xml_read_enum(&sky->type, SkyTextureNode::type_enum, node, "type");
+ xml_read_enum_value((int*)&sky->type, SkyTextureNode::type_enum, node, "type");
xml_read_float3(&sky->sun_direction, node, "sun_direction");
xml_read_float(&sky->turbidity, node, "turbidity");
xml_read_float(&sky->ground_albedo, node, "ground_albedo");
@@ -452,17 +359,17 @@ static void xml_read_shader_graph(XMLReadState& state, Shader *shader, pugi::xml
}
else if(string_iequals(node.name(), "gradient_texture")) {
GradientTextureNode *blend = new GradientTextureNode();
- xml_read_enum(&blend->type, GradientTextureNode::type_enum, node, "type");
+ xml_read_enum_value((int*)&blend->type, GradientTextureNode::type_enum, node, "type");
snode = blend;
}
else if(string_iequals(node.name(), "voronoi_texture")) {
VoronoiTextureNode *voronoi = new VoronoiTextureNode();
- xml_read_enum(&voronoi->coloring, VoronoiTextureNode::coloring_enum, node, "coloring");
+ xml_read_enum_value((int*)&voronoi->coloring, VoronoiTextureNode::coloring_enum, node, "coloring");
snode = voronoi;
}
else if(string_iequals(node.name(), "musgrave_texture")) {
MusgraveTextureNode *musgrave = new MusgraveTextureNode();
- xml_read_enum(&musgrave->type, MusgraveTextureNode::type_enum, node, "type");
+ xml_read_enum_value((int*)&musgrave->type, MusgraveTextureNode::type_enum, node, "type");
snode = musgrave;
}
else if(string_iequals(node.name(), "magic_texture")) {
@@ -472,8 +379,8 @@ static void xml_read_shader_graph(XMLReadState& state, Shader *shader, pugi::xml
}
else if(string_iequals(node.name(), "wave_texture")) {
WaveTextureNode *wave = new WaveTextureNode();
- xml_read_enum(&wave->type, WaveTextureNode::type_enum, node, "type");
- xml_read_enum(&wave->profile, WaveTextureNode::profile_enum, node, "profile");
+ xml_read_enum_value((int*)&wave->type, WaveTextureNode::type_enum, node, "type");
+ xml_read_enum_value((int*)&wave->profile, WaveTextureNode::profile_enum, node, "profile");
snode = wave;
}
else if(string_iequals(node.name(), "normal")) {
@@ -508,7 +415,7 @@ static void xml_read_shader_graph(XMLReadState& state, Shader *shader, pugi::xml
}
else if(string_iequals(node.name(), "anisotropic_bsdf")) {
AnisotropicBsdfNode *aniso = new AnisotropicBsdfNode();
- xml_read_enum(&aniso->distribution, AnisotropicBsdfNode::distribution_enum, node, "distribution");
+ xml_read_enum_value((int*)&aniso->distribution, AnisotropicBsdfNode::distribution_enum, node, "distribution");
snode = aniso;
}
else if(string_iequals(node.name(), "diffuse_bsdf")) {
@@ -525,27 +432,27 @@ static void xml_read_shader_graph(XMLReadState& state, Shader *shader, pugi::xml
}
else if(string_iequals(node.name(), "toon_bsdf")) {
ToonBsdfNode *toon = new ToonBsdfNode();
- xml_read_enum(&toon->component, ToonBsdfNode::component_enum, node, "component");
+ xml_read_enum_value((int*)&toon->component, ToonBsdfNode::component_enum, node, "component");
snode = toon;
}
else if(string_iequals(node.name(), "glossy_bsdf")) {
GlossyBsdfNode *glossy = new GlossyBsdfNode();
- xml_read_enum(&glossy->distribution, GlossyBsdfNode::distribution_enum, node, "distribution");
+ xml_read_enum_value((int*)&glossy->distribution, GlossyBsdfNode::distribution_enum, node, "distribution");
snode = glossy;
}
else if(string_iequals(node.name(), "glass_bsdf")) {
GlassBsdfNode *diel = new GlassBsdfNode();
- xml_read_enum(&diel->distribution, GlassBsdfNode::distribution_enum, node, "distribution");
+ xml_read_enum_value((int*)&diel->distribution, GlassBsdfNode::distribution_enum, node, "distribution");
snode = diel;
}
else if(string_iequals(node.name(), "refraction_bsdf")) {
RefractionBsdfNode *diel = new RefractionBsdfNode();
- xml_read_enum(&diel->distribution, RefractionBsdfNode::distribution_enum, node, "distribution");
+ xml_read_enum_value((int*)&diel->distribution, RefractionBsdfNode::distribution_enum, node, "distribution");
snode = diel;
}
else if(string_iequals(node.name(), "hair_bsdf")) {
HairBsdfNode *hair = new HairBsdfNode();
- xml_read_enum(&hair->component, HairBsdfNode::component_enum, node, "component");
+ xml_read_enum_value((int*)&hair->component, HairBsdfNode::component_enum, node, "component");
snode = hair;
}
else if(string_iequals(node.name(), "emission")) {
@@ -623,7 +530,7 @@ static void xml_read_shader_graph(XMLReadState& state, Shader *shader, pugi::xml
else if(string_iequals(node.name(), "mix")) {
/* ToDo: Tag Mix case for optimization */
MixNode *mix = new MixNode();
- xml_read_enum(&mix->type, MixNode::type_enum, node, "type");
+ xml_read_enum_value((int*)&mix->type, MixNode::type_enum, node, "type");
xml_read_bool(&mix->use_clamp, node, "use_clamp");
snode = mix;
}
@@ -687,32 +594,32 @@ static void xml_read_shader_graph(XMLReadState& state, Shader *shader, pugi::xml
else if(string_iequals(node.name(), "normal_map")) {
NormalMapNode *nmap = new NormalMapNode;
xml_read_ustring(&nmap->attribute, node, "attribute");
- xml_read_enum(&nmap->space, NormalMapNode::space_enum, node, "space");
+ xml_read_enum_value((int*)&nmap->space, NormalMapNode::space_enum, node, "space");
snode = nmap;
}
else if(string_iequals(node.name(), "tangent")) {
TangentNode *tangent = new TangentNode;
xml_read_ustring(&tangent->attribute, node, "attribute");
- xml_read_enum(&tangent->direction_type, TangentNode::direction_type_enum, node, "direction_type");
- xml_read_enum(&tangent->axis, TangentNode::axis_enum, node, "axis");
+ xml_read_enum_value((int*)&tangent->direction_type, TangentNode::direction_type_enum, node, "direction_type");
+ xml_read_enum_value((int*)&tangent->axis, TangentNode::axis_enum, node, "axis");
snode = tangent;
}
else if(string_iequals(node.name(), "math")) {
MathNode *math = new MathNode();
- xml_read_enum(&math->type, MathNode::type_enum, node, "type");
+ xml_read_enum_value((int*)&math->type, MathNode::type_enum, node, "type");
xml_read_bool(&math->use_clamp, node, "use_clamp");
snode = math;
}
else if(string_iequals(node.name(), "vector_math")) {
VectorMathNode *vmath = new VectorMathNode();
- xml_read_enum(&vmath->type, VectorMathNode::type_enum, node, "type");
+ xml_read_enum_value((int*)&vmath->type, VectorMathNode::type_enum, node, "type");
snode = vmath;
}
else if(string_iequals(node.name(), "vector_transform")) {
VectorTransformNode *vtransform = new VectorTransformNode();
- xml_read_enum(&vtransform->type, VectorTransformNode::type_enum, node, "type");
- xml_read_enum(&vtransform->convert_from, VectorTransformNode::convert_space_enum, node, "convert_from");
- xml_read_enum(&vtransform->convert_to, VectorTransformNode::convert_space_enum, node, "convert_to");
+ xml_read_enum_value((int*)&vtransform->type, VectorTransformNode::type_enum, node, "type");
+ xml_read_enum_value((int*)&vtransform->convert_from, VectorTransformNode::convert_space_enum, node, "convert_from");
+ xml_read_enum_value((int*)&vtransform->convert_to, VectorTransformNode::convert_space_enum, node, "convert_to");
snode = vtransform;
}
else if(string_iequals(node.name(), "connect")) {
@@ -731,7 +638,7 @@ static void xml_read_shader_graph(XMLReadState& state, Shader *shader, pugi::xml
ShaderNode *fromnode = nodemap[from_tokens[0]];
foreach(ShaderOutput *out, fromnode->outputs)
- if(string_iequals(xml_socket_name(out->name), from_tokens[1]))
+ if(string_iequals(xml_socket_name(out->name().c_str()), from_tokens[1]))
output = out;
if(!output)
@@ -744,7 +651,7 @@ static void xml_read_shader_graph(XMLReadState& state, Shader *shader, pugi::xml
ShaderNode *tonode = nodemap[to_tokens[0]];
foreach(ShaderInput *in, tonode->inputs)
- if(string_iequals(xml_socket_name(in->name), to_tokens[1]))
+ if(string_iequals(xml_socket_name(in->name().c_str()), to_tokens[1]))
input = in;
if(!input)
@@ -776,20 +683,20 @@ static void xml_read_shader_graph(XMLReadState& state, Shader *shader, pugi::xml
/* read input values */
for(pugi::xml_attribute attr = node.first_attribute(); attr; attr = attr.next_attribute()) {
foreach(ShaderInput *in, snode->inputs) {
- if(string_iequals(in->name, attr.name())) {
- switch(in->type) {
- case SHADER_SOCKET_FLOAT:
- case SHADER_SOCKET_INT:
- xml_read_float(&in->value.x, node, attr.name());
+ if(string_iequals(in->name().c_str(), attr.name())) {
+ switch(in->type()) {
+ case SocketType::FLOAT:
+ case SocketType::INT:
+ xml_read_float(&in->value_float(), node, attr.name());
break;
- case SHADER_SOCKET_COLOR:
- case SHADER_SOCKET_VECTOR:
- case SHADER_SOCKET_POINT:
- case SHADER_SOCKET_NORMAL:
- xml_read_float3(&in->value, node, attr.name());
+ case SocketType::COLOR:
+ case SocketType::VECTOR:
+ case SocketType::POINT:
+ case SocketType::NORMAL:
+ xml_read_float3(&in->value(), node, attr.name());
break;
- case SHADER_SOCKET_STRING:
- xml_read_ustring( &in->value_string, node, attr.name() );
+ case SocketType::STRING:
+ xml_read_ustring( &in->value_string(), node, attr.name() );
break;
default:
break;
@@ -908,6 +815,11 @@ static void xml_read_mesh(const XMLReadState& state, pugi::xml_node node)
/* create vertices */
mesh->verts = P;
+ size_t num_triangles = 0;
+ for(size_t i = 0; i < nverts.size(); i++)
+ num_triangles += nverts[i]-2;
+ mesh->reserve_mesh(mesh->verts.size(), num_triangles);
+
/* create triangles */
int index_offset = 0;
@@ -936,9 +848,9 @@ static void xml_read_mesh(const XMLReadState& state, pugi::xml_node node)
index_offset = 0;
for(size_t i = 0; i < nverts.size(); i++) {
for(int j = 0; j < nverts[i]-2; j++) {
- int v0 = verts[index_offset];
- int v1 = verts[index_offset + j + 1];
- int v2 = verts[index_offset + j + 2];
+ int v0 = index_offset;
+ int v1 = index_offset + j + 1;
+ int v2 = index_offset + j + 2;
assert(v0*2+1 < (int)UV.size());
assert(v1*2+1 < (int)UV.size());
diff --git a/intern/cycles/blender/addon/properties.py b/intern/cycles/blender/addon/properties.py
index eed86a6e65a..140862721a8 100644
--- a/intern/cycles/blender/addon/properties.py
+++ b/intern/cycles/blender/addon/properties.py
@@ -359,7 +359,7 @@ class CyclesRenderSettings(bpy.types.PropertyGroup):
description="Distance between volume shader samples when rendering the volume "
"(lower values give more accurate and detailed results, but also increased render time)",
default=0.1,
- min=0.0000001, max=100000.0, soft_min=0.01, soft_max=1.0
+ min=0.0000001, max=100000.0, soft_min=0.01, soft_max=1.0, precision=4
)
cls.volume_max_steps = IntProperty(
diff --git a/intern/cycles/blender/addon/ui.py b/intern/cycles/blender/addon/ui.py
index 023841a7a17..0961c349fc3 100644
--- a/intern/cycles/blender/addon/ui.py
+++ b/intern/cycles/blender/addon/ui.py
@@ -76,9 +76,8 @@ def use_cuda(context):
def use_branched_path(context):
cscene = context.scene.cycles
- device_type = context.user_preferences.system.compute_device_type
- return (cscene.progressive == 'BRANCHED_PATH' and device_type != 'OPENCL')
+ return (cscene.progressive == 'BRANCHED_PATH' and not use_opencl(context))
def use_sample_all_lights(context):
@@ -704,7 +703,7 @@ class Cycles_PT_mesh_displacement(CyclesButtonsPanel, Panel):
col = split.column()
sub = col.column(align=True)
- sub.label(text="Displacment:")
+ sub.label(text="Displacement:")
sub.prop(cdata, "displacement_method", text="")
col = split.column()
diff --git a/intern/cycles/blender/blender_camera.cpp b/intern/cycles/blender/blender_camera.cpp
index 9dec489ce33..f02fc553908 100644
--- a/intern/cycles/blender/blender_camera.cpp
+++ b/intern/cycles/blender/blender_camera.cpp
@@ -37,7 +37,7 @@ struct BlenderCamera {
float lens;
float shuttertime;
Camera::MotionPosition motion_position;
- float shutter_curve[RAMP_TABLE_SIZE];
+ array<float> shutter_curve;
Camera::RollingShutterType rolling_shutter_type;
float rolling_shutter_duration;
@@ -108,10 +108,6 @@ static void blender_camera_init(BlenderCamera *bcam,
/* render resolution */
bcam->full_width = render_resolution_x(b_render);
bcam->full_height = render_resolution_y(b_render);
-
- /* pixel aspect */
- bcam->pixelaspect.x = b_render.pixel_aspect_x();
- bcam->pixelaspect.y = b_render.pixel_aspect_y();
}
static float blender_camera_focal_distance(BL::RenderEngine& b_engine,
@@ -464,7 +460,7 @@ static void blender_camera_sync(Camera *cam, BlenderCamera *bcam, int width, int
cam->rolling_shutter_type = bcam->rolling_shutter_type;
cam->rolling_shutter_duration = bcam->rolling_shutter_duration;
- memcpy(cam->shutter_curve, bcam->shutter_curve, sizeof(cam->shutter_curve));
+ cam->shutter_curve = bcam->shutter_curve;
/* border */
cam->border = bcam->border;
@@ -563,6 +559,10 @@ void BlenderSync::sync_camera_motion(BL::RenderSettings& b_render,
float aspectratio, sensor_size;
blender_camera_init(&bcam, b_render);
+ /* TODO(sergey): Consider making it a part of blender_camera_init(). */
+ bcam.pixelaspect.x = b_render.pixel_aspect_x();
+ bcam.pixelaspect.y = b_render.pixel_aspect_y();
+
blender_camera_from_object(&bcam, b_engine, b_ob);
blender_camera_viewplane(&bcam,
width, height,
diff --git a/intern/cycles/blender/blender_curves.cpp b/intern/cycles/blender/blender_curves.cpp
index 64f1b66405e..378ae67f0c7 100644
--- a/intern/cycles/blender/blender_curves.cpp
+++ b/intern/cycles/blender/blender_curves.cpp
@@ -156,16 +156,16 @@ bool ObtainCacheParticleData(Mesh *mesh, BL::Mesh *b_mesh, BL::Object *b_ob, Par
PointerRNA cpsys = RNA_pointer_get(&b_part.ptr, "cycles");
- CData->psys_firstcurve.push_back(curvenum);
- CData->psys_curvenum.push_back(totcurves);
- CData->psys_shader.push_back(shader);
+ CData->psys_firstcurve.push_back_slow(curvenum);
+ CData->psys_curvenum.push_back_slow(totcurves);
+ CData->psys_shader.push_back_slow(shader);
float radius = get_float(cpsys, "radius_scale") * 0.5f;
- CData->psys_rootradius.push_back(radius * get_float(cpsys, "root_width"));
- CData->psys_tipradius.push_back(radius * get_float(cpsys, "tip_width"));
- CData->psys_shape.push_back(get_float(cpsys, "shape"));
- CData->psys_closetip.push_back(get_boolean(cpsys, "use_closetip"));
+ CData->psys_rootradius.push_back_slow(radius * get_float(cpsys, "root_width"));
+ CData->psys_tipradius.push_back_slow(radius * get_float(cpsys, "tip_width"));
+ CData->psys_shape.push_back_slow(get_float(cpsys, "shape"));
+ CData->psys_closetip.push_back_slow(get_boolean(cpsys, "use_closetip"));
int pa_no = 0;
if(!(b_part.child_type() == 0) && totchild != 0)
@@ -180,7 +180,7 @@ bool ObtainCacheParticleData(Mesh *mesh, BL::Mesh *b_mesh, BL::Object *b_ob, Par
for(; pa_no < totparts+totchild; pa_no++) {
int keynum = 0;
- CData->curve_firstkey.push_back(keyno);
+ CData->curve_firstkey.push_back_slow(keyno);
float curve_length = 0.0f;
float3 pcKey;
@@ -195,15 +195,15 @@ bool ObtainCacheParticleData(Mesh *mesh, BL::Mesh *b_mesh, BL::Object *b_ob, Par
continue;
curve_length += step_length;
}
- CData->curvekey_co.push_back(cKey);
- CData->curvekey_time.push_back(curve_length);
+ CData->curvekey_co.push_back_slow(cKey);
+ CData->curvekey_time.push_back_slow(curve_length);
pcKey = cKey;
keynum++;
}
keyno += keynum;
- CData->curve_keynum.push_back(keynum);
- CData->curve_length.push_back(curve_length);
+ CData->curve_keynum.push_back_slow(keynum);
+ CData->curve_length.push_back_slow(curve_length);
curvenum++;
}
}
@@ -255,7 +255,7 @@ bool ObtainCacheParticleUV(Mesh *mesh, BL::Mesh *b_mesh, BL::Object *b_ob, Parti
float3 uv = make_float3(0.0f, 0.0f, 0.0f);
if(b_mesh->tessface_uv_textures.length())
b_psys.uv_on_emitter(psmd, *b_pa, pa_no, uv_num, &uv.x);
- CData->curve_uv.push_back(uv);
+ CData->curve_uv.push_back_slow(uv);
if(pa_no < totparts && b_pa != b_psys.particles.end())
++b_pa;
@@ -309,7 +309,7 @@ bool ObtainCacheParticleVcol(Mesh *mesh, BL::Mesh *b_mesh, BL::Object *b_ob, Par
float3 vcol = make_float3(0.0f, 0.0f, 0.0f);
if(b_mesh->tessface_vertex_colors.length())
b_psys.mcol_on_emitter(psmd, *b_pa, pa_no, vcol_num, &vcol.x);
- CData->curve_vcol.push_back(vcol);
+ CData->curve_vcol.push_back_slow(vcol);
if(pa_no < totparts && b_pa != b_psys.particles.end())
++b_pa;
@@ -351,10 +351,7 @@ void ExportCurveTrianglePlanes(Mesh *mesh, ParticleCurveData *CData,
}
}
- mesh->verts.reserve(mesh->verts.size() + numverts);
- mesh->triangles.reserve(mesh->triangles.size() + numtris);
- mesh->shader.reserve(mesh->shader.size() + numtris);
- mesh->smooth.reserve(mesh->smooth.size() + numtris);
+ mesh->reserve_mesh(mesh->verts.size() + numverts, mesh->num_triangles() + numtris);
/* actually export */
for(int sys = 0; sys < CData->psys_firstcurve.size() ; sys++) {
@@ -374,8 +371,8 @@ void ExportCurveTrianglePlanes(Mesh *mesh, ParticleCurveData *CData,
xbasis = normalize(cross(RotCam - ickey_loc, v1));
float3 ickey_loc_shfl = ickey_loc - radius * xbasis;
float3 ickey_loc_shfr = ickey_loc + radius * xbasis;
- mesh->verts.push_back(ickey_loc_shfl);
- mesh->verts.push_back(ickey_loc_shfr);
+ mesh->add_vertex(ickey_loc_shfl);
+ mesh->add_vertex(ickey_loc_shfr);
vertexindex += 2;
for(int curvekey = CData->curve_firstkey[curve] + 1; curvekey < CData->curve_firstkey[curve] + CData->curve_keynum[curve]; curvekey++) {
@@ -401,8 +398,8 @@ void ExportCurveTrianglePlanes(Mesh *mesh, ParticleCurveData *CData,
xbasis = normalize(cross(RotCam - ickey_loc, v1));
float3 ickey_loc_shfl = ickey_loc - radius * xbasis;
float3 ickey_loc_shfr = ickey_loc + radius * xbasis;
- mesh->verts.push_back(ickey_loc_shfl);
- mesh->verts.push_back(ickey_loc_shfr);
+ mesh->add_vertex(ickey_loc_shfl);
+ mesh->add_vertex(ickey_loc_shfr);
mesh->add_triangle(vertexindex-2, vertexindex, vertexindex-1, CData->psys_shader[sys], true);
mesh->add_triangle(vertexindex+1, vertexindex-1, vertexindex, CData->psys_shader[sys], true);
vertexindex += 2;
@@ -410,7 +407,6 @@ void ExportCurveTrianglePlanes(Mesh *mesh, ParticleCurveData *CData,
}
}
- mesh->reserve(mesh->verts.size(), mesh->triangles.size(), 0, 0);
mesh->attributes.remove(ATTR_STD_VERTEX_NORMAL);
mesh->attributes.remove(ATTR_STD_FACE_NORMAL);
mesh->add_face_normals();
@@ -437,10 +433,7 @@ void ExportCurveTriangleGeometry(Mesh *mesh, ParticleCurveData *CData, int resol
}
}
- mesh->verts.reserve(mesh->verts.size() + numverts);
- mesh->triangles.reserve(mesh->triangles.size() + numtris);
- mesh->shader.reserve(mesh->shader.size() + numtris);
- mesh->smooth.reserve(mesh->smooth.size() + numtris);
+ mesh->reserve_mesh(mesh->verts.size() + numverts, mesh->num_triangles() + numtris);
/* actually export */
for(int sys = 0; sys < CData->psys_firstcurve.size() ; sys++) {
@@ -529,7 +522,7 @@ void ExportCurveTriangleGeometry(Mesh *mesh, ParticleCurveData *CData, int resol
float angle = M_2PI_F / (float)resolution;
for(int section = 0; section < resolution; section++) {
float3 ickey_loc_shf = ickey_loc + radius * (cosf(angle * section) * xbasis + sinf(angle * section) * ybasis);
- mesh->verts.push_back(ickey_loc_shf);
+ mesh->add_vertex(ickey_loc_shf);
}
if(subv != 0) {
@@ -546,7 +539,6 @@ void ExportCurveTriangleGeometry(Mesh *mesh, ParticleCurveData *CData, int resol
}
}
- mesh->reserve(mesh->verts.size(), mesh->triangles.size(), 0, 0);
mesh->attributes.remove(ATTR_STD_VERTEX_NORMAL);
mesh->attributes.remove(ATTR_STD_FACE_NORMAL);
mesh->add_face_normals();
@@ -561,7 +553,7 @@ void ExportCurveSegments(Scene *scene, Mesh *mesh, ParticleCurveData *CData)
int num_keys = 0;
int num_curves = 0;
- if(!(mesh->curves.empty() && mesh->curve_keys.empty()))
+ if(mesh->num_curves())
return;
Attribute *attr_intercept = NULL;
@@ -584,8 +576,7 @@ void ExportCurveSegments(Scene *scene, Mesh *mesh, ParticleCurveData *CData)
VLOG(1) << "Exporting curve segments for mesh " << mesh->name;
}
- mesh->curve_keys.reserve(mesh->curve_keys.size() + num_keys);
- mesh->curves.reserve(mesh->curves.size() + num_curves);
+ mesh->reserve_curves(mesh->num_curves() + num_curves, mesh->curve_keys.size() + num_keys);
num_keys = 0;
num_curves = 0;
@@ -613,18 +604,16 @@ void ExportCurveSegments(Scene *scene, Mesh *mesh, ParticleCurveData *CData)
num_curve_keys++;
}
- mesh->add_curve(num_keys, num_curve_keys, CData->psys_shader[sys]);
+ mesh->add_curve(num_keys, CData->psys_shader[sys]);
num_keys += num_curve_keys;
num_curves++;
}
}
/* check allocation */
- if((mesh->curve_keys.size() != num_keys) || (mesh->curves.size() != num_curves)) {
+ if((mesh->curve_keys.size() != num_keys) || (mesh->num_curves() != num_curves)) {
VLOG(1) << "Allocation failed, clearing data";
- mesh->curve_keys.clear();
- mesh->curves.clear();
- mesh->curve_attributes.clear();
+ mesh->clear();
}
}
@@ -667,13 +656,16 @@ static void ExportCurveSegmentsMotion(Mesh *mesh, ParticleCurveData *CData, int
if(CData->psys_closetip[sys] && (curvekey == CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 1))
radius = 0.0f;
+ /* curve motion keys store both position and radius in float4 */
mP[i] = float3_to_float4(ickey_loc);
mP[i].w = radius;
/* unlike mesh coordinates, these tend to be slightly different
* between frames due to particle transforms into/out of object
* space, so we use an epsilon to detect actual changes */
- if(len_squared(mP[i] - mesh->curve_keys[i]) > 1e-5f*1e-5f)
+ float4 curve_key = float3_to_float4(mesh->curve_keys[i]);
+ curve_key.w = mesh->curve_radius[i];
+ if(len_squared(mP[i] - curve_key) > 1e-5f*1e-5f)
have_motion = true;
}
@@ -697,8 +689,10 @@ static void ExportCurveSegmentsMotion(Mesh *mesh, ParticleCurveData *CData, int
for(int step = 0; step < time_index; step++) {
float4 *mP = attr_mP->data_float4() + step*numkeys;
- for(int key = 0; key < numkeys; key++)
- mP[key] = mesh->curve_keys[key];
+ for(int key = 0; key < numkeys; key++) {
+ mP[key] = float3_to_float4(mesh->curve_keys[key]);
+ mP[key].w = mesh->curve_radius[key];
+ }
}
}
}
@@ -872,7 +866,9 @@ void BlenderSync::sync_curves(Mesh *mesh,
if(!motion) {
/* Clear stored curve data */
mesh->curve_keys.clear();
- mesh->curves.clear();
+ mesh->curve_radius.clear();
+ mesh->curve_first_key.clear();
+ mesh->curve_shader.clear();
mesh->curve_attributes.clear();
}
@@ -889,7 +885,7 @@ void BlenderSync::sync_curves(Mesh *mesh,
int triangle_method = scene->curve_system_manager->triangle_method;
int resolution = scene->curve_system_manager->resolution;
size_t vert_num = mesh->verts.size();
- size_t tri_num = mesh->triangles.size();
+ size_t tri_num = mesh->num_triangles();
int used_res = 1;
/* extract particle hair data - should be combined with connecting to mesh later*/
@@ -950,11 +946,10 @@ void BlenderSync::sync_curves(Mesh *mesh,
else {
Attribute *attr_generated = mesh->curve_attributes.add(ATTR_STD_GENERATED);
float3 *generated = attr_generated->data_float3();
- size_t i = 0;
- foreach(Mesh::Curve& curve, mesh->curves) {
- float3 co = float4_to_float3(mesh->curve_keys[curve.first_key]);
- generated[i++] = co*size - loc;
+ for(size_t i = 0; i < mesh->num_curves(); i++) {
+ float3 co = mesh->curve_keys[mesh->get_curve(i).first_key];
+ generated[i] = co*size - loc;
}
}
}
diff --git a/intern/cycles/blender/blender_mesh.cpp b/intern/cycles/blender/blender_mesh.cpp
index 4a0ad79f3ae..80db51148e6 100644
--- a/intern/cycles/blender/blender_mesh.cpp
+++ b/intern/cycles/blender/blender_mesh.cpp
@@ -548,13 +548,12 @@ static void create_mesh(Scene *scene,
numtris += (vi[3] == 0)? 1: 2;
}
- /* reserve memory */
- mesh->reserve(numverts, numtris, 0, 0);
+ /* allocate memory */
+ mesh->reserve_mesh(numverts, numtris);
/* create vertex coordinates and normals */
- int i = 0;
- for(b_mesh.vertices.begin(v); v != b_mesh.vertices.end(); ++v, ++i)
- mesh->verts[i] = get_float3(v->co());
+ for(b_mesh.vertices.begin(v); v != b_mesh.vertices.end(); ++v)
+ mesh->add_vertex(get_float3(v->co()));
Attribute *attr_N = mesh->attributes.add(ATTR_STD_VERTEX_NORMAL);
float3 *N = attr_N->data_float3();
@@ -583,7 +582,7 @@ static void create_mesh(Scene *scene,
/* create faces */
vector<int> nverts(numfaces);
vector<int> face_flags(numfaces, FACE_FLAG_NONE);
- int fi = 0, ti = 0;
+ int fi = 0;
for(b_mesh.tessfaces.begin(f); f != b_mesh.tessfaces.end(); ++f, ++fi) {
int4 vi = get_int4(f->vertices_raw());
@@ -618,18 +617,18 @@ static void create_mesh(Scene *scene,
is_zero(cross(mesh->verts[vi[2]] - mesh->verts[vi[0]], mesh->verts[vi[3]] - mesh->verts[vi[0]])))
{
// TODO(mai): order here is probably wrong
- mesh->set_triangle(ti++, vi[0], vi[1], vi[3], shader, smooth, true);
- mesh->set_triangle(ti++, vi[2], vi[3], vi[1], shader, smooth, true);
+ mesh->add_triangle(vi[0], vi[1], vi[3], shader, smooth, true);
+ mesh->add_triangle(vi[2], vi[3], vi[1], shader, smooth, true);
face_flags[fi] |= FACE_FLAG_DIVIDE_24;
}
else {
- mesh->set_triangle(ti++, vi[0], vi[1], vi[2], shader, smooth, true);
- mesh->set_triangle(ti++, vi[0], vi[2], vi[3], shader, smooth, true);
+ mesh->add_triangle(vi[0], vi[1], vi[2], shader, smooth, true);
+ mesh->add_triangle(vi[0], vi[2], vi[3], shader, smooth, true);
face_flags[fi] |= FACE_FLAG_DIVIDE_13;
}
}
else
- mesh->set_triangle(ti++, vi[0], vi[1], vi[2], shader, smooth, false);
+ mesh->add_triangle(vi[0], vi[1], vi[2], shader, smooth, false);
nverts[fi] = n;
}
@@ -759,11 +758,12 @@ Mesh *BlenderSync::sync_mesh(BL::Object& b_ob,
/* create derived mesh */
PointerRNA cmesh = RNA_pointer_get(&b_ob_data.ptr, "cycles");
- vector<Mesh::Triangle> oldtriangle = mesh->triangles;
+ array<int> oldtriangle = mesh->triangles;
/* compares curve_keys rather than strands in order to handle quick hair
* adjustments in dynamic BVH - other methods could probably do this better*/
- vector<float4> oldcurve_keys = mesh->curve_keys;
+ array<float3> oldcurve_keys = mesh->curve_keys;
+ array<float> oldcurve_radius = mesh->curve_radius;
mesh->clear();
mesh->used_shaders = used_shaders;
@@ -827,14 +827,21 @@ Mesh *BlenderSync::sync_mesh(BL::Object& b_ob,
if(oldtriangle.size() != mesh->triangles.size())
rebuild = true;
else if(oldtriangle.size()) {
- if(memcmp(&oldtriangle[0], &mesh->triangles[0], sizeof(Mesh::Triangle)*oldtriangle.size()) != 0)
+ if(memcmp(&oldtriangle[0], &mesh->triangles[0], sizeof(int)*oldtriangle.size()) != 0)
rebuild = true;
}
if(oldcurve_keys.size() != mesh->curve_keys.size())
rebuild = true;
else if(oldcurve_keys.size()) {
- if(memcmp(&oldcurve_keys[0], &mesh->curve_keys[0], sizeof(float4)*oldcurve_keys.size()) != 0)
+ if(memcmp(&oldcurve_keys[0], &mesh->curve_keys[0], sizeof(float3)*oldcurve_keys.size()) != 0)
+ rebuild = true;
+ }
+
+ if(oldcurve_radius.size() != mesh->curve_radius.size())
+ rebuild = true;
+ else if(oldcurve_radius.size()) {
+ if(memcmp(&oldcurve_radius[0], &mesh->curve_radius[0], sizeof(float)*oldcurve_radius.size()) != 0)
rebuild = true;
}
@@ -931,8 +938,8 @@ void BlenderSync::sync_mesh_motion(BL::Object& b_ob,
Attribute *attr_mP = mesh->curve_attributes.find(ATTR_STD_MOTION_VERTEX_POSITION);
if(attr_mP) {
- float4 *keys = &mesh->curve_keys[0];
- memcpy(attr_mP->data_float4() + time_index*numkeys, keys, sizeof(float4)*numkeys);
+ float3 *keys = &mesh->curve_keys[0];
+ memcpy(attr_mP->data_float3() + time_index*numkeys, keys, sizeof(float3)*numkeys);
}
}
diff --git a/intern/cycles/blender/blender_particles.cpp b/intern/cycles/blender/blender_particles.cpp
index d1e702cfdc2..b9876cd604f 100644
--- a/intern/cycles/blender/blender_particles.cpp
+++ b/intern/cycles/blender/blender_particles.cpp
@@ -76,7 +76,7 @@ bool BlenderSync::sync_dupli_particle(BL::Object& b_ob,
pa.velocity = get_float3(b_pa.velocity());
pa.angular_velocity = get_float3(b_pa.angular_velocity());
- psys->particles.push_back(pa);
+ psys->particles.push_back_slow(pa);
if(object->particle_index != psys->particles.size() - 1)
scene->object_manager->tag_update(scene);
diff --git a/intern/cycles/blender/blender_shader.cpp b/intern/cycles/blender/blender_shader.cpp
index a56c2e75e4e..7a13641a312 100644
--- a/intern/cycles/blender/blender_shader.cpp
+++ b/intern/cycles/blender/blender_shader.cpp
@@ -127,82 +127,57 @@ static float3 get_node_output_vector(BL::Node& b_node, const string& name)
return make_float3(value[0], value[1], value[2]);
}
-static ShaderSocketType convert_socket_type(BL::NodeSocket& b_socket)
+static SocketType::Type convert_socket_type(BL::NodeSocket& b_socket)
{
switch(b_socket.type()) {
case BL::NodeSocket::type_VALUE:
- return SHADER_SOCKET_FLOAT;
+ return SocketType::FLOAT;
case BL::NodeSocket::type_INT:
- return SHADER_SOCKET_INT;
+ return SocketType::INT;
case BL::NodeSocket::type_VECTOR:
- return SHADER_SOCKET_VECTOR;
+ return SocketType::VECTOR;
case BL::NodeSocket::type_RGBA:
- return SHADER_SOCKET_COLOR;
+ return SocketType::COLOR;
case BL::NodeSocket::type_STRING:
- return SHADER_SOCKET_STRING;
+ return SocketType::STRING;
case BL::NodeSocket::type_SHADER:
- return SHADER_SOCKET_CLOSURE;
+ return SocketType::CLOSURE;
default:
- return SHADER_SOCKET_UNDEFINED;
+ return SocketType::UNDEFINED;
}
}
-#ifdef WITH_OSL
-static ShaderSocketType convert_osl_socket_type(OSL::OSLQuery& query,
- BL::NodeSocket& b_socket)
-{
- ShaderSocketType socket_type = convert_socket_type(b_socket);
- if(socket_type == SHADER_SOCKET_VECTOR) {
- /* TODO(sergey): Do we need compatible_name() here? */
- const OSL::OSLQuery::Parameter *param = query.getparam(b_socket.name());
- assert(param != NULL);
- if(param != NULL) {
- if(param->type.vecsemantics == TypeDesc::POINT) {
- socket_type = SHADER_SOCKET_POINT;
- }
- else if(param->type.vecsemantics == TypeDesc::NORMAL) {
- socket_type = SHADER_SOCKET_NORMAL;
- }
- }
- }
-
- return socket_type;
-}
-#endif /* WITH_OSL */
-
static void set_default_value(ShaderInput *input,
BL::NodeSocket& b_sock,
BL::BlendData& b_data,
BL::ID& b_id)
{
/* copy values for non linked inputs */
- switch(input->type) {
- case SHADER_SOCKET_FLOAT: {
+ switch(input->type()) {
+ case SocketType::FLOAT: {
input->set(get_float(b_sock.ptr, "default_value"));
break;
}
- case SHADER_SOCKET_INT: {
- input->set((float)get_int(b_sock.ptr, "default_value"));
+ case SocketType::INT: {
+ input->set(get_int(b_sock.ptr, "default_value"));
break;
}
- case SHADER_SOCKET_COLOR: {
+ case SocketType::COLOR: {
input->set(float4_to_float3(get_float4(b_sock.ptr, "default_value")));
break;
}
- case SHADER_SOCKET_NORMAL:
- case SHADER_SOCKET_POINT:
- case SHADER_SOCKET_VECTOR: {
+ case SocketType::NORMAL:
+ case SocketType::POINT:
+ case SocketType::VECTOR: {
input->set(get_float3(b_sock.ptr, "default_value"));
break;
}
- case SHADER_SOCKET_STRING: {
+ case SocketType::STRING: {
input->set((ustring)blender_absolute_path(b_data, b_id, get_string(b_sock.ptr, "default_value")));
break;
}
-
- case SHADER_SOCKET_CLOSURE:
- case SHADER_SOCKET_UNDEFINED:
+ default:
break;
}
}
@@ -315,7 +290,7 @@ static ShaderNode *add_node(Scene *scene,
else if(b_node.is_a(&RNA_ShaderNodeMixRGB)) {
BL::ShaderNodeMixRGB b_mix_node(b_node);
MixNode *mix = new MixNode();
- mix->type = MixNode::type_enum[b_mix_node.blend_type()];
+ mix->type = (NodeMix)b_mix_node.blend_type();
mix->use_clamp = b_mix_node.use_clamp();
node = mix;
}
@@ -341,27 +316,27 @@ static ShaderNode *add_node(Scene *scene,
node = new HSVNode();
}
else if(b_node.is_a(&RNA_ShaderNodeRGBToBW)) {
- node = new ConvertNode(SHADER_SOCKET_COLOR, SHADER_SOCKET_FLOAT);
+ node = new RGBToBWNode();
}
else if(b_node.is_a(&RNA_ShaderNodeMath)) {
BL::ShaderNodeMath b_math_node(b_node);
MathNode *math = new MathNode();
- math->type = MathNode::type_enum[b_math_node.operation()];
+ math->type = (NodeMath)b_math_node.operation();
math->use_clamp = b_math_node.use_clamp();
node = math;
}
else if(b_node.is_a(&RNA_ShaderNodeVectorMath)) {
BL::ShaderNodeVectorMath b_vector_math_node(b_node);
VectorMathNode *vmath = new VectorMathNode();
- vmath->type = VectorMathNode::type_enum[b_vector_math_node.operation()];
+ vmath->type = (NodeVectorMath)b_vector_math_node.operation();
node = vmath;
}
else if(b_node.is_a(&RNA_ShaderNodeVectorTransform)) {
BL::ShaderNodeVectorTransform b_vector_transform_node(b_node);
VectorTransformNode *vtransform = new VectorTransformNode();
- vtransform->type = VectorTransformNode::type_enum[b_vector_transform_node.vector_type()];
- vtransform->convert_from = VectorTransformNode::convert_space_enum[b_vector_transform_node.convert_from()];
- vtransform->convert_to = VectorTransformNode::convert_space_enum[b_vector_transform_node.convert_to()];
+ vtransform->type = (NodeVectorTransformType)b_vector_transform_node.vector_type();
+ vtransform->convert_from = (NodeVectorTransformConvertSpace)b_vector_transform_node.convert_from();
+ vtransform->convert_to = (NodeVectorTransformConvertSpace)b_vector_transform_node.convert_to();
node = vtransform;
}
else if(b_node.is_a(&RNA_ShaderNodeNormal)) {
@@ -410,13 +385,13 @@ static ShaderNode *add_node(Scene *scene,
switch(b_aniso_node.distribution()) {
case BL::ShaderNodeBsdfAnisotropic::distribution_BECKMANN:
- aniso->distribution = ustring("Beckmann");
+ aniso->distribution = CLOSURE_BSDF_MICROFACET_BECKMANN_ANISO_ID;
break;
case BL::ShaderNodeBsdfAnisotropic::distribution_GGX:
- aniso->distribution = ustring("GGX");
+ aniso->distribution = CLOSURE_BSDF_MICROFACET_GGX_ANISO_ID;
break;
case BL::ShaderNodeBsdfAnisotropic::distribution_ASHIKHMIN_SHIRLEY:
- aniso->distribution = ustring("Ashikhmin-Shirley");
+ aniso->distribution = CLOSURE_BSDF_ASHIKHMIN_SHIRLEY_ANISO_ID;
break;
}
@@ -432,13 +407,13 @@ static ShaderNode *add_node(Scene *scene,
switch(b_subsurface_node.falloff()) {
case BL::ShaderNodeSubsurfaceScattering::falloff_CUBIC:
- subsurface->closure = CLOSURE_BSSRDF_CUBIC_ID;
+ subsurface->falloff = CLOSURE_BSSRDF_CUBIC_ID;
break;
case BL::ShaderNodeSubsurfaceScattering::falloff_GAUSSIAN:
- subsurface->closure = CLOSURE_BSSRDF_GAUSSIAN_ID;
+ subsurface->falloff = CLOSURE_BSSRDF_GAUSSIAN_ID;
break;
case BL::ShaderNodeSubsurfaceScattering::falloff_BURLEY:
- subsurface->closure = CLOSURE_BSSRDF_BURLEY_ID;
+ subsurface->falloff = CLOSURE_BSSRDF_BURLEY_ID;
break;
}
@@ -450,16 +425,16 @@ static ShaderNode *add_node(Scene *scene,
switch(b_glossy_node.distribution()) {
case BL::ShaderNodeBsdfGlossy::distribution_SHARP:
- glossy->distribution = ustring("Sharp");
+ glossy->distribution = CLOSURE_BSDF_REFLECTION_ID;
break;
case BL::ShaderNodeBsdfGlossy::distribution_BECKMANN:
- glossy->distribution = ustring("Beckmann");
+ glossy->distribution = CLOSURE_BSDF_MICROFACET_BECKMANN_ID;
break;
case BL::ShaderNodeBsdfGlossy::distribution_GGX:
- glossy->distribution = ustring("GGX");
+ glossy->distribution = CLOSURE_BSDF_MICROFACET_GGX_ID;
break;
case BL::ShaderNodeBsdfGlossy::distribution_ASHIKHMIN_SHIRLEY:
- glossy->distribution = ustring("Ashikhmin-Shirley");
+ glossy->distribution = CLOSURE_BSDF_ASHIKHMIN_SHIRLEY_ANISO_ID;
break;
}
node = glossy;
@@ -469,13 +444,13 @@ static ShaderNode *add_node(Scene *scene,
GlassBsdfNode *glass = new GlassBsdfNode();
switch(b_glass_node.distribution()) {
case BL::ShaderNodeBsdfGlass::distribution_SHARP:
- glass->distribution = ustring("Sharp");
+ glass->distribution = CLOSURE_BSDF_SHARP_GLASS_ID;
break;
case BL::ShaderNodeBsdfGlass::distribution_BECKMANN:
- glass->distribution = ustring("Beckmann");
+ glass->distribution = CLOSURE_BSDF_MICROFACET_BECKMANN_GLASS_ID;
break;
case BL::ShaderNodeBsdfGlass::distribution_GGX:
- glass->distribution = ustring("GGX");
+ glass->distribution = CLOSURE_BSDF_MICROFACET_GGX_GLASS_ID;
break;
}
node = glass;
@@ -485,13 +460,13 @@ static ShaderNode *add_node(Scene *scene,
RefractionBsdfNode *refraction = new RefractionBsdfNode();
switch(b_refraction_node.distribution()) {
case BL::ShaderNodeBsdfRefraction::distribution_SHARP:
- refraction->distribution = ustring("Sharp");
+ refraction->distribution = CLOSURE_BSDF_REFRACTION_ID;
break;
case BL::ShaderNodeBsdfRefraction::distribution_BECKMANN:
- refraction->distribution = ustring("Beckmann");
+ refraction->distribution = CLOSURE_BSDF_MICROFACET_BECKMANN_REFRACTION_ID;
break;
case BL::ShaderNodeBsdfRefraction::distribution_GGX:
- refraction->distribution = ustring("GGX");
+ refraction->distribution = CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID;
break;
}
node = refraction;
@@ -501,10 +476,10 @@ static ShaderNode *add_node(Scene *scene,
ToonBsdfNode *toon = new ToonBsdfNode();
switch(b_toon_node.component()) {
case BL::ShaderNodeBsdfToon::component_DIFFUSE:
- toon->component = ustring("Diffuse");
+ toon->component = CLOSURE_BSDF_DIFFUSE_TOON_ID;
break;
case BL::ShaderNodeBsdfToon::component_GLOSSY:
- toon->component = ustring("Glossy");
+ toon->component = CLOSURE_BSDF_GLOSSY_TOON_ID;
break;
}
node = toon;
@@ -514,10 +489,10 @@ static ShaderNode *add_node(Scene *scene,
HairBsdfNode *hair = new HairBsdfNode();
switch(b_hair_node.component()) {
case BL::ShaderNodeBsdfHair::component_Reflection:
- hair->component = ustring("Reflection");
+ hair->component = CLOSURE_BSDF_HAIR_REFLECTION_ID;
break;
case BL::ShaderNodeBsdfHair::component_Transmission:
- hair->component = ustring("Transmission");
+ hair->component = CLOSURE_BSDF_HAIR_TRANSMISSION_ID;
break;
}
node = hair;
@@ -584,62 +559,17 @@ static ShaderNode *add_node(Scene *scene,
if(scene->shader_manager->use_osl()) {
/* create script node */
BL::ShaderNodeScript b_script_node(b_node);
- OSLScriptNode *script_node = new OSLScriptNode();
OSLShaderManager *manager = (OSLShaderManager*)scene->shader_manager;
string bytecode_hash = b_script_node.bytecode_hash();
- /* Gather additional information from the shader, such as
- * input/output type info needed for proper node construction.
- */
- OSL::OSLQuery query;
- string absolute_filepath;
-
- if(!bytecode_hash.empty()) {
- query.open_bytecode(b_script_node.bytecode());
- }
- else {
- absolute_filepath = blender_absolute_path(b_data, b_ntree, b_script_node.filepath());
- OSLShaderManager::osl_query(query, absolute_filepath);
- }
- /* TODO(sergey): Add proper query info error parsing. */
-
- /* Generate inputs/outputs from node sockets
- *
- * Note: the node sockets are generated from OSL parameters,
- * so the names match those of the corresponding parameters exactly.
- *
- * Note 2: ShaderInput/ShaderOutput store shallow string copies only!
- * So we register them as ustring to ensure the pointer stays valid. */
- BL::Node::inputs_iterator b_input;
-
- for(b_script_node.inputs.begin(b_input); b_input != b_script_node.inputs.end(); ++b_input) {
- ShaderInput *input = script_node->add_input(ustring(b_input->name()).c_str(),
- convert_osl_socket_type(query, *b_input));
- set_default_value(input, *b_input, b_data, b_ntree);
- }
-
- BL::Node::outputs_iterator b_output;
-
- for(b_script_node.outputs.begin(b_output); b_output != b_script_node.outputs.end(); ++b_output) {
- script_node->add_output(ustring(b_output->name()).c_str(),
- convert_osl_socket_type(query, *b_output));
- }
-
- /* load bytecode or filepath */
if(!bytecode_hash.empty()) {
- /* loaded bytecode if not already done */
- if(!manager->shader_test_loaded(bytecode_hash))
- manager->shader_load_bytecode(bytecode_hash, b_script_node.bytecode());
-
- script_node->bytecode_hash = bytecode_hash;
+ node = manager->osl_node("", bytecode_hash, b_script_node.bytecode());
}
else {
- /* set filepath */
- script_node->filepath = absolute_filepath;
+ string absolute_filepath = blender_absolute_path(b_data, b_ntree, b_script_node.filepath());
+ node = manager->osl_node(absolute_filepath, "");
}
-
- node = script_node;
}
#else
(void)b_data;
@@ -692,8 +622,8 @@ static ShaderNode *add_node(Scene *scene,
get_image_extension(b_image_node));
}
}
- image->color_space = ImageTextureNode::color_space_enum[(int)b_image_node.color_space()];
- image->projection = ImageTextureNode::projection_enum[(int)b_image_node.projection()];
+ image->color_space = (NodeImageColorSpace)b_image_node.color_space();
+ image->projection = (NodeImageProjection)b_image_node.projection();
image->interpolation = get_image_interpolation(b_image_node);
image->extension = get_image_extension(b_image_node);
image->projection_blend = b_image_node.projection_blend();
@@ -738,9 +668,9 @@ static ShaderNode *add_node(Scene *scene,
EXTENSION_REPEAT);
}
}
- env->color_space = EnvironmentTextureNode::color_space_enum[(int)b_env_node.color_space()];
+ env->color_space = (NodeImageColorSpace)b_env_node.color_space();
env->interpolation = get_image_interpolation(b_env_node);
- env->projection = EnvironmentTextureNode::projection_enum[(int)b_env_node.projection()];
+ env->projection = (NodeEnvironmentProjection)b_env_node.projection();
BL::TexMapping b_texture_mapping(b_env_node.texture_mapping());
get_tex_mapping(&env->tex_mapping, b_texture_mapping);
node = env;
@@ -748,7 +678,7 @@ static ShaderNode *add_node(Scene *scene,
else if(b_node.is_a(&RNA_ShaderNodeTexGradient)) {
BL::ShaderNodeTexGradient b_gradient_node(b_node);
GradientTextureNode *gradient = new GradientTextureNode();
- gradient->type = GradientTextureNode::type_enum[(int)b_gradient_node.gradient_type()];
+ gradient->type = (NodeGradientType)b_gradient_node.gradient_type();
BL::TexMapping b_texture_mapping(b_gradient_node.texture_mapping());
get_tex_mapping(&gradient->tex_mapping, b_texture_mapping);
node = gradient;
@@ -756,7 +686,7 @@ static ShaderNode *add_node(Scene *scene,
else if(b_node.is_a(&RNA_ShaderNodeTexVoronoi)) {
BL::ShaderNodeTexVoronoi b_voronoi_node(b_node);
VoronoiTextureNode *voronoi = new VoronoiTextureNode();
- voronoi->coloring = VoronoiTextureNode::coloring_enum[(int)b_voronoi_node.coloring()];
+ voronoi->coloring = (NodeVoronoiColoring)b_voronoi_node.coloring();
BL::TexMapping b_texture_mapping(b_voronoi_node.texture_mapping());
get_tex_mapping(&voronoi->tex_mapping, b_texture_mapping);
node = voronoi;
@@ -772,8 +702,8 @@ static ShaderNode *add_node(Scene *scene,
else if(b_node.is_a(&RNA_ShaderNodeTexWave)) {
BL::ShaderNodeTexWave b_wave_node(b_node);
WaveTextureNode *wave = new WaveTextureNode();
- wave->type = WaveTextureNode::type_enum[(int)b_wave_node.wave_type()];
- wave->profile = WaveTextureNode::profile_enum[(int)b_wave_node.wave_profile()];
+ wave->type = (NodeWaveType)b_wave_node.wave_type();
+ wave->profile = (NodeWaveProfile)b_wave_node.wave_profile();
BL::TexMapping b_texture_mapping(b_wave_node.texture_mapping());
get_tex_mapping(&wave->tex_mapping, b_texture_mapping);
node = wave;
@@ -806,7 +736,7 @@ static ShaderNode *add_node(Scene *scene,
else if(b_node.is_a(&RNA_ShaderNodeTexMusgrave)) {
BL::ShaderNodeTexMusgrave b_musgrave_node(b_node);
MusgraveTextureNode *musgrave = new MusgraveTextureNode();
- musgrave->type = MusgraveTextureNode::type_enum[(int)b_musgrave_node.musgrave_type()];
+ musgrave->type = (NodeMusgraveType)b_musgrave_node.musgrave_type();
BL::TexMapping b_texture_mapping(b_musgrave_node.texture_mapping());
get_tex_mapping(&musgrave->tex_mapping, b_texture_mapping);
node = musgrave;
@@ -824,7 +754,7 @@ static ShaderNode *add_node(Scene *scene,
else if(b_node.is_a(&RNA_ShaderNodeTexSky)) {
BL::ShaderNodeTexSky b_sky_node(b_node);
SkyTextureNode *sky = new SkyTextureNode();
- sky->type = SkyTextureNode::type_enum[(int)b_sky_node.sky_type()];
+ sky->type = (NodeSkyType)b_sky_node.sky_type();
sky->sun_direction = normalize(get_float3(b_sky_node.sun_direction()));
sky->turbidity = b_sky_node.turbidity();
sky->ground_albedo = b_sky_node.ground_albedo();
@@ -835,15 +765,15 @@ static ShaderNode *add_node(Scene *scene,
else if(b_node.is_a(&RNA_ShaderNodeNormalMap)) {
BL::ShaderNodeNormalMap b_normal_map_node(b_node);
NormalMapNode *nmap = new NormalMapNode();
- nmap->space = NormalMapNode::space_enum[(int)b_normal_map_node.space()];
+ nmap->space = (NodeNormalMapSpace)b_normal_map_node.space();
nmap->attribute = b_normal_map_node.uv_map();
node = nmap;
}
else if(b_node.is_a(&RNA_ShaderNodeTangent)) {
BL::ShaderNodeTangent b_tangent_node(b_node);
TangentNode *tangent = new TangentNode();
- tangent->direction_type = TangentNode::direction_type_enum[(int)b_tangent_node.direction_type()];
- tangent->axis = TangentNode::axis_enum[(int)b_tangent_node.axis()];
+ tangent->direction_type = (NodeTangentDirectionType)b_tangent_node.direction_type();
+ tangent->axis = (NodeTangentAxis)b_tangent_node.axis();
tangent->attribute = b_tangent_node.uv_map();
node = tangent;
}
@@ -858,8 +788,7 @@ static ShaderNode *add_node(Scene *scene,
BL::ShaderNodeTexPointDensity b_point_density_node(b_node);
PointDensityTextureNode *point_density = new PointDensityTextureNode();
point_density->filename = b_point_density_node.name();
- point_density->space =
- PointDensityTextureNode::space_enum[(int)b_point_density_node.space()];
+ point_density->space = (NodeTexVoxelSpace)b_point_density_node.space();
point_density->interpolation = get_image_interpolation(b_point_density_node);
point_density->builtin_data = b_point_density_node.ptr.data;
@@ -1020,7 +949,7 @@ static void add_nodes(Scene *scene,
BL::Node::internal_links_iterator b_link;
for(b_node->internal_links.begin(b_link); b_link != b_node->internal_links.end(); ++b_link) {
BL::NodeSocket to_socket(b_link->to_socket());
- ShaderSocketType to_socket_type = convert_socket_type(to_socket);
+ SocketType::Type to_socket_type = convert_socket_type(to_socket);
ConvertNode *proxy = new ConvertNode(to_socket_type, to_socket_type, true);
input_map[b_link->from_socket().ptr.data] = proxy->inputs[0];
@@ -1043,7 +972,7 @@ static void add_nodes(Scene *scene,
* so that links have something to connect to and assert won't fail.
*/
for(b_node->inputs.begin(b_input); b_input != b_node->inputs.end(); ++b_input) {
- ShaderSocketType input_type = convert_socket_type(*b_input);
+ SocketType::Type input_type = convert_socket_type(*b_input);
ConvertNode *proxy = new ConvertNode(input_type, input_type, true);
graph->add(proxy);
@@ -1055,7 +984,7 @@ static void add_nodes(Scene *scene,
set_default_value(proxy->inputs[0], *b_input, b_data, b_ntree);
}
for(b_node->outputs.begin(b_output); b_output != b_node->outputs.end(); ++b_output) {
- ShaderSocketType output_type = convert_socket_type(*b_output);
+ SocketType::Type output_type = convert_socket_type(*b_output);
ConvertNode *proxy = new ConvertNode(output_type, output_type, true);
graph->add(proxy);
@@ -1227,7 +1156,7 @@ void BlenderSync::sync_materials(bool update_all)
ShaderNode *closure, *out;
closure = graph->add(new DiffuseBsdfNode());
- closure->input("Color")->value = get_float3(b_mat->diffuse_color());
+ closure->input("Color")->set(get_float3(b_mat->diffuse_color()));
out = graph->output();
graph->connect(closure->output("BSDF"), out->input("Surface"));
@@ -1276,7 +1205,7 @@ void BlenderSync::sync_world(bool update_all)
ShaderNode *closure, *out;
closure = graph->add(new BackgroundNode());
- closure->input("Color")->value = get_float3(b_world.horizon_color());
+ closure->input("Color")->set(get_float3(b_world.horizon_color()));
out = graph->output();
graph->connect(closure->output("Background"), out->input("Surface"));
@@ -1369,8 +1298,8 @@ void BlenderSync::sync_lamps(bool update_all)
}
closure = graph->add(new EmissionNode());
- closure->input("Color")->value = get_float3(b_lamp->color());
- closure->input("Strength")->value.x = strength;
+ closure->input("Color")->set(get_float3(b_lamp->color()));
+ closure->input("Strength")->set(strength);
out = graph->output();
graph->connect(closure->output("Emission"), out->input("Surface"));
diff --git a/intern/cycles/blender/blender_util.h b/intern/cycles/blender/blender_util.h
index e23d8bf4e2d..2510cebcdc0 100644
--- a/intern/cycles/blender/blender_util.h
+++ b/intern/cycles/blender/blender_util.h
@@ -98,11 +98,12 @@ static inline void curvemapping_minmax(/*const*/ BL::CurveMapping& cumap,
}
static inline void curvemapping_to_array(BL::CurveMapping& cumap,
- float *data,
+ array<float>& data,
int size)
{
cumap.update();
BL::CurveMap curve = cumap.curves[0];
+ data.resize(size);
for(int i = 0; i < size; i++) {
float t = (float)i/(float)(size-1);
data[i] = curve.evaluate(t);
diff --git a/intern/cycles/bvh/bvh.cpp b/intern/cycles/bvh/bvh.cpp
index 5c474c8c3e9..fa2b9ae7279 100644
--- a/intern/cycles/bvh/bvh.cpp
+++ b/intern/cycles/bvh/bvh.cpp
@@ -128,11 +128,11 @@ void BVH::pack_triangle(int idx, float4 storage[3])
const Mesh *mesh = objects[tob]->mesh;
int tidx = pack.prim_index[idx];
- const int *vidx = mesh->triangles[tidx].v;
+ Mesh::Triangle t = mesh->get_triangle(tidx);
const float3* vpos = &mesh->verts[0];
- float3 v0 = vpos[vidx[0]];
- float3 v1 = vpos[vidx[1]];
- float3 v2 = vpos[vidx[2]];
+ float3 v0 = vpos[t.v[0]];
+ float3 v1 = vpos[t.v[1]];
+ float3 v2 = vpos[t.v[2]];
storage[0] = float3_to_float4(v0);
storage[1] = float3_to_float4(v1);
@@ -506,10 +506,10 @@ void RegularBVH::refit_node(int idx, bool leaf, BoundBox& bbox, uint& visibility
if(pack.prim_type[prim] & PRIMITIVE_ALL_CURVE) {
/* curves */
int str_offset = (params.top_level)? mesh->curve_offset: 0;
- const Mesh::Curve& curve = mesh->curves[pidx - str_offset];
+ Mesh::Curve curve = mesh->get_curve(pidx - str_offset);
int k = PRIMITIVE_UNPACK_SEGMENT(pack.prim_type[prim]);
- curve.bounds_grow(k, &mesh->curve_keys[0], bbox);
+ curve.bounds_grow(k, &mesh->curve_keys[0], &mesh->curve_radius[0], bbox);
visibility |= PATH_RAY_CURVE;
@@ -520,17 +520,17 @@ void RegularBVH::refit_node(int idx, bool leaf, BoundBox& bbox, uint& visibility
if(attr) {
size_t mesh_size = mesh->curve_keys.size();
size_t steps = mesh->motion_steps - 1;
- float4 *key_steps = attr->data_float4();
+ float3 *key_steps = attr->data_float3();
for(size_t i = 0; i < steps; i++)
- curve.bounds_grow(k, key_steps + i*mesh_size, bbox);
+ curve.bounds_grow(k, key_steps + i*mesh_size, &mesh->curve_radius[0], bbox);
}
}
}
else {
/* triangles */
int tri_offset = (params.top_level)? mesh->tri_offset: 0;
- const Mesh::Triangle& triangle = mesh->triangles[pidx - tri_offset];
+ Mesh::Triangle triangle = mesh->get_triangle(pidx - tri_offset);
const float3 *vpos = &mesh->verts[0];
triangle.bounds_grow(vpos, bbox);
@@ -770,10 +770,10 @@ void QBVH::refit_node(int idx, bool leaf, BoundBox& bbox, uint& visibility)
if(pack.prim_type[prim] & PRIMITIVE_ALL_CURVE) {
/* Curves. */
int str_offset = (params.top_level)? mesh->curve_offset: 0;
- const Mesh::Curve& curve = mesh->curves[pidx - str_offset];
+ Mesh::Curve curve = mesh->get_curve(pidx - str_offset);
int k = PRIMITIVE_UNPACK_SEGMENT(pack.prim_type[prim]);
- curve.bounds_grow(k, &mesh->curve_keys[0], bbox);
+ curve.bounds_grow(k, &mesh->curve_keys[0], &mesh->curve_radius[0], bbox);
visibility |= PATH_RAY_CURVE;
@@ -784,17 +784,17 @@ void QBVH::refit_node(int idx, bool leaf, BoundBox& bbox, uint& visibility)
if(attr) {
size_t mesh_size = mesh->curve_keys.size();
size_t steps = mesh->motion_steps - 1;
- float4 *key_steps = attr->data_float4();
+ float3 *key_steps = attr->data_float3();
for(size_t i = 0; i < steps; i++)
- curve.bounds_grow(k, key_steps + i*mesh_size, bbox);
+ curve.bounds_grow(k, key_steps + i*mesh_size, &mesh->curve_radius[0], bbox);
}
}
}
else {
/* Triangles. */
int tri_offset = (params.top_level)? mesh->tri_offset: 0;
- const Mesh::Triangle& triangle = mesh->triangles[pidx - tri_offset];
+ Mesh::Triangle triangle = mesh->get_triangle(pidx - tri_offset);
const float3 *vpos = &mesh->verts[0];
triangle.bounds_grow(vpos, bbox);
diff --git a/intern/cycles/bvh/bvh_build.cpp b/intern/cycles/bvh/bvh_build.cpp
index 76a1bfa2bfe..d00de007b2d 100644
--- a/intern/cycles/bvh/bvh_build.cpp
+++ b/intern/cycles/bvh/bvh_build.cpp
@@ -117,8 +117,9 @@ void BVHBuild::add_reference_mesh(BoundBox& root, BoundBox& center, Mesh *mesh,
if(mesh->has_motion_blur())
attr_mP = mesh->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION);
- for(uint j = 0; j < mesh->triangles.size(); j++) {
- Mesh::Triangle t = mesh->triangles[j];
+ size_t num_triangles = mesh->num_triangles();
+ for(uint j = 0; j < num_triangles; j++) {
+ Mesh::Triangle t = mesh->get_triangle(j);
BoundBox bounds = BoundBox::empty;
PrimitiveType type = PRIMITIVE_TRIANGLE;
@@ -148,22 +149,23 @@ void BVHBuild::add_reference_mesh(BoundBox& root, BoundBox& center, Mesh *mesh,
if(mesh->has_motion_blur())
curve_attr_mP = mesh->curve_attributes.find(ATTR_STD_MOTION_VERTEX_POSITION);
- for(uint j = 0; j < mesh->curves.size(); j++) {
- Mesh::Curve curve = mesh->curves[j];
+ size_t num_curves = mesh->num_curves();
+ for(uint j = 0; j < num_curves; j++) {
+ Mesh::Curve curve = mesh->get_curve(j);
PrimitiveType type = PRIMITIVE_CURVE;
for(int k = 0; k < curve.num_keys - 1; k++) {
BoundBox bounds = BoundBox::empty;
- curve.bounds_grow(k, &mesh->curve_keys[0], bounds);
+ curve.bounds_grow(k, &mesh->curve_keys[0], &mesh->curve_radius[0], bounds);
/* motion curve */
if(curve_attr_mP) {
size_t mesh_size = mesh->curve_keys.size();
size_t steps = mesh->motion_steps - 1;
- float4 *key_steps = curve_attr_mP->data_float4();
+ float3 *key_steps = curve_attr_mP->data_float3();
for(size_t i = 0; i < steps; i++)
- curve.bounds_grow(k, key_steps + i*mesh_size, bounds);
+ curve.bounds_grow(k, key_steps + i*mesh_size, &mesh->curve_radius[0], bounds);
type = PRIMITIVE_MOTION_CURVE;
}
@@ -188,10 +190,10 @@ void BVHBuild::add_reference_object(BoundBox& root, BoundBox& center, Object *ob
static size_t count_curve_segments(Mesh *mesh)
{
- size_t num = 0, num_curves = mesh->curves.size();
+ size_t num = 0, num_curves = mesh->num_curves();
for(size_t i = 0; i < num_curves; i++)
- num += mesh->curves[i].num_keys - 1;
+ num += mesh->get_curve(i).num_keys - 1;
return num;
}
@@ -203,15 +205,18 @@ void BVHBuild::add_references(BVHRange& root)
foreach(Object *ob, objects) {
if(params.top_level) {
+ if(!ob->is_traceable()) {
+ continue;
+ }
if(!ob->mesh->is_instanced()) {
- num_alloc_references += ob->mesh->triangles.size();
+ num_alloc_references += ob->mesh->num_triangles();
num_alloc_references += count_curve_segments(ob->mesh);
}
else
num_alloc_references++;
}
else {
- num_alloc_references += ob->mesh->triangles.size();
+ num_alloc_references += ob->mesh->num_triangles();
num_alloc_references += count_curve_segments(ob->mesh);
}
}
@@ -224,6 +229,9 @@ void BVHBuild::add_references(BVHRange& root)
foreach(Object *ob, objects) {
if(params.top_level) {
+ if(!ob->is_traceable()) {
+ continue;
+ }
if(!ob->mesh->is_instanced())
add_reference_mesh(bounds, center, ob->mesh, i);
else
@@ -326,11 +334,11 @@ BVHNode* BVHBuild::run()
VLOG(1) << "BVH build statistics:\n"
<< " Build time: " << time_dt() - build_start_time << "\n"
<< " Total number of nodes: "
- << rootnode->getSubtreeSize(BVH_STAT_NODE_COUNT) << "\n"
+ << string_human_readable_number(rootnode->getSubtreeSize(BVH_STAT_NODE_COUNT)) << "\n"
<< " Number of inner nodes: "
- << rootnode->getSubtreeSize(BVH_STAT_INNER_COUNT) << "\n"
+ << string_human_readable_number(rootnode->getSubtreeSize(BVH_STAT_INNER_COUNT)) << "\n"
<< " Number of leaf nodes: "
- << rootnode->getSubtreeSize(BVH_STAT_LEAF_COUNT) << "\n"
+ << string_human_readable_number(rootnode->getSubtreeSize(BVH_STAT_LEAF_COUNT)) << "\n"
<< " Allocation slop factor: "
<< ((prim_type.capacity() != 0)
? (float)prim_type.size() / prim_type.capacity()
diff --git a/intern/cycles/bvh/bvh_split.cpp b/intern/cycles/bvh/bvh_split.cpp
index 8084975565e..bf68b41021f 100644
--- a/intern/cycles/bvh/bvh_split.cpp
+++ b/intern/cycles/bvh/bvh_split.cpp
@@ -292,13 +292,13 @@ void BVHSpatialSplit::split_triangle_primitive(const Mesh *mesh,
BoundBox& left_bounds,
BoundBox& right_bounds)
{
- const int *inds = mesh->triangles[prim_index].v;
+ Mesh::Triangle t = mesh->get_triangle(prim_index);
const float3 *verts = &mesh->verts[0];
- float3 v1 = tfm ? transform_point(tfm, verts[inds[2]]) : verts[inds[2]];
+ float3 v1 = tfm ? transform_point(tfm, verts[t.v[2]]) : verts[t.v[2]];
for(int i = 0; i < 3; i++) {
float3 v0 = v1;
- int vindex = inds[i];
+ int vindex = t.v[i];
v1 = tfm ? transform_point(tfm, verts[vindex]) : verts[vindex];
float v0p = v0[dim];
float v1p = v1[dim];
@@ -329,12 +329,11 @@ void BVHSpatialSplit::split_curve_primitive(const Mesh *mesh,
BoundBox& right_bounds)
{
/* curve split: NOTE - Currently ignores curve width and needs to be fixed.*/
- const int k0 = mesh->curves[prim_index].first_key + segment_index;
+ Mesh::Curve curve = mesh->get_curve(prim_index);
+ const int k0 = curve.first_key + segment_index;
const int k1 = k0 + 1;
- const float4& key0 = mesh->curve_keys[k0];
- const float4& key1 = mesh->curve_keys[k1];
- float3 v0 = float4_to_float3(key0);
- float3 v1 = float4_to_float3(key1);
+ float3 v0 = mesh->curve_keys[k0];
+ float3 v1 = mesh->curve_keys[k1];
if(tfm != NULL) {
v0 = transform_point(tfm, v0);
@@ -405,7 +404,7 @@ void BVHSpatialSplit::split_object_reference(const Object *object,
BoundBox& right_bounds)
{
Mesh *mesh = object->mesh;
- for(int tri_idx = 0; tri_idx < mesh->triangles.size(); ++tri_idx) {
+ for(int tri_idx = 0; tri_idx < mesh->num_triangles(); ++tri_idx) {
split_triangle_primitive(mesh,
&object->tfm,
tri_idx,
@@ -414,8 +413,8 @@ void BVHSpatialSplit::split_object_reference(const Object *object,
left_bounds,
right_bounds);
}
- for(int curve_idx = 0; curve_idx < mesh->curves.size(); ++curve_idx) {
- Mesh::Curve &curve = mesh->curves[curve_idx];
+ for(int curve_idx = 0; curve_idx < mesh->num_curves(); ++curve_idx) {
+ Mesh::Curve curve = mesh->get_curve(curve_idx);
for(int segment_idx = 0;
segment_idx < curve.num_keys - 1;
++segment_idx)
diff --git a/intern/cycles/device/device_cpu.cpp b/intern/cycles/device/device_cpu.cpp
index 275ee028eb4..aed86d8d853 100644
--- a/intern/cycles/device/device_cpu.cpp
+++ b/intern/cycles/device/device_cpu.cpp
@@ -155,7 +155,9 @@ public:
InterpolationType interpolation,
ExtensionType extension)
{
- VLOG(1) << "Texture allocate: " << name << ", " << mem.memory_size() << " bytes.";
+ VLOG(1) << "Texture allocate: " << name << ", "
+ << string_human_readable_number(mem.memory_size()) << " bytes. ("
+ << string_human_readable_size(mem.memory_size()) << ")";
kernel_tex_copy(&kernel_globals,
name,
mem.data_pointer,
diff --git a/intern/cycles/device/device_cuda.cpp b/intern/cycles/device/device_cuda.cpp
index 9a78d055580..2d404918a38 100644
--- a/intern/cycles/device/device_cuda.cpp
+++ b/intern/cycles/device/device_cuda.cpp
@@ -493,7 +493,9 @@ public:
InterpolationType interpolation,
ExtensionType extension)
{
- VLOG(1) << "Texture allocate: " << name << ", " << mem.memory_size() << " bytes.";
+ VLOG(1) << "Texture allocate: " << name << ", "
+ << string_human_readable_number(mem.memory_size()) << " bytes. ("
+ << string_human_readable_size(mem.memory_size()) << ")";
/* Check if we are on sm_30 or above.
* We use arrays and bindles textures for storage there */
@@ -1366,6 +1368,7 @@ void device_cuda_info(vector<DeviceInfo>& devices)
/* if device has a kernel timeout, assume it is used for display */
if(cuDeviceGetAttribute(&attr, CU_DEVICE_ATTRIBUTE_KERNEL_EXEC_TIMEOUT, num) == CUDA_SUCCESS && attr == 1) {
+ info.description += " (Display)";
info.display_device = true;
display_devices.push_back(info);
}
diff --git a/intern/cycles/device/device_multi.cpp b/intern/cycles/device/device_multi.cpp
index 434d0085d39..c4f8d9e16e0 100644
--- a/intern/cycles/device/device_multi.cpp
+++ b/intern/cycles/device/device_multi.cpp
@@ -175,7 +175,9 @@ public:
interpolation,
ExtensionType extension)
{
- VLOG(1) << "Texture allocate: " << name << ", " << mem.memory_size() << " bytes.";
+ VLOG(1) << "Texture allocate: " << name << ", "
+ << string_human_readable_number(mem.memory_size()) << " bytes. ("
+ << string_human_readable_size(mem.memory_size()) << ")";
foreach(SubDevice& sub, devices) {
mem.device_pointer = 0;
diff --git a/intern/cycles/device/device_network.cpp b/intern/cycles/device/device_network.cpp
index cf4a05de8fc..3eb5ad2d2db 100644
--- a/intern/cycles/device/device_network.cpp
+++ b/intern/cycles/device/device_network.cpp
@@ -168,7 +168,9 @@ public:
InterpolationType interpolation,
ExtensionType extension)
{
- VLOG(1) << "Texture allocate: " << name << ", " << mem.memory_size() << " bytes.";
+ VLOG(1) << "Texture allocate: " << name << ", "
+ << string_human_readable_number(mem.memory_size()) << " bytes. ("
+ << string_human_readable_size(mem.memory_size()) << ")";
thread_scoped_lock lock(rpc_lock);
diff --git a/intern/cycles/device/device_opencl.cpp b/intern/cycles/device/device_opencl.cpp
index 1b4e5421b5a..afe21c49730 100644
--- a/intern/cycles/device/device_opencl.cpp
+++ b/intern/cycles/device/device_opencl.cpp
@@ -1187,7 +1187,9 @@ public:
InterpolationType /*interpolation*/,
ExtensionType /*extension*/)
{
- VLOG(1) << "Texture allocate: " << name << ", " << mem.memory_size() << " bytes.";
+ VLOG(1) << "Texture allocate: " << name << ", "
+ << string_human_readable_number(mem.memory_size()) << " bytes. ("
+ << string_human_readable_size(mem.memory_size()) << ")";
mem_alloc(mem, MEM_READ_ONLY);
mem_copy_to(mem);
assert(mem_map.find(name) == mem_map.end());
@@ -1222,18 +1224,28 @@ public:
CL_KERNEL_WORK_GROUP_SIZE, sizeof(size_t), &workgroup_size, NULL);
clGetDeviceInfo(cdDevice,
CL_DEVICE_MAX_WORK_ITEM_SIZES, sizeof(size_t)*3, max_work_items, NULL);
-
- /* try to divide evenly over 2 dimensions */
+
+ /* Try to divide evenly over 2 dimensions. */
size_t sqrt_workgroup_size = max((size_t)sqrt((double)workgroup_size), 1);
size_t local_size[2] = {sqrt_workgroup_size, sqrt_workgroup_size};
- /* some implementations have max size 1 on 2nd dimension */
+ /* Some implementations have max size 1 on 2nd dimension. */
if(local_size[1] > max_work_items[1]) {
local_size[0] = workgroup_size/max_work_items[1];
local_size[1] = max_work_items[1];
}
- size_t global_size[2] = {global_size_round_up(local_size[0], w), global_size_round_up(local_size[1], h)};
+ size_t global_size[2] = {global_size_round_up(local_size[0], w),
+ global_size_round_up(local_size[1], h)};
+
+ /* Vertical size of 1 is coming from bake/shade kernels where we should
+ * not round anything up because otherwise we'll either be doing too
+ * much work per pixel (if we don't check global ID on Y axis) or will
+ * be checking for global ID to always have Y of 0.
+ */
+ if (h == 1) {
+ global_size[h] = 1;
+ }
/* run kernel */
opencl_assert(clEnqueueNDRangeKernel(cqCommandQueue, kernel, 2, NULL, global_size, NULL, 0, NULL, NULL));
@@ -1318,48 +1330,49 @@ public:
else
kernel = ckShaderKernel;
- for(int sample = 0; sample < task.num_samples; sample++) {
-
- if(task.get_cancel())
- break;
-
- cl_int d_sample = sample;
-
- cl_uint start_arg_index =
- kernel_set_args(kernel,
- 0,
- d_data,
- d_input,
- d_output);
+ cl_uint start_arg_index =
+ kernel_set_args(kernel,
+ 0,
+ d_data,
+ d_input,
+ d_output);
- if(task.shader_eval_type < SHADER_EVAL_BAKE) {
- start_arg_index += kernel_set_args(kernel,
- start_arg_index,
- d_output_luma);
- }
+ if(task.shader_eval_type < SHADER_EVAL_BAKE) {
+ start_arg_index += kernel_set_args(kernel,
+ start_arg_index,
+ d_output_luma);
+ }
#define KERNEL_TEX(type, ttype, name) \
- set_kernel_arg_mem(kernel, &start_arg_index, #name);
+ set_kernel_arg_mem(kernel, &start_arg_index, #name);
#include "kernel_textures.h"
#undef KERNEL_TEX
+ start_arg_index += kernel_set_args(kernel,
+ start_arg_index,
+ d_shader_eval_type);
+ if(task.shader_eval_type >= SHADER_EVAL_BAKE) {
start_arg_index += kernel_set_args(kernel,
start_arg_index,
- d_shader_eval_type);
- if(task.shader_eval_type >= SHADER_EVAL_BAKE) {
- start_arg_index += kernel_set_args(kernel,
- start_arg_index,
- d_shader_filter);
- }
- start_arg_index += kernel_set_args(kernel,
- start_arg_index,
- d_shader_x,
- d_shader_w,
- d_offset,
- d_sample);
+ d_shader_filter);
+ }
+ start_arg_index += kernel_set_args(kernel,
+ start_arg_index,
+ d_shader_x,
+ d_shader_w,
+ d_offset);
+
+ for(int sample = 0; sample < task.num_samples; sample++) {
+
+ if(task.get_cancel())
+ break;
+
+ kernel_set_args(kernel, start_arg_index, sample);
enqueue_kernel(kernel, task.shader_w, 1);
+ clFinish(cqCommandQueue);
+
task.update_progress(NULL);
}
}
diff --git a/intern/cycles/graph/node.cpp b/intern/cycles/graph/node.cpp
index d482577b73b..941a66741c5 100644
--- a/intern/cycles/graph/node.cpp
+++ b/intern/cycles/graph/node.cpp
@@ -36,12 +36,8 @@ Node::Node(const NodeType *type_, ustring name_)
}
/* initialize default values */
- typedef unordered_map<ustring, SocketType, ustringHash> map_type;
- foreach(const map_type::value_type& it, type->inputs) {
- const SocketType& socket = it.second;
- const void *src = socket.default_value;
- void *dst = ((char*)this) + socket.struct_offset;
- memcpy(dst, src, socket.size());
+ foreach(const SocketType& socket, type->inputs) {
+ set_default_value(socket);
}
}
@@ -104,6 +100,11 @@ void Node::set(const SocketType& input, float3 value)
get_socket_value<float3>(this, input) = value;
}
+void Node::set(const SocketType& input, const char *value)
+{
+ set(input, ustring(value));
+}
+
void Node::set(const SocketType& input, ustring value)
{
if(input.type == SocketType::STRING) {
@@ -292,7 +293,8 @@ const array<Node*>& Node::get_node_array(const SocketType& input) const
return get_socket_value<array<Node*> >(this, input);
}
-/* default values */
+/* generic value operations */
+
bool Node::has_default_value(const SocketType& input) const
{
const void *src = input.default_value;
@@ -300,6 +302,48 @@ bool Node::has_default_value(const SocketType& input) const
return memcmp(dst, src, input.size()) == 0;
}
+void Node::set_default_value(const SocketType& socket)
+{
+ const void *src = socket.default_value;
+ void *dst = ((char*)this) + socket.struct_offset;
+ memcpy(dst, src, socket.size());
+}
+
+template<typename T>
+static void copy_array(const Node *node, const SocketType& socket, const Node *other, const SocketType& other_socket)
+{
+ const array<T>* src = (const array<T>*)(((char*)other) + other_socket.struct_offset);
+ array<T>* dst = (array<T>*)(((char*)node) + socket.struct_offset);
+ *dst = *src;
+}
+
+void Node::copy_value(const SocketType& socket, const Node& other, const SocketType& other_socket)
+{
+ assert(socket.type == other_socket.type);
+
+ if(socket.is_array()) {
+ switch(socket.type) {
+ case SocketType::BOOLEAN_ARRAY: copy_array<bool>(this, socket, &other, other_socket); break;
+ case SocketType::FLOAT_ARRAY: copy_array<float>(this, socket, &other, other_socket); break;
+ case SocketType::INT_ARRAY: copy_array<int>(this, socket, &other, other_socket); break;
+ case SocketType::COLOR_ARRAY: copy_array<float3>(this, socket, &other, other_socket); break;
+ case SocketType::VECTOR_ARRAY: copy_array<float3>(this, socket, &other, other_socket); break;
+ case SocketType::POINT_ARRAY: copy_array<float3>(this, socket, &other, other_socket); break;
+ case SocketType::NORMAL_ARRAY: copy_array<float3>(this, socket, &other, other_socket); break;
+ case SocketType::POINT2_ARRAY: copy_array<float2>(this, socket, &other, other_socket); break;
+ case SocketType::STRING_ARRAY: copy_array<ustring>(this, socket, &other, other_socket); break;
+ case SocketType::TRANSFORM_ARRAY: copy_array<Transform>(this, socket, &other, other_socket); break;
+ case SocketType::NODE_ARRAY: copy_array<void*>(this, socket, &other, other_socket); break;
+ default: assert(0); break;
+ }
+ }
+ else {
+ const void *src = ((char*)&other) + other_socket.struct_offset;
+ void *dst = ((char*)this) + socket.struct_offset;
+ memcpy(dst, src, socket.size());
+ }
+}
+
template<typename T>
static bool is_array_equal(const Node *node, const Node *other, const SocketType& socket)
{
@@ -308,48 +352,43 @@ static bool is_array_equal(const Node *node, const Node *other, const SocketType
return *a == *b;
}
-/* modified */
-bool Node::modified(const Node& other)
+bool Node::equals_value(const Node& other, const SocketType& socket) const
+{
+ if(socket.is_array()) {
+ switch(socket.type) {
+ case SocketType::BOOLEAN_ARRAY: return is_array_equal<bool>(this, &other, socket);
+ case SocketType::FLOAT_ARRAY: return is_array_equal<float>(this, &other, socket);
+ case SocketType::INT_ARRAY: return is_array_equal<int>(this, &other, socket);
+ case SocketType::COLOR_ARRAY: return is_array_equal<float3>(this, &other, socket);
+ case SocketType::VECTOR_ARRAY: return is_array_equal<float3>(this, &other, socket);
+ case SocketType::POINT_ARRAY: return is_array_equal<float3>(this, &other, socket);
+ case SocketType::NORMAL_ARRAY: return is_array_equal<float3>(this, &other, socket);
+ case SocketType::POINT2_ARRAY: return is_array_equal<float2>(this, &other, socket);
+ case SocketType::STRING_ARRAY: return is_array_equal<ustring>(this, &other, socket);
+ case SocketType::TRANSFORM_ARRAY: return is_array_equal<Transform>(this, &other, socket);
+ case SocketType::NODE_ARRAY: return is_array_equal<void*>(this, &other, socket);
+ default: assert(0); return true;
+ }
+ }
+ else {
+ const void *a = ((char*)this) + socket.struct_offset;
+ const void *b = ((char*)&other) + socket.struct_offset;
+ return (memcmp(a, b, socket.size()) == 0);
+ }
+}
+
+/* equals */
+
+bool Node::equals(const Node& other) const
{
assert(type == other.type);
- typedef unordered_map<ustring, SocketType, ustringHash> map_type;
- foreach(const map_type::value_type& it, type->inputs) {
- const SocketType& socket = it.second;
-
- if(socket.is_array()) {
- bool equal = true;
-
- switch(socket.type)
- {
- case SocketType::BOOLEAN_ARRAY: equal = is_array_equal<bool>(this, &other, socket); break;
- case SocketType::FLOAT_ARRAY: equal = is_array_equal<float>(this, &other, socket); break;
- case SocketType::INT_ARRAY: equal = is_array_equal<int>(this, &other, socket); break;
- case SocketType::COLOR_ARRAY: equal = is_array_equal<float3>(this, &other, socket); break;
- case SocketType::VECTOR_ARRAY: equal = is_array_equal<float3>(this, &other, socket); break;
- case SocketType::POINT_ARRAY: equal = is_array_equal<float3>(this, &other, socket); break;
- case SocketType::NORMAL_ARRAY: equal = is_array_equal<float3>(this, &other, socket); break;
- case SocketType::POINT2_ARRAY: equal = is_array_equal<float2>(this, &other, socket); break;
- case SocketType::STRING_ARRAY: equal = is_array_equal<ustring>(this, &other, socket); break;
- case SocketType::TRANSFORM_ARRAY: equal = is_array_equal<Transform>(this, &other, socket); break;
- case SocketType::NODE_ARRAY: equal = is_array_equal<void*>(this, &other, socket); break;
- default: assert(0); break;
- }
-
- if(!equal) {
- return true;
- }
- }
- else {
- const void *a = ((char*)this) + socket.struct_offset;
- const void *b = ((char*)&other) + socket.struct_offset;
- if(memcmp(a, b, socket.size()) != 0) {
- return true;
- }
- }
+ foreach(const SocketType& socket, type->inputs) {
+ if(!equals_value(other, socket))
+ return false;
}
- return false;
+ return true;
}
CCL_NAMESPACE_END
diff --git a/intern/cycles/graph/node.h b/intern/cycles/graph/node.h
index 33971fa714a..bb84f982fb3 100644
--- a/intern/cycles/graph/node.h
+++ b/intern/cycles/graph/node.h
@@ -41,6 +41,7 @@ struct Node
void set(const SocketType& input, float value);
void set(const SocketType& input, float2 value);
void set(const SocketType& input, float3 value);
+ void set(const SocketType& input, const char *value);
void set(const SocketType& input, ustring value);
void set(const SocketType& input, const Transform& value);
void set(const SocketType& input, Node *value);
@@ -76,11 +77,14 @@ struct Node
const array<Transform>& get_transform_array(const SocketType& input) const;
const array<Node*>& get_node_array(const SocketType& input) const;
- /* default values */
+ /* generic values operations */
bool has_default_value(const SocketType& input) const;
+ void set_default_value(const SocketType& input);
+ bool equals_value(const Node& other, const SocketType& input) const;
+ void copy_value(const SocketType& input, const Node& other, const SocketType& other_input);
- /* modified */
- bool modified(const Node& other);
+ /* equals */
+ bool equals(const Node& other) const;
ustring name;
const NodeType *type;
diff --git a/intern/cycles/graph/node_type.cpp b/intern/cycles/graph/node_type.cpp
index dc879655d7f..7f68ae9c7c7 100644
--- a/intern/cycles/graph/node_type.cpp
+++ b/intern/cycles/graph/node_type.cpp
@@ -114,9 +114,15 @@ ustring SocketType::type_name(Type type)
return names[(int)type];
}
+bool SocketType::is_float3(Type type)
+{
+ return (type == COLOR || type == VECTOR || type == POINT || type == NORMAL);
+}
+
/* Node Type */
-NodeType::NodeType()
+NodeType::NodeType(Type type_)
+: type(type_)
{
}
@@ -137,7 +143,7 @@ void NodeType::register_input(ustring name, ustring ui_name, SocketType::Type ty
socket.enum_values = enum_values;
socket.node_type = node_type;
socket.flags = flags | extra_flags;
- inputs[name] = socket;
+ inputs.push_back(socket);
}
void NodeType::register_output(ustring name, ustring ui_name, SocketType::Type type)
@@ -151,7 +157,29 @@ void NodeType::register_output(ustring name, ustring ui_name, SocketType::Type t
socket.enum_values = NULL;
socket.node_type = NULL;
socket.flags = SocketType::LINKABLE;
- outputs[name] = socket;
+ outputs.push_back(socket);
+}
+
+const SocketType *NodeType::find_input(ustring name) const
+{
+ foreach(const SocketType& socket, inputs) {
+ if(socket.name == name) {
+ return &socket;
+ }
+ }
+
+ return NULL;
+}
+
+const SocketType *NodeType::find_output(ustring name) const
+{
+ foreach(const SocketType& socket, outputs) {
+ if(socket.name == name) {
+ return &socket;
+ }
+ }
+
+ return NULL;
}
/* Node Type Registry */
@@ -162,7 +190,7 @@ unordered_map<ustring, NodeType, ustringHash>& NodeType::types()
return _types;
}
-NodeType *NodeType::add(const char *name_, CreateFunc create_)
+NodeType *NodeType::add(const char *name_, CreateFunc create_, Type type_)
{
ustring name(name_);
@@ -172,7 +200,7 @@ NodeType *NodeType::add(const char *name_, CreateFunc create_)
return NULL;
}
- types()[name] = NodeType();
+ types()[name] = NodeType(type_);
NodeType *type = &types()[name];
type->name = name;
diff --git a/intern/cycles/graph/node_type.h b/intern/cycles/graph/node_type.h
index 82ddd29da33..20816f634cd 100644
--- a/intern/cycles/graph/node_type.h
+++ b/intern/cycles/graph/node_type.h
@@ -21,6 +21,7 @@
#include "util_map.h"
#include "util_param.h"
#include "util_string.h"
+#include "util_vector.h"
CCL_NAMESPACE_BEGIN
@@ -94,13 +95,19 @@ struct SocketType
static size_t max_size();
static ustring type_name(Type type);
static void *zero_default_value();
+ static bool is_float3(Type type);
};
/* Node Type */
struct NodeType
{
- explicit NodeType();
+ enum Type {
+ NONE,
+ SHADER
+ };
+
+ explicit NodeType(Type type = NONE);
~NodeType();
void register_input(ustring name, ustring ui_name, SocketType::Type type,
@@ -110,15 +117,18 @@ struct NodeType
int flags = 0, int extra_flags = 0);
void register_output(ustring name, ustring ui_name, SocketType::Type type);
+ const SocketType *find_input(ustring name) const;
+ const SocketType *find_output(ustring name) const;
+
typedef Node *(*CreateFunc)(const NodeType *type);
- typedef unordered_map<ustring, SocketType, ustringHash> SocketMap;
ustring name;
- SocketMap inputs;
- SocketMap outputs;
+ Type type;
+ std::vector<SocketType> inputs;
+ std::vector<SocketType> outputs;
CreateFunc create;
- static NodeType *add(const char *name, CreateFunc create);
+ static NodeType *add(const char *name, CreateFunc create, Type type = NONE);
static const NodeType *find(ustring name);
static unordered_map<ustring, NodeType, ustringHash>& types();
};
diff --git a/intern/cycles/graph/node_xml.cpp b/intern/cycles/graph/node_xml.cpp
index fe06a243998..022de7cf32a 100644
--- a/intern/cycles/graph/node_xml.cpp
+++ b/intern/cycles/graph/node_xml.cpp
@@ -58,9 +58,7 @@ void xml_read_node(XMLReader& reader, Node *node, pugi::xml_node xml_node)
node->name = ustring(name_attr.value());
}
- foreach(const NodeType::SocketMap::value_type& it, node->type->inputs) {
- const SocketType& socket = it.second;
-
+ foreach(const SocketType& socket, node->type->inputs) {
if(socket.type == SocketType::CLOSURE || socket.type == SocketType::UNDEFINED) {
continue;
}
@@ -117,8 +115,9 @@ void xml_read_node(XMLReader& reader, Node *node, pugi::xml_node xml_node)
array<int> value;
value.resize(tokens.size());
- for(size_t i = 0; i < value.size(); i++)
+ for(size_t i = 0; i < value.size(); i++) {
value[i] = (int)atoi(attr.value());
+ }
node->set(socket, value);
break;
}
@@ -127,7 +126,7 @@ void xml_read_node(XMLReader& reader, Node *node, pugi::xml_node xml_node)
case SocketType::POINT:
case SocketType::NORMAL:
{
- array<float> value;
+ array<float3> value;
xml_read_float_array<3>(value, attr);
if(value.size() == 1) {
node->set(socket, value[0]);
@@ -161,11 +160,21 @@ void xml_read_node(XMLReader& reader, Node *node, pugi::xml_node xml_node)
break;
}
case SocketType::STRING:
- case SocketType::ENUM:
{
node->set(socket, attr.value());
break;
}
+ case SocketType::ENUM:
+ {
+ ustring value(attr.value());
+ if(socket.enum_values->exists(value)) {
+ node->set(socket, value);
+ }
+ else {
+ fprintf(stderr, "Unknown value \"%s\" for attribute \"%s\".\n", value.c_str(), socket.name.c_str());
+ }
+ break;
+ }
case SocketType::STRING_ARRAY:
{
vector<string> tokens;
@@ -173,8 +182,9 @@ void xml_read_node(XMLReader& reader, Node *node, pugi::xml_node xml_node)
array<ustring> value;
value.resize(tokens.size());
- for(size_t i = 0; i < value.size(); i++)
+ for(size_t i = 0; i < value.size(); i++) {
value[i] = ustring(tokens[i]);
+ }
node->set(socket, value);
break;
}
@@ -245,9 +255,7 @@ pugi::xml_node xml_write_node(Node *node, pugi::xml_node xml_root)
xml_node.append_attribute("name") = node->name.c_str();
- foreach(const NodeType::SocketMap::value_type& it, node->type->inputs) {
- const SocketType& socket = it.second;
-
+ foreach(const SocketType& socket, node->type->inputs) {
if(socket.type == SocketType::CLOSURE || socket.type == SocketType::UNDEFINED) {
continue;
}
diff --git a/intern/cycles/kernel/CMakeLists.txt b/intern/cycles/kernel/CMakeLists.txt
index 7c2fc1e4b14..61c484df094 100644
--- a/intern/cycles/kernel/CMakeLists.txt
+++ b/intern/cycles/kernel/CMakeLists.txt
@@ -234,6 +234,7 @@ if(WITH_CYCLES_CUDA_BINARIES)
OUTPUT ${cuda_cubin}
COMMAND ${CUDA_NVCC_EXECUTABLE}
-arch=${arch}
+ ${CUDA_NVCC_FLAGS}
-m${CUDA_BITS}
--cubin ${CMAKE_CURRENT_SOURCE_DIR}/kernels/cuda/kernel.cu
-o ${CMAKE_CURRENT_BINARY_DIR}/${cuda_cubin}
diff --git a/intern/cycles/kernel/geom/geom_bvh.h b/intern/cycles/kernel/geom/geom_bvh.h
index 9eadc97386c..d0eedd3396a 100644
--- a/intern/cycles/kernel/geom/geom_bvh.h
+++ b/intern/cycles/kernel/geom/geom_bvh.h
@@ -48,6 +48,28 @@ CCL_NAMESPACE_BEGIN
#define BVH_FEATURE(f) (((BVH_FUNCTION_FEATURES) & (f)) != 0)
+/* Debugging heleprs */
+#ifdef __KERNEL_DEBUG__
+# define BVH_DEBUG_INIT() \
+ do { \
+ isect->num_traversal_steps = 0; \
+ isect->num_traversed_instances = 0; \
+ } while(0)
+# define BVH_DEBUG_NEXT_STEP() \
+ do { \
+ ++isect->num_traversal_steps; \
+ } while(0)
+# define BVH_DEBUG_NEXT_INSTANCE() \
+ do { \
+ ++isect->num_traversed_instances; \
+ } while(0)
+#else /* __KERNEL_DEBUG__ */
+# define BVH_DEBUG_INIT()
+# define BVH_DEBUG_NEXT_STEP()
+# define BVH_DEBUG_NEXT_INSTANCE()
+#endif /* __KERNEL_DEBUG__ */
+
+
/* Common QBVH functions. */
#ifdef __QBVH__
# include "geom_qbvh.h"
diff --git a/intern/cycles/kernel/geom/geom_bvh_traversal.h b/intern/cycles/kernel/geom/geom_bvh_traversal.h
index 8560612addc..ae919ef3f86 100644
--- a/intern/cycles/kernel/geom/geom_bvh_traversal.h
+++ b/intern/cycles/kernel/geom/geom_bvh_traversal.h
@@ -74,10 +74,7 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg,
isect->prim = PRIM_NONE;
isect->object = OBJECT_NONE;
-#if defined(__KERNEL_DEBUG__)
- isect->num_traversal_steps = 0;
- isect->num_traversed_instances = 0;
-#endif
+ BVH_DEBUG_INIT();
#if defined(__KERNEL_SSE2__)
const shuffle_swap_t shuf_identity = shuffle_swap_identity();
@@ -241,10 +238,7 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg,
--stackPtr;
}
}
-
-#if defined(__KERNEL_DEBUG__)
- isect->num_traversal_steps++;
-#endif
+ BVH_DEBUG_NEXT_STEP();
}
/* if node is leaf, fetch triangle list */
@@ -266,9 +260,7 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg,
switch(type & PRIMITIVE_ALL) {
case PRIMITIVE_TRIANGLE: {
for(; primAddr < primAddr2; primAddr++) {
-#if defined(__KERNEL_DEBUG__)
- isect->num_traversal_steps++;
-#endif
+ BVH_DEBUG_NEXT_STEP();
kernel_assert(kernel_tex_fetch(__prim_type, primAddr) == type);
if(triangle_intersect(kg, &isect_precalc, isect, P, visibility, object, primAddr)) {
/* shadow ray early termination */
@@ -287,9 +279,7 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg,
#if BVH_FEATURE(BVH_MOTION)
case PRIMITIVE_MOTION_TRIANGLE: {
for(; primAddr < primAddr2; primAddr++) {
-# if defined(__KERNEL_DEBUG__)
- isect->num_traversal_steps++;
-# endif
+ BVH_DEBUG_NEXT_STEP();
kernel_assert(kernel_tex_fetch(__prim_type, primAddr) == type);
if(motion_triangle_intersect(kg, isect, P, dir, ray->time, visibility, object, primAddr)) {
/* shadow ray early termination */
@@ -310,9 +300,7 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg,
case PRIMITIVE_CURVE:
case PRIMITIVE_MOTION_CURVE: {
for(; primAddr < primAddr2; primAddr++) {
-# if defined(__KERNEL_DEBUG__)
- isect->num_traversal_steps++;
-# endif
+ BVH_DEBUG_NEXT_STEP();
kernel_assert(kernel_tex_fetch(__prim_type, primAddr) == type);
bool hit;
if(kernel_data.curve.curveflags & CURVE_KN_INTERPOLATE)
@@ -364,9 +352,7 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg,
nodeAddr = kernel_tex_fetch(__object_node, object);
-# if defined(__KERNEL_DEBUG__)
- isect->num_traversed_instances++;
-# endif
+ BVH_DEBUG_NEXT_INSTANCE();
}
}
#endif /* FEATURE(BVH_INSTANCING) */
diff --git a/intern/cycles/kernel/geom/geom_qbvh_traversal.h b/intern/cycles/kernel/geom/geom_qbvh_traversal.h
index ce3bbbdf957..738d08ac6fc 100644
--- a/intern/cycles/kernel/geom/geom_qbvh_traversal.h
+++ b/intern/cycles/kernel/geom/geom_qbvh_traversal.h
@@ -78,10 +78,7 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg,
isect->prim = PRIM_NONE;
isect->object = OBJECT_NONE;
-#if defined(__KERNEL_DEBUG__)
- isect->num_traversal_steps = 0;
- isect->num_traversed_instances = 0;
-#endif
+ BVH_DEBUG_INIT();
ssef tnear(0.0f), tfar(ray->t);
sse3f idir4(ssef(idir.x), ssef(idir.y), ssef(idir.z));
@@ -120,9 +117,7 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg,
int traverseChild;
ssef dist;
-#if defined(__KERNEL_DEBUG__)
- isect->num_traversal_steps++;
-#endif
+ BVH_DEBUG_NEXT_STEP();
#if BVH_FEATURE(BVH_HAIR_MINIMUM_WIDTH)
if(difl != 0.0f) {
@@ -295,9 +290,7 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg,
switch(type & PRIMITIVE_ALL) {
case PRIMITIVE_TRIANGLE: {
for(; primAddr < primAddr2; primAddr++) {
-#if defined(__KERNEL_DEBUG__)
- isect->num_traversal_steps++;
-#endif
+ BVH_DEBUG_NEXT_STEP();
kernel_assert(kernel_tex_fetch(__prim_type, primAddr) == type);
if(triangle_intersect(kg, &isect_precalc, isect, P, visibility, object, primAddr)) {
tfar = ssef(isect->t);
@@ -311,9 +304,7 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg,
#if BVH_FEATURE(BVH_MOTION)
case PRIMITIVE_MOTION_TRIANGLE: {
for(; primAddr < primAddr2; primAddr++) {
-# if defined(__KERNEL_DEBUG__)
- isect->num_traversal_steps++;
-# endif
+ BVH_DEBUG_NEXT_STEP();
kernel_assert(kernel_tex_fetch(__prim_type, primAddr) == type);
if(motion_triangle_intersect(kg, isect, P, dir, ray->time, visibility, object, primAddr)) {
tfar = ssef(isect->t);
@@ -329,9 +320,7 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg,
case PRIMITIVE_CURVE:
case PRIMITIVE_MOTION_CURVE: {
for(; primAddr < primAddr2; primAddr++) {
-# if defined(__KERNEL_DEBUG__)
- isect->num_traversal_steps++;
-# endif
+ BVH_DEBUG_NEXT_STEP();
kernel_assert(kernel_tex_fetch(__prim_type, primAddr) == type);
bool hit;
if(kernel_data.curve.curveflags & CURVE_KN_INTERPOLATE)
@@ -381,9 +370,7 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg,
nodeAddr = kernel_tex_fetch(__object_node, object);
-# if defined(__KERNEL_DEBUG__)
- isect->num_traversed_instances++;
-# endif
+ BVH_DEBUG_NEXT_INSTANCE();
}
}
#endif /* FEATURE(BVH_INSTANCING) */
diff --git a/intern/cycles/kernel/geom/geom_triangle_intersect.h b/intern/cycles/kernel/geom/geom_triangle_intersect.h
index d2957ad5474..b6dfc769012 100644
--- a/intern/cycles/kernel/geom/geom_triangle_intersect.h
+++ b/intern/cycles/kernel/geom/geom_triangle_intersect.h
@@ -159,16 +159,11 @@ ccl_device_inline bool triangle_intersect(KernelGlobals *kg,
if(kernel_tex_fetch(__prim_visibility, triAddr) & visibility)
#endif
{
-#ifdef __KERNEL_GPU__
- float4 a = tri_b - tri_a, b = tri_c - tri_a;
- if(len_squared(make_float3(a.y*b.z - a.z*b.y,
- a.z*b.x - a.x*b.z,
- a.x*b.y - a.y*b.x)) == 0.0f)
- {
+#ifdef __KERNEL_CUDA__
+ if(A == B && B == C) {
return false;
}
#endif
-
/* Normalize U, V, W, and T. */
const float inv_det = 1.0f / det;
isect->prim = triAddr;
diff --git a/intern/cycles/kernel/kernel_bake.h b/intern/cycles/kernel/kernel_bake.h
index 392cff9c281..8d05befe1d4 100644
--- a/intern/cycles/kernel/kernel_bake.h
+++ b/intern/cycles/kernel/kernel_bake.h
@@ -30,6 +30,9 @@ ccl_device void compute_light_pass(KernelGlobals *kg, ShaderData *sd, PathRadian
Ray ray;
float3 throughput = make_float3(1.0f, 1.0f, 1.0f);
+ /* emission and indirect shader data memory used by various functions */
+ ShaderData emission_sd, indirect_sd;
+
ray.P = sd->P + sd->Ng;
ray.D = -sd->Ng;
ray.t = FLT_MAX;
@@ -41,7 +44,7 @@ ccl_device void compute_light_pass(KernelGlobals *kg, ShaderData *sd, PathRadian
path_radiance_init(&L_sample, kernel_data.film.use_light_pass);
/* init path state */
- path_state_init(kg, &state, &rng, sample, NULL);
+ path_state_init(kg, &emission_sd, &state, &rng, sample, NULL);
/* evaluate surface shader */
float rbsdf = path_state_rng_1D(kg, &rng, &state, PRNG_BSDF);
@@ -56,7 +59,7 @@ ccl_device void compute_light_pass(KernelGlobals *kg, ShaderData *sd, PathRadian
/* sample ambient occlusion */
if(pass_filter & BAKE_FILTER_AO) {
- kernel_path_ao(kg, sd, &L_sample, &state, &rng, throughput);
+ kernel_path_ao(kg, sd, &emission_sd, &L_sample, &state, &rng, throughput);
}
/* sample emission */
@@ -75,6 +78,7 @@ ccl_device void compute_light_pass(KernelGlobals *kg, ShaderData *sd, PathRadian
kernel_path_subsurface_init_indirect(&ss_indirect);
if(kernel_path_subsurface_scatter(kg,
sd,
+ &emission_sd,
&L_sample,
&state,
&rng,
@@ -90,6 +94,8 @@ ccl_device void compute_light_pass(KernelGlobals *kg, ShaderData *sd, PathRadian
&L_sample,
&throughput);
kernel_path_indirect(kg,
+ &indirect_sd,
+ &emission_sd,
&rng,
&ray,
throughput,
@@ -105,14 +111,14 @@ ccl_device void compute_light_pass(KernelGlobals *kg, ShaderData *sd, PathRadian
/* sample light and BSDF */
if(!is_sss_sample && (pass_filter & (BAKE_FILTER_DIRECT | BAKE_FILTER_INDIRECT))) {
- kernel_path_surface_connect_light(kg, &rng, sd, throughput, &state, &L_sample);
+ kernel_path_surface_connect_light(kg, &rng, sd, &emission_sd, throughput, &state, &L_sample);
if(kernel_path_surface_bounce(kg, &rng, sd, &throughput, &state, &L_sample, &ray)) {
#ifdef __LAMP_MIS__
state.ray_t = 0.0f;
#endif
/* compute indirect light */
- kernel_path_indirect(kg, &rng, &ray, throughput, 1, &state, &L_sample);
+ kernel_path_indirect(kg, &indirect_sd, &emission_sd, &rng, &ray, throughput, 1, &state, &L_sample);
/* sum and reset indirect light pass variables for the next samples */
path_radiance_sum_indirect(&L_sample);
@@ -126,7 +132,7 @@ ccl_device void compute_light_pass(KernelGlobals *kg, ShaderData *sd, PathRadian
/* sample ambient occlusion */
if(pass_filter & BAKE_FILTER_AO) {
- kernel_branched_path_ao(kg, sd, &L_sample, &state, &rng, throughput);
+ kernel_branched_path_ao(kg, sd, &emission_sd, &L_sample, &state, &rng, throughput);
}
/* sample emission */
@@ -139,7 +145,8 @@ ccl_device void compute_light_pass(KernelGlobals *kg, ShaderData *sd, PathRadian
/* sample subsurface scattering */
if((pass_filter & BAKE_FILTER_SUBSURFACE) && (sd->flag & SD_BSSRDF)) {
/* when mixing BSSRDF and BSDF closures we should skip BSDF lighting if scattering was successful */
- kernel_branched_path_subsurface_scatter(kg, sd, &L_sample, &state, &rng, &ray, throughput);
+ kernel_branched_path_subsurface_scatter(kg, sd, &indirect_sd,
+ &emission_sd, &L_sample, &state, &rng, &ray, throughput);
}
#endif
@@ -150,13 +157,13 @@ ccl_device void compute_light_pass(KernelGlobals *kg, ShaderData *sd, PathRadian
if(kernel_data.integrator.use_direct_light) {
int all = kernel_data.integrator.sample_all_lights_direct;
kernel_branched_path_surface_connect_light(kg, &rng,
- sd, &state, throughput, 1.0f, &L_sample, all);
+ sd, &emission_sd, &state, throughput, 1.0f, &L_sample, all);
}
#endif
/* indirect light */
kernel_branched_path_surface_indirect_light(kg, &rng,
- sd, throughput, 1.0f, &state, &L_sample);
+ sd, &indirect_sd, &emission_sd, throughput, 1.0f, &state, &L_sample);
}
}
#endif
@@ -475,12 +482,10 @@ ccl_device void kernel_bake_evaluate(KernelGlobals *kg, ccl_global uint4 *input,
}
/* write output */
- float output_fac = is_aa_pass(type)? 1.0f/num_samples: 1.0f;
+ const float output_fac = is_aa_pass(type)? 1.0f/num_samples: 1.0f;
+ const float4 scaled_result = make_float4(out.x, out.y, out.z, 1.0f) * output_fac;
- if(sample == 0)
- output[i] = make_float4(out.x, out.y, out.z, 1.0f) * output_fac;
- else
- output[i] += make_float4(out.x, out.y, out.z, 1.0f) * output_fac;
+ output[i] = (sample == 0)? scaled_result: output[i] + scaled_result;
}
#endif /* __BAKING__ */
diff --git a/intern/cycles/kernel/kernel_emission.h b/intern/cycles/kernel/kernel_emission.h
index 5cf52f9d176..4de8e0f698a 100644
--- a/intern/cycles/kernel/kernel_emission.h
+++ b/intern/cycles/kernel/kernel_emission.h
@@ -18,6 +18,7 @@ CCL_NAMESPACE_BEGIN
/* Direction Emission */
ccl_device_noinline float3 direct_emissive_eval(KernelGlobals *kg,
+ ShaderData *emission_sd,
LightSample *ls,
ccl_addr_space PathState *state,
float3 I,
@@ -26,12 +27,6 @@ ccl_device_noinline float3 direct_emissive_eval(KernelGlobals *kg,
float time)
{
/* setup shading at emitter */
-#ifdef __SPLIT_KERNEL__
- ShaderData *sd = kg->sd_input;
-#else
- ShaderData sd_object;
- ShaderData *sd = &sd_object;
-#endif
float3 eval;
#ifdef __BACKGROUND_MIS__
@@ -46,28 +41,28 @@ ccl_device_noinline float3 direct_emissive_eval(KernelGlobals *kg,
ray.dP = differential3_zero();
ray.dD = dI;
- shader_setup_from_background(kg, sd, &ray);
+ shader_setup_from_background(kg, emission_sd, &ray);
path_state_modify_bounce(state, true);
- eval = shader_eval_background(kg, sd, state, 0, SHADER_CONTEXT_EMISSION);
+ eval = shader_eval_background(kg, emission_sd, state, 0, SHADER_CONTEXT_EMISSION);
path_state_modify_bounce(state, false);
}
else
#endif
{
- shader_setup_from_sample(kg, sd, ls->P, ls->Ng, I, ls->shader, ls->object, ls->prim, ls->u, ls->v, t, time);
+ shader_setup_from_sample(kg, emission_sd, ls->P, ls->Ng, I, ls->shader, ls->object, ls->prim, ls->u, ls->v, t, time);
- ls->Ng = ccl_fetch(sd, Ng);
+ ls->Ng = ccl_fetch(emission_sd, Ng);
/* no path flag, we're evaluating this for all closures. that's weak but
* we'd have to do multiple evaluations otherwise */
path_state_modify_bounce(state, true);
- shader_eval_surface(kg, sd, state, 0.0f, 0, SHADER_CONTEXT_EMISSION);
+ shader_eval_surface(kg, emission_sd, state, 0.0f, 0, SHADER_CONTEXT_EMISSION);
path_state_modify_bounce(state, false);
/* evaluate emissive closure */
- if(ccl_fetch(sd, flag) & SD_EMISSION)
- eval = shader_emissive_eval(kg, sd);
+ if(ccl_fetch(emission_sd, flag) & SD_EMISSION)
+ eval = shader_emissive_eval(kg, emission_sd);
else
eval = make_float3(0.0f, 0.0f, 0.0f);
}
@@ -79,6 +74,7 @@ ccl_device_noinline float3 direct_emissive_eval(KernelGlobals *kg,
ccl_device_noinline bool direct_emission(KernelGlobals *kg,
ShaderData *sd,
+ ShaderData *emission_sd,
LightSample *ls,
ccl_addr_space PathState *state,
Ray *ray,
@@ -94,6 +90,7 @@ ccl_device_noinline bool direct_emission(KernelGlobals *kg,
/* evaluate closure */
float3 light_eval = direct_emissive_eval(kg,
+ emission_sd,
ls,
state,
-ls->D,
@@ -198,6 +195,7 @@ ccl_device_noinline float3 indirect_primitive_emission(KernelGlobals *kg, Shader
/* Indirect Lamp Emission */
ccl_device_noinline bool indirect_lamp_emission(KernelGlobals *kg,
+ ShaderData *emission_sd,
ccl_addr_space PathState *state,
Ray *ray,
float3 *emission)
@@ -225,6 +223,7 @@ ccl_device_noinline bool indirect_lamp_emission(KernelGlobals *kg,
#endif
float3 L = direct_emissive_eval(kg,
+ emission_sd,
&ls,
state,
-ray->D,
@@ -238,7 +237,7 @@ ccl_device_noinline bool indirect_lamp_emission(KernelGlobals *kg,
Ray volume_ray = *ray;
volume_ray.t = ls.t;
float3 volume_tp = make_float3(1.0f, 1.0f, 1.0f);
- kernel_volume_shadow(kg, state, &volume_ray, &volume_tp);
+ kernel_volume_shadow(kg, emission_sd, state, &volume_ray, &volume_tp);
L *= volume_tp;
}
#endif
@@ -260,6 +259,7 @@ ccl_device_noinline bool indirect_lamp_emission(KernelGlobals *kg,
/* Indirect Background */
ccl_device_noinline float3 indirect_background(KernelGlobals *kg,
+ ShaderData *emission_sd,
ccl_addr_space PathState *state,
ccl_addr_space Ray *ray)
{
@@ -280,19 +280,14 @@ ccl_device_noinline float3 indirect_background(KernelGlobals *kg,
/* evaluate background closure */
# ifdef __SPLIT_KERNEL__
Ray priv_ray = *ray;
- shader_setup_from_background(kg, kg->sd_input, &priv_ray);
-
- path_state_modify_bounce(state, true);
- float3 L = shader_eval_background(kg, kg->sd_input, state, state->flag, SHADER_CONTEXT_EMISSION);
- path_state_modify_bounce(state, false);
+ shader_setup_from_background(kg, emission_sd, &priv_ray);
# else
- ShaderData sd;
- shader_setup_from_background(kg, &sd, ray);
+ shader_setup_from_background(kg, emission_sd, ray);
+# endif
path_state_modify_bounce(state, true);
- float3 L = shader_eval_background(kg, &sd, state, state->flag, SHADER_CONTEXT_EMISSION);
+ float3 L = shader_eval_background(kg, emission_sd, state, state->flag, SHADER_CONTEXT_EMISSION);
path_state_modify_bounce(state, false);
-# endif
#ifdef __BACKGROUND_MIS__
/* check if background light exists or if we should skip pdf */
diff --git a/intern/cycles/kernel/kernel_globals.h b/intern/cycles/kernel/kernel_globals.h
index 7e6cdf93fb9..e06c68f2fc9 100644
--- a/intern/cycles/kernel/kernel_globals.h
+++ b/intern/cycles/kernel/kernel_globals.h
@@ -35,10 +35,10 @@ struct Intersection;
struct VolumeStep;
typedef struct KernelGlobals {
- texture_image_uchar4 texture_byte4_images[TEX_NUM_BYTE4_IMAGES_CPU];
- texture_image_float4 texture_float4_images[TEX_NUM_FLOAT4_IMAGES_CPU];
- texture_image_float texture_float_images[TEX_NUM_FLOAT_IMAGES_CPU];
- texture_image_uchar texture_byte_images[TEX_NUM_BYTE_IMAGES_CPU];
+ texture_image_uchar4 texture_byte4_images[TEX_NUM_BYTE4_CPU];
+ texture_image_float4 texture_float4_images[TEX_NUM_FLOAT4_CPU];
+ texture_image_float texture_float_images[TEX_NUM_FLOAT_CPU];
+ texture_image_uchar texture_byte_images[TEX_NUM_BYTE_CPU];
# define KERNEL_TEX(type, ttype, name) ttype name;
# define KERNEL_IMAGE_TEX(type, ttype, name)
diff --git a/intern/cycles/kernel/kernel_light.h b/intern/cycles/kernel/kernel_light.h
index 675eacfc5ee..736a884f819 100644
--- a/intern/cycles/kernel/kernel_light.h
+++ b/intern/cycles/kernel/kernel_light.h
@@ -291,24 +291,13 @@ ccl_device float background_portal_pdf(KernelGlobals *kg,
}
num_possible++;
- float t = -(dot(P, dir) - dot(lightpos, dir)) / dot(direction, dir);
- if(t <= 1e-4f) {
- /* Either behind the portal or too close. */
- continue;
- }
-
float4 data1 = kernel_tex_fetch(__light_data, (p + kernel_data.integrator.portal_offset)*LIGHT_SIZE + 1);
float4 data2 = kernel_tex_fetch(__light_data, (p + kernel_data.integrator.portal_offset)*LIGHT_SIZE + 2);
float3 axisu = make_float3(data1.y, data1.z, data1.w);
float3 axisv = make_float3(data2.y, data2.z, data2.w);
- float3 hit = P + t*direction;
- float3 inplane = hit - lightpos;
- /* Skip if the the ray doesn't pass through portal. */
- if(fabsf(dot(inplane, axisu) / dot(axisu, axisu)) > 0.5f)
- continue;
- if(fabsf(dot(inplane, axisv) / dot(axisv, axisv)) > 0.5f)
+ if(!ray_quad_intersect(P, direction, 1e-4f, FLT_MAX, lightpos, axisu, axisv, dir, NULL, NULL))
continue;
portal_pdf += area_light_sample(P, &lightpos, axisu, axisv, 0.0f, 0.0f, false);
@@ -729,8 +718,8 @@ ccl_device bool lamp_light_eval(KernelGlobals *kg, int lamp, float3 P, float3 D,
float3 light_P = make_float3(data0.y, data0.z, data0.w);
- if(!ray_quad_intersect(P, D, t,
- light_P, axisu, axisv, &ls->P, &ls->t))
+ if(!ray_quad_intersect(P, D, 0.0f, t,
+ light_P, axisu, axisv, Ng, &ls->P, &ls->t))
{
return false;
}
diff --git a/intern/cycles/kernel/kernel_path.h b/intern/cycles/kernel/kernel_path.h
index c136c85df59..0dded397ffa 100644
--- a/intern/cycles/kernel/kernel_path.h
+++ b/intern/cycles/kernel/kernel_path.h
@@ -53,6 +53,8 @@
CCL_NAMESPACE_BEGIN
ccl_device void kernel_path_indirect(KernelGlobals *kg,
+ ShaderData *sd,
+ ShaderData *emission_sd,
RNG *rng,
Ray *ray,
float3 throughput,
@@ -87,7 +89,7 @@ ccl_device void kernel_path_indirect(KernelGlobals *kg,
/* intersect with lamp */
float3 emission;
- if(indirect_lamp_emission(kg, state, &light_ray, &emission)) {
+ if(indirect_lamp_emission(kg, emission_sd, state, &light_ray, &emission)) {
path_radiance_accum_emission(L,
throughput,
emission,
@@ -115,15 +117,14 @@ ccl_device void kernel_path_indirect(KernelGlobals *kg,
if(decoupled) {
/* cache steps along volume for repeated sampling */
VolumeSegment volume_segment;
- ShaderData volume_sd;
shader_setup_from_volume(kg,
- &volume_sd,
+ sd,
&volume_ray);
kernel_volume_decoupled_record(kg,
state,
&volume_ray,
- &volume_sd,
+ sd,
&volume_segment,
heterogeneous);
@@ -146,7 +147,8 @@ ccl_device void kernel_path_indirect(KernelGlobals *kg,
/* direct light sampling */
kernel_branched_path_volume_connect_light(kg,
rng,
- &volume_sd,
+ sd,
+ emission_sd,
throughput,
state,
L,
@@ -163,7 +165,7 @@ ccl_device void kernel_path_indirect(KernelGlobals *kg,
result = kernel_volume_decoupled_scatter(kg,
state,
&volume_ray,
- &volume_sd,
+ sd,
&throughput,
rphase,
rscatter,
@@ -178,7 +180,7 @@ ccl_device void kernel_path_indirect(KernelGlobals *kg,
if(result == VOLUME_PATH_SCATTERED) {
if(kernel_path_volume_bounce(kg,
rng,
- &volume_sd,
+ sd,
&throughput,
state,
L,
@@ -198,16 +200,16 @@ ccl_device void kernel_path_indirect(KernelGlobals *kg,
# endif
{
/* integrate along volume segment with distance sampling */
- ShaderData volume_sd;
VolumeIntegrateResult result = kernel_volume_integrate(
- kg, state, &volume_sd, &volume_ray, L, &throughput, rng, heterogeneous);
+ kg, state, sd, &volume_ray, L, &throughput, rng, heterogeneous);
# ifdef __VOLUME_SCATTER__
if(result == VOLUME_PATH_SCATTERED) {
/* direct lighting */
kernel_path_volume_connect_light(kg,
rng,
- &volume_sd,
+ sd,
+ emission_sd,
throughput,
state,
L);
@@ -215,7 +217,7 @@ ccl_device void kernel_path_indirect(KernelGlobals *kg,
/* indirect light bounce */
if(kernel_path_volume_bounce(kg,
rng,
- &volume_sd,
+ sd,
&throughput,
state,
L,
@@ -235,7 +237,7 @@ ccl_device void kernel_path_indirect(KernelGlobals *kg,
if(!hit) {
#ifdef __BACKGROUND__
/* sample background shader */
- float3 L_background = indirect_background(kg, state, ray);
+ float3 L_background = indirect_background(kg, emission_sd, state, ray);
path_radiance_accum_background(L,
throughput,
L_background,
@@ -246,15 +248,14 @@ ccl_device void kernel_path_indirect(KernelGlobals *kg,
}
/* setup shading */
- ShaderData sd;
shader_setup_from_ray(kg,
- &sd,
+ sd,
&isect,
ray);
float rbsdf = path_state_rng_1D_for_decision(kg, rng, state, PRNG_BSDF);
- shader_eval_surface(kg, &sd, state, rbsdf, state->flag, SHADER_CONTEXT_INDIRECT);
+ shader_eval_surface(kg, sd, state, rbsdf, state->flag, SHADER_CONTEXT_INDIRECT);
#ifdef __BRANCHED_PATH__
- shader_merge_closures(&sd);
+ shader_merge_closures(sd);
#endif
/* blurring of bsdf after bounces, for rays that have a small likelihood
@@ -264,15 +265,15 @@ ccl_device void kernel_path_indirect(KernelGlobals *kg,
if(blur_pdf < 1.0f) {
float blur_roughness = sqrtf(1.0f - blur_pdf)*0.5f;
- shader_bsdf_blur(kg, &sd, blur_roughness);
+ shader_bsdf_blur(kg, sd, blur_roughness);
}
}
#ifdef __EMISSION__
/* emission */
- if(sd.flag & SD_EMISSION) {
+ if(sd->flag & SD_EMISSION) {
float3 emission = indirect_primitive_emission(kg,
- &sd,
+ sd,
isect.t,
state->flag,
state->ray_pdf);
@@ -302,33 +303,33 @@ ccl_device void kernel_path_indirect(KernelGlobals *kg,
#ifdef __AO__
/* ambient occlusion */
- if(kernel_data.integrator.use_ambient_occlusion || (sd.flag & SD_AO)) {
+ if(kernel_data.integrator.use_ambient_occlusion || (sd->flag & SD_AO)) {
float bsdf_u, bsdf_v;
path_state_rng_2D(kg, rng, state, PRNG_BSDF_U, &bsdf_u, &bsdf_v);
float ao_factor = kernel_data.background.ao_factor;
float3 ao_N;
- float3 ao_bsdf = shader_bsdf_ao(kg, &sd, ao_factor, &ao_N);
+ float3 ao_bsdf = shader_bsdf_ao(kg, sd, ao_factor, &ao_N);
float3 ao_D;
float ao_pdf;
float3 ao_alpha = make_float3(0.0f, 0.0f, 0.0f);
sample_cos_hemisphere(ao_N, bsdf_u, bsdf_v, &ao_D, &ao_pdf);
- if(dot(sd.Ng, ao_D) > 0.0f && ao_pdf != 0.0f) {
+ if(dot(sd->Ng, ao_D) > 0.0f && ao_pdf != 0.0f) {
Ray light_ray;
float3 ao_shadow;
- light_ray.P = ray_offset(sd.P, sd.Ng);
+ light_ray.P = ray_offset(sd->P, sd->Ng);
light_ray.D = ao_D;
light_ray.t = kernel_data.background.ao_distance;
# ifdef __OBJECT_MOTION__
- light_ray.time = sd.time;
+ light_ray.time = sd->time;
# endif
- light_ray.dP = sd.dP;
+ light_ray.dP = sd->dP;
light_ray.dD = differential3_zero();
- if(!shadow_blocked(kg, state, &light_ray, &ao_shadow)) {
+ if(!shadow_blocked(kg, emission_sd, state, &light_ray, &ao_shadow)) {
path_radiance_accum_ao(L,
throughput,
ao_alpha,
@@ -343,9 +344,9 @@ ccl_device void kernel_path_indirect(KernelGlobals *kg,
#ifdef __SUBSURFACE__
/* bssrdf scatter to a different location on the same object, replacing
* the closures with a diffuse BSDF */
- if(sd.flag & SD_BSSRDF) {
+ if(sd->flag & SD_BSSRDF) {
float bssrdf_probability;
- ShaderClosure *sc = subsurface_scatter_pick_closure(kg, &sd, &bssrdf_probability);
+ ShaderClosure *sc = subsurface_scatter_pick_closure(kg, sd, &bssrdf_probability);
/* modify throughput for picking bssrdf or bsdf */
throughput *= bssrdf_probability;
@@ -361,7 +362,7 @@ ccl_device void kernel_path_indirect(KernelGlobals *kg,
PRNG_BSDF_U,
&bssrdf_u, &bssrdf_v);
subsurface_scatter_step(kg,
- &sd,
+ sd,
state,
state->flag,
sc,
@@ -377,7 +378,8 @@ ccl_device void kernel_path_indirect(KernelGlobals *kg,
int all = kernel_data.integrator.sample_all_lights_indirect;
kernel_branched_path_surface_connect_light(kg,
rng,
- &sd,
+ sd,
+ emission_sd,
state,
throughput,
1.0f,
@@ -386,13 +388,14 @@ ccl_device void kernel_path_indirect(KernelGlobals *kg,
}
#endif
- if(!kernel_path_surface_bounce(kg, rng, &sd, &throughput, state, L, ray))
+ if(!kernel_path_surface_bounce(kg, rng, sd, &throughput, state, L, ray))
break;
}
}
ccl_device_noinline void kernel_path_ao(KernelGlobals *kg,
ShaderData *sd,
+ ShaderData *emission_sd,
PathRadiance *L,
PathState *state,
RNG *rng,
@@ -425,7 +428,7 @@ ccl_device_noinline void kernel_path_ao(KernelGlobals *kg,
light_ray.dP = ccl_fetch(sd, dP);
light_ray.dD = differential3_zero();
- if(!shadow_blocked(kg, state, &light_ray, &ao_shadow))
+ if(!shadow_blocked(kg, emission_sd, state, &light_ray, &ao_shadow))
path_radiance_accum_ao(L, throughput, ao_alpha, ao_bsdf, ao_shadow, state->bounce);
}
}
@@ -435,6 +438,7 @@ ccl_device_noinline void kernel_path_ao(KernelGlobals *kg,
ccl_device bool kernel_path_subsurface_scatter(
KernelGlobals *kg,
ShaderData *sd,
+ ShaderData *emission_sd,
PathRadiance *L,
PathState *state,
RNG *rng,
@@ -503,7 +507,7 @@ ccl_device bool kernel_path_subsurface_scatter(
hit_L->direct_throughput = L->direct_throughput;
path_radiance_copy_indirect(hit_L, L);
- kernel_path_surface_connect_light(kg, rng, sd, *hit_tp, state, hit_L);
+ kernel_path_surface_connect_light(kg, rng, sd, emission_sd, *hit_tp, state, hit_L);
if(kernel_path_surface_bounce(kg,
rng,
@@ -526,6 +530,7 @@ ccl_device bool kernel_path_subsurface_scatter(
kernel_volume_stack_update_for_subsurface(
kg,
+ emission_sd,
&volume_ray,
hit_state->volume_stack);
}
@@ -604,8 +609,13 @@ ccl_device_inline float4 kernel_path_integrate(KernelGlobals *kg,
path_radiance_init(&L, kernel_data.film.use_light_pass);
+ /* shader data memory used for both volumes and surfaces, saves stack space */
+ ShaderData sd;
+ /* shader data used by emission, shadows, volume stacks */
+ ShaderData emission_sd;
+
PathState state;
- path_state_init(kg, &state, rng, sample, &ray);
+ path_state_init(kg, &emission_sd, &state, rng, sample, &ray);
#ifdef __KERNEL_DEBUG__
DebugData debug_data;
@@ -669,7 +679,7 @@ ccl_device_inline float4 kernel_path_integrate(KernelGlobals *kg,
/* intersect with lamp */
float3 emission;
- if(indirect_lamp_emission(kg, &state, &light_ray, &emission))
+ if(indirect_lamp_emission(kg, &emission_sd, &state, &light_ray, &emission))
path_radiance_accum_emission(&L, throughput, emission, state.bounce);
}
#endif
@@ -689,11 +699,10 @@ ccl_device_inline float4 kernel_path_integrate(KernelGlobals *kg,
if(decoupled) {
/* cache steps along volume for repeated sampling */
VolumeSegment volume_segment;
- ShaderData volume_sd;
- shader_setup_from_volume(kg, &volume_sd, &volume_ray);
+ shader_setup_from_volume(kg, &sd, &volume_ray);
kernel_volume_decoupled_record(kg, &state,
- &volume_ray, &volume_sd, &volume_segment, heterogeneous);
+ &volume_ray, &sd, &volume_segment, heterogeneous);
volume_segment.sampling_method = sampling_method;
@@ -708,8 +717,9 @@ ccl_device_inline float4 kernel_path_integrate(KernelGlobals *kg,
int all = false;
/* direct light sampling */
- kernel_branched_path_volume_connect_light(kg, rng, &volume_sd,
- throughput, &state, &L, all, &volume_ray, &volume_segment);
+ kernel_branched_path_volume_connect_light(kg, rng, &sd,
+ &emission_sd, throughput, &state, &L, all,
+ &volume_ray, &volume_segment);
/* indirect sample. if we use distance sampling and take just
* one sample for direct and indirect light, we could share
@@ -718,7 +728,7 @@ ccl_device_inline float4 kernel_path_integrate(KernelGlobals *kg,
float rscatter = path_state_rng_1D_for_decision(kg, rng, &state, PRNG_SCATTER_DISTANCE);
result = kernel_volume_decoupled_scatter(kg,
- &state, &volume_ray, &volume_sd, &throughput,
+ &state, &volume_ray, &sd, &throughput,
rphase, rscatter, &volume_segment, NULL, true);
}
@@ -726,7 +736,7 @@ ccl_device_inline float4 kernel_path_integrate(KernelGlobals *kg,
kernel_volume_decoupled_free(kg, &volume_segment);
if(result == VOLUME_PATH_SCATTERED) {
- if(kernel_path_volume_bounce(kg, rng, &volume_sd, &throughput, &state, &L, &ray))
+ if(kernel_path_volume_bounce(kg, rng, &sd, &throughput, &state, &L, &ray))
continue;
else
break;
@@ -739,17 +749,16 @@ ccl_device_inline float4 kernel_path_integrate(KernelGlobals *kg,
# endif
{
/* integrate along volume segment with distance sampling */
- ShaderData volume_sd;
VolumeIntegrateResult result = kernel_volume_integrate(
- kg, &state, &volume_sd, &volume_ray, &L, &throughput, rng, heterogeneous);
+ kg, &state, &sd, &volume_ray, &L, &throughput, rng, heterogeneous);
# ifdef __VOLUME_SCATTER__
if(result == VOLUME_PATH_SCATTERED) {
/* direct lighting */
- kernel_path_volume_connect_light(kg, rng, &volume_sd, throughput, &state, &L);
+ kernel_path_volume_connect_light(kg, rng, &sd, &emission_sd, throughput, &state, &L);
/* indirect light bounce */
- if(kernel_path_volume_bounce(kg, rng, &volume_sd, &throughput, &state, &L, &ray))
+ if(kernel_path_volume_bounce(kg, rng, &sd, &throughput, &state, &L, &ray))
continue;
else
break;
@@ -772,7 +781,7 @@ ccl_device_inline float4 kernel_path_integrate(KernelGlobals *kg,
#ifdef __BACKGROUND__
/* sample background shader */
- float3 L_background = indirect_background(kg, &state, &ray);
+ float3 L_background = indirect_background(kg, &emission_sd, &state, &ray);
path_radiance_accum_background(&L, throughput, L_background, state.bounce);
#endif
@@ -780,7 +789,6 @@ ccl_device_inline float4 kernel_path_integrate(KernelGlobals *kg,
}
/* setup shading */
- ShaderData sd;
shader_setup_from_ray(kg, &sd, &isect, &ray);
float rbsdf = path_state_rng_1D_for_decision(kg, rng, &state, PRNG_BSDF);
shader_eval_surface(kg, &sd, &state, rbsdf, state.flag, SHADER_CONTEXT_MAIN);
@@ -848,7 +856,7 @@ ccl_device_inline float4 kernel_path_integrate(KernelGlobals *kg,
#ifdef __AO__
/* ambient occlusion */
if(kernel_data.integrator.use_ambient_occlusion || (sd.flag & SD_AO)) {
- kernel_path_ao(kg, &sd, &L, &state, rng, throughput);
+ kernel_path_ao(kg, &sd, &emission_sd, &L, &state, rng, throughput);
}
#endif
@@ -858,6 +866,7 @@ ccl_device_inline float4 kernel_path_integrate(KernelGlobals *kg,
if(sd.flag & SD_BSSRDF) {
if(kernel_path_subsurface_scatter(kg,
&sd,
+ &emission_sd,
&L,
&state,
rng,
@@ -871,7 +880,7 @@ ccl_device_inline float4 kernel_path_integrate(KernelGlobals *kg,
#endif /* __SUBSURFACE__ */
/* direct lighting */
- kernel_path_surface_connect_light(kg, rng, &sd, throughput, &state, &L);
+ kernel_path_surface_connect_light(kg, rng, &sd, &emission_sd, throughput, &state, &L);
/* compute direct lighting and next bounce */
if(!kernel_path_surface_bounce(kg, rng, &sd, &throughput, &state, &L, &ray))
diff --git a/intern/cycles/kernel/kernel_path_branched.h b/intern/cycles/kernel/kernel_path_branched.h
index 13ae4cf669b..fdba1a7b025 100644
--- a/intern/cycles/kernel/kernel_path_branched.h
+++ b/intern/cycles/kernel/kernel_path_branched.h
@@ -18,7 +18,13 @@ CCL_NAMESPACE_BEGIN
#ifdef __BRANCHED_PATH__
-ccl_device void kernel_branched_path_ao(KernelGlobals *kg, ShaderData *sd, PathRadiance *L, PathState *state, RNG *rng, float3 throughput)
+ccl_device void kernel_branched_path_ao(KernelGlobals *kg,
+ ShaderData *sd,
+ ShaderData *emission_sd,
+ PathRadiance *L,
+ PathState *state,
+ RNG *rng,
+ float3 throughput)
{
int num_samples = kernel_data.integrator.ao_samples;
float num_samples_inv = 1.0f/num_samples;
@@ -49,7 +55,7 @@ ccl_device void kernel_branched_path_ao(KernelGlobals *kg, ShaderData *sd, PathR
light_ray.dP = ccl_fetch(sd, dP);
light_ray.dD = differential3_zero();
- if(!shadow_blocked(kg, state, &light_ray, &ao_shadow))
+ if(!shadow_blocked(kg, emission_sd, state, &light_ray, &ao_shadow))
path_radiance_accum_ao(L, throughput*num_samples_inv, ao_alpha, ao_bsdf, ao_shadow, state->bounce);
}
}
@@ -58,8 +64,8 @@ ccl_device void kernel_branched_path_ao(KernelGlobals *kg, ShaderData *sd, PathR
/* bounce off surface and integrate indirect light */
ccl_device_noinline void kernel_branched_path_surface_indirect_light(KernelGlobals *kg,
- RNG *rng, ShaderData *sd, float3 throughput, float num_samples_adjust,
- PathState *state, PathRadiance *L)
+ RNG *rng, ShaderData *sd, ShaderData *indirect_sd, ShaderData *emission_sd,
+ float3 throughput, float num_samples_adjust, PathState *state, PathRadiance *L)
{
for(int i = 0; i < ccl_fetch(sd, num_closure); i++) {
const ShaderClosure *sc = &ccl_fetch(sd, closure)[i];
@@ -106,6 +112,8 @@ ccl_device_noinline void kernel_branched_path_surface_indirect_light(KernelGloba
}
kernel_path_indirect(kg,
+ indirect_sd,
+ emission_sd,
rng,
&bsdf_ray,
tp*num_samples_inv,
@@ -124,6 +132,8 @@ ccl_device_noinline void kernel_branched_path_surface_indirect_light(KernelGloba
#ifdef __SUBSURFACE__
ccl_device void kernel_branched_path_subsurface_scatter(KernelGlobals *kg,
ShaderData *sd,
+ ShaderData *indirect_sd,
+ ShaderData *emission_sd,
PathRadiance *L,
PathState *state,
RNG *rng,
@@ -186,6 +196,7 @@ ccl_device void kernel_branched_path_subsurface_scatter(KernelGlobals *kg,
kernel_volume_stack_update_for_subsurface(
kg,
+ emission_sd,
&volume_ray,
hit_state.volume_stack);
}
@@ -199,6 +210,7 @@ ccl_device void kernel_branched_path_subsurface_scatter(KernelGlobals *kg,
kg,
rng,
&bssrdf_sd,
+ emission_sd,
&hit_state,
throughput,
num_samples_inv,
@@ -212,6 +224,8 @@ ccl_device void kernel_branched_path_subsurface_scatter(KernelGlobals *kg,
kg,
rng,
&bssrdf_sd,
+ indirect_sd,
+ emission_sd,
throughput,
num_samples_inv,
&hit_state,
@@ -231,8 +245,13 @@ ccl_device float4 kernel_branched_path_integrate(KernelGlobals *kg, RNG *rng, in
path_radiance_init(&L, kernel_data.film.use_light_pass);
+ /* shader data memory used for both volumes and surfaces, saves stack space */
+ ShaderData sd;
+ /* shader data used by emission, shadows, volume stacks, indirect path */
+ ShaderData emission_sd, indirect_sd;
+
PathState state;
- path_state_init(kg, &state, rng, sample, &ray);
+ path_state_init(kg, &emission_sd, &state, rng, sample, &ray);
#ifdef __KERNEL_DEBUG__
DebugData debug_data;
@@ -287,11 +306,10 @@ ccl_device float4 kernel_branched_path_integrate(KernelGlobals *kg, RNG *rng, in
/* cache steps along volume for repeated sampling */
VolumeSegment volume_segment;
- ShaderData volume_sd;
- shader_setup_from_volume(kg, &volume_sd, &volume_ray);
+ shader_setup_from_volume(kg, &sd, &volume_ray);
kernel_volume_decoupled_record(kg, &state,
- &volume_ray, &volume_sd, &volume_segment, heterogeneous);
+ &volume_ray, &sd, &volume_segment, heterogeneous);
/* direct light sampling */
if(volume_segment.closure_flag & SD_SCATTER) {
@@ -299,8 +317,9 @@ ccl_device float4 kernel_branched_path_integrate(KernelGlobals *kg, RNG *rng, in
int all = kernel_data.integrator.sample_all_lights_direct;
- kernel_branched_path_volume_connect_light(kg, rng, &volume_sd,
- throughput, &state, &L, all, &volume_ray, &volume_segment);
+ kernel_branched_path_volume_connect_light(kg, rng, &sd,
+ &emission_sd, throughput, &state, &L, all,
+ &volume_ray, &volume_segment);
/* indirect light sampling */
int num_samples = kernel_data.integrator.volume_samples;
@@ -326,20 +345,22 @@ ccl_device float4 kernel_branched_path_integrate(KernelGlobals *kg, RNG *rng, in
float rscatter = path_state_rng_1D_for_decision(kg, &tmp_rng, &ps, PRNG_SCATTER_DISTANCE);
VolumeIntegrateResult result = kernel_volume_decoupled_scatter(kg,
- &ps, &pray, &volume_sd, &tp, rphase, rscatter, &volume_segment, NULL, false);
+ &ps, &pray, &sd, &tp, rphase, rscatter, &volume_segment, NULL, false);
(void)result;
kernel_assert(result == VOLUME_PATH_SCATTERED);
if(kernel_path_volume_bounce(kg,
rng,
- &volume_sd,
+ &sd,
&tp,
&ps,
&L,
&pray))
{
kernel_path_indirect(kg,
+ &indirect_sd,
+ &emission_sd,
rng,
&pray,
tp*num_samples_inv,
@@ -373,30 +394,31 @@ ccl_device float4 kernel_branched_path_integrate(KernelGlobals *kg, RNG *rng, in
for(int j = 0; j < num_samples; j++) {
PathState ps = state;
Ray pray = ray;
- ShaderData volume_sd;
float3 tp = throughput * num_samples_inv;
/* branch RNG state */
path_state_branch(&ps, j, num_samples);
VolumeIntegrateResult result = kernel_volume_integrate(
- kg, &ps, &volume_sd, &volume_ray, &L, &tp, rng, heterogeneous);
+ kg, &ps, &sd, &volume_ray, &L, &tp, rng, heterogeneous);
#ifdef __VOLUME_SCATTER__
if(result == VOLUME_PATH_SCATTERED) {
/* todo: support equiangular, MIS and all light sampling.
* alternatively get decoupled ray marching working on the GPU */
- kernel_path_volume_connect_light(kg, rng, &volume_sd, tp, &state, &L);
+ kernel_path_volume_connect_light(kg, rng, &sd, &emission_sd, tp, &state, &L);
if(kernel_path_volume_bounce(kg,
rng,
- &volume_sd,
+ &sd,
&tp,
&ps,
&L,
&pray))
{
kernel_path_indirect(kg,
+ &indirect_sd,
+ &emission_sd,
rng,
&pray,
tp,
@@ -414,7 +436,7 @@ ccl_device float4 kernel_branched_path_integrate(KernelGlobals *kg, RNG *rng, in
}
/* todo: avoid this calculation using decoupled ray marching */
- kernel_volume_shadow(kg, &state, &volume_ray, &throughput);
+ kernel_volume_shadow(kg, &emission_sd, &state, &volume_ray, &throughput);
#endif
}
#endif
@@ -432,7 +454,7 @@ ccl_device float4 kernel_branched_path_integrate(KernelGlobals *kg, RNG *rng, in
#ifdef __BACKGROUND__
/* sample background shader */
- float3 L_background = indirect_background(kg, &state, &ray);
+ float3 L_background = indirect_background(kg, &emission_sd, &state, &ray);
path_radiance_accum_background(&L, throughput, L_background, state.bounce);
#endif
@@ -440,7 +462,6 @@ ccl_device float4 kernel_branched_path_integrate(KernelGlobals *kg, RNG *rng, in
}
/* setup shading */
- ShaderData sd;
shader_setup_from_ray(kg, &sd, &isect, &ray);
shader_eval_surface(kg, &sd, &state, 0.0f, state.flag, SHADER_CONTEXT_MAIN);
shader_merge_closures(&sd);
@@ -499,15 +520,15 @@ ccl_device float4 kernel_branched_path_integrate(KernelGlobals *kg, RNG *rng, in
#ifdef __AO__
/* ambient occlusion */
if(kernel_data.integrator.use_ambient_occlusion || (sd.flag & SD_AO)) {
- kernel_branched_path_ao(kg, &sd, &L, &state, rng, throughput);
+ kernel_branched_path_ao(kg, &sd, &emission_sd, &L, &state, rng, throughput);
}
#endif
#ifdef __SUBSURFACE__
/* bssrdf scatter to a different location on the same object */
if(sd.flag & SD_BSSRDF) {
- kernel_branched_path_subsurface_scatter(kg, &sd, &L, &state,
- rng, &ray, throughput);
+ kernel_branched_path_subsurface_scatter(kg, &sd, &indirect_sd, &emission_sd,
+ &L, &state, rng, &ray, throughput);
}
#endif
@@ -519,13 +540,13 @@ ccl_device float4 kernel_branched_path_integrate(KernelGlobals *kg, RNG *rng, in
if(kernel_data.integrator.use_direct_light) {
int all = kernel_data.integrator.sample_all_lights_direct;
kernel_branched_path_surface_connect_light(kg, rng,
- &sd, &hit_state, throughput, 1.0f, &L, all);
+ &sd, &emission_sd, &hit_state, throughput, 1.0f, &L, all);
}
#endif
/* indirect light */
kernel_branched_path_surface_indirect_light(kg, rng,
- &sd, throughput, 1.0f, &hit_state, &L);
+ &sd, &indirect_sd, &emission_sd, throughput, 1.0f, &hit_state, &L);
/* continue in case of transparency */
throughput *= shader_bsdf_transparency(kg, &sd);
diff --git a/intern/cycles/kernel/kernel_path_state.h b/intern/cycles/kernel/kernel_path_state.h
index ef3765f7d89..e0e35d792ab 100644
--- a/intern/cycles/kernel/kernel_path_state.h
+++ b/intern/cycles/kernel/kernel_path_state.h
@@ -16,7 +16,12 @@
CCL_NAMESPACE_BEGIN
-ccl_device_inline void path_state_init(KernelGlobals *kg, ccl_addr_space PathState *state, ccl_addr_space RNG *rng, int sample, ccl_addr_space Ray *ray)
+ccl_device_inline void path_state_init(KernelGlobals *kg,
+ ShaderData *stack_sd,
+ ccl_addr_space PathState *state,
+ ccl_addr_space RNG *rng,
+ int sample,
+ ccl_addr_space Ray *ray)
{
state->flag = PATH_RAY_CAMERA|PATH_RAY_MIS_SKIP;
@@ -41,7 +46,7 @@ ccl_device_inline void path_state_init(KernelGlobals *kg, ccl_addr_space PathSta
if(kernel_data.integrator.use_volumes) {
/* initialize volume stack with volume we are inside of */
- kernel_volume_stack_init(kg, ray, state->volume_stack);
+ kernel_volume_stack_init(kg, stack_sd, ray, state->volume_stack);
/* seed RNG for cases where we can't use stratified samples */
state->rng_congruential = lcg_init(*rng + sample*0x51633e2d);
}
diff --git a/intern/cycles/kernel/kernel_path_surface.h b/intern/cycles/kernel/kernel_path_surface.h
index 1818c4fd2da..74b1ae0ca32 100644
--- a/intern/cycles/kernel/kernel_path_surface.h
+++ b/intern/cycles/kernel/kernel_path_surface.h
@@ -20,7 +20,8 @@ CCL_NAMESPACE_BEGIN
/* branched path tracing: connect path directly to position on one or more lights and add it to L */
ccl_device_noinline void kernel_branched_path_surface_connect_light(KernelGlobals *kg, RNG *rng,
- ShaderData *sd, PathState *state, float3 throughput, float num_samples_adjust, PathRadiance *L, int sample_all_lights)
+ ShaderData *sd, ShaderData *emission_sd, PathState *state, float3 throughput,
+ float num_samples_adjust, PathRadiance *L, int sample_all_lights)
{
#ifdef __EMISSION__
/* sample illumination from lights to find path contribution */
@@ -55,11 +56,11 @@ ccl_device_noinline void kernel_branched_path_surface_connect_light(KernelGlobal
LightSample ls;
lamp_light_sample(kg, i, light_u, light_v, ccl_fetch(sd, P), &ls);
- if(direct_emission(kg, sd, &ls, state, &light_ray, &L_light, &is_lamp)) {
+ if(direct_emission(kg, sd, emission_sd, &ls, state, &light_ray, &L_light, &is_lamp)) {
/* trace shadow ray */
float3 shadow;
- if(!shadow_blocked(kg, state, &light_ray, &shadow)) {
+ if(!shadow_blocked(kg, emission_sd, state, &light_ray, &shadow)) {
/* accumulate */
path_radiance_accum_light(L, throughput*num_samples_inv, &L_light, shadow, num_samples_inv, state->bounce, is_lamp);
}
@@ -87,11 +88,11 @@ ccl_device_noinline void kernel_branched_path_surface_connect_light(KernelGlobal
LightSample ls;
light_sample(kg, light_t, light_u, light_v, ccl_fetch(sd, time), ccl_fetch(sd, P), state->bounce, &ls);
- if(direct_emission(kg, sd, &ls, state, &light_ray, &L_light, &is_lamp)) {
+ if(direct_emission(kg, sd, emission_sd, &ls, state, &light_ray, &L_light, &is_lamp)) {
/* trace shadow ray */
float3 shadow;
- if(!shadow_blocked(kg, state, &light_ray, &shadow)) {
+ if(!shadow_blocked(kg, emission_sd, state, &light_ray, &shadow)) {
/* accumulate */
path_radiance_accum_light(L, throughput*num_samples_inv, &L_light, shadow, num_samples_inv, state->bounce, is_lamp);
}
@@ -109,11 +110,11 @@ ccl_device_noinline void kernel_branched_path_surface_connect_light(KernelGlobal
light_sample(kg, light_t, light_u, light_v, ccl_fetch(sd, time), ccl_fetch(sd, P), state->bounce, &ls);
/* sample random light */
- if(direct_emission(kg, sd, &ls, state, &light_ray, &L_light, &is_lamp)) {
+ if(direct_emission(kg, sd, emission_sd, &ls, state, &light_ray, &L_light, &is_lamp)) {
/* trace shadow ray */
float3 shadow;
- if(!shadow_blocked(kg, state, &light_ray, &shadow)) {
+ if(!shadow_blocked(kg, emission_sd, state, &light_ray, &shadow)) {
/* accumulate */
path_radiance_accum_light(L, throughput*num_samples_adjust, &L_light, shadow, num_samples_adjust, state->bounce, is_lamp);
}
@@ -184,7 +185,8 @@ ccl_device bool kernel_branched_path_surface_bounce(KernelGlobals *kg, RNG *rng,
#ifndef __SPLIT_KERNEL__
/* path tracing: connect path directly to position on a light and add it to L */
ccl_device_inline void kernel_path_surface_connect_light(KernelGlobals *kg, ccl_addr_space RNG *rng,
- ShaderData *sd, float3 throughput, ccl_addr_space PathState *state, PathRadiance *L)
+ ShaderData *sd, ShaderData *emission_sd, float3 throughput, ccl_addr_space PathState *state,
+ PathRadiance *L)
{
#ifdef __EMISSION__
if(!(kernel_data.integrator.use_direct_light && (ccl_fetch(sd, flag) & SD_BSDF_HAS_EVAL)))
@@ -206,11 +208,11 @@ ccl_device_inline void kernel_path_surface_connect_light(KernelGlobals *kg, ccl_
LightSample ls;
light_sample(kg, light_t, light_u, light_v, ccl_fetch(sd, time), ccl_fetch(sd, P), state->bounce, &ls);
- if(direct_emission(kg, sd, &ls, state, &light_ray, &L_light, &is_lamp)) {
+ if(direct_emission(kg, sd, emission_sd, &ls, state, &light_ray, &L_light, &is_lamp)) {
/* trace shadow ray */
float3 shadow;
- if(!shadow_blocked(kg, state, &light_ray, &shadow)) {
+ if(!shadow_blocked(kg, emission_sd, state, &light_ray, &shadow)) {
/* accumulate */
path_radiance_accum_light(L, throughput, &L_light, shadow, 1.0f, state->bounce, is_lamp);
}
diff --git a/intern/cycles/kernel/kernel_path_volume.h b/intern/cycles/kernel/kernel_path_volume.h
index 9eb8b240b88..e45522a4641 100644
--- a/intern/cycles/kernel/kernel_path_volume.h
+++ b/intern/cycles/kernel/kernel_path_volume.h
@@ -19,7 +19,7 @@ CCL_NAMESPACE_BEGIN
#ifdef __VOLUME_SCATTER__
ccl_device void kernel_path_volume_connect_light(KernelGlobals *kg, RNG *rng,
- ShaderData *sd, float3 throughput, PathState *state, PathRadiance *L)
+ ShaderData *sd, ShaderData *emission_sd, float3 throughput, PathState *state, PathRadiance *L)
{
#ifdef __EMISSION__
if(!kernel_data.integrator.use_direct_light)
@@ -44,11 +44,11 @@ ccl_device void kernel_path_volume_connect_light(KernelGlobals *kg, RNG *rng,
if(ls.pdf == 0.0f)
return;
- if(direct_emission(kg, sd, &ls, state, &light_ray, &L_light, &is_lamp)) {
+ if(direct_emission(kg, sd, emission_sd, &ls, state, &light_ray, &L_light, &is_lamp)) {
/* trace shadow ray */
float3 shadow;
- if(!shadow_blocked(kg, state, &light_ray, &shadow)) {
+ if(!shadow_blocked(kg, emission_sd, state, &light_ray, &shadow)) {
/* accumulate */
path_radiance_accum_light(L, throughput, &L_light, shadow, 1.0f, state->bounce, is_lamp);
}
@@ -106,7 +106,7 @@ bool kernel_path_volume_bounce(KernelGlobals *kg, RNG *rng,
}
ccl_device void kernel_branched_path_volume_connect_light(KernelGlobals *kg, RNG *rng,
- ShaderData *sd, float3 throughput, PathState *state, PathRadiance *L,
+ ShaderData *sd, ShaderData *emission_sd, float3 throughput, PathState *state, PathRadiance *L,
bool sample_all_lights, Ray *ray, const VolumeSegment *segment)
{
#ifdef __EMISSION__
@@ -160,11 +160,11 @@ ccl_device void kernel_branched_path_volume_connect_light(KernelGlobals *kg, RNG
if(ls.pdf == 0.0f)
continue;
- if(direct_emission(kg, sd, &ls, state, &light_ray, &L_light, &is_lamp)) {
+ if(direct_emission(kg, sd, emission_sd, &ls, state, &light_ray, &L_light, &is_lamp)) {
/* trace shadow ray */
float3 shadow;
- if(!shadow_blocked(kg, state, &light_ray, &shadow)) {
+ if(!shadow_blocked(kg, emission_sd, state, &light_ray, &shadow)) {
/* accumulate */
path_radiance_accum_light(L, tp*num_samples_inv, &L_light, shadow, num_samples_inv, state->bounce, is_lamp);
}
@@ -211,11 +211,11 @@ ccl_device void kernel_branched_path_volume_connect_light(KernelGlobals *kg, RNG
if(ls.pdf == 0.0f)
continue;
- if(direct_emission(kg, sd, &ls, state, &light_ray, &L_light, &is_lamp)) {
+ if(direct_emission(kg, sd, emission_sd, &ls, state, &light_ray, &L_light, &is_lamp)) {
/* trace shadow ray */
float3 shadow;
- if(!shadow_blocked(kg, state, &light_ray, &shadow)) {
+ if(!shadow_blocked(kg, emission_sd, state, &light_ray, &shadow)) {
/* accumulate */
path_radiance_accum_light(L, tp*num_samples_inv, &L_light, shadow, num_samples_inv, state->bounce, is_lamp);
}
@@ -251,11 +251,11 @@ ccl_device void kernel_branched_path_volume_connect_light(KernelGlobals *kg, RNG
return;
/* sample random light */
- if(direct_emission(kg, sd, &ls, state, &light_ray, &L_light, &is_lamp)) {
+ if(direct_emission(kg, sd, emission_sd, &ls, state, &light_ray, &L_light, &is_lamp)) {
/* trace shadow ray */
float3 shadow;
- if(!shadow_blocked(kg, state, &light_ray, &shadow)) {
+ if(!shadow_blocked(kg, emission_sd, state, &light_ray, &shadow)) {
/* accumulate */
path_radiance_accum_light(L, tp, &L_light, shadow, 1.0f, state->bounce, is_lamp);
}
diff --git a/intern/cycles/kernel/kernel_shadow.h b/intern/cycles/kernel/kernel_shadow.h
index 504ac2e40bc..1abbbb2ddad 100644
--- a/intern/cycles/kernel/kernel_shadow.h
+++ b/intern/cycles/kernel/kernel_shadow.h
@@ -41,7 +41,7 @@ CCL_NAMESPACE_BEGIN
#define STACK_MAX_HITS 64
-ccl_device_inline bool shadow_blocked(KernelGlobals *kg, PathState *state, Ray *ray, float3 *shadow)
+ccl_device_inline bool shadow_blocked(KernelGlobals *kg, ShaderData *shadow_sd, PathState *state, Ray *ray, float3 *shadow)
{
*shadow = make_float3(1.0f, 1.0f, 1.0f);
@@ -107,39 +107,36 @@ ccl_device_inline bool shadow_blocked(KernelGlobals *kg, PathState *state, Ray *
if(ps.volume_stack[0].shader != SHADER_NONE) {
Ray segment_ray = *ray;
segment_ray.t = isect->t;
- kernel_volume_shadow(kg, &ps, &segment_ray, &throughput);
+ kernel_volume_shadow(kg, shadow_sd, &ps, &segment_ray, &throughput);
}
#endif
/* setup shader data at surface */
- ShaderData sd;
- shader_setup_from_ray(kg, &sd, isect, ray);
+ shader_setup_from_ray(kg, shadow_sd, isect, ray);
/* attenuation from transparent surface */
- if(!(sd.flag & SD_HAS_ONLY_VOLUME)) {
+ if(!(shadow_sd->flag & SD_HAS_ONLY_VOLUME)) {
path_state_modify_bounce(state, true);
- shader_eval_surface(kg, &sd, state, 0.0f, PATH_RAY_SHADOW, SHADER_CONTEXT_SHADOW);
+ shader_eval_surface(kg, shadow_sd, state, 0.0f, PATH_RAY_SHADOW, SHADER_CONTEXT_SHADOW);
path_state_modify_bounce(state, false);
- throughput *= shader_bsdf_transparency(kg, &sd);
+ throughput *= shader_bsdf_transparency(kg, shadow_sd);
}
/* stop if all light is blocked */
if(is_zero(throughput)) {
/* free dynamic storage */
- if(hits != hits_stack)
- free(hits);
return true;
}
/* move ray forward */
- ray->P = sd.P;
+ ray->P = shadow_sd->P;
if(ray->t != FLT_MAX)
ray->D = normalize_len(Pend - ray->P, &ray->t);
#ifdef __VOLUME__
/* exit/enter volume */
- kernel_volume_stack_enter_exit(kg, &sd, ps.volume_stack);
+ kernel_volume_stack_enter_exit(kg, shadow_sd, ps.volume_stack);
#endif
bounce++;
@@ -148,7 +145,7 @@ ccl_device_inline bool shadow_blocked(KernelGlobals *kg, PathState *state, Ray *
#ifdef __VOLUME__
/* attenuation for last line segment towards light */
if(ps.volume_stack[0].shader != SHADER_NONE)
- kernel_volume_shadow(kg, &ps, ray, &throughput);
+ kernel_volume_shadow(kg, shadow_sd, &ps, ray, &throughput);
#endif
*shadow = throughput;
@@ -164,7 +161,7 @@ ccl_device_inline bool shadow_blocked(KernelGlobals *kg, PathState *state, Ray *
#ifdef __VOLUME__
if(!blocked && state->volume_stack[0].shader != SHADER_NONE) {
/* apply attenuation from current volume shader */
- kernel_volume_shadow(kg, state, ray, shadow);
+ kernel_volume_shadow(kg, shadow_sd, state, ray, shadow);
}
#endif
@@ -184,6 +181,7 @@ ccl_device_inline bool shadow_blocked(KernelGlobals *kg, PathState *state, Ray *
* one extra ray cast for the cases were we do want transparency. */
ccl_device_noinline bool shadow_blocked(KernelGlobals *kg,
+ ShaderData *shadow_sd,
ccl_addr_space PathState *state,
ccl_addr_space Ray *ray_input,
float3 *shadow)
@@ -228,7 +226,7 @@ ccl_device_noinline bool shadow_blocked(KernelGlobals *kg,
#ifdef __VOLUME__
/* attenuation for last line segment towards light */
if(ps.volume_stack[0].shader != SHADER_NONE)
- kernel_volume_shadow(kg, &ps, ray, &throughput);
+ kernel_volume_shadow(kg, shadow_sd, &ps, ray, &throughput);
#endif
*shadow *= throughput;
@@ -244,39 +242,33 @@ ccl_device_noinline bool shadow_blocked(KernelGlobals *kg,
if(ps.volume_stack[0].shader != SHADER_NONE) {
Ray segment_ray = *ray;
segment_ray.t = isect->t;
- kernel_volume_shadow(kg, &ps, &segment_ray, &throughput);
+ kernel_volume_shadow(kg, shadow_sd, &ps, &segment_ray, &throughput);
}
#endif
/* setup shader data at surface */
-#ifdef __SPLIT_KERNEL__
- ShaderData *sd = kg->sd_input;
-#else
- ShaderData sd_object;
- ShaderData *sd = &sd_object;
-#endif
- shader_setup_from_ray(kg, sd, isect, ray);
+ shader_setup_from_ray(kg, shadow_sd, isect, ray);
/* attenuation from transparent surface */
- if(!(ccl_fetch(sd, flag) & SD_HAS_ONLY_VOLUME)) {
+ if(!(ccl_fetch(shadow_sd, flag) & SD_HAS_ONLY_VOLUME)) {
path_state_modify_bounce(state, true);
- shader_eval_surface(kg, sd, state, 0.0f, PATH_RAY_SHADOW, SHADER_CONTEXT_SHADOW);
+ shader_eval_surface(kg, shadow_sd, state, 0.0f, PATH_RAY_SHADOW, SHADER_CONTEXT_SHADOW);
path_state_modify_bounce(state, false);
- throughput *= shader_bsdf_transparency(kg, sd);
+ throughput *= shader_bsdf_transparency(kg, shadow_sd);
}
if(is_zero(throughput))
return true;
/* move ray forward */
- ray->P = ray_offset(ccl_fetch(sd, P), -ccl_fetch(sd, Ng));
+ ray->P = ray_offset(ccl_fetch(shadow_sd, P), -ccl_fetch(shadow_sd, Ng));
if(ray->t != FLT_MAX)
ray->D = normalize_len(Pend - ray->P, &ray->t);
#ifdef __VOLUME__
/* exit/enter volume */
- kernel_volume_stack_enter_exit(kg, sd, ps.volume_stack);
+ kernel_volume_stack_enter_exit(kg, shadow_sd, ps.volume_stack);
#endif
bounce++;
@@ -286,7 +278,7 @@ ccl_device_noinline bool shadow_blocked(KernelGlobals *kg,
#ifdef __VOLUME__
else if(!blocked && state->volume_stack[0].shader != SHADER_NONE) {
/* apply attenuation from current volume shader */
- kernel_volume_shadow(kg, state, ray, shadow);
+ kernel_volume_shadow(kg, shadow_sd, state, ray, shadow);
}
#endif
#endif
diff --git a/intern/cycles/kernel/kernel_types.h b/intern/cycles/kernel/kernel_types.h
index ba50d180acf..1ffcfb94a15 100644
--- a/intern/cycles/kernel/kernel_types.h
+++ b/intern/cycles/kernel/kernel_types.h
@@ -121,9 +121,7 @@ CCL_NAMESPACE_BEGIN
# define __OBJECT_MOTION__
# define __HAIR__
# define __BAKING__
-# ifdef __KERNEL_EXPERIMENTAL__
-# define __TRANSPARENT_SHADOWS__
-# endif
+# define __TRANSPARENT_SHADOWS__
# endif /* __KERNEL_OPENCL_AMD__ */
# ifdef __KERNEL_OPENCL_INTEL_CPU__
diff --git a/intern/cycles/kernel/kernel_volume.h b/intern/cycles/kernel/kernel_volume.h
index 30a978f6c9e..0e313b8e88c 100644
--- a/intern/cycles/kernel/kernel_volume.h
+++ b/intern/cycles/kernel/kernel_volume.h
@@ -219,15 +219,14 @@ ccl_device void kernel_volume_shadow_heterogeneous(KernelGlobals *kg, PathState
/* get the volume attenuation over line segment defined by ray, with the
* assumption that there are no surfaces blocking light between the endpoints */
-ccl_device_noinline void kernel_volume_shadow(KernelGlobals *kg, PathState *state, Ray *ray, float3 *throughput)
+ccl_device_noinline void kernel_volume_shadow(KernelGlobals *kg, ShaderData *shadow_sd, PathState *state, Ray *ray, float3 *throughput)
{
- ShaderData sd;
- shader_setup_from_volume(kg, &sd, ray);
+ shader_setup_from_volume(kg, shadow_sd, ray);
if(volume_stack_is_heterogeneous(kg, state->volume_stack))
- kernel_volume_shadow_heterogeneous(kg, state, ray, &sd, throughput);
+ kernel_volume_shadow_heterogeneous(kg, state, ray, shadow_sd, throughput);
else
- kernel_volume_shadow_homogeneous(kg, state, ray, &sd, throughput);
+ kernel_volume_shadow_homogeneous(kg, state, ray, shadow_sd, throughput);
}
/* Equi-angular sampling as in:
@@ -1000,6 +999,7 @@ ccl_device bool kernel_volume_use_decoupled(KernelGlobals *kg, bool heterogeneou
* is inside of. */
ccl_device void kernel_volume_stack_init(KernelGlobals *kg,
+ ShaderData *stack_sd,
Ray *ray,
VolumeStack *stack)
{
@@ -1040,28 +1040,27 @@ ccl_device void kernel_volume_stack_init(KernelGlobals *kg,
qsort(hits, num_hits, sizeof(Intersection), intersections_compare);
for(uint hit = 0; hit < num_hits; ++hit, ++isect) {
- ShaderData sd;
- shader_setup_from_ray(kg, &sd, isect, &volume_ray);
- if(sd.flag & SD_BACKFACING) {
+ shader_setup_from_ray(kg, stack_sd, isect, &volume_ray);
+ if(stack_sd->flag & SD_BACKFACING) {
bool need_add = true;
for(int i = 0; i < enclosed_index && need_add; ++i) {
/* If ray exited the volume and never entered to that volume
* it means that camera is inside such a volume.
*/
- if(enclosed_volumes[i] == sd.object) {
+ if(enclosed_volumes[i] == stack_sd->object) {
need_add = false;
}
}
for(int i = 0; i < stack_index && need_add; ++i) {
/* Don't add intersections twice. */
- if(stack[i].object == sd.object) {
+ if(stack[i].object == stack_sd->object) {
need_add = false;
break;
}
}
if(need_add) {
- stack[stack_index].object = sd.object;
- stack[stack_index].shader = sd.shader;
+ stack[stack_index].object = stack_sd->object;
+ stack[stack_index].shader = stack_sd->shader;
++stack_index;
}
}
@@ -1069,7 +1068,7 @@ ccl_device void kernel_volume_stack_init(KernelGlobals *kg,
/* If ray from camera enters the volume, this volume shouldn't
* be added to the stack on exit.
*/
- enclosed_volumes[enclosed_index++] = sd.object;
+ enclosed_volumes[enclosed_index++] = stack_sd->object;
}
}
}
@@ -1086,9 +1085,8 @@ ccl_device void kernel_volume_stack_init(KernelGlobals *kg,
break;
}
- ShaderData sd;
- shader_setup_from_ray(kg, &sd, &isect, &volume_ray);
- if(sd.flag & SD_BACKFACING) {
+ shader_setup_from_ray(kg, stack_sd, &isect, &volume_ray);
+ if(stack_sd->flag & SD_BACKFACING) {
/* If ray exited the volume and never entered to that volume
* it means that camera is inside such a volume.
*/
@@ -1097,20 +1095,20 @@ ccl_device void kernel_volume_stack_init(KernelGlobals *kg,
/* If ray exited the volume and never entered to that volume
* it means that camera is inside such a volume.
*/
- if(enclosed_volumes[i] == sd.object) {
+ if(enclosed_volumes[i] == stack_sd->object) {
need_add = false;
}
}
for(int i = 0; i < stack_index && need_add; ++i) {
/* Don't add intersections twice. */
- if(stack[i].object == sd.object) {
+ if(stack[i].object == stack_sd->object) {
need_add = false;
break;
}
}
if(need_add) {
- stack[stack_index].object = sd.object;
- stack[stack_index].shader = sd.shader;
+ stack[stack_index].object = stack_sd->object;
+ stack[stack_index].shader = stack_sd->shader;
++stack_index;
}
}
@@ -1118,11 +1116,11 @@ ccl_device void kernel_volume_stack_init(KernelGlobals *kg,
/* If ray from camera enters the volume, this volume shouldn't
* be added to the stack on exit.
*/
- enclosed_volumes[enclosed_index++] = sd.object;
+ enclosed_volumes[enclosed_index++] = stack_sd->object;
}
/* Move ray forward. */
- volume_ray.P = ray_offset(sd.P, -sd.Ng);
+ volume_ray.P = ray_offset(stack_sd->P, -stack_sd->Ng);
++step;
}
#endif
@@ -1190,6 +1188,7 @@ ccl_device void kernel_volume_stack_enter_exit(KernelGlobals *kg, ShaderData *sd
#ifdef __SUBSURFACE__
ccl_device void kernel_volume_stack_update_for_subsurface(KernelGlobals *kg,
+ ShaderData *stack_sd,
Ray *ray,
VolumeStack *stack)
{
@@ -1210,27 +1209,28 @@ ccl_device void kernel_volume_stack_update_for_subsurface(KernelGlobals *kg,
qsort(hits, num_hits, sizeof(Intersection), intersections_compare);
for(uint hit = 0; hit < num_hits; ++hit, ++isect) {
- ShaderData sd;
- shader_setup_from_ray(kg, &sd, isect, &volume_ray);
- kernel_volume_stack_enter_exit(kg, &sd, stack);
+ shader_setup_from_ray(kg, stack_sd, isect, &volume_ray);
+ kernel_volume_stack_enter_exit(kg, stack_sd, stack);
}
}
# else
Intersection isect;
int step = 0;
+ float3 Pend = ray->P + ray->D*ray->t;
while(step < 2 * VOLUME_STACK_SIZE &&
scene_intersect_volume(kg,
&volume_ray,
&isect,
PATH_RAY_ALL_VISIBILITY))
{
- ShaderData sd;
- shader_setup_from_ray(kg, &sd, &isect, &volume_ray);
- kernel_volume_stack_enter_exit(kg, &sd, stack);
+ shader_setup_from_ray(kg, stack_sd, &isect, &volume_ray);
+ kernel_volume_stack_enter_exit(kg, stack_sd, stack);
/* Move ray forward. */
- volume_ray.P = ray_offset(sd.P, -sd.Ng);
- volume_ray.t -= sd.ray_length;
+ volume_ray.P = ray_offset(stack_sd->P, -stack_sd->Ng);
+ if(volume_ray.t != FLT_MAX) {
+ volume_ray.D = normalize_len(Pend - volume_ray.P, &volume_ray.t);
+ }
++step;
}
# endif
diff --git a/intern/cycles/kernel/kernels/cpu/kernel.cpp b/intern/cycles/kernel/kernels/cpu/kernel.cpp
index 365ce891354..d8a83f69685 100644
--- a/intern/cycles/kernel/kernels/cpu/kernel.cpp
+++ b/intern/cycles/kernel/kernels/cpu/kernel.cpp
@@ -95,7 +95,7 @@ void kernel_tex_copy(KernelGlobals *kg,
int id = atoi(name + strlen("__tex_image_float4_"));
int array_index = id;
- if(array_index >= 0 && array_index < TEX_NUM_FLOAT4_IMAGES_CPU) {
+ if(array_index >= 0 && array_index < TEX_NUM_FLOAT4_CPU) {
tex = &kg->texture_float4_images[array_index];
}
@@ -109,9 +109,9 @@ void kernel_tex_copy(KernelGlobals *kg,
else if(strstr(name, "__tex_image_float")) {
texture_image_float *tex = NULL;
int id = atoi(name + strlen("__tex_image_float_"));
- int array_index = id - TEX_IMAGE_FLOAT_START_CPU;
+ int array_index = id - TEX_START_FLOAT_CPU;
- if(array_index >= 0 && array_index < TEX_NUM_FLOAT_IMAGES_CPU) {
+ if(array_index >= 0 && array_index < TEX_NUM_FLOAT_CPU) {
tex = &kg->texture_float_images[array_index];
}
@@ -125,9 +125,9 @@ void kernel_tex_copy(KernelGlobals *kg,
else if(strstr(name, "__tex_image_byte4")) {
texture_image_uchar4 *tex = NULL;
int id = atoi(name + strlen("__tex_image_byte4_"));
- int array_index = id - TEX_IMAGE_BYTE4_START_CPU;
+ int array_index = id - TEX_START_BYTE4_CPU;
- if(array_index >= 0 && array_index < TEX_NUM_BYTE4_IMAGES_CPU) {
+ if(array_index >= 0 && array_index < TEX_NUM_BYTE4_CPU) {
tex = &kg->texture_byte4_images[array_index];
}
@@ -141,9 +141,9 @@ void kernel_tex_copy(KernelGlobals *kg,
else if(strstr(name, "__tex_image_byte")) {
texture_image_uchar *tex = NULL;
int id = atoi(name + strlen("__tex_image_byte_"));
- int array_index = id - TEX_IMAGE_BYTE_START_CPU;
+ int array_index = id - TEX_START_BYTE_CPU;
- if(array_index >= 0 && array_index < TEX_NUM_BYTE_IMAGES_CPU) {
+ if(array_index >= 0 && array_index < TEX_NUM_BYTE_CPU) {
tex = &kg->texture_byte_images[array_index];
}
diff --git a/intern/cycles/kernel/kernels/cpu/kernel_cpu_image.h b/intern/cycles/kernel/kernels/cpu/kernel_cpu_image.h
index 4807f96a0df..b10861ab857 100644
--- a/intern/cycles/kernel/kernels/cpu/kernel_cpu_image.h
+++ b/intern/cycles/kernel/kernels/cpu/kernel_cpu_image.h
@@ -23,24 +23,24 @@ CCL_NAMESPACE_BEGIN
ccl_device float4 kernel_tex_image_interp_impl(KernelGlobals *kg, int tex, float x, float y)
{
- if(tex >= TEX_IMAGE_BYTE_START_CPU)
- return kg->texture_byte_images[tex - TEX_IMAGE_BYTE_START_CPU].interp(x, y);
- else if(tex >= TEX_IMAGE_FLOAT_START_CPU)
- return kg->texture_float_images[tex - TEX_IMAGE_FLOAT_START_CPU].interp(x, y);
- else if(tex >= TEX_IMAGE_BYTE4_START_CPU)
- return kg->texture_byte4_images[tex - TEX_IMAGE_BYTE4_START_CPU].interp(x, y);
+ if(tex >= TEX_START_BYTE_CPU)
+ return kg->texture_byte_images[tex - TEX_START_BYTE_CPU].interp(x, y);
+ else if(tex >= TEX_START_FLOAT_CPU)
+ return kg->texture_float_images[tex - TEX_START_FLOAT_CPU].interp(x, y);
+ else if(tex >= TEX_START_BYTE4_CPU)
+ return kg->texture_byte4_images[tex - TEX_START_BYTE4_CPU].interp(x, y);
else
return kg->texture_float4_images[tex].interp(x, y);
}
ccl_device float4 kernel_tex_image_interp_3d_impl(KernelGlobals *kg, int tex, float x, float y, float z)
{
- if(tex >= TEX_IMAGE_BYTE_START_CPU)
- return kg->texture_byte_images[tex - TEX_IMAGE_BYTE_START_CPU].interp_3d(x, y, z);
- else if(tex >= TEX_IMAGE_FLOAT_START_CPU)
- return kg->texture_float_images[tex - TEX_IMAGE_FLOAT_START_CPU].interp_3d(x, y, z);
- else if(tex >= TEX_IMAGE_BYTE4_START_CPU)
- return kg->texture_byte4_images[tex - TEX_IMAGE_BYTE4_START_CPU].interp_3d(x, y, z);
+ if(tex >= TEX_START_BYTE_CPU)
+ return kg->texture_byte_images[tex - TEX_START_BYTE_CPU].interp_3d(x, y, z);
+ else if(tex >= TEX_START_FLOAT_CPU)
+ return kg->texture_float_images[tex - TEX_START_FLOAT_CPU].interp_3d(x, y, z);
+ else if(tex >= TEX_START_BYTE4_CPU)
+ return kg->texture_byte4_images[tex - TEX_START_BYTE4_CPU].interp_3d(x, y, z);
else
return kg->texture_float4_images[tex].interp_3d(x, y, z);
@@ -48,12 +48,12 @@ ccl_device float4 kernel_tex_image_interp_3d_impl(KernelGlobals *kg, int tex, fl
ccl_device float4 kernel_tex_image_interp_3d_ex_impl(KernelGlobals *kg, int tex, float x, float y, float z, int interpolation)
{
- if(tex >= TEX_IMAGE_BYTE_START_CPU)
- return kg->texture_byte_images[tex - TEX_IMAGE_BYTE_START_CPU].interp_3d_ex(x, y, z, interpolation);
- else if(tex >= TEX_IMAGE_FLOAT_START_CPU)
- return kg->texture_float_images[tex - TEX_IMAGE_FLOAT_START_CPU].interp_3d_ex(x, y, z, interpolation);
- else if(tex >= TEX_IMAGE_BYTE4_START_CPU)
- return kg->texture_byte4_images[tex - TEX_IMAGE_BYTE4_START_CPU].interp_3d_ex(x, y, z, interpolation);
+ if(tex >= TEX_START_BYTE_CPU)
+ return kg->texture_byte_images[tex - TEX_START_BYTE_CPU].interp_3d_ex(x, y, z, interpolation);
+ else if(tex >= TEX_START_FLOAT_CPU)
+ return kg->texture_float_images[tex - TEX_START_FLOAT_CPU].interp_3d_ex(x, y, z, interpolation);
+ else if(tex >= TEX_START_BYTE4_CPU)
+ return kg->texture_byte4_images[tex - TEX_START_BYTE4_CPU].interp_3d_ex(x, y, z, interpolation);
else
return kg->texture_float4_images[tex].interp_3d_ex(x, y, z, interpolation);
}
diff --git a/intern/cycles/kernel/shaders/node_brick_texture.osl b/intern/cycles/kernel/shaders/node_brick_texture.osl
index 35e01178ba8..d5e0a7d4c8c 100644
--- a/intern/cycles/kernel/shaders/node_brick_texture.osl
+++ b/intern/cycles/kernel/shaders/node_brick_texture.osl
@@ -59,10 +59,10 @@ float brick(point p, float mortar_size, float bias,
shader node_brick_texture(
int use_mapping = 0,
matrix mapping = matrix(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0),
- float Offset = 0.5,
- int OffsetFrequency = 2,
- float Squash = 1.0,
- int SquashFrequency = 1,
+ float offset = 0.5,
+ int offset_frequency = 2,
+ float squash = 1.0,
+ int squash_frequency = 1,
point Vector = P,
color Color1 = 0.2,
color Color2 = 0.8,
@@ -84,7 +84,7 @@ shader node_brick_texture(
color Col = Color1;
Fac = brick(p * Scale, MortarSize, Bias, BrickWidth, RowHeight,
- Offset, OffsetFrequency, Squash, SquashFrequency, tint);
+ offset, offset_frequency, squash, squash_frequency, tint);
if (Fac != 1.0) {
float facm = 1.0 - tint;
diff --git a/intern/cycles/kernel/shaders/node_convert_from_color.osl b/intern/cycles/kernel/shaders/node_convert_from_color.osl
index 44074317f42..e95a17f6fa1 100644
--- a/intern/cycles/kernel/shaders/node_convert_from_color.osl
+++ b/intern/cycles/kernel/shaders/node_convert_from_color.osl
@@ -17,18 +17,18 @@
#include "stdosl.h"
shader node_convert_from_color(
- color Color = 0.0,
- output string String = "",
- output float Val = 0.0,
- output int ValInt = 0,
- output vector Vector = vector(0.0, 0.0, 0.0),
- output point Point = point(0.0, 0.0, 0.0),
- output normal Normal = normal(0.0, 0.0, 0.0))
+ color value_color = 0.0,
+ output string value_string = "",
+ output float value_float = 0.0,
+ output int value_int = 0,
+ output vector value_vector = vector(0.0, 0.0, 0.0),
+ output point value_point = point(0.0, 0.0, 0.0),
+ output normal value_normal = normal(0.0, 0.0, 0.0))
{
- Val = Color[0] * 0.2126 + Color[1] * 0.7152 + Color[2] * 0.0722;
- ValInt = (int)(Color[0] * 0.2126 + Color[1] * 0.7152 + Color[2] * 0.0722);
- Vector = vector(Color[0], Color[1], Color[2]);
- Point = point(Color[0], Color[1], Color[2]);
- Normal = normal(Color[0], Color[1], Color[2]);
+ value_float = value_color[0] * 0.2126 + value_color[1] * 0.7152 + value_color[2] * 0.0722;
+ value_int = (int)(value_color[0] * 0.2126 + value_color[1] * 0.7152 + value_color[2] * 0.0722);
+ value_vector = vector(value_color[0], value_color[1], value_color[2]);
+ value_point = point(value_color[0], value_color[1], value_color[2]);
+ value_normal = normal(value_color[0], value_color[1], value_color[2]);
}
diff --git a/intern/cycles/kernel/shaders/node_convert_from_float.osl b/intern/cycles/kernel/shaders/node_convert_from_float.osl
index fc5c79c4c64..a5c2e3b26ad 100644
--- a/intern/cycles/kernel/shaders/node_convert_from_float.osl
+++ b/intern/cycles/kernel/shaders/node_convert_from_float.osl
@@ -17,18 +17,18 @@
#include "stdosl.h"
shader node_convert_from_float(
- float Val = 0.0,
- output string String = "",
- output int ValInt = 0,
- output color Color = 0.0,
- output vector Vector = vector(0.0, 0.0, 0.0),
- output point Point = point(0.0, 0.0, 0.0),
- output normal Normal = normal(0.0, 0.0, 0.0))
+ float value_float = 0.0,
+ output string value_string = "",
+ output int value_int = 0,
+ output color value_color = 0.0,
+ output vector value_vector = vector(0.0, 0.0, 0.0),
+ output point value_point = point(0.0, 0.0, 0.0),
+ output normal value_normal = normal(0.0, 0.0, 0.0))
{
- ValInt = (int)Val;
- Color = color(Val, Val, Val);
- Vector = vector(Val, Val, Val);
- Point = point(Val, Val, Val);
- Normal = normal(Val, Val, Val);
+ value_int = (int)value_float;
+ value_color = color(value_float, value_float, value_float);
+ value_vector = vector(value_float, value_float, value_float);
+ value_point = point(value_float, value_float, value_float);
+ value_normal = normal(value_float, value_float, value_float);
}
diff --git a/intern/cycles/kernel/shaders/node_convert_from_int.osl b/intern/cycles/kernel/shaders/node_convert_from_int.osl
index 3c3785ebc0d..0e6ae711210 100644
--- a/intern/cycles/kernel/shaders/node_convert_from_int.osl
+++ b/intern/cycles/kernel/shaders/node_convert_from_int.osl
@@ -17,19 +17,19 @@
#include "stdosl.h"
shader node_convert_from_int(
- int ValInt = 0,
- output string String = "",
- output float Val = 0.0,
- output color Color = 0.0,
- output vector Vector = vector(0.0, 0.0, 0.0),
- output point Point = point(0.0, 0.0, 0.0),
- output normal Normal = normal(0.0, 0.0, 0.0))
+ int value_int = 0,
+ output string value_string = "",
+ output float value_float = 0.0,
+ output color value_color = 0.0,
+ output vector value_vector = vector(0.0, 0.0, 0.0),
+ output point value_point = point(0.0, 0.0, 0.0),
+ output normal value_normal = normal(0.0, 0.0, 0.0))
{
- float f = (float)ValInt;
- Val = f;
- Color = color(f, f, f);
- Vector = vector(f, f, f);
- Point = point(f, f, f);
- Normal = normal(f, f, f);
+ float f = (float)value_int;
+ value_float = f;
+ value_color = color(f, f, f);
+ value_vector = vector(f, f, f);
+ value_point = point(f, f, f);
+ value_normal = normal(f, f, f);
}
diff --git a/intern/cycles/kernel/shaders/node_convert_from_normal.osl b/intern/cycles/kernel/shaders/node_convert_from_normal.osl
index 8ecc56ac8ce..7fffa7f6169 100644
--- a/intern/cycles/kernel/shaders/node_convert_from_normal.osl
+++ b/intern/cycles/kernel/shaders/node_convert_from_normal.osl
@@ -17,18 +17,18 @@
#include "stdosl.h"
shader node_convert_from_normal(
- normal Normal = normal(0.0, 0.0, 0.0),
- output string String = "",
- output float Val = 0.0,
- output int ValInt = 0,
- output vector Vector = vector(0.0, 0.0, 0.0),
- output color Color = 0.0,
- output point Point = point(0.0, 0.0, 0.0))
+ normal value_normal = normal(0.0, 0.0, 0.0),
+ output string value_string = "",
+ output float value_float = 0.0,
+ output int value_int = 0,
+ output vector value_vector = vector(0.0, 0.0, 0.0),
+ output color value_color = 0.0,
+ output point value_point = point(0.0, 0.0, 0.0))
{
- Val = (Normal[0] + Normal[1] + Normal[2]) * (1.0 / 3.0);
- ValInt = (int)((Normal[0] + Normal[1] + Normal[2]) * (1.0 / 3.0));
- Vector = vector(Normal[0], Normal[1], Normal[2]);
- Color = color(Normal[0], Normal[1], Normal[2]);
- Point = point(Normal[0], Normal[1], Normal[2]);
+ value_float = (value_normal[0] + value_normal[1] + value_normal[2]) * (1.0 / 3.0);
+ value_int = (int)((value_normal[0] + value_normal[1] + value_normal[2]) * (1.0 / 3.0));
+ value_vector = vector(value_normal[0], value_normal[1], value_normal[2]);
+ value_color = color(value_normal[0], value_normal[1], value_normal[2]);
+ value_point = point(value_normal[0], value_normal[1], value_normal[2]);
}
diff --git a/intern/cycles/kernel/shaders/node_convert_from_point.osl b/intern/cycles/kernel/shaders/node_convert_from_point.osl
index e5913b7a1e4..9e4930296bb 100644
--- a/intern/cycles/kernel/shaders/node_convert_from_point.osl
+++ b/intern/cycles/kernel/shaders/node_convert_from_point.osl
@@ -17,18 +17,18 @@
#include "stdosl.h"
shader node_convert_from_point(
- point Point = point(0.0, 0.0, 0.0),
- output string String = "",
- output float Val = 0.0,
- output int ValInt = 0,
- output vector Vector = vector(0.0, 0.0, 0.0),
- output color Color = 0.0,
- output normal Normal = normal(0.0, 0.0, 0.0))
+ point value_point = point(0.0, 0.0, 0.0),
+ output string value_string = "",
+ output float value_float = 0.0,
+ output int value_int = 0,
+ output vector value_vector = vector(0.0, 0.0, 0.0),
+ output color value_color = 0.0,
+ output normal value_normal = normal(0.0, 0.0, 0.0))
{
- Val = (Point[0] + Point[1] + Point[2]) * (1.0 / 3.0);
- ValInt = (int)((Normal[0] + Normal[1] + Normal[2]) * (1.0 / 3.0));
- Vector = vector(Point[0], Point[1], Point[2]);
- Color = color(Point[0], Point[1], Point[2]);
- Normal = normal(Point[0], Point[1], Point[2]);
+ value_float = (value_point[0] + value_point[1] + value_point[2]) * (1.0 / 3.0);
+ value_int = (int)((value_normal[0] + value_normal[1] + value_normal[2]) * (1.0 / 3.0));
+ value_vector = vector(value_point[0], value_point[1], value_point[2]);
+ value_color = color(value_point[0], value_point[1], value_point[2]);
+ value_normal = normal(value_point[0], value_point[1], value_point[2]);
}
diff --git a/intern/cycles/kernel/shaders/node_convert_from_string.osl b/intern/cycles/kernel/shaders/node_convert_from_string.osl
index 0466734277b..cbc6653eada 100644
--- a/intern/cycles/kernel/shaders/node_convert_from_string.osl
+++ b/intern/cycles/kernel/shaders/node_convert_from_string.osl
@@ -17,13 +17,13 @@
#include "stdosl.h"
shader node_convert_from_string(
- string String = "",
- output color Color = color(0.0, 0.0, 0.0),
- output float Val = 0.0,
- output int ValInt = 0,
- output vector Vector = vector(0.0, 0.0, 0.0),
- output point Point = point(0.0, 0.0, 0.0),
- output normal Normal = normal(0.0, 0.0, 0.0))
+ string value_string = "",
+ output color value_color = color(0.0, 0.0, 0.0),
+ output float value_float = 0.0,
+ output int value_int = 0,
+ output vector value_vector = vector(0.0, 0.0, 0.0),
+ output point value_point = point(0.0, 0.0, 0.0),
+ output normal value_normal = normal(0.0, 0.0, 0.0))
{
}
diff --git a/intern/cycles/kernel/shaders/node_convert_from_vector.osl b/intern/cycles/kernel/shaders/node_convert_from_vector.osl
index 79c5cb04550..8bdca469b90 100644
--- a/intern/cycles/kernel/shaders/node_convert_from_vector.osl
+++ b/intern/cycles/kernel/shaders/node_convert_from_vector.osl
@@ -17,18 +17,18 @@
#include "stdosl.h"
shader node_convert_from_vector(
- vector Vector = vector(0.0, 0.0, 0.0),
- output string String = "",
- output float Val = 0.0,
- output int ValInt = 0,
- output color Color = color(0.0, 0.0, 0.0),
- output point Point = point(0.0, 0.0, 0.0),
- output normal Normal = normal(0.0, 0.0, 0.0))
+ vector value_vector = vector(0.0, 0.0, 0.0),
+ output string value_string = "",
+ output float value_float = 0.0,
+ output int value_int = 0,
+ output color value_color = color(0.0, 0.0, 0.0),
+ output point value_point = point(0.0, 0.0, 0.0),
+ output normal value_normal = normal(0.0, 0.0, 0.0))
{
- Val = (Vector[0] + Vector[1] + Vector[2]) * (1.0 / 3.0);
- ValInt = (int)((Normal[0] + Normal[1] + Normal[2]) * (1.0 / 3.0));
- Color = color(Vector[0], Vector[1], Vector[2]);
- Point = point(Vector[0], Vector[1], Vector[2]);
- Normal = normal(Vector[0], Vector[1], Vector[2]);
+ value_float = (value_vector[0] + value_vector[1] + value_vector[2]) * (1.0 / 3.0);
+ value_int = (int)((value_normal[0] + value_normal[1] + value_normal[2]) * (1.0 / 3.0));
+ value_color = color(value_vector[0], value_vector[1], value_vector[2]);
+ value_point = point(value_vector[0], value_vector[1], value_vector[2]);
+ value_normal = normal(value_vector[0], value_vector[1], value_vector[2]);
}
diff --git a/intern/cycles/kernel/shaders/node_gradient_texture.osl b/intern/cycles/kernel/shaders/node_gradient_texture.osl
index 52b49688ab3..69e2ee54bdf 100644
--- a/intern/cycles/kernel/shaders/node_gradient_texture.osl
+++ b/intern/cycles/kernel/shaders/node_gradient_texture.osl
@@ -63,7 +63,7 @@ float gradient(point p, string type)
shader node_gradient_texture(
int use_mapping = 0,
matrix mapping = matrix(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0),
- string Type = "Linear",
+ string type = "Linear",
point Vector = P,
output float Fac = 0.0,
output color Color = 0.0)
@@ -73,7 +73,7 @@ shader node_gradient_texture(
if (use_mapping)
p = transform(mapping, p);
- Fac = gradient(p, Type);
+ Fac = gradient(p, type);
Color = color(Fac, Fac, Fac);
}
diff --git a/intern/cycles/kernel/shaders/node_image_texture.osl b/intern/cycles/kernel/shaders/node_image_texture.osl
index d3a347b70db..d09174ff5d3 100644
--- a/intern/cycles/kernel/shaders/node_image_texture.osl
+++ b/intern/cycles/kernel/shaders/node_image_texture.osl
@@ -62,9 +62,9 @@ color image_texture_lookup(string filename,
int use_alpha,
int is_float,
string interpolation,
- string wrap)
+ string extension)
{
- color rgb = (color)texture(filename, u, 1.0 - v, "wrap", wrap, "interp", interpolation, "alpha", Alpha);
+ color rgb = (color)texture(filename, u, 1.0 - v, "wrap", extension, "interp", interpolation, "alpha", Alpha);
if (use_alpha) {
rgb = color_unpremultiply(rgb, Alpha);
diff --git a/intern/cycles/kernel/shaders/node_magic_texture.osl b/intern/cycles/kernel/shaders/node_magic_texture.osl
index 55992e3494c..8d6af391e04 100644
--- a/intern/cycles/kernel/shaders/node_magic_texture.osl
+++ b/intern/cycles/kernel/shaders/node_magic_texture.osl
@@ -93,7 +93,7 @@ color magic(point p, int n, float distortion)
shader node_magic_texture(
int use_mapping = 0,
matrix mapping = matrix(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0),
- int Depth = 2,
+ int depth = 2,
float Distortion = 5.0,
float Scale = 5.0,
point Vector = P,
@@ -105,7 +105,7 @@ shader node_magic_texture(
if (use_mapping)
p = transform(mapping, p);
- Color = magic(p * Scale, Depth, Distortion);
+ Color = magic(p * Scale, depth, Distortion);
Fac = (Color[0] + Color[1] + Color[2]) * (1.0 / 3.0);
}
diff --git a/intern/cycles/kernel/shaders/node_math.osl b/intern/cycles/kernel/shaders/node_math.osl
index 7eef97fd7e8..85eac0b97a6 100644
--- a/intern/cycles/kernel/shaders/node_math.osl
+++ b/intern/cycles/kernel/shaders/node_math.osl
@@ -50,7 +50,7 @@ float safe_log(float a, float b)
shader node_math(
string type = "Add",
- int Clamp = 0,
+ int use_clamp = 0,
float Value1 = 0.0,
float Value2 = 0.0,
output float Value = 0.0)
@@ -96,7 +96,7 @@ shader node_math(
else if (type == "Absolute")
Value = fabs(Value1);
- if (Clamp)
+ if (use_clamp)
Value = clamp(Value, 0.0, 1.0);
}
diff --git a/intern/cycles/kernel/shaders/node_mix.osl b/intern/cycles/kernel/shaders/node_mix.osl
index 9ef58e4cbba..4a66748ed6a 100644
--- a/intern/cycles/kernel/shaders/node_mix.osl
+++ b/intern/cycles/kernel/shaders/node_mix.osl
@@ -278,7 +278,7 @@ color node_mix_clamp(color col)
shader node_mix(
string type = "Mix",
- int Clamp = 0,
+ int use_clamp = 0,
float Fac = 0.5,
color Color1 = 0.0,
color Color2 = 0.0,
@@ -323,7 +323,7 @@ shader node_mix(
if (type == "Linear Light")
Color = node_mix_linear(t, Color1, Color2);
- if (Clamp)
+ if (use_clamp)
Color = node_mix_clamp(Color);
}
diff --git a/intern/cycles/kernel/shaders/node_musgrave_texture.osl b/intern/cycles/kernel/shaders/node_musgrave_texture.osl
index 4f95dec910a..2f9f62bcfe8 100644
--- a/intern/cycles/kernel/shaders/node_musgrave_texture.osl
+++ b/intern/cycles/kernel/shaders/node_musgrave_texture.osl
@@ -187,7 +187,7 @@ float noise_musgrave_ridged_multi_fractal(point p, float H, float lacunarity,
shader node_musgrave_texture(
int use_mapping = 0,
matrix mapping = matrix(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0),
- string Type = "fBM",
+ string type = "fBM",
float Dimension = 2.0,
float Lacunarity = 1.0,
float Detail = 2.0,
@@ -210,15 +210,15 @@ shader node_musgrave_texture(
p = p * Scale;
- if (Type == "Multifractal")
+ if (type == "Multifractal")
Fac = intensity * noise_musgrave_multi_fractal(p, dimension, lacunarity, octaves);
- else if (Type == "fBM")
+ else if (type == "fBM")
Fac = intensity * noise_musgrave_fBm(p, dimension, lacunarity, octaves);
- else if (Type == "Hybrid Multifractal")
+ else if (type == "Hybrid Multifractal")
Fac = intensity * noise_musgrave_hybrid_multi_fractal(p, dimension, lacunarity, octaves, Offset, Gain);
- else if (Type == "Ridged Multifractal")
+ else if (type == "Ridged Multifractal")
Fac = intensity * noise_musgrave_ridged_multi_fractal(p, dimension, lacunarity, octaves, Offset, Gain);
- else if (Type == "Hetero Terrain")
+ else if (type == "Hetero Terrain")
Fac = intensity * noise_musgrave_hetero_terrain(p, dimension, lacunarity, octaves, Offset);
Color = color(Fac, Fac, Fac);
diff --git a/intern/cycles/kernel/shaders/node_normal.osl b/intern/cycles/kernel/shaders/node_normal.osl
index 2d04978fc72..7307971eddd 100644
--- a/intern/cycles/kernel/shaders/node_normal.osl
+++ b/intern/cycles/kernel/shaders/node_normal.osl
@@ -17,12 +17,12 @@
#include "stdosl.h"
shader node_normal(
- normal Direction = normal(0.0, 0.0, 0.0),
+ normal direction = normal(0.0, 0.0, 0.0),
normal NormalIn = normal(0.0, 0.0, 0.0),
output normal NormalOut = normal(0.0, 0.0, 0.0),
output float Dot = 1.0)
{
- NormalOut = normalize(Direction);
+ NormalOut = normalize(direction);
Dot = dot(NormalOut, normalize(NormalIn));
}
diff --git a/intern/cycles/kernel/shaders/node_rgb_ramp.osl b/intern/cycles/kernel/shaders/node_rgb_ramp.osl
index 2ab6b6778b7..c0ae74d6b33 100644
--- a/intern/cycles/kernel/shaders/node_rgb_ramp.osl
+++ b/intern/cycles/kernel/shaders/node_rgb_ramp.osl
@@ -20,7 +20,7 @@
shader node_rgb_ramp(
color ramp_color[] = {0.0},
float ramp_alpha[] = {0.0},
- int ramp_interpolate = 1,
+ int interpolate = 1,
float Fac = 0.0,
output color Color = 0.0,
@@ -38,7 +38,7 @@ shader node_rgb_ramp(
Color = ramp_color[i];
Alpha = ramp_alpha[i];
- if (ramp_interpolate && t > 0.0) {
+ if (interpolate && t > 0.0) {
Color = (1.0 - t) * Color + t * ramp_color[i + 1];
Alpha = (1.0 - t) * Alpha + t * ramp_alpha[i + 1];
}
diff --git a/intern/cycles/kernel/shaders/node_subsurface_scattering.osl b/intern/cycles/kernel/shaders/node_subsurface_scattering.osl
index a67333c5d4e..1877c7e595f 100644
--- a/intern/cycles/kernel/shaders/node_subsurface_scattering.osl
+++ b/intern/cycles/kernel/shaders/node_subsurface_scattering.osl
@@ -22,13 +22,13 @@ shader node_subsurface_scattering(
vector Radius = vector(0.1, 0.1, 0.1),
float TextureBlur = 0.0,
float Sharpness = 0.0,
- string Falloff = "Cubic",
+ string falloff = "Cubic",
normal Normal = N,
output closure color BSSRDF = 0)
{
- if (Falloff == "Gaussian")
+ if (falloff == "Gaussian")
BSSRDF = Color * bssrdf_gaussian(Normal, Scale * Radius, TextureBlur);
- else if (Falloff == "Cubic")
+ else if (falloff == "Cubic")
BSSRDF = Color * bssrdf_cubic(Normal, Scale * Radius, TextureBlur, Sharpness);
else
BSSRDF = Color * bssrdf_burley(Normal, Scale * Radius, TextureBlur, Color);
diff --git a/intern/cycles/kernel/shaders/node_voronoi_texture.osl b/intern/cycles/kernel/shaders/node_voronoi_texture.osl
index 29e143ae207..bacdd593c7c 100644
--- a/intern/cycles/kernel/shaders/node_voronoi_texture.osl
+++ b/intern/cycles/kernel/shaders/node_voronoi_texture.osl
@@ -22,7 +22,7 @@
shader node_voronoi_texture(
int use_mapping = 0,
matrix mapping = matrix(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0),
- string Coloring = "Intensity",
+ string coloring = "Intensity",
float Scale = 5.0,
point Vector = P,
output float Fac = 0.0,
@@ -40,7 +40,7 @@ shader node_voronoi_texture(
voronoi(p * Scale, 1.0, da, pa);
/* Colored output */
- if (Coloring == "Intensity") {
+ if (coloring == "Intensity") {
Fac = fabs(da[0]);
Color = color(Fac);
}
diff --git a/intern/cycles/kernel/shaders/node_wave_texture.osl b/intern/cycles/kernel/shaders/node_wave_texture.osl
index 59f61d3b46a..a07742faefc 100644
--- a/intern/cycles/kernel/shaders/node_wave_texture.osl
+++ b/intern/cycles/kernel/shaders/node_wave_texture.osl
@@ -48,8 +48,8 @@ float wave(point p, string type, string profile, float detail, float distortion,
shader node_wave_texture(
int use_mapping = 0,
matrix mapping = matrix(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0),
- string Type = "Bands",
- string Profile = "Sine",
+ string type = "Bands",
+ string profile = "Sine",
float Scale = 5.0,
float Distortion = 0.0,
float Detail = 2.0,
@@ -63,7 +63,7 @@ shader node_wave_texture(
if (use_mapping)
p = transform(mapping, p);
- Fac = wave(p * Scale, Type, Profile, Detail, Distortion, DetailScale);
+ Fac = wave(p * Scale, type, profile, Detail, Distortion, DetailScale);
Color = Fac;
}
diff --git a/intern/cycles/kernel/split/kernel_background_buffer_update.h b/intern/cycles/kernel/split/kernel_background_buffer_update.h
index 3d12a3dd993..f42d0a985bb 100644
--- a/intern/cycles/kernel/split/kernel_background_buffer_update.h
+++ b/intern/cycles/kernel/split/kernel_background_buffer_update.h
@@ -157,7 +157,7 @@ ccl_device char kernel_background_buffer_update(
if(IS_STATE(ray_state, ray_index, RAY_HIT_BACKGROUND)) {
#ifdef __BACKGROUND__
/* sample background shader */
- float3 L_background = indirect_background(kg, state, ray);
+ float3 L_background = indirect_background(kg, kg->sd_input, state, ray);
path_radiance_accum_background(L, (*throughput), L_background, state->bounce);
#endif
ASSIGN_RAY_STATE(ray_state, ray_index, RAY_UPDATE_BUFFER);
@@ -226,7 +226,7 @@ ccl_device char kernel_background_buffer_update(
*throughput = make_float3(1.0f, 1.0f, 1.0f);
*L_transparent = 0.0f;
path_radiance_init(L, kernel_data.film.use_light_pass);
- path_state_init(kg, state, rng, sample, ray);
+ path_state_init(kg, kg->sd_input, state, rng, sample, ray);
#ifdef __KERNEL_DEBUG__
debug_data_init(debug_data);
#endif
diff --git a/intern/cycles/kernel/split/kernel_data_init.h b/intern/cycles/kernel/split/kernel_data_init.h
index 9891391a3a3..e3dbc43757e 100644
--- a/intern/cycles/kernel/split/kernel_data_init.h
+++ b/intern/cycles/kernel/split/kernel_data_init.h
@@ -207,6 +207,7 @@ ccl_device void kernel_data_init(
L_transparent_coop[ray_index] = 0.0f;
path_radiance_init(&PathRadiance_coop[ray_index], kernel_data.film.use_light_pass);
path_state_init(kg,
+ kg->sd_input,
&PathState_coop[ray_index],
&rng_coop[ray_index],
my_sample,
diff --git a/intern/cycles/kernel/split/kernel_direct_lighting.h b/intern/cycles/kernel/split/kernel_direct_lighting.h
index c7a2aa6426c..ebe91097496 100644
--- a/intern/cycles/kernel/split/kernel_direct_lighting.h
+++ b/intern/cycles/kernel/split/kernel_direct_lighting.h
@@ -88,7 +88,7 @@ ccl_device char kernel_direct_lighting(
BsdfEval L_light;
bool is_lamp;
- if(direct_emission(kg, sd, &ls, state, &light_ray, &L_light, &is_lamp)) {
+ if(direct_emission(kg, sd, kg->sd_input, &ls, state, &light_ray, &L_light, &is_lamp)) {
/* Write intermediate data to global memory to access from
* the next kernel.
*/
diff --git a/intern/cycles/kernel/split/kernel_lamp_emission.h b/intern/cycles/kernel/split/kernel_lamp_emission.h
index dc3b4b34d4e..3bd0e361078 100644
--- a/intern/cycles/kernel/split/kernel_lamp_emission.h
+++ b/intern/cycles/kernel/split/kernel_lamp_emission.h
@@ -74,7 +74,7 @@ ccl_device void kernel_lamp_emission(
/* intersect with lamp */
float3 emission;
- if(indirect_lamp_emission(kg, state, &light_ray, &emission)) {
+ if(indirect_lamp_emission(kg, kg->sd_input, state, &light_ray, &emission)) {
path_radiance_accum_emission(L, throughput, emission, state->bounce);
}
}
diff --git a/intern/cycles/kernel/split/kernel_shadow_blocked.h b/intern/cycles/kernel/split/kernel_shadow_blocked.h
index 0c989861eef..6153af47f96 100644
--- a/intern/cycles/kernel/split/kernel_shadow_blocked.h
+++ b/intern/cycles/kernel/split/kernel_shadow_blocked.h
@@ -71,6 +71,7 @@ ccl_device void kernel_shadow_blocked(
float3 shadow;
update_path_radiance = !(shadow_blocked(kg,
+ kg->sd_input,
state,
light_ray_global,
&shadow));
diff --git a/intern/cycles/kernel/svm/svm_closure.h b/intern/cycles/kernel/svm/svm_closure.h
index 88397005b49..65512a0105c 100644
--- a/intern/cycles/kernel/svm/svm_closure.h
+++ b/intern/cycles/kernel/svm/svm_closure.h
@@ -365,8 +365,12 @@ ccl_device void svm_node_closure_bsdf(KernelGlobals *kg, ShaderData *sd, float *
}
break;
}
- case CLOSURE_BSDF_DIFFUSE_TOON_ID:
- case CLOSURE_BSDF_GLOSSY_TOON_ID: {
+ case CLOSURE_BSDF_GLOSSY_TOON_ID:
+#ifdef __CAUSTICS_TRICKS__
+ if(!kernel_data.integrator.caustics_reflective && (path_flag & PATH_RAY_DIFFUSE))
+ break;
+#endif
+ case CLOSURE_BSDF_DIFFUSE_TOON_ID: {
ShaderClosure *sc = svm_node_closure_get_bsdf(sd, mix_weight);
if(sc) {
diff --git a/intern/cycles/kernel/svm/svm_image.h b/intern/cycles/kernel/svm/svm_image.h
index 92d2b36bbb1..3d9ab405849 100644
--- a/intern/cycles/kernel/svm/svm_image.h
+++ b/intern/cycles/kernel/svm/svm_image.h
@@ -18,15 +18,15 @@ CCL_NAMESPACE_BEGIN
/* Float4 textures on various devices. */
#if defined(__KERNEL_CPU__)
-# define TEX_NUM_FLOAT4_IMAGES TEX_NUM_FLOAT4_IMAGES_CPU
+# define TEX_NUM_FLOAT4_IMAGES TEX_NUM_FLOAT4_CPU
#elif defined(__KERNEL_CUDA__)
# if __CUDA_ARCH__ < 300
-# define TEX_NUM_FLOAT4_IMAGES TEX_NUM_FLOAT4_IMAGES_CUDA
+# define TEX_NUM_FLOAT4_IMAGES TEX_NUM_FLOAT4_CUDA
# else
-# define TEX_NUM_FLOAT4_IMAGES TEX_NUM_FLOAT4_IMAGES_CUDA_KEPLER
+# define TEX_NUM_FLOAT4_IMAGES TEX_NUM_FLOAT4_CUDA_KEPLER
# endif
#else
-# define TEX_NUM_FLOAT4_IMAGES TEX_NUM_FLOAT4_IMAGES_OPENCL
+# define TEX_NUM_FLOAT4_IMAGES TEX_NUM_FLOAT4_OPENCL
#endif
#ifdef __KERNEL_OPENCL__
diff --git a/intern/cycles/kernel/svm/svm_types.h b/intern/cycles/kernel/svm/svm_types.h
index 8c69c589ebb..e57d22b1b13 100644
--- a/intern/cycles/kernel/svm/svm_types.h
+++ b/intern/cycles/kernel/svm/svm_types.h
@@ -343,6 +343,11 @@ typedef enum NodeNormalMapSpace {
NODE_NORMAL_MAP_BLENDER_WORLD,
} NodeNormalMapSpace;
+typedef enum NodeImageColorSpace {
+ NODE_COLOR_SPACE_NONE = 0,
+ NODE_COLOR_SPACE_COLOR = 1,
+} NodeImageColorSpace;
+
typedef enum NodeImageProjection {
NODE_IMAGE_PROJ_FLAT = 0,
NODE_IMAGE_PROJ_BOX = 1,
@@ -350,6 +355,11 @@ typedef enum NodeImageProjection {
NODE_IMAGE_PROJ_TUBE = 3,
} NodeImageProjection;
+typedef enum NodeEnvironmentProjection {
+ NODE_ENVIRONMENT_EQUIRECTANGULAR = 0,
+ NODE_ENVIRONMENT_MIRROR_BALL = 1,
+} NodeEnvironmentProjection;
+
typedef enum NodeBumpOffset {
NODE_BUMP_OFFSET_CENTER,
NODE_BUMP_OFFSET_DX,
@@ -370,6 +380,9 @@ typedef enum ShaderType {
/* Closure */
typedef enum ClosureType {
+ /* Special type, flags generic node as a non-BSDF. */
+ CLOSURE_NONE_ID,
+
CLOSURE_BSDF_ID,
/* Diffuse */
diff --git a/intern/cycles/render/attribute.cpp b/intern/cycles/render/attribute.cpp
index b7de83d89c1..71a3cba6811 100644
--- a/intern/cycles/render/attribute.cpp
+++ b/intern/cycles/render/attribute.cpp
@@ -51,13 +51,13 @@ void Attribute::set(ustring name_, TypeDesc type_, AttributeElement element_)
type == TypeDesc::TypeNormal || type == TypeDesc::TypeMatrix);
}
-void Attribute::reserve(int numverts, int numtris, int numsteps, int numcurves, int numkeys, bool resize)
+void Attribute::resize(int numverts, int numtris, int numsteps, int numcurves, int numkeys, bool reserve_only)
{
- if(resize) {
- buffer.resize(buffer_size(numverts, numtris, numsteps, numcurves, numkeys), 0);
+ if(reserve_only) {
+ buffer.reserve(buffer_size(numverts, numtris, numsteps, numcurves, numkeys));
}
else {
- buffer.reserve(buffer_size(numverts, numtris, numsteps, numcurves, numkeys));
+ buffer.resize(buffer_size(numverts, numtris, numsteps, numcurves, numkeys), 0);
}
}
@@ -263,7 +263,7 @@ AttributeSet::~AttributeSet()
{
}
-Attribute *AttributeSet::add(ustring name, TypeDesc type, AttributeElement element, bool resize)
+Attribute *AttributeSet::add(ustring name, TypeDesc type, AttributeElement element)
{
Attribute *attr = find(name);
@@ -291,9 +291,9 @@ Attribute *AttributeSet::add(ustring name, TypeDesc type, AttributeElement eleme
/* this is weak .. */
if(triangle_mesh)
- attr->reserve(triangle_mesh->verts.size(), triangle_mesh->triangles.size(), triangle_mesh->motion_steps, 0, 0, resize);
+ attr->resize(triangle_mesh->verts.size(), triangle_mesh->num_triangles(), triangle_mesh->motion_steps, 0, 0, false);
if(curve_mesh)
- attr->reserve(0, 0, curve_mesh->motion_steps, curve_mesh->curves.size(), curve_mesh->curve_keys.size(), resize);
+ attr->resize(0, 0, curve_mesh->motion_steps, curve_mesh->num_curves(), curve_mesh->curve_keys.size(), false);
return attr;
}
@@ -448,13 +448,13 @@ Attribute *AttributeSet::find(AttributeRequest& req)
return find(req.std);
}
-void AttributeSet::reserve()
+void AttributeSet::resize(bool reserve_only)
{
foreach(Attribute& attr, attributes) {
if(triangle_mesh)
- attr.reserve(triangle_mesh->verts.size(), triangle_mesh->triangles.size(), triangle_mesh->motion_steps, 0, 0, true);
+ attr.resize(triangle_mesh->verts.size(), triangle_mesh->num_triangles(), triangle_mesh->motion_steps, 0, 0, reserve_only);
if(curve_mesh)
- attr.reserve(0, 0, 0, curve_mesh->curves.size(), curve_mesh->curve_keys.size(), true);
+ attr.resize(0, 0, 0, curve_mesh->num_curves(), curve_mesh->curve_keys.size(), reserve_only);
}
}
diff --git a/intern/cycles/render/attribute.h b/intern/cycles/render/attribute.h
index 01102d22aaa..41b3626afd3 100644
--- a/intern/cycles/render/attribute.h
+++ b/intern/cycles/render/attribute.h
@@ -58,7 +58,7 @@ public:
Attribute() {}
~Attribute();
void set(ustring name, TypeDesc type, AttributeElement element);
- void reserve(int numverts, int numfaces, int numsteps, int numcurves, int numkeys, bool resize);
+ void resize(int numverts, int numfaces, int numsteps, int numcurves, int numkeys, bool reserve_only);
size_t data_sizeof() const;
size_t element_size(int numverts, int numfaces, int numsteps, int numcurves, int numkeys) const;
@@ -104,7 +104,7 @@ public:
AttributeSet();
~AttributeSet();
- Attribute *add(ustring name, TypeDesc type, AttributeElement element, bool resize = true);
+ Attribute *add(ustring name, TypeDesc type, AttributeElement element);
Attribute *find(ustring name) const;
void remove(ustring name);
@@ -114,7 +114,7 @@ public:
Attribute *find(AttributeRequest& req);
- void reserve();
+ void resize(bool reserve_only = false);
void clear();
};
diff --git a/intern/cycles/render/background.cpp b/intern/cycles/render/background.cpp
index 6f8d1d1d461..20536b74e87 100644
--- a/intern/cycles/render/background.cpp
+++ b/intern/cycles/render/background.cpp
@@ -116,6 +116,11 @@ void Background::device_free(Device * /*device*/, DeviceScene * /*dscene*/)
{
}
+bool Background::modified(const Background& background)
+{
+ return !Node::equals(background);
+}
+
void Background::tag_update(Scene *scene)
{
scene->integrator->tag_update(scene);
diff --git a/intern/cycles/render/background.h b/intern/cycles/render/background.h
index 843655b00a1..8029c6a9e80 100644
--- a/intern/cycles/render/background.h
+++ b/intern/cycles/render/background.h
@@ -50,6 +50,7 @@ public:
void device_update(Device *device, DeviceScene *dscene, Scene *scene);
void device_free(Device *device, DeviceScene *dscene);
+ bool modified(const Background& background);
void tag_update(Scene *scene);
};
diff --git a/intern/cycles/render/bake.cpp b/intern/cycles/render/bake.cpp
index 5bf5e5113ef..13310a61761 100644
--- a/intern/cycles/render/bake.cpp
+++ b/intern/cycles/render/bake.cpp
@@ -177,7 +177,7 @@ bool BakeManager::bake(Device *device, DeviceScene *dscene, Scene *scene, Progre
device->mem_alloc(d_input, MEM_READ_ONLY);
device->mem_copy_to(d_input);
- device->mem_alloc(d_output, MEM_WRITE_ONLY);
+ device->mem_alloc(d_output, MEM_READ_WRITE);
DeviceTask task(DeviceTask::SHADER);
task.shader_input = d_input.device_pointer;
diff --git a/intern/cycles/render/camera.cpp b/intern/cycles/render/camera.cpp
index d992cac5312..2310798be2e 100644
--- a/intern/cycles/render/camera.cpp
+++ b/intern/cycles/render/camera.cpp
@@ -30,70 +30,126 @@
CCL_NAMESPACE_BEGIN
static float shutter_curve_eval(float x,
- float shutter_curve[RAMP_TABLE_SIZE])
+ array<float>& shutter_curve)
{
- x *= RAMP_TABLE_SIZE;
+ if (shutter_curve.size() == 0)
+ return 1.0f;
+
+ x *= shutter_curve.size();
int index = (int)x;
float frac = x - index;
- if(index < RAMP_TABLE_SIZE - 1) {
+ if(index < shutter_curve.size() - 1) {
return lerp(shutter_curve[index], shutter_curve[index + 1], frac);
}
else {
- return shutter_curve[RAMP_TABLE_SIZE - 1];
+ return shutter_curve[shutter_curve.size() - 1];
}
}
+NODE_DEFINE(Camera)
+{
+ NodeType* type = NodeType::add("camera", create);
+
+ SOCKET_FLOAT(shuttertime, "Shutter Time", 1.0f);
+
+ static NodeEnum motion_position_enum;
+ motion_position_enum.insert("start", MOTION_POSITION_START);
+ motion_position_enum.insert("center", MOTION_POSITION_CENTER);
+ motion_position_enum.insert("end", MOTION_POSITION_END);
+ SOCKET_ENUM(motion_position, "Motion Position", motion_position_enum, MOTION_POSITION_CENTER);
+
+ static NodeEnum rolling_shutter_type_enum;
+ rolling_shutter_type_enum.insert("none", ROLLING_SHUTTER_NONE);
+ rolling_shutter_type_enum.insert("top", ROLLING_SHUTTER_TOP);
+ SOCKET_ENUM(rolling_shutter_type, "Rolling Shutter Type", rolling_shutter_type_enum, ROLLING_SHUTTER_NONE);
+ SOCKET_FLOAT(rolling_shutter_duration, "Rolling Shutter Duration", 0.1f);
+
+ SOCKET_FLOAT_ARRAY(shutter_curve, "Shutter Curve", array<float>());
+
+ SOCKET_FLOAT(aperturesize, "Aperture Size", 0.0f);
+ SOCKET_FLOAT(focaldistance, "Focal Distance", 10.0f);
+ SOCKET_INT(blades, "Blades", 0);
+ SOCKET_FLOAT(bladesrotation, "Blades Rotation", 0.0f);
+
+ SOCKET_TRANSFORM(matrix, "Matrix", transform_identity());
+
+ SOCKET_FLOAT(aperture_ratio, "Aperture Ratio", 1.0f);
+
+ static NodeEnum type_enum;
+ type_enum.insert("perspective", CAMERA_PERSPECTIVE);
+ type_enum.insert("orthograph", CAMERA_ORTHOGRAPHIC);
+ type_enum.insert("panorama", CAMERA_PANORAMA);
+ SOCKET_ENUM(type, "Type", type_enum, CAMERA_PERSPECTIVE);
+
+ static NodeEnum panorama_type_enum;
+ panorama_type_enum.insert("equirectangular", PANORAMA_EQUIRECTANGULAR);
+ panorama_type_enum.insert("mirrorball", PANORAMA_MIRRORBALL);
+ panorama_type_enum.insert("fisheye_equidistant", PANORAMA_FISHEYE_EQUIDISTANT);
+ panorama_type_enum.insert("fisheye_equisolid", PANORAMA_FISHEYE_EQUISOLID);
+ SOCKET_ENUM(panorama_type, "Panorama Type", panorama_type_enum, PANORAMA_EQUIRECTANGULAR);
+
+ SOCKET_FLOAT(fisheye_fov, "Fisheye FOV", M_PI_F);
+ SOCKET_FLOAT(fisheye_lens, "Fisheye Lens", 10.5f);
+ SOCKET_FLOAT(latitude_min, "Latitude Min", -M_PI_2_F);
+ SOCKET_FLOAT(latitude_max, "Latitude Max", M_PI_2_F);
+ SOCKET_FLOAT(longitude_min, "Longitude Min", -M_PI_F);
+ SOCKET_FLOAT(longitude_max, "Longitude Max", M_PI_F);
+ SOCKET_FLOAT(fov, "FOV", M_PI_4_F);
+ SOCKET_FLOAT(fov_pre, "FOV Pre", M_PI_4_F);
+ SOCKET_FLOAT(fov_post, "FOV Post", M_PI_4_F);
+
+ static NodeEnum stereo_eye_enum;
+ stereo_eye_enum.insert("none", STEREO_NONE);
+ stereo_eye_enum.insert("left", STEREO_LEFT);
+ stereo_eye_enum.insert("right", STEREO_RIGHT);
+ SOCKET_ENUM(stereo_eye, "Stereo Eye", stereo_eye_enum, STEREO_NONE);
+
+ SOCKET_FLOAT(interocular_distance, "Interocular Distance", 0.065f);
+ SOCKET_FLOAT(convergence_distance, "Convergence Distance", 30.0f * 0.065f);
+
+ SOCKET_BOOLEAN(use_pole_merge, "Use Pole Merge", false);
+ SOCKET_FLOAT(pole_merge_angle_from, "Pole Merge Angle From", 60.0f * M_PI_F / 180.0f);
+ SOCKET_FLOAT(pole_merge_angle_to, "Pole Merge Angle To", 75.0f * M_PI_F / 180.0f);
+
+ SOCKET_FLOAT(sensorwidth, "Sensor Width", 0.036f);
+ SOCKET_FLOAT(sensorheight, "Sensor Height", 0.024f);
+
+ SOCKET_FLOAT(nearclip, "Near Clip", 1e-5f);
+ SOCKET_FLOAT(farclip, "Far Clip", 1e5f);
+
+ SOCKET_FLOAT(viewplane.left, "Viewplane Left", 0);
+ SOCKET_FLOAT(viewplane.right, "Viewplane Right", 0);
+ SOCKET_FLOAT(viewplane.bottom, "Viewplane Bottom", 0);
+ SOCKET_FLOAT(viewplane.top, "Viewplane Top", 0);
+
+ SOCKET_FLOAT(border.left, "Border Left", 0);
+ SOCKET_FLOAT(border.right, "Border Right", 0);
+ SOCKET_FLOAT(border.bottom, "Border Bottom", 0);
+ SOCKET_FLOAT(border.top, "Border Top", 0);
+
+ return type;
+}
+
Camera::Camera()
+: Node(node_type)
{
- shuttertime = 1.0f;
- motion_position = MOTION_POSITION_CENTER;
shutter_table_offset = TABLE_OFFSET_INVALID;
- aperturesize = 0.0f;
- focaldistance = 10.0f;
- blades = 0;
- bladesrotation = 0.0f;
-
- matrix = transform_identity();
+ width = 1024;
+ height = 512;
+ resolution = 1;
motion.pre = transform_identity();
motion.post = transform_identity();
use_motion = false;
use_perspective_motion = false;
- aperture_ratio = 1.0f;
-
- type = CAMERA_PERSPECTIVE;
- panorama_type = PANORAMA_EQUIRECTANGULAR;
- fisheye_fov = M_PI_F;
- fisheye_lens = 10.5f;
- latitude_min = -M_PI_2_F;
- latitude_max = M_PI_2_F;
- longitude_min = -M_PI_F;
- longitude_max = M_PI_F;
- fov = M_PI_4_F;
- fov_pre = fov_post = fov;
- stereo_eye = STEREO_NONE;
- interocular_distance = 0.065f;
- convergence_distance = 30.0f * 0.065f;
- use_pole_merge = false;
- pole_merge_angle_from = 60.0f * M_PI_F / 180.0f;
- pole_merge_angle_to = 75.0f * M_PI_F / 180.0f;
-
- sensorwidth = 0.036f;
- sensorheight = 0.024f;
-
- nearclip = 1e-5f;
- farclip = 1e5f;
-
- width = 1024;
- height = 512;
- resolution = 1;
+ shutter_curve.resize(RAMP_TABLE_SIZE);
+ for(int i = 0; i < shutter_curve.size(); ++i) {
+ shutter_curve[i] = 1.0f;
+ }
- viewplane.left = -((float)width/(float)height);
- viewplane.right = (float)width/(float)height;
- viewplane.bottom = -1.0f;
- viewplane.top = 1.0f;
+ compute_auto_viewplane();
screentoworld = transform_identity();
rastertoworld = transform_identity();
@@ -109,16 +165,6 @@ Camera::Camera()
need_device_update = true;
need_flags_update = true;
previous_need_motion = -1;
-
- /* Initialize shutter curve. */
- const int num_shutter_points = sizeof(shutter_curve) / sizeof(*shutter_curve);
- for(int i = 0; i < num_shutter_points; ++i) {
- shutter_curve[i] = 1.0f;
- }
-
- /* Initialize rolling shutter effect. */
- rolling_shutter_type = ROLLING_SHUTTER_NONE;
- rolling_shutter_duration = 0.1f;
}
Camera::~Camera()
@@ -438,38 +484,14 @@ void Camera::device_free(Device * /*device*/,
bool Camera::modified(const Camera& cam)
{
- return !((shuttertime == cam.shuttertime) &&
- (aperturesize == cam.aperturesize) &&
- (blades == cam.blades) &&
- (bladesrotation == cam.bladesrotation) &&
- (focaldistance == cam.focaldistance) &&
- (type == cam.type) &&
- (fov == cam.fov) &&
- (nearclip == cam.nearclip) &&
- (farclip == cam.farclip) &&
- (sensorwidth == cam.sensorwidth) &&
- (sensorheight == cam.sensorheight) &&
- // modified for progressive render
- // (width == cam.width) &&
- // (height == cam.height) &&
- (viewplane == cam.viewplane) &&
- (border == cam.border) &&
- (matrix == cam.matrix) &&
- (aperture_ratio == cam.aperture_ratio) &&
- (panorama_type == cam.panorama_type) &&
- (fisheye_fov == cam.fisheye_fov) &&
- (fisheye_lens == cam.fisheye_lens) &&
- (latitude_min == cam.latitude_min) &&
- (latitude_max == cam.latitude_max) &&
- (longitude_min == cam.longitude_min) &&
- (longitude_max == cam.longitude_max) &&
- (stereo_eye == cam.stereo_eye));
+ return !Node::equals(cam);
}
bool Camera::motion_modified(const Camera& cam)
{
return !((motion == cam.motion) &&
- (use_motion == cam.use_motion));
+ (use_motion == cam.use_motion) &&
+ (use_perspective_motion == cam.use_perspective_motion));
}
void Camera::tag_update()
diff --git a/intern/cycles/render/camera.h b/intern/cycles/render/camera.h
index 57b9960e70b..141ef9cccef 100644
--- a/intern/cycles/render/camera.h
+++ b/intern/cycles/render/camera.h
@@ -19,6 +19,8 @@
#include "kernel_types.h"
+#include "node.h"
+
#include "util_boundbox.h"
#include "util_transform.h"
#include "util_types.h"
@@ -35,8 +37,10 @@ class Scene;
* Renderman, and Blender after remapping.
*/
-class Camera {
+class Camera : public Node {
public:
+ NODE_DECLARE;
+
/* Specifies an offset for the shutter's time interval. */
enum MotionPosition {
/* Shutter opens at the current frame. */
@@ -69,7 +73,7 @@ public:
/* motion blur */
float shuttertime;
MotionPosition motion_position;
- float shutter_curve[RAMP_TABLE_SIZE];
+ array<float> shutter_curve;
size_t shutter_table_offset;
/* ** Rolling shutter effect. ** */
diff --git a/intern/cycles/render/curves.h b/intern/cycles/render/curves.h
index 3d9b4e1f347..e41967eebf5 100644
--- a/intern/cycles/render/curves.h
+++ b/intern/cycles/render/curves.h
@@ -63,23 +63,23 @@ public:
ParticleCurveData();
~ParticleCurveData();
- vector<int> psys_firstcurve;
- vector<int> psys_curvenum;
- vector<int> psys_shader;
-
- vector<float> psys_rootradius;
- vector<float> psys_tipradius;
- vector<float> psys_shape;
- vector<bool> psys_closetip;
-
- vector<int> curve_firstkey;
- vector<int> curve_keynum;
- vector<float> curve_length;
- vector<float3> curve_uv;
- vector<float3> curve_vcol;
-
- vector<float3> curvekey_co;
- vector<float> curvekey_time;
+ array<int> psys_firstcurve;
+ array<int> psys_curvenum;
+ array<int> psys_shader;
+
+ array<float> psys_rootradius;
+ array<float> psys_tipradius;
+ array<float> psys_shape;
+ array<bool> psys_closetip;
+
+ array<int> curve_firstkey;
+ array<int> curve_keynum;
+ array<float> curve_length;
+ array<float3> curve_uv;
+ array<float3> curve_vcol;
+
+ array<float3> curvekey_co;
+ array<float> curvekey_time;
};
/* HairSystem Manager */
diff --git a/intern/cycles/render/film.cpp b/intern/cycles/render/film.cpp
index 12dce6ad999..e10a938e1eb 100644
--- a/intern/cycles/render/film.cpp
+++ b/intern/cycles/render/film.cpp
@@ -465,7 +465,7 @@ void Film::device_free(Device * /*device*/,
bool Film::modified(const Film& film)
{
- return Node::modified(film) || !Pass::equals(passes, film.passes);
+ return !Node::equals(film) || !Pass::equals(passes, film.passes);
}
void Film::tag_passes_update(Scene *scene, const array<Pass>& passes_)
diff --git a/intern/cycles/render/graph.cpp b/intern/cycles/render/graph.cpp
index 15c89cc4b51..29c0eec9b97 100644
--- a/intern/cycles/render/graph.cpp
+++ b/intern/cycles/render/graph.cpp
@@ -66,7 +66,7 @@ bool check_node_inputs_equals(const ShaderNode *node_a,
*input_b = node_b->inputs[i];
if(input_a->link == NULL && input_b->link == NULL) {
/* Unconnected inputs are expected to have the same value. */
- if(input_a->value != input_b->value) {
+ if(input_a->value() != input_b->value()) {
return false;
}
}
@@ -90,23 +90,22 @@ bool check_node_inputs_equals(const ShaderNode *node_a,
/* Input and Output */
-ShaderInput::ShaderInput(ShaderNode *parent_, const char *name_, ShaderSocketType type_)
+ShaderInput::ShaderInput(ShaderNode *parent_, const char *name, SocketType::Type type)
{
parent = parent_;
- name = name_;
- type = type_;
+ name_ = name;
+ type_ = type;
link = NULL;
- value = make_float3(0.0f, 0.0f, 0.0f);
+ value_ = make_float3(0.0f, 0.0f, 0.0f);
stack_offset = SVM_STACK_INVALID;
- default_value = NONE;
- usage = USE_ALL;
+ flags_ = 0;
}
-ShaderOutput::ShaderOutput(ShaderNode *parent_, const char *name_, ShaderSocketType type_)
+ShaderOutput::ShaderOutput(ShaderNode *parent_, const char *name, SocketType::Type type)
{
parent = parent_;
- name = name_;
- type = type_;
+ name_ = name;
+ type_ = type;
stack_offset = SVM_STACK_INVALID;
}
@@ -132,7 +131,7 @@ ShaderNode::~ShaderNode()
ShaderInput *ShaderNode::input(const char *name)
{
foreach(ShaderInput *socket, inputs) {
- if(strcmp(socket->name, name) == 0)
+ if(socket->name() == name)
return socket;
}
@@ -142,39 +141,50 @@ ShaderInput *ShaderNode::input(const char *name)
ShaderOutput *ShaderNode::output(const char *name)
{
foreach(ShaderOutput *socket, outputs)
- if(strcmp(socket->name, name) == 0)
+ if(socket->name() == name)
return socket;
return NULL;
}
-ShaderInput *ShaderNode::add_input(const char *name, ShaderSocketType type, float value, int usage)
+ShaderInput *ShaderNode::input(ustring name)
{
- ShaderInput *input = new ShaderInput(this, name, type);
- input->value.x = value;
- input->usage = usage;
- inputs.push_back(input);
- return input;
+ foreach(ShaderInput *socket, inputs) {
+ if(socket->name() == name)
+ return socket;
+ }
+
+ return NULL;
+}
+
+ShaderOutput *ShaderNode::output(ustring name)
+{
+ foreach(ShaderOutput *socket, outputs)
+ if(socket->name() == name)
+ return socket;
+
+ return NULL;
}
-ShaderInput *ShaderNode::add_input(const char *name, ShaderSocketType type, float3 value, int usage)
+ShaderInput *ShaderNode::add_input(const char *name, SocketType::Type type, float value, int flags)
{
ShaderInput *input = new ShaderInput(this, name, type);
- input->value = value;
- input->usage = usage;
+ input->value_.x = value;
+ input->flags_ = flags;
inputs.push_back(input);
return input;
}
-ShaderInput *ShaderNode::add_input(const char *name, ShaderSocketType type, ShaderInput::DefaultValue value, int usage)
+ShaderInput *ShaderNode::add_input(const char *name, SocketType::Type type, float3 value, int flags)
{
- ShaderInput *input = add_input(name, type);
- input->default_value = value;
- input->usage = usage;
+ ShaderInput *input = new ShaderInput(this, name, type);
+ input->value_ = value;
+ input->flags_ = flags;
+ inputs.push_back(input);
return input;
}
-ShaderOutput *ShaderNode::add_output(const char *name, ShaderSocketType type)
+ShaderOutput *ShaderNode::add_output(const char *name, SocketType::Type type)
{
ShaderOutput *output = new ShaderOutput(this, name, type);
outputs.push_back(output);
@@ -185,13 +195,13 @@ void ShaderNode::attributes(Shader *shader, AttributeRequestSet *attributes)
{
foreach(ShaderInput *input, inputs) {
if(!input->link) {
- if(input->default_value == ShaderInput::TEXTURE_GENERATED) {
+ if(input->flags() & SocketType::LINK_TEXTURE_GENERATED) {
if(shader->has_surface)
attributes->add(ATTR_STD_GENERATED);
if(shader->has_volume)
attributes->add(ATTR_STD_GENERATED_TRANSFORM);
}
- else if(input->default_value == ShaderInput::TEXTURE_UV) {
+ else if(input->flags() & SocketType::LINK_TEXTURE_UV) {
if(shader->has_surface)
attributes->add(ATTR_STD_UV);
}
@@ -256,18 +266,18 @@ void ShaderGraph::connect(ShaderOutput *from, ShaderInput *to)
return;
}
- if(from->type != to->type) {
+ if(from->type() != to->type()) {
/* for closures we can't do automatic conversion */
- if(from->type == SHADER_SOCKET_CLOSURE || to->type == SHADER_SOCKET_CLOSURE) {
+ if(from->type() == SocketType::CLOSURE || to->type() == SocketType::CLOSURE) {
fprintf(stderr, "Cycles shader graph connect: can only connect closure to closure "
"(%s.%s to %s.%s).\n",
- from->parent->name.c_str(), from->name,
- to->parent->name.c_str(), to->name);
+ from->parent->name.c_str(), from->name().c_str(),
+ to->parent->name.c_str(), to->name().c_str());
return;
}
/* add automatic conversion node in case of type mismatch */
- ShaderNode *convert = add(new ConvertNode(from->type, to->type, true));
+ ShaderNode *convert = add(new ConvertNode(from->type(), to->type(), true));
connect(from, convert->inputs[0]);
connect(convert->outputs[0], to);
@@ -401,8 +411,8 @@ void ShaderGraph::copy_nodes(ShaderNodeSet& nodes, ShaderNodeMap& nnodemap)
/* find new input and output */
ShaderNode *nfrom = nnodemap[input->link->parent];
ShaderNode *nto = nnodemap[input->parent];
- ShaderOutput *noutput = nfrom->output(input->link->name);
- ShaderInput *ninput = nto->input(input->name);
+ ShaderOutput *noutput = nfrom->output(input->link->name());
+ ShaderInput *ninput = nto->input(input->name());
/* connect */
connect(noutput, ninput);
@@ -447,10 +457,10 @@ void ShaderGraph::remove_proxy_nodes()
vector<ShaderInput*> links = tonode->outputs[0]->links;
foreach(ShaderInput *autoin, links) {
- if(autoin->default_value == ShaderInput::NONE)
- all_links_removed = false;
- else
+ if(autoin->flags() & SocketType::DEFAULT_LINK_MASK)
disconnect(autoin);
+ else
+ all_links_removed = false;
}
if(all_links_removed)
@@ -460,8 +470,8 @@ void ShaderGraph::remove_proxy_nodes()
disconnect(to);
/* transfer the default input value to the target socket */
- to->set(input->value);
- to->set(input->value_string);
+ to->set(input->value());
+ to->set(input->value_string());
}
}
@@ -527,14 +537,13 @@ void ShaderGraph::constant_fold()
}
}
/* Optimize current node. */
- float3 optimized_value = make_float3(0.0f, 0.0f, 0.0f);
- if(node->constant_fold(this, output, &optimized_value)) {
- /* Apply optimized value to connected sockets. */
+ if(node->constant_fold(this, output, output->links[0])) {
+ /* Apply optimized value to other connected sockets and disconnect. */
vector<ShaderInput*> links(output->links);
- foreach(ShaderInput *input, links) {
- /* Assign value and disconnect the optimizedinput. */
- input->value = optimized_value;
- disconnect(input);
+ for(size_t i = 0; i < links.size(); i++) {
+ if(i > 0)
+ links[i]->set(links[0]->value());
+ disconnect(links[i]);
}
}
}
@@ -706,38 +715,38 @@ void ShaderGraph::default_inputs(bool do_osl)
foreach(ShaderNode *node, nodes) {
foreach(ShaderInput *input, node->inputs) {
- if(!input->link && ((input->usage & ShaderInput::USE_SVM) || do_osl)) {
- if(input->default_value == ShaderInput::TEXTURE_GENERATED) {
+ if(!input->link && (!(input->flags() & SocketType::OSL_INTERNAL) || do_osl)) {
+ if(input->flags() & SocketType::LINK_TEXTURE_GENERATED) {
if(!texco)
texco = new TextureCoordinateNode();
connect(texco->output("Generated"), input);
}
- else if(input->default_value == ShaderInput::TEXTURE_UV) {
+ else if(input->flags() & SocketType::LINK_TEXTURE_UV) {
if(!texco)
texco = new TextureCoordinateNode();
connect(texco->output("UV"), input);
}
- else if(input->default_value == ShaderInput::INCOMING) {
+ else if(input->flags() & SocketType::LINK_INCOMING) {
if(!geom)
geom = new GeometryNode();
connect(geom->output("Incoming"), input);
}
- else if(input->default_value == ShaderInput::NORMAL) {
+ else if(input->flags() & SocketType::LINK_NORMAL) {
if(!geom)
geom = new GeometryNode();
connect(geom->output("Normal"), input);
}
- else if(input->default_value == ShaderInput::POSITION) {
+ else if(input->flags() & SocketType::LINK_POSITION) {
if(!geom)
geom = new GeometryNode();
connect(geom->output("Position"), input);
}
- else if(input->default_value == ShaderInput::TANGENT) {
+ else if(input->flags() & SocketType::LINK_TANGENT) {
if(!geom)
geom = new GeometryNode();
@@ -785,8 +794,8 @@ void ShaderGraph::refine_bump_nodes()
pair.second->bump = SHADER_BUMP_DY;
ShaderOutput *out = bump_input->link;
- ShaderOutput *out_dx = nodes_dx[out->parent]->output(out->name);
- ShaderOutput *out_dy = nodes_dy[out->parent]->output(out->name);
+ ShaderOutput *out_dx = nodes_dx[out->parent]->output(out->name());
+ ShaderOutput *out_dy = nodes_dy[out->parent]->output(out->name());
connect(out_dx, node->input("SampleX"));
connect(out_dy, node->input("SampleY"));
@@ -860,9 +869,9 @@ void ShaderGraph::bump_from_displacement()
ShaderNode *bump = add(new BumpNode());
ShaderOutput *out = displacement_in->link;
- ShaderOutput *out_center = nodes_center[out->parent]->output(out->name);
- ShaderOutput *out_dx = nodes_dx[out->parent]->output(out->name);
- ShaderOutput *out_dy = nodes_dy[out->parent]->output(out->name);
+ ShaderOutput *out_center = nodes_center[out->parent]->output(out->name());
+ ShaderOutput *out_dx = nodes_dx[out->parent]->output(out->name());
+ ShaderOutput *out_dy = nodes_dy[out->parent]->output(out->name());
connect(out_center, bump->input("SampleCenter"));
connect(out_dx, bump->input("SampleX"));
@@ -882,7 +891,7 @@ void ShaderGraph::bump_from_displacement()
continue;
}
foreach(ShaderInput *input, node->inputs) {
- if(!input->link && input->default_value == ShaderInput::NORMAL)
+ if(!input->link && (input->flags() & SocketType::LINK_NORMAL))
connect(set_normal->output("Normal"), input);
}
}
@@ -925,7 +934,7 @@ void ShaderGraph::transform_multi_closure(ShaderNode *node, ShaderOutput *weight
if(fin->link)
connect(fin->link, fac_in);
else
- fac_in->value = fin->value;
+ fac_in->set(fin->value_float());
if(weight_out)
connect(weight_out, weight_in);
@@ -952,7 +961,7 @@ void ShaderGraph::transform_multi_closure(ShaderNode *node, ShaderOutput *weight
return;
/* already has a weight connected to it? add weights */
- if(weight_in->link || weight_in->value.x != 0.0f) {
+ if(weight_in->link || weight_in->value_float() != 0.0f) {
ShaderNode *math_node = add(new MathNode());
ShaderInput *value1_in = math_node->input("Value1");
ShaderInput *value2_in = math_node->input("Value2");
@@ -960,12 +969,12 @@ void ShaderGraph::transform_multi_closure(ShaderNode *node, ShaderOutput *weight
if(weight_in->link)
connect(weight_in->link, value1_in);
else
- value1_in->value = weight_in->value;
+ value1_in->set(weight_in->value_float());
if(weight_out)
connect(weight_out, value2_in);
else
- value2_in->value.x = 1.0f;
+ value2_in->set(1.0f);
weight_out = math_node->output("Value");
if(weight_in->link)
@@ -976,7 +985,7 @@ void ShaderGraph::transform_multi_closure(ShaderNode *node, ShaderOutput *weight
if(weight_out)
connect(weight_out, weight_in);
else
- weight_in->value.x += 1.0f;
+ weight_in->set(weight_in->value_float() + 1.0f);
}
}
@@ -984,17 +993,18 @@ int ShaderGraph::get_num_closures()
{
int num_closures = 0;
foreach(ShaderNode *node, nodes) {
- if(node->special_type == SHADER_SPECIAL_TYPE_CLOSURE) {
- BsdfNode *bsdf_node = static_cast<BsdfNode*>(node);
- /* TODO(sergey): Make it more generic approach, maybe some utility
- * macros like CLOSURE_IS_FOO()?
- */
- if(CLOSURE_IS_BSSRDF(bsdf_node->closure))
- num_closures = num_closures + 3;
- else if(CLOSURE_IS_GLASS(bsdf_node->closure))
- num_closures = num_closures + 2;
- else
- num_closures = num_closures + 1;
+ ClosureType closure_type = node->get_closure_type();
+ if(closure_type == CLOSURE_NONE_ID) {
+ continue;
+ }
+ else if(CLOSURE_IS_BSSRDF(closure_type)) {
+ num_closures += 3;
+ }
+ else if(CLOSURE_IS_GLASS(closure_type)) {
+ num_closures += 2;
+ }
+ else {
+ ++num_closures;
}
}
return num_closures;
@@ -1023,7 +1033,7 @@ void ShaderGraph::dump_graph(const char *filename)
if(socket != node->inputs[0]) {
fprintf(fd, "|");
}
- fprintf(fd, "<IN_%p>%s", socket, socket->name);
+ fprintf(fd, "<IN_%p>%s", socket, socket->name().c_str());
}
fprintf(fd, "}|");
}
@@ -1043,7 +1053,7 @@ void ShaderGraph::dump_graph(const char *filename)
if(socket != node->outputs[0]) {
fprintf(fd, "|");
}
- fprintf(fd, "<OUT_%p>%s", socket, socket->name);
+ fprintf(fd, "<OUT_%p>%s", socket, socket->name().c_str());
}
fprintf(fd, "}");
}
@@ -1057,7 +1067,7 @@ void ShaderGraph::dump_graph(const char *filename)
"// CONNECTION: OUT_%p->IN_%p (%s:%s)\n",
output,
input,
- output->name, input->name);
+ output->name().c_str(), input->name().c_str());
fprintf(fd,
"\"%p\":\"OUT_%p\":e -> \"%p\":\"IN_%p\":w [label=\"\"]\n",
output->parent,
diff --git a/intern/cycles/render/graph.h b/intern/cycles/render/graph.h
index b1ebdbfd51d..882e495df20 100644
--- a/intern/cycles/render/graph.h
+++ b/intern/cycles/render/graph.h
@@ -17,6 +17,8 @@
#ifndef __GRAPH_H__
#define __GRAPH_H__
+#include "node.h"
+
#include "kernel_types.h"
#include "util_list.h"
@@ -39,23 +41,6 @@ class SVMCompiler;
class OSLCompiler;
class OutputNode;
-/* Socket Type
- *
- * Data type for inputs and outputs */
-
-enum ShaderSocketType {
- SHADER_SOCKET_UNDEFINED,
-
- SHADER_SOCKET_FLOAT,
- SHADER_SOCKET_INT,
- SHADER_SOCKET_COLOR,
- SHADER_SOCKET_VECTOR,
- SHADER_SOCKET_POINT,
- SHADER_SOCKET_NORMAL,
- SHADER_SOCKET_CLOSURE,
- SHADER_SOCKET_STRING
-};
-
/* Bump
*
* For bump mapping, a node may be evaluated multiple times, using different
@@ -86,30 +71,6 @@ enum ShaderNodeSpecialType {
SHADER_SPECIAL_TYPE_BUMP,
};
-/* Enum
- *
- * Utility class for enum values. */
-
-class ShaderEnum {
-public:
- bool empty() const { return left.empty(); }
- void insert(const char *x, int y) {
- left[ustring(x)] = y;
- right[y] = ustring(x);
- }
-
- bool exists(ustring x) { return left.find(x) != left.end(); }
- bool exists(int y) { return right.find(y) != right.end(); }
-
- int operator[](const char *x) { return left[ustring(x)]; }
- int operator[](ustring x) { return left[x]; }
- ustring operator[](int y) { return right[y]; }
-
-protected:
- map<ustring, int> left;
- map<int, ustring> right;
-};
-
/* Input
*
* Input socket for a shader node. May be linked to an output or not. If not
@@ -118,39 +79,32 @@ protected:
class ShaderInput {
public:
- enum DefaultValue {
- TEXTURE_GENERATED,
- TEXTURE_UV,
- INCOMING,
- NORMAL,
- POSITION,
- TANGENT,
- NONE
- };
-
- enum Usage {
- USE_SVM = 1,
- USE_OSL = 2,
- USE_ALL = USE_SVM|USE_OSL
- };
-
- ShaderInput(ShaderNode *parent, const char *name, ShaderSocketType type);
- void set(const float3& v) { value = v; }
- void set(float f) { value = make_float3(f, 0, 0); }
- void set(const ustring v) { value_string = v; }
-
- const char *name;
- ShaderSocketType type;
+ ShaderInput(ShaderNode *parent, const char *name, SocketType::Type type);
+
+ ustring name() { return name_; }
+ int flags() { return flags_; }
+ SocketType::Type type() { return type_; }
+
+ void set(float f) { value_.x = f; }
+ void set(float3 f) { value_ = f; }
+ void set(int i) { value_.x = (float)i; }
+ void set(ustring s) { value_string_ = s; }
+
+ float3& value() { return value_; }
+ float& value_float() { return value_.x; }
+ ustring& value_string() { return value_string_; }
+
+ ustring name_;
+ SocketType::Type type_;
ShaderNode *parent;
ShaderOutput *link;
- DefaultValue default_value;
- float3 value;
- ustring value_string;
+ float3 value_;
+ ustring value_string_;
int stack_offset; /* for SVM compiler */
- int usage;
+ int flags_;
};
/* Output
@@ -159,12 +113,15 @@ public:
class ShaderOutput {
public:
- ShaderOutput(ShaderNode *parent, const char *name, ShaderSocketType type);
+ ShaderOutput(ShaderNode *parent, const char *name, SocketType::Type type);
- const char *name;
- ShaderNode *parent;
- ShaderSocketType type;
+ ustring name() { return name_; }
+ SocketType::Type type() { return type_; }
+ ustring name_;
+ SocketType::Type type_;
+
+ ShaderNode *parent;
vector<ShaderInput*> links;
int stack_offset; /* for SVM compiler */
@@ -182,11 +139,12 @@ public:
ShaderInput *input(const char *name);
ShaderOutput *output(const char *name);
+ ShaderInput *input(ustring name);
+ ShaderOutput *output(ustring name);
- ShaderInput *add_input(const char *name, ShaderSocketType type, float value=0.0f, int usage=ShaderInput::USE_ALL);
- ShaderInput *add_input(const char *name, ShaderSocketType type, float3 value, int usage=ShaderInput::USE_ALL);
- ShaderInput *add_input(const char *name, ShaderSocketType type, ShaderInput::DefaultValue value, int usage=ShaderInput::USE_ALL);
- ShaderOutput *add_output(const char *name, ShaderSocketType type);
+ ShaderInput *add_input(const char *name, SocketType::Type type, float value=0.0f, int flags=0);
+ ShaderInput *add_input(const char *name, SocketType::Type type, float3 value, int flags=0);
+ ShaderOutput *add_output(const char *name, SocketType::Type type);
virtual ShaderNode *clone() const = 0;
virtual void attributes(Shader *shader, AttributeRequestSet *attributes);
@@ -195,7 +153,7 @@ public:
/* ** Node optimization ** */
/* Check whether the node can be replaced with single constant. */
- virtual bool constant_fold(ShaderGraph * /*graph*/, ShaderOutput * /*socket*/, float3 * /*optimized_value*/) { return false; }
+ virtual bool constant_fold(ShaderGraph * /*graph*/, ShaderOutput * /*socket*/, ShaderInput * /*optimized*/) { return false; }
/* Simplify settings used by artists to the ones which are simpler to
* evaluate in the kernel but keep the final result unchanged.
@@ -237,6 +195,9 @@ public:
*/
virtual int get_feature() { return bump == SHADER_BUMP_NONE ? 0 : NODE_FEATURE_BUMP; }
+ /* Get closure ID to which the node compiles into. */
+ virtual ClosureType get_closure_type() { return CLOSURE_NONE_ID; }
+
/* Check whether settings of the node equals to another one.
*
* This is mainly used to check whether two nodes can be merged
diff --git a/intern/cycles/render/image.cpp b/intern/cycles/render/image.cpp
index 150c742fd24..71dc85f5f03 100644
--- a/intern/cycles/render/image.cpp
+++ b/intern/cycles/render/image.cpp
@@ -36,59 +36,58 @@ ImageManager::ImageManager(const DeviceInfo& info)
osl_texture_system = NULL;
animation_frame = 0;
- /* Set image limits */
+ /* In case of multiple devices used we need to know type of an actual
+ * compute device.
+ *
+ * NOTE: We assume that all the devices are same type, otherwise we'll
+ * be screwed on so many levels..
+ */
+ DeviceType device_type = info.type;
+ if (device_type == DEVICE_MULTI) {
+ device_type = info.multi_devices[0].type;
+ }
- /* CPU */
- if(info.type == DEVICE_CPU) {
- tex_num_images[IMAGE_DATA_TYPE_BYTE4] = TEX_NUM_BYTE4_IMAGES_CPU;
- tex_num_images[IMAGE_DATA_TYPE_FLOAT4] = TEX_NUM_FLOAT4_IMAGES_CPU;
- tex_num_images[IMAGE_DATA_TYPE_FLOAT] = TEX_NUM_FLOAT_IMAGES_CPU;
- tex_num_images[IMAGE_DATA_TYPE_BYTE] = TEX_NUM_BYTE_IMAGES_CPU;
- tex_image_byte4_start = TEX_IMAGE_BYTE4_START_CPU;
- tex_image_float_start = TEX_IMAGE_FLOAT_START_CPU;
- tex_image_byte_start = TEX_IMAGE_BYTE_START_CPU;
+ /* Set image limits */
+#define SET_TEX_IMAGES_LIMITS(ARCH) \
+ { \
+ tex_num_images[IMAGE_DATA_TYPE_FLOAT4] = TEX_NUM_FLOAT4_ ## ARCH; \
+ tex_num_images[IMAGE_DATA_TYPE_BYTE4] = TEX_NUM_BYTE4_ ## ARCH; \
+ tex_num_images[IMAGE_DATA_TYPE_FLOAT] = TEX_NUM_FLOAT_ ## ARCH; \
+ tex_num_images[IMAGE_DATA_TYPE_BYTE] = TEX_NUM_BYTE_ ## ARCH; \
+ tex_start_images[IMAGE_DATA_TYPE_FLOAT4] = TEX_START_FLOAT4_ ## ARCH; \
+ tex_start_images[IMAGE_DATA_TYPE_BYTE4] = TEX_START_BYTE4_ ## ARCH; \
+ tex_start_images[IMAGE_DATA_TYPE_FLOAT] = TEX_START_FLOAT_ ## ARCH; \
+ tex_start_images[IMAGE_DATA_TYPE_BYTE] = TEX_START_BYTE_ ## ARCH; \
}
- /* CUDA (Fermi) */
- else if((info.type == DEVICE_CUDA || info.type == DEVICE_MULTI) && !info.has_bindless_textures) {
- tex_num_images[IMAGE_DATA_TYPE_BYTE4] = TEX_NUM_BYTE4_IMAGES_CUDA;
- tex_num_images[IMAGE_DATA_TYPE_FLOAT4] = TEX_NUM_FLOAT4_IMAGES_CUDA;
- tex_num_images[IMAGE_DATA_TYPE_FLOAT] = TEX_NUM_FLOAT_IMAGES_CUDA;
- tex_num_images[IMAGE_DATA_TYPE_BYTE] = TEX_NUM_BYTE_IMAGES_CUDA;
- tex_image_byte4_start = TEX_IMAGE_BYTE4_START_CUDA;
- tex_image_float_start = TEX_IMAGE_FLOAT_START_CUDA;
- tex_image_byte_start = TEX_IMAGE_BYTE_START_CUDA;
+
+ if(device_type == DEVICE_CPU) {
+ SET_TEX_IMAGES_LIMITS(CPU);
}
- /* CUDA (Kepler and above) */
- else if((info.type == DEVICE_CUDA || info.type == DEVICE_MULTI) && info.has_bindless_textures) {
- tex_num_images[IMAGE_DATA_TYPE_BYTE4] = TEX_NUM_BYTE4_IMAGES_CUDA_KEPLER;
- tex_num_images[IMAGE_DATA_TYPE_FLOAT4] = TEX_NUM_FLOAT4_IMAGES_CUDA_KEPLER;
- tex_num_images[IMAGE_DATA_TYPE_FLOAT] = TEX_NUM_FLOAT_IMAGES_CUDA_KEPLER;
- tex_num_images[IMAGE_DATA_TYPE_BYTE] = TEX_NUM_BYTE_IMAGES_CUDA_KEPLER;
- tex_image_byte4_start = TEX_IMAGE_BYTE4_START_CUDA_KEPLER;
- tex_image_float_start = TEX_IMAGE_FLOAT_START_CUDA_KEPLER;
- tex_image_byte_start = TEX_IMAGE_BYTE_START_CUDA_KEPLER;
+ else if(device_type == DEVICE_CUDA) {
+ if(info.has_bindless_textures) {
+ SET_TEX_IMAGES_LIMITS(CUDA_KEPLER);
+ }
+ else {
+ SET_TEX_IMAGES_LIMITS(CUDA);
+ }
}
- /* OpenCL */
- else if(info.pack_images) {
- tex_num_images[IMAGE_DATA_TYPE_BYTE4] = TEX_NUM_BYTE4_IMAGES_OPENCL;
- tex_num_images[IMAGE_DATA_TYPE_FLOAT4] = TEX_NUM_FLOAT4_IMAGES_OPENCL;
- tex_num_images[IMAGE_DATA_TYPE_FLOAT] = TEX_NUM_FLOAT_IMAGES_OPENCL;
- tex_num_images[IMAGE_DATA_TYPE_BYTE] = TEX_NUM_BYTE_IMAGES_OPENCL;
- tex_image_byte4_start = TEX_IMAGE_BYTE4_START_OPENCL;
- tex_image_float_start = TEX_IMAGE_FLOAT_START_OPENCL;
- tex_image_byte_start = TEX_IMAGE_BYTE_START_OPENCL;
+ else if(device_type == DEVICE_OPENCL) {
+ SET_TEX_IMAGES_LIMITS(OPENCL);
}
- /* Should never happen */
else {
- tex_num_images[IMAGE_DATA_TYPE_BYTE4] = 0;
+ /* Should not happen. */
tex_num_images[IMAGE_DATA_TYPE_FLOAT4] = 0;
+ tex_num_images[IMAGE_DATA_TYPE_BYTE4] = 0;
tex_num_images[IMAGE_DATA_TYPE_FLOAT] = 0;
tex_num_images[IMAGE_DATA_TYPE_BYTE] = 0;
- tex_image_byte4_start = 0;
- tex_image_float_start = 0;
- tex_image_byte_start = 0;
+ tex_start_images[IMAGE_DATA_TYPE_FLOAT4] = 0;
+ tex_start_images[IMAGE_DATA_TYPE_BYTE4] = 0;
+ tex_start_images[IMAGE_DATA_TYPE_FLOAT] = 0;
+ tex_start_images[IMAGE_DATA_TYPE_BYTE] = 0;
assert(0);
}
+
+#undef SET_TEX_IMAGES_LIMITS
}
ImageManager::~ImageManager()
@@ -207,34 +206,20 @@ ImageManager::ImageDataType ImageManager::get_image_metadata(const string& filen
* to device ones and vice versa. */
int ImageManager::type_index_to_flattened_slot(int slot, ImageDataType type)
{
- if(type == IMAGE_DATA_TYPE_BYTE4)
- return slot + tex_image_byte4_start;
- else if(type == IMAGE_DATA_TYPE_FLOAT)
- return slot + tex_image_float_start;
- else if(type == IMAGE_DATA_TYPE_BYTE)
- return slot + tex_image_byte_start;
- else
- return slot;
+ return slot + tex_start_images[type];
}
int ImageManager::flattened_slot_to_type_index(int flat_slot, ImageDataType *type)
{
- if(flat_slot >= tex_image_byte_start) {
- *type = IMAGE_DATA_TYPE_BYTE;
- return flat_slot - tex_image_byte_start;
- }
- else if(flat_slot >= tex_image_float_start) {
- *type = IMAGE_DATA_TYPE_FLOAT;
- return flat_slot - tex_image_float_start;
- }
- else if(flat_slot >= tex_image_byte4_start) {
- *type = IMAGE_DATA_TYPE_BYTE4;
- return flat_slot - tex_image_byte4_start;
- }
- else {
- *type = IMAGE_DATA_TYPE_FLOAT4;
- return flat_slot;
+ for(int i = IMAGE_DATA_NUM_TYPES - 1; i >= 0; i--) {
+ if(flat_slot >= tex_start_images[i]) {
+ *type = (ImageDataType)i;
+ return flat_slot - tex_start_images[i];
+ }
}
+
+ /* Should not happen. */
+ return flat_slot;
}
string ImageManager::name_from_type(int type)
@@ -280,7 +265,7 @@ int ImageManager::add_image(const string& filename,
if(type == IMAGE_DATA_TYPE_FLOAT || type == IMAGE_DATA_TYPE_FLOAT4)
is_float = true;
- /* No single channel textures on Fermi GPUs, use available slots */
+ /* No single channel textures on CUDA (Fermi) and OpenCL, use available slots */
if(type == IMAGE_DATA_TYPE_FLOAT && tex_num_images[type] == 0)
type = IMAGE_DATA_TYPE_FLOAT4;
if(type == IMAGE_DATA_TYPE_BYTE && tex_num_images[type] == 0)
@@ -460,7 +445,8 @@ bool ImageManager::file_load_image_generic(Image *img, ImageInput **in, int &wid
return true;
}
-bool ImageManager::file_load_byte4_image(Image *img, device_vector<uchar4>& tex_img)
+template<typename T>
+bool ImageManager::file_load_byte_image(Image *img, ImageDataType type, device_vector<T>& tex_img)
{
ImageInput *in = NULL;
int width, height, depth, components;
@@ -498,92 +484,59 @@ bool ImageManager::file_load_byte4_image(Image *img, device_vector<uchar4>& tex_
builtin_image_pixels_cb(img->filename, img->builtin_data, pixels);
}
- size_t num_pixels = ((size_t)width) * height * depth;
- if(cmyk) {
- /* CMYK */
- for(size_t i = num_pixels-1, pixel = 0; pixel < num_pixels; pixel++, i--) {
- pixels[i*4+2] = (pixels[i*4+2]*pixels[i*4+3])/255;
- pixels[i*4+1] = (pixels[i*4+1]*pixels[i*4+3])/255;
- pixels[i*4+0] = (pixels[i*4+0]*pixels[i*4+3])/255;
- pixels[i*4+3] = 255;
- }
- }
- else if(components == 2) {
- /* grayscale + alpha */
- for(size_t i = num_pixels-1, pixel = 0; pixel < num_pixels; pixel++, i--) {
- pixels[i*4+3] = pixels[i*2+1];
- pixels[i*4+2] = pixels[i*2+0];
- pixels[i*4+1] = pixels[i*2+0];
- pixels[i*4+0] = pixels[i*2+0];
+ /* Check if we actually have a byte4 slot, in case components == 1, but device
+ * doesn't support single channel textures. */
+ if(type == IMAGE_DATA_TYPE_BYTE4) {
+ size_t num_pixels = ((size_t)width) * height * depth;
+ if(cmyk) {
+ /* CMYK */
+ for(size_t i = num_pixels-1, pixel = 0; pixel < num_pixels; pixel++, i--) {
+ pixels[i*4+2] = (pixels[i*4+2]*pixels[i*4+3])/255;
+ pixels[i*4+1] = (pixels[i*4+1]*pixels[i*4+3])/255;
+ pixels[i*4+0] = (pixels[i*4+0]*pixels[i*4+3])/255;
+ pixels[i*4+3] = 255;
+ }
}
- }
- else if(components == 3) {
- /* RGB */
- for(size_t i = num_pixels-1, pixel = 0; pixel < num_pixels; pixel++, i--) {
- pixels[i*4+3] = 255;
- pixels[i*4+2] = pixels[i*3+2];
- pixels[i*4+1] = pixels[i*3+1];
- pixels[i*4+0] = pixels[i*3+0];
+ else if(components == 2) {
+ /* grayscale + alpha */
+ for(size_t i = num_pixels-1, pixel = 0; pixel < num_pixels; pixel++, i--) {
+ pixels[i*4+3] = pixels[i*2+1];
+ pixels[i*4+2] = pixels[i*2+0];
+ pixels[i*4+1] = pixels[i*2+0];
+ pixels[i*4+0] = pixels[i*2+0];
+ }
}
- }
- else if(components == 1) {
- /* grayscale */
- for(size_t i = num_pixels-1, pixel = 0; pixel < num_pixels; pixel++, i--) {
- pixels[i*4+3] = 255;
- pixels[i*4+2] = pixels[i];
- pixels[i*4+1] = pixels[i];
- pixels[i*4+0] = pixels[i];
+ else if(components == 3) {
+ /* RGB */
+ for(size_t i = num_pixels-1, pixel = 0; pixel < num_pixels; pixel++, i--) {
+ pixels[i*4+3] = 255;
+ pixels[i*4+2] = pixels[i*3+2];
+ pixels[i*4+1] = pixels[i*3+1];
+ pixels[i*4+0] = pixels[i*3+0];
+ }
}
- }
-
- if(img->use_alpha == false) {
- for(size_t i = num_pixels-1, pixel = 0; pixel < num_pixels; pixel++, i--) {
- pixels[i*4+3] = 255;
+ else if(components == 1) {
+ /* grayscale */
+ for(size_t i = num_pixels-1, pixel = 0; pixel < num_pixels; pixel++, i--) {
+ pixels[i*4+3] = 255;
+ pixels[i*4+2] = pixels[i];
+ pixels[i*4+1] = pixels[i];
+ pixels[i*4+0] = pixels[i];
+ }
}
- }
-
- return true;
-}
-
-bool ImageManager::file_load_byte_image(Image *img, device_vector<uchar>& tex_img)
-{
- ImageInput *in = NULL;
- int width, height, depth, components;
-
- if(!file_load_image_generic(img, &in, width, height, depth, components))
- return false;
-
- /* read BW pixels */
- uchar *pixels = (uchar*)tex_img.resize(width, height, depth);
- if(pixels == NULL) {
- return false;
- }
-
- if(in) {
- if(depth <= 1) {
- int scanlinesize = width*components*sizeof(uchar);
- in->read_image(TypeDesc::UINT8,
- (uchar*)pixels + (((size_t)height)-1)*scanlinesize,
- AutoStride,
- -scanlinesize,
- AutoStride);
- }
- else {
- in->read_image(TypeDesc::UINT8, (uchar*)pixels);
+ if(img->use_alpha == false) {
+ for(size_t i = num_pixels-1, pixel = 0; pixel < num_pixels; pixel++, i--) {
+ pixels[i*4+3] = 255;
+ }
}
-
- in->close();
- delete in;
- }
- else {
- builtin_image_pixels_cb(img->filename, img->builtin_data, pixels);
}
return true;
}
-bool ImageManager::file_load_float4_image(Image *img, device_vector<float4>& tex_img)
+template<typename T>
+bool ImageManager::file_load_float_image(Image *img, ImageDataType type, device_vector<T>& tex_img)
{
ImageInput *in = NULL;
int width, height, depth, components;
@@ -641,88 +594,52 @@ bool ImageManager::file_load_float4_image(Image *img, device_vector<float4>& tex
builtin_image_float_pixels_cb(img->filename, img->builtin_data, pixels);
}
- size_t num_pixels = ((size_t)width) * height * depth;
- if(cmyk) {
- /* CMYK */
- for(size_t i = num_pixels-1, pixel = 0; pixel < num_pixels; pixel++, i--) {
- pixels[i*4+3] = 255;
- pixels[i*4+2] = (pixels[i*4+2]*pixels[i*4+3])/255;
- pixels[i*4+1] = (pixels[i*4+1]*pixels[i*4+3])/255;
- pixels[i*4+0] = (pixels[i*4+0]*pixels[i*4+3])/255;
- }
- }
- else if(components == 2) {
- /* grayscale + alpha */
- for(size_t i = num_pixels-1, pixel = 0; pixel < num_pixels; pixel++, i--) {
- pixels[i*4+3] = pixels[i*2+1];
- pixels[i*4+2] = pixels[i*2+0];
- pixels[i*4+1] = pixels[i*2+0];
- pixels[i*4+0] = pixels[i*2+0];
+ /* Check if we actually have a float4 slot, in case components == 1, but device
+ * doesn't support single channel textures. */
+ if(type == IMAGE_DATA_TYPE_FLOAT4) {
+ size_t num_pixels = ((size_t)width) * height * depth;
+ if(cmyk) {
+ /* CMYK */
+ for(size_t i = num_pixels-1, pixel = 0; pixel < num_pixels; pixel++, i--) {
+ pixels[i*4+3] = 255;
+ pixels[i*4+2] = (pixels[i*4+2]*pixels[i*4+3])/255;
+ pixels[i*4+1] = (pixels[i*4+1]*pixels[i*4+3])/255;
+ pixels[i*4+0] = (pixels[i*4+0]*pixels[i*4+3])/255;
+ }
}
- }
- else if(components == 3) {
- /* RGB */
- for(size_t i = num_pixels-1, pixel = 0; pixel < num_pixels; pixel++, i--) {
- pixels[i*4+3] = 1.0f;
- pixels[i*4+2] = pixels[i*3+2];
- pixels[i*4+1] = pixels[i*3+1];
- pixels[i*4+0] = pixels[i*3+0];
+ else if(components == 2) {
+ /* grayscale + alpha */
+ for(size_t i = num_pixels-1, pixel = 0; pixel < num_pixels; pixel++, i--) {
+ pixels[i*4+3] = pixels[i*2+1];
+ pixels[i*4+2] = pixels[i*2+0];
+ pixels[i*4+1] = pixels[i*2+0];
+ pixels[i*4+0] = pixels[i*2+0];
+ }
}
- }
- else if(components == 1) {
- /* grayscale */
- for(size_t i = num_pixels-1, pixel = 0; pixel < num_pixels; pixel++, i--) {
- pixels[i*4+3] = 1.0f;
- pixels[i*4+2] = pixels[i];
- pixels[i*4+1] = pixels[i];
- pixels[i*4+0] = pixels[i];
+ else if(components == 3) {
+ /* RGB */
+ for(size_t i = num_pixels-1, pixel = 0; pixel < num_pixels; pixel++, i--) {
+ pixels[i*4+3] = 1.0f;
+ pixels[i*4+2] = pixels[i*3+2];
+ pixels[i*4+1] = pixels[i*3+1];
+ pixels[i*4+0] = pixels[i*3+0];
+ }
}
- }
-
- if(img->use_alpha == false) {
- for(size_t i = num_pixels-1, pixel = 0; pixel < num_pixels; pixel++, i--) {
- pixels[i*4+3] = 1.0f;
+ else if(components == 1) {
+ /* grayscale */
+ for(size_t i = num_pixels-1, pixel = 0; pixel < num_pixels; pixel++, i--) {
+ pixels[i*4+3] = 1.0f;
+ pixels[i*4+2] = pixels[i];
+ pixels[i*4+1] = pixels[i];
+ pixels[i*4+0] = pixels[i];
+ }
}
- }
-
- return true;
-}
-
-bool ImageManager::file_load_float_image(Image *img, device_vector<float>& tex_img)
-{
- ImageInput *in = NULL;
- int width, height, depth, components;
-
- if(!file_load_image_generic(img, &in, width, height, depth, components))
- return false;
-
- /* read BW pixels */
- float *pixels = (float*)tex_img.resize(width, height, depth);
- if(pixels == NULL) {
- return false;
- }
- if(in) {
- float *readpixels = pixels;
-
- if(depth <= 1) {
- int scanlinesize = width*components*sizeof(float);
-
- in->read_image(TypeDesc::FLOAT,
- (uchar*)readpixels + (height-1)*scanlinesize,
- AutoStride,
- -scanlinesize,
- AutoStride);
- }
- else {
- in->read_image(TypeDesc::FLOAT, (uchar*)readpixels);
+ if(img->use_alpha == false) {
+ for(size_t i = num_pixels-1, pixel = 0; pixel < num_pixels; pixel++, i--) {
+ pixels[i*4+3] = 1.0f;
+ }
}
-
- in->close();
- delete in;
- }
- else {
- builtin_image_float_pixels_cb(img->filename, img->builtin_data, pixels);
}
return true;
@@ -760,7 +677,7 @@ void ImageManager::device_load_image(Device *device, DeviceScene *dscene, ImageD
device->tex_free(tex_img);
}
- if(!file_load_float4_image(img, tex_img)) {
+ if(!file_load_float_image(img, type, tex_img)) {
/* on failure to load, we set a 1x1 pixels pink image */
float *pixels = (float*)tex_img.resize(1, 1);
@@ -786,7 +703,7 @@ void ImageManager::device_load_image(Device *device, DeviceScene *dscene, ImageD
device->tex_free(tex_img);
}
- if(!file_load_float_image(img, tex_img)) {
+ if(!file_load_float_image(img, type, tex_img)) {
/* on failure to load, we set a 1x1 pixels pink image */
float *pixels = (float*)tex_img.resize(1, 1);
@@ -809,7 +726,7 @@ void ImageManager::device_load_image(Device *device, DeviceScene *dscene, ImageD
device->tex_free(tex_img);
}
- if(!file_load_byte4_image(img, tex_img)) {
+ if(!file_load_byte_image(img, type, tex_img)) {
/* on failure to load, we set a 1x1 pixels pink image */
uchar *pixels = (uchar*)tex_img.resize(1, 1);
@@ -835,7 +752,7 @@ void ImageManager::device_load_image(Device *device, DeviceScene *dscene, ImageD
device->tex_free(tex_img);
}
- if(!file_load_byte_image(img, tex_img)) {
+ if(!file_load_byte_image(img, type, tex_img)) {
/* on failure to load, we set a 1x1 pixels pink image */
uchar *pixels = (uchar*)tex_img.resize(1, 1);
diff --git a/intern/cycles/render/image.h b/intern/cycles/render/image.h
index 53f739cd356..8735133fd91 100644
--- a/intern/cycles/render/image.h
+++ b/intern/cycles/render/image.h
@@ -96,9 +96,8 @@ public:
private:
int tex_num_images[IMAGE_DATA_NUM_TYPES];
- int tex_image_byte4_start;
- int tex_image_float_start;
- int tex_image_byte_start;
+ int tex_start_images[IMAGE_DATA_NUM_TYPES];
+
thread_mutex device_mutex;
int animation_frame;
@@ -107,10 +106,12 @@ private:
bool pack_images;
bool file_load_image_generic(Image *img, ImageInput **in, int &width, int &height, int &depth, int &components);
- bool file_load_byte4_image(Image *img, device_vector<uchar4>& tex_img);
- bool file_load_byte_image(Image *img, device_vector<uchar>& tex_img);
- bool file_load_float4_image(Image *img, device_vector<float4>& tex_img);
- bool file_load_float_image(Image *img, device_vector<float>& tex_img);
+
+ template<typename T>
+ bool file_load_byte_image(Image *img, ImageDataType type, device_vector<T>& tex_img);
+
+ template<typename T>
+ bool file_load_float_image(Image *img, ImageDataType type, device_vector<T>& tex_img);
int type_index_to_flattened_slot(int slot, ImageDataType type);
int flattened_slot_to_type_index(int flat_slot, ImageDataType *type);
diff --git a/intern/cycles/render/integrator.cpp b/intern/cycles/render/integrator.cpp
index 41e2571dc24..2a10eb474a4 100644
--- a/intern/cycles/render/integrator.cpp
+++ b/intern/cycles/render/integrator.cpp
@@ -204,6 +204,11 @@ void Integrator::device_free(Device *device, DeviceScene *dscene)
dscene->sobol_directions.clear();
}
+bool Integrator::modified(const Integrator& integrator)
+{
+ return !Node::equals(integrator);
+}
+
void Integrator::tag_update(Scene *scene)
{
foreach(Shader *shader, scene->shaders) {
diff --git a/intern/cycles/render/integrator.h b/intern/cycles/render/integrator.h
index a5cfb0c7863..39eaaf246d4 100644
--- a/intern/cycles/render/integrator.h
+++ b/intern/cycles/render/integrator.h
@@ -86,6 +86,7 @@ public:
void device_update(Device *device, DeviceScene *dscene, Scene *scene);
void device_free(Device *device, DeviceScene *dscene);
+ bool modified(const Integrator& integrator);
void tag_update(Scene *scene);
};
diff --git a/intern/cycles/render/light.cpp b/intern/cycles/render/light.cpp
index c20bf6b5e9e..9ef35820254 100644
--- a/intern/cycles/render/light.cpp
+++ b/intern/cycles/render/light.cpp
@@ -247,7 +247,8 @@ void LightManager::device_update_distribution(Device *device, DeviceScene *dscen
/* count triangles */
if(have_emission) {
- for(size_t i = 0; i < mesh->triangles.size(); i++) {
+ size_t mesh_num_triangles = mesh->num_triangles();
+ for(size_t i = 0; i < mesh_num_triangles; i++) {
int shader_index = mesh->shader[i];
Shader *shader = (shader_index < mesh->used_shaders.size()) ?
mesh->used_shaders[shader_index] : scene->default_surface;
@@ -319,7 +320,8 @@ void LightManager::device_update_distribution(Device *device, DeviceScene *dscen
use_light_visibility = true;
}
- for(size_t i = 0; i < mesh->triangles.size(); i++) {
+ size_t mesh_num_triangles = mesh->num_triangles();
+ for(size_t i = 0; i < mesh_num_triangles; i++) {
int shader_index = mesh->shader[i];
Shader *shader = (shader_index < mesh->used_shaders.size()) ?
mesh->used_shaders[shader_index] : scene->default_surface;
@@ -331,7 +333,7 @@ void LightManager::device_update_distribution(Device *device, DeviceScene *dscen
distribution[offset].w = __int_as_float(object_id);
offset++;
- Mesh::Triangle t = mesh->triangles[i];
+ Mesh::Triangle t = mesh->get_triangle(i);
float3 p1 = mesh->verts[t.v[0]];
float3 p2 = mesh->verts[t.v[1]];
float3 p3 = mesh->verts[t.v[2]];
diff --git a/intern/cycles/render/mesh.cpp b/intern/cycles/render/mesh.cpp
index de1533c26af..e25155630bd 100644
--- a/intern/cycles/render/mesh.cpp
+++ b/intern/cycles/render/mesh.cpp
@@ -51,14 +51,14 @@ void Mesh::Triangle::bounds_grow(const float3 *verts, BoundBox& bounds) const
/* Curve */
-void Mesh::Curve::bounds_grow(const int k, const float4 *curve_keys, BoundBox& bounds) const
+void Mesh::Curve::bounds_grow(const int k, const float3 *curve_keys, const float *curve_radius, BoundBox& bounds) const
{
float3 P[4];
- P[0] = float4_to_float3(curve_keys[max(first_key + k - 1,first_key)]);
- P[1] = float4_to_float3(curve_keys[first_key + k]);
- P[2] = float4_to_float3(curve_keys[first_key + k + 1]);
- P[3] = float4_to_float3(curve_keys[min(first_key + k + 2, first_key + num_keys - 1)]);
+ P[0] = curve_keys[max(first_key + k - 1,first_key)];
+ P[1] = curve_keys[first_key + k];
+ P[2] = curve_keys[first_key + k + 1];
+ P[3] = curve_keys[min(first_key + k + 2, first_key + num_keys - 1)];
float3 lower;
float3 upper;
@@ -67,7 +67,7 @@ void Mesh::Curve::bounds_grow(const int k, const float4 *curve_keys, BoundBox& b
curvebounds(&lower.y, &upper.y, P, 1);
curvebounds(&lower.z, &upper.z, P, 2);
- float mr = max(curve_keys[first_key + k].w, curve_keys[first_key + k + 1].w);
+ float mr = max(curve_radius[first_key + k], curve_radius[first_key + k + 1]);
bounds.grow(lower, mr);
bounds.grow(upper, mr);
@@ -75,19 +75,42 @@ void Mesh::Curve::bounds_grow(const int k, const float4 *curve_keys, BoundBox& b
/* Mesh */
+NODE_DEFINE(Mesh)
+{
+ NodeType* type = NodeType::add("mesh", create);
+
+ static NodeEnum displacement_method_enum;
+ displacement_method_enum.insert("bump", DISPLACE_BUMP);
+ displacement_method_enum.insert("true", DISPLACE_TRUE);
+ displacement_method_enum.insert("both", DISPLACE_BOTH);
+ SOCKET_ENUM(displacement_method, "Displacement Method", displacement_method_enum, DISPLACE_BUMP);
+
+ SOCKET_INT(motion_steps, "Motion Steps", 3);
+ SOCKET_BOOLEAN(use_motion_blur, "Use Motion Blur", false);
+
+ SOCKET_INT_ARRAY(triangles, "Triangles", array<int>());
+ SOCKET_POINT_ARRAY(verts, "Vertices", array<float3>());
+ SOCKET_INT_ARRAY(shader, "Shader", array<int>());
+ SOCKET_BOOLEAN_ARRAY(smooth, "Smooth", array<bool>());
+
+ SOCKET_POINT_ARRAY(curve_keys, "Curve Keys", array<float3>());
+ SOCKET_FLOAT_ARRAY(curve_radius, "Curve Radius", array<float>());
+ SOCKET_INT_ARRAY(curve_first_key, "Curve First Key", array<int>());
+ SOCKET_INT_ARRAY(curve_shader, "Curve Shader", array<int>());
+
+ return type;
+}
+
Mesh::Mesh()
+: Node(node_type)
{
need_update = true;
need_update_rebuild = false;
transform_applied = false;
transform_negative_scaled = false;
transform_normal = transform_identity();
- displacement_method = DISPLACE_BUMP;
bounds = BoundBox::empty;
- motion_steps = 3;
- use_motion_blur = false;
-
bvh = NULL;
tri_offset = 0;
@@ -99,6 +122,8 @@ Mesh::Mesh()
attributes.triangle_mesh = this;
curve_attributes.curve_mesh = this;
+ geometry_flags = GEOMETRY_NONE;
+
has_volume = false;
has_surface_bssrdf = false;
}
@@ -108,21 +133,49 @@ Mesh::~Mesh()
delete bvh;
}
-void Mesh::reserve(int numverts, int numtris, int numcurves, int numcurvekeys)
+void Mesh::resize_mesh(int numverts, int numtris)
{
- /* reserve space to add verts and triangles later */
verts.resize(numverts);
- triangles.resize(numtris);
+ triangles.resize(numtris * 3);
shader.resize(numtris);
smooth.resize(numtris);
forms_quad.resize(numtris);
- curve_keys.resize(numcurvekeys);
- curves.resize(numcurves);
+ attributes.resize();
+}
+
+void Mesh::reserve_mesh(int numverts, int numtris)
+{
+ /* reserve space to add verts and triangles later */
+ verts.reserve(numverts);
+ triangles.reserve(numtris * 3);
+ shader.reserve(numtris);
+ smooth.reserve(numtris);
+
+ forms_quad.reserve(numtris);
- attributes.reserve();
- curve_attributes.reserve();
+ attributes.resize(true);
+}
+
+void Mesh::resize_curves(int numcurves, int numkeys)
+{
+ curve_keys.resize(numkeys);
+ curve_radius.resize(numkeys);
+ curve_first_key.resize(numcurves);
+ curve_shader.resize(numcurves);
+
+ curve_attributes.resize();
+}
+
+void Mesh::reserve_curves(int numcurves, int numkeys)
+{
+ curve_keys.reserve(numkeys);
+ curve_radius.reserve(numkeys);
+ curve_first_key.reserve(numcurves);
+ curve_shader.reserve(numcurves);
+
+ curve_attributes.resize(true);
}
void Mesh::clear()
@@ -136,7 +189,9 @@ void Mesh::clear()
forms_quad.clear();
curve_keys.clear();
- curves.clear();
+ curve_radius.clear();
+ curve_first_key.clear();
+ curve_shader.clear();
attributes.clear();
curve_attributes.clear();
@@ -151,7 +206,7 @@ void Mesh::clear()
int Mesh::split_vertex(int vertex)
{
/* copy vertex location and vertex attributes */
- verts.push_back(verts[vertex]);
+ add_vertex_slow(verts[vertex]);
foreach(Attribute& attr, attributes.attributes) {
if(attr.element == ATTR_ELEMENT_VERTEX) {
@@ -164,48 +219,36 @@ int Mesh::split_vertex(int vertex)
return verts.size() - 1;
}
-void Mesh::set_triangle(int i, int v0, int v1, int v2, int shader_, bool smooth_, bool forms_quad_)
+void Mesh::add_vertex(float3 P)
{
- Triangle tri;
- tri.v[0] = v0;
- tri.v[1] = v1;
- tri.v[2] = v2;
-
- triangles[i] = tri;
- shader[i] = shader_;
- smooth[i] = smooth_;
- forms_quad[i] = forms_quad_;
+ verts.push_back_reserved(P);
+}
+
+void Mesh::add_vertex_slow(float3 P)
+{
+ verts.push_back_slow(P);
}
void Mesh::add_triangle(int v0, int v1, int v2, int shader_, bool smooth_, bool forms_quad_)
{
- Triangle tri;
- tri.v[0] = v0;
- tri.v[1] = v1;
- tri.v[2] = v2;
-
- triangles.push_back(tri);
- shader.push_back(shader_);
- smooth.push_back(smooth_);
- forms_quad.push_back(forms_quad_);
+ triangles.push_back_reserved(v0);
+ triangles.push_back_reserved(v1);
+ triangles.push_back_reserved(v2);
+ shader.push_back_reserved(shader_);
+ smooth.push_back_reserved(smooth_);
+ forms_quad.push_back_reserved(forms_quad_);
}
void Mesh::add_curve_key(float3 co, float radius)
{
- float4 key = float3_to_float4(co);
- key.w = radius;
-
- curve_keys.push_back(key);
+ curve_keys.push_back_reserved(co);
+ curve_radius.push_back_reserved(radius);
}
-void Mesh::add_curve(int first_key, int num_keys, int shader)
+void Mesh::add_curve(int first_key, int shader)
{
- Curve curve;
- curve.first_key = first_key;
- curve.num_keys = num_keys;
- curve.shader = shader;
-
- curves.push_back(curve);
+ curve_first_key.push_back_reserved(first_key);
+ curve_shader.push_back_reserved(shader);
}
void Mesh::compute_bounds()
@@ -219,7 +262,7 @@ void Mesh::compute_bounds()
bnds.grow(verts[i]);
for(size_t i = 0; i < curve_keys_size; i++)
- bnds.grow(float4_to_float3(curve_keys[i]), curve_keys[i].w);
+ bnds.grow(curve_keys[i], curve_radius[i]);
Attribute *attr = attributes.find(ATTR_STD_MOTION_VERTEX_POSITION);
if(use_motion_blur && attr) {
@@ -247,7 +290,7 @@ void Mesh::compute_bounds()
bnds.grow_safe(verts[i]);
for(size_t i = 0; i < curve_keys_size; i++)
- bnds.grow_safe(float4_to_float3(curve_keys[i]), curve_keys[i].w);
+ bnds.grow_safe(curve_keys[i], curve_radius[i]);
if(use_motion_blur && attr) {
size_t steps_size = verts.size() * (motion_steps - 1);
@@ -285,7 +328,7 @@ static float3 compute_face_normal(const Mesh::Triangle& t, float3 *verts)
float normlen = len(norm);
if(normlen == 0.0f)
- return make_float3(0.0f, 0.0f, 0.0f);
+ return make_float3(1.0f, 0.0f, 0.0f);
return norm / normlen;
}
@@ -301,15 +344,14 @@ void Mesh::add_face_normals()
float3 *fN = attr_fN->data_float3();
/* compute face normals */
- size_t triangles_size = triangles.size();
+ size_t triangles_size = num_triangles();
bool flip = transform_negative_scaled;
if(triangles_size) {
float3 *verts_ptr = &verts[0];
- Triangle *triangles_ptr = &triangles[0];
for(size_t i = 0; i < triangles_size; i++) {
- fN[i] = compute_face_normal(triangles_ptr[i], verts_ptr);
+ fN[i] = compute_face_normal(get_triangle(i), verts_ptr);
if(flip)
fN[i] = -fN[i];
@@ -329,7 +371,7 @@ void Mesh::add_vertex_normals()
{
bool flip = transform_negative_scaled;
size_t verts_size = verts.size();
- size_t triangles_size = triangles.size();
+ size_t triangles_size = num_triangles();
/* static vertex normals */
if(!attributes.find(ATTR_STD_VERTEX_NORMAL)) {
@@ -344,11 +386,10 @@ void Mesh::add_vertex_normals()
memset(vN, 0, verts.size()*sizeof(float3));
if(triangles_size) {
- Triangle *triangles_ptr = &triangles[0];
for(size_t i = 0; i < triangles_size; i++)
for(size_t j = 0; j < 3; j++)
- vN[triangles_ptr[i].v[j]] += fN[i];
+ vN[get_triangle(i).v[j]] += fN[i];
}
for(size_t i = 0; i < verts_size; i++) {
@@ -374,12 +415,10 @@ void Mesh::add_vertex_normals()
memset(mN, 0, verts.size()*sizeof(float3));
if(triangles_size) {
- Triangle *triangles_ptr = &triangles[0];
-
for(size_t i = 0; i < triangles_size; i++) {
for(size_t j = 0; j < 3; j++) {
- float3 fN = compute_face_normal(triangles_ptr[i], mP);
- mN[triangles_ptr[i].v[j]] += fN;
+ float3 fN = compute_face_normal(get_triangle(i), mP);
+ mN[get_triangle(i).v[j]] += fN;
}
}
}
@@ -402,8 +441,8 @@ void Mesh::pack_normals(Scene *scene, uint *tri_shader, float4 *vnormal)
uint last_shader = -1;
bool last_smooth = false;
- size_t triangles_size = triangles.size();
- uint *shader_ptr = (shader.size())? &shader[0]: NULL;
+ size_t triangles_size = num_triangles();
+ int *shader_ptr = (shader.size())? &shader[0]: NULL;
bool do_transform = transform_applied;
Transform ntfm = transform_normal;
@@ -446,13 +485,11 @@ void Mesh::pack_verts(float4 *tri_verts, float4 *tri_vindex, size_t vert_offset)
}
}
- size_t triangles_size = triangles.size();
+ size_t triangles_size = num_triangles();
if(triangles_size) {
- Triangle *triangles_ptr = &triangles[0];
-
for(size_t i = 0; i < triangles_size; i++) {
- Triangle t = triangles_ptr[i];
+ Triangle t = get_triangle(i);
tri_vindex[i] = make_float4(
__int_as_float(t.v[0] + vert_offset),
@@ -466,27 +503,25 @@ void Mesh::pack_verts(float4 *tri_verts, float4 *tri_vindex, size_t vert_offset)
void Mesh::pack_curves(Scene *scene, float4 *curve_key_co, float4 *curve_data, size_t curvekey_offset)
{
size_t curve_keys_size = curve_keys.size();
- float4 *keys_ptr = NULL;
/* pack curve keys */
if(curve_keys_size) {
- keys_ptr = &curve_keys[0];
+ float3 *keys_ptr = &curve_keys[0];
+ float *radius_ptr = &curve_radius[0];
for(size_t i = 0; i < curve_keys_size; i++)
- curve_key_co[i] = keys_ptr[i];
+ curve_key_co[i] = make_float4(keys_ptr[i].x, keys_ptr[i].y, keys_ptr[i].z, radius_ptr[i]);
}
/* pack curve segments */
- size_t curve_num = curves.size();
+ size_t curve_num = num_curves();
if(curve_num) {
- Curve *curve_ptr = &curves[0];
- int shader_id = 0;
-
for(size_t i = 0; i < curve_num; i++) {
- Curve curve = curve_ptr[i];
- Shader *shader = (curve.shader < used_shaders.size()) ?
- used_shaders[curve.shader] : scene->default_surface;
+ Curve curve = get_curve(i);
+ int shader_id = curve_shader[i];
+ Shader *shader = (shader_id < used_shaders.size()) ?
+ used_shaders[shader_id] : scene->default_surface;
shader_id = scene->shader_manager->get_shader_id(shader, this, false);
curve_data[i] = make_float4(
@@ -732,7 +767,7 @@ void MeshManager::update_svm_attributes(Device *device, DeviceScene *dscene, Sce
else
id = scene->shader_manager->get_attribute_id(req.std);
- if(mesh->triangles.size()) {
+ if(mesh->num_triangles()) {
attr_map[index].x = id;
attr_map[index].y = req.triangle_element;
attr_map[index].z = as_uint(req.triangle_offset);
@@ -747,7 +782,7 @@ void MeshManager::update_svm_attributes(Device *device, DeviceScene *dscene, Sce
index++;
- if(mesh->curves.size()) {
+ if(mesh->num_curves()) {
attr_map[index].x = id;
attr_map[index].y = req.curve_element;
attr_map[index].z = as_uint(req.curve_offset);
@@ -793,9 +828,9 @@ static void update_attribute_element_size(Mesh *mesh,
if(mattr) {
size_t size = mattr->element_size(
mesh->verts.size(),
- mesh->triangles.size(),
+ mesh->num_triangles(),
mesh->motion_steps,
- mesh->curves.size(),
+ mesh->num_curves(),
mesh->curve_keys.size());
if(mattr->element == ATTR_ELEMENT_VOXEL) {
@@ -836,9 +871,9 @@ static void update_attribute_element_offset(Mesh *mesh,
/* store attribute data in arrays */
size_t size = mattr->element_size(
mesh->verts.size(),
- mesh->triangles.size(),
+ mesh->num_triangles(),
mesh->motion_steps,
- mesh->curves.size(),
+ mesh->num_curves(),
mesh->curve_keys.size());
if(mattr->element == ATTR_ELEMENT_VOXEL) {
@@ -1052,10 +1087,10 @@ void MeshManager::device_update_mesh(Device *device, DeviceScene *dscene, Scene
mesh->curve_offset = curve_size;
vert_size += mesh->verts.size();
- tri_size += mesh->triangles.size();
+ tri_size += mesh->num_triangles();
curve_key_size += mesh->curve_keys.size();
- curve_size += mesh->curves.size();
+ curve_size += mesh->num_curves();
}
if(tri_size != 0) {
@@ -1450,7 +1485,7 @@ bool Mesh::need_attribute(Scene * /*scene*/, ustring name)
void Mesh::tessellate(DiagSplit *split)
{
- int num_faces = triangles.size();
+ int num_faces = num_triangles();
add_face_normals();
add_vertex_normals();
@@ -1465,16 +1500,17 @@ void Mesh::tessellate(DiagSplit *split)
if(!forms_quad[f]) {
/* triangle */
LinearTrianglePatch patch;
+ Triangle triangle = get_triangle(f);
float3 *hull = patch.hull;
float3 *normals = patch.normals;
for(int i = 0; i < 3; i++) {
- hull[i] = verts[triangles[f].v[i]];
+ hull[i] = verts[triangle.v[i]];
}
if(smooth[f]) {
for(int i = 0; i < 3; i++) {
- normals[i] = vN[triangles[f].v[i]];
+ normals[i] = vN[triangle.v[i]];
}
}
else {
@@ -1488,19 +1524,21 @@ void Mesh::tessellate(DiagSplit *split)
else {
/* quad */
LinearQuadPatch patch;
+ Triangle triangle0 = get_triangle(f);
+ Triangle triangle1 = get_triangle(f+1);
float3 *hull = patch.hull;
float3 *normals = patch.normals;
- hull[0] = verts[triangles[f ].v[0]];
- hull[1] = verts[triangles[f ].v[1]];
- hull[3] = verts[triangles[f ].v[2]];
- hull[2] = verts[triangles[f+1].v[2]];
+ hull[0] = verts[triangle0.v[0]];
+ hull[1] = verts[triangle0.v[1]];
+ hull[3] = verts[triangle0.v[2]];
+ hull[2] = verts[triangle1.v[2]];
if(smooth[f]) {
- normals[0] = vN[triangles[f ].v[0]];
- normals[1] = vN[triangles[f ].v[1]];
- normals[3] = vN[triangles[f ].v[2]];
- normals[2] = vN[triangles[f+1].v[2]];
+ normals[0] = vN[triangle0.v[0]];
+ normals[1] = vN[triangle0.v[1]];
+ normals[3] = vN[triangle0.v[2]];
+ normals[2] = vN[triangle1.v[2]];
}
else {
for(int i = 0; i < 4; i++) {
diff --git a/intern/cycles/render/mesh.h b/intern/cycles/render/mesh.h
index 557b664bff3..edad6d32f00 100644
--- a/intern/cycles/render/mesh.h
+++ b/intern/cycles/render/mesh.h
@@ -18,6 +18,7 @@
#define __MESH_H__
#include "attribute.h"
+#include "node.h"
#include "shader.h"
#include "util_boundbox.h"
@@ -42,8 +43,10 @@ class DiagSplit;
/* Mesh */
-class Mesh {
+class Mesh : public Node {
public:
+ NODE_DECLARE;
+
/* Mesh Triangle */
struct Triangle {
int v[3];
@@ -51,17 +54,41 @@ public:
void bounds_grow(const float3 *verts, BoundBox& bounds) const;
};
+ Triangle get_triangle(size_t i) const
+ {
+ Triangle tri = {{triangles[i*3 + 0], triangles[i*3 + 1], triangles[i*3 + 2]}};
+ return tri;
+ }
+
+ size_t num_triangles() const
+ {
+ return triangles.size() / 3;
+ }
+
/* Mesh Curve */
struct Curve {
int first_key;
int num_keys;
- uint shader;
int num_segments() { return num_keys - 1; }
- void bounds_grow(const int k, const float4 *curve_keys, BoundBox& bounds) const;
+ void bounds_grow(const int k, const float3 *curve_keys, const float *curve_radius, BoundBox& bounds) const;
};
+ Curve get_curve(size_t i) const
+ {
+ int first = curve_first_key[i];
+ int next_first = (i+1 < curve_first_key.size()) ? curve_first_key[i+1] : curve_keys.size();
+
+ Curve curve = {first, next_first - first};
+ return curve;
+ }
+
+ size_t num_curves() const
+ {
+ return curve_first_key.size();
+ }
+
/* Displacement */
enum DisplacementMethod {
DISPLACE_BUMP = 0,
@@ -71,8 +98,6 @@ public:
DISPLACE_NUM_METHODS,
};
- ustring name;
-
/* Mesh Data */
enum GeometryFlags {
GEOMETRY_NONE = 0,
@@ -82,17 +107,19 @@ public:
int geometry_flags; /* used to distinguish meshes with no verts
and meshed for which geometry is not created */
- vector<float3> verts;
- vector<Triangle> triangles;
- vector<uint> shader;
- vector<bool> smooth;
- vector<bool> forms_quad; /* used to tell if triangle is part of a quad patch */
+ array<int> triangles;
+ array<float3> verts;
+ array<int> shader;
+ array<bool> smooth;
+ array<bool> forms_quad; /* used to tell if triangle is part of a quad patch */
bool has_volume; /* Set in the device_update_flags(). */
bool has_surface_bssrdf; /* Set in the device_update_flags(). */
- vector<float4> curve_keys; /* co + radius */
- vector<Curve> curves;
+ array<float3> curve_keys;
+ array<float> curve_radius;
+ array<int> curve_first_key;
+ array<int> curve_shader;
vector<Shader*> used_shaders;
AttributeSet attributes;
@@ -123,12 +150,16 @@ public:
Mesh();
~Mesh();
- void reserve(int numverts, int numfaces, int numcurves, int numcurvekeys);
+ void resize_mesh(int numverts, int numfaces);
+ void reserve_mesh(int numverts, int numfaces);
+ void resize_curves(int numcurves, int numkeys);
+ void reserve_curves(int numcurves, int numkeys);
void clear();
- void set_triangle(int i, int v0, int v1, int v2, int shader, bool smooth, bool forms_quad = false);
+ void add_vertex(float3 P);
+ void add_vertex_slow(float3 P);
void add_triangle(int v0, int v1, int v2, int shader, bool smooth, bool forms_quad = false);
void add_curve_key(float3 loc, float radius);
- void add_curve(int first_key, int num_keys, int shader);
+ void add_curve(int first_key, int shader);
int split_vertex(int vertex);
void compute_bounds();
diff --git a/intern/cycles/render/mesh_displace.cpp b/intern/cycles/render/mesh_displace.cpp
index d19bf2084d7..95f46ff02a2 100644
--- a/intern/cycles/render/mesh_displace.cpp
+++ b/intern/cycles/render/mesh_displace.cpp
@@ -60,8 +60,9 @@ bool MeshManager::displace(Device *device, DeviceScene *dscene, Scene *scene, Me
uint4 *d_input_data = d_input.resize(num_verts);
size_t d_input_size = 0;
- for(size_t i = 0; i < mesh->triangles.size(); i++) {
- Mesh::Triangle t = mesh->triangles[i];
+ size_t num_triangles = mesh->num_triangles();
+ for(size_t i = 0; i < num_triangles; i++) {
+ Mesh::Triangle t = mesh->get_triangle(i);
int shader_index = mesh->shader[i];
Shader *shader = (shader_index < mesh->used_shaders.size()) ?
mesh->used_shaders[shader_index] : scene->default_surface;
@@ -146,8 +147,8 @@ bool MeshManager::displace(Device *device, DeviceScene *dscene, Scene *scene, Me
float4 *offset = (float4*)d_output.data_pointer;
Attribute *attr_mP = mesh->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION);
- for(size_t i = 0; i < mesh->triangles.size(); i++) {
- Mesh::Triangle t = mesh->triangles[i];
+ for(size_t i = 0; i < num_triangles; i++) {
+ Mesh::Triangle t = mesh->get_triangle(i);
int shader_index = mesh->shader[i];
Shader *shader = (shader_index < mesh->used_shaders.size()) ?
mesh->used_shaders[shader_index] : scene->default_surface;
diff --git a/intern/cycles/render/nodes.cpp b/intern/cycles/render/nodes.cpp
index 998d9cf31dd..df0fee63113 100644
--- a/intern/cycles/render/nodes.cpp
+++ b/intern/cycles/render/nodes.cpp
@@ -30,9 +30,9 @@ CCL_NAMESPACE_BEGIN
/* Texture Mapping */
-static ShaderEnum texture_mapping_type_init()
+static NodeEnum texture_mapping_type_init()
{
- ShaderEnum enm;
+ NodeEnum enm;
enm.insert("Point", TextureMapping::POINT);
enm.insert("Texture", TextureMapping::TEXTURE);
@@ -42,9 +42,9 @@ static ShaderEnum texture_mapping_type_init()
return enm;
}
-static ShaderEnum texture_mapping_mapping_init()
+static NodeEnum texture_mapping_mapping_init()
{
- ShaderEnum enm;
+ NodeEnum enm;
enm.insert("None", TextureMapping::NONE);
enm.insert("X", TextureMapping::X);
@@ -54,9 +54,9 @@ static ShaderEnum texture_mapping_mapping_init()
return enm;
}
-static ShaderEnum texture_mapping_projection_init()
+static NodeEnum texture_mapping_projection_init()
{
- ShaderEnum enm;
+ NodeEnum enm;
enm.insert("Flat", TextureMapping::FLAT);
enm.insert("Cube", TextureMapping::CUBE);
@@ -66,9 +66,9 @@ static ShaderEnum texture_mapping_projection_init()
return enm;
}
-ShaderEnum TextureMapping::type_enum = texture_mapping_type_init();
-ShaderEnum TextureMapping::mapping_enum = texture_mapping_mapping_init();
-ShaderEnum TextureMapping::projection_enum = texture_mapping_projection_init();
+NodeEnum TextureMapping::type_enum = texture_mapping_type_init();
+NodeEnum TextureMapping::mapping_enum = texture_mapping_mapping_init();
+NodeEnum TextureMapping::projection_enum = texture_mapping_projection_init();
TextureMapping::TextureMapping()
{
@@ -193,7 +193,7 @@ int TextureMapping::compile_begin(SVMCompiler& compiler, ShaderInput *vector_in)
{
if(!skip()) {
int offset_in = compiler.stack_assign(vector_in);
- int offset_out = compiler.stack_find_offset(SHADER_SOCKET_VECTOR);
+ int offset_out = compiler.stack_find_offset(SocketType::VECTOR);
compile(compiler, offset_in, offset_out);
@@ -206,7 +206,7 @@ int TextureMapping::compile_begin(SVMCompiler& compiler, ShaderInput *vector_in)
void TextureMapping::compile_end(SVMCompiler& compiler, ShaderInput *vector_in, int vector_offset)
{
if(!skip()) {
- compiler.stack_clear_offset(vector_in->type, vector_offset);
+ compiler.stack_clear_offset(vector_in->type(), vector_offset);
}
}
@@ -222,9 +222,9 @@ void TextureMapping::compile(OSLCompiler &compiler)
/* Image Texture */
-static ShaderEnum color_space_init()
+static NodeEnum color_space_init()
{
- ShaderEnum enm;
+ NodeEnum enm;
enm.insert("None", 0);
enm.insert("Color", 1);
@@ -232,9 +232,9 @@ static ShaderEnum color_space_init()
return enm;
}
-static ShaderEnum image_projection_init()
+static NodeEnum image_projection_init()
{
- ShaderEnum enm;
+ NodeEnum enm;
enm.insert("Flat", NODE_IMAGE_PROJ_FLAT);
enm.insert("Box", NODE_IMAGE_PROJ_BOX);
@@ -259,8 +259,8 @@ static const char* get_osl_interpolation_parameter(InterpolationType interpolati
}
}
-ShaderEnum ImageTextureNode::color_space_enum = color_space_init();
-ShaderEnum ImageTextureNode::projection_enum = image_projection_init();
+NodeEnum ImageTextureNode::color_space_enum = color_space_init();
+NodeEnum ImageTextureNode::projection_enum = image_projection_init();
ImageTextureNode::ImageTextureNode()
: ImageSlotTextureNode("image_texture")
@@ -272,16 +272,16 @@ ImageTextureNode::ImageTextureNode()
use_alpha = true;
filename = "";
builtin_data = NULL;
- color_space = ustring("Color");
- projection = ustring("Flat");
+ color_space = NODE_COLOR_SPACE_COLOR;
+ projection = NODE_IMAGE_PROJ_FLAT;
interpolation = INTERPOLATION_LINEAR;
extension = EXTENSION_REPEAT;
projection_blend = 0.0f;
animated = false;
- add_input("Vector", SHADER_SOCKET_POINT, ShaderInput::TEXTURE_UV);
- add_output("Color", SHADER_SOCKET_COLOR);
- add_output("Alpha", SHADER_SOCKET_FLOAT);
+ add_input("Vector", SocketType::POINT, make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_TEXTURE_UV);
+ add_output("Color", SocketType::COLOR);
+ add_output("Alpha", SocketType::FLOAT);
}
ImageTextureNode::~ImageTextureNode()
@@ -341,10 +341,10 @@ void ImageTextureNode::compile(SVMCompiler& compiler)
}
if(slot != -1) {
- int srgb = (is_linear || color_space != "Color")? 0: 1;
+ int srgb = (is_linear || color_space != NODE_COLOR_SPACE_COLOR)? 0: 1;
int vector_offset = tex_mapping.compile_begin(compiler, vector_in);
- if(projection != "Box") {
+ if(projection != NODE_IMAGE_PROJ_BOX) {
compiler.add_node(NODE_TEX_IMAGE,
slot,
compiler.encode_uchar4(
@@ -352,7 +352,7 @@ void ImageTextureNode::compile(SVMCompiler& compiler)
compiler.stack_assign_if_linked(color_out),
compiler.stack_assign_if_linked(alpha_out),
srgb),
- projection_enum[projection]);
+ projection);
}
else {
compiler.add_node(NODE_TEX_IMAGE_BOX,
@@ -421,7 +421,7 @@ void ImageTextureNode::compile(OSLCompiler& compiler)
*/
compiler.parameter("filename", string_printf("@%d", slot).c_str());
}
- if(is_linear || color_space != "Color")
+ if(is_linear || color_space != NODE_COLOR_SPACE_COLOR)
compiler.parameter("color_space", "Linear");
else
compiler.parameter("color_space", "sRGB");
@@ -433,14 +433,14 @@ void ImageTextureNode::compile(OSLCompiler& compiler)
switch(extension) {
case EXTENSION_EXTEND:
- compiler.parameter("wrap", "clamp");
+ compiler.parameter("extension", "clamp");
break;
case EXTENSION_CLIP:
- compiler.parameter("wrap", "black");
+ compiler.parameter("extension", "black");
break;
case EXTENSION_REPEAT:
default:
- compiler.parameter("wrap", "periodic");
+ compiler.parameter("extension", "periodic");
break;
}
@@ -449,9 +449,9 @@ void ImageTextureNode::compile(OSLCompiler& compiler)
/* Environment Texture */
-static ShaderEnum env_projection_init()
+static NodeEnum env_projection_init()
{
- ShaderEnum enm;
+ NodeEnum enm;
enm.insert("Equirectangular", 0);
enm.insert("Mirror Ball", 1);
@@ -459,8 +459,8 @@ static ShaderEnum env_projection_init()
return enm;
}
-ShaderEnum EnvironmentTextureNode::color_space_enum = color_space_init();
-ShaderEnum EnvironmentTextureNode::projection_enum = env_projection_init();
+NodeEnum EnvironmentTextureNode::color_space_enum = color_space_init();
+NodeEnum EnvironmentTextureNode::projection_enum = env_projection_init();
EnvironmentTextureNode::EnvironmentTextureNode()
: ImageSlotTextureNode("environment_texture")
@@ -472,14 +472,14 @@ EnvironmentTextureNode::EnvironmentTextureNode()
use_alpha = true;
filename = "";
builtin_data = NULL;
- color_space = ustring("Color");
+ color_space = NODE_COLOR_SPACE_COLOR;
interpolation = INTERPOLATION_LINEAR;
- projection = ustring("Equirectangular");
+ projection = NODE_ENVIRONMENT_EQUIRECTANGULAR;
animated = false;
- add_input("Vector", SHADER_SOCKET_VECTOR, ShaderInput::POSITION);
- add_output("Color", SHADER_SOCKET_COLOR);
- add_output("Alpha", SHADER_SOCKET_FLOAT);
+ add_input("Vector", SocketType::VECTOR, make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_POSITION);
+ add_output("Color", SocketType::COLOR);
+ add_output("Alpha", SocketType::FLOAT);
}
EnvironmentTextureNode::~EnvironmentTextureNode()
@@ -537,7 +537,7 @@ void EnvironmentTextureNode::compile(SVMCompiler& compiler)
}
if(slot != -1) {
- int srgb = (is_linear || color_space != "Color")? 0: 1;
+ int srgb = (is_linear || color_space != NODE_COLOR_SPACE_COLOR)? 0: 1;
int vector_offset = tex_mapping.compile_begin(compiler, vector_in);
compiler.add_node(NODE_TEX_ENVIRONMENT,
@@ -547,7 +547,7 @@ void EnvironmentTextureNode::compile(SVMCompiler& compiler)
compiler.stack_assign_if_linked(color_out),
compiler.stack_assign_if_linked(alpha_out),
srgb),
- projection_enum[projection]);
+ projection);
tex_mapping.compile_end(compiler, vector_in, vector_offset);
}
@@ -602,8 +602,8 @@ void EnvironmentTextureNode::compile(OSLCompiler& compiler)
else {
compiler.parameter("filename", string_printf("@%d", slot).c_str());
}
- compiler.parameter("projection", projection);
- if(is_linear || color_space != "Color")
+ compiler.parameter("projection", projection_enum[projection]);
+ if(is_linear || color_space != NODE_COLOR_SPACE_COLOR)
compiler.parameter("color_space", "Linear");
else
compiler.parameter("color_space", "sRGB");
@@ -738,9 +738,9 @@ static void sky_texture_precompute_new(SunSky *sunsky, float3 dir, float turbidi
arhosekskymodelstate_free(sky_state);
}
-static ShaderEnum sky_type_init()
+static NodeEnum sky_type_init()
{
- ShaderEnum enm;
+ NodeEnum enm;
enm.insert("Preetham", NODE_SKY_OLD);
enm.insert("Hosek / Wilkie", NODE_SKY_NEW);
@@ -748,19 +748,19 @@ static ShaderEnum sky_type_init()
return enm;
}
-ShaderEnum SkyTextureNode::type_enum = sky_type_init();
+NodeEnum SkyTextureNode::type_enum = sky_type_init();
SkyTextureNode::SkyTextureNode()
: TextureNode("sky_texture")
{
- type = ustring("Hosek / Wilkie");
+ type = NODE_SKY_NEW;
sun_direction = make_float3(0.0f, 0.0f, 1.0f);
turbidity = 2.2f;
ground_albedo = 0.3f;
- add_input("Vector", SHADER_SOCKET_VECTOR, ShaderInput::POSITION);
- add_output("Color", SHADER_SOCKET_COLOR);
+ add_input("Vector", SocketType::VECTOR, make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_POSITION);
+ add_output("Color", SocketType::COLOR);
}
void SkyTextureNode::compile(SVMCompiler& compiler)
@@ -769,15 +769,15 @@ void SkyTextureNode::compile(SVMCompiler& compiler)
ShaderOutput *color_out = output("Color");
SunSky sunsky;
- if(type_enum[type] == NODE_SKY_OLD)
+ if(type == NODE_SKY_OLD)
sky_texture_precompute_old(&sunsky, sun_direction, turbidity);
- else if(type_enum[type] == NODE_SKY_NEW)
+ else if(type == NODE_SKY_NEW)
sky_texture_precompute_new(&sunsky, sun_direction, turbidity, ground_albedo);
else
assert(false);
int vector_offset = tex_mapping.compile_begin(compiler, vector_in);
- int sky_model = type_enum[type];
+ int sky_model = type;
compiler.stack_assign(color_out);
compiler.add_node(NODE_TEX_SKY, vector_offset, compiler.stack_assign(color_out), sky_model);
@@ -799,14 +799,14 @@ void SkyTextureNode::compile(OSLCompiler& compiler)
SunSky sunsky;
- if(type_enum[type] == NODE_SKY_OLD)
+ if(type == NODE_SKY_OLD)
sky_texture_precompute_old(&sunsky, sun_direction, turbidity);
- else if(type_enum[type] == NODE_SKY_NEW)
+ else if(type == NODE_SKY_NEW)
sky_texture_precompute_new(&sunsky, sun_direction, turbidity, ground_albedo);
else
assert(false);
- compiler.parameter("sky_model", type);
+ compiler.parameter("sky_model", type_enum[type]);
compiler.parameter("theta", sunsky.theta);
compiler.parameter("phi", sunsky.phi);
compiler.parameter_color("radiance", make_float3(sunsky.radiance_x, sunsky.radiance_y, sunsky.radiance_z));
@@ -818,9 +818,9 @@ void SkyTextureNode::compile(OSLCompiler& compiler)
/* Gradient Texture */
-static ShaderEnum gradient_type_init()
+static NodeEnum gradient_type_init()
{
- ShaderEnum enm;
+ NodeEnum enm;
enm.insert("Linear", NODE_BLEND_LINEAR);
enm.insert("Quadratic", NODE_BLEND_QUADRATIC);
@@ -833,16 +833,16 @@ static ShaderEnum gradient_type_init()
return enm;
}
-ShaderEnum GradientTextureNode::type_enum = gradient_type_init();
+NodeEnum GradientTextureNode::type_enum = gradient_type_init();
GradientTextureNode::GradientTextureNode()
: TextureNode("gradient_texture")
{
- type = ustring("Linear");
+ type = NODE_BLEND_LINEAR;
- add_input("Vector", SHADER_SOCKET_POINT, ShaderInput::TEXTURE_GENERATED);
- add_output("Color", SHADER_SOCKET_COLOR);
- add_output("Fac", SHADER_SOCKET_FLOAT);
+ add_input("Vector", SocketType::POINT, make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_TEXTURE_GENERATED);
+ add_output("Color", SocketType::COLOR);
+ add_output("Fac", SocketType::FLOAT);
}
void GradientTextureNode::compile(SVMCompiler& compiler)
@@ -855,7 +855,7 @@ void GradientTextureNode::compile(SVMCompiler& compiler)
compiler.add_node(NODE_TEX_GRADIENT,
compiler.encode_uchar4(
- type_enum[type],
+ type,
vector_offset,
compiler.stack_assign_if_linked(fac_out),
compiler.stack_assign_if_linked(color_out)));
@@ -867,7 +867,7 @@ void GradientTextureNode::compile(OSLCompiler& compiler)
{
tex_mapping.compile(compiler);
- compiler.parameter("Type", type);
+ compiler.parameter("type", type_enum[type]);
compiler.add(this, "node_gradient_texture");
}
@@ -876,13 +876,13 @@ void GradientTextureNode::compile(OSLCompiler& compiler)
NoiseTextureNode::NoiseTextureNode()
: TextureNode("noise_texture")
{
- add_input("Vector", SHADER_SOCKET_POINT, ShaderInput::TEXTURE_GENERATED);
- add_input("Scale", SHADER_SOCKET_FLOAT, 1.0f);
- add_input("Detail", SHADER_SOCKET_FLOAT, 2.0f);
- add_input("Distortion", SHADER_SOCKET_FLOAT, 0.0f);
+ add_input("Vector", SocketType::POINT, make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_TEXTURE_GENERATED);
+ add_input("Scale", SocketType::FLOAT, 1.0f);
+ add_input("Detail", SocketType::FLOAT, 2.0f);
+ add_input("Distortion", SocketType::FLOAT, 0.0f);
- add_output("Color", SHADER_SOCKET_COLOR);
- add_output("Fac", SHADER_SOCKET_FLOAT);
+ add_output("Color", SocketType::COLOR);
+ add_output("Fac", SocketType::FLOAT);
}
void NoiseTextureNode::compile(SVMCompiler& compiler)
@@ -906,9 +906,9 @@ void NoiseTextureNode::compile(SVMCompiler& compiler)
compiler.stack_assign_if_linked(color_out),
compiler.stack_assign_if_linked(fac_out)));
compiler.add_node(
- __float_as_int(scale_in->value.x),
- __float_as_int(detail_in->value.x),
- __float_as_int(distortion_in->value.x));
+ __float_as_int(scale_in->value_float()),
+ __float_as_int(detail_in->value_float()),
+ __float_as_int(distortion_in->value_float()));
tex_mapping.compile_end(compiler, vector_in, vector_offset);
}
@@ -922,9 +922,9 @@ void NoiseTextureNode::compile(OSLCompiler& compiler)
/* Voronoi Texture */
-static ShaderEnum voronoi_coloring_init()
+static NodeEnum voronoi_coloring_init()
{
- ShaderEnum enm;
+ NodeEnum enm;
enm.insert("Intensity", NODE_VORONOI_INTENSITY);
enm.insert("Cells", NODE_VORONOI_CELLS);
@@ -932,18 +932,18 @@ static ShaderEnum voronoi_coloring_init()
return enm;
}
-ShaderEnum VoronoiTextureNode::coloring_enum = voronoi_coloring_init();
+NodeEnum VoronoiTextureNode::coloring_enum = voronoi_coloring_init();
VoronoiTextureNode::VoronoiTextureNode()
: TextureNode("voronoi_texture")
{
- coloring = ustring("Intensity");
+ coloring = NODE_VORONOI_INTENSITY;
- add_input("Scale", SHADER_SOCKET_FLOAT, 1.0f);
- add_input("Vector", SHADER_SOCKET_POINT, ShaderInput::TEXTURE_GENERATED);
+ add_input("Scale", SocketType::FLOAT, 1.0f);
+ add_input("Vector", SocketType::POINT, make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_TEXTURE_GENERATED);
- add_output("Color", SHADER_SOCKET_COLOR);
- add_output("Fac", SHADER_SOCKET_FLOAT);
+ add_output("Color", SocketType::COLOR);
+ add_output("Fac", SocketType::FLOAT);
}
void VoronoiTextureNode::compile(SVMCompiler& compiler)
@@ -956,13 +956,13 @@ void VoronoiTextureNode::compile(SVMCompiler& compiler)
int vector_offset = tex_mapping.compile_begin(compiler, vector_in);
compiler.add_node(NODE_TEX_VORONOI,
- coloring_enum[coloring],
+ coloring,
compiler.encode_uchar4(
compiler.stack_assign_if_linked(scale_in),
vector_offset,
compiler.stack_assign(fac_out),
compiler.stack_assign(color_out)),
- __float_as_int(scale_in->value.x));
+ __float_as_int(scale_in->value_float()));
tex_mapping.compile_end(compiler, vector_in, vector_offset);
}
@@ -971,15 +971,15 @@ void VoronoiTextureNode::compile(OSLCompiler& compiler)
{
tex_mapping.compile(compiler);
- compiler.parameter("Coloring", coloring);
+ compiler.parameter("coloring", coloring_enum[coloring]);
compiler.add(this, "node_voronoi_texture");
}
/* Musgrave Texture */
-static ShaderEnum musgrave_type_init()
+static NodeEnum musgrave_type_init()
{
- ShaderEnum enm;
+ NodeEnum enm;
enm.insert("Multifractal", NODE_MUSGRAVE_MULTIFRACTAL);
enm.insert("fBM", NODE_MUSGRAVE_FBM);
@@ -990,23 +990,23 @@ static ShaderEnum musgrave_type_init()
return enm;
}
-ShaderEnum MusgraveTextureNode::type_enum = musgrave_type_init();
+NodeEnum MusgraveTextureNode::type_enum = musgrave_type_init();
MusgraveTextureNode::MusgraveTextureNode()
: TextureNode("musgrave_texture")
{
- type = ustring("fBM");
+ type = NODE_MUSGRAVE_FBM;
- add_input("Scale", SHADER_SOCKET_FLOAT, 1.0f);
- add_input("Detail", SHADER_SOCKET_FLOAT, 2.0f);
- add_input("Vector", SHADER_SOCKET_POINT, ShaderInput::TEXTURE_GENERATED);
- add_input("Dimension", SHADER_SOCKET_FLOAT, 2.0f);
- add_input("Lacunarity", SHADER_SOCKET_FLOAT, 1.0f);
- add_input("Offset", SHADER_SOCKET_FLOAT, 0.0f);
- add_input("Gain", SHADER_SOCKET_FLOAT, 1.0f);
+ add_input("Scale", SocketType::FLOAT, 1.0f);
+ add_input("Detail", SocketType::FLOAT, 2.0f);
+ add_input("Vector", SocketType::POINT, make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_TEXTURE_GENERATED);
+ add_input("Dimension", SocketType::FLOAT, 2.0f);
+ add_input("Lacunarity", SocketType::FLOAT, 1.0f);
+ add_input("Offset", SocketType::FLOAT, 0.0f);
+ add_input("Gain", SocketType::FLOAT, 1.0f);
- add_output("Fac", SHADER_SOCKET_FLOAT);
- add_output("Color", SHADER_SOCKET_COLOR);
+ add_output("Fac", SocketType::FLOAT);
+ add_output("Color", SocketType::COLOR);
}
void MusgraveTextureNode::compile(SVMCompiler& compiler)
@@ -1025,7 +1025,7 @@ void MusgraveTextureNode::compile(SVMCompiler& compiler)
compiler.add_node(NODE_TEX_MUSGRAVE,
compiler.encode_uchar4(
- type_enum[type],
+ type,
vector_offset,
compiler.stack_assign_if_linked(color_out),
compiler.stack_assign_if_linked(fac_out)),
@@ -1037,12 +1037,12 @@ void MusgraveTextureNode::compile(SVMCompiler& compiler)
compiler.encode_uchar4(
compiler.stack_assign_if_linked(gain_in),
compiler.stack_assign_if_linked(scale_in)));
- compiler.add_node(__float_as_int(dimension_in->value.x),
- __float_as_int(lacunarity_in->value.x),
- __float_as_int(detail_in->value.x),
- __float_as_int(offset_in->value.x));
- compiler.add_node(__float_as_int(gain_in->value.x),
- __float_as_int(scale_in->value.x));
+ compiler.add_node(__float_as_int(dimension_in->value_float()),
+ __float_as_int(lacunarity_in->value_float()),
+ __float_as_int(detail_in->value_float()),
+ __float_as_int(offset_in->value_float()));
+ compiler.add_node(__float_as_int(gain_in->value_float()),
+ __float_as_int(scale_in->value_float()));
tex_mapping.compile_end(compiler, vector_in, vector_offset);
}
@@ -1051,16 +1051,16 @@ void MusgraveTextureNode::compile(OSLCompiler& compiler)
{
tex_mapping.compile(compiler);
- compiler.parameter("Type", type);
+ compiler.parameter("type", type_enum[type]);
compiler.add(this, "node_musgrave_texture");
}
/* Wave Texture */
-static ShaderEnum wave_type_init()
+static NodeEnum wave_type_init()
{
- ShaderEnum enm;
+ NodeEnum enm;
enm.insert("Bands", NODE_WAVE_BANDS);
enm.insert("Rings", NODE_WAVE_RINGS);
@@ -1068,9 +1068,9 @@ static ShaderEnum wave_type_init()
return enm;
}
-static ShaderEnum wave_profile_init()
+static NodeEnum wave_profile_init()
{
- ShaderEnum enm;
+ NodeEnum enm;
enm.insert("Sine", NODE_WAVE_PROFILE_SIN);
enm.insert("Saw", NODE_WAVE_PROFILE_SAW);
@@ -1078,23 +1078,23 @@ static ShaderEnum wave_profile_init()
return enm;
}
-ShaderEnum WaveTextureNode::type_enum = wave_type_init();
-ShaderEnum WaveTextureNode::profile_enum = wave_profile_init();
+NodeEnum WaveTextureNode::type_enum = wave_type_init();
+NodeEnum WaveTextureNode::profile_enum = wave_profile_init();
WaveTextureNode::WaveTextureNode()
: TextureNode("wave_texture")
{
- type = ustring("Bands");
- profile = ustring("Sine");
+ type = NODE_WAVE_BANDS;
+ profile = NODE_WAVE_PROFILE_SIN;
- add_input("Scale", SHADER_SOCKET_FLOAT, 1.0f);
- add_input("Distortion", SHADER_SOCKET_FLOAT, 0.0f);
- add_input("Detail", SHADER_SOCKET_FLOAT, 2.0f);
- add_input("Detail Scale", SHADER_SOCKET_FLOAT, 1.0f);
- add_input("Vector", SHADER_SOCKET_POINT, ShaderInput::TEXTURE_GENERATED);
+ add_input("Scale", SocketType::FLOAT, 1.0f);
+ add_input("Distortion", SocketType::FLOAT, 0.0f);
+ add_input("Detail", SocketType::FLOAT, 2.0f);
+ add_input("Detail Scale", SocketType::FLOAT, 1.0f);
+ add_input("Vector", SocketType::POINT, make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_TEXTURE_GENERATED);
- add_output("Color", SHADER_SOCKET_COLOR);
- add_output("Fac", SHADER_SOCKET_FLOAT);
+ add_output("Color", SocketType::COLOR);
+ add_output("Fac", SocketType::FLOAT);
}
void WaveTextureNode::compile(SVMCompiler& compiler)
@@ -1111,7 +1111,7 @@ void WaveTextureNode::compile(SVMCompiler& compiler)
compiler.add_node(NODE_TEX_WAVE,
compiler.encode_uchar4(
- type_enum[type],
+ type,
compiler.stack_assign_if_linked(color_out),
compiler.stack_assign_if_linked(fac_out),
compiler.stack_assign_if_linked(dscale_in)),
@@ -1120,13 +1120,13 @@ void WaveTextureNode::compile(SVMCompiler& compiler)
compiler.stack_assign_if_linked(scale_in),
compiler.stack_assign_if_linked(detail_in),
compiler.stack_assign_if_linked(distortion_in)),
- profile_enum[profile]);
+ profile);
compiler.add_node(
- __float_as_int(scale_in->value.x),
- __float_as_int(detail_in->value.x),
- __float_as_int(distortion_in->value.x),
- __float_as_int(dscale_in->value.x));
+ __float_as_int(scale_in->value_float()),
+ __float_as_int(detail_in->value_float()),
+ __float_as_int(distortion_in->value_float()),
+ __float_as_int(dscale_in->value_float()));
tex_mapping.compile_end(compiler, vector_in, vector_offset);
}
@@ -1135,8 +1135,8 @@ void WaveTextureNode::compile(OSLCompiler& compiler)
{
tex_mapping.compile(compiler);
- compiler.parameter("Type", type);
- compiler.parameter("Profile", profile);
+ compiler.parameter("type", type_enum[type]);
+ compiler.parameter("profile", profile_enum[profile]);
compiler.add(this, "node_wave_texture");
}
@@ -1148,12 +1148,12 @@ MagicTextureNode::MagicTextureNode()
{
depth = 2;
- add_input("Vector", SHADER_SOCKET_POINT, ShaderInput::TEXTURE_GENERATED);
- add_input("Scale", SHADER_SOCKET_FLOAT, 5.0f);
- add_input("Distortion", SHADER_SOCKET_FLOAT, 1.0f);
+ add_input("Vector", SocketType::POINT, make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_TEXTURE_GENERATED);
+ add_input("Scale", SocketType::FLOAT, 5.0f);
+ add_input("Distortion", SocketType::FLOAT, 1.0f);
- add_output("Color", SHADER_SOCKET_COLOR);
- add_output("Fac", SHADER_SOCKET_FLOAT);
+ add_output("Color", SocketType::COLOR);
+ add_output("Fac", SocketType::FLOAT);
}
void MagicTextureNode::compile(SVMCompiler& compiler)
@@ -1176,8 +1176,8 @@ void MagicTextureNode::compile(SVMCompiler& compiler)
compiler.stack_assign_if_linked(scale_in),
compiler.stack_assign_if_linked(distortion_in)));
compiler.add_node(
- __float_as_int(scale_in->value.x),
- __float_as_int(distortion_in->value.x));
+ __float_as_int(scale_in->value_float()),
+ __float_as_int(distortion_in->value_float()));
tex_mapping.compile_end(compiler, vector_in, vector_offset);
}
@@ -1186,7 +1186,7 @@ void MagicTextureNode::compile(OSLCompiler& compiler)
{
tex_mapping.compile(compiler);
- compiler.parameter("Depth", depth);
+ compiler.parameter("depth", depth);
compiler.add(this, "node_magic_texture");
}
@@ -1195,13 +1195,13 @@ void MagicTextureNode::compile(OSLCompiler& compiler)
CheckerTextureNode::CheckerTextureNode()
: TextureNode("checker_texture")
{
- add_input("Vector", SHADER_SOCKET_POINT, ShaderInput::TEXTURE_GENERATED);
- add_input("Color1", SHADER_SOCKET_COLOR);
- add_input("Color2", SHADER_SOCKET_COLOR);
- add_input("Scale", SHADER_SOCKET_FLOAT, 1.0f);
+ add_input("Vector", SocketType::POINT, make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_TEXTURE_GENERATED);
+ add_input("Color1", SocketType::COLOR);
+ add_input("Color2", SocketType::COLOR);
+ add_input("Scale", SocketType::FLOAT, 1.0f);
- add_output("Color", SHADER_SOCKET_COLOR);
- add_output("Fac", SHADER_SOCKET_FLOAT);
+ add_output("Color", SocketType::COLOR);
+ add_output("Fac", SocketType::FLOAT);
}
void CheckerTextureNode::compile(SVMCompiler& compiler)
@@ -1225,7 +1225,7 @@ void CheckerTextureNode::compile(SVMCompiler& compiler)
compiler.encode_uchar4(
compiler.stack_assign_if_linked(color_out),
compiler.stack_assign_if_linked(fac_out)),
- __float_as_int(scale_in->value.x));
+ __float_as_int(scale_in->value_float()));
tex_mapping.compile_end(compiler, vector_in, vector_offset);
}
@@ -1247,18 +1247,18 @@ BrickTextureNode::BrickTextureNode()
squash = 1.0f;
squash_frequency = 2;
- add_input("Vector", SHADER_SOCKET_POINT, ShaderInput::TEXTURE_GENERATED);
- add_input("Color1", SHADER_SOCKET_COLOR);
- add_input("Color2", SHADER_SOCKET_COLOR);
- add_input("Mortar", SHADER_SOCKET_COLOR);
- add_input("Scale", SHADER_SOCKET_FLOAT, 5.0f);
- add_input("Mortar Size", SHADER_SOCKET_FLOAT, 0.02f);
- add_input("Bias", SHADER_SOCKET_FLOAT, 0.0f);
- add_input("Brick Width", SHADER_SOCKET_FLOAT, 0.5f);
- add_input("Row Height", SHADER_SOCKET_FLOAT, 0.25f);
+ add_input("Vector", SocketType::POINT, make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_TEXTURE_GENERATED);
+ add_input("Color1", SocketType::COLOR);
+ add_input("Color2", SocketType::COLOR);
+ add_input("Mortar", SocketType::COLOR);
+ add_input("Scale", SocketType::FLOAT, 5.0f);
+ add_input("Mortar Size", SocketType::FLOAT, 0.02f);
+ add_input("Bias", SocketType::FLOAT, 0.0f);
+ add_input("Brick Width", SocketType::FLOAT, 0.5f);
+ add_input("Row Height", SocketType::FLOAT, 0.25f);
- add_output("Color", SHADER_SOCKET_COLOR);
- add_output("Fac", SHADER_SOCKET_FLOAT);
+ add_output("Color", SocketType::COLOR);
+ add_output("Fac", SocketType::FLOAT);
}
void BrickTextureNode::compile(SVMCompiler& compiler)
@@ -1295,12 +1295,12 @@ void BrickTextureNode::compile(SVMCompiler& compiler)
compiler.stack_assign_if_linked(fac_out)));
compiler.add_node(compiler.encode_uchar4(offset_frequency, squash_frequency),
- __float_as_int(scale_in->value.x),
- __float_as_int(mortar_size_in->value.x),
- __float_as_int(bias_in->value.x));
+ __float_as_int(scale_in->value_float()),
+ __float_as_int(mortar_size_in->value_float()),
+ __float_as_int(bias_in->value_float()));
- compiler.add_node(__float_as_int(brick_width_in->value.x),
- __float_as_int(row_height_in->value.x),
+ compiler.add_node(__float_as_int(brick_width_in->value_float()),
+ __float_as_int(row_height_in->value_float()),
__float_as_int(offset),
__float_as_int(squash));
@@ -1311,18 +1311,18 @@ void BrickTextureNode::compile(OSLCompiler& compiler)
{
tex_mapping.compile(compiler);
- compiler.parameter("Offset", offset);
- compiler.parameter("OffsetFrequency", offset_frequency);
- compiler.parameter("Squash", squash);
- compiler.parameter("SquashFrequency", squash_frequency);
+ compiler.parameter("offset", offset);
+ compiler.parameter("offset_frequency", offset_frequency);
+ compiler.parameter("squash", squash);
+ compiler.parameter("squash_frequency", squash_frequency);
compiler.add(this, "node_brick_texture");
}
/* Point Density Texture */
-static ShaderEnum point_density_space_init()
+static NodeEnum point_density_space_init()
{
- ShaderEnum enm;
+ NodeEnum enm;
enm.insert("Object", NODE_TEX_VOXEL_SPACE_OBJECT);
enm.insert("World", NODE_TEX_VOXEL_SPACE_WORLD);
@@ -1330,7 +1330,7 @@ static ShaderEnum point_density_space_init()
return enm;
}
-ShaderEnum PointDensityTextureNode::space_enum = point_density_space_init();
+NodeEnum PointDensityTextureNode::space_enum = point_density_space_init();
PointDensityTextureNode::PointDensityTextureNode()
: ShaderNode("point_density")
@@ -1338,15 +1338,15 @@ PointDensityTextureNode::PointDensityTextureNode()
image_manager = NULL;
slot = -1;
filename = "";
- space = ustring("Object");
+ space = NODE_TEX_VOXEL_SPACE_OBJECT;
builtin_data = NULL;
interpolation = INTERPOLATION_LINEAR;
tfm = transform_identity();
- add_input("Vector", SHADER_SOCKET_POINT, ShaderInput::POSITION);
- add_output("Density", SHADER_SOCKET_FLOAT);
- add_output("Color", SHADER_SOCKET_COLOR);
+ add_input("Vector", SocketType::POINT, make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_POSITION);
+ add_output("Density", SocketType::FLOAT);
+ add_output("Color", SocketType::COLOR);
}
PointDensityTextureNode::~PointDensityTextureNode()
@@ -1405,8 +1405,8 @@ void PointDensityTextureNode::compile(SVMCompiler& compiler)
compiler.encode_uchar4(compiler.stack_assign(vector_in),
compiler.stack_assign_if_linked(density_out),
compiler.stack_assign_if_linked(color_out),
- space_enum[space]));
- if(space == "World") {
+ space));
+ if(space == NODE_TEX_VOXEL_SPACE_WORLD) {
compiler.add_node(tfm.x);
compiler.add_node(tfm.y);
compiler.add_node(tfm.z);
@@ -1453,7 +1453,7 @@ void PointDensityTextureNode::compile(OSLCompiler& compiler)
if(slot != -1) {
compiler.parameter("filename", string_printf("@%d", slot).c_str());
}
- if(space == "World") {
+ if(space == NODE_TEX_VOXEL_SPACE_WORLD) {
compiler.parameter("mapping", transform_transpose(tfm));
compiler.parameter("use_mapping", 1);
}
@@ -1481,9 +1481,9 @@ NormalNode::NormalNode()
{
direction = make_float3(0.0f, 0.0f, 1.0f);
- add_input("Normal", SHADER_SOCKET_NORMAL);
- add_output("Normal", SHADER_SOCKET_NORMAL);
- add_output("Dot", SHADER_SOCKET_FLOAT);
+ add_input("Normal", SocketType::NORMAL);
+ add_output("Normal", SocketType::NORMAL);
+ add_output("Dot", SocketType::FLOAT);
}
void NormalNode::compile(SVMCompiler& compiler)
@@ -1504,7 +1504,7 @@ void NormalNode::compile(SVMCompiler& compiler)
void NormalNode::compile(OSLCompiler& compiler)
{
- compiler.parameter_normal("Direction", direction);
+ compiler.parameter_normal("direction", direction);
compiler.add(this, "node_normal");
}
@@ -1513,8 +1513,8 @@ void NormalNode::compile(OSLCompiler& compiler)
MappingNode::MappingNode()
: ShaderNode("mapping")
{
- add_input("Vector", SHADER_SOCKET_POINT);
- add_output("Vector", SHADER_SOCKET_POINT);
+ add_input("Vector", SocketType::POINT);
+ add_output("Vector", SocketType::POINT);
}
void MappingNode::compile(SVMCompiler& compiler)
@@ -1536,9 +1536,41 @@ void MappingNode::compile(OSLCompiler& compiler)
compiler.add(this, "node_mapping");
}
+/* RGBToBW */
+
+RGBToBWNode::RGBToBWNode()
+: ShaderNode("rgb_to_bw")
+{
+ add_input("Color", SocketType::COLOR);
+ add_output("Val", SocketType::FLOAT);
+}
+
+bool RGBToBWNode::constant_fold(ShaderGraph *, ShaderOutput *, ShaderInput *optimized)
+{
+ if(inputs[0]->link == NULL) {
+ optimized->set(linear_rgb_to_gray(inputs[0]->value()));
+ return true;
+ }
+
+ return false;
+}
+
+void RGBToBWNode::compile(SVMCompiler& compiler)
+{
+ compiler.add_node(NODE_CONVERT,
+ NODE_CONVERT_CF,
+ compiler.stack_assign(inputs[0]),
+ compiler.stack_assign(outputs[0]));
+}
+
+void RGBToBWNode::compile(OSLCompiler& compiler)
+{
+ compiler.add(this, "node_convert_from_color");
+}
+
/* Convert */
-ConvertNode::ConvertNode(ShaderSocketType from_, ShaderSocketType to_, bool autoconvert)
+ConvertNode::ConvertNode(SocketType::Type from_, SocketType::Type to_, bool autoconvert)
: ShaderNode("convert")
{
from = from_;
@@ -1551,92 +1583,72 @@ ConvertNode::ConvertNode(ShaderSocketType from_, ShaderSocketType to_, bool auto
special_type = SHADER_SPECIAL_TYPE_AUTOCONVERT;
}
- if(from == SHADER_SOCKET_FLOAT)
- add_input("Val", SHADER_SOCKET_FLOAT);
- else if(from == SHADER_SOCKET_INT)
- add_input("ValInt", SHADER_SOCKET_INT);
- else if(from == SHADER_SOCKET_COLOR)
- add_input("Color", SHADER_SOCKET_COLOR);
- else if(from == SHADER_SOCKET_VECTOR)
- add_input("Vector", SHADER_SOCKET_VECTOR);
- else if(from == SHADER_SOCKET_POINT)
- add_input("Point", SHADER_SOCKET_POINT);
- else if(from == SHADER_SOCKET_NORMAL)
- add_input("Normal", SHADER_SOCKET_NORMAL);
- else if(from == SHADER_SOCKET_STRING)
- add_input("String", SHADER_SOCKET_STRING);
- else if(from == SHADER_SOCKET_CLOSURE)
- add_input("Closure", SHADER_SOCKET_CLOSURE);
+ if(from == SocketType::FLOAT)
+ add_input("value_float", SocketType::FLOAT);
+ else if(from == SocketType::INT)
+ add_input("value_int", SocketType::INT);
+ else if(from == SocketType::COLOR)
+ add_input("value_color", SocketType::COLOR);
+ else if(from == SocketType::VECTOR)
+ add_input("value_vector", SocketType::VECTOR);
+ else if(from == SocketType::POINT)
+ add_input("value_point", SocketType::POINT);
+ else if(from == SocketType::NORMAL)
+ add_input("value_normal", SocketType::NORMAL);
+ else if(from == SocketType::STRING)
+ add_input("value_string", SocketType::STRING);
+ else if(from == SocketType::CLOSURE)
+ add_input("value_closure", SocketType::CLOSURE);
else
assert(0);
- if(to == SHADER_SOCKET_FLOAT)
- add_output("Val", SHADER_SOCKET_FLOAT);
- else if(to == SHADER_SOCKET_INT)
- add_output("ValInt", SHADER_SOCKET_INT);
- else if(to == SHADER_SOCKET_COLOR)
- add_output("Color", SHADER_SOCKET_COLOR);
- else if(to == SHADER_SOCKET_VECTOR)
- add_output("Vector", SHADER_SOCKET_VECTOR);
- else if(to == SHADER_SOCKET_POINT)
- add_output("Point", SHADER_SOCKET_POINT);
- else if(to == SHADER_SOCKET_NORMAL)
- add_output("Normal", SHADER_SOCKET_NORMAL);
- else if(to == SHADER_SOCKET_STRING)
- add_output("String", SHADER_SOCKET_STRING);
- else if(to == SHADER_SOCKET_CLOSURE)
- add_output("Closure", SHADER_SOCKET_CLOSURE);
+ if(to == SocketType::FLOAT)
+ add_output("value_float", SocketType::FLOAT);
+ else if(to == SocketType::INT)
+ add_output("value_int", SocketType::INT);
+ else if(to == SocketType::COLOR)
+ add_output("value_color", SocketType::COLOR);
+ else if(to == SocketType::VECTOR)
+ add_output("value_vector", SocketType::VECTOR);
+ else if(to == SocketType::POINT)
+ add_output("value_point", SocketType::POINT);
+ else if(to == SocketType::NORMAL)
+ add_output("value_normal", SocketType::NORMAL);
+ else if(to == SocketType::STRING)
+ add_output("value_string", SocketType::STRING);
+ else if(to == SocketType::CLOSURE)
+ add_output("value_closure", SocketType::CLOSURE);
else
assert(0);
}
-bool ConvertNode::constant_fold(ShaderGraph * /*graph*/,
- ShaderOutput * /*socket*/,
- float3 *optimized_value)
+bool ConvertNode::constant_fold(ShaderGraph *, ShaderOutput *, ShaderInput *optimized)
{
ShaderInput *in = inputs[0];
- float3 value = in->value;
+ float3 value = in->value();
/* TODO(DingTo): conversion from/to int is not supported yet, don't fold in that case */
if(in->link == NULL) {
- if(from == SHADER_SOCKET_FLOAT) {
- if(to == SHADER_SOCKET_INT)
- /* float to int */
- return false;
- else
- /* float to float3 */
- *optimized_value = make_float3(value.x, value.x, value.x);
- }
- else if(from == SHADER_SOCKET_INT) {
- if(to == SHADER_SOCKET_FLOAT)
- /* int to float */
- return false;
- else
- /* int to vector/point/normal */
- return false;
- }
- else if(to == SHADER_SOCKET_FLOAT) {
- if(from == SHADER_SOCKET_COLOR)
- /* color to float */
- optimized_value->x = linear_rgb_to_gray(value);
- else
- /* vector/point/normal to float */
- optimized_value->x = average(value);
- }
- else if(to == SHADER_SOCKET_INT) {
- if(from == SHADER_SOCKET_COLOR)
- /* color to int */
- return false;
- else
- /* vector/point/normal to int */
- return false;
+ if(from == SocketType::FLOAT) {
+ if(SocketType::is_float3(to)) {
+ optimized->set(make_float3(value.x, value.x, value.x));
+ return true;
+ }
}
- else {
- *optimized_value = value;
+ else if(SocketType::is_float3(from)) {
+ if(to == SocketType::FLOAT) {
+ if(from == SocketType::COLOR)
+ optimized->set(linear_rgb_to_gray(value));
+ else
+ optimized->set(average(value));
+ return true;
+ }
+ else if(SocketType::is_float3(to)) {
+ optimized->set(value);
+ return true;
+ }
}
-
- return true;
}
return false;
@@ -1650,32 +1662,32 @@ void ConvertNode::compile(SVMCompiler& compiler)
ShaderInput *in = inputs[0];
ShaderOutput *out = outputs[0];
- if(from == SHADER_SOCKET_FLOAT) {
- if(to == SHADER_SOCKET_INT)
+ if(from == SocketType::FLOAT) {
+ if(to == SocketType::INT)
/* float to int */
compiler.add_node(NODE_CONVERT, NODE_CONVERT_FI, compiler.stack_assign(in), compiler.stack_assign(out));
else
/* float to float3 */
compiler.add_node(NODE_CONVERT, NODE_CONVERT_FV, compiler.stack_assign(in), compiler.stack_assign(out));
}
- else if(from == SHADER_SOCKET_INT) {
- if(to == SHADER_SOCKET_FLOAT)
+ else if(from == SocketType::INT) {
+ if(to == SocketType::FLOAT)
/* int to float */
compiler.add_node(NODE_CONVERT, NODE_CONVERT_IF, compiler.stack_assign(in), compiler.stack_assign(out));
else
/* int to vector/point/normal */
compiler.add_node(NODE_CONVERT, NODE_CONVERT_IV, compiler.stack_assign(in), compiler.stack_assign(out));
}
- else if(to == SHADER_SOCKET_FLOAT) {
- if(from == SHADER_SOCKET_COLOR)
+ else if(to == SocketType::FLOAT) {
+ if(from == SocketType::COLOR)
/* color to float */
compiler.add_node(NODE_CONVERT, NODE_CONVERT_CF, compiler.stack_assign(in), compiler.stack_assign(out));
else
/* vector/point/normal to float */
compiler.add_node(NODE_CONVERT, NODE_CONVERT_VF, compiler.stack_assign(in), compiler.stack_assign(out));
}
- else if(to == SHADER_SOCKET_INT) {
- if(from == SHADER_SOCKET_COLOR)
+ else if(to == SocketType::INT) {
+ if(from == SocketType::COLOR)
/* color to int */
compiler.add_node(NODE_CONVERT, NODE_CONVERT_CI, compiler.stack_assign(in), compiler.stack_assign(out));
else
@@ -1691,7 +1703,7 @@ void ConvertNode::compile(SVMCompiler& compiler)
else {
/* set 0,0,0 value */
compiler.add_node(NODE_VALUE_V, compiler.stack_assign(out));
- compiler.add_node(NODE_VALUE_V, in->value);
+ compiler.add_node(NODE_VALUE_V, in->value());
}
}
}
@@ -1701,17 +1713,17 @@ void ConvertNode::compile(OSLCompiler& compiler)
/* constant folding should eliminate proxy nodes */
assert(from != to);
- if(from == SHADER_SOCKET_FLOAT)
+ if(from == SocketType::FLOAT)
compiler.add(this, "node_convert_from_float");
- else if(from == SHADER_SOCKET_INT)
+ else if(from == SocketType::INT)
compiler.add(this, "node_convert_from_int");
- else if(from == SHADER_SOCKET_COLOR)
+ else if(from == SocketType::COLOR)
compiler.add(this, "node_convert_from_color");
- else if(from == SHADER_SOCKET_VECTOR)
+ else if(from == SocketType::VECTOR)
compiler.add(this, "node_convert_from_vector");
- else if(from == SHADER_SOCKET_POINT)
+ else if(from == SocketType::POINT)
compiler.add(this, "node_convert_from_point");
- else if(from == SHADER_SOCKET_NORMAL)
+ else if(from == SocketType::NORMAL)
compiler.add(this, "node_convert_from_normal");
else
assert(0);
@@ -1724,17 +1736,17 @@ BsdfNode::BsdfNode(bool scattering_)
{
special_type = SHADER_SPECIAL_TYPE_CLOSURE;
- add_input("Color", SHADER_SOCKET_COLOR, make_float3(0.8f, 0.8f, 0.8f));
- add_input("Normal", SHADER_SOCKET_NORMAL, ShaderInput::NORMAL);
- add_input("SurfaceMixWeight", SHADER_SOCKET_FLOAT, 0.0f, ShaderInput::USE_SVM);
+ add_input("Color", SocketType::COLOR, make_float3(0.8f, 0.8f, 0.8f));
+ add_input("Normal", SocketType::NORMAL, make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_NORMAL);
+ add_input("SurfaceMixWeight", SocketType::FLOAT, 0.0f, SocketType::SVM_INTERNAL);
if(scattering) {
closure = CLOSURE_BSSRDF_CUBIC_ID;
- add_output("BSSRDF", SHADER_SOCKET_CLOSURE);
+ add_output("BSSRDF", SocketType::CLOSURE);
}
else {
closure = CLOSURE_BSDF_DIFFUSE_ID;
- add_output("BSDF", SHADER_SOCKET_CLOSURE);
+ add_output("BSDF", SocketType::CLOSURE);
}
}
@@ -1747,7 +1759,7 @@ void BsdfNode::compile(SVMCompiler& compiler, ShaderInput *param1, ShaderInput *
if(color_in->link)
compiler.add_node(NODE_CLOSURE_WEIGHT, compiler.stack_assign(color_in));
else
- compiler.add_node(NODE_CLOSURE_SET_WEIGHT, color_in->value);
+ compiler.add_node(NODE_CLOSURE_SET_WEIGHT, color_in->value());
int normal_offset = compiler.stack_assign_if_linked(normal_in);
int tangent_offset = (tangent_in) ? compiler.stack_assign_if_linked(tangent_in) : SVM_STACK_INVALID;
@@ -1759,8 +1771,8 @@ void BsdfNode::compile(SVMCompiler& compiler, ShaderInput *param1, ShaderInput *
(param1)? compiler.stack_assign(param1): SVM_STACK_INVALID,
(param2)? compiler.stack_assign(param2): SVM_STACK_INVALID,
compiler.closure_mix_weight_offset()),
- __float_as_int((param1)? param1->value.x: 0.0f),
- __float_as_int((param2)? param2->value.x: 0.0f));
+ __float_as_int((param1)? param1->value_float(): 0.0f),
+ __float_as_int((param2)? param2->value_float(): 0.0f));
compiler.add_node(normal_offset, tangent_offset, param3_offset, param4_offset);
}
@@ -1777,9 +1789,9 @@ void BsdfNode::compile(OSLCompiler& /*compiler*/)
/* Anisotropic BSDF Closure */
-static ShaderEnum aniso_distribution_init()
+static NodeEnum aniso_distribution_init()
{
- ShaderEnum enm;
+ NodeEnum enm;
enm.insert("Beckmann", CLOSURE_BSDF_MICROFACET_BECKMANN_ANISO_ID);
enm.insert("GGX", CLOSURE_BSDF_MICROFACET_GGX_ANISO_ID);
@@ -1788,18 +1800,18 @@ static ShaderEnum aniso_distribution_init()
return enm;
}
-ShaderEnum AnisotropicBsdfNode::distribution_enum = aniso_distribution_init();
+NodeEnum AnisotropicBsdfNode::distribution_enum = aniso_distribution_init();
AnisotropicBsdfNode::AnisotropicBsdfNode()
{
closure = CLOSURE_BSDF_MICROFACET_GGX_ANISO_ID;
- distribution = ustring("GGX");
+ distribution = CLOSURE_BSDF_MICROFACET_GGX_ANISO_ID;
- add_input("Tangent", SHADER_SOCKET_VECTOR, ShaderInput::TANGENT);
+ add_input("Tangent", SocketType::VECTOR, make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_TANGENT);
- add_input("Roughness", SHADER_SOCKET_FLOAT, 0.2f);
- add_input("Anisotropy", SHADER_SOCKET_FLOAT, 0.5f);
- add_input("Rotation", SHADER_SOCKET_FLOAT, 0.0f);
+ add_input("Roughness", SocketType::FLOAT, 0.2f);
+ add_input("Anisotropy", SocketType::FLOAT, 0.5f);
+ add_input("Rotation", SocketType::FLOAT, 0.0f);
}
void AnisotropicBsdfNode::attributes(Shader *shader, AttributeRequestSet *attributes)
@@ -1816,22 +1828,22 @@ void AnisotropicBsdfNode::attributes(Shader *shader, AttributeRequestSet *attrib
void AnisotropicBsdfNode::compile(SVMCompiler& compiler)
{
- closure = (ClosureType)distribution_enum[distribution];
+ closure = distribution;
BsdfNode::compile(compiler, input("Roughness"), input("Anisotropy"), input("Rotation"));
}
void AnisotropicBsdfNode::compile(OSLCompiler& compiler)
{
- compiler.parameter("distribution", distribution);
+ compiler.parameter("distribution", distribution_enum[distribution]);
compiler.add(this, "node_anisotropic_bsdf");
}
/* Glossy BSDF Closure */
-static ShaderEnum glossy_distribution_init()
+static NodeEnum glossy_distribution_init()
{
- ShaderEnum enm;
+ NodeEnum enm;
enm.insert("Sharp", CLOSURE_BSDF_REFLECTION_ID);
enm.insert("Beckmann", CLOSURE_BSDF_MICROFACET_BECKMANN_ID);
@@ -1841,20 +1853,20 @@ static ShaderEnum glossy_distribution_init()
return enm;
}
-ShaderEnum GlossyBsdfNode::distribution_enum = glossy_distribution_init();
+NodeEnum GlossyBsdfNode::distribution_enum = glossy_distribution_init();
GlossyBsdfNode::GlossyBsdfNode()
{
closure = CLOSURE_BSDF_MICROFACET_GGX_ID;
- distribution = ustring("GGX");
- distribution_orig = ustring("");
+ distribution = CLOSURE_BSDF_MICROFACET_GGX_ID;
+ distribution_orig = NBUILTIN_CLOSURES;
- add_input("Roughness", SHADER_SOCKET_FLOAT, 0.2f);
+ add_input("Roughness", SocketType::FLOAT, 0.2f);
}
void GlossyBsdfNode::simplify_settings(Scene *scene)
{
- if(distribution_orig == "") {
+ if(distribution_orig == NBUILTIN_CLOSURES) {
distribution_orig = distribution;
}
Integrator *integrator = scene->integrator;
@@ -1863,26 +1875,26 @@ void GlossyBsdfNode::simplify_settings(Scene *scene)
* Note: Keep the epsilon in sync with kernel!
*/
ShaderInput *roughness_input = input("Roughness");
- if(!roughness_input->link && roughness_input->value.x <= 1e-4f) {
- distribution = ustring("Sharp");
+ if(!roughness_input->link && roughness_input->value_float() <= 1e-4f) {
+ distribution = CLOSURE_BSDF_REFLECTION_ID;
}
}
else {
/* Rollback to original distribution when filter glossy is used. */
distribution = distribution_orig;
}
- closure = (ClosureType)distribution_enum[distribution];
+ closure = distribution;
}
bool GlossyBsdfNode::has_integrator_dependency()
{
ShaderInput *roughness_input = input("Roughness");
- return !roughness_input->link && roughness_input->value.x <= 1e-4f;
+ return !roughness_input->link && roughness_input->value_float() <= 1e-4f;
}
void GlossyBsdfNode::compile(SVMCompiler& compiler)
{
- closure = (ClosureType)distribution_enum[distribution];
+ closure = distribution;
if(closure == CLOSURE_BSDF_REFLECTION_ID)
BsdfNode::compile(compiler, NULL, NULL);
@@ -1892,15 +1904,15 @@ void GlossyBsdfNode::compile(SVMCompiler& compiler)
void GlossyBsdfNode::compile(OSLCompiler& compiler)
{
- compiler.parameter("distribution", distribution);
+ compiler.parameter("distribution", distribution_enum[distribution]);
compiler.add(this, "node_glossy_bsdf");
}
/* Glass BSDF Closure */
-static ShaderEnum glass_distribution_init()
+static NodeEnum glass_distribution_init()
{
- ShaderEnum enm;
+ NodeEnum enm;
enm.insert("Sharp", CLOSURE_BSDF_SHARP_GLASS_ID);
enm.insert("Beckmann", CLOSURE_BSDF_MICROFACET_BECKMANN_GLASS_ID);
@@ -1909,21 +1921,21 @@ static ShaderEnum glass_distribution_init()
return enm;
}
-ShaderEnum GlassBsdfNode::distribution_enum = glass_distribution_init();
+NodeEnum GlassBsdfNode::distribution_enum = glass_distribution_init();
GlassBsdfNode::GlassBsdfNode()
{
closure = CLOSURE_BSDF_SHARP_GLASS_ID;
- distribution = ustring("Sharp");
- distribution_orig = ustring("");
+ distribution = CLOSURE_BSDF_SHARP_GLASS_ID;
+ distribution_orig = NBUILTIN_CLOSURES;
- add_input("Roughness", SHADER_SOCKET_FLOAT, 0.0f);
- add_input("IOR", SHADER_SOCKET_FLOAT, 0.3f);
+ add_input("Roughness", SocketType::FLOAT, 0.0f);
+ add_input("IOR", SocketType::FLOAT, 0.3f);
}
void GlassBsdfNode::simplify_settings(Scene *scene)
{
- if(distribution_orig == "") {
+ if(distribution_orig == NBUILTIN_CLOSURES) {
distribution_orig = distribution;
}
Integrator *integrator = scene->integrator;
@@ -1932,26 +1944,26 @@ void GlassBsdfNode::simplify_settings(Scene *scene)
* Note: Keep the epsilon in sync with kernel!
*/
ShaderInput *roughness_input = input("Roughness");
- if(!roughness_input->link && roughness_input->value.x <= 1e-4f) {
- distribution = ustring("Sharp");
+ if(!roughness_input->link && roughness_input->value_float() <= 1e-4f) {
+ distribution = CLOSURE_BSDF_SHARP_GLASS_ID;
}
}
else {
/* Rollback to original distribution when filter glossy is used. */
distribution = distribution_orig;
}
- closure = (ClosureType)distribution_enum[distribution];
+ closure = distribution;
}
bool GlassBsdfNode::has_integrator_dependency()
{
ShaderInput *roughness_input = input("Roughness");
- return !roughness_input->link && roughness_input->value.x <= 1e-4f;
+ return !roughness_input->link && roughness_input->value_float() <= 1e-4f;
}
void GlassBsdfNode::compile(SVMCompiler& compiler)
{
- closure = (ClosureType)distribution_enum[distribution];
+ closure = distribution;
if(closure == CLOSURE_BSDF_SHARP_GLASS_ID)
BsdfNode::compile(compiler, NULL, input("IOR"));
@@ -1961,15 +1973,15 @@ void GlassBsdfNode::compile(SVMCompiler& compiler)
void GlassBsdfNode::compile(OSLCompiler& compiler)
{
- compiler.parameter("distribution", distribution);
+ compiler.parameter("distribution", distribution_enum[distribution]);
compiler.add(this, "node_glass_bsdf");
}
/* Refraction BSDF Closure */
-static ShaderEnum refraction_distribution_init()
+static NodeEnum refraction_distribution_init()
{
- ShaderEnum enm;
+ NodeEnum enm;
enm.insert("Sharp", CLOSURE_BSDF_REFRACTION_ID);
enm.insert("Beckmann", CLOSURE_BSDF_MICROFACET_BECKMANN_REFRACTION_ID);
@@ -1978,21 +1990,21 @@ static ShaderEnum refraction_distribution_init()
return enm;
}
-ShaderEnum RefractionBsdfNode::distribution_enum = refraction_distribution_init();
+NodeEnum RefractionBsdfNode::distribution_enum = refraction_distribution_init();
RefractionBsdfNode::RefractionBsdfNode()
{
closure = CLOSURE_BSDF_REFRACTION_ID;
- distribution = ustring("Sharp");
- distribution_orig = ustring("");
+ distribution = CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID;
+ distribution_orig = NBUILTIN_CLOSURES;
- add_input("Roughness", SHADER_SOCKET_FLOAT, 0.0f);
- add_input("IOR", SHADER_SOCKET_FLOAT, 0.3f);
+ add_input("Roughness", SocketType::FLOAT, 0.0f);
+ add_input("IOR", SocketType::FLOAT, 0.3f);
}
void RefractionBsdfNode::simplify_settings(Scene *scene)
{
- if(distribution_orig == "") {
+ if(distribution_orig == NBUILTIN_CLOSURES) {
distribution_orig = distribution;
}
Integrator *integrator = scene->integrator;
@@ -2001,26 +2013,26 @@ void RefractionBsdfNode::simplify_settings(Scene *scene)
* Note: Keep the epsilon in sync with kernel!
*/
ShaderInput *roughness_input = input("Roughness");
- if(!roughness_input->link && roughness_input->value.x <= 1e-4f) {
- distribution = ustring("Sharp");
+ if(!roughness_input->link && roughness_input->value_float() <= 1e-4f) {
+ distribution = CLOSURE_BSDF_REFRACTION_ID;
}
}
else {
/* Rollback to original distribution when filter glossy is used. */
distribution = distribution_orig;
}
- closure = (ClosureType)distribution_enum[distribution];
+ closure = distribution;
}
bool RefractionBsdfNode::has_integrator_dependency()
{
ShaderInput *roughness_input = input("Roughness");
- return !roughness_input->link && roughness_input->value.x <= 1e-4f;
+ return !roughness_input->link && roughness_input->value_float() <= 1e-4f;
}
void RefractionBsdfNode::compile(SVMCompiler& compiler)
{
- closure = (ClosureType)distribution_enum[distribution];
+ closure = distribution;
if(closure == CLOSURE_BSDF_REFRACTION_ID)
BsdfNode::compile(compiler, NULL, input("IOR"));
@@ -2030,15 +2042,15 @@ void RefractionBsdfNode::compile(SVMCompiler& compiler)
void RefractionBsdfNode::compile(OSLCompiler& compiler)
{
- compiler.parameter("distribution", distribution);
+ compiler.parameter("distribution", distribution_enum[distribution]);
compiler.add(this, "node_refraction_bsdf");
}
/* Toon BSDF Closure */
-static ShaderEnum toon_component_init()
+static NodeEnum toon_component_init()
{
- ShaderEnum enm;
+ NodeEnum enm;
enm.insert("Diffuse", CLOSURE_BSDF_DIFFUSE_TOON_ID);
enm.insert("Glossy", CLOSURE_BSDF_GLOSSY_TOON_ID);
@@ -2046,27 +2058,27 @@ static ShaderEnum toon_component_init()
return enm;
}
-ShaderEnum ToonBsdfNode::component_enum = toon_component_init();
+NodeEnum ToonBsdfNode::component_enum = toon_component_init();
ToonBsdfNode::ToonBsdfNode()
{
closure = CLOSURE_BSDF_DIFFUSE_TOON_ID;
- component = ustring("Diffuse");
+ component = CLOSURE_BSDF_DIFFUSE_TOON_ID;
- add_input("Size", SHADER_SOCKET_FLOAT, 0.5f);
- add_input("Smooth", SHADER_SOCKET_FLOAT, 0.0f);
+ add_input("Size", SocketType::FLOAT, 0.5f);
+ add_input("Smooth", SocketType::FLOAT, 0.0f);
}
void ToonBsdfNode::compile(SVMCompiler& compiler)
{
- closure = (ClosureType)component_enum[component];
+ closure = component;
BsdfNode::compile(compiler, input("Size"), input("Smooth"));
}
void ToonBsdfNode::compile(OSLCompiler& compiler)
{
- compiler.parameter("component", component);
+ compiler.parameter("component", component_enum[component]);
compiler.add(this, "node_toon_bsdf");
}
@@ -2076,7 +2088,7 @@ VelvetBsdfNode::VelvetBsdfNode()
{
closure = CLOSURE_BSDF_ASHIKHMIN_VELVET_ID;
- add_input("Sigma", SHADER_SOCKET_FLOAT, 1.0f);
+ add_input("Sigma", SocketType::FLOAT, 1.0f);
}
void VelvetBsdfNode::compile(SVMCompiler& compiler)
@@ -2094,7 +2106,7 @@ void VelvetBsdfNode::compile(OSLCompiler& compiler)
DiffuseBsdfNode::DiffuseBsdfNode()
{
closure = CLOSURE_BSDF_DIFFUSE_ID;
- add_input("Roughness", SHADER_SOCKET_FLOAT, 0.0f);
+ add_input("Roughness", SocketType::FLOAT, 0.0f);
}
void DiffuseBsdfNode::compile(SVMCompiler& compiler)
@@ -2144,9 +2156,9 @@ void TransparentBsdfNode::compile(OSLCompiler& compiler)
/* Subsurface Scattering Closure */
-static ShaderEnum subsurface_falloff_init()
+static NodeEnum subsurface_falloff_init()
{
- ShaderEnum enm;
+ NodeEnum enm;
enm.insert("Cubic", CLOSURE_BSSRDF_CUBIC_ID);
enm.insert("Gaussian", CLOSURE_BSSRDF_GAUSSIAN_ID);
@@ -2155,28 +2167,29 @@ static ShaderEnum subsurface_falloff_init()
return enm;
}
-ShaderEnum SubsurfaceScatteringNode::falloff_enum = subsurface_falloff_init();
+NodeEnum SubsurfaceScatteringNode::falloff_enum = subsurface_falloff_init();
SubsurfaceScatteringNode::SubsurfaceScatteringNode()
: BsdfNode(true)
{
name = "subsurface_scattering";
- closure = CLOSURE_BSSRDF_CUBIC_ID;
+ falloff = CLOSURE_BSSRDF_CUBIC_ID;
- add_input("Scale", SHADER_SOCKET_FLOAT, 0.01f);
- add_input("Radius", SHADER_SOCKET_VECTOR, make_float3(0.1f, 0.1f, 0.1f));
- add_input("Sharpness", SHADER_SOCKET_FLOAT, 0.0f);
- add_input("Texture Blur", SHADER_SOCKET_FLOAT, 1.0f);
+ add_input("Scale", SocketType::FLOAT, 0.01f);
+ add_input("Radius", SocketType::VECTOR, make_float3(0.1f, 0.1f, 0.1f));
+ add_input("Sharpness", SocketType::FLOAT, 0.0f);
+ add_input("Texture Blur", SocketType::FLOAT, 1.0f);
}
void SubsurfaceScatteringNode::compile(SVMCompiler& compiler)
{
+ closure = falloff;
BsdfNode::compile(compiler, input("Scale"), input("Texture Blur"), input("Radius"), input("Sharpness"));
}
void SubsurfaceScatteringNode::compile(OSLCompiler& compiler)
{
- compiler.parameter("Falloff", falloff_enum[closure]);
+ compiler.parameter("falloff", falloff_enum[closure]);
compiler.add(this, "node_subsurface_scattering");
}
@@ -2192,11 +2205,11 @@ bool SubsurfaceScatteringNode::has_bssrdf_bump()
EmissionNode::EmissionNode()
: ShaderNode("emission")
{
- add_input("Color", SHADER_SOCKET_COLOR, make_float3(0.8f, 0.8f, 0.8f));
- add_input("Strength", SHADER_SOCKET_FLOAT, 10.0f);
- add_input("SurfaceMixWeight", SHADER_SOCKET_FLOAT, 0.0f, ShaderInput::USE_SVM);
+ add_input("Color", SocketType::COLOR, make_float3(0.8f, 0.8f, 0.8f));
+ add_input("Strength", SocketType::FLOAT, 10.0f);
+ add_input("SurfaceMixWeight", SocketType::FLOAT, 0.0f, SocketType::SVM_INTERNAL);
- add_output("Emission", SHADER_SOCKET_CLOSURE);
+ add_output("Emission", SocketType::CLOSURE);
}
void EmissionNode::compile(SVMCompiler& compiler)
@@ -2210,7 +2223,7 @@ void EmissionNode::compile(SVMCompiler& compiler)
compiler.stack_assign(strength_in));
}
else
- compiler.add_node(NODE_CLOSURE_SET_WEIGHT, color_in->value * strength_in->value.x);
+ compiler.add_node(NODE_CLOSURE_SET_WEIGHT, color_in->value() * strength_in->value_float());
compiler.add_node(NODE_CLOSURE_EMISSION, compiler.closure_mix_weight_offset());
}
@@ -2220,13 +2233,13 @@ void EmissionNode::compile(OSLCompiler& compiler)
compiler.add(this, "node_emission");
}
-bool EmissionNode::constant_fold(ShaderGraph * /*graph*/, ShaderOutput * /*socket*/, float3 * /*optimized_value*/)
+bool EmissionNode::constant_fold(ShaderGraph *, ShaderOutput *, ShaderInput *)
{
ShaderInput *color_in = input("Color");
ShaderInput *strength_in = input("Strength");
- return ((!color_in->link && color_in->value == make_float3(0.0f, 0.0f, 0.0f)) ||
- (!strength_in->link && strength_in->value.x == 0.0f));
+ return ((!color_in->link && color_in->value() == make_float3(0.0f, 0.0f, 0.0f)) ||
+ (!strength_in->link && strength_in->value_float() == 0.0f));
}
/* Background Closure */
@@ -2234,11 +2247,11 @@ bool EmissionNode::constant_fold(ShaderGraph * /*graph*/, ShaderOutput * /*socke
BackgroundNode::BackgroundNode()
: ShaderNode("background")
{
- add_input("Color", SHADER_SOCKET_COLOR, make_float3(0.8f, 0.8f, 0.8f));
- add_input("Strength", SHADER_SOCKET_FLOAT, 1.0f);
- add_input("SurfaceMixWeight", SHADER_SOCKET_FLOAT, 0.0f, ShaderInput::USE_SVM);
+ add_input("Color", SocketType::COLOR, make_float3(0.8f, 0.8f, 0.8f));
+ add_input("Strength", SocketType::FLOAT, 1.0f);
+ add_input("SurfaceMixWeight", SocketType::FLOAT, 0.0f, SocketType::SVM_INTERNAL);
- add_output("Background", SHADER_SOCKET_CLOSURE);
+ add_output("Background", SocketType::CLOSURE);
}
void BackgroundNode::compile(SVMCompiler& compiler)
@@ -2252,7 +2265,7 @@ void BackgroundNode::compile(SVMCompiler& compiler)
compiler.stack_assign(strength_in));
}
else
- compiler.add_node(NODE_CLOSURE_SET_WEIGHT, color_in->value*strength_in->value.x);
+ compiler.add_node(NODE_CLOSURE_SET_WEIGHT, color_in->value()*strength_in->value_float());
compiler.add_node(NODE_CLOSURE_BACKGROUND, compiler.closure_mix_weight_offset());
}
@@ -2262,13 +2275,13 @@ void BackgroundNode::compile(OSLCompiler& compiler)
compiler.add(this, "node_background");
}
-bool BackgroundNode::constant_fold(ShaderGraph * /*graph*/, ShaderOutput * /*socket*/, float3 * /*optimized_value*/)
+bool BackgroundNode::constant_fold(ShaderGraph *, ShaderOutput *, ShaderInput *)
{
ShaderInput *color_in = input("Color");
ShaderInput *strength_in = input("Strength");
- return ((!color_in->link && color_in->value == make_float3(0.0f, 0.0f, 0.0f)) ||
- (!strength_in->link && strength_in->value.x == 0.0f));
+ return ((!color_in->link && color_in->value() == make_float3(0.0f, 0.0f, 0.0f)) ||
+ (!strength_in->link && strength_in->value_float() == 0.0f));
}
/* Holdout Closure */
@@ -2276,10 +2289,10 @@ bool BackgroundNode::constant_fold(ShaderGraph * /*graph*/, ShaderOutput * /*soc
HoldoutNode::HoldoutNode()
: ShaderNode("holdout")
{
- add_input("SurfaceMixWeight", SHADER_SOCKET_FLOAT, 0.0f, ShaderInput::USE_SVM);
- add_input("VolumeMixWeight", SHADER_SOCKET_FLOAT, 0.0f, ShaderInput::USE_SVM);
+ add_input("SurfaceMixWeight", SocketType::FLOAT, 0.0f, SocketType::SVM_INTERNAL);
+ add_input("VolumeMixWeight", SocketType::FLOAT, 0.0f, SocketType::SVM_INTERNAL);
- add_output("Holdout", SHADER_SOCKET_CLOSURE);
+ add_output("Holdout", SocketType::CLOSURE);
}
void HoldoutNode::compile(SVMCompiler& compiler)
@@ -2300,11 +2313,11 @@ void HoldoutNode::compile(OSLCompiler& compiler)
AmbientOcclusionNode::AmbientOcclusionNode()
: ShaderNode("ambient_occlusion")
{
- add_input("NormalIn", SHADER_SOCKET_NORMAL, ShaderInput::NORMAL, ShaderInput::USE_OSL);
- add_input("Color", SHADER_SOCKET_COLOR, make_float3(0.8f, 0.8f, 0.8f));
- add_input("SurfaceMixWeight", SHADER_SOCKET_FLOAT, 0.0f, ShaderInput::USE_SVM);
+ add_input("NormalIn", SocketType::NORMAL, make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_NORMAL | SocketType::OSL_INTERNAL);
+ add_input("Color", SocketType::COLOR, make_float3(0.8f, 0.8f, 0.8f));
+ add_input("SurfaceMixWeight", SocketType::FLOAT, 0.0f, SocketType::SVM_INTERNAL);
- add_output("AO", SHADER_SOCKET_CLOSURE);
+ add_output("AO", SocketType::CLOSURE);
}
void AmbientOcclusionNode::compile(SVMCompiler& compiler)
@@ -2314,7 +2327,7 @@ void AmbientOcclusionNode::compile(SVMCompiler& compiler)
if(color_in->link)
compiler.add_node(NODE_CLOSURE_WEIGHT, compiler.stack_assign(color_in));
else
- compiler.add_node(NODE_CLOSURE_SET_WEIGHT, color_in->value);
+ compiler.add_node(NODE_CLOSURE_SET_WEIGHT, color_in->value());
compiler.add_node(NODE_CLOSURE_AMBIENT_OCCLUSION, compiler.closure_mix_weight_offset());
}
@@ -2331,11 +2344,11 @@ VolumeNode::VolumeNode()
{
closure = CLOSURE_VOLUME_HENYEY_GREENSTEIN_ID;
- add_input("Color", SHADER_SOCKET_COLOR, make_float3(0.8f, 0.8f, 0.8f));
- add_input("Density", SHADER_SOCKET_FLOAT, 1.0f);
- add_input("VolumeMixWeight", SHADER_SOCKET_FLOAT, 0.0f, ShaderInput::USE_SVM);
+ add_input("Color", SocketType::COLOR, make_float3(0.8f, 0.8f, 0.8f));
+ add_input("Density", SocketType::FLOAT, 1.0f);
+ add_input("VolumeMixWeight", SocketType::FLOAT, 0.0f, SocketType::SVM_INTERNAL);
- add_output("Volume", SHADER_SOCKET_CLOSURE);
+ add_output("Volume", SocketType::CLOSURE);
}
void VolumeNode::compile(SVMCompiler& compiler, ShaderInput *param1, ShaderInput *param2)
@@ -2345,15 +2358,15 @@ void VolumeNode::compile(SVMCompiler& compiler, ShaderInput *param1, ShaderInput
if(color_in->link)
compiler.add_node(NODE_CLOSURE_WEIGHT, compiler.stack_assign(color_in));
else
- compiler.add_node(NODE_CLOSURE_SET_WEIGHT, color_in->value);
+ compiler.add_node(NODE_CLOSURE_SET_WEIGHT, color_in->value());
compiler.add_node(NODE_CLOSURE_VOLUME,
compiler.encode_uchar4(closure,
(param1)? compiler.stack_assign(param1): SVM_STACK_INVALID,
(param2)? compiler.stack_assign(param2): SVM_STACK_INVALID,
compiler.closure_mix_weight_offset()),
- __float_as_int((param1)? param1->value.x: 0.0f),
- __float_as_int((param2)? param2->value.x: 0.0f));
+ __float_as_int((param1)? param1->value_float(): 0.0f),
+ __float_as_int((param2)? param2->value_float(): 0.0f));
}
void VolumeNode::compile(SVMCompiler& compiler)
@@ -2389,7 +2402,7 @@ ScatterVolumeNode::ScatterVolumeNode()
{
closure = CLOSURE_VOLUME_HENYEY_GREENSTEIN_ID;
- add_input("Anisotropy", SHADER_SOCKET_FLOAT, 0.0f);
+ add_input("Anisotropy", SocketType::FLOAT, 0.0f);
}
void ScatterVolumeNode::compile(SVMCompiler& compiler)
@@ -2404,9 +2417,9 @@ void ScatterVolumeNode::compile(OSLCompiler& compiler)
/* Hair BSDF Closure */
-static ShaderEnum hair_component_init()
+static NodeEnum hair_component_init()
{
- ShaderEnum enm;
+ NodeEnum enm;
enm.insert("Reflection", CLOSURE_BSDF_HAIR_REFLECTION_ID);
enm.insert("Transmission", CLOSURE_BSDF_HAIR_TRANSMISSION_ID);
@@ -2414,29 +2427,29 @@ static ShaderEnum hair_component_init()
return enm;
}
-ShaderEnum HairBsdfNode::component_enum = hair_component_init();
+NodeEnum HairBsdfNode::component_enum = hair_component_init();
HairBsdfNode::HairBsdfNode()
{
closure = CLOSURE_BSDF_HAIR_REFLECTION_ID;
- component = ustring("Reflection");
+ component = CLOSURE_BSDF_HAIR_REFLECTION_ID;
- add_input("Offset", SHADER_SOCKET_FLOAT);
- add_input("RoughnessU", SHADER_SOCKET_FLOAT);
- add_input("RoughnessV", SHADER_SOCKET_FLOAT);
- add_input("Tangent", SHADER_SOCKET_VECTOR);
+ add_input("Offset", SocketType::FLOAT);
+ add_input("RoughnessU", SocketType::FLOAT);
+ add_input("RoughnessV", SocketType::FLOAT);
+ add_input("Tangent", SocketType::VECTOR);
}
void HairBsdfNode::compile(SVMCompiler& compiler)
{
- closure = (ClosureType)component_enum[component];
+ closure = component;
BsdfNode::compile(compiler, input("RoughnessU"), input("RoughnessV"), input("Offset"));
}
void HairBsdfNode::compile(OSLCompiler& compiler)
{
- compiler.parameter("component", component);
+ compiler.parameter("component", component_enum[component]);
compiler.add(this, "node_hair_bsdf");
}
@@ -2448,15 +2461,15 @@ GeometryNode::GeometryNode()
{
special_type = SHADER_SPECIAL_TYPE_GEOMETRY;
- add_input("NormalIn", SHADER_SOCKET_NORMAL, ShaderInput::NORMAL, ShaderInput::USE_OSL);
- add_output("Position", SHADER_SOCKET_POINT);
- add_output("Normal", SHADER_SOCKET_NORMAL);
- add_output("Tangent", SHADER_SOCKET_NORMAL);
- add_output("True Normal", SHADER_SOCKET_NORMAL);
- add_output("Incoming", SHADER_SOCKET_VECTOR);
- add_output("Parametric", SHADER_SOCKET_POINT);
- add_output("Backfacing", SHADER_SOCKET_FLOAT);
- add_output("Pointiness", SHADER_SOCKET_FLOAT);
+ add_input("NormalIn", SocketType::NORMAL, make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_NORMAL | SocketType::OSL_INTERNAL);
+ add_output("Position", SocketType::POINT);
+ add_output("Normal", SocketType::NORMAL);
+ add_output("Tangent", SocketType::NORMAL);
+ add_output("True Normal", SocketType::NORMAL);
+ add_output("Incoming", SocketType::VECTOR);
+ add_output("Parametric", SocketType::POINT);
+ add_output("Backfacing", SocketType::FLOAT);
+ add_output("Pointiness", SocketType::FLOAT);
}
void GeometryNode::attributes(Shader *shader, AttributeRequestSet *attributes)
@@ -2554,14 +2567,14 @@ void GeometryNode::compile(OSLCompiler& compiler)
TextureCoordinateNode::TextureCoordinateNode()
: ShaderNode("texture_coordinate")
{
- add_input("NormalIn", SHADER_SOCKET_NORMAL, ShaderInput::NORMAL, ShaderInput::USE_OSL);
- add_output("Generated", SHADER_SOCKET_POINT);
- add_output("Normal", SHADER_SOCKET_NORMAL);
- add_output("UV", SHADER_SOCKET_POINT);
- add_output("Object", SHADER_SOCKET_POINT);
- add_output("Camera", SHADER_SOCKET_POINT);
- add_output("Window", SHADER_SOCKET_POINT);
- add_output("Reflection", SHADER_SOCKET_NORMAL);
+ add_input("NormalIn", SocketType::NORMAL, make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_NORMAL | SocketType::OSL_INTERNAL);
+ add_output("Generated", SocketType::POINT);
+ add_output("Normal", SocketType::NORMAL);
+ add_output("UV", SocketType::POINT);
+ add_output("Object", SocketType::POINT);
+ add_output("Camera", SocketType::POINT);
+ add_output("Window", SocketType::POINT);
+ add_output("Reflection", SocketType::NORMAL);
from_dupli = false;
use_transform = false;
@@ -2704,7 +2717,7 @@ UVMapNode::UVMapNode()
attribute = "";
from_dupli = false;
- add_output("UV", SHADER_SOCKET_POINT);
+ add_output("UV", SocketType::POINT);
}
void UVMapNode::attributes(Shader *shader, AttributeRequestSet *attributes)
@@ -2773,18 +2786,18 @@ void UVMapNode::compile(OSLCompiler& compiler)
LightPathNode::LightPathNode()
: ShaderNode("light_path")
{
- add_output("Is Camera Ray", SHADER_SOCKET_FLOAT);
- add_output("Is Shadow Ray", SHADER_SOCKET_FLOAT);
- add_output("Is Diffuse Ray", SHADER_SOCKET_FLOAT);
- add_output("Is Glossy Ray", SHADER_SOCKET_FLOAT);
- add_output("Is Singular Ray", SHADER_SOCKET_FLOAT);
- add_output("Is Reflection Ray", SHADER_SOCKET_FLOAT);
- add_output("Is Transmission Ray", SHADER_SOCKET_FLOAT);
- add_output("Is Volume Scatter Ray", SHADER_SOCKET_FLOAT);
- add_output("Ray Length", SHADER_SOCKET_FLOAT);
- add_output("Ray Depth", SHADER_SOCKET_FLOAT);
- add_output("Transparent Depth", SHADER_SOCKET_FLOAT);
- add_output("Transmission Depth", SHADER_SOCKET_FLOAT);
+ add_output("Is Camera Ray", SocketType::FLOAT);
+ add_output("Is Shadow Ray", SocketType::FLOAT);
+ add_output("Is Diffuse Ray", SocketType::FLOAT);
+ add_output("Is Glossy Ray", SocketType::FLOAT);
+ add_output("Is Singular Ray", SocketType::FLOAT);
+ add_output("Is Reflection Ray", SocketType::FLOAT);
+ add_output("Is Transmission Ray", SocketType::FLOAT);
+ add_output("Is Volume Scatter Ray", SocketType::FLOAT);
+ add_output("Ray Length", SocketType::FLOAT);
+ add_output("Ray Depth", SocketType::FLOAT);
+ add_output("Transparent Depth", SocketType::FLOAT);
+ add_output("Transmission Depth", SocketType::FLOAT);
}
void LightPathNode::compile(SVMCompiler& compiler)
@@ -2863,11 +2876,11 @@ void LightPathNode::compile(OSLCompiler& compiler)
LightFalloffNode::LightFalloffNode()
: ShaderNode("light_fallof")
{
- add_input("Strength", SHADER_SOCKET_FLOAT, 100.0f);
- add_input("Smooth", SHADER_SOCKET_FLOAT, 0.0f);
- add_output("Quadratic", SHADER_SOCKET_FLOAT);
- add_output("Linear", SHADER_SOCKET_FLOAT);
- add_output("Constant", SHADER_SOCKET_FLOAT);
+ add_input("Strength", SocketType::FLOAT, 100.0f);
+ add_input("Smooth", SocketType::FLOAT, 0.0f);
+ add_output("Quadratic", SocketType::FLOAT);
+ add_output("Linear", SocketType::FLOAT);
+ add_output("Constant", SocketType::FLOAT);
}
void LightFalloffNode::compile(SVMCompiler& compiler)
@@ -2913,10 +2926,10 @@ void LightFalloffNode::compile(OSLCompiler& compiler)
ObjectInfoNode::ObjectInfoNode()
: ShaderNode("object_info")
{
- add_output("Location", SHADER_SOCKET_VECTOR);
- add_output("Object Index", SHADER_SOCKET_FLOAT);
- add_output("Material Index", SHADER_SOCKET_FLOAT);
- add_output("Random", SHADER_SOCKET_FLOAT);
+ add_output("Location", SocketType::VECTOR);
+ add_output("Object Index", SocketType::FLOAT);
+ add_output("Material Index", SocketType::FLOAT);
+ add_output("Random", SocketType::FLOAT);
}
void ObjectInfoNode::compile(SVMCompiler& compiler)
@@ -2952,16 +2965,16 @@ void ObjectInfoNode::compile(OSLCompiler& compiler)
ParticleInfoNode::ParticleInfoNode()
: ShaderNode("particle_info")
{
- add_output("Index", SHADER_SOCKET_FLOAT);
- add_output("Age", SHADER_SOCKET_FLOAT);
- add_output("Lifetime", SHADER_SOCKET_FLOAT);
- add_output("Location", SHADER_SOCKET_POINT);
+ add_output("Index", SocketType::FLOAT);
+ add_output("Age", SocketType::FLOAT);
+ add_output("Lifetime", SocketType::FLOAT);
+ add_output("Location", SocketType::POINT);
#if 0 /* not yet supported */
add_output("Rotation", SHADER_SOCKET_QUATERNION);
#endif
- add_output("Size", SHADER_SOCKET_FLOAT);
- add_output("Velocity", SHADER_SOCKET_VECTOR);
- add_output("Angular Velocity", SHADER_SOCKET_VECTOR);
+ add_output("Size", SocketType::FLOAT);
+ add_output("Velocity", SocketType::VECTOR);
+ add_output("Angular Velocity", SocketType::VECTOR);
}
void ParticleInfoNode::attributes(Shader *shader, AttributeRequestSet *attributes)
@@ -3046,12 +3059,12 @@ void ParticleInfoNode::compile(OSLCompiler& compiler)
HairInfoNode::HairInfoNode()
: ShaderNode("hair_info")
{
- add_output("Is Strand", SHADER_SOCKET_FLOAT);
- add_output("Intercept", SHADER_SOCKET_FLOAT);
- add_output("Thickness", SHADER_SOCKET_FLOAT);
- add_output("Tangent Normal", SHADER_SOCKET_NORMAL);
+ add_output("Is Strand", SocketType::FLOAT);
+ add_output("Intercept", SocketType::FLOAT);
+ add_output("Thickness", SocketType::FLOAT);
+ add_output("Tangent Normal", SocketType::NORMAL);
/*output for minimum hair width transparency - deactivated*/
- /*add_output("Fade", SHADER_SOCKET_FLOAT);*/
+ /*add_output("Fade", SocketType::FLOAT);*/
}
void HairInfoNode::attributes(Shader *shader, AttributeRequestSet *attributes)
@@ -3110,13 +3123,12 @@ ValueNode::ValueNode()
{
value = 0.0f;
- add_output("Value", SHADER_SOCKET_FLOAT);
+ add_output("Value", SocketType::FLOAT);
}
-bool ValueNode::constant_fold(ShaderGraph * /*graph*/, ShaderOutput * /*socket*/,
- float3 *optimized_value)
+bool ValueNode::constant_fold(ShaderGraph *, ShaderOutput *, ShaderInput *optimized)
{
- *optimized_value = make_float3(value, value, value);
+ optimized->set(value);
return true;
}
@@ -3140,13 +3152,12 @@ ColorNode::ColorNode()
{
value = make_float3(0.0f, 0.0f, 0.0f);
- add_output("Color", SHADER_SOCKET_COLOR);
+ add_output("Color", SocketType::COLOR);
}
-bool ColorNode::constant_fold(ShaderGraph * /*graph*/, ShaderOutput * /*socket*/,
- float3 *optimized_value)
+bool ColorNode::constant_fold(ShaderGraph *, ShaderOutput *, ShaderInput *optimized)
{
- *optimized_value = value;
+ optimized->set(value);
return true;
}
@@ -3174,9 +3185,9 @@ AddClosureNode::AddClosureNode()
{
special_type = SHADER_SPECIAL_TYPE_COMBINE_CLOSURE;
- add_input("Closure1", SHADER_SOCKET_CLOSURE);
- add_input("Closure2", SHADER_SOCKET_CLOSURE);
- add_output("Closure", SHADER_SOCKET_CLOSURE);
+ add_input("Closure1", SocketType::CLOSURE);
+ add_input("Closure2", SocketType::CLOSURE);
+ add_output("Closure", SocketType::CLOSURE);
}
void AddClosureNode::compile(SVMCompiler& /*compiler*/)
@@ -3196,10 +3207,10 @@ MixClosureNode::MixClosureNode()
{
special_type = SHADER_SPECIAL_TYPE_COMBINE_CLOSURE;
- add_input("Fac", SHADER_SOCKET_FLOAT, 0.5f);
- add_input("Closure1", SHADER_SOCKET_CLOSURE);
- add_input("Closure2", SHADER_SOCKET_CLOSURE);
- add_output("Closure", SHADER_SOCKET_CLOSURE);
+ add_input("Fac", SocketType::FLOAT, 0.5f);
+ add_input("Closure1", SocketType::CLOSURE);
+ add_input("Closure2", SocketType::CLOSURE);
+ add_output("Closure", SocketType::CLOSURE);
}
void MixClosureNode::compile(SVMCompiler& /*compiler*/)
@@ -3212,7 +3223,7 @@ void MixClosureNode::compile(OSLCompiler& compiler)
compiler.add(this, "node_mix_closure");
}
-bool MixClosureNode::constant_fold(ShaderGraph *graph, ShaderOutput * /*socket*/, float3 * /*optimized_value*/)
+bool MixClosureNode::constant_fold(ShaderGraph *graph, ShaderOutput *, ShaderInput *)
{
ShaderInput *fac_in = input("Fac");
ShaderInput *closure1_in = input("Closure1");
@@ -3229,12 +3240,12 @@ bool MixClosureNode::constant_fold(ShaderGraph *graph, ShaderOutput * /*socket*/
/* check for closure links and make sure factor link is disconnected */
if(closure1_in->link && closure2_in->link && !fac_in->link) {
/* factor 0.0 */
- if(fac_in->value.x == 0.0f) {
+ if(fac_in->value_float() == 0.0f) {
graph->relink(this, closure_out, closure1_in->link);
return true;
}
/* factor 1.0 */
- else if(fac_in->value.x == 1.0f) {
+ else if(fac_in->value_float() == 1.0f) {
graph->relink(this, closure_out, closure2_in->link);
return true;
}
@@ -3248,10 +3259,10 @@ bool MixClosureNode::constant_fold(ShaderGraph *graph, ShaderOutput * /*socket*/
MixClosureWeightNode::MixClosureWeightNode()
: ShaderNode("mix_closure_weight")
{
- add_input("Weight", SHADER_SOCKET_FLOAT, 1.0f);
- add_input("Fac", SHADER_SOCKET_FLOAT, 1.0f);
- add_output("Weight1", SHADER_SOCKET_FLOAT);
- add_output("Weight2", SHADER_SOCKET_FLOAT);
+ add_input("Weight", SocketType::FLOAT, 1.0f);
+ add_input("Fac", SocketType::FLOAT, 1.0f);
+ add_output("Weight1", SocketType::FLOAT);
+ add_output("Weight2", SocketType::FLOAT);
}
void MixClosureWeightNode::compile(SVMCompiler& compiler)
@@ -3279,9 +3290,9 @@ void MixClosureWeightNode::compile(OSLCompiler& /*compiler*/)
InvertNode::InvertNode()
: ShaderNode("invert")
{
- add_input("Fac", SHADER_SOCKET_FLOAT, 1.0f);
- add_input("Color", SHADER_SOCKET_COLOR);
- add_output("Color", SHADER_SOCKET_COLOR);
+ add_input("Fac", SocketType::FLOAT, 1.0f);
+ add_input("Color", SocketType::COLOR);
+ add_output("Color", SocketType::COLOR);
}
void InvertNode::compile(SVMCompiler& compiler)
@@ -3306,19 +3317,19 @@ void InvertNode::compile(OSLCompiler& compiler)
MixNode::MixNode()
: ShaderNode("mix")
{
- type = ustring("Mix");
+ type = NODE_MIX_BLEND;
use_clamp = false;
- add_input("Fac", SHADER_SOCKET_FLOAT, 0.5f);
- add_input("Color1", SHADER_SOCKET_COLOR);
- add_input("Color2", SHADER_SOCKET_COLOR);
- add_output("Color", SHADER_SOCKET_COLOR);
+ add_input("Fac", SocketType::FLOAT, 0.5f);
+ add_input("Color1", SocketType::COLOR);
+ add_input("Color2", SocketType::COLOR);
+ add_output("Color", SocketType::COLOR);
}
-static ShaderEnum mix_type_init()
+static NodeEnum mix_type_init()
{
- ShaderEnum enm;
+ NodeEnum enm;
enm.insert("Mix", NODE_MIX_BLEND);
enm.insert("Add", NODE_MIX_ADD);
@@ -3342,7 +3353,7 @@ static ShaderEnum mix_type_init()
return enm;
}
-ShaderEnum MixNode::type_enum = mix_type_init();
+NodeEnum MixNode::type_enum = mix_type_init();
void MixNode::compile(SVMCompiler& compiler)
{
@@ -3355,7 +3366,7 @@ void MixNode::compile(SVMCompiler& compiler)
compiler.stack_assign(fac_in),
compiler.stack_assign(color1_in),
compiler.stack_assign(color2_in));
- compiler.add_node(NODE_MIX, type_enum[type], compiler.stack_assign(color_out));
+ compiler.add_node(NODE_MIX, type, compiler.stack_assign(color_out));
if(use_clamp) {
compiler.add_node(NODE_MIX, 0, compiler.stack_assign(color_out));
@@ -3365,14 +3376,14 @@ void MixNode::compile(SVMCompiler& compiler)
void MixNode::compile(OSLCompiler& compiler)
{
- compiler.parameter("type", type);
- compiler.parameter("Clamp", use_clamp);
+ compiler.parameter("type", type_enum[type]);
+ compiler.parameter("use_clamp", use_clamp);
compiler.add(this, "node_mix");
}
-bool MixNode::constant_fold(ShaderGraph *graph, ShaderOutput * /*socket*/, float3 * optimized_value)
+bool MixNode::constant_fold(ShaderGraph *graph, ShaderOutput *, ShaderInput *optimized)
{
- if(type != ustring("Mix")) {
+ if(type != NODE_MIX_BLEND) {
return false;
}
@@ -3390,19 +3401,19 @@ bool MixNode::constant_fold(ShaderGraph *graph, ShaderOutput * /*socket*/, float
/* remove unused mix color input when factor is 0.0 or 1.0 */
if(!fac_in->link) {
/* factor 0.0 */
- if(fac_in->value.x == 0.0f) {
+ if(fac_in->value_float() == 0.0f) {
if(color1_in->link)
graph->relink(this, color_out, color1_in->link);
else
- *optimized_value = color1_in->value;
+ optimized->set(color1_in->value());
return true;
}
/* factor 1.0 */
- else if(fac_in->value.x == 1.0f) {
+ else if(fac_in->value_float() == 1.0f) {
if(color2_in->link)
graph->relink(this, color_out, color2_in->link);
else
- *optimized_value = color2_in->value;
+ optimized->set(color2_in->value());
return true;
}
}
@@ -3414,10 +3425,10 @@ bool MixNode::constant_fold(ShaderGraph *graph, ShaderOutput * /*socket*/, float
CombineRGBNode::CombineRGBNode()
: ShaderNode("combine_rgb")
{
- add_input("R", SHADER_SOCKET_FLOAT);
- add_input("G", SHADER_SOCKET_FLOAT);
- add_input("B", SHADER_SOCKET_FLOAT);
- add_output("Image", SHADER_SOCKET_COLOR);
+ add_input("R", SocketType::FLOAT);
+ add_input("G", SocketType::FLOAT);
+ add_input("B", SocketType::FLOAT);
+ add_output("Image", SocketType::COLOR);
}
void CombineRGBNode::compile(SVMCompiler& compiler)
@@ -3449,10 +3460,10 @@ void CombineRGBNode::compile(OSLCompiler& compiler)
CombineXYZNode::CombineXYZNode()
: ShaderNode("combine_xyz")
{
- add_input("X", SHADER_SOCKET_FLOAT);
- add_input("Y", SHADER_SOCKET_FLOAT);
- add_input("Z", SHADER_SOCKET_FLOAT);
- add_output("Vector", SHADER_SOCKET_VECTOR);
+ add_input("X", SocketType::FLOAT);
+ add_input("Y", SocketType::FLOAT);
+ add_input("Z", SocketType::FLOAT);
+ add_output("Vector", SocketType::VECTOR);
}
void CombineXYZNode::compile(SVMCompiler& compiler)
@@ -3484,10 +3495,10 @@ void CombineXYZNode::compile(OSLCompiler& compiler)
CombineHSVNode::CombineHSVNode()
: ShaderNode("combine_hsv")
{
- add_input("H", SHADER_SOCKET_FLOAT);
- add_input("S", SHADER_SOCKET_FLOAT);
- add_input("V", SHADER_SOCKET_FLOAT);
- add_output("Color", SHADER_SOCKET_COLOR);
+ add_input("H", SocketType::FLOAT);
+ add_input("S", SocketType::FLOAT);
+ add_input("V", SocketType::FLOAT);
+ add_output("Color", SocketType::COLOR);
}
void CombineHSVNode::compile(SVMCompiler& compiler)
@@ -3514,20 +3525,20 @@ void CombineHSVNode::compile(OSLCompiler& compiler)
GammaNode::GammaNode()
: ShaderNode("gamma")
{
- add_input("Color", SHADER_SOCKET_COLOR);
- add_input("Gamma", SHADER_SOCKET_FLOAT);
- add_output("Color", SHADER_SOCKET_COLOR);
+ add_input("Color", SocketType::COLOR);
+ add_input("Gamma", SocketType::FLOAT);
+ add_output("Color", SocketType::COLOR);
}
-bool GammaNode::constant_fold(ShaderGraph * /*graph*/, ShaderOutput *socket, float3 *optimized_value)
+bool GammaNode::constant_fold(ShaderGraph *, ShaderOutput *socket, ShaderInput *optimized)
{
ShaderInput *color_in = input("Color");
ShaderInput *gamma_in = input("Gamma");
if(socket == output("Color")) {
if(color_in->link == NULL && gamma_in->link == NULL) {
- *optimized_value = svm_math_gamma_color(color_in->value,
- gamma_in->value.x);
+ optimized->set(svm_math_gamma_color(color_in->value(),
+ gamma_in->value_float()));
return true;
}
}
@@ -3556,10 +3567,10 @@ void GammaNode::compile(OSLCompiler& compiler)
BrightContrastNode::BrightContrastNode()
: ShaderNode("brightness")
{
- add_input("Color", SHADER_SOCKET_COLOR);
- add_input("Bright", SHADER_SOCKET_FLOAT);
- add_input("Contrast", SHADER_SOCKET_FLOAT);
- add_output("Color", SHADER_SOCKET_COLOR);
+ add_input("Color", SocketType::COLOR);
+ add_input("Bright", SocketType::FLOAT);
+ add_input("Contrast", SocketType::FLOAT);
+ add_output("Color", SocketType::COLOR);
}
void BrightContrastNode::compile(SVMCompiler& compiler)
@@ -3586,10 +3597,10 @@ void BrightContrastNode::compile(OSLCompiler& compiler)
SeparateRGBNode::SeparateRGBNode()
: ShaderNode("separate_rgb")
{
- add_input("Image", SHADER_SOCKET_COLOR);
- add_output("R", SHADER_SOCKET_FLOAT);
- add_output("G", SHADER_SOCKET_FLOAT);
- add_output("B", SHADER_SOCKET_FLOAT);
+ add_input("Image", SocketType::COLOR);
+ add_output("R", SocketType::FLOAT);
+ add_output("G", SocketType::FLOAT);
+ add_output("B", SocketType::FLOAT);
}
void SeparateRGBNode::compile(SVMCompiler& compiler)
@@ -3621,10 +3632,10 @@ void SeparateRGBNode::compile(OSLCompiler& compiler)
SeparateXYZNode::SeparateXYZNode()
: ShaderNode("separate_xyz")
{
- add_input("Vector", SHADER_SOCKET_VECTOR);
- add_output("X", SHADER_SOCKET_FLOAT);
- add_output("Y", SHADER_SOCKET_FLOAT);
- add_output("Z", SHADER_SOCKET_FLOAT);
+ add_input("Vector", SocketType::VECTOR);
+ add_output("X", SocketType::FLOAT);
+ add_output("Y", SocketType::FLOAT);
+ add_output("Z", SocketType::FLOAT);
}
void SeparateXYZNode::compile(SVMCompiler& compiler)
@@ -3656,10 +3667,10 @@ void SeparateXYZNode::compile(OSLCompiler& compiler)
SeparateHSVNode::SeparateHSVNode()
: ShaderNode("separate_hsv")
{
- add_input("Color", SHADER_SOCKET_COLOR);
- add_output("H", SHADER_SOCKET_FLOAT);
- add_output("S", SHADER_SOCKET_FLOAT);
- add_output("V", SHADER_SOCKET_FLOAT);
+ add_input("Color", SocketType::COLOR);
+ add_output("H", SocketType::FLOAT);
+ add_output("S", SocketType::FLOAT);
+ add_output("V", SocketType::FLOAT);
}
void SeparateHSVNode::compile(SVMCompiler& compiler)
@@ -3686,12 +3697,12 @@ void SeparateHSVNode::compile(OSLCompiler& compiler)
HSVNode::HSVNode()
: ShaderNode("hsv")
{
- add_input("Hue", SHADER_SOCKET_FLOAT);
- add_input("Saturation", SHADER_SOCKET_FLOAT);
- add_input("Value", SHADER_SOCKET_FLOAT);
- add_input("Fac", SHADER_SOCKET_FLOAT);
- add_input("Color", SHADER_SOCKET_COLOR);
- add_output("Color", SHADER_SOCKET_COLOR);
+ add_input("Hue", SocketType::FLOAT);
+ add_input("Saturation", SocketType::FLOAT);
+ add_input("Value", SocketType::FLOAT);
+ add_input("Fac", SocketType::FLOAT);
+ add_input("Color", SocketType::COLOR);
+ add_output("Color", SocketType::COLOR);
}
void HSVNode::compile(SVMCompiler& compiler)
@@ -3726,9 +3737,9 @@ AttributeNode::AttributeNode()
{
attribute = "";
- add_output("Color", SHADER_SOCKET_COLOR);
- add_output("Vector", SHADER_SOCKET_VECTOR);
- add_output("Fac", SHADER_SOCKET_FLOAT);
+ add_output("Color", SocketType::COLOR);
+ add_output("Vector", SocketType::VECTOR);
+ add_output("Fac", SocketType::FLOAT);
}
void AttributeNode::attributes(Shader *shader, AttributeRequestSet *attributes)
@@ -3807,9 +3818,9 @@ void AttributeNode::compile(OSLCompiler& compiler)
CameraNode::CameraNode()
: ShaderNode("camera")
{
- add_output("View Vector", SHADER_SOCKET_VECTOR);
- add_output("View Z Depth", SHADER_SOCKET_FLOAT);
- add_output("View Distance", SHADER_SOCKET_FLOAT);
+ add_output("View Vector", SocketType::VECTOR);
+ add_output("View Z Depth", SocketType::FLOAT);
+ add_output("View Distance", SocketType::FLOAT);
}
void CameraNode::compile(SVMCompiler& compiler)
@@ -3834,9 +3845,9 @@ void CameraNode::compile(OSLCompiler& compiler)
FresnelNode::FresnelNode()
: ShaderNode("fresnel")
{
- add_input("Normal", SHADER_SOCKET_NORMAL, ShaderInput::NORMAL, ShaderInput::USE_OSL);
- add_input("IOR", SHADER_SOCKET_FLOAT, 1.45f);
- add_output("Fac", SHADER_SOCKET_FLOAT);
+ add_input("Normal", SocketType::NORMAL, make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_NORMAL | SocketType::OSL_INTERNAL);
+ add_input("IOR", SocketType::FLOAT, 1.45f);
+ add_output("Fac", SocketType::FLOAT);
}
void FresnelNode::compile(SVMCompiler& compiler)
@@ -3847,7 +3858,7 @@ void FresnelNode::compile(SVMCompiler& compiler)
compiler.add_node(NODE_FRESNEL,
compiler.stack_assign(IOR_in),
- __float_as_int(IOR_in->value.x),
+ __float_as_int(IOR_in->value_float()),
compiler.encode_uchar4(
compiler.stack_assign_if_linked(normal_in),
compiler.stack_assign(fac_out)));
@@ -3863,11 +3874,11 @@ void FresnelNode::compile(OSLCompiler& compiler)
LayerWeightNode::LayerWeightNode()
: ShaderNode("layer_weight")
{
- add_input("Normal", SHADER_SOCKET_NORMAL, ShaderInput::NORMAL, ShaderInput::USE_OSL);
- add_input("Blend", SHADER_SOCKET_FLOAT, 0.5f);
+ add_input("Normal", SocketType::NORMAL, make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_NORMAL | SocketType::OSL_INTERNAL);
+ add_input("Blend", SocketType::FLOAT, 0.5f);
- add_output("Fresnel", SHADER_SOCKET_FLOAT);
- add_output("Facing", SHADER_SOCKET_FLOAT);
+ add_output("Fresnel", SocketType::FLOAT);
+ add_output("Facing", SocketType::FLOAT);
}
void LayerWeightNode::compile(SVMCompiler& compiler)
@@ -3880,7 +3891,7 @@ void LayerWeightNode::compile(SVMCompiler& compiler)
if(!fresnel_out->links.empty()) {
compiler.add_node(NODE_LAYER_WEIGHT,
compiler.stack_assign_if_linked(blend_in),
- __float_as_int(blend_in->value.x),
+ __float_as_int(blend_in->value_float()),
compiler.encode_uchar4(NODE_LAYER_WEIGHT_FRESNEL,
compiler.stack_assign_if_linked(normal_in),
compiler.stack_assign(fresnel_out)));
@@ -3889,7 +3900,7 @@ void LayerWeightNode::compile(SVMCompiler& compiler)
if(!facing_out->links.empty()) {
compiler.add_node(NODE_LAYER_WEIGHT,
compiler.stack_assign_if_linked(blend_in),
- __float_as_int(blend_in->value.x),
+ __float_as_int(blend_in->value_float()),
compiler.encode_uchar4(NODE_LAYER_WEIGHT_FACING,
compiler.stack_assign_if_linked(normal_in),
compiler.stack_assign(facing_out)));
@@ -3906,8 +3917,8 @@ void LayerWeightNode::compile(OSLCompiler& compiler)
WireframeNode::WireframeNode()
: ShaderNode("wireframe")
{
- add_input("Size", SHADER_SOCKET_FLOAT, 0.01f);
- add_output("Fac", SHADER_SOCKET_FLOAT);
+ add_input("Size", SocketType::FLOAT, 0.01f);
+ add_output("Fac", SocketType::FLOAT);
use_pixel_size = false;
}
@@ -3951,8 +3962,8 @@ void WireframeNode::compile(OSLCompiler& compiler)
WavelengthNode::WavelengthNode()
: ShaderNode("wavelength")
{
- add_input("Wavelength", SHADER_SOCKET_FLOAT, 500.0f);
- add_output("Color", SHADER_SOCKET_COLOR);
+ add_input("Wavelength", SocketType::FLOAT, 500.0f);
+ add_output("Color", SocketType::COLOR);
}
void WavelengthNode::compile(SVMCompiler& compiler)
@@ -3975,17 +3986,17 @@ void WavelengthNode::compile(OSLCompiler& compiler)
BlackbodyNode::BlackbodyNode()
: ShaderNode("blackbody")
{
- add_input("Temperature", SHADER_SOCKET_FLOAT, 1200.0f);
- add_output("Color", SHADER_SOCKET_COLOR);
+ add_input("Temperature", SocketType::FLOAT, 1200.0f);
+ add_output("Color", SocketType::COLOR);
}
-bool BlackbodyNode::constant_fold(ShaderGraph * /*graph*/, ShaderOutput *socket, float3 *optimized_value)
+bool BlackbodyNode::constant_fold(ShaderGraph *, ShaderOutput *socket, ShaderInput *optimized)
{
ShaderInput *temperature_in = input("Temperature");
if(socket == output("Color")) {
if(temperature_in->link == NULL) {
- *optimized_value = svm_math_blackbody_color(temperature_in->value.x);
+ optimized->set(svm_math_blackbody_color(temperature_in->value_float()));
return true;
}
}
@@ -4015,10 +4026,10 @@ OutputNode::OutputNode()
{
special_type = SHADER_SPECIAL_TYPE_OUTPUT;
- add_input("Surface", SHADER_SOCKET_CLOSURE);
- add_input("Volume", SHADER_SOCKET_CLOSURE);
- add_input("Displacement", SHADER_SOCKET_FLOAT);
- add_input("Normal", SHADER_SOCKET_NORMAL);
+ add_input("Surface", SocketType::CLOSURE);
+ add_input("Volume", SocketType::CLOSURE);
+ add_input("Displacement", SocketType::FLOAT);
+ add_input("Normal", SocketType::NORMAL);
}
void OutputNode::compile(SVMCompiler& compiler)
@@ -4047,18 +4058,18 @@ void OutputNode::compile(OSLCompiler& compiler)
MathNode::MathNode()
: ShaderNode("math")
{
- type = ustring("Add");
+ type = NODE_MATH_ADD;
use_clamp = false;
- add_input("Value1", SHADER_SOCKET_FLOAT);
- add_input("Value2", SHADER_SOCKET_FLOAT);
- add_output("Value", SHADER_SOCKET_FLOAT);
+ add_input("Value1", SocketType::FLOAT);
+ add_input("Value2", SocketType::FLOAT);
+ add_output("Value", SocketType::FLOAT);
}
-static ShaderEnum math_type_init()
+static NodeEnum math_type_init()
{
- ShaderEnum enm;
+ NodeEnum enm;
enm.insert("Add", NODE_MATH_ADD);
enm.insert("Subtract", NODE_MATH_SUBTRACT);
@@ -4083,23 +4094,25 @@ static ShaderEnum math_type_init()
return enm;
}
-ShaderEnum MathNode::type_enum = math_type_init();
+NodeEnum MathNode::type_enum = math_type_init();
-bool MathNode::constant_fold(ShaderGraph * /*graph*/, ShaderOutput *socket, float3 *optimized_value)
+bool MathNode::constant_fold(ShaderGraph *, ShaderOutput *socket, ShaderInput *optimized)
{
ShaderInput *value1_in = input("Value1");
ShaderInput *value2_in = input("Value2");
if(socket == output("Value")) {
if(value1_in->link == NULL && value2_in->link == NULL) {
- optimized_value->x = svm_math((NodeMath)type_enum[type],
- value1_in->value.x,
- value2_in->value.x);
+ float value = svm_math(type,
+ value1_in->value_float(),
+ value2_in->value_float());
if(use_clamp) {
- optimized_value->x = saturate(optimized_value->x);
+ value = saturate(value);
}
+ optimized->set(value);
+
return true;
}
}
@@ -4113,10 +4126,7 @@ void MathNode::compile(SVMCompiler& compiler)
ShaderInput *value2_in = input("Value2");
ShaderOutput *value_out = output("Value");
- compiler.add_node(NODE_MATH,
- type_enum[type],
- compiler.stack_assign(value1_in),
- compiler.stack_assign(value2_in));
+ compiler.add_node(NODE_MATH, type, compiler.stack_assign(value1_in), compiler.stack_assign(value2_in));
compiler.add_node(NODE_MATH, compiler.stack_assign(value_out));
if(use_clamp) {
@@ -4127,8 +4137,8 @@ void MathNode::compile(SVMCompiler& compiler)
void MathNode::compile(OSLCompiler& compiler)
{
- compiler.parameter("type", type);
- compiler.parameter("Clamp", use_clamp);
+ compiler.parameter("type", type_enum[type]);
+ compiler.parameter("use_clamp", use_clamp);
compiler.add(this, "node_math");
}
@@ -4137,17 +4147,17 @@ void MathNode::compile(OSLCompiler& compiler)
VectorMathNode::VectorMathNode()
: ShaderNode("vector_math")
{
- type = ustring("Add");
+ type = NODE_VECTOR_MATH_ADD;
- add_input("Vector1", SHADER_SOCKET_VECTOR);
- add_input("Vector2", SHADER_SOCKET_VECTOR);
- add_output("Value", SHADER_SOCKET_FLOAT);
- add_output("Vector", SHADER_SOCKET_VECTOR);
+ add_input("Vector1", SocketType::VECTOR);
+ add_input("Vector2", SocketType::VECTOR);
+ add_output("Value", SocketType::FLOAT);
+ add_output("Vector", SocketType::VECTOR);
}
-static ShaderEnum vector_math_type_init()
+static NodeEnum vector_math_type_init()
{
- ShaderEnum enm;
+ NodeEnum enm;
enm.insert("Add", NODE_VECTOR_MATH_ADD);
enm.insert("Subtract", NODE_VECTOR_MATH_SUBTRACT);
@@ -4159,9 +4169,9 @@ static ShaderEnum vector_math_type_init()
return enm;
}
-ShaderEnum VectorMathNode::type_enum = vector_math_type_init();
+NodeEnum VectorMathNode::type_enum = vector_math_type_init();
-bool VectorMathNode::constant_fold(ShaderGraph * /*graph*/, ShaderOutput *socket, float3 *optimized_value)
+bool VectorMathNode::constant_fold(ShaderGraph *, ShaderOutput *socket, ShaderInput *optimized)
{
ShaderInput *vector1_in = input("Vector1");
ShaderInput *vector2_in = input("Vector2");
@@ -4172,16 +4182,16 @@ bool VectorMathNode::constant_fold(ShaderGraph * /*graph*/, ShaderOutput *socket
if(vector1_in->link == NULL && vector2_in->link == NULL) {
svm_vector_math(&value,
&vector,
- (NodeVectorMath)type_enum[type],
- vector1_in->value,
- vector2_in->value);
+ type,
+ vector1_in->value(),
+ vector2_in->value());
if(socket == output("Value")) {
- optimized_value->x = value;
+ optimized->set(value);
return true;
}
else if(socket == output("Vector")) {
- *optimized_value = vector;
+ optimized->set(vector);
return true;
}
}
@@ -4197,7 +4207,7 @@ void VectorMathNode::compile(SVMCompiler& compiler)
ShaderOutput *vector_out = output("Vector");
compiler.add_node(NODE_VECTOR_MATH,
- type_enum[type],
+ type,
compiler.stack_assign(vector1_in),
compiler.stack_assign(vector2_in));
compiler.add_node(NODE_VECTOR_MATH,
@@ -4207,7 +4217,7 @@ void VectorMathNode::compile(SVMCompiler& compiler)
void VectorMathNode::compile(OSLCompiler& compiler)
{
- compiler.parameter("type", type);
+ compiler.parameter("type", type_enum[type]);
compiler.add(this, "node_vector_math");
}
@@ -4216,17 +4226,17 @@ void VectorMathNode::compile(OSLCompiler& compiler)
VectorTransformNode::VectorTransformNode()
: ShaderNode("vector_transform")
{
- type = ustring("Vector");
- convert_from = ustring("world");
- convert_to = ustring("object");
+ type = NODE_VECTOR_TRANSFORM_TYPE_VECTOR;
+ convert_from = NODE_VECTOR_TRANSFORM_CONVERT_SPACE_WORLD;
+ convert_to = NODE_VECTOR_TRANSFORM_CONVERT_SPACE_OBJECT;
- add_input("Vector", SHADER_SOCKET_VECTOR);
- add_output("Vector", SHADER_SOCKET_VECTOR);
+ add_input("Vector", SocketType::VECTOR);
+ add_output("Vector", SocketType::VECTOR);
}
-static ShaderEnum vector_transform_type_init()
+static NodeEnum vector_transform_type_init()
{
- ShaderEnum enm;
+ NodeEnum enm;
enm.insert("Vector", NODE_VECTOR_TRANSFORM_TYPE_VECTOR);
enm.insert("Point", NODE_VECTOR_TRANSFORM_TYPE_POINT);
@@ -4235,9 +4245,9 @@ static ShaderEnum vector_transform_type_init()
return enm;
}
-static ShaderEnum vector_transform_convert_space_init()
+static NodeEnum vector_transform_convert_space_init()
{
- ShaderEnum enm;
+ NodeEnum enm;
enm.insert("world", NODE_VECTOR_TRANSFORM_CONVERT_SPACE_WORLD);
enm.insert("object", NODE_VECTOR_TRANSFORM_CONVERT_SPACE_OBJECT);
@@ -4246,8 +4256,8 @@ static ShaderEnum vector_transform_convert_space_init()
return enm;
}
-ShaderEnum VectorTransformNode::type_enum = vector_transform_type_init();
-ShaderEnum VectorTransformNode::convert_space_enum = vector_transform_convert_space_init();
+NodeEnum VectorTransformNode::type_enum = vector_transform_type_init();
+NodeEnum VectorTransformNode::convert_space_enum = vector_transform_convert_space_init();
void VectorTransformNode::compile(SVMCompiler& compiler)
{
@@ -4255,18 +4265,16 @@ void VectorTransformNode::compile(SVMCompiler& compiler)
ShaderOutput *vector_out = output("Vector");
compiler.add_node(NODE_VECTOR_TRANSFORM,
- compiler.encode_uchar4(type_enum[type],
- convert_space_enum[convert_from],
- convert_space_enum[convert_to]),
+ compiler.encode_uchar4(type, convert_from, convert_to),
compiler.encode_uchar4(compiler.stack_assign(vector_in),
compiler.stack_assign(vector_out)));
}
void VectorTransformNode::compile(OSLCompiler& compiler)
{
- compiler.parameter("type", type);
- compiler.parameter("convert_from", convert_from);
- compiler.parameter("convert_to", convert_to);
+ compiler.parameter("type", type_enum[type]);
+ compiler.parameter("convert_from", convert_space_enum[convert_from]);
+ compiler.parameter("convert_to", convert_space_enum[convert_to]);
compiler.add(this, "node_vector_transform");
}
@@ -4281,16 +4289,16 @@ BumpNode::BumpNode()
/* this input is used by the user, but after graph transform it is no longer
* used and moved to sampler center/x/y instead */
- add_input("Height", SHADER_SOCKET_FLOAT);
+ add_input("Height", SocketType::FLOAT);
- add_input("SampleCenter", SHADER_SOCKET_FLOAT);
- add_input("SampleX", SHADER_SOCKET_FLOAT);
- add_input("SampleY", SHADER_SOCKET_FLOAT);
- add_input("Normal", SHADER_SOCKET_NORMAL, ShaderInput::NORMAL);
- add_input("Strength", SHADER_SOCKET_FLOAT, 1.0f);
- add_input("Distance", SHADER_SOCKET_FLOAT, 0.1f);
+ add_input("SampleCenter", SocketType::FLOAT);
+ add_input("SampleX", SocketType::FLOAT);
+ add_input("SampleY", SocketType::FLOAT);
+ add_input("Normal", SocketType::NORMAL, make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_NORMAL);
+ add_input("Strength", SocketType::FLOAT, 1.0f);
+ add_input("Distance", SocketType::FLOAT, 0.1f);
- add_output("Normal", SHADER_SOCKET_NORMAL);
+ add_output("Normal", SocketType::NORMAL);
}
void BumpNode::compile(SVMCompiler& compiler)
@@ -4323,9 +4331,7 @@ void BumpNode::compile(OSLCompiler& compiler)
compiler.add(this, "node_bump");
}
-bool BumpNode::constant_fold(ShaderGraph *graph,
- ShaderOutput * /*socket*/,
- float3 * /*optimized_value*/)
+bool BumpNode::constant_fold(ShaderGraph *graph, ShaderOutput *, ShaderInput *)
{
ShaderInput *height_in = input("Height");
ShaderInput *normal_in = input("Normal");
@@ -4352,9 +4358,9 @@ bool BumpNode::constant_fold(ShaderGraph *graph,
RGBCurvesNode::RGBCurvesNode()
: ShaderNode("rgb_curves")
{
- add_input("Fac", SHADER_SOCKET_FLOAT);
- add_input("Color", SHADER_SOCKET_COLOR);
- add_output("Color", SHADER_SOCKET_COLOR);
+ add_input("Fac", SocketType::FLOAT);
+ add_input("Color", SocketType::COLOR);
+ add_output("Color", SocketType::COLOR);
min_x = 0.0f;
max_x = 1.0f;
@@ -4397,9 +4403,9 @@ void RGBCurvesNode::compile(OSLCompiler& compiler)
VectorCurvesNode::VectorCurvesNode()
: ShaderNode("vector_curves")
{
- add_input("Fac", SHADER_SOCKET_FLOAT);
- add_input("Vector", SHADER_SOCKET_VECTOR);
- add_output("Vector", SHADER_SOCKET_VECTOR);
+ add_input("Fac", SocketType::FLOAT);
+ add_input("Vector", SocketType::VECTOR);
+ add_output("Vector", SocketType::VECTOR);
min_x = 0.0f;
max_x = 1.0f;
@@ -4442,9 +4448,9 @@ void VectorCurvesNode::compile(OSLCompiler& compiler)
RGBRampNode::RGBRampNode()
: ShaderNode("rgb_ramp")
{
- add_input("Fac", SHADER_SOCKET_FLOAT);
- add_output("Color", SHADER_SOCKET_COLOR);
- add_output("Alpha", SHADER_SOCKET_FLOAT);
+ add_input("Fac", SocketType::FLOAT);
+ add_output("Color", SocketType::COLOR);
+ add_output("Alpha", SocketType::FLOAT);
interpolate = true;
}
@@ -4477,7 +4483,7 @@ void RGBRampNode::compile(OSLCompiler& compiler)
compiler.parameter_color_array("ramp_color", ramp);
compiler.parameter_array("ramp_alpha", ramp_alpha.data(), ramp_alpha.size());
- compiler.parameter("ramp_interpolate", interpolate);
+ compiler.parameter("interpolate", interpolate);
compiler.add(this, "node_rgb_ramp");
}
@@ -4487,8 +4493,8 @@ void RGBRampNode::compile(OSLCompiler& compiler)
SetNormalNode::SetNormalNode()
: ShaderNode("set_normal")
{
- add_input("Direction", SHADER_SOCKET_VECTOR);
- add_output("Normal", SHADER_SOCKET_NORMAL);
+ add_input("Direction", SocketType::VECTOR);
+ add_output("Normal", SocketType::NORMAL);
}
void SetNormalNode::compile(SVMCompiler& compiler)
@@ -4506,20 +4512,29 @@ void SetNormalNode::compile(OSLCompiler& compiler)
compiler.add(this, "node_set_normal");
}
-/* OSLScriptNode */
+/* OSLNode */
-OSLScriptNode::OSLScriptNode()
-: ShaderNode("osl_script")
+OSLNode::OSLNode()
+: ShaderNode("osl_shader")
{
special_type = SHADER_SPECIAL_TYPE_SCRIPT;
}
-void OSLScriptNode::compile(SVMCompiler& /*compiler*/)
+OSLNode::~OSLNode()
+{
+}
+
+OSLNode* OSLNode::create(size_t)
+{
+ return new OSLNode();
+}
+
+void OSLNode::compile(SVMCompiler&)
{
/* doesn't work for SVM, obviously ... */
}
-void OSLScriptNode::compile(OSLCompiler& compiler)
+void OSLNode::compile(OSLCompiler& compiler)
{
if(!filepath.empty())
compiler.add(this, filepath.c_str(), true);
@@ -4529,9 +4544,9 @@ void OSLScriptNode::compile(OSLCompiler& compiler)
/* Normal Map */
-static ShaderEnum normal_map_space_init()
+static NodeEnum normal_map_space_init()
{
- ShaderEnum enm;
+ NodeEnum enm;
enm.insert("Tangent", NODE_NORMAL_MAP_TANGENT);
enm.insert("Object", NODE_NORMAL_MAP_OBJECT);
@@ -4542,24 +4557,24 @@ static ShaderEnum normal_map_space_init()
return enm;
}
-ShaderEnum NormalMapNode::space_enum = normal_map_space_init();
+NodeEnum NormalMapNode::space_enum = normal_map_space_init();
NormalMapNode::NormalMapNode()
: ShaderNode("normal_map")
{
- space = ustring("Tangent");
+ space = NODE_NORMAL_MAP_TANGENT;
attribute = ustring("");
- add_input("NormalIn", SHADER_SOCKET_NORMAL, ShaderInput::NORMAL, ShaderInput::USE_OSL);
- add_input("Strength", SHADER_SOCKET_FLOAT, 1.0f);
- add_input("Color", SHADER_SOCKET_COLOR);
+ add_input("NormalIn", SocketType::NORMAL, make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_NORMAL | SocketType::OSL_INTERNAL);
+ add_input("Strength", SocketType::FLOAT, 1.0f);
+ add_input("Color", SocketType::COLOR);
- add_output("Normal", SHADER_SOCKET_NORMAL);
+ add_output("Normal", SocketType::NORMAL);
}
void NormalMapNode::attributes(Shader *shader, AttributeRequestSet *attributes)
{
- if(shader->has_surface && space == ustring("Tangent")) {
+ if(shader->has_surface && space == NODE_NORMAL_MAP_TANGENT) {
if(attribute == ustring("")) {
attributes->add(ATTR_STD_UV_TANGENT);
attributes->add(ATTR_STD_UV_TANGENT_SIGN);
@@ -4582,7 +4597,7 @@ void NormalMapNode::compile(SVMCompiler& compiler)
ShaderOutput *normal_out = output("Normal");
int attr = 0, attr_sign = 0;
- if(space == ustring("Tangent")) {
+ if(space == NODE_NORMAL_MAP_TANGENT) {
if(attribute == ustring("")) {
attr = compiler.attribute(ATTR_STD_UV_TANGENT);
attr_sign = compiler.attribute(ATTR_STD_UV_TANGENT_SIGN);
@@ -4598,13 +4613,13 @@ void NormalMapNode::compile(SVMCompiler& compiler)
compiler.stack_assign(color_in),
compiler.stack_assign(strength_in),
compiler.stack_assign(normal_out),
- space_enum[space]),
+ space),
attr, attr_sign);
}
void NormalMapNode::compile(OSLCompiler& compiler)
{
- if(space == ustring("Tangent")) {
+ if(space == NODE_NORMAL_MAP_TANGENT) {
if(attribute == ustring("")) {
compiler.parameter("attr_name", ustring("geom:tangent"));
compiler.parameter("attr_sign_name", ustring("geom:tangent_sign"));
@@ -4615,16 +4630,16 @@ void NormalMapNode::compile(OSLCompiler& compiler)
}
}
- compiler.parameter("space", space);
+ compiler.parameter("space", space_enum[space]);
compiler.add(this, "node_normal_map");
}
/* Tangent */
-static ShaderEnum tangent_direction_type_init()
+static NodeEnum tangent_direction_type_init()
{
- ShaderEnum enm;
+ NodeEnum enm;
enm.insert("Radial", NODE_TANGENT_RADIAL);
enm.insert("UV Map", NODE_TANGENT_UVMAP);
@@ -4632,9 +4647,9 @@ static ShaderEnum tangent_direction_type_init()
return enm;
}
-static ShaderEnum tangent_axis_init()
+static NodeEnum tangent_axis_init()
{
- ShaderEnum enm;
+ NodeEnum enm;
enm.insert("X", NODE_TANGENT_AXIS_X);
enm.insert("Y", NODE_TANGENT_AXIS_Y);
@@ -4643,24 +4658,24 @@ static ShaderEnum tangent_axis_init()
return enm;
}
-ShaderEnum TangentNode::direction_type_enum = tangent_direction_type_init();
-ShaderEnum TangentNode::axis_enum = tangent_axis_init();
+NodeEnum TangentNode::direction_type_enum = tangent_direction_type_init();
+NodeEnum TangentNode::axis_enum = tangent_axis_init();
TangentNode::TangentNode()
: ShaderNode("tangent")
{
- direction_type = ustring("Radial");
- axis = ustring("X");
+ direction_type = NODE_TANGENT_RADIAL;
+ axis = NODE_TANGENT_AXIS_X;
attribute = ustring("");
- add_input("NormalIn", SHADER_SOCKET_NORMAL, ShaderInput::NORMAL, ShaderInput::USE_OSL);
- add_output("Tangent", SHADER_SOCKET_NORMAL);
+ add_input("NormalIn", SocketType::NORMAL, make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_NORMAL | SocketType::OSL_INTERNAL);
+ add_output("Tangent", SocketType::NORMAL);
}
void TangentNode::attributes(Shader *shader, AttributeRequestSet *attributes)
{
if(shader->has_surface) {
- if(direction_type == ustring("UV Map")) {
+ if(direction_type == NODE_TANGENT_UVMAP) {
if(attribute == ustring(""))
attributes->add(ATTR_STD_UV_TANGENT);
else
@@ -4678,7 +4693,7 @@ void TangentNode::compile(SVMCompiler& compiler)
ShaderOutput *tangent_out = output("Tangent");
int attr;
- if(direction_type == ustring("UV Map")) {
+ if(direction_type == NODE_TANGENT_UVMAP) {
if(attribute == ustring(""))
attr = compiler.attribute(ATTR_STD_UV_TANGENT);
else
@@ -4690,21 +4705,21 @@ void TangentNode::compile(SVMCompiler& compiler)
compiler.add_node(NODE_TANGENT,
compiler.encode_uchar4(
compiler.stack_assign(tangent_out),
- direction_type_enum[direction_type],
- axis_enum[axis]), attr);
+ direction_type,
+ axis), attr);
}
void TangentNode::compile(OSLCompiler& compiler)
{
- if(direction_type == ustring("UV Map")) {
+ if(direction_type == NODE_TANGENT_UVMAP) {
if(attribute == ustring(""))
compiler.parameter("attr_name", ustring("geom:tangent"));
else
compiler.parameter("attr_name", ustring((string(attribute.c_str()) + ".tangent").c_str()));
}
- compiler.parameter("direction_type", direction_type);
- compiler.parameter("axis", axis);
+ compiler.parameter("direction_type", direction_type_enum[direction_type]);
+ compiler.parameter("axis", axis_enum[axis]);
compiler.add(this, "node_tangent");
}
diff --git a/intern/cycles/render/nodes.h b/intern/cycles/render/nodes.h
index 40fda070ec4..8b17e455f7a 100644
--- a/intern/cycles/render/nodes.h
+++ b/intern/cycles/render/nodes.h
@@ -49,15 +49,15 @@ public:
enum Type { POINT = 0, TEXTURE = 1, VECTOR = 2, NORMAL = 3 };
Type type;
- static ShaderEnum type_enum;
+ static NodeEnum type_enum;
enum Mapping { NONE = 0, X = 1, Y = 2, Z = 3 };
Mapping x_mapping, y_mapping, z_mapping;
- static ShaderEnum mapping_enum;
+ static NodeEnum mapping_enum;
enum Projection { FLAT, CUBE, TUBE, SPHERE };
Projection projection;
- static ShaderEnum projection_enum;
+ static NodeEnum projection_enum;
bool equals(const TextureMapping& other) {
return translation == other.translation &&
@@ -109,15 +109,15 @@ public:
bool use_alpha;
string filename;
void *builtin_data;
- ustring color_space;
- ustring projection;
+ NodeImageColorSpace color_space;
+ NodeImageProjection projection;
InterpolationType interpolation;
ExtensionType extension;
float projection_blend;
bool animated;
- static ShaderEnum color_space_enum;
- static ShaderEnum projection_enum;
+ static NodeEnum color_space_enum;
+ static NodeEnum projection_enum;
virtual bool equals(const ShaderNode *other) {
const ImageTextureNode *image_node = (const ImageTextureNode*)other;
@@ -148,13 +148,13 @@ public:
bool use_alpha;
string filename;
void *builtin_data;
- ustring color_space;
- ustring projection;
+ NodeImageColorSpace color_space;
+ NodeEnvironmentProjection projection;
InterpolationType interpolation;
bool animated;
- static ShaderEnum color_space_enum;
- static ShaderEnum projection_enum;
+ static NodeEnum color_space_enum;
+ static NodeEnum projection_enum;
virtual bool equals(const ShaderNode *other) {
const EnvironmentTextureNode *env_node = (const EnvironmentTextureNode*)other;
@@ -175,12 +175,12 @@ public:
virtual int get_group() { return NODE_GROUP_LEVEL_2; }
+ NodeSkyType type;
float3 sun_direction;
float turbidity;
float ground_albedo;
- ustring type;
- static ShaderEnum type_enum;
+ static NodeEnum type_enum;
virtual bool equals(const ShaderNode *other) {
const SkyTextureNode *sky_node = (const SkyTextureNode*)other;
@@ -206,8 +206,8 @@ public:
virtual int get_group() { return NODE_GROUP_LEVEL_2; }
- ustring type;
- static ShaderEnum type_enum;
+ NodeGradientType type;
+ static NodeEnum type_enum;
virtual bool equals(const ShaderNode *other) {
const GradientTextureNode *gradient_node = (const GradientTextureNode*)other;
@@ -227,9 +227,8 @@ public:
virtual int get_group() { return NODE_GROUP_LEVEL_2; }
- ustring coloring;
-
- static ShaderEnum coloring_enum;
+ NodeVoronoiColoring coloring;
+ static NodeEnum coloring_enum;
virtual bool equals(const ShaderNode *other) {
const VoronoiTextureNode *voronoi_node = (const VoronoiTextureNode*)other;
@@ -244,9 +243,8 @@ public:
virtual int get_group() { return NODE_GROUP_LEVEL_2; }
- ustring type;
-
- static ShaderEnum type_enum;
+ NodeMusgraveType type;
+ static NodeEnum type_enum;
virtual bool equals(const ShaderNode *other) {
const MusgraveTextureNode *musgrave_node = (const MusgraveTextureNode*)other;
@@ -261,10 +259,10 @@ public:
virtual int get_group() { return NODE_GROUP_LEVEL_2; }
- ustring type;
- ustring profile;
- static ShaderEnum type_enum;
- static ShaderEnum profile_enum;
+ NodeWaveType type;
+ NodeWaveProfile profile;
+ static NodeEnum type_enum;
+ static NodeEnum profile_enum;
virtual bool equals(const ShaderNode *other) {
const WaveTextureNode *wave_node = (const WaveTextureNode*)other;
@@ -329,13 +327,13 @@ public:
ImageManager *image_manager;
int slot;
string filename;
- ustring space;
+ NodeTexVoxelSpace space;
void *builtin_data;
InterpolationType interpolation;
Transform tfm;
- static ShaderEnum space_enum;
+ static NodeEnum space_enum;
virtual bool equals(const ShaderNode *other) {
const PointDensityTextureNode *point_dendity_node = (const PointDensityTextureNode*)other;
@@ -362,14 +360,21 @@ public:
}
};
+class RGBToBWNode : public ShaderNode {
+public:
+ SHADER_NODE_CLASS(RGBToBWNode)
+
+ bool constant_fold(ShaderGraph *graph, ShaderOutput *socket, ShaderInput *optimized);
+};
+
class ConvertNode : public ShaderNode {
public:
- ConvertNode(ShaderSocketType from, ShaderSocketType to, bool autoconvert = false);
+ ConvertNode(SocketType::Type from, SocketType::Type to, bool autoconvert = false);
SHADER_NODE_BASE_CLASS(ConvertNode)
- bool constant_fold(ShaderGraph *graph, ShaderOutput *socket, float3 *optimized_value);
+ bool constant_fold(ShaderGraph *graph, ShaderOutput *socket, ShaderInput *optimized);
- ShaderSocketType from, to;
+ SocketType::Type from, to;
virtual bool equals(const ShaderNode *other)
{
@@ -387,6 +392,7 @@ public:
bool has_spatial_varying() { return true; }
void compile(SVMCompiler& compiler, ShaderInput *param1, ShaderInput *param2, ShaderInput *param3 = NULL, ShaderInput *param4 = NULL);
+ virtual ClosureType get_closure_type() { return closure; }
ClosureType closure;
bool scattering;
@@ -402,8 +408,8 @@ class AnisotropicBsdfNode : public BsdfNode {
public:
SHADER_NODE_CLASS(AnisotropicBsdfNode)
- ustring distribution;
- static ShaderEnum distribution_enum;
+ ClosureType distribution;
+ static NodeEnum distribution_enum;
void attributes(Shader *shader, AttributeRequestSet *attributes);
};
@@ -437,8 +443,8 @@ public:
void simplify_settings(Scene *scene);
bool has_integrator_dependency();
- ustring distribution, distribution_orig;
- static ShaderEnum distribution_enum;
+ ClosureType distribution, distribution_orig;
+ static NodeEnum distribution_enum;
};
class GlassBsdfNode : public BsdfNode {
@@ -448,8 +454,8 @@ public:
void simplify_settings(Scene *scene);
bool has_integrator_dependency();
- ustring distribution, distribution_orig;
- static ShaderEnum distribution_enum;
+ ClosureType distribution, distribution_orig;
+ static NodeEnum distribution_enum;
};
class RefractionBsdfNode : public BsdfNode {
@@ -459,16 +465,16 @@ public:
void simplify_settings(Scene *scene);
bool has_integrator_dependency();
- ustring distribution, distribution_orig;
- static ShaderEnum distribution_enum;
+ ClosureType distribution, distribution_orig;
+ static NodeEnum distribution_enum;
};
class ToonBsdfNode : public BsdfNode {
public:
SHADER_NODE_CLASS(ToonBsdfNode)
- ustring component;
- static ShaderEnum component_enum;
+ ClosureType component;
+ static NodeEnum component_enum;
};
class SubsurfaceScatteringNode : public BsdfNode {
@@ -477,13 +483,15 @@ public:
bool has_surface_bssrdf() { return true; }
bool has_bssrdf_bump();
- static ShaderEnum falloff_enum;
+ ClosureType falloff;
+ static NodeEnum falloff_enum;
};
class EmissionNode : public ShaderNode {
public:
SHADER_NODE_CLASS(EmissionNode)
- bool constant_fold(ShaderGraph *graph, ShaderOutput *socket, float3 *optimized_value);
+ bool constant_fold(ShaderGraph *graph, ShaderOutput *socket, ShaderInput *optimized);
+ virtual ClosureType get_closure_type() { return CLOSURE_EMISSION_ID; }
bool has_surface_emission() { return true; }
};
@@ -491,13 +499,15 @@ public:
class BackgroundNode : public ShaderNode {
public:
SHADER_NODE_CLASS(BackgroundNode)
- bool constant_fold(ShaderGraph *graph, ShaderOutput *socket, float3 *optimized_value);
+ bool constant_fold(ShaderGraph *graph, ShaderOutput *socket, ShaderInput *optimized);
+ virtual ClosureType get_closure_type() { return CLOSURE_BACKGROUND_ID; }
};
class HoldoutNode : public ShaderNode {
public:
SHADER_NODE_CLASS(HoldoutNode)
virtual int get_group() { return NODE_GROUP_LEVEL_1; }
+ virtual ClosureType get_closure_type() { return CLOSURE_HOLDOUT_ID; }
};
class AmbientOcclusionNode : public ShaderNode {
@@ -506,6 +516,7 @@ public:
bool has_spatial_varying() { return true; }
virtual int get_group() { return NODE_GROUP_LEVEL_1; }
+ virtual ClosureType get_closure_type() { return CLOSURE_AMBIENT_OCCLUSION_ID; }
};
class VolumeNode : public ShaderNode {
@@ -514,6 +525,10 @@ public:
void compile(SVMCompiler& compiler, ShaderInput *param1, ShaderInput *param2);
virtual int get_group() { return NODE_GROUP_LEVEL_1; }
+ virtual int get_feature() {
+ return ShaderNode::get_feature() | NODE_FEATURE_VOLUME;
+ }
+ virtual ClosureType get_closure_type() { return closure; }
ClosureType closure;
@@ -538,8 +553,8 @@ class HairBsdfNode : public BsdfNode {
public:
SHADER_NODE_CLASS(HairBsdfNode)
- ustring component;
- static ShaderEnum component_enum;
+ ClosureType component;
+ static NodeEnum component_enum;
};
@@ -630,7 +645,7 @@ class ValueNode : public ShaderNode {
public:
SHADER_NODE_CLASS(ValueNode)
- bool constant_fold(ShaderGraph *graph, ShaderOutput *socket, float3 *optimized_value);
+ bool constant_fold(ShaderGraph *graph, ShaderOutput *socket, ShaderInput *optimized);
float value;
@@ -645,7 +660,7 @@ class ColorNode : public ShaderNode {
public:
SHADER_NODE_CLASS(ColorNode)
- bool constant_fold(ShaderGraph *graph, ShaderOutput *socket, float3 *optimized_value);
+ bool constant_fold(ShaderGraph *graph, ShaderOutput *socket, ShaderInput *optimized);
float3 value;
@@ -664,7 +679,7 @@ public:
class MixClosureNode : public ShaderNode {
public:
SHADER_NODE_CLASS(MixClosureNode)
- bool constant_fold(ShaderGraph *graph, ShaderOutput *socket, float3 *optimized_value);
+ bool constant_fold(ShaderGraph *graph, ShaderOutput *socket, ShaderInput *optimized);
};
class MixClosureWeightNode : public ShaderNode {
@@ -682,14 +697,14 @@ public:
class MixNode : public ShaderNode {
public:
SHADER_NODE_CLASS(MixNode)
- bool constant_fold(ShaderGraph *graph, ShaderOutput *socket, float3 *optimized_value);
+ bool constant_fold(ShaderGraph *graph, ShaderOutput *socket, ShaderInput *optimized);
virtual int get_group() { return NODE_GROUP_LEVEL_3; }
bool use_clamp;
- ustring type;
- static ShaderEnum type_enum;
+ NodeMix type;
+ static NodeEnum type_enum;
virtual bool equals(const ShaderNode *other)
{
@@ -725,7 +740,7 @@ class GammaNode : public ShaderNode {
public:
SHADER_NODE_CLASS(GammaNode)
- bool constant_fold(ShaderGraph *graph, ShaderOutput *socket, float3 *optimized_value);
+ bool constant_fold(ShaderGraph *graph, ShaderOutput *socket, ShaderInput *optimized);
virtual int get_group() { return NODE_GROUP_LEVEL_1; }
};
@@ -816,7 +831,7 @@ public:
class BlackbodyNode : public ShaderNode {
public:
SHADER_NODE_CLASS(BlackbodyNode)
- bool constant_fold(ShaderGraph *graph, ShaderOutput *socket, float3 *optimized_value);
+ bool constant_fold(ShaderGraph *graph, ShaderOutput *socket, ShaderInput *optimized);
virtual int get_group() { return NODE_GROUP_LEVEL_3; }
};
@@ -825,12 +840,12 @@ class MathNode : public ShaderNode {
public:
SHADER_NODE_CLASS(MathNode)
virtual int get_group() { return NODE_GROUP_LEVEL_1; }
- bool constant_fold(ShaderGraph *graph, ShaderOutput *socket, float3 *optimized_value);
+ bool constant_fold(ShaderGraph *graph, ShaderOutput *socket, ShaderInput *optimized);
bool use_clamp;
- ustring type;
- static ShaderEnum type_enum;
+ NodeMath type;
+ static NodeEnum type_enum;
virtual bool equals(const ShaderNode *other)
{
@@ -860,14 +875,14 @@ class VectorMathNode : public ShaderNode {
public:
SHADER_NODE_CLASS(VectorMathNode)
virtual int get_group() { return NODE_GROUP_LEVEL_1; }
- bool constant_fold(ShaderGraph *graph, ShaderOutput *socket, float3 *optimized_value);
+ bool constant_fold(ShaderGraph *graph, ShaderOutput *socket, ShaderInput *optimized);
- ustring type;
- static ShaderEnum type_enum;
+ NodeVectorMath type;
+ static NodeEnum type_enum;
virtual bool equals(const ShaderNode *other)
{
- const MathNode *math_node = (const MathNode*)other;
+ const VectorMathNode *math_node = (const VectorMathNode*)other;
return ShaderNode::equals(other) &&
type == math_node->type;
}
@@ -879,12 +894,12 @@ public:
virtual int get_group() { return NODE_GROUP_LEVEL_3; }
- ustring type;
- ustring convert_from;
- ustring convert_to;
+ NodeVectorTransformType type;
+ NodeVectorTransformConvertSpace convert_from;
+ NodeVectorTransformConvertSpace convert_to;
- static ShaderEnum type_enum;
- static ShaderEnum convert_space_enum;
+ static NodeEnum type_enum;
+ static NodeEnum convert_space_enum;
virtual bool equals(const ShaderNode *other) {
const VectorTransformNode *vector_transform_node = (const VectorTransformNode*)other;
@@ -898,7 +913,7 @@ public:
class BumpNode : public ShaderNode {
public:
SHADER_NODE_CLASS(BumpNode)
- bool constant_fold(ShaderGraph *graph, ShaderOutput *socket, float3 *optimized_value);
+ bool constant_fold(ShaderGraph *graph, ShaderOutput *socket, ShaderInput *optimized);
bool has_spatial_varying() { return true; }
virtual int get_feature() {
return NODE_FEATURE_BUMP;
@@ -950,17 +965,22 @@ public:
SHADER_NODE_CLASS(SetNormalNode)
};
-class OSLScriptNode : public ShaderNode {
+class OSLNode : public ShaderNode {
public:
- SHADER_NODE_CLASS(OSLScriptNode)
+ static OSLNode *create(size_t num_inputs);
+ ~OSLNode();
+
+ SHADER_NODE_BASE_CLASS(OSLNode)
/* ideally we could beter detect this, but we can't query this now */
bool has_spatial_varying() { return true; }
+ virtual bool equals(const ShaderNode * /*other*/) { return false; }
string filepath;
string bytecode_hash;
- virtual bool equals(const ShaderNode * /*other*/) { return false; }
+private:
+ OSLNode();
};
class NormalMapNode : public ShaderNode {
@@ -970,8 +990,8 @@ public:
bool has_spatial_varying() { return true; }
virtual int get_group() { return NODE_GROUP_LEVEL_3; }
- ustring space;
- static ShaderEnum space_enum;
+ NodeNormalMapSpace space;
+ static NodeEnum space_enum;
ustring attribute;
@@ -991,11 +1011,10 @@ public:
bool has_spatial_varying() { return true; }
virtual int get_group() { return NODE_GROUP_LEVEL_3; }
- ustring direction_type;
- static ShaderEnum direction_type_enum;
-
- ustring axis;
- static ShaderEnum axis_enum;
+ NodeTangentDirectionType direction_type;
+ NodeTangentAxis axis;
+ static NodeEnum direction_type_enum;
+ static NodeEnum axis_enum;
ustring attribute;
diff --git a/intern/cycles/render/object.cpp b/intern/cycles/render/object.cpp
index e2fe0bd72a1..644e581bf4b 100644
--- a/intern/cycles/render/object.cpp
+++ b/intern/cycles/render/object.cpp
@@ -33,14 +33,25 @@ CCL_NAMESPACE_BEGIN
/* Object */
+NODE_DEFINE(Object)
+{
+ NodeType* type = NodeType::add("object", create);
+
+ SOCKET_NODE(mesh, "Mesh", &Mesh::node_type);
+ SOCKET_TRANSFORM(tfm, "Transform", transform_identity());
+ SOCKET_INT(visibility, "Visibility", ~0);
+ SOCKET_INT(random_id, "Random ID", 0);
+ SOCKET_INT(pass_id, "Pass ID", 0);
+ SOCKET_BOOLEAN(use_holdout, "Use Holdout", false);
+ SOCKET_POINT(dupli_generated, "Dupli Generated", make_float3(0.0f, 0.0f, 0.0f));
+ SOCKET_POINT2(dupli_uv, "Dupli UV", make_float2(0.0f, 0.0f));
+
+ return type;
+}
+
Object::Object()
+: Node(node_type)
{
- name = "";
- mesh = NULL;
- tfm = transform_identity();
- visibility = ~0;
- random_id = 0;
- pass_id = 0;
particle_system = NULL;
particle_index = 0;
bounds = BoundBox::empty;
@@ -48,9 +59,6 @@ Object::Object()
motion.mid = transform_identity();
motion.post = transform_identity();
use_motion = false;
- use_holdout = false;
- dupli_generated = make_float3(0.0f, 0.0f, 0.0f);
- dupli_uv = make_float2(0.0f, 0.0f);
}
Object::~Object()
@@ -137,12 +145,12 @@ void Object::apply_transform(bool apply_to_motion)
/* apply transform to curve keys */
for(size_t i = 0; i < mesh->curve_keys.size(); i++) {
- float3 co = transform_point(&tfm, float4_to_float3(mesh->curve_keys[i]));
- float radius = mesh->curve_keys[i].w * scalar;
+ float3 co = transform_point(&tfm, mesh->curve_keys[i]);
+ float radius = mesh->curve_radius[i] * scalar;
/* scale for curve radius is only correct for uniform scale */
- mesh->curve_keys[i] = float3_to_float4(co);
- mesh->curve_keys[i].w = radius;
+ mesh->curve_keys[i] = co;
+ mesh->curve_radius[i] = radius;
}
if(apply_to_motion) {
@@ -217,6 +225,16 @@ vector<float> Object::motion_times()
return times;
}
+bool Object::is_traceable()
+{
+ /* Mesh itself can be empty,can skip all such objects. */
+ if (bounds.size() == make_float3(0.0f, 0.0f, 0.0f)) {
+ return false;
+ }
+ /* TODO(sergey): Check for mesh vertices/curves. visibility flags. */
+ return true;
+}
+
/* Object Manager */
ObjectManager::ObjectManager()
@@ -269,7 +287,9 @@ void ObjectManager::device_update_object_transform(UpdateObejctTransformState *s
state->surface_area_lock.unlock();
if(it == state->surface_area_map.end()) {
- foreach(Mesh::Triangle& t, mesh->triangles) {
+ size_t num_triangles = mesh->num_triangles();
+ for(size_t j = 0; j < num_triangles; j++) {
+ Mesh::Triangle t = mesh->get_triangle(j);
float3 p1 = mesh->verts[t.v[0]];
float3 p2 = mesh->verts[t.v[1]];
float3 p3 = mesh->verts[t.v[2]];
@@ -288,7 +308,9 @@ void ObjectManager::device_update_object_transform(UpdateObejctTransformState *s
surface_area *= uniform_scale;
}
else {
- foreach(Mesh::Triangle& t, mesh->triangles) {
+ size_t num_triangles = mesh->num_triangles();
+ for(size_t j = 0; j < num_triangles; j++) {
+ Mesh::Triangle t = mesh->get_triangle(j);
float3 p1 = transform_point(&tfm, mesh->verts[t.v[0]]);
float3 p2 = transform_point(&tfm, mesh->verts[t.v[1]]);
float3 p3 = transform_point(&tfm, mesh->verts[t.v[2]]);
@@ -360,7 +382,7 @@ void ObjectManager::device_update_object_transform(UpdateObejctTransformState *s
state->object_flag[object_index] = flag;
/* Have curves. */
- if(mesh->curves.size()) {
+ if(mesh->num_curves()) {
state->have_curves = true;
}
}
diff --git a/intern/cycles/render/object.h b/intern/cycles/render/object.h
index c2a79ca8dc4..7ab73f3c91a 100644
--- a/intern/cycles/render/object.h
+++ b/intern/cycles/render/object.h
@@ -17,6 +17,7 @@
#ifndef __OBJECT_H__
#define __OBJECT_H__
+#include "node.h"
#include "scene.h"
#include "util_boundbox.h"
@@ -37,12 +38,13 @@ struct Transform;
/* Object */
-class Object {
+class Object : public Node {
public:
+ NODE_DECLARE;
+
Mesh *mesh;
Transform tfm;
BoundBox bounds;
- ustring name;
uint random_id;
int pass_id;
vector<ParamValue> attributes;
@@ -66,6 +68,11 @@ public:
void apply_transform(bool apply_to_motion);
vector<float> motion_times();
+
+ /* Check whether object is traceable and it worth adding it to
+ * kernel scene.
+ */
+ bool is_traceable();
};
/* Object Manager */
diff --git a/intern/cycles/render/osl.cpp b/intern/cycles/render/osl.cpp
index 3d14965b4ca..1cfe3fb38e2 100644
--- a/intern/cycles/render/osl.cpp
+++ b/intern/cycles/render/osl.cpp
@@ -394,16 +394,143 @@ const char *OSLShaderManager::shader_load_bytecode(const string& hash, const str
{
ss->LoadMemoryCompiledShader(hash.c_str(), bytecode.c_str());
- /* this is a bit weak, but works */
OSLShaderInfo info;
+
+ if(!info.query.open_bytecode(bytecode)) {
+ fprintf(stderr, "OSL query error: %s\n", info.query.geterror().c_str());
+ }
+
+ /* this is a bit weak, but works */
info.has_surface_emission = (bytecode.find("\"emission\"") != string::npos);
info.has_surface_transparent = (bytecode.find("\"transparent\"") != string::npos);
info.has_surface_bssrdf = (bytecode.find("\"bssrdf\"") != string::npos);
+
loaded_shaders[hash] = info;
return loaded_shaders.find(hash)->first.c_str();
}
+OSLNode *OSLShaderManager::osl_node(const std::string& filepath,
+ const std::string& bytecode_hash,
+ const std::string& bytecode)
+{
+ /* create query */
+ const char *hash;
+
+ if(!filepath.empty()) {
+ hash = shader_load_filepath(filepath);
+ }
+ else {
+ hash = shader_test_loaded(bytecode_hash);
+ if(!hash)
+ hash = shader_load_bytecode(bytecode_hash, bytecode);
+ }
+
+ if(!hash) {
+ return NULL;
+ }
+
+ OSLShaderInfo *info = shader_loaded_info(hash);
+
+ /* count number of inputs */
+ size_t num_inputs = 0;
+
+ for(int i = 0; i < info->query.nparams(); i++) {
+ const OSL::OSLQuery::Parameter *param = info->query.getparam(i);
+
+ /* skip unsupported types */
+ if(param->varlenarray || param->isstruct || param->type.arraylen > 1)
+ continue;
+
+ if(!param->isoutput)
+ num_inputs++;
+ }
+
+ /* create node */
+ OSLNode *node = OSLNode::create(num_inputs);
+
+ /* add new sockets from parameters */
+ set<void*> used_sockets;
+
+ for(int i = 0; i < info->query.nparams(); i++) {
+ const OSL::OSLQuery::Parameter *param = info->query.getparam(i);
+
+ /* skip unsupported types */
+ if(param->varlenarray || param->isstruct || param->type.arraylen > 1)
+ continue;
+
+ SocketType::Type socket_type;
+
+ if(param->isclosure) {
+ socket_type = SocketType::CLOSURE;
+ }
+ else if(param->type.vecsemantics != TypeDesc::NOSEMANTICS) {
+ if(param->type.vecsemantics == TypeDesc::COLOR)
+ socket_type = SocketType::COLOR;
+ else if(param->type.vecsemantics == TypeDesc::POINT)
+ socket_type = SocketType::POINT;
+ else if(param->type.vecsemantics == TypeDesc::VECTOR)
+ socket_type = SocketType::VECTOR;
+ else if(param->type.vecsemantics == TypeDesc::NORMAL)
+ socket_type = SocketType::NORMAL;
+ else
+ continue;
+
+ if(!param->isoutput && param->validdefault) {
+ node->add_input(param->name.c_str(), socket_type, make_float3(param->fdefault[0], param->fdefault[1], param->fdefault[2]));
+ continue;
+ }
+ }
+ else if(param->type.aggregate == TypeDesc::SCALAR) {
+ if(param->type.basetype == TypeDesc::INT) {
+ socket_type = SocketType::INT;
+
+ if(!param->isoutput && param->validdefault) {
+ node->add_input(param->name.c_str(), socket_type, (float)param->idefault[0]);
+ continue;
+ }
+ }
+ else if(param->type.basetype == TypeDesc::FLOAT) {
+ socket_type = SocketType::FLOAT;
+
+ if(!param->isoutput && param->validdefault) {
+ node->add_input(param->name.c_str(), socket_type, param->fdefault[0]);
+ continue;
+ }
+ }
+ else if(param->type.basetype == TypeDesc::STRING) {
+ socket_type = SocketType::STRING;
+
+ if(!param->isoutput && param->validdefault) {
+ node->add_input(param->name.c_str(), socket_type);
+ continue;
+ }
+ }
+ else
+ continue;
+ }
+ else
+ continue;
+
+ if(param->isoutput) {
+ node->add_output(param->name.c_str(), socket_type);
+ }
+ else {
+ node->add_input(param->name.c_str(), socket_type);
+ }
+ }
+
+ /* set bytcode hash or filepath */
+ if(!bytecode_hash.empty()) {
+ node->bytecode_hash = bytecode_hash;
+ }
+ else {
+ node->filepath = filepath;
+ }
+
+ return node;
+}
+
/* Graph Compiler */
OSLCompiler::OSLCompiler(void *manager_, void *shadingsys_, ImageManager *image_manager_)
@@ -427,7 +554,7 @@ string OSLCompiler::id(ShaderNode *node)
string OSLCompiler::compatible_name(ShaderNode *node, ShaderInput *input)
{
- string sname(input->name);
+ string sname(input->name().string());
size_t i;
/* strip whitespace */
@@ -436,7 +563,7 @@ string OSLCompiler::compatible_name(ShaderNode *node, ShaderInput *input)
/* if output exists with the same name, add "In" suffix */
foreach(ShaderOutput *output, node->outputs) {
- if(strcmp(input->name, output->name)==0) {
+ if(input->name() == output->name()) {
sname += "In";
break;
}
@@ -447,7 +574,7 @@ string OSLCompiler::compatible_name(ShaderNode *node, ShaderInput *input)
string OSLCompiler::compatible_name(ShaderNode *node, ShaderOutput *output)
{
- string sname(output->name);
+ string sname(output->name().string());
size_t i;
/* strip whitespace */
@@ -456,7 +583,7 @@ string OSLCompiler::compatible_name(ShaderNode *node, ShaderOutput *output)
/* if input exists with the same name, add "Out" suffix */
foreach(ShaderInput *input, node->inputs) {
- if(strcmp(input->name, output->name)==0) {
+ if(input->name() == output->name()) {
sname += "Out";
break;
}
@@ -470,21 +597,21 @@ bool OSLCompiler::node_skip_input(ShaderNode *node, ShaderInput *input)
/* exception for output node, only one input is actually used
* depending on the current shader type */
- if(!(input->usage & ShaderInput::USE_OSL))
+ if(input->flags() & SocketType::SVM_INTERNAL)
return true;
if(node->special_type == SHADER_SPECIAL_TYPE_OUTPUT) {
- if(strcmp(input->name, "Surface") == 0 && current_type != SHADER_TYPE_SURFACE)
+ if(input->name() == "Surface" && current_type != SHADER_TYPE_SURFACE)
return true;
- if(strcmp(input->name, "Volume") == 0 && current_type != SHADER_TYPE_VOLUME)
+ if(input->name() == "Volume" && current_type != SHADER_TYPE_VOLUME)
return true;
- if(strcmp(input->name, "Displacement") == 0 && current_type != SHADER_TYPE_DISPLACEMENT)
+ if(input->name() == "Displacement" && current_type != SHADER_TYPE_DISPLACEMENT)
return true;
- if(strcmp(input->name, "Normal") == 0)
+ if(input->name() == "Normal")
return true;
}
else if(node->special_type == SHADER_SPECIAL_TYPE_BUMP) {
- if(strcmp(input->name, "Height") == 0)
+ if(input->name() == "Height")
return true;
}
else if(current_type == SHADER_TYPE_DISPLACEMENT && input->link && input->link->parent->special_type == SHADER_SPECIAL_TYPE_BUMP)
@@ -512,34 +639,35 @@ void OSLCompiler::add(ShaderNode *node, const char *name, bool isfilepath)
if(node_skip_input(node, input))
continue;
/* already has default value assigned */
- else if(input->default_value != ShaderInput::NONE)
+ else if(input->flags() & SocketType::DEFAULT_LINK_MASK)
continue;
string param_name = compatible_name(node, input);
- switch(input->type) {
- case SHADER_SOCKET_COLOR:
- parameter_color(param_name.c_str(), input->value);
+ switch(input->type()) {
+ case SocketType::COLOR:
+ parameter_color(param_name.c_str(), input->value());
break;
- case SHADER_SOCKET_POINT:
- parameter_point(param_name.c_str(), input->value);
+ case SocketType::POINT:
+ parameter_point(param_name.c_str(), input->value());
break;
- case SHADER_SOCKET_VECTOR:
- parameter_vector(param_name.c_str(), input->value);
+ case SocketType::VECTOR:
+ parameter_vector(param_name.c_str(), input->value());
break;
- case SHADER_SOCKET_NORMAL:
- parameter_normal(param_name.c_str(), input->value);
+ case SocketType::NORMAL:
+ parameter_normal(param_name.c_str(), input->value());
break;
- case SHADER_SOCKET_FLOAT:
- parameter(param_name.c_str(), input->value.x);
+ case SocketType::FLOAT:
+ parameter(param_name.c_str(), input->value_float());
break;
- case SHADER_SOCKET_INT:
- parameter(param_name.c_str(), (int)input->value.x);
+ case SocketType::INT:
+ parameter(param_name.c_str(), (int)input->value_float());
break;
- case SHADER_SOCKET_STRING:
- parameter(param_name.c_str(), input->value_string);
+ case SocketType::STRING:
+ parameter(param_name.c_str(), input->value_string());
break;
- case SHADER_SOCKET_CLOSURE:
- case SHADER_SOCKET_UNDEFINED:
+ case SocketType::CLOSURE:
+ case SocketType::UNDEFINED:
+ default:
break;
}
}
diff --git a/intern/cycles/render/osl.h b/intern/cycles/render/osl.h
index 110897ff300..13b9d6307f9 100644
--- a/intern/cycles/render/osl.h
+++ b/intern/cycles/render/osl.h
@@ -22,6 +22,7 @@
#include "util_thread.h"
#include "graph.h"
+#include "nodes.h"
#include "shader.h"
#ifdef WITH_OSL
@@ -54,6 +55,7 @@ struct OSLShaderInfo {
has_surface_bssrdf(false)
{}
+ OSL::OSLQuery query;
bool has_surface_emission;
bool has_surface_transparent;
bool has_surface_bssrdf;
@@ -83,6 +85,11 @@ public:
const char *shader_load_filepath(string filepath);
OSLShaderInfo *shader_loaded_info(const string& hash);
+ /* create OSL node using OSLQuery */
+ OSLNode *osl_node(const std::string& filepath,
+ const std::string& bytecode_hash = "",
+ const std::string& bytecode = "");
+
protected:
void texture_system_init();
void texture_system_free();
diff --git a/intern/cycles/render/particles.cpp b/intern/cycles/render/particles.cpp
index 50726bb4574..1a35d60fb4b 100644
--- a/intern/cycles/render/particles.cpp
+++ b/intern/cycles/render/particles.cpp
@@ -58,8 +58,8 @@ void ParticleSystemManager::device_update_particles(Device *device, DeviceScene
* adds one dummy particle at the beginning to avoid invalid lookups,
* in case a shader uses particle info without actual particle data. */
int num_particles = 1;
- foreach(ParticleSystem *psys, scene->particle_systems)
- num_particles += psys->particles.size();
+ for(size_t j = 0; j < scene->particle_systems.size(); j++)
+ num_particles += scene->particle_systems[j]->particles.size();
float4 *particles = dscene->particles.resize(PARTICLE_SIZE*num_particles);
@@ -71,9 +71,12 @@ void ParticleSystemManager::device_update_particles(Device *device, DeviceScene
particles[4] = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
int i = 1;
- foreach(ParticleSystem *psys, scene->particle_systems) {
- foreach(Particle &pa, psys->particles) {
+ for(size_t j = 0; j < scene->particle_systems.size(); j++) {
+ ParticleSystem *psys = scene->particle_systems[j];
+
+ for(size_t k = 0; k < psys->particles.size(); k++) {
/* pack in texture */
+ Particle& pa = psys->particles[k];
int offset = i*PARTICLE_SIZE;
particles[offset] = make_float4(pa.index, pa.age, pa.lifetime, pa.size);
diff --git a/intern/cycles/render/particles.h b/intern/cycles/render/particles.h
index bf2b6b77015..2509e27b44b 100644
--- a/intern/cycles/render/particles.h
+++ b/intern/cycles/render/particles.h
@@ -47,7 +47,7 @@ public:
void tag_update(Scene *scene);
- vector<Particle> particles;
+ array<Particle> particles;
};
/* ParticleSystem Manager */
diff --git a/intern/cycles/render/scene.cpp b/intern/cycles/render/scene.cpp
index b0052c30af4..e8367e1eb36 100644
--- a/intern/cycles/render/scene.cpp
+++ b/intern/cycles/render/scene.cpp
@@ -242,9 +242,14 @@ void Scene::device_update(Device *device_, Progress& progress)
}
if(print_stats) {
+ size_t mem_used = util_guarded_get_mem_used();
+ size_t mem_peak = util_guarded_get_mem_peak();
+
VLOG(1) << "System memory statistics after full device sync:\n"
- << " Usage: " << util_guarded_get_mem_used() << "\n"
- << " Peak: " << util_guarded_get_mem_peak();
+ << " Usage: " << string_human_readable_number(mem_used)
+ << " (" << string_human_readable_size(mem_used) << ")\n"
+ << " Peak: " << string_human_readable_number(mem_peak)
+ << " (" << string_human_readable_size(mem_peak) << ")";
}
}
diff --git a/intern/cycles/render/scene.h b/intern/cycles/render/scene.h
index 33c03d40f27..b34d6127118 100644
--- a/intern/cycles/render/scene.h
+++ b/intern/cycles/render/scene.h
@@ -109,10 +109,10 @@ public:
device_vector<uint> sobol_directions;
/* cpu images */
- device_vector<uchar4> tex_byte4_image[TEX_NUM_BYTE4_IMAGES_CPU];
- device_vector<float4> tex_float4_image[TEX_NUM_FLOAT4_IMAGES_CPU];
- device_vector<float> tex_float_image[TEX_NUM_FLOAT_IMAGES_CPU];
- device_vector<uchar> tex_byte_image[TEX_NUM_BYTE_IMAGES_CPU];
+ device_vector<uchar4> tex_byte4_image[TEX_NUM_BYTE4_CPU];
+ device_vector<float4> tex_float4_image[TEX_NUM_FLOAT4_CPU];
+ device_vector<float> tex_float_image[TEX_NUM_FLOAT_CPU];
+ device_vector<uchar> tex_byte_image[TEX_NUM_BYTE_CPU];
/* opencl images */
device_vector<uchar4> tex_image_byte4_packed;
diff --git a/intern/cycles/render/session.cpp b/intern/cycles/render/session.cpp
index 63037311889..1cd76ff2b39 100644
--- a/intern/cycles/render/session.cpp
+++ b/intern/cycles/render/session.cpp
@@ -610,17 +610,17 @@ DeviceRequestedFeatures Session::get_requested_device_features()
/* TODO(sergey): Consider moving this to the Scene level. */
DeviceRequestedFeatures requested_features;
requested_features.experimental = params.experimental;
+
+ requested_features.max_closure = get_max_closure_count();
+ scene->shader_manager->get_requested_features(
+ scene,
+ &requested_features);
if(!params.background) {
+ /* Avoid too much re-compilations for viewport render. */
requested_features.max_closure = 64;
requested_features.max_nodes_group = NODE_GROUP_LEVEL_MAX;
requested_features.nodes_features = NODE_FEATURE_ALL;
}
- else {
- requested_features.max_closure = get_max_closure_count();
- scene->shader_manager->get_requested_features(
- scene,
- &requested_features);
- }
/* This features are not being tweaked as often as shaders,
* so could be done selective magic for the viewport as well.
@@ -630,7 +630,7 @@ DeviceRequestedFeatures Session::get_requested_device_features()
requested_features.use_camera_motion = scene->camera->use_motion;
foreach(Object *object, scene->objects) {
Mesh *mesh = object->mesh;
- if(mesh->curves.size() > 0) {
+ if(mesh->num_curves()) {
requested_features.use_hair = true;
}
requested_features.use_object_motion |= object->use_motion | mesh->use_motion_blur;
diff --git a/intern/cycles/render/shader.cpp b/intern/cycles/render/shader.cpp
index 635024d7bdf..708eeef3b50 100644
--- a/intern/cycles/render/shader.cpp
+++ b/intern/cycles/render/shader.cpp
@@ -456,7 +456,7 @@ void ShaderManager::add_default(Scene *scene)
ShaderGraph *graph = new ShaderGraph();
closure = graph->add(new DiffuseBsdfNode());
- closure->input("Color")->value = make_float3(0.8f, 0.8f, 0.8f);
+ closure->input("Color")->set(make_float3(0.8f, 0.8f, 0.8f));
out = graph->output();
graph->connect(closure->output("BSDF"), out->input("Surface"));
@@ -473,8 +473,8 @@ void ShaderManager::add_default(Scene *scene)
ShaderGraph *graph = new ShaderGraph();
closure = graph->add(new EmissionNode());
- closure->input("Color")->value = make_float3(0.8f, 0.8f, 0.8f);
- closure->input("Strength")->value.x = 0.0f;
+ closure->input("Color")->set(make_float3(0.8f, 0.8f, 0.8f));
+ closure->input("Strength")->set(0.0f);
out = graph->output();
graph->connect(closure->output("Emission"), out->input("Surface"));
diff --git a/intern/cycles/render/svm.cpp b/intern/cycles/render/svm.cpp
index 4c97a5ad792..d54afd1ba6f 100644
--- a/intern/cycles/render/svm.cpp
+++ b/intern/cycles/render/svm.cpp
@@ -120,22 +120,22 @@ SVMCompiler::SVMCompiler(ShaderManager *shader_manager_, ImageManager *image_man
compile_failed = false;
}
-int SVMCompiler::stack_size(ShaderSocketType type)
+int SVMCompiler::stack_size(SocketType::Type type)
{
int size = 0;
switch(type) {
- case SHADER_SOCKET_FLOAT:
- case SHADER_SOCKET_INT:
+ case SocketType::FLOAT:
+ case SocketType::INT:
size = 1;
break;
- case SHADER_SOCKET_COLOR:
- case SHADER_SOCKET_VECTOR:
- case SHADER_SOCKET_NORMAL:
- case SHADER_SOCKET_POINT:
+ case SocketType::COLOR:
+ case SocketType::VECTOR:
+ case SocketType::NORMAL:
+ case SocketType::POINT:
size = 3;
break;
- case SHADER_SOCKET_CLOSURE:
+ case SocketType::CLOSURE:
size = 0;
break;
default:
@@ -146,7 +146,7 @@ int SVMCompiler::stack_size(ShaderSocketType type)
return size;
}
-int SVMCompiler::stack_find_offset(ShaderSocketType type)
+int SVMCompiler::stack_find_offset(SocketType::Type type)
{
int size = stack_size(type);
int offset = -1;
@@ -175,7 +175,7 @@ int SVMCompiler::stack_find_offset(ShaderSocketType type)
return 0;
}
-void SVMCompiler::stack_clear_offset(ShaderSocketType type, int offset)
+void SVMCompiler::stack_clear_offset(SocketType::Type type, int offset)
{
int size = stack_size(type);
@@ -193,22 +193,22 @@ int SVMCompiler::stack_assign(ShaderInput *input)
}
else {
/* not linked to output -> add nodes to load default value */
- input->stack_offset = stack_find_offset(input->type);
+ input->stack_offset = stack_find_offset(input->type());
- if(input->type == SHADER_SOCKET_FLOAT) {
- add_node(NODE_VALUE_F, __float_as_int(input->value.x), input->stack_offset);
+ if(input->type() == SocketType::FLOAT) {
+ add_node(NODE_VALUE_F, __float_as_int(input->value_float()), input->stack_offset);
}
- else if(input->type == SHADER_SOCKET_INT) {
- add_node(NODE_VALUE_F, (int)input->value.x, input->stack_offset);
+ else if(input->type() == SocketType::INT) {
+ add_node(NODE_VALUE_F, (int)input->value_float(), input->stack_offset);
}
- else if(input->type == SHADER_SOCKET_VECTOR ||
- input->type == SHADER_SOCKET_NORMAL ||
- input->type == SHADER_SOCKET_POINT ||
- input->type == SHADER_SOCKET_COLOR)
+ else if(input->type() == SocketType::VECTOR ||
+ input->type() == SocketType::NORMAL ||
+ input->type() == SocketType::POINT ||
+ input->type() == SocketType::COLOR)
{
add_node(NODE_VALUE_V, input->stack_offset);
- add_node(NODE_VALUE_V, input->value);
+ add_node(NODE_VALUE_V, input->value());
}
else /* should not get called for closure */
assert(0);
@@ -222,7 +222,7 @@ int SVMCompiler::stack_assign(ShaderOutput *output)
{
/* if no stack offset assigned yet, find one */
if(output->stack_offset == SVM_STACK_INVALID)
- output->stack_offset = stack_find_offset(output->type);
+ output->stack_offset = stack_find_offset(output->type());
return output->stack_offset;
}
@@ -247,11 +247,11 @@ void SVMCompiler::stack_link(ShaderInput *input, ShaderOutput *output)
{
if(output->stack_offset == SVM_STACK_INVALID) {
assert(input->link);
- assert(stack_size(output->type) == stack_size(input->link->type));
+ assert(stack_size(output->type()) == stack_size(input->link->type()));
output->stack_offset = input->link->stack_offset;
- int size = stack_size(output->type);
+ int size = stack_size(output->type());
for(int i = 0; i < size; i++)
active_stack.users[output->stack_offset + i]++;
@@ -279,7 +279,7 @@ void SVMCompiler::stack_clear_users(ShaderNode *node, ShaderNodeSet& done)
all_done = false;
if(all_done) {
- stack_clear_offset(output->type, output->stack_offset);
+ stack_clear_offset(output->type(), output->stack_offset);
output->stack_offset = SVM_STACK_INVALID;
foreach(ShaderInput *in, output->links)
@@ -293,7 +293,7 @@ void SVMCompiler::stack_clear_temporary(ShaderNode *node)
{
foreach(ShaderInput *input, node->inputs) {
if(!input->link && input->stack_offset != SVM_STACK_INVALID) {
- stack_clear_offset(input->type, input->stack_offset);
+ stack_clear_offset(input->type(), input->stack_offset);
input->stack_offset = SVM_STACK_INVALID;
}
}
@@ -446,7 +446,7 @@ void SVMCompiler::generate_closure_node(ShaderNode *node,
const char *weight_name = (current_type == SHADER_TYPE_VOLUME)? "VolumeMixWeight": "SurfaceMixWeight";
ShaderInput *weight_in = node->input(weight_name);
- if(weight_in && (weight_in->link || weight_in->value.x != 1.0f))
+ if(weight_in && (weight_in->link || weight_in->value_float() != 1.0f))
mix_weight_offset = stack_assign(weight_in);
else
mix_weight_offset = SVM_STACK_INVALID;
@@ -479,7 +479,7 @@ void SVMCompiler::generated_shared_closure_nodes(ShaderNode *root_node,
}
else {
foreach(ShaderInput *in, node->inputs) {
- if(in->type == SHADER_SOCKET_CLOSURE && in->link)
+ if(in->type() == SocketType::CLOSURE && in->link)
generated_shared_closure_nodes(root_node,
in->link->parent,
state,
diff --git a/intern/cycles/render/svm.h b/intern/cycles/render/svm.h
index dbf1b1de947..e14d57d7601 100644
--- a/intern/cycles/render/svm.h
+++ b/intern/cycles/render/svm.h
@@ -99,8 +99,8 @@ public:
int stack_assign(ShaderInput *input);
int stack_assign_if_linked(ShaderInput *input);
int stack_assign_if_linked(ShaderOutput *output);
- int stack_find_offset(ShaderSocketType type);
- void stack_clear_offset(ShaderSocketType type, int offset);
+ int stack_find_offset(SocketType::Type type);
+ void stack_clear_offset(SocketType::Type type, int offset);
void stack_link(ShaderInput *input, ShaderOutput *output);
void add_node(ShaderNodeType type, int a = 0, int b = 0, int c = 0);
@@ -172,7 +172,7 @@ protected:
};
void stack_clear_temporary(ShaderNode *node);
- int stack_size(ShaderSocketType type);
+ int stack_size(SocketType::Type type);
void stack_clear_users(ShaderNode *node, ShaderNodeSet& done);
bool node_skip_input(ShaderNode *node, ShaderInput *input);
diff --git a/intern/cycles/subd/subd_dice.cpp b/intern/cycles/subd/subd_dice.cpp
index a5dfcd21ceb..7c74f21950e 100644
--- a/intern/cycles/subd/subd_dice.cpp
+++ b/intern/cycles/subd/subd_dice.cpp
@@ -41,14 +41,14 @@ EdgeDice::EdgeDice(const SubdParams& params_)
}
}
-void EdgeDice::reserve(int num_verts, int num_tris)
+void EdgeDice::reserve(int num_verts)
{
Mesh *mesh = params.mesh;
vert_offset = mesh->verts.size();
- tri_offset = mesh->triangles.size();
+ tri_offset = mesh->num_triangles();
- mesh->reserve(vert_offset + num_verts, tri_offset + num_tris, 0, 0);
+ mesh->resize_mesh(vert_offset + num_verts, tri_offset);
Attribute *attr_vN = mesh->attributes.add(ATTR_STD_VERTEX_NORMAL);
@@ -69,7 +69,7 @@ int EdgeDice::add_vert(Patch *patch, float2 uv)
if(params.ptex) {
Attribute *attr_ptex_uv = params.mesh->attributes.add(ATTR_STD_PTEX_UV);
- params.mesh->attributes.reserve();
+ params.mesh->attributes.resize();
float3 *ptex_uv = attr_ptex_uv->data_float3();
ptex_uv[vert_offset] = make_float3(uv.x, uv.y, 0.0f);
@@ -80,11 +80,17 @@ int EdgeDice::add_vert(Patch *patch, float2 uv)
void EdgeDice::add_triangle(Patch *patch, int v0, int v1, int v2)
{
- params.mesh->add_triangle(v0, v1, v2, params.shader, params.smooth, false);
+ Mesh *mesh = params.mesh;
+
+ /* todo: optimize so we can reserve in advance, this is like push_back_slow() */
+ if(mesh->triangles.size() == mesh->triangles.capacity())
+ mesh->reserve_mesh(mesh->verts.size(), size_t(max(mesh->num_triangles() + 1, 1) * 1.2));
+
+ mesh->add_triangle(v0, v1, v2, params.shader, params.smooth, false);
if(params.ptex) {
Attribute *attr_ptex_face_id = params.mesh->attributes.add(ATTR_STD_PTEX_FACE_ID);
- params.mesh->attributes.reserve();
+ params.mesh->attributes.resize();
float *ptex_face_id = attr_ptex_face_id->data_float();
ptex_face_id[tri_offset] = (float)patch->ptex_face_id();
@@ -141,8 +147,7 @@ void QuadDice::reserve(EdgeFactors& ef, int Mu, int Mv)
{
/* XXX need to make this also work for edge factor 0 and 1 */
int num_verts = (ef.tu0 + ef.tu1 + ef.tv0 + ef.tv1) + (Mu - 1)*(Mv - 1);
- int num_tris = 0;
- EdgeDice::reserve(num_verts, num_tris);
+ EdgeDice::reserve(num_verts);
}
float2 QuadDice::map_uv(SubPatch& sub, float u, float v)
@@ -352,7 +357,7 @@ void TriangleDice::reserve(EdgeFactors& ef, int M)
if(!(M & 1))
num_verts++;
- EdgeDice::reserve(num_verts, 0);
+ EdgeDice::reserve(num_verts);
}
float2 TriangleDice::map_uv(SubPatch& sub, float2 uv)
diff --git a/intern/cycles/subd/subd_dice.h b/intern/cycles/subd/subd_dice.h
index 49f786e949e..85bd0ea28f0 100644
--- a/intern/cycles/subd/subd_dice.h
+++ b/intern/cycles/subd/subd_dice.h
@@ -72,7 +72,7 @@ public:
explicit EdgeDice(const SubdParams& params);
- void reserve(int num_verts, int num_tris);
+ void reserve(int num_verts);
int add_vert(Patch *patch, float2 uv);
void add_triangle(Patch *patch, int v0, int v1, int v2);
diff --git a/intern/cycles/util/CMakeLists.txt b/intern/cycles/util/CMakeLists.txt
index cceec8d444c..e6140b3ed09 100644
--- a/intern/cycles/util/CMakeLists.txt
+++ b/intern/cycles/util/CMakeLists.txt
@@ -19,8 +19,10 @@ set(SRC
util_simd.cpp
util_system.cpp
util_task.cpp
+ util_thread.cpp
util_time.cpp
util_transform.cpp
+ util_windows.cpp
)
if(NOT CYCLES_STANDALONE_REPOSITORY)
diff --git a/intern/cycles/util/util_math.h b/intern/cycles/util/util_math.h
index 32924f9a8c2..53944ec1cc4 100644
--- a/intern/cycles/util/util_math.h
+++ b/intern/cycles/util/util_math.h
@@ -1479,21 +1479,25 @@ ccl_device bool ray_triangle_intersect_uv(
return true;
}
-ccl_device bool ray_quad_intersect(float3 ray_P, float3 ray_D, float ray_t,
- float3 quad_P, float3 quad_u, float3 quad_v,
+ccl_device bool ray_quad_intersect(float3 ray_P, float3 ray_D, float ray_mint, float ray_maxt,
+ float3 quad_P, float3 quad_u, float3 quad_v, float3 quad_n,
float3 *isect_P, float *isect_t)
{
- float3 v0 = quad_P - quad_u*0.5f - quad_v*0.5f;
- float3 v1 = quad_P + quad_u*0.5f - quad_v*0.5f;
- float3 v2 = quad_P + quad_u*0.5f + quad_v*0.5f;
- float3 v3 = quad_P - quad_u*0.5f + quad_v*0.5f;
+ float t = -(dot(ray_P, quad_n) - dot(quad_P, quad_n)) / dot(ray_D, quad_n);
+ if(t < ray_mint || t > ray_maxt)
+ return false;
- if(ray_triangle_intersect(ray_P, ray_D, ray_t, v0, v1, v2, isect_P, isect_t))
- return true;
- else if(ray_triangle_intersect(ray_P, ray_D, ray_t, v0, v2, v3, isect_P, isect_t))
- return true;
-
- return false;
+ float3 hit = ray_P + t*ray_D;
+ float3 inplane = hit - quad_P;
+ if(fabsf(dot(inplane, quad_u) / dot(quad_u, quad_u)) > 0.5f)
+ return false;
+ if(fabsf(dot(inplane, quad_v) / dot(quad_v, quad_v)) > 0.5f)
+ return false;
+
+ if(isect_P) *isect_P = hit;
+ if(isect_t) *isect_t = t;
+
+ return true;
}
/* projections */
diff --git a/intern/cycles/util/util_string.cpp b/intern/cycles/util/util_string.cpp
index b3a8c6d7c2e..e16a83d56d0 100644
--- a/intern/cycles/util/util_string.cpp
+++ b/intern/cycles/util/util_string.cpp
@@ -239,5 +239,45 @@ string string_to_ansi(const string& str)
#endif /* _WIN32 */
+string string_human_readable_size(size_t size)
+{
+ static const char suffixes[] = "BKMGTPEZY";
+
+ const char* suffix = suffixes;
+ size_t r = 0;
+
+ while(size >= 1024) {
+ r = size % 1024;
+ size /= 1024;
+ suffix++;
+ }
+
+ if(*suffix != 'B')
+ return string_printf("%.2f%c", double(size*1024+r)/1024.0, *suffix);
+ else
+ return string_printf("%zu", size);
+}
+
+string string_human_readable_number(size_t num)
+{
+ /* add thousands separators */
+ char buf[32];
+
+ char* p = buf+31;
+ *p = '\0';
+
+ int i = -1;
+ while(num) {
+ if(++i && i % 3 == 0)
+ *(--p) = ',';
+
+ *(--p) = '0' + (num % 10);
+
+ num /= 10;
+ }
+
+ return p;
+}
+
CCL_NAMESPACE_END
diff --git a/intern/cycles/util/util_string.h b/intern/cycles/util/util_string.h
index c4b51bda432..d3b5248c380 100644
--- a/intern/cycles/util/util_string.h
+++ b/intern/cycles/util/util_string.h
@@ -62,6 +62,11 @@ string string_from_wstring(const wstring& path);
string string_to_ansi(const string& str);
#endif
+/* Make a string from a size in bytes in human readable form */
+string string_human_readable_size(size_t size);
+/* Make a string from a unitless quantity in human readable form */
+string string_human_readable_number(size_t num);
+
CCL_NAMESPACE_END
#endif /* __UTIL_STRING_H__ */
diff --git a/intern/cycles/util/util_system.cpp b/intern/cycles/util/util_system.cpp
index 4ff0ee91d73..d5fac9a0e34 100644
--- a/intern/cycles/util/util_system.cpp
+++ b/intern/cycles/util/util_system.cpp
@@ -15,7 +15,9 @@
*/
#include "util_system.h"
+
#include "util_debug.h"
+#include "util_logging.h"
#include "util_types.h"
#include "util_string.h"
@@ -33,28 +35,56 @@
CCL_NAMESPACE_BEGIN
-int system_cpu_thread_count()
+int system_cpu_group_count()
{
- static uint count = 0;
-
- if(count > 0)
- return count;
+#ifdef _WIN32
+ util_windows_init_numa_groups();
+ return GetActiveProcessorGroupCount();
+#else
+ /* TODO(sergey): Need to adopt for other platforms. */
+ return 1;
+#endif
+}
+int system_cpu_group_thread_count(int group)
+{
+ /* TODO(sergey): Need make other platforms aware of groups. */
#ifdef _WIN32
- SYSTEM_INFO info;
- GetSystemInfo(&info);
- count = (uint)info.dwNumberOfProcessors;
+ util_windows_init_numa_groups();
+ return GetActiveProcessorCount(group);
#elif defined(__APPLE__)
+ (void)group;
+ int count;
size_t len = sizeof(count);
int mib[2] = { CTL_HW, HW_NCPU };
-
sysctl(mib, 2, &count, &len, NULL, 0);
+ return count;
#else
- count = (uint)sysconf(_SC_NPROCESSORS_ONLN);
+ (void)group;
+ return sysconf(_SC_NPROCESSORS_ONLN);
#endif
+}
+
+int system_cpu_thread_count()
+{
+ static uint count = 0;
- if(count < 1)
+ if(count > 0) {
+ return count;
+ }
+
+ int max_group = system_cpu_group_count();
+ VLOG(1) << "Detected " << max_group << " CPU groups.";
+ for(int group = 0; group < max_group; ++group) {
+ int num_threads = system_cpu_group_thread_count(group);
+ VLOG(1) << "Group " << group
+ << " has " << num_threads << " threads.";
+ count += num_threads;
+ }
+
+ if(count < 1) {
count = 1;
+ }
return count;
}
diff --git a/intern/cycles/util/util_system.h b/intern/cycles/util/util_system.h
index 4e7e00f85fd..557aab6cbae 100644
--- a/intern/cycles/util/util_system.h
+++ b/intern/cycles/util/util_system.h
@@ -21,7 +21,15 @@
CCL_NAMESPACE_BEGIN
+/* Get number of available CPU groups. */
+int system_cpu_group_count();
+
+/* Get number of threads/processors in the specified group. */
+int system_cpu_group_thread_count(int group);
+
+/* Get total number of threads in all groups. */
int system_cpu_thread_count();
+
string system_cpu_brand_string();
int system_cpu_bits();
bool system_cpu_support_sse2();
diff --git a/intern/cycles/util/util_task.cpp b/intern/cycles/util/util_task.cpp
index d86aa8a4a46..352ba81c95a 100644
--- a/intern/cycles/util/util_task.cpp
+++ b/intern/cycles/util/util_task.cpp
@@ -16,6 +16,7 @@
#include "util_debug.h"
#include "util_foreach.h"
+#include "util_logging.h"
#include "util_system.h"
#include "util_task.h"
#include "util_time.h"
@@ -198,12 +199,30 @@ void TaskScheduler::init(int num_threads)
/* automatic number of threads */
num_threads = system_cpu_thread_count();
}
+ VLOG(1) << "Creating pool of " << num_threads << " threads.";
/* launch threads that will be waiting for work */
threads.resize(num_threads);
- for(size_t i = 0; i < threads.size(); i++)
- threads[i] = new thread(function_bind(&TaskScheduler::thread_run, i + 1));
+ int num_groups = system_cpu_group_count();
+ int thread_index = 0;
+ for(int group = 0; group < num_groups; ++group) {
+ /* NOTE: That's not really efficient from threading point of view,
+ * but it is simple to read and it doesn't make sense to use more
+ * user-specified threads than logical threads anyway.
+ */
+ int num_group_threads = (group == num_groups - 1)
+ ? (threads.size() - thread_index)
+ : system_cpu_group_thread_count(group);
+ for(int group_thread = 0;
+ group_thread < num_group_threads && thread_index < threads.size();
+ ++group_thread, ++thread_index)
+ {
+ threads[thread_index] = new thread(function_bind(&TaskScheduler::thread_run,
+ thread_index + 1),
+ group);
+ }
+ }
}
users++;
diff --git a/intern/cycles/util/util_texture.h b/intern/cycles/util/util_texture.h
index 6da47858133..e00edc046f7 100644
--- a/intern/cycles/util/util_texture.h
+++ b/intern/cycles/util/util_texture.h
@@ -19,43 +19,47 @@
CCL_NAMESPACE_BEGIN
-/* Texture limits on various devices. */
+/* Texture limits on devices. */
/* CPU */
-#define TEX_NUM_BYTE4_IMAGES_CPU 1024
-#define TEX_NUM_FLOAT4_IMAGES_CPU 1024
-#define TEX_NUM_FLOAT_IMAGES_CPU 1024
-#define TEX_NUM_BYTE_IMAGES_CPU 1024
-#define TEX_IMAGE_BYTE4_START_CPU TEX_NUM_FLOAT4_IMAGES_CPU
-#define TEX_IMAGE_FLOAT_START_CPU (TEX_NUM_FLOAT4_IMAGES_CPU + TEX_NUM_BYTE4_IMAGES_CPU)
-#define TEX_IMAGE_BYTE_START_CPU (TEX_NUM_FLOAT4_IMAGES_CPU + TEX_NUM_BYTE4_IMAGES_CPU + TEX_NUM_BYTE_IMAGES_CPU)
+#define TEX_NUM_FLOAT4_CPU 1024
+#define TEX_NUM_BYTE4_CPU 1024
+#define TEX_NUM_FLOAT_CPU 1024
+#define TEX_NUM_BYTE_CPU 1024
+#define TEX_START_FLOAT4_CPU 0
+#define TEX_START_BYTE4_CPU TEX_NUM_FLOAT4_CPU
+#define TEX_START_FLOAT_CPU (TEX_NUM_FLOAT4_CPU + TEX_NUM_BYTE4_CPU)
+#define TEX_START_BYTE_CPU (TEX_NUM_FLOAT4_CPU + TEX_NUM_BYTE4_CPU + TEX_NUM_BYTE_CPU)
-/* CUDA (Fermi) */
-#define TEX_NUM_BYTE4_IMAGES_CUDA 88
-#define TEX_NUM_FLOAT4_IMAGES_CUDA 5
-#define TEX_NUM_FLOAT_IMAGES_CUDA 0
-#define TEX_NUM_BYTE_IMAGES_CUDA 0
-#define TEX_IMAGE_BYTE4_START_CUDA TEX_NUM_FLOAT4_IMAGES_CUDA
-#define TEX_IMAGE_FLOAT_START_CUDA (TEX_NUM_FLOAT4_IMAGES_CUDA + TEX_NUM_BYTE4_IMAGES_CUDA)
-#define TEX_IMAGE_BYTE_START_CUDA (TEX_NUM_FLOAT4_IMAGES_CUDA + TEX_NUM_BYTE4_IMAGES_CUDA + TEX_NUM_BYTE_IMAGES_CUDA)
+/* CUDA (Geforce 4xx and 5xx) */
+#define TEX_NUM_FLOAT4_CUDA 5
+#define TEX_NUM_BYTE4_CUDA 88
+#define TEX_NUM_FLOAT_CUDA 0
+#define TEX_NUM_BYTE_CUDA 0
+#define TEX_START_FLOAT4_CUDA 0
+#define TEX_START_BYTE4_CUDA TEX_NUM_FLOAT4_CUDA
+#define TEX_START_FLOAT_CUDA (TEX_NUM_FLOAT4_CUDA + TEX_NUM_BYTE4_CUDA)
+#define TEX_START_BYTE_CUDA (TEX_NUM_FLOAT4_CUDA + TEX_NUM_BYTE4_CUDA + TEX_NUM_BYTE_CUDA)
-/* CUDA (KEPLER and above) */
-#define TEX_NUM_BYTE4_IMAGES_CUDA_KEPLER 1024
-#define TEX_NUM_FLOAT4_IMAGES_CUDA_KEPLER 1024
-#define TEX_NUM_FLOAT_IMAGES_CUDA_KEPLER 1024
-#define TEX_NUM_BYTE_IMAGES_CUDA_KEPLER 1024
-#define TEX_IMAGE_BYTE4_START_CUDA_KEPLER TEX_NUM_FLOAT4_IMAGES_CUDA_KEPLER
-#define TEX_IMAGE_FLOAT_START_CUDA_KEPLER (TEX_NUM_FLOAT4_IMAGES_CUDA_KEPLER + TEX_NUM_BYTE4_IMAGES_CUDA_KEPLER)
-#define TEX_IMAGE_BYTE_START_CUDA_KEPLER (TEX_NUM_FLOAT4_IMAGES_CUDA_KEPLER + TEX_NUM_BYTE4_IMAGES_CUDA_KEPLER + TEX_NUM_BYTE_IMAGES_CUDA_KEPLER)
+/* CUDA (Kepler, Geforce 6xx and above) */
+#define TEX_NUM_FLOAT4_CUDA_KEPLER 1024
+#define TEX_NUM_BYTE4_CUDA_KEPLER 1024
+#define TEX_NUM_FLOAT_CUDA_KEPLER 1024
+#define TEX_NUM_BYTE_CUDA_KEPLER 1024
+#define TEX_START_FLOAT4_CUDA_KEPLER 0
+#define TEX_START_BYTE4_CUDA_KEPLER TEX_NUM_FLOAT4_CUDA_KEPLER
+#define TEX_START_FLOAT_CUDA_KEPLER (TEX_NUM_FLOAT4_CUDA_KEPLER + TEX_NUM_BYTE4_CUDA_KEPLER)
+#define TEX_START_BYTE_CUDA_KEPLER (TEX_NUM_FLOAT4_CUDA_KEPLER + TEX_NUM_BYTE4_CUDA_KEPLER + TEX_NUM_BYTE_CUDA_KEPLER)
/* OpenCL */
-#define TEX_NUM_BYTE4_IMAGES_OPENCL 1024
-#define TEX_NUM_FLOAT4_IMAGES_OPENCL 1024
-#define TEX_NUM_FLOAT_IMAGES_OPENCL 0
-#define TEX_NUM_BYTE_IMAGES_OPENCL 0
-#define TEX_IMAGE_BYTE4_START_OPENCL TEX_NUM_FLOAT4_IMAGES_OPENCL
-#define TEX_IMAGE_FLOAT_START_OPENCL (TEX_NUM_FLOAT4_IMAGES_OPENCL + TEX_NUM_BYTE4_IMAGES_OPENCL)
-#define TEX_IMAGE_BYTE_START_OPENCL (TEX_NUM_FLOAT4_IMAGES_OPENCL + TEX_NUM_BYTE4_IMAGES_OPENCL + TEX_NUM_BYTE_IMAGES_OPENCL)
+#define TEX_NUM_FLOAT4_OPENCL 1024
+#define TEX_NUM_BYTE4_OPENCL 1024
+#define TEX_NUM_FLOAT_OPENCL 0
+#define TEX_NUM_BYTE_OPENCL 0
+#define TEX_START_FLOAT4_OPENCL 0
+#define TEX_START_BYTE4_OPENCL TEX_NUM_FLOAT4_OPENCL
+#define TEX_START_FLOAT_OPENCL (TEX_NUM_FLOAT4_OPENCL + TEX_NUM_BYTE4_OPENCL)
+#define TEX_START_BYTE_OPENCL (TEX_NUM_FLOAT4_OPENCL + TEX_NUM_BYTE4_OPENCL + TEX_NUM_BYTE_OPENCL)
/* Color to use when textures are not found. */
diff --git a/intern/cycles/util/util_thread.cpp b/intern/cycles/util/util_thread.cpp
new file mode 100644
index 00000000000..3db8b4bd197
--- /dev/null
+++ b/intern/cycles/util/util_thread.cpp
@@ -0,0 +1,66 @@
+/*
+ * Copyright 2011-2016 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "util_thread.h"
+
+#include "util_system.h"
+#include "util_windows.h"
+
+CCL_NAMESPACE_BEGIN
+
+thread::thread(function<void(void)> run_cb, int group)
+ : run_cb_(run_cb),
+ joined_(false),
+ group_(group)
+{
+ pthread_create(&pthread_id_, NULL, run, (void*)this);
+}
+
+thread::~thread()
+{
+ if(!joined_) {
+ join();
+ }
+}
+
+void *thread::run(void *arg)
+{
+ thread *self = (thread*)(arg);
+ if(self->group_ != -1) {
+#ifdef _WIN32
+ HANDLE thread_handle = GetCurrentThread();
+ GROUP_AFFINITY group_affinity = { 0 };
+ int num_threads = system_cpu_group_thread_count(self->group_);
+ group_affinity.Group = self->group_;
+ group_affinity.Mask = (num_threads == 64)
+ ? -1
+ : (1ull << num_threads) - 1;
+ if(SetThreadGroupAffinity(thread_handle, &group_affinity, NULL) == 0) {
+ fprintf(stderr, "Error setting thread affinity.\n");
+ }
+#endif
+ }
+ self->run_cb_();
+ return NULL;
+}
+
+bool thread::join()
+{
+ joined_ = true;
+ return pthread_join(pthread_id_, NULL) == 0;
+}
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/util/util_thread.h b/intern/cycles/util/util_thread.h
index 59575f31c13..427c633d2ce 100644
--- a/intern/cycles/util/util_thread.h
+++ b/intern/cycles/util/util_thread.h
@@ -52,37 +52,17 @@ typedef boost::condition_variable thread_condition_variable;
class thread {
public:
- thread(function<void(void)> run_cb_)
+ thread(function<void(void)> run_cb, int group = -1);
+ ~thread();
- {
- joined = false;
- run_cb = run_cb_;
-
- pthread_create(&pthread_id, NULL, run, (void*)this);
- }
-
- ~thread()
- {
- if(!joined)
- join();
- }
-
- static void *run(void *arg)
- {
- ((thread*)arg)->run_cb();
- return NULL;
- }
-
- bool join()
- {
- joined = true;
- return pthread_join(pthread_id, NULL) == 0;
- }
+ static void *run(void *arg);
+ bool join();
protected:
- function<void(void)> run_cb;
- pthread_t pthread_id;
- bool joined;
+ function<void(void)> run_cb_;
+ pthread_t pthread_id_;
+ bool joined_;
+ int group_;
};
/* Own wrapper around pthread's spin lock to make it's use easier. */
diff --git a/intern/cycles/util/util_windows.cpp b/intern/cycles/util/util_windows.cpp
new file mode 100644
index 00000000000..ee5b3fd73c0
--- /dev/null
+++ b/intern/cycles/util/util_windows.cpp
@@ -0,0 +1,88 @@
+/*
+ * Copyright 2011-2016 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "util_windows.h"
+
+#ifdef _WIN32
+
+CCL_NAMESPACE_BEGIN
+
+#ifdef _M_X64
+# include <VersionHelpers.h>
+#endif
+
+#if _WIN32_WINNT < 0x0601
+tGetActiveProcessorGroupCount *GetActiveProcessorGroupCount;
+tGetActiveProcessorCount *GetActiveProcessorCount;
+tSetThreadGroupAffinity *SetThreadGroupAffinity;
+#endif
+
+static WORD GetActiveProcessorGroupCount_stub()
+{
+ return 1;
+}
+
+static DWORD GetActiveProcessorCount_stub(WORD /*GroupNumber*/)
+{
+ SYSTEM_INFO info;
+ GetSystemInfo(&info);
+ return info.dwNumberOfProcessors;
+}
+
+static BOOL SetThreadGroupAffinity_stub(
+ HANDLE /*hThread*/,
+ const GROUP_AFFINITY * /*GroupAffinity*/,
+ PGROUP_AFFINITY /*PreviousGroupAffinity*/)
+{
+ return TRUE;
+}
+
+static bool supports_numa()
+{
+#ifndef _M_X64
+ return false;
+#else
+ return IsWindows7OrGreater();
+#endif
+}
+
+void util_windows_init_numa_groups()
+{
+ static bool initialized = false;
+ if(initialized) {
+ return;
+ }
+ initialized = true;
+#if _WIN32_WINNT < 0x0601
+ if(!supports_numa()) {
+ /* Use stubs on platforms which doesn't have rean NUMA/Groups. */
+ GetActiveProcessorGroupCount = GetActiveProcessorGroupCount_stub;
+ GetActiveProcessorCount = GetActiveProcessorCount_stub;
+ SetThreadGroupAffinity = SetThreadGroupAffinity_stub;
+ return;
+ }
+ HMODULE kernel = GetModuleHandleA("kernel32.dll");
+# define READ_SYMBOL(sym) sym = (t##sym*)GetProcAddress(kernel, #sym)
+ READ_SYMBOL(GetActiveProcessorGroupCount);
+ READ_SYMBOL(GetActiveProcessorCount);
+ READ_SYMBOL(SetThreadGroupAffinity);
+# undef READ_SUMBOL
+#endif
+}
+
+CCL_NAMESPACE_END
+
+#endif /* _WIN32 */
diff --git a/intern/cycles/util/util_windows.h b/intern/cycles/util/util_windows.h
index f67e34d0f31..ac61d5348c3 100644
--- a/intern/cycles/util/util_windows.h
+++ b/intern/cycles/util/util_windows.h
@@ -31,6 +31,25 @@
#include <windows.h>
+CCL_NAMESPACE_BEGIN
+
+#if _WIN32_WINNT < 0x0601
+typedef WORD tGetActiveProcessorGroupCount();
+typedef DWORD tGetActiveProcessorCount(WORD GroupNumber);
+typedef BOOL tSetThreadGroupAffinity(HANDLE hThread,
+ const GROUP_AFFINITY *GroupAffinity,
+ PGROUP_AFFINITY PreviousGroupAffinity);
+
+extern tGetActiveProcessorGroupCount *GetActiveProcessorGroupCount;
+extern tGetActiveProcessorCount *GetActiveProcessorCount;
+extern tSetThreadGroupAffinity *SetThreadGroupAffinity;
+#endif
+
+/* Make sure NUMA and processor groups API is initialized. */
+void util_windows_init_numa_groups();
+
+CCL_NAMESPACE_END
+
#endif /* WIN32 */
#endif /* __UTIL_WINDOWS_H__ */
diff --git a/intern/ghost/intern/GHOST_ContextSDL.cpp b/intern/ghost/intern/GHOST_ContextSDL.cpp
index d80a638818c..39627fac899 100644
--- a/intern/ghost/intern/GHOST_ContextSDL.cpp
+++ b/intern/ghost/intern/GHOST_ContextSDL.cpp
@@ -69,7 +69,7 @@ GHOST_ContextSDL::GHOST_ContextSDL(
GHOST_ContextSDL::~GHOST_ContextSDL()
{
if (m_context != NULL) {
- if (m_window != 0 && m_context == SDL_GL_GetCurrentContext())
+ if (m_window != NULL && m_context == SDL_GL_GetCurrentContext())
SDL_GL_MakeCurrent(m_window, m_context);
if (m_context != s_sharedContext || s_sharedCount == 1) {
diff --git a/intern/ghost/intern/GHOST_DropTargetWin32.cpp b/intern/ghost/intern/GHOST_DropTargetWin32.cpp
index fd9abce96b7..96ff79aa65a 100644
--- a/intern/ghost/intern/GHOST_DropTargetWin32.cpp
+++ b/intern/ghost/intern/GHOST_DropTargetWin32.cpp
@@ -75,7 +75,7 @@ HRESULT __stdcall GHOST_DropTargetWin32::QueryInterface(REFIID riid, void **ppvO
return S_OK;
}
else {
- *ppvObj = 0;
+ *ppvObj = NULL;
return E_NOINTERFACE;
}
}
@@ -97,8 +97,7 @@ ULONG __stdcall GHOST_DropTargetWin32::Release(void)
{
ULONG refs = ::InterlockedDecrement(&m_cRef);
- if (refs == 0)
- {
+ if (refs == 0) {
delete this;
return 0;
}
diff --git a/intern/ghost/intern/GHOST_ISystem.cpp b/intern/ghost/intern/GHOST_ISystem.cpp
index d7dd2b1cde1..37d5926ffc2 100644
--- a/intern/ghost/intern/GHOST_ISystem.cpp
+++ b/intern/ghost/intern/GHOST_ISystem.cpp
@@ -54,7 +54,7 @@
# endif
#endif
-GHOST_ISystem *GHOST_ISystem::m_system = 0;
+GHOST_ISystem *GHOST_ISystem::m_system = NULL;
GHOST_TSuccess GHOST_ISystem::createSystem()
@@ -76,7 +76,7 @@ GHOST_TSuccess GHOST_ISystem::createSystem()
# endif
# endif
#endif
- success = m_system != 0 ? GHOST_kSuccess : GHOST_kFailure;
+ success = m_system != NULL ? GHOST_kSuccess : GHOST_kFailure;
}
else {
success = GHOST_kFailure;
@@ -92,7 +92,7 @@ GHOST_TSuccess GHOST_ISystem::disposeSystem()
GHOST_TSuccess success = GHOST_kSuccess;
if (m_system) {
delete m_system;
- m_system = 0;
+ m_system = NULL;
}
else {
success = GHOST_kFailure;
diff --git a/intern/ghost/intern/GHOST_ISystemPaths.cpp b/intern/ghost/intern/GHOST_ISystemPaths.cpp
index 6ebcb37ba06..93ca0bc3880 100644
--- a/intern/ghost/intern/GHOST_ISystemPaths.cpp
+++ b/intern/ghost/intern/GHOST_ISystemPaths.cpp
@@ -36,6 +36,9 @@
* \date May 7, 2001
*/
+
+#include <stdio.h> /* just for NULL */
+
#include "GHOST_ISystemPaths.h"
#ifdef WIN32
@@ -49,7 +52,7 @@
#endif
-GHOST_ISystemPaths *GHOST_ISystemPaths::m_systemPaths = 0;
+GHOST_ISystemPaths *GHOST_ISystemPaths::m_systemPaths = NULL;
GHOST_TSuccess GHOST_ISystemPaths::create()
@@ -65,7 +68,7 @@ GHOST_TSuccess GHOST_ISystemPaths::create()
m_systemPaths = new GHOST_SystemPathsUnix();
# endif
#endif
- success = m_systemPaths != 0 ? GHOST_kSuccess : GHOST_kFailure;
+ success = m_systemPaths != NULL ? GHOST_kSuccess : GHOST_kFailure;
}
else {
success = GHOST_kFailure;
@@ -78,7 +81,7 @@ GHOST_TSuccess GHOST_ISystemPaths::dispose()
GHOST_TSuccess success = GHOST_kSuccess;
if (m_systemPaths) {
delete m_systemPaths;
- m_systemPaths = 0;
+ m_systemPaths = NULL;
}
else {
success = GHOST_kFailure;
diff --git a/intern/ghost/intern/GHOST_NDOFManager.cpp b/intern/ghost/intern/GHOST_NDOFManager.cpp
index 27285e49e9e..f18b7911f45 100644
--- a/intern/ghost/intern/GHOST_NDOFManager.cpp
+++ b/intern/ghost/intern/GHOST_NDOFManager.cpp
@@ -299,6 +299,12 @@ bool GHOST_NDOFManager::setDevice(unsigned short vendor_id, unsigned short produ
m_buttonMask = 0x07C0F137;
m_hidMap = Modern3Dx_HID_map;
break;
+ case 0xC633:
+ puts("ndof: using SpaceMouse Enterprise");
+ m_deviceType = NDOF_SpaceMouseEnterprise;
+ m_buttonCount = 31;
+ m_hidMap = Modern3Dx_HID_map;
+ break;
default:
printf("ndof: unknown 3Dconnexion product %04hx\n", product_id);
diff --git a/intern/ghost/intern/GHOST_NDOFManager.h b/intern/ghost/intern/GHOST_NDOFManager.h
index ba82f37bb2a..d3c70bbac50 100644
--- a/intern/ghost/intern/GHOST_NDOFManager.h
+++ b/intern/ghost/intern/GHOST_NDOFManager.h
@@ -40,6 +40,7 @@ typedef enum {
NDOF_SpaceMousePro,
NDOF_SpaceMouseWireless,
NDOF_SpaceMouseProWireless,
+ NDOF_SpaceMouseEnterprise,
// older devices
NDOF_SpacePilot,
diff --git a/intern/ghost/intern/GHOST_System.cpp b/intern/ghost/intern/GHOST_System.cpp
index 735f15777f2..c53580818e6 100644
--- a/intern/ghost/intern/GHOST_System.cpp
+++ b/intern/ghost/intern/GHOST_System.cpp
@@ -88,7 +88,7 @@ GHOST_ITimerTask *GHOST_System::installTimer(GHOST_TUns64 delay,
}
else {
delete timer;
- timer = 0;
+ timer = NULL;
}
}
return timer;
@@ -328,27 +328,22 @@ GHOST_TSuccess GHOST_System::exit()
if (getFullScreen()) {
endFullScreen();
}
- if (m_displayManager) {
- delete m_displayManager;
- m_displayManager = NULL;
- }
- if (m_windowManager) {
- delete m_windowManager;
- m_windowManager = NULL;
- }
- if (m_timerManager) {
- delete m_timerManager;
- m_timerManager = NULL;
- }
- if (m_eventManager) {
- delete m_eventManager;
- m_eventManager = NULL;
- }
+
+ delete m_displayManager;
+ m_displayManager = NULL;
+
+ delete m_windowManager;
+ m_windowManager = NULL;
+
+ delete m_timerManager;
+ m_timerManager = NULL;
+
+ delete m_eventManager;
+ m_eventManager = NULL;
+
#ifdef WITH_INPUT_NDOF
- if (m_ndofManager) {
- delete m_ndofManager;
- m_ndofManager = 0;
- }
+ delete m_ndofManager;
+ m_ndofManager = NULL;
#endif
return GHOST_kSuccess;
}
diff --git a/intern/ghost/intern/GHOST_SystemCocoa.mm b/intern/ghost/intern/GHOST_SystemCocoa.mm
index bf44d938a47..c9855cfdf7e 100644
--- a/intern/ghost/intern/GHOST_SystemCocoa.mm
+++ b/intern/ghost/intern/GHOST_SystemCocoa.mm
@@ -539,7 +539,7 @@ GHOST_IWindow* GHOST_SystemCocoa::createWindow(
)
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
- GHOST_IWindow* window = 0;
+ GHOST_IWindow* window = NULL;
//Get the available rect for including window contents
NSRect frame = [[NSScreen mainScreen] visibleFrame];
@@ -567,7 +567,7 @@ GHOST_IWindow* GHOST_SystemCocoa::createWindow(
else {
GHOST_PRINT("GHOST_SystemCocoa::createWindow(): window invalid\n");
delete window;
- window = 0;
+ window = NULL;
}
[pool drain];
diff --git a/intern/ghost/intern/GHOST_SystemWin32.cpp b/intern/ghost/intern/GHOST_SystemWin32.cpp
index 9a11c7287ff..ed08ce02f47 100644
--- a/intern/ghost/intern/GHOST_SystemWin32.cpp
+++ b/intern/ghost/intern/GHOST_SystemWin32.cpp
@@ -254,7 +254,7 @@ GHOST_IWindow *GHOST_SystemWin32::createWindow(
else {
GHOST_PRINT("GHOST_SystemWin32::createWindow(): window invalid\n");
delete window;
- window = 0;
+ window = NULL;
}
return window;
@@ -771,7 +771,7 @@ GHOST_EventKey *GHOST_SystemWin32::processKeyEvent(GHOST_WindowWin32 *window, RA
// GHOST_PRINTF("%c\n", ascii); // we already get this info via EventPrinter
}
else {
- event = 0;
+ event = NULL;
}
return event;
}
@@ -905,7 +905,7 @@ bool GHOST_SystemWin32::processNDOF(RAWINPUT const &raw)
LRESULT WINAPI GHOST_SystemWin32::s_wndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
- GHOST_Event *event = 0;
+ GHOST_Event *event = NULL;
bool eventHandled = false;
LRESULT lResult = 0;
diff --git a/intern/ghost/intern/GHOST_SystemX11.cpp b/intern/ghost/intern/GHOST_SystemX11.cpp
index 316e69400eb..25daa8ce2a7 100644
--- a/intern/ghost/intern/GHOST_SystemX11.cpp
+++ b/intern/ghost/intern/GHOST_SystemX11.cpp
@@ -302,7 +302,7 @@ createWindow(const STR_String& title,
const bool exclusive,
const GHOST_TEmbedderWindowID parentWindow)
{
- GHOST_WindowX11 *window = 0;
+ GHOST_WindowX11 *window = NULL;
if (!m_display) return 0;
@@ -325,7 +325,7 @@ createWindow(const STR_String& title,
}
else {
delete window;
- window = 0;
+ window = NULL;
}
}
return window;
diff --git a/intern/ghost/intern/GHOST_Window.h b/intern/ghost/intern/GHOST_Window.h
index 52cb9cbf54b..d778628ea37 100644
--- a/intern/ghost/intern/GHOST_Window.h
+++ b/intern/ghost/intern/GHOST_Window.h
@@ -106,7 +106,7 @@ public:
* \return The validity of the window.
*/
virtual bool getValid() const {
- return m_context != 0;
+ return m_context != NULL;
}
/**
diff --git a/intern/ghost/intern/GHOST_WindowCocoa.mm b/intern/ghost/intern/GHOST_WindowCocoa.mm
index b3fc8efbab1..00e00b6a1ea 100644
--- a/intern/ghost/intern/GHOST_WindowCocoa.mm
+++ b/intern/ghost/intern/GHOST_WindowCocoa.mm
@@ -663,7 +663,7 @@ GHOST_WindowCocoa::~GHOST_WindowCocoa()
bool GHOST_WindowCocoa::getValid() const
{
- return GHOST_Window::getValid() && m_window != 0 && m_openGLView != 0;
+ return GHOST_Window::getValid() && m_window != NULL && m_openGLView != NULL;
}
void* GHOST_WindowCocoa::getOSWindow() const
diff --git a/intern/ghost/intern/GHOST_WindowManager.cpp b/intern/ghost/intern/GHOST_WindowManager.cpp
index 83490cecce5..790c73deca5 100644
--- a/intern/ghost/intern/GHOST_WindowManager.cpp
+++ b/intern/ghost/intern/GHOST_WindowManager.cpp
@@ -110,7 +110,7 @@ bool GHOST_WindowManager::getWindowFound(const GHOST_IWindow *window) const
bool GHOST_WindowManager::getFullScreen(void) const
{
- return m_fullScreenWindow != 0;
+ return m_fullScreenWindow != NULL;
}
@@ -140,13 +140,13 @@ GHOST_TSuccess GHOST_WindowManager::endFullScreen(void)
{
GHOST_TSuccess success = GHOST_kFailure;
if (getFullScreen()) {
- if (m_fullScreenWindow != 0) {
+ if (m_fullScreenWindow != NULL) {
//GHOST_PRINT("GHOST_WindowManager::endFullScreen(): deleting full-screen window\n");
setWindowInactive(m_fullScreenWindow);
m_fullScreenWindow->endFullScreen();
delete m_fullScreenWindow;
//GHOST_PRINT("GHOST_WindowManager::endFullScreen(): done\n");
- m_fullScreenWindow = 0;
+ m_fullScreenWindow = NULL;
if (m_activeWindowBeforeFullScreen) {
setActiveWindow(m_activeWindowBeforeFullScreen);
}
@@ -181,7 +181,7 @@ GHOST_IWindow *GHOST_WindowManager::getActiveWindow(void) const
void GHOST_WindowManager::setWindowInactive(const GHOST_IWindow *window)
{
if (window == m_activeWindow) {
- m_activeWindow = 0;
+ m_activeWindow = NULL;
}
}
diff --git a/intern/ghost/intern/GHOST_WindowWin32.cpp b/intern/ghost/intern/GHOST_WindowWin32.cpp
index 4171fdc2dd8..c9bcb38ab68 100644
--- a/intern/ghost/intern/GHOST_WindowWin32.cpp
+++ b/intern/ghost/intern/GHOST_WindowWin32.cpp
@@ -361,8 +361,7 @@ GHOST_WindowWin32::~GHOST_WindowWin32()
if (fpWTClose) {
if (m_tablet)
fpWTClose(m_tablet);
- if (m_tabletData)
- delete m_tabletData;
+ delete m_tabletData;
m_tabletData = NULL;
}
}
diff --git a/intern/opencolorio/gpu_shader_display_transform.glsl b/intern/opencolorio/gpu_shader_display_transform.glsl
index 5921d6d9c73..853bf575582 100644
--- a/intern/opencolorio/gpu_shader_display_transform.glsl
+++ b/intern/opencolorio/gpu_shader_display_transform.glsl
@@ -38,7 +38,7 @@ float read_curve_mapping(int table, int index)
* But is it actually correct to subtract 1 here?
*/
float texture_index = float(index) / float(curve_mapping_lut_size - 1);
- return texture1D(curve_mapping_texture, texture_index) [table];
+ return texture1D(curve_mapping_texture, texture_index)[table];
}
float curvemap_calc_extend(int table, float x, vec2 first, vec2 last)
diff --git a/intern/opensubdiv/gpu_shader_opensubd_display.glsl b/intern/opensubdiv/gpu_shader_opensubd_display.glsl
index 51e8ed46c34..a17dcef81c7 100644
--- a/intern/opensubdiv/gpu_shader_opensubd_display.glsl
+++ b/intern/opensubdiv/gpu_shader_opensubd_display.glsl
@@ -111,7 +111,7 @@ void emit(int index, vec3 normal)
outpt.v.normal = normal;
/* TODO(sergey): Only uniform subdivisions atm. */
- vec2 quadst[4] = vec2[](vec2(0,0), vec2(1,0), vec2(1,1), vec2(0,1));
+ vec2 quadst[4] = vec2[](vec2(0, 0), vec2(1, 0), vec2(1, 1), vec2(0, 1));
vec2 st = quadst[index];
INTERP_FACE_VARYING_2(outpt.v.uv, osd_active_uv_offset, st);
@@ -135,7 +135,7 @@ void emit(int index)
outpt.v.normal = inpt[index].v.normal;
/* TODO(sergey): Only uniform subdivisions atm. */
- vec2 quadst[4] = vec2[](vec2(0,0), vec2(1,0), vec2(1,1), vec2(0,1));
+ vec2 quadst[4] = vec2[](vec2(0, 0), vec2(1, 0), vec2(1, 1), vec2(0, 1));
vec2 st = quadst[index];
INTERP_FACE_VARYING_2(outpt.v.uv, osd_active_uv_offset, st);
@@ -261,7 +261,7 @@ void main()
#else /* USE_COLOR_MATERIAL */
vec3 varying_position = inpt.v.position.xyz;
vec3 V = (gl_ProjectionMatrix[3][3] == 0.0) ?
- normalize(varying_position): vec3(0.0, 0.0, -1.0);
+ normalize(varying_position) : vec3(0.0, 0.0, -1.0);
for (int i = 0; i < num_enabled_lights; i++) {
/* todo: this is a slow check for disabled lights */
if (lightSource[i].specular.a == 0.0)
@@ -299,7 +299,7 @@ void main()
/* diffuse light */
vec3 light_diffuse = lightSource[i].diffuse.rgb;
float diffuse_bsdf = max(dot(N, light_direction), 0.0);
- L_diffuse += light_diffuse*diffuse_bsdf*intensity;
+ L_diffuse += light_diffuse * diffuse_bsdf * intensity;
/* specular light */
vec3 light_specular = lightSource[i].specular.rgb;
@@ -307,7 +307,7 @@ void main()
float specular_bsdf = pow(max(dot(N, H), 0.0),
gl_FrontMaterial.shininess);
- L_specular += light_specular*specular_bsdf * intensity;
+ L_specular += light_specular * specular_bsdf * intensity;
}
#endif /* USE_COLOR_MATERIAL */
diff --git a/release/scripts/modules/bl_i18n_utils/utils_spell_check.py b/release/scripts/modules/bl_i18n_utils/utils_spell_check.py
index df014e8262b..636b6b0f46b 100644
--- a/release/scripts/modules/bl_i18n_utils/utils_spell_check.py
+++ b/release/scripts/modules/bl_i18n_utils/utils_spell_check.py
@@ -58,7 +58,7 @@ class SpellChecker:
"vertices",
# Merged words
- "addon", "addons",
+ #~ "addon", "addons",
"antialiasing",
"arcsine", "arccosine", "arctangent",
"autoclip",
@@ -118,6 +118,7 @@ class SpellChecker:
"localview",
"lookup", "lookups",
"mathutils",
+ "micropolygon",
"midlevel",
"midground",
"mixdown",
@@ -127,6 +128,7 @@ class SpellChecker:
"multires", "multiresolution",
"multisampling",
"multitexture",
+ "multithreaded",
"multiuser",
"multiview",
"namespace",
@@ -412,6 +414,7 @@ class SpellChecker:
# Blender terms
"audaspace",
"bbone",
+ "bendy", # bones
"bmesh",
"breakdowner",
"bspline",
@@ -473,9 +476,10 @@ class SpellChecker:
"wpaint",
"uvwarp",
- # Algorithm names
+ # Algorithm/library names
"ashikhmin", # Ashikhmin-Shirley
"beckmann",
+ "blosc",
"catmull",
"catrom",
"chebychev",
diff --git a/release/scripts/modules/bpy_types.py b/release/scripts/modules/bpy_types.py
index c1a37d10961..d194de32bf3 100644
--- a/release/scripts/modules/bpy_types.py
+++ b/release/scripts/modules/bpy_types.py
@@ -408,6 +408,14 @@ class Mesh(bpy_types.ID):
the *vertices* argument. eg: [(5, 6, 8, 9), (1, 2, 3), ...]
:type faces: iterable object
+
+ .. warning::
+
+ Invalid mesh data
+ *(out of range indices, edges with matching indices,
+ 2 sided faces... etc)* are **not** prevented.
+ If the data used for mesh creation isn't known to be valid,
+ run :class:`Mesh.validate` after this function.
"""
from itertools import chain, islice, accumulate
diff --git a/release/scripts/presets/interface_theme/blender_24x.xml b/release/scripts/presets/interface_theme/blender_24x.xml
index 445c23b4c4e..90730aeaebc 100644
--- a/release/scripts/presets/interface_theme/blender_24x.xml
+++ b/release/scripts/presets/interface_theme/blender_24x.xml
@@ -179,7 +179,7 @@
</wcol_tooltip>
<wcol_menu_item>
<ThemeWidgetColors outline="#000000"
- inner="#00000000"
+ inner="#d2d2d200"
inner_sel="#7f7f7fff"
item="#ffffffff"
text="#000000"
@@ -371,7 +371,7 @@
header="#b4b4b4"
header_text="#000000"
header_text_hi="#ffffff"
- button="#727272ff"
+ button="#b4b4b457"
button_title="#000000"
button_text="#000000"
button_text_hi="#ffffff"
diff --git a/release/scripts/presets/keyconfig/maya.py b/release/scripts/presets/keyconfig/maya.py
index cdd16f26877..67fd1fddcac 100644
--- a/release/scripts/presets/keyconfig/maya.py
+++ b/release/scripts/presets/keyconfig/maya.py
@@ -698,7 +698,7 @@ kmi.properties.level = 5
km = kc.keymaps.new('Knife Tool Modal Map', space_type='EMPTY', region_type='WINDOW', modal=True)
kmi = km.keymap_items.new_modal('CANCEL', 'ESC', 'ANY', any=True)
-kmi = km.keymap_items.new_modal('ADD_CUT', 'LEFTMOUSE', 'ANY')
+kmi = km.keymap_items.new_modal('ADD_CUT', 'LEFTMOUSE', 'ANY', any=True)
kmi = km.keymap_items.new_modal('PANNING', 'LEFTMOUSE', 'ANY', alt=True)
kmi = km.keymap_items.new_modal('PANNING', 'MIDDLEMOUSE', 'ANY', alt=True)
kmi = km.keymap_items.new_modal('PANNING', 'RIGHTMOUSE', 'ANY', alt=True)
diff --git a/release/scripts/startup/bl_operators/wm.py b/release/scripts/startup/bl_operators/wm.py
index 76d41d91b78..cc8921f1a8e 100644
--- a/release/scripts/startup/bl_operators/wm.py
+++ b/release/scripts/startup/bl_operators/wm.py
@@ -1357,7 +1357,10 @@ class WM_OT_properties_add(Operator):
return prop_new
- prop = unique_name(item.keys())
+ prop = unique_name(
+ {*item.keys(),
+ *type(item).bl_rna.properties.keys(),
+ })
item[prop] = 1.0
rna_idprop_ui_prop_update(item, prop)
diff --git a/release/scripts/startup/bl_ui/__init__.py b/release/scripts/startup/bl_ui/__init__.py
index 6fc668e67f5..2389be6787d 100644
--- a/release/scripts/startup/bl_ui/__init__.py
+++ b/release/scripts/startup/bl_ui/__init__.py
@@ -126,7 +126,7 @@ def register():
WindowManager.addon_filter = EnumProperty(
items=addon_filter_items,
name="Category",
- description="Filter addons by category",
+ description="Filter add-ons by category",
)
WindowManager.addon_support = EnumProperty(
diff --git a/release/scripts/startup/bl_ui/properties_data_modifier.py b/release/scripts/startup/bl_ui/properties_data_modifier.py
index aa03863a198..7863c075344 100644
--- a/release/scripts/startup/bl_ui/properties_data_modifier.py
+++ b/release/scripts/startup/bl_ui/properties_data_modifier.py
@@ -1418,6 +1418,7 @@ class DATA_PT_modifiers(ModifierButtonsPanel, Panel):
sub = row.row(align=True)
sub.active = has_vgroup
sub.prop(md, "invert_vertex_group", text="", icon='ARROW_LEFTRIGHT')
+ subcol.prop(md, "mix_limit")
def CORRECTIVE_SMOOTH(self, layout, ob, md):
is_bind = md.is_bind
diff --git a/release/scripts/startup/bl_ui/properties_render.py b/release/scripts/startup/bl_ui/properties_render.py
index 13e7265319b..4ea1c3a5cc7 100644
--- a/release/scripts/startup/bl_ui/properties_render.py
+++ b/release/scripts/startup/bl_ui/properties_render.py
@@ -248,6 +248,7 @@ class RENDER_PT_shading(RenderButtonsPanel, Panel):
col = split.column()
col.prop(rd, "use_raytrace", text="Ray Tracing")
col.prop(rd, "alpha_mode", text="Alpha")
+ col.prop(rd, "use_world_space_shading", text="World Space Shading")
class RENDER_PT_performance(RenderButtonsPanel, Panel):
diff --git a/source/blender/blenkernel/BKE_DerivedMesh.h b/source/blender/blenkernel/BKE_DerivedMesh.h
index 2b13a847e14..8ccc4a6eb0e 100644
--- a/source/blender/blenkernel/BKE_DerivedMesh.h
+++ b/source/blender/blenkernel/BKE_DerivedMesh.h
@@ -757,22 +757,22 @@ void DM_update_weight_mcol(
typedef struct DMVertexAttribs {
struct {
struct MLoopUV *array;
- int em_offset, gl_index, gl_texco;
+ int em_offset, gl_index, gl_texco, gl_info_index;
} tface[MAX_MTFACE];
struct {
struct MLoopCol *array;
- int em_offset, gl_index;
+ int em_offset, gl_index, gl_info_index;
} mcol[MAX_MCOL];
struct {
float (*array)[4];
- int em_offset, gl_index;
+ int em_offset, gl_index, gl_info_index;
} tang[MAX_MTFACE];
struct {
float (*array)[3];
- int em_offset, gl_index, gl_texco;
+ int em_offset, gl_index, gl_texco, gl_info_index;
} orco;
int tottface, totmcol, tottang, totorco;
diff --git a/source/blender/blenkernel/BKE_animsys.h b/source/blender/blenkernel/BKE_animsys.h
index dc751747f32..6524afff051 100644
--- a/source/blender/blenkernel/BKE_animsys.h
+++ b/source/blender/blenkernel/BKE_animsys.h
@@ -177,7 +177,7 @@ void BKE_animsys_evaluate_all_animation(struct Main *main, struct Scene *scene,
/* TODO(sergey): This is mainly a temp public function. */
struct FCurve;
-bool BKE_animsys_execute_fcurve(struct PointerRNA *ptr, struct AnimMapper *remap, struct FCurve *fcu);
+bool BKE_animsys_execute_fcurve(struct PointerRNA *ptr, struct AnimMapper *remap, struct FCurve *fcu, float curval);
/* ------------ Specialized API --------------- */
/* There are a few special tools which require these following functions. They are NOT to be used
diff --git a/source/blender/blenkernel/BKE_fcurve.h b/source/blender/blenkernel/BKE_fcurve.h
index 2022d11d508..bb4eb652ae2 100644
--- a/source/blender/blenkernel/BKE_fcurve.h
+++ b/source/blender/blenkernel/BKE_fcurve.h
@@ -279,7 +279,7 @@ void correct_bezpart(float v1[2], float v2[2], float v3[2], float v4[2]);
/* evaluate fcurve */
float evaluate_fcurve(struct FCurve *fcu, float evaltime);
/* evaluate fcurve and store value */
-void calculate_fcurve(struct FCurve *fcu, float ctime);
+float calculate_fcurve(struct FCurve *fcu, float evaltime);
/* ************* F-Curve Samples API ******************** */
diff --git a/source/blender/blenkernel/BKE_library_idmap.h b/source/blender/blenkernel/BKE_library_idmap.h
new file mode 100644
index 00000000000..971586ea8b7
--- /dev/null
+++ b/source/blender/blenkernel/BKE_library_idmap.h
@@ -0,0 +1,50 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+#ifndef __BKE_LIBRARY_IDMAP_H__
+#define __BKE_LIBRARY_IDMAP_H__
+
+/** \file BKE_library_idmap.h
+ * \ingroup bke
+ */
+
+#include "BLI_compiler_attrs.h"
+
+struct ID;
+struct Main;
+struct IDNameLib_Map;
+
+struct IDNameLib_Map *BKE_main_idmap_create(
+ struct Main *bmain)
+ ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+void BKE_main_idmap_destroy(
+ struct IDNameLib_Map *id_typemap)
+ ATTR_NONNULL();
+struct Main *BKE_main_idmap_main_get(
+ struct IDNameLib_Map *id_typemap)
+ ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+struct ID *BKE_main_idmap_lookup(
+ struct IDNameLib_Map *id_typemap,
+ short id_type, const char *name, const struct Library *lib)
+ ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1, 3);
+struct ID *BKE_main_idmap_lookup_id(
+ struct IDNameLib_Map *id_typemap, const struct ID *id)
+ ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1, 2);
+
+#endif /* __BKE_LIBRARY_IDMAP_H__ */
diff --git a/source/blender/blenkernel/BKE_mesh.h b/source/blender/blenkernel/BKE_mesh.h
index c7d5857b873..d8d869015a3 100644
--- a/source/blender/blenkernel/BKE_mesh.h
+++ b/source/blender/blenkernel/BKE_mesh.h
@@ -323,7 +323,7 @@ void BKE_mesh_mdisp_flip(struct MDisps *md, const bool use_loop_mdisp_flip);
void BKE_mesh_polygon_flip_ex(
struct MPoly *mpoly, struct MLoop *mloop, struct CustomData *ldata,
- struct MDisps *mdisp, const bool use_loop_mdisp_flip);
+ float (*lnors)[3], struct MDisps *mdisp, const bool use_loop_mdisp_flip);
void BKE_mesh_polygon_flip(struct MPoly *mpoly, struct MLoop *mloop, struct CustomData *ldata);
void BKE_mesh_polygons_flip(struct MPoly *mpoly, struct MLoop *mloop, struct CustomData *ldata, int totpoly);
diff --git a/source/blender/blenkernel/BKE_object.h b/source/blender/blenkernel/BKE_object.h
index 7d6096407ff..c591ec2a0aa 100644
--- a/source/blender/blenkernel/BKE_object.h
+++ b/source/blender/blenkernel/BKE_object.h
@@ -208,6 +208,8 @@ void BKE_object_eval_uber_data(struct EvaluationContext *eval_ctx,
struct Scene *scene,
struct Object *ob);
+void BKE_object_eval_proxy_backlink(struct EvaluationContext *eval_ctx, struct Object *ob);
+
void BKE_object_handle_data_update(struct EvaluationContext *eval_ctx,
struct Scene *scene,
struct Object *ob);
diff --git a/source/blender/blenkernel/BKE_scene.h b/source/blender/blenkernel/BKE_scene.h
index a4c44b9934e..12bfc07e958 100644
--- a/source/blender/blenkernel/BKE_scene.h
+++ b/source/blender/blenkernel/BKE_scene.h
@@ -135,6 +135,7 @@ float get_render_aosss_error(const struct RenderData *r, float error);
bool BKE_scene_use_new_shading_nodes(const struct Scene *scene);
bool BKE_scene_use_shading_nodes_custom(struct Scene *scene);
+bool BKE_scene_use_world_space_shading(struct Scene *scene);
bool BKE_scene_use_spherical_stereo(struct Scene *scene);
bool BKE_scene_uses_blender_internal(const struct Scene *scene);
diff --git a/source/blender/blenkernel/CMakeLists.txt b/source/blender/blenkernel/CMakeLists.txt
index afab0ccc5a5..86264224851 100644
--- a/source/blender/blenkernel/CMakeLists.txt
+++ b/source/blender/blenkernel/CMakeLists.txt
@@ -121,6 +121,7 @@ set(SRC
intern/lamp.c
intern/lattice.c
intern/library.c
+ intern/library_idmap.c
intern/library_query.c
intern/linestyle.c
intern/mask.c
@@ -244,6 +245,7 @@ set(SRC
BKE_lamp.h
BKE_lattice.h
BKE_library.h
+ BKE_library_idmap.h
BKE_library_query.h
BKE_linestyle.h
BKE_main.h
diff --git a/source/blender/blenkernel/intern/DerivedMesh.c b/source/blender/blenkernel/intern/DerivedMesh.c
index 1bfc3d90730..0de0e4d7797 100644
--- a/source/blender/blenkernel/intern/DerivedMesh.c
+++ b/source/blender/blenkernel/intern/DerivedMesh.c
@@ -2003,15 +2003,10 @@ static void mesh_calc_modifiers(
DM_add_edge_layer(dm, CD_ORIGINDEX, CD_CALLOC, NULL);
DM_add_poly_layer(dm, CD_ORIGINDEX, CD_CALLOC, NULL);
-#pragma omp parallel sections if (dm->numVertData + dm->numEdgeData + dm->numPolyData >= BKE_MESH_OMP_LIMIT)
- {
-#pragma omp section
- { range_vn_i(DM_get_vert_data_layer(dm, CD_ORIGINDEX), dm->numVertData, 0); }
-#pragma omp section
- { range_vn_i(DM_get_edge_data_layer(dm, CD_ORIGINDEX), dm->numEdgeData, 0); }
-#pragma omp section
- { range_vn_i(DM_get_poly_data_layer(dm, CD_ORIGINDEX), dm->numPolyData, 0); }
- }
+ /* Not worth parallelizing this, gives less than 0.1% overall speedup in best of best cases... */
+ range_vn_i(DM_get_vert_data_layer(dm, CD_ORIGINDEX), dm->numVertData, 0);
+ range_vn_i(DM_get_edge_data_layer(dm, CD_ORIGINDEX), dm->numEdgeData, 0);
+ range_vn_i(DM_get_poly_data_layer(dm, CD_ORIGINDEX), dm->numPolyData, 0);
}
}
@@ -3269,17 +3264,18 @@ void DM_calc_loop_tangents_step_0(
bool *rcalc_act, bool *rcalc_ren, int *ract_uv_n, int *rren_uv_n,
char *ract_uv_name, char *rren_uv_name, char *rtangent_mask) {
/* Active uv in viewport */
+ int layer_index = CustomData_get_layer_index(loopData, CD_MLOOPUV);
*ract_uv_n = CustomData_get_active_layer(loopData, CD_MLOOPUV);
ract_uv_name[0] = 0;
if (*ract_uv_n != -1) {
- strcpy(ract_uv_name, loopData->layers[*ract_uv_n].name);
+ strcpy(ract_uv_name, loopData->layers[*ract_uv_n + layer_index].name);
}
/* Active tangent in render */
*rren_uv_n = CustomData_get_render_layer(loopData, CD_MLOOPUV);
rren_uv_name[0] = 0;
if (*rren_uv_n != -1) {
- strcpy(rren_uv_name, loopData->layers[*rren_uv_n].name);
+ strcpy(rren_uv_name, loopData->layers[*rren_uv_n + layer_index].name);
}
/* If active tangent not in tangent_names we take it into account */
@@ -3629,12 +3625,41 @@ void DM_vertex_attributes_from_gpu(DerivedMesh *dm, GPUVertexAttribs *gattribs,
dm->calcLoopTangents(dm, false, (const char (*)[MAX_NAME])tangent_names, tangent_names_count);
for (b = 0; b < gattribs->totlayer; b++) {
- if (gattribs->layer[b].type == CD_MTFACE) {
+ int type = gattribs->layer[b].type;
+ layer = -1;
+ if (type == CD_AUTO_FROM_NAME) {
+ /* We need to deduct what exact layer is used.
+ *
+ * We do it based on the specified name.
+ */
+ if (gattribs->layer[b].name[0]) {
+ layer = CustomData_get_named_layer_index(&dm->loopData, CD_TANGENT, gattribs->layer[b].name);
+ type = CD_TANGENT;
+ if (layer == -1) {
+ layer = CustomData_get_named_layer_index(ldata, CD_MLOOPCOL, gattribs->layer[b].name);
+ type = CD_MCOL;
+ }
+ if (layer == -1) {
+ layer = CustomData_get_named_layer_index(ldata, CD_MLOOPUV, gattribs->layer[b].name);
+ type = CD_MTFACE;
+ }
+ if (layer == -1) {
+ continue;
+ }
+ }
+ else {
+ /* Fall back to the UV layer, which matches old behavior. */
+ type = CD_MTFACE;
+ }
+ }
+ if (type == CD_MTFACE) {
/* uv coordinates */
- if (gattribs->layer[b].name[0])
- layer = CustomData_get_named_layer_index(ldata, CD_MLOOPUV, gattribs->layer[b].name);
- else
- layer = CustomData_get_active_layer_index(ldata, CD_MLOOPUV);
+ if (layer == -1) {
+ if (gattribs->layer[b].name[0])
+ layer = CustomData_get_named_layer_index(ldata, CD_MLOOPUV, gattribs->layer[b].name);
+ else
+ layer = CustomData_get_active_layer_index(ldata, CD_MLOOPUV);
+ }
a = attribs->tottface++;
@@ -3648,13 +3673,16 @@ void DM_vertex_attributes_from_gpu(DerivedMesh *dm, GPUVertexAttribs *gattribs,
}
attribs->tface[a].gl_index = gattribs->layer[b].glindex;
+ attribs->tface[a].gl_info_index = gattribs->layer[b].glinfoindoex;
attribs->tface[a].gl_texco = gattribs->layer[b].gltexco;
}
- else if (gattribs->layer[b].type == CD_MCOL) {
- if (gattribs->layer[b].name[0])
- layer = CustomData_get_named_layer_index(ldata, CD_MLOOPCOL, gattribs->layer[b].name);
- else
- layer = CustomData_get_active_layer_index(ldata, CD_MLOOPCOL);
+ else if (type == CD_MCOL) {
+ if (layer == -1) {
+ if (gattribs->layer[b].name[0])
+ layer = CustomData_get_named_layer_index(ldata, CD_MLOOPCOL, gattribs->layer[b].name);
+ else
+ layer = CustomData_get_active_layer_index(ldata, CD_MLOOPCOL);
+ }
a = attribs->totmcol++;
@@ -3669,14 +3697,16 @@ void DM_vertex_attributes_from_gpu(DerivedMesh *dm, GPUVertexAttribs *gattribs,
}
attribs->mcol[a].gl_index = gattribs->layer[b].glindex;
+ attribs->mcol[a].gl_info_index = gattribs->layer[b].glinfoindoex;
}
- else if (gattribs->layer[b].type == CD_TANGENT) {
+ else if (type == CD_TANGENT) {
/* note, even with 'is_editmesh' this uses the derived-meshes loop data */
-
- if (gattribs->layer[b].name[0])
- layer = CustomData_get_named_layer_index(&dm->loopData, CD_TANGENT, gattribs->layer[b].name);
- else
- layer = CustomData_get_active_layer_index(&dm->loopData, CD_TANGENT);
+ if (layer == -1) {
+ if (gattribs->layer[b].name[0])
+ layer = CustomData_get_named_layer_index(&dm->loopData, CD_TANGENT, gattribs->layer[b].name);
+ else
+ layer = CustomData_get_active_layer_index(&dm->loopData, CD_TANGENT);
+ }
a = attribs->tottang++;
@@ -3690,10 +3720,13 @@ void DM_vertex_attributes_from_gpu(DerivedMesh *dm, GPUVertexAttribs *gattribs,
}
attribs->tang[a].gl_index = gattribs->layer[b].glindex;
+ attribs->tang[a].gl_info_index = gattribs->layer[b].glinfoindoex;
}
- else if (gattribs->layer[b].type == CD_ORCO) {
+ else if (type == CD_ORCO) {
/* original coordinates */
- layer = CustomData_get_layer_index(vdata, CD_ORCO);
+ if (layer == -1) {
+ layer = CustomData_get_layer_index(vdata, CD_ORCO);
+ }
attribs->totorco = 1;
if (layer != -1) {
@@ -3707,6 +3740,7 @@ void DM_vertex_attributes_from_gpu(DerivedMesh *dm, GPUVertexAttribs *gattribs,
attribs->orco.gl_index = gattribs->layer[b].glindex;
attribs->orco.gl_texco = gattribs->layer[b].gltexco;
+ attribs->orco.gl_info_index = gattribs->layer[b].glinfoindoex;
}
}
}
@@ -3735,6 +3769,7 @@ void DM_draw_attrib_vertex(DMVertexAttribs *attribs, int a, int index, int vert,
glTexCoord3fv(orco);
else
glVertexAttrib3fv(attribs->orco.gl_index, orco);
+ glUniform1i(attribs->orco.gl_info_index, 0);
}
/* uv texture coordinates */
@@ -3753,21 +3788,23 @@ void DM_draw_attrib_vertex(DMVertexAttribs *attribs, int a, int index, int vert,
glTexCoord2fv(uv);
else
glVertexAttrib2fv(attribs->tface[b].gl_index, uv);
+ glUniform1i(attribs->tface[b].gl_info_index, 0);
}
/* vertex colors */
for (b = 0; b < attribs->totmcol; b++) {
- GLubyte col[4];
+ GLfloat col[4];
if (attribs->mcol[b].array) {
const MLoopCol *cp = &attribs->mcol[b].array[loop];
- copy_v4_v4_uchar(col, &cp->r);
+ rgba_uchar_to_float(col, &cp->r);
}
else {
- col[0] = 0; col[1] = 0; col[2] = 0; col[3] = 0;
+ zero_v4(col);
}
- glVertexAttrib4ubv(attribs->mcol[b].gl_index, col);
+ glVertexAttrib4fv(attribs->mcol[b].gl_index, col);
+ glUniform1i(attribs->mcol[b].gl_info_index, GPU_ATTR_INFO_SRGB);
}
/* tangent for normal mapping */
@@ -3777,6 +3814,7 @@ void DM_draw_attrib_vertex(DMVertexAttribs *attribs, int a, int index, int vert,
const float *tang = (array) ? array[a * 4 + vert] : zero;
glVertexAttrib4fv(attribs->tang[b].gl_index, tang);
}
+ glUniform1i(attribs->tang[b].gl_info_index, 0);
}
}
diff --git a/source/blender/blenkernel/intern/anim_sys.c b/source/blender/blenkernel/intern/anim_sys.c
index 41950c59a22..99aae6239e8 100644
--- a/source/blender/blenkernel/intern/anim_sys.c
+++ b/source/blender/blenkernel/intern/anim_sys.c
@@ -730,14 +730,10 @@ static char *rna_path_rename_fix(ID *owner_id, const char *prefix, const char *o
DynStr *ds = BLI_dynstr_new();
const char *postfixPtr = oldNamePtr + oldNameLen;
char *newPath = NULL;
- char oldChar;
-
+
/* add the part of the string that goes up to the start of the prefix */
if (prefixPtr > oldpath) {
- oldChar = prefixPtr[0];
- prefixPtr[0] = 0;
- BLI_dynstr_append(ds, oldpath);
- prefixPtr[0] = oldChar;
+ BLI_dynstr_nappend(ds, oldpath, prefixPtr - oldpath);
}
/* add the prefix */
@@ -1620,7 +1616,7 @@ static bool animsys_write_rna_setting(PointerRNA *ptr, char *path, int array_ind
}
/* Simple replacement based data-setting of the FCurve using RNA */
-bool BKE_animsys_execute_fcurve(PointerRNA *ptr, AnimMapper *remap, FCurve *fcu)
+bool BKE_animsys_execute_fcurve(PointerRNA *ptr, AnimMapper *remap, FCurve *fcu, float curval)
{
char *path = NULL;
bool free_path = false;
@@ -1631,7 +1627,7 @@ bool BKE_animsys_execute_fcurve(PointerRNA *ptr, AnimMapper *remap, FCurve *fcu)
/* write value to setting */
if (path)
- ok = animsys_write_rna_setting(ptr, path, fcu->array_index, fcu->curval);
+ ok = animsys_write_rna_setting(ptr, path, fcu->array_index, curval);
/* free temp path-info */
if (free_path)
@@ -1654,8 +1650,8 @@ static void animsys_evaluate_fcurves(PointerRNA *ptr, ListBase *list, AnimMapper
if ((fcu->grp == NULL) || (fcu->grp->flag & AGRP_MUTED) == 0) {
/* check if this curve should be skipped */
if ((fcu->flag & (FCURVE_MUTED | FCURVE_DISABLED)) == 0) {
- calculate_fcurve(fcu, ctime);
- BKE_animsys_execute_fcurve(ptr, remap, fcu);
+ const float curval = calculate_fcurve(fcu, ctime);
+ BKE_animsys_execute_fcurve(ptr, remap, fcu, curval);
}
}
}
@@ -1684,8 +1680,8 @@ static void animsys_evaluate_drivers(PointerRNA *ptr, AnimData *adt, float ctime
/* evaluate this using values set already in other places
* NOTE: for 'layering' option later on, we should check if we should remove old value before adding
* new to only be done when drivers only changed */
- calculate_fcurve(fcu, ctime);
- ok = BKE_animsys_execute_fcurve(ptr, NULL, fcu);
+ const float curval = calculate_fcurve(fcu, ctime);
+ ok = BKE_animsys_execute_fcurve(ptr, NULL, fcu, curval);
/* clear recalc flag */
driver->flag &= ~DRIVER_FLAG_RECALC;
@@ -1753,8 +1749,8 @@ void animsys_evaluate_action_group(PointerRNA *ptr, bAction *act, bActionGroup *
for (fcu = agrp->channels.first; (fcu) && (fcu->grp == agrp); fcu = fcu->next) {
/* check if this curve should be skipped */
if ((fcu->flag & (FCURVE_MUTED | FCURVE_DISABLED)) == 0) {
- calculate_fcurve(fcu, ctime);
- BKE_animsys_execute_fcurve(ptr, remap, fcu);
+ const float curval = calculate_fcurve(fcu, ctime);
+ BKE_animsys_execute_fcurve(ptr, remap, fcu, curval);
}
}
}
@@ -2888,8 +2884,8 @@ void BKE_animsys_eval_driver(EvaluationContext *eval_ctx,
* NOTE: for 'layering' option later on, we should check if we should remove old value before adding
* new to only be done when drivers only changed */
//printf("\told val = %f\n", fcu->curval);
- calculate_fcurve(fcu, eval_ctx->ctime);
- ok = BKE_animsys_execute_fcurve(&id_ptr, NULL, fcu);
+ const float curval = calculate_fcurve(fcu, eval_ctx->ctime);
+ ok = BKE_animsys_execute_fcurve(&id_ptr, NULL, fcu, curval);
//printf("\tnew val = %f\n", fcu->curval);
/* clear recalc flag */
diff --git a/source/blender/blenkernel/intern/armature.c b/source/blender/blenkernel/intern/armature.c
index 5c95cde4d8d..04b4733fd44 100644
--- a/source/blender/blenkernel/intern/armature.c
+++ b/source/blender/blenkernel/intern/armature.c
@@ -475,7 +475,7 @@ void b_bone_spline_setup(bPoseChannel *pchan, int rest, Mat4 result_array[MAX_BB
{
bPoseChannel *next, *prev;
Bone *bone = pchan->bone;
- float h1[3], h2[3], scale[3], length, hlength1, hlength2, roll1 = 0.0f, roll2;
+ float h1[3], h2[3], scale[3], length, roll1 = 0.0f, roll2;
float mat3[3][3], imat[4][4], posemat[4][4], scalemat[4][4], iscalemat[4][4];
float data[MAX_BBONE_SUBDIV + 1][4], *fp;
int a;
@@ -496,9 +496,6 @@ void b_bone_spline_setup(bPoseChannel *pchan, int rest, Mat4 result_array[MAX_BB
}
}
- hlength1 = bone->ease1 * length * 0.390464f; /* 0.5f * sqrt(2) * kappa, the handle length for near-perfect circles */
- hlength2 = bone->ease2 * length * 0.390464f;
-
/* get "next" and "prev" bones - these are used for handle calculations */
if (pchan->bboneflag & PCHAN_BBONE_CUSTOM_HANDLES) {
/* use the provided bones as the next/prev - leave blank to eliminate this effect altogether */
@@ -563,7 +560,7 @@ void b_bone_spline_setup(bPoseChannel *pchan, int rest, Mat4 result_array[MAX_BB
}
normalize_v3(h1);
- mul_v3_fl(h1, -hlength1);
+ negate_v3(h1);
if (prev->bone->segments == 1) {
/* find the previous roll to interpolate */
@@ -582,7 +579,7 @@ void b_bone_spline_setup(bPoseChannel *pchan, int rest, Mat4 result_array[MAX_BB
}
}
else {
- h1[0] = 0.0f; h1[1] = hlength1; h1[2] = 0.0f;
+ h1[0] = 0.0f; h1[1] = 1.0; h1[2] = 0.0f;
roll1 = 0.0f;
}
if (next) {
@@ -635,14 +632,22 @@ void b_bone_spline_setup(bPoseChannel *pchan, int rest, Mat4 result_array[MAX_BB
roll2 = atan2f(mat3[2][0], mat3[2][2]);
- /* and only now negate handle */
- mul_v3_fl(h2, -hlength2);
}
else {
- h2[0] = 0.0f; h2[1] = -hlength2; h2[2] = 0.0f;
+ h2[0] = 0.0f; h2[1] = 1.0f; h2[2] = 0.0f;
roll2 = 0.0;
}
+ {
+ const float circle_factor = length * (cubic_tangent_factor_circle_v3(h1, h2) / 0.75f);
+ const float hlength1 = bone->ease1 * circle_factor;
+ const float hlength2 = bone->ease2 * circle_factor;
+
+ /* and only now negate h2 */
+ mul_v3_fl(h1, hlength1);
+ mul_v3_fl(h2, -hlength2);
+ }
+
/* Add effects from bbone properties over the top
* - These properties allow users to hand-animate the
* bone curve/shape, without having to resort to using
diff --git a/source/blender/blenkernel/intern/autoexec.c b/source/blender/blenkernel/intern/autoexec.c
index d9462cd0262..bde06b02ae8 100644
--- a/source/blender/blenkernel/intern/autoexec.c
+++ b/source/blender/blenkernel/intern/autoexec.c
@@ -59,7 +59,10 @@ bool BKE_autoexec_match(const char *path)
BLI_assert((U.flag & USER_SCRIPT_AUTOEXEC_DISABLE) == 0);
for (path_cmp = U.autoexec_paths.first; path_cmp; path_cmp = path_cmp->next) {
- if ((path_cmp->flag & USER_PATHCMP_GLOB)) {
+ if (path_cmp->path[0] == '\0') {
+ /* pass */
+ }
+ else if ((path_cmp->flag & USER_PATHCMP_GLOB)) {
if (fnmatch(path_cmp->path, path, fnmatch_flags) == 0) {
return true;
}
diff --git a/source/blender/blenkernel/intern/brush.c b/source/blender/blenkernel/intern/brush.c
index 31dac038e43..da7863096e3 100644
--- a/source/blender/blenkernel/intern/brush.c
+++ b/source/blender/blenkernel/intern/brush.c
@@ -852,7 +852,7 @@ int BKE_brush_size_get(const Scene *scene, const Brush *brush)
UnifiedPaintSettings *ups = &scene->toolsettings->unified_paint_settings;
int size = (ups->flag & UNIFIED_PAINT_SIZE) ? ups->size : brush->size;
- return (int)((float)size * U.pixelsize);
+ return size;
}
int BKE_brush_use_locked_size(const Scene *scene, const Brush *brush)
diff --git a/source/blender/blenkernel/intern/cdderivedmesh.c b/source/blender/blenkernel/intern/cdderivedmesh.c
index af1ad4900b3..392a38773e7 100644
--- a/source/blender/blenkernel/intern/cdderivedmesh.c
+++ b/source/blender/blenkernel/intern/cdderivedmesh.c
@@ -1032,6 +1032,7 @@ static void cdDM_drawMappedFacesGLSL(
if (matconv[a].attribs.totorco && matconv[a].attribs.orco.array) {
matconv[a].datatypes[numdata].index = matconv[a].attribs.orco.gl_index;
+ matconv[a].datatypes[numdata].info_index = matconv[a].attribs.orco.gl_info_index;
matconv[a].datatypes[numdata].size = 3;
matconv[a].datatypes[numdata].type = GL_FLOAT;
numdata++;
@@ -1039,6 +1040,7 @@ static void cdDM_drawMappedFacesGLSL(
for (b = 0; b < matconv[a].attribs.tottface; b++) {
if (matconv[a].attribs.tface[b].array) {
matconv[a].datatypes[numdata].index = matconv[a].attribs.tface[b].gl_index;
+ matconv[a].datatypes[numdata].info_index = matconv[a].attribs.tface[b].gl_info_index;
matconv[a].datatypes[numdata].size = 2;
matconv[a].datatypes[numdata].type = GL_FLOAT;
numdata++;
@@ -1047,6 +1049,7 @@ static void cdDM_drawMappedFacesGLSL(
for (b = 0; b < matconv[a].attribs.totmcol; b++) {
if (matconv[a].attribs.mcol[b].array) {
matconv[a].datatypes[numdata].index = matconv[a].attribs.mcol[b].gl_index;
+ matconv[a].datatypes[numdata].info_index = matconv[a].attribs.mcol[b].gl_info_index;
matconv[a].datatypes[numdata].size = 4;
matconv[a].datatypes[numdata].type = GL_UNSIGNED_BYTE;
numdata++;
@@ -1055,6 +1058,7 @@ static void cdDM_drawMappedFacesGLSL(
for (b = 0; b < matconv[a].attribs.tottang; b++) {
if (matconv[a].attribs.tang[b].array) {
matconv[a].datatypes[numdata].index = matconv[a].attribs.tang[b].gl_index;
+ matconv[a].datatypes[numdata].info_index = matconv[a].attribs.tang[b].gl_info_index;
matconv[a].datatypes[numdata].size = 4;
matconv[a].datatypes[numdata].type = GL_FLOAT;
numdata++;
@@ -2656,6 +2660,9 @@ void CDDM_calc_loop_normals(DerivedMesh *dm, const bool use_split_normals, const
}
/* #define DEBUG_CLNORS */
+#ifdef DEBUG_CLNORS
+# include "BLI_linklist.h"
+#endif
void CDDM_calc_loop_normals_spacearr(
DerivedMesh *dm, const bool use_split_normals, const float split_angle, MLoopNorSpaceArray *r_lnors_spacearr)
diff --git a/source/blender/blenkernel/intern/colortools.c b/source/blender/blenkernel/intern/colortools.c
index bac59c8c62d..c1f1f0128f5 100644
--- a/source/blender/blenkernel/intern/colortools.c
+++ b/source/blender/blenkernel/intern/colortools.c
@@ -43,6 +43,7 @@
#include "BLI_blenlib.h"
#include "BLI_math.h"
#include "BLI_utildefines.h"
+#include "BLI_task.h"
#include "BLI_threads.h"
#include "BKE_colortools.h"
@@ -53,10 +54,6 @@
#include "IMB_colormanagement.h"
#include "IMB_imbuf_types.h"
-#ifdef _OPENMP
-# include <omp.h>
-#endif
-
/* ********************************* color curve ********************* */
/* ***************** operations on full struct ************* */
@@ -1089,31 +1086,170 @@ void BKE_histogram_update_sample_line(Histogram *hist, ImBuf *ibuf, const ColorM
}
/* if view_settings, it also applies this to byte buffers */
+typedef struct ScopesUpdateData {
+ Scopes *scopes;
+ const ImBuf *ibuf;
+ struct ColormanageProcessor *cm_processor;
+ const unsigned char *display_buffer;
+ const int ycc_mode;
+
+ unsigned int *bin_lum, *bin_r, *bin_g, *bin_b, *bin_a;
+} ScopesUpdateData;
+
+typedef struct ScopesUpdateDataChunk {
+ unsigned int bin_lum[256];
+ unsigned int bin_r[256];
+ unsigned int bin_g[256];
+ unsigned int bin_b[256];
+ unsigned int bin_a[256];
+ float min[3], max[3];
+} ScopesUpdateDataChunk;
+
+static void scopes_update_cb(void *userdata, void *userdata_chunk, const int y, const int UNUSED(threadid))
+{
+ const ScopesUpdateData *data = userdata;
+
+ Scopes *scopes = data->scopes;
+ const ImBuf *ibuf = data->ibuf;
+ struct ColormanageProcessor *cm_processor = data->cm_processor;
+ const unsigned char *display_buffer = data->display_buffer;
+ const int ycc_mode = data->ycc_mode;
+
+ ScopesUpdateDataChunk *data_chunk = userdata_chunk;
+ unsigned int *bin_lum = data_chunk->bin_lum;
+ unsigned int *bin_r = data_chunk->bin_r;
+ unsigned int *bin_g = data_chunk->bin_g;
+ unsigned int *bin_b = data_chunk->bin_b;
+ unsigned int *bin_a = data_chunk->bin_a;
+ float *min = data_chunk->min;
+ float *max = data_chunk->max;
+
+ const float *rf = NULL;
+ const unsigned char *rc = NULL;
+ const int rows_per_sample_line = ibuf->y / scopes->sample_lines;
+ const int savedlines = y / rows_per_sample_line;
+ const bool do_sample_line = (savedlines < scopes->sample_lines) && (y % rows_per_sample_line) == 0;
+ const bool is_float = (ibuf->rect_float != NULL);
+
+ if (is_float)
+ rf = ibuf->rect_float + ((size_t)y) * ibuf->x * ibuf->channels;
+ else {
+ rc = display_buffer + ((size_t)y) * ibuf->x * ibuf->channels;
+ }
+
+ for (int x = 0; x < ibuf->x; x++) {
+ float rgba[4], ycc[3], luma;
+
+ if (is_float) {
+ switch (ibuf->channels) {
+ case 4:
+ copy_v4_v4(rgba, rf);
+ IMB_colormanagement_processor_apply_v4(cm_processor, rgba);
+ break;
+ case 3:
+ copy_v3_v3(rgba, rf);
+ IMB_colormanagement_processor_apply_v3(cm_processor, rgba);
+ rgba[3] = 1.0f;
+ break;
+ case 2:
+ copy_v3_fl(rgba, rf[0]);
+ rgba[3] = rf[1];
+ break;
+ case 1:
+ copy_v3_fl(rgba, rf[0]);
+ rgba[3] = 1.0f;
+ break;
+ default:
+ BLI_assert(0);
+ }
+ }
+ else {
+ for (int c = 4; c--;)
+ rgba[c] = rc[c] * INV_255;
+ }
+
+ /* we still need luma for histogram */
+ luma = IMB_colormanagement_get_luminance(rgba);
+
+ /* check for min max */
+ if (ycc_mode == -1) {
+ minmax_v3v3_v3(min, max, rgba);
+ }
+ else {
+ rgb_to_ycc(rgba[0], rgba[1], rgba[2], &ycc[0], &ycc[1], &ycc[2], ycc_mode);
+ mul_v3_fl(ycc, INV_255);
+ minmax_v3v3_v3(min, max, ycc);
+ }
+ /* increment count for histo*/
+ bin_lum[get_bin_float(luma)]++;
+ bin_r[get_bin_float(rgba[0])]++;
+ bin_g[get_bin_float(rgba[1])]++;
+ bin_b[get_bin_float(rgba[2])]++;
+ bin_a[get_bin_float(rgba[3])]++;
+
+ /* save sample if needed */
+ if (do_sample_line) {
+ const float fx = (float)x / (float)ibuf->x;
+ const int idx = 2 * (ibuf->x * savedlines + x);
+ save_sample_line(scopes, idx, fx, rgba, ycc);
+ }
+
+ rf += ibuf->channels;
+ rc += ibuf->channels;
+ }
+}
+
+static void scopes_update_finalize(void *userdata, void *userdata_chunk)
+{
+ const ScopesUpdateData *data = userdata;
+ const ScopesUpdateDataChunk *data_chunk = userdata_chunk;
+
+ unsigned int *bin_lum = data->bin_lum;
+ unsigned int *bin_r = data->bin_r;
+ unsigned int *bin_g = data->bin_g;
+ unsigned int *bin_b = data->bin_b;
+ unsigned int *bin_a = data->bin_a;
+ const unsigned int *bin_lum_c = data_chunk->bin_lum;
+ const unsigned int *bin_r_c = data_chunk->bin_r;
+ const unsigned int *bin_g_c = data_chunk->bin_g;
+ const unsigned int *bin_b_c = data_chunk->bin_b;
+ const unsigned int *bin_a_c = data_chunk->bin_a;
+
+ float (*minmax)[2] = data->scopes->minmax;
+ const float *min = data_chunk->min;
+ const float *max = data_chunk->max;
+
+ for (int b = 256; b--;) {
+ bin_lum[b] += bin_lum_c[b];
+ bin_r[b] += bin_r_c[b];
+ bin_g[b] += bin_g_c[b];
+ bin_b[b] += bin_b_c[b];
+ bin_a[b] += bin_a_c[b];
+ }
+
+ for (int c = 3; c--;) {
+ if (min[c] < minmax[c][0])
+ minmax[c][0] = min[c];
+ if (max[c] > minmax[c][1])
+ minmax[c][1] = max[c];
+ }
+}
+
void scopes_update(Scopes *scopes, ImBuf *ibuf, const ColorManagedViewSettings *view_settings,
const ColorManagedDisplaySettings *display_settings)
{
-#ifdef _OPENMP
- const int num_threads = BLI_system_thread_count();
-#endif
- int a, y;
+ int a;
unsigned int nl, na, nr, ng, nb;
double divl, diva, divr, divg, divb;
- unsigned char *display_buffer;
+ const unsigned char *display_buffer = NULL;
unsigned int bin_lum[256] = {0},
bin_r[256] = {0},
bin_g[256] = {0},
bin_b[256] = {0},
bin_a[256] = {0};
- unsigned int bin_lum_t[BLENDER_MAX_THREADS][256] = {{0}},
- bin_r_t[BLENDER_MAX_THREADS][256] = {{0}},
- bin_g_t[BLENDER_MAX_THREADS][256] = {{0}},
- bin_b_t[BLENDER_MAX_THREADS][256] = {{0}},
- bin_a_t[BLENDER_MAX_THREADS][256] = {{0}};
int ycc_mode = -1;
- const bool is_float = (ibuf->rect_float != NULL);
void *cache_handle = NULL;
struct ColormanageProcessor *cm_processor = NULL;
- int rows_per_sample_line;
if (ibuf->rect == NULL && ibuf->rect_float == NULL) return;
@@ -1151,7 +1287,6 @@ void scopes_update(Scopes *scopes, ImBuf *ibuf, const ColorManagedViewSettings *
scopes->sample_lines = ibuf->y;
/* scan the image */
- rows_per_sample_line = ibuf->y / scopes->sample_lines;
for (a = 0; a < 3; a++) {
scopes->minmax[a][0] = 25500.0f;
scopes->minmax[a][1] = -25500.0f;
@@ -1177,129 +1312,21 @@ void scopes_update(Scopes *scopes, ImBuf *ibuf, const ColorManagedViewSettings *
cm_processor = IMB_colormanagement_display_processor_new(view_settings, display_settings);
}
else {
- display_buffer = (unsigned char *)IMB_display_buffer_acquire(ibuf,
- view_settings,
- display_settings,
- &cache_handle);
+ display_buffer = (const unsigned char *)IMB_display_buffer_acquire(
+ ibuf, view_settings, display_settings, &cache_handle);
}
/* Keep number of threads in sync with the merge parts below. */
-#pragma omp parallel for private(y) schedule(static) num_threads(num_threads) if (ibuf->y > 256)
- for (y = 0; y < ibuf->y; y++) {
-#ifdef _OPENMP
- const int thread_idx = omp_get_thread_num();
-#else
- const int thread_idx = 0;
-#endif
- const float *rf = NULL;
- const unsigned char *rc = NULL;
- const int savedlines = y / rows_per_sample_line;
- const bool do_sample_line = (savedlines < scopes->sample_lines) && (y % rows_per_sample_line) == 0;
- float min[3] = { FLT_MAX, FLT_MAX, FLT_MAX},
- max[3] = {-FLT_MAX, -FLT_MAX, -FLT_MAX};
- int x, c;
- if (is_float)
- rf = ibuf->rect_float + ((size_t)y) * ibuf->x * ibuf->channels;
- else {
- rc = display_buffer + ((size_t)y) * ibuf->x * ibuf->channels;
- }
- for (x = 0; x < ibuf->x; x++) {
- float rgba[4], ycc[3], luma;
- if (is_float) {
-
- switch (ibuf->channels) {
- case 4:
- copy_v4_v4(rgba, rf);
- IMB_colormanagement_processor_apply_v4(cm_processor, rgba);
- break;
- case 3:
- copy_v3_v3(rgba, rf);
- IMB_colormanagement_processor_apply_v3(cm_processor, rgba);
- rgba[3] = 1.0f;
- break;
- case 2:
- copy_v3_fl(rgba, rf[0]);
- rgba[3] = rf[1];
- break;
- case 1:
- copy_v3_fl(rgba, rf[0]);
- rgba[3] = 1.0f;
- break;
- default:
- BLI_assert(0);
- }
- }
- else {
- for (c = 0; c < 4; c++)
- rgba[c] = rc[c] * INV_255;
- }
-
- /* we still need luma for histogram */
- luma = IMB_colormanagement_get_luminance(rgba);
-
- /* check for min max */
- if (ycc_mode == -1) {
- for (c = 0; c < 3; c++) {
- if (rgba[c] < min[c]) min[c] = rgba[c];
- if (rgba[c] > max[c]) max[c] = rgba[c];
- }
- }
- else {
- rgb_to_ycc(rgba[0], rgba[1], rgba[2], &ycc[0], &ycc[1], &ycc[2], ycc_mode);
- for (c = 0; c < 3; c++) {
- ycc[c] *= INV_255;
- if (ycc[c] < min[c]) min[c] = ycc[c];
- if (ycc[c] > max[c]) max[c] = ycc[c];
- }
- }
- /* increment count for histo*/
- bin_lum_t[thread_idx][get_bin_float(luma)] += 1;
- bin_r_t[thread_idx][get_bin_float(rgba[0])] += 1;
- bin_g_t[thread_idx][get_bin_float(rgba[1])] += 1;
- bin_b_t[thread_idx][get_bin_float(rgba[2])] += 1;
- bin_a_t[thread_idx][get_bin_float(rgba[3])] += 1;
-
- /* save sample if needed */
- if (do_sample_line) {
- const float fx = (float)x / (float)ibuf->x;
- const int idx = 2 * (ibuf->x * savedlines + x);
- save_sample_line(scopes, idx, fx, rgba, ycc);
- }
-
- rf += ibuf->channels;
- rc += ibuf->channels;
- }
-#pragma omp critical
- {
- for (c = 0; c < 3; c++) {
- if (min[c] < scopes->minmax[c][0]) scopes->minmax[c][0] = min[c];
- if (max[c] > scopes->minmax[c][1]) scopes->minmax[c][1] = max[c];
- }
- }
- }
-
-#ifdef _OPENMP
- if (ibuf->y > 256) {
- for (a = 0; a < num_threads; a++) {
- int b;
- for (b = 0; b < 256; b++) {
- bin_lum[b] += bin_lum_t[a][b];
- bin_r[b] += bin_r_t[a][b];
- bin_g[b] += bin_g_t[a][b];
- bin_b[b] += bin_b_t[a][b];
- bin_a[b] += bin_a_t[a][b];
- }
- }
- }
- else
-#endif
- {
- memcpy(bin_lum, bin_lum_t[0], sizeof(bin_lum));
- memcpy(bin_r, bin_r_t[0], sizeof(bin_r));
- memcpy(bin_g, bin_g_t[0], sizeof(bin_g));
- memcpy(bin_b, bin_b_t[0], sizeof(bin_b));
- memcpy(bin_a, bin_a_t[0], sizeof(bin_a));
- }
+ ScopesUpdateData data = {
+ .scopes = scopes, . ibuf = ibuf,
+ .cm_processor = cm_processor, .display_buffer = display_buffer, .ycc_mode = ycc_mode,
+ .bin_lum = bin_lum, .bin_r = bin_r, .bin_g = bin_g, .bin_b = bin_b, .bin_a = bin_a,
+ };
+ ScopesUpdateDataChunk data_chunk = {0};
+ INIT_MINMAX(data_chunk.min, data_chunk.max);
+
+ BLI_task_parallel_range_finalize(0, ibuf->y, &data, &data_chunk, sizeof(data_chunk),
+ scopes_update_cb, scopes_update_finalize, ibuf->y > 256, false);
/* test for nicer distribution even - non standard, leave it out for a while */
#if 0
diff --git a/source/blender/blenkernel/intern/customdata.c b/source/blender/blenkernel/intern/customdata.c
index de79a30bd60..612f1f477e1 100644
--- a/source/blender/blenkernel/intern/customdata.c
+++ b/source/blender/blenkernel/intern/customdata.c
@@ -1853,8 +1853,6 @@ static CustomDataLayer *customData_add_layer__internal(CustomData *data, int typ
(alloctype == CD_DUPLICATE) ||
(alloctype == CD_REFERENCE));
- BLI_assert(size >= 0);
-
if (!typeInfo->defaultname && CustomData_has_layer(data, type))
return &data->layers[CustomData_get_layer_index(data, type)];
diff --git a/source/blender/blenkernel/intern/editderivedmesh.c b/source/blender/blenkernel/intern/editderivedmesh.c
index 6c117447664..ffd000eed88 100644
--- a/source/blender/blenkernel/intern/editderivedmesh.c
+++ b/source/blender/blenkernel/intern/editderivedmesh.c
@@ -57,6 +57,7 @@
#include "MEM_guardedalloc.h"
#include "GPU_glew.h"
+#include "GPU_buffers.h"
#include "GPU_shader.h"
#include "GPU_basic_shader.h"
@@ -1405,6 +1406,24 @@ static void emDM_drawMappedFacesTex(
emDM_drawFacesTex_common(dm, NULL, setDrawOptions, compareDrawOptions, userData);
}
+static void emdm_pass_attrib_update_uniforms(const DMVertexAttribs *attribs)
+{
+ int i;
+ if (attribs->totorco) {
+ glUniform1i(attribs->orco.gl_info_index, 0);
+ }
+ for (i = 0; i < attribs->tottface; i++) {
+ glUniform1i(attribs->tface[i].gl_info_index, 0);
+ }
+ for (i = 0; i < attribs->totmcol; i++) {
+ glUniform1i(attribs->mcol[i].gl_info_index, GPU_ATTR_INFO_SRGB);
+ }
+
+ for (i = 0; i < attribs->tottang; i++) {
+ glUniform1i(attribs->tang[i].gl_info_index, 0);
+ }
+}
+
/**
* \note
*
@@ -1449,15 +1468,15 @@ static void emdm_pass_attrib_vertex_glsl(const DMVertexAttribs *attribs, const B
glVertexAttrib2fv(attribs->tface[i].gl_index, uv);
}
for (i = 0; i < attribs->totmcol; i++) {
- GLubyte col[4];
+ float col[4];
if (attribs->mcol[i].em_offset != -1) {
const MLoopCol *cp = BM_ELEM_CD_GET_VOID_P(loop, attribs->mcol[i].em_offset);
- copy_v4_v4_uchar(col, &cp->r);
+ rgba_uchar_to_float(col, &cp->r);
}
else {
- col[0] = 0; col[1] = 0; col[2] = 0; col[3] = 0;
+ col[0] = 0.0f; col[1] = 0.0f; col[2] = 0.0f; col[3] = 0.0f;
}
- glVertexAttrib4ubv(attribs->mcol[i].gl_index, col);
+ glVertexAttrib4fv(attribs->mcol[i].gl_index, col);
}
for (i = 0; i < attribs->tottang; i++) {
@@ -1527,6 +1546,7 @@ static void emDM_drawMappedFacesGLSL(
do_draw = setMaterial(matnr = new_matnr, &gattribs);
if (do_draw) {
DM_vertex_attributes_from_gpu(dm, &gattribs, &attribs);
+ emdm_pass_attrib_update_uniforms(&attribs);
if (UNLIKELY(attribs.tottang && bm->elem_index_dirty & BM_LOOP)) {
BM_mesh_elem_index_ensure(bm, BM_LOOP);
}
diff --git a/source/blender/blenkernel/intern/effect.c b/source/blender/blenkernel/intern/effect.c
index 6284b3a46fb..f06dd6f9de4 100644
--- a/source/blender/blenkernel/intern/effect.c
+++ b/source/blender/blenkernel/intern/effect.c
@@ -566,7 +566,9 @@ int get_effector_data(EffectorCache *eff, EffectorData *efd, EffectedPoint *poin
float cfra = eff->scene->r.cfra;
int ret = 0;
- if (eff->pd && eff->pd->shape==PFIELD_SHAPE_SURFACE && eff->surmd) {
+ /* In case surface object is in Edit mode when loading the .blend, surface modifier is never executed
+ * and bvhtree never built, see T48415. */
+ if (eff->pd && eff->pd->shape==PFIELD_SHAPE_SURFACE && eff->surmd && eff->surmd->bvhtree) {
/* closest point in the object surface is an effector */
float vec[3];
diff --git a/source/blender/blenkernel/intern/fcurve.c b/source/blender/blenkernel/intern/fcurve.c
index a2b5a05feac..395161aa6ed 100644
--- a/source/blender/blenkernel/intern/fcurve.c
+++ b/source/blender/blenkernel/intern/fcurve.c
@@ -2671,7 +2671,7 @@ float evaluate_fcurve(FCurve *fcu, float evaltime)
}
/* Calculate the value of the given F-Curve at the given frame, and set its curval */
-void calculate_fcurve(FCurve *fcu, float ctime)
+float calculate_fcurve(FCurve *fcu, float evaltime)
{
/* only calculate + set curval (overriding the existing value) if curve has
* any data which warrants this...
@@ -2680,7 +2680,12 @@ void calculate_fcurve(FCurve *fcu, float ctime)
list_has_suitable_fmodifier(&fcu->modifiers, 0, FMI_TYPE_GENERATE_CURVE))
{
/* calculate and set curval (evaluates driver too if necessary) */
- fcu->curval = evaluate_fcurve(fcu, ctime);
+ float curval = evaluate_fcurve(fcu, evaltime);
+ fcu->curval = curval; /* debug display only, not thread safe! */
+ return curval;
+ }
+ else {
+ return 0.0f;
}
}
diff --git a/source/blender/blenkernel/intern/idcode.c b/source/blender/blenkernel/intern/idcode.c
index 68a741bc3fc..899ed548783 100644
--- a/source/blender/blenkernel/intern/idcode.c
+++ b/source/blender/blenkernel/intern/idcode.c
@@ -39,6 +39,7 @@
#include "BLT_translation.h"
+#include "BKE_library.h"
#include "BKE_idcode.h"
typedef struct {
@@ -54,6 +55,7 @@ typedef struct {
/* plural need to match rna_main.c's MainCollectionDef */
/* WARNING! Keep it in sync with i18n contexts in BLT_translation.h */
static IDType idtypes[] = {
+ /** ID's directly below must all be in #Main, and be kept in sync with #MAX_LIBARRAY (membership, not order) */
{ ID_AC, "Action", "actions", BLT_I18NCONTEXT_ID_ACTION, IDTYPE_FLAGS_ISLINKABLE },
{ ID_AR, "Armature", "armatures", BLT_I18NCONTEXT_ID_ARMATURE, IDTYPE_FLAGS_ISLINKABLE },
{ ID_BR, "Brush", "brushes", BLT_I18NCONTEXT_ID_BRUSH, IDTYPE_FLAGS_ISLINKABLE },
@@ -61,7 +63,6 @@ static IDType idtypes[] = {
{ ID_CU, "Curve", "curves", BLT_I18NCONTEXT_ID_CURVE, IDTYPE_FLAGS_ISLINKABLE },
{ ID_GD, "GPencil", "grease_pencil", BLT_I18NCONTEXT_ID_GPENCIL, IDTYPE_FLAGS_ISLINKABLE }, /* rename gpencil */
{ ID_GR, "Group", "groups", BLT_I18NCONTEXT_ID_GROUP, IDTYPE_FLAGS_ISLINKABLE },
- { ID_ID, "ID", "ids", BLT_I18NCONTEXT_ID_ID, 0 }, /* plural is fake */
{ ID_IM, "Image", "images", BLT_I18NCONTEXT_ID_IMAGE, IDTYPE_FLAGS_ISLINKABLE },
{ ID_IP, "Ipo", "ipos", "", IDTYPE_FLAGS_ISLINKABLE }, /* deprecated */
{ ID_KE, "Key", "shape_keys", BLT_I18NCONTEXT_ID_SHAPEKEY, 0 },
@@ -89,8 +90,14 @@ static IDType idtypes[] = {
{ ID_VF, "VFont", "fonts", BLT_I18NCONTEXT_ID_VFONT, IDTYPE_FLAGS_ISLINKABLE },
{ ID_WO, "World", "worlds", BLT_I18NCONTEXT_ID_WORLD, IDTYPE_FLAGS_ISLINKABLE },
{ ID_WM, "WindowManager", "window_managers", BLT_I18NCONTEXT_ID_WINDOWMANAGER, 0 },
+
+ /** Keep last, not an ID exactly, only include for completeness */
+ { ID_ID, "ID", "ids", BLT_I18NCONTEXT_ID_ID, 0 }, /* plural is fake */
};
+/* -1 for ID_ID */
+BLI_STATIC_ASSERT((ARRAY_SIZE(idtypes) - 1 == MAX_LIBARRAY), "Missing IDType");
+
static IDType *idtype_from_name(const char *str)
{
int i = ARRAY_SIZE(idtypes);
diff --git a/source/blender/blenkernel/intern/image.c b/source/blender/blenkernel/intern/image.c
index 1ae7ca189fb..0b2c844cb2c 100644
--- a/source/blender/blenkernel/intern/image.c
+++ b/source/blender/blenkernel/intern/image.c
@@ -109,8 +109,8 @@ static void image_add_view(Image *ima, const char *viewname, const char *filepat
#define IMA_NO_INDEX 0x7FEFEFEF
/* quick lookup: supports 1 million frames, thousand passes */
-#define IMA_MAKE_INDEX(frame, index) ((frame) << 10) + index
-#define IMA_INDEX_FRAME(index) (index >> 10)
+#define IMA_MAKE_INDEX(frame, index) (((frame) << 10) + (index))
+#define IMA_INDEX_FRAME(index) ((index) >> 10)
/*
#define IMA_INDEX_PASS(index) (index & ~1023)
*/
diff --git a/source/blender/blenkernel/intern/library_idmap.c b/source/blender/blenkernel/intern/library_idmap.c
new file mode 100644
index 00000000000..fd78d9b23ce
--- /dev/null
+++ b/source/blender/blenkernel/intern/library_idmap.c
@@ -0,0 +1,174 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public 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 *****
+ */
+
+#include <string.h>
+#include <stdlib.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_utildefines.h"
+#include "BLI_ghash.h"
+#include "BLI_listbase.h"
+
+#include "DNA_ID.h"
+
+#include "BKE_idcode.h"
+#include "BKE_library.h"
+#include "BKE_library_idmap.h" /* own include */
+
+/** \file blender/blenkernel/intern/library_map.c
+ * \ingroup bke
+ *
+ * Utility functions for faster ID lookups.
+ */
+
+/** \name BKE_main_idmap API
+ *
+ * Cache ID (name, library lookups).
+ * This doesn't account for adding/removing data-blocks,
+ * and should only be used when performing many lookups.
+ *
+ * \note GHash's are initialized on demand,
+ * since its likely some types will never have lookups run on them,
+ * so its a waste to create and never use.
+ * \{ */
+
+struct IDNameLib_Key {
+ /** ``ID.name + 2``: without the ID type prefix, since each id type gets it's own 'map' */
+ const char *name;
+ /** ``ID.lib``: */
+ const Library *lib;
+};
+
+struct IDNameLib_TypeMap {
+ GHash *map;
+ short id_type;
+ /* only for storage of keys in the ghash, avoid many single allocs */
+ struct IDNameLib_Key *keys;
+};
+
+/**
+ * Opaque structure, external API users only see this.
+ */
+struct IDNameLib_Map {
+ struct IDNameLib_TypeMap type_maps[MAX_LIBARRAY];
+ struct Main *bmain;
+};
+
+static struct IDNameLib_TypeMap *main_idmap_from_idcode(struct IDNameLib_Map *id_map, short id_type)
+{
+ for (int i = 0; i < MAX_LIBARRAY; i++) {
+ if (id_map->type_maps[i].id_type == id_type) {
+ return &id_map->type_maps[i];
+ }
+ }
+ return NULL;
+}
+
+struct IDNameLib_Map *BKE_main_idmap_create(struct Main *bmain)
+{
+ struct IDNameLib_Map *id_map = MEM_mallocN(sizeof(*id_map), __func__);
+
+ int index = 0;
+ while (index < MAX_LIBARRAY) {
+ id_map->type_maps[index].map = NULL;
+ id_map->type_maps[index].id_type = BKE_idcode_iter_step(&index);
+ }
+ BLI_assert(index == MAX_LIBARRAY);
+
+ id_map->bmain = bmain;
+
+ return id_map;
+}
+
+struct Main *BKE_main_idmap_main_get(struct IDNameLib_Map *id_map)
+{
+ return id_map->bmain;
+}
+
+static unsigned int idkey_hash(const void *ptr)
+{
+ const struct IDNameLib_Key *idkey = ptr;
+ unsigned int key = BLI_ghashutil_strhash(idkey->name);
+ if (idkey->lib) {
+ key ^= BLI_ghashutil_ptrhash(idkey->lib);
+ }
+ return key;
+}
+
+static bool idkey_cmp(const void *a, const void *b)
+{
+ const struct IDNameLib_Key *idkey_a = a;
+ const struct IDNameLib_Key *idkey_b = b;
+ return strcmp(idkey_a->name, idkey_b->name) || (idkey_a->lib != idkey_b->lib);
+}
+
+ID *BKE_main_idmap_lookup(struct IDNameLib_Map *id_map, short id_type, const char *name, const Library *lib)
+{
+ struct IDNameLib_TypeMap *type_map = main_idmap_from_idcode(id_map, id_type);
+
+ if (UNLIKELY(type_map == NULL)) {
+ return NULL;
+ }
+
+ /* lazy init */
+ if (type_map->map == NULL) {
+ ListBase *lb = which_libbase(id_map->bmain, id_type);
+ const int lb_len = BLI_listbase_count(lb);
+ if (lb_len == 0) {
+ return NULL;
+ }
+ type_map->map = BLI_ghash_new_ex(idkey_hash, idkey_cmp, __func__, lb_len);
+ type_map->keys = MEM_mallocN(sizeof(struct IDNameLib_Key) * lb_len, __func__);
+
+ GHash *map = type_map->map;
+ struct IDNameLib_Key *key = type_map->keys;
+
+ for (ID *id = lb->first; id; id = id->next, key++) {
+ key->name = id->name + 2;
+ key->lib = id->lib;
+ BLI_ghash_insert(map, key, id);
+ }
+ }
+
+ const struct IDNameLib_Key key_lookup = {name, lib};
+ return BLI_ghash_lookup(type_map->map, &key_lookup);
+}
+
+ID *BKE_main_idmap_lookup_id(struct IDNameLib_Map *id_map, const ID *id)
+{
+ return BKE_main_idmap_lookup(id_map, GS(id->name), id->name + 2, id->lib);
+}
+
+void BKE_main_idmap_destroy(struct IDNameLib_Map *id_map)
+{
+ struct IDNameLib_TypeMap *type_map = id_map->type_maps;
+ for (int i = 0; i < MAX_LIBARRAY; i++, type_map++) {
+ if (type_map->map) {
+ BLI_ghash_free(type_map->map, NULL, NULL);
+ type_map->map = NULL;
+ MEM_freeN(type_map->keys);
+ }
+ }
+
+ MEM_freeN(id_map);
+}
+
+/** \} */
diff --git a/source/blender/blenkernel/intern/material.c b/source/blender/blenkernel/intern/material.c
index 1fec725dbb7..30f82a50ed9 100644
--- a/source/blender/blenkernel/intern/material.c
+++ b/source/blender/blenkernel/intern/material.c
@@ -1148,7 +1148,6 @@ static void init_render_nodetree(bNodeTree *ntree, Material *basemat, int r_mode
/* parses the geom+tex nodes */
ntreeShaderGetTexcoMode(ntree, r_mode, &basemat->texco, &basemat->mode_l);
- basemat->nmap_tangent_names_count = 0;
for (node = ntree->nodes.first; node; node = node->next) {
if (node->id) {
if (GS(node->id->name) == ID_MA) {
@@ -1199,7 +1198,7 @@ void init_render_material(Material *mat, int r_mode, float *amb)
* mode_l will have it set when all node materials are shadeless. */
mat->mode_l = (mat->mode & MA_MODE_PIPELINE) | MA_SHLESS;
mat->mode2_l = mat->mode2 & MA_MODE2_PIPELINE;
-
+ mat->nmap_tangent_names_count = 0;
init_render_nodetree(mat->nodetree, mat, r_mode, amb);
if (!mat->nodetree->execdata)
diff --git a/source/blender/blenkernel/intern/mesh_evaluate.c b/source/blender/blenkernel/intern/mesh_evaluate.c
index 577a21285f8..1c86fbcfe8e 100644
--- a/source/blender/blenkernel/intern/mesh_evaluate.c
+++ b/source/blender/blenkernel/intern/mesh_evaluate.c
@@ -677,7 +677,7 @@ static void split_loop_nor_single_do(LoopSplitTaskDataCommon *common_data, LoopS
*/
copy_v3_v3(*lnor, polynors[mp_index]);
- /* printf("BASIC: handling loop %d / edge %d / vert %d\n", ml_curr_index, ml_curr->e, ml_curr->v); */
+ /* printf("BASIC: handling loop %d / edge %d / vert %d / poly %d\n", ml_curr_index, ml_curr->e, ml_curr->v, mp_index); */
/* If needed, generate this (simple!) lnor space. */
if (lnors_spacearr) {
@@ -3262,14 +3262,14 @@ void BKE_mesh_mdisp_flip(MDisps *md, const bool use_loop_mdisp_flip)
*/
void BKE_mesh_polygon_flip_ex(
MPoly *mpoly, MLoop *mloop, CustomData *ldata,
- MDisps *mdisp, const bool use_loop_mdisp_flip)
+ float (*lnors)[3], MDisps *mdisp, const bool use_loop_mdisp_flip)
{
int loopstart = mpoly->loopstart;
int loopend = loopstart + mpoly->totloop - 1;
const bool loops_in_ldata = (CustomData_get_layer(ldata, CD_MLOOP) == mloop);
if (mdisp) {
- for (int i = mpoly->loopstart; i <= loopend; i++) {
+ for (int i = loopstart; i <= loopend; i++) {
BKE_mesh_mdisp_flip(&mdisp[i], use_loop_mdisp_flip);
}
}
@@ -3288,6 +3288,9 @@ void BKE_mesh_polygon_flip_ex(
if (!loops_in_ldata) {
SWAP(MLoop, mloop[loopstart], mloop[loopend]);
}
+ if (lnors) {
+ swap_v3_v3(lnors[loopstart], lnors[loopend]);
+ }
CustomData_swap(ldata, loopstart, loopend);
}
/* Even if we did not swap the other 'pivot' loop, we need to set its swapped edge. */
@@ -3299,7 +3302,7 @@ void BKE_mesh_polygon_flip_ex(
void BKE_mesh_polygon_flip(MPoly *mpoly, MLoop *mloop, CustomData *ldata)
{
MDisps *mdisp = CustomData_get_layer(ldata, CD_MDISPS);
- BKE_mesh_polygon_flip_ex(mpoly, mloop, ldata, mdisp, true);
+ BKE_mesh_polygon_flip_ex(mpoly, mloop, ldata, NULL, mdisp, true);
}
/**
@@ -3315,7 +3318,7 @@ void BKE_mesh_polygons_flip(
int i;
for (mp = mpoly, i = 0; i < totpoly; mp++, i++) {
- BKE_mesh_polygon_flip_ex(mp, mloop, ldata, mdisp, true);
+ BKE_mesh_polygon_flip_ex(mp, mloop, ldata, NULL, mdisp, true);
}
}
diff --git a/source/blender/blenkernel/intern/object_update.c b/source/blender/blenkernel/intern/object_update.c
index 03348adeabc..2468cb8b697 100644
--- a/source/blender/blenkernel/intern/object_update.c
+++ b/source/blender/blenkernel/intern/object_update.c
@@ -347,3 +347,10 @@ void BKE_object_eval_uber_data(EvaluationContext *eval_ctx,
ob->recalc &= ~(OB_RECALC_DATA | OB_RECALC_TIME);
}
+
+void BKE_object_eval_proxy_backlink(EvaluationContext *UNUSED(eval_ctx), Object *ob)
+{
+ if (ob->proxy) {
+ ob->proxy->proxy_from = ob;
+ }
+}
diff --git a/source/blender/blenkernel/intern/particle.c b/source/blender/blenkernel/intern/particle.c
index 7dce237c737..25dd7fff380 100644
--- a/source/blender/blenkernel/intern/particle.c
+++ b/source/blender/blenkernel/intern/particle.c
@@ -141,6 +141,11 @@ int count_particles_mod(ParticleSystem *psys, int totgr, int cur)
#define PATH_CACHE_BUF_SIZE 1024
+static ParticleCacheKey *pcache_key_segment_endpoint_safe(ParticleCacheKey *key)
+{
+ return (key->segments > 0) ? (key + (key->segments - 1)) : key;
+}
+
static ParticleCacheKey **psys_alloc_path_cache_buffers(ListBase *bufs, int tot, int totkeys)
{
LinkData *buf;
@@ -2205,20 +2210,22 @@ static void psys_thread_create_path(ParticleTask *task, struct ChildParticle *cp
/* modify weights to create parting */
if (p_fac > 0.f) {
+ const ParticleCacheKey *key_0_last = pcache_key_segment_endpoint_safe(key[0]);
for (w = 0; w < 4; w++) {
- if (w && weight[w] > 0.f) {
+ if (w && (weight[w] > 0.f)) {
+ const ParticleCacheKey *key_w_last = pcache_key_segment_endpoint_safe(key[w]);
float d;
if (part->flag & PART_CHILD_LONG_HAIR) {
/* For long hair use tip distance/root distance as parting factor instead of root to tip angle. */
float d1 = len_v3v3(key[0]->co, key[w]->co);
- float d2 = len_v3v3((key[0] + key[0]->segments - 1)->co, (key[w] + key[w]->segments - 1)->co);
+ float d2 = len_v3v3(key_0_last->co, key_w_last->co);
d = d1 > 0.f ? d2 / d1 - 1.f : 10000.f;
}
else {
float v1[3], v2[3];
- sub_v3_v3v3(v1, (key[0] + key[0]->segments - 1)->co, key[0]->co);
- sub_v3_v3v3(v2, (key[w] + key[w]->segments - 1)->co, key[w]->co);
+ sub_v3_v3v3(v1, key_0_last->co, key[0]->co);
+ sub_v3_v3v3(v2, key_w_last->co, key[w]->co);
normalize_v3(v1);
normalize_v3(v2);
diff --git a/source/blender/blenkernel/intern/pbvh.c b/source/blender/blenkernel/intern/pbvh.c
index d73f087a3fe..58ec75dc706 100644
--- a/source/blender/blenkernel/intern/pbvh.c
+++ b/source/blender/blenkernel/intern/pbvh.c
@@ -637,6 +637,7 @@ void BKE_pbvh_free(PBVH *bvh)
BLI_gset_free(node->bm_other_verts, NULL);
}
}
+ GPU_free_pbvh_buffer_multires(&bvh->grid_common_gpu_buffer);
if (bvh->deformed) {
if (bvh->verts) {
@@ -1100,7 +1101,7 @@ static void pbvh_update_draw_buffers(PBVH *bvh, PBVHNode **nodes, int totnode)
node->totprim,
bvh->grid_hidden,
bvh->gridkey.grid_size,
- &bvh->gridkey);
+ &bvh->gridkey, &bvh->grid_common_gpu_buffer);
break;
case PBVH_FACES:
node->draw_buffers =
diff --git a/source/blender/blenkernel/intern/pbvh_intern.h b/source/blender/blenkernel/intern/pbvh_intern.h
index bae323dedef..4d2307c3e12 100644
--- a/source/blender/blenkernel/intern/pbvh_intern.h
+++ b/source/blender/blenkernel/intern/pbvh_intern.h
@@ -145,6 +145,11 @@ struct PBVH {
const DMFlagMat *grid_flag_mats;
int totgrid;
BLI_bitmap **grid_hidden;
+ /* index_buf of GPU_PBVH_Buffers can be the same for all 'fully drawn' nodes (same size).
+ * Previously was stored in a static var in gpu_buffer.c, but this breaks in case we handle several different
+ * objects in sculpt mode with different sizes at the same time, so now storing that common gpu buffer
+ * in an opaque pointer per pbvh. See T47637. */
+ struct GridCommonGPUBuffer *grid_common_gpu_buffer;
/* Only used during BVH build and update,
* don't need to remain valid after */
diff --git a/source/blender/blenkernel/intern/scene.c b/source/blender/blenkernel/intern/scene.c
index d307ba1811b..a3393b6b9c0 100644
--- a/source/blender/blenkernel/intern/scene.c
+++ b/source/blender/blenkernel/intern/scene.c
@@ -2193,6 +2193,13 @@ bool BKE_scene_use_shading_nodes_custom(Scene *scene)
return (type && type->flag & RE_USE_SHADING_NODES_CUSTOM);
}
+bool BKE_scene_use_world_space_shading(Scene *scene)
+{
+ const RenderEngineType *type = RE_engines_find(scene->r.engine);
+ return ((scene->r.mode & R_USE_WS_SHADING) ||
+ (type && (type->flag & RE_USE_SHADING_NODES)));
+}
+
bool BKE_scene_use_spherical_stereo(Scene *scene)
{
RenderEngineType *type = RE_engines_find(scene->r.engine);
diff --git a/source/blender/blenkernel/intern/shrinkwrap.c b/source/blender/blenkernel/intern/shrinkwrap.c
index e855f6faa22..518d8d68919 100644
--- a/source/blender/blenkernel/intern/shrinkwrap.c
+++ b/source/blender/blenkernel/intern/shrinkwrap.c
@@ -44,6 +44,7 @@
#include "BLI_math.h"
#include "BLI_utildefines.h"
+#include "BLI_task.h"
#include "BKE_shrinkwrap.h"
#include "BKE_DerivedMesh.h"
@@ -58,7 +59,7 @@
/* for timing... */
#if 0
-# include "PIL_time.h"
+# include "PIL_time_utildefines.h"
#else
# define TIMEIT_BENCH(expr, id) (expr)
#endif
@@ -66,16 +67,88 @@
/* Util macros */
#define OUT_OF_MEMORY() ((void)printf("Shrinkwrap: Out of memory\n"))
+typedef struct ShrinkwrapCalcCBData {
+ ShrinkwrapCalcData *calc;
+
+ void *treeData;
+ void *auxData;
+ BVHTree *targ_tree;
+ BVHTree *aux_tree;
+ void *targ_callback;
+ void *aux_callback;
+
+ float *proj_axis;
+ SpaceTransform *local2aux;
+} ShrinkwrapCalcCBData;
+
/*
* Shrinkwrap to the nearest vertex
*
* it builds a kdtree of vertexs we can attach to and then
* for each vertex performs a nearest vertex search on the tree
*/
-static void shrinkwrap_calc_nearest_vertex(ShrinkwrapCalcData *calc)
+static void shrinkwrap_calc_nearest_vertex_cb_ex(
+ void *userdata, void *userdata_chunk, const int i, const int UNUSED(threadid))
{
- int i;
+ ShrinkwrapCalcCBData *data = userdata;
+
+ ShrinkwrapCalcData *calc = data->calc;
+ BVHTreeFromMesh *treeData = data->treeData;
+ BVHTreeNearest *nearest = userdata_chunk;
+
+ float *co = calc->vertexCos[i];
+ float tmp_co[3];
+ float weight = defvert_array_find_weight_safe(calc->dvert, i, calc->vgroup);
+
+ if (calc->invert_vgroup) {
+ weight = 1.0f - weight;
+ }
+
+ if (weight == 0.0f) {
+ return;
+ }
+
+ /* Convert the vertex to tree coordinates */
+ if (calc->vert) {
+ copy_v3_v3(tmp_co, calc->vert[i].co);
+ }
+ else {
+ copy_v3_v3(tmp_co, co);
+ }
+ BLI_space_transform_apply(&calc->local2target, tmp_co);
+
+ /* Use local proximity heuristics (to reduce the nearest search)
+ *
+ * If we already had an hit before.. we assume this vertex is going to have a close hit to that other vertex
+ * so we can initiate the "nearest.dist" with the expected value to that last hit.
+ * This will lead in pruning of the search tree. */
+ if (nearest->index != -1)
+ nearest->dist_sq = len_squared_v3v3(tmp_co, nearest->co);
+ else
+ nearest->dist_sq = FLT_MAX;
+
+ BLI_bvhtree_find_nearest(treeData->tree, tmp_co, nearest, treeData->nearest_callback, treeData);
+
+
+ /* Found the nearest vertex */
+ if (nearest->index != -1) {
+ /* Adjusting the vertex weight,
+ * so that after interpolating it keeps a certain distance from the nearest position */
+ if (nearest->dist_sq > FLT_EPSILON) {
+ const float dist = sqrtf(nearest->dist_sq);
+ weight *= (dist - calc->keepDist) / dist;
+ }
+
+ /* Convert the coordinates back to mesh coordinates */
+ copy_v3_v3(tmp_co, nearest->co);
+ BLI_space_transform_invert(&calc->local2target, tmp_co);
+
+ interp_v3_v3v3(co, co, tmp_co, weight); /* linear interpolation */
+ }
+}
+static void shrinkwrap_calc_nearest_vertex(ShrinkwrapCalcData *calc)
+{
BVHTreeFromMesh treeData = NULL_BVHTreeFromMesh;
BVHTreeNearest nearest = NULL_BVHTreeNearest;
@@ -89,61 +162,11 @@ static void shrinkwrap_calc_nearest_vertex(ShrinkwrapCalcData *calc)
/* Setup nearest */
nearest.index = -1;
nearest.dist_sq = FLT_MAX;
-#ifndef __APPLE__
-#pragma omp parallel for default(none) private(i) firstprivate(nearest) shared(treeData, calc) schedule(static) if (calc->numVerts > BKE_MESH_OMP_LIMIT)
-#endif
- for (i = 0; i < calc->numVerts; ++i) {
- float *co = calc->vertexCos[i];
- float tmp_co[3];
- float weight = defvert_array_find_weight_safe(calc->dvert, i, calc->vgroup);
-
- if (calc->invert_vgroup) {
- weight = 1.0f - weight;
- }
-
- if (weight == 0.0f) {
- continue;
- }
-
-
- /* Convert the vertex to tree coordinates */
- if (calc->vert) {
- copy_v3_v3(tmp_co, calc->vert[i].co);
- }
- else {
- copy_v3_v3(tmp_co, co);
- }
- BLI_space_transform_apply(&calc->local2target, tmp_co);
-
- /* Use local proximity heuristics (to reduce the nearest search)
- *
- * If we already had an hit before.. we assume this vertex is going to have a close hit to that other vertex
- * so we can initiate the "nearest.dist" with the expected value to that last hit.
- * This will lead in pruning of the search tree. */
- if (nearest.index != -1)
- nearest.dist_sq = len_squared_v3v3(tmp_co, nearest.co);
- else
- nearest.dist_sq = FLT_MAX;
-
- BLI_bvhtree_find_nearest(treeData.tree, tmp_co, &nearest, treeData.nearest_callback, &treeData);
-
-
- /* Found the nearest vertex */
- if (nearest.index != -1) {
- /* Adjusting the vertex weight,
- * so that after interpolating it keeps a certain distance from the nearest position */
- if (nearest.dist_sq > FLT_EPSILON) {
- const float dist = sqrtf(nearest.dist_sq);
- weight *= (dist - calc->keepDist) / dist;
- }
- /* Convert the coordinates back to mesh coordinates */
- copy_v3_v3(tmp_co, nearest.co);
- BLI_space_transform_invert(&calc->local2target, tmp_co);
-
- interp_v3_v3v3(co, co, tmp_co, weight); /* linear interpolation */
- }
- }
+ ShrinkwrapCalcCBData data = {.calc = calc, .treeData = &treeData};
+ BLI_task_parallel_range_ex(
+ 0, calc->numVerts, &data, &nearest, sizeof(nearest), shrinkwrap_calc_nearest_vertex_cb_ex,
+ calc->numVerts > BKE_MESH_OMP_LIMIT, false);
free_bvhtree_from_mesh(&treeData);
}
@@ -230,13 +253,109 @@ bool BKE_shrinkwrap_project_normal(
return false;
}
+static void shrinkwrap_calc_normal_projection_cb_ex(
+ void *userdata, void *userdata_chunk, const int i, const int UNUSED(threadid))
+{
+ ShrinkwrapCalcCBData *data = userdata;
+
+ ShrinkwrapCalcData *calc = data->calc;
+ void *treeData = data->treeData;
+ void *auxData = data->auxData;
+ BVHTree *targ_tree = data->targ_tree;
+ BVHTree *aux_tree = data->aux_tree;
+ void *targ_callback = data->targ_callback;
+ void *aux_callback = data->aux_callback;
+
+ float *proj_axis = data->proj_axis;
+ SpaceTransform *local2aux = data->local2aux;
+
+ BVHTreeRayHit *hit = userdata_chunk;
+
+ const float proj_limit_squared = calc->smd->projLimit * calc->smd->projLimit;
+ float *co = calc->vertexCos[i];
+ float tmp_co[3], tmp_no[3];
+ float weight = defvert_array_find_weight_safe(calc->dvert, i, calc->vgroup);
+
+ if (calc->invert_vgroup) {
+ weight = 1.0f - weight;
+ }
+
+ if (weight == 0.0f) {
+ return;
+ }
+
+ if (calc->vert) {
+ /* calc->vert contains verts from derivedMesh */
+ /* this coordinated are deformed by vertexCos only for normal projection (to get correct normals) */
+ /* for other cases calc->varts contains undeformed coordinates and vertexCos should be used */
+ if (calc->smd->projAxis == MOD_SHRINKWRAP_PROJECT_OVER_NORMAL) {
+ copy_v3_v3(tmp_co, calc->vert[i].co);
+ normal_short_to_float_v3(tmp_no, calc->vert[i].no);
+ }
+ else {
+ copy_v3_v3(tmp_co, co);
+ copy_v3_v3(tmp_no, proj_axis);
+ }
+ }
+ else {
+ copy_v3_v3(tmp_co, co);
+ copy_v3_v3(tmp_no, proj_axis);
+ }
+
+
+ hit->index = -1;
+ hit->dist = BVH_RAYCAST_DIST_MAX; /* TODO: we should use FLT_MAX here, but sweepsphere code isn't prepared for that */
+
+ /* Project over positive direction of axis */
+ if (calc->smd->shrinkOpts & MOD_SHRINKWRAP_PROJECT_ALLOW_POS_DIR) {
+ if (aux_tree) {
+ BKE_shrinkwrap_project_normal(
+ 0, tmp_co, tmp_no,
+ local2aux, aux_tree, hit,
+ aux_callback, auxData);
+ }
+
+ BKE_shrinkwrap_project_normal(
+ calc->smd->shrinkOpts, tmp_co, tmp_no,
+ &calc->local2target, targ_tree, hit,
+ targ_callback, treeData);
+ }
+
+ /* Project over negative direction of axis */
+ if (calc->smd->shrinkOpts & MOD_SHRINKWRAP_PROJECT_ALLOW_NEG_DIR) {
+ float inv_no[3];
+ negate_v3_v3(inv_no, tmp_no);
+
+ if (aux_tree) {
+ BKE_shrinkwrap_project_normal(
+ 0, tmp_co, inv_no,
+ local2aux, aux_tree, hit,
+ aux_callback, auxData);
+ }
+
+ BKE_shrinkwrap_project_normal(
+ calc->smd->shrinkOpts, tmp_co, inv_no,
+ &calc->local2target, targ_tree, hit,
+ targ_callback, treeData);
+ }
+
+ /* don't set the initial dist (which is more efficient),
+ * because its calculated in the targets space, we want the dist in our own space */
+ if (proj_limit_squared != 0.0f) {
+ if (len_squared_v3v3(hit->co, co) > proj_limit_squared) {
+ hit->index = -1;
+ }
+ }
+
+ if (hit->index != -1) {
+ madd_v3_v3v3fl(hit->co, hit->co, tmp_no, calc->keepDist);
+ interp_v3_v3v3(co, co, hit->co, weight);
+ }
+}
static void shrinkwrap_calc_normal_projection(ShrinkwrapCalcData *calc, bool for_render)
{
- int i;
-
/* Options about projection direction */
- const float proj_limit_squared = calc->smd->projLimit * calc->smd->projLimit;
float proj_axis[3] = {0.0f, 0.0f, 0.0f};
/* Raycast and tree stuff */
@@ -305,7 +424,7 @@ static void shrinkwrap_calc_normal_projection(ShrinkwrapCalcData *calc, bool for
}
if (targ_tree) {
BVHTree *aux_tree = NULL;
- void *aux_callback;
+ void *aux_callback = NULL;
if (auxMesh != NULL) {
/* use editmesh to avoid array allocation */
if (calc->smd->auxTarget && auxMesh->type == DM_TYPE_EDITBMESH) {
@@ -316,99 +435,22 @@ static void shrinkwrap_calc_normal_projection(ShrinkwrapCalcData *calc, bool for
}
}
else {
- if ((aux_tree = bvhtree_from_mesh_looptri(&dmauxdata_stack, calc->target, 0.0, 4, 6)) != NULL) {
+ if ((aux_tree = bvhtree_from_mesh_looptri(&dmauxdata_stack, auxMesh, 0.0, 4, 6)) != NULL) {
aux_callback = dmauxdata_stack.raycast_callback;
auxData = &dmauxdata_stack;
}
}
}
/* After sucessufuly build the trees, start projection vertexs */
-
-#ifndef __APPLE__
-#pragma omp parallel for private(i, hit) schedule(static) if (calc->numVerts > BKE_MESH_OMP_LIMIT)
-#endif
- for (i = 0; i < calc->numVerts; ++i) {
- float *co = calc->vertexCos[i];
- float tmp_co[3], tmp_no[3];
- float weight = defvert_array_find_weight_safe(calc->dvert, i, calc->vgroup);
-
- if (calc->invert_vgroup) {
- weight = 1.0f - weight;
- }
-
- if (weight == 0.0f) {
- continue;
- }
-
- if (calc->vert) {
- /* calc->vert contains verts from derivedMesh */
- /* this coordinated are deformed by vertexCos only for normal projection (to get correct normals) */
- /* for other cases calc->varts contains undeformed coordinates and vertexCos should be used */
- if (calc->smd->projAxis == MOD_SHRINKWRAP_PROJECT_OVER_NORMAL) {
- copy_v3_v3(tmp_co, calc->vert[i].co);
- normal_short_to_float_v3(tmp_no, calc->vert[i].no);
- }
- else {
- copy_v3_v3(tmp_co, co);
- copy_v3_v3(tmp_no, proj_axis);
- }
- }
- else {
- copy_v3_v3(tmp_co, co);
- copy_v3_v3(tmp_no, proj_axis);
- }
-
-
- hit.index = -1;
- hit.dist = BVH_RAYCAST_DIST_MAX; /* TODO: we should use FLT_MAX here, but sweepsphere code isn't prepared for that */
-
- /* Project over positive direction of axis */
- if (calc->smd->shrinkOpts & MOD_SHRINKWRAP_PROJECT_ALLOW_POS_DIR) {
-
- if (aux_tree) {
- BKE_shrinkwrap_project_normal(
- 0, tmp_co, tmp_no,
- &local2aux, aux_tree, &hit,
- aux_callback, auxData);
- }
-
- BKE_shrinkwrap_project_normal(
- calc->smd->shrinkOpts, tmp_co, tmp_no,
- &calc->local2target, targ_tree, &hit,
- targ_callback, treeData);
- }
-
- /* Project over negative direction of axis */
- if (calc->smd->shrinkOpts & MOD_SHRINKWRAP_PROJECT_ALLOW_NEG_DIR) {
- float inv_no[3];
- negate_v3_v3(inv_no, tmp_no);
-
- if (aux_tree) {
- BKE_shrinkwrap_project_normal(
- 0, tmp_co, inv_no,
- &local2aux, aux_tree, &hit,
- aux_callback, auxData);
- }
-
- BKE_shrinkwrap_project_normal(
- calc->smd->shrinkOpts, tmp_co, inv_no,
- &calc->local2target, targ_tree, &hit,
- targ_callback, treeData);
- }
-
- /* don't set the initial dist (which is more efficient),
- * because its calculated in the targets space, we want the dist in our own space */
- if (proj_limit_squared != 0.0f) {
- if (len_squared_v3v3(hit.co, co) > proj_limit_squared) {
- hit.index = -1;
- }
- }
-
- if (hit.index != -1) {
- madd_v3_v3v3fl(hit.co, hit.co, tmp_no, calc->keepDist);
- interp_v3_v3v3(co, co, hit.co, weight);
- }
- }
+ ShrinkwrapCalcCBData data = {
+ .calc = calc,
+ .treeData = treeData, .targ_tree = targ_tree, .targ_callback = targ_callback,
+ .auxData = auxData, .aux_tree = aux_tree, .aux_callback = aux_callback,
+ .proj_axis = proj_axis, .local2aux = &local2aux,
+ };
+ BLI_task_parallel_range_ex(
+ 0, calc->numVerts, &data, &hit, sizeof(hit), shrinkwrap_calc_normal_projection_cb_ex,
+ calc->numVerts > BKE_MESH_OMP_LIMIT, false);
}
/* free data structures */
@@ -428,10 +470,75 @@ static void shrinkwrap_calc_normal_projection(ShrinkwrapCalcData *calc, bool for
* it builds a BVHTree from the target mesh and then performs a
* NN matches for each vertex
*/
-static void shrinkwrap_calc_nearest_surface_point(ShrinkwrapCalcData *calc)
+static void shrinkwrap_calc_nearest_surface_point_cb_ex(
+ void *userdata, void *userdata_chunk, const int i, const int UNUSED(threadid))
{
- int i;
+ ShrinkwrapCalcCBData *data = userdata;
+
+ ShrinkwrapCalcData *calc = data->calc;
+ BVHTreeFromMesh *treeData = data->treeData;
+ BVHTreeNearest *nearest = userdata_chunk;
+
+ float *co = calc->vertexCos[i];
+ float tmp_co[3];
+ float weight = defvert_array_find_weight_safe(calc->dvert, i, calc->vgroup);
+
+ if (calc->invert_vgroup) {
+ weight = 1.0f - weight;
+ }
+
+ if (weight == 0.0f) {
+ return;
+ }
+
+ /* Convert the vertex to tree coordinates */
+ if (calc->vert) {
+ copy_v3_v3(tmp_co, calc->vert[i].co);
+ }
+ else {
+ copy_v3_v3(tmp_co, co);
+ }
+ BLI_space_transform_apply(&calc->local2target, tmp_co);
+
+ /* Use local proximity heuristics (to reduce the nearest search)
+ *
+ * If we already had an hit before.. we assume this vertex is going to have a close hit to that other vertex
+ * so we can initiate the "nearest.dist" with the expected value to that last hit.
+ * This will lead in pruning of the search tree. */
+ if (nearest->index != -1)
+ nearest->dist_sq = len_squared_v3v3(tmp_co, nearest->co);
+ else
+ nearest->dist_sq = FLT_MAX;
+
+ BLI_bvhtree_find_nearest(treeData->tree, tmp_co, nearest, treeData->nearest_callback, treeData);
+
+ /* Found the nearest vertex */
+ if (nearest->index != -1) {
+ if (calc->smd->shrinkOpts & MOD_SHRINKWRAP_KEEP_ABOVE_SURFACE) {
+ /* Make the vertex stay on the front side of the face */
+ madd_v3_v3v3fl(tmp_co, nearest->co, nearest->no, calc->keepDist);
+ }
+ else {
+ /* Adjusting the vertex weight,
+ * so that after interpolating it keeps a certain distance from the nearest position */
+ const float dist = sasqrt(nearest->dist_sq);
+ if (dist > FLT_EPSILON) {
+ /* linear interpolation */
+ interp_v3_v3v3(tmp_co, tmp_co, nearest->co, (dist - calc->keepDist) / dist);
+ }
+ else {
+ copy_v3_v3(tmp_co, nearest->co);
+ }
+ }
+ /* Convert the coordinates back to mesh coordinates */
+ BLI_space_transform_invert(&calc->local2target, tmp_co);
+ interp_v3_v3v3(co, co, tmp_co, weight); /* linear interpolation */
+ }
+}
+
+static void shrinkwrap_calc_nearest_surface_point(ShrinkwrapCalcData *calc)
+{
BVHTreeFromMesh treeData = NULL_BVHTreeFromMesh;
BVHTreeNearest nearest = NULL_BVHTreeNearest;
@@ -446,67 +553,11 @@ static void shrinkwrap_calc_nearest_surface_point(ShrinkwrapCalcData *calc)
nearest.index = -1;
nearest.dist_sq = FLT_MAX;
-
/* Find the nearest vertex */
-#ifndef __APPLE__
-#pragma omp parallel for default(none) private(i) firstprivate(nearest) shared(calc, treeData) schedule(static) if (calc->numVerts > BKE_MESH_OMP_LIMIT)
-#endif
- for (i = 0; i < calc->numVerts; ++i) {
- float *co = calc->vertexCos[i];
- float tmp_co[3];
- float weight = defvert_array_find_weight_safe(calc->dvert, i, calc->vgroup);
-
- if (calc->invert_vgroup) {
- weight = 1.0f - weight;
- }
-
- if (weight == 0.0f) continue;
-
- /* Convert the vertex to tree coordinates */
- if (calc->vert) {
- copy_v3_v3(tmp_co, calc->vert[i].co);
- }
- else {
- copy_v3_v3(tmp_co, co);
- }
- BLI_space_transform_apply(&calc->local2target, tmp_co);
-
- /* Use local proximity heuristics (to reduce the nearest search)
- *
- * If we already had an hit before.. we assume this vertex is going to have a close hit to that other vertex
- * so we can initiate the "nearest.dist" with the expected value to that last hit.
- * This will lead in pruning of the search tree. */
- if (nearest.index != -1)
- nearest.dist_sq = len_squared_v3v3(tmp_co, nearest.co);
- else
- nearest.dist_sq = FLT_MAX;
-
- BLI_bvhtree_find_nearest(treeData.tree, tmp_co, &nearest, treeData.nearest_callback, &treeData);
-
- /* Found the nearest vertex */
- if (nearest.index != -1) {
- if (calc->smd->shrinkOpts & MOD_SHRINKWRAP_KEEP_ABOVE_SURFACE) {
- /* Make the vertex stay on the front side of the face */
- madd_v3_v3v3fl(tmp_co, nearest.co, nearest.no, calc->keepDist);
- }
- else {
- /* Adjusting the vertex weight,
- * so that after interpolating it keeps a certain distance from the nearest position */
- const float dist = sasqrt(nearest.dist_sq);
- if (dist > FLT_EPSILON) {
- /* linear interpolation */
- interp_v3_v3v3(tmp_co, tmp_co, nearest.co, (dist - calc->keepDist) / dist);
- }
- else {
- copy_v3_v3(tmp_co, nearest.co);
- }
- }
-
- /* Convert the coordinates back to mesh coordinates */
- BLI_space_transform_invert(&calc->local2target, tmp_co);
- interp_v3_v3v3(co, co, tmp_co, weight); /* linear interpolation */
- }
- }
+ ShrinkwrapCalcCBData data = {.calc = calc, .treeData = &treeData};
+ BLI_task_parallel_range_ex(
+ 0, calc->numVerts, &data, &nearest, sizeof(nearest), shrinkwrap_calc_nearest_surface_point_cb_ex,
+ calc->numVerts > BKE_MESH_OMP_LIMIT, false);
free_bvhtree_from_mesh(&treeData);
}
diff --git a/source/blender/blenkernel/intern/subsurf_ccg.c b/source/blender/blenkernel/intern/subsurf_ccg.c
index 5fd418fadfc..88bc3fb9854 100644
--- a/source/blender/blenkernel/intern/subsurf_ccg.c
+++ b/source/blender/blenkernel/intern/subsurf_ccg.c
@@ -2996,6 +2996,7 @@ static void ccgDM_drawMappedFacesGLSL(DerivedMesh *dm,
if (matconv[a].attribs.totorco && matconv[a].attribs.orco.array) {
matconv[a].datatypes[numdata].index = matconv[a].attribs.orco.gl_index;
+ matconv[a].datatypes[numdata].info_index = matconv[a].attribs.orco.gl_info_index;
matconv[a].datatypes[numdata].size = 3;
matconv[a].datatypes[numdata].type = GL_FLOAT;
numdata++;
@@ -3003,6 +3004,7 @@ static void ccgDM_drawMappedFacesGLSL(DerivedMesh *dm,
for (b = 0; b < matconv[a].attribs.tottface; b++) {
if (matconv[a].attribs.tface[b].array) {
matconv[a].datatypes[numdata].index = matconv[a].attribs.tface[b].gl_index;
+ matconv[a].datatypes[numdata].info_index = matconv[a].attribs.tface[b].gl_info_index;
matconv[a].datatypes[numdata].size = 2;
matconv[a].datatypes[numdata].type = GL_FLOAT;
numdata++;
@@ -3011,6 +3013,7 @@ static void ccgDM_drawMappedFacesGLSL(DerivedMesh *dm,
for (b = 0; b < matconv[a].attribs.totmcol; b++) {
if (matconv[a].attribs.mcol[b].array) {
matconv[a].datatypes[numdata].index = matconv[a].attribs.mcol[b].gl_index;
+ matconv[a].datatypes[numdata].info_index = matconv[a].attribs.mcol[b].gl_info_index;
matconv[a].datatypes[numdata].size = 4;
matconv[a].datatypes[numdata].type = GL_UNSIGNED_BYTE;
numdata++;
@@ -3019,6 +3022,7 @@ static void ccgDM_drawMappedFacesGLSL(DerivedMesh *dm,
for (b = 0; b < matconv[a].attribs.tottang; b++) {
if (matconv[a].attribs.tottang && matconv[a].attribs.tang[b].array) {
matconv[a].datatypes[numdata].index = matconv[a].attribs.tang[b].gl_index;
+ matconv[a].datatypes[numdata].info_index = matconv[a].attribs.tang[b].gl_info_index;
matconv[a].datatypes[numdata].size = 4;
matconv[a].datatypes[numdata].type = GL_FLOAT;
numdata++;
diff --git a/source/blender/blenlib/BLI_array_store.h b/source/blender/blenlib/BLI_array_store.h
new file mode 100644
index 00000000000..f4cbc07bf26
--- /dev/null
+++ b/source/blender/blenlib/BLI_array_store.h
@@ -0,0 +1,66 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __BLI_ARRAY_STORE_H__
+#define __BLI_ARRAY_STORE_H__
+
+/** \file BLI_array_store.h
+ * \ingroup bli
+ * \brief Efficient in-memory storage of multiple similar arrays.
+ */
+
+typedef struct BArrayStore BArrayStore;
+typedef struct BArrayState BArrayState;
+
+BArrayStore *BLI_array_store_create(
+ unsigned int stride, unsigned int chunk_count);
+void BLI_array_store_destroy(
+ BArrayStore *bs);
+void BLI_array_store_clear(
+ BArrayStore *bs);
+
+/* find the memory used by all states (expanded & real) */
+size_t BLI_array_store_calc_size_expanded_get(
+ const BArrayStore *bs);
+size_t BLI_array_store_calc_size_compacted_get(
+ const BArrayStore *bs);
+
+BArrayState *BLI_array_store_state_add(
+ BArrayStore *bs,
+ const void *data, const size_t data_len,
+ const BArrayState *state_reference);
+void BLI_array_store_state_remove(
+ BArrayStore *bs,
+ BArrayState *state);
+
+size_t BLI_array_store_state_size_get(
+ BArrayState *state);
+void BLI_array_store_state_data_get(
+ BArrayState *state,
+ void *data);
+void *BLI_array_store_state_data_get_alloc(
+ BArrayState *state,
+ size_t *r_data_len);
+
+/* only for tests */
+bool BLI_array_store_is_valid(
+ BArrayStore *bs);
+
+#endif /* __BLI_ARRAY_STORE_H__ */
diff --git a/source/blender/blenlib/BLI_math_geom.h b/source/blender/blenlib/BLI_math_geom.h
index 45edaca544d..54b824c91ac 100644
--- a/source/blender/blenlib/BLI_math_geom.h
+++ b/source/blender/blenlib/BLI_math_geom.h
@@ -470,6 +470,10 @@ MINLINE float shell_v2v2_normalized_to_dist(const float a[2], const float b[2]);
MINLINE float shell_v3v3_mid_normalized_to_dist(const float a[3], const float b[3]);
MINLINE float shell_v2v2_mid_normalized_to_dist(const float a[2], const float b[2]);
+/********************************* Cubic (Bezier) *******************************/
+
+float cubic_tangent_factor_circle_v3(const float tan_l[3], const float tan_r[3]);
+
/**************************** Inline Definitions ******************************/
#if BLI_MATH_DO_INLINE
diff --git a/source/blender/blenlib/BLI_stackdefines.h b/source/blender/blenlib/BLI_stackdefines.h
index b26dc3e26aa..42b11eb9a2b 100644
--- a/source/blender/blenlib/BLI_stackdefines.h
+++ b/source/blender/blenlib/BLI_stackdefines.h
@@ -31,28 +31,28 @@
/* only validate array-bounds in debug mode */
#ifdef DEBUG
# define STACK_DECLARE(stack) unsigned int _##stack##_index, _##stack##_totalloc
-# define STACK_INIT(stack, tot) ((void)stack, (void)((_##stack##_index) = 0), (void)((_##stack##_totalloc) = tot))
-# define _STACK_SIZETEST(stack, off) (BLI_assert((_##stack##_index) + off <= _##stack##_totalloc))
+# define STACK_INIT(stack, tot) ((void)stack, (void)((_##stack##_index) = 0), (void)((_##stack##_totalloc) = (tot)))
+# define _STACK_SIZETEST(stack, off) (BLI_assert((_##stack##_index) + (off) <= _##stack##_totalloc))
# define _STACK_SWAP_TOTALLOC(stack_a, stack_b) SWAP(unsigned int, _##stack_a##_totalloc, _##stack_b##_totalloc)
#else
# define STACK_DECLARE(stack) unsigned int _##stack##_index
-# define STACK_INIT(stack, tot) ((void)stack, (void)((_##stack##_index) = 0), (void)(0 ? tot : 0))
+# define STACK_INIT(stack, tot) ((void)stack, (void)((_##stack##_index) = 0), (void)(0 ? (tot) : 0))
# define _STACK_SIZETEST(stack, off) (void)(stack), (void)(off)
# define _STACK_SWAP_TOTALLOC(stack_a, stack_b) (void)(stack_a), (void)(stack_b)
#endif
-#define _STACK_BOUNDSTEST(stack, index) ((void)stack, BLI_assert((unsigned int)index < _##stack##_index))
+#define _STACK_BOUNDSTEST(stack, index) ((void)stack, BLI_assert((unsigned int)(index) < _##stack##_index))
#define STACK_SIZE(stack) ((void)stack, (_##stack##_index))
#define STACK_CLEAR(stack) {(void)stack; _##stack##_index = 0; } ((void)0)
/** add item to stack */
-#define STACK_PUSH(stack, val) ((void)stack, _STACK_SIZETEST(stack, 1), ((stack)[(_##stack##_index)++] = val))
+#define STACK_PUSH(stack, val) ((void)stack, _STACK_SIZETEST(stack, 1), ((stack)[(_##stack##_index)++] = (val)))
#define STACK_PUSH_RET(stack) ((void)stack, _STACK_SIZETEST(stack, 1), ((stack)[(_##stack##_index)++]))
#define STACK_PUSH_RET_PTR(stack) ((void)stack, _STACK_SIZETEST(stack, 1), &((stack)[(_##stack##_index)++]))
/** take last item from stack */
#define STACK_POP(stack) ((_##stack##_index) ? ((stack)[--(_##stack##_index)]) : NULL)
#define STACK_POP_PTR(stack) ((_##stack##_index) ? &((stack)[--(_##stack##_index)]) : NULL)
-#define STACK_POP_DEFAULT(stack, r) ((_##stack##_index) ? ((stack)[--(_##stack##_index)]) : r)
+#define STACK_POP_DEFAULT(stack, r) ((_##stack##_index) ? ((stack)[--(_##stack##_index)]) : (r))
/** look at last item (assumes non-empty stack) */
#define STACK_PEEK(stack) (BLI_assert(_##stack##_index), ((stack)[_##stack##_index - 1]))
#define STACK_PEEK_PTR(stack) (BLI_assert(_##stack##_index), &((stack)[_##stack##_index - 1]))
diff --git a/source/blender/blenlib/CMakeLists.txt b/source/blender/blenlib/CMakeLists.txt
index 944ba60eb58..42d958774d8 100644
--- a/source/blender/blenlib/CMakeLists.txt
+++ b/source/blender/blenlib/CMakeLists.txt
@@ -52,6 +52,7 @@ set(SRC
intern/BLI_memarena.c
intern/BLI_mempool.c
intern/DLRB_tree.c
+ intern/array_store.c
intern/array_utils.c
intern/astar.c
intern/boxpack2d.c
@@ -120,6 +121,7 @@ set(SRC
BLI_alloca.h
BLI_args.h
BLI_array.h
+ BLI_array_store.h
BLI_array_utils.h
BLI_astar.h
BLI_bitmap.h
diff --git a/source/blender/blenlib/intern/BLI_mempool.c b/source/blender/blenlib/intern/BLI_mempool.c
index 7338804c685..b7a51f2c48e 100644
--- a/source/blender/blenlib/intern/BLI_mempool.c
+++ b/source/blender/blenlib/intern/BLI_mempool.c
@@ -57,12 +57,29 @@
#ifdef __BIG_ENDIAN__
/* Big Endian */
# define MAKE_ID(a, b, c, d) ( (int)(a) << 24 | (int)(b) << 16 | (c) << 8 | (d) )
+# define MAKE_ID_8(a, b, c, d, e, f, g, h) \
+ ((int64_t)(a) << 56 | (int64_t)(b) << 48 | (int64_t)(c) << 40 | (int64_t)(d) << 32 | \
+ (int64_t)(e) << 24 | (int64_t)(f) << 16 | (int64_t)(g) << 8 | (h) )
#else
/* Little Endian */
# define MAKE_ID(a, b, c, d) ( (int)(d) << 24 | (int)(c) << 16 | (b) << 8 | (a) )
+# define MAKE_ID_8(a, b, c, d, e, f, g, h) \
+ ((int64_t)(h) << 56 | (int64_t)(g) << 48 | (int64_t)(f) << 40 | (int64_t)(e) << 32 | \
+ (int64_t)(d) << 24 | (int64_t)(c) << 16 | (int64_t)(b) << 8 | (a) )
#endif
-#define FREEWORD MAKE_ID('f', 'r', 'e', 'e')
+/**
+ * Important that this value is an is _not_ aligned with ``sizeof(void *)``.
+ * So having a pointer to 2/4/8... aligned memory is enough to ensure the freeword will never be used.
+ * To be safe, use a word thats the same in both directions.
+ */
+#define FREEWORD ((sizeof(void *) > sizeof(int32_t)) ? \
+ MAKE_ID_8('e', 'e', 'r', 'f', 'f', 'r', 'e', 'e') : \
+ MAKE_ID('e', 'f', 'f', 'e'))
+
+/**
+ * The 'used' word just needs to be set to something besides FREEWORD.
+ */
#define USEDWORD MAKE_ID('u', 's', 'e', 'd')
/* currently totalloc isnt used */
@@ -87,7 +104,7 @@ static bool mempool_debug_memset = false;
*/
typedef struct BLI_freenode {
struct BLI_freenode *next;
- int freeword; /* used to identify this as a freed node */
+ intptr_t freeword; /* used to identify this as a freed node */
} BLI_freenode;
/**
@@ -588,19 +605,26 @@ void *BLI_mempool_iterstep(BLI_mempool_iter *iter)
*/
void *BLI_mempool_iterstep(BLI_mempool_iter *iter)
{
- BLI_freenode *ret;
+ if (UNLIKELY(iter->curchunk == NULL)) {
+ return NULL;
+ }
+ const unsigned int esize = iter->pool->esize;
+ BLI_freenode *curnode = POINTER_OFFSET(CHUNK_DATA(iter->curchunk), (esize * iter->curindex));
+ BLI_freenode *ret;
do {
- if (LIKELY(iter->curchunk)) {
- ret = (BLI_freenode *)(((char *)CHUNK_DATA(iter->curchunk)) + (iter->pool->esize * iter->curindex));
+ ret = curnode;
+
+ if (++iter->curindex != iter->pool->pchunk) {
+ curnode = POINTER_OFFSET(curnode, esize);
}
else {
- return NULL;
- }
-
- if (UNLIKELY(++iter->curindex == iter->pool->pchunk)) {
iter->curindex = 0;
iter->curchunk = iter->curchunk->next;
+ if (iter->curchunk == NULL) {
+ return NULL;
+ }
+ curnode = CHUNK_DATA(iter->curchunk);
}
} while (ret->freeword == FREEWORD);
diff --git a/source/blender/blenlib/intern/array_store.c b/source/blender/blenlib/intern/array_store.c
new file mode 100644
index 00000000000..9baccf38fa3
--- /dev/null
+++ b/source/blender/blenlib/intern/array_store.c
@@ -0,0 +1,1812 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/blenlib/intern/array_store.c
+ * \ingroup bli
+ * \brief Array storage to minimize duplication.
+ *
+ * This is done by splitting arrays into chunks and using copy-on-write (COW),
+ * to de-duplicate chunks,
+ * from the users perspective this is an implementation detail.
+ *
+ *
+ * Overview
+ * ========
+ *
+ *
+ * Data Structure
+ * --------------
+ *
+ * This diagram is an overview of the structure of a single array-store.
+ *
+ * \note The only 2 structues here which are referenced externally are the.
+ *
+ * - BArrayStore: The whole array store.
+ * - BArrayState: Represents a single state (array) of data.
+ * These can be add using a reference state, while this could be considered the previous or parent state.
+ * no relationship is kept, so the caller is free to add any state from the same BArrayStore as a reference.
+ *
+ * <pre>
+ * <+> BArrayStore: root data-structure,
+ * | can store many 'states', which share memory.
+ * |
+ * | This can store many arrays, however they must share the same 'stride'.
+ * | Arrays of different types will need to use a new BArrayStore.
+ * |
+ * +- <+> states (Collection of BArrayState's):
+ * | | Each represents an array added by the user of this API.
+ * | | and references a chunk_list (each state is a chunk_list user).
+ * | | Note that the list order has no significance.
+ * | |
+ * | +- <+> chunk_list (BChunkList):
+ * | | The chunks that make up this state.
+ * | | Each state is a chunk_list user,
+ * | | avoids duplicating lists when there is no change between states.
+ * | |
+ * | +- chunk_refs (List of BChunkRef): Each chunk_ref links to a a BChunk.
+ * | Each reference is a chunk user,
+ * | avoids duplicating smaller chunks of memory found in multiple states.
+ * |
+ * +- info (BArrayInfo):
+ * | Sizes and offsets for this array-store.
+ * | Also caches some variables for reuse.
+ * |
+ * +- <+> memory (BArrayMemory):
+ * | Memory pools for storing BArrayStore data.
+ * |
+ * +- chunk_list (Pool of BChunkList):
+ * | All chunk_lists, (reference counted, used by BArrayState).
+ * |
+ * +- chunk_ref (Pool of BChunkRef):
+ * | All chunk_refs (link between BChunkList & BChunk).
+ * |
+ * +- chunks (Pool of BChunk):
+ * All chunks, (reference counted, used by BChunkList).
+ * These have their headers hashed for reuse so we can quickly check for duplicates.
+ * </pre>
+ *
+ *
+ * De-Duplication
+ * --------------
+ *
+ * When creating a new state, a previous state can be given as a reference,
+ * matching chunks from this state are re-used in the new state.
+ *
+ * First matches at either end of the array are detected.
+ * For identical arrays this is all thats needed.
+ *
+ * De-duplication is performed on any remaining chunks, by hasing the first few bytes of the chunk
+ * (see: BCHUNK_HASH_TABLE_ACCUMULATE_STEPS).
+ *
+ * \note This is cached for reuse since the referenced data never changes.
+ *
+ * An array is created to store hash values at every 'stride',
+ * then stepped over to search for matching chunks.
+ *
+ * Once a match is found, there is a high chance next chunks match too,
+ * so this is checked to avoid performing so many hash-lookups.
+ * Otherwise new chunks are created.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_listbase.h"
+#include "BLI_mempool.h"
+
+#include "BLI_strict_flags.h"
+
+#include "BLI_array_store.h" /* own include */
+
+/* only for BLI_array_store_is_valid */
+#include "BLI_ghash.h"
+
+/** \name Defines
+ *
+ * Some of the logic for merging is quite involved,
+ * support disabling some parts of this.
+ * \{ */
+
+/* Scan first chunks (happy path when beginning of the array matches).
+ * When the array is a perfect match, we can re-use the entire list.
+ *
+ * Note that disabling makes some tests fail that check for output-size.
+ */
+#define USE_FASTPATH_CHUNKS_FIRST
+
+/* Scan last chunks (happy path when end of the array matches).
+ * When the end of the array matches, we can quickly add these chunks.
+ * note that we will add contiguous matching chunks
+ * so this isn't as useful as USE_FASTPATH_CHUNKS_FIRST,
+ * however it avoids adding matching chunks into the lookup table,
+ * so creating the lookup table won't be as expensive.
+ */
+#ifdef USE_FASTPATH_CHUNKS_FIRST
+# define USE_FASTPATH_CHUNKS_LAST
+#endif
+
+/* For arrays of matching length, test that *enough* of the chunks are aligned,
+ * and simply step over both arrays, using matching chunks.
+ * This avoids overhead of using a lookup table for cases when we can assume they're mostly aligned.
+ */
+#define USE_ALIGN_CHUNKS_TEST
+
+/* Accumulate hashes from right to left so we can create a hash for the chunk-start.
+ * This serves to increase uniqueness and will help when there is many values which are the same.
+ */
+#define USE_HASH_TABLE_ACCUMULATE
+
+#ifdef USE_HASH_TABLE_ACCUMULATE
+/* Number of times to propagate hashes back.
+ * Effectively a 'triangle-number'.
+ * so 4 -> 7, 5 -> 10, 6 -> 15... etc.
+ */
+# define BCHUNK_HASH_TABLE_ACCUMULATE_STEPS 4
+#else
+/* How many items to hash (multiplied by stride)
+ */
+# define BCHUNK_HASH_LEN 4
+#endif
+
+/* Calculate the key once and reuse it
+ */
+#define USE_HASH_TABLE_KEY_CACHE
+#ifdef USE_HASH_TABLE_KEY_CACHE
+# define HASH_TABLE_KEY_UNSET ((uint64_t)-1)
+# define HASH_TABLE_KEY_FALLBACK ((uint64_t)-2)
+#endif
+
+/* How much larger the table is then the total number of chunks.
+ */
+#define BCHUNK_HASH_TABLE_MUL 3
+
+/* Merge too small/large chunks:
+ *
+ * Using this means chunks below a threshold will be merged together.
+ * Even though short term this uses more memory,
+ * long term the overhead of maintaining many small chunks is reduced.
+ * This is defined by setting the minimum chunk size (as a fraction of the regular chunk size).
+ *
+ * Chunks may also become too large (when incrementally growing an array),
+ * this also enables chunk splitting.
+ */
+#define USE_MERGE_CHUNKS
+
+#ifdef USE_MERGE_CHUNKS
+/* Merge chunks smaller then: (chunk_size / BCHUNK_MIN_SIZE_DIV)
+ */
+# define BCHUNK_SIZE_MIN_DIV 8
+
+/* Disallow chunks bigger then the regular chunk size scaled by this value
+ * note: must be at least 2!
+ * however, this code runs wont run in tests unless its ~1.1 ugh.
+ * so lower only to check splitting works.
+ */
+# define BCHUNK_SIZE_MAX_MUL 2
+#endif /* USE_MERGE_CHUNKS */
+
+/* slow (keep disabled), but handy for debugging */
+// #define USE_VALIDATE_LIST_SIZE
+
+// #define USE_VALIDATE_LIST_DATA_PARTIAL
+
+// #define USE_PARANOID_CHECKS
+
+/** \} */
+
+
+/** \name Internal Structs
+ * \{ */
+
+typedef unsigned int uint;
+typedef unsigned char ubyte;
+
+typedef uint64_t hash_key;
+
+
+typedef struct BArrayInfo {
+ size_t chunk_stride;
+ uint chunk_count;
+
+ /* pre-calculated */
+ size_t chunk_byte_size;
+ /* min/max limits (inclusive) */
+ size_t chunk_byte_size_min;
+ size_t chunk_byte_size_max;
+
+ size_t accum_read_ahead_bytes;
+#ifdef USE_HASH_TABLE_ACCUMULATE
+ size_t accum_steps;
+ size_t accum_read_ahead_len;
+#endif
+} BArrayInfo;
+
+typedef struct BArrayMemory {
+ BLI_mempool *chunk_list; /* BChunkList */
+ BLI_mempool *chunk_ref; /* BChunkRef */
+ BLI_mempool *chunk; /* BChunk */
+} BArrayMemory;
+
+/**
+ * Main storage for all states
+ */
+typedef struct BArrayStore {
+ /* static */
+ BArrayInfo info;
+
+ /* memory storage */
+ BArrayMemory memory;
+
+ /**
+ * #BArrayState may be in any order (logic should never depend on state order).
+ */
+ ListBase states;
+} BArrayStore;
+
+/**
+ * A single instance of an array.
+ *
+ * This is how external API's hold a reference to an in-memory state,
+ * although the struct is private.
+ *
+ * \note Currently each 'state' is allocated separately.
+ * While this could be moved to a memory pool,
+ * it makes it easier to trace invalid usage, so leave as-is for now.
+ */
+typedef struct BArrayState {
+ /** linked list in #BArrayStore.states */
+ struct BArrayState *next, *prev;
+
+ struct BChunkList *chunk_list; /* BChunkList's */
+
+} BArrayState;
+
+typedef struct BChunkList {
+ ListBase chunk_refs; /* BChunkRef's */
+ uint chunk_refs_len; /* BLI_listbase_count(chunks), store for reuse. */
+ size_t total_size; /* size of all chunks */
+
+ /** number of #BArrayState using this. */
+ int users;
+} BChunkList;
+
+/* a chunk of an array */
+typedef struct BChunk {
+ const ubyte *data;
+ size_t data_len;
+ /** number of #BChunkList using this. */
+ int users;
+
+#ifdef USE_HASH_TABLE_KEY_CACHE
+ hash_key key;
+#endif
+} BChunk;
+
+/**
+ * Links to store #BChunk data in #BChunkList.chunks.
+ */
+typedef struct BChunkRef {
+ struct BChunkRef *next, *prev;
+ BChunk *link;
+} BChunkRef;
+
+/**
+ * Single linked list used when putting chunks into a temporary table,
+ * used for lookups.
+ *
+ * Point to the #BChunkRef, not the #BChunk,
+ * to allow talking down the chunks in-order until a mis-match is found,
+ * this avoids having to do so many table lookups.
+ */
+typedef struct BTableRef {
+ struct BTableRef *next;
+ const BChunkRef *cref;
+} BTableRef;
+
+/** \} */
+
+
+static size_t bchunk_list_size(const BChunkList *chunk_list);
+
+
+/** \name Internal BChunk API
+ * \{ */
+
+static BChunk *bchunk_new(
+ BArrayMemory *bs_mem, const ubyte *data, const size_t data_len)
+{
+ BChunk *chunk = BLI_mempool_alloc(bs_mem->chunk);
+ chunk->data = data;
+ chunk->data_len = data_len;
+ chunk->users = 0;
+#ifdef USE_HASH_TABLE_KEY_CACHE
+ chunk->key = HASH_TABLE_KEY_UNSET;
+#endif
+ return chunk;
+}
+
+static BChunk *bchunk_new_copydata(
+ BArrayMemory *bs_mem, const ubyte *data, const size_t data_len)
+{
+ ubyte *data_copy = MEM_mallocN(data_len, __func__);
+ memcpy(data_copy, data, data_len);
+ return bchunk_new(bs_mem, data_copy, data_len);
+}
+
+static void bchunk_decref(
+ BArrayMemory *bs_mem, BChunk *chunk)
+{
+ BLI_assert(chunk->users > 0);
+ if (chunk->users == 1) {
+ MEM_freeN((void *)chunk->data);
+ BLI_mempool_free(bs_mem->chunk, chunk);
+ }
+ else {
+ chunk->users -= 1;
+ }
+}
+
+static bool bchunk_data_compare(
+ const BChunk *chunk,
+ const ubyte *data_base, const size_t data_base_len,
+ const size_t offset)
+{
+ if (offset + (size_t)chunk->data_len <= data_base_len) {
+ return (memcmp(&data_base[offset], chunk->data, chunk->data_len) == 0);
+ }
+ else {
+ return false;
+ }
+}
+
+/** \} */
+
+
+/** \name Internal BChunkList API
+ * \{ */
+
+static BChunkList *bchunk_list_new(
+ BArrayMemory *bs_mem, size_t total_size)
+{
+ BChunkList *chunk_list = BLI_mempool_alloc(bs_mem->chunk_list);
+
+ BLI_listbase_clear(&chunk_list->chunk_refs);
+ chunk_list->chunk_refs_len = 0;
+ chunk_list->total_size = total_size;
+ chunk_list->users = 0;
+ return chunk_list;
+}
+
+static void bchunk_list_decref(
+ BArrayMemory *bs_mem, BChunkList *chunk_list)
+{
+ BLI_assert(chunk_list->users > 0);
+ if (chunk_list->users == 1) {
+ for (BChunkRef *cref = chunk_list->chunk_refs.first, *cref_next; cref; cref = cref_next) {
+ cref_next = cref->next;
+ bchunk_decref(bs_mem, cref->link);
+ BLI_mempool_free(bs_mem->chunk_ref, cref);
+ }
+
+ BLI_mempool_free(bs_mem->chunk_list, chunk_list);
+ }
+ else {
+ chunk_list->users -= 1;
+ }
+}
+
+#ifdef USE_VALIDATE_LIST_SIZE
+# ifndef NDEBUG
+# define ASSERT_CHUNKLIST_SIZE(chunk_list, n) BLI_assert(bchunk_list_size(chunk_list) == n)
+# endif
+#endif
+#ifndef ASSERT_CHUNKLIST_SIZE
+# define ASSERT_CHUNKLIST_SIZE(chunk_list, n) (EXPR_NOP(chunk_list), EXPR_NOP(n))
+#endif
+
+
+#ifdef USE_VALIDATE_LIST_DATA_PARTIAL
+static size_t bchunk_list_data_check(
+ const BChunkList *chunk_list, const ubyte *data)
+{
+ size_t total_size = 0;
+ for (BChunkRef *cref = chunk_list->chunk_refs.first; cref; cref = cref->next) {
+ if (memcmp(&data[total_size], cref->link->data, cref->link->data_len) != 0) {
+ return false;
+ }
+ total_size += cref->link->data_len;
+ }
+ return true;
+}
+# define ASSERT_CHUNKLIST_DATA(chunk_list, data) BLI_assert(bchunk_list_data_check(chunk_list, data))
+#else
+# define ASSERT_CHUNKLIST_DATA(chunk_list, data) (EXPR_NOP(chunk_list), EXPR_NOP(data))
+#endif
+
+
+#ifdef USE_MERGE_CHUNKS
+static void bchunk_list_ensure_min_size_last(
+ const BArrayInfo *info, BArrayMemory *bs_mem,
+ BChunkList *chunk_list)
+{
+ BChunkRef *cref = chunk_list->chunk_refs.last;
+ if (cref && cref->prev) {
+ /* both are decref'd after use (end of this block) */
+ BChunk *chunk_curr = cref->link;
+ BChunk *chunk_prev = cref->prev->link;
+
+ if (MIN2(chunk_prev->data_len, chunk_curr->data_len) < info->chunk_byte_size_min) {
+ const size_t data_merge_len = chunk_prev->data_len + chunk_curr->data_len;
+ /* we could pass, but no need */
+ if (data_merge_len <= info->chunk_byte_size_max) {
+ /* we have enough space to merge */
+
+ /* remove last from linklist */
+ BLI_assert(chunk_list->chunk_refs.last != chunk_list->chunk_refs.first);
+ cref->prev->next = NULL;
+ chunk_list->chunk_refs.last = cref->prev;
+ chunk_list->chunk_refs_len -= 1;
+
+ ubyte *data_merge = MEM_mallocN(data_merge_len, __func__);
+ memcpy(data_merge, chunk_prev->data, chunk_prev->data_len);
+ memcpy(&data_merge[chunk_prev->data_len], chunk_curr->data, chunk_curr->data_len);
+
+ cref->prev->link = bchunk_new(bs_mem, data_merge, data_merge_len);
+ cref->prev->link->users += 1;
+
+ BLI_mempool_free(bs_mem->chunk_ref, cref);
+ }
+ else {
+ /* If we always merge small slices, we should _almost_ never end up having very large chunks.
+ * Gradual expanding on contracting will cause this.
+ *
+ * if we do, the code below works (test by setting 'BCHUNK_SIZE_MAX_MUL = 1.2') */
+
+ /* keep chunk on the left hand side a regular size */
+ const size_t split = info->chunk_byte_size;
+
+ /* merge and split */
+ const size_t data_prev_len = split;
+ const size_t data_curr_len = data_merge_len - split;
+ ubyte *data_prev = MEM_mallocN(data_prev_len, __func__);
+ ubyte *data_curr = MEM_mallocN(data_curr_len, __func__);
+
+ if (data_prev_len <= chunk_prev->data_len) {
+ const size_t data_curr_shrink_len = chunk_prev->data_len - data_prev_len;
+
+ /* setup 'data_prev' */
+ memcpy(data_prev, chunk_prev->data, data_prev_len);
+
+ /* setup 'data_curr' */
+ memcpy(data_curr, &chunk_prev->data[data_prev_len], data_curr_shrink_len);
+ memcpy(&data_curr[data_curr_shrink_len], chunk_curr->data, chunk_curr->data_len);
+ }
+ else {
+ BLI_assert(data_curr_len <= chunk_curr->data_len);
+ BLI_assert(data_prev_len >= chunk_prev->data_len);
+
+ const size_t data_prev_grow_len = data_prev_len - chunk_prev->data_len;
+
+ /* setup 'data_prev' */
+ memcpy(data_prev, chunk_prev->data, chunk_prev->data_len);
+ memcpy(&data_prev[chunk_prev->data_len], chunk_curr->data, data_prev_grow_len);
+
+ /* setup 'data_curr' */
+ memcpy(data_curr, &chunk_curr->data[data_prev_grow_len], data_curr_len);
+ }
+
+ cref->prev->link = bchunk_new(bs_mem, data_prev, data_prev_len);
+ cref->prev->link->users += 1;
+
+ cref->link = bchunk_new(bs_mem, data_curr, data_curr_len);
+ cref->link->users += 1;
+ }
+
+ /* free zero users */
+ bchunk_decref(bs_mem, chunk_curr);
+ bchunk_decref(bs_mem, chunk_prev);
+ }
+ }
+}
+#endif /* USE_MERGE_CHUNKS */
+
+
+/**
+ * Split length into 2 values
+ * \param r_data_trim_len: Length which is aligned to the #BArrayInfo.chunk_byte_size
+ * \param r_data_last_chunk_len: The remaining bytes.
+ *
+ * \note This function ensures the size of \a r_data_last_chunk_len
+ * is larger than #BArrayInfo.chunk_byte_size_min.
+ */
+static void bchunk_list_calc_trim_len(
+ const BArrayInfo *info, const size_t data_len,
+ size_t *r_data_trim_len, size_t *r_data_last_chunk_len)
+{
+ size_t data_last_chunk_len = 0;
+ size_t data_trim_len = data_len;
+
+#ifdef USE_MERGE_CHUNKS
+ /* avoid creating too-small chunks
+ * more efficient then merging after */
+ if (data_len > info->chunk_byte_size) {
+ data_last_chunk_len = (data_trim_len % info->chunk_byte_size);
+ data_trim_len = data_trim_len - data_last_chunk_len;
+ if (data_last_chunk_len) {
+ if (data_last_chunk_len < info->chunk_byte_size_min) {
+ /* may be zero and thats OK */
+ data_trim_len -= info->chunk_byte_size;
+ data_last_chunk_len += info->chunk_byte_size;
+ }
+ }
+ }
+ else {
+ data_trim_len = 0;
+ data_last_chunk_len = data_len;
+ }
+
+ BLI_assert((data_trim_len == 0) || (data_trim_len >= info->chunk_byte_size));
+#else
+ data_last_chunk_len = (data_trim_len % info->chunk_byte_size);
+ data_trim_len = data_trim_len - data_last_chunk_len;
+#endif
+
+ BLI_assert(data_trim_len + data_last_chunk_len == data_len);
+
+ *r_data_trim_len = data_trim_len;
+ *r_data_last_chunk_len = data_last_chunk_len;
+}
+
+/**
+ * Append and don't manage merging small chunks.
+ */
+static bool bchunk_list_append_only(
+ BArrayMemory *bs_mem,
+ BChunkList *chunk_list, BChunk *chunk)
+{
+ BChunkRef *cref = BLI_mempool_alloc(bs_mem->chunk_ref);
+ BLI_addtail(&chunk_list->chunk_refs, cref);
+ cref->link = chunk;
+ chunk_list->chunk_refs_len += 1;
+ chunk->users += 1;
+ return chunk;
+}
+
+/**
+ * \note This is for writing single chunks,
+ * use #bchunk_list_append_data_n when writing large blocks of memory into many chunks.
+ */
+static void bchunk_list_append_data(
+ const BArrayInfo *info, BArrayMemory *bs_mem,
+ BChunkList *chunk_list,
+ const ubyte *data, const size_t data_len)
+{
+ BLI_assert(data_len != 0);
+
+ // printf("data_len: %d\n", data_len);
+#ifdef USE_MERGE_CHUNKS
+ BLI_assert(data_len <= info->chunk_byte_size_max);
+
+ if (!BLI_listbase_is_empty(&chunk_list->chunk_refs)) {
+ BChunkRef *cref = chunk_list->chunk_refs.last;
+ BChunk *chunk_prev = cref->link;
+
+ if (MIN2(chunk_prev->data_len, data_len) < info->chunk_byte_size_min) {
+ const size_t data_merge_len = chunk_prev->data_len + data_len;
+ /* realloc for single user */
+ if (cref->link->users == 1) {
+ ubyte *data_merge = MEM_reallocN((void *)cref->link->data, data_merge_len);
+ memcpy(&data_merge[chunk_prev->data_len], data, data_len);
+ cref->link->data = data_merge;
+ cref->link->data_len = data_merge_len;
+ }
+ else {
+ ubyte *data_merge = MEM_mallocN(data_merge_len, __func__);
+ memcpy(data_merge, chunk_prev->data, chunk_prev->data_len);
+ memcpy(&data_merge[chunk_prev->data_len], data, data_len);
+ cref->link = bchunk_new(bs_mem, data_merge, data_merge_len);
+ cref->link->users += 1;
+ bchunk_decref(bs_mem, chunk_prev);
+ }
+ return;
+ }
+ }
+#else
+ UNUSED_VARS(info);
+#endif /* USE_MERGE_CHUNKS */
+
+ BChunk *chunk = bchunk_new_copydata(bs_mem, data, data_len);
+ bchunk_list_append_only(bs_mem, chunk_list, chunk);
+
+ /* don't run this, instead preemptively avoid creating a chunk only to merge it (above). */
+#if 0
+#ifdef USE_MERGE_CHUNKS
+ bchunk_list_ensure_min_size_last(info, bs_mem, chunk_list, chunk_size_min);
+#endif
+#endif
+}
+
+/**
+ * Similar to #bchunk_list_append_data, but handle multiple chunks.
+ * Use for adding arrays of arbitrary sized memory at once.
+ *
+ * \note This function takes care not to perform redundant chunk-merging checks,
+ * so we can write succesive fixed size chunks quickly.
+ */
+static void bchunk_list_append_data_n(
+ const BArrayInfo *info, BArrayMemory *bs_mem,
+ BChunkList *chunk_list,
+ const ubyte *data, size_t data_len)
+{
+ size_t data_trim_len, data_last_chunk_len;
+ bchunk_list_calc_trim_len(info, data_len, &data_trim_len, &data_last_chunk_len);
+
+ if (data_trim_len != 0) {
+ size_t i_prev;
+
+ {
+ const size_t i = info->chunk_byte_size;
+ bchunk_list_append_data(info, bs_mem, chunk_list, data, i);
+ i_prev = i;
+ }
+
+ while (i_prev != data_trim_len) {
+ const size_t i = i_prev + info->chunk_byte_size;
+ BChunk *chunk = bchunk_new_copydata(bs_mem, &data[i_prev], i - i_prev);
+ bchunk_list_append_only(bs_mem, chunk_list, chunk);
+ i_prev = i;
+ }
+
+ if (data_last_chunk_len) {
+ BChunk *chunk = bchunk_new_copydata(bs_mem, &data[i_prev], data_last_chunk_len);
+ bchunk_list_append_only(bs_mem, chunk_list, chunk);
+ // i_prev = data_len; /* UNUSED */
+ }
+ }
+ else {
+ /* if we didn't write any chunks previously,
+ * we may need to merge with the last. */
+ if (data_last_chunk_len) {
+ bchunk_list_append_data(info, bs_mem, chunk_list, data, data_last_chunk_len);
+ // i_prev = data_len; /* UNUSED */
+ }
+ }
+
+#ifdef USE_MERGE_CHUNKS
+ if (data_len > info->chunk_byte_size) {
+ BLI_assert(((BChunkRef *)chunk_list->chunk_refs.last)->link->data_len >= info->chunk_byte_size_min);
+ }
+#endif
+}
+
+static void bchunk_list_append(
+ const BArrayInfo *info, BArrayMemory *bs_mem,
+ BChunkList *chunk_list,
+ BChunk *chunk)
+{
+ bchunk_list_append_only(bs_mem, chunk_list, chunk);
+
+#ifdef USE_MERGE_CHUNKS
+ bchunk_list_ensure_min_size_last(info, bs_mem, chunk_list);
+#else
+ UNUSED_VARS(info);
+#endif
+}
+
+static void bchunk_list_fill_from_array(
+ const BArrayInfo *info, BArrayMemory *bs_mem,
+ BChunkList *chunk_list,
+ const ubyte *data,
+ const size_t data_len)
+{
+ BLI_assert(BLI_listbase_is_empty(&chunk_list->chunk_refs));
+
+ size_t data_trim_len, data_last_chunk_len;
+ bchunk_list_calc_trim_len(info, data_len, &data_trim_len, &data_last_chunk_len);
+
+ size_t i_prev = 0;
+ while (i_prev != data_trim_len) {
+ const size_t i = i_prev + info->chunk_byte_size;
+ BChunk *chunk = bchunk_new_copydata(bs_mem, &data[i_prev], i - i_prev);
+ bchunk_list_append_only(bs_mem, chunk_list, chunk);
+ i_prev = i;
+ }
+
+ if (data_last_chunk_len) {
+ BChunk *chunk = bchunk_new_copydata(bs_mem, &data[i_prev], data_last_chunk_len);
+ bchunk_list_append_only(bs_mem, chunk_list, chunk);
+ // i_prev = data_len;
+ }
+
+#ifdef USE_MERGE_CHUNKS
+ if (data_len > info->chunk_byte_size) {
+ BLI_assert(((BChunkRef *)chunk_list->chunk_refs.last)->link->data_len >= info->chunk_byte_size_min);
+ }
+#endif
+
+ /* works but better avoid redundant re-alloc */
+#if 0
+#ifdef USE_MERGE_CHUNKS
+ bchunk_list_ensure_min_size_last(info, bs_mem, chunk_list);
+#endif
+#endif
+
+ ASSERT_CHUNKLIST_SIZE(chunk_list, data_len);
+ ASSERT_CHUNKLIST_DATA(chunk_list, data);
+}
+
+
+/* ---------------------------------------------------------------------------
+ * Internal Table Lookup Functions
+ */
+
+/** \name Internal Hashing/De-Duplication API
+ *
+ * Only used by #bchunk_list_from_data_merge
+ * \{ */
+
+#define HASH_INIT (5381)
+
+BLI_INLINE uint hash_data_single(const ubyte p)
+{
+ return (HASH_INIT << 5) + HASH_INIT + (unsigned int)p;
+}
+
+/* hash bytes, from BLI_ghashutil_strhash_n */
+static uint hash_data(const ubyte *key, size_t n)
+{
+ const signed char *p;
+ unsigned int h = HASH_INIT;
+
+ for (p = (const signed char *)key; n--; p++) {
+ h = (h << 5) + h + (unsigned int)*p;
+ }
+
+ return h;
+}
+
+#undef HASH_INIT
+
+
+#ifdef USE_HASH_TABLE_ACCUMULATE
+static void hash_array_from_data(
+ const BArrayInfo *info, const ubyte *data_slice, const size_t data_slice_len,
+ hash_key *hash_array)
+{
+ if (info->chunk_stride != 1) {
+ for (size_t i = 0, i_step = 0; i_step < data_slice_len; i++, i_step += info->chunk_stride) {
+ hash_array[i] = hash_data(&data_slice[i_step], info->chunk_stride);
+ }
+ }
+ else {
+ /* fast-path for bytes */
+ for (size_t i = 0; i < data_slice_len; i++) {
+ hash_array[i] = hash_data_single(data_slice[i]);
+ }
+ }
+}
+
+/*
+ * Similar to hash_array_from_data,
+ * but able to step into the next chunk if we run-out of data.
+ */
+static void hash_array_from_cref(
+ const BArrayInfo *info, const BChunkRef *cref, const size_t data_len,
+ hash_key *hash_array)
+{
+ const size_t hash_array_len = data_len / info->chunk_stride;
+ size_t i = 0;
+ do {
+ size_t i_next = hash_array_len - i;
+ size_t data_trim_len = i_next * info->chunk_stride;
+ if (data_trim_len > cref->link->data_len) {
+ data_trim_len = cref->link->data_len;
+ i_next = data_trim_len / info->chunk_stride;
+ }
+ BLI_assert(data_trim_len <= cref->link->data_len);
+ hash_array_from_data(info, cref->link->data, data_trim_len, &hash_array[i]);
+ i += i_next;
+ cref = cref->next;
+ } while ((i < hash_array_len) && (cref != NULL));
+
+ /* If this isn't equal, the caller didn't properly check
+ * that there was enough data left in all chunks */
+ BLI_assert(i == hash_array_len);
+}
+
+static void hash_accum(hash_key *hash_array, const size_t hash_array_len, size_t iter_steps)
+{
+ /* _very_ unlikely, can happen if you select a chunk-size of 1 for example. */
+ if (UNLIKELY((iter_steps > hash_array_len))) {
+ iter_steps = hash_array_len;
+ }
+
+ const size_t hash_array_search_len = hash_array_len - iter_steps;
+ while (iter_steps != 0) {
+ const size_t hash_offset = iter_steps;
+ for (uint i = 0; i < hash_array_search_len; i++) {
+ hash_array[i] += (hash_array[i + hash_offset]) * ((hash_array[i] & 0xff) + 1);
+ }
+ iter_steps -= 1;
+ }
+}
+
+/**
+ * When we only need a single value, can use a small optimization.
+ * we can avoid accumulating the tail of the array a little, each iteration.
+ */
+static void hash_accum_single(hash_key *hash_array, const size_t hash_array_len, size_t iter_steps)
+{
+ BLI_assert(iter_steps <= hash_array_len);
+ if (UNLIKELY(!(iter_steps <= hash_array_len))) {
+ /* while this shouldn't happen, avoid crashing */
+ iter_steps = hash_array_len;
+ }
+ /* We can increase this value each step to avoid accumulating quite as much
+ * while getting the same results as hash_accum */
+ size_t iter_steps_sub = iter_steps;
+
+ while (iter_steps != 0) {
+ const size_t hash_array_search_len = hash_array_len - iter_steps_sub;
+ const size_t hash_offset = iter_steps;
+ for (uint i = 0; i < hash_array_search_len; i++) {
+ hash_array[i] += (hash_array[i + hash_offset]) * ((hash_array[i] & 0xff) + 1);
+ }
+ iter_steps -= 1;
+ iter_steps_sub += iter_steps;
+ }
+}
+
+static hash_key key_from_chunk_ref(
+ const BArrayInfo *info, const BChunkRef *cref,
+ /* avoid reallicating each time */
+ hash_key *hash_store, const size_t hash_store_len)
+{
+ /* in C, will fill in a reusable array */
+ BChunk *chunk = cref->link;
+ BLI_assert(info->accum_read_ahead_bytes * info->chunk_stride);
+
+ if (info->accum_read_ahead_bytes <= chunk->data_len) {
+ hash_key key;
+
+#ifdef USE_HASH_TABLE_KEY_CACHE
+ key = chunk->key;
+ if (key != HASH_TABLE_KEY_UNSET) {
+ /* Using key cache!
+ * avoids calculating every time */
+ }
+ else {
+ hash_array_from_cref(info, cref, info->accum_read_ahead_bytes, hash_store);
+ hash_accum_single(hash_store, hash_store_len, info->accum_steps);
+ key = hash_store[0];
+
+ /* cache the key */
+ if (key == HASH_TABLE_KEY_UNSET) {
+ key = HASH_TABLE_KEY_FALLBACK;
+ }
+ chunk->key = key;
+ }
+#else
+ hash_array_from_cref(info, cref, info->accum_read_ahead_bytes, hash_store);
+ hash_accum_single(hash_store, hash_store_len, info->accum_steps);
+ key = hash_store[0];
+#endif
+ return key;
+ }
+ else {
+ /* corner case - we're too small, calculate the key each time. */
+
+ hash_array_from_cref(info, cref, info->accum_read_ahead_bytes, hash_store);
+ hash_accum_single(hash_store, hash_store_len, info->accum_steps);
+ hash_key key = hash_store[0];
+
+#ifdef USE_HASH_TABLE_KEY_CACHE
+ if (UNLIKELY(key == HASH_TABLE_KEY_UNSET)) {
+ key = HASH_TABLE_KEY_FALLBACK;
+ }
+#endif
+ return key;
+ }
+}
+
+static const BChunkRef *table_lookup(
+ const BArrayInfo *info, BTableRef **table, const size_t table_len, const size_t i_table_start,
+ const ubyte *data, const size_t data_len, const size_t offset, const hash_key *table_hash_array)
+{
+ size_t size_left = data_len - offset;
+ hash_key key = table_hash_array[((offset - i_table_start) / info->chunk_stride)];
+ size_t key_index = (size_t)(key % (hash_key)table_len);
+ for (BTableRef *tref = table[key_index]; tref; tref = tref->next) {
+ const BChunkRef *cref = tref->cref;
+#ifdef USE_HASH_TABLE_KEY_CACHE
+ if (cref->link->key == key)
+#endif
+ {
+ BChunk *chunk_test = cref->link;
+ if (chunk_test->data_len <= size_left) {
+ if (bchunk_data_compare(chunk_test, data, data_len, offset)) {
+ /* we could remove the chunk from the table, to avoid multiple hits */
+ return cref;
+ }
+ }
+ }
+ }
+ return NULL;
+}
+
+#else /* USE_HASH_TABLE_ACCUMULATE */
+
+/* NON USE_HASH_TABLE_ACCUMULATE code (simply hash each chunk) */
+
+static hash_key key_from_chunk_ref(const BArrayInfo *info, const BChunkRef *cref)
+{
+ const size_t data_hash_len = BCHUNK_HASH_LEN * info->chunk_stride;
+ hash_key key;
+ BChunk *chunk = cref->link;
+
+#ifdef USE_HASH_TABLE_KEY_CACHE
+ key = chunk->key;
+ if (key != HASH_TABLE_KEY_UNSET) {
+ /* Using key cache!
+ * avoids calculating every time */
+ }
+ else {
+ /* cache the key */
+ key = hash_data(chunk->data, data_hash_len);
+ if (key == HASH_TABLE_KEY_UNSET) {
+ key = HASH_TABLE_KEY_FALLBACK;
+ }
+ chunk->key = key;
+ }
+#else
+ key = hash_data(chunk->data, data_hash_len);
+#endif
+
+ return key;
+}
+
+static const BChunkRef *table_lookup(
+ const BArrayInfo *info, BTableRef **table, const size_t table_len, const uint UNUSED(i_table_start),
+ const ubyte *data, const size_t data_len, const size_t offset, const hash_key *UNUSED(table_hash_array))
+{
+ const size_t data_hash_len = BCHUNK_HASH_LEN * info->chunk_stride; /* TODO, cache */
+
+ size_t size_left = data_len - offset;
+ hash_key key = hash_data(&data[offset], MIN2(data_hash_len, size_left));
+ size_t key_index = (size_t)(key % (hash_key)table_len);
+ for (BTableRef *tref = table[key_index]; tref; tref = tref->next) {
+ const BChunkRef *cref = tref->cref;
+#ifdef USE_HASH_TABLE_KEY_CACHE
+ if (cref->link->key == key)
+#endif
+ {
+ BChunk *chunk_test = cref->link;
+ if (chunk_test->data_len <= size_left) {
+ if (bchunk_data_compare(chunk_test, data, data_len, offset)) {
+ /* we could remove the chunk from the table, to avoid multiple hits */
+ return cref;
+ }
+ }
+ }
+ }
+ return NULL;
+}
+
+#endif /* USE_HASH_TABLE_ACCUMULATE */
+
+/* End Table Lookup
+ * ---------------- */
+
+/** \} */
+
+/**
+ * \param data: Data to store in the returned value.
+ * \param data_len_original: Length of data in bytes.
+ * \param chunk_list_reference: Reuse this list or chunks within it, don't modify its content.
+ * \note Caller is responsible for adding the user.
+ */
+static BChunkList *bchunk_list_from_data_merge(
+ const BArrayInfo *info, BArrayMemory *bs_mem,
+ const ubyte *data, const size_t data_len_original,
+ const BChunkList *chunk_list_reference)
+{
+ ASSERT_CHUNKLIST_SIZE(chunk_list_reference, chunk_list_reference->total_size);
+
+ /* -----------------------------------------------------------------------
+ * Fast-Path for exact match
+ * Check for exact match, if so, return the current list.
+ */
+
+ const BChunkRef *cref_match_first = NULL;
+
+ uint chunk_list_reference_skip_len = 0;
+ size_t chunk_list_reference_skip_bytes = 0;
+ size_t i_prev = 0;
+
+#ifdef USE_FASTPATH_CHUNKS_FIRST
+ bool full_match = false;
+
+ {
+ full_match = true;
+
+ const BChunkRef *cref = chunk_list_reference->chunk_refs.first;
+ while (i_prev < data_len_original) {
+ if (cref != NULL && bchunk_data_compare(cref->link, data, data_len_original, i_prev)) {
+ cref_match_first = cref;
+ chunk_list_reference_skip_len += 1;
+ chunk_list_reference_skip_bytes += cref->link->data_len;
+ i_prev += cref->link->data_len;
+ cref = cref->next;
+ }
+ else {
+ full_match = false;
+ break;
+ }
+ }
+
+ if (full_match) {
+ if (chunk_list_reference->total_size == data_len_original) {
+ return (BChunkList *)chunk_list_reference;
+ }
+ }
+ }
+
+ /* End Fast-Path (first)
+ * --------------------- */
+
+#endif /* USE_FASTPATH_CHUNKS_FIRST */
+
+ /* Copy until we have a mismatch */
+ BChunkList *chunk_list = bchunk_list_new(bs_mem, data_len_original);
+ if (cref_match_first != NULL) {
+ size_t chunk_size_step = 0;
+ const BChunkRef *cref = chunk_list_reference->chunk_refs.first;
+ while (true) {
+ BChunk *chunk = cref->link;
+ chunk_size_step += chunk->data_len;
+ bchunk_list_append_only(bs_mem, chunk_list, chunk);
+ ASSERT_CHUNKLIST_SIZE(chunk_list, chunk_size_step);
+ ASSERT_CHUNKLIST_DATA(chunk_list, data);
+ if (cref == cref_match_first) {
+ break;
+ }
+ else {
+ cref = cref->next;
+ }
+ }
+ /* happens when bytes are removed from the end of the array */
+ if (chunk_size_step == data_len_original) {
+ return chunk_list;
+ }
+
+ i_prev = chunk_size_step;
+ }
+ else {
+ i_prev = 0;
+ }
+
+ /* ------------------------------------------------------------------------
+ * Fast-Path for end chunks
+ *
+ * Check for trailing chunks
+ */
+
+ /* In this case use 'chunk_list_reference_last' to define the last index
+ * index_match_last = -1 */
+
+ /* warning, from now on don't use len(data)
+ * since we want to ignore chunks already matched */
+ size_t data_len = data_len_original;
+#define data_len_original invalid_usage
+#ifdef data_len_original /* quiet warning */
+#endif
+
+ const BChunkRef *chunk_list_reference_last = NULL;
+
+#ifdef USE_FASTPATH_CHUNKS_LAST
+ if (!BLI_listbase_is_empty(&chunk_list_reference->chunk_refs)) {
+ const BChunkRef *cref = chunk_list_reference->chunk_refs.last;
+ while ((cref->prev != NULL) &&
+ (cref != cref_match_first) &&
+ (cref->link->data_len <= data_len - i_prev))
+ {
+ BChunk *chunk_test = cref->link;
+ size_t offset = data_len - chunk_test->data_len;
+ if (bchunk_data_compare(chunk_test, data, data_len, offset)) {
+ data_len = offset;
+ chunk_list_reference_last = cref;
+ chunk_list_reference_skip_len += 1;
+ chunk_list_reference_skip_bytes += cref->link->data_len;
+ cref = cref->prev;
+ }
+ else {
+ break;
+ }
+ }
+ }
+
+ /* End Fast-Path (last)
+ * -------------------- */
+#endif /* USE_FASTPATH_CHUNKS_LAST */
+
+ /* -----------------------------------------------------------------------
+ * Check for aligned chunks
+ *
+ * This saves a lot of searching, so use simple heuristics to detect aligned arrays.
+ * (may need to tweak exact method).
+ */
+
+ bool use_aligned = false;
+
+#ifdef USE_ALIGN_CHUNKS_TEST
+ if (chunk_list->total_size == chunk_list_reference->total_size) {
+ /* if we're already a quarter aligned */
+ if (data_len - i_prev <= chunk_list->total_size / 4) {
+ use_aligned = true;
+ }
+ else {
+ /* TODO, walk over chunks and check if some arbitrary amount align */
+ }
+ }
+#endif /* USE_ALIGN_CHUNKS_TEST */
+
+ /* End Aligned Chunk Case
+ * ----------------------- */
+
+ if (use_aligned) {
+ /* Copy matching chunks, creates using the same 'layout' as the reference */
+ const BChunkRef *cref = cref_match_first ? cref_match_first->next : chunk_list_reference->chunk_refs.first;
+ while (i_prev != data_len) {
+ const size_t i = i_prev + cref->link->data_len;
+ BLI_assert(i != i_prev);
+
+ if ((cref != chunk_list_reference_last) &&
+ bchunk_data_compare(cref->link, data, data_len, i_prev))
+ {
+ bchunk_list_append(info, bs_mem, chunk_list, cref->link);
+ ASSERT_CHUNKLIST_SIZE(chunk_list, i);
+ ASSERT_CHUNKLIST_DATA(chunk_list, data);
+ }
+ else {
+ bchunk_list_append_data(info, bs_mem, chunk_list, &data[i_prev], i - i_prev);
+ ASSERT_CHUNKLIST_SIZE(chunk_list, i);
+ ASSERT_CHUNKLIST_DATA(chunk_list, data);
+ }
+
+ cref = cref->next;
+
+ i_prev = i;
+ }
+ }
+ else if ((data_len - i_prev >= info->chunk_byte_size) &&
+ (chunk_list_reference->chunk_refs_len >= chunk_list_reference_skip_len) &&
+ (chunk_list_reference->chunk_refs.first != NULL))
+ {
+
+ /* --------------------------------------------------------------------
+ * Non-Aligned Chunk De-Duplication */
+
+ /* only create a table if we have at least one chunk to search
+ * otherwise just make a new one.
+ *
+ * Support re-arranged chunks */
+
+#ifdef USE_HASH_TABLE_ACCUMULATE
+ size_t i_table_start = i_prev;
+ const size_t table_hash_array_len = (data_len - i_prev) / info->chunk_stride;
+ hash_key *table_hash_array = MEM_mallocN(sizeof(*table_hash_array) * table_hash_array_len, __func__);
+ hash_array_from_data(info, &data[i_prev], data_len - i_prev, table_hash_array);
+
+ hash_accum(table_hash_array, table_hash_array_len, info->accum_steps);
+#else
+ /* dummy vars */
+ uint i_table_start = 0;
+ hash_key *table_hash_array = NULL;
+#endif
+
+ const uint chunk_list_reference_remaining_len =
+ (chunk_list_reference->chunk_refs_len - chunk_list_reference_skip_len) + 1;
+ BTableRef *table_ref_stack = MEM_mallocN(chunk_list_reference_remaining_len * sizeof(BTableRef), __func__);
+ uint table_ref_stack_n = 0;
+
+ const size_t table_len = chunk_list_reference_remaining_len * BCHUNK_HASH_TABLE_MUL;
+ BTableRef **table = MEM_callocN(table_len * sizeof(*table), __func__);
+
+ /* table_make - inline
+ * include one matching chunk, to allow for repeating values */
+ {
+#ifdef USE_HASH_TABLE_ACCUMULATE
+ const size_t hash_store_len = info->accum_read_ahead_len;
+ hash_key *hash_store = MEM_mallocN(sizeof(hash_key) * hash_store_len, __func__);
+#endif
+
+ const BChunkRef *cref;
+ size_t chunk_list_reference_bytes_remaining =
+ chunk_list_reference->total_size - chunk_list_reference_skip_bytes;
+
+ if (cref_match_first) {
+ cref = cref_match_first;
+ chunk_list_reference_bytes_remaining += cref->link->data_len;
+ }
+ else {
+ cref = chunk_list_reference->chunk_refs.first;
+ }
+
+#ifdef USE_PARANOID_CHECKS
+ {
+ size_t test_bytes_len = 0;
+ const BChunkRef *cr = cref;
+ while (cr != chunk_list_reference_last) {
+ test_bytes_len += cr->link->data_len;
+ cr = cr->next;
+ }
+ BLI_assert(test_bytes_len == chunk_list_reference_bytes_remaining);
+ }
+#endif
+
+ while ((cref != chunk_list_reference_last) &&
+ (chunk_list_reference_bytes_remaining >= info->accum_read_ahead_bytes))
+ {
+ hash_key key = key_from_chunk_ref(info, cref
+
+#ifdef USE_HASH_TABLE_ACCUMULATE
+ , hash_store, hash_store_len
+#endif
+ );
+ size_t key_index = (size_t)(key % (hash_key)table_len);
+ BTableRef *tref_prev = table[key_index];
+ BLI_assert(table_ref_stack_n < chunk_list_reference_remaining_len);
+ BTableRef *tref = &table_ref_stack[table_ref_stack_n++];
+ tref->cref = cref;
+ tref->next = tref_prev;
+ table[key_index] = tref;
+
+ chunk_list_reference_bytes_remaining -= cref->link->data_len;
+ cref = cref->next;
+ }
+
+ BLI_assert(table_ref_stack_n <= chunk_list_reference_remaining_len);
+
+#ifdef USE_HASH_TABLE_ACCUMULATE
+ MEM_freeN(hash_store);
+#endif
+ }
+ /* done making the table */
+
+ BLI_assert(i_prev <= data_len);
+ for (size_t i = i_prev; i < data_len; ) {
+ /* Assumes exiting chunk isnt a match! */
+
+ const BChunkRef *cref_found = table_lookup(
+ info,
+ table, table_len, i_table_start,
+ data, data_len, i, table_hash_array);
+ if (cref_found != NULL) {
+ BLI_assert(i < data_len);
+ if (i != i_prev) {
+ bchunk_list_append_data_n(info, bs_mem, chunk_list, &data[i_prev], i - i_prev);
+ i_prev = i;
+ }
+
+ /* now add the reference chunk */
+ {
+ BChunk *chunk_found = cref_found->link;
+ i += chunk_found->data_len;
+ bchunk_list_append(info, bs_mem, chunk_list, chunk_found);
+ }
+ i_prev = i;
+ BLI_assert(i_prev <= data_len);
+ ASSERT_CHUNKLIST_SIZE(chunk_list, i_prev);
+ ASSERT_CHUNKLIST_DATA(chunk_list, data);
+
+ /* its likely that the next chunk in the list will be a match, so check it! */
+ while ((cref_found->next != NULL) &&
+ (cref_found->next != chunk_list_reference_last))
+ {
+ cref_found = cref_found->next;
+ BChunk *chunk_found = cref_found->link;
+
+ if (bchunk_data_compare(chunk_found, data, data_len, i_prev)) {
+ /* may be useful to remove table data, assuming we dont have repeating memory
+ * where it would be useful to re-use chunks. */
+ i += chunk_found->data_len;
+ bchunk_list_append(info, bs_mem, chunk_list, chunk_found);
+ /* chunk_found may be freed! */
+ i_prev = i;
+ BLI_assert(i_prev <= data_len);
+ ASSERT_CHUNKLIST_SIZE(chunk_list, i_prev);
+ ASSERT_CHUNKLIST_DATA(chunk_list, data);
+ }
+ else {
+ break;
+ }
+ }
+ }
+ else {
+ i = i + info->chunk_stride;
+ }
+ }
+
+#ifdef USE_HASH_TABLE_ACCUMULATE
+ MEM_freeN(table_hash_array);
+#endif
+ MEM_freeN(table);
+ MEM_freeN(table_ref_stack);
+
+ /* End Table Lookup
+ * ---------------- */
+ }
+
+ ASSERT_CHUNKLIST_SIZE(chunk_list, i_prev);
+ ASSERT_CHUNKLIST_DATA(chunk_list, data);
+
+ /* -----------------------------------------------------------------------
+ * No Duplicates to copy, write new chunks
+ *
+ * Trailing chunks, no matches found in table lookup above.
+ * Write all new data. */
+ if (i_prev != data_len) {
+ bchunk_list_append_data_n(info, bs_mem, chunk_list, &data[i_prev], data_len - i_prev);
+ i_prev = data_len;
+ }
+
+ BLI_assert(i_prev == data_len);
+
+#ifdef USE_FASTPATH_CHUNKS_LAST
+ if (chunk_list_reference_last != NULL) {
+ /* write chunk_list_reference_last since it hasn't been written yet */
+ const BChunkRef *cref = chunk_list_reference_last;
+ while (cref != NULL) {
+ BChunk *chunk = cref->link;
+ // BLI_assert(bchunk_data_compare(chunk, data, data_len, i_prev));
+ i_prev += chunk->data_len;
+ /* use simple since we assume the references chunks have already been sized correctly. */
+ bchunk_list_append_only(bs_mem, chunk_list, chunk);
+ ASSERT_CHUNKLIST_DATA(chunk_list, data);
+ cref = cref->next;
+ }
+ }
+#endif
+
+#undef data_len_original
+
+ BLI_assert(i_prev == data_len_original);
+
+ /* check we're the correct size and that we didn't accidentally modify the reference */
+ ASSERT_CHUNKLIST_SIZE(chunk_list, data_len_original);
+ ASSERT_CHUNKLIST_SIZE(chunk_list_reference, chunk_list_reference->total_size);
+
+ ASSERT_CHUNKLIST_DATA(chunk_list, data);
+
+ return chunk_list;
+}
+/* end private API */
+
+/** \} */
+
+
+/** \name Main Array Storage API
+ * \{ */
+
+
+/**
+ * Create a new array store, which can store any number of arrays
+ * as long as their stride matches.
+ *
+ * \param stride: ``sizeof()`` each element,
+ *
+ * \note while a stride of ``1`` will always work,
+ * its less efficient since duplicate chunks of memory will be searched
+ * at positions unaligned with the array data.
+ *
+ * \param chunk_count: Number of elements to split each chunk into.
+ * - A small value increases the ability to de-duplicate chunks,
+ * but adds overhead by increasing the number of chunks to look-up when searching for duplicates,
+ * as well as some overhead constructing the original array again, with more calls to ``memcpy``.
+ * - Larger values reduce the *book keeping* overhead,
+ * but increase the chance a small, isolated change will cause a larger amount of data to be duplicated.
+ *
+ * \return A new array store, to be freed with #BLI_array_store_destroy.
+ */
+BArrayStore *BLI_array_store_create(
+ uint stride,
+ uint chunk_count)
+{
+ BArrayStore *bs = MEM_callocN(sizeof(BArrayStore), __func__);
+
+ bs->info.chunk_stride = stride;
+ bs->info.chunk_count = chunk_count;
+
+ bs->info.chunk_byte_size = chunk_count * stride;
+#ifdef USE_MERGE_CHUNKS
+ bs->info.chunk_byte_size_min = MAX2(1u, chunk_count / BCHUNK_SIZE_MIN_DIV) * stride;
+ bs->info.chunk_byte_size_max = (chunk_count * BCHUNK_SIZE_MAX_MUL) * stride;
+#endif
+
+#ifdef USE_HASH_TABLE_ACCUMULATE
+ bs->info.accum_steps = BCHUNK_HASH_TABLE_ACCUMULATE_STEPS - 1;
+ /* Triangle number, identifying now much read-ahead we need:
+ * https://en.wikipedia.org/wiki/Triangular_number (+ 1) */
+ bs->info.accum_read_ahead_len = (uint)((((bs->info.accum_steps * (bs->info.accum_steps + 1))) / 2) + 1);
+ bs->info.accum_read_ahead_bytes = bs->info.accum_read_ahead_len * stride;
+#else
+ bs->info.accum_read_ahead_bytes = BCHUNK_HASH_LEN * stride;
+#endif
+
+ bs->memory.chunk_list = BLI_mempool_create(sizeof(BChunkList), 0, 512, BLI_MEMPOOL_NOP);
+ bs->memory.chunk_ref = BLI_mempool_create(sizeof(BChunkRef), 0, 512, BLI_MEMPOOL_NOP);
+ /* allow iteration to simplify freeing, otherwise its not needed
+ * (we could loop over all states as an alternative). */
+ bs->memory.chunk = BLI_mempool_create(sizeof(BChunk), 0, 512, BLI_MEMPOOL_ALLOW_ITER);
+
+ return bs;
+}
+
+static void array_store_free_data(BArrayStore *bs)
+{
+ /* free chunk data */
+ {
+ BLI_mempool_iter iter;
+ BChunk *chunk;
+ BLI_mempool_iternew(bs->memory.chunk, &iter);
+ while ((chunk = BLI_mempool_iterstep(&iter))) {
+ BLI_assert(chunk->users > 0);
+ MEM_freeN((void *)chunk->data);
+ }
+ }
+
+ /* free states */
+ for (BArrayState *state = bs->states.first, *state_next; state; state = state_next) {
+ state_next = state->next;
+ MEM_freeN(state);
+ }
+}
+
+/**
+ * Free the #BArrayStore, including all states and chunks.
+ */
+void BLI_array_store_destroy(
+ BArrayStore *bs)
+{
+ array_store_free_data(bs);
+
+ BLI_mempool_destroy(bs->memory.chunk_list);
+ BLI_mempool_destroy(bs->memory.chunk_ref);
+ BLI_mempool_destroy(bs->memory.chunk);
+
+ MEM_freeN(bs);
+}
+
+/**
+ * Clear all contents, allowing reuse of \a bs.
+ */
+void BLI_array_store_clear(
+ BArrayStore *bs)
+{
+ array_store_free_data(bs);
+
+ BLI_listbase_clear(&bs->states);
+
+ BLI_mempool_clear(bs->memory.chunk_list);
+ BLI_mempool_clear(bs->memory.chunk_ref);
+ BLI_mempool_clear(bs->memory.chunk);
+}
+
+/** \name BArrayStore Statistics
+ * \{ */
+
+/**
+ * \return the total amount of memory that would be used by getting the arrays for all states.
+ */
+size_t BLI_array_store_calc_size_expanded_get(
+ const BArrayStore *bs)
+{
+ size_t size_accum = 0;
+ for (const BArrayState *state = bs->states.first; state; state = state->next) {
+ size_accum += state->chunk_list->total_size;
+ }
+ return size_accum;
+}
+
+/**
+ * \return the amount of memory used by all #BChunk.data
+ * (duplicate chunks are only counted once).
+ */
+size_t BLI_array_store_calc_size_compacted_get(
+ const BArrayStore *bs)
+{
+ size_t size_total = 0;
+ BLI_mempool_iter iter;
+ BChunk *chunk;
+ BLI_mempool_iternew(bs->memory.chunk, &iter);
+ while ((chunk = BLI_mempool_iterstep(&iter))) {
+ BLI_assert(chunk->users > 0);
+ size_total += (size_t)chunk->data_len;
+ }
+ return size_total;
+}
+
+/** \} */
+
+
+/** \name BArrayState Access
+ * \{ */
+
+/**
+ *
+ * \param data: Data used to create
+ * \param state_reference: The state to use as a reference when adding the new state,
+ * typically this is the previous state,
+ * however it can be any previously created state from this \a bs.
+ *
+ * \return The new state, which is used by the caller as a handle to get back the contents of \a data.
+ * This may be removed using #BLI_array_store_state_remove,
+ * otherwise it will be removed with #BLI_array_store_destroy.
+ */
+BArrayState *BLI_array_store_state_add(
+ BArrayStore *bs,
+ const void *data, const size_t data_len,
+ const BArrayState *state_reference)
+{
+ /* ensure we're aligned to the stride */
+ BLI_assert((data_len % bs->info.chunk_stride) == 0);
+
+#ifdef USE_PARANOID_CHECKS
+ if (state_reference) {
+ BLI_assert(BLI_findindex(&bs->states, state_reference) != -1);
+ }
+#endif
+
+ BChunkList *chunk_list;
+ if (state_reference) {
+ chunk_list = bchunk_list_from_data_merge(
+ &bs->info, &bs->memory,
+ (const ubyte *)data, data_len,
+ /* re-use reference chunks */
+ state_reference->chunk_list);
+ }
+ else {
+ chunk_list = bchunk_list_new(&bs->memory, data_len);
+ bchunk_list_fill_from_array(
+ &bs->info, &bs->memory,
+ chunk_list,
+ (const ubyte *)data, data_len);
+ }
+
+ chunk_list->users += 1;
+
+ BArrayState *state = MEM_callocN(sizeof(BArrayState), __func__);
+ state->chunk_list = chunk_list;
+
+ BLI_addtail(&bs->states, state);
+
+#ifdef USE_PARANOID_CHECKS
+ {
+ size_t data_test_len;
+ void *data_test = BLI_array_store_state_data_get_alloc(state, &data_test_len);
+ BLI_assert(data_test_len == data_len);
+ BLI_assert(memcmp(data_test, data, data_len) == 0);
+ MEM_freeN(data_test);
+ }
+#endif
+
+ return state;
+}
+
+/**
+ * Remove a state and free any unused #BChunk data.
+ *
+ * The states can be freed in any order.
+ */
+void BLI_array_store_state_remove(
+ BArrayStore *bs,
+ BArrayState *state)
+{
+#ifdef USE_PARANOID_CHECKS
+ BLI_assert(BLI_findindex(&bs->states, state) != -1);
+#endif
+
+ bchunk_list_decref(&bs->memory, state->chunk_list);
+ BLI_remlink(&bs->states, state);
+
+ MEM_freeN(state);
+}
+
+/**
+ * \return the expanded size of the array,
+ * use this to know how much memory to allocate #BLI_array_store_state_data_get's argument.
+ */
+size_t BLI_array_store_state_size_get(
+ BArrayState *state)
+{
+ return state->chunk_list->total_size;
+}
+
+/**
+ * Fill in existing allocated memory with the contents of \a state.
+ */
+void BLI_array_store_state_data_get(
+ BArrayState *state,
+ void *data)
+{
+#ifdef USE_PARANOID_CHECKS
+ size_t data_test_len = 0;
+ for (BChunkRef *cref = state->chunk_list->chunk_refs.first; cref; cref = cref->next) {
+ data_test_len += cref->link->data_len;
+ }
+ BLI_assert(data_test_len == state->chunk_list->total_size);
+#endif
+
+ ubyte *data_step = (ubyte *)data;
+ for (BChunkRef *cref = state->chunk_list->chunk_refs.first; cref; cref = cref->next) {
+ BLI_assert(cref->link->users > 0);
+ memcpy(data_step, cref->link->data, cref->link->data_len);
+ data_step += cref->link->data_len;
+ }
+}
+
+/**
+ * Allocate an array for \a state and return it.
+ */
+void *BLI_array_store_state_data_get_alloc(
+ BArrayState *state,
+ size_t *r_data_len)
+{
+ void *data = MEM_mallocN(state->chunk_list->total_size, __func__);
+ BLI_array_store_state_data_get(state, data);
+ *r_data_len = state->chunk_list->total_size;
+ return data;
+}
+
+/** \} */
+
+
+/** \name Debigging API (for testing).
+ * \{ */
+
+/* only for test validation */
+static size_t bchunk_list_size(const BChunkList *chunk_list)
+{
+ size_t total_size = 0;
+ for (BChunkRef *cref = chunk_list->chunk_refs.first; cref; cref = cref->next) {
+ total_size += cref->link->data_len;
+ }
+ return total_size;
+}
+
+bool BLI_array_store_is_valid(
+ BArrayStore *bs)
+{
+ bool ok = true;
+
+ /* Check Length
+ * ------------ */
+
+ for (BArrayState *state = bs->states.first; state; state = state->next) {
+ BChunkList *chunk_list = state->chunk_list;
+ if (!(bchunk_list_size(chunk_list) == chunk_list->total_size)) {
+ return false;
+ }
+
+ if (BLI_listbase_count(&chunk_list->chunk_refs) != (int)chunk_list->chunk_refs_len) {
+ return false;
+ }
+
+#ifdef USE_MERGE_CHUNKS
+ /* ensure we merge all chunks that could be merged */
+ if (chunk_list->total_size > bs->info.chunk_byte_size_min) {
+ for (BChunkRef *cref = chunk_list->chunk_refs.first; cref; cref = cref->next) {
+ if (cref->link->data_len < bs->info.chunk_byte_size_min) {
+ return false;
+ }
+ }
+ }
+#endif
+ }
+
+ {
+ BLI_mempool_iter iter;
+ BChunk *chunk;
+ BLI_mempool_iternew(bs->memory.chunk, &iter);
+ while ((chunk = BLI_mempool_iterstep(&iter))) {
+ if (!(MEM_allocN_len(chunk->data) >= chunk->data_len)) {
+ return false;
+ }
+ }
+ }
+
+ /* Check User Count & Lost References
+ * ---------------------------------- */
+ {
+ GHashIterator gh_iter;
+
+#define GHASH_PTR_ADD_USER(gh, pt) \
+ { \
+ void **val; \
+ if (BLI_ghash_ensure_p((gh), (pt), &val)) { \
+ *((int *)val) += 1; \
+ } \
+ else { \
+ *((int *)val) = 1; \
+ } \
+ } ((void)0)
+
+
+ /* count chunk_list's */
+ int totrefs = 0;
+ GHash *chunk_list_map = BLI_ghash_ptr_new(__func__);
+ for (BArrayState *state = bs->states.first; state; state = state->next) {
+ GHASH_PTR_ADD_USER(chunk_list_map, state->chunk_list);
+ }
+ GHASH_ITER (gh_iter, chunk_list_map) {
+ const struct BChunkList *chunk_list = BLI_ghashIterator_getKey(&gh_iter);
+ const int users = GET_INT_FROM_POINTER(BLI_ghashIterator_getValue(&gh_iter));
+ if (!(chunk_list->users == users)) {
+ ok = false;
+ goto user_finally;
+ }
+ }
+ if (!(BLI_mempool_count(bs->memory.chunk_list) == (int)BLI_ghash_size(chunk_list_map))) {
+ ok = false;
+ goto user_finally;
+ }
+
+ /* count chunk's */
+ GHash *chunk_map = BLI_ghash_ptr_new(__func__);
+ GHASH_ITER (gh_iter, chunk_list_map) {
+ const struct BChunkList *chunk_list = BLI_ghashIterator_getKey(&gh_iter);
+ for (const BChunkRef *cref = chunk_list->chunk_refs.first; cref; cref = cref->next) {
+ GHASH_PTR_ADD_USER(chunk_map, cref->link);
+ totrefs += 1;
+ }
+ }
+ if (!(BLI_mempool_count(bs->memory.chunk) == (int)BLI_ghash_size(chunk_map))) {
+ ok = false;
+ goto user_finally;
+ }
+ if (!(BLI_mempool_count(bs->memory.chunk_ref) == totrefs)) {
+ ok = false;
+ goto user_finally;
+ }
+
+ GHASH_ITER (gh_iter, chunk_map) {
+ const struct BChunk *chunk = BLI_ghashIterator_getKey(&gh_iter);
+ const int users = GET_INT_FROM_POINTER(BLI_ghashIterator_getValue(&gh_iter));
+ if (!(chunk->users == users)) {
+ ok = false;
+ goto user_finally;
+ }
+ }
+
+#undef GHASH_PTR_ADD_USER
+
+user_finally:
+ BLI_ghash_free(chunk_list_map, NULL, NULL);
+ BLI_ghash_free(chunk_map, NULL, NULL);
+ }
+
+
+ return ok;
+ /* TODO, dangling pointer checks */
+}
+
+/** \} */
diff --git a/source/blender/blenlib/intern/math_geom.c b/source/blender/blenlib/intern/math_geom.c
index f80099bee1b..370e8bb0035 100644
--- a/source/blender/blenlib/intern/math_geom.c
+++ b/source/blender/blenlib/intern/math_geom.c
@@ -4988,3 +4988,37 @@ int is_quad_flip_v3(const float v1[3], const float v2[3], const float v3[3], con
return ret;
}
+
+/**
+ * Return the value which the distance between points will need to be scaled by,
+ * to define a handle, given both points are on a perfect circle.
+ *
+ * Use when we want a bezier curve to match a circle as closely as possible.
+ *
+ * \note the return value will need to be divided by 0.75 for correct results.
+ */
+float cubic_tangent_factor_circle_v3(const float tan_l[3], const float tan_r[3])
+{
+ BLI_ASSERT_UNIT_V3(tan_l);
+ BLI_ASSERT_UNIT_V3(tan_r);
+
+ const float eps = 1e-7f;
+ const float tan_dot = dot_v3v3(tan_l, tan_r);
+ if (tan_dot > 1.0f - eps) {
+ /* no angle difference (use fallback, length wont make any difference) */
+ return (1.0f / 3.0f) * 0.75f;
+ }
+ else if (tan_dot < -1.0f + eps) {
+ /* parallele tangents (half-circle) */
+ return (1.0f / 2.0f);
+ }
+ else {
+ /* non-aligned tangents, calculate handle length */
+ const float angle = acosf(tan_dot) / 2.0f;
+
+ /* could also use 'angle_sin = len_vnvn(tan_l, tan_r, dims) / 2.0' */
+ const float angle_sin = sinf(angle);
+ const float angle_cos = cosf(angle);
+ return ((1.0f - angle_cos) / (angle_sin * 2.0f)) / angle_sin;
+ }
+}
diff --git a/source/blender/blenlib/intern/noise.c b/source/blender/blenlib/intern/noise.c
index c3a0c44d7c5..f834c5b4c74 100644
--- a/source/blender/blenlib/intern/noise.c
+++ b/source/blender/blenlib/intern/noise.c
@@ -1048,8 +1048,8 @@ static float noise3_perlin(float vec[3])
b01 = p[i + by1];
b11 = p[j + by1];
-#define VALUE_AT(rx, ry, rz) (rx * q[0] + ry * q[1] + rz * q[2])
-#define SURVE(t) (t * t * (3.0f - 2.0f * t))
+#define VALUE_AT(rx, ry, rz) ((rx) * q[0] + (ry) * q[1] + (rz) * q[2])
+#define SURVE(t) ((t) * (t) * (3.0f - 2.0f * (t)))
/* lerp moved to improved perlin above */
diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c
index 464fc0a2d49..621088c5a3c 100644
--- a/source/blender/blenloader/intern/readfile.c
+++ b/source/blender/blenloader/intern/readfile.c
@@ -124,6 +124,7 @@
#include "BKE_global.h" // for G
#include "BKE_group.h"
#include "BKE_library.h" // for which_libbase
+#include "BKE_library_idmap.h"
#include "BKE_library_query.h"
#include "BKE_idcode.h"
#include "BKE_material.h"
@@ -211,17 +212,21 @@
/* use GHash for BHead name-based lookups (speeds up linking) */
#define USE_GHASH_BHEAD
+/* Use GHash for restoring pointers by name */
+#define USE_GHASH_RESTORE_POINTER
+
/***/
typedef struct OldNew {
- void *old, *newp;
+ const void *old;
+ void *newp;
int nr;
} OldNew;
typedef struct OldNewMap {
OldNew *entries;
int nentries, entriessize;
- int sorted;
+ bool sorted;
int lasthit;
} OldNewMap;
@@ -287,12 +292,13 @@ static int verg_oldnewmap(const void *v1, const void *v2)
static void oldnewmap_sort(FileData *fd)
{
+ BLI_assert(fd->libmap->sorted == false);
qsort(fd->libmap->entries, fd->libmap->nentries, sizeof(OldNew), verg_oldnewmap);
fd->libmap->sorted = 1;
}
/* nr is zero for data, and ID code for libdata */
-static void oldnewmap_insert(OldNewMap *onm, void *oldaddr, void *newaddr, int nr)
+static void oldnewmap_insert(OldNewMap *onm, const void *oldaddr, void *newaddr, int nr)
{
OldNew *entry;
@@ -309,7 +315,7 @@ static void oldnewmap_insert(OldNewMap *onm, void *oldaddr, void *newaddr, int n
entry->nr = nr;
}
-void blo_do_versions_oldnewmap_insert(OldNewMap *onm, void *oldaddr, void *newaddr, int nr)
+void blo_do_versions_oldnewmap_insert(OldNewMap *onm, const void *oldaddr, void *newaddr, int nr)
{
oldnewmap_insert(onm, oldaddr, newaddr, nr);
}
@@ -364,7 +370,7 @@ static int oldnewmap_lookup_entry_full(const OldNewMap *onm, const void *addr, i
return -1;
}
-static void *oldnewmap_lookup_and_inc(OldNewMap *onm, void *addr, bool increase_users)
+static void *oldnewmap_lookup_and_inc(OldNewMap *onm, const void *addr, bool increase_users)
{
int i;
@@ -394,7 +400,7 @@ static void *oldnewmap_lookup_and_inc(OldNewMap *onm, void *addr, bool increase_
}
/* for libdata, nr has ID code, no increment */
-static void *oldnewmap_liblookup(OldNewMap *onm, void *addr, void *lib)
+static void *oldnewmap_liblookup(OldNewMap *onm, const void *addr, const void *lib)
{
if (addr == NULL) {
return NULL;
@@ -402,11 +408,8 @@ static void *oldnewmap_liblookup(OldNewMap *onm, void *addr, void *lib)
/* lasthit works fine for non-libdata, linking there is done in same sequence as writing */
if (onm->sorted) {
- OldNew entry_s, *entry;
-
- entry_s.old = addr;
-
- entry = bsearch(&entry_s, onm->entries, onm->nentries, sizeof(OldNew), verg_oldnewmap);
+ const OldNew entry_s = {.old = addr};
+ OldNew *entry = bsearch(&entry_s, onm->entries, onm->nentries, sizeof(OldNew), verg_oldnewmap);
if (entry) {
ID *id = entry->newp;
@@ -486,53 +489,57 @@ void blo_join_main(ListBase *mainlist)
}
}
-static void split_libdata(ListBase *lb, Main *first)
+static void split_libdata(ListBase *lb_src, Main **lib_main_array, const unsigned int lib_main_array_len)
{
- ListBase *lbn;
- ID *id, *idnext;
- Main *mainvar;
-
- id = lb->first;
- while (id) {
+ for (ID *id = lb_src->first, *idnext; id; id = idnext) {
idnext = id->next;
+
if (id->lib) {
- mainvar = first;
- while (mainvar) {
- if (mainvar->curlib == id->lib) {
- lbn= which_libbase(mainvar, GS(id->name));
- BLI_remlink(lb, id);
- BLI_addtail(lbn, id);
- break;
- }
- mainvar = mainvar->next;
+ if (((unsigned int)id->lib->temp_index < lib_main_array_len) &&
+ /* this check should never fail, just incase 'id->lib' is a dangling pointer. */
+ (lib_main_array[id->lib->temp_index]->curlib == id->lib))
+ {
+ Main *mainvar = lib_main_array[id->lib->temp_index];
+ ListBase *lb_dst = which_libbase(mainvar, GS(id->name));
+ BLI_remlink(lb_src, id);
+ BLI_addtail(lb_dst, id);
+ }
+ else {
+ printf("%s: invalid library for '%s'\n", __func__, id->name);
+ BLI_assert(0);
}
- if (mainvar == NULL) printf("error split_libdata\n");
}
- id = idnext;
}
}
void blo_split_main(ListBase *mainlist, Main *main)
{
- ListBase *lbarray[MAX_LIBARRAY];
- Library *lib;
- int i;
-
mainlist->first = mainlist->last = main;
main->next = NULL;
if (BLI_listbase_is_empty(&main->library))
return;
- for (lib = main->library.first; lib; lib = lib->id.next) {
+ /* (Library.temp_index -> Main), lookup table */
+ const unsigned int lib_main_array_len = BLI_listbase_count(&main->library);
+ Main **lib_main_array = MEM_mallocN(lib_main_array_len * sizeof(*lib_main_array), __func__);
+
+ int i = 0;
+ for (Library *lib = main->library.first; lib; lib = lib->id.next, i++) {
Main *libmain = BKE_main_new();
libmain->curlib = lib;
BLI_addtail(mainlist, libmain);
+ lib->temp_index = i;
+ lib_main_array[i] = libmain;
}
+ ListBase *lbarray[MAX_LIBARRAY];
i = set_listbasepointers(main, lbarray);
- while (i--)
- split_libdata(lbarray[i], main->next);
+ while (i--) {
+ split_libdata(lbarray[i], lib_main_array, lib_main_array_len);
+ }
+
+ MEM_freeN(lib_main_array);
}
static void read_file_version(FileData *fd, Main *main)
@@ -1413,7 +1420,7 @@ BlendThumbnail *BLO_thumbnail_from_file(const char *filepath)
/* ************** OLD POINTERS ******************* */
-static void *newdataadr(FileData *fd, void *adr) /* only direct databocks */
+static void *newdataadr(FileData *fd, const void *adr) /* only direct databocks */
{
return oldnewmap_lookup_and_inc(fd->datamap, adr, true);
}
@@ -1430,7 +1437,7 @@ static void *newdataadr(FileData *fd, void *adr) /* only direct databocks */
* fcurve group pointer and keeps lasthit optimal for linking all further
* fcurves.
*/
-static void *newdataadr_ex(FileData *fd, void *adr, bool increase_lasthit) /* only direct databocks */
+static void *newdataadr_ex(FileData *fd, const void *adr, bool increase_lasthit) /* only direct databocks */
{
if (increase_lasthit) {
return newdataadr(fd, adr);
@@ -1443,38 +1450,38 @@ static void *newdataadr_ex(FileData *fd, void *adr, bool increase_lasthit) /* o
}
}
-static void *newdataadr_no_us(FileData *fd, void *adr) /* only direct databocks */
+static void *newdataadr_no_us(FileData *fd, const void *adr) /* only direct databocks */
{
return oldnewmap_lookup_and_inc(fd->datamap, adr, false);
}
-static void *newglobadr(FileData *fd, void *adr) /* direct datablocks with global linking */
+static void *newglobadr(FileData *fd, const void *adr) /* direct datablocks with global linking */
{
return oldnewmap_lookup_and_inc(fd->globmap, adr, true);
}
-static void *newimaadr(FileData *fd, void *adr) /* used to restore image data after undo */
+static void *newimaadr(FileData *fd, const void *adr) /* used to restore image data after undo */
{
if (fd->imamap && adr)
return oldnewmap_lookup_and_inc(fd->imamap, adr, true);
return NULL;
}
-static void *newmclipadr(FileData *fd, void *adr) /* used to restore movie clip data after undo */
+static void *newmclipadr(FileData *fd, const void *adr) /* used to restore movie clip data after undo */
{
if (fd->movieclipmap && adr)
return oldnewmap_lookup_and_inc(fd->movieclipmap, adr, true);
return NULL;
}
-static void *newsoundadr(FileData *fd, void *adr) /* used to restore sound data after undo */
+static void *newsoundadr(FileData *fd, const void *adr) /* used to restore sound data after undo */
{
if (fd->soundmap && adr)
return oldnewmap_lookup_and_inc(fd->soundmap, adr, true);
return NULL;
}
-static void *newpackedadr(FileData *fd, void *adr) /* used to restore packed data after undo */
+static void *newpackedadr(FileData *fd, const void *adr) /* used to restore packed data after undo */
{
if (fd->packedmap && adr)
return oldnewmap_lookup_and_inc(fd->packedmap, adr, true);
@@ -1483,17 +1490,17 @@ static void *newpackedadr(FileData *fd, void *adr) /* used to restore packe
}
-static void *newlibadr(FileData *fd, void *lib, void *adr) /* only lib data */
+static void *newlibadr(FileData *fd, const void *lib, const void *adr) /* only lib data */
{
return oldnewmap_liblookup(fd->libmap, adr, lib);
}
-void *blo_do_versions_newlibadr(FileData *fd, void *lib, void *adr) /* only lib data */
+void *blo_do_versions_newlibadr(FileData *fd, const void *lib, const void *adr) /* only lib data */
{
return newlibadr(fd, lib, adr);
}
-static void *newlibadr_us(FileData *fd, void *lib, void *adr) /* increases user number */
+static void *newlibadr_us(FileData *fd, const void *lib, const void *adr) /* increases user number */
{
ID *id = newlibadr(fd, lib, adr);
@@ -1502,15 +1509,18 @@ static void *newlibadr_us(FileData *fd, void *lib, void *adr) /* increases user
return id;
}
-void *blo_do_versions_newlibadr_us(FileData *fd, void *lib, void *adr) /* increases user number */
+void *blo_do_versions_newlibadr_us(FileData *fd, const void *lib, const void *adr) /* increases user number */
{
return newlibadr_us(fd, lib, adr);
}
-static void change_idid_adr_fd(FileData *fd, void *old, void *new)
+static void change_idid_adr_fd(FileData *fd, const void *old, void *new)
{
int i;
+ /* use a binary search if we have a sorted libmap, for now it's not needed. */
+ BLI_assert(fd->libmap->sorted == false);
+
for (i = 0; i < fd->libmap->nentries; i++) {
OldNew *entry = &fd->libmap->entries[i];
@@ -6383,68 +6393,96 @@ typedef enum ePointerUserMode {
USER_REAL = 1, /* ensure at least one real user (fake user ignored) */
} ePointerUserMode;
-static bool restore_pointer(ID *id, ID *newid, ePointerUserMode user)
+static void restore_pointer_user(ID *id, ID *newid, ePointerUserMode user)
{
- if (STREQ(newid->name + 2, id->name + 2)) {
- if (newid->lib == id->lib) {
- if (user == USER_REAL) {
- id_us_ensure_real(newid);
+ BLI_assert(STREQ(newid->name + 2, id->name + 2));
+ BLI_assert(newid->lib == id->lib);
+ UNUSED_VARS_NDEBUG(id);
+
+ if (user == USER_REAL) {
+ id_us_ensure_real(newid);
+ }
+}
+
+#ifndef USE_GHASH_RESTORE_POINTER
+/**
+ * A version of #restore_pointer_by_name that performs a full search (slow!).
+ * Use only for limited lookups, when the overhead of
+ * creating a #IDNameLib_Map for a single lookup isn't worthwhile.
+ */
+static void *restore_pointer_by_name_main(Main *mainp, ID *id, ePointerUserMode user)
+{
+ if (id) {
+ ListBase *lb = which_libbase(mainp, GS(id->name));
+ if (lb) { /* there's still risk of checking corrupt mem (freed Ids in oops) */
+ ID *idn = lb->first;
+ for (; idn; idn = idn->next) {
+ if (STREQ(idn->name + 2, id->name + 2)) {
+ if (idn->lib == id->lib) {
+ restore_pointer_user(id, idn, user);
+ break;
+ }
+ }
}
- return true;
+ return idn;
}
}
- return false;
+ return NULL;
}
+#endif
/**
* Only for undo files, or to restore a screen after reading without UI...
*
- * user
+ * \param user:
* - USER_IGNORE: no usercount change
* - USER_REAL: ensure a real user (even if a fake one is set)
+ * \param id_map: lookup table, use when performing many lookups.
+ * this could be made an optional agument (falling back to a full lookup),
+ * however at the moment it's always available.
*/
-static void *restore_pointer_by_name(Main *mainp, ID *id, ePointerUserMode user)
+static void *restore_pointer_by_name(struct IDNameLib_Map *id_map, ID *id, ePointerUserMode user)
{
+#ifdef USE_GHASH_RESTORE_POINTER
if (id) {
- ListBase *lb = which_libbase(mainp, GS(id->name));
- if (lb) { // there's still risk of checking corrupt mem (freed Ids in oops)
- ID *idn = lb->first;
-
- for (; idn; idn = idn->next) {
- if (restore_pointer(id, idn, user))
- break;
- }
-
- return idn;
+ /* use fast lookup when available */
+ ID *idn = BKE_main_idmap_lookup_id(id_map, id);
+ if (idn) {
+ restore_pointer_user(id, idn, user);
}
+ return idn;
}
return NULL;
+#else
+ Main *mainp = BKE_main_idmap_main_get(id_map);
+ return restore_pointer_by_name_main(mainp, id, user);
+#endif
}
-static void lib_link_seq_clipboard_pt_restore(ID *id, Main *newmain)
+static void lib_link_seq_clipboard_pt_restore(ID *id, struct IDNameLib_Map *id_map)
{
if (id) {
/* clipboard must ensure this */
BLI_assert(id->newid != NULL);
- id->newid = restore_pointer_by_name(newmain, (ID *)id->newid, USER_REAL);
+ id->newid = restore_pointer_by_name(id_map, id->newid, USER_REAL);
}
}
static int lib_link_seq_clipboard_cb(Sequence *seq, void *arg_pt)
{
- Main *newmain = (Main *)arg_pt;
+ struct IDNameLib_Map *id_map = arg_pt;
- lib_link_seq_clipboard_pt_restore((ID *)seq->scene, newmain);
- lib_link_seq_clipboard_pt_restore((ID *)seq->scene_camera, newmain);
- lib_link_seq_clipboard_pt_restore((ID *)seq->clip, newmain);
- lib_link_seq_clipboard_pt_restore((ID *)seq->mask, newmain);
- lib_link_seq_clipboard_pt_restore((ID *)seq->sound, newmain);
+ lib_link_seq_clipboard_pt_restore((ID *)seq->scene, id_map);
+ lib_link_seq_clipboard_pt_restore((ID *)seq->scene_camera, id_map);
+ lib_link_seq_clipboard_pt_restore((ID *)seq->clip, id_map);
+ lib_link_seq_clipboard_pt_restore((ID *)seq->mask, id_map);
+ lib_link_seq_clipboard_pt_restore((ID *)seq->sound, id_map);
return 1;
}
-static void lib_link_clipboard_restore(Main *newmain)
+static void lib_link_clipboard_restore(struct IDNameLib_Map *id_map)
{
/* update IDs stored in sequencer clipboard */
- BKE_sequencer_base_recursive_apply(&seqbase_clipboard, lib_link_seq_clipboard_cb, newmain);
+ BKE_sequencer_base_recursive_apply(&seqbase_clipboard, lib_link_seq_clipboard_cb, id_map);
}
/* called from kernel/blender.c */
@@ -6456,11 +6494,13 @@ void blo_lib_link_screen_restore(Main *newmain, bScreen *curscreen, Scene *cursc
wmWindowManager *wm;
bScreen *sc;
ScrArea *sa;
-
+
+ struct IDNameLib_Map *id_map = BKE_main_idmap_create(newmain);
+
/* first windowmanager */
for (wm = newmain->wm.first; wm; wm = wm->id.next) {
for (win= wm->windows.first; win; win= win->next) {
- win->screen = restore_pointer_by_name(newmain, (ID *)win->screen, USER_REAL);
+ win->screen = restore_pointer_by_name(id_map, (ID *)win->screen, USER_REAL);
if (win->screen == NULL)
win->screen = curscreen;
@@ -6473,7 +6513,7 @@ void blo_lib_link_screen_restore(Main *newmain, bScreen *curscreen, Scene *cursc
for (sc = newmain->screen.first; sc; sc = sc->id.next) {
Scene *oldscene = sc->scene;
- sc->scene= restore_pointer_by_name(newmain, (ID *)sc->scene, USER_REAL);
+ sc->scene= restore_pointer_by_name(id_map, (ID *)sc->scene, USER_REAL);
if (sc->scene == NULL)
sc->scene = curscene;
@@ -6492,16 +6532,16 @@ void blo_lib_link_screen_restore(Main *newmain, bScreen *curscreen, Scene *cursc
if (v3d->scenelock)
v3d->camera = NULL; /* always get from scene */
else
- v3d->camera = restore_pointer_by_name(newmain, (ID *)v3d->camera, USER_REAL);
+ v3d->camera = restore_pointer_by_name(id_map, (ID *)v3d->camera, USER_REAL);
if (v3d->camera == NULL)
v3d->camera = sc->scene->camera;
- v3d->ob_centre = restore_pointer_by_name(newmain, (ID *)v3d->ob_centre, USER_REAL);
+ v3d->ob_centre = restore_pointer_by_name(id_map, (ID *)v3d->ob_centre, USER_REAL);
for (bgpic= v3d->bgpicbase.first; bgpic; bgpic= bgpic->next) {
- if ((bgpic->ima = restore_pointer_by_name(newmain, (ID *)bgpic->ima, USER_IGNORE))) {
+ if ((bgpic->ima = restore_pointer_by_name(id_map, (ID *)bgpic->ima, USER_IGNORE))) {
id_us_plus((ID *)bgpic->ima);
}
- if ((bgpic->clip = restore_pointer_by_name(newmain, (ID *)bgpic->clip, USER_IGNORE))) {
+ if ((bgpic->clip = restore_pointer_by_name(id_map, (ID *)bgpic->clip, USER_IGNORE))) {
id_us_plus((ID *)bgpic->clip);
}
}
@@ -6545,10 +6585,10 @@ void blo_lib_link_screen_restore(Main *newmain, bScreen *curscreen, Scene *cursc
bDopeSheet *ads = sipo->ads;
if (ads) {
- ads->source = restore_pointer_by_name(newmain, (ID *)ads->source, USER_REAL);
+ ads->source = restore_pointer_by_name(id_map, (ID *)ads->source, USER_REAL);
if (ads->filter_grp)
- ads->filter_grp = restore_pointer_by_name(newmain, (ID *)ads->filter_grp, USER_IGNORE);
+ ads->filter_grp = restore_pointer_by_name(id_map, (ID *)ads->filter_grp, USER_IGNORE);
}
/* force recalc of list of channels (i.e. includes calculating F-Curve colors)
@@ -6558,7 +6598,7 @@ void blo_lib_link_screen_restore(Main *newmain, bScreen *curscreen, Scene *cursc
}
else if (sl->spacetype == SPACE_BUTS) {
SpaceButs *sbuts = (SpaceButs *)sl;
- sbuts->pinid = restore_pointer_by_name(newmain, sbuts->pinid, USER_IGNORE);
+ sbuts->pinid = restore_pointer_by_name(id_map, sbuts->pinid, USER_IGNORE);
if (sbuts->pinid == NULL) {
sbuts->flag &= ~SB_PIN_CONTEXT;
}
@@ -6575,11 +6615,11 @@ void blo_lib_link_screen_restore(Main *newmain, bScreen *curscreen, Scene *cursc
else if (sl->spacetype == SPACE_ACTION) {
SpaceAction *saction = (SpaceAction *)sl;
- saction->action = restore_pointer_by_name(newmain, (ID *)saction->action, USER_REAL);
- saction->ads.source = restore_pointer_by_name(newmain, (ID *)saction->ads.source, USER_REAL);
+ saction->action = restore_pointer_by_name(id_map, (ID *)saction->action, USER_REAL);
+ saction->ads.source = restore_pointer_by_name(id_map, (ID *)saction->ads.source, USER_REAL);
if (saction->ads.filter_grp)
- saction->ads.filter_grp = restore_pointer_by_name(newmain, (ID *)saction->ads.filter_grp, USER_IGNORE);
+ saction->ads.filter_grp = restore_pointer_by_name(id_map, (ID *)saction->ads.filter_grp, USER_IGNORE);
/* force recalc of list of channels, potentially updating the active action
@@ -6590,7 +6630,7 @@ void blo_lib_link_screen_restore(Main *newmain, bScreen *curscreen, Scene *cursc
else if (sl->spacetype == SPACE_IMAGE) {
SpaceImage *sima = (SpaceImage *)sl;
- sima->image = restore_pointer_by_name(newmain, (ID *)sima->image, USER_REAL);
+ sima->image = restore_pointer_by_name(id_map, (ID *)sima->image, USER_REAL);
/* this will be freed, not worth attempting to find same scene,
* since it gets initialized later */
@@ -6605,8 +6645,8 @@ void blo_lib_link_screen_restore(Main *newmain, bScreen *curscreen, Scene *cursc
/* NOTE: pre-2.5, this was local data not lib data, but now we need this as lib data
* so assume that here we're doing for undo only...
*/
- sima->gpd = restore_pointer_by_name(newmain, (ID *)sima->gpd, USER_REAL);
- sima->mask_info.mask = restore_pointer_by_name(newmain, (ID *)sima->mask_info.mask, USER_REAL);
+ sima->gpd = restore_pointer_by_name(id_map, (ID *)sima->gpd, USER_REAL);
+ sima->mask_info.mask = restore_pointer_by_name(id_map, (ID *)sima->mask_info.mask, USER_REAL);
}
else if (sl->spacetype == SPACE_SEQ) {
SpaceSeq *sseq = (SpaceSeq *)sl;
@@ -6614,29 +6654,29 @@ void blo_lib_link_screen_restore(Main *newmain, bScreen *curscreen, Scene *cursc
/* NOTE: pre-2.5, this was local data not lib data, but now we need this as lib data
* so assume that here we're doing for undo only...
*/
- sseq->gpd = restore_pointer_by_name(newmain, (ID *)sseq->gpd, USER_REAL);
+ sseq->gpd = restore_pointer_by_name(id_map, (ID *)sseq->gpd, USER_REAL);
}
else if (sl->spacetype == SPACE_NLA) {
SpaceNla *snla = (SpaceNla *)sl;
bDopeSheet *ads = snla->ads;
if (ads) {
- ads->source = restore_pointer_by_name(newmain, (ID *)ads->source, USER_REAL);
+ ads->source = restore_pointer_by_name(id_map, (ID *)ads->source, USER_REAL);
if (ads->filter_grp)
- ads->filter_grp = restore_pointer_by_name(newmain, (ID *)ads->filter_grp, USER_IGNORE);
+ ads->filter_grp = restore_pointer_by_name(id_map, (ID *)ads->filter_grp, USER_IGNORE);
}
}
else if (sl->spacetype == SPACE_TEXT) {
SpaceText *st = (SpaceText *)sl;
- st->text = restore_pointer_by_name(newmain, (ID *)st->text, USER_REAL);
+ st->text = restore_pointer_by_name(id_map, (ID *)st->text, USER_REAL);
if (st->text == NULL) st->text = newmain->text.first;
}
else if (sl->spacetype == SPACE_SCRIPT) {
SpaceScript *scpt = (SpaceScript *)sl;
- scpt->script = restore_pointer_by_name(newmain, (ID *)scpt->script, USER_REAL);
+ scpt->script = restore_pointer_by_name(id_map, (ID *)scpt->script, USER_REAL);
/*sc->script = NULL; - 2.45 set to null, better re-run the script */
if (scpt->script) {
@@ -6646,7 +6686,7 @@ void blo_lib_link_screen_restore(Main *newmain, bScreen *curscreen, Scene *cursc
else if (sl->spacetype == SPACE_OUTLINER) {
SpaceOops *so= (SpaceOops *)sl;
- so->search_tse.id = restore_pointer_by_name(newmain, so->search_tse.id, USER_IGNORE);
+ so->search_tse.id = restore_pointer_by_name(id_map, so->search_tse.id, USER_IGNORE);
if (so->treestore) {
TreeStoreElem *tselem;
@@ -6656,7 +6696,7 @@ void blo_lib_link_screen_restore(Main *newmain, bScreen *curscreen, Scene *cursc
while ((tselem = BLI_mempool_iterstep(&iter))) {
/* Do not try to restore pointers to drivers/sequence/etc., can crash in undo case! */
if (TSE_IS_REAL_ID(tselem)) {
- tselem->id = restore_pointer_by_name(newmain, tselem->id, USER_IGNORE);
+ tselem->id = restore_pointer_by_name(id_map, tselem->id, USER_IGNORE);
}
else {
tselem->id = NULL;
@@ -6674,14 +6714,14 @@ void blo_lib_link_screen_restore(Main *newmain, bScreen *curscreen, Scene *cursc
bNodeTree *ntree;
/* node tree can be stored locally in id too, link this first */
- snode->id = restore_pointer_by_name(newmain, snode->id, USER_REAL);
- snode->from = restore_pointer_by_name(newmain, snode->from, USER_IGNORE);
+ snode->id = restore_pointer_by_name(id_map, snode->id, USER_REAL);
+ snode->from = restore_pointer_by_name(id_map, snode->from, USER_IGNORE);
ntree = nodetree_from_id(snode->id);
if (ntree)
snode->nodetree = ntree;
else
- snode->nodetree = restore_pointer_by_name(newmain, (ID*)snode->nodetree, USER_REAL);
+ snode->nodetree = restore_pointer_by_name(id_map, (ID*)snode->nodetree, USER_REAL);
for (path = snode->treepath.first; path; path = path->next) {
if (path == snode->treepath.first) {
@@ -6689,7 +6729,7 @@ void blo_lib_link_screen_restore(Main *newmain, bScreen *curscreen, Scene *cursc
path->nodetree = snode->nodetree;
}
else
- path->nodetree= restore_pointer_by_name(newmain, (ID*)path->nodetree, USER_REAL);
+ path->nodetree= restore_pointer_by_name(id_map, (ID*)path->nodetree, USER_REAL);
if (!path->nodetree)
break;
@@ -6715,22 +6755,24 @@ void blo_lib_link_screen_restore(Main *newmain, bScreen *curscreen, Scene *cursc
else if (sl->spacetype == SPACE_CLIP) {
SpaceClip *sclip = (SpaceClip *)sl;
- sclip->clip = restore_pointer_by_name(newmain, (ID *)sclip->clip, USER_REAL);
- sclip->mask_info.mask = restore_pointer_by_name(newmain, (ID *)sclip->mask_info.mask, USER_REAL);
+ sclip->clip = restore_pointer_by_name(id_map, (ID *)sclip->clip, USER_REAL);
+ sclip->mask_info.mask = restore_pointer_by_name(id_map, (ID *)sclip->mask_info.mask, USER_REAL);
sclip->scopes.ok = 0;
}
else if (sl->spacetype == SPACE_LOGIC) {
SpaceLogic *slogic = (SpaceLogic *)sl;
- slogic->gpd = restore_pointer_by_name(newmain, (ID *)slogic->gpd, USER_REAL);
+ slogic->gpd = restore_pointer_by_name(id_map, (ID *)slogic->gpd, USER_REAL);
}
}
}
}
/* update IDs stored in all possible clipboards */
- lib_link_clipboard_restore(newmain);
+ lib_link_clipboard_restore(id_map);
+
+ BKE_main_idmap_destroy(id_map);
}
static void direct_link_region(FileData *fd, ARegion *ar, int spacetype)
@@ -7880,7 +7922,7 @@ static BHead *read_data_into_oldnewmap(FileData *fd, BHead *bhead, const char *a
return bhead;
}
-static BHead *read_libblock(FileData *fd, Main *main, BHead *bhead, int flag, ID **r_id)
+static BHead *read_libblock(FileData *fd, Main *main, BHead *bhead, const short tag, ID **r_id)
{
/* this routine reads a libblock and its direct data. Use link functions to connect it all
*/
@@ -7892,8 +7934,8 @@ static BHead *read_libblock(FileData *fd, Main *main, BHead *bhead, int flag, ID
/* In undo case, most libs and linked data should be kept as is from previous state (see BLO_read_from_memfile).
* However, some needed by the snapshot being read may have been removed in previous one, and would go missing.
* This leads e.g. to desappearing objects in some undo/redo case, see T34446.
- * That means we have to carefully check whether current lib or libdata already exits in old main, if it does
- * we merely copy it over into new main area, otherwise we have to do a full read of that bhead... */
+ * That means we have to carefully check whether current lib or libdata already exits in old main, if it does
+ * we merely copy it over into new main area, otherwise we have to do a full read of that bhead... */
if (fd->memfile && ELEM(bhead->code, ID_LI, ID_ID)) {
const char *idname = bhead_id_name(fd, bhead);
@@ -7966,7 +8008,7 @@ static BHead *read_libblock(FileData *fd, Main *main, BHead *bhead, int flag, ID
if (!id)
return blo_nextbhead(fd, bhead);
- id->tag = flag | LIB_TAG_NEED_LINK;
+ id->tag = tag | LIB_TAG_NEED_LINK;
id->lib = main->curlib;
id->us = ID_FAKE_USERS(id);
id->icon_id = 0;
@@ -9644,7 +9686,7 @@ static void give_base_to_groups(
}
}
-static ID *create_placeholder(Main *mainvar, const char *idname, const short flag)
+static ID *create_placeholder(Main *mainvar, const char *idname, const short tag)
{
const short idcode = GS(idname);
ListBase *lb = which_libbase(mainvar, idcode);
@@ -9653,7 +9695,7 @@ static ID *create_placeholder(Main *mainvar, const char *idname, const short fla
memcpy(ph_id->name, idname, sizeof(ph_id->name));
BKE_libblock_init_empty(ph_id);
ph_id->lib = mainvar->curlib;
- ph_id->tag = flag | LIB_TAG_MISSING;
+ ph_id->tag = tag | LIB_TAG_MISSING;
ph_id->us = ID_FAKE_USERS(ph_id);
ph_id->icon_id = 0;
@@ -9992,21 +10034,22 @@ void *BLO_library_read_struct(FileData *fd, BHead *bh, const char *blockname)
/* ************* READ LIBRARY ************** */
-static int mainvar_count_libread_blocks(Main *mainvar)
+static int mainvar_id_tag_any_check(Main *mainvar, const short tag)
{
ListBase *lbarray[MAX_LIBARRAY];
- int a, tot = 0;
+ int a;
a = set_listbasepointers(mainvar, lbarray);
while (a--) {
ID *id;
for (id = lbarray[a]->first; id; id = id->next) {
- if (id->tag & LIB_TAG_READ)
- tot++;
+ if (id->tag & tag) {
+ return true;
+ }
}
}
- return tot;
+ return false;
}
static void read_libraries(FileData *basefd, ListBase *mainlist)
@@ -10026,10 +10069,9 @@ static void read_libraries(FileData *basefd, ListBase *mainlist)
/* test 1: read libdata */
mainptr= mainl->next;
while (mainptr) {
- int tot = mainvar_count_libread_blocks(mainptr);
-
- // printf("found LIB_TAG_READ %s\n", mainptr->curlib->name);
- if (tot) {
+ if (mainvar_id_tag_any_check(mainptr, LIB_TAG_READ)) {
+ // printf("found LIB_TAG_READ %s\n", mainptr->curlib->name);
+
FileData *fd = mainptr->curlib->filedata;
if (fd == NULL) {
diff --git a/source/blender/blenloader/intern/readfile.h b/source/blender/blenloader/intern/readfile.h
index f5c19f5ee22..42728fd406f 100644
--- a/source/blender/blenloader/intern/readfile.h
+++ b/source/blender/blenloader/intern/readfile.h
@@ -156,9 +156,9 @@ const char *bhead_id_name(const FileData *fd, const BHead *bhead);
void blo_reportf_wrap(struct ReportList *reports, ReportType type, const char *format, ...) ATTR_PRINTF_FORMAT(3, 4);
-void blo_do_versions_oldnewmap_insert(struct OldNewMap *onm, void *oldaddr, void *newaddr, int nr);
-void *blo_do_versions_newlibadr(struct FileData *fd, void *lib, void *adr);
-void *blo_do_versions_newlibadr_us(struct FileData *fd, void *lib, void *adr);
+void blo_do_versions_oldnewmap_insert(struct OldNewMap *onm, const void *oldaddr, void *newaddr, int nr);
+void *blo_do_versions_newlibadr(struct FileData *fd, const void *lib, const void *adr);
+void *blo_do_versions_newlibadr_us(struct FileData *fd, const void *lib, const void *adr);
struct PartEff *blo_do_version_give_parteff_245(struct Object *ob);
void blo_do_version_old_trackto_to_constraints(struct Object *ob);
diff --git a/source/blender/blenloader/intern/versioning_270.c b/source/blender/blenloader/intern/versioning_270.c
index 0ea4078a5cb..b7b6ace3c1a 100644
--- a/source/blender/blenloader/intern/versioning_270.c
+++ b/source/blender/blenloader/intern/versioning_270.c
@@ -1189,9 +1189,7 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main)
}
}
}
- }
- {
for (Camera *camera = main->camera.first; camera != NULL; camera = camera->id.next) {
if (camera->stereo.pole_merge_angle_from == 0.0f &&
camera->stereo.pole_merge_angle_to == 0.0f)
@@ -1200,5 +1198,19 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main)
camera->stereo.pole_merge_angle_to = DEG2RAD(75.0f);
}
}
+
+ if (!DNA_struct_elem_find(fd->filesdna, "NormalEditModifierData", "float", "mix_limit")) {
+ Object *ob;
+
+ for (ob = main->object.first; ob; ob = ob->id.next) {
+ ModifierData *md;
+ for (md = ob->modifiers.first; md; md = md->next) {
+ if (md->type == eModifierType_NormalEdit) {
+ NormalEditModifierData *nemd = (NormalEditModifierData *)md;
+ nemd->mix_limit = DEG2RADF(180.0f);
+ }
+ }
+ }
+ }
}
}
diff --git a/source/blender/bmesh/intern/bmesh_mesh_conv.c b/source/blender/bmesh/intern/bmesh_mesh_conv.c
index 7b102c9283b..bb61f66e267 100644
--- a/source/blender/bmesh/intern/bmesh_mesh_conv.c
+++ b/source/blender/bmesh/intern/bmesh_mesh_conv.c
@@ -804,10 +804,10 @@ void BM_mesh_bm_to_me(
BMEditSelection *selected;
me->totselect = BLI_listbase_count(&(bm->selected));
- if (me->mselect) MEM_freeN(me->mselect);
-
- me->mselect = MEM_callocN(sizeof(MSelect) * me->totselect, "Mesh selection history");
-
+ MEM_SAFE_FREE(me->mselect);
+ if (me->totselect != 0) {
+ me->mselect = MEM_mallocN(sizeof(MSelect) * me->totselect, "Mesh selection history");
+ }
for (i = 0, selected = bm->selected.first; selected; i++, selected = selected->next) {
if (selected->htype == BM_VERT) {
diff --git a/source/blender/bmesh/tools/bmesh_bevel.c b/source/blender/bmesh/tools/bmesh_bevel.c
index 5a7788c0b62..0ed1dffcafb 100644
--- a/source/blender/bmesh/tools/bmesh_bevel.c
+++ b/source/blender/bmesh/tools/bmesh_bevel.c
@@ -198,6 +198,12 @@ typedef struct BevelParams {
// #include "bevdebug.c"
+/* some flags to re-enable old behavior for a while, in case fixes broke things not caught by regression tests */
+static int bev_debug_flags = 0;
+#define DEBUG_OLD_PLANE_SPECIAL (bev_debug_flags & 1)
+#define DEBUG_OLD_PROJ_TO_PERP_PLANE (bev_debug_flags & 2)
+#define DEBUG_OLD_FLAT_MID (bev_debug_flags & 4)
+
/* Make a new BoundVert of the given kind, insert it at the end of the circular linked
* list with entry point bv->boundstart, and return it. */
static BoundVert *add_new_bound_vert(MemArena *mem_arena, VMesh *vm, const float co[3])
@@ -345,6 +351,36 @@ static EdgeHalf *next_bev(BevVert *bv, EdgeHalf *from_e)
return NULL;
}
+/* return count of edges between e1 and e2 when going around bv CCW */
+static int count_ccw_edges_between(EdgeHalf *e1, EdgeHalf *e2)
+{
+ int cnt = 0;
+ EdgeHalf *e = e1;
+
+ do {
+ if (e == e2)
+ break;
+ e = e->next;
+ cnt++;
+ } while (e != e1);
+ return cnt;
+}
+
+/* Assume bme1 and bme2 both share some vert. Do they share a face?
+ * If they share a face then there is some loop around bme1 that is in a face
+ * where the next or previous edge in the face must be bme2. */
+static bool edges_face_connected_at_vert(BMEdge *bme1, BMEdge *bme2)
+{
+ BMLoop *l;
+ BMIter iter;
+
+ BM_ITER_ELEM(l, &iter, bme1, BM_LOOPS_OF_EDGE) {
+ if (l->prev->e == bme2 || l->next->e == bme2)
+ return true;
+ }
+ return false;
+}
+
/* Return a good representative face (for materials, etc.) for faces
* created around/near BoundVert v.
* Sometimes care about a second choice, if there is one.
@@ -1015,15 +1051,21 @@ static void set_profile_params(BevelParams *bp, BevVert *bv, BoundVert *bndv)
sub_v3_v3v3(pro->proj_dir, e->e->v1->co, e->e->v2->co);
normalize_v3(pro->proj_dir);
project_to_edge(e->e, co1, co2, pro->midco);
- /* put arc endpoints on plane with normal proj_dir, containing midco */
- add_v3_v3v3(co3, co1, pro->proj_dir);
- if (!isect_line_plane_v3(pro->coa, co1, co3, pro->midco, pro->proj_dir)) {
- /* shouldn't happen */
- copy_v3_v3(pro->coa, co1);
+ if (DEBUG_OLD_PROJ_TO_PERP_PLANE) {
+ /* put arc endpoints on plane with normal proj_dir, containing midco */
+ add_v3_v3v3(co3, co1, pro->proj_dir);
+ if (!isect_line_plane_v3(pro->coa, co1, co3, pro->midco, pro->proj_dir)) {
+ /* shouldn't happen */
+ copy_v3_v3(pro->coa, co1);
+ }
+ add_v3_v3v3(co3, co2, pro->proj_dir);
+ if (!isect_line_plane_v3(pro->cob, co2, co3, pro->midco, pro->proj_dir)) {
+ /* shouldn't happen */
+ copy_v3_v3(pro->cob, co2);
+ }
}
- add_v3_v3v3(co3, co2, pro->proj_dir);
- if (!isect_line_plane_v3(pro->cob, co2, co3, pro->midco, pro->proj_dir)) {
- /* shouldn't happen */
+ else {
+ copy_v3_v3(pro->coa, co1);
copy_v3_v3(pro->cob, co2);
}
/* default plane to project onto is the one with triangle co1 - midco - co2 in it */
@@ -1036,19 +1078,48 @@ static void set_profile_params(BevelParams *bp, BevVert *bv, BoundVert *bndv)
if (l <= BEVEL_EPSILON_BIG) {
/* co1 - midco -co2 are collinear.
* Should be case that beveled edge is coplanar with two boundary verts.
+ * We want to move the profile to that common plane, if possible.
+ * That makes the multi-segment bevels curve nicely in that plane, as users expect.
+ * The new midco should be either v (when neighbor edges are unbeveled)
+ * or the intersection of the offset lines (if they are).
* If the profile is going to lead into unbeveled edges on each side
* (that is, both BoundVerts are "on-edge" points on non-beveled edges)
- * then in order to get curve in multi-segment case, change projection plane
- * to be that common plane, projection dir to be the plane normal,
- * and mid to be the original vertex.
- * Otherwise, we just want to linearly interpolate between co1 and co2.
*/
- if (e->prev->is_bev || e->next->is_bev) {
+ if (DEBUG_OLD_PLANE_SPECIAL && (e->prev->is_bev || e->next->is_bev)) {
do_linear_interp = true;
}
else {
- copy_v3_v3(pro->coa, co1);
- copy_v3_v3(pro->midco, bv->v->co);
+ if (DEBUG_OLD_PROJ_TO_PERP_PLANE) {
+ copy_v3_v3(pro->coa, co1);
+ copy_v3_v3(pro->cob, co2);
+ }
+ if (DEBUG_OLD_FLAT_MID) {
+ copy_v3_v3(pro->midco, bv->v->co);
+ }
+ else {
+ copy_v3_v3(pro->midco, bv->v->co);
+ if (e->prev->is_bev && e->next->is_bev && bv->selcount >= 3) {
+ /* want mid at the meet point of next and prev offset edges */
+ float d3[3], d4[3], co4[3], meetco[3], isect2[3];
+ int isect_kind;
+
+ sub_v3_v3v3(d3, e->prev->e->v1->co, e->prev->e->v2->co);
+ sub_v3_v3v3(d4, e->next->e->v1->co, e->next->e->v2->co);
+ normalize_v3(d3);
+ normalize_v3(d4);
+ add_v3_v3v3(co3, co1, d3);
+ add_v3_v3v3(co4, co2, d4);
+ isect_kind = isect_line_line_v3(co1, co3, co2, co4, meetco, isect2);
+ if (isect_kind != 0) {
+ copy_v3_v3(pro->midco, meetco);
+ }
+ else {
+ /* offset lines are collinear - want linear interpolation */
+ mid_v3_v3v3(pro->midco, co1, co2);
+ do_linear_interp = true;
+ }
+ }
+ }
copy_v3_v3(pro->cob, co2);
sub_v3_v3v3(d1, pro->midco, co1);
normalize_v3(d1);
@@ -1557,7 +1628,7 @@ static void build_boundary_vertex_only(BevelParams *bp, BevVert *bv, bool constr
if (construct) {
v = add_new_bound_vert(bp->mem_arena, vm, co);
v->efirst = v->elast = e;
- e->leftv = v;
+ e->leftv = e->rightv = v;
}
else {
adjust_bound_vert(e->leftv, co);
@@ -1637,7 +1708,7 @@ static void build_boundary_terminal_edge(BevelParams *bp, BevVert *bv, EdgeHalf
v->efirst = e->prev;
v->elast = v->ebev = e;
e->leftv = v;
- e->prev->leftv = v;
+ e->prev->leftv = e->prev->rightv = v;
}
else {
adjust_bound_vert(e->leftv, co);
@@ -1648,7 +1719,7 @@ static void build_boundary_terminal_edge(BevelParams *bp, BevVert *bv, EdgeHalf
v = add_new_bound_vert(mem_arena, vm, co);
v->efirst = e->prev;
v->elast = e;
- e->leftv = v;
+ e->leftv = e->rightv = v;
e->prev->rightv = v;
}
else {
@@ -1661,7 +1732,7 @@ static void build_boundary_terminal_edge(BevelParams *bp, BevVert *bv, EdgeHalf
if (construct) {
v = add_new_bound_vert(mem_arena, vm, co);
v->efirst = v->elast = e;
- e->leftv = v;
+ e->leftv = e->rightv = v;
}
else {
adjust_bound_vert(e->leftv, co);
@@ -3237,6 +3308,11 @@ static void build_vmesh(BevelParams *bp, BMesh *bm, BevVert *bv)
if (!weld)
create_mesh_bmvert(bm, vm, i, 0, k, bv->v);
}
+ else if (n == 2 && !v->ebev && vm->mesh_kind != M_ADJ) {
+ /* case of one edge beveled and this is the v without ebev */
+ /* want to copy the verts from other v, in reverse order */
+ copy_mesh_vert(vm, i, 0, k, 1 - i, 0, ns - k);
+ }
}
} while ((v = v->next) != vm->boundstart);
@@ -3305,6 +3381,219 @@ static float edge_face_angle(EdgeHalf *e)
#define BM_BEVEL_EDGE_TAG_DISABLE(bme) BM_ELEM_API_FLAG_DISABLE( (bme), _FLAG_OVERLAP)
#define BM_BEVEL_EDGE_TAG_TEST(bme) BM_ELEM_API_FLAG_TEST( (bme), _FLAG_OVERLAP)
+/* Try to extend the bv->edges[] array beyond i by finding more successor edges.
+ * This is a possibly exponential-time search, but it is only exponential in the number
+ * of "internal faces" at a vertex -- i.e., faces that bridge between the edges that naturally
+ * form a manifold cap around bv. It is rare to have more than one of these, so unlikely
+ * that the exponential time case will be hit in practice.
+ * Returns the new index i' where bv->edges[i'] ends the best path found.
+ * The path will have the tags of all of its edges set. */
+static int bevel_edge_order_extend(BMesh *bm, BevVert *bv, int i)
+{
+ BMEdge *bme, *bme2, *nextbme;
+ BMLoop *l;
+ BMIter iter;
+ int j, tryj, bestj, nsucs, sucindex, k;
+ BMEdge **sucs = NULL;
+ BMEdge **save_path = NULL;
+ BLI_array_staticdeclare(sucs, 4); /* likely very few faces attached to same edge */
+ BLI_array_staticdeclare(save_path, BM_DEFAULT_NGON_STACK_SIZE);
+
+ bme = bv->edges[i].e;
+ /* fill sucs with all unmarked edges of bmes */
+ BM_ITER_ELEM(l, &iter, bme, BM_LOOPS_OF_EDGE) {
+ bme2 = (l->v == bv->v) ? l->prev->e : l->next->e;
+ if (!BM_BEVEL_EDGE_TAG_TEST(bme2)) {
+ BLI_array_append(sucs, bme2);
+ }
+ }
+ nsucs = BLI_array_count(sucs);
+
+ bestj = j = i;
+ for (sucindex = 0; sucindex < nsucs; sucindex++) {
+ nextbme = sucs[sucindex];
+ BLI_assert(nextbme != NULL);
+ BLI_assert(!BM_BEVEL_EDGE_TAG_TEST(nextbme));
+ BLI_assert(j + 1 < bv->edgecount);
+ bv->edges[j + 1].e = nextbme;
+ BM_BEVEL_EDGE_TAG_ENABLE(nextbme);
+ tryj = bevel_edge_order_extend(bm, bv, j + 1);
+ if (tryj > bestj || (tryj == bestj && edges_face_connected_at_vert(bv->edges[tryj].e, bv->edges[0].e))) {
+ bestj = tryj;
+ BLI_array_empty(save_path);
+ for (k = j + 1; k <= bestj; k++) {
+ BLI_array_append(save_path, bv->edges[k].e);
+ }
+ }
+ /* now reset to path only-going-to-j state */
+ for (k = j + 1; k <= tryj; k++) {
+ BM_BEVEL_EDGE_TAG_DISABLE(bv->edges[k].e);
+ bv->edges[k].e = NULL;
+ }
+ }
+ /* at this point we should be back at invariant on entrance: path up to j */
+ if (bestj > j) {
+ /* save_path should have from j + 1 to bestj inclusive edges to add to edges[] before returning */
+ for (k = j + 1; k <= bestj; k++) {
+ BLI_assert(save_path[k - (j + 1)] != NULL);
+ bv->edges[k].e = save_path[k - (j + 1)];
+ BM_BEVEL_EDGE_TAG_ENABLE(bv->edges[k].e);
+ }
+ }
+ BLI_array_free(sucs);
+ BLI_array_free(save_path);
+ return bestj;
+}
+
+/* See if we have usual case for bevel edge order:
+ * there is an ordering such that all the faces are between
+ * successive edges and form a manifold "cap" at bv.
+ * If this is the case, set bv->edges to such an order
+ * and return true; else return unmark any partial path and return false.
+ * Assume the first edge is already in bv->edges[0].e and it is tagged. */
+#ifdef FASTER_FASTORDER
+/* The alternative older code is O(n^2) where n = # of edges incident to bv->v.
+ * This implementation is O(n * m) where m = average number of faces attached to an edge incident to bv->v,
+ * which is almost certainly a small constant except in very strange cases. But this code produces different
+ * choices of ordering than the legacy system, leading to differences in vertex orders etc. in user models,
+ * so for now will continue to use the legacy code. */
+static bool fast_bevel_edge_order(BevVert *bv)
+{
+ int j, k, nsucs;
+ BMEdge *bme, *bme2, *bmenext;
+ BMIter iter;
+ BMLoop *l;
+
+ for (j = 1; j < bv->edgecount; j++) {
+ bme = bv->edges[j - 1].e;
+ bmenext = NULL;
+ nsucs = 0;
+ BM_ITER_ELEM(l, &iter, bme, BM_LOOPS_OF_EDGE) {
+ bme2 = (l->v == bv->v) ? l->prev->e : l->next->e;
+ if (!BM_BEVEL_EDGE_TAG_TEST(bme2)) {
+ nsucs++;
+ if (bmenext == NULL)
+ bmenext = bme2;
+ }
+ }
+ if (nsucs == 0 || (nsucs == 2 && j != 1) || nsucs > 2 ||
+ (j == bv->edgecount - 1 && !edges_face_connected_at_vert(bmenext, bv->edges[0].e)))
+ {
+ for (k = 1; k < j; k++) {
+ BM_BEVEL_EDGE_TAG_DISABLE(bv->edges[k].e);
+ bv->edges[k].e = NULL;
+ }
+ return false;
+ }
+ bv->edges[j].e = bmenext;
+ BM_BEVEL_EDGE_TAG_ENABLE(bmenext);
+ }
+ return true;
+}
+#else
+static bool fast_bevel_edge_order(BevVert *bv)
+{
+ BMEdge *bme, *bme2, *first_suc;
+ BMIter iter, iter2;
+ BMFace *f;
+ EdgeHalf *e;
+ int i, k, ntot, num_shared_face;
+
+ ntot = bv->edgecount;
+
+ /* add edges to bv->edges in order that keeps adjacent edges sharing
+ * a unique face, if possible */
+ e = &bv->edges[0];
+ bme = e->e;
+ if (!bme->l)
+ return false;
+ for (i = 1; i < ntot; i++) {
+ /* find an unflagged edge bme2 that shares a face f with previous bme */
+ num_shared_face = 0;
+ first_suc = NULL; /* keep track of first successor to match legacy behavior */
+ BM_ITER_ELEM (bme2, &iter, bv->v, BM_EDGES_OF_VERT) {
+ if (BM_BEVEL_EDGE_TAG_TEST(bme2))
+ continue;
+ BM_ITER_ELEM (f, &iter2, bme2, BM_FACES_OF_EDGE) {
+ if (BM_face_edge_share_loop(f, bme)) {
+ num_shared_face++;
+ if (first_suc == NULL)
+ first_suc = bme2;
+ }
+ }
+ if (num_shared_face >= 3)
+ break;
+ }
+ if (num_shared_face == 1 || (i == 1 && num_shared_face == 2)) {
+ e = &bv->edges[i];
+ e->e = bme = first_suc;
+ BM_BEVEL_EDGE_TAG_ENABLE(bme);
+ }
+ else {
+ for (k = 1; k < i; k++) {
+ BM_BEVEL_EDGE_TAG_DISABLE(bv->edges[k].e);
+ bv->edges[k].e = NULL;
+ }
+ return false;
+ }
+ }
+ return true;
+}
+#endif
+
+/* Fill in bv->edges with a good ordering of non-wire edges around bv->v.
+ * Use only edges where BM_BEVEL_EDGE_TAG is disabled so far
+ * (if edge beveling, others are wire).
+ * first_bme is a good edge to start with.*/
+static void find_bevel_edge_order(BMesh *bm, BevVert *bv, BMEdge *first_bme)
+{
+ BMEdge *bme, *bme2;
+ BMIter iter;
+ BMFace *f;
+ EdgeHalf *e;
+ EdgeHalf *e2;
+ BMLoop *l;
+ int i, ntot;
+
+ ntot = bv->edgecount;
+ i = 0;
+ for (;;) {
+ BLI_assert(first_bme != NULL);
+ bv->edges[i].e = first_bme;
+ BM_BEVEL_EDGE_TAG_ENABLE(first_bme);
+ if (fast_bevel_edge_order(bv))
+ break;
+ i = bevel_edge_order_extend(bm, bv, i);
+ i++;
+ if (i >= bv->edgecount)
+ break;
+ /* Not done yet: find a new first_bme */
+ first_bme = NULL;
+ BM_ITER_ELEM(bme, &iter, bv->v, BM_EDGES_OF_VERT) {
+ if (BM_BEVEL_EDGE_TAG_TEST(bme))
+ continue;
+ if (!first_bme)
+ first_bme = bme;
+ if (BM_edge_face_count(bme) == 1) {
+ first_bme = bme;
+ break;
+ }
+ }
+ }
+ /* now fill in the faces ... */
+ for (i = 0; i < ntot; i++) {
+ e = &bv->edges[i];
+ e2 = (i == bv->edgecount - 1) ? &bv->edges[0] : &bv->edges[i + 1];
+ bme = e->e;
+ bme2 = e2->e;
+ BM_ITER_ELEM(l, &iter, bme, BM_LOOPS_OF_EDGE) {
+ f = l->f;
+ if ((l->prev->e == bme2 || l->next->e == bme2) && !e->fnext && !e2->fprev)
+ e->fnext = e2->fprev = f;
+ }
+ }
+}
+
/*
* Construction around the vertex
*/
@@ -3312,13 +3601,12 @@ static BevVert *bevel_vert_construct(BMesh *bm, BevelParams *bp, BMVert *v)
{
BMEdge *bme;
BevVert *bv;
- BMEdge *bme2, *unflagged_bme, *first_bme;
- BMFace *f;
+ BMEdge *first_bme;
BMVert *v1, *v2;
- BMIter iter, iter2;
+ BMIter iter;
EdgeHalf *e;
float weight, z;
- int i, found_shared_face, ccw_test_sum;
+ int i, ccw_test_sum;
int nsel = 0;
int ntot = 0;
int nwire = 0;
@@ -3398,47 +3686,12 @@ static BevVert *bevel_vert_construct(BMesh *bm, BevelParams *bp, BMVert *v)
}
BLI_ghash_insert(bp->vert_hash, v, bv);
- /* add edges to bv->edges in order that keeps adjacent edges sharing
- * a face, if possible */
- i = 0;
+ find_bevel_edge_order(bm, bv, first_bme);
- bme = first_bme;
- BM_BEVEL_EDGE_TAG_ENABLE(bme);
- e = &bv->edges[0];
- e->e = bme;
+ /* fill in other attributes of EdgeHalfs */
for (i = 0; i < ntot; i++) {
- if (i > 0) {
- /* find an unflagged edge bme2 that shares a face f with previous bme */
- found_shared_face = 0;
- unflagged_bme = NULL;
- BM_ITER_ELEM (bme2, &iter, v, BM_EDGES_OF_VERT) {
- if (BM_BEVEL_EDGE_TAG_TEST(bme2))
- continue;
- if (!unflagged_bme)
- unflagged_bme = bme2;
- if (!bme->l)
- continue;
- BM_ITER_ELEM (f, &iter2, bme2, BM_FACES_OF_EDGE) {
- if (BM_face_edge_share_loop(f, bme)) {
- found_shared_face = 1;
- break;
- }
- }
- if (found_shared_face)
- break;
- }
- e = &bv->edges[i];
- if (found_shared_face) {
- e->e = bme2;
- e->fprev = f;
- bv->edges[i - 1].fnext = f;
- }
- else {
- e->e = unflagged_bme;
- }
- }
+ e = &bv->edges[i];
bme = e->e;
- BM_BEVEL_EDGE_TAG_ENABLE(bme);
if (BM_elem_flag_test(bme, BM_ELEM_TAG) && !bp->vertex_only) {
e->is_bev = true;
e->seg = bp->seg;
@@ -3449,16 +3702,6 @@ static BevVert *bevel_vert_construct(BMesh *bm, BevelParams *bp, BMVert *v)
}
e->is_rev = (bme->v2 == v);
}
- /* find wrap-around shared face */
- BM_ITER_ELEM (f, &iter2, bme, BM_FACES_OF_EDGE) {
- if (bv->edges[0].e->l && BM_face_edge_share_loop(f, bv->edges[0].e)) {
- if (bv->edges[0].fnext == f)
- continue; /* if two shared faces, want the other one now */
- bv->edges[ntot - 1].fnext = f;
- bv->edges[0].fprev = f;
- break;
- }
- }
/* now done with tag flag */
BM_ITER_ELEM (bme, &iter, v, BM_EDGES_OF_VERT) {
@@ -3586,6 +3829,7 @@ static bool bev_rebuild_polygon(BMesh *bm, BevelParams *bp, BMFace *f)
VMesh *vm;
int i, k, n;
bool do_rebuild = false;
+ bool go_ccw, corner3special;
BMVert *bmv;
BMEdge *bme, *bme_new, *bme_prev;
BMFace *f_new;
@@ -3600,47 +3844,88 @@ static bool bev_rebuild_polygon(BMesh *bm, BevelParams *bp, BMFace *f)
if (BM_elem_flag_test(l->v, BM_ELEM_TAG)) {
lprev = l->prev;
bv = find_bevvert(bp, l->v);
+ vm = bv->vmesh;
e = find_edge_half(bv, l->e);
bme = e->e;
eprev = find_edge_half(bv, lprev->e);
BLI_assert(e != NULL && eprev != NULL);
- vstart = eprev->leftv;
- if (e->is_bev)
- vend = e->rightv;
- else
+
+ /* which direction around our vertex do we travel to match orientation of f? */
+ if (e->prev == eprev) {
+ if (eprev->prev == e) {
+ /* valence 2 vertex: use f is one of e->fnext or e->fprev to break tie */
+ go_ccw = (e->fnext != f);
+ }
+ else {
+ go_ccw = true; /* going ccw around bv to trace this corner */
+ }
+ }
+ else if (eprev->prev == e) {
+ go_ccw = false; /* going cw around bv to trace this corner */
+ }
+ else {
+ /* edges in face are non-contiguous in our ordering around bv.
+ * Which way should we go when going from eprev to e? */
+ if (count_ccw_edges_between(eprev, e) < count_ccw_edges_between(e, eprev)) {
+ /* go counterclockewise from eprev to e */
+ go_ccw = true;
+ }
+ else {
+ /* go clockwise from eprev to e */
+ go_ccw = false;
+ }
+ }
+ if (go_ccw) {
+ vstart = eprev->rightv;
vend = e->leftv;
+ }
+ else {
+ vstart = eprev->leftv;
+ vend = e->rightv;
+ }
+ BLI_assert(vstart != NULL && vend != NULL);
v = vstart;
- vm = bv->vmesh;
BLI_array_append(vv, v->nv.v);
BLI_array_append(ee, bme);
+ /* check for special case: multisegment 3rd face opposite a beveled edge with no vmesh */
+ corner3special = (vm->mesh_kind == M_NONE && v->ebev != e && v->ebev != eprev);
while (v != vend) {
- if (vm->mesh_kind == M_NONE && v->ebev && v->ebev->seg > 1 && v->ebev != e && v->ebev != eprev) {
- /* case of 3rd face opposite a beveled edge, with no vmesh */
- i = v->index;
- e = v->ebev;
- for (k = 1; k < e->seg; k++) {
- bmv = mesh_vert(vm, i, 0, k)->v;
- BLI_array_append(vv, bmv);
- BLI_array_append(ee, bme);
- /* may want to merge UVs of these later */
- if (!e->is_seam)
- BLI_array_append(vv_fix, bmv);
+ if (go_ccw) {
+ if (vm->seg > 1) {
+ if (vm->mesh_kind == M_ADJ || bp->vertex_only || corner3special) {
+ i = v->index;
+ for (k = 1; k < vm->seg; k++) {
+ bmv = mesh_vert(vm, i, 0, k)->v;
+ BLI_array_append(vv, bmv);
+ BLI_array_append(ee, bme); /* TODO: maybe better edge here */
+ if (corner3special && v->ebev && !v->ebev->is_seam)
+ BLI_array_append(vv_fix, bmv);
+ }
+ }
}
+ v = v->next;
}
- else if ((vm->mesh_kind == M_ADJ || bp->vertex_only) && vm->seg > 1 && !e->is_bev && !eprev->is_bev) {
- BLI_assert(v->prev == vend);
- i = vend->index;
- for (k = vm->seg - 1; k > 0; k--) {
- bmv = mesh_vert(vm, i, 0, k)->v;
- BLI_array_append(vv, bmv);
- BLI_array_append(ee, bme);
+ else {
+ /* going cw */
+ if (vm->seg > 1) {
+ if (vm->mesh_kind == M_ADJ || bp->vertex_only ||
+ (vm->mesh_kind == M_NONE && v->ebev != e && v->ebev != eprev))
+ {
+ i = v->prev->index;
+ for (k = vm->seg - 1; k > 0; k--) {
+ bmv = mesh_vert(vm, i, 0, k)->v;
+ BLI_array_append(vv, bmv);
+ BLI_array_append(ee, bme);
+ if (corner3special && v->ebev && !v->ebev->is_seam)
+ BLI_array_append(vv_fix, bmv);
+ }
+ }
}
+ v = v->prev;
}
- v = v->prev;
BLI_array_append(vv, v->nv.v);
BLI_array_append(ee, bme);
}
-
do_rebuild = true;
}
else {
diff --git a/source/blender/collada/ArmatureExporter.cpp b/source/blender/collada/ArmatureExporter.cpp
index 36ab85b9b5b..4f5cf83f5ca 100644
--- a/source/blender/collada/ArmatureExporter.cpp
+++ b/source/blender/collada/ArmatureExporter.cpp
@@ -67,12 +67,19 @@ void ArmatureExporter::add_armature_bones(Object *ob_arm, Scene *sce,
std::list<Object *>& child_objects)
{
// write bone nodes
+
+ bArmature * armature = (bArmature *)ob_arm->data;
+ ED_armature_to_edit(armature);
+
bArmature *arm = (bArmature *)ob_arm->data;
for (Bone *bone = (Bone *)arm->bonebase.first; bone; bone = bone->next) {
// start from root bones
if (!bone->parent)
add_bone_node(bone, ob_arm, sce, se, child_objects);
}
+
+ ED_armature_from_edit(armature);
+ ED_armature_edit_free(armature);
}
void ArmatureExporter::write_bone_URLs(COLLADASW::InstanceController &ins, Object *ob_arm, Bone *bone)
@@ -167,12 +174,30 @@ void ArmatureExporter::add_bone_node(Bone *bone, Object *ob_arm, Scene *sce,
node.setNodeName(node_name);
node.setNodeSid(node_sid);
-#if 0
- if (BLI_listbase_is_empty(&bone->childbase) || BLI_listbase_count_ex(&bone->childbase, 2) == 2) {
- add_blender_leaf_bone( bone, ob_arm, node);
+ if (this->export_settings->use_blender_profile)
+ {
+ if (bone->parent) {
+ if (bone->flag & BONE_CONNECTED) {
+ node.addExtraTechniqueParameter("blender", "connect", true);
+ }
+ }
+ std::string layers = BoneExtended::get_bone_layers(bone->layer);
+ node.addExtraTechniqueParameter("blender", "layer", layers);
+
+ bArmature *armature = (bArmature *)ob_arm->data;
+ EditBone *ebone = bc_get_edit_bone(armature, bone->name);
+ if (ebone && ebone->roll != 0)
+ {
+ node.addExtraTechniqueParameter("blender", "roll", ebone->roll);
+ }
+ if (bc_is_leaf_bone(bone))
+ {
+ node.addExtraTechniqueParameter("blender", "tip_x", bone->arm_tail[0] - bone->arm_head[0]);
+ node.addExtraTechniqueParameter("blender", "tip_y", bone->arm_tail[1] - bone->arm_head[1]);
+ node.addExtraTechniqueParameter("blender", "tip_z", bone->arm_tail[2] - bone->arm_head[2]);
+ }
}
- else {
-#endif
+
node.start();
add_bone_transform(ob_arm, bone, node);
@@ -227,25 +252,6 @@ void ArmatureExporter::add_bone_node(Bone *bone, Object *ob_arm, Scene *sce,
}
}
-//#if 1
-void ArmatureExporter::add_blender_leaf_bone(Bone *bone, Object *ob_arm, COLLADASW::Node& node)
-{
- node.start();
-
- add_bone_transform(ob_arm, bone, node);
-
- node.addExtraTechniqueParameter("blender", "tip_x", bone->tail[0]);
- node.addExtraTechniqueParameter("blender", "tip_y", bone->tail[1]);
- node.addExtraTechniqueParameter("blender", "tip_z", bone->tail[2]);
-
- /*for (Bone *child = (Bone *)bone->childbase.first; child; child = child->next) {
- add_bone_node(child, ob_arm, sce, se, child_objects);
- }*/
- node.end();
-
-}
-//#endif
-
void ArmatureExporter::add_bone_transform(Object *ob_arm, Bone *bone, COLLADASW::Node& node)
{
//bPoseChannel *pchan = BKE_pose_channel_find_name(ob_arm->pose, bone->name);
diff --git a/source/blender/collada/ArmatureExporter.h b/source/blender/collada/ArmatureExporter.h
index 931cc5d2988..883a6aca847 100644
--- a/source/blender/collada/ArmatureExporter.h
+++ b/source/blender/collada/ArmatureExporter.h
@@ -92,8 +92,6 @@ private:
void add_bone_transform(Object *ob_arm, Bone *bone, COLLADASW::Node& node);
- void add_blender_leaf_bone(Bone *bone, Object *ob_arm, COLLADASW::Node& node);
-
std::string get_controller_id(Object *ob_arm, Object *ob);
void write_bone_URLs(COLLADASW::InstanceController &ins, Object *ob_arm, Bone *bone);
diff --git a/source/blender/collada/ArmatureImporter.cpp b/source/blender/collada/ArmatureImporter.cpp
index fd08e1ebfab..1bc2bff74e3 100644
--- a/source/blender/collada/ArmatureImporter.cpp
+++ b/source/blender/collada/ArmatureImporter.cpp
@@ -50,19 +50,6 @@ static const char *bc_get_joint_name(T *node)
return id.size() ? id.c_str() : node->getOriginalId().c_str();
}
-static EditBone *get_edit_bone(bArmature * armature, char *name) {
- EditBone *eBone;
-
- for (eBone = (EditBone *)armature->edbo->first; eBone; eBone = eBone->next) {
- if (STREQ(name, eBone->name))
- return eBone;
- }
-
- return NULL;
-
-}
-
-
ArmatureImporter::ArmatureImporter(UnitConverter *conv, MeshImporterBase *mesh, Scene *sce, const ImportSettings *import_settings) :
import_settings(import_settings),
@@ -110,7 +97,7 @@ JointData *ArmatureImporter::get_joint_data(COLLADAFW::Node *node);
#endif
int ArmatureImporter::create_bone(SkinInfo *skin, COLLADAFW::Node *node, EditBone *parent, int totchild,
- float parent_mat[4][4], bArmature *arm)
+ float parent_mat[4][4], bArmature *arm, std::vector<std::string> &layer_labels)
{
float mat[4][4];
float joint_inv_bind_mat[4][4];
@@ -120,27 +107,39 @@ 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;
-
- // JointData* jd = get_joint_data(node);
- // TODO rename from Node "name" attrs later
EditBone *bone = ED_armature_edit_bone_add(arm, (char *)bc_get_joint_name(node));
totbone++;
- if (skin && skin->get_joint_inv_bind_matrix(joint_inv_bind_mat, node)) {
- // get original world-space matrix
- invert_m4_m4(mat, joint_inv_bind_mat);
+ /*
+ * We use the inv_bind_shape matrix to apply the armature bind pose as its rest pose.
+ */
+
+ std::map<COLLADAFW::UniqueId, SkinInfo>::iterator skin_it;
+ bool bone_is_not_skinned = true;
+ for (skin_it = skin_by_data_uid.begin(); skin_it != skin_by_data_uid.end(); skin_it++) {
+
+ SkinInfo *b = &skin_it->second;
+ if (b->get_joint_inv_bind_matrix(joint_inv_bind_mat, node)) {
- // And make local to armature
- Object *ob_arm = skin->BKE_armature_from_object();
- if (ob_arm) {
- float invmat[4][4];
- invert_m4_m4(invmat, ob_arm->obmat);
- mul_m4_m4m4(mat, invmat, mat);
+ // get original world-space matrix
+ invert_m4_m4(mat, joint_inv_bind_mat);
+
+ // And make local to armature
+ Object *ob_arm = skin->BKE_armature_from_object();
+ if (ob_arm) {
+ float invmat[4][4];
+ invert_m4_m4(invmat, ob_arm->obmat);
+ mul_m4_m4m4(mat, invmat, mat);
+ }
+
+ bone_is_not_skinned = false;
+ break;
}
}
+
// create a bone even if there's no joint data for it (i.e. it has no influence)
- else {
+ if (bone_is_not_skinned) {
float obmat[4][4];
// bone-space
get_node_mat(obmat, node, NULL, NULL);
@@ -157,22 +156,40 @@ int ArmatureImporter::create_bone(SkinInfo *skin, COLLADAFW::Node *node, EditBon
if (parent) bone->parent = parent;
float loc[3], size[3], rot[3][3];
- float angle;
- float vec[3] = {0.0f, 0.5f, 0.0f};
- mat4_to_loc_rot_size(loc, rot, size, mat);
- //copy_m3_m4(bonemat,mat);
- mat3_to_vec_roll(rot, vec, &angle);
-
- bone->roll = angle;
- // set head
- copy_v3_v3(bone->head, mat[3]);
- // set tail, don't set it to head because 0-length bones are not allowed
- add_v3_v3v3(bone->tail, bone->head, vec);
+ BoneExtended &be = add_bone_extended(bone, node, totchild, layer_labels);
+ int layer = be.get_bone_layers();
+ if (layer) bone->layer = layer;
+ arm->layer |= layer; // ensure that all populated bone layers are visible after import
+
+ float *tail = be.get_tail();
+ int use_connect = be.get_use_connect();
+
+ switch (use_connect) {
+ case 1: bone->flag |= BONE_CONNECTED;
+ break;
+ case 0: bone->flag &= ~BONE_CONNECTED;
+ case -1: break; // not defined
+ }
+
+ if (be.has_roll()) {
+ bone->roll = be.get_roll();
+ }
+ else {
+ float angle;
+ mat4_to_loc_rot_size(loc, rot, size, mat);
+ mat3_to_vec_roll(rot, NULL, &angle);
+ }
+ copy_v3_v3(bone->head, mat[3]);
+ add_v3_v3v3(bone->tail, bone->head, tail); //tail must be non zero
/* find smallest bone length in armature (used later for leaf bone length) */
if (parent) {
+ if (use_connect == 1) {
+ copy_v3_v3(parent->tail, bone->head);
+ }
+
/* guess reasonable leaf bone length */
float length = len_v3v3(parent->head, bone->head);
if ((length < leaf_bone_length || totbone == 0) && length > MINIMUM_BONE_LENGTH) {
@@ -182,11 +199,8 @@ int ArmatureImporter::create_bone(SkinInfo *skin, COLLADAFW::Node *node, EditBon
COLLADAFW::NodePointerArray& children = node->getChildNodes();
- BoneExtended &be = add_bone_extended(bone, node);
- be.set_leaf_bone(true);
-
for (unsigned int i = 0; i < children.getCount(); i++) {
- int cl = create_bone(skin, children[i], bone, children.getCount(), mat, arm);
+ int cl = create_bone(skin, children[i], bone, children.getCount(), mat, arm, layer_labels);
if (cl > chain_length)
chain_length = cl;
}
@@ -209,22 +223,23 @@ int ArmatureImporter::create_bone(SkinInfo *skin, COLLADAFW::Node *node, EditBon
**/
void ArmatureImporter::fix_leaf_bones(bArmature *armature, Bone *bone)
{
- /* armature has no bones */
if (bone == NULL)
return;
- BoneExtended *be = extended_bones[bone->name];
- if (be != NULL && be->is_leaf_bone() ) {
- /* Collada only knows Joints, Here we guess a reasonable leaf bone length */
- float leaf_length = (leaf_bone_length == FLT_MAX) ? 1.0 : leaf_bone_length;
+ if (bc_is_leaf_bone(bone)) {
+
+ BoneExtended *be = extended_bones[bone->name];
+ if (be == NULL || !be->has_tail()) {
- EditBone *ebone = get_edit_bone(armature, bone->name);
- float vec[3];
+ /* Collada only knows Joints, Here we guess a reasonable leaf bone length */
+ float leaf_length = (leaf_bone_length == FLT_MAX) ? 1.0 : leaf_bone_length;
+
+ EditBone *ebone = bc_get_edit_bone(armature, bone->name);
+ float vec[3];
- if (this->import_settings->fix_orientation) {
if (ebone->parent != NULL) {
EditBone *parent = ebone->parent;
- sub_v3_v3v3(vec, ebone->head, parent->tail);
+ sub_v3_v3v3(vec, ebone->head, parent->head);
if (len_squared_v3(vec) < MINIMUM_BONE_LENGTH)
{
sub_v3_v3v3(vec, parent->tail, parent->head);
@@ -234,19 +249,31 @@ void ArmatureImporter::fix_leaf_bones(bArmature *armature, Bone *bone)
vec[2] = 0.1f;
sub_v3_v3v3(vec, ebone->tail, ebone->head);
}
- }
- else {
- sub_v3_v3v3(vec, ebone->tail, ebone->head);
- }
- normalize_v3_v3(vec, vec);
- mul_v3_fl(vec, leaf_length);
- add_v3_v3v3(ebone->tail, ebone->head, vec);
+ normalize_v3_v3(vec, vec);
+ mul_v3_fl(vec, leaf_length);
+ add_v3_v3v3(ebone->tail, ebone->head, vec);
+ }
}
for (Bone *child = (Bone *)bone->childbase.first; child; child = child->next) {
fix_leaf_bones(armature, child);
}
+}
+
+void ArmatureImporter::fix_parent_connect(bArmature *armature, Bone *bone)
+{
+ /* armature has no bones */
+ if (bone == NULL)
+ return;
+
+ if (bone->parent && bone->flag & BONE_CONNECTED) {
+ copy_v3_v3(bone->parent->tail, bone->head);
+ }
+
+ for (Bone *child = (Bone *)bone->childbase.first; child; child = child->next) {
+ fix_parent_connect(armature, child);
+ }
}
@@ -281,8 +308,8 @@ void ArmatureImporter::connect_bone_chains(bArmature *armature, Bone *parentbone
BoneExtended *pbe = extended_bones[parentbone->name];
if (dominant_child != NULL) {
/* Found a valid chain. Now connect current bone with that chain.*/
- EditBone *pebone = get_edit_bone(armature, parentbone->name);
- EditBone *cebone = get_edit_bone(armature, dominant_child->get_name());
+ EditBone *pebone = bc_get_edit_bone(armature, parentbone->name);
+ EditBone *cebone = bc_get_edit_bone(armature, dominant_child->get_name());
if (pebone && !(cebone->flag & BONE_CONNECTED)) {
float vec[3];
@@ -418,11 +445,12 @@ ArmatureJoints& ArmatureImporter::get_armature_joints(Object *ob_arm)
return armature_joints.back();
}
#endif
-void ArmatureImporter::create_armature_bones( )
+Object *ArmatureImporter::create_armature_bones(std::vector<Object *> &ob_arms)
{
std::vector<COLLADAFW::Node *>::iterator ri;
+ std::vector<std::string> layer_labels;
+ Object *ob_arm = NULL;
- leaf_bone_length = FLT_MAX;
//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;
@@ -445,29 +473,26 @@ void ArmatureImporter::create_armature_bones( )
clear_extended_boneset();
ED_armature_to_edit(armature);
+ armature->layer = 0; // layer is set according to imported bone set in create_bone()
- create_bone(NULL, *ri , NULL, (*ri)->getChildNodes().getCount(), NULL, armature);
+ create_bone(NULL, *ri , NULL, (*ri)->getChildNodes().getCount(), NULL, armature, layer_labels);
/* exit armature edit mode to populate the Armature object */
+ unskinned_armature_map[(*ri)->getUniqueId()] = ob_arm;
ED_armature_from_edit(armature);
ED_armature_edit_free(armature);
- /* and step back to edit mode to fix the leaf nodes */
- ED_armature_to_edit(armature);
-
- connect_bone_chains(armature, (Bone *)armature->bonebase.first, UNLIMITED_CHAIN_MAX);
- fix_leaf_bones(armature, (Bone *)armature->bonebase.first);
-
- // exit armature edit mode
- unskinned_armature_map[(*ri)->getUniqueId()] = ob_arm;
+ int index = std::find(ob_arms.begin(), ob_arms.end(), ob_arm) - ob_arms.begin();
+ if (index == 0) {
+ ob_arms.push_back(ob_arm);
+ }
- ED_armature_from_edit(armature);
- ED_armature_edit_free(armature);
DAG_id_tag_update(&ob_arm->id, OB_RECALC_OB | OB_RECALC_DATA);
}
+ return ob_arm;
}
-void ArmatureImporter::create_armature_bones(SkinInfo& skin)
+Object *ArmatureImporter::create_armature_bones(SkinInfo& skin)
{
// just do like so:
// - get armature
@@ -513,6 +538,7 @@ void ArmatureImporter::create_armature_bones(SkinInfo& skin)
SkinInfo *a = &skin;
Object *shared = NULL;
std::vector<COLLADAFW::Node *> skin_root_joints;
+ std::vector<std::string> layer_labels;
std::map<COLLADAFW::UniqueId, SkinInfo>::iterator it;
for (it = skin_by_data_uid.begin(); it != skin_by_data_uid.end(); it++) {
@@ -562,7 +588,6 @@ void ArmatureImporter::create_armature_bones(SkinInfo& skin)
totbone = 0;
// bone_direction_row = 1; // TODO: don't default to Y but use asset and based on it decide on default row
- leaf_bone_length = FLT_MAX;
// create bones
/*
@@ -578,7 +603,8 @@ void ArmatureImporter::create_armature_bones(SkinInfo& skin)
// since root_joints may contain joints for multiple controllers, we need to filter
if (skin.uses_joint_or_descendant(*ri)) {
- create_bone(&skin, *ri, NULL, (*ri)->getChildNodes().getCount(), NULL, armature);
+
+ create_bone(&skin, *ri, NULL, (*ri)->getChildNodes().getCount(), NULL, armature, layer_labels);
if (joint_parent_map.find((*ri)->getUniqueId()) != joint_parent_map.end() && !skin.get_parent())
skin.set_parent(joint_parent_map[(*ri)->getUniqueId()]);
@@ -589,18 +615,9 @@ void ArmatureImporter::create_armature_bones(SkinInfo& skin)
ED_armature_from_edit(armature);
ED_armature_edit_free(armature);
- /* and step back to edit mode to fix the leaf nodes */
- ED_armature_to_edit(armature);
-
- if (armature->bonebase.first) {
- /* Do this only if Armature has bones */
- connect_bone_chains(armature, (Bone *)armature->bonebase.first, UNLIMITED_CHAIN_MAX);
- fix_leaf_bones(armature, (Bone *)armature->bonebase.first);
- }
- // exit armature edit mode
- ED_armature_from_edit(armature);
- ED_armature_edit_free(armature);
DAG_id_tag_update(&ob_arm->id, OB_RECALC_OB | OB_RECALC_DATA);
+
+ return ob_arm;
}
void ArmatureImporter::set_pose(Object *ob_arm, COLLADAFW::Node *root_node, const char *parentname, float parent_mat[4][4])
@@ -675,22 +692,42 @@ void ArmatureImporter::add_root_joint(COLLADAFW::Node *node)
#endif
// here we add bones to armatures, having armatures previously created in write_controller
-void ArmatureImporter::make_armatures(bContext *C)
+void ArmatureImporter::make_armatures(bContext *C, std::vector<Object *> &objects_to_scale)
{
+ std::vector<Object *> ob_arms;
std::map<COLLADAFW::UniqueId, SkinInfo>::iterator it;
+
+ leaf_bone_length = FLT_MAX; /*TODO: Make this work for more than one armature in the import file*/
+
for (it = skin_by_data_uid.begin(); it != skin_by_data_uid.end(); it++) {
SkinInfo& skin = it->second;
- create_armature_bones(skin);
+ Object *ob_arm = create_armature_bones(skin);
// link armature with a mesh object
const COLLADAFW::UniqueId &uid = skin.get_controller_uid();
const COLLADAFW::UniqueId *guid = get_geometry_uid(uid);
if (guid != NULL) {
Object *ob = mesh_importer->get_object_by_geom_uid(*guid);
- if (ob)
+ if (ob) {
skin.link_armature(C, ob, joint_by_uid, this);
+
+ std::vector<Object *>::iterator ob_it = std::find(objects_to_scale.begin(), objects_to_scale.end(), ob);
+
+ if (ob_it != objects_to_scale.end()) {
+ int index = ob_it - objects_to_scale.begin();
+ objects_to_scale.erase(objects_to_scale.begin() + index);
+ }
+
+ if (std::find(objects_to_scale.begin(), objects_to_scale.end(), ob_arm) == objects_to_scale.end()) {
+ objects_to_scale.push_back(ob_arm);
+ }
+
+ if (std::find(ob_arms.begin(), ob_arms.end(), ob_arm) == ob_arms.end()) {
+ ob_arms.push_back(ob_arm);
+ }
+ }
else
fprintf(stderr, "Cannot find object to link armature with.\n");
}
@@ -707,7 +744,35 @@ void ArmatureImporter::make_armatures(bContext *C)
}
//for bones without skins
- create_armature_bones();
+ create_armature_bones(ob_arms);
+
+ // Fix bone relations
+ std::vector<Object *>::iterator ob_arm_it;
+ for (ob_arm_it = ob_arms.begin(); ob_arm_it != ob_arms.end(); ob_arm_it++) {
+
+ Object *ob_arm = *ob_arm_it;
+ bArmature *armature = (bArmature *)ob_arm->data;
+
+ /* and step back to edit mode to fix the leaf nodes */
+ ED_armature_to_edit(armature);
+
+ if (this->import_settings->fix_orientation || this->import_settings->find_chains) {
+
+ if (this->import_settings->find_chains)
+ connect_bone_chains(armature, (Bone *)armature->bonebase.first, UNLIMITED_CHAIN_MAX);
+
+ if (this->import_settings->fix_orientation)
+ fix_leaf_bones(armature, (Bone *)armature->bonebase.first);
+
+ // exit armature edit mode
+
+ }
+
+ fix_parent_connect(armature, (Bone *)armature->bonebase.first);
+
+ ED_armature_from_edit(armature);
+ ED_armature_edit_free(armature);
+ }
}
#if 0
@@ -894,70 +959,55 @@ bool ArmatureImporter::get_joint_bind_mat(float m[4][4], COLLADAFW::Node *joint)
return found;
}
-
-/**
- * BoneExtended is a helper class needed for the Bone chain finder
- * See ArmatureImporter::fix_leaf_bones()
- * and ArmatureImporter::connect_bone_chains()
- **/
-
-BoneExtended::BoneExtended(EditBone *aBone)
+BoneExtended &ArmatureImporter::add_bone_extended(EditBone *bone, COLLADAFW::Node *node, int sibcount, std::vector<std::string> &layer_labels)
{
- this->set_name(aBone->name);
- this->chain_length = 0;
- this->is_leaf = false;
-}
+ BoneExtended *be = new BoneExtended(bone);
+ extended_bones[bone->name] = be;
-char *BoneExtended::get_name()
-{
- return name;
-}
+ TagsMap::iterator etit;
+ ExtraTags *et = 0;
+ etit = uid_tags_map.find(node->getUniqueId().toAscii());
-void BoneExtended::set_name(char *aName)
-{
- BLI_strncpy(name, aName, MAXBONENAME);
-}
+ bool has_connect = false;
+ int connect_type = -1;
-int BoneExtended::get_chain_length()
-{
- return chain_length;
-}
+ if (etit != uid_tags_map.end()) {
-void BoneExtended::set_chain_length(const int aLength)
-{
- chain_length = aLength;
-}
+ float tail[3] = { FLT_MAX, FLT_MAX, FLT_MAX };
+ float roll = 0;
+ std::string layers;
+ et = etit->second;
-void BoneExtended::set_leaf_bone(bool state)
-{
- is_leaf = state;
-}
+ bool has_tail = false;
+ has_tail |= et->setData("tip_x", &tail[0]);
+ has_tail |= et->setData("tip_y", &tail[1]);
+ has_tail |= et->setData("tip_z", &tail[2]);
-bool BoneExtended::is_leaf_bone()
-{
- return is_leaf;
-}
+ has_connect = et->setData("connect", &connect_type);
+ bool has_roll = et->setData("roll", &roll);
+
+ layers = et->setData("layer", layers);
-BoneExtended &ArmatureImporter::add_bone_extended(EditBone *bone, COLLADAFW::Node *node)
-{
+ if (has_tail && !has_connect)
+ {
+ /* got a bone tail definition but no connect info -> bone is not connected */
+ has_connect = true;
+ connect_type = 0;
+ }
- TagsMap::iterator etit;
- ExtraTags *et = 0;
- etit = uid_tags_map.find(node->getUniqueId().toAscii());
- if (etit != uid_tags_map.end()) {
- float x, y, z;
+ be->set_bone_layers(layers, layer_labels);
+ if (has_tail) be->set_tail(tail);
+ if (has_roll) be->set_roll(roll);
+ }
- et = etit->second;
- et->setData("tip_x", &x);
- et->setData("tip_y", &y);
- et->setData("tip_z", &z);
- float vec[3] = { x, y, z };
- copy_v3_v3(bone->tail, bone->head);
- add_v3_v3v3(bone->tail, bone->head, vec);
+ if (!has_connect && this->import_settings->auto_connect) {
+ /* auto connect only whyen parent has exactly one child*/
+ connect_type = sibcount == 1;
}
- BoneExtended *be = new BoneExtended(bone);
- extended_bones[bone->name] = be;
+ be->set_use_connect(connect_type);
+ be->set_leaf_bone(true);
+
return *be;
}
diff --git a/source/blender/collada/ArmatureImporter.h b/source/blender/collada/ArmatureImporter.h
index 732fda80ff1..e006ccbc94a 100644
--- a/source/blender/collada/ArmatureImporter.h
+++ b/source/blender/collada/ArmatureImporter.h
@@ -59,25 +59,6 @@ extern "C" {
#define UNLIMITED_CHAIN_MAX INT_MAX
#define MINIMUM_BONE_LENGTH 0.000001f
-class BoneExtended {
-
-private:
- char name[MAXBONENAME];
- int chain_length;
- bool is_leaf;
-
-public:
-
- BoneExtended(EditBone *aBone);
- char *get_name();
- int get_chain_length();
-
- void set_name(char *aName);
- void set_chain_length(const int aLength);
- void set_leaf_bone(bool state);
- bool is_leaf_bone();
-};
-
class ArmatureImporter : private TransformReader
{
private:
@@ -125,12 +106,13 @@ private:
#endif
int create_bone(SkinInfo* skin, COLLADAFW::Node *node, EditBone *parent, int totchild,
- float parent_mat[4][4], bArmature *arm);
+ float parent_mat[4][4], bArmature *arm, std::vector<std::string> &layer_labels);
- BoneExtended &add_bone_extended(EditBone *bone, COLLADAFW::Node * node);
+ BoneExtended &add_bone_extended(EditBone *bone, COLLADAFW::Node * node, int sibcount, std::vector<std::string> &layer_labels);
void clear_extended_boneset();
void fix_leaf_bones(bArmature *armature, Bone *bone);
+ void fix_parent_connect(bArmature *armature, Bone *bone);
void connect_bone_chains(bArmature *armature, Bone *bone, const int max_chain_length);
void set_pose( Object *ob_arm, COLLADAFW::Node *root_node, const char *parentname, float parent_mat[4][4]);
@@ -149,8 +131,8 @@ private:
ArmatureJoints& get_armature_joints(Object *ob_arm);
#endif
- void create_armature_bones(SkinInfo& skin);
- void create_armature_bones( );
+ Object *create_armature_bones(SkinInfo& skin);
+ Object *create_armature_bones(std::vector<Object *> &arm_objs);
/** TagsMap typedef for uid_tags_map. */
typedef std::map<std::string, ExtraTags*> TagsMap;
@@ -163,7 +145,7 @@ public:
void add_root_joint(COLLADAFW::Node *node, Object *parent);
// here we add bones to armatures, having armatures previously created in write_controller
- void make_armatures(bContext *C);
+ void make_armatures(bContext *C, std::vector<Object *> &objects_to_scale);
void make_shape_keys();
diff --git a/source/blender/collada/DocumentImporter.cpp b/source/blender/collada/DocumentImporter.cpp
index 45dcf436473..3a709da78e1 100644
--- a/source/blender/collada/DocumentImporter.cpp
+++ b/source/blender/collada/DocumentImporter.cpp
@@ -239,7 +239,7 @@ void DocumentImporter::finish()
mesh_importer.optimize_material_assignements();
armature_importer.set_tags_map(this->uid_tags_map);
- armature_importer.make_armatures(mContext);
+ armature_importer.make_armatures(mContext, *objects_to_scale);
armature_importer.make_shape_keys();
DAG_relations_tag_update(bmain);
@@ -517,7 +517,7 @@ std::vector<Object *> *DocumentImporter::write_node(COLLADAFW::Node *node, COLLA
name.c_str());
if (is_joint) {
- if (parent_node == NULL) {
+ if (parent_node == NULL && !is_library_node) {
// A Joint on root level is a skeleton without root node.
// Here we add the armature "on the fly":
par = bc_add_object(sce, OB_ARMATURE, std::string("Armature").c_str());
diff --git a/source/blender/collada/ExportSettings.h b/source/blender/collada/ExportSettings.h
index 3dc7e74379e..9451cac9dae 100644
--- a/source/blender/collada/ExportSettings.h
+++ b/source/blender/collada/ExportSettings.h
@@ -48,6 +48,7 @@ public:
bool triangulate;
bool use_object_instantiation;
+ bool use_blender_profile;
bool sort_by_name;
BC_export_transformation_type export_transformation_type;
bool open_sim;
diff --git a/source/blender/collada/ExtraTags.cpp b/source/blender/collada/ExtraTags.cpp
index 6af61432fda..ea225d8a4ae 100644
--- a/source/blender/collada/ExtraTags.cpp
+++ b/source/blender/collada/ExtraTags.cpp
@@ -85,32 +85,45 @@ std::string ExtraTags::asString(std::string tag, bool *ok)
}
-void ExtraTags::setData(std::string tag, short *data)
+bool ExtraTags::setData(std::string tag, short *data)
{
bool ok = false;
int tmp = asInt(tag, &ok);
if (ok)
*data = (short)tmp;
+ return ok;
}
-void ExtraTags::setData(std::string tag, int *data)
+
+bool ExtraTags::setData(std::string tag, int *data)
{
bool ok = false;
int tmp = asInt(tag, &ok);
if (ok)
*data = tmp;
+ return ok;
}
-void ExtraTags::setData(std::string tag, float *data)
+
+bool ExtraTags::setData(std::string tag, float *data)
{
bool ok = false;
float tmp = asFloat(tag, &ok);
if (ok)
*data = tmp;
+ return ok;
}
-void ExtraTags::setData(std::string tag, char *data)
+
+bool ExtraTags::setData(std::string tag, char *data)
{
bool ok = false;
int tmp = asInt(tag, &ok);
if (ok)
*data = (char)tmp;
+ return ok;
+}
+
+std::string ExtraTags::setData(std::string tag, std::string &data)
+{
+ bool ok = false;
+ std::string tmp = asString(tag, &ok);
+ return (ok) ? tmp : data;
}
-
diff --git a/source/blender/collada/ExtraTags.h b/source/blender/collada/ExtraTags.h
index 03a311a7e86..ad272dcba65 100644
--- a/source/blender/collada/ExtraTags.h
+++ b/source/blender/collada/ExtraTags.h
@@ -43,17 +43,18 @@ public:
bool addTag(std::string tag, std::string data);
/** Set given short pointer to value of tag, if it exists. */
- void setData(std::string tag, short *data);
+ bool setData(std::string tag, short *data);
/** Set given int pointer to value of tag, if it exists. */
- void setData(std::string tag, int *data);
+ bool setData(std::string tag, int *data);
/** Set given float pointer to value of tag, if it exists. */
- void setData(std::string tag, float *data);
+ bool setData(std::string tag, float *data);
/** Set given char pointer to value of tag, if it exists. */
- void setData(std::string tag, char *data);
-
+ 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);
diff --git a/source/blender/collada/ImportSettings.h b/source/blender/collada/ImportSettings.h
index 783f58e6bff..2c52d73e756 100644
--- a/source/blender/collada/ImportSettings.h
+++ b/source/blender/collada/ImportSettings.h
@@ -33,6 +33,7 @@ struct ImportSettings {
public:
bool import_units;
bool find_chains;
+ bool auto_connect;
bool fix_orientation;
int min_chain_length;
char *filepath;
diff --git a/source/blender/collada/MeshImporter.cpp b/source/blender/collada/MeshImporter.cpp
index a884268fd5e..3adddddb8e7 100644
--- a/source/blender/collada/MeshImporter.cpp
+++ b/source/blender/collada/MeshImporter.cpp
@@ -211,15 +211,27 @@ void VCOLDataWrapper::get_vcol(int v_index, MLoopCol *mloopcol)
MeshImporter::MeshImporter(UnitConverter *unitconv, ArmatureImporter *arm, Scene *sce) : unitconverter(unitconv), scene(sce), armature_importer(arm) {
}
-void MeshImporter::set_poly_indices(MPoly *mpoly, MLoop *mloop, int loop_index, unsigned int *indices, int loop_count)
+bool MeshImporter::set_poly_indices(MPoly *mpoly, MLoop *mloop, int loop_index, unsigned int *indices, int loop_count)
{
mpoly->loopstart = loop_index;
mpoly->totloop = loop_count;
-
+ bool broken_loop = false;
for (int index=0; index < loop_count; index++) {
+
+ /* Test if loop defines a hole */
+ if (!broken_loop) {
+ for (int i = 0; i < index; i++) {
+ if (indices[i] == indices[index]) {
+ // duplicate index -> not good
+ broken_loop = true;
+ }
+ }
+ }
+
mloop->v = indices[index];
mloop++;
}
+ return broken_loop;
}
void MeshImporter::set_vcol(MLoopCol *mlc, VCOLDataWrapper &vob, int loop_index, COLLADAFW::IndexList &index_list, int count)
@@ -259,7 +271,8 @@ bool MeshImporter::is_nice_mesh(COLLADAFW::Mesh *mesh) // checks if mesh has su
COLLADAFW::MeshPrimitiveArray& prim_arr = mesh->getMeshPrimitives();
const std::string &name = bc_get_dae_name(mesh);
-
+ int hole_count = 0;
+
for (unsigned i = 0; i < prim_arr.getCount(); i++) {
COLLADAFW::MeshPrimitive *mp = prim_arr[i];
@@ -275,13 +288,21 @@ bool MeshImporter::is_nice_mesh(COLLADAFW::Mesh *mesh) // checks if mesh has su
for (unsigned int j = 0; j < vca.getCount(); j++) {
int count = vca[j];
- if (count < 3) {
- fprintf(stderr, "Primitive %s in %s has at least one face with vertex count < 3\n",
+ if (abs(count) < 3) {
+ fprintf(stderr, "ERROR: Primitive %s in %s has at least one face with vertex count < 3\n",
type_str, name.c_str());
return false;
}
+ if (count < 0)
+ {
+ hole_count ++;
+ }
+ }
+
+ if (hole_count > 0)
+ {
+ fprintf(stderr, "WARNING: Primitive %s in %s: %d holes not imported (unsupported)\n", type_str, name.c_str(), hole_count);
}
-
}
else if (type == COLLADAFW::MeshPrimitive::LINES) {
@@ -289,13 +310,13 @@ bool MeshImporter::is_nice_mesh(COLLADAFW::Mesh *mesh) // checks if mesh has su
}
else if (type != COLLADAFW::MeshPrimitive::TRIANGLES && type != COLLADAFW::MeshPrimitive::TRIANGLE_FANS) {
- fprintf(stderr, "Primitive type %s is not supported.\n", type_str);
+ fprintf(stderr, "ERROR: Primitive type %s is not supported.\n", type_str);
return false;
}
}
if (mesh->getPositions().empty()) {
- fprintf(stderr, "Mesh %s has no vertices.\n", name.c_str());
+ fprintf(stderr, "ERROR: Mesh %s has no vertices.\n", name.c_str());
return false;
}
@@ -409,11 +430,18 @@ 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++) {
- prim_loop_count += get_vertex_count(mpvc, index);
+ for (int index=0; index < prim_poly_count; index++)
+ {
+ int vcount = get_vertex_count(mpvc, index);
+ if (vcount > 0) {
+ prim_loop_count += vcount;
+ total_poly_count++;
+ }
+ else {
+ // TODO: this is a hole and not another polygon!
+ }
}
- total_poly_count += prim_poly_count;
total_loop_count += prim_loop_count;
break;
@@ -682,12 +710,20 @@ void MeshImporter::read_polys(COLLADAFW::Mesh *collada_mesh, Mesh *me)
COLLADAFW::IndexListArray& index_list_array_uvcoord = mp->getUVCoordIndicesArray();
COLLADAFW::IndexListArray& index_list_array_vcolor = mp->getColorIndicesArray();
+ int invalid_loop_holes = 0;
for (unsigned int j = 0; j < prim_totpoly; j++) {
-
+
// Vertices in polygon:
int vcount = get_vertex_count(mpvc, j);
- set_poly_indices(mpoly, mloop, loop_index, position_indices, vcount);
+ if (vcount < 0) {
+ continue; // TODO: add support for holes
+ }
+ bool broken_loop = set_poly_indices(mpoly, mloop, loop_index, position_indices, vcount);
+ if (broken_loop)
+ {
+ invalid_loop_holes += 1;
+ }
for (unsigned int uvset_index = 0; uvset_index < index_list_array_uvcoord.getCount(); uvset_index++) {
// get mtface by face index and uv set index
@@ -735,6 +771,11 @@ void MeshImporter::read_polys(COLLADAFW::Mesh *collada_mesh, Mesh *me)
position_indices += vcount;
}
+
+ if (invalid_loop_holes > 0)
+ {
+ fprintf(stderr, "Collada import: Mesh [%s] : contains %d unsupported loops (holes).\n", me->id.name, invalid_loop_holes);
+ }
}
else if (collada_meshtype == COLLADAFW::MeshPrimitive::LINES) {
diff --git a/source/blender/collada/MeshImporter.h b/source/blender/collada/MeshImporter.h
index 9d5fefb83f2..d6426fbaf56 100644
--- a/source/blender/collada/MeshImporter.h
+++ b/source/blender/collada/MeshImporter.h
@@ -109,7 +109,7 @@ private:
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
- void set_poly_indices(MPoly *mpoly,
+ bool set_poly_indices(MPoly *mpoly,
MLoop *mloop,
int loop_index,
unsigned int *indices,
diff --git a/source/blender/collada/SkinInfo.cpp b/source/blender/collada/SkinInfo.cpp
index 71875d6274a..7242a24523c 100644
--- a/source/blender/collada/SkinInfo.cpp
+++ b/source/blender/collada/SkinInfo.cpp
@@ -230,6 +230,7 @@ void SkinInfo::link_armature(bContext *C, Object *ob, std::map<COLLADAFW::Unique
ModifierData *md = ED_object_modifier_add(NULL, bmain, scene, ob, NULL, eModifierType_Armature);
ArmatureModifierData *amd = (ArmatureModifierData *)md;
amd->object = ob_arm;
+ struct bArmature *armature = (bArmature *)ob_arm->data;
#if 1
bc_set_parent(ob, ob_arm, C);
diff --git a/source/blender/collada/collada.cpp b/source/blender/collada/collada.cpp
index b64b10e0833..fe8b1d2320a 100644
--- a/source/blender/collada/collada.cpp
+++ b/source/blender/collada/collada.cpp
@@ -46,6 +46,7 @@ int collada_import(bContext *C,
const char *filepath,
int import_units,
int find_chains,
+ int auto_connect,
int fix_orientation,
int min_chain_length)
{
@@ -53,6 +54,7 @@ int collada_import(bContext *C,
ImportSettings import_settings;
import_settings.filepath = (char *)filepath;
import_settings.import_units = import_units != 0;
+ import_settings.auto_connect = auto_connect != 0;
import_settings.find_chains = find_chains != 0;
import_settings.fix_orientation = fix_orientation != 0;
import_settings.min_chain_length = min_chain_length;
@@ -81,8 +83,9 @@ int collada_export(Scene *sce,
int use_texture_copies,
int triangulate,
- int use_object_instantiation,
- int sort_by_name,
+ int use_object_instantiation,
+ int use_blender_profile,
+ int sort_by_name,
BC_export_transformation_type export_transformation_type,
int open_sim)
{
@@ -105,6 +108,7 @@ int collada_export(Scene *sce,
export_settings.triangulate = triangulate != 0;
export_settings.use_object_instantiation = use_object_instantiation != 0;
+ export_settings.use_blender_profile = use_blender_profile != 0;
export_settings.sort_by_name = sort_by_name != 0;
export_settings.export_transformation_type = export_transformation_type;
export_settings.open_sim = open_sim != 0;
diff --git a/source/blender/collada/collada.h b/source/blender/collada/collada.h
index 6819a62fdf0..0017c66836a 100644
--- a/source/blender/collada/collada.h
+++ b/source/blender/collada/collada.h
@@ -57,6 +57,7 @@ int collada_import(struct bContext *C,
const char *filepath,
int import_units,
int find_chains,
+ int auto_connect,
int fix_orientation,
int min_chain_length);
@@ -78,6 +79,7 @@ int collada_export(struct Scene *sce,
int triangulate,
int use_object_instantiation,
+ int use_blender_profile,
int sort_by_name,
BC_export_transformation_type export_transformation_type,
int open_sim);
diff --git a/source/blender/collada/collada_utils.cpp b/source/blender/collada/collada_utils.cpp
index f8feed8145c..f0984fbc127 100644
--- a/source/blender/collada/collada_utils.cpp
+++ b/source/blender/collada/collada_utils.cpp
@@ -54,6 +54,8 @@ extern "C" {
#include "BKE_scene.h"
#include "BKE_DerivedMesh.h"
+#include "ED_armature.h"
+
#include "WM_api.h" // XXX hrm, see if we can do without this
#include "WM_types.h"
@@ -366,3 +368,212 @@ void bc_triangulate_mesh(Mesh *me)
BM_mesh_bm_to_me(bm, me, &bm_to_me_params);
BM_mesh_free(bm);
}
+
+/*
+* A bone is a leaf when it has no children or all children are not connected.
+*/
+bool bc_is_leaf_bone(Bone *bone)
+{
+ for (Bone *child = (Bone *)bone->childbase.first; child; child = child->next) {
+ if (child->flag & BONE_CONNECTED)
+ return false;
+ }
+ return true;
+}
+
+EditBone *bc_get_edit_bone(bArmature * armature, char *name) {
+ EditBone *eBone;
+
+ for (eBone = (EditBone *)armature->edbo->first; eBone; eBone = eBone->next) {
+ if (STREQ(name, eBone->name))
+ return eBone;
+ }
+
+ return NULL;
+
+}
+int bc_set_layer(int bitfield, int layer)
+{
+ return bc_set_layer(bitfield, layer, true); /* enable */
+}
+
+int bc_set_layer(int bitfield, int layer, bool enable)
+{
+ int bit = 1u << layer;
+
+ if (enable)
+ bitfield |= bit;
+ else
+ bitfield &= ~bit;
+
+ return bitfield;
+}
+
+/**
+* BoneExtended is a helper class needed for the Bone chain finder
+* See ArmatureImporter::fix_leaf_bones()
+* and ArmatureImporter::connect_bone_chains()
+**/
+
+BoneExtended::BoneExtended(EditBone *aBone)
+{
+ this->set_name(aBone->name);
+ this->chain_length = 0;
+ this->is_leaf = false;
+ this->tail[0] = 0.0f;
+ this->tail[1] = 0.5f;
+ this->tail[2] = 0.0f;
+ this->use_connect = -1;
+ this->roll = 0;
+ this->bone_layers = 0;
+
+ this->has_custom_tail = false;
+ this->has_custom_roll = false;
+}
+
+char *BoneExtended::get_name()
+{
+ return name;
+}
+
+void BoneExtended::set_name(char *aName)
+{
+ BLI_strncpy(name, aName, MAXBONENAME);
+}
+
+int BoneExtended::get_chain_length()
+{
+ return chain_length;
+}
+
+void BoneExtended::set_chain_length(const int aLength)
+{
+ chain_length = aLength;
+}
+
+void BoneExtended::set_leaf_bone(bool state)
+{
+ is_leaf = state;
+}
+
+bool BoneExtended::is_leaf_bone()
+{
+ return is_leaf;
+}
+
+void BoneExtended::set_roll(float roll)
+{
+ this->roll = roll;
+ this->has_custom_roll = true;
+}
+
+bool BoneExtended::has_roll()
+{
+ return this->has_custom_roll;
+}
+
+float BoneExtended::get_roll()
+{
+ return this->roll;
+}
+
+void BoneExtended::set_tail(float vec[])
+{
+ this->tail[0] = vec[0];
+ this->tail[1] = vec[1];
+ this->tail[2] = vec[2];
+ this->has_custom_tail = true;
+}
+
+bool BoneExtended::has_tail()
+{
+ return this->has_custom_tail;
+}
+
+float *BoneExtended::get_tail()
+{
+ return this->tail;
+}
+
+inline bool isInteger(const std::string & s)
+{
+ if (s.empty() || ((!isdigit(s[0])) && (s[0] != '-') && (s[0] != '+'))) return false;
+
+ char * p;
+ strtol(s.c_str(), &p, 10);
+
+ return (*p == 0);
+}
+
+void BoneExtended::set_bone_layers(std::string layerString, std::vector<std::string> &layer_labels)
+{
+ std::stringstream ss(layerString);
+ std::string layer;
+ int pos;
+
+ while (ss >> layer) {
+
+ /* Blender uses numbers to specify layers*/
+ if (isInteger(layer))
+ {
+ pos = atoi(layer.c_str());
+ if (pos >= 0 && pos < 32) {
+ this->bone_layers = bc_set_layer(this->bone_layers, pos);
+ continue;
+ }
+ }
+
+ /* layer uses labels (not supported by blender). Map to layer numbers:*/
+ pos = find(layer_labels.begin(), layer_labels.end(), layer) - layer_labels.begin();
+ if (pos >= layer_labels.size()) {
+ layer_labels.push_back(layer); /* remember layer number for future usage*/
+ }
+
+ if (pos > 31)
+ {
+ fprintf(stderr, "Too many layers in Import. Layer %s mapped to Blender layer 31\n", layer.c_str());
+ pos = 31;
+ }
+
+ /* If numeric layers and labeled layers are used in parallel (unlikely),
+ we get a potential mixup. Just leave as is for now.
+ */
+ this->bone_layers = bc_set_layer(this->bone_layers, pos);
+
+ }
+}
+
+std::string BoneExtended::get_bone_layers(int bitfield)
+{
+ std::string result = "";
+ std::string sep = "";
+ int bit = 1u;
+
+ std::ostringstream ss;
+ for (int i = 0; i < 32; i++)
+ {
+ if (bit & bitfield)
+ {
+ ss << sep << i;
+ sep = " ";
+ }
+ bit = bit << 1;
+ }
+ return ss.str();
+}
+
+int BoneExtended::get_bone_layers()
+{
+ return (bone_layers == 0) ? 1 : bone_layers; // ensure that the bone is in at least one bone layer!
+}
+
+
+void BoneExtended::set_use_connect(int use_connect)
+{
+ this->use_connect = use_connect;
+}
+
+int BoneExtended::get_use_connect()
+{
+ return this->use_connect;
+}
diff --git a/source/blender/collada/collada_utils.h b/source/blender/collada/collada_utils.h
index 4bc2f55cf33..ee371f7959e 100644
--- a/source/blender/collada/collada_utils.h
+++ b/source/blender/collada/collada_utils.h
@@ -34,6 +34,7 @@
#include <vector>
#include <map>
+#include <algorithm>
extern "C" {
#include "DNA_object_types.h"
@@ -46,6 +47,7 @@ extern "C" {
#include "BLI_linklist.h"
#include "BLI_utildefines.h"
+#include "BLI_string.h"
#include "BKE_context.h"
#include "BKE_object.h"
@@ -87,7 +89,10 @@ extern void bc_match_scale(Object *ob, UnitConverter &bc_unit, bool scale_to_sce
extern void bc_match_scale(std::vector<Object *> *objects_done, UnitConverter &unit_converter, bool scale_to_scene);
extern void bc_triangulate_mesh(Mesh *me);
-
+extern bool bc_is_leaf_bone(Bone *bone);
+extern EditBone *bc_get_edit_bone(bArmature * armature, char *name);
+extern int bc_set_layer(int bitfield, int layer, bool enable);
+extern int bc_set_layer(int bitfield, int layer);
class BCPolygonNormalsIndices
{
@@ -105,4 +110,48 @@ class BCPolygonNormalsIndices
};
+class BoneExtended {
+
+private:
+ char name[MAXBONENAME];
+ int chain_length;
+ bool is_leaf;
+ float tail[3];
+ float roll;
+
+ int bone_layers;
+ int use_connect;
+ bool has_custom_tail;
+ bool has_custom_roll;
+
+public:
+
+ BoneExtended(EditBone *aBone);
+
+ void set_name(char *aName);
+ char *get_name();
+
+ void set_chain_length(const int aLength);
+ int get_chain_length();
+
+ void set_leaf_bone(bool state);
+ bool is_leaf_bone();
+
+ void set_bone_layers(std::string layers, std::vector<std::string> &layer_labels);
+ int get_bone_layers();
+ static std::string get_bone_layers(int bitfield);
+
+ void set_roll(float roll);
+ bool has_roll();
+ float get_roll();
+
+ void set_tail(float *vec);
+ float *get_tail();
+ bool has_tail();
+
+ void set_use_connect(int use_connect);
+ int get_use_connect();
+};
+
+
#endif
diff --git a/source/blender/compositor/operations/COM_ImageOperation.cpp b/source/blender/compositor/operations/COM_ImageOperation.cpp
index 624378f2ae9..7d59358831c 100644
--- a/source/blender/compositor/operations/COM_ImageOperation.cpp
+++ b/source/blender/compositor/operations/COM_ImageOperation.cpp
@@ -160,10 +160,10 @@ static void sampleImageAtLocation(ImBuf *ibuf, float x, float y, PixelSampler sa
void ImageOperation::executePixelSampled(float output[4], float x, float y, PixelSampler sampler)
{
int ix = x, iy = y;
- if (ix < 0 || iy < 0 || ix >= this->m_buffer->x || iy >= this->m_buffer->y) {
+ if (this->m_imageFloatBuffer == NULL && this->m_imageByteBuffer == NULL) {
zero_v4(output);
}
- else if (this->m_imageFloatBuffer == NULL && this->m_imageByteBuffer == NULL) {
+ else if (ix < 0 || iy < 0 || ix >= this->m_buffer->x || iy >= this->m_buffer->y) {
zero_v4(output);
}
else {
diff --git a/source/blender/depsgraph/CMakeLists.txt b/source/blender/depsgraph/CMakeLists.txt
index 2b4df85f29c..fd2a521bec5 100644
--- a/source/blender/depsgraph/CMakeLists.txt
+++ b/source/blender/depsgraph/CMakeLists.txt
@@ -25,8 +25,6 @@
set(INC
.
- intern
- util
../blenkernel
../blenlib
../bmesh
@@ -42,45 +40,50 @@ set(INC_SYS
)
set(SRC
+ intern/builder/deg_builder.cc
+ intern/builder/deg_builder_cycle.cc
+ intern/builder/deg_builder_nodes.cc
+ intern/builder/deg_builder_pchanmap.cc
+ intern/builder/deg_builder_relations.cc
+ intern/builder/deg_builder_transitive.cc
+ intern/debug/deg_debug_graphviz.cc
+ intern/eval/deg_eval.cc
+ intern/eval/deg_eval_debug.cc
+ intern/eval/deg_eval_flush.cc
+ intern/nodes/deg_node.cc
+ intern/nodes/deg_node_component.cc
+ intern/nodes/deg_node_operation.cc
intern/depsgraph.cc
- intern/depsnode.cc
- intern/depsnode_component.cc
- intern/depsnode_operation.cc
intern/depsgraph_build.cc
- intern/depsgraph_build_nodes.cc
- intern/depsgraph_build_relations.cc
intern/depsgraph_debug.cc
intern/depsgraph_eval.cc
intern/depsgraph_query.cc
- intern/depsgraph_queue.cc
intern/depsgraph_tag.cc
intern/depsgraph_type_defines.cc
- util/depsgraph_util_cycle.cc
- util/depsgraph_util_pchanmap.cc
- util/depsgraph_util_transitive.cc
DEG_depsgraph.h
DEG_depsgraph_build.h
DEG_depsgraph_debug.h
DEG_depsgraph_query.h
+
+ intern/builder/deg_builder.h
+ intern/builder/deg_builder_cycle.h
+ intern/builder/deg_builder_nodes.h
+ intern/builder/deg_builder_pchanmap.h
+ intern/builder/deg_builder_relations.h
+ intern/builder/deg_builder_transitive.h
+ intern/eval/deg_eval.h
+ intern/eval/deg_eval_debug.h
+ intern/eval/deg_eval_flush.h
+ intern/nodes/deg_node.h
+ intern/nodes/deg_node_component.h
+ intern/nodes/deg_node_operation.h
intern/depsgraph.h
- intern/depsnode.h
- intern/depsnode_component.h
- intern/depsnode_operation.h
- intern/depsnode_opcodes.h
- intern/depsgraph_build.h
- intern/depsgraph_debug.h
intern/depsgraph_intern.h
- intern/depsgraph_queue.h
intern/depsgraph_types.h
- util/depsgraph_util_cycle.h
- util/depsgraph_util_function.h
- util/depsgraph_util_hash.h
- util/depsgraph_util_map.h
- util/depsgraph_util_pchanmap.h
- util/depsgraph_util_set.h
- util/depsgraph_util_transitive.h
+ util/deg_util_function.h
+ util/deg_util_hash.h
)
if(WITH_CXX11)
diff --git a/source/blender/depsgraph/DEG_depsgraph.h b/source/blender/depsgraph/DEG_depsgraph.h
index f37ba71ab65..d1de83ec8a9 100644
--- a/source/blender/depsgraph/DEG_depsgraph.h
+++ b/source/blender/depsgraph/DEG_depsgraph.h
@@ -131,9 +131,6 @@ void DEG_ids_clear_recalc(struct Main *bmain);
/* Update Flushing ------------------------------- */
-/* Flush updates */
-void DEG_graph_flush_updates(struct Main *bmain, Depsgraph *graph);
-
/* Flush updates for all IDs */
void DEG_ids_flush_tagged(struct Main *bmain);
@@ -144,11 +141,6 @@ void DEG_ids_check_recalc(struct Main *bmain,
struct Scene *scene,
bool time);
-/* Clear all update tags
- * - For aborted updates, or after successful evaluation
- */
-void DEG_graph_clear_tags(Depsgraph *graph);
-
/* ************************************************ */
/* Evaluation Engine API */
diff --git a/source/blender/depsgraph/DEG_depsgraph_build.h b/source/blender/depsgraph/DEG_depsgraph_build.h
index f680c47247a..49b648c7dae 100644
--- a/source/blender/depsgraph/DEG_depsgraph_build.h
+++ b/source/blender/depsgraph/DEG_depsgraph_build.h
@@ -43,9 +43,6 @@ struct Depsgraph;
struct Main;
struct Scene;
-struct PointerRNA;
-struct PropertyRNA;
-
#ifdef __cplusplus
extern "C" {
#endif
diff --git a/source/blender/depsgraph/DEG_depsgraph_debug.h b/source/blender/depsgraph/DEG_depsgraph_debug.h
index 374fad63c34..0d19b8e1e97 100644
--- a/source/blender/depsgraph/DEG_depsgraph_debug.h
+++ b/source/blender/depsgraph/DEG_depsgraph_debug.h
@@ -39,13 +39,10 @@
extern "C" {
#endif
-struct DepsgraphSettings;
struct GHash;
struct ID;
struct Depsgraph;
-struct DepsNode;
-struct DepsRelation;
/* ************************************************ */
/* Statistics */
diff --git a/source/blender/depsgraph/DEG_depsgraph_query.h b/source/blender/depsgraph/DEG_depsgraph_query.h
index 60d673d4c5b..ccd204a2083 100644
--- a/source/blender/depsgraph/DEG_depsgraph_query.h
+++ b/source/blender/depsgraph/DEG_depsgraph_query.h
@@ -19,7 +19,7 @@
* All rights reserved.
*
* Original Author: Joshua Leung
- * Contributor(s): None Yet
+ * Contributor(s): Sergey Sharybin
*
* ***** END GPL LICENSE BLOCK *****
*/
@@ -33,155 +33,14 @@
#ifndef __DEG_DEPSGRAPH_QUERY_H__
#define __DEG_DEPSGRAPH_QUERY_H__
-struct ListBase;
struct ID;
struct Depsgraph;
-struct DepsNode;
-struct DepsRelation;
#ifdef __cplusplus
extern "C" {
#endif
-/* ************************************************ */
-/* Type Defines */
-
-/* FilterPredicate Callback
- *
- * Defines a callback function which can be supplied to check whether a
- * node is relevant or not.
- *
- * < graph: Depsgraph that we're traversing
- * < node: The node to check
- * < userdata: FilterPredicate state data (as needed)
- * > returns: True if node is relevant
- */
-typedef bool (*DEG_FilterPredicate)(const struct Depsgraph *graph, const struct DepsNode *node, void *userdata);
-
-
-/* Node Operation
- *
- * Performs some action on the given node, provided that the node was
- * deemed to be relevant to operate on.
- *
- * < graph: Depsgraph that we're traversing
- * < node: The node to perform operation on/with
- * < userdata: Node Operation's state data (as needed)
- * > returns: True if traversal should be aborted at this point
- */
-typedef bool (*DEG_NodeOperation)(const struct Depsgraph *graph, struct DepsNode *node, void *userdata);
-
-/* ************************************************ */
-/* Low-Level Filtering API */
-
-/* Create a filtered copy of the given graph which contains only the
- * nodes which fulfill the criteria specified using the FilterPredicate
- * passed in.
- *
- * < graph: The graph to be copied and filtered
- * < filter: FilterPredicate used to check which nodes should be included
- * (If null, full graph is copied as-is)
- * < userdata: State data for filter (as necessary)
- *
- * > returns: a full copy of all the relevant nodes - the matching subgraph
- */
-// XXX: is there any need for extra settings/options for how the filtering goes?
-Depsgraph *DEG_graph_filter(const struct Depsgraph *graph, DEG_FilterPredicate *filter, void *userdata);
-
-
-/* Traverse nodes in graph which are deemed relevant,
- * performing the provided operation on the nodes.
- *
- * < graph: The graph to perform operations on
- * < filter: FilterPredicate used to check which nodes should be included
- * (If null, all nodes are considered valid targets)
- * < filter_data: Custom state data for FilterPredicate
- * (Note: This can be the same as op_data, where appropriate)
- * < op: NodeOperation to perform on each node
- * (If null, no graph traversal is performed for efficiency)
- * < op_data: Custom state data for NodeOperation
- * (Note: This can be the same as filter_data, where appropriate)
- */
-void DEG_graph_traverse(const struct Depsgraph *graph,
- DEG_FilterPredicate *filter, void *filter_data,
- DEG_NodeOperation *op, void *op_data);
-
-/* ************************************************ */
-/* Node-Based Operations */
-// XXX: do we want to be able to attach conditional requirements here?
-
-/* Find an (outer) node matching given conditions
- * ! Assumes that there will only be one such node, or that only the first one matters
- *
- * < graph: a dependency graph which may or may not contain a node matching these requirements
- * < query: query conditions for the criteria that the node must satisfy
- */
-//DepsNode *DEG_node_find(const Depsgraph *graph, DEG_QueryConditions *query);
-
-/* Topology Queries (Direct) ---------------------- */
-
-/* Get list of nodes which directly depend on given node
- *
- * > result: list to write results to
- * < node: the node to find the children/dependents of
- */
-void DEG_node_get_children(struct ListBase *result, const struct DepsNode *node);
-
-
-/* Get list of nodes which given node directly depends on
- *
- * > result: list to write results to
- * < node: the node to find the dependencies of
- */
-void DEG_node_get_dependencies(struct ListBase *result, const struct DepsNode *node);
-
-
-/* Topology Queries (Subgraph) -------------------- */
-// XXX: given that subgraphs potentially involve many interconnected nodes, we currently
-// just spit out a copy of the subgraph which matches. This works well for the cases
-// where these are used - mostly for efficient updating of subsets of the nodes.
-
-// XXX: allow supplying a filter predicate to provide further filtering/pruning?
-
-
-/* Get all descendants of a node
- *
- * That is, get the subgraph / subset of nodes which are dependent
- * on the results of the given node.
- */
-Depsgraph *DEG_node_get_descendants(const struct Depsgraph *graph, const struct DepsNode *node);
-
-
-/* Get all ancestors of a node
- *
- * That is, get the subgraph / subset of nodes which the given node
- * is dependent on in order to be evaluated.
- */
-Depsgraph *DEG_node_get_ancestors(const struct Depsgraph *graph, const struct DepsNode *node);
-
-/* ************************************************ */
-/* Higher-Level Queries */
-
-/* Get ID-blocks which would be affected if specified ID is modified
- * < only_direct: True = Only ID-blocks with direct relationships to ID-block will be returned
- *
- * > result: (LinkData : ID) a list of ID-blocks matching the specified criteria
- * > returns: number of matching ID-blocks
- */
-size_t DEG_query_affected_ids(struct ListBase *result, const struct ID *id, const bool only_direct);
-
-
-/* Get ID-blocks which are needed to update/evaluate specified ID
- * < only_direct: True = Only ID-blocks with direct relationships to ID-block will be returned
- *
- * > result: (LinkData : ID) a list of ID-blocks matching the specified criteria
- * > returns: number of matching ID-blocks
- */
-size_t DEG_query_required_ids(struct ListBase *result, const struct ID *id, const bool only_direct);
-
-/* ************************************************ */
-
/* Check if given ID type was tagged for update. */
bool DEG_id_type_tagged(struct Main *bmain, short idtype);
diff --git a/source/blender/depsgraph/intern/builder/deg_builder.cc b/source/blender/depsgraph/intern/builder/deg_builder.cc
new file mode 100644
index 00000000000..9f80c21a6a4
--- /dev/null
+++ b/source/blender/depsgraph/intern/builder/deg_builder.cc
@@ -0,0 +1,129 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2016 Blender Foundation.
+ * All rights reserved.
+ *
+ * Original Author: Sergey Sharybin
+ * Contributor(s): None Yet
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/depsgraph/intern/build/deg_builder.cc
+ * \ingroup depsgraph
+ */
+
+#include "intern/builder/deg_builder.h"
+
+// TODO(sergey): Use own wrapper over STD.
+#include <stack>
+
+#include "DNA_anim_types.h"
+
+#include "BLI_utildefines.h"
+#include "BLI_ghash.h"
+
+#include "intern/depsgraph.h"
+#include "intern/depsgraph_types.h"
+#include "intern/nodes/deg_node.h"
+#include "intern/nodes/deg_node_component.h"
+#include "intern/nodes/deg_node_operation.h"
+
+#include "util/deg_util_foreach.h"
+
+namespace DEG {
+
+string deg_fcurve_id_name(const FCurve *fcu)
+{
+ char index_buf[32];
+ // TODO(sergey): Use int-to-string utility or so.
+ BLI_snprintf(index_buf, sizeof(index_buf), "[%d]", fcu->array_index);
+ return string(fcu->rna_path) + index_buf;
+}
+
+void deg_graph_build_finalize(Depsgraph *graph)
+{
+ std::stack<OperationDepsNode *> stack;
+
+ foreach (OperationDepsNode *node, graph->operations) {
+ IDDepsNode *id_node = node->owner->owner;
+ node->done = 0;
+ node->num_links_pending = 0;
+ foreach (DepsRelation *rel, node->outlinks) {
+ if ((rel->from->type == DEPSNODE_TYPE_OPERATION) &&
+ (rel->flag & DEPSREL_FLAG_CYCLIC) == 0)
+ {
+ ++node->num_links_pending;
+ }
+ }
+ if (node->num_links_pending == 0) {
+ stack.push(node);
+ node->done = 1;
+ }
+ node->owner->layers = id_node->layers;
+ id_node->id->tag |= LIB_TAG_DOIT;
+ }
+
+ while (!stack.empty()) {
+ OperationDepsNode *node = stack.top();
+ stack.pop();
+ /* Flush layers to parents. */
+ foreach (DepsRelation *rel, node->inlinks) {
+ if (rel->from->type == DEPSNODE_TYPE_OPERATION) {
+ OperationDepsNode *from = (OperationDepsNode *)rel->from;
+ from->owner->layers |= node->owner->layers;
+ }
+ }
+ /* Schedule parent nodes. */
+ foreach (DepsRelation *rel, node->inlinks) {
+ if (rel->from->type == DEPSNODE_TYPE_OPERATION) {
+ OperationDepsNode *from = (OperationDepsNode *)rel->from;
+ if ((rel->flag & DEPSREL_FLAG_CYCLIC) == 0) {
+ BLI_assert(from->num_links_pending > 0);
+ --from->num_links_pending;
+ }
+ if (from->num_links_pending == 0 && from->done == 0) {
+ stack.push(from);
+ from->done = 1;
+ }
+ }
+ }
+ }
+
+ /* Re-tag IDs for update if it was tagged before the relations update tag. */
+ GHASH_FOREACH_BEGIN(IDDepsNode *, id_node, graph->id_hash)
+ {
+ GHASH_FOREACH_BEGIN(ComponentDepsNode *, comp, id_node->components)
+ {
+ id_node->layers |= comp->layers;
+ }
+ GHASH_FOREACH_END();
+
+ ID *id = id_node->id;
+ if (id->tag & LIB_TAG_ID_RECALC_ALL &&
+ id->tag & LIB_TAG_DOIT)
+ {
+ id_node->tag_update(graph);
+ id->tag &= ~LIB_TAG_DOIT;
+ }
+ id_node->finalize_build();
+ }
+ GHASH_FOREACH_END();
+}
+
+} // namespace DEG
diff --git a/source/blender/depsgraph/intern/builder/deg_builder.h b/source/blender/depsgraph/intern/builder/deg_builder.h
new file mode 100644
index 00000000000..7ecb4b20684
--- /dev/null
+++ b/source/blender/depsgraph/intern/builder/deg_builder.h
@@ -0,0 +1,46 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2016 Blender Foundation.
+ * All rights reserved.
+ *
+ * Original Author: Sergey Sharybin
+ * Contributor(s): None Yet
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/depsgraph/intern/build/deg_builder.h
+ * \ingroup depsgraph
+ */
+
+#pragma once
+
+#include "intern/depsgraph_types.h"
+
+struct FCurve;
+
+namespace DEG {
+
+struct Depsgraph;
+
+/* Get unique identifier for FCurves and Drivers */
+string deg_fcurve_id_name(const FCurve *fcu);
+
+void deg_graph_build_finalize(struct Depsgraph *graph);
+
+} // namespace DEG
diff --git a/source/blender/depsgraph/util/depsgraph_util_cycle.cc b/source/blender/depsgraph/intern/builder/deg_builder_cycle.cc
index 5eae8c087ad..225cc64ae4d 100644
--- a/source/blender/depsgraph/util/depsgraph_util_cycle.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder_cycle.cc
@@ -23,28 +23,30 @@
* ***** END GPL LICENSE BLOCK *****
*/
-/** \file blender/depsgraph/util/depsgraph_util_cycle.cc
+/** \file blender/depsgraph/intern/builder/deg_builder_cycle.cc
* \ingroup depsgraph
*/
+#include "intern/builder/deg_builder_cycle.h"
+
+// TOO(sergey): Use some wrappers over those?
#include <cstdio>
#include <cstdlib>
#include <stack>
extern "C" {
#include "BLI_utildefines.h"
+}
-#include "DNA_ID.h"
+#include "util/deg_util_foreach.h"
-#include "RNA_access.h"
-#include "RNA_types.h"
-}
+#include "intern/nodes/deg_node.h"
+#include "intern/nodes/deg_node_component.h"
+#include "intern/nodes/deg_node_operation.h"
-#include "depsgraph_util_cycle.h"
-#include "depsgraph.h"
-#include "depsnode.h"
-#include "depsnode_component.h"
-#include "depsnode_operation.h"
+#include "intern/depsgraph.h"
+
+namespace DEG {
struct StackEntry {
OperationDepsNode *node;
@@ -62,17 +64,9 @@ void deg_graph_detect_cycles(Depsgraph *graph)
const int NODE_IN_STACK = 2;
std::stack<StackEntry> traversal_stack;
- for (Depsgraph::OperationNodes::const_iterator it_op = graph->operations.begin();
- it_op != graph->operations.end();
- ++it_op)
- {
- OperationDepsNode *node = *it_op;
+ foreach (OperationDepsNode *node, graph->operations) {
bool has_inlinks = false;
- for (OperationDepsNode::Relations::const_iterator it_rel = node->inlinks.begin();
- it_rel != node->inlinks.end();
- ++it_rel)
- {
- DepsRelation *rel = *it_rel;
+ foreach (DepsRelation *rel, node->inlinks) {
if (rel->from->type == DEPSNODE_TYPE_OPERATION) {
has_inlinks = true;
}
@@ -94,11 +88,7 @@ void deg_graph_detect_cycles(Depsgraph *graph)
StackEntry &entry = traversal_stack.top();
OperationDepsNode *node = entry.node;
bool all_child_traversed = true;
- for (OperationDepsNode::Relations::const_iterator it_rel = node->outlinks.begin();
- it_rel != node->outlinks.end();
- ++it_rel)
- {
- DepsRelation *rel = *it_rel;
+ foreach (DepsRelation *rel, node->outlinks) {
if (rel->to->type == DEPSNODE_TYPE_OPERATION) {
OperationDepsNode *to = (OperationDepsNode *)rel->to;
if (to->done == NODE_IN_STACK) {
@@ -138,3 +128,5 @@ void deg_graph_detect_cycles(Depsgraph *graph)
}
}
}
+
+} // namespace DEG
diff --git a/source/blender/depsgraph/util/depsgraph_util_cycle.h b/source/blender/depsgraph/intern/builder/deg_builder_cycle.h
index fac38b61057..386fbd80d19 100644
--- a/source/blender/depsgraph/util/depsgraph_util_cycle.h
+++ b/source/blender/depsgraph/intern/builder/deg_builder_cycle.h
@@ -23,15 +23,18 @@
* ***** END GPL LICENSE BLOCK *****
*/
-/** \file blender/depsgraph/util/depsgraph_util_cycle.h
+/** \file blender/depsgraph/intern/builder/deg_builder_cycle.h
* \ingroup depsgraph
*/
-#ifndef __DEPSGRAPH_UTIL_CYCLE_H__
-#define __DEPSGRAPH_UTIL_CYCLE_H__
+
+#pragma once
+
+namespace DEG {
struct Depsgraph;
+/* Detect and solve dependency cycles. */
void deg_graph_detect_cycles(Depsgraph *graph);
-#endif /* __DEPSGRAPH_UTIL_CYCLE_H__ */
+} // namespace DEG
diff --git a/source/blender/depsgraph/intern/depsgraph_build_nodes.cc b/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc
index be706ffb338..18cfdb3593a 100644
--- a/source/blender/depsgraph/intern/depsgraph_build_nodes.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc
@@ -24,12 +24,14 @@
* ***** END GPL LICENSE BLOCK *****
*/
-/** \file blender/depsgraph/intern/depsgraph_build_nodes.cc
+/** \file blender/depsgraph/intern/builder/deg_build_nodes.cc
* \ingroup depsgraph
*
* Methods for constructing depsgraph's nodes
*/
+#include "intern/builder/deg_builder_nodes.h"
+
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -97,12 +99,14 @@ extern "C" {
#include "RNA_types.h"
} /* extern "C" */
-#include "depsnode.h"
-#include "depsnode_component.h"
-#include "depsnode_operation.h"
-#include "depsgraph_types.h"
-#include "depsgraph_build.h"
-#include "depsgraph_intern.h"
+#include "intern/builder/deg_builder.h"
+#include "intern/nodes/deg_node.h"
+#include "intern/nodes/deg_node_component.h"
+#include "intern/nodes/deg_node_operation.h"
+#include "intern/depsgraph_types.h"
+#include "intern/depsgraph_intern.h"
+
+namespace DEG {
/* ************ */
/* Node Builder */
@@ -217,6 +221,17 @@ OperationDepsNode *DepsgraphNodeBuilder::add_operation_node(
return add_operation_node(comp_node, optype, op, opcode, description);
}
+OperationDepsNode *DepsgraphNodeBuilder::add_operation_node(
+ ID *id,
+ eDepsNode_Type comp_type,
+ eDepsOperation_Type optype,
+ DepsEvalOperationCb op,
+ eDepsOperation_Code opcode,
+ const string& description)
+{
+ return add_operation_node(id, comp_type, "", optype, op, opcode, description);
+}
+
bool DepsgraphNodeBuilder::has_operation_node(ID *id,
eDepsNode_Type comp_type,
const string &comp_name,
@@ -237,6 +252,14 @@ OperationDepsNode *DepsgraphNodeBuilder::find_operation_node(
return comp_node->has_operation(opcode, description);
}
+OperationDepsNode *DepsgraphNodeBuilder::find_operation_node(
+ ID *id,
+ eDepsNode_Type comp_type,
+ eDepsOperation_Code opcode,
+ const string& description)
+{
+ return find_operation_node(id, comp_type, "", opcode, description);
+}
/* **** Build functions for entity nodes **** */
@@ -273,16 +296,15 @@ void DepsgraphNodeBuilder::build_scene(Main *bmain, Scene *scene)
for (Base *base = (Base *)scene->base.first; base; base = base->next) {
Object *ob = base->object;
- /* object itself */
- build_object(scene, base, ob);
-
/* object that this is a proxy for */
// XXX: the way that proxies work needs to be completely reviewed!
if (ob->proxy) {
ob->proxy->proxy_from = ob;
- build_object(scene, base, ob->proxy);
}
+ /* object itself */
+ build_object(scene, base, ob);
+
/* Object dupligroup. */
if (ob->dup_group) {
build_group(scene, base, ob->dup_group);
@@ -343,7 +365,7 @@ SubgraphDepsNode *DepsgraphNodeBuilder::build_subgraph(Group *group)
return NULL;
/* create new subgraph's data */
- Depsgraph *subgraph = DEG_graph_new();
+ Depsgraph *subgraph = reinterpret_cast<Depsgraph *>(DEG_graph_new());
DepsgraphNodeBuilder subgraph_builder(m_bmain, subgraph);
@@ -381,11 +403,11 @@ void DepsgraphNodeBuilder::build_object(Scene *scene, Base *base, Object *ob)
IDDepsNode *id_node = add_id_node(&ob->id);
id_node->layers = base->lay;
+ ob->customdata_mask = 0;
/* standard components */
build_object_transform(scene, ob);
-
/* object data */
if (ob->data) {
/* type-specific data... */
@@ -463,6 +485,12 @@ void DepsgraphNodeBuilder::build_object(Scene *scene, Base *base, Object *ob)
if (ob->gpd) {
build_gpencil(ob->gpd);
}
+
+ if (ob->proxy != NULL) {
+ add_operation_node(&ob->id, DEPSNODE_TYPE_PROXY, DEPSOP_TYPE_POST,
+ function_bind(BKE_object_eval_proxy_backlink, _1, ob),
+ DEG_OPCODE_PLACEHOLDER, "Parameters Eval");
+ }
}
void DepsgraphNodeBuilder::build_object_transform(Scene *scene, Object *ob)
@@ -1234,3 +1262,5 @@ void DepsgraphNodeBuilder::build_gpencil(bGPdata *gpd)
*/
build_animdata(gpd_id);
}
+
+} // namespace DEG
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes.h b/source/blender/depsgraph/intern/builder/deg_builder_nodes.h
new file mode 100644
index 00000000000..6ee0b8406a1
--- /dev/null
+++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes.h
@@ -0,0 +1,153 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2013 Blender Foundation.
+ * All rights reserved.
+ *
+ * Original Author: Lukas Toenne
+ * Contributor(s): None Yet
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/depsgraph/intern/builder/deg_builder_nodes.h
+ * \ingroup depsgraph
+ */
+
+#pragma once
+
+#include "intern/depsgraph_types.h"
+
+struct Base;
+struct bGPdata;
+struct ListBase;
+struct GHash;
+struct ID;
+struct FCurve;
+struct Group;
+struct Key;
+struct Main;
+struct Material;
+struct MTex;
+struct bNodeTree;
+struct Object;
+struct bPoseChannel;
+struct bConstraint;
+struct Scene;
+struct Tex;
+struct World;
+
+struct PropertyRNA;
+
+namespace DEG {
+
+struct Depsgraph;
+struct DepsNode;
+struct RootDepsNode;
+struct SubgraphDepsNode;
+struct IDDepsNode;
+struct TimeSourceDepsNode;
+struct ComponentDepsNode;
+struct OperationDepsNode;
+
+struct DepsgraphNodeBuilder {
+ DepsgraphNodeBuilder(Main *bmain, Depsgraph *graph);
+ ~DepsgraphNodeBuilder();
+
+ RootDepsNode *add_root_node();
+ IDDepsNode *add_id_node(ID *id);
+ TimeSourceDepsNode *add_time_source(ID *id);
+
+ ComponentDepsNode *add_component_node(ID *id,
+ eDepsNode_Type comp_type,
+ const string& comp_name = "");
+
+ OperationDepsNode *add_operation_node(ComponentDepsNode *comp_node,
+ eDepsOperation_Type optype,
+ DepsEvalOperationCb op,
+ eDepsOperation_Code opcode,
+ const string& description = "");
+ OperationDepsNode *add_operation_node(ID *id,
+ eDepsNode_Type comp_type,
+ const string& comp_name,
+ eDepsOperation_Type optype,
+ DepsEvalOperationCb op,
+ eDepsOperation_Code opcode,
+ const string& description = "");
+ OperationDepsNode *add_operation_node(ID *id,
+ eDepsNode_Type comp_type,
+ eDepsOperation_Type optype,
+ DepsEvalOperationCb op,
+ eDepsOperation_Code opcode,
+ const string& description = "");
+
+ bool has_operation_node(ID *id,
+ eDepsNode_Type comp_type,
+ const string& comp_name,
+ eDepsOperation_Code opcode,
+ const string& description = "");
+
+ OperationDepsNode *find_operation_node(ID *id,
+ eDepsNode_Type comp_type,
+ const string &comp_name,
+ eDepsOperation_Code opcode,
+ const string &description = "");
+
+ OperationDepsNode *find_operation_node(ID *id,
+ eDepsNode_Type comp_type,
+ eDepsOperation_Code opcode,
+ const string &description = "");
+
+ void build_scene(Main *bmain, Scene *scene);
+ SubgraphDepsNode *build_subgraph(Group *group);
+ void build_group(Scene *scene, Base *base, Group *group);
+ void build_object(Scene *scene, Base *base, Object *ob);
+ void build_object_transform(Scene *scene, Object *ob);
+ void build_object_constraints(Scene *scene, Object *ob);
+ void build_pose_constraints(Object *ob, bPoseChannel *pchan);
+ void build_rigidbody(Scene *scene);
+ void build_particles(Scene *scene, Object *ob);
+ void build_animdata(ID *id);
+ OperationDepsNode *build_driver(ID *id, FCurve *fcurve);
+ void build_ik_pose(Scene *scene,
+ Object *ob,
+ bPoseChannel *pchan,
+ bConstraint *con);
+ void build_splineik_pose(Scene *scene,
+ Object *ob,
+ bPoseChannel *pchan,
+ bConstraint *con);
+ void build_rig(Scene *scene, Object *ob);
+ void build_proxy_rig(Object *ob);
+ void build_shapekeys(Key *key);
+ void build_obdata_geom(Scene *scene, Object *ob);
+ void build_camera(Object *ob);
+ void build_lamp(Object *ob);
+ void build_nodetree(DepsNode *owner_node, bNodeTree *ntree);
+ void build_material(DepsNode *owner_node, Material *ma);
+ void build_texture(DepsNode *owner_node, Tex *tex);
+ void build_texture_stack(DepsNode *owner_node, MTex **texture_stack);
+ void build_world(World *world);
+ void build_compositor(Scene *scene);
+ void build_gpencil(bGPdata *gpd);
+
+protected:
+ Main *m_bmain;
+ Depsgraph *m_graph;
+};
+
+} // namespace DEG
diff --git a/source/blender/depsgraph/util/depsgraph_util_pchanmap.cc b/source/blender/depsgraph/intern/builder/deg_builder_pchanmap.cc
index 80b37ec622d..0e78df52ff8 100644
--- a/source/blender/depsgraph/util/depsgraph_util_pchanmap.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder_pchanmap.cc
@@ -24,11 +24,11 @@
* ***** END GPL LICENSE BLOCK *****
*/
-/** \file blender/depsgraph/util/depsgraph_util_pchanmap.cc
+/** \file blender/depsgraph/intern/builder/deg_builder_pchanmap.h
* \ingroup depsgraph
*/
-#include "depsgraph_util_pchanmap.h"
+#include "intern/builder/deg_builder_pchanmap.h"
#include <stdio.h>
#include <string.h>
@@ -38,6 +38,8 @@ extern "C" {
#include "BLI_ghash.h"
}
+namespace DEG {
+
static void free_rootpchanmap_valueset(void *val)
{
/* Just need to free the set itself - the names stored are all references. */
@@ -48,13 +50,13 @@ static void free_rootpchanmap_valueset(void *val)
RootPChanMap::RootPChanMap()
{
/* Just create empty map. */
- m_map = BLI_ghash_str_new("RootPChanMap");
+ map_ = BLI_ghash_str_new("RootPChanMap");
}
RootPChanMap::~RootPChanMap()
{
/* Free the map, and all the value sets. */
- BLI_ghash_free(m_map, NULL, free_rootpchanmap_valueset);
+ BLI_ghash_free(map_, NULL, free_rootpchanmap_valueset);
}
/* Debug contents of map */
@@ -64,7 +66,7 @@ void RootPChanMap::print_debug()
GSetIterator it2;
printf("Root PChan Map:\n");
- GHASH_ITER(it1, m_map) {
+ GHASH_ITER(it1, map_) {
const char *item = (const char *)BLI_ghashIterator_getKey(&it1);
GSet *values = (GSet *)BLI_ghashIterator_getValue(&it1);
@@ -80,11 +82,11 @@ void RootPChanMap::print_debug()
/* Add a mapping. */
void RootPChanMap::add_bone(const char *bone, const char *root)
{
- if (BLI_ghash_haskey(m_map, bone)) {
+ if (BLI_ghash_haskey(map_, bone)) {
/* Add new entry, but only add the root if it doesn't already
* exist in there.
*/
- GSet *values = (GSet *)BLI_ghash_lookup(m_map, bone);
+ GSet *values = (GSet *)BLI_ghash_lookup(map_, bone);
BLI_gset_add(values, (void *)root);
}
else {
@@ -92,7 +94,7 @@ void RootPChanMap::add_bone(const char *bone, const char *root)
GSet *values = BLI_gset_new(BLI_ghashutil_strhash_p,
BLI_ghashutil_strcmp,
"RootPChanMap Value Set");
- BLI_ghash_insert(m_map, (void *)bone, (void *)values);
+ BLI_ghash_insert(map_, (void *)bone, (void *)values);
/* Add new entry now. */
BLI_gset_insert(values, (void *)root);
@@ -103,20 +105,20 @@ void RootPChanMap::add_bone(const char *bone, const char *root)
bool RootPChanMap::has_common_root(const char *bone1, const char *bone2)
{
/* Ensure that both are in the map... */
- if (BLI_ghash_haskey(m_map, bone1) == false) {
+ if (BLI_ghash_haskey(map_, bone1) == false) {
//fprintf("RootPChanMap: bone1 '%s' not found (%s => %s)\n", bone1, bone1, bone2);
//print_debug();
return false;
}
- if (BLI_ghash_haskey(m_map, bone2) == false) {
+ if (BLI_ghash_haskey(map_, bone2) == false) {
//fprintf("RootPChanMap: bone2 '%s' not found (%s => %s)\n", bone2, bone1, bone2);
//print_debug();
return false;
}
- GSet *bone1_roots = (GSet *)BLI_ghash_lookup(m_map, (void *)bone1);
- GSet *bone2_roots = (GSet *)BLI_ghash_lookup(m_map, (void *)bone2);
+ GSet *bone1_roots = (GSet *)BLI_ghash_lookup(map_, (void *)bone1);
+ GSet *bone2_roots = (GSet *)BLI_ghash_lookup(map_, (void *)bone2);
GSetIterator it1, it2;
GSET_ITER(it1, bone1_roots) {
@@ -134,3 +136,5 @@ bool RootPChanMap::has_common_root(const char *bone1, const char *bone2)
//fprintf("RootPChanMap: No common root found (%s => %s)\n", bone1, bone2);
return false;
}
+
+} // namespace DEG
diff --git a/source/blender/depsgraph/util/depsgraph_util_pchanmap.h b/source/blender/depsgraph/intern/builder/deg_builder_pchanmap.h
index b7f4c495933..233d8602fce 100644
--- a/source/blender/depsgraph/util/depsgraph_util_pchanmap.h
+++ b/source/blender/depsgraph/intern/builder/deg_builder_pchanmap.h
@@ -24,12 +24,15 @@
* ***** END GPL LICENSE BLOCK *****
*/
-/** \file blender/depsgraph/util/depsgraph_util_pchanmap.h
+/** \file blender/depsgraph/intern/builder/deg_builder_pchanmap.h
* \ingroup depsgraph
*/
-#ifndef __DEPSGRAPH_UTIL_PCHANMAP_H__
-#define __DEPSGRAPH_UTIL_PCHANMAP_H__
+#pragma once
+
+struct GHash;
+
+namespace DEG {
struct RootPChanMap {
/* ctor and dtor - Create and free the internal map respectively. */
@@ -45,7 +48,7 @@ struct RootPChanMap {
/* Check if there's a common root bone between two bones. */
bool has_common_root(const char *bone1, const char *bone2);
-private:
+protected:
/* The actual map:
* - Keys are "strings" (const char *) - not dynamically allocated.
* - Values are "sets" (const char *) - not dynamically allocated.
@@ -53,7 +56,7 @@ private:
* We don't use the C++ maps here, as it's more convenient to use
* Blender's GHash and be able to compare by-value instead of by-ref.
*/
- struct GHash *m_map;
+ struct GHash *map_;
};
-#endif /* __DEPSGRAPH_UTIL_PCHANMAP_H__ */
+} // namespace DEG
diff --git a/source/blender/depsgraph/intern/depsgraph_build_relations.cc b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc
index 52af483d87c..874837ff003 100644
--- a/source/blender/depsgraph/intern/depsgraph_build_relations.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc
@@ -24,12 +24,14 @@
* ***** END GPL LICENSE BLOCK *****
*/
-/** \file blender/depsgraph/intern/depsgraph_build_relations.cc
+/** \file blender/depsgraph/intern/builder/deg_builder_relations.cc
* \ingroup depsgraph
*
* Methods for constructing depsgraph
*/
+#include "intern/builder/deg_builder_relations.h"
+
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -93,15 +95,19 @@ extern "C" {
#include "RNA_types.h"
} /* extern "C" */
-#include "depsnode.h"
-#include "depsnode_component.h"
-#include "depsnode_operation.h"
-#include "depsgraph_build.h"
-#include "depsgraph_debug.h"
-#include "depsgraph_intern.h"
-#include "depsgraph_types.h"
+#include "intern/builder/deg_builder.h"
+#include "intern/builder/deg_builder_pchanmap.h"
+
+#include "intern/nodes/deg_node.h"
+#include "intern/nodes/deg_node_component.h"
+#include "intern/nodes/deg_node_operation.h"
+
+#include "intern/depsgraph_intern.h"
+#include "intern/depsgraph_types.h"
-#include "depsgraph_util_pchanmap.h"
+#include "util/deg_util_foreach.h"
+
+namespace DEG {
/* ***************** */
/* Relations Builder */
@@ -260,6 +266,13 @@ void DepsgraphRelationBuilder::build_scene(Main *bmain, Scene *scene)
for (Base *base = (Base *)scene->base.first; base; base = base->next) {
Object *ob = base->object;
+ /* Object that this is a proxy for.
+ * Just makes sure backlink is correct.
+ */
+ if (ob->proxy) {
+ ob->proxy->proxy_from = ob;
+ }
+
/* object itself */
build_object(bmain, scene, ob);
@@ -304,6 +317,19 @@ void DepsgraphRelationBuilder::build_scene(Main *bmain, Scene *scene)
if (scene->gpd) {
build_gpencil(&scene->id, scene->gpd);
}
+
+ for (Depsgraph::OperationNodes::const_iterator it_op = m_graph->operations.begin();
+ it_op != m_graph->operations.end();
+ ++it_op)
+ {
+ OperationDepsNode *node = *it_op;
+ IDDepsNode *id_node = node->owner->owner;
+ ID *id = id_node->id;
+ if (GS(id->name) == ID_OB) {
+ Object *object = (Object *)id;
+ object->customdata_mask |= node->customdata_mask;
+ }
+ }
}
void DepsgraphRelationBuilder::build_group(Main *bmain,
@@ -414,7 +440,6 @@ void DepsgraphRelationBuilder::build_object(Main *bmain, Scene *scene, Object *o
break;
}
-
case OB_ARMATURE: /* Pose */
if (ob->id.lib != NULL && ob->proxy_from != NULL) {
build_proxy_rig(ob);
@@ -473,8 +498,12 @@ void DepsgraphRelationBuilder::build_object_parent(Object *ob)
{
ComponentKey parent_key(&ob->parent->id, DEPSNODE_TYPE_GEOMETRY);
add_relation(parent_key, ob_key, DEPSREL_TYPE_GEOMETRY_EVAL, "Vertex Parent");
+
/* XXX not sure what this is for or how you could be done properly - lukas */
- //parent_node->customdata_mask |= CD_MASK_ORIGINDEX;
+ OperationDepsNode *parent_node = find_operation_node(parent_key);
+ if (parent_node != NULL) {
+ parent_node->customdata_mask |= CD_MASK_ORIGINDEX;
+ }
ComponentKey transform_key(&ob->parent->id, DEPSNODE_TYPE_TRANSFORM);
add_relation(transform_key, ob_key, DEPSREL_TYPE_TRANSFORM, "Vertex Parent TFM");
@@ -625,7 +654,10 @@ void DepsgraphRelationBuilder::build_constraints(Scene *scene, ID *id, eDepsNode
add_relation(target_key, constraint_op_key, DEPSREL_TYPE_GEOMETRY_EVAL, cti->name);
if (ct->tar->type == OB_MESH) {
- //node2->customdata_mask |= CD_MASK_MDEFORMVERT;
+ OperationDepsNode *node2 = find_operation_node(target_key);
+ if (node2 != NULL) {
+ node2->customdata_mask |= CD_MASK_MDEFORMVERT;
+ }
}
}
else if (con->type == CONSTRAINT_TYPE_SHRINKWRAP) {
@@ -766,8 +798,7 @@ void DepsgraphRelationBuilder::build_driver(ID *id, FCurve *fcu)
if (arm_node && bone_name) {
/* find objects which use this, and make their eval callbacks depend on this */
- DEPSNODE_RELATIONS_ITER_BEGIN(arm_node->outlinks, rel)
- {
+ foreach (DepsRelation *rel, arm_node->outlinks) {
IDDepsNode *to_node = (IDDepsNode *)rel->to;
/* we only care about objects with pose data which use this... */
@@ -781,7 +812,6 @@ void DepsgraphRelationBuilder::build_driver(ID *id, FCurve *fcu)
}
}
}
- DEPSNODE_RELATIONS_ITER_END;
/* free temp data */
MEM_freeN(bone_name);
@@ -1202,7 +1232,10 @@ void DepsgraphRelationBuilder::build_ik_pose(Object *ob,
add_relation(target_key, solver_key, DEPSREL_TYPE_GEOMETRY_EVAL, con->name);
if (data->tar->type == OB_MESH) {
- //node2->customdata_mask |= CD_MASK_MDEFORMVERT;
+ OperationDepsNode *node2 = find_operation_node(target_key);
+ if (node2 != NULL) {
+ node2->customdata_mask |= CD_MASK_MDEFORMVERT;
+ }
}
}
else {
@@ -1234,7 +1267,10 @@ void DepsgraphRelationBuilder::build_ik_pose(Object *ob,
add_relation(target_key, solver_key, DEPSREL_TYPE_GEOMETRY_EVAL, con->name);
if (data->poletar->type == OB_MESH) {
- //node2->customdata_mask |= CD_MASK_MDEFORMVERT;
+ OperationDepsNode *node2 = find_operation_node(target_key);
+ if (node2 != NULL) {
+ node2->customdata_mask |= CD_MASK_MDEFORMVERT;
+ }
}
}
else {
@@ -1610,13 +1646,18 @@ void DepsgraphRelationBuilder::build_obdata_geom(Main *bmain, Scene *scene, Obje
if (mti->updateDepsgraph) {
DepsNodeHandle handle = create_node_handle(mod_key);
- mti->updateDepsgraph(md, bmain, scene, ob, &handle);
+ mti->updateDepsgraph(
+ md,
+ bmain,
+ scene,
+ ob,
+ reinterpret_cast< ::DepsNodeHandle* >(&handle));
}
if (BKE_object_modifier_use_time(ob, md)) {
TimeSourceKey time_src_key;
add_relation(time_src_key, mod_key, DEPSREL_TYPE_TIME, "Time Source");
-
+
/* Hacky fix for T45633 (Animated modifiers aren't updated)
*
* This check works because BKE_object_modifier_use_time() tests
@@ -1926,3 +1967,4 @@ bool DepsgraphRelationBuilder::needs_animdata_node(ID *id)
return false;
}
+} // namespace DEG
diff --git a/source/blender/depsgraph/intern/depsgraph_build.h b/source/blender/depsgraph/intern/builder/deg_builder_relations.h
index c5b04ec299c..c0bf82becda 100644
--- a/source/blender/depsgraph/intern/depsgraph_build.h
+++ b/source/blender/depsgraph/intern/builder/deg_builder_relations.h
@@ -24,12 +24,27 @@
* ***** END GPL LICENSE BLOCK *****
*/
-/** \file blender/depsgraph/intern/depsgraph_build.h
+/** \file blender/depsgraph/intern/builder/deg_builder_relations.h
* \ingroup depsgraph
*/
-#ifndef __DEPSGRAPH_BUILD_H__
-#define __DEPSGRAPH_BUILD_H__
+#pragma once
+
+#include <cstdio>
+
+#include "intern/depsgraph_types.h"
+
+#include "DNA_ID.h"
+
+#include "RNA_access.h"
+#include "RNA_types.h"
+
+#include "BLI_utildefines.h"
+#include "BLI_string.h"
+
+#include "intern/depsgraph_types.h"
+#include "intern/nodes/deg_node.h"
+#include "intern/nodes/deg_node_operation.h"
struct Base;
struct bGPdata;
@@ -52,6 +67,8 @@ struct World;
struct PropertyRNA;
+namespace DEG {
+
struct Depsgraph;
struct DepsNode;
struct DepsNodeHandle;
@@ -63,75 +80,6 @@ struct ComponentDepsNode;
struct OperationDepsNode;
struct RootPChanMap;
-struct DepsgraphNodeBuilder {
- DepsgraphNodeBuilder(Main *bmain, Depsgraph *graph);
- ~DepsgraphNodeBuilder();
-
- RootDepsNode *add_root_node();
- IDDepsNode *add_id_node(ID *id);
- TimeSourceDepsNode *add_time_source(ID *id);
-
- ComponentDepsNode *add_component_node(ID *id, eDepsNode_Type comp_type, const string &comp_name = "");
-
- OperationDepsNode *add_operation_node(ComponentDepsNode *comp_node, eDepsOperation_Type optype,
- DepsEvalOperationCb op, eDepsOperation_Code opcode, const string &description = "");
- OperationDepsNode *add_operation_node(ID *id, eDepsNode_Type comp_type, const string &comp_name, eDepsOperation_Type optype,
- DepsEvalOperationCb op, eDepsOperation_Code opcode, const string &description = "");
- OperationDepsNode *add_operation_node(ID *id, eDepsNode_Type comp_type, eDepsOperation_Type optype,
- DepsEvalOperationCb op, eDepsOperation_Code opcode, const string &description = "")
- {
- return add_operation_node(id, comp_type, "", optype, op, opcode, description);
- }
-
- bool has_operation_node(ID *id, eDepsNode_Type comp_type, const string &comp_name,
- eDepsOperation_Code opcode, const string &description = "");
-
- OperationDepsNode *find_operation_node(ID *id,
- eDepsNode_Type comp_type,
- const string &comp_name,
- eDepsOperation_Code opcode,
- const string &description = "");
-
- OperationDepsNode *find_operation_node(ID *id,
- eDepsNode_Type comp_type,
- eDepsOperation_Code opcode,
- const string &description = "")
- {
- return find_operation_node(id, comp_type, "", opcode, description);
- }
-
- void build_scene(Main *bmain, Scene *scene);
- SubgraphDepsNode *build_subgraph(Group *group);
- void build_group(Scene *scene, Base *base, Group *group);
- void build_object(Scene *scene, Base *base, Object *ob);
- void build_object_transform(Scene *scene, Object *ob);
- void build_object_constraints(Scene *scene, Object *ob);
- void build_pose_constraints(Object *ob, bPoseChannel *pchan);
- void build_rigidbody(Scene *scene);
- void build_particles(Scene *scene, Object *ob);
- void build_animdata(ID *id);
- OperationDepsNode *build_driver(ID *id, FCurve *fcurve);
- void build_ik_pose(Scene *scene, Object *ob, bPoseChannel *pchan, bConstraint *con);
- void build_splineik_pose(Scene *scene, Object *ob, bPoseChannel *pchan, bConstraint *con);
- void build_rig(Scene *scene, Object *ob);
- void build_proxy_rig(Object *ob);
- void build_shapekeys(Key *key);
- void build_obdata_geom(Scene *scene, Object *ob);
- void build_camera(Object *ob);
- void build_lamp(Object *ob);
- void build_nodetree(DepsNode *owner_node, bNodeTree *ntree);
- void build_material(DepsNode *owner_node, Material *ma);
- void build_texture(DepsNode *owner_node, Tex *tex);
- void build_texture_stack(DepsNode *owner_node, MTex **texture_stack);
- void build_world(World *world);
- void build_compositor(Scene *scene);
- void build_gpencil(bGPdata *gpd);
-
-private:
- Main *m_bmain;
- Depsgraph *m_graph;
-};
-
struct RootKey
{
RootKey() {}
@@ -164,7 +112,7 @@ struct ComponentKey
const char *idname = (id) ? id->name : "<None>";
char typebuf[5];
- sprintf(typebuf, "%d", type);
+ BLI_snprintf(typebuf, sizeof(typebuf), "%d", type);
return string("ComponentKey(") + idname + ", " + typebuf + ", '" + name + "')";
}
@@ -204,7 +152,7 @@ struct OperationKey
string identifier() const
{
char typebuf[5];
- sprintf(typebuf, "%d", component_type);
+ BLI_snprintf(typebuf, sizeof(typebuf), "%d", component_type);
return string("OperationKey(") + "t: " + typebuf + ", cn: '" + component_name + "', c: " + DEG_OPNAMES[opcode] + ", n: '" + name + "')";
}
@@ -245,30 +193,45 @@ struct DepsgraphRelationBuilder
DepsgraphRelationBuilder(Depsgraph *graph);
template <typename KeyFrom, typename KeyTo>
- void add_relation(const KeyFrom &key_from, const KeyTo &key_to,
- eDepsRelation_Type type, const char *description);
+ void add_relation(const KeyFrom& key_from,
+ const KeyTo& key_to,
+ eDepsRelation_Type type,
+ const char *description);
template <typename KeyTo>
- void add_relation(const TimeSourceKey &key_from, const KeyTo &key_to,
- eDepsRelation_Type type, const char *description);
+ void add_relation(const TimeSourceKey& key_from,
+ const KeyTo& key_to,
+ eDepsRelation_Type type,
+ const char *description);
template <typename KeyType>
- void add_node_handle_relation(const KeyType &key_from, const DepsNodeHandle *handle,
- eDepsRelation_Type type, const char *description);
+ void add_node_handle_relation(const KeyType& key_from,
+ const DepsNodeHandle *handle,
+ eDepsRelation_Type type,
+ const char *description);
void build_scene(Main *bmain, Scene *scene);
void build_group(Main *bmain, Scene *scene, Object *object, Group *group);
void build_object(Main *bmain, Scene *scene, Object *ob);
void build_object_parent(Object *ob);
- void build_constraints(Scene *scene, ID *id, eDepsNode_Type component_type, const char *component_subdata,
- ListBase *constraints, RootPChanMap *root_map);
+ void build_constraints(Scene *scene, ID *id,
+ eDepsNode_Type component_type,
+ const char *component_subdata,
+ ListBase *constraints,
+ RootPChanMap *root_map);
void build_animdata(ID *id);
void build_driver(ID *id, FCurve *fcurve);
void build_world(World *world);
void build_rigidbody(Scene *scene);
void build_particles(Scene *scene, Object *ob);
- void build_ik_pose(Object *ob, bPoseChannel *pchan, bConstraint *con, RootPChanMap *root_map);
- void build_splineik_pose(Object *ob, bPoseChannel *pchan, bConstraint *con, RootPChanMap *root_map);
+ void build_ik_pose(Object *ob,
+ bPoseChannel *pchan,
+ bConstraint *con,
+ RootPChanMap *root_map);
+ void build_splineik_pose(Object *ob,
+ bPoseChannel *pchan,
+ bConstraint *con,
+ RootPChanMap *root_map);
void build_rig(Scene *scene, Object *ob);
void build_proxy_rig(Object *ob);
void build_shapekeys(ID *obdata, Key *key);
@@ -282,6 +245,9 @@ struct DepsgraphRelationBuilder
void build_compositor(Scene *scene);
void build_gpencil(ID *owner, bGPdata *gpd);
+ template <typename KeyType>
+ OperationDepsNode *find_operation_node(const KeyType &key);
+
protected:
RootDepsNode *find_node(const RootKey &key) const;
TimeSourceDepsNode *find_node(const TimeSourceKey &key) const;
@@ -290,12 +256,17 @@ protected:
DepsNode *find_node(const RNAPathKey &key) const;
OperationDepsNode *has_node(const OperationKey &key) const;
- void add_time_relation(TimeSourceDepsNode *timesrc, DepsNode *node_to, const char *description);
- void add_operation_relation(OperationDepsNode *node_from, OperationDepsNode *node_to,
- eDepsRelation_Type type, const char *description);
+ void add_time_relation(TimeSourceDepsNode *timesrc,
+ DepsNode *node_to,
+ const char *description);
+ void add_operation_relation(OperationDepsNode *node_from,
+ OperationDepsNode *node_to,
+ eDepsRelation_Type type,
+ const char *description);
template <typename KeyType>
- DepsNodeHandle create_node_handle(const KeyType &key, const string &default_name = "");
+ DepsNodeHandle create_node_handle(const KeyType& key,
+ const string& default_name = "");
bool needs_animdata_node(ID *id);
@@ -320,8 +291,11 @@ struct DepsNodeHandle
/* Utilities for Builders ----------------------------------------------------- */
-/* Get unique identifier for FCurves and Drivers */
-string deg_fcurve_id_name(const FCurve *fcu);
+template <typename KeyType>
+OperationDepsNode *DepsgraphRelationBuilder::find_operation_node(const KeyType& key) {
+ DepsNode *node = find_node(key);
+ return node != NULL ? node->get_exit_operation() : NULL;
+}
template <typename KeyFrom, typename KeyTo>
void DepsgraphRelationBuilder::add_relation(const KeyFrom &key_from,
@@ -377,10 +351,11 @@ void DepsgraphRelationBuilder::add_relation(const TimeSourceKey &key_from,
}
template <typename KeyType>
-void DepsgraphRelationBuilder::add_node_handle_relation(const KeyType &key_from,
- const DepsNodeHandle *handle,
- eDepsRelation_Type type,
- const char *description)
+void DepsgraphRelationBuilder::add_node_handle_relation(
+ const KeyType &key_from,
+ const DepsNodeHandle *handle,
+ eDepsRelation_Type type,
+ const char *description)
{
DepsNode *node_from = find_node(key_from);
OperationDepsNode *op_from = node_from ? node_from->get_exit_operation() : NULL;
@@ -399,10 +374,11 @@ void DepsgraphRelationBuilder::add_node_handle_relation(const KeyType &key_from,
}
template <typename KeyType>
-DepsNodeHandle DepsgraphRelationBuilder::create_node_handle(const KeyType &key,
- const string &default_name)
+DepsNodeHandle DepsgraphRelationBuilder::create_node_handle(
+ const KeyType &key,
+ const string &default_name)
{
return DepsNodeHandle(this, find_node(key), default_name);
}
-#endif /* __DEPSGRAPH_BUILD_H__ */
+} // namespace DEG
diff --git a/source/blender/depsgraph/util/depsgraph_util_transitive.cc b/source/blender/depsgraph/intern/builder/deg_builder_transitive.cc
index 98192a9540f..0322ef7fa1d 100644
--- a/source/blender/depsgraph/util/depsgraph_util_transitive.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder_transitive.cc
@@ -24,26 +24,25 @@
* ***** END GPL LICENSE BLOCK *****
*/
-/** \file blender/depsgraph/util/depsgraph_util_transitive.cc
+/** \file blender/depsgraph/intern/builder/deg_builder_transitive.cc
* \ingroup depsgraph
*/
+#include "intern/builder/deg_builder_transitive.h"
+
extern "C" {
#include "MEM_guardedalloc.h"
+}
-#include "BLI_utildefines.h"
+#include "intern/nodes/deg_node.h"
+#include "intern/nodes/deg_node_component.h"
+#include "intern/nodes/deg_node_operation.h"
-#include "DNA_ID.h"
+#include "intern/depsgraph.h"
-#include "RNA_access.h"
-#include "RNA_types.h"
-}
+#include "util/deg_util_foreach.h"
-#include "depsgraph_util_transitive.h"
-#include "depsgraph.h"
-#include "depsnode.h"
-#include "depsnode_component.h"
-#include "depsnode_operation.h"
+namespace DEG {
/* -------------------------------------------------- */
@@ -67,16 +66,11 @@ enum {
static void deg_graph_tag_paths_recursive(DepsNode *node)
{
- if (node->done & OP_VISITED)
+ if (node->done & OP_VISITED) {
return;
+ }
node->done |= OP_VISITED;
-
- for (OperationDepsNode::Relations::const_iterator it = node->inlinks.begin();
- it != node->inlinks.end();
- ++it)
- {
- DepsRelation *rel = *it;
-
+ foreach (DepsRelation *rel, node->inlinks) {
deg_graph_tag_paths_recursive(rel->from);
/* Do this only in inlinks loop, so the target node does not get
* flagged.
@@ -87,18 +81,9 @@ static void deg_graph_tag_paths_recursive(DepsNode *node)
void deg_graph_transitive_reduction(Depsgraph *graph)
{
- for (Depsgraph::OperationNodes::const_iterator it_target = graph->operations.begin();
- it_target != graph->operations.end();
- ++it_target)
- {
- OperationDepsNode *target = *it_target;
-
+ foreach (OperationDepsNode *target, graph->operations) {
/* Clear tags. */
- for (Depsgraph::OperationNodes::const_iterator it = graph->operations.begin();
- it != graph->operations.end();
- ++it)
- {
- OperationDepsNode *node = *it;
+ foreach (OperationDepsNode *node, graph->operations) {
node->done = 0;
}
@@ -107,19 +92,14 @@ void deg_graph_transitive_reduction(Depsgraph *graph)
* flagged.
*/
target->done |= OP_VISITED;
- for (OperationDepsNode::Relations::const_iterator it = target->inlinks.begin();
- it != target->inlinks.end();
- ++it)
- {
- DepsRelation *rel = *it;
-
+ foreach (DepsRelation *rel, target->inlinks) {
deg_graph_tag_paths_recursive(rel->from);
}
- /* Eemove redundant paths to the target. */
+ /* Remove redundant paths to the target. */
for (DepsNode::Relations::const_iterator it_rel = target->inlinks.begin();
it_rel != target->inlinks.end();
- )
+ )
{
DepsRelation *rel = *it_rel;
/* Increment in advance, so we can safely remove the relation. */
@@ -137,3 +117,5 @@ void deg_graph_transitive_reduction(Depsgraph *graph)
}
}
}
+
+} // namespace DEG
diff --git a/source/blender/depsgraph/util/depsgraph_util_transitive.h b/source/blender/depsgraph/intern/builder/deg_builder_transitive.h
index a80a1d783d7..be9d7c3ca9c 100644
--- a/source/blender/depsgraph/util/depsgraph_util_transitive.h
+++ b/source/blender/depsgraph/intern/builder/deg_builder_transitive.h
@@ -24,15 +24,17 @@
* ***** END GPL LICENSE BLOCK *****
*/
-/** \file blender/depsgraph/util/depsgraph_util_transitive.h
+/** \file blender/depsgraph/intern/builder/deg_builder_transitive.h
* \ingroup depsgraph
*/
-#ifndef __DEPSGRAPH_UTIL_TRANSITIVE_H__
-#define __DEPSGRAPH_UTIL_TRANSITIVE_H__
+#pragma once
+
+namespace DEG {
struct Depsgraph;
+/* Performs a transitive reduction to remove redundant relations. */
void deg_graph_transitive_reduction(Depsgraph *graph);
-#endif /* __DEPSGRAPH_UTIL_TRANSITIVE_H__ */
+} // namespace DEG
diff --git a/source/blender/depsgraph/intern/debug/deg_debug_graphviz.cc b/source/blender/depsgraph/intern/debug/deg_debug_graphviz.cc
new file mode 100644
index 00000000000..5ce84ee29db
--- /dev/null
+++ b/source/blender/depsgraph/intern/debug/deg_debug_graphviz.cc
@@ -0,0 +1,588 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2014 Blender Foundation.
+ * All rights reserved.
+ *
+ * Original Author: Lukas Toenne
+ * Contributor(s): None Yet
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/depsgraph/intern/debug/deg_debug_graphviz.cc
+ * \ingroup depsgraph
+ *
+ * Implementation of tools for debugging the depsgraph
+ */
+
+#include "BLI_utildefines.h"
+#include "BLI_ghash.h"
+
+extern "C" {
+#include "DNA_listBase.h"
+
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_debug.h"
+} /* extern "C" */
+
+#include "intern/depsgraph_intern.h"
+#include "util/deg_util_foreach.h"
+
+/* ****************** */
+/* Graphviz Debugging */
+
+namespace DEG {
+
+#define NL "\r\n"
+
+/* Only one should be enabled, defines whether graphviz nodes
+ * get colored by individual types or classes.
+ */
+#define COLOR_SCHEME_NODE_CLASS 1
+//#define COLOR_SCHEME_NODE_TYPE 2
+
+static const char *deg_debug_graphviz_fontname = "helvetica";
+static float deg_debug_graphviz_graph_label_size = 20.0f;
+static float deg_debug_graphviz_node_label_size = 14.0f;
+static const int deg_debug_max_colors = 12;
+#ifdef COLOR_SCHEME_NODE_TYPE
+static const char *deg_debug_colors[] = {
+ "#a6cee3", "#1f78b4", "#b2df8a",
+ "#33a02c", "#fb9a99", "#e31a1c",
+ "#fdbf6f", "#ff7f00", "#cab2d6",
+ "#6a3d9a", "#ffff99", "#b15928",
+};
+#endif
+static const char *deg_debug_colors_light[] = {
+ "#8dd3c7", "#ffffb3", "#bebada",
+ "#fb8072", "#80b1d3", "#fdb462",
+ "#b3de69", "#fccde5", "#d9d9d9",
+ "#bc80bd", "#ccebc5", "#ffed6f",
+};
+
+#ifdef COLOR_SCHEME_NODE_TYPE
+static const int deg_debug_node_type_color_map[][2] = {
+ {DEPSNODE_TYPE_ROOT, 0},
+ {DEPSNODE_TYPE_TIMESOURCE, 1},
+ {DEPSNODE_TYPE_ID_REF, 2},
+ {DEPSNODE_TYPE_SUBGRAPH, 3},
+
+ /* Outer Types */
+ {DEPSNODE_TYPE_PARAMETERS, 4},
+ {DEPSNODE_TYPE_PROXY, 5},
+ {DEPSNODE_TYPE_ANIMATION, 6},
+ {DEPSNODE_TYPE_TRANSFORM, 7},
+ {DEPSNODE_TYPE_GEOMETRY, 8},
+ {DEPSNODE_TYPE_SEQUENCER, 9},
+ {DEPSNODE_TYPE_SHADING, 10},
+ {-1, 0}
+};
+#endif
+
+static int deg_debug_node_color_index(const DepsNode *node)
+{
+#ifdef COLOR_SCHEME_NODE_CLASS
+ /* Some special types. */
+ switch (node->type) {
+ case DEPSNODE_TYPE_ID_REF:
+ return 5;
+ case DEPSNODE_TYPE_OPERATION:
+ {
+ OperationDepsNode *op_node = (OperationDepsNode *)node;
+ if (op_node->is_noop())
+ return 8;
+ break;
+ }
+
+ default:
+ break;
+ }
+ /* Do others based on class. */
+ switch (node->tclass) {
+ case DEPSNODE_CLASS_OPERATION:
+ return 4;
+ case DEPSNODE_CLASS_COMPONENT:
+ return 1;
+ default:
+ return 9;
+ }
+#endif
+
+#ifdef COLOR_SCHEME_NODE_TYPE
+ const int (*pair)[2];
+ for (pair = deg_debug_node_type_color_map; (*pair)[0] >= 0; ++pair) {
+ if ((*pair)[0] == node->type) {
+ return (*pair)[1];
+ }
+ }
+ return -1;
+#endif
+}
+
+struct DebugContext {
+ FILE *file;
+ bool show_tags;
+ bool show_eval_priority;
+};
+
+static void deg_debug_fprintf(const DebugContext &ctx, const char *fmt, ...) ATTR_PRINTF_FORMAT(2, 3);
+static void deg_debug_fprintf(const DebugContext &ctx, const char *fmt, ...)
+{
+ va_list args;
+ va_start(args, fmt);
+ vfprintf(ctx.file, fmt, args);
+ va_end(args);
+}
+
+static void deg_debug_graphviz_legend_color(const DebugContext &ctx,
+ const char *name,
+ const char *color)
+{
+ deg_debug_fprintf(ctx, "<TR>");
+ deg_debug_fprintf(ctx, "<TD>%s</TD>", name);
+ deg_debug_fprintf(ctx, "<TD BGCOLOR=\"%s\"></TD>", color);
+ deg_debug_fprintf(ctx, "</TR>" NL);
+}
+
+static void deg_debug_graphviz_legend(const DebugContext &ctx)
+{
+ deg_debug_fprintf(ctx, "{" NL);
+ deg_debug_fprintf(ctx, "rank = sink;" NL);
+ deg_debug_fprintf(ctx, "Legend [shape=none, margin=0, label=<" NL);
+ deg_debug_fprintf(ctx, " <TABLE BORDER=\"0\" CELLBORDER=\"1\" CELLSPACING=\"0\" CELLPADDING=\"4\">" NL);
+ deg_debug_fprintf(ctx, "<TR><TD COLSPAN=\"2\"><B>Legend</B></TD></TR>" NL);
+
+#ifdef COLOR_SCHEME_NODE_CLASS
+ const char **colors = deg_debug_colors_light;
+ deg_debug_graphviz_legend_color(ctx, "Operation", colors[4]);
+ deg_debug_graphviz_legend_color(ctx, "Component", colors[1]);
+ deg_debug_graphviz_legend_color(ctx, "ID Node", colors[5]);
+ deg_debug_graphviz_legend_color(ctx, "NOOP", colors[8]);
+#endif
+
+#ifdef COLOR_SCHEME_NODE_TYPE
+ const int (*pair)[2];
+ for (pair = deg_debug_node_type_color_map; (*pair)[0] >= 0; ++pair) {
+ DepsNodeFactory *nti = DEG_get_node_factory((eDepsNode_Type)(*pair)[0]);
+ deg_debug_graphviz_legend_color(ctx,
+ nti->tname().c_str(),
+ deg_debug_colors_light[(*pair)[1] % deg_debug_max_colors]);
+ }
+#endif
+
+ deg_debug_fprintf(ctx, "</TABLE>" NL);
+ deg_debug_fprintf(ctx, ">" NL);
+ deg_debug_fprintf(ctx, ",fontname=\"%s\"", deg_debug_graphviz_fontname);
+ deg_debug_fprintf(ctx, "];" NL);
+ deg_debug_fprintf(ctx, "}" NL);
+}
+
+static void deg_debug_graphviz_node_color(const DebugContext &ctx,
+ const DepsNode *node)
+{
+ const char *color_default = "black";
+ const char *color_modified = "orangered4";
+ const char *color_update = "dodgerblue3";
+ const char *color = color_default;
+ if (ctx.show_tags) {
+ if (node->tclass == DEPSNODE_CLASS_OPERATION) {
+ OperationDepsNode *op_node = (OperationDepsNode *)node;
+ if (op_node->flag & DEPSOP_FLAG_DIRECTLY_MODIFIED) {
+ color = color_modified;
+ }
+ else if (op_node->flag & DEPSOP_FLAG_NEEDS_UPDATE) {
+ color = color_update;
+ }
+ }
+ }
+ deg_debug_fprintf(ctx, "\"%s\"", color);
+}
+
+static void deg_debug_graphviz_node_penwidth(const DebugContext &ctx,
+ const DepsNode *node)
+{
+ float penwidth_default = 1.0f;
+ float penwidth_modified = 4.0f;
+ float penwidth_update = 4.0f;
+ float penwidth = penwidth_default;
+ if (ctx.show_tags) {
+ if (node->tclass == DEPSNODE_CLASS_OPERATION) {
+ OperationDepsNode *op_node = (OperationDepsNode *)node;
+ if (op_node->flag & DEPSOP_FLAG_DIRECTLY_MODIFIED) {
+ penwidth = penwidth_modified;
+ }
+ else if (op_node->flag & DEPSOP_FLAG_NEEDS_UPDATE) {
+ penwidth = penwidth_update;
+ }
+ }
+ }
+ deg_debug_fprintf(ctx, "\"%f\"", penwidth);
+}
+
+static void deg_debug_graphviz_node_fillcolor(const DebugContext &ctx,
+ const DepsNode *node)
+{
+ const char *defaultcolor = "gainsboro";
+ int color_index = deg_debug_node_color_index(node);
+ const char *fillcolor = color_index < 0 ? defaultcolor : deg_debug_colors_light[color_index % deg_debug_max_colors];
+ deg_debug_fprintf(ctx, "\"%s\"", fillcolor);
+}
+
+static void deg_debug_graphviz_relation_color(const DebugContext &ctx,
+ const DepsRelation *rel)
+{
+ const char *color_default = "black";
+ const char *color_error = "red4";
+ const char *color = color_default;
+ if (rel->flag & DEPSREL_FLAG_CYCLIC) {
+ color = color_error;
+ }
+ deg_debug_fprintf(ctx, "%s", color);
+}
+
+static void deg_debug_graphviz_node_style(const DebugContext &ctx, const DepsNode *node)
+{
+ const char *base_style = "filled"; /* default style */
+ if (ctx.show_tags) {
+ if (node->tclass == DEPSNODE_CLASS_OPERATION) {
+ OperationDepsNode *op_node = (OperationDepsNode *)node;
+ if (op_node->flag & (DEPSOP_FLAG_DIRECTLY_MODIFIED | DEPSOP_FLAG_NEEDS_UPDATE)) {
+ base_style = "striped";
+ }
+ }
+ }
+ switch (node->tclass) {
+ case DEPSNODE_CLASS_GENERIC:
+ deg_debug_fprintf(ctx, "\"%s\"", base_style);
+ break;
+ case DEPSNODE_CLASS_COMPONENT:
+ deg_debug_fprintf(ctx, "\"%s\"", base_style);
+ break;
+ case DEPSNODE_CLASS_OPERATION:
+ deg_debug_fprintf(ctx, "\"%s,rounded\"", base_style);
+ break;
+ }
+}
+
+static void deg_debug_graphviz_node_single(const DebugContext &ctx,
+ const DepsNode *node)
+{
+ const char *shape = "box";
+ string name = node->identifier();
+ float priority = -1.0f;
+ if (node->type == DEPSNODE_TYPE_ID_REF) {
+ IDDepsNode *id_node = (IDDepsNode *)node;
+ char buf[256];
+ BLI_snprintf(buf, sizeof(buf), " (Layers: %d)", id_node->layers);
+ name += buf;
+ }
+ if (ctx.show_eval_priority && node->tclass == DEPSNODE_CLASS_OPERATION) {
+ priority = ((OperationDepsNode *)node)->eval_priority;
+ }
+ deg_debug_fprintf(ctx, "// %s\n", name.c_str());
+ deg_debug_fprintf(ctx, "\"node_%p\"", node);
+ deg_debug_fprintf(ctx, "[");
+// deg_debug_fprintf(ctx, "label=<<B>%s</B>>", name);
+ if (priority >= 0.0f) {
+ deg_debug_fprintf(ctx, "label=<%s<BR/>(<I>%.2f</I>)>",
+ name.c_str(),
+ priority);
+ }
+ else {
+ deg_debug_fprintf(ctx, "label=<%s>", name.c_str());
+ }
+ deg_debug_fprintf(ctx, ",fontname=\"%s\"", deg_debug_graphviz_fontname);
+ deg_debug_fprintf(ctx, ",fontsize=%f", deg_debug_graphviz_node_label_size);
+ deg_debug_fprintf(ctx, ",shape=%s", shape);
+ deg_debug_fprintf(ctx, ",style="); deg_debug_graphviz_node_style(ctx, node);
+ deg_debug_fprintf(ctx, ",color="); deg_debug_graphviz_node_color(ctx, node);
+ deg_debug_fprintf(ctx, ",fillcolor="); deg_debug_graphviz_node_fillcolor(ctx, node);
+ deg_debug_fprintf(ctx, ",penwidth="); deg_debug_graphviz_node_penwidth(ctx, node);
+ deg_debug_fprintf(ctx, "];" NL);
+ deg_debug_fprintf(ctx, NL);
+}
+
+static void deg_debug_graphviz_node_cluster_begin(const DebugContext &ctx,
+ const DepsNode *node)
+{
+ string name = node->identifier().c_str();
+ if (node->type == DEPSNODE_TYPE_ID_REF) {
+ IDDepsNode *id_node = (IDDepsNode *)node;
+ char buf[256];
+ BLI_snprintf(buf, sizeof(buf), " (Layers: %d)", id_node->layers);
+ name += buf;
+ }
+ deg_debug_fprintf(ctx, "// %s\n", name.c_str());
+ deg_debug_fprintf(ctx, "subgraph \"cluster_%p\" {" NL, node);
+// deg_debug_fprintf(ctx, "label=<<B>%s</B>>;" NL, name);
+ deg_debug_fprintf(ctx, "label=<%s>;" NL, name.c_str());
+ deg_debug_fprintf(ctx, "fontname=\"%s\";" NL, deg_debug_graphviz_fontname);
+ deg_debug_fprintf(ctx, "fontsize=%f;" NL, deg_debug_graphviz_node_label_size);
+ deg_debug_fprintf(ctx, "margin=\"%d\";" NL, 16);
+ deg_debug_fprintf(ctx, "style="); deg_debug_graphviz_node_style(ctx, node); deg_debug_fprintf(ctx, ";" NL);
+ deg_debug_fprintf(ctx, "color="); deg_debug_graphviz_node_color(ctx, node); deg_debug_fprintf(ctx, ";" NL);
+ deg_debug_fprintf(ctx, "fillcolor="); deg_debug_graphviz_node_fillcolor(ctx, node); deg_debug_fprintf(ctx, ";" NL);
+ deg_debug_fprintf(ctx, "penwidth="); deg_debug_graphviz_node_penwidth(ctx, node); deg_debug_fprintf(ctx, ";" NL);
+ /* dummy node, so we can add edges between clusters */
+ deg_debug_fprintf(ctx, "\"node_%p\"", node);
+ deg_debug_fprintf(ctx, "[");
+ deg_debug_fprintf(ctx, "shape=%s", "point");
+ deg_debug_fprintf(ctx, ",style=%s", "invis");
+ deg_debug_fprintf(ctx, "];" NL);
+ deg_debug_fprintf(ctx, NL);
+}
+
+static void deg_debug_graphviz_node_cluster_end(const DebugContext &ctx)
+{
+ deg_debug_fprintf(ctx, "}" NL);
+ deg_debug_fprintf(ctx, NL);
+}
+
+static void deg_debug_graphviz_graph_nodes(const DebugContext &ctx,
+ const Depsgraph *graph);
+static void deg_debug_graphviz_graph_relations(const DebugContext &ctx,
+ const Depsgraph *graph);
+
+static void deg_debug_graphviz_node(const DebugContext &ctx,
+ const DepsNode *node)
+{
+ switch (node->type) {
+ case DEPSNODE_TYPE_ID_REF:
+ {
+ const IDDepsNode *id_node = (const IDDepsNode *)node;
+ if (BLI_ghash_size(id_node->components) == 0) {
+ deg_debug_graphviz_node_single(ctx, node);
+ }
+ else {
+ deg_debug_graphviz_node_cluster_begin(ctx, node);
+ GHASH_FOREACH_BEGIN(const ComponentDepsNode *, comp, id_node->components)
+ {
+ deg_debug_graphviz_node(ctx, comp);
+ }
+ GHASH_FOREACH_END();
+ deg_debug_graphviz_node_cluster_end(ctx);
+ }
+ break;
+ }
+ case DEPSNODE_TYPE_SUBGRAPH:
+ {
+ SubgraphDepsNode *sub_node = (SubgraphDepsNode *)node;
+ if (sub_node->graph) {
+ deg_debug_graphviz_node_cluster_begin(ctx, node);
+ deg_debug_graphviz_graph_nodes(ctx, sub_node->graph);
+ deg_debug_graphviz_node_cluster_end(ctx);
+ }
+ else {
+ deg_debug_graphviz_node_single(ctx, node);
+ }
+ break;
+ }
+ case DEPSNODE_TYPE_PARAMETERS:
+ case DEPSNODE_TYPE_ANIMATION:
+ case DEPSNODE_TYPE_TRANSFORM:
+ case DEPSNODE_TYPE_PROXY:
+ case DEPSNODE_TYPE_GEOMETRY:
+ case DEPSNODE_TYPE_SEQUENCER:
+ case DEPSNODE_TYPE_EVAL_POSE:
+ case DEPSNODE_TYPE_BONE:
+ case DEPSNODE_TYPE_SHADING:
+ case DEPSNODE_TYPE_EVAL_PARTICLES:
+ {
+ ComponentDepsNode *comp_node = (ComponentDepsNode *)node;
+ if (!comp_node->operations.empty()) {
+ deg_debug_graphviz_node_cluster_begin(ctx, node);
+ foreach (DepsNode *op_node, comp_node->operations) {
+ deg_debug_graphviz_node(ctx, op_node);
+ }
+ deg_debug_graphviz_node_cluster_end(ctx);
+ }
+ else {
+ deg_debug_graphviz_node_single(ctx, node);
+ }
+ break;
+ }
+ default:
+ deg_debug_graphviz_node_single(ctx, node);
+ break;
+ }
+}
+
+static bool deg_debug_graphviz_is_cluster(const DepsNode *node)
+{
+ switch (node->type) {
+ case DEPSNODE_TYPE_ID_REF:
+ {
+ const IDDepsNode *id_node = (const IDDepsNode *)node;
+ return BLI_ghash_size(id_node->components) > 0;
+ }
+ case DEPSNODE_TYPE_SUBGRAPH:
+ {
+ SubgraphDepsNode *sub_node = (SubgraphDepsNode *)node;
+ return sub_node->graph != NULL;
+ }
+ case DEPSNODE_TYPE_PARAMETERS:
+ case DEPSNODE_TYPE_ANIMATION:
+ case DEPSNODE_TYPE_TRANSFORM:
+ case DEPSNODE_TYPE_PROXY:
+ case DEPSNODE_TYPE_GEOMETRY:
+ case DEPSNODE_TYPE_SEQUENCER:
+ case DEPSNODE_TYPE_EVAL_POSE:
+ case DEPSNODE_TYPE_BONE:
+ {
+ ComponentDepsNode *comp_node = (ComponentDepsNode *)node;
+ return !comp_node->operations.empty();
+ }
+ default:
+ return false;
+ }
+}
+
+static bool deg_debug_graphviz_is_owner(const DepsNode *node,
+ const DepsNode *other)
+{
+ switch (node->tclass) {
+ case DEPSNODE_CLASS_COMPONENT:
+ {
+ ComponentDepsNode *comp_node = (ComponentDepsNode *)node;
+ if (comp_node->owner == other)
+ return true;
+ break;
+ }
+ case DEPSNODE_CLASS_OPERATION:
+ {
+ OperationDepsNode *op_node = (OperationDepsNode *)node;
+ if (op_node->owner == other)
+ return true;
+ else if (op_node->owner->owner == other)
+ return true;
+ break;
+ }
+ default: break;
+ }
+ return false;
+}
+
+static void deg_debug_graphviz_node_relations(const DebugContext &ctx,
+ const DepsNode *node)
+{
+ foreach (DepsRelation *rel, node->inlinks) {
+ float penwidth = 2.0f;
+
+ const DepsNode *tail = rel->to; /* same as node */
+ const DepsNode *head = rel->from;
+ deg_debug_fprintf(ctx, "// %s -> %s\n",
+ head->identifier().c_str(),
+ tail->identifier().c_str());
+ deg_debug_fprintf(ctx, "\"node_%p\"", head);
+ deg_debug_fprintf(ctx, " -> ");
+ deg_debug_fprintf(ctx, "\"node_%p\"", tail);
+
+ deg_debug_fprintf(ctx, "[");
+ /* Note: without label an id seem necessary to avoid bugs in graphviz/dot */
+ deg_debug_fprintf(ctx, "id=\"%s\"", rel->name);
+ deg_debug_fprintf(ctx, ",color="); deg_debug_graphviz_relation_color(ctx, rel);
+ deg_debug_fprintf(ctx, ",penwidth=\"%f\"", penwidth);
+ /* NOTE: edge from node to own cluster is not possible and gives graphviz
+ * warning, avoid this here by just linking directly to the invisible
+ * placeholder node
+ */
+ if (deg_debug_graphviz_is_cluster(tail) && !deg_debug_graphviz_is_owner(head, tail)) {
+ deg_debug_fprintf(ctx, ",ltail=\"cluster_%p\"", tail);
+ }
+ if (deg_debug_graphviz_is_cluster(head) && !deg_debug_graphviz_is_owner(tail, head)) {
+ deg_debug_fprintf(ctx, ",lhead=\"cluster_%p\"", head);
+ }
+ deg_debug_fprintf(ctx, "];" NL);
+ deg_debug_fprintf(ctx, NL);
+ }
+}
+
+static void deg_debug_graphviz_graph_nodes(const DebugContext &ctx,
+ const Depsgraph *graph)
+{
+ if (graph->root_node) {
+ deg_debug_graphviz_node(ctx, graph->root_node);
+ }
+ GHASH_FOREACH_BEGIN (DepsNode *, node, graph->id_hash)
+ {
+ deg_debug_graphviz_node(ctx, node);
+ }
+ GHASH_FOREACH_END();
+ TimeSourceDepsNode *time_source = graph->find_time_source(NULL);
+ if (time_source != NULL) {
+ deg_debug_graphviz_node(ctx, time_source);
+ }
+}
+
+static void deg_debug_graphviz_graph_relations(const DebugContext &ctx,
+ const Depsgraph *graph)
+{
+ GHASH_FOREACH_BEGIN(IDDepsNode *, id_node, graph->id_hash)
+ {
+ GHASH_FOREACH_BEGIN(ComponentDepsNode *, comp_node, id_node->components)
+ {
+ foreach (OperationDepsNode *op_node, comp_node->operations) {
+ deg_debug_graphviz_node_relations(ctx, op_node);
+ }
+ }
+ GHASH_FOREACH_END();
+ }
+ GHASH_FOREACH_END();
+
+ TimeSourceDepsNode *time_source = graph->find_time_source(NULL);
+ if (time_source != NULL) {
+ deg_debug_graphviz_node_relations(ctx, time_source);
+ }
+}
+
+} // namespace DEG
+
+void DEG_debug_graphviz(const Depsgraph *graph, FILE *f, const char *label, bool show_eval)
+{
+ if (!graph) {
+ return;
+ }
+
+ const DEG::Depsgraph *deg_graph = reinterpret_cast<const DEG::Depsgraph *>(graph);
+
+ DEG::DebugContext ctx;
+ ctx.file = f;
+ ctx.show_tags = show_eval;
+ ctx.show_eval_priority = show_eval;
+
+ DEG::deg_debug_fprintf(ctx, "digraph depgraph {" NL);
+ DEG::deg_debug_fprintf(ctx, "rankdir=LR;" NL);
+ DEG::deg_debug_fprintf(ctx, "graph [");
+ DEG::deg_debug_fprintf(ctx, "compound=true");
+ DEG::deg_debug_fprintf(ctx, ",labelloc=\"t\"");
+ DEG::deg_debug_fprintf(ctx, ",fontsize=%f", DEG::deg_debug_graphviz_graph_label_size);
+ DEG::deg_debug_fprintf(ctx, ",fontname=\"%s\"", DEG::deg_debug_graphviz_fontname);
+ DEG::deg_debug_fprintf(ctx, ",label=\"%s\"", label);
+ DEG::deg_debug_fprintf(ctx, ",splines=ortho");
+ DEG::deg_debug_fprintf(ctx, ",overlap=scalexy"); // XXX: only when using neato
+ DEG::deg_debug_fprintf(ctx, "];" NL);
+
+ DEG::deg_debug_graphviz_graph_nodes(ctx, deg_graph);
+ DEG::deg_debug_graphviz_graph_relations(ctx, deg_graph);
+
+ DEG::deg_debug_graphviz_legend(ctx);
+
+ DEG::deg_debug_fprintf(ctx, "}" NL);
+}
+
+#undef NL
diff --git a/source/blender/depsgraph/intern/depsgraph.cc b/source/blender/depsgraph/intern/depsgraph.cc
index d293d03f63d..2b7c63767ab 100644
--- a/source/blender/depsgraph/intern/depsgraph.cc
+++ b/source/blender/depsgraph/intern/depsgraph.cc
@@ -30,10 +30,14 @@
* Core routines for how the Depsgraph works.
*/
+#include "intern/depsgraph.h" /* own include */
+
#include <string.h>
#include "MEM_guardedalloc.h"
+#include "BLI_utildefines.h"
+#include "BLI_ghash.h"
#include "BLI_listbase.h"
extern "C" {
@@ -50,11 +54,15 @@ extern "C" {
}
#include "DEG_depsgraph.h"
-#include "depsgraph.h" /* own include */
-#include "depsnode.h"
-#include "depsnode_operation.h"
-#include "depsnode_component.h"
-#include "depsgraph_intern.h"
+
+#include "intern/nodes/deg_node.h"
+#include "intern/nodes/deg_node_component.h"
+#include "intern/nodes/deg_node_operation.h"
+
+#include "intern/depsgraph_intern.h"
+#include "util/deg_util_foreach.h"
+
+namespace DEG {
static DEG_EditorUpdateIDCb deg_editor_update_id_cb = NULL;
static DEG_EditorUpdateSceneCb deg_editor_update_scene_cb = NULL;
@@ -66,6 +74,9 @@ Depsgraph::Depsgraph()
layers(0)
{
BLI_spin_init(&lock);
+ id_hash = BLI_ghash_ptr_new("Depsgraph id hash");
+ subgraphs = BLI_gset_ptr_new("Depsgraph subgraphs");
+ entry_tags = BLI_gset_ptr_new("Depsgraph entry_tags");
}
Depsgraph::~Depsgraph()
@@ -73,6 +84,9 @@ Depsgraph::~Depsgraph()
/* Free root node - it won't have been freed yet... */
clear_id_nodes();
clear_subgraph_nodes();
+ BLI_ghash_free(id_hash, NULL, NULL);
+ BLI_gset_free(subgraphs, NULL);
+ BLI_gset_free(entry_tags, NULL);
if (this->root_node != NULL) {
OBJECT_GUARDED_DELETE(this->root_node, RootDepsNode);
}
@@ -235,10 +249,16 @@ DepsNode *Depsgraph::find_node_from_pointer(const PointerRNA *ptr,
/* Node Management ---------------------------- */
+static void id_node_deleter(void *value)
+{
+ IDDepsNode *id_node = reinterpret_cast<IDDepsNode *>(value);
+ OBJECT_GUARDED_DELETE(id_node, IDDepsNode);
+}
+
RootDepsNode *Depsgraph::add_root_node()
{
if (!root_node) {
- DepsNodeFactory *factory = DEG_get_node_factory(DEPSNODE_TYPE_ROOT);
+ DepsNodeFactory *factory = deg_get_node_factory(DEPSNODE_TYPE_ROOT);
root_node = (RootDepsNode *)factory->create_node(NULL, "", "Root (Scene)");
}
return root_node;
@@ -267,12 +287,12 @@ TimeSourceDepsNode *Depsgraph::find_time_source(const ID *id) const
SubgraphDepsNode *Depsgraph::add_subgraph_node(const ID *id)
{
- DepsNodeFactory *factory = DEG_get_node_factory(DEPSNODE_TYPE_SUBGRAPH);
+ DepsNodeFactory *factory = deg_get_node_factory(DEPSNODE_TYPE_SUBGRAPH);
SubgraphDepsNode *subgraph_node =
(SubgraphDepsNode *)factory->create_node(id, "", id->name + 2);
/* Add to subnodes list. */
- this->subgraphs.insert(subgraph_node);
+ BLI_gset_insert(subgraphs, subgraph_node);
/* if there's an ID associated, add to ID-nodes lookup too */
if (id) {
@@ -289,37 +309,34 @@ SubgraphDepsNode *Depsgraph::add_subgraph_node(const ID *id)
void Depsgraph::remove_subgraph_node(SubgraphDepsNode *subgraph_node)
{
- subgraphs.erase(subgraph_node);
+ BLI_gset_remove(subgraphs, subgraph_node, NULL);
OBJECT_GUARDED_DELETE(subgraph_node, SubgraphDepsNode);
}
void Depsgraph::clear_subgraph_nodes()
{
- for (Subgraphs::iterator it = subgraphs.begin();
- it != subgraphs.end();
- ++it)
+ GSET_FOREACH_BEGIN(SubgraphDepsNode *, subgraph_node, subgraphs)
{
- SubgraphDepsNode *subgraph_node = *it;
OBJECT_GUARDED_DELETE(subgraph_node, SubgraphDepsNode);
}
- subgraphs.clear();
+ GSET_FOREACH_END();
+ BLI_gset_clear(subgraphs, NULL);
}
IDDepsNode *Depsgraph::find_id_node(const ID *id) const
{
- IDNodeMap::const_iterator it = this->id_hash.find(id);
- return it != this->id_hash.end() ? it->second : NULL;
+ return reinterpret_cast<IDDepsNode *>(BLI_ghash_lookup(id_hash, id));
}
IDDepsNode *Depsgraph::add_id_node(ID *id, const string &name)
{
IDDepsNode *id_node = find_id_node(id);
if (!id_node) {
- DepsNodeFactory *factory = DEG_get_node_factory(DEPSNODE_TYPE_ID_REF);
+ DepsNodeFactory *factory = deg_get_node_factory(DEPSNODE_TYPE_ID_REF);
id_node = (IDDepsNode *)factory->create_node(id, "", name);
id->tag |= LIB_TAG_DOIT;
/* register */
- this->id_hash[id] = id_node;
+ BLI_ghash_insert(id_hash, id, id_node);
}
return id_node;
}
@@ -329,21 +346,14 @@ void Depsgraph::remove_id_node(const ID *id)
IDDepsNode *id_node = find_id_node(id);
if (id_node) {
/* unregister */
- this->id_hash.erase(id);
+ BLI_ghash_remove(id_hash, id, NULL, NULL);
OBJECT_GUARDED_DELETE(id_node, IDDepsNode);
}
}
void Depsgraph::clear_id_nodes()
{
- for (IDNodeMap::const_iterator it = id_hash.begin();
- it != id_hash.end();
- ++it)
- {
- IDDepsNode *id_node = it->second;
- OBJECT_GUARDED_DELETE(id_node, IDDepsNode);
- }
- id_hash.clear();
+ BLI_ghash_clear(id_hash, NULL, id_node_deleter);
}
/* Add new relationship between two nodes. */
@@ -449,33 +459,52 @@ void Depsgraph::add_entry_tag(OperationDepsNode *node)
/* Add to graph-level set of directly modified nodes to start searching from.
* NOTE: this is necessary since we have several thousand nodes to play with...
*/
- this->entry_tags.insert(node);
+ BLI_gset_insert(entry_tags, node);
}
void Depsgraph::clear_all_nodes()
{
clear_id_nodes();
clear_subgraph_nodes();
- id_hash.clear();
+ BLI_ghash_clear(id_hash, NULL, NULL);
if (this->root_node) {
OBJECT_GUARDED_DELETE(this->root_node, RootDepsNode);
root_node = NULL;
}
}
+void deg_editors_id_update(Main *bmain, ID *id)
+{
+ if (deg_editor_update_id_cb != NULL) {
+ deg_editor_update_id_cb(bmain, id);
+ }
+}
+
+void deg_editors_scene_update(Main *bmain, Scene *scene, bool updated)
+{
+ if (deg_editor_update_scene_cb != NULL) {
+ deg_editor_update_scene_cb(bmain, scene, updated);
+ }
+}
+
+} // namespace DEG
+
/* **************** */
/* Public Graph API */
/* Initialize a new Depsgraph */
Depsgraph *DEG_graph_new()
{
- return OBJECT_GUARDED_NEW(Depsgraph);
+ DEG::Depsgraph *deg_depsgraph = OBJECT_GUARDED_NEW(DEG::Depsgraph);
+ return reinterpret_cast<Depsgraph *>(deg_depsgraph);
}
/* Free graph's contents and graph itself */
void DEG_graph_free(Depsgraph *graph)
{
- OBJECT_GUARDED_DELETE(graph, Depsgraph);
+ using DEG::Depsgraph;
+ DEG::Depsgraph *deg_depsgraph = reinterpret_cast<DEG::Depsgraph *>(graph);
+ OBJECT_GUARDED_DELETE(deg_depsgraph, Depsgraph);
}
/* Set callbacks which are being called when depsgraph changes. */
@@ -483,28 +512,14 @@ void DEG_editors_set_update_cb(DEG_EditorUpdateIDCb id_func,
DEG_EditorUpdateSceneCb scene_func,
DEG_EditorUpdateScenePreCb scene_pre_func)
{
- deg_editor_update_id_cb = id_func;
- deg_editor_update_scene_cb = scene_func;
- deg_editor_update_scene_pre_cb = scene_pre_func;
+ DEG::deg_editor_update_id_cb = id_func;
+ DEG::deg_editor_update_scene_cb = scene_func;
+ DEG::deg_editor_update_scene_pre_cb = scene_pre_func;
}
void DEG_editors_update_pre(Main *bmain, Scene *scene, bool time)
{
- if (deg_editor_update_scene_pre_cb != NULL) {
- deg_editor_update_scene_pre_cb(bmain, scene, time);
- }
-}
-
-void deg_editors_id_update(Main *bmain, ID *id)
-{
- if (deg_editor_update_id_cb != NULL) {
- deg_editor_update_id_cb(bmain, id);
- }
-}
-
-void deg_editors_scene_update(Main *bmain, Scene *scene, bool updated)
-{
- if (deg_editor_update_scene_cb != NULL) {
- deg_editor_update_scene_cb(bmain, scene, updated);
+ if (DEG::deg_editor_update_scene_pre_cb != NULL) {
+ DEG::deg_editor_update_scene_pre_cb(bmain, scene, time);
}
}
diff --git a/source/blender/depsgraph/intern/depsgraph.h b/source/blender/depsgraph/intern/depsgraph.h
index 9533fbd10d5..213bb304d73 100644
--- a/source/blender/depsgraph/intern/depsgraph.h
+++ b/source/blender/depsgraph/intern/depsgraph.h
@@ -34,19 +34,20 @@
* in the graph.
*/
-#ifndef __DEPSGRAPH_H__
-#define __DEPSGRAPH_H__
+#pragma once
#include "BLI_threads.h" /* for SpinLock */
-#include "depsgraph_types.h"
-
-#include "depsgraph_util_map.h"
-#include "depsgraph_util_set.h"
+#include "intern/depsgraph_types.h"
+struct ID;
+struct GHash;
+struct GSet;
struct PointerRNA;
struct PropertyRNA;
+namespace DEG {
+
struct DepsNode;
struct RootDepsNode;
struct TimeSourceDepsNode;
@@ -94,9 +95,6 @@ struct DepsRelation {
/* Dependency Graph object */
struct Depsgraph {
- typedef unordered_map<const ID *, IDDepsNode *> IDNodeMap;
- typedef unordered_set<SubgraphDepsNode *> Subgraphs;
- typedef unordered_set<OperationDepsNode *> EntryTags;
typedef vector<OperationDepsNode *> OperationNodes;
Depsgraph();
@@ -163,13 +161,13 @@ struct Depsgraph {
/* <ID : IDDepsNode> mapping from ID blocks to nodes representing these blocks
* (for quick lookups). */
- IDNodeMap id_hash;
+ GHash *id_hash;
/* "root" node - the one where all evaluation enters from. */
RootDepsNode *root_node;
/* Subgraphs referenced in tree. */
- Subgraphs subgraphs;
+ GSet *subgraphs;
/* Indicates whether relations needs to be updated. */
bool need_update;
@@ -177,7 +175,7 @@ struct Depsgraph {
/* Quick-Access Temp Data ............. */
/* Nodes which have been tagged as "directly modified". */
- EntryTags entry_tags;
+ GSet *entry_tags;
/* Convenience Data ................... */
@@ -198,27 +196,4 @@ struct Depsgraph {
// XXX: additional stuff like eval contexts, mempools for allocating nodes from, etc.
};
-/**
- * Helper macros for iterating over set of relationship links
- * incident on each node.
- *
- * \note it is safe to perform removal operations here...
- *
- * relations_set[in]: (DepsNode::Relations) set of relationships (in/out links)
- * relation[out]: (DepsRelation *) identifier where DepsRelation that we're
- * currently accessing comes up
- */
-#define DEPSNODE_RELATIONS_ITER_BEGIN(relations_set_, relation_) \
- { \
- OperationDepsNode::Relations::const_iterator __rel_iter = relations_set_.begin(); \
- while (__rel_iter != relations_set_.end()) { \
- DepsRelation *relation_ = *__rel_iter; \
- ++__rel_iter; \
-
- /* ... code for iterator body can be written here ... */
-
-#define DEPSNODE_RELATIONS_ITER_END \
- } \
- } ((void)0)
-
-#endif /* __DEPSGRAPH_H__ */
+} // namespace DEG
diff --git a/source/blender/depsgraph/intern/depsgraph_build.cc b/source/blender/depsgraph/intern/depsgraph_build.cc
index 877ce6e52e9..b1271c39851 100644
--- a/source/blender/depsgraph/intern/depsgraph_build.cc
+++ b/source/blender/depsgraph/intern/depsgraph_build.cc
@@ -30,137 +30,128 @@
* Methods for constructing depsgraph.
*/
-#include <stack>
-
#include "MEM_guardedalloc.h"
extern "C" {
-#include "BLI_blenlib.h"
-#include "BLI_string.h"
-#include "BLI_utildefines.h"
-
-#include "DNA_action_types.h"
-#include "DNA_anim_types.h"
-#include "DNA_armature_types.h"
-#include "DNA_camera_types.h"
-#include "DNA_constraint_types.h"
-#include "DNA_curve_types.h"
-#include "DNA_effect_types.h"
-#include "DNA_group_types.h"
-#include "DNA_key_types.h"
-#include "DNA_lamp_types.h"
-#include "DNA_material_types.h"
-#include "DNA_mesh_types.h"
-#include "DNA_meta_types.h"
-#include "DNA_node_types.h"
-#include "DNA_particle_types.h"
#include "DNA_object_types.h"
-#include "DNA_rigidbody_types.h"
#include "DNA_scene_types.h"
-#include "DNA_texture_types.h"
-#include "DNA_world_types.h"
-
-#include "BKE_action.h"
-#include "BKE_armature.h"
-#include "BKE_animsys.h"
-#include "BKE_constraint.h"
-#include "BKE_curve.h"
-#include "BKE_effect.h"
-#include "BKE_fcurve.h"
-#include "BKE_group.h"
-#include "BKE_key.h"
-#include "BKE_library.h"
+
+#include "BLI_utildefines.h"
+#include "BLI_ghash.h"
+
#include "BKE_main.h"
-#include "BKE_material.h"
-#include "BKE_mball.h"
-#include "BKE_modifier.h"
-#include "BKE_node.h"
-#include "BKE_object.h"
-#include "BKE_particle.h"
-#include "BKE_rigidbody.h"
-#include "BKE_sound.h"
-#include "BKE_texture.h"
-#include "BKE_tracking.h"
-#include "BKE_world.h"
#include "DEG_depsgraph.h"
#include "DEG_depsgraph_debug.h"
#include "DEG_depsgraph_build.h"
-#include "RNA_access.h"
-#include "RNA_types.h"
} /* extern "C" */
-#include "depsnode.h"
-#include "depsnode_component.h"
-#include "depsgraph_debug.h"
-#include "depsnode_operation.h"
-#include "depsgraph_types.h"
-#include "depsgraph_build.h"
-#include "depsgraph_intern.h"
+#include "builder/deg_builder.h"
+#include "builder/deg_builder_cycle.h"
+#include "builder/deg_builder_nodes.h"
+#include "builder/deg_builder_relations.h"
+#include "builder/deg_builder_transitive.h"
+
+#include "intern/nodes/deg_node.h"
+#include "intern/nodes/deg_node_component.h"
+#include "intern/nodes/deg_node_operation.h"
+
+#include "intern/depsgraph_types.h"
+#include "intern/depsgraph_intern.h"
-#include "depsgraph_util_cycle.h"
-#include "depsgraph_util_transitive.h"
+#include "util/deg_util_foreach.h"
/* ****************** */
/* External Build API */
-static eDepsNode_Type deg_build_scene_component_type(eDepsSceneComponentType component)
+static DEG::eDepsNode_Type deg_build_scene_component_type(
+ eDepsSceneComponentType component)
{
switch (component) {
- case DEG_SCENE_COMP_PARAMETERS: return DEPSNODE_TYPE_PARAMETERS;
- case DEG_SCENE_COMP_ANIMATION: return DEPSNODE_TYPE_ANIMATION;
- case DEG_SCENE_COMP_SEQUENCER: return DEPSNODE_TYPE_SEQUENCER;
+ case DEG_SCENE_COMP_PARAMETERS: return DEG::DEPSNODE_TYPE_PARAMETERS;
+ case DEG_SCENE_COMP_ANIMATION: return DEG::DEPSNODE_TYPE_ANIMATION;
+ case DEG_SCENE_COMP_SEQUENCER: return DEG::DEPSNODE_TYPE_SEQUENCER;
}
- return DEPSNODE_TYPE_UNDEFINED;
+ return DEG::DEPSNODE_TYPE_UNDEFINED;
}
-static eDepsNode_Type deg_build_object_component_type(eDepsObjectComponentType component)
+static DEG::eDepsNode_Type deg_build_object_component_type(
+ eDepsObjectComponentType component)
{
switch (component) {
- case DEG_OB_COMP_PARAMETERS: return DEPSNODE_TYPE_PARAMETERS;
- case DEG_OB_COMP_PROXY: return DEPSNODE_TYPE_PROXY;
- case DEG_OB_COMP_ANIMATION: return DEPSNODE_TYPE_ANIMATION;
- case DEG_OB_COMP_TRANSFORM: return DEPSNODE_TYPE_TRANSFORM;
- case DEG_OB_COMP_GEOMETRY: return DEPSNODE_TYPE_GEOMETRY;
- case DEG_OB_COMP_EVAL_POSE: return DEPSNODE_TYPE_EVAL_POSE;
- case DEG_OB_COMP_BONE: return DEPSNODE_TYPE_BONE;
- case DEG_OB_COMP_EVAL_PARTICLES: return DEPSNODE_TYPE_EVAL_PARTICLES;
- case DEG_OB_COMP_SHADING: return DEPSNODE_TYPE_SHADING;
+ case DEG_OB_COMP_PARAMETERS: return DEG::DEPSNODE_TYPE_PARAMETERS;
+ case DEG_OB_COMP_PROXY: return DEG::DEPSNODE_TYPE_PROXY;
+ case DEG_OB_COMP_ANIMATION: return DEG::DEPSNODE_TYPE_ANIMATION;
+ case DEG_OB_COMP_TRANSFORM: return DEG::DEPSNODE_TYPE_TRANSFORM;
+ case DEG_OB_COMP_GEOMETRY: return DEG::DEPSNODE_TYPE_GEOMETRY;
+ case DEG_OB_COMP_EVAL_POSE: return DEG::DEPSNODE_TYPE_EVAL_POSE;
+ case DEG_OB_COMP_BONE: return DEG::DEPSNODE_TYPE_BONE;
+ case DEG_OB_COMP_EVAL_PARTICLES: return DEG::DEPSNODE_TYPE_EVAL_PARTICLES;
+ case DEG_OB_COMP_SHADING: return DEG::DEPSNODE_TYPE_SHADING;
}
- return DEPSNODE_TYPE_UNDEFINED;
+ return DEG::DEPSNODE_TYPE_UNDEFINED;
}
-void DEG_add_scene_relation(DepsNodeHandle *handle, struct Scene *scene, eDepsSceneComponentType component, const char *description)
+static DEG::DepsNodeHandle *get_handle(DepsNodeHandle *handle)
{
- eDepsNode_Type type = deg_build_scene_component_type(component);
- ComponentKey comp_key(&scene->id, type);
- handle->builder->add_node_handle_relation(comp_key, handle, DEPSREL_TYPE_GEOMETRY_EVAL, description);
+ return reinterpret_cast<DEG::DepsNodeHandle *>(handle);
}
-void DEG_add_object_relation(DepsNodeHandle *handle, struct Object *ob, eDepsObjectComponentType component, const char *description)
+void DEG_add_scene_relation(DepsNodeHandle *handle,
+ Scene *scene,
+ eDepsSceneComponentType component,
+ const char *description)
{
- eDepsNode_Type type = deg_build_object_component_type(component);
- ComponentKey comp_key(&ob->id, type);
- handle->builder->add_node_handle_relation(comp_key, handle, DEPSREL_TYPE_GEOMETRY_EVAL, description);
+ DEG::eDepsNode_Type type = deg_build_scene_component_type(component);
+ DEG::ComponentKey comp_key(&scene->id, type);
+ DEG::DepsNodeHandle *deg_handle = get_handle(handle);
+ deg_handle->builder->add_node_handle_relation(comp_key,
+ deg_handle,
+ DEG::DEPSREL_TYPE_GEOMETRY_EVAL,
+ description);
}
-void DEG_add_bone_relation(DepsNodeHandle *handle, struct Object *ob, const char *bone_name, eDepsObjectComponentType component, const char *description)
+void DEG_add_object_relation(DepsNodeHandle *handle,
+ Object *ob,
+ eDepsObjectComponentType component,
+ const char *description)
{
- eDepsNode_Type type = deg_build_object_component_type(component);
- ComponentKey comp_key(&ob->id, type, bone_name);
+ DEG::eDepsNode_Type type = deg_build_object_component_type(component);
+ DEG::ComponentKey comp_key(&ob->id, type);
+ DEG::DepsNodeHandle *deg_handle = get_handle(handle);
+ deg_handle->builder->add_node_handle_relation(comp_key,
+ deg_handle,
+ DEG::DEPSREL_TYPE_GEOMETRY_EVAL,
+ description);
+}
- // XXX: "Geometry Eval" might not always be true, but this only gets called from modifier building now
- handle->builder->add_node_handle_relation(comp_key, handle, DEPSREL_TYPE_GEOMETRY_EVAL, description);
+void DEG_add_bone_relation(DepsNodeHandle *handle,
+ Object *ob,
+ const char *bone_name,
+ eDepsObjectComponentType component,
+ const char *description)
+{
+ DEG::eDepsNode_Type type = deg_build_object_component_type(component);
+ DEG::ComponentKey comp_key(&ob->id, type, bone_name);
+ DEG::DepsNodeHandle *deg_handle = get_handle(handle);
+ /* XXX: "Geometry Eval" might not always be true, but this only gets called
+ * from modifier building now.
+ */
+ deg_handle->builder->add_node_handle_relation(comp_key,
+ deg_handle,
+ DEG::DEPSREL_TYPE_GEOMETRY_EVAL,
+ description);
}
void DEG_add_special_eval_flag(Depsgraph *graph, ID *id, short flag)
{
+ DEG::Depsgraph *deg_graph = reinterpret_cast<DEG::Depsgraph *>(graph);
if (graph == NULL) {
BLI_assert(!"Graph should always be valid");
return;
}
- IDDepsNode *id_node = graph->find_id_node(id);
+ DEG::IDDepsNode *id_node = deg_graph->find_id_node(id);
if (id_node == NULL) {
BLI_assert(!"ID should always be valid");
return;
@@ -168,110 +159,21 @@ void DEG_add_special_eval_flag(Depsgraph *graph, ID *id, short flag)
id_node->eval_flags |= flag;
}
-/* ********************** */
-/* Utilities for Builders */
-
-/* Get unique identifier for FCurves and Drivers */
-string deg_fcurve_id_name(const FCurve *fcu)
-{
- char index_buf[32];
- sprintf(index_buf, "[%d]", fcu->array_index);
-
- return string(fcu->rna_path) + index_buf;
-}
-
-static void deg_graph_build_finalize(Depsgraph *graph)
-{
- std::stack<OperationDepsNode *> stack;
-
- for (Depsgraph::OperationNodes::const_iterator it_op = graph->operations.begin();
- it_op != graph->operations.end();
- ++it_op)
- {
- OperationDepsNode *node = *it_op;
- node->done = 0;
- node->num_links_pending = 0;
- for (OperationDepsNode::Relations::const_iterator it_rel = node->inlinks.begin();
- it_rel != node->inlinks.end();
- ++it_rel)
- {
- DepsRelation *rel = *it_rel;
- if ((rel->from->type == DEPSNODE_TYPE_OPERATION) &&
- (rel->flag & DEPSREL_FLAG_CYCLIC) == 0)
- {
- ++node->num_links_pending;
- }
- }
- if (node->num_links_pending == 0) {
- stack.push(node);
- }
- IDDepsNode *id_node = node->owner->owner;
- id_node->id->tag |= LIB_TAG_DOIT;
- }
-
- while (!stack.empty()) {
- OperationDepsNode *node = stack.top();
- if (node->done == 0 && node->outlinks.size() != 0) {
- for (OperationDepsNode::Relations::const_iterator it_rel = node->outlinks.begin();
- it_rel != node->outlinks.end();
- ++it_rel)
- {
- DepsRelation *rel = *it_rel;
- if (rel->to->type == DEPSNODE_TYPE_OPERATION) {
- OperationDepsNode *to = (OperationDepsNode *)rel->to;
- if ((rel->flag & DEPSREL_FLAG_CYCLIC) == 0) {
- BLI_assert(to->num_links_pending > 0);
- --to->num_links_pending;
- }
- if (to->num_links_pending == 0) {
- stack.push(to);
- }
- }
- }
- node->done = 1;
- }
- else {
- stack.pop();
- IDDepsNode *id_node = node->owner->owner;
- for (OperationDepsNode::Relations::const_iterator it_rel = node->outlinks.begin();
- it_rel != node->outlinks.end();
- ++it_rel)
- {
- DepsRelation *rel = *it_rel;
- if (rel->to->type == DEPSNODE_TYPE_OPERATION) {
- OperationDepsNode *to = (OperationDepsNode *)rel->to;
- IDDepsNode *id_to = to->owner->owner;
- id_node->layers |= id_to->layers;
- }
- }
- }
- }
-
- /* Re-tag IDs for update if it was tagged before the relations update tag. */
- for (Depsgraph::IDNodeMap::const_iterator it = graph->id_hash.begin();
- it != graph->id_hash.end();
- ++it)
- {
- IDDepsNode *id_node = it->second;
- ID *id = id_node->id;
- if (id->tag & LIB_TAG_ID_RECALC_ALL &&
- id->tag & LIB_TAG_DOIT)
- {
- id_node->tag_update(graph);
- id->tag &= ~LIB_TAG_DOIT;
- }
- }
-}
-
/* ******************** */
/* Graph Building API's */
-/* Build depsgraph for the given scene, and dump results in given graph container */
-// XXX: assume that this is called from outside, given the current scene as the "main" scene
+/* Build depsgraph for the given scene, and dump results in given
+ * graph container.
+ */
+/* XXX: assume that this is called from outside, given the current scene as
+ * the "main" scene.
+ */
void DEG_graph_build_from_scene(Depsgraph *graph, Main *bmain, Scene *scene)
{
+ DEG::Depsgraph *deg_graph = reinterpret_cast<DEG::Depsgraph *>(graph);
+
/* 1) Generate all the nodes in the graph first */
- DepsgraphNodeBuilder node_builder(bmain, graph);
+ DEG::DepsgraphNodeBuilder node_builder(bmain, deg_graph);
/* create root node for scene first
* - this way it should be the first in the graph,
* reflecting its role as the entrypoint
@@ -279,29 +181,40 @@ void DEG_graph_build_from_scene(Depsgraph *graph, Main *bmain, Scene *scene)
node_builder.add_root_node();
node_builder.build_scene(bmain, scene);
- /* 2) Hook up relationships between operations - to determine evaluation order */
- DepsgraphRelationBuilder relation_builder(graph);
- /* hook scene up to the root node as entrypoint to graph */
+ /* 2) Hook up relationships between operations - to determine evaluation
+ * order.
+ */
+ DEG::DepsgraphRelationBuilder relation_builder(deg_graph);
+ /* Hook scene up to the root node as entrypoint to graph. */
/* XXX what does this relation actually mean?
- * it doesnt add any operations anyway and is not clear what part of the scene is to be connected.
+ * it doesnt add any operations anyway and is not clear what part of the
+ * scene is to be connected.
*/
- //relation_builder.add_relation(RootKey(), IDKey(scene), DEPSREL_TYPE_ROOT_TO_ACTIVE, "Root to Active Scene");
+#if 0
+ relation_builder.add_relation(RootKey(),
+ IDKey(scene),
+ DEPSREL_TYPE_ROOT_TO_ACTIVE,
+ "Root to Active Scene");
+#endif
relation_builder.build_scene(bmain, scene);
/* Detect and solve cycles. */
- deg_graph_detect_cycles(graph);
+ DEG::deg_graph_detect_cycles(deg_graph);
- /* 3) Simplify the graph by removing redundant relations (to optimise traversal later) */
- // TODO: it would be useful to have an option to disable this in cases where it is causing trouble
+ /* 3) Simplify the graph by removing redundant relations (to optimize
+ * traversal later). */
+ /* TODO: it would be useful to have an option to disable this in cases where
+ * it is causing trouble.
+ */
if (G.debug_value == 799) {
- deg_graph_transitive_reduction(graph);
+ DEG::deg_graph_transitive_reduction(deg_graph);
}
/* 4) Flush visibility layer and re-schedule nodes for update. */
- deg_graph_build_finalize(graph);
+ DEG::deg_graph_build_finalize(deg_graph);
#if 0
- if (!DEG_debug_consistency_check(graph)) {
+ if (!DEG_debug_consistency_check(deg_graph)) {
printf("Consistency validation failed, ABORTING!\n");
abort();
}
@@ -311,7 +224,8 @@ void DEG_graph_build_from_scene(Depsgraph *graph, Main *bmain, Scene *scene)
/* Tag graph relations for update. */
void DEG_graph_tag_relations_update(Depsgraph *graph)
{
- graph->need_update = true;
+ DEG::Depsgraph *deg_graph = reinterpret_cast<DEG::Depsgraph *>(graph);
+ deg_graph->need_update = true;
}
/* Tag all relations for update. */
@@ -339,7 +253,7 @@ void DEG_scene_relations_update(Main *bmain, Scene *scene)
return;
}
- Depsgraph *graph = scene->depsgraph;
+ DEG::Depsgraph *graph = reinterpret_cast<DEG::Depsgraph *>(scene->depsgraph);
if (!graph->need_update) {
/* Graph is up to date, nothing to do. */
return;
@@ -348,10 +262,12 @@ void DEG_scene_relations_update(Main *bmain, Scene *scene)
/* Clear all previous nodes and operations. */
graph->clear_all_nodes();
graph->operations.clear();
- graph->entry_tags.clear();
+ BLI_gset_clear(graph->entry_tags, NULL);
/* Build new nodes and relations. */
- DEG_graph_build_from_scene(graph, bmain, scene);
+ DEG_graph_build_from_scene(reinterpret_cast< ::Depsgraph * >(graph),
+ bmain,
+ scene);
graph->need_update = false;
}
diff --git a/source/blender/depsgraph/intern/depsgraph_debug.cc b/source/blender/depsgraph/intern/depsgraph_debug.cc
index efb3e330857..d3b48930779 100644
--- a/source/blender/depsgraph/intern/depsgraph_debug.cc
+++ b/source/blender/depsgraph/intern/depsgraph_debug.cc
@@ -30,956 +30,39 @@
* Implementation of tools for debugging the depsgraph
*/
-//#include <stdlib.h>
-#include <string.h>
-
-extern "C" {
#include "BLI_utildefines.h"
-#include "BLI_listbase.h"
#include "BLI_ghash.h"
-#include "BLI_string.h"
+extern "C" {
#include "DNA_scene_types.h"
-#include "DNA_userdef_types.h"
#include "DEG_depsgraph.h"
#include "DEG_depsgraph_debug.h"
#include "DEG_depsgraph_build.h"
-
-#include "WM_api.h"
-#include "WM_types.h"
} /* extern "C" */
-#include "depsgraph_debug.h"
-#include "depsnode.h"
-#include "depsnode_component.h"
-#include "depsnode_operation.h"
-#include "depsgraph_intern.h"
-
-/* ****************** */
-/* Graphviz Debugging */
-
-#define NL "\r\n"
-
-/* Only one should be enabled, defines whether graphviz nodes
- * get colored by individual types or classes.
- */
-#define COLOR_SCHEME_NODE_CLASS 1
-//#define COLOR_SCHEME_NODE_TYPE 2
-
-static const char *deg_debug_graphviz_fontname = "helvetica";
-static float deg_debug_graphviz_graph_label_size = 20.0f;
-static float deg_debug_graphviz_node_label_size = 14.0f;
-static const int deg_debug_max_colors = 12;
-#if 0
-static const char *deg_debug_colors_dark[] = {
- "#6e8997", "#144f77", "#76945b",
- "#216a1d", "#a76665", "#971112",
- "#a87f49", "#0a9540", "#86768e",
- "#462866", "#a9a965", "#753b1a",
-};
-#endif
-#ifdef COLOR_SCHEME_NODE_TYPE
-static const char *deg_debug_colors[] = {
- "#a6cee3", "#1f78b4", "#b2df8a",
- "#33a02c", "#fb9a99", "#e31a1c",
- "#fdbf6f", "#ff7f00", "#cab2d6",
- "#6a3d9a", "#ffff99", "#b15928",
-};
-#endif
-static const char *deg_debug_colors_light[] = {
- "#8dd3c7", "#ffffb3", "#bebada",
- "#fb8072", "#80b1d3", "#fdb462",
- "#b3de69", "#fccde5", "#d9d9d9",
- "#bc80bd", "#ccebc5", "#ffed6f",
-};
-
-#ifdef COLOR_SCHEME_NODE_TYPE
-static const int deg_debug_node_type_color_map[][2] = {
- {DEPSNODE_TYPE_ROOT, 0},
- {DEPSNODE_TYPE_TIMESOURCE, 1},
- {DEPSNODE_TYPE_ID_REF, 2},
- {DEPSNODE_TYPE_SUBGRAPH, 3},
-
- /* Outer Types */
- {DEPSNODE_TYPE_PARAMETERS, 4},
- {DEPSNODE_TYPE_PROXY, 5},
- {DEPSNODE_TYPE_ANIMATION, 6},
- {DEPSNODE_TYPE_TRANSFORM, 7},
- {DEPSNODE_TYPE_GEOMETRY, 8},
- {DEPSNODE_TYPE_SEQUENCER, 9},
- {DEPSNODE_TYPE_SHADING, 10},
- {-1, 0}
-};
-#endif
-
-#if 0 /* unused */
-static const int deg_debug_relation_type_color_map[][2] = {
- {DEPSREL_TYPE_STANDARD, 0},
- {DEPSREL_TYPE_ROOT_TO_ACTIVE, 1},
- {DEPSREL_TYPE_DATABLOCK, 2},
- {DEPSREL_TYPE_TIME, 3},
- {DEPSREL_TYPE_COMPONENT_ORDER, 4},
- {DEPSREL_TYPE_OPERATION, 5},
- {DEPSREL_TYPE_DRIVER, 6},
- {DEPSREL_TYPE_DRIVER_TARGET, 7},
- {DEPSREL_TYPE_TRANSFORM, 8},
- {DEPSREL_TYPE_GEOMETRY_EVAL, 9},
- {DEPSREL_TYPE_UPDATE, 10},
- {DEPSREL_TYPE_UPDATE_UI, 11},
- {-1, 0}
-};
-#endif
-
-static int deg_debug_node_color_index(const DepsNode *node)
-{
-#ifdef COLOR_SCHEME_NODE_CLASS
- /* Some special types. */
- switch (node->type) {
- case DEPSNODE_TYPE_ID_REF:
- return 5;
- case DEPSNODE_TYPE_OPERATION:
- {
- OperationDepsNode *op_node = (OperationDepsNode *)node;
- if (op_node->is_noop())
- return 8;
- break;
- }
-
- default:
- break;
- }
- /* Do others based on class. */
- switch (node->tclass) {
- case DEPSNODE_CLASS_OPERATION:
- return 4;
- case DEPSNODE_CLASS_COMPONENT:
- return 1;
- default:
- return 9;
- }
-#endif
-
-#ifdef COLOR_SCHEME_NODE_TYPE
- const int (*pair)[2];
- for (pair = deg_debug_node_type_color_map; (*pair)[0] >= 0; ++pair) {
- if ((*pair)[0] == node->type) {
- return (*pair)[1];
- }
- }
- return -1;
-#endif
-}
-
-struct DebugContext {
- FILE *file;
- bool show_tags;
- bool show_eval_priority;
-};
-
-static void deg_debug_fprintf(const DebugContext &ctx, const char *fmt, ...) ATTR_PRINTF_FORMAT(2, 3);
-static void deg_debug_fprintf(const DebugContext &ctx, const char *fmt, ...)
-{
- va_list args;
- va_start(args, fmt);
- vfprintf(ctx.file, fmt, args);
- va_end(args);
-}
-
-static void deg_debug_graphviz_legend_color(const DebugContext &ctx,
- const char *name,
- const char *color)
-{
- deg_debug_fprintf(ctx, "<TR>");
- deg_debug_fprintf(ctx, "<TD>%s</TD>", name);
- deg_debug_fprintf(ctx, "<TD BGCOLOR=\"%s\"></TD>", color);
- deg_debug_fprintf(ctx, "</TR>" NL);
-}
-
-#if 0
-static void deg_debug_graphviz_legend_line(const DebugContext &ctx,
- const char *name,
- const char *color,
- const char *style)
-{
- /* XXX TODO */
- deg_debug_fprintf(ctx, "" NL);
-}
-
-static void deg_debug_graphviz_legend_cluster(const DebugContext &ctx,
- const char *name,
- const char *color,
- const char *style)
-{
- deg_debug_fprintf(ctx, "<TR>");
- deg_debug_fprintf(ctx, "<TD>%s</TD>", name);
- deg_debug_fprintf(ctx, "<TD CELLPADDING=\"4\"><TABLE BORDER=\"1\" CELLBORDER=\"0\" CELLSPACING=\"0\" CELLPADDING=\"0\">");
- deg_debug_fprintf(ctx, "<TR><TD BGCOLOR=\"%s\"></TD></TR>", color);
- deg_debug_fprintf(ctx, "</TABLE></TD>");
- deg_debug_fprintf(ctx, "</TR>" NL);
-}
-#endif
-
-static void deg_debug_graphviz_legend(const DebugContext &ctx)
-{
- deg_debug_fprintf(ctx, "{" NL);
- deg_debug_fprintf(ctx, "rank = sink;" NL);
- deg_debug_fprintf(ctx, "Legend [shape=none, margin=0, label=<" NL);
- deg_debug_fprintf(ctx, " <TABLE BORDER=\"0\" CELLBORDER=\"1\" CELLSPACING=\"0\" CELLPADDING=\"4\">" NL);
- deg_debug_fprintf(ctx, "<TR><TD COLSPAN=\"2\"><B>Legend</B></TD></TR>" NL);
-
-#ifdef COLOR_SCHEME_NODE_CLASS
- const char **colors = deg_debug_colors_light;
- deg_debug_graphviz_legend_color(ctx, "Operation", colors[4]);
- deg_debug_graphviz_legend_color(ctx, "Component", colors[1]);
- deg_debug_graphviz_legend_color(ctx, "ID Node", colors[5]);
- deg_debug_graphviz_legend_color(ctx, "NOOP", colors[8]);
-#endif
-
-#ifdef COLOR_SCHEME_NODE_TYPE
- const int (*pair)[2];
- for (pair = deg_debug_node_type_color_map; (*pair)[0] >= 0; ++pair) {
- DepsNodeFactory *nti = DEG_get_node_factory((eDepsNode_Type)(*pair)[0]);
- deg_debug_graphviz_legend_color(ctx,
- nti->tname().c_str(),
- deg_debug_colors_light[(*pair)[1] % deg_debug_max_colors]);
- }
-#endif
-
- deg_debug_fprintf(ctx, "</TABLE>" NL);
- deg_debug_fprintf(ctx, ">" NL);
- deg_debug_fprintf(ctx, ",fontname=\"%s\"", deg_debug_graphviz_fontname);
- deg_debug_fprintf(ctx, "];" NL);
- deg_debug_fprintf(ctx, "}" NL);
-}
-
-#if 0 /* unused */
-static int deg_debug_relation_type_color_index(eDepsRelation_Type type)
-{
- const int (*pair)[2];
- for (pair = deg_debug_relation_type_color_map; (*pair)[0] >= 0; ++pair) {
- if ((*pair)[0] == type) {
- return (*pair)[1];
- }
- }
- return -1;
-}
-#endif
-
-static void deg_debug_graphviz_node_color(const DebugContext &ctx,
- const DepsNode *node)
-{
- const char *color_default = "black";
- const char *color_modified = "orangered4";
- const char *color_update = "dodgerblue3";
- const char *color = color_default;
- if (ctx.show_tags) {
- if (node->tclass == DEPSNODE_CLASS_OPERATION) {
- OperationDepsNode *op_node = (OperationDepsNode *)node;
- if (op_node->flag & DEPSOP_FLAG_DIRECTLY_MODIFIED) {
- color = color_modified;
- }
- else if (op_node->flag & DEPSOP_FLAG_NEEDS_UPDATE) {
- color = color_update;
- }
- }
- }
- deg_debug_fprintf(ctx, "\"%s\"", color);
-}
-
-static void deg_debug_graphviz_node_penwidth(const DebugContext &ctx,
- const DepsNode *node)
-{
- float penwidth_default = 1.0f;
- float penwidth_modified = 4.0f;
- float penwidth_update = 4.0f;
- float penwidth = penwidth_default;
- if (ctx.show_tags) {
- if (node->tclass == DEPSNODE_CLASS_OPERATION) {
- OperationDepsNode *op_node = (OperationDepsNode *)node;
- if (op_node->flag & DEPSOP_FLAG_DIRECTLY_MODIFIED) {
- penwidth = penwidth_modified;
- }
- else if (op_node->flag & DEPSOP_FLAG_NEEDS_UPDATE) {
- penwidth = penwidth_update;
- }
- }
- }
- deg_debug_fprintf(ctx, "\"%f\"", penwidth);
-}
-
-static void deg_debug_graphviz_node_fillcolor(const DebugContext &ctx,
- const DepsNode *node)
-{
- const char *defaultcolor = "gainsboro";
- int color_index = deg_debug_node_color_index(node);
- const char *fillcolor = color_index < 0 ? defaultcolor : deg_debug_colors_light[color_index % deg_debug_max_colors];
- deg_debug_fprintf(ctx, "\"%s\"", fillcolor);
-}
-
-#if 0 /* implementation using stripes, a bit too noisy ... */
-static void deg_debug_graphviz_node_fillcolor(const DebugContext &ctx,
- const DepsNode *node)
-{
- const char *defaultcolor = "gainsboro";
- const char *color_needs_update = "orange";
- const int num_stripes = 10;
- int color_index = deg_debug_node_color_index(node);
- const char *base_color = color_index < 0 ? defaultcolor : deg_debug_colors_light[color_index % deg_debug_max_colors];
- if (ctx.show_tags &&
- (node->flag & (DEPSNODE_FLAG_DIRECTLY_MODIFIED | DEPSNODE_FLAG_NEEDS_UPDATE)))
- {
- deg_debug_fprintf(ctx, "\"");
- for (int i = 0; i < num_stripes; ++i) {
- if (i > 0) {
- deg_debug_fprintf(ctx, ":");
- }
- deg_debug_fprintf(ctx, "%s:%s", base_color, color_needs_update);
- }
- deg_debug_fprintf(ctx, "\"");
- }
- else {
- deg_debug_fprintf(ctx, "\"%s\"", base_color);
- }
-}
-#endif
-
-static void deg_debug_graphviz_relation_color(const DebugContext &ctx,
- const DepsRelation *rel)
-{
- const char *color_default = "black";
- const char *color_error = "red4";
- const char *color = color_default;
-#if 0 /* disabled for now, edge colors are hardly distinguishable */
- int color = deg_debug_relation_type_color_index(rel->type);
- if (color < 0) {
- deg_debug_fprintf(ctx, "%s", defaultcolor);
- }
- else {
- deg_debug_fprintf(ctx, "\"%s\"", deg_debug_colors_dark[color % deg_debug_max_colors]);
- }
-#else
- if (rel->flag & DEPSREL_FLAG_CYCLIC)
- color = color_error;
-
- deg_debug_fprintf(ctx, "%s", color);
-#endif
-}
-
-static void deg_debug_graphviz_node_style(const DebugContext &ctx, const DepsNode *node)
-{
- const char *base_style = "filled"; /* default style */
- if (ctx.show_tags) {
- if (node->tclass == DEPSNODE_CLASS_OPERATION) {
- OperationDepsNode *op_node = (OperationDepsNode *)node;
- if (op_node->flag & (DEPSOP_FLAG_DIRECTLY_MODIFIED | DEPSOP_FLAG_NEEDS_UPDATE)) {
- base_style = "striped";
- }
- }
- }
- switch (node->tclass) {
- case DEPSNODE_CLASS_GENERIC:
- deg_debug_fprintf(ctx, "\"%s\"", base_style);
- break;
- case DEPSNODE_CLASS_COMPONENT:
- deg_debug_fprintf(ctx, "\"%s\"", base_style);
- break;
- case DEPSNODE_CLASS_OPERATION:
- deg_debug_fprintf(ctx, "\"%s,rounded\"", base_style);
- break;
- }
-}
-
-static void deg_debug_graphviz_node_single(const DebugContext &ctx,
- const DepsNode *node)
-{
- const char *shape = "box";
- string name = node->identifier();
- float priority = -1.0f;
- if (node->type == DEPSNODE_TYPE_ID_REF) {
- IDDepsNode *id_node = (IDDepsNode *)node;
- char buf[256];
- BLI_snprintf(buf, sizeof(buf), " (Layers: %d)", id_node->layers);
- name += buf;
- }
- if (ctx.show_eval_priority && node->tclass == DEPSNODE_CLASS_OPERATION) {
- priority = ((OperationDepsNode *)node)->eval_priority;
- }
- deg_debug_fprintf(ctx, "// %s\n", name.c_str());
- deg_debug_fprintf(ctx, "\"node_%p\"", node);
- deg_debug_fprintf(ctx, "[");
-// deg_debug_fprintf(ctx, "label=<<B>%s</B>>", name);
- if (priority >= 0.0f) {
- deg_debug_fprintf(ctx, "label=<%s<BR/>(<I>%.2f</I>)>",
- name.c_str(),
- priority);
- }
- else {
- deg_debug_fprintf(ctx, "label=<%s>", name.c_str());
- }
- deg_debug_fprintf(ctx, ",fontname=\"%s\"", deg_debug_graphviz_fontname);
- deg_debug_fprintf(ctx, ",fontsize=%f", deg_debug_graphviz_node_label_size);
- deg_debug_fprintf(ctx, ",shape=%s", shape);
- deg_debug_fprintf(ctx, ",style="); deg_debug_graphviz_node_style(ctx, node);
- deg_debug_fprintf(ctx, ",color="); deg_debug_graphviz_node_color(ctx, node);
- deg_debug_fprintf(ctx, ",fillcolor="); deg_debug_graphviz_node_fillcolor(ctx, node);
- deg_debug_fprintf(ctx, ",penwidth="); deg_debug_graphviz_node_penwidth(ctx, node);
- deg_debug_fprintf(ctx, "];" NL);
- deg_debug_fprintf(ctx, NL);
-}
-
-static void deg_debug_graphviz_node_cluster_begin(const DebugContext &ctx,
- const DepsNode *node)
-{
- string name = node->identifier().c_str();
- if (node->type == DEPSNODE_TYPE_ID_REF) {
- IDDepsNode *id_node = (IDDepsNode *)node;
- char buf[256];
- BLI_snprintf(buf, sizeof(buf), " (Layers: %d)", id_node->layers);
- name += buf;
- }
- deg_debug_fprintf(ctx, "// %s\n", name.c_str());
- deg_debug_fprintf(ctx, "subgraph \"cluster_%p\" {" NL, node);
-// deg_debug_fprintf(ctx, "label=<<B>%s</B>>;" NL, name);
- deg_debug_fprintf(ctx, "label=<%s>;" NL, name.c_str());
- deg_debug_fprintf(ctx, "fontname=\"%s\";" NL, deg_debug_graphviz_fontname);
- deg_debug_fprintf(ctx, "fontsize=%f;" NL, deg_debug_graphviz_node_label_size);
- deg_debug_fprintf(ctx, "margin=\"%d\";" NL, 16);
- deg_debug_fprintf(ctx, "style="); deg_debug_graphviz_node_style(ctx, node); deg_debug_fprintf(ctx, ";" NL);
- deg_debug_fprintf(ctx, "color="); deg_debug_graphviz_node_color(ctx, node); deg_debug_fprintf(ctx, ";" NL);
- deg_debug_fprintf(ctx, "fillcolor="); deg_debug_graphviz_node_fillcolor(ctx, node); deg_debug_fprintf(ctx, ";" NL);
- deg_debug_fprintf(ctx, "penwidth="); deg_debug_graphviz_node_penwidth(ctx, node); deg_debug_fprintf(ctx, ";" NL);
- /* dummy node, so we can add edges between clusters */
- deg_debug_fprintf(ctx, "\"node_%p\"", node);
- deg_debug_fprintf(ctx, "[");
- deg_debug_fprintf(ctx, "shape=%s", "point");
- deg_debug_fprintf(ctx, ",style=%s", "invis");
- deg_debug_fprintf(ctx, "];" NL);
- deg_debug_fprintf(ctx, NL);
-}
-
-static void deg_debug_graphviz_node_cluster_end(const DebugContext &ctx)
-{
- deg_debug_fprintf(ctx, "}" NL);
- deg_debug_fprintf(ctx, NL);
-}
-
-static void deg_debug_graphviz_graph_nodes(const DebugContext &ctx,
- const Depsgraph *graph);
-static void deg_debug_graphviz_graph_relations(const DebugContext &ctx,
- const Depsgraph *graph);
-
-static void deg_debug_graphviz_node(const DebugContext &ctx,
- const DepsNode *node)
-{
- switch (node->type) {
- case DEPSNODE_TYPE_ID_REF:
- {
- const IDDepsNode *id_node = (const IDDepsNode *)node;
- if (id_node->components.empty()) {
- deg_debug_graphviz_node_single(ctx, node);
- }
- else {
- deg_debug_graphviz_node_cluster_begin(ctx, node);
- for (IDDepsNode::ComponentMap::const_iterator it = id_node->components.begin();
- it != id_node->components.end();
- ++it)
- {
- const ComponentDepsNode *comp = it->second;
- deg_debug_graphviz_node(ctx, comp);
- }
- deg_debug_graphviz_node_cluster_end(ctx);
- }
- break;
- }
- case DEPSNODE_TYPE_SUBGRAPH:
- {
- SubgraphDepsNode *sub_node = (SubgraphDepsNode *)node;
- if (sub_node->graph) {
- deg_debug_graphviz_node_cluster_begin(ctx, node);
- deg_debug_graphviz_graph_nodes(ctx, sub_node->graph);
- deg_debug_graphviz_node_cluster_end(ctx);
- }
- else {
- deg_debug_graphviz_node_single(ctx, node);
- }
- break;
- }
- case DEPSNODE_TYPE_PARAMETERS:
- case DEPSNODE_TYPE_ANIMATION:
- case DEPSNODE_TYPE_TRANSFORM:
- case DEPSNODE_TYPE_PROXY:
- case DEPSNODE_TYPE_GEOMETRY:
- case DEPSNODE_TYPE_SEQUENCER:
- case DEPSNODE_TYPE_EVAL_POSE:
- case DEPSNODE_TYPE_BONE:
- case DEPSNODE_TYPE_SHADING:
- case DEPSNODE_TYPE_EVAL_PARTICLES:
- {
- ComponentDepsNode *comp_node = (ComponentDepsNode *)node;
- if (!comp_node->operations.empty()) {
- deg_debug_graphviz_node_cluster_begin(ctx, node);
- for (ComponentDepsNode::OperationMap::const_iterator it = comp_node->operations.begin();
- it != comp_node->operations.end();
- ++it)
- {
- const DepsNode *op_node = it->second;
- deg_debug_graphviz_node(ctx, op_node);
- }
- deg_debug_graphviz_node_cluster_end(ctx);
- }
- else {
- deg_debug_graphviz_node_single(ctx, node);
- }
- break;
- }
- default:
- deg_debug_graphviz_node_single(ctx, node);
- break;
- }
-}
-
-static bool deg_debug_graphviz_is_cluster(const DepsNode *node)
-{
- switch (node->type) {
- case DEPSNODE_TYPE_ID_REF:
- {
- const IDDepsNode *id_node = (const IDDepsNode *)node;
- return !id_node->components.empty();
- }
- case DEPSNODE_TYPE_SUBGRAPH:
- {
- SubgraphDepsNode *sub_node = (SubgraphDepsNode *)node;
- return sub_node->graph != NULL;
- }
- case DEPSNODE_TYPE_PARAMETERS:
- case DEPSNODE_TYPE_ANIMATION:
- case DEPSNODE_TYPE_TRANSFORM:
- case DEPSNODE_TYPE_PROXY:
- case DEPSNODE_TYPE_GEOMETRY:
- case DEPSNODE_TYPE_SEQUENCER:
- case DEPSNODE_TYPE_EVAL_POSE:
- case DEPSNODE_TYPE_BONE:
- {
- ComponentDepsNode *comp_node = (ComponentDepsNode *)node;
- return !comp_node->operations.empty();
- }
- default:
- return false;
- }
-}
-
-static bool deg_debug_graphviz_is_owner(const DepsNode *node,
- const DepsNode *other)
-{
- switch (node->tclass) {
- case DEPSNODE_CLASS_COMPONENT:
- {
- ComponentDepsNode *comp_node = (ComponentDepsNode *)node;
- if (comp_node->owner == other)
- return true;
- break;
- }
- case DEPSNODE_CLASS_OPERATION:
- {
- OperationDepsNode *op_node = (OperationDepsNode *)node;
- if (op_node->owner == other)
- return true;
- else if (op_node->owner->owner == other)
- return true;
- break;
- }
- default: break;
- }
- return false;
-}
-
-static void deg_debug_graphviz_node_relations(const DebugContext &ctx,
- const DepsNode *node)
-{
- DEPSNODE_RELATIONS_ITER_BEGIN(node->inlinks, rel)
- {
- float penwidth = 2.0f;
-
- const DepsNode *tail = rel->to; /* same as node */
- const DepsNode *head = rel->from;
- deg_debug_fprintf(ctx, "// %s -> %s\n",
- head->identifier().c_str(),
- tail->identifier().c_str());
- deg_debug_fprintf(ctx, "\"node_%p\"", head);
- deg_debug_fprintf(ctx, " -> ");
- deg_debug_fprintf(ctx, "\"node_%p\"", tail);
-
- deg_debug_fprintf(ctx, "[");
- /* XXX labels on relations are not very helpful:
- * - they tend to appear too far away to be associated with the edge lines
- * - names are mostly redundant, reflecting simply their from/to nodes
- * - no behavior or typing of relations themselves to justify labels
- */
-#if 0
- deg_debug_fprintf(ctx, "label=\"%s\"", rel->name);
- deg_debug_fprintf(ctx, ",fontname=\"%s\"", deg_debug_graphviz_fontname);
-#else
- /* Note: without label an id seem necessary to avoid bugs in graphviz/dot */
- deg_debug_fprintf(ctx, "id=\"%s\"", rel->name);
-#endif
- deg_debug_fprintf(ctx, ",color="); deg_debug_graphviz_relation_color(ctx, rel);
- deg_debug_fprintf(ctx, ",penwidth=\"%f\"", penwidth);
- /* NOTE: edge from node to own cluster is not possible and gives graphviz
- * warning, avoid this here by just linking directly to the invisible
- * placeholder node
- */
- if (deg_debug_graphviz_is_cluster(tail) && !deg_debug_graphviz_is_owner(head, tail)) {
- deg_debug_fprintf(ctx, ",ltail=\"cluster_%p\"", tail);
- }
- if (deg_debug_graphviz_is_cluster(head) && !deg_debug_graphviz_is_owner(tail, head)) {
- deg_debug_fprintf(ctx, ",lhead=\"cluster_%p\"", head);
- }
- deg_debug_fprintf(ctx, "];" NL);
- deg_debug_fprintf(ctx, NL);
- }
- DEPSNODE_RELATIONS_ITER_END;
-
-#if 0
- if (node->tclass == DEPSNODE_CLASS_COMPONENT) {
- const ComponentDepsNode *comp_node = (const ComponentDepsNode *)node;
- for (ComponentDepsNode::OperationMap::const_iterator it = comp_node->operations.begin();
- it != comp_node->operations.end();
- ++it)
- {
- OperationDepsNode *op_node = it->second;
- deg_debug_graphviz_node_relations(ctx, op_node);
- }
- }
- else if (node->type == DEPSNODE_TYPE_ID_REF) {
- const IDDepsNode *id_node = (const IDDepsNode *)node;
- for (IDDepsNode::ComponentMap::const_iterator it = id_node->components.begin();
- it != id_node->components.end();
- ++it)
- {
- const ComponentDepsNode *comp = it->second;
- deg_debug_graphviz_node_relations(ctx, comp);
- }
- }
- else if (node->type == DEPSNODE_TYPE_SUBGRAPH) {
- SubgraphDepsNode *sub_node = (SubgraphDepsNode *)node;
- if (sub_node->graph) {
- deg_debug_graphviz_graph_relations(ctx, sub_node->graph);
- }
- }
-#endif
-}
-
-static void deg_debug_graphviz_graph_nodes(const DebugContext &ctx,
- const Depsgraph *graph)
-{
- if (graph->root_node) {
- deg_debug_graphviz_node(ctx, graph->root_node);
- }
- for (Depsgraph::IDNodeMap::const_iterator it = graph->id_hash.begin();
- it != graph->id_hash.end();
- ++it)
- {
- DepsNode *node = it->second;
- deg_debug_graphviz_node(ctx, node);
- }
- TimeSourceDepsNode *time_source = graph->find_time_source(NULL);
- if (time_source != NULL) {
- deg_debug_graphviz_node(ctx, time_source);
- }
-}
-
-static void deg_debug_graphviz_graph_relations(const DebugContext &ctx,
- const Depsgraph *graph)
-{
-#if 0
- if (graph->root_node) {
- deg_debug_graphviz_node_relations(ctx, graph->root_node);
- }
- for (Depsgraph::IDNodeMap::const_iterator it = graph->id_hash.begin();
- it != graph->id_hash.end();
- ++it)
- {
- DepsNode *id_node = it->second;
- deg_debug_graphviz_node_relations(ctx, id_node);
- }
-#else
- /* XXX not in use yet */
-// for (Depsgraph::OperationNodes::const_iterator it = graph->all_opnodes.begin();
-// it != graph->all_opnodes.end();
-// ++it)
-// {
-// OperationDepsNode *op_node = *it;
-// deg_debug_graphviz_node_relations(ctx, op_node);
-// }
- for (Depsgraph::IDNodeMap::const_iterator it = graph->id_hash.begin();
- it != graph->id_hash.end();
- ++it)
- {
- IDDepsNode *id_node = it->second;
- for (IDDepsNode::ComponentMap::const_iterator it = id_node->components.begin();
- it != id_node->components.end();
- ++it)
- {
- ComponentDepsNode *comp_node = it->second;
- for (ComponentDepsNode::OperationMap::const_iterator it = comp_node->operations.begin();
- it != comp_node->operations.end();
- ++it)
- {
- OperationDepsNode *op_node = it->second;
- deg_debug_graphviz_node_relations(ctx, op_node);
- }
- }
- }
-
- TimeSourceDepsNode *time_source = graph->find_time_source(NULL);
- if (time_source != NULL) {
- deg_debug_graphviz_node_relations(ctx, time_source);
- }
-#endif
-}
-
-void DEG_debug_graphviz(const Depsgraph *graph, FILE *f, const char *label, bool show_eval)
-{
-#if 0 /* generate shaded color set */
- static char colors[][3] = {{0xa6, 0xce, 0xe3},{0x1f, 0x78, 0xb4},{0xb2, 0xdf, 0x8a},{0x33, 0xa0, 0x2c},
- {0xfb, 0x9a, 0x99},{0xe3, 0x1a, 0x1c},{0xfd, 0xbf, 0x6f},{0xff, 0x7f, 0x00},
- {0xca, 0xb2, 0xd6},{0x6a, 0x3d, 0x9a},{0xff, 0xff, 0x99},{0xb1, 0x59, 0x28}};
- int i;
- const float factor = 0.666f;
- for (i=0; i < 12; ++i)
- printf("\"#%x%x%x\"\n", (char)(colors[i][0] * factor), (char)(colors[i][1] * factor), (char)(colors[i][2] * factor));
-#endif
-
- if (!graph) {
- return;
- }
-
- DebugContext ctx;
- ctx.file = f;
- ctx.show_tags = show_eval;
- ctx.show_eval_priority = show_eval;
-
- deg_debug_fprintf(ctx, "digraph depgraph {" NL);
- deg_debug_fprintf(ctx, "rankdir=LR;" NL);
- deg_debug_fprintf(ctx, "graph [");
- deg_debug_fprintf(ctx, "compound=true");
- deg_debug_fprintf(ctx, ",labelloc=\"t\"");
- deg_debug_fprintf(ctx, ",fontsize=%f", deg_debug_graphviz_graph_label_size);
- deg_debug_fprintf(ctx, ",fontname=\"%s\"", deg_debug_graphviz_fontname);
- deg_debug_fprintf(ctx, ",label=\"%s\"", label);
- deg_debug_fprintf(ctx, ",splines=ortho");
- deg_debug_fprintf(ctx, ",overlap=scalexy"); // XXX: only when using neato
- deg_debug_fprintf(ctx, "];" NL);
-
- deg_debug_graphviz_graph_nodes(ctx, graph);
- deg_debug_graphviz_graph_relations(ctx, graph);
-
- deg_debug_graphviz_legend(ctx);
-
- deg_debug_fprintf(ctx, "}" NL);
-}
-
-#undef NL
+#include "intern/eval/deg_eval_debug.h"
+#include "intern/depsgraph_intern.h"
+#include "util/deg_util_foreach.h"
/* ************************************************ */
-static string get_component_name(eDepsNode_Type type, const string &name = "")
-{
- DepsNodeFactory *factory = DEG_get_node_factory(type);
- if (name.empty()) {
- return string(factory->tname());
- }
- else {
- return string(factory->tname()) + " | " + name;
- }
-}
-
-static void times_clear(DepsgraphStatsTimes &times)
-{
- times.duration_last = 0.0f;
-}
-
-static void times_add(DepsgraphStatsTimes &times, float time)
-{
- times.duration_last += time;
-}
-
-void DepsgraphDebug::eval_begin(const EvaluationContext *UNUSED(eval_ctx))
-{
- /* TODO(sergey): Stats are currently globally disabled. */
- /* verify_stats(); */
- reset_stats();
-}
-
-void DepsgraphDebug::eval_end(const EvaluationContext *UNUSED(eval_ctx))
-{
- WM_main_add_notifier(NC_SPACE | ND_SPACE_INFO_REPORT, NULL);
-}
-
-void DepsgraphDebug::eval_step(const EvaluationContext *UNUSED(eval_ctx),
- const char *message)
-{
-#ifdef DEG_DEBUG_BUILD
- if (deg_debug_eval_cb)
- deg_debug_eval_cb(deg_debug_eval_userdata, message);
-#else
- (void)message; /* Ignored. */
-#endif
-}
-
-void DepsgraphDebug::task_started(Depsgraph *graph,
- const OperationDepsNode *node)
-{
- if (stats) {
- BLI_spin_lock(&graph->lock);
-
- ComponentDepsNode *comp = node->owner;
- ID *id = comp->owner->id;
-
- DepsgraphStatsID *id_stats = get_id_stats(id, true);
- times_clear(id_stats->times);
-
- /* XXX TODO use something like: if (id->flag & ID_DEG_DETAILS) {...} */
- if (0) {
- /* XXX component name usage needs cleanup! currently mixes identifier and description strings! */
- DepsgraphStatsComponent *comp_stats = get_component_stats(id, get_component_name(comp->type, comp->name), true);
- times_clear(comp_stats->times);
- }
-
- BLI_spin_unlock(&graph->lock);
- }
-}
-
-void DepsgraphDebug::task_completed(Depsgraph *graph,
- const OperationDepsNode *node,
- double time)
-{
- if (stats) {
- BLI_spin_lock(&graph->lock);
-
- ComponentDepsNode *comp = node->owner;
- ID *id = comp->owner->id;
-
- DepsgraphStatsID *id_stats = get_id_stats(id, true);
- times_add(id_stats->times, time);
-
- /* XXX TODO use something like: if (id->flag & ID_DEG_DETAILS) {...} */
- if (0) {
- /* XXX component name usage needs cleanup! currently mixes identifier and description strings! */
- DepsgraphStatsComponent *comp_stats = get_component_stats(id, get_component_name(comp->type, comp->name), true);
- times_add(comp_stats->times, time);
- }
-
- BLI_spin_unlock(&graph->lock);
- }
-}
-
-/* ********** */
-/* Statistics */
-
-DepsgraphStats *DepsgraphDebug::stats = NULL;
-
-/* GHash callback */
-static void deg_id_stats_free(void *val)
-{
- DepsgraphStatsID *id_stats = (DepsgraphStatsID *)val;
-
- if (id_stats) {
- BLI_freelistN(&id_stats->components);
- MEM_freeN(id_stats);
- }
-}
-
-void DepsgraphDebug::stats_init()
-{
- if (!stats) {
- stats = (DepsgraphStats *)MEM_callocN(sizeof(DepsgraphStats), "Depsgraph Stats");
- stats->id_stats = BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, "Depsgraph ID Stats Hash");
- }
-}
-
-void DepsgraphDebug::stats_free()
-{
- if (stats) {
- BLI_ghash_free(stats->id_stats, NULL, deg_id_stats_free);
- MEM_freeN(stats);
- stats = NULL;
- }
-}
-
-void DepsgraphDebug::verify_stats()
-{
- stats_init();
-}
-
-void DepsgraphDebug::reset_stats()
-{
- if (!stats) {
- return;
- }
-
- /* XXX this doesn't work, will immediately clear all info,
- * since most depsgraph updates have none or very few updates to handle.
- *
- * Could consider clearing only zero-user ID blocks here
- */
-// BLI_ghash_clear(stats->id_stats, NULL, deg_id_stats_free);
-}
-
-DepsgraphStatsID *DepsgraphDebug::get_id_stats(ID *id, bool create)
-{
- DepsgraphStatsID *id_stats = (DepsgraphStatsID *)BLI_ghash_lookup(stats->id_stats, id);
-
- if (!id_stats && create) {
- id_stats = (DepsgraphStatsID *)MEM_callocN(sizeof(DepsgraphStatsID), "Depsgraph ID Stats");
- id_stats->id = id;
-
- BLI_ghash_insert(stats->id_stats, id, id_stats);
- }
-
- return id_stats;
-}
-
-DepsgraphStatsComponent *DepsgraphDebug::get_component_stats(
- DepsgraphStatsID *id_stats,
- const string &name,
- bool create)
-{
- DepsgraphStatsComponent *comp_stats;
- for (comp_stats = (DepsgraphStatsComponent *)id_stats->components.first;
- comp_stats != NULL;
- comp_stats = comp_stats->next)
- {
- if (STREQ(comp_stats->name, name.c_str()))
- break;
- }
- if (!comp_stats && create) {
- comp_stats = (DepsgraphStatsComponent *)MEM_callocN(sizeof(DepsgraphStatsComponent), "Depsgraph Component Stats");
- BLI_strncpy(comp_stats->name, name.c_str(), sizeof(comp_stats->name));
- BLI_addtail(&id_stats->components, comp_stats);
- }
- return comp_stats;
-}
-
-/* ------------------------------------------------ */
-
DepsgraphStats *DEG_stats(void)
{
- return DepsgraphDebug::stats;
+ return DEG::DepsgraphDebug::stats;
}
void DEG_stats_verify()
{
- DepsgraphDebug::verify_stats();
+ DEG::DepsgraphDebug::verify_stats();
}
DepsgraphStatsID *DEG_stats_id(ID *id)
{
- if (!DepsgraphDebug::stats) {
+ if (!DEG::DepsgraphDebug::stats) {
return NULL;
}
- return DepsgraphDebug::get_id_stats(id, false);
+ return DEG::DepsgraphDebug::get_id_stats(id, false);
}
bool DEG_debug_compare(const struct Depsgraph *graph1,
@@ -987,7 +70,9 @@ bool DEG_debug_compare(const struct Depsgraph *graph1,
{
BLI_assert(graph1 != NULL);
BLI_assert(graph2 != NULL);
- if (graph1->operations.size() != graph2->operations.size()) {
+ const DEG::Depsgraph *deg_graph1 = reinterpret_cast<const DEG::Depsgraph *>(graph1);
+ const DEG::Depsgraph *deg_graph2 = reinterpret_cast<const DEG::Depsgraph *>(graph2);
+ if (deg_graph1->operations.size() != deg_graph2->operations.size()) {
return false;
}
/* TODO(sergey): Currently we only do real stupid check,
@@ -1017,34 +102,21 @@ bool DEG_debug_scene_relations_validate(Main *bmain,
bool DEG_debug_consistency_check(Depsgraph *graph)
{
- /* Validate links exists in both directions. */
- for (Depsgraph::OperationNodes::const_iterator it_op = graph->operations.begin();
- it_op != graph->operations.end();
- ++it_op)
- {
- OperationDepsNode *node = *it_op;
- for (OperationDepsNode::Relations::const_iterator it_rel = node->outlinks.begin();
- it_rel != node->outlinks.end();
- ++it_rel)
- {
- DepsRelation *rel = *it_rel;
+ const DEG::Depsgraph *deg_graph = reinterpret_cast<const DEG::Depsgraph *>(graph);
+ /* Validate links exists in both directions. */
+ foreach (DEG::OperationDepsNode *node, deg_graph->operations) {
+ foreach (DEG::DepsRelation *rel, node->outlinks) {
int counter1 = 0;
- for (OperationDepsNode::Relations::const_iterator tmp_rel = node->outlinks.begin();
- tmp_rel != node->outlinks.end();
- ++tmp_rel)
- {
- if (*tmp_rel == rel) {
+ foreach (DEG::DepsRelation *tmp_rel, node->outlinks) {
+ if (tmp_rel == rel) {
++counter1;
}
}
int counter2 = 0;
- for (OperationDepsNode::Relations::const_iterator tmp_rel = rel->to->inlinks.begin();
- tmp_rel != rel->to->inlinks.end();
- ++tmp_rel)
- {
- if (*tmp_rel == rel) {
+ foreach (DEG::DepsRelation *tmp_rel, rel->to->inlinks) {
+ if (tmp_rel == rel) {
++counter2;
}
}
@@ -1057,33 +129,18 @@ bool DEG_debug_consistency_check(Depsgraph *graph)
}
}
- for (Depsgraph::OperationNodes::const_iterator it_op = graph->operations.begin();
- it_op != graph->operations.end();
- ++it_op)
- {
- OperationDepsNode *node = *it_op;
- for (OperationDepsNode::Relations::const_iterator it_rel = node->inlinks.begin();
- it_rel != node->inlinks.end();
- ++it_rel)
- {
- DepsRelation *rel = *it_rel;
-
+ foreach (DEG::OperationDepsNode *node, deg_graph->operations) {
+ foreach (DEG::DepsRelation *rel, node->inlinks) {
int counter1 = 0;
- for (OperationDepsNode::Relations::const_iterator tmp_rel = node->inlinks.begin();
- tmp_rel != node->inlinks.end();
- ++tmp_rel)
- {
- if (*tmp_rel == rel) {
+ foreach (DEG::DepsRelation *tmp_rel, node->inlinks) {
+ if (tmp_rel == rel) {
++counter1;
}
}
int counter2 = 0;
- for (OperationDepsNode::Relations::const_iterator tmp_rel = rel->from->outlinks.begin();
- tmp_rel != rel->from->outlinks.end();
- ++tmp_rel)
- {
- if (*tmp_rel == rel) {
+ foreach (DEG::DepsRelation *tmp_rel, rel->from->outlinks) {
+ if (tmp_rel == rel) {
++counter2;
}
}
@@ -1096,32 +153,20 @@ bool DEG_debug_consistency_check(Depsgraph *graph)
}
/* Validate node valency calculated in both directions. */
- for (Depsgraph::OperationNodes::const_iterator it_op = graph->operations.begin();
- it_op != graph->operations.end();
- ++it_op)
- {
- OperationDepsNode *node = *it_op;
+ foreach (DEG::OperationDepsNode *node, deg_graph->operations) {
node->num_links_pending = 0;
node->done = 0;
}
- for (Depsgraph::OperationNodes::const_iterator it_op = graph->operations.begin();
- it_op != graph->operations.end();
- ++it_op)
- {
- OperationDepsNode *node = *it_op;
+ foreach (DEG::OperationDepsNode *node, deg_graph->operations) {
if (node->done) {
printf("Node %s is twice in the operations!\n",
node->identifier().c_str());
return false;
}
- for (OperationDepsNode::Relations::const_iterator it_rel = node->outlinks.begin();
- it_rel != node->outlinks.end();
- ++it_rel)
- {
- DepsRelation *rel = *it_rel;
- if (rel->to->type == DEPSNODE_TYPE_OPERATION) {
- OperationDepsNode *to = (OperationDepsNode *)rel->to;
+ foreach (DEG::DepsRelation *rel, node->outlinks) {
+ if (rel->to->type == DEG::DEPSNODE_TYPE_OPERATION) {
+ DEG::OperationDepsNode *to = (DEG::OperationDepsNode *)rel->to;
BLI_assert(to->num_links_pending < to->inlinks.size());
++to->num_links_pending;
}
@@ -1129,18 +174,10 @@ bool DEG_debug_consistency_check(Depsgraph *graph)
node->done = 1;
}
- for (Depsgraph::OperationNodes::const_iterator it_op = graph->operations.begin();
- it_op != graph->operations.end();
- ++it_op)
- {
- OperationDepsNode *node = *it_op;
+ foreach (DEG::OperationDepsNode *node, deg_graph->operations) {
int num_links_pending = 0;
- for (OperationDepsNode::Relations::const_iterator it_rel = node->inlinks.begin();
- it_rel != node->inlinks.end();
- ++it_rel)
- {
- DepsRelation *rel = *it_rel;
- if (rel->from->type == DEPSNODE_TYPE_OPERATION) {
+ foreach (DEG::DepsRelation *rel, node->inlinks) {
+ if (rel->from->type == DEG::DEPSNODE_TYPE_OPERATION) {
++num_links_pending;
}
}
@@ -1166,12 +203,14 @@ bool DEG_debug_consistency_check(Depsgraph *graph)
void DEG_stats_simple(const Depsgraph *graph, size_t *r_outer,
size_t *r_operations, size_t *r_relations)
{
+ const DEG::Depsgraph *deg_graph = reinterpret_cast<const DEG::Depsgraph *>(graph);
+
/* number of operations */
if (r_operations) {
/* All operations should be in this list, allowing us to count the total
* number of nodes.
*/
- *r_operations = graph->operations.size();
+ *r_operations = deg_graph->operations.size();
}
/* Count number of outer nodes and/or relations between these. */
@@ -1179,29 +218,21 @@ void DEG_stats_simple(const Depsgraph *graph, size_t *r_outer,
size_t tot_outer = 0;
size_t tot_rels = 0;
- for (Depsgraph::IDNodeMap::const_iterator it = graph->id_hash.begin();
- it != graph->id_hash.end();
- ++it)
+ GHASH_FOREACH_BEGIN(DEG::IDDepsNode *, id_node, deg_graph->id_hash)
{
- IDDepsNode *id_node = it->second;
tot_outer++;
- for (IDDepsNode::ComponentMap::const_iterator it = id_node->components.begin();
- it != id_node->components.end();
- ++it)
+ GHASH_FOREACH_BEGIN(DEG::ComponentDepsNode *, comp_node, id_node->components)
{
- ComponentDepsNode *comp_node = it->second;
tot_outer++;
- for (ComponentDepsNode::OperationMap::const_iterator it = comp_node->operations.begin();
- it != comp_node->operations.end();
- ++it)
- {
- OperationDepsNode *op_node = it->second;
+ foreach (DEG::OperationDepsNode *op_node, comp_node->operations) {
tot_rels += op_node->inlinks.size();
}
}
+ GHASH_FOREACH_END();
}
+ GHASH_FOREACH_END();
- TimeSourceDepsNode *time_source = graph->find_time_source(NULL);
+ DEG::TimeSourceDepsNode *time_source = deg_graph->find_time_source(NULL);
if (time_source != NULL) {
tot_rels += time_source->inlinks.size();
}
@@ -1210,4 +241,3 @@ void DEG_stats_simple(const Depsgraph *graph, size_t *r_outer,
if (r_outer) *r_outer = tot_outer;
}
}
-
diff --git a/source/blender/depsgraph/intern/depsgraph_eval.cc b/source/blender/depsgraph/intern/depsgraph_eval.cc
index 66535f5214b..f8d40d0e6a8 100644
--- a/source/blender/depsgraph/intern/depsgraph_eval.cc
+++ b/source/blender/depsgraph/intern/depsgraph_eval.cc
@@ -32,11 +32,9 @@
#include "MEM_guardedalloc.h"
-#include "PIL_time.h"
-
extern "C" {
#include "BLI_utildefines.h"
-#include "BLI_task.h"
+#include "BLI_ghash.h"
#include "BKE_depsgraph.h"
#include "BKE_scene.h"
@@ -44,13 +42,13 @@ extern "C" {
#include "DEG_depsgraph.h"
} /* extern "C" */
-#include "atomic_ops.h"
+#include "intern/eval/deg_eval.h"
+#include "intern/eval/deg_eval_flush.h"
+
+#include "intern/nodes/deg_node.h"
+#include "intern/nodes/deg_node_operation.h"
-#include "depsgraph.h"
-#include "depsnode.h"
-#include "depsnode_component.h"
-#include "depsnode_operation.h"
-#include "depsgraph_debug.h"
+#include "intern/depsgraph.h"
#ifdef WITH_LEGACY_DEPSGRAPH
static bool use_legacy_depsgraph = true;
@@ -118,359 +116,16 @@ void DEG_evaluation_context_free(EvaluationContext *eval_ctx)
MEM_freeN(eval_ctx);
}
-/* ********************** */
-/* Evaluation Entrypoints */
-
-/* Forward declarations. */
-static void schedule_children(TaskPool *pool,
- Depsgraph *graph,
- OperationDepsNode *node,
- const int layers,
- const int thread_id);
-
-struct DepsgraphEvalState {
- EvaluationContext *eval_ctx;
- Depsgraph *graph;
- int layers;
-};
-
-static void deg_task_run_func(TaskPool *pool,
- void *taskdata,
- int thread_id)
-{
- DepsgraphEvalState *state = (DepsgraphEvalState *)BLI_task_pool_userdata(pool);
- OperationDepsNode *node = (OperationDepsNode *)taskdata;
-
- BLI_assert(!node->is_noop() && "NOOP nodes should not actually be scheduled");
-
- /* Should only be the case for NOOPs, which never get to this point. */
- BLI_assert(node->evaluate);
-
- while (true) {
- /* Get context. */
- // TODO: who initialises this? "Init" operations aren't able to initialise it!!!
- /* TODO(sergey): We don't use component contexts at this moment. */
- /* ComponentDepsNode *comp = node->owner; */
- BLI_assert(node->owner != NULL);
-
- /* Since we're not leaving the thread for until the graph branches it is
- * possible to have NO-OP on the way. for which evaluate() will be NULL.
- * but that's all fine, we'll just scheduler it's children.
- */
- if (node->evaluate) {
- /* Take note of current time. */
- double start_time = PIL_check_seconds_timer();
- DepsgraphDebug::task_started(state->graph, node);
-
- /* Perform operation. */
- node->evaluate(state->eval_ctx);
-
- /* Note how long this took. */
- double end_time = PIL_check_seconds_timer();
- DepsgraphDebug::task_completed(state->graph,
- node,
- end_time - start_time);
- }
-
- /* If there's only one outgoing link we try to immediately switch to
- * that node evaluation, without leaving the thread.
- *
- * It's only doable if the child don't have extra relations or all they
- * are satisfied.
- *
- * TODO(sergey): Checks here can be de-duplicated with the ones from
- * schedule_node(), however, how to do it nicely?
- */
- if (node->outlinks.size() == 1) {
- DepsRelation *rel = node->outlinks[0];
- OperationDepsNode *child = (OperationDepsNode *)rel->to;
- BLI_assert(child->type == DEPSNODE_TYPE_OPERATION);
- if (!child->scheduled) {
- int id_layers = child->owner->owner->layers;
- if (!((child->flag & DEPSOP_FLAG_NEEDS_UPDATE) != 0 &&
- (id_layers & state->layers) != 0))
- {
- /* Node does not need an update, so can;t continue with the
- * chain and need to switch to another one by leaving the
- * thread.
- */
- break;
- }
- if ((rel->flag & DEPSREL_FLAG_CYCLIC) == 0) {
- BLI_assert(child->num_links_pending > 0);
- atomic_sub_uint32(&child->num_links_pending, 1);
- }
- if (child->num_links_pending == 0) {
- bool is_scheduled = atomic_fetch_and_or_uint8((uint8_t *)&child->scheduled, (uint8_t)true);
- if (!is_scheduled) {
- /* Node was not scheduled, switch to it! */
- node = child;
- }
- else {
- /* Someone else scheduled the node, leaving us
- * unemployed in this thread, we're leaving.
- */
- break;
- }
- }
- else {
- /* There are other dependencies on the child, can't do
- * anything in the current thread.
- */
- break;
- }
- }
- else {
- /* Happens when having cyclic dependencies.
- *
- * Nothing to do here, single child was already scheduled, we
- * can leave the thread now.
- */
- break;
- }
- }
- else {
- /* TODO(sergey): It's possible to use one of the outgoing relations
- * as a chain which we'll try to keep alive, but it's a bit more
- * involved change.
- */
- schedule_children(pool, state->graph, node, state->layers, thread_id);
- break;
- }
- }
-}
-
-typedef struct CalculatePengindData {
- Depsgraph *graph;
- int layers;
-} CalculatePengindData;
-
-static void calculate_pending_func(void *data_v, int i)
-{
- CalculatePengindData *data = (CalculatePengindData *)data_v;
- Depsgraph *graph = data->graph;
- int layers = data->layers;
- OperationDepsNode *node = graph->operations[i];
- IDDepsNode *id_node = node->owner->owner;
-
- node->num_links_pending = 0;
- node->scheduled = false;
-
- /* count number of inputs that need updates */
- if ((id_node->layers & layers) != 0 &&
- (node->flag & DEPSOP_FLAG_NEEDS_UPDATE) != 0)
- {
- DEPSNODE_RELATIONS_ITER_BEGIN(node->inlinks, rel)
- {
- if (rel->from->type == DEPSNODE_TYPE_OPERATION &&
- (rel->flag & DEPSREL_FLAG_CYCLIC) == 0)
- {
- OperationDepsNode *from = (OperationDepsNode *)rel->from;
- IDDepsNode *id_from_node = from->owner->owner;
- if ((id_from_node->layers & layers) != 0 &&
- (from->flag & DEPSOP_FLAG_NEEDS_UPDATE) != 0)
- {
- ++node->num_links_pending;
- }
- }
- }
- DEPSNODE_RELATIONS_ITER_END;
- }
-}
-
-static void calculate_pending_parents(Depsgraph *graph, int layers)
-{
- const int num_operations = graph->operations.size();
- const bool do_threads = num_operations > 256;
- CalculatePengindData data;
- data.graph = graph;
- data.layers = layers;
- BLI_task_parallel_range(0, num_operations, &data, calculate_pending_func, do_threads);
-}
-
-#ifdef USE_EVAL_PRIORITY
-static void calculate_eval_priority(OperationDepsNode *node)
-{
- if (node->done) {
- return;
- }
- node->done = 1;
-
- if (node->flag & DEPSOP_FLAG_NEEDS_UPDATE) {
- /* XXX standard cost of a node, could be estimated somewhat later on */
- const float cost = 1.0f;
- /* NOOP nodes have no cost */
- node->eval_priority = node->is_noop() ? cost : 0.0f;
-
- for (OperationDepsNode::Relations::const_iterator it = node->outlinks.begin();
- it != node->outlinks.end();
- ++it)
- {
- DepsRelation *rel = *it;
- OperationDepsNode *to = (OperationDepsNode *)rel->to;
- BLI_assert(to->type == DEPSNODE_TYPE_OPERATION);
- calculate_eval_priority(to);
- node->eval_priority += to->eval_priority;
- }
- }
- else {
- node->eval_priority = 0.0f;
- }
-}
-#endif
-
-/* Schedule a node if it needs evaluation.
- * dec_parents: Decrement pending parents count, true when child nodes are scheduled
- * after a task has been completed.
- */
-static void schedule_node(TaskPool *pool, Depsgraph *graph, int layers,
- OperationDepsNode *node, bool dec_parents,
- const int thread_id)
-{
- int id_layers = node->owner->owner->layers;
-
- if ((node->flag & DEPSOP_FLAG_NEEDS_UPDATE) != 0 &&
- (id_layers & layers) != 0)
- {
- if (dec_parents) {
- BLI_assert(node->num_links_pending > 0);
- atomic_sub_uint32(&node->num_links_pending, 1);
- }
-
- if (node->num_links_pending == 0) {
- bool is_scheduled = atomic_fetch_and_or_uint8((uint8_t *)&node->scheduled, (uint8_t)true);
- if (!is_scheduled) {
- if (node->is_noop()) {
- /* skip NOOP node, schedule children right away */
- schedule_children(pool, graph, node, layers, thread_id);
- }
- else {
- /* children are scheduled once this task is completed */
- BLI_task_pool_push_from_thread(pool,
- deg_task_run_func,
- node,
- false,
- TASK_PRIORITY_LOW,
- thread_id);
- }
- }
- }
- }
-}
-
-static void schedule_graph(TaskPool *pool,
- Depsgraph *graph,
- const int layers)
-{
- for (Depsgraph::OperationNodes::const_iterator it = graph->operations.begin();
- it != graph->operations.end();
- ++it)
- {
- OperationDepsNode *node = *it;
- schedule_node(pool, graph, layers, node, false, 0);
- }
-}
-
-static void schedule_children(TaskPool *pool,
- Depsgraph *graph,
- OperationDepsNode *node,
- const int layers,
- const int thread_id)
-{
- DEPSNODE_RELATIONS_ITER_BEGIN(node->outlinks, rel)
- {
- OperationDepsNode *child = (OperationDepsNode *)rel->to;
- BLI_assert(child->type == DEPSNODE_TYPE_OPERATION);
- if (child->scheduled) {
- /* Happens when having cyclic dependencies. */
- continue;
- }
- schedule_node(pool, graph, layers, child, (rel->flag & DEPSREL_FLAG_CYCLIC) == 0, thread_id);
- }
- DEPSNODE_RELATIONS_ITER_END;
-}
-
-/**
- * Evaluate all nodes tagged for updating,
- * \warning This is usually done as part of main loop, but may also be
- * called from frame-change update.
- *
- * \note Time sources should be all valid!
- */
-void DEG_evaluate_on_refresh_ex(EvaluationContext *eval_ctx,
- Depsgraph *graph,
- const int layers)
-{
- /* Generate base evaluation context, upon which all the others are derived. */
- // TODO: this needs both main and scene access...
-
- /* Nothing to update, early out. */
- if (graph->entry_tags.size() == 0) {
- return;
- }
-
- /* Set time for the current graph evaluation context. */
- TimeSourceDepsNode *time_src = graph->find_time_source();
- eval_ctx->ctime = time_src->cfra;
-
- /* XXX could use a separate pool for each eval context */
- DepsgraphEvalState state;
- state.eval_ctx = eval_ctx;
- state.graph = graph;
- state.layers = layers;
-
- TaskScheduler *task_scheduler = BLI_task_scheduler_get();
- TaskPool *task_pool = BLI_task_pool_create(task_scheduler, &state);
-
- if (G.debug & G_DEBUG_DEPSGRAPH_NO_THREADS) {
- BLI_pool_set_num_threads(task_pool, 1);
- }
-
- calculate_pending_parents(graph, layers);
-
- /* Clear tags. */
- for (Depsgraph::OperationNodes::const_iterator it = graph->operations.begin();
- it != graph->operations.end();
- ++it)
- {
- OperationDepsNode *node = *it;
- node->done = 0;
- }
-
- /* Calculate priority for operation nodes. */
-#ifdef USE_EVAL_PRIORITY
- for (Depsgraph::OperationNodes::const_iterator it = graph->operations.begin();
- it != graph->operations.end();
- ++it)
- {
- OperationDepsNode *node = *it;
- calculate_eval_priority(node);
- }
-#endif
-
- DepsgraphDebug::eval_begin(eval_ctx);
-
- schedule_graph(task_pool, graph, layers);
-
- BLI_task_pool_work_and_wait(task_pool);
- BLI_task_pool_free(task_pool);
-
- DepsgraphDebug::eval_end(eval_ctx);
-
- /* Clear any uncleared tags - just in case. */
- DEG_graph_clear_tags(graph);
-}
-
/* Evaluate all nodes tagged for updating. */
void DEG_evaluate_on_refresh(EvaluationContext *eval_ctx,
Depsgraph *graph,
Scene *scene)
{
+ DEG::Depsgraph *deg_graph = reinterpret_cast<DEG::Depsgraph *>(graph);
/* Update time on primary timesource. */
- TimeSourceDepsNode *tsrc = graph->find_time_source();
+ DEG::TimeSourceDepsNode *tsrc = deg_graph->find_time_source();
tsrc->cfra = BKE_scene_frame_get(scene);
-
- DEG_evaluate_on_refresh_ex(eval_ctx, graph, graph->layers);
+ DEG::deg_evaluate_on_refresh(eval_ctx, deg_graph, deg_graph->layers);
}
/* Frame-change happened for root scene that graph belongs to. */
@@ -480,19 +135,18 @@ void DEG_evaluate_on_framechange(EvaluationContext *eval_ctx,
float ctime,
const int layers)
{
+ DEG::Depsgraph *deg_graph = reinterpret_cast<DEG::Depsgraph *>(graph);
/* Update time on primary timesource. */
- TimeSourceDepsNode *tsrc = graph->find_time_source();
+ DEG::TimeSourceDepsNode *tsrc = deg_graph->find_time_source();
tsrc->cfra = ctime;
-
- tsrc->tag_update(graph);
-
- DEG_graph_flush_updates(bmain, graph);
-
+ tsrc->tag_update(deg_graph);
+ DEG::deg_graph_flush_updates(bmain, deg_graph);
/* Perform recalculation updates. */
- DEG_evaluate_on_refresh_ex(eval_ctx, graph, layers);
+ DEG::deg_evaluate_on_refresh(eval_ctx, deg_graph, layers);
}
bool DEG_needs_eval(Depsgraph *graph)
{
- return graph->entry_tags.size() != 0;
+ DEG::Depsgraph *deg_graph = reinterpret_cast<DEG::Depsgraph *>(graph);
+ return BLI_gset_size(deg_graph->entry_tags) != 0;
}
diff --git a/source/blender/depsgraph/intern/depsgraph_intern.h b/source/blender/depsgraph/intern/depsgraph_intern.h
index 7fdc2454564..e5d3d1f5861 100644
--- a/source/blender/depsgraph/intern/depsgraph_intern.h
+++ b/source/blender/depsgraph/intern/depsgraph_intern.h
@@ -31,65 +31,26 @@
* - Also, defines for "Node Type Info"
*/
-#ifndef __DEPSGRAPH_INTERN_H__
-#define __DEPSGRAPH_INTERN_H__
+#pragma once
#include <cstdlib>
#include "MEM_guardedalloc.h"
-#include "depsgraph.h"
-#include "depsnode.h"
+extern "C" {
+#include "BKE_global.h"
+}
+
+#include "intern/nodes/deg_node.h"
+#include "intern/nodes/deg_node_component.h"
+#include "intern/nodes/deg_node_operation.h"
+#include "intern/depsgraph.h"
struct Main;
struct Group;
struct Scene;
-/* Graph Building ======================================================== */
-
-/**
- * Build depsgraph for the given group, and dump results in given graph container
- * This is usually used for building subgraphs for groups to use...
- */
-void DEG_graph_build_from_group(Depsgraph *graph, struct Main *bmain, struct Group *group);
-
-/* Build subgraph for group */
-DepsNode *DEG_graph_build_group_subgraph(Depsgraph *graph_main, struct Main *bmain, struct Group *group);
-
-/* Graph Copying ========================================================= */
-/* (Part of the Filtering API) */
-
-/**
- * Depsgraph Copying Context (dcc)
- *
- * Keeps track of node relationships/links/etc. during the copy
- * operation so that they can be safely remapped...
- */
-typedef struct DepsgraphCopyContext {
- struct GHash *nodes_hash; /* <DepsNode, DepsNode> mapping from src node to dst node */
- struct GHash *rels_hash; // XXX: same for relationships?
-
- // XXX: filtering criteria...
-} DepsgraphCopyContext;
-
-/* Internal Filtering API ---------------------------------------------- */
-
-/* Create filtering context */
-// XXX: needs params for conditions?
-DepsgraphCopyContext *DEG_filter_init(void);
-
-/* Free filtering context once filtering is done */
-void DEG_filter_cleanup(DepsgraphCopyContext *dcc);
-
-
-/* Data Copy Operations ------------------------------------------------ */
-
-/**
- * Make a (deep) copy of provided node and it's little subgraph
- * \warning Newly created node is not added to the existing graph
- * \param dcc: Context info for helping resolve links
- */
-DepsNode *DEG_copy_node(DepsgraphCopyContext *dcc, const DepsNode *src);
+namespace DEG {
/* Node Types Handling ================================================= */
@@ -101,8 +62,9 @@ struct DepsNodeFactory {
virtual eDepsNode_Class tclass() const = 0;
virtual const char *tname() const = 0;
- virtual DepsNode *create_node(const ID *id, const string &subdata, const string &name) const = 0;
- virtual DepsNode *copy_node(DepsgraphCopyContext *dcc, const DepsNode *copy) const = 0;
+ virtual DepsNode *create_node(const ID *id,
+ const string &subdata,
+ const string &name) const = 0;
};
template <class NodeType>
@@ -130,34 +92,18 @@ struct DepsNodeFactoryImpl : public DepsNodeFactory {
return node;
}
-
- virtual DepsNode *copy_node(DepsgraphCopyContext *dcc, const DepsNode *copy) const
- {
- BLI_assert(copy->type == type());
- DepsNode *node = OBJECT_GUARDED_NEW(NodeType);
-
- /* populate base node settings */
- node->type = type();
- node->tclass = tclass();
- // XXX: need to review the name here, as we can't have exact duplicates...
- node->name = copy->name;
-
- node->copy(dcc, static_cast<const NodeType *>(copy));
-
- return node;
- }
};
/* Typeinfo Management -------------------------------------------------- */
/* Register typeinfo */
-void DEG_register_node_typeinfo(DepsNodeFactory *factory);
+void deg_register_node_typeinfo(DepsNodeFactory *factory);
/* Get typeinfo for specified type */
-DepsNodeFactory *DEG_get_node_factory(const eDepsNode_Type type);
+DepsNodeFactory *deg_get_node_factory(const eDepsNode_Type type);
/* Get typeinfo for provided node */
-DepsNodeFactory *DEG_node_get_factory(const DepsNode *node);
+DepsNodeFactory *deg_node_get_factory(const DepsNode *node);
/* Editors Integration -------------------------------------------------- */
@@ -165,4 +111,11 @@ void deg_editors_id_update(struct Main *bmain, struct ID *id);
void deg_editors_scene_update(struct Main *bmain, struct Scene *scene, bool updated);
-#endif /* __DEPSGRAPH_INTERN_H__ */
+#define DEG_DEBUG_PRINTF(...) \
+ do { \
+ if (G.debug & G_DEBUG_DEPSGRAPH) { \
+ fprintf(stderr, __VA_ARGS__); \
+ } \
+ } while (0)
+
+} // namespace DEG
diff --git a/source/blender/depsgraph/intern/depsgraph_query.cc b/source/blender/depsgraph/intern/depsgraph_query.cc
index 73193747b93..cac4eaae215 100644
--- a/source/blender/depsgraph/intern/depsgraph_query.cc
+++ b/source/blender/depsgraph/intern/depsgraph_query.cc
@@ -33,162 +33,12 @@
#include "MEM_guardedalloc.h"
extern "C" {
-#include "BLI_utildefines.h"
-#include "BLI_ghash.h"
-
#include "BKE_main.h"
#include "DEG_depsgraph_query.h"
} /* extern "C" */
-#include "depsgraph_queue.h"
-#include "depsnode.h"
-#include "depsnode_operation.h"
-#include "depsgraph_intern.h"
-
-/* ************************* */
-/* Low-Level Graph Traversal */
-
-#if 0
-/* Prepare for graph traversal, by tagging nodes, etc. */
-static void DEG_graph_traverse_begin(Depsgraph * /*graph*/)
-{
- /* go over all nodes, initialising the valence counts */
- // XXX: this will end up being O(|V|), which is bad when we're just updating a few nodes...
-}
-
-/* Perform a traversal of graph from given starting node (in execution order) */
-// TODO: additional flags for controlling the process?
-void DEG_graph_traverse_from_node(Depsgraph *graph, OperationDepsNode *start_node,
- DEG_FilterPredicate filter, void *filter_data,
- DEG_NodeOperation op, void *operation_data)
-{
- DepsgraphQueue *q;
-
- /* sanity checks */
- if (ELEM(NULL, graph, start_node, op))
- return;
-
- /* add node as starting node to be evaluated, with value of 0 */
- q = DEG_queue_new();
-
- start_node->num_links_pending = 0;
- DEG_queue_push(q, start_node, 0.0f);
-
- /* while we still have nodes in the queue, grab and work on next one */
- do {
- /* grab item at front of queue */
- // XXX: in practice, we may need to wait until one becomes available...
- OperationDepsNode *node = (OperationDepsNode *)DEG_queue_pop(q);
-
- /* perform operation on node */
- op(graph, node, operation_data);
-
- /* schedule up operations which depend on this */
- DEPSNODE_RELATIONS_ITER_BEGIN(node->outlinks, rel)
- {
- /* ensure that relationship is not tagged for ignoring (i.e. cyclic, etc.) */
- // TODO: cyclic refs should probably all get clustered towards the end, so that we can just stop on the first one
- if ((rel->flag & DEPSREL_FLAG_CYCLIC) == 0) {
- OperationDepsNode *child_node = (OperationDepsNode *)rel->to;
-
- /* only visit node if the filtering function agrees */
- if ((filter == NULL) || filter(graph, child_node, filter_data)) {
- /* schedule up node... */
- child_node->num_links_pending--;
- DEG_queue_push(q, child_node, (float)child_node->num_links_pending);
- }
- }
- }
- DEPSNODE_RELATIONS_ITER_END;
- } while (DEG_queue_is_empty(q) == false);
-
- /* cleanup */
- DEG_queue_free(q);
-}
-#endif
-
-/* ************************************************************** */
-/* Filtering API - Basically, making a copy of the existing graph */
-
-/* Create filtering context */
-// TODO: allow passing in a number of criteria?
-DepsgraphCopyContext *DEG_filter_init()
-{
- DepsgraphCopyContext *dcc = (DepsgraphCopyContext *)MEM_callocN(sizeof(DepsgraphCopyContext), "DepsgraphCopyContext");
-
- /* init hashes for easy lookups */
- dcc->nodes_hash = BLI_ghash_ptr_new("Depsgraph Filter NodeHash");
- dcc->rels_hash = BLI_ghash_ptr_new("Depsgraph Filter Relationship Hash"); // XXX?
-
- /* store filtering criteria? */
- // xxx...
-
- return dcc;
-}
-
-/* Cleanup filtering context */
-void DEG_filter_cleanup(DepsgraphCopyContext *dcc)
-{
- /* sanity check */
- if (dcc == NULL)
- return;
-
- /* free hashes - contents are weren't copied, so are ok... */
- BLI_ghash_free(dcc->nodes_hash, NULL, NULL);
- BLI_ghash_free(dcc->rels_hash, NULL, NULL);
-
- /* clear filtering criteria */
- // ...
-
- /* free dcc itself */
- MEM_freeN(dcc);
-}
-
-/* -------------------------------------------------- */
-
-/* Create a copy of provided node */
-// FIXME: the handling of sub-nodes and links will need to be subject to filtering options...
-// XXX: perhaps this really shouldn't be exposed, as it will just be a sub-step of the evaluation process?
-DepsNode *DEG_copy_node(DepsgraphCopyContext *dcc, const DepsNode *src)
-{
- /* sanity check */
- if (src == NULL)
- return NULL;
-
- DepsNodeFactory *factory = DEG_get_node_factory(src->type);
- BLI_assert(factory != NULL);
- DepsNode *dst = factory->copy_node(dcc, src);
-
- /* add this node-pair to the hash... */
- BLI_ghash_insert(dcc->nodes_hash, (DepsNode *)src, dst);
-
-#if 0 /* XXX TODO */
- /* now, fix up any links in standard "node header" (i.e. DepsNode struct, that all
- * all others are derived from) that are now corrupt
- */
- {
- /* relationships to other nodes... */
- // FIXME: how to handle links? We may only have partial set of all nodes still?
- // XXX: the exact details of how to handle this are really part of the querying API...
-
- // XXX: BUT, for copying subgraphs, we'll need to define an API for doing this stuff anyways
- // (i.e. for resolving and patching over links that exist within subtree...)
- dst->inlinks.clear();
- dst->outlinks.clear();
-
- /* clear traversal data */
- dst->num_links_pending = 0;
- dst->lasttime = 0;
- }
-
- /* fix links */
- // XXX...
-#endif
-
- /* return copied node */
- return dst;
-}
+#include "intern/depsgraph_intern.h"
bool DEG_id_type_tagged(Main *bmain, short idtype)
{
@@ -207,7 +57,9 @@ short DEG_get_eval_flags_for_id(Depsgraph *graph, ID *id)
return 0;
}
- IDDepsNode *id_node = graph->find_id_node(id);
+ DEG::Depsgraph *deg_graph = reinterpret_cast<DEG::Depsgraph *>(graph);
+
+ DEG::IDDepsNode *id_node = deg_graph->find_id_node(id);
if (id_node == NULL) {
/* TODO(sergey): Does it mean we need to check set scene? */
return 0;
diff --git a/source/blender/depsgraph/intern/depsgraph_queue.cc b/source/blender/depsgraph/intern/depsgraph_queue.cc
deleted file mode 100644
index da60d73bc46..00000000000
--- a/source/blender/depsgraph/intern/depsgraph_queue.cc
+++ /dev/null
@@ -1,177 +0,0 @@
-/*
- * ***** BEGIN GPL LICENSE BLOCK *****
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * The Original Code is Copyright (C) 2013 Blender Foundation.
- * All rights reserved.
- *
- * Original Author: Joshua Leung
- * Contributor(s): None Yet
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-/** \file blender/depsgraph/intern/depsgraph_queue.cc
- * \ingroup depsgraph
- *
- * Implementation of special queue type for use in Depsgraph traversals.
- */
-
-#include <stdlib.h>
-
-#include "MEM_guardedalloc.h"
-
-extern "C" {
-#include "BLI_utildefines.h"
-#include "BLI_heap.h"
-#include "BLI_ghash.h"
-} /* extern "C" */
-
-#include "depsgraph_queue.h"
-
-/* ****************************** */
-/* Depsgraph Queue implementation */
-
-/* Data Management ----------------------------------------- */
-
-DepsgraphQueue *DEG_queue_new(void)
-{
- DepsgraphQueue *q = (DepsgraphQueue *)MEM_callocN(sizeof(DepsgraphQueue), "DEG_queue_new()");
-
- /* init data structures for use here */
- q->pending_heap = BLI_heap_new();
- q->pending_hash = BLI_ghash_ptr_new("DEG Queue Pending Hash");
-
- q->ready_heap = BLI_heap_new();
-
- /* init settings */
- q->idx = 0;
- q->tot = 0;
-
- /* return queue */
- return q;
-}
-
-void DEG_queue_free(DepsgraphQueue *q)
-{
- /* free data structures */
- BLI_assert(BLI_heap_size(q->pending_heap) == 0);
- BLI_assert(BLI_heap_size(q->ready_heap) == 0);
- BLI_assert(BLI_ghash_size(q->pending_hash) == 0);
-
- BLI_heap_free(q->pending_heap, NULL);
- BLI_heap_free(q->ready_heap, NULL);
- BLI_ghash_free(q->pending_hash, NULL, NULL);
-
- /* free queue itself */
- MEM_freeN(q);
-}
-
-/* Statistics --------------------------------------------- */
-
-/* Get the number of nodes which are we should visit, but are not able to yet */
-size_t DEG_queue_num_pending(DepsgraphQueue *q)
-{
- return BLI_heap_size(q->pending_heap);
-}
-
-/* Get the number of nodes which are now ready to be visited */
-size_t DEG_queue_num_ready(DepsgraphQueue *q)
-{
- return BLI_heap_size(q->ready_heap);
-}
-
-/* Get total size of queue */
-size_t DEG_queue_size(DepsgraphQueue *q)
-{
- return DEG_queue_num_pending(q) + DEG_queue_num_ready(q);
-}
-
-/* Check if queue has any items in it (still passing through) */
-bool DEG_queue_is_empty(DepsgraphQueue *q)
-{
- return DEG_queue_size(q) == 0;
-}
-
-/* Queue Operations --------------------------------------- */
-
-/**
- * Add DepsNode to the queue
- * \param dnode: ``(DepsNode *)`` node to add to the queue
- * Each node is only added once to the queue; Subsequent pushes
- * merely update its status (e.g. moving it from "pending" to "ready")
- * \param cost: new "num_links_pending" count for node *after* it has encountered
- * via an outlink from the node currently being visited
- * (i.e. we're one of the dependencies which may now be able to be processed)
- */
-void DEG_queue_push(DepsgraphQueue *q, void *dnode, float cost)
-{
- HeapNode *hnode = NULL;
-
- /* Shortcut: Directly add to ready if node isn't waiting on anything now... */
- if (cost == 0) {
- /* node is now ready to be visited - schedule it up for such */
- if (BLI_ghash_haskey(q->pending_hash, dnode)) {
- /* remove from pending queue - we're moving it to the scheduling queue */
- hnode = (HeapNode *)BLI_ghash_lookup(q->pending_hash, dnode);
- BLI_heap_remove(q->pending_heap, hnode);
-
- BLI_ghash_remove(q->pending_hash, dnode, NULL, NULL);
- }
-
- /* schedule up node using latest count (of ready nodes) */
- BLI_heap_insert(q->ready_heap, (float)q->idx, dnode);
- q->idx++;
- }
- else {
- /* node is still waiting on some other ancestors,
- * so add it to the pending heap in the meantime...
- */
- // XXX: is this even necessary now?
- if (BLI_ghash_haskey(q->pending_hash, dnode)) {
- /* just update cost on pending node */
- hnode = (HeapNode *)BLI_ghash_lookup(q->pending_hash, dnode);
- BLI_heap_remove(q->pending_heap, hnode);
- BLI_heap_insert(q->pending_heap, cost, hnode);
- }
- else {
- /* add new node to pending queue, and increase size of overall queue */
- hnode = BLI_heap_insert(q->pending_heap, cost, dnode);
- q->tot++;
- }
- }
-}
-
-/* Grab a "ready" node from the queue */
-void *DEG_queue_pop(DepsgraphQueue *q)
-{
- /* sanity check: if there are no "ready" nodes,
- * start pulling from "pending" to keep things moving,
- * but throw a warning so that we know that something's up here...
- */
- if (BLI_heap_is_empty(q->ready_heap)) {
- // XXX: this should never happen
- // XXX: if/when it does happen, we may want instead to just wait until something pops up here...
- printf("DepsgraphHeap Warning: No more ready nodes available. Trying from pending (idx = %d, tot = %d, pending = %d, ready = %d)\n",
- (int)q->idx, (int)q->tot, (int)DEG_queue_num_pending(q), (int)DEG_queue_num_ready(q));
-
- return BLI_heap_popmin(q->pending_heap);
- }
- else {
- /* only grab "ready" nodes */
- return BLI_heap_popmin(q->ready_heap);
- }
-}
diff --git a/source/blender/depsgraph/intern/depsgraph_queue.h b/source/blender/depsgraph/intern/depsgraph_queue.h
deleted file mode 100644
index b85d46bd173..00000000000
--- a/source/blender/depsgraph/intern/depsgraph_queue.h
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- * ***** BEGIN GPL LICENSE BLOCK *****
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * The Original Code is Copyright (C) 2013 Blender Foundation.
- * All rights reserved.
- *
- * Original Author: Joshua Leung
- * Contributor(s): None Yet
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-/** \file blender/depsgraph/intern/depsgraph_queue.h
- * \ingroup depsgraph
- *
- * Defines for special queue type for use in Depsgraph traversals.
- */
-
-#ifndef __DEPSGRAPH_QUEUE_H__
-#define __DEPSGRAPH_QUEUE_H__
-
-struct DepsNode;
-
-struct Heap;
-struct GHash;
-
-/* *********************************************** */
-/* Dependency Graph Traversal Queue
- *
- * There are two parts to this:
- * a) "Pending" Nodes - This part contains the set of nodes
- * which are related to those which have been visited
- * previously, but are not yet ready to actually be visited.
- * b) "Scheduled" Nodes - These are the nodes whose ancestors
- * have all been evaluated already, which means that any
- * or all of them can be picked (in practically in order) to
- * be visited immediately.
- *
- * Internally, the queue makes sure that each node in the graph
- * only gets added to the queue once. This is because there can
- * be multiple inlinks to each node given the way that the relations
- * work.
- */
-
-/* Depsgraph Queue Type */
-typedef struct DepsgraphQueue {
- /* Pending */
- struct Heap *pending_heap; /* (valence:int, DepsNode*) */
- struct GHash *pending_hash; /* (DepsNode* : HeapNode*>) */
-
- /* Ready to be visited - fifo */
- struct Heap *ready_heap; /* (idx:int, DepsNode*) */
-
- /* Size/Order counts */
- size_t idx; /* total number of nodes which are/have been ready so far (including those already visited) */
- size_t tot; /* total number of nodes which have passed through queue; mainly for debug */
-} DepsgraphQueue;
-
-/* ************************** */
-/* Depsgraph Queue Operations */
-
-/* Data management */
-DepsgraphQueue *DEG_queue_new(void);
-void DEG_queue_free(DepsgraphQueue *q);
-
-/* Statistics */
-size_t DEG_queue_num_pending(DepsgraphQueue *q);
-size_t DEG_queue_num_ready(DepsgraphQueue *q);
-
-size_t DEG_queue_size(DepsgraphQueue *q);
-bool DEG_queue_is_empty(DepsgraphQueue *q);
-
-/* Operations */
-void DEG_queue_push(DepsgraphQueue *q, void *dnode, float cost = 0.0f);
-void *DEG_queue_pop(DepsgraphQueue *q);
-
-#endif /* DEPSGRAPH_QUEUE_H */
diff --git a/source/blender/depsgraph/intern/depsgraph_tag.cc b/source/blender/depsgraph/intern/depsgraph_tag.cc
index 3ca23965749..ea5afaab3f7 100644
--- a/source/blender/depsgraph/intern/depsgraph_tag.cc
+++ b/source/blender/depsgraph/intern/depsgraph_tag.cc
@@ -55,11 +55,14 @@ extern "C" {
#include "DEG_depsgraph.h"
} /* extern "C" */
-#include "depsgraph_debug.h"
-#include "depsnode.h"
-#include "depsnode_component.h"
-#include "depsnode_operation.h"
-#include "depsgraph_intern.h"
+#include "intern/eval/deg_eval_flush.h"
+
+#include "intern/nodes/deg_node.h"
+#include "intern/nodes/deg_node_component.h"
+#include "intern/nodes/deg_node_operation.h"
+
+#include "intern/depsgraph_intern.h"
+#include "util/deg_util_foreach.h"
/* *********************** */
/* Update Tagging/Flushing */
@@ -154,19 +157,21 @@ void depsgraph_legacy_handle_update_tag(Main *bmain, ID *id, short flag)
*/
void DEG_graph_id_tag_update(Main *bmain, Depsgraph *graph, ID *id)
{
- IDDepsNode *node = graph->find_id_node(id);
+ DEG::Depsgraph *deg_graph = reinterpret_cast<DEG::Depsgraph *>(graph);
+ DEG::IDDepsNode *node = deg_graph->find_id_node(id);
lib_id_recalc_tag(bmain, id);
if (node != NULL) {
- node->tag_update(graph);
+ node->tag_update(deg_graph);
}
}
/* Tag nodes related to a specific piece of data */
void DEG_graph_data_tag_update(Depsgraph *graph, const PointerRNA *ptr)
{
- DepsNode *node = graph->find_node_from_pointer(ptr, NULL);
- if (node) {
- node->tag_update(graph);
+ DEG::Depsgraph *deg_graph = reinterpret_cast<DEG::Depsgraph *>(graph);
+ DEG::DepsNode *node = deg_graph->find_node_from_pointer(ptr, NULL);
+ if (node != NULL) {
+ node->tag_update(deg_graph);
}
else {
printf("Missing node in %s\n", __func__);
@@ -179,9 +184,10 @@ void DEG_graph_property_tag_update(Depsgraph *graph,
const PointerRNA *ptr,
const PropertyRNA *prop)
{
- DepsNode *node = graph->find_node_from_pointer(ptr, prop);
- if (node) {
- node->tag_update(graph);
+ DEG::Depsgraph *deg_graph = reinterpret_cast<DEG::Depsgraph *>(graph);
+ DEG::DepsNode *node = deg_graph->find_node_from_pointer(ptr, prop);
+ if (node != NULL) {
+ node->tag_update(deg_graph);
}
else {
printf("Missing node in %s\n", __func__);
@@ -259,131 +265,6 @@ void DEG_id_type_tag(Main *bmain, short idtype)
bmain->id_tag_update[((unsigned char *)&idtype)[0]] = 1;
}
-/* Update Flushing ---------------------------------- */
-
-/* FIFO queue for tagged nodes that need flushing */
-/* XXX This may get a dedicated implementation later if needed - lukas */
-typedef std::queue<OperationDepsNode *> FlushQueue;
-
-static void flush_init_func(void *data_v, int i)
-{
- /* ID node's done flag is used to avoid multiple editors update
- * for the same ID.
- */
- Depsgraph *graph = (Depsgraph *)data_v;
- OperationDepsNode *node = graph->operations[i];
- IDDepsNode *id_node = node->owner->owner;
- id_node->done = 0;
- node->scheduled = false;
- node->owner->flags &= ~DEPSCOMP_FULLY_SCHEDULED;
-}
-
-/* Flush updates from tagged nodes outwards until all affected nodes are tagged. */
-void DEG_graph_flush_updates(Main *bmain, Depsgraph *graph)
-{
- /* sanity check */
- if (graph == NULL)
- return;
-
- /* Nothing to update, early out. */
- if (graph->entry_tags.size() == 0) {
- return;
- }
-
- /* TODO(sergey): With a bit of flag magic we can get rid of this
- * extra loop.
- */
- const int num_operations = graph->operations.size();
- const bool do_threads = num_operations > 256;
- BLI_task_parallel_range(0, num_operations, graph, flush_init_func, do_threads);
-
- FlushQueue queue;
- /* Starting from the tagged "entry" nodes, flush outwards... */
- /* NOTE: Also need to ensure that for each of these, there is a path back to
- * root, or else they won't be done.
- * NOTE: Count how many nodes we need to handle - entry nodes may be
- * component nodes which don't count for this purpose!
- */
- for (Depsgraph::EntryTags::const_iterator it = graph->entry_tags.begin();
- it != graph->entry_tags.end();
- ++it)
- {
- OperationDepsNode *node = *it;
- IDDepsNode *id_node = node->owner->owner;
- queue.push(node);
- if (id_node->done == 0) {
- deg_editors_id_update(bmain, id_node->id);
- id_node->done = 1;
- }
- node->scheduled = true;
- }
-
- while (!queue.empty()) {
- OperationDepsNode *node = queue.front();
- queue.pop();
-
- IDDepsNode *id_node = node->owner->owner;
- lib_id_recalc_tag(bmain, id_node->id);
- /* TODO(sergey): For until we've got proper data nodes in the graph. */
- lib_id_recalc_data_tag(bmain, id_node->id);
-
- ID *id = id_node->id;
- /* This code is used to preserve those areas which does direct
- * object update,
- *
- * Plus it ensures visibility changes and relations and layers
- * visibility update has proper flags to work with.
- */
- if (GS(id->name) == ID_OB) {
- Object *object = (Object *)id;
- ComponentDepsNode *comp_node = node->owner;
- if (comp_node->type == DEPSNODE_TYPE_ANIMATION) {
- object->recalc |= OB_RECALC_TIME;
- }
- else if (comp_node->type == DEPSNODE_TYPE_TRANSFORM) {
- object->recalc |= OB_RECALC_OB;
- }
- else {
- object->recalc |= OB_RECALC_DATA;
- }
- }
-
- /* Flush to nodes along links... */
- for (OperationDepsNode::Relations::const_iterator it = node->outlinks.begin();
- it != node->outlinks.end();
- ++it)
- {
- DepsRelation *rel = *it;
- OperationDepsNode *to_node = (OperationDepsNode *)rel->to;
- if (to_node->scheduled == false) {
- to_node->flag |= DEPSOP_FLAG_NEEDS_UPDATE;
- queue.push(to_node);
- to_node->scheduled = true;
- if (id_node->done == 0) {
- deg_editors_id_update(bmain, id_node->id);
- id_node->done = 1;
- }
- }
- }
-
- /* TODO(sergey): For until incremental updates are possible
- * witin a component at least we tag the whole component
- * for update.
- */
- ComponentDepsNode *component = node->owner;
- if ((component->flags & DEPSCOMP_FULLY_SCHEDULED) == 0) {
- for (ComponentDepsNode::OperationMap::iterator it = component->operations.begin();
- it != node->owner->operations.end();
- ++it)
- {
- OperationDepsNode *op = it->second;
- op->flag |= DEPSOP_FLAG_NEEDS_UPDATE;
- }
- component->flags |= DEPSCOMP_FULLY_SCHEDULED;
- }
- }
-}
-
/* Recursively push updates out to all nodes dependent on this,
* until all affected are tagged and/or scheduled up for eval
*/
@@ -395,34 +276,17 @@ void DEG_ids_flush_tagged(Main *bmain)
{
/* TODO(sergey): Only visible scenes? */
if (scene->depsgraph != NULL) {
- DEG_graph_flush_updates(bmain, scene->depsgraph);
+ DEG::deg_graph_flush_updates(
+ bmain,
+ reinterpret_cast<DEG::Depsgraph *>(scene->depsgraph));
}
}
}
-static void graph_clear_func(void *data_v, int i)
-{
- Depsgraph *graph = (Depsgraph *)data_v;
- OperationDepsNode *node = graph->operations[i];
- /* Clear node's "pending update" settings. */
- node->flag &= ~(DEPSOP_FLAG_DIRECTLY_MODIFIED | DEPSOP_FLAG_NEEDS_UPDATE);
-}
-
-/* Clear tags from all operation nodes. */
-void DEG_graph_clear_tags(Depsgraph *graph)
-{
- /* Go over all operation nodes, clearing tags. */
- const int num_operations = graph->operations.size();
- const bool do_threads = num_operations > 256;
- BLI_task_parallel_range(0, num_operations, graph, graph_clear_func, do_threads);
- /* Clear any entry tags which haven't been flushed. */
- graph->entry_tags.clear();
-}
-
/* Update dependency graph when visible scenes/layers changes. */
void DEG_graph_on_visible_update(Main *bmain, Scene *scene)
{
- Depsgraph *graph = scene->depsgraph;
+ DEG::Depsgraph *graph = reinterpret_cast<DEG::Depsgraph *>(scene->depsgraph);
wmWindowManager *wm = (wmWindowManager *)bmain->wm.first;
int old_layers = graph->layers;
if (wm != NULL) {
@@ -450,11 +314,8 @@ void DEG_graph_on_visible_update(Main *bmain, Scene *scene)
* This is mainly needed on file load only, after that updates of invisible objects
* will be stored in the pending list.
*/
- for (Depsgraph::IDNodeMap::const_iterator it = graph->id_hash.begin();
- it != graph->id_hash.end();
- ++it)
+ GHASH_FOREACH_BEGIN(DEG::IDDepsNode *, id_node, graph->id_hash)
{
- IDDepsNode *id_node = it->second;
ID *id = id_node->id;
if ((id->tag & LIB_TAG_ID_RECALC_ALL) != 0 ||
(id_node->layers & scene->lay_updated) == 0)
@@ -472,14 +333,15 @@ void DEG_graph_on_visible_update(Main *bmain, Scene *scene)
(object->recalc & OB_RECALC_ALL) != 0)
{
id_node->tag_update(graph);
- ComponentDepsNode *anim_comp =
- id_node->find_component(DEPSNODE_TYPE_ANIMATION);
+ DEG::ComponentDepsNode *anim_comp =
+ id_node->find_component(DEG::DEPSNODE_TYPE_ANIMATION);
if (anim_comp != NULL && object->recalc & OB_RECALC_TIME) {
anim_comp->tag_update(graph);
}
}
}
}
+ GHASH_FOREACH_END();
}
scene->lay_updated |= graph->layers;
}
@@ -520,7 +382,7 @@ void DEG_ids_check_recalc(Main *bmain, Scene *scene, bool time)
}
}
- deg_editors_scene_update(bmain, scene, (updated || time));
+ DEG::deg_editors_scene_update(bmain, scene, (updated || time));
}
void DEG_ids_clear_recalc(Main *bmain)
diff --git a/source/blender/depsgraph/intern/depsgraph_type_defines.cc b/source/blender/depsgraph/intern/depsgraph_type_defines.cc
index 5a3048a4aa3..97208939e57 100644
--- a/source/blender/depsgraph/intern/depsgraph_type_defines.cc
+++ b/source/blender/depsgraph/intern/depsgraph_type_defines.cc
@@ -30,6 +30,8 @@
* Defines and code for core node types.
*/
+#include <cstdlib> // for BLI_assert()
+
extern "C" {
#include "BLI_utildefines.h"
#include "BLI_ghash.h"
@@ -37,10 +39,13 @@ extern "C" {
#include "DEG_depsgraph.h"
} /* extern "C" */
-#include "depsgraph_intern.h"
-#include "depsnode.h"
-#include "depsnode_component.h"
-#include "depsnode_operation.h"
+#include "intern/nodes/deg_node.h"
+#include "intern/nodes/deg_node_component.h"
+#include "intern/nodes/deg_node_operation.h"
+
+#include "intern/depsgraph_intern.h"
+
+namespace DEG {
/* ************ */
/* External API */
@@ -59,44 +64,108 @@ static GHash *_depsnode_typeinfo_registry = NULL;
/* Registration ------------------------------------------- */
/* Register node type */
-void DEG_register_node_typeinfo(DepsNodeFactory *factory)
+void deg_register_node_typeinfo(DepsNodeFactory *factory)
{
BLI_assert(factory != NULL);
BLI_ghash_insert(_depsnode_typeinfo_registry, SET_INT_IN_POINTER(factory->type()), factory);
}
-/* Register all node types */
-void DEG_register_node_types(void)
-{
- /* initialise registry */
- _depsnode_typeinfo_registry = BLI_ghash_int_new("Depsgraph Node Type Registry");
-
- /* register node types */
- DEG_register_base_depsnodes();
- DEG_register_component_depsnodes();
- DEG_register_operation_depsnodes();
-}
-
-/* Free registry on exit */
-void DEG_free_node_types(void)
-{
- BLI_ghash_free(_depsnode_typeinfo_registry, NULL, NULL);
-}
-
/* Getters ------------------------------------------------- */
/* Get typeinfo for specified type */
-DepsNodeFactory *DEG_get_node_factory(const eDepsNode_Type type)
+DepsNodeFactory *deg_get_node_factory(const eDepsNode_Type type)
{
/* look up type - at worst, it doesn't exist in table yet, and we fail */
return (DepsNodeFactory *)BLI_ghash_lookup(_depsnode_typeinfo_registry, SET_INT_IN_POINTER(type));
}
/* Get typeinfo for provided node */
-DepsNodeFactory *DEG_node_get_factory(const DepsNode *node)
+DepsNodeFactory *deg_node_get_factory(const DepsNode *node)
{
- if (!node)
+ if (node != NULL) {
return NULL;
+ }
+ return deg_get_node_factory(node->type);
+}
+
+/* Stringified opcodes ------------------------------------- */
+
+DepsOperationStringifier DEG_OPNAMES;
- return DEG_get_node_factory(node->type);
+static const char *stringify_opcode(eDepsOperation_Code opcode)
+{
+ switch (opcode) {
+#define STRINGIFY_OPCODE(name) case DEG_OPCODE_##name: return #name
+ STRINGIFY_OPCODE(OPERATION);
+ STRINGIFY_OPCODE(PLACEHOLDER);
+ STRINGIFY_OPCODE(NOOP);
+ STRINGIFY_OPCODE(ANIMATION);
+ STRINGIFY_OPCODE(DRIVER);
+ //STRINGIFY_OPCODE(PROXY);
+ STRINGIFY_OPCODE(TRANSFORM_LOCAL);
+ STRINGIFY_OPCODE(TRANSFORM_PARENT);
+ STRINGIFY_OPCODE(TRANSFORM_CONSTRAINTS);
+ //STRINGIFY_OPCODE(TRANSFORM_CONSTRAINTS_INIT);
+ //STRINGIFY_OPCODE(TRANSFORM_CONSTRAINT);
+ //STRINGIFY_OPCODE(TRANSFORM_CONSTRAINTS_DONE);
+ STRINGIFY_OPCODE(RIGIDBODY_REBUILD);
+ STRINGIFY_OPCODE(RIGIDBODY_SIM);
+ STRINGIFY_OPCODE(TRANSFORM_RIGIDBODY);
+ STRINGIFY_OPCODE(TRANSFORM_FINAL);
+ STRINGIFY_OPCODE(OBJECT_UBEREVAL);
+ STRINGIFY_OPCODE(GEOMETRY_UBEREVAL);
+ STRINGIFY_OPCODE(GEOMETRY_MODIFIER);
+ STRINGIFY_OPCODE(GEOMETRY_PATH);
+ STRINGIFY_OPCODE(POSE_INIT);
+ STRINGIFY_OPCODE(POSE_DONE);
+ STRINGIFY_OPCODE(POSE_IK_SOLVER);
+ STRINGIFY_OPCODE(POSE_SPLINE_IK_SOLVER);
+ STRINGIFY_OPCODE(BONE_LOCAL);
+ STRINGIFY_OPCODE(BONE_POSE_PARENT);
+ STRINGIFY_OPCODE(BONE_CONSTRAINTS);
+ //STRINGIFY_OPCODE(BONE_CONSTRAINTS_INIT);
+ //STRINGIFY_OPCODE(BONE_CONSTRAINT);
+ //STRINGIFY_OPCODE(BONE_CONSTRAINTS_DONE);
+ STRINGIFY_OPCODE(BONE_READY);
+ STRINGIFY_OPCODE(BONE_DONE);
+ STRINGIFY_OPCODE(PSYS_EVAL);
+
+ case DEG_NUM_OPCODES: return "SpecialCase";
+#undef STRINGIFY_OPCODE
+ }
+ return "UNKNOWN";
+}
+
+DepsOperationStringifier::DepsOperationStringifier() {
+ for (int i = 0; i < DEG_NUM_OPCODES; ++i) {
+ names_[i] = stringify_opcode((eDepsOperation_Code)i);
+ }
+}
+
+const char *DepsOperationStringifier::operator[](eDepsOperation_Code opcode) {
+ BLI_assert((opcode > 0) && (opcode < DEG_NUM_OPCODES));
+ if (opcode >= 0 && opcode < DEG_NUM_OPCODES) {
+ return names_[opcode];
+ }
+ return "UnknownOpcode";
+}
+
+} // namespace DEG
+
+/* Register all node types */
+void DEG_register_node_types(void)
+{
+ /* initialise registry */
+ DEG::_depsnode_typeinfo_registry = BLI_ghash_int_new("Depsgraph Node Type Registry");
+
+ /* register node types */
+ DEG::deg_register_base_depsnodes();
+ DEG::deg_register_component_depsnodes();
+ DEG::deg_register_operation_depsnodes();
+}
+
+/* Free registry on exit */
+void DEG_free_node_types(void)
+{
+ BLI_ghash_free(DEG::_depsnode_typeinfo_registry, NULL, NULL);
}
diff --git a/source/blender/depsgraph/intern/depsgraph_types.h b/source/blender/depsgraph/intern/depsgraph_types.h
index f5fbf0bcc76..7516ccbfdc2 100644
--- a/source/blender/depsgraph/intern/depsgraph_types.h
+++ b/source/blender/depsgraph/intern/depsgraph_types.h
@@ -34,10 +34,9 @@
* in the graph.
*/
-#ifndef __DEPSGRAPH_TYPES_H__
-#define __DEPSGRAPH_TYPES_H__
+#pragma once
-#include "depsgraph_util_function.h"
+#include "util/deg_util_function.h"
/* TODO(sergey): Ideally we'll just use char* and statically allocated strings
* to avoid any possible overhead caused by string (re)allocation/formatting.
@@ -55,69 +54,232 @@ struct PointerRNA;
struct EvaluationContext;
struct FCurve;
+namespace DEG {
+
/* Evaluation Operation for atomic operation */
// XXX: move this to another header that can be exposed?
typedef function<void(struct EvaluationContext *)> DepsEvalOperationCb;
-/* Metatype of Nodes - The general "level" in the graph structure the node serves */
+/* Metatype of Nodes - The general "level" in the graph structure
+ * the node serves.
+ */
typedef enum eDepsNode_Class {
- DEPSNODE_CLASS_GENERIC = 0, /* Types generally unassociated with user-visible entities, but needed for graph functioning */
-
- DEPSNODE_CLASS_COMPONENT = 1, /* [Outer Node] An "aspect" of evaluating/updating an ID-Block, requiring certain types of evaluation behaviours */
- DEPSNODE_CLASS_OPERATION = 2, /* [Inner Node] A glorified function-pointer/callback for scheduling up evaluation operations for components, subject to relationship requirements */
+ /* Types generally unassociated with user-visible entities,
+ * but needed for graph functioning.
+ */
+ DEPSNODE_CLASS_GENERIC = 0,
+ /* [Outer Node] An "aspect" of evaluating/updating an ID-Block, requiring
+ * certain types of evaluation behavior.
+ */
+ DEPSNODE_CLASS_COMPONENT = 1,
+ /* [Inner Node] A glorified function-pointer/callback for scheduling up
+ * evaluation operations for components, subject to relationship
+ * requirements.
+ */
+ DEPSNODE_CLASS_OPERATION = 2,
} eDepsNode_Class;
/* Types of Nodes */
typedef enum eDepsNode_Type {
- DEPSNODE_TYPE_UNDEFINED = -1, /* fallback type for invalid return value */
+ /* Fallback type for invalid return value */
+ DEPSNODE_TYPE_UNDEFINED = -1,
+ /* Inner Node (Operation) */
+ DEPSNODE_TYPE_OPERATION = 0,
+
+ /* **** Generic Types **** */
+
+ /* "Current Scene" - basically whatever kicks off the evaluation process. */
+ DEPSNODE_TYPE_ROOT = 1,
+ /* Time-Source */
+ DEPSNODE_TYPE_TIMESOURCE = 2,
+ /* ID-Block reference - used as landmarks/collection point for components,
+ * but not usually part of main graph.
+ */
+ DEPSNODE_TYPE_ID_REF = 3,
+ /* Isolated sub-graph - used for keeping instanced data separate from
+ * instances using them.
+ */
+ DEPSNODE_TYPE_SUBGRAPH = 4,
- DEPSNODE_TYPE_OPERATION = 0, /* Inner Node (Operation) */
+ /* **** Outer Types **** */
- /* Generic Types */
- DEPSNODE_TYPE_ROOT = 1, /* "Current Scene" - basically whatever kicks off the evaluation process */
- DEPSNODE_TYPE_TIMESOURCE = 2, /* Time-Source */
+ /* Parameters Component - Default when nothing else fits
+ * (i.e. just SDNA property setting).
+ */
+ DEPSNODE_TYPE_PARAMETERS = 11,
+ /* Generic "Proxy-Inherit" Component
+ * XXX: Also for instancing of subgraphs?
+ */
+ DEPSNODE_TYPE_PROXY = 12,
+ /* Animation Component
+ *
+ * XXX: merge in with parameters?
+ */
+ DEPSNODE_TYPE_ANIMATION = 13,
+ /* Transform Component (Parenting/Constraints) */
+ DEPSNODE_TYPE_TRANSFORM = 14,
+ /* Geometry Component (DerivedMesh/Displist) */
+ DEPSNODE_TYPE_GEOMETRY = 15,
+ /* Sequencer Component (Scene Only) */
+ DEPSNODE_TYPE_SEQUENCER = 16,
+
+ /* **** Evaluation-Related Outer Types (with Subdata) **** */
+
+ /* Pose Component - Owner/Container of Bones Eval */
+ DEPSNODE_TYPE_EVAL_POSE = 21,
+ /* Bone Component - Child/Subcomponent of Pose */
+ DEPSNODE_TYPE_BONE = 22,
+ /* Particle Systems Component */
+ DEPSNODE_TYPE_EVAL_PARTICLES = 23,
+ /* Material Shading Component */
+ DEPSNODE_TYPE_SHADING = 24,
+} eDepsNode_Type;
- DEPSNODE_TYPE_ID_REF = 3, /* ID-Block reference - used as landmarks/collection point for components, but not usually part of main graph */
- DEPSNODE_TYPE_SUBGRAPH = 4, /* Isolated sub-graph - used for keeping instanced data separate from instances using them */
+/* Identifiers for common operations (as an enum). */
+typedef enum eDepsOperation_Code {
+ /* Generic Operations ------------------------------ */
- /* Outer Types */
- DEPSNODE_TYPE_PARAMETERS = 11, /* Parameters Component - Default when nothing else fits (i.e. just SDNA property setting) */
- DEPSNODE_TYPE_PROXY = 12, /* Generic "Proxy-Inherit" Component */ // XXX: Also for instancing of subgraphs?
- DEPSNODE_TYPE_ANIMATION = 13, /* Animation Component */ // XXX: merge in with parameters?
- DEPSNODE_TYPE_TRANSFORM = 14, /* Transform Component (Parenting/Constraints) */
- DEPSNODE_TYPE_GEOMETRY = 15, /* Geometry Component (DerivedMesh/Displist) */
- DEPSNODE_TYPE_SEQUENCER = 16, /* Sequencer Component (Scene Only) */
+ /* Placeholder for operations which don't need special mention */
+ DEG_OPCODE_OPERATION = 0,
- /* Evaluation-Related Outer Types (with Subdata) */
- DEPSNODE_TYPE_EVAL_POSE = 21, /* Pose Component - Owner/Container of Bones Eval */
- DEPSNODE_TYPE_BONE = 22, /* Bone Component - Child/Subcomponent of Pose */
+ // XXX: Placeholder while porting depsgraph code
+ DEG_OPCODE_PLACEHOLDER,
- DEPSNODE_TYPE_EVAL_PARTICLES = 23, /* Particle Systems Component */
- DEPSNODE_TYPE_SHADING = 24, /* Material Shading Component */
-} eDepsNode_Type;
+ DEG_OPCODE_NOOP,
-/* Identifiers for common operations (as an enum) */
-typedef enum eDepsOperation_Code {
-#define DEF_DEG_OPCODE(label) DEG_OPCODE_##label,
-#include "depsnode_opcodes.h"
-#undef DEF_DEG_OPCODE
+ /* Animation, Drivers, etc. ------------------------ */
+
+ /* NLA + Action */
+ DEG_OPCODE_ANIMATION,
+
+ /* Driver */
+ DEG_OPCODE_DRIVER,
+
+ /* Proxy Inherit? */
+ //DEG_OPCODE_PROXY,
+
+ /* Transform --------------------------------------- */
+
+ /* Transform entry point - local transforms only */
+ DEG_OPCODE_TRANSFORM_LOCAL,
+
+ /* Parenting */
+ DEG_OPCODE_TRANSFORM_PARENT,
+
+ /* Constraints */
+ DEG_OPCODE_TRANSFORM_CONSTRAINTS,
+ //DEG_OPCODE_TRANSFORM_CONSTRAINTS_INIT,
+ //DEG_OPCODE_TRANSFORM_CONSTRAINT,
+ //DEG_OPCODE_TRANSFORM_CONSTRAINTS_DONE,
+
+ /* Rigidbody Sim - Perform Sim */
+ DEG_OPCODE_RIGIDBODY_REBUILD,
+ DEG_OPCODE_RIGIDBODY_SIM,
+
+ /* Rigidbody Sim - Copy Results to Object */
+ DEG_OPCODE_TRANSFORM_RIGIDBODY,
+
+ /* Transform exitpoint */
+ DEG_OPCODE_TRANSFORM_FINAL,
+
+ /* XXX: ubereval is for temporary porting purposes only */
+ DEG_OPCODE_OBJECT_UBEREVAL,
+
+ /* Geometry ---------------------------------------- */
+
+ /* XXX: Placeholder - UberEval */
+ DEG_OPCODE_GEOMETRY_UBEREVAL,
+
+ /* Modifier */
+ DEG_OPCODE_GEOMETRY_MODIFIER,
+
+ /* Curve Objects - Path Calculation (used for path-following tools, */
+ DEG_OPCODE_GEOMETRY_PATH,
+
+ /* Pose -------------------------------------------- */
+
+ /* Init IK Trees, etc. */
+ DEG_OPCODE_POSE_INIT,
+
+ /* Free IK Trees + Compute Deform Matrices */
+ DEG_OPCODE_POSE_DONE,
+
+ /* IK/Spline Solvers */
+ DEG_OPCODE_POSE_IK_SOLVER,
+ DEG_OPCODE_POSE_SPLINE_IK_SOLVER,
+
+ /* Bone -------------------------------------------- */
+
+ /* Bone local transforms - Entrypoint */
+ DEG_OPCODE_BONE_LOCAL,
+
+ /* Pose-space conversion (includes parent + restpose, */
+ DEG_OPCODE_BONE_POSE_PARENT,
+
+ /* Constraints */
+ DEG_OPCODE_BONE_CONSTRAINTS,
+ //DEG_OPCODE_BONE_CONSTRAINTS_INIT,
+ //DEG_OPCODE_BONE_CONSTRAINT,
+ //DEG_OPCODE_BONE_CONSTRAINTS_DONE,
+
+ /* Bone transforms are ready
+ *
+ * - "READY" This (internal, noop is used to signal that all pre-IK
+ * operations are done. Its role is to help mediate situations
+ * where cyclic relations may otherwise form (i.e. one bone in
+ * chain targetting another in same chain,
+ *
+ * - "DONE" This noop is used to signal that the bone's final pose
+ * transform can be read by others
+ */
+ // TODO: deform mats could get calculated in the final_transform ops...
+ DEG_OPCODE_BONE_READY,
+ DEG_OPCODE_BONE_DONE,
+
+ /* Particles --------------------------------------- */
+
+ /* XXX: placeholder - Particle System eval */
+ DEG_OPCODE_PSYS_EVAL,
+
+ DEG_NUM_OPCODES,
} eDepsOperation_Code;
-/* String defines for these opcodes, defined in depsnode_operation.cpp */
-extern const char *DEG_OPNAMES[];
+/* Some magic to stringify operation codes. */
+class DepsOperationStringifier {
+public:
+ DepsOperationStringifier();
+ const char *operator[](eDepsOperation_Code opcodex);
+protected:
+ const char *names_[DEG_NUM_OPCODES];
+};
+/* String defines for these opcodes, defined in depsgraph_type_defines.cpp */
+extern DepsOperationStringifier DEG_OPNAMES;
/* Type of operation */
typedef enum eDepsOperation_Type {
- /* Primary operation types */
- DEPSOP_TYPE_INIT = 0, /* initialise evaluation data */
- DEPSOP_TYPE_EXEC = 1, /* standard evaluation step */
- DEPSOP_TYPE_POST = 2, /* cleanup evaluation data + flush results */
-
- /* Additional operation types */
- DEPSOP_TYPE_OUT = 3, /* indicator for outputting a temporary result that other components can use */ // XXX?
- DEPSOP_TYPE_SIM = 4, /* indicator for things like IK Solvers and Rigidbody Sim steps which modify final results of separate entities at once */
- DEPSOP_TYPE_REBUILD = 5, /* rebuild internal evaluation data - used for Rigidbody Reset and Armature Rebuild-On-Load */
+ /* **** Primary operation types **** */
+
+ /* Initialise evaluation data */
+ DEPSOP_TYPE_INIT = 0,
+ /* Standard evaluation step */
+ DEPSOP_TYPE_EXEC = 1,
+ /* Cleanup evaluation data + flush results */
+ DEPSOP_TYPE_POST = 2,
+
+ /* **** Additional operation types **** */
+ /* Indicator for outputting a temporary result that other components
+ * can use. // XXX?
+ */
+ DEPSOP_TYPE_OUT = 3,
+ /* Indicator for things like IK Solvers and Rigidbody Sim steps which
+ * modify final results of separate entities at once.
+ */
+ DEPSOP_TYPE_SIM = 4,
+ /* Rebuild internal evaluation data - used for Rigidbody Reset and
+ * Armature Rebuild-On-Load.
+ */
+ DEPSOP_TYPE_REBUILD = 5,
} eDepsOperation_Type;
/* Types of relationships between nodes
@@ -170,4 +332,4 @@ typedef enum eDepsRelation_Type {
DEPSREL_TYPE_UPDATE_UI,
} eDepsRelation_Type;
-#endif /* __DEPSGRAPH_TYPES_H__ */
+} // namespace DEG
diff --git a/source/blender/depsgraph/intern/depsnode_opcodes.h b/source/blender/depsgraph/intern/depsnode_opcodes.h
deleted file mode 100644
index b81822c0ac5..00000000000
--- a/source/blender/depsgraph/intern/depsnode_opcodes.h
+++ /dev/null
@@ -1,145 +0,0 @@
-/*
- * ***** BEGIN GPL LICENSE BLOCK *****
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * The Original Code is Copyright (C) 2014 Blender Foundation.
- * All rights reserved.
- *
- * Original Author: Joshua Leung
- * Contributor(s): None Yet
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-/** \file blender/depsgraph/intern/depsnode_opcodes.h
- * \ingroup depsgraph
- *
- * \par OpCodes for OperationDepsNodes
- *
- * This file defines all the "operation codes" (opcodes) used to identify
- * common operation node types. The intention of these defines is to have
- * a fast and reliable way of identifying the relevant nodes within a component
- * without having to use fragile dynamic strings.
- *
- * This file is meant to be used like UI_icons.h. That is, before including
- * the file, the host file must define the DEG_OPCODE(_label) macro, which
- * is responsible for converting the define into whatever form is suitable.
- * Therefore, it intentionally doesn't have header guards.
- */
-
-
-/* Example macro define: */
-/* #define DEF_DEG_OPCODE(label) DEG_OPCODE_##label, */
-
-/* Generic Operations ------------------------------ */
-
-/* Placeholder for operations which don't need special mention */
-DEF_DEG_OPCODE(OPERATION)
-
-// XXX: Placeholder while porting depsgraph code
-DEF_DEG_OPCODE(PLACEHOLDER)
-
-DEF_DEG_OPCODE(NOOP)
-
-/* Animation, Drivers, etc. ------------------------ */
-
-/* NLA + Action */
-DEF_DEG_OPCODE(ANIMATION)
-
-/* Driver */
-DEF_DEG_OPCODE(DRIVER)
-
-/* Proxy Inherit? */
-//DEF_DEG_OPCODE(PROXY)
-
-/* Transform --------------------------------------- */
-
-/* Transform entry point - local transforms only */
-DEF_DEG_OPCODE(TRANSFORM_LOCAL)
-
-/* Parenting */
-DEF_DEG_OPCODE(TRANSFORM_PARENT)
-
-/* Constraints */
-DEF_DEG_OPCODE(TRANSFORM_CONSTRAINTS)
-//DEF_DEG_OPCODE(TRANSFORM_CONSTRAINTS_INIT)
-//DEF_DEG_OPCODE(TRANSFORM_CONSTRAINT)
-//DEF_DEG_OPCODE(TRANSFORM_CONSTRAINTS_DONE)
-
-/* Rigidbody Sim - Perform Sim */
-DEF_DEG_OPCODE(RIGIDBODY_REBUILD)
-DEF_DEG_OPCODE(RIGIDBODY_SIM)
-
-/* Rigidbody Sim - Copy Results to Object */
-DEF_DEG_OPCODE(TRANSFORM_RIGIDBODY)
-
-/* Transform exitpoint */
-DEF_DEG_OPCODE(TRANSFORM_FINAL)
-
-/* XXX: ubereval is for temporary porting purposes only */
-DEF_DEG_OPCODE(OBJECT_UBEREVAL)
-
-/* Geometry ---------------------------------------- */
-
-/* XXX: Placeholder - UberEval */
-DEF_DEG_OPCODE(GEOMETRY_UBEREVAL)
-
-/* Modifier */
-DEF_DEG_OPCODE(GEOMETRY_MODIFIER)
-
-/* Curve Objects - Path Calculation (used for path-following tools) */
-DEF_DEG_OPCODE(GEOMETRY_PATH)
-
-/* Pose -------------------------------------------- */
-
-/* Init IK Trees, etc. */
-DEF_DEG_OPCODE(POSE_INIT)
-
-/* Free IK Trees + Compute Deform Matrices */
-DEF_DEG_OPCODE(POSE_DONE)
-
-/* IK/Spline Solvers */
-DEF_DEG_OPCODE(POSE_IK_SOLVER)
-DEF_DEG_OPCODE(POSE_SPLINE_IK_SOLVER)
-
-/* Bone -------------------------------------------- */
-
-/* Bone local transforms - Entrypoint */
-DEF_DEG_OPCODE(BONE_LOCAL)
-
-/* Pose-space conversion (includes parent + restpose) */
-DEF_DEG_OPCODE(BONE_POSE_PARENT)
-
-/* Constraints */
-DEF_DEG_OPCODE(BONE_CONSTRAINTS)
-//DEF_DEG_OPCODE(BONE_CONSTRAINTS_INIT)
-//DEF_DEG_OPCODE(BONE_CONSTRAINT)
-//DEF_DEG_OPCODE(BONE_CONSTRAINTS_DONE)
-
-/* Bone transforms are ready
- * - "READY" This (internal) noop is used to signal that all pre-IK operations are done.
- * Its role is to help mediate situations where cyclic relations may otherwise form
- * (i.e. one bone in chain targetting another in same chain)
- * - "DONE" This noop is used to signal that the bone's final pose transform can be read by others
- */
-// TODO: deform mats could get calculated in the final_transform ops...
-DEF_DEG_OPCODE(BONE_READY)
-DEF_DEG_OPCODE(BONE_DONE)
-
-/* Particles --------------------------------------- */
-
-/* XXX: placeholder - Particle System eval */
-DEF_DEG_OPCODE(PSYS_EVAL)
diff --git a/source/blender/depsgraph/intern/eval/deg_eval.cc b/source/blender/depsgraph/intern/eval/deg_eval.cc
new file mode 100644
index 00000000000..198cd349002
--- /dev/null
+++ b/source/blender/depsgraph/intern/eval/deg_eval.cc
@@ -0,0 +1,409 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2013 Blender Foundation.
+ * All rights reserved.
+ *
+ * Original Author: Joshua Leung
+ * Contributor(s): None Yet
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/depsgraph/intern/depsgraph_eval.cc
+ * \ingroup depsgraph
+ *
+ * Evaluation engine entrypoints for Depsgraph Engine.
+ */
+
+#include "intern/eval/deg_eval.h"
+
+#include "PIL_time.h"
+
+extern "C" {
+#include "BLI_utildefines.h"
+#include "BLI_task.h"
+#include "BLI_ghash.h"
+
+#include "BKE_depsgraph.h"
+#include "BKE_global.h"
+
+#include "DEG_depsgraph.h"
+} /* extern "C" */
+
+#include "atomic_ops.h"
+
+#include "intern/eval/deg_eval_debug.h"
+#include "intern/eval/deg_eval_flush.h"
+#include "intern/nodes/deg_node.h"
+#include "intern/nodes/deg_node_component.h"
+#include "intern/nodes/deg_node_operation.h"
+#include "intern/depsgraph.h"
+#include "util/deg_util_foreach.h"
+
+/* Unfinished and unused, and takes quite some pre-processing time. */
+#undef USE_EVAL_PRIORITY
+
+/* Use integrated debugger to keep track how much each of the nodes was
+ * evaluating.
+ */
+#undef USE_DEBUGGER
+
+namespace DEG {
+
+/* ********************** */
+/* Evaluation Entrypoints */
+
+/* Forward declarations. */
+static void schedule_children(TaskPool *pool,
+ Depsgraph *graph,
+ OperationDepsNode *node,
+ const int layers,
+ const int thread_id);
+
+struct DepsgraphEvalState {
+ EvaluationContext *eval_ctx;
+ Depsgraph *graph;
+ int layers;
+};
+
+static void deg_task_run_func(TaskPool *pool,
+ void *taskdata,
+ int thread_id)
+{
+ DepsgraphEvalState *state =
+ reinterpret_cast<DepsgraphEvalState *>(BLI_task_pool_userdata(pool));
+ OperationDepsNode *node = reinterpret_cast<OperationDepsNode *>(taskdata);
+
+ BLI_assert(!node->is_noop() && "NOOP nodes should not actually be scheduled");
+
+ /* Should only be the case for NOOPs, which never get to this point. */
+ BLI_assert(node->evaluate);
+
+ while (true) {
+ /* Get context. */
+ /* TODO: Who initialises this? "Init" operations aren't able to
+ * initialise it!!!
+ */
+ /* TODO(sergey): We don't use component contexts at this moment. */
+ /* ComponentDepsNode *comp = node->owner; */
+ BLI_assert(node->owner != NULL);
+
+ /* Since we're not leaving the thread for until the graph branches it is
+ * possible to have NO-OP on the way. for which evaluate() will be NULL.
+ * but that's all fine, we'll just scheduler it's children.
+ */
+ if (node->evaluate) {
+ /* Take note of current time. */
+#ifdef USE_DEBUGGER
+ double start_time = PIL_check_seconds_timer();
+ DepsgraphDebug::task_started(state->graph, node);
+#endif
+
+ /* Perform operation. */
+ node->evaluate(state->eval_ctx);
+
+ /* Note how long this took. */
+#ifdef USE_DEBUGGER
+ double end_time = PIL_check_seconds_timer();
+ DepsgraphDebug::task_completed(state->graph,
+ node,
+ end_time - start_time);
+#endif
+ }
+
+ /* If there's only one outgoing link we try to immediately switch to
+ * that node evaluation, without leaving the thread.
+ *
+ * It's only doable if the child don't have extra relations or all they
+ * are satisfied.
+ *
+ * TODO(sergey): Checks here can be de-duplicated with the ones from
+ * schedule_node(), however, how to do it nicely?
+ */
+ if (node->outlinks.size() == 1) {
+ DepsRelation *rel = node->outlinks[0];
+ OperationDepsNode *child = (OperationDepsNode *)rel->to;
+ BLI_assert(child->type == DEPSNODE_TYPE_OPERATION);
+ if (!child->scheduled) {
+ int id_layers = child->owner->owner->layers;
+ if (!((child->flag & DEPSOP_FLAG_NEEDS_UPDATE) != 0 &&
+ (id_layers & state->layers) != 0))
+ {
+ /* Node does not need an update, so can;t continue with the
+ * chain and need to switch to another one by leaving the
+ * thread.
+ */
+ break;
+ }
+ if ((rel->flag & DEPSREL_FLAG_CYCLIC) == 0) {
+ BLI_assert(child->num_links_pending > 0);
+ atomic_sub_uint32(&child->num_links_pending, 1);
+ }
+ if (child->num_links_pending == 0) {
+ bool is_scheduled = atomic_fetch_and_or_uint8(
+ (uint8_t *)&child->scheduled, (uint8_t)true);
+ if (!is_scheduled) {
+ /* Node was not scheduled, switch to it! */
+ node = child;
+ }
+ else {
+ /* Someone else scheduled the node, leaving us
+ * unemployed in this thread, we're leaving.
+ */
+ break;
+ }
+ }
+ else {
+ /* There are other dependencies on the child, can't do
+ * anything in the current thread.
+ */
+ break;
+ }
+ }
+ else {
+ /* Happens when having cyclic dependencies.
+ *
+ * Nothing to do here, single child was already scheduled, we
+ * can leave the thread now.
+ */
+ break;
+ }
+ }
+ else {
+ /* TODO(sergey): It's possible to use one of the outgoing relations
+ * as a chain which we'll try to keep alive, but it's a bit more
+ * involved change.
+ */
+ schedule_children(pool, state->graph, node, state->layers, thread_id);
+ break;
+ }
+ }
+}
+
+typedef struct CalculatePengindData {
+ Depsgraph *graph;
+ int layers;
+} CalculatePengindData;
+
+static void calculate_pending_func(void *data_v, int i)
+{
+ CalculatePengindData *data = (CalculatePengindData *)data_v;
+ Depsgraph *graph = data->graph;
+ int layers = data->layers;
+ OperationDepsNode *node = graph->operations[i];
+ IDDepsNode *id_node = node->owner->owner;
+
+ node->num_links_pending = 0;
+ node->scheduled = false;
+
+ /* count number of inputs that need updates */
+ if ((id_node->layers & layers) != 0 &&
+ (node->flag & DEPSOP_FLAG_NEEDS_UPDATE) != 0)
+ {
+ foreach (DepsRelation *rel, node->inlinks) {
+ if (rel->from->type == DEPSNODE_TYPE_OPERATION &&
+ (rel->flag & DEPSREL_FLAG_CYCLIC) == 0)
+ {
+ OperationDepsNode *from = (OperationDepsNode *)rel->from;
+ IDDepsNode *id_from_node = from->owner->owner;
+ if ((id_from_node->layers & layers) != 0 &&
+ (from->flag & DEPSOP_FLAG_NEEDS_UPDATE) != 0)
+ {
+ ++node->num_links_pending;
+ }
+ }
+ }
+ }
+}
+
+static void calculate_pending_parents(Depsgraph *graph, int layers)
+{
+ const int num_operations = graph->operations.size();
+ const bool do_threads = num_operations > 256;
+ CalculatePengindData data;
+ data.graph = graph;
+ data.layers = layers;
+ BLI_task_parallel_range(0,
+ num_operations,
+ &data,
+ calculate_pending_func,
+ do_threads);
+}
+
+#ifdef USE_EVAL_PRIORITY
+static void calculate_eval_priority(OperationDepsNode *node)
+{
+ if (node->done) {
+ return;
+ }
+ node->done = 1;
+
+ if (node->flag & DEPSOP_FLAG_NEEDS_UPDATE) {
+ /* XXX standard cost of a node, could be estimated somewhat later on */
+ const float cost = 1.0f;
+ /* NOOP nodes have no cost */
+ node->eval_priority = node->is_noop() ? cost : 0.0f;
+
+ foreach (DepsRelation *rel, node->outlinks) {
+ OperationDepsNode *to = (OperationDepsNode *)rel->to;
+ BLI_assert(to->type == DEPSNODE_TYPE_OPERATION);
+ calculate_eval_priority(to);
+ node->eval_priority += to->eval_priority;
+ }
+ }
+ else {
+ node->eval_priority = 0.0f;
+ }
+}
+#endif
+
+/* Schedule a node if it needs evaluation.
+ * dec_parents: Decrement pending parents count, true when child nodes are
+ * scheduled after a task has been completed.
+ */
+static void schedule_node(TaskPool *pool, Depsgraph *graph, int layers,
+ OperationDepsNode *node, bool dec_parents,
+ const int thread_id)
+{
+ int id_layers = node->owner->owner->layers;
+
+ if ((node->flag & DEPSOP_FLAG_NEEDS_UPDATE) != 0 &&
+ (id_layers & layers) != 0)
+ {
+ if (dec_parents) {
+ BLI_assert(node->num_links_pending > 0);
+ atomic_sub_uint32(&node->num_links_pending, 1);
+ }
+
+ if (node->num_links_pending == 0) {
+ bool is_scheduled = atomic_fetch_and_or_uint8(
+ (uint8_t *)&node->scheduled, (uint8_t)true);
+ if (!is_scheduled) {
+ if (node->is_noop()) {
+ /* skip NOOP node, schedule children right away */
+ schedule_children(pool, graph, node, layers, thread_id);
+ }
+ else {
+ /* children are scheduled once this task is completed */
+ BLI_task_pool_push_from_thread(pool,
+ deg_task_run_func,
+ node,
+ false,
+ TASK_PRIORITY_LOW,
+ thread_id);
+ }
+ }
+ }
+ }
+}
+
+static void schedule_graph(TaskPool *pool,
+ Depsgraph *graph,
+ const int layers)
+{
+ foreach (OperationDepsNode *node, graph->operations) {
+ schedule_node(pool, graph, layers, node, false, 0);
+ }
+}
+
+static void schedule_children(TaskPool *pool,
+ Depsgraph *graph,
+ OperationDepsNode *node,
+ const int layers,
+ const int thread_id)
+{
+ foreach (DepsRelation *rel, node->outlinks) {
+ OperationDepsNode *child = (OperationDepsNode *)rel->to;
+ BLI_assert(child->type == DEPSNODE_TYPE_OPERATION);
+ if (child->scheduled) {
+ /* Happens when having cyclic dependencies. */
+ continue;
+ }
+ schedule_node(pool,
+ graph,
+ layers,
+ child,
+ (rel->flag & DEPSREL_FLAG_CYCLIC) == 0,
+ thread_id);
+ }
+}
+
+/**
+ * Evaluate all nodes tagged for updating,
+ * \warning This is usually done as part of main loop, but may also be
+ * called from frame-change update.
+ *
+ * \note Time sources should be all valid!
+ */
+void deg_evaluate_on_refresh(EvaluationContext *eval_ctx,
+ Depsgraph *graph,
+ const int layers)
+{
+ /* Generate base evaluation context, upon which all the others are derived. */
+ // TODO: this needs both main and scene access...
+
+ /* Nothing to update, early out. */
+ if (BLI_gset_size(graph->entry_tags) == 0) {
+ return;
+ }
+
+ /* Set time for the current graph evaluation context. */
+ TimeSourceDepsNode *time_src = graph->find_time_source();
+ eval_ctx->ctime = time_src->cfra;
+
+ /* XXX could use a separate pool for each eval context */
+ DepsgraphEvalState state;
+ state.eval_ctx = eval_ctx;
+ state.graph = graph;
+ state.layers = layers;
+
+ TaskScheduler *task_scheduler = BLI_task_scheduler_get();
+ TaskPool *task_pool = BLI_task_pool_create(task_scheduler, &state);
+
+ if (G.debug & G_DEBUG_DEPSGRAPH_NO_THREADS) {
+ BLI_pool_set_num_threads(task_pool, 1);
+ }
+
+ calculate_pending_parents(graph, layers);
+
+ /* Clear tags. */
+ foreach (OperationDepsNode *node, graph->operations) {
+ node->done = 0;
+ }
+
+ /* Calculate priority for operation nodes. */
+#ifdef USE_EVAL_PRIORITY
+ foreach (OperationDepsNode *node, graph->operations) {
+ calculate_eval_priority(node);
+ }
+#endif
+
+ DepsgraphDebug::eval_begin(eval_ctx);
+
+ schedule_graph(task_pool, graph, layers);
+
+ BLI_task_pool_work_and_wait(task_pool);
+ BLI_task_pool_free(task_pool);
+
+ DepsgraphDebug::eval_end(eval_ctx);
+
+ /* Clear any uncleared tags - just in case. */
+ deg_graph_clear_tags(graph);
+}
+
+} // namespace DEG
diff --git a/source/blender/depsgraph/intern/eval/deg_eval.h b/source/blender/depsgraph/intern/eval/deg_eval.h
new file mode 100644
index 00000000000..0d42f63433f
--- /dev/null
+++ b/source/blender/depsgraph/intern/eval/deg_eval.h
@@ -0,0 +1,52 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2013 Blender Foundation.
+ * All rights reserved.
+ *
+ * Original Author: Joshua Leung
+ * Contributor(s): None Yet
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/depsgraph/intern/eval/deg_eval.cc
+ * \ingroup depsgraph
+ *
+ * Evaluation engine entrypoints for Depsgraph Engine.
+ */
+
+#pragma once
+
+struct EvaluationContext;
+
+namespace DEG {
+
+struct Depsgraph;
+
+/**
+ * Evaluate all nodes tagged for updating,
+ * \warning This is usually done as part of main loop, but may also be
+ * called from frame-change update.
+ *
+ * \note Time sources should be all valid!
+ */
+void deg_evaluate_on_refresh(EvaluationContext *eval_ctx,
+ Depsgraph *graph,
+ const int layers);
+
+} // namespace DEG
diff --git a/source/blender/depsgraph/intern/eval/deg_eval_debug.cc b/source/blender/depsgraph/intern/eval/deg_eval_debug.cc
new file mode 100644
index 00000000000..67d64aae8bf
--- /dev/null
+++ b/source/blender/depsgraph/intern/eval/deg_eval_debug.cc
@@ -0,0 +1,249 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2014 Blender Foundation.
+ * All rights reserved.
+ *
+ * Original Author: Lukas Toenne
+ * Contributor(s): None Yet
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/depsgraph/intern/eval/deg_eval_debug.cc
+ * \ingroup depsgraph
+ *
+ * Implementation of tools for debugging the depsgraph
+ */
+
+#include <cstring>
+
+#include "intern/eval/deg_eval_debug.h"
+
+extern "C" {
+#include "BLI_listbase.h"
+#include "BLI_ghash.h"
+
+#include "DEG_depsgraph_debug.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+} /* extern "C" */
+
+#include "intern/nodes/deg_node.h"
+#include "intern/nodes/deg_node_component.h"
+#include "intern/nodes/deg_node_operation.h"
+#include "intern/depsgraph_intern.h"
+
+namespace DEG {
+
+DepsgraphStats *DepsgraphDebug::stats = NULL;
+
+static string get_component_name(eDepsNode_Type type, const string &name = "")
+{
+ DepsNodeFactory *factory = deg_get_node_factory(type);
+ if (name.empty()) {
+ return string(factory->tname());
+ }
+ else {
+ return string(factory->tname()) + " | " + name;
+ }
+}
+
+static void times_clear(DepsgraphStatsTimes &times)
+{
+ times.duration_last = 0.0f;
+}
+
+static void times_add(DepsgraphStatsTimes &times, float time)
+{
+ times.duration_last += time;
+}
+
+void DepsgraphDebug::eval_begin(const EvaluationContext *UNUSED(eval_ctx))
+{
+ /* TODO(sergey): Stats are currently globally disabled. */
+ /* verify_stats(); */
+ reset_stats();
+}
+
+void DepsgraphDebug::eval_end(const EvaluationContext *UNUSED(eval_ctx))
+{
+ WM_main_add_notifier(NC_SPACE | ND_SPACE_INFO_REPORT, NULL);
+}
+
+void DepsgraphDebug::eval_step(const EvaluationContext *UNUSED(eval_ctx),
+ const char *message)
+{
+#ifdef DEG_DEBUG_BUILD
+ if (deg_debug_eval_cb)
+ deg_debug_eval_cb(deg_debug_eval_userdata, message);
+#else
+ (void)message; /* Ignored. */
+#endif
+}
+
+void DepsgraphDebug::task_started(Depsgraph *graph,
+ const OperationDepsNode *node)
+{
+ if (stats) {
+ BLI_spin_lock(&graph->lock);
+
+ ComponentDepsNode *comp = node->owner;
+ ID *id = comp->owner->id;
+
+ DepsgraphStatsID *id_stats = get_id_stats(id, true);
+ times_clear(id_stats->times);
+
+ /* XXX TODO use something like: if (id->flag & ID_DEG_DETAILS) {...} */
+ if (0) {
+ /* XXX component name usage needs cleanup! currently mixes identifier
+ * and description strings!
+ */
+ DepsgraphStatsComponent *comp_stats =
+ get_component_stats(id, get_component_name(comp->type,
+ comp->name),
+ true);
+ times_clear(comp_stats->times);
+ }
+
+ BLI_spin_unlock(&graph->lock);
+ }
+}
+
+void DepsgraphDebug::task_completed(Depsgraph *graph,
+ const OperationDepsNode *node,
+ double time)
+{
+ if (stats) {
+ BLI_spin_lock(&graph->lock);
+
+ ComponentDepsNode *comp = node->owner;
+ ID *id = comp->owner->id;
+
+ DepsgraphStatsID *id_stats = get_id_stats(id, true);
+ times_add(id_stats->times, time);
+
+ /* XXX TODO use something like: if (id->flag & ID_DEG_DETAILS) {...} */
+ if (0) {
+ /* XXX component name usage needs cleanup! currently mixes identifier
+ * and description strings!
+ */
+ DepsgraphStatsComponent *comp_stats =
+ get_component_stats(id,
+ get_component_name(comp->type,
+ comp->name),
+ true);
+ times_add(comp_stats->times, time);
+ }
+
+ BLI_spin_unlock(&graph->lock);
+ }
+}
+
+/* ********** */
+/* Statistics */
+
+
+/* GHash callback */
+static void deg_id_stats_free(void *val)
+{
+ DepsgraphStatsID *id_stats = (DepsgraphStatsID *)val;
+
+ if (id_stats) {
+ BLI_freelistN(&id_stats->components);
+ MEM_freeN(id_stats);
+ }
+}
+
+void DepsgraphDebug::stats_init()
+{
+ if (!stats) {
+ stats = (DepsgraphStats *)MEM_callocN(sizeof(DepsgraphStats),
+ "Depsgraph Stats");
+ stats->id_stats = BLI_ghash_new(BLI_ghashutil_ptrhash,
+ BLI_ghashutil_ptrcmp,
+ "Depsgraph ID Stats Hash");
+ }
+}
+
+void DepsgraphDebug::stats_free()
+{
+ if (stats) {
+ BLI_ghash_free(stats->id_stats, NULL, deg_id_stats_free);
+ MEM_freeN(stats);
+ stats = NULL;
+ }
+}
+
+void DepsgraphDebug::verify_stats()
+{
+ stats_init();
+}
+
+void DepsgraphDebug::reset_stats()
+{
+ if (!stats) {
+ return;
+ }
+
+ /* XXX this doesn't work, will immediately clear all info,
+ * since most depsgraph updates have none or very few updates to handle.
+ *
+ * Could consider clearing only zero-user ID blocks here
+ */
+// BLI_ghash_clear(stats->id_stats, NULL, deg_id_stats_free);
+}
+
+DepsgraphStatsID *DepsgraphDebug::get_id_stats(ID *id, bool create)
+{
+ DepsgraphStatsID *id_stats = (DepsgraphStatsID *)BLI_ghash_lookup(stats->id_stats, id);
+
+ if (!id_stats && create) {
+ id_stats = (DepsgraphStatsID *)MEM_callocN(sizeof(DepsgraphStatsID),
+ "Depsgraph ID Stats");
+ id_stats->id = id;
+
+ BLI_ghash_insert(stats->id_stats, id, id_stats);
+ }
+
+ return id_stats;
+}
+
+DepsgraphStatsComponent *DepsgraphDebug::get_component_stats(
+ DepsgraphStatsID *id_stats,
+ const string &name,
+ bool create)
+{
+ DepsgraphStatsComponent *comp_stats;
+ for (comp_stats = (DepsgraphStatsComponent *)id_stats->components.first;
+ comp_stats != NULL;
+ comp_stats = comp_stats->next)
+ {
+ if (STREQ(comp_stats->name, name.c_str()))
+ break;
+ }
+ if (!comp_stats && create) {
+ comp_stats = (DepsgraphStatsComponent *)MEM_callocN(sizeof(DepsgraphStatsComponent),
+ "Depsgraph Component Stats");
+ BLI_strncpy(comp_stats->name, name.c_str(), sizeof(comp_stats->name));
+ BLI_addtail(&id_stats->components, comp_stats);
+ }
+ return comp_stats;
+}
+
+} // namespace DEG
diff --git a/source/blender/depsgraph/intern/depsgraph_debug.h b/source/blender/depsgraph/intern/eval/deg_eval_debug.h
index 64b97855f57..9109019eb2d 100644
--- a/source/blender/depsgraph/intern/depsgraph_debug.h
+++ b/source/blender/depsgraph/intern/eval/deg_eval_debug.h
@@ -24,27 +24,26 @@
* ***** END GPL LICENSE BLOCK *****
*/
-/** \file blender/depsgraph/intern/depsgraph_debug.h
+/** \file blender/depsgraph/intern/eval/deg_eval_debug.h
* \ingroup depsgraph
*/
-#ifndef __DEPSGRAPH_DEBUG_H__
-#define __DEPSGRAPH_DEBUG_H__
+#pragma once
-#include "depsgraph_types.h"
+#include "intern/depsgraph_types.h"
-extern "C" {
-#include "BKE_global.h"
-}
+struct ID;
+struct EvaluationContext;
struct DepsgraphStats;
struct DepsgraphStatsID;
struct DepsgraphStatsComponent;
-struct DepsgraphSettings;
-struct EvaluationContext;
-struct OperationDepsNode;
+
+namespace DEG {
struct Depsgraph;
+struct DepsgraphSettings;
+struct OperationDepsNode;
struct DepsgraphDebug {
static DepsgraphStats *stats;
@@ -77,11 +76,4 @@ struct DepsgraphDebug {
}
};
-#define DEG_DEBUG_PRINTF(...) \
- { \
- if (G.debug & G_DEBUG_DEPSGRAPH) { \
- fprintf(stderr, __VA_ARGS__); \
- } \
- } \
-
-#endif /* __DEPSGRAPH_DEBUG_H__ */
+} // namespace DEG
diff --git a/source/blender/depsgraph/intern/eval/deg_eval_flush.cc b/source/blender/depsgraph/intern/eval/deg_eval_flush.cc
new file mode 100644
index 00000000000..30d243867b0
--- /dev/null
+++ b/source/blender/depsgraph/intern/eval/deg_eval_flush.cc
@@ -0,0 +1,227 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2013 Blender Foundation.
+ * All rights reserved.
+ *
+ * Original Author: Joshua Leung
+ * Contributor(s): None Yet
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/depsgraph/intern/depsgraph_tag.cc
+ * \ingroup depsgraph
+ *
+ * Core routines for how the Depsgraph works.
+ */
+
+#include "intern/eval/deg_eval_flush.h"
+
+// TODO(sergey): Use some sort of wrapper.
+#include <queue>
+
+extern "C" {
+#include "DNA_object_types.h"
+
+#include "BLI_utildefines.h"
+#include "BLI_task.h"
+#include "BLI_ghash.h"
+
+#include "DEG_depsgraph.h"
+} /* extern "C" */
+
+#include "intern/nodes/deg_node.h"
+#include "intern/nodes/deg_node_component.h"
+#include "intern/nodes/deg_node_operation.h"
+
+#include "intern/depsgraph_intern.h"
+#include "util/deg_util_foreach.h"
+
+namespace DEG {
+
+namespace {
+
+// TODO(sergey): De-duplicate with depsgraph_tag,cc
+void lib_id_recalc_tag(Main *bmain, ID *id)
+{
+ id->tag |= LIB_TAG_ID_RECALC;
+ DEG_id_type_tag(bmain, GS(id->name));
+}
+
+void lib_id_recalc_data_tag(Main *bmain, ID *id)
+{
+ id->tag |= LIB_TAG_ID_RECALC_DATA;
+ DEG_id_type_tag(bmain, GS(id->name));
+}
+
+} /* namespace */
+
+typedef std::queue<OperationDepsNode *> FlushQueue;
+
+static void flush_init_func(void *data_v, int i)
+{
+ /* ID node's done flag is used to avoid multiple editors update
+ * for the same ID.
+ */
+ Depsgraph *graph = (Depsgraph *)data_v;
+ OperationDepsNode *node = graph->operations[i];
+ IDDepsNode *id_node = node->owner->owner;
+ id_node->done = 0;
+ node->scheduled = false;
+ node->owner->flags &= ~DEPSCOMP_FULLY_SCHEDULED;
+ if (node->owner->type == DEPSNODE_TYPE_PROXY) {
+ node->flag |= DEPSOP_FLAG_NEEDS_UPDATE;
+ }
+}
+
+/* Flush updates from tagged nodes outwards until all affected nodes
+ * are tagged.
+ */
+void deg_graph_flush_updates(Main *bmain, Depsgraph *graph)
+{
+ /* Sanity check. */
+ if (graph == NULL) {
+ return;
+ }
+
+ /* Nothing to update, early out. */
+ if (BLI_gset_size(graph->entry_tags) == 0) {
+ return;
+ }
+
+ /* TODO(sergey): With a bit of flag magic we can get rid of this
+ * extra loop.
+ */
+ const int num_operations = graph->operations.size();
+ const bool do_threads = num_operations > 256;
+ BLI_task_parallel_range(0,
+ num_operations,
+ graph,
+ flush_init_func,
+ do_threads);
+
+ FlushQueue queue;
+ /* Starting from the tagged "entry" nodes, flush outwards... */
+ /* NOTE: Also need to ensure that for each of these, there is a path back to
+ * root, or else they won't be done.
+ * NOTE: Count how many nodes we need to handle - entry nodes may be
+ * component nodes which don't count for this purpose!
+ */
+ GSET_FOREACH_BEGIN(OperationDepsNode *, node, graph->entry_tags)
+ {
+ queue.push(node);
+ node->scheduled = true;
+ }
+ GSET_FOREACH_END();
+
+ while (!queue.empty()) {
+ OperationDepsNode *node = queue.front();
+ queue.pop();
+
+ for (;;) {
+ node->flag |= DEPSOP_FLAG_NEEDS_UPDATE;
+
+ IDDepsNode *id_node = node->owner->owner;
+
+ if (id_node->done == 0) {
+ deg_editors_id_update(bmain, id_node->id);
+ id_node->done = 1;
+ }
+
+ lib_id_recalc_tag(bmain, id_node->id);
+ /* TODO(sergey): For until we've got proper data nodes in the graph. */
+ lib_id_recalc_data_tag(bmain, id_node->id);
+
+ ID *id = id_node->id;
+ /* This code is used to preserve those areas which does direct
+ * object update,
+ *
+ * Plus it ensures visibility changes and relations and layers
+ * visibility update has proper flags to work with.
+ */
+ if (GS(id->name) == ID_OB) {
+ Object *object = (Object *)id;
+ ComponentDepsNode *comp_node = node->owner;
+ if (comp_node->type == DEPSNODE_TYPE_ANIMATION) {
+ object->recalc |= OB_RECALC_TIME;
+ }
+ else if (comp_node->type == DEPSNODE_TYPE_TRANSFORM) {
+ object->recalc |= OB_RECALC_OB;
+ }
+ else {
+ object->recalc |= OB_RECALC_DATA;
+ }
+ }
+
+ /* TODO(sergey): For until incremental updates are possible
+ * witin a component at least we tag the whole component
+ * for update.
+ */
+ ComponentDepsNode *component = node->owner;
+ if ((component->flags & DEPSCOMP_FULLY_SCHEDULED) == 0) {
+ foreach (OperationDepsNode *op, component->operations) {
+ op->flag |= DEPSOP_FLAG_NEEDS_UPDATE;
+ }
+ component->flags |= DEPSCOMP_FULLY_SCHEDULED;
+ }
+
+ /* Flush to nodes along links... */
+ if (node->outlinks.size() == 1) {
+ OperationDepsNode *to_node = (OperationDepsNode *)node->outlinks[0]->to;
+ if (to_node->scheduled == false) {
+ to_node->scheduled = true;
+ node = to_node;
+ }
+ else {
+ break;
+ }
+ }
+ else {
+ foreach (DepsRelation *rel, node->outlinks) {
+ OperationDepsNode *to_node = (OperationDepsNode *)rel->to;
+ if (to_node->scheduled == false) {
+ queue.push(to_node);
+ to_node->scheduled = true;
+ }
+ }
+ break;
+ }
+ }
+ }
+}
+
+static void graph_clear_func(void *data_v, int i)
+{
+ Depsgraph *graph = (Depsgraph *)data_v;
+ OperationDepsNode *node = graph->operations[i];
+ /* Clear node's "pending update" settings. */
+ node->flag &= ~(DEPSOP_FLAG_DIRECTLY_MODIFIED | DEPSOP_FLAG_NEEDS_UPDATE);
+}
+
+/* Clear tags from all operation nodes. */
+void deg_graph_clear_tags(Depsgraph *graph)
+{
+ /* Go over all operation nodes, clearing tags. */
+ const int num_operations = graph->operations.size();
+ const bool do_threads = num_operations > 256;
+ BLI_task_parallel_range(0, num_operations, graph, graph_clear_func, do_threads);
+ /* Clear any entry tags which haven't been flushed. */
+ BLI_gset_clear(graph->entry_tags, NULL);
+}
+
+} // namespace DEG
diff --git a/source/blender/depsgraph/intern/eval/deg_eval_flush.h b/source/blender/depsgraph/intern/eval/deg_eval_flush.h
new file mode 100644
index 00000000000..8912aebee7d
--- /dev/null
+++ b/source/blender/depsgraph/intern/eval/deg_eval_flush.h
@@ -0,0 +1,49 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2013 Blender Foundation.
+ * All rights reserved.
+ *
+ * Original Author: Joshua Leung
+ * Contributor(s): None Yet
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/depsgraph/intern/eval/deg_eval_flush.cc
+ * \ingroup depsgraph
+ *
+ * Core routines for how the Depsgraph works.
+ */
+
+#pragma once
+
+struct Main;
+
+namespace DEG {
+
+struct Depsgraph;
+
+/* Flush updates from tagged nodes outwards until all affected nodes
+ * are tagged.
+ */
+void deg_graph_flush_updates(struct Main *bmain, struct Depsgraph *graph);
+
+/* Clear tags from all operation nodes. */
+void deg_graph_clear_tags(struct Depsgraph *graph);
+
+} // namespace DEG
diff --git a/source/blender/depsgraph/intern/depsnode.cc b/source/blender/depsgraph/intern/nodes/deg_node.cc
index 8aa1059d2dc..78293f7f483 100644
--- a/source/blender/depsgraph/intern/depsnode.cc
+++ b/source/blender/depsgraph/intern/nodes/deg_node.cc
@@ -28,10 +28,13 @@
* \ingroup depsgraph
*/
+#include "intern/nodes/deg_node.h"
+
#include <stdio.h>
#include <string.h>
#include "BLI_utildefines.h"
+#include "BLI_ghash.h"
extern "C" {
#include "DNA_ID.h"
@@ -42,10 +45,13 @@ extern "C" {
#include "DEG_depsgraph.h"
}
-#include "depsnode.h" /* own include */
-#include "depsnode_component.h"
-#include "depsnode_operation.h"
-#include "depsgraph_intern.h"
+#include "intern/nodes/deg_node_component.h"
+#include "intern/nodes/deg_node_operation.h"
+#include "intern/depsgraph_intern.h"
+#include "util/deg_util_foreach.h"
+#include "util/deg_util_hash.h"
+
+namespace DEG {
/* *************** */
/* Node Management */
@@ -66,7 +72,7 @@ DepsNode::TypeInfo::TypeInfo(eDepsNode_Type type, const char *tname)
DepsNode::DepsNode()
{
- this->name[0] = '\0';
+ name[0] = '\0';
}
DepsNode::~DepsNode()
@@ -76,11 +82,9 @@ DepsNode::~DepsNode()
* when we're trying to free same link from both it's sides. We don't have
* dangling links so this is not a problem from memory leaks point of view.
*/
- DEPSNODE_RELATIONS_ITER_BEGIN(this->inlinks, rel)
- {
+ foreach (DepsRelation *rel, inlinks) {
OBJECT_GUARDED_DELETE(rel, DepsRelation);
}
- DEPSNODE_RELATIONS_ITER_END;
}
@@ -100,11 +104,7 @@ string DepsNode::identifier() const
void TimeSourceDepsNode::tag_update(Depsgraph *graph)
{
- for (DepsNode::Relations::const_iterator it = outlinks.begin();
- it != outlinks.end();
- ++it)
- {
- DepsRelation *rel = *it;
+ foreach (DepsRelation *rel, outlinks) {
DepsNode *node = rel->to;
node->tag_update(graph);
}
@@ -125,7 +125,7 @@ RootDepsNode::~RootDepsNode()
TimeSourceDepsNode *RootDepsNode::add_time_source(const string &name)
{
if (!time_source) {
- DepsNodeFactory *factory = DEG_get_node_factory(DEPSNODE_TYPE_TIMESOURCE);
+ DepsNodeFactory *factory = deg_get_node_factory(DEPSNODE_TYPE_TIMESOURCE);
time_source = (TimeSourceDepsNode *)factory->create_node(NULL, "", name);
/*time_source->owner = this;*/ // XXX
}
@@ -142,6 +142,36 @@ static DepsNodeFactoryImpl<TimeSourceDepsNode> DNTI_TIMESOURCE;
/* ID Node ================================================ */
+static unsigned int id_deps_node_hash_key(const void *key_v)
+{
+ const IDDepsNode::ComponentIDKey *key =
+ reinterpret_cast<const IDDepsNode::ComponentIDKey *>(key_v);
+ return hash_combine(BLI_ghashutil_uinthash(key->type),
+ BLI_ghashutil_strhash_p(key->name.c_str()));
+}
+
+static bool id_deps_node_hash_key_cmp(const void *a, const void *b)
+{
+ const IDDepsNode::ComponentIDKey *key_a =
+ reinterpret_cast<const IDDepsNode::ComponentIDKey *>(a);
+ const IDDepsNode::ComponentIDKey *key_b =
+ reinterpret_cast<const IDDepsNode::ComponentIDKey *>(b);
+ return !(*key_a == *key_b);
+}
+
+static void id_deps_node_hash_key_free(void *key_v)
+{
+ typedef IDDepsNode::ComponentIDKey ComponentIDKey;
+ ComponentIDKey *key = reinterpret_cast<ComponentIDKey *>(key_v);
+ OBJECT_GUARDED_DELETE(key, ComponentIDKey);
+}
+
+static void id_deps_node_hash_value_free(void *value_v)
+{
+ ComponentDepsNode *comp_node = reinterpret_cast<ComponentDepsNode *>(value_v);
+ OBJECT_GUARDED_DELETE(comp_node, ComponentDepsNode);
+}
+
/* Initialize 'id' node - from pointer data given. */
void IDDepsNode::init(const ID *id, const string &UNUSED(subdata))
{
@@ -151,6 +181,10 @@ void IDDepsNode::init(const ID *id, const string &UNUSED(subdata))
this->layers = (1 << 20) - 1;
this->eval_flags = 0;
+ components = BLI_ghash_new(id_deps_node_hash_key,
+ id_deps_node_hash_key_cmp,
+ "Depsgraph id components hash");
+
/* NOTE: components themselves are created if/when needed.
* This prevents problems with components getting added
* twice if an ID-Ref needs to be created to house it...
@@ -161,51 +195,27 @@ void IDDepsNode::init(const ID *id, const string &UNUSED(subdata))
IDDepsNode::~IDDepsNode()
{
clear_components();
-}
-
-/* Copy 'id' node. */
-void IDDepsNode::copy(DepsgraphCopyContext *dcc, const IDDepsNode *src)
-{
- (void)src; /* Ignored. */
- /* Iterate over items in original hash, adding them to new hash. */
- for (IDDepsNode::ComponentMap::const_iterator it = this->components.begin();
- it != this->components.end();
- ++it)
- {
- /* Get current <type : component> mapping. */
- ComponentIDKey c_key = it->first;
- DepsNode *old_component = it->second;
-
- /* Make a copy of component. */
- ComponentDepsNode *component = (ComponentDepsNode *)DEG_copy_node(dcc, old_component);
-
- /* Add new node to hash... */
- this->components[c_key] = component;
- }
-
- // TODO: perform a second loop to fix up links?
- BLI_assert(!"Not expected to be used");
+ BLI_ghash_free(components, id_deps_node_hash_key_free, NULL);
}
ComponentDepsNode *IDDepsNode::find_component(eDepsNode_Type type,
const string &name) const
{
ComponentIDKey key(type, name);
- ComponentMap::const_iterator it = components.find(key);
- return it != components.end() ? it->second : NULL;
+ return reinterpret_cast<ComponentDepsNode *>(BLI_ghash_lookup(components, &key));
}
ComponentDepsNode *IDDepsNode::add_component(eDepsNode_Type type,
const string &name)
{
- ComponentIDKey key(type, name);
ComponentDepsNode *comp_node = find_component(type, name);
if (!comp_node) {
- DepsNodeFactory *factory = DEG_get_node_factory(type);
+ DepsNodeFactory *factory = deg_get_node_factory(type);
comp_node = (ComponentDepsNode *)factory->create_node(this->id, "", name);
/* Register. */
- this->components[key] = comp_node;
+ ComponentIDKey *key = OBJECT_GUARDED_NEW(ComponentIDKey, type, name);
+ BLI_ghash_insert(components, key, comp_node);
comp_node->owner = this;
}
return comp_node;
@@ -213,34 +223,28 @@ ComponentDepsNode *IDDepsNode::add_component(eDepsNode_Type type,
void IDDepsNode::remove_component(eDepsNode_Type type, const string &name)
{
- ComponentIDKey key(type, name);
ComponentDepsNode *comp_node = find_component(type, name);
if (comp_node) {
/* Unregister. */
- this->components.erase(key);
- OBJECT_GUARDED_DELETE(comp_node, ComponentDepsNode);
+ ComponentIDKey key(type, name);
+ BLI_ghash_remove(components,
+ &key,
+ id_deps_node_hash_key_free,
+ id_deps_node_hash_value_free);
}
}
void IDDepsNode::clear_components()
{
- for (ComponentMap::const_iterator it = components.begin();
- it != components.end();
- ++it)
- {
- ComponentDepsNode *comp_node = it->second;
- OBJECT_GUARDED_DELETE(comp_node, ComponentDepsNode);
- }
- components.clear();
+ BLI_ghash_clear(components,
+ id_deps_node_hash_key_free,
+ id_deps_node_hash_value_free);
}
void IDDepsNode::tag_update(Depsgraph *graph)
{
- for (ComponentMap::const_iterator it = components.begin();
- it != components.end();
- ++it)
+ GHASH_FOREACH_BEGIN(ComponentDepsNode *, comp_node, components)
{
- ComponentDepsNode *comp_node = it->second;
/* TODO(sergey): What about drievrs? */
bool do_component_tag = comp_node->type != DEPSNODE_TYPE_ANIMATION;
if (comp_node->type == DEPSNODE_TYPE_ANIMATION) {
@@ -254,6 +258,16 @@ void IDDepsNode::tag_update(Depsgraph *graph)
comp_node->tag_update(graph);
}
}
+ GHASH_FOREACH_END();
+}
+
+void IDDepsNode::finalize_build()
+{
+ GHASH_FOREACH_BEGIN(ComponentDepsNode *, comp_node, components)
+ {
+ comp_node->finalize_build();
+ }
+ GHASH_FOREACH_END();
}
DEG_DEPSNODE_DEFINE(IDDepsNode, DEPSNODE_TYPE_ID_REF, "ID Node");
@@ -281,31 +295,21 @@ SubgraphDepsNode::~SubgraphDepsNode()
// XXX: prune these flags a bit...
if ((this->flag & SUBGRAPH_FLAG_FIRSTREF) || !(this->flag & SUBGRAPH_FLAG_SHARED)) {
/* Free the referenced graph. */
- DEG_graph_free(this->graph);
- this->graph = NULL;
+ DEG_graph_free(reinterpret_cast< ::Depsgraph* >(graph));
+ graph = NULL;
}
}
-/* Copy 'subgraph' node - Assume that the subgraph doesn't get copied for now... */
-void SubgraphDepsNode::copy(DepsgraphCopyContext * /*dcc*/,
- const SubgraphDepsNode * /*src*/)
-{
- //const SubgraphDepsNode *src_node = (const SubgraphDepsNode *)src;
- //SubgraphDepsNode *dst_node = (SubgraphDepsNode *)dst;
-
- /* for now, subgraph itself isn't copied... */
- BLI_assert(!"Not expected to be used");
-}
-
DEG_DEPSNODE_DEFINE(SubgraphDepsNode, DEPSNODE_TYPE_SUBGRAPH, "Subgraph Node");
static DepsNodeFactoryImpl<SubgraphDepsNode> DNTI_SUBGRAPH;
-
-void DEG_register_base_depsnodes()
+void deg_register_base_depsnodes()
{
- DEG_register_node_typeinfo(&DNTI_ROOT);
- DEG_register_node_typeinfo(&DNTI_TIMESOURCE);
+ deg_register_node_typeinfo(&DNTI_ROOT);
+ deg_register_node_typeinfo(&DNTI_TIMESOURCE);
- DEG_register_node_typeinfo(&DNTI_ID_REF);
- DEG_register_node_typeinfo(&DNTI_SUBGRAPH);
+ deg_register_node_typeinfo(&DNTI_ID_REF);
+ deg_register_node_typeinfo(&DNTI_SUBGRAPH);
}
+
+} // namespace DEG
diff --git a/source/blender/depsgraph/intern/depsnode.h b/source/blender/depsgraph/intern/nodes/deg_node.h
index 4a464955384..d79d3d2348d 100644
--- a/source/blender/depsgraph/intern/depsnode.h
+++ b/source/blender/depsgraph/intern/nodes/deg_node.h
@@ -28,21 +28,18 @@
* \ingroup depsgraph
*/
-#ifndef __DEPSNODE_H__
-#define __DEPSNODE_H__
+#pragma once
-#include "depsgraph_types.h"
-
-#include "depsgraph_util_hash.h"
-#include "depsgraph_util_map.h"
-#include "depsgraph_util_set.h"
+#include "intern/depsgraph_types.h"
struct ID;
+struct GHash;
struct Scene;
+namespace DEG {
+
struct Depsgraph;
struct DepsRelation;
-struct DepsgraphCopyContext;
struct OperationDepsNode;
/* *********************************** */
@@ -94,8 +91,6 @@ struct DepsNode {
virtual void init(const ID * /*id*/,
const string &/*subdata*/) {}
- virtual void copy(DepsgraphCopyContext * /*dcc*/,
- const DepsNode * /*src*/) {}
virtual void tag_update(Depsgraph * /*graph*/) {}
@@ -160,24 +155,7 @@ struct IDDepsNode : public DepsNode {
string name;
};
- /* XXX can't specialize std::hash for this purpose, because ComponentIDKey is
- * a nested type ...
- *
- * http://stackoverflow.com/a/951245
- */
- struct component_key_hash {
- bool operator() (const ComponentIDKey &key) const
- {
- return hash_combine(hash<int>()(key.type), hash<string>()(key.name));
- }
- };
-
- typedef unordered_map<ComponentIDKey,
- ComponentDepsNode *,
- component_key_hash> ComponentMap;
-
void init(const ID *id, const string &subdata);
- void copy(DepsgraphCopyContext *dcc, const IDDepsNode *src);
~IDDepsNode();
ComponentDepsNode *find_component(eDepsNode_Type type,
@@ -189,11 +167,13 @@ struct IDDepsNode : public DepsNode {
void tag_update(Depsgraph *graph);
+ void finalize_build();
+
/* ID Block referenced. */
ID *id;
/* Hash to make it faster to look up components. */
- ComponentMap components;
+ GHash *components;
/* Layers of this node with accumulated layers of it's output relations. */
int layers;
@@ -210,7 +190,6 @@ struct IDDepsNode : public DepsNode {
/* Subgraph Reference. */
struct SubgraphDepsNode : public DepsNode {
void init(const ID *id, const string &subdata);
- void copy(DepsgraphCopyContext *dcc, const SubgraphDepsNode *src);
~SubgraphDepsNode();
/* Instanced graph. */
@@ -243,6 +222,6 @@ typedef enum eSubgraphRef_Flag {
SUBGRAPH_FLAG_FIRSTREF = (1 << 1),
} eSubgraphRef_Flag;
-void DEG_register_base_depsnodes();
+void deg_register_base_depsnodes();
-#endif /* __DEPSNODE_H__ */
+} // namespace DEG
diff --git a/source/blender/depsgraph/intern/depsnode_component.cc b/source/blender/depsgraph/intern/nodes/deg_node_component.cc
index a47a0d29228..7e49fec051f 100644
--- a/source/blender/depsgraph/intern/depsnode_component.cc
+++ b/source/blender/depsgraph/intern/nodes/deg_node_component.cc
@@ -28,6 +28,8 @@
* \ingroup depsgraph
*/
+#include "intern/nodes/deg_node_component.h"
+
#include <stdio.h>
#include <string.h>
@@ -39,20 +41,57 @@ extern "C" {
#include "BKE_action.h"
} /* extern "C" */
-#include "depsnode_component.h" /* own include */
-#include "depsnode_operation.h"
-#include "depsgraph_intern.h"
+#include "intern/nodes/deg_node_operation.h"
+#include "intern/depsgraph_intern.h"
+#include "util/deg_util_foreach.h"
+#include "util/deg_util_hash.h"
+
+namespace DEG {
/* *********** */
/* Outer Nodes */
/* Standard Component Methods ============================= */
+static unsigned int comp_node_hash_key(const void *key_v)
+{
+ const ComponentDepsNode::OperationIDKey *key =
+ reinterpret_cast<const ComponentDepsNode::OperationIDKey *>(key_v);
+ return hash_combine(BLI_ghashutil_uinthash(key->opcode),
+ BLI_ghashutil_strhash_p(key->name.c_str()));
+}
+
+static bool comp_node_hash_key_cmp(const void *a, const void *b)
+{
+ const ComponentDepsNode::OperationIDKey *key_a =
+ reinterpret_cast<const ComponentDepsNode::OperationIDKey *>(a);
+ const ComponentDepsNode::OperationIDKey *key_b =
+ reinterpret_cast<const ComponentDepsNode::OperationIDKey *>(b);
+ return !(*key_a == *key_b);
+}
+
+static void comp_node_hash_key_free(void *key_v)
+{
+ typedef ComponentDepsNode::OperationIDKey OperationIDKey;
+ OperationIDKey *key = reinterpret_cast<OperationIDKey *>(key_v);
+ OBJECT_GUARDED_DELETE(key, OperationIDKey);
+}
+
+static void comp_node_hash_value_free(void *value_v)
+{
+ OperationDepsNode *op_node = reinterpret_cast<OperationDepsNode *>(value_v);
+ OBJECT_GUARDED_DELETE(op_node, OperationDepsNode);
+}
+
ComponentDepsNode::ComponentDepsNode() :
entry_operation(NULL),
exit_operation(NULL),
- flags(0)
+ flags(0),
+ layers(0)
{
+ operations_map = BLI_ghash_new(comp_node_hash_key,
+ comp_node_hash_key_cmp,
+ "Depsgraph id hash");
}
/* Initialize 'component' node - from pointer data given */
@@ -63,37 +102,15 @@ void ComponentDepsNode::init(const ID * /*id*/,
// XXX: maybe this needs a special API?
}
-/* Copy 'component' node */
-void ComponentDepsNode::copy(DepsgraphCopyContext * /*dcc*/,
- const ComponentDepsNode * /*src*/)
-{
-#if 0 // XXX: remove all this
- /* duplicate list of operation nodes */
- this->operations.clear();
-
- for (OperationMap::const_iterator it = src->operations.begin(); it != src->operations.end(); ++it) {
- const string &pchan_name = it->first;
- OperationDepsNode *src_op = it->second;
-
- /* recursive copy */
- DepsNodeFactory *factory = DEG_node_get_factory(src_op);
- OperationDepsNode *dst_op = (OperationDepsNode *)factory->copy_node(dcc, src_op);
- this->operations[pchan_name] = dst_op;
-
- /* fix links... */
- // ...
- }
-
- /* copy evaluation contexts */
- //
-#endif
- BLI_assert(!"Not expected to be called");
-}
-
/* Free 'component' node */
ComponentDepsNode::~ComponentDepsNode()
{
clear_operations();
+ if (operations_map != NULL) {
+ BLI_ghash_free(operations_map,
+ comp_node_hash_key_free,
+ comp_node_hash_value_free);
+ }
}
string ComponentDepsNode::identifier() const
@@ -103,15 +120,17 @@ string ComponentDepsNode::identifier() const
char typebuf[7];
sprintf(typebuf, "(%d)", type);
- return string(typebuf) + name + " : " + idname;
+ char layers[7];
+ sprintf(layers, "%d", this->layers);
+
+ return string(typebuf) + name + " : " + idname + " (Layers: " + layers + ")";
}
OperationDepsNode *ComponentDepsNode::find_operation(OperationIDKey key) const
{
- OperationMap::const_iterator it = this->operations.find(key);
-
- if (it != this->operations.end()) {
- return it->second;
+ OperationDepsNode *node = reinterpret_cast<OperationDepsNode *>(BLI_ghash_lookup(operations_map, &key));
+ if (node != NULL) {
+ return node;
}
else {
fprintf(stderr, "%s: find_operation(%s) failed\n",
@@ -129,11 +148,7 @@ OperationDepsNode *ComponentDepsNode::find_operation(eDepsOperation_Code opcode,
OperationDepsNode *ComponentDepsNode::has_operation(OperationIDKey key) const
{
- OperationMap::const_iterator it = this->operations.find(key);
- if (it != this->operations.end()) {
- return it->second;
- }
- return NULL;
+ return reinterpret_cast<OperationDepsNode *>(BLI_ghash_lookup(operations_map, &key));
}
OperationDepsNode *ComponentDepsNode::has_operation(eDepsOperation_Code opcode,
@@ -147,12 +162,12 @@ OperationDepsNode *ComponentDepsNode::add_operation(eDepsOperation_Type optype,
{
OperationDepsNode *op_node = has_operation(opcode, name);
if (!op_node) {
- DepsNodeFactory *factory = DEG_get_node_factory(DEPSNODE_TYPE_OPERATION);
+ DepsNodeFactory *factory = deg_get_node_factory(DEPSNODE_TYPE_OPERATION);
op_node = (OperationDepsNode *)factory->create_node(this->owner->id, "", name);
/* register opnode in this component's operation set */
- OperationIDKey key(opcode, name);
- this->operations[key] = op_node;
+ OperationIDKey *key = OBJECT_GUARDED_NEW(OperationIDKey, opcode, name);
+ BLI_ghash_insert(operations_map, key, op_node);
/* set as entry/exit node of component (if appropriate) */
if (optype == DEPSOP_TYPE_INIT) {
@@ -185,18 +200,22 @@ OperationDepsNode *ComponentDepsNode::add_operation(eDepsOperation_Type optype,
void ComponentDepsNode::remove_operation(eDepsOperation_Code opcode, const string &name)
{
- OperationDepsNode *op_node = find_operation(opcode, name);
- if (op_node) {
- /* unregister */
- this->operations.erase(OperationIDKey(opcode, name));
- OBJECT_GUARDED_DELETE(op_node, OperationDepsNode);
- }
+ /* unregister */
+ OperationIDKey key(opcode, name);
+ BLI_ghash_remove(operations_map,
+ &key,
+ comp_node_hash_key_free,
+ comp_node_hash_key_free);
}
void ComponentDepsNode::clear_operations()
{
- for (OperationMap::const_iterator it = operations.begin(); it != operations.end(); ++it) {
- OperationDepsNode *op_node = it->second;
+ if (operations_map != NULL) {
+ BLI_ghash_clear(operations_map,
+ comp_node_hash_key_free,
+ comp_node_hash_value_free);
+ }
+ foreach (OperationDepsNode *op_node, operations) {
OBJECT_GUARDED_DELETE(op_node, OperationDepsNode);
}
operations.clear();
@@ -208,30 +227,79 @@ void ComponentDepsNode::tag_update(Depsgraph *graph)
if (entry_op != NULL && entry_op->flag & DEPSOP_FLAG_NEEDS_UPDATE) {
return;
}
- for (OperationMap::const_iterator it = operations.begin(); it != operations.end(); ++it) {
- OperationDepsNode *op_node = it->second;
+ foreach (OperationDepsNode *op_node, operations) {
op_node->tag_update(graph);
}
+ // It is possible that tag happens before finalization.
+ if (operations_map != NULL) {
+ GHASH_FOREACH_BEGIN(OperationDepsNode *, op_node, operations_map)
+ {
+ op_node->tag_update(graph);
+ }
+ GHASH_FOREACH_END();
+ }
}
OperationDepsNode *ComponentDepsNode::get_entry_operation()
{
- if (entry_operation)
+ if (entry_operation) {
return entry_operation;
- else if (operations.size() == 1)
- return operations.begin()->second;
+ }
+ else if (operations_map != NULL && BLI_ghash_size(operations_map) == 1) {
+ OperationDepsNode *op_node = NULL;
+ /* TODO(sergey): This is somewhat slow. */
+ GHASH_FOREACH_BEGIN(OperationDepsNode *, tmp, operations_map)
+ {
+ op_node = tmp;
+ }
+ GHASH_FOREACH_END();
+ /* Cache for the subsequent usage. */
+ entry_operation = op_node;
+ return op_node;
+ }
+ else if(operations.size() == 1) {
+ return operations[0];
+ }
return NULL;
}
OperationDepsNode *ComponentDepsNode::get_exit_operation()
{
- if (exit_operation)
+ if (exit_operation) {
return exit_operation;
- else if (operations.size() == 1)
- return operations.begin()->second;
+ }
+ else if (operations_map != NULL && BLI_ghash_size(operations_map) == 1) {
+ OperationDepsNode *op_node = NULL;
+ /* TODO(sergey): This is somewhat slow. */
+ GHASH_FOREACH_BEGIN(OperationDepsNode *, tmp, operations_map)
+ {
+ op_node = tmp;
+ }
+ GHASH_FOREACH_END();
+ /* Cache for the subsequent usage. */
+ exit_operation = op_node;
+ return op_node;
+ }
+ else if(operations.size() == 1) {
+ return operations[0];
+ }
return NULL;
}
+void ComponentDepsNode::finalize_build()
+{
+ operations.reserve(BLI_ghash_size(operations_map));
+ GHASH_FOREACH_BEGIN(OperationDepsNode *, op_node, operations_map)
+ {
+ operations.push_back(op_node);
+ }
+ GHASH_FOREACH_END();
+ BLI_ghash_free(operations_map,
+ comp_node_hash_key_free,
+ NULL);
+ operations_map = NULL;
+}
+
/* Parameter Component Defines ============================ */
DEG_DEPSNODE_DEFINE(ParametersComponentDepsNode, DEPSNODE_TYPE_PARAMETERS, "Parameters Component");
@@ -302,18 +370,20 @@ static DepsNodeFactoryImpl<ShadingComponentDepsNode> DNTI_SHADING;
/* Node Types Register =================================== */
-void DEG_register_component_depsnodes()
+void deg_register_component_depsnodes()
{
- DEG_register_node_typeinfo(&DNTI_PARAMETERS);
- DEG_register_node_typeinfo(&DNTI_PROXY);
- DEG_register_node_typeinfo(&DNTI_ANIMATION);
- DEG_register_node_typeinfo(&DNTI_TRANSFORM);
- DEG_register_node_typeinfo(&DNTI_GEOMETRY);
- DEG_register_node_typeinfo(&DNTI_SEQUENCER);
-
- DEG_register_node_typeinfo(&DNTI_EVAL_POSE);
- DEG_register_node_typeinfo(&DNTI_BONE);
-
- DEG_register_node_typeinfo(&DNTI_EVAL_PARTICLES);
- DEG_register_node_typeinfo(&DNTI_SHADING);
+ deg_register_node_typeinfo(&DNTI_PARAMETERS);
+ deg_register_node_typeinfo(&DNTI_PROXY);
+ deg_register_node_typeinfo(&DNTI_ANIMATION);
+ deg_register_node_typeinfo(&DNTI_TRANSFORM);
+ deg_register_node_typeinfo(&DNTI_GEOMETRY);
+ deg_register_node_typeinfo(&DNTI_SEQUENCER);
+
+ deg_register_node_typeinfo(&DNTI_EVAL_POSE);
+ deg_register_node_typeinfo(&DNTI_BONE);
+
+ deg_register_node_typeinfo(&DNTI_EVAL_PARTICLES);
+ deg_register_node_typeinfo(&DNTI_SHADING);
}
+
+} // namespace DEG
diff --git a/source/blender/depsgraph/intern/depsnode_component.h b/source/blender/depsgraph/intern/nodes/deg_node_component.h
index 7f44c0ed03f..df321ea9299 100644
--- a/source/blender/depsgraph/intern/depsnode_component.h
+++ b/source/blender/depsgraph/intern/nodes/deg_node_component.h
@@ -28,21 +28,22 @@
* \ingroup depsgraph
*/
-#ifndef __DEPSNODE_COMPONENT_H__
-#define __DEPSNODE_COMPONENT_H__
+#pragma once
-#include "depsnode.h"
+#include "intern/nodes/deg_node.h"
-#include "depsgraph_util_hash.h"
-#include "depsgraph_util_map.h"
-#include "depsgraph_util_set.h"
+#include "BLI_utildefines.h"
+#include "BLI_string.h"
struct ID;
struct bPoseChannel;
+struct GHash;
-struct Depsgraph;
-struct DepsgraphCopyContext;
struct EvaluationContext;
+
+namespace DEG {
+
+struct Depsgraph;
struct OperationDepsNode;
struct BoneComponentDepsNode;
@@ -75,7 +76,7 @@ struct ComponentDepsNode : public DepsNode {
string identifier() const
{
char codebuf[5];
- sprintf(codebuf, "%d", opcode);
+ BLI_snprintf(codebuf, sizeof(codebuf), "%d", opcode);
return string("OperationIDKey(") + codebuf + ", " + name + ")";
}
@@ -86,47 +87,41 @@ struct ComponentDepsNode : public DepsNode {
}
};
- /* XXX can't specialize std::hash for this purpose, because ComponentKey is a nested type ...
- * http://stackoverflow.com/a/951245
- */
- struct operation_key_hash {
- bool operator() (const OperationIDKey &key) const
- {
- return hash_combine(hash<int>()(key.opcode), hash<string>()(key.name));
- }
- };
-
/* Typedef for container of operations */
- typedef unordered_map<OperationIDKey, OperationDepsNode *, operation_key_hash> OperationMap;
-
-
ComponentDepsNode();
~ComponentDepsNode();
void init(const ID *id, const string &subdata);
- void copy(DepsgraphCopyContext *dcc, const ComponentDepsNode *src);
string identifier() const;
/* Find an existing operation, will throw an assert() if it does not exist. */
OperationDepsNode *find_operation(OperationIDKey key) const;
- OperationDepsNode *find_operation(eDepsOperation_Code opcode, const string &name) const;
+ OperationDepsNode *find_operation(eDepsOperation_Code opcode,
+ const string &name) const;
/* Check operation exists and return it. */
OperationDepsNode *has_operation(OperationIDKey key) const;
- OperationDepsNode *has_operation(eDepsOperation_Code opcode, const string &name) const;
+ OperationDepsNode *has_operation(eDepsOperation_Code opcode,
+ const string &name) const;
/**
* Create a new node for representing an operation and add this to graph
- * \warning If an existing node is found, it will be modified. This helps when node may
- * have been partially created earlier (e.g. parent ref before parent item is added)
+ * \warning If an existing node is found, it will be modified. This helps
+ * when node may have been partially created earlier (e.g. parent ref before
+ * parent item is added)
*
- * \param type: Operation node type (corresponding to context/component that it operates in)
- * \param optype: Role that operation plays within component (i.e. where in eval process)
+ * \param type: Operation node type (corresponding to context/component that
+ * it operates in)
+ * \param optype: Role that operation plays within component
+ * (i.e. where in eval process)
* \param op: The operation to perform
* \param name: Identifier for operation - used to find/locate it again
*/
- OperationDepsNode *add_operation(eDepsOperation_Type optype, DepsEvalOperationCb op, eDepsOperation_Code opcode, const string &name);
+ OperationDepsNode *add_operation(eDepsOperation_Type optype,
+ DepsEvalOperationCb op,
+ eDepsOperation_Code opcode,
+ const string &name);
void remove_operation(eDepsOperation_Code opcode, const string &name);
void clear_operations();
@@ -135,9 +130,13 @@ struct ComponentDepsNode : public DepsNode {
/* Evaluation Context Management .................. */
- /* Initialize component's evaluation context used for the specified purpose */
+ /* Initialize component's evaluation context used for the specified
+ * purpose.
+ */
virtual bool eval_context_init(EvaluationContext * /*eval_ctx*/) { return false; }
- /* Free data in component's evaluation context which is used for the specified purpose
+ /* Free data in component's evaluation context which is used for
+ * the specified purpose
+ *
* NOTE: this does not free the actual context in question
*/
virtual void eval_context_free(EvaluationContext * /*eval_ctx*/) {}
@@ -145,15 +144,31 @@ struct ComponentDepsNode : public DepsNode {
OperationDepsNode *get_entry_operation();
OperationDepsNode *get_exit_operation();
+ void finalize_build();
+
IDDepsNode *owner;
- OperationMap operations; /* inner nodes for this component */
+ /* ** Inner nodes for this component ** */
+
+ /* Operations stored as a hash map, for faster build.
+ * This hash map will be freed when graph is fully built.
+ */
+ GHash *operations_map;
+
+ /* This is a "normal" list of operations, used by evaluation
+ * and other routines after construction.
+ */
+ vector<OperationDepsNode *> operations;
+
OperationDepsNode *entry_operation;
OperationDepsNode *exit_operation;
// XXX: a poll() callback to check if component's first node can be started?
int flags;
+
+ /* Temporary bitmask, used during graph construction. */
+ int layers;
};
/* ---------------------------------------- */
@@ -204,6 +219,6 @@ struct ShadingComponentDepsNode : public ComponentDepsNode {
};
-void DEG_register_component_depsnodes();
+void deg_register_component_depsnodes();
-#endif /* __DEPSNODE_COMPONENT_H__ */
+} // namespace DEG
diff --git a/source/blender/depsgraph/intern/depsnode_operation.cc b/source/blender/depsgraph/intern/nodes/deg_node_operation.cc
index 6aeb163356b..a9f9703bb3b 100644
--- a/source/blender/depsgraph/intern/depsnode_operation.cc
+++ b/source/blender/depsgraph/intern/nodes/deg_node_operation.cc
@@ -28,35 +28,27 @@
* \ingroup depsgraph
*/
+#include "intern/nodes/deg_node_operation.h"
+
#include "MEM_guardedalloc.h"
extern "C" {
#include "BLI_utildefines.h"
} /* extern "C" */
-#include "depsnode_operation.h" /* own include */
-#include "depsnode_component.h"
-#include "depsgraph.h"
-#include "depsgraph_intern.h"
-
-/* ******************************************************************* */
-/* OpNode Identifiers Array - Exported to other depsgraph files too... */
+#include "intern/depsgraph.h"
+#include "intern/depsgraph_intern.h"
+#include "util/deg_util_hash.h"
-/* identifiers for operations */
-const char *DEG_OPNAMES[] = {
-#define DEF_DEG_OPCODE(label) #label,
-#include "depsnode_opcodes.h"
-#undef DEF_DEG_OPCODE
-
- "<Invalid>"
-};
+namespace DEG {
/* *********** */
/* Inner Nodes */
OperationDepsNode::OperationDepsNode() :
eval_priority(0.0f),
- flag(0)
+ flag(0),
+ customdata_mask(0)
{
}
@@ -66,7 +58,6 @@ OperationDepsNode::~OperationDepsNode()
string OperationDepsNode::identifier() const
{
- BLI_assert((opcode > 0) && (opcode < ARRAY_SIZE(DEG_OPNAMES)));
return string(DEG_OPNAMES[opcode]) + "(" + name + ")";
}
@@ -98,7 +89,9 @@ void OperationDepsNode::tag_update(Depsgraph *graph)
DEG_DEPSNODE_DEFINE(OperationDepsNode, DEPSNODE_TYPE_OPERATION, "Operation");
static DepsNodeFactoryImpl<OperationDepsNode> DNTI_OPERATION;
-void DEG_register_operation_depsnodes()
+void deg_register_operation_depsnodes()
{
- DEG_register_node_typeinfo(&DNTI_OPERATION);
+ deg_register_node_typeinfo(&DNTI_OPERATION);
}
+
+} // namespace DEG
diff --git a/source/blender/depsgraph/intern/depsnode_operation.h b/source/blender/depsgraph/intern/nodes/deg_node_operation.h
index 1119e10805d..f03078fc3db 100644
--- a/source/blender/depsgraph/intern/depsnode_operation.h
+++ b/source/blender/depsgraph/intern/nodes/deg_node_operation.h
@@ -28,15 +28,15 @@
* \ingroup depsgraph
*/
-#ifndef __DEPSNODE_OPERATION_H__
-#define __DEPSNODE_OPERATION_H__
+#pragma once
-#include "depsnode.h"
+#include "intern/nodes/deg_node.h"
struct ID;
struct Depsgraph;
-struct DepsgraphCopyContext;
+
+namespace DEG {
/* Flags for Depsgraph Nodes */
typedef enum eDepsOperation_Flag {
@@ -44,10 +44,14 @@ typedef enum eDepsOperation_Flag {
DEPSOP_FLAG_NEEDS_UPDATE = (1 << 0),
/* node was directly modified, causing need for update */
- /* XXX: intention is to make it easier to tell when we just need to take subgraphs */
+ /* XXX: intention is to make it easier to tell when we just need to
+ * take subgraphs.
+ */
DEPSOP_FLAG_DIRECTLY_MODIFIED = (1 << 1),
- /* Operation is evaluated using CPython; has GIL and security implications... */
+ /* Operation is evaluated using CPython; has GIL and security
+ * implications...
+ */
DEPSOP_FLAG_USES_PYTHON = (1 << 2),
} eDepsOperation_Flag;
@@ -68,23 +72,33 @@ struct OperationDepsNode : public DepsNode {
OperationDepsNode *get_entry_operation() { return this; }
OperationDepsNode *get_exit_operation() { return this; }
- ComponentDepsNode *owner; /* component that contains the operation */
+ /* Component that contains the operation. */
+ ComponentDepsNode *owner;
- DepsEvalOperationCb evaluate; /* callback for operation */
+ /* Callback for operation. */
+ DepsEvalOperationCb evaluate;
- uint32_t num_links_pending; /* how many inlinks are we still waiting on before we can be evaluated... */
+ /* How many inlinks are we still waiting on before we can be evaluated. */
+ uint32_t num_links_pending;
float eval_priority;
bool scheduled;
- short optype; /* (eDepsOperation_Type) stage of evaluation */
- int opcode; /* (eDepsOperation_Code) identifier for the operation being performed */
+ /* Stage of evaluation */
+ eDepsOperation_Type optype;
+
+ /* Identifier for the operation being performed. */
+ eDepsOperation_Code opcode;
+
+ /* (eDepsOperation_Flag) extra settings affecting evaluation. */
+ int flag;
- int flag; /* (eDepsOperation_Flag) extra settings affecting evaluation */
+ /* Extra customdata mask which needs to be evaluated for the object. */
+ uint64_t customdata_mask;
DEG_DEPSNODE_DECLARE;
};
-void DEG_register_operation_depsnodes();
+void deg_register_operation_depsnodes();
-#endif /* __DEPSNODE_OPERATION_H__ */
+} // namespace DEG
diff --git a/source/blender/depsgraph/util/deg_util_foreach.h b/source/blender/depsgraph/util/deg_util_foreach.h
new file mode 100644
index 00000000000..14cf4fc11ed
--- /dev/null
+++ b/source/blender/depsgraph/util/deg_util_foreach.h
@@ -0,0 +1,68 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2016 Blender Foundation.
+ * All rights reserved.
+ *
+ * Original Author: Sergey Sharybin
+ * Contributor(s):
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/depsgraph/util/deg_util_foreach.h
+ * \ingroup depsgraph
+ */
+
+#pragma once
+
+#if (__cplusplus > 199711L) || (defined(_MSC_VER) && _MSC_VER >= 1800)
+# define foreach(x, y) for(x : y)
+#elif defined(HAVE_BOOST_FUNCTION_BINDINGS)
+# include <boost/foreach.hpp>
+# define foreach BOOST_FOREACH
+#else
+#pragma message("No available foreach() implementation. Using stub instead, disabling new depsgraph")
+
+#ifndef WITH_LEGACY_DEPSGRAPH
+# error "Unable to build new depsgraph and legacy one is disabled."
+#endif
+
+#define DISABLE_NEW_DEPSGRAPH
+
+# define foreach(x, y) for (x; false; (void)y)
+#endif
+
+#define GHASH_FOREACH_BEGIN(type, var, what) \
+ do { \
+ GHashIterator gh_iter##var; \
+ GHASH_ITER(gh_iter##var, what) { \
+ type var = reinterpret_cast<type>(BLI_ghashIterator_getValue(&gh_iter##var)); \
+
+#define GHASH_FOREACH_END() \
+ } \
+ } while(0)
+
+#define GSET_FOREACH_BEGIN(type, var, what) \
+ do { \
+ GSetIterator gh_iter##var; \
+ GSET_ITER(gh_iter##var, what) { \
+ type var = reinterpret_cast<type>(BLI_gsetIterator_getKey(&gh_iter##var)); \
+
+#define GSET_FOREACH_END() \
+ } \
+ } while(0)
diff --git a/source/blender/depsgraph/util/depsgraph_util_function.h b/source/blender/depsgraph/util/deg_util_function.h
index a4301833408..1e34ae04d9a 100644
--- a/source/blender/depsgraph/util/depsgraph_util_function.h
+++ b/source/blender/depsgraph/util/deg_util_function.h
@@ -24,12 +24,11 @@
* ***** END GPL LICENSE BLOCK *****
*/
-/** \file blender/depsgraph/util/depsgraph_util_function.h
+/** \file blender/depsgraph/util/deg_util_function.h
* \ingroup depsgraph
*/
-#ifndef __DEPSGRAPH_UTIL_FUNCTION_H__
-#define __DEPSGRAPH_UTIL_FUNCTION_H__
+#pragma once
#if (__cplusplus > 199711L)
@@ -57,6 +56,7 @@ using boost::function;
#define DISABLE_NEW_DEPSGRAPH
+#include "BLI_utildefines.h"
#include <cstdlib>
template<typename T>
@@ -108,5 +108,3 @@ void *function_bind(T func,
#define _4 Wrap()
#endif
-
-#endif /* __DEPSGRAPH_UTIL_FUNCTION_H__ */
diff --git a/source/blender/depsgraph/util/depsgraph_util_set.h b/source/blender/depsgraph/util/deg_util_hash.h
index 008ec6b74ca..e490be1a7a1 100644
--- a/source/blender/depsgraph/util/depsgraph_util_set.h
+++ b/source/blender/depsgraph/util/deg_util_hash.h
@@ -24,43 +24,18 @@
* ***** END GPL LICENSE BLOCK *****
*/
-/** \file blender/depsgraph/util/depsgraph_util_set.h
+/** \file blender/depsgraph/util/deg_util_hash.h
* \ingroup depsgraph
*/
-#ifndef __DEPSGRAPH_UTIL_SET_H__
-#define __DEPSGRAPH_UTIL_SET_H__
+#pragma once
-#include <set>
+#include "BLI_utildefines.h"
-#include "depsgraph_util_hash.h"
+#include "BLI_ghash.h"
-using std::set;
-
-#if defined(DEG_NO_UNORDERED_MAP)
-# include <set>
-typedef std::set unordered_set;
-#endif
-
-#if defined(DEG_TR1_UNORDERED_MAP)
-# include <tr1/unordered_set>
-using std::tr1::unordered_set;
-#endif
-
-#if defined(DEG_STD_UNORDERED_MAP)
-# include <unordered_set>
-using std::unordered_set;
-#endif
-
-#if defined(DEG_STD_UNORDERED_MAP_IN_TR1_NAMESPACE)
-# include <unordered_set>
-using std::tr1::unordered_set;
-#endif
-
-#if !defined(DEG_NO_UNORDERED_MAP) && !defined(DEG_TR1_UNORDERED_MAP) && \
- !defined(DEG_STD_UNORDERED_MAP) && !defined(DEG_STD_UNORDERED_MAP_IN_TR1_NAMESPACE) // NOLINT
-# error One of: DEG_NO_UNORDERED_MAP, DEG_TR1_UNORDERED_MAP,\
- DEG_STD_UNORDERED_MAP, DEG_STD_UNORDERED_MAP_IN_TR1_NAMESPACE must be defined! // NOLINT
-#endif
-
-#endif /* __DEPSGRAPH_UTIL_SET_H__ */
+/* XXX this might require 2 different variants for sizeof(size_t) (32 vs 64 bit) */
+BLI_INLINE size_t hash_combine(size_t hash_a, size_t hash_b)
+{
+ return hash_a ^ (hash_b + 0x9e3779b9 + (hash_a << 6) + (hash_a >> 2));
+}
diff --git a/source/blender/depsgraph/util/depsgraph_util_hash.h b/source/blender/depsgraph/util/depsgraph_util_hash.h
deleted file mode 100644
index bc75627a026..00000000000
--- a/source/blender/depsgraph/util/depsgraph_util_hash.h
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * ***** BEGIN GPL LICENSE BLOCK *****
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * The Original Code is Copyright (C) 2014 Blender Foundation.
- * All rights reserved.
- *
- * Original Author: Brecht van Lommel
- * Contributor(s): Lukas Toenne
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-/** \file blender/depsgraph/util/depsgraph_util_hash.h
- * \ingroup depsgraph
- */
-
-#ifndef __DEPSGRAPH_UTIL_HASH_H__
-#define __DEPSGRAPH_UTIL_HASH_H__
-
-#if defined(DEG_NO_UNORDERED_MAP)
-# define DEG_HASH_NAMESPACE_BEGIN
-# define DEG_HASH_NAMESPACE_END
-#endif
-
-#if defined(DEG_TR1_UNORDERED_MAP)
-# include <tr1/unordered_map>
-# define DEG_HASH_NAMESPACE_BEGIN namespace std { namespace tr1 {
-# define DEG_HASH_NAMESPACE_END } }
-using std::tr1::hash;
-#endif
-
-#if defined(DEG_STD_UNORDERED_MAP)
-# include <unordered_map>
-# define DEG_HASH_NAMESPACE_BEGIN namespace std {
-# define DEG_HASH_NAMESPACE_END }
-using std::hash;
-#endif
-
-#if defined(DEG_STD_UNORDERED_MAP_IN_TR1_NAMESPACE)
-# include <unordered_map>
-# define DEG_HASH_NAMESPACE_BEGIN namespace std { namespace tr1 {
-# define DEG_HASH_NAMESPACE_END } }
-using std::tr1::hash;
-#endif
-
-#if !defined(DEG_NO_UNORDERED_MAP) && !defined(DEG_TR1_UNORDERED_MAP) && \
- !defined(DEG_STD_UNORDERED_MAP) && !defined(DEG_STD_UNORDERED_MAP_IN_TR1_NAMESPACE) // NOLINT
-# error One of: DEG_NO_UNORDERED_MAP, DEG_TR1_UNORDERED_MAP,\
- DEG_STD_UNORDERED_MAP, DEG_STD_UNORDERED_MAP_IN_TR1_NAMESPACE must be defined! // NOLINT
-#endif
-
-/* XXX this might require 2 different variants for sizeof(size_t) (32 vs 64 bit) */
-inline size_t hash_combine(size_t hash_a, size_t hash_b)
-{
- return hash_a ^ (hash_b + 0x9e3779b9 + (hash_a << 6) + (hash_a >> 2));
-}
-
-#endif /* __DEPSGRAPH_UTIL_HASH_H__ */
diff --git a/source/blender/depsgraph/util/depsgraph_util_map.h b/source/blender/depsgraph/util/depsgraph_util_map.h
deleted file mode 100644
index 0eae1d79e34..00000000000
--- a/source/blender/depsgraph/util/depsgraph_util_map.h
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * ***** BEGIN GPL LICENSE BLOCK *****
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * The Original Code is Copyright (C) 2014 Blender Foundation.
- * All rights reserved.
- *
- * Original Author: Brecht van Lommel
- * Contributor(s): Lukas Toenne
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-/** \file blender/depsgraph/util/depsgraph_util_map.h
- * \ingroup depsgraph
- */
-
-#ifndef __DEPSGRAPH_UTIL_MAP_H__
-#define __DEPSGRAPH_UTIL_MAP_H__
-
-#include <map>
-
-#include "depsgraph_util_hash.h"
-
-using std::map;
-using std::pair;
-
-#if defined(DEG_NO_UNORDERED_MAP)
-# include <map>
-typedef std::map unordered_map;
-#endif
-
-#if defined(DEG_TR1_UNORDERED_MAP)
-# include <tr1/unordered_map>
-using std::tr1::unordered_map;
-#endif
-
-#if defined(DEG_STD_UNORDERED_MAP)
-# include <unordered_map>
-using std::unordered_map;
-#endif
-
-#if defined(DEG_STD_UNORDERED_MAP_IN_TR1_NAMESPACE)
-# include <unordered_map>
-using std::tr1::unordered_map;
-#endif
-
-#if !defined(DEG_NO_UNORDERED_MAP) && !defined(DEG_TR1_UNORDERED_MAP) && \
- !defined(DEG_STD_UNORDERED_MAP) && !defined(DEG_STD_UNORDERED_MAP_IN_TR1_NAMESPACE) // NOLINT
-# error One of: DEG_NO_UNORDERED_MAP, DEG_TR1_UNORDERED_MAP,\
- DEG_STD_UNORDERED_MAP, DEG_STD_UNORDERED_MAP_IN_TR1_NAMESPACE must be defined! // NOLINT
-#endif
-
-#endif /* __DEPSGRAPH_UTIL_MAP_H__ */
diff --git a/source/blender/editors/animation/anim_deps.c b/source/blender/editors/animation/anim_deps.c
index 5665ce59783..437dd2b2de2 100644
--- a/source/blender/editors/animation/anim_deps.c
+++ b/source/blender/editors/animation/anim_deps.c
@@ -399,7 +399,13 @@ void ANIM_animdata_update(bAnimContext *ac, ListBase *anim_data)
ANIM_list_elem_update(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);
+ }
+ }
+
BLI_assert(ale->update == 0);
}
}
diff --git a/source/blender/editors/animation/drivers.c b/source/blender/editors/animation/drivers.c
index afc4e5c9e61..a82cca9e52a 100644
--- a/source/blender/editors/animation/drivers.c
+++ b/source/blender/editors/animation/drivers.c
@@ -753,7 +753,7 @@ EnumPropertyItem prop_driver_create_mapping_types[] = {
"Create drivers for each pair of corresponding elements"},
{CREATEDRIVER_MAPPING_NONE_ALL, "NONE_ALL", ICON_HAND, "Manually Create Later",
- "Create drivers for all properites without assigning any targets yet"},
+ "Create drivers for all properties without assigning any targets yet"},
{CREATEDRIVER_MAPPING_NONE, "NONE_SINGLE", 0, "Manually Create Later (Single)",
"Create driver for this property only and without assigning any targets yet"},
{0, NULL, 0, NULL, NULL}
@@ -866,7 +866,7 @@ static int add_driver_button_exec(bContext *C, wmOperator *op)
}
/* Show menu or create drivers */
-static int add_driver_button_invoke(bContext *C, wmOperator *op, const wmEvent *event)
+static int add_driver_button_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
{
PropertyRNA *prop;
@@ -877,7 +877,8 @@ static int add_driver_button_invoke(bContext *C, wmOperator *op, const wmEvent *
else {
/* Show menu */
// TODO: This should get filtered by the enum filter
- return WM_menu_invoke(C, op, event);
+ /* important to execute in the region we're currently in */
+ return WM_menu_invoke_ex(C, op, WM_OP_INVOKE_DEFAULT);
}
}
diff --git a/source/blender/editors/animation/keyframing.c b/source/blender/editors/animation/keyframing.c
index 6a19cf679be..172f2b9069e 100644
--- a/source/blender/editors/animation/keyframing.c
+++ b/source/blender/editors/animation/keyframing.c
@@ -2024,17 +2024,25 @@ bool autokeyframe_cfra_can_key(Scene *scene, ID *id)
/* only filter if auto-key mode requires this */
if (IS_AUTOKEY_ON(scene) == 0)
return false;
-
- if (IS_AUTOKEY_MODE(scene, NORMAL)) {
- /* can insert anytime we like... */
- return true;
- }
- else { /* REPLACE */
- /* for whole block - only key if there's a keyframe on that frame already
- * this is a valid assumption when we're blocking + tweaking
+
+ if (IS_AUTOKEY_MODE(scene, EDITKEYS)) {
+ /* Replace Mode:
+ * For whole block, only key if there's a keyframe on that frame already
+ * This is a valid assumption when we're blocking + tweaking
*/
return id_frame_has_keyframe(id, cfra, ANIMFILTER_KEYS_LOCAL);
}
+ else {
+ /* Normal Mode (or treat as being normal mode):
+ *
+ * Just in case the flags are't set properly (i.e. only on/off is set, without a mode)
+ * let's set the "normal" flag too, so that it will all be sane everywhere...
+ */
+ scene->toolsettings->autokey_mode = AUTOKEY_MODE_NORMAL;
+
+ /* Can insert anytime we like... */
+ return true;
+ }
}
/* ******************************************* */
diff --git a/source/blender/editors/armature/armature_utils.c b/source/blender/editors/armature/armature_utils.c
index d73536e5ba7..6306926e0b2 100644
--- a/source/blender/editors/armature/armature_utils.c
+++ b/source/blender/editors/armature/armature_utils.c
@@ -367,6 +367,8 @@ void transform_armature_mirror_update(Object *obedit)
eboflip->tail[2] = ebo->tail[2];
eboflip->rad_tail = ebo->rad_tail;
eboflip->roll = -ebo->roll;
+ eboflip->curveOutX = -ebo->curveOutX;
+ eboflip->roll2 = -ebo->roll2;
/* Also move connected children, in case children's name aren't mirrored properly */
for (children = arm->edbo->first; children; children = children->next) {
@@ -382,6 +384,8 @@ void transform_armature_mirror_update(Object *obedit)
eboflip->head[2] = ebo->head[2];
eboflip->rad_head = ebo->rad_head;
eboflip->roll = -ebo->roll;
+ eboflip->curveInX = -ebo->curveInX;
+ eboflip->roll1 = -ebo->roll1;
/* Also move connected parent, in case parent's name isn't mirrored properly */
if (eboflip->parent && eboflip->flag & BONE_CONNECTED) {
@@ -395,6 +399,11 @@ void transform_armature_mirror_update(Object *obedit)
eboflip->roll = -ebo->roll;
eboflip->xwidth = ebo->xwidth;
eboflip->zwidth = ebo->zwidth;
+
+ eboflip->curveInX = -ebo->curveInX;
+ eboflip->curveOutX = -ebo->curveOutX;
+ eboflip->roll1 = -ebo->roll1;
+ eboflip->roll2 = -ebo->roll2;
}
}
}
diff --git a/source/blender/editors/armature/editarmature_sketch.c b/source/blender/editors/armature/editarmature_sketch.c
index 5530e293edd..cc4c1809fbc 100644
--- a/source/blender/editors/armature/editarmature_sketch.c
+++ b/source/blender/editors/armature/editarmature_sketch.c
@@ -980,7 +980,11 @@ static int sk_getStrokeSnapPoint(bContext *C, SK_Point *pt, SK_Sketch *sketch, S
if (ts->snap_mode == SCE_SNAP_MODE_VOLUME) {
float size;
if (peelObjectsSnapContext(
- snap_context, mvalf, SNAP_ALL,
+ snap_context, mvalf,
+ &(const struct SnapObjectParams){
+ .snap_select = SNAP_NOT_SELECTED,
+ .use_object_edit_cage = false,
+ },
(ts->snap_flag & SCE_SNAP_PEEL_OBJECT) != 0,
loc, dummy_no, &size))
{
@@ -1017,9 +1021,10 @@ static int sk_getStrokeSnapPoint(bContext *C, SK_Point *pt, SK_Sketch *sketch, S
{
if (ED_transform_snap_object_project_view3d(
snap_context,
+ ts->snap_mode,
&(const struct SnapObjectParams){
.snap_select = SNAP_NOT_SELECTED,
- .snap_to = ts->snap_mode,
+ .use_object_edit_cage = false,
},
mvalf, &dist_px, NULL,
loc, dummy_no))
diff --git a/source/blender/editors/curve/editcurve.c b/source/blender/editors/curve/editcurve.c
index 18fdcb546b0..420f72fedb3 100644
--- a/source/blender/editors/curve/editcurve.c
+++ b/source/blender/editors/curve/editcurve.c
@@ -5004,9 +5004,10 @@ static int add_vertex_invoke(bContext *C, wmOperator *op, const wmEvent *event)
ED_transform_snap_object_project_view3d_mixed(
snap_context,
+ SCE_SELECT_FACE,
&(const struct SnapObjectParams){
- .snap_select = SNAP_NOT_OBEDIT,
- .snap_to_flag = SCE_SELECT_FACE,
+ .snap_select = (vc.scene->obedit != NULL) ? SNAP_NOT_ACTIVE : SNAP_ALL,
+ .use_object_edit_cage = false,
},
mval, NULL, true,
location, NULL);
diff --git a/source/blender/editors/include/ED_physics.h b/source/blender/editors/include/ED_physics.h
index 584e9a92bb6..fed842c969e 100644
--- a/source/blender/editors/include/ED_physics.h
+++ b/source/blender/editors/include/ED_physics.h
@@ -45,12 +45,12 @@ int PE_hair_poll(struct bContext *C);
int PE_poll_view3d(struct bContext *C);
/* rigidbody_object.c */
-bool ED_rigidbody_object_add(struct Scene *scene, struct Object *ob, int type, struct ReportList *reports);
-void ED_rigidbody_object_remove(struct Scene *scene, struct Object *ob);
+bool ED_rigidbody_object_add(struct Main *bmain, struct Scene *scene, struct Object *ob, int type, struct ReportList *reports);
+void ED_rigidbody_object_remove(struct Main *bmain, struct Scene *scene, struct Object *ob);
/* rigidbody_constraint.c */
-bool ED_rigidbody_constraint_add(struct Scene *scene, struct Object *ob, int type, struct ReportList *reports);
-void ED_rigidbody_constraint_remove(struct Scene *scene, struct Object *ob);
+bool ED_rigidbody_constraint_add(struct Main *bmain, struct Scene *scene, struct Object *ob, int type, struct ReportList *reports);
+void ED_rigidbody_constraint_remove(struct Main *bmain, struct Scene *scene, struct Object *ob);
/* operators */
void ED_operatortypes_physics(void);
diff --git a/source/blender/editors/include/ED_screen_types.h b/source/blender/editors/include/ED_screen_types.h
index effecf43839..1c41b14a874 100644
--- a/source/blender/editors/include/ED_screen_types.h
+++ b/source/blender/editors/include/ED_screen_types.h
@@ -42,6 +42,7 @@ typedef struct ScreenAnimData {
int sfra; /* frame that playback was started from */
int nextfra; /* next frame to go to (when ANIMPLAY_FLAG_USE_NEXT_FRAME is set) */
double last_duration; /* used for frame dropping */
+ bool from_anim_edit; /* playback was invoked from animation editor */
} ScreenAnimData;
/* for animplayer */
diff --git a/source/blender/editors/include/ED_transform.h b/source/blender/editors/include/ED_transform.h
index 933f480a554..ebd2a3dcb7a 100644
--- a/source/blender/editors/include/ED_transform.h
+++ b/source/blender/editors/include/ED_transform.h
@@ -45,6 +45,7 @@ struct wmKeyMap;
struct wmOperatorType;
struct Main;
struct SnapObjectContext;
+struct SnapObjectParams;
void transform_keymap_for_space(struct wmKeyConfig *keyconf, struct wmKeyMap *keymap, int spaceid);
void transform_operatortypes(void);
@@ -161,25 +162,27 @@ void BIF_draw_manipulator(const struct bContext *C);
typedef enum SnapSelect {
SNAP_ALL = 0,
SNAP_NOT_SELECTED = 1,
- SNAP_NOT_OBEDIT = 2
+ SNAP_NOT_ACTIVE = 2,
} SnapSelect;
#define SNAP_MIN_DISTANCE 30
bool peelObjectsTransform(
- struct TransInfo *t, const float mval[2],
- SnapSelect snap_select, bool use_peel_object,
+ struct TransInfo *t,
+ const float mval[2],
+ const bool use_peel_object,
/* return args */
float r_loc[3], float r_no[3], float *r_thickness);
bool peelObjectsSnapContext(
struct SnapObjectContext *sctx,
const float mval[2],
- SnapSelect snap_select, bool use_peel_object,
+ const struct SnapObjectParams *params,
+ const bool use_peel_object,
/* return args */
float r_loc[3], float r_no[3], float *r_thickness);
bool snapObjectsTransform(
- struct TransInfo *t, const float mval[2], SnapSelect snap_select,
+ struct TransInfo *t, const float mval[2],
float *dist_px,
/* return args */
float r_loc[3], float r_no[3]);
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 900b7593f2e..baf4ed574cf 100644
--- a/source/blender/editors/include/ED_transform_snap_object_context.h
+++ b/source/blender/editors/include/ED_transform_snap_object_context.h
@@ -57,17 +57,12 @@ struct SnapObjectHitDepth {
unsigned int ob_uuid;
};
+/** parameters that define which objects will be used to snap. */
struct SnapObjectParams {
- int snap_select; /* SnapSelect */
- union {
- unsigned int snap_to : 4;
- /* snap_target_flag: Snap to vert/edge/face. */
- unsigned int snap_to_flag : 4;
- };
+ /* special context sensitive handling for the active or selected object */
+ char snap_select;
/* use editmode cage */
- unsigned int use_object_edit : 1;
- /* special context sensitive handling for the active object */
- unsigned int use_object_active : 1;
+ unsigned int use_object_edit_cage : 1;
};
enum {
@@ -93,6 +88,7 @@ void ED_transform_snap_object_context_set_editmesh_callbacks(
bool ED_transform_snap_object_project_ray_ex(
struct SnapObjectContext *sctx,
+ const unsigned short snap_to,
const struct SnapObjectParams *params,
const float ray_start[3], const float ray_normal[3], float *ray_depth,
/* return args */
@@ -100,11 +96,13 @@ bool ED_transform_snap_object_project_ray_ex(
struct Object **r_ob, float r_obmat[4][4]);
bool ED_transform_snap_object_project_ray(
SnapObjectContext *sctx,
+ const struct SnapObjectParams *params,
const float ray_origin[3], const float ray_direction[3], float *ray_depth,
float r_co[3], float r_no[3]);
bool ED_transform_snap_object_project_ray_all(
SnapObjectContext *sctx,
+ const unsigned short snap_to,
const struct SnapObjectParams *params,
const float ray_start[3], const float ray_normal[3],
float ray_depth, bool sort,
@@ -112,12 +110,14 @@ bool ED_transform_snap_object_project_ray_all(
bool ED_transform_snap_object_project_view3d_ex(
struct SnapObjectContext *sctx,
+ const unsigned short snap_to,
const struct SnapObjectParams *params,
const float mval[2], float *dist_px,
float *ray_depth,
float r_loc[3], float r_no[3], int *r_index);
bool ED_transform_snap_object_project_view3d(
struct SnapObjectContext *sctx,
+ const unsigned short snap_to,
const struct SnapObjectParams *params,
const float mval[2], float *dist_px,
float *ray_depth,
@@ -125,6 +125,7 @@ bool ED_transform_snap_object_project_view3d(
float r_loc[3], float r_no[3]);
bool ED_transform_snap_object_project_view3d_mixed(
SnapObjectContext *sctx,
+ const unsigned short snap_to_flag,
const struct SnapObjectParams *params,
const float mval_fl[2], float *dist_px,
bool use_depth,
diff --git a/source/blender/editors/interface/interface_handlers.c b/source/blender/editors/interface/interface_handlers.c
index 10ab85a6142..5b8b8ae5bdb 100644
--- a/source/blender/editors/interface/interface_handlers.c
+++ b/source/blender/editors/interface/interface_handlers.c
@@ -634,6 +634,15 @@ PointerRNA *ui_handle_afterfunc_add_operator(wmOperatorType *ot, int opcontext,
return ptr;
}
+/**
+ * Check if a #uiAfterFunc is needed for this button.
+ */
+static bool ui_afterfunc_check(const uiBlock *block, const uiBut *but)
+{
+ return (but->func || but->funcN || but->rename_func || but->optype || but->rnaprop || block->handle_func ||
+ (but->type == UI_BTYPE_BUT_MENU && block->butm_func));
+}
+
static void ui_apply_but_func(bContext *C, uiBut *but)
{
uiAfterFunc *after;
@@ -643,9 +652,7 @@ static void ui_apply_but_func(bContext *C, uiBut *but)
* handling is done, i.e. menus are closed, in order to avoid conflicts
* with these functions removing the buttons we are working with */
- if (but->func || but->funcN || block->handle_func || but->rename_func ||
- (but->type == UI_BTYPE_BUT_MENU && block->butm_func) || but->optype || but->rnaprop)
- {
+ if (ui_afterfunc_check(block, but)) {
after = ui_afterfunc_new();
if (but->func && ELEM(but, but->func_arg1, but->func_arg2)) {
@@ -899,7 +906,8 @@ static void ui_apply_but_TEX(bContext *C, uiBut *but, uiHandleButtonData *data)
* having typed something already. */
but->rename_orig = BLI_strdup(data->origstr);
}
- else {
+ /* only if there are afterfuncs, otherwise 'renam_orig' isn't freed */
+ else if (ui_afterfunc_check(but->block, but)) {
but->rename_orig = data->origstr;
data->origstr = NULL;
}
diff --git a/source/blender/editors/interface/interface_icons.c b/source/blender/editors/interface/interface_icons.c
index 0a25a8fb3c6..222b0366791 100644
--- a/source/blender/editors/interface/interface_icons.c
+++ b/source/blender/editors/interface/interface_icons.c
@@ -1220,8 +1220,13 @@ static void icon_draw_rect(float x, float y, int w, int h, float UNUSED(aspect),
glaDrawPixelsSafe(draw_x, draw_y, draw_w, draw_h, draw_w, GL_RGBA, GL_UNSIGNED_BYTE, rect);
}
else {
+ int bound_options;
+ GPU_BASIC_SHADER_DISABLE_AND_STORE(bound_options);
+
glRasterPos2f(draw_x, draw_y);
glDrawPixels(draw_w, draw_h, GL_RGBA, GL_UNSIGNED_BYTE, rect);
+
+ GPU_BASIC_SHADER_ENABLE_AND_RESTORE(bound_options);
}
if (ima)
diff --git a/source/blender/editors/interface/interface_ops.c b/source/blender/editors/interface/interface_ops.c
index 7a9c3e827cf..ff29a6f8e33 100644
--- a/source/blender/editors/interface/interface_ops.c
+++ b/source/blender/editors/interface/interface_ops.c
@@ -897,7 +897,7 @@ static int edittranslation_exec(bContext *C, wmOperator *op)
}
ot = WM_operatortype_find(EDTSRC_I18N_OP_NAME, 0);
if (ot == NULL) {
- BKE_reportf(op->reports, RPT_ERROR, "Could not find operator '%s'! Please enable ui_translate addon "
+ BKE_reportf(op->reports, RPT_ERROR, "Could not find operator '%s'! Please enable ui_translate add-on "
"in the User Preferences", EDTSRC_I18N_OP_NAME);
return OPERATOR_CANCELLED;
}
diff --git a/source/blender/editors/interface/interface_regions.c b/source/blender/editors/interface/interface_regions.c
index 9e49d7e7e90..d4d3e1af1fd 100644
--- a/source/blender/editors/interface/interface_regions.c
+++ b/source/blender/editors/interface/interface_regions.c
@@ -2327,6 +2327,12 @@ static void ui_block_colorpicker(uiBlock *block, float rgba[4], PointerRNA *ptr,
RNA_property_float_range(ptr, prop, &hardmin, &hardmax);
RNA_property_float_get_array(ptr, prop, rgba);
+ /* when the softmax isn't defined in the RNA,
+ * using very large numbers causes sRGB/linear round trip to fail. */
+ if (softmax == FLT_MAX) {
+ softmax = 1.0f;
+ }
+
switch (U.color_picker_type) {
case USER_CP_SQUARE_SV:
ui_colorpicker_square(block, ptr, prop, UI_GRAD_SV, cpicker);
@@ -2418,7 +2424,7 @@ static void ui_block_colorpicker(uiBlock *block, float rgba[4], PointerRNA *ptr,
BLI_snprintf(hexcol, sizeof(hexcol), "%02X%02X%02X", UNPACK3_EX((unsigned int), rgb_gamma_uchar, ));
yco = -3.0f * UI_UNIT_Y;
- bt = uiDefBut(block, UI_BTYPE_TEXT, 0, IFACE_("Hex: "), 0, yco, butwidth, UI_UNIT_Y, hexcol, 0, 8, 0, 0, TIP_("Hex triplet for color (#RRGGBB)"));
+ bt = uiDefBut(block, UI_BTYPE_TEXT, 0, IFACE_("Hex: "), 0, yco, butwidth, UI_UNIT_Y, hexcol, 0, 7, 0, 0, TIP_("Hex triplet for color (#RRGGBB)"));
UI_but_func_set(bt, ui_colorpicker_hex_rna_cb, bt, hexcol);
bt->custom_data = cpicker;
uiDefBut(block, UI_BTYPE_LABEL, 0, IFACE_("(Gamma Corrected)"), 0, yco - UI_UNIT_Y, butwidth, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 0, "");
diff --git a/source/blender/editors/io/io_collada.c b/source/blender/editors/io/io_collada.c
index d4c976fb544..b1ca95efe04 100644
--- a/source/blender/editors/io/io_collada.c
+++ b/source/blender/editors/io/io_collada.c
@@ -94,6 +94,7 @@ static int wm_collada_export_exec(bContext *C, wmOperator *op)
int triangulate;
int use_object_instantiation;
+ int use_blender_profile;
int sort_by_name;
int export_transformation_type;
int open_sim;
@@ -142,6 +143,7 @@ static int wm_collada_export_exec(bContext *C, wmOperator *op)
triangulate = RNA_boolean_get(op->ptr, "triangulate");
use_object_instantiation = RNA_boolean_get(op->ptr, "use_object_instantiation");
+ use_blender_profile = RNA_boolean_get(op->ptr, "use_blender_profile");
sort_by_name = RNA_boolean_get(op->ptr, "sort_by_name");
export_transformation_type = RNA_enum_get(op->ptr, "export_transformation_type_selection");
open_sim = RNA_boolean_get(op->ptr, "open_sim");
@@ -167,6 +169,7 @@ static int wm_collada_export_exec(bContext *C, wmOperator *op)
triangulate,
use_object_instantiation,
+ use_blender_profile,
sort_by_name,
export_transformation_type,
open_sim);
@@ -256,6 +259,8 @@ static void uiCollada_exportSettings(uiLayout *layout, PointerRNA *imfptr)
uiItemR(row, imfptr, "triangulate", 0, NULL, ICON_NONE);
row = uiLayoutRow(box, false);
uiItemR(row, imfptr, "use_object_instantiation", 0, NULL, ICON_NONE);
+ row = uiLayoutRow(box, false);
+ uiItemR(row, imfptr, "use_blender_profile", 0, NULL, ICON_NONE);
row = uiLayoutRow(box, false);
split = uiLayoutSplit(row, 0.6f, UI_LAYOUT_ALIGN_RIGHT);
@@ -349,7 +354,10 @@ void WM_OT_collada_export(wmOperatorType *ot)
"Export Polygons (Quads & NGons) as Triangles");
RNA_def_boolean(ot->srna, "use_object_instantiation", 1, "Use Object Instances",
- "Instantiate multiple Objects from same Data");
+ "Instantiate multiple Objects from same Data");
+
+ RNA_def_boolean(ot->srna, "use_blender_profile", 1, "Use Blender Profile",
+ "Export additional Blender specific information (for material, shaders, bones, etc.)");
RNA_def_boolean(ot->srna, "sort_by_name", 0, "Sort by Object name",
"Sort exported data by Object name");
@@ -371,6 +379,7 @@ static int wm_collada_import_exec(bContext *C, wmOperator *op)
char filename[FILE_MAX];
int import_units;
int find_chains;
+ int auto_connect;
int fix_orientation;
int min_chain_length;
@@ -382,6 +391,7 @@ static int wm_collada_import_exec(bContext *C, wmOperator *op)
/* Options panel */
import_units = RNA_boolean_get(op->ptr, "import_units");
find_chains = RNA_boolean_get(op->ptr, "find_chains");
+ auto_connect = RNA_boolean_get(op->ptr, "auto_connect");
fix_orientation = RNA_boolean_get(op->ptr, "fix_orientation");
min_chain_length = RNA_int_get(op->ptr, "min_chain_length");
@@ -390,6 +400,7 @@ static int wm_collada_import_exec(bContext *C, wmOperator *op)
C, filename,
import_units,
find_chains,
+ auto_connect,
fix_orientation,
min_chain_length))
{
@@ -424,6 +435,9 @@ static void uiCollada_importSettings(uiLayout *layout, PointerRNA *imfptr)
uiItemR(row, imfptr, "find_chains", 0, NULL, ICON_NONE);
row = uiLayoutRow(box, false);
+ uiItemR(row, imfptr, "auto_connect", 0, NULL, ICON_NONE);
+
+ row = uiLayoutRow(box, false);
uiItemR(row, imfptr, "min_chain_length", 0, NULL, ICON_NONE);
}
@@ -466,6 +480,10 @@ void WM_OT_collada_import(wmOperatorType *ot)
"find_chains", 0, "Find Bone Chains",
"Find best matching Bone Chains and ensure bones in chain are connected");
+ RNA_def_boolean(ot->srna,
+ "auto_connect", 0, "Auto Connect",
+ "set use_connect for parent bones which have exactly one child bone");
+
RNA_def_int(ot->srna,
"min_chain_length",
0,
diff --git a/source/blender/editors/mesh/CMakeLists.txt b/source/blender/editors/mesh/CMakeLists.txt
index 0280f662a26..8783367ef7e 100644
--- a/source/blender/editors/mesh/CMakeLists.txt
+++ b/source/blender/editors/mesh/CMakeLists.txt
@@ -55,6 +55,7 @@ set(SRC
editmesh_rip_edge.c
editmesh_select.c
editmesh_tools.c
+ editmesh_undo.c
editmesh_utils.c
mesh_data.c
mesh_ops.c
diff --git a/source/blender/editors/mesh/editmesh_bevel.c b/source/blender/editors/mesh/editmesh_bevel.c
index 242cbf79a83..0f871cd4127 100644
--- a/source/blender/editors/mesh/editmesh_bevel.c
+++ b/source/blender/editors/mesh/editmesh_bevel.c
@@ -58,6 +58,9 @@
#define MVAL_PIXEL_MARGIN 5.0f
+/* until implement profile = 0 case, need to clamp somewhat above zero */
+#define PROFILE_HARD_MIN 0.15f
+
typedef struct {
BMEditMesh *em;
float initial_length;
@@ -71,13 +74,14 @@ typedef struct {
BMBackup mesh_backup;
void *draw_handle_pixel;
short twtype;
+ bool mouse_controls_profile;
float segments; /* Segments as float so smooth mouse pan works in small increments */
} BevelData;
static void edbm_bevel_update_header(bContext *C, wmOperator *op)
{
const char *str = IFACE_("Confirm: (Enter/LMB), Cancel: (Esc/RMB), Mode: %s (M), Clamp Overlap: %s (C), "
- "Vertex Only: %s (V), Offset: %s, Segments: %d");
+ "Vertex Only: %s (V), Profile Control: %s (P), Offset: %s, Segments: %d");
char msg[UI_MAX_DRAW_STR];
ScrArea *sa = CTX_wm_area(C);
@@ -101,6 +105,7 @@ static void edbm_bevel_update_header(bContext *C, wmOperator *op)
BLI_snprintf(msg, sizeof(msg), str, type_str,
WM_bool_as_string(RNA_boolean_get(op->ptr, "clamp_overlap")),
WM_bool_as_string(RNA_boolean_get(op->ptr, "vertex_only")),
+ WM_bool_as_string(opdata->mouse_controls_profile),
offset_str, RNA_int_get(op->ptr, "segments"));
ED_area_headerprint(sa, msg);
@@ -123,6 +128,7 @@ static bool edbm_bevel_init(bContext *C, wmOperator *op, const bool is_modal)
opdata->em = em;
opdata->is_modal = is_modal;
opdata->shift_factor = -1.0f;
+ opdata->mouse_controls_profile = false;
initNumInput(&opdata->num_input);
opdata->num_input.idx_max = 0;
@@ -291,7 +297,7 @@ static float edbm_bevel_mval_factor(wmOperator *op, const wmEvent *event)
{
BevelData *opdata = op->customdata;
bool use_dist;
- bool is_percent;
+ bool is_percent, is_profile;
float mdiff[2];
float factor;
@@ -299,15 +305,20 @@ static float edbm_bevel_mval_factor(wmOperator *op, const wmEvent *event)
mdiff[1] = opdata->mcenter[1] - event->mval[1];
is_percent = (RNA_enum_get(op->ptr, "offset_type") == BEVEL_AMT_PERCENT);
use_dist = !is_percent;
+ is_profile = opdata->mouse_controls_profile;
factor = ((len_v2(mdiff) - MVAL_PIXEL_MARGIN) - opdata->initial_length) * opdata->pixel_size;
/* Fake shift-transform... */
if (event->shift) {
if (opdata->shift_factor < 0.0f) {
- opdata->shift_factor = RNA_float_get(op->ptr, "offset");
- if (is_percent) {
- opdata->shift_factor /= 100.0f;
+ if (is_profile)
+ opdata->shift_factor = RNA_float_get(op->ptr, "profile");
+ else {
+ opdata->shift_factor = RNA_float_get(op->ptr, "offset");
+ if (is_percent) {
+ opdata->shift_factor /= 100.0f;
+ }
}
}
factor = (factor - opdata->shift_factor) * 0.1f + opdata->shift_factor;
@@ -316,14 +327,19 @@ static float edbm_bevel_mval_factor(wmOperator *op, const wmEvent *event)
opdata->shift_factor = -1.0f;
}
- /* clamp differently based on distance/factor */
- if (use_dist) {
- if (factor < 0.0f) factor = 0.0f;
+ /* clamp differently based on distance/factor/profile */
+ if (is_profile) {
+ CLAMP(factor, PROFILE_HARD_MIN, 1.0f);
}
else {
- CLAMP(factor, 0.0f, 1.0f);
- if (is_percent) {
- factor *= 100.0f;
+ if (use_dist) {
+ if (factor < 0.0f) factor = 0.0f;
+ }
+ else {
+ CLAMP(factor, 0.0f, 1.0f);
+ if (is_percent) {
+ factor *= 100.0f;
+ }
}
}
@@ -355,7 +371,10 @@ static int edbm_bevel_modal(bContext *C, wmOperator *op, const wmEvent *event)
case MOUSEMOVE:
if (!has_numinput) {
const float factor = edbm_bevel_mval_factor(op, event);
- RNA_float_set(op->ptr, "offset", factor);
+ if (opdata->mouse_controls_profile)
+ RNA_float_set(op->ptr, "profile", factor);
+ else
+ RNA_float_set(op->ptr, "offset", factor);
edbm_bevel_calc(op);
edbm_bevel_update_header(C, op);
@@ -448,6 +467,11 @@ static int edbm_bevel_modal(bContext *C, wmOperator *op, const wmEvent *event)
edbm_bevel_update_header(C, op);
handled = true;
break;
+ case PKEY:
+ if (event->val == KM_RELEASE)
+ break;
+ opdata->mouse_controls_profile = !opdata->mouse_controls_profile;
+ break;
case VKEY:
if (event->val == KM_RELEASE)
break;
@@ -519,7 +543,8 @@ void MESH_OT_bevel(wmOperatorType *ot)
prop = RNA_def_float(ot->srna, "offset", 0.0f, -1e6f, 1e6f, "Amount", "", 0.0f, 1.0f);
RNA_def_property_float_array_funcs_runtime(prop, NULL, NULL, mesh_ot_bevel_offset_range_func);
RNA_def_int(ot->srna, "segments", 1, 1, 50, "Segments", "Segments for curved edge", 1, 8);
- RNA_def_float(ot->srna, "profile", 0.5f, 0.15f, 1.0f, "Profile", "Controls profile shape (0.5 = round)", 0.15f, 1.0f);
+ RNA_def_float(ot->srna, "profile", 0.5f, PROFILE_HARD_MIN, 1.0f, "Profile",
+ "Controls profile shape (0.5 = round)", PROFILE_HARD_MIN, 1.0f);
RNA_def_boolean(ot->srna, "vertex_only", false, "Vertex Only", "Bevel only vertices");
RNA_def_boolean(ot->srna, "clamp_overlap", false, "Clamp Overlap",
"Do not allow beveled edges/vertices to overlap each other");
diff --git a/source/blender/editors/mesh/editmesh_tools.c b/source/blender/editors/mesh/editmesh_tools.c
index ba17684dd39..efe179790da 100644
--- a/source/blender/editors/mesh/editmesh_tools.c
+++ b/source/blender/editors/mesh/editmesh_tools.c
@@ -312,9 +312,10 @@ void EMBM_project_snap_verts(bContext *C, ARegion *ar, BMEditMesh *em)
if (ED_view3d_project_float_object(ar, eve->co, mval, V3D_PROJ_TEST_NOP) == V3D_PROJ_RET_OK) {
if (ED_transform_snap_object_project_view3d_mixed(
snap_context,
+ SCE_SELECT_FACE,
&(const struct SnapObjectParams){
- .snap_select = SNAP_NOT_OBEDIT,
- .snap_to_flag = SCE_SELECT_FACE,
+ .snap_select = SNAP_NOT_ACTIVE,
+ .use_object_edit_cage = false,
},
mval, NULL, true,
co_proj, NULL))
diff --git a/source/blender/editors/mesh/editmesh_undo.c b/source/blender/editors/mesh/editmesh_undo.c
new file mode 100644
index 00000000000..b9d3fd6c8be
--- /dev/null
+++ b/source/blender/editors/mesh/editmesh_undo.c
@@ -0,0 +1,726 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/editors/mesh/editmesh_undo.c
+ * \ingroup edmesh
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_mesh_types.h"
+#include "DNA_object_types.h"
+#include "DNA_key_types.h"
+
+#include "BLI_listbase.h"
+
+#include "BKE_DerivedMesh.h"
+#include "BKE_context.h"
+#include "BKE_key.h"
+#include "BKE_mesh.h"
+#include "BKE_editmesh.h"
+
+#include "ED_mesh.h"
+#include "ED_util.h"
+
+#define USE_ARRAY_STORE
+
+#ifdef USE_ARRAY_STORE
+// # define DEBUG_PRINT
+// # define DEBUG_TIME
+# ifdef DEBUG_TIME
+# include "PIL_time_utildefines.h"
+# endif
+
+# include "BLI_array_store.h"
+# include "BLI_math_base.h"
+ /* check on best size later... */
+# define ARRAY_CHUNK_SIZE 256
+
+# define USE_ARRAY_STORE_THREAD
+#endif
+
+#ifdef USE_ARRAY_STORE_THREAD
+# include "BLI_task.h"
+#endif
+
+
+#ifdef USE_ARRAY_STORE
+
+/* Single linked list of layers stored per type */
+typedef struct BArrayCustomData {
+ struct BArrayCustomData *next;
+ CustomDataType type;
+ int states_len; /* number of layers for each type */
+ BArrayState *states[0];
+} BArrayCustomData;
+
+#endif
+
+typedef struct UndoMesh {
+ Mesh me;
+ int selectmode;
+
+ /** \note
+ * this isn't a prefect solution, if you edit keys and change shapes this works well (fixing [#32442]),
+ * but editing shape keys, going into object mode, removing or changing their order,
+ * then go back into editmode and undo will give issues - where the old index will be out of sync
+ * with the new object index.
+ *
+ * There are a few ways this could be made to work but for now its a known limitation with mixing
+ * object and editmode operations - Campbell */
+ int shapenr;
+
+#ifdef USE_ARRAY_STORE
+ /* NULL arrays are considered empty */
+ struct {
+ /* most data is stored as 'custom' data */
+ BArrayCustomData *vdata, *edata, *ldata, *pdata;
+ BArrayState **keyblocks;
+ BArrayState *mselect;
+ } store;
+#endif /* USE_ARRAY_STORE */
+} UndoMesh;
+
+
+#ifdef USE_ARRAY_STORE
+
+/** \name Array Store
+ * \{ */
+
+static struct {
+ BArrayStore **bs_all;
+ int bs_all_len;
+ int users;
+
+ /* We could have the undo API pass in the previous state, for now store a local list */
+ ListBase local_links;
+
+#ifdef USE_ARRAY_STORE_THREAD
+ TaskPool *task_pool;
+#endif
+
+} um_arraystore = {NULL};
+
+static BArrayStore *array_store_at_size_ensure(const int stride)
+{
+ if (um_arraystore.bs_all_len < stride) {
+ um_arraystore.bs_all_len = stride;
+ um_arraystore.bs_all = MEM_recallocN(um_arraystore.bs_all, sizeof(*um_arraystore.bs_all) * stride);
+ }
+ BArrayStore **bs_p = &um_arraystore.bs_all[stride - 1];
+
+ if ((*bs_p) == NULL) {
+#if 0
+ unsigned int chunk_count = ARRAY_CHUNK_SIZE;
+#else
+ /* calculate best chunk-count to fit a power of two */
+ unsigned int chunk_count = ARRAY_CHUNK_SIZE;
+ {
+ unsigned int size = chunk_count * stride;
+ size = power_of_2_max_u(size);
+ size = MEM_SIZE_OPTIMAL(size);
+ chunk_count = size / stride;
+ }
+#endif
+
+ (*bs_p) = BLI_array_store_create(stride, chunk_count);
+ }
+ return *bs_p;
+}
+
+static BArrayStore *array_store_at_size_get(const int stride)
+{
+ BLI_assert(stride > 0 && stride <= um_arraystore.bs_all_len);
+ return um_arraystore.bs_all[stride - 1];
+}
+
+#ifdef DEBUG_PRINT
+static void um_arraystore_memory_usage(size_t *r_size_expanded, size_t *r_size_compacted)
+{
+ size_t size_compacted = 0;
+ size_t size_expanded = 0;
+ for (int i = 0; i < um_arraystore.bs_all_len; i++) {
+ BArrayStore *bs = um_arraystore.bs_all[i];
+ if (bs) {
+ size_compacted += BLI_array_store_calc_size_compacted_get(bs);
+ size_expanded += BLI_array_store_calc_size_expanded_get(bs);
+ }
+ }
+
+ *r_size_expanded = size_expanded;
+ *r_size_compacted = size_compacted;
+}
+#endif
+
+static void um_arraystore_cd_compact(
+ struct CustomData *cdata, const size_t data_len,
+ bool create,
+ const BArrayCustomData *bcd_reference,
+ BArrayCustomData **r_bcd_first)
+{
+ if (data_len == 0) {
+ if (create) {
+ *r_bcd_first = NULL;
+ }
+ }
+
+ const BArrayCustomData *bcd_reference_current = bcd_reference;
+ BArrayCustomData *bcd = NULL, *bcd_first = NULL, *bcd_prev = NULL;
+ for (int layer_start = 0, layer_end; layer_start < cdata->totlayer; layer_start = layer_end) {
+ const CustomDataType type = cdata->layers[layer_start].type;
+
+ layer_end = layer_start + 1;
+ while ((layer_end < cdata->totlayer) &&
+ (type == cdata->layers[layer_end].type))
+ {
+ layer_end++;
+ }
+
+ const int stride = CustomData_sizeof(type);
+ BArrayStore *bs = create ? array_store_at_size_ensure(stride) : NULL;
+ const int layer_len = layer_end - layer_start;
+
+ if (create) {
+ if (bcd_reference_current && (bcd_reference_current->type == type)) {
+ /* common case, the reference is aligned */
+ }
+ else {
+ bcd_reference_current = NULL;
+
+ /* do a full lookup when un-alligned */
+ if (bcd_reference) {
+ const BArrayCustomData *bcd_iter = bcd_reference;
+ while (bcd_iter) {
+ if (bcd_iter->type == type) {
+ bcd_reference_current = bcd_iter;
+ break;
+ }
+ bcd_iter = bcd_iter->next;
+ }
+ }
+ }
+ }
+
+ if (create) {
+ bcd = MEM_callocN(sizeof(BArrayCustomData) + (layer_len * sizeof(BArrayState *)), __func__);
+ bcd->next = NULL;
+ bcd->type = type;
+ bcd->states_len = layer_end - layer_start;
+
+ if (bcd_prev) {
+ bcd_prev->next = bcd;
+ bcd_prev = bcd;
+ }
+ else {
+ bcd_first = bcd;
+ bcd_prev = bcd;
+ }
+ }
+
+ CustomDataLayer *layer = &cdata->layers[layer_start];
+ for (int i = 0; i < layer_len; i++, layer++) {
+ if (create) {
+ if (layer->data) {
+ BArrayState *state_reference =
+ (bcd_reference_current && i < bcd_reference_current->states_len) ?
+ bcd_reference_current->states[i] : NULL;
+ bcd->states[i] = BLI_array_store_state_add(
+ bs, layer->data, (size_t)data_len * stride, state_reference);
+ }
+ else {
+ bcd->states[i] = NULL;
+ }
+ }
+
+ if (layer->data) {
+ MEM_freeN(layer->data);
+ layer->data = NULL;
+ }
+ }
+
+ if (create) {
+ if (bcd_reference_current) {
+ bcd_reference_current = bcd_reference_current->next;
+ }
+ }
+ }
+
+ if (create) {
+ *r_bcd_first = bcd_first;
+ }
+}
+
+/**
+ * \note There is no room for data going out of sync here.
+ * The layers and the states are stored together so this can be kept working.
+ */
+static void um_arraystore_cd_expand(
+ const BArrayCustomData *bcd, struct CustomData *cdata, const size_t data_len)
+{
+ CustomDataLayer *layer = cdata->layers;
+ while (bcd) {
+ const int stride = CustomData_sizeof(bcd->type);
+ for (int i = 0; i < bcd->states_len; i++) {
+ BLI_assert(bcd->type == layer->type);
+ if (bcd->states[i]) {
+ size_t state_len;
+ layer->data = BLI_array_store_state_data_get_alloc(bcd->states[i], &state_len);
+ BLI_assert(stride * data_len == state_len);
+ UNUSED_VARS_NDEBUG(stride, data_len);
+ }
+ else {
+ layer->data = NULL;
+ }
+ layer++;
+ }
+ bcd = bcd->next;
+ }
+}
+
+static void um_arraystore_cd_free(BArrayCustomData *bcd)
+{
+ while (bcd) {
+ BArrayCustomData *bcd_next = bcd->next;
+ const int stride = CustomData_sizeof(bcd->type);
+ BArrayStore *bs = array_store_at_size_get(stride);
+ for (int i = 0; i < bcd->states_len; i++) {
+ if (bcd->states[i]) {
+ BLI_array_store_state_remove(bs, bcd->states[i]);
+ }
+ }
+ MEM_freeN(bcd);
+ bcd = bcd_next;
+ }
+}
+
+/**
+ * \param create: When false, only free the arrays.
+ * This is done since when reading from an undo state, they must be temporarily expanded.
+ * then discarded afterwards, having this argument avoids having 2x code paths.
+ */
+static void um_arraystore_compact_ex(
+ UndoMesh *um, const UndoMesh *um_ref,
+ bool create)
+{
+ Mesh *me = &um->me;
+
+ um_arraystore_cd_compact(&me->vdata, me->totvert, create, um_ref ? um_ref->store.vdata : NULL, &um->store.vdata);
+ um_arraystore_cd_compact(&me->edata, me->totedge, create, um_ref ? um_ref->store.edata : NULL, &um->store.edata);
+ um_arraystore_cd_compact(&me->ldata, me->totloop, create, um_ref ? um_ref->store.ldata : NULL, &um->store.ldata);
+ um_arraystore_cd_compact(&me->pdata, me->totpoly, create, um_ref ? um_ref->store.pdata : NULL, &um->store.pdata);
+
+ if (me->key && me->key->totkey) {
+ const size_t stride = me->key->elemsize;
+ BArrayStore *bs = create ? array_store_at_size_ensure(stride) : NULL;
+ if (create) {
+ um->store.keyblocks = MEM_mallocN(me->key->totkey * sizeof(*um->store.keyblocks), __func__);
+ }
+ KeyBlock *keyblock = me->key->block.first;
+ for (int i = 0; i < me->key->totkey; i++, keyblock = keyblock->next) {
+ if (create) {
+ BArrayState *state_reference =
+ (um_ref && um_ref->me.key && (i < um_ref->me.key->totkey)) ?
+ um_ref->store.keyblocks[i] : NULL;
+ um->store.keyblocks[i] = BLI_array_store_state_add(
+ bs, keyblock->data, (size_t)keyblock->totelem * stride,
+ state_reference);
+ }
+
+ if (keyblock->data) {
+ MEM_freeN(keyblock->data);
+ keyblock->data = NULL;
+ }
+ }
+ }
+
+ if (me->mselect && me->totselect) {
+ BLI_assert(create == (um->store.mselect == NULL));
+ if (create) {
+ BArrayState *state_reference = um_ref ? um_ref->store.mselect : NULL;
+ const size_t stride = sizeof(*me->mselect);
+ BArrayStore *bs = array_store_at_size_ensure(stride);
+ um->store.mselect = BLI_array_store_state_add(
+ bs, me->mselect, (size_t)me->totselect * stride, state_reference);
+ }
+
+ /* keep me->totselect for validation */
+ MEM_freeN(me->mselect);
+ me->mselect = NULL;
+ }
+
+ if (create) {
+ um_arraystore.users += 1;
+ }
+
+ BKE_mesh_update_customdata_pointers(me, false);
+}
+
+/**
+ * Move data from allocated arrays to de-duplicated states and clear arrays.
+ */
+static void um_arraystore_compact(UndoMesh *um, const UndoMesh *um_ref)
+{
+ um_arraystore_compact_ex(um, um_ref, true);
+}
+
+static void um_arraystore_compact_with_info(UndoMesh *um, const UndoMesh *um_ref)
+{
+#ifdef DEBUG_PRINT
+ size_t size_expanded_prev, size_compacted_prev;
+ um_arraystore_memory_usage(&size_expanded_prev, &size_compacted_prev);
+#endif
+
+#ifdef DEBUG_TIME
+ TIMEIT_START(mesh_undo_compact);
+#endif
+
+ um_arraystore_compact(um, um_ref);
+
+#ifdef DEBUG_TIME
+ TIMEIT_END(mesh_undo_compact);
+#endif
+
+#ifdef DEBUG_PRINT
+ {
+ size_t size_expanded, size_compacted;
+ um_arraystore_memory_usage(&size_expanded, &size_compacted);
+
+ const double percent_total = size_expanded ?
+ (((double)size_compacted / (double)size_expanded) * 100.0) : -1.0;
+
+ size_t size_expanded_step = size_expanded - size_expanded_prev;
+ size_t size_compacted_step = size_compacted - size_compacted_prev;
+ const double percent_step = size_expanded_step ?
+ (((double)size_compacted_step / (double)size_expanded_step) * 100.0) : -1.0;
+
+ printf("overall memory use: %.8f%% of expanded size\n", percent_total);
+ printf("step memory use: %.8f%% of expanded size\n", percent_step);
+ }
+#endif
+}
+
+#ifdef USE_ARRAY_STORE_THREAD
+
+struct UMArrayData {
+ UndoMesh *um;
+ const UndoMesh *um_ref; /* can be NULL */
+};
+static void um_arraystore_compact_cb(TaskPool *UNUSED(pool), void *taskdata, int UNUSED(threadid))
+{
+ struct UMArrayData *um_data = taskdata;
+ um_arraystore_compact_with_info(um_data->um, um_data->um_ref);
+}
+
+#endif /* USE_ARRAY_STORE_THREAD */
+
+/**
+ * Remove data we only expanded for temporary use.
+ */
+static void um_arraystore_expand_clear(UndoMesh *um)
+{
+ um_arraystore_compact_ex(um, NULL, false);
+}
+
+static void um_arraystore_expand(UndoMesh *um)
+{
+ Mesh *me = &um->me;
+
+ um_arraystore_cd_expand(um->store.vdata, &me->vdata, me->totvert);
+ um_arraystore_cd_expand(um->store.edata, &me->edata, me->totedge);
+ um_arraystore_cd_expand(um->store.ldata, &me->ldata, me->totloop);
+ um_arraystore_cd_expand(um->store.pdata, &me->pdata, me->totpoly);
+
+ if (um->store.keyblocks) {
+ const size_t stride = me->key->elemsize;
+ KeyBlock *keyblock = me->key->block.first;
+ for (int i = 0; i < me->key->totkey; i++, keyblock = keyblock->next) {
+ BArrayState *state = um->store.keyblocks[i];
+ size_t state_len;
+ keyblock->data = BLI_array_store_state_data_get_alloc(state, &state_len);
+ BLI_assert(keyblock->totelem == (state_len / stride));
+ UNUSED_VARS_NDEBUG(stride);
+ }
+ }
+
+ if (um->store.mselect) {
+ const size_t stride = sizeof(*me->mselect);
+ BArrayState *state = um->store.mselect;
+ size_t state_len;
+ me->mselect = BLI_array_store_state_data_get_alloc(state, &state_len);
+ BLI_assert(me->totselect == (state_len / stride));
+ UNUSED_VARS_NDEBUG(stride);
+ }
+
+ /* not essential, but prevents accidental dangling pointer access */
+ BKE_mesh_update_customdata_pointers(me, false);
+}
+
+static void um_arraystore_free(UndoMesh *um)
+{
+ Mesh *me = &um->me;
+
+ um_arraystore_cd_free(um->store.vdata);
+ um_arraystore_cd_free(um->store.edata);
+ um_arraystore_cd_free(um->store.ldata);
+ um_arraystore_cd_free(um->store.pdata);
+
+ if (um->store.keyblocks) {
+ const size_t stride = me->key->elemsize;
+ BArrayStore *bs = array_store_at_size_get(stride);
+ for (int i = 0; i < me->key->totkey; i++) {
+ BArrayState *state = um->store.keyblocks[i];
+ BLI_array_store_state_remove(bs, state);
+ }
+ MEM_freeN(um->store.keyblocks);
+ um->store.keyblocks = NULL;
+ }
+
+ if (um->store.mselect) {
+ const size_t stride = sizeof(*me->mselect);
+ BArrayStore *bs = array_store_at_size_get(stride);
+ BArrayState *state = um->store.mselect;
+ BLI_array_store_state_remove(bs, state);
+ um->store.mselect = NULL;
+ }
+
+ um_arraystore.users -= 1;
+
+ BLI_assert(um_arraystore.users >= 0);
+
+ if (um_arraystore.users == 0) {
+#ifdef DEBUG_PRINT
+ printf("mesh undo store: freeing all data!\n");
+#endif
+ for (int i = 0; i < um_arraystore.bs_all_len; i += 1) {
+ if (um_arraystore.bs_all[i]) {
+ BLI_array_store_destroy(um_arraystore.bs_all[i]);
+ }
+ }
+
+ MEM_freeN(um_arraystore.bs_all);
+ um_arraystore.bs_all = NULL;
+ um_arraystore.bs_all_len = 0;
+
+#ifdef USE_ARRAY_STORE_THREAD
+ BLI_task_pool_free(um_arraystore.task_pool);
+ um_arraystore.task_pool = NULL;
+#endif
+ }
+
+}
+
+/** \} */
+
+#endif /* USE_ARRAY_STORE */
+
+
+/* for callbacks */
+/* undo simply makes copies of a bmesh */
+static void *editbtMesh_to_undoMesh(void *emv, void *obdata)
+{
+
+#ifdef USE_ARRAY_STORE_THREAD
+ /* changes this waits is low, but must have finished */
+ if (um_arraystore.task_pool) {
+ BLI_task_pool_work_and_wait(um_arraystore.task_pool);
+ }
+#endif
+
+ BMEditMesh *em = emv;
+ Mesh *obme = obdata;
+
+ UndoMesh *um = MEM_callocN(sizeof(UndoMesh), "undo Mesh");
+
+ /* make sure shape keys work */
+ um->me.key = obme->key ? BKE_key_copy_nolib(obme->key) : NULL;
+
+ /* BM_mesh_validate(em->bm); */ /* for troubleshooting */
+
+ BM_mesh_bm_to_me(
+ em->bm, &um->me, (&(struct BMeshToMeshParams){
+ .cd_mask_extra = CD_MASK_SHAPE_KEYINDEX,
+ }));
+
+ um->selectmode = em->selectmode;
+ um->shapenr = em->bm->shapenr;
+
+#ifdef USE_ARRAY_STORE
+ {
+ /* We could be more clever here,
+ * the previous undo state may be from a separate mesh. */
+ const UndoMesh *um_ref = um_arraystore.local_links.last ?
+ ((LinkData *)um_arraystore.local_links.last)->data : NULL;
+
+ /* add oursrlves */
+ BLI_addtail(&um_arraystore.local_links, BLI_genericNodeN(um));
+
+#ifdef USE_ARRAY_STORE_THREAD
+ if (um_arraystore.task_pool == NULL) {
+ TaskScheduler *scheduler = BLI_task_scheduler_get();
+ um_arraystore.task_pool = BLI_task_pool_create_background(scheduler, NULL);
+ }
+
+ struct UMArrayData *um_data = MEM_mallocN(sizeof(*um_data), __func__);
+ um_data->um = um;
+ um_data->um_ref = um_ref;
+
+ BLI_task_pool_push(
+ um_arraystore.task_pool,
+ um_arraystore_compact_cb, um_data, true, TASK_PRIORITY_LOW);
+#else
+ um_arraystore_compact_with_info(um, um_ref);
+#endif
+ }
+#endif
+
+ return um;
+}
+
+static void undoMesh_to_editbtMesh(void *um_v, void *em_v, void *obdata)
+{
+ BMEditMesh *em = em_v, *em_tmp;
+ Object *ob = em->ob;
+ UndoMesh *um = um_v;
+ BMesh *bm;
+ Key *key = ((Mesh *) obdata)->key;
+
+#ifdef USE_ARRAY_STORE
+#ifdef USE_ARRAY_STORE_THREAD
+ /* changes this waits is low, but must have finished */
+ BLI_task_pool_work_and_wait(um_arraystore.task_pool);
+#endif
+
+#ifdef DEBUG_TIME
+ TIMEIT_START(mesh_undo_expand);
+#endif
+
+ um_arraystore_expand(um);
+
+#ifdef DEBUG_TIME
+ TIMEIT_END(mesh_undo_expand);
+#endif
+#endif /* USE_ARRAY_STORE */
+
+ const BMAllocTemplate allocsize = BMALLOC_TEMPLATE_FROM_ME(&um->me);
+
+ em->bm->shapenr = um->shapenr;
+
+ EDBM_mesh_free(em);
+
+ bm = BM_mesh_create(&allocsize);
+
+ BM_mesh_bm_from_me(
+ bm, &um->me, (&(struct BMeshFromMeshParams){
+ .calc_face_normal = true, .active_shapekey = um->shapenr,
+ }));
+
+ em_tmp = BKE_editmesh_create(bm, true);
+ *em = *em_tmp;
+
+ em->selectmode = um->selectmode;
+ bm->selectmode = um->selectmode;
+ em->ob = ob;
+
+ /* T35170: Restore the active key on the RealMesh. Otherwise 'fake' offset propagation happens
+ * if the active is a basis for any other. */
+ if (key && (key->type == KEY_RELATIVE)) {
+ /* Since we can't add, remove or reorder keyblocks in editmode, it's safe to assume
+ * shapenr from restored bmesh and keyblock indices are in sync. */
+ const int kb_act_idx = ob->shapenr - 1;
+
+ /* If it is, let's patch the current mesh key block to its restored value.
+ * Else, the offsets won't be computed and it won't matter. */
+ if (BKE_keyblock_is_basis(key, kb_act_idx)) {
+ KeyBlock *kb_act = BLI_findlink(&key->block, kb_act_idx);
+
+ if (kb_act->totelem != um->me.totvert) {
+ /* The current mesh has some extra/missing verts compared to the undo, adjust. */
+ MEM_SAFE_FREE(kb_act->data);
+ kb_act->data = MEM_mallocN((size_t)(key->elemsize * bm->totvert), __func__);
+ kb_act->totelem = um->me.totvert;
+ }
+
+ BKE_keyblock_update_from_mesh(&um->me, kb_act);
+ }
+ }
+
+ ob->shapenr = um->shapenr;
+
+ MEM_freeN(em_tmp);
+
+#ifdef USE_ARRAY_STORE
+ um_arraystore_expand_clear(um);
+#endif
+}
+
+static void free_undo(void *um_v)
+{
+ UndoMesh *um = um_v;
+ Mesh *me = &um->me;
+
+#ifdef USE_ARRAY_STORE
+
+#ifdef USE_ARRAY_STORE_THREAD
+ /* changes this waits is low, but must have finished */
+ BLI_task_pool_work_and_wait(um_arraystore.task_pool);
+#endif
+
+ /* we need to expand so any allocations in custom-data are freed with the mesh */
+ um_arraystore_expand(um);
+
+ {
+ LinkData *link = BLI_findptr(&um_arraystore.local_links, um, offsetof(LinkData, data));
+ BLI_remlink(&um_arraystore.local_links, link);
+ MEM_freeN(link);
+ }
+ um_arraystore_free(um);
+#endif
+
+ if (me->key) {
+ BKE_key_free(me->key);
+ MEM_freeN(me->key);
+ }
+
+ BKE_mesh_free(me, false);
+ MEM_freeN(me);
+}
+
+static void *getEditMesh(bContext *C)
+{
+ Object *obedit = CTX_data_edit_object(C);
+ if (obedit && obedit->type == OB_MESH) {
+ Mesh *me = obedit->data;
+ return me->edit_btmesh;
+ }
+ return NULL;
+}
+
+/* and this is all the undo system needs to know */
+void undo_push_mesh(bContext *C, const char *name)
+{
+ /* em->ob gets out of date and crashes on mesh undo,
+ * this is an easy way to ensure its OK
+ * though we could investigate the matter further. */
+ Object *obedit = CTX_data_edit_object(C);
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ em->ob = obedit;
+
+ undo_editmode_push(C, name, getEditMesh, free_undo, undoMesh_to_editbtMesh, editbtMesh_to_undoMesh, NULL);
+}
diff --git a/source/blender/editors/mesh/editmesh_utils.c b/source/blender/editors/mesh/editmesh_utils.c
index 82ec93c162f..99be37845ee 100644
--- a/source/blender/editors/mesh/editmesh_utils.c
+++ b/source/blender/editors/mesh/editmesh_utils.c
@@ -45,7 +45,6 @@
#include "BKE_context.h"
#include "BKE_global.h"
#include "BKE_depsgraph.h"
-#include "BKE_key.h"
#include "BKE_main.h"
#include "BKE_mesh.h"
#include "BKE_mesh_mapping.h"
@@ -60,7 +59,6 @@
#include "ED_mesh.h"
#include "ED_screen.h"
-#include "ED_util.h"
#include "ED_view3d.h"
#include "mesh_intern.h" /* own include */
@@ -491,140 +489,6 @@ void EDBM_flag_enable_all(BMEditMesh *em, const char hflag)
BM_mesh_elem_hflag_enable_all(em->bm, BM_VERT | BM_EDGE | BM_FACE, hflag, true);
}
-/**************-------------- Undo ------------*****************/
-
-/* for callbacks */
-
-static void *getEditMesh(bContext *C)
-{
- Object *obedit = CTX_data_edit_object(C);
- if (obedit && obedit->type == OB_MESH) {
- Mesh *me = obedit->data;
- return me->edit_btmesh;
- }
- return NULL;
-}
-
-typedef struct UndoMesh {
- Mesh me;
- int selectmode;
-
- /** \note
- * this isn't a prefect solution, if you edit keys and change shapes this works well (fixing [#32442]),
- * but editing shape keys, going into object mode, removing or changing their order,
- * then go back into editmode and undo will give issues - where the old index will be out of sync
- * with the new object index.
- *
- * There are a few ways this could be made to work but for now its a known limitation with mixing
- * object and editmode operations - Campbell */
- int shapenr;
-} UndoMesh;
-
-/* undo simply makes copies of a bmesh */
-static void *editbtMesh_to_undoMesh(void *emv, void *obdata)
-{
- BMEditMesh *em = emv;
- Mesh *obme = obdata;
-
- UndoMesh *um = MEM_callocN(sizeof(UndoMesh), "undo Mesh");
-
- /* make sure shape keys work */
- um->me.key = obme->key ? BKE_key_copy_nolib(obme->key) : NULL;
-
- /* BM_mesh_validate(em->bm); */ /* for troubleshooting */
-
- BM_mesh_bm_to_me(
- em->bm, &um->me, (&(struct BMeshToMeshParams){
- .cd_mask_extra = CD_MASK_SHAPE_KEYINDEX,
- }));
-
- um->selectmode = em->selectmode;
- um->shapenr = em->bm->shapenr;
-
- return um;
-}
-
-static void undoMesh_to_editbtMesh(void *umv, void *em_v, void *obdata)
-{
- BMEditMesh *em = em_v, *em_tmp;
- Object *ob = em->ob;
- UndoMesh *um = umv;
- BMesh *bm;
- Key *key = ((Mesh *) obdata)->key;
-
- const BMAllocTemplate allocsize = BMALLOC_TEMPLATE_FROM_ME(&um->me);
-
- em->bm->shapenr = um->shapenr;
-
- EDBM_mesh_free(em);
-
- bm = BM_mesh_create(&allocsize);
-
- BM_mesh_bm_from_me(
- bm, &um->me, (&(struct BMeshFromMeshParams){
- .calc_face_normal = true, .active_shapekey = um->shapenr,
- }));
-
- em_tmp = BKE_editmesh_create(bm, true);
- *em = *em_tmp;
-
- em->selectmode = um->selectmode;
- bm->selectmode = um->selectmode;
- em->ob = ob;
-
- /* T35170: Restore the active key on the RealMesh. Otherwise 'fake' offset propagation happens
- * if the active is a basis for any other. */
- if (key && (key->type == KEY_RELATIVE)) {
- /* Since we can't add, remove or reorder keyblocks in editmode, it's safe to assume
- * shapenr from restored bmesh and keyblock indices are in sync. */
- const int kb_act_idx = ob->shapenr - 1;
-
- /* If it is, let's patch the current mesh key block to its restored value.
- * Else, the offsets won't be computed and it won't matter. */
- if (BKE_keyblock_is_basis(key, kb_act_idx)) {
- KeyBlock *kb_act = BLI_findlink(&key->block, kb_act_idx);
-
- if (kb_act->totelem != um->me.totvert) {
- /* The current mesh has some extra/missing verts compared to the undo, adjust. */
- MEM_SAFE_FREE(kb_act->data);
- kb_act->data = MEM_mallocN((size_t)(key->elemsize * bm->totvert), __func__);
- kb_act->totelem = um->me.totvert;
- }
-
- BKE_keyblock_update_from_mesh(&um->me, kb_act);
- }
- }
-
- ob->shapenr = um->shapenr;
-
- MEM_freeN(em_tmp);
-}
-
-static void free_undo(void *me_v)
-{
- Mesh *me = me_v;
- if (me->key) {
- BKE_key_free(me->key);
- MEM_freeN(me->key);
- }
-
- BKE_mesh_free(me, false);
- MEM_freeN(me);
-}
-
-/* and this is all the undo system needs to know */
-void undo_push_mesh(bContext *C, const char *name)
-{
- /* em->ob gets out of date and crashes on mesh undo,
- * this is an easy way to ensure its OK
- * though we could investigate the matter further. */
- Object *obedit = CTX_data_edit_object(C);
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
- em->ob = obedit;
-
- undo_editmode_push(C, name, getEditMesh, free_undo, undoMesh_to_editbtMesh, editbtMesh_to_undoMesh, NULL);
-}
-
/**
* Return a new UVVertMap from the editmesh
*/
diff --git a/source/blender/editors/object/object_add.c b/source/blender/editors/object/object_add.c
index 88ab3450b04..09c9442db54 100644
--- a/source/blender/editors/object/object_add.c
+++ b/source/blender/editors/object/object_add.c
@@ -1601,7 +1601,7 @@ static int convert_exec(bContext *C, wmOperator *op)
if (newob->type == OB_CURVE) {
BKE_object_free_modifiers(newob); /* after derivedmesh calls! */
- ED_rigidbody_object_remove(scene, newob);
+ ED_rigidbody_object_remove(bmain, scene, newob);
}
}
else if (ob->type == OB_MESH && ob->modifiers.first) { /* converting a mesh with no modifiers causes a segfault */
diff --git a/source/blender/editors/physics/rigidbody_constraint.c b/source/blender/editors/physics/rigidbody_constraint.c
index f95599592b2..1bfc162a331 100644
--- a/source/blender/editors/physics/rigidbody_constraint.c
+++ b/source/blender/editors/physics/rigidbody_constraint.c
@@ -41,6 +41,7 @@
#include "BKE_depsgraph.h"
#include "BKE_global.h"
#include "BKE_group.h"
+#include "BKE_main.h"
#include "BKE_report.h"
#include "BKE_rigidbody.h"
@@ -70,7 +71,7 @@ static int ED_operator_rigidbody_con_active_poll(bContext *C)
}
-bool ED_rigidbody_constraint_add(Scene *scene, Object *ob, int type, ReportList *reports)
+bool ED_rigidbody_constraint_add(Main *bmain, Scene *scene, Object *ob, int type, ReportList *reports)
{
RigidBodyWorld *rbw = BKE_rigidbody_get_world(scene);
@@ -81,7 +82,7 @@ bool ED_rigidbody_constraint_add(Scene *scene, Object *ob, int type, ReportList
}
/* create constraint group if it doesn't already exits */
if (rbw->constraints == NULL) {
- rbw->constraints = BKE_group_add(G.main, "RigidBodyConstraints");
+ rbw->constraints = BKE_group_add(bmain, "RigidBodyConstraints");
}
/* make rigidbody constraint settings */
ob->rigidbody_constraint = BKE_rigidbody_create_constraint(scene, ob, type);
@@ -90,11 +91,12 @@ bool ED_rigidbody_constraint_add(Scene *scene, Object *ob, int type, ReportList
/* add constraint to rigid body constraint group */
BKE_group_object_add(rbw->constraints, ob, scene, NULL);
+ DAG_relations_tag_update(bmain);
DAG_id_tag_update(&ob->id, OB_RECALC_OB);
return true;
}
-void ED_rigidbody_constraint_remove(Scene *scene, Object *ob)
+void ED_rigidbody_constraint_remove(Main *bmain, Scene *scene, Object *ob)
{
RigidBodyWorld *rbw = BKE_rigidbody_get_world(scene);
@@ -102,6 +104,7 @@ void ED_rigidbody_constraint_remove(Scene *scene, Object *ob)
if (rbw)
BKE_group_object_unlink(rbw->constraints, ob, scene, NULL);
+ DAG_relations_tag_update(bmain);
DAG_id_tag_update(&ob->id, OB_RECALC_OB);
}
@@ -112,6 +115,7 @@ void ED_rigidbody_constraint_remove(Scene *scene, Object *ob)
static int rigidbody_con_add_exec(bContext *C, wmOperator *op)
{
+ Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
RigidBodyWorld *rbw = BKE_rigidbody_get_world(scene);
Object *ob = (scene) ? OBACT : NULL;
@@ -124,7 +128,7 @@ static int rigidbody_con_add_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
/* apply to active object */
- changed = ED_rigidbody_constraint_add(scene, ob, type, op->reports);
+ changed = ED_rigidbody_constraint_add(bmain, scene, ob, type, op->reports);
if (changed) {
/* send updates */
@@ -160,6 +164,7 @@ void RIGIDBODY_OT_constraint_add(wmOperatorType *ot)
static int rigidbody_con_remove_exec(bContext *C, wmOperator *op)
{
+ Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
Object *ob = (scene) ? OBACT : NULL;
@@ -173,7 +178,7 @@ static int rigidbody_con_remove_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
else {
- ED_rigidbody_constraint_remove(scene, ob);
+ ED_rigidbody_constraint_remove(bmain, scene, ob);
}
/* send updates */
diff --git a/source/blender/editors/physics/rigidbody_object.c b/source/blender/editors/physics/rigidbody_object.c
index 26d8af82b2d..30597d95497 100644
--- a/source/blender/editors/physics/rigidbody_object.c
+++ b/source/blender/editors/physics/rigidbody_object.c
@@ -46,6 +46,7 @@
#include "BKE_depsgraph.h"
#include "BKE_global.h"
#include "BKE_group.h"
+#include "BKE_main.h"
#include "BKE_report.h"
#include "BKE_rigidbody.h"
@@ -87,7 +88,7 @@ static int ED_operator_rigidbody_add_poll(bContext *C)
/* ----------------- */
-bool ED_rigidbody_object_add(Scene *scene, Object *ob, int type, ReportList *reports)
+bool ED_rigidbody_object_add(Main *bmain, Scene *scene, Object *ob, int type, ReportList *reports)
{
RigidBodyWorld *rbw = BKE_rigidbody_get_world(scene);
@@ -107,7 +108,7 @@ bool ED_rigidbody_object_add(Scene *scene, Object *ob, int type, ReportList *rep
scene->rigidbody_world = rbw;
}
if (rbw->group == NULL) {
- rbw->group = BKE_group_add(G.main, "RigidBodyWorld");
+ rbw->group = BKE_group_add(bmain, "RigidBodyWorld");
}
/* make rigidbody object settings */
@@ -120,12 +121,13 @@ bool ED_rigidbody_object_add(Scene *scene, Object *ob, int type, ReportList *rep
/* add object to rigid body group */
BKE_group_object_add(rbw->group, ob, scene, NULL);
+ DAG_relations_tag_update(bmain);
DAG_id_tag_update(&ob->id, OB_RECALC_OB);
return true;
}
-void ED_rigidbody_object_remove(Scene *scene, Object *ob)
+void ED_rigidbody_object_remove(Main *bmain, Scene *scene, Object *ob)
{
RigidBodyWorld *rbw = BKE_rigidbody_get_world(scene);
@@ -133,6 +135,7 @@ void ED_rigidbody_object_remove(Scene *scene, Object *ob)
if (rbw)
BKE_group_object_unlink(rbw->group, ob, scene, NULL);
+ DAG_relations_tag_update(bmain);
DAG_id_tag_update(&ob->id, OB_RECALC_OB);
}
@@ -143,13 +146,14 @@ void ED_rigidbody_object_remove(Scene *scene, Object *ob)
static int rigidbody_object_add_exec(bContext *C, wmOperator *op)
{
+ Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
Object *ob = ED_object_active_context(C);
int type = RNA_enum_get(op->ptr, "type");
bool changed;
/* apply to active object */
- changed = ED_rigidbody_object_add(scene, ob, type, op->reports);
+ changed = ED_rigidbody_object_add(bmain, scene, ob, type, op->reports);
if (changed) {
/* send updates */
@@ -186,13 +190,14 @@ void RIGIDBODY_OT_object_add(wmOperatorType *ot)
static int rigidbody_object_remove_exec(bContext *C, wmOperator *op)
{
+ Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
Object *ob = ED_object_active_context(C);
bool changed = false;
/* apply to active object */
if (!ELEM(NULL, ob, ob->rigidbody_object)) {
- ED_rigidbody_object_remove(scene, ob);
+ ED_rigidbody_object_remove(bmain, scene, ob);
changed = true;
}
@@ -232,13 +237,14 @@ void RIGIDBODY_OT_object_remove(wmOperatorType *ot)
static int rigidbody_objects_add_exec(bContext *C, wmOperator *op)
{
+ Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
int type = RNA_enum_get(op->ptr, "type");
bool changed = false;
/* create rigid body objects and add them to the world's group */
CTX_DATA_BEGIN(C, Object *, ob, selected_objects) {
- changed |= ED_rigidbody_object_add(scene, ob, type, op->reports);
+ changed |= ED_rigidbody_object_add(bmain, scene, ob, type, op->reports);
}
CTX_DATA_END;
@@ -277,6 +283,7 @@ void RIGIDBODY_OT_objects_add(wmOperatorType *ot)
static int rigidbody_objects_remove_exec(bContext *C, wmOperator *UNUSED(op))
{
+ Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
bool changed = false;
@@ -284,7 +291,7 @@ static int rigidbody_objects_remove_exec(bContext *C, wmOperator *UNUSED(op))
CTX_DATA_BEGIN(C, Object *, ob, selected_objects)
{
if (ob->rigidbody_object) {
- ED_rigidbody_object_remove(scene, ob);
+ ED_rigidbody_object_remove(bmain, scene, ob);
changed = true;
}
}
diff --git a/source/blender/editors/screen/glutil.c b/source/blender/editors/screen/glutil.c
index cbf87062955..014268262c4 100644
--- a/source/blender/editors/screen/glutil.c
+++ b/source/blender/editors/screen/glutil.c
@@ -579,6 +579,10 @@ void glaDrawPixelsSafe(float x, float y, int img_w, int img_h, int row_w, int fo
draw_h = min_ii(img_h - off_y, ceil((scissor[3] - rast_y) / yzoom));
if (draw_w > 0 && draw_h > 0) {
+
+ int bound_options;
+ GPU_BASIC_SHADER_DISABLE_AND_STORE(bound_options);
+
/* Don't use safe RasterPos (slower) if we can avoid it. */
if (rast_x >= 0 && rast_y >= 0) {
glRasterPos2f(rast_x, rast_y);
@@ -610,6 +614,8 @@ void glaDrawPixelsSafe(float x, float y, int img_w, int img_h, int row_w, int fo
}
glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
+
+ GPU_BASIC_SHADER_ENABLE_AND_RESTORE(bound_options);
}
}
diff --git a/source/blender/editors/screen/screen_edit.c b/source/blender/editors/screen/screen_edit.c
index 23c6aa37a83..a459f982ada 100644
--- a/source/blender/editors/screen/screen_edit.c
+++ b/source/blender/editors/screen/screen_edit.c
@@ -2070,7 +2070,10 @@ void ED_screen_animation_timer(bContext *C, int redraws, int refresh, int sync,
sad->refresh = refresh;
sad->flag |= (enable < 0) ? ANIMPLAY_FLAG_REVERSE : 0;
sad->flag |= (sync == 0) ? ANIMPLAY_FLAG_NO_SYNC : (sync == 1) ? ANIMPLAY_FLAG_SYNC : 0;
-
+
+ ScrArea *sa = CTX_wm_area(C);
+ sad->from_anim_edit = (ELEM(sa->spacetype, SPACE_IPO, SPACE_ACTION, SPACE_NLA, SPACE_TIME));
+
screen->animtimer->customdata = sad;
}
diff --git a/source/blender/editors/screen/screen_ops.c b/source/blender/editors/screen/screen_ops.c
index 4111f67553a..f340f716ccb 100644
--- a/source/blender/editors/screen/screen_ops.c
+++ b/source/blender/editors/screen/screen_ops.c
@@ -3355,24 +3355,24 @@ static int match_area_with_refresh(int spacetype, int refresh)
return 0;
}
-static int match_region_with_redraws(int spacetype, int regiontype, int redraws)
+static int match_region_with_redraws(int spacetype, int regiontype, int redraws, bool from_anim_edit)
{
if (regiontype == RGN_TYPE_WINDOW) {
switch (spacetype) {
case SPACE_VIEW3D:
- if (redraws & TIME_ALL_3D_WIN)
+ if ((redraws & TIME_ALL_3D_WIN) || from_anim_edit)
return 1;
break;
case SPACE_IPO:
case SPACE_ACTION:
case SPACE_NLA:
- if (redraws & TIME_ALL_ANIM_WIN)
+ if ((redraws & TIME_ALL_ANIM_WIN) || from_anim_edit)
return 1;
break;
case SPACE_TIME:
/* if only 1 window or 3d windows, we do timeline too */
- if (redraws & (TIME_ALL_ANIM_WIN | TIME_REGION | TIME_ALL_3D_WIN))
+ if ((redraws & (TIME_ALL_ANIM_WIN | TIME_REGION | TIME_ALL_3D_WIN)) || from_anim_edit)
return 1;
break;
case SPACE_BUTS:
@@ -3380,7 +3380,7 @@ static int match_region_with_redraws(int spacetype, int regiontype, int redraws)
return 1;
break;
case SPACE_SEQ:
- if (redraws & (TIME_SEQ | TIME_ALL_ANIM_WIN))
+ if ((redraws & (TIME_SEQ | TIME_ALL_ANIM_WIN)) || from_anim_edit)
return 1;
break;
case SPACE_NODE:
@@ -3388,11 +3388,11 @@ static int match_region_with_redraws(int spacetype, int regiontype, int redraws)
return 1;
break;
case SPACE_IMAGE:
- if (redraws & TIME_ALL_IMAGE_WIN)
+ if ((redraws & TIME_ALL_IMAGE_WIN) || from_anim_edit)
return 1;
break;
case SPACE_CLIP:
- if (redraws & TIME_CLIPS)
+ if ((redraws & TIME_CLIPS) || from_anim_edit)
return 1;
break;
@@ -3572,7 +3572,7 @@ static int screen_animation_step(bContext *C, wmOperator *UNUSED(op), const wmEv
if (ar == sad->ar) {
redraw = true;
}
- else if (match_region_with_redraws(sa->spacetype, ar->regiontype, sad->redraws)) {
+ else if (match_region_with_redraws(sa->spacetype, ar->regiontype, sad->redraws, sad->from_anim_edit)) {
redraw = true;
}
diff --git a/source/blender/editors/sculpt_paint/paint_cursor.c b/source/blender/editors/sculpt_paint/paint_cursor.c
index e4e9976c10d..eba9448aa40 100644
--- a/source/blender/editors/sculpt_paint/paint_cursor.c
+++ b/source/blender/editors/sculpt_paint/paint_cursor.c
@@ -1016,7 +1016,7 @@ static void paint_draw_cursor(bContext *C, int x, int y, void *UNUSED(unused))
translation[1] = y;
outline_alpha = 0.5;
outline_col = brush->add_col;
- final_radius = BKE_brush_size_get(scene, brush) * zoomx;
+ final_radius = (BKE_brush_size_get(scene, brush) * zoomx) / U.pixelsize;
/* don't calculate rake angles while a stroke is active because the rake variables are global and
* we may get interference with the stroke itself. For line strokes, such interference is visible */
diff --git a/source/blender/editors/space_action/action_edit.c b/source/blender/editors/space_action/action_edit.c
index c0947dacbf0..8261a211ed0 100644
--- a/source/blender/editors/space_action/action_edit.c
+++ b/source/blender/editors/space_action/action_edit.c
@@ -707,10 +707,13 @@ static void insert_action_keys(bAnimContext *ac, short mode)
* so it's easier for now to just read the F-Curve directly.
* (TODO: add the full-blown PointerRNA relative parsing case here...)
*/
- if (ale->id && !ale->owner)
+ if (ale->id && !ale->owner) {
insert_keyframe(reports, ale->id, NULL, ((fcu->grp) ? (fcu->grp->name) : (NULL)), fcu->rna_path, fcu->array_index, cfra, ts->keyframe_type, flag);
- else
- insert_vert_fcurve(fcu, cfra, fcu->curval, ts->keyframe_type, 0);
+ }
+ else {
+ const float curval = evaluate_fcurve(fcu, cfra);
+ insert_vert_fcurve(fcu, cfra, curval, ts->keyframe_type, 0);
+ }
ale->update |= ANIM_UPDATE_DEFAULT;
}
diff --git a/source/blender/editors/space_graph/graph_edit.c b/source/blender/editors/space_graph/graph_edit.c
index f1063996ca3..f38d36853d7 100644
--- a/source/blender/editors/space_graph/graph_edit.c
+++ b/source/blender/editors/space_graph/graph_edit.c
@@ -606,10 +606,13 @@ static void insert_graph_keys(bAnimContext *ac, eGraphKeys_InsertKey_Types mode)
* - fcu->driver != NULL: If this is set, then it's a driver. If we don't check for this, we'd end
* up adding the keyframes on a new F-Curve in the action data instead.
*/
- if (ale->id && !ale->owner && !fcu->driver)
+ if (ale->id && !ale->owner && !fcu->driver) {
insert_keyframe(reports, ale->id, NULL, ((fcu->grp) ? (fcu->grp->name) : (NULL)), fcu->rna_path, fcu->array_index, cfra, ts->keyframe_type, flag);
- else
- insert_vert_fcurve(fcu, cfra, fcu->curval, ts->keyframe_type, 0);
+ }
+ else {
+ const float curval = evaluate_fcurve(fcu, cfra);
+ insert_vert_fcurve(fcu, cfra, curval, ts->keyframe_type, 0);
+ }
ale->update |= ANIM_UPDATE_DEFAULT;
}
diff --git a/source/blender/editors/space_sequencer/CMakeLists.txt b/source/blender/editors/space_sequencer/CMakeLists.txt
index 778ccf902d1..6dce962ee02 100644
--- a/source/blender/editors/space_sequencer/CMakeLists.txt
+++ b/source/blender/editors/space_sequencer/CMakeLists.txt
@@ -28,6 +28,7 @@ set(INC
../../makesdna
../../makesrna
../../windowmanager
+ ../../../../intern/atomic
../../../../intern/guardedalloc
../../../../intern/glew-mx
)
diff --git a/source/blender/editors/space_sequencer/sequencer_scopes.c b/source/blender/editors/space_sequencer/sequencer_scopes.c
index c197aabedfd..80cb42c0b3d 100644
--- a/source/blender/editors/space_sequencer/sequencer_scopes.c
+++ b/source/blender/editors/space_sequencer/sequencer_scopes.c
@@ -30,11 +30,14 @@
#include <string.h>
#include "BLI_utildefines.h"
+#include "BLI_task.h"
#include "IMB_colormanagement.h"
#include "IMB_imbuf_types.h"
#include "IMB_imbuf.h"
+#include "atomic_ops.h"
+
#include "sequencer_intern.h"
/* XXX, why is this function better then BLI_math version?
@@ -450,41 +453,57 @@ static void draw_histogram_bar(ImBuf *ibuf, int x, float val, int col)
#define HIS_STEPS 512
-static ImBuf *make_histogram_view_from_ibuf_byte(ImBuf *ibuf)
+typedef struct MakeHistogramViewData {
+ const ImBuf *ibuf;
+ uint32_t (*bins)[HIS_STEPS];
+} MakeHistogramViewData;
+
+static void make_histogram_view_from_ibuf_byte_cb_ex(
+ void *userdata, void *userdata_chunk, const int y, const int UNUSED(threadid))
{
- ImBuf *rval = IMB_allocImBuf(515, 128, 32, IB_rect);
- int x, y;
- unsigned int nr, ng, nb;
+ MakeHistogramViewData *data = userdata;
+ const ImBuf *ibuf = data->ibuf;
const unsigned char *src = (unsigned char *)ibuf->rect;
- unsigned int bins[3][HIS_STEPS];
-
- memset(bins, 0, sizeof(bins));
+ uint32_t (*cur_bins)[HIS_STEPS] = userdata_chunk;
-#pragma omp parallel for shared(bins, src, ibuf) private(x, y) if (ibuf->y >= 256)
- for (y = 0; y < ibuf->y; y++) {
- unsigned int cur_bins[3][HIS_STEPS];
+ for (int x = 0; x < ibuf->x; x++) {
+ const unsigned char *pixel = src + (y * ibuf->x + x) * 4;
- memset(cur_bins, 0, sizeof(cur_bins));
+ for (int j = 3; j--;) {
+ cur_bins[j][pixel[j]]++;
+ }
+ }
+}
- for (x = 0; x < ibuf->x; x++) {
- const unsigned char *pixel = src + (y * ibuf->x + x) * 4;
+static void make_histogram_view_from_ibuf_finalize(void *userdata, void *userdata_chunk)
+{
+ MakeHistogramViewData *data = userdata;
+ uint32_t (*bins)[HIS_STEPS] = data->bins;
- cur_bins[0][pixel[0]]++;
- cur_bins[1][pixel[1]]++;
- cur_bins[2][pixel[2]]++;
- }
+ uint32_t (*cur_bins)[HIS_STEPS] = userdata_chunk;
-#pragma omp critical
- {
- int i;
- for (i = 0; i < HIS_STEPS; i++) {
- bins[0][i] += cur_bins[0][i];
- bins[1][i] += cur_bins[1][i];
- bins[2][i] += cur_bins[2][i];
- }
+ for (int j = 3; j--;) {
+ for (int i = 0; i < HIS_STEPS; i++) {
+ bins[j][i] += cur_bins[j][i];
}
}
+}
+
+static ImBuf *make_histogram_view_from_ibuf_byte(ImBuf *ibuf)
+{
+ ImBuf *rval = IMB_allocImBuf(515, 128, 32, IB_rect);
+ int x;
+ unsigned int nr, ng, nb;
+
+ unsigned int bins[3][HIS_STEPS];
+
+ memset(bins, 0, sizeof(bins));
+
+ MakeHistogramViewData data = {.ibuf = ibuf, .bins = bins};
+ BLI_task_parallel_range_finalize(
+ 0, ibuf->y, &data, bins, sizeof(bins), make_histogram_view_from_ibuf_byte_cb_ex,
+ make_histogram_view_from_ibuf_finalize, ibuf->y >= 256, false);
nr = nb = ng = 0;
for (x = 0; x < HIS_STEPS; x++) {
@@ -528,40 +547,38 @@ BLI_INLINE int get_bin_float(float f)
return (int) (((f + 0.25f) / 1.5f) * 512);
}
-static ImBuf *make_histogram_view_from_ibuf_float(ImBuf *ibuf)
+static void make_histogram_view_from_ibuf_float_cb_ex(
+ void *userdata, void *userdata_chunk, const int y, const int UNUSED(threadid))
{
- ImBuf *rval = IMB_allocImBuf(515, 128, 32, IB_rect);
- int nr, ng, nb, x, y;
+ const MakeHistogramViewData *data = userdata;
+ const ImBuf *ibuf = data->ibuf;
const float *src = ibuf->rect_float;
- unsigned int bins[3][HIS_STEPS];
+ uint32_t (*cur_bins)[HIS_STEPS] = userdata_chunk;
- memset(bins, 0, sizeof(bins));
+ for (int x = 0; x < ibuf->x; x++) {
+ const float *pixel = src + (y * ibuf->x + x) * 4;
-#pragma omp parallel for shared(bins, src, ibuf) private(x, y) if (ibuf->y >= 256)
- for (y = 0; y < ibuf->y; y++) {
- unsigned int cur_bins[3][HIS_STEPS];
+ for (int j = 3; j--;) {
+ cur_bins[j][get_bin_float(pixel[j])]++;
+ }
+ }
+}
- memset(cur_bins, 0, sizeof(cur_bins));
+static ImBuf *make_histogram_view_from_ibuf_float(ImBuf *ibuf)
+{
+ ImBuf *rval = IMB_allocImBuf(515, 128, 32, IB_rect);
+ int nr, ng, nb;
+ int x;
- for (x = 0; x < ibuf->x; x++) {
- const float *pixel = src + (y * ibuf->x + x) * 4;
+ unsigned int bins[3][HIS_STEPS];
- cur_bins[0][get_bin_float(pixel[0])]++;
- cur_bins[1][get_bin_float(pixel[1])]++;
- cur_bins[2][get_bin_float(pixel[2])]++;
- }
+ memset(bins, 0, sizeof(bins));
-#pragma omp critical
- {
- int i;
- for (i = 0; i < HIS_STEPS; i++) {
- bins[0][i] += cur_bins[0][i];
- bins[1][i] += cur_bins[1][i];
- bins[2][i] += cur_bins[2][i];
- }
- }
- }
+ MakeHistogramViewData data = {.ibuf = ibuf, .bins = bins};
+ BLI_task_parallel_range_finalize(
+ 0, ibuf->y, &data, bins, sizeof(bins), make_histogram_view_from_ibuf_float_cb_ex,
+ make_histogram_view_from_ibuf_finalize, ibuf->y >= 256, false);
nr = nb = ng = 0;
for (x = 0; x < HIS_STEPS; x++) {
diff --git a/source/blender/editors/space_sequencer/sequencer_select.c b/source/blender/editors/space_sequencer/sequencer_select.c
index 3c2a66cd3af..7475e8b27fd 100644
--- a/source/blender/editors/space_sequencer/sequencer_select.c
+++ b/source/blender/editors/space_sequencer/sequencer_select.c
@@ -107,6 +107,7 @@ static void select_active_side(ListBase *seqbase, int sel_side, int channel, int
break;
case SEQ_SIDE_BOTH:
seq->flag &= ~(SEQ_RIGHTSEL | SEQ_LEFTSEL);
+ seq->flag |= SELECT;
break;
}
}
@@ -812,7 +813,7 @@ static int sequencer_select_handles_exec(bContext *C, wmOperator *op)
seq->flag |= SEQ_RIGHTSEL;
break;
case SEQ_SIDE_BOTH:
- seq->flag |= SEQ_LEFTSEL + SEQ_RIGHTSEL;
+ seq->flag |= SEQ_LEFTSEL | SEQ_RIGHTSEL;
break;
}
}
diff --git a/source/blender/editors/space_view3d/view3d_draw.c b/source/blender/editors/space_view3d/view3d_draw.c
index 01e23f26568..445a4cbdfd6 100644
--- a/source/blender/editors/space_view3d/view3d_draw.c
+++ b/source/blender/editors/space_view3d/view3d_draw.c
@@ -1179,10 +1179,10 @@ static void drawviewborder(Scene *scene, ARegion *ar, View3D *v3d)
if (scene->r.mode & R_BORDER) {
float x3, y3, x4, y4;
- x3 = x1i + 1 + roundf(scene->r.border.xmin * (x2 - x1));
- y3 = y1i + 1 + roundf(scene->r.border.ymin * (y2 - y1));
- x4 = x1i + 1 + roundf(scene->r.border.xmax * (x2 - x1));
- y4 = y1i + 1 + roundf(scene->r.border.ymax * (y2 - y1));
+ x3 = floorf(x1 + (scene->r.border.xmin * (x2 - x1))) - 1;
+ y3 = floorf(y1 + (scene->r.border.ymin * (y2 - y1))) - 1;
+ x4 = floorf(x1 + (scene->r.border.xmax * (x2 - x1))) + (U.pixelsize - 1);
+ y4 = floorf(y1 + (scene->r.border.ymax * (y2 - y1))) + (U.pixelsize - 1);
cpack(0x4040FF);
sdrawbox(x3, y3, x4, y4);
diff --git a/source/blender/editors/space_view3d/view3d_ruler.c b/source/blender/editors/space_view3d/view3d_ruler.c
index dfa76753f64..c6951c79609 100644
--- a/source/blender/editors/space_view3d/view3d_ruler.c
+++ b/source/blender/editors/space_view3d/view3d_ruler.c
@@ -679,9 +679,10 @@ static bool view3d_ruler_item_mousemove(
if (ED_transform_snap_object_project_view3d_mixed(
ruler_info->snap_context,
+ SCE_SELECT_FACE,
&(const struct SnapObjectParams){
.snap_select = SNAP_ALL,
- .snap_to_flag = SCE_SELECT_FACE,
+ .use_object_edit_cage = true,
},
mval_fl, &dist_px, true,
co, ray_normal))
@@ -691,6 +692,10 @@ static bool view3d_ruler_item_mousemove(
madd_v3_v3v3fl(ray_start, co, ray_normal, eps_bias);
ED_transform_snap_object_project_ray(
ruler_info->snap_context,
+ &(const struct SnapObjectParams){
+ .snap_select = SNAP_ALL,
+ .use_object_edit_cage = true,
+ },
ray_start, ray_normal, NULL,
co_other, NULL);
}
@@ -703,9 +708,10 @@ static bool view3d_ruler_item_mousemove(
if (ED_transform_snap_object_project_view3d_mixed(
ruler_info->snap_context,
+ (SCE_SELECT_VERTEX | SCE_SELECT_EDGE) | (use_depth ? SCE_SELECT_FACE : 0),
&(const struct SnapObjectParams){
.snap_select = SNAP_ALL,
- .snap_to_flag = (SCE_SELECT_VERTEX | SCE_SELECT_EDGE) | (use_depth ? SCE_SELECT_FACE : 0),
+ .use_object_edit_cage = true,
},
mval_fl, &dist_px, use_depth,
co, NULL))
diff --git a/source/blender/editors/space_view3d/view3d_walk.c b/source/blender/editors/space_view3d/view3d_walk.c
index 47f81678699..384da277612 100644
--- a/source/blender/editors/space_view3d/view3d_walk.c
+++ b/source/blender/editors/space_view3d/view3d_walk.c
@@ -49,6 +49,7 @@
#include "ED_screen.h"
#include "ED_space_api.h"
+#include "ED_transform.h"
#include "ED_transform_snap_object_context.h"
#include "PIL_time.h" /* smoothview */
@@ -424,6 +425,9 @@ static bool walk_floor_distance_get(
ret = ED_transform_snap_object_project_ray(
walk->snap_context,
+ &(const struct SnapObjectParams){
+ .snap_select = SNAP_ALL,
+ },
ray_start, ray_normal, r_distance,
r_location, r_normal_dummy);
@@ -455,6 +459,9 @@ static bool walk_ray_cast(
ret = ED_transform_snap_object_project_ray(
walk->snap_context,
+ &(const struct SnapObjectParams){
+ .snap_select = SNAP_ALL,
+ },
ray_start, ray_normal, NULL,
r_location, r_normal);
diff --git a/source/blender/editors/transform/transform.c b/source/blender/editors/transform/transform.c
index 5c0c0bcd6c1..5b1a58497f0 100644
--- a/source/blender/editors/transform/transform.c
+++ b/source/blender/editors/transform/transform.c
@@ -2863,7 +2863,7 @@ static void initBend(TransInfo *t)
//copy_v3_v3(t->center, ED_view3d_cursor3d_get(t->scene, t->view));
calculateCenterCursor(t, t->center);
- calculateCenterGlobal(t);
+ calculateCenterGlobal(t, t->center, t->center_global);
t->val = 0.0f;
diff --git a/source/blender/editors/transform/transform.h b/source/blender/editors/transform/transform.h
index 11151a9c65a..0e0d085bf6f 100644
--- a/source/blender/editors/transform/transform.h
+++ b/source/blender/editors/transform/transform.h
@@ -369,6 +369,11 @@ typedef struct TransCustomData {
unsigned int use_free : 1;
} TransCustomData;
+typedef struct TransCenterData {
+ float local[3], global[3];
+ unsigned int is_set : 1;
+} TransCenterData;
+
typedef struct TransInfo {
int mode; /* current mode */
int flag; /* generic flags for special behaviors */
@@ -396,6 +401,9 @@ typedef struct TransInfo {
float center[3]; /* center of transformation (in local-space) */
float center_global[3]; /* center of transformation (in global-space) */
float center2d[2]; /* center in screen coordinates */
+ /* Lazy initialize center data for when we need other center values.
+ * V3D_AROUND_ACTIVE + 1 (static assert checks this) */
+ TransCenterData center_cache[5];
short idx_max; /* maximum index on the input vector */
float snap[3]; /* Snapping Gears */
float snap_spatial[3]; /* Spatial snapping gears(even when rotating, scaling... etc) */
@@ -742,8 +750,11 @@ void restoreTransObjects(TransInfo *t);
void recalcData(TransInfo *t);
void calculateCenter2D(TransInfo *t);
-void calculateCenterGlobal(TransInfo *t);
+void calculateCenterGlobal(
+ TransInfo *t, const float center_local[3],
+ float r_center_global[3]);
+const TransCenterData *transformCenter_from_type(TransInfo *t, int around);
void calculateCenter(TransInfo *t);
/* API functions for getting center points */
diff --git a/source/blender/editors/transform/transform_generics.c b/source/blender/editors/transform/transform_generics.c
index ed6477392d8..67740644afe 100644
--- a/source/blender/editors/transform/transform_generics.c
+++ b/source/blender/editors/transform/transform_generics.c
@@ -1610,16 +1610,18 @@ void calculateCenter2D(TransInfo *t)
}
}
-void calculateCenterGlobal(TransInfo *t)
+void calculateCenterGlobal(
+ TransInfo *t, const float center_local[3],
+ float r_center_global[3])
{
/* setting constraint center */
/* note, init functions may over-ride t->center */
if (t->flag & (T_EDIT | T_POSE)) {
Object *ob = t->obedit ? t->obedit : t->poseobj;
- mul_v3_m4v3(t->center_global, ob->obmat, t->center);
+ mul_v3_m4v3(r_center_global, ob->obmat, center_local);
}
else {
- copy_v3_v3(t->center_global, t->center);
+ copy_v3_v3(r_center_global, center_local);
}
}
@@ -1794,43 +1796,55 @@ bool calculateCenterActive(TransInfo *t, bool select_only, float r_center[3])
return ok;
}
-
-void calculateCenter(TransInfo *t)
+static void calculateCenter_FromAround(TransInfo *t, int around, float r_center[3])
{
- switch (t->around) {
+ switch (around) {
case V3D_AROUND_CENTER_BOUNDS:
- calculateCenterBound(t, t->center);
+ calculateCenterBound(t, r_center);
break;
case V3D_AROUND_CENTER_MEAN:
- calculateCenterMedian(t, t->center);
+ calculateCenterMedian(t, r_center);
break;
case V3D_AROUND_CURSOR:
if (ELEM(t->spacetype, SPACE_IMAGE, SPACE_CLIP))
- calculateCenterCursor2D(t, t->center);
+ calculateCenterCursor2D(t, r_center);
else if (t->spacetype == SPACE_IPO)
- calculateCenterCursorGraph2D(t, t->center);
+ calculateCenterCursorGraph2D(t, r_center);
else
- calculateCenterCursor(t, t->center);
+ calculateCenterCursor(t, r_center);
break;
case V3D_AROUND_LOCAL_ORIGINS:
/* Individual element center uses median center for helpline and such */
- calculateCenterMedian(t, t->center);
+ calculateCenterMedian(t, r_center);
break;
case V3D_AROUND_ACTIVE:
{
- if (calculateCenterActive(t, false, t->center)) {
+ if (calculateCenterActive(t, false, r_center)) {
/* pass */
}
else {
/* fallback */
- calculateCenterMedian(t, t->center);
+ calculateCenterMedian(t, r_center);
}
break;
}
}
+}
+
+void calculateCenter(TransInfo *t)
+{
+ calculateCenter_FromAround(t, t->around, t->center);
+ calculateCenterGlobal(t, t->center, t->center_global);
+
+ /* avoid calculating again */
+ {
+ TransCenterData *cd = &t->center_cache[t->around];
+ copy_v3_v3(cd->local, t->center);
+ copy_v3_v3(cd->global, t->center_global);
+ cd->is_set = true;
+ }
calculateCenter2D(t);
- calculateCenterGlobal(t);
/* for panning from cameraview */
if (t->flag & T_OBJECT) {
@@ -1884,6 +1898,23 @@ void calculateCenter(TransInfo *t)
}
}
+BLI_STATIC_ASSERT(ARRAY_SIZE(((TransInfo *)NULL)->center_cache) == (V3D_AROUND_ACTIVE + 1), "test size");
+
+/**
+ * Lazy initialize transform center data, when we need to access center values from other types.
+ */
+const TransCenterData *transformCenter_from_type(TransInfo *t, int around)
+{
+ BLI_assert(around <= V3D_AROUND_ACTIVE);
+ TransCenterData *cd = &t->center_cache[around];
+ if (cd->is_set == false) {
+ calculateCenter_FromAround(t, around, cd->local);
+ calculateCenterGlobal(t, cd->local, cd->global);
+ cd->is_set = true;
+ }
+ return cd;
+}
+
void calculatePropRatio(TransInfo *t)
{
TransData *td = t->data;
diff --git a/source/blender/editors/transform/transform_snap.c b/source/blender/editors/transform/transform_snap.c
index 38f1d37acd6..e1cf7436236 100644
--- a/source/blender/editors/transform/transform_snap.c
+++ b/source/blender/editors/transform/transform_snap.c
@@ -324,7 +324,7 @@ void applyProject(TransInfo *t)
if (ED_view3d_project_float_global(t->ar, iloc, mval_fl, V3D_PROJ_TEST_NOP) == V3D_PROJ_RET_OK) {
if (snapObjectsTransform(
- t, mval_fl, t->tsnap.modeSelect, &dist_px,
+ t, mval_fl, &dist_px,
loc, no))
{
// if (t->flag & (T_EDIT|T_POSE)) {
@@ -553,10 +553,10 @@ static void initSnappingMode(TransInfo *t)
{
/* Exclude editmesh if using proportional edit */
if ((obedit->type == OB_MESH) && (t->flag & T_PROP_EDIT)) {
- t->tsnap.modeSelect = SNAP_NOT_OBEDIT;
+ t->tsnap.modeSelect = SNAP_NOT_ACTIVE;
}
else {
- t->tsnap.modeSelect = t->tsnap.snap_self ? SNAP_ALL : SNAP_NOT_OBEDIT;
+ t->tsnap.modeSelect = t->tsnap.snap_self ? SNAP_ALL : SNAP_NOT_ACTIVE;
}
}
/* Particles edit mode*/
@@ -964,14 +964,14 @@ static void CalcSnapGeometry(TransInfo *t, float *UNUSED(vec))
if (t->tsnap.mode == SCE_SNAP_MODE_VOLUME) {
found = peelObjectsTransform(
- t, mval, t->tsnap.modeSelect,
+ t, mval,
(t->settings->snap_flag & SCE_SNAP_PEEL_OBJECT) != 0,
loc, no, NULL);
}
else {
zero_v3(no); /* objects won't set this */
found = snapObjectsTransform(
- t, mval, t->tsnap.modeSelect, &dist_px,
+ t, mval, &dist_px,
loc, no);
}
@@ -1207,17 +1207,16 @@ static void TargetSnapClosest(TransInfo *t)
}
bool snapObjectsTransform(
- TransInfo *t, const float mval[2], SnapSelect snap_select,
+ TransInfo *t, const float mval[2],
float *dist_px,
float r_loc[3], float r_no[3])
{
return ED_transform_snap_object_project_view3d_ex(
t->tsnap.object_context,
+ t->scene->toolsettings->snap_mode,
&(const struct SnapObjectParams){
- .snap_select = snap_select,
- .snap_to = t->scene->toolsettings->snap_mode,
- .use_object_edit = (t->flag & T_EDIT) != 0,
- .use_object_active = (t->options & CTX_GPENCIL_STROKES) == 0,
+ .snap_select = ((t->options & CTX_GPENCIL_STROKES) != 0) ? SNAP_NOT_ACTIVE : t->tsnap.modeSelect,
+ .use_object_edit_cage = (t->flag & T_EDIT) != 0,
},
mval, dist_px, NULL,
r_loc, r_no, NULL);
@@ -1228,18 +1227,16 @@ bool snapObjectsTransform(
bool peelObjectsSnapContext(
SnapObjectContext *sctx,
- const float mval[2], SnapSelect snap_select, bool use_peel_object,
+ const float mval[2],
+ const struct SnapObjectParams *params,
+ const bool use_peel_object,
/* return args */
float r_loc[3], float r_no[3], float *r_thickness)
{
ListBase depths_peel = {0};
ED_transform_snap_object_project_all_view3d_ex(
sctx,
- &(const struct SnapObjectParams){
- .snap_to = SCE_SNAP_MODE_FACE,
- .snap_select = snap_select,
- .use_object_edit = true,
- },
+ params,
mval, -1.0f, false,
&depths_peel);
@@ -1299,13 +1296,19 @@ bool peelObjectsSnapContext(
bool peelObjectsTransform(
TransInfo *t,
- const float mval[2], SnapSelect snap_select, bool use_peel_object,
+ const float mval[2],
+ const bool use_peel_object,
/* return args */
float r_loc[3], float r_no[3], float *r_thickness)
{
return peelObjectsSnapContext(
t->tsnap.object_context,
- mval, snap_select, use_peel_object,
+ mval,
+ &(const struct SnapObjectParams){
+ .snap_select = ((t->options & CTX_GPENCIL_STROKES) != 0) ? SNAP_NOT_ACTIVE : t->tsnap.modeSelect,
+ .use_object_edit_cage = (t->flag & T_EDIT) != 0,
+ },
+ use_peel_object,
r_loc, r_no, r_thickness);
}
@@ -1520,11 +1523,21 @@ static void applyGridIncrement(TransInfo *t, float *val, int max_index, const fl
/* absolute snapping on grid based on global center */
if ((t->tsnap.snap_spatial_grid) && (t->mode == TFM_TRANSLATION)) {
+ const float *center_global = t->center_global;
+
+ /* use a fallback for cursor selection,
+ * this isn't useful as a global center for absolute grid snapping
+ * since its not based on the position of the selection. */
+ if (t->around == V3D_AROUND_CURSOR) {
+ const TransCenterData *cd = transformCenter_from_type(t, V3D_AROUND_CENTER_MEAN);
+ center_global = cd->global;
+ }
+
for (i = 0; i <= max_index; i++) {
/* do not let unconstrained axis jump to absolute grid increments */
if (!(t->con.mode & CON_APPLY) || t->con.mode & (CON_AXIS0 << i)) {
const float iter_fac = fac[action] * asp[i];
- val[i] = iter_fac * roundf((val[i] + t->center_global[i]) / iter_fac) - t->center_global[i];
+ val[i] = iter_fac * roundf((val[i] + center_global[i]) / iter_fac) - center_global[i];
}
}
}
diff --git a/source/blender/editors/transform/transform_snap_object.c b/source/blender/editors/transform/transform_snap_object.c
index 62ca4e515a5..d7486372c36 100644
--- a/source/blender/editors/transform/transform_snap_object.c
+++ b/source/blender/editors/transform/transform_snap_object.c
@@ -992,7 +992,7 @@ static bool snapEditMesh(
float imat[4][4];
float timat[3][3]; /* transpose inverse matrix for normals */
float ray_start_local[3], ray_normal_local[3];
- float local_scale, local_depth, len_diff;
+ float local_scale, local_depth;
invert_m4_m4(imat, obmat);
transpose_m3_m4(timat, imat);
@@ -1089,6 +1089,7 @@ static bool snapEditMesh(
* been *inside* boundbox, leading to snap failures (see T38409).
* Note also ar might be null (see T38435), in this case we assume ray_start is ok!
*/
+ float len_diff = 0.0f;
if (do_ray_start_correction) {
/* We *need* a reasonably valid len_diff in this case.
* Use BHVTree to find the closest face from ray_start_local.
@@ -1098,27 +1099,24 @@ static bool snapEditMesh(
nearest.index = -1;
nearest.dist_sq = FLT_MAX;
/* Compute and store result. */
- BLI_bvhtree_find_nearest(
- treedata->tree, ray_start_local, &nearest, treedata->nearest_callback, treedata);
- if (nearest.index != -1) {
+ if (BLI_bvhtree_find_nearest(
+ treedata->tree, ray_start_local, &nearest, treedata->nearest_callback, treedata) != -1)
+ {
len_diff = sqrtf(nearest.dist_sq);
+ float ray_org_local[3];
+
+ copy_v3_v3(ray_org_local, ray_origin);
+ mul_m4_v3(imat, ray_org_local);
+
+ /* We pass a temp ray_start, set from object's boundbox, to avoid precision issues with very far
+ * away ray_start values (as returned in case of ortho view3d), see T38358.
+ */
+ len_diff -= local_scale; /* make temp start point a bit away from bbox hit point. */
+ madd_v3_v3v3fl(ray_start_local, ray_org_local, ray_normal_local,
+ len_diff - len_v3v3(ray_start_local, ray_org_local));
+ local_depth -= len_diff;
}
}
- float ray_org_local[3];
-
- copy_v3_v3(ray_org_local, ray_origin);
- mul_m4_v3(imat, ray_org_local);
-
- /* We pass a temp ray_start, set from object's boundbox, to avoid precision issues with very far
- * away ray_start values (as returned in case of ortho view3d), see T38358.
- */
- len_diff -= local_scale; /* make temp start point a bit away from bbox hit point. */
- madd_v3_v3v3fl(ray_start_local, ray_org_local, ray_normal_local,
- len_diff - len_v3v3(ray_start_local, ray_org_local));
- local_depth -= len_diff;
- }
- else {
- len_diff = 0.0f;
}
switch (snap_to) {
@@ -1316,39 +1314,28 @@ static bool snapObject(
static bool snapObjectsRay(
SnapObjectContext *sctx,
- SnapSelect snap_select, const short snap_to,
+ const unsigned short snap_to, const SnapSelect snap_select,
+ const bool use_object_edit_cage,
const float mval[2], float *dist_px,
- /* special handling of active and edit objects */
- Base *base_act, Object *obedit,
const float ray_start[3], const float ray_normal[3], const float ray_origin[3], float *ray_depth,
/* return args */
float r_loc[3], float r_no[3], int *r_index,
Object **r_ob, float r_obmat[4][4],
ListBase *r_hit_list)
{
- Base *base;
bool retval = false;
- bool snap_obedit_first = snap_select == SNAP_ALL && obedit;
unsigned int ob_index = 0;
-
- if (snap_obedit_first) {
- Object *ob = obedit;
-
- retval |= snapObject(
- sctx, ob, ob->obmat, true, snap_to,
- mval, dist_px, ob_index++,
- ray_start, ray_normal, ray_origin, ray_depth,
- r_loc, r_no, r_index, r_ob, r_obmat, r_hit_list);
- }
+ Object *obedit = use_object_edit_cage ? sctx->scene->obedit : NULL;
/* Need an exception for particle edit because the base is flagged with BA_HAS_RECALC_DATA
* which makes the loop skip it, even the derived mesh will never change
*
* To solve that problem, we do it first as an exception.
* */
- base = base_act;
- if (base && base->object && base->object->mode & OB_MODE_PARTICLE_EDIT) {
- Object *ob = base->object;
+ Base *base_act = sctx->scene->basact;
+ if (base_act && base_act->object && base_act->object->mode & OB_MODE_PARTICLE_EDIT) {
+ Object *ob = base_act->object;
+
retval |= snapObject(
sctx, ob, ob->obmat, false, snap_to,
mval, dist_px, ob_index++,
@@ -1356,16 +1343,25 @@ static bool snapObjectsRay(
r_loc, r_no, r_index, r_ob, r_obmat, r_hit_list);
}
- for (base = sctx->scene->base.first; base != NULL; base = base->next) {
+ bool ignore_object_selected = false, ignore_object_active = false;
+ switch (snap_select) {
+ case SNAP_ALL:
+ break;
+ case SNAP_NOT_SELECTED:
+ ignore_object_selected = true;
+ break;
+ case SNAP_NOT_ACTIVE:
+ ignore_object_active = true;
+ break;
+ }
+ for (Base *base = sctx->scene->base.first; base != NULL; base = base->next) {
if ((BASE_VISIBLE_BGMODE(sctx->v3d_data.v3d, sctx->scene, base)) &&
(base->flag & (BA_HAS_RECALC_OB | BA_HAS_RECALC_DATA)) == 0 &&
- ((snap_select == SNAP_NOT_SELECTED && (base->flag & (SELECT | BA_WAS_SEL)) == 0) ||
- (ELEM(snap_select, SNAP_ALL, SNAP_NOT_OBEDIT) && base != base_act)))
+ !((ignore_object_selected && (base->flag & (SELECT | BA_WAS_SEL))) ||
+ (ignore_object_active && base == base_act)))
{
Object *ob = base->object;
- Object *ob_snap = ob;
- bool use_obedit = false;
if (ob->transflag & OB_DUPLI) {
DupliObject *dupli_ob;
@@ -1385,19 +1381,8 @@ static bool snapObjectsRay(
free_object_duplilist(lb);
}
- if (obedit) {
- if ((ob == obedit) &&
- (snap_obedit_first || (snap_select == SNAP_NOT_OBEDIT)))
- {
- continue;
- }
-
- if (ob->data == obedit->data) {
- /* for linked objects, use the same object but a different matrix */
- use_obedit = true;
- ob_snap = obedit;
- }
- }
+ bool use_obedit = (obedit != NULL) && (ob->data == obedit->data);
+ Object *ob_snap = use_obedit ? obedit : ob;
retval |= snapObject(
sctx, ob_snap, ob->obmat, use_obedit, snap_to,
@@ -1502,22 +1487,18 @@ void ED_transform_snap_object_context_set_editmesh_callbacks(
bool ED_transform_snap_object_project_ray_ex(
SnapObjectContext *sctx,
+ const unsigned short snap_to,
const struct SnapObjectParams *params,
const float ray_start[3], const float ray_normal[3], float *ray_depth,
float r_loc[3], float r_no[3], int *r_index,
Object **r_ob, float r_obmat[4][4])
{
- Base *base_act = params->use_object_active ? sctx->scene->basact : NULL;
- Object *obedit = params->use_object_edit ? sctx->scene->obedit : NULL;
-
return snapObjectsRay(
sctx,
- params->snap_select, params->snap_to,
+ snap_to, params->snap_select, params->use_object_edit_cage,
NULL, NULL,
- base_act, obedit,
ray_start, ray_normal, ray_start, ray_depth,
- r_loc, r_no, r_index,
- r_ob, r_obmat, NULL);
+ r_loc, r_no, r_index, r_ob, r_obmat, NULL);
}
/**
@@ -1529,14 +1510,12 @@ bool ED_transform_snap_object_project_ray_ex(
*/
bool ED_transform_snap_object_project_ray_all(
SnapObjectContext *sctx,
+ const unsigned short snap_to,
const struct SnapObjectParams *params,
const float ray_start[3], const float ray_normal[3],
float ray_depth, bool sort,
ListBase *r_hit_list)
{
- Base *base_act = params->use_object_active ? sctx->scene->basact : NULL;
- Object *obedit = params->use_object_edit ? sctx->scene->obedit : NULL;
-
if (ray_depth == -1.0f) {
ray_depth = BVH_RAYCAST_DIST_MAX;
}
@@ -1547,9 +1526,8 @@ bool ED_transform_snap_object_project_ray_all(
bool retval = snapObjectsRay(
sctx,
- params->snap_select, params->snap_to,
+ snap_to, params->snap_select, params->use_object_edit_cage,
NULL, NULL,
- base_act, obedit,
ray_start, ray_normal, ray_start, &ray_depth,
NULL, NULL, NULL, NULL, NULL,
r_hit_list);
@@ -1575,6 +1553,7 @@ bool ED_transform_snap_object_project_ray_all(
*/
static bool transform_snap_context_project_ray_impl(
SnapObjectContext *sctx,
+ const struct SnapObjectParams *params,
const float ray_start[3], const float ray_normal[3], float *ray_depth,
float r_co[3], float r_no[3])
{
@@ -1583,11 +1562,8 @@ static bool transform_snap_context_project_ray_impl(
/* try snap edge, then face if it fails */
ret = ED_transform_snap_object_project_ray_ex(
sctx,
- &(const struct SnapObjectParams){
- .snap_select = SNAP_ALL,
- .snap_to = SCE_SNAP_MODE_FACE,
- .use_object_edit = (sctx->scene->obedit != NULL),
- },
+ SCE_SNAP_MODE_FACE,
+ params,
ray_start, ray_normal, ray_depth,
r_co, r_no, NULL,
NULL, NULL);
@@ -1597,6 +1573,7 @@ static bool transform_snap_context_project_ray_impl(
bool ED_transform_snap_object_project_ray(
SnapObjectContext *sctx,
+ const struct SnapObjectParams *params,
const float ray_origin[3], const float ray_direction[3], float *ray_depth,
float r_co[3], float r_no[3])
{
@@ -1613,12 +1590,14 @@ bool ED_transform_snap_object_project_ray(
return transform_snap_context_project_ray_impl(
sctx,
+ params,
ray_origin, ray_direction, ray_depth,
r_co, r_no);
}
static bool transform_snap_context_project_view3d_mixed_impl(
SnapObjectContext *sctx,
+ const unsigned short snap_to_flag,
const struct SnapObjectParams *params,
const float mval[2], float *dist_px,
bool use_depth,
@@ -1634,22 +1613,18 @@ static bool transform_snap_context_project_view3d_mixed_impl(
const int elem_type[3] = {SCE_SNAP_MODE_VERTEX, SCE_SNAP_MODE_EDGE, SCE_SNAP_MODE_FACE};
- BLI_assert(params->snap_to_flag != 0);
- BLI_assert((params->snap_to_flag & ~(1 | 2 | 4)) == 0);
-
- struct SnapObjectParams params_temp = *params;
+ BLI_assert(snap_to_flag != 0);
+ BLI_assert((snap_to_flag & ~(1 | 2 | 4)) == 0);
for (int i = 0; i < 3; i++) {
- if ((params->snap_to_flag & (1 << i)) && (is_hit == false || use_depth)) {
+ if ((snap_to_flag & (1 << i)) && (is_hit == false || use_depth)) {
if (use_depth == false) {
ray_depth = BVH_RAYCAST_DIST_MAX;
}
- params_temp.snap_to = elem_type[i];
-
if (ED_transform_snap_object_project_view3d(
sctx,
- &params_temp,
+ elem_type[i], params,
mval, dist_px, &ray_depth,
r_co, r_no))
{
@@ -1676,6 +1651,7 @@ static bool transform_snap_context_project_view3d_mixed_impl(
*/
bool ED_transform_snap_object_project_view3d_mixed(
SnapObjectContext *sctx,
+ const unsigned short snap_to_flag,
const struct SnapObjectParams *params,
const float mval_fl[2], float *dist_px,
bool use_depth,
@@ -1683,13 +1659,14 @@ bool ED_transform_snap_object_project_view3d_mixed(
{
return transform_snap_context_project_view3d_mixed_impl(
sctx,
- params,
+ snap_to_flag, params,
mval_fl, dist_px, use_depth,
r_co, r_no);
}
bool ED_transform_snap_object_project_view3d_ex(
SnapObjectContext *sctx,
+ const unsigned short snap_to,
const struct SnapObjectParams *params,
const float mval[2], float *dist_px,
float *ray_depth,
@@ -1710,19 +1687,17 @@ bool ED_transform_snap_object_project_view3d_ex(
return false;
}
- Base *base_act = params->use_object_active ? sctx->scene->basact : NULL;
- Object *obedit = params->use_object_edit ? sctx->scene->obedit : NULL;
return snapObjectsRay(
sctx,
- params->snap_select, params->snap_to,
+ snap_to, params->snap_select, params->use_object_edit_cage,
mval, dist_px,
- base_act, obedit,
ray_start, ray_normal, ray_orgigin, ray_depth,
r_loc, r_no, r_index, NULL, NULL, NULL);
}
bool ED_transform_snap_object_project_view3d(
SnapObjectContext *sctx,
+ const unsigned short snap_to,
const struct SnapObjectParams *params,
const float mval[2], float *dist_px,
float *ray_depth,
@@ -1730,6 +1705,7 @@ bool ED_transform_snap_object_project_view3d(
{
return ED_transform_snap_object_project_view3d_ex(
sctx,
+ snap_to,
params,
mval, dist_px,
ray_depth,
@@ -1748,8 +1724,6 @@ bool ED_transform_snap_object_project_all_view3d_ex(
{
float ray_start[3], ray_normal[3];
- BLI_assert(params->snap_to == SCE_SNAP_MODE_FACE);
-
if (!ED_view3d_win_to_ray_ex(
sctx->v3d_data.ar, sctx->v3d_data.v3d,
mval, NULL, ray_normal, ray_start, true))
@@ -1759,6 +1733,7 @@ bool ED_transform_snap_object_project_all_view3d_ex(
return ED_transform_snap_object_project_ray_all(
sctx,
+ SCE_SNAP_MODE_FACE,
params,
ray_start, ray_normal, ray_depth, sort,
r_hit_list);
diff --git a/source/blender/gpu/GPU_basic_shader.h b/source/blender/gpu/GPU_basic_shader.h
index df2da971845..1e2db6acc52 100644
--- a/source/blender/gpu/GPU_basic_shader.h
+++ b/source/blender/gpu/GPU_basic_shader.h
@@ -46,11 +46,12 @@ typedef enum GPUBasicShaderOption {
GPU_SHADER_LIGHTING = (1 << 1), /* use lighting */
GPU_SHADER_TWO_SIDED = (1 << 2), /* flip normals towards viewer */
GPU_SHADER_TEXTURE_2D = (1 << 3), /* use 2D texture to replace diffuse color */
+ GPU_SHADER_TEXTURE_RECT = (1 << 4), /* same as GPU_SHADER_TEXTURE_2D, for GL_TEXTURE_RECTANGLE */
- GPU_SHADER_SOLID_LIGHTING = (1 << 4), /* use faster lighting (set automatically) */
- GPU_SHADER_STIPPLE = (1 << 5), /* use stipple */
- GPU_SHADER_LINE = (1 << 6), /* draw lines */
- GPU_SHADER_OPTIONS_NUM = 7,
+ GPU_SHADER_SOLID_LIGHTING = (1 << 5), /* use faster lighting (set automatically) */
+ GPU_SHADER_STIPPLE = (1 << 6), /* use stipple */
+ GPU_SHADER_LINE = (1 << 7), /* draw lines */
+ GPU_SHADER_OPTIONS_NUM = 8,
GPU_SHADER_OPTION_COMBINATIONS = (1 << GPU_SHADER_OPTIONS_NUM)
} GPUBasicShaderOption;
@@ -76,6 +77,22 @@ void GPU_basic_shaders_exit(void);
void GPU_basic_shader_bind(int options);
int GPU_basic_shader_bound_options(void);
+/* Only use for small blocks of code that don't support glsl shader. */
+#define GPU_BASIC_SHADER_DISABLE_AND_STORE(bound_options) \
+if (GPU_basic_shader_use_glsl_get()) { \
+ if ((bound_options = GPU_basic_shader_bound_options())) { \
+ GPU_basic_shader_bind(0); \
+ } \
+} \
+else { bound_options = 0; } ((void)0)
+#define GPU_BASIC_SHADER_ENABLE_AND_RESTORE(bound_options) \
+if (GPU_basic_shader_use_glsl_get()) { \
+ if (bound_options) { \
+ GPU_basic_shader_bind(bound_options); \
+ } \
+} ((void)0)
+
+
void GPU_basic_shader_colors(const float diffuse[3], const float specular[3],
int shininess, float alpha);
@@ -110,6 +127,9 @@ void GPU_basic_shader_stipple(GPUBasicShaderStipple stipple_id);
void GPU_basic_shader_line_stipple(GLint stipple_factor, GLushort stipple_pattern);
void GPU_basic_shader_line_width(float line_width);
+bool GPU_basic_shader_use_glsl_get(void);
+void GPU_basic_shader_use_glsl_set(bool enabled);
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/gpu/GPU_buffers.h b/source/blender/gpu/GPU_buffers.h
index a8656c05224..aefaf1a0f54 100644
--- a/source/blender/gpu/GPU_buffers.h
+++ b/source/blender/gpu/GPU_buffers.h
@@ -49,6 +49,7 @@ struct DerivedMesh;
struct GSet;
struct GPUVertPointLink;
struct GPUDrawObject;
+struct GridCommonGPUBuffer;
struct PBVH;
struct MVert;
@@ -147,6 +148,7 @@ typedef struct GPUVertPointLink {
/* used for GLSL materials */
typedef struct GPUAttrib {
int index;
+ int info_index;
int size;
int type;
} GPUAttrib;
@@ -159,9 +161,6 @@ void GPU_buffer_free(GPUBuffer *buffer);
void GPU_drawobject_free(struct DerivedMesh *dm);
-/* free special global multires grid buffer */
-void GPU_buffer_multires_free(bool force);
-
/* flag that controls data type to fill buffer with, a modifier will prepare. */
typedef enum {
GPU_BUFFER_VERTEX = 0,
@@ -179,6 +178,10 @@ typedef enum {
GPU_BINDING_INDEX = 1,
} GPUBindingType;
+typedef enum {
+ GPU_ATTR_INFO_SRGB = (1 << 0),
+} GPUAttrInfo;
+
/* called before drawing */
void GPU_vertex_setup(struct DerivedMesh *dm);
void GPU_normal_setup(struct DerivedMesh *dm);
@@ -226,8 +229,9 @@ GPU_PBVH_Buffers *GPU_build_mesh_pbvh_buffers(
const int *face_indices,
const int face_indices_len);
-GPU_PBVH_Buffers *GPU_build_grid_pbvh_buffers(int *grid_indices, int totgrid,
- unsigned int **grid_hidden, int gridsize, const struct CCGKey *key);
+GPU_PBVH_Buffers *GPU_build_grid_pbvh_buffers(
+ int *grid_indices, int totgrid,unsigned int **grid_hidden, int gridsize, const struct CCGKey *key,
+ struct GridCommonGPUBuffer **grid_common_gpu_buffer);
GPU_PBVH_Buffers *GPU_build_bmesh_pbvh_buffers(bool smooth_shading);
@@ -262,5 +266,6 @@ void GPU_init_draw_pbvh_BB(void);
bool GPU_pbvh_buffers_diffuse_changed(GPU_PBVH_Buffers *buffers, struct GSet *bm_faces, bool show_diffuse_color);
void GPU_free_pbvh_buffers(GPU_PBVH_Buffers *buffers);
+void GPU_free_pbvh_buffer_multires(struct GridCommonGPUBuffer **grid_common_gpu_buffer);
#endif
diff --git a/source/blender/gpu/GPU_material.h b/source/blender/gpu/GPU_material.h
index fc2ca16db59..a79334df8ce 100644
--- a/source/blender/gpu/GPU_material.h
+++ b/source/blender/gpu/GPU_material.h
@@ -241,6 +241,7 @@ void GPU_material_vertex_attributes(GPUMaterial *material,
bool GPU_material_do_color_management(GPUMaterial *mat);
bool GPU_material_use_new_shading_nodes(GPUMaterial *mat);
+bool GPU_material_use_world_space_shading(GPUMaterial *mat);
/* Exported shading */
diff --git a/source/blender/gpu/GPU_shader.h b/source/blender/gpu/GPU_shader.h
index 4c674b460aa..762329ee077 100644
--- a/source/blender/gpu/GPU_shader.h
+++ b/source/blender/gpu/GPU_shader.h
@@ -104,6 +104,7 @@ typedef struct GPUVertexAttribs {
struct {
int type;
int glindex;
+ int glinfoindoex;
int gltexco;
int attribid;
char name[64]; /* MAX_CUSTOMDATA_LAYER_NAME */
diff --git a/source/blender/gpu/intern/gpu_basic_shader.c b/source/blender/gpu/intern/gpu_basic_shader.c
index b6fe40a13ee..b0669225a4d 100644
--- a/source/blender/gpu/intern/gpu_basic_shader.c
+++ b/source/blender/gpu/intern/gpu_basic_shader.c
@@ -51,8 +51,6 @@
/* State */
-static const bool USE_GLSL = false;
-
static struct {
GPUShader *cached_shaders[GPU_SHADER_OPTION_COMBINATIONS];
bool failed_shaders[GPU_SHADER_OPTION_COMBINATIONS];
@@ -269,6 +267,24 @@ const GLubyte stipple_hexagon[128] = {
0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22};
/* ********************************************* */
+/* GLSL State */
+
+static bool USE_GLSL = false;
+
+/**
+ * \note this isn't part of the basic shader API,
+ * only set from the command line once on startup.
+ */
+void GPU_basic_shader_use_glsl_set(bool enabled)
+{
+ USE_GLSL = enabled;
+}
+
+bool GPU_basic_shader_use_glsl_get(void)
+{
+ return USE_GLSL;
+}
+
/* Init / exit */
void GPU_basic_shaders_init(void)
@@ -308,6 +324,9 @@ static int detect_options()
if (glIsEnabled(GL_TEXTURE_2D))
options |= GPU_SHADER_TEXTURE_2D;
+ if (glIsEnabled(GL_TEXTURE_RECTANGLE))
+ options |= GPU_SHADER_TEXTURE_RECT;
+ GPU_SHADER_TEXTURE_RECT
if (glIsEnabled(GL_COLOR_MATERIAL))
options |= GPU_SHADER_USE_COLOR;
@@ -347,8 +366,10 @@ static GPUShader *gpu_basic_shader(int options)
strcat(defines, "#define USE_COLOR\n");
if (options & GPU_SHADER_TWO_SIDED)
strcat(defines, "#define USE_TWO_SIDED\n");
- if (options & GPU_SHADER_TEXTURE_2D)
+ if (options & (GPU_SHADER_TEXTURE_2D | GPU_SHADER_TEXTURE_RECT))
strcat(defines, "#define USE_TEXTURE\n");
+ if (options & GPU_SHADER_TEXTURE_RECT)
+ strcat(defines, "#define USE_TEXTURE_RECTANGLE\n");
if (options & GPU_SHADER_STIPPLE)
strcat(defines, "#define USE_STIPPLE\n");
if (options & GPU_SHADER_LINE) {
@@ -369,7 +390,7 @@ static GPUShader *gpu_basic_shader(int options)
if (shader) {
/* set texture map to first texture unit */
- if (options & GPU_SHADER_TEXTURE_2D) {
+ if (options & (GPU_SHADER_TEXTURE_2D | GPU_SHADER_TEXTURE_RECT)) {
GPU_shader_bind(shader);
glUniform1i(GPU_shader_get_uniform(shader, "texture_map"), 0);
GPU_shader_unbind();
@@ -399,6 +420,23 @@ void GPU_basic_shader_bind(int options)
{
if (USE_GLSL) {
if (options) {
+ const int bound_options = GPU_MATERIAL_STATE.bound_options;
+
+ /* texture options need to be set for basic shader too */
+ if (options & GPU_SHADER_TEXTURE_2D) {
+ glEnable(GL_TEXTURE_2D);
+ }
+ else if (bound_options & GPU_SHADER_TEXTURE_2D) {
+ glDisable(GL_TEXTURE_2D);
+ }
+
+ if (options & GPU_SHADER_TEXTURE_RECT) {
+ glEnable(GL_TEXTURE_RECTANGLE);
+ }
+ else if (bound_options & GPU_SHADER_TEXTURE_RECT) {
+ glDisable(GL_TEXTURE_RECTANGLE);
+ }
+
GPUShader *shader = gpu_basic_shader(options);
if (shader) {
@@ -411,7 +449,7 @@ void GPU_basic_shader_bind(int options)
}
}
else {
- int bound_options = GPU_MATERIAL_STATE.bound_options;
+ const int bound_options = GPU_MATERIAL_STATE.bound_options;
if (options & GPU_SHADER_LIGHTING) {
glEnable(GL_LIGHTING);
@@ -438,10 +476,24 @@ void GPU_basic_shader_bind(int options)
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, env_mode);
}
else if (bound_options & GPU_SHADER_TEXTURE_2D) {
- glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
+ if ((options & GPU_SHADER_TEXTURE_RECT) == 0) {
+ glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
+ }
glDisable(GL_TEXTURE_2D);
}
+ if (options & GPU_SHADER_TEXTURE_RECT) {
+ GLint env_mode = (options & (GPU_SHADER_USE_COLOR | GPU_SHADER_LIGHTING)) ? GL_MODULATE : GL_REPLACE;
+ glEnable(GL_TEXTURE_RECTANGLE);
+ glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, env_mode);
+ }
+ else if (bound_options & GPU_SHADER_TEXTURE_RECT) {
+ if ((options & GPU_SHADER_TEXTURE_2D) == 0) {
+ glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
+ }
+ glDisable(GL_TEXTURE_RECTANGLE);
+ }
+
if ((options & GPU_SHADER_LINE) && (options & GPU_SHADER_STIPPLE)) {
glEnable(GL_LINE_STIPPLE);
}
@@ -552,7 +604,8 @@ void GPU_basic_shader_light_set(int light_num, GPULightData *light)
GPU_MATERIAL_STATE.lights_directional |= light_bit;
}
else {
- if (USE_GLSL) {
+ /* TODO(sergey): Needs revisit. */
+ if (USE_GLSL || true) {
/* glsl shader needs these zero to skip them */
const float zero[4] = {0.0f, 0.0f, 0.0f, 0.0f};
diff --git a/source/blender/gpu/intern/gpu_buffers.c b/source/blender/gpu/intern/gpu_buffers.c
index 072ff5235bf..2c6f204d9d0 100644
--- a/source/blender/gpu/intern/gpu_buffers.c
+++ b/source/blender/gpu/intern/gpu_buffers.c
@@ -107,10 +107,12 @@ static GPUAttrib attribData[MAX_GPU_ATTRIB_DATA] = { { -1, 0, 0 } };
static ThreadMutex buffer_mutex = BLI_MUTEX_INITIALIZER;
/* multires global buffer, can be used for many grids having the same grid size */
-static GPUBuffer *mres_glob_buffer = NULL;
-static int mres_prev_gridsize = -1;
-static GLenum mres_prev_index_type = 0;
-static unsigned mres_prev_totquad = 0;
+typedef struct GridCommonGPUBuffer {
+ GPUBuffer *mres_buffer;
+ int mres_prev_gridsize;
+ GLenum mres_prev_index_type;
+ unsigned mres_prev_totquad;
+} GridCommonGPUBuffer;
void GPU_buffer_material_finalize(GPUDrawObject *gdo, GPUBufferMaterial *matinfo, int totmat)
{
@@ -407,33 +409,6 @@ void GPU_buffer_free(GPUBuffer *buffer)
BLI_mutex_unlock(&buffer_mutex);
}
-void GPU_buffer_multires_free(bool force)
-{
- if (!mres_glob_buffer) {
- /* Early output, no need to lock in this case, */
- return;
- }
-
- if (force && BLI_thread_is_main()) {
- if (mres_glob_buffer) {
- if (mres_glob_buffer->id)
- glDeleteBuffers(1, &mres_glob_buffer->id);
- MEM_freeN(mres_glob_buffer);
- }
- }
- else {
- BLI_mutex_lock(&buffer_mutex);
- gpu_buffer_free_intern(mres_glob_buffer);
- BLI_mutex_unlock(&buffer_mutex);
- }
-
- mres_glob_buffer = NULL;
- mres_prev_gridsize = -1;
- mres_prev_index_type = 0;
- mres_prev_totquad = 0;
-}
-
-
void GPU_drawobject_free(DerivedMesh *dm)
{
GPUDrawObject *gdo;
@@ -822,8 +797,14 @@ void GPU_interleaved_attrib_setup(GPUBuffer *buffer, GPUAttrib data[], int numda
for (i = 0; i < numdata; i++) {
glEnableVertexAttribArray(data[i].index);
+ int info = 0;
+ if (data[i].type == GL_UNSIGNED_BYTE) {
+ info |= GPU_ATTR_INFO_SRGB;
+ }
+ glUniform1i(data[i].info_index, info);
+
glVertexAttribPointer(data[i].index, data[i].size, data[i].type,
- GL_FALSE, elementsize, BUFFER_OFFSET(offset));
+ GL_TRUE, elementsize, BUFFER_OFFSET(offset));
offset += data[i].size * GPU_typesize(data[i].type);
attribData[i].index = data[i].index;
@@ -1003,6 +984,7 @@ struct GPU_PBVH_Buffers {
const int *grid_indices;
int totgrid;
bool has_hidden;
+ bool is_index_buf_global; /* Means index_buf uses global bvh's grid_common_gpu_buffer, **DO NOT** free it! */
bool use_bmesh;
@@ -1220,8 +1202,10 @@ GPU_PBVH_Buffers *GPU_build_mesh_pbvh_buffers(
/* An element index buffer is used for smooth shading, but flat
* shading requires separate vertex normals so an index buffer is
* can't be used there. */
- if (buffers->smooth)
+ if (buffers->smooth) {
buffers->index_buf = GPU_buffer_alloc(sizeof(unsigned short) * tottri * 3);
+ buffers->is_index_buf_global = false;
+ }
if (buffers->index_buf) {
/* Fill the triangle buffer */
@@ -1242,8 +1226,11 @@ GPU_PBVH_Buffers *GPU_build_mesh_pbvh_buffers(
GPU_buffer_unlock(buffers->index_buf, GPU_BINDING_INDEX);
}
else {
- GPU_buffer_free(buffers->index_buf);
+ if (!buffers->is_index_buf_global) {
+ GPU_buffer_free(buffers->index_buf);
+ }
buffers->index_buf = NULL;
+ buffers->is_index_buf_global = false;
}
}
@@ -1410,22 +1397,33 @@ void GPU_update_grid_pbvh_buffers(GPU_PBVH_Buffers *buffers, CCGElem **grids,
} (void)0
/* end FILL_QUAD_BUFFER */
-static GPUBuffer *gpu_get_grid_buffer(int gridsize, GLenum *index_type, unsigned *totquad)
+static GPUBuffer *gpu_get_grid_buffer(
+ int gridsize, GLenum *index_type, unsigned *totquad, GridCommonGPUBuffer **grid_common_gpu_buffer)
{
/* used in the FILL_QUAD_BUFFER macro */
BLI_bitmap * const *grid_hidden = NULL;
const int *grid_indices = NULL;
int totgrid = 1;
+ GridCommonGPUBuffer *gridbuff = *grid_common_gpu_buffer;
+
+ if (gridbuff == NULL) {
+ *grid_common_gpu_buffer = gridbuff = MEM_mallocN(sizeof(GridCommonGPUBuffer), __func__);
+ gridbuff->mres_buffer = NULL;
+ gridbuff->mres_prev_gridsize = -1;
+ gridbuff->mres_prev_index_type = 0;
+ gridbuff->mres_prev_totquad = 0;
+ }
+
/* VBO is already built */
- if (mres_glob_buffer && mres_prev_gridsize == gridsize) {
- *index_type = mres_prev_index_type;
- *totquad = mres_prev_totquad;
- return mres_glob_buffer;
+ if (gridbuff->mres_buffer && gridbuff->mres_prev_gridsize == gridsize) {
+ *index_type = gridbuff->mres_prev_index_type;
+ *totquad = gridbuff->mres_prev_totquad;
+ return gridbuff->mres_buffer;
}
/* we can't reuse old, delete the existing buffer */
- else if (mres_glob_buffer) {
- GPU_buffer_free(mres_glob_buffer);
+ else if (gridbuff->mres_buffer) {
+ GPU_buffer_free(gridbuff->mres_buffer);
}
/* Build new VBO */
@@ -1433,17 +1431,17 @@ static GPUBuffer *gpu_get_grid_buffer(int gridsize, GLenum *index_type, unsigned
if (gridsize * gridsize < USHRT_MAX) {
*index_type = GL_UNSIGNED_SHORT;
- FILL_QUAD_BUFFER(unsigned short, *totquad, mres_glob_buffer);
+ FILL_QUAD_BUFFER(unsigned short, *totquad, gridbuff->mres_buffer);
}
else {
*index_type = GL_UNSIGNED_INT;
- FILL_QUAD_BUFFER(unsigned int, *totquad, mres_glob_buffer);
+ FILL_QUAD_BUFFER(unsigned int, *totquad, gridbuff->mres_buffer);
}
- mres_prev_gridsize = gridsize;
- mres_prev_index_type = *index_type;
- mres_prev_totquad = *totquad;
- return mres_glob_buffer;
+ gridbuff->mres_prev_gridsize = gridsize;
+ gridbuff->mres_prev_index_type = *index_type;
+ gridbuff->mres_prev_totquad = *totquad;
+ return gridbuff->mres_buffer;
}
#define FILL_FAST_BUFFER(type_) \
@@ -1470,8 +1468,9 @@ static GPUBuffer *gpu_get_grid_buffer(int gridsize, GLenum *index_type, unsigned
} \
} (void)0
-GPU_PBVH_Buffers *GPU_build_grid_pbvh_buffers(int *grid_indices, int totgrid,
- BLI_bitmap **grid_hidden, int gridsize, const CCGKey *key)
+GPU_PBVH_Buffers *GPU_build_grid_pbvh_buffers(
+ int *grid_indices, int totgrid, BLI_bitmap **grid_hidden, int gridsize, const CCGKey *key,
+ GridCommonGPUBuffer **grid_common_gpu_buffer)
{
GPU_PBVH_Buffers *buffers;
int totquad;
@@ -1500,8 +1499,10 @@ GPU_PBVH_Buffers *GPU_build_grid_pbvh_buffers(int *grid_indices, int totgrid,
}
if (totquad == fully_visible_totquad) {
- buffers->index_buf = gpu_get_grid_buffer(gridsize, &buffers->index_type, &buffers->tot_quad);
+ buffers->index_buf = gpu_get_grid_buffer(
+ gridsize, &buffers->index_type, &buffers->tot_quad, grid_common_gpu_buffer);
buffers->has_hidden = false;
+ buffers->is_index_buf_global = true;
}
else {
buffers->tot_quad = totquad;
@@ -1516,6 +1517,7 @@ GPU_PBVH_Buffers *GPU_build_grid_pbvh_buffers(int *grid_indices, int totgrid,
}
buffers->has_hidden = true;
+ buffers->is_index_buf_global = false;
}
/* Build coord/normal VBO */
@@ -1740,8 +1742,9 @@ void GPU_update_bmesh_pbvh_buffers(GPU_PBVH_Buffers *buffers,
const int use_short = (maxvert < USHRT_MAX);
/* Initialize triangle index buffer */
- if (buffers->index_buf)
+ if (buffers->index_buf && !buffers->is_index_buf_global)
GPU_buffer_free(buffers->index_buf);
+ buffers->is_index_buf_global = false;
buffers->index_buf = GPU_buffer_alloc((use_short ?
sizeof(unsigned short) :
sizeof(unsigned int)) * 3 * tottri);
@@ -1786,12 +1789,19 @@ void GPU_update_bmesh_pbvh_buffers(GPU_PBVH_Buffers *buffers,
}
else {
/* Memory map failed */
- GPU_buffer_free(buffers->index_buf);
+ if (!buffers->is_index_buf_global) {
+ GPU_buffer_free(buffers->index_buf);
+ }
buffers->index_buf = NULL;
+ buffers->is_index_buf_global = false;
}
}
else if (buffers->index_buf) {
- GPU_buffer_free(buffers->index_buf);
+ if (!buffers->is_index_buf_global) {
+ GPU_buffer_free(buffers->index_buf);
+ }
+ buffers->index_buf = NULL;
+ buffers->is_index_buf_global = false;
}
}
@@ -1985,7 +1995,7 @@ void GPU_free_pbvh_buffers(GPU_PBVH_Buffers *buffers)
if (buffers) {
if (buffers->vert_buf)
GPU_buffer_free(buffers->vert_buf);
- if (buffers->index_buf && (buffers->tot_tri || buffers->has_hidden))
+ if (buffers->index_buf && !buffers->is_index_buf_global)
GPU_buffer_free(buffers->index_buf);
if (buffers->index_buf_fast)
GPU_buffer_free(buffers->index_buf_fast);
@@ -1998,6 +2008,20 @@ void GPU_free_pbvh_buffers(GPU_PBVH_Buffers *buffers)
}
}
+void GPU_free_pbvh_buffer_multires(GridCommonGPUBuffer **grid_common_gpu_buffer)
+{
+ GridCommonGPUBuffer *gridbuff = *grid_common_gpu_buffer;
+
+ if (gridbuff) {
+ if (gridbuff->mres_buffer) {
+ BLI_mutex_lock(&buffer_mutex);
+ gpu_buffer_free_intern(gridbuff->mres_buffer);
+ BLI_mutex_unlock(&buffer_mutex);
+ }
+ MEM_freeN(gridbuff);
+ *grid_common_gpu_buffer = NULL;
+ }
+}
/* debug function, draws the pbvh BB */
void GPU_draw_pbvh_BB(float min[3], float max[3], bool leaf)
diff --git a/source/blender/gpu/intern/gpu_codegen.c b/source/blender/gpu/intern/gpu_codegen.c
index 94d52c3617c..58ef4063430 100644
--- a/source/blender/gpu/intern/gpu_codegen.c
+++ b/source/blender/gpu/intern/gpu_codegen.c
@@ -749,6 +749,7 @@ static char *code_generate_vertex(ListBase *nodes, const GPUMatType type)
BLI_dynstr_appendf(ds, "%s %s att%d;\n",
GLEW_VERSION_3_0 ? "in" : "attribute",
GPU_DATATYPE_STR[input->type], input->attribid);
+ BLI_dynstr_appendf(ds, "uniform int att%d_info;\n", input->attribid);
BLI_dynstr_appendf(ds, "%s %s var%d;\n",
GLEW_VERSION_3_0 ? "out" : "varying",
GPU_DATATYPE_STR[input->type], input->attribid);
@@ -801,7 +802,8 @@ static char *code_generate_vertex(ListBase *nodes, const GPUMatType type)
BLI_dynstr_appendf(ds, "#ifndef USE_OPENSUBDIV\n");
}
#endif
- BLI_dynstr_appendf(ds, "\tvar%d = att%d;\n", input->attribid, input->attribid);
+ BLI_dynstr_appendf(ds, "\tset_var_from_attr(att%d, att%d_info, var%d);\n",
+ input->attribid, input->attribid, input->attribid);
#ifdef WITH_OPENSUBDIV
if (is_mtface) {
BLI_dynstr_appendf(ds, "#endif\n");
diff --git a/source/blender/gpu/intern/gpu_framebuffer.c b/source/blender/gpu/intern/gpu_framebuffer.c
index 0beba545147..835a96ea48b 100644
--- a/source/blender/gpu/intern/gpu_framebuffer.c
+++ b/source/blender/gpu/intern/gpu_framebuffer.c
@@ -575,7 +575,7 @@ void GPU_offscreen_read_pixels(GPUOffScreen *ofs, int type, void *pixels)
glFramebufferTexture2DEXT(
GL_READ_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT + ofs->color->fb_attachment,
GL_TEXTURE_2D_MULTISAMPLE, ofs->color->bindcode, 0);
- status = glCheckFramebufferStatus(GL_READ_FRAMEBUFFER_EXT);
+ status = glCheckFramebufferStatusEXT(GL_READ_FRAMEBUFFER_EXT);
if (status != GL_FRAMEBUFFER_COMPLETE_EXT) {
goto finally;
}
@@ -583,11 +583,11 @@ void GPU_offscreen_read_pixels(GPUOffScreen *ofs, int type, void *pixels)
/* write into new single-sample buffer */
glGenFramebuffersEXT(1, &fbo_blit);
- glBindFramebuffer(GL_DRAW_FRAMEBUFFER_EXT, fbo_blit);
+ glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, fbo_blit);
glFramebufferTexture2DEXT(
- GL_DRAW_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0,
+ GL_DRAW_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
GL_TEXTURE_2D, tex_blit, 0);
- status = glCheckFramebufferStatus(GL_DRAW_FRAMEBUFFER_EXT);
+ status = glCheckFramebufferStatusEXT(GL_DRAW_FRAMEBUFFER_EXT);
if (status != GL_FRAMEBUFFER_COMPLETE_EXT) {
goto finally;
}
diff --git a/source/blender/gpu/intern/gpu_init_exit.c b/source/blender/gpu/intern/gpu_init_exit.c
index da4dd65d2e1..8fed6a9ee80 100644
--- a/source/blender/gpu/intern/gpu_init_exit.c
+++ b/source/blender/gpu/intern/gpu_init_exit.c
@@ -73,7 +73,6 @@ void GPU_exit(void)
gpu_codegen_exit();
gpu_extensions_exit(); /* must come last */
- GPU_buffer_multires_free(true);
initialized = false;
}
diff --git a/source/blender/gpu/intern/gpu_material.c b/source/blender/gpu/intern/gpu_material.c
index aaa52b2c3f6..02f58ea6df2 100644
--- a/source/blender/gpu/intern/gpu_material.c
+++ b/source/blender/gpu/intern/gpu_material.c
@@ -212,6 +212,9 @@ static void gpu_material_set_attrib_id(GPUMaterial *material)
BLI_snprintf(name, sizeof(name), "att%d", attribs->layer[a].attribid);
attribs->layer[a].glindex = GPU_shader_get_attribute(shader, name);
+ BLI_snprintf(name, sizeof(name), "att%d_info", attribs->layer[a].attribid);
+ attribs->layer[a].glinfoindoex = GPU_shader_get_uniform(shader, name);
+
if (attribs->layer[a].glindex >= 0) {
attribs->layer[b] = attribs->layer[a];
b++;
@@ -514,6 +517,11 @@ bool GPU_material_use_new_shading_nodes(GPUMaterial *mat)
return BKE_scene_use_new_shading_nodes(mat->scene);
}
+bool GPU_material_use_world_space_shading(GPUMaterial *mat)
+{
+ return BKE_scene_use_world_space_shading(mat->scene);
+}
+
static GPUNodeLink *lamp_get_visibility(GPUMaterial *mat, GPULamp *lamp, GPUNodeLink **lv, GPUNodeLink **dist)
{
GPUNodeLink *visifac;
diff --git a/source/blender/gpu/shaders/gpu_shader_basic_frag.glsl b/source/blender/gpu/shaders/gpu_shader_basic_frag.glsl
index c7b29ee5707..ea5f6aef005 100644
--- a/source/blender/gpu/shaders/gpu_shader_basic_frag.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_basic_frag.glsl
@@ -3,6 +3,7 @@
*
* USE_COLOR: use glColor for diffuse colors
* USE_TEXTURE: use texture for diffuse colors
+ * USE_TEXTURE_RECTANGLE: use GL_TEXTURE_RECTANGLE instead of GL_TEXTURE_2D
* USE_SCENE_LIGHTING: use lights (up to 8)
* USE_SOLID_LIGHTING: assume 3 directional lights for solid draw mode
* USE_TWO_SIDED: flip normal towards viewer
@@ -39,8 +40,16 @@ varying vec4 varying_vertex_color;
#endif
#ifdef USE_TEXTURE
+#ifdef USE_TEXTURE_RECTANGLE
+#define sampler2D_default sampler2DRect
+#define texture2D_default texture2DRect
+#else
+#define sampler2D_default sampler2D
+#define texture2D_default texture2D
+#endif
+
varying vec2 varying_texture_coord;
-uniform sampler2D texture_map;
+uniform sampler2D_default texture_map;
#endif
#ifdef USE_STIPPLE
@@ -55,83 +64,83 @@ void main()
{
#if defined(USE_STIPPLE)
#if defined(DRAW_LINE)
- /* GLSL 1.3 */
- if (!bool((1 << int(mod(t, 16))) & stipple_pattern))
- discard;
+ /* GLSL 1.3 */
+ if (!bool((1 << int(mod(t, 16))) & stipple_pattern))
+ discard;
#else
- /* We have to use mod function and integer casting.
- * This can be optimized further with the bitwise operations
- * when GLSL 1.3 is supported. */
- if (stipple_id == STIPPLE_HALFTONE ||
- stipple_id == STIPPLE_S3D_INTERLACE_CHECKERBOARD ||
- stipple_id == STIPPLE_S3D_INTERLACE_CHECKERBOARD_SWAP)
- {
- int result = int(mod(gl_FragCoord.x + gl_FragCoord.y, 2));
- bool dis = result == 0;
- if (stipple_id == STIPPLE_S3D_INTERLACE_CHECKERBOARD_SWAP)
- dis = !dis;
- if (dis)
- discard;
- }
- else if (stipple_id == STIPPLE_QUARTTONE) {
- int mody = int(mod(gl_FragCoord.y, 4));
- int modx = int(mod(gl_FragCoord.x, 4));
- if (mody == 0) {
- if (modx != 2)
- discard;
- }
- else if (mody == 2){
- if (modx != 0)
- discard;
- }
- else
- discard;
- }
- else if (stipple_id == STIPPLE_CHECKER_8PX) {
- int result = int(mod(int(gl_FragCoord.x)/8 + int(gl_FragCoord.y)/8, 2));
- if (result != 0)
- discard;
- }
- else if (stipple_id == STIPPLE_DIAG_STRIPES) {
- int mody = int(mod(gl_FragCoord.y, 16));
- int modx = int(mod(gl_FragCoord.x, 16));
- if ((16 - modx > mody && mody > 8 - modx) || mody > 24 - modx)
- discard;
- }
- else if (stipple_id == STIPPLE_DIAG_STRIPES_SWAP) {
- int mody = int(mod(gl_FragCoord.y, 16));
- int modx = int(mod(gl_FragCoord.x, 16));
- if (!((16 - modx > mody && mody > 8 - modx) || mody > 24 - modx))
- discard;
- }
- else if (stipple_id == STIPPLE_S3D_INTERLACE_ROW || stipple_id == STIPPLE_S3D_INTERLACE_ROW_SWAP) {
- int result = int(mod(gl_FragCoord.y, 2));
- bool dis = result == 0;
- if (stipple_id == STIPPLE_S3D_INTERLACE_ROW_SWAP)
- dis = !dis;
- if (dis)
- discard;
- }
- else if (stipple_id == STIPPLE_S3D_INTERLACE_COLUMN || stipple_id == STIPPLE_S3D_INTERLACE_COLUMN_SWAP) {
- int result = int(mod(gl_FragCoord.x, 2));
- bool dis = result != 0;
- if (stipple_id == STIPPLE_S3D_INTERLACE_COLUMN_SWAP)
- dis = !dis;
- if (dis)
- discard;
- }
- else if (stipple_id == STIPPLE_HEXAGON) {
- int mody = int(mod(gl_FragCoord.y, 2));
- int modx = int(mod(gl_FragCoord.x, 4));
- if (mody != 0) {
- if (modx != 1)
- discard;
- }
- else {
- if (modx != 3)
- discard;
- }
- }
+ /* We have to use mod function and integer casting.
+ * This can be optimized further with the bitwise operations
+ * when GLSL 1.3 is supported. */
+ if (stipple_id == STIPPLE_HALFTONE ||
+ stipple_id == STIPPLE_S3D_INTERLACE_CHECKERBOARD ||
+ stipple_id == STIPPLE_S3D_INTERLACE_CHECKERBOARD_SWAP)
+ {
+ int result = int(mod(gl_FragCoord.x + gl_FragCoord.y, 2));
+ bool dis = result == 0;
+ if (stipple_id == STIPPLE_S3D_INTERLACE_CHECKERBOARD_SWAP)
+ dis = !dis;
+ if (dis)
+ discard;
+ }
+ else if (stipple_id == STIPPLE_QUARTTONE) {
+ int mody = int(mod(gl_FragCoord.y, 4));
+ int modx = int(mod(gl_FragCoord.x, 4));
+ if (mody == 0) {
+ if (modx != 2)
+ discard;
+ }
+ else if (mody == 2) {
+ if (modx != 0)
+ discard;
+ }
+ else
+ discard;
+ }
+ else if (stipple_id == STIPPLE_CHECKER_8PX) {
+ int result = int(mod(int(gl_FragCoord.x) / 8 + int(gl_FragCoord.y) / 8, 2));
+ if (result != 0)
+ discard;
+ }
+ else if (stipple_id == STIPPLE_DIAG_STRIPES) {
+ int mody = int(mod(gl_FragCoord.y, 16));
+ int modx = int(mod(gl_FragCoord.x, 16));
+ if ((16 - modx > mody && mody > 8 - modx) || mody > 24 - modx)
+ discard;
+ }
+ else if (stipple_id == STIPPLE_DIAG_STRIPES_SWAP) {
+ int mody = int(mod(gl_FragCoord.y, 16));
+ int modx = int(mod(gl_FragCoord.x, 16));
+ if (!((16 - modx > mody && mody > 8 - modx) || mody > 24 - modx))
+ discard;
+ }
+ else if (stipple_id == STIPPLE_S3D_INTERLACE_ROW || stipple_id == STIPPLE_S3D_INTERLACE_ROW_SWAP) {
+ int result = int(mod(gl_FragCoord.y, 2));
+ bool dis = result == 0;
+ if (stipple_id == STIPPLE_S3D_INTERLACE_ROW_SWAP)
+ dis = !dis;
+ if (dis)
+ discard;
+ }
+ else if (stipple_id == STIPPLE_S3D_INTERLACE_COLUMN || stipple_id == STIPPLE_S3D_INTERLACE_COLUMN_SWAP) {
+ int result = int(mod(gl_FragCoord.x, 2));
+ bool dis = result != 0;
+ if (stipple_id == STIPPLE_S3D_INTERLACE_COLUMN_SWAP)
+ dis = !dis;
+ if (dis)
+ discard;
+ }
+ else if (stipple_id == STIPPLE_HEXAGON) {
+ int mody = int(mod(gl_FragCoord.y, 2));
+ int modx = int(mod(gl_FragCoord.x, 4));
+ if (mody != 0) {
+ if (modx != 1)
+ discard;
+ }
+ else {
+ if (modx != 3)
+ discard;
+ }
+ }
#endif /* !DRAW_LINE */
#endif /* USE_STIPPLE */
@@ -158,7 +167,7 @@ void main()
/* diffuse light */
vec3 light_diffuse = gl_LightSource[i].diffuse.rgb;
float diffuse_bsdf = max(dot(N, light_direction), 0.0);
- L_diffuse += light_diffuse*diffuse_bsdf;
+ L_diffuse += light_diffuse * diffuse_bsdf;
#ifndef NO_SPECULAR
/* specular light */
@@ -166,7 +175,7 @@ void main()
vec3 H = gl_LightSource[i].halfVector.xyz;
float specular_bsdf = pow(max(dot(N, H), 0.0), gl_FrontMaterial.shininess);
- L_specular += light_specular*specular_bsdf;
+ L_specular += light_specular * specular_bsdf;
#endif
}
#else
@@ -174,7 +183,7 @@ void main()
#ifndef NO_SPECULAR
/* view vector computation, depends on orthographics or perspective */
- vec3 V = (gl_ProjectionMatrix[3][3] == 0.0) ? normalize(varying_position): vec3(0.0, 0.0, -1.0);
+ vec3 V = (gl_ProjectionMatrix[3][3] == 0.0) ? normalize(varying_position) : vec3(0.0, 0.0, -1.0);
#endif
for (int i = 0; i < NUM_SCENE_LIGHTS; i++) {
@@ -205,14 +214,14 @@ void main()
float distance = length(d);
intensity /= gl_LightSource[i].constantAttenuation +
- gl_LightSource[i].linearAttenuation * distance +
- gl_LightSource[i].quadraticAttenuation * distance * distance;
+ gl_LightSource[i].linearAttenuation * distance +
+ gl_LightSource[i].quadraticAttenuation * distance * distance;
}
/* diffuse light */
vec3 light_diffuse = gl_LightSource[i].diffuse.rgb;
float diffuse_bsdf = max(dot(N, light_direction), 0.0);
- L_diffuse += light_diffuse*diffuse_bsdf*intensity;
+ L_diffuse += light_diffuse * diffuse_bsdf * intensity;
#ifndef NO_SPECULAR
/* specular light */
@@ -220,7 +229,7 @@ void main()
vec3 H = normalize(light_direction - V);
float specular_bsdf = pow(max(dot(N, H), 0.0), gl_FrontMaterial.shininess);
- L_specular += light_specular*specular_bsdf*intensity;
+ L_specular += light_specular * specular_bsdf * intensity;
#endif
}
#endif
@@ -229,12 +238,12 @@ void main()
float alpha;
#if defined(USE_TEXTURE) && defined(USE_COLOR)
- vec4 texture_color = texture2D(texture_map, varying_texture_coord);
+ vec4 texture_color = texture2D_default(texture_map, varying_texture_coord);
L_diffuse *= texture_color.rgb * varying_vertex_color.rgb;
alpha = texture_color.a * varying_vertex_color.a;
#elif defined(USE_TEXTURE)
- vec4 texture_color = texture2D(texture_map, varying_texture_coord);
+ vec4 texture_color = texture2D_default(texture_map, varying_texture_coord);
L_diffuse *= texture_color.rgb;
alpha = texture_color.a;
@@ -250,7 +259,7 @@ void main()
vec3 L = gl_FrontLightModelProduct.sceneColor.rgb + L_diffuse;
#ifndef NO_SPECULAR
- L += L_specular*gl_FrontMaterial.specular.rgb;
+ L += L_specular * gl_FrontMaterial.specular.rgb;
#endif
/* write out fragment color */
@@ -259,9 +268,9 @@ void main()
/* no lighting */
#if defined(USE_TEXTURE) && defined(USE_COLOR)
- gl_FragColor = texture2D(texture_map, varying_texture_coord) * varying_vertex_color;
+ gl_FragColor = texture2D_default(texture_map, varying_texture_coord) * varying_vertex_color;
#elif defined(USE_TEXTURE)
- gl_FragColor = texture2D(texture_map, varying_texture_coord);
+ gl_FragColor = texture2D_default(texture_map, varying_texture_coord);
#elif defined(USE_COLOR)
gl_FragColor = varying_vertex_color;
#else
diff --git a/source/blender/gpu/shaders/gpu_shader_basic_geom.glsl b/source/blender/gpu/shaders/gpu_shader_basic_geom.glsl
index ffd747ab1eb..a88681a5fd3 100644
--- a/source/blender/gpu/shaders/gpu_shader_basic_geom.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_basic_geom.glsl
@@ -1,6 +1,6 @@
/*
-* Used the implementation of wide lines of Timo Suoranta (http://neure.dy.fi/wideline.html)
-*/
+ * Used the implementation of wide lines of Timo Suoranta (http://neure.dy.fi/wideline.html)
+ */
#define PASSTHROUGH 0
@@ -24,72 +24,72 @@ uniform int stipple_factor;
void main(void)
{
- vec2 window_size = viewport.zw;
- vec4 start = gl_in[0].gl_Position;
- vec4 end = gl_in[1].gl_Position;
+ vec2 window_size = viewport.zw;
+ vec4 start = gl_in[0].gl_Position;
+ vec4 end = gl_in[1].gl_Position;
#if PASSTHROUGH
- gl_Position = start; EmitVertex();
- gl_Position = end; EmitVertex();
- EndPrimitive();
- return;
+ gl_Position = start; EmitVertex();
+ gl_Position = end; EmitVertex();
+ EndPrimitive();
+ return;
#endif
-/* t = 0 t = ~(len(end - start) + 2*line_width)
- * A-------------------------------------B
- * | | | |
- * | side | |
- * | | | |
- * |--axis--*start--------------*end-----|
- * | | | |
- * | | | |
- * | | | |
- * D-------------------------------------C
- */
-
- /* Clip the line before homogenization.
- * Compute line start and end distances to nearplane in clipspace
- * Distances are t0 = dot(start, plane) and t1 = dot(end, plane)
- */
- float t0 = start.z + start.w;
- float t1 = end.z + end.w;
- if(t0 < 0.0) {
- if(t1 < 0.0) {
- return;
- }
- start = mix(start, end, (0 - t0) / (t1 - t0));
- }
- if(t1 < 0.0) {
- end = mix(start, end, (0 - t0) / (t1 - t0));
- }
-
- /* Compute line axis and side vector in screen space */
- vec2 startInNDC = start.xy / start.w; /* clip to NDC: homogenize and drop z */
- vec2 endInNDC = end.xy / end.w;
- vec2 lineInNDC = endInNDC - startInNDC;
- vec2 lineInScreen = lineInNDC * window_size; /* ndc to screen (direction vector) */
-
- vec2 axisInScreen = normalize(lineInScreen);
- vec2 sideInScreen = vec2(-axisInScreen.y, axisInScreen.x); /* rotate */
- vec2 axisInNDC = axisInScreen / window_size; /* screen to NDC */
- vec2 sideInNDC = sideInScreen / window_size;
- vec4 axis = vec4(axisInNDC, 0.0, 0.0) * line_width; /* NDC to clip (delta vector) */
- vec4 side = vec4(sideInNDC, 0.0, 0.0) * line_width;
-
- vec4 A = (start + (side - axis) * start.w);
- vec4 B = (end + (side + axis) * end.w);
- vec4 C = (end - (side - axis) * end.w);
- vec4 D = (start - (side + axis) * start.w);
-
- /* There is no relation between lines yet */
- /* TODO Pass here t0 to make continuous pattern. */
- t0 = 0;
- t1 = (length(lineInScreen) + 2*line_width)/ (2*line_width * stipple_factor);
-
- gl_Position = A; t = t0; varying_vertex_color = varying_vertex_color_line[0]; EmitVertex();
- gl_Position = D; t = t0; varying_vertex_color = varying_vertex_color_line[0]; EmitVertex();
- gl_Position = B; t = t1; varying_vertex_color = varying_vertex_color_line[1]; EmitVertex();
- gl_Position = C; t = t1; varying_vertex_color = varying_vertex_color_line[1]; EmitVertex();
- EndPrimitive();
+ /* t = 0 t = ~(len(end - start) + 2*line_width)
+ * A-------------------------------------B
+ * | | | |
+ * | side | |
+ * | | | |
+ * |--axis--*start--------------*end-----|
+ * | | | |
+ * | | | |
+ * | | | |
+ * D-------------------------------------C
+ */
+
+ /* Clip the line before homogenization.
+ * Compute line start and end distances to nearplane in clipspace
+ * Distances are t0 = dot(start, plane) and t1 = dot(end, plane)
+ */
+ float t0 = start.z + start.w;
+ float t1 = end.z + end.w;
+ if (t0 < 0.0) {
+ if (t1 < 0.0) {
+ return;
+ }
+ start = mix(start, end, (0 - t0) / (t1 - t0));
+ }
+ if (t1 < 0.0) {
+ end = mix(start, end, (0 - t0) / (t1 - t0));
+ }
+
+ /* Compute line axis and side vector in screen space */
+ vec2 startInNDC = start.xy / start.w; /* clip to NDC: homogenize and drop z */
+ vec2 endInNDC = end.xy / end.w;
+ vec2 lineInNDC = endInNDC - startInNDC;
+ vec2 lineInScreen = lineInNDC * window_size; /* ndc to screen (direction vector) */
+
+ vec2 axisInScreen = normalize(lineInScreen);
+ vec2 sideInScreen = vec2(-axisInScreen.y, axisInScreen.x); /* rotate */
+ vec2 axisInNDC = axisInScreen / window_size; /* screen to NDC */
+ vec2 sideInNDC = sideInScreen / window_size;
+ vec4 axis = vec4(axisInNDC, 0.0, 0.0) * line_width; /* NDC to clip (delta vector) */
+ vec4 side = vec4(sideInNDC, 0.0, 0.0) * line_width;
+
+ vec4 A = (start + (side - axis) * start.w);
+ vec4 B = (end + (side + axis) * end.w);
+ vec4 C = (end - (side - axis) * end.w);
+ vec4 D = (start - (side + axis) * start.w);
+
+ /* There is no relation between lines yet */
+ /* TODO Pass here t0 to make continuous pattern. */
+ t0 = 0;
+ t1 = (length(lineInScreen) + 2 * line_width) / (2 * line_width * stipple_factor);
+
+ gl_Position = A; t = t0; varying_vertex_color = varying_vertex_color_line[0]; EmitVertex();
+ gl_Position = D; t = t0; varying_vertex_color = varying_vertex_color_line[0]; EmitVertex();
+ gl_Position = B; t = t1; varying_vertex_color = varying_vertex_color_line[1]; EmitVertex();
+ gl_Position = C; t = t1; varying_vertex_color = varying_vertex_color_line[1]; EmitVertex();
+ EndPrimitive();
}
#else
diff --git a/source/blender/gpu/shaders/gpu_shader_basic_vert.glsl b/source/blender/gpu/shaders/gpu_shader_basic_vert.glsl
index 04900001998..cef28ea3026 100644
--- a/source/blender/gpu/shaders/gpu_shader_basic_vert.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_basic_vert.glsl
@@ -39,7 +39,7 @@ void main()
#ifdef CLIP_WORKAROUND
int i;
- for(i = 0; i < 6; i++)
+ for (i = 0; i < 6; i++)
gl_ClipDistance[i] = dot(co, gl_ClipPlane[i]);
#elif !defined(GPU_ATI)
// Setting gl_ClipVertex is necessary to get glClipPlane working on NVIDIA
diff --git a/source/blender/gpu/shaders/gpu_shader_fx_dof_frag.glsl b/source/blender/gpu/shaders/gpu_shader_fx_dof_frag.glsl
index e9dab04de5d..338ef6d51a7 100644
--- a/source/blender/gpu/shaders/gpu_shader_fx_dof_frag.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_fx_dof_frag.glsl
@@ -115,9 +115,9 @@ void second_pass()
color += texture2D(colorbuffer, uvcoordsvar.xy + invrendertargetdim) * 0.234375;
color += texture2D(colorbuffer, uvcoordsvar.xy + 2.5 * invrendertargetdim) * 0.09375;
color += texture2D(colorbuffer, uvcoordsvar.xy + 4.5 * invrendertargetdim) * 0.015625;
- color += texture2D(colorbuffer, uvcoordsvar.xy -invrendertargetdim) * 0.234375;
- color += texture2D(colorbuffer, uvcoordsvar.xy -2.5 * invrendertargetdim) * 0.09375;
- color += texture2D(colorbuffer, uvcoordsvar.xy -4.5 * invrendertargetdim) * 0.015625;
+ color += texture2D(colorbuffer, uvcoordsvar.xy - invrendertargetdim) * 0.234375;
+ color += texture2D(colorbuffer, uvcoordsvar.xy - 2.5 * invrendertargetdim) * 0.09375;
+ color += texture2D(colorbuffer, uvcoordsvar.xy - 4.5 * invrendertargetdim) * 0.015625;
gl_FragColor = color;
}
@@ -128,7 +128,7 @@ void third_pass()
{
vec4 color = texture2D(colorbuffer, uvcoordsvar.xy);
vec4 color_blurred = texture2D(blurredcolorbuffer, uvcoordsvar.xy);
- float coc = 2.0 * max(color_blurred.a, color.a); - color.a;
+ float coc = 2.0 * max(color_blurred.a, color.a); -color.a;
gl_FragColor = vec4(color.rgb, coc);
}
@@ -146,7 +146,7 @@ void fourth_pass()
vec4 small_sample_blur(in sampler2D colorbuffer, in vec2 uv, in vec4 color)
{
- float weight = 1.0/ 17.0;
+ float weight = 1.0 / 17.0;
vec4 result = weight * color;
weight *= 4.0;
diff --git a/source/blender/gpu/shaders/gpu_shader_fx_dof_hq_frag.glsl b/source/blender/gpu/shaders/gpu_shader_fx_dof_hq_frag.glsl
index e315d2fb97a..182113367d3 100644
--- a/source/blender/gpu/shaders/gpu_shader_fx_dof_hq_frag.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_fx_dof_hq_frag.glsl
@@ -102,7 +102,8 @@ void accumulate_pass(void) {
if (dof_params.w == 0.0)
r = 1.0;
else
- r = cos(M_PI / dof_params.w) / (cos(theta - (2.0 * M_PI / dof_params.w) * floor((dof_params.w * theta + M_PI) / (2.0 * M_PI))));
+ r = cos(M_PI / dof_params.w) /
+ (cos(theta - (2.0 * M_PI / dof_params.w) * floor((dof_params.w * theta + M_PI) / (2.0 * M_PI))));
if (dot(particlecoord, particlecoord) > r * r)
discard;
diff --git a/source/blender/gpu/shaders/gpu_shader_fx_dof_vert.glsl b/source/blender/gpu/shaders/gpu_shader_fx_dof_vert.glsl
index a2ef990c4e8..63b57d5775c 100644
--- a/source/blender/gpu/shaders/gpu_shader_fx_dof_vert.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_fx_dof_vert.glsl
@@ -38,8 +38,12 @@ void vert_dof_first_pass()
void vert_dof_fourth_pass()
{
vec4 halfpixel = vec4(-0.5, 0.5, -0.5, 0.5);
- uvcoordsvar = gl_MultiTexCoord0.xxyy + halfpixel * vec4(invrendertargetdim.x,
- invrendertargetdim.x, invrendertargetdim.y, invrendertargetdim.y);
+ uvcoordsvar = gl_MultiTexCoord0.xxyy +
+ halfpixel *
+ vec4(invrendertargetdim.x,
+ invrendertargetdim.x,
+ invrendertargetdim.y,
+ invrendertargetdim.y);
gl_Position = gl_Vertex;
}
diff --git a/source/blender/gpu/shaders/gpu_shader_fx_ssao_frag.glsl b/source/blender/gpu/shaders/gpu_shader_fx_ssao_frag.glsl
index 494a74dcdf8..054a2f795ee 100644
--- a/source/blender/gpu/shaders/gpu_shader_fx_ssao_frag.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_fx_ssao_frag.glsl
@@ -44,7 +44,8 @@ float calculate_ssao_factor(float depth)
vec3 position = get_view_space_from_depth(uvcoordsvar.xy, viewvecs[0].xyz, viewvecs[1].xyz, depth);
vec3 normal = calculate_view_space_normal(position);
- // find the offset in screen space by multiplying a point in camera space at the depth of the point by the projection matrix.
+ /* find the offset in screen space by multiplying a point
+ * in camera space at the depth of the point by the projection matrix. */
vec2 offset;
float homcoord = gl_ProjectionMatrix[2][3] * position.z + gl_ProjectionMatrix[3][3];
offset.x = gl_ProjectionMatrix[0][0] * ssao_params.x / homcoord;
@@ -76,7 +77,7 @@ float calculate_ssao_factor(float depth)
/* use minor bias here to avoid self shadowing */
if (f > 0.05 * len + 0.0001)
- factor += f * 1.0/(len * (1.0 + len * len * ssao_params.z));
+ factor += f * 1.0 / (len * (1.0 + len * len * ssao_params.z));
}
}
diff --git a/source/blender/gpu/shaders/gpu_shader_geometry.glsl b/source/blender/gpu/shaders/gpu_shader_geometry.glsl
index 16fba0dd055..1663915549c 100644
--- a/source/blender/gpu/shaders/gpu_shader_geometry.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_geometry.glsl
@@ -49,7 +49,7 @@ void emit_flat(int index, vec3 normal)
varposition = outpt.v.position.xyz;
/* TODO(sergey): Only uniform subdivisions atm. */
- vec2 quadst[4] = vec2[](vec2(0,0), vec2(1,0), vec2(1,1), vec2(0,1));
+ vec2 quadst[4] = vec2[](vec2(0, 0), vec2(1, 0), vec2(1, 1), vec2(0, 1));
vec2 st = quadst[index];
INTERP_FACE_VARYING_2(outpt.v.uv, osd_active_uv_offset, st);
@@ -70,7 +70,7 @@ void emit_smooth(int index)
varposition = outpt.v.position.xyz;
/* TODO(sergey): Only uniform subdivisions atm. */
- vec2 quadst[4] = vec2[](vec2(0,0), vec2(1,0), vec2(1,1), vec2(0,1));
+ vec2 quadst[4] = vec2[](vec2(0, 0), vec2(1, 0), vec2(1, 1), vec2(0, 1));
vec2 st = quadst[index];
INTERP_FACE_VARYING_2(outpt.v.uv, osd_active_uv_offset, st);
diff --git a/source/blender/gpu/shaders/gpu_shader_material.glsl b/source/blender/gpu/shaders/gpu_shader_material.glsl
index dcb888b1a9b..9914c4bb362 100644
--- a/source/blender/gpu/shaders/gpu_shader_material.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_material.glsl
@@ -3,7 +3,7 @@
float convert_rgba_to_float(vec4 color)
{
#ifdef USE_NEW_SHADING
- return color.r*0.2126 + color.g*0.7152 + color.b*0.0722;
+ return color.r * 0.2126 + color.g * 0.7152 + color.b * 0.0722;
#else
return (color.r + color.g + color.b) / 3.0;
#endif
@@ -16,17 +16,17 @@ float exp_blender(float f)
float compatible_pow(float x, float y)
{
- if(y == 0.0) /* x^0 -> 1, including 0^0 */
+ if (y == 0.0) /* x^0 -> 1, including 0^0 */
return 1.0;
/* glsl pow doesn't accept negative x */
- if(x < 0.0) {
- if(mod(-y, 2.0) == 0.0)
+ if (x < 0.0) {
+ if (mod(-y, 2.0) == 0.0)
return pow(-x, y);
else
return -pow(-x, y);
}
- else if(x == 0.0)
+ else if (x == 0.0)
return 0.0;
return pow(x, y);
@@ -39,11 +39,11 @@ void rgb_to_hsv(vec4 rgb, out vec4 outcol)
cmax = max(rgb[0], max(rgb[1], rgb[2]));
cmin = min(rgb[0], min(rgb[1], rgb[2]));
- cdelta = cmax-cmin;
+ cdelta = cmax - cmin;
v = cmax;
- if (cmax!=0.0)
- s = cdelta/cmax;
+ if (cmax != 0.0)
+ s = cdelta / cmax;
else {
s = 0.0;
h = 0.0;
@@ -53,15 +53,15 @@ void rgb_to_hsv(vec4 rgb, out vec4 outcol)
h = 0.0;
}
else {
- c = (vec3(cmax, cmax, cmax) - rgb.xyz)/cdelta;
+ c = (vec3(cmax, cmax, cmax) - rgb.xyz) / cdelta;
- if (rgb.x==cmax) h = c[2] - c[1];
- else if (rgb.y==cmax) h = 2.0 + c[0] - c[2];
+ if (rgb.x == cmax) h = c[2] - c[1];
+ else if (rgb.y == cmax) h = 2.0 + c[0] - c[2];
else h = 4.0 + c[1] - c[0];
h /= 6.0;
- if (h<0.0)
+ if (h < 0.0)
h += 1.0;
}
@@ -77,21 +77,21 @@ void hsv_to_rgb(vec4 hsv, out vec4 outcol)
s = hsv[1];
v = hsv[2];
- if(s==0.0) {
+ if (s == 0.0) {
rgb = vec3(v, v, v);
}
else {
- if(h==1.0)
+ if (h == 1.0)
h = 0.0;
-
+
h *= 6.0;
i = floor(h);
f = h - i;
rgb = vec3(f, f, f);
- p = v*(1.0-s);
- q = v*(1.0-(s*f));
- t = v*(1.0-(s*(1.0-f)));
-
+ p = v * (1.0 - s);
+ q = v * (1.0 - (s * f));
+ t = v * (1.0 - (s * (1.0 - f)));
+
if (i == 0.0) rgb = vec3(v, t, p);
else if (i == 1.0) rgb = vec3(q, v, p);
else if (i == 2.0) rgb = vec3(p, v, t);
@@ -105,18 +105,18 @@ void hsv_to_rgb(vec4 hsv, out vec4 outcol)
float srgb_to_linearrgb(float c)
{
- if(c < 0.04045)
- return (c < 0.0) ? 0.0: c * (1.0 / 12.92);
+ if (c < 0.04045)
+ return (c < 0.0) ? 0.0 : c * (1.0 / 12.92);
else
- return pow((c + 0.055)*(1.0/1.055), 2.4);
+ return pow((c + 0.055) * (1.0 / 1.055), 2.4);
}
float linearrgb_to_srgb(float c)
{
- if(c < 0.0031308)
- return (c < 0.0) ? 0.0: c * 12.92;
+ if (c < 0.0031308)
+ return (c < 0.0) ? 0.0 : c * 12.92;
else
- return 1.055 * pow(c, 1.0/2.4) - 0.055;
+ return 1.055 * pow(c, 1.0 / 2.4) - 0.055;
}
void srgb_to_linearrgb(vec4 col_from, out vec4 col_to)
@@ -142,6 +142,20 @@ void color_to_normal(vec3 color, out vec3 normal)
normal.z = 2.0 * ((color.b) - 0.5);
}
+void color_to_normal_new_shading(vec3 color, out vec3 normal)
+{
+ normal.x = 2.0 * ((color.r) - 0.5);
+ normal.y = 2.0 * ((color.g) - 0.5);
+ normal.z = 2.0 * ((color.b) - 0.5);
+}
+
+void color_to_blender_normal_new_shading(vec3 color, out vec3 normal)
+{
+ normal.x = 2.0 * ((color.r) - 0.5);
+ normal.y = -2.0 * ((color.g) - 0.5);
+ normal.z = -2.0 * ((color.b) - 0.5);
+}
+
#define M_PI 3.14159265358979323846
#define M_1_PI 0.31830988618379069
@@ -149,38 +163,44 @@ void color_to_normal(vec3 color, out vec3 normal)
void vcol_attribute(vec4 attvcol, out vec4 vcol)
{
- vcol = vec4(attvcol.x/255.0, attvcol.y/255.0, attvcol.z/255.0, 1.0);
+ vcol = vec4(attvcol.x, attvcol.y, attvcol.z, 1.0);
}
void uv_attribute(vec2 attuv, out vec3 uv)
{
- uv = vec3(attuv*2.0 - vec2(1.0, 1.0), 0.0);
+ uv = vec3(attuv * 2.0 - vec2(1.0, 1.0), 0.0);
}
-void geom(vec3 co, vec3 nor, mat4 viewinvmat, vec3 attorco, vec2 attuv, vec4 attvcol, out vec3 global, out vec3 local, out vec3 view, out vec3 orco, out vec3 uv, out vec3 normal, out vec4 vcol, out float vcol_alpha, out float frontback)
+void geom(
+ vec3 co, vec3 nor, mat4 viewinvmat, vec3 attorco, vec2 attuv, vec4 attvcol,
+ out vec3 global, out vec3 local, out vec3 view, out vec3 orco, out vec3 uv,
+ out vec3 normal, out vec4 vcol, out float vcol_alpha, out float frontback)
{
local = co;
- view = (gl_ProjectionMatrix[3][3] == 0.0)? normalize(local): vec3(0.0, 0.0, -1.0);
- global = (viewinvmat*vec4(local, 1.0)).xyz;
+ view = (gl_ProjectionMatrix[3][3] == 0.0) ? normalize(local) : vec3(0.0, 0.0, -1.0);
+ global = (viewinvmat * vec4(local, 1.0)).xyz;
orco = attorco;
uv_attribute(attuv, uv);
- normal = -normalize(nor); /* blender render normal is negated */
+ normal = -normalize(nor); /* blender render normal is negated */
vcol_attribute(attvcol, vcol);
srgb_to_linearrgb(vcol, vcol);
vcol_alpha = attvcol.a;
- frontback = (gl_FrontFacing)? 1.0: 0.0;
+ frontback = (gl_FrontFacing) ? 1.0 : 0.0;
}
-void particle_info(vec4 sprops, vec3 loc, vec3 vel, vec3 avel, out float index, out float age, out float life_time, out vec3 location, out float size, out vec3 velocity, out vec3 angular_velocity)
+void particle_info(
+ vec4 sprops, vec3 loc, vec3 vel, vec3 avel,
+ out float index, out float age, out float life_time, out vec3 location,
+ out float size, out vec3 velocity, out vec3 angular_velocity)
{
- index = sprops.x;
- age = sprops.y;
- life_time = sprops.z;
- size = sprops.w;
+ index = sprops.x;
+ age = sprops.y;
+ life_time = sprops.z;
+ size = sprops.w;
- location = loc;
- velocity = vel;
- angular_velocity = avel;
+ location = loc;
+ velocity = vel;
+ angular_velocity = avel;
}
void vect_normalize(vec3 vin, out vec3 vout)
@@ -190,20 +210,56 @@ void vect_normalize(vec3 vin, out vec3 vout)
void direction_transform_m4v3(vec3 vin, mat4 mat, out vec3 vout)
{
- vout = (mat*vec4(vin, 0.0)).xyz;
+ vout = (mat * vec4(vin, 0.0)).xyz;
}
void point_transform_m4v3(vec3 vin, mat4 mat, out vec3 vout)
{
- vout = (mat*vec4(vin, 1.0)).xyz;
+ vout = (mat * vec4(vin, 1.0)).xyz;
+}
+
+void point_texco_remap_square(vec3 vin, out vec3 vout)
+{
+ vout = vec3(vin - vec3(0.5, 0.5, 0.5)) * 2.0;
+}
+
+void point_map_to_sphere(vec3 vin, out vec3 vout)
+{
+ float len = length(vin);
+ float v, u;
+ if (len > 0.0) {
+ if (vin.x == 0.0 && vin.y == 0.0)
+ u = 0.0;
+ else
+ u = (1.0 - atan(vin.x, vin.y) / M_PI) / 2.0;
+
+ v = 1.0 - acos(vin.z / len) / M_PI;
+ }
+ else
+ v = u = 0.0;
+
+ vout = vec3(u, v, 0.0);
+}
+
+void point_map_to_tube(vec3 vin, out vec3 vout)
+{
+ float u, v;
+ v = (vin.z + 1.0) * 0.5;
+ float len = sqrt(vin.x * vin.x + vin.y * vin[1]);
+ if (len > 0.0)
+ u = (1.0 - (atan(vin.x / len, vin.y / len) / M_PI)) * 0.5;
+ else
+ v = u = 0.0;
+
+ vout = vec3(u, v, 0.0);
}
void mapping(vec3 vec, mat4 mat, vec3 minvec, vec3 maxvec, float domin, float domax, out vec3 outvec)
{
outvec = (mat * vec4(vec, 1.0)).xyz;
- if(domin == 1.0)
+ if (domin == 1.0)
outvec = max(outvec, minvec);
- if(domax == 1.0)
+ if (domax == 1.0)
outvec = min(outvec, maxvec);
}
@@ -214,7 +270,9 @@ void camera(vec3 co, out vec3 outview, out float outdepth, out float outdist)
outview = normalize(co);
}
-void lamp(vec4 col, float energy, vec3 lv, float dist, vec3 shadow, float visifac, out vec4 outcol, out vec3 outlv, out float outdist, out vec4 outshadow, out float outvisifac)
+void lamp(
+ vec4 col, float energy, vec3 lv, float dist, vec3 shadow, float visifac,
+ out vec4 outcol, out vec3 outlv, out float outdist, out vec4 outshadow, out float outvisifac)
{
outcol = col * energy;
outlv = lv;
@@ -299,10 +357,10 @@ void math_pow(float val1, float val2, out float outval)
void math_log(float val1, float val2, out float outval)
{
- if(val1 > 0.0 && val2 > 0.0)
- outval= log2(val1) / log2(val2);
+ if (val1 > 0.0 && val2 > 0.0)
+ outval = log2(val1) / log2(val2);
else
- outval= 0.0;
+ outval = 0.0;
}
void math_max(float val1, float val2, out float outval)
@@ -317,12 +375,12 @@ void math_min(float val1, float val2, out float outval)
void math_round(float val, out float outval)
{
- outval= floor(val + 0.5);
+ outval = floor(val + 0.5);
}
void math_less_than(float val1, float val2, out float outval)
{
- if(val1 < val2)
+ if (val1 < val2)
outval = 1.0;
else
outval = 0.0;
@@ -330,7 +388,7 @@ void math_less_than(float val1, float val2, out float outval)
void math_greater_than(float val1, float val2, out float outval)
{
- if(val1 > val2)
+ if (val1 > val2)
outval = 1.0;
else
outval = 0.0;
@@ -350,24 +408,24 @@ void math_modulo(float val1, float val2, out float outval)
void math_abs(float val1, out float outval)
{
- outval = abs(val1);
+ outval = abs(val1);
}
void squeeze(float val, float width, float center, out float outval)
{
- outval = 1.0/(1.0 + pow(2.71828183, -((val-center)*width)));
+ outval = 1.0 / (1.0 + pow(2.71828183, -((val - center) * width)));
}
void vec_math_add(vec3 v1, vec3 v2, out vec3 outvec, out float outval)
{
outvec = v1 + v2;
- outval = (abs(outvec[0]) + abs(outvec[1]) + abs(outvec[2]))/3.0;
+ outval = (abs(outvec[0]) + abs(outvec[1]) + abs(outvec[2])) / 3.0;
}
void vec_math_sub(vec3 v1, vec3 v2, out vec3 outvec, out float outval)
{
outvec = v1 - v2;
- outval = (abs(outvec[0]) + abs(outvec[1]) + abs(outvec[2]))/3.0;
+ outval = (abs(outvec[0]) + abs(outvec[1]) + abs(outvec[2])) / 3.0;
}
void vec_math_average(vec3 v1, vec3 v2, out vec3 outvec, out float outval)
@@ -378,7 +436,7 @@ void vec_math_average(vec3 v1, vec3 v2, out vec3 outvec, out float outval)
}
void vec_math_mix(float strength, vec3 v1, vec3 v2, out vec3 outvec)
{
- outvec = strength*v1 + (1 - strength) * v2;
+ outvec = strength * v1 + (1 - strength) * v2;
}
void vec_math_dot(vec3 v1, vec3 v2, out vec3 outvec, out float outval)
@@ -407,8 +465,8 @@ void vec_math_negate(vec3 v, out vec3 outv)
void invert_z(vec3 v, out vec3 outv)
{
- v.z = -v.z;
- outv = v;
+ v.z = -v.z;
+ outv = v;
}
void normal(vec3 dir, vec3 nor, out vec3 outnor, out float outdot)
@@ -425,12 +483,12 @@ void normal_new_shading(vec3 dir, vec3 nor, out vec3 outnor, out float outdot)
void curves_vec(float fac, vec3 vec, sampler2D curvemap, out vec3 outvec)
{
- outvec.x = texture2D(curvemap, vec2((vec.x + 1.0)*0.5, 0.0)).x;
- outvec.y = texture2D(curvemap, vec2((vec.y + 1.0)*0.5, 0.0)).y;
- outvec.z = texture2D(curvemap, vec2((vec.z + 1.0)*0.5, 0.0)).z;
+ outvec.x = texture2D(curvemap, vec2((vec.x + 1.0) * 0.5, 0.0)).x;
+ outvec.y = texture2D(curvemap, vec2((vec.y + 1.0) * 0.5, 0.0)).y;
+ outvec.z = texture2D(curvemap, vec2((vec.z + 1.0) * 0.5, 0.0)).z;
if (fac != 1.0)
- outvec = (outvec*fac) + (vec*(1.0-fac));
+ outvec = (outvec * fac) + (vec * (1.0 - fac));
}
@@ -441,7 +499,7 @@ void curves_rgb(float fac, vec4 col, sampler2D curvemap, out vec4 outcol)
outcol.b = texture2D(curvemap, vec2(texture2D(curvemap, vec2(col.b, 0.0)).a, 0.0)).b;
if (fac != 1.0)
- outcol = (outcol*fac) + (col*(1.0-fac));
+ outcol = (outcol * fac) + (col * (1.0 - fac));
outcol.a = col.a;
}
@@ -494,11 +552,11 @@ void set_rgba_one(out vec4 outval)
void brightness_contrast(vec4 col, float brightness, float contrast, out vec4 outcol)
{
float a = 1.0 + contrast;
- float b = brightness - contrast*0.5;
+ float b = brightness - contrast * 0.5;
- outcol.r = max(a*col.r + b, 0.0);
- outcol.g = max(a*col.g + b, 0.0);
- outcol.b = max(a*col.b + b, 0.0);
+ outcol.r = max(a * col.r + b, 0.0);
+ outcol.g = max(a * col.g + b, 0.0);
+ outcol.b = max(a * col.b + b, 0.0);
outcol.a = col.a;
}
@@ -528,7 +586,7 @@ void mix_screen(float fac, vec4 col1, vec4 col2, out vec4 outcol)
fac = clamp(fac, 0.0, 1.0);
float facm = 1.0 - fac;
- outcol = vec4(1.0) - (vec4(facm) + fac*(vec4(1.0) - col2))*(vec4(1.0) - col1);
+ outcol = vec4(1.0) - (vec4(facm) + fac * (vec4(1.0) - col2)) * (vec4(1.0) - col1);
outcol.a = col1.a;
}
@@ -539,20 +597,20 @@ void mix_overlay(float fac, vec4 col1, vec4 col2, out vec4 outcol)
outcol = col1;
- if(outcol.r < 0.5)
- outcol.r *= facm + 2.0*fac*col2.r;
+ if (outcol.r < 0.5)
+ outcol.r *= facm + 2.0 * fac * col2.r;
else
- outcol.r = 1.0 - (facm + 2.0*fac*(1.0 - col2.r))*(1.0 - outcol.r);
+ outcol.r = 1.0 - (facm + 2.0 * fac * (1.0 - col2.r)) * (1.0 - outcol.r);
- if(outcol.g < 0.5)
- outcol.g *= facm + 2.0*fac*col2.g;
+ if (outcol.g < 0.5)
+ outcol.g *= facm + 2.0 * fac * col2.g;
else
- outcol.g = 1.0 - (facm + 2.0*fac*(1.0 - col2.g))*(1.0 - outcol.g);
+ outcol.g = 1.0 - (facm + 2.0 * fac * (1.0 - col2.g)) * (1.0 - outcol.g);
- if(outcol.b < 0.5)
- outcol.b *= facm + 2.0*fac*col2.b;
+ if (outcol.b < 0.5)
+ outcol.b *= facm + 2.0 * fac * col2.b;
else
- outcol.b = 1.0 - (facm + 2.0*fac*(1.0 - col2.b))*(1.0 - outcol.b);
+ outcol.b = 1.0 - (facm + 2.0 * fac * (1.0 - col2.b)) * (1.0 - outcol.b);
}
void mix_sub(float fac, vec4 col1, vec4 col2, out vec4 outcol)
@@ -569,9 +627,9 @@ void mix_div(float fac, vec4 col1, vec4 col2, out vec4 outcol)
outcol = col1;
- if(col2.r != 0.0) outcol.r = facm*outcol.r + fac*outcol.r/col2.r;
- if(col2.g != 0.0) outcol.g = facm*outcol.g + fac*outcol.g/col2.g;
- if(col2.b != 0.0) outcol.b = facm*outcol.b + fac*outcol.b/col2.b;
+ if (col2.r != 0.0) outcol.r = facm * outcol.r + fac * outcol.r / col2.r;
+ if (col2.g != 0.0) outcol.g = facm * outcol.g + fac * outcol.g / col2.g;
+ if (col2.b != 0.0) outcol.b = facm * outcol.b + fac * outcol.b / col2.b;
}
void mix_diff(float fac, vec4 col1, vec4 col2, out vec4 outcol)
@@ -584,14 +642,14 @@ void mix_diff(float fac, vec4 col1, vec4 col2, out vec4 outcol)
void mix_dark(float fac, vec4 col1, vec4 col2, out vec4 outcol)
{
fac = clamp(fac, 0.0, 1.0);
- outcol.rgb = min(col1.rgb, col2.rgb*fac);
+ outcol.rgb = min(col1.rgb, col2.rgb * fac);
outcol.a = col1.a;
}
void mix_light(float fac, vec4 col1, vec4 col2, out vec4 outcol)
{
fac = clamp(fac, 0.0, 1.0);
- outcol.rgb = max(col1.rgb, col2.rgb*fac);
+ outcol.rgb = max(col1.rgb, col2.rgb * fac);
outcol.a = col1.a;
}
@@ -600,29 +658,29 @@ void mix_dodge(float fac, vec4 col1, vec4 col2, out vec4 outcol)
fac = clamp(fac, 0.0, 1.0);
outcol = col1;
- if(outcol.r != 0.0) {
- float tmp = 1.0 - fac*col2.r;
- if(tmp <= 0.0)
+ if (outcol.r != 0.0) {
+ float tmp = 1.0 - fac * col2.r;
+ if (tmp <= 0.0)
outcol.r = 1.0;
- else if((tmp = outcol.r/tmp) > 1.0)
+ else if ((tmp = outcol.r / tmp) > 1.0)
outcol.r = 1.0;
else
outcol.r = tmp;
}
- if(outcol.g != 0.0) {
- float tmp = 1.0 - fac*col2.g;
- if(tmp <= 0.0)
+ if (outcol.g != 0.0) {
+ float tmp = 1.0 - fac * col2.g;
+ if (tmp <= 0.0)
outcol.g = 1.0;
- else if((tmp = outcol.g/tmp) > 1.0)
+ else if ((tmp = outcol.g / tmp) > 1.0)
outcol.g = 1.0;
else
outcol.g = tmp;
}
- if(outcol.b != 0.0) {
- float tmp = 1.0 - fac*col2.b;
- if(tmp <= 0.0)
+ if (outcol.b != 0.0) {
+ float tmp = 1.0 - fac * col2.b;
+ if (tmp <= 0.0)
outcol.b = 1.0;
- else if((tmp = outcol.b/tmp) > 1.0)
+ else if ((tmp = outcol.b / tmp) > 1.0)
outcol.b = 1.0;
else
outcol.b = tmp;
@@ -636,32 +694,32 @@ void mix_burn(float fac, vec4 col1, vec4 col2, out vec4 outcol)
outcol = col1;
- tmp = facm + fac*col2.r;
- if(tmp <= 0.0)
+ tmp = facm + fac * col2.r;
+ if (tmp <= 0.0)
outcol.r = 0.0;
- else if((tmp = (1.0 - (1.0 - outcol.r)/tmp)) < 0.0)
+ else if ((tmp = (1.0 - (1.0 - outcol.r) / tmp)) < 0.0)
outcol.r = 0.0;
- else if(tmp > 1.0)
+ else if (tmp > 1.0)
outcol.r = 1.0;
else
outcol.r = tmp;
- tmp = facm + fac*col2.g;
- if(tmp <= 0.0)
+ tmp = facm + fac * col2.g;
+ if (tmp <= 0.0)
outcol.g = 0.0;
- else if((tmp = (1.0 - (1.0 - outcol.g)/tmp)) < 0.0)
+ else if ((tmp = (1.0 - (1.0 - outcol.g) / tmp)) < 0.0)
outcol.g = 0.0;
- else if(tmp > 1.0)
+ else if (tmp > 1.0)
outcol.g = 1.0;
else
outcol.g = tmp;
- tmp = facm + fac*col2.b;
- if(tmp <= 0.0)
+ tmp = facm + fac * col2.b;
+ if (tmp <= 0.0)
outcol.b = 0.0;
- else if((tmp = (1.0 - (1.0 - outcol.b)/tmp)) < 0.0)
+ else if ((tmp = (1.0 - (1.0 - outcol.b) / tmp)) < 0.0)
outcol.b = 0.0;
- else if(tmp > 1.0)
+ else if (tmp > 1.0)
outcol.b = 1.0;
else
outcol.b = tmp;
@@ -677,10 +735,10 @@ void mix_hue(float fac, vec4 col1, vec4 col2, out vec4 outcol)
vec4 hsv, hsv2, tmp;
rgb_to_hsv(col2, hsv2);
- if(hsv2.y != 0.0) {
+ if (hsv2.y != 0.0) {
rgb_to_hsv(outcol, hsv);
hsv.x = hsv2.x;
- hsv_to_rgb(hsv, tmp);
+ hsv_to_rgb(hsv, tmp);
outcol = mix(outcol, tmp, fac);
outcol.a = col1.a;
@@ -697,10 +755,10 @@ void mix_sat(float fac, vec4 col1, vec4 col2, out vec4 outcol)
vec4 hsv, hsv2;
rgb_to_hsv(outcol, hsv);
- if(hsv.y != 0.0) {
+ if (hsv.y != 0.0) {
rgb_to_hsv(col2, hsv2);
- hsv.y = facm*hsv.y + fac*hsv2.y;
+ hsv.y = facm * hsv.y + fac * hsv2.y;
hsv_to_rgb(hsv, outcol);
}
}
@@ -714,7 +772,7 @@ void mix_val(float fac, vec4 col1, vec4 col2, out vec4 outcol)
rgb_to_hsv(col1, hsv);
rgb_to_hsv(col2, hsv2);
- hsv.z = facm*hsv.z + fac*hsv2.z;
+ hsv.z = facm * hsv.z + fac * hsv2.z;
hsv_to_rgb(hsv, outcol);
}
@@ -728,11 +786,11 @@ void mix_color(float fac, vec4 col1, vec4 col2, out vec4 outcol)
vec4 hsv, hsv2, tmp;
rgb_to_hsv(col2, hsv2);
- if(hsv2.y != 0.0) {
+ if (hsv2.y != 0.0) {
rgb_to_hsv(outcol, hsv);
hsv.x = hsv2.x;
hsv.y = hsv2.y;
- hsv_to_rgb(hsv, tmp);
+ hsv_to_rgb(hsv, tmp);
outcol = mix(outcol, tmp, fac);
outcol.a = col1.a;
@@ -744,16 +802,16 @@ void mix_soft(float fac, vec4 col1, vec4 col2, out vec4 outcol)
fac = clamp(fac, 0.0, 1.0);
float facm = 1.0 - fac;
- vec4 one= vec4(1.0);
- vec4 scr= one - (one - col2)*(one - col1);
- outcol = facm*col1 + fac*((one - col1)*col2*col1 + col1*scr);
+ vec4 one = vec4(1.0);
+ vec4 scr = one - (one - col2) * (one - col1);
+ outcol = facm * col1 + fac * ((one - col1) * col2 * col1 + col1 * scr);
}
void mix_linear(float fac, vec4 col1, vec4 col2, out vec4 outcol)
{
fac = clamp(fac, 0.0, 1.0);
- outcol = col1 + fac*(2.0*(col2 - vec4(0.5)));
+ outcol = col1 + fac * (2.0 * (col2 - vec4(0.5)));
}
void valtorgb(float fac, sampler2D colormap, out vec4 outcol, out float outalpha)
@@ -762,12 +820,12 @@ void valtorgb(float fac, sampler2D colormap, out vec4 outcol, out float outalpha
outalpha = outcol.a;
}
-void rgbtobw(vec4 color, out float outval)
+void rgbtobw(vec4 color, out float outval)
{
#ifdef USE_NEW_SHADING
- outval = color.r*0.2126 + color.g*0.7152 + color.b*0.0722;
+ outval = color.r * 0.2126 + color.g * 0.7152 + color.b * 0.0722;
#else
- outval = color.r*0.35 + color.g*0.45 + color.b*0.2; /* keep these factors in sync with texture.h:RGBTOBW */
+ outval = color.r * 0.35 + color.g * 0.45 + color.b * 0.2; /* keep these factors in sync with texture.h:RGBTOBW */
#endif
}
@@ -794,11 +852,11 @@ void hue_sat(float hue, float sat, float value, float fac, vec4 col, out vec4 ou
rgb_to_hsv(col, hsv);
hsv[0] += (hue - 0.5);
- if(hsv[0]>1.0) hsv[0]-=1.0; else if(hsv[0]<0.0) hsv[0]+= 1.0;
+ if (hsv[0] > 1.0) hsv[0] -= 1.0; else if (hsv[0] < 0.0) hsv[0] += 1.0;
hsv[1] *= sat;
- if(hsv[1]>1.0) hsv[1]= 1.0; else if(hsv[1]<0.0) hsv[1]= 0.0;
+ if (hsv[1] > 1.0) hsv[1] = 1.0; else if (hsv[1] < 0.0) hsv[1] = 0.0;
hsv[2] *= value;
- if(hsv[2]>1.0) hsv[2]= 1.0; else if(hsv[2]<0.0) hsv[2]= 0.0;
+ if (hsv[2] > 1.0) hsv[2] = 1.0; else if (hsv[2] < 0.0) hsv[2] = 0.0;
hsv_to_rgb(hsv, outcol);
@@ -858,19 +916,19 @@ void texture_flip_blend(vec3 vec, out vec3 outvec)
void texture_blend_lin(vec3 vec, out float outval)
{
- outval = (1.0+vec.x)/2.0;
+ outval = (1.0 + vec.x) / 2.0;
}
void texture_blend_quad(vec3 vec, out float outval)
{
- outval = max((1.0+vec.x)/2.0, 0.0);
+ outval = max((1.0 + vec.x) / 2.0, 0.0);
outval *= outval;
}
void texture_wood_sin(vec3 vec, out float value, out vec4 color, out vec3 normal)
{
- float a = sqrt(vec.x*vec.x + vec.y*vec.y + vec.z*vec.z)*20.0;
- float wi = 0.5 + 0.5*sin(a);
+ float a = sqrt(vec.x * vec.x + vec.y * vec.y + vec.z * vec.z) * 20.0;
+ float wi = 0.5 + 0.5 * sin(a);
value = wi;
color = vec4(wi, wi, wi, 1.0);
@@ -879,12 +937,12 @@ void texture_wood_sin(vec3 vec, out float value, out vec4 color, out vec3 normal
void texture_image(vec3 vec, sampler2D ima, out float value, out vec4 color, out vec3 normal)
{
- color = texture2D(ima, (vec.xy + vec2(1.0, 1.0))*0.5);
+ color = texture2D(ima, (vec.xy + vec2(1.0, 1.0)) * 0.5);
value = color.a;
- normal.x = 2.0*(color.r - 0.5);
- normal.y = 2.0*(0.5 - color.g);
- normal.z = 2.0*(color.b - 0.5);
+ normal.x = 2.0 * (color.r - 0.5);
+ normal.y = 2.0 * (0.5 - color.g);
+ normal.z = 2.0 * (color.b - 0.5);
}
/************* MTEX *****************/
@@ -915,17 +973,17 @@ void texco_tangent(vec4 tangent, out vec3 outtangent)
void texco_global(mat4 viewinvmat, vec3 co, out vec3 global)
{
- global = (viewinvmat*vec4(co, 1.0)).xyz;
+ global = (viewinvmat * vec4(co, 1.0)).xyz;
}
void texco_object(mat4 viewinvmat, mat4 obinvmat, vec3 co, out vec3 object)
{
- object = (obinvmat*(viewinvmat*vec4(co, 1.0))).xyz;
+ object = (obinvmat * (viewinvmat * vec4(co, 1.0))).xyz;
}
void texco_refl(vec3 vn, vec3 view, out vec3 ref)
{
- ref = view - 2.0*dot(vn, view)*vn;
+ ref = view - 2.0 * dot(vn, view) * vn;
}
void shade_norm(vec3 normal, out vec3 outnormal)
@@ -936,7 +994,7 @@ void shade_norm(vec3 normal, out vec3 outnormal)
void mtex_mirror(vec3 tcol, vec4 refcol, float tin, float colmirfac, out vec4 outrefcol)
{
- outrefcol = mix(refcol, vec4(1.0, tcol), tin*colmirfac);
+ outrefcol = mix(refcol, vec4(1.0, tcol), tin * colmirfac);
}
void mtex_rgb_blend(vec3 outcol, vec3 texcol, float fact, float facg, out vec3 incol)
@@ -944,9 +1002,9 @@ void mtex_rgb_blend(vec3 outcol, vec3 texcol, float fact, float facg, out vec3 i
float facm;
fact *= facg;
- facm = 1.0-fact;
+ facm = 1.0 - fact;
- incol = fact*texcol + facm*outcol;
+ incol = fact * texcol + facm * outcol;
}
void mtex_rgb_mul(vec3 outcol, vec3 texcol, float fact, float facg, out vec3 incol)
@@ -954,9 +1012,9 @@ void mtex_rgb_mul(vec3 outcol, vec3 texcol, float fact, float facg, out vec3 inc
float facm;
fact *= facg;
- facm = 1.0-fact;
+ facm = 1.0 - fact;
- incol = (facm + fact*texcol)*outcol;
+ incol = (facm + fact * texcol) * outcol;
}
void mtex_rgb_screen(vec3 outcol, vec3 texcol, float fact, float facg, out vec3 incol)
@@ -964,9 +1022,9 @@ void mtex_rgb_screen(vec3 outcol, vec3 texcol, float fact, float facg, out vec3
float facm;
fact *= facg;
- facm = 1.0-fact;
+ facm = 1.0 - fact;
- incol = vec3(1.0) - (vec3(facm) + fact*(vec3(1.0) - texcol))*(vec3(1.0) - outcol);
+ incol = vec3(1.0) - (vec3(facm) + fact * (vec3(1.0) - texcol)) * (vec3(1.0) - outcol);
}
void mtex_rgb_overlay(vec3 outcol, vec3 texcol, float fact, float facg, out vec3 incol)
@@ -974,32 +1032,32 @@ void mtex_rgb_overlay(vec3 outcol, vec3 texcol, float fact, float facg, out vec3
float facm;
fact *= facg;
- facm = 1.0-fact;
+ facm = 1.0 - fact;
- if(outcol.r < 0.5)
- incol.r = outcol.r*(facm + 2.0*fact*texcol.r);
+ if (outcol.r < 0.5)
+ incol.r = outcol.r * (facm + 2.0 * fact * texcol.r);
else
- incol.r = 1.0 - (facm + 2.0*fact*(1.0 - texcol.r))*(1.0 - outcol.r);
+ incol.r = 1.0 - (facm + 2.0 * fact * (1.0 - texcol.r)) * (1.0 - outcol.r);
- if(outcol.g < 0.5)
- incol.g = outcol.g*(facm + 2.0*fact*texcol.g);
+ if (outcol.g < 0.5)
+ incol.g = outcol.g * (facm + 2.0 * fact * texcol.g);
else
- incol.g = 1.0 - (facm + 2.0*fact*(1.0 - texcol.g))*(1.0 - outcol.g);
+ incol.g = 1.0 - (facm + 2.0 * fact * (1.0 - texcol.g)) * (1.0 - outcol.g);
- if(outcol.b < 0.5)
- incol.b = outcol.b*(facm + 2.0*fact*texcol.b);
+ if (outcol.b < 0.5)
+ incol.b = outcol.b * (facm + 2.0 * fact * texcol.b);
else
- incol.b = 1.0 - (facm + 2.0*fact*(1.0 - texcol.b))*(1.0 - outcol.b);
+ incol.b = 1.0 - (facm + 2.0 * fact * (1.0 - texcol.b)) * (1.0 - outcol.b);
}
void mtex_rgb_sub(vec3 outcol, vec3 texcol, float fact, float facg, out vec3 incol)
{
- incol = -fact*facg*texcol + outcol;
+ incol = -fact * facg * texcol + outcol;
}
void mtex_rgb_add(vec3 outcol, vec3 texcol, float fact, float facg, out vec3 incol)
{
- incol = fact*facg*texcol + outcol;
+ incol = fact * facg * texcol + outcol;
}
void mtex_rgb_div(vec3 outcol, vec3 texcol, float fact, float facg, out vec3 incol)
@@ -1007,11 +1065,11 @@ void mtex_rgb_div(vec3 outcol, vec3 texcol, float fact, float facg, out vec3 inc
float facm;
fact *= facg;
- facm = 1.0-fact;
+ facm = 1.0 - fact;
- if(texcol.r != 0.0) incol.r = facm*outcol.r + fact*outcol.r/texcol.r;
- if(texcol.g != 0.0) incol.g = facm*outcol.g + fact*outcol.g/texcol.g;
- if(texcol.b != 0.0) incol.b = facm*outcol.b + fact*outcol.b/texcol.b;
+ if (texcol.r != 0.0) incol.r = facm * outcol.r + fact * outcol.r / texcol.r;
+ if (texcol.g != 0.0) incol.g = facm * outcol.g + fact * outcol.g / texcol.g;
+ if (texcol.b != 0.0) incol.b = facm * outcol.b + fact * outcol.b / texcol.b;
}
void mtex_rgb_diff(vec3 outcol, vec3 texcol, float fact, float facg, out vec3 incol)
@@ -1019,9 +1077,9 @@ void mtex_rgb_diff(vec3 outcol, vec3 texcol, float fact, float facg, out vec3 in
float facm;
fact *= facg;
- facm = 1.0-fact;
+ facm = 1.0 - fact;
- incol = facm*outcol + fact*abs(texcol - outcol);
+ incol = facm * outcol + fact * abs(texcol - outcol);
}
void mtex_rgb_dark(vec3 outcol, vec3 texcol, float fact, float facg, out vec3 incol)
@@ -1029,7 +1087,7 @@ void mtex_rgb_dark(vec3 outcol, vec3 texcol, float fact, float facg, out vec3 in
float facm, col;
fact *= facg;
- facm = 1.0-fact;
+ facm = 1.0 - fact;
incol.r = min(outcol.r, texcol.r) * fact + outcol.r * facm;
incol.g = min(outcol.g, texcol.g) * fact + outcol.g * facm;
@@ -1042,19 +1100,19 @@ void mtex_rgb_light(vec3 outcol, vec3 texcol, float fact, float facg, out vec3 i
fact *= facg;
- col = fact*texcol.r;
- if(col > outcol.r) incol.r = col; else incol.r = outcol.r;
- col = fact*texcol.g;
- if(col > outcol.g) incol.g = col; else incol.g = outcol.g;
- col = fact*texcol.b;
- if(col > outcol.b) incol.b = col; else incol.b = outcol.b;
+ col = fact * texcol.r;
+ if (col > outcol.r) incol.r = col; else incol.r = outcol.r;
+ col = fact * texcol.g;
+ if (col > outcol.g) incol.g = col; else incol.g = outcol.g;
+ col = fact * texcol.b;
+ if (col > outcol.b) incol.b = col; else incol.b = outcol.b;
}
void mtex_rgb_hue(vec3 outcol, vec3 texcol, float fact, float facg, out vec3 incol)
{
vec4 col;
- mix_hue(fact*facg, vec4(outcol, 1.0), vec4(texcol, 1.0), col);
+ mix_hue(fact * facg, vec4(outcol, 1.0), vec4(texcol, 1.0), col);
incol.rgb = col.rgb;
}
@@ -1062,7 +1120,7 @@ void mtex_rgb_sat(vec3 outcol, vec3 texcol, float fact, float facg, out vec3 inc
{
vec4 col;
- mix_sat(fact*facg, vec4(outcol, 1.0), vec4(texcol, 1.0), col);
+ mix_sat(fact * facg, vec4(outcol, 1.0), vec4(texcol, 1.0), col);
incol.rgb = col.rgb;
}
@@ -1070,7 +1128,7 @@ void mtex_rgb_val(vec3 outcol, vec3 texcol, float fact, float facg, out vec3 inc
{
vec4 col;
- mix_val(fact*facg, vec4(outcol, 1.0), vec4(texcol, 1.0), col);
+ mix_val(fact * facg, vec4(outcol, 1.0), vec4(texcol, 1.0), col);
incol.rgb = col.rgb;
}
@@ -1078,7 +1136,7 @@ void mtex_rgb_color(vec3 outcol, vec3 texcol, float fact, float facg, out vec3 i
{
vec4 col;
- mix_color(fact*facg, vec4(outcol, 1.0), vec4(texcol, 1.0), col);
+ mix_color(fact * facg, vec4(outcol, 1.0), vec4(texcol, 1.0), col);
incol.rgb = col.rgb;
}
@@ -1087,39 +1145,39 @@ void mtex_rgb_soft(vec3 outcol, vec3 texcol, float fact, float facg, out vec3 in
float facm;
fact *= facg;
- facm = 1.0-fact;
+ facm = 1.0 - fact;
vec3 one = vec3(1.0);
- vec3 scr = one - (one - texcol)*(one - outcol);
- incol = facm*outcol + fact*((one - texcol)*outcol*texcol + outcol*scr);
+ vec3 scr = one - (one - texcol) * (one - outcol);
+ incol = facm * outcol + fact * ((one - texcol) * outcol * texcol + outcol * scr);
}
void mtex_rgb_linear(vec3 outcol, vec3 texcol, float fact, float facg, out vec3 incol)
{
fact *= facg;
- if(texcol.r > 0.5)
- incol.r = outcol.r + fact*(2.0*(texcol.r - 0.5));
+ if (texcol.r > 0.5)
+ incol.r = outcol.r + fact * (2.0 * (texcol.r - 0.5));
else
- incol.r = outcol.r + fact*(2.0*(texcol.r) - 1.0);
+ incol.r = outcol.r + fact * (2.0 * (texcol.r) - 1.0);
- if(texcol.g > 0.5)
- incol.g = outcol.g + fact*(2.0*(texcol.g - 0.5));
+ if (texcol.g > 0.5)
+ incol.g = outcol.g + fact * (2.0 * (texcol.g - 0.5));
else
- incol.g = outcol.g + fact*(2.0*(texcol.g) - 1.0);
+ incol.g = outcol.g + fact * (2.0 * (texcol.g) - 1.0);
- if(texcol.b > 0.5)
- incol.b = outcol.b + fact*(2.0*(texcol.b - 0.5));
+ if (texcol.b > 0.5)
+ incol.b = outcol.b + fact * (2.0 * (texcol.b - 0.5));
else
- incol.b = outcol.b + fact*(2.0*(texcol.b) - 1.0);
+ incol.b = outcol.b + fact * (2.0 * (texcol.b) - 1.0);
}
void mtex_value_vars(inout float fact, float facg, out float facm)
{
fact *= abs(facg);
- facm = 1.0-fact;
+ facm = 1.0 - fact;
- if(facg < 0.0) {
+ if (facg < 0.0) {
float tmp = fact;
fact = facm;
facm = tmp;
@@ -1131,7 +1189,7 @@ void mtex_value_blend(float outcol, float texcol, float fact, float facg, out fl
float facm;
mtex_value_vars(fact, facg, facm);
- incol = fact*texcol + facm*outcol;
+ incol = fact * texcol + facm * outcol;
}
void mtex_value_mul(float outcol, float texcol, float fact, float facg, out float incol)
@@ -1140,7 +1198,7 @@ void mtex_value_mul(float outcol, float texcol, float fact, float facg, out floa
mtex_value_vars(fact, facg, facm);
facm = 1.0 - facg;
- incol = (facm + fact*texcol)*outcol;
+ incol = (facm + fact * texcol) * outcol;
}
void mtex_value_screen(float outcol, float texcol, float fact, float facg, out float incol)
@@ -1149,7 +1207,7 @@ void mtex_value_screen(float outcol, float texcol, float fact, float facg, out f
mtex_value_vars(fact, facg, facm);
facm = 1.0 - facg;
- incol = 1.0 - (facm + fact*(1.0 - texcol))*(1.0 - outcol);
+ incol = 1.0 - (facm + fact * (1.0 - texcol)) * (1.0 - outcol);
}
void mtex_value_sub(float outcol, float texcol, float fact, float facg, out float incol)
@@ -1158,7 +1216,7 @@ void mtex_value_sub(float outcol, float texcol, float fact, float facg, out floa
mtex_value_vars(fact, facg, facm);
fact = -fact;
- incol = fact*texcol + outcol;
+ incol = fact * texcol + outcol;
}
void mtex_value_add(float outcol, float texcol, float fact, float facg, out float incol)
@@ -1167,7 +1225,7 @@ void mtex_value_add(float outcol, float texcol, float fact, float facg, out floa
mtex_value_vars(fact, facg, facm);
fact = fact;
- incol = fact*texcol + outcol;
+ incol = fact * texcol + outcol;
}
void mtex_value_div(float outcol, float texcol, float fact, float facg, out float incol)
@@ -1175,8 +1233,8 @@ void mtex_value_div(float outcol, float texcol, float fact, float facg, out floa
float facm;
mtex_value_vars(fact, facg, facm);
- if(texcol != 0.0)
- incol = facm*outcol + fact*outcol/texcol;
+ if (texcol != 0.0)
+ incol = facm * outcol + fact * outcol / texcol;
else
incol = 0.0;
}
@@ -1186,7 +1244,7 @@ void mtex_value_diff(float outcol, float texcol, float fact, float facg, out flo
float facm;
mtex_value_vars(fact, facg, facm);
- incol = facm*outcol + fact*abs(texcol - outcol);
+ incol = facm * outcol + fact * abs(texcol - outcol);
}
void mtex_value_dark(float outcol, float texcol, float fact, float facg, out float incol)
@@ -1194,7 +1252,7 @@ void mtex_value_dark(float outcol, float texcol, float fact, float facg, out flo
float facm;
mtex_value_vars(fact, facg, facm);
- incol = facm*outcol + fact*min(outcol, texcol);
+ incol = facm * outcol + fact * min(outcol, texcol);
}
void mtex_value_light(float outcol, float texcol, float fact, float facg, out float incol)
@@ -1202,8 +1260,8 @@ void mtex_value_light(float outcol, float texcol, float fact, float facg, out fl
float facm;
mtex_value_vars(fact, facg, facm);
- float col = fact*texcol;
- if(col > outcol) incol = col; else incol = outcol;
+ float col = fact * texcol;
+ if (col > outcol) incol = col; else incol = outcol;
}
void mtex_value_clamp_positive(float fac, out float outfac)
@@ -1218,15 +1276,15 @@ void mtex_value_clamp(float fac, out float outfac)
void mtex_har_divide(float har, out float outhar)
{
- outhar = har/128.0;
+ outhar = har / 128.0;
}
void mtex_har_multiply_clamp(float har, out float outhar)
{
har *= 128.0;
- if(har < 1.0) outhar = 1.0;
- else if(har > 511.0) outhar = 511.0;
+ if (har < 1.0) outhar = 1.0;
+ else if (har > 511.0) outhar = 511.0;
else outhar = har;
}
@@ -1242,7 +1300,7 @@ void mtex_alpha_to_col(vec4 col, float alpha, out vec4 outcol)
void mtex_alpha_multiply_value(vec4 col, float value, out vec4 outcol)
{
- outcol = vec4(col.rgb, col.a * value);
+ outcol = vec4(col.rgb, col.a * value);
}
void mtex_rgbtoint(vec4 rgb, out float intensity)
@@ -1263,15 +1321,15 @@ void mtex_rgb_invert(vec4 inrgb, out vec4 outrgb)
void mtex_value_stencil(float stencil, float intensity, out float outstencil, out float outintensity)
{
float fact = intensity;
- outintensity = intensity*stencil;
- outstencil = stencil*fact;
+ outintensity = intensity * stencil;
+ outstencil = stencil * fact;
}
void mtex_rgb_stencil(float stencil, vec4 rgb, out float outstencil, out vec4 outrgb)
{
float fact = rgb.a;
- outrgb = vec4(rgb.rgb, rgb.a*stencil);
- outstencil = stencil*fact;
+ outrgb = vec4(rgb.rgb, rgb.a * stencil);
+ outstencil = stencil * fact;
}
void mtex_mapping_ofs(vec3 texco, vec3 ofs, out vec3 outtexco)
@@ -1281,17 +1339,17 @@ void mtex_mapping_ofs(vec3 texco, vec3 ofs, out vec3 outtexco)
void mtex_mapping_size(vec3 texco, vec3 size, out vec3 outtexco)
{
- outtexco = size*texco;
+ outtexco = size * texco;
}
void mtex_2d_mapping(vec3 vec, out vec3 outvec)
{
- outvec = vec3(vec.xy*0.5 + vec2(0.5), vec.z);
+ outvec = vec3(vec.xy * 0.5 + vec2(0.5), vec.z);
}
vec3 mtex_2d_mapping(vec3 vec)
{
- return vec3(vec.xy*0.5 + vec2(0.5), vec.z);
+ return vec3(vec.xy * 0.5 + vec2(0.5), vec.z);
}
void mtex_cube_map(vec3 co, samplerCube ima, out float value, out vec4 color)
@@ -1300,7 +1358,9 @@ void mtex_cube_map(vec3 co, samplerCube ima, out float value, out vec4 color)
value = 1.0;
}
-void mtex_cube_map_refl(samplerCube ima, vec3 vp, vec3 vn, mat4 viewmatrixinverse, mat4 viewmatrix, out float value, out vec4 color)
+void mtex_cube_map_refl(
+ samplerCube ima, vec3 vp, vec3 vn, mat4 viewmatrixinverse, mat4 viewmatrix,
+ out float value, out vec4 color)
{
vec3 viewdirection = vec3(viewmatrixinverse * vec4(vp, 0.0));
vec3 normaldirection = normalize(vec3(vec4(vn, 0.0) * viewmatrix));
@@ -1323,10 +1383,10 @@ void mtex_normal(vec3 texco, sampler2D ima, out vec3 normal)
// the normal used points inward.
// Should this ever change this negate must be removed.
vec4 color = texture2D(ima, texco.xy);
- normal = 2.0*(vec3(-color.r, color.g, color.b) - vec3(-0.5, 0.5, 0.5));
+ normal = 2.0 * (vec3(-color.r, color.g, color.b) - vec3(-0.5, 0.5, 0.5));
}
-void mtex_bump_normals_init( vec3 vN, out vec3 vNorg, out vec3 vNacc, out float fPrevMagnitude )
+void mtex_bump_normals_init(vec3 vN, out vec3 vNorg, out vec3 vNacc, out float fPrevMagnitude)
{
vNorg = vN;
vNacc = vN;
@@ -1343,171 +1403,175 @@ mat3 to_mat3(mat4 m4)
return m3;
}
-void mtex_bump_init_objspace( vec3 surf_pos, vec3 surf_norm,
- mat4 mView, mat4 mViewInv, mat4 mObj, mat4 mObjInv,
- float fPrevMagnitude_in, vec3 vNacc_in,
- out float fPrevMagnitude_out, out vec3 vNacc_out,
- out vec3 vR1, out vec3 vR2, out float fDet )
+void mtex_bump_init_objspace(
+ vec3 surf_pos, vec3 surf_norm,
+ mat4 mView, mat4 mViewInv, mat4 mObj, mat4 mObjInv,
+ float fPrevMagnitude_in, vec3 vNacc_in,
+ out float fPrevMagnitude_out, out vec3 vNacc_out,
+ out vec3 vR1, out vec3 vR2, out float fDet)
{
mat3 obj2view = to_mat3(gl_ModelViewMatrix);
mat3 view2obj = to_mat3(gl_ModelViewMatrixInverse);
-
- vec3 vSigmaS = view2obj * dFdx( surf_pos );
- vec3 vSigmaT = view2obj * dFdy( surf_pos );
- vec3 vN = normalize( surf_norm * obj2view );
- vR1 = cross( vSigmaT, vN );
- vR2 = cross( vN, vSigmaS ) ;
- fDet = dot ( vSigmaS, vR1 );
-
+ vec3 vSigmaS = view2obj * dFdx(surf_pos);
+ vec3 vSigmaT = view2obj * dFdy(surf_pos);
+ vec3 vN = normalize(surf_norm * obj2view);
+
+ vR1 = cross(vSigmaT, vN);
+ vR2 = cross(vN, vSigmaS);
+ fDet = dot(vSigmaS, vR1);
+
/* pretransform vNacc (in mtex_bump_apply) using the inverse transposed */
vR1 = vR1 * view2obj;
vR2 = vR2 * view2obj;
vN = vN * view2obj;
-
+
float fMagnitude = abs(fDet) * length(vN);
vNacc_out = vNacc_in * (fMagnitude / fPrevMagnitude_in);
fPrevMagnitude_out = fMagnitude;
}
-void mtex_bump_init_texturespace( vec3 surf_pos, vec3 surf_norm,
- float fPrevMagnitude_in, vec3 vNacc_in,
- out float fPrevMagnitude_out, out vec3 vNacc_out,
- out vec3 vR1, out vec3 vR2, out float fDet )
+void mtex_bump_init_texturespace(
+ vec3 surf_pos, vec3 surf_norm,
+ float fPrevMagnitude_in, vec3 vNacc_in,
+ out float fPrevMagnitude_out, out vec3 vNacc_out,
+ out vec3 vR1, out vec3 vR2, out float fDet)
{
- vec3 vSigmaS = dFdx( surf_pos );
- vec3 vSigmaT = dFdy( surf_pos );
+ vec3 vSigmaS = dFdx(surf_pos);
+ vec3 vSigmaT = dFdy(surf_pos);
vec3 vN = surf_norm; /* normalized interpolated vertex normal */
-
- vR1 = normalize( cross( vSigmaT, vN ) );
- vR2 = normalize( cross( vN, vSigmaS ) );
- fDet = sign( dot(vSigmaS, vR1) );
-
+
+ vR1 = normalize(cross(vSigmaT, vN));
+ vR2 = normalize(cross(vN, vSigmaS));
+ fDet = sign(dot(vSigmaS, vR1));
+
float fMagnitude = abs(fDet);
vNacc_out = vNacc_in * (fMagnitude / fPrevMagnitude_in);
fPrevMagnitude_out = fMagnitude;
}
-void mtex_bump_init_viewspace( vec3 surf_pos, vec3 surf_norm,
- float fPrevMagnitude_in, vec3 vNacc_in,
- out float fPrevMagnitude_out, out vec3 vNacc_out,
- out vec3 vR1, out vec3 vR2, out float fDet )
+void mtex_bump_init_viewspace(
+ vec3 surf_pos, vec3 surf_norm,
+ float fPrevMagnitude_in, vec3 vNacc_in,
+ out float fPrevMagnitude_out, out vec3 vNacc_out,
+ out vec3 vR1, out vec3 vR2, out float fDet)
{
- vec3 vSigmaS = dFdx( surf_pos );
- vec3 vSigmaT = dFdy( surf_pos );
+ vec3 vSigmaS = dFdx(surf_pos);
+ vec3 vSigmaT = dFdy(surf_pos);
vec3 vN = surf_norm; /* normalized interpolated vertex normal */
-
- vR1 = cross( vSigmaT, vN );
- vR2 = cross( vN, vSigmaS ) ;
- fDet = dot ( vSigmaS, vR1 );
-
+
+ vR1 = cross(vSigmaT, vN);
+ vR2 = cross(vN, vSigmaS);
+ fDet = dot(vSigmaS, vR1);
+
float fMagnitude = abs(fDet);
vNacc_out = vNacc_in * (fMagnitude / fPrevMagnitude_in);
fPrevMagnitude_out = fMagnitude;
}
-void mtex_bump_tap3( vec3 texco, sampler2D ima, float hScale,
- out float dBs, out float dBt )
+void mtex_bump_tap3(
+ vec3 texco, sampler2D ima, float hScale,
+ out float dBs, out float dBt)
{
vec2 STll = texco.xy;
- vec2 STlr = texco.xy + dFdx(texco.xy) ;
- vec2 STul = texco.xy + dFdy(texco.xy) ;
-
- float Hll,Hlr,Hul;
- rgbtobw( texture2D(ima, STll), Hll );
- rgbtobw( texture2D(ima, STlr), Hlr );
- rgbtobw( texture2D(ima, STul), Hul );
-
+ vec2 STlr = texco.xy + dFdx(texco.xy);
+ vec2 STul = texco.xy + dFdy(texco.xy);
+
+ float Hll, Hlr, Hul;
+ rgbtobw(texture2D(ima, STll), Hll);
+ rgbtobw(texture2D(ima, STlr), Hlr);
+ rgbtobw(texture2D(ima, STul), Hul);
+
dBs = hScale * (Hlr - Hll);
dBt = hScale * (Hul - Hll);
}
#ifdef BUMP_BICUBIC
-void mtex_bump_bicubic( vec3 texco, sampler2D ima, float hScale,
- out float dBs, out float dBt )
+void mtex_bump_bicubic(
+ vec3 texco, sampler2D ima, float hScale,
+ out float dBs, out float dBt )
{
float Hl;
float Hr;
float Hd;
float Hu;
-
+
vec2 TexDx = dFdx(texco.xy);
vec2 TexDy = dFdy(texco.xy);
-
- vec2 STl = texco.xy - 0.5 * TexDx ;
- vec2 STr = texco.xy + 0.5 * TexDx ;
- vec2 STd = texco.xy - 0.5 * TexDy ;
- vec2 STu = texco.xy + 0.5 * TexDy ;
-
+
+ vec2 STl = texco.xy - 0.5 * TexDx;
+ vec2 STr = texco.xy + 0.5 * TexDx;
+ vec2 STd = texco.xy - 0.5 * TexDy;
+ vec2 STu = texco.xy + 0.5 * TexDy;
+
rgbtobw(texture2D(ima, STl), Hl);
rgbtobw(texture2D(ima, STr), Hr);
rgbtobw(texture2D(ima, STd), Hd);
rgbtobw(texture2D(ima, STu), Hu);
-
+
vec2 dHdxy = vec2(Hr - Hl, Hu - Hd);
- float fBlend = clamp(1.0-textureQueryLOD(ima, texco.xy).x, 0.0, 1.0);
- if(fBlend!=0.0)
- {
+ float fBlend = clamp(1.0 - textureQueryLOD(ima, texco.xy).x, 0.0, 1.0);
+ if (fBlend != 0.0) {
// the derivative of the bicubic sampling of level 0
ivec2 vDim;
vDim = textureSize(ima, 0);
// taking the fract part of the texture coordinate is a hardcoded wrap mode.
- // this is acceptable as textures use wrap mode exclusively in 3D view elsewhere in blender.
+ // this is acceptable as textures use wrap mode exclusively in 3D view elsewhere in blender.
// this is done so that we can still get a valid texel with uvs outside the 0,1 range
// by texelFetch below, as coordinates are clamped when using this function.
- vec2 fTexLoc = vDim*fract(texco.xy) - vec2(0.5, 0.5);
+ vec2 fTexLoc = vDim * fract(texco.xy) - vec2(0.5, 0.5);
ivec2 iTexLoc = ivec2(floor(fTexLoc));
- vec2 t = clamp(fTexLoc - iTexLoc, 0.0, 1.0); // sat just to be pedantic
+ vec2 t = clamp(fTexLoc - iTexLoc, 0.0, 1.0); // sat just to be pedantic
/*******************************************************************************************
* This block will replace the one below when one channel textures are properly supported. *
*******************************************************************************************
- vec4 vSamplesUL = textureGather(ima, (iTexLoc+ivec2(-1,-1) + vec2(0.5,0.5))/vDim );
- vec4 vSamplesUR = textureGather(ima, (iTexLoc+ivec2(1,-1) + vec2(0.5,0.5))/vDim );
- vec4 vSamplesLL = textureGather(ima, (iTexLoc+ivec2(-1,1) + vec2(0.5,0.5))/vDim );
- vec4 vSamplesLR = textureGather(ima, (iTexLoc+ivec2(1,1) + vec2(0.5,0.5))/vDim );
+ vec4 vSamplesUL = textureGather(ima, (iTexLoc+ivec2(-1,-1) + vec2(0.5,0.5))/vDim);
+ vec4 vSamplesUR = textureGather(ima, (iTexLoc+ivec2(1,-1) + vec2(0.5,0.5))/vDim);
+ vec4 vSamplesLL = textureGather(ima, (iTexLoc+ivec2(-1,1) + vec2(0.5,0.5))/vDim);
+ vec4 vSamplesLR = textureGather(ima, (iTexLoc+ivec2(1,1) + vec2(0.5,0.5))/vDim);
mat4 H = mat4(vSamplesUL.w, vSamplesUL.x, vSamplesLL.w, vSamplesLL.x,
- vSamplesUL.z, vSamplesUL.y, vSamplesLL.z, vSamplesLL.y,
- vSamplesUR.w, vSamplesUR.x, vSamplesLR.w, vSamplesLR.x,
- vSamplesUR.z, vSamplesUR.y, vSamplesLR.z, vSamplesLR.y);
-*/
+ vSamplesUL.z, vSamplesUL.y, vSamplesLL.z, vSamplesLL.y,
+ vSamplesUR.w, vSamplesUR.x, vSamplesLR.w, vSamplesLR.x,
+ vSamplesUR.z, vSamplesUR.y, vSamplesLR.z, vSamplesLR.y);
+ */
ivec2 iTexLocMod = iTexLoc + ivec2(-1, -1);
mat4 H;
-
- for(int i = 0; i < 4; i++) {
- for(int j = 0; j < 4; j++) {
- ivec2 iTexTmp = iTexLocMod + ivec2(i,j);
-
+
+ for (int i = 0; i < 4; i++) {
+ for (int j = 0; j < 4; j++) {
+ ivec2 iTexTmp = iTexLocMod + ivec2(i, j);
+
// wrap texture coordinates manually for texelFetch to work on uvs oitside the 0,1 range.
// this is guaranteed to work since we take the fractional part of the uv above.
- iTexTmp.x = (iTexTmp.x < 0)? iTexTmp.x + vDim.x : ((iTexTmp.x >= vDim.x)? iTexTmp.x - vDim.x : iTexTmp.x);
- iTexTmp.y = (iTexTmp.y < 0)? iTexTmp.y + vDim.y : ((iTexTmp.y >= vDim.y)? iTexTmp.y - vDim.y : iTexTmp.y);
+ iTexTmp.x = (iTexTmp.x < 0) ? iTexTmp.x + vDim.x : ((iTexTmp.x >= vDim.x) ? iTexTmp.x - vDim.x : iTexTmp.x);
+ iTexTmp.y = (iTexTmp.y < 0) ? iTexTmp.y + vDim.y : ((iTexTmp.y >= vDim.y) ? iTexTmp.y - vDim.y : iTexTmp.y);
rgbtobw(texelFetch(ima, iTexTmp, 0), H[i][j]);
}
}
-
+
float x = t.x, y = t.y;
float x2 = x * x, x3 = x2 * x, y2 = y * y, y3 = y2 * y;
- vec4 X = vec4(-0.5*(x3+x)+x2, 1.5*x3-2.5*x2+1, -1.5*x3+2*x2+0.5*x, 0.5*(x3-x2));
- vec4 Y = vec4(-0.5*(y3+y)+y2, 1.5*y3-2.5*y2+1, -1.5*y3+2*y2+0.5*y, 0.5*(y3-y2));
- vec4 dX = vec4(-1.5*x2+2*x-0.5, 4.5*x2-5*x, -4.5*x2+4*x+0.5, 1.5*x2-x);
- vec4 dY = vec4(-1.5*y2+2*y-0.5, 4.5*y2-5*y, -4.5*y2+4*y+0.5, 1.5*y2-y);
-
+ vec4 X = vec4(-0.5 * (x3 + x) + x2, 1.5 * x3 - 2.5 * x2 + 1, -1.5 * x3 + 2 * x2 + 0.5 * x, 0.5 * (x3 - x2));
+ vec4 Y = vec4(-0.5 * (y3 + y) + y2, 1.5 * y3 - 2.5 * y2 + 1, -1.5 * y3 + 2 * y2 + 0.5 * y, 0.5 * (y3 - y2));
+ vec4 dX = vec4(-1.5 * x2 + 2 * x - 0.5, 4.5 * x2 - 5 * x, -4.5 * x2 + 4 * x + 0.5, 1.5 * x2 - x);
+ vec4 dY = vec4(-1.5 * y2 + 2 * y - 0.5, 4.5 * y2 - 5 * y, -4.5 * y2 + 4 * y + 0.5, 1.5 * y2 - y);
+
// complete derivative in normalized coordinates (mul by vDim)
vec2 dHdST = vDim * vec2(dot(Y, H * dX), dot(dY, H * X));
// transform derivative to screen-space
- vec2 dHdxy_bicubic = vec2( dHdST.x * TexDx.x + dHdST.y * TexDx.y,
- dHdST.x * TexDy.x + dHdST.y * TexDy.y );
+ vec2 dHdxy_bicubic = vec2(dHdST.x * TexDx.x + dHdST.y * TexDx.y,
+ dHdST.x * TexDy.x + dHdST.y * TexDy.y);
// blend between the two
- dHdxy = dHdxy*(1-fBlend) + dHdxy_bicubic*fBlend;
+ dHdxy = dHdxy * (1 - fBlend) + dHdxy_bicubic * fBlend;
}
dBs = hScale * dHdxy.x;
@@ -1516,67 +1580,71 @@ void mtex_bump_bicubic( vec3 texco, sampler2D ima, float hScale,
#endif
-void mtex_bump_tap5( vec3 texco, sampler2D ima, float hScale,
- out float dBs, out float dBt )
+void mtex_bump_tap5(
+ vec3 texco, sampler2D ima, float hScale,
+ out float dBs, out float dBt)
{
vec2 TexDx = dFdx(texco.xy);
vec2 TexDy = dFdy(texco.xy);
vec2 STc = texco.xy;
- vec2 STl = texco.xy - 0.5 * TexDx ;
- vec2 STr = texco.xy + 0.5 * TexDx ;
- vec2 STd = texco.xy - 0.5 * TexDy ;
- vec2 STu = texco.xy + 0.5 * TexDy ;
-
- float Hc,Hl,Hr,Hd,Hu;
- rgbtobw( texture2D(ima, STc), Hc );
- rgbtobw( texture2D(ima, STl), Hl );
- rgbtobw( texture2D(ima, STr), Hr );
- rgbtobw( texture2D(ima, STd), Hd );
- rgbtobw( texture2D(ima, STu), Hu );
-
+ vec2 STl = texco.xy - 0.5 * TexDx;
+ vec2 STr = texco.xy + 0.5 * TexDx;
+ vec2 STd = texco.xy - 0.5 * TexDy;
+ vec2 STu = texco.xy + 0.5 * TexDy;
+
+ float Hc, Hl, Hr, Hd, Hu;
+ rgbtobw(texture2D(ima, STc), Hc);
+ rgbtobw(texture2D(ima, STl), Hl);
+ rgbtobw(texture2D(ima, STr), Hr);
+ rgbtobw(texture2D(ima, STd), Hd);
+ rgbtobw(texture2D(ima, STu), Hu);
+
dBs = hScale * (Hr - Hl);
dBt = hScale * (Hu - Hd);
}
-void mtex_bump_deriv( vec3 texco, sampler2D ima, float ima_x, float ima_y, float hScale,
- out float dBs, out float dBt )
+void mtex_bump_deriv(
+ vec3 texco, sampler2D ima, float ima_x, float ima_y, float hScale,
+ out float dBs, out float dBt)
{
- float s = 1.0; // negate this if flipped texture coordinate
+ float s = 1.0; // negate this if flipped texture coordinate
vec2 TexDx = dFdx(texco.xy);
vec2 TexDy = dFdy(texco.xy);
-
+
// this variant using a derivative map is described here
// http://mmikkelsen3d.blogspot.com/2011/07/derivative-maps.html
vec2 dim = vec2(ima_x, ima_y);
- vec2 dBduv = hScale*dim*(2.0*texture2D(ima, texco.xy).xy-1.0);
-
- dBs = dBduv.x*TexDx.x + s*dBduv.y*TexDx.y;
- dBt = dBduv.x*TexDy.x + s*dBduv.y*TexDy.y;
+ vec2 dBduv = hScale * dim * (2.0 * texture2D(ima, texco.xy).xy - 1.0);
+
+ dBs = dBduv.x * TexDx.x + s * dBduv.y * TexDx.y;
+ dBt = dBduv.x * TexDy.x + s * dBduv.y * TexDy.y;
}
-void mtex_bump_apply( float fDet, float dBs, float dBt, vec3 vR1, vec3 vR2, vec3 vNacc_in,
- out vec3 vNacc_out, out vec3 perturbed_norm )
+void mtex_bump_apply(
+ float fDet, float dBs, float dBt, vec3 vR1, vec3 vR2, vec3 vNacc_in,
+ out vec3 vNacc_out, out vec3 perturbed_norm)
{
- vec3 vSurfGrad = sign(fDet) * ( dBs * vR1 + dBt * vR2 );
-
+ vec3 vSurfGrad = sign(fDet) * (dBs * vR1 + dBt * vR2);
+
vNacc_out = vNacc_in - vSurfGrad;
- perturbed_norm = normalize( vNacc_out );
+ perturbed_norm = normalize(vNacc_out);
}
-void mtex_bump_apply_texspace( float fDet, float dBs, float dBt, vec3 vR1, vec3 vR2,
- sampler2D ima, vec3 texco, float ima_x, float ima_y, vec3 vNacc_in,
- out vec3 vNacc_out, out vec3 perturbed_norm )
+void mtex_bump_apply_texspace(
+ float fDet, float dBs, float dBt, vec3 vR1, vec3 vR2,
+ sampler2D ima, vec3 texco, float ima_x, float ima_y, vec3 vNacc_in,
+ out vec3 vNacc_out, out vec3 perturbed_norm)
{
vec2 TexDx = dFdx(texco.xy);
vec2 TexDy = dFdy(texco.xy);
- vec3 vSurfGrad = sign(fDet) * (
- dBs / length( vec2(ima_x*TexDx.x, ima_y*TexDx.y) ) * vR1 +
- dBt / length( vec2(ima_x*TexDy.x, ima_y*TexDy.y) ) * vR2 );
-
+ vec3 vSurfGrad = sign(fDet) * (
+ dBs / length(vec2(ima_x * TexDx.x, ima_y * TexDx.y)) * vR1 +
+ dBt / length(vec2(ima_x * TexDy.x, ima_y * TexDy.y)) * vR2);
+
vNacc_out = vNacc_in - vSurfGrad;
- perturbed_norm = normalize( vNacc_out );
+ perturbed_norm = normalize(vNacc_out);
}
void mtex_negate_texnormal(vec3 normal, out vec3 outnormal)
@@ -1588,13 +1656,13 @@ void mtex_nspace_tangent(vec4 tangent, vec3 normal, vec3 texnormal, out vec3 out
{
vec3 B = tangent.w * cross(normal, tangent.xyz);
- outnormal = texnormal.x*tangent.xyz + texnormal.y*B + texnormal.z*normal;
+ outnormal = texnormal.x * tangent.xyz + texnormal.y * B + texnormal.z * normal;
outnormal = normalize(outnormal);
}
void mtex_nspace_world(mat4 viewmat, vec3 texnormal, out vec3 outnormal)
{
- outnormal = normalize((viewmat*vec4(texnormal, 0.0)).xyz);
+ outnormal = normalize((viewmat * vec4(texnormal, 0.0)).xyz);
}
void mtex_nspace_object(vec3 texnormal, out vec3 outnormal)
@@ -1604,7 +1672,7 @@ void mtex_nspace_object(vec3 texnormal, out vec3 outnormal)
void mtex_blend_normal(float norfac, vec3 normal, vec3 newnormal, out vec3 outnormal)
{
- outnormal = (1.0 - norfac)*normal + norfac*newnormal;
+ outnormal = (1.0 - norfac) * normal + norfac * newnormal;
outnormal = normalize(outnormal);
}
@@ -1627,26 +1695,26 @@ void lamp_visibility_other(vec3 co, vec3 lampco, out vec3 lv, out float dist, ou
void lamp_falloff_invlinear(float lampdist, float dist, out float visifac)
{
- visifac = lampdist/(lampdist + dist);
+ visifac = lampdist / (lampdist + dist);
}
void lamp_falloff_invsquare(float lampdist, float dist, out float visifac)
{
- visifac = lampdist/(lampdist + dist*dist);
+ visifac = lampdist / (lampdist + dist * dist);
}
void lamp_falloff_sliders(float lampdist, float ld1, float ld2, float dist, out float visifac)
{
- float lampdistkw = lampdist*lampdist;
+ float lampdistkw = lampdist * lampdist;
- visifac = lampdist/(lampdist + ld1*dist);
- visifac *= lampdistkw/(lampdistkw + ld2*dist*dist);
+ visifac = lampdist / (lampdist + ld1 * dist);
+ visifac *= lampdistkw / (lampdistkw + ld2 * dist * dist);
}
void lamp_falloff_invcoefficients(float coeff_const, float coeff_lin, float coeff_quad, float dist, out float visifac)
{
vec3 coeff = vec3(coeff_const, coeff_lin, coeff_quad);
- vec3 d_coeff = vec3(1.0, dist, dist*dist);
+ vec3 d_coeff = vec3(1.0, dist, dist * dist);
float visifac_r = dot(coeff, d_coeff);
if (visifac_r > 0.0)
visifac = 1.0 / visifac_r;
@@ -1656,25 +1724,25 @@ void lamp_falloff_invcoefficients(float coeff_const, float coeff_lin, float coef
void lamp_falloff_curve(float lampdist, sampler2D curvemap, float dist, out float visifac)
{
- visifac = texture2D(curvemap, vec2(dist/lampdist, 0.0)).x;
+ visifac = texture2D(curvemap, vec2(dist / lampdist, 0.0)).x;
}
void lamp_visibility_sphere(float lampdist, float dist, float visifac, out float outvisifac)
{
- float t= lampdist - dist;
+ float t = lampdist - dist;
- outvisifac= visifac*max(t, 0.0)/lampdist;
+ outvisifac = visifac * max(t, 0.0) / lampdist;
}
void lamp_visibility_spot_square(vec3 lampvec, mat4 lampimat, vec2 scale, vec3 lv, out float inpr)
{
- if(dot(lv, lampvec) > 0.0) {
- vec3 lvrot = (lampimat*vec4(lv, 0.0)).xyz;
+ if (dot(lv, lampvec) > 0.0) {
+ vec3 lvrot = (lampimat * vec4(lv, 0.0)).xyz;
/* without clever non-uniform scale, we could do: */
// float x = max(abs(lvrot.x / lvrot.z), abs(lvrot.y / lvrot.z));
float x = max(abs((lvrot.x / scale.x) / lvrot.z), abs((lvrot.y / scale.y) / lvrot.z));
- inpr = 1.0/sqrt(1.0 + x*x);
+ inpr = 1.0 / sqrt(1.0 + x * x);
}
else
inpr = 0.0;
@@ -1701,23 +1769,23 @@ void lamp_visibility_spot(float spotsi, float spotbl, float inpr, float visifac,
{
float t = spotsi;
- if(inpr <= t) {
+ if (inpr <= t) {
outvisifac = 0.0;
}
else {
t = inpr - t;
/* soft area */
- if(spotbl != 0.0)
- inpr *= smoothstep(0.0, 1.0, t/spotbl);
+ if (spotbl != 0.0)
+ inpr *= smoothstep(0.0, 1.0, t / spotbl);
- outvisifac = visifac*inpr;
+ outvisifac = visifac * inpr;
}
}
void lamp_visibility_clamp(float visifac, out float outvisifac)
{
- outvisifac = (visifac < 0.001)? 0.0: visifac;
+ outvisifac = (visifac < 0.001) ? 0.0 : visifac;
}
void world_paper_view(vec3 vec, out vec3 outvec)
@@ -1757,7 +1825,7 @@ void world_blend(vec3 vec, out float blend)
void shade_view(vec3 co, out vec3 view)
{
/* handle perspective/orthographic */
- view = (gl_ProjectionMatrix[3][3] == 0.0)? normalize(co): vec3(0.0, 0.0, -1.0);
+ view = (gl_ProjectionMatrix[3][3] == 0.0) ? normalize(co) : vec3(0.0, 0.0, -1.0);
}
void shade_tangent_v(vec3 lv, vec3 tang, out vec3 vn)
@@ -1780,14 +1848,14 @@ void shade_is_no_diffuse(out float is)
void shade_is_hemi(float inp, out float is)
{
- is = 0.5*inp + 0.5;
+ is = 0.5 * inp + 0.5;
}
float area_lamp_energy(mat4 area, vec3 co, vec3 vn)
{
vec3 vec[4], c[4];
float rad[4], fac;
-
+
vec[0] = normalize(co - area[0].xyz);
vec[1] = normalize(co - area[1].xyz);
vec[2] = normalize(co - area[2].xyz);
@@ -1803,26 +1871,28 @@ float area_lamp_energy(mat4 area, vec3 co, vec3 vn)
rad[2] = acos(dot(vec[2], vec[3]));
rad[3] = acos(dot(vec[3], vec[0]));
- fac= rad[0]*dot(vn, c[0]);
- fac+= rad[1]*dot(vn, c[1]);
- fac+= rad[2]*dot(vn, c[2]);
- fac+= rad[3]*dot(vn, c[3]);
+ fac = rad[0] * dot(vn, c[0]);
+ fac += rad[1] * dot(vn, c[1]);
+ fac += rad[2] * dot(vn, c[2]);
+ fac += rad[3] * dot(vn, c[3]);
return max(fac, 0.0);
}
-void shade_inp_area(vec3 position, vec3 lampco, vec3 lampvec, vec3 vn, mat4 area, float areasize, float k, out float inp)
+void shade_inp_area(
+ vec3 position, vec3 lampco, vec3 lampvec, vec3 vn, mat4 area, float areasize, float k,
+ out float inp)
{
vec3 co = position;
vec3 vec = co - lampco;
- if(dot(vec, lampvec) < 0.0) {
+ if (dot(vec, lampvec) < 0.0) {
inp = 0.0;
}
else {
float intens = area_lamp_energy(area, co, vn);
- inp = pow(intens*areasize, k);
+ inp = pow(intens * areasize, k);
}
}
@@ -1833,10 +1903,10 @@ void shade_diffuse_oren_nayer(float nl, vec3 n, vec3 l, vec3 v, float rough, out
float nv = max(dot(n, v), 0.0);
float realnl = dot(n, l);
- if(realnl < 0.0) {
+ if (realnl < 0.0) {
is = 0.0;
}
- else if(nl < 0.0) {
+ else if (nl < 0.0) {
is = 0.0;
}
else {
@@ -1844,14 +1914,14 @@ void shade_diffuse_oren_nayer(float nl, vec3 n, vec3 l, vec3 v, float rough, out
float Lit_A = acos(realnl);
float View_A = acos(nv);
- vec3 Lit_B = normalize(l - realnl*n);
- vec3 View_B = normalize(v - nv*n);
+ vec3 Lit_B = normalize(l - realnl * n);
+ vec3 View_B = normalize(v - nv * n);
float t = max(dot(Lit_B, View_B), 0.0);
float a, b;
- if(Lit_A > View_A) {
+ if (Lit_A > View_A) {
a = Lit_A;
b = View_A;
}
@@ -1860,11 +1930,11 @@ void shade_diffuse_oren_nayer(float nl, vec3 n, vec3 l, vec3 v, float rough, out
b = Lit_A;
}
- float A = 1.0 - (0.5*((rough*rough)/((rough*rough) + 0.33)));
- float B = 0.45*((rough*rough)/((rough*rough) + 0.09));
+ float A = 1.0 - (0.5 * ((rough * rough) / ((rough * rough) + 0.33)));
+ float B = 0.45 * ((rough * rough) / ((rough * rough) + 0.09));
b *= 0.95;
- is = nl*(A + (B * t * sin(a) * tan(b)));
+ is = nl * (A + (B * t * sin(a) * tan(b)));
}
}
@@ -1873,23 +1943,23 @@ void shade_diffuse_toon(vec3 n, vec3 l, vec3 v, float size, float tsmooth, out f
float rslt = dot(n, l);
float ang = acos(rslt);
- if(ang < size) is = 1.0;
- else if(ang > (size + tsmooth) || tsmooth == 0.0) is = 0.0;
- else is = 1.0 - ((ang - size)/tsmooth);
+ if (ang < size) is = 1.0;
+ else if (ang > (size + tsmooth) || tsmooth == 0.0) is = 0.0;
+ else is = 1.0 - ((ang - size) / tsmooth);
}
void shade_diffuse_minnaert(float nl, vec3 n, vec3 v, float darkness, out float is)
{
- if(nl <= 0.0) {
+ if (nl <= 0.0) {
is = 0.0;
}
else {
float nv = max(dot(n, v), 0.0);
- if(darkness <= 1.0)
- is = nl*pow(max(nv*nl, 0.1), darkness - 1.0);
+ if (darkness <= 1.0)
+ is = nl * pow(max(nv * nl, 0.1), darkness - 1.0);
else
- is = nl*pow(1.0001 - nv, darkness - 1.0);
+ is = nl * pow(1.0001 - nv, darkness - 1.0);
}
}
@@ -1898,18 +1968,18 @@ float fresnel_fac(vec3 view, vec3 vn, float grad, float fac)
float t1, t2;
float ffac;
- if(fac==0.0) {
+ if (fac == 0.0) {
ffac = 1.0;
}
else {
- t1= dot(view, vn);
- if(t1>0.0) t2= 1.0+t1;
- else t2= 1.0-t1;
+ t1 = dot(view, vn);
+ if (t1 > 0.0) t2 = 1.0 + t1;
+ else t2 = 1.0 - t1;
- t2= grad + (1.0-grad)*pow(t2, fac);
+ t2 = grad + (1.0 - grad) * pow(t2, fac);
- if(t2<0.0) ffac = 0.0;
- else if(t2>1.0) ffac = 1.0;
+ if (t2 < 0.0) ffac = 0.0;
+ else if (t2 > 1.0) ffac = 1.0;
else ffac = t2;
}
@@ -1923,18 +1993,18 @@ void shade_diffuse_fresnel(vec3 vn, vec3 lv, vec3 view, float fac_i, float fac,
void shade_cubic(float is, out float outis)
{
- if(is>0.0 && is<1.0)
- outis= smoothstep(0.0, 1.0, is);
+ if (is > 0.0 && is < 1.0)
+ outis = smoothstep(0.0, 1.0, is);
else
- outis= is;
+ outis = is;
}
void shade_visifac(float i, float visifac, float refl, out float outi)
{
- /*if(i > 0.0)*/
- outi = max(i*visifac*refl, 0.0);
+ /*if (i > 0.0)*/
+ outi = max(i * visifac * refl, 0.0);
/*else
- outi = i;*/
+ outi = i;*/
}
void shade_tangent_v_spec(vec3 tang, out vec3 vn)
@@ -1944,8 +2014,8 @@ void shade_tangent_v_spec(vec3 tang, out vec3 vn)
void shade_add_to_diffuse(float i, vec3 lampcol, vec3 col, out vec3 outcol)
{
- if(i > 0.0)
- outcol = i*lampcol*col;
+ if (i > 0.0)
+ outcol = i * lampcol * col;
else
outcol = vec3(0.0, 0.0, 0.0);
}
@@ -1956,9 +2026,9 @@ void shade_hemi_spec(vec3 vn, vec3 lv, vec3 view, float spec, float hard, float
lv = normalize(lv);
t = dot(vn, lv);
- t = 0.5*t + 0.5;
+ t = 0.5 * t + 0.5;
- t = visifac*spec*pow(t, hard);
+ t = visifac * spec * pow(t, hard);
}
void shade_phong_spec(vec3 n, vec3 l, vec3 v, float hard, out float specfac)
@@ -1974,61 +2044,63 @@ void shade_cooktorr_spec(vec3 n, vec3 l, vec3 v, float hard, out float specfac)
vec3 h = normalize(v + l);
float nh = dot(n, h);
- if(nh < 0.0) {
+ if (nh < 0.0) {
specfac = 0.0;
}
else {
float nv = max(dot(n, v), 0.0);
float i = pow(nh, hard);
- i = i/(0.1+nv);
+ i = i / (0.1 + nv);
specfac = i;
}
}
void shade_blinn_spec(vec3 n, vec3 l, vec3 v, float refrac, float spec_power, out float specfac)
{
- if(refrac < 1.0) {
+ if (refrac < 1.0) {
specfac = 0.0;
}
- else if(spec_power == 0.0) {
+ else if (spec_power == 0.0) {
specfac = 0.0;
}
else {
- if(spec_power<100.0)
- spec_power= sqrt(1.0/spec_power);
+ if (spec_power < 100.0)
+ spec_power = sqrt(1.0 / spec_power);
else
- spec_power= 10.0/spec_power;
+ spec_power = 10.0 / spec_power;
vec3 h = normalize(v + l);
float nh = dot(n, h);
- if(nh < 0.0) {
+ if (nh < 0.0) {
specfac = 0.0;
}
else {
float nv = max(dot(n, v), 0.01);
float nl = dot(n, l);
- if(nl <= 0.01) {
+ if (nl <= 0.01) {
specfac = 0.0;
}
else {
float vh = max(dot(v, h), 0.01);
float a = 1.0;
- float b = (2.0*nh*nv)/vh;
- float c = (2.0*nh*nl)/vh;
+ float b = (2.0 * nh * nv) / vh;
+ float c = (2.0 * nh * nl) / vh;
float g = 0.0;
- if(a < b && a < c) g = a;
- else if(b < a && b < c) g = b;
- else if(c < a && c < b) g = c;
+ if (a < b && a < c) g = a;
+ else if (b < a && b < c) g = b;
+ else if (c < a && c < b) g = c;
- float p = sqrt(((refrac * refrac)+(vh*vh)-1.0));
- float f = (((p-vh)*(p-vh))/((p+vh)*(p+vh)))*(1.0+((((vh*(p+vh))-1.0)*((vh*(p+vh))-1.0))/(((vh*(p-vh))+1.0)*((vh*(p-vh))+1.0))));
+ float p = sqrt(((refrac * refrac) + (vh * vh) - 1.0));
+ float f = ((((p - vh) * (p - vh)) / ((p + vh) * (p + vh))) *
+ (1.0 + ((((vh * (p + vh)) - 1.0) * ((vh * (p + vh)) - 1.0)) /
+ (((vh * (p - vh)) + 1.0) * ((vh * (p - vh)) + 1.0)))));
float ang = acos(nh);
- specfac = max(f*g*exp_blender((-(ang*ang)/(2.0*spec_power*spec_power))), 0.0);
+ specfac = max(f * g * exp_blender((-(ang * ang) / (2.0 * spec_power * spec_power))), 0.0);
}
}
}
@@ -2043,7 +2115,7 @@ void shade_wardiso_spec(vec3 n, vec3 l, vec3 v, float rms, out float specfac)
float angle = tan(acos(nh));
float alpha = max(rms, 0.001);
- specfac= nl * (1.0/(4.0*M_PI*alpha*alpha))*(exp_blender(-(angle*angle)/(alpha*alpha))/(sqrt(nv*nl)));
+ specfac = nl * (1.0 / (4.0 * M_PI * alpha * alpha)) * (exp_blender(-(angle * angle) / (alpha * alpha)) / (sqrt(nv * nl)));
}
void shade_toon_spec(vec3 n, vec3 l, vec3 v, float size, float tsmooth, out float specfac)
@@ -2052,31 +2124,31 @@ void shade_toon_spec(vec3 n, vec3 l, vec3 v, float size, float tsmooth, out floa
float rslt = dot(h, n);
float ang = acos(rslt);
- if(ang < size) rslt = 1.0;
- else if(ang >= (size + tsmooth) || tsmooth == 0.0) rslt = 0.0;
- else rslt = 1.0 - ((ang - size)/tsmooth);
+ if (ang < size) rslt = 1.0;
+ else if (ang >= (size + tsmooth) || tsmooth == 0.0) rslt = 0.0;
+ else rslt = 1.0 - ((ang - size) / tsmooth);
specfac = rslt;
}
void shade_spec_area_inp(float specfac, float inp, out float outspecfac)
{
- outspecfac = specfac*inp;
+ outspecfac = specfac * inp;
}
void shade_spec_t(float shadfac, float spec, float visifac, float specfac, out float t)
{
- t = shadfac*spec*visifac*specfac;
+ t = shadfac * spec * visifac * specfac;
}
void shade_add_spec(float t, vec3 lampcol, vec3 speccol, out vec3 outcol)
{
- outcol = t*lampcol*speccol;
+ outcol = t * lampcol * speccol;
}
void shade_add_mirror(vec3 mir, vec4 refcol, vec3 combined, out vec3 result)
{
- result = mir*refcol.gba + (vec3(1.0) - mir*refcol.rrr)*combined;
+ result = mir * refcol.gba + (vec3(1.0) - mir * refcol.rrr) * combined;
}
void alpha_spec_correction(vec3 spec, float spectra, float alpha, out float outalpha)
@@ -2097,7 +2169,7 @@ void shade_add(vec4 col1, vec4 col2, out vec4 outcol)
void shade_madd(vec4 col, vec4 col1, vec4 col2, out vec4 outcol)
{
- outcol = col + col1*col2;
+ outcol = col + col1 * col2;
}
void shade_add_clamped(vec4 col1, vec4 col2, out vec4 outcol)
@@ -2107,52 +2179,52 @@ void shade_add_clamped(vec4 col1, vec4 col2, out vec4 outcol)
void shade_madd_clamped(vec4 col, vec4 col1, vec4 col2, out vec4 outcol)
{
- outcol = col + max(col1*col2, vec4(0.0, 0.0, 0.0, 0.0));
+ outcol = col + max(col1 * col2, vec4(0.0, 0.0, 0.0, 0.0));
}
void shade_maddf(vec4 col, float f, vec4 col1, out vec4 outcol)
{
- outcol = col + f*col1;
+ outcol = col + f * col1;
}
void shade_mul(vec4 col1, vec4 col2, out vec4 outcol)
{
- outcol = col1*col2;
+ outcol = col1 * col2;
}
void shade_mul_value(float fac, vec4 col, out vec4 outcol)
{
- outcol = col*fac;
+ outcol = col * fac;
}
void shade_mul_value_v3(float fac, vec3 col, out vec3 outcol)
{
- outcol = col*fac;
+ outcol = col * fac;
}
void shade_obcolor(vec4 col, vec4 obcol, out vec4 outcol)
{
- outcol = vec4(col.rgb*obcol.rgb, col.a);
+ outcol = vec4(col.rgb * obcol.rgb, col.a);
}
void ramp_rgbtobw(vec3 color, out float outval)
{
- outval = color.r*0.3 + color.g*0.58 + color.b*0.12;
+ outval = color.r * 0.3 + color.g * 0.58 + color.b * 0.12;
}
void shade_only_shadow(float i, float shadfac, float energy, vec3 shadcol, out vec3 outshadrgb)
{
- outshadrgb = i*energy*(1.0 - shadfac)*(vec3(1.0)-shadcol);
+ outshadrgb = i * energy * (1.0 - shadfac) * (vec3(1.0) - shadcol);
}
void shade_only_shadow_diffuse(vec3 shadrgb, vec3 rgb, vec4 diff, out vec4 outdiff)
{
- outdiff = diff - vec4(rgb*shadrgb, 0.0);
+ outdiff = diff - vec4(rgb * shadrgb, 0.0);
}
void shade_only_shadow_specular(vec3 shadrgb, vec3 specrgb, vec4 spec, out vec4 outspec)
{
- outspec = spec - vec4(specrgb*shadrgb, 0.0);
+ outspec = spec - vec4(specrgb * shadrgb, 0.0);
}
void shade_clamp_positive(vec4 col, out vec4 outcol)
@@ -2160,47 +2232,51 @@ void shade_clamp_positive(vec4 col, out vec4 outcol)
outcol = max(col, vec4(0.0));
}
-void test_shadowbuf(vec3 rco, sampler2DShadow shadowmap, mat4 shadowpersmat, float shadowbias, float inp, out float result)
+void test_shadowbuf(
+ vec3 rco, sampler2DShadow shadowmap, mat4 shadowpersmat, float shadowbias, float inp,
+ out float result)
{
- if(inp <= 0.0) {
+ if (inp <= 0.0) {
result = 0.0;
}
else {
- vec4 co = shadowpersmat*vec4(rco, 1.0);
+ vec4 co = shadowpersmat * vec4(rco, 1.0);
//float bias = (1.5 - inp*inp)*shadowbias;
- co.z -= shadowbias*co.w;
-
- if (co.w > 0.0 && co.x > 0.0 && co.x/co.w < 1.0 && co.y > 0.0 && co.y/co.w < 1.0)
+ co.z -= shadowbias * co.w;
+
+ if (co.w > 0.0 && co.x > 0.0 && co.x / co.w < 1.0 && co.y > 0.0 && co.y / co.w < 1.0)
result = shadow2DProj(shadowmap, co).x;
else
result = 1.0;
}
}
-void test_shadowbuf_vsm(vec3 rco, sampler2D shadowmap, mat4 shadowpersmat, float shadowbias, float bleedbias, float inp, out float result)
+void test_shadowbuf_vsm(
+ vec3 rco, sampler2D shadowmap, mat4 shadowpersmat, float shadowbias, float bleedbias, float inp,
+ out float result)
{
- if(inp <= 0.0) {
+ if (inp <= 0.0) {
result = 0.0;
}
else {
- vec4 co = shadowpersmat*vec4(rco, 1.0);
- if (co.w > 0.0 && co.x > 0.0 && co.x/co.w < 1.0 && co.y > 0.0 && co.y/co.w < 1.0) {
+ vec4 co = shadowpersmat * vec4(rco, 1.0);
+ if (co.w > 0.0 && co.x > 0.0 && co.x / co.w < 1.0 && co.y > 0.0 && co.y / co.w < 1.0) {
vec2 moments = texture2DProj(shadowmap, co).rg;
- float dist = co.z/co.w;
+ float dist = co.z / co.w;
float p = 0.0;
-
- if(dist <= moments.x)
+
+ if (dist <= moments.x)
p = 1.0;
- float variance = moments.y - (moments.x*moments.x);
- variance = max(variance, shadowbias/10.0);
+ float variance = moments.y - (moments.x * moments.x);
+ variance = max(variance, shadowbias / 10.0);
float d = moments.x - dist;
- float p_max = variance / (variance + d*d);
+ float p_max = variance / (variance + d * d);
// Now reduce light-bleeding by removing the [0, x] tail and linearly rescaling (x, 1]
- p_max = clamp((p_max-bleedbias)/(1.0-bleedbias), 0.0, 1.0);
+ p_max = clamp((p_max - bleedbias) / (1.0 - bleedbias), 0.0, 1.0);
result = max(p, p_max);
}
@@ -2210,11 +2286,14 @@ void test_shadowbuf_vsm(vec3 rco, sampler2D shadowmap, mat4 shadowpersmat, float
}
}
-void shadows_only(vec3 rco, sampler2DShadow shadowmap, mat4 shadowpersmat, float shadowbias, vec3 shadowcolor, float inp, out vec3 result)
+void shadows_only(
+ vec3 rco, sampler2DShadow shadowmap, mat4 shadowpersmat,
+ float shadowbias, vec3 shadowcolor, float inp,
+ out vec3 result)
{
result = vec3(1.0);
- if(inp > 0.0) {
+ if (inp > 0.0) {
float shadfac;
test_shadowbuf(rco, shadowmap, shadowpersmat, shadowbias, inp, shadfac);
@@ -2222,11 +2301,14 @@ void shadows_only(vec3 rco, sampler2DShadow shadowmap, mat4 shadowpersmat, float
}
}
-void shadows_only_vsm(vec3 rco, sampler2D shadowmap, mat4 shadowpersmat, float shadowbias, float bleedbias, vec3 shadowcolor, float inp, out vec3 result)
+void shadows_only_vsm(
+ vec3 rco, sampler2D shadowmap, mat4 shadowpersmat,
+ float shadowbias, float bleedbias, vec3 shadowcolor, float inp,
+ out vec3 result)
{
result = vec3(1.0);
- if(inp > 0.0) {
+ if (inp > 0.0) {
float shadfac;
test_shadowbuf_vsm(rco, shadowmap, shadowpersmat, shadowbias, bleedbias, inp, shadfac);
@@ -2237,26 +2319,28 @@ void shadows_only_vsm(vec3 rco, sampler2D shadowmap, mat4 shadowpersmat, float s
void shade_light_texture(vec3 rco, sampler2D cookie, mat4 shadowpersmat, out vec4 result)
{
- vec4 co = shadowpersmat*vec4(rco, 1.0);
+ vec4 co = shadowpersmat * vec4(rco, 1.0);
result = texture2DProj(cookie, co);
}
void shade_exposure_correct(vec3 col, float linfac, float logfac, out vec3 outcol)
{
- outcol = linfac*(1.0 - exp(col*logfac));
+ outcol = linfac * (1.0 - exp(col * logfac));
}
-void shade_mist_factor(vec3 co, float enable, float miststa, float mistdist, float misttype, float misi, out float outfac)
+void shade_mist_factor(
+ vec3 co, float enable, float miststa, float mistdist, float misttype, float misi,
+ out float outfac)
{
- if(enable == 1.0) {
+ if (enable == 1.0) {
float fac, zcor;
- zcor = (gl_ProjectionMatrix[3][3] == 0.0)? length(co): -co[2];
-
+ zcor = (gl_ProjectionMatrix[3][3] == 0.0) ? length(co) : -co[2];
+
fac = clamp((zcor - miststa) / mistdist, 0.0, 1.0);
- if(misttype == 0.0) fac *= fac;
- else if(misttype == 1.0);
+ if (misttype == 0.0) fac *= fac;
+ else if (misttype == 1.0) ;
else fac = sqrt(fac);
outfac = 1.0 - (1.0 - fac) * (1.0 - misi);
@@ -2279,7 +2363,7 @@ void shade_alpha_opaque(vec4 col, out vec4 outcol)
void shade_alpha_obcolor(vec4 col, vec4 obcol, out vec4 outcol)
{
- outcol = vec4(col.rgb, col.a*obcol.a);
+ outcol = vec4(col.rgb, col.a * obcol.a);
}
/*********** NEW SHADER UTILITIES **************/
@@ -2292,11 +2376,11 @@ float fresnel_dielectric(vec3 Incoming, vec3 Normal, float eta)
float g = eta * eta - 1.0 + c * c;
float result;
- if(g > 0.0) {
+ if (g > 0.0) {
g = sqrt(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);
+ 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) */
@@ -2307,7 +2391,7 @@ float fresnel_dielectric(vec3 Incoming, vec3 Normal, float eta)
float hypot(float x, float y)
{
- return sqrt(x*x + y*y);
+ return sqrt(x * x + y * y);
}
void generated_from_orco(vec3 orco, out vec3 generated)
@@ -2315,6 +2399,17 @@ void generated_from_orco(vec3 orco, out vec3 generated)
generated = orco * 0.5 + vec3(0.5);
}
+int floor_to_int(float x)
+{
+ return int(floor(x));
+}
+
+int quick_floor(float x)
+{
+ return int(x) - ((x < 0) ? 1 : 0);
+}
+
+#ifdef BIT_OPERATIONS
float integer_noise(int n)
{
int nn;
@@ -2324,24 +2419,18 @@ float integer_noise(int n)
return 0.5 * (float(nn) / 1073741824.0);
}
-int floor_to_int(float x)
-{
- return int(floor(x));
-}
-
-#ifdef BIT_OPERATIONS
uint hash(uint kx, uint ky, uint kz)
{
-#define rot(x,k) (((x)<<(k)) | ((x)>>(32-(k))))
-#define final(a,b,c) \
+#define rot(x, k) (((x) << (k)) | ((x) >> (32 - (k))))
+#define final(a, b, c) \
{ \
- c ^= b; c -= rot(b,14); \
- a ^= c; a -= rot(c,11); \
- b ^= a; b -= rot(a,25); \
- c ^= b; c -= rot(b,16); \
- a ^= c; a -= rot(c,4); \
- b ^= a; b -= rot(a,14); \
- c ^= b; c -= rot(b,24); \
+ c ^= b; c -= rot(b, 14); \
+ a ^= c; a -= rot(c, 11); \
+ b ^= a; b -= rot(a, 25); \
+ c ^= b; c -= rot(b, 16); \
+ a ^= c; a -= rot(c, 4); \
+ b ^= a; b -= rot(a, 14); \
+ c ^= b; c -= rot(b, 24); \
}
// now hash the data!
uint a, b, c, len = 3u;
@@ -2350,7 +2439,7 @@ uint hash(uint kx, uint ky, uint kz)
c += kz;
b += ky;
a += kx;
- final(a, b, c);
+ final (a, b, c);
return c;
#undef rot
@@ -2370,9 +2459,9 @@ float bits_to_01(uint bits)
float cellnoise(vec3 p)
{
- int ix = floor_to_int(p.x);
- int iy = floor_to_int(p.y);
- int iz = floor_to_int(p.z);
+ int ix = quick_floor(p.x);
+ int iy = quick_floor(p.y);
+ int iz = quick_floor(p.z);
return bits_to_01(hash(uint(ix), uint(iy), uint(iz)));
}
@@ -2405,15 +2494,15 @@ void node_bsdf_diffuse(vec4 color, float roughness, vec3 N, out vec4 result)
vec3 L = vec3(0.2);
/* directional lights */
- for(int i = 0; i < NUM_LIGHTS; i++) {
+ for (int i = 0; i < NUM_LIGHTS; i++) {
vec3 light_position = gl_LightSource[i].position.xyz;
vec3 light_diffuse = gl_LightSource[i].diffuse.rgb;
float bsdf = max(dot(N, light_position), 0.0);
- L += light_diffuse*bsdf;
+ L += light_diffuse * bsdf;
}
- result = vec4(L*color.rgb, 1.0);
+ result = vec4(L * color.rgb, 1.0);
}
void node_bsdf_glossy(vec4 color, float roughness, vec3 N, out vec4 result)
@@ -2422,22 +2511,24 @@ void node_bsdf_glossy(vec4 color, float roughness, vec3 N, out vec4 result)
vec3 L = vec3(0.2);
/* directional lights */
- for(int i = 0; i < NUM_LIGHTS; i++) {
+ for (int i = 0; i < NUM_LIGHTS; i++) {
vec3 light_position = gl_LightSource[i].position.xyz;
vec3 H = gl_LightSource[i].halfVector.xyz;
vec3 light_diffuse = gl_LightSource[i].diffuse.rgb;
vec3 light_specular = gl_LightSource[i].specular.rgb;
/* we mix in some diffuse so low roughness still shows up */
- float bsdf = 0.5*pow(max(dot(N, H), 0.0), 1.0/roughness);
- bsdf += 0.5*max(dot(N, light_position), 0.0);
- L += light_specular*bsdf;
+ float bsdf = 0.5 * pow(max(dot(N, H), 0.0), 1.0 / roughness);
+ bsdf += 0.5 * max(dot(N, light_position), 0.0);
+ L += light_specular * bsdf;
}
- result = vec4(L*color.rgb, 1.0);
+ result = vec4(L * color.rgb, 1.0);
}
-void node_bsdf_anisotropic(vec4 color, float roughness, float anisotropy, float rotation, vec3 N, vec3 T, out vec4 result)
+void node_bsdf_anisotropic(
+ vec4 color, float roughness, float anisotropy, float rotation, vec3 N, vec3 T,
+ out vec4 result)
{
node_bsdf_diffuse(color, 0.0, N, result);
}
@@ -2471,7 +2562,9 @@ void node_bsdf_velvet(vec4 color, float sigma, vec3 N, out vec4 result)
node_bsdf_diffuse(color, 0.0, N, result);
}
-void node_subsurface_scattering(vec4 color, float scale, vec3 radius, float sharpen, float texture_blur, vec3 N, out vec4 result)
+void node_subsurface_scattering(
+ vec4 color, float scale, vec3 radius, float sharpen, float texture_blur, vec3 N,
+ out vec4 result)
{
node_bsdf_diffuse(color, 0.0, N, result);
}
@@ -2495,7 +2588,7 @@ void node_ambient_occlusion(vec4 color, out vec4 result)
void node_emission(vec4 color, float strength, vec3 N, out vec4 result)
{
- result = color*strength;
+ result = color * strength;
}
/* background */
@@ -2511,7 +2604,7 @@ void background_transform_to_world(vec3 viewvec, out vec3 worldvec)
void node_background(vec4 color, float strength, vec3 N, out vec4 result)
{
- result = color*strength;
+ result = color * strength;
}
/* closures */
@@ -2531,10 +2624,10 @@ void node_add_shader(vec4 shader1, vec4 shader2, out vec4 shader)
void node_fresnel(float ior, vec3 N, vec3 I, out float result)
{
/* handle perspective/orthographic */
- vec3 I_view = (gl_ProjectionMatrix[3][3] == 0.0)? normalize(I): vec3(0.0, 0.0, -1.0);
+ vec3 I_view = (gl_ProjectionMatrix[3][3] == 0.0) ? normalize(I) : vec3(0.0, 0.0, -1.0);
float eta = max(ior, 0.00001);
- result = fresnel_dielectric(I_view, N, (gl_FrontFacing)? eta: 1.0/eta);
+ result = fresnel_dielectric(I_view, N, (gl_FrontFacing) ? eta : 1.0 / eta);
}
/* layer_weight */
@@ -2543,15 +2636,15 @@ void node_layer_weight(float blend, vec3 N, vec3 I, out float fresnel, out float
{
/* fresnel */
float eta = max(1.0 - blend, 0.00001);
- vec3 I_view = (gl_ProjectionMatrix[3][3] == 0.0)? normalize(I): vec3(0.0, 0.0, -1.0);
+ vec3 I_view = (gl_ProjectionMatrix[3][3] == 0.0) ? normalize(I) : vec3(0.0, 0.0, -1.0);
- fresnel = fresnel_dielectric(I_view, N, (gl_FrontFacing)? 1.0/eta : eta );
+ fresnel = fresnel_dielectric(I_view, N, (gl_FrontFacing) ? 1.0 / eta : eta);
/* facing */
facing = abs(dot(I_view, N));
- if(blend != 0.5) {
+ if (blend != 0.5) {
blend = clamp(blend, 0.0, 0.99999);
- blend = (blend < 0.5)? 2.0*blend: 0.5/(1.0 - blend);
+ blend = (blend < 0.5) ? 2.0 * blend : 0.5 / (1.0 - blend);
facing = pow(facing, blend);
}
facing = 1.0 - facing;
@@ -2563,21 +2656,21 @@ void node_gamma(vec4 col, float gamma, out vec4 outcol)
{
outcol = col;
- if(col.r > 0.0)
+ if (col.r > 0.0)
outcol.r = compatible_pow(col.r, gamma);
- if(col.g > 0.0)
+ if (col.g > 0.0)
outcol.g = compatible_pow(col.g, gamma);
- if(col.b > 0.0)
+ if (col.b > 0.0)
outcol.b = compatible_pow(col.b, gamma);
}
/* geometry */
-void node_attribute(vec3 attr_uv, out vec4 outcol, out vec3 outvec, out float outf)
+void node_attribute(vec3 attr, out vec4 outcol, out vec3 outvec, out float outf)
{
- outcol = vec4(attr_uv, 1.0);
- outvec = attr_uv;
- outf = (attr_uv.x + attr_uv.y + attr_uv.z)/3.0;
+ outcol = vec4(attr, 1.0);
+ outvec = attr;
+ outf = (attr.x + attr.y + attr.z) / 3.0;
}
void node_uvmap(vec3 attr_uv, out vec3 outvec)
@@ -2585,48 +2678,51 @@ void node_uvmap(vec3 attr_uv, out vec3 outvec)
outvec = attr_uv;
}
-void node_geometry(vec3 I, vec3 N, mat4 toworld,
- out vec3 position, out vec3 normal, out vec3 tangent,
- out vec3 true_normal, out vec3 incoming, out vec3 parametric,
- out float backfacing, out float pointiness)
+void node_geometry(
+ vec3 I, vec3 N, mat4 toworld,
+ out vec3 position, out vec3 normal, out vec3 tangent,
+ out vec3 true_normal, out vec3 incoming, out vec3 parametric,
+ out float backfacing, out float pointiness)
{
- position = (toworld*vec4(I, 1.0)).xyz;
- normal = (toworld*vec4(N, 0.0)).xyz;
+ position = (toworld * vec4(I, 1.0)).xyz;
+ normal = (toworld * vec4(N, 0.0)).xyz;
tangent = vec3(0.0);
true_normal = normal;
/* handle perspective/orthographic */
- vec3 I_view = (gl_ProjectionMatrix[3][3] == 0.0)? normalize(I): vec3(0.0, 0.0, -1.0);
- incoming = -(toworld*vec4(I_view, 0.0)).xyz;
+ vec3 I_view = (gl_ProjectionMatrix[3][3] == 0.0) ? normalize(I) : vec3(0.0, 0.0, -1.0);
+ incoming = -(toworld * vec4(I_view, 0.0)).xyz;
parametric = vec3(0.0);
- backfacing = (gl_FrontFacing)? 0.0: 1.0;
+ backfacing = (gl_FrontFacing) ? 0.0 : 1.0;
pointiness = 0.0;
}
-void node_tex_coord(vec3 I, vec3 N, mat4 viewinvmat, mat4 obinvmat, vec4 camerafac,
- vec3 attr_orco, vec3 attr_uv,
- out vec3 generated, out vec3 normal, out vec3 uv, out vec3 object,
- out vec3 camera, out vec3 window, out vec3 reflection)
+void node_tex_coord(
+ vec3 I, vec3 N, mat4 viewinvmat, mat4 obinvmat, vec4 camerafac,
+ vec3 attr_orco, vec3 attr_uv,
+ out vec3 generated, out vec3 normal, out vec3 uv, out vec3 object,
+ out vec3 camera, out vec3 window, out vec3 reflection)
{
generated = attr_orco * 0.5 + vec3(0.5);
- normal = normalize((obinvmat*(viewinvmat*vec4(N, 0.0))).xyz);
+ normal = normalize((obinvmat * (viewinvmat * vec4(N, 0.0))).xyz);
uv = attr_uv;
- object = (obinvmat*(viewinvmat*vec4(I, 1.0))).xyz;
+ object = (obinvmat * (viewinvmat * vec4(I, 1.0))).xyz;
camera = vec3(I.xy, -I.z);
vec4 projvec = gl_ProjectionMatrix * vec4(I, 1.0);
- window = vec3(mtex_2d_mapping(projvec.xyz/projvec.w).xy * camerafac.xy + camerafac.zw, 0.0);
+ window = vec3(mtex_2d_mapping(projvec.xyz / projvec.w).xy * camerafac.xy + camerafac.zw, 0.0);
vec3 shade_I;
shade_view(I, shade_I);
vec3 view_reflection = reflect(shade_I, normalize(N));
- reflection = (viewinvmat*vec4(view_reflection, 0.0)).xyz;
+ reflection = (viewinvmat * vec4(view_reflection, 0.0)).xyz;
}
-void node_tex_coord_background(vec3 I, vec3 N, mat4 viewinvmat, mat4 obinvmat, vec4 camerafac,
- vec3 attr_orco, vec3 attr_uv,
- out vec3 generated, out vec3 normal, out vec3 uv, out vec3 object,
- out vec3 camera, out vec3 window, out vec3 reflection)
+void node_tex_coord_background(
+ vec3 I, vec3 N, mat4 viewinvmat, mat4 obinvmat, vec4 camerafac,
+ vec3 attr_orco, vec3 attr_uv,
+ out vec3 generated, out vec3 normal, out vec3 uv, out vec3 object,
+ out vec3 camera, out vec3 window, out vec3 reflection)
{
vec4 v = (gl_ProjectionMatrix[3][3] == 0.0) ? vec4(I, 1.0) : vec4(0.0, 0.0, 1.0, 1.0);
vec4 co_homogenous = (gl_ProjectionMatrixInverse * v);
@@ -2642,9 +2738,9 @@ void node_tex_coord_background(vec3 I, vec3 N, mat4 viewinvmat, mat4 obinvmat, v
object = coords;
camera = vec3(co.xy, -co.z);
- window = (gl_ProjectionMatrix[3][3] == 0.0) ?
- vec3(mtex_2d_mapping(I).xy * camerafac.xy + camerafac.zw, 0.0) :
- vec3(vec2(0.5) * camerafac.xy + camerafac.zw, 0.0);
+ window = (gl_ProjectionMatrix[3][3] == 0.0) ?
+ vec3(mtex_2d_mapping(I).xy * camerafac.xy + camerafac.zw, 0.0) :
+ vec3(vec2(0.5) * camerafac.xy + camerafac.zw, 0.0);
reflection = -coords;
}
@@ -2657,30 +2753,30 @@ float calc_gradient(vec3 p, int gradient_type)
x = p.x;
y = p.y;
z = p.z;
- if(gradient_type == 0) { /* linear */
+ if (gradient_type == 0) { /* linear */
return x;
}
- else if(gradient_type == 1) { /* quadratic */
+ else if (gradient_type == 1) { /* quadratic */
float r = max(x, 0.0);
- return r*r;
+ return r * r;
}
- else if(gradient_type == 2) { /* easing */
+ else if (gradient_type == 2) { /* easing */
float r = min(max(x, 0.0), 1.0);
- float t = r*r;
- return (3.0*t - 2.0*t*r);
+ float t = r * r;
+ return (3.0 * t - 2.0 * t * r);
}
- else if(gradient_type == 3) { /* diagonal */
+ else if (gradient_type == 3) { /* diagonal */
return (x + y) * 0.5;
}
- else if(gradient_type == 4) { /* radial */
+ else if (gradient_type == 4) { /* radial */
return atan(y, x) / (M_PI * 2) + 0.5;
}
else {
- float r = max(1.0 - sqrt(x*x + y*y + z*z), 0.0);
- if(gradient_type == 5) { /* quadratic sphere */
- return r*r;
+ float r = max(1.0 - sqrt(x * x + y * y + z * z), 0.0);
+ if (gradient_type == 5) { /* quadratic sphere */
+ return r * r;
}
- else if(gradient_type == 6) { /* sphere */
+ else if (gradient_type == 6) { /* sphere */
return r;
}
}
@@ -2701,20 +2797,21 @@ void node_tex_checker(vec3 co, vec4 color1, vec4 color2, float scale, out vec4 c
vec3 p = co * scale;
/* Prevent precision issues on unit coordinates. */
- p.x = (p.x + 0.000001)*0.999999;
- p.y = (p.y + 0.000001)*0.999999;
- p.z = (p.z + 0.000001)*0.999999;
+ p.x = (p.x + 0.000001) * 0.999999;
+ p.y = (p.y + 0.000001) * 0.999999;
+ p.z = (p.z + 0.000001) * 0.999999;
- int xi = abs(int(floor(p.x)));
- int yi = abs(int(floor(p.y)));
- int zi = abs(int(floor(p.z)));
+ int xi = int(abs(floor(p.x)));
+ int yi = int(abs(floor(p.y)));
+ int zi = int(abs(floor(p.z)));
- bool check = ((xi % 2 == yi % 2) == bool(zi % 2));
+ bool check = ((mod(xi, 2) == mod(yi, 2)) == bool(mod(zi, 2)));
color = check ? color1 : color2;
fac = check ? 1.0 : 0.0;
}
+#ifdef BIT_OPERATIONS
vec2 calc_brick_texture(vec3 p, float mortar_size, float bias,
float brick_width, float row_height,
float offset_amount, int offset_frequency,
@@ -2726,21 +2823,22 @@ vec2 calc_brick_texture(vec3 p, float mortar_size, float bias,
rownum = floor_to_int(p.y / row_height);
- if(offset_frequency != 0 && squash_frequency != 0) {
+ if (offset_frequency != 0 && squash_frequency != 0) {
brick_width *= (rownum % squash_frequency != 0) ? 1.0 : squash_amount; /* squash */
- offset = (rownum % offset_frequency != 0) ? 0.0 : (brick_width*offset_amount); /* offset */
+ offset = (rownum % offset_frequency != 0) ? 0.0 : (brick_width * offset_amount); /* offset */
}
- bricknum = floor_to_int((p.x+offset) / brick_width);
+ bricknum = floor_to_int((p.x + offset) / brick_width);
- x = (p.x+offset) - brick_width*bricknum;
- y = p.y - row_height*rownum;
+ x = (p.x + offset) - brick_width * bricknum;
+ y = p.y - row_height * rownum;
return vec2(clamp((integer_noise((rownum << 16) + (bricknum & 0xFFFF)) + bias), 0.0, 1.0),
(x < mortar_size || y < mortar_size ||
x > (brick_width - mortar_size) ||
y > (row_height - mortar_size)) ? 1.0 : 0.0);
}
+#endif
void node_tex_brick(vec3 co,
vec4 color1, vec4 color2,
@@ -2751,19 +2849,24 @@ void node_tex_brick(vec3 co,
float squash_amount, float squash_frequency,
out vec4 color, out float fac)
{
- vec2 f2 = calc_brick_texture(co*scale,
+#ifdef BIT_OPERATIONS
+ vec2 f2 = calc_brick_texture(co * scale,
mortar_size, bias,
brick_width, row_height,
offset_amount, int(offset_frequency),
squash_amount, int(squash_frequency));
float tint = f2.x;
float f = f2.y;
- if(f != 1.0) {
+ if (f != 1.0) {
float facm = 1.0 - tint;
color1 = facm * color1 + tint * color2;
}
color = (f == 1.0) ? mortar : color1;
fac = f;
+#else
+ color = vec4(1.0);
+ fac = 1.0;
+#endif
}
void node_tex_clouds(vec3 co, float size, out vec4 color, out float fac)
@@ -2775,8 +2878,8 @@ void node_tex_clouds(vec3 co, float size, out vec4 color, out float fac)
void node_tex_environment_equirectangular(vec3 co, sampler2D ima, out vec4 color)
{
vec3 nco = normalize(co);
- float u = -atan(nco.y, nco.x)/(2.0*M_PI) + 0.5;
- float v = atan(nco.z, hypot(nco.x, nco.y))/M_PI + 0.5;
+ float u = -atan(nco.y, nco.x) / (2.0 * M_PI) + 0.5;
+ float v = atan(nco.z, hypot(nco.x, nco.y)) / M_PI + 0.5;
color = texture2D(ima, vec2(u, v));
}
@@ -2787,12 +2890,12 @@ void node_tex_environment_mirror_ball(vec3 co, sampler2D ima, out vec4 color)
nco.y -= 1.0;
- float div = 2.0*sqrt(max(-0.5*nco.y, 0.0));
- if(div > 0.0)
+ float div = 2.0 * sqrt(max(-0.5 * nco.y, 0.0));
+ if (div > 0.0)
nco /= div;
- float u = 0.5*(nco.x + 1.0);
- float v = 0.5*(nco.z + 1.0);
+ float u = 0.5 * (nco.x + 1.0);
+ float v = 0.5 * (nco.z + 1.0);
color = texture2D(ima, vec2(u, v));
}
@@ -2808,6 +2911,82 @@ void node_tex_image(vec3 co, sampler2D ima, out vec4 color, out float alpha)
alpha = color.a;
}
+void node_tex_image_box(vec3 texco,
+ vec3 nob,
+ sampler2D ima,
+ float blend,
+ out vec4 color,
+ out float alpha)
+{
+ /* project from direction vector to barycentric coordinates in triangles */
+ nob = vec3(abs(nob.x), abs(nob.y), abs(nob.z));
+ nob /= (nob.x + nob.y + nob.z);
+
+ /* basic idea is to think of this as a triangle, each corner representing
+ * one of the 3 faces of the cube. in the corners we have single textures,
+ * in between we blend between two textures, and in the middle we a blend
+ * between three textures.
+ *
+ * the Nxyz values are the barycentric coordinates in an equilateral
+ * triangle, which in case of blending, in the middle has a smaller
+ * equilateral triangle where 3 textures blend. this divides things into
+ * 7 zones, with an if () test for each zone */
+
+ vec3 weight = vec3(0.0, 0.0, 0.0);
+ float limit = 0.5 * (1.0 + blend);
+
+ /* first test for corners with single texture */
+ if (nob.x > limit * (nob.x + nob.y) && nob.x > limit * (nob.x + nob.z)) {
+ weight.x = 1.0;
+ }
+ else if (nob.y > limit * (nob.x + nob.y) && nob.y > limit * (nob.y + nob.z)) {
+ weight.y = 1.0;
+ }
+ else if (nob.z > limit * (nob.x + nob.z) && nob.z > limit * (nob.y + nob.z)) {
+ weight.z = 1.0;
+ }
+ else if (blend > 0.0) {
+ /* in case of blending, test for mixes between two textures */
+ if (nob.z < (1.0 - limit) * (nob.y + nob.x)) {
+ weight.x = nob.x / (nob.x + nob.y);
+ weight.x = clamp((weight.x - 0.5 * (1.0 - blend)) / blend, 0.0, 1.0);
+ weight.y = 1.0 - weight.x;
+ }
+ else if (nob.x < (1.0 - limit) * (nob.y + nob.z)) {
+ weight.y = nob.y / (nob.y + nob.z);
+ weight.y = clamp((weight.y - 0.5 * (1.0 - blend)) / blend, 0.0, 1.0);
+ weight.z = 1.0 - weight.y;
+ }
+ else if (nob.y < (1.0 - limit) * (nob.x + nob.z)) {
+ weight.x = nob.x / (nob.x + nob.z);
+ weight.x = clamp((weight.x - 0.5 * (1.0 - blend)) / blend, 0.0, 1.0);
+ weight.z = 1.0 - weight.x;
+ }
+ else {
+ /* last case, we have a mix between three */
+ weight.x = ((2.0 - limit) * nob.x + (limit - 1.0)) / (2.0 * limit - 1.0);
+ weight.y = ((2.0 - limit) * nob.y + (limit - 1.0)) / (2.0 * limit - 1.0);
+ weight.z = ((2.0 - limit) * nob.z + (limit - 1.0)) / (2.0 * limit - 1.0);
+ }
+ }
+ else {
+ /* Desperate mode, no valid choice anyway, fallback to one side.*/
+ weight.x = 1.0;
+ }
+ color = vec4(0);
+ if (weight.x > 0.0) {
+ color += weight.x * texture2D(ima, texco.yz);
+ }
+ if (weight.y > 0.0) {
+ color += weight.y * texture2D(ima, texco.xz);
+ }
+ if (weight.z > 0.0) {
+ color += weight.z * texture2D(ima, texco.yx);
+ }
+
+ alpha = color.a;
+}
+
void node_tex_image_empty(vec3 co, out vec4 color, out float alpha)
{
color = vec4(0.0);
@@ -2817,42 +2996,42 @@ void node_tex_image_empty(vec3 co, out vec4 color, out float alpha)
void node_tex_magic(vec3 co, float scale, float distortion, float depth, out vec4 color, out float fac)
{
vec3 p = co * scale;
- float x = sin((p.x + p.y + p.z)*5.0);
- float y = cos((-p.x + p.y - p.z)*5.0);
- float z = -cos((-p.x - p.y + p.z)*5.0);
+ float x = sin((p.x + p.y + p.z) * 5.0);
+ float y = cos((-p.x + p.y - p.z) * 5.0);
+ float z = -cos((-p.x - p.y + p.z) * 5.0);
- if(depth > 0) {
+ if (depth > 0) {
x *= distortion;
y *= distortion;
z *= distortion;
- y = -cos(x-y+z);
+ y = -cos(x - y + z);
y *= distortion;
- if(depth > 1) {
- x = cos(x-y-z);
+ if (depth > 1) {
+ x = cos(x - y - z);
x *= distortion;
- if(depth > 2) {
- z = sin(-x-y-z);
+ if (depth > 2) {
+ z = sin(-x - y - z);
z *= distortion;
- if(depth > 3) {
- x = -cos(-x+y-z);
+ if (depth > 3) {
+ x = -cos(-x + y - z);
x *= distortion;
- if(depth > 4) {
- y = -sin(-x+y+z);
+ if (depth > 4) {
+ y = -sin(-x + y + z);
y *= distortion;
- if(depth > 5) {
- y = -cos(-x+y+z);
+ if (depth > 5) {
+ y = -cos(-x + y + z);
y *= distortion;
- if(depth > 6) {
- x = cos(x+y+z);
+ if (depth > 6) {
+ x = cos(x + y + z);
x *= distortion;
- if(depth > 7) {
- z = sin(x+y-z);
+ if (depth > 7) {
+ z = sin(x + y - z);
z *= distortion;
- if(depth > 8) {
- x = -cos(-x-y+z);
+ if (depth > 8) {
+ x = -cos(-x - y + z);
x *= distortion;
- if(depth > 9) {
- y = -sin(x-y+z);
+ if (depth > 9) {
+ y = -sin(x - y + z);
y *= distortion;
}
}
@@ -2864,14 +3043,14 @@ void node_tex_magic(vec3 co, float scale, float distortion, float depth, out vec
}
}
}
- if(distortion != 0.0) {
+ if (distortion != 0.0) {
distortion *= 2.0;
x /= distortion;
y /= distortion;
z /= distortion;
}
- color = vec4(0.5 - x, 0.5 - y, 0.f - z, 1.0);
+ color = vec4(0.5 - x, 0.5 - y, 0.5 - z, 1.0);
fac = (color.x + color.y + color.z) / 3.0;
}
@@ -2912,14 +3091,14 @@ float noise_perlin(float x, float y, float z)
float result;
- result = noise_nerp(w, noise_nerp(v, noise_nerp(u, noise_grad(hash(X, Y, Z), fx, fy, fz ),
- noise_grad(hash(X+1, Y, Z), fx-1.0, fy, fz)),
- noise_nerp(u, noise_grad(hash(X, Y+1, Z), fx, fy - 1.0, fz),
- noise_grad(hash(X+1, Y+1, Z), fx-1.0, fy-1.0, fz))),
- noise_nerp(v, noise_nerp(u, noise_grad(hash(X, Y, Z+1), fx, fy, fz-1.0),
- noise_grad(hash(X+1, Y, Z+1), fx-1.0, fy, fz-1.0)),
- noise_nerp(u, noise_grad(hash(X, Y+1, Z+1), fx, fy-1.0, fz-1.0),
- noise_grad(hash(X+1, Y+1, Z+1), fx-1.0, fy-1.0, fz-1.0))));
+ result = noise_nerp(w, noise_nerp(v, noise_nerp(u, noise_grad(hash(X, Y, Z), fx, fy, fz),
+ noise_grad(hash(X + 1, Y, Z), fx - 1.0, fy, fz)),
+ noise_nerp(u, noise_grad(hash(X, Y + 1, Z), fx, fy - 1.0, fz),
+ noise_grad(hash(X + 1, Y + 1, Z), fx - 1.0, fy - 1.0, fz))),
+ noise_nerp(v, noise_nerp(u, noise_grad(hash(X, Y, Z + 1), fx, fy, fz - 1.0),
+ noise_grad(hash(X + 1, Y, Z + 1), fx - 1.0, fy, fz - 1.0)),
+ noise_nerp(u, noise_grad(hash(X, Y + 1, Z + 1), fx, fy - 1.0, fz - 1.0),
+ noise_grad(hash(X + 1, Y + 1, Z + 1), fx - 1.0, fy - 1.0, fz - 1.0))));
return noise_scale3(result);
}
@@ -2942,27 +3121,27 @@ float noise_turbulence(vec3 p, float octaves, int hard)
octaves = clamp(octaves, 0.0, 16.0);
n = int(octaves);
for (i = 0; i <= n; i++) {
- float t = noise(fscale*p);
+ float t = noise(fscale * p);
if (hard != 0) {
- t = abs(2.0*t - 1.0);
+ t = abs(2.0 * t - 1.0);
}
- sum += t*amp;
+ sum += t * amp;
amp *= 0.5;
fscale *= 2.0;
}
float rmd = octaves - floor(octaves);
if (rmd != 0.0) {
- float t = noise(fscale*p);
+ float t = noise(fscale * p);
if (hard != 0) {
- t = abs(2.0*t - 1.0);
+ t = abs(2.0 * t - 1.0);
}
- float sum2 = sum + t*amp;
- sum *= (float(1 << n) / float((1 << (n+1)) - 1));
- sum2 *= (float(1 << (n+1)) / float((1 << (n+2)) - 1));
- return (1.0 - rmd)*sum + rmd*sum2;
+ float sum2 = sum + t * amp;
+ sum *= (float(1 << n) / float((1 << (n + 1)) - 1));
+ sum2 *= (float(1 << (n + 1)) / float((1 << (n + 2)) - 1));
+ return (1.0 - rmd) * sum + rmd * sum2;
}
else {
- sum *= (float(1 << n) / float((1 << (n+1)) - 1));
+ sum *= (float(1 << n) / float((1 << (n + 1)) - 1));
return sum;
}
}
@@ -3012,14 +3191,14 @@ float noise_musgrave_fBm(vec3 p, float H, float lacunarity, float octaves)
float pwHL = pow(lacunarity, -H);
int i;
- for(i = 0; i < int(octaves); i++) {
+ for (i = 0; i < int(octaves); i++) {
value += snoise(p) * pwr;
pwr *= pwHL;
p *= lacunarity;
}
rmd = octaves - floor(octaves);
- if(rmd != 0.0)
+ if (rmd != 0.0)
value += rmd * snoise(p) * pwr;
return value;
@@ -3040,14 +3219,14 @@ float noise_musgrave_multi_fractal(vec3 p, float H, float lacunarity, float octa
float pwHL = pow(lacunarity, -H);
int i;
- for(i = 0; i < int(octaves); i++) {
+ for (i = 0; i < int(octaves); i++) {
value *= (pwr * snoise(p) + 1.0);
pwr *= pwHL;
p *= lacunarity;
}
rmd = octaves - floor(octaves);
- if(rmd != 0.0)
+ if (rmd != 0.0)
value *= (rmd * pwr * snoise(p) + 1.0); /* correct? */
return value;
@@ -3072,7 +3251,7 @@ float noise_musgrave_hetero_terrain(vec3 p, float H, float lacunarity, float oct
value = offset + snoise(p);
p *= lacunarity;
- for(i = 1; i < int(octaves); i++) {
+ for (i = 1; i < int(octaves); i++) {
increment = (snoise(p) + offset) * pwr * value;
value += increment;
pwr *= pwHL;
@@ -3080,7 +3259,7 @@ float noise_musgrave_hetero_terrain(vec3 p, float H, float lacunarity, float oct
}
rmd = octaves - floor(octaves);
- if(rmd != 0.0) {
+ if (rmd != 0.0) {
increment = (snoise(p) + offset) * pwr * value;
value += rmd * increment;
}
@@ -3107,8 +3286,8 @@ float noise_musgrave_hybrid_multi_fractal(vec3 p, float H, float lacunarity, flo
weight = gain * result;
p *= lacunarity;
- for(i = 1; (weight > 0.001f) && (i < int(octaves)); i++) {
- if(weight > 1.0)
+ for (i = 1; (weight > 0.001f) && (i < int(octaves)); i++) {
+ if (weight > 1.0)
weight = 1.0;
signal = (snoise(p) + offset) * pwr;
@@ -3119,7 +3298,7 @@ float noise_musgrave_hybrid_multi_fractal(vec3 p, float H, float lacunarity, flo
}
rmd = octaves - floor(octaves);
- if(rmd != 0.0)
+ if (rmd != 0.0)
result += rmd * ((snoise(p) + offset) * pwr);
return result;
@@ -3145,7 +3324,7 @@ float noise_musgrave_ridged_multi_fractal(vec3 p, float H, float lacunarity, flo
result = signal;
weight = 1.0;
- for(i = 1; i < int(octaves); i++) {
+ for (i = 1; i < int(octaves); i++) {
p *= lacunarity;
weight = clamp(signal * gain, 0.0, 1.0);
signal = offset - abs(snoise(p));
@@ -3168,15 +3347,15 @@ float svm_musgrave(int type,
vec3 p)
{
if (type == 0 /*NODE_MUSGRAVE_MULTIFRACTAL*/)
- return intensity*noise_musgrave_multi_fractal(p, dimension, lacunarity, octaves);
+ return intensity * noise_musgrave_multi_fractal(p, dimension, lacunarity, octaves);
else if (type == 1 /*NODE_MUSGRAVE_FBM*/)
- return intensity*noise_musgrave_fBm(p, dimension, lacunarity, octaves);
+ return intensity * noise_musgrave_fBm(p, dimension, lacunarity, octaves);
else if (type == 2 /*NODE_MUSGRAVE_HYBRID_MULTIFRACTAL*/)
- return intensity*noise_musgrave_hybrid_multi_fractal(p, dimension, lacunarity, octaves, offset, gain);
+ return intensity * noise_musgrave_hybrid_multi_fractal(p, dimension, lacunarity, octaves, offset, gain);
else if (type == 3 /*NODE_MUSGRAVE_RIDGED_MULTIFRACTAL*/)
- return intensity*noise_musgrave_ridged_multi_fractal(p, dimension, lacunarity, octaves, offset, gain);
+ return intensity * noise_musgrave_ridged_multi_fractal(p, dimension, lacunarity, octaves, offset, gain);
else if (type == 4 /*NODE_MUSGRAVE_HETERO_TERRAIN*/)
- return intensity*noise_musgrave_hetero_terrain(p, dimension, lacunarity, octaves, offset);
+ return intensity * noise_musgrave_hetero_terrain(p, dimension, lacunarity, octaves, offset);
return 0.0;
}
#endif // #ifdef BIT_OPERATIONS
@@ -3200,7 +3379,7 @@ void node_tex_musgrave(vec3 co,
offset,
1.0,
gain,
- co*scale);
+ co * scale);
#else
fac = 1.0;
#endif
@@ -3291,30 +3470,32 @@ float calc_wave(vec3 p, float distortion, float detail, float detail_scale, int
{
float n;
- if(wave_type == 0) /* type bands */
+ if (wave_type == 0) /* type bands */
n = (p.x + p.y + p.z) * 10.0;
else /* type rings */
n = length(p) * 20.0;
- if(distortion != 0.0)
- n += distortion * noise_turbulence(p*detail_scale, detail, 0);
+ if (distortion != 0.0)
+ n += distortion * noise_turbulence(p * detail_scale, detail, 0);
- if(wave_profile == 0) { /* profile sin */
+ if (wave_profile == 0) { /* profile sin */
return 0.5 + 0.5 * sin(n);
}
else { /* profile saw */
n /= 2.0 * M_PI;
n -= int(n);
- return (n < 0.0)? n + 1.0: n;
+ return (n < 0.0) ? n + 1.0 : n;
}
}
#endif // BIT_OPERATIONS
-void node_tex_wave(vec3 co, float scale, float distortion, float detail, float detail_scale, float wave_type, float wave_profile, out vec4 color, out float fac)
+void node_tex_wave(
+ vec3 co, float scale, float distortion, float detail, float detail_scale, float wave_type, float wave_profile,
+ out vec4 color, out float fac)
{
#ifdef BIT_OPERATIONS
float f;
- f = calc_wave(co*scale, distortion, detail, detail_scale, int(wave_type), int(wave_profile));
+ f = calc_wave(co * scale, distortion, detail, detail_scale, int(wave_type), int(wave_profile));
color = vec4(f, f, f, 1.0);
fac = f;
@@ -3393,12 +3574,12 @@ void node_bump(float strength, float dist, float height, vec3 N, vec3 surf_pos,
float dHdx = dFdx(height);
float dHdy = dFdy(height);
- vec3 surfgrad = dHdx*Rx + dHdy*Ry;
+ vec3 surfgrad = dHdx * Rx + dHdy * Ry;
strength = max(strength, 0.0);
- result = normalize(absdet*N - dist*sign(det)*surfgrad);
- result = normalize(strength*result + (1.0 - strength)*N);
+ result = normalize(absdet * N - dist * sign(det) * surfgrad);
+ result = normalize(strength * result + (1.0 - strength) * N);
}
/* output */
@@ -3421,7 +3602,7 @@ void material_preview_matcap(vec4 color, sampler2D ima, vec4 N, vec4 mask, out v
vec2 tex;
#ifndef USE_OPENSUBDIV
- /* remap to 0.0 - 1.0 range. This is done because OpenGL 2.0 clamps colors
+ /* remap to 0.0 - 1.0 range. This is done because OpenGL 2.0 clamps colors
* between shader stages and we want the full range of the normal */
normal = vec3(2.0, 2.0, 2.0) * vec3(N.x, N.y, N.z) - vec3(1.0, 1.0, 1.0);
if (normal.z < 0.0) {
diff --git a/source/blender/gpu/shaders/gpu_shader_sep_gaussian_blur_frag.glsl b/source/blender/gpu/shaders/gpu_shader_sep_gaussian_blur_frag.glsl
index 5f406c959f1..b485d2cce86 100644
--- a/source/blender/gpu/shaders/gpu_shader_sep_gaussian_blur_frag.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_sep_gaussian_blur_frag.glsl
@@ -4,13 +4,13 @@ uniform sampler2D textureSource;
void main()
{
vec4 color = vec4(0.0);
- color += texture2D( textureSource, gl_TexCoord[0].st + vec2(-3.0 * ScaleU.x, -3.0 * ScaleU.y ) ) * 0.015625;
- color += texture2D( textureSource, gl_TexCoord[0].st + vec2(-2.0 * ScaleU.x, -2.0 * ScaleU.y ) ) * 0.09375;
- color += texture2D( textureSource, gl_TexCoord[0].st + vec2(-1.0 * ScaleU.x, -1.0 * ScaleU.y ) ) * 0.234375;
- color += texture2D( textureSource, gl_TexCoord[0].st + vec2(0.0, 0.0)) * 0.3125;
- color += texture2D( textureSource, gl_TexCoord[0].st + vec2(1.0 * ScaleU.x, 1.0 * ScaleU.y ) ) * 0.234375;
- color += texture2D( textureSource, gl_TexCoord[0].st + vec2(2.0 * ScaleU.x, 2.0 * ScaleU.y ) ) * 0.09375;
- color += texture2D( textureSource, gl_TexCoord[0].st + vec2(3.0 * ScaleU.x, 3.0 * ScaleU.y ) ) * 0.015625;
+ color += texture2D(textureSource, gl_TexCoord[0].st + vec2(-3.0 * ScaleU.x, -3.0 * ScaleU.y)) * 0.015625;
+ color += texture2D(textureSource, gl_TexCoord[0].st + vec2(-2.0 * ScaleU.x, -2.0 * ScaleU.y)) * 0.09375;
+ color += texture2D(textureSource, gl_TexCoord[0].st + vec2(-1.0 * ScaleU.x, -1.0 * ScaleU.y)) * 0.234375;
+ color += texture2D(textureSource, gl_TexCoord[0].st + vec2(0.0, 0.0)) * 0.3125;
+ color += texture2D(textureSource, gl_TexCoord[0].st + vec2(1.0 * ScaleU.x, 1.0 * ScaleU.y)) * 0.234375;
+ color += texture2D(textureSource, gl_TexCoord[0].st + vec2(2.0 * ScaleU.x, 2.0 * ScaleU.y)) * 0.09375;
+ color += texture2D(textureSource, gl_TexCoord[0].st + vec2(3.0 * ScaleU.x, 3.0 * ScaleU.y)) * 0.015625;
gl_FragColor = color;
}
diff --git a/source/blender/gpu/shaders/gpu_shader_sep_gaussian_blur_vert.glsl b/source/blender/gpu/shaders/gpu_shader_sep_gaussian_blur_vert.glsl
index 9bb2e7ad469..5d00108b052 100644
--- a/source/blender/gpu/shaders/gpu_shader_sep_gaussian_blur_vert.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_sep_gaussian_blur_vert.glsl
@@ -1,6 +1,6 @@
void main()
{
- gl_Position = ftransform();
- gl_TexCoord[0] = gl_MultiTexCoord0;
+ gl_Position = ftransform();
+ gl_TexCoord[0] = gl_MultiTexCoord0;
}
diff --git a/source/blender/gpu/shaders/gpu_shader_vertex.glsl b/source/blender/gpu/shaders/gpu_shader_vertex.glsl
index 7e332706695..9a6537b4f09 100644
--- a/source/blender/gpu/shaders/gpu_shader_vertex.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_vertex.glsl
@@ -14,6 +14,68 @@ varying vec3 varnormal;
varying float gl_ClipDistance[6];
#endif
+float srgb_to_linearrgb(float c)
+{
+ if (c < 0.04045)
+ return (c < 0.0) ? 0.0 : c * (1.0 / 12.92);
+ else
+ return pow((c + 0.055) * (1.0 / 1.055), 2.4);
+}
+
+void srgb_to_linearrgb(vec3 col_from, out vec3 col_to)
+{
+ col_to.r = srgb_to_linearrgb(col_from.r);
+ col_to.g = srgb_to_linearrgb(col_from.g);
+ col_to.b = srgb_to_linearrgb(col_from.b);
+}
+
+void srgb_to_linearrgb(vec4 col_from, out vec4 col_to)
+{
+ col_to.r = srgb_to_linearrgb(col_from.r);
+ col_to.g = srgb_to_linearrgb(col_from.g);
+ col_to.b = srgb_to_linearrgb(col_from.b);
+ col_to.a = col_from.a;
+}
+
+bool is_srgb(int info)
+{
+#ifdef USE_NEW_SHADING
+ return (info == 1)? true: false;
+#else
+ return false;
+#endif
+}
+
+void set_var_from_attr(float attr, int info, out float var)
+{
+ var = attr;
+}
+
+void set_var_from_attr(vec2 attr, int info, out vec2 var)
+{
+ var = attr;
+}
+
+void set_var_from_attr(vec3 attr, int info, out vec3 var)
+{
+ if (is_srgb(info)) {
+ srgb_to_linearrgb(attr, var);
+ }
+ else {
+ var = attr;
+ }
+}
+
+void set_var_from_attr(vec4 attr, int info, out vec4 var)
+{
+ if (is_srgb(info)) {
+ srgb_to_linearrgb(attr, var);
+ }
+ else {
+ var = attr;
+ }
+}
+
void main()
{
#ifndef USE_OPENSUBDIV
@@ -29,7 +91,7 @@ void main()
#ifdef CLIP_WORKAROUND
int i;
- for(i = 0; i < 6; i++)
+ for (i = 0; i < 6; i++)
gl_ClipDistance[i] = dot(co, gl_ClipPlane[i]);
#elif !defined(GPU_ATI)
// Setting gl_ClipVertex is necessary to get glClipPlane working on NVIDIA
diff --git a/source/blender/gpu/shaders/gpu_shader_vsm_store_frag.glsl b/source/blender/gpu/shaders/gpu_shader_vsm_store_frag.glsl
index 4838289ff9e..3761bf350eb 100644
--- a/source/blender/gpu/shaders/gpu_shader_vsm_store_frag.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_vsm_store_frag.glsl
@@ -15,7 +15,7 @@ void main()
// Adjusting moments using partial derivative
float dx = dFdx(depth);
float dy = dFdy(depth);
- moment2 += 0.25*(dx*dx+dy*dy);
+ moment2 += 0.25 * (dx * dx + dy * dy);
gl_FragColor = vec4(moment1, moment2, 0.0, 0.0);
}
diff --git a/source/blender/imbuf/intern/IMB_anim.h b/source/blender/imbuf/intern/IMB_anim.h
index f4763883489..d89393b9903 100644
--- a/source/blender/imbuf/intern/IMB_anim.h
+++ b/source/blender/imbuf/intern/IMB_anim.h
@@ -83,18 +83,10 @@
# include <libswscale/swscale.h>
#endif
-/* actually hard coded endianness */
-#define GET_BIG_LONG(x) (((uchar *) (x))[0] << 24 | ((uchar *) (x))[1] << 16 | ((uchar *) (x))[2] << 8 | ((uchar *) (x))[3])
-#define GET_LITTLE_LONG(x) (((uchar *) (x))[3] << 24 | ((uchar *) (x))[2] << 16 | ((uchar *) (x))[1] << 8 | ((uchar *) (x))[0])
-#define SWAP_L(x) (((x << 24) & 0xff000000) | ((x << 8) & 0xff0000) | ((x >> 8) & 0xff00) | ((x >> 24) & 0xff))
-#define SWAP_S(x) (((x << 8) & 0xff00) | ((x >> 8) & 0xff))
-
/* more endianness... should move to a separate file... */
#ifdef __BIG_ENDIAN__
-# define GET_ID GET_BIG_LONG
# define LITTLE_LONG SWAP_LONG
#else
-# define GET_ID GET_LITTLE_LONG
# define LITTLE_LONG ENDIAN_NOP
#endif
diff --git a/source/blender/makesdna/DNA_ID.h b/source/blender/makesdna/DNA_ID.h
index 0bf3c350263..b0812a81ee1 100644
--- a/source/blender/makesdna/DNA_ID.h
+++ b/source/blender/makesdna/DNA_ID.h
@@ -142,7 +142,6 @@ typedef struct ID {
*/
typedef struct Library {
ID id;
- ID *idblock;
struct FileData *filedata;
char name[1024]; /* path name used for reading, can be relative and edited in the outliner */
@@ -155,6 +154,9 @@ typedef struct Library {
struct Library *parent; /* set for indirectly linked libs, used in the outliner and while reading */
struct PackedFile *packedfile;
+
+ int temp_index;
+ int _pad;
} Library;
enum eIconSizes {
diff --git a/source/blender/makesdna/DNA_anim_types.h b/source/blender/makesdna/DNA_anim_types.h
index fdad6aae094..4c1283452ff 100644
--- a/source/blender/makesdna/DNA_anim_types.h
+++ b/source/blender/makesdna/DNA_anim_types.h
@@ -484,7 +484,7 @@ typedef struct FCurve {
unsigned int totvert; /* total number of points which define the curve (i.e. size of arrays in FPoints) */
/* value cache + settings */
- float curval; /* value stored from last time curve was evaluated */
+ float curval; /* value stored from last time curve was evaluated (not threadsafe, debug display only!) */
short flag; /* user-editable settings for this curve */
short extend; /* value-extending mode for this curve (does not cover */
diff --git a/source/blender/makesdna/DNA_customdata_types.h b/source/blender/makesdna/DNA_customdata_types.h
index 3807bb296fd..2d1ffaa53eb 100644
--- a/source/blender/makesdna/DNA_customdata_types.h
+++ b/source/blender/makesdna/DNA_customdata_types.h
@@ -75,6 +75,12 @@ typedef struct CustomData {
/* CustomData.type */
typedef enum CustomDataType {
+ /* Used by GLSL attributes in the cases when we need a delayed CD type
+ * assignment (in the cases when we don't know in advance which layer
+ * we are addressing).
+ */
+ CD_AUTO_FROM_NAME = -1,
+
CD_MVERT = 0,
#ifdef DNA_DEPRECATED
CD_MSTICKY = 1, /* DEPRECATED */
diff --git a/source/blender/makesdna/DNA_modifier_types.h b/source/blender/makesdna/DNA_modifier_types.h
index 457db70cd28..a58e995f1c6 100644
--- a/source/blender/makesdna/DNA_modifier_types.h
+++ b/source/blender/makesdna/DNA_modifier_types.h
@@ -1518,7 +1518,9 @@ typedef struct NormalEditModifierData {
short mix_mode;
char pad[2];
float mix_factor;
+ float mix_limit;
float offset[3];
+ float pad_f1;
} NormalEditModifierData;
/* NormalEditModifierData.mode */
diff --git a/source/blender/makesdna/DNA_scene_types.h b/source/blender/makesdna/DNA_scene_types.h
index 1bf044ffecb..79af1813a8f 100644
--- a/source/blender/makesdna/DNA_scene_types.h
+++ b/source/blender/makesdna/DNA_scene_types.h
@@ -1639,6 +1639,7 @@ typedef struct Scene {
#define R_SIMPLIFY 0x1000000
#define R_EDGE_FRS 0x2000000 /* R_EDGE reserved for Freestyle */
#define R_PERSISTENT_DATA 0x4000000 /* keep data around for re-render */
+#define R_USE_WS_SHADING 0x8000000 /* use world space interpretation of lighting data */
/* seq_flag */
#define R_SEQ_GL_PREV 1
diff --git a/source/blender/makesdna/DNA_view3d_types.h b/source/blender/makesdna/DNA_view3d_types.h
index 321ff26f68f..5b533d1ec48 100644
--- a/source/blender/makesdna/DNA_view3d_types.h
+++ b/source/blender/makesdna/DNA_view3d_types.h
@@ -298,7 +298,7 @@ typedef struct View3D {
#define RV3D_VIEW_CAMERA 8
#define RV3D_VIEW_IS_AXIS(view) \
- ((view >= RV3D_VIEW_FRONT) && (view <= RV3D_VIEW_BOTTOM))
+ (((view) >= RV3D_VIEW_FRONT) && ((view) <= RV3D_VIEW_BOTTOM))
/* View3d->flag2 (short) */
#define V3D_RENDER_OVERRIDE (1 << 2)
diff --git a/source/blender/makesrna/RNA_access.h b/source/blender/makesrna/RNA_access.h
index 3a19211ab39..c3d25ed2972 100644
--- a/source/blender/makesrna/RNA_access.h
+++ b/source/blender/makesrna/RNA_access.h
@@ -979,6 +979,7 @@ bool RNA_path_resolve_elements(PointerRNA *ptr, const char *path, struct ListBas
char *RNA_path_from_ID_to_struct(PointerRNA *ptr);
char *RNA_path_from_ID_to_property(PointerRNA *ptr, PropertyRNA *prop);
+char *RNA_path_from_ID_to_property_index(PointerRNA *ptr, PropertyRNA *prop, int array_dim, int index);
char *RNA_path_resolve_from_type_to_property(
struct PointerRNA *ptr, struct PropertyRNA *prop,
diff --git a/source/blender/makesrna/intern/rna_access.c b/source/blender/makesrna/intern/rna_access.c
index 97c71715349..c49a6197a4e 100644
--- a/source/blender/makesrna/intern/rna_access.c
+++ b/source/blender/makesrna/intern/rna_access.c
@@ -4642,7 +4642,47 @@ char *RNA_path_from_ID_to_struct(PointerRNA *ptr)
return ptrpath;
}
-char *RNA_path_from_ID_to_property(PointerRNA *ptr, PropertyRNA *prop)
+static void rna_path_array_multi_from_flat_index(
+ const int dimsize[RNA_MAX_ARRAY_LENGTH], const int totdims,
+ const int index_dim, int index,
+ int r_index_multi[RNA_MAX_ARRAY_LENGTH])
+{
+ int dimsize_step[RNA_MAX_ARRAY_LENGTH + 1];
+ int i = totdims - 1;
+ dimsize_step[i + 1] = 1;
+ dimsize_step[i] = dimsize[i];
+ while (--i != -1) {
+ dimsize_step[i] = dimsize[i] * dimsize_step[i + 1];
+ }
+ while (++i != index_dim) {
+ int index_round = index / dimsize_step[i + 1];
+ r_index_multi[i] = index_round;
+ index -= (index_round * dimsize_step[i + 1]);
+ }
+ BLI_assert(index == 0);
+}
+
+static void rna_path_array_multi_string_from_flat_index(
+ PointerRNA *ptr, PropertyRNA *prop, int index_dim, int index,
+ char *index_str, int index_str_len)
+{
+ int dimsize[RNA_MAX_ARRAY_LENGTH];
+ int totdims = RNA_property_array_dimension(ptr, prop, dimsize);
+ int index_multi[RNA_MAX_ARRAY_LENGTH];
+
+ rna_path_array_multi_from_flat_index(dimsize, totdims, index_dim, index, index_multi);
+
+ for (int i = 0, offset = 0; (i < index_dim) && (offset < index_str_len); i++) {
+ offset += BLI_snprintf_rlen(&index_str[offset], index_str_len - offset, "[%d]", index_multi[i]);
+ }
+}
+
+/**
+ * \param index_dim: The dimensiuon to show, 0 disables. 1 for 1d array, 2 for 2d. etc.
+ * \param index: The *flattened* index to use when \a ``index_dim > 0``,
+ * this is expanded when used with multi-dimensional arrays.
+ */
+char *RNA_path_from_ID_to_property_index(PointerRNA *ptr, PropertyRNA *prop, int index_dim, int index)
{
const bool is_rna = (prop->magic == RNA_MAGIC);
const char *propname;
@@ -4656,25 +4696,36 @@ char *RNA_path_from_ID_to_property(PointerRNA *ptr, PropertyRNA *prop)
propname = RNA_property_identifier(prop);
+ /* support indexing w/ multi-dimensional arrays */
+ char index_str[RNA_MAX_ARRAY_LENGTH * 12 + 1];
+ if (index_dim == 0) {
+ index_str[0] = '\0';
+ }
+ else {
+ rna_path_array_multi_string_from_flat_index(
+ ptr, prop, index_dim, index,
+ index_str, sizeof(index_str));
+ }
+
if (ptrpath) {
if (is_rna) {
- path = BLI_sprintfN("%s.%s", ptrpath, propname);
+ path = BLI_sprintfN("%s.%s%s", ptrpath, propname, index_str);
}
else {
char propname_esc[MAX_IDPROP_NAME * 2];
BLI_strescape(propname_esc, propname, sizeof(propname_esc));
- path = BLI_sprintfN("%s[\"%s\"]", ptrpath, propname_esc);
+ path = BLI_sprintfN("%s[\"%s\"]%s", ptrpath, propname_esc, index_str);
}
MEM_freeN(ptrpath);
}
else if (RNA_struct_is_ID(ptr->type)) {
if (is_rna) {
- path = BLI_strdup(propname);
+ path = BLI_sprintfN("%s%s", propname, index_str);
}
else {
char propname_esc[MAX_IDPROP_NAME * 2];
BLI_strescape(propname_esc, propname, sizeof(propname_esc));
- path = BLI_sprintfN("[\"%s\"]", propname_esc);
+ path = BLI_sprintfN("[\"%s\"]%s", propname_esc, index_str);
}
}
else {
@@ -4684,6 +4735,11 @@ char *RNA_path_from_ID_to_property(PointerRNA *ptr, PropertyRNA *prop)
return path;
}
+char *RNA_path_from_ID_to_property(PointerRNA *ptr, PropertyRNA *prop)
+{
+ return RNA_path_from_ID_to_property_index(ptr, prop, 0, -1);
+}
+
/**
* \return the path to given ptr/prop from the closest ancestor of given type, if any (else return NULL).
*/
diff --git a/source/blender/makesrna/intern/rna_camera.c b/source/blender/makesrna/intern/rna_camera.c
index dcb4d65f3f9..678b0ac8f1f 100644
--- a/source/blender/makesrna/intern/rna_camera.c
+++ b/source/blender/makesrna/intern/rna_camera.c
@@ -131,8 +131,8 @@ static void rna_def_camera_stereo_data(BlenderRNA *brna)
RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL);
prop = RNA_def_property(srna, "interocular_distance", PROP_FLOAT, PROP_DISTANCE);
- RNA_def_property_range(prop, 0.0f, 100.0f);
- RNA_def_property_ui_range(prop, 0.0f, 1.f, 1, 3);
+ RNA_def_property_range(prop, 0.0f, FLT_MAX);
+ RNA_def_property_ui_range(prop, 0.0f, 1e4f, 1, 3);
RNA_def_property_ui_text(prop, "Interocular Distance",
"Set the distance between the eyes - the stereo plane distance / 30 should be fine");
RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL);
diff --git a/source/blender/makesrna/intern/rna_curve.c b/source/blender/makesrna/intern/rna_curve.c
index d28dd8f7607..cb7a40a9238 100644
--- a/source/blender/makesrna/intern/rna_curve.c
+++ b/source/blender/makesrna/intern/rna_curve.c
@@ -1009,13 +1009,15 @@ static void rna_def_font(BlenderRNA *UNUSED(brna), StructRNA *srna)
prop = RNA_def_property(srna, "offset_x", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "xof");
- RNA_def_property_range(prop, -50.0f, 50.0f);
+ RNA_def_property_range(prop, -FLT_MAX, FLT_MAX);
+ RNA_def_property_ui_range(prop, -50.0f, 50.0f, 10, 3);
RNA_def_property_ui_text(prop, "X Offset", "Horizontal offset from the object origin");
RNA_def_property_update(prop, 0, "rna_Curve_update_data");
prop = RNA_def_property(srna, "offset_y", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "yof");
- RNA_def_property_range(prop, -50.0f, 50.0f);
+ RNA_def_property_range(prop, -FLT_MAX, FLT_MAX);
+ RNA_def_property_ui_range(prop, -50.0f, 50.0f, 10, 3);
RNA_def_property_ui_text(prop, "Y Offset", "Vertical offset from the object origin");
RNA_def_property_update(prop, 0, "rna_Curve_update_data");
@@ -1117,25 +1119,29 @@ static void rna_def_textbox(BlenderRNA *brna)
/* number values */
prop = RNA_def_property(srna, "x", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "x");
- RNA_def_property_range(prop, -50.0f, 50.0f);
+ RNA_def_property_range(prop, -FLT_MAX, FLT_MAX);
+ RNA_def_property_ui_range(prop, -50.0f, 50.0f, 10, 3);
RNA_def_property_ui_text(prop, "Textbox X Offset", "");
RNA_def_property_update(prop, 0, "rna_Curve_update_data");
prop = RNA_def_property(srna, "y", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "y");
- RNA_def_property_range(prop, -50.0f, 50.0f);
+ RNA_def_property_range(prop, -FLT_MAX, FLT_MAX);
+ RNA_def_property_ui_range(prop, -50.0f, 50.0f, 10, 3);
RNA_def_property_ui_text(prop, "Textbox Y Offset", "");
RNA_def_property_update(prop, 0, "rna_Curve_update_data");
prop = RNA_def_property(srna, "width", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "w");
- RNA_def_property_range(prop, 0.0f, 50.0f);
+ RNA_def_property_range(prop, 0.0f, FLT_MAX);
+ RNA_def_property_ui_range(prop, 0.0f, 50.0f, 10, 3);
RNA_def_property_ui_text(prop, "Textbox Width", "");
RNA_def_property_update(prop, 0, "rna_Curve_update_data");
prop = RNA_def_property(srna, "height", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "h");
- RNA_def_property_range(prop, 0.0f, 50.0f);
+ RNA_def_property_range(prop, 0.0f, FLT_MAX);
+ RNA_def_property_ui_range(prop, 0.0f, 50.0f, 10, 3);
RNA_def_property_ui_text(prop, "Textbox Height", "");
RNA_def_property_update(prop, 0, "rna_Curve_update_data");
diff --git a/source/blender/makesrna/intern/rna_modifier.c b/source/blender/makesrna/intern/rna_modifier.c
index 0c4b3ba485d..5a2113f3f95 100644
--- a/source/blender/makesrna/intern/rna_modifier.c
+++ b/source/blender/makesrna/intern/rna_modifier.c
@@ -4602,6 +4602,11 @@ static void rna_def_modifier_normaledit(BlenderRNA *brna)
"How much of generated normals to mix with exiting ones", 0.0f, 1.0f);
RNA_def_property_update(prop, 0, "rna_Modifier_update");
+ prop = RNA_def_float(srna, "mix_limit", 1.0f, 0.0f, DEG2RADF(180.0f), "Max Angle",
+ "Maximum angle between old and new normals", 0.0f, DEG2RADF(180.0f));
+ RNA_def_property_subtype(prop, PROP_ANGLE);
+ RNA_def_property_update(prop, 0, "rna_Modifier_update");
+
prop = RNA_def_property(srna, "vertex_group", PROP_STRING, PROP_NONE);
RNA_def_property_string_sdna(prop, NULL, "defgrp_name");
RNA_def_property_ui_text(prop, "Vertex Group", "Vertex group name for selecting/weighting the affected areas");
diff --git a/source/blender/makesrna/intern/rna_nodetree.c b/source/blender/makesrna/intern/rna_nodetree.c
index 3221e93fe84..bf7e4634c2f 100644
--- a/source/blender/makesrna/intern/rna_nodetree.c
+++ b/source/blender/makesrna/intern/rna_nodetree.c
@@ -803,6 +803,7 @@ static bNodeLink *rna_NodeTree_link_new(bNodeTree *ntree, ReportList *reports,
ntreeUpdateTree(G.main, ntree);
+ ED_node_tag_update_nodetree(G.main, ntree, ret->tonode);
WM_main_add_notifier(NC_NODE | NA_EDITED, ntree);
}
return ret;
diff --git a/source/blender/makesrna/intern/rna_object.c b/source/blender/makesrna/intern/rna_object.c
index 9ebef9db454..a7f5c21cc76 100644
--- a/source/blender/makesrna/intern/rna_object.c
+++ b/source/blender/makesrna/intern/rna_object.c
@@ -2387,6 +2387,8 @@ static void rna_def_object(BlenderRNA *brna)
prop = RNA_def_property(srna, "dimensions", PROP_FLOAT, PROP_XYZ_LENGTH);
RNA_def_property_array(prop, 3);
+ /* only for the transform-panel and conflicts with animating scale */
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
RNA_def_property_float_funcs(prop, "rna_Object_dimensions_get", "rna_Object_dimensions_set", NULL);
RNA_def_property_ui_range(prop, 0.0f, FLT_MAX, 1, 3);
RNA_def_property_ui_text(prop, "Dimensions", "Absolute bounding box dimensions of the object");
diff --git a/source/blender/makesrna/intern/rna_object_api.c b/source/blender/makesrna/intern/rna_object_api.c
index 7cc69831dce..b66556109e6 100644
--- a/source/blender/makesrna/intern/rna_object_api.c
+++ b/source/blender/makesrna/intern/rna_object_api.c
@@ -698,7 +698,7 @@ void RNA_api_object(StructRNA *srna)
#endif /* NDEBUG */
func = RNA_def_function(srna, "update_from_editmode", "rna_Object_update_from_editmode");
- RNA_def_function_ui_description(func, "Load the objects edit-mode data intp the object data");
+ RNA_def_function_ui_description(func, "Load the objects edit-mode data into the object data");
parm = RNA_def_boolean(func, "result", 0, "", "Success");
RNA_def_function_return(func, parm);
diff --git a/source/blender/makesrna/intern/rna_object_force.c b/source/blender/makesrna/intern/rna_object_force.c
index ed765f1b5c6..a8d8407fe74 100644
--- a/source/blender/makesrna/intern/rna_object_force.c
+++ b/source/blender/makesrna/intern/rna_object_force.c
@@ -199,6 +199,8 @@ static void rna_Cache_idname_change(Main *UNUSED(bmain), Scene *UNUSED(scene), P
}
if (use_new_name) {
+ BLI_filename_make_safe(cache->name);
+
if (pid2 && cache->flag & PTCACHE_DISK_CACHE) {
char old_name[80];
char new_name[80];
diff --git a/source/blender/makesrna/intern/rna_scene.c b/source/blender/makesrna/intern/rna_scene.c
index 79b8ddec08a..533c0f86460 100644
--- a/source/blender/makesrna/intern/rna_scene.c
+++ b/source/blender/makesrna/intern/rna_scene.c
@@ -5567,6 +5567,11 @@ static void rna_def_scene_render_data(BlenderRNA *brna)
RNA_def_property_boolean_sdna(prop, NULL, "mode", R_SSS);
RNA_def_property_ui_text(prop, "Subsurface Scattering", "Calculate sub-surface scattering in materials rendering");
RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_Scene_glsl_update");
+
+ prop = RNA_def_property(srna, "use_world_space_shading", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "mode", R_USE_WS_SHADING);
+ RNA_def_property_ui_text(prop, "World Space Shading", "Use world space interpretation of lighting data for node materials");
+ RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_Scene_glsl_update");
prop = RNA_def_property(srna, "use_raytrace", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "mode", R_RAYTRACE);
diff --git a/source/blender/makesrna/intern/rna_scene_api.c b/source/blender/makesrna/intern/rna_scene_api.c
index 74fb4a08eda..c3c66625c84 100644
--- a/source/blender/makesrna/intern/rna_scene_api.c
+++ b/source/blender/makesrna/intern/rna_scene_api.c
@@ -151,9 +151,9 @@ static void rna_Scene_ray_cast(
bool ret = ED_transform_snap_object_project_ray_ex(
sctx,
+ SCE_SNAP_MODE_FACE,
&(const struct SnapObjectParams){
.snap_select = SNAP_ALL,
- .snap_to = SCE_SNAP_MODE_FACE,
},
origin, direction, &ray_dist,
r_location, r_normal, r_index,
@@ -196,6 +196,7 @@ static void rna_Scene_collada_export(
int use_ngons,
int use_object_instantiation,
+ int use_blender_profile,
int sort_by_name,
int export_transformation_type,
int open_sim)
@@ -203,7 +204,7 @@ static void rna_Scene_collada_export(
collada_export(scene, filepath, apply_modifiers, export_mesh_type, selected,
include_children, include_armatures, include_shapekeys, deform_bones_only,
active_uv_only, include_uv_textures, include_material_textures,
- use_texture_copies, use_ngons, use_object_instantiation, sort_by_name, export_transformation_type, open_sim);
+ use_texture_copies, use_ngons, use_object_instantiation, use_blender_profile, sort_by_name, export_transformation_type, open_sim);
}
#endif
@@ -286,6 +287,7 @@ void RNA_api_scene(StructRNA *srna)
parm = RNA_def_boolean(func, "use_ngons", 1, "Use NGons", "Keep NGons in Export");
parm = RNA_def_boolean(func, "use_object_instantiation", 1, "Use Object Instances", "Instantiate multiple Objects from same Data");
+ parm = RNA_def_boolean(func, "use_blender_profile", 1, "Use Blender Profile", "Export additional Blender specific information (for material, shaders, bones, etc.)");
parm = RNA_def_boolean(func, "sort_by_name", 0, "Sort by Object name", "Sort exported data by Object name");
parm = RNA_def_boolean(func, "open_sim", 0, "Export for SL/OpenSim", "Compatibility mode for SL, OpenSim and similar online worlds");
diff --git a/source/blender/makesrna/intern/rna_sequencer.c b/source/blender/makesrna/intern/rna_sequencer.c
index 68d4f7f7e51..c3a66058888 100644
--- a/source/blender/makesrna/intern/rna_sequencer.c
+++ b/source/blender/makesrna/intern/rna_sequencer.c
@@ -2327,6 +2327,7 @@ static void rna_def_text(StructRNA *srna)
prop = RNA_def_property(srna, "font_size", PROP_INT, PROP_UNSIGNED);
RNA_def_property_int_sdna(prop, NULL, "text_size");
RNA_def_property_ui_text(prop, "Size", "Size of the text");
+ RNA_def_property_range(prop, 0.0, 2000);
RNA_def_property_ui_range(prop, 0.0f, 1000, 1, -1);
RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_update");
diff --git a/source/blender/makesrna/intern/rna_userdef.c b/source/blender/makesrna/intern/rna_userdef.c
index 0fbc1ce1854..5a1607aa7c7 100644
--- a/source/blender/makesrna/intern/rna_userdef.c
+++ b/source/blender/makesrna/intern/rna_userdef.c
@@ -408,7 +408,7 @@ static void rna_userdef_addon_remove(ReportList *reports, PointerRNA *path_cmp_p
{
bAddon *bext = path_cmp_ptr->data;
if (BLI_findindex(&U.addons, bext) == -1) {
- BKE_report(reports, RPT_ERROR, "Addon is no longer valid");
+ BKE_report(reports, RPT_ERROR, "Add-on is no longer valid");
return;
}
@@ -705,7 +705,7 @@ static StructRNA *rna_AddonPref_register(Main *bmain, ReportList *reports, void
BLI_strncpy(dummyapt.idname, dummyaddon.module, sizeof(dummyapt.idname));
if (strlen(identifier) >= sizeof(dummyapt.idname)) {
- BKE_reportf(reports, RPT_ERROR, "Registering addon-prefs class: '%s' is too long, maximum length is %d",
+ BKE_reportf(reports, RPT_ERROR, "Registering add-on preferences class: '%s' is too long, maximum length is %d",
identifier, (int)sizeof(dummyapt.idname));
return NULL;
}
@@ -3195,7 +3195,7 @@ static void rna_def_userdef_addon(BlenderRNA *brna)
srna = RNA_def_struct(brna, "Addon", NULL);
RNA_def_struct_sdna(srna, "bAddon");
RNA_def_struct_clear_flag(srna, STRUCT_UNDO);
- RNA_def_struct_ui_text(srna, "Addon", "Python addons to be loaded automatically");
+ RNA_def_struct_ui_text(srna, "Add-on", "Python add-ons to be loaded automatically");
prop = RNA_def_property(srna, "module", PROP_STRING, PROP_NONE);
RNA_def_property_ui_text(prop, "Module", "Module name");
@@ -3232,7 +3232,7 @@ static void rna_def_userdef_addon_pref(BlenderRNA *brna)
PropertyRNA *prop;
srna = RNA_def_struct(brna, "AddonPreferences", NULL);
- RNA_def_struct_ui_text(srna, "Addon Preferences", "");
+ RNA_def_struct_ui_text(srna, "Add-on Preferences", "");
RNA_def_struct_sdna(srna, "bAddon"); /* WARNING: only a bAddon during registration */
RNA_def_struct_refine_func(srna, "rna_AddonPref_refine");
@@ -4600,7 +4600,7 @@ static void rna_def_userdef_filepaths(BlenderRNA *brna)
RNA_def_property_string_sdna(prop, NULL, "pythondir");
RNA_def_property_ui_text(prop, "Python Scripts Directory",
"Alternate script path, matching the default layout with subdirs: "
- "startup, addons & modules (requires restart)");
+ "startup, add-ons & modules (requires restart)");
/* TODO, editing should reset sys.path! */
prop = RNA_def_property(srna, "i18n_branches_directory", PROP_STRING, PROP_DIRPATH);
@@ -4692,7 +4692,7 @@ static void rna_def_userdef_addon_collection(BlenderRNA *brna, PropertyRNA *cpro
func = RNA_def_function(srna, "remove", "rna_userdef_addon_remove");
RNA_def_function_flag(func, FUNC_NO_SELF | FUNC_USE_REPORTS);
RNA_def_function_ui_description(func, "Remove add-on");
- parm = RNA_def_pointer(func, "addon", "Addon", "", "Addon to remove");
+ parm = RNA_def_pointer(func, "addon", "Addon", "", "Add-on to remove");
RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
}
@@ -4768,7 +4768,7 @@ void RNA_def_userdef(BlenderRNA *brna)
prop = RNA_def_property(srna, "addons", PROP_COLLECTION, PROP_NONE);
RNA_def_property_collection_sdna(prop, NULL, "addons", NULL);
RNA_def_property_struct_type(prop, "Addon");
- RNA_def_property_ui_text(prop, "Addon", "");
+ RNA_def_property_ui_text(prop, "Add-on", "");
rna_def_userdef_addon_collection(brna, prop);
prop = RNA_def_property(srna, "autoexec_paths", PROP_COLLECTION, PROP_NONE);
diff --git a/source/blender/modifiers/intern/MOD_normal_edit.c b/source/blender/modifiers/intern/MOD_normal_edit.c
index 355dd6d6677..2cfa746ab3c 100644
--- a/source/blender/modifiers/intern/MOD_normal_edit.c
+++ b/source/blender/modifiers/intern/MOD_normal_edit.c
@@ -110,7 +110,7 @@ static void generate_vert_coordinates(
/* Note this modifies nos_new in-place. */
static void mix_normals(
const float mix_factor, MDeformVert *dvert, const int defgrp_index, const bool use_invert_vgroup,
- const short mix_mode,
+ const float mix_limit, const short mix_mode,
const int num_verts, MLoop *mloop, float (*nos_old)[3], float (*nos_new)[3], const int num_loops)
{
/* Mix with org normals... */
@@ -143,7 +143,9 @@ static void mix_normals(
case MOD_NORMALEDIT_MIX_COPY:
break;
}
- interp_v3_v3v3_slerp_safe(*no_new, *no_old, *no_new, fac);
+
+ interp_v3_v3v3_slerp_safe(*no_new, *no_old, *no_new,
+ (mix_limit < M_PI) ? min_ff(fac, mix_limit / angle_v3v3(*no_new, *no_old)) : fac);
}
MEM_SAFE_FREE(facs);
@@ -156,6 +158,7 @@ static bool polygons_check_flip(
MPoly *mpoly, float (*polynors)[3], const int num_polys)
{
MPoly *mp;
+ MDisps *mdisp = CustomData_get_layer(ldata, CD_MDISPS);
int i;
bool flipped = false;
@@ -174,7 +177,7 @@ static bool polygons_check_flip(
/* If average of new loop normals is opposed to polygon normal, flip polygon. */
if (dot_v3v3(polynors[i], norsum) < 0.0f) {
- BKE_mesh_polygon_flip(mp, mloop, ldata);
+ BKE_mesh_polygon_flip_ex(mp, mloop, ldata, nos, mdisp, true);
negate_v3(polynors[i]);
flipped = true;
}
@@ -186,7 +189,7 @@ static bool polygons_check_flip(
static void normalEditModifier_do_radial(
NormalEditModifierData *smd, Object *ob, DerivedMesh *dm,
short (*clnors)[2], float (*loopnors)[3], float (*polynors)[3],
- const short mix_mode, const float mix_factor,
+ const short mix_mode, const float mix_factor, const float mix_limit,
MDeformVert *dvert, const int defgrp_index, const bool use_invert_vgroup,
MVert *mvert, const int num_verts, MEdge *medge, const int num_edges,
MLoop *mloop, const int num_loops, MPoly *mpoly, const int num_polys)
@@ -265,11 +268,13 @@ static void normalEditModifier_do_radial(
if (loopnors) {
mix_normals(mix_factor, dvert, defgrp_index, use_invert_vgroup,
- mix_mode, num_verts, mloop, loopnors, nos, num_loops);
+ mix_limit, mix_mode, num_verts, mloop, loopnors, nos, num_loops);
}
if (polygons_check_flip(mloop, nos, dm->getLoopDataLayout(dm), mpoly, polynors, num_polys)) {
dm->dirty |= DM_DIRTY_TESS_CDLAYERS;
+ /* We need to recompute vertex normals! */
+ dm->calcNormals(dm);
}
BKE_mesh_normals_loop_custom_set(mvert, num_verts, medge, num_edges, mloop, nos, num_loops,
@@ -283,7 +288,7 @@ static void normalEditModifier_do_radial(
static void normalEditModifier_do_directional(
NormalEditModifierData *smd, Object *ob, DerivedMesh *dm,
short (*clnors)[2], float (*loopnors)[3], float (*polynors)[3],
- const short mix_mode, const float mix_factor,
+ const short mix_mode, const float mix_factor, const float mix_limit,
MDeformVert *dvert, const int defgrp_index, const bool use_invert_vgroup,
MVert *mvert, const int num_verts, MEdge *medge, const int num_edges,
MLoop *mloop, const int num_loops, MPoly *mpoly, const int num_polys)
@@ -342,7 +347,7 @@ static void normalEditModifier_do_directional(
if (loopnors) {
mix_normals(mix_factor, dvert, defgrp_index, use_invert_vgroup,
- mix_mode, num_verts, mloop, loopnors, nos, num_loops);
+ mix_limit, mix_mode, num_verts, mloop, loopnors, nos, num_loops);
}
if (polygons_check_flip(mloop, nos, dm->getLoopDataLayout(dm), mpoly, polynors, num_polys)) {
@@ -384,7 +389,8 @@ static DerivedMesh *normalEditModifier_do(NormalEditModifierData *smd, Object *o
const bool use_invert_vgroup = ((smd->flag & MOD_NORMALEDIT_INVERT_VGROUP) != 0);
const bool use_current_clnors = !((smd->mix_mode == MOD_NORMALEDIT_MIX_COPY) &&
(smd->mix_factor == 1.0f) &&
- (smd->defgrp_name[0] == '\0'));
+ (smd->defgrp_name[0] == '\0') &&
+ (smd->mix_limit == M_PI));
int defgrp_index;
MDeformVert *dvert;
@@ -439,13 +445,13 @@ static DerivedMesh *normalEditModifier_do(NormalEditModifierData *smd, Object *o
if (smd->mode == MOD_NORMALEDIT_MODE_RADIAL) {
normalEditModifier_do_radial(
smd, ob, dm, clnors, loopnors, polynors,
- smd->mix_mode, smd->mix_factor, dvert, defgrp_index, use_invert_vgroup,
+ smd->mix_mode, smd->mix_factor, smd->mix_limit, dvert, defgrp_index, use_invert_vgroup,
mvert, num_verts, medge, num_edges, mloop, num_loops, mpoly, num_polys);
}
else if (smd->mode == MOD_NORMALEDIT_MODE_DIRECTIONAL) {
normalEditModifier_do_directional(
smd, ob, dm, clnors, loopnors, polynors,
- smd->mix_mode, smd->mix_factor, dvert, defgrp_index, use_invert_vgroup,
+ smd->mix_mode, smd->mix_factor, smd->mix_limit, dvert, defgrp_index, use_invert_vgroup,
mvert, num_verts, medge, num_edges, mloop, num_loops, mpoly, num_polys);
}
@@ -464,6 +470,7 @@ static void initData(ModifierData *md)
smd->mix_mode = MOD_NORMALEDIT_MIX_COPY;
smd->mix_factor = 1.0f;
+ smd->mix_limit = M_PI;
}
static void copyData(ModifierData *md, ModifierData *target)
diff --git a/source/blender/modifiers/intern/MOD_screw.c b/source/blender/modifiers/intern/MOD_screw.c
index 41ebd865720..df94975e274 100644
--- a/source/blender/modifiers/intern/MOD_screw.c
+++ b/source/blender/modifiers/intern/MOD_screw.c
@@ -73,7 +73,7 @@ typedef struct ScrewVertIter {
#define SV_UNUSED (UINT_MAX)
#define SV_INVALID ((UINT_MAX) - 1)
-#define SV_IS_VALID(v) (v < SV_INVALID)
+#define SV_IS_VALID(v) ((v) < SV_INVALID)
static void screwvert_iter_init(ScrewVertIter *iter, ScrewVertConnect *array, unsigned int v_init, unsigned int dir)
{
diff --git a/source/blender/modifiers/intern/MOD_shapekey.c b/source/blender/modifiers/intern/MOD_shapekey.c
index a543aac74b9..97aae733532 100644
--- a/source/blender/modifiers/intern/MOD_shapekey.c
+++ b/source/blender/modifiers/intern/MOD_shapekey.c
@@ -124,6 +124,7 @@ ModifierTypeInfo modifierType_ShapeKey = {
/* structSize */ sizeof(ShapeKeyModifierData),
/* type */ eModifierTypeType_OnlyDeform,
/* flags */ eModifierTypeFlag_AcceptsCVs |
+ eModifierTypeFlag_AcceptsLattice |
eModifierTypeFlag_SupportsEditmode,
/* copyData */ NULL,
diff --git a/source/blender/nodes/shader/nodes/node_shader_attribute.c b/source/blender/nodes/shader/nodes/node_shader_attribute.c
index 61bdfb3dfd6..0a69593cf07 100644
--- a/source/blender/nodes/shader/nodes/node_shader_attribute.c
+++ b/source/blender/nodes/shader/nodes/node_shader_attribute.c
@@ -45,9 +45,9 @@ static void node_shader_init_attribute(bNodeTree *UNUSED(ntree), bNode *node)
static int node_shader_gpu_attribute(GPUMaterial *mat, bNode *node, bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out)
{
NodeShaderAttribute *attr = node->storage;
- GPUNodeLink *mtface = GPU_attribute(CD_MTFACE, attr->name);
+ GPUNodeLink *cd_attr = GPU_attribute(CD_AUTO_FROM_NAME, attr->name);
- return GPU_stack_link(mat, "node_attribute", in, out, mtface);
+ return GPU_stack_link(mat, "node_attribute", in, out, cd_attr);
}
/* node type definition */
diff --git a/source/blender/nodes/shader/nodes/node_shader_camera.c b/source/blender/nodes/shader/nodes/node_shader_camera.c
index 49ebb15d7a4..3bdb5c36d69 100644
--- a/source/blender/nodes/shader/nodes/node_shader_camera.c
+++ b/source/blender/nodes/shader/nodes/node_shader_camera.c
@@ -54,7 +54,15 @@ static void node_shader_exec_camera(void *data, int UNUSED(thread), bNode *UNUSE
static int gpu_shader_camera(GPUMaterial *mat, bNode *UNUSED(node), bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out)
{
- return GPU_stack_link(mat, "camera", in, out, GPU_builtin(GPU_VIEW_POSITION));
+ GPUNodeLink *viewvec;
+
+ viewvec = GPU_builtin(GPU_VIEW_POSITION);
+
+ /* Blender has negative Z, Cycles positive Z convention */
+ if (GPU_material_use_new_shading_nodes(mat))
+ GPU_link(mat, "invert_z", viewvec, &viewvec);
+
+ return GPU_stack_link(mat, "camera", in, out, viewvec);
}
void register_node_type_sh_camera(void)
diff --git a/source/blender/nodes/shader/nodes/node_shader_geom.c b/source/blender/nodes/shader/nodes/node_shader_geom.c
index cd52c4e2547..b289d66efc3 100644
--- a/source/blender/nodes/shader/nodes/node_shader_geom.c
+++ b/source/blender/nodes/shader/nodes/node_shader_geom.c
@@ -78,6 +78,10 @@ static void node_shader_exec_geom(void *data, int UNUSED(thread), bNode *node, b
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];
@@ -132,9 +136,14 @@ static int gpu_shader_geom(GPUMaterial *mat, bNode *node, bNodeExecData *UNUSED(
GPUNodeLink *mtface = GPU_attribute(CD_MTFACE, ngeo->uvname);
GPUNodeLink *mcol = GPU_attribute(CD_MCOL, ngeo->colname);
- return GPU_stack_link(mat, "geom", in, out,
+ 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 */
diff --git a/source/blender/nodes/shader/nodes/node_shader_lamp.c b/source/blender/nodes/shader/nodes/node_shader_lamp.c
index d5dac3b7ff8..2c96c91958e 100644
--- a/source/blender/nodes/shader/nodes/node_shader_lamp.c
+++ b/source/blender/nodes/shader/nodes/node_shader_lamp.c
@@ -54,6 +54,8 @@ static void node_shader_exec_lamp(void *data, int UNUSED(thread), bNode *node, b
shi->nodes = 1; /* temp hack to prevent trashadow recursion */
out[4]->vec[0] = RE_lamp_get_data(shi, ob, out[0]->vec, out[1]->vec, out[2]->vec, out[3]->vec);
shi->nodes = 0;
+ if (shi->use_world_space_shading)
+ mul_mat3_m4_v3((float (*)[4])RE_render_current_get_matrix(RE_VIEWINV_MATRIX), out[1]->vec);
}
}
}
@@ -66,7 +68,10 @@ static int gpu_shader_lamp(GPUMaterial *mat, bNode *node, bNodeExecData *UNUSED(
visifac = GPU_lamp_get_data(mat, lamp, &col, &lv, &dist, &shadow, &energy);
- return GPU_stack_link(mat, "lamp", in, out, col, energy, lv, dist, shadow, visifac);
+ bool ret = GPU_stack_link(mat, "lamp", in, out, col, energy, lv, dist, shadow, visifac);
+ if (GPU_material_use_world_space_shading(mat))
+ ret &= GPU_link(mat, "direction_transform_m4v3", out[1].link, GPU_builtin(GPU_INVERSE_VIEW_MATRIX), &out[1].link);
+ return ret;
}
return false;
diff --git a/source/blender/nodes/shader/nodes/node_shader_material.c b/source/blender/nodes/shader/nodes/node_shader_material.c
index fa13f6191ad..8b21b1ff33b 100644
--- a/source/blender/nodes/shader/nodes/node_shader_material.c
+++ b/source/blender/nodes/shader/nodes/node_shader_material.c
@@ -114,6 +114,10 @@ static void node_shader_exec_material(void *data, int UNUSED(thread), bNode *nod
/* 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
@@ -181,7 +185,11 @@ static void node_shader_exec_material(void *data, int UNUSED(thread), bNode *nod
}
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
@@ -255,6 +263,10 @@ static int gpu_shader_material(GPUMaterial *mat, bNode *node, bNodeExecData *UNU
if (hasinput[MAT_IN_NORMAL]) {
GPUNodeLink *tmp;
shi.vn = gpu_get_input_link(&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);
}
@@ -299,6 +311,10 @@ static int gpu_shader_material(GPUMaterial *mat, bNode *node, bNodeExecData *UNU
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;
diff --git a/source/blender/nodes/shader/nodes/node_shader_normal_map.c b/source/blender/nodes/shader/nodes/node_shader_normal_map.c
index 642e5b296be..57014bdc476 100644
--- a/source/blender/nodes/shader/nodes/node_shader_normal_map.c
+++ b/source/blender/nodes/shader/nodes/node_shader_normal_map.c
@@ -89,20 +89,34 @@ static void node_shader_exec_normal_map(void *data, int UNUSED(thread), bNode *n
for (int j = 0; j < 3; j++)
out[0]->vec[j] = vecIn[0] * T[j] + vecIn[1] * B[j] + vecIn[2] * N[j];
interp_v3_v3v3(out[0]->vec, N, out[0]->vec, strength);
+ if (shi->use_world_space_shading) {
+ mul_mat3_m4_v3((float (*)[4])RE_render_current_get_matrix(RE_VIEWINV_MATRIX), out[0]->vec);
+ }
break;
case SHD_NORMAL_MAP_OBJECT:
case SHD_NORMAL_MAP_BLENDER_OBJECT:
- mul_mat3_m4_v3((float (*)[4])RE_object_instance_get_matrix(shi->obi, RE_OBJECT_INSTANCE_MATRIX_LOCALTOVIEW), vecIn);
+ if (shi->use_world_space_shading) {
+ mul_mat3_m4_v3((float (*)[4])RE_object_instance_get_matrix(shi->obi, RE_OBJECT_INSTANCE_MATRIX_OB), vecIn);
+ mul_mat3_m4_v3((float (*)[4])RE_render_current_get_matrix(RE_VIEWINV_MATRIX), N);
+ }
+ else
+ mul_mat3_m4_v3((float (*)[4])RE_object_instance_get_matrix(shi->obi, RE_OBJECT_INSTANCE_MATRIX_LOCALTOVIEW), vecIn);
interp_v3_v3v3(out[0]->vec, N, vecIn, strength);
break;
case SHD_NORMAL_MAP_WORLD:
case SHD_NORMAL_MAP_BLENDER_WORLD:
- mul_mat3_m4_v3((float (*)[4])RE_render_current_get_matrix(RE_VIEW_MATRIX), vecIn);
+ if (shi->use_world_space_shading)
+ mul_mat3_m4_v3((float (*)[4])RE_render_current_get_matrix(RE_VIEWINV_MATRIX), N);
+ else
+ mul_mat3_m4_v3((float (*)[4])RE_render_current_get_matrix(RE_VIEW_MATRIX), vecIn);
interp_v3_v3v3(out[0]->vec, N, vecIn, strength);
break;
}
+ if (shi->use_world_space_shading) {
+ negate_v3(out[0]->vec);
+ }
normalize_v3(out[0]->vec);
}
}
@@ -121,34 +135,68 @@ static int gpu_shader_normal_map(GPUMaterial *mat, bNode *node, bNodeExecData *U
else
strength = GPU_uniform(in[0].vec);
- if (in[1].link) {
- GPU_link(mat, "color_to_normal", in[1].link, &realnorm);
- GPU_link(mat, "mtex_negate_texnormal", realnorm, &realnorm);
- }
+ if (in[1].link)
+ realnorm = in[1].link;
+ else
+ realnorm = GPU_uniform(in[1].vec);
+ negnorm = GPU_builtin(GPU_VIEW_NORMAL);
GPU_link(mat, "math_max", strength, GPU_uniform(d), &strength);
- GPU_link(mat, "vec_math_negate", GPU_builtin(GPU_VIEW_NORMAL), &negnorm);
- if (in[1].link) {
+ if (GPU_material_use_world_space_shading(mat)) {
+
+ /* ******* CYCLES or BLENDER INTERNAL with world space shading flag ******* */
+
+ const char *color_to_normal_fnc_name = "color_to_normal_new_shading";
+ if (nm->space == SHD_NORMAL_MAP_BLENDER_OBJECT || nm->space == SHD_NORMAL_MAP_BLENDER_WORLD || !GPU_material_use_new_shading_nodes(mat))
+ color_to_normal_fnc_name = "color_to_blender_normal_new_shading";
+ switch (nm->space) {
+ case SHD_NORMAL_MAP_TANGENT:
+ GPU_link(mat, "color_to_normal_new_shading", realnorm, &realnorm);
+ GPU_link(mat, "node_normal_map", GPU_attribute(CD_TANGENT, nm->uv_map), negnorm, realnorm, &realnorm);
+ GPU_link(mat, "vec_math_mix", strength, realnorm, GPU_builtin(GPU_VIEW_NORMAL), &out[0].link);
+ /* for uniform scale this is sufficient to match Cycles */
+ GPU_link(mat, "direction_transform_m4v3", out[0].link, GPU_builtin(GPU_INVERSE_VIEW_MATRIX), &out[0].link);
+ GPU_link(mat, "vect_normalize", out[0].link, &out[0].link);
+ return true;
+ case SHD_NORMAL_MAP_OBJECT:
+ case SHD_NORMAL_MAP_BLENDER_OBJECT:
+ GPU_link(mat, "direction_transform_m4v3", negnorm, GPU_builtin(GPU_INVERSE_VIEW_MATRIX), &negnorm);
+ GPU_link(mat, color_to_normal_fnc_name, realnorm, &realnorm);
+ GPU_link(mat, "direction_transform_m4v3", realnorm, GPU_builtin(GPU_OBJECT_MATRIX), &realnorm);
+ break;
+ case SHD_NORMAL_MAP_WORLD:
+ case SHD_NORMAL_MAP_BLENDER_WORLD:
+ GPU_link(mat, "direction_transform_m4v3", negnorm, GPU_builtin(GPU_INVERSE_VIEW_MATRIX), &negnorm);
+ GPU_link(mat, color_to_normal_fnc_name, realnorm, &realnorm);
+ break;
+ }
+
+ } else {
+
+ /* ************** BLENDER INTERNAL without world space shading flag ******* */
+
+ GPU_link(mat, "color_to_normal", realnorm, &realnorm);
+ GPU_link(mat, "mtex_negate_texnormal", realnorm, &realnorm);
+ GPU_link(mat, "vec_math_negate", negnorm, &negnorm);
+
switch (nm->space) {
case SHD_NORMAL_MAP_TANGENT:
- GPU_link(mat, "node_normal_map", GPU_attribute(CD_TANGENT, nm->uv_map), negnorm, realnorm, &out[0].link);
+ GPU_link(mat, "node_normal_map", GPU_attribute(CD_TANGENT, nm->uv_map), negnorm, realnorm, &realnorm);
break;
case SHD_NORMAL_MAP_OBJECT:
case SHD_NORMAL_MAP_BLENDER_OBJECT:
- GPU_link(mat, "direction_transform_m4v3", realnorm, GPU_builtin(GPU_LOC_TO_VIEW_MATRIX), &out[0].link);
+ GPU_link(mat, "direction_transform_m4v3", realnorm, GPU_builtin(GPU_LOC_TO_VIEW_MATRIX), &realnorm);
break;
case SHD_NORMAL_MAP_WORLD:
case SHD_NORMAL_MAP_BLENDER_WORLD:
- GPU_link(mat, "direction_transform_m4v3", realnorm, GPU_builtin(GPU_VIEW_MATRIX), &out[0].link);
+ GPU_link(mat, "direction_transform_m4v3", realnorm, GPU_builtin(GPU_VIEW_MATRIX), &realnorm);
break;
}
}
- if (out[0].link) {
- GPU_link(mat, "vec_math_mix", strength, out[0].link, negnorm, &out[0].link);
- GPU_link(mat, "vect_normalize", out[0].link, &out[0].link);
- }
+ GPU_link(mat, "vec_math_mix", strength, realnorm, negnorm, &out[0].link);
+ GPU_link(mat, "vect_normalize", out[0].link, &out[0].link);
return true;
}
@@ -169,4 +217,3 @@ void register_node_type_sh_normal_map(void)
nodeRegisterType(&ntype);
}
-
diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_image.c b/source/blender/nodes/shader/nodes/node_shader_tex_image.c
index f0a8cda045e..71200dfe9d3 100644
--- a/source/blender/nodes/shader/nodes/node_shader_tex_image.c
+++ b/source/blender/nodes/shader/nodes/node_shader_tex_image.c
@@ -59,17 +59,49 @@ static int node_shader_gpu_tex_image(GPUMaterial *mat, bNode *node, bNodeExecDat
Image *ima = (Image *)node->id;
ImageUser *iuser = NULL;
NodeTexImage *tex = node->storage;
+
+ GPUNodeLink *norm;
+
int isdata = tex->color_space == SHD_COLORSPACE_NONE;
+ float blend = tex->projection_blend;
if (!ima)
return GPU_stack_link(mat, "node_tex_image_empty", in, out);
-
+
if (!in[0].link)
in[0].link = GPU_attribute(CD_MTFACE, "");
node_shader_gpu_tex_mapping(mat, node, in, out);
- GPU_stack_link(mat, "node_tex_image", in, out, GPU_image(ima, iuser, isdata));
+ switch (tex->projection) {
+ case SHD_PROJ_FLAT:
+ GPU_stack_link(mat, "node_tex_image", in, out, GPU_image(ima, iuser, isdata));
+ break;
+ case SHD_PROJ_BOX:
+ GPU_link(mat, "direction_transform_m4v3", GPU_builtin(GPU_VIEW_NORMAL),
+ GPU_builtin(GPU_INVERSE_VIEW_MATRIX),
+ &norm);
+ GPU_link(mat, "direction_transform_m4v3", norm,
+ GPU_builtin(GPU_INVERSE_OBJECT_MATRIX),
+ &norm);
+ GPU_link(mat, "node_tex_image_box", in[0].link,
+ norm,
+ GPU_image(ima, iuser, isdata),
+ GPU_uniform(&blend),
+ &out[0].link,
+ &out[1].link);
+ break;
+ case SHD_PROJ_SPHERE:
+ GPU_link(mat, "point_texco_remap_square", in[0].link, &in[0].link);
+ GPU_link(mat, "point_map_to_sphere", in[0].link, &in[0].link);
+ GPU_stack_link(mat, "node_tex_image", in, out, GPU_image(ima, iuser, isdata));
+ break;
+ case SHD_PROJ_TUBE:
+ GPU_link(mat, "point_texco_remap_square", in[0].link, &in[0].link);
+ GPU_link(mat, "point_map_to_tube", in[0].link, &in[0].link);
+ GPU_stack_link(mat, "node_tex_image", in, out, GPU_image(ima, iuser, isdata));
+ break;
+ }
ImBuf *ibuf = BKE_image_acquire_ibuf(ima, iuser, NULL);
if ((tex->color_space == SHD_COLORSPACE_COLOR) &&
diff --git a/source/blender/python/intern/bpy_rna.c b/source/blender/python/intern/bpy_rna.c
index 33ac58dadb1..49b806347d6 100644
--- a/source/blender/python/intern/bpy_rna.c
+++ b/source/blender/python/intern/bpy_rna.c
@@ -973,7 +973,9 @@ static PyObject *pyrna_prop_str(BPy_PropertyRNA *self)
RNA_property_identifier(self->prop));
}
-static PyObject *pyrna_prop_repr(BPy_PropertyRNA *self)
+static PyObject *pyrna_prop_repr_ex(
+ BPy_PropertyRNA *self,
+ const int index_dim, const int index)
{
ID *id = self->ptr.id.data;
PyObject *tmp_str;
@@ -987,7 +989,8 @@ static PyObject *pyrna_prop_repr(BPy_PropertyRNA *self)
tmp_str = PyUnicode_FromString(id->name + 2);
- path = RNA_path_from_ID_to_property(&self->ptr, self->prop);
+ path = RNA_path_from_ID_to_property_index(&self->ptr, self->prop, index_dim, index);
+
if (path) {
const char *data_delim = (path[0] == '[') ? "" : ".";
if (GS(id->name) == ID_NT) { /* nodetree paths are not accurate */
@@ -1015,6 +1018,15 @@ static PyObject *pyrna_prop_repr(BPy_PropertyRNA *self)
return ret;
}
+static PyObject *pyrna_prop_repr(BPy_PropertyRNA *self)
+{
+ return pyrna_prop_repr_ex(self, 0, -1);
+}
+
+static PyObject *pyrna_prop_array_repr(BPy_PropertyArrayRNA *self)
+{
+ return pyrna_prop_repr_ex((BPy_PropertyRNA *)self, self->arraydim, self->arrayoffset);
+}
static PyObject *pyrna_func_repr(BPy_FunctionRNA *self)
{
@@ -5841,7 +5853,7 @@ PyTypeObject pyrna_prop_array_Type = {
NULL, /* getattrfunc tp_getattr; */
NULL, /* setattrfunc tp_setattr; */
NULL, /* tp_compare */ /* DEPRECATED in python 3.0! */
- NULL, /* subclassed */ /* tp_repr */
+ (reprfunc)pyrna_prop_array_repr, /* tp_repr */
/* Method suites for standard classes */
diff --git a/source/blender/python/mathutils/mathutils_Matrix.h b/source/blender/python/mathutils/mathutils_Matrix.h
index 9ae5a4bd61d..542a0e349c7 100644
--- a/source/blender/python/mathutils/mathutils_Matrix.h
+++ b/source/blender/python/mathutils/mathutils_Matrix.h
@@ -41,7 +41,7 @@ extern PyTypeObject matrix_access_Type;
# define MATRIX_ITEM_ASSERT(_mat, _row, _col) (void)0
#endif
-#define MATRIX_ITEM_INDEX_NUMROW(_totrow, _row, _col) ((_totrow * (_col)) + (_row))
+#define MATRIX_ITEM_INDEX_NUMROW(_totrow, _row, _col) (((_totrow) * (_col)) + (_row))
#define MATRIX_ITEM_INDEX(_mat, _row, _col) (MATRIX_ITEM_ASSERT(_mat, _row, _col),(((_mat)->num_row * (_col)) + (_row)))
#define MATRIX_ITEM_PTR( _mat, _row, _col) ((_mat)->matrix + MATRIX_ITEM_INDEX(_mat, _row, _col))
#define MATRIX_ITEM( _mat, _row, _col) ((_mat)->matrix [MATRIX_ITEM_INDEX(_mat, _row, _col)])
diff --git a/source/blender/render/extern/include/RE_shader_ext.h b/source/blender/render/extern/include/RE_shader_ext.h
index 8b6dfb88b73..73867de6b2e 100644
--- a/source/blender/render/extern/include/RE_shader_ext.h
+++ b/source/blender/render/extern/include/RE_shader_ext.h
@@ -172,6 +172,7 @@ typedef struct ShadeInput {
/* from initialize, part or renderlayer */
bool do_preview; /* for nodes, in previewrender */
bool do_manage; /* color management flag */
+ bool use_world_space_shading;
short thread, sample; /* sample: ShadeSample array index */
short nodes; /* indicate node shading, temp hack to prevent recursion */
diff --git a/source/blender/render/intern/include/rayintersection.h b/source/blender/render/intern/include/rayintersection.h
index 3607e66a237..1935e4ef59c 100644
--- a/source/blender/render/intern/include/rayintersection.h
+++ b/source/blender/render/intern/include/rayintersection.h
@@ -38,6 +38,8 @@
extern "C" {
#endif
+#include "BLI_math_geom.h"
+
struct RayObject;
/* Ray Hints */
@@ -101,6 +103,9 @@ typedef struct Isect {
#ifdef RE_RAYCOUNTER
RayCounter *raycounter;
#endif
+
+ /* Precalculated coefficients for watertight intersection check. */
+ struct IsectRayPrecalc isect_precalc;
} Isect;
/* ray types */
diff --git a/source/blender/render/intern/raytrace/rayobject.cpp b/source/blender/render/intern/raytrace/rayobject.cpp
index de6b9139363..f511042749e 100644
--- a/source/blender/render/intern/raytrace/rayobject.cpp
+++ b/source/blender/render/intern/raytrace/rayobject.cpp
@@ -138,80 +138,29 @@ MALWAYS_INLINE int vlr_check_bake(Isect *is, ObjectInstanceRen *obi, VlakRen *UN
/* Ray Triangle/Quad Intersection */
-MALWAYS_INLINE int isec_tri_quad(float start[3], float dir[3], RayFace *face, float uv[2], float *lambda)
+MALWAYS_INLINE int isec_tri_quad(float start[3], const struct IsectRayPrecalc *isect_precalc, RayFace *face, float r_uv[2], float *lambda)
{
- float co1[3], co2[3], co3[3], co4[3];
- float t0[3], t1[3], x[3], r[3], m[3], u, v, divdet, det1, l;
- int quad;
-
- quad = RE_rayface_isQuad(face);
-
- copy_v3_v3(co1, face->v1);
- copy_v3_v3(co2, face->v2);
- copy_v3_v3(co3, face->v3);
-
- copy_v3_v3(r, dir);
-
- /* intersect triangle */
- sub_v3_v3v3(t0, co3, co2);
- sub_v3_v3v3(t1, co3, co1);
-
- cross_v3_v3v3(x, r, t1);
- divdet = dot_v3v3(t0, x);
-
- sub_v3_v3v3(m, start, co3);
- det1 = dot_v3v3(m, x);
-
- if (divdet != 0.0f) {
- divdet = 1.0f / divdet;
- v = det1 * divdet;
-
- if (v < RE_RAYTRACE_EPSILON && v > -(1.0f + RE_RAYTRACE_EPSILON)) {
- float cros[3];
-
- cross_v3_v3v3(cros, m, t0);
- u = divdet * dot_v3v3(cros, r);
-
- if (u < RE_RAYTRACE_EPSILON && (v + u) > -(1.0f + RE_RAYTRACE_EPSILON)) {
- l = divdet * dot_v3v3(cros, t1);
-
- /* check if intersection is within ray length */
- if (l > -RE_RAYTRACE_EPSILON && l < *lambda) {
- uv[0] = u;
- uv[1] = v;
- *lambda = l;
- return 1;
- }
- }
+ float uv[2], l;
+
+ if (isect_ray_tri_watertight_v3(start, isect_precalc, face->v1, face->v2, face->v3, &l, uv)) {
+ /* check if intersection is within ray length */
+ if (l > -RE_RAYTRACE_EPSILON && l < *lambda) {
+ r_uv[0] = uv[0];
+ r_uv[1] = uv[1];
+ *lambda = l;
+ return 1;
}
}
/* intersect second triangle in quad */
- if (quad) {
- copy_v3_v3(co4, face->v4);
- sub_v3_v3v3(t0, co3, co4);
- divdet = dot_v3v3(t0, x);
-
- if (divdet != 0.0f) {
- divdet = 1.0f / divdet;
- v = det1 * divdet;
-
- if (v < RE_RAYTRACE_EPSILON && v > -(1.0f + RE_RAYTRACE_EPSILON)) {
- float cros[3];
-
- cross_v3_v3v3(cros, m, t0);
- u = divdet * dot_v3v3(cros, r);
-
- if (u < RE_RAYTRACE_EPSILON && (v + u) > -(1.0f + RE_RAYTRACE_EPSILON)) {
- l = divdet * dot_v3v3(cros, t1);
-
- if (l > -RE_RAYTRACE_EPSILON && l < *lambda) {
- uv[0] = u;
- uv[1] = -(1.0f + v + u);
- *lambda = l;
- return 2;
- }
- }
+ if (RE_rayface_isQuad(face)) {
+ if (isect_ray_tri_watertight_v3(start, isect_precalc, face->v1, face->v3, face->v4, &l, uv)) {
+ /* check if intersection is within ray length */
+ if (l > -RE_RAYTRACE_EPSILON && l < *lambda) {
+ r_uv[0] = uv[0];
+ r_uv[1] = uv[1];
+ *lambda = l;
+ return 2;
}
}
}
@@ -223,62 +172,23 @@ MALWAYS_INLINE int isec_tri_quad(float start[3], float dir[3], RayFace *face, fl
MALWAYS_INLINE int isec_tri_quad_neighbour(float start[3], float dir[3], RayFace *face)
{
- float co1[3], co2[3], co3[3], co4[3];
- float t0[3], t1[3], x[3], r[3], m[3], u, v, divdet, det1;
- int quad;
-
- quad = RE_rayface_isQuad(face);
+ float r[3];
+ struct IsectRayPrecalc isect_precalc;
+ float uv[2], l;
- copy_v3_v3(co1, face->v1);
- copy_v3_v3(co2, face->v2);
- copy_v3_v3(co3, face->v3);
negate_v3_v3(r, dir); /* note, different than above function */
- /* intersect triangle */
- sub_v3_v3v3(t0, co3, co2);
- sub_v3_v3v3(t1, co3, co1);
-
- cross_v3_v3v3(x, r, t1);
- divdet = dot_v3v3(t0, x);
-
- sub_v3_v3v3(m, start, co3);
- det1 = dot_v3v3(m, x);
-
- if (divdet != 0.0f) {
- divdet = 1.0f / divdet;
- v = det1 * divdet;
-
- if (v < RE_RAYTRACE_EPSILON && v > -(1.0f + RE_RAYTRACE_EPSILON)) {
- float cros[3];
-
- cross_v3_v3v3(cros, m, t0);
- u = divdet * dot_v3v3(cros, r);
+ isect_ray_tri_watertight_v3_precalc(&isect_precalc, r);
- if (u < RE_RAYTRACE_EPSILON && (v + u) > -(1.0f + RE_RAYTRACE_EPSILON))
- return 1;
- }
+ if (isect_ray_tri_watertight_v3(start, &isect_precalc, face->v1, face->v2, face->v3, &l, uv)) {
+ return 1;
}
/* intersect second triangle in quad */
- if (quad) {
- copy_v3_v3(co4, face->v4);
- sub_v3_v3v3(t0, co3, co4);
- divdet = dot_v3v3(t0, x);
-
- if (divdet != 0.0f) {
- divdet = 1.0f / divdet;
- v = det1 * divdet;
-
- if (v < RE_RAYTRACE_EPSILON && v > -(1.0f + RE_RAYTRACE_EPSILON)) {
- float cros[3];
-
- cross_v3_v3v3(cros, m, t0);
- u = divdet * dot_v3v3(cros, r);
-
- if (u < RE_RAYTRACE_EPSILON && (v + u) > -(1.0f + RE_RAYTRACE_EPSILON))
- return 2;
- }
+ if (RE_rayface_isQuad(face)) {
+ if (isect_ray_tri_watertight_v3(start, &isect_precalc, face->v1, face->v3, face->v4, &l, uv)) {
+ return 2;
}
}
@@ -317,7 +227,7 @@ MALWAYS_INLINE int intersect_rayface(RayObject *hit_obj, RayFace *face, Isect *i
RE_RC_COUNT(is->raycounter->faces.test);
dist = is->dist;
- ok = isec_tri_quad(is->start, is->dir, face, uv, &dist);
+ ok = isec_tri_quad(is->start, &is->isect_precalc, face, uv, &dist);
if (ok) {
@@ -389,6 +299,9 @@ 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 */
diff --git a/source/blender/render/intern/source/render_result.c b/source/blender/render/intern/source/render_result.c
index 2d26fcf4905..bddd84c45d7 100644
--- a/source/blender/render/intern/source/render_result.c
+++ b/source/blender/render/intern/source/render_result.c
@@ -359,102 +359,109 @@ static const char *name_from_passtype(int passtype, int channel)
return "Unknown";
}
-static int passtype_from_name(const char *str)
+static int passtype_from_name(const char *str, int passflag)
{
+ /* We do not really support several pass of the same types, so in case we are opening an EXR file with several pass
+ * names detected as same pass type, only return that pass type the first time, and return 'uknown' for the others.
+ * See T48466. */
+#define RETURN_PASS(_passtype) return (passflag & (_passtype)) ? 0 : (_passtype)
+
if (STRPREFIX(str, "Combined"))
- return SCE_PASS_COMBINED;
+ RETURN_PASS(SCE_PASS_COMBINED);
if (STRPREFIX(str, "Depth"))
- return SCE_PASS_Z;
+ RETURN_PASS(SCE_PASS_Z);
if (STRPREFIX(str, "Vector"))
- return SCE_PASS_VECTOR;
+ RETURN_PASS(SCE_PASS_VECTOR);
if (STRPREFIX(str, "Normal"))
- return SCE_PASS_NORMAL;
+ RETURN_PASS(SCE_PASS_NORMAL);
if (STRPREFIX(str, "UV"))
- return SCE_PASS_UV;
+ RETURN_PASS(SCE_PASS_UV);
if (STRPREFIX(str, "Color"))
- return SCE_PASS_RGBA;
+ RETURN_PASS(SCE_PASS_RGBA);
if (STRPREFIX(str, "Emit"))
- return SCE_PASS_EMIT;
+ RETURN_PASS(SCE_PASS_EMIT);
if (STRPREFIX(str, "Diffuse"))
- return SCE_PASS_DIFFUSE;
+ RETURN_PASS(SCE_PASS_DIFFUSE);
if (STRPREFIX(str, "Spec"))
- return SCE_PASS_SPEC;
+ RETURN_PASS(SCE_PASS_SPEC);
if (STRPREFIX(str, "Shadow"))
- return SCE_PASS_SHADOW;
+ RETURN_PASS(SCE_PASS_SHADOW);
if (STRPREFIX(str, "AO"))
- return SCE_PASS_AO;
+ RETURN_PASS(SCE_PASS_AO);
if (STRPREFIX(str, "Env"))
- return SCE_PASS_ENVIRONMENT;
+ RETURN_PASS(SCE_PASS_ENVIRONMENT);
if (STRPREFIX(str, "Indirect"))
- return SCE_PASS_INDIRECT;
+ RETURN_PASS(SCE_PASS_INDIRECT);
if (STRPREFIX(str, "Reflect"))
- return SCE_PASS_REFLECT;
+ RETURN_PASS(SCE_PASS_REFLECT);
if (STRPREFIX(str, "Refract"))
- return SCE_PASS_REFRACT;
+ RETURN_PASS(SCE_PASS_REFRACT);
if (STRPREFIX(str, "IndexOB"))
- return SCE_PASS_INDEXOB;
+ RETURN_PASS(SCE_PASS_INDEXOB);
if (STRPREFIX(str, "IndexMA"))
- return SCE_PASS_INDEXMA;
+ RETURN_PASS(SCE_PASS_INDEXMA);
if (STRPREFIX(str, "Mist"))
- return SCE_PASS_MIST;
+ RETURN_PASS(SCE_PASS_MIST);
if (STRPREFIX(str, "RayHits"))
- return SCE_PASS_RAYHITS;
+ RETURN_PASS(SCE_PASS_RAYHITS);
if (STRPREFIX(str, "DiffDir"))
- return SCE_PASS_DIFFUSE_DIRECT;
+ RETURN_PASS(SCE_PASS_DIFFUSE_DIRECT);
if (STRPREFIX(str, "DiffInd"))
- return SCE_PASS_DIFFUSE_INDIRECT;
+ RETURN_PASS(SCE_PASS_DIFFUSE_INDIRECT);
if (STRPREFIX(str, "DiffCol"))
- return SCE_PASS_DIFFUSE_COLOR;
+ RETURN_PASS(SCE_PASS_DIFFUSE_COLOR);
if (STRPREFIX(str, "GlossDir"))
- return SCE_PASS_GLOSSY_DIRECT;
+ RETURN_PASS(SCE_PASS_GLOSSY_DIRECT);
if (STRPREFIX(str, "GlossInd"))
- return SCE_PASS_GLOSSY_INDIRECT;
+ RETURN_PASS(SCE_PASS_GLOSSY_INDIRECT);
if (STRPREFIX(str, "GlossCol"))
- return SCE_PASS_GLOSSY_COLOR;
+ RETURN_PASS(SCE_PASS_GLOSSY_COLOR);
if (STRPREFIX(str, "TransDir"))
- return SCE_PASS_TRANSM_DIRECT;
+ RETURN_PASS(SCE_PASS_TRANSM_DIRECT);
if (STRPREFIX(str, "TransInd"))
- return SCE_PASS_TRANSM_INDIRECT;
+ RETURN_PASS(SCE_PASS_TRANSM_INDIRECT);
if (STRPREFIX(str, "TransCol"))
- return SCE_PASS_TRANSM_COLOR;
+ RETURN_PASS(SCE_PASS_TRANSM_COLOR);
if (STRPREFIX(str, "SubsurfaceDir"))
- return SCE_PASS_SUBSURFACE_DIRECT;
+ RETURN_PASS(SCE_PASS_SUBSURFACE_DIRECT);
if (STRPREFIX(str, "SubsurfaceInd"))
- return SCE_PASS_SUBSURFACE_INDIRECT;
+ RETURN_PASS(SCE_PASS_SUBSURFACE_INDIRECT);
if (STRPREFIX(str, "SubsurfaceCol"))
- return SCE_PASS_SUBSURFACE_COLOR;
+ RETURN_PASS(SCE_PASS_SUBSURFACE_COLOR);
return 0;
+
+#undef RETURN_PASS
}
@@ -838,8 +845,9 @@ static void ml_addpass_cb(void *base, void *lay, const char *str, float *rect, i
BLI_addtail(&rl->passes, rpass);
rpass->channels = totchan;
- rpass->passtype = passtype_from_name(str);
- if (rpass->passtype == 0) printf("unknown pass %s\n", str);
+ rpass->passtype = passtype_from_name(str, rl->passflag);
+ if (rpass->passtype == 0)
+ printf("unknown pass %s\n", str);
rl->passflag |= rpass->passtype;
/* channel id chars */
diff --git a/source/blender/render/intern/source/shadeinput.c b/source/blender/render/intern/source/shadeinput.c
index 6e01921a6a7..20602314526 100644
--- a/source/blender/render/intern/source/shadeinput.c
+++ b/source/blender/render/intern/source/shadeinput.c
@@ -1339,6 +1339,7 @@ void shade_input_initialize(ShadeInput *shi, RenderPart *pa, RenderLayer *rl, in
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;
diff --git a/source/blender/windowmanager/WM_api.h b/source/blender/windowmanager/WM_api.h
index db2547e4fbe..388837af67a 100644
--- a/source/blender/windowmanager/WM_api.h
+++ b/source/blender/windowmanager/WM_api.h
@@ -220,6 +220,7 @@ void WM_event_timer_sleep(struct wmWindowManager *wm, struct wmWindow *wi
/* invoke callback, uses enum property named "type" */
void WM_operator_view3d_unit_defaults(struct bContext *C, struct wmOperator *op);
int WM_operator_smooth_viewtx_get(const struct wmOperator *op);
+int WM_menu_invoke_ex(struct bContext *C, struct wmOperator *op, int opcontext);
int WM_menu_invoke (struct bContext *C, struct wmOperator *op, const struct wmEvent *event);
int WM_enum_search_invoke(struct bContext *C, struct wmOperator *op, const struct wmEvent *event);
/* invoke callback, confirm menu + exec */
diff --git a/source/blender/windowmanager/intern/wm_draw.c b/source/blender/windowmanager/intern/wm_draw.c
index 8f15d94f538..962ed3c040d 100644
--- a/source/blender/windowmanager/intern/wm_draw.c
+++ b/source/blender/windowmanager/intern/wm_draw.c
@@ -437,8 +437,6 @@ void wm_triple_draw_textures(wmWindow *win, wmDrawTriple *triple, float alpha)
float halfx, halfy, ratiox, ratioy;
- glEnable(triple->target);
-
/* wmOrtho for the screen has this same offset */
ratiox = sizex;
ratioy = sizey;
@@ -453,6 +451,8 @@ void wm_triple_draw_textures(wmWindow *win, wmDrawTriple *triple, float alpha)
halfy /= triple->y;
}
+ GPU_basic_shader_bind((triple->target == GL_TEXTURE_2D) ? GPU_SHADER_TEXTURE_2D : GPU_SHADER_TEXTURE_RECT);
+
glBindTexture(triple->target, triple->bind);
glColor4f(1.0f, 1.0f, 1.0f, alpha);
@@ -471,7 +471,8 @@ void wm_triple_draw_textures(wmWindow *win, wmDrawTriple *triple, float alpha)
glEnd();
glBindTexture(triple->target, 0);
- glDisable(triple->target);
+
+ GPU_basic_shader_bind(GPU_SHADER_USE_COLOR);
}
static void wm_triple_copy_textures(wmWindow *win, wmDrawTriple *triple)
diff --git a/source/blender/windowmanager/intern/wm_files.c b/source/blender/windowmanager/intern/wm_files.c
index 36b819d3495..729af731dfe 100644
--- a/source/blender/windowmanager/intern/wm_files.c
+++ b/source/blender/windowmanager/intern/wm_files.c
@@ -435,8 +435,7 @@ void wm_file_read_report(bContext *C)
}
BKE_reportf(reports, RPT_ERROR,
- "Engine '%s' not available for scene '%s' "
- "(an addon may need to be installed or enabled)",
+ "Engine '%s' not available for scene '%s' (an add-on may need to be installed or enabled)",
sce->r.engine, sce->id.name + 2);
}
}
diff --git a/source/blender/windowmanager/intern/wm_gesture.c b/source/blender/windowmanager/intern/wm_gesture.c
index 26d1d4c3266..db933ad2d76 100644
--- a/source/blender/windowmanager/intern/wm_gesture.c
+++ b/source/blender/windowmanager/intern/wm_gesture.c
@@ -281,6 +281,9 @@ static void draw_filled_lasso(wmWindow *win, wmGesture *gt)
(const int (*)[2])moves, tot,
draw_filled_lasso_px_cb, &lasso_fill_data);
+ int bound_options;
+ GPU_BASIC_SHADER_DISABLE_AND_STORE(bound_options);
+
glEnable(GL_BLEND);
// glColor4f(1.0, 1.0, 1.0, 0.05);
@@ -288,6 +291,8 @@ static void draw_filled_lasso(wmWindow *win, wmGesture *gt)
glDrawPixels(w, h, GL_RGBA, GL_UNSIGNED_BYTE, pixel_buf);
+ GPU_BASIC_SHADER_ENABLE_AND_RESTORE(bound_options);
+
glDisable(GL_BLEND);
MEM_freeN(pixel_buf);
}
diff --git a/source/blender/windowmanager/intern/wm_operators.c b/source/blender/windowmanager/intern/wm_operators.c
index 6ef8965a408..b4295bb2607 100644
--- a/source/blender/windowmanager/intern/wm_operators.c
+++ b/source/blender/windowmanager/intern/wm_operators.c
@@ -1068,7 +1068,7 @@ int WM_operator_smooth_viewtx_get(const wmOperator *op)
}
/* invoke callback, uses enum property named "type" */
-int WM_menu_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
+int WM_menu_invoke_ex(bContext *C, wmOperator *op, int opcontext)
{
PropertyRNA *prop = op->type->prop;
uiPopupMenu *pup;
@@ -1090,8 +1090,8 @@ int WM_menu_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
pup = UI_popup_menu_begin(C, RNA_struct_ui_name(op->type->srna), ICON_NONE);
layout = UI_popup_menu_layout(pup);
/* set this so the default execution context is the same as submenus */
- uiLayoutSetOperatorContext(layout, WM_OP_INVOKE_REGION_WIN);
- uiItemsFullEnumO(layout, op->type->idname, RNA_property_identifier(prop), op->ptr->data, WM_OP_EXEC_REGION_WIN, 0);
+ uiLayoutSetOperatorContext(layout, opcontext);
+ uiItemsFullEnumO(layout, op->type->idname, RNA_property_identifier(prop), op->ptr->data, opcontext, 0);
UI_popup_menu_end(C, pup);
return OPERATOR_INTERFACE;
}
@@ -1099,6 +1099,11 @@ int WM_menu_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
return OPERATOR_CANCELLED;
}
+int WM_menu_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
+{
+ return WM_menu_invoke_ex(C, op, WM_OP_INVOKE_REGION_WIN);
+}
+
/* generic enum search invoke popup */
static uiBlock *wm_enum_search_menu(bContext *C, ARegion *ar, void *arg_op)
diff --git a/source/blender/windowmanager/wm_event_types.h b/source/blender/windowmanager/wm_event_types.h
index 449612bc5fd..3085f138846 100644
--- a/source/blender/windowmanager/wm_event_types.h
+++ b/source/blender/windowmanager/wm_event_types.h
@@ -311,14 +311,17 @@ enum {
TIMERNOTIFIER = 0x0118, /* timer event, notifier sender */
TIMERF = 0x011F, /* last timer */
- /* Tweak, gestures: 0x500x, 0x501x */
+ /* Actionzones, tweak, gestures: 0x500x, 0x501x */
EVT_ACTIONZONE_AREA = 0x5000,
EVT_ACTIONZONE_REGION = 0x5001,
EVT_ACTIONZONE_FULLSCREEN = 0x5011,
/* NOTE: these values are saved in keymap files, do not change them but just add new ones */
- /* tweak events, for L M R mousebuttons */
+ /* Tweak events:
+ * Sent as additional event with the mouse coordinates from where the initial click was placed. */
+
+ /* tweak events for L M R mousebuttons */
EVT_TWEAK_L = 0x5002,
EVT_TWEAK_M = 0x5003,
EVT_TWEAK_R = 0x5004,
@@ -343,37 +346,38 @@ enum {
/* *********** wmEvent.type helpers. ********** */
/* test whether the event is timer event */
-#define ISTIMER(event_type) (event_type >= TIMER && event_type <= TIMERF)
+#define ISTIMER(event_type) ((event_type) >= TIMER && (event_type) <= TIMERF)
/* for event checks */
/* only used for KM_TEXTINPUT, so assume that we want all user-inputtable ascii codes included */
/* UNUSED - see wm_eventmatch - BUG [#30479] */
-/* #define ISTEXTINPUT(event_type) (event_type >= ' ' && event_type <= 255) */
+/* #define ISTEXTINPUT(event_type) ((event_type) >= ' ' && (event_type) <= 255) */
/* note, an alternative could be to check 'event->utf8_buf' */
/* test whether the event is a key on the keyboard */
#define ISKEYBOARD(event_type) \
- ((event_type >= 0x0020 && event_type <= 0x00ff) || \
- (event_type >= 0x012c && event_type <= 0x013f))
+ (((event_type) >= 0x0020 && (event_type) <= 0x00ff) || \
+ ((event_type) >= 0x012c && (event_type) <= 0x013f))
/* test whether the event is a modifier key */
-#define ISKEYMODIFIER(event_type) ((event_type >= LEFTCTRLKEY && event_type <= LEFTSHIFTKEY) || event_type == OSKEY)
+#define ISKEYMODIFIER(event_type) \
+ (((event_type) >= LEFTCTRLKEY && (event_type) <= LEFTSHIFTKEY) || (event_type) == OSKEY)
/* test whether the event is a mouse button */
-#define ISMOUSE(event_type) (event_type >= LEFTMOUSE && event_type <= BUTTON7MOUSE)
+#define ISMOUSE(event_type) ((event_type) >= LEFTMOUSE && (event_type) <= BUTTON7MOUSE)
/* test whether the event is tweak event */
-#define ISTWEAK(event_type) (event_type >= EVT_TWEAK_L && event_type <= EVT_GESTURE)
+#define ISTWEAK(event_type) ((event_type) >= EVT_TWEAK_L && (event_type) <= EVT_GESTURE)
/* test whether the event is a NDOF event */
-#define ISNDOF(event_type) (event_type >= NDOF_MOTION && event_type < NDOF_LAST)
+#define ISNDOF(event_type) ((event_type) >= NDOF_MOTION && (event_type) < NDOF_LAST)
/* test whether event type is acceptable as hotkey, excluding modifiers */
#define ISHOTKEY(event_type) \
((ISKEYBOARD(event_type) || ISMOUSE(event_type) || ISNDOF(event_type)) && \
- (event_type != ESCKEY) && \
- (event_type >= LEFTCTRLKEY && event_type <= LEFTSHIFTKEY) == false && \
- (event_type >= UNKNOWNKEY && event_type <= GRLESSKEY) == false)
+ ((event_type) != ESCKEY) && \
+ ((event_type) >= LEFTCTRLKEY && (event_type) <= LEFTSHIFTKEY) == false && \
+ ((event_type) >= UNKNOWNKEY && (event_type) <= GRLESSKEY) == false)
/* internal helpers*/
#define _VA_IS_EVENT_MOD2(v, a) (CHECK_TYPE_INLINE(v, wmEvent *), \
diff --git a/source/blenderplayer/CMakeLists.txt b/source/blenderplayer/CMakeLists.txt
index b543ac43378..b034ec91cb9 100644
--- a/source/blenderplayer/CMakeLists.txt
+++ b/source/blenderplayer/CMakeLists.txt
@@ -111,7 +111,6 @@ endif()
ge_player_common
bf_intern_string
bf_intern_ghost
- bf_intern_ghostndof3dconnexion
bf_rna
bf_blenkernel
bf_depsgraph
diff --git a/source/blenderplayer/bad_level_call_stubs/stubs.c b/source/blenderplayer/bad_level_call_stubs/stubs.c
index 3ce7788fdf8..95abfdc4f4c 100644
--- a/source/blenderplayer/bad_level_call_stubs/stubs.c
+++ b/source/blenderplayer/bad_level_call_stubs/stubs.c
@@ -530,6 +530,7 @@ SnapObjectContext *ED_transform_snap_object_context_create_view3d(
void ED_transform_snap_object_context_destroy(SnapObjectContext *sctx) RET_NONE
bool ED_transform_snap_object_project_ray_ex(
struct SnapObjectContext *sctx,
+ const unsigned short snap_to,
const struct SnapObjectParams *params,
const float ray_start[3], const float ray_normal[3], float *ray_depth,
/* return args */
@@ -712,6 +713,7 @@ int collada_export(struct Scene *sce,
int triangulate,
int use_object_instantiation,
+ int use_blender_profile,
int sort_by_name,
BC_export_transformation_type export_transformation_type,
int open_sim) RET_ZERO
diff --git a/source/creator/CMakeLists.txt b/source/creator/CMakeLists.txt
index e3cbfbf838b..122c10ef216 100644
--- a/source/creator/CMakeLists.txt
+++ b/source/creator/CMakeLists.txt
@@ -692,6 +692,10 @@ elseif(WIN32)
)
if(WITH_PYTHON_INSTALL_NUMPY)
+ set(PYTHON_NUMPY_VERSION 1.9)
+ if(MSVC_VERSION EQUAL 1900)
+ set(PYTHON_NUMPY_VERSION 1.11)
+ endif()
add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${BLENDER_VERSION}/python/lib/site-packages
COMMAND ${CMAKE_COMMAND} -E
make_directory ${CMAKE_CURRENT_BINARY_DIR}/${BLENDER_VERSION}/python/lib/site-packages)
@@ -699,9 +703,9 @@ elseif(WIN32)
add_custom_command(
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${BLENDER_VERSION}/python/lib/site-packages/numpy
COMMAND ${CMAKE_COMMAND} -E
- tar xzvf "${LIBDIR}/release/python${_PYTHON_VERSION_NO_DOTS}_numpy_1.9.tar.gz"
+ tar xzvf "${LIBDIR}/release/python${_PYTHON_VERSION_NO_DOTS}_numpy_${PYTHON_NUMPY_VERSION}.tar.gz"
DEPENDS
- ${LIBDIR}/release/python${_PYTHON_VERSION_NO_DOTS}_numpy_1.9.tar.gz
+ ${LIBDIR}/release/python${_PYTHON_VERSION_NO_DOTS}_numpy_${PYTHON_NUMPY_VERSION}.tar.gz
${CMAKE_CURRENT_BINARY_DIR}/${BLENDER_VERSION}/python/lib/site-packages
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/${BLENDER_VERSION}/python/lib/site-packages
)
diff --git a/source/creator/creator_args.c b/source/creator/creator_args.c
index 69765fc2341..c89cdea4e29 100644
--- a/source/creator/creator_args.c
+++ b/source/creator/creator_args.c
@@ -72,6 +72,7 @@
#include "WM_api.h"
+#include "GPU_basic_shader.h"
#include "GPU_draw.h"
#include "GPU_extensions.h"
@@ -583,9 +584,17 @@ static int arg_handle_print_help(int UNUSED(argc), const char **UNUSED(argv), vo
BLI_argsPrintArgDoc(ba, "--");
+ printf("\n");
printf("Other Options:\n");
BLI_argsPrintOtherDoc(ba);
+ /* keep last args */
+ printf("\n");
+ printf("Experimental Features:\n");
+ BLI_argsPrintArgDoc(ba, "--enable-new-depsgraph");
+ BLI_argsPrintArgDoc(ba, "--enable-new-basic-shader-glsl");
+
+ printf("\n");
printf("Argument Parsing:\n");
printf("\tArguments must be separated by white space, eg:\n");
printf("\t# blender -ba test.blend\n");
@@ -619,11 +628,6 @@ static int arg_handle_print_help(int UNUSED(argc), const char **UNUSED(argv), vo
#endif
printf(" $PYTHONHOME Path to the python directory, eg. /usr/lib/python.\n\n");
- /* keep last */
- printf("\n");
- printf("Experimental Features:\n");
- BLI_argsPrintArgDoc(ba, "--enable-new-depsgraph");
-
exit(0);
return 0;
@@ -862,7 +866,7 @@ static const char arg_handle_playback_mode_doc[] =
"<options> <file(s)>\n"
"\tPlayback <file(s)>, only operates this way when not running in background.\n"
"\t\t-p <sx> <sy>\tOpen with lower left corner at <sx>, <sy>\n"
-"\t\t-m\t\tRead from disk (Don't buffer)\n"
+"\t\t-m\t\tRead from disk (Do not buffer)\n"
"\t\t-f <fps> <fps-base>\t\tSpecify FPS to start with\n"
"\t\t-j <frame>\tSet frame step to <frame>\n"
"\t\t-s <frame>\tPlay from <frame>\n"
@@ -950,10 +954,10 @@ static int arg_handle_start_with_console(int UNUSED(argc), const char **UNUSED(a
}
static const char arg_handle_register_extension_doc[] =
-"\n\tRegister .blend extension, then exit (Windows only)"
+"\n\tRegister blend-file extension, then exit (Windows only)"
;
static const char arg_handle_register_extension_doc_silent[] =
-"\n\tSilently register .blend extension, then exit (Windows only)"
+"\n\tSilently register blend-file extension, then exit (Windows only)"
;
static int arg_handle_register_extension(int UNUSED(argc), const char **UNUSED(argv), void *data)
{
@@ -1170,6 +1174,16 @@ static int arg_handle_depsgraph_use_new(int UNUSED(argc), const char **UNUSED(ar
return 0;
}
+static const char arg_handle_basic_shader_glsl_use_new_doc[] =
+"\n\tUse new GLSL basic shader"
+;
+static int arg_handle_basic_shader_glsl_use_new(int UNUSED(argc), const char **UNUSED(argv), void *UNUSED(data))
+{
+ printf("Using new GLSL basic shader.\n");
+ GPU_basic_shader_use_glsl_set(true);
+ return 0;
+}
+
static const char arg_handle_verbosity_set_doc[] =
"<verbose>\n"
"\tSet logging verbosity level."
@@ -1805,6 +1819,7 @@ void main_args_setup(bContext *C, bArgs *ba, SYS_SystemHandle *syshandle)
CB_EX(arg_handle_debug_mode_generic_set, gpumem), (void *)G_DEBUG_GPU_MEM);
BLI_argsAdd(ba, 1, NULL, "--enable-new-depsgraph", CB(arg_handle_depsgraph_use_new), NULL);
+ BLI_argsAdd(ba, 1, NULL, "--enable-new-basic-shader-glsl", CB(arg_handle_basic_shader_glsl_use_new), NULL);
BLI_argsAdd(ba, 1, NULL, "--verbose", CB(arg_handle_verbosity_set), NULL);
diff --git a/tests/gtests/blenlib/BLI_array_store_test.cc b/tests/gtests/blenlib/BLI_array_store_test.cc
new file mode 100644
index 00000000000..33fb454ec2f
--- /dev/null
+++ b/tests/gtests/blenlib/BLI_array_store_test.cc
@@ -0,0 +1,815 @@
+/* Apache License, Version 2.0 */
+
+#include "testing/testing.h"
+
+extern "C" {
+#include "BLI_array_store.h"
+
+#include "MEM_guardedalloc.h"
+#include "BLI_sys_types.h"
+#include "BLI_utildefines.h"
+#include "BLI_listbase.h"
+#include "BLI_array_utils.h"
+#include "BLI_string.h"
+#include "BLI_rand.h"
+#include "BLI_ressource_strings.h"
+}
+
+/* print memory savings */
+// #define DEBUG_PRINT
+
+
+/* -------------------------------------------------------------------- */
+/* Helper functions */
+
+#ifdef DEBUG_PRINT
+static void print_mem_saved(const char *id, const BArrayStore *bs)
+{
+ const double size_real = BLI_array_store_calc_size_compacted_get(bs);
+ const double size_expand = BLI_array_store_calc_size_expanded_get(bs);
+ const double percent = size_expand ? ((size_real / size_expand) * 100.0) : -1.0;
+ printf("%s: %.8f%%\n", id, percent);
+}
+#endif
+
+
+/* -------------------------------------------------------------------- */
+/* Test Chunks (building data from list of chunks) */
+
+typedef struct TestChunnk {
+ struct TestChunnk *next, *prev;
+ const void *data;
+ size_t data_len;
+} TestChunnk;
+
+static TestChunnk *testchunk_list_add(ListBase *lb, const void *data, size_t data_len)
+{
+ TestChunnk *tc = (TestChunnk *)MEM_mallocN(sizeof(*tc), __func__);
+ tc->data = data;
+ tc->data_len = data_len;
+ BLI_addtail(lb, tc);
+
+ return tc;
+}
+
+#if 0
+static TestChunnk *testchunk_list_add_copydata(ListBase *lb, const void *data, size_t data_len)
+{
+ void *data_copy = MEM_mallocN(data_len, __func__);
+ memcpy(data_copy, data, data_len);
+ return testchunk_list_add(lb, data_copy, data_len);
+}
+#endif
+
+static void testchunk_list_free(ListBase *lb)
+{
+ for (TestChunnk *tc = (TestChunnk *)lb->first, *tb_next; tc; tc = tb_next) {
+ tb_next = tc->next;
+ MEM_freeN((void *)tc->data);
+ MEM_freeN(tc);
+ }
+ BLI_listbase_clear(lb);
+}
+
+#if 0
+static char *testchunk_as_data(
+ ListBase *lb,
+ size_t *r_data_len)
+{
+ size_t data_len = 0;
+ for (TestChunnk *tc = (TestChunnk *)lb->first; tc; tc = tc->next) {
+ data_len += tc->data_len;
+ }
+ char *data = (char *)MEM_mallocN(data_len, __func__);
+ size_t i = 0;
+ for (TestChunnk *tc = (TestChunnk *)lb->first; tc; tc = tc->next) {
+ memcpy(&data[i], tc->data, tc->data_len);
+ data_len += tc->data_len;
+ i += tc->data_len;
+ }
+ if (r_data_len) {
+ *r_data_len = i;
+ }
+ return data;
+}
+#endif
+
+static char *testchunk_as_data_array(
+ TestChunnk **tc_array, int tc_array_len,
+ size_t *r_data_len)
+{
+ size_t data_len = 0;
+ for (int tc_index = 0; tc_index < tc_array_len; tc_index++) {
+ data_len += tc_array[tc_index]->data_len;
+ }
+ char *data = (char *)MEM_mallocN(data_len, __func__);
+ size_t i = 0;
+ for (int tc_index = 0; tc_index < tc_array_len; tc_index++) {
+ TestChunnk *tc = tc_array[tc_index];
+ memcpy(&data[i], tc->data, tc->data_len);
+ i += tc->data_len;
+ }
+ if (r_data_len) {
+ *r_data_len = i;
+ }
+ return data;
+}
+
+
+/* -------------------------------------------------------------------- */
+/* Test Buffer */
+
+/* API to handle local allocation of data so we can compare it with the data in the array_store */
+typedef struct TestBuffer {
+ struct TestBuffer *next, *prev;
+ const void *data;
+ size_t data_len;
+
+ /* for reference */
+ BArrayState *state;
+} TestBuffer;
+
+static TestBuffer *testbuffer_list_add(ListBase *lb, const void *data, size_t data_len)
+{
+ TestBuffer *tb = (TestBuffer *)MEM_mallocN(sizeof(*tb), __func__);
+ tb->data = data;
+ tb->data_len = data_len;
+ tb->state = NULL;
+ BLI_addtail(lb, tb);
+ return tb;
+}
+
+static TestBuffer *testbuffer_list_add_copydata(ListBase *lb, const void *data, size_t data_len)
+{
+ void *data_copy = MEM_mallocN(data_len, __func__);
+ memcpy(data_copy, data, data_len);
+ return testbuffer_list_add(lb, data_copy, data_len);
+}
+
+static void testbuffer_list_state_from_data(
+ ListBase *lb,
+ const char *data, const size_t data_len)
+{
+ testbuffer_list_add_copydata(lb, (const void *)data, data_len);
+}
+
+/**
+ * A version of testbuffer_list_state_from_data that expand data by stride,
+ * handy so we can test data at different strides.
+ */
+static void testbuffer_list_state_from_data__stride_expand(
+ ListBase *lb,
+ const char *data, const size_t data_len,
+ const size_t stride)
+{
+ if (stride == 1) {
+ testbuffer_list_state_from_data(lb, data, data_len);
+ }
+ else {
+ const size_t data_stride_len = data_len * stride;
+ char *data_stride = (char *)MEM_mallocN(data_stride_len, __func__);
+
+ for (size_t i = 0, i_stride = 0; i < data_len; i += 1, i_stride += stride) {
+ memset(&data_stride[i_stride], data[i], stride);
+ }
+
+ testbuffer_list_add(lb, (const void *)data_stride, data_stride_len);
+ }
+}
+
+#define testbuffer_list_state_from_string_array(lb, data_array) \
+{ \
+ unsigned int i_ = 0; \
+ const char *data; \
+ while ((data = data_array[i_++])) { \
+ testbuffer_list_state_from_data(lb, data, strlen(data)); \
+ } \
+} ((void)0)
+
+//
+
+#define TESTBUFFER_STRINGS_CREATE(lb, ...) \
+{ \
+ BLI_listbase_clear(lb); \
+ const char *data_array[] = {__VA_ARGS__ NULL}; \
+ testbuffer_list_state_from_string_array((lb), data_array); \
+} ((void)0)
+
+/* test in both directions */
+#define TESTBUFFER_STRINGS_EX(bs, ...) \
+{ \
+ ListBase lb; \
+ TESTBUFFER_STRINGS_CREATE(&lb, __VA_ARGS__); \
+ \
+ testbuffer_run_tests(bs, &lb); \
+ \
+ testbuffer_list_free(&lb); \
+} ((void)0)
+
+#define TESTBUFFER_STRINGS(stride, chunk_count, ...) \
+{ \
+ ListBase lb; \
+ TESTBUFFER_STRINGS_CREATE(&lb, __VA_ARGS__); \
+ \
+ testbuffer_run_tests_simple(&lb, stride, chunk_count); \
+ \
+ testbuffer_list_free(&lb); \
+} ((void)0)
+
+static bool testbuffer_item_validate(TestBuffer *tb)
+{
+ size_t data_state_len;
+ bool ok = true;
+ void *data_state = BLI_array_store_state_data_get_alloc(tb->state, &data_state_len);
+ if (tb->data_len != data_state_len) {
+ ok = false;
+ }
+ else if (memcmp(data_state, tb->data, data_state_len) != 0) {
+ ok = false;
+ }
+ MEM_freeN(data_state);
+ return ok;
+}
+
+static bool testbuffer_list_validate(const ListBase *lb)
+{
+ for (TestBuffer *tb = (TestBuffer *)lb->first; tb; tb = tb->next) {
+ if (!testbuffer_item_validate(tb)) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+static void testbuffer_list_data_randomize(ListBase *lb, unsigned int random_seed)
+{
+ for (TestBuffer *tb = (TestBuffer *)lb->first; tb; tb = tb->next) {
+ BLI_array_randomize((void *)tb->data, 1, tb->data_len, random_seed++);
+ }
+}
+
+static void testbuffer_list_store_populate(
+ BArrayStore *bs, ListBase *lb)
+{
+ for (TestBuffer *tb = (TestBuffer *)lb->first, *tb_prev = NULL; tb; tb_prev = tb, tb = tb->next) {
+ tb->state = BLI_array_store_state_add(bs, tb->data, tb->data_len, (tb_prev ? tb_prev->state : NULL));
+ }
+}
+
+static void testbuffer_list_store_clear(
+ BArrayStore *bs, ListBase *lb)
+{
+ for (TestBuffer *tb = (TestBuffer *)lb->first; tb; tb = tb->next) {
+ BLI_array_store_state_remove(bs, tb->state);
+ tb->state = NULL;
+ }
+}
+
+static void testbuffer_list_free(ListBase *lb)
+{
+ for (TestBuffer *tb = (TestBuffer *)lb->first, *tb_next; tb; tb = tb_next) {
+ tb_next = tb->next;
+ MEM_freeN((void *)tb->data);
+ MEM_freeN(tb);
+ }
+ BLI_listbase_clear(lb);
+}
+
+static void testbuffer_run_tests_single(
+ BArrayStore *bs, ListBase *lb)
+{
+ testbuffer_list_store_populate(bs, lb);
+ EXPECT_EQ(true, testbuffer_list_validate(lb));
+ EXPECT_EQ(true, BLI_array_store_is_valid(bs));
+#ifdef DEBUG_PRINT
+ print_mem_saved("data", bs);
+#endif
+}
+
+/* avoid copy-paste code to run tests */
+static void testbuffer_run_tests(
+ BArrayStore *bs, ListBase *lb)
+{
+ /* forwards */
+ testbuffer_run_tests_single(bs, lb);
+ testbuffer_list_store_clear(bs, lb);
+
+ BLI_listbase_reverse(lb);
+
+ /* backwards */
+ testbuffer_run_tests_single(bs, lb);
+ testbuffer_list_store_clear(bs, lb);
+}
+
+static void testbuffer_run_tests_simple(
+ ListBase *lb,
+ const int stride, const int chunk_count)
+{
+ BArrayStore *bs = BLI_array_store_create(stride, chunk_count);
+ testbuffer_run_tests(bs, lb);
+ BLI_array_store_destroy(bs);
+}
+
+
+/* -------------------------------------------------------------------- */
+/* Basic Tests */
+
+TEST(array_store, Nop)
+{
+ BArrayStore *bs = BLI_array_store_create(1, 32);
+ BLI_array_store_destroy(bs);
+}
+
+TEST(array_store, NopState)
+{
+ BArrayStore *bs = BLI_array_store_create(1, 32);
+ const unsigned char data[] = "test";
+ BArrayState *state = BLI_array_store_state_add(bs, data, sizeof(data) - 1, NULL);
+ EXPECT_EQ(sizeof(data) - 1, BLI_array_store_state_size_get(state));
+ BLI_array_store_state_remove(bs, state);
+ BLI_array_store_destroy(bs);
+}
+
+TEST(array_store, Single)
+{
+ BArrayStore *bs = BLI_array_store_create(1, 32);
+ const char data_src[] = "test";
+ const char *data_dst;
+ BArrayState *state = BLI_array_store_state_add(bs, data_src, sizeof(data_src), NULL);
+ size_t data_dst_len;
+ data_dst = (char *)BLI_array_store_state_data_get_alloc(state, &data_dst_len);
+ EXPECT_STREQ(data_src, data_dst);
+ EXPECT_EQ(sizeof(data_src), data_dst_len);
+ BLI_array_store_destroy(bs);
+ MEM_freeN((void *)data_dst);
+}
+
+TEST(array_store, DoubleNop)
+{
+ BArrayStore *bs = BLI_array_store_create(1, 32);
+ const char data_src[] = "test";
+ const char *data_dst;
+
+ BArrayState *state_a = BLI_array_store_state_add(bs, data_src, sizeof(data_src), NULL);
+ BArrayState *state_b = BLI_array_store_state_add(bs, data_src, sizeof(data_src), state_a);
+
+ EXPECT_EQ(sizeof(data_src), BLI_array_store_calc_size_compacted_get(bs));
+ EXPECT_EQ(sizeof(data_src) * 2, BLI_array_store_calc_size_expanded_get(bs));
+
+ size_t data_dst_len;
+
+ data_dst = (char *)BLI_array_store_state_data_get_alloc(state_a, &data_dst_len);
+ EXPECT_STREQ(data_src, data_dst);
+ MEM_freeN((void *)data_dst);
+
+ data_dst = (char *)BLI_array_store_state_data_get_alloc(state_b, &data_dst_len);
+ EXPECT_STREQ(data_src, data_dst);
+ MEM_freeN((void *)data_dst);
+
+ EXPECT_EQ(sizeof(data_src), data_dst_len);
+ BLI_array_store_destroy(bs);
+}
+
+TEST(array_store, DoubleDiff)
+{
+ BArrayStore *bs = BLI_array_store_create(1, 32);
+ const char data_src_a[] = "test";
+ const char data_src_b[] = "####";
+ const char *data_dst;
+
+ BArrayState *state_a = BLI_array_store_state_add(bs, data_src_a, sizeof(data_src_a), NULL);
+ BArrayState *state_b = BLI_array_store_state_add(bs, data_src_b, sizeof(data_src_b), state_a);
+ size_t data_dst_len;
+
+ EXPECT_EQ(sizeof(data_src_a) * 2, BLI_array_store_calc_size_compacted_get(bs));
+ EXPECT_EQ(sizeof(data_src_a) * 2, BLI_array_store_calc_size_expanded_get(bs));
+
+ data_dst = (char *)BLI_array_store_state_data_get_alloc(state_a, &data_dst_len);
+ EXPECT_STREQ(data_src_a, data_dst);
+ MEM_freeN((void *)data_dst);
+
+ data_dst = (char *)BLI_array_store_state_data_get_alloc(state_b, &data_dst_len);
+ EXPECT_STREQ(data_src_b, data_dst);
+ MEM_freeN((void *)data_dst);
+
+ BLI_array_store_destroy(bs);
+}
+
+TEST(array_store, TextMixed)
+{
+ TESTBUFFER_STRINGS(1, 4, "",);
+ TESTBUFFER_STRINGS(1, 4, "test",);
+ TESTBUFFER_STRINGS(1, 4, "", "test",);
+ TESTBUFFER_STRINGS(1, 4, "test", "",);
+ TESTBUFFER_STRINGS(1, 4, "test", "", "test",);
+ TESTBUFFER_STRINGS(1, 4, "", "test", "",);
+}
+
+TEST(array_store, TextDupeIncreaseDecrease)
+{
+ ListBase lb;
+
+#define D "#1#2#3#4"
+ TESTBUFFER_STRINGS_CREATE(
+ &lb,
+ D,
+ D D,
+ D D D,
+ D D D D,
+ );
+
+ BArrayStore *bs = BLI_array_store_create(1, 8);
+
+ /* forward */
+ testbuffer_list_store_populate(bs, &lb);
+ EXPECT_EQ(true, testbuffer_list_validate(&lb));
+ EXPECT_EQ(true, BLI_array_store_is_valid(bs));
+ EXPECT_EQ(strlen(D), BLI_array_store_calc_size_compacted_get(bs));
+
+ testbuffer_list_store_clear(bs, &lb);
+ BLI_listbase_reverse(&lb);
+
+ /* backwards */
+ testbuffer_list_store_populate(bs, &lb);
+ EXPECT_EQ(true, testbuffer_list_validate(&lb));
+ EXPECT_EQ(true, BLI_array_store_is_valid(bs));
+ /* larger since first block doesn't de-duplicate */
+ EXPECT_EQ(strlen(D) * 4, BLI_array_store_calc_size_compacted_get(bs));
+
+#undef D
+ testbuffer_list_free(&lb); \
+
+ BLI_array_store_destroy(bs);
+}
+
+
+/* -------------------------------------------------------------------- */
+/* Plain Text Tests */
+
+/**
+ * Test that uses text input with different params for the array-store
+ * to ensure no corner cases fail.
+ */
+static void plain_text_helper(
+ const char *words, int words_len, const char word_delim,
+ const int stride, const int chunk_count, const int random_seed)
+{
+
+ ListBase lb;
+ BLI_listbase_clear(&lb);
+
+ for (int i = 0, i_prev = 0; i < words_len; i++) {
+ if (ELEM(words[i], word_delim, '\0')) {
+ if (i != i_prev) {
+ testbuffer_list_state_from_data__stride_expand(&lb, &words[i_prev], i - i_prev, stride);
+ }
+ i_prev = i;
+ }
+ }
+
+ if (random_seed) {
+ testbuffer_list_data_randomize(&lb, random_seed);
+ }
+
+ testbuffer_run_tests_simple(&lb, stride, chunk_count);
+
+ testbuffer_list_free(&lb);
+}
+
+/* split by '.' (multiple words) */
+#define WORDS words10k, sizeof(words10k)
+TEST(array_store, TextSentences_Chunk1) { plain_text_helper(WORDS, '.', 1, 1, 0); }
+TEST(array_store, TextSentences_Chunk2) { plain_text_helper(WORDS, '.', 1, 2, 0); }
+TEST(array_store, TextSentences_Chunk8) { plain_text_helper(WORDS, '.', 1, 8, 0); }
+TEST(array_store, TextSentences_Chunk32) { plain_text_helper(WORDS, '.', 1, 32, 0); }
+TEST(array_store, TextSentences_Chunk128) { plain_text_helper(WORDS, '.', 1, 128, 0); }
+TEST(array_store, TextSentences_Chunk1024) { plain_text_helper(WORDS, '.', 1, 1024, 0); }
+/* odd numbers */
+TEST(array_store, TextSentences_Chunk3) { plain_text_helper(WORDS, '.', 1, 3, 0); }
+TEST(array_store, TextSentences_Chunk13) { plain_text_helper(WORDS, '.', 1, 13, 0); }
+TEST(array_store, TextSentences_Chunk131) { plain_text_helper(WORDS, '.', 1, 131, 0); }
+
+/* split by ' ', individual words */
+TEST(array_store, TextWords_Chunk1) { plain_text_helper(WORDS, ' ', 1, 1, 0); }
+TEST(array_store, TextWords_Chunk2) { plain_text_helper(WORDS, ' ', 1, 2, 0); }
+TEST(array_store, TextWords_Chunk8) { plain_text_helper(WORDS, ' ', 1, 8, 0); }
+TEST(array_store, TextWords_Chunk32) { plain_text_helper(WORDS, ' ', 1, 32, 0); }
+TEST(array_store, TextWords_Chunk128) { plain_text_helper(WORDS, ' ', 1, 128, 0); }
+TEST(array_store, TextWords_Chunk1024) { plain_text_helper(WORDS, ' ', 1, 1024, 0); }
+/* odd numbers */
+TEST(array_store, TextWords_Chunk3) { plain_text_helper(WORDS, ' ', 1, 3, 0); }
+TEST(array_store, TextWords_Chunk13) { plain_text_helper(WORDS, ' ', 1, 13, 0); }
+TEST(array_store, TextWords_Chunk131) { plain_text_helper(WORDS, ' ', 1, 131, 0); }
+
+/* various tests with different strides & randomizing */
+TEST(array_store, TextSentencesRandom_Stride3_Chunk3) { plain_text_helper(WORDS, 'q', 3, 3, 7337); }
+TEST(array_store, TextSentencesRandom_Stride8_Chunk8) { plain_text_helper(WORDS, 'n', 8, 8, 5667); }
+TEST(array_store, TextSentencesRandom_Stride32_Chunk1) { plain_text_helper(WORDS, 'a', 1, 32, 1212); }
+TEST(array_store, TextSentencesRandom_Stride12_Chunk512) { plain_text_helper(WORDS, 'g', 12, 512, 9999); }
+TEST(array_store, TextSentencesRandom_Stride128_Chunk6) { plain_text_helper(WORDS, 'b', 20, 6, 1000); }
+
+#undef WORDS
+
+
+/* -------------------------------------------------------------------- */
+/* Random Data Tests */
+
+static unsigned int rand_range_i(RNG *rng, unsigned int min_i, unsigned int max_i, unsigned int step)
+{
+ if (min_i == max_i) {
+ return min_i;
+ }
+ BLI_assert(min_i <= max_i);
+ BLI_assert(((min_i % step) == 0) && ((max_i % step) == 0));
+ unsigned int range = (max_i - min_i);
+ unsigned int value = BLI_rng_get_uint(rng) % range;
+ value = (value / step) * step;
+ return min_i + value;
+}
+
+static void rand_bytes(RNG *rng, char *data, int data_len)
+{
+ BLI_assert(data_len != 0);
+ while (data_len--) {
+ *data = BLI_rng_get_uint(rng) % 256;
+ data++;
+ }
+}
+
+static void testbuffer_list_state_random_data(
+ ListBase *lb,
+ const size_t stride,
+ const size_t data_min_len, const size_t data_max_len,
+
+ const unsigned int mutate, RNG *rng)
+{
+ size_t data_len = rand_range_i(rng, data_min_len, data_max_len + stride, stride);
+ char *data = (char *)MEM_mallocN(data_len, __func__);
+
+ if (lb->last == NULL) {
+ rand_bytes(rng, data, data_len);
+ }
+ else {
+ TestBuffer *tb_last = (TestBuffer *)lb->last;
+ if (tb_last->data_len >= data_len) {
+ memcpy(data, tb_last->data, data_len);
+ }
+ else {
+ memcpy(data, tb_last->data, tb_last->data_len);
+ rand_bytes(rng, &data[tb_last->data_len], data_len - tb_last->data_len);
+ }
+
+ /* perform multiple small mutations to the array. */
+ for (int i = 0; i < mutate; i++) {
+ enum {
+ MUTATE_NOP = 0,
+ MUTATE_ADD,
+ MUTATE_REMOVE,
+ MUTATE_ROTATE,
+ MUTATE_RANDOMIZE,
+ MUTATE_TOTAL,
+ };
+
+ switch ((BLI_rng_get_uint(rng) % MUTATE_TOTAL)) {
+ case MUTATE_NOP:
+ {
+ break;
+ }
+ case MUTATE_ADD:
+ {
+ const unsigned int offset = rand_range_i(rng, 0, data_len, stride);
+ if (data_len < data_max_len) {
+ data_len += stride;
+ data = (char *)MEM_reallocN((void *)data, data_len);
+ memmove(&data[offset + stride], &data[offset], data_len - (offset + stride));
+ rand_bytes(rng, &data[offset], stride);
+ }
+ break;
+ }
+ case MUTATE_REMOVE:
+ {
+ const unsigned int offset = rand_range_i(rng, 0, data_len, stride);
+ if (data_len > data_min_len) {
+ memmove(&data[offset], &data[offset + stride], data_len - (offset + stride));
+ data_len -= stride;
+ }
+ break;
+ }
+ case MUTATE_ROTATE:
+ {
+ int items = data_len / stride;
+ if (items > 1) {
+ _bli_array_wrap(data, items, stride, (BLI_rng_get_uint(rng) % 2) ? -1 : 1);
+ }
+ break;
+ }
+ case MUTATE_RANDOMIZE:
+ {
+ if (data_len > 0) {
+ const unsigned int offset = rand_range_i(rng, 0, data_len - stride, stride);
+ rand_bytes(rng, &data[offset], stride);
+ }
+ break;
+ }
+ default:
+ BLI_assert(0);
+ }
+ }
+ }
+
+ testbuffer_list_add(lb, (const void *)data, data_len);
+}
+
+static void random_data_mutate_helper(
+ const int items_size_min, const int items_size_max, const int items_total,
+ const int stride, const int chunk_count,
+ const int random_seed, const int mutate)
+{
+
+
+ ListBase lb;
+ BLI_listbase_clear(&lb);
+
+ const size_t data_min_len = items_size_min * stride;
+ const size_t data_max_len = items_size_max * stride;
+
+ {
+ RNG *rng = BLI_rng_new(random_seed);
+ for (int i = 0; i < items_total; i++) {
+ testbuffer_list_state_random_data(&lb, stride, data_min_len, data_max_len, mutate, rng);
+ }
+ BLI_rng_free(rng);
+ }
+
+ testbuffer_run_tests_simple(&lb, stride, chunk_count);
+
+ testbuffer_list_free(&lb);
+}
+
+TEST(array_store, TestData_Stride1_Chunk32_Mutate2) { random_data_mutate_helper(0, 100, 400, 1, 32, 9779, 2); }
+TEST(array_store, TestData_Stride8_Chunk512_Mutate2) { random_data_mutate_helper(0, 128, 400, 8, 512, 1001, 2); }
+TEST(array_store, TestData_Stride12_Chunk48_Mutate2) { random_data_mutate_helper(200, 256, 400, 12, 48, 1331, 2); }
+TEST(array_store, TestData_Stride32_Chunk64_Mutate1) { random_data_mutate_helper(0, 256, 200, 32, 64, 3112, 1); }
+TEST(array_store, TestData_Stride32_Chunk64_Mutate8) { random_data_mutate_helper(0, 256, 200, 32, 64, 7117, 8); }
+
+
+/* -------------------------------------------------------------------- */
+/* Randomized Chunks Test */
+
+static void random_chunk_generate(
+ ListBase *lb,
+ const int chunks_per_buffer,
+ const int stride, const int chunk_count,
+ const int random_seed)
+{
+ RNG *rng = BLI_rng_new(random_seed);
+ const size_t chunk_size_bytes = stride * chunk_count;
+ for (int i = 0; i < chunks_per_buffer; i++) {
+ char *data_chunk = (char *)MEM_mallocN(chunk_size_bytes, __func__);
+ rand_bytes(rng, data_chunk, chunk_size_bytes);
+ testchunk_list_add(lb, data_chunk, chunk_size_bytes);
+ }
+ BLI_rng_free(rng);
+}
+
+/**
+ * Add random chunks, then re-order them to ensure chunk de-duplication is working.
+ */
+static void random_chunk_mutate_helper(
+ const int chunks_per_buffer, const int items_total,
+ const int stride, const int chunk_count,
+ const int random_seed)
+{
+ /* generate random chunks */
+
+ ListBase random_chunks;
+ BLI_listbase_clear(&random_chunks);
+ random_chunk_generate(&random_chunks, chunks_per_buffer, stride, chunk_count, random_seed);
+ TestChunnk **chunks_array = (TestChunnk **)MEM_mallocN(chunks_per_buffer * sizeof(TestChunnk *), __func__);
+ {
+ TestChunnk *tc = (TestChunnk *)random_chunks.first;
+ for (int i = 0; i < chunks_per_buffer; i++, tc = tc->next) {
+ chunks_array[i] = tc;
+ }
+ }
+
+ /* add and re-order each time */
+ ListBase lb;
+ BLI_listbase_clear(&lb);
+
+ {
+ RNG *rng = BLI_rng_new(random_seed);
+ for (int i = 0; i < items_total; i++) {
+ BLI_rng_shuffle_array(rng, chunks_array, sizeof(TestChunnk *), chunks_per_buffer);
+ size_t data_len;
+ char *data = testchunk_as_data_array(chunks_array, chunks_per_buffer, &data_len);
+ BLI_assert(data_len == chunks_per_buffer * chunk_count * stride);
+ testbuffer_list_add(&lb, (const void *)data, data_len);
+ }
+ BLI_rng_free(rng);
+ }
+
+ testchunk_list_free(&random_chunks);
+ MEM_freeN(chunks_array);
+
+ BArrayStore *bs = BLI_array_store_create(stride, chunk_count);
+ testbuffer_run_tests_single(bs, &lb);
+
+ size_t expected_size = chunks_per_buffer * chunk_count * stride;
+ EXPECT_EQ(expected_size, BLI_array_store_calc_size_compacted_get(bs));
+
+ BLI_array_store_destroy(bs);
+
+ testbuffer_list_free(&lb);
+
+}
+
+TEST(array_store, TestChunk_Rand8_Stride1_Chunk64) { random_chunk_mutate_helper(8, 100, 1, 64, 9779); }
+TEST(array_store, TestChunk_Rand32_Stride1_Chunk64) { random_chunk_mutate_helper(32, 100, 1, 64, 1331); }
+TEST(array_store, TestChunk_Rand64_Stride8_Chunk32) { random_chunk_mutate_helper(64, 100, 8, 32, 2772); }
+TEST(array_store, TestChunk_Rand31_Stride11_Chunk21) { random_chunk_mutate_helper(31, 100, 11, 21, 7117); }
+
+
+#if 0
+/* -------------------------------------------------------------------- */
+
+/* Test From Files (disabled, keep for local tests.) */
+
+void *file_read_binary_as_mem(const char *filepath, size_t pad_bytes, size_t *r_size)
+{
+ FILE *fp = fopen(filepath, "rb");
+ void *mem = NULL;
+
+ if (fp) {
+ long int filelen_read;
+ fseek(fp, 0L, SEEK_END);
+ const long int filelen = ftell(fp);
+ if (filelen == -1) {
+ goto finally;
+ }
+ fseek(fp, 0L, SEEK_SET);
+
+ mem = MEM_mallocN(filelen + pad_bytes, __func__);
+ if (mem == NULL) {
+ goto finally;
+ }
+
+ filelen_read = fread(mem, 1, filelen, fp);
+ if ((filelen_read != filelen) || ferror(fp)) {
+ MEM_freeN(mem);
+ mem = NULL;
+ goto finally;
+ }
+
+ *r_size = filelen_read;
+
+finally:
+ fclose(fp);
+ }
+
+ return mem;
+}
+
+
+TEST(array_store, PlainTextFiles)
+{ ListBase lb;
+ BLI_listbase_clear(&lb);
+ BArrayStore *bs = BLI_array_store_create(1, 128);
+
+ for (int i = 0; i < 629; i++) {
+ char str[512];
+ BLI_snprintf(str, sizeof(str), "/src/py_array_cow/test_data/xz_data/%04d.c.xz", i);
+ // BLI_snprintf(str, sizeof(str), "/src/py_array_cow/test_data/c_code/%04d.c", i);
+ // printf("%s\n", str);
+ size_t data_len;
+ void *data;
+ data = file_read_binary_as_mem(str, 0, &data_len);
+
+ testbuffer_list_add(&lb, (const void *)data, data_len);
+ }
+
+ /* forwards */
+ testbuffer_list_store_populate(bs, &lb);
+ EXPECT_EQ(true, testbuffer_list_validate(&lb));
+ EXPECT_EQ(true, BLI_array_store_is_valid(bs));
+#ifdef DEBUG_PRINT
+ print_mem_saved("source code forward", bs);
+#endif
+
+ testbuffer_list_store_clear(bs, &lb);
+ BLI_listbase_reverse(&lb);
+
+ /* backwards */
+ testbuffer_list_store_populate(bs, &lb);
+ EXPECT_EQ(true, testbuffer_list_validate(&lb));
+ EXPECT_EQ(true, BLI_array_store_is_valid(bs));
+#ifdef DEBUG_PRINT
+ print_mem_saved("source code backwards", bs);
+#endif
+
+
+ testbuffer_list_free(&lb);
+ BLI_array_store_destroy(bs);
+}
+#endif
diff --git a/tests/gtests/blenlib/BLI_ghash_performance_test.cc b/tests/gtests/blenlib/BLI_ghash_performance_test.cc
index 709302db021..fb32cb3f0a5 100644
--- a/tests/gtests/blenlib/BLI_ghash_performance_test.cc
+++ b/tests/gtests/blenlib/BLI_ghash_performance_test.cc
@@ -21,6 +21,12 @@ extern "C" {
/* Resizing the hash has a huge cost over global filling operation! */
//#define GHASH_RESERVE
+/* Run the longest tests! */
+//#define GHASH_RUN_BIG
+
+/* Size of 'small case' ghash (number of entries). */
+#define TESTCASE_SIZE_SMALL 17
+
#define PRINTF_GHASH_STATS(_gh) \
{ \
double q, lf, var, pempty, poverloaded; \
@@ -32,7 +38,6 @@ extern "C" {
BLI_ghash_size(_gh), q, var, lf, pempty * 100.0, poverloaded * 100.0, bigb); \
} void (0)
-
/* Str: whole text, lines and words from a 'corpus' text. */
static void str_ghash_tests(GHash *ghash, const char *id)
@@ -223,12 +228,14 @@ TEST(ghash, IntGHash12000)
int_ghash_tests(ghash, "IntGHash - GHash - 12000", 12000);
}
+#ifdef GHASH_RUN_BIG
TEST(ghash, IntGHash100000000)
{
GHash *ghash = BLI_ghash_new(BLI_ghashutil_inthash_p, BLI_ghashutil_intcmp, __func__);
int_ghash_tests(ghash, "IntGHash - GHash - 100000000", 100000000);
}
+#endif
TEST(ghash, IntMurmur2a12000)
{
@@ -237,13 +244,14 @@ TEST(ghash, IntMurmur2a12000)
int_ghash_tests(ghash, "IntGHash - Murmur - 12000", 12000);
}
+#ifdef GHASH_RUN_BIG
TEST(ghash, IntMurmur2a100000000)
{
GHash *ghash = BLI_ghash_new(BLI_ghashutil_inthash_p_murmur, BLI_ghashutil_intcmp, __func__);
int_ghash_tests(ghash, "IntGHash - Murmur - 100000000", 100000000);
}
-
+#endif
/* Int: random 50M integers. */
@@ -302,12 +310,14 @@ TEST(ghash, IntRandGHash12000)
randint_ghash_tests(ghash, "RandIntGHash - GHash - 12000", 12000);
}
+#ifdef GHASH_RUN_BIG
TEST(ghash, IntRandGHash50000000)
{
GHash *ghash = BLI_ghash_new(BLI_ghashutil_inthash_p, BLI_ghashutil_intcmp, __func__);
randint_ghash_tests(ghash, "RandIntGHash - GHash - 50000000", 50000000);
}
+#endif
TEST(ghash, IntRandMurmur2a12000)
{
@@ -316,12 +326,14 @@ TEST(ghash, IntRandMurmur2a12000)
randint_ghash_tests(ghash, "RandIntGHash - Murmur - 12000", 12000);
}
+#ifdef GHASH_RUN_BIG
TEST(ghash, IntRandMurmur2a50000000)
{
GHash *ghash = BLI_ghash_new(BLI_ghashutil_inthash_p_murmur, BLI_ghashutil_intcmp, __func__);
randint_ghash_tests(ghash, "RandIntGHash - Murmur - 50000000", 50000000);
}
+#endif
static unsigned int ghashutil_tests_nohash_p(const void *p)
{
@@ -340,13 +352,14 @@ TEST(ghash, Int4NoHash12000)
randint_ghash_tests(ghash, "RandIntGHash - No Hash - 12000", 12000);
}
+#ifdef GHASH_RUN_BIG
TEST(ghash, Int4NoHash50000000)
{
GHash *ghash = BLI_ghash_new(ghashutil_tests_nohash_p, ghashutil_tests_cmp_p, __func__);
randint_ghash_tests(ghash, "RandIntGHash - No Hash - 50000000", 50000000);
}
-
+#endif
/* Int_v4: 20M of randomly-generated integer vectors. */
@@ -409,12 +422,14 @@ TEST(ghash, Int4GHash2000)
int4_ghash_tests(ghash, "Int4GHash - GHash - 2000", 2000);
}
+#ifdef GHASH_RUN_BIG
TEST(ghash, Int4GHash20000000)
{
GHash *ghash = BLI_ghash_new(BLI_ghashutil_uinthash_v4_p, BLI_ghashutil_uinthash_v4_cmp, __func__);
int4_ghash_tests(ghash, "Int4GHash - GHash - 20000000", 20000000);
}
+#endif
TEST(ghash, Int4Murmur2a2000)
{
@@ -423,9 +438,99 @@ TEST(ghash, Int4Murmur2a2000)
int4_ghash_tests(ghash, "Int4GHash - Murmur - 2000", 2000);
}
+#ifdef GHASH_RUN_BIG
TEST(ghash, Int4Murmur2a20000000)
{
GHash *ghash = BLI_ghash_new(BLI_ghashutil_uinthash_v4_p_murmur, BLI_ghashutil_uinthash_v4_cmp, __func__);
int4_ghash_tests(ghash, "Int4GHash - Murmur - 20000000", 20000000);
}
+#endif
+
+/* MultiSmall: create and manipulate a lot of very small ghashes (90% < 10 items, 9% < 100 items, 1% < 1000 items). */
+
+static void multi_small_ghash_tests_one(GHash *ghash, RNG *rng, const unsigned int nbr)
+{
+ unsigned int *data = (unsigned int *)MEM_mallocN(sizeof(*data) * (size_t)nbr, __func__);
+ unsigned int *dt;
+ unsigned int i;
+
+ for (i = nbr, dt = data; i--; dt++) {
+ *dt = BLI_rng_get_uint(rng);
+ }
+
+#ifdef GHASH_RESERVE
+ BLI_ghash_reserve(ghash, nbr);
+#endif
+
+ for (i = nbr, dt = data; i--; dt++) {
+ BLI_ghash_insert(ghash, SET_UINT_IN_POINTER(*dt), SET_UINT_IN_POINTER(*dt));
+ }
+
+ for (i = nbr, dt = data; i--; dt++) {
+ void *v = BLI_ghash_lookup(ghash, SET_UINT_IN_POINTER(*dt));
+ EXPECT_EQ(*dt, GET_UINT_FROM_POINTER(v));
+ }
+
+ BLI_ghash_clear(ghash, NULL, NULL);
+}
+
+static void multi_small_ghash_tests(GHash *ghash, const char *id, const unsigned int nbr)
+{
+ printf("\n========== STARTING %s ==========\n", id);
+
+ RNG *rng = BLI_rng_new(0);
+
+ TIMEIT_START(multi_small_ghash);
+
+ unsigned int i = nbr;
+ while (i--) {
+ const int nbr = 1 + (BLI_rng_get_int(rng) % TESTCASE_SIZE_SMALL) * (!(i % 100) ? 100 : (!(i % 10) ? 10 : 1));
+ multi_small_ghash_tests_one(ghash, rng, nbr);
+ }
+
+ TIMEIT_END(multi_small_ghash);
+
+ TIMEIT_START(multi_small2_ghash);
+
+ unsigned int i = nbr;
+ while (i--) {
+ const int nbr = 1 + (BLI_rng_get_int(rng) % TESTCASE_SIZE_SMALL) / 2 * (!(i % 100) ? 100 : (!(i % 10) ? 10 : 1));
+ multi_small_ghash_tests_one(ghash, rng, nbr);
+ }
+
+ TIMEIT_END(multi_small2_ghash);
+
+ BLI_ghash_free(ghash, NULL, NULL);
+ BLI_rng_free(rng);
+
+ printf("========== ENDED %s ==========\n\n", id);
+}
+
+TEST(ghash, MultiRandIntGHash2000)
+{
+ GHash *ghash = BLI_ghash_new(BLI_ghashutil_inthash_p, BLI_ghashutil_intcmp, __func__);
+
+ multi_small_ghash_tests(ghash, "MultiSmall RandIntGHash - GHash - 2000", 2000);
+}
+
+TEST(ghash, MultiRandIntGHash200000)
+{
+ GHash *ghash = BLI_ghash_new(BLI_ghashutil_inthash_p, BLI_ghashutil_intcmp, __func__);
+
+ multi_small_ghash_tests(ghash, "MultiSmall RandIntGHash - GHash - 200000", 200000);
+}
+
+TEST(ghash, MultiRandIntMurmur2a2000)
+{
+ GHash *ghash = BLI_ghash_new(BLI_ghashutil_inthash_p_murmur, BLI_ghashutil_intcmp, __func__);
+
+ multi_small_ghash_tests(ghash, "MultiSmall RandIntGHash - Murmur2a - 2000", 2000);
+}
+
+TEST(ghash, MultiRandIntMurmur2a200000)
+{
+ GHash *ghash = BLI_ghash_new(BLI_ghashutil_inthash_p_murmur, BLI_ghashutil_intcmp, __func__);
+
+ multi_small_ghash_tests(ghash, "MultiSmall RandIntGHash - Murmur2a - 200000", 200000);
+}
diff --git a/tests/gtests/blenlib/CMakeLists.txt b/tests/gtests/blenlib/CMakeLists.txt
index 5e6bddcdeab..12112e7a481 100644
--- a/tests/gtests/blenlib/CMakeLists.txt
+++ b/tests/gtests/blenlib/CMakeLists.txt
@@ -35,6 +35,7 @@ set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${PLATFORM_LINKFLAGS}")
set(CMAKE_EXE_LINKER_FLAGS_DEBUG "${CMAKE_EXE_LINKER_FLAGS_DEBUG} ${PLATFORM_LINKFLAGS_DEBUG}")
+BLENDER_TEST(BLI_array_store "bf_blenlib")
BLENDER_TEST(BLI_array_utils "bf_blenlib")
BLENDER_TEST(BLI_stack "bf_blenlib")
BLENDER_TEST(BLI_math_color "bf_blenlib")