Page MenuHome

AssetBrowser: Localize external files.
Needs RevisionPublic

Authored by Jeroen Bakker (jbakker) on Sep 8 2021, 3:58 PM.

Details

Summary

This patch would localize external files when appending assets.
Localizing external files would make a local copy of a Image, Sound, or other
external stored file.

Only files that are not packed would be localized and are relative.
This patch contains only supports Single image files, but contains the machinery
to be easily extended.

Implementation overview

Before localizing an asset BKE_external_files_create is invoked. This function
creates a struct containing the original paths to the external files that needs
to be localized. It uses the newly added IDTypeInfo.foreach_external_file callback.
This callback goes over each external file for a given ID.
This patch only implements this for single file image sources (Files + Movies)

After localizing the asset BKE_external_files_localize is invoked. This function reuses
the BKE_packedfiles logic to copy the files over to the current file.

TODO

To be solved before committing.

  • Currently fails as the orig_id.lib is cleared by the make_local. Discussed solution is to store the source_library in the item.

To be solved when global implementation is agreed upon.

  • Add support for Image Sequences.
  • Add support for Tiled images.

Diff Detail

Repository
rB Blender
Branch
arcpatch-D12423 (branched from master)
Build Status
Buildable 16969
Build 16969: arc lint + arc unit

Event Timeline

Jeroen Bakker (jbakker) retitled this revision from AssetBrowser: Localize external files. to AssetBrowser: Localize external files [PoC]..
Jeroen Bakker (jbakker) retitled this revision from AssetBrowser: Localize external files [PoC]. to AssetBrowser: Localize external files..
  • Reuse packed file logic.

-rebased with master.

  • Implemented External files for Single file images.
Jeroen Bakker (jbakker) edited the summary of this revision. (Show Details)Sep 13 2021, 3:34 PM
Jeroen Bakker (jbakker) edited the summary of this revision. (Show Details)
Jeroen Bakker (jbakker) edited the summary of this revision. (Show Details)
Jeroen Bakker (jbakker) edited the summary of this revision. (Show Details)Sep 13 2021, 3:36 PM
Jeroen Bakker (jbakker) edited the summary of this revision. (Show Details)
  • Added license to top of files.

Generally this seems quite fine to me. Are you planning to address the remaining TODOs soon? I'd like to get this in for BCon2.

source/blender/blenkernel/intern/external_files.cc
85

I guess ima is the same as the id stored in the struct? Any reason to not use that instead?

124–130

Any reason to use this rather than ID_IS_LINKED()? Also, can we make these functions const correct?

242

Would prefer using OBJECT_GUARDED_NEW()/OBJECT_GUARDED_DELETE().

Jeroen Bakker (jbakker) planned changes to this revision.Sep 20 2021, 8:58 AM

This patch needs to be adjusted to the current master. We should not rely on the tagging anymore, but on WMLinkAppendData. Change is a bit more than expected, would need to look at it carefully.

source/blender/blenkernel/intern/external_files.cc
85

Yes, could remove this method or make it static.
Removing the Image parameter would create two methods with the same identifier. Think static is the cleanest.

Jeroen Bakker (jbakker) marked 3 inline comments as done.
  • Applied D12765
  • Try to use orig_id, but it failed.
Jeroen Bakker (jbakker) planned changes to this revision.Oct 6 2021, 4:27 PM
Jeroen Bakker (jbakker) edited the summary of this revision. (Show Details)Oct 6 2021, 4:40 PM
Jeroen Bakker (jbakker) edited the summary of this revision. (Show Details)Oct 6 2021, 4:52 PM
  • Modified localize external files via the source library.
Jeroen Bakker (jbakker) edited the summary of this revision. (Show Details)Oct 11 2021, 9:13 AM

Split into multiple patches.

Bastien Montagne (mont29) requested changes to this revision.Oct 11 2021, 10:58 AM

Am not convinced there should be a new BKE item for that? It's extremely specific 'one case' usage, would have rather kept everything in wm_files_link.c tbh (except for the IDType callback). But no super-strong opinion on this either, if consensus is to get this new BKE 'module' I can live with it.

Main strong bad thing in this patch for me is how update_file_path re-introduces ID-type specific behavior. The whole point of IDType and its callbacks is that all ID-specific code is kept there, and generic ID management code does not need to know actual ID type.

So think the new foreach_external_file callback should not use const file path, and add some extra info in case callback needs to edit the string, something along that line:

typedef void (*IDTypeForeachExternalFileFunctionCallback)(struct ID *id,
                                                          char **external_file_path,
                                                          size_t external_file_path_size,  /* In case it is an array of chars, 0 is dynamically allocated. */
                                                          const bool is_mem_alloc,  /* In case it is a dynamically allocated string (could also be a set of flags). */
                                                          void *user_data);

Then callbacks can properly edit the string themselves when needed.

Also, I don't think images are the only ID type that need this? Think movieclip, sound, scene (for the VSE), text, all node trees, etc. also need it? Maybe even meshes (for external custom data, although don't think this is really used in practice currently)?

source/blender/windowmanager/intern/wm_files_link.c
678

This behavior should be optional and flag-controlled (WM_APPEND_EXTRNAL_FILES_LOCALIZE ?). This function might be used only for asset currently, but this may not be the case in the future.

This revision now requires changes to proceed.Oct 11 2021, 10:58 AM

Am not convinced there should be a new BKE item for that? It's extremely specific 'one case' usage, would have rather kept everything in wm_files_link.c tbh (except for the IDType callback). But no super-strong opinion on this either, if consensus is to get this new BKE 'module' I can live with it.

I think that if certain code has a very specific, single use case, it's great to have it in a separate BKE module. Putting that functionality between more generic code would be more confusing to me than clearly separating those.

Main strong bad thing in this patch for me is how update_file_path re-introduces ID-type specific behavior. The whole point of IDType and its callbacks is that all ID-specific code is kept there, and generic ID management code does not need to know actual ID type.

I agree, ID-type-specific code should be in the corresponding IDType's callbacks.

So think the new foreach_external_file callback should not use const file path, and add some extra info in case callback needs to edit the string, something along that line:
[...] Then callbacks can properly edit the string themselves when needed.

I don't see how this follows from the preceeding text. If there is no concrete goal to make things mutable, we shouldn't. Such mutability adds all kinds of complexities, and if those complexities aren't even used at the moment, it isn't tested either. Either callbacks won't take this flexibility into account, setting the stage for future bugs, or it'll take extra effort to take into account these use cases as well (and they still aren't testable, so there are guaranteed to be bugs there).

typedef void (*IDTypeForeachExternalFileFunctionCallback)(struct ID *id,
                                                          char **external_file_path,
                                                          size_t external_file_path_size,  /* In case it is an array of chars, 0 is dynamically allocated. */
                                                          const bool is_mem_alloc,  /* In case it is a dynamically allocated string (could also be a set of flags). */
                                                          void *user_data);

If we do keep the mutable paths, I would strongly recommend to not have a redundant boolean parameter. If external_file_path_size == 0 already signifies "dynamically allocated", we don't need to pass is_mem_alloc=true.

Having said that, I think we should only continue with this mutable external_file_path if we also clearly define how such mutations are supposed to be handled by the IDType::foreach_external_file functions. Until there is a clear design for this, with concrete & testable goals, I wouldn't make the API more complex than necessary.

TL;DR: Yes, this is extremely rushed in, last minute change that is anything but trivial... Like half of what was done last month for asset project. Not happy with it, already said it several times. Urgency type of work is never fun and never lead to best possible cleanest solutions, especially not if design is needed.

In other words, I would not mind at all to keep this for after 3.0.


[...]

So think the new foreach_external_file callback should not use const file path, and add some extra info in case callback needs to edit the string, something along that line:
[...] Then callbacks can properly edit the string themselves when needed.

I don't see how this follows from the preceeding text. If there is no concrete goal to make things mutable, we shouldn't. Such mutability adds all kinds of complexities, and if those complexities aren't even used at the moment, it isn't tested either. Either callbacks won't take this flexibility into account, setting the stage for future bugs, or it'll take extra effort to take into account these use cases as well (and they still aren't testable, so there are guaranteed to be bugs there).

I do not see how you want to allow modification of those paths otherwise? Which is the very purpose of this patch, and is a very common use-case of such iterator, see existing BKE_bpath_traverse_id() usages.
Just like BKE_library_foreach_ID_link() allows to modify the iterated ID pointers. Having immutable paths here is basically useless, since callback code will have to find itself again what to edit.
(As a side note, one of the later goals of proposed new foreach_external_file is to replace BKE_bpath_traverse_id too - but this is definitively not for 3.0)

If editing such path requires specific handling (beyond regular ID tagging in depsgraph), then the specific IDtype iterator code should handle it .

Which points out to another need for those IDTypeForeachExternalFileFunctionCallback callbacks: they should return whether they edited the string or not.

typedef void (*IDTypeForeachExternalFileFunctionCallback)(struct ID *id,
                                                          char **external_file_path,
                                                          size_t external_file_path_size,  /* In case it is an array of chars, 0 is dynamically allocated. */
                                                          const bool is_mem_alloc,  /* In case it is a dynamically allocated string (could also be a set of flags). */
                                                          void *user_data);

If we do keep the mutable paths, I would strongly recommend to not have a redundant boolean parameter. If external_file_path_size == 0 already signifies "dynamically allocated", we don't need to pass is_mem_alloc=true.

Having said that, I think we should only continue with this mutable external_file_path if we also clearly define how such mutations are supposed to be handled by the IDType::foreach_external_file functions. Until there is a clear design for this, with concrete & testable goals, I wouldn't make the API more complex than necessary.

Suggested the extra boolean for sakes of clarity (and even to have a proper set of enum flags, in case we'd need to pass more flags in the future)...

@Bastien Montagne (mont29) I do have an idea how to design an API to address the issues we described above. I will work on the design this week and see how we can move forward.
Note as this feature has moved to 3.1 we should also lower the priority.