UI: Asset Shelf (Experimental Feature) #104831

Closed
Julian Eisel wants to merge 399 commits from asset-shelf into main

When changing the target branch, be careful to rebase the branch in your fork to match. See documentation.
64 changed files with 877 additions and 900 deletions
Showing only changes of commit 0e3f5c6673 - Show all commits

38
README.md Normal file
View File

@ -0,0 +1,38 @@
<!--
Keep this document short & concise,
linking to external resources instead of including content in-line.
See 'release/text/readme.html' for the end user read-me.
-->
Blender
=======
Blender is the free and open source 3D creation suite.
It supports the entirety of the 3D pipeline-modeling, rigging, animation, simulation, rendering, compositing,
motion tracking and video editing.
![Blender screenshot](https://code.blender.org/wp-content/uploads/2018/12/springrg.jpg "Blender screenshot")
Project Pages
-------------
- [Main Website](http://www.blender.org)
- [Reference Manual](https://docs.blender.org/manual/en/latest/index.html)
- [User Community](https://www.blender.org/community/)
Development
-----------
- [Build Instructions](https://wiki.blender.org/wiki/Building_Blender)
- [Code Review & Bug Tracker](https://developer.blender.org)
- [Developer Forum](https://devtalk.blender.org)
- [Developer Documentation](https://wiki.blender.org)
License
-------
Blender as a whole is licensed under the GNU General Public License, Version 3.
Individual files may have a different, but compatible license.
See [blender.org/about/license](https://www.blender.org/about/license) for details.

View File

@ -85,15 +85,11 @@ elseif(WIN32 AND MSVC AND NOT CMAKE_CXX_COMPILER_ID MATCHES "Clang")
# there is no /arch:SSE3, but intrinsics are available anyway
if(CMAKE_CL_64)
set(CYCLES_SSE2_KERNEL_FLAGS "${CYCLES_KERNEL_FLAGS}")
set(CYCLES_SSE3_KERNEL_FLAGS "${CYCLES_KERNEL_FLAGS}")
set(CYCLES_SSE41_KERNEL_FLAGS "${CYCLES_KERNEL_FLAGS}")
set(CYCLES_AVX_KERNEL_FLAGS "${CYCLES_AVX_ARCH_FLAGS} ${CYCLES_KERNEL_FLAGS}")
set(CYCLES_AVX2_KERNEL_FLAGS "${CYCLES_AVX2_ARCH_FLAGS} ${CYCLES_KERNEL_FLAGS}")
else()
set(CYCLES_SSE2_KERNEL_FLAGS "/arch:SSE2 ${CYCLES_KERNEL_FLAGS}")
set(CYCLES_SSE3_KERNEL_FLAGS "/arch:SSE2 ${CYCLES_KERNEL_FLAGS}")
set(CYCLES_SSE41_KERNEL_FLAGS "/arch:SSE2 ${CYCLES_KERNEL_FLAGS}")
set(CYCLES_AVX_KERNEL_FLAGS "${CYCLES_AVX_ARCH_FLAGS} ${CYCLES_KERNEL_FLAGS}")
set(CYCLES_AVX2_KERNEL_FLAGS "${CYCLES_AVX2_ARCH_FLAGS} ${CYCLES_KERNEL_FLAGS}")
endif()
@ -126,11 +122,7 @@ elseif(CMAKE_COMPILER_IS_GNUCC OR (CMAKE_CXX_COMPILER_ID MATCHES "Clang"))
endif()
set(CYCLES_SSE2_KERNEL_FLAGS "${CYCLES_KERNEL_FLAGS} -msse -msse2")
set(CYCLES_SSE3_KERNEL_FLAGS "${CYCLES_SSE2_KERNEL_FLAGS} -msse3 -mssse3")
set(CYCLES_SSE41_KERNEL_FLAGS "${CYCLES_SSE3_KERNEL_FLAGS} -msse4.1")
if(CXX_HAS_AVX)
set(CYCLES_AVX_KERNEL_FLAGS "${CYCLES_SSE41_KERNEL_FLAGS} -mavx")
endif()
set(CYCLES_SSE41_KERNEL_FLAGS "${CYCLES_SSE2_KERNEL_FLAGS} -msse3 -mssse3 -msse4.1")
if(CXX_HAS_AVX2)
set(CYCLES_AVX2_KERNEL_FLAGS "${CYCLES_SSE41_KERNEL_FLAGS} -mavx -mavx2 -mfma -mlzcnt -mbmi -mbmi2 -mf16c")
endif()
@ -144,13 +136,8 @@ elseif(WIN32 AND CMAKE_CXX_COMPILER_ID MATCHES "Intel")
if(CXX_HAS_SSE)
set(CYCLES_SSE2_KERNEL_FLAGS "/QxSSE2")
set(CYCLES_SSE3_KERNEL_FLAGS "/QxSSSE3")
set(CYCLES_SSE41_KERNEL_FLAGS "/QxSSE4.1")
if(CXX_HAS_AVX)
set(CYCLES_AVX_KERNEL_FLAGS "/arch:AVX")
endif()
if(CXX_HAS_AVX2)
set(CYCLES_AVX2_KERNEL_FLAGS "/QxCORE-AVX2")
endif()
@ -174,13 +161,8 @@ elseif(CMAKE_CXX_COMPILER_ID MATCHES "Intel")
set(CYCLES_SSE2_KERNEL_FLAGS "-xsse2")
endif()
set(CYCLES_SSE3_KERNEL_FLAGS "-xssse3")
set(CYCLES_SSE41_KERNEL_FLAGS "-xsse4.1")
if(CXX_HAS_AVX)
set(CYCLES_AVX_KERNEL_FLAGS "-xavx")
endif()
if(CXX_HAS_AVX2)
set(CYCLES_AVX2_KERNEL_FLAGS "-xcore-avx2")
endif()
@ -190,15 +172,10 @@ endif()
if(CXX_HAS_SSE)
add_definitions(
-DWITH_KERNEL_SSE2
-DWITH_KERNEL_SSE3
-DWITH_KERNEL_SSE41
)
endif()
if(CXX_HAS_AVX)
add_definitions(-DWITH_KERNEL_AVX)
endif()
if(CXX_HAS_AVX2)
add_definitions(-DWITH_KERNEL_AVX2)
endif()

View File

@ -951,9 +951,7 @@ class CyclesRenderSettings(bpy.types.PropertyGroup):
return _cycles.debug_flags_update(scene)
debug_use_cpu_avx2: BoolProperty(name="AVX2", default=True)
debug_use_cpu_avx: BoolProperty(name="AVX", default=True)
debug_use_cpu_sse41: BoolProperty(name="SSE41", default=True)
debug_use_cpu_sse3: BoolProperty(name="SSE3", default=True)
debug_use_cpu_sse2: BoolProperty(name="SSE2", default=True)
debug_bvh_layout: EnumProperty(
name="BVH Layout",

View File

@ -2112,9 +2112,7 @@ class CYCLES_RENDER_PT_debug(CyclesDebugButtonsPanel, Panel):
row = col.row(align=True)
row.prop(cscene, "debug_use_cpu_sse2", toggle=True)
row.prop(cscene, "debug_use_cpu_sse3", toggle=True)
row.prop(cscene, "debug_use_cpu_sse41", toggle=True)
row.prop(cscene, "debug_use_cpu_avx", toggle=True)
row.prop(cscene, "debug_use_cpu_avx2", toggle=True)
col.prop(cscene, "debug_bvh_layout", text="BVH")

View File

@ -63,9 +63,7 @@ static void debug_flags_sync_from_scene(BL::Scene b_scene)
PointerRNA cscene = RNA_pointer_get(&b_scene.ptr, "cycles");
/* Synchronize CPU flags. */
flags.cpu.avx2 = get_boolean(cscene, "debug_use_cpu_avx2");
flags.cpu.avx = get_boolean(cscene, "debug_use_cpu_avx");
flags.cpu.sse41 = get_boolean(cscene, "debug_use_cpu_sse41");
flags.cpu.sse3 = get_boolean(cscene, "debug_use_cpu_sse3");
flags.cpu.sse2 = get_boolean(cscene, "debug_use_cpu_sse2");
flags.cpu.bvh_layout = (BVHLayout)get_enum(cscene, "debug_bvh_layout");
/* Synchronize CUDA flags. */

View File

@ -45,9 +45,7 @@ string device_cpu_capabilities()
{
string capabilities = "";
capabilities += system_cpu_support_sse2() ? "SSE2 " : "";
capabilities += system_cpu_support_sse3() ? "SSE3 " : "";
capabilities += system_cpu_support_sse41() ? "SSE41 " : "";
capabilities += system_cpu_support_avx() ? "AVX " : "";
capabilities += system_cpu_support_avx2() ? "AVX2" : "";
if (capabilities[capabilities.size() - 1] == ' ')
capabilities.resize(capabilities.size() - 1);

View File

@ -9,8 +9,7 @@ CCL_NAMESPACE_BEGIN
#define KERNEL_FUNCTIONS(name) \
KERNEL_NAME_EVAL(cpu, name), KERNEL_NAME_EVAL(cpu_sse2, name), \
KERNEL_NAME_EVAL(cpu_sse3, name), KERNEL_NAME_EVAL(cpu_sse41, name), \
KERNEL_NAME_EVAL(cpu_avx, name), KERNEL_NAME_EVAL(cpu_avx2, name)
KERNEL_NAME_EVAL(cpu_sse41, name), KERNEL_NAME_EVAL(cpu_avx2, name)
#define REGISTER_KERNEL(name) name(KERNEL_FUNCTIONS(name))
#define REGISTER_KERNEL_FILM_CONVERT(name) \

View File

@ -17,13 +17,10 @@ template<typename FunctionType> class CPUKernelFunction {
public:
CPUKernelFunction(FunctionType kernel_default,
FunctionType kernel_sse2,
FunctionType kernel_sse3,
FunctionType kernel_sse41,
FunctionType kernel_avx,
FunctionType kernel_avx2)
{
kernel_info_ = get_best_kernel_info(
kernel_default, kernel_sse2, kernel_sse3, kernel_sse41, kernel_avx, kernel_avx2);
kernel_info_ = get_best_kernel_info(kernel_default, kernel_sse2, kernel_sse41, kernel_avx2);
}
template<typename... Args> inline auto operator()(Args... args) const
@ -60,16 +57,12 @@ template<typename FunctionType> class CPUKernelFunction {
KernelInfo get_best_kernel_info(FunctionType kernel_default,
FunctionType kernel_sse2,
FunctionType kernel_sse3,
FunctionType kernel_sse41,
FunctionType kernel_avx,
FunctionType kernel_avx2)
{
/* Silence warnings about unused variables when compiling without some architectures. */
(void)kernel_sse2;
(void)kernel_sse3;
(void)kernel_sse41;
(void)kernel_avx;
(void)kernel_avx2;
#ifdef WITH_CYCLES_OPTIMIZED_KERNEL_AVX2
@ -78,24 +71,12 @@ template<typename FunctionType> class CPUKernelFunction {
}
#endif
#ifdef WITH_CYCLES_OPTIMIZED_KERNEL_AVX
if (DebugFlags().cpu.has_avx() && system_cpu_support_avx()) {
return KernelInfo("AVX", kernel_avx);
}
#endif
#ifdef WITH_CYCLES_OPTIMIZED_KERNEL_SSE41
if (DebugFlags().cpu.has_sse41() && system_cpu_support_sse41()) {
return KernelInfo("SSE4.1", kernel_sse41);
}
#endif
#ifdef WITH_CYCLES_OPTIMIZED_KERNEL_SSE3
if (DebugFlags().cpu.has_sse3() && system_cpu_support_sse3()) {
return KernelInfo("SSE3", kernel_sse3);
}
#endif
#ifdef WITH_CYCLES_OPTIMIZED_KERNEL_SSE2
if (DebugFlags().cpu.has_sse2() && system_cpu_support_sse2()) {
return KernelInfo("SSE2", kernel_sse2);

View File

@ -14,9 +14,7 @@ set(INC_SYS
set(SRC_KERNEL_DEVICE_CPU
device/cpu/kernel.cpp
device/cpu/kernel_sse2.cpp
device/cpu/kernel_sse3.cpp
device/cpu/kernel_sse41.cpp
device/cpu/kernel_avx.cpp
device/cpu/kernel_avx2.cpp
)
@ -940,14 +938,9 @@ set_source_files_properties(device/cpu/kernel.cpp PROPERTIES COMPILE_FLAGS "${CY
if(CXX_HAS_SSE)
set_source_files_properties(device/cpu/kernel_sse2.cpp PROPERTIES COMPILE_FLAGS "${CYCLES_SSE2_KERNEL_FLAGS}")
set_source_files_properties(device/cpu/kernel_sse3.cpp PROPERTIES COMPILE_FLAGS "${CYCLES_SSE3_KERNEL_FLAGS}")
set_source_files_properties(device/cpu/kernel_sse41.cpp PROPERTIES COMPILE_FLAGS "${CYCLES_SSE41_KERNEL_FLAGS}")
endif()
if(CXX_HAS_AVX)
set_source_files_properties(device/cpu/kernel_avx.cpp PROPERTIES COMPILE_FLAGS "${CYCLES_AVX_KERNEL_FLAGS}")
endif()
if(CXX_HAS_AVX2)
set_source_files_properties(device/cpu/kernel_avx2.cpp PROPERTIES COMPILE_FLAGS "${CYCLES_AVX2_KERNEL_FLAGS}")
endif()

View File

@ -35,15 +35,9 @@ void kernel_global_memory_copy(KernelGlobalsCPU *kg, const char *name, void *mem
#define KERNEL_ARCH cpu_sse2
#include "kernel/device/cpu/kernel_arch.h"
#define KERNEL_ARCH cpu_sse3
#include "kernel/device/cpu/kernel_arch.h"
#define KERNEL_ARCH cpu_sse41
#include "kernel/device/cpu/kernel_arch.h"
#define KERNEL_ARCH cpu_avx
#include "kernel/device/cpu/kernel_arch.h"
#define KERNEL_ARCH cpu_avx2
#include "kernel/device/cpu/kernel_arch.h"

View File

@ -1,26 +0,0 @@
/* SPDX-License-Identifier: Apache-2.0
* Copyright 2011-2022 Blender Foundation */
/* Optimized CPU kernel entry points. This file is compiled with AVX
* optimization flags and nearly all functions inlined, while kernel.cpp
* is compiled without for other CPU's. */
#include "util/optimization.h"
#ifndef WITH_CYCLES_OPTIMIZED_KERNEL_AVX
# define KERNEL_STUB
#else
/* SSE optimization disabled for now on 32 bit, see bug T36316. */
# if !(defined(__GNUC__) && (defined(i386) || defined(_M_IX86)))
# define __KERNEL_SSE__
# define __KERNEL_SSE2__
# define __KERNEL_SSE3__
# define __KERNEL_SSSE3__
# define __KERNEL_SSE41__
# define __KERNEL_AVX__
# endif
#endif /* WITH_CYCLES_OPTIMIZED_KERNEL_AVX */
#include "kernel/device/cpu/kernel.h"
#define KERNEL_ARCH cpu_avx
#include "kernel/device/cpu/kernel_arch_impl.h"

View File

@ -1,23 +0,0 @@
/* SPDX-License-Identifier: Apache-2.0
* Copyright 2011-2022 Blender Foundation */
/* Optimized CPU kernel entry points. This file is compiled with SSE3/SSSE3
* optimization flags and nearly all functions inlined, while kernel.cpp
* is compiled without for other CPU's. */
#include "util/optimization.h"
#ifndef WITH_CYCLES_OPTIMIZED_KERNEL_SSE3
# define KERNEL_STUB
#else
/* SSE optimization disabled for now on 32 bit, see bug T36316. */
# if !(defined(__GNUC__) && (defined(i386) || defined(_M_IX86)))
# define __KERNEL_SSE2__
# define __KERNEL_SSE3__
# define __KERNEL_SSSE3__
# endif
#endif /* WITH_CYCLES_OPTIMIZED_KERNEL_SSE3 */
#include "kernel/device/cpu/kernel.h"
#define KERNEL_ARCH cpu_sse3
#include "kernel/device/cpu/kernel_arch_impl.h"

View File

@ -45,19 +45,6 @@ set(SRC
# Disable AVX tests on macOS. Rosetta has problems running them, and other
# platforms should be enough to verify AVX operations are implemented correctly.
if(NOT APPLE)
if(CXX_HAS_SSE)
list(APPEND SRC
util_float8_sse2_test.cpp
)
set_source_files_properties(util_float8_avx_test.cpp PROPERTIES COMPILE_FLAGS "${CYCLES_SSE2_KERNEL_FLAGS}")
endif()
if(CXX_HAS_AVX)
list(APPEND SRC
util_float8_avx_test.cpp
)
set_source_files_properties(util_float8_avx_test.cpp PROPERTIES COMPILE_FLAGS "${CYCLES_AVX_KERNEL_FLAGS}")
endif()
if(CXX_HAS_AVX2)
list(APPEND SRC
util_float8_avx2_test.cpp

View File

@ -29,9 +29,7 @@ void DebugFlags::CPU::reset()
} while (0)
CHECK_CPU_FLAGS(avx2, "CYCLES_CPU_NO_AVX2");
CHECK_CPU_FLAGS(avx, "CYCLES_CPU_NO_AVX");
CHECK_CPU_FLAGS(sse41, "CYCLES_CPU_NO_SSE41");
CHECK_CPU_FLAGS(sse3, "CYCLES_CPU_NO_SSE3");
CHECK_CPU_FLAGS(sse2, "CYCLES_CPU_NO_SSE2");
#undef STRINGIFY

View File

@ -26,9 +26,7 @@ class DebugFlags {
/* Flags describing which instructions sets are allowed for use. */
bool avx2 = true;
bool avx = true;
bool sse41 = true;
bool sse3 = true;
bool sse2 = true;
/* Check functions to see whether instructions up to the given one
@ -36,19 +34,11 @@ class DebugFlags {
*/
bool has_avx2()
{
return has_avx() && avx2;
}
bool has_avx()
{
return has_sse41() && avx;
return has_sse41() && avx2;
}
bool has_sse41()
{
return has_sse3() && sse41;
}
bool has_sse3()
{
return has_sse2() && sse3;
return has_sse2() && sse41;
}
bool has_sse2()
{

View File

@ -17,9 +17,6 @@
# ifdef WITH_KERNEL_SSE2
# define WITH_CYCLES_OPTIMIZED_KERNEL_SSE2
# endif
# ifdef WITH_KERNEL_SSE3
# define WITH_CYCLES_OPTIMIZED_KERNEL_SSE3
# endif
/* x86-64
*
@ -30,15 +27,9 @@
/* SSE2 is always available on x86-64 CPUs, so auto enable */
# define __KERNEL_SSE2__
/* no SSE2 kernel on x86-64, part of regular kernel */
# ifdef WITH_KERNEL_SSE3
# define WITH_CYCLES_OPTIMIZED_KERNEL_SSE3
# endif
# ifdef WITH_KERNEL_SSE41
# define WITH_CYCLES_OPTIMIZED_KERNEL_SSE41
# endif
# ifdef WITH_KERNEL_AVX
# define WITH_CYCLES_OPTIMIZED_KERNEL_AVX
# endif
# ifdef WITH_KERNEL_AVX2
# define WITH_CYCLES_OPTIMIZED_KERNEL_AVX2
# endif

View File

@ -204,24 +204,12 @@ bool system_cpu_support_sse2()
return caps.sse2;
}
bool system_cpu_support_sse3()
{
CPUCapabilities &caps = system_cpu_capabilities();
return caps.sse3;
}
bool system_cpu_support_sse41()
{
CPUCapabilities &caps = system_cpu_capabilities();
return caps.sse41;
}
bool system_cpu_support_avx()
{
CPUCapabilities &caps = system_cpu_capabilities();
return caps.avx;
}
bool system_cpu_support_avx2()
{
CPUCapabilities &caps = system_cpu_capabilities();
@ -234,20 +222,11 @@ bool system_cpu_support_sse2()
return false;
}
bool system_cpu_support_sse3()
{
return false;
}
bool system_cpu_support_sse41()
{
return false;
}
bool system_cpu_support_avx()
{
return false;
}
bool system_cpu_support_avx2()
{
return false;

View File

@ -17,9 +17,7 @@ int system_console_width();
std::string system_cpu_brand_string();
int system_cpu_bits();
bool system_cpu_support_sse2();
bool system_cpu_support_sse3();
bool system_cpu_support_sse41();
bool system_cpu_support_avx();
bool system_cpu_support_avx2();
size_t system_physical_ram();

View File

@ -1,41 +0,0 @@
.. Keep this document short & concise,
linking to external resources instead of including content in-line.
See 'release/text/readme.html' for the end user read-me.
Blender
=======
Blender is the free and open source 3D creation suite.
It supports the entirety of the 3D pipeline-modeling, rigging, animation, simulation, rendering, compositing,
motion tracking and video editing.
.. figure:: https://code.blender.org/wp-content/uploads/2018/12/springrg.jpg
:scale: 50 %
:align: center
Project Pages
-------------
- `Main Website <http://www.blender.org>`__
- `Reference Manual <https://docs.blender.org/manual/en/latest/index.html>`__
- `User Community <https://www.blender.org/community/>`__
Development
-----------
- `Build Instructions <https://wiki.blender.org/wiki/Building_Blender>`__
- `Code Review & Bug Tracker <https://developer.blender.org>`__
- `Developer Forum <https://devtalk.blender.org>`__
- `Developer Documentation <https://wiki.blender.org>`__
License
-------
Blender as a whole is licensed under the GNU General Public License, Version 3.
Individual files may have a different, but compatible license.
See `blender.org/about/license <https://www.blender.org/about/license>`__ for details.

View File

@ -181,6 +181,7 @@ def draw(layout, context, context_member, property_type, *, use_edit=True):
value_column.prop(rna_item, '["%s"]' % escape_identifier(key), text="")
operator_row = value_row.row()
operator_row.alignment = 'RIGHT'
# Do not allow editing of overridden properties (we cannot use a poll function
# of the operators here since they's have no access to the specific property).

View File

@ -1750,11 +1750,11 @@ class CLIP_MT_marker_pie(Menu):
# Match Keyframe
prop = pie.operator("wm.context_set_enum", text="Match Previous", icon='KEYFRAME_HLT')
prop.data_path = "space_data.clip.tracking.tracks.active.pattern_match"
prop.value = 'KEYFRAME'
prop.value = 'PREV_FRAME'
# Match Previous Frame
prop = pie.operator("wm.context_set_enum", text="Match Keyframe", icon='KEYFRAME')
prop.data_path = "space_data.clip.tracking.tracks.active.pattern_match"
prop.value = 'PREV_FRAME'
prop.value = 'KEYFRAME'
class CLIP_MT_tracking_pie(Menu):

View File

@ -13,7 +13,14 @@ struct Curves;
namespace blender::bke {
/**
* Convert the old curve type to the new data type. Caller owns the returned pointer.
*/
Curves *curve_legacy_to_curves(const Curve &curve_legacy);
/**
* Convert the old curve type to the new data type using a specific list of #Nurb for the actual
* geometry data. Caller owns the returned pointer.
*/
Curves *curve_legacy_to_curves(const Curve &curve_legacy, const ListBase &nurbs_list);
} // namespace blender::bke

View File

@ -519,7 +519,7 @@ void fill_points(const CurvesGeometry &curves,
}
/**
* Copy only the information on the point domain, but not the offsets or any point attributes,
* Copy only the attributes on the curve domain, but not the offsets or any point attributes,
* meant for operations that change the number of points but not the number of curves.
* \warning The returned curves have invalid offsets!
*/

View File

@ -28,18 +28,17 @@ typedef union IDPropertyTemplate {
double d;
struct {
const char *str;
/** String length (including the null byte): `strlen(str) + 1`. */
int len;
/** #eIDPropertySubType */
char subtype;
} string;
struct ID *id;
struct {
int len;
/** #eIDPropertyType */
char type;
} array;
struct {
int matvec_size;
const float *example;
} matrix_or_vector;
} IDPropertyTemplate;
/* ----------- Property Array Type ---------- */

View File

@ -104,6 +104,7 @@ namespace nodes {
class DNode;
class NodeMultiFunctionBuilder;
class GeoNodeExecParams;
class NodeDeclaration;
class NodeDeclarationBuilder;
class GatherLinkSearchOpParams;
} // namespace nodes
@ -118,6 +119,9 @@ using CPPTypeHandle = blender::CPPType;
using NodeMultiFunctionBuildFunction = void (*)(blender::nodes::NodeMultiFunctionBuilder &builder);
using NodeGeometryExecFunction = void (*)(blender::nodes::GeoNodeExecParams params);
using NodeDeclareFunction = void (*)(blender::nodes::NodeDeclarationBuilder &builder);
using NodeDeclareDynamicFunction = void (*)(const bNodeTree &tree,
const bNode &node,
blender::nodes::NodeDeclaration &r_declaration);
using SocketGetCPPValueFunction = void (*)(const struct bNodeSocket &socket, void *r_value);
using SocketGetGeometryNodesCPPValueFunction = void (*)(const struct bNodeSocket &socket,
void *r_value);
@ -137,6 +141,7 @@ typedef void *NodeGetCompositorShaderNodeFunction;
typedef void *NodeMultiFunctionBuildFunction;
typedef void *NodeGeometryExecFunction;
typedef void *NodeDeclareFunction;
typedef void *NodeDeclareDynamicFunction;
typedef void *NodeGatherSocketLinkOperationsFunction;
typedef void *SocketGetCPPTypeFunction;
typedef void *SocketGetGeometryNodesCPPTypeFunction;
@ -173,11 +178,6 @@ typedef struct bNodeSocketType {
struct bNode *node,
struct bNodeSocket *sock,
const char *data_path);
void (*interface_verify_socket)(struct bNodeTree *ntree,
const struct bNodeSocket *interface_socket,
struct bNode *node,
struct bNodeSocket *sock,
const char *data_path);
void (*interface_from_socket)(struct bNodeTree *ntree,
struct bNodeSocket *interface_socket,
const struct bNode *node,
@ -306,8 +306,8 @@ typedef struct bNodeType {
const struct bNodeTree *nodetree,
const char **r_disabled_hint);
/* optional handling of link insertion */
void (*insert_link)(struct bNodeTree *ntree, struct bNode *node, struct bNodeLink *link);
/* optional handling of link insertion. Returns false if the link shouldn't be created. */
bool (*insert_link)(struct bNodeTree *ntree, struct bNode *node, struct bNodeLink *link);
void (*free_self)(struct bNodeType *ntype);
@ -344,8 +344,13 @@ typedef struct bNodeType {
/* Declares which sockets the node has. */
NodeDeclareFunction declare;
/* Different nodes of this type can have different declarations. */
bool declaration_is_dynamic;
/**
* Declare which sockets the node has for declarations that aren't static per node type.
* In other words, defining this callback means that different nodes of this type can have
* different declarations and different sockets.
*/
NodeDeclareDynamicFunction declare_dynamic;
/* Declaration to be used when it is not dynamic. */
NodeDeclarationHandle *fixed_declaration;

View File

@ -242,7 +242,14 @@ MutableSpan<int8_t> CurvesGeometry::curve_types_for_write()
void CurvesGeometry::fill_curve_types(const CurveType type)
{
this->curve_types_for_write().fill(type);
if (type == CURVE_TYPE_CATMULL_ROM) {
/* Avoid creating the attribute for Catmull Rom which is the default when the attribute doesn't
* exist anyway. */
this->attributes_for_write().remove("curve_type");
}
else {
this->curve_types_for_write().fill(type);
}
this->runtime->type_counts.fill(0);
this->runtime->type_counts[type] = this->curves_num();
this->tag_topology_changed();

View File

@ -39,19 +39,19 @@
static CLG_LogRef LOG = {"bke.idprop"};
/* Local size table. */
/** Local size table, aligned with #eIDPropertyType. */
static size_t idp_size_table[] = {
1, /*strings*/
sizeof(int),
sizeof(float),
sizeof(float[3]), /* Vector type, deprecated. */
sizeof(float[16]), /* Matrix type, deprecated. */
0, /* Arrays don't have a fixed size. */
sizeof(ListBase), /* Group type. */
sizeof(void *),
sizeof(double),
0,
sizeof(int8_t), /* Boolean type. */
1, /* #IDP_STRING */
sizeof(int), /* #IDP_INT */
sizeof(float), /* #IDP_FLOAT */
sizeof(float[3]), /* DEPRECATED (was vector). */
sizeof(float[16]), /* DEPRECATED (was matrix). */
0, /* #IDP_ARRAY (no fixed size). */
sizeof(ListBase), /* #IDP_GROUP */
sizeof(void *), /* #IDP_ID */
sizeof(double), /* #IDP_DOUBLE */
0, /* #IDP_IDPARRAY (no fixed size). */
sizeof(int8_t), /* #IDP_BOOLEAN */
};
/* -------------------------------------------------------------------- */

View File

@ -1239,6 +1239,9 @@ void BKE_mesh_legacy_face_set_from_generic(Mesh *mesh,
void BKE_mesh_legacy_face_set_to_generic(Mesh *mesh)
{
using namespace blender;
if (mesh->attributes().contains(".sculpt_face_set")) {
return;
}
for (CustomDataLayer &layer : MutableSpan(mesh->pdata.layers, mesh->pdata.totlayer)) {
if (layer.type == CD_SCULPT_FACE_SETS) {
BLI_strncpy(layer.name, ".sculpt_face_set", sizeof(layer.name));
@ -1290,21 +1293,25 @@ void BKE_mesh_legacy_bevel_weight_from_layers(Mesh *mesh)
void BKE_mesh_legacy_bevel_weight_to_layers(Mesh *mesh)
{
using namespace blender;
const Span<MVert> verts(mesh->mvert, mesh->totvert);
if (mesh->cd_flag & ME_CDFLAG_VERT_BWEIGHT) {
float *weights = static_cast<float *>(
CustomData_add_layer(&mesh->vdata, CD_BWEIGHT, CD_CONSTRUCT, nullptr, verts.size()));
for (const int i : verts.index_range()) {
weights[i] = verts[i].bweight_legacy / 255.0f;
if (mesh->mvert && !CustomData_has_layer(&mesh->vdata, CD_BWEIGHT)) {
const Span<MVert> verts(mesh->mvert, mesh->totvert);
if (mesh->cd_flag & ME_CDFLAG_VERT_BWEIGHT) {
float *weights = static_cast<float *>(
CustomData_add_layer(&mesh->vdata, CD_BWEIGHT, CD_CONSTRUCT, nullptr, verts.size()));
for (const int i : verts.index_range()) {
weights[i] = verts[i].bweight_legacy / 255.0f;
}
}
}
const Span<MEdge> edges = mesh->edges();
if (mesh->cd_flag & ME_CDFLAG_EDGE_BWEIGHT) {
float *weights = static_cast<float *>(
CustomData_add_layer(&mesh->edata, CD_BWEIGHT, CD_CONSTRUCT, nullptr, edges.size()));
for (const int i : edges.index_range()) {
weights[i] = edges[i].bweight_legacy / 255.0f;
if (!CustomData_has_layer(&mesh->edata, CD_BWEIGHT)) {
if (mesh->cd_flag & ME_CDFLAG_EDGE_BWEIGHT) {
float *weights = static_cast<float *>(
CustomData_add_layer(&mesh->edata, CD_BWEIGHT, CD_CONSTRUCT, nullptr, edges.size()));
for (const int i : edges.index_range()) {
weights[i] = edges[i].bweight_legacy / 255.0f;
}
}
}
}
@ -1337,6 +1344,9 @@ void BKE_mesh_legacy_edge_crease_from_layers(Mesh *mesh)
void BKE_mesh_legacy_edge_crease_to_layers(Mesh *mesh)
{
using namespace blender;
if (CustomData_has_layer(&mesh->edata, CD_CREASE)) {
return;
}
const Span<MEdge> edges = mesh->edges();
if (mesh->cd_flag & ME_CDFLAG_EDGE_CREASE) {
float *creases = static_cast<float *>(
@ -1376,6 +1386,9 @@ void BKE_mesh_legacy_sharp_edges_from_flags(Mesh *mesh)
using namespace blender::bke;
const Span<MEdge> edges = mesh->edges();
MutableAttributeAccessor attributes = mesh->attributes_for_write();
if (attributes.contains("sharp_edge")) {
return;
}
if (std::any_of(
edges.begin(), edges.end(), [](const MEdge &edge) { return edge.flag & ME_SHARP; })) {
SpanAttributeWriter<bool> sharp_edges = attributes.lookup_or_add_for_write_only_span<bool>(
@ -1434,7 +1447,10 @@ void BKE_mesh_legacy_convert_flags_to_hide_layers(Mesh *mesh)
using namespace blender;
using namespace blender::bke;
MutableAttributeAccessor attributes = mesh->attributes_for_write();
if (!mesh->mvert || attributes.contains(".hide_vert") || attributes.contains(".hide_edge") ||
attributes.contains(".hide_poly")) {
return;
}
const Span<MVert> verts(mesh->mvert, mesh->totvert);
if (std::any_of(verts.begin(), verts.end(), [](const MVert &vert) {
return vert.flag_legacy & ME_HIDE;
@ -1502,6 +1518,9 @@ void BKE_mesh_legacy_convert_mpoly_to_material_indices(Mesh *mesh)
using namespace blender;
using namespace blender::bke;
MutableAttributeAccessor attributes = mesh->attributes_for_write();
if (attributes.contains("material_index")) {
return;
}
const Span<MPoly> polys = mesh->polys();
if (std::any_of(
polys.begin(), polys.end(), [](const MPoly &poly) { return poly.mat_nr_legacy != 0; })) {
@ -1737,6 +1756,10 @@ void BKE_mesh_legacy_convert_flags_to_selection_layers(Mesh *mesh)
using namespace blender;
using namespace blender::bke;
MutableAttributeAccessor attributes = mesh->attributes_for_write();
if (!mesh->mvert || attributes.contains(".select_vert") || attributes.contains(".select_edge") ||
attributes.contains(".select_poly")) {
return;
}
const Span<MVert> verts(mesh->mvert, mesh->totvert);
if (std::any_of(verts.begin(), verts.end(), [](const MVert &vert) {
@ -1840,6 +1863,9 @@ void BKE_mesh_legacy_convert_verts_to_positions(Mesh *mesh)
{
using namespace blender;
using namespace blender::bke;
if (!mesh->mvert || CustomData_get_layer_named(&mesh->vdata, CD_PROP_FLOAT3, "position")) {
return;
}
const Span<MVert> verts(static_cast<const MVert *>(CustomData_get_layer(&mesh->vdata, CD_MVERT)),
mesh->totvert);

View File

@ -1378,7 +1378,7 @@ void nodeRegisterType(bNodeType *nt)
BLI_assert(nt->idname[0] != '\0');
BLI_assert(nt->poll != nullptr);
if (nt->declare && !nt->declaration_is_dynamic) {
if (nt->declare && !nt->declare_dynamic) {
if (nt->fixed_declaration == nullptr) {
nt->fixed_declaration = new blender::nodes::NodeDeclaration();
blender::nodes::build_node_declaration(*nt, *nt->fixed_declaration);
@ -2990,7 +2990,7 @@ void node_free_node(bNodeTree *ntree, bNode *node)
MEM_freeN(node->prop);
}
if (node->typeinfo->declaration_is_dynamic) {
if (node->typeinfo->declare_dynamic) {
delete node->runtime->declaration;
}
@ -3602,7 +3602,7 @@ bool nodeDeclarationEnsureOnOutdatedNode(bNodeTree * /*ntree*/, bNode *node)
if (node->typeinfo->declare == nullptr) {
return false;
}
if (node->typeinfo->declaration_is_dynamic) {
if (node->typeinfo->declare_dynamic) {
node->runtime->declaration = new blender::nodes::NodeDeclaration();
blender::nodes::build_node_declaration(*node->typeinfo, *node->runtime->declaration);
}

View File

@ -22,6 +22,7 @@
#include "MOD_nodes.h"
#include "NOD_node_declaration.hh"
#include "NOD_socket.h"
#include "NOD_texture.h"
#include "DEG_depsgraph_query.h"
@ -538,7 +539,6 @@ class NodeTreeMainUpdater {
void update_individual_nodes(bNodeTree &ntree)
{
Vector<bNode *> group_inout_nodes;
for (bNode *node : ntree.all_nodes()) {
nodeDeclarationEnsure(&ntree, node);
if (this->should_update_individual_node(ntree, *node)) {
@ -549,18 +549,9 @@ class NodeTreeMainUpdater {
if (ntype.updatefunc) {
ntype.updatefunc(&ntree, node);
}
}
if (ELEM(node->type, NODE_GROUP_INPUT, NODE_GROUP_OUTPUT)) {
group_inout_nodes.append(node);
}
}
/* The update function of group input/output nodes may add new interface sockets. When that
* happens, all the input/output nodes have to be updated again. In the future it would be
* better to move this functionality out of the node update function into the operator that's
* supposed to create the new interface socket. */
if (ntree.runtime->changed_flag & NTREE_CHANGED_INTERFACE) {
for (bNode *node : group_inout_nodes) {
node->typeinfo->updatefunc(&ntree, node);
if (ntype.declare_dynamic) {
nodes::update_node_declaration_and_sockets(ntree, *node);
}
}
}
}
@ -574,23 +565,8 @@ class NodeTreeMainUpdater {
return true;
}
if (ntree.runtime->changed_flag & NTREE_CHANGED_LINK) {
ntree.ensure_topology_cache();
/* Node groups currently always rebuilt their sockets when they are updated.
* So avoid calling the update method when no new link was added to it. */
if (node.type == NODE_GROUP_INPUT) {
if (node.output_sockets().last()->is_directly_linked()) {
return true;
}
}
else if (node.type == NODE_GROUP_OUTPUT) {
if (node.input_sockets().last()->is_directly_linked()) {
return true;
}
}
else {
/* Currently we have no way to tell if a node needs to be updated when a link changed. */
return true;
}
/* Currently we have no way to tell if a node needs to be updated when a link changed. */
return true;
}
if (ntree.runtime->changed_flag & NTREE_CHANGED_INTERFACE) {
if (ELEM(node.type, NODE_GROUP_INPUT, NODE_GROUP_OUTPUT)) {

View File

@ -83,16 +83,12 @@ void mul_m3_m4m4(float R[3][3], const float A[4][4], const float B[4][4]);
/**
* Special matrix multiplies
* - uniq: `R <-- AB`, R is neither A nor B
* - pre: `R <-- AR`
* - post: `R <-- RB`.
*/
void mul_m3_m3m3_uniq(float R[3][3], const float A[3][3], const float B[3][3]);
void mul_m3_m3_pre(float R[3][3], const float A[3][3]);
void mul_m3_m3_post(float R[3][3], const float B[3][3]);
void mul_m4_m4m4_uniq(float R[4][4], const float A[4][4], const float B[4][4]);
void mul_m4_m4m4_db_uniq(double R[4][4], const double A[4][4], const double B[4][4]);
void mul_m4db_m4db_m4fl_uniq(double R[4][4], const double A[4][4], const float B[4][4]);
void mul_m4db_m4db_m4fl(double R[4][4], const double A[4][4], const float B[4][4]);
void mul_m4_m4_pre(float R[4][4], const float A[4][4]);
void mul_m4_m4_post(float R[4][4], const float B[4][4]);

View File

@ -257,22 +257,14 @@ void shuffle_m4(float R[4][4], const int index[4])
void mul_m4_m4m4(float R[4][4], const float A[4][4], const float B[4][4])
{
if (A == R) {
mul_m4_m4_post(R, B);
if (R == A || R == B) {
float T[4][4];
mul_m4_m4m4(T, A, B);
copy_m4_m4(R, T);
return;
}
else if (B == R) {
mul_m4_m4_pre(R, A);
}
else {
mul_m4_m4m4_uniq(R, A, B);
}
}
void mul_m4_m4m4_uniq(float R[4][4], const float A[4][4], const float B[4][4])
{
BLI_assert(!ELEM(R, A, B));
/* Matrix product: `R[j][k] = A[j][i] . B[i][k]`. */
/* Matrix product: `R[j][k] = B[j][i] . A[i][k]`. */
#ifdef BLI_HAVE_SSE2
__m128 A0 = _mm_loadu_ps(A[0]);
__m128 A1 = _mm_loadu_ps(A[1]);
@ -313,39 +305,16 @@ void mul_m4_m4m4_uniq(float R[4][4], const float A[4][4], const float B[4][4])
#endif
}
void mul_m4_m4m4_db_uniq(double R[4][4], const double A[4][4], const double B[4][4])
void mul_m4db_m4db_m4fl(double R[4][4], const double A[4][4], const float B[4][4])
{
BLI_assert(!ELEM(R, A, B));
if (R == A) {
double T[4][4];
mul_m4db_m4db_m4fl(T, A, B);
copy_m4_m4_db(R, T);
return;
}
/* Matrix product: `R[j][k] = A[j][i] . B[i][k]`. */
R[0][0] = B[0][0] * A[0][0] + B[0][1] * A[1][0] + B[0][2] * A[2][0] + B[0][3] * A[3][0];
R[0][1] = B[0][0] * A[0][1] + B[0][1] * A[1][1] + B[0][2] * A[2][1] + B[0][3] * A[3][1];
R[0][2] = B[0][0] * A[0][2] + B[0][1] * A[1][2] + B[0][2] * A[2][2] + B[0][3] * A[3][2];
R[0][3] = B[0][0] * A[0][3] + B[0][1] * A[1][3] + B[0][2] * A[2][3] + B[0][3] * A[3][3];
R[1][0] = B[1][0] * A[0][0] + B[1][1] * A[1][0] + B[1][2] * A[2][0] + B[1][3] * A[3][0];
R[1][1] = B[1][0] * A[0][1] + B[1][1] * A[1][1] + B[1][2] * A[2][1] + B[1][3] * A[3][1];
R[1][2] = B[1][0] * A[0][2] + B[1][1] * A[1][2] + B[1][2] * A[2][2] + B[1][3] * A[3][2];
R[1][3] = B[1][0] * A[0][3] + B[1][1] * A[1][3] + B[1][2] * A[2][3] + B[1][3] * A[3][3];
R[2][0] = B[2][0] * A[0][0] + B[2][1] * A[1][0] + B[2][2] * A[2][0] + B[2][3] * A[3][0];
R[2][1] = B[2][0] * A[0][1] + B[2][1] * A[1][1] + B[2][2] * A[2][1] + B[2][3] * A[3][1];
R[2][2] = B[2][0] * A[0][2] + B[2][1] * A[1][2] + B[2][2] * A[2][2] + B[2][3] * A[3][2];
R[2][3] = B[2][0] * A[0][3] + B[2][1] * A[1][3] + B[2][2] * A[2][3] + B[2][3] * A[3][3];
R[3][0] = B[3][0] * A[0][0] + B[3][1] * A[1][0] + B[3][2] * A[2][0] + B[3][3] * A[3][0];
R[3][1] = B[3][0] * A[0][1] + B[3][1] * A[1][1] + B[3][2] * A[2][1] + B[3][3] * A[3][1];
R[3][2] = B[3][0] * A[0][2] + B[3][1] * A[1][2] + B[3][2] * A[2][2] + B[3][3] * A[3][2];
R[3][3] = B[3][0] * A[0][3] + B[3][1] * A[1][3] + B[3][2] * A[2][3] + B[3][3] * A[3][3];
}
void mul_m4db_m4db_m4fl_uniq(double R[4][4], const double A[4][4], const float B[4][4])
{
/* Remove second check since types don't match. */
BLI_assert(!ELEM(R, A /*, B */));
/* Matrix product: `R[j][k] = A[j][i] . B[i][k]`. */
/* Matrix product: `R[j][k] = B[j][i] . A[i][k]`. */
R[0][0] = B[0][0] * A[0][0] + B[0][1] * A[1][0] + B[0][2] * A[2][0] + B[0][3] * A[3][0];
R[0][1] = B[0][0] * A[0][1] + B[0][1] * A[1][1] + B[0][2] * A[2][1] + B[0][3] * A[3][1];
@ -370,53 +339,32 @@ void mul_m4db_m4db_m4fl_uniq(double R[4][4], const double A[4][4], const float B
void mul_m4_m4_pre(float R[4][4], const float A[4][4])
{
BLI_assert(A != R);
float B[4][4];
copy_m4_m4(B, R);
mul_m4_m4m4_uniq(R, A, B);
mul_m4_m4m4(R, A, R);
}
void mul_m4_m4_post(float R[4][4], const float B[4][4])
{
BLI_assert(B != R);
float A[4][4];
copy_m4_m4(A, R);
mul_m4_m4m4_uniq(R, A, B);
}
void mul_m3_m3m3(float R[3][3], const float A[3][3], const float B[3][3])
{
if (A == R) {
mul_m3_m3_post(R, B);
}
else if (B == R) {
mul_m3_m3_pre(R, A);
}
else {
mul_m3_m3m3_uniq(R, A, B);
}
mul_m4_m4m4(R, R, B);
}
void mul_m3_m3_pre(float R[3][3], const float A[3][3])
{
BLI_assert(A != R);
float B[3][3];
copy_m3_m3(B, R);
mul_m3_m3m3_uniq(R, A, B);
mul_m3_m3m3(R, A, R);
}
void mul_m3_m3_post(float R[3][3], const float B[3][3])
{
BLI_assert(B != R);
float A[3][3];
copy_m3_m3(A, R);
mul_m3_m3m3_uniq(R, A, B);
mul_m3_m3m3(R, R, B);
}
void mul_m3_m3m3_uniq(float R[3][3], const float A[3][3], const float B[3][3])
void mul_m3_m3m3(float R[3][3], const float A[3][3], const float B[3][3])
{
BLI_assert(!ELEM(R, A, B));
if (R == A || R == B) {
float T[3][3];
mul_m3_m3m3(T, A, B);
copy_m3_m3(R, T);
return;
}
R[0][0] = B[0][0] * A[0][0] + B[0][1] * A[1][0] + B[0][2] * A[2][0];
R[0][1] = B[0][0] * A[0][1] + B[0][1] * A[1][1] + B[0][2] * A[2][1];
R[0][2] = B[0][0] * A[0][2] + B[0][1] * A[1][2] + B[0][2] * A[2][2];
@ -432,88 +380,90 @@ void mul_m3_m3m3_uniq(float R[3][3], const float A[3][3], const float B[3][3])
void mul_m4_m4m3(float R[4][4], const float A[4][4], const float B[3][3])
{
float B_[3][3], A_[4][4];
if (R == A) {
float T[4][4];
mul_m4_m4m3(T, A, B);
copy_m4_m4(R, T);
return;
}
/* copy so it works when R is the same pointer as A or B */
/* TODO: avoid copying when matrices are different */
copy_m4_m4(A_, A);
copy_m3_m3(B_, B);
R[0][0] = B_[0][0] * A_[0][0] + B_[0][1] * A_[1][0] + B_[0][2] * A_[2][0];
R[0][1] = B_[0][0] * A_[0][1] + B_[0][1] * A_[1][1] + B_[0][2] * A_[2][1];
R[0][2] = B_[0][0] * A_[0][2] + B_[0][1] * A_[1][2] + B_[0][2] * A_[2][2];
R[1][0] = B_[1][0] * A_[0][0] + B_[1][1] * A_[1][0] + B_[1][2] * A_[2][0];
R[1][1] = B_[1][0] * A_[0][1] + B_[1][1] * A_[1][1] + B_[1][2] * A_[2][1];
R[1][2] = B_[1][0] * A_[0][2] + B_[1][1] * A_[1][2] + B_[1][2] * A_[2][2];
R[2][0] = B_[2][0] * A_[0][0] + B_[2][1] * A_[1][0] + B_[2][2] * A_[2][0];
R[2][1] = B_[2][0] * A_[0][1] + B_[2][1] * A_[1][1] + B_[2][2] * A_[2][1];
R[2][2] = B_[2][0] * A_[0][2] + B_[2][1] * A_[1][2] + B_[2][2] * A_[2][2];
R[0][0] = B[0][0] * A[0][0] + B[0][1] * A[1][0] + B[0][2] * A[2][0];
R[0][1] = B[0][0] * A[0][1] + B[0][1] * A[1][1] + B[0][2] * A[2][1];
R[0][2] = B[0][0] * A[0][2] + B[0][1] * A[1][2] + B[0][2] * A[2][2];
R[1][0] = B[1][0] * A[0][0] + B[1][1] * A[1][0] + B[1][2] * A[2][0];
R[1][1] = B[1][0] * A[0][1] + B[1][1] * A[1][1] + B[1][2] * A[2][1];
R[1][2] = B[1][0] * A[0][2] + B[1][1] * A[1][2] + B[1][2] * A[2][2];
R[2][0] = B[2][0] * A[0][0] + B[2][1] * A[1][0] + B[2][2] * A[2][0];
R[2][1] = B[2][0] * A[0][1] + B[2][1] * A[1][1] + B[2][2] * A[2][1];
R[2][2] = B[2][0] * A[0][2] + B[2][1] * A[1][2] + B[2][2] * A[2][2];
}
void mul_m3_m3m4(float R[3][3], const float A[3][3], const float B[4][4])
{
float B_[4][4], A_[3][3];
if (R == A) {
float T[3][3];
mul_m3_m3m4(T, A, B);
copy_m3_m3(R, T);
return;
}
/* copy so it works when R is the same pointer as A or B */
/* TODO: avoid copying when matrices are different */
copy_m3_m3(A_, A);
copy_m4_m4(B_, B);
/* Matrix product: `R[j][k] = B[j][i] . A[i][k]`. */
/* R[i][j] = B_[i][k] * A_[k][j] */
R[0][0] = B_[0][0] * A_[0][0] + B_[0][1] * A_[1][0] + B_[0][2] * A_[2][0];
R[0][1] = B_[0][0] * A_[0][1] + B_[0][1] * A_[1][1] + B_[0][2] * A_[2][1];
R[0][2] = B_[0][0] * A_[0][2] + B_[0][1] * A_[1][2] + B_[0][2] * A_[2][2];
R[0][0] = B[0][0] * A[0][0] + B[0][1] * A[1][0] + B[0][2] * A[2][0];
R[0][1] = B[0][0] * A[0][1] + B[0][1] * A[1][1] + B[0][2] * A[2][1];
R[0][2] = B[0][0] * A[0][2] + B[0][1] * A[1][2] + B[0][2] * A[2][2];
R[1][0] = B_[1][0] * A_[0][0] + B_[1][1] * A_[1][0] + B_[1][2] * A_[2][0];
R[1][1] = B_[1][0] * A_[0][1] + B_[1][1] * A_[1][1] + B_[1][2] * A_[2][1];
R[1][2] = B_[1][0] * A_[0][2] + B_[1][1] * A_[1][2] + B_[1][2] * A_[2][2];
R[1][0] = B[1][0] * A[0][0] + B[1][1] * A[1][0] + B[1][2] * A[2][0];
R[1][1] = B[1][0] * A[0][1] + B[1][1] * A[1][1] + B[1][2] * A[2][1];
R[1][2] = B[1][0] * A[0][2] + B[1][1] * A[1][2] + B[1][2] * A[2][2];
R[2][0] = B_[2][0] * A_[0][0] + B_[2][1] * A_[1][0] + B_[2][2] * A_[2][0];
R[2][1] = B_[2][0] * A_[0][1] + B_[2][1] * A_[1][1] + B_[2][2] * A_[2][1];
R[2][2] = B_[2][0] * A_[0][2] + B_[2][1] * A_[1][2] + B_[2][2] * A_[2][2];
R[2][0] = B[2][0] * A[0][0] + B[2][1] * A[1][0] + B[2][2] * A[2][0];
R[2][1] = B[2][0] * A[0][1] + B[2][1] * A[1][1] + B[2][2] * A[2][1];
R[2][2] = B[2][0] * A[0][2] + B[2][1] * A[1][2] + B[2][2] * A[2][2];
}
void mul_m3_m4m3(float R[3][3], const float A[4][4], const float B[3][3])
{
float B_[3][3], A_[4][4];
if (R == B) {
float T[3][3];
mul_m3_m4m3(T, A, B);
copy_m3_m3(R, T);
return;
}
/* copy so it works when R is the same pointer as A or B */
/* TODO: avoid copying when matrices are different */
copy_m4_m4(A_, A);
copy_m3_m3(B_, B);
/* Matrix product: `R[j][k] = B[j][i] . A[i][k]`. */
/* R[i][j] = B[i][k] * A[k][j] */
R[0][0] = B_[0][0] * A_[0][0] + B_[0][1] * A_[1][0] + B_[0][2] * A_[2][0];
R[0][1] = B_[0][0] * A_[0][1] + B_[0][1] * A_[1][1] + B_[0][2] * A_[2][1];
R[0][2] = B_[0][0] * A_[0][2] + B_[0][1] * A_[1][2] + B_[0][2] * A_[2][2];
R[0][0] = B[0][0] * A[0][0] + B[0][1] * A[1][0] + B[0][2] * A[2][0];
R[0][1] = B[0][0] * A[0][1] + B[0][1] * A[1][1] + B[0][2] * A[2][1];
R[0][2] = B[0][0] * A[0][2] + B[0][1] * A[1][2] + B[0][2] * A[2][2];
R[1][0] = B_[1][0] * A_[0][0] + B_[1][1] * A_[1][0] + B_[1][2] * A_[2][0];
R[1][1] = B_[1][0] * A_[0][1] + B_[1][1] * A_[1][1] + B_[1][2] * A_[2][1];
R[1][2] = B_[1][0] * A_[0][2] + B_[1][1] * A_[1][2] + B_[1][2] * A_[2][2];
R[1][0] = B[1][0] * A[0][0] + B[1][1] * A[1][0] + B[1][2] * A[2][0];
R[1][1] = B[1][0] * A[0][1] + B[1][1] * A[1][1] + B[1][2] * A[2][1];
R[1][2] = B[1][0] * A[0][2] + B[1][1] * A[1][2] + B[1][2] * A[2][2];
R[2][0] = B_[2][0] * A_[0][0] + B_[2][1] * A_[1][0] + B_[2][2] * A_[2][0];
R[2][1] = B_[2][0] * A_[0][1] + B_[2][1] * A_[1][1] + B_[2][2] * A_[2][1];
R[2][2] = B_[2][0] * A_[0][2] + B_[2][1] * A_[1][2] + B_[2][2] * A_[2][2];
R[2][0] = B[2][0] * A[0][0] + B[2][1] * A[1][0] + B[2][2] * A[2][0];
R[2][1] = B[2][0] * A[0][1] + B[2][1] * A[1][1] + B[2][2] * A[2][1];
R[2][2] = B[2][0] * A[0][2] + B[2][1] * A[1][2] + B[2][2] * A[2][2];
}
void mul_m4_m3m4(float R[4][4], const float A[3][3], const float B[4][4])
{
float B_[4][4], A_[3][3];
if (R == B) {
float T[4][4];
mul_m4_m3m4(T, A, B);
copy_m4_m4(R, T);
return;
}
/* copy so it works when R is the same pointer as A or B */
/* TODO: avoid copying when matrices are different */
copy_m3_m3(A_, A);
copy_m4_m4(B_, B);
R[0][0] = B_[0][0] * A_[0][0] + B_[0][1] * A_[1][0] + B_[0][2] * A_[2][0];
R[0][1] = B_[0][0] * A_[0][1] + B_[0][1] * A_[1][1] + B_[0][2] * A_[2][1];
R[0][2] = B_[0][0] * A_[0][2] + B_[0][1] * A_[1][2] + B_[0][2] * A_[2][2];
R[1][0] = B_[1][0] * A_[0][0] + B_[1][1] * A_[1][0] + B_[1][2] * A_[2][0];
R[1][1] = B_[1][0] * A_[0][1] + B_[1][1] * A_[1][1] + B_[1][2] * A_[2][1];
R[1][2] = B_[1][0] * A_[0][2] + B_[1][1] * A_[1][2] + B_[1][2] * A_[2][2];
R[2][0] = B_[2][0] * A_[0][0] + B_[2][1] * A_[1][0] + B_[2][2] * A_[2][0];
R[2][1] = B_[2][0] * A_[0][1] + B_[2][1] * A_[1][1] + B_[2][2] * A_[2][1];
R[2][2] = B_[2][0] * A_[0][2] + B_[2][1] * A_[1][2] + B_[2][2] * A_[2][2];
R[0][0] = B[0][0] * A[0][0] + B[0][1] * A[1][0] + B[0][2] * A[2][0];
R[0][1] = B[0][0] * A[0][1] + B[0][1] * A[1][1] + B[0][2] * A[2][1];
R[0][2] = B[0][0] * A[0][2] + B[0][1] * A[1][2] + B[0][2] * A[2][2];
R[1][0] = B[1][0] * A[0][0] + B[1][1] * A[1][0] + B[1][2] * A[2][0];
R[1][1] = B[1][0] * A[0][1] + B[1][1] * A[1][1] + B[1][2] * A[2][1];
R[1][2] = B[1][0] * A[0][2] + B[1][1] * A[1][2] + B[1][2] * A[2][2];
R[2][0] = B[2][0] * A[0][0] + B[2][1] * A[1][0] + B[2][2] * A[2][0];
R[2][1] = B[2][0] * A[0][1] + B[2][1] * A[1][1] + B[2][2] * A[2][1];
R[2][2] = B[2][0] * A[0][2] + B[2][1] * A[1][2] + B[2][2] * A[2][2];
}
void mul_m3_m4m4(float R[3][3], const float A[4][4], const float B[4][4])
@ -1304,7 +1254,7 @@ void mul_m4_m4m4_aligned_scale(float R[4][4], const float A[4][4], const float B
mat4_to_loc_rot_size(loc_b, rot_b, size_b, B);
mul_v3_m4v3(loc_r, A, loc_b);
mul_m3_m3m3_uniq(rot_r, rot_a, rot_b);
mul_m3_m3m3(rot_r, rot_a, rot_b);
mul_v3_v3v3(size_r, size_a, size_b);
loc_rot_size_to_mat4(R, loc_r, rot_r, size_r);
@ -1320,7 +1270,7 @@ void mul_m4_m4m4_split_channels(float R[4][4], const float A[4][4], const float
mat4_to_loc_rot_size(loc_b, rot_b, size_b, B);
add_v3_v3v3(loc_r, loc_a, loc_b);
mul_m3_m3m3_uniq(rot_r, rot_a, rot_b);
mul_m3_m3m3(rot_r, rot_a, rot_b);
mul_v3_v3v3(size_r, size_a, size_b);
loc_rot_size_to_mat4(R, loc_r, rot_r, size_r);

View File

@ -24,16 +24,14 @@ void View::sync(const float4x4 &view_mat, const float4x4 &win_mat, int view_id)
is_inverted_ = (is_negative_m4(view_mat.ptr()) == is_negative_m4(win_mat.ptr()));
BoundBox &bound_box = *reinterpret_cast<BoundBox *>(&culling_[view_id].corners);
BoundSphere &bound_sphere = *reinterpret_cast<BoundSphere *>(&culling_[view_id].bound_sphere);
frustum_boundbox_calc(bound_box, view_id);
frustum_boundbox_calc(view_id);
frustum_culling_planes_calc(view_id);
frustum_culling_sphere_calc(bound_box, bound_sphere, view_id);
frustum_culling_sphere_calc(view_id);
dirty_ = true;
}
void View::frustum_boundbox_calc(BoundBox &bbox, int view_id)
void View::frustum_boundbox_calc(int view_id)
{
/* Extract the 8 corners from a Projection Matrix. */
#if 0 /* Equivalent to this but it has accuracy problems. */
@ -43,16 +41,18 @@ void View::frustum_boundbox_calc(BoundBox &bbox, int view_id)
}
#endif
MutableSpan<float4> corners = {culling_[view_id].corners, ARRAY_SIZE(culling_[view_id].corners)};
float left, right, bottom, top, near, far;
bool is_persp = data_[view_id].winmat[3][3] == 0.0f;
projmat_dimensions(data_[view_id].winmat.ptr(), &left, &right, &bottom, &top, &near, &far);
bbox.vec[0][2] = bbox.vec[3][2] = bbox.vec[7][2] = bbox.vec[4][2] = -near;
bbox.vec[0][0] = bbox.vec[3][0] = left;
bbox.vec[4][0] = bbox.vec[7][0] = right;
bbox.vec[0][1] = bbox.vec[4][1] = bottom;
bbox.vec[7][1] = bbox.vec[3][1] = top;
corners[0][2] = corners[3][2] = corners[7][2] = corners[4][2] = -near;
corners[0][0] = corners[3][0] = left;
corners[4][0] = corners[7][0] = right;
corners[0][1] = corners[4][1] = bottom;
corners[7][1] = corners[3][1] = top;
/* Get the coordinates of the far plane. */
if (is_persp) {
@ -63,15 +63,16 @@ void View::frustum_boundbox_calc(BoundBox &bbox, int view_id)
top *= sca_far;
}
bbox.vec[1][2] = bbox.vec[2][2] = bbox.vec[6][2] = bbox.vec[5][2] = -far;
bbox.vec[1][0] = bbox.vec[2][0] = left;
bbox.vec[6][0] = bbox.vec[5][0] = right;
bbox.vec[1][1] = bbox.vec[5][1] = bottom;
bbox.vec[2][1] = bbox.vec[6][1] = top;
corners[1][2] = corners[2][2] = corners[6][2] = corners[5][2] = -far;
corners[1][0] = corners[2][0] = left;
corners[6][0] = corners[5][0] = right;
corners[1][1] = corners[5][1] = bottom;
corners[2][1] = corners[6][1] = top;
/* Transform into world space. */
for (int i = 0; i < 8; i++) {
mul_m4_v3(data_[view_id].viewinv.ptr(), bbox.vec[i]);
for (float4 &corner : corners) {
mul_m4_v3(data_[view_id].viewinv.ptr(), corner);
corner.w = 1.0;
}
}
@ -87,19 +88,22 @@ void View::frustum_culling_planes_calc(int view_id)
culling_[view_id].planes[2]);
/* Normalize. */
for (int p = 0; p < 6; p++) {
culling_[view_id].planes[p].w /= normalize_v3(culling_[view_id].planes[p]);
for (float4 &plane : culling_[view_id].planes) {
plane.w /= normalize_v3(plane);
}
}
void View::frustum_culling_sphere_calc(const BoundBox &bbox, BoundSphere &bsphere, int view_id)
void View::frustum_culling_sphere_calc(int view_id)
{
BoundSphere &bsphere = *reinterpret_cast<BoundSphere *>(&culling_[view_id].bound_sphere);
Span<float4> corners = {culling_[view_id].corners, ARRAY_SIZE(culling_[view_id].corners)};
/* Extract Bounding Sphere */
if (data_[view_id].winmat[3][3] != 0.0f) {
/* Orthographic */
/* The most extreme points on the near and far plane. (normalized device coords). */
const float *nearpoint = bbox.vec[0];
const float *farpoint = bbox.vec[6];
const float *nearpoint = corners[0];
const float *farpoint = corners[6];
/* just use median point */
mid_v3_v3v3(bsphere.center, farpoint, nearpoint);
@ -113,12 +117,12 @@ void View::frustum_culling_sphere_calc(const BoundBox &bbox, BoundSphere &bspher
/* center of each clipping plane */
float mid_min[3], mid_max[3];
mid_v3_v3v3(mid_min, bbox.vec[3], bbox.vec[4]);
mid_v3_v3v3(mid_max, bbox.vec[2], bbox.vec[5]);
mid_v3_v3v3(mid_min, corners[3], corners[4]);
mid_v3_v3v3(mid_max, corners[2], corners[5]);
/* square length of the diagonals of each clipping plane */
float a_sq = len_squared_v3v3(bbox.vec[3], bbox.vec[4]);
float b_sq = len_squared_v3v3(bbox.vec[2], bbox.vec[5]);
float a_sq = len_squared_v3v3(corners[3], corners[4]);
float b_sq = len_squared_v3v3(corners[2], corners[5]);
/* distance squared between clipping planes */
float h_sq = len_squared_v3v3(mid_min, mid_max);
@ -132,7 +136,7 @@ void View::frustum_culling_sphere_calc(const BoundBox &bbox, BoundSphere &bspher
interp_v3_v3v3(bsphere.center, mid_min, mid_max, fac);
/* distance from the center to one of the points of the far plane (1, 2, 5, 6) */
bsphere.radius = len_v3v3(bsphere.center, bbox.vec[1]);
bsphere.radius = len_v3v3(bsphere.center, corners[1]);
}
else {
/* Perspective with asymmetrical frustum. */

View File

@ -139,9 +139,10 @@ class View {
void update_viewport_size();
void frustum_boundbox_calc(BoundBox &bbox, int view_id);
/* WARNING: These 3 functions must be called in order */
void frustum_boundbox_calc(int view_id);
void frustum_culling_planes_calc(int view_id);
void frustum_culling_sphere_calc(const BoundBox &bbox, BoundSphere &bsphere, int view_id);
void frustum_culling_sphere_calc(int view_id);
};
} // namespace blender::draw

View File

@ -2586,21 +2586,21 @@ typedef struct RegionMoveData {
} RegionMoveData;
static int area_max_regionsize(ScrArea *area, ARegion *scalear, AZEdge edge)
static int area_max_regionsize(ScrArea *area, ARegion *scale_region, AZEdge edge)
{
int dist;
/* regions in regions. */
if (scalear->alignment & RGN_SPLIT_PREV) {
const int align = RGN_ALIGN_ENUM_FROM_MASK(scalear->alignment);
if (scale_region->alignment & RGN_SPLIT_PREV) {
const int align = RGN_ALIGN_ENUM_FROM_MASK(scale_region->alignment);
if (ELEM(align, RGN_ALIGN_TOP, RGN_ALIGN_BOTTOM)) {
ARegion *region = scalear->prev;
dist = region->winy + scalear->winy - U.pixelsize;
ARegion *region = scale_region->prev;
dist = region->winy + scale_region->winy - U.pixelsize;
}
else /* if (ELEM(align, RGN_ALIGN_LEFT, RGN_ALIGN_RIGHT)) */ {
ARegion *region = scalear->prev;
dist = region->winx + scalear->winx - U.pixelsize;
ARegion *region = scale_region->prev;
dist = region->winx + scale_region->winx - U.pixelsize;
}
}
else {
@ -2614,23 +2614,23 @@ static int area_max_regionsize(ScrArea *area, ARegion *scalear, AZEdge edge)
/* Subtract the width of regions on opposite side
* prevents dragging regions into other opposite regions. */
LISTBASE_FOREACH (ARegion *, region, &area->regionbase) {
if (region == scalear) {
if (region == scale_region) {
continue;
}
if (scalear->alignment == RGN_ALIGN_LEFT && region->alignment == RGN_ALIGN_RIGHT) {
if (scale_region->alignment == RGN_ALIGN_LEFT && region->alignment == RGN_ALIGN_RIGHT) {
dist -= region->winx;
}
else if (scalear->alignment == RGN_ALIGN_RIGHT && region->alignment == RGN_ALIGN_LEFT) {
else if (scale_region->alignment == RGN_ALIGN_RIGHT && region->alignment == RGN_ALIGN_LEFT) {
dist -= region->winx;
}
else if (scalear->alignment == RGN_ALIGN_TOP &&
else if (scale_region->alignment == RGN_ALIGN_TOP &&
(region->alignment == RGN_ALIGN_BOTTOM ||
ELEM(
region->regiontype, RGN_TYPE_HEADER, RGN_TYPE_TOOL_HEADER, RGN_TYPE_FOOTER))) {
dist -= region->winy;
}
else if (scalear->alignment == RGN_ALIGN_BOTTOM &&
else if (scale_region->alignment == RGN_ALIGN_BOTTOM &&
(region->alignment == RGN_ALIGN_TOP ||
ELEM(
region->regiontype, RGN_TYPE_HEADER, RGN_TYPE_TOOL_HEADER, RGN_TYPE_FOOTER))) {

View File

@ -66,7 +66,7 @@ set(SRC
sculpt_brush_types.c
sculpt_cloth.c
sculpt_detail.c
sculpt_dyntopo.c
sculpt_dyntopo.cc
sculpt_expand.c
sculpt_face_set.cc
sculpt_filter_color.c

View File

@ -5,9 +5,10 @@
* \ingroup edsculpt
*/
#include "MEM_guardedalloc.h"
#include <cmath>
#include <cstdlib>
#include "BLI_task.h"
#include "MEM_guardedalloc.h"
#include "BLT_translation.h"
@ -41,14 +42,17 @@
#include "bmesh.h"
#include "bmesh_tools.h"
#include <math.h>
#include <stdlib.h>
void SCULPT_dynamic_topology_triangulate(BMesh *bm)
{
if (bm->totloop != bm->totface * 3) {
BM_mesh_triangulate(
bm, MOD_TRIANGULATE_QUAD_BEAUTY, MOD_TRIANGULATE_NGON_EARCLIP, 4, false, NULL, NULL, NULL);
BM_mesh_triangulate(bm,
MOD_TRIANGULATE_QUAD_BEAUTY,
MOD_TRIANGULATE_NGON_EARCLIP,
4,
false,
nullptr,
nullptr,
nullptr);
}
}
@ -59,7 +63,7 @@ void SCULPT_pbvh_clear(Object *ob)
/* Clear out any existing DM and PBVH. */
if (ss->pbvh) {
BKE_pbvh_free(ss->pbvh);
ss->pbvh = NULL;
ss->pbvh = nullptr;
}
MEM_SAFE_FREE(ss->pmap);
@ -75,7 +79,7 @@ void SCULPT_pbvh_clear(Object *ob)
void SCULPT_dynamic_topology_enable_ex(Main *bmain, Depsgraph *depsgraph, Scene *scene, Object *ob)
{
SculptSession *ss = ob->sculpt;
Mesh *me = ob->data;
Mesh *me = static_cast<Mesh *>(ob->data);
const BMAllocTemplate allocsize = BMALLOC_TEMPLATE_FROM_ME(me);
SCULPT_pbvh_clear(ob);
@ -87,19 +91,16 @@ void SCULPT_dynamic_topology_enable_ex(Main *bmain, Depsgraph *depsgraph, Scene
BKE_mesh_mselect_clear(me);
/* Create triangles-only BMesh. */
ss->bm = BM_mesh_create(&allocsize,
&((struct BMeshCreateParams){
.use_toolflags = false,
}));
BMeshCreateParams create_params{};
create_params.use_toolflags = false;
ss->bm = BM_mesh_create(&allocsize, &create_params);
BM_mesh_bm_from_me(ss->bm,
me,
(&(struct BMeshFromMeshParams){
.calc_face_normal = true,
.calc_vert_normal = true,
.use_shapekey = true,
.active_shapekey = ob->shapenr,
}));
BMeshFromMeshParams convert_params{};
convert_params.calc_face_normal = true;
convert_params.calc_vert_normal = true;
convert_params.use_shapekey = true;
convert_params.active_shapekey = ob->shapenr;
BM_mesh_bm_from_me(ss->bm, me, &convert_params);
SCULPT_dynamic_topology_triangulate(ss->bm);
BM_data_layer_add(ss->bm, &ss->bm->vdata, CD_PAINT_MASK);
@ -129,7 +130,7 @@ static void SCULPT_dynamic_topology_disable_ex(
Main *bmain, Depsgraph *depsgraph, Scene *scene, Object *ob, SculptUndoNode *unode)
{
SculptSession *ss = ob->sculpt;
Mesh *me = ob->data;
Mesh *me = static_cast<Mesh *>(ob->data);
if (ss->attrs.dyntopo_node_id_vertex) {
BKE_sculpt_attribute_destroy(ob, ss->attrs.dyntopo_node_id_vertex);
@ -175,7 +176,7 @@ static void SCULPT_dynamic_topology_disable_ex(
/* Sync the visibility to vertices manually as the pmap is still not initialized. */
bool *hide_vert = (bool *)CustomData_get_layer_named_for_write(
&me->vdata, CD_PROP_BOOL, ".hide_vert", me->totvert);
if (hide_vert != NULL) {
if (hide_vert != nullptr) {
memset(hide_vert, 0, sizeof(bool) * me->totvert);
}
}
@ -183,14 +184,14 @@ static void SCULPT_dynamic_topology_disable_ex(
/* Clear data. */
me->flag &= ~ME_SCULPT_DYNAMIC_TOPOLOGY;
/* Typically valid but with global-undo they can be NULL, see: T36234. */
/* Typically valid but with global-undo they can be nullptr, see: T36234. */
if (ss->bm) {
BM_mesh_free(ss->bm);
ss->bm = NULL;
ss->bm = nullptr;
}
if (ss->bm_log) {
BM_log_free(ss->bm_log);
ss->bm_log = NULL;
ss->bm_log = nullptr;
}
BKE_particlesystem_reset_all(ob);
@ -217,14 +218,14 @@ void sculpt_dynamic_topology_disable_with_undo(Main *bmain,
Object *ob)
{
SculptSession *ss = ob->sculpt;
if (ss->bm != NULL) {
if (ss->bm != nullptr) {
/* May be false in background mode. */
const bool use_undo = G.background ? (ED_undo_stack_get() != NULL) : true;
const bool use_undo = G.background ? (ED_undo_stack_get() != nullptr) : true;
if (use_undo) {
SCULPT_undo_push_begin_ex(ob, "Dynamic topology disable");
SCULPT_undo_push_node(ob, NULL, SCULPT_UNDO_DYNTOPO_END);
SCULPT_undo_push_node(ob, nullptr, SCULPT_UNDO_DYNTOPO_END);
}
SCULPT_dynamic_topology_disable_ex(bmain, depsgraph, scene, ob, NULL);
SCULPT_dynamic_topology_disable_ex(bmain, depsgraph, scene, ob, nullptr);
if (use_undo) {
SCULPT_undo_push_end(ob);
}
@ -237,21 +238,21 @@ static void sculpt_dynamic_topology_enable_with_undo(Main *bmain,
Object *ob)
{
SculptSession *ss = ob->sculpt;
if (ss->bm == NULL) {
if (ss->bm == nullptr) {
/* May be false in background mode. */
const bool use_undo = G.background ? (ED_undo_stack_get() != NULL) : true;
const bool use_undo = G.background ? (ED_undo_stack_get() != nullptr) : true;
if (use_undo) {
SCULPT_undo_push_begin_ex(ob, "Dynamic topology enable");
}
SCULPT_dynamic_topology_enable_ex(bmain, depsgraph, scene, ob);
if (use_undo) {
SCULPT_undo_push_node(ob, NULL, SCULPT_UNDO_DYNTOPO_BEGIN);
SCULPT_undo_push_node(ob, nullptr, SCULPT_UNDO_DYNTOPO_BEGIN);
SCULPT_undo_push_end(ob);
}
}
}
static int sculpt_dynamic_topology_toggle_exec(bContext *C, wmOperator *UNUSED(op))
static int sculpt_dynamic_topology_toggle_exec(bContext *C, wmOperator * /*op*/)
{
Main *bmain = CTX_data_main(C);
Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
@ -269,7 +270,7 @@ static int sculpt_dynamic_topology_toggle_exec(bContext *C, wmOperator *UNUSED(o
}
WM_cursor_wait(false);
WM_main_add_notifier(NC_SCENE | ND_TOOLSETTINGS, NULL);
WM_main_add_notifier(NC_SCENE | ND_TOOLSETTINGS, nullptr);
return OPERATOR_FINISHED;
}
@ -297,7 +298,7 @@ static int dyntopo_warning_popup(bContext *C, wmOperatorType *ot, enum eDynTopoW
uiItemS(layout);
}
uiItemFullO_ptr(layout, ot, IFACE_("OK"), ICON_NONE, NULL, WM_OP_EXEC_DEFAULT, 0, NULL);
uiItemFullO_ptr(layout, ot, IFACE_("OK"), ICON_NONE, nullptr, WM_OP_EXEC_DEFAULT, 0, nullptr);
UI_popup_menu_end(C, pup);
@ -306,12 +307,12 @@ static int dyntopo_warning_popup(bContext *C, wmOperatorType *ot, enum eDynTopoW
enum eDynTopoWarnFlag SCULPT_dynamic_topology_check(Scene *scene, Object *ob)
{
Mesh *me = ob->data;
Mesh *me = static_cast<Mesh *>(ob->data);
SculptSession *ss = ob->sculpt;
enum eDynTopoWarnFlag flag = 0;
enum eDynTopoWarnFlag flag = eDynTopoWarnFlag(0);
BLI_assert(ss->bm == NULL);
BLI_assert(ss->bm == nullptr);
UNUSED_VARS_NDEBUG(ss);
for (int i = 0; i < CD_NUMTYPES; i++) {
@ -334,7 +335,7 @@ enum eDynTopoWarnFlag SCULPT_dynamic_topology_check(Scene *scene, Object *ob)
/* Exception for shape keys because we can edit those. */
for (; md; md = md->next) {
const ModifierTypeInfo *mti = BKE_modifier_get_info(md->type);
const ModifierTypeInfo *mti = BKE_modifier_get_info(ModifierType(md->type));
if (!BKE_modifier_is_enabled(scene, md, eModifierMode_Realtime)) {
continue;
}
@ -351,7 +352,7 @@ enum eDynTopoWarnFlag SCULPT_dynamic_topology_check(Scene *scene, Object *ob)
static int sculpt_dynamic_topology_toggle_invoke(bContext *C,
wmOperator *op,
const wmEvent *UNUSED(event))
const wmEvent * /*event*/)
{
Object *ob = CTX_data_active_object(C);
SculptSession *ss = ob->sculpt;

View File

@ -1303,6 +1303,7 @@ enum eDynTopoWarnFlag {
DYNTOPO_WARN_LDATA = (1 << 2),
DYNTOPO_WARN_MODIFIER = (1 << 3),
};
ENUM_OPERATORS(eDynTopoWarnFlag, DYNTOPO_WARN_MODIFIER);
/** Enable dynamic topology; mesh will be triangulated */
void SCULPT_dynamic_topology_enable_ex(struct Main *bmain,

View File

@ -13,6 +13,7 @@
#include "BKE_node_tree_update.h"
#include "BKE_screen.h"
#include "NOD_socket.h"
#include "NOD_socket_search_link.hh"
#include "BLT_translation.h"
@ -198,7 +199,7 @@ static void search_link_ops_for_asset_metadata(const bNodeTree &node_tree,
DEG_relations_tag_update(&bmain);
/* Create the inputs and outputs on the new node. */
node.typeinfo->group_update_func(&params.node_tree, &node);
nodes::update_node_declaration_and_sockets(params.node_tree, node);
bNodeSocket *new_node_socket = bke::node_find_enabled_socket(
node, in_out, socket_property->name);

View File

@ -933,9 +933,9 @@ static void node_group_make_insert_selected(const bContext &C,
}
nodeRebuildIDVector(&ntree);
node_group_update(&ntree, gnode);
node_group_input_update(&group, input_node);
node_group_output_update(&group, output_node);
/* Update input and output node first, since the group node declaration can depend on them. */
nodes::update_node_declaration_and_sockets(group, *input_node);
nodes::update_node_declaration_and_sockets(group, *output_node);
/* move nodes in the group to the center */
for (bNode *node : nodes_to_move) {
@ -956,6 +956,7 @@ static void node_group_make_insert_selected(const bContext &C,
nodeRemLink(&ntree, link);
}
/* Handle links to the new group inputs. */
for (const auto item : input_links.items()) {
const char *interface_identifier = item.value.interface_socket->identifier;
bNodeSocket *input_socket = node_group_input_find_socket(input_node, interface_identifier);
@ -969,23 +970,17 @@ static void node_group_make_insert_selected(const bContext &C,
link->fromnode = input_node;
link->fromsock = input_socket;
}
/* Add a new link outside of the group. */
bNodeSocket *group_node_socket = node_group_find_input_socket(gnode, interface_identifier);
nodeAddLink(&ntree, item.value.from_node, item.key, gnode, group_node_socket);
}
/* Handle links to new group outputs. */
for (const OutputLinkInfo &info : output_links) {
/* Create a new link inside of the group. */
const char *io_identifier = info.interface_socket->identifier;
bNodeSocket *output_sock = node_group_output_find_socket(output_node, io_identifier);
nodeAddLink(&group, info.link->fromnode, info.link->fromsock, output_node, output_sock);
/* Reconnect the link to the group node instead of the node now inside the group. */
info.link->fromnode = gnode;
info.link->fromsock = node_group_find_output_socket(gnode, io_identifier);
}
/* Handle new links inside the group. */
for (const NewInternalLinkInfo &info : new_internal_links) {
const char *io_identifier = info.interface_socket->identifier;
if (info.socket->in_out == SOCK_IN) {
@ -997,6 +992,25 @@ static void node_group_make_insert_selected(const bContext &C,
nodeAddLink(&group, info.node, info.socket, output_node, output_socket);
}
}
bke::node_field_inferencing::update_field_inferencing(group);
nodes::update_node_declaration_and_sockets(ntree, *gnode);
/* Add new links to inputs outside of the group. */
for (const auto item : input_links.items()) {
const char *interface_identifier = item.value.interface_socket->identifier;
bNodeSocket *group_node_socket = node_group_find_input_socket(gnode, interface_identifier);
nodeAddLink(&ntree, item.value.from_node, item.key, gnode, group_node_socket);
}
/* Add new links to outputs outside the group. */
for (const OutputLinkInfo &info : output_links) {
/* Reconnect the link to the group node instead of the node now inside the group. */
info.link->fromnode = gnode;
info.link->fromsock = node_group_find_output_socket(gnode, info.interface_socket->identifier);
}
ED_node_tree_propagate_change(&C, bmain, nullptr);
}
static bNode *node_group_make_from_nodes(const bContext &C,
@ -1051,8 +1065,6 @@ static int node_group_make_exec(bContext *C, wmOperator *op)
}
}
ED_node_tree_propagate_change(C, bmain, nullptr);
WM_event_add_notifier(C, NC_NODE | NA_ADDED, nullptr);
/* We broke relations in node tree, need to rebuild them in the graphs. */
@ -1105,7 +1117,6 @@ static int node_group_insert_exec(bContext *C, wmOperator *op)
SpaceNode *snode = CTX_wm_space_node(C);
bNodeTree *ntree = snode->edittree;
const char *node_idname = node_group_idname(C);
Main *bmain = CTX_data_main(C);
ED_preview_kill_jobs(CTX_wm_manager(C), CTX_data_main(C));
@ -1137,7 +1148,6 @@ static int node_group_insert_exec(bContext *C, wmOperator *op)
nodeSetActive(ntree, gnode);
ED_node_tree_push(snode, ngroup, gnode);
ED_node_tree_propagate_change(C, bmain, nullptr);
return OPERATOR_FINISHED;
}

View File

@ -902,10 +902,14 @@ static void add_dragged_links_to_tree(bContext &C, bNodeLinkDrag &nldrag)
/* Before actually adding the link let nodes perform special link insertion handling. */
bNodeLink *new_link = MEM_new<bNodeLink>(__func__, link);
if (link.fromnode->typeinfo->insert_link) {
link.fromnode->typeinfo->insert_link(&ntree, link.fromnode, new_link);
if (!link.fromnode->typeinfo->insert_link(&ntree, link.fromnode, new_link)) {
continue;
}
}
if (link.tonode->typeinfo->insert_link) {
link.tonode->typeinfo->insert_link(&ntree, link.tonode, new_link);
if (!link.tonode->typeinfo->insert_link(&ntree, link.tonode, new_link)) {
continue;
}
}
/* Add link to the node tree. */

View File

@ -1563,7 +1563,7 @@ static void createTransEditVerts(bContext *UNUSED(C), TransInfo *t)
if (mirror_data.vert_map) {
tc->data_mirror_len = mirror_data.mirror_elem_len;
tc->data_mirror = MEM_mallocN(mirror_data.mirror_elem_len * sizeof(*tc->data_mirror),
tc->data_mirror = MEM_callocN(mirror_data.mirror_elem_len * sizeof(*tc->data_mirror),
__func__);
BM_ITER_MESH_INDEX (eve, &iter, bm, BM_VERTS_OF_MESH, a) {

View File

@ -885,10 +885,15 @@ static void compute_curve_trim_parameters(const bke::CurvesGeometry &curves,
if (end_length <= start_length) {
/* Single point. */
dst_curve_size[curve_i] = 1;
src_ranges[curve_i] = bke::curves::IndexRangeCyclic::get_range_from_size(
start_points[curve_i].index,
start_points[curve_i].is_controlpoint(), /* Only iterate if control point. */
point_count);
if (start_points[curve_i].is_controlpoint()) {
/* Only iterate if control point. */
const int single_point_index = start_points[curve_i].parameter == 1.0f ?
start_points[curve_i].next_index :
start_points[curve_i].index;
src_ranges[curve_i] = bke::curves::IndexRangeCyclic::get_range_from_size(
single_point_index, 1, point_count);
}
/* else: leave empty range */
}
else {
/* Split. */

View File

@ -2447,8 +2447,8 @@ static void lineart_object_load_single_instance(LineartData *ld,
/* Prepare the matrix used for transforming this specific object (instance). This has to be
* done before mesh boundbox check because the function needs that. */
mul_m4db_m4db_m4fl_uniq(obi->model_view_proj, ld->conf.view_projection, use_mat);
mul_m4db_m4db_m4fl_uniq(obi->model_view, ld->conf.view, use_mat);
mul_m4db_m4db_m4fl(obi->model_view_proj, ld->conf.view_projection, use_mat);
mul_m4db_m4db_m4fl(obi->model_view, ld->conf.view, use_mat);
if (!ELEM(ob->type, OB_MESH, OB_MBALL, OB_CURVES_LEGACY, OB_SURF, OB_FONT)) {
return;
@ -2524,7 +2524,7 @@ void lineart_main_load_geometries(Depsgraph *depsgraph,
}
invert_m4_m4(inv, ld->conf.cam_obmat);
mul_m4db_m4db_m4fl_uniq(result, proj, inv);
mul_m4db_m4db_m4fl(result, proj, inv);
copy_m4_m4_db(proj, result);
copy_m4_m4_db(ld->conf.view_projection, proj);

View File

@ -1226,7 +1226,7 @@ bool lineart_main_try_generate_shadow(Depsgraph *depsgraph,
proj, -ld->w, ld->w, -ld->h, ld->h, ld->conf.near_clip, ld->conf.far_clip);
}
invert_m4_m4(inv, ld->conf.cam_obmat);
mul_m4db_m4db_m4fl_uniq(result, proj, inv);
mul_m4db_m4db_m4fl(result, proj, inv);
copy_m4_m4_db(proj, result);
copy_m4_m4_db(ld->conf.view_projection, proj);
unit_m4_db(view);

View File

@ -45,9 +45,9 @@ typedef struct DrawDataList {
} DrawDataList;
typedef struct IDPropertyUIData {
/** Tooltip / property description pointer. Owned by the IDProperty. */
/** Tool-tip / property description pointer. Owned by the #IDProperty. */
char *description;
/** RNA subtype, used for every type except string properties (PropertySubType). */
/** RNA `subtype`, used for every type except string properties (#PropertySubType). */
int rna_subtype;
char _pad[4];
@ -68,7 +68,7 @@ typedef struct IDPropertyUIDataInt {
int default_value;
} IDPropertyUIDataInt;
/* IDP_UI_DATA_TYPE_BOOLEAN Use "int8_t" because DNA does not support "bool". */
/** For #IDP_UI_DATA_TYPE_BOOLEAN Use `int8_t` because DNA does not support `bool`. */
typedef struct IDPropertyUIDataBool {
IDPropertyUIData base;
int8_t *default_array; /* Only for array properties. */
@ -78,7 +78,7 @@ typedef struct IDPropertyUIDataBool {
int8_t default_value;
} IDPropertyUIDataBool;
/* IDP_UI_DATA_TYPE_FLOAT */
/** For #IDP_UI_DATA_TYPE_FLOAT */
typedef struct IDPropertyUIDataFloat {
IDPropertyUIData base;
double *default_array; /* Only for array properties. */
@ -95,13 +95,13 @@ typedef struct IDPropertyUIDataFloat {
double default_value;
} IDPropertyUIDataFloat;
/* IDP_UI_DATA_TYPE_STRING */
/** For #IDP_UI_DATA_TYPE_STRING */
typedef struct IDPropertyUIDataString {
IDPropertyUIData base;
char *default_value;
} IDPropertyUIDataString;
/* IDP_UI_DATA_TYPE_ID */
/** For #IDP_UI_DATA_TYPE_ID. */
typedef struct IDPropertyUIDataID {
IDPropertyUIData base;
} IDPropertyUIDataID;
@ -109,30 +109,39 @@ typedef struct IDPropertyUIDataID {
typedef struct IDPropertyData {
void *pointer;
ListBase group;
/** NOTE: we actually fit a double into these two 32bit integers. */
/** NOTE: a `double` is written into two 32bit integers. */
int val, val2;
} IDPropertyData;
typedef struct IDProperty {
struct IDProperty *next, *prev;
char type, subtype;
/** #eIDPropertyType */
char type;
/**
* #eIDPropertySubType when `type` is #IDP_STRING.
* #eIDPropertyType for all other types.
*/
char subtype;
/** #IDP_FLAG_GHOST and others. */
short flag;
/** MAX_IDPROP_NAME. */
/** Size matches #MAX_IDPROP_NAME. */
char name[64];
/* saved is used to indicate if this struct has been saved yet.
* seemed like a good idea as a '_pad' var was needed anyway :) */
int saved;
char _pad0[4];
/** NOTE: alignment for 64 bits. */
IDPropertyData data;
/* Array length, also (this is important!) string length + 1.
* the idea is to be able to reuse array realloc functions on strings. */
/**
* Array length, and importantly string length + 1.
* the idea is to be able to reuse array reallocation functions on strings.
*/
int len;
/* Strings and arrays are both buffered, though the buffer isn't saved. */
/* totallen is total length of allocated array/string, including a buffer.
* Note that the buffering is mild; the code comes from python's list implementation. */
/**
* Strings and arrays are both buffered, though the buffer isn't saved.
* `totallen` is total length of allocated array/string, including a buffer.
* \note the buffering is mild; see #IDP_ResizeIDPArray for details.
*/
int totallen;
IDPropertyUIData *ui_data;
@ -141,7 +150,7 @@ typedef struct IDProperty {
#define MAX_IDPROP_NAME 64
#define DEFAULT_ALLOC_FOR_NULL_STRINGS 64
/*->type*/
/** #IDProperty.type */
typedef enum eIDPropertyType {
IDP_STRING = 0,
IDP_INT = 1,
@ -173,27 +182,29 @@ enum {
IDP_TYPE_FILTER_BOOLEAN = 1 << 10,
};
/*->subtype */
/* IDP_STRING */
enum {
/** #IDProperty.subtype for #IDP_STRING properties. */
typedef enum eIDPropertySubType {
IDP_STRING_SUB_UTF8 = 0, /* default */
IDP_STRING_SUB_BYTE = 1, /* arbitrary byte array, _not_ null terminated */
};
} eIDPropertySubType;
/*->flag*/
/** #IDProperty.flag. */
enum {
/** This IDProp may be statically overridden.
* Should only be used/be relevant for custom properties. */
/**
* This #IDProperty may be statically overridden.
* Should only be used/be relevant for custom properties.
*/
IDP_FLAG_OVERRIDABLE_LIBRARY = 1 << 0,
/** This collection item IDProp has been inserted in a local override.
/**
* This collection item #IDProperty has been inserted in a local override.
* This is used by internal code to distinguish between library-originated items and
* local-inserted ones, as many operations are not allowed on the former. */
* local-inserted ones, as many operations are not allowed on the former.
*/
IDP_FLAG_OVERRIDELIBRARY_LOCAL = 1 << 1,
/** This means the property is set but RNA will return false when checking
* 'RNA_property_is_set', currently this is a runtime flag */
/**
* This means the property is set but RNA will return false when checking
* #RNA_property_is_set, currently this is a runtime flag.
*/
IDP_FLAG_GHOST = 1 << 7,
};
@ -208,7 +219,7 @@ typedef struct IDOverrideLibraryPropertyOperation {
short operation;
short flag;
/** Runtime, tags are common to both IDOverrideProperty and IDOverridePropertyOperation. */
/** Runtime, tags are common to both #IDOverrideProperty and #IDOverridePropertyOperation. */
short tag;
char _pad0[2];

View File

@ -1738,7 +1738,7 @@ static void rna_Node_update_reg(bNodeTree *ntree, bNode *node)
RNA_parameter_list_free(&list);
}
static void rna_Node_insert_link(bNodeTree *ntree, bNode *node, bNodeLink *link)
static bool rna_Node_insert_link(bNodeTree *ntree, bNode *node, bNodeLink *link)
{
extern FunctionRNA rna_Node_insert_link_func;
@ -1754,6 +1754,7 @@ static void rna_Node_insert_link(bNodeTree *ntree, bNode *node, bNodeLink *link)
node->typeinfo->rna_ext.call(NULL, &ptr, func, &list);
RNA_parameter_list_free(&list);
return true;
}
static void rna_Node_init(const bContext *C, PointerRNA *ptr)
@ -3386,9 +3387,6 @@ static StructRNA *rna_NodeCustomGroup_register(Main *bmain,
return NULL;
}
/* this updates the group node instance from the tree's interface */
nt->group_update_func = node_group_update;
nodeRegisterType(nt);
/* update while blender is running */
@ -3412,7 +3410,6 @@ static StructRNA *rna_GeometryNodeCustomGroup_register(Main *bmain,
return NULL;
}
nt->group_update_func = node_group_update;
nt->type = NODE_CUSTOM_GROUP;
register_node_type_geo_custom_group(nt);
@ -3441,7 +3438,6 @@ static StructRNA *rna_ShaderNodeCustomGroup_register(Main *bmain,
return NULL;
}
nt->group_update_func = node_group_update;
nt->type = NODE_CUSTOM_GROUP;
register_node_type_sh_custom_group(nt);
@ -3467,7 +3463,6 @@ static StructRNA *rna_CompositorNodeCustomGroup_register(Main *bmain,
return NULL;
}
nt->group_update_func = node_group_update;
nt->type = NODE_CUSTOM_GROUP;
register_node_type_cmp_custom_group(nt);

View File

@ -17,16 +17,24 @@ extern "C" {
struct bNodeSocket *node_group_find_input_socket(struct bNode *groupnode, const char *identifier);
struct bNodeSocket *node_group_find_output_socket(struct bNode *groupnode, const char *identifier);
/** Make sure all group node in ntree, which use ngroup, are sync'd. */
void node_group_update(struct bNodeTree *ntree, struct bNode *node);
struct bNodeSocket *node_group_input_find_socket(struct bNode *node, const char *identifier);
struct bNodeSocket *node_group_output_find_socket(struct bNode *node, const char *identifier);
void node_group_input_update(struct bNodeTree *ntree, struct bNode *node);
void node_group_output_update(struct bNodeTree *ntree, struct bNode *node);
void node_internal_links_create(struct bNodeTree *ntree, struct bNode *node);
#ifdef __cplusplus
}
#endif
#ifdef __cplusplus
namespace blender::nodes {
void node_group_declare_dynamic(const bNodeTree &node_tree,
const bNode &node,
NodeDeclaration &r_declaration);
} // namespace blender::nodes
#endif

View File

@ -160,6 +160,7 @@ class SocketDeclaration {
InputSocketFieldType input_field_type = InputSocketFieldType::None;
OutputFieldDependency output_field_dependency;
private:
/** The priority of the input for determining the domain of the node. See
* realtime_compositor::InputDescriptor for more information. */
int compositor_domain_priority_ = 0;
@ -461,6 +462,11 @@ class NodeDeclaration {
Vector<SocketDeclarationPtr> outputs;
std::unique_ptr<aal::RelationsInNode> anonymous_attribute_relations_;
/** Leave the sockets in place, even if they don't match the declaration. Used for dynamic
* declarations when the information used to build the declaration is missing, but might become
* available again in the future. */
bool skip_updating_sockets = false;
friend NodeDeclarationBuilder;
bool matches(const bNode &node) const;
@ -523,6 +529,9 @@ void id_or_index(const bNode &node, void *r_value);
} // namespace implicit_field_inputs
void build_node_declaration(const bNodeType &typeinfo, NodeDeclaration &r_declaration);
void build_node_declaration_dynamic(const bNodeTree &node_tree,
const bNode &node,
NodeDeclaration &r_declaration);
template<typename SocketDecl>
typename SocketDeclarationBuilder<SocketDecl>::Self &SocketDeclarationBuilder<

View File

@ -36,3 +36,13 @@ void register_standard_node_socket_types(void);
#ifdef __cplusplus
}
#endif
#ifdef __cplusplus
namespace blender::nodes {
void update_node_declaration_and_sockets(bNodeTree &ntree, bNode &node);
} // namespace blender::nodes
#endif

View File

@ -104,6 +104,7 @@ class Bool : public SocketDeclaration {
bNodeSocket &build(bNodeTree &ntree, bNode &node) const override;
bool matches(const bNodeSocket &socket) const override;
bNodeSocket &update_or_build(bNodeTree &ntree, bNode &node, bNodeSocket &socket) const override;
bool can_connect(const bNodeSocket &socket) const override;
};
@ -124,6 +125,7 @@ class Color : public SocketDeclaration {
bNodeSocket &build(bNodeTree &ntree, bNode &node) const override;
bool matches(const bNodeSocket &socket) const override;
bNodeSocket &update_or_build(bNodeTree &ntree, bNode &node, bNodeSocket &socket) const override;
bool can_connect(const bNodeSocket &socket) const override;
};
@ -144,6 +146,7 @@ class String : public SocketDeclaration {
bNodeSocket &build(bNodeTree &ntree, bNode &node) const override;
bool matches(const bNodeSocket &socket) const override;
bNodeSocket &update_or_build(bNodeTree &ntree, bNode &node, bNodeSocket &socket) const override;
bool can_connect(const bNodeSocket &socket) const override;
};
@ -216,6 +219,34 @@ class Shader : public SocketDeclaration {
class ShaderBuilder : public SocketDeclarationBuilder<Shader> {
};
class ExtendBuilder;
class Extend : public SocketDeclaration {
private:
friend ExtendBuilder;
public:
using Builder = ExtendBuilder;
bNodeSocket &build(bNodeTree &ntree, bNode &node) const override;
bool matches(const bNodeSocket &socket) const override;
bNodeSocket &update_or_build(bNodeTree &ntree, bNode &node, bNodeSocket &socket) const override;
bool can_connect(const bNodeSocket &socket) const override;
};
class ExtendBuilder : public SocketDeclarationBuilder<Extend> {
};
class Custom : public SocketDeclaration {
public:
const char *idname_;
bNodeSocket &build(bNodeTree &ntree, bNode &node) const override;
bool matches(const bNodeSocket &socket) const override;
bNodeSocket &update_or_build(bNodeTree &ntree, bNode &node, bNodeSocket &socket) const override;
bool can_connect(const bNodeSocket &socket) const override;
};
/* -------------------------------------------------------------------- */
/** \name #FloatBuilder Inline Methods
* \{ */

View File

@ -32,7 +32,7 @@ void register_node_type_cmp_group()
node_type_size(&ntype, 140, 60, 400);
ntype.labelfunc = node_group_label;
ntype.group_update_func = node_group_update;
ntype.declare_dynamic = blender::nodes::node_group_declare_dynamic;
nodeRegisterType(&ntype);
}

View File

@ -147,6 +147,7 @@ static void node_geo_exec(GeoNodeExecParams params)
if (!attribute_id) {
params.set_output("Geometry", geometry_set);
params.set_default_remaining_outputs();
return;
}

View File

@ -3,11 +3,41 @@
#include "BKE_node.h"
#include "NOD_geometry.h"
#include "NOD_node_declaration.hh"
#include "NOD_common.h"
#include "node_common.h"
#include "node_geometry_util.hh"
namespace blender::nodes {
static void node_declare(const bNodeTree &node_tree,
const bNode &node,
NodeDeclaration &r_declaration)
{
const bNodeTree *group = reinterpret_cast<const bNodeTree *>(node.id);
if (!group) {
return;
}
node_group_declare_dynamic(node_tree, node, r_declaration);
if (!node.id) {
return;
}
if (ID_IS_LINKED(&group->id) && (group->id.tag & LIB_TAG_MISSING)) {
return;
}
const FieldInferencingInterface &field_interface = *group->runtime->field_inferencing_interface;
for (const int i : r_declaration.inputs.index_range()) {
r_declaration.inputs[i]->input_field_type = field_interface.inputs[i];
}
for (const int i : r_declaration.outputs.index_range()) {
r_declaration.outputs[i]->output_field_dependency = field_interface.outputs[i];
}
}
} // namespace blender::nodes
void register_node_type_geo_group()
{
static bNodeType ntype;
@ -23,7 +53,7 @@ void register_node_type_geo_group()
node_type_size(&ntype, 140, 60, 400);
ntype.labelfunc = node_group_label;
ntype.group_update_func = node_group_update;
ntype.declare_dynamic = blender::nodes::node_declare;
nodeRegisterType(&ntype);
}

View File

@ -55,13 +55,15 @@ static void transform_positions(MutableSpan<float3> positions, const float4x4 &m
static void translate_mesh(Mesh &mesh, const float3 translation)
{
if (!math::is_zero(translation)) {
BKE_mesh_translate(&mesh, translation, false);
translate_positions(mesh.vert_positions_for_write(), translation);
BKE_mesh_tag_coords_changed_uniformly(&mesh);
}
}
static void transform_mesh(Mesh &mesh, const float4x4 &transform)
{
BKE_mesh_transform(&mesh, transform.values, false);
transform_positions(mesh.vert_positions_for_write(), transform);
BKE_mesh_tag_coords_changed(&mesh);
}
static void translate_pointcloud(PointCloud &pointcloud, const float3 translation)
@ -162,16 +164,17 @@ static void translate_volume(GeoNodeExecParams &params,
static void transform_curve_edit_hints(bke::CurvesEditHints &edit_hints, const float4x4 &transform)
{
if (edit_hints.positions.has_value()) {
for (float3 &pos : *edit_hints.positions) {
pos = transform * pos;
}
transform_positions(*edit_hints.positions, transform);
}
float3x3 deform_mat;
copy_m3_m4(deform_mat.values, transform.values);
if (edit_hints.deform_mats.has_value()) {
for (float3x3 &mat : *edit_hints.deform_mats) {
mat = deform_mat * mat;
}
MutableSpan<float3x3> deform_mats = *edit_hints.deform_mats;
threading::parallel_for(deform_mats.index_range(), 1024, [&](const IndexRange range) {
for (const int64_t i : range) {
deform_mats[i] = deform_mat * deform_mats[i];
}
});
}
else {
edit_hints.deform_mats.emplace(edit_hints.curves_id_orig.geometry.point_num, deform_mat);
@ -181,9 +184,7 @@ static void transform_curve_edit_hints(bke::CurvesEditHints &edit_hints, const f
static void translate_curve_edit_hints(bke::CurvesEditHints &edit_hints, const float3 &translation)
{
if (edit_hints.positions.has_value()) {
for (float3 &pos : *edit_hints.positions) {
pos += translation;
}
translate_positions(*edit_hints.positions, translation);
}
}

View File

@ -30,7 +30,11 @@
#include "MEM_guardedalloc.h"
#include "NOD_common.h"
#include "NOD_node_declaration.hh"
#include "NOD_register.hh"
#include "NOD_socket.h"
#include "NOD_socket_declarations.hh"
#include "NOD_socket_declarations_geometry.hh"
#include "node_common.h"
#include "node_util.h"
@ -120,124 +124,124 @@ bool nodeGroupPoll(const bNodeTree *nodetree,
return true;
}
static void add_new_socket_from_interface(bNodeTree &node_tree,
bNode &node,
const bNodeSocket &interface_socket,
const eNodeSocketInOut in_out)
{
bNodeSocket *socket = nodeAddSocket(&node_tree,
&node,
in_out,
interface_socket.idname,
interface_socket.identifier,
interface_socket.name);
namespace blender::nodes {
if (interface_socket.typeinfo->interface_init_socket) {
interface_socket.typeinfo->interface_init_socket(
&node_tree, &interface_socket, &node, socket, "interface");
static SocketDeclarationPtr declaration_for_interface_socket(const bNodeSocket &io_socket)
{
SocketDeclarationPtr dst;
switch (io_socket.type) {
case SOCK_FLOAT: {
const auto &value = *io_socket.default_value_typed<bNodeSocketValueFloat>();
std::unique_ptr<decl::Float> decl = std::make_unique<decl::Float>();
decl->subtype = PropertySubType(io_socket.typeinfo->subtype);
decl->default_value = value.value;
decl->soft_min_value = value.min;
decl->soft_max_value = value.max;
dst = std::move(decl);
break;
}
case SOCK_VECTOR: {
const auto &value = *io_socket.default_value_typed<bNodeSocketValueVector>();
std::unique_ptr<decl::Vector> decl = std::make_unique<decl::Vector>();
decl->subtype = PropertySubType(io_socket.typeinfo->subtype);
decl->default_value = value.value;
decl->soft_min_value = value.min;
decl->soft_max_value = value.max;
dst = std::move(decl);
break;
}
case SOCK_RGBA: {
const auto &value = *io_socket.default_value_typed<bNodeSocketValueRGBA>();
std::unique_ptr<decl::Color> decl = std::make_unique<decl::Color>();
decl->default_value = value.value;
dst = std::move(decl);
break;
}
case SOCK_SHADER: {
std::unique_ptr<decl::Shader> decl = std::make_unique<decl::Shader>();
dst = std::move(decl);
break;
}
case SOCK_BOOLEAN: {
const auto &value = *io_socket.default_value_typed<bNodeSocketValueBoolean>();
std::unique_ptr<decl::Bool> decl = std::make_unique<decl::Bool>();
decl->default_value = value.value;
dst = std::move(decl);
break;
}
case SOCK_INT: {
const auto &value = *io_socket.default_value_typed<bNodeSocketValueInt>();
std::unique_ptr<decl::Int> decl = std::make_unique<decl::Int>();
decl->subtype = PropertySubType(io_socket.typeinfo->subtype);
decl->default_value = value.value;
decl->soft_min_value = value.min;
decl->soft_max_value = value.max;
dst = std::move(decl);
break;
}
case SOCK_STRING: {
const auto &value = *io_socket.default_value_typed<bNodeSocketValueString>();
std::unique_ptr<decl::String> decl = std::make_unique<decl::String>();
decl->default_value = value.value;
dst = std::move(decl);
break;
}
case SOCK_OBJECT:
dst = std::make_unique<decl::Object>();
break;
case SOCK_IMAGE:
dst = std::make_unique<decl::Image>();
break;
case SOCK_GEOMETRY:
dst = std::make_unique<decl::Geometry>();
break;
case SOCK_COLLECTION:
dst = std::make_unique<decl::Collection>();
break;
case SOCK_TEXTURE:
dst = std::make_unique<decl::Texture>();
break;
case SOCK_MATERIAL:
dst = std::make_unique<decl::Material>();
break;
case SOCK_CUSTOM:
std::unique_ptr<decl::Custom> decl = std::make_unique<decl::Custom>();
decl->idname_ = io_socket.idname;
dst = std::move(decl);
break;
}
dst->name = io_socket.name;
dst->identifier = io_socket.identifier;
dst->in_out = eNodeSocketInOut(io_socket.in_out);
dst->description = io_socket.description;
dst->hide_value = io_socket.flag & SOCK_HIDE_VALUE;
dst->compact = io_socket.flag & SOCK_COMPACT;
return dst;
}
void node_group_declare_dynamic(const bNodeTree & /*node_tree*/,
const bNode &node,
NodeDeclaration &r_declaration)
{
const bNodeTree *group = reinterpret_cast<const bNodeTree *>(node.id);
if (!group) {
return;
}
if (ID_IS_LINKED(&group->id) && (group->id.tag & LIB_TAG_MISSING)) {
r_declaration.skip_updating_sockets = true;
return;
}
r_declaration.skip_updating_sockets = false;
LISTBASE_FOREACH (const bNodeSocket *, input, &group->inputs) {
r_declaration.inputs.append(declaration_for_interface_socket(*input));
}
LISTBASE_FOREACH (const bNodeSocket *, output, &group->outputs) {
r_declaration.outputs.append(declaration_for_interface_socket(*output));
}
}
static void update_socket_to_match_interface(bNodeTree &node_tree,
bNode &node,
bNodeSocket &socket_to_update,
const bNodeSocket &interface_socket)
{
strcpy(socket_to_update.name, interface_socket.name);
const int mask = SOCK_HIDE_VALUE;
socket_to_update.flag = (socket_to_update.flag & ~mask) | (interface_socket.flag & mask);
/* Update socket type if necessary */
if (socket_to_update.typeinfo != interface_socket.typeinfo) {
nodeModifySocketType(&node_tree, &node, &socket_to_update, interface_socket.idname);
}
if (interface_socket.typeinfo->interface_verify_socket) {
interface_socket.typeinfo->interface_verify_socket(
&node_tree, &interface_socket, &node, &socket_to_update, "interface");
}
}
/**
* Used for group nodes and group input/output nodes to update the list of input or output sockets
* on a node to match the provided interface. Assumes that \a verify_lb is the node's matching
* input or output socket list, depending on whether the node is a group input/output or a group
* node.
*/
static void group_verify_socket_list(bNodeTree &node_tree,
bNode &node,
const ListBase &interface_sockets,
ListBase &verify_lb,
const eNodeSocketInOut in_out,
const bool ensure_extend_socket_exists)
{
ListBase old_sockets = verify_lb;
Vector<bNodeSocket *> ordered_old_sockets = old_sockets;
BLI_listbase_clear(&verify_lb);
LISTBASE_FOREACH (const bNodeSocket *, interface_socket, &interface_sockets) {
bNodeSocket *matching_socket = find_matching_socket(old_sockets, interface_socket->identifier);
if (matching_socket) {
/* If a socket with the same identifier exists in the previous socket list, update it
* with the correct name, type, etc. Then move it from the old list to the new one. */
update_socket_to_match_interface(node_tree, node, *matching_socket, *interface_socket);
BLI_remlink(&old_sockets, matching_socket);
BLI_addtail(&verify_lb, matching_socket);
}
else {
/* If there was no socket with the same identifier already, simply create a new socket
* based on the interface socket, which will already add it to the new list. */
add_new_socket_from_interface(node_tree, node, *interface_socket, in_out);
}
}
if (ensure_extend_socket_exists) {
bNodeSocket *last_socket = static_cast<bNodeSocket *>(old_sockets.last);
if (last_socket != nullptr && STREQ(last_socket->identifier, "__extend__")) {
BLI_remlink(&old_sockets, last_socket);
BLI_addtail(&verify_lb, last_socket);
}
else {
nodeAddSocket(&node_tree, &node, in_out, "NodeSocketVirtual", "__extend__", "");
}
}
/* Remove leftover sockets that didn't match the node group's interface. */
LISTBASE_FOREACH_MUTABLE (bNodeSocket *, unused_socket, &old_sockets) {
nodeRemoveSocket(&node_tree, &node, unused_socket);
}
{
/* Check if new sockets match the old sockets. */
int index;
LISTBASE_FOREACH_INDEX (bNodeSocket *, new_socket, &verify_lb, index) {
if (index < ordered_old_sockets.size()) {
if (ordered_old_sockets[index] != new_socket) {
BKE_ntree_update_tag_interface(&node_tree);
break;
}
}
}
}
}
void node_group_update(struct bNodeTree *ntree, struct bNode *node)
{
/* check inputs and outputs, and remove or insert them */
if (node->id == nullptr) {
nodeRemoveAllSockets(ntree, node);
}
else if (ID_IS_LINKED(node->id) && (node->id->tag & LIB_TAG_MISSING)) {
/* Missing data-block, leave sockets unchanged so that when it comes back
* the links remain valid. */
}
else {
bNodeTree *ngroup = (bNodeTree *)node->id;
group_verify_socket_list(*ntree, *node, ngroup->inputs, node->inputs, SOCK_IN, false);
group_verify_socket_list(*ntree, *node, ngroup->outputs, node->outputs, SOCK_OUT, false);
}
}
} // namespace blender::nodes
/** \} */
@ -419,16 +423,6 @@ bool BKE_node_is_connected_to_output(const bNodeTree *ntree, const bNode *node)
/** \name Node #GROUP_INPUT / #GROUP_OUTPUT
* \{ */
static bool is_group_extension_socket(const bNode *node, const bNodeSocket *socket)
{
return socket->type == SOCK_CUSTOM && ELEM(node->type, NODE_GROUP_OUTPUT, NODE_GROUP_INPUT);
}
static void node_group_input_init(bNodeTree *ntree, bNode *node)
{
node_group_input_update(ntree, node);
}
bNodeSocket *node_group_input_find_socket(bNode *node, const char *identifier)
{
bNodeSocket *sock;
@ -440,59 +434,83 @@ bNodeSocket *node_group_input_find_socket(bNode *node, const char *identifier)
return nullptr;
}
void node_group_input_update(bNodeTree *ntree, bNode *node)
namespace blender::nodes {
static SocketDeclarationPtr extend_declaration(const eNodeSocketInOut in_out)
{
bNodeSocket *extsock = (bNodeSocket *)node->outputs.last;
/* Adding a tree socket and verifying will remove the extension socket!
* This list caches the existing links from the extension socket
* so they can be recreated after verification. */
Vector<bNodeLink> temp_links;
/* find links from the extension socket and store them */
LISTBASE_FOREACH_MUTABLE (bNodeLink *, link, &ntree->links) {
if (nodeLinkIsHidden(link)) {
continue;
}
if (link->fromsock == extsock) {
temp_links.append(*link);
nodeRemLink(ntree, link);
}
}
/* find valid link to expose */
bNodeLink *exposelink = nullptr;
for (bNodeLink &link : temp_links) {
/* XXX Multiple sockets can be connected to the extension socket at once,
* in that case the arbitrary first link determines name and type.
* This could be improved by choosing the "best" type among all links,
* whatever that means.
*/
if (!is_group_extension_socket(link.tonode, link.tosock)) {
exposelink = &link;
break;
}
}
if (exposelink) {
bNodeSocket *gsock = ntreeAddSocketInterfaceFromSocket(
ntree, exposelink->tonode, exposelink->tosock);
node_group_input_update(ntree, node);
bNodeSocket *newsock = node_group_input_find_socket(node, gsock->identifier);
/* redirect links from the extension socket */
for (bNodeLink &link : temp_links) {
bNodeLink *newlink = nodeAddLink(ntree, node, newsock, link.tonode, link.tosock);
if (newlink->tosock->flag & SOCK_MULTI_INPUT) {
newlink->multi_input_socket_index = link.multi_input_socket_index;
}
}
}
group_verify_socket_list(*ntree, *node, ntree->inputs, node->outputs, SOCK_OUT, true);
std::unique_ptr<decl::Extend> decl = std::make_unique<decl::Extend>();
decl->name = "";
decl->identifier = "__extend__";
decl->in_out = in_out;
return decl;
}
static void group_input_declare_dynamic(const bNodeTree &node_tree,
const bNode & /*node*/,
NodeDeclaration &r_declaration)
{
LISTBASE_FOREACH (const bNodeSocket *, input, &node_tree.inputs) {
r_declaration.outputs.append(declaration_for_interface_socket(*input));
r_declaration.outputs.last()->in_out = SOCK_OUT;
}
r_declaration.outputs.append(extend_declaration(SOCK_OUT));
}
static void group_output_declare_dynamic(const bNodeTree &node_tree,
const bNode & /*node*/,
NodeDeclaration &r_declaration)
{
LISTBASE_FOREACH (const bNodeSocket *, input, &node_tree.outputs) {
r_declaration.inputs.append(declaration_for_interface_socket(*input));
r_declaration.inputs.last()->in_out = SOCK_IN;
}
r_declaration.inputs.append(extend_declaration(SOCK_IN));
}
static bool group_input_insert_link(bNodeTree *ntree, bNode *node, bNodeLink *link)
{
BLI_assert(link->tonode != node);
BLI_assert(link->tosock->in_out == SOCK_IN);
if (link->fromsock->identifier != StringRef("__extend__")) {
return true;
}
if (link->tosock->identifier == StringRef("__extend__")) {
/* Don't connect to other "extend" sockets. */
return false;
}
const bNodeSocket *io_socket = ntreeAddSocketInterfaceFromSocket(
ntree, link->tonode, link->tosock);
if (!io_socket) {
return false;
}
update_node_declaration_and_sockets(*ntree, *node);
link->fromsock = node_group_input_find_socket(node, io_socket->identifier);
return true;
}
static bool group_output_insert_link(bNodeTree *ntree, bNode *node, bNodeLink *link)
{
BLI_assert(link->fromnode != node);
BLI_assert(link->fromsock->in_out == SOCK_OUT);
if (link->tosock->identifier != StringRef("__extend__")) {
return true;
}
if (link->fromsock->identifier == StringRef("__extend__")) {
/* Don't connect to other "extend" sockets. */
return false;
}
const bNodeSocket *io_socket = ntreeAddSocketInterfaceFromSocket(
ntree, link->fromnode, link->fromsock);
if (!io_socket) {
return false;
}
update_node_declaration_and_sockets(*ntree, *node);
link->tosock = node_group_output_find_socket(node, io_socket->identifier);
return true;
}
} // namespace blender::nodes
void register_node_type_group_input()
{
/* used for all tree types, needs dynamic allocation */
@ -501,17 +519,12 @@ void register_node_type_group_input()
node_type_base(ntype, NODE_GROUP_INPUT, "Group Input", NODE_CLASS_INTERFACE);
node_type_size(ntype, 140, 80, 400);
ntype->initfunc = node_group_input_init;
ntype->updatefunc = node_group_input_update;
ntype->declare_dynamic = blender::nodes::group_input_declare_dynamic;
ntype->insert_link = blender::nodes::group_input_insert_link;
nodeRegisterType(ntype);
}
static void node_group_output_init(bNodeTree *ntree, bNode *node)
{
node_group_output_update(ntree, node);
}
bNodeSocket *node_group_output_find_socket(bNode *node, const char *identifier)
{
bNodeSocket *sock;
@ -523,57 +536,6 @@ bNodeSocket *node_group_output_find_socket(bNode *node, const char *identifier)
return nullptr;
}
void node_group_output_update(bNodeTree *ntree, bNode *node)
{
bNodeSocket *extsock = (bNodeSocket *)node->inputs.last;
/* Adding a tree socket and verifying will remove the extension socket!
* This list caches the existing links to the extension socket
* so they can be recreated after verification. */
Vector<bNodeLink> temp_links;
/* find links to the extension socket and store them */
LISTBASE_FOREACH_MUTABLE (bNodeLink *, link, &ntree->links) {
if (nodeLinkIsHidden(link)) {
continue;
}
if (link->tosock == extsock) {
temp_links.append(*link);
nodeRemLink(ntree, link);
}
}
/* find valid link to expose */
bNodeLink *exposelink = nullptr;
for (bNodeLink &link : temp_links) {
/* XXX Multiple sockets can be connected to the extension socket at once,
* in that case the arbitrary first link determines name and type.
* This could be improved by choosing the "best" type among all links,
* whatever that means.
*/
if (!is_group_extension_socket(link.fromnode, link.fromsock)) {
exposelink = &link;
break;
}
}
if (exposelink) {
/* XXX what if connecting virtual to virtual socket?? */
bNodeSocket *gsock = ntreeAddSocketInterfaceFromSocket(
ntree, exposelink->fromnode, exposelink->fromsock);
node_group_output_update(ntree, node);
bNodeSocket *newsock = node_group_output_find_socket(node, gsock->identifier);
/* redirect links to the extension socket */
for (bNodeLink &link : temp_links) {
nodeAddLink(ntree, link.fromnode, link.fromsock, node, newsock);
}
}
group_verify_socket_list(*ntree, *node, ntree->outputs, node->inputs, SOCK_IN, true);
}
void register_node_type_group_output()
{
/* used for all tree types, needs dynamic allocation */
@ -582,8 +544,8 @@ void register_node_type_group_output()
node_type_base(ntype, NODE_GROUP_OUTPUT, "Group Output", NODE_CLASS_INTERFACE);
node_type_size(ntype, 140, 80, 400);
ntype->initfunc = node_group_output_init;
ntype->updatefunc = node_group_output_update;
ntype->declare_dynamic = blender::nodes::group_output_declare_dynamic;
ntype->insert_link = blender::nodes::group_output_insert_link;
ntype->no_muting = true;

View File

@ -16,6 +16,15 @@ void build_node_declaration(const bNodeType &typeinfo, NodeDeclaration &r_declar
node_decl_builder.finalize();
}
void build_node_declaration_dynamic(const bNodeTree &node_tree,
const bNode &node,
NodeDeclaration &r_declaration)
{
r_declaration.inputs.clear();
r_declaration.outputs.clear();
node.typeinfo->declare_dynamic(node_tree, node, r_declaration);
}
void NodeDeclarationBuilder::finalize()
{
if (is_function_node_) {

View File

@ -19,6 +19,7 @@
#include "BKE_lib_id.h"
#include "BKE_node.h"
#include "BKE_node_runtime.hh"
#include "BKE_node_tree_update.h"
#include "DNA_collection_types.h"
#include "DNA_material_types.h"
@ -171,6 +172,8 @@ static void verify_socket_template_list(bNodeTree *ntree,
}
}
namespace blender::nodes {
static void refresh_socket_list(bNodeTree &ntree,
bNode &node,
ListBase &sockets,
@ -232,6 +235,7 @@ static void refresh_socket_list(bNodeTree &ntree,
}
}
new_sockets.add_new(new_socket);
BKE_ntree_update_tag_socket_new(&ntree, new_socket);
}
LISTBASE_FOREACH_MUTABLE (bNodeSocket *, old_socket, &sockets) {
if (!new_sockets.contains(old_socket)) {
@ -249,10 +253,29 @@ static void refresh_node(bNodeTree &ntree,
blender::nodes::NodeDeclaration &node_decl,
bool do_id_user)
{
refresh_socket_list(ntree, node, node.inputs, node_decl.inputs, do_id_user);
refresh_socket_list(ntree, node, node.outputs, node_decl.outputs, do_id_user);
if (node_decl.skip_updating_sockets) {
return;
}
if (!node_decl.matches(node)) {
refresh_socket_list(ntree, node, node.inputs, node_decl.inputs, do_id_user);
refresh_socket_list(ntree, node, node.outputs, node_decl.outputs, do_id_user);
}
nodeSocketDeclarationsUpdate(&node);
}
void update_node_declaration_and_sockets(bNodeTree &ntree, bNode &node)
{
if (node.typeinfo->declare_dynamic) {
if (!node.runtime->declaration) {
node.runtime->declaration = new NodeDeclaration();
}
build_node_declaration_dynamic(ntree, node, *node.runtime->declaration);
}
refresh_node(ntree, node, *node.runtime->declaration, true);
}
} // namespace blender::nodes
void node_verify_sockets(bNodeTree *ntree, bNode *node, bool do_id_user)
{
bNodeType *ntype = node->typeinfo;
@ -261,10 +284,7 @@ void node_verify_sockets(bNodeTree *ntree, bNode *node, bool do_id_user)
}
if (ntype->declare != nullptr) {
nodeDeclarationEnsureOnOutdatedNode(ntree, node);
if (!node->runtime->declaration->matches(*node)) {
refresh_node(*ntree, *node, *node->runtime->declaration, do_id_user);
}
nodeSocketDeclarationsUpdate(node);
refresh_node(*ntree, *node, *node->runtime->declaration, do_id_user);
return;
}
/* Don't try to match socket lists when there are no templates.
@ -499,52 +519,6 @@ static void standard_node_socket_interface_init_socket(bNodeTree * /*ntree*/,
node_socket_copy_default_value(sock, interface_socket);
}
/* copies settings that are not changed for each socket instance */
static void standard_node_socket_interface_verify_socket(bNodeTree * /*ntree*/,
const bNodeSocket *interface_socket,
bNode * /*node*/,
bNodeSocket *sock,
const char * /*data_path*/)
{
/* sanity check */
if (sock->type != interface_socket->typeinfo->type) {
return;
}
/* make sure both exist */
if (!interface_socket->default_value) {
return;
}
node_socket_init_default_value(sock);
switch (interface_socket->typeinfo->type) {
case SOCK_FLOAT: {
bNodeSocketValueFloat *toval = (bNodeSocketValueFloat *)sock->default_value;
const bNodeSocketValueFloat *fromval = (const bNodeSocketValueFloat *)
interface_socket->default_value;
toval->min = fromval->min;
toval->max = fromval->max;
break;
}
case SOCK_INT: {
bNodeSocketValueInt *toval = (bNodeSocketValueInt *)sock->default_value;
const bNodeSocketValueInt *fromval = (const bNodeSocketValueInt *)
interface_socket->default_value;
toval->min = fromval->min;
toval->max = fromval->max;
break;
}
case SOCK_VECTOR: {
bNodeSocketValueVector *toval = (bNodeSocketValueVector *)sock->default_value;
const bNodeSocketValueVector *fromval = (const bNodeSocketValueVector *)
interface_socket->default_value;
toval->min = fromval->min;
toval->max = fromval->max;
break;
}
}
}
static void standard_node_socket_interface_from_socket(bNodeTree * /*ntree*/,
bNodeSocket *stemp,
const bNode * /*node*/,
@ -592,7 +566,6 @@ static bNodeSocketType *make_standard_socket_type(int type, int subtype)
stype->interface_init_socket = standard_node_socket_interface_init_socket;
stype->interface_from_socket = standard_node_socket_interface_from_socket;
stype->interface_verify_socket = standard_node_socket_interface_verify_socket;
stype->use_link_limits_of_type = true;
stype->input_link_limit = 1;

View File

@ -234,6 +234,14 @@ bool Vector::matches(const bNodeSocket &socket) const
if (socket.typeinfo->subtype != this->subtype) {
return false;
}
const bNodeSocketValueVector &value = *static_cast<const bNodeSocketValueVector *>(
socket.default_value);
if (value.min != this->soft_min_value) {
return false;
}
if (value.max != this->soft_max_value) {
return false;
}
return true;
}
@ -257,6 +265,8 @@ bNodeSocket &Vector::update_or_build(bNodeTree &ntree, bNode &node, bNodeSocket
this->set_common_flags(socket);
bNodeSocketValueVector &value = *(bNodeSocketValueVector *)socket.default_value;
value.subtype = this->subtype;
value.min = this->soft_min_value;
value.max = this->soft_max_value;
STRNCPY(socket.name, this->name.c_str());
return socket;
}
@ -301,6 +311,17 @@ bool Bool::can_connect(const bNodeSocket &socket) const
return basic_types_can_connect(*this, socket);
}
bNodeSocket &Bool::update_or_build(bNodeTree &ntree, bNode &node, bNodeSocket &socket) const
{
if (socket.type != SOCK_BOOLEAN) {
BLI_assert(socket.in_out == this->in_out);
return this->build(ntree, node);
}
this->set_common_flags(socket);
STRNCPY(socket.name, this->name.c_str());
return socket;
}
/** \} */
/* -------------------------------------------------------------------- */
@ -346,6 +367,17 @@ bool Color::can_connect(const bNodeSocket &socket) const
return basic_types_can_connect(*this, socket);
}
bNodeSocket &Color::update_or_build(bNodeTree &ntree, bNode &node, bNodeSocket &socket) const
{
if (socket.type != SOCK_RGBA) {
BLI_assert(socket.in_out == this->in_out);
return this->build(ntree, node);
}
this->set_common_flags(socket);
STRNCPY(socket.name, this->name.c_str());
return socket;
}
/** \} */
/* -------------------------------------------------------------------- */
@ -382,6 +414,17 @@ bool String::can_connect(const bNodeSocket &socket) const
return sockets_can_connect(*this, socket) && socket.type == SOCK_STRING;
}
bNodeSocket &String::update_or_build(bNodeTree &ntree, bNode &node, bNodeSocket &socket) const
{
if (socket.type != SOCK_STRING) {
BLI_assert(socket.in_out == this->in_out);
return this->build(ntree, node);
}
this->set_common_flags(socket);
STRNCPY(socket.name, this->name.c_str());
return socket;
}
/** \} */
/* -------------------------------------------------------------------- */
@ -542,4 +585,77 @@ bool Shader::can_connect(const bNodeSocket &socket) const
/** \} */
/* -------------------------------------------------------------------- */
/** \name #Extend
* \{ */
bNodeSocket &Extend::build(bNodeTree &ntree, bNode &node) const
{
bNodeSocket &socket = *nodeAddSocket(&ntree,
&node,
this->in_out,
"NodeSocketVirtual",
this->identifier.c_str(),
this->name.c_str());
return socket;
}
bool Extend::matches(const bNodeSocket &socket) const
{
if (socket.identifier != this->identifier) {
return false;
}
return true;
}
bool Extend::can_connect(const bNodeSocket & /*socket*/) const
{
return false;
}
bNodeSocket &Extend::update_or_build(bNodeTree & /*ntree*/,
bNode & /*node*/,
bNodeSocket &socket) const
{
return socket;
}
/** \} */
/* -------------------------------------------------------------------- */
/** \name #Custom
* \{ */
bNodeSocket &Custom::build(bNodeTree &ntree, bNode &node) const
{
bNodeSocket &socket = *nodeAddSocket(
&ntree, &node, this->in_out, idname_, this->identifier.c_str(), this->name.c_str());
return socket;
}
bool Custom::matches(const bNodeSocket &socket) const
{
if (!this->matches_common_data(socket)) {
return false;
}
if (socket.type != SOCK_CUSTOM) {
return false;
}
return true;
}
bool Custom::can_connect(const bNodeSocket &socket) const
{
return sockets_can_connect(*this, socket) && STREQ(socket.idname, idname_);
}
bNodeSocket &Custom::update_or_build(bNodeTree & /*ntree*/,
bNode & /*node*/,
bNodeSocket &socket) const
{
return socket;
}
/** \} */
} // namespace blender::nodes::decl

View File

@ -324,19 +324,19 @@ static bNodeSocket *node_find_linkable_socket(bNodeTree *ntree,
return nullptr;
}
void node_insert_link_default(bNodeTree *ntree, bNode *node, bNodeLink *link)
bool node_insert_link_default(bNodeTree *ntree, bNode *node, bNodeLink *link)
{
bNodeSocket *socket = link->tosock;
if (node != link->tonode) {
return;
return true;
}
/* If we're not at the link limit of the target socket, we can skip
* trying to move existing links to another socket. */
const int to_link_limit = nodeSocketLinkLimit(socket);
if (socket->runtime->total_inputs + 1 < to_link_limit) {
return;
return true;
}
LISTBASE_FOREACH_MUTABLE (bNodeLink *, to_link, &ntree->links) {
@ -345,16 +345,17 @@ void node_insert_link_default(bNodeTree *ntree, bNode *node, bNodeLink *link)
if (new_socket && new_socket != socket) {
/* Attempt to redirect the existing link to the new socket. */
to_link->tosock = new_socket;
return;
return true;
}
if (new_socket == nullptr) {
/* No possible replacement, remove the existing link. */
nodeRemLink(ntree, to_link);
return;
return true;
}
}
}
return true;
}
/** \} */

View File

@ -74,7 +74,7 @@ void node_combsep_color_label(const ListBase *sockets, NodeCombSepColorMode mode
* already linked (and if its not an Multi Input Socket), we try to find a replacement socket for
* the link that we try to overwrite and connect that previous link to the new socket.
*/
void node_insert_link_default(struct bNodeTree *ntree, struct bNode *node, struct bNodeLink *link);
bool node_insert_link_default(struct bNodeTree *ntree, struct bNode *node, struct bNodeLink *link);
float node_socket_get_float(struct bNodeTree *ntree, struct bNode *node, struct bNodeSocket *sock);
void node_socket_set_float(struct bNodeTree *ntree,

View File

@ -132,9 +132,8 @@ void search_link_ops_for_basic_node(GatherLinkSearchOpParams &params)
return;
}
if (node_type.declaration_is_dynamic) {
/* Dynamic declarations (whatever they end up being) aren't supported
* by this function, but still avoid a crash in release builds. */
if (node_type.declare_dynamic) {
/* Dynamic declarations aren't supported here, but avoid crashing in release builds. */
BLI_assert_unreachable();
return;
}

View File

@ -95,7 +95,7 @@ void register_node_type_sh_group()
node_type_size(&ntype, 140, 60, 400);
ntype.labelfunc = node_group_label;
ntype.group_update_func = node_group_update;
ntype.declare_dynamic = blender::nodes::node_group_declare_dynamic;
ntype.gpu_fn = gpu_group_execute;
nodeRegisterType(&ntype);

View File

@ -157,7 +157,7 @@ void register_node_type_tex_group(void)
node_type_size(&ntype, 140, 60, 400);
ntype.labelfunc = node_group_label;
ntype.group_update_func = node_group_update;
ntype.declare_dynamic = blender::nodes::node_group_declare_dynamic;
ntype.init_exec_fn = group_initexec;
ntype.free_exec_fn = group_freeexec;
ntype.exec_fn = group_execute;