diff options
author | Lukas Tönne <lukas.toenne@gmail.com> | 2018-01-03 13:24:05 +0300 |
---|---|---|
committer | Lukas Tönne <lukas.toenne@gmail.com> | 2018-01-03 13:24:05 +0300 |
commit | 36fac1e27ccc143a56bcf9ce35c236d5762e79fc (patch) | |
tree | 8def2e87a2c0f3905fde99af557b7a640dad9457 | |
parent | 2a7dfcd927c78d675bcde3d3ca9d417e0eae6704 (diff) | |
parent | 060fdb49d64857ff1cbf9937420ed70b10b17086 (diff) |
Merge branch 'blender2.8' into hair_guides
136 files changed, 2997 insertions, 1461 deletions
diff --git a/intern/cycles/blender/addon/properties.py b/intern/cycles/blender/addon/properties.py index 43f04bdff7a..355fed124da 100644 --- a/intern/cycles/blender/addon/properties.py +++ b/intern/cycles/blender/addon/properties.py @@ -1365,24 +1365,19 @@ class CyclesPreferences(bpy.types.AddonPreferences): devices = bpy.props.CollectionProperty(type=CyclesDeviceSettings) - def get_devices(self): - import _cycles - # Layout of the device tuples: (Name, Type, Persistent ID) - device_list = _cycles.available_devices() + def find_existing_device_entry(self, device): + for device_entry in self.devices: + if device_entry.id == device[2] and device_entry.type == device[1]: + return device_entry + return None - cuda_devices = [] - opencl_devices = [] - cpu_devices = [] + + def update_device_entries(self, device_list): for device in device_list: if not device[1] in {'CUDA', 'OPENCL', 'CPU'}: continue - - entry = None # Try to find existing Device entry - for dev in self.devices: - if dev.id == device[2] and dev.type == device[1]: - entry = dev - break + entry = self.find_existing_device_entry(device) if not entry: # Create new entry if no existing one was found entry = self.devices.add() @@ -1394,17 +1389,30 @@ class CyclesPreferences(bpy.types.AddonPreferences): # Update name in case it changed entry.name = device[0] - # Sort entries into lists + + def get_devices(self): + import _cycles + # Layout of the device tuples: (Name, Type, Persistent ID) + device_list = _cycles.available_devices() + # Make sure device entries are up to date and not referenced before + # we know we don't add new devices. This way we guarantee to not + # hold pointers to a resized array. + self.update_device_entries(device_list) + # Sort entries into lists + cuda_devices = [] + opencl_devices = [] + cpu_devices = [] + for device in device_list: + entry = self.find_existing_device_entry(device) if entry.type == 'CUDA': cuda_devices.append(entry) elif entry.type == 'OPENCL': opencl_devices.append(entry) - else: + elif entry.type == 'CPU': cpu_devices.append(entry) - + # Extend all GPU devices with CPU. cuda_devices.extend(cpu_devices) opencl_devices.extend(cpu_devices) - return cuda_devices, opencl_devices diff --git a/intern/cycles/blender/blender_object.cpp b/intern/cycles/blender/blender_object.cpp index 0c29c606df8..6564eea4767 100644 --- a/intern/cycles/blender/blender_object.cpp +++ b/intern/cycles/blender/blender_object.cpp @@ -469,6 +469,7 @@ static bool object_render_hide(BL::Object& b_ob, BL::Object::particle_systems_iterator b_psys; bool hair_present = false; + bool has_particles = false; bool show_emitter = false; bool hide_emitter = false; bool hide_as_dupli_parent = false; @@ -478,20 +479,17 @@ static bool object_render_hide(BL::Object& b_ob, if((b_psys->settings().render_type() == BL::ParticleSettings::render_type_PATH) && (b_psys->settings().type()==BL::ParticleSettings::type_HAIR)) hair_present = true; - - if(b_psys->settings().use_render_emitter()) - show_emitter = true; - else - hide_emitter = true; + has_particles = true; } - if(show_emitter) - hide_emitter = false; - - /* duplicators hidden by default, except dupliframes which duplicate self */ - if(b_ob.is_duplicator()) - if(top_level || b_ob.dupli_type() != BL::Object::dupli_type_FRAMES) + if(has_particles) { + show_emitter = b_ob.show_duplicator_for_render(); + hide_emitter = !show_emitter; + } else if(b_ob.is_duplicator()) { + if(top_level || b_ob.show_duplicator_for_render()) { hide_as_dupli_parent = true; + } + } /* hide original object for duplis */ BL::Object parent = b_ob.parent(); diff --git a/intern/cycles/device/device_cuda.cpp b/intern/cycles/device/device_cuda.cpp index 2e5f47002e8..47c09dfebf9 100644 --- a/intern/cycles/device/device_cuda.cpp +++ b/intern/cycles/device/device_cuda.cpp @@ -1372,8 +1372,8 @@ public: void *args[] = {&task->render_buffer.samples, &task->tiles_mem.device_pointer, - &mean_offset, - &variance_offset, + &mean_offset, + &variance_offset, &mean_ptr, &variance_ptr, &task->rect, diff --git a/intern/cycles/kernel/filter/filter_prefilter.h b/intern/cycles/kernel/filter/filter_prefilter.h index eefcbfea230..4af209341f6 100644 --- a/intern/cycles/kernel/filter/filter_prefilter.h +++ b/intern/cycles/kernel/filter/filter_prefilter.h @@ -117,61 +117,58 @@ ccl_device void kernel_filter_detect_outliers(int x, int y, { int buffer_w = align_up(rect.z - rect.x, 4); - int idx = (y-rect.y)*buffer_w + (x-rect.x); - float3 color = make_float3(image[idx], image[idx+pass_stride], image[idx+2*pass_stride]); - - float fac = 1.0f; - if(color.x < 0.0f || color.y < 0.0f || color.z < 0.0f) { - depth[idx] = -depth[idx]; - fac = 0.0f; - } - else { - float L = average(color); - int n = 0; - float values[25]; - for(int y1 = max(y-2, rect.y); y1 < min(y+3, rect.w); y1++) { - for(int x1 = max(x-2, rect.x); x1 < min(x+3, rect.z); x1++) { - int idx = (y1-rect.y)*buffer_w + (x1-rect.x); - float L = average(make_float3(image[idx], image[idx+pass_stride], image[idx+2*pass_stride])); - - /* Find the position of L. */ - int i; - for(i = 0; i < n; i++) { - if(values[i] > L) break; - } - /* Make space for L by shifting all following values to the right. */ - for(int j = n; j > i; j--) { - values[j] = values[j-1]; - } - /* Insert L. */ - values[i] = L; - n++; + int n = 0; + float values[25]; + for(int y1 = max(y-2, rect.y); y1 < min(y+3, rect.w); y1++) { + for(int x1 = max(x-2, rect.x); x1 < min(x+3, rect.z); x1++) { + int idx = (y1-rect.y)*buffer_w + (x1-rect.x); + float3 color = make_float3(image[idx], image[idx+pass_stride], image[idx+2*pass_stride]); + color = max(color, make_float3(0.0f, 0.0f, 0.0f)); + float L = average(color); + + /* Find the position of L. */ + int i; + for(i = 0; i < n; i++) { + if(values[i] > L) break; + } + /* Make space for L by shifting all following values to the right. */ + for(int j = n; j > i; j--) { + values[j] = values[j-1]; } + /* Insert L. */ + values[i] = L; + n++; } + } - float ref = 2.0f*values[(int)(n*0.75f)]; - if(L > ref) { - /* The pixel appears to be an outlier. - * However, it may just be a legitimate highlight. Therefore, it is checked how likely it is that the pixel - * should actually be at the reference value: - * If the reference is within the 3-sigma interval, the pixel is assumed to be a statistical outlier. - * Otherwise, it is very unlikely that the pixel should be darker, which indicates a legitimate highlight. - */ - float stddev = sqrtf(average(make_float3(variance[idx], variance[idx+pass_stride], variance[idx+2*pass_stride]))); - if(L - 3*stddev < ref) { - /* The pixel is an outlier, so negate the depth value to mark it as one. - * Also, scale its brightness down to the outlier threshold to avoid trouble with the NLM weights. */ - depth[idx] = -depth[idx]; - fac = ref/L; - variance[idx ] *= fac*fac; - variance[idx + pass_stride] *= fac*fac; - variance[idx+2*pass_stride] *= fac*fac; - } + int idx = (y-rect.y)*buffer_w + (x-rect.x); + float3 color = make_float3(image[idx], image[idx+pass_stride], image[idx+2*pass_stride]); + color = max(color, make_float3(0.0f, 0.0f, 0.0f)); + float L = average(color); + + float ref = 2.0f*values[(int)(n*0.75f)]; + if(L > ref) { + /* The pixel appears to be an outlier. + * However, it may just be a legitimate highlight. Therefore, it is checked how likely it is that the pixel + * should actually be at the reference value: + * If the reference is within the 3-sigma interval, the pixel is assumed to be a statistical outlier. + * Otherwise, it is very unlikely that the pixel should be darker, which indicates a legitimate highlight. + */ + float stddev = sqrtf(average(make_float3(variance[idx], variance[idx+pass_stride], variance[idx+2*pass_stride]))); + if(L - 3*stddev < ref) { + /* The pixel is an outlier, so negate the depth value to mark it as one. + * Also, scale its brightness down to the outlier threshold to avoid trouble with the NLM weights. */ + depth[idx] = -depth[idx]; + float fac = ref/L; + color *= fac; + variance[idx ] *= fac*fac; + variance[idx + pass_stride] *= fac*fac; + variance[idx+2*pass_stride] *= fac*fac; } } - out[idx ] = fac*image[idx]; - out[idx + pass_stride] = fac*image[idx + pass_stride]; - out[idx+2*pass_stride] = fac*image[idx+2*pass_stride]; + out[idx ] = color.x; + out[idx + pass_stride] = color.y; + out[idx+2*pass_stride] = color.z; } /* Combine A/B buffers. diff --git a/release/datafiles/locale b/release/datafiles/locale -Subproject b3d9c97f487bff8b2423c903c14204ba5ca21a8 +Subproject 47700dfc9835ef7154bbd34b8725c8abf2f290d diff --git a/release/scripts/addons b/release/scripts/addons -Subproject 371960484a38fc64e0a2635170a41a0d8ab2f6b +Subproject 6cdbffbc229bf263fa4b9b82a6e33b591c32934 diff --git a/release/scripts/addons_contrib b/release/scripts/addons_contrib -Subproject a8515cfdfe9a98127b592f36fcbe51b7e23b969 +Subproject e88b7dfc3bd68888be2d05437cf50e93e41ef47 diff --git a/release/scripts/modules/bpy_extras/keyconfig_utils.py b/release/scripts/modules/bpy_extras/keyconfig_utils.py index 3203bc41b76..9d206afb2c5 100644 --- a/release/scripts/modules/bpy_extras/keyconfig_utils.py +++ b/release/scripts/modules/bpy_extras/keyconfig_utils.py @@ -137,6 +137,7 @@ KM_HIERARCHY = [ ('Standard Modal Map', 'EMPTY', 'WINDOW', []), ('Transform Modal Map', 'EMPTY', 'WINDOW', []), ('Eyedropper Modal Map', 'EMPTY', 'WINDOW', []), + ('Eyedropper ColorBand PointSampling Map', 'EMPTY', 'WINDOW', []), ] diff --git a/release/scripts/startup/bl_ui/properties_object.py b/release/scripts/startup/bl_ui/properties_object.py index 23787756121..de608c42cb5 100644 --- a/release/scripts/startup/bl_ui/properties_object.py +++ b/release/scripts/startup/bl_ui/properties_object.py @@ -278,6 +278,13 @@ class OBJECT_PT_display(ObjectButtonsPanel, Panel): col.label(text="Object Color:") col.prop(obj, "color", text="") + col = layout.column() + col.active = bool(is_dupli or obj.particle_systems) + col.label(text="Duplicator Visibility:") + row = col.row(align=True) + row.prop(obj, "show_duplicator_for_viewport", text="Viewport") + row.prop(obj, "show_duplicator_for_render", text="Render") + class OBJECT_PT_duplication(ObjectButtonsPanel, Panel): bl_label = "Duplication" diff --git a/release/scripts/startup/bl_ui/properties_particle.py b/release/scripts/startup/bl_ui/properties_particle.py index a5793e6d9a9..fda3096a3f5 100644 --- a/release/scripts/startup/bl_ui/properties_particle.py +++ b/release/scripts/startup/bl_ui/properties_particle.py @@ -926,7 +926,6 @@ class PARTICLE_PT_render(ParticleButtonsPanel, Panel): split = layout.split() col = split.column() - col.prop(part, "use_render_emitter") col.prop(part, "use_parent_particles") col = split.column() diff --git a/release/scripts/startup/bl_ui/space_outliner.py b/release/scripts/startup/bl_ui/space_outliner.py index dbd436b72c3..043ca19ba11 100644 --- a/release/scripts/startup/bl_ui/space_outliner.py +++ b/release/scripts/startup/bl_ui/space_outliner.py @@ -60,14 +60,13 @@ class OUTLINER_HT_header(Header): elif space.display_mode == 'ORPHAN_DATA': layout.operator("outliner.orphans_purge") - elif space.display_mode in {'ACT_LAYER', 'MASTER_COLLECTION'}: + elif space.display_mode == 'ACT_LAYER': row = layout.row(align=True) row.operator("outliner.collection_new", text="", icon='NEW') - if space.display_mode == 'ACT_LAYER': - row.operator("outliner.collection_override_new", text="", icon='LINK_AREA') - row.operator("outliner.collection_link", text="", icon='LINKED') - row.operator("outliner.collection_unlink", text="", icon='UNLINKED') + row.operator("outliner.collection_override_new", text="", icon='LINK_AREA') + row.operator("outliner.collection_link", text="", icon='LINKED') + row.operator("outliner.collection_unlink", text="", icon='UNLINKED') row.operator("outliner.collections_delete", text="", icon='X') @@ -88,6 +87,9 @@ class OUTLINER_MT_editor_menus(Menu): if space.display_mode == 'DATABLOCKS': layout.menu("OUTLINER_MT_edit_datablocks") + elif space.display_mode == 'MASTER_COLLECTION': + layout.menu("OUTLINER_MT_edit_collections") + class OUTLINER_MT_view(Menu): bl_label = "View" @@ -127,6 +129,16 @@ class OUTLINER_MT_search(Menu): layout.prop(space, "use_filter_complete") +class OUTLINER_MT_edit_collections(Menu): + bl_label = "Edit" + + def draw(self, context): + layout = self.layout + + layout.operator("outliner.collection_nested_new", text="New Collection", icon='NEW') + layout.operator("outliner.collection_delete_selected", text="Delete Collections", icon='X') + + class OUTLINER_MT_edit_datablocks(Menu): bl_label = "Edit" @@ -147,6 +159,7 @@ classes = ( OUTLINER_MT_editor_menus, OUTLINER_MT_view, OUTLINER_MT_search, + OUTLINER_MT_edit_collections, OUTLINER_MT_edit_datablocks, ) diff --git a/source/blender/alembic/intern/abc_customdata.cc b/source/blender/alembic/intern/abc_customdata.cc index d6e7a80d174..8b526616053 100644 --- a/source/blender/alembic/intern/abc_customdata.cc +++ b/source/blender/alembic/intern/abc_customdata.cc @@ -235,17 +235,19 @@ static void read_uvs(const CDStreamConfig &config, void *data, MPoly *mpolys = config.mpoly; MLoopUV *mloopuvs = static_cast<MLoopUV *>(data); - unsigned int uv_index, loop_index; + unsigned int uv_index, loop_index, rev_loop_index; for (int i = 0; i < config.totpoly; ++i) { MPoly &poly = mpolys[i]; + unsigned int rev_loop_offset = poly.loopstart + poly.totloop - 1; for (int f = 0; f < poly.totloop; ++f) { loop_index = poly.loopstart + f; + rev_loop_index = rev_loop_offset - f; uv_index = (*indices)[loop_index]; const Imath::V2f &uv = (*uvs)[uv_index]; - MLoopUV &loopuv = mloopuvs[loop_index]; + MLoopUV &loopuv = mloopuvs[rev_loop_index]; loopuv.uv[0] = uv[0]; loopuv.uv[1] = uv[1]; } diff --git a/source/blender/blenkernel/BKE_font.h b/source/blender/blenkernel/BKE_font.h index 60ad061bf77..e5eea4423c9 100644 --- a/source/blender/blenkernel/BKE_font.h +++ b/source/blender/blenkernel/BKE_font.h @@ -86,7 +86,7 @@ struct VFont *BKE_vfont_load_exists(struct Main *bmain, const char *filepath); void BKE_vfont_make_local(struct Main *bmain, struct VFont *vfont, const bool lib_local); -bool BKE_vfont_to_curve_ex(struct Main *bmain, struct Object *ob, int mode, +bool BKE_vfont_to_curve_ex(struct Main *bmain, struct Object *ob, struct Curve *cu, int mode, struct ListBase *r_nubase, const wchar_t **r_text, int *r_text_len, bool *r_text_free, struct CharTrans **r_chartransdata); diff --git a/source/blender/blenkernel/BKE_freestyle.h b/source/blender/blenkernel/BKE_freestyle.h index 1045fde0039..f7368683d93 100644 --- a/source/blender/blenkernel/BKE_freestyle.h +++ b/source/blender/blenkernel/BKE_freestyle.h @@ -49,7 +49,7 @@ typedef struct FreestyleModuleSettings FreestyleModuleSettings; /* FreestyleConfig */ void BKE_freestyle_config_init(FreestyleConfig *config); -void BKE_freestyle_config_free(FreestyleConfig *config); +void BKE_freestyle_config_free(FreestyleConfig *config, const bool do_id_user); void BKE_freestyle_config_copy(FreestyleConfig *new_config, FreestyleConfig *config, const int flag); /* FreestyleConfig.modules */ diff --git a/source/blender/blenkernel/BKE_layer.h b/source/blender/blenkernel/BKE_layer.h index 6a762c9b711..77f760a7843 100644 --- a/source/blender/blenkernel/BKE_layer.h +++ b/source/blender/blenkernel/BKE_layer.h @@ -66,6 +66,7 @@ struct ViewLayer *BKE_view_layer_group_add(struct Group *group); struct ViewLayer *BKE_view_layer_context_active_PLACEHOLDER(const struct Scene *scene); void BKE_view_layer_free(struct ViewLayer *view_layer); +void BKE_view_layer_free_ex(struct ViewLayer *view_layer, const bool do_id_user); void BKE_view_layer_selected_objects_tag(struct ViewLayer *view_layer, const int tag); diff --git a/source/blender/blenkernel/BKE_object.h b/source/blender/blenkernel/BKE_object.h index 2b183906f57..d98c52aa91a 100644 --- a/source/blender/blenkernel/BKE_object.h +++ b/source/blender/blenkernel/BKE_object.h @@ -82,7 +82,14 @@ bool BKE_object_exists_check(struct Object *obtest); bool BKE_object_is_in_editmode(struct Object *ob); bool BKE_object_is_in_editmode_vgroup(struct Object *ob); bool BKE_object_is_in_wpaint_select_vert(struct Object *ob); -bool BKE_object_is_visible(struct Object *ob); + +typedef enum eObjectVisibilityCheck { + OB_VISIBILITY_CHECK_FOR_VIEWPORT, + OB_VISIBILITY_CHECK_FOR_RENDER, + OB_VISIBILITY_CHECK_UNKNOWN_RENDER_MODE, +} eObjectVisibilityCheck; + +bool BKE_object_is_visible(struct Object *ob, const eObjectVisibilityCheck mode); void BKE_object_init(struct Object *ob); struct Object *BKE_object_add_only_object( diff --git a/source/blender/blenkernel/BKE_paint.h b/source/blender/blenkernel/BKE_paint.h index 31f4695201c..b8fde8bd68e 100644 --- a/source/blender/blenkernel/BKE_paint.h +++ b/source/blender/blenkernel/BKE_paint.h @@ -157,7 +157,7 @@ float paint_grid_paint_mask(const struct GridPaintMask *gpm, unsigned level, unsigned x, unsigned y); /* stroke related */ -void paint_calculate_rake_rotation(struct UnifiedPaintSettings *ups, struct Brush *brush, const float mouse_pos[2]); +bool paint_calculate_rake_rotation(struct UnifiedPaintSettings *ups, struct Brush *brush, const float mouse_pos[2]); void paint_update_brush_rake_rotation(struct UnifiedPaintSettings *ups, struct Brush *brush, float rotation); void BKE_paint_stroke_get_average(struct Scene *scene, struct Object *ob, float stroke[3]); diff --git a/source/blender/blenkernel/BKE_tracking.h b/source/blender/blenkernel/BKE_tracking.h index b4ca1b79238..5da87de1cc9 100644 --- a/source/blender/blenkernel/BKE_tracking.h +++ b/source/blender/blenkernel/BKE_tracking.h @@ -289,6 +289,46 @@ void BKE_tracking_stabilization_data_to_mat4(int width, int height, float aspect void BKE_tracking_dopesheet_tag_update(struct MovieTracking *tracking); void BKE_tracking_dopesheet_update(struct MovieTracking *tracking); +/* **** Query/search **** */ + +struct MovieTrackingObject *BKE_tracking_find_object_for_track( + const struct MovieTracking *tracking, + const struct MovieTrackingTrack *track); +struct ListBase *BKE_tracking_find_tracks_list_for_track( + struct MovieTracking *tracking, + const struct MovieTrackingTrack *track); + +struct MovieTrackingObject *BKE_tracking_find_object_for_plane_track( + const struct MovieTracking *tracking, + const struct MovieTrackingPlaneTrack *plane_track); +struct ListBase *BKE_tracking_find_tracks_list_for_plane_track( + struct MovieTracking *tracking, + const struct MovieTrackingPlaneTrack *plane_track); + + +void BKE_tracking_get_rna_path_for_track( + const struct MovieTracking *tracking, + const struct MovieTrackingTrack *track, + char *rna_path, + size_t rna_path_len); +void BKE_tracking_get_rna_path_prefix_for_track( + const struct MovieTracking *tracking, + const struct MovieTrackingTrack *track, + char *rna_path, + size_t rna_path_len); +void BKE_tracking_get_rna_path_for_plane_track( + const struct MovieTracking *tracking, + const struct MovieTrackingPlaneTrack *plane_track, + char *rna_path, + size_t rna_path_len); +void BKE_tracking_get_rna_path_prefix_for_plane_track( + const struct MovieTracking *tracking, + const struct MovieTrackingPlaneTrack *plane_track, + char *rna_path, + size_t rna_path_len); + +/* **** Utility macros **** */ + #define TRACK_SELECTED(track) ((track)->flag & SELECT || (track)->pat_flag & SELECT || (track)->search_flag & SELECT) #define TRACK_AREA_SELECTED(track, area) ((area) == TRACK_AREA_POINT ? (track)->flag & SELECT : \ diff --git a/source/blender/blenkernel/intern/collection.c b/source/blender/blenkernel/intern/collection.c index 8d69563f5ff..e2b10de575c 100644 --- a/source/blender/blenkernel/intern/collection.c +++ b/source/blender/blenkernel/intern/collection.c @@ -50,6 +50,7 @@ #include "MEM_guardedalloc.h" /* Prototypes. */ +static SceneCollection *find_collection_parent(const struct SceneCollection *sc_child, struct SceneCollection *sc_parent); static bool is_collection_in_tree(const struct SceneCollection *sc_reference, struct SceneCollection *sc_parent); static SceneCollection *collection_master_from_id(const ID *owner_id) @@ -69,24 +70,35 @@ static SceneCollection *collection_master_from_id(const ID *owner_id) * Add a collection to a collection ListBase and syncronize all render layers * The ListBase is NULL when the collection is to be added to the master collection */ -SceneCollection *BKE_collection_add(ID *owner_id, SceneCollection *sc_parent, const int type, const char *name) +SceneCollection *BKE_collection_add(ID *owner_id, SceneCollection *sc_parent, const int type, const char *name_custom) { SceneCollection *sc_master = collection_master_from_id(owner_id); SceneCollection *sc = MEM_callocN(sizeof(SceneCollection), "New Collection"); sc->type = type; - - if (!name) { - name = DATA_("New Collection"); - } + const char *name = name_custom; if (!sc_parent) { sc_parent = sc_master; } - BKE_collection_rename((Scene *)owner_id, sc, name); + if (!name) { + if (sc_parent == sc_master) { + name = BLI_sprintfN("Collection %d", BLI_listbase_count(&sc_master->scene_collections) + 1); + } + else { + name = BLI_sprintfN("%s %d", sc_parent->name, BLI_listbase_count(&sc_parent->scene_collections) + 1); + } + } + BLI_addtail(&sc_parent->scene_collections, sc); + BKE_collection_rename((Scene *)owner_id, sc, name); BKE_layer_sync_new_scene_collection(owner_id, sc_parent, sc); + + if (name != name_custom) { + MEM_freeN((char *)name); + } + return sc; } @@ -164,6 +176,8 @@ static void layer_collection_remove(ViewLayer *view_layer, ListBase *lb, const S /** * Remove a collection from the scene, and syncronize all render layers + * + * If an object is in any other collection, link the object to the master collection. */ bool BKE_collection_remove(ID *owner_id, SceneCollection *sc) { @@ -174,11 +188,50 @@ bool BKE_collection_remove(ID *owner_id, SceneCollection *sc) return false; } + /* We need to do bottom up removal, otherwise we get a crash when we remove a collection that + * has one of its nested collections linked to a view layer. */ + SceneCollection *scene_collection_nested = sc->scene_collections.first; + while (scene_collection_nested != NULL) { + SceneCollection *scene_collection_next = scene_collection_nested->next; + BKE_collection_remove(owner_id, scene_collection_nested); + scene_collection_nested = scene_collection_next; + } + /* Unlink from the respective collection tree. */ if (!collection_remlink(sc_master, sc)) { BLI_assert(false); } + /* If an object is no longer in any collection, we add it to the master collection. */ + ListBase collection_objects; + BLI_duplicatelist(&collection_objects, &sc->objects); + + FOREACH_SCENE_COLLECTION(owner_id, scene_collection_iter) + { + if (scene_collection_iter == sc) { + continue; + } + + LinkData *link_next, *link = collection_objects.first; + while (link) { + link_next = link->next; + + if (BLI_findptr(&scene_collection_iter->objects, link->data, offsetof(LinkData, data))) { + BLI_remlink(&collection_objects, link); + MEM_freeN(link); + } + + link = link_next; + } + } + FOREACH_SCENE_COLLECTION_END + + for (LinkData *link = collection_objects.first; link; link = link->next) { + BKE_collection_object_add(owner_id, sc_master, link->data); + } + + BLI_freelistN(&collection_objects); + /* Clear the collection items. */ collection_free(sc, true); @@ -243,38 +296,11 @@ SceneCollection *BKE_collection_master(const ID *owner_id) return master_collection_from_id(owner_id); } -struct UniqueNameCheckData { - ListBase *lb; - SceneCollection *lookup_sc; -}; - -static bool collection_unique_name_check(void *arg, const char *name) -{ - struct UniqueNameCheckData *data = arg; - - for (SceneCollection *sc = data->lb->first; sc; sc = sc->next) { - struct UniqueNameCheckData child_data = {.lb = &sc->scene_collections, .lookup_sc = data->lookup_sc}; - - if (sc != data->lookup_sc) { - if (STREQ(sc->name, name)) { - return true; - } - } - if (collection_unique_name_check(&child_data, name)) { - return true; - } - } - - return false; -} - static void collection_rename(const ID *owner_id, SceneCollection *sc, const char *name) { - SceneCollection *sc_master = collection_master_from_id(owner_id); - struct UniqueNameCheckData data = {.lb = &sc_master->scene_collections, .lookup_sc = sc}; - + SceneCollection *sc_parent = find_collection_parent(sc, collection_master_from_id(owner_id)); BLI_strncpy(sc->name, name, sizeof(sc->name)); - BLI_uniquename_cb(collection_unique_name_check, &data, DATA_("Collection"), '.', sc->name, sizeof(sc->name)); + BLI_uniquename(&sc_parent->scene_collections, sc, DATA_("Collection"), '.', offsetof(SceneCollection, name), sizeof(sc->name)); } void BKE_collection_rename(const Scene *scene, SceneCollection *sc, const char *name) diff --git a/source/blender/blenkernel/intern/context.c b/source/blender/blenkernel/intern/context.c index 3c326a77f2b..b9a8ea67a0a 100644 --- a/source/blender/blenkernel/intern/context.c +++ b/source/blender/blenkernel/intern/context.c @@ -968,11 +968,11 @@ RenderEngineType *CTX_data_engine_type(const bContext *C) LayerCollection *CTX_data_layer_collection(const bContext *C) { ViewLayer *view_layer = CTX_data_view_layer(C); - LayerCollection *lc; + LayerCollection *layer_collection; - if (ctx_data_pointer_verify(C, "layer_collection", (void *)&lc)) { - if (BKE_view_layer_has_collection(view_layer, lc->scene_collection)) { - return lc; + if (ctx_data_pointer_verify(C, "layer_collection", (void *)&layer_collection)) { + if (BKE_view_layer_has_collection(view_layer, layer_collection->scene_collection)) { + return layer_collection; } } @@ -982,16 +982,14 @@ LayerCollection *CTX_data_layer_collection(const bContext *C) SceneCollection *CTX_data_scene_collection(const bContext *C) { - SceneCollection *sc; - if (ctx_data_pointer_verify(C, "scene_collection", (void *)&sc)) { - if (BKE_view_layer_has_collection(CTX_data_view_layer(C), sc)) { - return sc; - } + SceneCollection *scene_collection; + if (ctx_data_pointer_verify(C, "scene_collection", (void *)&scene_collection)) { + return scene_collection; } - LayerCollection *lc = CTX_data_layer_collection(C); - if (lc) { - return lc->scene_collection; + LayerCollection *layer_collection = CTX_data_layer_collection(C); + if (layer_collection) { + return layer_collection->scene_collection; } /* fallback */ diff --git a/source/blender/blenkernel/intern/curve.c b/source/blender/blenkernel/intern/curve.c index ba9ccf94303..5a284761814 100644 --- a/source/blender/blenkernel/intern/curve.c +++ b/source/blender/blenkernel/intern/curve.c @@ -4938,12 +4938,27 @@ void BKE_curve_nurb_vert_active_validate(Curve *cu) bool BKE_curve_minmax(Curve *cu, bool use_radius, float min[3], float max[3]) { ListBase *nurb_lb = BKE_curve_nurbs_get(cu); - Nurb *nu; - - for (nu = nurb_lb->first; nu; nu = nu->next) + ListBase temp_nurb_lb = {NULL, NULL}; + const bool is_font = (BLI_listbase_is_empty(nurb_lb)) && (cu->len != 0); + /* For font curves we generate temp list of splines. + * + * This is likely to be fine, this function is not supposed to be called + * often, and it's the only way to get meaningful bounds for fonts. + */ + if (is_font) { + nurb_lb = &temp_nurb_lb; + BKE_vfont_to_curve_ex(G.main, NULL, cu, FO_EDIT, nurb_lb, + NULL, NULL, NULL, NULL); + use_radius = false; + } + /* Do bounding box based on splines. */ + for (Nurb *nu = nurb_lb->first; nu; nu = nu->next) { BKE_nurb_minmax(nu, use_radius, min, max); - - return (BLI_listbase_is_empty(nurb_lb) == false); + } + const bool result = (BLI_listbase_is_empty(nurb_lb) == false); + /* Cleanup if needed. */ + BKE_nurbList_free(&temp_nurb_lb); + return result; } bool BKE_curve_center_median(Curve *cu, float cent[3]) diff --git a/source/blender/blenkernel/intern/font.c b/source/blender/blenkernel/intern/font.c index d6b28cfaf70..ef479d77915 100644 --- a/source/blender/blenkernel/intern/font.c +++ b/source/blender/blenkernel/intern/font.c @@ -635,11 +635,10 @@ struct TempLineInfo { int wspace_nr; /* number of whitespaces of line */ }; -bool BKE_vfont_to_curve_ex(Main *bmain, Object *ob, int mode, ListBase *r_nubase, +bool BKE_vfont_to_curve_ex(Main *bmain, Object *ob, Curve *cu, int mode, ListBase *r_nubase, const wchar_t **r_text, int *r_text_len, bool *r_text_free, struct CharTrans **r_chartransdata) { - Curve *cu = ob->data; EditFont *ef = cu->editfont; EditFontSelBox *selboxes = NULL; VFont *vfont, *oldvfont; @@ -670,7 +669,7 @@ bool BKE_vfont_to_curve_ex(Main *bmain, Object *ob, int mode, ListBase *r_nubase /* remark: do calculations including the trailing '\0' of a string * because the cursor can be at that location */ - BLI_assert(ob->type == OB_FONT); + BLI_assert(ob == NULL || ob->type == OB_FONT); /* Set font data */ vfont = cu->vfont; @@ -708,7 +707,7 @@ bool BKE_vfont_to_curve_ex(Main *bmain, Object *ob, int mode, ListBase *r_nubase if (cu->tb == NULL) cu->tb = MEM_callocN(MAXTEXTBOX * sizeof(TextBox), "TextBox compat"); - if (ef) { + if (ef != NULL && ob != NULL) { if (ef->selboxes) MEM_freeN(ef->selboxes); @@ -1258,7 +1257,7 @@ makebreak: cha = towupper(cha); } - if (info->mat_nr > (ob->totcol)) { + if (ob == NULL || info->mat_nr > (ob->totcol)) { /* printf("Error: Illegal material index (%d) in text object, setting to 0\n", info->mat_nr); */ info->mat_nr = 0; } @@ -1334,7 +1333,7 @@ bool BKE_vfont_to_curve_nubase(Main *bmain, Object *ob, int mode, ListBase *r_nu { BLI_assert(ob->type == OB_FONT); - return BKE_vfont_to_curve_ex(bmain, ob, mode, r_nubase, + return BKE_vfont_to_curve_ex(bmain, ob, ob->data, mode, r_nubase, NULL, NULL, NULL, NULL); } @@ -1342,7 +1341,7 @@ bool BKE_vfont_to_curve(Main *bmain, Object *ob, int mode) { Curve *cu = ob->data; - return BKE_vfont_to_curve_ex(bmain, ob, mode, &cu->nurb, NULL, NULL, NULL, NULL); + return BKE_vfont_to_curve_ex(bmain, ob, ob->data, mode, &cu->nurb, NULL, NULL, NULL, NULL); } diff --git a/source/blender/blenkernel/intern/freestyle.c b/source/blender/blenkernel/intern/freestyle.c index 686fe3bda93..b656d2cf7c0 100644 --- a/source/blender/blenkernel/intern/freestyle.c +++ b/source/blender/blenkernel/intern/freestyle.c @@ -61,17 +61,21 @@ void BKE_freestyle_config_init(FreestyleConfig *config) BLI_listbase_clear(&config->linesets); } -void BKE_freestyle_config_free(FreestyleConfig *config) +void BKE_freestyle_config_free(FreestyleConfig *config, const bool do_id_user) { FreestyleLineSet *lineset; for (lineset = (FreestyleLineSet *)config->linesets.first; lineset; lineset = lineset->next) { if (lineset->group) { - id_us_min(&lineset->group->id); + if (do_id_user) { + id_us_min(&lineset->group->id); + } lineset->group = NULL; } if (lineset->linestyle) { - id_us_min(&lineset->linestyle->id); + if (do_id_user) { + id_us_min(&lineset->linestyle->id); + } lineset->linestyle = NULL; } } diff --git a/source/blender/blenkernel/intern/group.c b/source/blender/blenkernel/intern/group.c index 5b55433c1b9..8295fafba56 100644 --- a/source/blender/blenkernel/intern/group.c +++ b/source/blender/blenkernel/intern/group.c @@ -88,10 +88,7 @@ void BKE_group_init(Group *group) BKE_collection_unlink(group->view_layer, group->view_layer->layer_collections.first); /* Create and link a new default collection. */ - SceneCollection *defaut_collection = BKE_collection_add(&group->id, - NULL, - COLLECTION_TYPE_GROUP_INTERNAL, - "Default Collection"); + SceneCollection *defaut_collection = BKE_collection_add(&group->id, NULL, COLLECTION_TYPE_GROUP_INTERNAL, NULL); BKE_collection_link(group->view_layer, defaut_collection); } diff --git a/source/blender/blenkernel/intern/layer.c b/source/blender/blenkernel/intern/layer.c index 2e6cd769db8..288dcb34439 100644 --- a/source/blender/blenkernel/intern/layer.c +++ b/source/blender/blenkernel/intern/layer.c @@ -163,10 +163,15 @@ ViewLayer *BKE_view_layer_group_add(Group *group) return view_layer; } +void BKE_view_layer_free(ViewLayer *view_layer) +{ + BKE_view_layer_free_ex(view_layer, true); +} + /** * Free (or release) any data used by this ViewLayer. */ -void BKE_view_layer_free(ViewLayer *view_layer) +void BKE_view_layer_free_ex(ViewLayer *view_layer, const bool do_id_user) { view_layer->basact = NULL; @@ -205,7 +210,7 @@ void BKE_view_layer_free(ViewLayer *view_layer) MEM_SAFE_FREE(view_layer->stats); - BKE_freestyle_config_free(&view_layer->freestyle_config); + BKE_freestyle_config_free(&view_layer->freestyle_config, do_id_user); if (view_layer->id_properties) { IDP_FreeProperty(view_layer->id_properties); diff --git a/source/blender/blenkernel/intern/mesh.c b/source/blender/blenkernel/intern/mesh.c index 8f41f0611d4..24ed97ccfc1 100644 --- a/source/blender/blenkernel/intern/mesh.c +++ b/source/blender/blenkernel/intern/mesh.c @@ -1436,6 +1436,17 @@ void BKE_mesh_from_nurbs_displist(Object *ob, ListBase *dispbase, const bool use me->totcol = cu->totcol; me->mat = cu->mat; + /* Copy evaluated texture space from curve to mesh. + * + * Note that we disable auto texture space feature since that will cause + * texture space to evaluate differently for curve and mesh, since curve + * uses CV to calculate bounding box, and mesh uses what is coming from + * tessellated curve. + */ + me->texflag = cu->texflag & ~CU_AUTOSPACE; + copy_v3_v3(me->loc, cu->loc); + copy_v3_v3(me->size, cu->size); + copy_v3_v3(me->rot, cu->rot); BKE_mesh_texspace_calc(me); cu->mat = NULL; @@ -2460,6 +2471,11 @@ Mesh *BKE_mesh_new_from_object( /* copies the data */ copycu = tmpobj->data = BKE_curve_copy(bmain, (Curve *) ob->data); + /* make sure texture space is calculated for a copy of curve, + * it will be used for the final result. + */ + BKE_curve_texspace_calc(copycu); + /* temporarily set edit so we get updates from edit mode, but * also because for text datablocks copying it while in edit * mode gives invalid data structures */ @@ -2490,8 +2506,6 @@ Mesh *BKE_mesh_new_from_object( return NULL; } - BKE_mesh_texspace_copy_from_object(tmpmesh, ob); - BKE_libblock_free_us(bmain, tmpobj); /* XXX The curve to mesh conversion is convoluted... But essentially, BKE_mesh_from_nurbs_displist() diff --git a/source/blender/blenkernel/intern/object.c b/source/blender/blenkernel/intern/object.c index ab09ccf5654..ddc73a4427a 100644 --- a/source/blender/blenkernel/intern/object.c +++ b/source/blender/blenkernel/intern/object.c @@ -566,11 +566,32 @@ bool BKE_object_is_in_wpaint_select_vert(Object *ob) /** * Return if the object is visible, as evaluated by depsgraph - * Keep in sync with rna_object.c (object.is_visible). */ -bool BKE_object_is_visible(Object *ob) +bool BKE_object_is_visible(Object *ob, const eObjectVisibilityCheck mode) { - return (ob->base_flag & BASE_VISIBLED) != 0; + if ((ob->base_flag & BASE_VISIBLED) == 0) { + return false; + } + + if (mode == OB_VISIBILITY_CHECK_UNKNOWN_RENDER_MODE) { + return true; + } + + if (((ob->transflag & OB_DUPLI) == 0) && + (ob->particlesystem.first == NULL)) + { + return true; + } + + switch (mode) { + case OB_VISIBILITY_CHECK_FOR_VIEWPORT: + return ((ob->duplicator_visibility_flag & OB_DUPLI_FLAG_VIEWPORT) != 0); + case OB_VISIBILITY_CHECK_FOR_RENDER: + return ((ob->duplicator_visibility_flag & OB_DUPLI_FLAG_RENDER) != 0); + default: + BLI_assert(!"Object visible test mode not supported."); + return false; + } } bool BKE_object_exists_check(Object *obtest) @@ -700,6 +721,7 @@ void BKE_object_init(Object *ob) ob->col_group = 0x01; ob->col_mask = 0xffff; ob->preview = NULL; + ob->duplicator_visibility_flag = OB_DUPLI_FLAG_VIEWPORT | OB_DUPLI_FLAG_RENDER; /* NT fluid sim defaults */ ob->fluidsimSettings = NULL; diff --git a/source/blender/blenkernel/intern/object_dupli.c b/source/blender/blenkernel/intern/object_dupli.c index 9b25a1db6ff..13589866e48 100644 --- a/source/blender/blenkernel/intern/object_dupli.c +++ b/source/blender/blenkernel/intern/object_dupli.c @@ -613,7 +613,7 @@ static void make_duplis_font(const DupliContext *ctx) /* in par the family name is stored, use this to find the other objects */ - BKE_vfont_to_curve_ex(G.main, par, FO_DUPLI, NULL, + BKE_vfont_to_curve_ex(G.main, par, par->data, FO_DUPLI, NULL, &text, &text_len, &text_free, &chartransdata); if (text == NULL || chartransdata == NULL) { diff --git a/source/blender/blenkernel/intern/paint.c b/source/blender/blenkernel/intern/paint.c index c88642a8164..11702236066 100644 --- a/source/blender/blenkernel/intern/paint.c +++ b/source/blender/blenkernel/intern/paint.c @@ -641,8 +641,9 @@ void paint_update_brush_rake_rotation(UnifiedPaintSettings *ups, Brush *brush, f ups->brush_rotation_sec = 0.0f; } -void paint_calculate_rake_rotation(UnifiedPaintSettings *ups, Brush *brush, const float mouse_pos[2]) +bool paint_calculate_rake_rotation(UnifiedPaintSettings *ups, Brush *brush, const float mouse_pos[2]) { + bool ok = false; if ((brush->mtex.brush_angle_mode & MTEX_ANGLE_RAKE) || (brush->mask_mtex.brush_angle_mode & MTEX_ANGLE_RAKE)) { const float r = RAKE_THRESHHOLD; float rotation; @@ -658,16 +659,20 @@ void paint_calculate_rake_rotation(UnifiedPaintSettings *ups, Brush *brush, cons ups->last_rake_angle = rotation; paint_update_brush_rake_rotation(ups, brush, rotation); + ok = true; } /* make sure we reset here to the last rotation to avoid accumulating * values in case a random rotation is also added */ else { paint_update_brush_rake_rotation(ups, brush, ups->last_rake_angle); + ok = false; } } else { ups->brush_rotation = ups->brush_rotation_sec = 0.0f; + ok = true; } + return ok; } void BKE_sculptsession_free_deformMats(SculptSession *ss) diff --git a/source/blender/blenkernel/intern/particle.c b/source/blender/blenkernel/intern/particle.c index 9bdf0acb1c3..b14c752fec3 100644 --- a/source/blender/blenkernel/intern/particle.c +++ b/source/blender/blenkernel/intern/particle.c @@ -3284,7 +3284,7 @@ static void default_particle_settings(ParticleSettings *part) part->clength = 1.0f; part->clength_thres = 0.0f; - part->draw = PART_DRAW_EMITTER; + part->draw = 0; part->draw_line[0] = 0.5; part->path_start = 0.0f; part->path_end = 1.0f; diff --git a/source/blender/blenkernel/intern/scene.c b/source/blender/blenkernel/intern/scene.c index 22c3da09f13..a462e5b215c 100644 --- a/source/blender/blenkernel/intern/scene.c +++ b/source/blender/blenkernel/intern/scene.c @@ -540,7 +540,7 @@ void BKE_scene_free_ex(Scene *sce, const bool do_id_user) view_layer_next = view_layer->next; BLI_remlink(&sce->view_layers, view_layer); - BKE_view_layer_free(view_layer); + BKE_view_layer_free_ex(view_layer, do_id_user); } /* Master Collection */ diff --git a/source/blender/blenkernel/intern/tracking.c b/source/blender/blenkernel/intern/tracking.c index 07e071df04a..ebd4c04e8ce 100644 --- a/source/blender/blenkernel/intern/tracking.c +++ b/source/blender/blenkernel/intern/tracking.c @@ -2905,3 +2905,155 @@ void BKE_tracking_dopesheet_update(MovieTracking *tracking) dopesheet->ok = true; } + +/* NOTE: Returns NULL if the track comes from camera object, */ +MovieTrackingObject *BKE_tracking_find_object_for_track( + const MovieTracking *tracking, + const MovieTrackingTrack *track) +{ + const ListBase *tracksbase = &tracking->tracks; + if (BLI_findindex(tracksbase, track) != -1) { + return NULL; + } + MovieTrackingObject *object = tracking->objects.first; + while (object != NULL) { + if (BLI_findindex(&object->tracks, track) != -1) { + return object; + } + object = object->next; + } + return NULL; +} + +ListBase *BKE_tracking_find_tracks_list_for_track( + MovieTracking *tracking, + const MovieTrackingTrack *track) +{ + MovieTrackingObject *object = BKE_tracking_find_object_for_track(tracking, + track); + if (object != NULL) { + return &object->tracks; + } + return &tracking->tracks; +} + +/* NOTE: Returns NULL if the track comes from camera object, */ +MovieTrackingObject *BKE_tracking_find_object_for_plane_track( + const MovieTracking *tracking, + const MovieTrackingPlaneTrack *plane_track) +{ + const ListBase *plane_tracks_base = &tracking->plane_tracks; + if (BLI_findindex(plane_tracks_base, plane_track) != -1) { + return NULL; + } + MovieTrackingObject *object = tracking->objects.first; + while (object != NULL) { + if (BLI_findindex(&object->plane_tracks, plane_track) != -1) { + return object; + } + object = object->next; + } + return NULL; +} + +ListBase *BKE_tracking_find_tracks_list_for_plane_track( + MovieTracking *tracking, + const MovieTrackingPlaneTrack *plane_track) +{ + MovieTrackingObject *object = + BKE_tracking_find_object_for_plane_track(tracking, plane_track); + if (object != NULL) { + return &object->plane_tracks; + } + return &tracking->plane_tracks; +} + +void BKE_tracking_get_rna_path_for_track( + const struct MovieTracking *tracking, + const struct MovieTrackingTrack *track, + char *rna_path, + size_t rna_path_len) +{ + MovieTrackingObject *object = + BKE_tracking_find_object_for_track(tracking, track); + char track_name_esc[MAX_NAME * 2]; + BLI_strescape(track_name_esc, track->name, sizeof(track_name_esc)); + if (object == NULL) { + BLI_snprintf(rna_path, rna_path_len, + "tracking.tracks[\"%s\"]", + track_name_esc); + } + else { + char object_name_esc[MAX_NAME * 2]; + BLI_strescape(object_name_esc, object->name, sizeof(object_name_esc)); + BLI_snprintf(rna_path, rna_path_len, + "tracking.objects[\"%s\"].tracks[\"%s\"]", + object_name_esc, + track_name_esc); + } +} + +void BKE_tracking_get_rna_path_prefix_for_track( + const struct MovieTracking *tracking, + const struct MovieTrackingTrack *track, + char *rna_path, + size_t rna_path_len) +{ + MovieTrackingObject *object = + BKE_tracking_find_object_for_track(tracking, track); + if (object == NULL) { + BLI_snprintf(rna_path, rna_path_len, "tracking.tracks"); + } + else { + char object_name_esc[MAX_NAME * 2]; + BLI_strescape(object_name_esc, object->name, sizeof(object_name_esc)); + BLI_snprintf(rna_path, rna_path_len, + "tracking.objects[\"%s\"]", + object_name_esc); + } +} + +void BKE_tracking_get_rna_path_for_plane_track( + const struct MovieTracking *tracking, + const struct MovieTrackingPlaneTrack *plane_track, + char *rna_path, + size_t rna_path_len) +{ + MovieTrackingObject *object = + BKE_tracking_find_object_for_plane_track(tracking, plane_track); + char track_name_esc[MAX_NAME * 2]; + BLI_strescape(track_name_esc, plane_track->name, sizeof(track_name_esc)); + if (object == NULL) { + BLI_snprintf(rna_path, rna_path_len, + "tracking.plane_tracks[\"%s\"]", + track_name_esc); + } + else { + char object_name_esc[MAX_NAME * 2]; + BLI_strescape(object_name_esc, object->name, sizeof(object_name_esc)); + BLI_snprintf(rna_path, rna_path_len, + "tracking.objects[\"%s\"].plane_tracks[\"%s\"]", + object_name_esc, + track_name_esc); + } +} + +void BKE_tracking_get_rna_path_prefix_for_plane_track( + const struct MovieTracking *tracking, + const struct MovieTrackingPlaneTrack *plane_track, + char *rna_path, + size_t rna_path_len) +{ + MovieTrackingObject *object = + BKE_tracking_find_object_for_plane_track(tracking, plane_track); + if (object == NULL) { + BLI_snprintf(rna_path, rna_path_len, "tracking.plane_tracks"); + } + else { + char object_name_esc[MAX_NAME * 2]; + BLI_strescape(object_name_esc, object->name, sizeof(object_name_esc)); + BLI_snprintf(rna_path, rna_path_len, + "tracking.objects[\"%s\"].plane_tracks", + object_name_esc); + } +} diff --git a/source/blender/blenlib/BLI_math_rotation.h b/source/blender/blenlib/BLI_math_rotation.h index e059327a490..1f206e5e234 100644 --- a/source/blender/blenlib/BLI_math_rotation.h +++ b/source/blender/blenlib/BLI_math_rotation.h @@ -97,6 +97,11 @@ float angle_normalized_qtqt(const float q1[4], const float q2[4]); float angle_qt(const float q[4]); float angle_qtqt(const float q1[4], const float q2[4]); +float angle_signed_normalized_qt(const float q[4]); +float angle_signed_normalized_qtqt(const float q1[4], const float q2[4]); +float angle_signed_qt(const float q[4]); +float angle_signed_qtqt(const float q1[4], const float q2[4]); + /* TODO: don't what this is, but it's not the same as mat3_to_quat */ void mat3_to_quat_is_ok(float q[4], float mat[3][3]); diff --git a/source/blender/blenlib/intern/math_bits_inline.c b/source/blender/blenlib/intern/math_bits_inline.c index d96cf969dae..37fdcd7878a 100644 --- a/source/blender/blenlib/intern/math_bits_inline.c +++ b/source/blender/blenlib/intern/math_bits_inline.c @@ -25,6 +25,10 @@ #ifndef __MATH_BITS_INLINE_C__ #define __MATH_BITS_INLINE_C__ +#ifdef _MSC_VER +# include <intrin.h> +#endif + #include "BLI_math_bits.h" MINLINE int bitscan_forward_i(int a) diff --git a/source/blender/blenlib/intern/math_rotation.c b/source/blender/blenlib/intern/math_rotation.c index 23bd5e60e22..29e7cf32ddc 100644 --- a/source/blender/blenlib/intern/math_rotation.c +++ b/source/blender/blenlib/intern/math_rotation.c @@ -511,6 +511,14 @@ void rotation_between_quats_to_quat(float q[4], const float q1[4], const float q } +/* -------------------------------------------------------------------- */ +/** \name Quaternion Angle + * + * Unlike the angle between vectors, this does NOT return the shortest angle. + * See signed functions below for this. + * + * \{ */ + float angle_normalized_qt(const float q[4]) { BLI_ASSERT_UNIT_QUAT(q); @@ -548,6 +556,64 @@ float angle_qtqt(const float q1[4], const float q2[4]) return angle_normalized_qtqt(quat1, quat2); } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Quaternion Angle (Signed) + * + * Angles with quaternion calculation can exceed 180d, + * Having signed versions of these functions allows 'fabsf(angle_signed_qtqt(...))' + * to give us the shortest angle between quaternions. + * With higher precision than subtracting pi afterwards. + * + * \{ */ + +float angle_signed_normalized_qt(const float q[4]) +{ + BLI_ASSERT_UNIT_QUAT(q); + if (q[0] >= 0.0f) { + return 2.0f * saacos(q[0]); + } + else { + return -2.0f * saacos(-q[0]); + } +} + +float angle_signed_normalized_qtqt(const float q1[4], const float q2[4]) +{ + if (dot_qtqt(q1, q2) >= 0.0f) { + return angle_normalized_qtqt(q1, q2); + } + else { + float q2_copy[4]; + negate_v4_v4(q2_copy, q2); + return -angle_normalized_qtqt(q1, q2_copy); + } +} + +float angle_signed_qt(const float q[4]) +{ + float tquat[4]; + + normalize_qt_qt(tquat, q); + + return angle_signed_normalized_qt(tquat); +} + +float angle_signed_qtqt(const float q1[4], const float q2[4]) +{ + if (dot_qtqt(q1, q2) >= 0.0f) { + return angle_qtqt(q1, q2); + } + else { + float q2_copy[4]; + negate_v4_v4(q2_copy, q2); + return -angle_qtqt(q1, q2_copy); + } +} + +/** \} */ + void vec_to_quat(float q[4], const float vec[3], short axis, const short upflag) { const float eps = 1e-4f; diff --git a/source/blender/blenloader/intern/versioning_280.c b/source/blender/blenloader/intern/versioning_280.c index 944ddf1763d..31d3b48aee0 100644 --- a/source/blender/blenloader/intern/versioning_280.c +++ b/source/blender/blenloader/intern/versioning_280.c @@ -45,6 +45,7 @@ #include "DNA_lightprobe_types.h" #include "DNA_material_types.h" #include "DNA_mesh_types.h" +#include "DNA_particle_types.h" #include "DNA_scene_types.h" #include "DNA_screen_types.h" #include "DNA_view3d_types.h" @@ -351,7 +352,7 @@ void do_versions_after_linking_280(Main *main) view_layer->pass_xor = srl->pass_xor; view_layer->pass_alpha_threshold = srl->pass_alpha_threshold; - BKE_freestyle_config_free(&view_layer->freestyle_config); + BKE_freestyle_config_free(&view_layer->freestyle_config, true); view_layer->freestyle_config = srl->freestyleConfig; view_layer->id_properties = srl->prop; @@ -424,7 +425,7 @@ void do_versions_after_linking_280(Main *main) IDP_FreeProperty(srl->prop); MEM_freeN(srl->prop); } - BKE_freestyle_config_free(&srl->freestyleConfig); + BKE_freestyle_config_free(&srl->freestyleConfig, true); } } BLI_freelistN(&scene->r.layers); @@ -481,11 +482,6 @@ void do_versions_after_linking_280(Main *main) base->lay = base->object->lay; } - /* Fallback name if only one layer was found in the original file */ - if (BLI_listbase_is_single(&sc_master->scene_collections)) { - BKE_collection_rename(scene, sc_master->scene_collections.first, "Default Collection"); - } - /* remove bases once and for all */ for (Base *base = scene->base.first; base; base = base->next) { id_us_min(&base->object->id); @@ -544,7 +540,7 @@ void do_versions_after_linking_280(Main *main) IDP_FreeProperty(srl->prop); MEM_freeN(srl->prop); } - BKE_freestyle_config_free(&srl->freestyleConfig); + BKE_freestyle_config_free(&srl->freestyleConfig, true); } BLI_freelistN(&scene->r.layers); } @@ -602,6 +598,38 @@ void do_versions_after_linking_280(Main *main) } } } + + { + for (Object *object = main->object.first; object; object = object->id.next) { +#ifndef VERSION_280_SUBVERSION_4 + /* If any object already has an initialized value for + * duplicator_visibility_flag it means we've already doversioned it. + * TODO(all) remove the VERSION_280_SUBVERSION_4 code once the subversion was bumped. */ + if (object->duplicator_visibility_flag != 0) { + break; + } +#endif + if (object->particlesystem.first) { + object->duplicator_visibility_flag = OB_DUPLI_FLAG_VIEWPORT; + for (ParticleSystem *psys = object->particlesystem.first; psys; psys=psys->next) { + if (psys->part->draw & PART_DRAW_EMITTER) { + object->duplicator_visibility_flag |= OB_DUPLI_FLAG_RENDER; +#ifndef VERSION_280_SUBVERSION_4 + psys->part->draw &= ~PART_DRAW_EMITTER; +#else + break; +#endif + } + } + } + else if (object->transflag & OB_DUPLI){ + object->duplicator_visibility_flag = OB_DUPLI_FLAG_VIEWPORT; + } + else { + object->duplicator_visibility_flag = OB_DUPLI_FLAG_VIEWPORT | OB_DUPLI_FLAG_RENDER; + } + } + } } static void do_version_layer_collections_idproperties(ListBase *lb) diff --git a/source/blender/bmesh/tools/bmesh_bevel.c b/source/blender/bmesh/tools/bmesh_bevel.c index 2c6213dacce..d00d0d508c7 100644 --- a/source/blender/bmesh/tools/bmesh_bevel.c +++ b/source/blender/bmesh/tools/bmesh_bevel.c @@ -718,14 +718,18 @@ static void slide_dist(EdgeHalf *e, BMVert *v, float d, float slideco[3]) /* Is co not on the edge e? if not, return the closer end of e in ret_closer_v */ static bool is_outside_edge(EdgeHalf *e, const float co[3], BMVert **ret_closer_v) { - float d_squared; - - d_squared = dist_squared_to_line_segment_v3(co, e->e->v1->co, e->e->v2->co); - if (d_squared > BEVEL_EPSILON_BIG * BEVEL_EPSILON_BIG) { - if (len_squared_v3v3(co, e->e->v1->co) > len_squared_v3v3(co, e->e->v2->co)) - *ret_closer_v = e->e->v2; - else - *ret_closer_v = e->e->v1; + float h[3], u[3], lambda, lenu, *l1 = e->e->v1->co; + + sub_v3_v3v3(u, e->e->v2->co, l1); + sub_v3_v3v3(h, co, l1); + lenu = normalize_v3(u); + lambda = dot_v3v3(u, h); + if (lambda <= -BEVEL_EPSILON_BIG * lenu) { + *ret_closer_v = e->e->v1; + return true; + } + else if (lambda >= (1.0f + BEVEL_EPSILON_BIG) * lenu) { + *ret_closer_v = e->e->v2; return true; } else { diff --git a/source/blender/depsgraph/CMakeLists.txt b/source/blender/depsgraph/CMakeLists.txt index 9495321a0ff..c42d06bd0a2 100644 --- a/source/blender/depsgraph/CMakeLists.txt +++ b/source/blender/depsgraph/CMakeLists.txt @@ -53,13 +53,17 @@ set(SRC intern/builder/deg_builder_relations_rig.cc intern/builder/deg_builder_relations_view_layer.cc intern/builder/deg_builder_transitive.cc - intern/debug/deg_debug_graphviz.cc + intern/debug/deg_debug_relations_graphviz.cc + intern/debug/deg_debug_stats_gnuplot.cc intern/eval/deg_eval.cc intern/eval/deg_eval_copy_on_write.cc intern/eval/deg_eval_flush.cc + intern/eval/deg_eval_stats.cc intern/nodes/deg_node.cc intern/nodes/deg_node_component.cc + intern/nodes/deg_node_id.cc intern/nodes/deg_node_operation.cc + intern/nodes/deg_node_time.cc intern/depsgraph.cc intern/depsgraph_build.cc intern/depsgraph_debug.cc @@ -85,9 +89,12 @@ set(SRC intern/eval/deg_eval.h intern/eval/deg_eval_copy_on_write.h intern/eval/deg_eval_flush.h + intern/eval/deg_eval_stats.h intern/nodes/deg_node.h intern/nodes/deg_node_component.h + intern/nodes/deg_node_id.h intern/nodes/deg_node_operation.h + intern/nodes/deg_node_time.h intern/depsgraph.h intern/depsgraph_intern.h intern/depsgraph_types.h diff --git a/source/blender/depsgraph/DEG_depsgraph.h b/source/blender/depsgraph/DEG_depsgraph.h index aaa6142fa21..4f45768cbea 100644 --- a/source/blender/depsgraph/DEG_depsgraph.h +++ b/source/blender/depsgraph/DEG_depsgraph.h @@ -140,10 +140,10 @@ void DEG_graph_on_visible_update(struct Main *bmain, Depsgraph *depsgraph); void DEG_on_visible_update(struct Main *bmain, const bool do_time); /* Tag given ID for an update in all the dependency graphs. */ -enum { +typedef enum eDepsgraph_Tag { /* Object transformation changed, corresponds to OB_RECALC_OB. */ DEG_TAG_TRANSFORM = (1 << 0), - /* Object geoemtry changed, corresponds to OB_RECALC_DATA. */ + /* Object geometry changed, corresponds to OB_RECALC_DATA. */ DEG_TAG_GEOMETRY = (1 << 1), /* Time changed and animation is to be re-evaluated, OB_RECALC_TIME. */ DEG_TAG_TIME = (1 << 2), @@ -168,7 +168,7 @@ enum { DEG_TAG_BASE_FLAGS_UPDATE = (1 << 11), /* Only inform editors about the change. Don't modify datablock itself. */ DEG_TAG_EDITORS_UPDATE = (1 << 12), -}; +} eDepsgraph_Tag; void DEG_id_tag_update(struct ID *id, int flag); void DEG_id_tag_update_ex(struct Main *bmain, struct ID *id, int flag); diff --git a/source/blender/depsgraph/DEG_depsgraph_debug.h b/source/blender/depsgraph/DEG_depsgraph_debug.h index bd03874436b..363749dab26 100644 --- a/source/blender/depsgraph/DEG_depsgraph_debug.h +++ b/source/blender/depsgraph/DEG_depsgraph_debug.h @@ -53,7 +53,14 @@ void DEG_stats_simple(const struct Depsgraph *graph, /* ************************************************ */ /* Diagram-Based Graph Debugging */ -void DEG_debug_graphviz(const struct Depsgraph *graph, FILE *stream, const char *label, bool show_eval); +void DEG_debug_relations_graphviz(const struct Depsgraph *graph, + FILE *stream, + const char *label); + +void DEG_debug_stats_gnuplot(const struct Depsgraph *graph, + FILE *stream, + const char *label, + const char *output_filename); /* ************************************************ */ diff --git a/source/blender/depsgraph/DEG_depsgraph_query.h b/source/blender/depsgraph/DEG_depsgraph_query.h index c782a91f76e..83fb100436c 100644 --- a/source/blender/depsgraph/DEG_depsgraph_query.h +++ b/source/blender/depsgraph/DEG_depsgraph_query.h @@ -77,12 +77,18 @@ enum { DEG_ITER_OBJECT_FLAG_DUPLI = (1 << 4), }; +typedef enum eDepsObjectIteratorMode { + DEG_ITER_OBJECT_MODE_VIEWPORT = 0, + DEG_ITER_OBJECT_MODE_RENDER = 1, +} eDepsObjectIteratorMode; + typedef struct DEGObjectIterData { struct Depsgraph *graph; struct Scene *scene; struct EvaluationContext eval_ctx; int flag; + eDepsObjectIteratorMode mode; /* **** Iteration over dupli-list. *** */ @@ -115,10 +121,11 @@ void DEG_iterator_objects_end(struct BLI_Iterator *iter); * Although they are available they have no overrides (collection_properties) * and will crash if you try to access it. */ -#define DEG_OBJECT_ITER(graph_, instance_, flag_) \ +#define DEG_OBJECT_ITER(graph_, instance_, mode_, flag_) \ { \ DEGObjectIterData data_ = { \ .graph = (graph_), \ + .mode = (mode_), \ .flag = (flag_), \ }; \ \ @@ -134,8 +141,8 @@ void DEG_iterator_objects_end(struct BLI_Iterator *iter); /** * Depsgraph objects iterator for draw manager and final render */ -#define DEG_OBJECT_ITER_FOR_RENDER_ENGINE(graph_, instance_) \ - DEG_OBJECT_ITER(graph_, instance_, \ +#define DEG_OBJECT_ITER_FOR_RENDER_ENGINE(graph_, instance_, mode_) \ + DEG_OBJECT_ITER(graph_, instance_, mode_, \ DEG_ITER_OBJECT_FLAG_LINKED_DIRECTLY | \ DEG_ITER_OBJECT_FLAG_LINKED_VIA_SET | \ DEG_ITER_OBJECT_FLAG_VISIBLE | \ diff --git a/source/blender/depsgraph/intern/builder/deg_builder.cc b/source/blender/depsgraph/intern/builder/deg_builder.cc index 1e906d454ac..2fcad233044 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder.cc @@ -36,6 +36,7 @@ #include "intern/depsgraph.h" #include "intern/depsgraph_types.h" #include "intern/nodes/deg_node.h" +#include "intern/nodes/deg_node_id.h" #include "util/deg_util_foreach.h" diff --git a/source/blender/depsgraph/intern/builder/deg_builder_cycle.cc b/source/blender/depsgraph/intern/builder/deg_builder_cycle.cc index 3eed0697b5e..e30b9b44490 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_cycle.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_cycle.cc @@ -46,17 +46,38 @@ namespace DEG { -void deg_graph_detect_cycles(Depsgraph *graph) +typedef enum eCyclicCheckVisitedState { + /* Not is not visited at all during traversal. */ + NODE_NOT_VISITED = 0, + /* Node has been visited during traversal and not in current stack. */ + NODE_VISITED = 1, + /* Node has been visited during traversal and is in current stack. */ + NODE_IN_STACK = 2, +} eCyclicCheckVisitedState; + +BLI_INLINE void set_node_visited_state(DepsNode *node, + eCyclicCheckVisitedState state) { - enum { - /* Not is not visited at all during traversal. */ - NODE_NOT_VISITED = 0, - /* Node has been visited during traversal and not in current stack. */ - NODE_VISITED = 1, - /* Node has been visited during traversal and is in current stack. */ - NODE_IN_STACK = 2, - }; + node->done = (node->done & ~0x3) | (int)state; +} + +BLI_INLINE eCyclicCheckVisitedState get_node_visited_state(DepsNode *node) +{ + return (eCyclicCheckVisitedState)(node->done & 0x3); +} + +BLI_INLINE void set_node_num_visited_children(DepsNode *node, int num_children) +{ + node->done = (node->done & 0x3) | (num_children << 2); +} + +BLI_INLINE int get_node_num_visited_children(DepsNode *node) +{ + return node->done >> 2; +} +void deg_graph_detect_cycles(Depsgraph *graph) +{ struct StackEntry { OperationDepsNode *node; StackEntry *from; @@ -73,29 +94,31 @@ void deg_graph_detect_cycles(Depsgraph *graph) has_inlinks = true; } } + node->done = 0; if (has_inlinks == false) { StackEntry entry; entry.node = node; entry.from = NULL; entry.via_relation = NULL; BLI_stack_push(traversal_stack, &entry); - node->tag = NODE_IN_STACK; + set_node_visited_state(node, NODE_IN_STACK); } else { - node->tag = NODE_NOT_VISITED; + set_node_visited_state(node, NODE_NOT_VISITED); } - node->done = 0; } while (!BLI_stack_is_empty(traversal_stack)) { StackEntry *entry = (StackEntry *)BLI_stack_peek(traversal_stack); OperationDepsNode *node = entry->node; bool all_child_traversed = true; - for (int i = node->done; i < node->outlinks.size(); ++i) { + const int num_visited = get_node_num_visited_children(node); + for (int i = num_visited; i < node->outlinks.size(); ++i) { DepsRelation *rel = node->outlinks[i]; if (rel->to->type == DEG_NODE_TYPE_OPERATION) { OperationDepsNode *to = (OperationDepsNode *)rel->to; - if (to->tag == NODE_IN_STACK) { + eCyclicCheckVisitedState to_state = get_node_visited_state(to); + if (to_state == NODE_IN_STACK) { printf("Dependency cycle detected:\n"); printf(" '%s' depends on '%s' through '%s'\n", to->full_identifier().c_str(), @@ -114,21 +137,21 @@ void deg_graph_detect_cycles(Depsgraph *graph) /* TODO(sergey): So called russian roulette cycle solver. */ rel->flag |= DEPSREL_FLAG_CYCLIC; } - else if (to->tag == NODE_NOT_VISITED) { + else if (to_state == NODE_NOT_VISITED) { StackEntry new_entry; new_entry.node = to; new_entry.from = entry; new_entry.via_relation = rel; BLI_stack_push(traversal_stack, &new_entry); - to->tag = NODE_IN_STACK; + set_node_visited_state(node, NODE_IN_STACK); all_child_traversed = false; - node->done = i; + set_node_num_visited_children(node, i); break; } } } if (all_child_traversed) { - node->tag = NODE_VISITED; + set_node_visited_state(node, NODE_VISITED); BLI_stack_discard(traversal_stack); } } diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc b/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc index 68440bb4ff1..95f710616c5 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc @@ -108,9 +108,11 @@ extern "C" { #include "intern/eval/deg_eval_copy_on_write.h" #include "intern/nodes/deg_node.h" #include "intern/nodes/deg_node_component.h" +#include "intern/nodes/deg_node_id.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 { diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc index dd41d6df7db..57fca7365d1 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc @@ -104,7 +104,9 @@ extern "C" { #include "intern/nodes/deg_node.h" #include "intern/nodes/deg_node_component.h" +#include "intern/nodes/deg_node_id.h" #include "intern/nodes/deg_node_operation.h" +#include "intern/nodes/deg_node_time.h" #include "intern/depsgraph_intern.h" #include "intern/depsgraph_types.h" @@ -1453,7 +1455,7 @@ void DepsgraphRelationBuilder::build_particles(Object *object) if (part->dup_ob->type == OB_MBALL) { ComponentKey dup_geometry_key(&part->dup_ob->id, DEG_NODE_TYPE_GEOMETRY); - add_relation(psys_key, + add_relation(obdata_ubereval_key, dup_geometry_key, "Particle MBall Visualization"); } diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations_view_layer.cc b/source/blender/depsgraph/intern/builder/deg_builder_relations_view_layer.cc index 29cff0cb28d..9b3e46df69a 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_relations_view_layer.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_relations_view_layer.cc @@ -59,6 +59,7 @@ extern "C" { #include "intern/nodes/deg_node.h" #include "intern/nodes/deg_node_component.h" +#include "intern/nodes/deg_node_id.h" #include "intern/nodes/deg_node_operation.h" #include "intern/depsgraph_intern.h" diff --git a/source/blender/depsgraph/intern/builder/deg_builder_transitive.cc b/source/blender/depsgraph/intern/builder/deg_builder_transitive.cc index b12af21fc8d..7731b76c6b9 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_transitive.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_transitive.cc @@ -37,6 +37,7 @@ #include "intern/nodes/deg_node_operation.h" #include "intern/depsgraph.h" +#include "intern/depsgraph_intern.h" #include "util/deg_util_foreach.h" @@ -79,13 +80,13 @@ static void deg_graph_tag_paths_recursive(DepsNode *node) void deg_graph_transitive_reduction(Depsgraph *graph) { + int num_removed_relations = 0; foreach (OperationDepsNode *target, graph->operations) { /* Clear tags. */ foreach (OperationDepsNode *node, graph->operations) { node->done = 0; } - - /* mark nodes from which we can reach the target + /* Mark nodes from which we can reach the target * start with children, so the target node and direct children are not * flagged. */ @@ -93,27 +94,30 @@ void deg_graph_transitive_reduction(Depsgraph *graph) foreach (DepsRelation *rel, target->inlinks) { deg_graph_tag_paths_recursive(rel->from); } - /* Remove redundant paths to the target. */ for (DepsNode::Relations::const_iterator it_rel = target->inlinks.begin(); it_rel != target->inlinks.end(); ) { DepsRelation *rel = *it_rel; - /* Increment in advance, so we can safely remove the relation. */ - ++it_rel; - if (rel->from->type == DEG_NODE_TYPE_TIMESOURCE) { /* HACK: time source nodes don't get "done" flag set/cleared. */ /* TODO: there will be other types in future, so iterators above * need modifying. */ + ++it_rel; } else if (rel->from->done & OP_REACHABLE) { + rel->unlink(); OBJECT_GUARDED_DELETE(rel, DepsRelation); + ++num_removed_relations; + } + else { + ++it_rel; } } } + DEG_DEBUG_PRINTF("Removed %d relations\n", num_removed_relations); } } // namespace DEG diff --git a/source/blender/depsgraph/intern/debug/deg_debug_graphviz.cc b/source/blender/depsgraph/intern/debug/deg_debug_relations_graphviz.cc index bd3d74b307b..827bb4d10ad 100644 --- a/source/blender/depsgraph/intern/debug/deg_debug_graphviz.cc +++ b/source/blender/depsgraph/intern/debug/deg_debug_relations_graphviz.cc @@ -24,7 +24,7 @@ * ***** END GPL LICENSE BLOCK ***** */ -/** \file blender/depsgraph/intern/debug/deg_debug_graphviz.cc +/** \file blender/depsgraph/intern/debug/deg_debug_relations_graphviz.cc * \ingroup depsgraph * * Implementation of tools for debugging the depsgraph @@ -41,6 +41,9 @@ extern "C" { #include "DEG_depsgraph_debug.h" #include "intern/depsgraph_intern.h" +#include "intern/nodes/deg_node_id.h" +#include "intern/nodes/deg_node_time.h" + #include "util/deg_util_foreach.h" /* ****************** */ @@ -115,7 +118,7 @@ static int deg_debug_node_color_index(const DepsNode *node) break; } /* Do others based on class. */ - switch (node->tclass) { + switch (node->get_class()) { case DEG_NODE_CLASS_OPERATION: return 4; case DEG_NODE_CLASS_COMPONENT: @@ -139,7 +142,6 @@ static int deg_debug_node_color_index(const DepsNode *node) struct DebugContext { FILE *file; bool show_tags; - bool show_eval_priority; }; static void deg_debug_fprintf(const DebugContext &ctx, const char *fmt, ...) ATTR_PRINTF_FORMAT(2, 3); @@ -202,7 +204,7 @@ static void deg_debug_graphviz_node_color(const DebugContext &ctx, const char *color_update = "dodgerblue3"; const char *color = color_default; if (ctx.show_tags) { - if (node->tclass == DEG_NODE_CLASS_OPERATION) { + if (node->get_class() == DEG_NODE_CLASS_OPERATION) { OperationDepsNode *op_node = (OperationDepsNode *)node; if (op_node->flag & DEPSOP_FLAG_DIRECTLY_MODIFIED) { color = color_modified; @@ -223,7 +225,7 @@ static void deg_debug_graphviz_node_penwidth(const DebugContext &ctx, float penwidth_update = 4.0f; float penwidth = penwidth_default; if (ctx.show_tags) { - if (node->tclass == DEG_NODE_CLASS_OPERATION) { + if (node->get_class() == DEG_NODE_CLASS_OPERATION) { OperationDepsNode *op_node = (OperationDepsNode *)node; if (op_node->flag & DEPSOP_FLAG_DIRECTLY_MODIFIED) { penwidth = penwidth_modified; @@ -261,14 +263,14 @@ static void deg_debug_graphviz_node_style(const DebugContext &ctx, const DepsNod { const char *base_style = "filled"; /* default style */ if (ctx.show_tags) { - if (node->tclass == DEG_NODE_CLASS_OPERATION) { + if (node->get_class() == DEG_NODE_CLASS_OPERATION) { OperationDepsNode *op_node = (OperationDepsNode *)node; if (op_node->flag & (DEPSOP_FLAG_DIRECTLY_MODIFIED | DEPSOP_FLAG_NEEDS_UPDATE)) { base_style = "striped"; } } } - switch (node->tclass) { + switch (node->get_class()) { case DEG_NODE_CLASS_GENERIC: deg_debug_fprintf(ctx, "\"%s\"", base_style); break; @@ -286,22 +288,11 @@ static void deg_debug_graphviz_node_single(const DebugContext &ctx, { const char *shape = "box"; string name = node->identifier(); - float priority = -1.0f; - if (ctx.show_eval_priority && node->tclass == DEG_NODE_CLASS_OPERATION) { - priority = ((OperationDepsNode *)node)->eval_priority; - } deg_debug_fprintf(ctx, "// %s\n", name.c_str()); deg_debug_fprintf(ctx, "\"node_%p\"", node); deg_debug_fprintf(ctx, "["); // deg_debug_fprintf(ctx, "label=<<B>%s</B>>", name); - if (priority >= 0.0f) { - deg_debug_fprintf(ctx, "label=<%s<BR/>(<I>%.2f</I>)>", - name.c_str(), - priority); - } - else { - deg_debug_fprintf(ctx, "label=<%s>", name.c_str()); - } + deg_debug_fprintf(ctx, "label=<%s>", name.c_str()); deg_debug_fprintf(ctx, ",fontname=\"%s\"", deg_debug_graphviz_fontname); deg_debug_fprintf(ctx, ",fontsize=%f", deg_debug_graphviz_node_label_size); deg_debug_fprintf(ctx, ",shape=%s", shape); @@ -436,7 +427,7 @@ static bool deg_debug_graphviz_is_cluster(const DepsNode *node) static bool deg_debug_graphviz_is_owner(const DepsNode *node, const DepsNode *other) { - switch (node->tclass) { + switch (node->get_class()) { case DEG_NODE_CLASS_COMPONENT: { ComponentDepsNode *comp_node = (ComponentDepsNode *)node; @@ -526,7 +517,9 @@ static void deg_debug_graphviz_graph_relations(const DebugContext &ctx, } // namespace DEG -void DEG_debug_graphviz(const Depsgraph *graph, FILE *f, const char *label, bool show_eval) +void DEG_debug_relations_graphviz(const Depsgraph *graph, + FILE *f, + const char *label) { if (!graph) { return; @@ -536,8 +529,6 @@ void DEG_debug_graphviz(const Depsgraph *graph, FILE *f, const char *label, bool DEG::DebugContext ctx; ctx.file = f; - ctx.show_tags = show_eval; - ctx.show_eval_priority = show_eval; DEG::deg_debug_fprintf(ctx, "digraph depgraph {" NL); DEG::deg_debug_fprintf(ctx, "rankdir=LR;" NL); diff --git a/source/blender/depsgraph/intern/debug/deg_debug_stats_gnuplot.cc b/source/blender/depsgraph/intern/debug/deg_debug_stats_gnuplot.cc new file mode 100644 index 00000000000..35888f8d5e3 --- /dev/null +++ b/source/blender/depsgraph/intern/debug/deg_debug_stats_gnuplot.cc @@ -0,0 +1,157 @@ +/* + * ***** 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) 2017 Blender Foundation. + * All rights reserved. + * + * Original Author: Sergey Sharybin + * Contributor(s): None Yet + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/depsgraph/intern/debug/deg_debug_stats_gnuplot.cc + * \ingroup depsgraph + */ + +#include "DEG_depsgraph_debug.h" + +#include <algorithm> +#include <cstdarg> + +#include "BLI_compiler_attrs.h" +#include "BLI_math_base.h" + +#include "intern/depsgraph.h" +#include "intern/nodes/deg_node_id.h" + +#include "util/deg_util_foreach.h" + +extern "C" { +#include "DNA_ID.h" +} /* extern "C" */ + +#define NL "\r\n" + +namespace DEG { +namespace { + +struct DebugContext { + FILE *file; + const Depsgraph *graph; + const char *label; + const char *output_filename; +}; + +struct StatsEntry { + const IDDepsNode *id_node; + double time; +}; + +/* TODO(sergey): De-duplicate with graphviz relation debugger. */ +static void deg_debug_fprintf(const DebugContext &ctx, + const char *fmt, + ...) ATTR_PRINTF_FORMAT(2, 3); +static void deg_debug_fprintf(const DebugContext &ctx, const char *fmt, ...) +{ + va_list args; + va_start(args, fmt); + vfprintf(ctx.file, fmt, args); + va_end(args); +} + +BLI_INLINE double get_node_time(const DebugContext& /*ctx*/, + const DepsNode *node) +{ + // TODO(sergey): Figure out a nice way to define which exact time + // we want to show. + return node->stats.current_time; +} + +bool stat_entry_comparator(const StatsEntry& a, const StatsEntry& b) +{ + return a.time < b.time; +} + +void write_stats_data(const DebugContext& ctx) +{ + // Fill in array of all stats which are to be displayed. + vector<StatsEntry> stats; + stats.reserve(ctx.graph->id_nodes.size()); + foreach (const IDDepsNode *id_node, ctx.graph->id_nodes) { + const double time = get_node_time(ctx, id_node); + if (time == 0.0) { + continue; + } + StatsEntry entry; + entry.id_node = id_node; + entry.time = time; + stats.push_back(entry); + } + // Sort the data. + std::sort(stats.begin(), stats.end(), stat_entry_comparator); + // We limit number of entries, otherwise things become unreadable. + stats.resize(min_ii(stats.size(), 32)); + // Print data to the file stream. + deg_debug_fprintf(ctx, "$data << EOD" NL); + foreach (const StatsEntry& entry, stats) { + deg_debug_fprintf(ctx, "\"%s\",%f" NL, + entry.id_node->id_orig->name + 2, + entry.time); + } + deg_debug_fprintf(ctx, "EOD" NL); +} + +void deg_debug_stats_gnuplot(const DebugContext& ctx) +{ + // Data itself. + write_stats_data(ctx); + // Optional label. + if (ctx.label && ctx.label[0]) { + deg_debug_fprintf(ctx, "set title \"%s\"" NL, ctx.label); + } + // Rest of the commands. + // TODO(sergey): Need to decide on the resolution somehow. + deg_debug_fprintf(ctx, "set terminal pngcairo size 1920,1080" NL); + deg_debug_fprintf(ctx, "set output \"%s\"" NL, ctx.output_filename); + deg_debug_fprintf(ctx, "set grid" NL); + deg_debug_fprintf(ctx, "set datafile separator ','" NL); + deg_debug_fprintf(ctx, "set style fill solid" NL); + deg_debug_fprintf(ctx, "plot \"$data\" using " \ + "($2*0.5):0:($2*0.5):(0.2):yticlabels(1) " + "with boxxyerrorbars t '' lt rgb \"#406090\"" NL); + +} + +} // namespace +} // namespace DEG + +void DEG_debug_stats_gnuplot(const Depsgraph *depsgraph, + FILE *f, + const char *label, + const char *output_filename) +{ + if (depsgraph == NULL) { + return; + } + DEG::DebugContext ctx; + ctx.file = f; + ctx.graph = (DEG::Depsgraph *)depsgraph; + ctx.label = label; + ctx.output_filename = output_filename; + DEG::deg_debug_stats_gnuplot(ctx); +} diff --git a/source/blender/depsgraph/intern/depsgraph.cc b/source/blender/depsgraph/intern/depsgraph.cc index 995157f5c9a..45013bb1bcd 100644 --- a/source/blender/depsgraph/intern/depsgraph.cc +++ b/source/blender/depsgraph/intern/depsgraph.cc @@ -49,6 +49,7 @@ extern "C" { #include "RNA_access.h" } +#include <algorithm> #include <cstring> #include "DEG_depsgraph.h" @@ -57,7 +58,9 @@ extern "C" { #include "intern/nodes/deg_node.h" #include "intern/nodes/deg_node_component.h" +#include "intern/nodes/deg_node_id.h" #include "intern/nodes/deg_node_operation.h" +#include "intern/nodes/deg_node_time.h" #include "intern/depsgraph_intern.h" #include "util/deg_util_foreach.h" @@ -79,6 +82,14 @@ namespace DEG { static DEG_EditorUpdateIDCb deg_editor_update_id_cb = NULL; static DEG_EditorUpdateSceneCb deg_editor_update_scene_cb = NULL; +/* TODO(sergey): Find a better place for this. */ +template <typename T> +static void remove_from_vector(vector<T> *vector, const T& value) +{ + vector->erase(std::remove(vector->begin(), vector->end(), value), + vector->end()); +} + Depsgraph::Depsgraph() : time_source(NULL), need_update(true), @@ -431,7 +442,15 @@ DepsRelation::DepsRelation(DepsNode *from, DepsRelation::~DepsRelation() { /* Sanity check. */ - BLI_assert(this->from && this->to); + BLI_assert(from != NULL && to != NULL); +} + +void DepsRelation::unlink() +{ + /* Sanity check. */ + BLI_assert(from != NULL && to != NULL); + remove_from_vector(&from->outlinks, this); + remove_from_vector(&to->inlinks, this); } /* Low level tagging -------------------------------------- */ diff --git a/source/blender/depsgraph/intern/depsgraph.h b/source/blender/depsgraph/intern/depsgraph.h index 8a34be0c7a2..f18b93c9807 100644 --- a/source/blender/depsgraph/intern/depsgraph.h +++ b/source/blender/depsgraph/intern/depsgraph.h @@ -87,6 +87,8 @@ struct DepsRelation { const char *description); ~DepsRelation(); + + void unlink(); }; /* ********* */ diff --git a/source/blender/depsgraph/intern/depsgraph_build.cc b/source/blender/depsgraph/intern/depsgraph_build.cc index 57153279acb..5b07630240d 100644 --- a/source/blender/depsgraph/intern/depsgraph_build.cc +++ b/source/blender/depsgraph/intern/depsgraph_build.cc @@ -68,6 +68,7 @@ extern "C" { #include "intern/nodes/deg_node.h" #include "intern/nodes/deg_node_component.h" +#include "intern/nodes/deg_node_id.h" #include "intern/nodes/deg_node_operation.h" #include "intern/depsgraph_types.h" diff --git a/source/blender/depsgraph/intern/depsgraph_debug.cc b/source/blender/depsgraph/intern/depsgraph_debug.cc index 42c1cf861eb..e8d166532ad 100644 --- a/source/blender/depsgraph/intern/depsgraph_debug.cc +++ b/source/blender/depsgraph/intern/depsgraph_debug.cc @@ -42,6 +42,9 @@ extern "C" { #include "DEG_depsgraph_build.h" #include "intern/depsgraph_intern.h" +#include "intern/nodes/deg_node_id.h" +#include "intern/nodes/deg_node_time.h" + #include "util/deg_util_foreach.h" bool DEG_debug_compare(const struct Depsgraph *graph1, diff --git a/source/blender/depsgraph/intern/depsgraph_eval.cc b/source/blender/depsgraph/intern/depsgraph_eval.cc index 2ed403c463a..ad1a850a807 100644 --- a/source/blender/depsgraph/intern/depsgraph_eval.cc +++ b/source/blender/depsgraph/intern/depsgraph_eval.cc @@ -48,12 +48,10 @@ extern "C" { #include "intern/nodes/deg_node.h" #include "intern/nodes/deg_node_operation.h" +#include "intern/nodes/deg_node_time.h" #include "intern/depsgraph.h" -/* Unfinished and unused, and takes quite some pre-processing time. */ -#undef USE_EVAL_PRIORITY - /* ****************** */ /* Evaluation Context */ diff --git a/source/blender/depsgraph/intern/depsgraph_intern.h b/source/blender/depsgraph/intern/depsgraph_intern.h index 4484d4ed94f..df5e51a3910 100644 --- a/source/blender/depsgraph/intern/depsgraph_intern.h +++ b/source/blender/depsgraph/intern/depsgraph_intern.h @@ -60,8 +60,8 @@ namespace DEG { /* Typeinfo Struct (nti) */ struct DepsNodeFactory { virtual eDepsNode_Type type() const = 0; - virtual eDepsNode_Class tclass() const = 0; virtual const char *tname() const = 0; + virtual int id_recalc_tag() const = 0; virtual DepsNode *create_node(const ID *id, const char *subdata, @@ -71,8 +71,8 @@ struct DepsNodeFactory { template <class NodeType> struct DepsNodeFactoryImpl : public DepsNodeFactory { eDepsNode_Type type() const { return NodeType::typeinfo.type; } - eDepsNode_Class tclass() const { return NodeType::typeinfo.tclass; } const char *tname() const { return NodeType::typeinfo.tname; } + int id_recalc_tag() const { return NodeType::typeinfo.id_recalc_tag; } DepsNode *create_node(const ID *id, const char *subdata, const char *name) const { @@ -80,7 +80,6 @@ struct DepsNodeFactoryImpl : public DepsNodeFactory { /* populate base node settings */ node->type = type(); - node->tclass = tclass(); if (name[0] != '\0') { /* set name if provided ... */ @@ -113,10 +112,6 @@ void deg_editors_id_update(const DEGEditorUpdateContext *update_ctx, void deg_editors_scene_update(const DEGEditorUpdateContext *update_ctx, bool updated); -/* Tagging helpers ------------------------------------------------------ */ - -void lib_id_recalc_tag(struct Main *bmain, struct ID *id); - #define DEG_DEBUG_PRINTF(...) \ do { \ if (G.debug & G_DEBUG_DEPSGRAPH) { \ diff --git a/source/blender/depsgraph/intern/depsgraph_query.cc b/source/blender/depsgraph/intern/depsgraph_query.cc index 6892bdaa178..98bf335f89e 100644 --- a/source/blender/depsgraph/intern/depsgraph_query.cc +++ b/source/blender/depsgraph/intern/depsgraph_query.cc @@ -46,6 +46,7 @@ extern "C" { #include "DEG_depsgraph_query.h" #include "intern/depsgraph_intern.h" +#include "intern/nodes/deg_node_id.h" bool DEG_id_type_tagged(Main *bmain, short id_type) { diff --git a/source/blender/depsgraph/intern/depsgraph_query_foreach.cc b/source/blender/depsgraph/intern/depsgraph_query_foreach.cc index b1353f528bc..e6692cf49b3 100644 --- a/source/blender/depsgraph/intern/depsgraph_query_foreach.cc +++ b/source/blender/depsgraph/intern/depsgraph_query_foreach.cc @@ -50,6 +50,7 @@ extern "C" { #include "intern/nodes/deg_node.h" #include "intern/nodes/deg_node_component.h" +#include "intern/nodes/deg_node_id.h" #include "intern/nodes/deg_node_operation.h" #include "util/deg_util_foreach.h" diff --git a/source/blender/depsgraph/intern/depsgraph_query_iter.cc b/source/blender/depsgraph/intern/depsgraph_query_iter.cc index a7f37575ff6..42d512d473c 100644 --- a/source/blender/depsgraph/intern/depsgraph_query_iter.cc +++ b/source/blender/depsgraph/intern/depsgraph_query_iter.cc @@ -50,6 +50,8 @@ extern "C" { #include "intern/depsgraph_intern.h" #include "util/deg_util_foreach.h" +#include "intern/nodes/deg_node_id.h" + #ifndef NDEBUG # include "intern/eval/deg_eval_copy_on_write.h" #endif @@ -82,6 +84,7 @@ static bool deg_objects_dupli_iterator_next(BLI_Iterator *iter) Object *dupli_parent = data->dupli_parent; Object *temp_dupli_object = &data->temp_dupli_object; *temp_dupli_object = *dob->ob; + temp_dupli_object->transflag &= ~OB_DUPLI; temp_dupli_object->select_color = dupli_parent->select_color; temp_dupli_object->base_flag = dupli_parent->base_flag | BASE_FROMDUPLI; @@ -137,7 +140,7 @@ static void DEG_iterator_objects_step(BLI_Iterator *iter, DEG::IDDepsNode *id_no Object *object = (Object *)id_node->id_cow; BLI_assert(DEG::deg_validate_copy_on_write_datablock(&object->id)); - if ((BKE_object_is_visible(object) == false) && + if ((BKE_object_is_visible(object, OB_VISIBILITY_CHECK_UNKNOWN_RENDER_MODE) == false) && ((data->flag & DEG_ITER_OBJECT_FLAG_VISIBLE) != 0)) { return; @@ -147,6 +150,14 @@ static void DEG_iterator_objects_step(BLI_Iterator *iter, DEG::IDDepsNode *id_no data->dupli_parent = object; data->dupli_list = object_duplilist(&data->eval_ctx, data->scene, object); data->dupli_object_next = (DupliObject *)data->dupli_list->first; + + const eObjectVisibilityCheck mode = (data->mode == DEG_ITER_OBJECT_MODE_RENDER) ? + OB_VISIBILITY_CHECK_FOR_RENDER : + OB_VISIBILITY_CHECK_FOR_VIEWPORT; + + if (BKE_object_is_visible(object, mode) == false) { + return; + } } iter->current = object; @@ -165,7 +176,10 @@ void DEG_iterator_objects_begin(BLI_Iterator *iter, DEGObjectIterData *data) } /* TODO(sergey): What evaluation type we want here? */ - DEG_evaluation_context_init(&data->eval_ctx, DAG_EVAL_RENDER); + /* TODO(dfelinto): Get rid of evaluation context here, it's only used to do + * direct dupli-objects update in group.c. Which is terribly bad, and all + * objects are expected to be evaluated already. */ + DEG_evaluation_context_init(&data->eval_ctx, DAG_EVAL_VIEWPORT); data->eval_ctx.view_layer = DEG_get_evaluated_view_layer(depsgraph); iter->data = data; @@ -191,6 +205,7 @@ void DEG_iterator_objects_next(BLI_Iterator *iter) Depsgraph *depsgraph = data->graph; DEG::Depsgraph *deg_graph = reinterpret_cast<DEG::Depsgraph *>(depsgraph); do { + iter->skip = false; if (data->dupli_list) { if (deg_objects_dupli_iterator_next(iter)) { return; diff --git a/source/blender/depsgraph/intern/depsgraph_tag.cc b/source/blender/depsgraph/intern/depsgraph_tag.cc index dc8a4aecc46..9082c885c64 100644 --- a/source/blender/depsgraph/intern/depsgraph_tag.cc +++ b/source/blender/depsgraph/intern/depsgraph_tag.cc @@ -35,8 +35,9 @@ #include <queue> #include "BLI_utildefines.h" -#include "BLI_task.h" #include "BLI_listbase.h" +#include "BLI_math_bits.h" +#include "BLI_task.h" extern "C" { #include "DNA_object_types.h" @@ -63,105 +64,29 @@ extern "C" { #include "intern/eval/deg_eval_flush.h" #include "intern/nodes/deg_node.h" #include "intern/nodes/deg_node_component.h" +#include "intern/nodes/deg_node_id.h" #include "intern/nodes/deg_node_operation.h" #include "intern/depsgraph_intern.h" #include "util/deg_util_foreach.h" -/* Define this in order to have more strict sanitization of what tagging flags - * are used for ID databnlocks. Ideally, we would always want this, but there - * are cases in generic modules (like IR remapping) where we don't want to spent - * lots of time trying to guess which components are to be updated. - */ -// #define STRICT_COMPONENT_TAGGING - /* *********************** */ /* Update Tagging/Flushing */ namespace DEG { -/* Data-Based Tagging ------------------------------- */ - -void lib_id_recalc_tag(Main *bmain, ID *id) -{ - id->recalc |= ID_RECALC; - DEG_id_type_tag(bmain, GS(id->name)); -} - namespace { void deg_graph_id_tag_update(Main *bmain, Depsgraph *graph, ID *id, int flag); -void lib_id_recalc_tag_flag(Main *bmain, ID *id, int flag) +void depsgraph_geometry_tag_to_component(const ID *id, + eDepsNode_Type *component_type) { - /* This bit of code ensures legacy object->recalc flags are still filled in - * the same way as it was expected with the old dependency graph. - * - * This is because some areas like motion paths and likely some other - * physics baking process are doing manual scene update on all the frames, - * trying to minimize number of updates. - * - * But this flag will also let us to re-construct entry nodes for update - * after relations update and after layer visibility changes. - */ - if (flag) { - if (flag & OB_RECALC_OB) { - lib_id_recalc_tag(bmain, id); - } - if (flag & (OB_RECALC_DATA)) { - if (GS(id->name) == ID_OB) { - Object *object = (Object *)id; - ID *object_data = (ID *)object->data; - if (object_data != NULL) { - lib_id_recalc_tag(bmain, object_data); - } - } - else { - // BLI_assert(!"Tagging non-object as object data update"); - lib_id_recalc_tag(bmain, id); - } - } - if (flag & PSYS_RECALC) { - lib_id_recalc_tag(bmain, id); - } - } - else { - lib_id_recalc_tag(bmain, id); - } -} - -/* Special tagging */ -void id_tag_update_special_zero_flag(Depsgraph *graph, IDDepsNode *id_node) -{ - /* NOTE: Full ID node update for now, need to minimize that in the future. */ - id_node->tag_update(graph); -} - -/* Tag corresponding to OB_RECALC_OB. */ -void id_tag_update_object_transform(Depsgraph *graph, IDDepsNode *id_node) -{ - ComponentDepsNode *transform_comp = - id_node->find_component(DEG_NODE_TYPE_TRANSFORM); - if (transform_comp == NULL) { -#ifdef STRICT_COMPONENT_TAGGING - DEG_ERROR_PRINTF("ERROR: Unable to find transform component for %s\n", - id_node->id_orig->name); - BLI_assert(!"This is not supposed to happen!"); -#endif - return; - } - transform_comp->tag_update(graph); -} - -/* Tag corresponding to OB_RECALC_DATA. */ -void id_tag_update_object_data(Depsgraph *graph, IDDepsNode *id_node) -{ - const ID_Type id_type = GS(id_node->id_orig->name); - ComponentDepsNode *data_comp = NULL; + const ID_Type id_type = GS(id->name); switch (id_type) { case ID_OB: { - const Object *object = (Object *)id_node->id_orig; + const Object *object = (Object *)id; switch (object->type) { case OB_MESH: case OB_CURVE: @@ -169,127 +94,34 @@ void id_tag_update_object_data(Depsgraph *graph, IDDepsNode *id_node) case OB_FONT: case OB_MBALL: case OB_GROOM: - data_comp = id_node->find_component(DEG_NODE_TYPE_GEOMETRY); + *component_type = DEG_NODE_TYPE_GEOMETRY; break; case OB_ARMATURE: - data_comp = id_node->find_component(DEG_NODE_TYPE_EVAL_POSE); + *component_type = DEG_NODE_TYPE_EVAL_POSE; break; - /* TODO(sergey): More cases here? */ + /* TODO(sergey): More cases here? */ } break; } case ID_ME: - data_comp = id_node->find_component(DEG_NODE_TYPE_GEOMETRY); + *component_type = DEG_NODE_TYPE_GEOMETRY; break; case ID_PA: return; case ID_LP: - data_comp = id_node->find_component(DEG_NODE_TYPE_PARAMETERS); + *component_type = DEG_NODE_TYPE_PARAMETERS; break; default: break; } - if (data_comp == NULL) { -#ifdef STRICT_COMPONENT_TAGGING - DEG_ERROR_PRINTF("ERROR: Unable to find data component for %s\n", - id_node->id_orig->name); - BLI_assert(!"This is not supposed to happen!"); -#endif - return; - } - data_comp->tag_update(graph); - /* Special legacy compatibility code, tag data ID for update when object - * is tagged for data update. - */ - if (id_type == ID_OB) { - Object *object = (Object *)id_node->id_orig; - ID *data_id = (ID *)object->data; - if (data_id != NULL) { - IDDepsNode *data_id_node = graph->find_id_node(data_id); - // BLI_assert(data_id_node != NULL); - /* TODO(sergey): Do we want more granular tags here? */ - /* TODO(sergey): Hrm, during some operations it's possible to have - * object node existing but not it's data. For example, when making - * objects local. This is valid situation, but how can we distinguish - * that from someone trying to do stupid things with dependency - * graph? - */ - if (data_id_node != NULL) { - data_id_node->tag_update(graph); - } - } - } -} - -/* Tag corresponding to OB_RECALC_TIME. */ -void id_tag_update_object_time(Depsgraph *graph, IDDepsNode *id_node) -{ - ComponentDepsNode *animation_comp = - id_node->find_component(DEG_NODE_TYPE_ANIMATION); - if (animation_comp == NULL) { - /* It's not necessarily we've got animation component in cases when - * we are tagging for time updates. - */ - return; - } - animation_comp->tag_update(graph); - /* TODO(sergey): More components to tag here? */ -} - -void id_tag_update_particle(Depsgraph *graph, IDDepsNode *id_node, int tag) -{ - ComponentDepsNode *particle_comp = - id_node->find_component(DEG_NODE_TYPE_PARAMETERS); - ParticleSettings *particle_settings = (ParticleSettings *)id_node->id_orig; - particle_settings->recalc |= (tag & PSYS_RECALC); - if (particle_comp == NULL) { -#ifdef STRICT_COMPONENT_TAGGING - DEG_ERROR_PRINTF("ERROR: Unable to find particle component for %s\n", - id_node->id_orig->name); - BLI_assert(!"This is not supposed to happen!"); -#endif - return; - } - particle_comp->tag_update(graph); } -void id_tag_update_shading(Depsgraph *graph, IDDepsNode *id_node) +void depsgraph_select_tag_to_component_opcode( + const ID *id, + eDepsNode_Type *component_type, + eDepsOperation_Code *operation_code) { - ComponentDepsNode *shading_comp; - if (GS(id_node->id_orig->name) == ID_NT) { - shading_comp = id_node->find_component(DEG_NODE_TYPE_SHADING_PARAMETERS); - } - else { - shading_comp = id_node->find_component(DEG_NODE_TYPE_SHADING); - } - if (shading_comp == NULL) { -#ifdef STRICT_COMPONENT_TAGGING - DEG_ERROR_PRINTF("ERROR: Unable to find shading component for %s\n", - id_node->id_orig->name); - BLI_assert(!"This is not supposed to happen!"); -#endif - return; - } - shading_comp->tag_update(graph); -} - -/* Tag corresponding to DEG_TAG_COPY_ON_WRITE. */ -void id_tag_update_copy_on_write(Depsgraph *graph, IDDepsNode *id_node) -{ - if (!DEG_depsgraph_use_copy_on_write()) { - return; - } - ComponentDepsNode *cow_comp = - id_node->find_component(DEG_NODE_TYPE_COPY_ON_WRITE); - OperationDepsNode *cow_node = cow_comp->get_entry_operation(); - cow_node->tag_update(graph); -} - -void id_tag_update_select_update(Depsgraph *graph, IDDepsNode *id_node) -{ - ComponentDepsNode *component; - OperationDepsNode *node = NULL; - const ID_Type id_type = GS(id_node->id_orig->name); + const ID_Type id_type = GS(id->name); if (id_type == ID_SCE) { /* We need to flush base flags to all objects in a scene since we * don't know which ones changed. However, we don't want to update @@ -300,62 +132,107 @@ void id_tag_update_select_update(Depsgraph *graph, IDDepsNode *id_node) * does nothing and which is only used to cascade flush down the * road. */ - component = id_node->find_component(DEG_NODE_TYPE_LAYER_COLLECTIONS); - BLI_assert(component != NULL); - if (component != NULL) { - node = component->find_operation(DEG_OPCODE_VIEW_LAYER_DONE); - } + *component_type = DEG_NODE_TYPE_LAYER_COLLECTIONS; + *operation_code = DEG_OPCODE_VIEW_LAYER_DONE; } else if (id_type == ID_OB) { - component = id_node->find_component(DEG_NODE_TYPE_LAYER_COLLECTIONS); - /* NOTE: This component might be missing for indirectly linked - * objects. - */ - if (component != NULL) { - node = component->find_operation(DEG_OPCODE_OBJECT_BASE_FLAGS); - } + *component_type = DEG_NODE_TYPE_LAYER_COLLECTIONS; + *operation_code = DEG_OPCODE_OBJECT_BASE_FLAGS; } else { - component = id_node->find_component(DEG_NODE_TYPE_BATCH_CACHE); - BLI_assert(component != NULL); - if (component != NULL) { - node = component->find_operation(DEG_OPCODE_GEOMETRY_SELECT_UPDATE, - "", -1); - } - } - if (node != NULL) { - node->tag_update(graph); + *component_type = DEG_NODE_TYPE_BATCH_CACHE; + *operation_code = DEG_OPCODE_GEOMETRY_SELECT_UPDATE; } } -void id_tag_update_base_flags(Depsgraph *graph, IDDepsNode *id_node) +void depsgraph_base_flags_tag_to_component_opcode( + const ID *id, + eDepsNode_Type *component_type, + eDepsOperation_Code *operation_code) { - ComponentDepsNode *component; - OperationDepsNode *node = NULL; - const ID_Type id_type = GS(id_node->id_orig->name); + const ID_Type id_type = GS(id->name); if (id_type == ID_SCE) { - component = id_node->find_component(DEG_NODE_TYPE_LAYER_COLLECTIONS); - if (component == NULL) { - return; - } - node = component->find_operation(DEG_OPCODE_VIEW_LAYER_INIT); + *component_type = DEG_NODE_TYPE_LAYER_COLLECTIONS; + *operation_code = DEG_OPCODE_VIEW_LAYER_INIT; } else if (id_type == ID_OB) { - component = id_node->find_component(DEG_NODE_TYPE_LAYER_COLLECTIONS); - if (component == NULL) { - return; - } - node = component->find_operation(DEG_OPCODE_OBJECT_BASE_FLAGS); - if (node == NULL) { - return; - } + *component_type = DEG_NODE_TYPE_LAYER_COLLECTIONS; + *operation_code = DEG_OPCODE_OBJECT_BASE_FLAGS; } - if (node != NULL) { - node->tag_update(graph); +} + +void depsgraph_tag_to_component_opcode(const ID *id, + eDepsgraph_Tag tag, + eDepsNode_Type *component_type, + eDepsOperation_Code *operation_code) +{ + const ID_Type id_type = GS(id->name); + *component_type = DEG_NODE_TYPE_UNDEFINED; + *operation_code = DEG_OPCODE_OPERATION; + /* Special case for now, in the future we should get rid of this. */ + if (tag == 0) { + *component_type = DEG_NODE_TYPE_ID_REF; + *operation_code = DEG_OPCODE_OPERATION; + return; + } + switch (tag) { + case DEG_TAG_TRANSFORM: + *component_type = DEG_NODE_TYPE_TRANSFORM; + break; + case DEG_TAG_GEOMETRY: + depsgraph_geometry_tag_to_component(id, component_type); + break; + case DEG_TAG_TIME: + *component_type = DEG_NODE_TYPE_ANIMATION; + break; + case DEG_TAG_PSYS_REDO: + case DEG_TAG_PSYS_RESET: + case DEG_TAG_PSYS_TYPE: + case DEG_TAG_PSYS_CHILD: + case DEG_TAG_PSYS_PHYS: + *component_type = DEG_NODE_TYPE_EVAL_PARTICLES; + break; + case DEG_TAG_COPY_ON_WRITE: + *component_type = DEG_NODE_TYPE_COPY_ON_WRITE; + break; + case DEG_TAG_SHADING_UPDATE: + if (id_type == ID_NT) { + *component_type = DEG_NODE_TYPE_SHADING_PARAMETERS; + } + else { + *component_type = DEG_NODE_TYPE_SHADING; + } + break; + case DEG_TAG_SELECT_UPDATE: + depsgraph_select_tag_to_component_opcode(id, + component_type, + operation_code); + break; + case DEG_TAG_BASE_FLAGS_UPDATE: + depsgraph_base_flags_tag_to_component_opcode(id, + component_type, + operation_code); + case DEG_TAG_EDITORS_UPDATE: + /* There is no such node in depsgraph, this tag is to be handled + * separately. + */ + break; + case DEG_TAG_PSYS_ALL: + BLI_assert(!"Should not happen"); + break; } } -void id_tag_update_editors_update(Main *bmain, Depsgraph *graph, ID *id) +void id_tag_update_ntree_special(Main *bmain, Depsgraph *graph, ID *id, int flag) +{ + bNodeTree *ntree = ntreeFromID(id); + if (ntree == NULL) { + return; + } + deg_graph_id_tag_update(bmain, graph, &ntree->id, flag); +} + +void depsgraph_update_editors_tag(Main *bmain, Depsgraph *graph, ID *id) { /* NOTE: We handle this immediately, without delaying anything, to be * sure we don't cause threading issues with OpenGL. @@ -368,77 +245,93 @@ void id_tag_update_editors_update(Main *bmain, Depsgraph *graph, ID *id) deg_editors_id_update(&update_ctx, id); } -void id_tag_update_ntree_special(Main *bmain, Depsgraph *graph, ID *id, int flag) +void deg_graph_id_tag_update_single_flag(Main *bmain, + Depsgraph *graph, + ID *id, + IDDepsNode *id_node, + eDepsgraph_Tag tag) { - bNodeTree *ntree = ntreeFromID(id); - if (ntree == NULL) { + if (tag == DEG_TAG_EDITORS_UPDATE) { + if (graph != NULL) { + depsgraph_update_editors_tag(bmain, graph, id); + } return; } - IDDepsNode *id_node = graph->find_id_node(&ntree->id); - if (id_node != NULL) { - deg_graph_id_tag_update(bmain, graph, id_node->id_orig, flag); - } -} - -void deg_graph_id_tag_update(Main *bmain, Depsgraph *graph, ID *id, int flag) -{ - Depsgraph *deg_graph = reinterpret_cast<DEG::Depsgraph *>(graph); - IDDepsNode *id_node = deg_graph->find_id_node(id); - /* Make sure legacy flags are all nicely update. */ - lib_id_recalc_tag_flag(bmain, id, flag); - if (id_node == NULL) { - /* Shouldn't happen, but better be sure here. */ + /* Get description of what is to be tagged. */ + eDepsNode_Type component_type; + eDepsOperation_Code operation_code; + depsgraph_tag_to_component_opcode(id, + tag, + &component_type, + &operation_code); + /* Check whether we've got something to tag. */ + if (component_type == DEG_NODE_TYPE_UNDEFINED) { + /* Given ID does not support tag. */ + /* TODO(sergey): Shall we raise some panic here? */ return; } - /* Tag components based on flags. */ - if (flag == 0) { - id_tag_update_special_zero_flag(graph, id_node); - id_tag_update_ntree_special(bmain, graph, id, flag); + /* Tag ID recalc flag. */ + DepsNodeFactory *factory = deg_type_get_factory(component_type); + BLI_assert(factory != NULL); + id->recalc |= factory->id_recalc_tag(); + /* Some sanity checks before moving forward. */ + if (id_node == NULL) { + /* Happens when object is tagged for update and not yet in the + * dependency graph (but will be after relations update). + */ return; } - if (flag & OB_RECALC_OB) { - id_tag_update_object_transform(graph, id_node); + /* Tag corresponding dependency graph operation for update. */ + if (component_type == DEG_NODE_TYPE_ID_REF) { + id_node->tag_update(graph); } - if (flag & OB_RECALC_DATA) { - id_tag_update_object_data(graph, id_node); - if (DEG_depsgraph_use_copy_on_write()) { - if (flag & DEG_TAG_COPY_ON_WRITE) { - const ID_Type id_type = GS(id_node->id_orig->name); - if (id_type == ID_OB) { - Object *object = (Object *)id_node->id_orig; - ID *ob_data = (ID *)object->data; - DEG_id_tag_update_ex(bmain, ob_data, flag); + else { + ComponentDepsNode *component_node = + id_node->find_component(component_type); + if (component_node != NULL) { + if (operation_code == DEG_OPCODE_OPERATION) { + component_node->tag_update(graph); + } + else { + OperationDepsNode *operation_node = + component_node->find_operation(operation_code); + if (operation_node != NULL) { + operation_node->tag_update(graph); } } } } - if (flag & OB_RECALC_TIME) { - id_tag_update_object_time(graph, id_node); - } - if (flag & PSYS_RECALC) { - id_tag_update_particle(graph, id_node, flag); - } - if (flag & DEG_TAG_SHADING_UPDATE) { - id_tag_update_shading(graph, id_node); - } - if (flag & DEG_TAG_COPY_ON_WRITE) { - id_tag_update_copy_on_write(graph, id_node); - } - if (flag & DEG_TAG_SELECT_UPDATE) { - id_tag_update_select_update(graph, id_node); - } - if (flag & DEG_TAG_BASE_FLAGS_UPDATE) { - id_tag_update_base_flags(graph, id_node); - } - if (flag & DEG_TAG_EDITORS_UPDATE) { - id_tag_update_editors_update(bmain, graph, id); +} + +void deg_graph_id_tag_update(Main *bmain, Depsgraph *graph, ID *id, int flag) +{ + IDDepsNode *id_node = (graph != NULL) ? graph->find_id_node(id) + : NULL; + DEG_id_type_tag(bmain, GS(id->name)); + if (flag == 0) { + /* TODO(sergey): Which recalc flags to set here? */ + id->recalc |= ID_RECALC_ALL; + if (id_node != NULL) { + id_node->tag_update(graph); + } } + int current_flag = flag; + while (current_flag != 0) { + eDepsgraph_Tag tag = + (eDepsgraph_Tag)(1 << bitscan_forward_clear_i(¤t_flag)); + deg_graph_id_tag_update_single_flag(bmain, + graph, + id, + id_node, + tag); + } + /* Special case for nested node tree datablocks. */ id_tag_update_ntree_special(bmain, graph, id, flag); } void deg_id_tag_update(Main *bmain, ID *id, int flag) { - lib_id_recalc_tag_flag(bmain, id, flag); + deg_graph_id_tag_update(bmain, NULL, id, flag); LINKLIST_FOREACH(Scene *, scene, &bmain->scene) { LINKLIST_FOREACH(ViewLayer *, view_layer, &scene->view_layers) { Depsgraph *depsgraph = @@ -470,7 +363,10 @@ void deg_graph_on_visible_update(Main *bmain, Depsgraph *graph) deg_graph_id_tag_update(bmain, graph, id_node->id_orig, flag); } /* Make sure collection properties are up to date. */ - for (Scene *scene_iter = graph->scene; scene_iter != NULL; scene_iter = scene_iter->set) { + for (Scene *scene_iter = graph->scene; + scene_iter != NULL; + scene_iter = scene_iter->set) + { IDDepsNode *scene_id_node = graph->find_id_node(&scene_iter->id); BLI_assert(scene_id_node != NULL); scene_id_node->tag_update(graph); @@ -481,6 +377,8 @@ void deg_graph_on_visible_update(Main *bmain, Depsgraph *graph) } // namespace DEG +/* Data-Based Tagging */ + /* Tag given ID for an update in all the dependency graphs. */ void DEG_id_tag_update(ID *id, int flag) { diff --git a/source/blender/depsgraph/intern/eval/deg_eval.cc b/source/blender/depsgraph/intern/eval/deg_eval.cc index 5aebd6814a0..ee58a3b02a5 100644 --- a/source/blender/depsgraph/intern/eval/deg_eval.cc +++ b/source/blender/depsgraph/intern/eval/deg_eval.cc @@ -46,20 +46,16 @@ #include "atomic_ops.h" #include "intern/eval/deg_eval_flush.h" +#include "intern/eval/deg_eval_stats.h" #include "intern/nodes/deg_node.h" #include "intern/nodes/deg_node_component.h" +#include "intern/nodes/deg_node_id.h" #include "intern/nodes/deg_node_operation.h" +#include "intern/nodes/deg_node_time.h" #include "intern/depsgraph.h" #include "intern/depsgraph_intern.h" -#include "util/deg_util_foreach.h" - -/* Unfinished and unused, and takes quite some pre-processing time. */ -#undef USE_EVAL_PRIORITY -/* Use integrated debugger to keep track how much each of the nodes was - * evaluating. - */ -#undef USE_DEBUGGER +#include "util/deg_util_foreach.h" namespace DEG { @@ -75,52 +71,28 @@ static void schedule_children(TaskPool *pool, struct DepsgraphEvalState { EvaluationContext *eval_ctx; Depsgraph *graph; + bool do_stats; }; static void deg_task_run_func(TaskPool *pool, void *taskdata, int thread_id) { - DepsgraphEvalState *state = - reinterpret_cast<DepsgraphEvalState *>(BLI_task_pool_userdata(pool)); - OperationDepsNode *node = reinterpret_cast<OperationDepsNode *>(taskdata); - + void *userdata_v = BLI_task_pool_userdata(pool); + DepsgraphEvalState *state = (DepsgraphEvalState *)userdata_v; + OperationDepsNode *node = (OperationDepsNode *)taskdata; + /* Sanity checks. */ BLI_assert(!node->is_noop() && "NOOP nodes should not actually be scheduled"); - - /* Should only be the case for NOOPs, which never get to this point. */ - BLI_assert(node->evaluate); - - /* Get context. */ - /* TODO: Who initialises this? "Init" operations aren't able to - * initialise it!!! - */ - /* TODO(sergey): We don't use component contexts at this moment. */ - /* ComponentDepsNode *comp = node->owner; */ - BLI_assert(node->owner != NULL); - - /* Since we're not leaving the thread for until the graph branches it is - * possible to have NO-OP on the way. for which evaluate() will be NULL. - * but that's all fine, we'll just scheduler it's children. - */ - if (node->evaluate) { - /* Take note of current time. */ -#ifdef USE_DEBUGGER - double start_time = PIL_check_seconds_timer(); - DepsgraphDebug::task_started(state->graph, node); -#endif - - /* Perform operation. */ + /* Perform operation. */ + if (state->do_stats) { + const double start_time = PIL_check_seconds_timer(); node->evaluate(state->eval_ctx); - - /* Note how long this took. */ -#ifdef USE_DEBUGGER - double end_time = PIL_check_seconds_timer(); - DepsgraphDebug::task_completed(state->graph, - node, - end_time - start_time); -#endif + node->stats.current_time += PIL_check_seconds_timer() - start_time; } - + else { + node->evaluate(state->eval_ctx); + } + /* Schedule children. */ BLI_task_pool_delayed_push_begin(pool, thread_id); schedule_children(pool, state->graph, node, thread_id); BLI_task_pool_delayed_push_end(pool, thread_id); @@ -167,32 +139,18 @@ static void calculate_pending_parents(Depsgraph *graph) do_threads); } -#ifdef USE_EVAL_PRIORITY -static void calculate_eval_priority(OperationDepsNode *node) +static void initialize_execution(DepsgraphEvalState *state, Depsgraph *graph) { - if (node->done) { - return; - } - node->done = 1; - - if (node->flag & DEPSOP_FLAG_NEEDS_UPDATE) { - /* XXX standard cost of a node, could be estimated somewhat later on */ - const float cost = 1.0f; - /* NOOP nodes have no cost */ - node->eval_priority = node->is_noop() ? cost : 0.0f; - - foreach (DepsRelation *rel, node->outlinks) { - OperationDepsNode *to = (OperationDepsNode *)rel->to; - BLI_assert(to->type == DEG_NODE_TYPE_OPERATION); - calculate_eval_priority(to); - node->eval_priority += to->eval_priority; + const bool do_stats = state->do_stats; + calculate_pending_parents(graph); + /* Clear tags and other things which needs to be clear. */ + foreach (OperationDepsNode *node, graph->operations) { + node->done = 0; + if (do_stats) { + node->stats.reset_current(); } } - else { - node->eval_priority = 0.0f; - } } -#endif /* Schedule a node if it needs evaluation. * dec_parents: Decrement pending parents count, true when child nodes are @@ -267,28 +225,23 @@ static void schedule_children(TaskPool *pool, void deg_evaluate_on_refresh(EvaluationContext *eval_ctx, Depsgraph *graph) { - /* Generate base evaluation context, upon which all the others are derived. */ - // TODO: this needs both main and scene access... - /* Nothing to update, early out. */ if (BLI_gset_size(graph->entry_tags) == 0) { return; } - /* Set time for the current graph evaluation context. */ TimeSourceDepsNode *time_src = graph->find_time_source(); eval_ctx->depsgraph = (::Depsgraph *)graph; eval_ctx->view_layer = DEG_get_evaluated_view_layer((::Depsgraph *)graph); eval_ctx->ctime = time_src->cfra; - - /* XXX could use a separate pool for each eval context */ + /* Set up evaluation context for depsgraph itself. */ DepsgraphEvalState state; state.eval_ctx = eval_ctx; state.graph = graph; - + state.do_stats = (G.debug_value != 0); + /* Set up task scheduler and pull for threaded evaluation. */ TaskScheduler *task_scheduler; bool need_free_scheduler; - if (G.debug & G_DEBUG_DEPSGRAPH_NO_THREADS) { task_scheduler = BLI_task_scheduler_create(1); need_free_scheduler = true; @@ -297,31 +250,22 @@ void deg_evaluate_on_refresh(EvaluationContext *eval_ctx, task_scheduler = BLI_task_scheduler_get(); need_free_scheduler = false; } - TaskPool *task_pool = BLI_task_pool_create_suspended(task_scheduler, &state); - - calculate_pending_parents(graph); - - /* Clear tags. */ - foreach (OperationDepsNode *node, graph->operations) { - node->done = 0; - } - - /* Calculate priority for operation nodes. */ -#ifdef USE_EVAL_PRIORITY - foreach (OperationDepsNode *node, graph->operations) { - calculate_eval_priority(node); - } -#endif - + /* Prepare all nodes for evaluation. */ + initialize_execution(&state, graph); + /* Do actual evaluation now. */ schedule_graph(task_pool, graph); - BLI_task_pool_work_and_wait(task_pool); BLI_task_pool_free(task_pool); - + /* Finalize statistics gathering. This is because we only gather single + * operation timing here, without aggregating anything to avoid any extra + * synchronization. + */ + if (state.do_stats) { + deg_eval_stats_aggregate(graph); + } /* Clear any uncleared tags - just in case. */ deg_graph_clear_tags(graph); - if (need_free_scheduler) { BLI_task_scheduler_free(task_scheduler); } diff --git a/source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.cc b/source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.cc index 00406cc8342..abd17616584 100644 --- a/source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.cc +++ b/source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.cc @@ -80,6 +80,7 @@ extern "C" { #include "intern/depsgraph.h" #include "intern/builder/deg_builder_nodes.h" #include "intern/nodes/deg_node.h" +#include "intern/nodes/deg_node_id.h" namespace DEG { diff --git a/source/blender/depsgraph/intern/eval/deg_eval_flush.cc b/source/blender/depsgraph/intern/eval/deg_eval_flush.cc index a839a8beac6..af1d09ad54a 100644 --- a/source/blender/depsgraph/intern/eval/deg_eval_flush.cc +++ b/source/blender/depsgraph/intern/eval/deg_eval_flush.cc @@ -47,6 +47,7 @@ extern "C" { #include "intern/nodes/deg_node.h" #include "intern/nodes/deg_node_component.h" +#include "intern/nodes/deg_node_id.h" #include "intern/nodes/deg_node_operation.h" #include "intern/depsgraph_intern.h" @@ -190,6 +191,7 @@ BLI_INLINE OperationDepsNode *flush_schedule_children( return result; } +/* NOTE: It will also accumulate flags from changed components. */ BLI_INLINE void flush_editors_id_update(Main *bmain, Depsgraph *graph, const DEGEditorUpdateContext *update_ctx) @@ -198,6 +200,7 @@ BLI_INLINE void flush_editors_id_update(Main *bmain, if (id_node->done != ID_STATE_MODIFIED) { continue; } + DEG_id_type_tag(bmain, GS(id_node->id_orig->name)); /* TODO(sergey): Do we need to pass original or evaluated ID here? */ ID *id_orig = id_node->id_orig; ID *id_cow = id_node->id_cow; @@ -206,10 +209,23 @@ BLI_INLINE void flush_editors_id_update(Main *bmain, * data. */ id_cow->recalc |= (id_orig->recalc & ID_RECALC_ALL); + /* Gather recalc flags from all changed components. */ + GHASH_FOREACH_BEGIN(ComponentDepsNode *, comp_node, id_node->components) + { + if (comp_node->done != COMPONENT_STATE_DONE) { + continue; + } + DepsNodeFactory *factory = deg_type_get_factory(comp_node->type); + BLI_assert(factory != NULL); + id_cow->recalc |= factory->id_recalc_tag(); + } + GHASH_FOREACH_END(); + DEG_DEBUG_PRINTF("Accumulated recalc bits for %s: %u\n", + id_orig->name, (unsigned int)id_cow->recalc); + /* Inform editors. */ if (deg_copy_on_write_is_expanded(id_cow)) { deg_editors_id_update(update_ctx, id_cow); } - lib_id_recalc_tag(bmain, id_orig); } } diff --git a/source/blender/depsgraph/intern/eval/deg_eval_stats.cc b/source/blender/depsgraph/intern/eval/deg_eval_stats.cc new file mode 100644 index 00000000000..52ce744cc0a --- /dev/null +++ b/source/blender/depsgraph/intern/eval/deg_eval_stats.cc @@ -0,0 +1,70 @@ +/* + * ***** 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) 2017 Blender Foundation. + * All rights reserved. + * + * Original Author: Sergey Sharybin + * Contributor(s): None Yet + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/depsgraph/intern/eval/deg_eval_stats.cc + * \ingroup depsgraph + */ + +#include "intern/eval/deg_eval_stats.h" + +#include "BLI_utildefines.h" +#include "BLI_ghash.h" + +#include "intern/depsgraph.h" + +#include "intern/nodes/deg_node.h" +#include "intern/nodes/deg_node_component.h" +#include "intern/nodes/deg_node_id.h" +#include "intern/nodes/deg_node_operation.h" + +#include "util/deg_util_foreach.h" + +namespace DEG { + +void deg_eval_stats_aggregate(Depsgraph *graph) +{ + /* Reset current evaluation stats for ID and component nodes. + * Those are not filled in by the evaluation engine. + */ + foreach (DepsNode *node, graph->id_nodes) { + IDDepsNode *id_node = (IDDepsNode *)node; + GHASH_FOREACH_BEGIN(ComponentDepsNode *, comp_node, id_node->components) + { + comp_node->stats.reset_current(); + } + GHASH_FOREACH_END(); + id_node->stats.reset_current(); + } + /* Now accumulate operation timings to components and IDs. */ + foreach (OperationDepsNode *op_node, graph->operations) { + ComponentDepsNode *comp_node = op_node->owner; + IDDepsNode *id_node = comp_node->owner; + id_node->stats.current_time += op_node->stats.current_time; + comp_node->stats.current_time += op_node->stats.current_time; + } +} + +} // namespace DEG diff --git a/source/blender/depsgraph/intern/eval/deg_eval_stats.h b/source/blender/depsgraph/intern/eval/deg_eval_stats.h new file mode 100644 index 00000000000..8a7272ac89c --- /dev/null +++ b/source/blender/depsgraph/intern/eval/deg_eval_stats.h @@ -0,0 +1,40 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2017 Blender Foundation. + * All rights reserved. + * + * Original Author: Sergey Sharybin + * Contributor(s): None Yet + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/depsgraph/intern/eval/deg_eval_stats.h + * \ingroup depsgraph + */ + +#pragma once + +namespace DEG { + +struct Depsgraph; + +/* Aggregate operation timings to overall component and ID nodes timing. */ +void deg_eval_stats_aggregate(Depsgraph *graph); + +} // namespace DEG diff --git a/source/blender/depsgraph/intern/nodes/deg_node.cc b/source/blender/depsgraph/intern/nodes/deg_node.cc index 3f70f8e1281..fdcfc129073 100644 --- a/source/blender/depsgraph/intern/nodes/deg_node.cc +++ b/source/blender/depsgraph/intern/nodes/deg_node.cc @@ -31,48 +31,57 @@ #include "intern/nodes/deg_node.h" #include <stdio.h> -#include <cstring> /* required for STREQ later on. */ #include "BLI_utildefines.h" -#include "BLI_ghash.h" - -extern "C" { -#include "DNA_ID.h" -#include "DNA_anim_types.h" -#include "DNA_object_types.h" - -#include "BKE_animsys.h" -#include "BKE_library.h" -} - -#include "DEG_depsgraph.h" #include "intern/eval/deg_eval_copy_on_write.h" #include "intern/nodes/deg_node_component.h" +#include "intern/nodes/deg_node_id.h" #include "intern/nodes/deg_node_operation.h" +#include "intern/nodes/deg_node_time.h" #include "intern/depsgraph_intern.h" + #include "util/deg_util_foreach.h" #include "util/deg_util_function.h" namespace DEG { -/* *************** */ -/* Node Management */ +/******************************************************************************* + * Type information. + */ -/* Add ------------------------------------------------ */ +DepsNode::TypeInfo::TypeInfo(eDepsNode_Type type, + const char *tname, + int id_recalc_tag) + : type(type), + tname(tname), + id_recalc_tag(id_recalc_tag) +{ +} -DepsNode::TypeInfo::TypeInfo(eDepsNode_Type type, const char *tname) +/******************************************************************************* + * Evaluation statistics. + */ + +DepsNode::Stats::Stats() { - this->type = type; - if (type == DEG_NODE_TYPE_OPERATION) - this->tclass = DEG_NODE_CLASS_OPERATION; - else if (type < DEG_NODE_TYPE_PARAMETERS) - this->tclass = DEG_NODE_CLASS_GENERIC; - else - this->tclass = DEG_NODE_CLASS_COMPONENT; - this->tname = tname; + reset(); } +void DepsNode::Stats::reset() +{ + current_time = 0.0; +} + +void DepsNode::Stats::reset_current() +{ + current_time = 0.0; +} + +/******************************************************************************* + * Node itself. + */ + DepsNode::DepsNode() { name = ""; @@ -100,185 +109,24 @@ string DepsNode::identifier() const return string(typebuf) + " : " + name; } -/* ************* */ -/* Generic Nodes */ - -/* Time Source Node ============================================== */ - -void TimeSourceDepsNode::tag_update(Depsgraph *graph) -{ - foreach (DepsRelation *rel, outlinks) { - DepsNode *node = rel->to; - node->tag_update(graph); - } -} - -/* Time Source Node ======================================= */ - -DEG_DEPSNODE_DEFINE(TimeSourceDepsNode, DEG_NODE_TYPE_TIMESOURCE, "Time Source"); -static DepsNodeFactoryImpl<TimeSourceDepsNode> DNTI_TIMESOURCE; - -/* ID Node ================================================ */ - -IDDepsNode::ComponentIDKey::ComponentIDKey(eDepsNode_Type type, - const char *name) - : type(type), name(name) -{ -} - -bool IDDepsNode::ComponentIDKey::operator== (const ComponentIDKey &other) const -{ - return type == other.type && - STREQ(name, other.name); -} - -static unsigned int id_deps_node_hash_key(const void *key_v) -{ - const IDDepsNode::ComponentIDKey *key = - reinterpret_cast<const IDDepsNode::ComponentIDKey *>(key_v); - return BLI_ghashutil_combine_hash(BLI_ghashutil_uinthash(key->type), - BLI_ghashutil_strhash_p(key->name)); -} - -static bool id_deps_node_hash_key_cmp(const void *a, const void *b) -{ - const IDDepsNode::ComponentIDKey *key_a = - reinterpret_cast<const IDDepsNode::ComponentIDKey *>(a); - const IDDepsNode::ComponentIDKey *key_b = - reinterpret_cast<const IDDepsNode::ComponentIDKey *>(b); - return !(*key_a == *key_b); -} - -static void id_deps_node_hash_key_free(void *key_v) -{ - typedef IDDepsNode::ComponentIDKey ComponentIDKey; - ComponentIDKey *key = reinterpret_cast<ComponentIDKey *>(key_v); - OBJECT_GUARDED_DELETE(key, ComponentIDKey); -} - -static void id_deps_node_hash_value_free(void *value_v) -{ - ComponentDepsNode *comp_node = reinterpret_cast<ComponentDepsNode *>(value_v); - OBJECT_GUARDED_DELETE(comp_node, ComponentDepsNode); -} - -/* Initialize 'id' node - from pointer data given. */ -void IDDepsNode::init(const ID *id, const char *UNUSED(subdata)) -{ - BLI_assert(id != NULL); - /* Store ID-pointer. */ - id_orig = (ID *)id; - eval_flags = 0; - linked_state = DEG_ID_LINKED_INDIRECTLY; - - components = BLI_ghash_new(id_deps_node_hash_key, - id_deps_node_hash_key_cmp, - "Depsgraph id components hash"); -} - -void IDDepsNode::init_copy_on_write(ID *id_cow_hint) -{ - /* Early output for non-copy-on-write case: we keep CoW pointer same as - * an original one. - */ - if (!DEG_depsgraph_use_copy_on_write()) { - UNUSED_VARS(id_cow_hint); - id_cow = id_orig; - return; +eDepsNode_Class DepsNode::get_class() const { + if (type == DEG_NODE_TYPE_OPERATION) { + return DEG_NODE_CLASS_OPERATION; } - /* Create pointer as early as possible, so we can use it for function - * bindings. Rest of data we'll be copying to the new datablock when - * it is actually needed. - */ - if (id_cow_hint != NULL) { - // BLI_assert(deg_copy_on_write_is_needed(id_orig)); - if (deg_copy_on_write_is_needed(id_orig)) { - id_cow = id_cow_hint; - } - else { - id_cow = id_orig; - } - } - else if (deg_copy_on_write_is_needed(id_orig)) { - id_cow = (ID *)BKE_libblock_alloc_notest(GS(id_orig->name)); - DEG_COW_PRINT("Create shallow copy for %s: id_orig=%p id_cow=%p\n", - id_orig->name, id_orig, id_cow); - deg_tag_copy_on_write_id(id_cow, id_orig); + else if (type < DEG_NODE_TYPE_PARAMETERS) { + return DEG_NODE_CLASS_GENERIC; } else { - id_cow = id_orig; - } -} - -/* Free 'id' node. */ -IDDepsNode::~IDDepsNode() -{ - destroy(); -} - -void IDDepsNode::destroy() -{ - if (id_orig == NULL) { - return; - } - - BLI_ghash_free(components, - id_deps_node_hash_key_free, - id_deps_node_hash_value_free); - - /* Free memory used by this CoW ID. */ - if (id_cow != id_orig && id_cow != NULL) { - deg_free_copy_on_write_datablock(id_cow); - MEM_freeN(id_cow); - DEG_COW_PRINT("Destroy CoW for %s: id_orig=%p id_cow=%p\n", - id_orig->name, id_orig, id_cow); - } - - /* Tag that the node is freed. */ - id_orig = NULL; -} - -ComponentDepsNode *IDDepsNode::find_component(eDepsNode_Type type, - const char *name) const -{ - ComponentIDKey key(type, name); - return reinterpret_cast<ComponentDepsNode *>(BLI_ghash_lookup(components, &key)); -} - -ComponentDepsNode *IDDepsNode::add_component(eDepsNode_Type type, - const char *name) -{ - ComponentDepsNode *comp_node = find_component(type, name); - if (!comp_node) { - DepsNodeFactory *factory = deg_type_get_factory(type); - comp_node = (ComponentDepsNode *)factory->create_node(this->id_orig, "", name); - - /* Register. */ - ComponentIDKey *key = OBJECT_GUARDED_NEW(ComponentIDKey, type, name); - BLI_ghash_insert(components, key, comp_node); - comp_node->owner = this; + return DEG_NODE_CLASS_COMPONENT; } - return comp_node; } -void IDDepsNode::tag_update(Depsgraph *graph) -{ - GHASH_FOREACH_BEGIN(ComponentDepsNode *, comp_node, components) - { - comp_node->tag_update(graph); - } - GHASH_FOREACH_END(); -} - -void IDDepsNode::finalize_build(Depsgraph *graph) -{ - /* Finalize build of all components. */ - GHASH_FOREACH_BEGIN(ComponentDepsNode *, comp_node, components) - { - comp_node->finalize_build(graph); - } - GHASH_FOREACH_END(); -} +/******************************************************************************* + * Generic nodes definition. + */ +\ +DEG_DEPSNODE_DEFINE(TimeSourceDepsNode, DEG_NODE_TYPE_TIMESOURCE, "Time Source"); +static DepsNodeFactoryImpl<TimeSourceDepsNode> DNTI_TIMESOURCE; DEG_DEPSNODE_DEFINE(IDDepsNode, DEG_NODE_TYPE_ID_REF, "ID Node"); static DepsNodeFactoryImpl<IDDepsNode> DNTI_ID_REF; diff --git a/source/blender/depsgraph/intern/nodes/deg_node.h b/source/blender/depsgraph/intern/nodes/deg_node.h index fd3ed694c9c..603a6be7ceb 100644 --- a/source/blender/depsgraph/intern/nodes/deg_node.h +++ b/source/blender/depsgraph/intern/nodes/deg_node.h @@ -51,22 +51,24 @@ struct OperationDepsNode; struct DepsNode { /* Helper class for static typeinfo in subclasses. */ struct TypeInfo { - TypeInfo(eDepsNode_Type type, const char *tname); - + TypeInfo(eDepsNode_Type type, const char *tname, int id_recalc_tag = 0); eDepsNode_Type type; - eDepsNode_Class tclass; const char *tname; + int id_recalc_tag; + }; + struct Stats { + Stats(); + /* Reset all the counters. Including all stats needed for average + * evaluation time calculation. + */ + void reset(); + /* Reset counters needed for the current graph evaluation, does not + * touch averaging accumulators. + */ + void reset_current(); + /* Time spend on this node during current graph evaluation. */ + double current_time; }; - - /* Identifier - mainly for debugging purposes. */ - const char *name; - - /* Structural type of node. */ - eDepsNode_Type type; - - /* Type of data/behaviour represented by node... */ - eDepsNode_Class tclass; - /* Relationships between nodes * The reason why all depsgraph nodes are descended from this type (apart * from basic serialization benefits - from the typeinfo) is that we can have @@ -74,23 +76,18 @@ struct DepsNode { */ typedef vector<DepsRelation *> Relations; - /* Nodes which this one depends on. */ - Relations inlinks; - - /* Nodes which depend on this one. */ - Relations outlinks; - - /* Generic tags for traversal algorithms. */ - int done; - int tag; + const char *name; /* Identifier - mainly for debugging purposes. */ + eDepsNode_Type type; /* Structural type of node. */ + Relations inlinks; /* Nodes which this one depends on. */ + Relations outlinks; /* Nodes which depend on this one. */ + int done; /* Generic tags for traversal algorithms. */ + Stats stats; /* Evaluation statistics. */ /* Methods. */ - DepsNode(); virtual ~DepsNode(); virtual string identifier() const; - string full_identifier() const; virtual void init(const ID * /*id*/, const char * /*subdata*/) {} @@ -99,6 +96,8 @@ struct DepsNode { virtual OperationDepsNode *get_entry_operation() { return NULL; } virtual OperationDepsNode *get_exit_operation() { return NULL; } + + virtual eDepsNode_Class get_class() const; }; /* Macros for common static typeinfo. */ @@ -107,68 +106,6 @@ struct DepsNode { #define DEG_DEPSNODE_DEFINE(NodeType, type_, tname_) \ const DepsNode::TypeInfo NodeType::typeinfo = DepsNode::TypeInfo(type_, tname_) -/* Generic Nodes ======================= */ - -struct ComponentDepsNode; -struct IDDepsNode; - -/* Time Source Node. */ -struct TimeSourceDepsNode : public DepsNode { - /* New "current time". */ - float cfra; - - /* time-offset relative to the "official" time source that this one has. */ - float offset; - - // TODO: evaluate() operation needed - - void tag_update(Depsgraph *graph); - - DEG_DEPSNODE_DECLARE; -}; - -/* ID-Block Reference */ -struct IDDepsNode : public DepsNode { - struct ComponentIDKey { - ComponentIDKey(eDepsNode_Type type, const char *name = ""); - bool operator==(const ComponentIDKey &other) const; - - eDepsNode_Type type; - const char *name; - }; - - void init(const ID *id, const char *subdata); - void init_copy_on_write(ID *id_cow_hint = NULL); - ~IDDepsNode(); - void destroy(); - - ComponentDepsNode *find_component(eDepsNode_Type type, - const char *name = "") const; - ComponentDepsNode *add_component(eDepsNode_Type type, - const char *name = ""); - - void tag_update(Depsgraph *graph); - - void finalize_build(Depsgraph *graph); - - /* ID Block referenced. */ - ID *id_orig; - ID *id_cow; - - /* Hash to make it faster to look up components. */ - GHash *components; - - /* Additional flags needed for scene evaluation. - * TODO(sergey): Only needed for until really granular updates - * of all the entities. - */ - int eval_flags; - - eDepsNode_LinkedState_Type linked_state; - - DEG_DEPSNODE_DECLARE; -}; - void deg_register_base_depsnodes(); } // namespace DEG diff --git a/source/blender/depsgraph/intern/nodes/deg_node_component.cc b/source/blender/depsgraph/intern/nodes/deg_node_component.cc index f4530ecebdb..1f56edd1f87 100644 --- a/source/blender/depsgraph/intern/nodes/deg_node_component.cc +++ b/source/blender/depsgraph/intern/nodes/deg_node_component.cc @@ -42,6 +42,7 @@ extern "C" { #include "BKE_action.h" } /* extern "C" */ +#include "intern/nodes/deg_node_id.h" #include "intern/nodes/deg_node_operation.h" #include "intern/depsgraph_intern.h" #include "util/deg_util_foreach.h" @@ -355,30 +356,6 @@ void ComponentDepsNode::finalize_build(Depsgraph * /*graph*/) operations_map = NULL; } -/* Register all components. =============================== */ - -#define DEG_COMPONENT_DEFINE(name, NAME) \ - DEG_DEPSNODE_DEFINE(name ## ComponentDepsNode, \ - DEG_NODE_TYPE_ ## NAME, \ - #name " Component"); \ -static DepsNodeFactoryImpl<name ## ComponentDepsNode> DNTI_ ## NAME - - -DEG_COMPONENT_DEFINE(Animation, ANIMATION); -DEG_COMPONENT_DEFINE(BatchCache, BATCH_CACHE); -DEG_COMPONENT_DEFINE(Cache, CACHE); -DEG_COMPONENT_DEFINE(CopyOnWrite, COPY_ON_WRITE); -DEG_COMPONENT_DEFINE(Geometry, GEOMETRY); -DEG_COMPONENT_DEFINE(LayerCollections, LAYER_COLLECTIONS); -DEG_COMPONENT_DEFINE(Parameters, PARAMETERS); -DEG_COMPONENT_DEFINE(Particles, EVAL_PARTICLES); -DEG_COMPONENT_DEFINE(Proxy, PROXY); -DEG_COMPONENT_DEFINE(Pose, EVAL_POSE); -DEG_COMPONENT_DEFINE(Sequencer, SEQUENCER); -DEG_COMPONENT_DEFINE(Shading, SHADING); -DEG_COMPONENT_DEFINE(ShadingParameters, SHADING_PARAMETERS); -DEG_COMPONENT_DEFINE(Transform, TRANSFORM); - /* Bone Component ========================================= */ /* Initialize 'bone component' node - from pointer data given */ @@ -398,7 +375,23 @@ void BoneComponentDepsNode::init(const ID *id, const char *subdata) this->pchan = BKE_pose_channel_find_name(object->pose, subdata); } -DEG_COMPONENT_DEFINE(Bone, BONE); +/* Register all components. =============================== */ + +DEG_COMPONENT_NODE_DEFINE(Animation, ANIMATION, ID_RECALC_ANIMATION); +DEG_COMPONENT_NODE_DEFINE(BatchCache, BATCH_CACHE, ID_RECALC_DRAW_CACHE); +DEG_COMPONENT_NODE_DEFINE(Bone, BONE, ID_RECALC_GEOMETRY); +DEG_COMPONENT_NODE_DEFINE(Cache, CACHE, ID_RECALC); +DEG_COMPONENT_NODE_DEFINE(CopyOnWrite, COPY_ON_WRITE, ID_RECALC); +DEG_COMPONENT_NODE_DEFINE(Geometry, GEOMETRY, ID_RECALC_GEOMETRY); +DEG_COMPONENT_NODE_DEFINE(LayerCollections, LAYER_COLLECTIONS, ID_RECALC_COLLECTIONS); +DEG_COMPONENT_NODE_DEFINE(Parameters, PARAMETERS, ID_RECALC); +DEG_COMPONENT_NODE_DEFINE(Particles, EVAL_PARTICLES, ID_RECALC_GEOMETRY); +DEG_COMPONENT_NODE_DEFINE(Proxy, PROXY, ID_RECALC_GEOMETRY); +DEG_COMPONENT_NODE_DEFINE(Pose, EVAL_POSE, ID_RECALC_GEOMETRY); +DEG_COMPONENT_NODE_DEFINE(Sequencer, SEQUENCER, ID_RECALC); +DEG_COMPONENT_NODE_DEFINE(Shading, SHADING, ID_RECALC_DRAW); +DEG_COMPONENT_NODE_DEFINE(ShadingParameters, SHADING_PARAMETERS, ID_RECALC_DRAW); +DEG_COMPONENT_NODE_DEFINE(Transform, TRANSFORM, ID_RECALC_TRANSFORM); /* Node Types Register =================================== */ diff --git a/source/blender/depsgraph/intern/nodes/deg_node_component.h b/source/blender/depsgraph/intern/nodes/deg_node_component.h index ba4f8551fea..b8009cc0a7f 100644 --- a/source/blender/depsgraph/intern/nodes/deg_node_component.h +++ b/source/blender/depsgraph/intern/nodes/deg_node_component.h @@ -46,6 +46,7 @@ namespace DEG { struct Depsgraph; struct OperationDepsNode; struct BoneComponentDepsNode; +struct IDDepsNode; /* ID Component - Base type for all components */ struct ComponentDepsNode : public DepsNode { @@ -123,19 +124,6 @@ struct ComponentDepsNode : public DepsNode { void tag_update(Depsgraph *graph); - /* Evaluation Context Management .................. */ - - /* Initialize component's evaluation context used for the specified - * purpose. - */ - virtual bool eval_context_init(EvaluationContext * /*eval_ctx*/) { return false; } - /* Free data in component's evaluation context which is used for - * the specified purpose - * - * NOTE: this does not free the actual context in question - */ - virtual void eval_context_free(EvaluationContext * /*eval_ctx*/) {} - OperationDepsNode *get_entry_operation(); OperationDepsNode *get_exit_operation(); @@ -164,25 +152,38 @@ struct ComponentDepsNode : public DepsNode { /* ---------------------------------------- */ -#define DEG_COMPONENT_DECLARE_GENERIC(name) \ +#define DEG_COMPONENT_NODE_DEFINE_TYPEINFO(NodeType, type_, tname_, id_recalc_tag) \ + const DepsNode::TypeInfo NodeType::typeinfo = \ + DepsNode::TypeInfo(type_, tname_, id_recalc_tag) + +#define DEG_COMPONENT_NODE_DECLARE DEG_DEPSNODE_DECLARE + +#define DEG_COMPONENT_NODE_DEFINE(name, NAME, id_recalc_tag) \ + DEG_COMPONENT_NODE_DEFINE_TYPEINFO(name ## ComponentDepsNode, \ + DEG_NODE_TYPE_ ## NAME, \ + #name " Component", \ + id_recalc_tag) ; \ + static DepsNodeFactoryImpl<name ## ComponentDepsNode> DNTI_ ## NAME + +#define DEG_COMPONENT_NODE_DECLARE_GENERIC(name) \ struct name ## ComponentDepsNode : public ComponentDepsNode { \ - DEG_DEPSNODE_DECLARE; \ + DEG_COMPONENT_NODE_DECLARE; \ } -DEG_COMPONENT_DECLARE_GENERIC(Animation); -DEG_COMPONENT_DECLARE_GENERIC(BatchCache); -DEG_COMPONENT_DECLARE_GENERIC(Cache); -DEG_COMPONENT_DECLARE_GENERIC(CopyOnWrite); -DEG_COMPONENT_DECLARE_GENERIC(Geometry); -DEG_COMPONENT_DECLARE_GENERIC(LayerCollections); -DEG_COMPONENT_DECLARE_GENERIC(Parameters); -DEG_COMPONENT_DECLARE_GENERIC(Particles); -DEG_COMPONENT_DECLARE_GENERIC(Proxy); -DEG_COMPONENT_DECLARE_GENERIC(Pose); -DEG_COMPONENT_DECLARE_GENERIC(Sequencer); -DEG_COMPONENT_DECLARE_GENERIC(Shading); -DEG_COMPONENT_DECLARE_GENERIC(ShadingParameters); -DEG_COMPONENT_DECLARE_GENERIC(Transform); +DEG_COMPONENT_NODE_DECLARE_GENERIC(Animation); +DEG_COMPONENT_NODE_DECLARE_GENERIC(BatchCache); +DEG_COMPONENT_NODE_DECLARE_GENERIC(Cache); +DEG_COMPONENT_NODE_DECLARE_GENERIC(CopyOnWrite); +DEG_COMPONENT_NODE_DECLARE_GENERIC(Geometry); +DEG_COMPONENT_NODE_DECLARE_GENERIC(LayerCollections); +DEG_COMPONENT_NODE_DECLARE_GENERIC(Parameters); +DEG_COMPONENT_NODE_DECLARE_GENERIC(Particles); +DEG_COMPONENT_NODE_DECLARE_GENERIC(Proxy); +DEG_COMPONENT_NODE_DECLARE_GENERIC(Pose); +DEG_COMPONENT_NODE_DECLARE_GENERIC(Sequencer); +DEG_COMPONENT_NODE_DECLARE_GENERIC(Shading); +DEG_COMPONENT_NODE_DECLARE_GENERIC(ShadingParameters); +DEG_COMPONENT_NODE_DECLARE_GENERIC(Transform); /* Bone Component */ struct BoneComponentDepsNode : public ComponentDepsNode { @@ -190,7 +191,7 @@ struct BoneComponentDepsNode : public ComponentDepsNode { struct bPoseChannel *pchan; /* the bone that this component represents */ - DEG_DEPSNODE_DECLARE; + DEG_COMPONENT_NODE_DECLARE; }; void deg_register_component_depsnodes(); diff --git a/source/blender/depsgraph/intern/nodes/deg_node_id.cc b/source/blender/depsgraph/intern/nodes/deg_node_id.cc new file mode 100644 index 00000000000..edc5c0114f9 --- /dev/null +++ b/source/blender/depsgraph/intern/nodes/deg_node_id.cc @@ -0,0 +1,217 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2013 Blender Foundation. + * All rights reserved. + * + * Original Author: Joshua Leung + * Contributor(s): None Yet + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/depsgraph/intern/nodes/deg_node_id.cc + * \ingroup depsgraph + */ + +#include "intern/nodes/deg_node_id.h" + +#include <stdio.h> +#include <cstring> /* required for STREQ later on. */ + +#include "BLI_utildefines.h" +#include "BLI_ghash.h" + +extern "C" { +#include "DNA_ID.h" +#include "DNA_anim_types.h" + +#include "BKE_animsys.h" +#include "BKE_library.h" +} + +#include "DEG_depsgraph.h" + +#include "intern/eval/deg_eval_copy_on_write.h" +#include "intern/nodes/deg_node_time.h" +#include "intern/depsgraph_intern.h" + +#include "util/deg_util_foreach.h" + +namespace DEG { + +IDDepsNode::ComponentIDKey::ComponentIDKey(eDepsNode_Type type, + const char *name) + : type(type), name(name) +{ +} + +bool IDDepsNode::ComponentIDKey::operator== (const ComponentIDKey &other) const +{ + return type == other.type && + STREQ(name, other.name); +} + +static unsigned int id_deps_node_hash_key(const void *key_v) +{ + const IDDepsNode::ComponentIDKey *key = + reinterpret_cast<const IDDepsNode::ComponentIDKey *>(key_v); + return BLI_ghashutil_combine_hash(BLI_ghashutil_uinthash(key->type), + BLI_ghashutil_strhash_p(key->name)); +} + +static bool id_deps_node_hash_key_cmp(const void *a, const void *b) +{ + const IDDepsNode::ComponentIDKey *key_a = + reinterpret_cast<const IDDepsNode::ComponentIDKey *>(a); + const IDDepsNode::ComponentIDKey *key_b = + reinterpret_cast<const IDDepsNode::ComponentIDKey *>(b); + return !(*key_a == *key_b); +} + +static void id_deps_node_hash_key_free(void *key_v) +{ + typedef IDDepsNode::ComponentIDKey ComponentIDKey; + ComponentIDKey *key = reinterpret_cast<ComponentIDKey *>(key_v); + OBJECT_GUARDED_DELETE(key, ComponentIDKey); +} + +static void id_deps_node_hash_value_free(void *value_v) +{ + ComponentDepsNode *comp_node = reinterpret_cast<ComponentDepsNode *>(value_v); + OBJECT_GUARDED_DELETE(comp_node, ComponentDepsNode); +} + +/* Initialize 'id' node - from pointer data given. */ +void IDDepsNode::init(const ID *id, const char *UNUSED(subdata)) +{ + BLI_assert(id != NULL); + /* Store ID-pointer. */ + id_orig = (ID *)id; + eval_flags = 0; + linked_state = DEG_ID_LINKED_INDIRECTLY; + + components = BLI_ghash_new(id_deps_node_hash_key, + id_deps_node_hash_key_cmp, + "Depsgraph id components hash"); +} + +void IDDepsNode::init_copy_on_write(ID *id_cow_hint) +{ + /* Early output for non-copy-on-write case: we keep CoW pointer same as + * an original one. + */ + if (!DEG_depsgraph_use_copy_on_write()) { + UNUSED_VARS(id_cow_hint); + id_cow = id_orig; + return; + } + /* Create pointer as early as possible, so we can use it for function + * bindings. Rest of data we'll be copying to the new datablock when + * it is actually needed. + */ + if (id_cow_hint != NULL) { + // BLI_assert(deg_copy_on_write_is_needed(id_orig)); + if (deg_copy_on_write_is_needed(id_orig)) { + id_cow = id_cow_hint; + } + else { + id_cow = id_orig; + } + } + else if (deg_copy_on_write_is_needed(id_orig)) { + id_cow = (ID *)BKE_libblock_alloc_notest(GS(id_orig->name)); + DEG_COW_PRINT("Create shallow copy for %s: id_orig=%p id_cow=%p\n", + id_orig->name, id_orig, id_cow); + deg_tag_copy_on_write_id(id_cow, id_orig); + } + else { + id_cow = id_orig; + } +} + +/* Free 'id' node. */ +IDDepsNode::~IDDepsNode() +{ + destroy(); +} + +void IDDepsNode::destroy() +{ + if (id_orig == NULL) { + return; + } + + BLI_ghash_free(components, + id_deps_node_hash_key_free, + id_deps_node_hash_value_free); + + /* Free memory used by this CoW ID. */ + if (id_cow != id_orig && id_cow != NULL) { + deg_free_copy_on_write_datablock(id_cow); + MEM_freeN(id_cow); + DEG_COW_PRINT("Destroy CoW for %s: id_orig=%p id_cow=%p\n", + id_orig->name, id_orig, id_cow); + } + + /* Tag that the node is freed. */ + id_orig = NULL; +} + +ComponentDepsNode *IDDepsNode::find_component(eDepsNode_Type type, + const char *name) const +{ + ComponentIDKey key(type, name); + return reinterpret_cast<ComponentDepsNode *>(BLI_ghash_lookup(components, &key)); +} + +ComponentDepsNode *IDDepsNode::add_component(eDepsNode_Type type, + const char *name) +{ + ComponentDepsNode *comp_node = find_component(type, name); + if (!comp_node) { + DepsNodeFactory *factory = deg_type_get_factory(type); + comp_node = (ComponentDepsNode *)factory->create_node(this->id_orig, "", name); + + /* Register. */ + ComponentIDKey *key = OBJECT_GUARDED_NEW(ComponentIDKey, type, name); + BLI_ghash_insert(components, key, comp_node); + comp_node->owner = this; + } + return comp_node; +} + +void IDDepsNode::tag_update(Depsgraph *graph) +{ + GHASH_FOREACH_BEGIN(ComponentDepsNode *, comp_node, components) + { + comp_node->tag_update(graph); + } + GHASH_FOREACH_END(); +} + +void IDDepsNode::finalize_build(Depsgraph *graph) +{ + /* Finalize build of all components. */ + GHASH_FOREACH_BEGIN(ComponentDepsNode *, comp_node, components) + { + comp_node->finalize_build(graph); + } + GHASH_FOREACH_END(); +} + +} // namespace DEG diff --git a/source/blender/depsgraph/intern/nodes/deg_node_id.h b/source/blender/depsgraph/intern/nodes/deg_node_id.h new file mode 100644 index 00000000000..505a1129192 --- /dev/null +++ b/source/blender/depsgraph/intern/nodes/deg_node_id.h @@ -0,0 +1,81 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2013 Blender Foundation. + * All rights reserved. + * + * Original Author: Joshua Leung + * Contributor(s): None Yet + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file depsgraph/intern/nodes/deg_node_id.h + * \ingroup depsgraph + */ + +#pragma once + +#include "intern/nodes/deg_node.h" + +namespace DEG { + +struct ComponentDepsNode; + +/* ID-Block Reference */ +struct IDDepsNode : public DepsNode { + struct ComponentIDKey { + ComponentIDKey(eDepsNode_Type type, const char *name = ""); + bool operator==(const ComponentIDKey &other) const; + + eDepsNode_Type type; + const char *name; + }; + + void init(const ID *id, const char *subdata); + void init_copy_on_write(ID *id_cow_hint = NULL); + ~IDDepsNode(); + void destroy(); + + ComponentDepsNode *find_component(eDepsNode_Type type, + const char *name = "") const; + ComponentDepsNode *add_component(eDepsNode_Type type, + const char *name = ""); + + void tag_update(Depsgraph *graph); + + void finalize_build(Depsgraph *graph); + + /* ID Block referenced. */ + ID *id_orig; + ID *id_cow; + + /* Hash to make it faster to look up components. */ + GHash *components; + + /* Additional flags needed for scene evaluation. + * TODO(sergey): Only needed for until really granular updates + * of all the entities. + */ + int eval_flags; + + eDepsNode_LinkedState_Type linked_state; + + DEG_DEPSNODE_DECLARE; +}; + +} // namespace DEG diff --git a/source/blender/depsgraph/intern/nodes/deg_node_operation.cc b/source/blender/depsgraph/intern/nodes/deg_node_operation.cc index 7467264f612..cbc0fbb4241 100644 --- a/source/blender/depsgraph/intern/nodes/deg_node_operation.cc +++ b/source/blender/depsgraph/intern/nodes/deg_node_operation.cc @@ -37,6 +37,7 @@ #include "intern/depsgraph.h" #include "intern/depsgraph_intern.h" +#include "intern/nodes/deg_node_id.h" namespace DEG { @@ -44,7 +45,6 @@ namespace DEG { /* Inner Nodes */ OperationDepsNode::OperationDepsNode() : - eval_priority(0.0f), flag(0), customdata_mask(0) { diff --git a/source/blender/depsgraph/intern/nodes/deg_node_operation.h b/source/blender/depsgraph/intern/nodes/deg_node_operation.h index d8203540fc5..c172f73be5f 100644 --- a/source/blender/depsgraph/intern/nodes/deg_node_operation.h +++ b/source/blender/depsgraph/intern/nodes/deg_node_operation.h @@ -38,6 +38,8 @@ struct Depsgraph; namespace DEG { +struct ComponentDepsNode; + /* Flags for Depsgraph Nodes */ typedef enum eDepsOperation_Flag { /* node needs to be updated */ @@ -74,7 +76,6 @@ struct OperationDepsNode : public DepsNode { /* How many inlinks are we still waiting on before we can be evaluated. */ uint32_t num_links_pending; - float eval_priority; bool scheduled; /* Identifier for the operation being performed. */ diff --git a/source/blender/depsgraph/intern/nodes/deg_node_time.cc b/source/blender/depsgraph/intern/nodes/deg_node_time.cc new file mode 100644 index 00000000000..230488b2328 --- /dev/null +++ b/source/blender/depsgraph/intern/nodes/deg_node_time.cc @@ -0,0 +1,46 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2013 Blender Foundation. + * All rights reserved. + * + * Original Author: Joshua Leung + * Contributor(s): None Yet + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/depsgraph/intern/nodes/deg_node_time.cc + * \ingroup depsgraph + */ + +#include "intern/nodes/deg_node_time.h" + +#include "intern/depsgraph_intern.h" +#include "util/deg_util_foreach.h" + +namespace DEG { + +void TimeSourceDepsNode::tag_update(Depsgraph *graph) +{ + foreach (DepsRelation *rel, outlinks) { + DepsNode *node = rel->to; + node->tag_update(graph); + } +} + +} // namespace DEG diff --git a/source/blender/depsgraph/intern/nodes/deg_node_time.h b/source/blender/depsgraph/intern/nodes/deg_node_time.h new file mode 100644 index 00000000000..93f3edef9cf --- /dev/null +++ b/source/blender/depsgraph/intern/nodes/deg_node_time.h @@ -0,0 +1,52 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2013 Blender Foundation. + * All rights reserved. + * + * Original Author: Joshua Leung + * Contributor(s): None Yet + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file depsgraph/intern/nodes/deg_node_time.h + * \ingroup depsgraph + */ + +#pragma once + +#include "intern/nodes/deg_node.h" + +namespace DEG { + +/* Time Source Node. */ +struct TimeSourceDepsNode : public DepsNode { + /* New "current time". */ + float cfra; + + /* time-offset relative to the "official" time source that this one has. */ + float offset; + + // TODO: evaluate() operation needed + + void tag_update(Depsgraph *graph); + + DEG_DEPSNODE_DECLARE; +}; + +} // namespace DEG diff --git a/source/blender/draw/DRW_engine.h b/source/blender/draw/DRW_engine.h index ba0f8681f10..7efd9639874 100644 --- a/source/blender/draw/DRW_engine.h +++ b/source/blender/draw/DRW_engine.h @@ -95,6 +95,7 @@ void DRW_draw_render_loop_offscreen( struct Depsgraph *graph, struct RenderEngineType *engine_type, struct ARegion *ar, struct View3D *v3d, + const bool draw_background, struct GPUOffScreen *ofs); void DRW_draw_select_loop( struct Depsgraph *graph, diff --git a/source/blender/draw/engines/clay/clay_engine.c b/source/blender/draw/engines/clay/clay_engine.c index 01f89ae6b1c..9f9ebd692b9 100644 --- a/source/blender/draw/engines/clay/clay_engine.c +++ b/source/blender/draw/engines/clay/clay_engine.c @@ -746,12 +746,45 @@ static void clay_cache_init(void *vedata) } } +static void clay_cache_populate_particles(void *vedata, Object *ob) +{ + CLAY_PassList *psl = ((CLAY_Data *)vedata)->psl; + CLAY_StorageList *stl = ((CLAY_Data *)vedata)->stl; + const DRWContextState *draw_ctx = DRW_context_state_get(); + + + Scene *scene = draw_ctx->scene; + Object *obedit = scene->obedit; + + if (ob != obedit) { + for (ParticleSystem *psys = ob->particlesystem.first; psys; psys = psys->next) { + if (psys_check_enabled(ob, psys, false)) { + ParticleSettings *part = psys->part; + int draw_as = (part->draw_as == PART_DRAW_REND) ? part->ren_as : part->draw_as; + + if (draw_as == PART_DRAW_PATH && !psys->pathcache && !psys->childcache) { + draw_as = PART_DRAW_DOT; + } + + static float mat[4][4]; + unit_m4(mat); + + if (draw_as == PART_DRAW_PATH) { + struct Gwn_Batch *geom = DRW_cache_particles_get_hair(psys, NULL); + DRWShadingGroup *hair_shgrp = CLAY_hair_shgrp_get(vedata, ob, stl, psl); + DRW_shgroup_call_add(hair_shgrp, geom, mat); + } + } + } + } +} + static void clay_cache_populate(void *vedata, Object *ob) { CLAY_PassList *psl = ((CLAY_Data *)vedata)->psl; CLAY_StorageList *stl = ((CLAY_Data *)vedata)->stl; - DRWShadingGroup *clay_shgrp, *hair_shgrp; + DRWShadingGroup *clay_shgrp; if (!DRW_object_is_renderable(ob)) return; @@ -764,6 +797,15 @@ static void clay_cache_populate(void *vedata, Object *ob) } } + /* Handle particles first in case the emitter itself shouldn't be rendered. */ + if (ob->type == OB_MESH) { + clay_cache_populate_particles(vedata, ob); + } + + if (DRW_check_object_visible_within_active_context(ob) == false) { + return; + } + struct Gwn_Batch *geom = DRW_cache_object_surface_get(ob); if (geom) { IDProperty *ces_mode_ob = BKE_layer_collection_engine_evaluated_get(ob, COLLECTION_MODE_OBJECT, ""); @@ -797,33 +839,6 @@ static void clay_cache_populate(void *vedata, Object *ob) DRW_shgroup_call_add(clay_shgrp, geom, ob->obmat); } } - - if (ob->type == OB_MESH) { - Scene *scene = draw_ctx->scene; - Object *obedit = scene->obedit; - - if (ob != obedit) { - for (ParticleSystem *psys = ob->particlesystem.first; psys; psys = psys->next) { - if (psys_check_enabled(ob, psys, false)) { - ParticleSettings *part = psys->part; - int draw_as = (part->draw_as == PART_DRAW_REND) ? part->ren_as : part->draw_as; - - if (draw_as == PART_DRAW_PATH && !psys->pathcache && !psys->childcache) { - draw_as = PART_DRAW_DOT; - } - - static float mat[4][4]; - unit_m4(mat); - - if (draw_as == PART_DRAW_PATH) { - geom = DRW_cache_particles_get_hair(psys, NULL); - hair_shgrp = CLAY_hair_shgrp_get(vedata, ob, stl, psl); - DRW_shgroup_call_add(hair_shgrp, geom, mat); - } - } - } - } - } } static void clay_cache_finish(void *vedata) diff --git a/source/blender/draw/engines/eevee/eevee_engine.c b/source/blender/draw/engines/eevee/eevee_engine.c index f24381e1fb4..31ce5d4174d 100644 --- a/source/blender/draw/engines/eevee/eevee_engine.c +++ b/source/blender/draw/engines/eevee/eevee_engine.c @@ -56,7 +56,7 @@ static void eevee_engine_init(void *ved) /* Alloc transient pointers */ stl->g_data = MEM_callocN(sizeof(*stl->g_data), __func__); } - stl->g_data->background_alpha = 1.0f; + stl->g_data->background_alpha = DRW_state_draw_background() ? 1.0f : 0.0f; stl->g_data->valid_double_buffer = (txl->color_double_buffer != NULL); DRWFboTexture tex = {&txl->color, DRW_TEX_RGBA_16, DRW_TEX_FILTER | DRW_TEX_MIPMAP}; @@ -113,6 +113,10 @@ static void eevee_cache_populate(void *vedata, Object *ob) } } + if (DRW_check_object_visible_within_active_context(ob) == false) { + return; + } + if (ELEM(ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_FONT)) { EEVEE_materials_cache_populate(vedata, sldata, ob); @@ -283,6 +287,13 @@ static void eevee_view_update(void *vedata) static void eevee_id_update(void *UNUSED(vedata), ID *id) { + /* This is a bit mask of components which update is to be ignored. */ + const int ignore_updates = ID_RECALC_COLLECTIONS; + /* Check whether we have to do anything here. */ + if ((id->recalc & ~ignore_updates) == 0) { + return; + } + /* Handle updates based on ID type. */ const ID_Type id_type = GS(id->name); if (id_type == ID_OB) { Object *object = (Object *)id; @@ -407,8 +418,8 @@ DrawEngineType draw_engine_eevee_type = { &eevee_cache_init, &eevee_cache_populate, &eevee_cache_finish, + NULL, &eevee_draw_scene, - NULL, //&EEVEE_draw_scene &eevee_view_update, &eevee_id_update, }; diff --git a/source/blender/draw/intern/DRW_render.h b/source/blender/draw/intern/DRW_render.h index 0753dbc7a1a..505371d8e3b 100644 --- a/source/blender/draw/intern/DRW_render.h +++ b/source/blender/draw/intern/DRW_render.h @@ -396,6 +396,7 @@ void DRW_lamp_engine_data_free(struct LampEngineData *led); /* Settings */ bool DRW_object_is_renderable(struct Object *ob); +bool DRW_check_object_visible_within_active_context(struct Object *ob); bool DRW_object_is_flat_normal(const struct Object *ob); int DRW_object_is_mode_shade(const struct Object *ob); @@ -431,6 +432,9 @@ bool DRW_state_is_image_render(void); bool DRW_state_is_scene_render(void); bool DRW_state_show_text(void); bool DRW_state_draw_support(void); +bool DRW_state_draw_background(void); + +enum eDepsObjectIteratorMode DRW_iterator_mode_get(void); struct DRWTextStore *DRW_state_text_cache_get(void); diff --git a/source/blender/draw/intern/draw_cache_impl_curve.c b/source/blender/draw/intern/draw_cache_impl_curve.c index 6d98195495f..a6dc52f66c9 100644 --- a/source/blender/draw/intern/draw_cache_impl_curve.c +++ b/source/blender/draw/intern/draw_cache_impl_curve.c @@ -126,7 +126,8 @@ static int curve_render_normal_len_get(const ListBase *lb, const CurveCache *ob_ nr -= skip; } #else - normal_len += max_ii((nr + max_ii(skip - 1, 0)) / (skip + 1), 0); + /* Same as loop above */ + normal_len += (nr / (skip + 1)) + ((nr % (skip + 1)) != 0); #endif } return normal_len; @@ -1043,7 +1044,7 @@ Gwn_Batch **DRW_curve_batch_cache_get_surface_shaded( for (int i = 0; i < gpumat_array_len; ++i) { cache->surface.shaded_triangles[i] = GWN_batch_create_ex( - GWN_PRIM_TRIS, cache->surface.verts, el[i], el[i] ? GWN_BATCH_OWNS_INDEX : 0); + GWN_PRIM_TRIS, cache->surface.verts, el[i], GWN_BATCH_OWNS_INDEX); /* TODO: Add vertbuff for UV */ } diff --git a/source/blender/draw/intern/draw_cache_impl_displist.c b/source/blender/draw/intern/draw_cache_impl_displist.c index b055a023e79..fd095c0ce4f 100644 --- a/source/blender/draw/intern/draw_cache_impl_displist.c +++ b/source/blender/draw/intern/draw_cache_impl_displist.c @@ -128,32 +128,28 @@ Gwn_VertBuf *DRW_displist_vertbuf_calc_pos_with_normals(ListBase *lb) attr_id.nor = GWN_vertformat_attr_add(&format, "nor", GWN_COMP_F32, 3, GWN_FETCH_FLOAT); } - const int vert_len = curve_render_surface_vert_len_get(lb); Gwn_VertBuf *vbo = GWN_vertbuf_create_with_format(&format); - { - const int vbo_len_capacity = vert_len; - int vbo_len_used = 0; - GWN_vertbuf_data_alloc(vbo, vbo_len_capacity); - - BKE_displist_normals_add(lb); - - for (const DispList *dl = lb->first; dl; dl = dl->next) { - const bool ndata_is_single = dl->type == DL_INDEX3; - if (ELEM(dl->type, DL_INDEX3, DL_INDEX4, DL_SURF)) { - const float *fp_co = dl->verts; - const float *fp_no = dl->nors; - const int vbo_end = vbo_len_used + dl_vert_len(dl); - while (vbo_len_used < vbo_end) { - GWN_vertbuf_attr_set(vbo, attr_id.pos, vbo_len_used, fp_co); - if (fp_no) { - GWN_vertbuf_attr_set(vbo, attr_id.nor, vbo_len_used, fp_no); - if (ndata_is_single == false) { - fp_no += 3; - } + GWN_vertbuf_data_alloc(vbo, curve_render_surface_vert_len_get(lb)); + + BKE_displist_normals_add(lb); + + int vbo_len_used = 0; + for (const DispList *dl = lb->first; dl; dl = dl->next) { + const bool ndata_is_single = dl->type == DL_INDEX3; + if (ELEM(dl->type, DL_INDEX3, DL_INDEX4, DL_SURF)) { + const float *fp_co = dl->verts; + const float *fp_no = dl->nors; + const int vbo_end = vbo_len_used + dl_vert_len(dl); + while (vbo_len_used < vbo_end) { + GWN_vertbuf_attr_set(vbo, attr_id.pos, vbo_len_used, fp_co); + if (fp_no) { + GWN_vertbuf_attr_set(vbo, attr_id.nor, vbo_len_used, fp_no); + if (ndata_is_single == false) { + fp_no += 3; } - fp_co += 3; - vbo_len_used += 1; } + fp_co += 3; + vbo_len_used += 1; } } } @@ -164,52 +160,44 @@ Gwn_VertBuf *DRW_displist_vertbuf_calc_pos_with_normals(ListBase *lb) Gwn_IndexBuf *DRW_displist_indexbuf_calc_triangles_in_order(ListBase *lb) { const int tri_len = curve_render_surface_tri_len_get(lb); - if (tri_len == 0) { - return NULL; - } - const int vert_len = curve_render_surface_vert_len_get(lb); - { - Gwn_IndexBufBuilder elb; - GWN_indexbuf_init(&elb, GWN_PRIM_TRIS, tri_len, vert_len); - - int ofs = 0; - for (const DispList *dl = lb->first; dl; dl = dl->next) { - displist_indexbufbuilder_set(&elb, dl, ofs); - ofs += dl_vert_len(dl); - } + Gwn_IndexBufBuilder elb; + GWN_indexbuf_init(&elb, GWN_PRIM_TRIS, tri_len, vert_len); - return GWN_indexbuf_build(&elb); + int ofs = 0; + for (const DispList *dl = lb->first; dl; dl = dl->next) { + displist_indexbufbuilder_set(&elb, dl, ofs); + ofs += dl_vert_len(dl); } + + return GWN_indexbuf_build(&elb); } Gwn_IndexBuf **DRW_displist_indexbuf_calc_triangles_in_order_split_by_material(ListBase *lb, uint gpumat_array_len) { Gwn_IndexBuf **shaded_triangles_in_order = MEM_callocN(sizeof(*shaded_triangles_in_order) * gpumat_array_len, __func__); - const int tri_len = curve_render_surface_tri_len_get(lb); + Gwn_IndexBufBuilder *elb = BLI_array_alloca(elb, gpumat_array_len); - if (tri_len != 0) { - const int vert_len = curve_render_surface_vert_len_get(lb); - int i; - Gwn_IndexBufBuilder *elb = BLI_array_alloca(elb, gpumat_array_len); + const int tri_len = curve_render_surface_tri_len_get(lb); + const int vert_len = curve_render_surface_vert_len_get(lb); + int i; - /* Init each index buffer builder */ - for (i = 0; i < gpumat_array_len; i++) { - GWN_indexbuf_init(&elb[i], GWN_PRIM_TRIS, tri_len, vert_len); - } + /* Init each index buffer builder */ + for (i = 0; i < gpumat_array_len; i++) { + GWN_indexbuf_init(&elb[i], GWN_PRIM_TRIS, tri_len, vert_len); + } - /* calc each index buffer builder */ - int ofs = 0; - for (const DispList *dl = lb->first; dl; dl = dl->next) { - displist_indexbufbuilder_set(&elb[dl->col], dl, ofs); - ofs += dl_vert_len(dl); - } + /* calc each index buffer builder */ + int ofs = 0; + for (const DispList *dl = lb->first; dl; dl = dl->next) { + displist_indexbufbuilder_set(&elb[dl->col], dl, ofs); + ofs += dl_vert_len(dl); + } - /* build each indexbuf */ - for (i = 0; i < gpumat_array_len; i++) { - shaded_triangles_in_order[i] = GWN_indexbuf_build(&elb[i]); - } + /* build each indexbuf */ + for (i = 0; i < gpumat_array_len; i++) { + shaded_triangles_in_order[i] = GWN_indexbuf_build(&elb[i]); } return shaded_triangles_in_order; diff --git a/source/blender/draw/intern/draw_cache_impl_metaball.c b/source/blender/draw/intern/draw_cache_impl_metaball.c index 9a9bbbd2c0c..f01e7b929f8 100644 --- a/source/blender/draw/intern/draw_cache_impl_metaball.c +++ b/source/blender/draw/intern/draw_cache_impl_metaball.c @@ -133,10 +133,9 @@ Gwn_Batch *DRW_metaball_batch_cache_get_triangles_with_normals(Object *ob) if (cache->batch == NULL) { ListBase *lb = &ob->curve_cache->disp; - Gwn_VertBuf *verts = DRW_displist_vertbuf_calc_pos_with_normals(lb); cache->batch = GWN_batch_create_ex( GWN_PRIM_TRIS, - verts, + DRW_displist_vertbuf_calc_pos_with_normals(lb), DRW_displist_indexbuf_calc_triangles_in_order(lb), GWN_BATCH_OWNS_VBO | GWN_BATCH_OWNS_INDEX); } diff --git a/source/blender/draw/intern/draw_manager.c b/source/blender/draw/intern/draw_manager.c index 421d8f9088f..20eb4dd534d 100644 --- a/source/blender/draw/intern/draw_manager.c +++ b/source/blender/draw/intern/draw_manager.c @@ -354,6 +354,7 @@ static struct DRWGlobalState { unsigned int is_depth : 1; unsigned int is_image_render : 1; unsigned int is_scene_render : 1; + unsigned int draw_background : 1; } options; /* Current rendering context */ @@ -2214,7 +2215,7 @@ bool DRW_object_is_renderable(Object *ob) Scene *scene = DST.draw_ctx.scene; Object *obedit = scene->obedit; - BLI_assert(BKE_object_is_visible(ob)); + BLI_assert(BKE_object_is_visible(ob, OB_VISIBILITY_CHECK_UNKNOWN_RENDER_MODE)); if (ob->type == OB_MESH) { if (ob == obedit) { @@ -2233,6 +2234,18 @@ bool DRW_object_is_renderable(Object *ob) return true; } +/** + * Return whether this object is visible depending if + * we are rendering or drawing in the viewport. + */ +bool DRW_check_object_visible_within_active_context(Object *ob) +{ + const eObjectVisibilityCheck mode = DRW_state_is_scene_render() ? + OB_VISIBILITY_CHECK_FOR_RENDER : + OB_VISIBILITY_CHECK_FOR_VIEWPORT; + return BKE_object_is_visible(ob, mode); +} + bool DRW_object_is_flat_normal(const Object *ob) { if (ob->type == OB_MESH) { @@ -2244,7 +2257,6 @@ bool DRW_object_is_flat_normal(const Object *ob) return true; } - /** * Return true if the object has its own draw mode. * Caller must check this is active */ @@ -3405,7 +3417,7 @@ void DRW_draw_render_loop_ex( PROFILE_START(stime); drw_engines_cache_init(); - DEG_OBJECT_ITER_FOR_RENDER_ENGINE(graph, ob) + DEG_OBJECT_ITER_FOR_RENDER_ENGINE(graph, ob, DRW_iterator_mode_get()) { drw_engines_cache_populate(ob); } @@ -3419,7 +3431,10 @@ void DRW_draw_render_loop_ex( /* Start Drawing */ DRW_state_reset(); - drw_engines_draw_background(); + + if (DRW_state_draw_background()) { + drw_engines_draw_background(); + } /* WIP, single image drawn over the camera view (replace) */ bool do_bg_image = false; @@ -3506,7 +3521,7 @@ void DRW_draw_render_loop( void DRW_draw_render_loop_offscreen( struct Depsgraph *graph, RenderEngineType *engine_type, - ARegion *ar, View3D *v3d, GPUOffScreen *ofs) + ARegion *ar, View3D *v3d, const bool draw_background, GPUOffScreen *ofs) { RegionView3D *rv3d = ar->regiondata; @@ -3520,6 +3535,7 @@ void DRW_draw_render_loop_offscreen( /* Reset before using it. */ memset(&DST, 0x0, sizeof(DST)); DST.options.is_image_render = true; + DST.options.draw_background = draw_background; DRW_draw_render_loop_ex(graph, engine_type, ar, v3d, NULL); /* restore */ @@ -3618,7 +3634,7 @@ void DRW_draw_select_loop( drw_engines_cache_populate(scene->obedit); } else { - DEG_OBJECT_ITER(graph, ob, + DEG_OBJECT_ITER(graph, ob, DRW_iterator_mode_get(), DEG_ITER_OBJECT_FLAG_LINKED_DIRECTLY | DEG_ITER_OBJECT_FLAG_VISIBLE | DEG_ITER_OBJECT_FLAG_DUPLI) @@ -3713,7 +3729,7 @@ void DRW_draw_depth_loop( if (cache_is_dirty) { drw_engines_cache_init(); - DEG_OBJECT_ITER_FOR_RENDER_ENGINE(graph, ob) + DEG_OBJECT_ITER_FOR_RENDER_ENGINE(graph, ob, DRW_iterator_mode_get()) { drw_engines_cache_populate(ob); } @@ -3799,6 +3815,15 @@ bool DRW_state_is_scene_render(void) } /** + * Gives you the iterator mode to use for depsgraph. + */ +eDepsObjectIteratorMode DRW_iterator_mode_get(void) +{ + return DRW_state_is_scene_render() ? DEG_ITER_OBJECT_MODE_RENDER : + DEG_ITER_OBJECT_MODE_VIEWPORT; +} + +/** * Should text draw in this mode? */ bool DRW_state_show_text(void) @@ -3820,6 +3845,17 @@ bool DRW_state_draw_support(void) ((v3d->flag2 & V3D_RENDER_OVERRIDE) == 0); } +/** + * Whether we should render the background + */ +bool DRW_state_draw_background(void) +{ + if (DRW_state_is_image_render() == false) { + return true; + } + return DST.options.draw_background; +} + /** \} */ diff --git a/source/blender/draw/modes/object_mode.c b/source/blender/draw/modes/object_mode.c index e2263ef35f7..cd81ac59350 100644 --- a/source/blender/draw/modes/object_mode.c +++ b/source/blender/draw/modes/object_mode.c @@ -1675,7 +1675,7 @@ static void DRW_shgroup_lightprobe(OBJECT_StorageList *stl, OBJECT_PassList *psl static void DRW_shgroup_relationship_lines(OBJECT_StorageList *stl, Object *ob) { - if (ob->parent && BKE_object_is_visible(ob->parent)) { + if (ob->parent && DRW_check_object_visible_within_active_context(ob->parent)) { DRW_shgroup_call_dynamic_add(stl->g_data->relationship_lines, ob->obmat[3]); DRW_shgroup_call_dynamic_add(stl->g_data->relationship_lines, ob->parent->obmat[3]); } @@ -1790,6 +1790,15 @@ static void OBJECT_cache_populate(void *vedata, Object *ob) View3D *v3d = draw_ctx->v3d; int theme_id = TH_UNDEFINED; + /* Handle particles first in case the emitter itself shouldn't be rendered. */ + if (ob->type == OB_MESH) { + OBJECT_cache_populate_particles(ob, psl); + } + + if (DRW_check_object_visible_within_active_context(ob) == false) { + return; + } + //CollectionEngineSettings *ces_mode_ob = BKE_layer_collection_engine_evaluated_get(ob, COLLECTION_MODE_OBJECT, ""); //bool do_wire = BKE_collection_engine_property_value_get_bool(ces_mode_ob, "show_wire"); @@ -1827,8 +1836,6 @@ static void OBJECT_cache_populate(void *vedata, Object *ob) } } } - - OBJECT_cache_populate_particles(ob, psl); break; } case OB_SURF: diff --git a/source/blender/editors/include/UI_interface.h b/source/blender/editors/include/UI_interface.h index 4fc72200c04..c94a890b357 100644 --- a/source/blender/editors/include/UI_interface.h +++ b/source/blender/editors/include/UI_interface.h @@ -73,6 +73,7 @@ struct bNodeSocket; struct wmDropBox; struct wmDrag; struct wmEvent; +struct wmManipulator; struct wmMsgBus; typedef struct uiBut uiBut; @@ -1135,6 +1136,13 @@ void UI_butstore_register(uiButStore *bs_handle, uiBut **but_p); bool UI_butstore_register_update(uiBlock *block, uiBut *but_dst, const uiBut *but_src); void UI_butstore_unregister(uiButStore *bs_handle, uiBut **but_p); +/* ui_interface_region_tooltip.c */ +struct ARegion *UI_tooltip_create_from_button(struct bContext *C, struct ARegion *butregion, uiBut *but); +struct ARegion *UI_tooltip_create_from_manipulator(struct bContext *C, struct wmManipulator *mpr); +void UI_tooltip_free(struct bContext *C, struct ARegion *ar); + +/* How long before a tool-tip shows. */ +#define UI_TOOLTIP_DELAY 0.5 /* Float precision helpers */ #define UI_PRECISION_FLOAT_MAX 6 diff --git a/source/blender/editors/interface/interface_handlers.c b/source/blender/editors/interface/interface_handlers.c index f28a398a46a..5218a9b8216 100644 --- a/source/blender/editors/interface/interface_handlers.c +++ b/source/blender/editors/interface/interface_handlers.c @@ -130,7 +130,6 @@ static bool ui_mouse_motion_keynav_test(struct uiKeyNavLock *keynav, const wmEve /***************** structs and defines ****************/ -#define BUTTON_TOOLTIP_DELAY 0.500 #define BUTTON_FLASH_DELAY 0.020 #define MENU_SCROLL_INTERVAL 0.1 #define PIE_MENU_INTERVAL 0.01 @@ -7697,8 +7696,8 @@ void UI_but_tooltip_refresh(bContext *C, uiBut *but) data = but->active; if (data && data->tooltip) { - ui_tooltip_free(C, data->tooltip); - data->tooltip = ui_tooltip_create(C, data->region, but); + UI_tooltip_free(C, data->tooltip); + data->tooltip = UI_tooltip_create_from_button(C, data->region, but); } } @@ -7715,7 +7714,7 @@ void UI_but_tooltip_timer_remove(bContext *C, uiBut *but) data->tooltiptimer = NULL; } if (data->tooltip) { - ui_tooltip_free(C, data->tooltip); + UI_tooltip_free(C, data->tooltip); data->tooltip = NULL; } @@ -7741,7 +7740,7 @@ static void button_tooltip_timer_reset(bContext *C, uiBut *but) if ((U.flag & USER_TOOLTIPS) || (data->tooltip_force)) { if (!but->block->tooltipdisabled) { if (!wm->drags.first) { - data->tooltiptimer = WM_event_add_timer(data->wm, data->window, TIMER, BUTTON_TOOLTIP_DELAY); + data->tooltiptimer = WM_event_add_timer(data->wm, data->window, TIMER, UI_TOOLTIP_DELAY); } } } @@ -8443,7 +8442,7 @@ static int ui_handle_button_event(bContext *C, const wmEvent *event, uiBut *but) data->tooltiptimer = NULL; if (!data->tooltip) - data->tooltip = ui_tooltip_create(C, data->region, but); + data->tooltip = UI_tooltip_create_from_button(C, data->region, but); } /* handle menu auto open timer */ else if (event->customdata == data->autoopentimer) { diff --git a/source/blender/editors/interface/interface_intern.h b/source/blender/editors/interface/interface_intern.h index ba62def7458..8d7f9d47ab5 100644 --- a/source/blender/editors/interface/interface_intern.h +++ b/source/blender/editors/interface/interface_intern.h @@ -590,8 +590,7 @@ struct uiPopupBlockHandle { /* interface_region_*.c */ /* interface_region_tooltip.c */ -struct ARegion *ui_tooltip_create(struct bContext *C, struct ARegion *butregion, uiBut *but); -void ui_tooltip_free(struct bContext *C, struct ARegion *ar); +/* exposed as public API in UI_interface.h */ /* interface_region_color_picker.c */ void ui_rgb_to_color_picker_compat_v(const float rgb[3], float r_cp[3]); diff --git a/source/blender/editors/interface/interface_region_tooltip.c b/source/blender/editors/interface/interface_region_tooltip.c index f71b71fce43..9a818efebee 100644 --- a/source/blender/editors/interface/interface_region_tooltip.c +++ b/source/blender/editors/interface/interface_region_tooltip.c @@ -29,6 +29,14 @@ * ToolTip Region and Construction */ +/* TODO(campbell): + * We may want to have a higher level API that initializes a timer, + * checks for mouse motion and clears the tool-tip afterwards. + * We never want multiple tool-tips at once so this could be handled on the window / window-manager level. + * + * For now it's not a priority, so leave as-is. + */ + #include <stdarg.h> #include <stdlib.h> #include <string.h> @@ -97,7 +105,6 @@ typedef struct uiTooltipField { } uiTooltipField; -#define MAX_TOOLTIP_LINES 8 typedef struct uiTooltipData { rcti bbox; uiTooltipField *fields; @@ -314,8 +321,6 @@ static uiTooltipData *ui_tooltip_data_from_keymap(bContext *C, wmKeyMap *keymap) /* create tooltip data */ uiTooltipData *data = MEM_callocN(sizeof(uiTooltipData), "uiTooltipData"); - BLI_assert(data->fields_len < MAX_TOOLTIP_LINES); - for (wmKeyMapItem *kmi = keymap->items.first; kmi; kmi = kmi->next) { wmOperatorType *ot = WM_operatortype_find(kmi->idname, true); if (ot != NULL) { @@ -609,8 +614,6 @@ static uiTooltipData *ui_tooltip_data_from_button(bContext *C, uiBut *but) if (rna_prop.strinfo) MEM_freeN(rna_prop.strinfo); - BLI_assert(data->fields_len < MAX_TOOLTIP_LINES); - if (data->fields_len == 0) { MEM_freeN(data); return NULL; @@ -620,13 +623,116 @@ static uiTooltipData *ui_tooltip_data_from_button(bContext *C, uiBut *but) } } -/** \} */ +static uiTooltipData *ui_tooltip_data_from_manipulator(bContext *C, wmManipulator *mpr) +{ + uiTooltipData *data = MEM_callocN(sizeof(uiTooltipData), "uiTooltipData"); -/* -------------------------------------------------------------------- */ -/** \name ToolTip Public API - * \{ */ + /* TODO(campbell): a way for manipulators to have their own descriptions (low priority). */ + + /* Operator Actions */ + { + bool use_drag = mpr->drag_part != -1 && mpr->highlight_part != mpr->drag_part; + + const struct { + int part; + const char *prefix; + } mpop_actions[] = { + { + .part = mpr->highlight_part, + .prefix = use_drag ? TIP_("Click") : NULL, + }, { + .part = use_drag ? mpr->drag_part : -1, + .prefix = use_drag ? TIP_("Drag") : NULL, + }, + }; + + for (int i = 0; i < ARRAY_SIZE(mpop_actions); i++) { + wmManipulatorOpElem *mpop = (mpop_actions[i].part != -1) ? WM_manipulator_operator_get(mpr, mpop_actions[i].part) : NULL; + if (mpop != NULL) { + /* Description */ + const char *info = RNA_struct_ui_description(mpop->type->srna); + if (!(info && info[0])) { + info = RNA_struct_ui_name(mpop->type->srna); + } -ARegion *ui_tooltip_create(bContext *C, ARegion *butregion, uiBut *but) + if (info && info[0]) { + char *text = NULL; + if (mpop_actions[i].prefix != NULL) { + text = BLI_sprintfN("%s: %s", mpop_actions[i].prefix, info); + } + else { + text = BLI_strdup(info); + } + + if (text != NULL) { + uiTooltipField *field = text_field_add( + data, &(uiTooltipFormat){ + .style = UI_TIP_STYLE_HEADER, + .color_id = UI_TIP_LC_VALUE, + .is_pad = true, + }); + field->text = text; + } + } + + /* Shortcut */ + { + bool found = false; + IDProperty *prop = mpop->ptr.data; + char buf[128]; + if (WM_key_event_operator_string( + C, mpop->type->idname, WM_OP_INVOKE_DEFAULT, prop, true, + buf, ARRAY_SIZE(buf))) + { + found = true; + } + uiTooltipField *field = text_field_add( + data, &(uiTooltipFormat){ + .style = UI_TIP_STYLE_NORMAL, + .color_id = UI_TIP_LC_VALUE, + .is_pad = true, + }); + field->text = BLI_sprintfN(TIP_("Shortcut: %s"), found ? buf : "None"); + } + } + } + } + + /* Property Actions */ + if (mpr->type->target_property_defs_len) { + wmManipulatorProperty *mpr_prop_array = WM_manipulator_target_property_array(mpr); + for (int i = 0; i < mpr->type->target_property_defs_len; i++) { + /* TODO(campbell): function callback descriptions. */ + wmManipulatorProperty *mpr_prop = &mpr_prop_array[i]; + if (mpr_prop->prop != NULL) { + const char *info = RNA_property_ui_description(mpr_prop->prop); + if (info && info[0]) { + uiTooltipField *field = text_field_add( + data, &(uiTooltipFormat){ + .style = UI_TIP_STYLE_NORMAL, + .color_id = UI_TIP_LC_VALUE, + .is_pad = true, + }); + field->text = BLI_strdup(info); + } + } + } + } + + if (data->fields_len == 0) { + MEM_freeN(data); + return NULL; + } + else { + return data; + } +} + + +static ARegion *ui_tooltip_create_with_data( + bContext *C, uiTooltipData *data, + const float init_position[2], + const float aspect) { const float pad_px = UI_TIP_PADDING; wmWindow *win = CTX_wm_window(C); @@ -634,43 +740,12 @@ ARegion *ui_tooltip_create(bContext *C, ARegion *butregion, uiBut *but) uiStyle *style = UI_style_get(); static ARegionType type; ARegion *ar; -/* IDProperty *prop;*/ - /* aspect values that shrink text are likely unreadable */ - const float aspect = min_ff(1.0f, but->block->aspect); int fonth, fontw; - int ofsx, ofsy, h, i; + int h, i; rctf rect_fl; rcti rect_i; int font_flag = 0; - if (but->drawflag & UI_BUT_NO_TOOLTIP) { - return NULL; - } - uiTooltipData *data = NULL; - - /* custom tips for pre-defined operators */ - if (but->optype) { - if (STREQ(but->optype->idname, "WM_OT_tool_set")) { - char keymap[64] = ""; - RNA_string_get(but->opptr, "keymap", keymap); - if (keymap[0]) { - ScrArea *sa = CTX_wm_area(C); - wmKeyMap *km = WM_keymap_find_all(C, keymap, sa->spacetype, RGN_TYPE_WINDOW); - if (km != NULL) { - data = ui_tooltip_data_from_keymap(C, km); - } - } - } - } - /* toolsystem exception */ - - if (data == NULL) { - data = ui_tooltip_data_from_button(C, but); - } - if (data == NULL) { - return NULL; - } - /* create area region */ ar = ui_region_temp_add(CTX_wm_screen(C)); @@ -748,31 +823,12 @@ ARegion *ui_tooltip_create(bContext *C, ARegion *butregion, uiBut *but) data->lineh = h; /* compute position */ - ofsx = 0; //(but->block->panel) ? but->block->panel->ofsx : 0; - ofsy = 0; //(but->block->panel) ? but->block->panel->ofsy : 0; - rect_fl.xmin = BLI_rctf_cent_x(&but->rect) + ofsx - TIP_BORDER_X; + rect_fl.xmin = init_position[0] - TIP_BORDER_X; rect_fl.xmax = rect_fl.xmin + fontw + pad_px; - rect_fl.ymax = but->rect.ymin + ofsy - TIP_BORDER_Y; + rect_fl.ymax = init_position[1] - TIP_BORDER_Y; rect_fl.ymin = rect_fl.ymax - fonth - TIP_BORDER_Y; - /* since the text has beens caled already, the size of tooltips is defined now */ - /* here we try to figure out the right location */ - if (butregion) { - float mx, my; - float ofsx_fl = rect_fl.xmin, ofsy_fl = rect_fl.ymax; - ui_block_to_window_fl(butregion, but->block, &ofsx_fl, &ofsy_fl); - -#if 1 - /* use X mouse location */ - mx = (win->eventstate->x + (TIP_BORDER_X * 2)) - BLI_rctf_cent_x(&but->rect); -#else - mx = ofsx_fl - rect_fl.xmin; -#endif - my = ofsy_fl - rect_fl.ymax; - - BLI_rctf_translate(&rect_fl, mx, my); - } BLI_rcti_rctf_copy(&rect_i, &rect_fl); #undef TIP_BORDER_X @@ -827,7 +883,77 @@ ARegion *ui_tooltip_create(bContext *C, ARegion *butregion, uiBut *but) return ar; } -void ui_tooltip_free(bContext *C, ARegion *ar) +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name ToolTip Public API + * \{ */ + + +ARegion *UI_tooltip_create_from_button(bContext *C, ARegion *butregion, uiBut *but) +{ + wmWindow *win = CTX_wm_window(C); + /* aspect values that shrink text are likely unreadable */ + const float aspect = min_ff(1.0f, but->block->aspect); + float init_position[2]; + + if (but->drawflag & UI_BUT_NO_TOOLTIP) { + return NULL; + } + uiTooltipData *data = NULL; + + /* custom tips for pre-defined operators */ + if (but->optype) { + if (STREQ(but->optype->idname, "WM_OT_tool_set")) { + char keymap[64] = ""; + RNA_string_get(but->opptr, "keymap", keymap); + if (keymap[0]) { + ScrArea *sa = CTX_wm_area(C); + wmKeyMap *km = WM_keymap_find_all(C, keymap, sa->spacetype, RGN_TYPE_WINDOW); + if (km != NULL) { + data = ui_tooltip_data_from_keymap(C, km); + } + } + } + } + /* toolsystem exception */ + + if (data == NULL) { + data = ui_tooltip_data_from_button(C, but); + } + if (data == NULL) { + return NULL; + } + + init_position[0] = BLI_rctf_cent_x(&but->rect); + init_position[1] = but->rect.ymin; + + if (butregion) { + ui_block_to_window_fl(butregion, but->block, &init_position[0], &init_position[1]); + init_position[0] = win->eventstate->x; + } + + return ui_tooltip_create_with_data(C, data, init_position, aspect); +} + +ARegion *UI_tooltip_create_from_manipulator(bContext *C, wmManipulator *mpr) +{ + wmWindow *win = CTX_wm_window(C); + const float aspect = 1.0f; + float init_position[2]; + + uiTooltipData *data = ui_tooltip_data_from_manipulator(C, mpr); + if (data == NULL) { + return NULL; + } + + init_position[0] = win->eventstate->x; + init_position[1] = win->eventstate->y; + + return ui_tooltip_create_with_data(C, data, init_position, aspect); +} + +void UI_tooltip_free(bContext *C, ARegion *ar) { ui_region_temp_remove(C, CTX_wm_screen(C), ar); } diff --git a/source/blender/editors/interface/interface_templates.c b/source/blender/editors/interface/interface_templates.c index 5a2200fbe49..7d378a11a23 100644 --- a/source/blender/editors/interface/interface_templates.c +++ b/source/blender/editors/interface/interface_templates.c @@ -383,28 +383,34 @@ static void template_id_cb(bContext *C, void *arg_litem, void *arg_event) case UI_ID_LOCAL: if (id) { Main *bmain = CTX_data_main(C); - if (id_make_local(bmain, id, false, false)) { - BKE_main_id_clear_newpoins(bmain); + if (CTX_wm_window(C)->eventstate->shift) { + ID *override_id = BKE_override_static_create_from(bmain, id); + if (override_id != NULL) { + BKE_main_id_clear_newpoins(bmain); - /* reassign to get get proper updates/notifiers */ - idptr = RNA_property_pointer_get(&template_ui->ptr, template_ui->prop); - RNA_property_pointer_set(&template_ui->ptr, template_ui->prop, idptr); - RNA_property_update(C, &template_ui->ptr, template_ui->prop); + /* Assign new pointer, takes care of updates/notifiers */ + RNA_id_pointer_create(override_id, &idptr); + } + } + else { + if (id_make_local(bmain, id, false, false)) { + BKE_main_id_clear_newpoins(bmain); + + /* reassign to get get proper updates/notifiers */ + idptr = RNA_property_pointer_get(&template_ui->ptr, template_ui->prop); + } } + RNA_property_pointer_set(&template_ui->ptr, template_ui->prop, idptr); + RNA_property_update(C, &template_ui->ptr, template_ui->prop); } break; case UI_ID_OVERRIDE: - if (id) { - Main *bmain = CTX_data_main(C); - ID *override_id = BKE_override_static_create_from(bmain, id); - if (override_id != NULL) { - BKE_main_id_clear_newpoins(bmain); - - /* Assign new pointer, takes care of updates/notifiers */ - RNA_id_pointer_create(override_id, &idptr); - RNA_property_pointer_set(&template_ui->ptr, template_ui->prop, idptr); - RNA_property_update(C, &template_ui->ptr, template_ui->prop); - } + if (id && id->override_static) { + BKE_override_static_free(&id->override_static); + /* reassign to get get proper updates/notifiers */ + idptr = RNA_property_pointer_get(&template_ui->ptr, template_ui->prop); + RNA_property_pointer_set(&template_ui->ptr, template_ui->prop, idptr); + RNA_property_update(C, &template_ui->ptr, template_ui->prop); } break; case UI_ID_ALONE: @@ -542,25 +548,23 @@ static void template_ID( const bool disabled = (!id_make_local(CTX_data_main(C), id, true /* test */, false) || (idfrom && idfrom->lib)); but = uiDefIconBut(block, UI_BTYPE_BUT, 0, ICON_LIBRARY_DATA_DIRECT, 0, 0, UI_UNIT_X, UI_UNIT_Y, - NULL, 0, 0, 0, 0, TIP_("Direct linked library data-block, click to make local")); - if (disabled) { - UI_but_flag_enable(but, UI_BUT_DISABLED); - } - else { - UI_but_funcN_set(but, template_id_cb, MEM_dupallocN(template_ui), SET_INT_IN_POINTER(UI_ID_LOCAL)); - } - - but = uiDefIconBut(block, UI_BTYPE_BUT, 0, ICON_LIBRARY_DATA_OVERRIDE, 0, 0, UI_UNIT_X, UI_UNIT_Y, NULL, 0, 0, 0, 0, - TIP_("Direct linked library data-block, click to create static override")); + TIP_("Direct linked library data-block, click to make local, " + "Shift + Click to create a static override")); if (disabled) { UI_but_flag_enable(but, UI_BUT_DISABLED); } else { - UI_but_funcN_set(but, template_id_cb, MEM_dupallocN(template_ui), SET_INT_IN_POINTER(UI_ID_OVERRIDE)); + UI_but_funcN_set(but, template_id_cb, MEM_dupallocN(template_ui), SET_INT_IN_POINTER(UI_ID_LOCAL)); } } } + else if (ID_IS_STATIC_OVERRIDE(id)) { + but = uiDefIconBut(block, UI_BTYPE_BUT, 0, ICON_LIBRARY_DATA_OVERRIDE, 0, 0, UI_UNIT_X, UI_UNIT_Y, + NULL, 0, 0, 0, 0, + TIP_("Static override of linked library data-block, click to make fully local")); + UI_but_funcN_set(but, template_id_cb, MEM_dupallocN(template_ui), SET_INT_IN_POINTER(UI_ID_OVERRIDE)); + } if (id->us > 1) { char numstr[32]; diff --git a/source/blender/editors/manipulator_library/manipulator_types/button2d_manipulator.c b/source/blender/editors/manipulator_library/manipulator_types/button2d_manipulator.c index 32c1dbae0a6..cad97a9ef03 100644 --- a/source/blender/editors/manipulator_library/manipulator_types/button2d_manipulator.c +++ b/source/blender/editors/manipulator_library/manipulator_types/button2d_manipulator.c @@ -114,8 +114,8 @@ static void button3d_draw_intern( int icon = RNA_enum_get(mpr->ptr, "icon"); if (icon != ICON_NONE) { UI_icon_draw( - mpr->matrix_basis[3][0] - (ICON_DEFAULT_WIDTH / 2.0) * U.pixelsize, - mpr->matrix_basis[3][1] - (ICON_DEFAULT_HEIGHT / 2.0) * U.pixelsize, + mpr->matrix_basis[3][0] - (ICON_DEFAULT_WIDTH / 2.0) * U.ui_scale, + mpr->matrix_basis[3][1] - (ICON_DEFAULT_HEIGHT / 2.0) * U.ui_scale, icon); } } @@ -153,9 +153,8 @@ static int manipulator_button_test_select( else { copy_v2_v2(point_local, (float [2]){UNPACK2(event->mval)}); sub_v2_v2(point_local, mpr->matrix_basis[3]); - mul_v2_fl(point_local, 1.0f / mpr->scale_basis); + mul_v2_fl(point_local, 1.0f / (mpr->scale_basis * U.ui_scale)); } - /* The 'mpr->scale_final' is already applied when projecting. */ if (len_squared_v2(point_local) < 1.0f) { return 0; diff --git a/source/blender/editors/mesh/editmesh_add.c b/source/blender/editors/mesh/editmesh_add.c index 77772cfc8cc..a21fc2fffde 100644 --- a/source/blender/editors/mesh/editmesh_add.c +++ b/source/blender/editors/mesh/editmesh_add.c @@ -60,30 +60,35 @@ /* ********* add primitive operators ************* */ +typedef struct MakePrimitiveData { + float mat[4][4]; + bool was_editmode; +} MakePrimitiveData; + static Object *make_prim_init(bContext *C, const char *idname, - float *dia, float mat[4][4], - bool *was_editmode, const float loc[3], const float rot[3], const unsigned int layer) + const float loc[3], const float rot[3], const unsigned int layer, + MakePrimitiveData *r_creation_data) { Object *obedit = CTX_data_edit_object(C); - *was_editmode = false; + r_creation_data->was_editmode = false; if (obedit == NULL || obedit->type != OB_MESH) { obedit = ED_object_add_type(C, OB_MESH, idname, loc, rot, false, layer); /* create editmode */ ED_object_editmode_enter(C, EM_DO_UNDO | EM_IGNORE_LAYER); /* rare cases the active layer is messed up */ - *was_editmode = true; + r_creation_data->was_editmode = true; } - *dia = ED_object_new_primitive_matrix(C, obedit, loc, rot, mat); + ED_object_new_primitive_matrix(C, obedit, loc, rot, r_creation_data->mat); return obedit; } -static void make_prim_finish(bContext *C, Object *obedit, bool was_editmode, int enter_editmode) +static void make_prim_finish(bContext *C, Object *obedit, const MakePrimitiveData *creation_data, int enter_editmode) { BMEditMesh *em = BKE_editmesh_from_object(obedit); - const bool exit_editmode = ((was_editmode == true) && (enter_editmode == false)); + const bool exit_editmode = ((creation_data->was_editmode == true) && (enter_editmode == false)); /* Primitive has all verts selected, use vert select flush * to push this up to edges & faces. */ @@ -101,17 +106,17 @@ static void make_prim_finish(bContext *C, Object *obedit, bool was_editmode, int static int add_primitive_plane_exec(bContext *C, wmOperator *op) { + MakePrimitiveData creation_data; Object *obedit; BMEditMesh *em; - float loc[3], rot[3], mat[4][4], dia; + float loc[3], rot[3]; bool enter_editmode; - bool was_editmode; unsigned int layer; const bool calc_uvs = RNA_boolean_get(op->ptr, "calc_uvs"); WM_operator_view3d_unit_defaults(C, op); ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, &enter_editmode, &layer, NULL); - obedit = make_prim_init(C, CTX_DATA_(BLT_I18NCONTEXT_ID_MESH, "Plane"), &dia, mat, &was_editmode, loc, rot, layer); + obedit = make_prim_init(C, CTX_DATA_(BLT_I18NCONTEXT_ID_MESH, "Plane"), loc, rot, layer, &creation_data); em = BKE_editmesh_from_object(obedit); if (calc_uvs) { @@ -121,12 +126,12 @@ static int add_primitive_plane_exec(bContext *C, wmOperator *op) if (!EDBM_op_call_and_selectf( em, op, "verts.out", false, "create_grid x_segments=%i y_segments=%i size=%f matrix=%m4 calc_uvs=%b", - 1, 1, RNA_float_get(op->ptr, "radius"), mat, calc_uvs)) + 1, 1, RNA_float_get(op->ptr, "radius"), creation_data.mat, calc_uvs)) { return OPERATOR_CANCELLED; } - make_prim_finish(C, obedit, was_editmode, enter_editmode); + make_prim_finish(C, obedit, &creation_data, enter_editmode); return OPERATOR_FINISHED; } @@ -152,17 +157,17 @@ void MESH_OT_primitive_plane_add(wmOperatorType *ot) static int add_primitive_cube_exec(bContext *C, wmOperator *op) { + MakePrimitiveData creation_data; Object *obedit; BMEditMesh *em; - float loc[3], rot[3], mat[4][4], dia; + float loc[3], rot[3]; bool enter_editmode; - bool was_editmode; unsigned int layer; const bool calc_uvs = RNA_boolean_get(op->ptr, "calc_uvs"); WM_operator_view3d_unit_defaults(C, op); ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, &enter_editmode, &layer, NULL); - obedit = make_prim_init(C, CTX_DATA_(BLT_I18NCONTEXT_ID_MESH, "Cube"), &dia, mat, &was_editmode, loc, rot, layer); + obedit = make_prim_init(C, CTX_DATA_(BLT_I18NCONTEXT_ID_MESH, "Cube"), loc, rot, layer, &creation_data); em = BKE_editmesh_from_object(obedit); if (calc_uvs) { @@ -172,13 +177,13 @@ static int add_primitive_cube_exec(bContext *C, wmOperator *op) if (!EDBM_op_call_and_selectf( em, op, "verts.out", false, "create_cube matrix=%m4 size=%f calc_uvs=%b", - mat, RNA_float_get(op->ptr, "radius") * 2.0f, calc_uvs)) + creation_data.mat, RNA_float_get(op->ptr, "radius") * 2.0f, calc_uvs)) { return OPERATOR_CANCELLED; } /* BMESH_TODO make plane side this: M_SQRT2 - plane (diameter of 1.41 makes it unit size) */ - make_prim_finish(C, obedit, was_editmode, enter_editmode); + make_prim_finish(C, obedit, &creation_data, enter_editmode); return OPERATOR_FINISHED; } @@ -210,13 +215,13 @@ static const EnumPropertyItem fill_type_items[] = { static int add_primitive_circle_exec(bContext *C, wmOperator *op) { + MakePrimitiveData creation_data; Object *obedit; BMEditMesh *em; - float loc[3], rot[3], mat[4][4], dia; + float loc[3], rot[3]; bool enter_editmode; int cap_end, cap_tri; unsigned int layer; - bool was_editmode; const bool calc_uvs = RNA_boolean_get(op->ptr, "calc_uvs"); cap_end = RNA_enum_get(op->ptr, "fill_type"); @@ -224,7 +229,7 @@ static int add_primitive_circle_exec(bContext *C, wmOperator *op) WM_operator_view3d_unit_defaults(C, op); ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, &enter_editmode, &layer, NULL); - obedit = make_prim_init(C, CTX_DATA_(BLT_I18NCONTEXT_ID_MESH, "Circle"), &dia, mat, &was_editmode, loc, rot, layer); + obedit = make_prim_init(C, CTX_DATA_(BLT_I18NCONTEXT_ID_MESH, "Circle"), loc, rot, layer, &creation_data); em = BKE_editmesh_from_object(obedit); if (calc_uvs) { @@ -235,12 +240,12 @@ static int add_primitive_circle_exec(bContext *C, wmOperator *op) em, op, "verts.out", false, "create_circle segments=%i radius=%f cap_ends=%b cap_tris=%b matrix=%m4 calc_uvs=%b", RNA_int_get(op->ptr, "vertices"), RNA_float_get(op->ptr, "radius"), - cap_end, cap_tri, mat, calc_uvs)) + cap_end, cap_tri, creation_data.mat, calc_uvs)) { return OPERATOR_CANCELLED; } - make_prim_finish(C, obedit, was_editmode, enter_editmode); + make_prim_finish(C, obedit, &creation_data, enter_editmode); return OPERATOR_FINISHED; } @@ -270,12 +275,12 @@ void MESH_OT_primitive_circle_add(wmOperatorType *ot) static int add_primitive_cylinder_exec(bContext *C, wmOperator *op) { + MakePrimitiveData creation_data; Object *obedit; BMEditMesh *em; - float loc[3], rot[3], mat[4][4], dia; + float loc[3], rot[3]; bool enter_editmode; unsigned int layer; - bool was_editmode; const int end_fill_type = RNA_enum_get(op->ptr, "end_fill_type"); const bool cap_end = (end_fill_type != 0); const bool cap_tri = (end_fill_type == 2); @@ -283,7 +288,7 @@ static int add_primitive_cylinder_exec(bContext *C, wmOperator *op) WM_operator_view3d_unit_defaults(C, op); ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, &enter_editmode, &layer, NULL); - obedit = make_prim_init(C, CTX_DATA_(BLT_I18NCONTEXT_ID_MESH, "Cylinder"), &dia, mat, &was_editmode, loc, rot, layer); + obedit = make_prim_init(C, CTX_DATA_(BLT_I18NCONTEXT_ID_MESH, "Cylinder"), loc, rot, layer, &creation_data); em = BKE_editmesh_from_object(obedit); if (calc_uvs) { @@ -297,12 +302,12 @@ static int add_primitive_cylinder_exec(bContext *C, wmOperator *op) RNA_float_get(op->ptr, "radius"), RNA_float_get(op->ptr, "radius"), cap_end, cap_tri, - RNA_float_get(op->ptr, "depth"), mat, calc_uvs)) + RNA_float_get(op->ptr, "depth"), creation_data.mat, calc_uvs)) { return OPERATOR_CANCELLED; } - make_prim_finish(C, obedit, was_editmode, enter_editmode); + make_prim_finish(C, obedit, &creation_data, enter_editmode); return OPERATOR_FINISHED; } @@ -333,12 +338,12 @@ void MESH_OT_primitive_cylinder_add(wmOperatorType *ot) static int add_primitive_cone_exec(bContext *C, wmOperator *op) { + MakePrimitiveData creation_data; Object *obedit; BMEditMesh *em; - float loc[3], rot[3], mat[4][4], dia; + float loc[3], rot[3]; bool enter_editmode; unsigned int layer; - bool was_editmode; const int end_fill_type = RNA_enum_get(op->ptr, "end_fill_type"); const bool cap_end = (end_fill_type != 0); const bool cap_tri = (end_fill_type == 2); @@ -346,7 +351,7 @@ static int add_primitive_cone_exec(bContext *C, wmOperator *op) WM_operator_view3d_unit_defaults(C, op); ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, &enter_editmode, &layer, NULL); - obedit = make_prim_init(C, CTX_DATA_(BLT_I18NCONTEXT_ID_MESH, "Cone"), &dia, mat, &was_editmode, loc, rot, layer); + obedit = make_prim_init(C, CTX_DATA_(BLT_I18NCONTEXT_ID_MESH, "Cone"), loc, rot, layer, &creation_data); em = BKE_editmesh_from_object(obedit); if (calc_uvs) { @@ -357,12 +362,13 @@ static int add_primitive_cone_exec(bContext *C, wmOperator *op) em, op, "verts.out", false, "create_cone segments=%i diameter1=%f diameter2=%f cap_ends=%b cap_tris=%b depth=%f matrix=%m4 calc_uvs=%b", RNA_int_get(op->ptr, "vertices"), RNA_float_get(op->ptr, "radius1"), - RNA_float_get(op->ptr, "radius2"), cap_end, cap_tri, RNA_float_get(op->ptr, "depth"), mat, calc_uvs)) + RNA_float_get(op->ptr, "radius2"), cap_end, cap_tri, RNA_float_get(op->ptr, "depth"), + creation_data.mat, calc_uvs)) { return OPERATOR_CANCELLED; } - make_prim_finish(C, obedit, was_editmode, enter_editmode); + make_prim_finish(C, obedit, &creation_data, enter_editmode); return OPERATOR_FINISHED; } @@ -394,17 +400,17 @@ void MESH_OT_primitive_cone_add(wmOperatorType *ot) static int add_primitive_grid_exec(bContext *C, wmOperator *op) { + MakePrimitiveData creation_data; Object *obedit; BMEditMesh *em; - float loc[3], rot[3], mat[4][4], dia; + float loc[3], rot[3]; bool enter_editmode; - bool was_editmode; unsigned int layer; const bool calc_uvs = RNA_boolean_get(op->ptr, "calc_uvs"); WM_operator_view3d_unit_defaults(C, op); ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, &enter_editmode, &layer, NULL); - obedit = make_prim_init(C, CTX_DATA_(BLT_I18NCONTEXT_ID_MESH, "Grid"), &dia, mat, &was_editmode, loc, rot, layer); + obedit = make_prim_init(C, CTX_DATA_(BLT_I18NCONTEXT_ID_MESH, "Grid"), loc, rot, layer, &creation_data); em = BKE_editmesh_from_object(obedit); if (calc_uvs) { @@ -416,12 +422,12 @@ static int add_primitive_grid_exec(bContext *C, wmOperator *op) "create_grid x_segments=%i y_segments=%i size=%f matrix=%m4 calc_uvs=%b", RNA_int_get(op->ptr, "x_subdivisions"), RNA_int_get(op->ptr, "y_subdivisions"), - RNA_float_get(op->ptr, "radius"), mat, calc_uvs)) + RNA_float_get(op->ptr, "radius"), creation_data.mat, calc_uvs)) { return OPERATOR_CANCELLED; } - make_prim_finish(C, obedit, was_editmode, enter_editmode); + make_prim_finish(C, obedit, &creation_data, enter_editmode); return OPERATOR_FINISHED; } @@ -453,22 +459,21 @@ void MESH_OT_primitive_grid_add(wmOperatorType *ot) static int add_primitive_monkey_exec(bContext *C, wmOperator *op) { + MakePrimitiveData creation_data; Object *obedit; BMEditMesh *em; - float mat[4][4]; float loc[3], rot[3]; float dia; bool enter_editmode; unsigned int layer; - bool was_editmode; const bool calc_uvs = RNA_boolean_get(op->ptr, "calc_uvs"); WM_operator_view3d_unit_defaults(C, op); ED_object_add_generic_get_opts(C, op, 'Y', loc, rot, &enter_editmode, &layer, NULL); - obedit = make_prim_init(C, CTX_DATA_(BLT_I18NCONTEXT_ID_MESH, "Suzanne"), &dia, mat, &was_editmode, loc, rot, layer); + obedit = make_prim_init(C, CTX_DATA_(BLT_I18NCONTEXT_ID_MESH, "Suzanne"), loc, rot, layer, &creation_data); dia = RNA_float_get(op->ptr, "radius"); - mul_mat3_m4_fl(mat, dia); + mul_mat3_m4_fl(creation_data.mat, dia); em = BKE_editmesh_from_object(obedit); @@ -478,12 +483,12 @@ static int add_primitive_monkey_exec(bContext *C, wmOperator *op) if (!EDBM_op_call_and_selectf( em, op, "verts.out", false, - "create_monkey matrix=%m4 calc_uvs=%b", mat, calc_uvs)) + "create_monkey matrix=%m4 calc_uvs=%b", creation_data.mat, calc_uvs)) { return OPERATOR_CANCELLED; } - make_prim_finish(C, obedit, was_editmode, enter_editmode); + make_prim_finish(C, obedit, &creation_data, enter_editmode); return OPERATOR_FINISHED; } @@ -510,17 +515,17 @@ void MESH_OT_primitive_monkey_add(wmOperatorType *ot) static int add_primitive_uvsphere_exec(bContext *C, wmOperator *op) { + MakePrimitiveData creation_data; Object *obedit; BMEditMesh *em; - float loc[3], rot[3], mat[4][4], dia; + float loc[3], rot[3]; bool enter_editmode; - bool was_editmode; unsigned int layer; const bool calc_uvs = RNA_boolean_get(op->ptr, "calc_uvs"); WM_operator_view3d_unit_defaults(C, op); ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, &enter_editmode, &layer, NULL); - obedit = make_prim_init(C, CTX_DATA_(BLT_I18NCONTEXT_ID_MESH, "Sphere"), &dia, mat, &was_editmode, loc, rot, layer); + obedit = make_prim_init(C, CTX_DATA_(BLT_I18NCONTEXT_ID_MESH, "Sphere"), loc, rot, layer, &creation_data); em = BKE_editmesh_from_object(obedit); if (calc_uvs) { @@ -531,12 +536,12 @@ static int add_primitive_uvsphere_exec(bContext *C, wmOperator *op) em, op, "verts.out", false, "create_uvsphere u_segments=%i v_segments=%i diameter=%f matrix=%m4 calc_uvs=%b", RNA_int_get(op->ptr, "segments"), RNA_int_get(op->ptr, "ring_count"), - RNA_float_get(op->ptr, "size"), mat, calc_uvs)) + RNA_float_get(op->ptr, "size"), creation_data.mat, calc_uvs)) { return OPERATOR_CANCELLED; } - make_prim_finish(C, obedit, was_editmode, enter_editmode); + make_prim_finish(C, obedit, &creation_data, enter_editmode); return OPERATOR_FINISHED; } @@ -566,17 +571,17 @@ void MESH_OT_primitive_uv_sphere_add(wmOperatorType *ot) static int add_primitive_icosphere_exec(bContext *C, wmOperator *op) { + MakePrimitiveData creation_data; Object *obedit; BMEditMesh *em; - float loc[3], rot[3], mat[4][4], dia; + float loc[3], rot[3]; bool enter_editmode; - bool was_editmode; unsigned int layer; const bool calc_uvs = RNA_boolean_get(op->ptr, "calc_uvs"); WM_operator_view3d_unit_defaults(C, op); ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, &enter_editmode, &layer, NULL); - obedit = make_prim_init(C, CTX_DATA_(BLT_I18NCONTEXT_ID_MESH, "Icosphere"), &dia, mat, &was_editmode, loc, rot, layer); + obedit = make_prim_init(C, CTX_DATA_(BLT_I18NCONTEXT_ID_MESH, "Icosphere"), loc, rot, layer, &creation_data); em = BKE_editmesh_from_object(obedit); if (calc_uvs) { @@ -587,12 +592,12 @@ static int add_primitive_icosphere_exec(bContext *C, wmOperator *op) em, op, "verts.out", false, "create_icosphere subdivisions=%i diameter=%f matrix=%m4 calc_uvs=%b", RNA_int_get(op->ptr, "subdivisions"), - RNA_float_get(op->ptr, "size"), mat, calc_uvs)) + RNA_float_get(op->ptr, "size"), creation_data.mat, calc_uvs)) { return OPERATOR_CANCELLED; } - make_prim_finish(C, obedit, was_editmode, enter_editmode); + make_prim_finish(C, obedit, &creation_data, enter_editmode); return OPERATOR_FINISHED; } diff --git a/source/blender/editors/object/object_add.c b/source/blender/editors/object/object_add.c index 3eb26fa52b8..af131e270ef 100644 --- a/source/blender/editors/object/object_add.c +++ b/source/blender/editors/object/object_add.c @@ -1137,6 +1137,7 @@ static int group_instance_add_exec(bContext *C, wmOperator *op) /* works without this except if you try render right after, see: 22027 */ DEG_relations_tag_update(bmain); + DEG_id_tag_update(&group->id, 0); WM_event_add_notifier(C, NC_SCENE | ND_OB_ACTIVE, scene); diff --git a/source/blender/editors/sculpt_paint/paint_stroke.c b/source/blender/editors/sculpt_paint/paint_stroke.c index dacaea6a96e..9dd51b289f4 100644 --- a/source/blender/editors/sculpt_paint/paint_stroke.c +++ b/source/blender/editors/sculpt_paint/paint_stroke.c @@ -233,6 +233,9 @@ static bool paint_brush_update(bContext *C, UnifiedPaintSettings *ups = stroke->ups; bool location_sampled = false; bool location_success = false; + /* Use to perform all operations except applying the stroke, + * needed for operations that require cursor motion (rake). */ + bool is_dry_run = false; bool do_random = false; bool do_random_mask = false; /* XXX: Use pressure value from first brush step for brushes which don't @@ -371,7 +374,10 @@ static bool paint_brush_update(bContext *C, } /* curve strokes do their own rake calculation */ else if (!(brush->flag & BRUSH_CURVE)) { - paint_calculate_rake_rotation(ups, brush, mouse_init); + if (!paint_calculate_rake_rotation(ups, brush, mouse_init)) { + /* Not enough motion to define an angle. */ + is_dry_run = true; + } } } @@ -402,7 +408,7 @@ static bool paint_brush_update(bContext *C, } } - return location_success; + return location_success && (is_dry_run == false); } static bool paint_stroke_use_jitter(ePaintMode mode, Brush *brush, bool invert) diff --git a/source/blender/editors/space_buttons/space_buttons.c b/source/blender/editors/space_buttons/space_buttons.c index 878feb81e8a..179780bf517 100644 --- a/source/blender/editors/space_buttons/space_buttons.c +++ b/source/blender/editors/space_buttons/space_buttons.c @@ -226,11 +226,12 @@ static void buttons_header_region_draw(const bContext *C, ARegion *ar) } static void buttons_header_region_message_subscribe( - const struct bContext *UNUSED(C), - struct WorkSpace *UNUSED(workspace), struct Scene *UNUSED(scene), - struct bScreen *UNUSED(screen), struct ScrArea *UNUSED(sa), struct ARegion *ar, + const bContext *UNUSED(C), + WorkSpace *UNUSED(workspace), Scene *UNUSED(scene), + bScreen *UNUSED(screen), ScrArea *sa, ARegion *ar, struct wmMsgBus *mbus) { + SpaceButs *sbuts = sa->spacedata.first; wmMsgSubscribeValue msg_sub_value_region_tag_redraw = { .owner = ar, .user_data = ar, @@ -240,6 +241,10 @@ static void buttons_header_region_message_subscribe( /* Don't check for SpaceButs.mainb here, we may toggle between view-layers * where one has no active object, so that available contexts changes. */ WM_msg_subscribe_rna_anon_prop(mbus, Window, view_layer, &msg_sub_value_region_tag_redraw); + + if (!ELEM(sbuts->mainb, BCONTEXT_RENDER, BCONTEXT_SCENE, BCONTEXT_WORLD)) { + WM_msg_subscribe_rna_anon_prop(mbus, ViewLayer, name, &msg_sub_value_region_tag_redraw); + } } /* draw a certain button set only if properties area is currently diff --git a/source/blender/editors/space_clip/clip_intern.h b/source/blender/editors/space_clip/clip_intern.h index ffc7a41f0aa..b0d00744558 100644 --- a/source/blender/editors/space_clip/clip_intern.h +++ b/source/blender/editors/space_clip/clip_intern.h @@ -139,6 +139,8 @@ void clip_graph_tracking_iterate(struct SpaceClip *sc, bool selected_only, bool void clip_delete_track(struct bContext *C, struct MovieClip *clip, struct MovieTrackingTrack *track); void clip_delete_marker(struct bContext *C, struct MovieClip *clip, struct MovieTrackingTrack *track, struct MovieTrackingMarker *marker); +void clip_delete_plane_track(struct bContext *C, struct MovieClip *clip, struct MovieTrackingPlaneTrack *plane_track); + void clip_view_center_to_point(SpaceClip *sc, float x, float y); void clip_draw_cfra(struct SpaceClip *sc, struct ARegion *ar, struct Scene *scene); diff --git a/source/blender/editors/space_clip/clip_utils.c b/source/blender/editors/space_clip/clip_utils.c index 40661937bae..7f9d9bf577c 100644 --- a/source/blender/editors/space_clip/clip_utils.c +++ b/source/blender/editors/space_clip/clip_utils.c @@ -184,37 +184,37 @@ void clip_delete_track(bContext *C, MovieClip *clip, MovieTrackingTrack *track) MovieTrackingTrack *act_track = BKE_tracking_track_get_active(tracking); ListBase *tracksbase = BKE_tracking_get_active_tracks(tracking); bool has_bundle = false; - char track_name_escaped[MAX_NAME], prefix[MAX_NAME * 2]; - const bool used_for_stabilization = (track->flag & (TRACK_USE_2D_STAB | TRACK_USE_2D_STAB_ROT)); - - if (track == act_track) + const bool used_for_stabilization = + (track->flag & (TRACK_USE_2D_STAB | TRACK_USE_2D_STAB_ROT)) != 0; + if (track == act_track) { tracking->act_track = NULL; - - /* handle reconstruction display in 3d viewport */ - if (track->flag & TRACK_HAS_BUNDLE) + } + /* Handle reconstruction display in 3d viewport. */ + if (track->flag & TRACK_HAS_BUNDLE) { has_bundle = true; - + } /* Make sure no plane will use freed track */ BKE_tracking_plane_tracks_remove_point_track(tracking, track); - /* Delete f-curves associated with the track (such as weight, i.e.) */ - BLI_strescape(track_name_escaped, track->name, sizeof(track_name_escaped)); - BLI_snprintf(prefix, sizeof(prefix), "tracks[\"%s\"]", track_name_escaped); - BKE_animdata_fix_paths_remove(&clip->id, prefix); - + /* Escaped object name, escaped track name, rest of the path. */ + char rna_path[MAX_NAME * 4 + 64]; + BKE_tracking_get_rna_path_for_track(tracking, + track, + rna_path, sizeof(rna_path)); + BKE_animdata_fix_paths_remove(&clip->id, rna_path); + /* Delete track itself. */ BKE_tracking_track_free(track); BLI_freelinkN(tracksbase, track); - + /* Send notifiers. */ WM_event_add_notifier(C, NC_MOVIECLIP | NA_EDITED, clip); - if (used_for_stabilization) { WM_event_add_notifier(C, NC_MOVIECLIP | ND_DISPLAY, clip); } - + /* Inform dependency graph. */ DEG_id_tag_update(&clip->id, 0); - - if (has_bundle) + if (has_bundle) { WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, NULL); + } } void clip_delete_marker(bContext *C, MovieClip *clip, MovieTrackingTrack *track, @@ -230,6 +230,28 @@ void clip_delete_marker(bContext *C, MovieClip *clip, MovieTrackingTrack *track, } } +void clip_delete_plane_track(bContext *C, + MovieClip *clip, + MovieTrackingPlaneTrack *plane_track) +{ + MovieTracking *tracking = &clip->tracking; + ListBase *plane_tracks_base = BKE_tracking_get_active_plane_tracks(tracking); + /* Delete f-curves associated with the track (such as weight, i.e.) */ + /* Escaped object name, escaped track name, rest of the path. */ + char rna_path[MAX_NAME * 4 + 64]; + BKE_tracking_get_rna_path_for_plane_track(tracking, + plane_track, + rna_path, sizeof(rna_path)); + BKE_animdata_fix_paths_remove(&clip->id, rna_path); + /* Delete the plane track itself. */ + BKE_tracking_plane_track_free(plane_track); + BLI_freelinkN(plane_tracks_base, plane_track); + /* TODO(sergey): Any notifiers to be sent here? */ + (void) C; + /* Inform dependency graph. */ + DEG_id_tag_update(&clip->id, 0); +} + void clip_view_center_to_point(SpaceClip *sc, float x, float y) { int width, height; diff --git a/source/blender/editors/space_clip/tracking_ops.c b/source/blender/editors/space_clip/tracking_ops.c index 2439ac06d9c..4dd96a838e0 100644 --- a/source/blender/editors/space_clip/tracking_ops.c +++ b/source/blender/editors/space_clip/tracking_ops.c @@ -227,7 +227,6 @@ static int delete_track_exec(bContext *C, wmOperator *UNUSED(op)) MovieClip *clip = ED_space_clip_get_clip(sc); MovieTracking *tracking = &clip->tracking; bool changed = false; - /* Delete selected plane tracks. */ ListBase *plane_tracks_base = BKE_tracking_get_active_plane_tracks(tracking); for (MovieTrackingPlaneTrack *plane_track = plane_tracks_base->first, @@ -236,14 +235,11 @@ static int delete_track_exec(bContext *C, wmOperator *UNUSED(op)) plane_track = next_plane_track) { next_plane_track = plane_track->next; - if (PLANE_TRACK_VIEW_SELECTED(plane_track)) { - BKE_tracking_plane_track_free(plane_track); - BLI_freelinkN(plane_tracks_base, plane_track); + clip_delete_plane_track(C, clip, plane_track); changed = true; } } - /* Remove selected point tracks (they'll also be removed from planes which * uses them). */ @@ -258,14 +254,11 @@ static int delete_track_exec(bContext *C, wmOperator *UNUSED(op)) changed = true; } } - /* Nothing selected now, unlock view so it can be scrolled nice again. */ sc->flag &= ~SC_LOCK_SELECTION; - if (changed) { WM_event_add_notifier(C, NC_MOVIECLIP | NA_EDITED, clip); } - return OPERATOR_FINISHED; } diff --git a/source/blender/editors/space_info/space_info.c b/source/blender/editors/space_info/space_info.c index 4f042364c63..b13152883c3 100644 --- a/source/blender/editors/space_info/space_info.c +++ b/source/blender/editors/space_info/space_info.c @@ -50,6 +50,9 @@ #include "WM_api.h" #include "WM_types.h" +#include "WM_message.h" + +#include "RNA_access.h" #include "UI_resources.h" #include "UI_interface.h" @@ -284,6 +287,22 @@ static void info_header_listener( } +static void info_header_region_message_subscribe( + const bContext *UNUSED(C), + WorkSpace *UNUSED(workspace), Scene *UNUSED(scene), + bScreen *UNUSED(screen), ScrArea *UNUSED(sa), ARegion *ar, + struct wmMsgBus *mbus) +{ + wmMsgSubscribeValue msg_sub_value_region_tag_redraw = { + .owner = ar, + .user_data = ar, + .notify = ED_region_do_msg_notify_tag_redraw, + }; + + WM_msg_subscribe_rna_anon_prop(mbus, Window, view_layer, &msg_sub_value_region_tag_redraw); + WM_msg_subscribe_rna_anon_prop(mbus, ViewLayer, name, &msg_sub_value_region_tag_redraw); +} + static void recent_files_menu_draw(const bContext *UNUSED(C), Menu *menu) { struct RecentFile *recent; @@ -347,6 +366,7 @@ void ED_spacetype_info(void) art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_VIEW2D | ED_KEYMAP_FRAMES | ED_KEYMAP_HEADER; art->listener = info_header_listener; + art->message_subscribe = info_header_region_message_subscribe; art->init = info_header_region_init; art->draw = info_header_region_draw; diff --git a/source/blender/editors/space_outliner/outliner_collections.c b/source/blender/editors/space_outliner/outliner_collections.c index 0a51b1a0d69..7689131bad4 100644 --- a/source/blender/editors/space_outliner/outliner_collections.c +++ b/source/blender/editors/space_outliner/outliner_collections.c @@ -51,6 +51,9 @@ #include "outliner_intern.h" /* own include */ +/* Prototypes. */ +static int collection_delete_exec(struct bContext *C, struct wmOperator *op); + /* -------------------------------------------------------------------- */ static LayerCollection *outliner_collection_active(bContext *C) @@ -86,6 +89,19 @@ static CollectionOverride *outliner_override_active(bContext *UNUSED(C)) #endif /* -------------------------------------------------------------------- */ +/* Poll functions. */ + +static int collections_editor_poll(bContext *C) +{ + ScrArea *sa = CTX_wm_area(C); + if ((sa) && (sa->spacetype == SPACE_OUTLINER)) { + SpaceOops *so = CTX_wm_space_outliner(C); + return (so->outlinevis == SO_COLLECTIONS); + } + return 0; +} + +/* -------------------------------------------------------------------- */ /* collection manager operators */ /** @@ -306,12 +322,14 @@ void OUTLINER_OT_collection_unlink(wmOperatorType *ot) static int collection_new_exec(bContext *C, wmOperator *UNUSED(op)) { + SpaceOops *soops = CTX_wm_space_outliner(C); Main *bmain = CTX_data_main(C); Scene *scene = CTX_data_scene(C); ViewLayer *view_layer = CTX_data_view_layer(C); SceneCollection *scene_collection = BKE_collection_add(&scene->id, NULL, COLLECTION_TYPE_NONE, NULL); BKE_collection_link(view_layer, scene_collection); + outliner_cleanup_tree(soops); DEG_relations_tag_update(bmain); WM_main_add_notifier(NC_SCENE | ND_LAYER, NULL); return OPERATOR_FINISHED; @@ -332,6 +350,96 @@ void OUTLINER_OT_collection_new(wmOperatorType *ot) } /**********************************************************************************/ +/* Add new nested collection. */ + +struct CollectionNewData +{ + bool error; + SceneCollection *scene_collection; +}; + +static TreeTraversalAction collection_find_selected_to_add(TreeElement *te, void *customdata) +{ + struct CollectionNewData *data = customdata; + SceneCollection *scene_collection = outliner_scene_collection_from_tree_element(te); + + if (!scene_collection) { + return TRAVERSE_SKIP_CHILDS; + } + + if (data->scene_collection != NULL) { + data->error = true; + return TRAVERSE_BREAK; + } + + data->scene_collection = scene_collection; + return TRAVERSE_CONTINUE; +} + +static int collection_nested_new_exec(bContext *C, wmOperator *op) +{ + SpaceOops *soops = CTX_wm_space_outliner(C); + Main *bmain = CTX_data_main(C); + Scene *scene = CTX_data_scene(C); + + struct CollectionNewData data = { + .error = false, + .scene_collection = NULL, + }; + + outliner_tree_traverse(soops, &soops->tree, 0, TSE_SELECTED, collection_find_selected_to_add, &data); + + if (data.error) { + BKE_report(op->reports, RPT_ERROR, "More than one collection is selected"); + return OPERATOR_CANCELLED; + } + + BKE_collection_add( + &scene->id, + data.scene_collection, + COLLECTION_TYPE_NONE, + NULL); + + outliner_cleanup_tree(soops); + DEG_relations_tag_update(bmain); + WM_main_add_notifier(NC_SCENE | ND_LAYER, NULL); + return OPERATOR_FINISHED; +} + +void OUTLINER_OT_collection_nested_new(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "New Nested Collection"; + ot->idname = "OUTLINER_OT_collection_nested_new"; + ot->description = "Add a new collection inside selected collection"; + + /* api callbacks */ + ot->exec = collection_nested_new_exec; + ot->poll = collections_editor_poll; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; +} + +/**********************************************************************************/ +/* Delete selected collection. */ + +void OUTLINER_OT_collection_delete_selected(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Delete Selected Collections"; + ot->idname = "OUTLINER_OT_collection_delete_selected"; + ot->description = "Delete all the selected collections"; + + /* api callbacks */ + ot->exec = collection_delete_exec; + ot->poll = collections_editor_poll; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; +} + +/**********************************************************************************/ /** * Returns true is selected element is a collection diff --git a/source/blender/editors/space_outliner/outliner_draw.c b/source/blender/editors/space_outliner/outliner_draw.c index af9d1fa3107..32f7ef39c19 100644 --- a/source/blender/editors/space_outliner/outliner_draw.c +++ b/source/blender/editors/space_outliner/outliner_draw.c @@ -1416,8 +1416,11 @@ static void outliner_draw_tree_element( te->flag |= TE_ACTIVE; // for lookup in display hierarchies } + if ((soops->outlinevis == SO_COLLECTIONS) && te->parent == NULL) { + /* Master collection can't expand/collapse. */ + } + else if (te->subtree.first || (tselem->type == 0 && te->idcode == ID_SCE) || (te->flag & TE_LAZY_CLOSED)) { /* open/close icon, only when sublevels, except for scene */ - if (te->subtree.first || (tselem->type == 0 && te->idcode == ID_SCE) || (te->flag & TE_LAZY_CLOSED)) { int icon_x; if (tselem->type == 0 && ELEM(te->idcode, ID_OB, ID_SCE)) icon_x = startx; @@ -1458,6 +1461,11 @@ static void outliner_draw_tree_element( } offsx += UI_UNIT_X + 2 * ufac; } + else if (tselem->type == 0 && ID_IS_STATIC_OVERRIDE(tselem->id)) { + UI_icon_draw_alpha((float)startx + offsx + 2 * ufac, (float)*starty + 2 * ufac, ICON_LIBRARY_DATA_OVERRIDE, + alpha_fac); + offsx += UI_UNIT_X + 2 * ufac; + } glDisable(GL_BLEND); /* name */ diff --git a/source/blender/editors/space_outliner/outliner_intern.h b/source/blender/editors/space_outliner/outliner_intern.h index 20dfa43ce8e..e81a7668bbc 100644 --- a/source/blender/editors/space_outliner/outliner_intern.h +++ b/source/blender/editors/space_outliner/outliner_intern.h @@ -340,6 +340,9 @@ void OUTLINER_OT_collection_objects_remove(struct wmOperatorType *ot); void OUTLINER_OT_collection_objects_select(struct wmOperatorType *ot); void OUTLINER_OT_collection_objects_deselect(struct wmOperatorType *ot); +void OUTLINER_OT_collection_nested_new(struct wmOperatorType *ot); +void OUTLINER_OT_collection_delete_selected(struct wmOperatorType *ot); + /* outliner_utils.c ---------------------------------------------- */ TreeElement *outliner_find_item_at_y(const SpaceOops *soops, const ListBase *tree, float view_co_y); diff --git a/source/blender/editors/space_outliner/outliner_ops.c b/source/blender/editors/space_outliner/outliner_ops.c index 856dd022c14..98e8aca0e1f 100644 --- a/source/blender/editors/space_outliner/outliner_ops.c +++ b/source/blender/editors/space_outliner/outliner_ops.c @@ -335,6 +335,9 @@ void outliner_operatortypes(void) WM_operatortype_append(OUTLINER_OT_collection_objects_remove); WM_operatortype_append(OUTLINER_OT_collection_objects_select); WM_operatortype_append(OUTLINER_OT_collection_objects_deselect); + + WM_operatortype_append(OUTLINER_OT_collection_nested_new); + WM_operatortype_append(OUTLINER_OT_collection_delete_selected); } static wmKeyMap *outliner_item_drag_drop_modal_keymap(wmKeyConfig *keyconf) @@ -432,6 +435,9 @@ void outliner_keymap(wmKeyConfig *keyconf) WM_keymap_verify_item(keymap, "OUTLINER_OT_drivers_add_selected", DKEY, KM_PRESS, 0, 0); WM_keymap_verify_item(keymap, "OUTLINER_OT_drivers_delete_selected", DKEY, KM_PRESS, KM_ALT, 0); + WM_keymap_verify_item(keymap, "OUTLINER_OT_collection_nested_new", CKEY, KM_PRESS, 0, 0); + WM_keymap_verify_item(keymap, "OUTLINER_OT_collection_delete_selected", XKEY, KM_PRESS, 0, 0); + outliner_item_drag_drop_modal_keymap(keyconf); } diff --git a/source/blender/editors/space_outliner/outliner_tree.c b/source/blender/editors/space_outliner/outliner_tree.c index 2fe860508d5..23190a6fa80 100644 --- a/source/blender/editors/space_outliner/outliner_tree.c +++ b/source/blender/editors/space_outliner/outliner_tree.c @@ -1483,35 +1483,46 @@ static bool outliner_scene_collections_reorder_poll( return true; } -static void outliner_add_scene_collection_objects( +BLI_INLINE void outliner_add_scene_collection_init(TreeElement *te, SceneCollection *collection) +{ + te->name = collection->name; + te->directdata = collection; + te->reinsert = outliner_scene_collections_reorder; + te->reinsert_poll = outliner_scene_collections_reorder_poll; +} + +BLI_INLINE void outliner_add_scene_collection_objects( SpaceOops *soops, ListBase *tree, SceneCollection *collection, TreeElement *parent) { for (LinkData *link = collection->objects.first; link; link = link->next) { outliner_add_element(soops, tree, link->data, parent, 0, 0); } - outliner_make_hierarchy(tree); } -static void outliner_add_scene_collections_recursive( - SpaceOops *soops, ListBase *tree, ListBase *scene_collections, TreeElement *parent_ten) +static TreeElement *outliner_add_scene_collection_recursive( + SpaceOops *soops, ListBase *tree, SceneCollection *scene_collection, TreeElement *parent_ten) { - for (SceneCollection *collection = scene_collections->first; collection; collection = collection->next) { - TreeElement *ten = outliner_add_element(soops, tree, collection, parent_ten, TSE_SCENE_COLLECTION, 0); - - ten->name = collection->name; - ten->directdata = collection; - ten->reinsert = outliner_scene_collections_reorder; - ten->reinsert_poll = outliner_scene_collections_reorder_poll; + TreeElement *ten = outliner_add_element(soops, tree, scene_collection, parent_ten, TSE_SCENE_COLLECTION, 0); + outliner_add_scene_collection_init(ten, scene_collection); + outliner_add_scene_collection_objects(soops, &ten->subtree, scene_collection, ten); - outliner_add_scene_collections_recursive(soops, &ten->subtree, &collection->scene_collections, ten); - outliner_add_scene_collection_objects(soops, &ten->subtree, collection, ten); + for (SceneCollection *scene_collection_nested = scene_collection->scene_collections.first; + scene_collection_nested != NULL; + scene_collection_nested = scene_collection_nested->next) + { + outliner_add_scene_collection_recursive(soops, &ten->subtree, scene_collection_nested, ten); } + + outliner_make_hierarchy(&ten->subtree); + return ten; } + static void outliner_add_collections_master(SpaceOops *soops, Scene *scene) { - SceneCollection *master = BKE_collection_master(&scene->id); - outliner_add_scene_collections_recursive(soops, &soops->tree, &master->scene_collections, NULL); - outliner_add_scene_collection_objects(soops, &soops->tree, master, NULL); + SceneCollection *master_collection = BKE_collection_master(&scene->id); + TreeElement *ten = outliner_add_scene_collection_recursive(soops, &soops->tree, master_collection, NULL); + /* Master Collection should always be expanded. */ + TREESTORE(ten)->flag &= ~TSE_CLOSED; } /* ======================================================= */ @@ -1967,8 +1978,10 @@ void outliner_build_tree(Main *mainvar, Scene *scene, ViewLayer *view_layer, Spa outliner_add_collections_master(soops, scene); } else { - ten = outliner_add_element(soops, &soops->tree, OBACT(view_layer), NULL, 0, 0); - ten->directdata = BASACT(view_layer); + if (BASACT(view_layer)) { + ten = outliner_add_element(soops, &soops->tree, OBACT(view_layer), NULL, 0, 0); + ten->directdata = BASACT(view_layer); + } } if ((soops->flag & SO_SKIP_SORT_ALPHA) == 0) { diff --git a/source/blender/editors/space_sequencer/sequencer_edit.c b/source/blender/editors/space_sequencer/sequencer_edit.c index 8f6eb064b0d..cb0c5bd3717 100644 --- a/source/blender/editors/space_sequencer/sequencer_edit.c +++ b/source/blender/editors/space_sequencer/sequencer_edit.c @@ -2190,23 +2190,24 @@ static int sequencer_delete_exec(bContext *C, wmOperator *UNUSED(op)) Editing *ed = BKE_sequencer_editing_get(scene, false); Sequence *seq; MetaStack *ms; - bool nothingSelected = true; + bool nothing_selected = true; seq = BKE_sequencer_active_get(scene); if (seq && seq->flag & SELECT) { /* avoid a loop since this is likely to be selected */ - nothingSelected = false; + nothing_selected = false; } else { for (seq = ed->seqbasep->first; seq; seq = seq->next) { if (seq->flag & SELECT) { - nothingSelected = false; + nothing_selected = false; break; } } } - if (nothingSelected) + if (nothing_selected) { return OPERATOR_FINISHED; + } /* for effects and modifiers, try to find a replacement input */ for (seq = ed->seqbasep->first; seq; seq = seq->next) { diff --git a/source/blender/editors/space_view3d/drawobject.c b/source/blender/editors/space_view3d/drawobject.c index c1e45f8280f..58002880c5e 100644 --- a/source/blender/editors/space_view3d/drawobject.c +++ b/source/blender/editors/space_view3d/drawobject.c @@ -7405,7 +7405,7 @@ static void draw_editnurb( } #else /* Same as loop above */ - count += 4 * max_ii((nr + max_ii(skip - 1, 0)) / (skip + 1), 0); + count += 4 * ((nr / (skip + 1)) + ((nr % (skip + 1)) != 0)); #endif } @@ -9217,7 +9217,10 @@ afterdraw: /* help lines and so */ if (ob != scene->obedit && ob->parent) { - if (BKE_object_is_visible(ob->parent)) { + const eObjectVisibilityCheck mode = eval_ctx->mode != DAG_EVAL_VIEWPORT ? + OB_VISIBILITY_CHECK_FOR_RENDER : + OB_VISIBILITY_CHECK_FOR_VIEWPORT; + if (BKE_object_is_visible(ob->parent, mode)) { setlinestyle(3); immBegin(GWN_PRIM_LINES, 2); immVertex3fv(pos, ob->obmat[3]); diff --git a/source/blender/editors/space_view3d/view3d_draw.c b/source/blender/editors/space_view3d/view3d_draw.c index 6ea2ff10af2..4a00329bd09 100644 --- a/source/blender/editors/space_view3d/view3d_draw.c +++ b/source/blender/editors/space_view3d/view3d_draw.c @@ -2060,7 +2060,7 @@ void ED_view3d_draw_offscreen( /* XXX, should take depsgraph as arg */ Depsgraph *depsgraph = BKE_scene_get_depsgraph(scene, view_layer, false); BLI_assert(depsgraph != NULL); - DRW_draw_render_loop_offscreen(depsgraph, eval_ctx->engine_type, ar, v3d, ofs); + DRW_draw_render_loop_offscreen(depsgraph, eval_ctx->engine_type, ar, v3d, do_sky, ofs); } /* restore size */ diff --git a/source/blender/editors/space_view3d/view3d_manipulator_navigate.c b/source/blender/editors/space_view3d/view3d_manipulator_navigate.c index b7a62c3e60f..bacb14336a9 100644 --- a/source/blender/editors/space_view3d/view3d_manipulator_navigate.c +++ b/source/blender/editors/space_view3d/view3d_manipulator_navigate.c @@ -127,9 +127,9 @@ static void WIDGETGROUP_navigate_setup(const bContext *UNUSED(C), wmManipulatorG const struct NavigateManipulatorInfo *info = &g_navigate_params[i]; navgroup->mpr_array[i] = WM_manipulator_new(info->manipulator, mgroup, NULL); wmManipulator *mpr = navgroup->mpr_array[i]; - mpr->flag |= WM_MANIPULATOR_GRAB_CURSOR; - copy_v3_fl(mpr->color, 1.0f); - mpr->color[3] = 0.4f; + mpr->flag |= WM_MANIPULATOR_GRAB_CURSOR | WM_MANIPULATOR_DRAW_MODAL; + mpr->color[3] = 0.2f; + mpr->color_hi[3] = 0.4f; /* may be overwritten later */ mpr->scale_basis = (MANIPULATOR_SIZE * MANIPULATOR_MINI_FAC) / 2; @@ -159,10 +159,13 @@ static void WIDGETGROUP_navigate_setup(const bContext *UNUSED(C), wmManipulatorG RV3D_VIEW_TOP, }; - for (int part_index = 0; part_index < 6; part_index+= 1) { - PointerRNA *ptr = WM_manipulator_operator_set(mpr, mapping[part_index], ot_viewnumpad, NULL); - RNA_enum_set(ptr, "type", RV3D_VIEW_FRONT + part_index); + for (int part_index = 0; part_index < 6; part_index += 1) { + PointerRNA *ptr = WM_manipulator_operator_set(mpr, part_index + 1, ot_viewnumpad, NULL); + RNA_enum_set(ptr, "type", mapping[part_index]); } + + /* When dragging an axis, use this instead. */ + mpr->drag_part = 0; } mgroup->customdata = navgroup; @@ -188,8 +191,8 @@ static void WIDGETGROUP_navigate_draw_prepare(const bContext *C, wmManipulatorGr navgroup->region_size[1] = ar->winy; const float icon_size = MANIPULATOR_SIZE; - const float icon_offset = (icon_size / 2.0) * MANIPULATOR_OFFSET_FAC * U.pixelsize; - const float icon_offset_mini = icon_size * MANIPULATOR_MINI_OFFSET_FAC * U.pixelsize; + const float icon_offset = (icon_size / 2.0) * MANIPULATOR_OFFSET_FAC * U.ui_scale; + const float icon_offset_mini = icon_size * MANIPULATOR_MINI_OFFSET_FAC * U.ui_scale; const float co[2] = {ar->winx - icon_offset, ar->winy - icon_offset}; wmManipulator *mpr; @@ -220,7 +223,8 @@ void VIEW3D_WGT_navigate(wmManipulatorGroupType *wgt) wgt->idname = "VIEW3D_WGT_navigate"; wgt->flag |= (WM_MANIPULATORGROUPTYPE_PERSISTENT | - WM_MANIPULATORGROUPTYPE_SCALE); + WM_MANIPULATORGROUPTYPE_SCALE | + WM_MANIPULATORGROUPTYPE_DRAW_MODAL_ALL); wgt->poll = WIDGETGROUP_navigate_poll; wgt->setup = WIDGETGROUP_navigate_setup; diff --git a/source/blender/editors/space_view3d/view3d_manipulator_navigate_type.c b/source/blender/editors/space_view3d/view3d_manipulator_navigate_type.c index b520f239ef5..424b5dae402 100644 --- a/source/blender/editors/space_view3d/view3d_manipulator_navigate_type.c +++ b/source/blender/editors/space_view3d/view3d_manipulator_navigate_type.c @@ -43,7 +43,6 @@ #include "GPU_immediate.h" #include "GPU_immediate_util.h" #include "GPU_matrix.h" -#include "GPU_select.h" #include "RNA_access.h" #include "RNA_define.h" @@ -54,8 +53,6 @@ #include "WM_types.h" #include "ED_screen.h" -#include "ED_view3d.h" -#include "ED_manipulator_library.h" #include "view3d_intern.h" @@ -96,8 +93,9 @@ static void axis_geom_draw( }; qsort(&axis_order, ARRAY_SIZE(axis_order), sizeof(axis_order[0]), BLI_sortutil_cmp_float); - const float scale_axis = 0.33f; + const float scale_axis = 0.25f; static const float axis_highlight[4] = {1, 1, 1, 1}; + static const float axis_nop[4] = {1, 1, 1, 0}; static const float axis_black[4] = {0, 0, 0, 1}; static float axis_color[3][4]; gpuPushMatrix(); @@ -138,7 +136,8 @@ static void axis_geom_draw( glEnable(GL_LINE_SMOOTH); glEnable(GL_BLEND); glLineWidth(1.0f); - immUniformColor4fv(axis_highlight); + /* Just draw depth values. */ + immUniformColor4fv(axis_nop); imm_draw_cube_fill_3d(pos_id, center, size); immUniformColor4fv(axis_black); madd_v3_v3fl( @@ -224,7 +223,7 @@ static void axis3d_draw_intern( static void manipulator_axis_draw(const bContext *C, wmManipulator *mpr) { const bool is_modal = mpr->state & WM_MANIPULATOR_STATE_MODAL; - const bool is_highlight = (mpr->state & WM_MANIPULATOR_STATE_HIGHLIGHT) != 0 && (mpr->highlight_part == 0); + const bool is_highlight = (mpr->state & WM_MANIPULATOR_STATE_HIGHLIGHT) != 0; (void)is_modal; @@ -238,16 +237,17 @@ static int manipulator_axis_test_select( { float point_local[2] = {UNPACK2(event->mval)}; sub_v2_v2(point_local, mpr->matrix_basis[3]); - mul_v2_fl(point_local, 1.0f / mpr->scale_basis); + mul_v2_fl(point_local, 1.0f / (mpr->scale_basis * U.ui_scale)); const float len_sq = len_squared_v2(point_local); - if (len_sq > SQUARE(1.0 + HANDLE_SIZE)) { + if (len_sq > 1.0) { return -1; } int part_best = -1; int part_index = 1; - float i_best_len_sq = SQUARE(HANDLE_SIZE); + /* Use 'SQUARE(HANDLE_SIZE)' if we want to be able to _not_ focus on one of the axis. */ + float i_best_len_sq = FLT_MAX; for (int i = 0; i < 3; i++) { for (int is_pos = 0; is_pos < 2; is_pos++) { float co[2] = { diff --git a/source/blender/editors/space_view3d/view3d_view.c b/source/blender/editors/space_view3d/view3d_view.c index 882f0ec0bc0..880707f3b4b 100644 --- a/source/blender/editors/space_view3d/view3d_view.c +++ b/source/blender/editors/space_view3d/view3d_view.c @@ -273,7 +273,7 @@ void ED_view3d_smooth_view_ex( * this means small rotations wont lag */ if (sview->quat && !sview->ofs && !sview->dist) { /* scale the time allowed by the rotation */ - sms.time_allowed *= (double)angle_normalized_qtqt(sms.dst.quat, sms.src.quat) / M_PI; /* 180deg == 1.0 */ + sms.time_allowed *= (double)fabsf(angle_signed_normalized_qtqt(sms.dst.quat, sms.src.quat)) / M_PI; /* 180deg == 1.0 */ } /* ensure it shows correct */ @@ -1069,7 +1069,7 @@ char ED_view3d_quat_to_axis_view(const float quat[4], const float epsilon) char view; for (view = RV3D_VIEW_FRONT; view <= RV3D_VIEW_BOTTOM; view++) { - if (angle_qtqt(quat, view3d_quat_axis[view - RV3D_VIEW_FRONT]) < epsilon) { + if (fabsf(angle_signed_qtqt(quat, view3d_quat_axis[view - RV3D_VIEW_FRONT])) < epsilon) { return view; } } diff --git a/source/blender/editors/transform/transform_manipulator.c b/source/blender/editors/transform/transform_manipulator.c index 90428dc5ddd..0643687c29a 100644 --- a/source/blender/editors/transform/transform_manipulator.c +++ b/source/blender/editors/transform/transform_manipulator.c @@ -1155,6 +1155,8 @@ static void manipulator_xform_message_subscribe( else { BLI_assert(0); } + + WM_msg_subscribe_rna_anon_prop(mbus, Window, view_layer, &msg_sub_value_mpr_tag_refresh); } /** \} */ diff --git a/source/blender/makesdna/DNA_ID.h b/source/blender/makesdna/DNA_ID.h index 946c2302d47..69e377faa97 100644 --- a/source/blender/makesdna/DNA_ID.h +++ b/source/blender/makesdna/DNA_ID.h @@ -375,6 +375,12 @@ typedef enum ID_Type { #define ID_IS_LINKED(_id) (((ID *)(_id))->lib != NULL) +#define ID_IS_STATIC_OVERRIDE(_id) (((ID *)(_id))->override_static != NULL && \ + ((ID *)(_id))->override_static->reference != NULL) + +#define ID_IS_STATIC_OVERRIDE_TEMPLATE(_id) (((ID *)(_id))->override_static != NULL && \ + ((ID *)(_id))->override_static->reference == NULL) + #ifdef GS # undef GS #endif @@ -453,10 +459,18 @@ enum { enum { /* RESET_AFTER_USE, used by update code (depsgraph). */ + ID_RECALC_NONE = 0, + /* Generic recalc flag, when nothing else matches. */ ID_RECALC = 1 << 0, - ID_RECALC_DATA = 1 << 1, - ID_RECALC_SKIP_ANIM_TAG = 1 << 2, - ID_RECALC_ALL = (ID_RECALC | ID_RECALC_DATA), + /* Per-component update flags. */ + ID_RECALC_ANIMATION = 1 << 1, + ID_RECALC_DRAW = 1 << 2, + ID_RECALC_DRAW_CACHE = 1 << 3, + ID_RECALC_GEOMETRY = 1 << 4, + ID_RECALC_TRANSFORM = 1 << 5, + ID_RECALC_COLLECTIONS = 1 << 6, + /* Special flag to check if SOMETHING was changed. */ + ID_RECALC_ALL = (~(int)0), }; /* To filter ID types (filter_id) */ diff --git a/source/blender/makesdna/DNA_object_types.h b/source/blender/makesdna/DNA_object_types.h index a876cacbcc8..6cf6dc06d5e 100644 --- a/source/blender/makesdna/DNA_object_types.h +++ b/source/blender/makesdna/DNA_object_types.h @@ -208,7 +208,7 @@ typedef struct Object { /* did last modifier stack generation need mapping support? */ char lastNeedMapping; /* bool */ - char pad; + char duplicator_visibility_flag; /* dupli-frame settings */ int dupon, dupoff, dupsta, dupend; @@ -709,6 +709,12 @@ enum { OB_LOCK_ROT4D = 1 << 10, }; +/* ob->duplicator_visibility_flag */ +enum { + OB_DUPLI_FLAG_VIEWPORT = 1 << 0, + OB_DUPLI_FLAG_RENDER = 1 << 1, +}; + /* ob->mode */ typedef enum eObjectMode { OB_MODE_OBJECT = 0, diff --git a/source/blender/makesrna/intern/rna_ID.c b/source/blender/makesrna/intern/rna_ID.c index 7c78d42a530..1e6023bd278 100644 --- a/source/blender/makesrna/intern/rna_ID.c +++ b/source/blender/makesrna/intern/rna_ID.c @@ -1043,7 +1043,6 @@ static void rna_def_ID(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Is Updated", "Data-block is tagged for recalculation"); prop = RNA_def_property(srna, "is_updated_data", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_sdna(prop, NULL, "recalc", ID_RECALC_DATA); RNA_def_property_clear_flag(prop, PROP_EDITABLE); RNA_def_property_boolean_funcs(prop, "rna_ID_is_updated_data_get", NULL); RNA_def_property_ui_text(prop, "Is Updated Data", "Data-block data is tagged for recalculation"); diff --git a/source/blender/makesrna/intern/rna_context.c b/source/blender/makesrna/intern/rna_context.c index 3df114282fd..bcd805b0f3a 100644 --- a/source/blender/makesrna/intern/rna_context.c +++ b/source/blender/makesrna/intern/rna_context.c @@ -132,7 +132,11 @@ static PointerRNA rna_Context_scene_get(PointerRNA *ptr) static PointerRNA rna_Context_view_layer_get(PointerRNA *ptr) { bContext *C = (bContext *)ptr->data; - return rna_pointer_inherit_refine(ptr, &RNA_ViewLayer, CTX_data_view_layer(C)); + Scene *scene = CTX_data_scene(C); + PointerRNA scene_ptr; + + RNA_id_pointer_create(&scene->id, &scene_ptr); + return rna_pointer_inherit_refine(&scene_ptr, &RNA_ViewLayer, CTX_data_view_layer(C)); } static PointerRNA rna_Context_view_render_get(PointerRNA *ptr) diff --git a/source/blender/makesrna/intern/rna_depsgraph.c b/source/blender/makesrna/intern/rna_depsgraph.c index ffa75dd75cb..706fb23ab56 100644 --- a/source/blender/makesrna/intern/rna_depsgraph.c +++ b/source/blender/makesrna/intern/rna_depsgraph.c @@ -120,13 +120,26 @@ static int rna_DepsgraphIter_is_instance_get(PointerRNA *ptr) /* **************** Depsgraph **************** */ -static void rna_Depsgraph_debug_graphviz(Depsgraph *graph, const char *filename) +static void rna_Depsgraph_debug_relations_graphviz(Depsgraph *graph, + const char *filename) { FILE *f = fopen(filename, "w"); if (f == NULL) { return; } - DEG_debug_graphviz(graph, f, "Depsgraph", false); + DEG_debug_relations_graphviz(graph, f, "Depsgraph"); + fclose(f); +} + +static void rna_Depsgraph_debug_stats_gnuplot(Depsgraph *graph, + const char *filename, + const char *output_filename) +{ + FILE *f = fopen(filename, "w"); + if (f == NULL) { + return; + } + DEG_debug_stats_gnuplot(graph, f, "Timing Statistics", output_filename); fclose(f); } @@ -155,6 +168,7 @@ static void rna_Depsgraph_objects_begin(CollectionPropertyIterator *iter, Pointe data->flag = DEG_ITER_OBJECT_FLAG_LINKED_DIRECTLY | DEG_ITER_OBJECT_FLAG_VISIBLE | DEG_ITER_OBJECT_FLAG_LINKED_VIA_SET; + data->mode = DEG_ITER_OBJECT_MODE_RENDER; ((BLI_Iterator *)iter->internal.custom)->valid = true; DEG_iterator_objects_begin(iter->internal.custom, data); @@ -195,6 +209,7 @@ static void rna_Depsgraph_duplis_begin(CollectionPropertyIterator *iter, Pointer DEG_ITER_OBJECT_FLAG_LINKED_VIA_SET | DEG_ITER_OBJECT_FLAG_VISIBLE | DEG_ITER_OBJECT_FLAG_DUPLI; + data->mode = DEG_ITER_OBJECT_MODE_RENDER; ((BLI_Iterator *)iter->internal.custom)->valid = true; DEG_iterator_objects_begin(iter->internal.custom, data); @@ -297,10 +312,18 @@ static void rna_def_depsgraph(BlenderRNA *brna) srna = RNA_def_struct(brna, "Depsgraph", NULL); RNA_def_struct_ui_text(srna, "Dependency Graph", ""); - func = RNA_def_function(srna, "debug_graphviz", "rna_Depsgraph_debug_graphviz"); + func = RNA_def_function(srna, "debug_relations_graphviz", "rna_Depsgraph_debug_relations_graphviz"); + parm = RNA_def_string_file_path(func, "filename", NULL, FILE_MAX, "File Name", + "File in which to store graphviz debug output"); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); + + func = RNA_def_function(srna, "debug_stats_gnuplot", "rna_Depsgraph_debug_stats_gnuplot"); parm = RNA_def_string_file_path(func, "filename", NULL, FILE_MAX, "File Name", "File in which to store graphviz debug output"); RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); + parm = RNA_def_string_file_path(func, "output_filename", NULL, FILE_MAX, "Output File Name", + "File name where gnuplot script will save the result"); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); func = RNA_def_function(srna, "debug_tag_update", "rna_Depsgraph_debug_tag_update"); diff --git a/source/blender/makesrna/intern/rna_layer.c b/source/blender/makesrna/intern/rna_layer.c index 00b08957fdd..bcf8f36d7ce 100644 --- a/source/blender/makesrna/intern/rna_layer.c +++ b/source/blender/makesrna/intern/rna_layer.c @@ -870,7 +870,7 @@ static void rna_LayerObjects_selected_begin(CollectionPropertyIterator *iter, Po static void rna_ViewLayer_update_tagged(ViewLayer *UNUSED(view_layer), bContext *C) { Depsgraph *graph = CTX_data_depsgraph(C); - DEG_OBJECT_ITER(graph, ob, + DEG_OBJECT_ITER(graph, ob, DEG_ITER_OBJECT_MODE_VIEWPORT, DEG_ITER_OBJECT_FLAG_LINKED_DIRECTLY | DEG_ITER_OBJECT_FLAG_LINKED_VIA_SET | DEG_ITER_OBJECT_FLAG_LINKED_INDIRECTLY | @@ -991,15 +991,14 @@ static void rna_def_scene_collections(BlenderRNA *brna, PropertyRNA *cprop) func = RNA_def_function(srna, "new", "rna_SceneCollection_new"); RNA_def_function_ui_description(func, "Add a collection to scene"); RNA_def_function_flag(func, FUNC_USE_SELF_ID | FUNC_USE_MAIN); - parm = RNA_def_string(func, "name", "SceneCollection", 0, "", "New name for the collection (not unique)"); - RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); + parm = RNA_def_string(func, "name", NULL, 0, "", "New name for the collection (not unique)"); parm = RNA_def_pointer(func, "result", "SceneCollection", "", "Newly created collection"); RNA_def_function_return(func, parm); func = RNA_def_function(srna, "remove", "rna_SceneCollection_remove"); - RNA_def_function_ui_description(func, "Remove a collection layer"); + RNA_def_function_ui_description(func, "Remove a collection and move its objects to the master collection"); RNA_def_function_flag(func, FUNC_USE_SELF_ID | FUNC_USE_MAIN | FUNC_USE_REPORTS); - parm = RNA_def_pointer(func, "layer", "SceneCollection", "", "Collection to remove"); + parm = RNA_def_pointer(func, "collection", "SceneCollection", "", "Collection to remove"); RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR); RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0); } diff --git a/source/blender/makesrna/intern/rna_object.c b/source/blender/makesrna/intern/rna_object.c index c9dcc787617..9ba341fde03 100644 --- a/source/blender/makesrna/intern/rna_object.c +++ b/source/blender/makesrna/intern/rna_object.c @@ -233,7 +233,13 @@ static void rna_Object_hide_update(Main *bmain, Scene *UNUSED(scene), PointerRNA static int rna_Object_is_visible_get(PointerRNA *ptr) { Object *ob = ptr->id.data; - return BKE_object_is_visible(ob); + /* The duplicators final visibility is not evaluated by depsgraph, so it's + * in ob->base_flag & VISIBLED. Instead we need to take into account whether + * we are rendering or not, and the ob->duplicator_visibility_flag. + * However for this assessor we don't know if we are rendering, so we just + * ignore the duplicator visibility + */ + return BKE_object_is_visible(ob, OB_VISIBILITY_CHECK_UNKNOWN_RENDER_MODE); } static void rna_Object_collection_properties_begin(CollectionPropertyIterator *iter, PointerRNA *ptr) @@ -2800,6 +2806,14 @@ static void rna_def_object(BlenderRNA *brna) RNA_def_property_ui_icon(prop, ICON_RESTRICT_RENDER_OFF, 1); RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, "rna_Object_hide_update"); + prop = RNA_def_property(srna, "show_duplicator_for_render", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "duplicator_visibility_flag", OB_DUPLI_FLAG_RENDER); + RNA_def_property_ui_text(prop, "Render Duplicator", "Make duplicator visible when rendering"); + + prop = RNA_def_property(srna, "show_duplicator_for_viewport", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "duplicator_visibility_flag", OB_DUPLI_FLAG_VIEWPORT); + RNA_def_property_ui_text(prop, "Show Duplicator", "Make duplicator visible in the viewport"); + prop = RNA_def_property(srna, "is_visible", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_funcs(prop, "rna_Object_is_visible_get", NULL); RNA_def_property_ui_text(prop, "Visible", "Visible to camera rays, set only on objects evaluated by depsgraph"); diff --git a/source/blender/makesrna/intern/rna_particle.c b/source/blender/makesrna/intern/rna_particle.c index 67eaa22fbe4..12e56b8e926 100644 --- a/source/blender/makesrna/intern/rna_particle.c +++ b/source/blender/makesrna/intern/rna_particle.c @@ -2292,11 +2292,6 @@ static void rna_def_particle_settings(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Size", "Show particle size"); RNA_def_property_update(prop, 0, "rna_Particle_redo"); - prop = RNA_def_property(srna, "use_render_emitter", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_sdna(prop, NULL, "draw", PART_DRAW_EMITTER); - RNA_def_property_ui_text(prop, "Emitter", "Render emitter Object also"); - RNA_def_property_update(prop, 0, "rna_Particle_redo"); - prop = RNA_def_property(srna, "show_health", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "draw", PART_DRAW_HEALTH); RNA_def_property_ui_text(prop, "Health", "Draw boid health"); diff --git a/source/blender/makesrna/intern/rna_rna.c b/source/blender/makesrna/intern/rna_rna.c index da4eea41223..38149734bc2 100644 --- a/source/blender/makesrna/intern/rna_rna.c +++ b/source/blender/makesrna/intern/rna_rna.c @@ -337,7 +337,7 @@ static void rna_Struct_property_tags_begin(CollectionPropertyIterator *iter, Poi /* here ptr->data should always be the same as iter->parent.type */ StructRNA *srna = (StructRNA *)ptr->data; const EnumPropertyItem *tag_defines = RNA_struct_property_tag_defines(srna); - unsigned int tag_count = RNA_enum_items_count(tag_defines); + unsigned int tag_count = tag_defines ? RNA_enum_items_count(tag_defines) : 0; rna_iterator_array_begin(iter, (void *)tag_defines, sizeof(EnumPropertyItem), tag_count, 0, NULL); } diff --git a/source/blender/makesrna/intern/rna_tracking.c b/source/blender/makesrna/intern/rna_tracking.c index d23017429c1..ccc118edfb6 100644 --- a/source/blender/makesrna/intern/rna_tracking.c +++ b/source/blender/makesrna/intern/rna_tracking.c @@ -48,6 +48,9 @@ #ifdef RNA_RUNTIME +#include "DNA_anim_types.h" + +#include "BKE_animsys.h" #include "BKE_node.h" #include "DEG_depsgraph.h" @@ -56,71 +59,6 @@ #include "WM_api.h" -static MovieTrackingObject *tracking_object_from_track(MovieClip *clip, - MovieTrackingTrack *track) -{ - MovieTracking *tracking = &clip->tracking; - ListBase *tracksbase = &tracking->tracks; - /* TODO: it's a bit difficult to find list track came from knowing just - * movie clip ID and MovieTracking structure, so keep this naive - * search for a while */ - if (BLI_findindex(tracksbase, track) == -1) { - MovieTrackingObject *object = tracking->objects.first; - while (object) { - if (BLI_findindex(&object->tracks, track) != -1) { - return object; - } - object = object->next; - } - } - return NULL; -} - -static ListBase *tracking_tracksbase_from_track(MovieClip *clip, - MovieTrackingTrack *track) -{ - MovieTracking *tracking = &clip->tracking; - MovieTrackingObject *object = tracking_object_from_track(clip, track); - if (object != NULL) { - return &object->tracks; - } - return &tracking->tracks; -} - -static MovieTrackingObject *tracking_object_from_plane_track( - MovieClip *clip, - MovieTrackingPlaneTrack *plane_track) -{ - MovieTracking *tracking = &clip->tracking; - ListBase *plane_tracks_base = &tracking->plane_tracks; - /* TODO: it's a bit difficult to find list track came from knowing just - * movie clip ID and MovieTracking structure, so keep this naive - * search for a while */ - if (BLI_findindex(plane_tracks_base, plane_track) == -1) { - MovieTrackingObject *object = tracking->objects.first; - while (object) { - if (BLI_findindex(&object->plane_tracks, plane_track) != -1) { - return object; - } - object = object->next; - } - } - return NULL; -} - -static ListBase *tracking_tracksbase_from_plane_track( - MovieClip *clip, - MovieTrackingPlaneTrack *plane_track) -{ - MovieTracking *tracking = &clip->tracking; - MovieTrackingObject *object = tracking_object_from_plane_track(clip, - plane_track); - if (object != NULL) { - return &object->plane_tracks; - } - return &tracking->plane_tracks; -} - static char *rna_tracking_path(PointerRNA *UNUSED(ptr)) { return BLI_sprintfN("tracking"); @@ -150,19 +88,12 @@ static char *rna_trackingTrack_path(PointerRNA *ptr) { MovieClip *clip = (MovieClip *)ptr->id.data; MovieTrackingTrack *track = (MovieTrackingTrack *)ptr->data; - MovieTrackingObject *object = tracking_object_from_track(clip, track); - char track_name_esc[sizeof(track->name) * 2]; - BLI_strescape(track_name_esc, track->name, sizeof(track_name_esc)); - if (object == NULL) { - return BLI_sprintfN("tracking.tracks[\"%s\"]", track_name_esc); - } - else { - char object_name_esc[sizeof(object->name) * 2]; - BLI_strescape(object_name_esc, object->name, sizeof(object_name_esc)); - return BLI_sprintfN("tracking.objects[\"%s\"].tracks[\"%s\"]", - object_name_esc, - track_name_esc); - } + /* Escaped object name, escaped track name, rest of the path. */ + char rna_path[MAX_NAME * 4 + 64]; + BKE_tracking_get_rna_path_for_track(&clip->tracking, + track, + rna_path, sizeof(rna_path)); + return BLI_strdup(rna_path); } static void rna_trackingTracks_begin(CollectionPropertyIterator *iter, PointerRNA *ptr) @@ -256,9 +187,26 @@ static void rna_trackingTrack_name_set(PointerRNA *ptr, const char *value) { MovieClip *clip = (MovieClip *)ptr->id.data; MovieTrackingTrack *track = (MovieTrackingTrack *)ptr->data; - ListBase *tracksbase = tracking_tracksbase_from_track(clip, track); + ListBase *tracksbase = + BKE_tracking_find_tracks_list_for_track(&clip->tracking, track); + /* Store old name, for the animation fix later. */ + char old_name[sizeof(track->name)]; + BLI_strncpy(old_name, track->name, sizeof(track->name)); + /* Update the name, */ BLI_strncpy(track->name, value, sizeof(track->name)); BKE_tracking_track_unique_name(tracksbase, track); + /* Fix animation paths. */ + AnimData *adt = BKE_animdata_from_id(&clip->id); + if (adt != NULL) { + char rna_path[MAX_NAME * 2 + 64]; + BKE_tracking_get_rna_path_prefix_for_track(&clip->tracking, + track, + rna_path, sizeof(rna_path)); + BKE_animdata_fix_paths_rename(&clip->id, adt, NULL, + rna_path, + old_name, track->name, + 0, 0, 1); + } } static int rna_trackingTrack_select_get(PointerRNA *ptr) @@ -327,28 +275,40 @@ static char *rna_trackingPlaneTrack_path(PointerRNA *ptr) { MovieClip *clip = (MovieClip *)ptr->id.data; MovieTrackingPlaneTrack *plane_track = (MovieTrackingPlaneTrack *)ptr->data; - char track_name_esc[sizeof(plane_track->name) * 2]; - MovieTrackingObject *object = tracking_object_from_plane_track(clip, plane_track); - BLI_strescape(track_name_esc, plane_track->name, sizeof(track_name_esc)); - if (object == NULL) { - return BLI_sprintfN("tracking.plane_tracks[\"%s\"]", track_name_esc); - } - else { - char object_name_esc[sizeof(object->name) * 2]; - BLI_strescape(object_name_esc, object->name, sizeof(object_name_esc)); - return BLI_sprintfN("tracking.objects[\"%s\"].plane_tracks[\"%s\"]", - object_name_esc, - track_name_esc); - } + /* Escaped object name, escaped track name, rest of the path. */ + char rna_path[MAX_NAME * 4 + 64]; + BKE_tracking_get_rna_path_for_plane_track(&clip->tracking, + plane_track, + rna_path, sizeof(rna_path)); + return BLI_strdup(rna_path); } static void rna_trackingPlaneTrack_name_set(PointerRNA *ptr, const char *value) { MovieClip *clip = (MovieClip *)ptr->id.data; MovieTrackingPlaneTrack *plane_track = (MovieTrackingPlaneTrack *)ptr->data; - ListBase *plane_tracks_base = tracking_tracksbase_from_plane_track(clip, plane_track); + ListBase *plane_tracks_base = + BKE_tracking_find_tracks_list_for_plane_track(&clip->tracking, + plane_track); + /* Store old name, for the animation fix later. */ + char old_name[sizeof(plane_track->name)]; + BLI_strncpy(old_name, plane_track->name, sizeof(plane_track->name)); + /* Update the name, */ BLI_strncpy(plane_track->name, value, sizeof(plane_track->name)); BKE_tracking_plane_track_unique_name(plane_tracks_base, plane_track); + /* Fix animation paths. */ + AnimData *adt = BKE_animdata_from_id(&clip->id); + if (adt != NULL) { + char rna_path[MAX_NAME * 2 + 64]; + BKE_tracking_get_rna_path_prefix_for_plane_track(&clip->tracking, + plane_track, + rna_path, + sizeof(rna_path)); + BKE_animdata_fix_paths_rename(&clip->id, adt, NULL, + rna_path, + old_name, plane_track->name, + 0, 0, 1); + } } static char *rna_trackingCamera_path(PointerRNA *UNUSED(ptr)) @@ -1651,6 +1611,7 @@ static void rna_def_trackingPlaneTrack(BlenderRNA *brna) /* auto keyframing */ prop = RNA_def_property(srna, "use_auto_keying", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", PLANE_TRACK_AUTOKEY); + RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); RNA_def_property_ui_text(prop, "Auto Keyframe", "Automatic keyframe insertion when moving plane corners"); RNA_def_property_ui_icon(prop, ICON_REC, 0); diff --git a/source/blender/makesrna/intern/rna_wm.c b/source/blender/makesrna/intern/rna_wm.c index d25888e0f93..36f07db727b 100644 --- a/source/blender/makesrna/intern/rna_wm.c +++ b/source/blender/makesrna/intern/rna_wm.c @@ -763,8 +763,10 @@ static PointerRNA rna_Window_view_layer_get(PointerRNA *ptr) Scene *scene = WM_window_get_active_scene(win); WorkSpace *workspace = WM_window_get_active_workspace(win); ViewLayer *view_layer = BKE_workspace_view_layer_get(workspace, scene); + PointerRNA scene_ptr; - return rna_pointer_inherit_refine(ptr, &RNA_ViewLayer, view_layer); + RNA_id_pointer_create(&scene->id, &scene_ptr); + return rna_pointer_inherit_refine(&scene_ptr, &RNA_ViewLayer, view_layer); } static void rna_Window_view_layer_set(PointerRNA *ptr, PointerRNA value) diff --git a/source/blender/modifiers/intern/MOD_surfacedeform.c b/source/blender/modifiers/intern/MOD_surfacedeform.c index b623293ed5c..2919f169d00 100644 --- a/source/blender/modifiers/intern/MOD_surfacedeform.c +++ b/source/blender/modifiers/intern/MOD_surfacedeform.c @@ -314,11 +314,13 @@ BLI_INLINE int isPolyValid(const float coords[][2], const unsigned int nr) copy_v2_v2(prev_co, coords[nr - 1]); sub_v2_v2v2(prev_vec, prev_co, coords[nr - 2]); + normalize_v2(prev_vec); for (int i = 0; i < nr; i++) { sub_v2_v2v2(curr_vec, coords[i], prev_co); - if (len_squared_v2(curr_vec) < FLT_EPSILON) { + const float curr_len = normalize_v2(curr_vec); + if (curr_len < FLT_EPSILON) { return MOD_SDEF_BIND_RESULT_OVERLAP_ERR; } diff --git a/source/blender/render/intern/source/convertblender.c b/source/blender/render/intern/source/convertblender.c index 74de3fcded6..fc60c70c2c4 100644 --- a/source/blender/render/intern/source/convertblender.c +++ b/source/blender/render/intern/source/convertblender.c @@ -4668,9 +4668,8 @@ static void add_render_object(Render *re, Object *ob, Object *par, DupliObject * /* the emitter has to be processed first (render levels of modifiers) */ /* so here we only check if the emitter should be rendered */ if (ob->particlesystem.first) { - show_emitter= 0; + show_emitter = (ob->duplicator_visibility_flag & OB_DUPLI_FLAG_RENDER) != 0; for (psys=ob->particlesystem.first; psys; psys=psys->next) { - show_emitter += psys->part->draw & PART_DRAW_EMITTER; if (!(re->r.scemode & R_VIEWPORT_PREVIEW)) { psys_has_renderdata |= (psys->renderdata != NULL); psys_render_set(ob, psys, re->viewmat, re->winmat, re->winx, re->winy, timeoffset); diff --git a/source/blender/windowmanager/intern/wm_event_system.c b/source/blender/windowmanager/intern/wm_event_system.c index b1ec1c009df..d50788063e2 100644 --- a/source/blender/windowmanager/intern/wm_event_system.c +++ b/source/blender/windowmanager/intern/wm_event_system.c @@ -2251,13 +2251,32 @@ static int wm_handlers_do_intern(bContext *C, wmEvent *event, ListBase *handlers wm_manipulatormap_handler_context(C, handler); wm_region_mouse_co(C, event); + if (event->type == MOUSEMOVE) { + WM_manipulatormap_tooltip_clear(C, mmap); + } + /* handle manipulator highlighting */ if (event->type == MOUSEMOVE && !wm_manipulatormap_modal_get(mmap)) { int part; mpr = wm_manipulatormap_highlight_find(mmap, C, event, &part); wm_manipulatormap_highlight_set(mmap, C, mpr, part); + if (mpr != NULL) { + WM_manipulatormap_tooltip_timer_init(C, mmap); + } } /* handle user configurable manipulator-map keymap */ + else if ((event->type == TIMER) && + (event->customdata == WM_manipulatormap_tooltip_timer_get(mmap))) + { + if (mpr) { + if (mpr->state & WM_MANIPULATOR_STATE_MODAL) { + WM_manipulatormap_tooltip_clear(C, mmap); + } + else { + WM_manipulatormap_tooltip_create(C, mmap); + } + } + } else { /* Either we operate on a single highlighted item * or groups attached to the selected manipulators. diff --git a/source/blender/windowmanager/manipulators/WM_manipulator_api.h b/source/blender/windowmanager/manipulators/WM_manipulator_api.h index 9214bccb6a0..7a31f4e6f1f 100644 --- a/source/blender/windowmanager/manipulators/WM_manipulator_api.h +++ b/source/blender/windowmanager/manipulators/WM_manipulator_api.h @@ -259,6 +259,15 @@ bool WM_manipulatormap_minmax( const struct wmManipulatorMap *mmap, bool use_hidden, bool use_select, float r_min[3], float r_max[3]); +void WM_manipulatormap_tooltip_create( + struct bContext *C, struct wmManipulatorMap *mmap); +void WM_manipulatormap_tooltip_clear( + struct bContext *C, struct wmManipulatorMap *mmap); +void WM_manipulatormap_tooltip_timer_init( + struct bContext *C, struct wmManipulatorMap *mmap); +const void *WM_manipulatormap_tooltip_timer_get( + struct wmManipulatorMap *mmap); + /* -------------------------------------------------------------------- */ /* wmManipulatorMapType */ diff --git a/source/blender/windowmanager/manipulators/WM_manipulator_types.h b/source/blender/windowmanager/manipulators/WM_manipulator_types.h index e8b81e1a78c..f2c0a8e93d9 100644 --- a/source/blender/windowmanager/manipulators/WM_manipulator_types.h +++ b/source/blender/windowmanager/manipulators/WM_manipulator_types.h @@ -182,6 +182,8 @@ struct wmManipulator { /* Optional ID for highlighting different parts of this manipulator. * -1 when unset, otherwise a valid index. (Used as index to 'op_data'). */ int highlight_part; + /* For single click button manipulators, use a different part as a fallback, -1 when unused. */ + int drag_part; /* Transformation of the manipulator in 2d or 3d space. * - Matrix axis are expected to be unit length (scale is applied after). diff --git a/source/blender/windowmanager/manipulators/intern/wm_manipulator.c b/source/blender/windowmanager/manipulators/intern/wm_manipulator.c index 7ca1f8fd5f2..5190a4932b4 100644 --- a/source/blender/windowmanager/manipulators/intern/wm_manipulator.c +++ b/source/blender/windowmanager/manipulators/intern/wm_manipulator.c @@ -98,6 +98,8 @@ static wmManipulator *wm_manipulator_create( unit_m4(mpr->matrix_basis); unit_m4(mpr->matrix_offset); + mpr->drag_part = -1; + return mpr; } diff --git a/source/blender/windowmanager/manipulators/intern/wm_manipulator_group.c b/source/blender/windowmanager/manipulators/intern/wm_manipulator_group.c index ebb5d835455..c4220aa3a5d 100644 --- a/source/blender/windowmanager/manipulators/intern/wm_manipulator_group.c +++ b/source/blender/windowmanager/manipulators/intern/wm_manipulator_group.c @@ -39,6 +39,7 @@ #include "BLI_listbase.h" #include "BLI_string.h" +#include "BLI_math.h" #include "BKE_context.h" #include "BKE_main.h" @@ -61,6 +62,10 @@ # include "BPY_extern.h" #endif +/* Allow manipulator part's to be single click only, + * dragging falls back to activating their 'drag_part' action. */ +#define USE_DRAG_DETECT + /* -------------------------------------------------------------------- */ /** \name wmManipulatorGroup * @@ -307,15 +312,71 @@ typedef struct ManipulatorTweakData { int init_event; /* initial event type */ int flag; /* tweak flags */ + +#ifdef USE_DRAG_DETECT + /* True until the mouse is moved (only use when the operator has no modal). + * this allows some manipulators to be click-only. */ + enum { + /* Don't detect dragging. */ + DRAG_NOP = 0, + /* Detect dragging (wait until a drag or click is detected). */ + DRAG_DETECT, + /* Drag has started, idle until there is no active modal operator. + * This is needed because finishing the modal operator also exits + * the modal manipulator state (un-grabbs the cursor). + * Ideally this workaround could be removed later. */ + DRAG_IDLE, + } drag_state; +#endif + } ManipulatorTweakData; -static void manipulator_tweak_finish(bContext *C, wmOperator *op, const bool cancel) +static bool manipulator_tweak_start( + bContext *C, wmManipulatorMap *mmap, wmManipulator *mpr, const wmEvent *event) +{ + /* activate highlighted manipulator */ + wm_manipulatormap_modal_set(mmap, C, mpr, event, true); + + return (mpr->state & WM_MANIPULATOR_STATE_MODAL); +} + +static bool manipulator_tweak_start_and_finish( + bContext *C, wmManipulatorMap *mmap, wmManipulator *mpr, const wmEvent *event, bool *r_is_modal) +{ + wmManipulatorOpElem *mpop = WM_manipulator_operator_get(mpr, mpr->highlight_part); + if (r_is_modal) { + *r_is_modal = false; + } + if (mpop && mpop->type) { + /* XXX temporary workaround for modal manipulator operator + * conflicting with modal operator attached to manipulator */ + if (mpop->type->modal) { + /* activate highlighted manipulator */ + wm_manipulatormap_modal_set(mmap, C, mpr, event, true); + if (r_is_modal) { + *r_is_modal = true; + } + } + else { + /* Allow for 'button' manipulators, single click to run an action. */ + WM_operator_name_call_ptr(C, mpop->type, WM_OP_INVOKE_DEFAULT, &mpop->ptr); + } + return true; + } + else { + return false; + } +} + +static void manipulator_tweak_finish(bContext *C, wmOperator *op, const bool cancel, bool clear_modal) { ManipulatorTweakData *mtweak = op->customdata; if (mtweak->mpr_modal->type->exit) { mtweak->mpr_modal->type->exit(C, mtweak->mpr_modal, cancel); } - wm_manipulatormap_modal_set(mtweak->mmap, C, mtweak->mpr_modal, NULL, false); + if (clear_modal) { + wm_manipulatormap_modal_set(mtweak->mmap, C, mtweak->mpr_modal, NULL, false); + } MEM_freeN(mtweak); } @@ -323,27 +384,68 @@ static int manipulator_tweak_modal(bContext *C, wmOperator *op, const wmEvent *e { ManipulatorTweakData *mtweak = op->customdata; wmManipulator *mpr = mtweak->mpr_modal; + int retval = OPERATOR_PASS_THROUGH; + bool clear_modal = true; if (mpr == NULL) { BLI_assert(0); return (OPERATOR_CANCELLED | OPERATOR_PASS_THROUGH); } - if (event->type == mtweak->init_event && event->val == KM_RELEASE) { - manipulator_tweak_finish(C, op, false); - return OPERATOR_FINISHED; - } +#ifdef USE_DRAG_DETECT + wmManipulatorMap *mmap = mtweak->mmap; + if (mtweak->drag_state == DRAG_DETECT) { + if (ELEM(event->type, MOUSEMOVE, INBETWEEN_MOUSEMOVE)) { + if (len_manhattan_v2v2_int(&event->x, mmap->mmap_context.event_xy) > 2) { + mtweak->drag_state = DRAG_IDLE; + mpr->highlight_part = mpr->drag_part; + } + } + else if (event->type == mtweak->init_event && event->val == KM_RELEASE) { + mtweak->drag_state = DRAG_NOP; + retval = OPERATOR_FINISHED; + } + if (mtweak->drag_state != DRAG_DETECT) { + /* Follow logic in 'manipulator_tweak_invoke' */ + bool is_modal = false; + if (manipulator_tweak_start_and_finish(C, mmap, mpr, event, &is_modal)) { + if (is_modal) { + clear_modal = false; + } + } + else { + if (!manipulator_tweak_start(C, mmap, mpr, event)) { + retval = OPERATOR_FINISHED; + } + } + } + } + if (mtweak->drag_state == DRAG_IDLE) { + if (mmap->mmap_context.modal != NULL) { + return OPERATOR_PASS_THROUGH; + } + else { + manipulator_tweak_finish(C, op, false, false); + return OPERATOR_FINISHED; + } + } +#endif /* USE_DRAG_DETECT */ - if (event->type == EVT_MODAL_MAP) { + if (retval == OPERATOR_FINISHED) { + /* pass */ + } + else if (event->type == mtweak->init_event && event->val == KM_RELEASE) { + retval = OPERATOR_FINISHED; + } + else if (event->type == EVT_MODAL_MAP) { switch (event->val) { case TWEAK_MODAL_CANCEL: - manipulator_tweak_finish(C, op, true); - return OPERATOR_CANCELLED; + retval = OPERATOR_CANCELLED; + break; case TWEAK_MODAL_CONFIRM: - manipulator_tweak_finish(C, op, false); - return OPERATOR_FINISHED; - + retval = OPERATOR_FINISHED; + break; case TWEAK_MODAL_PRECISION_ON: mtweak->flag |= WM_MANIPULATOR_TWEAK_PRECISE; break; @@ -360,20 +462,28 @@ static int manipulator_tweak_modal(bContext *C, wmOperator *op, const wmEvent *e } } + if (retval != OPERATOR_PASS_THROUGH) { + manipulator_tweak_finish(C, op, retval != OPERATOR_FINISHED, clear_modal); + return retval; + } + /* handle manipulator */ wmManipulatorFnModal modal_fn = mpr->custom_modal ? mpr->custom_modal : mpr->type->modal; - int retval = modal_fn(C, mpr, event, mtweak->flag); + if (modal_fn) { + int modal_retval = modal_fn(C, mpr, event, mtweak->flag); - if ((retval & OPERATOR_RUNNING_MODAL) == 0) { - manipulator_tweak_finish(C, op, (retval & OPERATOR_CANCELLED) != 0); - return OPERATOR_FINISHED; - } + if ((modal_retval & OPERATOR_RUNNING_MODAL) == 0) { + manipulator_tweak_finish(C, op, (modal_retval & OPERATOR_CANCELLED) != 0, true); + return OPERATOR_FINISHED; + } - /* Ugly hack to send manipulator events */ - ((wmEvent *)event)->type = EVT_MANIPULATOR_UPDATE; + /* Ugly hack to send manipulator events */ + ((wmEvent *)event)->type = EVT_MANIPULATOR_UPDATE; + } /* always return PASS_THROUGH so modal handlers * with manipulators attached can update */ + BLI_assert(retval == OPERATOR_PASS_THROUGH); return OPERATOR_PASS_THROUGH; } @@ -383,36 +493,44 @@ static int manipulator_tweak_invoke(bContext *C, wmOperator *op, const wmEvent * wmManipulatorMap *mmap = ar->manipulator_map; wmManipulator *mpr = mmap->mmap_context.highlight; + /* Needed for single click actions which don't enter modal state. */ + WM_manipulatormap_tooltip_clear(C, mmap); + if (!mpr) { /* wm_handlers_do_intern shouldn't let this happen */ BLI_assert(0); return (OPERATOR_CANCELLED | OPERATOR_PASS_THROUGH); } - wmManipulatorOpElem *mpop = WM_manipulator_operator_get(mpr, mpr->highlight_part); + bool use_drag_fallback = false; - /* Allow for 'button' manipulators, single click to run an action. */ - if (mpop && mpop->type) { - if (mpop->type->modal == NULL) { - WM_operator_name_call_ptr(C, mpop->type, WM_OP_INVOKE_DEFAULT, &mpop->ptr); +#ifdef USE_DRAG_DETECT + use_drag_fallback = !ELEM(mpr->drag_part, -1, mpr->highlight_part); +#endif + + if (use_drag_fallback == false) { + if (manipulator_tweak_start_and_finish(C, mmap, mpr, event, NULL)) { return OPERATOR_FINISHED; } } - /* activate highlighted manipulator */ - wm_manipulatormap_modal_set(mmap, C, mpr, event, true); - - /* XXX temporary workaround for modal manipulator operator - * conflicting with modal operator attached to manipulator */ - if (mpop && mpop->type) { - if (mpop->type->modal) { - return OPERATOR_FINISHED; + bool use_drag_detect = false; +#ifdef USE_DRAG_DETECT + if (use_drag_fallback) { + wmManipulatorOpElem *mpop = WM_manipulator_operator_get(mpr, mpr->highlight_part); + if (mpop && mpop->type) { + if (mpop->type->modal == NULL) { + use_drag_detect = true; + } } } +#endif - /* Couldn't start the manipulator. */ - if ((mpr->state & WM_MANIPULATOR_STATE_MODAL) == 0) { - return OPERATOR_PASS_THROUGH; + if (use_drag_detect == false) { + if (!manipulator_tweak_start(C, mmap, mpr, event)) { + /* failed to start */ + return OPERATOR_PASS_THROUGH; + } } ManipulatorTweakData *mtweak = MEM_mallocN(sizeof(ManipulatorTweakData), __func__); @@ -422,6 +540,10 @@ static int manipulator_tweak_invoke(bContext *C, wmOperator *op, const wmEvent * mtweak->mmap = mmap; mtweak->flag = 0; +#ifdef USE_DRAG_DETECT + mtweak->drag_state = use_drag_detect ? DRAG_DETECT : DRAG_NOP; +#endif + op->customdata = mtweak; WM_event_add_modal_handler(C, op); diff --git a/source/blender/windowmanager/manipulators/intern/wm_manipulator_intern.h b/source/blender/windowmanager/manipulators/intern/wm_manipulator_intern.h index 419ac7d5521..fc814adaef1 100644 --- a/source/blender/windowmanager/manipulators/intern/wm_manipulator_intern.h +++ b/source/blender/windowmanager/manipulators/intern/wm_manipulator_intern.h @@ -115,6 +115,9 @@ struct wmManipulatorMap { /* cursor location at point of entering modal (see: WM_MANIPULATOR_GRAB_CURSOR) */ int event_xy[2]; short event_grabcursor; + + struct ARegion *tooltip; + struct wmTimer *tooltip_timer; } mmap_context; }; diff --git a/source/blender/windowmanager/manipulators/intern/wm_manipulator_map.c b/source/blender/windowmanager/manipulators/intern/wm_manipulator_map.c index ba3b405e612..ab7b4688d49 100644 --- a/source/blender/windowmanager/manipulators/intern/wm_manipulator_map.c +++ b/source/blender/windowmanager/manipulators/intern/wm_manipulator_map.c @@ -51,6 +51,9 @@ #include "WM_types.h" #include "wm_event_system.h" +/* for tool-tips */ +#include "UI_interface.h" + #include "DEG_depsgraph.h" /* own includes */ @@ -888,6 +891,8 @@ void wm_manipulatormap_modal_set( BLI_assert(mmap->mmap_context.modal == NULL); wmWindow *win = CTX_wm_window(C); + WM_manipulatormap_tooltip_clear(C, mmap); + /* For now only grab cursor for 3D manipulators. */ int retval = OPERATOR_RUNNING_MODAL; @@ -953,6 +958,8 @@ void wm_manipulatormap_modal_set( ED_region_tag_redraw(CTX_wm_region(C)); WM_event_add_mousemove(C); } + + mmap->mmap_context.event_xy[0] = INT_MAX; } } @@ -995,6 +1002,54 @@ void WM_manipulatormap_message_subscribe( /* -------------------------------------------------------------------- */ +/** \name Tooltip Handling + * + * \{ */ + + +void WM_manipulatormap_tooltip_create( + bContext *C, wmManipulatorMap *mmap) +{ + WM_manipulatormap_tooltip_clear(C, mmap); + if (mmap->mmap_context.highlight) { + mmap->mmap_context.tooltip = UI_tooltip_create_from_manipulator(C, mmap->mmap_context.highlight); + } +} + +void WM_manipulatormap_tooltip_clear( + bContext *C, wmManipulatorMap *mmap) +{ + if (mmap->mmap_context.tooltip_timer != NULL) { + wmWindowManager *wm = CTX_wm_manager(C); + wmWindow *win = CTX_wm_window(C); + WM_event_remove_timer(wm, win, mmap->mmap_context.tooltip_timer); + mmap->mmap_context.tooltip_timer = NULL; + } + if (mmap->mmap_context.tooltip != NULL) { + UI_tooltip_free(C, mmap->mmap_context.tooltip); + mmap->mmap_context.tooltip = NULL; + } +} + +void WM_manipulatormap_tooltip_timer_init( + bContext *C, wmManipulatorMap *mmap) +{ + if (mmap->mmap_context.tooltip_timer == NULL) { + wmWindowManager *wm = CTX_wm_manager(C); + wmWindow *win = CTX_wm_window(C); + /* TODO: BUTTON_TOOLTIP_DELAY */ + mmap->mmap_context.tooltip_timer = WM_event_add_timer(wm, win, TIMER, UI_TOOLTIP_DELAY); + } +} + +const void *WM_manipulatormap_tooltip_timer_get(wmManipulatorMap *mmap) +{ + return mmap->mmap_context.tooltip_timer; +} + +/** \} */ /* wmManipulatorMapType */ + +/* -------------------------------------------------------------------- */ /** \name wmManipulatorMapType * * \{ */ diff --git a/source/tools b/source/tools -Subproject 9ea62ef860cde8eb313b74cd1b23ca5a0734eef +Subproject ccf20e08702ee6424edbda01544bb9f8bc386de diff --git a/tests/python/CMakeLists.txt b/tests/python/CMakeLists.txt index dd4c57b43eb..9f1de64c2e9 100644 --- a/tests/python/CMakeLists.txt +++ b/tests/python/CMakeLists.txt @@ -547,6 +547,7 @@ if(WITH_CYCLES) add_cycles_render_test(shader) add_cycles_render_test(shader_tangent) add_cycles_render_test(shadow_catcher) + add_cycles_render_test(texture_space) add_cycles_render_test(volume) else() MESSAGE(STATUS "Disabling Cycles tests because tests folder does not exist") diff --git a/tests/python/view_layer/CMakeLists.txt b/tests/python/view_layer/CMakeLists.txt index 22cfcd344f3..eaaf25b3889 100644 --- a/tests/python/view_layer/CMakeLists.txt +++ b/tests/python/view_layer/CMakeLists.txt @@ -170,6 +170,7 @@ VIEW_LAYER_TEST(move_into_layer_collection_i) VIEW_LAYER_TEST(move_into_layer_collection_j) VIEW_LAYER_TEST(layer_linking) VIEW_LAYER_TEST(layer_syncing) +VIEW_LAYER_TEST(scene_collection_delete) VIEW_LAYER_TEST(scene_copy_a) VIEW_LAYER_TEST(scene_copy_b) VIEW_LAYER_TEST(scene_copy_c) @@ -178,3 +179,4 @@ VIEW_LAYER_TEST(scene_copy_e) VIEW_LAYER_TEST(scene_copy_f) VIEW_LAYER_TEST(scene_delete) VIEW_LAYER_TEST(scene_write_read) +VIEW_LAYER_TEST(view_layer_rename) diff --git a/tests/python/view_layer/test_collection_rename.py b/tests/python/view_layer/test_collection_rename.py index 3fcc5981e68..ea156d7346f 100644 --- a/tests/python/view_layer/test_collection_rename.py +++ b/tests/python/view_layer/test_collection_rename.py @@ -34,7 +34,8 @@ class UnitTesting(ViewLayerTesting): family = self.setup_family() family['mom'].name = family['daughter'].name - self.assertNotEqual(family['mom'].name, family['daughter'].name) + # Since they are not siblings, we allow them to have the same name. + self.assertEqual(family['mom'].name, family['daughter'].name) def test_rename_b(self): family = self.setup_family() @@ -46,7 +47,8 @@ class UnitTesting(ViewLayerTesting): family = self.setup_family() family['cousin'].name = family['daughter'].name - self.assertNotEqual(family['cousin'].name, family['daughter'].name) + # Since they are not siblings, we allow them to have the same name. + self.assertEqual(family['cousin'].name, family['daughter'].name) def test_rename_d(self): family = self.setup_family() @@ -54,6 +56,12 @@ class UnitTesting(ViewLayerTesting): family['son'].name = family['daughter'].name self.assertNotEqual(family['son'].name, family['daughter'].name) + def test_rename_e(self): + family = self.setup_family() + + family['grandma'].name = family['grandpa'].name + self.assertNotEqual(family['grandma'].name, family['grandpa'].name) + def test_add_equal_name_a(self): family = self.setup_family() @@ -64,7 +72,14 @@ class UnitTesting(ViewLayerTesting): family = self.setup_family() other_aunt = family['grandma'].collections.new(family['daughter'].name) - self.assertNotEqual(other_aunt.name, family['daughter'].name) + # Since they are not siblings, we allow them to have the same name. + self.assertEqual(other_aunt.name, family['daughter'].name) + + def test_add_equal_name_c(self): + family = self.setup_family() + + other_aunt = family['grandma'].collections.new(family['mom'].name) + self.assertNotEqual(other_aunt.name, family['mom'].name) # ############################################################ diff --git a/tests/python/view_layer/test_operator_context.py b/tests/python/view_layer/test_operator_context.py index ff751bc0fa5..34f46c963bb 100644 --- a/tests/python/view_layer/test_operator_context.py +++ b/tests/python/view_layer/test_operator_context.py @@ -114,11 +114,14 @@ class UnitTesting(ViewLayerTesting): override = bpy.context.copy() override["view_layer"] = layer + self.assertNotEqual(bpy.context.view_layer.name, layer.name) + self.assertNotEqual(bpy.context.scene_collection.name, layer.collections.active.name) + self.assertEqual(bpy.ops.testing.sample( override, view_layer=layer.name, scene_collection=layer.collections.active.name, # 'scorpion' - use_verbose=True), {'FINISHED'}) + use_verbose=False), {'CANCELLED'}) # ############################################################ diff --git a/tests/python/view_layer/test_scene_collection_delete.py b/tests/python/view_layer/test_scene_collection_delete.py new file mode 100644 index 00000000000..3f917e5a35c --- /dev/null +++ b/tests/python/view_layer/test_scene_collection_delete.py @@ -0,0 +1,54 @@ +# ############################################################ +# Importing - Same For All Render Layer Tests +# ############################################################ + +import unittest +import os +import sys + +from view_layer_common import * + + +# ############################################################ +# Testing +# ############################################################ + +class UnitTesting(ViewLayerTesting): + def test_scene_collection_delete(self): + """ + See if a scene collection can be properly deleted even + when linked + """ + import bpy + + # delete all initial objects + while bpy.data.objects: + bpy.data.objects.remove(bpy.data.objects[0]) + + # delete all initial collections + scene = bpy.context.scene + master_collection = scene.master_collection + while master_collection.collections: + master_collection.collections.remove(master_collection.collections[0]) + + collection_parent = master_collection.collections.new('parent') + collection_nested = collection_parent.collections.new('child linked') + bpy.context.view_layer.collections.link(collection_nested) + master_collection.collections.remove(collection_parent) + + # Update depsgraph. + scene.update() + + +# ############################################################ +# Main - Same For All Render Layer Tests +# ############################################################ + +if __name__ == '__main__': + import sys + + extra_arguments = sys.argv[sys.argv.index("--") + 1:] if "--" in sys.argv else [] + sys.argv = [__file__] + (sys.argv[sys.argv.index("--") + 2:] if "--" in sys.argv else []) + + UnitTesting._extra_arguments = extra_arguments + unittest.main() diff --git a/tests/python/view_layer/test_view_layer_rename.py b/tests/python/view_layer/test_view_layer_rename.py new file mode 100644 index 00000000000..fefb317d0b1 --- /dev/null +++ b/tests/python/view_layer/test_view_layer_rename.py @@ -0,0 +1,33 @@ +# ############################################################ +# Importing - Same For All Render Layer Tests +# ############################################################ + +import unittest +import os +import sys + +from view_layer_common import * + + +# ############################################################ +# Testing +# ############################################################ + +class UnitTesting(ViewLayerTesting): + def test_view_layer_rename(self): + """ + See if we can rename view layers. + """ + import bpy + view_layer = bpy.context.view_layer + print("View layer name: " + view_layer.name) + view_layer.name = "New Name" + + +# ############################################################ +# Main - Same For All Render Layer Tests +# ############################################################ + +if __name__ == '__main__': + UnitTesting._extra_arguments = setup_extra_arguments(__file__) + unittest.main() |