diff options
author | Lukas Stockner <lukas.stockner@freenet.de> | 2016-11-22 06:12:44 +0300 |
---|---|---|
committer | Lukas Stockner <lukas.stockner@freenet.de> | 2016-11-22 06:12:44 +0300 |
commit | 51e9b190c8f8c4bce54006c45461737e790bbb97 (patch) | |
tree | a9828e17070bc741de2c625c6575b5ceaf86b79c | |
parent | 358191c9d70b09c0acdb3a9823eca1257ad7d2e7 (diff) | |
parent | bd8cbf5c079b4cffb3652195ba8a9c92d8a60d15 (diff) |
Merge remote-tracking branch 'origin/master' into soc-2016-cycles_denoising
Conflicts:
intern/cycles/blender/blender_session.cpp
63 files changed, 1690 insertions, 1081 deletions
diff --git a/extern/clew/include/clew.h b/extern/clew/include/clew.h index 1f79c12481b..2a583c81599 100644 --- a/extern/clew/include/clew.h +++ b/extern/clew/include/clew.h @@ -369,7 +369,8 @@ typedef unsigned int cl_GLenum; #endif /* Define basic vector types */ -#if defined( __VEC__ ) +/* WOrkaround for ppc64el platform: conflicts with bool from C++. */ +#if defined( __VEC__ ) && !(defined(__PPC64__) && defined(__LITTLE_ENDIAN__)) #include <altivec.h> /* may be omitted depending on compiler. AltiVec spec provides no way to detect whether the header is required. */ typedef vector unsigned char __cl_uchar16; typedef vector signed char __cl_char16; diff --git a/extern/glog/src/stacktrace_powerpc-inl.h b/extern/glog/src/stacktrace_powerpc-inl.h index 1090ddedbc7..03b91089aad 100644 --- a/extern/glog/src/stacktrace_powerpc-inl.h +++ b/extern/glog/src/stacktrace_powerpc-inl.h @@ -111,7 +111,7 @@ int GetStackTrace(void** result, int max_depth, int skip_count) { result[n++] = *(sp+2); #elif defined(_CALL_SYSV) result[n++] = *(sp+1); -#elif defined(__APPLE__) || (defined(__linux) && defined(__PPC64__)) +#elif defined(__APPLE__) || ((defined(__linux) || defined(__linux__)) && defined(__PPC64__)) // This check is in case the compiler doesn't define _CALL_AIX/etc. result[n++] = *(sp+2); #elif defined(__linux) diff --git a/extern/rangetree/intern/range_tree.c b/extern/rangetree/intern/range_tree.c index 4c81036dceb..77496e32fa3 100644 --- a/extern/rangetree/intern/range_tree.c +++ b/extern/rangetree/intern/range_tree.c @@ -808,7 +808,7 @@ bool range_tree_uint_retake(RangeTreeUInt *rt, const uint value) uint range_tree_uint_take_any(RangeTreeUInt *rt) { - Node *node = node = rt->list.first; + Node *node = rt->list.first; uint value = node->min; if (value == node->max) { rt_node_remove(rt, node); diff --git a/intern/cycles/blender/addon/properties.py b/intern/cycles/blender/addon/properties.py index a7dff1f79f3..b53f85c3266 100644 --- a/intern/cycles/blender/addon/properties.py +++ b/intern/cycles/blender/addon/properties.py @@ -30,7 +30,7 @@ import _cycles enum_devices = ( ('CPU', "CPU", "Use CPU for rendering"), - ('GPU', "GPU Compute", "Use GPU compute device for rendering, configured in user preferences"), + ('GPU', "GPU Compute", "Use GPU compute device for rendering, configured in the system tab in the user preferences"), ) if _cycles.with_network: @@ -566,6 +566,19 @@ class CyclesRenderSettings(bpy.types.PropertyGroup): min=0.0, max=5.0 ) + cls.use_distance_cull = BoolProperty( + name="Use Distance Cull", + description="Allow objects to be culled based on the distance from camera", + default=False, + ) + + cls.distance_cull_margin = FloatProperty( + name="Cull Distance", + description="Cull objects which are further away from camera then this distance", + default=50, + min=0.0 + ) + cls.motion_blur_position = EnumProperty( name="Motion Blur Position", default='CENTER', @@ -1016,6 +1029,12 @@ class CyclesObjectSettings(bpy.types.PropertyGroup): default=False, ) + cls.use_distance_cull = BoolProperty( + name="Use Distance Cull", + description="Allow this object and its duplicators to be culled by distance from camera", + default=False, + ) + cls.use_adaptive_subdivision = BoolProperty( name="Use Adaptive Subdivision", description="Use adaptive render time subdivision", @@ -1169,7 +1188,7 @@ class CyclesPreferences(bpy.types.AddonPreferences): def get_devices(self): import _cycles - # Layout of the device tuples: (Name, Type, Internal ID, Persistent ID) + # Layout of the device tuples: (Name, Type, Persistent ID) device_list = _cycles.available_devices() cuda_devices = [] @@ -1217,21 +1236,19 @@ class CyclesPreferences(bpy.types.AddonPreferences): def draw_impl(self, layout, context): - layout.label(text="Compute Device:") + layout.label(text="Cycles Compute Device:") layout.row().prop(self, "compute_device_type", expand=True) cuda_devices, opencl_devices = self.get_devices() row = layout.row() - if cuda_devices: + if self.compute_device_type == 'CUDA' and cuda_devices: col = row.column(align=True) - col.label(text="CUDA devices:") for device in cuda_devices: col.prop(device, "use", text=device.name, toggle=True) - if opencl_devices: + if self.compute_device_type == 'OPENCL' and opencl_devices: col = row.column(align=True) - col.label(text="OpenCL devices:") for device in opencl_devices: col.prop(device, "use", text=device.name, toggle=True) diff --git a/intern/cycles/blender/addon/ui.py b/intern/cycles/blender/addon/ui.py index ea07ac27794..5e894f98a53 100644 --- a/intern/cycles/blender/addon/ui.py +++ b/intern/cycles/blender/addon/ui.py @@ -811,6 +811,8 @@ class CyclesObject_PT_cycles_settings(CyclesButtonsPanel, Panel): row = col.row() row.active = scene.render.use_simplify and cscene.use_camera_cull row.prop(cob, "use_camera_cull") + row.active = scene.render.use_simplify and cscene.use_distance_cull + row.prop(cob, "use_distance_cull") class CYCLES_OT_use_shading_nodes(Operator): @@ -1639,12 +1641,17 @@ class CyclesScene_PT_simplify(CyclesButtonsPanel, Panel): col.prop(rd, "simplify_subdivision_render", text="Subdivision") col.prop(rd, "simplify_child_particles_render", text="Child Particles") - col = layout.column() + layout.separator() + + split = layout.split() + + col = split.column() col.prop(cscene, "use_camera_cull") - subsub = col.column() - subsub.active = cscene.use_camera_cull - subsub.prop(cscene, "camera_cull_margin") + col.prop(cscene, "camera_cull_margin", text="Margin") + col = split.column() + col.prop(cscene, "use_distance_cull") + col.prop(cscene, "distance_cull_margin", text="Distance") def draw_device(self, context): scene = context.scene @@ -1658,11 +1665,9 @@ def draw_device(self, context): split = layout.split(percentage=1/3) split.label("Device:") - row = split.row(align=True) - sub = row.split(align=True) - sub.active = show_device_selection(context) - sub.prop(cscene, "device", text="") - row.operator("wm.addon_userpref_show", text="", icon='PREFERENCES').module = __package__ + row = split.row() + row.active = show_device_selection(context) + row.prop(cscene, "device", text="") if engine.with_osl() and use_cpu(context): layout.prop(cscene, "shading_system") diff --git a/intern/cycles/blender/addon/version_update.py b/intern/cycles/blender/addon/version_update.py index 951afd37a92..136080efadc 100644 --- a/intern/cycles/blender/addon/version_update.py +++ b/intern/cycles/blender/addon/version_update.py @@ -172,6 +172,18 @@ def custom_bake_remap(scene): @persistent def do_versions(self): + if bpy.context.user_preferences.version <= (2, 78, 1): + prop = bpy.context.user_preferences.addons[__package__].preferences + system = bpy.context.user_preferences.system + if not prop.is_property_set("compute_device_type"): + if system.legacy_compute_device_type == 1: + prop.compute_device_type = 'OPENCL' + elif system.legacy_compute_device_type == 2: + prop.compute_device_type = 'CUDA' + else: + prop.compute_device_type = 'NONE' + prop.get_devices() + # We don't modify startup file because it assumes to # have all the default values only. if not bpy.data.is_saved: diff --git a/intern/cycles/blender/blender_object.cpp b/intern/cycles/blender/blender_object.cpp index 0d961c5bf88..681a22e1f07 100644 --- a/intern/cycles/blender/blender_object.cpp +++ b/intern/cycles/blender/blender_object.cpp @@ -88,6 +88,143 @@ static uint object_ray_visibility(BL::Object& b_ob) return flag; } +/* Culling */ + +class BlenderObjectCulling +{ +public: + BlenderObjectCulling(Scene *scene, BL::Scene& b_scene) + : use_scene_camera_cull(false), + use_camera_cull(false), + camera_cull_margin(0.0f), + use_scene_distance_cull(false), + use_distance_cull(false), + distance_cull_margin(0.0f) + { + if(b_scene.render().use_simplify()) { + PointerRNA cscene = RNA_pointer_get(&b_scene.ptr, "cycles"); + + use_scene_camera_cull = scene->camera->type != CAMERA_PANORAMA && + !b_scene.render().use_multiview() && + get_boolean(cscene, "use_camera_cull"); + use_scene_distance_cull = scene->camera->type != CAMERA_PANORAMA && + !b_scene.render().use_multiview() && + get_boolean(cscene, "use_distance_cull"); + + camera_cull_margin = get_float(cscene, "camera_cull_margin"); + distance_cull_margin = get_float(cscene, "distance_cull_margin"); + + if (distance_cull_margin == 0.0f) { + use_scene_distance_cull = false; + } + } + } + + void init_object(Scene *scene, BL::Object& b_ob) + { + if(!use_scene_camera_cull && !use_scene_distance_cull) { + return; + } + + PointerRNA cobject = RNA_pointer_get(&b_ob.ptr, "cycles"); + + use_camera_cull = use_scene_camera_cull && get_boolean(cobject, "use_camera_cull"); + use_distance_cull = use_scene_distance_cull && get_boolean(cobject, "use_distance_cull"); + + if(use_camera_cull || use_distance_cull) { + /* Need to have proper projection matrix. */ + scene->camera->update(); + } + } + + bool test(Scene *scene, BL::Object& b_ob, Transform& tfm) + { + if(!use_camera_cull && !use_distance_cull) { + return false; + } + + /* Compute world space bounding box corners. */ + float3 bb[8]; + BL::Array<float, 24> boundbox = b_ob.bound_box(); + for(int i = 0; i < 8; ++i) { + float3 p = make_float3(boundbox[3 * i + 0], + boundbox[3 * i + 1], + boundbox[3 * i + 2]); + bb[i] = transform_point(&tfm, p); + } + + bool camera_culled = use_camera_cull && test_camera(scene, bb); + bool distance_culled = use_distance_cull && test_distance(scene, bb); + + return ((camera_culled && distance_culled) || + (camera_culled && !use_distance_cull) || + (distance_culled && !use_camera_cull)); + } + +private: + /* TODO(sergey): Not really optimal, consider approaches based on k-DOP in order + * to reduce number of objects which are wrongly considered visible. + */ + bool test_camera(Scene *scene, float3 bb[8]) + { + Camera *cam = scene->camera; + Transform& worldtondc = cam->worldtondc; + float3 bb_min = make_float3(FLT_MAX, FLT_MAX, FLT_MAX), + bb_max = make_float3(-FLT_MAX, -FLT_MAX, -FLT_MAX); + bool all_behind = true; + for(int i = 0; i < 8; ++i) { + float3 p = bb[i]; + float4 b = make_float4(p.x, p.y, p.z, 1.0f); + float4 c = make_float4(dot(worldtondc.x, b), + dot(worldtondc.y, b), + dot(worldtondc.z, b), + dot(worldtondc.w, b)); + p = float4_to_float3(c / c.w); + if(c.z < 0.0f) { + p.x = 1.0f - p.x; + p.y = 1.0f - p.y; + } + if(c.z >= -camera_cull_margin) { + all_behind = false; + } + bb_min = min(bb_min, p); + bb_max = max(bb_max, p); + } + if(all_behind) { + return true; + } + return (bb_min.x >= 1.0f + camera_cull_margin || + bb_min.y >= 1.0f + camera_cull_margin || + bb_max.x <= -camera_cull_margin || + bb_max.y <= -camera_cull_margin); + } + + bool test_distance(Scene *scene, float3 bb[8]) + { + float3 camera_position = transform_get_column(&scene->camera->matrix, 3); + float3 bb_min = make_float3(FLT_MAX, FLT_MAX, FLT_MAX), + bb_max = make_float3(-FLT_MAX, -FLT_MAX, -FLT_MAX); + + /* Find min & max points for x & y & z on bounding box */ + for(int i = 0; i < 8; ++i) { + float3 p = bb[i]; + bb_min = min(bb_min, p); + bb_max = max(bb_max, p); + } + + float3 closest_point = max(min(bb_max,camera_position),bb_min); + return (len_squared(camera_position - closest_point) > + distance_cull_margin * distance_cull_margin); + } + + bool use_scene_camera_cull; + bool use_camera_cull; + float camera_cull_margin; + bool use_scene_distance_cull; + bool use_distance_cull; + float distance_cull_margin; +}; + /* Light */ void BlenderSync::sync_light(BL::Object& b_parent, @@ -235,55 +372,6 @@ void BlenderSync::sync_background_light(bool use_portal) /* Object */ -/* TODO(sergey): Not really optimal, consider approaches based on k-DOP in order - * to reduce number of objects which are wrongly considered visible. - */ -static bool object_boundbox_clip(Scene *scene, - BL::Object& b_ob, - Transform& tfm, - float margin) -{ - Camera *cam = scene->camera; - Transform& worldtondc = cam->worldtondc; - BL::Array<float, 24> boundbox = b_ob.bound_box(); - float3 bb_min = make_float3(FLT_MAX, FLT_MAX, FLT_MAX), - bb_max = make_float3(-FLT_MAX, -FLT_MAX, -FLT_MAX); - bool all_behind = true; - for(int i = 0; i < 8; ++i) { - float3 p = make_float3(boundbox[3 * i + 0], - boundbox[3 * i + 1], - boundbox[3 * i + 2]); - p = transform_point(&tfm, p); - - float4 b = make_float4(p.x, p.y, p.z, 1.0f); - float4 c = make_float4(dot(worldtondc.x, b), - dot(worldtondc.y, b), - dot(worldtondc.z, b), - dot(worldtondc.w, b)); - p = float4_to_float3(c / c.w); - if(c.z < 0.0f) { - p.x = 1.0f - p.x; - p.y = 1.0f - p.y; - } - if(c.z >= -margin) { - all_behind = false; - } - bb_min = min(bb_min, p); - bb_max = max(bb_max, p); - } - if(!all_behind) { - if(bb_min.x >= 1.0f + margin || - bb_min.y >= 1.0f + margin || - bb_max.x <= -margin || - bb_max.y <= -margin) - { - return true; - } - return false; - } - return true; -} - Object *BlenderSync::sync_object(BL::Object& b_parent, int persistent_id[OBJECT_PERSISTENT_ID_SIZE], BL::DupliObject& b_dupli_ob, @@ -291,8 +379,7 @@ Object *BlenderSync::sync_object(BL::Object& b_parent, uint layer_flag, float motion_time, bool hide_tris, - bool use_camera_cull, - float camera_cull_margin, + BlenderObjectCulling& culling, bool *use_portal) { BL::Object b_ob = (b_dupli_ob ? b_dupli_ob.object() : b_parent); @@ -308,11 +395,12 @@ Object *BlenderSync::sync_object(BL::Object& b_parent, } /* only interested in object that we can create meshes from */ - if(!object_is_mesh(b_ob)) + if(!object_is_mesh(b_ob)) { return NULL; + } - /* Perform camera space culling. */ - if(use_camera_cull && object_boundbox_clip(scene, b_ob, tfm, camera_cull_margin)) { + /* Perform object culling. */ + if(culling.test(scene, b_ob, tfm)) { return NULL; } @@ -548,17 +636,8 @@ void BlenderSync::sync_objects(BL::SpaceView3D& b_v3d, float motion_time) mesh_motion_synced.clear(); } - bool allow_camera_cull = false; - float camera_cull_margin = 0.0f; - if(b_scene.render().use_simplify()) { - PointerRNA cscene = RNA_pointer_get(&b_scene.ptr, "cycles"); - allow_camera_cull = scene->camera->type != CAMERA_PANORAMA && - !b_scene.render().use_multiview() && - get_boolean(cscene, "use_camera_cull"); - if(allow_camera_cull) { - camera_cull_margin = get_float(cscene, "camera_cull_margin"); - } - } + /* initialize culling */ + BlenderObjectCulling culling(scene, b_scene); /* object loop */ BL::Scene::object_bases_iterator b_base; @@ -590,12 +669,9 @@ void BlenderSync::sync_objects(BL::SpaceView3D& b_v3d, float motion_time) if(!hide) { progress.set_sync_status("Synchronizing object", b_ob.name()); - PointerRNA cobject = RNA_pointer_get(&b_ob.ptr, "cycles"); - bool use_camera_cull = allow_camera_cull && get_boolean(cobject, "use_camera_cull"); - if(use_camera_cull) { - /* Need to have proper projection matrix. */ - scene->camera->update(); - } + /* load per-object culling data */ + culling.init_object(scene, b_ob); + if(b_ob.is_duplicator() && !object_render_hide_duplis(b_ob)) { /* dupli objects */ b_ob.dupli_list_create(b_scene, dupli_settings); @@ -622,8 +698,7 @@ void BlenderSync::sync_objects(BL::SpaceView3D& b_v3d, float motion_time) ob_layer, motion_time, hide_tris, - use_camera_cull, - camera_cull_margin, + culling, &use_portal); /* sync possible particle data, note particle_id @@ -652,8 +727,7 @@ void BlenderSync::sync_objects(BL::SpaceView3D& b_v3d, float motion_time) ob_layer, motion_time, hide_tris, - use_camera_cull, - camera_cull_margin, + culling, &use_portal); } } diff --git a/intern/cycles/blender/blender_session.cpp b/intern/cycles/blender/blender_session.cpp index 4dadc633ef0..fa33a9d26e3 100644 --- a/intern/cycles/blender/blender_session.cpp +++ b/intern/cycles/blender/blender_session.cpp @@ -32,6 +32,7 @@ #include "util_color.h" #include "util_foreach.h" #include "util_function.h" +#include "util_hash.h" #include "util_logging.h" #include "util_progress.h" #include "util_time.h" @@ -497,7 +498,8 @@ void BlenderSession::render() } } - for(b_rr.views.begin(b_view_iter); b_view_iter != b_rr.views.end(); ++b_view_iter) { + int view_index = 0; + for(b_rr.views.begin(b_view_iter); b_view_iter != b_rr.views.end(); ++b_view_iter, ++view_index) { b_rview_name = b_view_iter->name(); /* set the current view */ @@ -513,6 +515,12 @@ void BlenderSession::render() &python_thread_state, b_rlay_name.c_str()); + /* Make sure all views have different noise patterns. - hardcoded value just to make it random */ + if(view_index != 0) { + scene->integrator->seed += hash_int_2d(scene->integrator->seed, hash_int(view_index * 0xdeadbeef)); + scene->integrator->tag_update(scene); + } + /* Update number of samples per layer. */ int samples = sync->get_layer_samples(); bool bound_samples = sync->get_layer_bound_samples(); diff --git a/intern/cycles/blender/blender_sync.h b/intern/cycles/blender/blender_sync.h index 5fe12bc97f7..cc1674e68f5 100644 --- a/intern/cycles/blender/blender_sync.h +++ b/intern/cycles/blender/blender_sync.h @@ -36,6 +36,7 @@ CCL_NAMESPACE_BEGIN class Background; +class BlenderObjectCulling; class Camera; class Film; class Light; @@ -129,8 +130,7 @@ private: uint layer_flag, float motion_time, bool hide_tris, - bool use_camera_cull, - float camera_cull_margin, + BlenderObjectCulling& culling, bool *use_portal); void sync_light(BL::Object& b_parent, int persistent_id[OBJECT_PERSISTENT_ID_SIZE], diff --git a/intern/cycles/device/opencl/opencl.h b/intern/cycles/device/opencl/opencl.h index 054ac9014f0..4023ba89a10 100644 --- a/intern/cycles/device/opencl/opencl.h +++ b/intern/cycles/device/opencl/opencl.h @@ -16,14 +16,14 @@ #ifdef WITH_OPENCL -#include "clew.h" - #include "device.h" #include "util_map.h" #include "util_param.h" #include "util_string.h" +#include "clew.h" + CCL_NAMESPACE_BEGIN #define CL_MEM_PTR(p) ((cl_mem)(uintptr_t)(p)) diff --git a/intern/cycles/render/mesh.cpp b/intern/cycles/render/mesh.cpp index 72a2c1bfbe8..41de633426b 100644 --- a/intern/cycles/render/mesh.cpp +++ b/intern/cycles/render/mesh.cpp @@ -1084,7 +1084,7 @@ void MeshManager::update_svm_attributes(Device *device, DeviceScene *dscene, Sce } /* terminator */ - for(int i = 0; i < ATTR_PRIM_TYPES; i++) { + for(int j = 0; j < ATTR_PRIM_TYPES; j++) { attr_map[index].x = ATTR_STD_NONE; attr_map[index].y = 0; attr_map[index].z = 0; diff --git a/intern/ghost/intern/GHOST_WindowX11.cpp b/intern/ghost/intern/GHOST_WindowX11.cpp index ec2b65e67d0..47fbe1256b1 100644 --- a/intern/ghost/intern/GHOST_WindowX11.cpp +++ b/intern/ghost/intern/GHOST_WindowX11.cpp @@ -861,24 +861,32 @@ void GHOST_WindowX11::icccmSetState(int state) int GHOST_WindowX11::icccmGetState(void) const { - Atom *prop_ret; + struct { + CARD32 state; + XID icon; + } *prop_ret; unsigned long bytes_after, num_ret; Atom type_ret; - int format_ret, st; + int ret, format_ret; + CARD32 st; prop_ret = NULL; - st = XGetWindowProperty( + ret = XGetWindowProperty( m_display, m_window, m_system->m_atom.WM_STATE, 0, 2, False, m_system->m_atom.WM_STATE, &type_ret, &format_ret, &num_ret, &bytes_after, ((unsigned char **)&prop_ret)); - if ((st == Success) && (prop_ret) && (num_ret == 2)) - st = prop_ret[0]; - else + if ((ret == Success) && (prop_ret != NULL) && (num_ret == 2)) { + st = prop_ret->state; + } + else { st = NormalState; + } - if (prop_ret) + if (prop_ret) { XFree(prop_ret); - return (st); + } + + return st; } void GHOST_WindowX11::netwmMaximized(bool set) diff --git a/release/scripts/modules/bpy/utils/__init__.py b/release/scripts/modules/bpy/utils/__init__.py index 66974dedc24..31dd836e034 100644 --- a/release/scripts/modules/bpy/utils/__init__.py +++ b/release/scripts/modules/bpy/utils/__init__.py @@ -154,8 +154,6 @@ def load_scripts(reload_scripts=False, refresh_scripts=False): original_modules = _sys.modules.values() if reload_scripts: - _bpy_types.TypeMap.clear() - # just unload, don't change user defaults, this means we can sync # to reload. note that they will only actually reload of the # modification time changes. This `won't` work for packages so... @@ -163,6 +161,9 @@ def load_scripts(reload_scripts=False, refresh_scripts=False): for module_name in [ext.module for ext in _user_preferences.addons]: _addon_utils.disable(module_name) + # *AFTER* unregistering all add-ons, otherwise all calls to unregister_module() will silently fail (do nothing). + _bpy_types.TypeMap.clear() + def register_module_call(mod): register = getattr(mod, "register", None) if register: diff --git a/release/scripts/modules/bpy_extras/object_utils.py b/release/scripts/modules/bpy_extras/object_utils.py index 88cd7398fe0..c48f03c133d 100644 --- a/release/scripts/modules/bpy_extras/object_utils.py +++ b/release/scripts/modules/bpy_extras/object_utils.py @@ -189,6 +189,14 @@ def object_data_add(context, obdata, operator=None, use_active_layer=True, name= scene.update() # apply location # scene.objects.active = obj_new + # Match up UV layers, this is needed so adding an object with UV's + # doesn't create new layers when there happens to be a naming mis-match. + uv_new = obdata.uv_layers.active + if uv_new is not None: + uv_act = obj_act.data.uv_layers.active + if uv_act is not None: + uv_new.name = uv_act.name + bpy.ops.object.join() # join into the active. if obdata: bpy.data.meshes.remove(obdata) diff --git a/release/scripts/startup/bl_operators/add_mesh_torus.py b/release/scripts/startup/bl_operators/add_mesh_torus.py index 303a8b01192..f12e7484e64 100644 --- a/release/scripts/startup/bl_operators/add_mesh_torus.py +++ b/release/scripts/startup/bl_operators/add_mesh_torus.py @@ -84,26 +84,27 @@ def add_torus(major_rad, minor_rad, major_seg, minor_seg): def add_uvs(mesh, minor_seg, major_seg): mesh.uv_textures.new() - uv_layer = mesh.uv_layers.active - u_step = 1.0/major_seg - v_step = 1.0/minor_seg + uv_data = mesh.uv_layers.active.data + polygons = mesh.polygons + u_step = 1.0 / major_seg + v_step = 1.0 / minor_seg vertex_index = 0 u = 0.5 for major_index in range(major_seg): v = 0.5 for minor_index in range(minor_seg): - loops = mesh.polygons[vertex_index].loop_indices - if minor_index == minor_seg-1 and major_index == 0: - uv_layer.data[loops[1]].uv = (u, v) - uv_layer.data[loops[2]].uv = (u + u_step, v) - uv_layer.data[loops[0]].uv = (u, v + v_step) - uv_layer.data[loops[3]].uv = (u + u_step, v + v_step) + loops = polygons[vertex_index].loop_indices + if minor_index == minor_seg - 1 and major_index == 0: + uv_data[loops[1]].uv = (u, v) + uv_data[loops[2]].uv = (u + u_step, v) + uv_data[loops[0]].uv = (u, v + v_step) + uv_data[loops[3]].uv = (u + u_step, v + v_step) else: - uv_layer.data[loops[0]].uv = (u, v) - uv_layer.data[loops[1]].uv = (u + u_step, v) - uv_layer.data[loops[3]].uv = (u, v + v_step) - uv_layer.data[loops[2]].uv = (u + u_step, v + v_step) + uv_data[loops[0]].uv = (u, v) + uv_data[loops[1]].uv = (u + u_step, v) + uv_data[loops[3]].uv = (u, v + v_step) + uv_data[loops[2]].uv = (u + u_step, v + v_step) v = (v + v_step) % 1.0 vertex_index += 1 u = (u + u_step) % 1.0 diff --git a/release/scripts/startup/bl_ui/properties_paint_common.py b/release/scripts/startup/bl_ui/properties_paint_common.py index cca142b645c..09a3a19cbce 100644 --- a/release/scripts/startup/bl_ui/properties_paint_common.py +++ b/release/scripts/startup/bl_ui/properties_paint_common.py @@ -119,16 +119,14 @@ def brush_texpaint_common(panel, context, layout, brush, settings, projpaint=Fal col.label("Gradient Colors") col.template_color_ramp(brush, "gradient", expand=True) - if brush.image_tool != 'FILL': + if brush.image_tool == 'DRAW': col.label("Background Color") row = col.row(align=True) panel.prop_unified_color(row, context, brush, "secondary_color", text="") - - if brush.image_tool == 'DRAW': col.prop(brush, "gradient_stroke_mode", text="Mode") if brush.gradient_stroke_mode in {'SPACING_REPEAT', 'SPACING_CLAMP'}: col.prop(brush, "grad_spacing") - elif brush.image_tool == 'FILL': + else: # if brush.image_tool == 'FILL': col.prop(brush, "gradient_fill_mode") else: row = col.row(align=True) @@ -139,6 +137,9 @@ def brush_texpaint_common(panel, context, layout, brush, settings, projpaint=Fal panel.prop_unified_color(row, context, brush, "secondary_color", text="") row.separator() row.operator("paint.brush_colors_flip", icon='FILE_REFRESH', text="") + else: + if brush.image_tool == 'FILL' and not projpaint: + col.prop(brush, "fill_threshold") elif brush.image_tool == 'SOFTEN': col = layout.column(align=True) diff --git a/release/scripts/startup/bl_ui/space_userpref.py b/release/scripts/startup/bl_ui/space_userpref.py index ab3ec3559e5..bdbb6330232 100644 --- a/release/scripts/startup/bl_ui/space_userpref.py +++ b/release/scripts/startup/bl_ui/space_userpref.py @@ -429,6 +429,9 @@ class USERPREF_PT_system(Panel): col.separator() + if userpref.addons.find('cycles') != -1: + userpref.addons['cycles'].preferences.draw_impl(col, context) + if hasattr(system, "opensubdiv_compute_type"): col.label(text="OpenSubdiv compute:") col.row().prop(system, "opensubdiv_compute_type", text="") diff --git a/source/blender/blenkernel/BKE_blender_version.h b/source/blender/blenkernel/BKE_blender_version.h index baf8510dd0d..4f4787f9da5 100644 --- a/source/blender/blenkernel/BKE_blender_version.h +++ b/source/blender/blenkernel/BKE_blender_version.h @@ -28,7 +28,7 @@ * and keep comment above the defines. * Use STRINGIFY() rather than defining with quotes */ #define BLENDER_VERSION 278 -#define BLENDER_SUBVERSION 3 +#define BLENDER_SUBVERSION 4 /* Several breakages with 270, e.g. constraint deg vs rad */ #define BLENDER_MINVERSION 270 #define BLENDER_MINSUBVERSION 6 diff --git a/source/blender/blenkernel/BKE_constraint.h b/source/blender/blenkernel/BKE_constraint.h index f3cfb901154..047d1787f76 100644 --- a/source/blender/blenkernel/BKE_constraint.h +++ b/source/blender/blenkernel/BKE_constraint.h @@ -120,7 +120,6 @@ void BKE_constraint_unique_name(struct bConstraint *con, struct ListBase *list); void BKE_constraints_free(struct ListBase *list); void BKE_constraints_free_ex(struct ListBase *list, bool do_id_user); void BKE_constraints_copy(struct ListBase *dst, const struct ListBase *src, bool do_extern); -void BKE_constraints_relink(struct ListBase *list); void BKE_constraints_id_loop(struct ListBase *list, ConstraintIDFunc func, void *userdata); void BKE_constraint_free_data(struct bConstraint *con); void BKE_constraint_free_data_ex(struct bConstraint *con, bool do_id_user); diff --git a/source/blender/blenkernel/intern/blender_undo.c b/source/blender/blenkernel/intern/blender_undo.c index ce6d29bbfee..bc98d6f6805 100644 --- a/source/blender/blenkernel/intern/blender_undo.c +++ b/source/blender/blenkernel/intern/blender_undo.c @@ -320,7 +320,7 @@ const char *BKE_undo_get_name(int nr, bool *r_active) } /* return the name of the last item */ -const char *BKE_undo_get_name_last() +const char *BKE_undo_get_name_last(void) { UndoElem *uel = undobase.last; return (uel ? uel->name : NULL); diff --git a/source/blender/blenkernel/intern/constraint.c b/source/blender/blenkernel/intern/constraint.c index b85f1b838ff..9d4de30aa2c 100644 --- a/source/blender/blenkernel/intern/constraint.c +++ b/source/blender/blenkernel/intern/constraint.c @@ -4705,27 +4705,6 @@ bConstraint *BKE_constraint_add_for_object(Object *ob, const char *name, short t /* ......... */ -/* helper for BKE_constraints_relink() - call ID_NEW() on every ID reference the constraint has */ -static void con_relink_id_cb(bConstraint *UNUSED(con), ID **idpoin, bool UNUSED(is_reference), void *UNUSED(userdata)) -{ - /* ID_NEW() expects a struct with inline "id" member as first - * since we've got the actual ID block, let's just inline this - * code. - * - * See ID_NEW(a) in DNA_ID.h - */ - if ((*idpoin) && (*idpoin)->newid) - (*idpoin) = (void *)(*idpoin)->newid; -} - -/* Reassign links that constraints have to other data (called during file loading?) */ -void BKE_constraints_relink(ListBase *conlist) -{ - /* just a wrapper around ID-loop for just calling ID_NEW() on all ID refs */ - BKE_constraints_id_loop(conlist, con_relink_id_cb, NULL); -} - - /* Run the given callback on all ID-blocks in list of constraints */ void BKE_constraints_id_loop(ListBase *conlist, ConstraintIDFunc func, void *userdata) { diff --git a/source/blender/blenkernel/intern/image.c b/source/blender/blenkernel/intern/image.c index df3a7630bb0..c9bad2160ff 100644 --- a/source/blender/blenkernel/intern/image.c +++ b/source/blender/blenkernel/intern/image.c @@ -1244,7 +1244,6 @@ char BKE_imtype_valid_channels(const char imtype, bool write_file) case R_IMF_IMTYPE_RAWTGA: case R_IMF_IMTYPE_IRIS: case R_IMF_IMTYPE_PNG: - case R_IMF_IMTYPE_RADHDR: case R_IMF_IMTYPE_TIFF: case R_IMF_IMTYPE_OPENEXR: case R_IMF_IMTYPE_MULTILAYER: diff --git a/source/blender/blenkernel/intern/library_remap.c b/source/blender/blenkernel/intern/library_remap.c index 40441034171..62f59832481 100644 --- a/source/blender/blenkernel/intern/library_remap.c +++ b/source/blender/blenkernel/intern/library_remap.c @@ -378,6 +378,18 @@ static void libblock_remap_data_postprocess_obdata_relink(Main *UNUSED(bmain), O } } +static void libblock_remap_data_postprocess_nodetree_update(Main *bmain, ID *new_id) +{ + /* Verify all nodetree user nodes. */ + ntreeVerifyNodes(bmain, new_id); + + /* Update node trees as necessary. */ + FOREACH_NODETREE(bmain, ntree, id) { + /* make an update call for the tree */ + ntreeUpdateTree(bmain, ntree); + } FOREACH_NODETREE_END +} + /** * Execute the 'data' part of the remapping (that is, all ID pointers from other ID datablocks). * @@ -551,6 +563,8 @@ void BKE_libblock_remap_locked( default: break; } + /* Node trees may virtually use any kind of data-block... */ + libblock_remap_data_postprocess_nodetree_update(bmain, new_id); /* Full rebuild of DAG! */ DAG_relations_tag_update(bmain); diff --git a/source/blender/blenkernel/intern/node.c b/source/blender/blenkernel/intern/node.c index 2b88ae4823c..a227228ceb5 100644 --- a/source/blender/blenkernel/intern/node.c +++ b/source/blender/blenkernel/intern/node.c @@ -736,11 +736,14 @@ void nodeRemoveAllSockets(bNodeTree *ntree, bNode *node) node_socket_free(ntree, sock, node); MEM_freeN(sock); } + BLI_listbase_clear(&node->inputs); + for (sock = node->outputs.first; sock; sock = sock_next) { sock_next = sock->next; node_socket_free(ntree, sock, node); MEM_freeN(sock); } + BLI_listbase_clear(&node->outputs); node->update |= NODE_UPDATE; } diff --git a/source/blender/blenkernel/intern/object.c b/source/blender/blenkernel/intern/object.c index 5bcf31ba45b..4489ca907f6 100644 --- a/source/blender/blenkernel/intern/object.c +++ b/source/blender/blenkernel/intern/object.c @@ -1347,7 +1347,10 @@ void BKE_object_make_proxy(Object *ob, Object *target, Object *gob) ob->type = target->type; ob->data = target->data; id_us_plus((ID *)ob->data); /* ensures lib data becomes LIB_TAG_EXTERN */ - + + /* copy vertex groups */ + defgroup_copy_list(&ob->defbase, &target->defbase); + /* copy material and index information */ ob->actcol = ob->totcol = 0; if (ob->mat) MEM_freeN(ob->mat); diff --git a/source/blender/blenloader/intern/versioning_270.c b/source/blender/blenloader/intern/versioning_270.c index 4aad3c86d46..2c60de0f732 100644 --- a/source/blender/blenloader/intern/versioning_270.c +++ b/source/blender/blenloader/intern/versioning_270.c @@ -1483,4 +1483,11 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main) } } } + + if (!MAIN_VERSION_ATLEAST(main, 278, 4)) { + const float sqrt_3 = (float)M_SQRT3; + for (Brush *br = main->brush.first; br; br = br->id.next) { + br->fill_threshold /= sqrt_3; + } + } } diff --git a/source/blender/blenloader/intern/writefile.c b/source/blender/blenloader/intern/writefile.c index d104fc85eb7..ad1999c0bc7 100644 --- a/source/blender/blenloader/intern/writefile.c +++ b/source/blender/blenloader/intern/writefile.c @@ -914,20 +914,22 @@ static void write_curvemapping(WriteData *wd, CurveMapping *cumap) static void write_node_socket(WriteData *wd, bNodeTree *UNUSED(ntree), bNode *node, bNodeSocket *sock) { #ifdef USE_NODE_COMPAT_CUSTOMNODES - /* forward compatibility code, so older blenders still open */ - sock->stack_type = 1; - - if (node->type == NODE_GROUP) { - bNodeTree *ngroup = (bNodeTree *)node->id; - if (ngroup) { - /* for node groups: look up the deprecated groupsock pointer */ - sock->groupsock = ntreeFindSocketInterface(ngroup, sock->in_out, sock->identifier); - BLI_assert(sock->groupsock != NULL); - - /* node group sockets now use the generic identifier string to verify group nodes, - * old blender uses the own_index. - */ - sock->own_index = sock->groupsock->own_index; + /* forward compatibility code, so older blenders still open (not for undo) */ + if (wd->current == NULL) { + sock->stack_type = 1; + + if (node->type == NODE_GROUP) { + bNodeTree *ngroup = (bNodeTree *)node->id; + if (ngroup) { + /* for node groups: look up the deprecated groupsock pointer */ + sock->groupsock = ntreeFindSocketInterface(ngroup, sock->in_out, sock->identifier); + BLI_assert(sock->groupsock != NULL); + + /* node group sockets now use the generic identifier string to verify group nodes, + * old blender uses the own_index. + */ + sock->own_index = sock->groupsock->own_index; + } } } #endif diff --git a/source/blender/bmesh/intern/bmesh_core.c b/source/blender/bmesh/intern/bmesh_core.c index 0cd91107171..d1178a198dc 100644 --- a/source/blender/bmesh/intern/bmesh_core.c +++ b/source/blender/bmesh/intern/bmesh_core.c @@ -2682,8 +2682,10 @@ BMVert *bmesh_urmv_loop(BMesh *bm, BMLoop *l_sep) /** * A version of #bmesh_urmv_loop that disconnects multiple loops at once. + * The loops must all share the same vertex, can be in any order + * and are all moved to use a single new vertex - which is returned. * - * Handles the task of finding fans boundaries. + * This function handles the details of finding fans boundaries. */ BMVert *bmesh_urmv_loop_multi( BMesh *bm, BMLoop **larr, int larr_len) diff --git a/source/blender/bmesh/intern/bmesh_mesh_validate.c b/source/blender/bmesh/intern/bmesh_mesh_validate.c index 478194735f3..7c9ebc800a3 100644 --- a/source/blender/bmesh/intern/bmesh_mesh_validate.c +++ b/source/blender/bmesh/intern/bmesh_mesh_validate.c @@ -64,7 +64,7 @@ bool BM_mesh_validate(BMesh *bm) int i, j; - errtot = -1; + errtot = -1; /* 'ERRMSG' next line will set at zero */ fprintf(stderr, "\n"); ERRMSG("This is a debugging function and not intended for general use, running slow test!"); @@ -187,15 +187,22 @@ bool BM_mesh_validate(BMesh *bm) } while ((l_iter = l_iter->next) != l_first); if (j != f->len) { - ERRMSG("face %d: has length if %d but should be %d", i, f->len, j); + ERRMSG("face %d: has length of %d but should be %d", i, f->len, j); } + + /* leave elements un-tagged, not essential but nice to avoid unintended dirty tag use later. */ + do { + BM_elem_flag_disable(l_iter, BM_ELEM_INTERNAL_TAG); + BM_elem_flag_disable(l_iter->v, BM_ELEM_INTERNAL_TAG); + BM_elem_flag_disable(l_iter->e, BM_ELEM_INTERNAL_TAG); + } while ((l_iter = l_iter->next) != l_first); } BLI_edgehash_free(edge_hash, NULL); + const bool is_valid = (errtot == 0); ERRMSG("Finished - errors %d", errtot); - - return (errtot == 0); + return is_valid; } diff --git a/source/blender/bmesh/intern/bmesh_mods.c b/source/blender/bmesh/intern/bmesh_mods.c index 03165beb329..500da6b8788 100644 --- a/source/blender/bmesh/intern/bmesh_mods.c +++ b/source/blender/bmesh/intern/bmesh_mods.c @@ -346,7 +346,7 @@ BMFace *BM_face_split_n( BMLoop **r_l, BMEdge *example) { BMFace *f_new, *f_tmp; - BMLoop *l_dummy; + BMLoop *l_new; BMEdge *e, *e_new; BMVert *v_new; // BMVert *v_a = l_a->v; /* UNUSED */ @@ -368,24 +368,21 @@ BMFace *BM_face_split_n( } f_tmp = BM_face_copy(bm, bm, f, true, true); - - if (!r_l) - r_l = &l_dummy; #ifdef USE_BMESH_HOLES - f_new = bmesh_sfme(bm, f, l_a, l_b, r_l, NULL, example, false); + f_new = bmesh_sfme(bm, f, l_a, l_b, &l_new, NULL, example, false); #else - f_new = bmesh_sfme(bm, f, l_a, l_b, r_l, example, false); + f_new = bmesh_sfme(bm, f, l_a, l_b, &l_new, example, false); #endif - /* bmesh_sfme returns in r_l a Loop for f_new going from v_a to v_b. - * The radial_next is for f and goes from v_b to v_a */ + /* bmesh_sfme returns in 'l_new' a Loop for f_new going from 'v_a' to 'v_b'. + * The radial_next is for 'f' and goes from 'v_b' to 'v_a' */ if (f_new) { - e = (*r_l)->e; + e = l_new->e; for (i = 0; i < n; i++) { v_new = bmesh_semv(bm, v_b, e, &e_new); BLI_assert(v_new != NULL); - /* bmesh_semv returns in e_new the edge going from v_new to tv */ + /* bmesh_semv returns in 'e_new' the edge going from 'v_new' to 'v_b' */ copy_v3_v3(v_new->co, cos[i]); /* interpolate the loop data for the loops with (v == v_new), using orig face */ @@ -405,6 +402,10 @@ BMFace *BM_face_split_n( BM_face_verts_kill(bm, f_tmp); + if (r_l) { + *r_l = l_new; + } + return f_new; } diff --git a/source/blender/bmesh/intern/bmesh_polygon.c b/source/blender/bmesh/intern/bmesh_polygon.c index c500d7b9ec2..6acd790fc0c 100644 --- a/source/blender/bmesh/intern/bmesh_polygon.c +++ b/source/blender/bmesh/intern/bmesh_polygon.c @@ -225,24 +225,16 @@ void BM_face_calc_point_in_face(const BMFace *f, float r_co[3]) */ float BM_face_calc_area(const BMFace *f) { + /* inline 'area_poly_v3' logic, avoid creating a temp array */ const BMLoop *l_iter, *l_first; - float (*verts)[3] = BLI_array_alloca(verts, f->len); - float area; - unsigned int i = 0; + float n[3]; + zero_v3(n); l_iter = l_first = BM_FACE_FIRST_LOOP(f); do { - copy_v3_v3(verts[i++], l_iter->v->co); + add_newell_cross_v3_v3v3(n, l_iter->v->co, l_iter->next->v->co); } while ((l_iter = l_iter->next) != l_first); - - if (f->len == 3) { - area = area_tri_v3(verts[0], verts[1], verts[2]); - } - else { - area = area_poly_v3((const float (*)[3])verts, f->len); - } - - return area; + return len_v3(n) * 0.5f; } /** diff --git a/source/blender/bmesh/intern/bmesh_queries.h b/source/blender/bmesh/intern/bmesh_queries.h index a6a37767ee9..903fdc59cb8 100644 --- a/source/blender/bmesh/intern/bmesh_queries.h +++ b/source/blender/bmesh/intern/bmesh_queries.h @@ -135,7 +135,7 @@ BMLoop *BM_face_find_longest_loop(BMFace *f) ATTR_WARN_UNUSED_RESULT ATTR_NONNUL BMEdge *BM_edge_exists(BMVert *v1, BMVert *v2) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); BMEdge *BM_edge_find_double(BMEdge *e) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); -BMFace* BM_face_exists(BMVert **varr, int len) ATTR_NONNULL(1); +BMFace *BM_face_exists(BMVert **varr, int len) ATTR_NONNULL(1); bool BM_face_exists_multi(BMVert **varr, BMEdge **earr, int len) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); bool BM_face_exists_multi_edge(BMEdge **earr, int len) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); diff --git a/source/blender/bmesh/operators/bmo_primitive.c b/source/blender/bmesh/operators/bmo_primitive.c index 7b32921f8cf..8408169d85e 100644 --- a/source/blender/bmesh/operators/bmo_primitive.c +++ b/source/blender/bmesh/operators/bmo_primitive.c @@ -1174,7 +1174,7 @@ void BM_mesh_calc_uvs_sphere(BMesh *bm, const short oflag) } BMIter iter2; - BMLoop* l; + BMLoop *l; int loop_index; float minx = 1.0f; @@ -1236,14 +1236,14 @@ void bmo_create_monkey_exec(BMesh *bm, BMOperator *op) int uvi = 0; const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV); for (i = 0; i < monkeynf; i++) { - BMFace* temp1 = BM_face_create_quad_tri(bm, + BMFace *f_new_a = BM_face_create_quad_tri(bm, tv[monkeyf[i][0] + i - monkeyo], tv[monkeyf[i][1] + i - monkeyo], tv[monkeyf[i][2] + i - monkeyo], (monkeyf[i][3] != monkeyf[i][2]) ? tv[monkeyf[i][3] + i - monkeyo] : NULL, NULL, BM_CREATE_NOP); - BMFace* temp2 = BM_face_create_quad_tri(bm, + BMFace *f_new_b = BM_face_create_quad_tri(bm, tv[monkeynv + monkeyf[i][2] + i - monkeyo], tv[monkeynv + monkeyf[i][1] + i - monkeyo], tv[monkeynv + monkeyf[i][0] + i - monkeyo], @@ -1252,20 +1252,19 @@ void bmo_create_monkey_exec(BMesh *bm, BMOperator *op) /* Set the UVs here, the iteration order of the faces is not guaranteed, * so it's best to set the UVs right after the face is created. */ - if(calc_uvs) { - BMLoop* l; + if (calc_uvs) { + BMLoop *l; BMIter liter; - int loop_index; - BM_ITER_ELEM_INDEX (l, &liter, temp1, BM_LOOPS_OF_FACE, loop_index) { + BM_ITER_ELEM (l, &liter, f_new_a, BM_LOOPS_OF_FACE) { MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); - luv->uv[0] = monkeyuvs[uvi*2 + 0]; - luv->uv[1] = monkeyuvs[uvi*2 + 1]; + luv->uv[0] = monkeyuvs[uvi * 2 + 0]; + luv->uv[1] = monkeyuvs[uvi * 2 + 1]; uvi++; } - BM_ITER_ELEM_INDEX (l, &liter, temp2, BM_LOOPS_OF_FACE, loop_index) { + BM_ITER_ELEM (l, &liter, f_new_b, BM_LOOPS_OF_FACE) { MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); - luv->uv[0] = monkeyuvs[uvi*2 + 0]; - luv->uv[1] = monkeyuvs[uvi*2 + 1]; + luv->uv[0] = monkeyuvs[uvi * 2 + 0]; + luv->uv[1] = monkeyuvs[uvi * 2 + 1]; uvi++; } diff --git a/source/blender/depsgraph/CMakeLists.txt b/source/blender/depsgraph/CMakeLists.txt index ab12a8d5b3e..e635256cda6 100644 --- a/source/blender/depsgraph/CMakeLists.txt +++ b/source/blender/depsgraph/CMakeLists.txt @@ -43,9 +43,13 @@ set(SRC intern/builder/deg_builder.cc intern/builder/deg_builder_cycle.cc intern/builder/deg_builder_nodes.cc + intern/builder/deg_builder_nodes_rig.cc + intern/builder/deg_builder_nodes_scene.cc intern/builder/deg_builder_pchanmap.cc intern/builder/deg_builder_relations.cc intern/builder/deg_builder_relations_keys.cc + intern/builder/deg_builder_relations_rig.cc + intern/builder/deg_builder_relations_scene.cc intern/builder/deg_builder_transitive.cc intern/debug/deg_debug_graphviz.cc intern/eval/deg_eval.cc diff --git a/source/blender/depsgraph/intern/builder/deg_builder.cc b/source/blender/depsgraph/intern/builder/deg_builder.cc index 8939e4cc93a..aedd00685b3 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder.cc @@ -48,6 +48,8 @@ #include "util/deg_util_foreach.h" +#include <cstdio> + namespace DEG { string deg_fcurve_id_name(const FCurve *fcu) @@ -85,7 +87,7 @@ void deg_graph_build_finalize(Depsgraph *graph) */ GHASH_FOREACH_BEGIN(IDDepsNode *, id_node, graph->id_hash) { - if (id_node->layers == 0 || 1) { + if (id_node->layers == 0) { ID *id = id_node->id; if (GS(id->name) == ID_OB) { Object *object = (Object *)id; @@ -153,8 +155,8 @@ void deg_graph_build_finalize(Depsgraph *graph) GHASH_FOREACH_END(); ID *id = id_node->id; - if (id->tag & LIB_TAG_ID_RECALC_ALL && - id->tag & LIB_TAG_DOIT) + if ((id->tag & LIB_TAG_ID_RECALC_ALL) && + (id->tag & LIB_TAG_DOIT)) { id_node->tag_update(graph); id->tag &= ~LIB_TAG_DOIT; diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc b/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc index 12050e3e003..e312c4e0dcb 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc @@ -55,8 +55,10 @@ extern "C" { #include "DNA_key_types.h" #include "DNA_lamp_types.h" #include "DNA_material_types.h" +#include "DNA_mask_types.h" #include "DNA_mesh_types.h" #include "DNA_meta_types.h" +#include "DNA_movieclip_types.h" #include "DNA_node_types.h" #include "DNA_particle_types.h" #include "DNA_object_types.h" @@ -105,6 +107,7 @@ extern "C" { #include "intern/nodes/deg_node_operation.h" #include "intern/depsgraph_types.h" #include "intern/depsgraph_intern.h" +#include "util/deg_util_foreach.h" namespace DEG { @@ -317,92 +320,6 @@ OperationDepsNode *DepsgraphNodeBuilder::find_operation_node( /* **** Build functions for entity nodes **** */ -void DepsgraphNodeBuilder::build_scene(Main *bmain, Scene *scene) -{ - /* LIB_TAG_DOIT is used to indicate whether node for given ID was already - * created or not. This flag is being set in add_id_node(), so functions - * shouldn't bother with setting it, they only might query this flag when - * needed. - */ - BKE_main_id_tag_all(bmain, LIB_TAG_DOIT, false); - /* XXX nested node trees are not included in tag-clearing above, - * so we need to do this manually. - */ - FOREACH_NODETREE(bmain, nodetree, id) { - if (id != (ID *)nodetree) - nodetree->id.tag &= ~LIB_TAG_DOIT; - } FOREACH_NODETREE_END - - /* scene ID block */ - add_id_node(&scene->id); - - /* timesource */ - add_time_source(NULL); - - /* build subgraph for set, and link this in... */ - // XXX: depending on how this goes, that scene itself could probably store its - // own little partial depsgraph? - if (scene->set) { - build_scene(bmain, scene->set); - } - - /* scene objects */ - for (Base *base = (Base *)scene->base.first; base; base = base->next) { - Object *ob = base->object; - - /* object itself */ - build_object(scene, base, ob); - - /* object that this is a proxy for */ - // XXX: the way that proxies work needs to be completely reviewed! - if (ob->proxy) { - ob->proxy->proxy_from = ob; - build_object(scene, base, ob->proxy); - } - - /* Object dupligroup. */ - if (ob->dup_group) { - build_group(scene, base, ob->dup_group); - } - } - - /* rigidbody */ - if (scene->rigidbody_world) { - build_rigidbody(scene); - } - - /* scene's animation and drivers */ - if (scene->adt) { - build_animdata(&scene->id); - } - - /* world */ - if (scene->world) { - build_world(scene->world); - } - - /* compo nodes */ - if (scene->nodetree) { - build_compositor(scene); - } - - /* sequencer */ - // XXX... - - /* grease pencil */ - if (scene->gpd) { - build_gpencil(scene->gpd); - } - - /* cache files */ - for (CacheFile *cachefile = static_cast<CacheFile *>(bmain->cachefiles.first); - cachefile; - cachefile = static_cast<CacheFile *>(cachefile->id.next)) - { - build_cachefile(cachefile); - } -} - void DepsgraphNodeBuilder::build_group(Scene *scene, Base *base, Group *group) @@ -413,10 +330,7 @@ void DepsgraphNodeBuilder::build_group(Scene *scene, } group_id->tag |= LIB_TAG_DOIT; - for (GroupObject *go = (GroupObject *)group->gobject.first; - go != NULL; - go = go->next) - { + LINKLIST_FOREACH (GroupObject *, go, &group->gobject) { build_object(scene, base, go->ob); } } @@ -433,10 +347,7 @@ SubgraphDepsNode *DepsgraphNodeBuilder::build_subgraph(Group *group) DepsgraphNodeBuilder subgraph_builder(m_bmain, subgraph); /* add group objects */ - for (GroupObject *go = (GroupObject *)group->gobject.first; - go != NULL; - go = go->next) - { + LINKLIST_FOREACH (GroupObject *, go, &group->gobject) { /*Object *ob = go->ob;*/ /* Each "group object" is effectively a separate instance of the @@ -461,19 +372,26 @@ SubgraphDepsNode *DepsgraphNodeBuilder::build_subgraph(Group *group) void DepsgraphNodeBuilder::build_object(Scene *scene, Base *base, Object *ob) { - if (ob->id.tag & LIB_TAG_DOIT) { - IDDepsNode *id_node = m_graph->find_id_node(&ob->id); - if (base != NULL) { - id_node->layers |= base->lay; - } - return; - } - ob->id.tag |= LIB_TAG_DOIT; - - IDDepsNode *id_node = add_id_node(&ob->id); + const bool has_object = (ob->id.tag & LIB_TAG_DOIT); + IDDepsNode *id_node = (has_object) + ? m_graph->find_id_node(&ob->id) + : add_id_node(&ob->id); + /* Update node layers. + * Do it for both new and existing ID nodes. This is so because several + * bases might be sharing same object. + */ if (base != NULL) { id_node->layers |= base->lay; } + if (ob == scene->camera) { + /* Camera should always be updated, it used directly by viewport. */ + id_node->layers |= (unsigned int)(-1); + } + /* Skip rest of components if the ID node was already there. */ + if (has_object) { + return; + } + ob->id.tag |= LIB_TAG_DOIT; ob->customdata_mask = 0; /* Standard components. */ @@ -626,14 +544,6 @@ void DepsgraphNodeBuilder::build_object_constraints(Scene *scene, Object *ob) DEG_OPCODE_TRANSFORM_CONSTRAINTS); } -void DepsgraphNodeBuilder::build_pose_constraints(Object *ob, bPoseChannel *pchan) -{ - /* create node for constraint stack */ - add_operation_node(&ob->id, DEPSNODE_TYPE_BONE, pchan->name, - DEPSOP_TYPE_EXEC, function_bind(BKE_pose_constraints_evaluate, _1, ob, pchan), - DEG_OPCODE_BONE_CONSTRAINTS); -} - /** * Build graph nodes for AnimData block * \param id: ID-Block which hosts the AnimData @@ -661,7 +571,7 @@ void DepsgraphNodeBuilder::build_animdata(ID *id) } /* drivers */ - for (FCurve *fcu = (FCurve *)adt->drivers.first; fcu; fcu = fcu->next) { + LINKLIST_FOREACH (FCurve *, fcu, &adt->drivers) { /* create driver */ build_driver(id, fcu); } @@ -774,7 +684,7 @@ void DepsgraphNodeBuilder::build_rigidbody(Scene *scene) /* objects - simulation participants */ if (rbw->group) { - for (GroupObject *go = (GroupObject *)rbw->group->gobject.first; go; go = go->next) { + LINKLIST_FOREACH (GroupObject *, go, &rbw->group->gobject) { Object *ob = go->ob; if (!ob || (ob->type != OB_MESH)) @@ -810,7 +720,7 @@ void DepsgraphNodeBuilder::build_particles(Scene *scene, Object *ob) ComponentDepsNode *psys_comp = add_component_node(&ob->id, DEPSNODE_TYPE_EVAL_PARTICLES); /* particle systems */ - for (ParticleSystem *psys = (ParticleSystem *)ob->particlesystem.first; psys; psys = psys->next) { + LINKLIST_FOREACH (ParticleSystem *, psys, &ob->particlesystem) { ParticleSettings *part = psys->part; /* particle settings */ @@ -820,7 +730,11 @@ void DepsgraphNodeBuilder::build_particles(Scene *scene, Object *ob) /* this particle system */ // TODO: for now, this will just be a placeholder "ubereval" node add_operation_node(psys_comp, - DEPSOP_TYPE_EXEC, function_bind(BKE_particle_system_eval, _1, scene, ob, psys), + DEPSOP_TYPE_EXEC, function_bind(BKE_particle_system_eval, + _1, + scene, + ob, + psys), DEG_OPCODE_PSYS_EVAL, psys->name); } @@ -829,207 +743,6 @@ void DepsgraphNodeBuilder::build_particles(Scene *scene, Object *ob) // TODO... } -/* IK Solver Eval Steps */ -void DepsgraphNodeBuilder::build_ik_pose(Scene *scene, Object *ob, bPoseChannel *pchan, bConstraint *con) -{ - bKinematicConstraint *data = (bKinematicConstraint *)con->data; - - /* Find the chain's root. */ - bPoseChannel *rootchan = BKE_armature_ik_solver_find_root(pchan, data); - - if (has_operation_node(&ob->id, DEPSNODE_TYPE_EVAL_POSE, rootchan->name, - DEG_OPCODE_POSE_IK_SOLVER)) - { - return; - } - - /* Operation node for evaluating/running IK Solver. */ - add_operation_node(&ob->id, DEPSNODE_TYPE_EVAL_POSE, rootchan->name, - DEPSOP_TYPE_SIM, function_bind(BKE_pose_iktree_evaluate, _1, scene, ob, rootchan), - DEG_OPCODE_POSE_IK_SOLVER); -} - -/* Spline IK Eval Steps */ -void DepsgraphNodeBuilder::build_splineik_pose(Scene *scene, Object *ob, bPoseChannel *pchan, bConstraint *con) -{ - bSplineIKConstraint *data = (bSplineIKConstraint *)con->data; - - /* Find the chain's root. */ - bPoseChannel *rootchan = BKE_armature_splineik_solver_find_root(pchan, data); - - /* Operation node for evaluating/running Spline IK Solver. - * Store the "root bone" of this chain in the solver, so it knows where to start. - */ - add_operation_node(&ob->id, DEPSNODE_TYPE_EVAL_POSE, rootchan->name, - DEPSOP_TYPE_SIM, function_bind(BKE_pose_splineik_evaluate, _1, scene, ob, rootchan), - DEG_OPCODE_POSE_SPLINE_IK_SOLVER); -} - -/* Pose/Armature Bones Graph */ -void DepsgraphNodeBuilder::build_rig(Scene *scene, Object *ob) -{ - bArmature *arm = (bArmature *)ob->data; - - /* animation and/or drivers linking posebones to base-armature used to define them - * NOTE: AnimData here is really used to control animated deform properties, - * which ideally should be able to be unique across different instances. - * Eventually, we need some type of proxy/isolation mechanism in-between here - * to ensure that we can use same rig multiple times in same scene... - */ - build_animdata(&arm->id); - - /* Rebuild pose if not up to date. */ - if (ob->pose == NULL || (ob->pose->flag & POSE_RECALC)) { - BKE_pose_rebuild_ex(ob, arm, false); - /* XXX: Without this animation gets lost in certain circumstances - * after loading file. Need to investigate further since it does - * not happen with simple scenes.. - */ - if (ob->adt) { - ob->adt->recalc |= ADT_RECALC_ANIM; - } - } - - /* speed optimization for animation lookups */ - if (ob->pose) { - BKE_pose_channels_hash_make(ob->pose); - if (ob->pose->flag & POSE_CONSTRAINTS_NEED_UPDATE_FLAGS) { - BKE_pose_update_constraint_flags(ob->pose); - } - } - - /* Make sure pose is up-to-date with armature updates. */ - add_operation_node(&arm->id, - DEPSNODE_TYPE_PARAMETERS, - DEPSOP_TYPE_EXEC, - NULL, - DEG_OPCODE_PLACEHOLDER, - "Armature Eval"); - - /** - * Pose Rig Graph - * ============== - * - * Pose Component: - * - Mainly used for referencing Bone components. - * - This is where the evaluation operations for init/exec/cleanup - * (ik) solvers live, and are later hooked up (so that they can be - * interleaved during runtime) with bone-operations they depend on/affect. - * - init_pose_eval() and cleanup_pose_eval() are absolute first and last - * steps of pose eval process. ALL bone operations must be performed - * between these two... - * - * Bone Component: - * - Used for representing each bone within the rig - * - Acts to encapsulate the evaluation operations (base matrix + parenting, - * and constraint stack) so that they can be easily found. - * - Everything else which depends on bone-results hook up to the component only - * so that we can redirect those to point at either the the post-IK/ - * post-constraint/post-matrix steps, as needed. - */ - - /* pose eval context */ - add_operation_node(&ob->id, DEPSNODE_TYPE_EVAL_POSE, - DEPSOP_TYPE_INIT, function_bind(BKE_pose_eval_init, _1, scene, ob, ob->pose), DEG_OPCODE_POSE_INIT); - - add_operation_node(&ob->id, DEPSNODE_TYPE_EVAL_POSE, - DEPSOP_TYPE_POST, function_bind(BKE_pose_eval_flush, _1, scene, ob, ob->pose), DEG_OPCODE_POSE_DONE); - - /* bones */ - for (bPoseChannel *pchan = (bPoseChannel *)ob->pose->chanbase.first; pchan; pchan = pchan->next) { - /* node for bone eval */ - add_operation_node(&ob->id, DEPSNODE_TYPE_BONE, pchan->name, - DEPSOP_TYPE_INIT, NULL, // XXX: BKE_pose_eval_bone_local - DEG_OPCODE_BONE_LOCAL); - - add_operation_node(&ob->id, DEPSNODE_TYPE_BONE, pchan->name, - DEPSOP_TYPE_EXEC, function_bind(BKE_pose_eval_bone, _1, scene, ob, pchan), // XXX: BKE_pose_eval_bone_pose - DEG_OPCODE_BONE_POSE_PARENT); - - add_operation_node(&ob->id, DEPSNODE_TYPE_BONE, pchan->name, - DEPSOP_TYPE_OUT, NULL, /* NOTE: dedicated noop for easier relationship construction */ - DEG_OPCODE_BONE_READY); - - add_operation_node(&ob->id, DEPSNODE_TYPE_BONE, pchan->name, - DEPSOP_TYPE_POST, function_bind(BKE_pose_bone_done, _1, pchan), - DEG_OPCODE_BONE_DONE); - - /* constraints */ - if (pchan->constraints.first != NULL) { - build_pose_constraints(ob, pchan); - } - - /** - * IK Solvers... - * - * - These require separate processing steps are pose-level - * to be executed between chains of bones (i.e. once the - * base transforms of a bunch of bones is done) - * - * Unsolved Issues: - * - Care is needed to ensure that multi-headed trees work out the same as in ik-tree building - * - Animated chain-lengths are a problem... - */ - for (bConstraint *con = (bConstraint *)pchan->constraints.first; con; con = con->next) { - switch (con->type) { - case CONSTRAINT_TYPE_KINEMATIC: - build_ik_pose(scene, ob, pchan, con); - break; - - case CONSTRAINT_TYPE_SPLINEIK: - build_splineik_pose(scene, ob, pchan, con); - break; - - default: - break; - } - } - } -} - -void DepsgraphNodeBuilder::build_proxy_rig(Object *ob) -{ - ID *obdata = (ID *)ob->data; - build_animdata(obdata); - - BLI_assert(ob->pose != NULL); - - /* speed optimization for animation lookups */ - BKE_pose_channels_hash_make(ob->pose); - if (ob->pose->flag & POSE_CONSTRAINTS_NEED_UPDATE_FLAGS) { - BKE_pose_update_constraint_flags(ob->pose); - } - - add_operation_node(&ob->id, - DEPSNODE_TYPE_EVAL_POSE, - DEPSOP_TYPE_INIT, - function_bind(BKE_pose_eval_proxy_copy, _1, ob), - DEG_OPCODE_POSE_INIT); - - for (bPoseChannel *pchan = (bPoseChannel *)ob->pose->chanbase.first; - pchan != NULL; - pchan = pchan->next) - { - add_operation_node(&ob->id, DEPSNODE_TYPE_BONE, pchan->name, - DEPSOP_TYPE_INIT, NULL, - DEG_OPCODE_BONE_LOCAL); - - add_operation_node(&ob->id, DEPSNODE_TYPE_BONE, pchan->name, - DEPSOP_TYPE_EXEC, NULL, - DEG_OPCODE_BONE_READY); - - add_operation_node(&ob->id, DEPSNODE_TYPE_BONE, pchan->name, - DEPSOP_TYPE_POST, NULL, - DEG_OPCODE_BONE_DONE); - } - - add_operation_node(&ob->id, - DEPSNODE_TYPE_EVAL_POSE, - DEPSOP_TYPE_POST, - NULL, - DEG_OPCODE_POSE_DONE); -} - /* Shapekeys */ void DepsgraphNodeBuilder::build_shapekeys(Key *key) { @@ -1080,33 +793,26 @@ void DepsgraphNodeBuilder::build_obdata_geom(Scene *scene, Object *ob) // TODO: "Done" operation /* Modifiers */ - if (ob->modifiers.first) { - for (ModifierData *md = (ModifierData *)ob->modifiers.first; - md != NULL; - md = md->next) - { - add_operation_node(&ob->id, - DEPSNODE_TYPE_GEOMETRY, - DEPSOP_TYPE_EXEC, - function_bind(BKE_object_eval_modifier, - _1, - scene, - ob, - md), - DEG_OPCODE_GEOMETRY_MODIFIER, - md->name); - } + LINKLIST_FOREACH (ModifierData *, md, &ob->modifiers) { + add_operation_node(&ob->id, + DEPSNODE_TYPE_GEOMETRY, + DEPSOP_TYPE_EXEC, + function_bind(BKE_object_eval_modifier, + _1, + scene, + ob, + md), + DEG_OPCODE_GEOMETRY_MODIFIER, + md->name); } /* materials */ - if (ob->totcol) { - for (int a = 1; a <= ob->totcol; a++) { - Material *ma = give_current_material(ob, a); - if (ma != NULL) { - // XXX?! - ComponentDepsNode *geom_node = add_component_node(&ob->id, DEPSNODE_TYPE_GEOMETRY); - build_material(geom_node, ma); - } + for (int a = 1; a <= ob->totcol; a++) { + Material *ma = give_current_material(ob, a); + if (ma != NULL) { + // XXX?! + ComponentDepsNode *geom_node = add_component_node(&ob->id, DEPSNODE_TYPE_GEOMETRY); + build_material(geom_node, ma); } } @@ -1202,7 +908,7 @@ void DepsgraphNodeBuilder::build_obdata_geom(Scene *scene, Object *ob) build_object(scene, NULL, cu->bevobj); } if (cu->taperobj != NULL) { - build_object(scene, NULL, cu->bevobj); + build_object(scene, NULL, cu->taperobj); } if (ob->type == OB_FONT && cu->textoncurve != NULL) { build_object(scene, NULL, cu->textoncurve); @@ -1300,7 +1006,7 @@ void DepsgraphNodeBuilder::build_nodetree(DepsNode *owner_node, bNodeTree *ntree DEG_OPCODE_PLACEHOLDER, "Parameters Eval"); /* nodetree's nodes... */ - for (bNode *bnode = (bNode *)ntree->nodes.first; bnode; bnode = bnode->next) { + LINKLIST_FOREACH (bNode *, bnode, &ntree->nodes) { ID *id = bnode->id; if (id != NULL) { short id_type = GS(id->name); @@ -1431,7 +1137,6 @@ void DepsgraphNodeBuilder::build_cachefile(CacheFile *cache_file) ID *cache_file_id = &cache_file->id; add_component_node(cache_file_id, DEPSNODE_TYPE_CACHE); - add_operation_node(cache_file_id, DEPSNODE_TYPE_CACHE, DEPSOP_TYPE_EXEC, NULL, DEG_OPCODE_PLACEHOLDER, "Cache File Update"); @@ -1440,4 +1145,17 @@ void DepsgraphNodeBuilder::build_cachefile(CacheFile *cache_file) build_animdata(cache_file_id); } +void DepsgraphNodeBuilder::build_mask(Mask *mask) +{ + ID *mask_id = &mask->id; + add_id_node(mask_id); + build_animdata(mask_id); +} + +void DepsgraphNodeBuilder::build_movieclip(MovieClip *clip) { + ID *clip_id = &clip->id; + add_id_node(clip_id); + build_animdata(clip_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 index 72dc73357bf..9cb8bc5d45c 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_nodes.h +++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes.h @@ -44,7 +44,9 @@ struct Group; struct Key; struct Main; struct Material; +struct Mask; struct MTex; +struct MovieClip; struct bNodeTree; struct Object; struct bPoseChannel; @@ -154,6 +156,8 @@ struct DepsgraphNodeBuilder { void build_compositor(Scene *scene); void build_gpencil(bGPdata *gpd); void build_cachefile(CacheFile *cache_file); + void build_mask(Mask *mask); + void build_movieclip(MovieClip *clip); protected: Main *m_bmain; diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes_rig.cc b/source/blender/depsgraph/intern/builder/deg_builder_nodes_rig.cc new file mode 100644 index 00000000000..4a5f3dc8664 --- /dev/null +++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes_rig.cc @@ -0,0 +1,273 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2013 Blender Foundation. + * All rights reserved. + * + * Original Author: Joshua Leung + * Contributor(s): Based on original depsgraph.c code - Blender Foundation (2005-2013) + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/depsgraph/intern/builder/deg_builder_nodes_rig.cc + * \ingroup depsgraph + * + * Methods for constructing depsgraph's nodes + */ + +#include "intern/builder/deg_builder_nodes.h" + +#include <stdio.h> +#include <stdlib.h> + +#include "MEM_guardedalloc.h" + +extern "C" { +#include "BLI_blenlib.h" +#include "BLI_string.h" +#include "BLI_utildefines.h" + +#include "DNA_anim_types.h" +#include "DNA_armature_types.h" +#include "DNA_constraint_types.h" +#include "DNA_object_types.h" + +#include "BKE_action.h" +#include "BKE_armature.h" + +#include "DEG_depsgraph.h" +#include "DEG_depsgraph_build.h" +} /* extern "C" */ + +#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" +#include "util/deg_util_foreach.h" + +namespace DEG { + +void DepsgraphNodeBuilder::build_pose_constraints(Object *ob, bPoseChannel *pchan) +{ + /* create node for constraint stack */ + add_operation_node(&ob->id, DEPSNODE_TYPE_BONE, pchan->name, + DEPSOP_TYPE_EXEC, function_bind(BKE_pose_constraints_evaluate, _1, ob, pchan), + DEG_OPCODE_BONE_CONSTRAINTS); +} + +/* IK Solver Eval Steps */ +void DepsgraphNodeBuilder::build_ik_pose(Scene *scene, Object *ob, bPoseChannel *pchan, bConstraint *con) +{ + bKinematicConstraint *data = (bKinematicConstraint *)con->data; + + /* Find the chain's root. */ + bPoseChannel *rootchan = BKE_armature_ik_solver_find_root(pchan, data); + + if (has_operation_node(&ob->id, DEPSNODE_TYPE_EVAL_POSE, rootchan->name, + DEG_OPCODE_POSE_IK_SOLVER)) + { + return; + } + + /* Operation node for evaluating/running IK Solver. */ + add_operation_node(&ob->id, DEPSNODE_TYPE_EVAL_POSE, rootchan->name, + DEPSOP_TYPE_SIM, function_bind(BKE_pose_iktree_evaluate, _1, scene, ob, rootchan), + DEG_OPCODE_POSE_IK_SOLVER); +} + +/* Spline IK Eval Steps */ +void DepsgraphNodeBuilder::build_splineik_pose(Scene *scene, Object *ob, bPoseChannel *pchan, bConstraint *con) +{ + bSplineIKConstraint *data = (bSplineIKConstraint *)con->data; + + /* Find the chain's root. */ + bPoseChannel *rootchan = BKE_armature_splineik_solver_find_root(pchan, data); + + /* Operation node for evaluating/running Spline IK Solver. + * Store the "root bone" of this chain in the solver, so it knows where to start. + */ + add_operation_node(&ob->id, DEPSNODE_TYPE_EVAL_POSE, rootchan->name, + DEPSOP_TYPE_SIM, function_bind(BKE_pose_splineik_evaluate, _1, scene, ob, rootchan), + DEG_OPCODE_POSE_SPLINE_IK_SOLVER); +} + +/* Pose/Armature Bones Graph */ +void DepsgraphNodeBuilder::build_rig(Scene *scene, Object *ob) +{ + bArmature *arm = (bArmature *)ob->data; + + /* animation and/or drivers linking posebones to base-armature used to define them + * NOTE: AnimData here is really used to control animated deform properties, + * which ideally should be able to be unique across different instances. + * Eventually, we need some type of proxy/isolation mechanism in-between here + * to ensure that we can use same rig multiple times in same scene... + */ + build_animdata(&arm->id); + + /* Rebuild pose if not up to date. */ + if (ob->pose == NULL || (ob->pose->flag & POSE_RECALC)) { + BKE_pose_rebuild_ex(ob, arm, false); + /* XXX: Without this animation gets lost in certain circumstances + * after loading file. Need to investigate further since it does + * not happen with simple scenes.. + */ + if (ob->adt) { + ob->adt->recalc |= ADT_RECALC_ANIM; + } + } + + /* speed optimization for animation lookups */ + if (ob->pose) { + BKE_pose_channels_hash_make(ob->pose); + if (ob->pose->flag & POSE_CONSTRAINTS_NEED_UPDATE_FLAGS) { + BKE_pose_update_constraint_flags(ob->pose); + } + } + + /* Make sure pose is up-to-date with armature updates. */ + add_operation_node(&arm->id, + DEPSNODE_TYPE_PARAMETERS, + DEPSOP_TYPE_EXEC, + NULL, + DEG_OPCODE_PLACEHOLDER, + "Armature Eval"); + + /** + * Pose Rig Graph + * ============== + * + * Pose Component: + * - Mainly used for referencing Bone components. + * - This is where the evaluation operations for init/exec/cleanup + * (ik) solvers live, and are later hooked up (so that they can be + * interleaved during runtime) with bone-operations they depend on/affect. + * - init_pose_eval() and cleanup_pose_eval() are absolute first and last + * steps of pose eval process. ALL bone operations must be performed + * between these two... + * + * Bone Component: + * - Used for representing each bone within the rig + * - Acts to encapsulate the evaluation operations (base matrix + parenting, + * and constraint stack) so that they can be easily found. + * - Everything else which depends on bone-results hook up to the component only + * so that we can redirect those to point at either the the post-IK/ + * post-constraint/post-matrix steps, as needed. + */ + + /* pose eval context */ + add_operation_node(&ob->id, DEPSNODE_TYPE_EVAL_POSE, + DEPSOP_TYPE_INIT, function_bind(BKE_pose_eval_init, _1, scene, ob, ob->pose), DEG_OPCODE_POSE_INIT); + + add_operation_node(&ob->id, DEPSNODE_TYPE_EVAL_POSE, + DEPSOP_TYPE_POST, function_bind(BKE_pose_eval_flush, _1, scene, ob, ob->pose), DEG_OPCODE_POSE_DONE); + + /* bones */ + LINKLIST_FOREACH (bPoseChannel *, pchan, &ob->pose->chanbase) { + /* node for bone eval */ + add_operation_node(&ob->id, DEPSNODE_TYPE_BONE, pchan->name, + DEPSOP_TYPE_INIT, NULL, // XXX: BKE_pose_eval_bone_local + DEG_OPCODE_BONE_LOCAL); + + add_operation_node(&ob->id, DEPSNODE_TYPE_BONE, pchan->name, + DEPSOP_TYPE_EXEC, function_bind(BKE_pose_eval_bone, _1, scene, ob, pchan), // XXX: BKE_pose_eval_bone_pose + DEG_OPCODE_BONE_POSE_PARENT); + + add_operation_node(&ob->id, DEPSNODE_TYPE_BONE, pchan->name, + DEPSOP_TYPE_OUT, NULL, /* NOTE: dedicated noop for easier relationship construction */ + DEG_OPCODE_BONE_READY); + + add_operation_node(&ob->id, DEPSNODE_TYPE_BONE, pchan->name, + DEPSOP_TYPE_POST, function_bind(BKE_pose_bone_done, _1, pchan), + DEG_OPCODE_BONE_DONE); + + /* constraints */ + if (pchan->constraints.first != NULL) { + build_pose_constraints(ob, pchan); + } + + /** + * IK Solvers... + * + * - These require separate processing steps are pose-level + * to be executed between chains of bones (i.e. once the + * base transforms of a bunch of bones is done) + * + * Unsolved Issues: + * - Care is needed to ensure that multi-headed trees work out the same as in ik-tree building + * - Animated chain-lengths are a problem... + */ + LINKLIST_FOREACH (bConstraint *, con, &pchan->constraints) { + switch (con->type) { + case CONSTRAINT_TYPE_KINEMATIC: + build_ik_pose(scene, ob, pchan, con); + break; + + case CONSTRAINT_TYPE_SPLINEIK: + build_splineik_pose(scene, ob, pchan, con); + break; + + default: + break; + } + } + } +} + +void DepsgraphNodeBuilder::build_proxy_rig(Object *ob) +{ + ID *obdata = (ID *)ob->data; + build_animdata(obdata); + + BLI_assert(ob->pose != NULL); + + /* speed optimization for animation lookups */ + BKE_pose_channels_hash_make(ob->pose); + if (ob->pose->flag & POSE_CONSTRAINTS_NEED_UPDATE_FLAGS) { + BKE_pose_update_constraint_flags(ob->pose); + } + + add_operation_node(&ob->id, + DEPSNODE_TYPE_EVAL_POSE, + DEPSOP_TYPE_INIT, + function_bind(BKE_pose_eval_proxy_copy, _1, ob), + DEG_OPCODE_POSE_INIT); + + LINKLIST_FOREACH (bPoseChannel *, pchan, &ob->pose->chanbase) { + add_operation_node(&ob->id, DEPSNODE_TYPE_BONE, pchan->name, + DEPSOP_TYPE_INIT, NULL, + DEG_OPCODE_BONE_LOCAL); + + add_operation_node(&ob->id, DEPSNODE_TYPE_BONE, pchan->name, + DEPSOP_TYPE_EXEC, NULL, + DEG_OPCODE_BONE_READY); + + add_operation_node(&ob->id, DEPSNODE_TYPE_BONE, pchan->name, + DEPSOP_TYPE_POST, NULL, + DEG_OPCODE_BONE_DONE); + } + + add_operation_node(&ob->id, + DEPSNODE_TYPE_EVAL_POSE, + DEPSOP_TYPE_POST, + NULL, + DEG_OPCODE_POSE_DONE); +} + +} // namespace DEG diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes_scene.cc b/source/blender/depsgraph/intern/builder/deg_builder_nodes_scene.cc new file mode 100644 index 00000000000..bcd4bc51448 --- /dev/null +++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes_scene.cc @@ -0,0 +1,159 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2013 Blender Foundation. + * All rights reserved. + * + * Original Author: Joshua Leung + * Contributor(s): Based on original depsgraph.c code - Blender Foundation (2005-2013) + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/depsgraph/intern/builder/deg_builder_nodes_scene.cc + * \ingroup depsgraph + * + * Methods for constructing depsgraph's nodes + */ + +#include "intern/builder/deg_builder_nodes.h" + +#include <stdio.h> +#include <stdlib.h> + +#include "MEM_guardedalloc.h" + +extern "C" { +#include "BLI_blenlib.h" +#include "BLI_string.h" +#include "BLI_utildefines.h" + +#include "DNA_node_types.h" +#include "DNA_object_types.h" +#include "DNA_scene_types.h" + +#include "BKE_main.h" +#include "BKE_node.h" + +#include "DEG_depsgraph.h" +#include "DEG_depsgraph_build.h" +} /* extern "C" */ + +#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" +#include "util/deg_util_foreach.h" + +namespace DEG { + +void DepsgraphNodeBuilder::build_scene(Main *bmain, Scene *scene) +{ + /* LIB_TAG_DOIT is used to indicate whether node for given ID was already + * created or not. This flag is being set in add_id_node(), so functions + * shouldn't bother with setting it, they only might query this flag when + * needed. + */ + BKE_main_id_tag_all(bmain, LIB_TAG_DOIT, false); + /* XXX nested node trees are not included in tag-clearing above, + * so we need to do this manually. + */ + FOREACH_NODETREE(bmain, nodetree, id) { + if (id != (ID *)nodetree) + nodetree->id.tag &= ~LIB_TAG_DOIT; + } FOREACH_NODETREE_END + + /* scene ID block */ + add_id_node(&scene->id); + + /* timesource */ + add_time_source(NULL); + + /* build subgraph for set, and link this in... */ + // XXX: depending on how this goes, that scene itself could probably store its + // own little partial depsgraph? + if (scene->set) { + build_scene(bmain, scene->set); + } + + /* scene objects */ + LINKLIST_FOREACH (Base *, base, &scene->base) { + 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 dupligroup. */ + if (ob->dup_group) { + build_group(scene, base, ob->dup_group); + } + } + + /* rigidbody */ + if (scene->rigidbody_world) { + build_rigidbody(scene); + } + + /* scene's animation and drivers */ + if (scene->adt) { + build_animdata(&scene->id); + } + + /* world */ + if (scene->world) { + build_world(scene->world); + } + + /* compo nodes */ + if (scene->nodetree) { + build_compositor(scene); + } + + /* sequencer */ + // XXX... + + /* grease pencil */ + if (scene->gpd) { + build_gpencil(scene->gpd); + } + + /* Cache file. */ + LINKLIST_FOREACH (CacheFile *, cachefile, &bmain->cachefiles) { + build_cachefile(cachefile); + } + + /* Masks. */ + LINKLIST_FOREACH (Mask *, mask, &bmain->mask) { + build_mask(mask); + } + + /* Movie clips. */ + LINKLIST_FOREACH (MovieClip *, clip, &bmain->movieclip) { + build_movieclip(clip); + } +} + +} // namespace DEG diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc index fe75de5e350..dadb7f8917f 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc @@ -55,8 +55,10 @@ extern "C" { #include "DNA_key_types.h" #include "DNA_lamp_types.h" #include "DNA_material_types.h" +#include "DNA_mask_types.h" #include "DNA_mesh_types.h" #include "DNA_meta_types.h" +#include "DNA_movieclip_types.h" #include "DNA_node_types.h" #include "DNA_particle_types.h" #include "DNA_object_types.h" @@ -337,88 +339,6 @@ void DepsgraphRelationBuilder::add_forcefield_relations(const OperationKey &key, /* **** Functions to build relations between entities **** */ -void DepsgraphRelationBuilder::build_scene(Main *bmain, Scene *scene) -{ - /* LIB_TAG_DOIT is used to indicate whether node for given ID was already - * created or not. - */ - BKE_main_id_tag_all(bmain, LIB_TAG_DOIT, false); - /* XXX nested node trees are not included in tag-clearing above, - * so we need to do this manually. - */ - FOREACH_NODETREE(bmain, nodetree, id) { - if (id != (ID *)nodetree) - nodetree->id.tag &= ~LIB_TAG_DOIT; - } FOREACH_NODETREE_END - - if (scene->set) { - // TODO: link set to scene, especially our timesource... - } - - /* scene objects */ - for (Base *base = (Base *)scene->base.first; base; base = base->next) { - Object *ob = base->object; - - /* object itself */ - build_object(bmain, scene, ob); - - /* object that this is a proxy for */ - if (ob->proxy) { - ob->proxy->proxy_from = ob; - build_object(bmain, scene, ob->proxy); - /* TODO(sergey): This is an inverted relation, matches old depsgraph - * behavior and need to be investigated if it still need to be inverted. - */ - ComponentKey ob_pose_key(&ob->id, DEPSNODE_TYPE_EVAL_POSE); - ComponentKey proxy_pose_key(&ob->proxy->id, DEPSNODE_TYPE_EVAL_POSE); - add_relation(ob_pose_key, proxy_pose_key, DEPSREL_TYPE_TRANSFORM, "Proxy"); - } - - /* Object dupligroup. */ - if (ob->dup_group) { - build_group(bmain, scene, ob, ob->dup_group); - } - } - - /* rigidbody */ - if (scene->rigidbody_world) { - build_rigidbody(scene); - } - - /* scene's animation and drivers */ - if (scene->adt) { - build_animdata(&scene->id); - } - - /* world */ - if (scene->world) { - build_world(scene->world); - } - - /* compo nodes */ - if (scene->nodetree) { - build_compositor(scene); - } - - /* grease pencil */ - if (scene->gpd) { - build_gpencil(&scene->id, scene->gpd); - } - - 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, Scene *scene, Object *object, @@ -429,10 +349,7 @@ void DepsgraphRelationBuilder::build_group(Main *bmain, OperationKey object_local_transform_key(&object->id, DEPSNODE_TYPE_TRANSFORM, DEG_OPCODE_TRANSFORM_LOCAL); - for (GroupObject *go = (GroupObject *)group->gobject.first; - go != NULL; - go = go->next) - { + LINKLIST_FOREACH (GroupObject *, go, &group->gobject) { if (!group_done) { build_object(bmain, scene, go->ob); } @@ -709,9 +626,10 @@ void DepsgraphRelationBuilder::build_constraints(Scene *scene, ID *id, eDepsNode ListBase targets = {NULL, NULL}; cti->get_constraint_targets(con, &targets); - for (bConstraintTarget *ct = (bConstraintTarget *)targets.first; ct; ct = ct->next) { - if (!ct->tar) + LINKLIST_FOREACH (bConstraintTarget *, ct, &targets) { + if (ct->tar == NULL) { continue; + } if (ELEM(con->type, CONSTRAINT_TYPE_KINEMATIC, CONSTRAINT_TYPE_SPLINEIK)) { /* ignore IK constraints - these are handled separately (on pose level) */ @@ -838,7 +756,7 @@ void DepsgraphRelationBuilder::build_animdata(ID *id) } /* drivers */ - for (FCurve *fcu = (FCurve *)adt->drivers.first; fcu; fcu = fcu->next) { + LINKLIST_FOREACH (FCurve *, fcu, &adt->drivers) { OperationKey driver_key(id, DEPSNODE_TYPE_PARAMETERS, DEG_OPCODE_DRIVER, @@ -862,10 +780,7 @@ void DepsgraphRelationBuilder::build_animdata(ID *id) */ if (fcu->array_index > 0) { FCurve *fcu_prev = NULL; - for (FCurve *fcu_candidate = (FCurve *)adt->drivers.first; - fcu_candidate != NULL; - fcu_candidate = fcu_candidate->next) - { + LINKLIST_FOREACH (FCurve *, fcu_candidate, &adt->drivers) { /* Writing to different RNA paths is */ if (!STREQ(fcu_candidate->rna_path, fcu->rna_path)) { continue; @@ -1029,7 +944,7 @@ void DepsgraphRelationBuilder::build_driver(ID *id, FCurve *fcu) // XXX: the data itself could also set this, if it were to be truly initialised later? /* loop over variables to get the target relationships */ - for (DriverVar *dvar = (DriverVar *)driver->variables.first; dvar; dvar = dvar->next) { + LINKLIST_FOREACH (DriverVar *, dvar, &driver->variables) { /* only used targets */ DRIVER_TARGETS_USED_LOOPER(dvar) { @@ -1149,10 +1064,11 @@ void DepsgraphRelationBuilder::build_rigidbody(Scene *scene) /* objects - simulation participants */ if (rbw->group) { - for (GroupObject *go = (GroupObject *)rbw->group->gobject.first; go; go = go->next) { + LINKLIST_FOREACH (GroupObject *, go, &rbw->group->gobject) { Object *ob = go->ob; - if (!ob || ob->type != OB_MESH) + if (ob == NULL || ob->type != OB_MESH) { continue; + } /* hook up evaluation order... * 1) flushing rigidbody results follows base transforms being applied @@ -1200,10 +1116,11 @@ void DepsgraphRelationBuilder::build_rigidbody(Scene *scene) /* constraints */ if (rbw->constraints) { - for (GroupObject *go = (GroupObject *)rbw->constraints->gobject.first; go; go = go->next) { + LINKLIST_FOREACH (GroupObject *, go, &rbw->constraints->gobject) { Object *ob = go->ob; - if (!ob || !ob->rigidbody_constraint) + if (ob == NULL || !ob->rigidbody_constraint) { continue; + } RigidBodyCon *rbc = ob->rigidbody_constraint; @@ -1232,7 +1149,7 @@ void DepsgraphRelationBuilder::build_particles(Scene *scene, Object *ob) DEG_OPCODE_GEOMETRY_UBEREVAL); /* particle systems */ - for (ParticleSystem *psys = (ParticleSystem *)ob->particlesystem.first; psys; psys = psys->next) { + LINKLIST_FOREACH (ParticleSystem *, psys, &ob->particlesystem) { ParticleSettings *part = psys->part; /* particle settings */ @@ -1263,9 +1180,7 @@ void DepsgraphRelationBuilder::build_particles(Scene *scene, Object *ob) #if 0 if (ELEM(part->phystype, PART_PHYS_KEYED, PART_PHYS_BOIDS)) { - ParticleTarget *pt; - - for (pt = psys->targets.first; pt; pt = pt->next) { + LINKLIST_FOREACH (ParticleTarget *, pt, &psys->targets) { if (pt->ob && BLI_findlink(&pt->ob->particlesystem, pt->psys - 1)) { node2 = dag_get_node(dag, pt->ob); dag_add_relation(dag, node2, node, DAG_RL_DATA_DATA | DAG_RL_OB_DATA, "Particle Targets"); @@ -1284,7 +1199,7 @@ void DepsgraphRelationBuilder::build_particles(Scene *scene, Object *ob) } if (part->ren_as == PART_DRAW_GR && part->dup_group) { - for (go = part->dup_group->gobject.first; go; go = go->next) { + LINKLIST_FOREACH (GroupObject *, go, &part->dup_group->gobject) { node2 = dag_get_node(dag, go->ob); dag_add_relation(dag, node2, node, DAG_RL_OB_OB, "Particle Group Visualization"); } @@ -1301,11 +1216,8 @@ void DepsgraphRelationBuilder::build_particles(Scene *scene, Object *ob) /* boids */ if (part->boids) { - BoidRule *rule = NULL; - BoidState *state = NULL; - - for (state = (BoidState *)part->boids->states.first; state; state = state->next) { - for (rule = (BoidRule *)state->rules.first; rule; rule = rule->next) { + LINKLIST_FOREACH (BoidState *, state, &part->boids->states) { + LINKLIST_FOREACH (BoidRule *, rule, &state->rules) { Object *ruleob = NULL; if (rule->type == eBoidRuleType_Avoid) ruleob = ((BoidRuleGoalAvoid *)rule)->ob; @@ -1345,391 +1257,6 @@ void DepsgraphRelationBuilder::build_particles(Scene *scene, Object *ob) // TODO... } -/* IK Solver Eval Steps */ -void DepsgraphRelationBuilder::build_ik_pose(Object *ob, - bPoseChannel *pchan, - bConstraint *con, - RootPChanMap *root_map) -{ - bKinematicConstraint *data = (bKinematicConstraint *)con->data; - - /* attach owner to IK Solver too - * - assume that owner is always part of chain - * - see notes on direction of rel below... - */ - bPoseChannel *rootchan = BKE_armature_ik_solver_find_root(pchan, data); - OperationKey solver_key(&ob->id, DEPSNODE_TYPE_EVAL_POSE, rootchan->name, DEG_OPCODE_POSE_IK_SOLVER); - - /* IK target */ - // XXX: this should get handled as part of the constraint code - if (data->tar != NULL) { - /* TODO(sergey): For until we'll store partial matricies in the depsgraph, - * we create dependency between target object and pose eval component. - * - * This way we ensuring the whole subtree is updated from scratch without - * need of intermediate matricies. This is an overkill, but good enough for - * testing IK solver. - */ - // FIXME: geometry targets... - ComponentKey pose_key(&ob->id, DEPSNODE_TYPE_EVAL_POSE); - if ((data->tar->type == OB_ARMATURE) && (data->subtarget[0])) { - /* TODO(sergey): This is only for until granular update stores intermediate result. */ - if (data->tar != ob) { - /* different armature - can just read the results */ - ComponentKey target_key(&data->tar->id, DEPSNODE_TYPE_BONE, data->subtarget); - add_relation(target_key, pose_key, DEPSREL_TYPE_TRANSFORM, con->name); - } - else { - /* same armature - we'll use the ready state only, just in case this bone is in the chain we're solving */ - OperationKey target_key(&data->tar->id, DEPSNODE_TYPE_BONE, data->subtarget, DEG_OPCODE_BONE_DONE); - add_relation(target_key, solver_key, DEPSREL_TYPE_TRANSFORM, con->name); - } - } - else if (ELEM(data->tar->type, OB_MESH, OB_LATTICE) && (data->subtarget[0])) { - /* vertex group target */ - /* NOTE: for now, we don't need to represent vertex groups separately... */ - ComponentKey target_key(&data->tar->id, DEPSNODE_TYPE_GEOMETRY); - add_relation(target_key, solver_key, DEPSREL_TYPE_GEOMETRY_EVAL, con->name); - - if (data->tar->type == OB_MESH) { - OperationDepsNode *node2 = find_operation_node(target_key); - if (node2 != NULL) { - node2->customdata_mask |= CD_MASK_MDEFORMVERT; - } - } - } - else { - /* Standard Object Target */ - ComponentKey target_key(&data->tar->id, DEPSNODE_TYPE_TRANSFORM); - add_relation(target_key, pose_key, DEPSREL_TYPE_TRANSFORM, con->name); - } - - if ((data->tar == ob) && (data->subtarget[0])) { - /* Prevent target's constraints from linking to anything from same - * chain that it controls. - */ - root_map->add_bone(data->subtarget, rootchan->name); - } - } - - /* Pole Target */ - // XXX: this should get handled as part of the constraint code - if (data->poletar != NULL) { - if ((data->poletar->type == OB_ARMATURE) && (data->polesubtarget[0])) { - // XXX: same armature issues - ready vs done? - ComponentKey target_key(&data->poletar->id, DEPSNODE_TYPE_BONE, data->polesubtarget); - add_relation(target_key, solver_key, DEPSREL_TYPE_TRANSFORM, con->name); - } - else if (ELEM(data->poletar->type, OB_MESH, OB_LATTICE) && (data->polesubtarget[0])) { - /* vertex group target */ - /* NOTE: for now, we don't need to represent vertex groups separately... */ - ComponentKey target_key(&data->poletar->id, DEPSNODE_TYPE_GEOMETRY); - add_relation(target_key, solver_key, DEPSREL_TYPE_GEOMETRY_EVAL, con->name); - - if (data->poletar->type == OB_MESH) { - OperationDepsNode *node2 = find_operation_node(target_key); - if (node2 != NULL) { - node2->customdata_mask |= CD_MASK_MDEFORMVERT; - } - } - } - else { - ComponentKey target_key(&data->poletar->id, DEPSNODE_TYPE_TRANSFORM); - add_relation(target_key, solver_key, DEPSREL_TYPE_TRANSFORM, con->name); - } - } - - DEG_DEBUG_PRINTF("\nStarting IK Build: pchan = %s, target = (%s, %s), segcount = %d\n", - pchan->name, data->tar->id.name, data->subtarget, data->rootbone); - - bPoseChannel *parchan = pchan; - /* exclude tip from chain? */ - if (!(data->flag & CONSTRAINT_IK_TIP)) { - OperationKey tip_transforms_key(&ob->id, DEPSNODE_TYPE_BONE, - parchan->name, DEG_OPCODE_BONE_LOCAL); - add_relation(solver_key, tip_transforms_key, - DEPSREL_TYPE_TRANSFORM, "IK Solver Result"); - parchan = pchan->parent; - } - - root_map->add_bone(parchan->name, rootchan->name); - - OperationKey parchan_transforms_key(&ob->id, DEPSNODE_TYPE_BONE, - parchan->name, DEG_OPCODE_BONE_READY); - add_relation(parchan_transforms_key, solver_key, - DEPSREL_TYPE_TRANSFORM, "IK Solver Owner"); - - /* Walk to the chain's root */ - //size_t segcount = 0; - int segcount = 0; - - while (parchan) { - /* Make IK-solver dependent on this bone's result, - * since it can only run after the standard results - * of the bone are know. Validate links step on the - * bone will ensure that users of this bone only - * grab the result with IK solver results... - */ - if (parchan != pchan) { - OperationKey parent_key(&ob->id, DEPSNODE_TYPE_BONE, parchan->name, DEG_OPCODE_BONE_READY); - add_relation(parent_key, solver_key, DEPSREL_TYPE_TRANSFORM, "IK Chain Parent"); - - OperationKey done_key(&ob->id, DEPSNODE_TYPE_BONE, parchan->name, DEG_OPCODE_BONE_DONE); - add_relation(solver_key, done_key, DEPSREL_TYPE_TRANSFORM, "IK Chain Result"); - } - else { - OperationKey final_transforms_key(&ob->id, DEPSNODE_TYPE_BONE, parchan->name, DEG_OPCODE_BONE_DONE); - add_relation(solver_key, final_transforms_key, DEPSREL_TYPE_TRANSFORM, "IK Solver Result"); - } - parchan->flag |= POSE_DONE; - - - root_map->add_bone(parchan->name, rootchan->name); - - /* continue up chain, until we reach target number of items... */ - DEG_DEBUG_PRINTF(" %d = %s\n", segcount, parchan->name); - segcount++; - if ((segcount == data->rootbone) || (segcount > 255)) break; /* 255 is weak */ - - parchan = parchan->parent; - } - - OperationKey flush_key(&ob->id, DEPSNODE_TYPE_EVAL_POSE, DEG_OPCODE_POSE_DONE); - add_relation(solver_key, flush_key, DEPSREL_TYPE_OPERATION, "PoseEval Result-Bone Link"); -} - -/* Spline IK Eval Steps */ -void DepsgraphRelationBuilder::build_splineik_pose(Object *ob, - bPoseChannel *pchan, - bConstraint *con, - RootPChanMap *root_map) -{ - bSplineIKConstraint *data = (bSplineIKConstraint *)con->data; - bPoseChannel *rootchan = BKE_armature_splineik_solver_find_root(pchan, data); - OperationKey transforms_key(&ob->id, DEPSNODE_TYPE_BONE, pchan->name, DEG_OPCODE_BONE_READY); - OperationKey solver_key(&ob->id, DEPSNODE_TYPE_EVAL_POSE, rootchan->name, DEG_OPCODE_POSE_SPLINE_IK_SOLVER); - - /* attach owner to IK Solver too - * - assume that owner is always part of chain - * - see notes on direction of rel below... - */ - add_relation(transforms_key, solver_key, DEPSREL_TYPE_TRANSFORM, "Spline IK Solver Owner"); - - /* attach path dependency to solver */ - if (data->tar) { - /* TODO(sergey): For until we'll store partial matricies in the depsgraph, - * we create dependency between target object and pose eval component. - * See IK pose for a bit more information. - */ - // TODO: the bigggest point here is that we need the curve PATH and not just the general geometry... - ComponentKey target_key(&data->tar->id, DEPSNODE_TYPE_GEOMETRY); - ComponentKey pose_key(&ob->id, DEPSNODE_TYPE_EVAL_POSE); - add_relation(target_key, pose_key, DEPSREL_TYPE_TRANSFORM, "[Curve.Path -> Spline IK] DepsRel"); - } - - pchan->flag |= POSE_DONE; - OperationKey final_transforms_key(&ob->id, DEPSNODE_TYPE_BONE, pchan->name, DEG_OPCODE_BONE_DONE); - add_relation(solver_key, final_transforms_key, DEPSREL_TYPE_TRANSFORM, "Spline IK Result"); - - root_map->add_bone(pchan->name, rootchan->name); - - /* Walk to the chain's root */ - //size_t segcount = 0; - int segcount = 0; - - for (bPoseChannel *parchan = pchan->parent; parchan; parchan = parchan->parent) { - /* Make Spline IK solver dependent on this bone's result, - * since it can only run after the standard results - * of the bone are know. Validate links step on the - * bone will ensure that users of this bone only - * grab the result with IK solver results... - */ - if (parchan != pchan) { - OperationKey parent_key(&ob->id, DEPSNODE_TYPE_BONE, parchan->name, DEG_OPCODE_BONE_READY); - add_relation(parent_key, solver_key, DEPSREL_TYPE_TRANSFORM, "Spline IK Solver Update"); - - OperationKey done_key(&ob->id, DEPSNODE_TYPE_BONE, parchan->name, DEG_OPCODE_BONE_DONE); - add_relation(solver_key, done_key, DEPSREL_TYPE_TRANSFORM, "IK Chain Result"); - } - parchan->flag |= POSE_DONE; - - OperationKey final_transforms_key(&ob->id, DEPSNODE_TYPE_BONE, parchan->name, DEG_OPCODE_BONE_DONE); - add_relation(solver_key, final_transforms_key, DEPSREL_TYPE_TRANSFORM, "Spline IK Solver Result"); - - root_map->add_bone(parchan->name, rootchan->name); - - /* continue up chain, until we reach target number of items... */ - segcount++; - if ((segcount == data->chainlen) || (segcount > 255)) break; /* 255 is weak */ - } - - OperationKey flush_key(&ob->id, DEPSNODE_TYPE_EVAL_POSE, DEG_OPCODE_POSE_DONE); - add_relation(solver_key, flush_key, DEPSREL_TYPE_OPERATION, "PoseEval Result-Bone Link"); -} - -/* Pose/Armature Bones Graph */ -void DepsgraphRelationBuilder::build_rig(Scene *scene, Object *ob) -{ - /* Armature-Data */ - bArmature *arm = (bArmature *)ob->data; - - // TODO: selection status? - - /* attach links between pose operations */ - OperationKey init_key(&ob->id, DEPSNODE_TYPE_EVAL_POSE, DEG_OPCODE_POSE_INIT); - OperationKey flush_key(&ob->id, DEPSNODE_TYPE_EVAL_POSE, DEG_OPCODE_POSE_DONE); - - add_relation(init_key, flush_key, DEPSREL_TYPE_COMPONENT_ORDER, "[Pose Init -> Pose Cleanup]"); - - /* Make sure pose is up-to-date with armature updates. */ - OperationKey armature_key(&arm->id, - DEPSNODE_TYPE_PARAMETERS, - DEG_OPCODE_PLACEHOLDER, - "Armature Eval"); - add_relation(armature_key, init_key, DEPSREL_TYPE_COMPONENT_ORDER, "Data dependency"); - - if (needs_animdata_node(&ob->id)) { - ComponentKey animation_key(&ob->id, DEPSNODE_TYPE_ANIMATION); - add_relation(animation_key, init_key, DEPSREL_TYPE_OPERATION, "Rig Animation"); - } - - /* IK Solvers... - * - These require separate processing steps are pose-level - * to be executed between chains of bones (i.e. once the - * base transforms of a bunch of bones is done) - * - * - We build relations for these before the dependencies - * between ops in the same component as it is necessary - * to check whether such bones are in the same IK chain - * (or else we get weird issues with either in-chain - * references, or with bones being parented to IK'd bones) - * - * Unsolved Issues: - * - Care is needed to ensure that multi-headed trees work out the same as in ik-tree building - * - Animated chain-lengths are a problem... - */ - RootPChanMap root_map; - bool pose_depends_on_local_transform = false; - for (bPoseChannel *pchan = (bPoseChannel *)ob->pose->chanbase.first; pchan; pchan = pchan->next) { - for (bConstraint *con = (bConstraint *)pchan->constraints.first; con; con = con->next) { - switch (con->type) { - case CONSTRAINT_TYPE_KINEMATIC: - build_ik_pose(ob, pchan, con, &root_map); - pose_depends_on_local_transform = true; - break; - - case CONSTRAINT_TYPE_SPLINEIK: - build_splineik_pose(ob, pchan, con, &root_map); - pose_depends_on_local_transform = true; - break; - - /* Constraints which needs world's matrix for transform. - * TODO(sergey): More constraints here? - */ - case CONSTRAINT_TYPE_ROTLIKE: - case CONSTRAINT_TYPE_SIZELIKE: - case CONSTRAINT_TYPE_LOCLIKE: - case CONSTRAINT_TYPE_TRANSLIKE: - /* TODO(sergey): Add used space check. */ - pose_depends_on_local_transform = true; - break; - - default: - break; - } - } - } - //root_map.print_debug(); - - if (pose_depends_on_local_transform) { - /* TODO(sergey): Once partial updates are possible use relation between - * object transform and solver itself in it's build function. - */ - ComponentKey pose_key(&ob->id, DEPSNODE_TYPE_EVAL_POSE); - ComponentKey local_transform_key(&ob->id, DEPSNODE_TYPE_TRANSFORM); - add_relation(local_transform_key, pose_key, DEPSREL_TYPE_TRANSFORM, "Local Transforms"); - } - - - /* links between operations for each bone */ - for (bPoseChannel *pchan = (bPoseChannel *)ob->pose->chanbase.first; pchan; pchan = pchan->next) { - OperationKey bone_local_key(&ob->id, DEPSNODE_TYPE_BONE, pchan->name, DEG_OPCODE_BONE_LOCAL); - OperationKey bone_pose_key(&ob->id, DEPSNODE_TYPE_BONE, pchan->name, DEG_OPCODE_BONE_POSE_PARENT); - OperationKey bone_ready_key(&ob->id, DEPSNODE_TYPE_BONE, pchan->name, DEG_OPCODE_BONE_READY); - OperationKey bone_done_key(&ob->id, DEPSNODE_TYPE_BONE, pchan->name, DEG_OPCODE_BONE_DONE); - - pchan->flag &= ~POSE_DONE; - - /* pose init to bone local */ - add_relation(init_key, bone_local_key, DEPSREL_TYPE_OPERATION, "PoseEval Source-Bone Link"); - - /* local to pose parenting operation */ - add_relation(bone_local_key, bone_pose_key, DEPSREL_TYPE_OPERATION, "Bone Local - PoseSpace Link"); - - /* parent relation */ - if (pchan->parent != NULL) { - eDepsOperation_Code parent_key_opcode; - - /* NOTE: this difference in handling allows us to prevent lockups while ensuring correct poses for separate chains */ - if (root_map.has_common_root(pchan->name, pchan->parent->name)) { - parent_key_opcode = DEG_OPCODE_BONE_READY; - } - else { - parent_key_opcode = DEG_OPCODE_BONE_DONE; - } - - OperationKey parent_key(&ob->id, DEPSNODE_TYPE_BONE, pchan->parent->name, parent_key_opcode); - add_relation(parent_key, bone_pose_key, DEPSREL_TYPE_TRANSFORM, "[Parent Bone -> Child Bone]"); - } - - /* constraints */ - if (pchan->constraints.first != NULL) { - /* constraints stack and constraint dependencies */ - build_constraints(scene, &ob->id, DEPSNODE_TYPE_BONE, pchan->name, &pchan->constraints, &root_map); - - /* pose -> constraints */ - OperationKey constraints_key(&ob->id, DEPSNODE_TYPE_BONE, pchan->name, DEG_OPCODE_BONE_CONSTRAINTS); - add_relation(bone_pose_key, constraints_key, DEPSREL_TYPE_OPERATION, "Constraints Stack"); - - /* constraints -> ready */ - // TODO: when constraint stack is exploded, this step should occur before the first IK solver - add_relation(constraints_key, bone_ready_key, DEPSREL_TYPE_OPERATION, "Constraints -> Ready"); - } - else { - /* pose -> ready */ - add_relation(bone_pose_key, bone_ready_key, DEPSREL_TYPE_OPERATION, "Pose -> Ready"); - } - - /* bone ready -> done - * NOTE: For bones without IK, this is all that's needed. - * For IK chains however, an additional rel is created from IK to done, - * with transitive reduction removing this one... - */ - add_relation(bone_ready_key, bone_done_key, DEPSREL_TYPE_OPERATION, "Ready -> Done"); - - /* assume that all bones must be done for the pose to be ready (for deformers) */ - add_relation(bone_done_key, flush_key, DEPSREL_TYPE_OPERATION, "PoseEval Result-Bone Link"); - } -} - -void DepsgraphRelationBuilder::build_proxy_rig(Object *ob) -{ - OperationKey pose_init_key(&ob->id, DEPSNODE_TYPE_EVAL_POSE, DEG_OPCODE_POSE_INIT); - OperationKey pose_done_key(&ob->id, DEPSNODE_TYPE_EVAL_POSE, DEG_OPCODE_POSE_DONE); - for (bPoseChannel *pchan = (bPoseChannel *)ob->pose->chanbase.first; - pchan != NULL; - pchan = pchan->next) - { - OperationKey bone_local_key(&ob->id, DEPSNODE_TYPE_BONE, pchan->name, DEG_OPCODE_BONE_LOCAL); - OperationKey bone_ready_key(&ob->id, DEPSNODE_TYPE_BONE, pchan->name, DEG_OPCODE_BONE_READY); - OperationKey bone_done_key(&ob->id, DEPSNODE_TYPE_BONE, pchan->name, DEG_OPCODE_BONE_DONE); - add_relation(pose_init_key, bone_local_key, DEPSREL_TYPE_OPERATION, "Pose Init -> Bone Local"); - add_relation(bone_local_key, bone_ready_key, DEPSREL_TYPE_OPERATION, "Local -> Ready"); - add_relation(bone_ready_key, bone_done_key, DEPSREL_TYPE_OPERATION, "Ready -> Done"); - add_relation(bone_done_key, pose_done_key, DEPSREL_TYPE_OPERATION, "Bone Done -> Pose Done"); - } -} - /* Shapekeys */ void DepsgraphRelationBuilder::build_shapekeys(ID *obdata, Key *key) { @@ -1790,10 +1317,9 @@ void DepsgraphRelationBuilder::build_obdata_geom(Main *bmain, Scene *scene, Obje /* Modifiers */ if (ob->modifiers.first) { - ModifierData *md; OperationKey prev_mod_key; - for (md = (ModifierData *)ob->modifiers.first; md; md = md->next) { + LINKLIST_FOREACH (ModifierData *, md, &ob->modifiers) { const ModifierTypeInfo *mti = modifierType_getInfo((ModifierType)md->type); OperationKey mod_key(&ob->id, DEPSNODE_TYPE_GEOMETRY, DEG_OPCODE_GEOMETRY_MODIFIER, md->name); @@ -2028,7 +1554,7 @@ void DepsgraphRelationBuilder::build_nodetree(ID *owner, bNodeTree *ntree) "Parameters Eval"); /* nodetree's nodes... */ - for (bNode *bnode = (bNode *)ntree->nodes.first; bnode; bnode = bnode->next) { + LINKLIST_FOREACH (bNode *, bnode, &ntree->nodes) { if (bnode->id) { if (GS(bnode->id->name) == ID_MA) { build_material(owner, (Material *)bnode->id); @@ -2132,4 +1658,21 @@ bool DepsgraphRelationBuilder::needs_animdata_node(ID *id) return false; } +void DepsgraphRelationBuilder::build_cachefile(CacheFile *cache_file) { + /* Animation. */ + build_animdata(&cache_file->id); +} + +void DepsgraphRelationBuilder::build_mask(Mask *mask) +{ + /* Animation. */ + build_animdata(&mask->id); +} + +void DepsgraphRelationBuilder::build_movieclip(MovieClip *clip) +{ + /* Animation. */ + build_animdata(&clip->id); +} + } // namespace DEG diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations.h b/source/blender/depsgraph/intern/builder/deg_builder_relations.h index 8d8ad6772b8..6e8485bee30 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_relations.h +++ b/source/blender/depsgraph/intern/builder/deg_builder_relations.h @@ -47,6 +47,7 @@ struct Base; struct bGPdata; +struct CacheFile; struct ListBase; struct GHash; struct ID; @@ -54,8 +55,10 @@ struct FCurve; struct Group; struct Key; struct Main; +struct Mask; struct Material; struct MTex; +struct MovieClip; struct bNodeTree; struct Object; struct bPoseChannel; @@ -220,6 +223,9 @@ struct DepsgraphRelationBuilder void build_texture_stack(ID *owner, MTex **texture_stack); void build_compositor(Scene *scene); void build_gpencil(ID *owner, bGPdata *gpd); + void build_cachefile(CacheFile *cache_file); + void build_mask(Mask *mask); + void build_movieclip(MovieClip *clip); void add_collision_relations(const OperationKey &key, Scene *scene, Object *ob, Group *group, int layer, bool dupli, const char *name); void add_forcefield_relations(const OperationKey &key, Scene *scene, Object *ob, ParticleSystem *psys, EffectorWeights *eff, bool add_absorption, const char *name); diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations_keys.cc b/source/blender/depsgraph/intern/builder/deg_builder_relations_keys.cc index 7ada04e8f74..feae8bca303 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_relations_keys.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_relations_keys.cc @@ -24,7 +24,7 @@ * ***** END GPL LICENSE BLOCK ***** */ -/** \file blender/depsgraph/intern/builder/deg_builder_relations.cc +/** \file blender/depsgraph/intern/builder/deg_builder_relations_keys.cc * \ingroup depsgraph * * Methods for constructing depsgraph diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations_rig.cc b/source/blender/depsgraph/intern/builder/deg_builder_relations_rig.cc new file mode 100644 index 00000000000..2b4c000f483 --- /dev/null +++ b/source/blender/depsgraph/intern/builder/deg_builder_relations_rig.cc @@ -0,0 +1,455 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2013 Blender Foundation. + * All rights reserved. + * + * Original Author: Joshua Leung + * Contributor(s): Based on original depsgraph.c code - Blender Foundation (2005-2013) + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/depsgraph/intern/builder/deg_builder_relations_rig.cc + * \ingroup depsgraph + * + * Methods for constructing depsgraph + */ + +#include "intern/builder/deg_builder_relations.h" + +#include <stdio.h> +#include <stdlib.h> +#include <cstring> /* required for STREQ later on. */ + +#include "MEM_guardedalloc.h" + +extern "C" { +#include "BLI_blenlib.h" +#include "BLI_utildefines.h" + +#include "DNA_action_types.h" +#include "DNA_anim_types.h" +#include "DNA_armature_types.h" +#include "DNA_constraint_types.h" +#include "DNA_customdata_types.h" +#include "DNA_object_types.h" + +#include "BKE_action.h" +#include "BKE_armature.h" + +#include "DEG_depsgraph.h" +#include "DEG_depsgraph_build.h" +} /* extern "C" */ + +#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 "util/deg_util_foreach.h" + +namespace DEG { + +/* IK Solver Eval Steps */ +void DepsgraphRelationBuilder::build_ik_pose(Object *ob, + bPoseChannel *pchan, + bConstraint *con, + RootPChanMap *root_map) +{ + bKinematicConstraint *data = (bKinematicConstraint *)con->data; + + /* attach owner to IK Solver too + * - assume that owner is always part of chain + * - see notes on direction of rel below... + */ + bPoseChannel *rootchan = BKE_armature_ik_solver_find_root(pchan, data); + OperationKey solver_key(&ob->id, DEPSNODE_TYPE_EVAL_POSE, rootchan->name, DEG_OPCODE_POSE_IK_SOLVER); + + /* IK target */ + // XXX: this should get handled as part of the constraint code + if (data->tar != NULL) { + /* TODO(sergey): For until we'll store partial matricies in the depsgraph, + * we create dependency between target object and pose eval component. + * + * This way we ensuring the whole subtree is updated from scratch without + * need of intermediate matricies. This is an overkill, but good enough for + * testing IK solver. + */ + // FIXME: geometry targets... + ComponentKey pose_key(&ob->id, DEPSNODE_TYPE_EVAL_POSE); + if ((data->tar->type == OB_ARMATURE) && (data->subtarget[0])) { + /* TODO(sergey): This is only for until granular update stores intermediate result. */ + if (data->tar != ob) { + /* different armature - can just read the results */ + ComponentKey target_key(&data->tar->id, DEPSNODE_TYPE_BONE, data->subtarget); + add_relation(target_key, pose_key, DEPSREL_TYPE_TRANSFORM, con->name); + } + else { + /* same armature - we'll use the ready state only, just in case this bone is in the chain we're solving */ + OperationKey target_key(&data->tar->id, DEPSNODE_TYPE_BONE, data->subtarget, DEG_OPCODE_BONE_DONE); + add_relation(target_key, solver_key, DEPSREL_TYPE_TRANSFORM, con->name); + } + } + else if (ELEM(data->tar->type, OB_MESH, OB_LATTICE) && (data->subtarget[0])) { + /* vertex group target */ + /* NOTE: for now, we don't need to represent vertex groups separately... */ + ComponentKey target_key(&data->tar->id, DEPSNODE_TYPE_GEOMETRY); + add_relation(target_key, solver_key, DEPSREL_TYPE_GEOMETRY_EVAL, con->name); + + if (data->tar->type == OB_MESH) { + OperationDepsNode *node2 = find_operation_node(target_key); + if (node2 != NULL) { + node2->customdata_mask |= CD_MASK_MDEFORMVERT; + } + } + } + else { + /* Standard Object Target */ + ComponentKey target_key(&data->tar->id, DEPSNODE_TYPE_TRANSFORM); + add_relation(target_key, pose_key, DEPSREL_TYPE_TRANSFORM, con->name); + } + + if ((data->tar == ob) && (data->subtarget[0])) { + /* Prevent target's constraints from linking to anything from same + * chain that it controls. + */ + root_map->add_bone(data->subtarget, rootchan->name); + } + } + + /* Pole Target */ + // XXX: this should get handled as part of the constraint code + if (data->poletar != NULL) { + if ((data->poletar->type == OB_ARMATURE) && (data->polesubtarget[0])) { + // XXX: same armature issues - ready vs done? + ComponentKey target_key(&data->poletar->id, DEPSNODE_TYPE_BONE, data->polesubtarget); + add_relation(target_key, solver_key, DEPSREL_TYPE_TRANSFORM, con->name); + } + else if (ELEM(data->poletar->type, OB_MESH, OB_LATTICE) && (data->polesubtarget[0])) { + /* vertex group target */ + /* NOTE: for now, we don't need to represent vertex groups separately... */ + ComponentKey target_key(&data->poletar->id, DEPSNODE_TYPE_GEOMETRY); + add_relation(target_key, solver_key, DEPSREL_TYPE_GEOMETRY_EVAL, con->name); + + if (data->poletar->type == OB_MESH) { + OperationDepsNode *node2 = find_operation_node(target_key); + if (node2 != NULL) { + node2->customdata_mask |= CD_MASK_MDEFORMVERT; + } + } + } + else { + ComponentKey target_key(&data->poletar->id, DEPSNODE_TYPE_TRANSFORM); + add_relation(target_key, solver_key, DEPSREL_TYPE_TRANSFORM, con->name); + } + } + + DEG_DEBUG_PRINTF("\nStarting IK Build: pchan = %s, target = (%s, %s), segcount = %d\n", + pchan->name, data->tar->id.name, data->subtarget, data->rootbone); + + bPoseChannel *parchan = pchan; + /* exclude tip from chain? */ + if (!(data->flag & CONSTRAINT_IK_TIP)) { + OperationKey tip_transforms_key(&ob->id, DEPSNODE_TYPE_BONE, + parchan->name, DEG_OPCODE_BONE_LOCAL); + add_relation(solver_key, tip_transforms_key, + DEPSREL_TYPE_TRANSFORM, "IK Solver Result"); + parchan = pchan->parent; + } + + root_map->add_bone(parchan->name, rootchan->name); + + OperationKey parchan_transforms_key(&ob->id, DEPSNODE_TYPE_BONE, + parchan->name, DEG_OPCODE_BONE_READY); + add_relation(parchan_transforms_key, solver_key, + DEPSREL_TYPE_TRANSFORM, "IK Solver Owner"); + + /* Walk to the chain's root */ + //size_t segcount = 0; + int segcount = 0; + + while (parchan) { + /* Make IK-solver dependent on this bone's result, + * since it can only run after the standard results + * of the bone are know. Validate links step on the + * bone will ensure that users of this bone only + * grab the result with IK solver results... + */ + if (parchan != pchan) { + OperationKey parent_key(&ob->id, DEPSNODE_TYPE_BONE, parchan->name, DEG_OPCODE_BONE_READY); + add_relation(parent_key, solver_key, DEPSREL_TYPE_TRANSFORM, "IK Chain Parent"); + + OperationKey done_key(&ob->id, DEPSNODE_TYPE_BONE, parchan->name, DEG_OPCODE_BONE_DONE); + add_relation(solver_key, done_key, DEPSREL_TYPE_TRANSFORM, "IK Chain Result"); + } + else { + OperationKey final_transforms_key(&ob->id, DEPSNODE_TYPE_BONE, parchan->name, DEG_OPCODE_BONE_DONE); + add_relation(solver_key, final_transforms_key, DEPSREL_TYPE_TRANSFORM, "IK Solver Result"); + } + parchan->flag |= POSE_DONE; + + + root_map->add_bone(parchan->name, rootchan->name); + + /* continue up chain, until we reach target number of items... */ + DEG_DEBUG_PRINTF(" %d = %s\n", segcount, parchan->name); + segcount++; + if ((segcount == data->rootbone) || (segcount > 255)) break; /* 255 is weak */ + + parchan = parchan->parent; + } + + OperationKey flush_key(&ob->id, DEPSNODE_TYPE_EVAL_POSE, DEG_OPCODE_POSE_DONE); + add_relation(solver_key, flush_key, DEPSREL_TYPE_OPERATION, "PoseEval Result-Bone Link"); +} + +/* Spline IK Eval Steps */ +void DepsgraphRelationBuilder::build_splineik_pose(Object *ob, + bPoseChannel *pchan, + bConstraint *con, + RootPChanMap *root_map) +{ + bSplineIKConstraint *data = (bSplineIKConstraint *)con->data; + bPoseChannel *rootchan = BKE_armature_splineik_solver_find_root(pchan, data); + OperationKey transforms_key(&ob->id, DEPSNODE_TYPE_BONE, pchan->name, DEG_OPCODE_BONE_READY); + OperationKey solver_key(&ob->id, DEPSNODE_TYPE_EVAL_POSE, rootchan->name, DEG_OPCODE_POSE_SPLINE_IK_SOLVER); + + /* attach owner to IK Solver too + * - assume that owner is always part of chain + * - see notes on direction of rel below... + */ + add_relation(transforms_key, solver_key, DEPSREL_TYPE_TRANSFORM, "Spline IK Solver Owner"); + + /* attach path dependency to solver */ + if (data->tar) { + /* TODO(sergey): For until we'll store partial matricies in the depsgraph, + * we create dependency between target object and pose eval component. + * See IK pose for a bit more information. + */ + // TODO: the bigggest point here is that we need the curve PATH and not just the general geometry... + ComponentKey target_key(&data->tar->id, DEPSNODE_TYPE_GEOMETRY); + ComponentKey pose_key(&ob->id, DEPSNODE_TYPE_EVAL_POSE); + add_relation(target_key, pose_key, DEPSREL_TYPE_TRANSFORM, "[Curve.Path -> Spline IK] DepsRel"); + } + + pchan->flag |= POSE_DONE; + OperationKey final_transforms_key(&ob->id, DEPSNODE_TYPE_BONE, pchan->name, DEG_OPCODE_BONE_DONE); + add_relation(solver_key, final_transforms_key, DEPSREL_TYPE_TRANSFORM, "Spline IK Result"); + + root_map->add_bone(pchan->name, rootchan->name); + + /* Walk to the chain's root */ + //size_t segcount = 0; + int segcount = 0; + + for (bPoseChannel *parchan = pchan->parent; parchan; parchan = parchan->parent) { + /* Make Spline IK solver dependent on this bone's result, + * since it can only run after the standard results + * of the bone are know. Validate links step on the + * bone will ensure that users of this bone only + * grab the result with IK solver results... + */ + if (parchan != pchan) { + OperationKey parent_key(&ob->id, DEPSNODE_TYPE_BONE, parchan->name, DEG_OPCODE_BONE_READY); + add_relation(parent_key, solver_key, DEPSREL_TYPE_TRANSFORM, "Spline IK Solver Update"); + + OperationKey done_key(&ob->id, DEPSNODE_TYPE_BONE, parchan->name, DEG_OPCODE_BONE_DONE); + add_relation(solver_key, done_key, DEPSREL_TYPE_TRANSFORM, "IK Chain Result"); + } + parchan->flag |= POSE_DONE; + + OperationKey final_transforms_key(&ob->id, DEPSNODE_TYPE_BONE, parchan->name, DEG_OPCODE_BONE_DONE); + add_relation(solver_key, final_transforms_key, DEPSREL_TYPE_TRANSFORM, "Spline IK Solver Result"); + + root_map->add_bone(parchan->name, rootchan->name); + + /* continue up chain, until we reach target number of items... */ + segcount++; + if ((segcount == data->chainlen) || (segcount > 255)) break; /* 255 is weak */ + } + + OperationKey flush_key(&ob->id, DEPSNODE_TYPE_EVAL_POSE, DEG_OPCODE_POSE_DONE); + add_relation(solver_key, flush_key, DEPSREL_TYPE_OPERATION, "PoseEval Result-Bone Link"); +} + +/* Pose/Armature Bones Graph */ +void DepsgraphRelationBuilder::build_rig(Scene *scene, Object *ob) +{ + /* Armature-Data */ + bArmature *arm = (bArmature *)ob->data; + + // TODO: selection status? + + /* attach links between pose operations */ + OperationKey init_key(&ob->id, DEPSNODE_TYPE_EVAL_POSE, DEG_OPCODE_POSE_INIT); + OperationKey flush_key(&ob->id, DEPSNODE_TYPE_EVAL_POSE, DEG_OPCODE_POSE_DONE); + + add_relation(init_key, flush_key, DEPSREL_TYPE_COMPONENT_ORDER, "[Pose Init -> Pose Cleanup]"); + + /* Make sure pose is up-to-date with armature updates. */ + OperationKey armature_key(&arm->id, + DEPSNODE_TYPE_PARAMETERS, + DEG_OPCODE_PLACEHOLDER, + "Armature Eval"); + add_relation(armature_key, init_key, DEPSREL_TYPE_COMPONENT_ORDER, "Data dependency"); + + if (needs_animdata_node(&ob->id)) { + ComponentKey animation_key(&ob->id, DEPSNODE_TYPE_ANIMATION); + add_relation(animation_key, init_key, DEPSREL_TYPE_OPERATION, "Rig Animation"); + } + + /* IK Solvers... + * - These require separate processing steps are pose-level + * to be executed between chains of bones (i.e. once the + * base transforms of a bunch of bones is done) + * + * - We build relations for these before the dependencies + * between ops in the same component as it is necessary + * to check whether such bones are in the same IK chain + * (or else we get weird issues with either in-chain + * references, or with bones being parented to IK'd bones) + * + * Unsolved Issues: + * - Care is needed to ensure that multi-headed trees work out the same as in ik-tree building + * - Animated chain-lengths are a problem... + */ + RootPChanMap root_map; + bool pose_depends_on_local_transform = false; + LINKLIST_FOREACH (bPoseChannel *, pchan, &ob->pose->chanbase) { + LINKLIST_FOREACH (bConstraint *, con, &pchan->constraints) { + switch (con->type) { + case CONSTRAINT_TYPE_KINEMATIC: + build_ik_pose(ob, pchan, con, &root_map); + pose_depends_on_local_transform = true; + break; + + case CONSTRAINT_TYPE_SPLINEIK: + build_splineik_pose(ob, pchan, con, &root_map); + pose_depends_on_local_transform = true; + break; + + /* Constraints which needs world's matrix for transform. + * TODO(sergey): More constraints here? + */ + case CONSTRAINT_TYPE_ROTLIKE: + case CONSTRAINT_TYPE_SIZELIKE: + case CONSTRAINT_TYPE_LOCLIKE: + case CONSTRAINT_TYPE_TRANSLIKE: + /* TODO(sergey): Add used space check. */ + pose_depends_on_local_transform = true; + break; + + default: + break; + } + } + } + //root_map.print_debug(); + + if (pose_depends_on_local_transform) { + /* TODO(sergey): Once partial updates are possible use relation between + * object transform and solver itself in it's build function. + */ + ComponentKey pose_key(&ob->id, DEPSNODE_TYPE_EVAL_POSE); + ComponentKey local_transform_key(&ob->id, DEPSNODE_TYPE_TRANSFORM); + add_relation(local_transform_key, pose_key, DEPSREL_TYPE_TRANSFORM, "Local Transforms"); + } + + + /* links between operations for each bone */ + LINKLIST_FOREACH (bPoseChannel *, pchan, &ob->pose->chanbase) { + OperationKey bone_local_key(&ob->id, DEPSNODE_TYPE_BONE, pchan->name, DEG_OPCODE_BONE_LOCAL); + OperationKey bone_pose_key(&ob->id, DEPSNODE_TYPE_BONE, pchan->name, DEG_OPCODE_BONE_POSE_PARENT); + OperationKey bone_ready_key(&ob->id, DEPSNODE_TYPE_BONE, pchan->name, DEG_OPCODE_BONE_READY); + OperationKey bone_done_key(&ob->id, DEPSNODE_TYPE_BONE, pchan->name, DEG_OPCODE_BONE_DONE); + + pchan->flag &= ~POSE_DONE; + + /* pose init to bone local */ + add_relation(init_key, bone_local_key, DEPSREL_TYPE_OPERATION, "PoseEval Source-Bone Link"); + + /* local to pose parenting operation */ + add_relation(bone_local_key, bone_pose_key, DEPSREL_TYPE_OPERATION, "Bone Local - PoseSpace Link"); + + /* parent relation */ + if (pchan->parent != NULL) { + eDepsOperation_Code parent_key_opcode; + + /* NOTE: this difference in handling allows us to prevent lockups while ensuring correct poses for separate chains */ + if (root_map.has_common_root(pchan->name, pchan->parent->name)) { + parent_key_opcode = DEG_OPCODE_BONE_READY; + } + else { + parent_key_opcode = DEG_OPCODE_BONE_DONE; + } + + OperationKey parent_key(&ob->id, DEPSNODE_TYPE_BONE, pchan->parent->name, parent_key_opcode); + add_relation(parent_key, bone_pose_key, DEPSREL_TYPE_TRANSFORM, "[Parent Bone -> Child Bone]"); + } + + /* constraints */ + if (pchan->constraints.first != NULL) { + /* constraints stack and constraint dependencies */ + build_constraints(scene, &ob->id, DEPSNODE_TYPE_BONE, pchan->name, &pchan->constraints, &root_map); + + /* pose -> constraints */ + OperationKey constraints_key(&ob->id, DEPSNODE_TYPE_BONE, pchan->name, DEG_OPCODE_BONE_CONSTRAINTS); + add_relation(bone_pose_key, constraints_key, DEPSREL_TYPE_OPERATION, "Constraints Stack"); + + /* constraints -> ready */ + // TODO: when constraint stack is exploded, this step should occur before the first IK solver + add_relation(constraints_key, bone_ready_key, DEPSREL_TYPE_OPERATION, "Constraints -> Ready"); + } + else { + /* pose -> ready */ + add_relation(bone_pose_key, bone_ready_key, DEPSREL_TYPE_OPERATION, "Pose -> Ready"); + } + + /* bone ready -> done + * NOTE: For bones without IK, this is all that's needed. + * For IK chains however, an additional rel is created from IK to done, + * with transitive reduction removing this one... + */ + add_relation(bone_ready_key, bone_done_key, DEPSREL_TYPE_OPERATION, "Ready -> Done"); + + /* assume that all bones must be done for the pose to be ready (for deformers) */ + add_relation(bone_done_key, flush_key, DEPSREL_TYPE_OPERATION, "PoseEval Result-Bone Link"); + } +} + +void DepsgraphRelationBuilder::build_proxy_rig(Object *ob) +{ + OperationKey pose_init_key(&ob->id, DEPSNODE_TYPE_EVAL_POSE, DEG_OPCODE_POSE_INIT); + OperationKey pose_done_key(&ob->id, DEPSNODE_TYPE_EVAL_POSE, DEG_OPCODE_POSE_DONE); + LINKLIST_FOREACH (bPoseChannel *, pchan, &ob->pose->chanbase) { + OperationKey bone_local_key(&ob->id, DEPSNODE_TYPE_BONE, pchan->name, DEG_OPCODE_BONE_LOCAL); + OperationKey bone_ready_key(&ob->id, DEPSNODE_TYPE_BONE, pchan->name, DEG_OPCODE_BONE_READY); + OperationKey bone_done_key(&ob->id, DEPSNODE_TYPE_BONE, pchan->name, DEG_OPCODE_BONE_DONE); + add_relation(pose_init_key, bone_local_key, DEPSREL_TYPE_OPERATION, "Pose Init -> Bone Local"); + add_relation(bone_local_key, bone_ready_key, DEPSREL_TYPE_OPERATION, "Local -> Ready"); + add_relation(bone_ready_key, bone_done_key, DEPSREL_TYPE_OPERATION, "Ready -> Done"); + add_relation(bone_done_key, pose_done_key, DEPSREL_TYPE_OPERATION, "Bone Done -> Pose Done"); + } +} + +} // namespace DEG diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations_scene.cc b/source/blender/depsgraph/intern/builder/deg_builder_relations_scene.cc new file mode 100644 index 00000000000..6b51a957da0 --- /dev/null +++ b/source/blender/depsgraph/intern/builder/deg_builder_relations_scene.cc @@ -0,0 +1,162 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2013 Blender Foundation. + * All rights reserved. + * + * Original Author: Joshua Leung + * Contributor(s): Based on original depsgraph.c code - Blender Foundation (2005-2013) + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/depsgraph/intern/builder/deg_builder_relations_scene.cc + * \ingroup depsgraph + * + * Methods for constructing depsgraph + */ + +#include "intern/builder/deg_builder_relations.h" + +#include <stdio.h> +#include <stdlib.h> +#include <cstring> /* required for STREQ later on. */ + +#include "MEM_guardedalloc.h" + +extern "C" { +#include "BLI_blenlib.h" +#include "BLI_utildefines.h" + +#include "DNA_node_types.h" +#include "DNA_object_types.h" +#include "DNA_scene_types.h" + +#include "BKE_main.h" +#include "BKE_node.h" + +#include "DEG_depsgraph.h" +#include "DEG_depsgraph_build.h" +} /* extern "C" */ + +#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 "util/deg_util_foreach.h" + +namespace DEG { + +void DepsgraphRelationBuilder::build_scene(Main *bmain, Scene *scene) +{ + /* LIB_TAG_DOIT is used to indicate whether node for given ID was already + * created or not. + */ + BKE_main_id_tag_all(bmain, LIB_TAG_DOIT, false); + /* XXX nested node trees are not included in tag-clearing above, + * so we need to do this manually. + */ + FOREACH_NODETREE(bmain, nodetree, id) { + if (id != (ID *)nodetree) + nodetree->id.tag &= ~LIB_TAG_DOIT; + } FOREACH_NODETREE_END + + if (scene->set) { + // TODO: link set to scene, especially our timesource... + } + + /* scene objects */ + LINKLIST_FOREACH (Base *, base, &scene->base) { + Object *ob = base->object; + + /* object itself */ + build_object(bmain, scene, ob); + + /* object that this is a proxy for */ + if (ob->proxy) { + ob->proxy->proxy_from = ob; + build_object(bmain, scene, ob->proxy); + /* TODO(sergey): This is an inverted relation, matches old depsgraph + * behavior and need to be investigated if it still need to be inverted. + */ + ComponentKey ob_pose_key(&ob->id, DEPSNODE_TYPE_EVAL_POSE); + ComponentKey proxy_pose_key(&ob->proxy->id, DEPSNODE_TYPE_EVAL_POSE); + add_relation(ob_pose_key, proxy_pose_key, DEPSREL_TYPE_TRANSFORM, "Proxy"); + } + + /* Object dupligroup. */ + if (ob->dup_group) { + build_group(bmain, scene, ob, ob->dup_group); + } + } + + /* rigidbody */ + if (scene->rigidbody_world) { + build_rigidbody(scene); + } + + /* scene's animation and drivers */ + if (scene->adt) { + build_animdata(&scene->id); + } + + /* world */ + if (scene->world) { + build_world(scene->world); + } + + /* compo nodes */ + if (scene->nodetree) { + build_compositor(scene); + } + + /* grease pencil */ + if (scene->gpd) { + build_gpencil(&scene->id, scene->gpd); + } + + /* Masks. */ + LINKLIST_FOREACH (Mask *, mask, &bmain->mask) { + build_mask(mask); + } + + /* Movie clips. */ + LINKLIST_FOREACH (MovieClip *, clip, &bmain->movieclip) { + build_movieclip(clip); + } + + 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; + } + } +} + +} // namespace DEG diff --git a/source/blender/depsgraph/intern/depsgraph.cc b/source/blender/depsgraph/intern/depsgraph.cc index 3502267d9ca..9a4a35a5a35 100644 --- a/source/blender/depsgraph/intern/depsgraph.cc +++ b/source/blender/depsgraph/intern/depsgraph.cc @@ -371,8 +371,7 @@ DepsRelation *Depsgraph::add_new_relation(OperationDepsNode *from, if (comp_node->type == DEPSNODE_TYPE_GEOMETRY) { IDDepsNode *id_to = to->owner->owner; IDDepsNode *id_from = from->owner->owner; - Object *object_to = (Object *)id_to->id; - if (id_to != id_from && (object_to->recalc & OB_RECALC_ALL)) { + if (id_to != id_from && (id_to->id->tag & LIB_TAG_ID_RECALC_ALL)) { if ((id_from->eval_flags & DAG_EVAL_NEED_CPU) == 0) { id_from->tag_update(this); id_from->eval_flags |= DAG_EVAL_NEED_CPU; diff --git a/source/blender/depsgraph/util/deg_util_foreach.h b/source/blender/depsgraph/util/deg_util_foreach.h index 14cf4fc11ed..87d37168d51 100644 --- a/source/blender/depsgraph/util/deg_util_foreach.h +++ b/source/blender/depsgraph/util/deg_util_foreach.h @@ -66,3 +66,8 @@ #define GSET_FOREACH_END() \ } \ } while(0) + +#define LINKLIST_FOREACH(type, var, list) \ + for (type var = (type)((list)->first); \ + var != NULL; \ + var = (type)(((Link*)(var))->next)) diff --git a/source/blender/editors/gpencil/gpencil_edit.c b/source/blender/editors/gpencil/gpencil_edit.c index 12d837dfb29..15f65b394a9 100644 --- a/source/blender/editors/gpencil/gpencil_edit.c +++ b/source/blender/editors/gpencil/gpencil_edit.c @@ -96,7 +96,11 @@ static int gpencil_editmode_toggle_exec(bContext *C, wmOperator *UNUSED(op)) /* Just toggle editmode flag... */ gpd->flag ^= GP_DATA_STROKE_EDITMODE; - + /* recalculate parent matrix */ + if (gpd->flag & GP_DATA_STROKE_EDITMODE) { + ED_gpencil_reset_layers_parent(gpd); + } + WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | ND_GPENCIL_EDITMODE, NULL); WM_event_add_notifier(C, NC_SCENE | ND_MODE, NULL); diff --git a/source/blender/editors/gpencil/gpencil_utils.c b/source/blender/editors/gpencil/gpencil_utils.c index 564ba639983..8073b13ba10 100644 --- a/source/blender/editors/gpencil/gpencil_utils.c +++ b/source/blender/editors/gpencil/gpencil_utils.c @@ -997,6 +997,46 @@ void ED_gpencil_parent_location(bGPDlayer *gpl, float diff_mat[4][4]) } } +/* reset parent matrix for all layers */ +void ED_gpencil_reset_layers_parent(bGPdata *gpd) +{ + bGPDspoint *pt; + int i; + float diff_mat[4][4]; + float cur_mat[4][4]; + + for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) { + if (gpl->parent != NULL) { + /* calculate new matrix */ + if ((gpl->partype == PAROBJECT) || (gpl->partype == PARSKEL)) { + invert_m4_m4(cur_mat, gpl->parent->obmat); + } + else if (gpl->partype == PARBONE) { + bPoseChannel *pchan = BKE_pose_channel_find_name(gpl->parent->pose, gpl->parsubstr); + if (pchan) { + float tmp_mat[4][4]; + mul_m4_m4m4(tmp_mat, gpl->parent->obmat, pchan->pose_mat); + invert_m4_m4(cur_mat, tmp_mat); + } + } + + /* only redo if any change */ + if (!equals_m4m4(gpl->inverse, cur_mat)) { + /* first apply current transformation to all strokes */ + ED_gpencil_parent_location(gpl, diff_mat); + for (bGPDframe *gpf = gpl->frames.first; gpf; gpf = gpf->next) { + for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) { + for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) { + mul_m4_v3(diff_mat, &pt->x); + } + } + } + /* set new parent matrix */ + copy_m4_m4(gpl->inverse, cur_mat); + } + } + } +} /* ******************************************************** */ bool ED_gpencil_stroke_minmax( const bGPDstroke *gps, const bool use_select, diff --git a/source/blender/editors/include/ED_gpencil.h b/source/blender/editors/include/ED_gpencil.h index bc93b5622cb..74d9ad0886d 100644 --- a/source/blender/editors/include/ED_gpencil.h +++ b/source/blender/editors/include/ED_gpencil.h @@ -185,6 +185,8 @@ int ED_undo_gpencil_step(struct bContext *C, int step, const char *name); /* get difference matrix using parent */ void ED_gpencil_parent_location(struct bGPDlayer *gpl, float diff_mat[4][4]); +/* reset parent matrix for all layers */ +void ED_gpencil_reset_layers_parent(struct bGPdata *gpd); #endif /* __ED_GPENCIL_H__ */ diff --git a/source/blender/editors/interface/interface_anim.c b/source/blender/editors/interface/interface_anim.c index 991cd54fecf..5da294302e9 100644 --- a/source/blender/editors/interface/interface_anim.c +++ b/source/blender/editors/interface/interface_anim.c @@ -99,6 +99,10 @@ void ui_but_anim_flag(uiBut *but, float cfra) } } +/** + * \a str can be NULL to only perform check if \a but has an expression at all. + * \return if button has an expression. + */ bool ui_but_anim_expression_get(uiBut *but, char *str, size_t maxlen) { FCurve *fcu; @@ -111,7 +115,9 @@ bool ui_but_anim_expression_get(uiBut *but, char *str, size_t maxlen) driver = fcu->driver; if (driver && driver->type == DRIVER_TYPE_PYTHON) { - BLI_strncpy(str, driver->expression, maxlen); + if (str) { + BLI_strncpy(str, driver->expression, maxlen); + } return true; } } diff --git a/source/blender/editors/interface/interface_handlers.c b/source/blender/editors/interface/interface_handlers.c index f3eeadb6604..fc511d61e2b 100644 --- a/source/blender/editors/interface/interface_handlers.c +++ b/source/blender/editors/interface/interface_handlers.c @@ -3067,7 +3067,7 @@ static void ui_textedit_begin(bContext *C, uiBut *but, uiHandleButtonData *data) data->str = ui_but_string_get_dynamic(but, &data->maxlen); } - if (ui_but_is_float(but) && !ui_but_is_unit(but)) { + if (ui_but_is_float(but) && !ui_but_is_unit(but) && !ui_but_anim_expression_get(but, NULL, 0)) { BLI_str_rstrip_float_zero(data->str, '\0'); } diff --git a/source/blender/editors/sculpt_paint/paint_image_2d.c b/source/blender/editors/sculpt_paint/paint_image_2d.c index 9474a46d716..4f93c12385d 100644 --- a/source/blender/editors/sculpt_paint/paint_image_2d.c +++ b/source/blender/editors/sculpt_paint/paint_image_2d.c @@ -1489,7 +1489,8 @@ void paint_2d_bucket_fill( float image_init[2]; int minx = ibuf->x, miny = ibuf->y, maxx = 0, maxy = 0; float pixel_color[4]; - float threshold_sq = br->fill_threshold * br->fill_threshold; + /* We are comparing to sum of three squared values (assumed in range [0,1]), so need to multiply... */ + float threshold_sq = br->fill_threshold * br->fill_threshold * 3; UI_view2d_region_to_view(s->v2d, mouse_init[0], mouse_init[1], &image_init[0], &image_init[1]); diff --git a/source/blender/editors/space_node/space_node.c b/source/blender/editors/space_node/space_node.c index 4ef703c8994..bbdf6feef01 100644 --- a/source/blender/editors/space_node/space_node.c +++ b/source/blender/editors/space_node/space_node.c @@ -855,6 +855,42 @@ static void node_id_remap(ScrArea *UNUSED(sa), SpaceLink *slink, ID *old_id, ID id_us_plus(new_id); } } + else if (GS(old_id->name) == ID_NT) { + bNodeTreePath *path, *path_next; + + for (path = snode->treepath.first; path; path = path->next) { + if ((ID *)path->nodetree == old_id) { + path->nodetree = (bNodeTree *)new_id; + id_us_min(old_id); + id_us_plus(new_id); + } + if (path == snode->treepath.first) { + /* first nodetree in path is same as snode->nodetree */ + snode->nodetree = path->nodetree; + } + if (path->nodetree == NULL) { + break; + } + } + + /* remaining path entries are invalid, remove */ + for (; path; path = path_next) { + path_next = path->next; + + BLI_remlink(&snode->treepath, path); + MEM_freeN(path); + } + + /* edittree is just the last in the path, + * set this directly since the path may have been shortened above */ + if (snode->treepath.last) { + path = snode->treepath.last; + snode->edittree = path->nodetree; + } + else { + snode->edittree = NULL; + } + } } /* only called once, from space/spacetypes.c */ diff --git a/source/blender/editors/space_outliner/outliner_tree.c b/source/blender/editors/space_outliner/outliner_tree.c index 015988efc42..20f7ca4db16 100644 --- a/source/blender/editors/space_outliner/outliner_tree.c +++ b/source/blender/editors/space_outliner/outliner_tree.c @@ -1108,8 +1108,12 @@ static TreeElement *outliner_add_element(SpaceOops *soops, ListBase *lb, void *i tselem->flag &= ~TSE_CLOSED; if (TSELEM_OPEN(tselem, soops)) { - for (a = 0; a < tot; a++) - outliner_add_element(soops, &te->subtree, (void *)ptr, te, TSE_RNA_PROPERTY, a); + for (a = 0; a < tot; a++) { + RNA_property_collection_lookup_int(ptr, iterprop, a, &propptr); + if (!(RNA_property_flag(propptr.data) & PROP_HIDDEN)) { + outliner_add_element(soops, &te->subtree, (void *)ptr, te, TSE_RNA_PROPERTY, a); + } + } } else if (tot) te->flag |= TE_LAZY_CLOSED; diff --git a/source/blender/editors/space_view3d/drawobject.c b/source/blender/editors/space_view3d/drawobject.c index dd282c427f6..90d33dc5995 100644 --- a/source/blender/editors/space_view3d/drawobject.c +++ b/source/blender/editors/space_view3d/drawobject.c @@ -631,10 +631,20 @@ void drawaxes(const float viewmat_local[4][4], float size, char drawtype) /* Function to draw an Image on an empty Object */ -static void draw_empty_image(Object *ob, const short dflag, const unsigned char ob_wire_col[4]) +static void draw_empty_image(Object *ob, const short dflag, const unsigned char ob_wire_col[4], StereoViews sview) { Image *ima = ob->data; - ImBuf *ibuf = BKE_image_acquire_ibuf(ima, ob->iuser, NULL); + ImBuf *ibuf; + ImageUser iuser = *ob->iuser; + + /* Support multi-view */ + if (ima && (sview == STEREO_RIGHT_ID)) { + iuser.multiview_eye = sview; + iuser.flag |= IMA_SHOW_STEREO; + BKE_image_multiview_index(ima, &iuser); + } + + ibuf = BKE_image_acquire_ibuf(ima, &iuser, NULL); if (ibuf && (ibuf->rect == NULL) && (ibuf->rect_float != NULL)) { IMB_rect_from_float(ibuf); @@ -7708,7 +7718,7 @@ void draw_object(Scene *scene, ARegion *ar, View3D *v3d, Base *base, const short case OB_EMPTY: if (!render_override) { if (ob->empty_drawtype == OB_EMPTY_IMAGE) { - draw_empty_image(ob, dflag, ob_wire_col); + draw_empty_image(ob, dflag, ob_wire_col, v3d->multiview_eye); } else { drawaxes(rv3d->viewmatob, ob->empty_drawsize, ob->empty_drawtype); @@ -8488,7 +8498,7 @@ void draw_object_instance(Scene *scene, View3D *v3d, RegionView3D *rv3d, Object case OB_EMPTY: if (ob->empty_drawtype == OB_EMPTY_IMAGE) { /* CONSTCOLOR == no wire outline */ - draw_empty_image(ob, DRAW_CONSTCOLOR, NULL); + draw_empty_image(ob, DRAW_CONSTCOLOR, NULL, v3d->multiview_eye); } else { drawaxes(rv3d->viewmatob, ob->empty_drawsize, ob->empty_drawtype); diff --git a/source/blender/makesdna/DNA_userdef_types.h b/source/blender/makesdna/DNA_userdef_types.h index e018b66dd60..0ad4482708f 100644 --- a/source/blender/makesdna/DNA_userdef_types.h +++ b/source/blender/makesdna/DNA_userdef_types.h @@ -867,14 +867,6 @@ typedef enum eNdof_Flag { #define NDOF_PIXELS_PER_SECOND 600.0f -/* compute_device_type */ -typedef enum eCompute_Device_Type { - USER_COMPUTE_DEVICE_NONE = 0, - USER_COMPUTE_DEVICE_OPENCL = 1, - USER_COMPUTE_DEVICE_CUDA = 2, -} eCompute_Device_Type; - - typedef enum eMultiSample_Type { USER_MULTISAMPLE_NONE = 0, USER_MULTISAMPLE_2 = 2, diff --git a/source/blender/makesrna/intern/makesrna.c b/source/blender/makesrna/intern/makesrna.c index 569c1ee5f3f..309d39a379f 100644 --- a/source/blender/makesrna/intern/makesrna.c +++ b/source/blender/makesrna/intern/makesrna.c @@ -1536,7 +1536,11 @@ static void rna_def_property_funcs(FILE *f, StructRNA *srna, PropertyDefRNA *dp) const char *nextfunc = (const char *)cprop->next; const char *item_type = (const char *)cprop->item_type; - if (dp->dnatype && STREQ(dp->dnatype, "ListBase")) { + if (cprop->length) { + /* always generate if we have a manual implementation */ + cprop->length = (void *)rna_def_property_length_func(f, srna, prop, dp, (const char *)cprop->length); + } + else if (dp->dnatype && STREQ(dp->dnatype, "ListBase")) { /* pass */ } else if (dp->dnalengthname || dp->dnalengthfixed) { diff --git a/source/blender/makesrna/intern/rna_ID.c b/source/blender/makesrna/intern/rna_ID.c index 5174c957834..87fb45a4419 100644 --- a/source/blender/makesrna/intern/rna_ID.c +++ b/source/blender/makesrna/intern/rna_ID.c @@ -1018,9 +1018,9 @@ static void rna_def_ID(BlenderRNA *brna) RNA_def_function_ui_description(func, "Make this datablock local, return local one " "(may be a copy of the original, in case it is also indirectly used)"); RNA_def_function_flag(func, FUNC_USE_MAIN); - RNA_def_boolean(func, "clear_proxy", true, "", - "Whether to clear proxies (the default behavior); can cause proxies to be duplicated" - " when still referred to from another library"); + parm = RNA_def_boolean(func, "clear_proxy", true, "", + "Whether to clear proxies (the default behavior, " + "note that if object has to be duplicated to be made local, proxies are always cleared)"); RNA_def_property_flag(parm, PROP_PYFUNC_OPTIONAL); parm = RNA_def_pointer(func, "id", "ID", "", "This ID, or the new ID if it was copied"); RNA_def_function_return(func, parm); diff --git a/source/blender/makesrna/intern/rna_main.c b/source/blender/makesrna/intern/rna_main.c index d432f086dba..94687b6fd46 100644 --- a/source/blender/makesrna/intern/rna_main.c +++ b/source/blender/makesrna/intern/rna_main.c @@ -399,7 +399,7 @@ void RNA_def_main(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Use Autopack", "Automatically pack all external data into .blend file"); prop = RNA_def_int_vector(srna, "version", 3, NULL, 0, INT_MAX, - "Version", "Version of the blender the .blend was saved with", 0, INT_MAX); + "Version", "Version of Blender the .blend was saved with", 0, INT_MAX); RNA_def_property_int_funcs(prop, "rna_Main_version_get", NULL, NULL); RNA_def_property_clear_flag(prop, PROP_EDITABLE); RNA_def_property_flag(prop, PROP_THICK_WRAP); diff --git a/source/blender/makesrna/intern/rna_userdef.c b/source/blender/makesrna/intern/rna_userdef.c index 10807c32b91..ffdc5bb0592 100644 --- a/source/blender/makesrna/intern/rna_userdef.c +++ b/source/blender/makesrna/intern/rna_userdef.c @@ -124,6 +124,14 @@ static EnumPropertyItem rna_enum_language_default_items[] = { #endif +static void rna_userdef_version_get(PointerRNA *ptr, int *value) +{ + UserDef *userdef = (UserDef *)ptr->data; + value[0] = userdef->versionfile / 100; + value[1] = userdef->versionfile % 100; + value[2] = userdef->subversionfile; +} + static void rna_userdef_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *UNUSED(ptr)) { WM_main_add_notifier(NC_WINDOW, NULL); @@ -4194,6 +4202,14 @@ static void rna_def_userdef_system(BlenderRNA *brna) RNA_def_property_ui_text(prop, "OpenSubdiv Compute Type", "Type of computer back-end used with OpenSubdiv"); RNA_def_property_update(prop, NC_SPACE | ND_SPACE_PROPERTIES, "rna_userdef_opensubdiv_update"); #endif + +#ifdef WITH_CYCLES + prop = RNA_def_property(srna, "legacy_compute_device_type", PROP_INT, PROP_NONE); + RNA_def_property_int_sdna(prop, NULL, "compute_device_type"); + RNA_def_property_clear_flag(prop, PROP_EDITABLE); + RNA_def_property_flag(prop, PROP_HIDDEN); + RNA_def_property_ui_text(prop, "Legacy Compute Device Type", "For backwards compatibility only"); +#endif } static void rna_def_userdef_input(BlenderRNA *brna) @@ -4711,6 +4727,12 @@ void RNA_def_userdef(BlenderRNA *brna) RNA_def_property_pointer_funcs(prop, "rna_UserDef_system_get", NULL, NULL, NULL); RNA_def_property_ui_text(prop, "System & OpenGL", "Graphics driver and operating system settings"); + prop = RNA_def_int_vector(srna, "version", 3, NULL, 0, INT_MAX, + "Version", "Version of Blender the userpref.blend was saved with", 0, INT_MAX); + RNA_def_property_int_funcs(prop, "rna_userdef_version_get", NULL, NULL); + RNA_def_property_clear_flag(prop, PROP_EDITABLE); + RNA_def_property_flag(prop, PROP_THICK_WRAP); + rna_def_userdef_view(brna); rna_def_userdef_edit(brna); rna_def_userdef_input(brna); diff --git a/source/blender/modifiers/intern/MOD_meshsequencecache.c b/source/blender/modifiers/intern/MOD_meshsequencecache.c index d25e8e38de3..72644d56323 100644 --- a/source/blender/modifiers/intern/MOD_meshsequencecache.c +++ b/source/blender/modifiers/intern/MOD_meshsequencecache.c @@ -114,6 +114,10 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *ob, mcmd->reader, ob, mcmd->object_path); + if (!mcmd->reader) { + modifier_setError(md, "Could not create Alembic reader for file %s", cache_file->filepath); + return dm; + } } DerivedMesh *result = ABC_read_mesh(mcmd->reader, diff --git a/source/blender/nodes/intern/node_common.c b/source/blender/nodes/intern/node_common.c index fbc036435f0..736f17f1d70 100644 --- a/source/blender/nodes/intern/node_common.c +++ b/source/blender/nodes/intern/node_common.c @@ -178,9 +178,14 @@ void node_group_verify(struct bNodeTree *ntree, struct bNode *node, struct ID *i { /* check inputs and outputs, and remove or insert them */ if (id == node->id) { - bNodeTree *ngroup = (bNodeTree *)node->id; - group_verify_socket_list(ntree, node, &ngroup->inputs, &node->inputs, SOCK_IN); - group_verify_socket_list(ntree, node, &ngroup->outputs, &node->outputs, SOCK_OUT); + if (id == NULL) { + nodeRemoveAllSockets(ntree, node); + } + else { + bNodeTree *ngroup = (bNodeTree *)node->id; + group_verify_socket_list(ntree, node, &ngroup->inputs, &node->inputs, SOCK_IN); + group_verify_socket_list(ntree, node, &ngroup->outputs, &node->outputs, SOCK_OUT); + } } } diff --git a/source/blender/windowmanager/intern/wm_files.c b/source/blender/windowmanager/intern/wm_files.c index fe257cc4c41..05d63869074 100644 --- a/source/blender/windowmanager/intern/wm_files.c +++ b/source/blender/windowmanager/intern/wm_files.c @@ -1144,6 +1144,9 @@ void wm_autosave_timer(const bContext *C, wmWindowManager *wm, wmTimer *UNUSED(w for (handler = win->modalhandlers.first; handler; handler = handler->next) { if (handler->op) { wm->autosavetimer = WM_event_add_timer(wm, NULL, TIMERAUTOSAVE, 10.0); + if (G.debug) { + printf("Skipping auto-save, modal operator running, retrying in ten seconds...\n"); + } return; } } @@ -1161,7 +1164,7 @@ void wm_autosave_timer(const bContext *C, wmWindowManager *wm, wmTimer *UNUSED(w ED_editors_flush_edits(C, false); - /* no error reporting to console */ + /* Error reporting into console */ BLO_write_file(CTX_data_main(C), filepath, fileflags, NULL, NULL); } /* do timer after file write, just in case file write takes a long time */ |