Merge branch 'master' into asset-shelf

This commit is contained in:
Julian Eisel 2023-01-17 13:08:57 +01:00
commit 0e3f5c6673
64 changed files with 877 additions and 900 deletions

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;