GPv3: Opacity modifier #116946
|
@ -230,7 +230,7 @@ endif
|
|||
ifndef PYTHON
|
||||
# If not overriden, first try using Python from LIBDIR.
|
||||
PYTHON:=$(LIBDIR)/python/bin/python$(PY_LIB_VERSION)
|
||||
ifeq (, $(PYTHON))
|
||||
ifeq (, $(wildcard $(PYTHON)))
|
||||
# If not available, use system python3 or python command.
|
||||
PYTHON:=python3
|
||||
ifeq (, $(shell command -v $(PYTHON)))
|
||||
|
|
|
@ -614,9 +614,9 @@ set(ZSTD_HASH_TYPE SHA256)
|
|||
set(ZSTD_FILE zstd-${ZSTD_VERSION}.tar.gz)
|
||||
set(ZSTD_CPE "cpe:2.3:a:facebook:zstandard:${ZSTD_VERSION}:*:*:*:*:*:*:*")
|
||||
|
||||
set(SSE2NEON_VERSION 4614a1a8b8be9ad8ac30f4d1e5e2348cc5212ef7)
|
||||
set(SSE2NEON_VERSION cfaa59fc04fecb117c0a0f3fe9c82dece6f359ad)
|
||||
set(SSE2NEON_URI https://github.com/DLTcollab/sse2neon/archive/${SSE2NEON_VERSION}.tar.gz)
|
||||
set(SSE2NEON_HASH dd55460db7b7db51e575071fd4200d54a2b53551844ac2e571b4d46631c5af45)
|
||||
set(SSE2NEON_HASH 5491c5038a301a6b0ba0531e516568bb50d165d206360f03d8d56558a2490669)
|
||||
set(SSE2NEON_HASH_TYPE SHA256)
|
||||
set(SSE2NEON_FILE sse2neon-${SSE2NEON_VERSION}.tar.gz)
|
||||
|
||||
|
|
|
@ -705,31 +705,7 @@ class NODE_PT_active_node_properties(Panel):
|
|||
def draw(self, context):
|
||||
layout = self.layout
|
||||
node = context.active_node
|
||||
# set "node" context pointer for the panel layout
|
||||
layout.context_pointer_set("node", node)
|
||||
|
||||
if hasattr(node, "draw_buttons_ext"):
|
||||
node.draw_buttons_ext(context, layout)
|
||||
elif hasattr(node, "draw_buttons"):
|
||||
node.draw_buttons(context, layout)
|
||||
|
||||
# XXX this could be filtered further to exclude socket types
|
||||
# which don't have meaningful input values (e.g. cycles shader)
|
||||
value_inputs = [socket for socket in node.inputs if self.show_socket_input(socket)]
|
||||
if value_inputs:
|
||||
layout.separator()
|
||||
layout.label(text="Inputs:")
|
||||
for socket in value_inputs:
|
||||
row = layout.row()
|
||||
socket.draw(
|
||||
context,
|
||||
row,
|
||||
node,
|
||||
iface_(socket.label if socket.label else socket.name, socket.bl_rna.translation_context),
|
||||
)
|
||||
|
||||
def show_socket_input(self, socket):
|
||||
return hasattr(socket, "draw") and socket.enabled and not socket.is_linked
|
||||
layout.template_node_inputs(node)
|
||||
|
||||
|
||||
class NODE_PT_texture_mapping(Panel):
|
||||
|
|
|
@ -29,7 +29,7 @@ extern "C" {
|
|||
|
||||
/* Blender file format version. */
|
||||
#define BLENDER_FILE_VERSION BLENDER_VERSION
|
||||
#define BLENDER_FILE_SUBVERSION 10
|
||||
#define BLENDER_FILE_SUBVERSION 11
|
||||
|
||||
/* Minimum Blender version that supports reading file written with the current
|
||||
* version. Older Blender versions will test this and cancel loading the file, showing a warning to
|
||||
|
|
|
@ -476,6 +476,7 @@ static void write_node_socket_interface(BlendWriter *writer, const bNodeSocket *
|
|||
static bNodeSocket *make_socket(bNodeTree *ntree,
|
||||
const eNodeSocketInOut in_out,
|
||||
const StringRef idname,
|
||||
|
||||
const StringRef name,
|
||||
const StringRef identifier)
|
||||
{
|
||||
|
@ -501,6 +502,59 @@ static bNodeSocket *make_socket(bNodeTree *ntree,
|
|||
return sock;
|
||||
}
|
||||
|
||||
/* Include the subtype suffix for old socket idnames. */
|
||||
static StringRef get_legacy_socket_subtype_idname(StringRef idname, const void *socket_data)
|
||||
{
|
||||
if (idname == "NodeSocketFloat") {
|
||||
const bNodeSocketValueFloat &float_data = *static_cast<const bNodeSocketValueFloat *>(
|
||||
socket_data);
|
||||
switch (float_data.subtype) {
|
||||
case PROP_UNSIGNED:
|
||||
return "NodeSocketFloatUnsigned";
|
||||
case PROP_PERCENTAGE:
|
||||
return "NodeSocketFloatPercentage";
|
||||
case PROP_FACTOR:
|
||||
return "NodeSocketFloatFactor";
|
||||
case PROP_ANGLE:
|
||||
return "NodeSocketFloatAngle";
|
||||
case PROP_TIME:
|
||||
return "NodeSocketFloatTime";
|
||||
case PROP_TIME_ABSOLUTE:
|
||||
return "NodeSocketFloatTimeAbsolute";
|
||||
case PROP_DISTANCE:
|
||||
return "NodeSocketFloatDistance";
|
||||
}
|
||||
}
|
||||
if (idname == "NodeSocketInt") {
|
||||
const bNodeSocketValueInt &int_data = *static_cast<const bNodeSocketValueInt *>(socket_data);
|
||||
switch (int_data.subtype) {
|
||||
case PROP_UNSIGNED:
|
||||
return "NodeSocketIntUnsigned";
|
||||
case PROP_PERCENTAGE:
|
||||
return "NodeSocketIntPercentage";
|
||||
case PROP_FACTOR:
|
||||
return "NodeSocketIntFactor";
|
||||
}
|
||||
}
|
||||
if (idname == "NodeSocketVector") {
|
||||
const bNodeSocketValueVector &vector_data = *static_cast<const bNodeSocketValueVector *>(
|
||||
socket_data);
|
||||
switch (vector_data.subtype) {
|
||||
case PROP_TRANSLATION:
|
||||
return "NodeSocketVectorTranslation";
|
||||
case PROP_DIRECTION:
|
||||
return "NodeSocketVectorDirection";
|
||||
case PROP_VELOCITY:
|
||||
return "NodeSocketVectorVelocity";
|
||||
case PROP_ACCELERATION:
|
||||
return "NodeSocketVectorAcceleration";
|
||||
case PROP_EULER:
|
||||
return "NodeSocketVectorEuler";
|
||||
}
|
||||
}
|
||||
return idname;
|
||||
}
|
||||
|
||||
/**
|
||||
* Socket interface reconstruction for forward compatibility.
|
||||
* To enable previous Blender versions to read the new interface DNA data,
|
||||
|
@ -516,7 +570,11 @@ static void construct_interface_as_legacy_sockets(bNodeTree *ntree)
|
|||
auto make_legacy_socket = [&](const bNodeTreeInterfaceSocket &socket,
|
||||
eNodeSocketInOut in_out) -> bNodeSocket * {
|
||||
bNodeSocket *iosock = make_socket(
|
||||
ntree, in_out, socket.socket_type, socket.name ? socket.name : "", socket.identifier);
|
||||
ntree,
|
||||
in_out,
|
||||
get_legacy_socket_subtype_idname(socket.socket_type, socket.socket_data),
|
||||
socket.name ? socket.name : "",
|
||||
socket.identifier);
|
||||
if (!iosock) {
|
||||
return nullptr;
|
||||
}
|
||||
|
|
|
@ -1386,6 +1386,36 @@ static void version_geometry_nodes_use_rotation_socket(bNodeTree &ntree)
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Find the base socket name for an idname that may include a subtype. */
|
||||
static blender::StringRef legacy_socket_idname_to_socket_type(blender::StringRef idname)
|
||||
{
|
||||
using string_pair = std::pair<const char *, const char *>;
|
||||
static const string_pair subtypes_map[] = {{"NodeSocketFloatUnsigned", "NodeSocketFloat"},
|
||||
{"NodeSocketFloatPercentage", "NodeSocketFloat"},
|
||||
{"NodeSocketFloatFactor", "NodeSocketFloat"},
|
||||
{"NodeSocketFloatAngle", "NodeSocketFloat"},
|
||||
{"NodeSocketFloatTime", "NodeSocketFloat"},
|
||||
{"NodeSocketFloatTimeAbsolute", "NodeSocketFloat"},
|
||||
{"NodeSocketFloatDistance", "NodeSocketFloat"},
|
||||
{"NodeSocketIntUnsigned", "NodeSocketInt"},
|
||||
{"NodeSocketIntPercentage", "NodeSocketInt"},
|
||||
{"NodeSocketIntFactor", "NodeSocketInt"},
|
||||
{"NodeSocketVectorTranslation", "NodeSocketVector"},
|
||||
{"NodeSocketVectorDirection", "NodeSocketVector"},
|
||||
{"NodeSocketVectorVelocity", "NodeSocketVector"},
|
||||
{"NodeSocketVectorAcceleration", "NodeSocketVector"},
|
||||
{"NodeSocketVectorEuler", "NodeSocketVector"},
|
||||
{"NodeSocketVectorXYZ", "NodeSocketVector"}};
|
||||
for (const string_pair &pair : subtypes_map) {
|
||||
if (pair.first == idname) {
|
||||
return pair.second;
|
||||
}
|
||||
}
|
||||
/* Unchanged socket idname. */
|
||||
return idname;
|
||||
}
|
||||
|
||||
static bNodeTreeInterfaceItem *legacy_socket_move_to_interface(bNodeSocket &legacy_socket,
|
||||
const eNodeSocketInOut in_out)
|
||||
{
|
||||
|
@ -1396,7 +1426,10 @@ static bNodeTreeInterfaceItem *legacy_socket_move_to_interface(bNodeSocket &lega
|
|||
new_socket->name = BLI_strdup(legacy_socket.name);
|
||||
new_socket->identifier = BLI_strdup(legacy_socket.identifier);
|
||||
new_socket->description = BLI_strdup(legacy_socket.description);
|
||||
new_socket->socket_type = BLI_strdup(legacy_socket.idname);
|
||||
/* If the socket idname includes a subtype (e.g. "NodeSocketFloatFactor") this will convert it to
|
||||
* the base type name ("NodeSocketFloat"). */
|
||||
new_socket->socket_type = BLI_strdup(
|
||||
legacy_socket_idname_to_socket_type(legacy_socket.idname).data());
|
||||
new_socket->flag = (in_out == SOCK_IN ? NODE_INTERFACE_SOCKET_INPUT :
|
||||
NODE_INTERFACE_SOCKET_OUTPUT);
|
||||
SET_FLAG_FROM_TEST(
|
||||
|
@ -1444,6 +1477,28 @@ static void versioning_convert_node_tree_socket_lists_to_interface(bNodeTree *nt
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Original node tree interface conversion in did not convert socket idnames with subtype suffixes
|
||||
* to correct socket base types (see #versioning_convert_node_tree_socket_lists_to_interface).
|
||||
*/
|
||||
static void versioning_fix_socket_subtype_idnames(bNodeTree *ntree)
|
||||
{
|
||||
bNodeTreeInterface &tree_interface = ntree->tree_interface;
|
||||
|
||||
tree_interface.foreach_item([](bNodeTreeInterfaceItem &item) -> bool {
|
||||
if (item.item_type == NODE_INTERFACE_SOCKET) {
|
||||
bNodeTreeInterfaceSocket &socket = reinterpret_cast<bNodeTreeInterfaceSocket &>(item);
|
||||
blender::StringRef corrected_socket_type = legacy_socket_idname_to_socket_type(
|
||||
socket.socket_type);
|
||||
if (socket.socket_type != corrected_socket_type) {
|
||||
MEM_freeN(socket.socket_type);
|
||||
socket.socket_type = BLI_strdup(corrected_socket_type.data());
|
||||
}
|
||||
}
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
/* Convert coat inputs on the Principled BSDF. */
|
||||
static void version_principled_bsdf_coat(bNodeTree *ntree)
|
||||
{
|
||||
|
@ -2577,6 +2632,14 @@ void blo_do_versions_400(FileData *fd, Library * /*lib*/, Main *bmain)
|
|||
}
|
||||
}
|
||||
|
||||
if (MAIN_VERSION_FILE_ATLEAST(bmain, 400, 20) && !MAIN_VERSION_FILE_ATLEAST(bmain, 401, 11)) {
|
||||
/* Convert old socket lists into new interface items. */
|
||||
FOREACH_NODETREE_BEGIN (bmain, ntree, id) {
|
||||
versioning_fix_socket_subtype_idnames(ntree);
|
||||
}
|
||||
FOREACH_NODETREE_END;
|
||||
}
|
||||
|
||||
/**
|
||||
* Always bump subversion in BKE_blender_version.h when adding versioning
|
||||
* code here, and wrap it inside a MAIN_VERSION_FILE_ATLEAST check.
|
||||
|
|
|
@ -354,6 +354,7 @@ void LightModule::end_sync()
|
|||
/* Default to 32 as this is likely to be the maximum
|
||||
* tile size used by hardware or compute shading. */
|
||||
uint tile_size = 16;
|
||||
bool tile_size_valid = false;
|
||||
do {
|
||||
tile_size *= 2;
|
||||
tiles_extent = math::divide_ceil(render_extent, int2(tile_size));
|
||||
|
@ -362,8 +363,9 @@ void LightModule::end_sync()
|
|||
continue;
|
||||
}
|
||||
total_word_count_ = tile_count * word_per_tile;
|
||||
tile_size_valid = true;
|
||||
|
||||
} while (total_word_count_ > max_word_count_threshold);
|
||||
} while (total_word_count_ > max_word_count_threshold || !tile_size_valid);
|
||||
/* Keep aligned with storage buffer requirements. */
|
||||
total_word_count_ = ceil_to_multiple_u(total_word_count_, 32);
|
||||
|
||||
|
|
|
@ -2714,6 +2714,10 @@ void uiTemplateGreasePencilLayerTree(uiLayout *layout, bContext *C);
|
|||
#endif
|
||||
|
||||
void uiTemplateNodeTreeInterface(uiLayout *layout, PointerRNA *ptr);
|
||||
/**
|
||||
* Draw all node buttons and socket default values with the same panel structure used by the node.
|
||||
*/
|
||||
void uiTemplateNodeInputs(uiLayout *layout, bContext *C, PointerRNA *ptr);
|
||||
|
||||
/**
|
||||
* \return: A RNA pointer for the operator properties.
|
||||
|
|
|
@ -70,6 +70,7 @@ set(SRC
|
|||
interface_template_bone_collection_tree.cc
|
||||
interface_template_light_linking.cc
|
||||
interface_template_list.cc
|
||||
interface_template_node_inputs.cc
|
||||
interface_template_node_tree_interface.cc
|
||||
interface_template_search_menu.cc
|
||||
interface_template_search_operator.cc
|
||||
|
|
|
@ -0,0 +1,142 @@
|
|||
/* SPDX-FileCopyrightText: 2023 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
/** \file
|
||||
* \ingroup edinterface
|
||||
*/
|
||||
|
||||
#include "BLI_vector.hh"
|
||||
|
||||
#include "BKE_context.hh"
|
||||
#include "BKE_node.hh"
|
||||
#include "BKE_node_runtime.hh"
|
||||
#include "BKE_screen.hh"
|
||||
|
||||
#include "BLT_translation.h"
|
||||
|
||||
#include "NOD_node_declaration.hh"
|
||||
|
||||
#include "RNA_access.hh"
|
||||
#include "RNA_prototypes.h"
|
||||
|
||||
#include "UI_interface.hh"
|
||||
#include "UI_resources.hh"
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Node Input Buttons Template
|
||||
* \{ */
|
||||
|
||||
using blender::nodes::ItemDeclaration;
|
||||
using blender::nodes::NodeDeclaration;
|
||||
using blender::nodes::PanelDeclaration;
|
||||
using blender::nodes::SocketDeclaration;
|
||||
|
||||
using ItemIterator = blender::Vector<blender::nodes::ItemDeclarationPtr>::const_iterator;
|
||||
|
||||
namespace blender::ui::nodes {
|
||||
|
||||
static void draw_node_input(bContext *C,
|
||||
uiLayout *layout,
|
||||
PointerRNA *node_ptr,
|
||||
bNodeSocket &socket)
|
||||
{
|
||||
BLI_assert(socket.typeinfo != nullptr);
|
||||
/* Ignore disabled sockets and linked sockets and sockets without a `draw` callback. */
|
||||
if (!socket.is_available() || (socket.flag & SOCK_IS_LINKED) || socket.typeinfo->draw == nullptr)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
PointerRNA socket_ptr = RNA_pointer_create(node_ptr->owner_id, &RNA_NodeSocket, &socket);
|
||||
const char *text = IFACE_(bke::nodeSocketLabel(&socket));
|
||||
socket.typeinfo->draw(C, layout, &socket_ptr, node_ptr, text);
|
||||
}
|
||||
|
||||
static void draw_node_input(bContext *C,
|
||||
uiLayout *layout,
|
||||
PointerRNA *node_ptr,
|
||||
StringRefNull identifier)
|
||||
{
|
||||
bNode &node = *static_cast<bNode *>(node_ptr->data);
|
||||
bNodeSocket *socket = node.runtime->inputs_by_identifier.lookup(identifier);
|
||||
draw_node_input(C, layout, node_ptr, *socket);
|
||||
}
|
||||
|
||||
/* Consume the item range, draw buttons if layout is not null. */
|
||||
static void handle_node_declaration_items(bContext *C,
|
||||
Panel *root_panel,
|
||||
uiLayout *layout,
|
||||
PointerRNA *node_ptr,
|
||||
ItemIterator &item_iter,
|
||||
const ItemIterator item_end)
|
||||
{
|
||||
while (item_iter != item_end) {
|
||||
const ItemDeclaration *item_decl = item_iter->get();
|
||||
++item_iter;
|
||||
|
||||
if (const SocketDeclaration *socket_decl = dynamic_cast<const SocketDeclaration *>(item_decl))
|
||||
{
|
||||
if (layout && socket_decl->in_out == SOCK_IN) {
|
||||
draw_node_input(C, layout, node_ptr, socket_decl->identifier);
|
||||
}
|
||||
}
|
||||
else if (const PanelDeclaration *panel_decl = dynamic_cast<const PanelDeclaration *>(
|
||||
item_decl))
|
||||
{
|
||||
const ItemIterator panel_item_end = item_iter + panel_decl->num_child_decls;
|
||||
BLI_assert(panel_item_end <= item_end);
|
||||
|
||||
/* Use a root panel property to toggle open/closed state. */
|
||||
const std::string panel_idname = "NodePanel" + std::to_string(panel_decl->identifier);
|
||||
LayoutPanelState *state = BKE_panel_layout_panel_state_ensure(
|
||||
root_panel, panel_idname.c_str(), panel_decl->default_collapsed);
|
||||
PointerRNA state_ptr = RNA_pointer_create(nullptr, &RNA_LayoutPanelState, state);
|
||||
uiLayout *panel_layout = uiLayoutPanel(
|
||||
C, layout, IFACE_(panel_decl->name.c_str()), &state_ptr, "is_open");
|
||||
/* Draw panel buttons at the top of each panel section. */
|
||||
if (panel_layout && panel_decl->draw_buttons) {
|
||||
panel_decl->draw_buttons(panel_layout, C, node_ptr);
|
||||
}
|
||||
|
||||
handle_node_declaration_items(
|
||||
C, root_panel, panel_layout, node_ptr, item_iter, panel_item_end);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace blender::ui::nodes
|
||||
|
||||
void uiTemplateNodeInputs(uiLayout *layout, bContext *C, PointerRNA *ptr)
|
||||
{
|
||||
bNodeTree &tree = *reinterpret_cast<bNodeTree *>(ptr->owner_id);
|
||||
bNode &node = *static_cast<bNode *>(ptr->data);
|
||||
|
||||
tree.ensure_topology_cache();
|
||||
|
||||
BLI_assert(node.typeinfo != nullptr);
|
||||
/* Draw top-level node buttons. */
|
||||
if (node.typeinfo->draw_buttons_ex) {
|
||||
node.typeinfo->draw_buttons_ex(layout, C, ptr);
|
||||
}
|
||||
else if (node.typeinfo->draw_buttons) {
|
||||
node.typeinfo->draw_buttons(layout, C, ptr);
|
||||
}
|
||||
|
||||
if (node.declaration()) {
|
||||
/* Draw socket inputs and panel buttons in the order of declaration panels. */
|
||||
ItemIterator item_iter = node.declaration()->items.begin();
|
||||
const ItemIterator item_end = node.declaration()->items.end();
|
||||
Panel *root_panel = uiLayoutGetRootPanel(layout);
|
||||
blender::ui::nodes::handle_node_declaration_items(
|
||||
C, root_panel, layout, ptr, item_iter, item_end);
|
||||
}
|
||||
else {
|
||||
/* Draw socket values using the flat inputs list. */
|
||||
for (bNodeSocket *input : node.runtime->inputs) {
|
||||
blender::ui::nodes::draw_node_input(C, layout, ptr, *input);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** \} */
|
|
@ -1636,24 +1636,13 @@ const float *SCULPT_brush_frontface_normal_from_falloff_shape(SculptSession *ss,
|
|||
return ss->cache->view_normal;
|
||||
}
|
||||
|
||||
static float frontface(const Brush *br,
|
||||
const float3 &sculpt_normal,
|
||||
const float3 &no,
|
||||
const float3 &fno)
|
||||
static float frontface(const Brush &brush, const float3 &view_normal, const float3 &normal)
|
||||
{
|
||||
using namespace blender;
|
||||
if (!(br->flag & BRUSH_FRONTFACE)) {
|
||||
if (!(brush.flag & BRUSH_FRONTFACE)) {
|
||||
return 1.0f;
|
||||
}
|
||||
|
||||
float dot;
|
||||
if (no) {
|
||||
dot = math::dot(no, sculpt_normal);
|
||||
}
|
||||
else {
|
||||
dot = math::dot(fno, sculpt_normal);
|
||||
}
|
||||
return dot > 0.0f ? dot : 0.0f;
|
||||
return std::max(math::dot(normal, view_normal), 0.0f);
|
||||
}
|
||||
|
||||
#if 0
|
||||
|
@ -2400,7 +2389,7 @@ float SCULPT_brush_strength_factor(
|
|||
|
||||
/* Falloff curve. */
|
||||
avg *= BKE_brush_curve_strength(brush, final_len, cache->radius);
|
||||
avg *= frontface(brush, cache->view_normal, vno, fno);
|
||||
avg *= frontface(*brush, cache->view_normal, vno ? vno : fno);
|
||||
|
||||
/* Paint mask. */
|
||||
avg *= 1.0f - mask;
|
||||
|
@ -2435,7 +2424,7 @@ void SCULPT_brush_strength_color(
|
|||
|
||||
/* Falloff curve. */
|
||||
const float falloff = BKE_brush_curve_strength(brush, final_len, cache->radius) *
|
||||
frontface(brush, cache->view_normal, vno, fno);
|
||||
frontface(*brush, cache->view_normal, vno ? vno : fno);
|
||||
|
||||
/* Paint mask. */
|
||||
const float paint_mask = 1.0f - mask;
|
||||
|
|
|
@ -28,25 +28,25 @@ struct TransformUserData {
|
|||
/** \brief Destination image buffer to write to. */
|
||||
ImBuf *dst;
|
||||
/** \brief UV coordinates at the origin (0,0) in source image space. */
|
||||
double2 start_uv;
|
||||
float2 start_uv;
|
||||
|
||||
/**
|
||||
* \brief delta UV coordinates along the source image buffer, when moving a single pixel in the X
|
||||
* axis of the dst image buffer.
|
||||
*/
|
||||
double2 add_x;
|
||||
float2 add_x;
|
||||
|
||||
/**
|
||||
* \brief delta UV coordinate along the source image buffer, when moving a single pixel in the Y
|
||||
* axes of the dst image buffer.
|
||||
*/
|
||||
double2 add_y;
|
||||
float2 add_y;
|
||||
|
||||
struct {
|
||||
/**
|
||||
* Contains per sub-sample a delta to be added to the uv of the source image buffer.
|
||||
*/
|
||||
Vector<double2, 9> delta_uvs;
|
||||
Vector<float2, 9> delta_uvs;
|
||||
} subsampling;
|
||||
|
||||
struct {
|
||||
|
@ -76,29 +76,29 @@ struct TransformUserData {
|
|||
private:
|
||||
void init_start_uv(const float4x4 &transform_matrix)
|
||||
{
|
||||
start_uv = double2(transform_matrix.location().xy());
|
||||
start_uv = transform_matrix.location().xy();
|
||||
}
|
||||
|
||||
void init_add_x(const float4x4 &transform_matrix)
|
||||
{
|
||||
add_x = double2(transform_matrix.x_axis());
|
||||
add_x = transform_matrix.x_axis().xy();
|
||||
}
|
||||
|
||||
void init_add_y(const float4x4 &transform_matrix)
|
||||
{
|
||||
add_y = double2(transform_matrix.y_axis());
|
||||
add_y = transform_matrix.y_axis().xy();
|
||||
}
|
||||
|
||||
void init_subsampling(const int num_subsamples)
|
||||
{
|
||||
double2 subsample_add_x = add_x / num_subsamples;
|
||||
double2 subsample_add_y = add_y / num_subsamples;
|
||||
double2 offset_x = -add_x * 0.5 + subsample_add_x * 0.5;
|
||||
double2 offset_y = -add_y * 0.5 + subsample_add_y * 0.5;
|
||||
float2 subsample_add_x = add_x / num_subsamples;
|
||||
float2 subsample_add_y = add_y / num_subsamples;
|
||||
float2 offset_x = -add_x * 0.5f + subsample_add_x * 0.5f;
|
||||
float2 offset_y = -add_y * 0.5f + subsample_add_y * 0.5f;
|
||||
|
||||
for (int y : IndexRange(0, num_subsamples)) {
|
||||
for (int x : IndexRange(0, num_subsamples)) {
|
||||
double2 delta_uv = offset_x + offset_y;
|
||||
float2 delta_uv = offset_x + offset_y;
|
||||
delta_uv += x * subsample_add_x;
|
||||
delta_uv += y * subsample_add_y;
|
||||
subsampling.delta_uvs.append(delta_uv);
|
||||
|
@ -150,7 +150,7 @@ struct CropSource {
|
|||
*
|
||||
* Uses user_data.src_crop to determine if the uv coordinate should be skipped.
|
||||
*/
|
||||
static bool should_discard(const TransformUserData &user_data, const double2 &uv)
|
||||
static bool should_discard(const TransformUserData &user_data, const float2 &uv)
|
||||
{
|
||||
return uv.x < user_data.src_crop.xmin || uv.x >= user_data.src_crop.xmax ||
|
||||
uv.y < user_data.src_crop.ymin || uv.y >= user_data.src_crop.ymax;
|
||||
|
@ -166,7 +166,7 @@ struct NoDiscard {
|
|||
*
|
||||
* Will never discard any pixels.
|
||||
*/
|
||||
static bool should_discard(const TransformUserData & /*user_data*/, const double2 & /*uv*/)
|
||||
static bool should_discard(const TransformUserData & /*user_data*/, const float2 & /*uv*/)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
@ -301,10 +301,10 @@ class Sampler {
|
|||
static const int ChannelLen = NumChannels;
|
||||
using SampleType = Pixel<StorageType, NumChannels>;
|
||||
|
||||
void sample(const ImBuf *source, const double2 &uv, SampleType &r_sample)
|
||||
void sample(const ImBuf *source, const float2 &uv, SampleType &r_sample)
|
||||
{
|
||||
float u = float(uv.x);
|
||||
float v = float(uv.y);
|
||||
float u = uv.x;
|
||||
float v = uv.y;
|
||||
if constexpr (UVWrapping) {
|
||||
u = wrap_uv(u, source->x);
|
||||
v = wrap_uv(v, source->y);
|
||||
|
@ -519,21 +519,19 @@ class ScanlineProcessor {
|
|||
void process_one_sample_per_pixel(const TransformUserData *user_data, int scanline)
|
||||
{
|
||||
/* Note: sample at pixel center for proper filtering. */
|
||||
double pixel_x = user_data->destination_region.x_range.first() + 0.5;
|
||||
double pixel_y = scanline + 0.5;
|
||||
double2 uv = user_data->start_uv + user_data->add_x * pixel_x + user_data->add_y * pixel_y;
|
||||
float pixel_x = 0.5f;
|
||||
float pixel_y = scanline + 0.5f;
|
||||
float2 uv0 = user_data->start_uv + user_data->add_x * pixel_x + user_data->add_y * pixel_y;
|
||||
|
||||
output.init_pixel_pointer(user_data->dst,
|
||||
int2(user_data->destination_region.x_range.first(), scanline));
|
||||
for (int xi : user_data->destination_region.x_range) {
|
||||
UNUSED_VARS(xi);
|
||||
float2 uv = uv0 + xi * user_data->add_x;
|
||||
if (!discarder.should_discard(*user_data, uv)) {
|
||||
typename Sampler::SampleType sample;
|
||||
sampler.sample(user_data->src, uv, sample);
|
||||
channel_converter.convert_and_store(sample, output);
|
||||
}
|
||||
|
||||
uv += user_data->add_x;
|
||||
output.increase_pixel_pointer();
|
||||
}
|
||||
}
|
||||
|
@ -541,20 +539,20 @@ class ScanlineProcessor {
|
|||
void process_with_subsampling(const TransformUserData *user_data, int scanline)
|
||||
{
|
||||
/* Note: sample at pixel center for proper filtering. */
|
||||
double pixel_x = user_data->destination_region.x_range.first() + 0.5;
|
||||
double pixel_y = scanline + 0.5;
|
||||
double2 uv = user_data->start_uv + user_data->add_x * pixel_x + user_data->add_y * pixel_y;
|
||||
float pixel_x = 0.5f;
|
||||
float pixel_y = scanline + 0.5f;
|
||||
float2 uv0 = user_data->start_uv + user_data->add_x * pixel_x + user_data->add_y * pixel_y;
|
||||
|
||||
output.init_pixel_pointer(user_data->dst,
|
||||
int2(user_data->destination_region.x_range.first(), scanline));
|
||||
for (int xi : user_data->destination_region.x_range) {
|
||||
UNUSED_VARS(xi);
|
||||
float2 uv = uv0 + xi * user_data->add_x;
|
||||
typename Sampler::SampleType sample;
|
||||
sample.clear();
|
||||
int num_subsamples_added = 0;
|
||||
|
||||
for (const double2 &delta_uv : user_data->subsampling.delta_uvs) {
|
||||
const double2 subsample_uv = uv + delta_uv;
|
||||
for (const float2 &delta_uv : user_data->subsampling.delta_uvs) {
|
||||
const float2 subsample_uv = uv + delta_uv;
|
||||
if (!discarder.should_discard(*user_data, subsample_uv)) {
|
||||
typename Sampler::SampleType sub_sample;
|
||||
sampler.sample(user_data->src, subsample_uv, sub_sample);
|
||||
|
@ -568,7 +566,6 @@ class ScanlineProcessor {
|
|||
user_data->subsampling.delta_uvs.size();
|
||||
channel_converter.mix_and_store(sample, output, mix_weight);
|
||||
}
|
||||
uv += user_data->add_x;
|
||||
output.increase_pixel_pointer();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
|
||||
#include "BLI_color.hh"
|
||||
#include "BLI_math_matrix.hh"
|
||||
#include "BLI_math_quaternion_types.hh"
|
||||
#include "IMB_imbuf.h"
|
||||
|
||||
namespace blender::imbuf::tests {
|
||||
|
@ -109,4 +110,37 @@ TEST(imbuf_transform, bicubic_fractional_larger)
|
|||
IMB_freeImBuf(res);
|
||||
}
|
||||
|
||||
TEST(imbuf_transform, nearest_very_large_scale)
|
||||
{
|
||||
/* Create 511x1 black image, with three middle pixels being red/green/blue. */
|
||||
ImBuf *src = IMB_allocImBuf(511, 1, 32, IB_rect);
|
||||
ColorTheme4b col_r = ColorTheme4b(255, 0, 0, 255);
|
||||
ColorTheme4b col_g = ColorTheme4b(0, 255, 0, 255);
|
||||
ColorTheme4b col_b = ColorTheme4b(0, 0, 255, 255);
|
||||
ColorTheme4b col_0 = ColorTheme4b(0, 0, 0, 0);
|
||||
ColorTheme4b *src_col = reinterpret_cast<ColorTheme4b *>(src->byte_buffer.data);
|
||||
src_col[254] = col_r;
|
||||
src_col[255] = col_g;
|
||||
src_col[256] = col_b;
|
||||
|
||||
/* Create 3841x1 image, and scale the input image so that the three middle
|
||||
* pixels cover almost all of it, except the rightmost pixel. */
|
||||
ImBuf *res = IMB_allocImBuf(3841, 1, 32, IB_rect);
|
||||
float4x4 matrix = math::from_loc_rot_scale<float4x4>(
|
||||
float3(254, 0, 0), math::Quaternion::identity(), float3(3.0f / 3840.0f, 1, 1));
|
||||
IMB_transform(
|
||||
src, res, IMB_TRANSFORM_MODE_REGULAR, IMB_FILTER_NEAREST, 1, matrix.ptr(), nullptr);
|
||||
|
||||
/* Check result: leftmost red, middle green, two rightmost pixels blue and black.
|
||||
* If the transform code internally does not have enough precision while stepping
|
||||
* through the scanline, the rightmost side will not come out correctly. */
|
||||
const ColorTheme4b *got = reinterpret_cast<ColorTheme4b *>(res->byte_buffer.data);
|
||||
EXPECT_EQ(got[0], col_r);
|
||||
EXPECT_EQ(got[res->x / 2], col_g);
|
||||
EXPECT_EQ(got[res->x - 2], col_b);
|
||||
EXPECT_EQ(got[res->x - 1], col_0);
|
||||
IMB_freeImBuf(src);
|
||||
IMB_freeImBuf(res);
|
||||
}
|
||||
|
||||
} // namespace blender::imbuf::tests
|
||||
|
|
|
@ -325,6 +325,13 @@ static StructRNA *rna_KeyingSetInfo_register(Main *bmain,
|
|||
/* check if we have registered this info before, and remove it */
|
||||
ksi = ANIM_keyingset_info_find_name(dummy_ksi.idname);
|
||||
if (ksi) {
|
||||
BKE_reportf(reports,
|
||||
RPT_INFO,
|
||||
"%s '%s', bl_idname '%s' has been registered before, unregistering previous",
|
||||
error_prefix,
|
||||
identifier,
|
||||
dummy_ksi.idname);
|
||||
|
||||
StructRNA *srna = ksi->rna_ext.srna;
|
||||
if (!(srna && rna_KeyingSetInfo_unregister(bmain, srna))) {
|
||||
BKE_reportf(reports,
|
||||
|
|
|
@ -991,6 +991,13 @@ static StructRNA *rna_NodeTree_register(Main *bmain,
|
|||
/* check if we have registered this tree type before, and remove it */
|
||||
nt = ntreeTypeFind(dummy_nt.idname);
|
||||
if (nt) {
|
||||
BKE_reportf(reports,
|
||||
RPT_INFO,
|
||||
"Registering node tree class: '%s', bl_idname '%s' has been registered before, "
|
||||
"unregistering previous",
|
||||
identifier,
|
||||
dummy_nt.idname);
|
||||
|
||||
/* NOTE: unlike most types `nt->rna_ext.srna` doesn't need to be checked for nullptr. */
|
||||
if (!rna_NodeTree_unregister(bmain, nt->rna_ext.srna)) {
|
||||
BKE_reportf(reports,
|
||||
|
@ -1663,6 +1670,13 @@ static bNodeType *rna_Node_register_base(Main *bmain,
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
BKE_reportf(reports,
|
||||
RPT_INFO,
|
||||
"Registering node class: '%s', bl_idname '%s' has been registered before, "
|
||||
"unregistering previous",
|
||||
identifier,
|
||||
dummy_nt.idname);
|
||||
|
||||
/* NOTE: unlike most types `nt->rna_ext.srna` doesn't need to be checked for nullptr. */
|
||||
if (!rna_Node_unregister(bmain, nt->rna_ext.srna)) {
|
||||
BKE_reportf(reports,
|
||||
|
|
|
@ -348,6 +348,13 @@ static StructRNA *rna_RenderEngine_register(Main *bmain,
|
|||
et = static_cast<RenderEngineType *>(
|
||||
BLI_findstring(&R_engines, dummy_et.idname, offsetof(RenderEngineType, idname)));
|
||||
if (et) {
|
||||
BKE_reportf(reports,
|
||||
RPT_INFO,
|
||||
"%s '%s', bl_idname '%s' has been registered before, unregistering previous",
|
||||
error_prefix,
|
||||
identifier,
|
||||
dummy_et.idname);
|
||||
|
||||
StructRNA *srna = et->rna_ext.srna;
|
||||
if (!(srna && rna_RenderEngine_unregister(bmain, srna))) {
|
||||
BKE_reportf(reports,
|
||||
|
|
|
@ -315,6 +315,12 @@ static StructRNA *rna_Panel_register(Main *bmain,
|
|||
PanelType *pt_next = pt->next;
|
||||
StructRNA *srna = pt->rna_ext.srna;
|
||||
if (srna) {
|
||||
BKE_reportf(reports,
|
||||
RPT_INFO,
|
||||
"%s '%s', bl_idname '%s' has been registered before, unregistering previous",
|
||||
error_prefix,
|
||||
identifier,
|
||||
dummy_pt.idname);
|
||||
if (!rna_Panel_unregister(bmain, srna)) {
|
||||
BKE_reportf(reports,
|
||||
RPT_ERROR,
|
||||
|
@ -721,6 +727,13 @@ static StructRNA *rna_UIList_register(Main *bmain,
|
|||
/* Check if we have registered this UI-list type before, and remove it. */
|
||||
ult = WM_uilisttype_find(dummy_ult.idname, true);
|
||||
if (ult) {
|
||||
BKE_reportf(reports,
|
||||
RPT_INFO,
|
||||
"%s '%s', bl_idname '%s' has been registered before, unregistering previous",
|
||||
error_prefix,
|
||||
identifier,
|
||||
dummy_ult.idname);
|
||||
|
||||
StructRNA *srna = ult->rna_ext.srna;
|
||||
if (!(srna && rna_UIList_unregister(bmain, srna))) {
|
||||
BKE_reportf(reports,
|
||||
|
@ -852,6 +865,13 @@ static StructRNA *rna_Header_register(Main *bmain,
|
|||
ht = static_cast<HeaderType *>(
|
||||
BLI_findstring(&art->headertypes, dummy_ht.idname, offsetof(HeaderType, idname)));
|
||||
if (ht) {
|
||||
BKE_reportf(reports,
|
||||
RPT_INFO,
|
||||
"%s '%s', bl_idname '%s' has been registered before, unregistering previous",
|
||||
error_prefix,
|
||||
identifier,
|
||||
dummy_ht.idname);
|
||||
|
||||
StructRNA *srna = ht->rna_ext.srna;
|
||||
if (!(srna && rna_Header_unregister(bmain, srna))) {
|
||||
BKE_reportf(reports,
|
||||
|
@ -1002,6 +1022,13 @@ static StructRNA *rna_Menu_register(Main *bmain,
|
|||
/* check if we have registered this menu type before, and remove it */
|
||||
mt = WM_menutype_find(dummy_mt.idname, true);
|
||||
if (mt) {
|
||||
BKE_reportf(reports,
|
||||
RPT_INFO,
|
||||
"%s '%s', bl_idname '%s' has been registered before, unregistering previous",
|
||||
error_prefix,
|
||||
identifier,
|
||||
dummy_mt.idname);
|
||||
|
||||
StructRNA *srna = mt->rna_ext.srna;
|
||||
if (!(srna && rna_Menu_unregister(bmain, srna))) {
|
||||
BKE_reportf(reports,
|
||||
|
@ -1207,6 +1234,12 @@ static StructRNA *rna_AssetShelf_register(Main *bmain,
|
|||
LISTBASE_FOREACH (AssetShelfType *, iter_shelf_type, &space_type->asset_shelf_types) {
|
||||
if (STREQ(iter_shelf_type->idname, dummy_shelf_type.idname)) {
|
||||
if (iter_shelf_type->rna_ext.srna) {
|
||||
BKE_reportf(reports,
|
||||
RPT_INFO,
|
||||
"Registering asset shelf class: '%s' has been registered before, "
|
||||
"unregistering previous",
|
||||
dummy_shelf_type.idname);
|
||||
|
||||
rna_AssetShelf_unregister(bmain, iter_shelf_type->rna_ext.srna);
|
||||
}
|
||||
break;
|
||||
|
|
|
@ -2205,6 +2205,12 @@ void RNA_api_ui_layout(StructRNA *srna)
|
|||
"Node Tree Interface",
|
||||
"Interface of a node tree to display");
|
||||
RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
|
||||
|
||||
func = RNA_def_function(srna, "template_node_inputs", "uiTemplateNodeInputs");
|
||||
RNA_def_function_ui_description(func, "Show a node settings and input socket values");
|
||||
RNA_def_function_flag(func, FUNC_USE_CONTEXT);
|
||||
parm = RNA_def_pointer(func, "node", "Node", "Node", "Display inputs of this node");
|
||||
RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -82,6 +82,13 @@ static StructRNA *rna_USDHook_register(Main *bmain,
|
|||
/* check if we have registered this hook before, and remove it */
|
||||
hook = USD_find_hook_name(dummy_hook.idname);
|
||||
if (hook) {
|
||||
BKE_reportf(reports,
|
||||
RPT_INFO,
|
||||
"%s '%s', bl_idname '%s' has been registered before, unregistering previous",
|
||||
error_prefix,
|
||||
identifier,
|
||||
dummy_hook.idname);
|
||||
|
||||
StructRNA *srna = hook->rna_ext.srna;
|
||||
if (!rna_USDHook_unregister(bmain, srna)) {
|
||||
BKE_reportf(reports,
|
||||
|
|
|
@ -1059,6 +1059,13 @@ static StructRNA *rna_AddonPref_register(Main *bmain,
|
|||
/* Check if we have registered this add-on preference type before, and remove it. */
|
||||
apt = BKE_addon_pref_type_find(dummy_addon.module, true);
|
||||
if (apt) {
|
||||
BKE_reportf(reports,
|
||||
RPT_INFO,
|
||||
"%s '%s', bl_idname '%s' has been registered before, unregistering previous",
|
||||
error_prefix,
|
||||
identifier,
|
||||
dummy_apt.idname);
|
||||
|
||||
StructRNA *srna = apt->rna_ext.srna;
|
||||
if (!(srna && rna_AddonPref_unregister(bmain, srna))) {
|
||||
BKE_reportf(reports,
|
||||
|
|
|
@ -1185,6 +1185,13 @@ static StructRNA *rna_wmKeyConfigPref_register(Main *bmain,
|
|||
/* check if we have registered this keyconf-prefs type before, and remove it */
|
||||
kpt_rt = BKE_keyconfig_pref_type_find(dummy_kpt.idname, true);
|
||||
if (kpt_rt) {
|
||||
BKE_reportf(reports,
|
||||
RPT_INFO,
|
||||
"%s '%s', bl_idname '%s' has been registered before, unregistering previous",
|
||||
error_prefix,
|
||||
identifier,
|
||||
dummy_kpt.idname);
|
||||
|
||||
StructRNA *srna = kpt_rt->rna_ext.srna;
|
||||
if (!(srna && rna_wmKeyConfigPref_unregister(bmain, srna))) {
|
||||
BKE_reportf(reports,
|
||||
|
@ -1530,6 +1537,13 @@ static StructRNA *rna_Operator_register(Main *bmain,
|
|||
{
|
||||
wmOperatorType *ot = WM_operatortype_find(dummy_ot.idname, true);
|
||||
if (ot) {
|
||||
BKE_reportf(reports,
|
||||
RPT_INFO,
|
||||
"%s '%s', bl_idname '%s' has been registered before, unregistering previous",
|
||||
error_prefix,
|
||||
identifier,
|
||||
dummy_ot.idname);
|
||||
|
||||
StructRNA *srna = ot->rna_ext.srna;
|
||||
if (!(srna && rna_Operator_unregister(bmain, srna))) {
|
||||
BKE_reportf(reports,
|
||||
|
@ -1700,6 +1714,13 @@ static StructRNA *rna_MacroOperator_register(Main *bmain,
|
|||
{
|
||||
wmOperatorType *ot = WM_operatortype_find(dummy_ot.idname, true);
|
||||
if (ot) {
|
||||
BKE_reportf(reports,
|
||||
RPT_INFO,
|
||||
"%s '%s', bl_idname '%s' has been registered before, unregistering previous",
|
||||
error_prefix,
|
||||
identifier,
|
||||
dummy_ot.idname);
|
||||
|
||||
StructRNA *srna = ot->rna_ext.srna;
|
||||
if (!(srna && rna_Operator_unregister(bmain, srna))) {
|
||||
BKE_reportf(reports,
|
||||
|
|
|
@ -460,6 +460,13 @@ static StructRNA *rna_Gizmo_register(Main *bmain,
|
|||
{
|
||||
const wmGizmoType *gzt = WM_gizmotype_find(dummy_gt.idname, true);
|
||||
if (gzt) {
|
||||
BKE_reportf(reports,
|
||||
RPT_INFO,
|
||||
"%s '%s', bl_idname '%s' has been registered before, unregistering previous",
|
||||
error_prefix,
|
||||
identifier,
|
||||
dummy_gt.idname);
|
||||
|
||||
StructRNA *srna = gzt->rna_ext.srna;
|
||||
if (!(srna && rna_Gizmo_unregister(bmain, srna))) {
|
||||
BKE_reportf(reports,
|
||||
|
|
|
@ -14,7 +14,25 @@ import bpy
|
|||
args = None
|
||||
|
||||
|
||||
type_info = {
|
||||
base_idname = {
|
||||
"VALUE": "NodeSocketFloat",
|
||||
"INT": "NodeSocketInt",
|
||||
"BOOLEAN": "NodeSocketBool",
|
||||
"ROTATION": "NodeSocketRotation",
|
||||
"VECTOR": "NodeSocketVector",
|
||||
"RGBA": "NodeSocketColor",
|
||||
"STRING": "NodeSocketString",
|
||||
"SHADER": "NodeSocketShader",
|
||||
"OBJECT": "NodeSocketObject",
|
||||
"IMAGE": "NodeSocketImage",
|
||||
"GEOMETRY": "NodeSocketGeometry",
|
||||
"COLLECTION": "NodeSocketCollection",
|
||||
"TEXTURE": "NodeSocketTexture",
|
||||
"MATERIAL": "NodeSocketMaterial",
|
||||
}
|
||||
|
||||
|
||||
subtype_idname = {
|
||||
("VALUE", "NONE"): "NodeSocketFloat",
|
||||
("VALUE", "UNSIGNED"): "NodeSocketFloatUnsigned",
|
||||
("VALUE", "PERCENTAGE"): "NodeSocketFloatPercentage",
|
||||
|
@ -63,8 +81,12 @@ class SocketSpec():
|
|||
external_links: int = 1
|
||||
|
||||
@property
|
||||
def idname(self):
|
||||
return type_info[(self.type, self.subtype)]
|
||||
def base_idname(self):
|
||||
return base_idname[self.type]
|
||||
|
||||
@property
|
||||
def subtype_idname(self):
|
||||
return subtype_idname[(self.type, self.subtype)]
|
||||
|
||||
|
||||
class AbstractNodeGroupInterfaceTest(unittest.TestCase):
|
||||
|
@ -95,7 +117,7 @@ class AbstractNodeGroupInterfaceTest(unittest.TestCase):
|
|||
|
||||
# Examine the interface item.
|
||||
self.assertEqual(item.name, spec.name)
|
||||
self.assertEqual(item.bl_socket_idname, spec.idname)
|
||||
self.assertEqual(item.bl_socket_idname, spec.base_idname)
|
||||
self.assertEqual(item.identifier, spec.identifier)
|
||||
|
||||
# Types that have subtypes.
|
||||
|
@ -134,7 +156,7 @@ class AbstractNodeGroupInterfaceTest(unittest.TestCase):
|
|||
socket = next(s for s in node.inputs if s.identifier == spec.identifier)
|
||||
self.assertIsNotNone(socket, f"Could not find socket for group input identifier {spec.identifier}")
|
||||
self.assertEqual(socket.name, spec.name)
|
||||
self.assertEqual(socket.bl_idname, spec.idname)
|
||||
self.assertEqual(socket.bl_idname, spec.subtype_idname)
|
||||
self.assertEqual(socket.type, spec.type)
|
||||
self.assertEqual(socket.hide_value, spec.hide_value)
|
||||
if test_links:
|
||||
|
@ -147,7 +169,7 @@ class AbstractNodeGroupInterfaceTest(unittest.TestCase):
|
|||
self.assertIsNotNone(
|
||||
socket, f"Could not find group input socket for group input identifier {spec.identifier}")
|
||||
self.assertEqual(socket.name, spec.name)
|
||||
self.assertEqual(socket.bl_idname, spec.idname)
|
||||
self.assertEqual(socket.bl_idname, spec.subtype_idname)
|
||||
self.assertEqual(socket.type, spec.type)
|
||||
self.assertEqual(socket.hide_value, spec.hide_value)
|
||||
if test_links:
|
||||
|
@ -158,7 +180,7 @@ class AbstractNodeGroupInterfaceTest(unittest.TestCase):
|
|||
socket = next(s for s in node.outputs if s.identifier == spec.identifier)
|
||||
self.assertIsNotNone(socket, f"Could not find socket for group output identifier {spec.identifier}")
|
||||
self.assertEqual(socket.name, spec.name)
|
||||
self.assertEqual(socket.bl_idname, spec.idname)
|
||||
self.assertEqual(socket.bl_idname, spec.subtype_idname)
|
||||
self.assertEqual(socket.type, spec.type)
|
||||
self.assertEqual(socket.hide_value, spec.hide_value)
|
||||
if test_links:
|
||||
|
@ -171,7 +193,7 @@ class AbstractNodeGroupInterfaceTest(unittest.TestCase):
|
|||
self.assertIsNotNone(
|
||||
socket, f"Could not find group output socket for group output identifier {spec.identifier}")
|
||||
self.assertEqual(socket.name, spec.name)
|
||||
self.assertEqual(socket.bl_idname, spec.idname)
|
||||
self.assertEqual(socket.bl_idname, spec.subtype_idname)
|
||||
self.assertEqual(socket.type, spec.type)
|
||||
self.assertEqual(socket.hide_value, spec.hide_value)
|
||||
if test_links:
|
||||
|
|
Loading…
Reference in New Issue