WIP: Brush assets project #106303

Draft
Julian Eisel wants to merge 358 commits from brush-assets-project into main

When changing the target branch, be careful to rebase the branch in your fork to match. See documentation.
61 changed files with 461 additions and 447 deletions
Showing only changes of commit ea56950b47 - 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

@ -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

@ -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);
}
}