Merge branch 'master' into asset-shelf
This commit is contained in:
commit
0e3f5c6673
|
@ -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.
|
|
@ -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()
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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")
|
||||
|
||||
|
|
|
@ -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. */
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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) \
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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"
|
||||
|
||||
|
|
|
@ -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"
|
|
@ -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"
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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()
|
||||
{
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
|
|
41
readme.rst
41
readme.rst
|
@ -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.
|
|
@ -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).
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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!
|
||||
*/
|
||||
|
|
|
@ -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 ---------- */
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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 */
|
||||
};
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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)) {
|
||||
|
|
|
@ -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]);
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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. */
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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))) {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
|
@ -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,
|
||||
|
|
|
@ -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(¶ms.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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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. */
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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. */
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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];
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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<
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
* \{ */
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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 ¶ms,
|
|||
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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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_) {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -132,9 +132,8 @@ void search_link_ops_for_basic_node(GatherLinkSearchOpParams ¶ms)
|
|||
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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue