diff options
27 files changed, 378 insertions, 186 deletions
diff --git a/release/scripts/startup/bl_ui/properties_object.py b/release/scripts/startup/bl_ui/properties_object.py index 52af4fafd09..81a641a20cf 100644 --- a/release/scripts/startup/bl_ui/properties_object.py +++ b/release/scripts/startup/bl_ui/properties_object.py @@ -267,7 +267,8 @@ class OBJECT_PT_instancing(ObjectButtonsPanel, Panel): @classmethod def poll(cls, context): ob = context.object - return (ob.type in {'MESH', 'EMPTY', 'POINTCLOUD'}) + # FONT objects need (vertex) instancing for the 'Object Font' feature + return (ob.type in {'MESH', 'EMPTY', 'POINTCLOUD', 'FONT'}) def draw(self, context): layout = self.layout diff --git a/release/scripts/startup/bl_ui/space_sequencer.py b/release/scripts/startup/bl_ui/space_sequencer.py index 30115618f3d..be669b1fe86 100644 --- a/release/scripts/startup/bl_ui/space_sequencer.py +++ b/release/scripts/startup/bl_ui/space_sequencer.py @@ -1659,7 +1659,7 @@ class SEQUENCER_PT_adjust_sound(SequencerButtonsPanel, Panel): def draw(self, context): layout = self.layout - layout.use_property_split = True + layout.use_property_split = False st = context.space_data strip = context.active_sequence_strip @@ -1667,20 +1667,39 @@ class SEQUENCER_PT_adjust_sound(SequencerButtonsPanel, Panel): layout.active = not strip.mute - col = layout.column() - - col.prop(strip, "volume", text="Volume") - col.prop(strip, "pitch") - - col = layout.column() - col.prop(strip, "pan") - col.enabled = sound is not None and sound.use_mono - if sound is not None: col = layout.column() + + split = col.split(factor=0.4) + split.label(text="") + split.prop(sound, "use_mono") if st.waveform_display_type == 'DEFAULT_WAVEFORMS': - col.prop(strip, "show_waveform") - col.prop(sound, "use_mono") + split = col.split(factor=0.4) + split.label(text="") + split.prop(strip, "show_waveform") + + col = layout.column() + + split = col.split(factor=0.4) + split.alignment = 'RIGHT' + split.label(text="Volume") + split.prop(strip, "volume", text="") + + split = col.split(factor=0.4) + split.alignment = 'RIGHT' + split.label(text="Pitch") + split.prop(strip, "pitch", text="") + + split = col.split(factor=0.4) + split.alignment = 'RIGHT' + split.label(text="Pan") + audio_channels = context.scene.render.ffmpeg.audio_channels + pan_text = "" + if audio_channels != 'MONO' and audio_channels != 'STEREO': + pan_text = "%.2f°" % (strip.pan * 90) + split.prop(strip, "pan", text=pan_text) + split.enabled = sound.use_mono and audio_channels != 'MONO' + class SEQUENCER_PT_adjust_comp(SequencerButtonsPanel, Panel): diff --git a/source/blender/blenkernel/intern/brush.c b/source/blender/blenkernel/intern/brush.c index 56c22df3b02..50264f348e9 100644 --- a/source/blender/blenkernel/intern/brush.c +++ b/source/blender/blenkernel/intern/brush.c @@ -148,8 +148,8 @@ static void brush_make_local(Main *bmain, ID *id, const int flags) Brush *brush = (Brush *)id; const bool lib_local = (flags & LIB_ID_MAKELOCAL_FULL_LIBRARY) != 0; - const bool force_local = (flags & LIB_ID_MAKELOCAL_FORCE_LOCAL) != 0; - const bool force_copy = (flags & LIB_ID_MAKELOCAL_FORCE_COPY) != 0; + bool force_local = (flags & LIB_ID_MAKELOCAL_FORCE_LOCAL) != 0; + bool force_copy = (flags & LIB_ID_MAKELOCAL_FORCE_COPY) != 0; BLI_assert(force_copy == false || force_copy != force_local); bool is_local = false, is_lib = false; @@ -166,27 +166,33 @@ static void brush_make_local(Main *bmain, ID *id, const int flags) if (!force_local && !force_copy) { BKE_library_ID_test_usages(bmain, brush, &is_local, &is_lib); + if (lib_local || is_local) { + if (!is_lib) { + force_local = true; + } + else { + force_copy = true; + } + } } - if (lib_local || is_local || force_copy || force_local) { - if (!is_lib || force_local) { - BKE_lib_id_clear_library_data(bmain, &brush->id); - BKE_lib_id_expand_local(bmain, &brush->id); + if (force_local) { + BKE_lib_id_clear_library_data(bmain, &brush->id); + BKE_lib_id_expand_local(bmain, &brush->id); - /* enable fake user by default */ - id_fake_user_set(&brush->id); - } - else { - Brush *brush_new = (Brush *)BKE_id_copy(bmain, &brush->id); /* Ensures FAKE_USER is set */ + /* enable fake user by default */ + id_fake_user_set(&brush->id); + } + else if (force_copy) { + Brush *brush_new = (Brush *)BKE_id_copy(bmain, &brush->id); /* Ensures FAKE_USER is set */ - brush_new->id.us = 0; + brush_new->id.us = 0; - /* setting newid is mandatory for complex make_lib_local logic... */ - ID_NEW_SET(brush, brush_new); + /* setting newid is mandatory for complex make_lib_local logic... */ + ID_NEW_SET(brush, brush_new); - if (!lib_local) { - BKE_libblock_remap(bmain, brush, brush_new, ID_REMAP_SKIP_INDIRECT_USAGE); - } + if (!lib_local) { + BKE_libblock_remap(bmain, brush, brush_new, ID_REMAP_SKIP_INDIRECT_USAGE); } } } diff --git a/source/blender/blenkernel/intern/lib_id.c b/source/blender/blenkernel/intern/lib_id.c index cd0c3635dac..66b83272769 100644 --- a/source/blender/blenkernel/intern/lib_id.c +++ b/source/blender/blenkernel/intern/lib_id.c @@ -411,8 +411,8 @@ void BKE_lib_id_make_local_generic(Main *bmain, ID *id, const int flags) } const bool lib_local = (flags & LIB_ID_MAKELOCAL_FULL_LIBRARY) != 0; - const bool force_local = (flags & LIB_ID_MAKELOCAL_FORCE_LOCAL) != 0; - const bool force_copy = (flags & LIB_ID_MAKELOCAL_FORCE_COPY) != 0; + bool force_local = (flags & LIB_ID_MAKELOCAL_FORCE_LOCAL) != 0; + bool force_copy = (flags & LIB_ID_MAKELOCAL_FORCE_COPY) != 0; BLI_assert(force_copy == false || force_copy != force_local); bool is_local = false, is_lib = false; @@ -426,43 +426,49 @@ void BKE_lib_id_make_local_generic(Main *bmain, ID *id, const int flags) if (!force_copy && !force_local) { BKE_library_ID_test_usages(bmain, id, &is_local, &is_lib); + if (lib_local || is_local) { + if (!is_lib) { + force_local = true; + } + else { + force_copy = true; + } + } } - if (lib_local || is_local || force_copy || force_local) { - if (!is_lib || force_local) { - BKE_lib_id_clear_library_data(bmain, id); - BKE_lib_id_expand_local(bmain, id); - } - else { - ID *id_new = BKE_id_copy(bmain, id); - - /* Should not fail in expected use cases, - * but a few ID types cannot be copied (LIB, WM, SCR...). */ - if (id_new != NULL) { - id_new->us = 0; - - /* setting newid is mandatory for complex make_lib_local logic... */ - ID_NEW_SET(id, id_new); - Key *key = BKE_key_from_id(id), *key_new = BKE_key_from_id(id); - if (key && key_new) { - ID_NEW_SET(key, key_new); - } - bNodeTree *ntree = ntreeFromID(id), *ntree_new = ntreeFromID(id_new); - if (ntree && ntree_new) { - ID_NEW_SET(ntree, ntree_new); - } - if (GS(id->name) == ID_SCE) { - Collection *master_collection = ((Scene *)id)->master_collection, - *master_collection_new = ((Scene *)id_new)->master_collection; - if (master_collection && master_collection_new) { - ID_NEW_SET(master_collection, master_collection_new); - } - } + if (force_local) { + BKE_lib_id_clear_library_data(bmain, id); + BKE_lib_id_expand_local(bmain, id); + } + else if (force_copy) { + ID *id_new = BKE_id_copy(bmain, id); + + /* Should not fail in expected use cases, + * but a few ID types cannot be copied (LIB, WM, SCR...). */ + if (id_new != NULL) { + id_new->us = 0; - if (!lib_local) { - BKE_libblock_remap(bmain, id, id_new, ID_REMAP_SKIP_INDIRECT_USAGE); + /* setting newid is mandatory for complex make_lib_local logic... */ + ID_NEW_SET(id, id_new); + Key *key = BKE_key_from_id(id), *key_new = BKE_key_from_id(id); + if (key && key_new) { + ID_NEW_SET(key, key_new); + } + bNodeTree *ntree = ntreeFromID(id), *ntree_new = ntreeFromID(id_new); + if (ntree && ntree_new) { + ID_NEW_SET(ntree, ntree_new); + } + if (GS(id->name) == ID_SCE) { + Collection *master_collection = ((Scene *)id)->master_collection, + *master_collection_new = ((Scene *)id_new)->master_collection; + if (master_collection && master_collection_new) { + ID_NEW_SET(master_collection, master_collection_new); } } + + if (!lib_local) { + BKE_libblock_remap(bmain, id, id_new, ID_REMAP_SKIP_INDIRECT_USAGE); + } } } } diff --git a/source/blender/blenkernel/intern/object.c b/source/blender/blenkernel/intern/object.c index d0d1db9b4f8..b4343578eab 100644 --- a/source/blender/blenkernel/intern/object.c +++ b/source/blender/blenkernel/intern/object.c @@ -331,8 +331,8 @@ static void object_make_local(Main *bmain, ID *id, const int flags) Object *ob = (Object *)id; const bool lib_local = (flags & LIB_ID_MAKELOCAL_FULL_LIBRARY) != 0; const bool clear_proxy = (flags & LIB_ID_MAKELOCAL_OBJECT_NO_PROXY_CLEARING) == 0; - const bool force_local = (flags & LIB_ID_MAKELOCAL_FORCE_LOCAL) != 0; - const bool force_copy = (flags & LIB_ID_MAKELOCAL_FORCE_COPY) != 0; + bool force_local = (flags & LIB_ID_MAKELOCAL_FORCE_LOCAL) != 0; + bool force_copy = (flags & LIB_ID_MAKELOCAL_FORCE_COPY) != 0; BLI_assert(force_copy == false || force_copy != force_local); bool is_local = false, is_lib = false; @@ -346,32 +346,38 @@ static void object_make_local(Main *bmain, ID *id, const int flags) if (!force_local && !force_copy) { BKE_library_ID_test_usages(bmain, ob, &is_local, &is_lib); + if (lib_local || is_local) { + if (!is_lib) { + force_local = true; + } + else { + force_copy = true; + } + } } - if (lib_local || is_local || force_copy || force_local) { - if (!is_lib || force_local) { - BKE_lib_id_clear_library_data(bmain, &ob->id); - BKE_lib_id_expand_local(bmain, &ob->id); - if (clear_proxy) { - if (ob->proxy_from != NULL) { - ob->proxy_from->proxy = NULL; - ob->proxy_from->proxy_group = NULL; - } - ob->proxy = ob->proxy_from = ob->proxy_group = NULL; + if (force_local) { + BKE_lib_id_clear_library_data(bmain, &ob->id); + BKE_lib_id_expand_local(bmain, &ob->id); + if (clear_proxy) { + if (ob->proxy_from != NULL) { + ob->proxy_from->proxy = NULL; + ob->proxy_from->proxy_group = NULL; } + ob->proxy = ob->proxy_from = ob->proxy_group = NULL; } - else { - Object *ob_new = (Object *)BKE_id_copy(bmain, &ob->id); - id_us_min(&ob_new->id); + } + else if (force_copy) { + Object *ob_new = (Object *)BKE_id_copy(bmain, &ob->id); + id_us_min(&ob_new->id); - ob_new->proxy = ob_new->proxy_from = ob_new->proxy_group = NULL; + ob_new->proxy = ob_new->proxy_from = ob_new->proxy_group = NULL; - /* setting newid is mandatory for complex make_lib_local logic... */ - ID_NEW_SET(ob, ob_new); + /* setting newid is mandatory for complex make_lib_local logic... */ + ID_NEW_SET(ob, ob_new); - if (!lib_local) { - BKE_libblock_remap(bmain, ob, ob_new, ID_REMAP_SKIP_INDIRECT_USAGE); - } + if (!lib_local) { + BKE_libblock_remap(bmain, ob, ob_new, ID_REMAP_SKIP_INDIRECT_USAGE); } } } @@ -5312,7 +5318,7 @@ KDTree_3d *BKE_object_as_kdtree(Object *ob, int *r_tot) unsigned int i; Mesh *me_eval = ob->runtime.mesh_deform_eval ? ob->runtime.mesh_deform_eval : - ob->runtime.mesh_deform_eval; + BKE_object_get_evaluated_mesh(ob); const int *index; if (me_eval && (index = CustomData_get_layer(&me_eval->vdata, CD_ORIGINDEX))) { diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c index 3e9ea8db758..9704e8bb413 100644 --- a/source/blender/blenloader/intern/readfile.c +++ b/source/blender/blenloader/intern/readfile.c @@ -4500,7 +4500,8 @@ static void add_loose_objects_to_scene(Main *mainvar, * or for a collection when *lib has been set. */ LISTBASE_FOREACH (Object *, ob, &mainvar->objects) { bool do_it = (ob->id.tag & LIB_TAG_DOIT) != 0; - if (do_it || ((ob->id.tag & LIB_TAG_INDIRECT) && (ob->id.tag & LIB_TAG_PRE_EXISTING) == 0)) { + if (do_it || + ((ob->id.tag & LIB_TAG_INDIRECT) != 0 && (ob->id.tag & LIB_TAG_PRE_EXISTING) == 0)) { if (do_append) { if (ob->id.us == 0) { do_it = true; @@ -4648,7 +4649,7 @@ static void add_collections_to_scene(Main *mainvar, LISTBASE_FOREACH (CollectionObject *, coll_ob, &collection->gobject) { Object *ob = coll_ob->ob; if ((ob->id.tag & (LIB_TAG_PRE_EXISTING | LIB_TAG_DOIT | LIB_TAG_INDIRECT)) == 0 && - (ob->id.lib == lib) && (object_in_any_scene(bmain, ob) == 0)) { + (ob->id.lib == lib) && (object_in_any_scene(bmain, ob) == false)) { do_add_collection = true; break; } diff --git a/source/blender/editors/gizmo_library/CMakeLists.txt b/source/blender/editors/gizmo_library/CMakeLists.txt index eeb1e60166b..bfe8334b390 100644 --- a/source/blender/editors/gizmo_library/CMakeLists.txt +++ b/source/blender/editors/gizmo_library/CMakeLists.txt @@ -27,6 +27,7 @@ set(INC ../../makesdna ../../makesrna ../../windowmanager + ../../../../intern/clog ../../../../intern/eigen ../../../../intern/glew-mx ../../../../intern/guardedalloc diff --git a/source/blender/editors/gizmo_library/gizmo_library_utils.c b/source/blender/editors/gizmo_library/gizmo_library_utils.c index 7d0ae5afb9b..a0db2a8e627 100644 --- a/source/blender/editors/gizmo_library/gizmo_library_utils.c +++ b/source/blender/editors/gizmo_library/gizmo_library_utils.c @@ -39,9 +39,13 @@ #include "ED_view3d.h" +#include "CLG_log.h" + /* own includes */ #include "gizmo_library_intern.h" +static CLG_LogRef LOG = {"ed.gizmo.library_utils"}; + /* factor for precision tweaking */ #define GIZMO_PRECISION_FAC 0.05f @@ -182,7 +186,7 @@ bool gizmo_window_project_2d(bContext *C, bool use_offset, float r_co[2]) { - float mat[4][4]; + float mat[4][4], imat[4][4]; { float mat_identity[4][4]; struct WM_GizmoMatrixParams params = {NULL}; @@ -193,6 +197,14 @@ bool gizmo_window_project_2d(bContext *C, WM_gizmo_calc_matrix_final_params(gz, ¶ms, mat); } + if (!invert_m4_m4(imat, mat)) { + CLOG_WARN(&LOG, + "Gizmo \"%s\" of group \"%s\" has matrix that could not be inverted " + "(projection will fail)", + gz->type->idname, + gz->parent_gzgroup->type->idname); + } + /* rotate mouse in relation to the center and relocate it */ if (gz->parent_gzgroup->type->flag & WM_GIZMOGROUPTYPE_3D) { /* For 3d views, transform 2D mouse pos onto plane. */ @@ -202,8 +214,6 @@ bool gizmo_window_project_2d(bContext *C, plane_from_point_normal_v3(plane, mat[3], mat[2]); bool clip_ray = ((RegionView3D *)region->regiondata)->is_persp; if (ED_view3d_win_to_3d_on_plane(region, plane, mval, clip_ray, co)) { - float imat[4][4]; - invert_m4_m4(imat, mat); mul_m4_v3(imat, co); r_co[0] = co[(axis + 1) % 3]; r_co[1] = co[(axis + 2) % 3]; @@ -213,8 +223,6 @@ bool gizmo_window_project_2d(bContext *C, } float co[3] = {mval[0], mval[1], 0.0f}; - float imat[4][4]; - invert_m4_m4(imat, mat); mul_m4_v3(imat, co); copy_v2_v2(r_co, co); return true; @@ -223,7 +231,7 @@ bool gizmo_window_project_2d(bContext *C, bool gizmo_window_project_3d( bContext *C, const struct wmGizmo *gz, const float mval[2], bool use_offset, float r_co[3]) { - float mat[4][4]; + float mat[4][4], imat[4][4]; { float mat_identity[4][4]; struct WM_GizmoMatrixParams params = {NULL}; @@ -234,20 +242,25 @@ bool gizmo_window_project_3d( WM_gizmo_calc_matrix_final_params(gz, ¶ms, mat); } + if (!invert_m4_m4(imat, mat)) { + CLOG_WARN(&LOG, + "Gizmo \"%s\" of group \"%s\" has matrix that could not be inverted " + "(projection will fail)", + gz->type->idname, + gz->parent_gzgroup->type->idname); + } + if (gz->parent_gzgroup->type->flag & WM_GIZMOGROUPTYPE_3D) { View3D *v3d = CTX_wm_view3d(C); ARegion *region = CTX_wm_region(C); /* NOTE: we might want a custom reference point passed in, * instead of the gizmo center. */ ED_view3d_win_to_3d(v3d, region, mat[3], mval, r_co); - invert_m4(mat); - mul_m4_v3(mat, r_co); + mul_m4_v3(imat, r_co); return true; } float co[3] = {mval[0], mval[1], 0.0f}; - float imat[4][4]; - invert_m4_m4(imat, mat); mul_m4_v3(imat, co); copy_v2_v2(r_co, co); return true; diff --git a/source/blender/editors/space_view3d/view3d_view.c b/source/blender/editors/space_view3d/view3d_view.c index b9f3706b084..a6dd95cac04 100644 --- a/source/blender/editors/space_view3d/view3d_view.c +++ b/source/blender/editors/space_view3d/view3d_view.c @@ -137,7 +137,6 @@ void ED_view3d_smooth_view_ex( { RegionView3D *rv3d = region->regiondata; struct SmoothView3DStore sms = {{0}}; - bool ok = false; /* initialize sms */ view3d_smooth_view_state_backup(&sms.dst, v3d, rv3d); @@ -200,29 +199,30 @@ void ED_view3d_smooth_view_ex( sms.to_camera = true; /* restore view3d values in end */ } - /* skip smooth viewing for external render engine draw */ - if (smooth_viewtx && !(v3d->shading.type == OB_RENDER && rv3d->render_engine)) { - bool changed = false; /* zero means no difference */ + bool changed = false; /* zero means no difference */ - if (sview->camera_old != sview->camera) { - changed = true; - } - else if (sms.dst.dist != rv3d->dist) { - changed = true; - } - else if (sms.dst.lens != v3d->lens) { - changed = true; - } - else if (!equals_v3v3(sms.dst.ofs, rv3d->ofs)) { - changed = true; - } - else if (!equals_v4v4(sms.dst.quat, rv3d->viewquat)) { - changed = true; - } + if (sview->camera_old != sview->camera) { + changed = true; + } + else if (sms.dst.dist != rv3d->dist) { + changed = true; + } + else if (sms.dst.lens != v3d->lens) { + changed = true; + } + else if (!equals_v3v3(sms.dst.ofs, rv3d->ofs)) { + changed = true; + } + else if (!equals_v4v4(sms.dst.quat, rv3d->viewquat)) { + changed = true; + } + + /* The new view is different from the previous state. */ + if (changed) { + + /* Skip smooth viewing for external render engine draw. */ + if (smooth_viewtx && !(v3d->shading.type == OB_RENDER && rv3d->render_engine)) { - /* The new view is different from the old one - * so animate the view */ - if (changed) { /* original values */ if (sview->camera_old) { Object *ob_camera_old_eval = DEG_get_evaluated_object(depsgraph, sview->camera_old); @@ -279,27 +279,25 @@ void ED_view3d_smooth_view_ex( } /* #TIMER1 is hard-coded in key-map. */ rv3d->smooth_timer = WM_event_add_timer(wm, win, TIMER1, 1.0 / 100.0); - - ok = true; } - } + else { + if (sms.to_camera == false) { + copy_v3_v3(rv3d->ofs, sms.dst.ofs); + copy_qt_qt(rv3d->viewquat, sms.dst.quat); + rv3d->dist = sms.dst.dist; + v3d->lens = sms.dst.lens; - /* if we get here nothing happens */ - if (ok == false) { - if (sms.to_camera == false) { - copy_v3_v3(rv3d->ofs, sms.dst.ofs); - copy_qt_qt(rv3d->viewquat, sms.dst.quat); - rv3d->dist = sms.dst.dist; - v3d->lens = sms.dst.lens; + ED_view3d_camera_lock_sync(depsgraph, v3d, rv3d); + } - ED_view3d_camera_lock_sync(depsgraph, v3d, rv3d); - } + if (RV3D_LOCK_FLAGS(rv3d) & RV3D_BOXVIEW) { + view3d_boxview_copy(area, region); + } - if (RV3D_LOCK_FLAGS(rv3d) & RV3D_BOXVIEW) { - view3d_boxview_copy(area, region); - } + ED_region_tag_redraw(region); - ED_region_tag_redraw(region); + WM_event_add_mousemove(win); + } } } @@ -320,6 +318,7 @@ void ED_view3d_smooth_view(bContext *C, /* only meant for timer usage */ static void view3d_smoothview_apply(bContext *C, View3D *v3d, ARegion *region, bool sync_boxview) { + wmWindowManager *wm = CTX_wm_manager(C); RegionView3D *rv3d = region->regiondata; struct SmoothView3DStore *sms = rv3d->sms; float step, step_inv; @@ -333,6 +332,7 @@ static void view3d_smoothview_apply(bContext *C, View3D *v3d, ARegion *region, b /* end timer */ if (step >= 1.0f) { + wmWindow *win = CTX_wm_window(C); /* if we went to camera, store the original */ if (sms->to_camera) { @@ -355,9 +355,12 @@ static void view3d_smoothview_apply(bContext *C, View3D *v3d, ARegion *region, b MEM_freeN(rv3d->sms); rv3d->sms = NULL; - WM_event_remove_timer(CTX_wm_manager(C), CTX_wm_window(C), rv3d->smooth_timer); + WM_event_remove_timer(wm, win, rv3d->smooth_timer); rv3d->smooth_timer = NULL; rv3d->rflag &= ~RV3D_NAVIGATING; + + /* Event handling won't know if a UI item has been moved under the pointer. */ + WM_event_add_mousemove(win); } else { /* ease in/out */ @@ -380,12 +383,9 @@ static void view3d_smoothview_apply(bContext *C, View3D *v3d, ARegion *region, b const Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C); ED_view3d_camera_lock_sync(depsgraph, v3d, rv3d); - if (ED_screen_animation_playing(CTX_wm_manager(C))) { + if (ED_screen_animation_playing(wm)) { ED_view3d_camera_lock_autokey(v3d, rv3d, C, true, true); } - - /* Event handling won't know if a UI item has been moved under the pointer. */ - WM_event_add_mousemove(CTX_wm_window(C)); } if (sync_boxview && (RV3D_LOCK_FLAGS(rv3d) & RV3D_BOXVIEW)) { diff --git a/source/blender/functions/intern/field.cc b/source/blender/functions/intern/field.cc index 06730a8b830..f680c7ba5ff 100644 --- a/source/blender/functions/intern/field.cc +++ b/source/blender/functions/intern/field.cc @@ -24,6 +24,8 @@ #include "FN_field.hh" #include "FN_multi_function_parallel.hh" +#include "FN_field.hh" + namespace blender::fn { /* -------------------------------------------------------------------- @@ -185,8 +187,8 @@ static void build_multi_function_procedure_for_fields(MFProcedure &procedure, const Span<GField> operation_inputs = operation.inputs(); if (field_with_index.current_input_index < operation_inputs.size()) { - /* Not all inputs are handled yet. Push the next input field to the stack and increment the - * input index. */ + /* Not all inputs are handled yet. Push the next input field to the stack and increment + * the input index. */ fields_to_check.push({operation_inputs[field_with_index.current_input_index]}); field_with_index.current_input_index++; } @@ -250,8 +252,8 @@ struct PartiallyInitializedArray : NonCopyable, NonMovable { }; /** - * Evaluate fields in the given context. If possible, multiple fields should be evaluated together, - * because that can be more efficient when they share common sub-fields. + * Evaluate fields in the given context. If possible, multiple fields should be evaluated + * together, because that can be more efficient when they share common sub-fields. * * \param scope: The resource scope that owns data that makes up the output virtual arrays. Make * sure the scope is not destructed when the output virtual arrays are still used. @@ -294,8 +296,8 @@ Vector<const GVArray *> evaluate_fields(ResourceScope &scope, Vector<const GVArray *> field_context_inputs = get_field_context_inputs( scope, mask, context, field_tree_info.deduplicated_field_inputs); - /* Finish fields that output an input varray directly. For those we don't have to do any further - * processing. */ + /* Finish fields that output an input varray directly. For those we don't have to do any + * further processing. */ for (const int out_index : fields_to_evaluate.index_range()) { const GFieldRef &field = fields_to_evaluate[out_index]; if (!field.node().is_input()) { @@ -426,8 +428,8 @@ Vector<const GVArray *> evaluate_fields(ResourceScope &scope, procedure_executor.call(IndexRange(1), mf_params, mf_context); } - /* Copy data to supplied destination arrays if necessary. In some cases the evaluation above has - * written the computed data in the right place already. */ + /* Copy data to supplied destination arrays if necessary. In some cases the evaluation above + * has written the computed data in the right place already. */ if (!dst_varrays.is_empty()) { for (const int out_index : fields_to_evaluate.index_range()) { GVMutableArray *output_varray = get_dst_varray_if_available(out_index); diff --git a/source/blender/io/alembic/exporter/abc_writer_abstract.cc b/source/blender/io/alembic/exporter/abc_writer_abstract.cc index 910e04f3bf5..3665494c046 100644 --- a/source/blender/io/alembic/exporter/abc_writer_abstract.cc +++ b/source/blender/io/alembic/exporter/abc_writer_abstract.cc @@ -118,7 +118,7 @@ void ABCAbstractWriter::update_bounding_box(Object *object) if (!bb) { if (object->type != OB_CAMERA) { - CLOG_WARN(&LOG, "Bounding box is null!\n"); + CLOG_WARN(&LOG, "Bounding box is null!"); } bounding_box_.min.x = bounding_box_.min.y = bounding_box_.min.z = 0; bounding_box_.max.x = bounding_box_.max.y = bounding_box_.max.z = 0; diff --git a/source/blender/makesdna/DNA_modifier_types.h b/source/blender/makesdna/DNA_modifier_types.h index 13213f70fed..8520786a030 100644 --- a/source/blender/makesdna/DNA_modifier_types.h +++ b/source/blender/makesdna/DNA_modifier_types.h @@ -1942,6 +1942,7 @@ typedef struct MeshCacheModifierData { float factor; char deform_mode; + char defgrp_name[64]; char _pad[7]; /* play_mode == MOD_MESHCACHE_PLAY_CFEA */ @@ -1958,6 +1959,11 @@ typedef struct MeshCacheModifierData { char filepath[1024]; } MeshCacheModifierData; +/* MeshCache modifier flags. */ +enum { + MOD_MESHCACHE_INVERT_VERTEX_GROUP = 1 << 0, +}; + enum { MOD_MESHCACHE_TYPE_MDD = 1, MOD_MESHCACHE_TYPE_PC2 = 2, diff --git a/source/blender/makesrna/intern/rna_access_compare_override.c b/source/blender/makesrna/intern/rna_access_compare_override.c index 2c552970c82..f8a36c1b2e6 100644 --- a/source/blender/makesrna/intern/rna_access_compare_override.c +++ b/source/blender/makesrna/intern/rna_access_compare_override.c @@ -788,7 +788,7 @@ bool RNA_struct_override_matches(Main *bmain, continue; } - CLOG_INFO(&LOG, 5, "Override Checking %s\n", rna_path); + CLOG_INFO(&LOG, 5, "Override Checking %s", rna_path); IDOverrideLibraryProperty *op = BKE_lib_override_library_property_find(override, rna_path); if (ignore_overridden && op != NULL) { diff --git a/source/blender/makesrna/intern/rna_modifier.c b/source/blender/makesrna/intern/rna_modifier.c index f11d845c582..fb4fd4528d6 100644 --- a/source/blender/makesrna/intern/rna_modifier.c +++ b/source/blender/makesrna/intern/rna_modifier.c @@ -755,6 +755,7 @@ RNA_MOD_VGROUP_NAME_SET(LaplacianDeform, anchor_grp_name); RNA_MOD_VGROUP_NAME_SET(LaplacianSmooth, defgrp_name); RNA_MOD_VGROUP_NAME_SET(Lattice, name); RNA_MOD_VGROUP_NAME_SET(Mask, vgroup); +RNA_MOD_VGROUP_NAME_SET(MeshCache, defgrp_name); RNA_MOD_VGROUP_NAME_SET(MeshDeform, defgrp_name); RNA_MOD_VGROUP_NAME_SET(NormalEdit, defgrp_name); RNA_MOD_VGROUP_NAME_SET(Shrinkwrap, vgroup_name); @@ -6045,6 +6046,20 @@ static void rna_def_modifier_meshcache(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Influence", "Influence of the deformation"); RNA_def_property_update(prop, 0, "rna_Modifier_update"); + prop = RNA_def_property(srna, "vertex_group", PROP_STRING, PROP_NONE); + RNA_def_property_string_sdna(prop, NULL, "defgrp_name"); + RNA_def_property_ui_text( + prop, + "Vertex Group", + "Name of the Vertex Group which determines the influence of the modifier per point"); + RNA_def_property_string_funcs(prop, NULL, NULL, "rna_MeshCacheModifier_defgrp_name_set"); + RNA_def_property_update(prop, 0, "rna_Modifier_update"); + + prop = RNA_def_property(srna, "invert_vertex_group", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", MOD_MESHCACHE_INVERT_VERTEX_GROUP); + RNA_def_property_ui_text(prop, "Invert", "Invert vertex group influence"); + RNA_def_property_update(prop, 0, "rna_Modifier_update"); + /* -------------------------------------------------------------------- */ /* Axis Conversion */ prop = RNA_def_property(srna, "forward_axis", PROP_ENUM, PROP_NONE); diff --git a/source/blender/makesrna/intern/rna_object.c b/source/blender/makesrna/intern/rna_object.c index d3cd3158db1..99865078cbe 100644 --- a/source/blender/makesrna/intern/rna_object.c +++ b/source/blender/makesrna/intern/rna_object.c @@ -224,6 +224,12 @@ static EnumPropertyItem instance_items_empty[] = { INSTANCE_ITEM_COLLECTION, {0, NULL, 0, NULL, NULL}, }; + +static EnumPropertyItem instance_items_font[] = { + {0, "NONE", 0, "None", ""}, + {OB_DUPLIVERTS, "VERTS", 0, "Vertices", "Use Object Font on characters"}, + {0, NULL, 0, NULL, NULL}, +}; #endif #undef INSTANCE_ITEMS_SHARED #undef INSTANCE_ITEM_COLLECTION @@ -762,6 +768,9 @@ static const EnumPropertyItem *rna_Object_instance_type_itemf(bContext *UNUSED(C else if (ob->type == OB_POINTCLOUD) { item = instance_items_pointcloud; } + else if (ob->type == OB_FONT) { + item = instance_items_font; + } else { item = instance_items_nogroup; } diff --git a/source/blender/makesrna/intern/rna_sequencer.c b/source/blender/makesrna/intern/rna_sequencer.c index d9837f21833..cd87e4d10c1 100644 --- a/source/blender/makesrna/intern/rna_sequencer.c +++ b/source/blender/makesrna/intern/rna_sequencer.c @@ -845,6 +845,17 @@ static void rna_Sequence_audio_update(Main *UNUSED(bmain), Scene *scene, Pointer DEG_id_tag_update(&scene->id, ID_RECALC_SEQUENCER_STRIPS); } +static void rna_Sequence_pan_range( + PointerRNA *ptr, float *min, float *max, float *softmin, float *softmax) +{ + Scene *scene = (Scene *)ptr->owner_id; + + *min = -FLT_MAX; + *max = FLT_MAX; + *softmax = 1 + (int)(scene->r.ffcodecdata.audio_channels > 2); + *softmin = -*softmax; +} + static int rna_Sequence_input_count_get(PointerRNA *ptr) { Sequence *seq = (Sequence *)(ptr->data); @@ -2559,8 +2570,10 @@ static void rna_def_sound(BlenderRNA *brna) prop = RNA_def_property(srna, "pan", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "pan"); - RNA_def_property_range(prop, -2.0f, 2.0f); + RNA_def_property_range(prop, -FLT_MAX, FLT_MAX); + RNA_def_property_ui_range(prop, -2, 2, 1, 2); RNA_def_property_ui_text(prop, "Pan", "Playback panning of the sound (only for Mono sources)"); + RNA_def_property_float_funcs(prop, NULL, NULL, "rna_Sequence_pan_range"); RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_audio_update"); prop = RNA_def_property(srna, "show_waveform", PROP_BOOLEAN, PROP_NONE); diff --git a/source/blender/modifiers/intern/MOD_meshcache.c b/source/blender/modifiers/intern/MOD_meshcache.c index 6ef64ad8bc9..74f9887a973 100644 --- a/source/blender/modifiers/intern/MOD_meshcache.c +++ b/source/blender/modifiers/intern/MOD_meshcache.c @@ -36,8 +36,11 @@ #include "DNA_screen_types.h" #include "BKE_context.h" +#include "BKE_deform.h" +#include "BKE_lib_id.h" #include "BKE_main.h" #include "BKE_mesh.h" +#include "BKE_mesh_wrapper.h" #include "BKE_scene.h" #include "BKE_screen.h" @@ -53,6 +56,7 @@ #include "MOD_meshcache_util.h" /* utility functions */ #include "MOD_modifiertypes.h" #include "MOD_ui_common.h" +#include "MOD_util.h" static void initData(ModifierData *md) { @@ -84,11 +88,16 @@ static bool isDisabled(const struct Scene *UNUSED(scene), static void meshcache_do(MeshCacheModifierData *mcmd, Scene *scene, Object *ob, + Mesh *mesh, float (*vertexCos_Real)[3], int numVerts) { const bool use_factor = mcmd->factor < 1.0f; - float(*vertexCos_Store)[3] = (use_factor || + int influence_group_index; + MDeformVert *dvert; + MOD_get_vgroup(ob, mesh, mcmd->defgrp_name, &dvert, &influence_group_index); + + float(*vertexCos_Store)[3] = (use_factor || influence_group_index != -1 || (mcmd->deform_mode == MOD_MESHCACHE_DEFORM_INTEGRATE)) ? MEM_malloc_arrayN( numVerts, sizeof(*vertexCos_Store), __func__) : @@ -256,7 +265,29 @@ static void meshcache_do(MeshCacheModifierData *mcmd, if (vertexCos_Store) { if (ok) { - if (use_factor) { + if (influence_group_index != -1) { + const float global_factor = (mcmd->flag & MOD_MESHCACHE_INVERT_VERTEX_GROUP) ? + -mcmd->factor : + mcmd->factor; + const float global_offset = (mcmd->flag & MOD_MESHCACHE_INVERT_VERTEX_GROUP) ? + mcmd->factor : + 0.0f; + if (mesh->dvert != NULL) { + for (int i = 0; i < numVerts; i++) { + /* For each vertex, compute its blending factor between the mesh cache (for `fac = 0`) + * and the former position of the vertex (for `fac = 1`). */ + const MDeformVert *currentIndexDVert = dvert + i; + const float local_vertex_fac = global_offset + + BKE_defvert_find_weight(currentIndexDVert, + influence_group_index) * + global_factor; + interp_v3_v3v3( + vertexCos_Real[i], vertexCos_Real[i], vertexCos_Store[i], local_vertex_fac); + } + } + } + else if (use_factor) { + /* Influence_group_index is -1. */ interp_vn_vn(*vertexCos_Real, *vertexCos_Store, mcmd->factor, numVerts * 3); } else { @@ -270,34 +301,59 @@ static void meshcache_do(MeshCacheModifierData *mcmd, static void deformVerts(ModifierData *md, const ModifierEvalContext *ctx, - Mesh *UNUSED(mesh), + Mesh *mesh, float (*vertexCos)[3], int numVerts) { MeshCacheModifierData *mcmd = (MeshCacheModifierData *)md; Scene *scene = DEG_get_evaluated_scene(ctx->depsgraph); - meshcache_do(mcmd, scene, ctx->object, vertexCos, numVerts); + Mesh *mesh_src = NULL; + + if (ctx->object->type == OB_MESH && mcmd->defgrp_name[0] != '\0') { + /* `mesh_src` is only needed for vertex groups. */ + mesh_src = MOD_deform_mesh_eval_get(ctx->object, NULL, mesh, NULL, numVerts, false, false); + } + meshcache_do(mcmd, scene, ctx->object, mesh_src, vertexCos, numVerts); + + if (!ELEM(mesh_src, NULL, mesh)) { + BKE_id_free(NULL, mesh_src); + } } static void deformVertsEM(ModifierData *md, const ModifierEvalContext *ctx, - struct BMEditMesh *UNUSED(editData), - Mesh *UNUSED(mesh), + struct BMEditMesh *editData, + Mesh *mesh, float (*vertexCos)[3], int numVerts) { MeshCacheModifierData *mcmd = (MeshCacheModifierData *)md; Scene *scene = DEG_get_evaluated_scene(ctx->depsgraph); - meshcache_do(mcmd, scene, ctx->object, vertexCos, numVerts); + Mesh *mesh_src = NULL; + + if (ctx->object->type == OB_MESH && mcmd->defgrp_name[0] != '\0') { + /* `mesh_src` is only needed for vertex groups. */ + mesh_src = MOD_deform_mesh_eval_get(ctx->object, editData, mesh, NULL, numVerts, false, false); + } + if (mesh_src != NULL) { + BKE_mesh_wrapper_ensure_mdata(mesh_src); + } + + meshcache_do(mcmd, scene, ctx->object, mesh_src, vertexCos, numVerts); + + if (!ELEM(mesh_src, NULL, mesh)) { + BKE_id_free(NULL, mesh_src); + } } static void panel_draw(const bContext *UNUSED(C), Panel *panel) { uiLayout *layout = panel->layout; - PointerRNA *ptr = modifier_panel_get_property_pointers(panel, NULL); + PointerRNA ob_ptr; + PointerRNA *ptr = modifier_panel_get_property_pointers(panel, &ob_ptr); uiLayoutSetPropSep(layout, true); @@ -307,6 +363,7 @@ static void panel_draw(const bContext *UNUSED(C), Panel *panel) uiItemR(layout, ptr, "factor", UI_ITEM_R_SLIDER, NULL, ICON_NONE); uiItemR(layout, ptr, "deform_mode", 0, NULL, ICON_NONE); uiItemR(layout, ptr, "interpolation", 0, NULL, ICON_NONE); + modifier_vgroup_ui(layout, ptr, &ob_ptr, "vertex_group", "invert_vertex_group", NULL); modifier_panel_end(layout, ptr); } diff --git a/source/blender/modifiers/intern/MOD_nodes.cc b/source/blender/modifiers/intern/MOD_nodes.cc index 10237ac13c7..ba557c3976c 100644 --- a/source/blender/modifiers/intern/MOD_nodes.cc +++ b/source/blender/modifiers/intern/MOD_nodes.cc @@ -330,8 +330,8 @@ static IDProperty *id_property_create_from_socket(const bNodeSocket &socket) ui_data->max = ui_data->soft_max = (double)value->max; ui_data->default_array = (double *)MEM_mallocN(sizeof(double[3]), "mod_prop_default"); ui_data->default_array_len = 3; - for (int i = 3; i < 3; i++) { - ui_data->default_array[i] = (double)value->value[i]; + for (const int i : IndexRange(3)) { + ui_data->default_array[i] = double(value->value[i]); } return property; } diff --git a/source/blender/python/generic/idprop_py_ui_api.c b/source/blender/python/generic/idprop_py_ui_api.c index 42856d88472..7827bd48dfe 100644 --- a/source/blender/python/generic/idprop_py_ui_api.c +++ b/source/blender/python/generic/idprop_py_ui_api.c @@ -468,7 +468,7 @@ static void idprop_ui_data_to_dict_int(IDProperty *property, PyObject *dict) Py_DECREF(list); } else { - PyDict_SetItemString(dict, "default", item = PyLong_FromLong(ui_data->step)); + PyDict_SetItemString(dict, "default", item = PyLong_FromLong(ui_data->default_value)); Py_DECREF(item); } } @@ -499,7 +499,7 @@ static void idprop_ui_data_to_dict_float(IDProperty *property, PyObject *dict) Py_DECREF(list); } else { - PyDict_SetItemString(dict, "default", item = PyFloat_FromDouble(ui_data->step)); + PyDict_SetItemString(dict, "default", item = PyFloat_FromDouble(ui_data->default_value)); Py_DECREF(item); } } diff --git a/source/blender/python/gpu/gpu_py_buffer.c b/source/blender/python/gpu/gpu_py_buffer.c index 0fef59d6352..abfde7b48c8 100644 --- a/source/blender/python/gpu/gpu_py_buffer.c +++ b/source/blender/python/gpu/gpu_py_buffer.c @@ -485,7 +485,7 @@ static int pygpu_buffer__sq_ass_item(BPyGPUBuffer *self, int i, PyObject *v) case GPU_DATA_UINT: case GPU_DATA_UINT_24_8: case GPU_DATA_10_11_11_REV: - return PyArg_Parse(v, "b:Expected ints", &self->buf.as_uint[i]) ? 0 : -1; + return PyArg_Parse(v, "I:Expected unsigned ints", &self->buf.as_uint[i]) ? 0 : -1; default: return 0; /* should never happen */ } diff --git a/source/blender/python/intern/bpy_interface.c b/source/blender/python/intern/bpy_interface.c index 68731a91dc9..7a93a076621 100644 --- a/source/blender/python/intern/bpy_interface.c +++ b/source/blender/python/intern/bpy_interface.c @@ -753,7 +753,7 @@ int BPY_context_member_get(bContext *C, const char *member, bContextDataResult * CLOG_INFO(BPY_LOG_CONTEXT, 1, "'%s' not a valid type", member); } else { - CLOG_INFO(BPY_LOG_CONTEXT, 1, "'%s' not found\n", member); + CLOG_INFO(BPY_LOG_CONTEXT, 1, "'%s' not found", member); } } else { diff --git a/source/blender/windowmanager/intern/wm_event_system.c b/source/blender/windowmanager/intern/wm_event_system.c index 1f47b152a2b..83a9a6c6383 100644 --- a/source/blender/windowmanager/intern/wm_event_system.c +++ b/source/blender/windowmanager/intern/wm_event_system.c @@ -3749,7 +3749,7 @@ wmKeyMap *WM_event_get_keymap_from_toolsystem_fallback(wmWindowManager *wm, const char *keymap_id = NULL; /* Support for the gizmo owning the tool keymap. */ - if (tref_rt->gizmo_group[0] != '\0' && tref_rt->keymap_fallback[0] != '\n') { + if (tref_rt->gizmo_group[0] != '\0' && tref_rt->keymap_fallback[0] != '\0') { wmGizmoMap *gzmap = NULL; wmGizmoGroup *gzgroup = NULL; LISTBASE_FOREACH (ARegion *, region, &area->regionbase) { diff --git a/source/blender/windowmanager/xr/intern/wm_xr_session.c b/source/blender/windowmanager/xr/intern/wm_xr_session.c index dc15b579e9d..88bf3ff453c 100644 --- a/source/blender/windowmanager/xr/intern/wm_xr_session.c +++ b/source/blender/windowmanager/xr/intern/wm_xr_session.c @@ -705,7 +705,7 @@ bool wm_xr_session_surface_offscreen_ensure(wmXrSurfaceData *surface_data, } if (failure) { - CLOG_ERROR(&LOG, "Failed to get buffer, %s\n", err_out); + CLOG_ERROR(&LOG, "Failed to get buffer, %s", err_out); return false; } diff --git a/tests/performance/api/config.py b/tests/performance/api/config.py index d3a79eede14..b5e2b390aa3 100644 --- a/tests/performance/api/config.py +++ b/tests/performance/api/config.py @@ -25,6 +25,7 @@ class TestEntry: category: str = '' revision: str = '' git_hash: str = '' + environment: Dict = field(default_factory=dict) executable: str = '' date: int = 0 device_type: str = 'CPU' @@ -160,7 +161,13 @@ class TestConfig: def read_blender_executables(env, name) -> List: config = TestConfig._read_config_module(env.base_dir / name) builds = getattr(config, 'builds', {}) - return [pathlib.Path(build) for build in builds.values()] + executables = [] + + for executable in builds.values(): + executable, _ = TestConfig._split_environment_variables(executable) + executables.append(pathlib.Path(executable)) + + return executables @staticmethod def _read_config_module(base_dir: pathlib.Path) -> None: @@ -191,9 +198,10 @@ class TestConfig: # Get entries for specified commits, tags and branches. for revision_name, revision_commit in self.revisions.items(): + revision_commit, environment = self._split_environment_variables(revision_commit) git_hash = env.resolve_git_hash(revision_commit) date = env.git_hash_date(git_hash) - entries += self._get_entries(revision_name, git_hash, '', date) + entries += self._get_entries(revision_name, git_hash, '', environment, date) # Optimization to avoid rebuilds. revisions_to_build = set() @@ -204,6 +212,7 @@ class TestConfig: # Get entries for revisions based on existing builds. for revision_name, executable in self.builds.items(): + executable, environment = self._split_environment_variables(executable) executable_path = env._blender_executable_from_path(pathlib.Path(executable)) if not executable_path: sys.stderr.write(f'Error: build {executable} not found\n') @@ -214,7 +223,7 @@ class TestConfig: env.set_default_blender_executable() mtime = executable_path.stat().st_mtime - entries += self._get_entries(revision_name, git_hash, executable, mtime) + entries += self._get_entries(revision_name, git_hash, executable, environment, mtime) # Detect number of categories for more compact printing. categories = set() @@ -229,6 +238,7 @@ class TestConfig: revision_name: str, git_hash: str, executable: pathlib.Path, + environment: str, date: int) -> None: entries = [] for test in self.tests.tests: @@ -241,10 +251,12 @@ class TestConfig: # Test if revision hash or executable changed. if entry.git_hash != git_hash or \ entry.executable != executable or \ + entry.environment != environment or \ entry.benchmark_type != self.benchmark_type or \ entry.date != date: # Update existing entry. entry.git_hash = git_hash + entry.environment = environment entry.executable = executable entry.benchmark_type = self.benchmark_type entry.date = date @@ -256,6 +268,7 @@ class TestConfig: revision=revision_name, git_hash=git_hash, executable=executable, + environment=environment, date=date, test=test_name, category=test_category, @@ -266,3 +279,10 @@ class TestConfig: entries.append(entry) return entries + + @staticmethod + def _split_environment_variables(revision): + if isinstance(revision, str): + return revision, {} + else: + return revision[0], revision[1] diff --git a/tests/performance/api/environment.py b/tests/performance/api/environment.py index 76c731b6118..750d991ebc8 100644 --- a/tests/performance/api/environment.py +++ b/tests/performance/api/environment.py @@ -104,9 +104,10 @@ class TestEnvironment: self._init_default_blender_executable() return True - def set_blender_executable(self, executable_path: pathlib.Path) -> None: + def set_blender_executable(self, executable_path: pathlib.Path, environment: Dict = {}) -> None: # Run all Blender commands with this executable. self.blender_executable = executable_path + self.blender_executable_environment = environment def _blender_executable_name(self) -> pathlib.Path: if platform.system() == "Windows": @@ -150,6 +151,7 @@ class TestEnvironment: def set_default_blender_executable(self) -> None: self.blender_executable = self.default_blender_executable + self.blender_executable_environment = {} def set_log_file(self, filepath: pathlib.Path, clear=True) -> None: # Log all commands and output to this file. @@ -161,7 +163,7 @@ class TestEnvironment: def unset_log_file(self) -> None: self.log_file = None - def call(self, args: List[str], cwd: pathlib.Path, silent=False) -> List[str]: + def call(self, args: List[str], cwd: pathlib.Path, silent: bool=False, environment: Dict={}) -> List[str]: # Execute command with arguments in specified directory, # and return combined stdout and stderr output. @@ -173,7 +175,13 @@ class TestEnvironment: f = open(self.log_file, 'a') f.write('\n' + ' '.join([str(arg) for arg in args]) + '\n\n') - proc = subprocess.Popen(args, cwd=cwd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) + env = os.environ + if len(environment): + env = env.copy() + for key, value in environment.items(): + env[key] = value + + proc = subprocess.Popen(args, cwd=cwd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, env=env) # Read line by line lines = [] @@ -208,7 +216,8 @@ class TestEnvironment: else: common_args += ['--background'] - return self.call([self.blender_executable] + common_args + args, cwd=self.base_dir) + return self.call([self.blender_executable] + common_args + args, cwd=self.base_dir, + environment=self.blender_executable_environment) def run_in_blender(self, function: Callable[[Dict], Dict], diff --git a/tests/performance/api/graph.py b/tests/performance/api/graph.py index 4ee5ae7cf0e..fe4d4800894 100644 --- a/tests/performance/api/graph.py +++ b/tests/performance/api/graph.py @@ -42,7 +42,7 @@ class TestGraph: # Generate one graph for every device x category x result key combination. for category, category_entries in categories.items(): - entries = sorted(category_entries, key=lambda entry: (entry.revision, entry.test)) + entries = sorted(category_entries, key=lambda entry: (entry.revision, entry.test, entry.date)) outputs = set() for entry in entries: @@ -58,8 +58,6 @@ class TestGraph: self.json = json.dumps(data, indent=2) def chart(self, device_name: str, chart_name: str, entries: List, chart_type: str, output: str) -> Dict: - entries = sorted(entries, key=lambda entry: entry.date) - # Gather used tests. tests = {} for entry in entries: diff --git a/tests/performance/benchmark b/tests/performance/benchmark index ad1e07d0ef3..343af3be7d1 100755 --- a/tests/performance/benchmark +++ b/tests/performance/benchmark @@ -83,15 +83,20 @@ def match_entry(entry: api.TestEntry, args: argparse.Namespace): entry.test.find(args.test) != -1 or \ entry.category.find(args.test) != -1 -def run_entry(env: api.TestEnvironment, config: api.TestConfig, row: List, entry: api.TestEntry): +def run_entry(env: api.TestEnvironment, + config: api.TestConfig, + row: List, + entry: api.TestEntry, + update_only: bool): # Check if entry needs to be run. - if entry.status not in ('queued', 'outdated'): + if update_only and entry.status not in ('queued', 'outdated'): print_row(config, row, end='\r') return False # Run test entry. revision = entry.revision git_hash = entry.git_hash + environment = entry.environment testname = entry.test testcategory = entry.category device_type = entry.device_type @@ -116,13 +121,15 @@ def run_entry(env: api.TestEnvironment, config: api.TestConfig, row: List, entry print_row(config, row, end='\r') executable_ok = True if len(entry.executable): - env.set_blender_executable(pathlib.Path(entry.executable)) + env.set_blender_executable(pathlib.Path(entry.executable), environment) else: env.checkout(git_hash) executable_ok = env.build() if not executable_ok: entry.status = 'failed' entry.error_msg = 'Failed to build' + else: + env.set_blender_executable(env.blender_executable, environment) # Run test and update output and status. if executable_ok: @@ -219,7 +226,7 @@ def cmd_reset(env: api.TestEnvironment, argv: List): config.queue.write() -def cmd_run(env: api.TestEnvironment, argv: List): +def cmd_run(env: api.TestEnvironment, argv: List, update_only: bool): # Run tests. parser = argparse.ArgumentParser() parser.add_argument('config', nargs='?', default=None) @@ -233,7 +240,7 @@ def cmd_run(env: api.TestEnvironment, argv: List): for row in config.queue.rows(use_revision_columns(config)): if match_entry(row[0], args): for entry in row: - if run_entry(env, config, row, entry): + if run_entry(env, config, row, entry, update_only): updated = True # Write queue every time in case running gets interrupted, # so it can be resumed. @@ -268,8 +275,9 @@ def main(): ' \n' ' list List available tests, devices and configurations\n' ' \n' - ' run [<config>] [<test>] Execute tests for configuration\n' - ' reset [<config>] [<test>] Clear tests results from config, for re-running\n' + ' run [<config>] [<test>] Execute all tests in configuration\n' + ' update [<config>] [<test>] Execute only queued and outdated tests\n' + ' reset [<config>] [<test>] Clear tests results in configuration\n' ' status [<config>] [<test>] List configurations and their tests\n' ' \n' ' graph a.json b.json... -o out.html Create graph from results in JSON files\n') @@ -304,7 +312,9 @@ def main(): if args.command == 'list': cmd_list(env, argv) elif args.command == 'run': - cmd_run(env, argv) + cmd_run(env, argv, update_only=False) + elif args.command == 'update': + cmd_run(env, argv, update_only=True) elif args.command == 'reset': cmd_reset(env, argv) elif args.command == 'status': |