Grease Pencil: Make brush asset pinned materials local
Keeping these as linked datablocks to the brush does not match the idea that assets should generally be appended, and leads to some confusing situations with linked materials on objects. Now use either a local material with matching weak library reference or make a local copy if it does not exist yet. This also add weak library references to the materials in the 2D Animation template, so they will be reused. A problem is that weak library references include a full path to assets blend files, including the Blender version for the essentials assets files. This means weak library references do not work across platforms and Blender versions. Another known limitation is that if the (linked) Brush Asset material is edited, and there is already a local copy of it, this local copy will remain unchanged and will be used by future strokes as well. Ref #131186 Pull Request: https://projects.blender.org/blender/blender/pulls/134226
This commit is contained in:
@@ -68,4 +68,9 @@ bool asset_edit_id_save(Main &global_main, const ID &id, ReportList &reports);
|
||||
ID *asset_edit_id_revert(Main &global_main, ID &id, ReportList &reports);
|
||||
bool asset_edit_id_delete(Main &global_main, ID &id, ReportList &reports);
|
||||
|
||||
/** Find a local copy of the asset. */
|
||||
ID *asset_edit_id_find_local(Main &global_main, ID &id);
|
||||
/** Ensure a local copy of the asset exists. */
|
||||
ID *asset_edit_id_ensure_local(Main &global_main, ID &id);
|
||||
|
||||
} // namespace blender::bke
|
||||
|
||||
@@ -476,6 +476,21 @@ void BKE_main_library_weak_reference_remove_item(
|
||||
const char *library_id_name,
|
||||
ID *old_id) ATTR_NONNULL();
|
||||
|
||||
/**
|
||||
* Find local ID with weak library reference matching library and ID name.
|
||||
* For cases where creating a full MainLibraryWeakReferenceMap is unnecessary.
|
||||
*/
|
||||
ID *BKE_main_library_weak_reference_find(Main *bmain,
|
||||
const char *library_filepath,
|
||||
const char *library_id_name);
|
||||
|
||||
/**
|
||||
* Add library weak reference to ID, referencing the specified library and ID name.
|
||||
* For cases where creating a full MainLibraryWeakReferenceMap is unnecessary.*/
|
||||
void BKE_main_library_weak_reference_add(ID *id,
|
||||
const char *library_filepath,
|
||||
const char *library_id_name);
|
||||
|
||||
/* *** Generic utils to loop over whole Main database. *** */
|
||||
|
||||
#define FOREACH_MAIN_LISTBASE_ID_BEGIN(_lb, _id) \
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
#include "BLI_path_utils.hh"
|
||||
#include "BLI_string.h"
|
||||
|
||||
#include "DNA_ID.h"
|
||||
#include "DNA_asset_types.h"
|
||||
#include "DNA_space_types.h"
|
||||
|
||||
@@ -386,4 +387,36 @@ bool asset_edit_id_is_writable(const ID &id)
|
||||
return asset_edit_id_is_editable(id) && (id.lib->runtime.tag & LIBRARY_ASSET_FILE_WRITABLE);
|
||||
}
|
||||
|
||||
ID *asset_edit_id_find_local(Main &global_main, ID &id)
|
||||
{
|
||||
if (!asset_edit_id_is_editable(id)) {
|
||||
return &id;
|
||||
}
|
||||
|
||||
/* Make filepath relative to match weak ref, it might not be if Library datablock is new. */
|
||||
char lib_filepath[FILE_MAX];
|
||||
STRNCPY(lib_filepath, id.lib->filepath);
|
||||
BLI_path_rel(lib_filepath, BKE_main_blendfile_path(&global_main));
|
||||
|
||||
return BKE_main_library_weak_reference_find(&global_main, lib_filepath, id.name);
|
||||
}
|
||||
|
||||
ID *asset_edit_id_ensure_local(Main &global_main, ID &id)
|
||||
{
|
||||
ID *local_id = asset_edit_id_find_local(global_main, id);
|
||||
if (local_id) {
|
||||
return local_id;
|
||||
}
|
||||
|
||||
/* Make local and create weak library reference for reuse. */
|
||||
BKE_lib_id_make_local(&global_main,
|
||||
&id,
|
||||
LIB_ID_MAKELOCAL_FORCE_COPY | LIB_ID_MAKELOCAL_INDIRECT |
|
||||
LIB_ID_MAKELOCAL_ASSET_DATA_CLEAR);
|
||||
BLI_assert(id.newid != nullptr);
|
||||
BKE_main_library_weak_reference_add(id.newid, id.lib->filepath, id.name);
|
||||
|
||||
return id.newid;
|
||||
}
|
||||
|
||||
} // namespace blender::bke
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
#include "BKE_action.hh"
|
||||
#include "BKE_anim_data.hh"
|
||||
#include "BKE_animsys.h"
|
||||
#include "BKE_asset_edit.hh"
|
||||
#include "BKE_bake_data_block_id.hh"
|
||||
#include "BKE_curves.hh"
|
||||
#include "BKE_customdata.hh"
|
||||
@@ -2465,6 +2466,11 @@ static Material *grease_pencil_object_material_ensure_from_brush_pinned(Main *bm
|
||||
{
|
||||
Material *ma = (brush->gpencil_settings) ? brush->gpencil_settings->material : nullptr;
|
||||
|
||||
if (ma) {
|
||||
/* Ensure we assign a local datablock if this is an editable asset. */
|
||||
ma = reinterpret_cast<Material *>(blender::bke::asset_edit_id_ensure_local(*bmain, ma->id));
|
||||
}
|
||||
|
||||
/* check if the material is already on object material slots and add it if missing */
|
||||
if (ma && BKE_object_material_index_get(ob, ma) < 0) {
|
||||
/* The object's active material is what's used for the unpinned material. Do not touch it
|
||||
@@ -2509,8 +2515,12 @@ Material *BKE_grease_pencil_object_material_alt_ensure_from_brush(Main *bmain,
|
||||
{
|
||||
Material *material_alt = (brush->gpencil_settings) ? brush->gpencil_settings->material_alt :
|
||||
nullptr;
|
||||
if (material_alt && BKE_object_material_slot_find_index(ob, material_alt) != -1) {
|
||||
return material_alt;
|
||||
if (material_alt) {
|
||||
material_alt = reinterpret_cast<Material *>(
|
||||
blender::bke::asset_edit_id_find_local(*bmain, material_alt->id));
|
||||
if (material_alt && BKE_object_material_slot_find_index(ob, material_alt) != -1) {
|
||||
return material_alt;
|
||||
}
|
||||
}
|
||||
|
||||
return BKE_grease_pencil_object_material_ensure_from_brush(bmain, ob, brush);
|
||||
|
||||
@@ -711,14 +711,10 @@ void BKE_main_library_weak_reference_add_item(
|
||||
BLI_assert(new_id->library_weak_reference == nullptr);
|
||||
BLI_assert(BKE_idtype_idcode_append_is_reusable(GS(new_id->name)));
|
||||
|
||||
new_id->library_weak_reference = static_cast<LibraryWeakReference *>(
|
||||
MEM_mallocN(sizeof(*(new_id->library_weak_reference)), __func__));
|
||||
|
||||
const LibWeakRefKey key{library_filepath, library_id_name};
|
||||
library_weak_reference_mapping->map.add_new(key, new_id);
|
||||
|
||||
STRNCPY(new_id->library_weak_reference->library_filepath, library_filepath);
|
||||
STRNCPY(new_id->library_weak_reference->library_id_name, library_id_name);
|
||||
BKE_main_library_weak_reference_add(new_id, library_filepath, library_id_name);
|
||||
}
|
||||
|
||||
void BKE_main_library_weak_reference_update_item(
|
||||
@@ -760,6 +756,35 @@ void BKE_main_library_weak_reference_remove_item(
|
||||
MEM_SAFE_FREE(old_id->library_weak_reference);
|
||||
}
|
||||
|
||||
ID *BKE_main_library_weak_reference_find(Main *bmain,
|
||||
const char *library_filepath,
|
||||
const char *library_id_name)
|
||||
{
|
||||
ListBase *id_list = which_libbase(bmain, GS(library_id_name));
|
||||
LISTBASE_FOREACH (ID *, existing_id, id_list) {
|
||||
if (existing_id->library_weak_reference &&
|
||||
STREQ(existing_id->library_weak_reference->library_id_name, library_id_name) &&
|
||||
STREQ(existing_id->library_weak_reference->library_filepath, library_filepath))
|
||||
{
|
||||
return existing_id;
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void BKE_main_library_weak_reference_add(ID *local_id,
|
||||
const char *library_filepath,
|
||||
const char *library_id_name)
|
||||
{
|
||||
if (local_id->library_weak_reference == nullptr) {
|
||||
local_id->library_weak_reference = MEM_cnew<LibraryWeakReference>(__func__);
|
||||
}
|
||||
|
||||
STRNCPY(local_id->library_weak_reference->library_filepath, library_filepath);
|
||||
STRNCPY(local_id->library_weak_reference->library_id_name, library_id_name);
|
||||
}
|
||||
|
||||
BlendThumbnail *BKE_main_thumbnail_from_buffer(Main *bmain, const uint8_t *rect, const int size[2])
|
||||
{
|
||||
BlendThumbnail *data = nullptr;
|
||||
|
||||
@@ -505,6 +505,17 @@ void BLO_update_defaults_startup_blend(Main *bmain, const char *app_template)
|
||||
}
|
||||
}
|
||||
|
||||
/* Add library weak references to avoid duplicating materials from essentials. */
|
||||
const std::optional<std::string> assets_path = BKE_appdir_folder_id(BLENDER_SYSTEM_DATAFILES,
|
||||
"assets/brushes");
|
||||
if (assets_path.has_value()) {
|
||||
const std::string assets_blend_path = *assets_path + "/essentials_brushes-gp_draw.blend";
|
||||
LISTBASE_FOREACH (Material *, material, &bmain->materials) {
|
||||
BKE_main_library_weak_reference_add(
|
||||
&material->id, assets_blend_path.c_str(), material->id.name);
|
||||
}
|
||||
}
|
||||
|
||||
/* Reset grease pencil paint modes. */
|
||||
LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) {
|
||||
ToolSettings *ts = scene->toolsettings;
|
||||
|
||||
Reference in New Issue
Block a user