From 2a2d0d463a4ae582464b1744f1b7d732fa0cc99a Mon Sep 17 00:00:00 2001 From: Bastien Montagne Date: Mon, 6 Apr 2020 11:23:29 +0200 Subject: i18n: Disable `es_ES` locale. We already have generic `es` one, having more only makes sense if poeple actually maintain them and they have different contents... --- release/scripts/modules/bl_i18n_utils/settings.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/release/scripts/modules/bl_i18n_utils/settings.py b/release/scripts/modules/bl_i18n_utils/settings.py index 4da9d515ffd..c736f78d501 100644 --- a/release/scripts/modules/bl_i18n_utils/settings.py +++ b/release/scripts/modules/bl_i18n_utils/settings.py @@ -108,7 +108,7 @@ IMPORT_MIN_LEVEL = 0.0 # Languages in /branches we do not want to import in /trunk currently... IMPORT_LANGUAGES_SKIP = { - 'am_ET', 'bg_BG', 'fi_FI', 'el_GR', 'et_EE', 'ne_NP', 'ro_RO', 'uz_UZ', 'uz_UZ@cyrillic', 'kk_KZ', + 'am_ET', 'bg_BG', 'fi_FI', 'el_GR', 'et_EE', 'ne_NP', 'ro_RO', 'uz_UZ', 'uz_UZ@cyrillic', 'kk_KZ', 'es_ES', } # Languages that need RTL pre-processing. -- cgit v1.2.3 From 2fc30978bce2c698e17e8c7f09e03b694fbdd805 Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Mon, 6 Apr 2020 11:45:59 +0200 Subject: Fix T75297: Apply base inflates meshes with Simple subdivision --- source/blender/blenkernel/intern/multires_reshape_apply_base.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/source/blender/blenkernel/intern/multires_reshape_apply_base.c b/source/blender/blenkernel/intern/multires_reshape_apply_base.c index 90736de12e1..e67e553e8ed 100644 --- a/source/blender/blenkernel/intern/multires_reshape_apply_base.c +++ b/source/blender/blenkernel/intern/multires_reshape_apply_base.c @@ -81,6 +81,11 @@ static float v3_dist_from_plane(float v[3], float center[3], float no[3]) void multires_reshape_apply_base_refit_base_mesh(MultiresReshapeContext *reshape_context) { + if (reshape_context->mmd->simple) { + /* Simple subdivisions does not move base mesh verticies, so no refitting is needed. */ + return; + } + Mesh *base_mesh = reshape_context->base_mesh; MeshElemMap *pmap; -- cgit v1.2.3 From f9c05f3fc0b7c5a9a4ca193f164e76caf3936006 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Mon, 6 Apr 2020 20:07:05 +1000 Subject: Fix f-curve sequencer versioning logic Screen loop was inside an existing screen loop, in the body of a function used to initialize the toolbar region. --- source/blender/blenkernel/BKE_blender_version.h | 2 +- source/blender/blenloader/intern/versioning_280.c | 50 ++++++++++++----------- 2 files changed, 28 insertions(+), 24 deletions(-) diff --git a/source/blender/blenkernel/BKE_blender_version.h b/source/blender/blenkernel/BKE_blender_version.h index 78e0e12355b..794313ecf62 100644 --- a/source/blender/blenkernel/BKE_blender_version.h +++ b/source/blender/blenkernel/BKE_blender_version.h @@ -27,7 +27,7 @@ * \note Use #STRINGIFY() rather than defining with quotes. */ #define BLENDER_VERSION 283 -#define BLENDER_SUBVERSION 11 +#define BLENDER_SUBVERSION 12 /** Several breakages with 280, e.g. collections vs layers. */ #define BLENDER_MINVERSION 280 #define BLENDER_MINSUBVERSION 0 diff --git a/source/blender/blenloader/intern/versioning_280.c b/source/blender/blenloader/intern/versioning_280.c index a95cb74af51..cd9f9dd7027 100644 --- a/source/blender/blenloader/intern/versioning_280.c +++ b/source/blender/blenloader/intern/versioning_280.c @@ -665,17 +665,6 @@ static void do_versions_area_ensure_tool_region(Main *bmain, } } } - /* Activate fcurves drawing in the vse. */ - for (bScreen *screen = bmain->screens.first; screen; screen = screen->id.next) { - for (ScrArea *area = screen->areabase.first; area; area = area->next) { - for (SpaceLink *sl = area->spacedata.first; sl; sl = sl->next) { - if (sl->spacetype == SPACE_SEQ) { - SpaceSeq *sseq = (SpaceSeq *)sl; - sseq->flag |= SEQ_SHOW_FCURVES; - } - } - } - } } } @@ -4889,18 +4878,19 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain) } } - /** - * Versioning code until next subversion bump goes here. - * - * \note Be sure to check when bumping the version: - * - #do_versions_after_linking_280 in this file. - * - "versioning_userdef.c", #BLO_version_defaults_userpref_blend - * - "versioning_userdef.c", #do_versions_theme - * - * \note Keep this message at the bottom of the function. - */ - { - /* Keep this block, even when empty. */ + if (!MAIN_VERSION_ATLEAST(bmain, 283, 12)) { + + /* Activate f-curve drawing in the sequencer. */ + for (bScreen *screen = bmain->screens.first; screen; screen = screen->id.next) { + for (ScrArea *area = screen->areabase.first; area; area = area->next) { + for (SpaceLink *sl = area->spacedata.first; sl; sl = sl->next) { + if (sl->spacetype == SPACE_SEQ) { + SpaceSeq *sseq = (SpaceSeq *)sl; + sseq->flag |= SEQ_SHOW_FCURVES; + } + } + } + } /* Remesh Modifier Voxel Mode. */ if (!DNA_struct_elem_find(fd->filesdna, "RemeshModifierData", "float", "voxel_size")) { @@ -4915,4 +4905,18 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain) } } } + + /** + * Versioning code until next subversion bump goes here. + * + * \note Be sure to check when bumping the version: + * - #do_versions_after_linking_280 in this file. + * - "versioning_userdef.c", #BLO_version_defaults_userpref_blend + * - "versioning_userdef.c", #do_versions_theme + * + * \note Keep this message at the bottom of the function. + */ + { + /* Keep this block, even when empty. */ + } } -- cgit v1.2.3 From 5d3c7d121879bd107687a12424e3b901e12dc82b Mon Sep 17 00:00:00 2001 From: Bastien Montagne Date: Mon, 6 Apr 2020 12:15:33 +0200 Subject: usual PY API doc gen fix after adding a new member to Context... --- doc/python_api/sphinx_doc_gen.py | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/python_api/sphinx_doc_gen.py b/doc/python_api/sphinx_doc_gen.py index 68a7a0df075..ee91bbc64b1 100644 --- a/doc/python_api/sphinx_doc_gen.py +++ b/doc/python_api/sphinx_doc_gen.py @@ -1052,6 +1052,7 @@ context_type_map = { "selected_editable_fcurves": ("FCurve", True), "selected_editable_objects": ("Object", True), "selected_editable_sequences": ("Sequence", True), + "selected_nla_strips": ("NlaStrip", True), "selected_nodes": ("Node", True), "selected_objects": ("Object", True), "selected_pose_bones": ("PoseBone", True), -- cgit v1.2.3 From ccaf6c74044d30bc2de9db033a703319d79127a7 Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Mon, 6 Apr 2020 12:15:14 +0200 Subject: Tracking: Fix slow undistored display TH distortion model was not cached properly, making it so frame is undistorted on every redraw. --- source/blender/blenkernel/intern/movieclip.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/source/blender/blenkernel/intern/movieclip.c b/source/blender/blenkernel/intern/movieclip.c index 1964dba7593..ad9314d7ee3 100644 --- a/source/blender/blenkernel/intern/movieclip.c +++ b/source/blender/blenkernel/intern/movieclip.c @@ -457,8 +457,8 @@ typedef struct MovieClipCache { /* cache for undistorted shot */ float principal[2]; - float polynomial_k1; - float division_k1; + float polynomial_k[3]; + float division_k[2]; short distortion_model; bool undistortion_used; @@ -896,11 +896,11 @@ static bool check_undistortion_cache_flags(const MovieClip *clip) return false; } - if (!equals_v3v3(&camera->k1, &cache->postprocessed.polynomial_k1)) { + if (!equals_v3v3(&camera->k1, cache->postprocessed.polynomial_k)) { return false; } - if (!equals_v2v2(&camera->division_k1, &cache->postprocessed.division_k1)) { + if (!equals_v2v2(&camera->division_k1, cache->postprocessed.division_k)) { return false; } @@ -1002,8 +1002,8 @@ static void put_postprocessed_frame_to_cache( if (need_undistortion_postprocess(user, flag)) { cache->postprocessed.distortion_model = camera->distortion_model; copy_v2_v2(cache->postprocessed.principal, camera->principal); - copy_v3_v3(&cache->postprocessed.polynomial_k1, &camera->k1); - copy_v2_v2(&cache->postprocessed.division_k1, &camera->division_k1); + copy_v3_v3(cache->postprocessed.polynomial_k, &camera->k1); + copy_v2_v2(cache->postprocessed.division_k, &camera->division_k1); cache->postprocessed.undistortion_used = true; } else { -- cgit v1.2.3 From cc0819aee119ad7a9dc9c383ec6895208ea1a184 Mon Sep 17 00:00:00 2001 From: Philipp Oeser Date: Thu, 2 Apr 2020 11:28:03 +0200 Subject: Fix (unreported) wrong hair vertex colors This was already fixed in rB985f33719ce9 once. But resurfaced after rB7070e4c15e6c [which just reverted a bit too much ;)]. Spotted while looking into T75263. Differential Revision: https://developer.blender.org/D7308 --- source/blender/draw/intern/draw_cache_impl_particles.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/source/blender/draw/intern/draw_cache_impl_particles.c b/source/blender/draw/intern/draw_cache_impl_particles.c index dca4f8e01e6..331a1f80bec 100644 --- a/source/blender/draw/intern/draw_cache_impl_particles.c +++ b/source/blender/draw/intern/draw_cache_impl_particles.c @@ -339,7 +339,8 @@ static void particle_calculate_parent_mcol(ParticleSystem *psys, if (num != DMCACHE_NOTFOUND && num != DMCACHE_ISCHILD) { MFace *mface = &psmd->mesh_final->mface[num]; for (int j = 0; j < num_col_layers; j++) { - psys_interpolate_mcol(mcols[j] + num, mface->v4, particle->fuv, &r_mcol[j]); + /* CustomDataLayer CD_MCOL has 4 structs per face. */ + psys_interpolate_mcol(mcols[j] + num * 4, mface->v4, particle->fuv, &r_mcol[j]); } } } @@ -388,6 +389,7 @@ static void particle_interpolate_children_mcol(ParticleSystem *psys, if (num != DMCACHE_NOTFOUND) { MFace *mface = &psmd->mesh_final->mface[num]; for (int j = 0; j < num_col_layers; j++) { + /* CustomDataLayer CD_MCOL has 4 structs per face. */ psys_interpolate_mcol(mcols[j] + num * 4, mface->v4, particle->fuv, &r_mcol[j]); } } -- cgit v1.2.3 From c03e5e78308c13e2d4a7d06fef84070f5044738f Mon Sep 17 00:00:00 2001 From: Philipp Oeser Date: Mon, 6 Apr 2020 13:03:15 +0200 Subject: Fix T75418: Outliner Blender File view has UNKNOWN category for armatures Typo in rB57daecc2cf88. Maniphest Tasks: T75418 Differential Revision: https://developer.blender.org/D7346 --- source/blender/blenkernel/intern/armature.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/blender/blenkernel/intern/armature.c b/source/blender/blenkernel/intern/armature.c index daf364432f4..af98992cc01 100644 --- a/source/blender/blenkernel/intern/armature.c +++ b/source/blender/blenkernel/intern/armature.c @@ -156,7 +156,7 @@ IDTypeInfo IDType_ID_AR = { .main_listbase_index = INDEX_ID_AR, .struct_size = sizeof(bArmature), .name = "Armature", - .name_plural = "armature", + .name_plural = "armatures", .translation_context = BLT_I18NCONTEXT_ID_ARMATURE, .flags = 0, -- cgit v1.2.3 From ded7af53b4f2fed41069dd52a9854fe1e904cad1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sybren=20A=2E=20St=C3=BCvel?= Date: Mon, 6 Apr 2020 13:37:51 +0200 Subject: Fix T74889 Baking to current action doesn't work properly Before this commit, baking an action would only insert keys that are necessary (i.e. using `INSERTKEY_NEEDED`). When baking to the current Action, if there are no constraints that influence the final animation, there are no additional keys necessary. This makes it appear as if nothing happened. However, when baking to a new Action every additional frame is necessary and thus a key is added for every frame. @mont29 and I agreed that this behaviour is confusing, so this commit changes the behaviour such that baking to the current action and to a new action result in the same baked animation (that is, keyed on every frame). --- release/scripts/modules/bpy_extras/anim_utils.py | 24 +++++++++++------------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/release/scripts/modules/bpy_extras/anim_utils.py b/release/scripts/modules/bpy_extras/anim_utils.py index c67134ac3f6..7de919f489e 100644 --- a/release/scripts/modules/bpy_extras/anim_utils.py +++ b/release/scripts/modules/bpy_extras/anim_utils.py @@ -216,8 +216,6 @@ def bake_action_iter( pose_info = [] obj_info = [] - options = {'INSERTKEY_NEEDED'} - # ------------------------------------------------------------------------- # Collect transformations @@ -281,7 +279,7 @@ def bake_action_iter( for (f, matrix, bbones) in pose_info: pbone.matrix_basis = matrix[name].copy() - pbone.keyframe_insert("location", index=-1, frame=f, group=name, options=options) + pbone.keyframe_insert("location", index=-1, frame=f, group=name) rotation_mode = pbone.rotation_mode if rotation_mode == 'QUATERNION': @@ -293,9 +291,9 @@ def bake_action_iter( del quat else: quat_prev = pbone.rotation_quaternion.copy() - pbone.keyframe_insert("rotation_quaternion", index=-1, frame=f, group=name, options=options) + pbone.keyframe_insert("rotation_quaternion", index=-1, frame=f, group=name) elif rotation_mode == 'AXIS_ANGLE': - pbone.keyframe_insert("rotation_axis_angle", index=-1, frame=f, group=name, options=options) + pbone.keyframe_insert("rotation_axis_angle", index=-1, frame=f, group=name) else: # euler, XYZ, ZXY etc if euler_prev is not None: euler = pbone.rotation_euler.copy() @@ -305,9 +303,9 @@ def bake_action_iter( del euler else: euler_prev = pbone.rotation_euler.copy() - pbone.keyframe_insert("rotation_euler", index=-1, frame=f, group=name, options=options) + pbone.keyframe_insert("rotation_euler", index=-1, frame=f, group=name) - pbone.keyframe_insert("scale", index=-1, frame=f, group=name, options=options) + pbone.keyframe_insert("scale", index=-1, frame=f, group=name) # Bendy Bones if pbone.bone.bbone_segments > 1: @@ -315,7 +313,7 @@ def bake_action_iter( for bb_prop in BBONE_PROPS: # update this property with value from bbone_shape, then key it setattr(pbone, bb_prop, bbone_shape[bb_prop]) - pbone.keyframe_insert(bb_prop, index=-1, frame=f, group=name, options=options) + pbone.keyframe_insert(bb_prop, index=-1, frame=f, group=name) # object. TODO. multiple objects if do_object: @@ -331,7 +329,7 @@ def bake_action_iter( name = "Action Bake" # XXX: placeholder obj.matrix_basis = matrix - obj.keyframe_insert("location", index=-1, frame=f, group=name, options=options) + obj.keyframe_insert("location", index=-1, frame=f, group=name) rotation_mode = obj.rotation_mode if rotation_mode == 'QUATERNION': @@ -344,9 +342,9 @@ def bake_action_iter( print ("quat_prev", quat_prev) else: quat_prev = obj.rotation_quaternion.copy() - obj.keyframe_insert("rotation_quaternion", index=-1, frame=f, group=name, options=options) + obj.keyframe_insert("rotation_quaternion", index=-1, frame=f, group=name) elif rotation_mode == 'AXIS_ANGLE': - obj.keyframe_insert("rotation_axis_angle", index=-1, frame=f, group=name, options=options) + obj.keyframe_insert("rotation_axis_angle", index=-1, frame=f, group=name) else: # euler, XYZ, ZXY etc if euler_prev is not None: euler = obj.rotation_euler.copy() @@ -356,9 +354,9 @@ def bake_action_iter( del euler else: euler_prev = obj.rotation_euler.copy() - obj.keyframe_insert("rotation_euler", index=-1, frame=f, group=name, options=options) + obj.keyframe_insert("rotation_euler", index=-1, frame=f, group=name) - obj.keyframe_insert("scale", index=-1, frame=f, group=name, options=options) + obj.keyframe_insert("scale", index=-1, frame=f, group=name) if do_parents_clear: obj.parent = None -- cgit v1.2.3 From 9ddbb03861fbfb36a83c1eb3fe2fb0feb455d0bd Mon Sep 17 00:00:00 2001 From: Sebastian Parborg Date: Mon, 6 Apr 2020 13:53:07 +0200 Subject: Fix T74111: Animation Playback Delayed With Time Remapping And AV-Sync MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When setting the current playback time in BKE_sound_play_scene we didn't account for the frame length. So the current frame/time would be wrong when we asked the audio playback what time it was. This would lead to playback being offset when using time remapping and AV sync. Reviewed By: Richard Antalik and Sybren A. Stüvel Differential Revision: http://developer.blender.org/D7248 --- source/blender/blenkernel/intern/sound.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/source/blender/blenkernel/intern/sound.c b/source/blender/blenkernel/intern/sound.c index 97a643e88b6..c26df027368 100644 --- a/source/blender/blenkernel/intern/sound.c +++ b/source/blender/blenkernel/intern/sound.c @@ -751,12 +751,20 @@ static void sound_start_play_scene(Scene *scene) } } +static float get_cur_time(Scene *scene) +{ + /* We divide by the current framelen to take into account time remapping. + * Otherwise we will get the wrong starting time which will break A/V sync. + * See T74111 for further details. */ + return FRA2TIME((CFRA + SUBFRA) / scene->r.framelen); +} + void BKE_sound_play_scene(Scene *scene) { sound_verify_evaluated_id(&scene->id); AUD_Status status; - const float cur_time = (float)((double)CFRA / FPS); + const float cur_time = get_cur_time(scene); AUD_Device_lock(sound_device); @@ -804,7 +812,7 @@ void BKE_sound_seek_scene(Main *bmain, Scene *scene) int animation_playing; const float one_frame = (float)(1.0 / FPS); - const float cur_time = (float)((double)CFRA / FPS); + const float cur_time = get_cur_time(scene); AUD_Device_lock(sound_device); -- cgit v1.2.3 From 2903fb69293b6c05a758290aa5f88a24ebcbc51a Mon Sep 17 00:00:00 2001 From: Jacques Lucke Date: Mon, 6 Apr 2020 15:12:38 +0200 Subject: Fix T75444: typo in tooltip --- source/blender/makesrna/intern/rna_brush.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/blender/makesrna/intern/rna_brush.c b/source/blender/makesrna/intern/rna_brush.c index b625b3f0a84..b5ed49b3476 100644 --- a/source/blender/makesrna/intern/rna_brush.c +++ b/source/blender/makesrna/intern/rna_brush.c @@ -1806,7 +1806,7 @@ static void rna_def_brush(BlenderRNA *brna) "SURFACE", 0, "Surface", - "Smooths the surface of the mesh, preserving the volue"}, + "Smooths the surface of the mesh, preserving the volume"}, {0, NULL, 0, NULL, NULL}, }; -- cgit v1.2.3 From 7e93d4eea3097e9e452c7c19953a01b6fab76163 Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Mon, 6 Apr 2020 14:47:19 +0200 Subject: Tracking: Fix (un)distortion happen in single thread Need to communicate available number of threads to the camera intrinsics implementation, otherwise default value of 1 is used. Must have been single-threaded for a very long time. --- intern/libmv/intern/camera_intrinsics.cc | 2 ++ intern/libmv/intern/camera_intrinsics.h | 1 + source/blender/blenkernel/intern/tracking_util.c | 3 +++ 3 files changed, 6 insertions(+) diff --git a/intern/libmv/intern/camera_intrinsics.cc b/intern/libmv/intern/camera_intrinsics.cc index 4bd6b1270f5..89e3d0d1178 100644 --- a/intern/libmv/intern/camera_intrinsics.cc +++ b/intern/libmv/intern/camera_intrinsics.cc @@ -80,6 +80,8 @@ void libmv_cameraIntrinsicsUpdate( * are not freed. */ + camera_intrinsics->SetThreads(libmv_camera_intrinsics_options->num_threads); + if (camera_intrinsics->focal_length() != focal_length) { camera_intrinsics->SetFocalLength(focal_length, focal_length); } diff --git a/intern/libmv/intern/camera_intrinsics.h b/intern/libmv/intern/camera_intrinsics.h index 9e900892952..40a5826a9c4 100644 --- a/intern/libmv/intern/camera_intrinsics.h +++ b/intern/libmv/intern/camera_intrinsics.h @@ -33,6 +33,7 @@ enum { typedef struct libmv_CameraIntrinsicsOptions { // Common settings of all distortion models. + int num_threads; int distortion_model; int image_width, image_height; double focal_length; diff --git a/source/blender/blenkernel/intern/tracking_util.c b/source/blender/blenkernel/intern/tracking_util.c index 51758abdf3f..d7600c06a6b 100644 --- a/source/blender/blenkernel/intern/tracking_util.c +++ b/source/blender/blenkernel/intern/tracking_util.c @@ -35,6 +35,7 @@ #include "BLI_math.h" #include "BLI_string.h" #include "BLI_string_utils.h" +#include "BLI_threads.h" #include "BLI_utildefines.h" #include "BLT_translation.h" @@ -442,6 +443,8 @@ void tracking_cameraIntrinscisOptionsFromTracking( MovieTrackingCamera *camera = &tracking->camera; float aspy = 1.0f / tracking->camera.pixel_aspect; + camera_intrinsics_options->num_threads = BLI_system_thread_count(); + camera_intrinsics_options->focal_length = camera->focal; camera_intrinsics_options->principal_point_x = camera->principal[0]; -- cgit v1.2.3 From 5dde5dd44e05024a53147aef70b26c70bfecdb1b Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Mon, 6 Apr 2020 14:47:35 +0200 Subject: Libmv: Use static scheduler for threading For a real-world distortion the payload is quite uniformly distributed across scanlines. Surely, in the corners more iterations of minimizer is needed, but that happens in threads without scheduling overhead. --- intern/libmv/libmv/simple_pipeline/camera_intrinsics_impl.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/intern/libmv/libmv/simple_pipeline/camera_intrinsics_impl.h b/intern/libmv/libmv/simple_pipeline/camera_intrinsics_impl.h index 97abee7ab01..e1b53992dfd 100644 --- a/intern/libmv/libmv/simple_pipeline/camera_intrinsics_impl.h +++ b/intern/libmv/libmv/simple_pipeline/camera_intrinsics_impl.h @@ -63,7 +63,7 @@ void LookupWarpGrid::Compute(const CameraIntrinsics &intrinsics, double aspx = (double) w / intrinsics.image_width(); double aspy = (double) h / intrinsics.image_height(); #if defined(_OPENMP) -# pragma omp parallel for schedule(dynamic) num_threads(threads_) \ +# pragma omp parallel for schedule(static) num_threads(threads_) \ if (threads_ > 1 && height > 100) #endif for (int y = 0; y < height; y++) { @@ -125,7 +125,7 @@ void LookupWarpGrid::Apply(const PixelType *input_buffer, int channels, PixelType *output_buffer) { #if defined(_OPENMP) -# pragma omp parallel for schedule(dynamic) num_threads(threads_) \ +# pragma omp parallel for schedule(static) num_threads(threads_) \ if (threads_ > 1 && height > 100) #endif for (int y = 0; y < height; y++) { -- cgit v1.2.3 From 3d439aa29b2fdde118b3f17dcf7c71abf98ec3dd Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Mon, 6 Apr 2020 21:42:31 +1000 Subject: Cleanup: keep parameter docs above the function body --- .../blender/editors/space_sequencer/sequencer_draw.c | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/source/blender/editors/space_sequencer/sequencer_draw.c b/source/blender/editors/space_sequencer/sequencer_draw.c index 93ff5263148..5d8851d5e3d 100644 --- a/source/blender/editors/space_sequencer/sequencer_draw.c +++ b/source/blender/editors/space_sequencer/sequencer_draw.c @@ -220,6 +220,10 @@ void color3ubv_from_seq(Scene *curscene, Sequence *seq, uchar col[3]) } } +/** + * \param x1, x2, y1, y2: The starting and end X value to draw the wave, same for y1 and y2. + * \param stepsize: The width of a pixel. + */ static void draw_seq_waveform(View2D *v2d, const bContext *C, SpaceSeq *sseq, @@ -231,9 +235,6 @@ static void draw_seq_waveform(View2D *v2d, float y2, float stepsize) { - /* X1, x2 is the starting and end X value to draw the wave, same for y1 and y2. - * Stepsize is width of a pixel. */ - /* Offset x1 and x2 values, to match view min/max, if strip is out of bounds. */ int x1_offset = max_ff(v2d->cur.xmin, x1); int x2_offset = min_ff(v2d->cur.xmax + 1.0f, x2); @@ -353,10 +354,10 @@ static void draw_seq_waveform(View2D *v2d, } } -/* Don't use SEQ_BEGIN/SEQ_END here, because it changes seq->depth, - * which is needed for tranform. */ static void drawmeta_contents(Scene *scene, Sequence *seqm, float x1, float y1, float x2, float y2) { + /* Don't use SEQ_BEGIN/SEQ_END here, + * because it changes seq->depth, which is needed for transform. */ Sequence *seq; uchar col[4]; @@ -988,9 +989,11 @@ static void fcurve_batch_add_verts(GPUVertBuf *vbo, *vert_count += 2; } -/* Draw f-curves as darkened regions of the strip. - * - Volume for sound strips. - * - Opacity for the other types. */ +/** + * Draw f-curves as darkened regions of the strip: + * - Volume for sound strips. + * - Opacity for the other types. + */ static void draw_seq_fcurve( Scene *scene, View2D *v2d, Sequence *seq, float x1, float y1, float x2, float y2, float pixelx) { -- cgit v1.2.3 From 95f51bb01deaf2f863f97aff1dbcd967ea524287 Mon Sep 17 00:00:00 2001 From: Roman Kornev Date: Mon, 6 Apr 2020 23:37:54 +1000 Subject: Keymap: sort exported key-maps This makes the resulting key-maps easier to compare. --- release/scripts/modules/bl_keymap_utils/io.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/release/scripts/modules/bl_keymap_utils/io.py b/release/scripts/modules/bl_keymap_utils/io.py index a93e86bc0a1..8cddbd37ea3 100644 --- a/release/scripts/modules/bl_keymap_utils/io.py +++ b/release/scripts/modules/bl_keymap_utils/io.py @@ -136,6 +136,9 @@ def keyconfig_export_as_data(wm, kc, filepath, *, all_keymaps=False): # First add all user_modified keymaps (found in keyconfigs.user.keymaps list), # then add all remaining keymaps from the currently active custom keyconfig. # + # Sort the resulting list according to top context name, + # while this isn't essential, it makes comparing keymaps simpler. + # # This will create a final list of keymaps that can be used as a "diff" against # the default blender keyconfig, recreating the current setup from a fresh blender # without needing to export keymaps which haven't been edited. @@ -152,6 +155,10 @@ def keyconfig_export_as_data(wm, kc, filepath, *, all_keymaps=False): else: export_keymaps = keyconfig_merge(edited_kc, edited_kc) + # Sort the keymap list by top context name before exporting, + # not essential, just convenient to order them predictably. + export_keymaps.sort(key=lambda k: k[0].name) + with open(filepath, "w") as fh: fw = fh.write fw("keyconfig_data = \\\n[") -- cgit v1.2.3 From c544df997ed9869ee053f1b45e1da6d8bf5f5e9c Mon Sep 17 00:00:00 2001 From: Maxim Vasiliev Date: Mon, 6 Apr 2020 16:23:43 +0200 Subject: Fix user counting when ungrouping a node group. Existing code for ungrouping did not correctly handle user counters: - counter for the group was not decremented - counters for containing nodes were not incremented The latter resulted in losing some nodes after orphan cleaning or several save/reload cycles. The bug did not have destructive consequences until recently, because it was compensated by another bug (fixed in rBe993667a46c2). Maniphest Tasks: T74665, T74682 Differential Revision: https://developer.blender.org/D7332 --- source/blender/editors/space_node/node_group.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/source/blender/editors/space_node/node_group.c b/source/blender/editors/space_node/node_group.c index 2a4c6147d5d..3a0ef45a68d 100644 --- a/source/blender/editors/space_node/node_group.c +++ b/source/blender/editors/space_node/node_group.c @@ -193,11 +193,11 @@ static int node_group_ungroup(Main *bmain, bNodeTree *ntree, bNode *gnode) } /* wgroup is a temporary copy of the NodeTree we're merging in - * - all of wgroup's nodes are transferred across to their new home + * - all of wgroup's nodes are copied across to their new home * - ngroup (i.e. the source NodeTree) is left unscathed - * - temp copy. don't change ID usercount + * - temp copy. do change ID usercount for the copies */ - wgroup = ntreeCopyTree_ex_new_pointers(ngroup, bmain, false); + wgroup = ntreeCopyTree_ex_new_pointers(ngroup, bmain, true); /* Add the nodes into the ntree */ for (node = wgroup->nodes.first; node; node = nextnode) { @@ -351,8 +351,8 @@ static int node_group_ungroup(Main *bmain, bNodeTree *ntree, bNode *gnode) nodeRemoveNode(bmain, ntree, node, false); } - /* delete the group instance */ - nodeRemoveNode(bmain, ntree, gnode, false); + /* delete the group instance and dereference group tree */ + nodeRemoveNode(bmain, ntree, gnode, true); ntree->update |= NTREE_UPDATE_NODES | NTREE_UPDATE_LINKS; -- cgit v1.2.3 From 71b1ee940bb0b8e159700e53137883b6995859ce Mon Sep 17 00:00:00 2001 From: Sebastian Parborg Date: Mon, 6 Apr 2020 16:32:30 +0200 Subject: Don't take into account time remapping when scrubbing with AV sync. It would cause the playhead to be remapped to an other frame than the one you clicked on. --- source/blender/blenkernel/intern/sound.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/blender/blenkernel/intern/sound.c b/source/blender/blenkernel/intern/sound.c index c26df027368..64fe396d6a3 100644 --- a/source/blender/blenkernel/intern/sound.c +++ b/source/blender/blenkernel/intern/sound.c @@ -812,7 +812,7 @@ void BKE_sound_seek_scene(Main *bmain, Scene *scene) int animation_playing; const float one_frame = (float)(1.0 / FPS); - const float cur_time = get_cur_time(scene); + const float cur_time = FRA2TIME(CFRA); AUD_Device_lock(sound_device); -- cgit v1.2.3 From 60d873bd22121a089101fe6058e0e6aba0467234 Mon Sep 17 00:00:00 2001 From: Jeroen Bakker Date: Mon, 6 Apr 2020 16:31:22 +0200 Subject: GPU: Panel Drag Widget Drawing Performance MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The 10g Intel/Win driver doesn't work well with our emulated intermediate mode. This patch alters the drawing of the drag widget of the panels to reduce unneeded drawing. The previous method would draw 16 boxes per widget. This new way would cache this drawing in a GPU batch and just move the matrix around. Reviewed By: Clément Foucault Differential Revision: https://developer.blender.org/D7345 --- source/blender/editors/interface/interface_panel.c | 80 +++--------- source/blender/gpu/GPU_batch_presets.h | 4 + source/blender/gpu/intern/gpu_batch_presets.c | 134 +++++++++++++++++++++ 3 files changed, 154 insertions(+), 64 deletions(-) diff --git a/source/blender/editors/interface/interface_panel.c b/source/blender/editors/interface/interface_panel.c index b3854cfc4ae..da0e8f34417 100644 --- a/source/blender/editors/interface/interface_panel.c +++ b/source/blender/editors/interface/interface_panel.c @@ -56,7 +56,9 @@ #include "UI_resources.h" #include "UI_view2d.h" +#include "GPU_batch_presets.h" #include "GPU_immediate.h" +#include "GPU_matrix.h" #include "GPU_state.h" #include "interface_intern.h" @@ -544,59 +546,6 @@ static void ui_draw_panel_scalewidget(uint pos, const rcti *rect) GPU_blend(false); } -static void immRectf_tris_color_ex( - uint pos, float x1, float y1, float x2, float y2, uint col, const float color[3]) -{ - immAttr4fv(col, color); - immVertex2f(pos, x1, y1); - immAttr4fv(col, color); - immVertex2f(pos, x2, y1); - immAttr4fv(col, color); - immVertex2f(pos, x2, y2); - - immAttr4fv(col, color); - immVertex2f(pos, x1, y1); - immAttr4fv(col, color); - immVertex2f(pos, x2, y2); - immAttr4fv(col, color); - immVertex2f(pos, x1, y2); -} - -static void ui_draw_panel_dragwidget(uint pos, uint col, const rctf *rect) -{ - float col_high[4], col_dark[4]; - const int col_tint = 84; - - const int px = (int)U.pixelsize; - const int px_zoom = max_ii(round_fl_to_int(BLI_rctf_size_y(rect) / 22.0f), 1); - - const int box_margin = max_ii(round_fl_to_int((float)(px_zoom * 2.0f)), px); - const int box_size = max_ii(round_fl_to_int((BLI_rctf_size_y(rect) / 8.0f) - px), px); - - const int x_min = rect->xmin; - const int y_min = rect->ymin; - const int y_ofs = max_ii(round_fl_to_int(BLI_rctf_size_y(rect) / 2.5f), px); - const int x_ofs = y_ofs; - int i_x, i_y; - - UI_GetThemeColorShade4fv(TH_PANEL_HEADER, col_tint, col_high); - UI_GetThemeColorShade4fv(TH_PANEL_BACK, -col_tint, col_dark); - - /* draw multiple boxes */ - immBegin(GPU_PRIM_TRIS, 4 * 2 * (6 * 2)); - for (i_x = 0; i_x < 4; i_x++) { - for (i_y = 0; i_y < 2; i_y++) { - const int x_co = (x_min + x_ofs) + (i_x * (box_size + box_margin)); - const int y_co = (y_min + y_ofs) + (i_y * (box_size + box_margin)); - - immRectf_tris_color_ex( - pos, x_co - box_size, y_co - px_zoom, x_co, (y_co + box_size) - px_zoom, col, col_dark); - immRectf_tris_color_ex(pos, x_co - box_size, y_co, x_co, y_co + box_size, col, col_high); - } - } - immEnd(); -} - /* For button layout next to label. */ void UI_panel_label_offset(uiBlock *block, int *r_x, int *r_y) { @@ -755,24 +704,27 @@ void ui_draw_aligned_panel(uiStyle *style, ui_draw_aligned_panel_header(style, block, &titlerect, 'h', show_background); if (show_drag) { - uint col; - GPUVertFormat *format = immVertexFormat(); - pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); - col = GPU_vertformat_attr_add(format, "color", GPU_COMP_F32, 4, GPU_FETCH_FLOAT); - /* itemrect smaller */ + const float scale = 0.7; itemrect.xmax = headrect.xmax - (0.2f * UI_UNIT_X); itemrect.xmin = itemrect.xmax - BLI_rcti_size_y(&headrect); itemrect.ymin = headrect.ymin; itemrect.ymax = headrect.ymax; + BLI_rctf_scale(&itemrect, scale); - BLI_rctf_scale(&itemrect, 0.7f); - immBindBuiltinProgram(GPU_SHADER_2D_FLAT_COLOR); - ui_draw_panel_dragwidget(pos, col, &itemrect); - immUnbindProgram(); + GPU_matrix_push(); + GPU_matrix_translate_2f(itemrect.xmin, itemrect.ymin); + + const int col_tint = 84; + float col_high[4], col_dark[4]; + UI_GetThemeColorShade4fv(TH_PANEL_HEADER, col_tint, col_high); + UI_GetThemeColorShade4fv(TH_PANEL_BACK, -col_tint, col_dark); - /* Restore format for the following draws. */ - pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); + GPUBatch *batch = GPU_batch_preset_panel_drag_widget( + U.pixelsize, col_high, col_dark, BLI_rcti_size_y(&headrect) * scale); + GPU_batch_program_set_builtin(batch, GPU_SHADER_2D_FLAT_COLOR); + GPU_batch_draw(batch); + GPU_matrix_pop(); } } diff --git a/source/blender/gpu/GPU_batch_presets.h b/source/blender/gpu/GPU_batch_presets.h index ba8ad3c4990..eb803333d98 100644 --- a/source/blender/gpu/GPU_batch_presets.h +++ b/source/blender/gpu/GPU_batch_presets.h @@ -39,6 +39,10 @@ extern "C" { /* Replacement for gluSphere */ struct GPUBatch *GPU_batch_preset_sphere(int lod) ATTR_WARN_UNUSED_RESULT; struct GPUBatch *GPU_batch_preset_sphere_wire(int lod) ATTR_WARN_UNUSED_RESULT; +struct GPUBatch *GPU_batch_preset_panel_drag_widget(const float pixelsize, + const float col_high[4], + const float col_dark[4], + const float width) ATTR_WARN_UNUSED_RESULT; void gpu_batch_presets_init(void); void gpu_batch_presets_register(struct GPUBatch *preset_batch); diff --git a/source/blender/gpu/intern/gpu_batch_presets.c b/source/blender/gpu/intern/gpu_batch_presets.c index e322b9fb9b8..e488880bf0a 100644 --- a/source/blender/gpu/intern/gpu_batch_presets.c +++ b/source/blender/gpu/intern/gpu_batch_presets.c @@ -27,7 +27,10 @@ #include "BLI_utildefines.h" #include "MEM_guardedalloc.h" +#include "DNA_userdef_types.h" + #include "UI_interface.h" +#include "UI_resources.h" #include "GPU_batch.h" #include "GPU_batch_presets.h" /* own include */ @@ -53,6 +56,23 @@ static struct { ThreadMutex mutex; } g_presets_3d = {{0}}; +static struct { + struct { + GPUBatch *panel_drag_widget; + } batch; + + float panel_drag_widget_pixelsize; + float panel_drag_widget_width; + float panel_drag_widget_col_high[4]; + float panel_drag_widget_col_dark[4]; + + GPUVertFormat format; + + struct { + uint pos, col; + } attr_id; +} g_presets_2d = {{0}}; + static ListBase presets_list = {NULL, NULL}; /* -------------------------------------------------------------------- */ @@ -71,6 +91,18 @@ static GPUVertFormat *preset_3d_format(void) return &g_presets_3d.format; } +static GPUVertFormat *preset_2d_format(void) +{ + if (g_presets_2d.format.attr_len == 0) { + GPUVertFormat *format = &g_presets_2d.format; + g_presets_2d.attr_id.pos = GPU_vertformat_attr_add( + format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); + g_presets_2d.attr_id.col = GPU_vertformat_attr_add( + format, "color", GPU_COMP_F32, 4, GPU_FETCH_FLOAT); + } + return &g_presets_2d.format; +} + static void batch_sphere_lat_lon_vert(GPUVertBufRaw *pos_step, GPUVertBufRaw *nor_step, float lat, @@ -193,6 +225,108 @@ static GPUBatch *batch_sphere_wire(int lat_res, int lon_res) /** \} */ +/* -------------------------------------------------------------------- */ +/** \name Panel Drag Widget + * \{ */ +static void gpu_batch_preset_rectf_tris_color_ex(GPUVertBufRaw *pos_step, + float x1, + float y1, + float x2, + float y2, + GPUVertBufRaw *col_step, + const float color[4]) +{ + copy_v2_v2(GPU_vertbuf_raw_step(pos_step), (const float[2]){x1, y1}); + copy_v4_v4(GPU_vertbuf_raw_step(col_step), color); + + copy_v2_v2(GPU_vertbuf_raw_step(pos_step), (const float[2]){x2, y1}); + copy_v4_v4(GPU_vertbuf_raw_step(col_step), color); + + copy_v2_v2(GPU_vertbuf_raw_step(pos_step), (const float[2]){x2, y2}); + copy_v4_v4(GPU_vertbuf_raw_step(col_step), color); + + copy_v2_v2(GPU_vertbuf_raw_step(pos_step), (const float[2]){x1, y1}); + copy_v4_v4(GPU_vertbuf_raw_step(col_step), color); + + copy_v2_v2(GPU_vertbuf_raw_step(pos_step), (const float[2]){x2, y2}); + copy_v4_v4(GPU_vertbuf_raw_step(col_step), color); + + copy_v2_v2(GPU_vertbuf_raw_step(pos_step), (const float[2]){x1, y2}); + copy_v4_v4(GPU_vertbuf_raw_step(col_step), color); +} + +static GPUBatch *gpu_batch_preset_panel_drag_widget(float pixelsize, + const float col_high[4], + const float col_dark[4], + const float width) +{ + GPUVertBuf *vbo = GPU_vertbuf_create_with_format(preset_2d_format()); + const uint vbo_len = 4 * 2 * (6 * 2); + GPU_vertbuf_data_alloc(vbo, vbo_len); + + GPUVertBufRaw pos_step, col_step; + GPU_vertbuf_attr_get_raw_data(vbo, g_presets_2d.attr_id.pos, &pos_step); + GPU_vertbuf_attr_get_raw_data(vbo, g_presets_2d.attr_id.col, &col_step); + + const int px = (int)pixelsize; + const int px_zoom = max_ii(round_fl_to_int(width / 22.0f), 1); + + const int box_margin = max_ii(round_fl_to_int((float)(px_zoom * 2.0f)), px); + const int box_size = max_ii(round_fl_to_int((width / 8.0f) - px), px); + + const int y_ofs = max_ii(round_fl_to_int(width / 2.5f), px); + const int x_ofs = y_ofs; + int i_x, i_y; + + for (i_x = 0; i_x < 4; i_x++) { + for (i_y = 0; i_y < 2; i_y++) { + const int x_co = (x_ofs) + (i_x * (box_size + box_margin)); + const int y_co = (y_ofs) + (i_y * (box_size + box_margin)); + + gpu_batch_preset_rectf_tris_color_ex(&pos_step, + x_co - box_size, + y_co - px_zoom, + x_co, + (y_co + box_size) - px_zoom, + &col_step, + col_dark); + gpu_batch_preset_rectf_tris_color_ex( + &pos_step, x_co - box_size, y_co, x_co, y_co + box_size, &col_step, col_high); + } + } + return GPU_batch_create_ex(GPU_PRIM_TRIS, vbo, NULL, GPU_BATCH_OWNS_VBO); +} + +GPUBatch *GPU_batch_preset_panel_drag_widget(const float pixelsize, + const float col_high[4], + const float col_dark[4], + const float width) +{ + const bool parameters_changed = (g_presets_2d.panel_drag_widget_pixelsize != pixelsize) || + (g_presets_2d.panel_drag_widget_width != width) || + !equals_v4v4(g_presets_2d.panel_drag_widget_col_high, + col_high) || + !equals_v4v4(g_presets_2d.panel_drag_widget_col_dark, col_dark); + + if (g_presets_2d.batch.panel_drag_widget && parameters_changed) { + gpu_batch_presets_unregister(g_presets_2d.batch.panel_drag_widget); + g_presets_2d.batch.panel_drag_widget = NULL; + } + + if (!g_presets_2d.batch.panel_drag_widget) { + g_presets_2d.batch.panel_drag_widget = gpu_batch_preset_panel_drag_widget( + pixelsize, col_high, col_dark, width); + gpu_batch_presets_register(g_presets_2d.batch.panel_drag_widget); + g_presets_2d.panel_drag_widget_pixelsize = pixelsize; + g_presets_2d.panel_drag_widget_width = width; + copy_v4_v4(g_presets_2d.panel_drag_widget_col_high, col_high); + copy_v4_v4(g_presets_2d.panel_drag_widget_col_dark, col_dark); + } + return g_presets_2d.batch.panel_drag_widget; +} + +/** \} */ + void gpu_batch_presets_init(void) { BLI_mutex_init(&g_presets_3d.mutex); -- cgit v1.2.3 From 71a52bbe2a2edaac77d146b27502dddf986d3284 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Barschkis?= Date: Mon, 6 Apr 2020 17:48:18 +0200 Subject: Fluid: Ensure correct velocities for noise bake Make sure that noise uses the unaltered velocity grid. This is particularly important once external velocities get added to the velocity grid. --- intern/mantaflow/intern/strings/smoke_script.h | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/intern/mantaflow/intern/strings/smoke_script.h b/intern/mantaflow/intern/strings/smoke_script.h index fb2eaa9b441..0f265fcb7ac 100644 --- a/intern/mantaflow/intern/strings/smoke_script.h +++ b/intern/mantaflow/intern/strings/smoke_script.h @@ -329,6 +329,9 @@ const std::string smoke_step = def smoke_step_$ID$():\n\ mantaMsg('Smoke step low')\n\ \n\ + # save original state for later (used during noise creation)\n\ + velTmp_s$ID$.copyFrom(vel_s$ID$)\n\ + \n\ if using_dissolve_s$ID$:\n\ mantaMsg('Dissolving smoke')\n\ dissolveSmoke(flags=flags_s$ID$, density=density_s$ID$, heat=heat_s$ID$, red=color_r_s$ID$, green=color_g_s$ID$, blue=color_b_s$ID$, speed=dissolveSpeed_s$ID$, logFalloff=using_logdissolve_s$ID$)\n\ @@ -422,36 +425,36 @@ def smoke_step_noise_$ID$(framenr):\n\ mantaMsg('Interpolating grids')\n\ # Join big obstacle levelset after initDomain() call as it overwrites everything in phiObs\n\ if using_obstacle_s$ID$:\n\ - interpolateGrid(target=phiIn_sn$ID$, source=phiObsIn_s$ID$) # mis-use phiIn_sn\n\ + phiIn_sn$ID$.copyFrom(phiObsIn_s$ID$) if upres_sn$ID$ <= 1 else interpolateGrid(target=phiIn_sn$ID$, source=phiObsIn_s$ID$) # mis-use phiIn_sn\n\ phiObs_sn$ID$.join(phiIn_sn$ID$)\n\ if using_outflow_s$ID$:\n\ - interpolateGrid(target=phiOut_sn$ID$, source=phiOut_s$ID$)\n\ - interpolateGrid(target=phiIn_sn$ID$, source=phiIn_s$ID$)\n\ - interpolateMACGrid(target=vel_sn$ID$, source=vel_s$ID$)\n\ + phiOut_sn$ID$.copyFrom(phiOut_s$ID$) if upres_sn$ID$ <= 1 else interpolateGrid(target=phiOut_sn$ID$, source=phiOut_s$ID$)\n\ + phiIn_sn$ID$.copyFrom(phiIn_s$ID$) if upres_sn$ID$ <= 1 else interpolateGrid(target=phiIn_sn$ID$, source=phiIn_s$ID$)\n\ + vel_sn$ID$.copyFrom(velTmp_s$ID$) if upres_sn$ID$ <= 1 else interpolateMACGrid(target=vel_sn$ID$, source=velTmp_s$ID$)\n\ \n\ setObstacleFlags(flags=flags_sn$ID$, phiObs=phiObs_sn$ID$, phiOut=phiOut_sn$ID$, phiIn=phiIn_sn$ID$, boundaryWidth=1)\n\ flags_sn$ID$.fillGrid()\n\ \n\ # Interpolate emission grids and apply them to big noise grids\n\ - interpolateGrid(source=densityIn_s$ID$, target=tmpIn_sn$ID$)\n\ - interpolateGrid(source=emissionIn_s$ID$, target=emissionIn_sn$ID$)\n\ + tmpIn_sn$ID$.copyFrom(densityIn_s$ID$) if upres_sn$ID$ <= 1 else interpolateGrid(source=densityIn_s$ID$, target=tmpIn_sn$ID$)\n\ + emissionIn_sn$ID$.copyFrom(emissionIn_s$ID$) if upres_sn$ID$ <= 1 else interpolateGrid(source=emissionIn_s$ID$, target=emissionIn_sn$ID$)\n\ \n\ # Higher-res noise grid needs scaled emission values\n\ tmpIn_sn$ID$.multConst(float(upres_sn$ID$))\n\ applyEmission(flags=flags_sn$ID$, target=density_sn$ID$, source=tmpIn_sn$ID$, emissionTexture=emissionIn_sn$ID$, type=FlagInflow|FlagOutflow)\n\ \n\ if using_colors_s$ID$:\n\ - interpolateGrid(source=color_r_in_s$ID$, target=tmpIn_sn$ID$)\n\ + tmpIn_sn$ID$.copyFrom(color_r_in_s$ID$) if upres_sn$ID$ <= 1 else interpolateGrid(source=color_r_in_s$ID$, target=tmpIn_sn$ID$)\n\ applyEmission(flags=flags_sn$ID$, target=color_r_sn$ID$, source=tmpIn_sn$ID$, emissionTexture=emissionIn_sn$ID$, type=FlagInflow|FlagOutflow)\n\ - interpolateGrid(source=color_g_in_s$ID$, target=tmpIn_sn$ID$)\n\ + tmpIn_sn$ID$.copyFrom(color_g_in_s$ID$) if upres_sn$ID$ <= 1 else interpolateGrid(source=color_g_in_s$ID$, target=tmpIn_sn$ID$)\n\ applyEmission(flags=flags_sn$ID$, target=color_g_sn$ID$, source=tmpIn_sn$ID$, emissionTexture=emissionIn_sn$ID$, type=FlagInflow|FlagOutflow)\n\ - interpolateGrid(source=color_b_in_s$ID$, target=tmpIn_sn$ID$)\n\ + tmpIn_sn$ID$.copyFrom(color_b_in_s$ID$) if upres_sn$ID$ <= 1 else interpolateGrid(source=color_b_in_s$ID$, target=tmpIn_sn$ID$)\n\ applyEmission(flags=flags_sn$ID$, target=color_b_sn$ID$, source=tmpIn_sn$ID$, emissionTexture=emissionIn_sn$ID$, type=FlagInflow|FlagOutflow)\n\ \n\ if using_fire_s$ID$:\n\ - interpolateGrid(source=fuelIn_s$ID$, target=tmpIn_sn$ID$)\n\ + tmpIn_sn$ID$.copyFrom(fuelIn_s$ID$) if upres_sn$ID$ <= 1 else interpolateGrid(source=fuelIn_s$ID$, target=tmpIn_sn$ID$)\n\ applyEmission(flags=flags_sn$ID$, target=fuel_sn$ID$, source=tmpIn_sn$ID$, emissionTexture=emissionIn_sn$ID$, type=FlagInflow|FlagOutflow)\n\ - interpolateGrid(source=reactIn_s$ID$, target=tmpIn_sn$ID$)\n\ + tmpIn_sn$ID$.copyFrom(reactIn_s$ID$) if upres_sn$ID$ <= 1 else interpolateGrid(source=reactIn_s$ID$, target=tmpIn_sn$ID$)\n\ applyEmission(flags=flags_sn$ID$, target=react_sn$ID$, source=tmpIn_sn$ID$, emissionTexture=emissionIn_sn$ID$, type=FlagInflow|FlagOutflow)\n\ \n\ mantaMsg('Noise step / sn$ID$.frame: ' + str(sn$ID$.frame))\n\ -- cgit v1.2.3 From 29b87b5615f60919977f2e383e8fdf30bdf498fb Mon Sep 17 00:00:00 2001 From: Ray Molenkamp Date: Mon, 6 Apr 2020 14:38:52 -0600 Subject: Fix T75357: USD export broken on windows Path to the jsons was wrong so they were not copied --- build_files/cmake/platform/platform_win32.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build_files/cmake/platform/platform_win32.cmake b/build_files/cmake/platform/platform_win32.cmake index 452deb497b2..1ecde8635c8 100644 --- a/build_files/cmake/platform/platform_win32.cmake +++ b/build_files/cmake/platform/platform_win32.cmake @@ -669,7 +669,7 @@ if(WITH_USD) set(USD_INCLUDE_DIRS ${LIBDIR}/usd/include) set(USD_RELEASE_LIB ${LIBDIR}/usd/lib/libusd_m.lib) set(USD_DEBUG_LIB ${LIBDIR}/usd/lib/libusd_m_d.lib) - set(USD_LIBRARY_DIR ${LIBDIR}/usd/lib/usd) + set(USD_LIBRARY_DIR ${LIBDIR}/usd/lib) set(USD_LIBRARIES debug ${USD_DEBUG_LIB} optimized ${USD_RELEASE_LIB} -- cgit v1.2.3 From e05552f7c4ac27faa510048e8c010e4323acb569 Mon Sep 17 00:00:00 2001 From: Brecht Van Lommel Date: Mon, 6 Apr 2020 23:19:01 +0200 Subject: Revert "Fix T74572: adaptive sampling not scaling render passes correctly" This reverts commit 82a8da0ec38a70efde4a91957824c67d0e60b8ad. It was completely wrong. Fixes T75388. --- intern/cycles/render/buffers.cpp | 89 +++++++++++++++------------------------- intern/cycles/render/film.cpp | 3 ++ intern/cycles/render/film.h | 1 + 3 files changed, 37 insertions(+), 56 deletions(-) diff --git a/intern/cycles/render/buffers.cpp b/intern/cycles/render/buffers.cpp index 22db8e875dc..2d89fb9ffba 100644 --- a/intern/cycles/render/buffers.cpp +++ b/intern/cycles/render/buffers.cpp @@ -165,35 +165,6 @@ bool RenderBuffers::copy_from_device() return true; } -static const float *get_sample_count_pass(const vector &passes, device_vector &buffer) -{ - int sample_offset = 0; - - for (const Pass &pass : passes) { - if (pass.type != PASS_SAMPLE_COUNT) { - sample_offset += pass.components; - } - else { - return buffer.data() + sample_offset; - } - } - - return NULL; -} - -static float get_pixel_pass_scale(const float rcp_sample, - const float *sample_count, - const int i, - const int pass_stride) -{ - if (sample_count) { - return 1.0f / fabsf(sample_count[i * pass_stride]); - } - else { - return rcp_sample; - } -} - bool RenderBuffers::get_denoising_pass_rect( int type, float exposure, int sample, int components, float *pixels) { @@ -289,7 +260,22 @@ bool RenderBuffers::get_pass_rect( return false; } - const float *sample_count = get_sample_count_pass(params.passes, buffer); + float *sample_count = NULL; + if (name == "Combined") { + int sample_offset = 0; + for (size_t j = 0; j < params.passes.size(); j++) { + Pass &pass = params.passes[j]; + if (pass.type != PASS_SAMPLE_COUNT) { + sample_offset += pass.components; + continue; + } + else { + sample_count = buffer.data() + sample_offset; + break; + } + } + } + int pass_offset = 0; for (size_t j = 0; j < params.passes.size(); j++) { @@ -307,8 +293,8 @@ bool RenderBuffers::get_pass_rect( float *in = buffer.data() + pass_offset; int pass_stride = params.get_passes_size(); - const float rcp_sample = 1.0f / (float)sample; - const float pass_exposure = (pass.exposure) ? exposure : 1.0f; + float scale = (pass.filter) ? 1.0f / (float)sample : 1.0f; + float scale_exposure = (pass.exposure) ? scale * exposure : scale; int size = params.width * params.height; @@ -326,36 +312,28 @@ bool RenderBuffers::get_pass_rect( if (type == PASS_DEPTH) { for (int i = 0; i < size; i++, in += pass_stride, pixels++) { float f = *in; - pixels[0] = (f == 0.0f) ? 1e10f : f; - } - } - else if (type == PASS_OBJECT_ID || type == PASS_MATERIAL_ID) { - for (int i = 0; i < size; i++, in += pass_stride, pixels++) { - pixels[0] = *in; + pixels[0] = (f == 0.0f) ? 1e10f : f * scale_exposure; } } else if (type == PASS_MIST) { for (int i = 0; i < size; i++, in += pass_stride, pixels++) { - const float scale = get_pixel_pass_scale(rcp_sample, sample_count, i, pass_stride); - const float f = *in; - pixels[0] = saturate(f * scale); + float f = *in; + pixels[0] = saturate(f * scale_exposure); } } #ifdef WITH_CYCLES_DEBUG else if (type == PASS_BVH_TRAVERSED_NODES || type == PASS_BVH_TRAVERSED_INSTANCES || type == PASS_BVH_INTERSECTIONS || type == PASS_RAY_BOUNCES) { for (int i = 0; i < size; i++, in += pass_stride, pixels++) { - const float scale = get_pixel_pass_scale(rcp_sample, sample_count, i, pass_stride); - const float f = *in; + float f = *in; pixels[0] = f * scale; } } #endif else { for (int i = 0; i < size; i++, in += pass_stride, pixels++) { - const float scale = get_pixel_pass_scale(rcp_sample, sample_count, i, pass_stride); - const float f = *in; - pixels[0] = f * scale * pass_exposure; + float f = *in; + pixels[0] = f * scale_exposure; } } } @@ -389,7 +367,7 @@ bool RenderBuffers::get_pass_rect( float3 f = make_float3(in[0], in[1], in[2]); float3 f_divide = make_float3(in_divide[0], in_divide[1], in_divide[2]); - f = safe_divide_even_color(f * pass_exposure, f_divide); + f = safe_divide_even_color(f * exposure, f_divide); pixels[0] = f.x; pixels[1] = f.y; @@ -399,9 +377,7 @@ bool RenderBuffers::get_pass_rect( else { /* RGB/vector */ for (int i = 0; i < size; i++, in += pass_stride, pixels += 3) { - const float scale = get_pixel_pass_scale(rcp_sample, sample_count, i, pass_stride); - const float scale_exposure = scale * pass_exposure; - const float3 f = make_float3(in[0], in[1], in[2]); + float3 f = make_float3(in[0], in[1], in[2]); pixels[0] = f.x * scale_exposure; pixels[1] = f.y * scale_exposure; @@ -449,9 +425,7 @@ bool RenderBuffers::get_pass_rect( } else if (type == PASS_CRYPTOMATTE) { for (int i = 0; i < size; i++, in += pass_stride, pixels += 4) { - const float scale = get_pixel_pass_scale(rcp_sample, sample_count, i, pass_stride); - const float4 f = make_float4(in[0], in[1], in[2], in[3]); - + float4 f = make_float4(in[0], in[1], in[2], in[3]); /* x and z contain integer IDs, don't rescale them. y and w contain matte weights, they get scaled. */ pixels[0] = f.x; @@ -462,9 +436,12 @@ bool RenderBuffers::get_pass_rect( } else { for (int i = 0; i < size; i++, in += pass_stride, pixels += 4) { - const float scale = get_pixel_pass_scale(rcp_sample, sample_count, i, pass_stride); - const float scale_exposure = scale * pass_exposure; - const float4 f = make_float4(in[0], in[1], in[2], in[3]); + if (sample_count && sample_count[i * pass_stride] < 0.0f) { + scale = (pass.filter) ? -1.0f / (sample_count[i * pass_stride]) : 1.0f; + scale_exposure = (pass.exposure) ? scale * exposure : scale; + } + + float4 f = make_float4(in[0], in[1], in[2], in[3]); pixels[0] = f.x * scale_exposure; pixels[1] = f.y * scale_exposure; diff --git a/intern/cycles/render/film.cpp b/intern/cycles/render/film.cpp index c29810d1494..baf02901123 100644 --- a/intern/cycles/render/film.cpp +++ b/intern/cycles/render/film.cpp @@ -76,6 +76,7 @@ void Pass::add(PassType type, vector &passes, const char *name) Pass pass; pass.type = type; + pass.filter = true; pass.exposure = false; pass.divide_type = PASS_NONE; if (name) { @@ -92,6 +93,7 @@ void Pass::add(PassType type, vector &passes, const char *name) break; case PASS_DEPTH: pass.components = 1; + pass.filter = false; break; case PASS_MIST: pass.components = 1; @@ -112,6 +114,7 @@ void Pass::add(PassType type, vector &passes, const char *name) case PASS_OBJECT_ID: case PASS_MATERIAL_ID: pass.components = 1; + pass.filter = false; break; case PASS_EMISSION: diff --git a/intern/cycles/render/film.h b/intern/cycles/render/film.h index 0fe4fe89d5e..aae8fb404b0 100644 --- a/intern/cycles/render/film.h +++ b/intern/cycles/render/film.h @@ -42,6 +42,7 @@ class Pass { public: PassType type; int components; + bool filter; bool exposure; PassType divide_type; string name; -- cgit v1.2.3 From 10f0e003a95a9d28be162605d7985c4d4620f6c0 Mon Sep 17 00:00:00 2001 From: Brecht Van Lommel Date: Mon, 6 Apr 2020 22:37:50 +0200 Subject: Fix T74572: adaptive sampling not scaling AOVs correctly --- intern/cycles/kernel/kernel_adaptive_sampling.h | 9 +++++++++ intern/cycles/kernel/kernel_types.h | 6 ++++-- intern/cycles/render/film.cpp | 12 +++++++----- 3 files changed, 20 insertions(+), 7 deletions(-) diff --git a/intern/cycles/kernel/kernel_adaptive_sampling.h b/intern/cycles/kernel/kernel_adaptive_sampling.h index 047fe8c92ec..ee4d1507ef1 100644 --- a/intern/cycles/kernel/kernel_adaptive_sampling.h +++ b/intern/cycles/kernel/kernel_adaptive_sampling.h @@ -150,6 +150,7 @@ ccl_device void kernel_adaptive_post_adjust(KernelGlobals *kg, } #endif /* __DENOISING_FEATURES__ */ + /* Cryptomatte. */ if (kernel_data.film.cryptomatte_passes) { int num_slots = 0; num_slots += (kernel_data.film.cryptomatte_passes & CRYPT_OBJECT) ? 1 : 0; @@ -162,6 +163,14 @@ ccl_device void kernel_adaptive_post_adjust(KernelGlobals *kg, id_buffer[slot].y *= sample_multiplier; } } + + /* AOVs. */ + for (int i = 0; i < kernel_data.film.pass_aov_value_num; i++) { + *(buffer + kernel_data.film.pass_aov_value + i) *= sample_multiplier; + } + for (int i = 0; i < kernel_data.film.pass_aov_color_num; i++) { + *((ccl_global float4 *)(buffer + kernel_data.film.pass_aov_color) + i) *= sample_multiplier; + } } /* This is a simple box filter in two passes. diff --git a/intern/cycles/kernel/kernel_types.h b/intern/cycles/kernel/kernel_types.h index b6d319311a1..44c936da626 100644 --- a/intern/cycles/kernel/kernel_types.h +++ b/intern/cycles/kernel/kernel_types.h @@ -1242,7 +1242,9 @@ typedef struct KernelFilm { int pass_aov_color; int pass_aov_value; - int pad1; + int pass_aov_color_num; + int pass_aov_value_num; + int pad1, pad2, pad3; /* XYZ to rendering color space transform. float4 instead of float3 to * ensure consistent padding/alignment across devices. */ @@ -1265,7 +1267,7 @@ typedef struct KernelFilm { int use_display_exposure; int use_display_pass_alpha; - int pad3, pad4, pad5; + int pad4, pad5, pad6; } KernelFilm; static_assert_align(KernelFilm, 16); diff --git a/intern/cycles/render/film.cpp b/intern/cycles/render/film.cpp index baf02901123..f28c943ea6c 100644 --- a/intern/cycles/render/film.cpp +++ b/intern/cycles/render/film.cpp @@ -362,8 +362,10 @@ void Film::device_update(Device *device, DeviceScene *dscene, Scene *scene) kfilm->light_pass_flag = 0; kfilm->pass_stride = 0; kfilm->use_light_pass = use_light_visibility; + kfilm->pass_aov_value_num = 0; + kfilm->pass_aov_color_num = 0; - bool have_cryptomatte = false, have_aov_color = false, have_aov_value = false; + bool have_cryptomatte = false; for (size_t i = 0; i < passes.size(); i++) { Pass &pass = passes[i]; @@ -498,16 +500,16 @@ void Film::device_update(Device *device, DeviceScene *dscene, Scene *scene) kfilm->pass_sample_count = kfilm->pass_stride; break; case PASS_AOV_COLOR: - if (!have_aov_color) { + if (kfilm->pass_aov_value_num == 0) { kfilm->pass_aov_color = kfilm->pass_stride; - have_aov_color = true; } + kfilm->pass_aov_value_num++; break; case PASS_AOV_VALUE: - if (!have_aov_value) { + if (kfilm->pass_aov_color_num == 0) { kfilm->pass_aov_value = kfilm->pass_stride; - have_aov_value = true; } + kfilm->pass_aov_color_num++; break; default: assert(false); -- cgit v1.2.3 From e9b4d2ca68ee2ecd99bbed1ecd4d3a4ab80812f2 Mon Sep 17 00:00:00 2001 From: Aaron Carlisle Date: Mon, 6 Apr 2020 20:58:10 -0400 Subject: UI: Use Consistent Operator Name Was called "Subdivide Multi" in Bone Edit and "Subdivide" in Mesh Edit --- source/blender/editors/armature/armature_add.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/blender/editors/armature/armature_add.c b/source/blender/editors/armature/armature_add.c index f6875a6e158..0bc405a9c67 100644 --- a/source/blender/editors/armature/armature_add.c +++ b/source/blender/editors/armature/armature_add.c @@ -1232,7 +1232,7 @@ void ARMATURE_OT_subdivide(wmOperatorType *ot) PropertyRNA *prop; /* identifiers */ - ot->name = "Subdivide Multi"; + ot->name = "Subdivide"; ot->idname = "ARMATURE_OT_subdivide"; ot->description = "Break selected bones into chains of smaller bones"; -- cgit v1.2.3 From 4e7c65035b0821d89e3be4e6f7a415752913a2cd Mon Sep 17 00:00:00 2001 From: Aaron Carlisle Date: Mon, 6 Apr 2020 21:45:41 -0400 Subject: UI: Use Consitent Menu Layout for Bone Names --- release/scripts/startup/bl_ui/space_view3d.py | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/release/scripts/startup/bl_ui/space_view3d.py b/release/scripts/startup/bl_ui/space_view3d.py index 88b94a86f00..eefcb6a71be 100644 --- a/release/scripts/startup/bl_ui/space_view3d.py +++ b/release/scripts/startup/bl_ui/space_view3d.py @@ -3316,13 +3316,7 @@ class VIEW3D_MT_pose(Menu): layout.separator() - layout.operator_context = 'EXEC_AREA' - layout.operator("pose.autoside_names", text="AutoName Left/Right").axis = 'XAXIS' - layout.operator("pose.autoside_names", text="AutoName Front/Back").axis = 'YAXIS' - layout.operator("pose.autoside_names", text="AutoName Top/Bottom").axis = 'ZAXIS' - - layout.operator("pose.flip_names") - + layout.menu("VIEW3D_MT_pose_names") layout.operator("pose.quaternions_flip") layout.separator() @@ -3459,6 +3453,19 @@ class VIEW3D_MT_pose_constraints(Menu): layout.operator("pose.constraints_clear") +class VIEW3D_MT_pose_names(Menu): + bl_label = "Names" + + def draw(self, _context): + layout = self.layout + + layout.operator_context = 'EXEC_REGION_WIN' + layout.operator("pose.autoside_names", text="AutoName Left/Right").axis = 'XAXIS' + layout.operator("pose.autoside_names", text="AutoName Front/Back").axis = 'YAXIS' + layout.operator("pose.autoside_names", text="AutoName Top/Bottom").axis = 'ZAXIS' + layout.operator("pose.flip_names") + + class VIEW3D_MT_pose_showhide(ShowHideMenu, Menu): _operator_name = "pose" @@ -7443,6 +7450,7 @@ classes = ( VIEW3D_MT_pose_group, VIEW3D_MT_pose_ik, VIEW3D_MT_pose_constraints, + VIEW3D_MT_pose_names, VIEW3D_MT_pose_showhide, VIEW3D_MT_pose_apply, VIEW3D_MT_pose_context_menu, -- cgit v1.2.3 From d54757e389862a081deb3d2064e95fdaddb1880a Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Tue, 7 Apr 2020 11:57:36 +1000 Subject: Cleanup: clang-format --- source/blender/editors/sculpt_paint/sculpt_dyntopo.c | 14 +++++--------- source/blender/editors/space_sequencer/sequencer_scopes.c | 8 ++++---- 2 files changed, 9 insertions(+), 13 deletions(-) diff --git a/source/blender/editors/sculpt_paint/sculpt_dyntopo.c b/source/blender/editors/sculpt_paint/sculpt_dyntopo.c index 5f75c1d6813..0ab3b8cd14e 100644 --- a/source/blender/editors/sculpt_paint/sculpt_dyntopo.c +++ b/source/blender/editors/sculpt_paint/sculpt_dyntopo.c @@ -42,8 +42,8 @@ #include "BKE_modifier.h" #include "BKE_object.h" #include "BKE_paint.h" -#include "BKE_pbvh.h" #include "BKE_particle.h" +#include "BKE_pbvh.h" #include "BKE_pointcache.h" #include "BKE_scene.h" #include "BKE_screen.h" @@ -141,10 +141,7 @@ void SCULPT_dyntopo_node_layers_add(SculptSession *ss) ss->bm->pdata.layers[cd_node_layer_index].flag |= CD_FLAG_TEMPORARY; } -void SCULPT_dynamic_topology_enable_ex(Main *bmain, - Depsgraph *depsgraph, - Scene *scene, - Object *ob) +void SCULPT_dynamic_topology_enable_ex(Main *bmain, Depsgraph *depsgraph, Scene *scene, Object *ob) { SculptSession *ss = ob->sculpt; Mesh *me = ob->data; @@ -281,9 +278,9 @@ void SCULPT_dynamic_topology_disable(bContext *C, SculptUndoNode *unode) } void sculpt_dynamic_topology_disable_with_undo(Main *bmain, - Depsgraph *depsgraph, - Scene *scene, - Object *ob) + Depsgraph *depsgraph, + Scene *scene, + Object *ob) { SculptSession *ss = ob->sculpt; if (ss->bm) { @@ -331,7 +328,6 @@ static int sculpt_dynamic_topology_toggle_exec(bContext *C, wmOperator *UNUSED(o return OPERATOR_FINISHED; } - static int dyntopo_warning_popup(bContext *C, wmOperatorType *ot, enum eDynTopoWarnFlag flag) { uiPopupMenu *pup = UI_popup_menu_begin(C, IFACE_("Warning!"), ICON_ERROR); diff --git a/source/blender/editors/space_sequencer/sequencer_scopes.c b/source/blender/editors/space_sequencer/sequencer_scopes.c index b08c35623af..b06bc7ad8b7 100644 --- a/source/blender/editors/space_sequencer/sequencer_scopes.c +++ b/source/blender/editors/space_sequencer/sequencer_scopes.c @@ -451,8 +451,8 @@ typedef struct MakeHistogramViewData { } MakeHistogramViewData; static void make_histogram_view_from_ibuf_byte_fn(void *__restrict userdata, - const int y, - const TaskParallelTLS *__restrict tls) + const int y, + const TaskParallelTLS *__restrict tls) { MakeHistogramViewData *data = userdata; const ImBuf *ibuf = data->ibuf; @@ -552,8 +552,8 @@ BLI_INLINE int get_bin_float(float f) } static void make_histogram_view_from_ibuf_float_fn(void *__restrict userdata, - const int y, - const TaskParallelTLS *__restrict tls) + const int y, + const TaskParallelTLS *__restrict tls) { const MakeHistogramViewData *data = userdata; const ImBuf *ibuf = data->ibuf; -- cgit v1.2.3 From d14e76806921f9a4d686ea731364242ededb735d Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Tue, 7 Apr 2020 12:02:21 +1000 Subject: Cleanup: BLI_path.h function renaming Use BLI_path_ prefix, more consistent names: BLI_parent_dir -> BLI_path_parent_dir BLI_parent_dir_until_exists -> BLI_path_parent_dir_until_exists BLI_ensure_filename -> BLI_path_filename_ensure BLI_first_slash -> BLI_path_slash_find BLI_last_slash -> BLI_path_slash_rfind BLI_add_slash -> BLI_path_slash_ensure BLI_del_slash -> BLI_path_slash_rstrip BLI_path_native_slash -> BLI_path_slash_native Rename 'cleanup' to 'normalize', similar to Python's `os.path.normpath`. BLI_cleanup_path -> BLI_path_normalize BLI_cleanup_dir -> BLI_path_normalize_dir BLI_cleanup_unc -> BLI_path_normalize_unc BLI_cleanup_unc16 -> BLI_path_normalize_unc16 Clarify naming for extracting, creating numbered paths: BLI_stringenc -> BLI_path_sequence_encode BLI_stringdec -> BLI_path_sequence_decode Part of T74506 proposal. --- source/blender/blenkernel/intern/appdir.c | 10 +-- source/blender/blenkernel/intern/blendfile.c | 4 +- source/blender/blenkernel/intern/bpath.c | 8 +-- source/blender/blenkernel/intern/image.c | 6 +- source/blender/blenkernel/intern/image_save.c | 6 +- source/blender/blenkernel/intern/movieclip.c | 10 +-- source/blender/blenkernel/intern/pointcache.c | 6 +- source/blender/blenkernel/intern/seqcache.c | 4 +- source/blender/blenlib/BLI_path_util.h | 26 ++++---- source/blender/blenlib/intern/BLI_filelist.c | 2 +- source/blender/blenlib/intern/fileops.c | 26 ++++---- source/blender/blenlib/intern/path_util.c | 74 +++++++++++----------- source/blender/blenloader/intern/readfile.c | 6 +- source/blender/blenloader/intern/writefile.c | 4 +- source/blender/editors/space_buttons/buttons_ops.c | 6 +- source/blender/editors/space_clip/clip_buttons.c | 2 +- source/blender/editors/space_clip/clip_ops.c | 2 +- source/blender/editors/space_file/file_ops.c | 32 +++++----- source/blender/editors/space_file/filelist.c | 18 +++--- source/blender/editors/space_file/filesel.c | 4 +- source/blender/editors/space_image/image_buttons.c | 2 +- source/blender/editors/space_image/image_ops.c | 3 +- .../blender/editors/space_image/image_sequence.c | 8 +-- .../freestyle/intern/application/Controller.cpp | 2 +- .../freestyle/intern/system/StringUtils.cpp | 2 +- source/blender/imbuf/intern/anim_movie.c | 2 +- source/blender/io/collada/ImageExporter.cpp | 2 +- source/blender/makesrna/intern/rna_userdef.c | 2 +- source/blender/windowmanager/intern/wm_files.c | 4 +- .../blender/windowmanager/intern/wm_files_link.c | 2 +- source/blender/windowmanager/intern/wm_playanim.c | 6 +- tests/gtests/blenlib/BLI_path_util_test.cc | 18 +++--- 32 files changed, 156 insertions(+), 153 deletions(-) diff --git a/source/blender/blenkernel/intern/appdir.c b/source/blender/blenkernel/intern/appdir.c index 0e578250b39..92b7bdcfb98 100644 --- a/source/blender/blenkernel/intern/appdir.c +++ b/source/blender/blenkernel/intern/appdir.c @@ -232,7 +232,7 @@ static bool get_path_local(char *targetpath, char osx_resourses[FILE_MAX]; BLI_snprintf(osx_resourses, sizeof(osx_resourses), "%s../Resources", bprogdir); /* Remove the '/../' added above. */ - BLI_cleanup_path(NULL, osx_resourses); + BLI_path_normalize(NULL, osx_resourses); return test_path( targetpath, targetpath_len, osx_resourses, blender_version_decimal(ver), relfolder); #else @@ -692,7 +692,7 @@ static void where_am_i(char *fullname, const size_t maxlen, const char *name) BLI_path_program_extensions_add_win32(fullname, maxlen); #endif } - else if (BLI_last_slash(name)) { + else if (BLI_path_slash_rfind(name)) { // full path BLI_strncpy(fullname, name, maxlen); #ifdef _WIN32 @@ -703,7 +703,7 @@ static void where_am_i(char *fullname, const size_t maxlen, const char *name) BLI_path_program_search(fullname, maxlen, name); } /* Remove "/./" and "/../" so string comparisons can be used on the path. */ - BLI_cleanup_path(NULL, fullname); + BLI_path_normalize(NULL, fullname); #if defined(DEBUG) if (!STREQ(name, fullname)) { @@ -939,7 +939,7 @@ static void where_is_temp(char *fullname, char *basename, const size_t maxlen, c } else { /* add a trailing slash if needed */ - BLI_add_slash(fullname); + BLI_path_slash_ensure(fullname); #ifdef WIN32 if (userdir && userdir != fullname) { /* also set user pref to show %TEMP%. /tmp/ is just plain confusing for Windows users. */ @@ -967,7 +967,7 @@ static void where_is_temp(char *fullname, char *basename, const size_t maxlen, c if (BLI_is_dir(tmp_name)) { BLI_strncpy(basename, fullname, maxlen); BLI_strncpy(fullname, tmp_name, maxlen); - BLI_add_slash(fullname); + BLI_path_slash_ensure(fullname); } else { CLOG_WARN(&LOG, diff --git a/source/blender/blenkernel/intern/blendfile.c b/source/blender/blenkernel/intern/blendfile.c index d862132480a..2a53a0b69a4 100644 --- a/source/blender/blenkernel/intern/blendfile.c +++ b/source/blender/blenkernel/intern/blendfile.c @@ -76,7 +76,7 @@ static bool clean_paths_visit_cb(void *UNUSED(userdata), char *path_dst, const char *path_src) { strcpy(path_dst, path_src); - BLI_path_native_slash(path_dst); + BLI_path_slash_native(path_dst); return !STREQ(path_dst, path_src); } @@ -88,7 +88,7 @@ static void clean_paths(Main *main) BKE_bpath_traverse_main(main, clean_paths_visit_cb, BKE_BPATH_TRAVERSE_SKIP_MULTIFILE, NULL); for (scene = main->scenes.first; scene; scene = scene->id.next) { - BLI_path_native_slash(scene->r.pic); + BLI_path_slash_native(scene->r.pic); } } diff --git a/source/blender/blenkernel/intern/bpath.c b/source/blender/blenkernel/intern/bpath.c index 5891a0361d8..d179bfbedfd 100644 --- a/source/blender/blenkernel/intern/bpath.c +++ b/source/blender/blenkernel/intern/bpath.c @@ -137,7 +137,7 @@ static bool bpath_relative_rebase_visit_cb(void *userdata, char *path_dst, const char filepath[(FILE_MAXDIR * 2) + FILE_MAXFILE]; BLI_strncpy(filepath, path_src, FILE_MAX); if (BLI_path_abs(filepath, data->basedir_src)) { - BLI_cleanup_path(NULL, filepath); + BLI_path_normalize(NULL, filepath); /* This may fail, if so it's fine to leave absolute since the path is still valid. */ BLI_path_rel(filepath, data->basedir_dst); @@ -815,13 +815,13 @@ bool BKE_bpath_relocate_visitor(void *pathbase_v, char *path_dst, const char *pa } /* Make referenced file absolute. This would be a side-effect of - * BLI_cleanup_path, but we do it explicitly so we know if it changed. */ + * BLI_path_normalize, but we do it explicitly so we know if it changed. */ BLI_strncpy(filepath, path_src, FILE_MAX); if (BLI_path_abs(filepath, base_old)) { /* Path was relative and is now absolute. Remap. - * Important BLI_cleanup_path runs before the path is made relative + * Important BLI_path_normalize runs before the path is made relative * because it wont work for paths that start with "//../" */ - BLI_cleanup_path(base_new, filepath); + BLI_path_normalize(base_new, filepath); BLI_path_rel(filepath, base_new); BLI_strncpy(path_dst, filepath, FILE_MAX); return true; diff --git a/source/blender/blenkernel/intern/image.c b/source/blender/blenkernel/intern/image.c index f58e7c06d7f..9bd1a632278 100644 --- a/source/blender/blenkernel/intern/image.c +++ b/source/blender/blenkernel/intern/image.c @@ -5316,8 +5316,8 @@ void BKE_image_user_file_path(ImageUser *iuser, Image *ima, char *filepath) index = (iuser && iuser->tile) ? iuser->tile : 1001; } - BLI_stringdec(filepath, head, tail, &numlen); - BLI_stringenc(filepath, head, tail, numlen, index); + BLI_path_sequence_decode(filepath, head, tail, &numlen); + BLI_path_sequence_encode(filepath, head, tail, numlen, index); } BLI_path_abs(filepath, ID_BLEND_PATH_FROM_GLOBAL(&ima->id)); @@ -5458,7 +5458,7 @@ float *BKE_image_get_float_pixels_for_frame(struct Image *image, int frame, int int BKE_image_sequence_guess_offset(Image *image) { - return BLI_stringdec(image->name, NULL, NULL, NULL); + return BLI_path_sequence_decode(image->name, NULL, NULL, NULL); } bool BKE_image_has_anim(Image *ima) diff --git a/source/blender/blenkernel/intern/image_save.c b/source/blender/blenkernel/intern/image_save.c index b2e0f234f1e..c034fe895a6 100644 --- a/source/blender/blenkernel/intern/image_save.c +++ b/source/blender/blenkernel/intern/image_save.c @@ -406,7 +406,7 @@ bool BKE_image_save( if (ima->source == IMA_SRC_TILED) { /* Verify filepath for tiles images. */ - if (BLI_stringdec(opts->filepath, NULL, NULL, NULL) != 1001) { + if (BLI_path_sequence_decode(opts->filepath, NULL, NULL, NULL) != 1001) { BKE_reportf(reports, RPT_ERROR, "When saving a tiled image, the path '%s' must contain the UDIM tag 1001", @@ -429,7 +429,7 @@ bool BKE_image_save( char head[FILE_MAX], tail[FILE_MAX]; unsigned short numlen; - BLI_stringdec(filepath, head, tail, &numlen); + BLI_path_sequence_decode(filepath, head, tail, &numlen); /* Save all other tiles. */ LISTBASE_FOREACH (ImageTile *, tile, &ima->tiles) { @@ -439,7 +439,7 @@ bool BKE_image_save( } /* Build filepath of the tile. */ - BLI_stringenc(opts->filepath, head, tail, numlen, tile->tile_number); + BLI_path_sequence_encode(opts->filepath, head, tail, numlen, tile->tile_number); iuser->tile = tile->tile_number; ok = ok && image_save_single(reports, ima, iuser, opts, &colorspace_changed); diff --git a/source/blender/blenkernel/intern/movieclip.c b/source/blender/blenkernel/intern/movieclip.c index ad9314d7ee3..847466915ab 100644 --- a/source/blender/blenkernel/intern/movieclip.c +++ b/source/blender/blenkernel/intern/movieclip.c @@ -197,14 +197,14 @@ static void get_sequence_fname(const MovieClip *clip, const int framenr, char *n int offset; BLI_strncpy(name, clip->name, sizeof(clip->name)); - BLI_stringdec(name, head, tail, &numlen); + BLI_path_sequence_decode(name, head, tail, &numlen); /* Movie-clips always points to first image from sequence, auto-guess offset for now. * Could be something smarter in the future. */ offset = sequence_guess_offset(clip->name, strlen(head), numlen); if (numlen) { - BLI_stringenc( + BLI_path_sequence_encode( name, head, tail, numlen, offset + framenr - clip->start_frame + clip->frame_offset); } else { @@ -421,7 +421,7 @@ static void movieclip_calc_length(MovieClip *clip) unsigned short numlen; char name[FILE_MAX], head[FILE_MAX], tail[FILE_MAX]; - BLI_stringdec(clip->name, head, tail, &numlen); + BLI_path_sequence_decode(clip->name, head, tail, &numlen); if (numlen == 0) { /* there's no number group in file name, assume it's single framed sequence */ @@ -505,7 +505,7 @@ static int user_frame_to_cache_frame(MovieClip *clip, int framenr) unsigned short numlen; char head[FILE_MAX], tail[FILE_MAX]; - BLI_stringdec(clip->name, head, tail, &numlen); + BLI_path_sequence_decode(clip->name, head, tail, &numlen); /* see comment in get_sequence_fname */ clip->cache->sequence_offset = sequence_guess_offset(clip->name, strlen(head), numlen); @@ -648,7 +648,7 @@ static bool put_imbuf_cache( clip->cache->sequence_offset = -1; if (clip->source == MCLIP_SRC_SEQUENCE) { unsigned short numlen; - BLI_stringdec(clip->name, NULL, NULL, &numlen); + BLI_path_sequence_decode(clip->name, NULL, NULL, &numlen); clip->cache->is_still_sequence = (numlen == 0); } } diff --git a/source/blender/blenkernel/intern/pointcache.c b/source/blender/blenkernel/intern/pointcache.c index 78e7dec9f38..77b3f1580ac 100644 --- a/source/blender/blenkernel/intern/pointcache.c +++ b/source/blender/blenkernel/intern/pointcache.c @@ -2066,7 +2066,7 @@ static int ptcache_path(PTCacheID *pid, char *filename) BLI_path_abs(filename, blendfilename); } - return BLI_add_slash(filename); /* new strlen() */ + return BLI_path_slash_ensure(filename); /* new strlen() */ } else if (G.relbase_valid || lib) { char file[MAX_PTCACHE_PATH]; /* we don't want the dir, only the file */ @@ -2083,14 +2083,14 @@ static int ptcache_path(PTCacheID *pid, char *filename) BLI_snprintf(filename, MAX_PTCACHE_PATH, "//" PTCACHE_PATH "%s", file); BLI_path_abs(filename, blendfilename); - return BLI_add_slash(filename); /* new strlen() */ + return BLI_path_slash_ensure(filename); /* new strlen() */ } /* use the temp path. this is weak but better then not using point cache at all */ /* temporary directory is assumed to exist and ALWAYS has a trailing slash */ BLI_snprintf(filename, MAX_PTCACHE_PATH, "%s" PTCACHE_PATH, BKE_tempdir_session()); - return BLI_add_slash(filename); /* new strlen() */ + return BLI_path_slash_ensure(filename); /* new strlen() */ } static int ptcache_filename(PTCacheID *pid, char *filename, int cfra, short do_path, short do_ext) diff --git a/source/blender/blenkernel/intern/seqcache.c b/source/blender/blenkernel/intern/seqcache.c index a2c0434a474..12c5821e858 100644 --- a/source/blender/blenkernel/intern/seqcache.c +++ b/source/blender/blenkernel/intern/seqcache.c @@ -243,7 +243,7 @@ static void seq_disk_cache_get_files(SeqDiskCache *disk_cache, char *path) if (is_dir && !FILENAME_IS_CURRPAR(file)) { char subpath[FILE_MAX]; BLI_strncpy(subpath, fl->path, sizeof(subpath)); - BLI_add_slash(subpath); + BLI_path_slash_ensure(subpath); seq_disk_cache_get_files(disk_cache, subpath); } @@ -439,7 +439,7 @@ static void seq_disk_cache_delete_invalid_files(SeqDiskCache *disk_cache, DiskCacheFile *next_file, *cache_file = disk_cache->files.first; char cache_dir[FILE_MAX]; seq_disk_cache_get_dir(disk_cache, scene, seq, cache_dir, sizeof(cache_dir)); - BLI_add_slash(cache_dir); + BLI_path_slash_ensure(cache_dir); while (cache_file) { next_file = cache_file->next; diff --git a/source/blender/blenlib/BLI_path_util.h b/source/blender/blenlib/BLI_path_util.h index 4376aefdc25..2b88359861a 100644 --- a/source/blender/blenlib/BLI_path_util.h +++ b/source/blender/blenlib/BLI_path_util.h @@ -56,11 +56,11 @@ bool BLI_path_name_at_index(const char *__restrict path, int *__restrict r_offset, int *__restrict r_len) ATTR_NONNULL() ATTR_WARN_UNUSED_RESULT; -const char *BLI_last_slash(const char *string) ATTR_NONNULL() ATTR_WARN_UNUSED_RESULT; -int BLI_add_slash(char *string) ATTR_NONNULL(); -void BLI_del_slash(char *string) ATTR_NONNULL(); -const char *BLI_first_slash(const char *string) ATTR_NONNULL() ATTR_WARN_UNUSED_RESULT; -void BLI_path_native_slash(char *path) ATTR_NONNULL(); +const char *BLI_path_slash_rfind(const char *string) ATTR_NONNULL() ATTR_WARN_UNUSED_RESULT; +int BLI_path_slash_ensure(char *string) ATTR_NONNULL(); +void BLI_path_slash_rstrip(char *string) ATTR_NONNULL(); +const char *BLI_path_slash_find(const char *string) ATTR_NONNULL() ATTR_WARN_UNUSED_RESULT; +void BLI_path_slash_native(char *path) ATTR_NONNULL(); #ifdef _WIN32 bool BLI_path_program_extensions_add_win32(char *name, const size_t maxlen); @@ -77,22 +77,22 @@ bool BLI_path_extension_check_glob(const char *str, const char *ext_fnmatch) bool BLI_path_extension_glob_validate(char *ext_fnmatch) ATTR_NONNULL(); bool BLI_path_extension_replace(char *path, size_t maxlen, const char *ext) ATTR_NONNULL(); bool BLI_path_extension_ensure(char *path, size_t maxlen, const char *ext) ATTR_NONNULL(); -bool BLI_ensure_filename(char *filepath, size_t maxlen, const char *filename) ATTR_NONNULL(); -int BLI_stringdec(const char *string, char *head, char *start, unsigned short *numlen); -void BLI_stringenc( +bool BLI_path_filename_ensure(char *filepath, size_t maxlen, const char *filename) ATTR_NONNULL(); +int BLI_path_sequence_decode(const char *string, char *head, char *start, unsigned short *numlen); +void BLI_path_sequence_encode( char *string, const char *head, const char *tail, unsigned short numlen, int pic); -void BLI_cleanup_path(const char *relabase, char *path) ATTR_NONNULL(2); +void BLI_path_normalize(const char *relabase, char *path) ATTR_NONNULL(2); /* Same as above but adds a trailing slash. */ -void BLI_cleanup_dir(const char *relabase, char *dir) ATTR_NONNULL(2); +void BLI_path_normalize_dir(const char *relabase, char *dir) ATTR_NONNULL(2); bool BLI_filename_make_safe(char *fname) ATTR_NONNULL(1); bool BLI_path_make_safe(char *path) ATTR_NONNULL(1); /* Go back one directory. */ -bool BLI_parent_dir(char *path) ATTR_NONNULL(); +bool BLI_path_parent_dir(char *path) ATTR_NONNULL(); /* Go back until the directory is found. */ -bool BLI_parent_dir_until_exists(char *path) ATTR_NONNULL(); +bool BLI_path_parent_dir_until_exists(char *path) ATTR_NONNULL(); bool BLI_path_abs(char *path, const char *basepath) ATTR_NONNULL(); bool BLI_path_frame(char *path, int frame, int digits) ATTR_NONNULL(); @@ -110,7 +110,7 @@ void BLI_path_to_display_name(char *display_name, int maxlen, const char *name) #if defined(WIN32) void BLI_cleanup_unc_16(wchar_t *path_16); -void BLI_cleanup_unc(char *path_16, int maxlen); +void BLI_path_normalize_unc(char *path_16, int maxlen); #endif bool BLI_path_suffix(char *string, size_t maxlen, const char *suffix, const char *sep) diff --git a/source/blender/blenlib/intern/BLI_filelist.c b/source/blender/blenlib/intern/BLI_filelist.c index 2e402f0c063..26f1de33aa9 100644 --- a/source/blender/blenlib/intern/BLI_filelist.c +++ b/source/blender/blenlib/intern/BLI_filelist.c @@ -147,7 +147,7 @@ static void bli_builddir(struct BuildDirCtx *dir_ctx, const char *dirname) char pardir[FILE_MAXDIR]; BLI_strncpy(pardir, dirname, sizeof(pardir)); - if (BLI_parent_dir(pardir) && (BLI_access(pardir, R_OK) == 0)) { + if (BLI_path_parent_dir(pardir) && (BLI_access(pardir, R_OK) == 0)) { struct dirlink *const dlink = (struct dirlink *)malloc(sizeof(struct dirlink)); if (dlink != NULL) { dlink->name = BLI_strdup(FILENAME_PARENT); diff --git a/source/blender/blenlib/intern/fileops.c b/source/blender/blenlib/intern/fileops.c index da77046547c..b9133edcae3 100644 --- a/source/blender/blenlib/intern/fileops.c +++ b/source/blender/blenlib/intern/fileops.c @@ -492,7 +492,7 @@ static bool delete_recursive(const char *dir) /* dir listing produces dir path without trailing slash... */ BLI_strncpy(path, fl->path, sizeof(path)); - BLI_add_slash(path); + BLI_path_slash_ensure(path); if (delete_recursive(path)) { err = true; @@ -562,9 +562,9 @@ int BLI_move(const char *file, const char *to) BLI_strncpy(str, to, sizeof(str)); /* points 'to' to a directory ? */ - if (BLI_last_slash(str) == (str + strlen(str) - 1)) { - if (BLI_last_slash(file) != NULL) { - strcat(str, BLI_last_slash(file) + 1); + if (BLI_path_slash_rfind(str) == (str + strlen(str) - 1)) { + if (BLI_path_slash_rfind(file) != NULL) { + strcat(str, BLI_path_slash_rfind(file) + 1); } } @@ -594,9 +594,9 @@ int BLI_copy(const char *file, const char *to) BLI_strncpy(str, to, sizeof(str)); /* points 'to' to a directory ? */ - if (BLI_last_slash(str) == (str + strlen(str) - 1)) { - if (BLI_last_slash(file) != NULL) { - strcat(str, BLI_last_slash(file) + 1); + if (BLI_path_slash_rfind(str) == (str + strlen(str) - 1)) { + if (BLI_path_slash_rfind(file) != NULL) { + strcat(str, BLI_path_slash_rfind(file) + 1); } } @@ -638,7 +638,7 @@ bool BLI_dir_create_recursive(const char *dirname) * blah1/blah2 (without slash) */ BLI_strncpy(tmp, dirname, sizeof(tmp)); - BLI_del_slash(tmp); + BLI_path_slash_rstrip(tmp); /* check special case "c:\foo", don't try create "c:", harmless but prints an error below */ if (isalpha(tmp[0]) && (tmp[1] == ':') && tmp[2] == '\0') { @@ -652,7 +652,7 @@ bool BLI_dir_create_recursive(const char *dirname) return false; } - lslash = (char *)BLI_last_slash(tmp); + lslash = (char *)BLI_path_slash_rfind(tmp); if (lslash) { /* Split about the last slash and recurse */ @@ -723,7 +723,7 @@ static void join_dirfile_alloc(char **dst, size_t *alloc_len, const char *dir, c static char *strip_last_slash(const char *dir) { char *result = BLI_strdup(dir); - BLI_del_slash(result); + BLI_path_slash_rstrip(result); return result; } @@ -1277,7 +1277,7 @@ static const char *check_destination(const char *file, const char *to) size_t len = 0; str = strip_last_slash(file); - filename = BLI_last_slash(str); + filename = BLI_path_slash_rfind(str); if (!filename) { MEM_freeN(str); @@ -1350,9 +1350,9 @@ bool BLI_dir_create_recursive(const char *dirname) BLI_strncpy(tmp, dirname, size); /* Avoids one useless recursion in case of '/foo/bar/' path... */ - BLI_del_slash(tmp); + BLI_path_slash_rstrip(tmp); - lslash = (char *)BLI_last_slash(tmp); + lslash = (char *)BLI_path_slash_rfind(tmp); if (lslash) { /* Split about the last slash and recurse */ *lslash = 0; diff --git a/source/blender/blenlib/intern/path_util.c b/source/blender/blenlib/intern/path_util.c index 0bb2ba5859b..ad93b643c5e 100644 --- a/source/blender/blenlib/intern/path_util.c +++ b/source/blender/blenlib/intern/path_util.c @@ -80,12 +80,12 @@ static bool BLI_path_is_abs(const char *name); * or from dot if no digits. * \param r_num_len: Optional to return number of digits found. */ -int BLI_stringdec(const char *string, char *head, char *tail, ushort *r_num_len) +int BLI_path_sequence_decode(const char *string, char *head, char *tail, ushort *r_num_len) { uint nums = 0, nume = 0; int i; bool found_digit = false; - const char *const lslash = BLI_last_slash(string); + const char *const lslash = BLI_path_slash_rfind(string); const uint string_len = strlen(string); const uint lslash_len = lslash != NULL ? (int)(lslash - string) : 0; uint name_end = string_len; @@ -151,7 +151,7 @@ int BLI_stringdec(const char *string, char *head, char *tail, ushort *r_num_len) * Returns in area pointed to by string a string of the form "", where pic * is formatted as numlen digits with leading zeroes. */ -void BLI_stringenc( +void BLI_path_sequence_encode( char *string, const char *head, const char *tail, unsigned short numlen, int pic) { sprintf(string, "%s%.*d%s", head, numlen, MAX2(0, pic), tail); @@ -170,7 +170,7 @@ static int BLI_path_unc_prefix_len(const char *path); /* defined below in same f * * \note \a path isn't protected for max string names... */ -void BLI_cleanup_path(const char *relabase, char *path) +void BLI_path_normalize(const char *relabase, char *path) { ptrdiff_t a; char *start, *eind; @@ -263,10 +263,10 @@ void BLI_cleanup_path(const char *relabase, char *path) /** * Cleanup filepath ensuring a trailing slash. */ -void BLI_cleanup_dir(const char *relabase, char *dir) +void BLI_path_normalize_dir(const char *relabase, char *dir) { - BLI_cleanup_path(relabase, dir); - BLI_add_slash(dir); + BLI_path_normalize(relabase, dir); + BLI_path_slash_ensure(dir); } /** @@ -381,8 +381,8 @@ bool BLI_path_make_safe(char *path) } #endif - for (curr_slash = (char *)BLI_first_slash(curr_path); curr_slash; - curr_slash = (char *)BLI_first_slash(curr_path)) { + for (curr_slash = (char *)BLI_path_slash_find(curr_path); curr_slash; + curr_slash = (char *)BLI_path_slash_find(curr_path)) { const char backup = *curr_slash; *curr_slash = '\0'; if (!skip_first && (*curr_path != '\0') && BLI_filename_make_safe(curr_path)) { @@ -494,7 +494,7 @@ static void BLI_path_unc_to_short(wchar_t *unc) } } -void BLI_cleanup_unc(char *path, int maxlen) +void BLI_path_normalize_unc(char *path, int maxlen) { wchar_t *tmp_16 = alloc_utf16_from_8(path, 1); BLI_cleanup_unc_16(tmp_16); @@ -578,11 +578,11 @@ void BLI_path_rel(char *file, const char *relfile) BLI_str_replace_char(file + BLI_path_unc_prefix_len(file), '\\', '/'); /* remove /./ which confuse the following slash counting... */ - BLI_cleanup_path(NULL, file); - BLI_cleanup_path(NULL, temp); + BLI_path_normalize(NULL, file); + BLI_path_normalize(NULL, temp); /* the last slash in the file indicates where the path part ends */ - lslash = BLI_last_slash(temp); + lslash = BLI_path_slash_rfind(temp); if (lslash) { /* find the prefix of the filename that is equal for both filenames. @@ -701,13 +701,13 @@ bool BLI_path_suffix(char *string, size_t maxlen, const char *suffix, const char * Replaces path with the path of its parent directory, returning true if * it was able to find a parent directory within the pathname. */ -bool BLI_parent_dir(char *path) +bool BLI_path_parent_dir(char *path) { const char parent_dir[] = {'.', '.', SEP, '\0'}; /* "../" or "..\\" */ char tmp[FILE_MAX + 4]; BLI_join_dirfile(tmp, sizeof(tmp), path, parent_dir); - BLI_cleanup_path(NULL, tmp); /* does all the work of normalizing the path for us */ + BLI_path_normalize(NULL, tmp); /* does all the work of normalizing the path for us */ if (!BLI_path_extension_check(tmp, parent_dir)) { strcpy(path, tmp); /* We assume pardir is always shorter... */ @@ -722,12 +722,12 @@ bool BLI_parent_dir(char *path) * Strips off nonexistent (or non-accessible) subdirectories from the end of *dir, * leaving the path of the lowest-level directory that does exist and we can read. */ -bool BLI_parent_dir_until_exists(char *dir) +bool BLI_path_parent_dir_until_exists(char *dir) { bool valid_path = true; /* Loop as long as cur path is not a dir, and we can get a parent path. */ - while ((BLI_access(dir, R_OK) != 0) && (valid_path = BLI_parent_dir(dir))) { + while ((BLI_access(dir, R_OK) != 0) && (valid_path = BLI_path_parent_dir(dir))) { /* pass */ } return (valid_path && dir[0]); @@ -777,7 +777,7 @@ static bool stringframe_chars(const char *path, int *char_start, int *char_end) */ static void ensure_digits(char *path, int digits) { - char *file = (char *)BLI_last_slash(path); + char *file = (char *)BLI_path_slash_rfind(path); if (file == NULL) { file = path; @@ -852,7 +852,7 @@ bool BLI_path_frame_range(char *path, int sta, int end, int digits) bool BLI_path_frame_get(char *path, int *r_frame, int *r_numdigits) { if (*path) { - char *file = (char *)BLI_last_slash(path); + char *file = (char *)BLI_path_slash_rfind(path); char *c; int len, numdigits; @@ -908,7 +908,7 @@ void BLI_path_frame_strip(char *path, char *r_ext) return; } - char *file = (char *)BLI_last_slash(path); + char *file = (char *)BLI_path_slash_rfind(path); char *c, *suffix; int len; int numdigits = 0; @@ -1075,8 +1075,8 @@ bool BLI_path_abs(char *path, const char *basepath) BLI_strncpy(base, basepath, sizeof(base)); /* file component is ignored, so don't bother with the trailing slash */ - BLI_cleanup_path(NULL, base); - lslash = BLI_last_slash(base); + BLI_path_normalize(NULL, base); + lslash = BLI_path_slash_rfind(base); BLI_str_replace_char(base + BLI_path_unc_prefix_len(base), '\\', '/'); if (lslash) { @@ -1110,7 +1110,7 @@ bool BLI_path_abs(char *path, const char *basepath) #endif /* ensure this is after correcting for path switch */ - BLI_cleanup_path(NULL, path); + BLI_path_normalize(NULL, path); return wasrelative; } @@ -1363,7 +1363,7 @@ void BLI_make_file_string(const char *relabase, char *string, const char *dir, c /* Get the file name, chop everything past the last slash (ie. the filename) */ strcpy(string, relabase); - lslash = (char *)BLI_last_slash(string); + lslash = (char *)BLI_path_slash_rfind(string); if (lslash) { *(lslash + 1) = 0; } @@ -1418,7 +1418,7 @@ void BLI_make_file_string(const char *relabase, char *string, const char *dir, c strcat(string, file); /* Push all slashes to the system preferred direction */ - BLI_path_native_slash(string); + BLI_path_slash_native(string); } static bool path_extension_check_ex(const char *str, @@ -1608,12 +1608,12 @@ bool BLI_path_extension_ensure(char *path, size_t maxlen, const char *ext) return true; } -bool BLI_ensure_filename(char *filepath, size_t maxlen, const char *filename) +bool BLI_path_filename_ensure(char *filepath, size_t maxlen, const char *filename) { #ifdef DEBUG_STRSIZE memset(filepath, 0xff, sizeof(*filepath) * maxlen); #endif - char *c = (char *)BLI_last_slash(filepath); + char *c = (char *)BLI_path_slash_rfind(filepath); if (!c || ((c - filepath) < maxlen - (strlen(filename) + 1))) { strcpy(c ? &c[1] : filepath, filename); return true; @@ -1636,7 +1636,7 @@ void BLI_split_dirfile( memset(dir, 0xff, sizeof(*dir) * dirlen); memset(file, 0xff, sizeof(*file) * filelen); #endif - const char *lslash_str = BLI_last_slash(string); + const char *lslash_str = BLI_path_slash_rfind(string); const size_t lslash = lslash_str ? (size_t)(lslash_str - string) + 1 : 0; if (dir) { @@ -1680,7 +1680,7 @@ const char *BLI_path_extension(const char *filepath) if (extension == NULL) { return NULL; } - if (BLI_first_slash(extension) != NULL) { + if (BLI_path_slash_find(extension) != NULL) { /* There is a path separator in the extension, so the '.' was found in a * directory component and not in the filename. */ return NULL; @@ -1695,7 +1695,7 @@ void BLI_path_append(char *__restrict dst, const size_t maxlen, const char *__re { size_t dirlen = BLI_strnlen(dst, maxlen); - /* inline BLI_add_slash */ + /* inline BLI_path_slash_ensure */ if ((dirlen > 0) && (dst[dirlen - 1] != SEP)) { dst[dirlen++] = SEP; dst[dirlen] = '\0'; @@ -1738,7 +1738,7 @@ void BLI_join_dirfile(char *__restrict dst, return; /* fills the path */ } - /* inline BLI_add_slash */ + /* inline BLI_path_slash_ensure */ if ((dirlen > 0) && !ELEM(dst[dirlen - 1], SEP, ALTSEP)) { dst[dirlen++] = SEP; dst[dirlen] = '\0'; @@ -1846,7 +1846,7 @@ size_t BLI_path_join(char *__restrict dst, const size_t dst_len, const char *pat */ const char *BLI_path_basename(const char *path) { - const char *const filename = BLI_last_slash(path); + const char *const filename = BLI_path_slash_rfind(path); return filename ? filename + 1 : path; } @@ -1921,7 +1921,7 @@ bool BLI_path_name_at_index(const char *__restrict path, /** * Returns pointer to the leftmost path separator in string. Not actually used anywhere. */ -const char *BLI_first_slash(const char *string) +const char *BLI_path_slash_find(const char *string) { const char *const ffslash = strchr(string, '/'); const char *const fbslash = strchr(string, '\\'); @@ -1939,7 +1939,7 @@ const char *BLI_first_slash(const char *string) /** * Returns pointer to the rightmost path separator in string. */ -const char *BLI_last_slash(const char *string) +const char *BLI_path_slash_rfind(const char *string) { const char *const lfslash = strrchr(string, '/'); const char *const lbslash = strrchr(string, '\\'); @@ -1958,7 +1958,7 @@ const char *BLI_last_slash(const char *string) * Appends a slash to string if there isn't one there already. * Returns the new length of the string. */ -int BLI_add_slash(char *string) +int BLI_path_slash_ensure(char *string) { int len = strlen(string); if (len == 0 || string[len - 1] != SEP) { @@ -1972,7 +1972,7 @@ int BLI_add_slash(char *string) /** * Removes the last slash and everything after it to the end of string, if there is one. */ -void BLI_del_slash(char *string) +void BLI_path_slash_rstrip(char *string) { int len = strlen(string); while (len) { @@ -1989,7 +1989,7 @@ void BLI_del_slash(char *string) /** * Changes to the path separators to the native ones for this OS. */ -void BLI_path_native_slash(char *path) +void BLI_path_slash_native(char *path) { #ifdef WIN32 if (path && BLI_strnlen(path, 3) > 2) { diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c index a47c2e3ea13..07cd39e2559 100644 --- a/source/blender/blenloader/intern/readfile.c +++ b/source/blender/blenloader/intern/readfile.c @@ -664,7 +664,7 @@ static Main *blo_find_main(FileData *fd, const char *filepath, const char *relab char name1[FILE_MAX]; BLI_strncpy(name1, filepath, sizeof(name1)); - BLI_cleanup_path(relabase, name1); + BLI_path_normalize(relabase, name1); // printf("blo_find_main: relabase %s\n", relabase); // printf("blo_find_main: original in %s\n", filepath); @@ -1680,7 +1680,7 @@ bool BLO_library_path_explode(const char *path, char *r_dir, char **r_group, cha strcpy(r_dir, path); - while ((slash = (char *)BLI_last_slash(r_dir))) { + while ((slash = (char *)BLI_path_slash_rfind(r_dir))) { char tc = *slash; *slash = '\0'; if (BLO_has_bfile_extension(r_dir) && BLI_is_file(r_dir)) { @@ -8436,7 +8436,7 @@ static void direct_link_library(FileData *fd, Library *lib, Main *main) /* make sure we have full path in lib->filepath */ BLI_strncpy(lib->filepath, lib->name, sizeof(lib->name)); - BLI_cleanup_path(fd->relabase, lib->filepath); + BLI_path_normalize(fd->relabase, lib->filepath); // printf("direct_link_library: name %s\n", lib->name); // printf("direct_link_library: filepath %s\n", lib->filepath); diff --git a/source/blender/blenloader/intern/writefile.c b/source/blender/blenloader/intern/writefile.c index f0280c78407..fc6ec80e09a 100644 --- a/source/blender/blenloader/intern/writefile.c +++ b/source/blender/blenloader/intern/writefile.c @@ -4348,8 +4348,8 @@ bool BLO_write_file(Main *mainvar, BLI_split_dir_part(filepath, dir_dst, sizeof(dir_dst)); /* Just in case there is some subtle difference. */ - BLI_cleanup_path(mainvar->name, dir_dst); - BLI_cleanup_path(mainvar->name, dir_src); + BLI_path_normalize(mainvar->name, dir_dst); + BLI_path_normalize(mainvar->name, dir_src); if (G.relbase_valid && (BLI_path_cmp(dir_dst, dir_src) == 0)) { /* Saved to same path. Nothing to do. */ diff --git a/source/blender/editors/space_buttons/buttons_ops.c b/source/blender/editors/space_buttons/buttons_ops.c index e2affa7bc36..9af623d8065 100644 --- a/source/blender/editors/space_buttons/buttons_ops.c +++ b/source/blender/editors/space_buttons/buttons_ops.c @@ -110,7 +110,7 @@ static int file_browse_exec(bContext *C, wmOperator *op) if (BLI_is_dir(path)) { /* do this first so '//' isnt converted to '//\' on windows */ - BLI_add_slash(path); + BLI_path_slash_ensure(path); if (is_relative) { BLI_strncpy(path, str, FILE_MAX); BLI_path_rel(path, BKE_main_blendfile_path(bmain)); @@ -122,7 +122,7 @@ static int file_browse_exec(bContext *C, wmOperator *op) } } else { - char *const lslash = (char *)BLI_last_slash(str); + char *const lslash = (char *)BLI_path_slash_rfind(str); if (lslash) { lslash[1] = '\0'; } @@ -187,7 +187,7 @@ static int file_browse_invoke(bContext *C, wmOperator *op, const wmEvent *event) PointerRNA props_ptr; if (event->alt) { - char *lslash = (char *)BLI_last_slash(str); + char *lslash = (char *)BLI_path_slash_rfind(str); if (lslash) { *lslash = '\0'; } diff --git a/source/blender/editors/space_clip/clip_buttons.c b/source/blender/editors/space_clip/clip_buttons.c index dc85b3959e1..3b1cc6fcab0 100644 --- a/source/blender/editors/space_clip/clip_buttons.c +++ b/source/blender/editors/space_clip/clip_buttons.c @@ -872,7 +872,7 @@ void uiTemplateMovieclipInformation(uiLayout *layout, if (framenr <= clip->len) { BKE_movieclip_filename_for_frame(clip, user, filepath); - file = BLI_last_slash(filepath); + file = BLI_path_slash_rfind(filepath); } else { file = "-"; diff --git a/source/blender/editors/space_clip/clip_ops.c b/source/blender/editors/space_clip/clip_ops.c index 48bc885405d..266212fdfd7 100644 --- a/source/blender/editors/space_clip/clip_ops.c +++ b/source/blender/editors/space_clip/clip_ops.c @@ -286,7 +286,7 @@ static int open_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event) BLI_strncpy(path, clip->name, sizeof(path)); BLI_path_abs(path, CTX_data_main(C)->name); - BLI_parent_dir(path); + BLI_path_parent_dir(path); } else { BLI_strncpy(path, U.textudir, sizeof(path)); diff --git a/source/blender/editors/space_file/file_ops.c b/source/blender/editors/space_file/file_ops.c index 7cce243696d..a5263378850 100644 --- a/source/blender/editors/space_file/file_ops.c +++ b/source/blender/editors/space_file/file_ops.c @@ -211,7 +211,7 @@ static FileSelect file_select_do(bContext *C, int selected_idx, bool do_diropen) else { if (is_parent_dir) { /* avoids /../../ */ - BLI_parent_dir(params->dir); + BLI_path_parent_dir(params->dir); if (params->recursion_level > 1) { /* Disable 'dirtree' recursion when going up in tree. */ @@ -220,9 +220,9 @@ static FileSelect file_select_do(bContext *C, int selected_idx, bool do_diropen) } } else { - BLI_cleanup_dir(BKE_main_blendfile_path(bmain), params->dir); + BLI_path_normalize_dir(BKE_main_blendfile_path(bmain), params->dir); strcat(params->dir, file->relpath); - BLI_add_slash(params->dir); + BLI_path_slash_ensure(params->dir); } ED_file_change_dir(C); @@ -940,7 +940,7 @@ static int bookmark_select_exec(bContext *C, wmOperator *op) RNA_property_string_get(op->ptr, prop, entry); BLI_strncpy(params->dir, entry, sizeof(params->dir)); - BLI_cleanup_dir(BKE_main_blendfile_path(bmain), params->dir); + BLI_path_normalize_dir(BKE_main_blendfile_path(bmain), params->dir); ED_file_change_dir(C); WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_LIST, NULL); @@ -1627,12 +1627,12 @@ static int file_exec(bContext *C, wmOperator *exec_op) } if (FILENAME_IS_PARENT(file->relpath)) { - BLI_parent_dir(sfile->params->dir); + BLI_path_parent_dir(sfile->params->dir); } else { - BLI_cleanup_path(BKE_main_blendfile_path(bmain), sfile->params->dir); + BLI_path_normalize(BKE_main_blendfile_path(bmain), sfile->params->dir); BLI_path_append(sfile->params->dir, sizeof(sfile->params->dir) - 1, file->relpath); - BLI_add_slash(sfile->params->dir); + BLI_path_slash_ensure(sfile->params->dir); } if (file->redirection_path) { STRNCPY(sfile->params->dir, file->redirection_path); @@ -1754,8 +1754,8 @@ static int file_parent_exec(bContext *C, wmOperator *UNUSED(unused)) SpaceFile *sfile = CTX_wm_space_file(C); if (sfile->params) { - if (BLI_parent_dir(sfile->params->dir)) { - BLI_cleanup_dir(BKE_main_blendfile_path(bmain), sfile->params->dir); + if (BLI_path_parent_dir(sfile->params->dir)) { + BLI_path_normalize_dir(BKE_main_blendfile_path(bmain), sfile->params->dir); ED_file_change_dir(C); if (sfile->params->recursion_level > 1) { /* Disable 'dirtree' recursion when going up in tree. */ @@ -2274,7 +2274,7 @@ static void file_expand_directory(bContext *C) sfile->params->dir[3] = '\0'; } else if (BLI_path_is_unc(sfile->params->dir)) { - BLI_cleanup_unc(sfile->params->dir, FILE_MAX_LIBEXTRA); + BLI_path_normalize_unc(sfile->params->dir, FILE_MAX_LIBEXTRA); } #endif } @@ -2291,7 +2291,7 @@ static bool can_create_dir(const char *dir) if (BLI_path_is_unc(dir)) { char parent[PATH_MAX]; BLI_strncpy(parent, dir, PATH_MAX); - BLI_parent_dir(parent); + BLI_path_parent_dir(parent); return BLI_is_dir(parent); } return true; @@ -2338,7 +2338,7 @@ void file_directory_enter_handle(bContext *C, void *UNUSED(arg_unused), void *UN } } - BLI_cleanup_dir(BKE_main_blendfile_path(bmain), sfile->params->dir); + BLI_path_normalize_dir(BKE_main_blendfile_path(bmain), sfile->params->dir); if (filelist_is_dir(sfile->files, sfile->params->dir)) { if (!STREQ(sfile->params->dir, old_dir)) { /* Avoids flickering when nothing's changed. */ @@ -2423,7 +2423,7 @@ void file_filename_enter_handle(bContext *C, void *UNUSED(arg_unused), void *arg /* if directory, open it and empty filename field */ if (filelist_is_dir(sfile->files, filepath)) { - BLI_cleanup_dir(BKE_main_blendfile_path(bmain), filepath); + BLI_path_normalize_dir(BKE_main_blendfile_path(bmain), filepath); BLI_strncpy(sfile->params->dir, filepath, sizeof(sfile->params->dir)); sfile->params->file[0] = '\0'; ED_file_change_dir(C); @@ -2487,7 +2487,7 @@ static bool file_filenum_poll(bContext *C) } /** - * Looks for a string of digits within name (using BLI_stringdec) and adjusts it by add. + * Looks for a string of digits within name (using BLI_path_sequence_decode) and adjusts it by add. */ static void filenum_newname(char *name, size_t name_size, int add) { @@ -2496,7 +2496,7 @@ static void filenum_newname(char *name, size_t name_size, int add) int pic; ushort digits; - pic = BLI_stringdec(name, head, tail, &digits); + pic = BLI_path_sequence_decode(name, head, tail, &digits); /* are we going from 100 -> 99 or from 10 -> 9 */ if (add < 0 && digits > 0) { @@ -2514,7 +2514,7 @@ static void filenum_newname(char *name, size_t name_size, int add) if (pic < 0) { pic = 0; } - BLI_stringenc(name_temp, head, tail, digits, pic); + BLI_path_sequence_encode(name_temp, head, tail, digits, pic); BLI_strncpy(name, name_temp, name_size); } diff --git a/source/blender/editors/space_file/filelist.c b/source/blender/editors/space_file/filelist.c index 126430986a5..778c27e1a17 100644 --- a/source/blender/editors/space_file/filelist.c +++ b/source/blender/editors/space_file/filelist.c @@ -635,7 +635,7 @@ static bool is_hidden_dot_filename(const char *filename, FileListInternEntry *fi /* filename might actually be a piece of path, in which case we have to check all its parts. */ bool hidden = false; - char *sep = (char *)BLI_last_slash(filename); + char *sep = (char *)BLI_path_slash_rfind(filename); if (!hidden && sep) { char tmp_filename[FILE_MAX_LIBEXTRA]; @@ -654,7 +654,7 @@ static bool is_hidden_dot_filename(const char *filename, FileListInternEntry *fi break; } *sep = '\0'; - sep = (char *)BLI_last_slash(tmp_filename); + sep = (char *)BLI_path_slash_rfind(tmp_filename); } } return hidden; @@ -1023,7 +1023,7 @@ static int filelist_geticon_ex(FileDirEntry *file, FSMenuEntry *tfsm = ED_fsmenu_get_category(fsmenu, categories[i]); char fullpath[FILE_MAX_LIBEXTRA]; BLI_join_dirfile(fullpath, sizeof(fullpath), root, file->relpath); - BLI_add_slash(fullpath); + BLI_path_slash_ensure(fullpath); for (; tfsm; tfsm = tfsm->next) { if (STREQ(tfsm->path, fullpath)) { /* Never want a little folder inside a large one. */ @@ -1112,7 +1112,7 @@ int filelist_geticon(struct FileList *filelist, const int index, const bool is_m static void parent_dir_until_exists_or_default_root(char *dir) { - if (!BLI_parent_dir_until_exists(dir)) { + if (!BLI_path_parent_dir_until_exists(dir)) { #ifdef WIN32 get_default_root(dir); #else @@ -1624,7 +1624,7 @@ void filelist_setdir(struct FileList *filelist, char *r_dir) { BLI_assert(strlen(r_dir) < FILE_MAX_LIBEXTRA); - BLI_cleanup_dir(BKE_main_blendfile_path_from_global(), r_dir); + BLI_path_normalize_dir(BKE_main_blendfile_path_from_global(), r_dir); const bool is_valid_path = filelist->checkdirf(filelist, r_dir, true); BLI_assert(is_valid_path); UNUSED_VARS_NDEBUG(is_valid_path); @@ -2448,7 +2448,7 @@ static int groupname_to_code(const char *group) BLI_assert(group); BLI_strncpy(buf, group, sizeof(buf)); - lslash = (char *)BLI_last_slash(buf); + lslash = (char *)BLI_path_slash_rfind(buf); if (lslash) { lslash[0] = '\0'; } @@ -2816,7 +2816,7 @@ static void filelist_readjob_do(const bool do_lib, BLI_strncpy(dir, filelist->filelist.root, sizeof(dir)); BLI_strncpy(filter_glob, filelist->filter_data.filter_glob, sizeof(filter_glob)); - BLI_cleanup_dir(main_name, dir); + BLI_path_normalize_dir(main_name, dir); td_dir->dir = BLI_strdup(dir); while (!BLI_stack_is_empty(todo_dirs) && !(*stop)) { @@ -2842,7 +2842,7 @@ static void filelist_readjob_do(const bool do_lib, * Note that in the end, this means we 'cache' valid relative subdir once here, * this is actually better. */ BLI_strncpy(rel_subdir, subdir, sizeof(rel_subdir)); - BLI_cleanup_dir(root, rel_subdir); + BLI_path_normalize_dir(root, rel_subdir); BLI_path_rel(rel_subdir, root); if (do_lib) { @@ -2884,7 +2884,7 @@ static void filelist_readjob_do(const bool do_lib, else { /* We have a directory we want to list, add it to todo list! */ BLI_join_dirfile(dir, sizeof(dir), root, entry->relpath); - BLI_cleanup_dir(main_name, dir); + BLI_path_normalize_dir(main_name, dir); td_dir = BLI_stack_push_r(todo_dirs); td_dir->level = recursion_level + 1; td_dir->dir = BLI_strdup(dir); diff --git a/source/blender/editors/space_file/filesel.c b/source/blender/editors/space_file/filesel.c index 67c0fae3565..6b594c02c15 100644 --- a/source/blender/editors/space_file/filesel.c +++ b/source/blender/editors/space_file/filesel.c @@ -156,7 +156,7 @@ short ED_fileselect_set_params(SpaceFile *sfile) } if (params->dir[0]) { - BLI_cleanup_dir(blendfile_path, params->dir); + BLI_path_normalize_dir(blendfile_path, params->dir); BLI_path_abs(params->dir, blendfile_path); } @@ -924,7 +924,7 @@ int autocomplete_directory(struct bContext *C, char *str, void *UNUSED(arg_v)) match = UI_autocomplete_end(autocpl, str); if (match == AUTOCOMPLETE_FULL_MATCH) { - BLI_add_slash(str); + BLI_path_slash_ensure(str); } } } diff --git a/source/blender/editors/space_image/image_buttons.c b/source/blender/editors/space_image/image_buttons.c index 873091bd68d..3658ebae3a2 100644 --- a/source/blender/editors/space_image/image_buttons.c +++ b/source/blender/editors/space_image/image_buttons.c @@ -1276,7 +1276,7 @@ void uiTemplateImageInfo(uiLayout *layout, bContext *C, Image *ima, ImageUser *i } else if (ima->source == IMA_SRC_SEQUENCE && ibuf) { /* Image sequence frame number + filename */ - const char *filename = BLI_last_slash(ibuf->name); + const char *filename = BLI_path_slash_rfind(ibuf->name); filename = (filename == NULL) ? ibuf->name : filename + 1; BLI_snprintf(str, MAX_IMAGE_INFO_LEN, TIP_("Frame %d: %s"), framenr, filename); } diff --git a/source/blender/editors/space_image/image_ops.c b/source/blender/editors/space_image/image_ops.c index 67e64c52051..14245327bdd 100644 --- a/source/blender/editors/space_image/image_ops.c +++ b/source/blender/editors/space_image/image_ops.c @@ -1794,7 +1794,8 @@ static int image_save_options_init(Main *bmain, } /* append UDIM numbering if not present */ - if (ima->source == IMA_SRC_TILED && (BLI_stringdec(ima->name, NULL, NULL, NULL) != 1001)) { + if (ima->source == IMA_SRC_TILED && + (BLI_path_sequence_decode(ima->name, NULL, NULL, NULL) != 1001)) { int len = strlen(opts->filepath); STR_CONCAT(opts->filepath, len, ".1001"); } diff --git a/source/blender/editors/space_image/image_sequence.c b/source/blender/editors/space_image/image_sequence.c index 8b298045597..e65924d0eb9 100644 --- a/source/blender/editors/space_image/image_sequence.c +++ b/source/blender/editors/space_image/image_sequence.c @@ -74,7 +74,7 @@ static void image_sequence_get_frame_ranges(wmOperator *op, ListBase *ranges) ImageFrame *frame = MEM_callocN(sizeof(ImageFrame), "image_frame"); /* use the first file in the list as base filename */ - frame->framenr = BLI_stringdec(filename, head, tail, &digits); + frame->framenr = BLI_path_sequence_decode(filename, head, tail, &digits); /* still in the same sequence */ if (do_frame_range && (range != NULL) && (STREQLEN(base_head, head, FILE_MAX)) && @@ -127,7 +127,7 @@ static int image_get_udim(char *filepath, ListBase *udim_tiles) ushort digits; char base_head[FILE_MAX], base_tail[FILE_MAX]; - int id = BLI_stringdec(filename, base_head, base_tail, &digits); + int id = BLI_path_sequence_decode(filename, base_head, base_tail, &digits); if (id < 1001 || id >= IMA_UDIM_MAX) { return 0; @@ -144,7 +144,7 @@ static int image_get_udim(char *filepath, ListBase *udim_tiles) continue; } char head[FILE_MAX], tail[FILE_MAX]; - id = BLI_stringdec(dir[i].relname, head, tail, &digits); + id = BLI_path_sequence_decode(dir[i].relname, head, tail, &digits); if (digits > 4 || !(STREQLEN(base_head, head, FILE_MAX)) || !(STREQLEN(base_tail, tail, FILE_MAX))) { @@ -166,7 +166,7 @@ static int image_get_udim(char *filepath, ListBase *udim_tiles) if (is_udim && has_primary) { char primary_filename[FILE_MAX]; - BLI_stringenc(primary_filename, base_head, base_tail, digits, 1001); + BLI_path_sequence_encode(primary_filename, base_head, base_tail, digits, 1001); BLI_join_dirfile(filepath, FILE_MAX, dirname, primary_filename); return max_udim - 1000; } diff --git a/source/blender/freestyle/intern/application/Controller.cpp b/source/blender/freestyle/intern/application/Controller.cpp index f7da64624e0..c2f6796bf31 100644 --- a/source/blender/freestyle/intern/application/Controller.cpp +++ b/source/blender/freestyle/intern/application/Controller.cpp @@ -349,7 +349,7 @@ int Controller::LoadMesh(Render *re, ViewLayer *view_layer, Depsgraph *depsgraph soc string basename((const char *)qfi.fileName().toAscii().data()); char cleaned[FILE_MAX]; BLI_strncpy(cleaned, iFileName, FILE_MAX); - BLI_cleanup_path(NULL, cleaned); + BLI_path_normalize(NULL, cleaned); string basename = string(cleaned); #endif diff --git a/source/blender/freestyle/intern/system/StringUtils.cpp b/source/blender/freestyle/intern/system/StringUtils.cpp index 58d84010574..cd85aaaa5ff 100644 --- a/source/blender/freestyle/intern/system/StringUtils.cpp +++ b/source/blender/freestyle/intern/system/StringUtils.cpp @@ -48,7 +48,7 @@ void getPathName(const string &path, const string &base, vector &pathnam dir = path.substr(pos, sep - pos); BLI_strncpy(cleaned, dir.c_str(), FILE_MAX); - BLI_cleanup_path(NULL, cleaned); + BLI_path_normalize(NULL, cleaned); res = string(cleaned); if (!base.empty()) { diff --git a/source/blender/imbuf/intern/anim_movie.c b/source/blender/imbuf/intern/anim_movie.c index e9ac40de442..11b30a24cde 100644 --- a/source/blender/imbuf/intern/anim_movie.c +++ b/source/blender/imbuf/intern/anim_movie.c @@ -154,7 +154,7 @@ static int an_stringdec(const char *string, char *head, char *tail, unsigned sho static void an_stringenc( char *string, const char *head, const char *tail, unsigned short numlen, int pic) { - BLI_stringenc(string, head, tail, numlen, pic); + BLI_path_sequence_encode(string, head, tail, numlen, pic); } #ifdef WITH_AVI diff --git a/source/blender/io/collada/ImageExporter.cpp b/source/blender/io/collada/ImageExporter.cpp index 9d2b873f862..1cd3301b8a8 100644 --- a/source/blender/io/collada/ImageExporter.cpp +++ b/source/blender/io/collada/ImageExporter.cpp @@ -108,7 +108,7 @@ void ImagesExporter::export_UV_Image(Image *image, bool use_copies) /* make absolute source path */ BLI_strncpy(source_path, image->name, sizeof(source_path)); BLI_path_abs(source_path, ID_BLEND_PATH_FROM_GLOBAL(&image->id)); - BLI_cleanup_path(NULL, source_path); + BLI_path_normalize(NULL, source_path); if (use_copies) { diff --git a/source/blender/makesrna/intern/rna_userdef.c b/source/blender/makesrna/intern/rna_userdef.c index b107c89388d..f52307355c2 100644 --- a/source/blender/makesrna/intern/rna_userdef.c +++ b/source/blender/makesrna/intern/rna_userdef.c @@ -544,7 +544,7 @@ static void rna_Userdef_disk_cache_dir_update(Main *UNUSED(bmain), { if (U.sequencer_disk_cache_dir[0] != '\0') { BLI_path_abs(U.sequencer_disk_cache_dir, BKE_main_blendfile_path_from_global()); - BLI_add_slash(U.sequencer_disk_cache_dir); + BLI_path_slash_ensure(U.sequencer_disk_cache_dir); BLI_path_make_safe(U.sequencer_disk_cache_dir); } diff --git a/source/blender/windowmanager/intern/wm_files.c b/source/blender/windowmanager/intern/wm_files.c index 95c7afcbf15..fe4305830ab 100644 --- a/source/blender/windowmanager/intern/wm_files.c +++ b/source/blender/windowmanager/intern/wm_files.c @@ -2298,7 +2298,7 @@ static bool wm_open_mainfile_check(bContext *UNUSED(C), wmOperator *op) RNA_string_get(op->ptr, "filepath", path); /* get the dir */ - lslash = (char *)BLI_last_slash(path); + lslash = (char *)BLI_path_slash_rfind(path); if (lslash) { *(lslash + 1) = '\0'; } @@ -2536,7 +2536,7 @@ void WM_OT_recover_auto_save(wmOperatorType *ot) static void wm_filepath_default(char *filepath) { if (G.save_over == false) { - BLI_ensure_filename(filepath, FILE_MAX, "untitled.blend"); + BLI_path_filename_ensure(filepath, FILE_MAX, "untitled.blend"); } } diff --git a/source/blender/windowmanager/intern/wm_files_link.c b/source/blender/windowmanager/intern/wm_files_link.c index 5acc8a5fbc6..da4e4160724 100644 --- a/source/blender/windowmanager/intern/wm_files_link.c +++ b/source/blender/windowmanager/intern/wm_files_link.c @@ -104,7 +104,7 @@ static int wm_link_append_invoke(bContext *C, wmOperator *op, const wmEvent *UNU else if (G.relbase_valid) { char path[FILE_MAX]; BLI_strncpy(path, BKE_main_blendfile_path_from_global(), sizeof(path)); - BLI_parent_dir(path); + BLI_path_parent_dir(path); RNA_string_set(op->ptr, "filepath", path); } } diff --git a/source/blender/windowmanager/intern/wm_playanim.c b/source/blender/windowmanager/intern/wm_playanim.c index 8a872010ecc..84f099b0dbc 100644 --- a/source/blender/windowmanager/intern/wm_playanim.c +++ b/source/blender/windowmanager/intern/wm_playanim.c @@ -429,7 +429,8 @@ static void build_pict_list_ex( } fp_decoded; BLI_strncpy(filepath, first, sizeof(filepath)); - fp_framenr = BLI_stringdec(filepath, fp_decoded.head, fp_decoded.tail, &fp_decoded.digits); + fp_framenr = BLI_path_sequence_decode( + filepath, fp_decoded.head, fp_decoded.tail, &fp_decoded.digits); pupdate_time(); ptottime = 1.0; @@ -522,7 +523,8 @@ static void build_pict_list_ex( /* create a new filepath each time */ fp_framenr += fstep; - BLI_stringenc(filepath, fp_decoded.head, fp_decoded.tail, fp_decoded.digits, fp_framenr); + BLI_path_sequence_encode( + filepath, fp_decoded.head, fp_decoded.tail, fp_decoded.digits, fp_framenr); while ((hasevent = GHOST_ProcessEvents(g_WS.ghost_system, 0))) { GHOST_DispatchEvents(g_WS.ghost_system); diff --git a/tests/gtests/blenlib/BLI_path_util_test.cc b/tests/gtests/blenlib/BLI_path_util_test.cc index 18d7a9c4fea..480d48d6080 100644 --- a/tests/gtests/blenlib/BLI_path_util_test.cc +++ b/tests/gtests/blenlib/BLI_path_util_test.cc @@ -58,59 +58,59 @@ char *zLhm65070058860608_br_find_exe(const char *default_exe) /* -------------------------------------------------------------------- */ /* tests */ -/* BLI_cleanup_path */ +/* BLI_path_normalize */ #ifndef _WIN32 TEST(path_util, Clean) { /* "/./" -> "/" */ { char path[FILE_MAX] = "/a/./b/./c/./"; - BLI_cleanup_path(NULL, path); + BLI_path_normalize(NULL, path); EXPECT_STREQ("/a/b/c/", path); } { char path[FILE_MAX] = "/./././"; - BLI_cleanup_path(NULL, path); + BLI_path_normalize(NULL, path); EXPECT_STREQ("/", path); } { char path[FILE_MAX] = "/a/./././b/"; - BLI_cleanup_path(NULL, path); + BLI_path_normalize(NULL, path); EXPECT_STREQ("/a/b/", path); } /* "//" -> "/" */ { char path[FILE_MAX] = "a////"; - BLI_cleanup_path(NULL, path); + BLI_path_normalize(NULL, path); EXPECT_STREQ("a/", path); } if (0) /* FIXME */ { char path[FILE_MAX] = "./a////"; - BLI_cleanup_path(NULL, path); + BLI_path_normalize(NULL, path); EXPECT_STREQ("./a/", path); } /* "foo/bar/../" -> "foo/" */ { char path[FILE_MAX] = "/a/b/c/../../../"; - BLI_cleanup_path(NULL, path); + BLI_path_normalize(NULL, path); EXPECT_STREQ("/", path); } { char path[FILE_MAX] = "/a/../a/b/../b/c/../c/"; - BLI_cleanup_path(NULL, path); + BLI_path_normalize(NULL, path); EXPECT_STREQ("/a/b/c/", path); } { char path[FILE_MAX] = "//../"; - BLI_cleanup_path("/a/b/c/", path); + BLI_path_normalize("/a/b/c/", path); EXPECT_STREQ("/a/b/", path); } } -- cgit v1.2.3 From 7c4391e6aa88e18231302e733481b26afa0072bd Mon Sep 17 00:00:00 2001 From: mano-wii Date: Tue, 7 Apr 2020 13:42:50 +1000 Subject: Fix T60069: repeated extrusion uses wrong axis --- source/blender/editors/transform/transform.c | 1 + 1 file changed, 1 insertion(+) diff --git a/source/blender/editors/transform/transform.c b/source/blender/editors/transform/transform.c index c48c86bd423..c1e890ed5f1 100644 --- a/source/blender/editors/transform/transform.c +++ b/source/blender/editors/transform/transform.c @@ -1767,6 +1767,7 @@ void saveTransform(bContext *C, TransInfo *t, wmOperator *op) } else { orientation = V3D_ORIENT_GLOBAL; + unit_m3(t->spacemtx); } if ((prop = RNA_struct_find_property(op->ptr, "orient_axis"))) { -- cgit v1.2.3 From a1eb5ec81c8116e09f62b123cf6facbff5967e25 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Tue, 7 Apr 2020 14:44:13 +1000 Subject: Cleanup: doxy sections, move utility function to editmesh_utils.c --- source/blender/editors/include/ED_mesh.h | 13 +++-- source/blender/editors/mesh/editmesh_tools.c | 80 ++++++++++++---------------- source/blender/editors/mesh/editmesh_utils.c | 46 ++++++++++++++++ 3 files changed, 86 insertions(+), 53 deletions(-) diff --git a/source/blender/editors/include/ED_mesh.h b/source/blender/editors/include/ED_mesh.h index 7f69bcb25cd..20e54df1ccb 100644 --- a/source/blender/editors/include/ED_mesh.h +++ b/source/blender/editors/include/ED_mesh.h @@ -139,6 +139,12 @@ bool BMBVH_EdgeVisible(struct BMBVHTree *tree, struct View3D *v3d, struct Object *obedit); +void EDBM_project_snap_verts(struct bContext *C, + struct Depsgraph *depsgraph, + struct ARegion *region, + struct Object *obedit, + struct BMEditMesh *em); + /* editmesh_automerge.c */ void EDBM_automerge(struct Object *ob, bool update, const char hflag, const float dist); void EDBM_automerge_and_split(struct Object *ob, @@ -293,13 +299,6 @@ void ED_operatortypes_mesh(void); void ED_operatormacros_mesh(void); void ED_keymap_mesh(struct wmKeyConfig *keyconf); -/* editmesh_tools.c (could be moved) */ -void EDBM_project_snap_verts(struct bContext *C, - struct Depsgraph *depsgraph, - struct ARegion *region, - struct Object *obedit, - struct BMEditMesh *em); - /* editface.c */ void paintface_flush_flags(struct bContext *C, struct Object *ob, short flag); bool paintface_mouse_select(struct bContext *C, diff --git a/source/blender/editors/mesh/editmesh_tools.c b/source/blender/editors/mesh/editmesh_tools.c index b9ac24e1d03..bdec7987201 100644 --- a/source/blender/editors/mesh/editmesh_tools.c +++ b/source/blender/editors/mesh/editmesh_tools.c @@ -71,7 +71,6 @@ #include "ED_object.h" #include "ED_screen.h" #include "ED_transform.h" -#include "ED_transform_snap_object_context.h" #include "ED_uvedit.h" #include "ED_view3d.h" @@ -410,45 +409,6 @@ void MESH_OT_unsubdivide(wmOperatorType *ot) ot->srna, "iterations", 2, 1, 1000, "Iterations", "Number of times to unsubdivide", 1, 100); } -void EDBM_project_snap_verts( - bContext *C, Depsgraph *depsgraph, ARegion *region, Object *obedit, BMEditMesh *em) -{ - Main *bmain = CTX_data_main(C); - BMIter iter; - BMVert *eve; - - ED_view3d_init_mats_rv3d(obedit, region->regiondata); - - struct SnapObjectContext *snap_context = ED_transform_snap_object_context_create_view3d( - bmain, CTX_data_scene(C), 0, region, CTX_wm_view3d(C)); - - BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) { - if (BM_elem_flag_test(eve, BM_ELEM_SELECT)) { - float mval[2], co_proj[3]; - if (ED_view3d_project_float_object(region, eve->co, mval, V3D_PROJ_TEST_NOP) == - V3D_PROJ_RET_OK) { - if (ED_transform_snap_object_project_view3d(snap_context, - depsgraph, - SCE_SNAP_MODE_FACE, - &(const struct SnapObjectParams){ - .snap_select = SNAP_NOT_ACTIVE, - .use_object_edit_cage = false, - .use_occlusion_test = true, - }, - mval, - NULL, - NULL, - co_proj, - NULL)) { - mul_v3_m4v3(eve->co, obedit->imat, co_proj); - } - } - } - } - - ED_transform_snap_object_context_destroy(snap_context); -} - /** \} */ /* -------------------------------------------------------------------- */ @@ -1186,6 +1146,12 @@ void MESH_OT_mark_sharp(wmOperatorType *ot) RNA_def_property_flag(prop, PROP_SKIP_SAVE); } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Connect Vertex Path Operator + * \{ */ + static bool edbm_connect_vert_pair(BMEditMesh *em, struct Mesh *me, wmOperator *op) { BMesh *bm = em->bm; @@ -1311,7 +1277,7 @@ void MESH_OT_vert_connect(wmOperatorType *ot) /** \} */ /* -------------------------------------------------------------------- */ -/** \name Split Concave Faces Operator +/** \name Connect Vertex Path Operator * \{ */ /** @@ -1600,6 +1566,12 @@ void MESH_OT_vert_connect_path(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Connect Concave Operator + * \{ */ + static int edbm_vert_connect_concave_exec(bContext *C, wmOperator *op) { ViewLayer *view_layer = CTX_data_view_layer(C); @@ -3210,7 +3182,7 @@ void MESH_OT_merge(wmOperatorType *ot) /** \} */ /* -------------------------------------------------------------------- */ -/** \name Remove Doubles Operator +/** \name Merge By Distance Operator * \{ */ static int edbm_remove_doubles_exec(bContext *C, wmOperator *op) @@ -7812,7 +7784,11 @@ wmKeyMap *point_normals_modal_keymap(wmKeyConfig *keyconf) #define CLNORS_VALID_VEC_LEN (1e-4f) -/********************** 'Point to' Loop Normals **********************/ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Loop Normals 'Point To' Operator + * \{ */ enum { EDBM_CLNOR_POINTTO_MODE_COORDINATES = 1, @@ -8273,7 +8249,7 @@ void MESH_OT_point_normals(struct wmOperatorType *ot) /** \} */ /* -------------------------------------------------------------------- */ -/** \name Split/Merge Loop Normals +/** \name Split/Merge Loop Normals Operator * \{ */ static void normals_merge(BMesh *bm, BMLoopNorEditDataArray *lnors_ed_arr) @@ -8484,7 +8460,7 @@ void MESH_OT_split_normals(struct wmOperatorType *ot) /** \} */ /* -------------------------------------------------------------------- */ -/** \name Average Loop Normals +/** \name Average Loop Normals Operator * \{ */ enum { @@ -8716,7 +8692,7 @@ void MESH_OT_average_normals(struct wmOperatorType *ot) /** \} */ /* -------------------------------------------------------------------- */ -/** \name Custom Normal Interface Tools +/** \name Custom Normal Interface Tools Operator * \{ */ enum { @@ -8952,6 +8928,12 @@ void MESH_OT_normals_tools(struct wmOperatorType *ot) "Copy Absolute coordinates or Normal vector"); } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Set Normals from Faces Operator + * \{ */ + static int edbm_set_normals_from_faces_exec(bContext *C, wmOperator *op) { ViewLayer *view_layer = CTX_data_view_layer(C); @@ -9059,6 +9041,12 @@ void MESH_OT_set_normals_from_faces(struct wmOperatorType *ot) RNA_def_boolean(ot->srna, "keep_sharp", 0, "Keep Sharp Edges", "Do not set sharp edges to face"); } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Smooth Normal Vectors Operator + * \{ */ + static int edbm_smoothen_normals_exec(bContext *C, wmOperator *op) { ViewLayer *view_layer = CTX_data_view_layer(C); diff --git a/source/blender/editors/mesh/editmesh_utils.c b/source/blender/editors/mesh/editmesh_utils.c index 998e0d736e6..a26003d78ed 100644 --- a/source/blender/editors/mesh/editmesh_utils.c +++ b/source/blender/editors/mesh/editmesh_utils.c @@ -52,6 +52,7 @@ #include "ED_mesh.h" #include "ED_screen.h" +#include "ED_transform_snap_object_context.h" #include "ED_uvedit.h" #include "ED_view3d.h" @@ -1638,3 +1639,48 @@ bool BMBVH_EdgeVisible(struct BMBVHTree *tree, } /** \} */ + +/* -------------------------------------------------------------------- */ +/** \name BMesh Vertex Projection API + * \{ */ + +void EDBM_project_snap_verts( + bContext *C, Depsgraph *depsgraph, ARegion *region, Object *obedit, BMEditMesh *em) +{ + Main *bmain = CTX_data_main(C); + BMIter iter; + BMVert *eve; + + ED_view3d_init_mats_rv3d(obedit, region->regiondata); + + struct SnapObjectContext *snap_context = ED_transform_snap_object_context_create_view3d( + bmain, CTX_data_scene(C), 0, region, CTX_wm_view3d(C)); + + BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) { + if (BM_elem_flag_test(eve, BM_ELEM_SELECT)) { + float mval[2], co_proj[3]; + if (ED_view3d_project_float_object(region, eve->co, mval, V3D_PROJ_TEST_NOP) == + V3D_PROJ_RET_OK) { + if (ED_transform_snap_object_project_view3d(snap_context, + depsgraph, + SCE_SNAP_MODE_FACE, + &(const struct SnapObjectParams){ + .snap_select = SNAP_NOT_ACTIVE, + .use_object_edit_cage = false, + .use_occlusion_test = true, + }, + mval, + NULL, + NULL, + co_proj, + NULL)) { + mul_v3_m4v3(eve->co, obedit->imat, co_proj); + } + } + } + } + + ED_transform_snap_object_context_destroy(snap_context); +} + +/** \} */ -- cgit v1.2.3 From 17193f6c765775ff971cd6399fe0f9cbc4fa793c Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Tue, 7 Apr 2020 15:12:18 +1000 Subject: UI: rename 'smoothen' to 'smooth' Other smooth operators use term 'smooth'. --- release/scripts/modules/rna_manual_reference.py | 2 +- release/scripts/startup/bl_ui/space_view3d.py | 2 +- source/blender/editors/mesh/editmesh_tools.c | 14 +++++++------- source/blender/editors/mesh/mesh_intern.h | 2 +- source/blender/editors/mesh/mesh_ops.c | 2 +- 5 files changed, 11 insertions(+), 11 deletions(-) diff --git a/release/scripts/modules/rna_manual_reference.py b/release/scripts/modules/rna_manual_reference.py index b49c2f959b0..22bea11cbc2 100644 --- a/release/scripts/modules/rna_manual_reference.py +++ b/release/scripts/modules/rna_manual_reference.py @@ -621,7 +621,7 @@ url_manual_mapping = ( ("bpy.ops.mesh.dissolve_limited*", "modeling/meshes/editing/mesh/delete.html#bpy-ops-mesh-dissolve-limited"), ("bpy.ops.mesh.face_make_planar*", "modeling/meshes/editing/mesh/cleanup.html#bpy-ops-mesh-face-make-planar"), ("bpy.ops.mesh.paint_mask_slice*", "sculpt_paint/sculpting/hide_mask.html#bpy-ops-mesh-paint-mask-slice"), - ("bpy.ops.mesh.smoothen_normals*", "modeling/meshes/editing/mesh/normals.html#bpy-ops-mesh-smoothen-normals"), + ("bpy.ops.mesh.smooth_normals*", "modeling/meshes/editing/mesh/normals.html#bpy-ops-mesh-smooth-normals"), ("bpy.ops.object.duplicate_move*", "scene_layout/object/editing/duplicate.html#bpy-ops-object-duplicate-move"), ("bpy.ops.object.hook_add_selob*", "modeling/meshes/editing/vertex/hooks.html#bpy-ops-object-hook-add-selob"), ("bpy.ops.object.select_by_type*", "scene_layout/object/selecting.html#bpy-ops-object-select-by-type"), diff --git a/release/scripts/startup/bl_ui/space_view3d.py b/release/scripts/startup/bl_ui/space_view3d.py index eefcb6a71be..167091815b4 100644 --- a/release/scripts/startup/bl_ui/space_view3d.py +++ b/release/scripts/startup/bl_ui/space_view3d.py @@ -4179,7 +4179,7 @@ class VIEW3D_MT_edit_mesh_normals(Menu): layout.operator("mesh.normals_tools", text="Copy Vectors").mode = 'COPY' layout.operator("mesh.normals_tools", text="Paste Vectors").mode = 'PASTE' - layout.operator("mesh.smoothen_normals", text="Smoothen Vectors") + layout.operator("mesh.smooth_normals", text="Smooth Vectors") layout.operator("mesh.normals_tools", text="Reset Vectors").mode = 'RESET' layout.separator() diff --git a/source/blender/editors/mesh/editmesh_tools.c b/source/blender/editors/mesh/editmesh_tools.c index bdec7987201..ebfb5754acc 100644 --- a/source/blender/editors/mesh/editmesh_tools.c +++ b/source/blender/editors/mesh/editmesh_tools.c @@ -9047,7 +9047,7 @@ void MESH_OT_set_normals_from_faces(struct wmOperatorType *ot) /** \name Smooth Normal Vectors Operator * \{ */ -static int edbm_smoothen_normals_exec(bContext *C, wmOperator *op) +static int edbm_smooth_normals_exec(bContext *C, wmOperator *op) { ViewLayer *view_layer = CTX_data_view_layer(C); uint objects_len = 0; @@ -9100,7 +9100,7 @@ static int edbm_smoothen_normals_exec(bContext *C, wmOperator *op) float current_normal[3]; if (normalize_v3(smooth_normal[i]) < CLNORS_VALID_VEC_LEN) { - /* Skip in case smoothen normal is invalid... */ + /* Skip in case the smooth normal is invalid. */ continue; } @@ -9114,7 +9114,7 @@ static int edbm_smoothen_normals_exec(bContext *C, wmOperator *op) add_v3_v3(current_normal, smooth_normal[i]); if (normalize_v3(current_normal) < CLNORS_VALID_VEC_LEN) { - /* Skip in case smoothen normal is invalid... */ + /* Skip in case the smoothed normal is invalid. */ continue; } @@ -9132,15 +9132,15 @@ static int edbm_smoothen_normals_exec(bContext *C, wmOperator *op) return OPERATOR_FINISHED; } -void MESH_OT_smoothen_normals(struct wmOperatorType *ot) +void MESH_OT_smooth_normals(struct wmOperatorType *ot) { /* identifiers */ ot->name = "Smooth Normals Vectors"; - ot->description = "Smoothen custom normals based on adjacent vertex normals"; - ot->idname = "MESH_OT_smoothen_normals"; + ot->description = "Smooth custom normals based on adjacent vertex normals"; + ot->idname = "MESH_OT_smooth_normals"; /* api callbacks */ - ot->exec = edbm_smoothen_normals_exec; + ot->exec = edbm_smooth_normals_exec; ot->poll = ED_operator_editmesh; /* flags */ diff --git a/source/blender/editors/mesh/mesh_intern.h b/source/blender/editors/mesh/mesh_intern.h index 594429d4925..5e70069456b 100644 --- a/source/blender/editors/mesh/mesh_intern.h +++ b/source/blender/editors/mesh/mesh_intern.h @@ -248,7 +248,7 @@ void MESH_OT_split_normals(struct wmOperatorType *ot); void MESH_OT_normals_tools(struct wmOperatorType *ot); void MESH_OT_set_normals_from_faces(struct wmOperatorType *ot); void MESH_OT_average_normals(struct wmOperatorType *ot); -void MESH_OT_smoothen_normals(struct wmOperatorType *ot); +void MESH_OT_smooth_normals(struct wmOperatorType *ot); void MESH_OT_mod_weighted_strength(struct wmOperatorType *ot); /* *** editmesh_mask_extract.c *** */ diff --git a/source/blender/editors/mesh/mesh_ops.c b/source/blender/editors/mesh/mesh_ops.c index c61fe39b5fd..66b2c66f2aa 100644 --- a/source/blender/editors/mesh/mesh_ops.c +++ b/source/blender/editors/mesh/mesh_ops.c @@ -203,7 +203,7 @@ void ED_operatortypes_mesh(void) WM_operatortype_append(MESH_OT_normals_tools); WM_operatortype_append(MESH_OT_set_normals_from_faces); WM_operatortype_append(MESH_OT_average_normals); - WM_operatortype_append(MESH_OT_smoothen_normals); + WM_operatortype_append(MESH_OT_smooth_normals); WM_operatortype_append(MESH_OT_mod_weighted_strength); } -- cgit v1.2.3 From 284d28acbca58be4eb629b395c64cc9bb0a06bee Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Tue, 7 Apr 2020 15:32:09 +1000 Subject: Cleanup: remove unused BM_total_loop_select function --- source/blender/bmesh/intern/bmesh_mesh.c | 14 -------------- source/blender/bmesh/intern/bmesh_mesh.h | 1 - 2 files changed, 15 deletions(-) diff --git a/source/blender/bmesh/intern/bmesh_mesh.c b/source/blender/bmesh/intern/bmesh_mesh.c index b65d563d441..854421d32d4 100644 --- a/source/blender/bmesh/intern/bmesh_mesh.c +++ b/source/blender/bmesh/intern/bmesh_mesh.c @@ -1628,20 +1628,6 @@ void BM_loop_normal_editdata_array_free(BMLoopNorEditDataArray *lnors_ed_arr) MEM_freeN(lnors_ed_arr); } -int BM_total_loop_select(BMesh *bm) -{ - int r_sel = 0; - BMVert *v; - BMIter viter; - - BM_ITER_MESH (v, &viter, bm, BM_VERTS_OF_MESH) { - if (BM_elem_flag_test(v, BM_ELEM_SELECT)) { - r_sel += BM_vert_face_count(v); - } - } - return r_sel; -} - /** * \brief BMesh Begin Edit * diff --git a/source/blender/bmesh/intern/bmesh_mesh.h b/source/blender/bmesh/intern/bmesh_mesh.h index ea0fea1f603..fa542ba5f12 100644 --- a/source/blender/bmesh/intern/bmesh_mesh.h +++ b/source/blender/bmesh/intern/bmesh_mesh.h @@ -72,7 +72,6 @@ void BM_lnorspace_err(BMesh *bm); struct BMLoopNorEditDataArray *BM_loop_normal_editdata_array_init(BMesh *bm, const bool do_all_loops_of_vert); void BM_loop_normal_editdata_array_free(struct BMLoopNorEditDataArray *lnors_ed_arr); -int BM_total_loop_select(BMesh *bm); void BM_edges_sharp_from_angle_set(BMesh *bm, const float split_angle); -- cgit v1.2.3 From ffe599b4bdbe94a2c9f3edd0476f1e9f210ca97d Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Tue, 7 Apr 2020 16:24:48 +1000 Subject: Fix T68159: Normals point target crashes when exiting edit-mode When the modal operator passes events, free the internal state of the operator as we can't be sure those events don't cause the mesh data to be re-allocated or removed. Longer term it might be best to make this into a tool since the main purpose of this operator is to run other actions. --- source/blender/editors/mesh/editmesh_tools.c | 70 +++++++++++++++++++++------- 1 file changed, 53 insertions(+), 17 deletions(-) diff --git a/source/blender/editors/mesh/editmesh_tools.c b/source/blender/editors/mesh/editmesh_tools.c index ebfb5754acc..ba3520f2217 100644 --- a/source/blender/editors/mesh/editmesh_tools.c +++ b/source/blender/editors/mesh/editmesh_tools.c @@ -7806,7 +7806,7 @@ static EnumPropertyItem clnors_pointto_mode_items[] = { }; /* Initialize loop normal data */ -static int point_normals_init(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) +static bool point_normals_init(bContext *C, wmOperator *op) { Object *obedit = CTX_data_edit_object(C); BMEditMesh *em = BKE_editmesh_from_object(obedit); @@ -7818,14 +7818,29 @@ static int point_normals_init(bContext *C, wmOperator *op, const wmEvent *UNUSED op->customdata = lnors_ed_arr; - return lnors_ed_arr->totloop; + return (lnors_ed_arr->totloop != 0); } -static void point_normals_free(bContext *C, wmOperator *op) +static bool point_normals_ensure(bContext *C, wmOperator *op) { - BMLoopNorEditDataArray *lnors_ed_arr = op->customdata; - BM_loop_normal_editdata_array_free(lnors_ed_arr); - op->customdata = NULL; + if (op->customdata != NULL) { + return true; + } + return point_normals_init(C, op); +} + +static void point_normals_free(wmOperator *op) +{ + if (op->customdata != NULL) { + BMLoopNorEditDataArray *lnors_ed_arr = op->customdata; + BM_loop_normal_editdata_array_free(lnors_ed_arr); + op->customdata = NULL; + } +} + +static void point_normals_cancel(bContext *C, wmOperator *op) +{ + point_normals_free(op); ED_area_status_text(CTX_wm_area(C), NULL); } @@ -7942,6 +7957,13 @@ static void point_normals_apply(bContext *C, wmOperator *op, float target[3], co static int edbm_point_normals_modal(bContext *C, wmOperator *op, const wmEvent *event) { + /* As this operator passes events through, we can't be sure the user didn't exit edit-mode. + * or performed some other operation. */ + if (!WM_operator_poll(C, op->type)) { + point_normals_cancel(C, op); + return OPERATOR_CANCELLED; + } + View3D *v3d = CTX_wm_view3d(C); Scene *scene = CTX_data_scene(C); Object *obedit = CTX_data_edit_object(C); @@ -8112,23 +8134,37 @@ static int edbm_point_normals_modal(bContext *C, wmOperator *op, const wmEvent * if (!ELEM(ret, OPERATOR_CANCELLED, OPERATOR_FINISHED)) { RNA_property_float_set_array(op->ptr, prop_target, target); } - point_normals_apply(C, op, target, do_reset); - EDBM_update_generic(obedit->data, true, false); /* Recheck bools. */ - point_normals_update_header(C, op); + if (point_normals_ensure(C, op)) { + point_normals_apply(C, op, target, do_reset); + EDBM_update_generic(obedit->data, true, false); /* Recheck bools. */ + point_normals_update_header(C, op); + } + else { + ret = OPERATOR_CANCELLED; + } } if (ELEM(ret, OPERATOR_CANCELLED, OPERATOR_FINISHED)) { - point_normals_free(C, op); + point_normals_cancel(C, op); } + /* If we allow other tools to run, we can't be sure if they will re-allocate + * the data this operator uses, see: T68159. + * Free the data here, then use #point_normals_ensure to add it back on demand. */ + if (ret == OPERATOR_PASS_THROUGH) { + /* Don't free on mouse-move, causes creation/freeing of the loop data in an inefficient way. */ + if (!ELEM(event->type, MOUSEMOVE, INBETWEEN_MOUSEMOVE)) { + point_normals_free(op); + } + } return ret; } -static int edbm_point_normals_invoke(bContext *C, wmOperator *op, const wmEvent *event) +static int edbm_point_normals_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { - if (!point_normals_init(C, op, event)) { - point_normals_free(C, op); + if (!point_normals_init(C, op)) { + point_normals_cancel(C, op); return OPERATOR_CANCELLED; } @@ -8145,8 +8181,8 @@ static int edbm_point_normals_exec(bContext *C, wmOperator *op) { Object *obedit = CTX_data_edit_object(C); - if (!point_normals_init(C, op, NULL)) { - point_normals_free(C, op); + if (!point_normals_init(C, op)) { + point_normals_cancel(C, op); return OPERATOR_CANCELLED; } @@ -8159,7 +8195,7 @@ static int edbm_point_normals_exec(bContext *C, wmOperator *op) point_normals_apply(C, op, target, false); EDBM_update_generic(obedit->data, true, false); - point_normals_free(C, op); + point_normals_cancel(C, op); return OPERATOR_FINISHED; } @@ -8204,7 +8240,7 @@ void MESH_OT_point_normals(struct wmOperatorType *ot) ot->modal = edbm_point_normals_modal; ot->poll = ED_operator_editmesh; ot->ui = edbm_point_normals_ui; - ot->cancel = point_normals_free; + ot->cancel = point_normals_cancel; /* flags */ ot->flag = OPTYPE_BLOCKING | OPTYPE_REGISTER | OPTYPE_UNDO; -- cgit v1.2.3 From cdbb61704d7edb9e67452b848b1eebcb3f4b0ae7 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Tue, 7 Apr 2020 17:43:27 +1000 Subject: Fix T75128: Select Linked fails when the selection is a delimiter Starting select linked failed when the selected vertex or edge was it's self delimiting. Support using these elements for linked select as long as they're part of an isolated selection. --- source/blender/bmesh/intern/bmesh_query.c | 16 ++++++++++++++++ source/blender/bmesh/intern/bmesh_query.h | 2 ++ source/blender/editors/mesh/editmesh_select.c | 19 +++++++++++++------ 3 files changed, 31 insertions(+), 6 deletions(-) diff --git a/source/blender/bmesh/intern/bmesh_query.c b/source/blender/bmesh/intern/bmesh_query.c index e3b6e243906..64950411fed 100644 --- a/source/blender/bmesh/intern/bmesh_query.c +++ b/source/blender/bmesh/intern/bmesh_query.c @@ -2431,6 +2431,22 @@ bool BM_edge_is_all_face_flag_test(const BMEdge *e, const char hflag, const bool return true; } +bool BM_edge_is_any_face_flag_test(const BMEdge *e, const char hflag) +{ + if (e->l) { + BMLoop *l_iter, *l_first; + + l_iter = l_first = e->l; + do { + if (BM_elem_flag_test(l_iter->f, hflag)) { + return true; + } + } while ((l_iter = l_iter->radial_next) != l_first); + } + + return false; +} + /* convenience functions for checking flags */ bool BM_edge_is_any_vert_flag_test(const BMEdge *e, const char hflag) { diff --git a/source/blender/bmesh/intern/bmesh_query.h b/source/blender/bmesh/intern/bmesh_query.h index fb646b11076..aaf8191c5db 100644 --- a/source/blender/bmesh/intern/bmesh_query.h +++ b/source/blender/bmesh/intern/bmesh_query.h @@ -226,6 +226,8 @@ bool BM_edge_is_all_face_flag_test(const BMEdge *e, bool BM_edge_is_any_vert_flag_test(const BMEdge *e, const char hflag) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); +bool BM_edge_is_any_face_flag_test(const BMEdge *e, const char hflag) ATTR_WARN_UNUSED_RESULT + ATTR_NONNULL(); bool BM_face_is_any_vert_flag_test(const BMFace *f, const char hflag) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); bool BM_face_is_any_edge_flag_test(const BMFace *f, const char hflag) ATTR_WARN_UNUSED_RESULT diff --git a/source/blender/editors/mesh/editmesh_select.c b/source/blender/editors/mesh/editmesh_select.c index f01511fa513..3847f32b19a 100644 --- a/source/blender/editors/mesh/editmesh_select.c +++ b/source/blender/editors/mesh/editmesh_select.c @@ -3201,8 +3201,12 @@ static int edbm_select_linked_exec(bContext *C, wmOperator *op) BMEdge *e; BM_ITER_MESH (e, &iter, em->bm, BM_EDGES_OF_MESH) { if (!BMO_edge_flag_test(bm, e, BMO_ELE_TAG)) { - BM_elem_flag_disable(e->v1, BM_ELEM_TAG); - BM_elem_flag_disable(e->v2, BM_ELEM_TAG); + /* Check the edge for selected faces, + * this supports stepping off isolated vertices which would otherwise be ignored. */ + if (BM_edge_is_any_face_flag_test(e, BM_ELEM_SELECT)) { + BM_elem_flag_disable(e->v1, BM_ELEM_TAG); + BM_elem_flag_disable(e->v2, BM_ELEM_TAG); + } } } } @@ -3258,10 +3262,13 @@ static int edbm_select_linked_exec(bContext *C, wmOperator *op) if (delimit) { BM_ITER_MESH (e, &iter, em->bm, BM_EDGES_OF_MESH) { - BM_elem_flag_set( - e, - BM_ELEM_TAG, - (BM_elem_flag_test(e, BM_ELEM_SELECT) && BMO_edge_flag_test(bm, e, BMO_ELE_TAG))); + /* Check the edge for selected faces, + * this supports stepping off isolated edges which would otherwise be ignored. */ + BM_elem_flag_set(e, + BM_ELEM_TAG, + (BM_elem_flag_test(e, BM_ELEM_SELECT) && + (BMO_edge_flag_test(bm, e, BMO_ELE_TAG) || + !BM_edge_is_any_face_flag_test(e, BM_ELEM_SELECT)))); } } else { -- cgit v1.2.3 From 49deda4ca223fbfb33912ea7d14f9c2b77155f68 Mon Sep 17 00:00:00 2001 From: Jeroen Bakker Date: Tue, 7 Apr 2020 10:46:44 +0200 Subject: GPUBatch: Correctly Free Panel Widget Batch The GPU Batch for the panel drag widget wasn't freed anywhere. This patch will free the GPUBatch. --- source/blender/gpu/intern/gpu_batch_presets.c | 1 + 1 file changed, 1 insertion(+) diff --git a/source/blender/gpu/intern/gpu_batch_presets.c b/source/blender/gpu/intern/gpu_batch_presets.c index e488880bf0a..34bd921992c 100644 --- a/source/blender/gpu/intern/gpu_batch_presets.c +++ b/source/blender/gpu/intern/gpu_batch_presets.c @@ -310,6 +310,7 @@ GPUBatch *GPU_batch_preset_panel_drag_widget(const float pixelsize, if (g_presets_2d.batch.panel_drag_widget && parameters_changed) { gpu_batch_presets_unregister(g_presets_2d.batch.panel_drag_widget); + GPU_batch_discard(g_presets_2d.batch.panel_drag_widget); g_presets_2d.batch.panel_drag_widget = NULL; } -- cgit v1.2.3 From 9fca9b99534923b69f5b2bb59f51d117aed81bac Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Tue, 7 Apr 2020 11:36:59 +0200 Subject: Fix crash using object.to_mesh() when in edit mode The root of the issue was caused by mesh which was a result of to_mesh() had the same edit_mesh pointer as the input object, causing double-free error. This fix makes it so result mesh does not have edit mesh pointer. Motivation part behind this is to make the result of to_mesh() to be somewhat independent from the input. Differential Revision: https://developer.blender.org/D7361 --- source/blender/blenkernel/intern/mesh_convert.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/source/blender/blenkernel/intern/mesh_convert.c b/source/blender/blenkernel/intern/mesh_convert.c index 74b79490d67..e24718ebe30 100644 --- a/source/blender/blenkernel/intern/mesh_convert.c +++ b/source/blender/blenkernel/intern/mesh_convert.c @@ -1155,9 +1155,21 @@ Mesh *BKE_mesh_new_from_object(Depsgraph *depsgraph, Object *object, bool preser /* Happens in special cases like request of mesh for non-mother meta ball. */ return NULL; } + /* The result must have 0 users, since it's just a mesh which is free-dangling data-block. * All the conversion functions are supposed to ensure mesh is not counted. */ BLI_assert(new_mesh->id.us == 0); + + /* It is possible that mesh came from modifier stack evaluation, which preserves edit_mesh + * pointer (which allows draw manager to access edit mesh when drawing). Normally this does + * not cause ownership problems because evaluated object runtime is keeping track of the real + * ownership. + * + * Here we are constructing a mesh which is supposed to be iondependent, which means no shared + * ownership is allowed, so we make sure edit mesh is reset to NULL (which is similar to as if + * one duplicates the objects and applies all the modifiers). */ + new_mesh->edit_mesh = NULL; + return new_mesh; } -- cgit v1.2.3 From c4def7992b589aaf9f45aca04b5dcb0b760ad36e Mon Sep 17 00:00:00 2001 From: Sebastian Parborg Date: Tue, 7 Apr 2020 13:12:14 +0200 Subject: Fix T73598: Pose options - Auto IK. Bones move on release The issue was that the code tried to use the bones transformation matrix as a rotation matrix. This works fine as long as the scale is 1. Now we simply make sure that we only get a pure rotation matrix when extracting it for the bone's transformation matrix. --- source/blender/editors/transform/transform_convert.c | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/source/blender/editors/transform/transform_convert.c b/source/blender/editors/transform/transform_convert.c index 1e751f67c9d..0beacf1244a 100644 --- a/source/blender/editors/transform/transform_convert.c +++ b/source/blender/editors/transform/transform_convert.c @@ -377,23 +377,25 @@ static short apply_targetless_ik(Object *ob) } for (; segcount; segcount--) { Bone *bone; - float rmat[4][4] /*, tmat[4][4], imat[4][4]*/; + float mat[4][4]; /* pose_mat(b) = pose_mat(b-1) * offs_bone * channel * constraint * IK */ - /* we put in channel the entire result of rmat = (channel * constraint * IK) */ - /* pose_mat(b) = pose_mat(b-1) * offs_bone * rmat */ - /* rmat = pose_mat(b) * inv(pose_mat(b-1) * offs_bone ) */ + /* we put in channel the entire result of mat = (channel * constraint * IK) */ + /* pose_mat(b) = pose_mat(b-1) * offs_bone * mat */ + /* mat = pose_mat(b) * inv(pose_mat(b-1) * offs_bone ) */ parchan = chanlist[segcount - 1]; bone = parchan->bone; bone->flag |= BONE_TRANSFORM; /* ensures it gets an auto key inserted */ - BKE_armature_mat_pose_to_bone(parchan, parchan->pose_mat, rmat); - + BKE_armature_mat_pose_to_bone(parchan, parchan->pose_mat, mat); /* apply and decompose, doesn't work for constraints or non-uniform scale well */ { float rmat3[3][3], qrmat[3][3], imat3[3][3], smat[3][3]; - copy_m3_m4(rmat3, rmat); + + copy_m3_m4(rmat3, mat); + /* Make sure that our rotation matrix only contains rotation and not scale. */ + normalize_m3(rmat3); /* rotation */ /* [#22409] is partially caused by this, as slight numeric error introduced during @@ -413,7 +415,7 @@ static short apply_targetless_ik(Object *ob) /* causes problems with some constraints (e.g. childof), so disable this */ /* as it is IK shouldn't affect location directly */ - /* copy_v3_v3(parchan->loc, rmat[3]); */ + /* copy_v3_v3(parchan->loc, mat[3]); */ } } -- cgit v1.2.3 From 0aac74f18f2d4de1cdde6ca9bf4f8b9a97085d28 Mon Sep 17 00:00:00 2001 From: Brecht Van Lommel Date: Fri, 3 Apr 2020 13:34:12 +0200 Subject: Cleanup: split off direct_link_id() function Differential Revision: https://developer.blender.org/D7324 --- source/blender/blenloader/intern/readfile.c | 365 ++++++++++++++-------------- 1 file changed, 187 insertions(+), 178 deletions(-) diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c index 07cd39e2559..3c5908efa3f 100644 --- a/source/blender/blenloader/intern/readfile.c +++ b/source/blender/blenloader/intern/readfile.c @@ -470,8 +470,9 @@ static void *oldnewmap_liblookup(OldNewMap *onm, const void *addr, const void *l return NULL; } -static void oldnewmap_free_unused(OldNewMap *onm) +static void oldnewmap_clear(OldNewMap *onm) { + /* Free unused data. */ for (int i = 0; i < onm->nentries; i++) { OldNew *entry = &onm->entries[i]; if (entry->nr == 0) { @@ -479,10 +480,7 @@ static void oldnewmap_free_unused(OldNewMap *onm) entry->newp = NULL; } } -} -static void oldnewmap_clear(OldNewMap *onm) -{ onm->capacity_exp = DEFAULT_SIZE_EXP; oldnewmap_clear_map(onm); onm->nentries = 0; @@ -2768,7 +2766,7 @@ static void direct_link_id_override_property_cb(FileData *fd, void *data) link_list_ex(fd, &op->operations, direct_link_id_override_property_operation_cb); } -static void direct_link_id(FileData *fd, ID *id, ID *id_old); +static void direct_link_id_common(FileData *fd, ID *id, ID *id_old, const int tag); static void direct_link_nodetree(FileData *fd, bNodeTree *ntree); static void direct_link_collection(FileData *fd, Collection *collection); @@ -2778,7 +2776,8 @@ static void direct_link_id_private_id(FileData *fd, ID *id, ID *id_old) bNodeTree **nodetree = BKE_ntree_ptr_from_id(id); if (nodetree != NULL && *nodetree != NULL) { *nodetree = newdataadr(fd, *nodetree); - direct_link_id(fd, (ID *)*nodetree, id_old != NULL ? (ID *)ntreeFromID(id_old) : NULL); + direct_link_id_common( + fd, (ID *)*nodetree, id_old != NULL ? (ID *)ntreeFromID(id_old) : NULL, 0); direct_link_nodetree(fd, *nodetree); } @@ -2786,15 +2785,16 @@ static void direct_link_id_private_id(FileData *fd, ID *id, ID *id_old) Scene *scene = (Scene *)id; if (scene->master_collection != NULL) { scene->master_collection = newdataadr(fd, scene->master_collection); - direct_link_id(fd, - &scene->master_collection->id, - id_old != NULL ? &((Scene *)id_old)->master_collection->id : NULL); + direct_link_id_common(fd, + &scene->master_collection->id, + id_old != NULL ? &((Scene *)id_old)->master_collection->id : NULL, + 0); direct_link_collection(fd, scene->master_collection); } } } -static void direct_link_id(FileData *fd, ID *id, ID *id_old) +static void direct_link_id_common(FileData *fd, ID *id, ID *id_old, const int tag) { /*link direct data of ID properties*/ if (id->properties) { @@ -2804,10 +2804,8 @@ static void direct_link_id(FileData *fd, ID *id, ID *id_old) } id->py_instance = NULL; - /* That way data-lock reading not going through main read_libblock() - * function are still in a clear tag state. - * (glowering at certain nodetree fake data-lock here...). */ - id->tag = 0; + /* Initialize with provided tag. */ + id->tag = tag; id->flag &= ~LIB_INDIRECT_WEAK_LINK; /* NOTE: It is important to not clear the recalc flags for undo/redo. @@ -8378,7 +8376,7 @@ void blo_do_versions_view3d_split_250(View3D *v3d, ListBase *regions) static bool direct_link_screen(FileData *fd, bScreen *screen) { - bool wrong_id = false; + bool success = true; screen->regionbase.first = screen->regionbase.last = NULL; screen->context = NULL; @@ -8388,10 +8386,10 @@ static bool direct_link_screen(FileData *fd, bScreen *screen) if (!direct_link_area_map(fd, AREAMAP_FROM_SCREEN(screen))) { printf("Error reading Screen %s... removing it.\n", screen->id.name + 2); - wrong_id = true; + success = false; } - return wrong_id; + return success; } /** \} */ @@ -9227,6 +9225,158 @@ static const char *dataname(short id_code) return "Data from Lib Block"; } +static bool direct_link_id(FileData *fd, Main *main, const int tag, ID *id, ID *id_old) +{ + if (fd->memfile == NULL) { + /* When actually reading a file , we do want to reset/re-generate session uuids. + * In undo case, we want to re-use existing ones. */ + id->session_uuid = MAIN_ID_SESSION_UUID_UNSET; + } + + BKE_lib_libblock_session_uuid_ensure(id); + + id->lib = main->curlib; + id->us = ID_FAKE_USERS(id); + id->icon_id = 0; + id->newid = NULL; /* Needed because .blend may have been saved with crap value here... */ + id->orig_id = NULL; + + if (tag & LIB_TAG_ID_LINK_PLACEHOLDER) { + /* For placeholder we only need to set the tag, no further data to read. */ + id->tag = tag; + return true; + } + + /* Read part of datablock that is common between real and embedded datablocks. */ + direct_link_id_common(fd, id, id_old, tag); + + /* XXX Very weakly handled currently, see comment in read_libblock() before trying to + * use it for anything new. */ + bool success = true; + + switch (GS(id->name)) { + case ID_WM: + direct_link_windowmanager(fd, (wmWindowManager *)id); + break; + case ID_SCR: + success = direct_link_screen(fd, (bScreen *)id); + break; + case ID_SCE: + direct_link_scene(fd, (Scene *)id); + break; + case ID_OB: + direct_link_object(fd, (Object *)id); + break; + case ID_ME: + direct_link_mesh(fd, (Mesh *)id); + break; + case ID_CU: + direct_link_curve(fd, (Curve *)id); + break; + case ID_MB: + direct_link_mball(fd, (MetaBall *)id); + break; + case ID_MA: + direct_link_material(fd, (Material *)id); + break; + case ID_TE: + direct_link_texture(fd, (Tex *)id); + break; + case ID_IM: + direct_link_image(fd, (Image *)id); + break; + case ID_LA: + direct_link_light(fd, (Light *)id); + break; + case ID_VF: + direct_link_vfont(fd, (VFont *)id); + break; + case ID_TXT: + direct_link_text(fd, (Text *)id); + break; + case ID_IP: + direct_link_ipo(fd, (Ipo *)id); + break; + case ID_KE: + direct_link_key(fd, (Key *)id); + break; + case ID_LT: + direct_link_latt(fd, (Lattice *)id); + break; + case ID_WO: + direct_link_world(fd, (World *)id); + break; + case ID_LI: + direct_link_library(fd, (Library *)id, main); + break; + case ID_CA: + direct_link_camera(fd, (Camera *)id); + break; + case ID_SPK: + direct_link_speaker(fd, (Speaker *)id); + break; + case ID_SO: + direct_link_sound(fd, (bSound *)id); + break; + case ID_LP: + direct_link_lightprobe(fd, (LightProbe *)id); + break; + case ID_GR: + direct_link_collection(fd, (Collection *)id); + break; + case ID_AR: + direct_link_armature(fd, (bArmature *)id); + break; + case ID_AC: + direct_link_action(fd, (bAction *)id); + break; + case ID_NT: + direct_link_nodetree(fd, (bNodeTree *)id); + break; + case ID_BR: + direct_link_brush(fd, (Brush *)id); + break; + case ID_PA: + direct_link_particlesettings(fd, (ParticleSettings *)id); + break; + case ID_GD: + direct_link_gpencil(fd, (bGPdata *)id); + break; + case ID_MC: + direct_link_movieclip(fd, (MovieClip *)id); + break; + case ID_MSK: + direct_link_mask(fd, (Mask *)id); + break; + case ID_LS: + direct_link_linestyle(fd, (FreestyleLineStyle *)id); + break; + case ID_PAL: + direct_link_palette(fd, (Palette *)id); + break; + case ID_PC: + direct_link_paint_curve(fd, (PaintCurve *)id); + break; + case ID_CF: + direct_link_cachefile(fd, (CacheFile *)id); + break; + case ID_WS: + direct_link_workspace(fd, (WorkSpace *)id, main); + break; + case ID_HA: + direct_link_hair(fd, (Hair *)id); + break; + case ID_PT: + direct_link_pointcloud(fd, (PointCloud *)id); + break; + case ID_VO: + direct_link_volume(fd, (Volume *)id); + break; + } + + return success; +} + static BHead *read_data_into_oldnewmap(FileData *fd, BHead *bhead, const char *allocname) { bhead = blo_bhead_next(fd, bhead); @@ -9261,15 +9411,8 @@ static BHead *read_libblock(FileData *fd, const bool placeholder_set_indirect_extern, ID **r_id) { - /* this routine reads a libblock and its direct data. Use link functions to connect it all - */ - ID *id; - ListBase *lb; - const char *allocname; - - /* XXX Very weakly handled currently, see comment at the end of this function before trying to - * use it for anything new. */ - bool wrong_id = false; + /* This routine reads a libblock and its direct data. Lib link functions will + * set points between datablocks. */ /* In undo case, most libs and linked data should be kept as is from previous state * (see BLO_read_from_memfile). @@ -9314,7 +9457,8 @@ static BHead *read_libblock(FileData *fd, DEBUG_PRINTF("... in %s (%s): ", main->curlib ? main->curlib->id.name : "", main->curlib ? main->curlib->name : ""); - if ((id = BKE_libblock_find_name(main, GS(idname), idname + 2))) { + ID *id = BKE_libblock_find_name(main, GS(idname), idname + 2); + if (id != NULL) { DEBUG_PRINTF("FOUND!\n"); /* Even though we found our linked ID, * there is no guarantee its address is still the same. */ @@ -9335,7 +9479,7 @@ static BHead *read_libblock(FileData *fd, /* read libblock */ fd->are_memchunks_identical = true; - id = read_struct(fd, bhead, "lib block"); + ID *id = read_struct(fd, bhead, "lib block"); const short idcode = id != NULL ? GS(id->name) : 0; BHead *id_bhead = bhead; @@ -9348,7 +9492,7 @@ static BHead *read_libblock(FileData *fd, if (id_bhead->code != ID_LINK_PLACEHOLDER) { /* need a name for the mallocN, just for debugging and sane prints on leaks */ - allocname = dataname(idcode); + const char *allocname = dataname(idcode); /* read all data into fd->datamap */ /* TODO: instead of building oldnewmap here we could just quickly check the bheads... could @@ -9442,7 +9586,6 @@ static BHead *read_libblock(FileData *fd, } MEM_freeN(id); - oldnewmap_free_unused(fd->datamap); oldnewmap_clear(fd->datamap); return bhead; @@ -9451,7 +9594,7 @@ static BHead *read_libblock(FileData *fd, } /* do after read_struct, for dna reconstruct */ - lb = which_libbase(main, idcode); + ListBase *lb = which_libbase(main, idcode); if (lb) { /* Some re-used old IDs might also use newly read ones, so we have to check for old memory * addresses for those as well. */ @@ -9487,14 +9630,6 @@ static BHead *read_libblock(FileData *fd, oldnewmap_insert(fd->libmap, id_old, id_target, id_bhead->code); BLI_addtail(lb, id); - - if (fd->memfile == NULL) { - /* When actually reading a file , we do want to reset/re-generate session uuids. - * In unod case, we want to re-use existing ones. */ - id->session_uuid = MAIN_ID_SESSION_UUID_UNSET; - } - - BKE_lib_libblock_session_uuid_ensure(id); } else { /* unknown ID type */ @@ -9511,160 +9646,35 @@ static BHead *read_libblock(FileData *fd, return blo_bhead_next(fd, id_bhead); } - id->lib = main->curlib; - id->us = ID_FAKE_USERS(id); - id->icon_id = 0; - id->newid = NULL; /* Needed because .blend may have been saved with crap value here... */ - id->orig_id = NULL; + /* Set tag for new datablock to indicate lib linking and versioning needs + * to be done still. */ + int id_tag = tag | LIB_TAG_NEED_LINK | LIB_TAG_NEW; - /* this case cannot be direct_linked: it's just the ID part */ if (id_bhead->code == ID_LINK_PLACEHOLDER) { - /* That way, we know which data-lock needs do_versions (required currently for linking). */ - id->tag = tag | LIB_TAG_ID_LINK_PLACEHOLDER | LIB_TAG_NEED_LINK | LIB_TAG_NEW; + /* Tag to get replaced by the actual linked datablock. */ + id_tag |= LIB_TAG_ID_LINK_PLACEHOLDER; if (placeholder_set_indirect_extern) { if (id->flag & LIB_INDIRECT_WEAK_LINK) { - id->tag |= LIB_TAG_INDIRECT; + id_tag |= LIB_TAG_INDIRECT; } else { - id->tag |= LIB_TAG_EXTERN; + id_tag |= LIB_TAG_EXTERN; } } - - return blo_bhead_next(fd, id_bhead); } - /* init pointers direct data */ - direct_link_id(fd, id, id_old); + /* Read datablock contents. */ + const bool success = direct_link_id(fd, main, id_tag, id, id_old); - /* That way, we know which data-lock needs do_versions (required currently for linking). */ - /* Note: doing this after direct_link_id(), which resets that field. */ - id->tag = tag | LIB_TAG_NEED_LINK | LIB_TAG_NEW; - - switch (idcode) { - case ID_WM: - direct_link_windowmanager(fd, (wmWindowManager *)id); - break; - case ID_SCR: - wrong_id = direct_link_screen(fd, (bScreen *)id); - break; - case ID_SCE: - direct_link_scene(fd, (Scene *)id); - break; - case ID_OB: - direct_link_object(fd, (Object *)id); - break; - case ID_ME: - direct_link_mesh(fd, (Mesh *)id); - break; - case ID_CU: - direct_link_curve(fd, (Curve *)id); - break; - case ID_MB: - direct_link_mball(fd, (MetaBall *)id); - break; - case ID_MA: - direct_link_material(fd, (Material *)id); - break; - case ID_TE: - direct_link_texture(fd, (Tex *)id); - break; - case ID_IM: - direct_link_image(fd, (Image *)id); - break; - case ID_LA: - direct_link_light(fd, (Light *)id); - break; - case ID_VF: - direct_link_vfont(fd, (VFont *)id); - break; - case ID_TXT: - direct_link_text(fd, (Text *)id); - break; - case ID_IP: - direct_link_ipo(fd, (Ipo *)id); - break; - case ID_KE: - direct_link_key(fd, (Key *)id); - break; - case ID_LT: - direct_link_latt(fd, (Lattice *)id); - break; - case ID_WO: - direct_link_world(fd, (World *)id); - break; - case ID_LI: - direct_link_library(fd, (Library *)id, main); - break; - case ID_CA: - direct_link_camera(fd, (Camera *)id); - break; - case ID_SPK: - direct_link_speaker(fd, (Speaker *)id); - break; - case ID_SO: - direct_link_sound(fd, (bSound *)id); - break; - case ID_LP: - direct_link_lightprobe(fd, (LightProbe *)id); - break; - case ID_GR: - direct_link_collection(fd, (Collection *)id); - break; - case ID_AR: - direct_link_armature(fd, (bArmature *)id); - break; - case ID_AC: - direct_link_action(fd, (bAction *)id); - break; - case ID_NT: - direct_link_nodetree(fd, (bNodeTree *)id); - break; - case ID_BR: - direct_link_brush(fd, (Brush *)id); - break; - case ID_PA: - direct_link_particlesettings(fd, (ParticleSettings *)id); - break; - case ID_GD: - direct_link_gpencil(fd, (bGPdata *)id); - break; - case ID_MC: - direct_link_movieclip(fd, (MovieClip *)id); - break; - case ID_MSK: - direct_link_mask(fd, (Mask *)id); - break; - case ID_LS: - direct_link_linestyle(fd, (FreestyleLineStyle *)id); - break; - case ID_PAL: - direct_link_palette(fd, (Palette *)id); - break; - case ID_PC: - direct_link_paint_curve(fd, (PaintCurve *)id); - break; - case ID_CF: - direct_link_cachefile(fd, (CacheFile *)id); - break; - case ID_WS: - direct_link_workspace(fd, (WorkSpace *)id, main); - break; - case ID_HA: - direct_link_hair(fd, (Hair *)id); - break; - case ID_PT: - direct_link_pointcloud(fd, (PointCloud *)id); - break; - case ID_VO: - direct_link_volume(fd, (Volume *)id); - break; + /* For placeholders we are done here. */ + if (id_bhead->code == ID_LINK_PLACEHOLDER) { + return blo_bhead_next(fd, id_bhead); } - oldnewmap_free_unused(fd->datamap); oldnewmap_clear(fd->datamap); - if (wrong_id) { + if (!success) { /* XXX This is probably working OK currently given the very limited scope of that flag. * However, it is absolutely **not** handled correctly: it is freeing an ID pointer that has * been added to the fd->libmap mapping, which in theory could lead to nice crashes... @@ -10151,7 +10161,6 @@ static BHead *read_userdef(BlendFileData *bfd, FileData *fd, BHead *bhead) user->edit_studio_light = 0; /* free fd->datamap again */ - oldnewmap_free_unused(fd->datamap); oldnewmap_clear(fd->datamap); return bhead; -- cgit v1.2.3 From 624b231ec49997120cff17ae68a39cb13e267ee7 Mon Sep 17 00:00:00 2001 From: Brecht Van Lommel Date: Fri, 3 Apr 2020 14:12:57 +0200 Subject: Cleanup: early out on invalid ID data to simplify control flow Differential Revision: https://developer.blender.org/D7325 --- source/blender/blenloader/intern/readfile.c | 301 ++++++++++++++-------------- 1 file changed, 150 insertions(+), 151 deletions(-) diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c index 3c5908efa3f..8f77c80d64b 100644 --- a/source/blender/blenloader/intern/readfile.c +++ b/source/blender/blenloader/intern/readfile.c @@ -9413,6 +9413,26 @@ static BHead *read_libblock(FileData *fd, { /* This routine reads a libblock and its direct data. Lib link functions will * set points between datablocks. */ + if (r_id) { + *r_id = NULL; /* In case of early return. */ + } + + /* Read libblock struct. */ + fd->are_memchunks_identical = true; + ID *id = read_struct(fd, bhead, "lib block"); + if (id == NULL) { + return blo_bhead_next(fd, bhead); + } + + /* Determine ID type. */ + const short idcode = GS(id->name); + ListBase *lb = which_libbase(main, idcode); + if (lb == NULL) { + /* Unknown ID type. */ + printf("%s: unknown id code '%c%c'\n", __func__, (idcode & 0xff), (idcode >> 8)); + MEM_freeN(id); + return blo_bhead_next(fd, bhead); + } /* In undo case, most libs and linked data should be kept as is from previous state * (see BLO_read_from_memfile). @@ -9422,17 +9442,15 @@ static BHead *read_libblock(FileData *fd, * That means we have to carefully check whether current lib or * libdata already exits in old main, if it does we merely copy it over into new main area, * otherwise we have to do a full read of that bhead... */ - if (fd->memfile && ELEM(bhead->code, ID_LI, ID_LINK_PLACEHOLDER)) { - const char *idname = blo_bhead_id_name(fd, bhead); - - DEBUG_PRINTF("Checking %s...\n", idname); + if (fd->memfile != NULL && ELEM(bhead->code, ID_LI, ID_LINK_PLACEHOLDER)) { + DEBUG_PRINTF("Checking %s...\n", id->name); if (bhead->code == ID_LI) { Main *libmain = fd->old_mainlist->first; /* Skip oldmain itself... */ for (libmain = libmain->next; libmain; libmain = libmain->next) { DEBUG_PRINTF("... against %s: ", libmain->curlib ? libmain->curlib->id.name : ""); - if (libmain->curlib && STREQ(idname, libmain->curlib->id.name)) { + if (libmain->curlib && STREQ(id->name, libmain->curlib->id.name)) { Main *oldmain = fd->old_mainlist->first; DEBUG_PRINTF("FOUND!\n"); /* In case of a library, we need to re-add its main to fd->mainlist, @@ -9445,9 +9463,7 @@ static BHead *read_libblock(FileData *fd, BLI_addtail(fd->mainlist, libmain); BLI_addtail(&main->libraries, libmain->curlib); - if (r_id) { - *r_id = NULL; /* Just in case... */ - } + MEM_freeN(id); return blo_bhead_next(fd, bhead); } DEBUG_PRINTF("nothing...\n"); @@ -9457,20 +9473,18 @@ static BHead *read_libblock(FileData *fd, DEBUG_PRINTF("... in %s (%s): ", main->curlib ? main->curlib->id.name : "", main->curlib ? main->curlib->name : ""); - ID *id = BKE_libblock_find_name(main, GS(idname), idname + 2); - if (id != NULL) { + ID *existing_id = BKE_libblock_find_name(main, GS(id->name), id->name + 2); + if (existing_id != NULL) { DEBUG_PRINTF("FOUND!\n"); /* Even though we found our linked ID, * there is no guarantee its address is still the same. */ - if (id != bhead->old) { - oldnewmap_insert(fd->libmap, bhead->old, id, GS(id->name)); + if (existing_id != bhead->old) { + oldnewmap_insert(fd->libmap, bhead->old, existing_id, GS(existing_id->name)); } /* No need to do anything else for ID_LINK_PLACEHOLDER, * it's assumed already present in its lib's main. */ - if (r_id) { - *r_id = NULL; /* Just in case... */ - } + MEM_freeN(id); return blo_bhead_next(fd, bhead); } DEBUG_PRINTF("nothing...\n"); @@ -9478,173 +9492,158 @@ static BHead *read_libblock(FileData *fd, } /* read libblock */ - fd->are_memchunks_identical = true; - ID *id = read_struct(fd, bhead, "lib block"); - const short idcode = id != NULL ? GS(id->name) : 0; - BHead *id_bhead = bhead; + + if (id_bhead->code != ID_LINK_PLACEHOLDER) { + /* need a name for the mallocN, just for debugging and sane prints on leaks */ + const char *allocname = dataname(idcode); + + /* read all data into fd->datamap */ + /* TODO: for the undo case instead of building oldnewmap here we could just quickly check the + * bheads... could save some more ticks. Probably not worth it though, bottleneck is full + * depsgraph rebuild and evaluate, not actual file reading. */ + bhead = read_data_into_oldnewmap(fd, id_bhead, allocname); + } + + /* Restore existing datablocks for undo. */ + const bool do_partial_undo = (fd->skip_flags & BLO_READ_SKIP_UNDO_OLD_MAIN) == 0; + /* Used when undoing from memfile, we swap changed IDs into their old addresses when found. */ ID *id_old = NULL; bool do_id_swap = false; - if (id != NULL) { - const bool do_partial_undo = (fd->skip_flags & BLO_READ_SKIP_UNDO_OLD_MAIN) == 0; - + if (fd->memfile != NULL) { if (id_bhead->code != ID_LINK_PLACEHOLDER) { - /* need a name for the mallocN, just for debugging and sane prints on leaks */ - const char *allocname = dataname(idcode); - - /* read all data into fd->datamap */ - /* TODO: instead of building oldnewmap here we could just quickly check the bheads... could - * save some more ticks. Probably not worth it though, bottleneck is full depsgraph rebuild - * and evaluate, not actual file reading. */ - bhead = read_data_into_oldnewmap(fd, id_bhead, allocname); - DEBUG_PRINTF( "%s: ID %s is unchanged: %d\n", __func__, id->name, fd->are_memchunks_identical); - if (fd->memfile != NULL) { - BLI_assert(fd->old_idmap != NULL || !do_partial_undo); - /* This code should only ever be reached for local data-blocks. */ - BLI_assert(main->curlib == NULL); - - /* Find the 'current' existing ID we want to reuse instead of the one we would read from - * the undo memfile. */ - DEBUG_PRINTF("\t Looking for ID %s with uuid %u instead of newly read one\n", - id->name, - id->session_uuid); - id_old = do_partial_undo ? BKE_main_idmap_lookup_uuid(fd->old_idmap, id->session_uuid) : - NULL; - bool can_finalize_and_return = false; - - if (ELEM(idcode, ID_WM, ID_SCR, ID_WS)) { - /* Read WindowManager, Screen and WorkSpace IDs are never actually used during undo (see - * `setup_app_data()` in `blendfile.c`). - * So we can just abort here, just ensuring libmapping is set accordingly. */ - can_finalize_and_return = true; - } - else if (id_old != NULL && fd->are_memchunks_identical) { - /* Do not add LIB_TAG_NEW here, this should not be needed/used in undo case anyway (as - * this is only for do_version-like code), but for sake of consistency, and also because - * it will tell us which ID is re-used from old Main, and which one is actually new. */ - id_old->tag = tag | LIB_TAG_NEED_LINK | LIB_TAG_UNDO_OLD_ID_REUSED; - id_old->lib = main->curlib; - id_old->us = ID_FAKE_USERS(id_old); - /* Do not reset id->icon_id here, memory allocated for it remains valid. */ - /* Needed because .blend may have been saved with crap value here... */ - id_old->newid = NULL; - id_old->orig_id = NULL; - - /* About recalc: since that ID did not change at all, we know that its recalc fields also - * remained unchanged, so no need to handle neither recalc nor recalc_undo_future here. - */ + BLI_assert(fd->old_idmap != NULL || !do_partial_undo); + /* This code should only ever be reached for local data-blocks. */ + BLI_assert(main->curlib == NULL); + + /* Find the 'current' existing ID we want to reuse instead of the one we would read from + * the undo memfile. */ + DEBUG_PRINTF("\t Looking for ID %s with uuid %u instead of newly read one\n", + id->name, + id->session_uuid); + id_old = do_partial_undo ? BKE_main_idmap_lookup_uuid(fd->old_idmap, id->session_uuid) : + NULL; + bool can_finalize_and_return = false; + + if (ELEM(idcode, ID_WM, ID_SCR, ID_WS)) { + /* Read WindowManager, Screen and WorkSpace IDs are never actually used during undo (see + * `setup_app_data()` in `blendfile.c`). + * So we can just abort here, just ensuring libmapping is set accordingly. */ + can_finalize_and_return = true; + } + else if (id_old != NULL && fd->are_memchunks_identical) { + /* Do not add LIB_TAG_NEW here, this should not be needed/used in undo case anyway (as + * this is only for do_version-like code), but for sake of consistency, and also because + * it will tell us which ID is re-used from old Main, and which one is actually new. */ + id_old->tag = tag | LIB_TAG_NEED_LINK | LIB_TAG_UNDO_OLD_ID_REUSED; + id_old->lib = main->curlib; + id_old->us = ID_FAKE_USERS(id_old); + /* Do not reset id->icon_id here, memory allocated for it remains valid. */ + /* Needed because .blend may have been saved with crap value here... */ + id_old->newid = NULL; + id_old->orig_id = NULL; + + /* About recalc: since that ID did not change at all, we know that its recalc fields also + * remained unchanged, so no need to handle neither recalc nor recalc_undo_future here. + */ - Main *old_bmain = fd->old_mainlist->first; - ListBase *old_lb = which_libbase(old_bmain, idcode); - ListBase *new_lb = which_libbase(main, idcode); - BLI_remlink(old_lb, id_old); - BLI_addtail(new_lb, id_old); + Main *old_bmain = fd->old_mainlist->first; + ListBase *old_lb = which_libbase(old_bmain, idcode); + ListBase *new_lb = which_libbase(main, idcode); + BLI_remlink(old_lb, id_old); + BLI_addtail(new_lb, id_old); - can_finalize_and_return = true; - } + can_finalize_and_return = true; + } - if (can_finalize_and_return) { - DEBUG_PRINTF("Re-using existing ID %s instead of newly read one\n", id_old->name); - oldnewmap_insert(fd->libmap, id_bhead->old, id_old, id_bhead->code); - oldnewmap_insert(fd->libmap, id_old, id_old, id_bhead->code); + if (can_finalize_and_return) { + DEBUG_PRINTF("Re-using existing ID %s instead of newly read one\n", id_old->name); + oldnewmap_insert(fd->libmap, id_bhead->old, id_old, id_bhead->code); + oldnewmap_insert(fd->libmap, id_old, id_old, id_bhead->code); - if (r_id) { - *r_id = id_old; - } + if (r_id) { + *r_id = id_old; + } - if (do_partial_undo) { - /* Even though we re-use the old ID as-is, it does not mean that we are 100% safe from - * needing some depsgraph updates for it (it could depend on another ID which address - * did not change, but which actual content might have been re-read from the memfile). - * IMPORTANT: Do not fully overwrite recalc flag here, depsgraph may not have been ran - * yet for previous undo step(s), we do not want to erase flags set by those. + if (do_partial_undo) { + /* Even though we re-use the old ID as-is, it does not mean that we are 100% safe from + * needing some depsgraph updates for it (it could depend on another ID which address + * did not change, but which actual content might have been re-read from the memfile). + * IMPORTANT: Do not fully overwrite recalc flag here, depsgraph may not have been ran + * yet for previous undo step(s), we do not want to erase flags set by those. + */ + if (fd->undo_direction < 0) { + /* We are coming from the future (i.e. do an actual undo, and not a redo), we use our + * old reused ID's 'accumulated recalc flags since last memfile undo step saving' as + * recalc flags. */ + id_old->recalc |= id_old->recalc_undo_accumulated; + } + else { + /* We are coming from the past (i.e. do a redo), we use the saved 'accumulated recalc + * flags since last memfile undo step saving' from the newly read ID as recalc flags. */ - if (fd->undo_direction < 0) { - /* We are coming from the future (i.e. do an actual undo, and not a redo), we use our - * old reused ID's 'accumulated recalc flags since last memfile undo step saving' as - * recalc flags. */ - id_old->recalc |= id_old->recalc_undo_accumulated; - } - else { - /* We are coming from the past (i.e. do a redo), we use the saved 'accumulated recalc - * flags since last memfile undo step saving' from the newly read ID as recalc flags. - */ - id_old->recalc |= id->recalc_undo_accumulated; - } - /* There is no need to flush the depsgraph's CoWs here, since that ID's data itself did - * not change. */ - - /* We need to 'accumulate' the accumulated recalc flags of all undo steps until we - * actually perform a depsgraph update, otherwise we'd only ever use the flags from one - * of the steps, and never get proper flags matching all others. */ - id_old->recalc_undo_accumulated |= id->recalc_undo_accumulated; + id_old->recalc |= id->recalc_undo_accumulated; } + /* There is no need to flush the depsgraph's CoWs here, since that ID's data itself did + * not change. */ - MEM_freeN(id); - oldnewmap_clear(fd->datamap); - - return bhead; + /* We need to 'accumulate' the accumulated recalc flags of all undo steps until we + * actually perform a depsgraph update, otherwise we'd only ever use the flags from one + * of the steps, and never get proper flags matching all others. */ + id_old->recalc_undo_accumulated |= id->recalc_undo_accumulated; } - } - } - /* do after read_struct, for dna reconstruct */ - ListBase *lb = which_libbase(main, idcode); - if (lb) { - /* Some re-used old IDs might also use newly read ones, so we have to check for old memory - * addresses for those as well. */ - if (fd->memfile != NULL && do_partial_undo && id->lib == NULL) { - BLI_assert(fd->old_idmap != NULL); - DEBUG_PRINTF("\t Looking for ID %s with uuid %u instead of newly read one\n", - id->name, - id->session_uuid); - id_old = BKE_main_idmap_lookup_uuid(fd->old_idmap, id->session_uuid); - if (id_old != NULL) { - BLI_assert(MEM_allocN_len(id) == MEM_allocN_len(id_old)); - /* UI IDs are always re-used from old bmain at higher-level calling code, so never swap - * those. Besides maybe custom properties, no other ID should have pointers to those - * anyway... - * And linked IDs are handled separately as well. */ - do_id_swap = !ELEM(idcode, ID_WM, ID_SCR, ID_WS) && - !(id_bhead->code == ID_LINK_PLACEHOLDER); - } - } + MEM_freeN(id); + oldnewmap_clear(fd->datamap); - /* At this point, we know we are going to keep that newly read & allocated ID, so we need to - * reallocate it to ensure we actually get a unique memory address for it. */ - if (!do_id_swap) { - DEBUG_PRINTF("using newly-read ID %s to a new mem address\n", id->name); - } - else { - DEBUG_PRINTF("using newly-read ID %s to its old, already existing address\n", id->name); + return bhead; } + } - /* for ID_LINK_PLACEHOLDER check */ - ID *id_target = do_id_swap ? id_old : id; - oldnewmap_insert(fd->libmap, id_bhead->old, id_target, id_bhead->code); - oldnewmap_insert(fd->libmap, id_old, id_target, id_bhead->code); + /* Some re-used old IDs might also use newly read ones, so we have to check for old memory + * addresses for those as well. */ + if (do_partial_undo && id->lib == NULL) { + BLI_assert(fd->old_idmap != NULL); + DEBUG_PRINTF("\t Looking for ID %s with uuid %u instead of newly read one\n", + id->name, + id->session_uuid); + id_old = BKE_main_idmap_lookup_uuid(fd->old_idmap, id->session_uuid); + if (id_old != NULL) { + BLI_assert(MEM_allocN_len(id) == MEM_allocN_len(id_old)); + /* UI IDs are always re-used from old bmain at higher-level calling code, so never swap + * those. Besides maybe custom properties, no other ID should have pointers to those + * anyway... + * And linked IDs are handled separately as well. */ + do_id_swap = !ELEM(idcode, ID_WM, ID_SCR, ID_WS) && + !(id_bhead->code == ID_LINK_PLACEHOLDER); + } + } - BLI_addtail(lb, id); + /* At this point, we know we are going to keep that newly read & allocated ID, so we need to + * reallocate it to ensure we actually get a unique memory address for it. */ + if (!do_id_swap) { + DEBUG_PRINTF("using newly-read ID %s to a new mem address\n", id->name); } else { - /* unknown ID type */ - printf("%s: unknown id code '%c%c'\n", __func__, (idcode & 0xff), (idcode >> 8)); - MEM_freeN(id); - id = NULL; + DEBUG_PRINTF("using newly-read ID %s to its old, already existing address\n", id->name); } } + /* for ID_LINK_PLACEHOLDER check */ + ID *id_target = do_id_swap ? id_old : id; + oldnewmap_insert(fd->libmap, id_bhead->old, id_target, id_bhead->code); + oldnewmap_insert(fd->libmap, id_old, id_target, id_bhead->code); + + BLI_addtail(lb, id); + if (r_id) { *r_id = do_id_swap ? id_old : id; } - if (!id) { - return blo_bhead_next(fd, id_bhead); - } /* Set tag for new datablock to indicate lib linking and versioning needs * to be done still. */ -- cgit v1.2.3 From c75aaf5329afa9cfbecbb6ac7f646e76546613ca Mon Sep 17 00:00:00 2001 From: Brecht Van Lommel Date: Fri, 3 Apr 2020 13:34:12 +0200 Subject: Cleanup: split off library and linked datablock undo restore Differential Revision: https://developer.blender.org/D7326 --- source/blender/blenloader/intern/readfile.c | 116 ++++++++++++++++------------ 1 file changed, 68 insertions(+), 48 deletions(-) diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c index 8f77c80d64b..2cd891a1796 100644 --- a/source/blender/blenloader/intern/readfile.c +++ b/source/blender/blenloader/intern/readfile.c @@ -9404,6 +9404,67 @@ static BHead *read_data_into_oldnewmap(FileData *fd, BHead *bhead, const char *a return bhead; } +static bool read_libblock_undo_restore_library(FileData *fd, Main *main, const ID *id) +{ + /* In undo case, most libs and linked data should be kept as is from previous state + * (see BLO_read_from_memfile). + * However, some needed by the snapshot being read may have been removed in previous one, + * and would go missing. + * This leads e.g. to disappearing objects in some undo/redo case, see T34446. + * That means we have to carefully check whether current lib or + * libdata already exits in old main, if it does we merely copy it over into new main area, + * otherwise we have to do a full read of that bhead... */ + DEBUG_PRINTF("UNDO: restore library %s\n", id->name); + + Main *libmain = fd->old_mainlist->first; + /* Skip oldmain itself... */ + for (libmain = libmain->next; libmain; libmain = libmain->next) { + DEBUG_PRINTF(" compare with %s -> ", libmain->curlib ? libmain->curlib->id.name : ""); + if (libmain->curlib && STREQ(id->name, libmain->curlib->id.name)) { + Main *oldmain = fd->old_mainlist->first; + DEBUG_PRINTF("match!\n"); + /* In case of a library, we need to re-add its main to fd->mainlist, + * because if we have later a missing ID_LINK_PLACEHOLDER, + * we need to get the correct lib it is linked to! + * Order is crucial, we cannot bulk-add it in BLO_read_from_memfile() + * like it used to be. */ + BLI_remlink(fd->old_mainlist, libmain); + BLI_remlink_safe(&oldmain->libraries, libmain->curlib); + BLI_addtail(fd->mainlist, libmain); + BLI_addtail(&main->libraries, libmain->curlib); + return true; + } + DEBUG_PRINTF("no match\n"); + } + + return false; +} + +static bool read_libblock_undo_restore_linked(FileData *fd, Main *main, const ID *id, BHead *bhead) +{ + DEBUG_PRINTF("UNDO: restore linked datablock %s\n", id->name); + DEBUG_PRINTF(" from %s (%s): ", + main->curlib ? main->curlib->id.name : "", + main->curlib ? main->curlib->name : ""); + + ID *existing_id = BKE_libblock_find_name(main, GS(id->name), id->name + 2); + if (existing_id != NULL) { + DEBUG_PRINTF(" found!\n"); + /* Even though we found our linked ID, + * there is no guarantee its address is still the same. */ + if (existing_id != bhead->old) { + oldnewmap_insert(fd->libmap, bhead->old, existing_id, GS(existing_id->name)); + } + + /* No need to do anything else for ID_LINK_PLACEHOLDER, + * it's assumed already present in its lib's main. */ + return true; + } + + DEBUG_PRINTF(" not found\n"); + return false; +} + static BHead *read_libblock(FileData *fd, Main *main, BHead *bhead, @@ -9434,60 +9495,19 @@ static BHead *read_libblock(FileData *fd, return blo_bhead_next(fd, bhead); } - /* In undo case, most libs and linked data should be kept as is from previous state - * (see BLO_read_from_memfile). - * However, some needed by the snapshot being read may have been removed in previous one, - * and would go missing. - * This leads e.g. to disappearing objects in some undo/redo case, see T34446. - * That means we have to carefully check whether current lib or - * libdata already exits in old main, if it does we merely copy it over into new main area, - * otherwise we have to do a full read of that bhead... */ - if (fd->memfile != NULL && ELEM(bhead->code, ID_LI, ID_LINK_PLACEHOLDER)) { - DEBUG_PRINTF("Checking %s...\n", id->name); - + /* Restore library and linked datablocks for undo. */ + if (fd->memfile != NULL) { if (bhead->code == ID_LI) { - Main *libmain = fd->old_mainlist->first; - /* Skip oldmain itself... */ - for (libmain = libmain->next; libmain; libmain = libmain->next) { - DEBUG_PRINTF("... against %s: ", libmain->curlib ? libmain->curlib->id.name : ""); - if (libmain->curlib && STREQ(id->name, libmain->curlib->id.name)) { - Main *oldmain = fd->old_mainlist->first; - DEBUG_PRINTF("FOUND!\n"); - /* In case of a library, we need to re-add its main to fd->mainlist, - * because if we have later a missing ID_LINK_PLACEHOLDER, - * we need to get the correct lib it is linked to! - * Order is crucial, we cannot bulk-add it in BLO_read_from_memfile() - * like it used to be. */ - BLI_remlink(fd->old_mainlist, libmain); - BLI_remlink_safe(&oldmain->libraries, libmain->curlib); - BLI_addtail(fd->mainlist, libmain); - BLI_addtail(&main->libraries, libmain->curlib); - - MEM_freeN(id); - return blo_bhead_next(fd, bhead); - } - DEBUG_PRINTF("nothing...\n"); + if (read_libblock_undo_restore_library(fd, main, id)) { + MEM_freeN(id); + return blo_bhead_next(fd, bhead); } } - else { - DEBUG_PRINTF("... in %s (%s): ", - main->curlib ? main->curlib->id.name : "", - main->curlib ? main->curlib->name : ""); - ID *existing_id = BKE_libblock_find_name(main, GS(id->name), id->name + 2); - if (existing_id != NULL) { - DEBUG_PRINTF("FOUND!\n"); - /* Even though we found our linked ID, - * there is no guarantee its address is still the same. */ - if (existing_id != bhead->old) { - oldnewmap_insert(fd->libmap, bhead->old, existing_id, GS(existing_id->name)); - } - - /* No need to do anything else for ID_LINK_PLACEHOLDER, - * it's assumed already present in its lib's main. */ + else if (bhead->code == ID_LINK_PLACEHOLDER) { + if (read_libblock_undo_restore_linked(fd, main, id, bhead)) { MEM_freeN(id); return blo_bhead_next(fd, bhead); } - DEBUG_PRINTF("nothing...\n"); } } -- cgit v1.2.3 From 44e5f7a8cfc01771563d4ae663b1d2df3c4aeb7e Mon Sep 17 00:00:00 2001 From: Brecht Van Lommel Date: Fri, 3 Apr 2020 16:01:56 +0200 Subject: Cleanup: don't use global variable for test if IDs are identical Differential Revision: https://developer.blender.org/D7327 --- source/blender/blenloader/intern/readfile.c | 40 +++++++++++++++++++++-------- source/blender/blenloader/intern/readfile.h | 5 ---- 2 files changed, 30 insertions(+), 15 deletions(-) diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c index 2cd891a1796..a5a872a84d0 100644 --- a/source/blender/blenloader/intern/readfile.c +++ b/source/blender/blenloader/intern/readfile.c @@ -2374,9 +2374,6 @@ static void *read_struct(FileData *fd, BHead *bh, const char *blockname) } } - if (!BHEADN_FROM_BHEAD(bh)->is_memchunk_identical) { - fd->are_memchunks_identical = false; - } #ifdef USE_BHEAD_READ_ON_DEMAND if (bh_orig != bh) { MEM_freeN(BHEADN_FROM_BHEAD(bh)); @@ -9377,7 +9374,8 @@ static bool direct_link_id(FileData *fd, Main *main, const int tag, ID *id, ID * return success; } -static BHead *read_data_into_oldnewmap(FileData *fd, BHead *bhead, const char *allocname) +/* Read all data associated with a datablock into datamap. */ +static BHead *read_data_into_datamap(FileData *fd, BHead *bhead, const char *allocname) { bhead = blo_bhead_next(fd, bhead); @@ -9404,6 +9402,28 @@ static BHead *read_data_into_oldnewmap(FileData *fd, BHead *bhead, const char *a return bhead; } +/* Verify if the datablock and all associated data is identical. */ +static bool read_libblock_is_identical(FileData *fd, BHead *bhead) +{ + /* Test ID itself. */ + if (bhead->len && !BHEADN_FROM_BHEAD(bhead)->is_memchunk_identical) { + return false; + } + + /* Test any other data that is part of ID (logic must match read_data_into_datamap). */ + bhead = blo_bhead_next(fd, bhead); + + while (bhead && bhead->code == DATA) { + if (bhead->len && !BHEADN_FROM_BHEAD(bhead)->is_memchunk_identical) { + return false; + } + + bhead = blo_bhead_next(fd, bhead); + } + + return true; +} + static bool read_libblock_undo_restore_library(FileData *fd, Main *main, const ID *id) { /* In undo case, most libs and linked data should be kept as is from previous state @@ -9479,7 +9499,7 @@ static BHead *read_libblock(FileData *fd, } /* Read libblock struct. */ - fd->are_memchunks_identical = true; + BHead *first_bhead = bhead; ID *id = read_struct(fd, bhead, "lib block"); if (id == NULL) { return blo_bhead_next(fd, bhead); @@ -9522,7 +9542,7 @@ static BHead *read_libblock(FileData *fd, /* TODO: for the undo case instead of building oldnewmap here we could just quickly check the * bheads... could save some more ticks. Probably not worth it though, bottleneck is full * depsgraph rebuild and evaluate, not actual file reading. */ - bhead = read_data_into_oldnewmap(fd, id_bhead, allocname); + bhead = read_data_into_datamap(fd, id_bhead, allocname); } /* Restore existing datablocks for undo. */ @@ -9534,8 +9554,8 @@ static BHead *read_libblock(FileData *fd, if (fd->memfile != NULL) { if (id_bhead->code != ID_LINK_PLACEHOLDER) { - DEBUG_PRINTF( - "%s: ID %s is unchanged: %d\n", __func__, id->name, fd->are_memchunks_identical); + const bool is_identical = read_libblock_is_identical(fd, first_bhead); + DEBUG_PRINTF("%s: ID %s is unchanged: %d\n", __func__, id->name, is_identical); BLI_assert(fd->old_idmap != NULL || !do_partial_undo); /* This code should only ever be reached for local data-blocks. */ @@ -9556,7 +9576,7 @@ static BHead *read_libblock(FileData *fd, * So we can just abort here, just ensuring libmapping is set accordingly. */ can_finalize_and_return = true; } - else if (id_old != NULL && fd->are_memchunks_identical) { + else if (id_old != NULL && is_identical) { /* Do not add LIB_TAG_NEW here, this should not be needed/used in undo case anyway (as * this is only for do_version-like code), but for sake of consistency, and also because * it will tell us which ID is re-used from old Main, and which one is actually new. */ @@ -10112,7 +10132,7 @@ static BHead *read_userdef(BlendFileData *bfd, FileData *fd, BHead *bhead) user->subversionfile = bfd->main->subversionfile; /* read all data into fd->datamap */ - bhead = read_data_into_oldnewmap(fd, bhead, "user def"); + bhead = read_data_into_datamap(fd, bhead, "user def"); link_list(fd, &user->themes); link_list(fd, &user->user_keymaps); diff --git a/source/blender/blenloader/intern/readfile.h b/source/blender/blenloader/intern/readfile.h index 5be7e703d6b..80f8bfc3f07 100644 --- a/source/blender/blenloader/intern/readfile.h +++ b/source/blender/blenloader/intern/readfile.h @@ -85,11 +85,6 @@ typedef struct FileData { const char *buffer; /** Variables needed for reading from memfile (undo). */ struct MemFile *memfile; - /** Whether all data read from memfile so far was identical - * (i.e. shared with some previous undo step). - * Updated by `fd_read_from_memfile()`, user is responsible to reset it to true when needed. - * Used to detect unchanged IDs. */ - bool are_memchunks_identical; /** Whether we are undoing (< 0) or redoing (> 0), used to choose which 'unchanged' flag to use * to detect unchanged data from memfile. */ short undo_direction; -- cgit v1.2.3 From d2a07c7b78ae902af532013308e0e304dc77dd3a Mon Sep 17 00:00:00 2001 From: Brecht Van Lommel Date: Fri, 3 Apr 2020 13:34:12 +0200 Subject: Cleanup: delay creating datamap until it's actually needed Differential Revision: https://developer.blender.org/D7328 --- source/blender/blenloader/intern/readfile.c | 54 ++++++++++------------------- 1 file changed, 19 insertions(+), 35 deletions(-) diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c index a5a872a84d0..92ac722f1d1 100644 --- a/source/blender/blenloader/intern/readfile.c +++ b/source/blender/blenloader/intern/readfile.c @@ -9499,7 +9499,7 @@ static BHead *read_libblock(FileData *fd, } /* Read libblock struct. */ - BHead *first_bhead = bhead; + BHead *id_bhead = bhead; ID *id = read_struct(fd, bhead, "lib block"); if (id == NULL) { return blo_bhead_next(fd, bhead); @@ -9531,20 +9531,6 @@ static BHead *read_libblock(FileData *fd, } } - /* read libblock */ - BHead *id_bhead = bhead; - - if (id_bhead->code != ID_LINK_PLACEHOLDER) { - /* need a name for the mallocN, just for debugging and sane prints on leaks */ - const char *allocname = dataname(idcode); - - /* read all data into fd->datamap */ - /* TODO: for the undo case instead of building oldnewmap here we could just quickly check the - * bheads... could save some more ticks. Probably not worth it though, bottleneck is full - * depsgraph rebuild and evaluate, not actual file reading. */ - bhead = read_data_into_datamap(fd, id_bhead, allocname); - } - /* Restore existing datablocks for undo. */ const bool do_partial_undo = (fd->skip_flags & BLO_READ_SKIP_UNDO_OLD_MAIN) == 0; @@ -9553,8 +9539,8 @@ static BHead *read_libblock(FileData *fd, bool do_id_swap = false; if (fd->memfile != NULL) { - if (id_bhead->code != ID_LINK_PLACEHOLDER) { - const bool is_identical = read_libblock_is_identical(fd, first_bhead); + if (bhead->code != ID_LINK_PLACEHOLDER) { + const bool is_identical = read_libblock_is_identical(fd, id_bhead); DEBUG_PRINTF("%s: ID %s is unchanged: %d\n", __func__, id->name, is_identical); BLI_assert(fd->old_idmap != NULL || !do_partial_undo); @@ -9603,8 +9589,8 @@ static BHead *read_libblock(FileData *fd, if (can_finalize_and_return) { DEBUG_PRINTF("Re-using existing ID %s instead of newly read one\n", id_old->name); - oldnewmap_insert(fd->libmap, id_bhead->old, id_old, id_bhead->code); - oldnewmap_insert(fd->libmap, id_old, id_old, id_bhead->code); + oldnewmap_insert(fd->libmap, bhead->old, id_old, bhead->code); + oldnewmap_insert(fd->libmap, id_old, id_old, bhead->code); if (r_id) { *r_id = id_old; @@ -9639,9 +9625,8 @@ static BHead *read_libblock(FileData *fd, } MEM_freeN(id); - oldnewmap_clear(fd->datamap); - return bhead; + return blo_bhead_next(fd, bhead); } } @@ -9659,8 +9644,7 @@ static BHead *read_libblock(FileData *fd, * those. Besides maybe custom properties, no other ID should have pointers to those * anyway... * And linked IDs are handled separately as well. */ - do_id_swap = !ELEM(idcode, ID_WM, ID_SCR, ID_WS) && - !(id_bhead->code == ID_LINK_PLACEHOLDER); + do_id_swap = !ELEM(idcode, ID_WM, ID_SCR, ID_WS) && !(bhead->code == ID_LINK_PLACEHOLDER); } } @@ -9676,8 +9660,8 @@ static BHead *read_libblock(FileData *fd, /* for ID_LINK_PLACEHOLDER check */ ID *id_target = do_id_swap ? id_old : id; - oldnewmap_insert(fd->libmap, id_bhead->old, id_target, id_bhead->code); - oldnewmap_insert(fd->libmap, id_old, id_target, id_bhead->code); + oldnewmap_insert(fd->libmap, bhead->old, id_target, bhead->code); + oldnewmap_insert(fd->libmap, id_old, id_target, bhead->code); BLI_addtail(lb, id); @@ -9689,8 +9673,8 @@ static BHead *read_libblock(FileData *fd, * to be done still. */ int id_tag = tag | LIB_TAG_NEED_LINK | LIB_TAG_NEW; - if (id_bhead->code == ID_LINK_PLACEHOLDER) { - /* Tag to get replaced by the actual linked datablock. */ + /* Read placeholder for linked datablock. */ + if (bhead->code == ID_LINK_PLACEHOLDER) { id_tag |= LIB_TAG_ID_LINK_PLACEHOLDER; if (placeholder_set_indirect_extern) { @@ -9701,16 +9685,16 @@ static BHead *read_libblock(FileData *fd, id_tag |= LIB_TAG_EXTERN; } } - } - - /* Read datablock contents. */ - const bool success = direct_link_id(fd, main, id_tag, id, id_old); - /* For placeholders we are done here. */ - if (id_bhead->code == ID_LINK_PLACEHOLDER) { - return blo_bhead_next(fd, id_bhead); + direct_link_id(fd, main, id_tag, id, id_old); + return blo_bhead_next(fd, bhead); } + /* Read datablock contents. + * Use convenient malloc name for debugging and better memory link prints. */ + const char *allocname = dataname(idcode); + bhead = read_data_into_datamap(fd, bhead, allocname); + const bool success = direct_link_id(fd, main, id_tag, id, id_old); oldnewmap_clear(fd->datamap); if (!success) { @@ -9755,7 +9739,7 @@ static BHead *read_libblock(FileData *fd, id); } - return (bhead); + return bhead; } /** \} */ -- cgit v1.2.3 From 826e4ba99c5c7b0a74d9d8dcbc7e16117adfd565 Mon Sep 17 00:00:00 2001 From: Brecht Van Lommel Date: Fri, 3 Apr 2020 16:29:48 +0200 Subject: Cleanup: skip reading UI datablocks entirely for undo Other types of datablocks pointing to UI datablocks is unsupported, so there is no need to store them in fd->libmap. With the experimental undo speedup enabled preserving such pointers was done. But it didn't work in 2.82 and such pointers are easily lost in cases other than undo. Differential Revision: https://developer.blender.org/D7329 --- source/blender/blenloader/intern/readfile.c | 22 +++++++++------------- 1 file changed, 9 insertions(+), 13 deletions(-) diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c index 92ac722f1d1..fb5e93f7928 100644 --- a/source/blender/blenloader/intern/readfile.c +++ b/source/blender/blenloader/intern/readfile.c @@ -9529,6 +9529,13 @@ static BHead *read_libblock(FileData *fd, return blo_bhead_next(fd, bhead); } } + else if (ELEM(idcode, ID_WM, ID_SCR, ID_WS)) { + /* Skip reading any UI datablocks, existing ones are kept. We don't + * support pointers from other datablocks to UI datablocks so those + * we also don't put UI datablocks in fd->libmap. */ + MEM_freeN(id); + return blo_bhead_next(fd, bhead); + } } /* Restore existing datablocks for undo. */ @@ -9554,15 +9561,8 @@ static BHead *read_libblock(FileData *fd, id->session_uuid); id_old = do_partial_undo ? BKE_main_idmap_lookup_uuid(fd->old_idmap, id->session_uuid) : NULL; - bool can_finalize_and_return = false; - if (ELEM(idcode, ID_WM, ID_SCR, ID_WS)) { - /* Read WindowManager, Screen and WorkSpace IDs are never actually used during undo (see - * `setup_app_data()` in `blendfile.c`). - * So we can just abort here, just ensuring libmapping is set accordingly. */ - can_finalize_and_return = true; - } - else if (id_old != NULL && is_identical) { + if (id_old != NULL && is_identical) { /* Do not add LIB_TAG_NEW here, this should not be needed/used in undo case anyway (as * this is only for do_version-like code), but for sake of consistency, and also because * it will tell us which ID is re-used from old Main, and which one is actually new. */ @@ -9584,10 +9584,6 @@ static BHead *read_libblock(FileData *fd, BLI_remlink(old_lb, id_old); BLI_addtail(new_lb, id_old); - can_finalize_and_return = true; - } - - if (can_finalize_and_return) { DEBUG_PRINTF("Re-using existing ID %s instead of newly read one\n", id_old->name); oldnewmap_insert(fd->libmap, bhead->old, id_old, bhead->code); oldnewmap_insert(fd->libmap, id_old, id_old, bhead->code); @@ -9644,7 +9640,7 @@ static BHead *read_libblock(FileData *fd, * those. Besides maybe custom properties, no other ID should have pointers to those * anyway... * And linked IDs are handled separately as well. */ - do_id_swap = !ELEM(idcode, ID_WM, ID_SCR, ID_WS) && !(bhead->code == ID_LINK_PLACEHOLDER); + do_id_swap = !(bhead->code == ID_LINK_PLACEHOLDER); } } -- cgit v1.2.3 From 7bc99fdb322c303ab5aa7167e77b48c86f0aee9e Mon Sep 17 00:00:00 2001 From: Brecht Van Lommel Date: Fri, 3 Apr 2020 16:48:31 +0200 Subject: Cleanup: simplify logic for partial undo in ID read Differential Revision: https://developer.blender.org/D7330 --- source/blender/blenloader/intern/readfile.c | 174 +++++++++++++--------------- 1 file changed, 78 insertions(+), 96 deletions(-) diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c index fb5e93f7928..06f53a6c640 100644 --- a/source/blender/blenloader/intern/readfile.c +++ b/source/blender/blenloader/intern/readfile.c @@ -9539,118 +9539,100 @@ static BHead *read_libblock(FileData *fd, } /* Restore existing datablocks for undo. */ - const bool do_partial_undo = (fd->skip_flags & BLO_READ_SKIP_UNDO_OLD_MAIN) == 0; + const bool do_partial_undo = (fd->memfile != NULL) && + (fd->skip_flags & BLO_READ_SKIP_UNDO_OLD_MAIN) == 0 && + (bhead->code != ID_LINK_PLACEHOLDER); /* Used when undoing from memfile, we swap changed IDs into their old addresses when found. */ ID *id_old = NULL; bool do_id_swap = false; - if (fd->memfile != NULL) { - if (bhead->code != ID_LINK_PLACEHOLDER) { - const bool is_identical = read_libblock_is_identical(fd, id_bhead); - DEBUG_PRINTF("%s: ID %s is unchanged: %d\n", __func__, id->name, is_identical); - - BLI_assert(fd->old_idmap != NULL || !do_partial_undo); - /* This code should only ever be reached for local data-blocks. */ - BLI_assert(main->curlib == NULL); - - /* Find the 'current' existing ID we want to reuse instead of the one we would read from - * the undo memfile. */ - DEBUG_PRINTF("\t Looking for ID %s with uuid %u instead of newly read one\n", - id->name, - id->session_uuid); - id_old = do_partial_undo ? BKE_main_idmap_lookup_uuid(fd->old_idmap, id->session_uuid) : - NULL; - - if (id_old != NULL && is_identical) { - /* Do not add LIB_TAG_NEW here, this should not be needed/used in undo case anyway (as - * this is only for do_version-like code), but for sake of consistency, and also because - * it will tell us which ID is re-used from old Main, and which one is actually new. */ - id_old->tag = tag | LIB_TAG_NEED_LINK | LIB_TAG_UNDO_OLD_ID_REUSED; - id_old->lib = main->curlib; - id_old->us = ID_FAKE_USERS(id_old); - /* Do not reset id->icon_id here, memory allocated for it remains valid. */ - /* Needed because .blend may have been saved with crap value here... */ - id_old->newid = NULL; - id_old->orig_id = NULL; - - /* About recalc: since that ID did not change at all, we know that its recalc fields also - * remained unchanged, so no need to handle neither recalc nor recalc_undo_future here. - */ - - Main *old_bmain = fd->old_mainlist->first; - ListBase *old_lb = which_libbase(old_bmain, idcode); - ListBase *new_lb = which_libbase(main, idcode); - BLI_remlink(old_lb, id_old); - BLI_addtail(new_lb, id_old); + if (do_partial_undo) { + const bool is_identical = read_libblock_is_identical(fd, id_bhead); + DEBUG_PRINTF("%s: ID %s is unchanged: %d\n", __func__, id->name, is_identical); - DEBUG_PRINTF("Re-using existing ID %s instead of newly read one\n", id_old->name); - oldnewmap_insert(fd->libmap, bhead->old, id_old, bhead->code); - oldnewmap_insert(fd->libmap, id_old, id_old, bhead->code); + BLI_assert(fd->old_idmap != NULL || !do_partial_undo); + /* This code should only ever be reached for local data-blocks. */ + BLI_assert(main->curlib == NULL); - if (r_id) { - *r_id = id_old; - } - - if (do_partial_undo) { - /* Even though we re-use the old ID as-is, it does not mean that we are 100% safe from - * needing some depsgraph updates for it (it could depend on another ID which address - * did not change, but which actual content might have been re-read from the memfile). - * IMPORTANT: Do not fully overwrite recalc flag here, depsgraph may not have been ran - * yet for previous undo step(s), we do not want to erase flags set by those. - */ - if (fd->undo_direction < 0) { - /* We are coming from the future (i.e. do an actual undo, and not a redo), we use our - * old reused ID's 'accumulated recalc flags since last memfile undo step saving' as - * recalc flags. */ - id_old->recalc |= id_old->recalc_undo_accumulated; - } - else { - /* We are coming from the past (i.e. do a redo), we use the saved 'accumulated recalc - * flags since last memfile undo step saving' from the newly read ID as recalc flags. - */ - id_old->recalc |= id->recalc_undo_accumulated; - } - /* There is no need to flush the depsgraph's CoWs here, since that ID's data itself did - * not change. */ + /* Find the 'current' existing ID we want to reuse instead of the one we would read from + * the undo memfile. */ + DEBUG_PRINTF("\t Looking for ID %s with uuid %u instead of newly read one\n", + id->name, + id->session_uuid); + id_old = BKE_main_idmap_lookup_uuid(fd->old_idmap, id->session_uuid); + + if (id_old != NULL && is_identical) { + /* Do not add LIB_TAG_NEW here, this should not be needed/used in undo case anyway (as + * this is only for do_version-like code), but for sake of consistency, and also because + * it will tell us which ID is re-used from old Main, and which one is actually new. */ + id_old->tag = tag | LIB_TAG_NEED_LINK | LIB_TAG_UNDO_OLD_ID_REUSED; + id_old->lib = main->curlib; + id_old->us = ID_FAKE_USERS(id_old); + /* Do not reset id->icon_id here, memory allocated for it remains valid. */ + /* Needed because .blend may have been saved with crap value here... */ + id_old->newid = NULL; + id_old->orig_id = NULL; + + /* About recalc: since that ID did not change at all, we know that its recalc fields also + * remained unchanged, so no need to handle neither recalc nor recalc_undo_future here. + */ - /* We need to 'accumulate' the accumulated recalc flags of all undo steps until we - * actually perform a depsgraph update, otherwise we'd only ever use the flags from one - * of the steps, and never get proper flags matching all others. */ - id_old->recalc_undo_accumulated |= id->recalc_undo_accumulated; - } + Main *old_bmain = fd->old_mainlist->first; + ListBase *old_lb = which_libbase(old_bmain, idcode); + ListBase *new_lb = which_libbase(main, idcode); + BLI_remlink(old_lb, id_old); + BLI_addtail(new_lb, id_old); - MEM_freeN(id); + DEBUG_PRINTF("Re-using existing ID %s instead of newly read one\n", id_old->name); + oldnewmap_insert(fd->libmap, bhead->old, id_old, bhead->code); + oldnewmap_insert(fd->libmap, id_old, id_old, bhead->code); - return blo_bhead_next(fd, bhead); + if (r_id) { + *r_id = id_old; } - } - /* Some re-used old IDs might also use newly read ones, so we have to check for old memory - * addresses for those as well. */ - if (do_partial_undo && id->lib == NULL) { - BLI_assert(fd->old_idmap != NULL); - DEBUG_PRINTF("\t Looking for ID %s with uuid %u instead of newly read one\n", - id->name, - id->session_uuid); - id_old = BKE_main_idmap_lookup_uuid(fd->old_idmap, id->session_uuid); - if (id_old != NULL) { - BLI_assert(MEM_allocN_len(id) == MEM_allocN_len(id_old)); - /* UI IDs are always re-used from old bmain at higher-level calling code, so never swap - * those. Besides maybe custom properties, no other ID should have pointers to those - * anyway... - * And linked IDs are handled separately as well. */ - do_id_swap = !(bhead->code == ID_LINK_PLACEHOLDER); + /* Even though we re-use the old ID as-is, it does not mean that we are 100% safe from + * needing some depsgraph updates for it (it could depend on another ID which address + * did not change, but which actual content might have been re-read from the memfile). + * IMPORTANT: Do not fully overwrite recalc flag here, depsgraph may not have been ran + * yet for previous undo step(s), we do not want to erase flags set by those. + */ + if (fd->undo_direction < 0) { + /* We are coming from the future (i.e. do an actual undo, and not a redo), we use our + * old reused ID's 'accumulated recalc flags since last memfile undo step saving' as + * recalc flags. */ + id_old->recalc |= id_old->recalc_undo_accumulated; } - } + else { + /* We are coming from the past (i.e. do a redo), we use the saved 'accumulated recalc + * flags since last memfile undo step saving' from the newly read ID as recalc flags. + */ + id_old->recalc |= id->recalc_undo_accumulated; + } + /* There is no need to flush the depsgraph's CoWs here, since that ID's data itself did + * not change. */ - /* At this point, we know we are going to keep that newly read & allocated ID, so we need to - * reallocate it to ensure we actually get a unique memory address for it. */ - if (!do_id_swap) { - DEBUG_PRINTF("using newly-read ID %s to a new mem address\n", id->name); + /* We need to 'accumulate' the accumulated recalc flags of all undo steps until we + * actually perform a depsgraph update, otherwise we'd only ever use the flags from one + * of the steps, and never get proper flags matching all others. */ + id_old->recalc_undo_accumulated |= id->recalc_undo_accumulated; + + MEM_freeN(id); + + return blo_bhead_next(fd, bhead); } - else { + else if (id_old != NULL) { + /* Some re-used old IDs might also use newly read ones, so we have to check for old memory + * addresses for those as well. */ DEBUG_PRINTF("using newly-read ID %s to its old, already existing address\n", id->name); + BLI_assert(MEM_allocN_len(id) == MEM_allocN_len(id_old)); + do_id_swap = true; + } + else { + /* At this point, we know we are going to keep that newly read & allocated ID, so we need to + * reallocate it to ensure we actually get a unique memory address for it. */ + DEBUG_PRINTF("using newly-read ID %s to a new mem address\n", id->name); } } -- cgit v1.2.3 From c786f9587123b55afc412d1645977c29865ba9c6 Mon Sep 17 00:00:00 2001 From: Brecht Van Lommel Date: Fri, 3 Apr 2020 14:31:05 +0200 Subject: Cleanup: split partial undo code off into functions, tweak debug prints Differential Revision: https://developer.blender.org/D7331 --- source/blender/blenloader/intern/readfile.c | 264 +++++++++++++++------------- 1 file changed, 142 insertions(+), 122 deletions(-) diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c index 06f53a6c640..d23d61b4d20 100644 --- a/source/blender/blenloader/intern/readfile.c +++ b/source/blender/blenloader/intern/readfile.c @@ -9424,6 +9424,7 @@ static bool read_libblock_is_identical(FileData *fd, BHead *bhead) return true; } +/* For undo, restore matching library datablock from the old main. */ static bool read_libblock_undo_restore_library(FileData *fd, Main *main, const ID *id) { /* In undo case, most libs and linked data should be kept as is from previous state @@ -9460,6 +9461,7 @@ static bool read_libblock_undo_restore_library(FileData *fd, Main *main, const I return false; } +/* For undo, restore existing linked datablock from the old main. */ static bool read_libblock_undo_restore_linked(FileData *fd, Main *main, const ID *id, BHead *bhead) { DEBUG_PRINTF("UNDO: restore linked datablock %s\n", id->name); @@ -9467,17 +9469,17 @@ static bool read_libblock_undo_restore_linked(FileData *fd, Main *main, const ID main->curlib ? main->curlib->id.name : "", main->curlib ? main->curlib->name : ""); - ID *existing_id = BKE_libblock_find_name(main, GS(id->name), id->name + 2); - if (existing_id != NULL) { + ID *id_old = BKE_libblock_find_name(main, GS(id->name), id->name + 2); + if (id_old != NULL) { DEBUG_PRINTF(" found!\n"); - /* Even though we found our linked ID, - * there is no guarantee its address is still the same. */ - if (existing_id != bhead->old) { - oldnewmap_insert(fd->libmap, bhead->old, existing_id, GS(existing_id->name)); + /* Even though we found our linked ID, there is no guarantee its address + * is still the same. */ + if (id_old != bhead->old) { + oldnewmap_insert(fd->libmap, bhead->old, id_old, GS(id_old->name)); } - /* No need to do anything else for ID_LINK_PLACEHOLDER, - * it's assumed already present in its lib's main. */ + /* No need to do anything else for ID_LINK_PLACEHOLDER, it's assumed + * already present in its lib's main. */ return true; } @@ -9485,6 +9487,94 @@ static bool read_libblock_undo_restore_linked(FileData *fd, Main *main, const ID return false; } +/* For undo, restore unchanged datablock from old main. */ +static void read_libblock_undo_restore_identical( + FileData *fd, Main *main, const ID *id, ID *id_old, const int tag) +{ + BLI_assert((fd->skip_flags & BLO_READ_SKIP_UNDO_OLD_MAIN) == 0); + BLI_assert(id_old != NULL); + + id_old->tag = tag; + id_old->lib = main->curlib; + id_old->us = ID_FAKE_USERS(id_old); + /* Do not reset id->icon_id here, memory allocated for it remains valid. */ + /* Needed because .blend may have been saved with crap value here... */ + id_old->newid = NULL; + id_old->orig_id = NULL; + + /* About recalc: since that ID did not change at all, we know that its recalc fields also + * remained unchanged, so no need to handle neither recalc nor recalc_undo_future here. + */ + + const short idcode = GS(id_old->name); + Main *old_bmain = fd->old_mainlist->first; + ListBase *old_lb = which_libbase(old_bmain, idcode); + ListBase *new_lb = which_libbase(main, idcode); + BLI_remlink(old_lb, id_old); + BLI_addtail(new_lb, id_old); + + /* Even though we re-use the old ID as-is, it does not mean that we are 100% safe from + * needing some depsgraph updates for it (it could depend on another ID which address + * did not change, but which actual content might have been re-read from the memfile). + * IMPORTANT: Do not fully overwrite recalc flag here, depsgraph may not have been ran + * yet for previous undo step(s), we do not want to erase flags set by those. + */ + if (fd->undo_direction < 0) { + /* We are coming from the future (i.e. do an actual undo, and not a redo), we use our + * old reused ID's 'accumulated recalc flags since last memfile undo step saving' as + * recalc flags. */ + id_old->recalc |= id_old->recalc_undo_accumulated; + } + else { + /* We are coming from the past (i.e. do a redo), we use the saved 'accumulated recalc + * flags since last memfile undo step saving' from the newly read ID as recalc flags. + */ + id_old->recalc |= id->recalc_undo_accumulated; + } + /* There is no need to flush the depsgraph's CoWs here, since that ID's data itself did + * not change. */ + + /* We need to 'accumulate' the accumulated recalc flags of all undo steps until we + * actually perform a depsgraph update, otherwise we'd only ever use the flags from one + * of the steps, and never get proper flags matching all others. */ + id_old->recalc_undo_accumulated |= id->recalc_undo_accumulated; +} + +/* For undo, store changed datablock at old address. */ +static void read_libblock_undo_restore_at_old_address(FileData *fd, Main *main, ID *id, ID *id_old) +{ + /* During memfile undo, if an ID changed and we cannot directly re-use existing one from old + * bmain, we do a full read of the new id from the memfile, and then fully swap its content + * with the old id. This allows us to keep the same pointer even for modified data, which + * helps reducing further detected changes by the depsgraph (since unchanged IDs remain fully + * unchanged, even if they are using/pointing to a changed one). */ + BLI_assert((fd->skip_flags & BLO_READ_SKIP_UNDO_OLD_MAIN) == 0); + BLI_assert(id_old != NULL); + + const short idcode = GS(id->name); + + Main *old_bmain = fd->old_mainlist->first; + ListBase *old_lb = which_libbase(old_bmain, idcode); + ListBase *new_lb = which_libbase(main, idcode); + BLI_remlink(old_lb, id_old); + BLI_remlink(new_lb, id); + + /* We do not need any remapping from this call here, since no ID pointer is valid in the data + * currently (they are all pointing to old addresses, and need to go through `lib_link` + * process). So we can pass NULL for the Main pointer parameter. */ + BKE_lib_id_swap_full(NULL, id, id_old); + + BLI_addtail(new_lb, id_old); + BLI_addtail(old_lb, id); +} + +/* This routine reads a datablock and its direct data, and advances bhead to + * the next datablock. For library linked datablocks, only a placeholder will + * be generated, to be replaced in read_library_linked_ids. + * + * When reading for undo, libraries, linked datablocks and unchanged datablocks + * will be restored from the old database. Only new or changed datablocks will + * actually be read. */ static BHead *read_libblock(FileData *fd, Main *main, BHead *bhead, @@ -9492,10 +9582,9 @@ static BHead *read_libblock(FileData *fd, const bool placeholder_set_indirect_extern, ID **r_id) { - /* This routine reads a libblock and its direct data. Lib link functions will - * set points between datablocks. */ + /* Initialize in case of early return. */ if (r_id) { - *r_id = NULL; /* In case of early return. */ + *r_id = NULL; } /* Read libblock struct. */ @@ -9515,15 +9604,21 @@ static BHead *read_libblock(FileData *fd, return blo_bhead_next(fd, bhead); } - /* Restore library and linked datablocks for undo. */ + /* Used when undoing from memfile, we swap changed IDs into their old addresses when found. */ + ID *id_old = NULL; + bool restore_at_old_address = false; + + /* Restore existing datablocks for undo. */ if (fd->memfile != NULL) { if (bhead->code == ID_LI) { + /* Restore library datablock. */ if (read_libblock_undo_restore_library(fd, main, id)) { MEM_freeN(id); return blo_bhead_next(fd, bhead); } } else if (bhead->code == ID_LINK_PLACEHOLDER) { + /* Restore linked datablock. */ if (read_libblock_undo_restore_linked(fd, main, id, bhead)) { MEM_freeN(id); return blo_bhead_next(fd, bhead); @@ -9536,55 +9631,33 @@ static BHead *read_libblock(FileData *fd, MEM_freeN(id); return blo_bhead_next(fd, bhead); } - } - /* Restore existing datablocks for undo. */ - const bool do_partial_undo = (fd->memfile != NULL) && - (fd->skip_flags & BLO_READ_SKIP_UNDO_OLD_MAIN) == 0 && - (bhead->code != ID_LINK_PLACEHOLDER); + /* Restore local datablocks. */ + DEBUG_PRINTF("UNDO: read %s (uuid %d) -> ", id->name, id->session_uuid); - /* Used when undoing from memfile, we swap changed IDs into their old addresses when found. */ - ID *id_old = NULL; - bool do_id_swap = false; + const bool do_partial_undo = (fd->skip_flags & BLO_READ_SKIP_UNDO_OLD_MAIN) == 0; + if (do_partial_undo && (bhead->code != ID_LINK_PLACEHOLDER)) { + /* This code should only ever be reached for local data-blocks. */ + BLI_assert(main->curlib == NULL); - if (do_partial_undo) { - const bool is_identical = read_libblock_is_identical(fd, id_bhead); - DEBUG_PRINTF("%s: ID %s is unchanged: %d\n", __func__, id->name, is_identical); - - BLI_assert(fd->old_idmap != NULL || !do_partial_undo); - /* This code should only ever be reached for local data-blocks. */ - BLI_assert(main->curlib == NULL); + /* Find the 'current' existing ID we want to reuse instead of the one we + * would read from the undo memfile. */ + BLI_assert(fd->old_idmap != NULL); + id_old = BKE_main_idmap_lookup_uuid(fd->old_idmap, id->session_uuid); + } - /* Find the 'current' existing ID we want to reuse instead of the one we would read from - * the undo memfile. */ - DEBUG_PRINTF("\t Looking for ID %s with uuid %u instead of newly read one\n", - id->name, - id->session_uuid); - id_old = BKE_main_idmap_lookup_uuid(fd->old_idmap, id->session_uuid); + if (id_old != NULL && read_libblock_is_identical(fd, id_bhead)) { + /* Local datablock was unchanged, restore from the old main. */ + DEBUG_PRINTF("keep identical datablock\n"); - if (id_old != NULL && is_identical) { /* Do not add LIB_TAG_NEW here, this should not be needed/used in undo case anyway (as * this is only for do_version-like code), but for sake of consistency, and also because * it will tell us which ID is re-used from old Main, and which one is actually new. */ - id_old->tag = tag | LIB_TAG_NEED_LINK | LIB_TAG_UNDO_OLD_ID_REUSED; - id_old->lib = main->curlib; - id_old->us = ID_FAKE_USERS(id_old); - /* Do not reset id->icon_id here, memory allocated for it remains valid. */ - /* Needed because .blend may have been saved with crap value here... */ - id_old->newid = NULL; - id_old->orig_id = NULL; - - /* About recalc: since that ID did not change at all, we know that its recalc fields also - * remained unchanged, so no need to handle neither recalc nor recalc_undo_future here. - */ + const int id_tag = tag | LIB_TAG_NEED_LINK | LIB_TAG_UNDO_OLD_ID_REUSED; + read_libblock_undo_restore_identical(fd, main, id, id_old, id_tag); - Main *old_bmain = fd->old_mainlist->first; - ListBase *old_lb = which_libbase(old_bmain, idcode); - ListBase *new_lb = which_libbase(main, idcode); - BLI_remlink(old_lb, id_old); - BLI_addtail(new_lb, id_old); - - DEBUG_PRINTF("Re-using existing ID %s instead of newly read one\n", id_old->name); + /* Insert into library map for lookup by newly read datablocks (with pointer + * value bhead->old) or existing datablocks in memory (pointer value id_old). */ oldnewmap_insert(fd->libmap, bhead->old, id_old, bhead->code); oldnewmap_insert(fd->libmap, id_old, id_old, bhead->code); @@ -9592,67 +9665,41 @@ static BHead *read_libblock(FileData *fd, *r_id = id_old; } - /* Even though we re-use the old ID as-is, it does not mean that we are 100% safe from - * needing some depsgraph updates for it (it could depend on another ID which address - * did not change, but which actual content might have been re-read from the memfile). - * IMPORTANT: Do not fully overwrite recalc flag here, depsgraph may not have been ran - * yet for previous undo step(s), we do not want to erase flags set by those. - */ - if (fd->undo_direction < 0) { - /* We are coming from the future (i.e. do an actual undo, and not a redo), we use our - * old reused ID's 'accumulated recalc flags since last memfile undo step saving' as - * recalc flags. */ - id_old->recalc |= id_old->recalc_undo_accumulated; - } - else { - /* We are coming from the past (i.e. do a redo), we use the saved 'accumulated recalc - * flags since last memfile undo step saving' from the newly read ID as recalc flags. - */ - id_old->recalc |= id->recalc_undo_accumulated; - } - /* There is no need to flush the depsgraph's CoWs here, since that ID's data itself did - * not change. */ - - /* We need to 'accumulate' the accumulated recalc flags of all undo steps until we - * actually perform a depsgraph update, otherwise we'd only ever use the flags from one - * of the steps, and never get proper flags matching all others. */ - id_old->recalc_undo_accumulated |= id->recalc_undo_accumulated; - MEM_freeN(id); - return blo_bhead_next(fd, bhead); } else if (id_old != NULL) { - /* Some re-used old IDs might also use newly read ones, so we have to check for old memory - * addresses for those as well. */ - DEBUG_PRINTF("using newly-read ID %s to its old, already existing address\n", id->name); + /* Local datablock was changed. Restore at the address of the old datablock. */ + DEBUG_PRINTF("read to old existing address\n"); BLI_assert(MEM_allocN_len(id) == MEM_allocN_len(id_old)); - do_id_swap = true; + restore_at_old_address = true; } else { - /* At this point, we know we are going to keep that newly read & allocated ID, so we need to - * reallocate it to ensure we actually get a unique memory address for it. */ - DEBUG_PRINTF("using newly-read ID %s to a new mem address\n", id->name); + /* Local datablock does not exist in the undo step, so read from scratch. */ + DEBUG_PRINTF("read at new address\n"); } } - /* for ID_LINK_PLACEHOLDER check */ - ID *id_target = do_id_swap ? id_old : id; + /* Insert into library map for lookup by newly read datablocks (with pointer + * value bhead->old) or existing datablocks in memory (pointer value id_old). */ + ID *id_target = restore_at_old_address ? id_old : id; oldnewmap_insert(fd->libmap, bhead->old, id_target, bhead->code); oldnewmap_insert(fd->libmap, id_old, id_target, bhead->code); - BLI_addtail(lb, id); - if (r_id) { - *r_id = do_id_swap ? id_old : id; + *r_id = id_target; } + /* NOTE: id must be added to the list before direct_link_id(), since + * direct_link_library() may remove it from there in case of duplicates. */ + BLI_addtail(lb, id); + /* Set tag for new datablock to indicate lib linking and versioning needs * to be done still. */ int id_tag = tag | LIB_TAG_NEED_LINK | LIB_TAG_NEW; - /* Read placeholder for linked datablock. */ if (bhead->code == ID_LINK_PLACEHOLDER) { + /* Read placeholder for linked datablock. */ id_tag |= LIB_TAG_ID_LINK_PLACEHOLDER; if (placeholder_set_indirect_extern) { @@ -9685,36 +9732,9 @@ static BHead *read_libblock(FileData *fd, *r_id = NULL; } } - else if (do_id_swap) { - /* During memfile undo, if an ID changed and we cannot directly re-use existing one from old - * bmain, we do a full read of the new id from the memfile, and then fully swap its content - * with the old id. This allows us to keep the same pointer even for modified data, which helps - * reducing further detected changes by the depsgraph (since unchanged IDs remain fully - * unchanged, even if they are using/pointing to a changed one). */ - - BLI_assert((fd->skip_flags & BLO_READ_SKIP_UNDO_OLD_MAIN) == 0); - - Main *old_bmain = fd->old_mainlist->first; - BLI_assert(id_old != NULL); - - ListBase *old_lb = which_libbase(old_bmain, idcode); - ListBase *new_lb = which_libbase(main, idcode); - BLI_remlink(old_lb, id_old); - BLI_remlink(new_lb, id); - - /* We do not need any remapping from this call here, since no ID pointer is valid in the data - * currently (they are all pointing to old addresses, and need to go through `lib_link` - * process). So we can pass NULL for the Main pointer parameter. */ - BKE_lib_id_swap_full(NULL, id, id_old); - - BLI_addtail(new_lb, id_old); - BLI_addtail(old_lb, id); - } - else if (fd->memfile != NULL) { - DEBUG_PRINTF("We had to fully re-recreate ID %s (old addr: %p, new addr: %p)...\n", - id->name, - id_old, - id); + else if (restore_at_old_address) { + /* For undo, store contents read into id at id_old. */ + read_libblock_undo_restore_at_old_address(fd, main, id, id_old); } return bhead; -- cgit v1.2.3 From e953ada0bb9d22108e3a96b8faecfaa58c97caac Mon Sep 17 00:00:00 2001 From: Brecht Van Lommel Date: Sat, 4 Apr 2020 17:38:07 +0200 Subject: Cleanup: avoid memory allocation for unchanged datablocks in undo Differential Revision: https://developer.blender.org/D7336 --- source/blender/blenloader/intern/readfile.c | 190 +++++++++++++++------------- 1 file changed, 104 insertions(+), 86 deletions(-) diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c index d23d61b4d20..d4799404ef2 100644 --- a/source/blender/blenloader/intern/readfile.c +++ b/source/blender/blenloader/intern/readfile.c @@ -2384,6 +2384,15 @@ static void *read_struct(FileData *fd, BHead *bh, const char *blockname) return temp; } +/* Like read_struct, but gets a pointer without allocating. Only works for + * undo since DNA must match. */ +static const void *peek_struct_undo(FileData *fd, BHead *bhead) +{ + BLI_assert(fd->memfile != NULL); + UNUSED_VARS_NDEBUG(fd); + return (bhead->len) ? (const void *)(bhead + 1) : NULL; +} + typedef void (*link_list_cb)(FileData *fd, void *data); static void link_list_ex(FileData *fd, ListBase *lb, link_list_cb callback) /* only direct data */ @@ -9568,6 +9577,78 @@ static void read_libblock_undo_restore_at_old_address(FileData *fd, Main *main, BLI_addtail(old_lb, id); } +static bool read_libblock_undo_restore( + FileData *fd, Main *main, BHead *bhead, const int tag, ID **r_id_old) +{ + /* Get pointer to memory of new ID that we will be reading. */ + const ID *id = peek_struct_undo(fd, bhead); + const short idcode = GS(id->name); + + if (bhead->code == ID_LI) { + /* Restore library datablock. */ + if (read_libblock_undo_restore_library(fd, main, id)) { + return true; + } + } + else if (bhead->code == ID_LINK_PLACEHOLDER) { + /* Restore linked datablock. */ + if (read_libblock_undo_restore_linked(fd, main, id, bhead)) { + return true; + } + } + else if (ELEM(idcode, ID_WM, ID_SCR, ID_WS)) { + /* Skip reading any UI datablocks, existing ones are kept. We don't + * support pointers from other datablocks to UI datablocks so those + * we also don't put UI datablocks in fd->libmap. */ + return true; + } + + /* Restore local datablocks. */ + DEBUG_PRINTF("UNDO: read %s (uuid %d) -> ", id->name, id->session_uuid); + + ID *id_old = NULL; + const bool do_partial_undo = (fd->skip_flags & BLO_READ_SKIP_UNDO_OLD_MAIN) == 0; + if (do_partial_undo && (bhead->code != ID_LINK_PLACEHOLDER)) { + /* This code should only ever be reached for local data-blocks. */ + BLI_assert(main->curlib == NULL); + + /* Find the 'current' existing ID we want to reuse instead of the one we + * would read from the undo memfile. */ + BLI_assert(fd->old_idmap != NULL); + id_old = BKE_main_idmap_lookup_uuid(fd->old_idmap, id->session_uuid); + } + + if (id_old != NULL && read_libblock_is_identical(fd, bhead)) { + /* Local datablock was unchanged, restore from the old main. */ + DEBUG_PRINTF("keep identical datablock\n"); + + /* Do not add LIB_TAG_NEW here, this should not be needed/used in undo case anyway (as + * this is only for do_version-like code), but for sake of consistency, and also because + * it will tell us which ID is re-used from old Main, and which one is actually new. */ + const int id_tag = tag | LIB_TAG_NEED_LINK | LIB_TAG_UNDO_OLD_ID_REUSED; + read_libblock_undo_restore_identical(fd, main, id, id_old, id_tag); + + /* Insert into library map for lookup by newly read datablocks (with pointer + * value bhead->old) or existing datablocks in memory (pointer value id_old). */ + oldnewmap_insert(fd->libmap, bhead->old, id_old, bhead->code); + oldnewmap_insert(fd->libmap, id_old, id_old, bhead->code); + + *r_id_old = id_old; + return true; + } + else if (id_old != NULL) { + /* Local datablock was changed. Restore at the address of the old datablock. */ + DEBUG_PRINTF("read to old existing address\n"); + *r_id_old = id_old; + return false; + } + else { + /* Local datablock does not exist in the undo step, so read from scratch. */ + DEBUG_PRINTF("read at new address\n"); + return false; + } +} + /* This routine reads a datablock and its direct data, and advances bhead to * the next datablock. For library linked datablocks, only a placeholder will * be generated, to be replaced in read_library_linked_ids. @@ -9582,107 +9663,48 @@ static BHead *read_libblock(FileData *fd, const bool placeholder_set_indirect_extern, ID **r_id) { - /* Initialize in case of early return. */ - if (r_id) { - *r_id = NULL; + /* First attemp to restore existing datablocks for undo. + * When datablocks are changed but still exist, we restore them at the old + * address and inherit recalc flags for the dependency graph. */ + ID *id_old = NULL; + if (fd->memfile != NULL) { + if (read_libblock_undo_restore(fd, main, bhead, tag, &id_old)) { + if (r_id) { + *r_id = id_old; + } + return blo_bhead_next(fd, bhead); + } } /* Read libblock struct. */ - BHead *id_bhead = bhead; ID *id = read_struct(fd, bhead, "lib block"); if (id == NULL) { + if (r_id) { + *r_id = NULL; + } return blo_bhead_next(fd, bhead); } - /* Determine ID type. */ + /* Determine ID type and add to main database list. */ const short idcode = GS(id->name); ListBase *lb = which_libbase(main, idcode); if (lb == NULL) { /* Unknown ID type. */ printf("%s: unknown id code '%c%c'\n", __func__, (idcode & 0xff), (idcode >> 8)); MEM_freeN(id); + if (r_id) { + *r_id = NULL; + } return blo_bhead_next(fd, bhead); } - /* Used when undoing from memfile, we swap changed IDs into their old addresses when found. */ - ID *id_old = NULL; - bool restore_at_old_address = false; - - /* Restore existing datablocks for undo. */ - if (fd->memfile != NULL) { - if (bhead->code == ID_LI) { - /* Restore library datablock. */ - if (read_libblock_undo_restore_library(fd, main, id)) { - MEM_freeN(id); - return blo_bhead_next(fd, bhead); - } - } - else if (bhead->code == ID_LINK_PLACEHOLDER) { - /* Restore linked datablock. */ - if (read_libblock_undo_restore_linked(fd, main, id, bhead)) { - MEM_freeN(id); - return blo_bhead_next(fd, bhead); - } - } - else if (ELEM(idcode, ID_WM, ID_SCR, ID_WS)) { - /* Skip reading any UI datablocks, existing ones are kept. We don't - * support pointers from other datablocks to UI datablocks so those - * we also don't put UI datablocks in fd->libmap. */ - MEM_freeN(id); - return blo_bhead_next(fd, bhead); - } - - /* Restore local datablocks. */ - DEBUG_PRINTF("UNDO: read %s (uuid %d) -> ", id->name, id->session_uuid); - - const bool do_partial_undo = (fd->skip_flags & BLO_READ_SKIP_UNDO_OLD_MAIN) == 0; - if (do_partial_undo && (bhead->code != ID_LINK_PLACEHOLDER)) { - /* This code should only ever be reached for local data-blocks. */ - BLI_assert(main->curlib == NULL); - - /* Find the 'current' existing ID we want to reuse instead of the one we - * would read from the undo memfile. */ - BLI_assert(fd->old_idmap != NULL); - id_old = BKE_main_idmap_lookup_uuid(fd->old_idmap, id->session_uuid); - } - - if (id_old != NULL && read_libblock_is_identical(fd, id_bhead)) { - /* Local datablock was unchanged, restore from the old main. */ - DEBUG_PRINTF("keep identical datablock\n"); - - /* Do not add LIB_TAG_NEW here, this should not be needed/used in undo case anyway (as - * this is only for do_version-like code), but for sake of consistency, and also because - * it will tell us which ID is re-used from old Main, and which one is actually new. */ - const int id_tag = tag | LIB_TAG_NEED_LINK | LIB_TAG_UNDO_OLD_ID_REUSED; - read_libblock_undo_restore_identical(fd, main, id, id_old, id_tag); - - /* Insert into library map for lookup by newly read datablocks (with pointer - * value bhead->old) or existing datablocks in memory (pointer value id_old). */ - oldnewmap_insert(fd->libmap, bhead->old, id_old, bhead->code); - oldnewmap_insert(fd->libmap, id_old, id_old, bhead->code); - - if (r_id) { - *r_id = id_old; - } - - MEM_freeN(id); - return blo_bhead_next(fd, bhead); - } - else if (id_old != NULL) { - /* Local datablock was changed. Restore at the address of the old datablock. */ - DEBUG_PRINTF("read to old existing address\n"); - BLI_assert(MEM_allocN_len(id) == MEM_allocN_len(id_old)); - restore_at_old_address = true; - } - else { - /* Local datablock does not exist in the undo step, so read from scratch. */ - DEBUG_PRINTF("read at new address\n"); - } - } + /* NOTE: id must be added to the list before direct_link_id(), since + * direct_link_library() may remove it from there in case of duplicates. */ + BLI_addtail(lb, id); /* Insert into library map for lookup by newly read datablocks (with pointer * value bhead->old) or existing datablocks in memory (pointer value id_old). */ - ID *id_target = restore_at_old_address ? id_old : id; + ID *id_target = id_old ? id_old : id; oldnewmap_insert(fd->libmap, bhead->old, id_target, bhead->code); oldnewmap_insert(fd->libmap, id_old, id_target, bhead->code); @@ -9690,10 +9712,6 @@ static BHead *read_libblock(FileData *fd, *r_id = id_target; } - /* NOTE: id must be added to the list before direct_link_id(), since - * direct_link_library() may remove it from there in case of duplicates. */ - BLI_addtail(lb, id); - /* Set tag for new datablock to indicate lib linking and versioning needs * to be done still. */ int id_tag = tag | LIB_TAG_NEED_LINK | LIB_TAG_NEW; @@ -9732,7 +9750,7 @@ static BHead *read_libblock(FileData *fd, *r_id = NULL; } } - else if (restore_at_old_address) { + else if (id_old) { /* For undo, store contents read into id at id_old. */ read_libblock_undo_restore_at_old_address(fd, main, id, id_old); } -- cgit v1.2.3 From aaaa0a43af1b40b9de31a737a055b3d2f62b6458 Mon Sep 17 00:00:00 2001 From: Brecht Van Lommel Date: Tue, 7 Apr 2020 03:52:46 +0200 Subject: Build: use -no-pie for portable builds on Linux Otherwise file browsers do not recognize the Blender executable. This is already done for official releases. We leave it off for non-portable builds, since that's how Linux distribution packages will typically build Blender and we can continue to follow the OS default there. Using a file browser to launch executables from e.g. /usr/bin would be rare as wel. Differential Revision: https://developer.blender.org/D7363 --- build_files/cmake/platform/platform_unix.cmake | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/build_files/cmake/platform/platform_unix.cmake b/build_files/cmake/platform/platform_unix.cmake index cd304d65eac..050ab8f3ba1 100644 --- a/build_files/cmake/platform/platform_unix.cmake +++ b/build_files/cmake/platform/platform_unix.cmake @@ -606,3 +606,10 @@ endif() set(PLATFORM_LINKFLAGS "${PLATFORM_LINKFLAGS} -Wl,--version-script='${CMAKE_SOURCE_DIR}/source/creator/blender.map'" ) + +# Don't use position independent executable for portable install since file +# browsers can't properly detect blender as an executable then. Still enabled +# for non-portable installs as typically used by Linux distributions. +if(WITH_INSTALL_PORTABLE) + set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -no-pie") +endif() -- cgit v1.2.3 From 58e20b432a2bd7fbff7ebb7aa1f49a6662dc6e7c Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Tue, 7 Apr 2020 21:30:18 +1000 Subject: Fix memory leak in recent panel drag widget cache Memory leak from 60d873bd22121. --- source/blender/gpu/intern/gpu_batch_presets.c | 1 + 1 file changed, 1 insertion(+) diff --git a/source/blender/gpu/intern/gpu_batch_presets.c b/source/blender/gpu/intern/gpu_batch_presets.c index 34bd921992c..9a282e95664 100644 --- a/source/blender/gpu/intern/gpu_batch_presets.c +++ b/source/blender/gpu/intern/gpu_batch_presets.c @@ -309,6 +309,7 @@ GPUBatch *GPU_batch_preset_panel_drag_widget(const float pixelsize, !equals_v4v4(g_presets_2d.panel_drag_widget_col_dark, col_dark); if (g_presets_2d.batch.panel_drag_widget && parameters_changed) { + GPU_batch_discard(g_presets_2d.batch.panel_drag_widget); gpu_batch_presets_unregister(g_presets_2d.batch.panel_drag_widget); GPU_batch_discard(g_presets_2d.batch.panel_drag_widget); g_presets_2d.batch.panel_drag_widget = NULL; -- cgit v1.2.3 From 6feeede47ffa59f4128da7a82d1e0f115337bdac Mon Sep 17 00:00:00 2001 From: Brecht Van Lommel Date: Tue, 7 Apr 2020 13:42:43 +0200 Subject: Fix Blender not rebuilding when changing linker script --- source/creator/CMakeLists.txt | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/source/creator/CMakeLists.txt b/source/creator/CMakeLists.txt index ced0532a8fa..4b51f9738b3 100644 --- a/source/creator/CMakeLists.txt +++ b/source/creator/CMakeLists.txt @@ -1061,6 +1061,12 @@ unset(LIB) setup_liblinks(blender) +if(APPLE) + set_target_properties(blender PROPERTIES LINK_DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/osx_locals.map) +elseif(UNIX) + set_target_properties(blender PROPERTIES LINK_DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/blender.map) +endif() + # ----------------------------------------------------------------------------- # USD registry. # USD requires a set of JSON files that define the standard schemas. These -- cgit v1.2.3 From ee43cf572247d3ac158da8e284e0afeb78437a7f Mon Sep 17 00:00:00 2001 From: Sebastian Parborg Date: Tue, 7 Apr 2020 13:50:57 +0200 Subject: Fix T66751: Symmetrizing armature does not symmetrize constraints. The symmetrize operator now tries to make sure that the armature constraints are correctly mirrored. Before it would only mirror the subtargets for the constraints (and that failed too in some cases). Reviewed By: Sybren Differential Revision: http://developer.blender.org/D6009 --- source/blender/blenkernel/intern/action.c | 1 + source/blender/editors/armature/armature_add.c | 546 ++++++++++++++++++++-- source/blender/editors/armature/armature_intern.h | 9 - 3 files changed, 504 insertions(+), 52 deletions(-) diff --git a/source/blender/blenkernel/intern/action.c b/source/blender/blenkernel/intern/action.c index 478609f2f3f..ba77538bfb6 100644 --- a/source/blender/blenkernel/intern/action.c +++ b/source/blender/blenkernel/intern/action.c @@ -925,6 +925,7 @@ void BKE_pose_channel_free_ex(bPoseChannel *pchan, bool do_id_user) if (pchan->prop) { IDP_FreeProperty(pchan->prop); + pchan->prop = NULL; } /* Cached data, for new draw manager rendering code. */ diff --git a/source/blender/editors/armature/armature_add.c b/source/blender/editors/armature/armature_add.c index 0bc405a9c67..3fce2376b40 100644 --- a/source/blender/editors/armature/armature_add.c +++ b/source/blender/editors/armature/armature_add.c @@ -22,6 +22,7 @@ * \ingroup edarmature */ +#include "DNA_anim_types.h" #include "DNA_armature_types.h" #include "DNA_constraint_types.h" #include "DNA_object_types.h" @@ -38,8 +39,12 @@ #include "BKE_constraint.h" #include "BKE_context.h" #include "BKE_deform.h" +#include "BKE_fcurve.h" #include "BKE_idprop.h" #include "BKE_layer.h" +#include "BKE_lib_id.h" +#include "BKE_library.h" +#include "BKE_main.h" #include "RNA_access.h" #include "RNA_define.h" @@ -375,25 +380,20 @@ void postEditBoneDuplicate(struct ListBase *editbones, Object *ob) BLI_ghash_free(name_map, NULL, NULL); } -/* - * Note: When duplicating cross objects, editbones here is the list of bones - * from the SOURCE object but ob is the DESTINATION object - * */ -void updateDuplicateSubtargetObjects(EditBone *dupBone, +static void updateDuplicateSubtarget(EditBone *dup_bone, ListBase *editbones, - Object *src_ob, - Object *dst_ob) + Object *ob, + bool lookup_mirror_subtarget) { - /* If an edit bone has been duplicated, lets - * update it's constraints if the subtarget - * they point to has also been duplicated + /* If an edit bone has been duplicated, lets update it's constraints if the + * subtarget they point to has also been duplicated. */ EditBone *oldtarget, *newtarget; bPoseChannel *pchan; bConstraint *curcon; ListBase *conlist; - if ((pchan = BKE_pose_channel_verify(dst_ob->pose, dupBone->name))) { + if ((pchan = BKE_pose_channel_verify(ob->pose, dup_bone->name))) { if ((conlist = &pchan->constraints)) { for (curcon = conlist->first; curcon; curcon = curcon->next) { /* does this constraint have a subtarget in @@ -407,8 +407,7 @@ void updateDuplicateSubtargetObjects(EditBone *dupBone, cti->get_constraint_targets(curcon, &targets); for (ct = targets.first; ct; ct = ct->next) { - if ((ct->tar == src_ob) && (ct->subtarget[0])) { - ct->tar = dst_ob; /* update target */ + if ((ct->tar == ob) && (ct->subtarget[0])) { oldtarget = get_named_editbone(editbones, ct->subtarget); if (oldtarget) { /* was the subtarget bone duplicated too? If @@ -419,6 +418,17 @@ void updateDuplicateSubtargetObjects(EditBone *dupBone, newtarget = oldtarget->temp.ebone; BLI_strncpy(ct->subtarget, newtarget->name, sizeof(ct->subtarget)); } + else if (lookup_mirror_subtarget) { + /* The subtarget was not selected for duplication, try to see if a mirror bone of + * the current target exists */ + char name_flip[MAXBONENAME]; + + BLI_string_flip_side_name(name_flip, oldtarget->name, false, sizeof(name_flip)); + newtarget = get_named_editbone(editbones, name_flip); + if (newtarget) { + BLI_strncpy(ct->subtarget, newtarget->name, sizeof(ct->subtarget)); + } + } } } } @@ -432,32 +442,435 @@ void updateDuplicateSubtargetObjects(EditBone *dupBone, } } -void updateDuplicateSubtarget(EditBone *dupBone, ListBase *editbones, Object *ob) +static void updateDuplicateActionConstraintSettings(EditBone *dup_bone, + EditBone *orig_bone, + Object *ob, + bConstraint *curcon) { - updateDuplicateSubtargetObjects(dupBone, editbones, ob, ob); + bActionConstraint *act_con = (bActionConstraint *)curcon->data; + bAction *act = (bAction *)act_con->act; + + float mat[4][4]; + + unit_m4(mat); + bPoseChannel *target_pchan = BKE_pose_channel_find_name(ob->pose, act_con->subtarget); + BKE_constraint_mat_convertspace( + ob, target_pchan, mat, curcon->tarspace, CONSTRAINT_SPACE_LOCAL, false); + + float max_axis_val = 0; + int max_axis = 0; + /* Which axis represents X now. IE, which axis defines the mirror plane. */ + for (int i = 0; i < 3; i++) { + float cur_val = fabsf(mat[0][i]); + if (cur_val > max_axis_val) { + max_axis = i; + max_axis_val = cur_val; + } + } + + /* data->type is mapped as follows for backwards compatibility: + * 00,01,02 - rotation (it used to be like this) + * 10,11,12 - scaling + * 20,21,22 - location + */ + /* Mirror the target range */ + if (act_con->type < 10 && act_con->type != max_axis) { + /* Y or Z rotation */ + act_con->min = -act_con->min; + act_con->max = -act_con->max; + } + else if (act_con->type == max_axis + 10) { + /* X scaling */ + } + else if (act_con->type == max_axis + 20) { + /* X location */ + float imat[4][4]; + + invert_m4_m4(imat, mat); + + float min_vec[3], max_vec[3]; + + zero_v3(min_vec); + zero_v3(max_vec); + + min_vec[0] = act_con->min; + max_vec[0] = act_con->max; + + /* convert values into local object space */ + mul_m4_v3(mat, min_vec); + mul_m4_v3(mat, max_vec); + + min_vec[0] *= -1; + max_vec[0] *= -1; + + /* convert back to the settings space */ + mul_m4_v3(imat, min_vec); + mul_m4_v3(imat, max_vec); + + act_con->min = min_vec[0]; + act_con->max = max_vec[0]; + } + + /* See if there is any channels that uses this bone */ + ListBase ani_curves; + BLI_listbase_clear(&ani_curves); + if (list_find_data_fcurves(&ani_curves, &act->curves, "pose.bones[", orig_bone->name)) { + /* Create a copy and mirror the animation */ + for (LinkData *ld = ani_curves.first; ld; ld = ld->next) { + FCurve *old_curve = ld->data; + FCurve *new_curve = copy_fcurve(old_curve); + bActionGroup *agrp; + + char *old_path = new_curve->rna_path; + + new_curve->rna_path = BLI_str_replaceN(old_path, orig_bone->name, dup_bone->name); + MEM_freeN(old_path); + + /* Flip the animation */ + int i; + BezTriple *bezt; + for (i = 0, bezt = new_curve->bezt; i < new_curve->totvert; i++, bezt++) { + const size_t slength = strlen(new_curve->rna_path); + bool flip = false; + if (BLI_strn_endswith(new_curve->rna_path, "location", slength) && + new_curve->array_index == 0) { + flip = true; + } + else if (BLI_strn_endswith(new_curve->rna_path, "rotation_quaternion", slength) && + ELEM(new_curve->array_index, 2, 3)) { + flip = true; + } + else if (BLI_strn_endswith(new_curve->rna_path, "rotation_euler", slength) && + ELEM(new_curve->array_index, 1, 2)) { + flip = true; + } + else if (BLI_strn_endswith(new_curve->rna_path, "rotation_axis_angle", slength) && + ELEM(new_curve->array_index, 2, 3)) { + flip = true; + } + + if (flip) { + bezt->vec[0][1] *= -1; + bezt->vec[1][1] *= -1; + bezt->vec[2][1] *= -1; + } + } + + /* Make sure that a action group name for the new bone exists */ + agrp = BKE_action_group_find_name(act, dup_bone->name); + + if (agrp == NULL) { + agrp = action_groups_add_new(act, dup_bone->name); + } + BLI_assert(agrp != NULL); + action_groups_add_channel(act, agrp, new_curve); + } + } + BLI_freelistN(&ani_curves); + + /* Make deps graph aware of our changes */ + DEG_id_tag_update(&act->id, ID_RECALC_ANIMATION_NO_FLUSH); } -EditBone *duplicateEditBoneObjects( - EditBone *curBone, const char *name, ListBase *editbones, Object *src_ob, Object *dst_ob) +static void updateDuplicateKinematicConstraintSettings(bConstraint *curcon) { - EditBone *eBone = MEM_mallocN(sizeof(EditBone), "addup_editbone"); + /* IK constraint */ + bKinematicConstraint *ik = (bKinematicConstraint *)curcon->data; + ik->poleangle = -M_PI - ik->poleangle; + /* Wrap the angle to the +/-180.0f range (default soft limit of the input boxes). */ + ik->poleangle = angle_wrap_rad(ik->poleangle); +} - /* Copy data from old bone to new bone */ - memcpy(eBone, curBone, sizeof(EditBone)); +static void updateDuplicateLocRotConstraintSettings(Object *ob, + bPoseChannel *pchan, + bConstraint *curcon) +{ + /* This code assumes that bRotLimitConstraint and bLocLimitConstraint have the same fields in + * the same memory locations. */ + BLI_assert(sizeof(bLocLimitConstraint) == sizeof(bRotLimitConstraint)); - curBone->temp.ebone = eBone; - eBone->temp.ebone = curBone; + bRotLimitConstraint *limit = (bRotLimitConstraint *)curcon->data; + float local_mat[4][4], imat[4][4]; - if (name != NULL) { - BLI_strncpy(eBone->name, name, sizeof(eBone->name)); + float min_vec[3], max_vec[3]; + + min_vec[0] = limit->xmin; + min_vec[1] = limit->ymin; + min_vec[2] = limit->zmin; + + max_vec[0] = limit->xmax; + max_vec[1] = limit->ymax; + max_vec[2] = limit->zmax; + + unit_m4(local_mat); + + BKE_constraint_mat_convertspace( + ob, pchan, local_mat, curcon->ownspace, CONSTRAINT_SPACE_LOCAL, false); + + if (curcon->type == CONSTRAINT_TYPE_ROTLIMIT) { + /* Zero out any location translation */ + local_mat[3][0] = local_mat[3][1] = local_mat[3][2] = 0; + } + + invert_m4_m4(imat, local_mat); + /* convert values into local object space */ + mul_m4_v3(local_mat, min_vec); + mul_m4_v3(local_mat, max_vec); + + if (curcon->type == CONSTRAINT_TYPE_ROTLIMIT) { + float min_copy[3]; + + copy_v3_v3(min_copy, min_vec); + + min_vec[1] = max_vec[1] * -1; + min_vec[2] = max_vec[2] * -1; + + max_vec[1] = min_copy[1] * -1; + max_vec[2] = min_copy[2] * -1; + } + else { + float min_x_copy = min_vec[0]; + + min_vec[0] = max_vec[0] * -1; + max_vec[0] = min_x_copy * -1; + } + + /* convert back to the settings space */ + mul_m4_v3(imat, min_vec); + mul_m4_v3(imat, max_vec); + + limit->xmin = min_vec[0]; + limit->ymin = min_vec[1]; + limit->zmin = min_vec[2]; + + limit->xmax = max_vec[0]; + limit->ymax = max_vec[1]; + limit->zmax = max_vec[2]; +} + +static void updateDuplicateTransformConstraintSettings(Object *ob, + bPoseChannel *pchan, + bConstraint *curcon) +{ + bTransformConstraint *trans = (bTransformConstraint *)curcon->data; + + float target_mat[4][4], own_mat[4][4], imat[4][4]; + + unit_m4(own_mat); + BKE_constraint_mat_convertspace( + ob, pchan, own_mat, curcon->ownspace, CONSTRAINT_SPACE_LOCAL, false); + + /* ###Source map mirroring### */ + float old_min, old_max; + + /* Source location */ + invert_m4_m4(imat, own_mat); + + /* convert values into local object space */ + mul_m4_v3(own_mat, trans->from_min); + mul_m4_v3(own_mat, trans->from_max); + + old_min = trans->from_min[0]; + old_max = trans->from_max[0]; + + trans->from_min[0] = -old_max; + trans->from_max[0] = -old_min; + + /* convert back to the settings space */ + mul_m4_v3(imat, trans->from_min); + mul_m4_v3(imat, trans->from_max); + + /* Source rotation */ + + /* Zero out any location translation */ + own_mat[3][0] = own_mat[3][1] = own_mat[3][2] = 0; + + invert_m4_m4(imat, own_mat); + + /* convert values into local object space */ + mul_m4_v3(own_mat, trans->from_min_rot); + mul_m4_v3(own_mat, trans->from_max_rot); + + old_min = trans->from_min_rot[1]; + old_max = trans->from_max_rot[1]; + + trans->from_min_rot[1] = old_max * -1; + trans->from_max_rot[1] = old_min * -1; + + old_min = trans->from_min_rot[2]; + old_max = trans->from_max_rot[2]; + + trans->from_min_rot[2] = old_max * -1; + trans->from_max_rot[2] = old_min * -1; + + /* convert back to the settings space */ + mul_m4_v3(imat, trans->from_min_rot); + mul_m4_v3(imat, trans->from_max_rot); + + /* Source scale does not require any mirroring */ + + /* ###Destination map mirroring### */ + float temp_vec[3]; + float imat_rot[4][4]; + + bPoseChannel *target_pchan = BKE_pose_channel_find_name(ob->pose, trans->subtarget); + unit_m4(target_mat); + BKE_constraint_mat_convertspace( + ob, target_pchan, target_mat, curcon->tarspace, CONSTRAINT_SPACE_LOCAL, false); + + invert_m4_m4(imat, target_mat); + /* convert values into local object space */ + mul_m4_v3(target_mat, trans->to_min); + mul_m4_v3(target_mat, trans->to_max); + mul_m4_v3(target_mat, trans->to_min_scale); + mul_m4_v3(target_mat, trans->to_max_scale); + + /* Zero out any location translation */ + target_mat[3][0] = target_mat[3][1] = target_mat[3][2] = 0; + invert_m4_m4(imat_rot, target_mat); + + mul_m4_v3(target_mat, trans->to_min_rot); + mul_m4_v3(target_mat, trans->to_max_rot); + + /* TODO This does not support euler order, but doing so will make this way more complex. + * For now we have decided to not support all cornercases and advanced setups. (sebpa) + */ + + /* Helper variables to denote the axis in trans->map */ + const char X = 0; + const char Y = 1; + const char Z = 2; + + switch (trans->to) { + case TRANS_SCALE: + copy_v3_v3(temp_vec, trans->to_max_scale); + + for (int i = 0; i < 3; i++) { + if ((trans->from == TRANS_LOCATION && trans->map[i] == X) || + (trans->from == TRANS_ROTATION && trans->map[i] != X)) { + /* X Loc to X/Y/Z Scale: Min/Max Flipped */ + /* Y Rot to X/Y/Z Scale: Min/Max Flipped */ + /* Z Rot to X/Y/Z Scale: Min/Max Flipped */ + trans->to_max_scale[i] = trans->to_min_scale[i]; + trans->to_min_scale[i] = temp_vec[i]; + } + } + break; + case TRANS_LOCATION: + /* Invert the X location */ + trans->to_min[0] *= -1; + trans->to_max[0] *= -1; + + copy_v3_v3(temp_vec, trans->to_max); + + for (int i = 0; i < 3; i++) { + if ((trans->from == TRANS_LOCATION && trans->map[i] == X) || + (trans->from == TRANS_ROTATION && trans->map[i] != X)) { + /* X Loc to X/Y/Z Loc: Min/Max Flipped (and Inverted) + * Y Rot to X/Y/Z Loc: Min/Max Flipped + * Z Rot to X/Y/Z Loc: Min/Max Flipped */ + trans->to_max[i] = trans->to_min[i]; + trans->to_min[i] = temp_vec[i]; + } + } + break; + case TRANS_ROTATION: + /* Invert the Z rotation */ + trans->to_min_rot[2] *= -1; + trans->to_max_rot[2] *= -1; + + if ((trans->from == TRANS_LOCATION && trans->map[1] != X) || + (trans->from == TRANS_ROTATION && trans->map[1] != Y) || trans->from == TRANS_SCALE) { + /* Invert the Y rotation */ + trans->to_min_rot[1] *= -1; + trans->to_max_rot[1] *= -1; + } + + copy_v3_v3(temp_vec, trans->to_max_rot); + + for (int i = 0; i < 3; i++) { + if ((trans->from == TRANS_LOCATION && trans->map[i] == X && i != 1) || + (trans->from == TRANS_ROTATION && trans->map[i] == Y && i != 1) || + (trans->from == TRANS_ROTATION && trans->map[i] == Z)) { + /* X Loc to X/Z Rot: Flipped + * Y Rot to X/Z Rot: Flipped + * Z Rot to X/Y/Z rot: Flipped */ + trans->to_max_rot[i] = trans->to_min_rot[i]; + trans->to_min_rot[i] = temp_vec[i]; + } + } + break; + } + /* convert back to the settings space */ + mul_m4_v3(imat, trans->to_min); + mul_m4_v3(imat, trans->to_max); + mul_m4_v3(imat_rot, trans->to_min_rot); + mul_m4_v3(imat_rot, trans->to_max_rot); + mul_m4_v3(imat, trans->to_min_scale); + mul_m4_v3(imat, trans->to_max_scale); +} + +static void updateDuplicateConstraintSettings(EditBone *dup_bone, EditBone *orig_bone, Object *ob) +{ + /* If an edit bone has been duplicated, lets update it's constraints if the + * subtarget they point to has also been duplicated. + */ + bPoseChannel *pchan; + bConstraint *curcon; + ListBase *conlist; + + if ((pchan = BKE_pose_channel_verify(ob->pose, dup_bone->name)) == NULL || + (conlist = &pchan->constraints) == NULL) { + return; + } + + for (curcon = conlist->first; curcon; curcon = curcon->next) { + switch (curcon->type) { + case CONSTRAINT_TYPE_ACTION: + updateDuplicateActionConstraintSettings(dup_bone, orig_bone, ob, curcon); + break; + case CONSTRAINT_TYPE_KINEMATIC: + updateDuplicateKinematicConstraintSettings(curcon); + break; + case CONSTRAINT_TYPE_LOCLIMIT: + case CONSTRAINT_TYPE_ROTLIMIT: + updateDuplicateLocRotConstraintSettings(ob, pchan, curcon); + break; + case CONSTRAINT_TYPE_TRANSFORM: + updateDuplicateTransformConstraintSettings(ob, pchan, curcon); + break; + } + } +} + +static void updateDuplicateCustomBoneShapes(bContext *C, EditBone *dup_bone, Object *ob) +{ + if (ob->pose == NULL) { + return; } + bPoseChannel *pchan; + pchan = BKE_pose_channel_verify(ob->pose, dup_bone->name); + + if (pchan->custom != NULL) { + Main *bmain = CTX_data_main(C); + char name_flip[MAX_ID_NAME - 2]; - ED_armature_ebone_unique_name(editbones, eBone->name, NULL); - BLI_addtail(editbones, eBone); + /* Skip the first two chars in the object name as those are used to store object type */ + BLI_string_flip_side_name(name_flip, pchan->custom->id.name + 2, false, sizeof(name_flip)); + Object *shape_ob = (Object *)BKE_libblock_find_name(bmain, ID_OB, name_flip); + if (shape_ob != NULL) { + /* A flipped shape object exists, use it! */ + pchan->custom = shape_ob; + } + } +} + +static void copy_pchan(EditBone *src_bone, EditBone *dst_bone, Object *src_ob, Object *dst_ob) +{ /* copy the ID property */ - if (curBone->prop) { - eBone->prop = IDP_CopyProperty(curBone->prop); + if (src_bone->prop) { + dst_bone->prop = IDP_CopyProperty(src_bone->prop); } /* Lets duplicate the list of constraints that the @@ -466,25 +879,46 @@ EditBone *duplicateEditBoneObjects( if (src_ob->pose) { bPoseChannel *chanold, *channew; - chanold = BKE_pose_channel_verify(src_ob->pose, curBone->name); + chanold = BKE_pose_channel_verify(src_ob->pose, src_bone->name); if (chanold) { /* WARNING: this creates a new posechannel, but there will not be an attached bone * yet as the new bones created here are still 'EditBones' not 'Bones'. */ - channew = BKE_pose_channel_verify(dst_ob->pose, eBone->name); + channew = BKE_pose_channel_verify(dst_ob->pose, dst_bone->name); if (channew) { BKE_pose_channel_copy_data(channew, chanold); } } } +} - return eBone; +EditBone *duplicateEditBoneObjects( + EditBone *cur_bone, const char *name, ListBase *editbones, Object *src_ob, Object *dst_ob) +{ + EditBone *e_bone = MEM_mallocN(sizeof(EditBone), "addup_editbone"); + + /* Copy data from old bone to new bone */ + memcpy(e_bone, cur_bone, sizeof(EditBone)); + + cur_bone->temp.ebone = e_bone; + e_bone->temp.ebone = cur_bone; + + if (name != NULL) { + BLI_strncpy(e_bone->name, name, sizeof(e_bone->name)); + } + + ED_armature_ebone_unique_name(editbones, e_bone->name, NULL); + BLI_addtail(editbones, e_bone); + + copy_pchan(cur_bone, e_bone, src_ob, dst_ob); + + return e_bone; } -EditBone *duplicateEditBone(EditBone *curBone, const char *name, ListBase *editbones, Object *ob) +EditBone *duplicateEditBone(EditBone *cur_bone, const char *name, ListBase *editbones, Object *ob) { - return duplicateEditBoneObjects(curBone, name, editbones, ob, ob); + return duplicateEditBoneObjects(cur_bone, name, editbones, ob, ob); } static int armature_duplicate_selected_exec(bContext *C, wmOperator *op) @@ -538,8 +972,8 @@ static int armature_duplicate_selected_exec(bContext *C, wmOperator *op) BLI_string_flip_side_name( new_bone_name_buff, ebone_iter->name, false, sizeof(new_bone_name_buff)); - /* Only use flipped name if not yet in use. Otherwise we'd get again inconsistent namings - * (different numbers), better keep default behavior in this case. */ + /* Only use flipped name if not yet in use. Otherwise we'd get again inconsistent + * namings (different numbers), better keep default behavior in this case. */ if (ED_armature_ebone_find_name(arm->edbo, new_bone_name_buff) == NULL) { new_bone_name = new_bone_name_buff; } @@ -567,13 +1001,13 @@ static int armature_duplicate_selected_exec(bContext *C, wmOperator *op) } else if (ebone_iter->parent->temp.ebone) { /* If this bone has a parent that was duplicated, - * Set the duplicate->parent to the curBone->parent->temp + * Set the duplicate->parent to the cur_bone->parent->temp */ ebone->parent = ebone_iter->parent->temp.ebone; } else { /* If this bone has a parent that IS not selected, - * Set the duplicate->parent to the curBone->parent + * Set the duplicate->parent to the cur_bone->parent */ ebone->parent = (EditBone *)ebone_iter->parent; ebone->flag &= ~BONE_CONNECTED; @@ -590,7 +1024,7 @@ static int armature_duplicate_selected_exec(bContext *C, wmOperator *op) /* Lets try to fix any constraint subtargets that might * have been duplicated */ - updateDuplicateSubtarget(ebone, arm->edbo, ob); + updateDuplicateSubtarget(ebone, arm->edbo, ob, false); } } @@ -745,9 +1179,21 @@ static int armature_symmetrize_exec(bContext *C, wmOperator *op) /* Find the selected bones and duplicate them as needed, with mirrored name. */ for (ebone_iter = arm->edbo->first; ebone_iter && ebone_iter != ebone_first_dupe; ebone_iter = ebone_iter->next) { - if (EBONE_VISIBLE(arm, ebone_iter) && (ebone_iter->flag & BONE_SELECTED) && - /* will be set if the mirror bone already exists (no need to make a new one) */ - (ebone_iter->temp.ebone == NULL)) { + if (EBONE_VISIBLE(arm, ebone_iter) && (ebone_iter->flag & BONE_SELECTED)) { + if (ebone_iter->temp.ebone != NULL) { + /* will be set if the mirror bone already exists (no need to make a new one) + * but we do need to make sure that the pchan settings (constraints etc) is syncronized + */ + bPoseChannel *pchan; + /* Make sure we clean up the old data before overwriting it */ + pchan = BKE_pose_channel_verify(obedit->pose, ebone_iter->temp.ebone->name); + BKE_pose_channel_free(pchan); + /* Sync pchan data */ + copy_pchan(ebone_iter, ebone_iter->temp.ebone, obedit, obedit); + /* Sync scale mode */ + ebone_iter->temp.ebone->inherit_scale_mode = ebone_iter->inherit_scale_mode; + continue; + } char name_flip[MAXBONENAME]; BLI_string_flip_side_name(name_flip, ebone_iter->name, false, sizeof(name_flip)); @@ -793,7 +1239,12 @@ static int armature_symmetrize_exec(bContext *C, wmOperator *op) * then we can assume the parent has no L/R but is a center bone. * So just use the same parent for both. */ - ebone->flag &= ~BONE_CONNECTED; + + if (ebone->head[axis] != 0.0f) { + /* The mirrored bone doesn't start on the mirror axis, so assume that this one should + * not be connected to the old parent */ + ebone->flag &= ~BONE_CONNECTED; + } } ebone->parent = ebone_parent; @@ -803,10 +1254,19 @@ static int armature_symmetrize_exec(bContext *C, wmOperator *op) ebone->bbone_prev = get_symmetrized_bone(arm, ebone_iter->bbone_prev); ebone->bbone_next = get_symmetrized_bone(arm, ebone_iter->bbone_next); + /* Sync bbone handle types */ + ebone->bbone_prev_type = ebone_iter->bbone_prev_type; + ebone->bbone_next_type = ebone_iter->bbone_next_type; + /* Lets try to fix any constraint subtargets that might * have been duplicated */ - updateDuplicateSubtarget(ebone, arm->edbo, obedit); + updateDuplicateSubtarget(ebone, arm->edbo, obedit, true); + /* Try to update constraint options so that they are mirrored as well + * (need to supply bone_iter as well in case we are working with existing bones) */ + updateDuplicateConstraintSettings(ebone, ebone_iter, obedit); + /* Mirror bone shapes if possible */ + updateDuplicateCustomBoneShapes(C, ebone, obedit); } } diff --git a/source/blender/editors/armature/armature_intern.h b/source/blender/editors/armature/armature_intern.h index a454461b144..3d41fd5f0c6 100644 --- a/source/blender/editors/armature/armature_intern.h +++ b/source/blender/editors/armature/armature_intern.h @@ -232,9 +232,6 @@ struct EditBone *duplicateEditBone(struct EditBone *curBone, const char *name, struct ListBase *editbones, struct Object *ob); -void updateDuplicateSubtarget(struct EditBone *dupBone, - struct ListBase *editbones, - struct Object *ob); /* duplicate method (cross objects) */ /* editbones is the target list */ @@ -244,12 +241,6 @@ struct EditBone *duplicateEditBoneObjects(struct EditBone *curBone, struct Object *src_ob, struct Object *dst_ob); -/* editbones is the source list */ -void updateDuplicateSubtargetObjects(struct EditBone *dupBone, - struct ListBase *editbones, - struct Object *src_ob, - struct Object *dst_ob); - EditBone *add_points_bone(struct Object *obedit, float head[3], float tail[3]); void bone_free(struct bArmature *arm, struct EditBone *bone); -- cgit v1.2.3 From 5892622d684cf23ac0eaadcb9f501699255ceec7 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Tue, 7 Apr 2020 22:09:08 +1000 Subject: Revert "Fix memory leak in recent panel drag widget cache" This reverts commit 58e20b432a2bd7fbff7ebb7aa1f49a6662dc6e7c. Was calling discard twice, tsk. Although for some reason it did quiet the leak. Reverting because this is causing a crash. --- source/blender/gpu/intern/gpu_batch_presets.c | 1 - 1 file changed, 1 deletion(-) diff --git a/source/blender/gpu/intern/gpu_batch_presets.c b/source/blender/gpu/intern/gpu_batch_presets.c index 9a282e95664..34bd921992c 100644 --- a/source/blender/gpu/intern/gpu_batch_presets.c +++ b/source/blender/gpu/intern/gpu_batch_presets.c @@ -309,7 +309,6 @@ GPUBatch *GPU_batch_preset_panel_drag_widget(const float pixelsize, !equals_v4v4(g_presets_2d.panel_drag_widget_col_dark, col_dark); if (g_presets_2d.batch.panel_drag_widget && parameters_changed) { - GPU_batch_discard(g_presets_2d.batch.panel_drag_widget); gpu_batch_presets_unregister(g_presets_2d.batch.panel_drag_widget); GPU_batch_discard(g_presets_2d.batch.panel_drag_widget); g_presets_2d.batch.panel_drag_widget = NULL; -- cgit v1.2.3 From ea78f9922eff794858983cdb5bf3cf59e6b52b39 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Barschkis?= Date: Tue, 7 Apr 2020 14:13:05 +0200 Subject: Fluid: Fixed assertion error Fix for new assertion statements that were introduced in bfdc42d9906a. --- intern/mantaflow/intern/MANTA_main.cpp | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/intern/mantaflow/intern/MANTA_main.cpp b/intern/mantaflow/intern/MANTA_main.cpp index 54b728b734e..95487ff3bd0 100644 --- a/intern/mantaflow/intern/MANTA_main.cpp +++ b/intern/mantaflow/intern/MANTA_main.cpp @@ -1222,19 +1222,21 @@ bool MANTA::updateSmokeStructures(FluidModifierData *mmd, int framenr) if (mUsingColors) { file = getFile(mmd, FLUID_DOMAIN_DIR_DATA, FLUID_DOMAIN_FILE_COLORR, dformat, framenr); - expected += 3; + expected += 1; if (BLI_exists(file.c_str())) { result += updateGridFromFile(file, mColorR, false); assert(result == expected); } file = getFile(mmd, FLUID_DOMAIN_DIR_DATA, FLUID_DOMAIN_FILE_COLORG, dformat, framenr); + expected += 1; if (BLI_exists(file.c_str())) { result += updateGridFromFile(file, mColorG, false); assert(result == expected); } file = getFile(mmd, FLUID_DOMAIN_DIR_DATA, FLUID_DOMAIN_FILE_COLORB, dformat, framenr); + expected += 1; if (BLI_exists(file.c_str())) { result += updateGridFromFile(file, mColorB, false); assert(result == expected); @@ -1243,19 +1245,21 @@ bool MANTA::updateSmokeStructures(FluidModifierData *mmd, int framenr) if (mUsingFire) { file = getFile(mmd, FLUID_DOMAIN_DIR_DATA, FLUID_DOMAIN_FILE_FLAME, dformat, framenr); - expected += 3; + expected += 1; if (BLI_exists(file.c_str())) { result += updateGridFromFile(file, mFlame, false); assert(result == expected); } file = getFile(mmd, FLUID_DOMAIN_DIR_DATA, FLUID_DOMAIN_FILE_FUEL, dformat, framenr); + expected += 1; if (BLI_exists(file.c_str())) { result += updateGridFromFile(file, mFuel, false); assert(result == expected); } file = getFile(mmd, FLUID_DOMAIN_DIR_DATA, FLUID_DOMAIN_FILE_REACT, dformat, framenr); + expected += 1; if (BLI_exists(file.c_str())) { result += updateGridFromFile(file, mReact, false); assert(result == expected); @@ -1301,19 +1305,21 @@ bool MANTA::updateNoiseStructures(FluidModifierData *mmd, int framenr) if (mUsingColors) { file = getFile(mmd, FLUID_DOMAIN_DIR_NOISE, FLUID_DOMAIN_FILE_COLORRNOISE, nformat, framenr); - expected += 3; + expected += 1; if (BLI_exists(file.c_str())) { result += updateGridFromFile(file, mColorRHigh, true); assert(result == expected); } file = getFile(mmd, FLUID_DOMAIN_DIR_NOISE, FLUID_DOMAIN_FILE_COLORGNOISE, nformat, framenr); + expected += 1; if (BLI_exists(file.c_str())) { result += updateGridFromFile(file, mColorGHigh, true); assert(result == expected); } file = getFile(mmd, FLUID_DOMAIN_DIR_NOISE, FLUID_DOMAIN_FILE_COLORBNOISE, nformat, framenr); + expected += 1; if (BLI_exists(file.c_str())) { result += updateGridFromFile(file, mColorBHigh, true); assert(result == expected); @@ -1322,19 +1328,21 @@ bool MANTA::updateNoiseStructures(FluidModifierData *mmd, int framenr) if (mUsingFire) { file = getFile(mmd, FLUID_DOMAIN_DIR_NOISE, FLUID_DOMAIN_FILE_FLAMENOISE, nformat, framenr); - expected += 3; + expected += 1; if (BLI_exists(file.c_str())) { result += updateGridFromFile(file, mFlameHigh, true); assert(result == expected); } file = getFile(mmd, FLUID_DOMAIN_DIR_NOISE, FLUID_DOMAIN_FILE_FUELNOISE, nformat, framenr); + expected += 1; if (BLI_exists(file.c_str())) { result += updateGridFromFile(file, mFuelHigh, true); assert(result == expected); } file = getFile(mmd, FLUID_DOMAIN_DIR_NOISE, FLUID_DOMAIN_FILE_REACTNOISE, nformat, framenr); + expected += 1; if (BLI_exists(file.c_str())) { result += updateGridFromFile(file, mReactHigh, true); assert(result == expected); -- cgit v1.2.3 From 4a83832120647044908898a9afc5e54028d78617 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Barschkis?= Date: Tue, 7 Apr 2020 14:22:56 +0200 Subject: Fix T74828: Fluid: Crash with Fire/Smoke Noise Issue was that the noise simulation was trying to bake with a minimized domain size (adaptive domain initializes domain with size (1,1,1)). Similarly to the base resolution bake, there should be no noise baking happening at those domain sizes - a domain at this size is considered empty. --- intern/mantaflow/extern/manta_fluid_API.h | 1 + intern/mantaflow/intern/MANTA_main.cpp | 23 +++++++++++++++++++++++ intern/mantaflow/intern/MANTA_main.h | 3 ++- intern/mantaflow/intern/manta_fluid_API.cpp | 7 +++++++ source/blender/blenkernel/intern/fluid.c | 6 +++++- 5 files changed, 38 insertions(+), 2 deletions(-) diff --git a/intern/mantaflow/extern/manta_fluid_API.h b/intern/mantaflow/extern/manta_fluid_API.h index 939f24fbeef..85cc04b4a52 100644 --- a/intern/mantaflow/extern/manta_fluid_API.h +++ b/intern/mantaflow/extern/manta_fluid_API.h @@ -39,6 +39,7 @@ void manta_ensure_invelocity(struct MANTA *fluid, struct FluidModifierData *mmd) void manta_ensure_outflow(struct MANTA *fluid, struct FluidModifierData *mmd); int manta_write_config(struct MANTA *fluid, struct FluidModifierData *mmd, int framenr); int manta_write_data(struct MANTA *fluid, struct FluidModifierData *mmd, int framenr); +int manta_write_noise(struct MANTA *fluid, struct FluidModifierData *mmd, int framenr); int manta_read_config(struct MANTA *fluid, struct FluidModifierData *mmd, int framenr); int manta_read_data(struct MANTA *fluid, struct FluidModifierData *mmd, int framenr); int manta_read_noise(struct MANTA *fluid, struct FluidModifierData *mmd, int framenr); diff --git a/intern/mantaflow/intern/MANTA_main.cpp b/intern/mantaflow/intern/MANTA_main.cpp index 95487ff3bd0..293abae1b3a 100644 --- a/intern/mantaflow/intern/MANTA_main.cpp +++ b/intern/mantaflow/intern/MANTA_main.cpp @@ -1441,6 +1441,29 @@ bool MANTA::writeData(FluidModifierData *mmd, int framenr) return runPythonString(pythonCommands); } +bool MANTA::writeNoise(FluidModifierData *mmd, int framenr) +{ + if (with_debug) + std::cout << "MANTA::writeNoise()" << std::endl; + + std::ostringstream ss; + std::vector pythonCommands; + + std::string directory = getDirectory(mmd, FLUID_DOMAIN_DIR_NOISE); + std::string nformat = getCacheFileEnding(mmd->domain->cache_noise_format); + + bool final_cache = (mmd->domain->cache_type == FLUID_DOMAIN_CACHE_FINAL); + std::string resumable_cache = (final_cache) ? "False" : "True"; + + if (mUsingSmoke && mUsingNoise) { + ss.str(""); + ss << "smoke_save_noise_" << mCurrentID << "('" << escapeSlashes(directory) << "', " << framenr + << ", '" << nformat << "', " << resumable_cache << ")"; + pythonCommands.push_back(ss.str()); + } + return runPythonString(pythonCommands); +} + bool MANTA::readConfiguration(FluidModifierData *mmd, int framenr) { if (with_debug) diff --git a/intern/mantaflow/intern/MANTA_main.h b/intern/mantaflow/intern/MANTA_main.h index f4699e857ff..caac63d8e39 100644 --- a/intern/mantaflow/intern/MANTA_main.h +++ b/intern/mantaflow/intern/MANTA_main.h @@ -79,7 +79,8 @@ struct MANTA { // Write cache bool writeConfiguration(FluidModifierData *mmd, int framenr); bool writeData(FluidModifierData *mmd, int framenr); - // write call for noise, mesh and particles were left in bake calls for now + bool writeNoise(FluidModifierData *mmd, int framenr); + // write calls for mesh and particles were left in bake calls for now // Read cache (via Manta save/load) bool readConfiguration(FluidModifierData *mmd, int framenr); diff --git a/intern/mantaflow/intern/manta_fluid_API.cpp b/intern/mantaflow/intern/manta_fluid_API.cpp index 594f7a44e7f..b4582051c3c 100644 --- a/intern/mantaflow/intern/manta_fluid_API.cpp +++ b/intern/mantaflow/intern/manta_fluid_API.cpp @@ -80,6 +80,13 @@ int manta_write_data(MANTA *fluid, FluidModifierData *mmd, int framenr) return fluid->writeData(mmd, framenr); } +int manta_write_noise(MANTA *fluid, FluidModifierData *mmd, int framenr) +{ + if (!fluid || !mmd) + return 0; + return fluid->writeNoise(mmd, framenr); +} + int manta_read_config(MANTA *fluid, FluidModifierData *mmd, int framenr) { if (!fluid || !mmd) diff --git a/source/blender/blenkernel/intern/fluid.c b/source/blender/blenkernel/intern/fluid.c index cbb933725eb..985d0a79b23 100644 --- a/source/blender/blenkernel/intern/fluid.c +++ b/source/blender/blenkernel/intern/fluid.c @@ -3999,7 +3999,11 @@ static void BKE_fluid_modifier_processDomain(FluidModifierData *mmd, } if (has_data || baking_data) { if (baking_noise && with_smoke && with_noise) { - manta_bake_noise(mds->fluid, mmd, scene_framenr); + /* Ensure that no bake occurs if domain was minimized by adaptive domain. */ + if (mds->total_cells > 1) { + manta_bake_noise(mds->fluid, mmd, scene_framenr); + } + manta_write_noise(mds->fluid, mmd, scene_framenr); } if (baking_mesh && with_liquid && with_mesh) { manta_bake_mesh(mds->fluid, mmd, scene_framenr); -- cgit v1.2.3 From 5e0465e4ecba5349418f3b76b3d0061788047e9a Mon Sep 17 00:00:00 2001 From: Philipp Oeser Date: Sat, 4 Apr 2020 11:14:45 +0200 Subject: Fix T75343: Wireframe overylay is not working properly with multiple modifiers Since rBcf258b02f449, only wires and edges that are mapped to the original mesh were drawn if the mesh was modified by modifiers. Above commit was only meant for showing orig wires for paint mask overlays [where final wireframe is not desired], so now only use MR_EXTRACT_MAPPED when we are in a paint mode. Maniphest Tasks: T75343 Differential Revision: https://developer.blender.org/D7333 --- source/blender/draw/intern/draw_cache_extract.h | 1 + source/blender/draw/intern/draw_cache_extract_mesh.c | 16 +++++++++++++--- source/blender/draw/intern/draw_cache_impl_mesh.c | 3 +++ 3 files changed, 17 insertions(+), 3 deletions(-) diff --git a/source/blender/draw/intern/draw_cache_extract.h b/source/blender/draw/intern/draw_cache_extract.h index 0e02b07e95b..b2fea957227 100644 --- a/source/blender/draw/intern/draw_cache_extract.h +++ b/source/blender/draw/intern/draw_cache_extract.h @@ -253,6 +253,7 @@ void mesh_buffer_cache_create_requested(MeshBatchCache *cache, MeshBufferCache mbc, Mesh *me, const bool is_editmode, + const bool is_paint_mode, const float obmat[4][4], const bool do_final, const bool do_uvedit, diff --git a/source/blender/draw/intern/draw_cache_extract_mesh.c b/source/blender/draw/intern/draw_cache_extract_mesh.c index 70fe6a55461..0449601adf7 100644 --- a/source/blender/draw/intern/draw_cache_extract_mesh.c +++ b/source/blender/draw/intern/draw_cache_extract_mesh.c @@ -129,6 +129,7 @@ typedef struct MeshRenderData { static MeshRenderData *mesh_render_data_create(Mesh *me, const bool is_editmode, + const bool is_paint_mode, const float obmat[4][4], const bool do_final, const bool do_uvedit, @@ -192,7 +193,7 @@ static MeshRenderData *mesh_render_data_create(Mesh *me, mr->me = me; mr->edit_bmesh = NULL; - bool use_mapped = mr->me && !mr->me->runtime.is_original; + bool use_mapped = is_paint_mode && mr->me && !mr->me->runtime.is_original; if (use_mapped) { mr->v_origindex = CustomData_get_layer(&mr->me->vdata, CD_ORIGINDEX); mr->e_origindex = CustomData_get_layer(&mr->me->edata, CD_ORIGINDEX); @@ -4596,6 +4597,7 @@ void mesh_buffer_cache_create_requested(MeshBatchCache *cache, MeshBufferCache mbc, Mesh *me, const bool is_editmode, + const bool is_paint_mode, const float obmat[4][4], const bool do_final, const bool do_uvedit, @@ -4657,8 +4659,16 @@ void mesh_buffer_cache_create_requested(MeshBatchCache *cache, double rdata_start = PIL_check_seconds_timer(); #endif - MeshRenderData *mr = mesh_render_data_create( - me, is_editmode, obmat, do_final, do_uvedit, iter_flag, data_flag, cd_layer_used, ts); + MeshRenderData *mr = mesh_render_data_create(me, + is_editmode, + is_paint_mode, + obmat, + do_final, + do_uvedit, + iter_flag, + data_flag, + cd_layer_used, + ts); mr->cache = cache; /* HACK */ mr->use_hide = use_hide; mr->use_subsurf_fdots = use_subsurf_fdots; diff --git a/source/blender/draw/intern/draw_cache_impl_mesh.c b/source/blender/draw/intern/draw_cache_impl_mesh.c index 308d87f1385..1aaead27ee7 100644 --- a/source/blender/draw/intern/draw_cache_impl_mesh.c +++ b/source/blender/draw/intern/draw_cache_impl_mesh.c @@ -1369,6 +1369,7 @@ void DRW_mesh_batch_cache_create_requested( cache->uv_cage, me, is_editmode, + is_paint_mode, ob->obmat, false, true, @@ -1384,6 +1385,7 @@ void DRW_mesh_batch_cache_create_requested( cache->cage, me, is_editmode, + is_paint_mode, ob->obmat, false, false, @@ -1398,6 +1400,7 @@ void DRW_mesh_batch_cache_create_requested( cache->final, me, is_editmode, + is_paint_mode, ob->obmat, true, false, -- cgit v1.2.3 From 3a65397473e7a60b606489ea154687a16f656b6b Mon Sep 17 00:00:00 2001 From: Philipp Oeser Date: Tue, 7 Apr 2020 12:59:46 +0200 Subject: Fix T75471: Outliner: crash selecting modifier objects/targets that are in a excluded collection There is no garuantee 'outliner_find_id()' can find those corresponding TreeElements, safeguard against failure now. note: not sure why this was no problem in Release builds? (could only reproduce crashes in Debug builds...) Maniphest Tasks: T75471 Differential Revision: https://developer.blender.org/D7365 --- source/blender/editors/space_outliner/outliner_select.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/source/blender/editors/space_outliner/outliner_select.c b/source/blender/editors/space_outliner/outliner_select.c index ec1595eb930..64d86293fb7 100644 --- a/source/blender/editors/space_outliner/outliner_select.c +++ b/source/blender/editors/space_outliner/outliner_select.c @@ -312,6 +312,7 @@ static eOLDrawState tree_element_set_active_object(bContext *C, Scene *sce; Base *base; Object *ob = NULL; + TreeElement *te_ob = NULL; /* if id is not object, we search back */ if (te->idcode == ID_OB) { @@ -355,8 +356,12 @@ static eOLDrawState tree_element_set_active_object(bContext *C, } } - parent_tselem = TREESTORE(outliner_find_id(soops, &soops->tree, (ID *)ob)); - if (base) { + te_ob = outliner_find_id(soops, &soops->tree, (ID *)ob); + if (te_ob != NULL) { + parent_tselem = TREESTORE(te_ob); + } + + if (!ELEM(NULL, parent_tselem, base)) { if (set == OL_SETSEL_EXTEND) { /* swap select */ if (base->flag & BASE_SELECTED) { -- cgit v1.2.3 From 1de5cb6a31dc477356f8061fd648f1154f10e9c4 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Tue, 7 Apr 2020 22:20:41 +1000 Subject: Cleanup: use doxy sections --- source/blender/blenkernel/intern/object.c | 42 +++++++++++++++++++++++---- source/blender/gpu/intern/gpu_batch_presets.c | 13 +++++++++ 2 files changed, 49 insertions(+), 6 deletions(-) diff --git a/source/blender/blenkernel/intern/object.c b/source/blender/blenkernel/intern/object.c index 733f112f80c..f68b1a4d314 100644 --- a/source/blender/blenkernel/intern/object.c +++ b/source/blender/blenkernel/intern/object.c @@ -1883,7 +1883,9 @@ bool BKE_object_obdata_is_libdata(const Object *ob) return (ob && ob->data && ID_IS_LINKED(ob->data)); } -/* *************** PROXY **************** */ +/* -------------------------------------------------------------------- */ +/** \name Object Proxy API + * \{ */ /* when you make proxy, ensure the exposed layers are extern */ static void armature_set_id_extern(Object *ob) @@ -2093,7 +2095,11 @@ void BKE_object_obdata_size_init(struct Object *ob, const float size) } } -/* *************** CALC ****************** */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Object Matrix Get/Set API + * \{ */ void BKE_object_scale_to_mat3(Object *ob, float mat[3][3]) { @@ -2586,6 +2592,12 @@ void BKE_object_get_parent_matrix(Object *ob, Object *par, float parentmat[4][4] } } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Object Matrix Evaluation API + * \{ */ + /** * \param r_originmat: Optional matrix that stores the space the object is in * (without its own matrix applied) @@ -2790,6 +2802,12 @@ void BKE_object_apply_mat4(Object *ob, BKE_object_apply_mat4_ex(ob, mat, use_parent ? ob->parent : NULL, ob->parentinv, use_compat); } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Object Bounding Box API + * \{ */ + BoundBox *BKE_boundbox_alloc_unit(void) { BoundBox *bb; @@ -2911,6 +2929,8 @@ void BKE_object_boundbox_calc_from_mesh(struct Object *ob, struct Mesh *me_eval) ob->runtime.bb->flag &= ~BOUNDBOX_DIRTY; } +/** \} */ + /* -------------------------------------------------------------------- */ /** \name Object Dimension Get/Set * @@ -3594,9 +3614,11 @@ void BKE_object_delete_ptcache(Object *ob, int index) BLI_freelinkN(&ob->pc_ids, link); } -/* shape key utility function */ +/* -------------------------------------------------------------------- */ +/** \name Object Data Shape Key Insert + * \{ */ -/************************* Mesh ************************/ +/* Mesh */ static KeyBlock *insert_meshkey(Main *bmain, Object *ob, const char *name, const bool from_mix) { Mesh *me = ob->data; @@ -3628,7 +3650,7 @@ static KeyBlock *insert_meshkey(Main *bmain, Object *ob, const char *name, const return kb; } -/************************* Lattice ************************/ +/* Lattice */ static KeyBlock *insert_lattkey(Main *bmain, Object *ob, const char *name, const bool from_mix) { Lattice *lt = ob->data; @@ -3666,7 +3688,7 @@ static KeyBlock *insert_lattkey(Main *bmain, Object *ob, const char *name, const return kb; } -/************************* Curve ************************/ +/* Curve */ static KeyBlock *insert_curvekey(Main *bmain, Object *ob, const char *name, const bool from_mix) { Curve *cu = ob->data; @@ -3707,6 +3729,12 @@ static KeyBlock *insert_curvekey(Main *bmain, Object *ob, const char *name, cons return kb; } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Object Shape Key API + * \{ */ + KeyBlock *BKE_object_shapekey_insert(Main *bmain, Object *ob, const char *name, @@ -3804,6 +3832,8 @@ bool BKE_object_shapekey_remove(Main *bmain, Object *ob, KeyBlock *kb) return true; } +/** \} */ + bool BKE_object_flag_test_recursive(const Object *ob, short flag) { if (ob->flag & flag) { diff --git a/source/blender/gpu/intern/gpu_batch_presets.c b/source/blender/gpu/intern/gpu_batch_presets.c index 34bd921992c..d16edab5ac9 100644 --- a/source/blender/gpu/intern/gpu_batch_presets.c +++ b/source/blender/gpu/intern/gpu_batch_presets.c @@ -37,6 +37,10 @@ #include "GPU_batch_utils.h" #include "gpu_shader_private.h" +/* -------------------------------------------------------------------- */ +/** \name Local Structures + * \{ */ + /* Struct to store 3D Batches and their format */ static struct { struct { @@ -75,6 +79,8 @@ static struct { static ListBase presets_list = {NULL, NULL}; +/** \} */ + /* -------------------------------------------------------------------- */ /** \name 3D Primitives * \{ */ @@ -228,6 +234,7 @@ static GPUBatch *batch_sphere_wire(int lat_res, int lon_res) /* -------------------------------------------------------------------- */ /** \name Panel Drag Widget * \{ */ + static void gpu_batch_preset_rectf_tris_color_ex(GPUVertBufRaw *pos_step, float x1, float y1, @@ -328,6 +335,10 @@ GPUBatch *GPU_batch_preset_panel_drag_widget(const float pixelsize, /** \} */ +/* -------------------------------------------------------------------- */ +/** \name Preset Registration Management + * \{ */ + void gpu_batch_presets_init(void) { BLI_mutex_init(&g_presets_3d.mutex); @@ -394,3 +405,5 @@ void gpu_batch_presets_exit(void) BLI_mutex_end(&g_presets_3d.mutex); } + +/** \} */ -- cgit v1.2.3 From 3a5c16f1c981567a800c1094898e892f84d855a0 Mon Sep 17 00:00:00 2001 From: mano-wii Date: Tue, 7 Apr 2020 23:22:28 +1000 Subject: Fix T74720: bmesh.ops.delete default context argument does nothing --- source/blender/bmesh/intern/bmesh_operators.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/source/blender/bmesh/intern/bmesh_operators.c b/source/blender/bmesh/intern/bmesh_operators.c index d3c8499477b..6454079a5dc 100644 --- a/source/blender/bmesh/intern/bmesh_operators.c +++ b/source/blender/bmesh/intern/bmesh_operators.c @@ -138,6 +138,8 @@ static void bmo_op_slots_init(const BMOSlotType *slot_types, BMOpSlot *slot_args BMO_OP_SLOT_SUBTYPE_INT_ENUM, BMO_OP_SLOT_SUBTYPE_INT_FLAG)) { slot->data.enum_data.flags = slot_types[i].enum_flags; + /* Set the first value of the enum as the default value. */ + slot->data.i = slot->data.enum_data.flags[0].value; } default: break; -- cgit v1.2.3 From 02598e629eb3a3291784b297528c8596c964cd37 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Wed, 8 Apr 2020 00:43:47 +1000 Subject: Fix T73566: Mesh analysis, error showing intersecting faces --- source/blender/blenlib/intern/math_geom.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/source/blender/blenlib/intern/math_geom.c b/source/blender/blenlib/intern/math_geom.c index 4c0d7e08a3c..a26824bd2b5 100644 --- a/source/blender/blenlib/intern/math_geom.c +++ b/source/blender/blenlib/intern/math_geom.c @@ -2379,7 +2379,10 @@ bool isect_tri_tri_epsilon_v3(const float t_a0[3], if (UNLIKELY(edge_fac == -1.0f)) { /* pass */ } - else if (edge_fac > 0.0f && edge_fac < 1.0f) { + /* Important to include 0.0f and 1.0f as one of the triangles vertices may be placed + * exactly on the plane. In this case both it's edges will have a factor of 0 or 1, + * but not be going through the plane. See T73566. */ + else if (edge_fac >= 0.0f && edge_fac <= 1.0f) { float ix_tri[3]; float span_fac; -- cgit v1.2.3 From c5ed2eb95e3d75121b93b0271abf6cdec69d5a66 Mon Sep 17 00:00:00 2001 From: Brecht Van Lommel Date: Sat, 4 Apr 2020 19:30:42 +0200 Subject: Undo: change depsgraph recalc flags handling to improve performance These changes only have an effect when the experimental Undo Speedup preference is enabled. * For DEG_id_tag_update, accumulate recalc flags immediately before the undo push happens instead of afterwards. Otherwise the undo state does not contain enough flags, and the current state may contain too many flags. This also means we call DEG_id_tag_update after undo with the accumulated flags to ensure they are flushed to other datablocks. * For undo, accumulate recalc flags in id->recalc and clear accumulated flags immediately. Not clearing would cause circular behavior where accumulated flags may never end up being cleared. This matches what happens after an undo push where these are also cleared, indicating that the undo state and current in-memory state match exactly. * Don't change id->recalc of identical datablocks, it should not be needed. There is one exception for armatures where pointers across datablocks exist which otherwise would cause problems. There may be a better solution to this but it seems to work in agent 327 production files. * This contains a change in undofile.c to avoid detecting all datablocks as changed for the first of the two undo steps, where we restore to the state of the last undo push before going to the one before. Without this the whole system is much less efficient. However this is unsafe in the sense that if an app handler or operators edits a datablock after an undo push, that change will not be undone. It can be argued that this is acceptable behavior, since a following undo push will include that change and this may already have unexpected side effects. Ref T60695 Differential Revision: https://developer.blender.org/D7339 --- source/blender/blenkernel/intern/scene.c | 2 - source/blender/blenloader/intern/readfile.c | 119 +++++++++++++---------- source/blender/blenloader/intern/undofile.c | 5 +- source/blender/depsgraph/intern/depsgraph_tag.cc | 7 +- source/blender/editors/undo/memfile_undo.c | 34 ++++++- 5 files changed, 103 insertions(+), 64 deletions(-) diff --git a/source/blender/blenkernel/intern/scene.c b/source/blender/blenkernel/intern/scene.c index 20f7add0c74..c4b6f5dafe5 100644 --- a/source/blender/blenkernel/intern/scene.c +++ b/source/blender/blenkernel/intern/scene.c @@ -2167,8 +2167,6 @@ GHash *BKE_scene_undo_depsgraphs_extract(Main *bmain) void BKE_scene_undo_depsgraphs_restore(Main *bmain, GHash *depsgraph_extract) { for (Scene *scene = bmain->scenes.first; scene != NULL; scene = scene->id.next) { - BLI_assert(scene->depsgraph_hash == NULL); - for (ViewLayer *view_layer = scene->view_layers.first; view_layer != NULL; view_layer = view_layer->next) { char key_full[MAX_ID_NAME + FILE_MAX + MAX_NAME] = {0}; diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c index d4799404ef2..6b67842bf1e 100644 --- a/source/blender/blenloader/intern/readfile.c +++ b/source/blender/blenloader/intern/readfile.c @@ -2800,6 +2800,62 @@ static void direct_link_id_private_id(FileData *fd, ID *id, ID *id_old) } } +static int direct_link_id_restore_recalc_exceptions(const ID *id_current) +{ + /* Exception for armature objects, where the pose has direct points to the + * armature databolock. */ + if (GS(id_current->name) == ID_OB && ((Object *)id_current)->pose) { + return ID_RECALC_GEOMETRY; + } + + return 0; +} + +static int direct_link_id_restore_recalc(const FileData *fd, + const ID *id_target, + const ID *id_current, + const bool is_identical) +{ + /* These are the evaluations that had not been performed yet at the time the + * target undo state was written. These need to be done again, since they may + * flush back changes to the original datablock. */ + int recalc = id_target->recalc; + + if (id_current == NULL) { + /* ID does not currently exist in the database, so also will not exist in + * the dependency graphs. That means it will be newly created and as a + * result also fully re-evaluated regardless of the recalc flag set here. */ + recalc |= ID_RECALC_ALL; + } + else { + /* If the contents datablock changed, the depsgraph needs to copy the + * datablock again to ensure it matches the original datablock. */ + if (!is_identical) { + recalc |= ID_RECALC_COPY_ON_WRITE; + } + + /* Special exceptions. */ + recalc |= direct_link_id_restore_recalc_exceptions(id_current); + + /* Evaluations for the current state that have not been performed yet + * by the time we are perfoming this undo step. */ + recalc |= id_current->recalc; + + /* Tags that were set between the target state and the current state, + * that we need to perform again. */ + if (fd->undo_direction < 0) { + /* Undo: tags from target to the current state. */ + recalc |= id_current->recalc_undo_accumulated; + } + else { + /* Redo: tags from current to the target state. */ + recalc |= id_target->recalc_undo_accumulated; + } + } + + return recalc; +} + static void direct_link_id_common(FileData *fd, ID *id, ID *id_old, const int tag) { /*link direct data of ID properties*/ @@ -2827,29 +2883,8 @@ static void direct_link_id_common(FileData *fd, ID *id, ID *id_old, const int ta id->recalc_undo_accumulated = 0; } else if ((fd->skip_flags & BLO_READ_SKIP_UNDO_OLD_MAIN) == 0) { - if (fd->undo_direction < 0) { - /* We are coming from the future (i.e. do an actual undo, and not a redo), and we found an - * old (aka existing) ID: we use its 'accumulated recalc flags since last memfile undo step - * saving' as recalc flags of our newly read ID. */ - if (id_old != NULL) { - id->recalc = id_old->recalc_undo_accumulated; - } - } - else { - /* We are coming from the past (i.e. do a redo), we use saved 'accumulated - * recalc flags since last memfile undo step saving' as recalc flags of our newly read ID. */ - id->recalc = id->recalc_undo_accumulated; - } - /* In any case, we need to flush the depsgraph's CoWs, as even if the ID address itself did not - * change, internal data most likely have. */ - id->recalc |= ID_RECALC_COPY_ON_WRITE; - - /* We need to 'accumulate' the accumulated recalc flags of all undo steps until we actually - * perform a depsgraph update, otherwise we'd only ever use the flags from one of the steps, - * and never get proper flags matching all others. */ - if (id_old != NULL) { - id->recalc_undo_accumulated |= id_old->recalc_undo_accumulated; - } + id->recalc = direct_link_id_restore_recalc(fd, id, id_old, false); + id->recalc_undo_accumulated = 0; } /* Link direct data of overrides. */ @@ -9498,7 +9533,7 @@ static bool read_libblock_undo_restore_linked(FileData *fd, Main *main, const ID /* For undo, restore unchanged datablock from old main. */ static void read_libblock_undo_restore_identical( - FileData *fd, Main *main, const ID *id, ID *id_old, const int tag) + FileData *fd, Main *main, const ID *UNUSED(id), ID *id_old, const int tag) { BLI_assert((fd->skip_flags & BLO_READ_SKIP_UNDO_OLD_MAIN) == 0); BLI_assert(id_old != NULL); @@ -9511,10 +9546,6 @@ static void read_libblock_undo_restore_identical( id_old->newid = NULL; id_old->orig_id = NULL; - /* About recalc: since that ID did not change at all, we know that its recalc fields also - * remained unchanged, so no need to handle neither recalc nor recalc_undo_future here. - */ - const short idcode = GS(id_old->name); Main *old_bmain = fd->old_mainlist->first; ListBase *old_lb = which_libbase(old_bmain, idcode); @@ -9522,31 +9553,9 @@ static void read_libblock_undo_restore_identical( BLI_remlink(old_lb, id_old); BLI_addtail(new_lb, id_old); - /* Even though we re-use the old ID as-is, it does not mean that we are 100% safe from - * needing some depsgraph updates for it (it could depend on another ID which address - * did not change, but which actual content might have been re-read from the memfile). - * IMPORTANT: Do not fully overwrite recalc flag here, depsgraph may not have been ran - * yet for previous undo step(s), we do not want to erase flags set by those. - */ - if (fd->undo_direction < 0) { - /* We are coming from the future (i.e. do an actual undo, and not a redo), we use our - * old reused ID's 'accumulated recalc flags since last memfile undo step saving' as - * recalc flags. */ - id_old->recalc |= id_old->recalc_undo_accumulated; - } - else { - /* We are coming from the past (i.e. do a redo), we use the saved 'accumulated recalc - * flags since last memfile undo step saving' from the newly read ID as recalc flags. - */ - id_old->recalc |= id->recalc_undo_accumulated; - } - /* There is no need to flush the depsgraph's CoWs here, since that ID's data itself did - * not change. */ - - /* We need to 'accumulate' the accumulated recalc flags of all undo steps until we - * actually perform a depsgraph update, otherwise we'd only ever use the flags from one - * of the steps, and never get proper flags matching all others. */ - id_old->recalc_undo_accumulated |= id->recalc_undo_accumulated; + /* Recalc flags, mostly these just remain as they are. */ + id_old->recalc |= direct_link_id_restore_recalc_exceptions(id_old); + id_old->recalc_undo_accumulated = 0; } /* For undo, store changed datablock at old address. */ @@ -10217,6 +10226,10 @@ BlendFileData *blo_read_file_internal(FileData *fd, const char *filepath) BlendFileData *bfd; ListBase mainlist = {NULL, NULL}; + if (fd->memfile != NULL) { + DEBUG_PRINTF("\nUNDO: read step\n"); + } + bfd = MEM_callocN(sizeof(BlendFileData), "blendfiledata"); bfd->main = BKE_main_new(); diff --git a/source/blender/blenloader/intern/undofile.c b/source/blender/blenloader/intern/undofile.c index d8780409e93..c7057883f88 100644 --- a/source/blender/blenloader/intern/undofile.c +++ b/source/blender/blenloader/intern/undofile.c @@ -106,7 +106,10 @@ void memfile_chunk_add(MemFile *memfile, const char *buf, uint size, MemFileChun curchunk->size = size; curchunk->buf = NULL; curchunk->is_identical = false; - curchunk->is_identical_future = false; + /* This is unsafe in the sense that an app handler or other code that does not + * perform an undo push may make changes after the last undo push that + * will then not be undo. Though it's not entirely clear that is wrong behavior. */ + curchunk->is_identical_future = true; BLI_addtail(&memfile->chunks, curchunk); /* we compare compchunk with buf */ diff --git a/source/blender/depsgraph/intern/depsgraph_tag.cc b/source/blender/depsgraph/intern/depsgraph_tag.cc index f1180c16a87..aa9ce28850c 100644 --- a/source/blender/depsgraph/intern/depsgraph_tag.cc +++ b/source/blender/depsgraph/intern/depsgraph_tag.cc @@ -622,6 +622,10 @@ void id_tag_update(Main *bmain, ID *id, int flag, eUpdateSource update_source) for (DEG::Depsgraph *depsgraph : DEG::get_all_registered_graphs(bmain)) { graph_id_tag_update(bmain, depsgraph, id, flag, update_source); } + + /* Accumulate all tags for an ID between two undo steps, so they can be + * replayed for undo. */ + id->recalc_undo_accumulated |= flag; } void graph_id_tag_update( @@ -820,13 +824,10 @@ void DEG_ids_check_recalc( static void deg_graph_clear_id_recalc_flags(ID *id) { - /* Keep incremental track of used recalc flags, to get proper update when undoing. */ - id->recalc_undo_accumulated |= id->recalc; id->recalc &= ~ID_RECALC_ALL; bNodeTree *ntree = ntreeFromID(id); /* Clear embedded node trees too. */ if (ntree) { - ntree->id.recalc_undo_accumulated |= ntree->id.recalc; ntree->id.recalc &= ~ID_RECALC_ALL; } /* XXX And what about scene's master collection here? */ diff --git a/source/blender/editors/undo/memfile_undo.c b/source/blender/editors/undo/memfile_undo.c index 086aa6c4c9d..a5c503fec90 100644 --- a/source/blender/editors/undo/memfile_undo.c +++ b/source/blender/editors/undo/memfile_undo.c @@ -25,14 +25,17 @@ #include "BLI_ghash.h" +#include "DNA_node_types.h" #include "DNA_object_enums.h" #include "DNA_object_types.h" +#include "DNA_scene_types.h" #include "BKE_blender_undo.h" #include "BKE_context.h" #include "BKE_lib_id.h" #include "BKE_lib_query.h" #include "BKE_main.h" +#include "BKE_node.h" #include "BKE_scene.h" #include "BKE_undo_system.h" @@ -106,7 +109,6 @@ static int memfile_undosys_step_id_reused_cb(LibraryIDLinkCallbackData *cb_data) ID *id_self = cb_data->id_self; ID **id_pointer = cb_data->id_pointer; BLI_assert((id_self->tag & LIB_TAG_UNDO_OLD_ID_REUSED) != 0); - Main *bmain = cb_data->user_data; ID *id = *id_pointer; if (id != NULL && id->lib == NULL && (id->tag & LIB_TAG_UNDO_OLD_ID_REUSED) == 0) { @@ -129,9 +131,6 @@ static int memfile_undosys_step_id_reused_cb(LibraryIDLinkCallbackData *cb_data) } } - /* In case an old, re-used ID is using a newly read data-block (i.e. one of its ID pointers got - * updated), we have to tell the depsgraph about it. */ - DEG_id_tag_update_ex(bmain, id_self, ID_RECALC_COPY_ON_WRITE); return do_stop_iter ? IDWALK_RET_STOP_ITER : IDWALK_RET_NOP; } @@ -219,10 +218,35 @@ static void memfile_undosys_step_decode(struct bContext *C, BKE_library_foreach_ID_link( bmain, id, memfile_undosys_step_id_reused_cb, bmain, IDWALK_READONLY); } + + /* Tag depsgraph to update datablock for changes that happend between the + * current and the target state, see direct_link_id_restore_recalc(). */ + if (id->recalc) { + DEG_id_tag_update_ex(bmain, id, id->recalc); + } } FOREACH_MAIN_ID_END; - BKE_main_id_tag_all(bmain, LIB_TAG_UNDO_OLD_ID_REUSED, false); + FOREACH_MAIN_ID_BEGIN (bmain, id) { + /* Clear temporary tag. */ + id->tag &= ~LIB_TAG_UNDO_OLD_ID_REUSED; + + /* We only start accumulating from this point, any tags set up to here + * are already part of the current undo state. This is done in a second + * loop because DEG_id_tag_update may set tags on other datablocks. */ + id->recalc_undo_accumulated = 0; + bNodeTree *nodetree = ntreeFromID(id); + if (nodetree != NULL) { + nodetree->id.recalc_undo_accumulated = 0; + } + if (GS(id->name) == ID_SCE) { + Scene *scene = (Scene *)id; + if (scene->master_collection != NULL) { + scene->master_collection->id.recalc_undo_accumulated = 0; + } + } + } + FOREACH_MAIN_ID_END; } WM_event_add_notifier(C, NC_SCENE | ND_LAYER_CONTENT, CTX_data_scene(C)); -- cgit v1.2.3 From 6b5857181390033b06f18d5a4b19e03f2829d51a Mon Sep 17 00:00:00 2001 From: Hans Goudey Date: Tue, 7 Apr 2020 11:51:08 -0500 Subject: UI: Don't collapse all panels for subpanels The behavior for subpanels was incorrect, and the ideal behavior isn't even clear. This disables the "collapse all" ctrl click feature for panels that have parents. Differential Revision: https://developer.blender.org/D7355 --- source/blender/editors/interface/interface_panel.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/source/blender/editors/interface/interface_panel.c b/source/blender/editors/interface/interface_panel.c index da0e8f34417..d1c61925d40 100644 --- a/source/blender/editors/interface/interface_panel.c +++ b/source/blender/editors/interface/interface_panel.c @@ -1574,10 +1574,13 @@ static void ui_handle_panel_header( } else { /* collapse */ if (ctrl) { - panels_collapse_all(area, region, block->panel); + /* Only collapse all for parent panels. */ + if (block->panel->type != NULL && block->panel->type->parent == NULL) { + panels_collapse_all(area, region, block->panel); - /* reset the view - we don't want to display a view without content */ - UI_view2d_offset(®ion->v2d, 0.0f, 1.0f); + /* reset the view - we don't want to display a view without content */ + UI_view2d_offset(®ion->v2d, 0.0f, 1.0f); + } } if (block->panel->flag & PNL_CLOSED) { -- cgit v1.2.3 From 7b4b07a7ddc874efd11b3932f152c7136d720f9c Mon Sep 17 00:00:00 2001 From: Antonio Vazquez Date: Tue, 7 Apr 2020 20:07:58 +0200 Subject: GPencil: Fix unreported problems with Chisel brush With the new sampling, the arc points were not using the angle of the brush and the line was with the same thickness in all orientations. --- source/blender/editors/gpencil/gpencil_paint.c | 33 ++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/source/blender/editors/gpencil/gpencil_paint.c b/source/blender/editors/gpencil/gpencil_paint.c index 40068b0fb85..9de15c411cc 100644 --- a/source/blender/editors/gpencil/gpencil_paint.c +++ b/source/blender/editors/gpencil/gpencil_paint.c @@ -3127,6 +3127,34 @@ static tGPsdata *gpencil_stroke_begin(bContext *C, wmOperator *op) return op->customdata; } +/* Apply pressure change depending of the angle of the stroke for a segment. */ +static void gp_brush_angle_segment(tGPsdata *p, tGPspoint *pt_prev, tGPspoint *pt) +{ + Brush *brush = p->brush; + /* Sensitivity. */ + const float sen = brush->gpencil_settings->draw_angle_factor; + /* Default angle of brush in radians */ + const float angle = brush->gpencil_settings->draw_angle; + + float mvec[2]; + float fac; + float mpressure; + + /* angle vector of the brush with full thickness */ + float v0[2] = {cos(angle), sin(angle)}; + + mvec[0] = pt->x - pt_prev->x; + mvec[1] = pt->y - pt_prev->y; + normalize_v2(mvec); + + fac = 1.0f - fabs(dot_v2v2(v0, mvec)); /* 0.0 to 1.0 */ + /* interpolate with previous point for smoother transitions */ + mpressure = interpf(pt->pressure - (sen * fac), pt_prev->pressure, 0.3f); + pt->pressure = mpressure; + + CLAMP(pt->pressure, pt_prev->pressure * 0.5f, 1.0f); +} + /* Add arc points between two mouse events using the previous segment to determine the vertice of * the arc. * /+ CTL @@ -3209,6 +3237,11 @@ static void gpencil_add_arc_points(tGPsdata *p, float mval[2], int segments) pt->pressure = pt_prev->pressure; pt->strength = pt_prev->strength; + /* Apply angle of stroke to brush size. */ + if (brush_settings->draw_angle_factor != 0.0f) { + gp_brush_angle_segment(p, pt_prev, pt); + } + /* Apply randomness to pressure. */ if (brush_settings->draw_random_press > 0.0f) { float rand = BLI_rng_get_float(p->rng) * 2.0f - 1.0f; -- cgit v1.2.3 From 53981c7fb6fdd9973e40f81f867f25d10540c1d1 Mon Sep 17 00:00:00 2001 From: Brecht Van Lommel Date: Tue, 7 Apr 2020 19:43:51 +0200 Subject: Cleanup: refactor adaptive sampling to more easily change some parameters No functional changes yet, this is work towards making CPU and GPU results match more closely. --- intern/cycles/device/device.cpp | 2 ++ intern/cycles/device/device.h | 14 ++++++++------ intern/cycles/device/device_cpu.cpp | 22 ++++++++++++++++++---- intern/cycles/device/device_cuda.cpp | 1 + intern/cycles/device/device_network.cpp | 1 + intern/cycles/device/device_opencl.cpp | 1 + intern/cycles/device/device_task.cpp | 3 +-- intern/cycles/kernel/kernel_passes.h | 10 +++++++--- intern/cycles/kernel/kernel_types.h | 9 +++------ intern/cycles/render/integrator.cpp | 7 +++++++ intern/cycles/render/session.cpp | 1 + 11 files changed, 50 insertions(+), 21 deletions(-) diff --git a/intern/cycles/device/device.cpp b/intern/cycles/device/device.cpp index d94d409175b..dfbf57e8b88 100644 --- a/intern/cycles/device/device.cpp +++ b/intern/cycles/device/device.cpp @@ -597,6 +597,7 @@ DeviceInfo Device::get_multi_device(const vector &subdevices, info.has_half_images = true; info.has_volume_decoupled = true; + info.has_adaptive_stop_per_sample = true; info.has_osl = true; info.has_profiling = true; @@ -639,6 +640,7 @@ DeviceInfo Device::get_multi_device(const vector &subdevices, /* Accumulate device info. */ info.has_half_images &= device.has_half_images; info.has_volume_decoupled &= device.has_volume_decoupled; + info.has_adaptive_stop_per_sample &= device.has_adaptive_stop_per_sample; info.has_osl &= device.has_osl; info.has_profiling &= device.has_profiling; } diff --git a/intern/cycles/device/device.h b/intern/cycles/device/device.h index a98ac171709..c55dfb3a83b 100644 --- a/intern/cycles/device/device.h +++ b/intern/cycles/device/device.h @@ -75,12 +75,13 @@ class DeviceInfo { string description; string id; /* used for user preferences, should stay fixed with changing hardware config */ int num; - bool display_device; /* GPU is used as a display device. */ - bool has_half_images; /* Support half-float textures. */ - bool has_volume_decoupled; /* Decoupled volume shading. */ - bool has_osl; /* Support Open Shading Language. */ - bool use_split_kernel; /* Use split or mega kernel. */ - bool has_profiling; /* Supports runtime collection of profiling info. */ + bool display_device; /* GPU is used as a display device. */ + bool has_half_images; /* Support half-float textures. */ + bool has_volume_decoupled; /* Decoupled volume shading. */ + bool has_adaptive_stop_per_sample; /* Per-sample adaptive sampling stopping. */ + bool has_osl; /* Support Open Shading Language. */ + bool use_split_kernel; /* Use split or mega kernel. */ + bool has_profiling; /* Supports runtime collection of profiling info. */ int cpu_threads; vector multi_devices; vector denoising_devices; @@ -94,6 +95,7 @@ class DeviceInfo { display_device = false; has_half_images = false; has_volume_decoupled = false; + has_adaptive_stop_per_sample = false; has_osl = false; use_split_kernel = false; has_profiling = false; diff --git a/intern/cycles/device/device_cpu.cpp b/intern/cycles/device/device_cpu.cpp index 57e8523e02a..c701c14318f 100644 --- a/intern/cycles/device/device_cpu.cpp +++ b/intern/cycles/device/device_cpu.cpp @@ -839,7 +839,7 @@ class CPUDevice : public Device { return true; } - bool adaptive_sampling_filter(KernelGlobals *kg, RenderTile &tile) + bool adaptive_sampling_filter(KernelGlobals *kg, RenderTile &tile, int sample) { WorkTile wtile; wtile.x = tile.x; @@ -850,11 +850,24 @@ class CPUDevice : public Device { wtile.stride = tile.stride; wtile.buffer = (float *)tile.buffer; + /* For CPU we do adaptive stopping per sample so we can stop earlier, but + * for combined CPU + GPU rendering we match the GPU and do it per tile + * after a given number of sample steps. */ + if (!kernel_data.integrator.adaptive_stop_per_sample) { + for (int y = wtile.y; y < wtile.y + wtile.h; ++y) { + for (int x = wtile.x; x < wtile.x + wtile.w; ++x) { + const int index = wtile.offset + x + y * wtile.stride; + float *buffer = wtile.buffer + index * kernel_data.film.pass_stride; + kernel_do_adaptive_stopping(kg, buffer, sample); + } + } + } + bool any = false; - for (int y = tile.y; y < tile.y + tile.h; ++y) { + for (int y = wtile.y; y < wtile.y + wtile.h; ++y) { any |= kernel_do_adaptive_filter_x(kg, y, &wtile); } - for (int x = tile.x; x < tile.x + tile.w; ++x) { + for (int x = wtile.x; x < wtile.x + wtile.w; ++x) { any |= kernel_do_adaptive_filter_y(kg, x, &wtile); } return (!any); @@ -917,7 +930,7 @@ class CPUDevice : public Device { tile.sample = sample + 1; if (task.adaptive_sampling.use && task.adaptive_sampling.need_filter(sample)) { - const bool stop = adaptive_sampling_filter(kg, tile); + const bool stop = adaptive_sampling_filter(kg, tile, sample); if (stop) { const int num_progress_samples = end_sample - sample; tile.sample = end_sample; @@ -1327,6 +1340,7 @@ void device_cpu_info(vector &devices) info.id = "CPU"; info.num = 0; info.has_volume_decoupled = true; + info.has_adaptive_stop_per_sample = true; info.has_osl = true; info.has_half_images = true; info.has_profiling = true; diff --git a/intern/cycles/device/device_cuda.cpp b/intern/cycles/device/device_cuda.cpp index 9a703b45c0a..4a53fcd151d 100644 --- a/intern/cycles/device/device_cuda.cpp +++ b/intern/cycles/device/device_cuda.cpp @@ -129,6 +129,7 @@ void device_cuda_info(vector &devices) info.has_half_images = (major >= 3); info.has_volume_decoupled = false; + info.has_adaptive_stop_per_sample = false; int pci_location[3] = {0, 0, 0}; cuDeviceGetAttribute(&pci_location[0], CU_DEVICE_ATTRIBUTE_PCI_DOMAIN_ID, num); diff --git a/intern/cycles/device/device_network.cpp b/intern/cycles/device/device_network.cpp index 2742cbf53aa..0933d51f321 100644 --- a/intern/cycles/device/device_network.cpp +++ b/intern/cycles/device/device_network.cpp @@ -311,6 +311,7 @@ void device_network_info(vector &devices) /* todo: get this info from device */ info.has_volume_decoupled = false; + info.has_adaptive_stop_per_sample = false; info.has_osl = false; devices.push_back(info); diff --git a/intern/cycles/device/device_opencl.cpp b/intern/cycles/device/device_opencl.cpp index 891b73351a0..8a0b128697f 100644 --- a/intern/cycles/device/device_opencl.cpp +++ b/intern/cycles/device/device_opencl.cpp @@ -119,6 +119,7 @@ void device_opencl_info(vector &devices) info.display_device = true; info.use_split_kernel = true; info.has_volume_decoupled = false; + info.has_adaptive_stop_per_sample = false; info.id = id; /* Check OpenCL extensions */ diff --git a/intern/cycles/device/device_task.cpp b/intern/cycles/device/device_task.cpp index c36b1344c3b..d2447eae867 100644 --- a/intern/cycles/device/device_task.cpp +++ b/intern/cycles/device/device_task.cpp @@ -138,8 +138,7 @@ void DeviceTask::update_progress(RenderTile *rtile, int pixel_samples) /* Adaptive Sampling */ -AdaptiveSampling::AdaptiveSampling() - : use(true), adaptive_step(ADAPTIVE_SAMPLE_STEP), min_samples(0) +AdaptiveSampling::AdaptiveSampling() : use(true), adaptive_step(0), min_samples(0) { } diff --git a/intern/cycles/kernel/kernel_passes.h b/intern/cycles/kernel/kernel_passes.h index 98136bc7047..7437e540a1f 100644 --- a/intern/cycles/kernel/kernel_passes.h +++ b/intern/cycles/kernel/kernel_passes.h @@ -403,9 +403,13 @@ ccl_device_inline void kernel_write_result(KernelGlobals *kg, make_float4(L_sum.x * 2.0f, L_sum.y * 2.0f, L_sum.z * 2.0f, 0.0f)); } #ifdef __KERNEL_CPU__ - if (sample > kernel_data.integrator.adaptive_min_samples && - (sample & (ADAPTIVE_SAMPLE_STEP - 1)) == (ADAPTIVE_SAMPLE_STEP - 1)) { - kernel_do_adaptive_stopping(kg, buffer, sample); + if ((sample > kernel_data.integrator.adaptive_min_samples) && + kernel_data.integrator.adaptive_stop_per_sample) { + const int step = kernel_data.integrator.adaptive_step; + + if ((sample & (step - 1)) == (step - 1)) { + kernel_do_adaptive_stopping(kg, buffer, sample); + } } #endif } diff --git a/intern/cycles/kernel/kernel_types.h b/intern/cycles/kernel/kernel_types.h index 44c936da626..a1f8c35348d 100644 --- a/intern/cycles/kernel/kernel_types.h +++ b/intern/cycles/kernel/kernel_types.h @@ -63,11 +63,6 @@ CCL_NAMESPACE_BEGIN #define VOLUME_STACK_SIZE 32 -/* Adaptive sampling constants */ -#define ADAPTIVE_SAMPLE_STEP 4 -static_assert((ADAPTIVE_SAMPLE_STEP & (ADAPTIVE_SAMPLE_STEP - 1)) == 0, - "ADAPTIVE_SAMPLE_STEP must be power of two for bitwise operations to work"); - /* Split kernel constants */ #define WORK_POOL_SIZE_GPU 64 #define WORK_POOL_SIZE_CPU 1 @@ -1350,6 +1345,8 @@ typedef struct KernelIntegrator { int sampling_pattern; int aa_samples; int adaptive_min_samples; + int adaptive_step; + int adaptive_stop_per_sample; float adaptive_threshold; /* volume render */ @@ -1362,7 +1359,7 @@ typedef struct KernelIntegrator { int max_closures; - int pad1, pad2, pad3; + int pad1; } KernelIntegrator; static_assert_align(KernelIntegrator, 16); diff --git a/intern/cycles/render/integrator.cpp b/intern/cycles/render/integrator.cpp index 2f9d088899e..d4beb06e57b 100644 --- a/intern/cycles/render/integrator.cpp +++ b/intern/cycles/render/integrator.cpp @@ -190,6 +190,13 @@ void Integrator::device_update(Device *device, DeviceScene *dscene, Scene *scene else { kintegrator->adaptive_min_samples = max(4, adaptive_min_samples); } + + kintegrator->adaptive_step = 4; + kintegrator->adaptive_stop_per_sample = device->info.has_adaptive_stop_per_sample; + + /* Adaptive step must be a power of two for bitwise operations to work. */ + assert((kintegrator->adaptive_step & (kintegrator->adaptive_step - 1)) == 0); + if (aa_samples > 0 && adaptive_threshold == 0.0f) { kintegrator->adaptive_threshold = max(0.001f, 1.0f / (float)aa_samples); VLOG(1) << "Cycles adaptive sampling: automatic threshold = " diff --git a/intern/cycles/render/session.cpp b/intern/cycles/render/session.cpp index b1b30979b0e..58bcc7ccdfb 100644 --- a/intern/cycles/render/session.cpp +++ b/intern/cycles/render/session.cpp @@ -1110,6 +1110,7 @@ void Session::render(bool with_denoising) task.adaptive_sampling.use = (scene->integrator->sampling_pattern == SAMPLING_PATTERN_PMJ) && scene->dscene.data.film.pass_adaptive_aux_buffer; task.adaptive_sampling.min_samples = scene->dscene.data.integrator.adaptive_min_samples; + task.adaptive_sampling.adaptive_step = scene->dscene.data.integrator.adaptive_step; /* Acquire render tiles by default. */ task.tile_types = RenderTile::PATH_TRACE; -- cgit v1.2.3 From 968619d03626c7e4d92d4cb383ac304b72595af3 Mon Sep 17 00:00:00 2001 From: Harley Acheson Date: Tue, 7 Apr 2020 13:25:49 -0700 Subject: UI: Language Selection Changes Removal of 'Translation' checkbox. Enable translation options when selecting non-English languages. Differential Revision: https://developer.blender.org/D7210 Reviewed by Brecht Van Lommel --- release/scripts/startup/bl_ui/space_userpref.py | 9 +------ source/blender/blenkernel/BKE_blender_version.h | 2 +- .../blender/blenloader/intern/versioning_userdef.c | 13 ++++++++++ source/blender/blentranslation/BLT_translation.h | 4 +++ source/blender/blentranslation/intern/blt_lang.c | 13 +++------- .../blentranslation/intern/blt_translation.c | 2 +- source/blender/makesdna/DNA_userdef_types.h | 2 +- source/blender/makesrna/intern/rna_userdef.c | 29 ++++++++++++++-------- 8 files changed, 43 insertions(+), 31 deletions(-) diff --git a/release/scripts/startup/bl_ui/space_userpref.py b/release/scripts/startup/bl_ui/space_userpref.py index 165761254d0..76e80fdb414 100644 --- a/release/scripts/startup/bl_ui/space_userpref.py +++ b/release/scripts/startup/bl_ui/space_userpref.py @@ -242,21 +242,14 @@ class USERPREF_PT_interface_translation(InterfacePanel, CenterAlignMixIn, Panel) def poll(cls, context): return bpy.app.build_options.international - def draw_header(self, context): - prefs = context.preferences - view = prefs.view - - self.layout.prop(view, "use_international_fonts", text="") - def draw_centered(self, context, layout): prefs = context.preferences view = prefs.view - layout.active = view.use_international_fonts - layout.prop(view, "language") flow = layout.grid_flow(row_major=False, columns=0, even_columns=True, even_rows=False, align=False) + flow.active = (bpy.app.translations.locale != 'en_US') flow.prop(view, "use_translate_tooltips", text="Tooltips") flow.prop(view, "use_translate_interface", text="Interface") diff --git a/source/blender/blenkernel/BKE_blender_version.h b/source/blender/blenkernel/BKE_blender_version.h index 794313ecf62..b9eab004ddf 100644 --- a/source/blender/blenkernel/BKE_blender_version.h +++ b/source/blender/blenkernel/BKE_blender_version.h @@ -27,7 +27,7 @@ * \note Use #STRINGIFY() rather than defining with quotes. */ #define BLENDER_VERSION 283 -#define BLENDER_SUBVERSION 12 +#define BLENDER_SUBVERSION 13 /** Several breakages with 280, e.g. collections vs layers. */ #define BLENDER_MINVERSION 280 #define BLENDER_MINSUBVERSION 0 diff --git a/source/blender/blenloader/intern/versioning_userdef.c b/source/blender/blenloader/intern/versioning_userdef.c index 28118d6e87a..a426e49dd77 100644 --- a/source/blender/blenloader/intern/versioning_userdef.c +++ b/source/blender/blenloader/intern/versioning_userdef.c @@ -26,6 +26,10 @@ #include "BLI_math.h" #include "BLI_utildefines.h" +#ifdef WITH_INTERNATIONAL +# include "BLT_translation.h" +#endif + #include "DNA_anim_types.h" #include "DNA_curve_types.h" #include "DNA_scene_types.h" @@ -740,6 +744,15 @@ void BLO_version_defaults_userpref_blend(Main *bmain, UserDef *userdef) userdef->gpu_flag |= USER_GPU_FLAG_OVERLAY_SMOOTH_WIRE; } + if (!USER_VERSION_ATLEAST(283, 13)) { + /* If Translations is off then language should default to English. */ + if ((userdef->transopts & USER_DOTRANSLATE_DEPRECATED) == 0) { + userdef->language = ULANGUAGE_ENGLISH; + } + /* Clear this deprecated flag. */ + userdef->transopts &= ~USER_DOTRANSLATE_DEPRECATED; + } + /** * Versioning code until next subversion bump goes here. * diff --git a/source/blender/blentranslation/BLT_translation.h b/source/blender/blentranslation/BLT_translation.h index 74c46b1cf3e..01e32c3f71a 100644 --- a/source/blender/blentranslation/BLT_translation.h +++ b/source/blender/blentranslation/BLT_translation.h @@ -32,6 +32,10 @@ extern "C" { #endif +/* Locale Ids. Auto will try to get local from OS. Our default is English though. */ +#define ULANGUAGE_AUTO 0 +#define ULANGUAGE_ENGLISH 1 + bool BLT_is_default_context(const char *msgctxt); const char *BLT_pgettext(const char *msgctxt, const char *msgid); diff --git a/source/blender/blentranslation/intern/blt_lang.c b/source/blender/blentranslation/intern/blt_lang.c index 112c615fac2..a533d29b188 100644 --- a/source/blender/blentranslation/intern/blt_lang.c +++ b/source/blender/blentranslation/intern/blt_lang.c @@ -253,7 +253,8 @@ void BLT_lang_free(void) } #ifdef WITH_INTERNATIONAL -# define ULANGUAGE ((U.language >= 0 && U.language < num_locales) ? U.language : 0) +# define ULANGUAGE \ + ((U.language >= ULANGUAGE_AUTO && U.language < num_locales) ? U.language : ULANGUAGE_ENGLISH) # define LOCALE(_id) (locales ? locales[(_id)] : "") #endif @@ -264,7 +265,7 @@ void BLT_lang_set(const char *str) const char *short_locale = str ? str : LOCALE(ulang); const char *short_locale_utf8 = NULL; - if ((U.transopts & USER_DOTRANSLATE) == 0) { + if (U.language == ULANGUAGE_ENGLISH) { return; } @@ -388,13 +389,7 @@ static void blt_lang_check_ime_supported(void) { #ifdef WITH_INPUT_IME const char *uilng = BLT_lang_get(); - if (U.transopts & USER_DOTRANSLATE) { - ime_is_lang_supported = STREQ(uilng, "zh_CN") || STREQ(uilng, "zh_TW") || - STREQ(uilng, "ja_JP"); - } - else { - ime_is_lang_supported = false; - } + ime_is_lang_supported = STREQ(uilng, "zh_CN") || STREQ(uilng, "zh_TW") || STREQ(uilng, "ja_JP"); #else ime_is_lang_supported = false; #endif diff --git a/source/blender/blentranslation/intern/blt_translation.c b/source/blender/blentranslation/intern/blt_translation.c index 64e14522aca..0ca068d4263 100644 --- a/source/blender/blentranslation/intern/blt_translation.c +++ b/source/blender/blentranslation/intern/blt_translation.c @@ -81,7 +81,7 @@ const char *BLT_pgettext(const char *msgctxt, const char *msgid) bool BLT_translate(void) { #ifdef WITH_INTERNATIONAL - return BLI_thread_is_main() && (U.transopts & USER_DOTRANSLATE); + return BLI_thread_is_main() && (U.language != ULANGUAGE_ENGLISH); #else return false; #endif diff --git a/source/blender/makesdna/DNA_userdef_types.h b/source/blender/makesdna/DNA_userdef_types.h index 54470dc59fc..667b6bbf33c 100644 --- a/source/blender/makesdna/DNA_userdef_types.h +++ b/source/blender/makesdna/DNA_userdef_types.h @@ -1124,7 +1124,7 @@ typedef enum eUserpref_Translation_Flags { USER_TR_UNUSED_2 = (1 << 2), /* cleared */ USER_TR_UNUSED_3 = (1 << 3), /* cleared */ USER_TR_UNUSED_4 = (1 << 4), /* cleared */ - USER_DOTRANSLATE = (1 << 5), + USER_DOTRANSLATE_DEPRECATED = (1 << 5), /* Deprecated in 2.83. */ USER_TR_UNUSED_6 = (1 << 6), /* cleared */ USER_TR_UNUSED_7 = (1 << 7), /* cleared */ USER_TR_NEWDATANAME = (1 << 8), diff --git a/source/blender/makesrna/intern/rna_userdef.c b/source/blender/makesrna/intern/rna_userdef.c index f52307355c2..514d7428ff8 100644 --- a/source/blender/makesrna/intern/rna_userdef.c +++ b/source/blender/makesrna/intern/rna_userdef.c @@ -307,14 +307,27 @@ static void rna_userdef_screen_update_header_default(Main *bmain, Scene *scene, USERDEF_TAG_DIRTY; } +static void rna_userdef_font_update(Main *UNUSED(bmain), + Scene *UNUSED(scene), + PointerRNA *UNUSED(ptr)) +{ + BLF_cache_clear(); + UI_reinit_font(); +} + static void rna_userdef_language_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *UNUSED(ptr)) { - BLF_cache_clear(); BLT_lang_set(NULL); - UI_reinit_font(); - USERDEF_TAG_DIRTY; + + const char *uilng = BLT_lang_get(); + if (STREQ(uilng, "en_US")) { + U.transopts &= ~(USER_TR_IFACE | USER_TR_TOOLTIPS | USER_TR_NEWDATANAME); + } + else { + U.transopts |= (USER_TR_IFACE | USER_TR_TOOLTIPS | USER_TR_NEWDATANAME); + } } static void rna_userdef_script_autoexec_update(Main *UNUSED(bmain), @@ -4716,21 +4729,15 @@ static void rna_def_userdef_view(BlenderRNA *brna) prop = RNA_def_property(srna, "font_path_ui", PROP_STRING, PROP_FILEPATH); RNA_def_property_string_sdna(prop, NULL, "font_path_ui"); RNA_def_property_ui_text(prop, "Interface Font", "Path to interface font"); - RNA_def_property_update(prop, NC_WINDOW, "rna_userdef_language_update"); + RNA_def_property_update(prop, NC_WINDOW, "rna_userdef_font_update"); prop = RNA_def_property(srna, "font_path_ui_mono", PROP_STRING, PROP_FILEPATH); RNA_def_property_string_sdna(prop, NULL, "font_path_ui_mono"); RNA_def_property_ui_text(prop, "Mono-space Font", "Path to interface mono-space Font"); - RNA_def_property_update(prop, NC_WINDOW, "rna_userdef_language_update"); + RNA_def_property_update(prop, NC_WINDOW, "rna_userdef_font_update"); /* Language. */ - prop = RNA_def_property(srna, "use_international_fonts", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_sdna(prop, NULL, "transopts", USER_DOTRANSLATE); - RNA_def_property_ui_text( - prop, "Translate UI", "Enable UI translation and use international fonts"); - RNA_def_property_update(prop, NC_WINDOW, "rna_userdef_language_update"); - prop = RNA_def_property(srna, "language", PROP_ENUM, PROP_NONE); RNA_def_property_enum_items(prop, rna_enum_language_default_items); # ifdef WITH_INTERNATIONAL -- cgit v1.2.3 From a2243f1b5178fde2a49e5536b674cae57c096659 Mon Sep 17 00:00:00 2001 From: Brecht Van Lommel Date: Tue, 7 Apr 2020 23:41:30 +0200 Subject: Debugging: change Undo/Redo redraw timer to include dependency graph update This is often the slowest part and was not counted before. --- source/blender/windowmanager/intern/wm_operators.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/source/blender/windowmanager/intern/wm_operators.c b/source/blender/windowmanager/intern/wm_operators.c index 6d25874da45..a7578291a21 100644 --- a/source/blender/windowmanager/intern/wm_operators.c +++ b/source/blender/windowmanager/intern/wm_operators.c @@ -103,6 +103,7 @@ #include "wm.h" #include "wm_draw.h" +#include "wm_event_system.h" #include "wm_event_types.h" #include "wm_files.h" #include "wm_window.h" @@ -3244,8 +3245,12 @@ static void redraw_timer_step(bContext *C, } } else { /* eRTUndo */ + /* Undo and redo, including depsgraph update since that can be a + * significant part of the cost. */ ED_undo_pop(C); + wm_event_do_refresh_wm_and_depsgraph(C); ED_undo_redo(C); + wm_event_do_refresh_wm_and_depsgraph(C); } } -- cgit v1.2.3 From 9d0f4520768fdf9689a05cf2640f097972aa68a3 Mon Sep 17 00:00:00 2001 From: Brecht Van Lommel Date: Tue, 7 Apr 2020 23:56:07 +0200 Subject: Fix missed depsgraph update after undo in some cases Forgot to take into account legacy DEG_id_tag_update with zero flag. --- source/blender/depsgraph/intern/depsgraph_tag.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/blender/depsgraph/intern/depsgraph_tag.cc b/source/blender/depsgraph/intern/depsgraph_tag.cc index aa9ce28850c..627a93b5869 100644 --- a/source/blender/depsgraph/intern/depsgraph_tag.cc +++ b/source/blender/depsgraph/intern/depsgraph_tag.cc @@ -625,7 +625,7 @@ void id_tag_update(Main *bmain, ID *id, int flag, eUpdateSource update_source) /* Accumulate all tags for an ID between two undo steps, so they can be * replayed for undo. */ - id->recalc_undo_accumulated |= flag; + id->recalc_undo_accumulated |= deg_recalc_flags_effective(NULL, flag); } void graph_id_tag_update( -- cgit v1.2.3 From 1ee3def5d39f6d17ca7bb2dc74c5499f92eec739 Mon Sep 17 00:00:00 2001 From: Harley Acheson Date: Tue, 7 Apr 2020 16:32:42 -0700 Subject: UI: Splash Screen Language Selection Quick Setup splash now includes language selection. Differential Revision: https://developer.blender.org/D7370 Reviewed by Brecht Van Lommel --- release/scripts/startup/bl_operators/wm.py | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/release/scripts/startup/bl_operators/wm.py b/release/scripts/startup/bl_operators/wm.py index 6e3b883aa8a..f0f3ba14d92 100644 --- a/release/scripts/startup/bl_operators/wm.py +++ b/release/scripts/startup/bl_operators/wm.py @@ -2423,7 +2423,14 @@ class WM_MT_splash(Menu): col = split.column() - col.label() + sub = col.split(factor=0.35) + row = sub.row() + row.alignment = 'RIGHT' + row.label(text="Language") + prefs = context.preferences + sub.prop(prefs.view, "language", text="") + + col.separator() sub = col.split(factor=0.35) row = sub.row() @@ -2465,14 +2472,6 @@ class WM_MT_splash(Menu): label = "Blender Dark" sub.menu("USERPREF_MT_interface_theme_presets", text=label) - # We need to make switching to a language easier first - #sub = col.split(factor=0.35) - #row = sub.row() - #row.alignment = 'RIGHT' - # row.label(text="Language:") - #prefs = context.preferences - #sub.prop(prefs.system, "language", text="") - # Keep height constant if not has_select_mouse: col.label() -- cgit v1.2.3 From 161c13e12be0c968808612010268e81c88327f65 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Wed, 8 Apr 2020 10:24:33 +1000 Subject: Fix building without translations enabled --- source/blender/blentranslation/BLT_translation.h | 4 ---- source/blender/makesdna/DNA_userdef_types.h | 7 +++++++ 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/source/blender/blentranslation/BLT_translation.h b/source/blender/blentranslation/BLT_translation.h index 01e32c3f71a..74c46b1cf3e 100644 --- a/source/blender/blentranslation/BLT_translation.h +++ b/source/blender/blentranslation/BLT_translation.h @@ -32,10 +32,6 @@ extern "C" { #endif -/* Locale Ids. Auto will try to get local from OS. Our default is English though. */ -#define ULANGUAGE_AUTO 0 -#define ULANGUAGE_ENGLISH 1 - bool BLT_is_default_context(const char *msgctxt); const char *BLT_pgettext(const char *msgctxt, const char *msgid); diff --git a/source/blender/makesdna/DNA_userdef_types.h b/source/blender/makesdna/DNA_userdef_types.h index 667b6bbf33c..d2a099b4fcf 100644 --- a/source/blender/makesdna/DNA_userdef_types.h +++ b/source/blender/makesdna/DNA_userdef_types.h @@ -1305,6 +1305,13 @@ typedef enum eUserpref_DiskCacheCompression { USER_SEQ_DISK_CACHE_COMPRESSION_HIGH = 2, } eUserpref_DiskCacheCompression; +/* Locale Ids. Auto will try to get local from OS. Our default is English though. */ +/** #UserDef.language */ +enum { + ULANGUAGE_AUTO = 0, + ULANGUAGE_ENGLISH = 1, +}; + #ifdef __cplusplus } #endif -- cgit v1.2.3 From 1ec2f8d1f22634fc171a88d739c96ee8406b6c29 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Wed, 8 Apr 2020 10:33:56 +1000 Subject: Cleanup: spelling --- source/blender/blenkernel/intern/mesh_convert.c | 2 +- source/blender/blenloader/intern/readfile.c | 4 ++-- source/blender/editors/armature/armature_add.c | 11 +++++------ source/blender/editors/undo/memfile_undo.c | 2 +- 4 files changed, 9 insertions(+), 10 deletions(-) diff --git a/source/blender/blenkernel/intern/mesh_convert.c b/source/blender/blenkernel/intern/mesh_convert.c index e24718ebe30..28a32e1573b 100644 --- a/source/blender/blenkernel/intern/mesh_convert.c +++ b/source/blender/blenkernel/intern/mesh_convert.c @@ -1165,7 +1165,7 @@ Mesh *BKE_mesh_new_from_object(Depsgraph *depsgraph, Object *object, bool preser * not cause ownership problems because evaluated object runtime is keeping track of the real * ownership. * - * Here we are constructing a mesh which is supposed to be iondependent, which means no shared + * Here we are constructing a mesh which is supposed to be independent, which means no shared * ownership is allowed, so we make sure edit mesh is reset to NULL (which is similar to as if * one duplicates the objects and applies all the modifiers). */ new_mesh->edit_mesh = NULL; diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c index 6b67842bf1e..898f318f60b 100644 --- a/source/blender/blenloader/intern/readfile.c +++ b/source/blender/blenloader/intern/readfile.c @@ -2838,7 +2838,7 @@ static int direct_link_id_restore_recalc(const FileData *fd, recalc |= direct_link_id_restore_recalc_exceptions(id_current); /* Evaluations for the current state that have not been performed yet - * by the time we are perfoming this undo step. */ + * by the time we are performing this undo step. */ recalc |= id_current->recalc; /* Tags that were set between the target state and the current state, @@ -9672,7 +9672,7 @@ static BHead *read_libblock(FileData *fd, const bool placeholder_set_indirect_extern, ID **r_id) { - /* First attemp to restore existing datablocks for undo. + /* First attempt to restore existing datablocks for undo. * When datablocks are changed but still exist, we restore them at the old * address and inherit recalc flags for the dependency graph. */ ID *id_old = NULL; diff --git a/source/blender/editors/armature/armature_add.c b/source/blender/editors/armature/armature_add.c index 3fce2376b40..dfb274fdefe 100644 --- a/source/blender/editors/armature/armature_add.c +++ b/source/blender/editors/armature/armature_add.c @@ -732,9 +732,8 @@ static void updateDuplicateTransformConstraintSettings(Object *ob, mul_m4_v3(target_mat, trans->to_min_rot); mul_m4_v3(target_mat, trans->to_max_rot); - /* TODO This does not support euler order, but doing so will make this way more complex. - * For now we have decided to not support all cornercases and advanced setups. (sebpa) - */ + /* TODO(sebpa): This does not support euler order, but doing so will make this way more complex. + * For now we have decided to not support all corner cases and advanced setups. */ /* Helper variables to denote the axis in trans->map */ const char X = 0; @@ -1181,9 +1180,9 @@ static int armature_symmetrize_exec(bContext *C, wmOperator *op) ebone_iter = ebone_iter->next) { if (EBONE_VISIBLE(arm, ebone_iter) && (ebone_iter->flag & BONE_SELECTED)) { if (ebone_iter->temp.ebone != NULL) { - /* will be set if the mirror bone already exists (no need to make a new one) - * but we do need to make sure that the pchan settings (constraints etc) is syncronized - */ + /* This will be set if the mirror bone already exists (no need to make a new one) + * but we do need to make sure that the 'pchan' settings (constraints etc) + * is synchronized. */ bPoseChannel *pchan; /* Make sure we clean up the old data before overwriting it */ pchan = BKE_pose_channel_verify(obedit->pose, ebone_iter->temp.ebone->name); diff --git a/source/blender/editors/undo/memfile_undo.c b/source/blender/editors/undo/memfile_undo.c index a5c503fec90..ebd5b2272b1 100644 --- a/source/blender/editors/undo/memfile_undo.c +++ b/source/blender/editors/undo/memfile_undo.c @@ -219,7 +219,7 @@ static void memfile_undosys_step_decode(struct bContext *C, bmain, id, memfile_undosys_step_id_reused_cb, bmain, IDWALK_READONLY); } - /* Tag depsgraph to update datablock for changes that happend between the + /* Tag depsgraph to update data-block for changes that happened between the * current and the target state, see direct_link_id_restore_recalc(). */ if (id->recalc) { DEG_id_tag_update_ex(bmain, id, id->recalc); -- cgit v1.2.3 From 056ebb56b16b92de8a3889c530da1cf14d445170 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Wed, 8 Apr 2020 10:34:39 +1000 Subject: Cleanup: clang-format --- source/blender/makesdna/DNA_userdef_types.h | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/source/blender/makesdna/DNA_userdef_types.h b/source/blender/makesdna/DNA_userdef_types.h index d2a099b4fcf..e8f4cae573a 100644 --- a/source/blender/makesdna/DNA_userdef_types.h +++ b/source/blender/makesdna/DNA_userdef_types.h @@ -1121,12 +1121,12 @@ typedef enum eAutokey_Flag { typedef enum eUserpref_Translation_Flags { USER_TR_TOOLTIPS = (1 << 0), USER_TR_IFACE = (1 << 1), - USER_TR_UNUSED_2 = (1 << 2), /* cleared */ - USER_TR_UNUSED_3 = (1 << 3), /* cleared */ - USER_TR_UNUSED_4 = (1 << 4), /* cleared */ + USER_TR_UNUSED_2 = (1 << 2), /* cleared */ + USER_TR_UNUSED_3 = (1 << 3), /* cleared */ + USER_TR_UNUSED_4 = (1 << 4), /* cleared */ USER_DOTRANSLATE_DEPRECATED = (1 << 5), /* Deprecated in 2.83. */ - USER_TR_UNUSED_6 = (1 << 6), /* cleared */ - USER_TR_UNUSED_7 = (1 << 7), /* cleared */ + USER_TR_UNUSED_6 = (1 << 6), /* cleared */ + USER_TR_UNUSED_7 = (1 << 7), /* cleared */ USER_TR_NEWDATANAME = (1 << 8), } eUserpref_Translation_Flags; -- cgit v1.2.3 From 1c5831144040709380e02fc41ddef2e10d998cda Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Wed, 8 Apr 2020 13:19:09 +1000 Subject: Fix status bar message showing saved when saving failed Resolves the following issues: - For the first time you save a .blend file, there was no feedback. - If the file fails to save (eg "No space left on device") the status bar message replaces the error with an invalid "Saved" message. While there is a popup, the user may cancel it with mouse motion and be left with the status bar message saying the file saved. D7371 by @XDroid with edits. --- source/blender/windowmanager/intern/wm_files.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/source/blender/windowmanager/intern/wm_files.c b/source/blender/windowmanager/intern/wm_files.c index fe4305830ab..8af83aac1be 100644 --- a/source/blender/windowmanager/intern/wm_files.c +++ b/source/blender/windowmanager/intern/wm_files.c @@ -1433,6 +1433,9 @@ static bool wm_file_write(bContext *C, const char *filepath, int fileflags, Repo ibuf_thumb = IMB_thumb_create(filepath, THB_LARGE, THB_SOURCE_BLEND, ibuf_thumb); } + /* Without this there is no feedback the file was saved. */ + BKE_reportf(reports, RPT_INFO, "Saved \"%s\"", BLI_path_basename(filepath)); + /* Success. */ ok = true; } @@ -2715,8 +2718,6 @@ static int wm_save_mainfile_invoke(bContext *C, wmOperator *op, const wmEvent *U RNA_string_get(op->ptr, "filepath", path); ret = wm_save_as_mainfile_exec(C, op); - /* Without this there is no feedback the file was saved. */ - BKE_reportf(op->reports, RPT_INFO, "Saved \"%s\"", BLI_path_basename(path)); } else { WM_event_add_fileselect(C, op); -- cgit v1.2.3 From bd45ec0b06c6dfd5dcf222350bb78a055c7315a5 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Wed, 8 Apr 2020 13:29:51 +1000 Subject: Cleanup: disable clang-format for character table --- source/blender/imbuf/intern/thumbs.c | 105 +++-------------------------------- 1 file changed, 9 insertions(+), 96 deletions(-) diff --git a/source/blender/imbuf/intern/thumbs.c b/source/blender/imbuf/intern/thumbs.c index 195a2e9fe9c..17b619d451c 100644 --- a/source/blender/imbuf/intern/thumbs.c +++ b/source/blender/imbuf/intern/thumbs.c @@ -151,111 +151,24 @@ typedef enum { UNSAFE_SLASHES = 0x20, /* Allows all characters except for '/' and '%' */ } UnsafeCharacterSet; +/* Don't loose comment alignment. */ +/* clang-format off */ static const unsigned char acceptable[96] = { /* A table of the ASCII chars from space (32) to DEL (127) */ /* ! " # $ % & ' ( ) * + , - . / */ - 0x00, - 0x3F, - 0x20, - 0x20, - 0x28, - 0x00, - 0x2C, - 0x3F, - 0x3F, - 0x3F, - 0x3F, - 0x2A, - 0x28, - 0x3F, - 0x3F, - 0x1C, + 0x00,0x3F,0x20,0x20,0x28,0x00,0x2C,0x3F,0x3F,0x3F,0x3F,0x2A,0x28,0x3F,0x3F,0x1C, /* 0 1 2 3 4 5 6 7 8 9 : ; < = > ? */ - 0x3F, - 0x3F, - 0x3F, - 0x3F, - 0x3F, - 0x3F, - 0x3F, - 0x3F, - 0x3F, - 0x3F, - 0x38, - 0x20, - 0x20, - 0x2C, - 0x20, - 0x20, + 0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x38,0x20,0x20,0x2C,0x20,0x20, /* @ A B C D E F G H I J K L M N O */ - 0x38, - 0x3F, - 0x3F, - 0x3F, - 0x3F, - 0x3F, - 0x3F, - 0x3F, - 0x3F, - 0x3F, - 0x3F, - 0x3F, - 0x3F, - 0x3F, - 0x3F, - 0x3F, + 0x38,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F, /* P Q R S T U V W X Y Z [ \ ] ^ _ */ - 0x3F, - 0x3F, - 0x3F, - 0x3F, - 0x3F, - 0x3F, - 0x3F, - 0x3F, - 0x3F, - 0x3F, - 0x3F, - 0x20, - 0x20, - 0x20, - 0x20, - 0x3F, + 0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x20,0x20,0x20,0x20,0x3F, /* ` a b c d e f g h i j k l m n o */ - 0x20, - 0x3F, - 0x3F, - 0x3F, - 0x3F, - 0x3F, - 0x3F, - 0x3F, - 0x3F, - 0x3F, - 0x3F, - 0x3F, - 0x3F, - 0x3F, - 0x3F, - 0x3F, + 0x20,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F, /* p q r s t u v w x y z { | } ~ DEL */ - 0x3F, - 0x3F, - 0x3F, - 0x3F, - 0x3F, - 0x3F, - 0x3F, - 0x3F, - 0x3F, - 0x3F, - 0x3F, - 0x20, - 0x20, - 0x20, - 0x3F, - 0x20, + 0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x20,0x20,0x20,0x3F,0x20, }; +/* clang-format on */ static const char hex[17] = "0123456789abcdef"; -- cgit v1.2.3 From 35861a49eef94dd9384d967ea1c92c87408a68d9 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Wed, 8 Apr 2020 16:24:33 +1000 Subject: Fix T67098: Inset causes shape keys to reset exiting edit-mode Edit-mesh interactive redo reset the meshes shape-key index. Also copy the selection mode when copying meshes. --- source/blender/blenkernel/intern/editmesh.c | 4 ++++ source/blender/bmesh/intern/bmesh_construct.c | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/source/blender/blenkernel/intern/editmesh.c b/source/blender/blenkernel/intern/editmesh.c index 94976ed0c96..5aaae74e670 100644 --- a/source/blender/blenkernel/intern/editmesh.c +++ b/source/blender/blenkernel/intern/editmesh.c @@ -67,6 +67,10 @@ BMEditMesh *BKE_editmesh_copy(BMEditMesh *em) * tessellation only when/if that copy ends up getting used. */ em_copy->looptris = NULL; + /* Copy various settings. */ + em_copy->selectmode = em->selectmode; + em_copy->mat_nr = em->mat_nr; + return em_copy; } diff --git a/source/blender/bmesh/intern/bmesh_construct.c b/source/blender/bmesh/intern/bmesh_construct.c index 592d8124b23..0d79d60e5c1 100644 --- a/source/blender/bmesh/intern/bmesh_construct.c +++ b/source/blender/bmesh/intern/bmesh_construct.c @@ -717,6 +717,10 @@ BMesh *BM_mesh_copy(BMesh *bm_old) MEM_freeN(vtable); MEM_freeN(ftable); + /* Copy various settings. */ + bm_new->shapenr = bm_old->shapenr; + bm_new->selectmode = bm_old->selectmode; + return bm_new; } -- cgit v1.2.3 From b0d565e5b60c987b2e9aa6a438704a57e93412c3 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Wed, 8 Apr 2020 16:27:59 +1000 Subject: Cleanup: reduce scope of variables in custom data copying --- source/blender/blenkernel/intern/customdata.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/source/blender/blenkernel/intern/customdata.c b/source/blender/blenkernel/intern/customdata.c index 87a5ac80bc7..754c2ce097f 100644 --- a/source/blender/blenkernel/intern/customdata.c +++ b/source/blender/blenkernel/intern/customdata.c @@ -3556,10 +3556,9 @@ void CustomData_bmesh_copy_data_exclude_by_type(const CustomData *source, /* if we found a matching layer, copy the data */ if (dest->layers[dest_i].type == source->layers[src_i].type && STREQ(dest->layers[dest_i].name, source->layers[src_i].name)) { - const void *src_data = POINTER_OFFSET(src_block, source->layers[src_i].offset); - void *dest_data = POINTER_OFFSET(*dest_block, dest->layers[dest_i].offset); - if (no_mask || ((CD_TYPE_AS_MASK(dest->layers[dest_i].type) & mask_exclude) == 0)) { + const void *src_data = POINTER_OFFSET(src_block, source->layers[src_i].offset); + void *dest_data = POINTER_OFFSET(*dest_block, dest->layers[dest_i].offset); const LayerTypeInfo *typeInfo = layerType_getInfo(source->layers[src_i].type); if (typeInfo->copy) { typeInfo->copy(src_data, dest_data, 1); -- cgit v1.2.3 From 57468ae37ef98c7380edfbd97acb3bf6d626e4a7 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Wed, 8 Apr 2020 16:29:46 +1000 Subject: Cleanup: missed renaming BLI_cleanup_unc_16 in recent refactor Missed from d14e76806921f --- source/blender/blenlib/BLI_path_util.h | 2 +- source/blender/blenlib/intern/path_util.c | 4 ++-- source/blender/blenlib/intern/storage.c | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/source/blender/blenlib/BLI_path_util.h b/source/blender/blenlib/BLI_path_util.h index 2b88359861a..87f1ec5e4ff 100644 --- a/source/blender/blenlib/BLI_path_util.h +++ b/source/blender/blenlib/BLI_path_util.h @@ -109,7 +109,7 @@ bool BLI_path_is_unc(const char *path); void BLI_path_to_display_name(char *display_name, int maxlen, const char *name) ATTR_NONNULL(); #if defined(WIN32) -void BLI_cleanup_unc_16(wchar_t *path_16); +void BLI_path_normalize_unc_16(wchar_t *path_16); void BLI_path_normalize_unc(char *path_16, int maxlen); #endif diff --git a/source/blender/blenlib/intern/path_util.c b/source/blender/blenlib/intern/path_util.c index ad93b643c5e..95b2caa8836 100644 --- a/source/blender/blenlib/intern/path_util.c +++ b/source/blender/blenlib/intern/path_util.c @@ -497,11 +497,11 @@ static void BLI_path_unc_to_short(wchar_t *unc) void BLI_path_normalize_unc(char *path, int maxlen) { wchar_t *tmp_16 = alloc_utf16_from_8(path, 1); - BLI_cleanup_unc_16(tmp_16); + BLI_path_normalize_unc_16(tmp_16); conv_utf_16_to_8(tmp_16, path, maxlen); } -void BLI_cleanup_unc_16(wchar_t *path_16) +void BLI_path_normalize_unc_16(wchar_t *path_16) { BLI_path_unc_to_short(path_16); BLI_path_add_slash_to_share(path_16); diff --git a/source/blender/blenlib/intern/storage.c b/source/blender/blenlib/intern/storage.c index 7274a15661a..9b437b02c0a 100644 --- a/source/blender/blenlib/intern/storage.c +++ b/source/blender/blenlib/intern/storage.c @@ -316,7 +316,7 @@ int BLI_exists(const char *name) * 2. after the C:\ when the path is the volume only */ if ((len >= 3) && (tmp_16[0] == L'\\') && (tmp_16[1] == L'\\')) { - BLI_cleanup_unc_16(tmp_16); + BLI_path_normalize_unc_16(tmp_16); } if ((tmp_16[1] == L':') && (tmp_16[2] == L'\0')) { -- cgit v1.2.3 From a3c16055819f7236d0265dfa687f45031ee1b798 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Wed, 8 Apr 2020 16:35:13 +1000 Subject: Cleanup: rename to BLI_path_cwd to BLI_path_abs_from_cwd This is now more clearly a function that makes the path absolute using the current working directory. --- source/blender/blenkernel/intern/appdir.c | 2 +- source/blender/blenlib/BLI_path_util.h | 2 +- source/blender/blenlib/intern/path_util.c | 11 ++++++----- source/blender/python/intern/bpy_interface.c | 2 +- source/creator/creator_args.c | 4 ++-- 5 files changed, 11 insertions(+), 10 deletions(-) diff --git a/source/blender/blenkernel/intern/appdir.c b/source/blender/blenkernel/intern/appdir.c index 92b7bdcfb98..4071cc024aa 100644 --- a/source/blender/blenkernel/intern/appdir.c +++ b/source/blender/blenkernel/intern/appdir.c @@ -687,7 +687,7 @@ static void where_am_i(char *fullname, const size_t maxlen, const char *name) BLI_strncpy(fullname, name, maxlen); if (name[0] == '.') { - BLI_path_cwd(fullname, maxlen); + BLI_path_abs_from_cwd(fullname, maxlen); #ifdef _WIN32 BLI_path_program_extensions_add_win32(fullname, maxlen); #endif diff --git a/source/blender/blenlib/BLI_path_util.h b/source/blender/blenlib/BLI_path_util.h index 87f1ec5e4ff..9a6a14547d2 100644 --- a/source/blender/blenlib/BLI_path_util.h +++ b/source/blender/blenlib/BLI_path_util.h @@ -100,7 +100,7 @@ bool BLI_path_frame_range(char *path, int sta, int end, int digits) ATTR_NONNULL bool BLI_path_frame_get(char *path, int *r_frame, int *numdigits) ATTR_NONNULL(); void BLI_path_frame_strip(char *path, char *ext) ATTR_NONNULL(); bool BLI_path_frame_check_chars(const char *path) ATTR_NONNULL(); -bool BLI_path_cwd(char *path, const size_t maxlen) ATTR_NONNULL(); +bool BLI_path_abs_from_cwd(char *path, const size_t maxlen) ATTR_NONNULL(); void BLI_path_rel(char *file, const char *relfile) ATTR_NONNULL(); bool BLI_path_is_rel(const char *path) ATTR_NONNULL() ATTR_WARN_UNUSED_RESULT; diff --git a/source/blender/blenlib/intern/path_util.c b/source/blender/blenlib/intern/path_util.c index 95b2caa8836..2f51b66725b 100644 --- a/source/blender/blenlib/intern/path_util.c +++ b/source/blender/blenlib/intern/path_util.c @@ -1116,13 +1116,14 @@ bool BLI_path_abs(char *path, const char *basepath) } /** - * Expands path relative to the current working directory, if it was relative. - * Returns true if such expansion was done. + * Checks for relative path, expanding them relative to the current working directory. + * Returns true if the expansion was performed. * - * \note Should only be done with command line paths. - * this is _not_ something blenders internal paths support like the "//" prefix + * \note Should only be called with command line paths. + * This is _not_ something Blender's internal paths support, instead they use the "//" prefix. + * In most cases #BLI_path_abs should be used instead. */ -bool BLI_path_cwd(char *path, const size_t maxlen) +bool BLI_path_abs_from_cwd(char *path, const size_t maxlen) { #ifdef DEBUG_STRSIZE memset(path, 0xff, sizeof(*path) * maxlen); diff --git a/source/blender/python/intern/bpy_interface.c b/source/blender/python/intern/bpy_interface.c index fdf7e127af9..b09d3187f3c 100644 --- a/source/blender/python/intern/bpy_interface.c +++ b/source/blender/python/intern/bpy_interface.c @@ -940,7 +940,7 @@ static void bpy_module_delay_init(PyObject *bpy_proxy) char filename_abs[1024]; BLI_strncpy(filename_abs, filename_rel, sizeof(filename_abs)); - BLI_path_cwd(filename_abs, sizeof(filename_abs)); + BLI_path_abs_from_cwd(filename_abs, sizeof(filename_abs)); Py_DECREF(filename_obj); argv[0] = filename_abs; diff --git a/source/creator/creator_args.c b/source/creator/creator_args.c index 6ce3066ece1..381a43ff521 100644 --- a/source/creator/creator_args.c +++ b/source/creator/creator_args.c @@ -1780,7 +1780,7 @@ static int arg_handle_python_file_run(int argc, const char **argv, void *data) /* Make the path absolute because its needed for relative linked blends to be found */ char filename[FILE_MAX]; BLI_strncpy(filename, argv[1], sizeof(filename)); - BLI_path_cwd(filename, sizeof(filename)); + BLI_path_abs_from_cwd(filename, sizeof(filename)); bool ok; BPY_CTX_SETUP(ok = BPY_execute_filepath(C, filename, NULL)); @@ -1982,7 +1982,7 @@ static int arg_handle_load_file(int UNUSED(argc), const char **argv, void *data) } BLI_strncpy(filename, argv[0], sizeof(filename)); - BLI_path_cwd(filename, sizeof(filename)); + BLI_path_abs_from_cwd(filename, sizeof(filename)); /* load the file */ BKE_reports_init(&reports, RPT_PRINT); -- cgit v1.2.3 From d478cc71dd73691b8e482911df42c71aaa85de8c Mon Sep 17 00:00:00 2001 From: Miguel Pozo Date: Wed, 8 Apr 2020 12:16:43 +0200 Subject: Fix Windows Tablet API preference not being used It was sometimes set before reading preferences, now it's passed to GHOST every time preferences are read. Differential Revision: https://developer.blender.org/D5641 --- release/scripts/addons | 2 +- source/blender/windowmanager/intern/wm_files.c | 3 +++ source/blender/windowmanager/intern/wm_window.c | 2 -- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/release/scripts/addons b/release/scripts/addons index 8e6f485cf5b..d348bde0f96 160000 --- a/release/scripts/addons +++ b/release/scripts/addons @@ -1 +1 @@ -Subproject commit 8e6f485cf5b160c425d7da7c743879b20f3d6a96 +Subproject commit d348bde0f96809e289b0514c015cafb97f2dcf79 diff --git a/source/blender/windowmanager/intern/wm_files.c b/source/blender/windowmanager/intern/wm_files.c index 8af83aac1be..f2050befac1 100644 --- a/source/blender/windowmanager/intern/wm_files.c +++ b/source/blender/windowmanager/intern/wm_files.c @@ -375,6 +375,9 @@ static void wm_init_userdef(Main *bmain) /* update tempdir from user preferences */ BKE_tempdir_init(U.tempdir); + + /* Update tablet API preference. */ + WM_init_tablet_api(); } /* return codes */ diff --git a/source/blender/windowmanager/intern/wm_window.c b/source/blender/windowmanager/intern/wm_window.c index a83432e0248..1e25d73a86d 100644 --- a/source/blender/windowmanager/intern/wm_window.c +++ b/source/blender/windowmanager/intern/wm_window.c @@ -1679,8 +1679,6 @@ void wm_ghost_init(bContext *C) } GHOST_UseWindowFocus(wm_init_state.window_focus); - - WM_init_tablet_api(); } } -- cgit v1.2.3 From c43473e88415db1b62f9fa225baa23ca344cace8 Mon Sep 17 00:00:00 2001 From: Brecht Van Lommel Date: Fri, 27 Mar 2020 17:41:02 +0100 Subject: Cleanup: remove GHOST API to query tablet state from Window It's not used by Blender anymore and it's unreliable since this state really only makes sense associated with events in a particular order. Ref D6675 --- intern/ghost/GHOST_C-api.h | 7 ---- intern/ghost/GHOST_IWindow.h | 10 ----- intern/ghost/GHOST_Types.h | 2 +- intern/ghost/intern/GHOST_C-api.cpp | 5 --- intern/ghost/intern/GHOST_EventButton.h | 10 +++-- intern/ghost/intern/GHOST_EventCursor.h | 6 ++- intern/ghost/intern/GHOST_SystemCocoa.mm | 70 ++++++++++++++++++++++--------- intern/ghost/intern/GHOST_SystemSDL.cpp | 22 +++++++--- intern/ghost/intern/GHOST_SystemWin32.cpp | 32 +++++++++----- intern/ghost/intern/GHOST_SystemX11.cpp | 22 +++++++--- intern/ghost/intern/GHOST_WindowCocoa.h | 5 --- intern/ghost/intern/GHOST_WindowCocoa.mm | 2 +- intern/ghost/intern/GHOST_WindowWin32.cpp | 4 +- intern/ghost/intern/GHOST_WindowX11.cpp | 2 +- 14 files changed, 119 insertions(+), 80 deletions(-) diff --git a/intern/ghost/GHOST_C-api.h b/intern/ghost/GHOST_C-api.h index 5b45510a39f..75527d50c6a 100644 --- a/intern/ghost/GHOST_C-api.h +++ b/intern/ghost/GHOST_C-api.h @@ -761,13 +761,6 @@ extern unsigned int GHOST_GetDefaultOpenGLFramebuffer(GHOST_WindowHandle windwHa */ extern void GHOST_SetTabletAPI(GHOST_SystemHandle systemhandle, GHOST_TTabletAPI api); -/** - * Returns the status of the tablet - * \param windowhandle The handle to the window - * \return Status of tablet - */ -extern const GHOST_TabletData *GHOST_GetTabletData(GHOST_WindowHandle windowhandle); - /** * Access to rectangle width. * \param rectanglehandle The handle to the rectangle diff --git a/intern/ghost/GHOST_IWindow.h b/intern/ghost/GHOST_IWindow.h index c456f2b1dba..daf07b81e01 100644 --- a/intern/ghost/GHOST_IWindow.h +++ b/intern/ghost/GHOST_IWindow.h @@ -243,16 +243,6 @@ class GHOST_IWindow { virtual bool isDialog() const = 0; - /** - * Returns the tablet data (pressure etc). - * \return The tablet data (pressure etc). - */ - virtual const GHOST_TabletData &GetTabletData() - { - /* Default state when no tablet is used, for systems without tablet support. */ - return GHOST_TABLET_DATA_DEFAULT; - } - /*************************************************************************************** * Progress bar functionality ***************************************************************************************/ diff --git a/intern/ghost/GHOST_Types.h b/intern/ghost/GHOST_Types.h index eb844c9e574..8126c2299c6 100644 --- a/intern/ghost/GHOST_Types.h +++ b/intern/ghost/GHOST_Types.h @@ -117,7 +117,7 @@ typedef struct GHOST_TabletData { float Ytilt; /* as above */ } GHOST_TabletData; -static const GHOST_TabletData GHOST_TABLET_DATA_DEFAULT = { +static const GHOST_TabletData GHOST_TABLET_DATA_NONE = { GHOST_kTabletModeNone, /* No tablet connected. */ 1.0f, /* Pressure */ 0.0f, /* Xtilt */ diff --git a/intern/ghost/intern/GHOST_C-api.cpp b/intern/ghost/intern/GHOST_C-api.cpp index 6ee1557122d..db9fd2e3bf9 100644 --- a/intern/ghost/intern/GHOST_C-api.cpp +++ b/intern/ghost/intern/GHOST_C-api.cpp @@ -717,11 +717,6 @@ void GHOST_SetTabletAPI(GHOST_SystemHandle systemhandle, GHOST_TTabletAPI api) system->setTabletAPI(api); } -const GHOST_TabletData *GHOST_GetTabletData(GHOST_WindowHandle windowhandle) -{ - return &((GHOST_IWindow *)windowhandle)->GetTabletData(); -} - GHOST_TInt32 GHOST_GetWidthRectangle(GHOST_RectangleHandle rectanglehandle) { return ((GHOST_Rect *)rectanglehandle)->getWidth(); diff --git a/intern/ghost/intern/GHOST_EventButton.h b/intern/ghost/intern/GHOST_EventButton.h index e854bc23e5a..4247ae150a4 100644 --- a/intern/ghost/intern/GHOST_EventButton.h +++ b/intern/ghost/intern/GHOST_EventButton.h @@ -37,17 +37,19 @@ class GHOST_EventButton : public GHOST_Event { * Constructor. * \param time The time this event was generated. * \param type The type of this event. - * \param window: The window of this event. - * \param button: The state of the buttons were at the time of the event. + * \param window The window of this event. + * \param button The state of the buttons were at the time of the event. + * \param tablet The tablet data associated with this event. */ GHOST_EventButton(GHOST_TUns64 time, GHOST_TEventType type, GHOST_IWindow *window, - GHOST_TButtonMask button) + GHOST_TButtonMask button, + const GHOST_TabletData &tablet) : GHOST_Event(time, type, window) { m_buttonEventData.button = button; - m_buttonEventData.tablet = window->GetTabletData(); + m_buttonEventData.tablet = tablet; m_data = &m_buttonEventData; } diff --git a/intern/ghost/intern/GHOST_EventCursor.h b/intern/ghost/intern/GHOST_EventCursor.h index 41597db216a..8ba657fd9fa 100644 --- a/intern/ghost/intern/GHOST_EventCursor.h +++ b/intern/ghost/intern/GHOST_EventCursor.h @@ -38,17 +38,19 @@ class GHOST_EventCursor : public GHOST_Event { * \param type The type of this event. * \param x The x-coordinate of the location the cursor was at the time of the event. * \param y The y-coordinate of the location the cursor was at the time of the event. + * \param tablet The tablet data associated with this event. */ GHOST_EventCursor(GHOST_TUns64 msec, GHOST_TEventType type, GHOST_IWindow *window, GHOST_TInt32 x, - GHOST_TInt32 y) + GHOST_TInt32 y, + const GHOST_TabletData &tablet) : GHOST_Event(msec, type, window) { m_cursorEventData.x = x; m_cursorEventData.y = y; - m_cursorEventData.tablet = window->GetTabletData(); + m_cursorEventData.tablet = tablet; m_data = &m_cursorEventData; } diff --git a/intern/ghost/intern/GHOST_SystemCocoa.mm b/intern/ghost/intern/GHOST_SystemCocoa.mm index 9becff40995..3d6d187587c 100644 --- a/intern/ghost/intern/GHOST_SystemCocoa.mm +++ b/intern/ghost/intern/GHOST_SystemCocoa.mm @@ -817,7 +817,8 @@ GHOST_TSuccess GHOST_SystemCocoa::setCursorPosition(GHOST_TInt32 x, GHOST_TInt32 CGAssociateMouseAndMouseCursorPosition(true); // Force mouse move event (not pushed by Cocoa) - pushEvent(new GHOST_EventCursor(getMilliSeconds(), GHOST_kEventCursorMove, window, x, y)); + pushEvent(new GHOST_EventCursor( + getMilliSeconds(), GHOST_kEventCursorMove, window, x, y, window->GetCocoaTabletData())); m_outsideLoopEventProcessed = true; return GHOST_kSuccess; @@ -1098,8 +1099,11 @@ GHOST_TSuccess GHOST_SystemCocoa::handleWindowEvent(GHOST_TEventType eventType, pushEvent(new GHOST_Event(getMilliSeconds(), GHOST_kEventWindowSize, window)); // Mouse up event is trapped by the resizing event loop, // so send it anyway to the window manager. - pushEvent(new GHOST_EventButton( - getMilliSeconds(), GHOST_kEventButtonUp, window, GHOST_kButtonMaskLeft)); + pushEvent(new GHOST_EventButton(getMilliSeconds(), + GHOST_kEventButtonUp, + window, + GHOST_kButtonMaskLeft, + GHOST_TABLET_DATA_NONE)); // m_ignoreWindowSizedMessages = true; } break; @@ -1437,7 +1441,7 @@ GHOST_TSuccess GHOST_SystemCocoa::handleTabletEvent(void *eventPtr, short eventT case NSEventTypeTabletProximity: /* Reset tablet data when device enters proximity or leaves. */ - ct = GHOST_TABLET_DATA_DEFAULT; + ct = GHOST_TABLET_DATA_NONE; if ([event isEnteringProximity]) { /* Pointer is entering tablet area proximity. */ switch ([event pointingDeviceType]) { @@ -1504,38 +1508,52 @@ GHOST_TSuccess GHOST_SystemCocoa::handleMouseEvent(void *eventPtr) switch ([event type]) { case NSEventTypeLeftMouseDown: handleTabletEvent(event); // Update window tablet state to be included in event. - pushEvent(new GHOST_EventButton( - [event timestamp] * 1000, GHOST_kEventButtonDown, window, GHOST_kButtonMaskLeft)); + pushEvent(new GHOST_EventButton([event timestamp] * 1000, + GHOST_kEventButtonDown, + window, + GHOST_kButtonMaskLeft, + window -> GetCocoaTabletData())); break; case NSEventTypeRightMouseDown: handleTabletEvent(event); // Update window tablet state to be included in event. - pushEvent(new GHOST_EventButton( - [event timestamp] * 1000, GHOST_kEventButtonDown, window, GHOST_kButtonMaskRight)); + pushEvent(new GHOST_EventButton([event timestamp] * 1000, + GHOST_kEventButtonDown, + window, + GHOST_kButtonMaskRight, + window -> GetCocoaTabletData())); break; case NSEventTypeOtherMouseDown: handleTabletEvent(event); // Handle tablet events combined with mouse events pushEvent(new GHOST_EventButton([event timestamp] * 1000, GHOST_kEventButtonDown, window, - convertButton([event buttonNumber]))); + convertButton([event buttonNumber]), + window -> GetCocoaTabletData())); break; case NSEventTypeLeftMouseUp: handleTabletEvent(event); // Update window tablet state to be included in event. - pushEvent(new GHOST_EventButton( - [event timestamp] * 1000, GHOST_kEventButtonUp, window, GHOST_kButtonMaskLeft)); + pushEvent(new GHOST_EventButton([event timestamp] * 1000, + GHOST_kEventButtonUp, + window, + GHOST_kButtonMaskLeft, + window -> GetCocoaTabletData())); break; case NSEventTypeRightMouseUp: handleTabletEvent(event); // Update window tablet state to be included in event. - pushEvent(new GHOST_EventButton( - [event timestamp] * 1000, GHOST_kEventButtonUp, window, GHOST_kButtonMaskRight)); + pushEvent(new GHOST_EventButton([event timestamp] * 1000, + GHOST_kEventButtonUp, + window, + GHOST_kButtonMaskRight, + window -> GetCocoaTabletData())); break; case NSEventTypeOtherMouseUp: handleTabletEvent(event); // Update window tablet state to be included in event. pushEvent(new GHOST_EventButton([event timestamp] * 1000, GHOST_kEventButtonUp, window, - convertButton([event buttonNumber]))); + convertButton([event buttonNumber]), + window -> GetCocoaTabletData())); break; case NSEventTypeLeftMouseDragged: @@ -1568,8 +1586,12 @@ GHOST_TSuccess GHOST_SystemCocoa::handleMouseEvent(void *eventPtr) window->setCursorGrabAccum(x_accum, y_accum); window->clientToScreenIntern(x_warp + x_accum, y_warp + y_accum, x, y); - pushEvent(new GHOST_EventCursor( - [event timestamp] * 1000, GHOST_kEventCursorMove, window, x, y)); + pushEvent(new GHOST_EventCursor([event timestamp] * 1000, + GHOST_kEventCursorMove, + window, + x, + y, + window -> GetCocoaTabletData())); break; } case GHOST_kGrabWrap: // Wrap cursor at area/window boundaries @@ -1614,8 +1636,12 @@ GHOST_TSuccess GHOST_SystemCocoa::handleMouseEvent(void *eventPtr) // Generate event GHOST_TInt32 x, y; window->clientToScreenIntern(x_mouse + x_accum, y_mouse + y_accum, x, y); - pushEvent(new GHOST_EventCursor( - [event timestamp] * 1000, GHOST_kEventCursorMove, window, x, y)); + pushEvent(new GHOST_EventCursor([event timestamp] * 1000, + GHOST_kEventCursorMove, + window, + x, + y, + window -> GetCocoaTabletData())); break; } default: { @@ -1624,8 +1650,12 @@ GHOST_TSuccess GHOST_SystemCocoa::handleMouseEvent(void *eventPtr) GHOST_TInt32 x, y; window->clientToScreenIntern(mousePos.x, mousePos.y, x, y); - pushEvent(new GHOST_EventCursor( - [event timestamp] * 1000, GHOST_kEventCursorMove, window, x, y)); + pushEvent(new GHOST_EventCursor([event timestamp] * 1000, + GHOST_kEventCursorMove, + window, + x, + y, + window -> GetCocoaTabletData())); break; } } diff --git a/intern/ghost/intern/GHOST_SystemSDL.cpp b/intern/ghost/intern/GHOST_SystemSDL.cpp index 5dae0ce504b..97a75d7a0f5 100644 --- a/intern/ghost/intern/GHOST_SystemSDL.cpp +++ b/intern/ghost/intern/GHOST_SystemSDL.cpp @@ -390,22 +390,31 @@ void GHOST_SystemSDL::processEvent(SDL_Event *sdl_event) SDL_WarpMouseInWindow(sdl_win, x_new - x_win, y_new - y_win); } - g_event = new GHOST_EventCursor( - getMilliSeconds(), GHOST_kEventCursorMove, window, x_new, y_new); + g_event = new GHOST_EventCursor(getMilliSeconds(), + GHOST_kEventCursorMove, + window, + x_new, + y_new, + GHOST_TABLET_DATA_NONE); } else { g_event = new GHOST_EventCursor(getMilliSeconds(), GHOST_kEventCursorMove, window, x_root + x_accum, - y_root + y_accum); + y_root + y_accum, + GHOST_TABLET_DATA_NONE); } } else #endif { - g_event = new GHOST_EventCursor( - getMilliSeconds(), GHOST_kEventCursorMove, window, x_root, y_root); + g_event = new GHOST_EventCursor(getMilliSeconds(), + GHOST_kEventCursorMove, + window, + x_root, + y_root, + GHOST_TABLET_DATA_NONE); } break; } @@ -435,7 +444,8 @@ void GHOST_SystemSDL::processEvent(SDL_Event *sdl_event) else break; - g_event = new GHOST_EventButton(getMilliSeconds(), type, window, gbmask); + g_event = new GHOST_EventButton( + getMilliSeconds(), type, window, gbmask, GHOST_TABLET_DATA_NONE); break; } case SDL_MOUSEWHEEL: { diff --git a/intern/ghost/intern/GHOST_SystemWin32.cpp b/intern/ghost/intern/GHOST_SystemWin32.cpp index 9149d81e32e..25a825dbb6a 100644 --- a/intern/ghost/intern/GHOST_SystemWin32.cpp +++ b/intern/ghost/intern/GHOST_SystemWin32.cpp @@ -911,7 +911,8 @@ GHOST_EventButton *GHOST_SystemWin32::processButtonEvent(GHOST_TEventType type, if (window->useTabletAPI(GHOST_kTabletNative)) { window->setTabletData(NULL); } - return new GHOST_EventButton(system->getMilliSeconds(), type, window, mask); + return new GHOST_EventButton( + system->getMilliSeconds(), type, window, mask, window->getTabletData()); } GHOST_Event *GHOST_SystemWin32::processPointerEvent(GHOST_TEventType type, @@ -943,21 +944,27 @@ GHOST_Event *GHOST_SystemWin32::processPointerEvent(GHOST_TEventType type, /* Update window tablet data to be included in event. */ window->setTabletData(&pointerInfo.tabletData); eventHandled = true; - return new GHOST_EventButton( - system->getMilliSeconds(), GHOST_kEventButtonDown, window, pointerInfo.buttonMask); + return new GHOST_EventButton(system->getMilliSeconds(), + GHOST_kEventButtonDown, + window, + pointerInfo.buttonMask, + pointerInfo.tabletData); case GHOST_kEventButtonUp: eventHandled = true; - return new GHOST_EventButton( - system->getMilliSeconds(), GHOST_kEventButtonUp, window, pointerInfo.buttonMask); + return new GHOST_EventButton(system->getMilliSeconds(), + GHOST_kEventButtonUp, + window, + pointerInfo.buttonMask, + window->getTabletData()); case GHOST_kEventCursorMove: /* Update window tablet data to be included in event. */ - window->setTabletData(&pointerInfo.tabletData); eventHandled = true; return new GHOST_EventCursor(system->getMilliSeconds(), GHOST_kEventCursorMove, window, pointerInfo.pixelLocation.x, - pointerInfo.pixelLocation.y); + pointerInfo.pixelLocation.y, + pointerInfo.tabletData); default: return NULL; } @@ -1001,12 +1008,17 @@ GHOST_EventCursor *GHOST_SystemWin32::processCursorEvent(GHOST_TEventType type, GHOST_kEventCursorMove, window, x_screen + x_accum, - y_screen + y_accum); + y_screen + y_accum, + window->getTabletData()); } } else { - return new GHOST_EventCursor( - system->getMilliSeconds(), GHOST_kEventCursorMove, window, x_screen, y_screen); + return new GHOST_EventCursor(system->getMilliSeconds(), + GHOST_kEventCursorMove, + window, + x_screen, + y_screen, + window->getTabletData()); } return NULL; } diff --git a/intern/ghost/intern/GHOST_SystemX11.cpp b/intern/ghost/intern/GHOST_SystemX11.cpp index f076fe4c94a..ca511073ea1 100644 --- a/intern/ghost/intern/GHOST_SystemX11.cpp +++ b/intern/ghost/intern/GHOST_SystemX11.cpp @@ -1000,12 +1000,17 @@ void GHOST_SystemX11::processEvent(XEvent *xe) GHOST_kEventCursorMove, window, xme.x_root + x_accum, - xme.y_root + y_accum); + xme.y_root + y_accum, + window->GetTabletData()); } } else { - g_event = new GHOST_EventCursor( - getMilliSeconds(), GHOST_kEventCursorMove, window, xme.x_root, xme.y_root); + g_event = new GHOST_EventCursor(getMilliSeconds(), + GHOST_kEventCursorMove, + window, + xme.x_root, + xme.y_root, + window->GetTabletData()); } break; } @@ -1272,7 +1277,8 @@ void GHOST_SystemX11::processEvent(XEvent *xe) else break; - g_event = new GHOST_EventButton(getMilliSeconds(), type, window, gbmask); + g_event = new GHOST_EventButton( + getMilliSeconds(), type, window, gbmask, window->GetTabletData()); break; } @@ -1373,8 +1379,12 @@ void GHOST_SystemX11::processEvent(XEvent *xe) */ XCrossingEvent &xce = xe->xcrossing; if (xce.mode == NotifyNormal) { - g_event = new GHOST_EventCursor( - getMilliSeconds(), GHOST_kEventCursorMove, window, xce.x_root, xce.y_root); + g_event = new GHOST_EventCursor(getMilliSeconds(), + GHOST_kEventCursorMove, + window, + xce.x_root, + xce.y_root, + window->GetTabletData()); } // printf("X: %s window %d\n", diff --git a/intern/ghost/intern/GHOST_WindowCocoa.h b/intern/ghost/intern/GHOST_WindowCocoa.h index a49949c2c8d..efa418deee2 100644 --- a/intern/ghost/intern/GHOST_WindowCocoa.h +++ b/intern/ghost/intern/GHOST_WindowCocoa.h @@ -222,11 +222,6 @@ class GHOST_WindowCocoa : public GHOST_Window { bool isDialog() const; - const GHOST_TabletData &GetTabletData() - { - return m_tablet; - } - GHOST_TabletData &GetCocoaTabletData() { return m_tablet; diff --git a/intern/ghost/intern/GHOST_WindowCocoa.mm b/intern/ghost/intern/GHOST_WindowCocoa.mm index c90b49c27a5..10ab05a0de1 100644 --- a/intern/ghost/intern/GHOST_WindowCocoa.mm +++ b/intern/ghost/intern/GHOST_WindowCocoa.mm @@ -395,7 +395,7 @@ GHOST_WindowCocoa::GHOST_WindowCocoa(GHOST_SystemCocoa *systemCocoa, setTitle(title); - m_tablet = GHOST_TABLET_DATA_DEFAULT; + m_tablet = GHOST_TABLET_DATA_NONE; CocoaWindowDelegate *windowDelegate = [[CocoaWindowDelegate alloc] init]; [windowDelegate setSystemAndWindowCocoa:systemCocoa windowCocoa:this]; diff --git a/intern/ghost/intern/GHOST_WindowWin32.cpp b/intern/ghost/intern/GHOST_WindowWin32.cpp index 6570f27ac5a..f1a4110995e 100644 --- a/intern/ghost/intern/GHOST_WindowWin32.cpp +++ b/intern/ghost/intern/GHOST_WindowWin32.cpp @@ -90,7 +90,7 @@ GHOST_WindowWin32::GHOST_WindowWin32(GHOST_SystemWin32 *system, { // Initialize tablet variables memset(&m_wintab, 0, sizeof(m_wintab)); - m_tabletData = GHOST_TABLET_DATA_DEFAULT; + m_tabletData = GHOST_TABLET_DATA_NONE; // Create window if (state != GHOST_kWindowStateFullScreen) { @@ -1101,7 +1101,7 @@ void GHOST_WindowWin32::setTabletData(GHOST_TabletData *pTabletData) m_tabletData = *pTabletData; } else { - m_tabletData = GHOST_TABLET_DATA_DEFAULT; + m_tabletData = GHOST_TABLET_DATA_NONE; } } diff --git a/intern/ghost/intern/GHOST_WindowX11.cpp b/intern/ghost/intern/GHOST_WindowX11.cpp index 3bece605d45..363a8145c5a 100644 --- a/intern/ghost/intern/GHOST_WindowX11.cpp +++ b/intern/ghost/intern/GHOST_WindowX11.cpp @@ -499,7 +499,7 @@ GHOST_WindowX11::GHOST_WindowX11(GHOST_SystemX11 *system, #ifdef WITH_X11_XINPUT refreshXInputDevices(); - m_tabletData = GHOST_TABLET_DATA_DEFAULT; + m_tabletData = GHOST_TABLET_DATA_NONE; #endif /* now set up the rendering context. */ -- cgit v1.2.3 From 4e4bf241c8a08d4f083e36eed9fe3938ef4301f2 Mon Sep 17 00:00:00 2001 From: Nicholas Rishel Date: Fri, 27 Mar 2020 18:02:03 +0100 Subject: Cleanup: add utility functions for milliseconds conversion Ref D6675 --- intern/ghost/intern/GHOST_SystemWin32.cpp | 26 +++++++++++++++++++------- intern/ghost/intern/GHOST_SystemWin32.h | 16 ++++++++++++++++ 2 files changed, 35 insertions(+), 7 deletions(-) diff --git a/intern/ghost/intern/GHOST_SystemWin32.cpp b/intern/ghost/intern/GHOST_SystemWin32.cpp index 25a825dbb6a..12226be10ab 100644 --- a/intern/ghost/intern/GHOST_SystemWin32.cpp +++ b/intern/ghost/intern/GHOST_SystemWin32.cpp @@ -184,7 +184,8 @@ typedef enum MONITOR_DPI_TYPE { typedef HRESULT(API *GHOST_WIN32_SetProcessDpiAwareness)(PROCESS_DPI_AWARENESS); typedef BOOL(API *GHOST_WIN32_EnableNonClientDpiScaling)(HWND); -GHOST_SystemWin32::GHOST_SystemWin32() : m_hasPerformanceCounter(false), m_freq(0), m_start(0) +GHOST_SystemWin32::GHOST_SystemWin32() + : m_hasPerformanceCounter(false), m_freq(0), m_start(0), m_lfstart(0) { m_displayManager = new GHOST_DisplayManagerWin32(); GHOST_ASSERT(m_displayManager, "GHOST_SystemWin32::GHOST_SystemWin32(): m_displayManager==0\n"); @@ -223,22 +224,32 @@ GHOST_SystemWin32::~GHOST_SystemWin32() toggleConsole(1); } +GHOST_TUns64 GHOST_SystemWin32::performanceCounterToMillis(__int64 perf_ticks) const +{ + // Calculate the time passed since system initialization. + __int64 delta = (perf_ticks - m_start) * 1000; + + GHOST_TUns64 t = (GHOST_TUns64)(delta / m_freq); + return t; +} + +GHOST_TUns64 GHOST_SystemWin32::tickCountToMillis(__int64 ticks) const +{ + return ticks - m_lfstart; +} + GHOST_TUns64 GHOST_SystemWin32::getMilliSeconds() const { // Hardware does not support high resolution timers. We will use GetTickCount instead then. if (!m_hasPerformanceCounter) { - return ::GetTickCount(); + return tickCountToMillis(::GetTickCount()); } // Retrieve current count __int64 count = 0; ::QueryPerformanceCounter((LARGE_INTEGER *)&count); - // Calculate the time passed since system initialization. - __int64 delta = 1000 * (count - m_start); - - GHOST_TUns64 t = (GHOST_TUns64)(delta / m_freq); - return t; + return performanceCounterToMillis(count); } GHOST_TUns8 GHOST_SystemWin32::getNumDisplays() const @@ -570,6 +581,7 @@ GHOST_TSuccess GHOST_SystemWin32::init() FreeLibrary(user32); initRawInput(); + m_lfstart = ::GetTickCount(); // Determine whether this system has a high frequency performance counter. */ m_hasPerformanceCounter = ::QueryPerformanceFrequency((LARGE_INTEGER *)&m_freq) == TRUE; if (m_hasPerformanceCounter) { diff --git a/intern/ghost/intern/GHOST_SystemWin32.h b/intern/ghost/intern/GHOST_SystemWin32.h index 27f23e00ae7..14ee1f38ecd 100644 --- a/intern/ghost/intern/GHOST_SystemWin32.h +++ b/intern/ghost/intern/GHOST_SystemWin32.h @@ -65,6 +65,20 @@ class GHOST_SystemWin32 : public GHOST_System { ** Time(r) functionality ***************************************************************************************/ + /** + * This method converts performance counter measurements into milliseconds since the start of the + * system process. + * \return The number of milliseconds since the start of the system process. + */ + GHOST_TUns64 performanceCounterToMillis(__int64 perf_ticks) const; + + /** + * This method converts system ticks into milliseconds since the start of the + * system process. + * \return The number of milliseconds since the start of the system process. + */ + GHOST_TUns64 tickCountToMillis(__int64 ticks) const; + /** * Returns the system time. * Returns the number of milliseconds since the start of the system process. @@ -426,6 +440,8 @@ class GHOST_SystemWin32 : public GHOST_System { __int64 m_freq; /** High frequency timer variable. */ __int64 m_start; + /** Low frequency timer variable. */ + __int64 m_lfstart; /** AltGr on current keyboard layout. */ bool m_hasAltGr; /** language identifier. */ -- cgit v1.2.3 From 3d8c57f4daec7c07eca78c0290131d8c02629889 Mon Sep 17 00:00:00 2001 From: Nicholas Rishel Date: Fri, 27 Mar 2020 17:21:43 +0100 Subject: Cleanup: minor refactoring of pointer event handling Ref D6675 --- intern/ghost/intern/GHOST_SystemWin32.cpp | 100 +++++++++++++----------------- intern/ghost/intern/GHOST_SystemWin32.h | 22 ++++--- intern/ghost/intern/GHOST_WindowWin32.cpp | 22 ++++--- intern/ghost/intern/GHOST_WindowWin32.h | 24 ++++--- 4 files changed, 86 insertions(+), 82 deletions(-) diff --git a/intern/ghost/intern/GHOST_SystemWin32.cpp b/intern/ghost/intern/GHOST_SystemWin32.cpp index 12226be10ab..ad53afd9555 100644 --- a/intern/ghost/intern/GHOST_SystemWin32.cpp +++ b/intern/ghost/intern/GHOST_SystemWin32.cpp @@ -920,6 +920,14 @@ GHOST_EventButton *GHOST_SystemWin32::processButtonEvent(GHOST_TEventType type, GHOST_TButtonMask mask) { GHOST_SystemWin32 *system = (GHOST_SystemWin32 *)getSystem(); + + if (type == GHOST_kEventButtonDown) { + window->updateMouseCapture(MousePressed); + } + else if (type == GHOST_kEventButtonUp) { + window->updateMouseCapture(MouseReleased); + } + if (window->useTabletAPI(GHOST_kTabletNative)) { window->setTabletData(NULL); } @@ -927,63 +935,63 @@ GHOST_EventButton *GHOST_SystemWin32::processButtonEvent(GHOST_TEventType type, system->getMilliSeconds(), type, window, mask, window->getTabletData()); } -GHOST_Event *GHOST_SystemWin32::processPointerEvent(GHOST_TEventType type, - GHOST_WindowWin32 *window, - WPARAM wParam, - LPARAM lParam, - bool &eventHandled) +void GHOST_SystemWin32::processPointerEvents( + UINT type, GHOST_WindowWin32 *window, WPARAM wParam, LPARAM lParam, bool &eventHandled) { GHOST_PointerInfoWin32 pointerInfo; GHOST_SystemWin32 *system = (GHOST_SystemWin32 *)getSystem(); if (!window->useTabletAPI(GHOST_kTabletNative)) { - return NULL; + return; } if (window->getPointerInfo(&pointerInfo, wParam, lParam) != GHOST_kSuccess) { - return NULL; + return; } if (!pointerInfo.isPrimary) { eventHandled = true; - return NULL; // For multi-touch displays we ignore these events + return; // For multi-touch displays we ignore these events } system->setCursorPosition(pointerInfo.pixelLocation.x, pointerInfo.pixelLocation.y); switch (type) { - case GHOST_kEventButtonDown: + case WM_POINTERDOWN: /* Update window tablet data to be included in event. */ window->setTabletData(&pointerInfo.tabletData); - eventHandled = true; - return new GHOST_EventButton(system->getMilliSeconds(), - GHOST_kEventButtonDown, - window, - pointerInfo.buttonMask, - pointerInfo.tabletData); - case GHOST_kEventButtonUp: - eventHandled = true; - return new GHOST_EventButton(system->getMilliSeconds(), - GHOST_kEventButtonUp, - window, - pointerInfo.buttonMask, - window->getTabletData()); - case GHOST_kEventCursorMove: + system->pushEvent(new GHOST_EventButton(system->getMilliSeconds(), + GHOST_kEventButtonDown, + window, + pointerInfo.buttonMask, + pointerInfo.tabletData)); + window->updateMouseCapture(MousePressed); + break; + case WM_POINTERUPDATE: /* Update window tablet data to be included in event. */ - eventHandled = true; - return new GHOST_EventCursor(system->getMilliSeconds(), - GHOST_kEventCursorMove, - window, - pointerInfo.pixelLocation.x, - pointerInfo.pixelLocation.y, - pointerInfo.tabletData); + system->pushEvent(GHOST_EventCursor(system->getMilliSeconds(), + GHOST_kEventCursorMove, + window, + pointerInfo.pixelLocation.x, + pointerInfo.pixelLocation.y, + pointerInfo.tabletData)); + break; + case WM_POINTERUP: + system->pushEvent(new GHOST_EventButton(system->getMilliSeconds(), + GHOST_kEventButtonUp, + window, + pointerInfo.buttonMask, + window->getTabletData())); + window->updateMouseCapture(MouseReleased); + break; default: - return NULL; + break; } + + eventHandled = true; } -GHOST_EventCursor *GHOST_SystemWin32::processCursorEvent(GHOST_TEventType type, - GHOST_WindowWin32 *window) +GHOST_EventCursor *GHOST_SystemWin32::processCursorEvent(GHOST_WindowWin32 *window) { GHOST_TInt32 x_screen, y_screen; GHOST_SystemWin32 *system = (GHOST_SystemWin32 *)getSystem(); @@ -1417,39 +1425,23 @@ LRESULT WINAPI GHOST_SystemWin32::s_wndProc(HWND hwnd, UINT msg, WPARAM wParam, // Pointer events, processed //////////////////////////////////////////////////////////////////////// case WM_POINTERDOWN: - event = processPointerEvent( - GHOST_kEventButtonDown, window, wParam, lParam, eventHandled); - if (event && eventHandled) { - window->registerMouseClickEvent(0); - } - break; - case WM_POINTERUP: - event = processPointerEvent(GHOST_kEventButtonUp, window, wParam, lParam, eventHandled); - if (event && eventHandled) { - window->registerMouseClickEvent(1); - } - break; case WM_POINTERUPDATE: - event = processPointerEvent( - GHOST_kEventCursorMove, window, wParam, lParam, eventHandled); + case WM_POINTERUP: + processPointerEvents(msg, window, wParam, lParam, eventHandled); break; //////////////////////////////////////////////////////////////////////// // Mouse events, processed //////////////////////////////////////////////////////////////////////// case WM_LBUTTONDOWN: - window->registerMouseClickEvent(0); event = processButtonEvent(GHOST_kEventButtonDown, window, GHOST_kButtonMaskLeft); break; case WM_MBUTTONDOWN: - window->registerMouseClickEvent(0); event = processButtonEvent(GHOST_kEventButtonDown, window, GHOST_kButtonMaskMiddle); break; case WM_RBUTTONDOWN: - window->registerMouseClickEvent(0); event = processButtonEvent(GHOST_kEventButtonDown, window, GHOST_kButtonMaskRight); break; case WM_XBUTTONDOWN: - window->registerMouseClickEvent(0); if ((short)HIWORD(wParam) == XBUTTON1) { event = processButtonEvent(GHOST_kEventButtonDown, window, GHOST_kButtonMaskButton4); } @@ -1458,19 +1450,15 @@ LRESULT WINAPI GHOST_SystemWin32::s_wndProc(HWND hwnd, UINT msg, WPARAM wParam, } break; case WM_LBUTTONUP: - window->registerMouseClickEvent(1); event = processButtonEvent(GHOST_kEventButtonUp, window, GHOST_kButtonMaskLeft); break; case WM_MBUTTONUP: - window->registerMouseClickEvent(1); event = processButtonEvent(GHOST_kEventButtonUp, window, GHOST_kButtonMaskMiddle); break; case WM_RBUTTONUP: - window->registerMouseClickEvent(1); event = processButtonEvent(GHOST_kEventButtonUp, window, GHOST_kButtonMaskRight); break; case WM_XBUTTONUP: - window->registerMouseClickEvent(1); if ((short)HIWORD(wParam) == XBUTTON1) { event = processButtonEvent(GHOST_kEventButtonUp, window, GHOST_kButtonMaskButton4); } @@ -1479,7 +1467,7 @@ LRESULT WINAPI GHOST_SystemWin32::s_wndProc(HWND hwnd, UINT msg, WPARAM wParam, } break; case WM_MOUSEMOVE: - event = processCursorEvent(GHOST_kEventCursorMove, window); + event = processCursorEvent(window); break; case WM_MOUSEWHEEL: { /* The WM_MOUSEWHEEL message is sent to the focus window diff --git a/intern/ghost/intern/GHOST_SystemWin32.h b/intern/ghost/intern/GHOST_SystemWin32.h index 14ee1f38ecd..c6d810d2a38 100644 --- a/intern/ghost/intern/GHOST_SystemWin32.h +++ b/intern/ghost/intern/GHOST_SystemWin32.h @@ -310,27 +310,29 @@ class GHOST_SystemWin32 : public GHOST_System { GHOST_TButtonMask mask); /** - * Creates pointer event. - * \param type The type of event to create. + * Creates tablet events from Wintab events. + * \param type The type of pointer event + * \param window The window receiving the event (the active window). + */ + static GHOST_TSuccess processWintabEvents(GHOST_TEventType type, GHOST_WindowWin32 *window); + + /** + * Creates tablet events from pointer events. + * \param type The type of pointer event * \param window The window receiving the event (the active window). * \param wParam The wParam from the wndproc * \param lParam The lParam from the wndproc * \param eventhandled true if the method handled the event - * \return The event created. */ - static GHOST_Event *processPointerEvent(GHOST_TEventType type, - GHOST_WindowWin32 *window, - WPARAM wParam, - LPARAM lParam, - bool &eventhandled); + static void processPointerEvents( + UINT type, GHOST_WindowWin32 *window, WPARAM wParam, LPARAM lParam, bool &eventhandled); /** * Creates cursor event. - * \param type The type of event to create. * \param window The window receiving the event (the active window). * \return The event created. */ - static GHOST_EventCursor *processCursorEvent(GHOST_TEventType type, GHOST_WindowWin32 *window); + static GHOST_EventCursor *processCursorEvent(GHOST_WindowWin32 *window); /** * Handles a mouse wheel event. diff --git a/intern/ghost/intern/GHOST_WindowWin32.cpp b/intern/ghost/intern/GHOST_WindowWin32.cpp index f1a4110995e..9d957da61cd 100644 --- a/intern/ghost/intern/GHOST_WindowWin32.cpp +++ b/intern/ghost/intern/GHOST_WindowWin32.cpp @@ -785,21 +785,20 @@ bool GHOST_WindowWin32::isDialog() const return (parent != 0) && (style & WS_POPUPWINDOW); } -void GHOST_WindowWin32::registerMouseClickEvent(int press) +void GHOST_WindowWin32::updateMouseCapture(GHOST_MouseCaptureEventWin32 event) { - - switch (press) { - case 0: + switch (event) { + case MousePressed: m_nPressedButtons++; break; - case 1: + case MouseReleased: if (m_nPressedButtons) m_nPressedButtons--; break; - case 2: + case OperatorGrab: m_hasGrabMouse = true; break; - case 3: + case OperatorUngrab: m_hasGrabMouse = false; break; } @@ -814,6 +813,11 @@ void GHOST_WindowWin32::registerMouseClickEvent(int press) } } +bool GHOST_WindowWin32::getMousePressed() const +{ + return m_nPressedButtons; +} + HCURSOR GHOST_WindowWin32::getStandardCursor(GHOST_TStandardCursor shape) const { // Convert GHOST cursor to Windows OEM cursor @@ -977,7 +981,7 @@ GHOST_TSuccess GHOST_WindowWin32::setWindowCursorGrab(GHOST_TGrabCursorMode mode if (mode == GHOST_kGrabHide) setWindowCursorVisibility(false); } - registerMouseClickEvent(2); + updateMouseCapture(OperatorGrab); } else { if (m_cursorGrab == GHOST_kGrabHide) { @@ -997,7 +1001,7 @@ GHOST_TSuccess GHOST_WindowWin32::setWindowCursorGrab(GHOST_TGrabCursorMode mode * can be incorrect on exit. */ setCursorGrabAccum(0, 0); m_cursorGrabBounds.m_l = m_cursorGrabBounds.m_r = -1; /* disable */ - registerMouseClickEvent(3); + updateMouseCapture(OperatorUngrab); } return GHOST_kSuccess; diff --git a/intern/ghost/intern/GHOST_WindowWin32.h b/intern/ghost/intern/GHOST_WindowWin32.h index ac1ec0ee852..fad8813c5d0 100644 --- a/intern/ghost/intern/GHOST_WindowWin32.h +++ b/intern/ghost/intern/GHOST_WindowWin32.h @@ -206,6 +206,13 @@ struct GHOST_PointerInfoWin32 { GHOST_TabletData tabletData; }; +typedef enum { + MousePressed, + MouseReleased, + OperatorGrab, + OperatorUngrab +} GHOST_MouseCaptureEventWin32; + /** * GHOST window on M$ Windows OSs. */ @@ -364,17 +371,14 @@ class GHOST_WindowWin32 : public GHOST_Window { GHOST_TSuccess endProgressBar(); /** - * Register a mouse click event (should be called + * Register a mouse capture state (should be called * for any real button press, controls mouse * capturing). * - * \param press - * 0 - mouse pressed - * 1 - mouse released - * 2 - operator grab - * 3 - operator ungrab + * \param event Whether mouse was pressed and released, or an operator grabbed or ungrabbed the + * mouse */ - void registerMouseClickEvent(int press); + void updateMouseCapture(GHOST_MouseCaptureEventWin32 event); /** * Inform the window that it has lost mouse capture, @@ -419,6 +423,12 @@ class GHOST_WindowWin32 : public GHOST_Window { GHOST_TUns16 getDPIHint() override; + /** + * Get whether there are currently any mouse buttons pressed + * \return True if there are any currently pressed mouse buttons + */ + bool getMousePressed() const; + GHOST_TSuccess getPointerInfo(GHOST_PointerInfoWin32 *pointerInfo, WPARAM wParam, LPARAM lParam); /** if the window currently resizing */ -- cgit v1.2.3 From d571d615a59a40f1d313121cf07fe6e17461e8f0 Mon Sep 17 00:00:00 2001 From: Nicholas Rishel Date: Fri, 27 Mar 2020 18:31:09 +0100 Subject: Windows: support high resolution tablet pen events for Windows Ink Rather than using the last state of the tablet, we now query the history of pointer events so strokes can follow the pen even if Blender does not handle events at the same rate. Differential Revision: https://developer.blender.org/D6675 --- intern/ghost/GHOST_Types.h | 2 +- intern/ghost/intern/GHOST_SystemWin32.cpp | 104 +++++++++++++++------- intern/ghost/intern/GHOST_WindowWin32.cpp | 140 ++++++++++++++++-------------- intern/ghost/intern/GHOST_WindowWin32.h | 57 +++++++++--- 4 files changed, 195 insertions(+), 108 deletions(-) diff --git a/intern/ghost/GHOST_Types.h b/intern/ghost/GHOST_Types.h index 8126c2299c6..b8de31df6c6 100644 --- a/intern/ghost/GHOST_Types.h +++ b/intern/ghost/GHOST_Types.h @@ -118,7 +118,7 @@ typedef struct GHOST_TabletData { } GHOST_TabletData; static const GHOST_TabletData GHOST_TABLET_DATA_NONE = { - GHOST_kTabletModeNone, /* No tablet connected. */ + GHOST_kTabletModeNone, /* No cursor in range */ 1.0f, /* Pressure */ 0.0f, /* Xtilt */ 0.0f}; /* Ytilt */ diff --git a/intern/ghost/intern/GHOST_SystemWin32.cpp b/intern/ghost/intern/GHOST_SystemWin32.cpp index ad53afd9555..fdd022e44ac 100644 --- a/intern/ghost/intern/GHOST_SystemWin32.cpp +++ b/intern/ghost/intern/GHOST_SystemWin32.cpp @@ -115,12 +115,22 @@ # define WM_DPICHANGED 0x02E0 #endif // WM_DPICHANGED +// WM_POINTER API messages minimum Windows 7 +#ifndef WM_POINTERENTER +# define WM_POINTERENTER 0x0249 +#endif // WM_POINTERENTER +#ifndef WM_POINTERDOWN +# define WM_POINTERDOWN 0x0246 +#endif // WM_POINTERDOWN #ifndef WM_POINTERUPDATE # define WM_POINTERUPDATE 0x0245 #endif // WM_POINTERUPDATE - -#define WM_POINTERDOWN 0x0246 -#define WM_POINTERUP 0x0247 +#ifndef WM_POINTERUP +# define WM_POINTERUP 0x0247 +#endif // WM_POINTERUP +#ifndef WM_POINTERLEAVE +# define WM_POINTERLEAVE 0x024A +#endif // WM_POINTERLEAVE /* Workaround for some laptop touchpads, some of which seems to * have driver issues which makes it so window function receives @@ -928,9 +938,13 @@ GHOST_EventButton *GHOST_SystemWin32::processButtonEvent(GHOST_TEventType type, window->updateMouseCapture(MouseReleased); } - if (window->useTabletAPI(GHOST_kTabletNative)) { - window->setTabletData(NULL); + if (window->m_tabletInRange) { + if (window->useTabletAPI(GHOST_kTabletNative)) { + // Win32 Pointer processing handles input while in-range and in-contact events. + return NULL; + } } + return new GHOST_EventButton( system->getMilliSeconds(), type, window, mask, window->getTabletData()); } @@ -938,57 +952,81 @@ GHOST_EventButton *GHOST_SystemWin32::processButtonEvent(GHOST_TEventType type, void GHOST_SystemWin32::processPointerEvents( UINT type, GHOST_WindowWin32 *window, WPARAM wParam, LPARAM lParam, bool &eventHandled) { - GHOST_PointerInfoWin32 pointerInfo; + std::vector pointerInfo; GHOST_SystemWin32 *system = (GHOST_SystemWin32 *)getSystem(); if (!window->useTabletAPI(GHOST_kTabletNative)) { return; } - if (window->getPointerInfo(&pointerInfo, wParam, lParam) != GHOST_kSuccess) { + if (window->getPointerInfo(pointerInfo, wParam, lParam) != GHOST_kSuccess) { return; } - if (!pointerInfo.isPrimary) { + if (!pointerInfo[0].isPrimary) { eventHandled = true; return; // For multi-touch displays we ignore these events } - system->setCursorPosition(pointerInfo.pixelLocation.x, pointerInfo.pixelLocation.y); - switch (type) { + case WM_POINTERENTER: + window->m_tabletInRange = true; + system->pushEvent(new GHOST_EventCursor(pointerInfo[0].time, + GHOST_kEventCursorMove, + window, + pointerInfo[0].pixelLocation.x, + pointerInfo[0].pixelLocation.y, + pointerInfo[0].tabletData)); + break; case WM_POINTERDOWN: - /* Update window tablet data to be included in event. */ - window->setTabletData(&pointerInfo.tabletData); - system->pushEvent(new GHOST_EventButton(system->getMilliSeconds(), + // Move cursor to point of contact because GHOST_EventButton does not include position. + system->pushEvent(new GHOST_EventCursor(pointerInfo[0].time, + GHOST_kEventCursorMove, + window, + pointerInfo[0].pixelLocation.x, + pointerInfo[0].pixelLocation.y, + pointerInfo[0].tabletData)); + system->pushEvent(new GHOST_EventButton(pointerInfo[0].time, GHOST_kEventButtonDown, window, - pointerInfo.buttonMask, - pointerInfo.tabletData)); + pointerInfo[0].buttonMask, + pointerInfo[0].tabletData)); window->updateMouseCapture(MousePressed); break; case WM_POINTERUPDATE: - /* Update window tablet data to be included in event. */ - system->pushEvent(GHOST_EventCursor(system->getMilliSeconds(), - GHOST_kEventCursorMove, - window, - pointerInfo.pixelLocation.x, - pointerInfo.pixelLocation.y, - pointerInfo.tabletData)); + // Coalesced pointer events are reverse chronological order, reorder chronologically. + // Only contiguous move events are coalesced. + for (GHOST_TUns32 i = pointerInfo.size(); i-- > 0;) { + system->pushEvent(new GHOST_EventCursor(pointerInfo[i].time, + GHOST_kEventCursorMove, + window, + pointerInfo[i].pixelLocation.x, + pointerInfo[i].pixelLocation.y, + pointerInfo[i].tabletData)); + } break; case WM_POINTERUP: - system->pushEvent(new GHOST_EventButton(system->getMilliSeconds(), + system->pushEvent(new GHOST_EventButton(pointerInfo[0].time, GHOST_kEventButtonUp, window, - pointerInfo.buttonMask, - window->getTabletData())); + pointerInfo[0].buttonMask, + pointerInfo[0].tabletData)); window->updateMouseCapture(MouseReleased); break; + case WM_POINTERLEAVE: + window->m_tabletInRange = false; + system->pushEvent(new GHOST_EventButton(pointerInfo[0].time, + GHOST_kEventCursorMove, + window, + pointerInfo[0].buttonMask, + pointerInfo[0].tabletData)); + break; default: break; } eventHandled = true; + system->setCursorPosition(pointerInfo[0].pixelLocation.x, pointerInfo[0].pixelLocation.y); } GHOST_EventCursor *GHOST_SystemWin32::processCursorEvent(GHOST_WindowWin32 *window) @@ -996,12 +1034,18 @@ GHOST_EventCursor *GHOST_SystemWin32::processCursorEvent(GHOST_WindowWin32 *wind GHOST_TInt32 x_screen, y_screen; GHOST_SystemWin32 *system = (GHOST_SystemWin32 *)getSystem(); - system->getCursorPosition(x_screen, y_screen); + if (window->m_tabletInRange) { + if (window->useTabletAPI(GHOST_kTabletNative)) { + // Tablet input handled in WM_POINTER* events. WM_MOUSEMOVE events in response to tablet + // input aren't normally generated when using WM_POINTER events, but manually moving the + // system cursor as we do in WM_POINTER handling does. + return NULL; + } + } - /* TODO: CHECK IF THIS IS A TABLET EVENT */ - bool is_tablet = false; + system->getCursorPosition(x_screen, y_screen); - if (is_tablet == false && window->getCursorGrabModeIsWarp()) { + if (window->getCursorGrabModeIsWarp() && !window->m_tabletInRange) { GHOST_TInt32 x_new = x_screen; GHOST_TInt32 y_new = y_screen; GHOST_TInt32 x_accum, y_accum; @@ -1424,9 +1468,11 @@ LRESULT WINAPI GHOST_SystemWin32::s_wndProc(HWND hwnd, UINT msg, WPARAM wParam, //////////////////////////////////////////////////////////////////////// // Pointer events, processed //////////////////////////////////////////////////////////////////////// + case WM_POINTERENTER: case WM_POINTERDOWN: case WM_POINTERUPDATE: case WM_POINTERUP: + case WM_POINTERLEAVE: processPointerEvents(msg, window, wParam, lParam, eventHandled); break; //////////////////////////////////////////////////////////////////////// diff --git a/intern/ghost/intern/GHOST_WindowWin32.cpp b/intern/ghost/intern/GHOST_WindowWin32.cpp index 9d957da61cd..b0ba7b6befb 100644 --- a/intern/ghost/intern/GHOST_WindowWin32.cpp +++ b/intern/ghost/intern/GHOST_WindowWin32.cpp @@ -82,11 +82,12 @@ GHOST_WindowWin32::GHOST_WindowWin32(GHOST_SystemWin32 *system, m_wantAlphaBackground(alphaBackground), m_normal_state(GHOST_kWindowStateNormal), m_user32(NULL), - m_fpGetPointerInfo(NULL), - m_fpGetPointerPenInfo(NULL), - m_fpGetPointerTouchInfo(NULL), + m_fpGetPointerInfoHistory(NULL), + m_fpGetPointerPenInfoHistory(NULL), + m_fpGetPointerTouchInfoHistory(NULL), m_parentWindowHwnd(parentwindow ? parentwindow->m_hWnd : NULL), - m_debug_context(is_debug) + m_debug_context(is_debug), + m_tabletInRange(false) { // Initialize tablet variables memset(&m_wintab, 0, sizeof(m_wintab)); @@ -288,11 +289,12 @@ GHOST_WindowWin32::GHOST_WindowWin32(GHOST_SystemWin32 *system, // Initialize Windows Ink if (m_user32) { - m_fpGetPointerInfo = (GHOST_WIN32_GetPointerInfo)::GetProcAddress(m_user32, "GetPointerInfo"); - m_fpGetPointerPenInfo = (GHOST_WIN32_GetPointerPenInfo)::GetProcAddress(m_user32, - "GetPointerPenInfo"); - m_fpGetPointerTouchInfo = (GHOST_WIN32_GetPointerTouchInfo)::GetProcAddress( - m_user32, "GetPointerTouchInfo"); + m_fpGetPointerInfoHistory = (GHOST_WIN32_GetPointerInfoHistory)::GetProcAddress( + m_user32, "GetPointerInfoHistory"); + m_fpGetPointerPenInfoHistory = (GHOST_WIN32_GetPointerPenInfoHistory)::GetProcAddress( + m_user32, "GetPointerPenInfoHistory"); + m_fpGetPointerTouchInfoHistory = (GHOST_WIN32_GetPointerTouchInfoHistory)::GetProcAddress( + m_user32, "GetPointerTouchInfoHistory"); } // Initialize Wintab @@ -379,9 +381,9 @@ GHOST_WindowWin32::~GHOST_WindowWin32() if (m_user32) { FreeLibrary(m_user32); m_user32 = NULL; - m_fpGetPointerInfo = NULL; - m_fpGetPointerPenInfo = NULL; - m_fpGetPointerTouchInfo = NULL; + m_fpGetPointerInfoHistory = NULL; + m_fpGetPointerPenInfoHistory = NULL; + m_fpGetPointerTouchInfoHistory = NULL; } if (m_customCursor) { @@ -1021,78 +1023,82 @@ GHOST_TSuccess GHOST_WindowWin32::hasCursorShape(GHOST_TStandardCursor cursorSha return (getStandardCursor(cursorShape)) ? GHOST_kSuccess : GHOST_kFailure; } -GHOST_TSuccess GHOST_WindowWin32::getPointerInfo(GHOST_PointerInfoWin32 *pointerInfo, - WPARAM wParam, - LPARAM lParam) +GHOST_TSuccess GHOST_WindowWin32::getPointerInfo( + std::vector &outPointerInfo, WPARAM wParam, LPARAM lParam) { - ZeroMemory(pointerInfo, sizeof(GHOST_PointerInfoWin32)); - - // Obtain the basic information from the event - pointerInfo->pointerId = GET_POINTERID_WPARAM(wParam); - pointerInfo->isInContact = IS_POINTER_INCONTACT_WPARAM(wParam); - pointerInfo->isPrimary = IS_POINTER_PRIMARY_WPARAM(wParam); - - // Obtain more accurate and predicted information from the Pointer API - POINTER_INFO pointerApiInfo; - if (!(m_fpGetPointerInfo && m_fpGetPointerInfo(pointerInfo->pointerId, &pointerApiInfo))) { + if (!useTabletAPI(GHOST_kTabletNative)) { return GHOST_kFailure; } - pointerInfo->hasButtonMask = GHOST_kSuccess; - switch (pointerApiInfo.ButtonChangeType) { - case POINTER_CHANGE_FIRSTBUTTON_DOWN: - case POINTER_CHANGE_FIRSTBUTTON_UP: - pointerInfo->buttonMask = GHOST_kButtonMaskLeft; - break; - case POINTER_CHANGE_SECONDBUTTON_DOWN: - case POINTER_CHANGE_SECONDBUTTON_UP: - pointerInfo->buttonMask = GHOST_kButtonMaskRight; - break; - case POINTER_CHANGE_THIRDBUTTON_DOWN: - case POINTER_CHANGE_THIRDBUTTON_UP: - pointerInfo->buttonMask = GHOST_kButtonMaskMiddle; - break; - case POINTER_CHANGE_FOURTHBUTTON_DOWN: - case POINTER_CHANGE_FOURTHBUTTON_UP: - pointerInfo->buttonMask = GHOST_kButtonMaskButton4; - break; - case POINTER_CHANGE_FIFTHBUTTON_DOWN: - case POINTER_CHANGE_FIFTHBUTTON_UP: - pointerInfo->buttonMask = GHOST_kButtonMaskButton5; - break; - default: - pointerInfo->hasButtonMask = GHOST_kFailure; - break; + GHOST_TInt32 pointerId = GET_POINTERID_WPARAM(wParam); + GHOST_TInt32 isPrimary = IS_POINTER_PRIMARY_WPARAM(wParam); + GHOST_SystemWin32 *system = (GHOST_SystemWin32 *)GHOST_System::getSystem(); + GHOST_TUns32 outCount; + + if (!(m_fpGetPointerInfoHistory && m_fpGetPointerInfoHistory(pointerId, &outCount, NULL))) { + return GHOST_kFailure; } - pointerInfo->pixelLocation = pointerApiInfo.ptPixelLocation; - pointerInfo->tabletData.Active = GHOST_kTabletModeNone; - pointerInfo->tabletData.Pressure = 1.0f; - pointerInfo->tabletData.Xtilt = 0.0f; - pointerInfo->tabletData.Ytilt = 0.0f; + auto pointerPenInfo = std::vector(outCount); + outPointerInfo.resize(outCount); - if (pointerApiInfo.pointerType != PT_PEN) { + if (!(m_fpGetPointerPenInfoHistory && + m_fpGetPointerPenInfoHistory(pointerId, &outCount, pointerPenInfo.data()))) { return GHOST_kFailure; } - POINTER_PEN_INFO pointerPenInfo; - if (m_fpGetPointerPenInfo && m_fpGetPointerPenInfo(pointerInfo->pointerId, &pointerPenInfo)) { - pointerInfo->tabletData.Active = GHOST_kTabletModeStylus; + for (GHOST_TUns32 i = 0; i < outCount; i++) { + POINTER_INFO pointerApiInfo = pointerPenInfo[i].pointerInfo; + // Obtain the basic information from the event + outPointerInfo[i].pointerId = pointerId; + outPointerInfo[i].isPrimary = isPrimary; + + switch (pointerApiInfo.ButtonChangeType) { + case POINTER_CHANGE_FIRSTBUTTON_DOWN: + case POINTER_CHANGE_FIRSTBUTTON_UP: + outPointerInfo[i].buttonMask = GHOST_kButtonMaskLeft; + break; + case POINTER_CHANGE_SECONDBUTTON_DOWN: + case POINTER_CHANGE_SECONDBUTTON_UP: + outPointerInfo[i].buttonMask = GHOST_kButtonMaskRight; + break; + case POINTER_CHANGE_THIRDBUTTON_DOWN: + case POINTER_CHANGE_THIRDBUTTON_UP: + outPointerInfo[i].buttonMask = GHOST_kButtonMaskMiddle; + break; + case POINTER_CHANGE_FOURTHBUTTON_DOWN: + case POINTER_CHANGE_FOURTHBUTTON_UP: + outPointerInfo[i].buttonMask = GHOST_kButtonMaskButton4; + break; + case POINTER_CHANGE_FIFTHBUTTON_DOWN: + case POINTER_CHANGE_FIFTHBUTTON_UP: + outPointerInfo[i].buttonMask = GHOST_kButtonMaskButton5; + break; + default: + break; + } + + outPointerInfo[i].pixelLocation = pointerApiInfo.ptPixelLocation; + outPointerInfo[i].tabletData.Active = GHOST_kTabletModeStylus; + outPointerInfo[i].tabletData.Pressure = 1.0f; + outPointerInfo[i].tabletData.Xtilt = 0.0f; + outPointerInfo[i].tabletData.Ytilt = 0.0f; + outPointerInfo[i].time = system->performanceCounterToMillis(pointerApiInfo.PerformanceCount); - if (pointerPenInfo.penMask & PEN_MASK_PRESSURE) { - pointerInfo->tabletData.Pressure = pointerPenInfo.pressure / 1024.0f; + if (pointerPenInfo[i].penMask & PEN_MASK_PRESSURE) { + outPointerInfo[i].tabletData.Pressure = pointerPenInfo[i].pressure / 1024.0f; } - if (pointerPenInfo.penFlags & PEN_FLAG_ERASER) { - pointerInfo->tabletData.Active = GHOST_kTabletModeEraser; + if (pointerPenInfo[i].penFlags & PEN_FLAG_ERASER) { + outPointerInfo[i].tabletData.Active = GHOST_kTabletModeEraser; } - if (pointerPenInfo.penFlags & PEN_MASK_TILT_X) { - pointerInfo->tabletData.Xtilt = fmin(fabs(pointerPenInfo.tiltX / 90), 1.0f); + if (pointerPenInfo[i].penMask & PEN_MASK_TILT_X) { + outPointerInfo[i].tabletData.Xtilt = fmin(fabs(pointerPenInfo[i].tiltX / 90.0f), 1.0f); } - if (pointerPenInfo.penFlags & PEN_MASK_TILT_Y) { - pointerInfo->tabletData.Ytilt = fmin(fabs(pointerPenInfo.tiltY / 90), 1.0f); + if (pointerPenInfo[i].penMask & PEN_MASK_TILT_Y) { + outPointerInfo[i].tabletData.Ytilt = fmin(fabs(pointerPenInfo[i].tiltY / 90.0f), 1.0f); } } diff --git a/intern/ghost/intern/GHOST_WindowWin32.h b/intern/ghost/intern/GHOST_WindowWin32.h index fad8813c5d0..2951901ceb4 100644 --- a/intern/ghost/intern/GHOST_WindowWin32.h +++ b/intern/ghost/intern/GHOST_WindowWin32.h @@ -88,6 +88,26 @@ typedef enum tagPOINTER_BUTTON_CHANGE_TYPE { typedef DWORD POINTER_INPUT_TYPE; typedef UINT32 POINTER_FLAGS; +#define POINTER_FLAG_NONE 0x00000000 +#define POINTER_FLAG_NEW 0x00000001 +#define POINTER_FLAG_INRANGE 0x00000002 +#define POINTER_FLAG_INCONTACT 0x00000004 +#define POINTER_FLAG_FIRSTBUTTON 0x00000010 +#define POINTER_FLAG_SECONDBUTTON 0x00000020 +#define POINTER_FLAG_THIRDBUTTON 0x00000040 +#define POINTER_FLAG_FOURTHBUTTON 0x00000080 +#define POINTER_FLAG_FIFTHBUTTON 0x00000100 +#define POINTER_FLAG_PRIMARY 0x00002000 +#define POINTER_FLAG_CONFIDENCE 0x000004000 +#define POINTER_FLAG_CANCELED 0x000008000 +#define POINTER_FLAG_DOWN 0x00010000 +#define POINTER_FLAG_UPDATE 0x00020000 +#define POINTER_FLAG_UP 0x00040000 +#define POINTER_FLAG_WHEEL 0x00080000 +#define POINTER_FLAG_HWHEEL 0x00100000 +#define POINTER_FLAG_CAPTURECHANGED 0x00200000 +#define POINTER_FLAG_HASTRANSFORM 0x00400000 + typedef struct tagPOINTER_INFO { POINTER_INPUT_TYPE pointerType; UINT32 pointerId; @@ -192,17 +212,23 @@ typedef struct tagPOINTER_TOUCH_INFO { #define IS_POINTER_CANCELED_WPARAM(wParam) \ IS_POINTER_FLAG_SET_WPARAM(wParam, POINTER_MESSAGE_FLAG_CANCELED) -typedef BOOL(API *GHOST_WIN32_GetPointerInfo)(UINT32 pointerId, POINTER_INFO *pointerInfo); -typedef BOOL(API *GHOST_WIN32_GetPointerPenInfo)(UINT32 pointerId, POINTER_PEN_INFO *penInfo); -typedef BOOL(API *GHOST_WIN32_GetPointerTouchInfo)(UINT32 pointerId, POINTER_TOUCH_INFO *penInfo); +typedef BOOL(WINAPI *GHOST_WIN32_GetPointerInfoHistory)(UINT32 pointerId, + UINT32 *entriesCount, + POINTER_INFO *pointerInfo); +typedef BOOL(WINAPI *GHOST_WIN32_GetPointerPenInfoHistory)(UINT32 pointerId, + UINT32 *entriesCount, + POINTER_PEN_INFO *penInfo); +typedef BOOL(WINAPI *GHOST_WIN32_GetPointerTouchInfoHistory)(UINT32 pointerId, + UINT32 *entriesCount, + POINTER_TOUCH_INFO *touchInfo); struct GHOST_PointerInfoWin32 { GHOST_TInt32 pointerId; - GHOST_TInt32 isInContact; GHOST_TInt32 isPrimary; - GHOST_TSuccess hasButtonMask; GHOST_TButtonMask buttonMask; POINT pixelLocation; + GHOST_TUns64 time; + GHOST_TabletData tabletData; }; @@ -403,9 +429,17 @@ class GHOST_WindowWin32 : public GHOST_Window { void setTabletData(GHOST_TabletData *tabletData); bool useTabletAPI(GHOST_TTabletAPI api) const; - void getPointerInfo(WPARAM wParam); - void processWin32PointerEvent(WPARAM wParam); + /** + * Translate WM_POINTER events into GHOST_PointerInfoWin32 structs. + * \param outPointerInfo Storage to return resulting GHOST_PointerInfoWin32 structs + * \param wParam WPARAM of the event + * \param lParam LPARAM of the event + */ + GHOST_TSuccess getPointerInfo(std::vector &outPointerInfo, + WPARAM wParam, + LPARAM lParam); + void processWin32TabletActivateEvent(WORD state); void processWin32TabletInitEvent(); void processWin32TabletEvent(WPARAM wParam, LPARAM lParam); @@ -429,7 +463,8 @@ class GHOST_WindowWin32 : public GHOST_Window { */ bool getMousePressed() const; - GHOST_TSuccess getPointerInfo(GHOST_PointerInfoWin32 *pointerInfo, WPARAM wParam, LPARAM lParam); + /** Whether a tablet stylus is being tracked */ + bool m_tabletInRange; /** if the window currently resizing */ bool m_inLiveResize; @@ -537,9 +572,9 @@ class GHOST_WindowWin32 : public GHOST_Window { /** user32 dll handle*/ HMODULE m_user32; - GHOST_WIN32_GetPointerInfo m_fpGetPointerInfo; - GHOST_WIN32_GetPointerPenInfo m_fpGetPointerPenInfo; - GHOST_WIN32_GetPointerTouchInfo m_fpGetPointerTouchInfo; + GHOST_WIN32_GetPointerInfoHistory m_fpGetPointerInfoHistory; + GHOST_WIN32_GetPointerPenInfoHistory m_fpGetPointerPenInfoHistory; + GHOST_WIN32_GetPointerTouchInfoHistory m_fpGetPointerTouchInfoHistory; HWND m_parentWindowHwnd; -- cgit v1.2.3 From ea3e0b3e8cbcf2768f2e8316addf554e06b888ee Mon Sep 17 00:00:00 2001 From: Nicholas Rishel Date: Fri, 27 Mar 2020 17:03:28 +0100 Subject: Windows: support high resolution tablet pen events for Wintab Together with Windows Ink support, this should fully resolve T70765. Differential Revision: https://developer.blender.org/D6675 --- intern/ghost/intern/GHOST_System.h | 2 +- intern/ghost/intern/GHOST_SystemWin32.cpp | 148 +++++++++- intern/ghost/intern/GHOST_SystemWin32.h | 10 + intern/ghost/intern/GHOST_WindowWin32.cpp | 456 +++++++++++++++++++----------- intern/ghost/intern/GHOST_WindowWin32.h | 116 ++++++-- 5 files changed, 529 insertions(+), 203 deletions(-) diff --git a/intern/ghost/intern/GHOST_System.h b/intern/ghost/intern/GHOST_System.h index eaaa2ff6ee6..c404fe21e41 100644 --- a/intern/ghost/intern/GHOST_System.h +++ b/intern/ghost/intern/GHOST_System.h @@ -238,7 +238,7 @@ class GHOST_System : public GHOST_ISystem { * Set which tablet API to use. Only affects Windows, other platforms have a single API. * \param api Enum indicating which API to use. */ - void setTabletAPI(GHOST_TTabletAPI api); + virtual void setTabletAPI(GHOST_TTabletAPI api); GHOST_TTabletAPI getTabletAPI(void); #ifdef WITH_INPUT_NDOF diff --git a/intern/ghost/intern/GHOST_SystemWin32.cpp b/intern/ghost/intern/GHOST_SystemWin32.cpp index fdd022e44ac..b91792938d5 100644 --- a/intern/ghost/intern/GHOST_SystemWin32.cpp +++ b/intern/ghost/intern/GHOST_SystemWin32.cpp @@ -938,15 +938,100 @@ GHOST_EventButton *GHOST_SystemWin32::processButtonEvent(GHOST_TEventType type, window->updateMouseCapture(MouseReleased); } - if (window->m_tabletInRange) { - if (window->useTabletAPI(GHOST_kTabletNative)) { + /* Check for active Wintab mouse emulation in addition to a tablet in range because a proximity + * leave event might have fired before the Windows mouse up event, thus there are still tablet + * events to grab. The described behavior was observed in a Wacom Bamboo CTE-450. + */ + if (window->m_tabletInRange || window->wintabSysButPressed()) { + if (window->useTabletAPI(GHOST_kTabletWintab) && processWintabEvents(type, window)) { + // Wintab processing only handles in-contact events. + return NULL; + } + else if (window->useTabletAPI(GHOST_kTabletNative)) { // Win32 Pointer processing handles input while in-range and in-contact events. return NULL; } + + // If using Wintab and this was a button down event but no button event was queued while + // processing Wintab packets, fall through to create a button event. } return new GHOST_EventButton( - system->getMilliSeconds(), type, window, mask, window->getTabletData()); + system->getMilliSeconds(), type, window, mask, GHOST_TABLET_DATA_NONE); +} + +GHOST_TSuccess GHOST_SystemWin32::processWintabEvents(GHOST_TEventType type, + GHOST_WindowWin32 *window) +{ + GHOST_SystemWin32 *system = (GHOST_SystemWin32 *)getSystem(); + + /* Only process Wintab packets if we can correlate them to a Window's mouse button event. When a + * button event associated to a mouse button by Wintab occurs outside of WM_*BUTTON events, + * there's no way to tell if other simultaneously pressed non-mouse mapped buttons are associated + * to a modifier key (shift, alt, ctrl) or a system event (scroll, etc.) and thus it is not + * possible to determine if a mouse click event should occur. + */ + if (!window->getMousePressed() && !window->wintabSysButPressed()) { + return GHOST_kFailure; + } + + std::vector wintabInfo; + if (!window->getWintabInfo(wintabInfo)) { + return GHOST_kFailure; + } + + auto wtiIter = wintabInfo.begin(); + + /* We only process events that correlate to a mouse button events, so there may exist Wintab + * button down events that were instead mapped to e.g. scroll still in the queue. We need to + * skip those and find the last button down mapped to mouse buttons. + */ + if (!window->wintabSysButPressed()) { + for (auto it = wtiIter; it != wintabInfo.end(); it++) { + if (it->type == GHOST_kEventButtonDown) { + wtiIter = it; + } + } + } + + for (; wtiIter != wintabInfo.end(); wtiIter++) { + auto info = *wtiIter; + + switch (info.type) { + case GHOST_kEventButtonDown: { + /* While changing windows with a tablet, Window's mouse button events normally occur before + * tablet proximity events, so a button up event can't be differentiated as occurring from + * a Wintab tablet or a normal mouse and a Ghost button event will always be generated. + * + * If we were called during a button down event create a ghost button down event, otherwise + * don't duplicate the prior button down as it interrupts drawing immediately after + * changing a window. + */ + if (type == GHOST_kEventButtonDown) { + // Move cursor to point of contact because GHOST_EventButton does not include position. + system->pushEvent(new GHOST_EventCursor( + info.time, GHOST_kEventCursorMove, window, info.x, info.y, info.tabletData)); + system->pushEvent( + new GHOST_EventButton(info.time, info.type, window, info.button, info.tabletData)); + } + window->updateWintabSysBut(MousePressed); + break; + } + case GHOST_kEventCursorMove: + system->pushEvent(new GHOST_EventCursor( + info.time, GHOST_kEventCursorMove, window, info.x, info.y, info.tabletData)); + break; + case GHOST_kEventButtonUp: + system->pushEvent( + new GHOST_EventButton(info.time, info.type, window, info.button, info.tabletData)); + window->updateWintabSysBut(MouseReleased); + break; + default: + break; + } + } + + return GHOST_kSuccess; } void GHOST_SystemWin32::processPointerEvents( @@ -1034,13 +1119,19 @@ GHOST_EventCursor *GHOST_SystemWin32::processCursorEvent(GHOST_WindowWin32 *wind GHOST_TInt32 x_screen, y_screen; GHOST_SystemWin32 *system = (GHOST_SystemWin32 *)getSystem(); - if (window->m_tabletInRange) { - if (window->useTabletAPI(GHOST_kTabletNative)) { + if (window->m_tabletInRange || window->wintabSysButPressed()) { + if (window->useTabletAPI(GHOST_kTabletWintab) && + processWintabEvents(GHOST_kEventCursorMove, window)) { + return NULL; + } + else if (window->useTabletAPI(GHOST_kTabletNative)) { // Tablet input handled in WM_POINTER* events. WM_MOUSEMOVE events in response to tablet // input aren't normally generated when using WM_POINTER events, but manually moving the // system cursor as we do in WM_POINTER handling does. return NULL; } + + // If using Wintab but no button event is currently active, fall through to default handling } system->getCursorPosition(x_screen, y_screen); @@ -1073,7 +1164,7 @@ GHOST_EventCursor *GHOST_SystemWin32::processCursorEvent(GHOST_WindowWin32 *wind window, x_screen + x_accum, y_screen + y_accum, - window->getTabletData()); + GHOST_TABLET_DATA_NONE); } } else { @@ -1082,7 +1173,7 @@ GHOST_EventCursor *GHOST_SystemWin32::processCursorEvent(GHOST_WindowWin32 *wind window, x_screen, y_screen, - window->getTabletData()); + GHOST_TABLET_DATA_NONE); } return NULL; } @@ -1193,7 +1284,6 @@ GHOST_Event *GHOST_SystemWin32::processWindowEvent(GHOST_TEventType type, if (type == GHOST_kEventWindowActivate) { system->getWindowManager()->setActiveWindow(window); - window->bringTabletContextToFront(); } return new GHOST_Event(system->getMilliSeconds(), type, window); @@ -1221,6 +1311,19 @@ GHOST_TSuccess GHOST_SystemWin32::pushDragDropEvent(GHOST_TEventType eventType, system->getMilliSeconds(), eventType, draggedObjectType, window, mouseX, mouseY, data)); } +void GHOST_SystemWin32::setTabletAPI(GHOST_TTabletAPI api) +{ + GHOST_System::setTabletAPI(api); + + GHOST_WindowManager *wm = getWindowManager(); + GHOST_WindowWin32 *activeWindow = (GHOST_WindowWin32 *)wm->getActiveWindow(); + + for (GHOST_IWindow *win : wm->getWindows()) { + GHOST_WindowWin32 *windowsWindow = (GHOST_WindowWin32 *)win; + windowsWindow->updateWintab(windowsWindow == activeWindow); + } +} + void GHOST_SystemWin32::processMinMaxInfo(MINMAXINFO *minmax) { minmax->ptMinTrackSize.x = 320; @@ -1456,15 +1559,17 @@ LRESULT WINAPI GHOST_SystemWin32::s_wndProc(HWND hwnd, UINT msg, WPARAM wParam, } break; //////////////////////////////////////////////////////////////////////// - // Tablet events, processed + // Wintab events, processed //////////////////////////////////////////////////////////////////////// - case WT_PACKET: - window->processWin32TabletEvent(wParam, lParam); + case WT_INFOCHANGE: { + window->processWintabInfoChangeEvent(lParam); break; - case WT_CSRCHANGE: - case WT_PROXIMITY: - window->processWin32TabletInitEvent(); + } + case WT_PROXIMITY: { + bool inRange = LOWORD(lParam); + window->processWintabProximityEvent(inRange); break; + } //////////////////////////////////////////////////////////////////////// // Pointer events, processed //////////////////////////////////////////////////////////////////////// @@ -1603,7 +1708,9 @@ LRESULT WINAPI GHOST_SystemWin32::s_wndProc(HWND hwnd, UINT msg, WPARAM wParam, * will not be dispatched to OUR active window if we minimize one of OUR windows. */ if (LOWORD(wParam) == WA_INACTIVE) window->lostMouseCapture(); - window->processWin32TabletActivateEvent(GET_WM_ACTIVATE_STATE(wParam, lParam)); + + window->updateWintab(LOWORD(wParam) != WA_INACTIVE); + lResult = ::DefWindowProc(hwnd, msg, wParam, lParam); break; } @@ -1661,6 +1768,11 @@ LRESULT WINAPI GHOST_SystemWin32::s_wndProc(HWND hwnd, UINT msg, WPARAM wParam, else { event = processWindowEvent(GHOST_kEventWindowSize, window); } + + if (msg == WM_SIZE && wParam == SIZE_MINIMIZED) { + window->updateWintab(false); + } + break; case WM_CAPTURECHANGED: window->lostMouseCapture(); @@ -1711,6 +1823,12 @@ LRESULT WINAPI GHOST_SystemWin32::s_wndProc(HWND hwnd, UINT msg, WPARAM wParam, SWP_NOZORDER | SWP_NOACTIVATE); } break; + case WM_DISPLAYCHANGE: + for (GHOST_IWindow *iter_win : system->getWindowManager()->getWindows()) { + GHOST_WindowWin32 *iter_win32win = (GHOST_WindowWin32 *)iter_win; + iter_win32win->processWintabDisplayChangeEvent(); + } + break; //////////////////////////////////////////////////////////////////////// // Window events, ignored //////////////////////////////////////////////////////////////////////// diff --git a/intern/ghost/intern/GHOST_SystemWin32.h b/intern/ghost/intern/GHOST_SystemWin32.h index c6d810d2a38..05221cbdc40 100644 --- a/intern/ghost/intern/GHOST_SystemWin32.h +++ b/intern/ghost/intern/GHOST_SystemWin32.h @@ -266,6 +266,16 @@ class GHOST_SystemWin32 : public GHOST_System { int mouseY, void *data); + /*************************************************************************************** + ** Modify tablet API + ***************************************************************************************/ + + /** + * Set which tablet API to use. + * \param api Enum indicating which API to use. + */ + void setTabletAPI(GHOST_TTabletAPI api) override; + protected: /** * Initializes the system. diff --git a/intern/ghost/intern/GHOST_WindowWin32.cpp b/intern/ghost/intern/GHOST_WindowWin32.cpp index b0ba7b6befb..d4fe7af8861 100644 --- a/intern/ghost/intern/GHOST_WindowWin32.cpp +++ b/intern/ghost/intern/GHOST_WindowWin32.cpp @@ -72,6 +72,7 @@ GHOST_WindowWin32::GHOST_WindowWin32(GHOST_SystemWin32 *system, bool is_debug, bool dialog) : GHOST_Window(width, height, state, wantStereoVisual, false), + m_tabletInRange(false), m_inLiveResize(false), m_system(system), m_hDC(0), @@ -80,19 +81,15 @@ GHOST_WindowWin32::GHOST_WindowWin32(GHOST_SystemWin32 *system, m_nPressedButtons(0), m_customCursor(0), m_wantAlphaBackground(alphaBackground), + m_wintab(), m_normal_state(GHOST_kWindowStateNormal), m_user32(NULL), m_fpGetPointerInfoHistory(NULL), m_fpGetPointerPenInfoHistory(NULL), m_fpGetPointerTouchInfoHistory(NULL), m_parentWindowHwnd(parentwindow ? parentwindow->m_hWnd : NULL), - m_debug_context(is_debug), - m_tabletInRange(false) + m_debug_context(is_debug) { - // Initialize tablet variables - memset(&m_wintab, 0, sizeof(m_wintab)); - m_tabletData = GHOST_TABLET_DATA_NONE; - // Create window if (state != GHOST_kWindowStateFullScreen) { RECT rect; @@ -297,66 +294,25 @@ GHOST_WindowWin32::GHOST_WindowWin32(GHOST_SystemWin32 *system, m_user32, "GetPointerTouchInfoHistory"); } - // Initialize Wintab - m_wintab.handle = ::LoadLibrary("Wintab32.dll"); - if (m_wintab.handle) { - // Get API functions - m_wintab.info = (GHOST_WIN32_WTInfo)::GetProcAddress(m_wintab.handle, "WTInfoA"); - m_wintab.open = (GHOST_WIN32_WTOpen)::GetProcAddress(m_wintab.handle, "WTOpenA"); - m_wintab.close = (GHOST_WIN32_WTClose)::GetProcAddress(m_wintab.handle, "WTClose"); - m_wintab.packet = (GHOST_WIN32_WTPacket)::GetProcAddress(m_wintab.handle, "WTPacket"); - m_wintab.enable = (GHOST_WIN32_WTEnable)::GetProcAddress(m_wintab.handle, "WTEnable"); - m_wintab.overlap = (GHOST_WIN32_WTOverlap)::GetProcAddress(m_wintab.handle, "WTOverlap"); - - // Let's see if we can initialize tablet here. - // Check if WinTab available by getting system context info. - LOGCONTEXT lc = {0}; - lc.lcOptions |= CXO_SYSTEM; - if (m_wintab.open && m_wintab.info && m_wintab.info(WTI_DEFSYSCTX, 0, &lc)) { - // Now init the tablet - /* The maximum tablet size, pressure and orientation (tilt) */ - AXIS TabletX, TabletY, Pressure, Orientation[3]; - - // Open a Wintab context - - // Open the context - lc.lcPktData = PACKETDATA; - lc.lcPktMode = PACKETMODE; - lc.lcOptions |= CXO_MESSAGES; - lc.lcMoveMask = PACKETDATA; - - /* Set the entire tablet as active */ - m_wintab.info(WTI_DEVICES, DVC_X, &TabletX); - m_wintab.info(WTI_DEVICES, DVC_Y, &TabletY); - - /* get the max pressure, to divide into a float */ - BOOL pressureSupport = m_wintab.info(WTI_DEVICES, DVC_NPRESSURE, &Pressure); - if (pressureSupport) - m_wintab.maxPressure = Pressure.axMax; - else - m_wintab.maxPressure = 0; - - /* get the max tilt axes, to divide into floats */ - BOOL tiltSupport = m_wintab.info(WTI_DEVICES, DVC_ORIENTATION, &Orientation); - if (tiltSupport) { - /* does the tablet support azimuth ([0]) and altitude ([1]) */ - if (Orientation[0].axResolution && Orientation[1].axResolution) { - /* all this assumes the minimum is 0 */ - m_wintab.maxAzimuth = Orientation[0].axMax; - m_wintab.maxAltitude = Orientation[1].axMax; - } - else { /* no so dont do tilt stuff */ - m_wintab.maxAzimuth = m_wintab.maxAltitude = 0; - } - } - - // The Wintab spec says we must open the context disabled if we are using cursor masks. - m_wintab.tablet = m_wintab.open(m_hWnd, &lc, FALSE); - if (m_wintab.enable && m_wintab.tablet) { - m_wintab.enable(m_wintab.tablet, TRUE); - } - } + if ((m_wintab.handle = ::LoadLibrary("Wintab32.dll")) && + (m_wintab.info = (GHOST_WIN32_WTInfo)::GetProcAddress(m_wintab.handle, "WTInfoA")) && + (m_wintab.open = (GHOST_WIN32_WTOpen)::GetProcAddress(m_wintab.handle, "WTOpenA")) && + (m_wintab.get = (GHOST_WIN32_WTGet)::GetProcAddress(m_wintab.handle, "WTGetA")) && + (m_wintab.set = (GHOST_WIN32_WTSet)::GetProcAddress(m_wintab.handle, "WTSetA")) && + (m_wintab.close = (GHOST_WIN32_WTClose)::GetProcAddress(m_wintab.handle, "WTClose")) && + (m_wintab.packetsGet = (GHOST_WIN32_WTPacketsGet)::GetProcAddress(m_wintab.handle, + "WTPacketsGet")) && + (m_wintab.queueSizeGet = (GHOST_WIN32_WTQueueSizeGet)::GetProcAddress(m_wintab.handle, + "WTQueueSizeGet")) && + (m_wintab.queueSizeSet = (GHOST_WIN32_WTQueueSizeSet)::GetProcAddress(m_wintab.handle, + "WTQueueSizeSet")) && + (m_wintab.enable = (GHOST_WIN32_WTEnable)::GetProcAddress(m_wintab.handle, "WTEnable")) && + (m_wintab.overlap = (GHOST_WIN32_WTOverlap)::GetProcAddress(m_wintab.handle, "WTOverlap"))) { + initializeWintab(); + // Determine which tablet API to use and enable it. + updateWintab(true); } + CoCreateInstance( CLSID_TaskbarList, NULL, CLSCTX_INPROC_SERVER, IID_ITaskbarList3, (LPVOID *)&m_Bar); } @@ -370,8 +326,8 @@ GHOST_WindowWin32::~GHOST_WindowWin32() } if (m_wintab.handle) { - if (m_wintab.close && m_wintab.tablet) { - m_wintab.close(m_wintab.tablet); + if (m_wintab.close && m_wintab.context) { + m_wintab.close(m_wintab.context); } FreeLibrary(m_wintab.handle); @@ -820,6 +776,27 @@ bool GHOST_WindowWin32::getMousePressed() const return m_nPressedButtons; } +bool GHOST_WindowWin32::wintabSysButPressed() const +{ + return m_wintab.numSysButtons; +} + +void GHOST_WindowWin32::updateWintabSysBut(GHOST_MouseCaptureEventWin32 event) +{ + switch (event) { + case MousePressed: + m_wintab.numSysButtons++; + break; + case MouseReleased: + if (m_wintab.numSysButtons) + m_wintab.numSysButtons--; + break; + case OperatorGrab: + case OperatorUngrab: + break; + } +} + HCURSOR GHOST_WindowWin32::getStandardCursor(GHOST_TStandardCursor shape) const { // Convert GHOST cursor to Windows OEM cursor @@ -1023,6 +1000,104 @@ GHOST_TSuccess GHOST_WindowWin32::hasCursorShape(GHOST_TStandardCursor cursorSha return (getStandardCursor(cursorShape)) ? GHOST_kSuccess : GHOST_kFailure; } +void GHOST_WindowWin32::updateWintab(bool active) +{ + if (m_wintab.enable && m_wintab.overlap && m_wintab.context) { + bool useWintab = useTabletAPI(GHOST_kTabletWintab); + bool enable = active && useWintab; + + // Disabling context while the Window is not minimized can cause issues on receiving Wintab + // input while changing a window for some drivers, so only disable if either Wintab had been + // disabled or the window is minimized. + m_wintab.enable(m_wintab.context, useWintab && !::IsIconic(m_hWnd)); + m_wintab.overlap(m_wintab.context, enable); + + if (!enable) { + // WT_PROXIMITY event doesn't occur unless tablet's cursor leaves the proximity while the + // window is active. + m_tabletInRange = false; + m_wintab.numSysButtons = 0; + m_wintab.sysButtonsPressed = 0; + } + } +} + +void GHOST_WindowWin32::initializeWintab() +{ + // return if wintab library handle doesn't exist or wintab is already initialized + if (!m_wintab.handle || m_wintab.context) { + return; + } + + // Let's see if we can initialize tablet here. + // Check if WinTab available by getting system context info. + LOGCONTEXT lc = {0}; + if (m_wintab.open && m_wintab.info && m_wintab.queueSizeGet && m_wintab.queueSizeSet && + m_wintab.info(WTI_DEFSYSCTX, 0, &lc)) { + // Now init the tablet + /* The pressure and orientation (tilt) */ + AXIS Pressure, Orientation[3]; + + // Open a Wintab context + + // Open the context + lc.lcPktData = PACKETDATA; + lc.lcPktMode = PACKETMODE; + lc.lcMoveMask = PACKETDATA; + // Wacom maps y origin to the tablet's bottom + // Invert to match Windows y origin mapping to the screen top + lc.lcOutExtY = -lc.lcOutExtY; + + m_wintab.info(WTI_INTERFACE, IFC_NDEVICES, &m_wintab.numDevices); + + /* get the max pressure, to divide into a float */ + BOOL pressureSupport = m_wintab.info(WTI_DEVICES, DVC_NPRESSURE, &Pressure); + m_wintab.maxPressure = pressureSupport ? Pressure.axMax : 0; + + /* get the max tilt axes, to divide into floats */ + BOOL tiltSupport = m_wintab.info(WTI_DEVICES, DVC_ORIENTATION, &Orientation); + /* does the tablet support azimuth ([0]) and altitude ([1]) */ + if (tiltSupport && Orientation[0].axResolution && Orientation[1].axResolution) { + /* all this assumes the minimum is 0 */ + m_wintab.maxAzimuth = Orientation[0].axMax; + m_wintab.maxAltitude = Orientation[1].axMax; + } + else { /* no so dont do tilt stuff */ + m_wintab.maxAzimuth = m_wintab.maxAltitude = 0; + } + + // The Wintab spec says we must open the context disabled if we are using cursor masks. + m_wintab.context = m_wintab.open(m_hWnd, &lc, FALSE); + + // Wintab provides no way to determine the maximum queue size aside from checking if attempts + // to change the queue size are successful. + const int maxQueue = 500; + int initialQueueSize = m_wintab.queueSizeGet(m_wintab.context); + int queueSize = initialQueueSize; + + while (queueSize < maxQueue) { + int testSize = min(queueSize + initialQueueSize, maxQueue); + if (m_wintab.queueSizeSet(m_wintab.context, testSize)) { + queueSize = testSize; + } + else { + /* From Windows Wintab Documentation for WTQueueSizeSet: + * "If the return value is zero, the context has no queue because the function deletes the + * original queue before attempting to create a new one. The application must continue + * calling the function with a smaller queue size until the function returns a non - zero + * value." + * + * In our case we start with a known valid queue size and in the event of failure roll + * back to the last valid queue size. + */ + m_wintab.queueSizeSet(m_wintab.context, queueSize); + break; + } + } + m_wintab.pkts.resize(queueSize); + } +} + GHOST_TSuccess GHOST_WindowWin32::getPointerInfo( std::vector &outPointerInfo, WPARAM wParam, LPARAM lParam) { @@ -1105,28 +1180,20 @@ GHOST_TSuccess GHOST_WindowWin32::getPointerInfo( return GHOST_kSuccess; } -void GHOST_WindowWin32::setTabletData(GHOST_TabletData *pTabletData) +void GHOST_WindowWin32::processWintabDisplayChangeEvent() { - if (pTabletData) { - m_tabletData = *pTabletData; - } - else { - m_tabletData = GHOST_TABLET_DATA_NONE; - } -} + LOGCONTEXT lc_sys = {0}, lc_curr = {0}; -void GHOST_WindowWin32::processWin32TabletActivateEvent(WORD state) -{ - if (!useTabletAPI(GHOST_kTabletWintab)) { - return; - } + if (m_wintab.info && m_wintab.get && m_wintab.set && m_wintab.info(WTI_DEFSYSCTX, 0, &lc_sys)) { - if (m_wintab.enable && m_wintab.tablet) { - m_wintab.enable(m_wintab.tablet, state); + m_wintab.get(m_wintab.context, &lc_curr); - if (m_wintab.overlap && state) { - m_wintab.overlap(m_wintab.tablet, TRUE); - } + lc_curr.lcOutOrgX = lc_sys.lcOutOrgX; + lc_curr.lcOutOrgY = lc_sys.lcOutOrgY; + lc_curr.lcOutExtX = lc_sys.lcOutExtX; + lc_curr.lcOutExtY = -lc_sys.lcOutExtY; + + m_wintab.set(m_wintab.context, &lc_curr); } } @@ -1136,7 +1203,7 @@ bool GHOST_WindowWin32::useTabletAPI(GHOST_TTabletAPI api) const return true; } else if (m_system->getTabletAPI() == GHOST_kTabletAutomatic) { - if (m_wintab.tablet) + if (m_wintab.numDevices) return api == GHOST_kTabletWintab; else return api == GHOST_kTabletNative; @@ -1146,115 +1213,180 @@ bool GHOST_WindowWin32::useTabletAPI(GHOST_TTabletAPI api) const } } -void GHOST_WindowWin32::processWin32TabletInitEvent() +void GHOST_WindowWin32::processWintabProximityEvent(bool inRange) { if (!useTabletAPI(GHOST_kTabletWintab)) { return; } // Let's see if we can initialize tablet here - if (m_wintab.info && m_wintab.tablet) { + if (m_wintab.info && m_wintab.context) { AXIS Pressure, Orientation[3]; /* The maximum tablet size */ BOOL pressureSupport = m_wintab.info(WTI_DEVICES, DVC_NPRESSURE, &Pressure); - if (pressureSupport) - m_wintab.maxPressure = Pressure.axMax; - else - m_wintab.maxPressure = 0; + m_wintab.maxPressure = pressureSupport ? Pressure.axMax : 0; BOOL tiltSupport = m_wintab.info(WTI_DEVICES, DVC_ORIENTATION, &Orientation); - if (tiltSupport) { - /* does the tablet support azimuth ([0]) and altitude ([1]) */ - if (Orientation[0].axResolution && Orientation[1].axResolution) { - m_wintab.maxAzimuth = Orientation[0].axMax; - m_wintab.maxAltitude = Orientation[1].axMax; - } - else { /* no so dont do tilt stuff */ - m_wintab.maxAzimuth = m_wintab.maxAltitude = 0; - } + /* does the tablet support azimuth ([0]) and altitude ([1]) */ + if (tiltSupport && Orientation[0].axResolution && Orientation[1].axResolution) { + m_wintab.maxAzimuth = Orientation[0].axMax; + m_wintab.maxAltitude = Orientation[1].axMax; } + else { /* no so dont do tilt stuff */ + m_wintab.maxAzimuth = m_wintab.maxAltitude = 0; + } + } + + m_tabletInRange = inRange; +} + +void GHOST_WindowWin32::processWintabInfoChangeEvent(LPARAM lParam) +{ + GHOST_SystemWin32 *system = (GHOST_SystemWin32 *)GHOST_System::getSystem(); + + // Update number of connected Wintab digitizers + if (LOWORD(lParam) == WTI_INTERFACE && HIWORD(lParam) == IFC_NDEVICES) { + m_wintab.info(WTI_INTERFACE, IFC_NDEVICES, &m_wintab.numDevices); + updateWintab((GHOST_WindowWin32 *)system->getWindowManager()->getActiveWindow() == this); + } +} + +GHOST_TSuccess GHOST_WindowWin32::wintabMouseToGhost(UINT cursor, + DWORD physicalButton, + GHOST_TButtonMask &ghostButton) +{ + const DWORD numButtons = 32; + BYTE logicalButtons[numButtons] = {0}; + BYTE systemButtons[numButtons] = {0}; + + m_wintab.info(WTI_CURSORS + cursor, CSR_BUTTONMAP, &logicalButtons); + m_wintab.info(WTI_CURSORS + cursor, CSR_SYSBTNMAP, &systemButtons); + + if (physicalButton >= numButtons) { + return GHOST_kFailure; } + BYTE lb = logicalButtons[physicalButton]; - m_tabletData.Active = GHOST_kTabletModeNone; + if (lb >= numButtons) { + return GHOST_kFailure; + } + switch (systemButtons[lb]) { + case SBN_LCLICK: + ghostButton = GHOST_kButtonMaskLeft; + return GHOST_kSuccess; + case SBN_RCLICK: + ghostButton = GHOST_kButtonMaskRight; + return GHOST_kSuccess; + case SBN_MCLICK: + ghostButton = GHOST_kButtonMaskMiddle; + return GHOST_kSuccess; + default: + return GHOST_kFailure; + } } -void GHOST_WindowWin32::processWin32TabletEvent(WPARAM wParam, LPARAM lParam) +GHOST_TSuccess GHOST_WindowWin32::getWintabInfo(std::vector &outWintabInfo) { if (!useTabletAPI(GHOST_kTabletWintab)) { - return; + return GHOST_kFailure; } - if (m_wintab.packet && m_wintab.tablet) { - PACKET pkt; - if (m_wintab.packet((HCTX)lParam, wParam, &pkt)) { - switch (pkt.pkCursor % 3) { /* % 3 for multiple devices ("DualTrack") */ - case 0: - m_tabletData.Active = GHOST_kTabletModeNone; /* puck - not yet supported */ - break; - case 1: - m_tabletData.Active = GHOST_kTabletModeStylus; /* stylus */ - break; - case 2: - m_tabletData.Active = GHOST_kTabletModeEraser; /* eraser */ - break; - } + if (!(m_wintab.packetsGet && m_wintab.context)) { + return GHOST_kFailure; + } - if (m_wintab.maxPressure > 0) { - m_tabletData.Pressure = (float)pkt.pkNormalPressure / (float)m_wintab.maxPressure; - } - else { - m_tabletData.Pressure = 1.0f; - } + GHOST_SystemWin32 *system = (GHOST_SystemWin32 *)GHOST_System::getSystem(); - if ((m_wintab.maxAzimuth > 0) && (m_wintab.maxAltitude > 0)) { - ORIENTATION ort = pkt.pkOrientation; - float vecLen; - float altRad, azmRad; /* in radians */ + const int numPackets = m_wintab.packetsGet( + m_wintab.context, m_wintab.pkts.size(), m_wintab.pkts.data()); + outWintabInfo.resize(numPackets); - /* - * from the wintab spec: - * orAzimuth Specifies the clockwise rotation of the - * cursor about the z axis through a full circular range. - * - * orAltitude Specifies the angle with the x-y plane - * through a signed, semicircular range. Positive values - * specify an angle upward toward the positive z axis; - * negative values specify an angle downward toward the negative z axis. - * - * wintab.h defines .orAltitude as a UINT but documents .orAltitude - * as positive for upward angles and negative for downward angles. - * WACOM uses negative altitude values to show that the pen is inverted; - * therefore we cast .orAltitude as an (int) and then use the absolute value. - */ + for (int i = 0; i < numPackets; i++) { + PACKET pkt = m_wintab.pkts[i]; + GHOST_TabletData tabletData = GHOST_TABLET_DATA_NONE; + switch (pkt.pkCursor % 3) { /* % 3 for multiple devices ("DualTrack") */ + case 0: + tabletData.Active = GHOST_kTabletModeNone; /* puck - not yet supported */ + break; + case 1: + tabletData.Active = GHOST_kTabletModeStylus; /* stylus */ + break; + case 2: + tabletData.Active = GHOST_kTabletModeEraser; /* eraser */ + break; + } + + if (m_wintab.maxPressure > 0) { + tabletData.Pressure = (float)pkt.pkNormalPressure / (float)m_wintab.maxPressure; + } + + if ((m_wintab.maxAzimuth > 0) && (m_wintab.maxAltitude > 0)) { + ORIENTATION ort = pkt.pkOrientation; + float vecLen; + float altRad, azmRad; /* in radians */ + + /* + * from the wintab spec: + * orAzimuth Specifies the clockwise rotation of the + * cursor about the z axis through a full circular range. + * + * orAltitude Specifies the angle with the x-y plane + * through a signed, semicircular range. Positive values + * specify an angle upward toward the positive z axis; + * negative values specify an angle downward toward the negative z axis. + * + * wintab.h defines .orAltitude as a UINT but documents .orAltitude + * as positive for upward angles and negative for downward angles. + * WACOM uses negative altitude values to show that the pen is inverted; + * therefore we cast .orAltitude as an (int) and then use the absolute value. + */ + + /* convert raw fixed point data to radians */ + altRad = (float)((fabs((float)ort.orAltitude) / (float)m_wintab.maxAltitude) * M_PI / 2.0); + azmRad = (float)(((float)ort.orAzimuth / (float)m_wintab.maxAzimuth) * M_PI * 2.0); + + /* find length of the stylus' projected vector on the XY plane */ + vecLen = cos(altRad); + + /* from there calculate X and Y components based on azimuth */ + tabletData.Xtilt = sin(azmRad) * vecLen; + tabletData.Ytilt = (float)(sin(M_PI / 2.0 - azmRad) * vecLen); + } + + outWintabInfo[i].x = pkt.pkX; + outWintabInfo[i].y = pkt.pkY; - /* convert raw fixed point data to radians */ - altRad = (float)((fabs((float)ort.orAltitude) / (float)m_wintab.maxAltitude) * M_PI / 2.0); - azmRad = (float)(((float)ort.orAzimuth / (float)m_wintab.maxAzimuth) * M_PI * 2.0); + // Some Wintab libraries don't handle relative button input correctly, so we track button + // presses manually. + DWORD buttonsChanged = m_wintab.sysButtonsPressed ^ pkt.pkButtons; - /* find length of the stylus' projected vector on the XY plane */ - vecLen = cos(altRad); + // Find the index for the changed button from the button map. + DWORD physicalButton = 0; + for (DWORD diff = (unsigned)buttonsChanged >> 1; diff > 0; diff = (unsigned)diff >> 1) { + physicalButton++; + } - /* from there calculate X and Y components based on azimuth */ - m_tabletData.Xtilt = sin(azmRad) * vecLen; - m_tabletData.Ytilt = (float)(sin(M_PI / 2.0 - azmRad) * vecLen); + if (buttonsChanged && + wintabMouseToGhost(pkt.pkCursor, physicalButton, outWintabInfo[i].button)) { + if (buttonsChanged & pkt.pkButtons) { + outWintabInfo[i].type = GHOST_kEventButtonDown; } else { - m_tabletData.Xtilt = 0.0f; - m_tabletData.Ytilt = 0.0f; + outWintabInfo[i].type = GHOST_kEventButtonUp; } } - } -} + else { + outWintabInfo[i].type = GHOST_kEventCursorMove; + } -void GHOST_WindowWin32::bringTabletContextToFront() -{ - if (!useTabletAPI(GHOST_kTabletWintab)) { - return; - } + m_wintab.sysButtonsPressed = pkt.pkButtons; - if (m_wintab.overlap && m_wintab.tablet) { - m_wintab.overlap(m_wintab.tablet, TRUE); + // Wintab does not support performance counters, so use low frequency counter instead + outWintabInfo[i].time = system->tickCountToMillis(pkt.pkTime); + outWintabInfo[i].tabletData = tabletData; } + + return GHOST_kSuccess; } GHOST_TUns16 GHOST_WindowWin32::getDPIHint() diff --git a/intern/ghost/intern/GHOST_WindowWin32.h b/intern/ghost/intern/GHOST_WindowWin32.h index 2951901ceb4..a3d4e89dd38 100644 --- a/intern/ghost/intern/GHOST_WindowWin32.h +++ b/intern/ghost/intern/GHOST_WindowWin32.h @@ -36,8 +36,9 @@ #endif #include -#define PACKETDATA (PK_BUTTONS | PK_NORMAL_PRESSURE | PK_ORIENTATION | PK_CURSOR) -#define PACKETMODE PK_BUTTONS +#define PACKETDATA \ + (PK_BUTTONS | PK_NORMAL_PRESSURE | PK_ORIENTATION | PK_CURSOR | PK_X | PK_Y | PK_TIME) +#define PACKETMODE 0 #include class GHOST_SystemWin32; @@ -45,9 +46,13 @@ class GHOST_DropTargetWin32; // typedefs for WinTab functions to allow dynamic loading typedef UINT(API *GHOST_WIN32_WTInfo)(UINT, UINT, LPVOID); +typedef BOOL(API *GHOST_WIN32_WTGet)(HCTX, LPLOGCONTEXTA); +typedef BOOL(API *GHOST_WIN32_WTSet)(HCTX, LPLOGCONTEXTA); typedef HCTX(API *GHOST_WIN32_WTOpen)(HWND, LPLOGCONTEXTA, BOOL); typedef BOOL(API *GHOST_WIN32_WTClose)(HCTX); -typedef BOOL(API *GHOST_WIN32_WTPacket)(HCTX, UINT, LPVOID); +typedef BOOL(API *GHOST_WIN32_WTPacketsGet)(HCTX, int, LPVOID); +typedef int(API *GHOST_WIN32_WTQueueSizeGet)(HCTX); +typedef BOOL(API *GHOST_WIN32_WTQueueSizeSet)(HCTX, int); typedef BOOL(API *GHOST_WIN32_WTEnable)(HCTX, BOOL); typedef BOOL(API *GHOST_WIN32_WTOverlap)(HCTX, BOOL); @@ -228,7 +233,14 @@ struct GHOST_PointerInfoWin32 { GHOST_TButtonMask buttonMask; POINT pixelLocation; GHOST_TUns64 time; + GHOST_TabletData tabletData; +}; +struct GHOST_WintabInfoWin32 { + GHOST_TInt32 x, y; + GHOST_TEventType type; + GHOST_TButtonMask button; + GHOST_TUns64 time; GHOST_TabletData tabletData; }; @@ -422,12 +434,16 @@ class GHOST_WindowWin32 : public GHOST_Window { HCURSOR getStandardCursor(GHOST_TStandardCursor shape) const; void loadCursor(bool visible, GHOST_TStandardCursor cursorShape) const; - const GHOST_TabletData &GetTabletData() - { - return m_tabletData; - } + /** + * Handle setup and switch between Wintab and Pointer APIs + * \param active Whether the window is or will be in an active state + */ + void updateWintab(bool active); - void setTabletData(GHOST_TabletData *tabletData); + /** + * Query whether given tablet API should be used. + * \param api Tablet API to test. + */ bool useTabletAPI(GHOST_TTabletAPI api) const; /** @@ -440,10 +456,28 @@ class GHOST_WindowWin32 : public GHOST_Window { WPARAM wParam, LPARAM lParam); - void processWin32TabletActivateEvent(WORD state); - void processWin32TabletInitEvent(); - void processWin32TabletEvent(WPARAM wParam, LPARAM lParam); - void bringTabletContextToFront(); + /** + * Handle Wintab coordinate changes when DisplayChange events occur. + */ + void processWintabDisplayChangeEvent(); + + /** + * Set tablet details when a cursor enters range + */ + void processWintabProximityEvent(bool inRange); + + /** + * Handle Wintab info changes such as change in number of connected tablets. + * \param lParam LPARAM of the event + */ + void processWintabInfoChangeEvent(LPARAM lParam); + + /** + * Translate Wintab packets into GHOST_WintabInfoWin32 structs. + * \param outWintabInfo Storage to return resulting GHOST_WintabInfoWin32 structs + * \return Success if able to read packets, even if there are none + */ + GHOST_TSuccess getWintabInfo(std::vector &outWintabInfo); GHOST_TSuccess beginFullScreen() const { @@ -463,6 +497,19 @@ class GHOST_WindowWin32 : public GHOST_Window { */ bool getMousePressed() const; + /** + * Get if there are currently pressed Wintab buttons associated to a Windows mouse button press + * \return True if there are currently any pressed Wintab buttons associated to a Windows + * mouse button press + */ + bool wintabSysButPressed() const; + + /** + * Register a Wintab button has been associated to a Windows mouse button press + * \param event Whether the button was pressed or released + */ + void updateWintabSysBut(GHOST_MouseCaptureEventWin32 event); + /** Whether a tablet stylus is being tracked */ bool m_tabletInRange; @@ -546,28 +593,47 @@ class GHOST_WindowWin32 : public GHOST_Window { static const wchar_t *s_windowClassName; static const int s_maxTitleLength; - /** Tablet data for GHOST */ - GHOST_TabletData m_tabletData; - /* Wintab API */ struct { /** WinTab dll handle */ - HMODULE handle; + HMODULE handle = NULL; /** API functions */ - GHOST_WIN32_WTInfo info; - GHOST_WIN32_WTOpen open; - GHOST_WIN32_WTClose close; - GHOST_WIN32_WTPacket packet; - GHOST_WIN32_WTEnable enable; - GHOST_WIN32_WTOverlap overlap; + GHOST_WIN32_WTInfo info = NULL; + GHOST_WIN32_WTGet get = NULL; + GHOST_WIN32_WTSet set = NULL; + GHOST_WIN32_WTOpen open = NULL; + GHOST_WIN32_WTClose close = NULL; + GHOST_WIN32_WTPacketsGet packetsGet = NULL; + GHOST_WIN32_WTQueueSizeGet queueSizeGet = NULL; + GHOST_WIN32_WTQueueSizeSet queueSizeSet = NULL; + GHOST_WIN32_WTEnable enable = NULL; + GHOST_WIN32_WTOverlap overlap = NULL; /** Stores the Tablet context if detected Tablet features using WinTab.dll */ - HCTX tablet; - LONG maxPressure; - LONG maxAzimuth, maxAltitude; + HCTX context = NULL; + /** Number of connected Wintab digitizers */ + UINT numDevices = 0; + /** Number of cursors currently in contact mapped to system buttons */ + GHOST_TUns8 numSysButtons = 0; + /** Cursors currently in contact mapped to system buttons */ + DWORD sysButtonsPressed = 0; + LONG maxPressure = 0; + LONG maxAzimuth = 0, maxAltitude = 0; + /* Queue size doesn't change once set, so reuse the same buffer */ + std::vector pkts; } m_wintab; + /** + * Wintab setup + */ + void initializeWintab(); + + /** + * Convert Wintab system mapped (mouse) buttons into Ghost button mask + */ + GHOST_TSuccess wintabMouseToGhost(UINT cursor, DWORD physicalButton, GHOST_TButtonMask &buttonMask); + GHOST_TWindowState m_normal_state; /** user32 dll handle*/ -- cgit v1.2.3 From ea5a2efb57075736e277b679cc4dd4dbb458b349 Mon Sep 17 00:00:00 2001 From: Brecht Van Lommel Date: Wed, 8 Apr 2020 12:43:49 +0200 Subject: Fix manual reference error after removal of use_international_fonts --- release/scripts/modules/rna_manual_reference.py | 36 ++++++++++++------------- 1 file changed, 17 insertions(+), 19 deletions(-) diff --git a/release/scripts/modules/rna_manual_reference.py b/release/scripts/modules/rna_manual_reference.py index 22bea11cbc2..7b266d66d29 100644 --- a/release/scripts/modules/rna_manual_reference.py +++ b/release/scripts/modules/rna_manual_reference.py @@ -9,27 +9,25 @@ else: url_manual_prefix = "https://docs.blender.org/manual/en/" + manual_version + "/" -language = "" -if bpy.context.preferences.view.use_international_fonts: - language = bpy.context.preferences.view.language - if language == 'DEFAULT': - import os - language = os.getenv('LANG', '').split('.')[0] +language = bpy.context.preferences.view.language +if language == 'DEFAULT': + import os + language = os.getenv('LANG', '').split('.')[0] LANG = { - "de_DE": "de", - "ru_RU": "ru", - "uk_UA": "uk", - "es": "es", - "fr_FR": "fr", - "it_IT": "it", - "ja_JP": "ja", - "ko_KR": "ko", - "pt_PT": "pt", - "pt_BR": "pt", - "vi_VN": "vi", - "zh_CN": "zh-hans", - "zh_TW": "zh-hant", +"de_DE": "de", +"ru_RU": "ru", +"uk_UA": "uk", +"es": "es", +"fr_FR": "fr", +"it_IT": "it", +"ja_JP": "ja", +"ko_KR": "ko", +"pt_PT": "pt", +"pt_BR": "pt", +"vi_VN": "vi", +"zh_CN": "zh-hans", +"zh_TW": "zh-hant", }.get(language) if LANG is not None: -- cgit v1.2.3 From 7cafdc57e06d675061ec40cfaba03c2af1f58122 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Barschkis?= Date: Wed, 8 Apr 2020 13:20:18 +0200 Subject: Fluid: Manta clang-format update Do not use sort-includes in Manta source files for now when applying clang-format. Too many conflicts. --- extern/mantaflow/UPDATE.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extern/mantaflow/UPDATE.sh b/extern/mantaflow/UPDATE.sh index 0db18d03094..3feb1ba9226 100644 --- a/extern/mantaflow/UPDATE.sh +++ b/extern/mantaflow/UPDATE.sh @@ -71,7 +71,7 @@ rm $BLENDER_INSTALLATION/blender/tmp/preprocessed/fileio/*.reg cd $BLENDER_INSTALLATION/blender/tmp/ echo "Applying clang format to Mantaflow source files" -find . -iname *.h -o -iname *.cpp | xargs clang-format --verbose -i -style=file +find . -iname *.h -o -iname *.cpp | xargs clang-format --verbose -i -style=file -sort-includes=0 find . -iname *.h -o -iname *.cpp | xargs dos2unix --verbose # ==================== 5) MOVE MANTAFLOW FILES TO EXTERN/ ================================ -- cgit v1.2.3 From a1ddb633297a603ed19a37340be5f27c1c439d36 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Barschkis?= Date: Wed, 8 Apr 2020 13:25:16 +0200 Subject: Fluid: Update Mantaflow source files Update includes new grid helper functions and some cleanups. --- extern/mantaflow/preprocessed/gitinfo.h | 2 +- extern/mantaflow/preprocessed/grid.cpp | 153 ++++++++++++++++++ extern/mantaflow/preprocessed/grid.h | 60 +++++-- extern/mantaflow/preprocessed/grid.h.reg.cpp | 172 +++++++++++---------- .../preprocessed/plugin/secondaryparticles.cpp | 2 +- 5 files changed, 288 insertions(+), 101 deletions(-) diff --git a/extern/mantaflow/preprocessed/gitinfo.h b/extern/mantaflow/preprocessed/gitinfo.h index 208d8008a7e..6a26c480392 100644 --- a/extern/mantaflow/preprocessed/gitinfo.h +++ b/extern/mantaflow/preprocessed/gitinfo.h @@ -1,3 +1,3 @@ -#define MANTA_GIT_VERSION "commit 5fbd3d04381b21afce4a593d1fe2d9bc7bef5424" +#define MANTA_GIT_VERSION "commit f3d32c45934fd08c40096fb3510e9cc403730977" diff --git a/extern/mantaflow/preprocessed/grid.cpp b/extern/mantaflow/preprocessed/grid.cpp index f10052349d5..0ea3afb91f4 100644 --- a/extern/mantaflow/preprocessed/grid.cpp +++ b/extern/mantaflow/preprocessed/grid.cpp @@ -853,6 +853,147 @@ template struct knPermuteAxes : public KernelBase { int axis2; }; +struct knJoinVec : public KernelBase { + knJoinVec(Grid &a, const Grid &b, bool keepMax) + : KernelBase(&a, 0), a(a), b(b), keepMax(keepMax) + { + runMessage(); + run(); + } + inline void op(IndexInt idx, Grid &a, const Grid &b, bool keepMax) const + { + Real a1 = normSquare(a[idx]); + Real b1 = normSquare(b[idx]); + a[idx] = (keepMax) ? max(a1, b1) : min(a1, b1); + } + inline Grid &getArg0() + { + return a; + } + typedef Grid type0; + inline const Grid &getArg1() + { + return b; + } + typedef Grid type1; + inline bool &getArg2() + { + return keepMax; + } + typedef bool type2; + void runMessage() + { + debMsg("Executing kernel knJoinVec ", 3); + debMsg("Kernel range" + << " x " << maxX << " y " << maxY << " z " << minZ << " - " << maxZ << " ", + 4); + }; + void operator()(const tbb::blocked_range &__r) const + { + for (IndexInt idx = __r.begin(); idx != (IndexInt)__r.end(); idx++) + op(idx, a, b, keepMax); + } + void run() + { + tbb::parallel_for(tbb::blocked_range(0, size), *this); + } + Grid &a; + const Grid &b; + bool keepMax; +}; +struct knJoinInt : public KernelBase { + knJoinInt(Grid &a, const Grid &b, bool keepMax) + : KernelBase(&a, 0), a(a), b(b), keepMax(keepMax) + { + runMessage(); + run(); + } + inline void op(IndexInt idx, Grid &a, const Grid &b, bool keepMax) const + { + a[idx] = (keepMax) ? max(a[idx], b[idx]) : min(a[idx], b[idx]); + } + inline Grid &getArg0() + { + return a; + } + typedef Grid type0; + inline const Grid &getArg1() + { + return b; + } + typedef Grid type1; + inline bool &getArg2() + { + return keepMax; + } + typedef bool type2; + void runMessage() + { + debMsg("Executing kernel knJoinInt ", 3); + debMsg("Kernel range" + << " x " << maxX << " y " << maxY << " z " << minZ << " - " << maxZ << " ", + 4); + }; + void operator()(const tbb::blocked_range &__r) const + { + for (IndexInt idx = __r.begin(); idx != (IndexInt)__r.end(); idx++) + op(idx, a, b, keepMax); + } + void run() + { + tbb::parallel_for(tbb::blocked_range(0, size), *this); + } + Grid &a; + const Grid &b; + bool keepMax; +}; +struct knJoinReal : public KernelBase { + knJoinReal(Grid &a, const Grid &b, bool keepMax) + : KernelBase(&a, 0), a(a), b(b), keepMax(keepMax) + { + runMessage(); + run(); + } + inline void op(IndexInt idx, Grid &a, const Grid &b, bool keepMax) const + { + a[idx] = (keepMax) ? max(a[idx], b[idx]) : min(a[idx], b[idx]); + } + inline Grid &getArg0() + { + return a; + } + typedef Grid type0; + inline const Grid &getArg1() + { + return b; + } + typedef Grid type1; + inline bool &getArg2() + { + return keepMax; + } + typedef bool type2; + void runMessage() + { + debMsg("Executing kernel knJoinReal ", 3); + debMsg("Kernel range" + << " x " << maxX << " y " << maxY << " z " << minZ << " - " << maxZ << " ", + 4); + }; + void operator()(const tbb::blocked_range &__r) const + { + for (IndexInt idx = __r.begin(); idx != (IndexInt)__r.end(); idx++) + op(idx, a, b, keepMax); + } + void run() + { + tbb::parallel_for(tbb::blocked_range(0, size), *this); + } + Grid &a; + const Grid &b; + bool keepMax; +}; + template Grid &Grid::safeDivide(const Grid &a) { knGridSafeDiv(*this, a); @@ -928,6 +1069,18 @@ void Grid::permuteAxesCopyToGrid(int axis0, int axis1, int axis2, Grid &ou "Permuted grids must have the same dimensions!"); knPermuteAxes(*this, out, axis0, axis1, axis2); } +template<> void Grid::join(const Grid &a, bool keepMax) +{ + knJoinVec(*this, a, keepMax); +} +template<> void Grid::join(const Grid &a, bool keepMax) +{ + knJoinInt(*this, a, keepMax); +} +template<> void Grid::join(const Grid &a, bool keepMax) +{ + knJoinReal(*this, a, keepMax); +} template<> Real Grid::getMax() const { diff --git a/extern/mantaflow/preprocessed/grid.h b/extern/mantaflow/preprocessed/grid.h index 6abe3a2b08a..fe386cfc269 100644 --- a/extern/mantaflow/preprocessed/grid.h +++ b/extern/mantaflow/preprocessed/grid.h @@ -966,10 +966,38 @@ template class Grid : public GridBase { } } + //! join other grid by either keeping min or max value at cell + void join(const Grid &a, bool keepMax = true); + static PyObject *_W_27(PyObject *_self, PyObject *_linargs, PyObject *_kwds) + { + try { + PbArgs _args(_linargs, _kwds); + Grid *pbo = dynamic_cast(Pb::objFromPy(_self)); + bool noTiming = _args.getOpt("notiming", -1, 0); + pbPreparePlugin(pbo->getParent(), "Grid::join", !noTiming); + PyObject *_retval = 0; + { + ArgLocker _lock; + const Grid &a = *_args.getPtr>("a", 0, &_lock); + bool keepMax = _args.getOpt("keepMax", 1, true, &_lock); + pbo->_args.copy(_args); + _retval = getPyNone(); + pbo->join(a, keepMax); + pbo->_args.check(); + } + pbFinalizePlugin(pbo->getParent(), "Grid::join", !noTiming); + return _retval; + } + catch (std::exception &e) { + pbSetError("Grid::join", e.what()); + return 0; + } + } + // common compound operators //! get absolute max value in grid Real getMaxAbs() const; - static PyObject *_W_27(PyObject *_self, PyObject *_linargs, PyObject *_kwds) + static PyObject *_W_28(PyObject *_self, PyObject *_linargs, PyObject *_kwds) { try { PbArgs _args(_linargs, _kwds); @@ -994,7 +1022,7 @@ template class Grid : public GridBase { //! get max value in grid Real getMax() const; - static PyObject *_W_28(PyObject *_self, PyObject *_linargs, PyObject *_kwds) + static PyObject *_W_29(PyObject *_self, PyObject *_linargs, PyObject *_kwds) { try { PbArgs _args(_linargs, _kwds); @@ -1019,7 +1047,7 @@ template class Grid : public GridBase { //! get min value in grid Real getMin() const; - static PyObject *_W_29(PyObject *_self, PyObject *_linargs, PyObject *_kwds) + static PyObject *_W_30(PyObject *_self, PyObject *_linargs, PyObject *_kwds) { try { PbArgs _args(_linargs, _kwds); @@ -1044,7 +1072,7 @@ template class Grid : public GridBase { //! calculate L1 norm of grid content Real getL1(int bnd = 0); - static PyObject *_W_30(PyObject *_self, PyObject *_linargs, PyObject *_kwds) + static PyObject *_W_31(PyObject *_self, PyObject *_linargs, PyObject *_kwds) { try { PbArgs _args(_linargs, _kwds); @@ -1070,7 +1098,7 @@ template class Grid : public GridBase { //! calculate L2 norm of grid content Real getL2(int bnd = 0); - static PyObject *_W_31(PyObject *_self, PyObject *_linargs, PyObject *_kwds) + static PyObject *_W_32(PyObject *_self, PyObject *_linargs, PyObject *_kwds) { try { PbArgs _args(_linargs, _kwds); @@ -1096,7 +1124,7 @@ template class Grid : public GridBase { //! set all boundary cells to constant value (Dirichlet) void setBound(T value, int boundaryWidth = 1); - static PyObject *_W_32(PyObject *_self, PyObject *_linargs, PyObject *_kwds) + static PyObject *_W_33(PyObject *_self, PyObject *_linargs, PyObject *_kwds) { try { PbArgs _args(_linargs, _kwds); @@ -1124,7 +1152,7 @@ template class Grid : public GridBase { //! set all boundary cells to last inner value (Neumann) void setBoundNeumann(int boundaryWidth = 1); - static PyObject *_W_33(PyObject *_self, PyObject *_linargs, PyObject *_kwds) + static PyObject *_W_34(PyObject *_self, PyObject *_linargs, PyObject *_kwds) { try { PbArgs _args(_linargs, _kwds); @@ -1151,7 +1179,7 @@ template class Grid : public GridBase { //! get data pointer of grid std::string getDataPointer(); - static PyObject *_W_34(PyObject *_self, PyObject *_linargs, PyObject *_kwds) + static PyObject *_W_35(PyObject *_self, PyObject *_linargs, PyObject *_kwds) { try { PbArgs _args(_linargs, _kwds); @@ -1176,7 +1204,7 @@ template class Grid : public GridBase { //! debugging helper, print grid from python. skip boundary of width bnd void printGrid(int zSlice = -1, bool printIndex = false, int bnd = 1); - static PyObject *_W_35(PyObject *_self, PyObject *_linargs, PyObject *_kwds) + static PyObject *_W_36(PyObject *_self, PyObject *_linargs, PyObject *_kwds) { try { PbArgs _args(_linargs, _kwds); @@ -1244,7 +1272,7 @@ class MACGrid : public Grid { { mType = (GridType)(TypeMAC | TypeVec3); } - static int _W_36(PyObject *_self, PyObject *_linargs, PyObject *_kwds) + static int _W_37(PyObject *_self, PyObject *_linargs, PyObject *_kwds) { PbClass *obj = Pb::objFromPy(_self); if (obj) @@ -1326,7 +1354,7 @@ class MACGrid : public Grid { //! set all boundary cells of a MAC grid to certain value (Dirchlet). Respects staggered grid //! locations optionally, only set normal components void setBoundMAC(Vec3 value, int boundaryWidth, bool normalOnly = false); - static PyObject *_W_37(PyObject *_self, PyObject *_linargs, PyObject *_kwds) + static PyObject *_W_38(PyObject *_self, PyObject *_linargs, PyObject *_kwds) { try { PbArgs _args(_linargs, _kwds); @@ -1367,7 +1395,7 @@ class FlagGrid : public Grid { { mType = (GridType)(TypeFlags | TypeInt); } - static int _W_38(PyObject *_self, PyObject *_linargs, PyObject *_kwds) + static int _W_39(PyObject *_self, PyObject *_linargs, PyObject *_kwds) { PbClass *obj = Pb::objFromPy(_self); if (obj) @@ -1547,7 +1575,7 @@ class FlagGrid : public Grid { const std::string &inflow = " ", const std::string &outflow = " ", Grid *phiWalls = 0x00); - static PyObject *_W_39(PyObject *_self, PyObject *_linargs, PyObject *_kwds) + static PyObject *_W_40(PyObject *_self, PyObject *_linargs, PyObject *_kwds) { try { PbArgs _args(_linargs, _kwds); @@ -1581,7 +1609,7 @@ class FlagGrid : public Grid { //! set fluid flags inside levelset (liquids) void updateFromLevelset(LevelsetGrid &levelset); - static PyObject *_W_40(PyObject *_self, PyObject *_linargs, PyObject *_kwds) + static PyObject *_W_41(PyObject *_self, PyObject *_linargs, PyObject *_kwds) { try { PbArgs _args(_linargs, _kwds); @@ -1608,7 +1636,7 @@ class FlagGrid : public Grid { //! set all cells (except obs/in/outflow) to type (fluid by default) void fillGrid(int type = TypeFluid); - static PyObject *_W_41(PyObject *_self, PyObject *_linargs, PyObject *_kwds) + static PyObject *_W_42(PyObject *_self, PyObject *_linargs, PyObject *_kwds) { try { PbArgs _args(_linargs, _kwds); @@ -1637,7 +1665,7 @@ class FlagGrid : public Grid { //! warning for large grids! only regular int returned (due to python interface) //! optionally creates mask in RealGrid (1 where flag matches, 0 otherwise) int countCells(int flag, int bnd = 0, Grid *mask = NULL); - static PyObject *_W_42(PyObject *_self, PyObject *_linargs, PyObject *_kwds) + static PyObject *_W_43(PyObject *_self, PyObject *_linargs, PyObject *_kwds) { try { PbArgs _args(_linargs, _kwds); diff --git a/extern/mantaflow/preprocessed/grid.h.reg.cpp b/extern/mantaflow/preprocessed/grid.h.reg.cpp index 70c4d8de453..9fe3e7298fa 100644 --- a/extern/mantaflow/preprocessed/grid.h.reg.cpp +++ b/extern/mantaflow/preprocessed/grid.h.reg.cpp @@ -8,11 +8,11 @@ namespace Manta { #ifdef _C_FlagGrid static const Pb::Register _R_26("FlagGrid", "FlagGrid", "Grid"); template<> const char *Namify::S = "FlagGrid"; -static const Pb::Register _R_27("FlagGrid", "FlagGrid", FlagGrid::_W_38); -static const Pb::Register _R_28("FlagGrid", "initDomain", FlagGrid::_W_39); -static const Pb::Register _R_29("FlagGrid", "updateFromLevelset", FlagGrid::_W_40); -static const Pb::Register _R_30("FlagGrid", "fillGrid", FlagGrid::_W_41); -static const Pb::Register _R_31("FlagGrid", "countCells", FlagGrid::_W_42); +static const Pb::Register _R_27("FlagGrid", "FlagGrid", FlagGrid::_W_39); +static const Pb::Register _R_28("FlagGrid", "initDomain", FlagGrid::_W_40); +static const Pb::Register _R_29("FlagGrid", "updateFromLevelset", FlagGrid::_W_41); +static const Pb::Register _R_30("FlagGrid", "fillGrid", FlagGrid::_W_42); +static const Pb::Register _R_31("FlagGrid", "countCells", FlagGrid::_W_43); #endif #ifdef _C_Grid static const Pb::Register _R_32("Grid", "Grid", "GridBase"); @@ -35,92 +35,95 @@ static const Pb::Register _R_47("Grid", "clamp", Grid::_W_23); static const Pb::Register _R_48("Grid", "stomp", Grid::_W_24); static const Pb::Register _R_49("Grid", "permuteAxes", Grid::_W_25); static const Pb::Register _R_50("Grid", "permuteAxesCopyToGrid", Grid::_W_26); -static const Pb::Register _R_51("Grid", "getMaxAbs", Grid::_W_27); -static const Pb::Register _R_52("Grid", "getMax", Grid::_W_28); -static const Pb::Register _R_53("Grid", "getMin", Grid::_W_29); -static const Pb::Register _R_54("Grid", "getL1", Grid::_W_30); -static const Pb::Register _R_55("Grid", "getL2", Grid::_W_31); -static const Pb::Register _R_56("Grid", "setBound", Grid::_W_32); -static const Pb::Register _R_57("Grid", "setBoundNeumann", Grid::_W_33); -static const Pb::Register _R_58("Grid", "getDataPointer", Grid::_W_34); -static const Pb::Register _R_59("Grid", "printGrid", Grid::_W_35); -static const Pb::Register _R_60("Grid", "Grid", "GridBase"); +static const Pb::Register _R_51("Grid", "join", Grid::_W_27); +static const Pb::Register _R_52("Grid", "getMaxAbs", Grid::_W_28); +static const Pb::Register _R_53("Grid", "getMax", Grid::_W_29); +static const Pb::Register _R_54("Grid", "getMin", Grid::_W_30); +static const Pb::Register _R_55("Grid", "getL1", Grid::_W_31); +static const Pb::Register _R_56("Grid", "getL2", Grid::_W_32); +static const Pb::Register _R_57("Grid", "setBound", Grid::_W_33); +static const Pb::Register _R_58("Grid", "setBoundNeumann", Grid::_W_34); +static const Pb::Register _R_59("Grid", "getDataPointer", Grid::_W_35); +static const Pb::Register _R_60("Grid", "printGrid", Grid::_W_36); +static const Pb::Register _R_61("Grid", "Grid", "GridBase"); template<> const char *Namify>::S = "Grid"; -static const Pb::Register _R_61("Grid", "Grid", Grid::_W_9); -static const Pb::Register _R_62("Grid", "save", Grid::_W_10); -static const Pb::Register _R_63("Grid", "load", Grid::_W_11); -static const Pb::Register _R_64("Grid", "clear", Grid::_W_12); -static const Pb::Register _R_65("Grid", "copyFrom", Grid::_W_13); -static const Pb::Register _R_66("Grid", "getGridType", Grid::_W_14); -static const Pb::Register _R_67("Grid", "add", Grid::_W_15); -static const Pb::Register _R_68("Grid", "sub", Grid::_W_16); -static const Pb::Register _R_69("Grid", "setConst", Grid::_W_17); -static const Pb::Register _R_70("Grid", "addConst", Grid::_W_18); -static const Pb::Register _R_71("Grid", "addScaled", Grid::_W_19); -static const Pb::Register _R_72("Grid", "mult", Grid::_W_20); -static const Pb::Register _R_73("Grid", "multConst", Grid::_W_21); -static const Pb::Register _R_74("Grid", "safeDivide", Grid::_W_22); -static const Pb::Register _R_75("Grid", "clamp", Grid::_W_23); -static const Pb::Register _R_76("Grid", "stomp", Grid::_W_24); -static const Pb::Register _R_77("Grid", "permuteAxes", Grid::_W_25); -static const Pb::Register _R_78("Grid", "permuteAxesCopyToGrid", Grid::_W_26); -static const Pb::Register _R_79("Grid", "getMaxAbs", Grid::_W_27); -static const Pb::Register _R_80("Grid", "getMax", Grid::_W_28); -static const Pb::Register _R_81("Grid", "getMin", Grid::_W_29); -static const Pb::Register _R_82("Grid", "getL1", Grid::_W_30); -static const Pb::Register _R_83("Grid", "getL2", Grid::_W_31); -static const Pb::Register _R_84("Grid", "setBound", Grid::_W_32); -static const Pb::Register _R_85("Grid", "setBoundNeumann", Grid::_W_33); -static const Pb::Register _R_86("Grid", "getDataPointer", Grid::_W_34); -static const Pb::Register _R_87("Grid", "printGrid", Grid::_W_35); -static const Pb::Register _R_88("Grid", "Grid", "GridBase"); +static const Pb::Register _R_62("Grid", "Grid", Grid::_W_9); +static const Pb::Register _R_63("Grid", "save", Grid::_W_10); +static const Pb::Register _R_64("Grid", "load", Grid::_W_11); +static const Pb::Register _R_65("Grid", "clear", Grid::_W_12); +static const Pb::Register _R_66("Grid", "copyFrom", Grid::_W_13); +static const Pb::Register _R_67("Grid", "getGridType", Grid::_W_14); +static const Pb::Register _R_68("Grid", "add", Grid::_W_15); +static const Pb::Register _R_69("Grid", "sub", Grid::_W_16); +static const Pb::Register _R_70("Grid", "setConst", Grid::_W_17); +static const Pb::Register _R_71("Grid", "addConst", Grid::_W_18); +static const Pb::Register _R_72("Grid", "addScaled", Grid::_W_19); +static const Pb::Register _R_73("Grid", "mult", Grid::_W_20); +static const Pb::Register _R_74("Grid", "multConst", Grid::_W_21); +static const Pb::Register _R_75("Grid", "safeDivide", Grid::_W_22); +static const Pb::Register _R_76("Grid", "clamp", Grid::_W_23); +static const Pb::Register _R_77("Grid", "stomp", Grid::_W_24); +static const Pb::Register _R_78("Grid", "permuteAxes", Grid::_W_25); +static const Pb::Register _R_79("Grid", "permuteAxesCopyToGrid", Grid::_W_26); +static const Pb::Register _R_80("Grid", "join", Grid::_W_27); +static const Pb::Register _R_81("Grid", "getMaxAbs", Grid::_W_28); +static const Pb::Register _R_82("Grid", "getMax", Grid::_W_29); +static const Pb::Register _R_83("Grid", "getMin", Grid::_W_30); +static const Pb::Register _R_84("Grid", "getL1", Grid::_W_31); +static const Pb::Register _R_85("Grid", "getL2", Grid::_W_32); +static const Pb::Register _R_86("Grid", "setBound", Grid::_W_33); +static const Pb::Register _R_87("Grid", "setBoundNeumann", Grid::_W_34); +static const Pb::Register _R_88("Grid", "getDataPointer", Grid::_W_35); +static const Pb::Register _R_89("Grid", "printGrid", Grid::_W_36); +static const Pb::Register _R_90("Grid", "Grid", "GridBase"); template<> const char *Namify>::S = "Grid"; -static const Pb::Register _R_89("Grid", "Grid", Grid::_W_9); -static const Pb::Register _R_90("Grid", "save", Grid::_W_10); -static const Pb::Register _R_91("Grid", "load", Grid::_W_11); -static const Pb::Register _R_92("Grid", "clear", Grid::_W_12); -static const Pb::Register _R_93("Grid", "copyFrom", Grid::_W_13); -static const Pb::Register _R_94("Grid", "getGridType", Grid::_W_14); -static const Pb::Register _R_95("Grid", "add", Grid::_W_15); -static const Pb::Register _R_96("Grid", "sub", Grid::_W_16); -static const Pb::Register _R_97("Grid", "setConst", Grid::_W_17); -static const Pb::Register _R_98("Grid", "addConst", Grid::_W_18); -static const Pb::Register _R_99("Grid", "addScaled", Grid::_W_19); -static const Pb::Register _R_100("Grid", "mult", Grid::_W_20); -static const Pb::Register _R_101("Grid", "multConst", Grid::_W_21); -static const Pb::Register _R_102("Grid", "safeDivide", Grid::_W_22); -static const Pb::Register _R_103("Grid", "clamp", Grid::_W_23); -static const Pb::Register _R_104("Grid", "stomp", Grid::_W_24); -static const Pb::Register _R_105("Grid", "permuteAxes", Grid::_W_25); -static const Pb::Register _R_106("Grid", "permuteAxesCopyToGrid", Grid::_W_26); -static const Pb::Register _R_107("Grid", "getMaxAbs", Grid::_W_27); -static const Pb::Register _R_108("Grid", "getMax", Grid::_W_28); -static const Pb::Register _R_109("Grid", "getMin", Grid::_W_29); -static const Pb::Register _R_110("Grid", "getL1", Grid::_W_30); -static const Pb::Register _R_111("Grid", "getL2", Grid::_W_31); -static const Pb::Register _R_112("Grid", "setBound", Grid::_W_32); -static const Pb::Register _R_113("Grid", "setBoundNeumann", Grid::_W_33); -static const Pb::Register _R_114("Grid", "getDataPointer", Grid::_W_34); -static const Pb::Register _R_115("Grid", "printGrid", Grid::_W_35); +static const Pb::Register _R_91("Grid", "Grid", Grid::_W_9); +static const Pb::Register _R_92("Grid", "save", Grid::_W_10); +static const Pb::Register _R_93("Grid", "load", Grid::_W_11); +static const Pb::Register _R_94("Grid", "clear", Grid::_W_12); +static const Pb::Register _R_95("Grid", "copyFrom", Grid::_W_13); +static const Pb::Register _R_96("Grid", "getGridType", Grid::_W_14); +static const Pb::Register _R_97("Grid", "add", Grid::_W_15); +static const Pb::Register _R_98("Grid", "sub", Grid::_W_16); +static const Pb::Register _R_99("Grid", "setConst", Grid::_W_17); +static const Pb::Register _R_100("Grid", "addConst", Grid::_W_18); +static const Pb::Register _R_101("Grid", "addScaled", Grid::_W_19); +static const Pb::Register _R_102("Grid", "mult", Grid::_W_20); +static const Pb::Register _R_103("Grid", "multConst", Grid::_W_21); +static const Pb::Register _R_104("Grid", "safeDivide", Grid::_W_22); +static const Pb::Register _R_105("Grid", "clamp", Grid::_W_23); +static const Pb::Register _R_106("Grid", "stomp", Grid::_W_24); +static const Pb::Register _R_107("Grid", "permuteAxes", Grid::_W_25); +static const Pb::Register _R_108("Grid", "permuteAxesCopyToGrid", Grid::_W_26); +static const Pb::Register _R_109("Grid", "join", Grid::_W_27); +static const Pb::Register _R_110("Grid", "getMaxAbs", Grid::_W_28); +static const Pb::Register _R_111("Grid", "getMax", Grid::_W_29); +static const Pb::Register _R_112("Grid", "getMin", Grid::_W_30); +static const Pb::Register _R_113("Grid", "getL1", Grid::_W_31); +static const Pb::Register _R_114("Grid", "getL2", Grid::_W_32); +static const Pb::Register _R_115("Grid", "setBound", Grid::_W_33); +static const Pb::Register _R_116("Grid", "setBoundNeumann", Grid::_W_34); +static const Pb::Register _R_117("Grid", "getDataPointer", Grid::_W_35); +static const Pb::Register _R_118("Grid", "printGrid", Grid::_W_36); #endif #ifdef _C_GridBase -static const Pb::Register _R_116("GridBase", "GridBase", "PbClass"); +static const Pb::Register _R_119("GridBase", "GridBase", "PbClass"); template<> const char *Namify::S = "GridBase"; -static const Pb::Register _R_117("GridBase", "GridBase", GridBase::_W_0); -static const Pb::Register _R_118("GridBase", "getSizeX", GridBase::_W_1); -static const Pb::Register _R_119("GridBase", "getSizeY", GridBase::_W_2); -static const Pb::Register _R_120("GridBase", "getSizeZ", GridBase::_W_3); -static const Pb::Register _R_121("GridBase", "getSize", GridBase::_W_4); -static const Pb::Register _R_122("GridBase", "is3D", GridBase::_W_5); -static const Pb::Register _R_123("GridBase", "is4D", GridBase::_W_6); -static const Pb::Register _R_124("GridBase", "getSizeT", GridBase::_W_7); -static const Pb::Register _R_125("GridBase", "getStrideT", GridBase::_W_8); +static const Pb::Register _R_120("GridBase", "GridBase", GridBase::_W_0); +static const Pb::Register _R_121("GridBase", "getSizeX", GridBase::_W_1); +static const Pb::Register _R_122("GridBase", "getSizeY", GridBase::_W_2); +static const Pb::Register _R_123("GridBase", "getSizeZ", GridBase::_W_3); +static const Pb::Register _R_124("GridBase", "getSize", GridBase::_W_4); +static const Pb::Register _R_125("GridBase", "is3D", GridBase::_W_5); +static const Pb::Register _R_126("GridBase", "is4D", GridBase::_W_6); +static const Pb::Register _R_127("GridBase", "getSizeT", GridBase::_W_7); +static const Pb::Register _R_128("GridBase", "getStrideT", GridBase::_W_8); #endif #ifdef _C_MACGrid -static const Pb::Register _R_126("MACGrid", "MACGrid", "Grid"); +static const Pb::Register _R_129("MACGrid", "MACGrid", "Grid"); template<> const char *Namify::S = "MACGrid"; -static const Pb::Register _R_127("MACGrid", "MACGrid", MACGrid::_W_36); -static const Pb::Register _R_128("MACGrid", "setBoundMAC", MACGrid::_W_37); +static const Pb::Register _R_130("MACGrid", "MACGrid", MACGrid::_W_37); +static const Pb::Register _R_131("MACGrid", "setBoundMAC", MACGrid::_W_38); #endif static const Pb::Register _R_7("GridType_TypeNone", 0); static const Pb::Register _R_8("GridType_TypeReal", 1); @@ -247,6 +250,9 @@ void PbRegister_file_7() KEEP_UNUSED(_R_126); KEEP_UNUSED(_R_127); KEEP_UNUSED(_R_128); + KEEP_UNUSED(_R_129); + KEEP_UNUSED(_R_130); + KEEP_UNUSED(_R_131); } } } // namespace Manta \ No newline at end of file diff --git a/extern/mantaflow/preprocessed/plugin/secondaryparticles.cpp b/extern/mantaflow/preprocessed/plugin/secondaryparticles.cpp index 18582d57e64..23f5e23d99d 100644 --- a/extern/mantaflow/preprocessed/plugin/secondaryparticles.cpp +++ b/extern/mantaflow/preprocessed/plugin/secondaryparticles.cpp @@ -1834,7 +1834,7 @@ struct knFlipDeleteParticlesInObstacle : public KernelBase { } int gridIndex = flags.index(xidx); // remove particles that penetrate obstacles - if (flags[gridIndex] == FlagGrid::TypeObstacle || flags[gridIndex] == FlagGrid::TypeOutflow) { + if (flags.isObstacle(gridIndex) || flags.isOutflow(gridIndex)) { pts.kill(idx); } } -- cgit v1.2.3 From c2cb87f8976b813821a5166686d7625fbe384ba8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Barschkis?= Date: Wed, 8 Apr 2020 13:27:12 +0200 Subject: Fluid: Fix problem with inconsistent noise when using multiple adaptive time-steps Problem was mentioned in T74062. --- intern/mantaflow/intern/strings/smoke_script.h | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/intern/mantaflow/intern/strings/smoke_script.h b/intern/mantaflow/intern/strings/smoke_script.h index 0f265fcb7ac..7a855ff2cb8 100644 --- a/intern/mantaflow/intern/strings/smoke_script.h +++ b/intern/mantaflow/intern/strings/smoke_script.h @@ -82,6 +82,7 @@ const std::string smoke_alloc = "\n\ mantaMsg('Smoke alloc')\n\ shadow_s$ID$ = s$ID$.create(RealGrid)\n\ +emission_s$ID$ = s$ID$.create(RealGrid)\n\ emissionIn_s$ID$ = s$ID$.create(RealGrid)\n\ density_s$ID$ = s$ID$.create(RealGrid)\n\ densityIn_s$ID$ = s$ID$.create(RealGrid)\n\ @@ -101,7 +102,7 @@ color_b_in_s$ID$ = None\n\ \n\ # Keep track of important objects in dict to load them later on\n\ smoke_data_dict_final_s$ID$ = dict(density=density_s$ID$, shadow=shadow_s$ID$)\n\ -smoke_data_dict_resume_s$ID$ = dict(densityIn=densityIn_s$ID$, emissionIn=emissionIn_s$ID$)\n"; +smoke_data_dict_resume_s$ID$ = dict(densityIn=densityIn_s$ID$, emission=emission_s$ID$)\n"; const std::string smoke_alloc_noise = "\n\ @@ -300,6 +301,9 @@ def smoke_adaptive_step_$ID$(framenr):\n\ setObstacleFlags(flags=flags_s$ID$, phiObs=phiObs_s$ID$, phiOut=phiOut_s$ID$, phiIn=phiIn_s$ID$, boundaryWidth=1)\n\ flags_s$ID$.fillGrid()\n\ \n\ + # accumulate emission value per adaptive step for later use in noise computation\n\ + emission_s$ID$.join(emissionIn_s$ID$)\n\ + \n\ applyEmission(flags=flags_s$ID$, target=density_s$ID$, source=densityIn_s$ID$, emissionTexture=emissionIn_s$ID$, type=FlagInflow|FlagOutflow)\n\ if using_heat_s$ID$:\n\ applyEmission(flags=flags_s$ID$, target=heat_s$ID$, source=heatIn_s$ID$, emissionTexture=emissionIn_s$ID$, type=FlagInflow|FlagOutflow)\n\ @@ -437,7 +441,7 @@ def smoke_step_noise_$ID$(framenr):\n\ \n\ # Interpolate emission grids and apply them to big noise grids\n\ tmpIn_sn$ID$.copyFrom(densityIn_s$ID$) if upres_sn$ID$ <= 1 else interpolateGrid(source=densityIn_s$ID$, target=tmpIn_sn$ID$)\n\ - emissionIn_sn$ID$.copyFrom(emissionIn_s$ID$) if upres_sn$ID$ <= 1 else interpolateGrid(source=emissionIn_s$ID$, target=emissionIn_sn$ID$)\n\ + emissionIn_sn$ID$.copyFrom(emission_s$ID$) if upres_sn$ID$ <= 1 else interpolateGrid(source=emission_s$ID$, target=emissionIn_sn$ID$)\n\ \n\ # Higher-res noise grid needs scaled emission values\n\ tmpIn_sn$ID$.multConst(float(upres_sn$ID$))\n\ -- cgit v1.2.3 From ff2c67d7e8ed334c482681e2342bf8cce0957546 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Barschkis?= Date: Wed, 8 Apr 2020 13:42:40 +0200 Subject: Fluid: Disable subframes when using adaptive time-steps in the first frame First frame should only produce inflow once and not compute the emission for the frame before the first frame. Problem became evident in T74062. --- source/blender/blenkernel/intern/fluid.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/source/blender/blenkernel/intern/fluid.c b/source/blender/blenkernel/intern/fluid.c index 985d0a79b23..e96f65751de 100644 --- a/source/blender/blenkernel/intern/fluid.c +++ b/source/blender/blenkernel/intern/fluid.c @@ -1250,7 +1250,8 @@ static void update_obstacles(Depsgraph *depsgraph, /* Set scene time */ /* Handle emission subframe */ - if (subframe < subframes || time_per_frame + dt + FLT_EPSILON < frame_length) { + if ((subframe < subframes || time_per_frame + dt + FLT_EPSILON < frame_length) && + !is_first_frame) { scene->r.subframe = (time_per_frame + (subframe + 1.0f) * subframe_dt) / frame_length; scene->r.cfra = frame - 1; } @@ -2763,7 +2764,8 @@ static void update_flowsfluids(struct Depsgraph *depsgraph, FluidObjectBB bb_temp = {NULL}; /* Set scene time */ - if (subframe < subframes || time_per_frame + dt + FLT_EPSILON < frame_length) { + if ((subframe < subframes || time_per_frame + dt + FLT_EPSILON < frame_length) && + !is_first_frame) { scene->r.subframe = (time_per_frame + (subframe + 1.0f) * subframe_dt) / frame_length; scene->r.cfra = frame - 1; } -- cgit v1.2.3 From fd487b1f4ec0ab06ccf5bc3f6561096a755cdce2 Mon Sep 17 00:00:00 2001 From: Brecht Van Lommel Date: Wed, 8 Apr 2020 14:02:38 +0200 Subject: Fix build error with WITH_X11_XINPUT=OFF after recent changes --- intern/ghost/intern/GHOST_SystemX11.cpp | 4 ---- intern/ghost/intern/GHOST_WindowX11.cpp | 3 +-- intern/ghost/intern/GHOST_WindowX11.h | 5 +---- 3 files changed, 2 insertions(+), 10 deletions(-) diff --git a/intern/ghost/intern/GHOST_SystemX11.cpp b/intern/ghost/intern/GHOST_SystemX11.cpp index ca511073ea1..aebf829a546 100644 --- a/intern/ghost/intern/GHOST_SystemX11.cpp +++ b/intern/ghost/intern/GHOST_SystemX11.cpp @@ -960,11 +960,7 @@ void GHOST_SystemX11::processEvent(XEvent *xe) case MotionNotify: { XMotionEvent &xme = xe->xmotion; -#ifdef WITH_X11_XINPUT bool is_tablet = window->GetTabletData().Active != GHOST_kTabletModeNone; -#else - bool is_tablet = false; -#endif if (is_tablet == false && window->getCursorGrabModeIsWarp()) { GHOST_TInt32 x_new = xme.x_root; diff --git a/intern/ghost/intern/GHOST_WindowX11.cpp b/intern/ghost/intern/GHOST_WindowX11.cpp index 363a8145c5a..db9f6846b11 100644 --- a/intern/ghost/intern/GHOST_WindowX11.cpp +++ b/intern/ghost/intern/GHOST_WindowX11.cpp @@ -239,6 +239,7 @@ GHOST_WindowX11::GHOST_WindowX11(GHOST_SystemX11 *system, #ifdef WITH_XDND m_dropTarget(NULL), #endif + m_tabletData(GHOST_TABLET_DATA_NONE), #if defined(WITH_X11_XINPUT) && defined(X_HAVE_UTF8_STRING) m_xic(NULL), #endif @@ -498,8 +499,6 @@ GHOST_WindowX11::GHOST_WindowX11(GHOST_SystemX11 *system, #ifdef WITH_X11_XINPUT refreshXInputDevices(); - - m_tabletData = GHOST_TABLET_DATA_NONE; #endif /* now set up the rendering context. */ diff --git a/intern/ghost/intern/GHOST_WindowX11.h b/intern/ghost/intern/GHOST_WindowX11.h index a9914d88340..4704cb45e58 100644 --- a/intern/ghost/intern/GHOST_WindowX11.h +++ b/intern/ghost/intern/GHOST_WindowX11.h @@ -144,12 +144,11 @@ class GHOST_WindowX11 : public GHOST_Window { * Return a handle to the x11 window type. */ Window getXWindow(); -#ifdef WITH_X11_XINPUT + GHOST_TabletData &GetTabletData() { return m_tabletData; } -#endif // WITH_X11_XINPUT #if defined(WITH_X11_XINPUT) && defined(X_HAVE_UTF8_STRING) XIC getX11_XIC() @@ -269,9 +268,7 @@ class GHOST_WindowX11 : public GHOST_Window { GHOST_DropTargetX11 *m_dropTarget; #endif -#ifdef WITH_X11_XINPUT GHOST_TabletData m_tabletData; -#endif #if defined(WITH_X11_XINPUT) && defined(X_HAVE_UTF8_STRING) XIC m_xic; -- cgit v1.2.3 From 91d7f5d2463495f20f1e3a985241a2672961ad3f Mon Sep 17 00:00:00 2001 From: Brecht Van Lommel Date: Wed, 8 Apr 2020 14:09:10 +0200 Subject: Fix T74572: adaptive sampling still not working correct with shader AOVs --- intern/cycles/render/film.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/intern/cycles/render/film.cpp b/intern/cycles/render/film.cpp index f28c943ea6c..26eda93fadd 100644 --- a/intern/cycles/render/film.cpp +++ b/intern/cycles/render/film.cpp @@ -500,16 +500,16 @@ void Film::device_update(Device *device, DeviceScene *dscene, Scene *scene) kfilm->pass_sample_count = kfilm->pass_stride; break; case PASS_AOV_COLOR: - if (kfilm->pass_aov_value_num == 0) { + if (kfilm->pass_aov_color_num == 0) { kfilm->pass_aov_color = kfilm->pass_stride; } - kfilm->pass_aov_value_num++; + kfilm->pass_aov_color_num++; break; case PASS_AOV_VALUE: - if (kfilm->pass_aov_color_num == 0) { + if (kfilm->pass_aov_value_num == 0) { kfilm->pass_aov_value = kfilm->pass_stride; } - kfilm->pass_aov_color_num++; + kfilm->pass_aov_value_num++; break; default: assert(false); -- cgit v1.2.3 From 34b28850bf86d674df428cddf0920c2853ebadb9 Mon Sep 17 00:00:00 2001 From: Germano Cavalcante Date: Wed, 8 Apr 2020 09:44:26 -0300 Subject: Fix wrong material indicated in the error message when baking The material displayed in the error message due to the lack of active texture was that of the previous slot. --- source/blender/editors/object/object_bake_api.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/source/blender/editors/object/object_bake_api.c b/source/blender/editors/object/object_bake_api.c index d625b770164..debad321583 100644 --- a/source/blender/editors/object/object_bake_api.c +++ b/source/blender/editors/object/object_bake_api.c @@ -446,7 +446,8 @@ static bool bake_object_check(ViewLayer *view_layer, Object *ob, ReportList *rep for (i = 0; i < ob->totcol; i++) { bNodeTree *ntree = NULL; bNode *node = NULL; - ED_object_get_active_image(ob, i + 1, &image, NULL, &node, &ntree); + const int mat_nr = i + 1; + ED_object_get_active_image(ob, mat_nr, &image, NULL, &node, &ntree); if (image) { ImBuf *ibuf; @@ -481,7 +482,7 @@ static bool bake_object_check(ViewLayer *view_layer, Object *ob, ReportList *rep } } else { - Material *mat = BKE_object_material_get(ob, i); + Material *mat = BKE_object_material_get(ob, mat_nr); if (mat != NULL) { BKE_reportf(reports, RPT_INFO, -- cgit v1.2.3 From 020d1e23aee934dfad5fabc4038362cb8adf6c2a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Barschkis?= Date: Wed, 8 Apr 2020 16:25:00 +0200 Subject: Fluid: Fix issue with mesh not being loaded Fixed an issue that was likely introduced in a past cleanup. --- intern/mantaflow/intern/MANTA_main.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/intern/mantaflow/intern/MANTA_main.cpp b/intern/mantaflow/intern/MANTA_main.cpp index 293abae1b3a..79c8625ec48 100644 --- a/intern/mantaflow/intern/MANTA_main.cpp +++ b/intern/mantaflow/intern/MANTA_main.cpp @@ -1098,12 +1098,14 @@ bool MANTA::updateMeshStructures(FluidModifierData *mmd, int framenr) int expected = 0; /* Expected number of read successes for this frame. */ /* Ensure empty data structures at start. */ - if (!mMeshNodes || !mMeshTriangles || !mMeshVelocities) + if (!mMeshNodes || !mMeshTriangles) return false; mMeshNodes->clear(); mMeshTriangles->clear(); - mMeshVelocities->clear(); + + if (mMeshVelocities) + mMeshVelocities->clear(); std::string mformat = getCacheFileEnding(mmd->domain->cache_mesh_format); std::string dformat = getCacheFileEnding(mmd->domain->cache_data_format); -- cgit v1.2.3 From b0f229dd276bffa838da0efb580eee9f3c61b79d Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Wed, 8 Apr 2020 17:19:02 +0200 Subject: Tracking: Fix missing distortion update on focal length change --- source/blender/blenkernel/intern/movieclip.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/source/blender/blenkernel/intern/movieclip.c b/source/blender/blenkernel/intern/movieclip.c index 847466915ab..193fe859def 100644 --- a/source/blender/blenkernel/intern/movieclip.c +++ b/source/blender/blenkernel/intern/movieclip.c @@ -456,6 +456,7 @@ typedef struct MovieClipCache { int flag; /* cache for undistorted shot */ + float focal_length; float principal[2]; float polynomial_k[3]; float division_k[2]; @@ -887,6 +888,10 @@ static bool check_undistortion_cache_flags(const MovieClip *clip) const MovieClipCache *cache = clip->cache; const MovieTrackingCamera *camera = &clip->tracking.camera; + if (camera->focal != cache->postprocessed.focal_length) { + return false; + } + /* check for distortion model changes */ if (!equals_v2v2(camera->principal, cache->postprocessed.principal)) { return false; @@ -1001,6 +1006,7 @@ static void put_postprocessed_frame_to_cache( if (need_undistortion_postprocess(user, flag)) { cache->postprocessed.distortion_model = camera->distortion_model; + cache->postprocessed.focal_length = camera->focal; copy_v2_v2(cache->postprocessed.principal, camera->principal); copy_v3_v3(cache->postprocessed.polynomial_k, &camera->k1); copy_v2_v2(cache->postprocessed.division_k, &camera->division_k1); -- cgit v1.2.3 From 2328599e978c51e4563ce6d925387cbd91ac3861 Mon Sep 17 00:00:00 2001 From: Bastien Montagne Date: Wed, 8 Apr 2020 17:41:01 +0200 Subject: NewUndo: Fix (studio-reported) discrepency in proxies when undoing. Took me an unreasonable amount of time to understand what was happening here... Our beloved proxies, as usual, need some specific careful handling. --- source/blender/blenloader/intern/readfile.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c index 898f318f60b..799330a07bf 100644 --- a/source/blender/blenloader/intern/readfile.c +++ b/source/blender/blenloader/intern/readfile.c @@ -9556,6 +9556,20 @@ static void read_libblock_undo_restore_identical( /* Recalc flags, mostly these just remain as they are. */ id_old->recalc |= direct_link_id_restore_recalc_exceptions(id_old); id_old->recalc_undo_accumulated = 0; + + /* As usual, proxies require some special love... + * In `blo_clear_proxy_pointers_from_lib()` we clear all `proxy_from` pointers to local IDs, for + * undo. This is required since we do not re-read linked data in that case, so we also do not + * re-'lib_link' their pointers. + * Those `proxy_from` pointers are then re-defined properly when lib_linking the newly read local + * object. However, in case of re-used data 'as-is', we never lib_link it again, so we have to + * fix those backward pointers here. */ + if (GS(id_old->name) == ID_OB) { + Object *ob = (Object *)id_old; + if (ob->proxy != NULL) { + ob->proxy->proxy_from = ob; + } + } } /* For undo, store changed datablock at old address. */ -- cgit v1.2.3 From 4a6f715421af0d6cc15dc9e7ab6f3f90438d0a3d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Barschkis?= Date: Wed, 8 Apr 2020 18:29:11 +0200 Subject: Fix T73552: Mantaflow - liquid particles show up in organized unrealistic structure Issue was being caused by a particle offset which was random but the same for every particle. --- extern/mantaflow/preprocessed/gitinfo.h | 2 +- extern/mantaflow/preprocessed/plugin/secondaryparticles.cpp | 8 +++----- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/extern/mantaflow/preprocessed/gitinfo.h b/extern/mantaflow/preprocessed/gitinfo.h index 6a26c480392..791dd001bbe 100644 --- a/extern/mantaflow/preprocessed/gitinfo.h +++ b/extern/mantaflow/preprocessed/gitinfo.h @@ -1,3 +1,3 @@ -#define MANTA_GIT_VERSION "commit f3d32c45934fd08c40096fb3510e9cc403730977" +#define MANTA_GIT_VERSION "commit 21303fab2eda588ec22988bf9e5762d2001c131f" diff --git a/extern/mantaflow/preprocessed/plugin/secondaryparticles.cpp b/extern/mantaflow/preprocessed/plugin/secondaryparticles.cpp index 23f5e23d99d..a8913a218c1 100644 --- a/extern/mantaflow/preprocessed/plugin/secondaryparticles.cpp +++ b/extern/mantaflow/preprocessed/plugin/secondaryparticles.cpp @@ -525,7 +525,7 @@ struct knFlipSampleSecondaryParticlesMoreCylinders : public KernelBase { if (!(flags(i, j, k) & itype)) return; - RandomStream mRand(9832); + static RandomStream mRand(9832); Real radius = 0.25; // diameter=0.5 => sampling with two cylinders in each dimension since cell size=1 for (Real x = i - radius; x <= i + radius; x += 2 * radius) { @@ -791,11 +791,9 @@ struct knFlipSampleSecondaryParticles : public KernelBase { const int n = KE * (k_ta * TA + k_wc * WC) * dt; // number of secondary particles if (n == 0) return; - RandomStream mRand(9832); + static RandomStream mRand(9832); - Vec3 xi = Vec3(i + mRand.getReal(), - j + mRand.getReal(), - k + mRand.getReal()); // randomized offset uniform in cell + Vec3 xi = Vec3(i, j, k) + mRand.getVec3(); // randomized offset uniform in cell Vec3 vi = v.getInterpolated(xi); Vec3 dir = dt * vi; // direction of movement of current particle Vec3 e1 = getNormalized(Vec3(dir.z, 0, -dir.x)); // perpendicular to dir -- cgit v1.2.3 From d41d4d059332481b4e9bd9809758791de63f4f74 Mon Sep 17 00:00:00 2001 From: Antonio Vazquez Date: Wed, 8 Apr 2020 19:03:04 +0200 Subject: GPencil: Small changes to brush defaults --- source/blender/blenkernel/intern/brush.c | 38 ++++++++++++++++++++++++++------ 1 file changed, 31 insertions(+), 7 deletions(-) diff --git a/source/blender/blenkernel/intern/brush.c b/source/blender/blenkernel/intern/brush.c index 2306b046026..e1303b8d723 100644 --- a/source/blender/blenkernel/intern/brush.c +++ b/source/blender/blenkernel/intern/brush.c @@ -344,6 +344,7 @@ typedef enum eGPCurveMappingPreset { GPCURVE_PRESET_INK = 1, GPCURVE_PRESET_INKNOISE = 2, GPCURVE_PRESET_MARKER = 3, + GPCURVE_PRESET_CHISEL = 4, } eGPCurveMappingPreset; static void brush_gpencil_curvemap_reset(CurveMap *cuma, int tot, int preset) @@ -375,9 +376,9 @@ static void brush_gpencil_curvemap_reset(CurveMap *cuma, int tot, int preset) case GPCURVE_PRESET_INKNOISE: cuma->curve[0].x = 0.0f; cuma->curve[0].y = 0.0f; - cuma->curve[1].x = 0.63134f; - cuma->curve[1].y = 0.3625f; - cuma->curve[2].x = 1.0f; + cuma->curve[1].x = 0.55f; + cuma->curve[1].y = 0.45f; + cuma->curve[2].x = 0.85f; cuma->curve[2].y = 1.0f; break; case GPCURVE_PRESET_MARKER: @@ -390,6 +391,12 @@ static void brush_gpencil_curvemap_reset(CurveMap *cuma, int tot, int preset) cuma->curve[3].x = 1.0f; cuma->curve[3].y = 1.0f; break; + case GPCURVE_PRESET_CHISEL: + cuma->curve[0].x = 0.0f; + cuma->curve[0].y = 0.0f; + cuma->curve[1].x = 0.8f; + cuma->curve[1].y = 1.0f; + break; } if (cuma->table) { @@ -519,7 +526,7 @@ void BKE_gpencil_brush_preset_set(Main *bmain, Brush *brush, const short type) brush->gpencil_settings->simplify_f = 0.000f; brush->gpencil_settings->flag |= GP_BRUSH_GROUP_RANDOM; - brush->gpencil_settings->draw_random_press = 1.0f; + brush->gpencil_settings->draw_random_press = 0.6f; brush->gpencil_settings->draw_random_strength = 0.0f; brush->gpencil_settings->draw_jitter = 0.0f; brush->gpencil_settings->flag |= GP_BRUSH_USE_JITTER_PRESSURE; @@ -574,7 +581,7 @@ void BKE_gpencil_brush_preset_set(Main *bmain, Brush *brush, const short type) break; } case GP_BRUSH_PRESET_MARKER_CHISEL: { - brush->size = 80.0f; + brush->size = 100.0f; brush->gpencil_settings->flag |= GP_BRUSH_USE_PRESSURE; brush->gpencil_settings->draw_strength = 1.0f; @@ -597,6 +604,12 @@ void BKE_gpencil_brush_preset_set(Main *bmain, Brush *brush, const short type) brush->gpencil_settings->draw_jitter = 0.0f; brush->gpencil_settings->flag |= GP_BRUSH_USE_JITTER_PRESSURE; + /* Curve. */ + custom_curve = brush->gpencil_settings->curve_sensitivity; + BKE_curvemapping_set_defaults(custom_curve, 0, 0.0f, 0.0f, 1.0f, 1.0f); + BKE_curvemapping_initialize(custom_curve); + brush_gpencil_curvemap_reset(custom_curve->cm, 2, GPCURVE_PRESET_CHISEL); + brush->gpencil_settings->icon_id = GP_BRUSH_ICON_CHISEL; brush->gpencil_tool = GPAINT_TOOL_DRAW; @@ -604,7 +617,7 @@ void BKE_gpencil_brush_preset_set(Main *bmain, Brush *brush, const short type) break; } case GP_BRUSH_PRESET_PEN: { - brush->size = 30.0f; + brush->size = 25.0f; brush->gpencil_settings->flag |= GP_BRUSH_USE_PRESSURE; brush->gpencil_settings->draw_strength = 1.0f; @@ -662,11 +675,22 @@ void BKE_gpencil_brush_preset_set(Main *bmain, Brush *brush, const short type) brush->gpencil_settings->icon_id = GP_BRUSH_ICON_PENCIL; brush->gpencil_tool = GPAINT_TOOL_DRAW; + /* Create and link Black Dots material to brush. + * This material is required because the brush uses the material to define how the stroke is + * drawn. */ + Material *ma = BLI_findstring(&bmain->materials, "Dots Stroke", offsetof(ID, name) + 2); + if (ma == NULL) { + ma = BKE_gpencil_material_add(bmain, "Dots Stroke"); + } + brush->gpencil_settings->material = ma; + /* Pin the matterial to the brush. */ + brush->gpencil_settings->flag |= GP_BRUSH_MATERIAL_PINNED; + zero_v3(brush->secondary_rgb); break; } case GP_BRUSH_PRESET_PENCIL: { - brush->size = 25.0f; + brush->size = 20.0f; brush->gpencil_settings->flag |= GP_BRUSH_USE_PRESSURE; brush->gpencil_settings->draw_strength = 0.6f; -- cgit v1.2.3 From f405934fe3d31e650cec9af48a4b6c69fd771b1f Mon Sep 17 00:00:00 2001 From: Brecht Van Lommel Date: Wed, 8 Apr 2020 18:11:25 +0200 Subject: Fix T75445: Filmic transform not working when using Turkish locale This is a bug in OpenColorIO that we work around (see "Turkish I" problem), a proper fix will be submitted upstream. --- release/datafiles/colormanagement/filmic/filmic_desat65cube.spi3d | 2 +- release/datafiles/colormanagement/filmic/filmic_false_color.spi3d | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/release/datafiles/colormanagement/filmic/filmic_desat65cube.spi3d b/release/datafiles/colormanagement/filmic/filmic_desat65cube.spi3d index bd80dd4eae0..66778b93e4e 100644 --- a/release/datafiles/colormanagement/filmic/filmic_desat65cube.spi3d +++ b/release/datafiles/colormanagement/filmic/filmic_desat65cube.spi3d @@ -1,4 +1,4 @@ -SPILUT 1.0 +spilut 1.0 3 3 65 65 65 0 0 0 0.000175781 0.000175781 0.000175781 diff --git a/release/datafiles/colormanagement/filmic/filmic_false_color.spi3d b/release/datafiles/colormanagement/filmic/filmic_false_color.spi3d index d8fcfd4e70d..b81b18ec643 100644 --- a/release/datafiles/colormanagement/filmic/filmic_false_color.spi3d +++ b/release/datafiles/colormanagement/filmic/filmic_false_color.spi3d @@ -1,4 +1,4 @@ -SPILUT 1.0 +spilut 1.0 3 3 65 65 65 0 0 0 0 0 0 -- cgit v1.2.3 From 8360bfb75c36cfe65ee7f5585f2178d17b28eb38 Mon Sep 17 00:00:00 2001 From: Brecht Van Lommel Date: Wed, 8 Apr 2020 21:54:23 +0200 Subject: Cleanup: clang-format --- intern/ghost/intern/GHOST_WindowWin32.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/intern/ghost/intern/GHOST_WindowWin32.h b/intern/ghost/intern/GHOST_WindowWin32.h index a3d4e89dd38..d4427f67e9b 100644 --- a/intern/ghost/intern/GHOST_WindowWin32.h +++ b/intern/ghost/intern/GHOST_WindowWin32.h @@ -632,7 +632,9 @@ class GHOST_WindowWin32 : public GHOST_Window { /** * Convert Wintab system mapped (mouse) buttons into Ghost button mask */ - GHOST_TSuccess wintabMouseToGhost(UINT cursor, DWORD physicalButton, GHOST_TButtonMask &buttonMask); + GHOST_TSuccess wintabMouseToGhost(UINT cursor, + DWORD physicalButton, + GHOST_TButtonMask &buttonMask); GHOST_TWindowState m_normal_state; -- cgit v1.2.3 From cc53c9e4764fd938af3a486feb013026c134080f Mon Sep 17 00:00:00 2001 From: Brecht Van Lommel Date: Wed, 8 Apr 2020 21:41:56 +0200 Subject: Fix T75290: Cycles crash with out of bounds memory access in volume mesh build --- intern/cycles/render/mesh_volume.cpp | 51 +++++++++++++++++++----------------- 1 file changed, 27 insertions(+), 24 deletions(-) diff --git a/intern/cycles/render/mesh_volume.cpp b/intern/cycles/render/mesh_volume.cpp index d73ba3b06dd..74b8fc9e5ba 100644 --- a/intern/cycles/render/mesh_volume.cpp +++ b/intern/cycles/render/mesh_volume.cpp @@ -25,18 +25,18 @@ CCL_NAMESPACE_BEGIN -static size_t compute_voxel_index(const int3 &resolution, size_t x, size_t y, size_t z) +const int64_t VOXEL_INDEX_NONE = -1; + +static int64_t compute_voxel_index(const int3 &resolution, int64_t x, int64_t y, int64_t z) { - if (x == -1 || x >= resolution.x) { - return -1; + if (x < 0 || x >= resolution.x) { + return VOXEL_INDEX_NONE; } - - if (y == -1 || y >= resolution.y) { - return -1; + else if (y < 0 || y >= resolution.y) { + return VOXEL_INDEX_NONE; } - - if (z == -1 || z >= resolution.z) { - return -1; + else if (z < 0 || z >= resolution.z) { + return VOXEL_INDEX_NONE; } return x + y * resolution.x + z * resolution.x * resolution.y; @@ -184,15 +184,15 @@ VolumeMeshBuilder::VolumeMeshBuilder(VolumeParams *volume_params) params = volume_params; number_of_nodes = 0; - const size_t x = divide_up(params->resolution.x, CUBE_SIZE); - const size_t y = divide_up(params->resolution.y, CUBE_SIZE); - const size_t z = divide_up(params->resolution.z, CUBE_SIZE); + const int64_t x = divide_up(params->resolution.x, CUBE_SIZE); + const int64_t y = divide_up(params->resolution.y, CUBE_SIZE); + const int64_t z = divide_up(params->resolution.z, CUBE_SIZE); /* Adding 2*pad_size since we pad in both positive and negative directions * along the axis. */ - const size_t px = divide_up(params->resolution.x + 2 * params->pad_size, CUBE_SIZE); - const size_t py = divide_up(params->resolution.y + 2 * params->pad_size, CUBE_SIZE); - const size_t pz = divide_up(params->resolution.z + 2 * params->pad_size, CUBE_SIZE); + const int64_t px = divide_up(params->resolution.x + 2 * params->pad_size, CUBE_SIZE); + const int64_t py = divide_up(params->resolution.y + 2 * params->pad_size, CUBE_SIZE); + const int64_t pz = divide_up(params->resolution.z + 2 * params->pad_size, CUBE_SIZE); res = make_int3(px, py, pz); pad_offset = make_int3(px - x, py - y, pz - z); @@ -209,7 +209,10 @@ void VolumeMeshBuilder::add_node(int x, int y, int z) assert((index_x >= 0) && (index_y >= 0) && (index_z >= 0)); - const size_t index = compute_voxel_index(res, index_x, index_y, index_z); + const int64_t index = compute_voxel_index(res, index_x, index_y, index_z); + if (index == VOXEL_INDEX_NONE) { + return; + } /* We already have a node here. */ if (grid[index] == 1) { @@ -256,7 +259,7 @@ void VolumeMeshBuilder::generate_vertices_and_quads(vector &vertices_ for (int z = 0; z < res.z; ++z) { for (int y = 0; y < res.y; ++y) { for (int x = 0; x < res.x; ++x) { - size_t voxel_index = compute_voxel_index(res, x, y, z); + int64_t voxel_index = compute_voxel_index(res, x, y, z); if (grid[voxel_index] == 0) { continue; } @@ -285,32 +288,32 @@ void VolumeMeshBuilder::generate_vertices_and_quads(vector &vertices_ */ voxel_index = compute_voxel_index(res, x - 1, y, z); - if (voxel_index == -1 || grid[voxel_index] == 0) { + if (voxel_index == VOXEL_INDEX_NONE || grid[voxel_index] == 0) { create_quad(corners, vertices_is, quads, res, used_verts, QUAD_X_MIN); } voxel_index = compute_voxel_index(res, x + 1, y, z); - if (voxel_index == -1 || grid[voxel_index] == 0) { + if (voxel_index == VOXEL_INDEX_NONE || grid[voxel_index] == 0) { create_quad(corners, vertices_is, quads, res, used_verts, QUAD_X_MAX); } voxel_index = compute_voxel_index(res, x, y - 1, z); - if (voxel_index == -1 || grid[voxel_index] == 0) { + if (voxel_index == VOXEL_INDEX_NONE || grid[voxel_index] == 0) { create_quad(corners, vertices_is, quads, res, used_verts, QUAD_Y_MIN); } voxel_index = compute_voxel_index(res, x, y + 1, z); - if (voxel_index == -1 || grid[voxel_index] == 0) { + if (voxel_index == VOXEL_INDEX_NONE || grid[voxel_index] == 0) { create_quad(corners, vertices_is, quads, res, used_verts, QUAD_Y_MAX); } voxel_index = compute_voxel_index(res, x, y, z - 1); - if (voxel_index == -1 || grid[voxel_index] == 0) { + if (voxel_index == VOXEL_INDEX_NONE || grid[voxel_index] == 0) { create_quad(corners, vertices_is, quads, res, used_verts, QUAD_Z_MIN); } voxel_index = compute_voxel_index(res, x, y, z + 1); - if (voxel_index == -1 || grid[voxel_index] == 0) { + if (voxel_index == VOXEL_INDEX_NONE || grid[voxel_index] == 0) { create_quad(corners, vertices_is, quads, res, used_verts, QUAD_Z_MAX); } } @@ -455,7 +458,7 @@ void GeometryManager::create_volume_mesh(Mesh *mesh, Progress &progress) for (int z = 0; z < resolution.z; ++z) { for (int y = 0; y < resolution.y; ++y) { for (int x = 0; x < resolution.x; ++x) { - size_t voxel_index = compute_voxel_index(resolution, x, y, z); + int64_t voxel_index = compute_voxel_index(resolution, x, y, z); for (size_t i = 0; i < voxel_grids.size(); ++i) { const VoxelAttributeGrid &voxel_grid = voxel_grids[i]; -- cgit v1.2.3 From c13aa95eda888c61514693c33ec506bf182257a1 Mon Sep 17 00:00:00 2001 From: Brecht Van Lommel Date: Wed, 8 Apr 2020 21:57:40 +0200 Subject: Fix T75288: crash in Cycles image loading with multithreaded shader compilation --- intern/cycles/render/image.cpp | 5 ++++- intern/cycles/render/image.h | 1 + 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/intern/cycles/render/image.cpp b/intern/cycles/render/image.cpp index 67ed1176171..75050b66bf2 100644 --- a/intern/cycles/render/image.cpp +++ b/intern/cycles/render/image.cpp @@ -283,6 +283,7 @@ void ImageManager::set_osl_texture_system(void *texture_system) bool ImageManager::set_animation_frame_update(int frame) { if (frame != animation_frame) { + thread_scoped_lock device_lock(images_mutex); animation_frame = frame; for (size_t slot = 0; slot < images.size(); slot++) { @@ -377,7 +378,7 @@ int ImageManager::add_image_slot(ImageLoader *loader, Image *img; size_t slot; - thread_scoped_lock device_lock(device_mutex); + thread_scoped_lock device_lock(images_mutex); /* Fnd existing image. */ for (slot = 0; slot < images.size(); slot++) { @@ -418,6 +419,7 @@ int ImageManager::add_image_slot(ImageLoader *loader, void ImageManager::add_image_user(int slot) { + thread_scoped_lock device_lock(images_mutex); Image *image = images[slot]; assert(image && image->users >= 1); @@ -426,6 +428,7 @@ void ImageManager::add_image_user(int slot) void ImageManager::remove_image_user(int slot) { + thread_scoped_lock device_lock(images_mutex); Image *image = images[slot]; assert(image && image->users >= 1); diff --git a/intern/cycles/render/image.h b/intern/cycles/render/image.h index 00ab12afd7a..2000582ce70 100644 --- a/intern/cycles/render/image.h +++ b/intern/cycles/render/image.h @@ -206,6 +206,7 @@ class ImageManager { bool has_half_images; thread_mutex device_mutex; + thread_mutex images_mutex; int animation_frame; vector images; -- cgit v1.2.3 From 74fa8787d8640c0856f3192898b8ebeaa0d639ac Mon Sep 17 00:00:00 2001 From: Julian Eisel Date: Wed, 8 Apr 2020 22:36:58 +0200 Subject: Fix error in UI_butstore_ API If the `uiButStore` data was freed after the buttons/blocks were updated from previous instances (see `UI_block_update_from_old()`), e.g. by delaying that to the "afterfuncs" (`ui_apply_but_funcs_after()`), the data would get lost. As result, the button pointers that the API is supposed to keep valid would point to freed memory. This wasn't an issue so far since the API didn't happen to be used this way. That changes with the next commit. --- source/blender/editors/interface/interface_utils.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source/blender/editors/interface/interface_utils.c b/source/blender/editors/interface/interface_utils.c index a69837e9b51..67cb91a3cc4 100644 --- a/source/blender/editors/interface/interface_utils.c +++ b/source/blender/editors/interface/interface_utils.c @@ -647,6 +647,7 @@ void UI_butstore_free(uiBlock *block, uiButStore *bs_handle) } BLI_freelistN(&bs_handle->items); + BLI_assert(BLI_findindex(&block->butstore, bs_handle) != -1); BLI_remlink(&block->butstore, bs_handle); MEM_freeN(bs_handle); @@ -747,8 +748,7 @@ void UI_butstore_update(uiBlock *block) /* move this list to the new block */ if (block->oldblock) { if (block->oldblock->butstore.first) { - block->butstore = block->oldblock->butstore; - BLI_listbase_clear(&block->oldblock->butstore); + BLI_movelisttolist(&block->butstore, &block->oldblock->butstore); } } -- cgit v1.2.3 From 1239cab11ff97faec708c7a4cf11007ac2b37108 Mon Sep 17 00:00:00 2001 From: Julian Eisel Date: Wed, 8 Apr 2020 23:08:32 +0200 Subject: Fix T75203: Crash when changing active keying set When updating the active button, the search data wasn't updated, so it kept using the old pointers. A check in `ui_rna_collection_search_cb()` relied on this incorrect behavior so I had to fix that too. Note that the previous commit was also needed for the second fix to work. Caused by c46dcdf8871e. --- source/blender/editors/interface/interface.c | 3 +++ source/blender/editors/interface/interface_intern.h | 6 +++++- source/blender/editors/interface/interface_layout.c | 14 ++++++++++++-- source/blender/editors/interface/interface_utils.c | 2 +- 4 files changed, 21 insertions(+), 4 deletions(-) diff --git a/source/blender/editors/interface/interface.c b/source/blender/editors/interface/interface.c index 339124db355..18666daa8b8 100644 --- a/source/blender/editors/interface/interface.c +++ b/source/blender/editors/interface/interface.c @@ -790,6 +790,9 @@ static bool ui_but_update_from_old_block(const bContext *C, SWAP(ListBase, but->extra_op_icons, oldbut->extra_op_icons); + SWAP(uiButSearchArgFreeFunc, oldbut->search_arg_free_func, but->search_arg_free_func); + SWAP(void *, oldbut->search_arg, but->search_arg); + /* copy hardmin for list rows to prevent 'sticking' highlight to mouse position * when scrolling without moving mouse (see [#28432]) */ if (ELEM(oldbut->type, UI_BTYPE_ROW, UI_BTYPE_LISTROW)) { diff --git a/source/blender/editors/interface/interface_intern.h b/source/blender/editors/interface/interface_intern.h index 942f19eb4e9..5573d9b2edb 100644 --- a/source/blender/editors/interface/interface_intern.h +++ b/source/blender/editors/interface/interface_intern.h @@ -1014,7 +1014,11 @@ typedef struct uiRNACollectionSearch { PointerRNA search_ptr; PropertyRNA *search_prop; - bool *but_changed; /* pointer to uiBut.changed */ + uiBut *search_but; + /* Let UI_butstore_ API update search_but pointer above over redraws. */ + uiButStore *butstore; + /* Block has to be stored for freeing butstore (uiBut.block doesn't work with undo). */ + uiBlock *butstore_block; } uiRNACollectionSearch; void ui_rna_collection_search_cb(const struct bContext *C, void *arg, diff --git a/source/blender/editors/interface/interface_layout.c b/source/blender/editors/interface/interface_layout.c index 44def6a2c09..92779c83d9a 100644 --- a/source/blender/editors/interface/interface_layout.c +++ b/source/blender/editors/interface/interface_layout.c @@ -2577,6 +2577,13 @@ static void search_id_collection(StructRNA *ptype, PointerRNA *r_ptr, PropertyRN RNA_STRUCT_END; } +static void ui_rna_collection_search_free_cb(void *ptr) +{ + uiRNACollectionSearch *coll_search = ptr; + UI_butstore_free(coll_search->butstore_block, coll_search->butstore); + MEM_freeN(ptr); +} + void ui_but_add_search( uiBut *but, PointerRNA *ptr, PropertyRNA *prop, PointerRNA *searchptr, PropertyRNA *searchprop) { @@ -2609,7 +2616,10 @@ void ui_but_add_search( coll_search->target_prop = prop; coll_search->search_ptr = *searchptr; coll_search->search_prop = searchprop; - coll_search->but_changed = &but->changed; + coll_search->search_but = but; + coll_search->butstore_block = but->block; + coll_search->butstore = UI_butstore_create(coll_search->butstore_block); + UI_butstore_register(coll_search->butstore, &coll_search->search_but); if (RNA_property_type(prop) == PROP_ENUM) { /* XXX, this will have a menu string, @@ -2621,7 +2631,7 @@ void ui_but_add_search( ui_searchbox_create_generic, ui_rna_collection_search_cb, coll_search, - MEM_freeN, + ui_rna_collection_search_free_cb, NULL, NULL); } diff --git a/source/blender/editors/interface/interface_utils.c b/source/blender/editors/interface/interface_utils.c index 67cb91a3cc4..2d687781b61 100644 --- a/source/blender/editors/interface/interface_utils.c +++ b/source/blender/editors/interface/interface_utils.c @@ -399,7 +399,7 @@ void ui_rna_collection_search_cb(const struct bContext *C, int i = 0, iconid = 0, flag = RNA_property_flag(data->target_prop); ListBase *items_list = MEM_callocN(sizeof(ListBase), "items_list"); CollItemSearch *cis; - const bool skip_filter = (data->but_changed && !(*data->but_changed)); + const bool skip_filter = data->search_but && !data->search_but->changed; /* build a temporary list of relevant items first */ RNA_PROP_BEGIN (&data->search_ptr, itemptr, data->search_prop) { -- cgit v1.2.3 From 7df787b2c1977e549da0c4f2213eb11cb96af32f Mon Sep 17 00:00:00 2001 From: Harley Acheson Date: Wed, 8 Apr 2020 16:10:48 -0700 Subject: UI: English as Default Language Set language setting for new profiles to English. Differential Revision: https://developer.blender.org/D7373 Reviewed by Brecht Van Lommel --- release/datafiles/userdef/userdef_default.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/release/datafiles/userdef/userdef_default.c b/release/datafiles/userdef/userdef_default.c index ec4b214c5f5..9771530ff18 100644 --- a/release/datafiles/userdef/userdef_default.c +++ b/release/datafiles/userdef/userdef_default.c @@ -64,7 +64,8 @@ const UserDef U_default = { .uiflag2 = USER_REGION_OVERLAP, .gpu_flag = USER_GPU_FLAG_OVERLAY_SMOOTH_WIRE, .app_flag = 0, - .language = 0, + /** Default language of English (1), not Automatic (0). */ + .language = 1, .viewzoom = USER_ZOOM_DOLLY, .mixbufsize = 2048, .audiodevice = 0, -- cgit v1.2.3 From 19352bca163dbd832ffc93ec5925736e4f25c959 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Thu, 9 Apr 2020 10:51:34 +1000 Subject: Cleanup: spelling --- intern/ghost/intern/GHOST_SystemX11.cpp | 2 +- intern/ghost/intern/GHOST_XrGraphicsBinding.cpp | 2 +- source/blender/blenkernel/BKE_particle.h | 2 +- source/blender/blenlib/intern/BLI_ghash.c | 2 +- source/blender/blenlib/intern/math_vector.c | 2 +- source/blender/blenloader/intern/versioning_280.c | 4 ++-- source/blender/compositor/operations/COM_DoubleEdgeMaskOperation.cpp | 2 +- 7 files changed, 8 insertions(+), 8 deletions(-) diff --git a/intern/ghost/intern/GHOST_SystemX11.cpp b/intern/ghost/intern/GHOST_SystemX11.cpp index aebf829a546..825b93de36f 100644 --- a/intern/ghost/intern/GHOST_SystemX11.cpp +++ b/intern/ghost/intern/GHOST_SystemX11.cpp @@ -1569,7 +1569,7 @@ void GHOST_SystemX11::processEvent(XEvent *xe) GHOST_TSuccess GHOST_SystemX11::getModifierKeys(GHOST_ModifierKeys &keys) const { - /* Analyze the masks retuned from XQueryPointer. */ + /* Analyze the masks returned from XQueryPointer. */ memset((void *)m_keyboard_vector, 0, sizeof(m_keyboard_vector)); diff --git a/intern/ghost/intern/GHOST_XrGraphicsBinding.cpp b/intern/ghost/intern/GHOST_XrGraphicsBinding.cpp index e8de5d1bed7..60b3b06f6a8 100644 --- a/intern/ghost/intern/GHOST_XrGraphicsBinding.cpp +++ b/intern/ghost/intern/GHOST_XrGraphicsBinding.cpp @@ -279,7 +279,7 @@ class GHOST_XrGraphicsBindingD3D : public GHOST_IXrGraphicsBinding { swapchain_image); # if 0 - /* Ideally we'd just create a render target view for the OpenXR swapchain image texture and + /* Ideally we'd just create a render target view for the OpenXR swap-chain image texture and * blit from the OpenGL context into it. The NV_DX_interop extension doesn't want to work with * this though. At least not with Optimus hardware. See: * https://github.com/mpv-player/mpv/issues/2949#issuecomment-197262807. diff --git a/source/blender/blenkernel/BKE_particle.h b/source/blender/blenkernel/BKE_particle.h index eff546a7c55..ea81be05b03 100644 --- a/source/blender/blenkernel/BKE_particle.h +++ b/source/blender/blenkernel/BKE_particle.h @@ -270,7 +270,7 @@ BLI_INLINE float psys_frand(ParticleSystem *psys, unsigned int seed) /* XXX far from ideal, this simply scrambles particle random numbers a bit * to avoid obvious correlations. * Can't use previous psys->frand arrays because these require initialization - * inside psys_check_enabled, which wreaks havoc in multi-threaded depgraph updates. + * inside psys_check_enabled, which wreaks havoc in multi-threaded depsgraph updates. */ unsigned int offset = PSYS_FRAND_SEED_OFFSET[psys->seed % PSYS_FRAND_COUNT]; unsigned int multiplier = PSYS_FRAND_SEED_MULTIPLIER[psys->seed % PSYS_FRAND_COUNT]; diff --git a/source/blender/blenlib/intern/BLI_ghash.c b/source/blender/blenlib/intern/BLI_ghash.c index 0800027e520..09dbf18acd0 100644 --- a/source/blender/blenlib/intern/BLI_ghash.c +++ b/source/blender/blenlib/intern/BLI_ghash.c @@ -1056,7 +1056,7 @@ void BLI_ghash_flag_clear(GHash *gh, uint flag) * #BLI_ghash_len(gh) times before becoming done. * * \param gh: The GHash to iterate over. - * \return Pointer to a new DynStr. + * \return Pointer to a new iterator. */ GHashIterator *BLI_ghashIterator_new(GHash *gh) { diff --git a/source/blender/blenlib/intern/math_vector.c b/source/blender/blenlib/intern/math_vector.c index 5919b7e1dd6..9009f73a62f 100644 --- a/source/blender/blenlib/intern/math_vector.c +++ b/source/blender/blenlib/intern/math_vector.c @@ -778,7 +778,7 @@ void bisect_v3_v3v3v3(float out[3], const float v1[3], const float v2[3], const *
  * v
  * +  ^
- * \ |
+ *  \ |
  *   \|
  *    + normal: axis of reflection
  *   /
diff --git a/source/blender/blenloader/intern/versioning_280.c b/source/blender/blenloader/intern/versioning_280.c
index cd9f9dd7027..ff3aef4588f 100644
--- a/source/blender/blenloader/intern/versioning_280.c
+++ b/source/blender/blenloader/intern/versioning_280.c
@@ -4125,7 +4125,7 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain)
             v3d->shading.flag |= V3D_SHADING_SCENE_LIGHTS_RENDER | V3D_SHADING_SCENE_WORLD_RENDER;
 
             /* files by default don't have studio lights selected unless interacted
-             * with the shading popover. When no studiolight could be read, we will
+             * with the shading popover. When no studio-light could be read, we will
              * select the default world one. */
             StudioLight *studio_light = BKE_studiolight_find(v3d->shading.lookdev_light,
                                                              STUDIOLIGHT_TYPE_WORLD);
@@ -4194,7 +4194,7 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain)
       }
     }
 
-    /* Added studiolight intensity */
+    /* Added studio-light intensity. */
     if (!DNA_struct_elem_find(fd->filesdna, "View3DShading", "float", "studiolight_intensity")) {
       for (bScreen *screen = bmain->screens.first; screen; screen = screen->id.next) {
         LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
diff --git a/source/blender/compositor/operations/COM_DoubleEdgeMaskOperation.cpp b/source/blender/compositor/operations/COM_DoubleEdgeMaskOperation.cpp
index 22949a8e6f1..ae6f49bffcd 100644
--- a/source/blender/compositor/operations/COM_DoubleEdgeMaskOperation.cpp
+++ b/source/blender/compositor/operations/COM_DoubleEdgeMaskOperation.cpp
@@ -1136,7 +1136,7 @@ static void do_fillGradientBuffer(unsigned int rw,
    * purpose of GO for the proportion calculation.
    *
    * For the purposes of the minimum distance comparisons, we only check
-   * the sums-of-squares against eachother, since they are in the same
+   * the sums-of-squares against each other, since they are in the same
    * mathematical sort-order as if we did go ahead and take square roots
    *
    * Loop through all gradient pixels.
-- 
cgit v1.2.3


From bd59781c66e15617b5c0cccfb07b2c0e3079b210 Mon Sep 17 00:00:00 2001
From: Campbell Barton 
Date: Thu, 9 Apr 2020 18:35:01 +1000
Subject: Fix T75425: Bone selection cycling not working

Edit-mode bone selection now cycles on successive clicks.
This now cycles through multiple edit-objects & bones.
---
 source/blender/editors/armature/armature_select.c | 176 +++++++++++++---------
 1 file changed, 107 insertions(+), 69 deletions(-)

diff --git a/source/blender/editors/armature/armature_select.c b/source/blender/editors/armature/armature_select.c
index 4b938fb0072..98f067af148 100644
--- a/source/blender/editors/armature/armature_select.c
+++ b/source/blender/editors/armature/armature_select.c
@@ -657,45 +657,28 @@ static EditBone *get_nearest_editbonepoint(
     uint hitresult;
     Base *base;
     EditBone *ebone;
-  } best = {
-      .hitresult = BONESEL_NOSEL,
-      .base = NULL,
-      .ebone = NULL,
-  };
+  } *result = NULL,
+
+    result_cycle = {.hitresult = BONESEL_NOSEL, .base = NULL, .ebone = NULL},
+    result_bias = {.hitresult = BONESEL_NOSEL, .base = NULL, .ebone = NULL};
 
   /* find the bone after the current active bone, so as to bump up its chances in selection.
    * this way overlapping bones will cycle selection state as with objects. */
-  EditBone *ebone_next_act = ((bArmature *)vc->obedit->data)->act_edbone;
-  {
-    bArmature *arm = (bArmature *)vc->obedit->data;
-    if (ebone_next_act && EBONE_VISIBLE(arm, ebone_next_act) &&
-        ebone_next_act->flag & (BONE_SELECTED | BONE_ROOTSEL | BONE_TIPSEL)) {
-      ebone_next_act = ebone_next_act->next ? ebone_next_act->next : arm->edbo->first;
-    }
-    else {
-      ebone_next_act = NULL;
-    }
+  Object *obedit_orig = vc->obedit;
+  EditBone *ebone_active_orig = ((bArmature *)obedit_orig->data)->act_edbone;
+  if (ebone_active_orig == NULL) {
+    use_cycle = false;
   }
 
-  bool do_nearest = false;
-
-  /* define if we use solid nearest select or not */
   if (use_cycle) {
     static int last_mval[2] = {-100, -100};
-
-    if (!XRAY_ACTIVE(vc->v3d)) {
-      do_nearest = true;
-      if (len_manhattan_v2v2_int(vc->mval, last_mval) <= WM_EVENT_CURSOR_MOTION_THRESHOLD) {
-        do_nearest = false;
-      }
+    if ((len_manhattan_v2v2_int(vc->mval, last_mval) <= WM_EVENT_CURSOR_MOTION_THRESHOLD) == 0) {
+      use_cycle = false;
     }
     copy_v2_v2_int(last_mval, vc->mval);
   }
-  else {
-    if (!XRAY_ACTIVE(vc->v3d)) {
-      do_nearest = true;
-    }
-  }
+
+  const bool do_nearest = !(XRAY_ACTIVE(vc->v3d) || use_cycle);
 
   /* matching logic from 'mixed_bones_object_selectbuffer' */
   int hits = 0;
@@ -750,13 +733,39 @@ cache_end:
   if (hits > 0) {
     if (hits == 1) {
       if (!(buffer[3] & BONESEL_NOSEL)) {
-        best.hitresult = buffer[3];
-        best.base = ED_armature_base_and_ebone_from_select_buffer(
-            bases, bases_len, best.hitresult, &best.ebone);
+        result_bias.hitresult = buffer[3];
+        result_bias.base = ED_armature_base_and_ebone_from_select_buffer(
+            bases, bases_len, result_bias.hitresult, &result_bias.ebone);
       }
     }
     else {
-      int dep_min = 5;
+      int bias_max = INT_MIN;
+
+      /* Track cycle variables. */
+      struct {
+        union {
+          uint32_t cmp;
+          struct {
+#ifdef __BIG_ENDIAN__
+            uint16_t ob;
+            uint16_t bone;
+#else
+            uint16_t bone;
+            uint16_t ob;
+#endif
+          } index;
+        } active, test, best;
+      } cycle_order;
+
+      if (use_cycle) {
+        bArmature *arm = obedit_orig->data;
+        int ob_index = obedit_orig->runtime.select_id & 0xFFFF;
+        int bone_index = BLI_findindex(arm->edbo, ebone_active_orig);
+        cycle_order.active.index.ob = ob_index;
+        cycle_order.active.index.bone = bone_index;
+        cycle_order.best.cmp = 0xffffffff;
+      }
+
       for (int i = 0; i < hits; i++) {
         const uint hitresult = buffer[3 + (i * 4)];
         if (!(hitresult & BONESEL_NOSEL)) {
@@ -767,69 +776,98 @@ cache_end:
           /* If this fails, selection code is setting the selection ID's incorrectly. */
           BLI_assert(base && ebone);
 
-          int dep;
-          /* clicks on bone points get advantage */
-          if (hitresult & (BONESEL_ROOT | BONESEL_TIP)) {
-            /* but also the unselected one */
-            if (findunsel) {
-              if ((hitresult & BONESEL_ROOT) && (ebone->flag & BONE_ROOTSEL) == 0) {
-                dep = 1;
-              }
-              else if ((hitresult & BONESEL_TIP) && (ebone->flag & BONE_TIPSEL) == 0) {
-                dep = 1;
+          /* Prioritized selection. */
+          {
+            int bias;
+            /* clicks on bone points get advantage */
+            if (hitresult & (BONESEL_ROOT | BONESEL_TIP)) {
+              /* but also the unselected one */
+              if (findunsel) {
+                if ((hitresult & BONESEL_ROOT) && (ebone->flag & BONE_ROOTSEL) == 0) {
+                  bias = 4;
+                }
+                else if ((hitresult & BONESEL_TIP) && (ebone->flag & BONE_TIPSEL) == 0) {
+                  bias = 4;
+                }
+                else {
+                  bias = 3;
+                }
               }
               else {
-                dep = 2;
+                bias = 4;
               }
             }
             else {
-              dep = 1;
-            }
-          }
-          else {
-            /* bone found */
-            if (findunsel) {
-              if ((ebone->flag & BONE_SELECTED) == 0) {
-                dep = 3;
+              /* bone found */
+              if (findunsel) {
+                if ((ebone->flag & BONE_SELECTED) == 0) {
+                  bias = 2;
+                }
+                else {
+                  bias = 1;
+                }
               }
               else {
-                dep = 4;
+                bias = 2;
               }
             }
-            else {
-              dep = 3;
+
+            if (bias > bias_max) {
+              bias_max = bias;
+
+              result_bias.hitresult = hitresult;
+              result_bias.base = base;
+              result_bias.ebone = ebone;
             }
           }
 
-          if (ebone == ebone_next_act) {
-            dep -= 1;
-          }
+          /* Cycle selected items (objects & bones). */
+          if (use_cycle) {
+            bool found = false;
+            cycle_order.test.index.ob = hitresult & 0xFFFF;
+            cycle_order.test.index.bone = (hitresult & ~BONESEL_ANY) >> 16;
+            if (ebone == ebone_active_orig) {
+              BLI_assert(cycle_order.test.index.ob == cycle_order.active.index.ob);
+              BLI_assert(cycle_order.test.index.bone == cycle_order.active.index.bone);
+            }
+            cycle_order.test.cmp -= cycle_order.active.cmp;
 
-          if (dep < dep_min) {
-            dep_min = dep;
-            best.hitresult = hitresult;
-            best.base = base;
-            best.ebone = ebone;
+            if (cycle_order.test.cmp < cycle_order.best.cmp && ebone != ebone_active_orig) {
+              cycle_order.best.cmp = cycle_order.test.cmp;
+              found = true;
+            }
+            else if (ELEM(result_cycle.ebone, NULL, ebone_active_orig)) {
+              /* Let the active bone become selected, but don't set the cycle order. */
+              found = true;
+            }
+
+            if (found) {
+              result_cycle.hitresult = hitresult;
+              result_cycle.base = base;
+              result_cycle.ebone = ebone;
+            }
           }
         }
       }
     }
 
-    if (!(best.hitresult & BONESEL_NOSEL)) {
-      *r_base = best.base;
+    result = (use_cycle && result_cycle.ebone) ? &result_cycle : &result_bias;
+
+    if (!(result->hitresult & BONESEL_NOSEL)) {
+      *r_base = result->base;
 
       *r_selmask = 0;
-      if (best.hitresult & BONESEL_ROOT) {
+      if (result->hitresult & BONESEL_ROOT) {
         *r_selmask |= BONE_ROOTSEL;
       }
-      if (best.hitresult & BONESEL_TIP) {
+      if (result->hitresult & BONESEL_TIP) {
         *r_selmask |= BONE_TIPSEL;
       }
-      if (best.hitresult & BONESEL_BONE) {
+      if (result->hitresult & BONESEL_BONE) {
         *r_selmask |= BONE_SELECTED;
       }
       MEM_freeN(bases);
-      return best.ebone;
+      return result->ebone;
     }
   }
   *r_selmask = 0;
-- 
cgit v1.2.3


From ee5cec4a5019853b474b044caa17c7ae34b611d7 Mon Sep 17 00:00:00 2001
From: Antonio Vazquez 
Date: Thu, 9 Apr 2020 10:56:48 +0200
Subject: Fix T75122: Annotations: Only visible scene annotations in dopesheet

The loop of datablocks was using the scene datablock (3D View) only, but all others datablocks were ignored.

Now the loop consider any annotation datablock.
---
 source/blender/editors/animation/anim_filter.c | 12 ++++++++----
 1 file changed, 8 insertions(+), 4 deletions(-)

diff --git a/source/blender/editors/animation/anim_filter.c b/source/blender/editors/animation/anim_filter.c
index 38a19e85661..c054691ca38 100644
--- a/source/blender/editors/animation/anim_filter.c
+++ b/source/blender/editors/animation/anim_filter.c
@@ -1844,11 +1844,15 @@ static size_t animdata_filter_gpencil(bAnimContext *ac,
   ViewLayer *view_layer = (ViewLayer *)ac->view_layer;
   Base *base;
 
-  /* Active scene's GPencil block first - No parent item needed... */
-  if (scene->gpd) {
-    items += animdata_filter_gpencil_data(anim_data, ads, scene->gpd, filter_mode);
+  /* Include all annotation datablocks. */
+  if (((ads->filterflag & ADS_FILTER_ONLYSEL) == 0) ||
+      (ads->filterflag & ADS_FILTER_INCL_HIDDEN)) {
+    LISTBASE_FOREACH (bGPdata *, gpd, &ac->bmain->gpencils) {
+      if (gpd->flag & GP_DATA_ANNOTATIONS) {
+        items += animdata_filter_gpencil_data(anim_data, ads, gpd, filter_mode);
+      }
+    }
   }
-
   /* Objects in the scene */
   for (base = view_layer->object_bases.first; base; base = base->next) {
     /* Only consider this object if it has got some GP data (saving on all the other tests) */
-- 
cgit v1.2.3


From b5e277ed05aab64b03c51c57476b0d02b78e9eff Mon Sep 17 00:00:00 2001
From: Antonio Vazquez 
Date: Thu, 9 Apr 2020 10:58:42 +0200
Subject: Cleanup: Fix typo error

---
 source/blender/editors/gpencil/gpencil_convert.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/source/blender/editors/gpencil/gpencil_convert.c b/source/blender/editors/gpencil/gpencil_convert.c
index 28e632d2b82..e89903adf5f 100644
--- a/source/blender/editors/gpencil/gpencil_convert.c
+++ b/source/blender/editors/gpencil/gpencil_convert.c
@@ -1822,7 +1822,7 @@ void GPENCIL_OT_image_to_grease_pencil(wmOperatorType *ot)
                            0.0001f,
                            10.0f,
                            "Point Size",
-                           "Size used for graese pencil points",
+                           "Size used for grease pencil points",
                            0.001f,
                            1.0f);
   RNA_def_property_flag(ot->prop, PROP_SKIP_SAVE);
-- 
cgit v1.2.3


From 36746474fdf4d05f3eccc45a42295dbbb7745d36 Mon Sep 17 00:00:00 2001
From: Sergey Sharybin 
Date: Thu, 9 Apr 2020 10:57:18 +0200
Subject: Tracking: Forward compatibility code for distortion models

Allows to open newer files in older Blender after new distortion model
has been added.

It will behave as if this is a polynomial model with all 0 coefficients
which are then being refined and assigned explicitly after solving the
motion.
---
 source/blender/blenkernel/intern/tracking_util.c | 89 +++++++++++++++---------
 1 file changed, 55 insertions(+), 34 deletions(-)

diff --git a/source/blender/blenkernel/intern/tracking_util.c b/source/blender/blenkernel/intern/tracking_util.c
index d7600c06a6b..5f7452e4775 100644
--- a/source/blender/blenkernel/intern/tracking_util.c
+++ b/source/blender/blenkernel/intern/tracking_util.c
@@ -433,6 +433,59 @@ void tracking_marker_insert_disabled(MovieTrackingTrack *track,
   }
 }
 
+static void distortion_model_parameters_from_tracking(
+    const MovieTrackingCamera *camera, libmv_CameraIntrinsicsOptions *camera_intrinsics_options)
+{
+  switch (camera->distortion_model) {
+    case TRACKING_DISTORTION_MODEL_POLYNOMIAL:
+      camera_intrinsics_options->distortion_model = LIBMV_DISTORTION_MODEL_POLYNOMIAL;
+      camera_intrinsics_options->polynomial_k1 = camera->k1;
+      camera_intrinsics_options->polynomial_k2 = camera->k2;
+      camera_intrinsics_options->polynomial_k3 = camera->k3;
+      camera_intrinsics_options->polynomial_p1 = 0.0;
+      camera_intrinsics_options->polynomial_p2 = 0.0;
+      return;
+
+    case TRACKING_DISTORTION_MODEL_DIVISION:
+      camera_intrinsics_options->distortion_model = LIBMV_DISTORTION_MODEL_DIVISION;
+      camera_intrinsics_options->division_k1 = camera->division_k1;
+      camera_intrinsics_options->division_k2 = camera->division_k2;
+      return;
+  }
+
+  /* Unknown distortion model, which might be due to opening newer file in older Blender.
+   * Fallback to a known and supported model with 0 distortion. */
+  camera_intrinsics_options->distortion_model = LIBMV_DISTORTION_MODEL_POLYNOMIAL;
+  camera_intrinsics_options->polynomial_k1 = 0.0;
+  camera_intrinsics_options->polynomial_k2 = 0.0;
+  camera_intrinsics_options->polynomial_k3 = 0.0;
+  camera_intrinsics_options->polynomial_p1 = 0.0;
+  camera_intrinsics_options->polynomial_p2 = 0.0;
+}
+
+static void distortion_model_parameters_from_options(
+    const libmv_CameraIntrinsicsOptions *camera_intrinsics_options, MovieTrackingCamera *camera)
+{
+  switch (camera_intrinsics_options->distortion_model) {
+    case LIBMV_DISTORTION_MODEL_POLYNOMIAL:
+      camera->distortion_model = TRACKING_DISTORTION_MODEL_POLYNOMIAL;
+      camera->k1 = camera_intrinsics_options->polynomial_k1;
+      camera->k2 = camera_intrinsics_options->polynomial_k2;
+      camera->k3 = camera_intrinsics_options->polynomial_k3;
+      return;
+
+    case LIBMV_DISTORTION_MODEL_DIVISION:
+      camera->distortion_model = TRACKING_DISTORTION_MODEL_DIVISION;
+      camera->division_k1 = camera_intrinsics_options->division_k1;
+      camera->division_k2 = camera_intrinsics_options->division_k2;
+      return;
+  }
+
+  /* Libmv returned distortion model which is not known to Blender. This is a logical error in code
+   * and Blender side is to be updated to match Libmv. */
+  BLI_assert(!"Unknown distortion model");
+}
+
 /* Fill in Libmv C-API camera intrinsics options from tracking structure. */
 void tracking_cameraIntrinscisOptionsFromTracking(
     MovieTracking *tracking,
@@ -450,24 +503,7 @@ void tracking_cameraIntrinscisOptionsFromTracking(
   camera_intrinsics_options->principal_point_x = camera->principal[0];
   camera_intrinsics_options->principal_point_y = camera->principal[1] * aspy;
 
-  switch (camera->distortion_model) {
-    case TRACKING_DISTORTION_MODEL_POLYNOMIAL:
-      camera_intrinsics_options->distortion_model = LIBMV_DISTORTION_MODEL_POLYNOMIAL;
-      camera_intrinsics_options->polynomial_k1 = camera->k1;
-      camera_intrinsics_options->polynomial_k2 = camera->k2;
-      camera_intrinsics_options->polynomial_k3 = camera->k3;
-      camera_intrinsics_options->polynomial_p1 = 0.0;
-      camera_intrinsics_options->polynomial_p2 = 0.0;
-      break;
-    case TRACKING_DISTORTION_MODEL_DIVISION:
-      camera_intrinsics_options->distortion_model = LIBMV_DISTORTION_MODEL_DIVISION;
-      camera_intrinsics_options->division_k1 = camera->division_k1;
-      camera_intrinsics_options->division_k2 = camera->division_k2;
-      break;
-    default:
-      BLI_assert(!"Unknown distortion model");
-      break;
-  }
+  distortion_model_parameters_from_tracking(camera, camera_intrinsics_options);
 
   camera_intrinsics_options->image_width = calibration_width;
   camera_intrinsics_options->image_height = (int)(calibration_height * aspy);
@@ -484,22 +520,7 @@ void tracking_trackingCameraFromIntrinscisOptions(
   camera->principal[0] = camera_intrinsics_options->principal_point_x;
   camera->principal[1] = camera_intrinsics_options->principal_point_y / (double)aspy;
 
-  switch (camera_intrinsics_options->distortion_model) {
-    case LIBMV_DISTORTION_MODEL_POLYNOMIAL:
-      camera->distortion_model = TRACKING_DISTORTION_MODEL_POLYNOMIAL;
-      camera->k1 = camera_intrinsics_options->polynomial_k1;
-      camera->k2 = camera_intrinsics_options->polynomial_k2;
-      camera->k3 = camera_intrinsics_options->polynomial_k3;
-      break;
-    case LIBMV_DISTORTION_MODEL_DIVISION:
-      camera->distortion_model = TRACKING_DISTORTION_MODEL_DIVISION;
-      camera->division_k1 = camera_intrinsics_options->division_k1;
-      camera->division_k2 = camera_intrinsics_options->division_k2;
-      break;
-    default:
-      BLI_assert(!"Unknown distortion model");
-      break;
-  }
+  distortion_model_parameters_from_options(camera_intrinsics_options, camera);
 }
 
 /* Get previous keyframed marker. */
-- 
cgit v1.2.3


From 80255e67e30c4d77be64a5fa8dc68c0a55f39ebc Mon Sep 17 00:00:00 2001
From: Bastien Montagne 
Date: Thu, 9 Apr 2020 11:19:11 +0200
Subject: Silence assert on ID usercount for deprecated IPO.

We do not really care about those, so just avoid the noise when loading
very old files...

Re T75389.
---
 source/blender/blenkernel/intern/lib_id.c | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/source/blender/blenkernel/intern/lib_id.c b/source/blender/blenkernel/intern/lib_id.c
index 286ee4a8723..487ec0bf161 100644
--- a/source/blender/blenkernel/intern/lib_id.c
+++ b/source/blender/blenkernel/intern/lib_id.c
@@ -320,7 +320,11 @@ void id_us_min(ID *id)
                  id->lib ? id->lib->filepath : "[Main]",
                  id->us,
                  limit);
-      BLI_assert(0);
+      if (GS(id->name) != ID_IP) {
+        /* Do not assert on deprecated ID types, we cannot really ensure that their ID refcounting
+         * is valid... */
+        BLI_assert(0);
+      }
       id->us = limit;
     }
     else {
-- 
cgit v1.2.3