Fix #105778: Prevent invalid links with link swap #105809
|
@ -153,6 +153,16 @@ static float3 output_estimate_emission(ShaderOutput *output, bool &is_constant)
|
|||
estimate *= node->get_float(strength_in->socket_type);
|
||||
}
|
||||
|
||||
/* Lower importance of emission nodes from automatic value/color to shader
|
||||
* conversion, as these are likely used for previewing and can be slow to
|
||||
* build a light tree for on dense meshes. */
|
||||
if (node->type == EmissionNode::get_node_type()) {
|
||||
EmissionNode *emission_node = static_cast<EmissionNode *>(node);
|
||||
if (emission_node->from_auto_conversion) {
|
||||
estimate *= 0.1f;
|
||||
}
|
||||
}
|
||||
|
||||
return estimate;
|
||||
}
|
||||
else if (node->type == LightFalloffNode::get_node_type() ||
|
||||
|
|
|
@ -260,6 +260,7 @@ void ShaderGraph::connect(ShaderOutput *from, ShaderInput *to)
|
|||
|
||||
if (to->type() == SocketType::CLOSURE) {
|
||||
EmissionNode *emission = create_node<EmissionNode>();
|
||||
emission->from_auto_conversion = true;
|
||||
emission->set_color(one_float3());
|
||||
emission->set_strength(1.0f);
|
||||
convert = add(emission);
|
||||
|
|
|
@ -723,6 +723,8 @@ class EmissionNode : public ShaderNode {
|
|||
NODE_SOCKET_API(float3, color)
|
||||
NODE_SOCKET_API(float, strength)
|
||||
NODE_SOCKET_API(float, surface_mix_weight)
|
||||
|
||||
bool from_auto_conversion = false;
|
||||
};
|
||||
|
||||
class BackgroundNode : public ShaderNode {
|
||||
|
|
|
@ -671,6 +671,7 @@ class ShaderImageTextureWrapper():
|
|||
tree.links.new(node_image.outputs["Alpha" if self.use_alpha else "Color"], self.socket_dst)
|
||||
if self.use_alpha:
|
||||
self.owner_shader.material.blend_method = 'BLEND'
|
||||
self.owner_shader.material.show_transparent_back = False
|
||||
|
||||
self._node_image = node_image
|
||||
return self._node_image
|
||||
|
|
|
@ -726,7 +726,7 @@ class USERPREF_PT_viewport_display(ViewportPanel, CenterAlignMixIn, Panel):
|
|||
|
||||
col.separator()
|
||||
|
||||
col.prop(view, "mini_axis_type", text="3D Viewport Axis")
|
||||
col.prop(view, "mini_axis_type", text="3D Viewport Axes")
|
||||
|
||||
if view.mini_axis_type == 'MINIMAL':
|
||||
col.prop(view, "mini_axis_size", text="Size")
|
||||
|
|
|
@ -25,6 +25,7 @@ class AssetIdentifier {
|
|||
AssetIdentifier(const AssetIdentifier &) = default;
|
||||
|
||||
std::string full_path() const;
|
||||
std::string full_library_path() const;
|
||||
};
|
||||
|
||||
} // namespace blender::asset_system
|
||||
|
|
|
@ -21,6 +21,8 @@ const char *AS_asset_representation_name_get(const AssetRepresentation *asset)
|
|||
ATTR_WARN_UNUSED_RESULT;
|
||||
AssetMetaData *AS_asset_representation_metadata_get(const AssetRepresentation *asset)
|
||||
ATTR_WARN_UNUSED_RESULT;
|
||||
struct ID *AS_asset_representation_local_id_get(const AssetRepresentation *asset)
|
||||
ATTR_WARN_UNUSED_RESULT;
|
||||
bool AS_asset_representation_is_local_id(const AssetRepresentation *asset) ATTR_WARN_UNUSED_RESULT;
|
||||
bool AS_asset_representation_is_never_link(const AssetRepresentation *asset)
|
||||
ATTR_WARN_UNUSED_RESULT;
|
||||
|
|
|
@ -82,6 +82,9 @@ class AssetRepresentation {
|
|||
* #get_import_method(). Also returns true if there is no predefined import method
|
||||
* (when #get_import_method() returns no value). */
|
||||
bool may_override_import_method() const;
|
||||
/** If this asset is stored inside this current file (#is_local_id() is true), this returns the
|
||||
* ID's pointer, otherwise null. */
|
||||
ID *local_id() const;
|
||||
/** Returns if this asset is stored inside this current file, and as such fully editable. */
|
||||
bool is_local_id() const;
|
||||
const AssetLibrary &owner_asset_library() const;
|
||||
|
@ -92,7 +95,11 @@ class AssetRepresentation {
|
|||
/* C-Handle */
|
||||
struct AssetRepresentation;
|
||||
|
||||
const std::string AS_asset_representation_full_path_get(const ::AssetRepresentation *asset);
|
||||
std::string AS_asset_representation_full_path_get(const ::AssetRepresentation *asset);
|
||||
/** Get the absolute path to the .blend file containing the given asset. String will be empty if
|
||||
* the asset could not be mapped to a valid .blend file path. Valid in this case also means that
|
||||
* the file needs to exist on disk. */
|
||||
std::string AS_asset_representation_full_library_path_get(const ::AssetRepresentation *asset);
|
||||
std::optional<eAssetImportMethod> AS_asset_representation_import_method_get(
|
||||
const ::AssetRepresentation *asset_handle);
|
||||
bool AS_asset_representation_may_override_import_method(const ::AssetRepresentation *asset_handle);
|
||||
|
|
|
@ -5,6 +5,7 @@ set(INC
|
|||
intern
|
||||
../blenkernel
|
||||
../blenlib
|
||||
../blenloader
|
||||
../makesdna
|
||||
../../../intern/clog
|
||||
../../../intern/guardedalloc
|
||||
|
|
|
@ -4,8 +4,11 @@
|
|||
* \ingroup asset_system
|
||||
*/
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "BLO_readfile.h"
|
||||
|
||||
#include "BLI_path_util.h"
|
||||
#include <iostream>
|
||||
|
||||
#include "AS_asset_identifier.hh"
|
||||
|
||||
|
@ -24,4 +27,16 @@ std::string AssetIdentifier::full_path() const
|
|||
return path;
|
||||
}
|
||||
|
||||
std::string AssetIdentifier::full_library_path() const
|
||||
{
|
||||
std::string asset_path = full_path();
|
||||
|
||||
char blend_path[1090 /*FILE_MAX_LIBEXTRA*/];
|
||||
if (!BLO_library_path_explode(asset_path.c_str(), blend_path, nullptr, nullptr)) {
|
||||
return {};
|
||||
}
|
||||
|
||||
return blend_path;
|
||||
}
|
||||
|
||||
} // namespace blender::asset_system
|
||||
|
|
|
@ -97,6 +97,11 @@ bool AssetRepresentation::may_override_import_method() const
|
|||
return owner_asset_library_->may_override_import_method_;
|
||||
}
|
||||
|
||||
ID *AssetRepresentation::local_id() const
|
||||
{
|
||||
return is_local_id_ ? local_asset_id_ : nullptr;
|
||||
}
|
||||
|
||||
bool AssetRepresentation::is_local_id() const
|
||||
{
|
||||
return is_local_id_;
|
||||
|
@ -111,7 +116,7 @@ const AssetLibrary &AssetRepresentation::owner_asset_library() const
|
|||
|
||||
using namespace blender;
|
||||
|
||||
const std::string AS_asset_representation_full_path_get(const AssetRepresentation *asset_handle)
|
||||
std::string AS_asset_representation_full_path_get(const AssetRepresentation *asset_handle)
|
||||
{
|
||||
const asset_system::AssetRepresentation *asset =
|
||||
reinterpret_cast<const asset_system::AssetRepresentation *>(asset_handle);
|
||||
|
@ -119,6 +124,13 @@ const std::string AS_asset_representation_full_path_get(const AssetRepresentatio
|
|||
return identifier.full_path();
|
||||
}
|
||||
|
||||
std::string AS_asset_representation_full_library_path_get(const AssetRepresentation *asset_handle)
|
||||
{
|
||||
const asset_system::AssetRepresentation *asset =
|
||||
reinterpret_cast<const asset_system::AssetRepresentation *>(asset_handle);
|
||||
return asset->get_identifier().full_library_path();
|
||||
}
|
||||
|
||||
std::optional<eAssetImportMethod> AS_asset_representation_import_method_get(
|
||||
const AssetRepresentation *asset_handle)
|
||||
{
|
||||
|
@ -152,6 +164,13 @@ AssetMetaData *AS_asset_representation_metadata_get(const AssetRepresentation *a
|
|||
return &asset->get_metadata();
|
||||
}
|
||||
|
||||
ID *AS_asset_representation_local_id_get(const AssetRepresentation *asset_handle)
|
||||
{
|
||||
const asset_system::AssetRepresentation *asset =
|
||||
reinterpret_cast<const asset_system::AssetRepresentation *>(asset_handle);
|
||||
return asset->local_id();
|
||||
}
|
||||
|
||||
bool AS_asset_representation_is_local_id(const AssetRepresentation *asset_handle)
|
||||
{
|
||||
const asset_system::AssetRepresentation *asset =
|
||||
|
|
|
@ -381,6 +381,8 @@ bool CTX_data_editable_gpencil_strokes(const bContext *C, ListBase *list);
|
|||
const struct AssetLibraryReference *CTX_wm_asset_library_ref(const bContext *C);
|
||||
struct AssetHandle CTX_wm_asset_handle(const bContext *C, bool *r_is_valid);
|
||||
|
||||
struct AssetRepresentation *CTX_wm_asset(const bContext *C);
|
||||
|
||||
bool CTX_wm_interface_locked(const bContext *C);
|
||||
|
||||
/**
|
||||
|
|
|
@ -1493,6 +1493,11 @@ AssetHandle CTX_wm_asset_handle(const bContext *C, bool *r_is_valid)
|
|||
return AssetHandle{nullptr};
|
||||
}
|
||||
|
||||
AssetRepresentation *CTX_wm_asset(const bContext *C)
|
||||
{
|
||||
return static_cast<AssetRepresentation *>(ctx_data_pointer_get(C, "asset"));
|
||||
}
|
||||
|
||||
Depsgraph *CTX_data_depsgraph_pointer(const bContext *C)
|
||||
{
|
||||
Main *bmain = CTX_data_main(C);
|
||||
|
|
|
@ -24,6 +24,7 @@ set(SRC
|
|||
intern/asset_catalog.cc
|
||||
intern/asset_filter.cc
|
||||
intern/asset_handle.cc
|
||||
intern/asset_import.cc
|
||||
intern/asset_indexer.cc
|
||||
intern/asset_library_reference.cc
|
||||
intern/asset_library_reference_enum.cc
|
||||
|
@ -37,6 +38,7 @@ set(SRC
|
|||
ED_asset_catalog.hh
|
||||
ED_asset_filter.h
|
||||
ED_asset_handle.h
|
||||
ED_asset_import.h
|
||||
ED_asset_indexer.h
|
||||
ED_asset_library.h
|
||||
ED_asset_list.h
|
||||
|
|
|
@ -21,6 +21,7 @@ extern "C" {
|
|||
|
||||
struct AssetHandle;
|
||||
|
||||
struct AssetRepresentation *ED_asset_handle_get_representation(const struct AssetHandle *asset);
|
||||
const char *ED_asset_handle_get_name(const struct AssetHandle *asset);
|
||||
struct AssetMetaData *ED_asset_handle_get_metadata(const struct AssetHandle *asset);
|
||||
struct ID *ED_asset_handle_get_local_id(const struct AssetHandle *asset);
|
||||
|
@ -45,11 +46,4 @@ void ED_asset_handle_get_full_library_path(
|
|||
std::optional<eAssetImportMethod> ED_asset_handle_get_import_method(
|
||||
const struct AssetHandle *asset);
|
||||
|
||||
namespace blender::ed::asset {
|
||||
|
||||
/** If the ID already exists in the database, return it, otherwise add it. */
|
||||
ID *get_local_id_from_asset_or_append_and_reuse(Main &bmain, AssetHandle asset);
|
||||
|
||||
} // namespace blender::ed::asset
|
||||
|
||||
#endif
|
||||
|
|
|
@ -0,0 +1,23 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
/** \file
|
||||
* \ingroup edasset
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "DNA_ID_enums.h"
|
||||
|
||||
struct AssetRepresentation;
|
||||
struct Main;
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct ID *ED_asset_get_local_id_from_asset_or_append_and_reuse(
|
||||
struct Main *bmain, const struct AssetRepresentation *asset_c_ptr, ID_Type idtype);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
|
@ -6,11 +6,12 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "DNA_asset_types.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct AssetHandle;
|
||||
struct AssetLibraryReference;
|
||||
struct ID;
|
||||
struct bContext;
|
||||
|
@ -49,6 +50,9 @@ void ED_assetlist_storage_id_remap(struct ID *id_old, struct ID *id_new);
|
|||
*/
|
||||
void ED_assetlist_storage_exit(void);
|
||||
|
||||
AssetHandle ED_assetlist_asset_get_by_index(const AssetLibraryReference *library_reference,
|
||||
int asset_index);
|
||||
|
||||
struct ImBuf *ED_assetlist_asset_image_get(const AssetHandle *asset_handle);
|
||||
|
||||
/**
|
||||
|
|
|
@ -30,4 +30,8 @@ blender::asset_system::AssetLibrary *ED_assetlist_library_get_once_available(
|
|||
|
||||
/* Can return false to stop iterating. */
|
||||
using AssetListIterFn = blender::FunctionRef<bool(AssetHandle)>;
|
||||
/**
|
||||
* \warning Never keep the asset handle passed to \a fn outside of \a fn's scope. While iterating,
|
||||
* the file data wrapped by the asset handle can be freed, since the file cache has a maximum size.
|
||||
*/
|
||||
void ED_assetlist_iterate(const AssetLibraryReference &library_reference, AssetListIterFn fn);
|
||||
|
|
|
@ -9,13 +9,16 @@
|
|||
#include "AS_asset_representation.h"
|
||||
#include "AS_asset_representation.hh"
|
||||
|
||||
#include "DNA_space_types.h"
|
||||
#include "BLI_string.h"
|
||||
|
||||
#include "BLO_readfile.h"
|
||||
#include "DNA_space_types.h"
|
||||
|
||||
#include "ED_asset_handle.h"
|
||||
|
||||
#include "WM_api.h"
|
||||
AssetRepresentation *ED_asset_handle_get_representation(const AssetHandle *asset)
|
||||
{
|
||||
return asset->file_data->asset;
|
||||
}
|
||||
|
||||
const char *ED_asset_handle_get_name(const AssetHandle *asset)
|
||||
{
|
||||
|
@ -53,36 +56,11 @@ void ED_asset_handle_get_full_library_path(const AssetHandle *asset_handle,
|
|||
{
|
||||
*r_full_lib_path = '\0';
|
||||
|
||||
std::string asset_path = AS_asset_representation_full_path_get(asset_handle->file_data->asset);
|
||||
if (asset_path.empty()) {
|
||||
std::string library_path = AS_asset_representation_full_library_path_get(
|
||||
asset_handle->file_data->asset);
|
||||
if (library_path.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
BLO_library_path_explode(asset_path.c_str(), r_full_lib_path, nullptr, nullptr);
|
||||
BLI_strncpy(r_full_lib_path, library_path.c_str(), FILE_MAX);
|
||||
}
|
||||
|
||||
namespace blender::ed::asset {
|
||||
|
||||
ID *get_local_id_from_asset_or_append_and_reuse(Main &bmain, const AssetHandle asset)
|
||||
{
|
||||
if (ID *local_id = ED_asset_handle_get_local_id(&asset)) {
|
||||
return local_id;
|
||||
}
|
||||
|
||||
char blend_path[FILE_MAX_LIBEXTRA];
|
||||
ED_asset_handle_get_full_library_path(&asset, blend_path);
|
||||
const char *id_name = ED_asset_handle_get_name(&asset);
|
||||
|
||||
return WM_file_append_datablock(&bmain,
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr,
|
||||
blend_path,
|
||||
ED_asset_handle_get_id_type(&asset),
|
||||
id_name,
|
||||
BLO_LIBLINK_APPEND_RECURSIVE |
|
||||
BLO_LIBLINK_APPEND_ASSET_DATA_CLEAR |
|
||||
BLO_LIBLINK_APPEND_LOCAL_ID_REUSE);
|
||||
}
|
||||
|
||||
} // namespace blender::ed::asset
|
||||
|
|
|
@ -0,0 +1,44 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
/** \file
|
||||
* \ingroup edasset
|
||||
*/
|
||||
|
||||
#include "AS_asset_representation.h"
|
||||
#include "AS_asset_representation.hh"
|
||||
|
||||
#include "BLO_readfile.h"
|
||||
|
||||
#include "WM_api.h"
|
||||
|
||||
#include "ED_asset_import.h"
|
||||
|
||||
using namespace blender;
|
||||
|
||||
ID *ED_asset_get_local_id_from_asset_or_append_and_reuse(Main *bmain,
|
||||
const AssetRepresentation *asset_c_ptr,
|
||||
ID_Type idtype)
|
||||
{
|
||||
const asset_system::AssetRepresentation &asset =
|
||||
*reinterpret_cast<const asset_system::AssetRepresentation *>(asset_c_ptr);
|
||||
|
||||
if (ID *local_id = asset.local_id()) {
|
||||
return local_id;
|
||||
}
|
||||
|
||||
std::string blend_path = asset.get_identifier().full_library_path();
|
||||
if (blend_path.empty()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return WM_file_append_datablock(bmain,
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr,
|
||||
blend_path.c_str(),
|
||||
idtype,
|
||||
asset.get_name().c_str(),
|
||||
BLO_LIBLINK_APPEND_RECURSIVE |
|
||||
BLO_LIBLINK_APPEND_ASSET_DATA_CLEAR |
|
||||
BLO_LIBLINK_APPEND_LOCAL_ID_REUSE);
|
||||
}
|
|
@ -112,6 +112,8 @@ class AssetList : NonCopyable {
|
|||
void ensurePreviewsJob(const bContext *C);
|
||||
void clear(bContext *C);
|
||||
|
||||
AssetHandle asset_get_by_index(int index) const;
|
||||
|
||||
bool needsRefetch() const;
|
||||
bool isLoaded() const;
|
||||
asset_system::AssetLibrary *asset_library() const;
|
||||
|
@ -139,7 +141,7 @@ void AssetList::setup()
|
|||
filelist_setlibrary(files, &library_ref_);
|
||||
filelist_setfilter_options(
|
||||
files,
|
||||
false,
|
||||
true,
|
||||
true,
|
||||
true, /* Just always hide parent, prefer to not add an extra user option for this. */
|
||||
FILE_TYPE_BLENDERLIB,
|
||||
|
@ -246,6 +248,11 @@ void AssetList::clear(bContext *C)
|
|||
WM_main_add_notifier(NC_ASSET | ND_ASSET_LIST, nullptr);
|
||||
}
|
||||
|
||||
AssetHandle AssetList::asset_get_by_index(int index) const
|
||||
{
|
||||
return {filelist_file(filelist_, index)};
|
||||
}
|
||||
|
||||
/**
|
||||
* \return True if the asset-list needs a UI redraw.
|
||||
*/
|
||||
|
@ -472,6 +479,13 @@ asset_system::AssetLibrary *ED_assetlist_library_get_once_available(
|
|||
return list->asset_library();
|
||||
}
|
||||
|
||||
AssetHandle ED_assetlist_asset_get_by_index(const AssetLibraryReference *library_reference,
|
||||
int asset_index)
|
||||
{
|
||||
const AssetList *list = AssetListStorage::lookup_list(*library_reference);
|
||||
return list->asset_get_by_index(asset_index);
|
||||
}
|
||||
|
||||
ImBuf *ED_assetlist_asset_image_get(const AssetHandle *asset_handle)
|
||||
{
|
||||
ImBuf *imbuf = filelist_file_getimage(asset_handle->file_data);
|
||||
|
|
|
@ -8,9 +8,15 @@
|
|||
*/
|
||||
|
||||
#include <new>
|
||||
#include <string>
|
||||
|
||||
#include "AS_asset_representation.h"
|
||||
#include "AS_asset_representation.hh"
|
||||
|
||||
#include "DNA_space_types.h"
|
||||
|
||||
#include "ED_asset.h"
|
||||
|
||||
#include "BKE_report.h"
|
||||
|
||||
#include "BLI_utility_mixins.hh"
|
||||
|
@ -19,17 +25,16 @@
|
|||
|
||||
#include "MEM_guardedalloc.h"
|
||||
|
||||
#include "ED_asset_handle.h"
|
||||
#include "ED_asset_temp_id_consumer.h"
|
||||
|
||||
using namespace blender;
|
||||
|
||||
class AssetTemporaryIDConsumer : NonCopyable, NonMovable {
|
||||
const AssetHandle &handle_;
|
||||
const AssetRepresentation *asset_;
|
||||
TempLibraryContext *temp_lib_context_ = nullptr;
|
||||
|
||||
public:
|
||||
AssetTemporaryIDConsumer(const AssetHandle &handle) : handle_(handle)
|
||||
AssetTemporaryIDConsumer(const AssetRepresentation *asset) : asset_(asset)
|
||||
{
|
||||
}
|
||||
~AssetTemporaryIDConsumer()
|
||||
|
@ -41,20 +46,20 @@ class AssetTemporaryIDConsumer : NonCopyable, NonMovable {
|
|||
|
||||
ID *get_local_id()
|
||||
{
|
||||
return ED_asset_handle_get_local_id(&handle_);
|
||||
return AS_asset_representation_local_id_get(asset_);
|
||||
}
|
||||
|
||||
ID *import_id(ID_Type id_type, Main &bmain, ReportList &reports)
|
||||
{
|
||||
const char *asset_name = ED_asset_handle_get_name(&handle_);
|
||||
char blend_file_path[FILE_MAX_LIBEXTRA];
|
||||
ED_asset_handle_get_full_library_path(&handle_, blend_file_path);
|
||||
const char *asset_name = AS_asset_representation_name_get(asset_);
|
||||
std::string blend_file_path = AS_asset_representation_full_library_path_get(asset_);
|
||||
|
||||
temp_lib_context_ = BLO_library_temp_load_id(
|
||||
&bmain, blend_file_path, id_type, asset_name, &reports);
|
||||
&bmain, blend_file_path.c_str(), id_type, asset_name, &reports);
|
||||
|
||||
if (temp_lib_context_ == nullptr || temp_lib_context_->temp_id == nullptr) {
|
||||
BKE_reportf(&reports, RPT_ERROR, "Unable to load %s from %s", asset_name, blend_file_path);
|
||||
BKE_reportf(
|
||||
&reports, RPT_ERROR, "Unable to load %s from %s", asset_name, blend_file_path.c_str());
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
@ -70,7 +75,7 @@ AssetTempIDConsumer *ED_asset_temp_id_consumer_create(const AssetHandle *handle)
|
|||
}
|
||||
BLI_assert(handle->file_data->asset != nullptr);
|
||||
return reinterpret_cast<AssetTempIDConsumer *>(
|
||||
MEM_new<AssetTemporaryIDConsumer>(__func__, *handle));
|
||||
MEM_new<AssetTemporaryIDConsumer>(__func__, ED_asset_handle_get_representation(handle)));
|
||||
}
|
||||
|
||||
void ED_asset_temp_id_consumer_free(AssetTempIDConsumer **consumer)
|
||||
|
|
|
@ -25,6 +25,7 @@ void ED_operatortypes_asset(void);
|
|||
#include "../asset/ED_asset_catalog.h"
|
||||
#include "../asset/ED_asset_filter.h"
|
||||
#include "../asset/ED_asset_handle.h"
|
||||
#include "../asset/ED_asset_import.h"
|
||||
#include "../asset/ED_asset_library.h"
|
||||
#include "../asset/ED_asset_list.h"
|
||||
#include "../asset/ED_asset_mark_clear.h"
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
|
||||
#include <memory>
|
||||
|
||||
#include "BLI_function_ref.hh"
|
||||
#include "BLI_string_ref.hh"
|
||||
#include "BLI_vector.hh"
|
||||
|
||||
|
@ -17,8 +18,10 @@ namespace blender::nodes::geo_eval_log {
|
|||
struct GeometryAttributeInfo;
|
||||
}
|
||||
|
||||
struct PointerRNA;
|
||||
struct StructRNA;
|
||||
struct uiBlock;
|
||||
struct uiList;
|
||||
struct uiSearchItems;
|
||||
|
||||
namespace blender::ui {
|
||||
|
@ -53,6 +56,60 @@ void attribute_search_add_items(StringRefNull str,
|
|||
|
||||
} // namespace blender::ui
|
||||
|
||||
enum eUIListFilterResult {
|
||||
/** Never show this item, even when filter results are inverted (#UILST_FLT_EXCLUDE). */
|
||||
UI_LIST_ITEM_NEVER_SHOW,
|
||||
/** Show this item, unless filter results are inverted (#UILST_FLT_EXCLUDE). */
|
||||
UI_LIST_ITEM_FILTER_MATCHES,
|
||||
/** Don't show this item, unless filter results are inverted (#UILST_FLT_EXCLUDE). */
|
||||
UI_LIST_ITEM_FILTER_MISMATCHES,
|
||||
};
|
||||
|
||||
/**
|
||||
* Function object for UI list item filtering that does the default name comparison with '*'
|
||||
* wildcards. Create an instance of this once and pass it to #UI_list_filter_and_sort_items(), do
|
||||
* NOT create an instance for every item, this would be costly.
|
||||
*/
|
||||
class uiListNameFilter {
|
||||
/* Storage with an inline buffer for smaller strings (small buffer optimization). */
|
||||
struct {
|
||||
char filter_buff[32];
|
||||
char *filter_dyn = nullptr;
|
||||
} storage_;
|
||||
char *filter_ = nullptr;
|
||||
|
||||
public:
|
||||
uiListNameFilter(uiList &list);
|
||||
~uiListNameFilter();
|
||||
|
||||
eUIListFilterResult operator()(const PointerRNA &itemptr,
|
||||
blender::StringRefNull name,
|
||||
int index);
|
||||
};
|
||||
|
||||
using uiListItemFilterFn = blender::FunctionRef<eUIListFilterResult(
|
||||
const PointerRNA &itemptr, blender::StringRefNull name, int index)>;
|
||||
using uiListItemGetNameFn =
|
||||
blender::FunctionRef<std::string(const PointerRNA &itemptr, int index)>;
|
||||
|
||||
/**
|
||||
* Filter list items using \a item_filter_fn and sort the result. This respects the normal UI list
|
||||
* filter settings like alphabetical sorting (#UILST_FLT_SORT_ALPHA), and result inverting
|
||||
* (#UILST_FLT_EXCLUDE).
|
||||
*
|
||||
* Call this from a #uiListType::filter_items callback with any #item_filter_fn. #uiListNameFilter
|
||||
* can be used to apply the default name based filtering.
|
||||
*
|
||||
* \param get_name_fn: In some cases the name cannot be retrieved via RNA. This function can be set
|
||||
* to provide the name still.
|
||||
*/
|
||||
void UI_list_filter_and_sort_items(uiList *ui_list,
|
||||
const struct bContext *C,
|
||||
uiListItemFilterFn item_filter_fn,
|
||||
PointerRNA *dataptr,
|
||||
const char *propname,
|
||||
uiListItemGetNameFn get_name_fn = nullptr);
|
||||
|
||||
/**
|
||||
* Override this for all available view types.
|
||||
*/
|
||||
|
|
|
@ -7934,6 +7934,16 @@ static int ui_do_button(bContext *C, uiBlock *block, uiBut *but, const wmEvent *
|
|||
return WM_UI_HANDLER_CONTINUE;
|
||||
}
|
||||
|
||||
#ifdef WITH_INPUT_NDOF
|
||||
/* 2D view navigation conflicts with using NDOF to adjust colors,
|
||||
* especially in the node-editor, see: #105224. */
|
||||
if (event->type == NDOF_MOTION) {
|
||||
if (data->region->type->keymapflag & ED_KEYMAP_VIEW2D) {
|
||||
return WM_UI_HANDLER_CONTINUE;
|
||||
}
|
||||
}
|
||||
#endif /* WITH_INPUT_NDOF */
|
||||
|
||||
if (do_paste) {
|
||||
ui_but_paste(C, but, data, event->modifier & KM_ALT);
|
||||
return WM_UI_HANDLER_BREAK;
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
#include "RNA_prototypes.h"
|
||||
|
||||
#include "UI_interface.h"
|
||||
#include "UI_interface.hh"
|
||||
|
||||
#include "WM_api.h"
|
||||
#include "WM_types.h"
|
||||
|
@ -32,6 +33,7 @@
|
|||
|
||||
struct AssetViewListData {
|
||||
AssetLibraryReference asset_library_ref;
|
||||
AssetFilterSettings filter_settings;
|
||||
bScreen *screen;
|
||||
bool show_names;
|
||||
};
|
||||
|
@ -45,8 +47,6 @@ static void asset_view_item_but_drag_set(uiBut *but, AssetHandle *asset_handle)
|
|||
}
|
||||
|
||||
char blend_path[FILE_MAX_LIBEXTRA];
|
||||
/* Context can be null here, it's only needed for a File Browser specific hack that should go
|
||||
* away before too long. */
|
||||
ED_asset_handle_get_full_library_path(asset_handle, blend_path);
|
||||
|
||||
const eAssetImportMethod import_method =
|
||||
|
@ -68,19 +68,23 @@ static void asset_view_draw_item(uiList *ui_list,
|
|||
const bContext * /*C*/,
|
||||
uiLayout *layout,
|
||||
PointerRNA * /*dataptr*/,
|
||||
PointerRNA *itemptr,
|
||||
PointerRNA * /*itemptr*/,
|
||||
int /*icon*/,
|
||||
PointerRNA * /*active_dataptr*/,
|
||||
const char * /*active_propname*/,
|
||||
int /*index*/,
|
||||
int index,
|
||||
int /*flt_flag*/)
|
||||
{
|
||||
AssetViewListData *list_data = (AssetViewListData *)ui_list->dyn_data->customdata;
|
||||
|
||||
BLI_assert(RNA_struct_is_a(itemptr->type, &RNA_AssetHandle));
|
||||
AssetHandle *asset_handle = (AssetHandle *)itemptr->data;
|
||||
AssetHandle asset_handle = ED_assetlist_asset_get_by_index(&list_data->asset_library_ref, index);
|
||||
|
||||
uiLayoutSetContextPointer(layout, "asset_handle", itemptr);
|
||||
PointerRNA file_ptr;
|
||||
RNA_pointer_create(&list_data->screen->id,
|
||||
&RNA_FileSelectEntry,
|
||||
const_cast<FileDirEntry *>(asset_handle.file_data),
|
||||
&file_ptr);
|
||||
uiLayoutSetContextPointer(layout, "active_file", &file_ptr);
|
||||
|
||||
uiBlock *block = uiLayoutGetBlock(layout);
|
||||
const bool show_names = list_data->show_names;
|
||||
|
@ -90,8 +94,8 @@ static void asset_view_draw_item(uiList *ui_list,
|
|||
uiBut *but = uiDefIconTextBut(block,
|
||||
UI_BTYPE_PREVIEW_TILE,
|
||||
0,
|
||||
ED_asset_handle_get_preview_icon_id(asset_handle),
|
||||
show_names ? ED_asset_handle_get_name(asset_handle) : "",
|
||||
ED_asset_handle_get_preview_icon_id(&asset_handle),
|
||||
show_names ? ED_asset_handle_get_name(&asset_handle) : "",
|
||||
0,
|
||||
0,
|
||||
size_x,
|
||||
|
@ -103,14 +107,43 @@ static void asset_view_draw_item(uiList *ui_list,
|
|||
0,
|
||||
"");
|
||||
ui_def_but_icon(but,
|
||||
ED_asset_handle_get_preview_icon_id(asset_handle),
|
||||
ED_asset_handle_get_preview_icon_id(&asset_handle),
|
||||
/* NOLINTNEXTLINE: bugprone-suspicious-enum-usage */
|
||||
UI_HAS_ICON | UI_BUT_ICON_PREVIEW);
|
||||
if (!ui_list->dyn_data->custom_drag_optype) {
|
||||
asset_view_item_but_drag_set(but, asset_handle);
|
||||
asset_view_item_but_drag_set(but, &asset_handle);
|
||||
}
|
||||
}
|
||||
|
||||
static void asset_view_filter_items(uiList *ui_list,
|
||||
const bContext *C,
|
||||
PointerRNA *dataptr,
|
||||
const char *propname)
|
||||
{
|
||||
AssetViewListData *list_data = (AssetViewListData *)ui_list->dyn_data->customdata;
|
||||
AssetFilterSettings &filter_settings = list_data->filter_settings;
|
||||
|
||||
uiListNameFilter name_filter(*ui_list);
|
||||
|
||||
UI_list_filter_and_sort_items(
|
||||
ui_list,
|
||||
C,
|
||||
[&name_filter, list_data, &filter_settings](
|
||||
const PointerRNA &itemptr, blender::StringRefNull name, int index) {
|
||||
AssetHandle asset = ED_assetlist_asset_get_by_index(&list_data->asset_library_ref, index);
|
||||
if (!ED_asset_filter_matches_asset(&filter_settings, &asset)) {
|
||||
return UI_LIST_ITEM_NEVER_SHOW;
|
||||
}
|
||||
return name_filter(itemptr, name, index);
|
||||
},
|
||||
dataptr,
|
||||
propname,
|
||||
[list_data](const PointerRNA & /*itemptr*/, int index) -> std::string {
|
||||
AssetHandle asset = ED_assetlist_asset_get_by_index(&list_data->asset_library_ref, index);
|
||||
return ED_asset_handle_get_name(&asset);
|
||||
});
|
||||
}
|
||||
|
||||
static void asset_view_listener(uiList *ui_list, wmRegionListenerParams *params)
|
||||
{
|
||||
AssetViewListData *list_data = (AssetViewListData *)ui_list->dyn_data->customdata;
|
||||
|
@ -136,14 +169,13 @@ uiListType *UI_UL_asset_view()
|
|||
|
||||
BLI_strncpy(list_type->idname, "UI_UL_asset_view", sizeof(list_type->idname));
|
||||
list_type->draw_item = asset_view_draw_item;
|
||||
list_type->filter_items = asset_view_filter_items;
|
||||
list_type->listener = asset_view_listener;
|
||||
|
||||
return list_type;
|
||||
}
|
||||
|
||||
static void asset_view_template_refresh_asset_collection(
|
||||
const AssetLibraryReference &asset_library_ref,
|
||||
const AssetFilterSettings &filter_settings,
|
||||
static void populate_asset_collection(const AssetLibraryReference &asset_library_ref,
|
||||
PointerRNA &assets_dataptr,
|
||||
const char *assets_propname)
|
||||
{
|
||||
|
@ -164,17 +196,15 @@ static void asset_view_template_refresh_asset_collection(
|
|||
|
||||
RNA_property_collection_clear(&assets_dataptr, assets_prop);
|
||||
|
||||
ED_assetlist_iterate(asset_library_ref, [&](AssetHandle asset) {
|
||||
if (!ED_asset_filter_matches_asset(&filter_settings, &asset)) {
|
||||
/* Don't do anything else, but return true to continue iterating. */
|
||||
return true;
|
||||
}
|
||||
ED_assetlist_iterate(asset_library_ref, [&](AssetHandle /*asset*/) {
|
||||
/* XXX creating a dummy #RNA_AssetHandle collection item. It's #file_data will be null. This is
|
||||
* because the #FileDirEntry may be freed while iterating, there's a cache for them with a
|
||||
* maximum size. Further code will query as needed it using the collection index. */
|
||||
|
||||
PointerRNA itemptr, fileptr;
|
||||
RNA_property_collection_add(&assets_dataptr, assets_prop, &itemptr);
|
||||
|
||||
RNA_pointer_create(
|
||||
nullptr, &RNA_FileSelectEntry, const_cast<FileDirEntry *>(asset.file_data), &fileptr);
|
||||
RNA_pointer_create(nullptr, &RNA_FileSelectEntry, nullptr, &fileptr);
|
||||
RNA_pointer_set(&itemptr, "file_data", fileptr);
|
||||
|
||||
return true;
|
||||
|
@ -221,12 +251,12 @@ void uiTemplateAssetView(uiLayout *layout,
|
|||
ED_assetlist_ensure_previews_job(&asset_library_ref, C);
|
||||
const int tot_items = ED_assetlist_size(&asset_library_ref);
|
||||
|
||||
asset_view_template_refresh_asset_collection(
|
||||
asset_library_ref, *filter_settings, *assets_dataptr, assets_propname);
|
||||
populate_asset_collection(asset_library_ref, *assets_dataptr, assets_propname);
|
||||
|
||||
AssetViewListData *list_data = (AssetViewListData *)MEM_mallocN(sizeof(*list_data),
|
||||
"AssetViewListData");
|
||||
list_data->asset_library_ref = asset_library_ref;
|
||||
list_data->filter_settings = *filter_settings;
|
||||
list_data->screen = CTX_wm_screen(C);
|
||||
list_data->show_names = (display_flags & UI_TEMPLATE_ASSET_DRAW_NO_NAMES) == 0;
|
||||
|
||||
|
|
|
@ -8,9 +8,11 @@
|
|||
#include <cstring>
|
||||
|
||||
#include "BLI_fnmatch.h"
|
||||
#include "BLI_function_ref.hh"
|
||||
#include "BLI_listbase.h"
|
||||
#include "BLI_math_base.h"
|
||||
#include "BLI_string.h"
|
||||
#include "BLI_string_ref.hh"
|
||||
#include "BLI_utildefines.h"
|
||||
|
||||
#include "BKE_screen.h"
|
||||
|
@ -26,12 +28,15 @@
|
|||
#include "RNA_prototypes.h"
|
||||
|
||||
#include "UI_interface.h"
|
||||
#include "UI_interface.hh"
|
||||
#include "UI_view2d.h"
|
||||
|
||||
#include "WM_api.h"
|
||||
|
||||
#include "interface_intern.hh"
|
||||
|
||||
using namespace blender;
|
||||
|
||||
/**
|
||||
* The validated data that was passed to #uiTemplateList (typically through Python).
|
||||
* Populated through #ui_template_list_data_retrieve().
|
||||
|
@ -148,6 +153,45 @@ static void uilist_draw_filter_default(struct uiList *ui_list,
|
|||
}
|
||||
}
|
||||
|
||||
uiListNameFilter::uiListNameFilter(uiList &list)
|
||||
{
|
||||
const char *filter_raw = list.filter_byname;
|
||||
|
||||
if (filter_raw[0]) {
|
||||
const size_t slen = strlen(filter_raw);
|
||||
|
||||
/* Implicitly add heading/trailing wildcards if needed. */
|
||||
if (slen + 3 <= sizeof(storage_.filter_buff)) {
|
||||
filter_ = storage_.filter_buff;
|
||||
}
|
||||
else {
|
||||
filter_ = storage_.filter_dyn = static_cast<char *>(
|
||||
MEM_mallocN((slen + 3) * sizeof(char), "filter_dyn"));
|
||||
}
|
||||
BLI_strncpy_ensure_pad(filter_, filter_raw, '*', slen + 3);
|
||||
}
|
||||
}
|
||||
|
||||
uiListNameFilter::~uiListNameFilter()
|
||||
{
|
||||
MEM_SAFE_FREE(storage_.filter_dyn);
|
||||
}
|
||||
|
||||
eUIListFilterResult uiListNameFilter::operator()(const PointerRNA & /* itemptr */,
|
||||
StringRefNull name,
|
||||
int /* index */)
|
||||
{
|
||||
if (!filter_) {
|
||||
return UI_LIST_ITEM_FILTER_MATCHES;
|
||||
}
|
||||
|
||||
/* Case-insensitive! */
|
||||
if (fnmatch(filter_, name.c_str(), FNM_CASEFOLD) == 0) {
|
||||
return UI_LIST_ITEM_FILTER_MATCHES;
|
||||
}
|
||||
return UI_LIST_ITEM_FILTER_MISMATCHES;
|
||||
}
|
||||
|
||||
struct StringCmp {
|
||||
char name[MAX_IDPROP_NAME];
|
||||
int org_idx;
|
||||
|
@ -159,16 +203,16 @@ static int cmpstringp(const void *p1, const void *p2)
|
|||
return BLI_strcasecmp(((StringCmp *)p1)->name, ((StringCmp *)p2)->name);
|
||||
}
|
||||
|
||||
static void uilist_filter_items_default(struct uiList *ui_list,
|
||||
const struct bContext * /*C*/,
|
||||
struct PointerRNA *dataptr,
|
||||
const char *propname)
|
||||
void UI_list_filter_and_sort_items(uiList *ui_list,
|
||||
const bContext * /*C*/,
|
||||
uiListItemFilterFn item_filter_fn,
|
||||
PointerRNA *dataptr,
|
||||
const char *propname,
|
||||
uiListItemGetNameFn get_name_fn)
|
||||
{
|
||||
uiListDyn *dyn_data = ui_list->dyn_data;
|
||||
PropertyRNA *prop = RNA_struct_find_property(dataptr, propname);
|
||||
|
||||
const char *filter_raw = ui_list->filter_byname;
|
||||
char *filter = (char *)filter_raw, filter_buff[32], *filter_dyn = nullptr;
|
||||
const bool filter_exclude = (ui_list->filter_flag & UILST_FLT_EXCLUDE) != 0;
|
||||
const bool order_by_name = (ui_list->filter_sort_flag & UILST_FLT_SORT_MASK) ==
|
||||
UILST_FLT_SORT_ALPHA;
|
||||
|
@ -176,41 +220,26 @@ static void uilist_filter_items_default(struct uiList *ui_list,
|
|||
|
||||
dyn_data->items_shown = dyn_data->items_len = len;
|
||||
|
||||
if (len && (order_by_name || filter_raw[0])) {
|
||||
if (len && (order_by_name || item_filter_fn)) {
|
||||
StringCmp *names = nullptr;
|
||||
int order_idx = 0, i = 0;
|
||||
|
||||
if (order_by_name) {
|
||||
names = static_cast<StringCmp *>(MEM_callocN(sizeof(StringCmp) * len, "StringCmp"));
|
||||
}
|
||||
if (filter_raw[0]) {
|
||||
const size_t slen = strlen(filter_raw);
|
||||
|
||||
if (item_filter_fn) {
|
||||
dyn_data->items_filter_flags = static_cast<int *>(
|
||||
MEM_callocN(sizeof(int) * len, "items_filter_flags"));
|
||||
dyn_data->items_shown = 0;
|
||||
|
||||
/* Implicitly add heading/trailing wildcards if needed. */
|
||||
if (slen + 3 <= sizeof(filter_buff)) {
|
||||
filter = filter_buff;
|
||||
}
|
||||
else {
|
||||
filter = filter_dyn = static_cast<char *>(
|
||||
MEM_mallocN((slen + 3) * sizeof(char), "filter_dyn"));
|
||||
}
|
||||
BLI_strncpy_ensure_pad(filter, filter_raw, '*', slen + 3);
|
||||
}
|
||||
|
||||
RNA_PROP_BEGIN (dataptr, itemptr, prop) {
|
||||
bool do_order = false;
|
||||
|
||||
char *namebuf;
|
||||
if (RNA_struct_is_a(itemptr.type, &RNA_AssetHandle)) {
|
||||
/* XXX The AssetHandle design is hacky and meant to be temporary. It can't have a proper
|
||||
* name property, so for now this hardcoded exception is needed. */
|
||||
AssetHandle *asset_handle = (AssetHandle *)itemptr.data;
|
||||
const char *asset_name = ED_asset_handle_get_name(asset_handle);
|
||||
namebuf = BLI_strdup(asset_name);
|
||||
if (get_name_fn) {
|
||||
namebuf = BLI_strdup(get_name_fn(itemptr, i).c_str());
|
||||
}
|
||||
else {
|
||||
namebuf = RNA_struct_name_get_alloc(&itemptr, nullptr, 0, nullptr);
|
||||
|
@ -218,9 +247,13 @@ static void uilist_filter_items_default(struct uiList *ui_list,
|
|||
|
||||
const char *name = namebuf ? namebuf : "";
|
||||
|
||||
if (filter[0]) {
|
||||
/* Case-insensitive! */
|
||||
if (fnmatch(filter, name, FNM_CASEFOLD) == 0) {
|
||||
if (item_filter_fn) {
|
||||
const eUIListFilterResult filter_result = item_filter_fn(itemptr, name, i);
|
||||
|
||||
if (filter_result == UI_LIST_ITEM_NEVER_SHOW) {
|
||||
/* Pass. */
|
||||
}
|
||||
else if (filter_result == UI_LIST_ITEM_FILTER_MATCHES) {
|
||||
dyn_data->items_filter_flags[i] = UILST_FLT_ITEM;
|
||||
if (!filter_exclude) {
|
||||
dyn_data->items_shown++;
|
||||
|
@ -266,15 +299,30 @@ static void uilist_filter_items_default(struct uiList *ui_list,
|
|||
}
|
||||
}
|
||||
|
||||
if (filter_dyn) {
|
||||
MEM_freeN(filter_dyn);
|
||||
}
|
||||
if (names) {
|
||||
MEM_freeN(names);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Default UI List filtering: Filter by name.
|
||||
*/
|
||||
static void uilist_filter_items_default(struct uiList *ui_list,
|
||||
const struct bContext *C,
|
||||
struct PointerRNA *dataptr,
|
||||
const char *propname)
|
||||
{
|
||||
if (ui_list->filter_byname[0]) {
|
||||
uiListNameFilter name_filter(*ui_list);
|
||||
UI_list_filter_and_sort_items(ui_list, C, name_filter, dataptr, propname);
|
||||
}
|
||||
/* Optimization: Skip filtering entirely when there is no filter string set. */
|
||||
else {
|
||||
UI_list_filter_and_sort_items(ui_list, C, nullptr, dataptr, propname);
|
||||
}
|
||||
}
|
||||
|
||||
static void uilist_free_dyn_data(uiList *ui_list)
|
||||
{
|
||||
uiListDyn *dyn_data = ui_list->dyn_data;
|
||||
|
|
|
@ -102,17 +102,16 @@ static float view2d_major_step_x__time(const View2D *v2d, const Scene *scene)
|
|||
for (int step = 1; step < fps; step *= 2) {
|
||||
possible_distances.append(step);
|
||||
}
|
||||
possible_distances.append(fps);
|
||||
possible_distances.append(2 * fps);
|
||||
possible_distances.append(5 * fps);
|
||||
possible_distances.append(10 * fps);
|
||||
possible_distances.append(30 * fps);
|
||||
possible_distances.append(60 * fps);
|
||||
possible_distances.append(2 * 60 * fps);
|
||||
possible_distances.append(5 * 60 * fps);
|
||||
possible_distances.append(10 * 60 * fps);
|
||||
possible_distances.append(30 * 60 * fps);
|
||||
possible_distances.append(60 * 60 * fps);
|
||||
|
||||
for (int i = 0; i <= 5; i++) {
|
||||
uint fac = pow(60, i);
|
||||
possible_distances.append(fac * fps);
|
||||
possible_distances.append(fac * 2 * fps);
|
||||
possible_distances.append(fac * 5 * fps);
|
||||
possible_distances.append(fac * 10 * fps);
|
||||
possible_distances.append(fac * 30 * fps);
|
||||
possible_distances.append(fac * 60 * fps);
|
||||
}
|
||||
|
||||
float distance = select_major_distance(possible_distances.data(),
|
||||
possible_distances.size(),
|
||||
|
|
|
@ -1732,7 +1732,7 @@ void MASK_OT_hide_view_clear(wmOperatorType *ot)
|
|||
|
||||
/* identifiers */
|
||||
ot->name = "Clear Restrict View";
|
||||
ot->description = "Reveal the layer by setting the hide flag";
|
||||
ot->description = "Reveal temporarily hidden mask layers";
|
||||
ot->idname = "MASK_OT_hide_view_clear";
|
||||
|
||||
/* api callbacks */
|
||||
|
@ -1792,7 +1792,7 @@ void MASK_OT_hide_view_set(wmOperatorType *ot)
|
|||
{
|
||||
/* identifiers */
|
||||
ot->name = "Set Restrict View";
|
||||
ot->description = "Hide the layer by setting the hide flag";
|
||||
ot->description = "Temporarily hide mask layers";
|
||||
ot->idname = "MASK_OT_hide_view_set";
|
||||
|
||||
/* api callbacks */
|
||||
|
|
|
@ -147,6 +147,18 @@ void immDrawPixelsTexTiled_scaling_clipping(IMMDrawPixelsTexState *state,
|
|||
const float color[4])
|
||||
{
|
||||
int subpart_x, subpart_y, tex_w = 256, tex_h = 256;
|
||||
#ifdef __APPLE__
|
||||
if (GPU_backend_get_type() == GPU_BACKEND_METAL) {
|
||||
/* NOTE(Metal): The Metal backend will keep all temporary texture memory within a command
|
||||
* submission in-flight, so using a partial tile size does not provide any tangible memory
|
||||
* reduction, but does incur additional API overhead and significant cache inefficiency on AMD
|
||||
* platforms.
|
||||
* The Metal API also provides smart resource paging such that the application can
|
||||
* still efficiently swap memory, even if system is low in physical memory. */
|
||||
tex_w = img_w;
|
||||
tex_h = img_h;
|
||||
}
|
||||
#endif
|
||||
int seamless, offset_x, offset_y, nsubparts_x, nsubparts_y;
|
||||
int components;
|
||||
const bool use_clipping = ((clip_min_x < clip_max_x) && (clip_min_y < clip_max_y));
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
#include "AS_asset_catalog.hh"
|
||||
#include "AS_asset_catalog_tree.hh"
|
||||
#include "AS_asset_library.hh"
|
||||
#include "AS_asset_representation.h"
|
||||
|
||||
#include "BLI_multi_value_map.hh"
|
||||
|
||||
|
@ -46,7 +47,7 @@ static void node_add_menu_assets_listen_fn(const wmRegionListenerParams *params)
|
|||
|
||||
struct LibraryAsset {
|
||||
AssetLibraryReference library_ref;
|
||||
AssetHandle handle;
|
||||
AssetRepresentation &asset;
|
||||
};
|
||||
|
||||
struct AssetItemTree {
|
||||
|
@ -93,11 +94,11 @@ static AssetItemTree build_catalog_tree(const bContext &C, const bNodeTree *node
|
|||
return {};
|
||||
}
|
||||
|
||||
ED_assetlist_iterate(all_library_ref, [&](AssetHandle asset) {
|
||||
if (!ED_asset_filter_matches_asset(&type_filter, &asset)) {
|
||||
ED_assetlist_iterate(all_library_ref, [&](AssetHandle asset_handle) {
|
||||
if (!ED_asset_filter_matches_asset(&type_filter, &asset_handle)) {
|
||||
return true;
|
||||
}
|
||||
const AssetMetaData &meta_data = *ED_asset_handle_get_metadata(&asset);
|
||||
const AssetMetaData &meta_data = *ED_asset_handle_get_metadata(&asset_handle);
|
||||
const IDProperty *tree_type = BKE_asset_metadata_idprop_find(&meta_data, "type");
|
||||
if (tree_type == nullptr || IDP_Int(tree_type) != node_tree->type) {
|
||||
return true;
|
||||
|
@ -111,7 +112,8 @@ static AssetItemTree build_catalog_tree(const bContext &C, const bNodeTree *node
|
|||
if (catalog == nullptr) {
|
||||
return true;
|
||||
}
|
||||
assets_per_path.add(catalog->path, LibraryAsset{all_library_ref, asset});
|
||||
AssetRepresentation *asset = ED_asset_handle_get_representation(&asset_handle);
|
||||
assets_per_path.add(catalog->path, LibraryAsset{all_library_ref, *asset});
|
||||
return true;
|
||||
});
|
||||
|
||||
|
@ -178,16 +180,17 @@ static void node_add_catalog_assets_draw(const bContext *C, Menu *menu)
|
|||
|
||||
for (const LibraryAsset &item : asset_items) {
|
||||
uiLayout *col = uiLayoutColumn(layout, false);
|
||||
PointerRNA file{
|
||||
&screen.id, &RNA_FileSelectEntry, const_cast<FileDirEntry *>(item.handle.file_data)};
|
||||
uiLayoutSetContextPointer(col, "active_file", &file);
|
||||
|
||||
PointerRNA asset_ptr{NULL, &RNA_AssetRepresentation, &item.asset};
|
||||
uiLayoutSetContextPointer(col, "asset", &asset_ptr);
|
||||
|
||||
PointerRNA library_ptr{&screen.id,
|
||||
&RNA_AssetLibraryReference,
|
||||
const_cast<AssetLibraryReference *>(&item.library_ref)};
|
||||
uiLayoutSetContextPointer(col, "asset_library_ref", &library_ptr);
|
||||
|
||||
uiItemO(col, ED_asset_handle_get_name(&item.handle), ICON_NONE, "NODE_OT_add_group_asset");
|
||||
uiItemO(
|
||||
col, AS_asset_representation_name_get(&item.asset), ICON_NONE, "NODE_OT_add_group_asset");
|
||||
}
|
||||
|
||||
catalog_item->foreach_child([&](asset_system::AssetCatalogTreeItem &child_item) {
|
||||
|
|
|
@ -39,7 +39,7 @@ struct AddNodeItem {
|
|||
std::string ui_name;
|
||||
std::string identifier;
|
||||
std::string description;
|
||||
std::optional<AssetHandle> asset;
|
||||
const AssetRepresentation *asset;
|
||||
std::function<void(const bContext &, bNodeTree &, bNode &)> after_add_fn;
|
||||
int weight = 0;
|
||||
};
|
||||
|
@ -67,24 +67,25 @@ static void add_node_search_listen_fn(const wmRegionListenerParams *params, void
|
|||
}
|
||||
|
||||
static void search_items_for_asset_metadata(const bNodeTree &node_tree,
|
||||
const AssetHandle asset,
|
||||
const AssetHandle asset_handle,
|
||||
Vector<AddNodeItem> &search_items)
|
||||
{
|
||||
const AssetMetaData &asset_data = *ED_asset_handle_get_metadata(&asset);
|
||||
const AssetMetaData &asset_data = *ED_asset_handle_get_metadata(&asset_handle);
|
||||
const IDProperty *tree_type = BKE_asset_metadata_idprop_find(&asset_data, "type");
|
||||
if (tree_type == nullptr || IDP_Int(tree_type) != node_tree.type) {
|
||||
return;
|
||||
}
|
||||
|
||||
const AssetRepresentation *asset = ED_asset_handle_get_representation(&asset_handle);
|
||||
AddNodeItem item{};
|
||||
item.ui_name = ED_asset_handle_get_name(&asset);
|
||||
item.ui_name = ED_asset_handle_get_name(&asset_handle);
|
||||
item.identifier = node_tree.typeinfo->group_idname;
|
||||
item.description = asset_data.description == nullptr ? "" : asset_data.description;
|
||||
item.asset = asset;
|
||||
item.after_add_fn = [asset](const bContext &C, bNodeTree &node_tree, bNode &node) {
|
||||
Main &bmain = *CTX_data_main(&C);
|
||||
node.flag &= ~NODE_OPTIONS;
|
||||
node.id = asset::get_local_id_from_asset_or_append_and_reuse(bmain, asset);
|
||||
node.id = ED_asset_get_local_id_from_asset_or_append_and_reuse(&bmain, asset, ID_NT);
|
||||
id_us_plus(node.id);
|
||||
BKE_ntree_update_tag_node_property(&node_tree, &node);
|
||||
DEG_relations_tag_update(&bmain);
|
||||
|
|
|
@ -143,10 +143,10 @@ static void add_existing_group_input_fn(nodes::LinkSearchOpParams ¶ms,
|
|||
*/
|
||||
static void search_link_ops_for_asset_metadata(const bNodeTree &node_tree,
|
||||
const bNodeSocket &socket,
|
||||
const AssetHandle asset,
|
||||
const AssetHandle asset_handle,
|
||||
Vector<SocketLinkOperation> &search_link_ops)
|
||||
{
|
||||
const AssetMetaData &asset_data = *ED_asset_handle_get_metadata(&asset);
|
||||
const AssetMetaData &asset_data = *ED_asset_handle_get_metadata(&asset_handle);
|
||||
const IDProperty *tree_type = BKE_asset_metadata_idprop_find(&asset_data, "type");
|
||||
if (tree_type == nullptr || IDP_Int(tree_type) != node_tree.type) {
|
||||
return;
|
||||
|
@ -182,7 +182,8 @@ static void search_link_ops_for_asset_metadata(const bNodeTree &node_tree,
|
|||
continue;
|
||||
}
|
||||
|
||||
const StringRef asset_name = ED_asset_handle_get_name(&asset);
|
||||
AssetRepresentation *asset = ED_asset_handle_get_representation(&asset_handle);
|
||||
const StringRef asset_name = ED_asset_handle_get_name(&asset_handle);
|
||||
const StringRef socket_name = socket_property->name;
|
||||
|
||||
search_link_ops.append(
|
||||
|
@ -193,7 +194,7 @@ static void search_link_ops_for_asset_metadata(const bNodeTree &node_tree,
|
|||
bNode &node = params.add_node(params.node_tree.typeinfo->group_idname);
|
||||
node.flag &= ~NODE_OPTIONS;
|
||||
|
||||
node.id = asset::get_local_id_from_asset_or_append_and_reuse(bmain, asset);
|
||||
node.id = ED_asset_get_local_id_from_asset_or_append_and_reuse(&bmain, asset, ID_NT);
|
||||
id_us_plus(node.id);
|
||||
BKE_ntree_update_tag_node_property(¶ms.node_tree, &node);
|
||||
DEG_relations_tag_update(&bmain);
|
||||
|
|
|
@ -7,6 +7,8 @@
|
|||
|
||||
#include <numeric>
|
||||
|
||||
#include "AS_asset_representation.h"
|
||||
|
||||
#include "MEM_guardedalloc.h"
|
||||
|
||||
#include "DNA_collection_types.h"
|
||||
|
@ -378,14 +380,16 @@ void NODE_OT_add_group(wmOperatorType *ot)
|
|||
/** \name Add Node Group Asset Operator
|
||||
* \{ */
|
||||
|
||||
static bool add_node_group_asset(const bContext &C, const AssetHandle asset, ReportList &reports)
|
||||
static bool add_node_group_asset(const bContext &C,
|
||||
const AssetRepresentation *asset,
|
||||
ReportList &reports)
|
||||
{
|
||||
Main &bmain = *CTX_data_main(&C);
|
||||
SpaceNode &snode = *CTX_wm_space_node(&C);
|
||||
bNodeTree &edit_tree = *snode.edittree;
|
||||
|
||||
bNodeTree *node_group = reinterpret_cast<bNodeTree *>(
|
||||
asset::get_local_id_from_asset_or_append_and_reuse(bmain, asset));
|
||||
ED_asset_get_local_id_from_asset_or_append_and_reuse(&bmain, asset, ID_NT));
|
||||
if (!node_group) {
|
||||
return false;
|
||||
}
|
||||
|
@ -427,9 +431,8 @@ static int node_add_group_asset_invoke(bContext *C, wmOperator *op, const wmEven
|
|||
if (!library_ref) {
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
bool is_valid;
|
||||
const AssetHandle handle = CTX_wm_asset_handle(C, &is_valid);
|
||||
if (!is_valid) {
|
||||
const AssetRepresentation *asset = CTX_wm_asset(C);
|
||||
if (!asset) {
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
|
||||
|
@ -442,7 +445,7 @@ static int node_add_group_asset_invoke(bContext *C, wmOperator *op, const wmEven
|
|||
|
||||
snode.runtime->cursor /= UI_DPI_FAC;
|
||||
|
||||
if (!add_node_group_asset(*C, handle, *op->reports)) {
|
||||
if (!add_node_group_asset(*C, asset, *op->reports)) {
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
|
||||
|
@ -460,12 +463,11 @@ static char *node_add_group_asset_get_description(struct bContext *C,
|
|||
struct wmOperatorType * /*op*/,
|
||||
struct PointerRNA * /*values*/)
|
||||
{
|
||||
bool is_valid;
|
||||
const AssetHandle handle = CTX_wm_asset_handle(C, &is_valid);
|
||||
if (!is_valid) {
|
||||
const AssetRepresentation *asset = CTX_wm_asset(C);
|
||||
if (!asset) {
|
||||
return nullptr;
|
||||
}
|
||||
const AssetMetaData &asset_data = *ED_asset_handle_get_metadata(&handle);
|
||||
const AssetMetaData &asset_data = *AS_asset_representation_metadata_get(asset);
|
||||
if (!asset_data.description) {
|
||||
return nullptr;
|
||||
}
|
||||
|
|
|
@ -1295,7 +1295,6 @@ static int view3d_ruler_add_invoke(bContext *C, wmOperator *op, const wmEvent *e
|
|||
{
|
||||
ARegion *region = CTX_wm_region(C);
|
||||
View3D *v3d = CTX_wm_view3d(C);
|
||||
RegionView3D *rv3d = region->regiondata;
|
||||
|
||||
if (v3d->gizmo_flag & (V3D_GIZMO_HIDE | V3D_GIZMO_HIDE_TOOL)) {
|
||||
BKE_report(op->reports, RPT_WARNING, "Gizmos hidden in this view");
|
||||
|
@ -1304,7 +1303,6 @@ static int view3d_ruler_add_invoke(bContext *C, wmOperator *op, const wmEvent *e
|
|||
|
||||
wmGizmoMap *gzmap = region->gizmo_map;
|
||||
wmGizmoGroup *gzgroup = WM_gizmomap_group_find(gzmap, view3d_gzgt_ruler_id);
|
||||
const bool use_depth = (v3d->shading.type >= OB_SOLID);
|
||||
|
||||
if (!gizmo_ruler_check_for_operator(gzgroup)) {
|
||||
return OPERATOR_CANCELLED;
|
||||
|
@ -1324,9 +1322,7 @@ static int view3d_ruler_add_invoke(bContext *C, wmOperator *op, const wmEvent *e
|
|||
OPERATOR_RUNNING_MODAL) {
|
||||
RulerInfo *ruler_info = gzgroup->customdata;
|
||||
RulerInteraction *inter = ruler_item->gz.interaction_data;
|
||||
if (use_depth) {
|
||||
struct Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
|
||||
/* snap the first point added, not essential but handy */
|
||||
inter->co_index = 0;
|
||||
view3d_ruler_item_mousemove(C,
|
||||
depsgraph,
|
||||
|
@ -1343,12 +1339,6 @@ static int view3d_ruler_add_invoke(bContext *C, wmOperator *op, const wmEvent *e
|
|||
RNA_property_float_set_array(ruler_info->snap_data.gizmo->ptr,
|
||||
ruler_info->snap_data.prop_prevpoint,
|
||||
inter->drag_start_co);
|
||||
}
|
||||
else {
|
||||
negate_v3_v3(inter->drag_start_co, rv3d->ofs);
|
||||
copy_v3_v3(ruler_item->co[0], inter->drag_start_co);
|
||||
view3d_ruler_item_project(ruler_info, ruler_item->co[0], mval);
|
||||
}
|
||||
|
||||
copy_v3_v3(ruler_item->co[2], ruler_item->co[0]);
|
||||
ruler_item->gz.highlight_part = inter->co_index = 2;
|
||||
|
|
|
@ -99,6 +99,8 @@ struct GPUPass {
|
|||
/** Hint that an optimized variant of this pass should be created based on a complexity heuristic
|
||||
* during pass code generation. */
|
||||
bool should_optimize;
|
||||
/** Whether pass is in the GPUPass cache. */
|
||||
bool cached;
|
||||
};
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
|
@ -132,6 +134,7 @@ static GPUPass *gpu_pass_cache_lookup(uint32_t hash)
|
|||
static void gpu_pass_cache_insert_after(GPUPass *node, GPUPass *pass)
|
||||
{
|
||||
BLI_spin_lock(&pass_cache_spin);
|
||||
pass->cached = true;
|
||||
if (node != nullptr) {
|
||||
/* Add after the first pass having the same hash. */
|
||||
pass->next = node->next;
|
||||
|
@ -775,6 +778,7 @@ GPUPass *GPU_generate_pass(GPUMaterial *material,
|
|||
pass->create_info = codegen.create_info;
|
||||
pass->hash = codegen.hash_get();
|
||||
pass->compiled = false;
|
||||
pass->cached = false;
|
||||
/* Only flag pass optimization hint if this is the first generated pass for a material.
|
||||
* Optimized passes cannot be optimized further, even if the heuristic is still not
|
||||
* favorable. */
|
||||
|
@ -881,14 +885,6 @@ GPUShader *GPU_pass_shader_get(GPUPass *pass)
|
|||
return pass->shader;
|
||||
}
|
||||
|
||||
void GPU_pass_release(GPUPass *pass)
|
||||
{
|
||||
BLI_spin_lock(&pass_cache_spin);
|
||||
BLI_assert(pass->refcount > 0);
|
||||
pass->refcount--;
|
||||
BLI_spin_unlock(&pass_cache_spin);
|
||||
}
|
||||
|
||||
static void gpu_pass_free(GPUPass *pass)
|
||||
{
|
||||
BLI_assert(pass->refcount == 0);
|
||||
|
@ -899,6 +895,18 @@ static void gpu_pass_free(GPUPass *pass)
|
|||
MEM_freeN(pass);
|
||||
}
|
||||
|
||||
void GPU_pass_release(GPUPass *pass)
|
||||
{
|
||||
BLI_spin_lock(&pass_cache_spin);
|
||||
BLI_assert(pass->refcount > 0);
|
||||
pass->refcount--;
|
||||
/* Un-cached passes will not be filtered by garbage collection, so release here. */
|
||||
if (pass->refcount == 0 && !pass->cached) {
|
||||
gpu_pass_free(pass);
|
||||
}
|
||||
BLI_spin_unlock(&pass_cache_spin);
|
||||
}
|
||||
|
||||
void GPU_pass_cache_garbage_collect(void)
|
||||
{
|
||||
static int lasttime = 0;
|
||||
|
|
|
@ -287,17 +287,17 @@ class MTLSafeFreeList {
|
|||
std::atomic<bool> in_free_queue_;
|
||||
std::atomic<bool> referenced_by_workload_;
|
||||
std::recursive_mutex lock_;
|
||||
|
||||
/* Linked list of next MTLSafeFreeList chunk if current chunk is full. */
|
||||
std::atomic<int> has_next_pool_;
|
||||
std::atomic<MTLSafeFreeList *> next_;
|
||||
|
||||
/* Lockless list. MAX_NUM_BUFFERS_ within a chunk based on considerations
|
||||
* for performance and memory.
|
||||
* for performance and memory. Higher chunk counts are preferable for efficiently
|
||||
* performing block operations such as copying several objects simultaneously.
|
||||
*
|
||||
* MIN_BUFFER_FLUSH_COUNT refers to the minimum count of buffers in the MTLSafeFreeList
|
||||
* before buffers are returned to global memory pool. This is set at a point to reduce
|
||||
* overhead of small pool flushes, while ensuring floating memory overhead is not excessive. */
|
||||
static const int MAX_NUM_BUFFERS_ = 1024;
|
||||
static const int MAX_NUM_BUFFERS_ = 8192;
|
||||
static const int MIN_BUFFER_FLUSH_COUNT = 120;
|
||||
std::atomic<int> current_list_index_;
|
||||
gpu::MTLBuffer *safe_free_pool_[MAX_NUM_BUFFERS_];
|
||||
|
@ -305,8 +305,8 @@ class MTLSafeFreeList {
|
|||
public:
|
||||
MTLSafeFreeList();
|
||||
|
||||
/* Add buffer to Safe Free List, can be called from secondary threads.
|
||||
* Performs a lockless list insert. */
|
||||
/* Can be used from multiple threads. Performs insertion into Safe Free List with the least
|
||||
* amount of threading synchronization. */
|
||||
void insert_buffer(gpu::MTLBuffer *buffer);
|
||||
|
||||
/* Whether we need to start a new safe free list, or can carry on using the existing one. */
|
||||
|
@ -321,12 +321,13 @@ class MTLSafeFreeList {
|
|||
void flag_in_queue()
|
||||
{
|
||||
in_free_queue_ = true;
|
||||
if (has_next_pool_) {
|
||||
if (current_list_index_ >= MTLSafeFreeList::MAX_NUM_BUFFERS_) {
|
||||
MTLSafeFreeList *next_pool = next_.load();
|
||||
BLI_assert(next_pool != nullptr);
|
||||
if (next_pool) {
|
||||
next_pool->flag_in_queue();
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/* MTLBuffer pools. */
|
||||
|
|
|
@ -257,10 +257,7 @@ void MTLBufferPool::update_memory_pools()
|
|||
}
|
||||
|
||||
/* Fetch next MTLSafeFreeList chunk, if any. */
|
||||
MTLSafeFreeList *next_list = nullptr;
|
||||
if (current_pool->has_next_pool_ > 0) {
|
||||
next_list = current_pool->next_.load();
|
||||
}
|
||||
MTLSafeFreeList *next_list = current_pool->next_.load();
|
||||
|
||||
/* Delete current MTLSafeFreeList */
|
||||
current_pool->lock_.unlock();
|
||||
|
@ -396,7 +393,6 @@ MTLSafeFreeList::MTLSafeFreeList()
|
|||
in_free_queue_ = false;
|
||||
current_list_index_ = 0;
|
||||
next_ = nullptr;
|
||||
has_next_pool_ = 0;
|
||||
}
|
||||
|
||||
void MTLSafeFreeList::insert_buffer(gpu::MTLBuffer *buffer)
|
||||
|
@ -410,12 +406,19 @@ void MTLSafeFreeList::insert_buffer(gpu::MTLBuffer *buffer)
|
|||
* insert the buffer into the next available chunk. */
|
||||
if (insert_index >= MTLSafeFreeList::MAX_NUM_BUFFERS_) {
|
||||
|
||||
/* Check if first caller to generate next pool. */
|
||||
int has_next = has_next_pool_++;
|
||||
if (has_next == 0) {
|
||||
next_ = new MTLSafeFreeList();
|
||||
}
|
||||
/* Check if first caller to generate next pool in chain.
|
||||
* Otherwise, ensure pool exists or wait for first caller to create next pool. */
|
||||
MTLSafeFreeList *next_list = next_.load();
|
||||
|
||||
if (!next_list) {
|
||||
std::unique_lock lock(lock_);
|
||||
|
||||
next_list = next_.load();
|
||||
if (!next_list) {
|
||||
next_list = new MTLSafeFreeList();
|
||||
next_.store(next_list);
|
||||
}
|
||||
}
|
||||
BLI_assert(next_list);
|
||||
next_list->insert_buffer(buffer);
|
||||
|
||||
|
|
|
@ -490,8 +490,12 @@ class MSLGeneratorInterface {
|
|||
std::string generate_msl_uniform_undefs(ShaderStage stage);
|
||||
std::string generate_ubo_block_undef_chain(ShaderStage stage);
|
||||
std::string generate_msl_texture_vars(ShaderStage shader_stage);
|
||||
void generate_msl_textures_input_string(std::stringstream &out, ShaderStage stage);
|
||||
void generate_msl_uniforms_input_string(std::stringstream &out, ShaderStage stage);
|
||||
void generate_msl_textures_input_string(std::stringstream &out,
|
||||
ShaderStage stage,
|
||||
bool &is_first_parameter);
|
||||
void generate_msl_uniforms_input_string(std::stringstream &out,
|
||||
ShaderStage stage,
|
||||
bool &is_first_parameter);
|
||||
|
||||
/* Location is not always specified, so this will resolve outstanding locations. */
|
||||
void resolve_input_attribute_locations();
|
||||
|
|
|
@ -2145,8 +2145,20 @@ std::string MSLGeneratorInterface::generate_msl_compute_entry_stub()
|
|||
return out.str();
|
||||
}
|
||||
|
||||
/* If first parameter in function signature, do not print out a comma.
|
||||
* Update first parameter flag to false for future invocations. */
|
||||
static char parameter_delimiter(bool &is_first_parameter)
|
||||
{
|
||||
if (is_first_parameter) {
|
||||
is_first_parameter = false;
|
||||
return ' ';
|
||||
}
|
||||
return ',';
|
||||
}
|
||||
|
||||
void MSLGeneratorInterface::generate_msl_textures_input_string(std::stringstream &out,
|
||||
ShaderStage stage)
|
||||
ShaderStage stage,
|
||||
bool &is_first_parameter)
|
||||
{
|
||||
/* Note: Shader stage must be specified as the singular stage index for which the input
|
||||
* is generating. Compound stages are not valid inputs. */
|
||||
|
@ -2156,7 +2168,8 @@ void MSLGeneratorInterface::generate_msl_textures_input_string(std::stringstream
|
|||
BLI_assert(this->texture_samplers.size() <= GPU_max_textures_vert());
|
||||
for (const MSLTextureSampler &tex : this->texture_samplers) {
|
||||
if (bool(tex.stage & stage)) {
|
||||
out << ",\n\t" << tex.get_msl_typestring(false) << " [[texture(" << tex.location << ")]]";
|
||||
out << parameter_delimiter(is_first_parameter) << "\n\t" << tex.get_msl_typestring(false)
|
||||
<< " [[texture(" << tex.location << ")]]";
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2166,7 +2179,8 @@ void MSLGeneratorInterface::generate_msl_textures_input_string(std::stringstream
|
|||
* If we exceed the hardware-supported limit, then follow a bind-less model using argument
|
||||
* buffers. */
|
||||
if (this->use_argument_buffer_for_samplers()) {
|
||||
out << ",\n\tconstant SStruct& samplers [[buffer(MTL_uniform_buffer_base_index+"
|
||||
out << parameter_delimiter(is_first_parameter)
|
||||
<< "\n\tconstant SStruct& samplers [[buffer(MTL_uniform_buffer_base_index+"
|
||||
<< (this->get_sampler_argument_buffer_bind_index(stage)) << ")]]";
|
||||
}
|
||||
else {
|
||||
|
@ -2175,7 +2189,8 @@ void MSLGeneratorInterface::generate_msl_textures_input_string(std::stringstream
|
|||
BLI_assert(this->texture_samplers.size() <= MTL_MAX_DEFAULT_SAMPLERS);
|
||||
for (const MSLTextureSampler &tex : this->texture_samplers) {
|
||||
if (bool(tex.stage & stage)) {
|
||||
out << ",\n\tsampler " << tex.name << "_sampler [[sampler(" << tex.location << ")]]";
|
||||
out << parameter_delimiter(is_first_parameter) << "\n\tsampler " << tex.name
|
||||
<< "_sampler [[sampler(" << tex.location << ")]]";
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2189,12 +2204,13 @@ void MSLGeneratorInterface::generate_msl_textures_input_string(std::stringstream
|
|||
}
|
||||
|
||||
void MSLGeneratorInterface::generate_msl_uniforms_input_string(std::stringstream &out,
|
||||
ShaderStage stage)
|
||||
ShaderStage stage,
|
||||
bool &is_first_parameter)
|
||||
{
|
||||
for (const MSLUniformBlock &ubo : this->uniform_blocks) {
|
||||
if (bool(ubo.stage & stage)) {
|
||||
/* For literal/existing global types, we do not need the class name-space accessor. */
|
||||
out << ",\n\tconstant ";
|
||||
out << parameter_delimiter(is_first_parameter) << "\n\tconstant ";
|
||||
if (!is_builtin_type(ubo.type_name)) {
|
||||
out << get_stage_class_name(stage) << "::";
|
||||
}
|
||||
|
@ -2211,104 +2227,135 @@ void MSLGeneratorInterface::generate_msl_uniforms_input_string(std::stringstream
|
|||
std::string MSLGeneratorInterface::generate_msl_vertex_inputs_string()
|
||||
{
|
||||
std::stringstream out;
|
||||
bool is_first_parameter = true;
|
||||
|
||||
if (this->uses_ssbo_vertex_fetch_mode) {
|
||||
/* Vertex Buffers bound as raw buffers. */
|
||||
for (int i = 0; i < MTL_SSBO_VERTEX_FETCH_MAX_VBOS; i++) {
|
||||
out << "\tconstant uchar* MTL_VERTEX_DATA_" << i << " [[buffer(" << i << ")]],\n";
|
||||
out << parameter_delimiter(is_first_parameter) << "\tconstant uchar* MTL_VERTEX_DATA_" << i
|
||||
<< " [[buffer(" << i << ")]]\n";
|
||||
}
|
||||
out << "\tconstant ushort* MTL_INDEX_DATA[[buffer(MTL_SSBO_VERTEX_FETCH_IBO_INDEX)]],";
|
||||
out << parameter_delimiter(is_first_parameter)
|
||||
<< "\tconstant ushort* MTL_INDEX_DATA[[buffer(MTL_SSBO_VERTEX_FETCH_IBO_INDEX)]]";
|
||||
}
|
||||
else {
|
||||
if (this->vertex_input_attributes.size() > 0) {
|
||||
/* Vertex Buffers use input assembly. */
|
||||
out << get_stage_class_name(ShaderStage::VERTEX) << "::VertexIn v_in [[stage_in]],";
|
||||
out << get_stage_class_name(ShaderStage::VERTEX) << "::VertexIn v_in [[stage_in]]";
|
||||
is_first_parameter = false;
|
||||
}
|
||||
}
|
||||
out << "\n\tconstant " << get_stage_class_name(ShaderStage::VERTEX)
|
||||
<< "::PushConstantBlock* uniforms[[buffer(MTL_uniform_buffer_base_index)]]";
|
||||
|
||||
this->generate_msl_uniforms_input_string(out, ShaderStage::VERTEX);
|
||||
if (this->uniforms.size() > 0) {
|
||||
out << parameter_delimiter(is_first_parameter) << "\n\tconstant "
|
||||
<< get_stage_class_name(ShaderStage::VERTEX)
|
||||
<< "::PushConstantBlock* uniforms[[buffer(MTL_uniform_buffer_base_index)]]";
|
||||
is_first_parameter = false;
|
||||
}
|
||||
|
||||
this->generate_msl_uniforms_input_string(out, ShaderStage::VERTEX, is_first_parameter);
|
||||
|
||||
/* Transform feedback buffer binding. */
|
||||
if (this->uses_transform_feedback) {
|
||||
out << ",\n\tdevice " << get_stage_class_name(ShaderStage::VERTEX)
|
||||
out << parameter_delimiter(is_first_parameter) << "\n\tdevice "
|
||||
<< get_stage_class_name(ShaderStage::VERTEX)
|
||||
<< "::VertexOut_TF* "
|
||||
"transform_feedback_results[[buffer(MTL_transform_feedback_buffer_index)]]";
|
||||
}
|
||||
|
||||
/* Generate texture signatures. */
|
||||
this->generate_msl_textures_input_string(out, ShaderStage::VERTEX);
|
||||
this->generate_msl_textures_input_string(out, ShaderStage::VERTEX, is_first_parameter);
|
||||
|
||||
/* Entry point parameters for gl Globals. */
|
||||
if (this->uses_gl_VertexID) {
|
||||
out << ",\n\tconst uint32_t gl_VertexID [[vertex_id]]";
|
||||
out << parameter_delimiter(is_first_parameter)
|
||||
<< "\n\tconst uint32_t gl_VertexID [[vertex_id]]";
|
||||
}
|
||||
if (this->uses_gl_InstanceID) {
|
||||
out << ",\n\tconst uint32_t gl_InstanceID [[instance_id]]";
|
||||
out << parameter_delimiter(is_first_parameter)
|
||||
<< "\n\tconst uint32_t gl_InstanceID [[instance_id]]";
|
||||
}
|
||||
if (this->uses_gl_BaseInstanceARB) {
|
||||
out << ",\n\tconst uint32_t gl_BaseInstanceARB [[base_instance]]";
|
||||
out << parameter_delimiter(is_first_parameter)
|
||||
<< "\n\tconst uint32_t gl_BaseInstanceARB [[base_instance]]";
|
||||
}
|
||||
return out.str();
|
||||
}
|
||||
|
||||
std::string MSLGeneratorInterface::generate_msl_fragment_inputs_string()
|
||||
{
|
||||
bool is_first_parameter = true;
|
||||
std::stringstream out;
|
||||
out << get_stage_class_name(ShaderStage::FRAGMENT)
|
||||
<< "::VertexOut v_in [[stage_in]],\n\tconstant "
|
||||
out << parameter_delimiter(is_first_parameter) << get_stage_class_name(ShaderStage::FRAGMENT)
|
||||
<< "::VertexOut v_in [[stage_in]]";
|
||||
|
||||
if (this->uniforms.size() > 0) {
|
||||
out << parameter_delimiter(is_first_parameter) << "\n\tconstant "
|
||||
<< get_stage_class_name(ShaderStage::FRAGMENT)
|
||||
<< "::PushConstantBlock* uniforms[[buffer(MTL_uniform_buffer_base_index)]]";
|
||||
}
|
||||
|
||||
this->generate_msl_uniforms_input_string(out, ShaderStage::FRAGMENT);
|
||||
this->generate_msl_uniforms_input_string(out, ShaderStage::FRAGMENT, is_first_parameter);
|
||||
|
||||
/* Generate texture signatures. */
|
||||
this->generate_msl_textures_input_string(out, ShaderStage::FRAGMENT);
|
||||
this->generate_msl_textures_input_string(out, ShaderStage::FRAGMENT, is_first_parameter);
|
||||
|
||||
if (this->uses_gl_PointCoord) {
|
||||
out << ",\n\tconst float2 gl_PointCoord [[point_coord]]";
|
||||
out << parameter_delimiter(is_first_parameter)
|
||||
<< "\n\tconst float2 gl_PointCoord [[point_coord]]";
|
||||
}
|
||||
if (this->uses_gl_FrontFacing) {
|
||||
out << ",\n\tconst MTLBOOL gl_FrontFacing [[front_facing]]";
|
||||
out << parameter_delimiter(is_first_parameter)
|
||||
<< "\n\tconst MTLBOOL gl_FrontFacing [[front_facing]]";
|
||||
}
|
||||
if (this->uses_gl_PrimitiveID) {
|
||||
out << ",\n\tconst uint gl_PrimitiveID [[primitive_id]]";
|
||||
out << parameter_delimiter(is_first_parameter)
|
||||
<< "\n\tconst uint gl_PrimitiveID [[primitive_id]]";
|
||||
}
|
||||
|
||||
/* Barycentrics. */
|
||||
if (this->uses_barycentrics) {
|
||||
out << ",\n\tconst float3 mtl_barycentric_coord [[barycentric_coord]]";
|
||||
out << parameter_delimiter(is_first_parameter)
|
||||
<< "\n\tconst float3 mtl_barycentric_coord [[barycentric_coord]]";
|
||||
}
|
||||
return out.str();
|
||||
}
|
||||
|
||||
std::string MSLGeneratorInterface::generate_msl_compute_inputs_string()
|
||||
{
|
||||
bool is_first_parameter = true;
|
||||
std::stringstream out;
|
||||
out << "constant " << get_stage_class_name(ShaderStage::COMPUTE)
|
||||
if (this->uniforms.size() > 0) {
|
||||
out << parameter_delimiter(is_first_parameter) << "constant "
|
||||
<< get_stage_class_name(ShaderStage::COMPUTE)
|
||||
<< "::PushConstantBlock* uniforms[[buffer(MTL_uniform_buffer_base_index)]]";
|
||||
}
|
||||
|
||||
this->generate_msl_uniforms_input_string(out, ShaderStage::COMPUTE);
|
||||
this->generate_msl_uniforms_input_string(out, ShaderStage::COMPUTE, is_first_parameter);
|
||||
|
||||
/* Generate texture signatures. */
|
||||
this->generate_msl_textures_input_string(out, ShaderStage::COMPUTE);
|
||||
this->generate_msl_textures_input_string(out, ShaderStage::COMPUTE, is_first_parameter);
|
||||
|
||||
/* Entry point parameters for gl Globals. */
|
||||
if (this->uses_gl_GlobalInvocationID) {
|
||||
out << ",\n\tconst uint3 gl_GlobalInvocationID [[thread_position_in_grid]]";
|
||||
out << parameter_delimiter(is_first_parameter)
|
||||
<< "\n\tconst uint3 gl_GlobalInvocationID [[thread_position_in_grid]]";
|
||||
}
|
||||
if (this->uses_gl_WorkGroupID) {
|
||||
out << ",\n\tconst uint3 gl_WorkGroupID [[threadgroup_position_in_grid]]";
|
||||
out << parameter_delimiter(is_first_parameter)
|
||||
<< "\n\tconst uint3 gl_WorkGroupID [[threadgroup_position_in_grid]]";
|
||||
}
|
||||
if (this->uses_gl_NumWorkGroups) {
|
||||
out << ",\n\tconst uint3 gl_NumWorkGroups [[threadgroups_per_grid]]";
|
||||
out << parameter_delimiter(is_first_parameter)
|
||||
<< "\n\tconst uint3 gl_NumWorkGroups [[threadgroups_per_grid]]";
|
||||
}
|
||||
if (this->uses_gl_LocalInvocationIndex) {
|
||||
out << ",\n\tconst uint gl_LocalInvocationIndex [[thread_index_in_threadgroup]]";
|
||||
out << parameter_delimiter(is_first_parameter)
|
||||
<< "\n\tconst uint gl_LocalInvocationIndex [[thread_index_in_threadgroup]]";
|
||||
}
|
||||
if (this->uses_gl_LocalInvocationID) {
|
||||
out << ",\n\tconst uint3 gl_LocalInvocationID [[thread_position_in_threadgroup]]";
|
||||
out << parameter_delimiter(is_first_parameter)
|
||||
<< "\n\tconst uint3 gl_LocalInvocationID [[thread_position_in_threadgroup]]";
|
||||
}
|
||||
|
||||
return out.str();
|
||||
|
@ -2316,6 +2363,10 @@ std::string MSLGeneratorInterface::generate_msl_compute_inputs_string()
|
|||
|
||||
std::string MSLGeneratorInterface::generate_msl_uniform_structs(ShaderStage shader_stage)
|
||||
{
|
||||
/* Only generate PushConstantBlock if we have uniforms. */
|
||||
if (this->uniforms.size() == 0) {
|
||||
return "";
|
||||
}
|
||||
BLI_assert(shader_stage == ShaderStage::VERTEX || shader_stage == ShaderStage::FRAGMENT);
|
||||
std::stringstream out;
|
||||
|
||||
|
@ -2624,6 +2675,9 @@ std::string MSLGeneratorInterface::generate_msl_fragment_out_struct()
|
|||
|
||||
std::string MSLGeneratorInterface::generate_msl_global_uniform_population(ShaderStage stage)
|
||||
{
|
||||
if (this->uniforms.size() == 0) {
|
||||
return "";
|
||||
}
|
||||
/* Populate Global Uniforms. */
|
||||
std::stringstream out;
|
||||
|
||||
|
|
|
@ -594,17 +594,6 @@ void gpu::MTLTexture::update_sub(
|
|||
}
|
||||
}
|
||||
|
||||
/* Prepare staging buffer for data. */
|
||||
id<MTLBuffer> staging_buffer = nil;
|
||||
uint64_t staging_buffer_offset = 0;
|
||||
|
||||
/* Fetch allocation from scratch buffer. */
|
||||
MTLTemporaryBuffer allocation =
|
||||
ctx->get_scratchbuffer_manager().scratch_buffer_allocate_range_aligned(totalsize, 256);
|
||||
memcpy(allocation.data, data, totalsize);
|
||||
staging_buffer = allocation.metal_buffer;
|
||||
staging_buffer_offset = allocation.buffer_offset;
|
||||
|
||||
/* Common Properties. */
|
||||
MTLPixelFormat compatible_write_format = mtl_format_get_writeable_view_format(
|
||||
destination_format);
|
||||
|
@ -616,6 +605,12 @@ void gpu::MTLTexture::update_sub(
|
|||
return;
|
||||
}
|
||||
|
||||
/* Fetch allocation from memory pool. */
|
||||
MTLBuffer *temp_allocation = MTLContext::get_global_memory_manager()->allocate_with_data(
|
||||
totalsize, true, data);
|
||||
id<MTLBuffer> staging_buffer = temp_allocation->get_metal_buffer();
|
||||
BLI_assert(staging_buffer != nil);
|
||||
|
||||
/* Prepare command encoders. */
|
||||
id<MTLBlitCommandEncoder> blit_encoder = nil;
|
||||
id<MTLComputeCommandEncoder> compute_encoder = nil;
|
||||
|
@ -697,7 +692,7 @@ void gpu::MTLTexture::update_sub(
|
|||
int max_array_index = ((type_ == GPU_TEXTURE_1D_ARRAY) ? extent[1] : 1);
|
||||
for (int array_index = 0; array_index < max_array_index; array_index++) {
|
||||
|
||||
int buffer_array_offset = staging_buffer_offset + (bytes_per_image * array_index);
|
||||
int buffer_array_offset = (bytes_per_image * array_index);
|
||||
[blit_encoder
|
||||
copyFromBuffer:staging_buffer
|
||||
sourceOffset:buffer_array_offset
|
||||
|
@ -727,7 +722,7 @@ void gpu::MTLTexture::update_sub(
|
|||
MTLComputeState &cs = ctx->main_command_buffer.get_compute_state();
|
||||
cs.bind_pso(pso);
|
||||
cs.bind_compute_bytes(¶ms, sizeof(params), 0);
|
||||
cs.bind_compute_buffer(staging_buffer, staging_buffer_offset, 1);
|
||||
cs.bind_compute_buffer(staging_buffer, 0, 1);
|
||||
cs.bind_compute_texture(texture_handle, 0);
|
||||
[compute_encoder
|
||||
dispatchThreads:MTLSizeMake(extent[0], 1, 1) /* Width, Height, Layer */
|
||||
|
@ -747,7 +742,7 @@ void gpu::MTLTexture::update_sub(
|
|||
MTLComputeState &cs = ctx->main_command_buffer.get_compute_state();
|
||||
cs.bind_pso(pso);
|
||||
cs.bind_compute_bytes(¶ms, sizeof(params), 0);
|
||||
cs.bind_compute_buffer(staging_buffer, staging_buffer_offset, 1);
|
||||
cs.bind_compute_buffer(staging_buffer, 0, 1);
|
||||
cs.bind_compute_texture(texture_handle, 0);
|
||||
[compute_encoder
|
||||
dispatchThreads:MTLSizeMake(extent[0], extent[1], 1) /* Width, layers, nil */
|
||||
|
@ -779,7 +774,7 @@ void gpu::MTLTexture::update_sub(
|
|||
}
|
||||
|
||||
[blit_encoder copyFromBuffer:staging_buffer
|
||||
sourceOffset:staging_buffer_offset + texture_array_relative_offset
|
||||
sourceOffset:texture_array_relative_offset
|
||||
sourceBytesPerRow:bytes_per_row
|
||||
sourceBytesPerImage:bytes_per_image
|
||||
sourceSize:MTLSizeMake(extent[0], extent[1], 1)
|
||||
|
@ -807,7 +802,7 @@ void gpu::MTLTexture::update_sub(
|
|||
MTLComputeState &cs = ctx->main_command_buffer.get_compute_state();
|
||||
cs.bind_pso(pso);
|
||||
cs.bind_compute_bytes(¶ms, sizeof(params), 0);
|
||||
cs.bind_compute_buffer(staging_buffer, staging_buffer_offset, 1);
|
||||
cs.bind_compute_buffer(staging_buffer, 0, 1);
|
||||
cs.bind_compute_texture(texture_handle, 0);
|
||||
[compute_encoder
|
||||
dispatchThreads:MTLSizeMake(
|
||||
|
@ -828,7 +823,7 @@ void gpu::MTLTexture::update_sub(
|
|||
MTLComputeState &cs = ctx->main_command_buffer.get_compute_state();
|
||||
cs.bind_pso(pso);
|
||||
cs.bind_compute_bytes(¶ms, sizeof(params), 0);
|
||||
cs.bind_compute_buffer(staging_buffer, staging_buffer_offset, 1);
|
||||
cs.bind_compute_buffer(staging_buffer, 0, 1);
|
||||
cs.bind_compute_texture(texture_handle, 0);
|
||||
[compute_encoder dispatchThreads:MTLSizeMake(extent[0],
|
||||
extent[1],
|
||||
|
@ -848,7 +843,7 @@ void gpu::MTLTexture::update_sub(
|
|||
ctx->pipeline_state.unpack_row_length);
|
||||
int bytes_per_image = bytes_per_row * extent[1];
|
||||
[blit_encoder copyFromBuffer:staging_buffer
|
||||
sourceOffset:staging_buffer_offset
|
||||
sourceOffset:0
|
||||
sourceBytesPerRow:bytes_per_row
|
||||
sourceBytesPerImage:bytes_per_image
|
||||
sourceSize:MTLSizeMake(extent[0], extent[1], extent[2])
|
||||
|
@ -871,7 +866,7 @@ void gpu::MTLTexture::update_sub(
|
|||
MTLComputeState &cs = ctx->main_command_buffer.get_compute_state();
|
||||
cs.bind_pso(pso);
|
||||
cs.bind_compute_bytes(¶ms, sizeof(params), 0);
|
||||
cs.bind_compute_buffer(staging_buffer, staging_buffer_offset, 1);
|
||||
cs.bind_compute_buffer(staging_buffer, 0, 1);
|
||||
cs.bind_compute_texture(texture_handle, 0);
|
||||
[compute_encoder
|
||||
dispatchThreads:MTLSizeMake(
|
||||
|
@ -896,7 +891,7 @@ void gpu::MTLTexture::update_sub(
|
|||
int face_index = offset[2] + i;
|
||||
|
||||
[blit_encoder copyFromBuffer:staging_buffer
|
||||
sourceOffset:staging_buffer_offset + texture_array_relative_offset
|
||||
sourceOffset:texture_array_relative_offset
|
||||
sourceBytesPerRow:bytes_per_row
|
||||
sourceBytesPerImage:bytes_per_image
|
||||
sourceSize:MTLSizeMake(extent[0], extent[1], 1)
|
||||
|
@ -930,7 +925,7 @@ void gpu::MTLTexture::update_sub(
|
|||
for (int i = 0; i < extent[2]; i++) {
|
||||
int face_index = offset[2] + i;
|
||||
[blit_encoder copyFromBuffer:staging_buffer
|
||||
sourceOffset:staging_buffer_offset + texture_array_relative_offset
|
||||
sourceOffset:texture_array_relative_offset
|
||||
sourceBytesPerRow:bytes_per_row
|
||||
sourceBytesPerImage:bytes_per_image
|
||||
sourceSize:MTLSizeMake(extent[0], extent[1], 1)
|
||||
|
@ -1058,6 +1053,11 @@ void gpu::MTLTexture::update_sub(
|
|||
|
||||
/* Decrement texture reference counts. This ensures temporary texture views are released. */
|
||||
[texture_handle release];
|
||||
|
||||
/* Release temporary staging buffer allocation.
|
||||
* NOTE: Allocation will be tracked with command submission and released once no longer in use.
|
||||
*/
|
||||
temp_allocation->free();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -342,9 +342,13 @@ id<MTLComputePipelineState> gpu::MTLTexture::mtl_texture_update_impl(
|
|||
options:options
|
||||
error:&error] autorelease];
|
||||
if (error) {
|
||||
/* Only exit out if genuine error and not warning. */
|
||||
if ([[error localizedDescription] rangeOfString:@"Compilation succeeded"].location ==
|
||||
NSNotFound) {
|
||||
NSLog(@"Compile Error - Metal Shader Library error %@ ", error);
|
||||
BLI_assert(false);
|
||||
return nullptr;
|
||||
return nil;
|
||||
}
|
||||
}
|
||||
|
||||
/* Fetch compute function. */
|
||||
|
@ -658,10 +662,14 @@ id<MTLComputePipelineState> gpu::MTLTexture::mtl_texture_read_impl(
|
|||
options:options
|
||||
error:&error] autorelease];
|
||||
if (error) {
|
||||
/* Only exit out if genuine error and not warning. */
|
||||
if ([[error localizedDescription] rangeOfString:@"Compilation succeeded"].location ==
|
||||
NSNotFound) {
|
||||
NSLog(@"Compile Error - Metal Shader Library error %@ ", error);
|
||||
BLI_assert(false);
|
||||
return nil;
|
||||
}
|
||||
}
|
||||
|
||||
/* Fetch compute function. */
|
||||
BLI_assert(temp_lib != nil);
|
||||
|
|
|
@ -7,6 +7,10 @@
|
|||
* and texture2d types in metal).
|
||||
*/
|
||||
|
||||
/* Suppress unhelpful shader compiler warnings. */
|
||||
#pragma clang diagnostic ignored "-Wunused-variable"
|
||||
#pragma clang diagnostic ignored "-Wcomment"
|
||||
|
||||
/* Base instance with offsets. */
|
||||
#define gpu_BaseInstance gl_BaseInstanceARB
|
||||
#define gpu_InstanceIndex (gl_InstanceID + gpu_BaseInstance)
|
||||
|
|
|
@ -315,6 +315,7 @@ static void set_bsdf_socket_values(bNode *bsdf, Material *mat, const MTLMaterial
|
|||
}
|
||||
if (do_tranparency || (alpha >= 0.0f && alpha < 1.0f)) {
|
||||
mat->blend_method = MA_BM_BLEND;
|
||||
mat->blend_flag |= MA_BL_HIDE_BACKFACE;
|
||||
}
|
||||
|
||||
if (mtl_mat.sheen >= 0) {
|
||||
|
@ -393,6 +394,7 @@ static void add_image_textures(Main *bmain,
|
|||
else if (key == int(MTLTexMapType::Alpha)) {
|
||||
link_sockets(ntree, image_node, "Alpha", bsdf, tex_map_type_to_socket_id[key]);
|
||||
mat->blend_method = MA_BM_BLEND;
|
||||
mat->blend_flag |= MA_BL_HIDE_BACKFACE;
|
||||
}
|
||||
else {
|
||||
link_sockets(ntree, image_node, "Color", bsdf, tex_map_type_to_socket_id[key]);
|
||||
|
|
|
@ -140,6 +140,10 @@ typedef struct AssetLibraryReference {
|
|||
* Not part of the core design, we should try to get rid of it. Only needed to wrap FileDirEntry
|
||||
* into a type with PropertyGroup as base, so we can have an RNA collection of #AssetHandle's to
|
||||
* pass to the UI.
|
||||
*
|
||||
* \warning Never store this! When using #ED_assetlist_iterate(), only access it within the
|
||||
* iterator function. The contained file data can be freed since the file cache has a
|
||||
* maximum number of items.
|
||||
*/
|
||||
#
|
||||
#
|
||||
|
|
|
@ -578,6 +578,17 @@ static void rna_def_asset_handle(BlenderRNA *brna)
|
|||
rna_def_asset_handle_api(srna);
|
||||
}
|
||||
|
||||
static void rna_def_asset_representation(BlenderRNA *brna)
|
||||
{
|
||||
StructRNA *srna;
|
||||
|
||||
srna = RNA_def_struct(brna, "AssetRepresentation", NULL);
|
||||
RNA_def_struct_ui_text(srna,
|
||||
"Asset Representation",
|
||||
"Information about an entity that makes it possible for the asset system "
|
||||
"to deal with the entity as asset");
|
||||
}
|
||||
|
||||
static void rna_def_asset_catalog_path(BlenderRNA *brna)
|
||||
{
|
||||
StructRNA *srna = RNA_def_struct(brna, "AssetCatalogPath", NULL);
|
||||
|
@ -610,6 +621,7 @@ void RNA_def_asset(BlenderRNA *brna)
|
|||
rna_def_asset_data(brna);
|
||||
rna_def_asset_library_reference(brna);
|
||||
rna_def_asset_handle(brna);
|
||||
rna_def_asset_representation(brna);
|
||||
rna_def_asset_catalog_path(brna);
|
||||
|
||||
RNA_define_animate_sdna(true);
|
||||
|
|
|
@ -826,7 +826,7 @@ static void rna_def_mask_splines(BlenderRNA *brna)
|
|||
NULL,
|
||||
NULL);
|
||||
RNA_def_property_flag(prop, PROP_EDITABLE | PROP_NEVER_UNLINK);
|
||||
RNA_def_property_ui_text(prop, "Active Spline", "Active spline of masking layer");
|
||||
RNA_def_property_ui_text(prop, "Active Point", "Active point of masking layer");
|
||||
}
|
||||
|
||||
static void rna_def_maskSplinePoints(BlenderRNA *brna)
|
||||
|
|
|
@ -4779,7 +4779,7 @@ static void rna_def_userdef_view(BlenderRNA *brna)
|
|||
/* mini axis */
|
||||
static const EnumPropertyItem mini_axis_type_items[] = {
|
||||
{USER_MINI_AXIS_TYPE_NONE, "NONE", 0, "Off", ""},
|
||||
{USER_MINI_AXIS_TYPE_MINIMAL, "MINIMAL", 0, "Simple Axis", ""},
|
||||
{USER_MINI_AXIS_TYPE_MINIMAL, "MINIMAL", 0, "Simple Axes", ""},
|
||||
{USER_MINI_AXIS_TYPE_GIZMO, "GIZMO", 0, "Interactive Navigation", ""},
|
||||
{0, NULL, 0, NULL, NULL},
|
||||
};
|
||||
|
@ -4789,7 +4789,7 @@ static void rna_def_userdef_view(BlenderRNA *brna)
|
|||
RNA_def_property_ui_text(
|
||||
prop,
|
||||
"Mini Axes Type",
|
||||
"Show a small rotating 3D axes in the top right corner of the 3D viewport");
|
||||
"Show small rotating 3D axes in the top right corner of the 3D viewport");
|
||||
RNA_def_property_update(prop, 0, "rna_userdef_gizmo_update");
|
||||
|
||||
prop = RNA_def_property(srna, "mini_axis_size", PROP_INT, PROP_PIXEL);
|
||||
|
|
|
@ -437,9 +437,6 @@ static void panel_draw(const bContext *C, Panel *panel)
|
|||
if (runtime_data->used_cpu) {
|
||||
uiItemL(layout, "Using both CPU and GPU subdivision", ICON_INFO);
|
||||
}
|
||||
else {
|
||||
uiItemL(layout, "Using GPU subdivision", ICON_INFO);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -337,7 +337,7 @@ DefNode(GeometryNode, GEO_NODE_INPUT_MESH_EDGE_ANGLE, 0, "MESH_EDGE_ANGLE", Inpu
|
|||
DefNode(GeometryNode, GEO_NODE_INPUT_MESH_EDGE_NEIGHBORS, 0, "MESH_EDGE_NEIGHBORS",InputMeshEdgeNeighbors, "Edge Neighbors", "Retrieve the number of faces that use each edge as one of their sides")
|
||||
DefNode(GeometryNode, GEO_NODE_INPUT_MESH_EDGE_VERTICES, 0, "MESH_EDGE_VERTICES", InputMeshEdgeVertices, "Edge Vertices", "Retrieve topology information relating to each edge of a mesh")
|
||||
DefNode(GeometryNode, GEO_NODE_INPUT_MESH_FACE_AREA, 0, "MESH_FACE_AREA", InputMeshFaceArea, "Face Area", "Calculate the surface area of a mesh's faces")
|
||||
DefNode(GeometryNode, GEO_NODE_INPUT_MESH_FACE_IS_PLANAR, 0, "MESH_FACE_IS_PLANAR",InputMeshFaceIsPlanar, "Is Face Planar", "Retrieve whether all triangles in a face are on the same plane, i.e. whether have the same normal")
|
||||
DefNode(GeometryNode, GEO_NODE_INPUT_MESH_FACE_IS_PLANAR, 0, "MESH_FACE_IS_PLANAR", InputMeshFaceIsPlanar, "Is Face Planar", "Retrieve whether all triangles in a face are on the same plane, i.e. whether they have the same normal")
|
||||
DefNode(GeometryNode, GEO_NODE_INPUT_MESH_FACE_NEIGHBORS, 0, "MESH_FACE_NEIGHBORS",InputMeshFaceNeighbors, "Face Neighbors", "Retrieve topology information relating to each face of a mesh")
|
||||
DefNode(GeometryNode, GEO_NODE_INPUT_MESH_ISLAND, 0, "MESH_ISLAND", InputMeshIsland, "Mesh Island", "Retrieve information about separate connected regions in a mesh")
|
||||
DefNode(GeometryNode, GEO_NODE_INPUT_MESH_VERTEX_NEIGHBORS, 0, "MESH_VERTEX_NEIGHBORS", InputMeshVertexNeighbors, "Vertex Neighbors", "Retrieve topology information relating to each vertex of a mesh")
|
||||
|
|
Loading…
Reference in New Issue