Brush Assets: Add catalog option to asset pushing operator #118382

Merged
Hans Goudey merged 26 commits from HooglyBoogly/blender:brush-assets-save-catalog-option into brush-assets-project 2024-02-21 14:03:41 +01:00
63 changed files with 517 additions and 448 deletions
Showing only changes of commit 79a07675ce - Show all commits

View File

@ -234,11 +234,6 @@ std::string AS_asset_library_find_suitable_root_path_from_path(blender::StringRe
*/
std::string AS_asset_library_find_suitable_root_path_from_main(const Main *bmain);
blender::asset_system::AssetCatalogService *AS_asset_library_get_catalog_service(
const blender::asset_system::AssetLibrary *library);
blender::asset_system::AssetCatalogTree *AS_asset_library_get_catalog_tree(
const blender::asset_system::AssetLibrary *library);
/**
* Force clearing of all asset library data. After calling this, new asset libraries can be loaded
* just as usual using #AS_asset_library_load(), no init or other setup is needed.
@ -257,10 +252,6 @@ void AS_asset_libraries_exit();
blender::asset_system::AssetLibrary *AS_asset_library_load(const char *name,
const char *library_dirpath);
/** Look up the asset's catalog and copy its simple name into #asset_data. */
void AS_asset_library_refresh_catalog_simplename(
blender::asset_system::AssetLibrary *asset_library, AssetMetaData *asset_data);
/** Return whether any loaded AssetLibrary has unsaved changes to its catalogs. */
bool AS_asset_library_has_any_unsaved_catalogs(void);

View File

@ -317,7 +317,7 @@ static std::string asset_definition_default_file_path_from_dir(StringRef asset_l
void AssetCatalogService::load_from_disk()
{
load_from_disk(asset_library_root_);
this->load_from_disk(asset_library_root_);
}
void AssetCatalogService::load_from_disk(const CatalogFilePath &file_or_directory_path)
@ -330,10 +330,10 @@ void AssetCatalogService::load_from_disk(const CatalogFilePath &file_or_director
}
if (S_ISREG(status.st_mode)) {
load_single_file(file_or_directory_path);
this->load_single_file(file_or_directory_path);
}
else if (S_ISDIR(status.st_mode)) {
load_directory_recursive(file_or_directory_path);
this->load_directory_recursive(file_or_directory_path);
}
else {
/* TODO(@sybren): throw an appropriate exception. */
@ -341,7 +341,7 @@ void AssetCatalogService::load_from_disk(const CatalogFilePath &file_or_director
/* TODO: Should there be a sanitize step? E.g. to remove catalogs with identical paths? */
rebuild_tree();
this->rebuild_tree();
}
void AssetCatalogService::add_from_existing(const AssetCatalogService &other_service)
@ -423,7 +423,7 @@ void AssetCatalogService::reload_catalogs()
const CatalogID catalog_id = catalog->catalog_id;
cats_in_file.add(catalog_id);
const bool should_skip = is_catalog_known_with_unsaved_changes(catalog_id);
const bool should_skip = this->is_catalog_known_with_unsaved_changes(catalog_id);
if (should_skip) {
/* Do not overwrite unsaved local changes. */
return false;
@ -447,7 +447,7 @@ void AssetCatalogService::purge_catalogs_not_listed(const Set<CatalogID> &catalo
if (catalogs_to_keep.contains(cat_id)) {
continue;
}
if (is_catalog_known_with_unsaved_changes(cat_id)) {
if (this->is_catalog_known_with_unsaved_changes(cat_id)) {
continue;
}
/* This catalog is not on disk, but also not modified, so get rid of it. */
@ -455,7 +455,7 @@ void AssetCatalogService::purge_catalogs_not_listed(const Set<CatalogID> &catalo
}
for (CatalogID cat_id : cats_to_remove) {
delete_catalog_by_id_hard(cat_id);
this->delete_catalog_by_id_hard(cat_id);
}
}
@ -481,12 +481,12 @@ bool AssetCatalogService::write_to_disk(const CatalogFilePath &blend_file_path)
{
BLI_assert(!is_read_only_);
if (!write_to_disk_ex(blend_file_path)) {
if (!this->write_to_disk_ex(blend_file_path)) {
return false;
}
untag_has_unsaved_changes();
rebuild_tree();
this->untag_has_unsaved_changes();
this->rebuild_tree();
return true;
}
@ -496,7 +496,7 @@ bool AssetCatalogService::write_to_disk_ex(const CatalogFilePath &blend_file_pat
/* - Already loaded a CDF from disk? -> Always write to that file. */
if (catalog_collection_->catalog_definition_file_) {
reload_catalogs();
this->reload_catalogs();
return catalog_collection_->catalog_definition_file_->write_to_disk();
}
@ -507,9 +507,10 @@ bool AssetCatalogService::write_to_disk_ex(const CatalogFilePath &blend_file_pat
return true; /* Writing nothing when there is nothing to write is still a success. */
}
const CatalogFilePath cdf_path_to_write = find_suitable_cdf_path_for_writing(blend_file_path);
catalog_collection_->catalog_definition_file_ = construct_cdf_in_memory(cdf_path_to_write);
reload_catalogs();
const CatalogFilePath cdf_path_to_write = this->find_suitable_cdf_path_for_writing(
blend_file_path);
catalog_collection_->catalog_definition_file_ = this->construct_cdf_in_memory(cdf_path_to_write);
this->reload_catalogs();
return catalog_collection_->catalog_definition_file_->write_to_disk();
}
@ -528,7 +529,7 @@ void AssetCatalogService::prepare_to_merge_on_write()
/* Mark all in-memory catalogs as "dirty", to force them to be kept around on
* the next "load-merge-write" cycle. */
tag_all_catalogs_as_unsaved_changes();
this->tag_all_catalogs_as_unsaved_changes();
}
CatalogFilePath AssetCatalogService::find_suitable_cdf_path_for_writing(
@ -590,8 +591,8 @@ std::unique_ptr<AssetCatalogTree> AssetCatalogService::read_into_tree()
void AssetCatalogService::rebuild_tree()
{
create_missing_catalogs();
this->catalog_tree_ = read_into_tree();
this->create_missing_catalogs();
this->catalog_tree_ = this->read_into_tree();
}
void AssetCatalogService::create_missing_catalogs()
@ -661,7 +662,7 @@ void AssetCatalogService::redo()
undo_snapshots_.append(std::move(catalog_collection_));
catalog_collection_ = redo_snapshots_.pop_last();
rebuild_tree();
this->rebuild_tree();
AssetLibraryService::get()->rebuild_all_library();
}

View File

@ -94,29 +94,6 @@ std::string AS_asset_library_find_suitable_root_path_from_main(const Main *bmain
return AS_asset_library_find_suitable_root_path_from_path(bmain->filepath);
}
AssetCatalogService *AS_asset_library_get_catalog_service(const AssetLibrary *library)
{
if (library == nullptr) {
return nullptr;
}
return library->catalog_service.get();
}
AssetCatalogTree *AS_asset_library_get_catalog_tree(const AssetLibrary *library)
{
AssetCatalogService *catalog_service = AS_asset_library_get_catalog_service(library);
if (catalog_service == nullptr) {
return nullptr;
}
return catalog_service->get_catalog_tree();
}
void AS_asset_library_refresh_catalog_simplename(AssetLibrary *asset_library,
AssetMetaData *asset_data)
{
asset_library->refresh_catalog_simplename(asset_data);
}
void AS_asset_library_remap_ids(const bke::id::IDRemapper &mappings)
{

View File

@ -15,7 +15,7 @@ OnDiskAssetLibrary::OnDiskAssetLibrary(eAssetLibraryType library_type,
StringRef root_path)
: AssetLibrary(library_type, name, root_path)
{
on_blend_save_handler_register();
this->on_blend_save_handler_register();
}
void OnDiskAssetLibrary::refresh_catalogs()

View File

@ -12,7 +12,7 @@ namespace blender::asset_system {
RuntimeAssetLibrary::RuntimeAssetLibrary() : AssetLibrary(ASSET_LIBRARY_LOCAL)
{
on_blend_save_handler_register();
this->on_blend_save_handler_register();
}
} // namespace blender::asset_system

View File

@ -74,7 +74,7 @@ AssetLibrary *AssetLibraryService::get_asset_library(
return nullptr;
}
return get_asset_library_on_disk_builtin(type, root_path);
return this->get_asset_library_on_disk_builtin(type, root_path);
}
case ASSET_LIBRARY_LOCAL: {
/* For the "Current File" library we get the asset library root path based on main. */
@ -83,14 +83,14 @@ AssetLibrary *AssetLibraryService::get_asset_library(
if (root_path.empty()) {
/* File wasn't saved yet. */
return get_asset_library_current_file();
return this->get_asset_library_current_file();
}
return get_asset_library_on_disk_builtin(type, root_path);
return this->get_asset_library_on_disk_builtin(type, root_path);
}
case ASSET_LIBRARY_ALL:
return get_asset_library_all(bmain);
return this->get_asset_library_all(bmain);
case ASSET_LIBRARY_CUSTOM: {
bUserAssetLibrary *custom_library = find_custom_asset_library_from_library_ref(
bUserAssetLibrary *custom_library = this->find_custom_asset_library_from_library_ref(
library_reference);
if (!custom_library) {
return nullptr;
@ -101,7 +101,8 @@ AssetLibrary *AssetLibraryService::get_asset_library(
return nullptr;
}
AssetLibrary *library = get_asset_library_on_disk_custom(custom_library->name, root_path);
AssetLibrary *library = this->get_asset_library_on_disk_custom(custom_library->name,
root_path);
library->import_method_ = eAssetImportMethod(custom_library->import_method);
library->may_override_import_method_ = true;
library->use_relative_path_ = (custom_library->flag & ASSET_LIBRARY_RELATIVE_PATH) != 0;
@ -156,7 +157,7 @@ AssetLibrary *AssetLibraryService::get_asset_library_on_disk(eAssetLibraryType l
AssetLibrary *AssetLibraryService::get_asset_library_on_disk_custom(StringRef name,
StringRefNull root_path)
{
return get_asset_library_on_disk(ASSET_LIBRARY_CUSTOM, name, root_path);
return this->get_asset_library_on_disk(ASSET_LIBRARY_CUSTOM, name, root_path);
}
AssetLibrary *AssetLibraryService::get_asset_library_on_disk_builtin(eAssetLibraryType type,
@ -168,7 +169,7 @@ AssetLibrary *AssetLibraryService::get_asset_library_on_disk_builtin(eAssetLibra
/* Builtin asset libraries don't need a name, the #eAssetLibraryType is enough to identify them
* (and doesn't change, unlike the name). */
return get_asset_library_on_disk(type, {}, root_path);
return this->get_asset_library_on_disk(type, {}, root_path);
}
AssetLibrary *AssetLibraryService::get_asset_library_current_file()
@ -203,7 +204,7 @@ AssetLibrary *AssetLibraryService::get_asset_library_all(const Main *bmain)
}
/* Ensure all asset libraries are loaded. */
get_asset_library(bmain, library_ref);
this->get_asset_library(bmain, library_ref);
}
if (all_library_) {
@ -249,8 +250,8 @@ std::string AssetLibraryService::resolve_asset_weak_reference_to_library_path(
switch (eAssetLibraryType(asset_reference.asset_library_type)) {
case ASSET_LIBRARY_CUSTOM: {
bUserAssetLibrary *custom_lib = find_custom_preferences_asset_library_from_asset_weak_ref(
asset_reference);
bUserAssetLibrary *custom_lib =
this->find_custom_preferences_asset_library_from_asset_weak_ref(asset_reference);
if (custom_lib) {
library_dirpath = custom_lib->dirpath;
break;
@ -258,7 +259,7 @@ std::string AssetLibraryService::resolve_asset_weak_reference_to_library_path(
/* A bit of an odd-ball, the API supports loading custom libraries from arbitrary paths (used
* by unit tests). So check all loaded on-disk libraries too. */
AssetLibrary *loaded_custom_lib = find_loaded_on_disk_asset_library_from_name(
AssetLibrary *loaded_custom_lib = this->find_loaded_on_disk_asset_library_from_name(
asset_reference.asset_library_identifier);
if (!loaded_custom_lib) {
return "";
@ -368,7 +369,7 @@ std::optional<AssetLibraryService::ExplodedPath> AssetLibraryService::
switch (eAssetLibraryType(asset_reference.asset_library_type)) {
case ASSET_LIBRARY_LOCAL: {
std::string path_in_file = normalize_asset_weak_reference_relative_asset_identifier(
std::string path_in_file = this->normalize_asset_weak_reference_relative_asset_identifier(
asset_reference);
const int64_t group_len = int64_t(path_in_file.find(SEP));
@ -381,14 +382,14 @@ std::optional<AssetLibraryService::ExplodedPath> AssetLibraryService::
}
case ASSET_LIBRARY_CUSTOM:
case ASSET_LIBRARY_ESSENTIALS: {
std::string full_path = resolve_asset_weak_reference_to_full_path(asset_reference);
std::string full_path = this->resolve_asset_weak_reference_to_full_path(asset_reference);
/* #full_path uses native slashes, so others don't need to be considered in the following. */
if (full_path.empty()) {
return std::nullopt;
}
int64_t blendfile_extension_pos = rfind_blendfile_extension(full_path);
int64_t blendfile_extension_pos = this->rfind_blendfile_extension(full_path);
BLI_assert(blendfile_extension_pos != StringRef::not_found);
size_t group_pos = full_path.find(SEP, blendfile_extension_pos);

View File

@ -29,7 +29,7 @@ extern "C" {
/* Blender file format version. */
#define BLENDER_FILE_VERSION BLENDER_VERSION
#define BLENDER_FILE_SUBVERSION 3
#define BLENDER_FILE_SUBVERSION 4
/* Minimum Blender version that supports reading file written with the current
* version. Older Blender versions will test this and cancel loading the file, showing a warning to

View File

@ -306,6 +306,9 @@ inline int edge_other_vert(const int2 edge, const int vert)
} // namespace mesh
/** Create a mesh with no built-in attributes. */
Mesh *mesh_new_no_attributes(int verts_num, int edges_num, int faces_num, int corners_num);
/** Calculate edges from faces. */
void mesh_calc_edges(Mesh &mesh, bool keep_existing_edges, bool select_new_edges);

View File

@ -52,18 +52,10 @@ AssetMetaData *BKE_asset_metadata_copy(const AssetMetaData *source)
BKE_asset_metadata_catalog_id_set(copy, source->catalog_id, source->catalog_simple_name);
if (source->author) {
copy->author = BLI_strdup(source->author);
}
if (source->description) {
copy->description = BLI_strdup(source->description);
}
if (source->copyright) {
copy->copyright = BLI_strdup(source->copyright);
}
if (source->license) {
copy->license = BLI_strdup(source->license);
}
copy->author = BLI_strdup_null(source->author);
copy->description = BLI_strdup_null(source->description);
copy->copyright = BLI_strdup_null(source->copyright);
copy->license = BLI_strdup_null(source->license);
BLI_duplicatelist(&copy->tags, &source->tags);
copy->active_tag = source->active_tag;

View File

@ -252,7 +252,7 @@ static void test_idprop(const IDProperty *id_property,
static void test_idprop(const IDProperty *id_property,
StringRef expected_name,
const Vector<int32_t> &values)
const Span<int32_t> values)
{
ASSERT_NE(id_property, nullptr);
EXPECT_EQ(id_property->type, IDP_ARRAY);
@ -267,7 +267,7 @@ static void test_idprop(const IDProperty *id_property,
static void test_idprop(const IDProperty *id_property,
StringRef expected_name,
const Vector<float> &values)
const Span<float> values)
{
ASSERT_NE(id_property, nullptr);
EXPECT_EQ(id_property->type, IDP_ARRAY);
@ -282,7 +282,7 @@ static void test_idprop(const IDProperty *id_property,
static void test_idprop(const IDProperty *id_property,
StringRef expected_name,
const Vector<double> &values)
const Span<double> values)
{
ASSERT_NE(id_property, nullptr);
EXPECT_EQ(id_property->type, IDP_ARRAY);

View File

@ -702,6 +702,26 @@ Mesh *BKE_mesh_new_nomain(const int verts_num,
return mesh;
}
namespace blender::bke {
Mesh *mesh_new_no_attributes(const int verts_num,
const int edges_num,
const int faces_num,
const int corners_num)
{
Mesh *mesh = BKE_mesh_new_nomain(0, 0, faces_num, 0);
mesh->verts_num = verts_num;
mesh->edges_num = edges_num;
mesh->corners_num = corners_num;
CustomData_free_layer_named(&mesh->vert_data, "position", 0);
CustomData_free_layer_named(&mesh->edge_data, ".edge_verts", 0);
CustomData_free_layer_named(&mesh->corner_data, ".corner_vert", 0);
CustomData_free_layer_named(&mesh->corner_data, ".corner_edge", 0);
return mesh;
}
} // namespace blender::bke
static void copy_attribute_names(const Mesh &mesh_src, Mesh &mesh_dst)
{
if (mesh_src.active_color_attribute) {

View File

@ -1384,8 +1384,7 @@ static void mesh_normals_corner_custom_set(const Span<float3> positions,
* We know those two corners do not point to the same edge,
* since we do not allow reversed winding in a same smooth fan. */
const IndexRange face = faces[corner_to_face[lidx]];
const int corner_prev = (lidx == face.start()) ? face.start() + face.size() - 1 :
lidx - 1;
const int corner_prev = face_corner_prev(face, lidx);
const int edge = corner_edges[lidx];
const int edge_prev = corner_edges[corner_prev];
const int prev_edge = corner_edges[prev_corner];
@ -1408,8 +1407,7 @@ static void mesh_normals_corner_custom_set(const Span<float3> positions,
if (dot_v3v3(org_nor, nor) < LNOR_SPACE_TRIGO_THRESHOLD) {
const IndexRange face = faces[corner_to_face[lidx]];
const int corner_prev = (lidx == face.start()) ? face.start() + face.size() - 1 :
lidx - 1;
const int corner_prev = face_corner_prev(face, lidx);
const int edge = corner_edges[lidx];
const int edge_prev = corner_edges[corner_prev];
const int prev_edge = corner_edges[prev_corner];

View File

@ -472,7 +472,7 @@ struct Rows {
return selected_pixels;
}
void pack_into(const Vector<std::reference_wrapper<Pixel>> &selected_pixels,
void pack_into(const Span<std::reference_wrapper<Pixel>> selected_pixels,
CopyPixelTile &copy_tile) const
{
std::optional<std::reference_wrapper<CopyPixelGroup>> last_group = std::nullopt;

View File

@ -98,7 +98,7 @@ template<typename T> class StringSearch : private StringSearchBase {
* \param weight: Can be used to customize the order when multiple items have the same match
* score.
*/
void add(const StringRefNull str, T *user_data, const int weight = 0)
void add(const StringRef str, T *user_data, const int weight = 0)
{
this->add_impl(str, (void *)user_data, weight);
}

View File

@ -1836,9 +1836,7 @@ void get_next_crossing_from_edge(CrossData<T> *cd,
}
}
constexpr int inline_crossings_size = 128;
template<typename T>
void dump_crossings(const Vector<CrossData<T>, inline_crossings_size> &crossings)
template<typename T> void dump_crossings(const Span<CrossData<T>> crossings)
{
std::cout << "CROSSINGS\n";
for (int i = 0; i < crossings.size(); ++i) {
@ -1917,7 +1915,7 @@ void add_edge_constraint(
* one hop. Saves a bunch of orient2d tests in that common case.
*/
int visit = ++cdt_state->visit_count;
Vector<CrossData<T>, inline_crossings_size> crossings;
Vector<CrossData<T>, 128> crossings;
crossings.append(CrossData<T>(T(0), v1, nullptr, nullptr));
int n;
while (!((n = crossings.size()) > 0 && crossings[n - 1].vert == v2)) {
@ -1949,7 +1947,7 @@ void add_edge_constraint(
}
if (dbg_level > 0) {
dump_crossings(crossings);
dump_crossings<T>(crossings);
}
/*

View File

@ -149,7 +149,7 @@ class TriMeshTopology : NonCopyable {
/* Which edges are incident on the given vertex?
* We assume v has some incident edges. */
const Vector<Edge> &vert_edges(const Vert *v) const
Span<Edge> vert_edges(const Vert *v) const
{
return vert_edges_.lookup(v);
}
@ -1540,7 +1540,7 @@ static int find_ambient_cell(const IMesh &tm,
/* Find edge attached to v_extreme with max absolute slope
* when projected onto the XY plane. That edge is guaranteed to
* be on the convex hull of the mesh. */
const Vector<Edge> &edges = tmtopo.vert_edges(v_extreme);
const Span<Edge> edges = tmtopo.vert_edges(v_extreme);
const mpq_class &extreme_x = v_extreme->co_exact.x;
const mpq_class &extreme_y = v_extreme->co_exact.y;
Edge ehull;
@ -1625,7 +1625,7 @@ static Edge find_good_sorting_edge(const Vert *testp,
mpq_class nlen2 = math::length_squared(normal);
mpq_class max_abs_slope = -1;
Edge esort;
const Vector<Edge> &edges = tmtopo.vert_edges(closestp);
const Span<Edge> edges = tmtopo.vert_edges(closestp);
for (Edge e : edges) {
const Vert *v_other = (e.v0() == closestp) ? e.v1() : e.v0();
const mpq3 &co_other = v_other->co_exact;
@ -1697,7 +1697,7 @@ static int find_containing_cell(const Vert *v,
if (close_edge != -1) {
const Vert *v0 = tri[close_edge];
const Vert *v1 = tri[(close_edge + 1) % 3];
const Vector<Edge> &edges = tmtopo.vert_edges(v0);
const Span<Edge> edges = tmtopo.vert_edges(v0);
if (dbg_level > 0) {
std::cout << "look for edge containing " << v0 << " and " << v1 << "\n";
std::cout << " in edges: ";
@ -1907,7 +1907,7 @@ struct ComponentContainer {
* (maybe not directly nested, which is why there can be more than one).
*/
static Vector<ComponentContainer> find_component_containers(int comp,
const Vector<Vector<int>> &components,
const Span<Vector<int>> components,
const Array<int> &ambient_cell,
const IMesh &tm,
const PatchesInfo &pinfo,
@ -2022,7 +2022,7 @@ static Vector<ComponentContainer> find_component_containers(int comp,
* by an appropriate epsilon so that we conservatively will say
* that components could intersect if the BBs overlap.
*/
static void populate_comp_bbs(const Vector<Vector<int>> &components,
static void populate_comp_bbs(const Span<Vector<int>> components,
const PatchesInfo &pinfo,
const IMesh &im,
Array<BoundingBox> &comp_bb)
@ -2970,7 +2970,7 @@ static std::ostream &operator<<(std::ostream &os, const FaceMergeState &fms)
* Hence, try to be tolerant of such unexpected topology.
*/
static void init_face_merge_state(FaceMergeState *fms,
const Vector<int> &tris,
const Span<int> tris,
const IMesh &tm,
const double3 &norm)
{
@ -3507,7 +3507,7 @@ static IMesh polymesh_from_trimesh_with_dissolve(const IMesh &tm_out,
Array<Face *> face(tot_out_face);
int out_f_index = 0;
for (int in_f : imesh_in.face_index_range()) {
const Vector<Face *> &f_faces = face_output_face[in_f];
const Span<Face *> f_faces = face_output_face[in_f];
if (f_faces.size() > 0) {
std::copy(f_faces.begin(), f_faces.end(), &face[out_f_index]);
out_f_index += f_faces.size();

View File

@ -26,6 +26,7 @@
#include "DNA_movieclip_types.h"
#include "DNA_scene_types.h"
#include "DNA_sequence_types.h"
#include "DNA_workspace_types.h"
#include "DNA_world_types.h"
#include "DNA_defaults.h"
@ -47,6 +48,7 @@
#include "BKE_animsys.h"
#include "BKE_armature.hh"
#include "BKE_attribute.hh"
#include "BKE_context.hh"
#include "BKE_curve.hh"
#include "BKE_effect.h"
#include "BKE_grease_pencil.hh"
@ -1939,6 +1941,55 @@ static bool seq_filter_bilinear_to_auto(Sequence *seq, void * /*user_data*/)
return true;
}
static void update_paint_modes_for_brush_assets(Main &bmain)
{
/* Replace paint brushes with a reference to the default brush asset for that mode. */
LISTBASE_FOREACH (Scene *, scene, &bmain.scenes) {
auto set_paint_asset_ref = [&](Paint &paint, const blender::StringRef asset) {
AssetWeakReference *weak_ref = MEM_new<AssetWeakReference>(__func__);
weak_ref->asset_library_type = eAssetLibraryType::ASSET_LIBRARY_ESSENTIALS;
const std::string path = "brushes/essentials_brushes.blend/Brush/" + asset;
weak_ref->relative_asset_identifier = BLI_strdupn(path.data(), path.size());
paint.brush_asset_reference = weak_ref;
paint.brush = nullptr;
};
ToolSettings *ts = scene->toolsettings;
if (ts->sculpt) {
set_paint_asset_ref(ts->sculpt->paint, "Draw");
}
if (ts->curves_sculpt) {
set_paint_asset_ref(ts->curves_sculpt->paint, "Comb Curves");
}
if (ts->wpaint) {
set_paint_asset_ref(ts->wpaint->paint, "Paint Weight");
}
if (ts->vpaint) {
set_paint_asset_ref(ts->vpaint->paint, "Paint Vertex");
}
set_paint_asset_ref(ts->imapaint.paint, "Paint Texture");
}
/* Replace persistent tool references with the new single builtin brush tool. */
LISTBASE_FOREACH (WorkSpace *, workspace, &bmain.workspaces) {
LISTBASE_FOREACH (bToolRef *, tref, &workspace->tools) {
if (tref->space_type != SPACE_VIEW3D) {
continue;
}
if (!ELEM(tref->mode,
CTX_MODE_SCULPT,
CTX_MODE_SCULPT_CURVES,
CTX_MODE_PAINT_TEXTURE,
CTX_MODE_PAINT_VERTEX,
CTX_MODE_PAINT_WEIGHT))
{
continue;
}
STRNCPY(tref->idname, "builtin.brush");
}
}
}
void blo_do_versions_400(FileData *fd, Library * /*lib*/, Main *bmain)
{
if (!MAIN_VERSION_FILE_ATLEAST(bmain, 400, 1)) {
@ -2938,6 +2989,10 @@ void blo_do_versions_400(FileData *fd, Library * /*lib*/, Main *bmain)
FOREACH_NODETREE_END;
}
if (!MAIN_VERSION_FILE_ATLEAST(bmain, 402, 4)) {
update_paint_modes_for_brush_assets(*bmain);
}
/**
* Always bump subversion in BKE_blender_version.h when adding versioning
* code here, and wrap it inside a MAIN_VERSION_FILE_ATLEAST check.

View File

@ -87,8 +87,8 @@ ExecutionSystem::~ExecutionSystem()
groups_.clear();
}
void ExecutionSystem::set_operations(const Vector<NodeOperation *> &operations,
const Vector<ExecutionGroup *> &groups)
void ExecutionSystem::set_operations(const Span<NodeOperation *> operations,
const Span<ExecutionGroup *> groups)
{
operations_ = operations;
groups_ = groups;

View File

@ -178,8 +178,7 @@ class ExecutionSystem {
*/
~ExecutionSystem();
void set_operations(const Vector<NodeOperation *> &operations,
const Vector<ExecutionGroup *> &groups);
void set_operations(Span<NodeOperation *> operations, Span<ExecutionGroup *> groups);
/**
* \brief execute this system

View File

@ -98,7 +98,7 @@ class Node {
/**
* \brief get access to the vector of input sockets
*/
const Vector<NodeInput *> &get_input_sockets() const
Span<NodeInput *> get_input_sockets() const
{
return inputs_;
}
@ -106,7 +106,7 @@ class Node {
/**
* \brief get access to the vector of input sockets
*/
const Vector<NodeOutput *> &get_output_sockets() const
Span<NodeOutput *> get_output_sockets() const
{
return outputs_;
}

View File

@ -37,11 +37,11 @@ class NodeGraph {
public:
~NodeGraph();
const Vector<Node *> &nodes() const
Span<Node *> nodes() const
{
return nodes_;
}
const Vector<Link> &links() const
Span<Link> links() const
{
return links_;
}

View File

@ -107,12 +107,12 @@ class NodeOperationBuilder {
return active_viewer_;
}
const Vector<NodeOperation *> &get_operations() const
Span<NodeOperation *> get_operations() const
{
return operations_;
}
const Vector<Link> &get_links() const
Span<Link> get_links() const
{
return links_;
}

View File

@ -564,6 +564,7 @@ set(GLSL_SRC
engines/eevee_next/shaders/eevee_ray_trace_screen_comp.glsl
engines/eevee_next/shaders/eevee_ray_trace_screen_lib.glsl
engines/eevee_next/shaders/eevee_ray_types_lib.glsl
engines/eevee_next/shaders/eevee_reflection_probe_convolve_comp.glsl
engines/eevee_next/shaders/eevee_reflection_probe_eval_lib.glsl
engines/eevee_next/shaders/eevee_reflection_probe_lib.glsl
engines/eevee_next/shaders/eevee_reflection_probe_remap_comp.glsl

View File

@ -97,7 +97,7 @@ struct SphereProbeAtlasCoord {
{
SphereProbePixelArea coord;
coord.extent = atlas_extent >> (subdivision_lvl + mip_lvl);
coord.offset = (area_location() * coord.extent) >> mip_lvl;
coord.offset = area_location() * coord.extent;
coord.layer = atlas_layer;
return coord;
}

View File

@ -46,10 +46,20 @@ void SphereProbeModule::begin_sync()
pass.push_constant("probe_coord_packed", reinterpret_cast<int4 *>(&probe_sampling_coord_));
pass.push_constant("write_coord_packed", reinterpret_cast<int4 *>(&probe_write_coord_));
pass.push_constant("world_coord_packed", reinterpret_cast<int4 *>(&world_data.atlas_coord));
pass.push_constant("mip_level", &probe_mip_level_);
pass.push_constant("probe_brightness_clamp", probe_brightness_clamp);
pass.dispatch(&dispatch_probe_pack_);
}
{
PassSimple &pass = convolve_ps_;
pass.init();
pass.shader_set(instance_.shaders.static_shader_get(SPHERE_PROBE_CONVOLVE));
pass.bind_image("in_atlas_mip_img", &convolve_input_);
pass.bind_image("out_atlas_mip_img", &convolve_output_);
pass.push_constant("write_coord_packed", reinterpret_cast<int4 *>(&probe_write_coord_));
pass.barrier(GPU_BARRIER_SHADER_IMAGE_ACCESS);
pass.dispatch(&dispatch_probe_convolve_);
pass.barrier(GPU_BARRIER_SHADER_IMAGE_ACCESS);
}
{
PassSimple &pass = update_irradiance_ps_;
pass.init();
@ -85,6 +95,7 @@ bool SphereProbeModule::ensure_atlas()
nullptr,
SPHERE_PROBE_MIPMAP_LEVELS))
{
probes_tx_.ensure_mip_views();
/* TODO(fclem): Clearing means that we need to render all probes again.
* If existing data exists, copy it using `CopyImageSubData`. */
probes_tx_.clear(float4(0.0f));
@ -122,11 +133,8 @@ void SphereProbeModule::end_sync()
void SphereProbeModule::ensure_cubemap_render_target(int resolution)
{
if (cubemap_tx_.ensure_cube(
GPU_RGBA16F, resolution, GPU_TEXTURE_USAGE_ATTACHMENT | GPU_TEXTURE_USAGE_SHADER_READ))
{
GPU_texture_mipmap_mode(cubemap_tx_, false, true);
}
eGPUTextureUsage usage = GPU_TEXTURE_USAGE_ATTACHMENT | GPU_TEXTURE_USAGE_SHADER_READ;
cubemap_tx_.ensure_cube(GPU_RGBA16F, resolution, usage);
/* TODO(fclem): deallocate it. */
}
@ -185,10 +193,20 @@ void SphereProbeModule::remap_to_octahedral_projection(const SphereProbeAtlasCoo
/* Update shader parameters that change per dispatch. */
probe_sampling_coord_ = atlas_coord.as_sampling_coord(max_resolution_);
probe_write_coord_ = atlas_coord.as_write_coord(max_resolution_, 0);
probe_mip_level_ = atlas_coord.subdivision_lvl;
dispatch_probe_pack_ = int3(int2(ceil_division(resolution, SPHERE_PROBE_GROUP_SIZE)), 1);
instance_.manager->submit(remap_ps_);
/* Populate the mip levels */
for (auto i : IndexRange(SPHERE_PROBE_MIPMAP_LEVELS - 1)) {
convolve_input_ = probes_tx_.mip_view(i);
convolve_output_ = probes_tx_.mip_view(i + 1);
probe_write_coord_ = atlas_coord.as_write_coord(max_resolution_, i + 1);
int out_mip_res = resolution >> (i + 1);
dispatch_probe_convolve_ = int3(int2(ceil_division(out_mip_res, SPHERE_PROBE_GROUP_SIZE)), 1);
instance_.manager->submit(convolve_ps_);
}
/* Sync with atlas usage for shading. */
GPU_memory_barrier(GPU_BARRIER_TEXTURE_FETCH);
}
void SphereProbeModule::update_world_irradiance()
@ -198,11 +216,6 @@ void SphereProbeModule::update_world_irradiance()
instance_.volume_probes.do_update_world_ = true;
}
void SphereProbeModule::update_probes_texture_mipmaps()
{
GPU_texture_update_mipmap_chain(probes_tx_);
}
void SphereProbeModule::set_view(View & /*view*/)
{
Vector<SphereProbe *> probe_active;

View File

@ -53,9 +53,17 @@ class SphereProbeModule {
PassSimple remap_ps_ = {"Probe.CubemapToOctahedral"};
/** Extract irradiance information from the world. */
PassSimple update_irradiance_ps_ = {"Probe.UpdateIrradiance"};
/** Copy volume probe irradiance for the center of sphere probes. */
PassSimple select_ps_ = {"Probe.Select"};
/** Convolve the octahedral map to fill the Mip-map levels. */
PassSimple convolve_ps_ = {"Probe.Convolve"};
/** Input mip level for the convolution. */
GPUTexture *convolve_input_ = nullptr;
/** Output mip level for the convolution. */
GPUTexture *convolve_output_ = nullptr;
int3 dispatch_probe_pack_ = int3(1);
int3 dispatch_probe_convolve_ = int3(1);
int3 dispatch_probe_select_ = int3(1);
/**
@ -66,8 +74,6 @@ class SphereProbeModule {
Texture cubemap_tx_ = {"Probe.Cubemap"};
/** Index of the probe being updated. */
int probe_index_ = 0;
/** Mip level being sampled for remapping. */
int probe_mip_level_ = 0;
/** Updated Probe coordinates in the atlas. */
SphereProbeUvArea probe_sampling_coord_;
SphereProbePixelArea probe_write_coord_;
@ -167,7 +173,6 @@ class SphereProbeModule {
* Internal processing passes.
*/
void remap_to_octahedral_projection(const SphereProbeAtlasCoord &atlas_coord);
void update_probes_texture_mipmaps();
void update_world_irradiance();
void sync_display(Vector<SphereProbe *> &probe_active);

View File

@ -214,6 +214,8 @@ const char *ShaderModule::static_shader_create_info_name_get(eShaderType shader_
return "eevee_lightprobe_irradiance_ray";
case LIGHTPROBE_IRRADIANCE_LOAD:
return "eevee_lightprobe_irradiance_load";
case SPHERE_PROBE_CONVOLVE:
return "eevee_reflection_probe_convolve";
case SPHERE_PROBE_REMAP:
return "eevee_reflection_probe_remap";
case SPHERE_PROBE_UPDATE_IRRADIANCE:

View File

@ -104,9 +104,10 @@ enum eShaderType {
RAY_TRACE_PLANAR,
RAY_TRACE_SCREEN,
SPHERE_PROBE_CONVOLVE,
SPHERE_PROBE_REMAP,
SPHERE_PROBE_UPDATE_IRRADIANCE,
SPHERE_PROBE_SELECT,
SPHERE_PROBE_UPDATE_IRRADIANCE,
SHADOW_CLIPMAP_CLEAR,
SHADOW_DEBUG,

View File

@ -263,7 +263,6 @@ void CaptureView::render_world()
}
inst_.sphere_probes.remap_to_octahedral_projection(update_info->atlas_coord);
inst_.sphere_probes.update_probes_texture_mipmaps();
}
if (update_info->do_world_irradiance_update) {
@ -277,10 +276,8 @@ void CaptureView::render_probes()
{
Framebuffer prepass_fb;
View view = {"Capture.View"};
bool do_update_mipmap_chain = false;
while (const auto update_info = inst_.sphere_probes.probe_update_info_pop()) {
GPU_debug_group_begin("Probe.Capture");
do_update_mipmap_chain = true;
if (inst_.pipelines.data.is_probe_reflection != true) {
inst_.pipelines.data.is_probe_reflection = true;
@ -334,11 +331,6 @@ void CaptureView::render_probes()
inst_.pipelines.data.is_probe_reflection = false;
inst_.uniform_data.push_update();
}
if (do_update_mipmap_chain) {
/* TODO: only update the regions that have been updated. */
inst_.sphere_probes.update_probes_texture_mipmaps();
}
}
/** \} */

View File

@ -0,0 +1,39 @@
/* SPDX-FileCopyrightText: 2023 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
/* Shader to convert cube-map to octahedral projection. */
#pragma BLENDER_REQUIRE(eevee_octahedron_lib.glsl)
SphereProbePixelArea reinterpret_as_write_coord(ivec4 packed_coord)
{
SphereProbePixelArea unpacked;
unpacked.offset = packed_coord.xy;
unpacked.extent = packed_coord.z;
unpacked.layer = packed_coord.w;
return unpacked;
}
void main()
{
SphereProbePixelArea write_coord = reinterpret_as_write_coord(write_coord_packed);
/* Texel in probe. */
ivec2 local_texel = ivec2(gl_GlobalInvocationID.xy);
/* Exit when pixel being written doesn't fit in the area reserved for the probe. */
if (any(greaterThanEqual(local_texel, ivec2(write_coord.extent)))) {
return;
}
ivec2 texel_out = write_coord.offset + local_texel;
vec4 color = vec4(0.0);
color += imageLoad(in_atlas_mip_img, ivec3(texel_out * 2 + ivec2(0, 0), write_coord.layer));
color += imageLoad(in_atlas_mip_img, ivec3(texel_out * 2 + ivec2(1, 0), write_coord.layer));
color += imageLoad(in_atlas_mip_img, ivec3(texel_out * 2 + ivec2(0, 1), write_coord.layer));
color += imageLoad(in_atlas_mip_img, ivec3(texel_out * 2 + ivec2(1, 1), write_coord.layer));
color *= 0.25;
imageStore(out_atlas_mip_img, ivec3(texel_out, write_coord.layer), color);
}

View File

@ -61,7 +61,7 @@ void main()
vec2 wrapped_uv = mirror_repeat_uv(sampling_uv);
/* Direction in world space. */
vec3 direction = octahedral_uv_to_direction(wrapped_uv);
vec4 radiance_and_transmittance = textureLod(cubemap_tx, direction, float(mip_level));
vec4 radiance_and_transmittance = texture(cubemap_tx, direction);
vec3 radiance = radiance_and_transmittance.xyz;
float opacity = 1.0 - radiance_and_transmittance.a;

View File

@ -22,7 +22,6 @@ GPU_SHADER_CREATE_INFO(eevee_reflection_probe_remap)
.push_constant(Type::IVEC4, "probe_coord_packed")
.push_constant(Type::IVEC4, "write_coord_packed")
.push_constant(Type::IVEC4, "world_coord_packed")
.push_constant(Type::INT, "mip_level")
.push_constant(Type::FLOAT, "probe_brightness_clamp")
.sampler(0, ImageType::FLOAT_CUBE, "cubemap_tx")
.sampler(1, ImageType::FLOAT_2D_ARRAY, "atlas_tx")
@ -54,6 +53,15 @@ GPU_SHADER_CREATE_INFO(eevee_reflection_probe_select)
.compute_source("eevee_reflection_probe_select_comp.glsl")
.do_static_compilation(true);
GPU_SHADER_CREATE_INFO(eevee_reflection_probe_convolve)
.local_group_size(SPHERE_PROBE_GROUP_SIZE, SPHERE_PROBE_GROUP_SIZE)
.additional_info("eevee_shared")
.push_constant(Type::IVEC4, "write_coord_packed")
.image(0, GPU_RGBA16F, Qualifier::READ, ImageType::FLOAT_2D_ARRAY, "in_atlas_mip_img")
.image(1, GPU_RGBA16F, Qualifier::WRITE, ImageType::FLOAT_2D_ARRAY, "out_atlas_mip_img")
.compute_source("eevee_reflection_probe_convolve_comp.glsl")
.do_static_compilation(true);
GPU_SHADER_INTERFACE_INFO(eevee_display_probe_reflection_iface, "")
.smooth(Type::VEC2, "lP")
.flat(Type::INT, "probe_index");

View File

@ -456,14 +456,13 @@ static void statvis_calc_distort(const MeshRenderData &mr, float *r_distort)
const float *f_no = mr.face_normals[face_index];
fac = 0.0f;
for (int i = 1; i <= face.size(); i++) {
const int corner_prev = face.start() + (i - 1) % face.size();
const int corner_curr = face.start() + (i + 0) % face.size();
const int corner_next = face.start() + (i + 1) % face.size();
for (const int corner : face.drop_front(1)) {
const int corner_prev = bke::mesh::face_corner_prev(face, corner);
const int corner_next = bke::mesh::face_corner_next(face, corner);
float no_corner[3];
normal_tri_v3(no_corner,
mr.vert_positions[mr.corner_verts[corner_prev]],
mr.vert_positions[mr.corner_verts[corner_curr]],
mr.vert_positions[mr.corner_verts[corner]],
mr.vert_positions[mr.corner_verts[corner_next]]);
/* simple way to detect (what is most likely) concave */
if (dot_v3v3(f_no, no_corner) < 0.0f) {
@ -540,9 +539,9 @@ static void statvis_calc_sharp(const MeshRenderData &mr, float *r_sharp)
for (int face_index = 0; face_index < mr.face_len; face_index++) {
const IndexRange face = mr.faces[face_index];
for (int i = 0; i < face.size(); i++) {
const int vert_curr = mr.corner_verts[face.start() + (i + 0) % face.size()];
const int vert_next = mr.corner_verts[face.start() + (i + 1) % face.size()];
for (const int corner : face) {
const int vert_curr = mr.corner_verts[corner];
const int vert_next = mr.corner_verts[bke::mesh::face_corner_next(face, corner)];
float angle;
eh.add_or_modify(
{vert_curr, vert_next},

View File

@ -744,10 +744,10 @@ KeyingSet *ANIM_get_keyingset_for_autokeying(const Scene *scene, const char *tra
return ANIM_builtin_keyingset_get_named(transformKSName);
}
static void anim_keyingset_visit_for_search_impl(const bContext *C,
StringPropertySearchVisitFunc visit_fn,
void *visit_user_data,
const bool use_poll)
static void anim_keyingset_visit_for_search_impl(
const bContext *C,
blender::FunctionRef<void(StringPropertySearchVisitParams)> visit_fn,
const bool use_poll)
{
/* Poll requires context. */
if (use_poll && (C == nullptr)) {
@ -758,10 +758,10 @@ static void anim_keyingset_visit_for_search_impl(const bContext *C,
/* Active Keying Set. */
if (!use_poll || (scene && scene->active_keyingset)) {
StringPropertySearchVisitParams visit_params = {nullptr};
StringPropertySearchVisitParams visit_params{};
visit_params.text = "__ACTIVE__";
visit_params.info = "Active Keying Set";
visit_fn(visit_user_data, &visit_params);
visit_fn(visit_params);
}
/* User-defined Keying Sets. */
@ -770,10 +770,10 @@ static void anim_keyingset_visit_for_search_impl(const bContext *C,
if (use_poll && !ANIM_keyingset_context_ok_poll((bContext *)C, keyingset)) {
continue;
}
StringPropertySearchVisitParams visit_params = {nullptr};
StringPropertySearchVisitParams visit_params{};
visit_params.text = keyingset->idname;
visit_params.info = keyingset->name;
visit_fn(visit_user_data, &visit_params);
visit_fn(visit_params);
}
}
@ -782,31 +782,31 @@ static void anim_keyingset_visit_for_search_impl(const bContext *C,
if (use_poll && !ANIM_keyingset_context_ok_poll((bContext *)C, keyingset)) {
continue;
}
StringPropertySearchVisitParams visit_params = {nullptr};
StringPropertySearchVisitParams visit_params{};
visit_params.text = keyingset->idname;
visit_params.info = keyingset->name;
visit_fn(visit_user_data, &visit_params);
visit_fn(visit_params);
}
}
void ANIM_keyingset_visit_for_search(const bContext *C,
PointerRNA * /*ptr*/,
PropertyRNA * /*prop*/,
const char * /*edit_text*/,
StringPropertySearchVisitFunc visit_fn,
void *visit_user_data)
void ANIM_keyingset_visit_for_search(
const bContext *C,
PointerRNA * /*ptr*/,
PropertyRNA * /*prop*/,
const char * /*edit_text*/,
blender::FunctionRef<void(StringPropertySearchVisitParams)> visit_fn)
{
anim_keyingset_visit_for_search_impl(C, visit_fn, visit_user_data, false);
anim_keyingset_visit_for_search_impl(C, visit_fn, false);
}
void ANIM_keyingset_visit_for_search_no_poll(const bContext *C,
PointerRNA * /*ptr*/,
PropertyRNA * /*prop*/,
const char * /*edit_text*/,
StringPropertySearchVisitFunc visit_fn,
void *visit_user_data)
void ANIM_keyingset_visit_for_search_no_poll(
const bContext *C,
PointerRNA * /*ptr*/,
PropertyRNA * /*prop*/,
const char * /*edit_text*/,
blender::FunctionRef<void(StringPropertySearchVisitParams)> visit_fn)
{
anim_keyingset_visit_for_search_impl(C, visit_fn, visit_user_data, true);
anim_keyingset_visit_for_search_impl(C, visit_fn, true);
}
/* Menu of All Keying Sets ----------------------------- */

View File

@ -28,8 +28,7 @@ using namespace blender::asset_system;
bool catalogs_read_only(const AssetLibrary &library)
{
asset_system::AssetCatalogService *catalog_service = AS_asset_library_get_catalog_service(
&library);
asset_system::AssetCatalogService *catalog_service = library.catalog_service.get();
return catalog_service->is_read_only();
}
@ -62,12 +61,11 @@ asset_system::AssetCatalog *catalog_add(AssetLibrary *library,
StringRefNull name,
StringRef parent_path)
{
asset_system::AssetCatalogService *catalog_service = AS_asset_library_get_catalog_service(
library);
asset_system::AssetCatalogService *catalog_service = library->catalog_service.get();
if (!catalog_service) {
return nullptr;
}
if (catalogs_read_only(*library)) {
if (catalog_service->is_read_only()) {
return nullptr;
}
@ -87,13 +85,12 @@ asset_system::AssetCatalog *catalog_add(AssetLibrary *library,
void catalog_remove(AssetLibrary *library, const CatalogID &catalog_id)
{
asset_system::AssetCatalogService *catalog_service = AS_asset_library_get_catalog_service(
library);
asset_system::AssetCatalogService *catalog_service = library->catalog_service.get();
if (!catalog_service) {
BLI_assert_unreachable();
return;
}
if (catalogs_read_only(*library)) {
if (catalog_service->is_read_only()) {
return;
}
@ -107,13 +104,12 @@ void catalog_rename(AssetLibrary *library,
const CatalogID catalog_id,
const StringRefNull new_name)
{
asset_system::AssetCatalogService *catalog_service = AS_asset_library_get_catalog_service(
library);
asset_system::AssetCatalogService *catalog_service = library->catalog_service.get();
if (!catalog_service) {
BLI_assert_unreachable();
return;
}
if (catalogs_read_only(*library)) {
if (catalog_service->is_read_only()) {
return;
}
@ -137,13 +133,12 @@ void catalog_move(AssetLibrary *library,
const CatalogID src_catalog_id,
const std::optional<CatalogID> dst_parent_catalog_id)
{
asset_system::AssetCatalogService *catalog_service = AS_asset_library_get_catalog_service(
library);
asset_system::AssetCatalogService *catalog_service = library->catalog_service.get();
if (!catalog_service) {
BLI_assert_unreachable();
return;
}
if (catalogs_read_only(*library)) {
if (catalog_service->is_read_only()) {
return;
}
@ -181,13 +176,12 @@ void catalog_move(AssetLibrary *library,
void catalogs_save_from_main_path(AssetLibrary *library, const Main *bmain)
{
asset_system::AssetCatalogService *catalog_service = AS_asset_library_get_catalog_service(
library);
asset_system::AssetCatalogService *catalog_service = library->catalog_service.get();
if (!catalog_service) {
BLI_assert_unreachable();
return;
}
if (catalogs_read_only(*library)) {
if (catalog_service->is_read_only()) {
return;
}

View File

@ -89,7 +89,7 @@ struct IDVecStats {
* Helper to report stats about the IDs in context. Operator polls use this, also to report a
* helpful disabled hint to the user.
*/
static IDVecStats asset_operation_get_id_vec_stats_from_ids(const Vector<PointerRNA> &id_pointers)
static IDVecStats asset_operation_get_id_vec_stats_from_ids(const Span<PointerRNA> id_pointers)
{
IDVecStats stats;
@ -125,7 +125,7 @@ static const char *asset_operation_unsupported_type_msg(const bool is_single)
class AssetMarkHelper {
public:
void operator()(const bContext &C, const Vector<PointerRNA> &ids);
void operator()(const bContext &C, Span<PointerRNA> ids);
void reportResults(ReportList &reports) const;
bool wasSuccessful() const;
@ -140,7 +140,7 @@ class AssetMarkHelper {
Stats stats;
};
void AssetMarkHelper::operator()(const bContext &C, const Vector<PointerRNA> &ids)
void AssetMarkHelper::operator()(const bContext &C, const Span<PointerRNA> ids)
{
for (const PointerRNA &ptr : ids) {
BLI_assert(RNA_struct_is_ID(ptr.type));
@ -190,7 +190,7 @@ void AssetMarkHelper::reportResults(ReportList &reports) const
}
}
static int asset_mark_exec(const bContext *C, const wmOperator *op, const Vector<PointerRNA> &ids)
static int asset_mark_exec(const bContext *C, const wmOperator *op, const Span<PointerRNA> ids)
{
AssetMarkHelper mark_helper;
mark_helper(*C, ids);
@ -206,7 +206,7 @@ static int asset_mark_exec(const bContext *C, const wmOperator *op, const Vector
return OPERATOR_FINISHED;
}
static bool asset_mark_poll(bContext *C, const Vector<PointerRNA> &ids)
static bool asset_mark_poll(bContext *C, const Span<PointerRNA> ids)
{
IDVecStats ctx_stats = asset_operation_get_id_vec_stats_from_ids(ids);
@ -265,7 +265,7 @@ class AssetClearHelper {
public:
AssetClearHelper(const bool set_fake_user) : set_fake_user_(set_fake_user) {}
void operator()(const Vector<PointerRNA> &ids);
void operator()(Span<PointerRNA> ids);
void reportResults(const bContext *C, ReportList &reports) const;
bool wasSuccessful() const;
@ -279,7 +279,7 @@ class AssetClearHelper {
Stats stats;
};
void AssetClearHelper::operator()(const Vector<PointerRNA> &ids)
void AssetClearHelper::operator()(const Span<PointerRNA> ids)
{
for (const PointerRNA &ptr : ids) {
BLI_assert(RNA_struct_is_ID(ptr.type));
@ -332,7 +332,7 @@ bool AssetClearHelper::wasSuccessful() const
return stats.tot_cleared > 0;
}
static int asset_clear_exec(const bContext *C, const wmOperator *op, const Vector<PointerRNA> &ids)
static int asset_clear_exec(const bContext *C, const wmOperator *op, const Span<PointerRNA> ids)
{
const bool set_fake_user = RNA_boolean_get(op->ptr, "set_fake_user");
AssetClearHelper clear_helper(set_fake_user);
@ -349,7 +349,7 @@ static int asset_clear_exec(const bContext *C, const wmOperator *op, const Vecto
return OPERATOR_FINISHED;
}
static bool asset_clear_poll(bContext *C, const Vector<PointerRNA> &ids)
static bool asset_clear_poll(bContext *C, const Span<PointerRNA> ids)
{
IDVecStats ctx_stats = asset_operation_get_id_vec_stats_from_ids(ids);
@ -587,7 +587,7 @@ static asset_system::AssetCatalogService *get_catalog_service(bContext *C)
}
asset_system::AssetLibrary *asset_lib = ED_fileselect_active_asset_library_get(sfile);
return AS_asset_library_get_catalog_service(asset_lib);
return asset_lib->catalog_service.get();
}
static int asset_catalog_undo_exec(bContext *C, wmOperator * /*op*/)

View File

@ -225,19 +225,19 @@ int ANIM_scene_get_keyingset_index(Scene *scene, KeyingSet *ks);
*/
KeyingSet *ANIM_get_keyingset_for_autokeying(const Scene *scene, const char *transformKSName);
void ANIM_keyingset_visit_for_search(const bContext *C,
PointerRNA *ptr,
PropertyRNA *prop,
const char *edit_text,
StringPropertySearchVisitFunc visit_fn,
void *visit_user_data);
void ANIM_keyingset_visit_for_search(
const bContext *C,
PointerRNA *ptr,
PropertyRNA *prop,
const char *edit_text,
blender::FunctionRef<void(StringPropertySearchVisitParams)> visit_fn);
void ANIM_keyingset_visit_for_search_no_poll(const bContext *C,
PointerRNA *ptr,
PropertyRNA *prop,
const char *edit_text,
StringPropertySearchVisitFunc visit_fn,
void *visit_user_data);
void ANIM_keyingset_visit_for_search_no_poll(
const bContext *C,
PointerRNA *ptr,
PropertyRNA *prop,
const char *edit_text,
blender::FunctionRef<void(StringPropertySearchVisitParams)> visit_fn);
/**
* Dynamically populate an enum of Keying Sets.
*/

View File

@ -10,6 +10,7 @@
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <fmt/format.h>
#include "DNA_object_types.h"
#include "DNA_screen_types.h"
@ -365,51 +366,46 @@ void UI_but_func_identity_compare_set(uiBut *but, uiButIdentityCompareFunc cmp_f
/* *** RNA collection search menu *** */
struct CollItemSearch {
CollItemSearch *next, *prev;
void *data;
char *name;
std::string name;
int index;
int iconid;
bool is_id;
int name_prefix_offset;
uint has_sep_char : 1;
bool is_id;
bool has_sep_char;
};
static bool add_collection_search_item(CollItemSearch *cis,
static bool add_collection_search_item(CollItemSearch &cis,
const bool requires_exact_data_name,
const bool has_id_icon,
uiSearchItems *items)
{
char name_buf[UI_MAX_DRAW_STR];
/* If no item has an own icon to display, libraries can use the library icons rather than the
* name prefix for showing the library status. */
int name_prefix_offset = cis->name_prefix_offset;
if (!has_id_icon && cis->is_id && !requires_exact_data_name) {
cis->iconid = UI_icon_from_library(static_cast<const ID *>(cis->data));
/* No need to re-allocate, string should be shorter than before (lib status prefix is
* removed). */
int name_prefix_offset = cis.name_prefix_offset;
if (!has_id_icon && cis.is_id && !requires_exact_data_name) {
cis.iconid = UI_icon_from_library(static_cast<const ID *>(cis.data));
char name_buf[UI_MAX_DRAW_STR];
BKE_id_full_name_ui_prefix_get(
name_buf, static_cast<const ID *>(cis->data), false, UI_SEP_CHAR, &name_prefix_offset);
const int name_buf_len = strlen(name_buf);
BLI_assert(name_buf_len <= strlen(cis->name));
memcpy(cis->name, name_buf, name_buf_len + 1);
name_buf, static_cast<const ID *>(cis.data), false, UI_SEP_CHAR, &name_prefix_offset);
cis.name = name_buf;
}
return UI_search_item_add(items,
cis->name,
cis->data,
cis->iconid,
cis->has_sep_char ? int(UI_BUT_HAS_SEP_CHAR) : 0,
cis.name.c_str(),
cis.data,
cis.iconid,
cis.has_sep_char ? int(UI_BUT_HAS_SEP_CHAR) : 0,
name_prefix_offset);
}
void ui_rna_collection_search_update_fn(
const bContext *C, void *arg, const char *str, uiSearchItems *items, const bool is_first)
{
using namespace blender;
uiRNACollectionSearch *data = static_cast<uiRNACollectionSearch *>(arg);
const int flag = RNA_property_flag(data->target_prop);
ListBase *items_list = MEM_cnew<ListBase>("items_list");
const bool is_ptr_target = (RNA_property_type(data->target_prop) == PROP_POINTER);
/* For non-pointer properties, UI code acts entirely based on the item's name. So the name has to
* match the RNA name exactly. So only for pointer properties, the name can be modified to add
@ -417,16 +413,14 @@ void ui_rna_collection_search_update_fn(
const bool requires_exact_data_name = !is_ptr_target;
const bool skip_filter = is_first;
char name_buf[UI_MAX_DRAW_STR];
char *name;
bool has_id_icon = false;
blender::ui::string_search::StringSearch<CollItemSearch> search;
/* The string search API requires pointer stability. */
Vector<std::unique_ptr<CollItemSearch>> items_list;
if (data->search_prop != nullptr) {
/* build a temporary list of relevant items first */
int item_index = 0;
RNA_PROP_BEGIN (&data->search_ptr, itemptr, data->search_prop) {
if (flag & PROP_ID_SELF_CHECK) {
if (itemptr.data == data->target_ptr.owner_id) {
continue;
@ -445,6 +439,7 @@ void ui_rna_collection_search_update_fn(
bool has_sep_char = false;
const bool is_id = itemptr.type && RNA_struct_is_ID(itemptr.type);
char *name;
if (is_id) {
iconid = ui_id_icon_get(C, static_cast<ID *>(itemptr.data), false);
if (!ELEM(iconid, 0, ICON_BLANK1)) {
@ -468,24 +463,19 @@ void ui_rna_collection_search_update_fn(
}
if (name) {
CollItemSearch *cis = MEM_cnew<CollItemSearch>(__func__);
auto cis = std::make_unique<CollItemSearch>();
cis->data = itemptr.data;
cis->name = BLI_strdup(name);
cis->index = item_index;
cis->name = name;
cis->index = items_list.size();
cis->iconid = iconid;
cis->is_id = is_id;
cis->name_prefix_offset = name_prefix_offset;
cis->has_sep_char = has_sep_char;
if (!skip_filter) {
search.add(name, cis);
}
BLI_addtail(items_list, cis);
items_list.append(std::move(cis));
if (name != name_buf) {
MEM_freeN(name);
}
}
item_index++;
}
RNA_PROP_END;
}
@ -495,85 +485,66 @@ void ui_rna_collection_search_update_fn(
data->target_prop);
BLI_assert(search_flag & PROP_STRING_SEARCH_SUPPORTED);
struct SearchVisitUserData {
blender::string_search::StringSearch<CollItemSearch> *search;
bool skip_filter;
int item_index;
ListBase *items_list;
const char *func_id;
} user_data = {nullptr};
const bool show_extra_info = (G.debug_value == 102);
user_data.search = &search;
user_data.skip_filter = skip_filter;
user_data.items_list = items_list;
user_data.func_id = __func__;
RNA_property_string_search(C,
&data->target_ptr,
data->target_prop,
str,
[&](StringPropertySearchVisitParams visit_params) {
auto cis = std::make_unique<CollItemSearch>();
RNA_property_string_search(
C,
&data->target_ptr,
data->target_prop,
str,
[](void *user_data, const StringPropertySearchVisitParams *visit_params) {
const bool show_extra_info = (G.debug_value == 102);
cis->data = nullptr;
if (visit_params.info && show_extra_info) {
cis->name = fmt::format("{}" UI_SEP_CHAR_S "{}",
visit_params.text,
*visit_params.info);
}
else {
cis->name = std::move(visit_params.text);
}
SearchVisitUserData *search_data = (SearchVisitUserData *)user_data;
CollItemSearch *cis = MEM_cnew<CollItemSearch>(search_data->func_id);
cis->data = nullptr;
if (visit_params->info && show_extra_info) {
cis->name = BLI_sprintfN(
"%s" UI_SEP_CHAR_S "%s", visit_params->text, visit_params->info);
}
else {
cis->name = BLI_strdup(visit_params->text);
}
cis->index = search_data->item_index;
cis->iconid = ICON_NONE;
cis->is_id = false;
cis->name_prefix_offset = 0;
cis->has_sep_char = visit_params->info != nullptr;
if (!search_data->skip_filter) {
search_data->search->add(visit_params->text, cis);
}
BLI_addtail(search_data->items_list, cis);
search_data->item_index++;
},
(void *)&user_data);
cis->index = items_list.size();
cis->iconid = ICON_NONE;
cis->is_id = false;
cis->name_prefix_offset = 0;
cis->has_sep_char = visit_params.info.has_value();
items_list.append(std::move(cis));
});
if (search_flag & PROP_STRING_SEARCH_SORT) {
BLI_listbase_sort(items_list, [](const void *a_, const void *b_) -> int {
const CollItemSearch *cis_a = (const CollItemSearch *)a_;
const CollItemSearch *cis_b = (const CollItemSearch *)b_;
return BLI_strcasecmp_natural(cis_a->name, cis_b->name);
});
int i = 0;
LISTBASE_FOREACH (CollItemSearch *, cis, items_list) {
cis->index = i;
i++;
std::sort(
items_list.begin(),
items_list.end(),
[](const std::unique_ptr<CollItemSearch> &a, const std::unique_ptr<CollItemSearch> &b) {
return BLI_strcasecmp_natural(a->name.c_str(), b->name.c_str()) <= 0;
});
for (const int i : items_list.index_range()) {
items_list[i]->index = i;
}
}
}
if (skip_filter) {
LISTBASE_FOREACH (CollItemSearch *, cis, items_list) {
if (!add_collection_search_item(cis, requires_exact_data_name, has_id_icon, items)) {
for (std::unique_ptr<CollItemSearch> &cis : items_list) {
if (!add_collection_search_item(*cis, requires_exact_data_name, has_id_icon, items)) {
break;
}
}
}
else {
const blender::Vector<CollItemSearch *> filtered_items = search.query(str);
ui::string_search::StringSearch<CollItemSearch> search;
for (std::unique_ptr<CollItemSearch> &cis : items_list) {
search.add(cis->name, cis.get());
}
const Vector<CollItemSearch *> filtered_items = search.query(str);
for (CollItemSearch *cis : filtered_items) {
if (!add_collection_search_item(cis, requires_exact_data_name, has_id_icon, items)) {
if (!add_collection_search_item(*cis, requires_exact_data_name, has_id_icon, items)) {
break;
}
}
}
LISTBASE_FOREACH (CollItemSearch *, cis, items_list) {
MEM_freeN(cis->name);
}
BLI_freelistN(items_list);
MEM_freeN(items_list);
}
int UI_icon_from_id(const ID *id)

View File

@ -4846,6 +4846,8 @@ void ui_draw_but(const bContext *C, ARegion *region, uiStyle *style, uiBut *but,
case UI_BTYPE_SEPR:
break;
case UI_BTYPE_SEPR_LINE:
/* Add horizontal padding between the line and menu sides. */
BLI_rcti_pad(rect, int(-7.0f * UI_SCALE_FAC), 0);
ui_draw_separator(&tui->wcol_menu_item, but, rect);
break;
default: {

View File

@ -182,7 +182,7 @@ AssetCatalogTreeView::AssetCatalogTreeView(asset_system::AssetLibrary *library,
FileAssetSelectParams *params,
SpaceFile &space_file)
: asset_library_(library),
catalog_tree_(AS_asset_library_get_catalog_tree(library)),
catalog_tree_(library->catalog_service->get_catalog_tree()),
params_(params),
space_file_(space_file)
{
@ -502,8 +502,7 @@ AssetCatalog *AssetCatalogDropTarget::get_drag_catalog(
if (drag.type != WM_DRAG_ASSET_CATALOG) {
return nullptr;
}
const AssetCatalogService *catalog_service = AS_asset_library_get_catalog_service(
&asset_library);
const AssetCatalogService *catalog_service = asset_library.catalog_service.get();
const wmDragAssetCatalog *catalog_drag = WM_drag_get_asset_catalog_data(&drag);
return catalog_service->find_catalog(catalog_drag->drag_catalog_id);

View File

@ -70,25 +70,6 @@ static void remap_edges(const OffsetIndices<int> src_faces,
});
}
/** Create a mesh with no built-in attributes. */
static Mesh *create_mesh_no_attributes(const Mesh &params_mesh,
const int verts_num,
const int edges_num,
const int faces_num,
const int corners_num)
{
Mesh *mesh = BKE_mesh_new_nomain(0, 0, faces_num, 0);
mesh->verts_num = verts_num;
mesh->edges_num = edges_num;
mesh->corners_num = corners_num;
CustomData_free_layer_named(&mesh->vert_data, "position", 0);
CustomData_free_layer_named(&mesh->edge_data, ".edge_verts", 0);
CustomData_free_layer_named(&mesh->corner_data, ".corner_vert", 0);
CustomData_free_layer_named(&mesh->corner_data, ".corner_edge", 0);
BKE_mesh_copy_parameters_for_eval(mesh, &params_mesh);
return mesh;
}
static void copy_loose_vert_hint(const Mesh &src, Mesh &dst)
{
const auto &src_cache = src.runtime->loose_verts_cache;
@ -218,8 +199,9 @@ std::optional<Mesh *> mesh_copy_selection(
return std::nullopt;
}
Mesh *dst_mesh = create_mesh_no_attributes(
src_mesh, vert_mask.size(), edge_mask.size(), face_mask.size(), 0);
Mesh *dst_mesh = bke::mesh_new_no_attributes(
vert_mask.size(), edge_mask.size(), face_mask.size(), 0);
BKE_mesh_copy_parameters_for_eval(dst_mesh, &src_mesh);
bke::MutableAttributeAccessor dst_attributes = dst_mesh->attributes_for_write();
dst_attributes.add<int2>(".edge_verts", bke::AttrDomain::Edge, bke::AttributeInitConstruct());
MutableSpan<int2> dst_edges = dst_mesh->edges_for_write();
@ -351,8 +333,9 @@ std::optional<Mesh *> mesh_copy_selection_keep_verts(
return std::nullopt;
}
Mesh *dst_mesh = create_mesh_no_attributes(
src_mesh, src_mesh.verts_num, edge_mask.size(), face_mask.size(), 0);
Mesh *dst_mesh = bke::mesh_new_no_attributes(
src_mesh.verts_num, edge_mask.size(), face_mask.size(), 0);
BKE_mesh_copy_parameters_for_eval(dst_mesh, &src_mesh);
bke::MutableAttributeAccessor dst_attributes = dst_mesh->attributes_for_write();
const OffsetIndices<int> dst_faces = offset_indices::gather_selected_offsets(
@ -443,8 +426,9 @@ std::optional<Mesh *> mesh_copy_selection_keep_edges(
return std::nullopt;
}
Mesh *dst_mesh = create_mesh_no_attributes(
src_mesh, src_mesh.verts_num, src_mesh.edges_num, face_mask.size(), 0);
Mesh *dst_mesh = bke::mesh_new_no_attributes(
src_mesh.verts_num, src_mesh.edges_num, face_mask.size(), 0);
BKE_mesh_copy_parameters_for_eval(dst_mesh, &src_mesh);
bke::MutableAttributeAccessor dst_attributes = dst_mesh->attributes_for_write();
const OffsetIndices<int> dst_faces = offset_indices::gather_selected_offsets(

View File

@ -755,9 +755,9 @@ std::string GLShader::fragment_interface_declare(const ShaderCreateInfo &info) c
std::string pre_main, post_main;
ss << "\n/* Interfaces. */\n";
const Vector<StageInterfaceInfo *> &in_interfaces = info.geometry_source_.is_empty() ?
info.vertex_out_interfaces_ :
info.geometry_out_interfaces_;
const Span<StageInterfaceInfo *> in_interfaces = info.geometry_source_.is_empty() ?
info.vertex_out_interfaces_ :
info.geometry_out_interfaces_;
for (const StageInterfaceInfo *iface : in_interfaces) {
print_interface(ss, "in", *iface);
}
@ -909,7 +909,7 @@ std::string GLShader::geometry_layout_declare(const ShaderCreateInfo &info) cons
return ss.str();
}
static StageInterfaceInfo *find_interface_by_name(const Vector<StageInterfaceInfo *> &ifaces,
static StageInterfaceInfo *find_interface_by_name(const Span<StageInterfaceInfo *> ifaces,
const StringRefNull &name)
{
for (auto *iface : ifaces) {

View File

@ -316,7 +316,7 @@ void VKDevice::context_unregister(VKContext &context)
{
contexts_.remove(contexts_.first_index_of(std::reference_wrapper(context)));
}
const Vector<std::reference_wrapper<VKContext>> &VKDevice::contexts_get() const
Span<std::reference_wrapper<VKContext>> VKDevice::contexts_get() const
{
return contexts_;
};

View File

@ -207,7 +207,7 @@ class VKDevice : public NonCopyable {
void context_register(VKContext &context);
void context_unregister(VKContext &context);
const Vector<std::reference_wrapper<VKContext>> &contexts_get() const;
Span<std::reference_wrapper<VKContext>> contexts_get() const;
const VKBuffer &dummy_buffer_get() const
{

View File

@ -135,7 +135,7 @@ void VKFrameBuffer::build_clear_attachments_color(const float (*clear_colors)[4]
/** \name Clear
* \{ */
void VKFrameBuffer::clear(const Vector<VkClearAttachment> &attachments) const
void VKFrameBuffer::clear(const Span<VkClearAttachment> attachments) const
{
if (attachments.is_empty()) {
return;

View File

@ -139,7 +139,7 @@ class VKFrameBuffer : public FrameBuffer {
void build_clear_attachments_color(const float (*clear_colors)[4],
const bool multi_clear_colors,
Vector<VkClearAttachment> &r_attachments) const;
void clear(const Vector<VkClearAttachment> &attachments) const;
void clear(Span<VkClearAttachment> attachments) const;
};
static inline VKFrameBuffer *unwrap(FrameBuffer *framebuffer)

View File

@ -869,7 +869,7 @@ static VkDescriptorSetLayoutBinding create_descriptor_set_layout_binding(
static void add_descriptor_set_layout_bindings(
const VKShaderInterface &interface,
const Vector<shader::ShaderCreateInfo::Resource> &resources,
const Span<shader::ShaderCreateInfo::Resource> resources,
Vector<VkDescriptorSetLayoutBinding> &r_bindings,
VkShaderStageFlags vk_shader_stages)
{
@ -888,7 +888,7 @@ static void add_descriptor_set_layout_bindings(
static VkDescriptorSetLayoutCreateInfo create_descriptor_set_layout(
const VKShaderInterface &interface,
const Vector<shader::ShaderCreateInfo::Resource> &resources,
const Span<shader::ShaderCreateInfo::Resource> resources,
Vector<VkDescriptorSetLayoutBinding> &r_bindings,
VkShaderStageFlags vk_shader_stages)
{
@ -1123,9 +1123,9 @@ std::string VKShader::fragment_interface_declare(const shader::ShaderCreateInfo
const VKWorkarounds &workarounds = VKBackend::get().device_get().workarounds_get();
ss << "\n/* Interfaces. */\n";
const Vector<StageInterfaceInfo *> &in_interfaces = info.geometry_source_.is_empty() ?
info.vertex_out_interfaces_ :
info.geometry_out_interfaces_;
const Span<StageInterfaceInfo *> in_interfaces = info.geometry_source_.is_empty() ?
info.vertex_out_interfaces_ :
info.geometry_out_interfaces_;
int location = 0;
for (const StageInterfaceInfo *iface : in_interfaces) {
print_interface(ss, "in", *iface, location);
@ -1227,10 +1227,10 @@ std::string VKShader::geometry_interface_declare(const shader::ShaderCreateInfo
return ss.str();
}
static StageInterfaceInfo *find_interface_by_name(const Vector<StageInterfaceInfo *> &ifaces,
const StringRefNull &name)
static StageInterfaceInfo *find_interface_by_name(const Span<StageInterfaceInfo *> ifaces,
const StringRefNull name)
{
for (auto *iface : ifaces) {
for (StageInterfaceInfo *iface : ifaces) {
if (iface->instance_name == name) {
return iface;
}

View File

@ -167,7 +167,7 @@ static float *find_or_add_attribute(const StringRef name,
}
static void load_custom_attributes(const Mesh *mesh,
const Vector<int> &ply_to_vertex,
const Span<int> ply_to_vertex,
uint32_t vertex_offset,
Vector<PlyCustomAttribute> &r_attributes)
{

View File

@ -1247,7 +1247,7 @@ void shape_key_export_chaser(pxr::UsdStageRefPtr stage,
void export_deform_verts(const Mesh *mesh,
const pxr::UsdSkelBindingAPI &skel_api,
const Vector<std::string> &bone_names)
const Span<std::string> bone_names)
{
BLI_assert(mesh);
BLI_assert(skel_api);

View File

@ -143,6 +143,6 @@ void shape_key_export_chaser(pxr::UsdStageRefPtr stage,
*/
void export_deform_verts(const Mesh *mesh,
const pxr::UsdSkelBindingAPI &skel_api,
const Vector<std::string> &bone_names);
Span<std::string> bone_names);
} // namespace blender::io::usd

View File

@ -474,7 +474,7 @@ static bool parse_keyword(const char *&p, const char *end, StringRef keyword)
/* Special case: if there were no faces/edges in any geometries,
* treat all the vertices as a point cloud. */
static void use_all_vertices_if_no_faces(Geometry *geom,
const Vector<std::unique_ptr<Geometry>> &all_geometries,
const Span<std::unique_ptr<Geometry>> all_geometries,
const GlobalVertices &global_vertices)
{
if (!global_vertices.vertices.is_empty() && geom && geom->geom_type_ == GEOM_MESH) {

View File

@ -50,11 +50,6 @@ typedef struct AssetFilterSettings {
* more than that from the file. So pointers to other IDs or ID data are strictly forbidden.
*/
typedef struct AssetMetaData {
#ifdef __cplusplus
/** Enables use with `std::unique_ptr<AssetMetaData>`. */
~AssetMetaData();
#endif
/** Runtime type, to reference event callbacks. Only valid for local assets. */
struct AssetTypeInfo *local_type_info;
@ -96,6 +91,11 @@ typedef struct AssetMetaData {
short tot_tags;
char _pad[4];
#ifdef __cplusplus
/** Enables use with `std::unique_ptr<AssetMetaData>`. */
~AssetMetaData();
#endif
} AssetMetaData;
typedef enum eAssetLibraryType {

View File

@ -17,6 +17,7 @@
#include "RNA_types.hh"
#include "BLI_compiler_attrs.h"
#include "BLI_function_ref.hh"
struct ID;
struct IDOverrideLibrary;
@ -378,16 +379,15 @@ void RNA_property_string_set_bytes(PointerRNA *ptr, PropertyRNA *prop, const cha
eStringPropertySearchFlag RNA_property_string_search_flag(PropertyRNA *prop);
/**
* Search candidates for string `prop` by calling `visit_fn` with each string.
* Typically these strings are collected in `visit_user_data` in a format defined by the caller.
*
* See #PropStringSearchFunc for details.
*/
void RNA_property_string_search(const bContext *C,
PointerRNA *ptr,
PropertyRNA *prop,
const char *edit_text,
StringPropertySearchVisitFunc visit_fn,
void *visit_user_data);
void RNA_property_string_search(
const bContext *C,
PointerRNA *ptr,
PropertyRNA *prop,
const char *edit_text,
blender::FunctionRef<void(StringPropertySearchVisitParams)> visit_fn);
/**
* \return the length without `\0` terminator.

View File

@ -10,6 +10,10 @@
#ifndef __RNA_TYPES_H__
#define __RNA_TYPES_H__
#include <optional>
#include <string>
#include "../blenlib/BLI_function_ref.hh"
#include "../blenlib/BLI_sys_types.h"
#include "../blenlib/BLI_utildefines.h"
@ -538,10 +542,10 @@ using StringPropertyLengthFunc = int (*)(PointerRNA *ptr, PropertyRNA *prop);
using StringPropertySetFunc = void (*)(PointerRNA *ptr, PropertyRNA *prop, const char *value);
struct StringPropertySearchVisitParams {
/** Text being searched for (never NULL). */
const char *text;
/** Additional information to display (optional, may be NULL). */
const char *info;
/** Text being searched for. */
std::string text;
/** Additional information to display. */
std::optional<std::string> info;
};
enum eStringPropertySearchFlag {
@ -562,12 +566,6 @@ enum eStringPropertySearchFlag {
};
ENUM_OPERATORS(eStringPropertySearchFlag, PROP_STRING_SEARCH_SUGGESTION)
/**
* Visit string search candidates, `text` may be freed once this callback has finished,
* so references to it should not be held.
*/
using StringPropertySearchVisitFunc = void (*)(void *visit_user_data,
const StringPropertySearchVisitParams *params);
/**
* \param C: context, may be NULL (in this case all available items should be shown).
* \param ptr: RNA pointer.
@ -577,14 +575,13 @@ using StringPropertySearchVisitFunc = void (*)(void *visit_user_data,
* for the search results (auto-complete Python attributes for e.g.).
* \param visit_fn: This function is called with every search candidate and is typically
* responsible for storing the search results.
* \param visit_user_data: Caller defined data, passed to `visit_fn`.
*/
using StringPropertySearchFunc = void (*)(const bContext *C,
PointerRNA *ptr,
PropertyRNA *prop,
const char *edit_text,
StringPropertySearchVisitFunc visit_fn,
void *visit_user_data);
using StringPropertySearchFunc =
void (*)(const bContext *C,
PointerRNA *ptr,
PropertyRNA *prop,
const char *edit_text,
blender::FunctionRef<void(StringPropertySearchVisitParams)> visit_fn);
using EnumPropertyGetFunc = int (*)(PointerRNA *ptr, PropertyRNA *prop);
using EnumPropertySetFunc = void (*)(PointerRNA *ptr, PropertyRNA *prop, int value);

View File

@ -1169,11 +1169,10 @@ static char *rna_def_property_search_func(
"PointerRNA *ptr, "
"PropertyRNA *prop, "
"const char *edit_text, "
"StringPropertySearchVisitFunc visit_fn, "
"void *visit_user_data)\n",
"blender::FunctionRef<void(StringPropertySearchVisitParams)> visit_fn)\n",
func);
fprintf(f, "{\n");
fprintf(f, "\n %s(C, ptr, prop, edit_text, visit_fn, visit_user_data);\n", manualfunc);
fprintf(f, "\n %s(C, ptr, prop, edit_text, visit_fn);\n", manualfunc);
fprintf(f, "}\n\n");
return func;
}

View File

@ -3702,12 +3702,11 @@ void RNA_property_string_search(const bContext *C,
PointerRNA *ptr,
PropertyRNA *prop,
const char *edit_text,
StringPropertySearchVisitFunc visit_fn,
void *visit_user_data)
blender::FunctionRef<void(StringPropertySearchVisitParams)> visit_fn)
{
BLI_assert(RNA_property_string_search_flag(prop) & PROP_STRING_SEARCH_SUPPORTED);
StringPropertyRNA *sprop = (StringPropertyRNA *)rna_ensure_property(prop);
sprop->search(C, ptr, prop, edit_text, visit_fn, visit_user_data);
sprop->search(C, ptr, prop, edit_text, visit_fn);
}
int RNA_property_enum_get(PointerRNA *ptr, PropertyRNA *prop)

View File

@ -364,7 +364,7 @@ void rna_AssetMetaData_catalog_id_update(bContext *C, PointerRNA *ptr)
}
AssetMetaData *asset_data = static_cast<AssetMetaData *>(ptr->data);
AS_asset_library_refresh_catalog_simplename(asset_library, asset_data);
asset_library->refresh_catalog_simplename(asset_data);
}
static PointerRNA rna_AssetHandle_file_data_get(PointerRNA *ptr)

View File

@ -1597,10 +1597,10 @@ static void bpy_prop_string_set_fn(PointerRNA *ptr, PropertyRNA *prop, const cha
}
}
static bool bpy_prop_string_visit_fn_call(PyObject *py_func,
PyObject *item,
StringPropertySearchVisitFunc visit_fn,
void *visit_user_data)
static bool bpy_prop_string_visit_fn_call(
PyObject *py_func,
PyObject *item,
blender::FunctionRef<void(StringPropertySearchVisitParams)> visit_fn)
{
const char *text;
const char *info = nullptr;
@ -1637,19 +1637,19 @@ static bool bpy_prop_string_visit_fn_call(PyObject *py_func,
}
}
StringPropertySearchVisitParams visit_params = {nullptr};
StringPropertySearchVisitParams visit_params{};
visit_params.text = text;
visit_params.info = info;
visit_fn(visit_user_data, &visit_params);
visit_params.info = info ? info : "";
visit_fn(visit_params);
return true;
}
static void bpy_prop_string_visit_for_search_fn(const bContext *C,
PointerRNA *ptr,
PropertyRNA *prop,
const char *edit_text,
StringPropertySearchVisitFunc visit_fn,
void *visit_user_data)
static void bpy_prop_string_visit_for_search_fn(
const bContext *C,
PointerRNA *ptr,
PropertyRNA *prop,
const char *edit_text,
blender::FunctionRef<void(StringPropertySearchVisitParams)> visit_fn)
{
BPyPropStore *prop_store = static_cast<BPyPropStore *>(RNA_property_py_data_get(prop));
PyObject *py_func;
@ -1703,8 +1703,7 @@ static void bpy_prop_string_visit_for_search_fn(const bContext *C,
if (py_text == nullptr) {
break;
}
const bool ok = bpy_prop_string_visit_fn_call(
py_func, py_text, visit_fn, visit_user_data);
const bool ok = bpy_prop_string_visit_fn_call(py_func, py_text, visit_fn);
Py_DECREF(py_text);
if (!ok) {
break;
@ -1734,8 +1733,7 @@ static void bpy_prop_string_visit_for_search_fn(const bContext *C,
const Py_ssize_t ret_num = PySequence_Fast_GET_SIZE(ret_fast);
PyObject **ret_fast_items = PySequence_Fast_ITEMS(ret_fast);
for (Py_ssize_t i = 0; i < ret_num; i++) {
const bool ok = bpy_prop_string_visit_fn_call(
py_func, ret_fast_items[i], visit_fn, visit_user_data);
const bool ok = bpy_prop_string_visit_fn_call(py_func, ret_fast_items[i], visit_fn);
if (!ok) {
break;
}

View File

@ -33,6 +33,10 @@
#include "RE_compositor.hh"
#include "RE_pipeline.h"
#include "WM_api.hh"
#include "GPU_context.h"
#include "render_types.h"
namespace blender::render {
@ -504,7 +508,23 @@ class RealtimeCompositor {
* to avoid them blocking each other. */
BLI_assert(!BLI_thread_is_main() || G.background);
/* The realtime compositor uses GPU module and does not rely on the draw manager, or its global
* state. This means that activation of GPU context does not require lock of the main thread.
*
* However, while this has been tested on Linux and works well, on macOS it causes to
* spontaneous invalid colors in the composite output. The Windows has not been extensively
* tested yet. */
#if defined(__linux__)
void *re_system_gpu_context = RE_system_gpu_context_get(&render_);
void *re_blender_gpu_context = RE_blender_gpu_context_ensure(&render_);
GPU_render_begin();
WM_system_gpu_context_activate(re_system_gpu_context);
GPU_context_active_set(static_cast<GPUContext *>(re_blender_gpu_context));
#else
DRW_render_context_enable(&render_);
#endif
context_->update_input_data(input_data);
/* Always recreate the evaluator, as this only runs on compositing node changes and
@ -517,7 +537,15 @@ class RealtimeCompositor {
context_->output_to_render_result();
context_->viewer_output_to_viewer_image();
texture_pool_->free_unused_and_reset();
#if defined(__linux__)
GPU_flush();
GPU_render_end();
GPU_context_active_set(nullptr);
WM_system_gpu_context_release(re_system_gpu_context);
#else
DRW_render_context_disable(&render_);
#endif
}
};

View File

@ -17,9 +17,12 @@
#include <optional>
#include <string>
#include "BLI_compiler_attrs.h"
#include "BLI_sys_types.h"
#include "DNA_windowmanager_types.h"
#include "BLI_compiler_attrs.h"
#include "BLI_function_ref.hh"
#include "BLI_sys_types.h"
#include "WM_keymap.hh"
#include "WM_types.hh"
@ -1122,12 +1125,12 @@ bool WM_operatortype_remove(const char *idname);
*/
void WM_operatortype_last_properties_clear_all();
void WM_operatortype_idname_visit_for_search(const bContext *C,
PointerRNA *ptr,
PropertyRNA *prop,
const char *edit_text,
StringPropertySearchVisitFunc visit_fn,
void *visit_user_data);
void WM_operatortype_idname_visit_for_search(
const bContext *C,
PointerRNA *ptr,
PropertyRNA *prop,
const char *edit_text,
blender::FunctionRef<void(StringPropertySearchVisitParams)> visit_fn);
/**
* Tag all operator-properties of \a ot defined after calling this, until
@ -1229,12 +1232,12 @@ void WM_menutype_freelink(MenuType *mt);
void WM_menutype_free();
bool WM_menutype_poll(bContext *C, MenuType *mt);
void WM_menutype_idname_visit_for_search(const bContext *C,
PointerRNA *ptr,
PropertyRNA *prop,
const char *edit_text,
StringPropertySearchVisitFunc visit_fn,
void *visit_user_data);
void WM_menutype_idname_visit_for_search(
const bContext *C,
PointerRNA *ptr,
PropertyRNA *prop,
const char *edit_text,
blender::FunctionRef<void(StringPropertySearchVisitParams)> visit_fn);
/* `wm_panel_type.cc` */
@ -1247,12 +1250,12 @@ PanelType *WM_paneltype_find(const char *idname, bool quiet);
bool WM_paneltype_add(PanelType *pt);
void WM_paneltype_remove(PanelType *pt);
void WM_paneltype_idname_visit_for_search(const bContext *C,
PointerRNA *ptr,
PropertyRNA *prop,
const char *edit_text,
StringPropertySearchVisitFunc visit_fn,
void *visit_user_data);
void WM_paneltype_idname_visit_for_search(
const bContext *C,
PointerRNA *ptr,
PropertyRNA *prop,
const char *edit_text,
blender::FunctionRef<void(StringPropertySearchVisitParams)> visit_fn);
/* `wm_gesture_ops.cc` */

View File

@ -101,20 +101,20 @@ bool WM_menutype_poll(bContext *C, MenuType *mt)
return true;
}
void WM_menutype_idname_visit_for_search(const bContext * /*C*/,
PointerRNA * /*ptr*/,
PropertyRNA * /*prop*/,
const char * /*edit_text*/,
StringPropertySearchVisitFunc visit_fn,
void *visit_user_data)
void WM_menutype_idname_visit_for_search(
const bContext * /*C*/,
PointerRNA * /*ptr*/,
PropertyRNA * /*prop*/,
const char * /*edit_text*/,
blender::FunctionRef<void(StringPropertySearchVisitParams)> visit_fn)
{
GHashIterator gh_iter;
GHASH_ITER (gh_iter, menutypes_hash) {
MenuType *mt = static_cast<MenuType *>(BLI_ghashIterator_getValue(&gh_iter));
StringPropertySearchVisitParams visit_params = {nullptr};
StringPropertySearchVisitParams visit_params{};
visit_params.text = mt->idname;
visit_params.info = mt->label;
visit_fn(visit_user_data, &visit_params);
visit_fn(visit_params);
}
}

View File

@ -249,12 +249,12 @@ void WM_operatortype_last_properties_clear_all()
}
}
void WM_operatortype_idname_visit_for_search(const bContext * /*C*/,
PointerRNA * /*ptr*/,
PropertyRNA * /*prop*/,
const char * /*edit_text*/,
StringPropertySearchVisitFunc visit_fn,
void *visit_user_data)
void WM_operatortype_idname_visit_for_search(
const bContext * /*C*/,
PointerRNA * /*ptr*/,
PropertyRNA * /*prop*/,
const char * /*edit_text*/,
blender::FunctionRef<void(StringPropertySearchVisitParams)> visit_fn)
{
GHashIterator gh_iter;
GHASH_ITER (gh_iter, global_ops_hash) {
@ -263,10 +263,10 @@ void WM_operatortype_idname_visit_for_search(const bContext * /*C*/,
char idname_py[OP_MAX_TYPENAME];
WM_operator_py_idname(idname_py, ot->idname);
StringPropertySearchVisitParams visit_params = {nullptr};
StringPropertySearchVisitParams visit_params{};
visit_params.text = idname_py;
visit_params.info = ot->name;
visit_fn(visit_user_data, &visit_params);
visit_fn(visit_params);
}
}

View File

@ -68,20 +68,20 @@ void WM_paneltype_clear()
BLI_ghash_free(g_paneltypes_hash, nullptr, nullptr);
}
void WM_paneltype_idname_visit_for_search(const bContext * /*C*/,
PointerRNA * /*ptr*/,
PropertyRNA * /*prop*/,
const char * /*edit_text*/,
StringPropertySearchVisitFunc visit_fn,
void *visit_user_data)
void WM_paneltype_idname_visit_for_search(
const bContext * /*C*/,
PointerRNA * /*ptr*/,
PropertyRNA * /*prop*/,
const char * /*edit_text*/,
blender::FunctionRef<void(StringPropertySearchVisitParams)> visit_fn)
{
GHashIterator gh_iter;
GHASH_ITER (gh_iter, g_paneltypes_hash) {
PanelType *pt = static_cast<PanelType *>(BLI_ghashIterator_getValue(&gh_iter));
StringPropertySearchVisitParams visit_params = {nullptr};
StringPropertySearchVisitParams visit_params{};
visit_params.text = pt->idname;
visit_params.info = pt->label;
visit_fn(visit_user_data, &visit_params);
visit_fn(visit_params);
}
}