Brush Assets: Make revert and delete operators affect dependencies #119806
|
@ -86,7 +86,9 @@ void BKE_asset_weak_reference_read(BlendDataReader *reader, AssetWeakReference *
|
||||||
* currently used for brush assets and their dependencies.
|
* currently used for brush assets and their dependencies.
|
||||||
*/
|
*/
|
||||||
Main *BKE_asset_weak_reference_main(const ID *id);
|
Main *BKE_asset_weak_reference_main(const ID *id);
|
||||||
void BKE_asset_weak_reference_main_free();
|
|
||||||
ID *BKE_asset_weak_reference_ensure(Main &global_main,
|
ID *BKE_asset_weak_reference_ensure(Main &global_main,
|
||||||
ID_Type id_type,
|
ID_Type id_type,
|
||||||
const AssetWeakReference &weak_ref);
|
const AssetWeakReference &weak_ref);
|
||||||
|
void BKE_asset_weak_reference_main_reload(Main &global_main, Main &main);
|
||||||
|
void BKE_asset_weak_reference_main_free(Main &global_main, Main &asset_main);
|
||||||
|
void BKE_asset_weak_reference_main_free_all();
|
||||||
|
|
|
@ -9,7 +9,9 @@
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
|
#include "BLI_path_util.h"
|
||||||
#include "BLI_string.h"
|
#include "BLI_string.h"
|
||||||
|
#include "BLI_vector.hh"
|
||||||
|
|
||||||
#include "DNA_space_types.h"
|
#include "DNA_space_types.h"
|
||||||
|
|
||||||
|
@ -20,10 +22,9 @@
|
||||||
#include "BKE_blendfile_link_append.hh"
|
#include "BKE_blendfile_link_append.hh"
|
||||||
#include "BKE_idtype.hh"
|
#include "BKE_idtype.hh"
|
||||||
#include "BKE_lib_id.hh"
|
#include "BKE_lib_id.hh"
|
||||||
|
#include "BKE_lib_remap.hh"
|
||||||
#include "BKE_main.hh"
|
#include "BKE_main.hh"
|
||||||
|
|
||||||
#include "BLI_vector.hh"
|
|
||||||
|
|
||||||
#include "BLO_read_write.hh"
|
#include "BLO_read_write.hh"
|
||||||
#include "BLO_readfile.hh"
|
#include "BLO_readfile.hh"
|
||||||
|
|
||||||
|
@ -132,12 +133,9 @@ void BKE_asset_weak_reference_read(BlendDataReader *reader, AssetWeakReference *
|
||||||
/* Main database for storing assets that are weak referenced.
|
/* Main database for storing assets that are weak referenced.
|
||||||
*
|
*
|
||||||
* This avoids mixing asset datablocks in the regular main, which leads to naming conflicts and
|
* This avoids mixing asset datablocks in the regular main, which leads to naming conflicts and
|
||||||
* confusing user interface.
|
* confusing user interface. */
|
||||||
*
|
|
||||||
* TODO: Heavily WIP code. */
|
|
||||||
|
|
||||||
struct AssetWeakReferenceMain {
|
struct AssetWeakReferenceMain {
|
||||||
/* TODO: not sure if this is the best unique identifier. */
|
|
||||||
std::string filepath;
|
std::string filepath;
|
||||||
Main *main;
|
Main *main;
|
||||||
|
|
||||||
|
@ -145,12 +143,22 @@ struct AssetWeakReferenceMain {
|
||||||
: filepath(std::move(filepath)), main(BKE_main_new())
|
: filepath(std::move(filepath)), main(BKE_main_new())
|
||||||
{
|
{
|
||||||
main->is_asset_weak_reference_main = true;
|
main->is_asset_weak_reference_main = true;
|
||||||
|
BLI_assert(!BLI_path_is_rel(filepath.c_str()));
|
||||||
}
|
}
|
||||||
AssetWeakReferenceMain(const AssetWeakReferenceMain &) = delete;
|
AssetWeakReferenceMain(const AssetWeakReferenceMain &) = delete;
|
||||||
AssetWeakReferenceMain(AssetWeakReferenceMain &&other)
|
AssetWeakReferenceMain(AssetWeakReferenceMain &&other)
|
||||||
: filepath(std::exchange(other.filepath, "")), main(std::exchange(other.main, nullptr))
|
: filepath(std::exchange(other.filepath, "")), main(std::exchange(other.main, nullptr))
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
AssetWeakReferenceMain &operator=(AssetWeakReferenceMain &&other)
|
||||||
|
{
|
||||||
|
if (this == &other) {
|
||||||
brecht marked this conversation as resolved
Outdated
|
|||||||
|
return *this;
|
||||||
|
}
|
||||||
|
this->filepath = std::exchange(other.filepath, "");
|
||||||
|
this->main = std::exchange(other.main, nullptr);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
~AssetWeakReferenceMain()
|
~AssetWeakReferenceMain()
|
||||||
{
|
{
|
||||||
|
@ -158,8 +166,70 @@ struct AssetWeakReferenceMain {
|
||||||
BKE_main_free(main);
|
BKE_main_free(main);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void reload(Main &global_main);
|
||||||
|
void clear_users(Main &global_main);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
void AssetWeakReferenceMain::reload(Main &global_main)
|
||||||
|
{
|
||||||
|
Main *old_main = this->main;
|
||||||
|
this->main = BKE_main_new();
|
||||||
|
this->main->is_asset_weak_reference_main = true;
|
||||||
|
|
||||||
|
/* Fill fresh main database with same datablock as before. */
|
||||||
|
LibraryLink_Params lapp_params{};
|
||||||
|
lapp_params.bmain = this->main;
|
||||||
|
BlendfileLinkAppendContext *lapp_context = BKE_blendfile_link_append_context_new(&lapp_params);
|
||||||
|
BKE_blendfile_link_append_context_flag_set(lapp_context, BLO_LIBLINK_FORCE_INDIRECT, true);
|
||||||
|
BKE_blendfile_link_append_context_flag_set(lapp_context, 0, true);
|
||||||
|
|
||||||
brecht marked this conversation as resolved
Hans Goudey
commented
`to be append` -> `to be appended`
|
|||||||
|
BKE_blendfile_link_append_context_library_add(lapp_context, this->filepath.c_str(), nullptr);
|
||||||
|
|
||||||
|
/* Requests all existing datablocks to be appended again. */
|
||||||
|
ID *old_id;
|
||||||
|
FOREACH_MAIN_ID_BEGIN (old_main, old_id) {
|
||||||
|
ID_Type old_id_code = GS(old_id->name);
|
||||||
|
if (BKE_idtype_idcode_is_linkable(old_id_code)) {
|
||||||
|
BlendfileLinkAppendContextItem *lapp_item = BKE_blendfile_link_append_context_item_add(
|
||||||
|
lapp_context, old_id->name + 2, old_id_code, nullptr);
|
||||||
|
BKE_blendfile_link_append_context_item_library_index_enable(lapp_context, lapp_item, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
FOREACH_MAIN_ID_END;
|
||||||
|
|
||||||
|
BKE_blendfile_link(lapp_context, nullptr);
|
||||||
|
BKE_blendfile_append(lapp_context, nullptr);
|
||||||
|
|
||||||
|
BKE_blendfile_link_append_context_free(lapp_context);
|
||||||
|
|
||||||
|
BKE_main_id_tag_all(this->main, LIB_TAG_ASSET_MAIN, true);
|
||||||
|
|
||||||
|
/* Remap old to new. */
|
||||||
|
bke::id::IDRemapper mappings;
|
||||||
|
FOREACH_MAIN_ID_BEGIN (old_main, old_id) {
|
||||||
|
ID *new_id = BKE_libblock_find_name(this->main, GS(old_id->name), old_id->name + 2);
|
||||||
|
mappings.add(old_id, new_id);
|
||||||
|
}
|
||||||
|
FOREACH_MAIN_ID_END;
|
||||||
|
BKE_libblock_remap_multiple(&global_main, mappings, 0);
|
||||||
|
|
||||||
|
/* Free old database. */
|
||||||
|
BKE_main_free(old_main);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AssetWeakReferenceMain::clear_users(Main &global_main)
|
||||||
|
{
|
||||||
|
/* Remap old to null pointer. */
|
||||||
|
bke::id::IDRemapper mappings;
|
||||||
|
ID *old_id;
|
||||||
|
FOREACH_MAIN_ID_BEGIN (this->main, old_id) {
|
||||||
|
mappings.add(old_id, nullptr);
|
||||||
|
}
|
||||||
|
FOREACH_MAIN_ID_END;
|
||||||
|
BKE_libblock_remap_multiple(&global_main, mappings, 0);
|
||||||
|
}
|
||||||
|
|
||||||
static Vector<AssetWeakReferenceMain> &get_weak_reference_mains()
|
static Vector<AssetWeakReferenceMain> &get_weak_reference_mains()
|
||||||
{
|
{
|
||||||
static Vector<AssetWeakReferenceMain> mains;
|
static Vector<AssetWeakReferenceMain> mains;
|
||||||
|
@ -196,7 +266,34 @@ static Main &asset_weak_reference_main_ensure(const StringRef filepath)
|
||||||
return *get_weak_reference_mains().last().main;
|
return *get_weak_reference_mains().last().main;
|
||||||
}
|
}
|
||||||
|
|
||||||
brecht marked this conversation as resolved
Outdated
Hans Goudey
commented
Could consider extracting this for loop search to a separate function, I bet it will be used more in the future too. Could consider extracting this for loop search to a separate function, I bet it will be used more in the future too.
Brecht Van Lommel
commented
I prefer to not do this preemptively. I prefer to not do this preemptively.
|
|||||||
void BKE_asset_weak_reference_main_free()
|
void BKE_asset_weak_reference_main_reload(Main &global_main, Main &asset_main)
|
||||||
|
{
|
||||||
|
for (AssetWeakReferenceMain &weak_ref_main : get_weak_reference_mains()) {
|
||||||
|
if (weak_ref_main.main == &asset_main) {
|
||||||
|
weak_ref_main.reload(global_main);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
BLI_assert_unreachable();
|
||||||
|
}
|
||||||
|
|
||||||
|
void BKE_asset_weak_reference_main_free(Main &global_main, Main &asset_main)
|
||||||
|
{
|
||||||
|
int index = 0;
|
||||||
|
for (AssetWeakReferenceMain &weak_ref_main : get_weak_reference_mains()) {
|
||||||
|
if (weak_ref_main.main == &asset_main) {
|
||||||
|
weak_ref_main.clear_users(global_main);
|
||||||
|
get_weak_reference_mains().remove(index);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
index++;
|
||||||
|
}
|
||||||
|
|
||||||
|
BLI_assert_unreachable();
|
||||||
|
}
|
||||||
|
|
||||||
|
void BKE_asset_weak_reference_main_free_all()
|
||||||
{
|
{
|
||||||
get_weak_reference_mains().clear_and_shrink();
|
get_weak_reference_mains().clear_and_shrink();
|
||||||
}
|
}
|
||||||
|
@ -247,7 +344,6 @@ ID *BKE_asset_weak_reference_ensure(Main &global_main,
|
||||||
|
|
||||||
BKE_blendfile_link_append_context_free(lapp_context);
|
BKE_blendfile_link_append_context_free(lapp_context);
|
||||||
|
|
||||||
/* TODO: only do for new ones? */
|
|
||||||
BKE_main_id_tag_all(&bmain, LIB_TAG_ASSET_MAIN, true);
|
BKE_main_id_tag_all(&bmain, LIB_TAG_ASSET_MAIN, true);
|
||||||
|
|
||||||
/* Verify that the name matches. It must for referencing the same asset again to work. */
|
/* Verify that the name matches. It must for referencing the same asset again to work. */
|
||||||
|
|
|
@ -64,7 +64,7 @@ void BKE_blender_free()
|
||||||
/* Free separate data-bases after #BKE_blender_globals_clear in case any data-blocks in the
|
/* Free separate data-bases after #BKE_blender_globals_clear in case any data-blocks in the
|
||||||
* global main use pointers to asset main data-blocks when they're freed. That generally
|
* global main use pointers to asset main data-blocks when they're freed. That generally
|
||||||
* shouldn't happen but it's better to be safe. */
|
* shouldn't happen but it's better to be safe. */
|
||||||
BKE_asset_weak_reference_main_free();
|
BKE_asset_weak_reference_main_free_all();
|
||||||
|
|
||||||
if (G.log.file != nullptr) {
|
if (G.log.file != nullptr) {
|
||||||
fclose(static_cast<FILE *>(G.log.file));
|
fclose(static_cast<FILE *>(G.log.file));
|
||||||
|
|
|
@ -34,7 +34,6 @@
|
||||||
#include "BKE_context.hh"
|
#include "BKE_context.hh"
|
||||||
#include "BKE_image.h"
|
#include "BKE_image.h"
|
||||||
#include "BKE_lib_id.hh"
|
#include "BKE_lib_id.hh"
|
||||||
#include "BKE_lib_override.hh"
|
|
||||||
#include "BKE_lib_remap.hh"
|
#include "BKE_lib_remap.hh"
|
||||||
#include "BKE_main.hh"
|
#include "BKE_main.hh"
|
||||||
#include "BKE_paint.hh"
|
#include "BKE_paint.hh"
|
||||||
|
@ -1248,11 +1247,8 @@ static int brush_asset_delete_exec(bContext *C, wmOperator *op)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (asset_main != bmain) {
|
if (asset_main != bmain) {
|
||||||
// TODO: hack: no pointer should exist, should do runtime lookup
|
BKE_asset_weak_reference_main_free(*bmain, *asset_main);
|
||||||
BKE_libblock_remap(bmain, brush, nullptr, 0);
|
|
||||||
}
|
}
|
||||||
BKE_id_delete(asset_main, brush);
|
|
||||||
// TODO: delete whole asset main if empty?
|
|
||||||
|
|
||||||
refresh_asset_library(C, *library);
|
refresh_asset_library(C, *library);
|
||||||
|
|
||||||
|
@ -1349,14 +1345,13 @@ static void BRUSH_OT_asset_update(wmOperatorType *ot)
|
||||||
|
|
||||||
static bool brush_asset_revert_poll(bContext *C)
|
static bool brush_asset_revert_poll(bContext *C)
|
||||||
{
|
{
|
||||||
/* TODO: check if there is anything to revert? */
|
|
||||||
Paint *paint = BKE_paint_get_active_from_context(C);
|
Paint *paint = BKE_paint_get_active_from_context(C);
|
||||||
Brush *brush = (paint) ? BKE_paint_brush(paint) : nullptr;
|
Brush *brush = (paint) ? BKE_paint_brush(paint) : nullptr;
|
||||||
if (paint == nullptr || brush == nullptr) {
|
if (paint == nullptr || brush == nullptr) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return paint->brush_asset_reference && ID_IS_ASSET(brush);
|
return paint->brush_asset_reference && (brush->id.tag & LIB_TAG_ASSET_MAIN);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int brush_asset_revert_exec(bContext *C, wmOperator * /*op*/)
|
static int brush_asset_revert_exec(bContext *C, wmOperator * /*op*/)
|
||||||
|
@ -1366,19 +1361,12 @@ static int brush_asset_revert_exec(bContext *C, wmOperator * /*op*/)
|
||||||
Brush *brush = BKE_paint_brush(paint);
|
Brush *brush = BKE_paint_brush(paint);
|
||||||
Main *asset_main = BKE_main_from_id(bmain, &brush->id);
|
Main *asset_main = BKE_main_from_id(bmain, &brush->id);
|
||||||
|
|
||||||
// TODO: delete and reload dependencies too?
|
/* Reload entire main, including texture dependencies. This relies on there
|
||||||
brecht marked this conversation as resolved
Outdated
Hans Goudey
commented
I'd add a comment here that this relies on a single brush asset stored per file I'd add a comment here that this relies on a single brush asset stored per file
|
|||||||
// TODO: hack to make remapping work, should not be needed
|
* being only a single brush asset per blend file. */
|
||||||
// if we can make brush pointer not part of ID management at all
|
BKE_asset_weak_reference_main_reload(*bmain, *asset_main);
|
||||||
BLI_remlink(&asset_main->brushes, brush);
|
|
||||||
|
|
||||||
Brush *new_brush = reinterpret_cast<Brush *>(
|
WM_main_add_notifier(NC_BRUSH | NA_EDITED, nullptr);
|
||||||
BKE_asset_weak_reference_ensure(*bmain, ID_BR, *paint->brush_asset_reference));
|
WM_main_add_notifier(NC_TEXTURE | ND_NODES, nullptr);
|
||||||
|
|
||||||
BKE_libblock_remap(bmain, brush, new_brush, 0);
|
|
||||||
BLI_addtail(&asset_main->brushes, brush);
|
|
||||||
BKE_id_delete(asset_main, brush);
|
|
||||||
|
|
||||||
WM_main_add_notifier(NC_BRUSH | NA_EDITED, new_brush);
|
|
||||||
|
|
||||||
return OPERATOR_FINISHED;
|
return OPERATOR_FINISHED;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
I think this needs a
this == &other
check