Assets: Support automatic collection previews

Adds supports for collection previews that are rendered automatically when
collections are marked as assets. (Or when preview rendering is triggered
differently, e.g. through the //Refresh Data-Block Previews// operator).

Idea in this patch is to create a collection instance empty outside of main for
the collection, and then reuse the object rendering code to render the preview.
This keeps things very simple and works just fine.

Differential Revision: https://developer.blender.org/D14460

Reviewed by: Bastien Montagne
This commit is contained in:
Julian Eisel 2022-03-29 15:36:02 +02:00
parent 9ec77d709c
commit 810e225c26
Notes: blender-bot 2023-02-14 06:54:28 +01:00
Referenced by issue #83836, Support Collection Preview Images
4 changed files with 60 additions and 4 deletions

View File

@ -163,9 +163,12 @@ int BKE_object_visibility(const struct Object *ob, int dag_eval_mode);
/**
* More general add: creates minimum required data, but without vertices etc.
*
* \param bmain: The main to add the object to. May be null for #LIB_ID_CREATE_NO_MAIN behavior.
*/
struct Object *BKE_object_add_only_object(struct Main *bmain, int type, const char *name)
ATTR_NONNULL(1) ATTR_RETURNS_NONNULL;
struct Object *BKE_object_add_only_object(struct Main *bmain,
int type,
const char *name) ATTR_RETURNS_NONNULL;
/**
* General add: to scene, with layer from area and default name.
*

View File

@ -416,7 +416,7 @@ void BKE_previewimg_id_custom_set(ID *id, const char *path)
bool BKE_previewimg_id_supports_jobs(const ID *id)
{
return ELEM(GS(id->name), ID_OB, ID_MA, ID_TE, ID_LA, ID_WO, ID_IM, ID_BR);
return ELEM(GS(id->name), ID_OB, ID_MA, ID_TE, ID_LA, ID_WO, ID_IM, ID_BR, ID_GR);
}
void BKE_previewimg_deferred_release(PreviewImage *prv)

View File

@ -2217,7 +2217,7 @@ Object *BKE_object_add_only_object(Main *bmain, int type, const char *name)
}
/* We cannot use #BKE_id_new here as we need some custom initialization code. */
Object *ob = (Object *)BKE_libblock_alloc(bmain, ID_OB, name, 0);
Object *ob = (Object *)BKE_libblock_alloc(bmain, ID_OB, name, bmain ? 0 : LIB_ID_CREATE_NO_MAIN);
/* We increase object user count when linking to Collections. */
id_us_min(&ob->id);

View File

@ -374,6 +374,14 @@ static ID *duplicate_ids(ID *id, const bool allow_failure)
LIB_ID_COPY_NO_ANIMDATA);
return id_copy;
}
case ID_GR: {
/* Doesn't really duplicate the collection. Just creates a collection instance empty. */
BLI_assert(BKE_previewimg_id_supports_jobs(id));
Object *instance_empty = BKE_object_add_only_object(nullptr, OB_EMPTY, nullptr);
instance_empty->instance_collection = (Collection *)id;
instance_empty->transflag |= OB_DUPLICOLLECTION;
return &instance_empty->id;
}
/* These support threading, but don't need duplicating. */
case ID_IM:
case ID_BR:
@ -883,6 +891,42 @@ static void object_preview_render(IconPreview *preview, IconPreviewSize *preview
/** \} */
/* -------------------------------------------------------------------- */
/** \name Collection Preview
*
* For the most part this reuses the object preview code by creating an instance collection empty
* object and rendering that.
*
* \{ */
/**
* Check if the collection contains any geometry that can be rendered. Otherwise there's nothing to
* display in the preview, so don't generate one.
* Objects and sub-collections hidden in the render will be skipped.
*/
static bool collection_preview_contains_geometry_recursive(const Collection *collection)
{
LISTBASE_FOREACH (CollectionObject *, col_ob, &collection->gobject) {
if (col_ob->ob->visibility_flag & OB_HIDE_RENDER) {
continue;
}
if (OB_TYPE_IS_GEOMETRY(col_ob->ob->type)) {
return true;
}
}
LISTBASE_FOREACH (CollectionChild *, child_col, &collection->children) {
if (child_col->collection->flag & COLLECTION_HIDE_RENDER) {
continue;
}
if (collection_preview_contains_geometry_recursive(child_col->collection)) {
return true;
}
}
return false;
}
/* -------------------------------------------------------------------- */
/** \name Action Preview
* \{ */
@ -1577,6 +1621,12 @@ static void icon_preview_startjob_all_sizes(void *customdata,
continue;
}
break;
case ID_GR:
BLI_assert(collection_preview_contains_geometry_recursive((Collection *)ip->id));
/* A collection instance empty was created, so this can just reuse the object preview
* rendering. */
object_preview_render(ip, cur_size);
continue;
case ID_AC:
action_preview_render(ip, cur_size);
continue;
@ -1868,6 +1918,9 @@ bool ED_preview_id_is_supported(const ID *id)
if (GS(id->name) == ID_OB) {
return object_preview_is_type_supported((const Object *)id);
}
if (GS(id->name) == ID_GR) {
return collection_preview_contains_geometry_recursive((const Collection *)id);
}
return BKE_previewimg_id_get_p(id) != nullptr;
}