diff options
Diffstat (limited to 'source')
104 files changed, 2054 insertions, 1118 deletions
diff --git a/source/blender/blenkernel/BKE_blender_version.h b/source/blender/blenkernel/BKE_blender_version.h index 78e0e12355b..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 11 +#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/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/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/blenkernel/intern/appdir.c b/source/blender/blenkernel/intern/appdir.c index 0e578250b39..4071cc024aa 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 @@ -687,12 +687,12 @@ 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 } - 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/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, 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/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; 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); 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/blenkernel/intern/fluid.c b/source/blender/blenkernel/intern/fluid.c index cbb933725eb..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; } @@ -3999,7 +4001,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); 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/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 { diff --git a/source/blender/blenkernel/intern/mesh_convert.c b/source/blender/blenkernel/intern/mesh_convert.c index 74b79490d67..28a32e1573b 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 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; + return new_mesh; } diff --git a/source/blender/blenkernel/intern/movieclip.c b/source/blender/blenkernel/intern/movieclip.c index 1964dba7593..193fe859def 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 */ @@ -456,9 +456,10 @@ typedef struct MovieClipCache { int flag; /* cache for undistorted shot */ + float focal_length; float principal[2]; - float polynomial_k1; - float division_k1; + float polynomial_k[3]; + float division_k[2]; short distortion_model; bool undistortion_used; @@ -505,7 +506,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 +649,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); } } @@ -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; @@ -896,11 +901,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; } @@ -1001,9 +1006,10 @@ 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_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 { 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; 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/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/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/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/blenkernel/intern/sound.c b/source/blender/blenkernel/intern/sound.c index 97a643e88b6..64fe396d6a3 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 = FRA2TIME(CFRA); AUD_Device_lock(sound_device); diff --git a/source/blender/blenkernel/intern/tracking_util.c b/source/blender/blenkernel/intern/tracking_util.c index 51758abdf3f..5f7452e4775 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" @@ -432,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, @@ -442,29 +496,14 @@ 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]; 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); @@ -481,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. */ diff --git a/source/blender/blenlib/BLI_path_util.h b/source/blender/blenlib/BLI_path_util.h index 4376aefdc25..9a6a14547d2 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(); @@ -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; @@ -109,8 +109,8 @@ 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_cleanup_unc(char *path_16, int maxlen); +void BLI_path_normalize_unc_16(wchar_t *path_16); +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/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/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/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; 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 * <pre> * v * + ^ - * \ | + * \ | * \| * + normal: axis of reflection * / diff --git a/source/blender/blenlib/intern/path_util.c b/source/blender/blenlib/intern/path_util.c index 0bb2ba5859b..2f51b66725b 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 "<head><pic><tail>", 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,14 +494,14 @@ 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); + 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); @@ -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,19 +1110,20 @@ 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; } /** - * 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); @@ -1363,7 +1364,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 +1419,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 +1609,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 +1637,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 +1681,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 +1696,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 +1739,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 +1847,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 +1922,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 +1940,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 +1959,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 +1973,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 +1990,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/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')) { diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c index f771a859459..96c7339c6da 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; @@ -664,7 +662,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 +1678,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)) { @@ -2376,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)); @@ -2389,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 */ @@ -2768,7 +2772,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 +2782,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 +2791,72 @@ 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 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 performing 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*/ if (id->properties) { @@ -2804,10 +2866,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. @@ -2823,29 +2883,8 @@ static void direct_link_id(FileData *fd, ID *id, ID *id_old) 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. */ @@ -8402,7 +8441,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; @@ -8412,10 +8451,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; } /** \} */ @@ -8460,7 +8499,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); @@ -9251,289 +9290,15 @@ static const char *dataname(short id_code) return "Data from Lib Block"; } -static BHead *read_data_into_oldnewmap(FileData *fd, BHead *bhead, const char *allocname) -{ - bhead = blo_bhead_next(fd, bhead); - - while (bhead && bhead->code == DATA) { - void *data; -#if 0 - /* XXX DUMB DEBUGGING OPTION TO GIVE NAMES for guarded malloc errors */ - short* sp = fd->filesdna->structs[bhead->SDNAnr]; - char* tmp = malloc(100); - allocname = fd->filesdna->types[sp[0]]; - strcpy(tmp, allocname); - data = read_struct(fd, bhead, tmp); -#else - data = read_struct(fd, bhead, allocname); -#endif - - if (data) { - oldnewmap_insert(fd->datamap, bhead->old, data, 0); - } - - bhead = blo_bhead_next(fd, bhead); - } - - return bhead; -} - -static BHead *read_libblock(FileData *fd, - Main *main, - BHead *bhead, - const int tag, - const bool placeholder_set_indirect_extern, - ID **r_id) +static bool direct_link_id(FileData *fd, Main *main, const int tag, ID *id, ID *id_old) { - /* 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; - - /* 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 && ELEM(bhead->code, ID_LI, ID_LINK_PLACEHOLDER)) { - const char *idname = blo_bhead_id_name(fd, bhead); - - DEBUG_PRINTF("Checking %s...\n", idname); - - 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 : "<NULL>"); - if (libmain->curlib && STREQ(idname, 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); - - if (r_id) { - *r_id = NULL; /* Just in case... */ - } - return blo_bhead_next(fd, bhead); - } - DEBUG_PRINTF("nothing...\n"); - } - } - else { - DEBUG_PRINTF("... in %s (%s): ", - main->curlib ? main->curlib->id.name : "<NULL>", - main->curlib ? main->curlib->name : "<NULL>"); - if ((id = BKE_libblock_find_name(main, GS(idname), idname + 2))) { - 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)); - } - - /* 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... */ - } - return blo_bhead_next(fd, bhead); - } - DEBUG_PRINTF("nothing...\n"); - } - } - - /* read libblock */ - fd->are_memchunks_identical = true; - id = read_struct(fd, bhead, "lib block"); - const short idcode = id != NULL ? GS(id->name) : 0; - - BHead *id_bhead = bhead; - /* 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 (id_bhead->code != ID_LINK_PLACEHOLDER) { - /* need a name for the mallocN, just for debugging and sane prints on leaks */ - 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. - */ - - 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; - } - - 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 (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. */ - - /* 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); - oldnewmap_free_unused(fd->datamap); - oldnewmap_clear(fd->datamap); - - return bhead; - } - } - } - - /* do after read_struct, for dna reconstruct */ - 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); - } - } - - /* 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); - } - - /* 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 (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 */ - printf("%s: unknown id code '%c%c'\n", __func__, (idcode & 0xff), (idcode >> 8)); - MEM_freeN(id); - id = NULL; - } + 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; } - if (r_id) { - *r_id = do_id_swap ? id_old : id; - } - if (!id) { - return blo_bhead_next(fd, id_bhead); - } + BKE_lib_libblock_session_uuid_ensure(id); id->lib = main->curlib; id->us = ID_FAKE_USERS(id); @@ -9541,36 +9306,25 @@ static BHead *read_libblock(FileData *fd, id->newid = NULL; /* Needed because .blend may have been saved with crap value here... */ id->orig_id = NULL; - /* 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; - - if (placeholder_set_indirect_extern) { - if (id->flag & LIB_INDIRECT_WEAK_LINK) { - id->tag |= LIB_TAG_INDIRECT; - } - else { - id->tag |= LIB_TAG_EXTERN; - } - } - - return blo_bhead_next(fd, id_bhead); + 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; } - /* init pointers direct data */ - direct_link_id(fd, id, id_old); + /* Read part of datablock that is common between real and embedded datablocks. */ + direct_link_id_common(fd, id, id_old, tag); - /* 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; + /* XXX Very weakly handled currently, see comment in read_libblock() before trying to + * use it for anything new. */ + bool success = true; - switch (idcode) { + switch (GS(id->name)) { case ID_WM: direct_link_windowmanager(fd, (wmWindowManager *)id); break; case ID_SCR: - wrong_id = direct_link_screen(fd, (bScreen *)id); + success = direct_link_screen(fd, (bScreen *)id); break; case ID_SCE: direct_link_scene(fd, (Scene *)id); @@ -9685,10 +9439,355 @@ static BHead *read_libblock(FileData *fd, break; } - oldnewmap_free_unused(fd->datamap); + return success; +} + +/* 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); + + while (bhead && bhead->code == DATA) { + void *data; +#if 0 + /* XXX DUMB DEBUGGING OPTION TO GIVE NAMES for guarded malloc errors */ + short* sp = fd->filesdna->structs[bhead->SDNAnr]; + char* tmp = malloc(100); + allocname = fd->filesdna->types[sp[0]]; + strcpy(tmp, allocname); + data = read_struct(fd, bhead, tmp); +#else + data = read_struct(fd, bhead, allocname); +#endif + + if (data) { + oldnewmap_insert(fd->datamap, bhead->old, data, 0); + } + + bhead = blo_bhead_next(fd, bhead); + } + + 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; +} + +/* 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 + * (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 : "<NULL>"); + 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; +} + +/* 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); + DEBUG_PRINTF(" from %s (%s): ", + main->curlib ? main->curlib->id.name : "<NULL>", + main->curlib ? main->curlib->name : "<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 (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. */ + return true; + } + + DEBUG_PRINTF(" not found\n"); + return false; +} + +/* For undo, restore unchanged datablock from old main. */ +static void read_libblock_undo_restore_identical( + 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); + + 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; + + 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); + + /* 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. */ +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); +} + +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. + * + * 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, + const int tag, + const bool placeholder_set_indirect_extern, + ID **r_id) +{ + /* 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; + 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. */ + 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 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); + } + + /* 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 = 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); + + if (r_id) { + *r_id = id_target; + } + + /* 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; + + if (bhead->code == ID_LINK_PLACEHOLDER) { + /* Read placeholder for 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; + } + else { + id_tag |= LIB_TAG_EXTERN; + } + } + + 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 (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... @@ -9698,39 +9797,12 @@ 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 (id_old) { + /* For undo, store contents read into id at id_old. */ + read_libblock_undo_restore_at_old_address(fd, main, id, id_old); } - return (bhead); + return bhead; } /** \} */ @@ -10107,7 +10179,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); @@ -10175,7 +10247,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; @@ -10193,6 +10264,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/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; 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/blenloader/intern/versioning_280.c b/source/blender/blenloader/intern/versioning_280.c index a95cb74af51..ff3aef4588f 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; - } - } - } - } } } @@ -4136,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); @@ -4205,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) { @@ -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. */ + } } 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/blenloader/intern/writefile.c b/source/blender/blenloader/intern/writefile.c index 2cea7bff718..68be8683f84 100644 --- a/source/blender/blenloader/intern/writefile.c +++ b/source/blender/blenloader/intern/writefile.c @@ -4379,8 +4379,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/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/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; } 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); 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; 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/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. diff --git a/source/blender/depsgraph/intern/depsgraph_tag.cc b/source/blender/depsgraph/intern/depsgraph_tag.cc index f1180c16a87..627a93b5869 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 |= deg_recalc_flags_effective(NULL, 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/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, 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]); } } 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) */ diff --git a/source/blender/editors/armature/armature_add.c b/source/blender/editors/armature/armature_add.c index f6875a6e158..dfb274fdefe 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,434 @@ 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(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; + 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); - ED_armature_ebone_unique_name(editbones, eBone->name, NULL); - BLI_addtail(editbones, eBone); + if (pchan->custom != NULL) { + Main *bmain = CTX_data_main(C); + char name_flip[MAX_ID_NAME - 2]; + /* 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 +878,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 +971,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 +1000,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 +1023,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 +1178,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) { + /* 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); + 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 +1238,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 +1253,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); } } @@ -1232,7 +1691,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"; 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); 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; 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); 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; 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/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_panel.c b/source/blender/editors/interface/interface_panel.c index b3854cfc4ae..d1c61925d40 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(); } } @@ -1622,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) { diff --git a/source/blender/editors/interface/interface_utils.c b/source/blender/editors/interface/interface_utils.c index a69837e9b51..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) { @@ -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); } } 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 { diff --git a/source/blender/editors/mesh/editmesh_tools.c b/source/blender/editors/mesh/editmesh_tools.c index b9ac24e1d03..ba3520f2217 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, @@ -7830,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); @@ -7842,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); } @@ -7966,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); @@ -8136,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; } @@ -8169,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; } @@ -8183,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; } @@ -8228,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; @@ -8273,7 +8285,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 +8496,7 @@ void MESH_OT_split_normals(struct wmOperatorType *ot) /** \} */ /* -------------------------------------------------------------------- */ -/** \name Average Loop Normals +/** \name Average Loop Normals Operator * \{ */ enum { @@ -8716,7 +8728,7 @@ void MESH_OT_average_normals(struct wmOperatorType *ot) /** \} */ /* -------------------------------------------------------------------- */ -/** \name Custom Normal Interface Tools +/** \name Custom Normal Interface Tools Operator * \{ */ enum { @@ -8952,6 +8964,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,7 +9077,13 @@ 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"); } -static int edbm_smoothen_normals_exec(bContext *C, wmOperator *op) +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Smooth Normal Vectors Operator + * \{ */ + +static int edbm_smooth_normals_exec(bContext *C, wmOperator *op) { ViewLayer *view_layer = CTX_data_view_layer(C); uint objects_len = 0; @@ -9112,7 +9136,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; } @@ -9126,7 +9150,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; } @@ -9144,15 +9168,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/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); +} + +/** \} */ 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); } 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, 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_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/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; 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) { 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) { 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; 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"))) { 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]); */ } } diff --git a/source/blender/editors/undo/memfile_undo.c b/source/blender/editors/undo/memfile_undo.c index 086aa6c4c9d..ebd5b2272b1 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 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); + } } 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)); 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<string> &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/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..d16edab5ac9 100644 --- a/source/blender/gpu/intern/gpu_batch_presets.c +++ b/source/blender/gpu/intern/gpu_batch_presets.c @@ -27,13 +27,20 @@ #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 */ #include "GPU_batch_utils.h" #include "gpu_shader_private.h" +/* -------------------------------------------------------------------- */ +/** \name Local Structures + * \{ */ + /* Struct to store 3D Batches and their format */ static struct { struct { @@ -53,8 +60,27 @@ 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}; +/** \} */ + /* -------------------------------------------------------------------- */ /** \name 3D Primitives * \{ */ @@ -71,6 +97,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 +231,114 @@ 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); + GPU_batch_discard(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; +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Preset Registration Management + * \{ */ + void gpu_batch_presets_init(void) { BLI_mutex_init(&g_presets_3d.mutex); @@ -259,3 +405,5 @@ void gpu_batch_presets_exit(void) BLI_mutex_end(&g_presets_3d.mutex); } + +/** \} */ 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/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"; 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/makesdna/DNA_userdef_types.h b/source/blender/makesdna/DNA_userdef_types.h index 0d9336ac62b..5c620a9a346 100644 --- a/source/blender/makesdna/DNA_userdef_types.h +++ b/source/blender/makesdna/DNA_userdef_types.h @@ -1122,12 +1122,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_DOTRANSLATE = (1 << 5), - USER_TR_UNUSED_6 = (1 << 6), /* cleared */ - USER_TR_UNUSED_7 = (1 << 7), /* 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_NEWDATANAME = (1 << 8), } eUserpref_Translation_Flags; @@ -1306,6 +1306,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 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}, }; diff --git a/source/blender/makesrna/intern/rna_userdef.c b/source/blender/makesrna/intern/rna_userdef.c index 5354cf463eb..ee3434905b0 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), @@ -544,7 +557,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); } @@ -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 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/blender/windowmanager/intern/wm_files.c b/source/blender/windowmanager/intern/wm_files.c index 95c7afcbf15..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 */ @@ -1433,6 +1436,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; } @@ -2298,7 +2304,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 +2542,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"); } } @@ -2715,8 +2721,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); 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_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); } } 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/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(); } } diff --git a/source/creator/CMakeLists.txt b/source/creator/CMakeLists.txt index a8243e2119f..fa25248523c 100644 --- a/source/creator/CMakeLists.txt +++ b/source/creator/CMakeLists.txt @@ -1062,6 +1062,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 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); |