Compare commits

..

3 Commits

Author SHA1 Message Date
1da326f237 Fix, add the ability to add a "processor" group
It is broken and doesn't do anything yet
2021-03-24 18:09:47 -04:00
4ea3d24930 Merge branch 'master' into temp-geometry-nodes-processor-prototype 2021-03-24 17:46:39 -04:00
2495c0c539 Add new node tree type for nodes inside attribute processor group 2021-03-23 17:34:41 -04:00
808 changed files with 5766 additions and 13486 deletions

View File

@@ -2,7 +2,7 @@
# Configuration of clang-format
# =============================
#
# Tested to work with versions: 8 to 11.
# Tested to work with versions: 6 to 8.
# This causes parameters on continuations to align to the opening brace.
#
@@ -255,6 +255,7 @@ ForEachMacros:
- SCULPT_VERTEX_DUPLICATES_AND_NEIGHBORS_ITER_BEGIN
- SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN
- SEQ_ALL_BEGIN
- SEQ_CURRENT_BEGIN
- SURFACE_QUAD_ITER_BEGIN
- foreach
- ED_screen_areas_iter
@@ -263,5 +264,8 @@ ForEachMacros:
- MAP_SLOT_PROBING_BEGIN
- VECTOR_SET_SLOT_PROBING_BEGIN
StatementMacros:
- PyObject_VAR_HEAD
# Use once we bump the minimum version to version 8.
# # Without this string literals that in-line 'STRINGIFY' behave strangely (a bug?).
# StatementMacros:
# - PyObject_VAR_HEAD
# - STRINGIFY

View File

@@ -43,6 +43,7 @@ Checks: >
# the windows compiler currently.
-modernize-raw-string-literal
WarningsAsErrors: '*'
CheckOptions:
- key: modernize-use-default-member-init.UseAssignment
value: 1

3
.gitignore vendored
View File

@@ -46,6 +46,3 @@ Desktop.ini
# smoke simulation noise tile (generated)
waveletNoiseTile.bin
# testing environment
/Testing

View File

@@ -236,7 +236,9 @@ option(WITH_SYSTEM_AUDASPACE "Build with external audaspace library installed on
mark_as_advanced(WITH_AUDASPACE)
mark_as_advanced(WITH_SYSTEM_AUDASPACE)
set_and_warn_dependency(WITH_AUDASPACE WITH_SYSTEM_AUDASPACE OFF)
if(NOT WITH_AUDASPACE)
set(WITH_SYSTEM_AUDASPACE OFF)
endif()
option(WITH_OPENMP "Enable OpenMP (has to be supported by the compiler)" ON)
if(UNIX AND NOT APPLE)
@@ -520,10 +522,10 @@ if(CMAKE_COMPILER_IS_GNUCC)
mark_as_advanced(WITH_LINKER_LLD)
endif()
option(WITH_COMPILER_ASAN "Build and link against address sanitizer (only for Debug & RelWithDebInfo targets)." OFF)
mark_as_advanced(WITH_COMPILER_ASAN)
if(CMAKE_COMPILER_IS_GNUCC OR CMAKE_C_COMPILER_ID MATCHES "Clang")
option(WITH_COMPILER_ASAN "Build and link against address sanitizer (only for Debug & RelWithDebInfo targets)." OFF)
mark_as_advanced(WITH_COMPILER_ASAN)
if(WITH_COMPILER_ASAN)
set(_asan_defaults "\
-fsanitize=address \
@@ -702,8 +704,10 @@ if(WITH_PYTHON_MODULE AND WITH_PYTHON_INSTALL)
message(FATAL_ERROR "WITH_PYTHON_MODULE requires WITH_PYTHON_INSTALL to be OFF")
endif()
set_and_warn_dependency(WITH_PYTHON WITH_CYCLES OFF)
set_and_warn_dependency(WITH_PYTHON WITH_DRACO OFF)
if(NOT WITH_PYTHON)
set(WITH_CYCLES OFF)
set(WITH_DRACO OFF)
endif()
if(WITH_DRACO AND NOT WITH_PYTHON_INSTALL)
message(STATUS "WITH_DRACO requires WITH_PYTHON_INSTALL to be ON, disabling WITH_DRACO for now")
@@ -775,7 +779,6 @@ if(WITH_INSTALL_PORTABLE)
endif()
if(WITH_GHOST_SDL OR WITH_HEADLESS)
message(STATUS "Disabling Ghost Wayland, X11, Input IME, and OpenXR")
set(WITH_GHOST_WAYLAND OFF)
set(WITH_GHOST_X11 OFF)
set(WITH_X11_XINPUT OFF)
@@ -806,7 +809,7 @@ endif()
if(NOT WITH_CUDA_DYNLOAD)
find_package(CUDA)
if(NOT CUDA_FOUND)
message(STATUS "CUDA toolkit not found, using dynamic runtime loading of libraries (WITH_CUDA_DYNLOAD) instead")
message("CUDA toolkit not found, using dynamic runtime loading of libraries instead")
set(WITH_CUDA_DYNLOAD ON)
endif()
endif()
@@ -1232,7 +1235,6 @@ if(WITH_OPENMP)
string(APPEND CMAKE_C_FLAGS " ${OpenMP_C_FLAGS}")
string(APPEND CMAKE_CXX_FLAGS " ${OpenMP_CXX_FLAGS}")
string(APPEND CMAKE_EXE_LINKER_FLAGS " ${OpenMP_LINKER_FLAGS}")
string(APPEND CMAKE_MODULE_LINKER_FLAGS " ${OpenMP_LINKER_FLAGS}")
else()
# Typically avoid adding flags as defines but we can't
# pass OpenMP flags to the linker for static builds, meaning
@@ -1243,7 +1245,6 @@ if(WITH_OPENMP)
find_library_static(OpenMP_LIBRARIES gomp ${CMAKE_CXX_IMPLICIT_LINK_DIRECTORIES})
endif()
else()
message(STATUS "OpenMP not found, disabling WITH_OPENMP")
set(WITH_OPENMP OFF)
endif()
@@ -1319,7 +1320,6 @@ list(APPEND GL_DEFINITIONS -DGLEW_NO_GLU)
if(WITH_BULLET AND WITH_SYSTEM_BULLET)
find_package(Bullet)
if(NOT BULLET_FOUND)
message(STATUS "Bullet not found, disabling WITH_BULLET")
set(WITH_BULLET OFF)
endif()
else()

View File

@@ -129,10 +129,7 @@ Utilities
Create a compressed archive of the source code.
* update:
Updates git and all submodules and svn.
* update_code:
Updates git and all submodules but not svn.
updates git and all submodules
* format:
Format source code using clang (uses PATHS if passed in). For example::
@@ -525,9 +522,6 @@ icons_geom: .FORCE
update: .FORCE
$(PYTHON) ./build_files/utils/make_update.py
update_code: .FORCE
$(PYTHON) ./build_files/utils/make_update.py --no-libraries
format: .FORCE
PATH="../lib/${OS_NCASE}_${CPU}/llvm/bin/:../lib/${OS_NCASE}_centos7_${CPU}/llvm/bin/:../lib/${OS_NCASE}/llvm/bin/:$(PATH)" \
$(PYTHON) source/tools/utils_maintenance/clang_format_paths.py $(PATHS)

View File

@@ -21,8 +21,7 @@ if(WIN32)
endif()
option(WITH_WEBP "Enable building of oiio with webp support" OFF)
option(WITH_BOOST_PYTHON "Enable building of boost with python support" OFF)
cmake_host_system_information(RESULT NUM_CORES QUERY NUMBER_OF_LOGICAL_CORES)
set(MAKE_THREADS ${NUM_CORES} CACHE STRING "Number of threads to run make with")
set(MAKE_THREADS 1 CACHE STRING "Number of threads to run make with")
if(NOT BUILD_MODE)
set(BUILD_MODE "Release")

View File

@@ -56,7 +56,6 @@ list(APPEND ZLIB_LIBRARIES ${BZIP2_LIBRARIES})
if(WITH_OPENAL)
find_package(OpenAL)
if(NOT OPENAL_FOUND)
message(WARNING "OpenAL not found, disabling WITH_OPENAL")
set(WITH_OPENAL OFF)
endif()
endif()
@@ -66,7 +65,6 @@ if(WITH_JACK)
NAMES jackmp
)
if(NOT JACK_FRAMEWORK)
message(STATUS "JACK not found, disabling WITH_JACK")
set(WITH_JACK OFF)
else()
set(JACK_INCLUDE_DIRS ${JACK_FRAMEWORK}/headers)
@@ -104,7 +102,6 @@ endif()
if(WITH_USD)
find_package(USD)
if(NOT USD_FOUND)
message(STATUS "USD not found, disabling WITH_USD")
set(WITH_USD OFF)
endif()
endif()
@@ -149,7 +146,7 @@ if(WITH_PYTHON)
set(PYTHON_INCLUDE_DIR "${_py_framework}/include/python${PYTHON_VERSION}")
set(PYTHON_EXECUTABLE "${_py_framework}/bin/python${PYTHON_VERSION}")
set(PYTHON_LIBPATH "${_py_framework}/lib/python${PYTHON_VERSION}")
set(PYTHON_LIBPATH "${_py_framework}/lib/python${PYTHON_VERSION}/config-${PYTHON_VERSION}")
# set(PYTHON_LIBRARY python${PYTHON_VERSION})
# set(PYTHON_LINKFLAGS "-u _PyMac_Error -framework Python") # won't build with this enabled
@@ -311,7 +308,7 @@ if(WITH_OPENCOLORIO)
if(NOT OPENCOLORIO_FOUND)
set(WITH_OPENCOLORIO OFF)
message(STATUS "OpenColorIO not found, disabling WITH_OPENCOLORIO")
message(STATUS "OpenColorIO not found")
endif()
endif()
@@ -360,7 +357,7 @@ if(WITH_CYCLES_OSL)
if(OSL_INCLUDE_DIR AND OSL_LIBRARIES AND OSL_COMPILER AND OSL_SHADER_DIR)
set(OSL_FOUND TRUE)
else()
message(WARNING "OSL not found, disabling WITH_CYCLES_OSL")
message(STATUS "OSL not found")
set(WITH_CYCLES_OSL OFF)
endif()
endif()
@@ -388,7 +385,7 @@ if(WITH_OPENIMAGEDENOISE)
if(NOT OPENIMAGEDENOISE_FOUND)
set(WITH_OPENIMAGEDENOISE OFF)
message(STATUS "OpenImageDenoise not found, disabling WITH_OPENIMAGEDENOISE")
message(STATUS "OpenImageDenoise not found")
endif()
endif()
@@ -416,7 +413,7 @@ if(WITH_OPENMP)
set(OpenMP_LINKER_FLAGS "-L'${LIBDIR}/openmp/lib' -lomp")
# Copy libomp.dylib to allow executables like datatoc and tests to work.
# `@executable_path/../Resources/lib/` `LC_ID_DYLIB` is added by the deps builder.
# `@executable_path/../Resources/lib/` `LC_ID_DYLIB`is added by the deps builder.
# For single config generator datatoc, tests etc.
execute_process(
COMMAND mkdir -p ${CMAKE_BINARY_DIR}/Resources/lib

View File

@@ -149,6 +149,11 @@ add_definitions(-D_WIN32_WINNT=0x601)
include(build_files/cmake/platform/platform_win32_bundle_crt.cmake)
remove_cc_flag("/MDd" "/MD" "/Zi")
if(WITH_WINDOWS_PDB)
set(PDB_INFO_OVERRIDE_FLAGS "/Z7")
set(PDB_INFO_OVERRIDE_LINKER_FLAGS "/DEBUG /OPT:REF /OPT:ICF /INCREMENTAL:NO")
endif()
if(MSVC_CLANG) # Clangs version of cl doesn't support all flags
string(APPEND CMAKE_CXX_FLAGS " ${CXX_WARN_FLAGS} /nologo /J /Gd /EHsc -Wno-unused-command-line-argument -Wno-microsoft-enum-forward-reference ")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /nologo /J /Gd -Wno-unused-command-line-argument -Wno-microsoft-enum-forward-reference")
@@ -157,21 +162,6 @@ else()
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /nologo /J /Gd /MP /bigobj")
endif()
# X64 ASAN is available and usable on MSVC 16.9 preview 4 and up)
if(WITH_COMPILER_ASAN AND MSVC AND NOT MSVC_CLANG)
if(CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 19.28.29828)
#set a flag so we don't have to do this comparison all the time
SET(MSVC_ASAN On)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /fsanitize=address")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /fsanitize=address")
string(APPEND CMAKE_EXE_LINKER_FLAGS_DEBUG " /INCREMENTAL:NO")
string(APPEND CMAKE_SHARED_LINKER_FLAGS_DEBUG " /INCREMENTAL:NO")
else()
message("-- ASAN not supported on MSVC ${CMAKE_CXX_COMPILER_VERSION}")
endif()
endif()
# C++ standards conformace (/permissive-) is available on msvc 15.5 (1912) and up
if(MSVC_VERSION GREATER 1911 AND NOT MSVC_CLANG)
string(APPEND CMAKE_CXX_FLAGS " /permissive-")
@@ -184,41 +174,14 @@ if(WITH_WINDOWS_SCCACHE AND CMAKE_VS_MSBUILD_COMMAND)
set(WITH_WINDOWS_SCCACHE Off)
endif()
# Debug Symbol format
# sccache # MSVC_ASAN # format # why
# On # On # Z7 # sccache will only play nice with Z7
# On # Off # Z7 # sccache will only play nice with Z7
# Off # On # Zi # Asan will not play nice with Edit and Continue
# Off # Off # ZI # Neither asan nor sscache is enabled Edit and Continue is available
# Release Symbol format
# sccache # MSVC_ASAN # format # why
# On # On # Z7 # sccache will only play nice with Z7
# On # Off # Z7 # sccache will only play nice with Z7
# Off # On # Zi # Asan will not play nice with Edit and Continue
# Off # Off # Zi # Edit and Continue disables some optimizations
if(WITH_WINDOWS_SCCACHE)
set(CMAKE_C_COMPILER_LAUNCHER sccache)
set(CMAKE_CXX_COMPILER_LAUNCHER sccache)
set(SYMBOL_FORMAT /Z7)
set(SYMBOL_FORMAT_RELEASE /Z7)
else()
unset(CMAKE_C_COMPILER_LAUNCHER)
unset(CMAKE_CXX_COMPILER_LAUNCHER)
if(MSVC_ASAN)
set(SYMBOL_FORMAT /Z7)
set(SYMBOL_FORMAT_RELEASE /Z7)
else()
set(SYMBOL_FORMAT /ZI)
set(SYMBOL_FORMAT_RELEASE /Zi)
endif()
endif()
if(WITH_WINDOWS_PDB)
set(PDB_INFO_OVERRIDE_FLAGS "${SYMBOL_FORMAT_RELEASE}")
set(PDB_INFO_OVERRIDE_LINKER_FLAGS "/DEBUG /OPT:REF /OPT:ICF /INCREMENTAL:NO")
set(SYMBOL_FORMAT /ZI)
endif()
string(APPEND CMAKE_CXX_FLAGS_DEBUG " /MDd ${SYMBOL_FORMAT}")
@@ -227,11 +190,9 @@ string(APPEND CMAKE_CXX_FLAGS_RELEASE " /MD ${PDB_INFO_OVERRIDE_FLAGS}")
string(APPEND CMAKE_C_FLAGS_RELEASE " /MD ${PDB_INFO_OVERRIDE_FLAGS}")
string(APPEND CMAKE_CXX_FLAGS_MINSIZEREL " /MD ${PDB_INFO_OVERRIDE_FLAGS}")
string(APPEND CMAKE_C_FLAGS_MINSIZEREL " /MD ${PDB_INFO_OVERRIDE_FLAGS}")
string(APPEND CMAKE_CXX_FLAGS_RELWITHDEBINFO " /MD ${SYMBOL_FORMAT_RELEASE}")
string(APPEND CMAKE_C_FLAGS_RELWITHDEBINFO " /MD ${SYMBOL_FORMAT_RELEASE}")
string(APPEND CMAKE_CXX_FLAGS_RELWITHDEBINFO " /MD ${SYMBOL_FORMAT}")
string(APPEND CMAKE_C_FLAGS_RELWITHDEBINFO " /MD ${SYMBOL_FORMAT}")
unset(SYMBOL_FORMAT)
unset(SYMBOL_FORMAT_RELEASE)
# JMC is available on msvc 15.8 (1915) and up
if(MSVC_VERSION GREATER 1914 AND NOT MSVC_CLANG)
string(APPEND CMAKE_CXX_FLAGS_DEBUG " /JMC")

View File

@@ -9,10 +9,14 @@ if "%BUILD_WITH_SCCACHE%"=="1" (
if "%WITH_CLANG%"=="1" (
set CLANG_CMAKE_ARGS=-T"llvm"
)
if "%WITH_ASAN%"=="1" (
if "%WITH_ASAN%"=="1" (
set ASAN_CMAKE_ARGS=-DWITH_COMPILER_ASAN=On
)
) else (
if "%WITH_ASAN%"=="1" (
echo ASAN is only supported with clang.
exit /b 1
)
)
if "%WITH_PYDEBUG%"=="1" (

View File

@@ -46,10 +46,16 @@ set LLVM_DIR=
set CFLAGS=-m64 -fmsc-version=1914
set CXXFLAGS=-m64 -fmsc-version=1914
)
if "%WITH_ASAN%"=="1" (
set BUILD_CMAKE_ARGS=%BUILD_CMAKE_ARGS% -DWITH_COMPILER_ASAN=On
)
)
if "%WITH_ASAN%"=="1" (
set BUILD_CMAKE_ARGS=%BUILD_CMAKE_ARGS% -DWITH_COMPILER_ASAN=On
if "%WITH_CLANG%" == "" (
echo ASAN is only supported with clang.
exit /b 1
)
)
if NOT "%verbose%" == "" (

View File

@@ -553,7 +553,7 @@ def example_extract_docstring(filepath):
line_no += 1
else:
file.close()
return "", 0, False
return "", 0
for line in file:
line_no += 1
@@ -563,17 +563,15 @@ def example_extract_docstring(filepath):
text.append(line.rstrip())
line_no += 1
line_no_has_content = False
# Skip over blank lines so the Python code doesn't have blank lines at the top.
for line in file:
if line.strip():
line_no_has_content = True
break
line_no += 1
file.close()
return "\n".join(text), line_no, line_no_has_content
return "\n".join(text), line_no
def title_string(text, heading_char, double=False):
@@ -592,18 +590,16 @@ def write_example_ref(ident, fw, example_id, ext="py"):
filepath = os.path.join("..", "examples", "%s.%s" % (example_id, ext))
filepath_full = os.path.join(os.path.dirname(fw.__self__.name), filepath)
text, line_no, line_no_has_content = example_extract_docstring(filepath_full)
text, line_no = example_extract_docstring(filepath_full)
for line in text.split("\n"):
fw("%s\n" % (ident + line).rstrip())
fw("\n")
# Some files only contain a doc-string.
if line_no_has_content:
fw("%s.. literalinclude:: %s\n" % (ident, filepath))
if line_no > 0:
fw("%s :lines: %d-\n" % (ident, line_no))
fw("\n")
fw("%s.. literalinclude:: %s\n" % (ident, filepath))
if line_no > 0:
fw("%s :lines: %d-\n" % (ident, line_no))
fw("\n")
EXAMPLE_SET_USED.add(example_id)
else:
if bpy.app.debug:
@@ -1412,8 +1408,7 @@ def pyrna2sphinx(basepath):
else:
fw(" .. attribute:: %s\n\n" % prop.identifier)
if prop.description:
write_indented_lines(" ", fw, prop.description, False)
fw("\n")
fw(" %s\n\n" % prop.description)
# special exception, can't use generic code here for enums
if prop.type == "enum":

View File

@@ -109,7 +109,3 @@ endif()
if(WITH_MOD_FLUID)
add_subdirectory(mantaflow)
endif()
if (WITH_COMPOSITOR)
add_subdirectory(smaa_areatex)
endif()

View File

@@ -42,7 +42,6 @@ set(SRC
src/devices/NULLDevice.cpp
src/devices/ReadDevice.cpp
src/devices/SoftwareDevice.cpp
src/devices/ThreadedDevice.cpp
src/Exception.cpp
src/file/File.cpp
src/file/FileManager.cpp
@@ -149,7 +148,6 @@ set(PUBLIC_HDR
include/devices/NULLDevice.h
include/devices/ReadDevice.h
include/devices/SoftwareDevice.h
include/devices/ThreadedDevice.h
include/Exception.h
include/file/File.h
include/file/FileManager.h

View File

@@ -255,7 +255,6 @@ protected:
/**
* This function tells the device, to start or pause playback.
* \param playing True if device should playback.
* \note This method is only called when the device is locked.
*/
virtual void playing(bool playing)=0;

View File

@@ -1,95 +0,0 @@
/*******************************************************************************
* Copyright 2009-2016 Jörg Müller
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
******************************************************************************/
#pragma once
/**
* @file ThreadedDevice.h
* @ingroup plugin
* The ThreadedDevice class.
*/
#include "devices/SoftwareDevice.h"
#include <thread>
AUD_NAMESPACE_BEGIN
/**
* This device extends the SoftwareDevice with code for running mixing in a separate thread.
*/
class AUD_PLUGIN_API ThreadedDevice : public SoftwareDevice
{
private:
/**
* Whether there is currently playback.
*/
bool m_playing;
/**
* Whether the current playback should stop.
*/
bool m_stop;
/**
* The streaming thread.
*/
std::thread m_thread;
/**
* Starts the streaming thread.
*/
AUD_LOCAL void start();
/**
* Streaming thread main function.
*/
AUD_LOCAL virtual void runMixingThread()=0;
// delete copy constructor and operator=
ThreadedDevice(const ThreadedDevice&) = delete;
ThreadedDevice& operator=(const ThreadedDevice&) = delete;
protected:
virtual void playing(bool playing);
/**
* Empty default constructor. To setup the device call the function create()
* and to uninitialize call destroy().
*/
ThreadedDevice();
/**
* Indicates that the mixing thread should be stopped.
* \return Whether the mixing thread should be stopping.
* \warning For thread safety, the device needs to be locked, when this method is called.
*/
inline bool shouldStop() { return m_stop; }
/**
* This method needs to be called when the mixing thread is stopping.
* \warning For thread safety, the device needs to be locked, when this method is called.
*/
inline void doStop() { m_stop = m_playing = false; }
/**
* Stops all playback and notifies the mixing thread to stop.
* \warning The device has to be unlocked to not run into a deadlock.
*/
void stopMixingThread();
};
AUD_NAMESPACE_END

View File

@@ -27,9 +27,9 @@ void PulseAudioDevice::PulseAudio_state_callback(pa_context *context, void *data
{
PulseAudioDevice* device = (PulseAudioDevice*)data;
std::lock_guard<ILockable> lock(*device);
device->m_state = AUD_pa_context_get_state(context);
AUD_pa_threaded_mainloop_signal(device->m_mainloop, 0);
}
void PulseAudioDevice::PulseAudio_request(pa_stream *stream, size_t num_bytes, void *data)
@@ -68,40 +68,29 @@ void PulseAudioDevice::PulseAudio_underflow(pa_stream *stream, void *data)
}
}
void PulseAudioDevice::runMixingThread()
void PulseAudioDevice::playing(bool playing)
{
for(;;)
{
{
std::lock_guard<ILockable> lock(*this);
m_playback = playing;
if(shouldStop())
{
AUD_pa_stream_cork(m_stream, 1, nullptr, nullptr);
doStop();
return;
}
}
if(AUD_pa_stream_is_corked(m_stream))
AUD_pa_stream_cork(m_stream, 0, nullptr, nullptr);
AUD_pa_mainloop_iterate(m_mainloop, true, nullptr);
}
AUD_pa_stream_cork(m_stream, playing ? 0 : 1, nullptr, nullptr);
}
PulseAudioDevice::PulseAudioDevice(std::string name, DeviceSpecs specs, int buffersize) :
m_playback(false),
m_state(PA_CONTEXT_UNCONNECTED),
m_buffersize(buffersize),
m_underflows(0)
{
m_mainloop = AUD_pa_mainloop_new();
m_mainloop = AUD_pa_threaded_mainloop_new();
m_context = AUD_pa_context_new(AUD_pa_mainloop_get_api(m_mainloop), name.c_str());
AUD_pa_threaded_mainloop_lock(m_mainloop);
m_context = AUD_pa_context_new(AUD_pa_threaded_mainloop_get_api(m_mainloop), name.c_str());
if(!m_context)
{
AUD_pa_mainloop_free(m_mainloop);
AUD_pa_threaded_mainloop_unlock(m_mainloop);
AUD_pa_threaded_mainloop_free(m_mainloop);
AUD_THROW(DeviceException, "Could not connect to PulseAudio.");
}
@@ -110,21 +99,26 @@ PulseAudioDevice::PulseAudioDevice(std::string name, DeviceSpecs specs, int buff
AUD_pa_context_connect(m_context, nullptr, PA_CONTEXT_NOFLAGS, nullptr);
AUD_pa_threaded_mainloop_start(m_mainloop);
while(m_state != PA_CONTEXT_READY)
{
switch(m_state)
{
case PA_CONTEXT_FAILED:
case PA_CONTEXT_TERMINATED:
AUD_pa_threaded_mainloop_unlock(m_mainloop);
AUD_pa_threaded_mainloop_stop(m_mainloop);
AUD_pa_context_disconnect(m_context);
AUD_pa_context_unref(m_context);
AUD_pa_mainloop_free(m_mainloop);
AUD_pa_threaded_mainloop_free(m_mainloop);
AUD_THROW(DeviceException, "Could not connect to PulseAudio.");
break;
default:
AUD_pa_mainloop_iterate(m_mainloop, true, nullptr);
AUD_pa_threaded_mainloop_wait(m_mainloop);
break;
}
}
@@ -172,10 +166,13 @@ PulseAudioDevice::PulseAudioDevice(std::string name, DeviceSpecs specs, int buff
if(!m_stream)
{
AUD_pa_threaded_mainloop_unlock(m_mainloop);
AUD_pa_threaded_mainloop_stop(m_mainloop);
AUD_pa_context_disconnect(m_context);
AUD_pa_context_unref(m_context);
AUD_pa_mainloop_free(m_mainloop);
AUD_pa_threaded_mainloop_free(m_mainloop);
AUD_THROW(DeviceException, "Could not create PulseAudio stream.");
}
@@ -191,27 +188,32 @@ PulseAudioDevice::PulseAudioDevice(std::string name, DeviceSpecs specs, int buff
buffer_attr.prebuf = -1U;
buffer_attr.tlength = buffersize;
if(AUD_pa_stream_connect_playback(m_stream, nullptr, &buffer_attr, static_cast<pa_stream_flags_t>(PA_STREAM_START_CORKED | PA_STREAM_INTERPOLATE_TIMING | PA_STREAM_ADJUST_LATENCY | PA_STREAM_AUTO_TIMING_UPDATE), nullptr, nullptr) < 0)
if(AUD_pa_stream_connect_playback(m_stream, nullptr, &buffer_attr, static_cast<pa_stream_flags_t>(PA_STREAM_INTERPOLATE_TIMING | PA_STREAM_ADJUST_LATENCY | PA_STREAM_AUTO_TIMING_UPDATE), nullptr, nullptr) < 0)
{
AUD_pa_threaded_mainloop_unlock(m_mainloop);
AUD_pa_threaded_mainloop_stop(m_mainloop);
AUD_pa_context_disconnect(m_context);
AUD_pa_context_unref(m_context);
AUD_pa_mainloop_free(m_mainloop);
AUD_pa_threaded_mainloop_free(m_mainloop);
AUD_THROW(DeviceException, "Could not connect PulseAudio stream.");
}
AUD_pa_threaded_mainloop_unlock(m_mainloop);
create();
}
PulseAudioDevice::~PulseAudioDevice()
{
stopMixingThread();
AUD_pa_threaded_mainloop_stop(m_mainloop);
AUD_pa_context_disconnect(m_context);
AUD_pa_context_unref(m_context);
AUD_pa_mainloop_free(m_mainloop);
AUD_pa_threaded_mainloop_free(m_mainloop);
destroy();
}

View File

@@ -26,7 +26,7 @@
* The PulseAudioDevice class.
*/
#include "devices/ThreadedDevice.h"
#include "devices/SoftwareDevice.h"
#include <pulse/pulseaudio.h>
@@ -35,10 +35,15 @@ AUD_NAMESPACE_BEGIN
/**
* This device plays back through PulseAudio, the simple direct media layer.
*/
class AUD_PLUGIN_API PulseAudioDevice : public ThreadedDevice
class AUD_PLUGIN_API PulseAudioDevice : public SoftwareDevice
{
private:
pa_mainloop* m_mainloop;
/**
* Whether there is currently playback.
*/
volatile bool m_playback;
pa_threaded_mainloop* m_mainloop;
pa_context* m_context;
pa_stream* m_stream;
pa_context_state_t m_state;
@@ -69,15 +74,13 @@ private:
*/
AUD_LOCAL static void PulseAudio_underflow(pa_stream* stream, void* data);
/**
* Streaming thread main function.
*/
AUD_LOCAL void runMixingThread();
// delete copy constructor and operator=
PulseAudioDevice(const PulseAudioDevice&) = delete;
PulseAudioDevice& operator=(const PulseAudioDevice&) = delete;
protected:
virtual void playing(bool playing);
public:
/**
* Opens the PulseAudio audio device for playback.

View File

@@ -24,14 +24,18 @@ PULSEAUDIO_SYMBOL(pa_context_unref);
PULSEAUDIO_SYMBOL(pa_stream_begin_write);
PULSEAUDIO_SYMBOL(pa_stream_connect_playback);
PULSEAUDIO_SYMBOL(pa_stream_cork);
PULSEAUDIO_SYMBOL(pa_stream_is_corked);
PULSEAUDIO_SYMBOL(pa_stream_new);
PULSEAUDIO_SYMBOL(pa_stream_set_buffer_attr);
PULSEAUDIO_SYMBOL(pa_stream_set_underflow_callback);
PULSEAUDIO_SYMBOL(pa_stream_set_write_callback);
PULSEAUDIO_SYMBOL(pa_stream_write);
PULSEAUDIO_SYMBOL(pa_mainloop_free);
PULSEAUDIO_SYMBOL(pa_mainloop_get_api);
PULSEAUDIO_SYMBOL(pa_mainloop_new);
PULSEAUDIO_SYMBOL(pa_mainloop_iterate);
PULSEAUDIO_SYMBOL(pa_threaded_mainloop_free);
PULSEAUDIO_SYMBOL(pa_threaded_mainloop_get_api);
PULSEAUDIO_SYMBOL(pa_threaded_mainloop_lock);
PULSEAUDIO_SYMBOL(pa_threaded_mainloop_new);
PULSEAUDIO_SYMBOL(pa_threaded_mainloop_signal);
PULSEAUDIO_SYMBOL(pa_threaded_mainloop_start);
PULSEAUDIO_SYMBOL(pa_threaded_mainloop_stop);
PULSEAUDIO_SYMBOL(pa_threaded_mainloop_unlock);
PULSEAUDIO_SYMBOL(pa_threaded_mainloop_wait);

View File

@@ -31,83 +31,159 @@ template <class T> void SafeRelease(T **ppT)
}
}
void WASAPIDevice::runMixingThread()
void WASAPIDevice::start()
{
lock();
// thread is still running, we can abort stopping it
if(m_stop)
m_stop = false;
// thread is not running, let's start it
else if(!m_playing)
{
if(m_thread.joinable())
m_thread.join();
m_playing = true;
m_thread = std::thread(&WASAPIDevice::updateStream, this);
}
unlock();
}
void WASAPIDevice::updateStream()
{
UINT32 buffer_size;
UINT32 padding;
UINT32 length;
data_t* buffer;
IAudioRenderClient* render_client = nullptr;
lock();
if(FAILED(m_audio_client->GetBufferSize(&buffer_size)))
{
std::lock_guard<ILockable> lock(*this);
const IID IID_IAudioRenderClient = __uuidof(IAudioRenderClient);
if(FAILED(m_audio_client->GetBufferSize(&buffer_size)))
goto init_error;
if(FAILED(m_audio_client->GetService(IID_IAudioRenderClient, reinterpret_cast<void**>(&render_client))))
goto init_error;
if(FAILED(m_audio_client->GetCurrentPadding(&padding)))
goto init_error;
length = buffer_size - padding;
if(FAILED(render_client->GetBuffer(length, &buffer)))
goto init_error;
mix((data_t*)buffer, length);
if(FAILED(render_client->ReleaseBuffer(length, 0)))
{
init_error:
SafeRelease(&render_client);
doStop();
return;
}
m_playing = false;
m_stop = false;
unlock();
return;
}
IAudioRenderClient* render_client = nullptr;
const IID IID_IAudioRenderClient = __uuidof(IAudioRenderClient);
if(FAILED(m_audio_client->GetService(IID_IAudioRenderClient, reinterpret_cast<void**>(&render_client))))
{
m_playing = false;
m_stop = false;
unlock();
return;
}
UINT32 padding;
if(FAILED(m_audio_client->GetCurrentPadding(&padding)))
{
SafeRelease(&render_client);
m_playing = false;
m_stop = false;
unlock();
return;
}
UINT32 length = buffer_size - padding;
if(FAILED(render_client->GetBuffer(length, &buffer)))
{
SafeRelease(&render_client);
m_playing = false;
m_stop = false;
unlock();
return;
}
mix((data_t*)buffer, length);
if(FAILED(render_client->ReleaseBuffer(length, 0)))
{
SafeRelease(&render_client);
m_playing = false;
m_stop = false;
unlock();
return;
}
unlock();
m_audio_client->Start();
auto sleepDuration = std::chrono::milliseconds(buffer_size * 1000 / int(m_specs.rate) / 2);
for(;;)
{
lock();
if(FAILED(m_audio_client->GetCurrentPadding(&padding)))
{
std::lock_guard<ILockable> lock(*this);
if(FAILED(m_audio_client->GetCurrentPadding(&padding)))
goto stop_thread;
length = buffer_size - padding;
if(FAILED(render_client->GetBuffer(length, &buffer)))
goto stop_thread;
mix((data_t*)buffer, length);
if(FAILED(render_client->ReleaseBuffer(length, 0)))
goto stop_thread;
// stop thread
if(shouldStop())
{
stop_thread:
m_audio_client->Stop();
SafeRelease(&render_client);
doStop();
return;
}
m_audio_client->Stop();
SafeRelease(&render_client);
m_playing = false;
m_stop = false;
unlock();
return;
}
length = buffer_size - padding;
if(FAILED(render_client->GetBuffer(length, &buffer)))
{
m_audio_client->Stop();
SafeRelease(&render_client);
m_playing = false;
m_stop = false;
unlock();
return;
}
mix((data_t*)buffer, length);
if(FAILED(render_client->ReleaseBuffer(length, 0)))
{
m_audio_client->Stop();
SafeRelease(&render_client);
m_playing = false;
m_stop = false;
unlock();
return;
}
// stop thread
if(m_stop)
{
m_audio_client->Stop();
SafeRelease(&render_client);
m_playing = false;
m_stop = false;
unlock();
return;
}
unlock();
std::this_thread::sleep_for(sleepDuration);
}
}
void WASAPIDevice::playing(bool playing)
{
if((!m_playing || m_stop) && playing)
start();
else
m_stop = true;
}
WASAPIDevice::WASAPIDevice(DeviceSpecs specs, int buffersize) :
m_playing(false),
m_stop(false),
m_imm_device_enumerator(nullptr),
m_imm_device(nullptr),
m_audio_client(nullptr),
@@ -285,7 +361,14 @@ WASAPIDevice::WASAPIDevice(DeviceSpecs specs, int buffersize) :
WASAPIDevice::~WASAPIDevice()
{
stopMixingThread();
lock();
stopAll();
unlock();
if(m_thread.joinable())
m_thread.join();
SafeRelease(&m_audio_client);
SafeRelease(&m_imm_device);

View File

@@ -26,7 +26,7 @@
* The WASAPIDevice class.
*/
#include "devices/ThreadedDevice.h"
#include "devices/SoftwareDevice.h"
#include <thread>
@@ -40,23 +40,46 @@ AUD_NAMESPACE_BEGIN
/**
* This device plays back through WASAPI, the Windows audio API.
*/
class AUD_PLUGIN_API WASAPIDevice : public ThreadedDevice
class AUD_PLUGIN_API WASAPIDevice : public SoftwareDevice
{
private:
/**
* Whether there is currently playback.
*/
bool m_playing;
/**
* Whether the current playback should stop.
*/
bool m_stop;
IMMDeviceEnumerator* m_imm_device_enumerator;
IMMDevice* m_imm_device;
IAudioClient* m_audio_client;
WAVEFORMATEXTENSIBLE m_wave_format_extensible;
/**
* The streaming thread.
*/
std::thread m_thread;
/**
* Starts the streaming thread.
*/
AUD_LOCAL void start();
/**
* Streaming thread main function.
*/
AUD_LOCAL void runMixingThread();
AUD_LOCAL void updateStream();
// delete copy constructor and operator=
WASAPIDevice(const WASAPIDevice&) = delete;
WASAPIDevice& operator=(const WASAPIDevice&) = delete;
protected:
virtual void playing(bool playing);
public:
/**
* Opens the WASAPI audio device for playback.

View File

@@ -737,7 +737,7 @@ void SoftwareDevice::mix(data_t* buffer, int length)
{
m_buffer.assureSize(length * AUD_SAMPLE_SIZE(m_specs));
std::lock_guard<ILockable> lock(*this);
std::lock_guard<std::recursive_mutex> lock(m_mutex);
{
std::shared_ptr<SoftwareDevice::SoftwareHandle> sound;
@@ -880,7 +880,7 @@ std::shared_ptr<IHandle> SoftwareDevice::play(std::shared_ptr<IReader> reader, b
// play sound
std::shared_ptr<SoftwareDevice::SoftwareHandle> sound = std::shared_ptr<SoftwareDevice::SoftwareHandle>(new SoftwareDevice::SoftwareHandle(this, reader, pitch, resampler, mapper, keep));
std::lock_guard<ILockable> lock(*this);
std::lock_guard<std::recursive_mutex> lock(m_mutex);
m_playingSounds.push_back(sound);
@@ -897,7 +897,7 @@ std::shared_ptr<IHandle> SoftwareDevice::play(std::shared_ptr<ISound> sound, boo
void SoftwareDevice::stopAll()
{
std::lock_guard<ILockable> lock(*this);
std::lock_guard<std::recursive_mutex> lock(m_mutex);
while(!m_playingSounds.empty())
m_playingSounds.front()->stop();

View File

@@ -1,65 +0,0 @@
/*******************************************************************************
* Copyright 2009-2016 Jörg Müller
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
******************************************************************************/
#include "devices/ThreadedDevice.h"
#include <mutex>
AUD_NAMESPACE_BEGIN
void ThreadedDevice::start()
{
std::lock_guard<ILockable> lock(*this);
// thread is still running, we can abort stopping it
if(m_stop)
m_stop = false;
// thread is not running, let's start it
else if(!m_playing)
{
if(m_thread.joinable())
m_thread.join();
m_playing = true;
m_thread = std::thread(&ThreadedDevice::runMixingThread, this);
}
}
void ThreadedDevice::playing(bool playing)
{
if((!m_playing || m_stop) && playing)
start();
else
m_stop = true;
}
ThreadedDevice::ThreadedDevice() :
m_playing(false),
m_stop(false)
{
}
void aud::ThreadedDevice::stopMixingThread()
{
stopAll();
if(m_thread.joinable())
m_thread.join();
}
AUD_NAMESPACE_END

View File

@@ -1,26 +0,0 @@
# ***** BEGIN GPL LICENSE BLOCK *****
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software Foundation,
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
# The Original Code is Copyright (C) 2017, Blender Foundation
# All rights reserved.
#
# The Original Code is: all of this file.
#
# Contributor(s): IRIE Shinsuke
#
# ***** END GPL LICENSE BLOCK *****
add_executable(smaa_areatex smaa_areatex.cpp)

View File

@@ -1,5 +0,0 @@
Project: smaa-cpp
URL: https://github.com/iRi-E/smaa-cpp
License: MIT
Upstream version: 0.4.0
Local modifications:

File diff suppressed because it is too large Load Diff

View File

@@ -1409,15 +1409,15 @@ class CYCLES_LIGHT_PT_nodes(CyclesButtonsPanel, Panel):
panel_node_draw(layout, light, 'OUTPUT_LIGHT', 'Surface')
class CYCLES_LIGHT_PT_beam_shape(CyclesButtonsPanel, Panel):
bl_label = "Beam Shape"
class CYCLES_LIGHT_PT_spot(CyclesButtonsPanel, Panel):
bl_label = "Spot Shape"
bl_parent_id = "CYCLES_LIGHT_PT_light"
bl_context = "data"
@classmethod
def poll(cls, context):
if context.light.type in {'SPOT', 'AREA'}:
return context.light and CyclesButtonsPanel.poll(context)
light = context.light
return (light and light.type == 'SPOT') and CyclesButtonsPanel.poll(context)
def draw(self, context):
layout = self.layout
@@ -1425,12 +1425,9 @@ class CYCLES_LIGHT_PT_beam_shape(CyclesButtonsPanel, Panel):
layout.use_property_split = True
col = layout.column()
if light.type == 'SPOT':
col.prop(light, "spot_size", text="Spot Size")
col.prop(light, "spot_blend", text="Blend", slider=True)
col.prop(light, "show_cone")
elif light.type == 'AREA':
col.prop(light, "spread", text="Spread")
col.prop(light, "spot_size", text="Size")
col.prop(light, "spot_blend", text="Blend", slider=True)
col.prop(light, "show_cone")
class CYCLES_WORLD_PT_preview(CyclesButtonsPanel, Panel):
@@ -2287,7 +2284,7 @@ classes = (
CYCLES_LIGHT_PT_preview,
CYCLES_LIGHT_PT_light,
CYCLES_LIGHT_PT_nodes,
CYCLES_LIGHT_PT_beam_shape,
CYCLES_LIGHT_PT_spot,
CYCLES_WORLD_PT_preview,
CYCLES_WORLD_PT_surface,
CYCLES_WORLD_PT_volume,
@@ -2317,7 +2314,7 @@ classes = (
node_panel(CYCLES_WORLD_PT_settings_surface),
node_panel(CYCLES_WORLD_PT_settings_volume),
node_panel(CYCLES_LIGHT_PT_light),
node_panel(CYCLES_LIGHT_PT_beam_shape)
node_panel(CYCLES_LIGHT_PT_spot),
)

View File

@@ -29,7 +29,7 @@ BlenderImageLoader::BlenderImageLoader(BL::Image b_image, int frame)
{
}
bool BlenderImageLoader::load_metadata(const ImageDeviceFeatures &, ImageMetaData &metadata)
bool BlenderImageLoader::load_metadata(ImageMetaData &metadata)
{
metadata.width = b_image.size()[0];
metadata.height = b_image.size()[1];
@@ -171,7 +171,7 @@ BlenderPointDensityLoader::BlenderPointDensityLoader(BL::Depsgraph b_depsgraph,
{
}
bool BlenderPointDensityLoader::load_metadata(const ImageDeviceFeatures &, ImageMetaData &metadata)
bool BlenderPointDensityLoader::load_metadata(ImageMetaData &metadata)
{
metadata.channels = 4;
metadata.width = b_node.resolution();

View File

@@ -27,7 +27,7 @@ class BlenderImageLoader : public ImageLoader {
public:
BlenderImageLoader(BL::Image b_image, int frame);
bool load_metadata(const ImageDeviceFeatures &features, ImageMetaData &metadata) override;
bool load_metadata(ImageMetaData &metadata) override;
bool load_pixels(const ImageMetaData &metadata,
void *pixels,
const size_t pixels_size,
@@ -44,7 +44,7 @@ class BlenderPointDensityLoader : public ImageLoader {
public:
BlenderPointDensityLoader(BL::Depsgraph depsgraph, BL::ShaderNodeTexPointDensity b_node);
bool load_metadata(const ImageDeviceFeatures &features, ImageMetaData &metadata) override;
bool load_metadata(ImageMetaData &metadata) override;
bool load_pixels(const ImageMetaData &metadata,
void *pixels,
const size_t pixels_size,

View File

@@ -82,7 +82,6 @@ void BlenderSync::sync_light(BL::Object &b_parent,
light->set_axisu(transform_get_column(&tfm, 0));
light->set_axisv(transform_get_column(&tfm, 1));
light->set_sizeu(b_area_light.size());
light->set_spread(b_area_light.spread());
switch (b_area_light.shape()) {
case BL::AreaLight::shape_SQUARE:
light->set_sizev(light->get_sizeu());

View File

@@ -375,7 +375,7 @@ static void attr_create_generic(Scene *scene, Mesh *mesh, BL::Mesh &b_mesh, bool
case BL::Attribute::domain_POINT:
element = ATTR_ELEMENT_VERTEX;
break;
case BL::Attribute::domain_FACE:
case BL::Attribute::domain_POLYGON:
element = ATTR_ELEMENT_FACE;
break;
default:

View File

@@ -41,7 +41,7 @@ class BlenderSmokeLoader : public ImageLoader {
mesh_texture_space(b_mesh, texspace_loc, texspace_size);
}
bool load_metadata(const ImageDeviceFeatures &, ImageMetaData &metadata) override
bool load_metadata(ImageMetaData &metadata) override
{
if (!b_domain) {
return false;

View File

@@ -619,7 +619,6 @@ DeviceInfo Device::get_multi_device(const vector<DeviceInfo> &subdevices,
info.num = 0;
info.has_half_images = true;
info.has_nanovdb = true;
info.has_volume_decoupled = true;
info.has_branched_path = true;
info.has_adaptive_stop_per_sample = true;
@@ -666,7 +665,6 @@ DeviceInfo Device::get_multi_device(const vector<DeviceInfo> &subdevices,
/* Accumulate device info. */
info.has_half_images &= device.has_half_images;
info.has_nanovdb &= device.has_nanovdb;
info.has_volume_decoupled &= device.has_volume_decoupled;
info.has_branched_path &= device.has_branched_path;
info.has_adaptive_stop_per_sample &= device.has_adaptive_stop_per_sample;

View File

@@ -78,7 +78,6 @@ class DeviceInfo {
int num;
bool display_device; /* GPU is used as a display device. */
bool has_half_images; /* Support half-float textures. */
bool has_nanovdb; /* Support NanoVDB volumes. */
bool has_volume_decoupled; /* Decoupled volume shading. */
bool has_branched_path; /* Supports branched path tracing. */
bool has_adaptive_stop_per_sample; /* Per-sample adaptive sampling stopping. */
@@ -100,7 +99,6 @@ class DeviceInfo {
cpu_threads = 0;
display_device = false;
has_half_images = false;
has_nanovdb = false;
has_volume_decoupled = false;
has_branched_path = true;
has_adaptive_stop_per_sample = false;

View File

@@ -1654,7 +1654,6 @@ void device_cpu_info(vector<DeviceInfo> &devices)
info.has_adaptive_stop_per_sample = true;
info.has_osl = true;
info.has_half_images = true;
info.has_nanovdb = true;
info.has_profiling = true;
info.denoisers = DENOISER_NLM;
if (openimagedenoise_supported()) {

View File

@@ -128,7 +128,6 @@ void device_cuda_info(vector<DeviceInfo> &devices)
info.num = num;
info.has_half_images = (major >= 3);
info.has_nanovdb = true;
info.has_volume_decoupled = false;
info.has_adaptive_stop_per_sample = false;
info.denoisers = DENOISER_NLM;

View File

@@ -46,13 +46,10 @@ class MultiDevice : public Device {
list<SubDevice> devices, denoising_devices;
device_ptr unique_key;
vector<vector<SubDevice *>> peer_islands;
bool use_denoising;
bool matching_rendering_and_denoising_devices;
MultiDevice(DeviceInfo &info, Stats &stats, Profiler &profiler, bool background_)
: Device(info, stats, profiler, background_),
unique_key(1),
use_denoising(!info.denoising_devices.empty())
: Device(info, stats, profiler, background_), unique_key(1)
{
foreach (DeviceInfo &subinfo, info.multi_devices) {
/* Always add CPU devices at the back since GPU devices can change
@@ -197,7 +194,6 @@ class MultiDevice : public Device {
if (!sub.device->load_kernels(requested_features))
return false;
use_denoising = requested_features.use_denoising;
if (requested_features.use_denoising) {
/* Only need denoising feature, everything else is unused. */
DeviceRequestedFeatures denoising_features;
@@ -404,7 +400,7 @@ class MultiDevice : public Device {
size_t existing_size = mem.device_size;
/* The tile buffers are allocated on each device (see below), so copy to all of them */
if (strcmp(mem.name, "RenderBuffers") == 0 && use_denoising) {
if (strcmp(mem.name, "RenderBuffers") == 0) {
foreach (SubDevice &sub, devices) {
mem.device = sub.device;
mem.device_pointer = (existing_key) ? sub.ptr_map[existing_key] : 0;
@@ -470,7 +466,7 @@ class MultiDevice : public Device {
/* This is a hack to only allocate the tile buffers on denoising devices
* Similarly the tile buffers also need to be allocated separately on all devices so any
* overlap rendered for denoising does not interfere with each other */
if (strcmp(mem.name, "RenderBuffers") == 0 && use_denoising) {
if (strcmp(mem.name, "RenderBuffers") == 0) {
vector<device_ptr> device_pointers;
device_pointers.reserve(devices.size());
@@ -522,7 +518,7 @@ class MultiDevice : public Device {
size_t existing_size = mem.device_size;
/* Free memory that was allocated for all devices (see above) on each device */
if (mem.type == MEM_PIXELS || (strcmp(mem.name, "RenderBuffers") == 0 && use_denoising)) {
if (strcmp(mem.name, "RenderBuffers") == 0 || mem.type == MEM_PIXELS) {
foreach (SubDevice &sub, devices) {
mem.device = sub.device;
mem.device_pointer = sub.ptr_map[key];

View File

@@ -126,9 +126,6 @@ void device_opencl_info(vector<DeviceInfo> &devices)
/* Check OpenCL extensions */
info.has_half_images = platform_device.device_extensions.find("cl_khr_fp16") != string::npos;
/* Disabled for now due to apparent AMD driver bug. */
info.has_nanovdb = platform_name != "AMD Accelerated Parallel Processing";
devices.push_back(info);
num_devices++;
}

View File

@@ -2036,9 +2036,7 @@ string OpenCLDevice::kernel_build_options(const string *debug_src)
# endif
# ifdef WITH_NANOVDB
if (info.has_nanovdb) {
build_options += "-DWITH_NANOVDB ";
}
build_options += "-DWITH_NANOVDB ";
# endif
return build_options;

View File

@@ -119,11 +119,11 @@ ccl_device_inline bool lamp_light_sample(
klight->area.axisu[0], klight->area.axisu[1], klight->area.axisu[2]);
float3 axisv = make_float3(
klight->area.axisv[0], klight->area.axisv[1], klight->area.axisv[2]);
float3 Ng = make_float3(klight->area.dir[0], klight->area.dir[1], klight->area.dir[2]);
float3 D = make_float3(klight->area.dir[0], klight->area.dir[1], klight->area.dir[2]);
float invarea = fabsf(klight->area.invarea);
bool is_round = (klight->area.invarea < 0.0f);
if (dot(ls->P - P, Ng) > 0.0f) {
if (dot(ls->P - P, D) > 0.0f) {
return false;
}
@@ -135,37 +135,20 @@ ccl_device_inline bool lamp_light_sample(
ls->pdf = invarea;
}
else {
float3 sample_axisu = axisu;
float3 sample_axisv = axisv;
if (klight->area.tan_spread > 0.0f) {
if (!light_spread_clamp_area_light(
P, Ng, &ls->P, &sample_axisu, &sample_axisv, klight->area.tan_spread)) {
return false;
}
}
inplane = ls->P;
ls->pdf = rect_light_sample(P, &ls->P, sample_axisu, sample_axisv, randu, randv, true);
ls->pdf = rect_light_sample(P, &ls->P, axisu, axisv, randu, randv, true);
inplane = ls->P - inplane;
}
ls->u = dot(inplane, axisu) * (1.0f / dot(axisu, axisu)) + 0.5f;
ls->v = dot(inplane, axisv) * (1.0f / dot(axisv, axisv)) + 0.5f;
ls->Ng = Ng;
ls->Ng = D;
ls->D = normalize_len(ls->P - P, &ls->t);
ls->eval_fac = 0.25f * invarea;
if (klight->area.tan_spread > 0.0f) {
/* Area Light spread angle attenuation */
ls->eval_fac *= light_spread_attenuation(
ls->D, ls->Ng, klight->area.tan_spread, klight->area.normalize_spread);
}
if (is_round) {
ls->pdf *= lamp_light_pdf(kg, Ng, -ls->D, ls->t);
ls->pdf *= lamp_light_pdf(kg, D, -ls->D, ls->t);
}
}
}
@@ -300,28 +283,9 @@ ccl_device bool lamp_light_eval(
ls->pdf = invarea * lamp_light_pdf(kg, Ng, -D, ls->t);
}
else {
float3 sample_axisu = axisu;
float3 sample_axisv = axisv;
if (klight->area.tan_spread > 0.0f) {
if (!light_spread_clamp_area_light(
P, Ng, &light_P, &sample_axisu, &sample_axisv, klight->area.tan_spread)) {
return false;
}
}
ls->pdf = rect_light_sample(P, &light_P, sample_axisu, sample_axisv, 0, 0, false);
ls->pdf = rect_light_sample(P, &light_P, axisu, axisv, 0, 0, false);
}
ls->eval_fac = 0.25f * invarea;
if (klight->area.tan_spread > 0.0f) {
/* Area Light spread angle attenuation */
ls->eval_fac *= light_spread_attenuation(
ls->D, ls->Ng, klight->area.tan_spread, klight->area.normalize_spread);
if (ls->eval_fac == 0.0f) {
return false;
}
}
}
else {
return false;

View File

@@ -146,70 +146,6 @@ ccl_device float spot_light_attenuation(float3 dir, float spot_angle, float spot
return attenuation;
}
ccl_device float light_spread_attenuation(const float3 D,
const float3 lightNg,
const float tan_spread,
const float normalize_spread)
{
/* Model a soft-box grid, computing the ratio of light not hidden by the
* slats of the grid at a given angle. (see D10594). */
const float cos_a = -dot(D, lightNg);
const float sin_a = safe_sqrtf(1.0f - sqr(cos_a));
const float tan_a = sin_a / cos_a;
return max((1.0f - (tan_spread * tan_a)) * normalize_spread, 0.0f);
}
/* Compute subset of area light that actually has an influence on the shading point, to
* reduce noise with low spread. */
ccl_device bool light_spread_clamp_area_light(const float3 P,
const float3 lightNg,
float3 *lightP,
float3 *axisu,
float3 *axisv,
const float tan_spread)
{
/* Closest point in area light plane and distance to that plane. */
const float3 closest_P = P - dot(lightNg, P - *lightP) * lightNg;
const float t = len(closest_P - P);
/* Radius of circle on area light that actually affects the shading point. */
const float radius = t / tan_spread;
/* TODO: would be faster to store as normalized vector + length, also in rect_light_sample. */
float len_u, len_v;
const float3 u = normalize_len(*axisu, &len_u);
const float3 v = normalize_len(*axisv, &len_v);
/* Local uv coordinates of closest point. */
const float closest_u = dot(u, closest_P - *lightP);
const float closest_v = dot(v, closest_P - *lightP);
/* Compute rectangle encompassing the circle that affects the shading point,
* clamped to the bounds of the area light. */
const float min_u = max(closest_u - radius, -len_u * 0.5f);
const float max_u = min(closest_u + radius, len_u * 0.5f);
const float min_v = max(closest_v - radius, -len_v * 0.5f);
const float max_v = min(closest_v + radius, len_v * 0.5f);
/* Skip if rectangle is empty. */
if (min_u >= max_u || min_v >= max_v) {
return false;
}
/* Compute new area light center position and axes from rectangle in local
* uv coordinates. */
const float new_center_u = 0.5f * (min_u + max_u);
const float new_center_v = 0.5f * (min_v + max_v);
const float new_len_u = 0.5f * (max_u - min_u);
const float new_len_v = 0.5f * (max_v - min_v);
*lightP = *lightP + new_center_u * u + new_center_v * v;
*axisu = u * new_len_u * 2.0f;
*axisv = v * new_len_v * 2.0f;
return true;
}
ccl_device float lamp_light_pdf(KernelGlobals *kg, const float3 Ng, const float3 I, float t)
{
float cos_pi = dot(Ng, I);

View File

@@ -1501,9 +1501,9 @@ typedef struct KernelAreaLight {
float axisu[3];
float invarea;
float axisv[3];
float tan_spread;
float pad1;
float dir[3];
float normalize_spread;
float pad2;
} KernelAreaLight;
typedef struct KernelDistantLight {

View File

@@ -242,15 +242,12 @@ ccl_device float3 svm_math_blackbody_color(float t)
return make_float3(4.70366907f, 0.0f, 0.0f);
}
/* Manually align for readability. */
/* clang-format off */
int i = (t >= 6365.0f) ? 5 :
(t >= 3315.0f) ? 4 :
(t >= 1902.0f) ? 3 :
(t >= 1449.0f) ? 2 :
(t >= 1167.0f) ? 1 :
0;
/* clang-format on */
ccl_constant float *r = blackbody_table_r[i];
ccl_constant float *g = blackbody_table_g[i];

View File

@@ -1407,15 +1407,6 @@ void AlembicProcedural::generate(Scene *scene, Progress &progress)
need_data_updates = true;
}
/* Check if the shaders were modified. */
if (object->used_shaders_is_modified() && object->get_object() &&
object->get_object()->get_geometry()) {
Geometry *geometry = object->get_object()->get_geometry();
array<Node *> used_shaders = object->get_used_shaders();
geometry->set_used_shaders(used_shaders);
need_shader_updates = true;
}
/* Check for changes in shaders (e.g. newly requested attributes). */
foreach (Node *shader_node, object->get_used_shaders()) {
Shader *shader = static_cast<Shader *>(shader_node);
@@ -1595,11 +1586,6 @@ void AlembicProcedural::read_mesh(AlembicObject *abc_object, Abc::chrono_t frame
Mesh *mesh = static_cast<Mesh *>(object->get_geometry());
/* Make sure shader ids are also updated. */
if (mesh->used_shaders_is_modified()) {
mesh->tag_shader_modified();
}
cached_data.vertices.copy_to_socket(frame_time, mesh, mesh->get_verts_socket());
cached_data.shader.copy_to_socket(frame_time, mesh, mesh->get_shader_socket());
@@ -1667,11 +1653,6 @@ void AlembicProcedural::read_subd(AlembicObject *abc_object, Abc::chrono_t frame
Mesh *mesh = static_cast<Mesh *>(object->get_geometry());
/* Make sure shader ids are also updated. */
if (mesh->used_shaders_is_modified()) {
mesh->tag_shader_modified();
}
/* Cycles overwrites the original triangles when computing displacement, so we always have to
* repass the data if something is animated (vertices most likely) to avoid buffer overflows. */
if (!cached_data.is_constant()) {
@@ -1762,11 +1743,6 @@ void AlembicProcedural::read_curves(AlembicObject *abc_object, Abc::chrono_t fra
Hair *hair = static_cast<Hair *>(object->get_geometry());
/* Make sure shader ids are also updated. */
if (hair->used_shaders_is_modified()) {
hair->tag_curve_shader_modified();
}
cached_data.curve_keys.copy_to_socket(frame_time, hair, hair->get_curve_keys_socket());
cached_data.curve_radius.copy_to_socket(frame_time, hair, hair->get_curve_radius_socket());

View File

@@ -239,7 +239,6 @@ template<typename T> class DataStore {
{
invalidate_last_loaded_time();
data.clear();
index_data_map.clear();
}
void invalidate_last_loaded_time()
@@ -481,23 +480,16 @@ class AlembicProcedural : public Procedural {
* invocation, and updates the data on subsequent invocations if the frame changed. */
void generate(Scene *scene, Progress &progress);
/* Tag for an update only if something was modified. */
void tag_update(Scene *scene);
/* This should be called by scene exporters to request the rendering of an object located
* in the Alembic archive at the given path.
*
* Since we lazily load object, the function does not validate the existence of the object
* in the archive. If no objects with such path if found in the archive during the next call
* to `generate`, it will be ignored.
*
* Returns a pointer to an existing or a newly created AlembicObject for the given path. */
AlembicObject *get_or_create_object(const ustring &path);
private:
/* Add an object to our list of objects, and tag the socket as modified. */
void add_object(AlembicObject *object);
/* Tag for an update only if something was modified. */
void tag_update(Scene *scene);
/* Returns a pointer to an existing or a newly created AlembicObject for the given path. */
AlembicObject *get_or_create_object(const ustring &path);
private:
/* Load the data for all the objects whose data has not yet been loaded. */
void load_objects(Progress &progress);

View File

@@ -130,14 +130,6 @@ void Background::device_free(Device * /*device*/, DeviceScene * /*dscene*/)
void Background::tag_update(Scene *scene)
{
Shader *bg_shader = get_shader(scene);
if (bg_shader && bg_shader->is_modified()) {
/* Tag as modified to update the KernelBackground visibility information.
* We only tag the use_shader socket as modified as it is related to the shader
* and to avoid doing unnecessary updates anywhere else. */
tag_use_shader_modified();
}
if (ao_factor_is_modified() || use_ao_is_modified()) {
scene->integrator->tag_update(scene, Integrator::BACKGROUND_AO_MODIFIED);
}

View File

@@ -1584,6 +1584,7 @@ void GeometryManager::device_update_preprocess(Device *device, Scene *scene, Pro
dscene->tri_vnormal.tag_realloc();
dscene->tri_vindex.tag_realloc();
dscene->tri_patch.tag_realloc();
dscene->tri_vnormal.tag_realloc();
dscene->tri_patch_uv.tag_realloc();
dscene->tri_shader.tag_realloc();
dscene->patches.tag_realloc();

View File

@@ -303,8 +303,7 @@ ImageManager::ImageManager(const DeviceInfo &info)
animation_frame = 0;
/* Set image limits */
features.has_half_float = info.has_half_images;
features.has_nanovdb = info.has_nanovdb;
has_half_images = info.has_half_images;
}
ImageManager::~ImageManager()
@@ -348,7 +347,7 @@ void ImageManager::load_image_metadata(Image *img)
metadata = ImageMetaData();
metadata.colorspace = img->params.colorspace;
if (img->loader->load_metadata(features, metadata)) {
if (img->loader->load_metadata(metadata)) {
assert(metadata.type != IMAGE_DATA_NUM_TYPES);
}
else {
@@ -357,10 +356,15 @@ void ImageManager::load_image_metadata(Image *img)
metadata.detect_colorspace();
assert(features.has_half_float ||
(metadata.type != IMAGE_DATA_TYPE_HALF4 && metadata.type != IMAGE_DATA_TYPE_HALF));
assert(features.has_nanovdb || (metadata.type != IMAGE_DATA_TYPE_NANOVDB_FLOAT ||
metadata.type != IMAGE_DATA_TYPE_NANOVDB_FLOAT3));
/* No half textures on OpenCL, use full float instead. */
if (!has_half_images) {
if (metadata.type == IMAGE_DATA_TYPE_HALF4) {
metadata.type = IMAGE_DATA_TYPE_FLOAT4;
}
else if (metadata.type == IMAGE_DATA_TYPE_HALF) {
metadata.type = IMAGE_DATA_TYPE_FLOAT;
}
}
img->need_metadata = false;
}

View File

@@ -97,13 +97,6 @@ class ImageMetaData {
void detect_colorspace();
};
/* Information about supported features that Image loaders can use. */
class ImageDeviceFeatures {
public:
bool has_half_float;
bool has_nanovdb;
};
/* Image loader base class, that can be subclassed to load image data
* from custom sources (file, memory, procedurally generated, etc). */
class ImageLoader {
@@ -112,7 +105,7 @@ class ImageLoader {
virtual ~ImageLoader(){};
/* Load metadata without actual image yet, should be fast. */
virtual bool load_metadata(const ImageDeviceFeatures &features, ImageMetaData &metadata) = 0;
virtual bool load_metadata(ImageMetaData &metadata) = 0;
/* Load actual image contents. */
virtual bool load_pixels(const ImageMetaData &metadata,
@@ -219,8 +212,7 @@ class ImageManager {
private:
bool need_update_;
ImageDeviceFeatures features;
bool has_half_images;
thread_mutex device_mutex;
thread_mutex images_mutex;

View File

@@ -30,7 +30,7 @@ OIIOImageLoader::~OIIOImageLoader()
{
}
bool OIIOImageLoader::load_metadata(const ImageDeviceFeatures &features, ImageMetaData &metadata)
bool OIIOImageLoader::load_metadata(ImageMetaData &metadata)
{
/* Perform preliminary checks, with meaningful logging. */
if (!path_exists(filepath.string())) {
@@ -76,7 +76,7 @@ bool OIIOImageLoader::load_metadata(const ImageDeviceFeatures &features, ImageMe
}
/* check if it's half float */
if (spec.format == TypeDesc::HALF && features.has_half_float) {
if (spec.format == TypeDesc::HALF) {
is_half = true;
}

View File

@@ -26,7 +26,7 @@ class OIIOImageLoader : public ImageLoader {
OIIOImageLoader(const string &filepath);
~OIIOImageLoader();
bool load_metadata(const ImageDeviceFeatures &features, ImageMetaData &metadata) override;
bool load_metadata(ImageMetaData &metadata) override;
bool load_pixels(const ImageMetaData &metadata,
void *pixels,

View File

@@ -40,7 +40,7 @@ SkyLoader::SkyLoader(float sun_elevation,
SkyLoader::~SkyLoader(){};
bool SkyLoader::load_metadata(const ImageDeviceFeatures &, ImageMetaData &metadata)
bool SkyLoader::load_metadata(ImageMetaData &metadata)
{
metadata.width = 512;
metadata.height = 128;

View File

@@ -34,7 +34,7 @@ class SkyLoader : public ImageLoader {
float ozone_density);
~SkyLoader();
bool load_metadata(const ImageDeviceFeatures &features, ImageMetaData &metadata) override;
bool load_metadata(ImageMetaData &metadata) override;
bool load_pixels(const ImageMetaData &metadata,
void *pixels,

View File

@@ -34,7 +34,7 @@ VDBImageLoader::~VDBImageLoader()
{
}
bool VDBImageLoader::load_metadata(const ImageDeviceFeatures &features, ImageMetaData &metadata)
bool VDBImageLoader::load_metadata(ImageMetaData &metadata)
{
#ifdef WITH_OPENVDB
if (!grid) {
@@ -56,71 +56,55 @@ bool VDBImageLoader::load_metadata(const ImageDeviceFeatures &features, ImageMet
if (grid->isType<openvdb::FloatGrid>()) {
metadata.channels = 1;
# ifdef WITH_NANOVDB
if (features.has_nanovdb) {
nanogrid = nanovdb::openToNanoVDB(*openvdb::gridConstPtrCast<openvdb::FloatGrid>(grid));
}
nanogrid = nanovdb::openToNanoVDB(*openvdb::gridConstPtrCast<openvdb::FloatGrid>(grid));
# endif
}
else if (grid->isType<openvdb::Vec3fGrid>()) {
metadata.channels = 3;
# ifdef WITH_NANOVDB
if (features.has_nanovdb) {
nanogrid = nanovdb::openToNanoVDB(*openvdb::gridConstPtrCast<openvdb::Vec3fGrid>(grid));
}
nanogrid = nanovdb::openToNanoVDB(*openvdb::gridConstPtrCast<openvdb::Vec3fGrid>(grid));
# endif
}
else if (grid->isType<openvdb::BoolGrid>()) {
metadata.channels = 1;
# ifdef WITH_NANOVDB
if (features.has_nanovdb) {
nanogrid = nanovdb::openToNanoVDB(
openvdb::FloatGrid(*openvdb::gridConstPtrCast<openvdb::BoolGrid>(grid)));
}
nanogrid = nanovdb::openToNanoVDB(
openvdb::FloatGrid(*openvdb::gridConstPtrCast<openvdb::BoolGrid>(grid)));
# endif
}
else if (grid->isType<openvdb::DoubleGrid>()) {
metadata.channels = 1;
# ifdef WITH_NANOVDB
if (features.has_nanovdb) {
nanogrid = nanovdb::openToNanoVDB(
openvdb::FloatGrid(*openvdb::gridConstPtrCast<openvdb::DoubleGrid>(grid)));
}
nanogrid = nanovdb::openToNanoVDB(
openvdb::FloatGrid(*openvdb::gridConstPtrCast<openvdb::DoubleGrid>(grid)));
# endif
}
else if (grid->isType<openvdb::Int32Grid>()) {
metadata.channels = 1;
# ifdef WITH_NANOVDB
if (features.has_nanovdb) {
nanogrid = nanovdb::openToNanoVDB(
openvdb::FloatGrid(*openvdb::gridConstPtrCast<openvdb::Int32Grid>(grid)));
}
nanogrid = nanovdb::openToNanoVDB(
openvdb::FloatGrid(*openvdb::gridConstPtrCast<openvdb::Int32Grid>(grid)));
# endif
}
else if (grid->isType<openvdb::Int64Grid>()) {
metadata.channels = 1;
# ifdef WITH_NANOVDB
if (features.has_nanovdb) {
nanogrid = nanovdb::openToNanoVDB(
openvdb::FloatGrid(*openvdb::gridConstPtrCast<openvdb::Int64Grid>(grid)));
}
nanogrid = nanovdb::openToNanoVDB(
openvdb::FloatGrid(*openvdb::gridConstPtrCast<openvdb::Int64Grid>(grid)));
# endif
}
else if (grid->isType<openvdb::Vec3IGrid>()) {
metadata.channels = 3;
# ifdef WITH_NANOVDB
if (features.has_nanovdb) {
nanogrid = nanovdb::openToNanoVDB(
openvdb::Vec3fGrid(*openvdb::gridConstPtrCast<openvdb::Vec3IGrid>(grid)));
}
nanogrid = nanovdb::openToNanoVDB(
openvdb::Vec3fGrid(*openvdb::gridConstPtrCast<openvdb::Vec3IGrid>(grid)));
# endif
}
else if (grid->isType<openvdb::Vec3dGrid>()) {
metadata.channels = 3;
# ifdef WITH_NANOVDB
if (features.has_nanovdb) {
nanogrid = nanovdb::openToNanoVDB(
openvdb::Vec3fGrid(*openvdb::gridConstPtrCast<openvdb::Vec3dGrid>(grid)));
}
nanogrid = nanovdb::openToNanoVDB(
openvdb::Vec3fGrid(*openvdb::gridConstPtrCast<openvdb::Vec3dGrid>(grid)));
# endif
}
else if (grid->isType<openvdb::MaskGrid>()) {
@@ -134,25 +118,21 @@ bool VDBImageLoader::load_metadata(const ImageDeviceFeatures &features, ImageMet
}
# ifdef WITH_NANOVDB
if (nanogrid) {
metadata.byte_size = nanogrid.size();
if (metadata.channels == 1) {
metadata.type = IMAGE_DATA_TYPE_NANOVDB_FLOAT;
}
else {
metadata.type = IMAGE_DATA_TYPE_NANOVDB_FLOAT3;
}
metadata.byte_size = nanogrid.size();
if (metadata.channels == 1) {
metadata.type = IMAGE_DATA_TYPE_NANOVDB_FLOAT;
}
else {
metadata.type = IMAGE_DATA_TYPE_NANOVDB_FLOAT3;
}
# else
if (metadata.channels == 1) {
metadata.type = IMAGE_DATA_TYPE_FLOAT;
}
else {
metadata.type = IMAGE_DATA_TYPE_FLOAT4;
}
else
# endif
{
if (metadata.channels == 1) {
metadata.type = IMAGE_DATA_TYPE_FLOAT;
}
else {
metadata.type = IMAGE_DATA_TYPE_FLOAT4;
}
}
/* Set transform from object space to voxel index. */
openvdb::math::Mat4f grid_matrix = grid->transform().baseMap()->getAffineMap()->getMat4();
@@ -163,29 +143,20 @@ bool VDBImageLoader::load_metadata(const ImageDeviceFeatures &features, ImageMet
}
}
Transform texture_to_index;
# ifdef WITH_NANOVDB
if (nanogrid) {
texture_to_index = transform_identity();
}
else
Transform texture_to_index = transform_identity();
# else
openvdb::Coord min = bbox.min();
Transform texture_to_index = transform_translate(min.x(), min.y(), min.z()) *
transform_scale(dim.x(), dim.y(), dim.z());
# endif
{
openvdb::Coord min = bbox.min();
texture_to_index = transform_translate(min.x(), min.y(), min.z()) *
transform_scale(dim.x(), dim.y(), dim.z());
}
metadata.transform_3d = transform_inverse(index_to_object * texture_to_index);
metadata.use_transform_3d = true;
# ifndef WITH_NANOVDB
(void)features;
# endif
return true;
#else
(void)metadata;
(void)features;
return false;
#endif
}
@@ -194,52 +165,48 @@ bool VDBImageLoader::load_pixels(const ImageMetaData &, void *pixels, const size
{
#ifdef WITH_OPENVDB
# ifdef WITH_NANOVDB
if (nanogrid) {
memcpy(pixels, nanogrid.data(), nanogrid.size());
memcpy(pixels, nanogrid.data(), nanogrid.size());
# else
if (grid->isType<openvdb::FloatGrid>()) {
openvdb::tools::Dense<float, openvdb::tools::LayoutXYZ> dense(bbox, (float *)pixels);
openvdb::tools::copyToDense(*openvdb::gridConstPtrCast<openvdb::FloatGrid>(grid), dense);
}
else if (grid->isType<openvdb::Vec3fGrid>()) {
openvdb::tools::Dense<openvdb::Vec3f, openvdb::tools::LayoutXYZ> dense(
bbox, (openvdb::Vec3f *)pixels);
openvdb::tools::copyToDense(*openvdb::gridConstPtrCast<openvdb::Vec3fGrid>(grid), dense);
}
else if (grid->isType<openvdb::BoolGrid>()) {
openvdb::tools::Dense<float, openvdb::tools::LayoutXYZ> dense(bbox, (float *)pixels);
openvdb::tools::copyToDense(*openvdb::gridConstPtrCast<openvdb::BoolGrid>(grid), dense);
}
else if (grid->isType<openvdb::DoubleGrid>()) {
openvdb::tools::Dense<float, openvdb::tools::LayoutXYZ> dense(bbox, (float *)pixels);
openvdb::tools::copyToDense(*openvdb::gridConstPtrCast<openvdb::DoubleGrid>(grid), dense);
}
else if (grid->isType<openvdb::Int32Grid>()) {
openvdb::tools::Dense<float, openvdb::tools::LayoutXYZ> dense(bbox, (float *)pixels);
openvdb::tools::copyToDense(*openvdb::gridConstPtrCast<openvdb::Int32Grid>(grid), dense);
}
else if (grid->isType<openvdb::Int64Grid>()) {
openvdb::tools::Dense<float, openvdb::tools::LayoutXYZ> dense(bbox, (float *)pixels);
openvdb::tools::copyToDense(*openvdb::gridConstPtrCast<openvdb::Int64Grid>(grid), dense);
}
else if (grid->isType<openvdb::Vec3IGrid>()) {
openvdb::tools::Dense<openvdb::Vec3f, openvdb::tools::LayoutXYZ> dense(
bbox, (openvdb::Vec3f *)pixels);
openvdb::tools::copyToDense(*openvdb::gridConstPtrCast<openvdb::Vec3IGrid>(grid), dense);
}
else if (grid->isType<openvdb::Vec3dGrid>()) {
openvdb::tools::Dense<openvdb::Vec3f, openvdb::tools::LayoutXYZ> dense(
bbox, (openvdb::Vec3f *)pixels);
openvdb::tools::copyToDense(*openvdb::gridConstPtrCast<openvdb::Vec3dGrid>(grid), dense);
}
else if (grid->isType<openvdb::MaskGrid>()) {
openvdb::tools::Dense<float, openvdb::tools::LayoutXYZ> dense(bbox, (float *)pixels);
openvdb::tools::copyToDense(*openvdb::gridConstPtrCast<openvdb::MaskGrid>(grid), dense);
}
else
# endif
{
if (grid->isType<openvdb::FloatGrid>()) {
openvdb::tools::Dense<float, openvdb::tools::LayoutXYZ> dense(bbox, (float *)pixels);
openvdb::tools::copyToDense(*openvdb::gridConstPtrCast<openvdb::FloatGrid>(grid), dense);
}
else if (grid->isType<openvdb::Vec3fGrid>()) {
openvdb::tools::Dense<openvdb::Vec3f, openvdb::tools::LayoutXYZ> dense(
bbox, (openvdb::Vec3f *)pixels);
openvdb::tools::copyToDense(*openvdb::gridConstPtrCast<openvdb::Vec3fGrid>(grid), dense);
}
else if (grid->isType<openvdb::BoolGrid>()) {
openvdb::tools::Dense<float, openvdb::tools::LayoutXYZ> dense(bbox, (float *)pixels);
openvdb::tools::copyToDense(*openvdb::gridConstPtrCast<openvdb::BoolGrid>(grid), dense);
}
else if (grid->isType<openvdb::DoubleGrid>()) {
openvdb::tools::Dense<float, openvdb::tools::LayoutXYZ> dense(bbox, (float *)pixels);
openvdb::tools::copyToDense(*openvdb::gridConstPtrCast<openvdb::DoubleGrid>(grid), dense);
}
else if (grid->isType<openvdb::Int32Grid>()) {
openvdb::tools::Dense<float, openvdb::tools::LayoutXYZ> dense(bbox, (float *)pixels);
openvdb::tools::copyToDense(*openvdb::gridConstPtrCast<openvdb::Int32Grid>(grid), dense);
}
else if (grid->isType<openvdb::Int64Grid>()) {
openvdb::tools::Dense<float, openvdb::tools::LayoutXYZ> dense(bbox, (float *)pixels);
openvdb::tools::copyToDense(*openvdb::gridConstPtrCast<openvdb::Int64Grid>(grid), dense);
}
else if (grid->isType<openvdb::Vec3IGrid>()) {
openvdb::tools::Dense<openvdb::Vec3f, openvdb::tools::LayoutXYZ> dense(
bbox, (openvdb::Vec3f *)pixels);
openvdb::tools::copyToDense(*openvdb::gridConstPtrCast<openvdb::Vec3IGrid>(grid), dense);
}
else if (grid->isType<openvdb::Vec3dGrid>()) {
openvdb::tools::Dense<openvdb::Vec3f, openvdb::tools::LayoutXYZ> dense(
bbox, (openvdb::Vec3f *)pixels);
openvdb::tools::copyToDense(*openvdb::gridConstPtrCast<openvdb::Vec3dGrid>(grid), dense);
}
else if (grid->isType<openvdb::MaskGrid>()) {
openvdb::tools::Dense<float, openvdb::tools::LayoutXYZ> dense(bbox, (float *)pixels);
openvdb::tools::copyToDense(*openvdb::gridConstPtrCast<openvdb::MaskGrid>(grid), dense);
}
}
return true;
#else
(void)pixels;

View File

@@ -33,8 +33,7 @@ class VDBImageLoader : public ImageLoader {
VDBImageLoader(const string &grid_name);
~VDBImageLoader();
virtual bool load_metadata(const ImageDeviceFeatures &features,
ImageMetaData &metadata) override;
virtual bool load_metadata(ImageMetaData &metadata) override;
virtual bool load_pixels(const ImageMetaData &metadata,
void *pixels,

View File

@@ -129,7 +129,6 @@ NODE_DEFINE(Light)
SOCKET_VECTOR(axisv, "Axis V", zero_float3());
SOCKET_FLOAT(sizev, "Size V", 1.0f);
SOCKET_BOOLEAN(round, "Round", false);
SOCKET_FLOAT(spread, "Spread", M_PI_F);
SOCKET_INT(map_resolution, "Map Resolution", 0);
@@ -859,15 +858,6 @@ void LightManager::device_update_points(Device *, DeviceScene *dscene, Scene *sc
float invarea = (area != 0.0f) ? 1.0f / area : 1.0f;
float3 dir = light->dir;
/* Convert from spread angle 0..180 to 90..0, clamping to a minimum
* angle to avoid excessive noise. */
const float min_spread_angle = 1.0f * M_PI_F / 180.0f;
const float spread_angle = 0.5f * (M_PI_F - max(light->spread, min_spread_angle));
/* Normalization computed using:
* integrate cos(x) (1 - tan(x) * tan(a)) * sin(x) from x = a to pi/2. */
const float tan_spread = tanf(spread_angle);
const float normalize_spread = 2.0f / (2.0f + (2.0f * spread_angle - M_PI_F) * tan_spread);
dir = safe_normalize(dir);
if (light->use_mis && area != 0.0f)
@@ -887,8 +877,6 @@ void LightManager::device_update_points(Device *, DeviceScene *dscene, Scene *sc
klights[light_index].area.dir[0] = dir.x;
klights[light_index].area.dir[1] = dir.y;
klights[light_index].area.dir[2] = dir.z;
klights[light_index].area.tan_spread = tan_spread;
klights[light_index].area.normalize_spread = normalize_spread;
}
else if (light->light_type == LIGHT_SPOT) {
shader_id &= ~SHADER_AREA_LIGHT;

View File

@@ -58,7 +58,6 @@ class Light : public Node {
NODE_SOCKET_API(float3, axisv)
NODE_SOCKET_API(float, sizev)
NODE_SOCKET_API(bool, round)
NODE_SOCKET_API(float, spread)
NODE_SOCKET_API(Transform, tfm)

View File

@@ -153,6 +153,10 @@ void Object::update_motion()
void Object::compute_bounds(bool motion_blur)
{
if (!is_modified() && !geometry->is_modified()) {
return;
}
BoundBox mbounds = geometry->bounds;
if (motion_blur && use_motion()) {

View File

@@ -18,7 +18,6 @@
#define TEST_CATEGORY_NAME util_avx2
#if (defined(i386) || defined(_M_IX86) || defined(__x86_64__) || defined(_M_X64)) && \
defined(__AVX2__)
#if defined(i386) || defined(_M_IX86) || defined(__x86_64__) || defined(_M_X64)
# include "util_avxf_test.h"
#endif

View File

@@ -18,7 +18,6 @@
#define TEST_CATEGORY_NAME util_avx
#if (defined(i386) || defined(_M_IX86) || defined(__x86_64__) || defined(_M_X64)) && \
defined(__AVX__)
#if defined(i386) || defined(_M_IX86) || defined(__x86_64__) || defined(_M_X64)
# include "util_avxf_test.h"
#endif

View File

@@ -24,8 +24,7 @@
#pragma once
/**
* \code{.py}
/*
* import bpy
* import textwrap
*
@@ -43,7 +42,6 @@
* print("%d,%d," % (w, h))
* text = ", ".join(["0x%x" % p for p in pixels])
* print(textwrap.fill(text, width=120), end=",\n")
* \endcode
*/
/**

View File

@@ -533,18 +533,11 @@ GHOST_TSuccess GHOST_WindowWin32::setState(GHOST_TWindowState state)
wp.showCmd = SW_SHOWMAXIMIZED;
wp.ptMaxPosition.x = 0;
wp.ptMaxPosition.y = 0;
style &= ~(WS_CAPTION | WS_MAXIMIZE);
style &= ~WS_CAPTION;
break;
case GHOST_kWindowStateNormal:
default:
if (curstate == GHOST_kWindowStateFullScreen &&
m_normal_state == GHOST_kWindowStateMaximized) {
wp.showCmd = SW_SHOWMAXIMIZED;
m_normal_state = GHOST_kWindowStateNormal;
}
else {
wp.showCmd = SW_SHOWNORMAL;
}
wp.showCmd = SW_SHOWNORMAL;
break;
}
::SetWindowLongPtr(m_hWnd, GWL_STYLE, style);

View File

@@ -1,2 +0,0 @@
DisableFormat: true
SortIncludes: false

View File

@@ -349,10 +349,6 @@ def enable(module_name, *, default_set=False, persistent=False, handle_error=Non
# 1) try import
try:
mod = __import__(module_name)
if mod.__file__ is None:
# This can happen when the addon has been removed but there are
# residual `.pyc` files left behind.
raise ImportError(name=module_name)
mod.__time__ = os.path.getmtime(mod.__file__)
mod.__addon_enabled__ = False
except Exception as ex:

View File

@@ -32,6 +32,12 @@ import bpy
IS_TESTING = False
def drepr(string):
# is there a less crappy way to do this in python?, re.escape also escapes
# single quotes strings so can't use it.
return '"%s"' % repr(string)[1:-1].replace("\"", "\\\"").replace("\\'", "'")
def classes_recursive(base_type, clss=None):
if clss is None:
clss = [base_type]
@@ -60,7 +66,7 @@ class DataPathBuilder:
if type(key) is int:
str_value = '[%d]' % key
elif type(key) is str:
str_value = '["%s"]' % bpy.utils.escape_identifier(key)
str_value = '[%s]' % drepr(key)
else:
raise Exception("unsupported accessor %r of type %r (internal error)" % (key, type(key)))
return DataPathBuilder(self.data_path + (str_value, ))

View File

@@ -1,91 +0,0 @@
# ##### BEGIN GPL LICENSE BLOCK #####
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software Foundation,
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
# ##### END GPL LICENSE BLOCK #####
# <pep8 compliant>
__all__ = (
"property_definition_from_data_path",
"decompose_data_path",
)
class _TokenizeDataPath:
"""
Class to split up tokens of a data-path.
Note that almost all access generates new objects with additional paths,
with the exception of iteration which is the intended way to access the resulting data."""
__slots__ = (
"data_path",
)
def __init__(self, attrs):
self.data_path = attrs
def __getattr__(self, attr):
return _TokenizeDataPath(self.data_path + ((".%s" % attr),))
def __getitem__(self, key):
return _TokenizeDataPath(self.data_path + (("[%r]" % (key,)),))
def __call__(self, *args, **kw):
value_str = ", ".join([
val for val in (
", ".join(repr(value) for value in args),
", ".join(["%s=%r" % (key, value) for key, value in kw.items()]),
) if val])
return _TokenizeDataPath(self.data_path + ('(%s)' % value_str, ))
def __iter__(self):
return iter(self.data_path)
def decompose_data_path(data_path):
"""
Return the components of a data path split into a list.
"""
ns = {"base": _TokenizeDataPath(())}
return list(eval("base" + data_path, ns, ns))
def property_definition_from_data_path(base, data_path):
"""
Return an RNA property definition from an object and a data path.
In Blender this is often used with ``context`` as the base and a
path that it references, for example ``.space_data.lock_camera``.
"""
data = decompose_data_path(data_path)
while data and (not data[-1].startswith(".")):
data.pop()
if (not data) or (not data[-1].startswith(".")) or (len(data) < 2):
return None
data_path_head = "".join(data[:-1])
data_path_tail = data[-1]
value_head = eval("base" + data_path_head)
value_head_rna = getattr(value_head, "bl_rna", None)
if value_head_rna is None:
return None
value_tail = value_head.bl_rna.properties.get(data_path_tail[1:])
if not value_tail:
return None
return value_tail

View File

@@ -1694,7 +1694,6 @@ def km_image(params):
("image.view_all", {"type": 'HOME', "value": 'PRESS', "shift": True},
{"properties": [("fit_view", True)]}),
("image.view_selected", {"type": 'NUMPAD_PERIOD', "value": 'PRESS'}, None),
("image.view_cursor_center", {"type": 'C', "value": 'PRESS', "shift": True}, None),
("image.view_pan", {"type": 'MIDDLEMOUSE', "value": 'PRESS'}, None),
("image.view_pan", {"type": 'MIDDLEMOUSE', "value": 'PRESS', "shift": True}, None),
("image.view_pan", {"type": 'TRACKPADPAN', "value": 'ANY'}, None),

View File

@@ -355,8 +355,7 @@ class UpdateAnimatedTransformConstraint(Operator):
use_convert_to_radians: BoolProperty(
name="Convert to Radians",
description="Convert f-curves/drivers affecting rotations to radians.\n"
"Warning: Use this only once",
description="Convert fcurves/drivers affecting rotations to radians (Warning: use this only once!)",
default=True,
)
@@ -431,9 +430,22 @@ class UpdateAnimatedTransformConstraint(Operator):
return {'FINISHED'}
class ANIM_OT_show_group_colors_deprecated(Operator):
"""This option moved to Preferences > Animation"""
bl_idname = "anim.show_group_colors_deprecated"
bl_label = "Show Group Colors"
bl_options = {'REGISTER'}
@classmethod
def poll(cls, _context):
return False
classes = (
ANIM_OT_keying_set_export,
NLA_OT_bake,
ClearUselessActions,
UpdateAnimatedTransformConstraint,
ANIM_OT_show_group_colors_deprecated,
)

View File

@@ -95,76 +95,6 @@ def context_path_validate(context, data_path):
return value
def context_path_to_rna_property(context, data_path):
from bl_rna_utils.data_path import property_definition_from_data_path
rna_prop = property_definition_from_data_path(context, "." + data_path)
if rna_prop is not None:
return rna_prop
return None
def context_path_decompose(data_path):
# Decompose a data_path into 3 components:
# base_path, prop_attr, prop_item, where:
# `"foo.bar["baz"].fiz().bob.buz[10][2]"`, returns...
# `("foo.bar["baz"].fiz().bob", "buz", "[10][2]")`
#
# This is useful as we often want the base and the property, ignoring any item access.
# Note that item access includes function calls since these aren't properties.
#
# Note that the `.` is removed from the start of the first and second values,
# this is done because `.attr` isn't convenient to use as an argument,
# also the convention is not to include this within the data paths or the operator logic for `bpy.ops.wm.*`.
from bl_rna_utils.data_path import decompose_data_path
path_split = decompose_data_path("." + data_path)
# Find the last property that isn't a function call.
value_prev = ""
i = len(path_split)
while (i := i - 1) >= 0:
value = path_split[i]
if value.startswith("."):
if not value_prev.startswith("("):
break
value_prev = value
if i != -1:
base_path = "".join(path_split[:i])
prop_attr = path_split[i]
prop_item = "".join(path_split[i + 1:])
if base_path:
assert(base_path.startswith("."))
base_path= base_path[1:]
if prop_attr:
assert(prop_attr.startswith("."))
prop_attr = prop_attr[1:]
else:
# If there are no properties, everything is an item.
# Note that should not happen in practice with values which are added onto `context`,
# include since it's correct to account for this case and not doing so will create a confusing exception.
base_path = ""
prop_attr = ""
prop_item = "".join(path_split)
return (base_path, prop_attr, prop_item)
def description_from_data_path(base, data_path, *, prefix, value=Ellipsis):
if context_path_validate(base, data_path) is Ellipsis:
return None
if (
(rna_prop := context_path_to_rna_property(base, data_path)) and
(description := rna_prop.description)
):
description = "%s: %s" % (prefix, description)
if value != Ellipsis:
description = "%s\n%s: %s" % (description, iface_("Value"), str(value))
return description
return None
def operator_value_is_undo(value):
if value in {None, Ellipsis}:
return False
@@ -190,9 +120,12 @@ def operator_value_is_undo(value):
def operator_path_is_undo(context, data_path):
data_path_head, _, _ = context_path_decompose(data_path)
# note that if we have data paths that use strings this could fail
# luckily we don't do this!
#
# When we can't find the data owner assume no undo is needed.
data_path_head = data_path.rpartition(".")[0]
if not data_path_head:
return False
@@ -235,10 +168,6 @@ class WM_OT_context_set_boolean(Operator):
default=True,
)
@classmethod
def description(cls, context, props):
return description_from_data_path(context, props.data_path, prefix=iface_("Assign"), value=props.value)
execute = execute_context_assign
@@ -256,10 +185,6 @@ class WM_OT_context_set_int(Operator): # same as enum
)
relative: rna_relative_prop
@classmethod
def description(cls, context, props):
return description_from_data_path(context, props.data_path, prefix="Assign", value=props.value)
execute = execute_context_assign
@@ -276,10 +201,6 @@ class WM_OT_context_scale_float(Operator):
default=1.0,
)
@classmethod
def description(cls, context, props):
return description_from_data_path(context, props.data_path, prefix=iface_("Scale"), value=props.value)
def execute(self, context):
data_path = self.data_path
if context_path_validate(context, data_path) is Ellipsis:
@@ -314,10 +235,6 @@ class WM_OT_context_scale_int(Operator):
options={'SKIP_SAVE'},
)
@classmethod
def description(cls, context, props):
return description_from_data_path(context, props.data_path, prefix=iface_("Scale"), value=props.value)
def execute(self, context):
data_path = self.data_path
if context_path_validate(context, data_path) is Ellipsis:
@@ -357,10 +274,6 @@ class WM_OT_context_set_float(Operator): # same as enum
)
relative: rna_relative_prop
@classmethod
def description(cls, context, props):
return description_from_data_path(context, props.data_path, prefix="Assign", value=props.value)
execute = execute_context_assign
@@ -377,10 +290,6 @@ class WM_OT_context_set_string(Operator): # same as enum
maxlen=1024,
)
@classmethod
def description(cls, context, props):
return description_from_data_path(context, props.data_path, prefix=iface_("Assign"), value=props.value)
execute = execute_context_assign
@@ -397,10 +306,6 @@ class WM_OT_context_set_enum(Operator):
maxlen=1024,
)
@classmethod
def description(cls, context, props):
return description_from_data_path(context, props.data_path, prefix=iface_("Assign"), value=props.value)
execute = execute_context_assign
@@ -417,10 +322,6 @@ class WM_OT_context_set_value(Operator):
maxlen=1024,
)
@classmethod
def description(cls, context, props):
return description_from_data_path(context, props.data_path, prefix=iface_("Assign"), value=props.value)
def execute(self, context):
data_path = self.data_path
if context_path_validate(context, data_path) is Ellipsis:
@@ -438,13 +339,6 @@ class WM_OT_context_toggle(Operator):
data_path: rna_path_prop
module: rna_module_prop
@classmethod
def description(cls, context, props):
# Currently unsupported, it might be possible to extract this.
if props.module:
return None
return description_from_data_path(context, props.data_path, prefix=iface_("Toggle"))
def execute(self, context):
data_path = self.data_path
@@ -481,11 +375,6 @@ class WM_OT_context_toggle_enum(Operator):
maxlen=1024,
)
@classmethod
def description(cls, context, props):
value = "(%r, %r)" % (props.value_1, props.value_2)
return description_from_data_path(context, props.data_path, prefix=iface_("Toggle"), value=value)
def execute(self, context):
data_path = self.data_path
@@ -517,10 +406,6 @@ class WM_OT_context_cycle_int(Operator):
reverse: rna_reverse_prop
wrap: rna_wrap_prop
@classmethod
def description(cls, context, props):
return description_from_data_path(context, props.data_path, prefix=iface_("Cycle"))
def execute(self, context):
data_path = self.data_path
value = context_path_validate(context, data_path)
@@ -557,10 +442,6 @@ class WM_OT_context_cycle_enum(Operator):
reverse: rna_reverse_prop
wrap: rna_wrap_prop
@classmethod
def description(cls, context, props):
return description_from_data_path(context, props.data_path, prefix=iface_("Cycle"))
def execute(self, context):
data_path = self.data_path
value = context_path_validate(context, data_path)
@@ -569,11 +450,22 @@ class WM_OT_context_cycle_enum(Operator):
orig_value = value
rna_prop = context_path_to_rna_property(context, data_path)
# Have to get rna enum values
rna_struct_str, rna_prop_str = data_path.rsplit('.', 1)
i = rna_prop_str.find('[')
# just in case we get "context.foo.bar[0]"
if i != -1:
rna_prop_str = rna_prop_str[0:i]
rna_struct = eval("context.%s.rna_type" % rna_struct_str)
rna_prop = rna_struct.properties[rna_prop_str]
if type(rna_prop) != bpy.types.EnumProperty:
raise Exception("expected an enum property")
enums = rna_prop.enum_items.keys()
enums = rna_struct.properties[rna_prop_str].enum_items.keys()
orig_index = enums.index(orig_value)
# Have the info we need, advance to the next item.
@@ -606,10 +498,6 @@ class WM_OT_context_cycle_array(Operator):
data_path: rna_path_prop
reverse: rna_reverse_prop
@classmethod
def description(cls, context, props):
return description_from_data_path(context, props.data_path, prefix=iface_("Cycle"))
def execute(self, context):
data_path = self.data_path
value = context_path_validate(context, data_path)
@@ -635,10 +523,6 @@ class WM_OT_context_menu_enum(Operator):
data_path: rna_path_prop
@classmethod
def description(cls, context, props):
return description_from_data_path(context, props.data_path, prefix=iface_("Menu"))
def execute(self, context):
data_path = self.data_path
value = context_path_validate(context, data_path)
@@ -646,15 +530,15 @@ class WM_OT_context_menu_enum(Operator):
if value is Ellipsis:
return {'PASS_THROUGH'}
base_path, prop_attr, _ = context_path_decompose(data_path)
base_path, prop_string = data_path.rsplit(".", 1)
value_base = context_path_validate(context, base_path)
rna_prop = context_path_to_rna_property(context, data_path)
prop = value_base.bl_rna.properties[prop_string]
def draw_cb(self, context):
layout = self.layout
layout.prop(value_base, prop_attr, expand=True)
layout.prop(value_base, prop_string, expand=True)
context.window_manager.popup_menu(draw_func=draw_cb, title=rna_prop.name, icon=rna_prop.icon)
context.window_manager.popup_menu(draw_func=draw_cb, title=prop.name, icon=prop.icon)
return {'FINISHED'}
@@ -666,10 +550,6 @@ class WM_OT_context_pie_enum(Operator):
data_path: rna_path_prop
@classmethod
def description(cls, context, props):
return description_from_data_path(context, props.data_path, prefix=iface_("Pie Menu"))
def invoke(self, context, event):
wm = context.window_manager
data_path = self.data_path
@@ -678,15 +558,15 @@ class WM_OT_context_pie_enum(Operator):
if value is Ellipsis:
return {'PASS_THROUGH'}
base_path, prop_attr, _ = context_path_decompose(data_path)
base_path, prop_string = data_path.rsplit(".", 1)
value_base = context_path_validate(context, base_path)
rna_prop = context_path_to_rna_property(context, data_path)
prop = value_base.bl_rna.properties[prop_string]
def draw_cb(self, context):
layout = self.layout
layout.prop(value_base, prop_attr, expand=True)
layout.prop(value_base, prop_string, expand=True)
wm.popup_menu_pie(draw_func=draw_cb, title=rna_prop.name, icon=rna_prop.icon, event=event)
wm.popup_menu_pie(draw_func=draw_cb, title=prop.name, icon=prop.icon, event=event)
return {'FINISHED'}
@@ -707,15 +587,11 @@ class WM_OT_operator_pie_enum(Operator):
maxlen=1024,
)
@classmethod
def description(cls, context, props):
return description_from_data_path(context, props.data_path, prefix=iface_("Pie Menu"))
def invoke(self, context, event):
wm = context.window_manager
data_path = self.data_path
prop_attr = self.prop_string
prop_string = self.prop_string
# same as eval("bpy.ops." + data_path)
op_mod_str, ob_id_str = data_path.split(".", 1)
@@ -731,7 +607,7 @@ class WM_OT_operator_pie_enum(Operator):
def draw_cb(self, context):
layout = self.layout
pie = layout.menu_pie()
pie.operator_enum(data_path, prop_attr)
pie.operator_enum(data_path, prop_string)
wm.popup_menu_pie(draw_func=draw_cb, title=op_rna.name, event=event)
@@ -755,17 +631,17 @@ class WM_OT_context_set_id(Operator):
value = self.value
data_path = self.data_path
# Match the pointer type from the target property to `bpy.data.*`
# match the pointer type from the target property to bpy.data.*
# so we lookup the correct list.
rna_prop = context_path_to_rna_property(context, data_path)
rna_prop_fixed_type = rna_prop.fixed_type
data_path_base, data_path_prop = data_path.rsplit(".", 1)
data_prop_rna = eval("context.%s" % data_path_base).rna_type.properties[data_path_prop]
data_prop_rna_type = data_prop_rna.fixed_type
id_iter = None
for prop in bpy.data.rna_type.properties:
if prop.rna_type.identifier == "CollectionProperty":
if prop.fixed_type == rna_prop_fixed_type:
if prop.fixed_type == data_prop_rna_type:
id_iter = prop.identifier
break

View File

@@ -77,7 +77,6 @@ class COLLECTION_PT_instancing(CollectionButtonsPanel, Panel):
class COLLECTION_PT_lineart_collection(CollectionButtonsPanel, Panel):
bl_label = "Line Art"
bl_order = 10
def draw(self, context):
layout = self.layout

View File

@@ -86,19 +86,12 @@ class DATA_PT_display(ArmatureButtonsPanel, Panel):
col = layout.column(heading="Show")
col.prop(arm, "show_names", text="Names")
col.prop(arm, "show_axes", text="Axes")
col.prop(arm, "show_bone_custom_shapes", text="Shapes")
col.prop(arm, "show_group_colors", text="Group Colors")
if ob:
col.prop(ob, "show_in_front", text="In Front")
col = layout.column(align=False, heading="Axes")
row = col.row(align=True)
row.prop(arm, "show_axes", text="")
sub = row.row(align=True)
sub.active = arm.show_axes
sub.prop(arm, "axes_position", text="Position")
class DATA_MT_bone_group_context_menu(Menu):
bl_label = "Bone Group Specials"

View File

@@ -277,7 +277,6 @@ class MATERIAL_PT_viewport(MaterialButtonsPanel, Panel):
class MATERIAL_PT_lineart(MaterialButtonsPanel, Panel):
bl_label = "Line Art"
bl_options = {'DEFAULT_CLOSED'}
bl_order = 10
@classmethod
def poll(cls, context):

View File

@@ -311,7 +311,6 @@ class OBJECT_PT_instancing_size(ObjectButtonsPanel, Panel):
class OBJECT_PT_lineart(ObjectButtonsPanel, Panel):
bl_label = "Line Art"
bl_options = {'DEFAULT_CLOSED'}
bl_order = 10
@classmethod
def poll(cls, context):

View File

@@ -74,6 +74,10 @@ class PHYSICS_PT_add(PhysicButtonsPanel, Panel):
def draw(self, context):
layout = self.layout
row = layout.row(align=True)
row.alignment = 'LEFT'
row.label(text="Enable physics for:")
flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=True)
obj = context.object

View File

@@ -348,6 +348,8 @@ class DOPESHEET_MT_view(Menu):
col.active = context.space_data.mode != 'SHAPEKEY'
col.prop(st, "show_sliders")
if bpy.app.version < (2, 93):
layout.operator("anim.show_group_colors_deprecated", icon='CHECKBOX_HLT')
layout.prop(st, "show_interpolation")
layout.prop(st, "show_extremes")
layout.prop(st, "use_auto_merge_keyframes")

View File

@@ -18,6 +18,7 @@
# <pep8 compliant>
import bpy
from bpy.types import Header, Menu, Panel
from bl_ui.space_dopesheet import (
DopesheetFilterPopoverBase,
@@ -119,6 +120,10 @@ class GRAPH_MT_view(Menu):
layout.prop(st, "use_realtime_update")
layout.prop(st, "show_cursor")
layout.prop(st, "show_sliders")
if bpy.app.version < (2, 93):
layout.operator("anim.show_group_colors_deprecated", icon='CHECKBOX_HLT')
layout.prop(st, "use_auto_merge_keyframes")
if st.mode != 'DRIVERS':

View File

@@ -481,7 +481,7 @@ class NODE_MT_context_menu(Menu):
class NODE_PT_active_node_generic(Panel):
bl_space_type = 'NODE_EDITOR'
bl_region_type = 'UI'
bl_category = "Node"
bl_category = "Item"
bl_label = "Node"
@classmethod
@@ -499,7 +499,7 @@ class NODE_PT_active_node_generic(Panel):
class NODE_PT_active_node_color(Panel):
bl_space_type = 'NODE_EDITOR'
bl_region_type = 'UI'
bl_category = "Node"
bl_category = "Item"
bl_label = "Color"
bl_options = {'DEFAULT_CLOSED'}
bl_parent_id = 'NODE_PT_active_node_generic'
@@ -529,7 +529,7 @@ class NODE_PT_active_node_color(Panel):
class NODE_PT_active_node_properties(Panel):
bl_space_type = 'NODE_EDITOR'
bl_region_type = 'UI'
bl_category = "Node"
bl_category = "Item"
bl_label = "Properties"
bl_options = {'DEFAULT_CLOSED'}
@@ -570,7 +570,7 @@ class NODE_PT_active_node_properties(Panel):
class NODE_PT_texture_mapping(Panel):
bl_space_type = 'NODE_EDITOR'
bl_region_type = 'UI'
bl_category = "Node"
bl_category = "Item"
bl_label = "Texture Mapping"
bl_options = {'DEFAULT_CLOSED'}
COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_WORKBENCH'}

View File

@@ -2244,7 +2244,6 @@ class USERPREF_PT_experimental_new_features(ExperimentalPanel, Panel):
({"property": "use_switch_object_operator"}, "T80402"),
({"property": "use_sculpt_tools_tilt"}, "T82877"),
({"property": "use_asset_browser"}, ("project/profile/124/", "Milestone 1")),
({"property": "use_override_templates"}, ("T73318", "Milestone 4")),
),
)

View File

@@ -622,15 +622,9 @@ class VIEW3D_PT_tools_brush_texture(Panel, View3DPaintPanel):
@classmethod
def poll(cls, context):
if (
(settings := cls.paint_settings(context)) and
(brush := settings.brush)
):
if context.sculpt_object or context.vertex_paint_object:
return True
elif context.image_paint_object:
return (brush.image_tool == 'DRAW')
return False
settings = cls.paint_settings(context)
return (settings and settings.brush and
(context.sculpt_object or context.image_paint_object or context.vertex_paint_object))
def draw(self, context):
layout = self.layout

View File

@@ -368,7 +368,6 @@ compositor_node_categories = [
NodeItem("CompositorNodePixelate"),
NodeItem("CompositorNodeSunBeams"),
NodeItem("CompositorNodeDenoise"),
NodeItem("CompositorNodeAntiAliasing"),
]),
CompositorNodeCategory("CMP_OP_VECTOR", "Vector", items=[
NodeItem("CompositorNodeNormal"),
@@ -485,7 +484,6 @@ geometry_node_categories = [
GeometryNodeCategory("GEO_ATTRIBUTE", "Attribute", items=[
NodeItem("GeometryNodeAttributeRandomize"),
NodeItem("GeometryNodeAttributeMath"),
NodeItem("GeometryNodeAttributeClamp"),
NodeItem("GeometryNodeAttributeCompare"),
NodeItem("GeometryNodeAttributeConvert"),
NodeItem("GeometryNodeAttributeFill"),
@@ -497,7 +495,7 @@ geometry_node_categories = [
NodeItem("GeometryNodeAttributeCombineXYZ"),
NodeItem("GeometryNodeAttributeSeparateXYZ"),
NodeItem("GeometryNodeAttributeRemove"),
NodeItem("GeometryNodeAttributeMapRange"),
NodeItem("FunctionNodeGroup"),
]),
GeometryNodeCategory("GEO_COLOR", "Color", items=[
NodeItem("ShaderNodeValToRGB"),
@@ -523,16 +521,7 @@ geometry_node_categories = [
NodeItem("GeometryNodeEdgeSplit"),
NodeItem("GeometryNodeSubdivisionSurface"),
NodeItem("GeometryNodeSubdivide"),
]),
GeometryNodeCategory("GEO_PRIMITIVES", "Mesh Primitives", items=[
NodeItem("GeometryNodeMeshCircle"),
NodeItem("GeometryNodeMeshCone"),
NodeItem("GeometryNodeMeshCube"),
NodeItem("GeometryNodeMeshCylinder"),
NodeItem("GeometryNodeMeshGrid"),
NodeItem("GeometryNodeMeshIcoSphere"),
NodeItem("GeometryNodeMeshLine"),
NodeItem("GeometryNodeMeshUVSphere"),
]),
GeometryNodeCategory("GEO_POINT", "Point", items=[
NodeItem("GeometryNodePointDistribute"),
@@ -543,6 +532,20 @@ geometry_node_categories = [
NodeItem("GeometryNodeRotatePoints"),
NodeItem("GeometryNodeAlignRotationToVector"),
]),
GeometryNodeCategory("GEO_VOLUME", "Volume", items=[
NodeItem("GeometryNodePointsToVolume"),
NodeItem("GeometryNodeVolumeToMesh"),
]),
GeometryNodeCategory("GEO_PRIMITIVES", "Mesh Primitives", items=[
NodeItem("GeometryNodeMeshCube"),
NodeItem("GeometryNodeMeshCircle"),
NodeItem("GeometryNodeMeshUVSphere"),
NodeItem("GeometryNodeMeshIcoSphere"),
NodeItem("GeometryNodeMeshCylinder"),
NodeItem("GeometryNodeMeshCone"),
NodeItem("GeometryNodeMeshLine"),
NodeItem("GeometryNodeMeshPlane"),
]),
GeometryNodeCategory("GEO_UTILITIES", "Utilities", items=[
NodeItem("ShaderNodeMapRange"),
NodeItem("ShaderNodeClamp"),
@@ -556,10 +559,6 @@ geometry_node_categories = [
NodeItem("ShaderNodeVectorMath"),
NodeItem("ShaderNodeVectorRotate"),
]),
GeometryNodeCategory("GEO_VOLUME", "Volume", items=[
NodeItem("GeometryNodePointsToVolume"),
NodeItem("GeometryNodeVolumeToMesh"),
]),
GeometryNodeCategory("GEO_GROUP", "Group", items=node_group_items),
GeometryNodeCategory("GEO_LAYOUT", "Layout", items=[
NodeItem("NodeFrame"),

View File

@@ -1,10 +0,0 @@
shader basic_shader(
float in_float = 1.0,
color in_color = color(1.0, 1.0, 1.0),
output float out_float = 0.0,
output color out_color = color(0.0, 0.0, 0.0)
)
{
out_float = in_float * 2.0;
out_color = in_color * 2.0;
}

View File

@@ -1,35 +0,0 @@
# This sample shows the an efficient way of doing image processing
# over Blender's images using Python.
import bpy
import numpy as np
input_image_name = "Image"
output_image_name = "NewImage"
# Retrieve input image.
input_image = bpy.data.images[input_image_name]
w, h = input_image.size
# Allocate a numpy array to manipulate pixel data.
pixel_data = np.zeros((w, h, 4), 'f')
# Fast copy of pixel data from bpy.data to numpy array.
input_image.pixels.foreach_get(pixel_data.ravel())
# Do whatever image processing you want using numpy here:
# Example 1: Inverse red green and blue channels.
pixel_data[:,:,:3] = 1.0 - pixel_data[:,:,:3]
# Example 2: Change gamma on the red channel.
pixel_data[:,:,0] = np.power(pixel_data[:,:,0], 1.5)
# Create output image.
if output_image_name in bpy.data.images:
output_image = bpy.data.images[output_image_name]
else:
output_image = bpy.data.images.new(output_image_name, width=w, height=h)
# Copy of pixel data from numpy array back to the output image.
output_image.pixels.foreach_set(pixel_data.ravel())
output_image.update()

View File

@@ -31,7 +31,6 @@ set(SRC
string(APPEND CMAKE_SHARED_LINKER_FLAGS_DEBUG " /nodefaultlib:MSVCRT.lib")
add_library(BlendThumb SHARED ${SRC})
setup_platform_linker_flags(BlendThumb)
target_link_libraries(BlendThumb ${ZLIB_LIBRARIES})
install(

View File

@@ -188,6 +188,10 @@ void BKE_pose_itasc_init(struct bItasc *itasc);
/* Checks if a bone is part of an IK chain or not */
bool BKE_pose_channel_in_IK_chain(struct Object *ob, struct bPoseChannel *pchan);
/* clears BONE_UNKEYED flags for frame changing */
// XXX to be deprecated for a more general solution in animsys...
void framechange_poses_clear_unkeyed(struct Main *bmain);
/* Bone Groups API --------------------- */
/* Adds a new bone-group */
@@ -223,9 +227,6 @@ void BKE_pose_blend_read_data(struct BlendDataReader *reader, struct bPose *pose
void BKE_pose_blend_read_lib(struct BlendLibReader *reader, struct Object *ob, struct bPose *pose);
void BKE_pose_blend_read_expand(struct BlendExpander *expander, struct bPose *pose);
/* action_mirror.c */
void BKE_action_flip_with_pose(struct bAction *act, struct Object *ob_arm);
#ifdef __cplusplus
};
#endif

View File

@@ -342,8 +342,6 @@ void BKE_pchan_bbone_deform_segment_index(const struct bPoseChannel *pchan,
#define PBONE_SELECTABLE(arm, bone) \
(PBONE_VISIBLE(arm, bone) && !((bone)->flag & BONE_UNSELECTABLE))
#define PBONE_SELECTED(arm, bone) (((bone)->flag & BONE_SELECTED) & PBONE_VISIBLE(arm, bone))
/* context.selected_pose_bones */
#define FOREACH_PCHAN_SELECTED_IN_OBJECT_BEGIN(_ob, _pchan) \
for (bPoseChannel *_pchan = (_ob)->pose->chanbase.first; _pchan; _pchan = _pchan->next) { \

View File

@@ -39,12 +39,12 @@ struct ReportList;
/* Attribute.domain */
typedef enum AttributeDomain {
ATTR_DOMAIN_AUTO = -1, /* Use for nodes to choose automatically based on other data. */
ATTR_DOMAIN_POINT = 0, /* Mesh, Hair or PointCloud Point */
ATTR_DOMAIN_EDGE = 1, /* Mesh Edge */
ATTR_DOMAIN_CORNER = 2, /* Mesh Corner */
ATTR_DOMAIN_FACE = 3, /* Mesh Face */
ATTR_DOMAIN_CURVE = 4, /* Hair Curve */
ATTR_DOMAIN_AUTO = -1, /* Use for nodes to choose automatically based on other data. */
ATTR_DOMAIN_POINT = 0, /* Mesh, Hair or PointCloud Point */
ATTR_DOMAIN_EDGE = 1, /* Mesh Edge */
ATTR_DOMAIN_CORNER = 2, /* Mesh Corner */
ATTR_DOMAIN_POLYGON = 3, /* Mesh Polygon */
ATTR_DOMAIN_CURVE = 4, /* Hair Curve */
ATTR_DOMAIN_NUM
} AttributeDomain;

View File

@@ -39,7 +39,7 @@ extern "C" {
/* Blender file format version. */
#define BLENDER_FILE_VERSION BLENDER_VERSION
#define BLENDER_FILE_SUBVERSION 15
#define BLENDER_FILE_SUBVERSION 14
/* Minimum Blender version that supports reading file written with the current
* version. Older Blender versions will test this and show a warning if the file

View File

@@ -108,7 +108,7 @@ void BKE_curve_transform(struct Curve *cu,
const bool do_props);
void BKE_curve_translate(struct Curve *cu, const float offset[3], const bool do_keys);
void BKE_curve_material_index_remove(struct Curve *cu, int index);
bool BKE_curve_material_index_used(const struct Curve *cu, int index);
bool BKE_curve_material_index_used(struct Curve *cu, int index);
void BKE_curve_material_index_clear(struct Curve *cu);
bool BKE_curve_material_index_validate(struct Curve *cu);
void BKE_curve_material_remap(struct Curve *cu, const unsigned int *remap, unsigned int remap_len);
@@ -125,10 +125,8 @@ void BKE_curve_nurb_vert_active_set(struct Curve *cu, const struct Nurb *nu, con
bool BKE_curve_nurb_vert_active_get(struct Curve *cu, struct Nurb **r_nu, void **r_vert);
void BKE_curve_nurb_vert_active_validate(struct Curve *cu);
float (*BKE_curve_nurbs_vert_coords_alloc(const struct ListBase *lb, int *r_vert_len))[3];
void BKE_curve_nurbs_vert_coords_get(const struct ListBase *lb,
float (*vert_coords)[3],
int vert_len);
float (*BKE_curve_nurbs_vert_coords_alloc(struct ListBase *lb, int *r_vert_len))[3];
void BKE_curve_nurbs_vert_coords_get(struct ListBase *lb, float (*vert_coords)[3], int vert_len);
void BKE_curve_nurbs_vert_coords_apply_with_mat4(struct ListBase *lb,
const float (*vert_coords)[3],
@@ -139,7 +137,7 @@ void BKE_curve_nurbs_vert_coords_apply(struct ListBase *lb,
const float (*vert_coords)[3],
const bool constrain_2d);
float (*BKE_curve_nurbs_key_vert_coords_alloc(const struct ListBase *lb,
float (*BKE_curve_nurbs_key_vert_coords_alloc(struct ListBase *lb,
float *key,
int *r_vert_len))[3];
void BKE_curve_nurbs_key_vert_tilts_apply(struct ListBase *lb, const float *key);
@@ -168,8 +166,8 @@ void BKE_curve_correct_bezpart(const float v1[2], float v2[2], float v3[2], cons
bool BKE_nurbList_index_get_co(struct ListBase *editnurb, const int index, float r_co[3]);
int BKE_nurbList_verts_count(const struct ListBase *nurb);
int BKE_nurbList_verts_count_without_handles(const struct ListBase *nurb);
int BKE_nurbList_verts_count(struct ListBase *nurb);
int BKE_nurbList_verts_count_without_handles(struct ListBase *nurb);
void BKE_nurbList_free(struct ListBase *lb);
void BKE_nurbList_duplicate(struct ListBase *lb1, const struct ListBase *lb2);
@@ -187,7 +185,7 @@ struct Nurb *BKE_nurb_duplicate(const struct Nurb *nu);
struct Nurb *BKE_nurb_copy(struct Nurb *src, int pntsu, int pntsv);
void BKE_nurb_test_2d(struct Nurb *nu);
void BKE_nurb_minmax(const struct Nurb *nu, bool use_radius, float min[3], float max[3]);
void BKE_nurb_minmax(struct Nurb *nu, bool use_radius, float min[3], float max[3]);
float BKE_nurb_calc_length(const struct Nurb *nu, int resolution);
void BKE_nurb_makeFaces(

View File

@@ -75,31 +75,33 @@ typedef struct DispList {
int *index;
int charidx;
int totindex; /* indexed array drawing surfaces */
unsigned int *bevel_split; /* BLI_bitmap */
} DispList;
void BKE_displist_copy(struct ListBase *lbn, const struct ListBase *lb);
void BKE_displist_copy(struct ListBase *lbn, struct ListBase *lb);
void BKE_displist_elem_free(DispList *dl);
DispList *BKE_displist_find_or_create(struct ListBase *lb, int type);
DispList *BKE_displist_find(struct ListBase *lb, int type);
void BKE_displist_normals_add(struct ListBase *lb);
void BKE_displist_count(const struct ListBase *lb, int *totvert, int *totface, int *tottri);
void BKE_displist_count(struct ListBase *lb, int *totvert, int *totface, int *tottri);
void BKE_displist_free(struct ListBase *lb);
bool BKE_displist_has_faces(const struct ListBase *lb);
bool BKE_displist_has_faces(struct ListBase *lb);
void BKE_displist_make_surf(struct Depsgraph *depsgraph,
const struct Scene *scene,
struct Scene *scene,
struct Object *ob,
struct ListBase *dispbase,
struct Mesh **r_final,
const bool for_render,
const bool for_orco);
void BKE_displist_make_curveTypes(struct Depsgraph *depsgraph,
const struct Scene *scene,
struct Scene *scene,
struct Object *ob,
const bool for_render,
const bool for_orco);
void BKE_displist_make_curveTypes_forRender(struct Depsgraph *depsgraph,
const struct Scene *scene,
struct Scene *scene,
struct Object *ob,
struct ListBase *dispbase,
struct Mesh **r_final,
@@ -111,26 +113,22 @@ void BKE_displist_make_mball_forRender(struct Depsgraph *depsgraph,
struct ListBase *dispbase);
bool BKE_curve_calc_modifiers_pre(struct Depsgraph *depsgraph,
const struct Scene *scene,
struct Scene *scene,
struct Object *ob,
struct ListBase *source_nurb,
struct ListBase *target_nurb,
const bool for_render);
bool BKE_displist_surfindex_get(
const struct DispList *dl, int a, int *b, int *p1, int *p2, int *p3, int *p4);
bool BKE_displist_surfindex_get(DispList *dl, int a, int *b, int *p1, int *p2, int *p3, int *p4);
void BKE_displist_fill(const struct ListBase *dispbase,
struct ListBase *to,
const float normal_proj[3],
const bool flip_normal);
float BKE_displist_calc_taper(struct Depsgraph *depsgraph,
const struct Scene *scene,
struct Object *taperobj,
int cur,
int tot);
float BKE_displist_calc_taper(
struct Depsgraph *depsgraph, struct Scene *scene, struct Object *taperobj, int cur, int tot);
void BKE_displist_minmax(const struct ListBase *dispbase, float min[3], float max[3]);
void BKE_displist_minmax(struct ListBase *dispbase, float min[3], float max[3]);
#ifdef __cplusplus
}

View File

@@ -232,19 +232,6 @@ int BKE_fcurve_bezt_binarysearch_index(struct BezTriple array[],
int arraylen,
bool *r_replace);
/* fcurve_cache.c */
/* Cached f-curve look-ups, use when this needs to be done many times. */
struct FCurvePathCache;
struct FCurvePathCache *BKE_fcurve_pathcache_create(ListBase *list);
void BKE_fcurve_pathcache_destroy(struct FCurvePathCache *fcache);
struct FCurve *BKE_fcurve_pathcache_find(struct FCurvePathCache *fcache,
const char rna_path[],
const int array_index);
int BKE_fcurve_pathcache_find_array(struct FCurvePathCache *fcache,
const char *rna_path,
struct FCurve **fcurve_result,
int fcurve_result_len);
/* get the time extents for F-Curve */
bool BKE_fcurve_calc_range(
struct FCurve *fcu, float *min, float *max, const bool do_sel_only, const bool do_min_length);
@@ -258,14 +245,6 @@ bool BKE_fcurve_calc_bounds(struct FCurve *fcu,
const bool do_sel_only,
const bool include_handles);
float *BKE_fcurves_calc_keyed_frames_ex(struct FCurve **fcurve_array,
const int fcurve_array_len,
const float interval,
int *r_frames_len);
float *BKE_fcurves_calc_keyed_frames(struct FCurve **fcurve_array,
const int fcurve_array_len,
int *r_frames_len);
void BKE_fcurve_active_keyframe_set(struct FCurve *fcu, const struct BezTriple *active_bezt);
int BKE_fcurve_active_keyframe_index(const struct FCurve *fcu);

View File

@@ -141,12 +141,6 @@ class GeometryComponent {
/* The returned component should be of the same type as the type this is called on. */
virtual GeometryComponent *copy() const = 0;
/* Direct data is everything except for instances of objects/collections.
* If this returns true, the geometry set can be cached and is still valid after e.g. modifier
* evaluation ends. Instances can only be valid as long as the data they instance is valid. */
virtual bool owns_direct_data() const = 0;
virtual void ensure_owns_direct_data() = 0;
void user_add() const;
void user_remove() const;
bool is_mutable() const;
@@ -319,10 +313,6 @@ struct GeometrySet {
friend bool operator==(const GeometrySet &a, const GeometrySet &b);
uint64_t hash() const;
void clear();
void ensure_owns_direct_data();
/* Utility methods for creation. */
static GeometrySet create_with_mesh(
Mesh *mesh, GeometryOwnershipType ownership = GeometryOwnershipType::Owned);
@@ -382,9 +372,6 @@ class MeshComponent : public GeometryComponent {
bool is_empty() const final;
bool owns_direct_data() const override;
void ensure_owns_direct_data() override;
static constexpr inline GeometryComponentType static_type = GEO_COMPONENT_TYPE_MESH;
private:
@@ -415,9 +402,6 @@ class PointCloudComponent : public GeometryComponent {
bool is_empty() const final;
bool owns_direct_data() const override;
void ensure_owns_direct_data() override;
static constexpr inline GeometryComponentType static_type = GEO_COMPONENT_TYPE_POINT_CLOUD;
private:
@@ -458,9 +442,6 @@ class InstancesComponent : public GeometryComponent {
bool is_empty() const final;
bool owns_direct_data() const override;
void ensure_owns_direct_data() override;
static constexpr inline GeometryComponentType static_type = GEO_COMPONENT_TYPE_INSTANCES;
};
@@ -483,8 +464,5 @@ class VolumeComponent : public GeometryComponent {
const Volume *get_for_read() const;
Volume *get_for_write();
bool owns_direct_data() const override;
void ensure_owns_direct_data() override;
static constexpr inline GeometryComponentType static_type = GEO_COMPONENT_TYPE_VOLUME;
};

View File

@@ -39,8 +39,7 @@ struct GeometryInstanceGroup {
Vector<float4x4> transforms;
};
void geometry_set_gather_instances(const GeometrySet &geometry_set,
Vector<GeometryInstanceGroup> &r_instance_groups);
Vector<GeometryInstanceGroup> geometry_set_gather_instances(const GeometrySet &geometry_set);
GeometrySet geometry_set_realize_mesh_for_modifier(const GeometrySet &geometry_set);
GeometrySet geometry_set_realize_instances(const GeometrySet &geometry_set);

View File

@@ -74,7 +74,6 @@ bool BKE_lib_override_library_create(struct Main *bmain,
struct ViewLayer *view_layer,
struct ID *id_root,
struct ID *id_reference);
bool BKE_lib_override_library_template_create(struct ID *id);
bool BKE_lib_override_library_proxy_convert(struct Main *bmain,
struct Scene *scene,
struct ViewLayer *view_layer,

View File

@@ -483,14 +483,14 @@ void ntreeBlendReadExpand(struct BlendExpander *expander, struct bNodeTree *ntre
/** \name Node Tree Interface
* \{ */
struct bNodeSocket *ntreeFindSocketInterface(struct bNodeTree *ntree,
eNodeSocketInOut in_out,
int in_out,
const char *identifier);
struct bNodeSocket *ntreeAddSocketInterface(struct bNodeTree *ntree,
eNodeSocketInOut in_out,
int in_out,
const char *idname,
const char *name);
struct bNodeSocket *ntreeInsertSocketInterface(struct bNodeTree *ntree,
eNodeSocketInOut in_out,
int in_out,
const char *idname,
struct bNodeSocket *next_sock,
const char *name);
@@ -556,32 +556,30 @@ const char *nodeStaticSocketInterfaceType(int type, int subtype);
} \
((void)0)
struct bNodeSocket *nodeFindSocket(const struct bNode *node,
eNodeSocketInOut in_out,
const char *identifier);
struct bNodeSocket *nodeFindSocket(const struct bNode *node, int in_out, const char *identifier);
struct bNodeSocket *nodeAddSocket(struct bNodeTree *ntree,
struct bNode *node,
eNodeSocketInOut in_out,
int in_out,
const char *idname,
const char *identifier,
const char *name);
struct bNodeSocket *nodeInsertSocket(struct bNodeTree *ntree,
struct bNode *node,
eNodeSocketInOut in_out,
int in_out,
const char *idname,
struct bNodeSocket *next_sock,
const char *identifier,
const char *name);
struct bNodeSocket *nodeAddStaticSocket(struct bNodeTree *ntree,
struct bNode *node,
eNodeSocketInOut in_out,
int in_out,
int type,
int subtype,
const char *identifier,
const char *name);
struct bNodeSocket *nodeInsertStaticSocket(struct bNodeTree *ntree,
struct bNode *node,
eNodeSocketInOut in_out,
int in_out,
int type,
int subtype,
struct bNodeSocket *next_sock,
@@ -1190,7 +1188,6 @@ void ntreeGPUMaterialNodes(struct bNodeTree *localtree,
#define CMP_NODE_TRACKPOS 271
#define CMP_NODE_INPAINT 272
#define CMP_NODE_DESPECKLE 273
#define CMP_NODE_ANTIALIASING 274
#define CMP_NODE_GLARE 301
#define CMP_NODE_TONEMAP 302
@@ -1396,9 +1393,7 @@ int ntreeTexExecTree(struct bNodeTree *ntree,
#define GEO_NODE_MESH_PRIMITIVE_ICO_SPHERE 1036
#define GEO_NODE_MESH_PRIMITIVE_CONE 1037
#define GEO_NODE_MESH_PRIMITIVE_LINE 1038
#define GEO_NODE_MESH_PRIMITIVE_GRID 1039
#define GEO_NODE_ATTRIBUTE_MAP_RANGE 1040
#define GEO_NODE_ATTRIBUTE_CLAMP 1041
#define GEO_NODE_MESH_PRIMITIVE_PLANE 1039
/** \} */

View File

@@ -58,7 +58,9 @@ class NodeTreeEvaluationContext {
uint64_t hash() const
{
return blender::get_default_hash_2(object_name_, modifier_session_uuid_);
const uint64_t hash1 = blender::DefaultHash<std::string>{}(object_name_);
const uint64_t hash2 = BLI_session_uuid_hash_uint64(&modifier_session_uuid_);
return hash1 ^ (hash2 * 33); /* Copied from DefaultHash for std::pair. */
}
friend bool operator==(const NodeTreeEvaluationContext &a, const NodeTreeEvaluationContext &b)

View File

@@ -34,7 +34,6 @@ struct Base;
struct BoundBox;
struct Curve;
struct Depsgraph;
struct GeometrySet;
struct GpencilModifierData;
struct HookGpencilModifierData;
struct HookModifierData;
@@ -70,8 +69,6 @@ void BKE_object_free_curve_cache(struct Object *ob);
void BKE_object_free_derived_caches(struct Object *ob);
void BKE_object_free_caches(struct Object *object);
void BKE_object_preview_geometry_set(struct Object *ob, struct GeometrySet *geometry_set);
void BKE_object_modifier_hook_reset(struct Object *ob, struct HookModifierData *hmd);
void BKE_object_modifier_gpencil_hook_reset(struct Object *ob,
struct HookGpencilModifierData *hmd);
@@ -339,12 +336,6 @@ struct Mesh *BKE_object_get_evaluated_mesh(struct Object *object);
struct Mesh *BKE_object_get_pre_modified_mesh(struct Object *object);
struct Mesh *BKE_object_get_original_mesh(struct Object *object);
/* Lattice accessors.
* These functions return either the regular lattice, or the edit-mode lattice,
* whichever is currently in use. */
struct Lattice *BKE_object_get_lattice(const struct Object *object);
struct Lattice *BKE_object_get_evaluated_lattice(const struct Object *object);
int BKE_object_insert_ptcache(struct Object *ob);
void BKE_object_delete_ptcache(struct Object *ob, int index);
struct KeyBlock *BKE_object_shapekey_insert(struct Main *bmain,

View File

@@ -69,7 +69,6 @@ set(SRC
intern/CCGSubSurf_util.c
intern/DerivedMesh.cc
intern/action.c
intern/action_mirror.c
intern/addon.c
intern/anim_data.c
intern/anim_path.c
@@ -127,7 +126,6 @@ set(SRC
intern/editmesh_tangent.c
intern/effect.c
intern/fcurve.c
intern/fcurve_cache.c
intern/fcurve_driver.c
intern/fluid.c
intern/fmodifier.c
@@ -387,7 +385,6 @@ set(SRC
BKE_multires.h
BKE_nla.h
BKE_node.h
BKE_node_ui_storage.hh
BKE_object.h
BKE_object_deform.h
BKE_object_facemap.h
@@ -437,10 +434,10 @@ set(SRC
nla_private.h
particle_private.h
tracking_private.h
intern/attribute_access_intern.hh
intern/CCGSubSurf.h
intern/CCGSubSurf_inline.h
intern/CCGSubSurf_intern.h
intern/attribute_access_intern.hh
intern/data_transfer_intern.h
intern/lib_intern.h
intern/multires_inline.h
@@ -745,7 +742,7 @@ if(WITH_GMP)
list(APPEND INC_SYS
${GMP_INCLUDE_DIRS}
)
endif()
endif()
# # Warnings as errors, this is too strict!
# if(MSVC)

View File

@@ -1316,6 +1316,30 @@ void BKE_pose_tag_update_constraint_flags(bPose *pose)
pose->flag |= POSE_CONSTRAINTS_NEED_UPDATE_FLAGS;
}
/* Clears all BONE_UNKEYED flags for every pose channel in every pose
* This should only be called on frame changing, when it is acceptable to
* do this. Otherwise, these flags should not get cleared as poses may get lost.
*/
void framechange_poses_clear_unkeyed(Main *bmain)
{
Object *ob;
bPose *pose;
bPoseChannel *pchan;
/* This needs to be done for each object that has a pose */
/* TODO: proxies may/may not be correctly handled here... (this needs checking) */
for (ob = bmain->objects.first; ob; ob = ob->id.next) {
/* we only need to do this on objects with a pose */
if ((pose = ob->pose)) {
for (pchan = pose->chanbase.first; pchan; pchan = pchan->next) {
if (pchan->bone) {
pchan->bone->flag &= ~BONE_UNKEYED;
}
}
}
}
}
/* ************************** Bone Groups ************************** */
/* Adds a new bone-group (name may be NULL) */

View File

@@ -1,457 +0,0 @@
/*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
/** \file
* \ingroup bke
*
* Mirror/Symmetry functions applying to actions.
*/
#include <math.h>
#include <string.h>
#include "MEM_guardedalloc.h"
#include "DNA_anim_types.h"
#include "DNA_armature_types.h"
#include "DNA_object_types.h"
#include "BLI_blenlib.h"
#include "BLI_math.h"
#include "BLI_string_utils.h"
#include "BLI_utildefines.h"
#include "BKE_action.h"
#include "BKE_armature.h"
#include "BKE_fcurve.h"
#include "DEG_depsgraph.h"
/* -------------------------------------------------------------------- */
/** \name Flip the Action (Armature/Pose Objects)
*
* This flips the action using the rest pose (not the evaluated pose).
*
* Details:
*
* - Key-frames are modified in-place, creating new key-frames is not yet supported.
* That could be useful if a user for example only has 2x rotation channels set.
* In practice users typically keyframe all rotation channels or none.
*
* - F-curve modifiers are disabled for evaluation,
* so the values written back to the keyframes don't include modifier offsets.
*
* - Sub-frame key-frames aren't supported,
* this could be added if needed without much trouble.
*
* - F-curves must have a #FCurve.bezt array (sampled curves aren't supported).
* \{ */
/**
* This structure is created for each pose channels F-curve,
* an action be evaluated and stored in `fcurve_eval`,
* with the mirrored values written into `bezt_array`.
*
* Store F-curve evaluated values, constructed with a sorted array of rounded keyed-frames,
* passed to #action_flip_pchan_cache_init.
*/
struct FCurve_KeyCache {
/**
* When NULL, ignore this channel.
*/
FCurve *fcurve;
/**
* Cached evaluated F-curve values (without modifiers).
*/
float *fcurve_eval;
/**
* Cached #FCurve.bezt values, NULL when no key-frame exists on this frame.
*
* \note The case where two keyframes round to the same frame isn't supported.
* In this case only the first will be used.
*/
BezTriple **bezt_array;
};
/**
* Assign `fkc` path, using a `path` lookup for a single value.
*/
static void action_flip_pchan_cache_fcurve_assign_value(struct FCurve_KeyCache *fkc,
int index,
const char *path,
struct FCurvePathCache *fcache)
{
FCurve *fcu = BKE_fcurve_pathcache_find(fcache, path, index);
if (fcu && fcu->bezt) {
fkc->fcurve = fcu;
}
}
/**
* Assign #FCurve_KeyCache.fcurve path, using a `path` lookup for an array.
*/
static void action_flip_pchan_cache_fcurve_assign_array(struct FCurve_KeyCache *fkc,
int fkc_len,
const char *path,
struct FCurvePathCache *fcache)
{
FCurve **fcurves = alloca(sizeof(*fcurves) * fkc_len);
if (BKE_fcurve_pathcache_find_array(fcache, path, fcurves, fkc_len)) {
for (int i = 0; i < fkc_len; i++) {
if (fcurves[i] && fcurves[i]->bezt) {
fkc[i].fcurve = fcurves[i];
}
}
}
}
/**
* Fill in pose channel cache for each frame in `keyed_frames`.
*
* \param keyed_frames: An array of keyed_frames to evaluate,
* note that each frame is rounded to the nearest int.
* \param keyed_frames_len: The length of the `keyed_frames` array.
*/
static void action_flip_pchan_cache_init(struct FCurve_KeyCache *fkc,
const float *keyed_frames,
int keyed_frames_len)
{
BLI_assert(fkc->fcurve != NULL);
/* Cache the F-curve values for `keyed_frames`. */
const int fcurve_flag = fkc->fcurve->flag;
fkc->fcurve->flag |= FCURVE_MOD_OFF;
fkc->fcurve_eval = MEM_mallocN(sizeof(float) * keyed_frames_len, __func__);
for (int frame_index = 0; frame_index < keyed_frames_len; frame_index++) {
const float evaltime = keyed_frames[frame_index];
fkc->fcurve_eval[frame_index] = evaluate_fcurve_only_curve(fkc->fcurve, evaltime);
}
fkc->fcurve->flag = fcurve_flag;
/* Cache the #BezTriple for `keyed_frames`, or leave as NULL. */
fkc->bezt_array = MEM_mallocN(sizeof(*fkc->bezt_array) * keyed_frames_len, __func__);
BezTriple *bezt = fkc->fcurve->bezt;
BezTriple *bezt_end = fkc->fcurve->bezt + fkc->fcurve->totvert;
int frame_index = 0;
while (frame_index < keyed_frames_len) {
const float evaltime = keyed_frames[frame_index];
const float bezt_time = roundf(bezt->vec[1][0]);
if (bezt_time > evaltime) {
fkc->bezt_array[frame_index++] = NULL;
}
else {
if (bezt_time == evaltime) {
fkc->bezt_array[frame_index++] = bezt;
}
bezt++;
if (bezt == bezt_end) {
break;
}
}
}
/* Clear remaining unset keyed_frames (if-any). */
while (frame_index < keyed_frames_len) {
fkc->bezt_array[frame_index++] = NULL;
}
}
/**
*/
static void action_flip_pchan(Object *ob_arm,
const bPoseChannel *pchan,
struct FCurvePathCache *fcache)
{
/* Begin F-Curve pose channel value extraction. */
/* Use a fixed buffer size as it's known this can only be at most:
* `pose.bones["{MAXBONENAME}"].rotation_quaternion`. */
char path_xform[256];
char pchan_name_esc[sizeof(((bActionChannel *)NULL)->name) * 2];
BLI_str_escape(pchan_name_esc, pchan->name, sizeof(pchan_name_esc));
const int path_xform_prefix_len = SNPRINTF(path_xform, "pose.bones[\"%s\"]", pchan_name_esc);
char *path_xform_suffix = path_xform + path_xform_prefix_len;
const int path_xform_suffix_len = sizeof(path_xform) - path_xform_prefix_len;
/* Lookup and assign all available #FCurve channels,
* unavailable channels are left NULL. */
/**
* Structure to store transformation F-curves corresponding to a pose bones transformation.
* Match struct member names from #bPoseChannel so macros avoid repetition.
*
* \note There is no need to read values unless they influence the 4x4 transform matrix,
* and no need to write values back unless they would be changed by a modified matrix.
* So `rotmode` needs to be read, but doesn't need to be written back to.
*
* Most bendy-bone settings don't need to be included either, flipping their RNA paths is enough.
* Although the X/Y settings could make sense to transform, in practice it would only
* work well if the rotation happened to swap X/Y alignment, leave this for now.
*/
struct {
struct FCurve_KeyCache loc[3], eul[3], quat[4], rotAxis[3], rotAngle, size[3], rotmode;
} fkc_pchan = {{{NULL}}};
#define FCURVE_ASSIGN_VALUE(id, path_test_suffix, index) \
BLI_strncpy(path_xform_suffix, path_test_suffix, path_xform_suffix_len); \
action_flip_pchan_cache_fcurve_assign_value(&fkc_pchan.id, index, path_xform, fcache)
#define FCURVE_ASSIGN_ARRAY(id, path_test_suffix) \
BLI_strncpy(path_xform_suffix, path_test_suffix, path_xform_suffix_len); \
action_flip_pchan_cache_fcurve_assign_array( \
fkc_pchan.id, ARRAY_SIZE(fkc_pchan.id), path_xform, fcache)
FCURVE_ASSIGN_ARRAY(loc, ".location");
FCURVE_ASSIGN_ARRAY(eul, ".rotation_euler");
FCURVE_ASSIGN_ARRAY(quat, ".rotation_quaternion");
FCURVE_ASSIGN_ARRAY(rotAxis, ".rotation_axis_angle");
FCURVE_ASSIGN_VALUE(rotAngle, ".rotation_axis_angle", 3);
FCURVE_ASSIGN_ARRAY(size, ".scale");
FCURVE_ASSIGN_VALUE(rotmode, ".rotation_mode", 0);
#undef FCURVE_ASSIGN_VALUE
#undef FCURVE_ASSIGN_ARRAY
/* Array of F-curves, for convenient access. */
#define FCURVE_CHANNEL_LEN (sizeof(fkc_pchan) / sizeof(struct FCurve_KeyCache))
FCurve *fcurve_array[FCURVE_CHANNEL_LEN];
int fcurve_array_len = 0;
for (int chan = 0; chan < FCURVE_CHANNEL_LEN; chan++) {
struct FCurve_KeyCache *fkc = (struct FCurve_KeyCache *)(&fkc_pchan) + chan;
if (fkc->fcurve != NULL) {
fcurve_array[fcurve_array_len++] = fkc->fcurve;
}
}
/* If this pose has no transform channels, there is nothing to do. */
if (fcurve_array_len == 0) {
return;
}
/* Calculate an array of frames used by any of the key-frames in `fcurve_array`. */
int keyed_frames_len;
const float *keyed_frames = BKE_fcurves_calc_keyed_frames(
fcurve_array, fcurve_array_len, &keyed_frames_len);
/* Initialize the pose channel curve cache from the F-curve. */
for (int chan = 0; chan < FCURVE_CHANNEL_LEN; chan++) {
struct FCurve_KeyCache *fkc = (struct FCurve_KeyCache *)(&fkc_pchan) + chan;
if (fkc->fcurve == NULL) {
continue;
}
action_flip_pchan_cache_init(fkc, keyed_frames, keyed_frames_len);
}
/* X-axis flipping matrix. */
float flip_mtx[4][4];
unit_m4(flip_mtx);
flip_mtx[0][0] = -1;
bPoseChannel *pchan_flip = NULL;
char pchan_name_flip[MAXBONENAME];
BLI_string_flip_side_name(pchan_name_flip, pchan->name, false, sizeof(pchan_name_flip));
if (!STREQ(pchan_name_flip, pchan->name)) {
pchan_flip = BKE_pose_channel_find_name(ob_arm->pose, pchan_name_flip);
}
float arm_mat_inv[4][4];
invert_m4_m4(arm_mat_inv, pchan_flip ? pchan_flip->bone->arm_mat : pchan->bone->arm_mat);
/* Now flip the transformation & write it back to the F-curves in `fkc_pchan`. */
for (int frame_index = 0; frame_index < keyed_frames_len; frame_index++) {
/* Temporary pose channel to write values into,
* using the `fkc_pchan` values, falling back to the values in the pose channel. */
bPoseChannel pchan_temp = *pchan;
/* Load the values into the channel. */
#define READ_VALUE_FLT(id) \
if (fkc_pchan.id.fcurve_eval != NULL) { \
pchan_temp.id = fkc_pchan.id.fcurve_eval[frame_index]; \
} \
((void)0)
#define READ_VALUE_INT(id) \
if (fkc_pchan.id.fcurve_eval != NULL) { \
pchan_temp.id = floorf(fkc_pchan.id.fcurve_eval[frame_index] + 0.5f); \
} \
((void)0)
#define READ_ARRAY_FLT(id) \
for (int i = 0; i < ARRAY_SIZE(pchan_temp.id); i++) { \
READ_VALUE_FLT(id[i]); \
} \
((void)0)
READ_ARRAY_FLT(loc);
READ_ARRAY_FLT(eul);
READ_ARRAY_FLT(quat);
READ_ARRAY_FLT(rotAxis);
READ_VALUE_FLT(rotAngle);
READ_ARRAY_FLT(size);
READ_VALUE_INT(rotmode);
#undef READ_ARRAY_FLT
#undef READ_VALUE_FLT
#undef READ_VALUE_INT
float chan_mat[4][4];
BKE_pchan_to_mat4(&pchan_temp, chan_mat);
/* Move to the pose-space. */
mul_m4_m4m4(chan_mat, pchan->bone->arm_mat, chan_mat);
/* Flip the matrix. */
mul_m4_m4m4(chan_mat, chan_mat, flip_mtx);
mul_m4_m4m4(chan_mat, flip_mtx, chan_mat);
/* Move back to bone-space space, using the flipped bone if it exists. */
mul_m4_m4m4(chan_mat, arm_mat_inv, chan_mat);
BKE_pchan_apply_mat4(&pchan_temp, chan_mat, false);
/* Write the values back to the F-curves. */
#define WRITE_VALUE_FLT(id) \
if (fkc_pchan.id.fcurve_eval != NULL) { \
BezTriple *bezt = fkc_pchan.id.bezt_array[frame_index]; \
if (bezt != NULL) { \
const float delta = pchan_temp.id - bezt->vec[1][1]; \
bezt->vec[0][1] += delta; \
bezt->vec[1][1] += delta; \
bezt->vec[2][1] += delta; \
} \
} \
((void)0)
#define WRITE_ARRAY_FLT(id) \
for (int i = 0; i < ARRAY_SIZE(pchan_temp.id); i++) { \
WRITE_VALUE_FLT(id[i]); \
} \
((void)0)
/* Write the values back the the F-curves. */
WRITE_ARRAY_FLT(loc);
WRITE_ARRAY_FLT(eul);
WRITE_ARRAY_FLT(quat);
WRITE_ARRAY_FLT(rotAxis);
WRITE_VALUE_FLT(rotAngle);
WRITE_ARRAY_FLT(size);
/* No need to write back 'rotmode' as it can't be transformed. */
#undef WRITE_ARRAY_FLT
#undef WRITE_VALUE_FLT
}
/* Recalculate handles. */
for (int i = 0; i < fcurve_array_len; i++) {
calchandles_fcurve_ex(fcurve_array[i], 0);
}
MEM_freeN((void *)keyed_frames);
for (int chan = 0; chan < FCURVE_CHANNEL_LEN; chan++) {
struct FCurve_KeyCache *fkc = (struct FCurve_KeyCache *)(&fkc_pchan) + chan;
if (fkc->fcurve_eval) {
MEM_freeN(fkc->fcurve_eval);
}
if (fkc->bezt_array) {
MEM_freeN(fkc->bezt_array);
}
}
}
/**
* Swap all RNA paths left/right.
*/
static void action_flip_pchan_rna_paths(struct bAction *act)
{
const char *path_pose_prefix = "pose.bones[\"";
const int path_pose_prefix_len = strlen(path_pose_prefix);
/* Tag curves that have renamed f-curves. */
LISTBASE_FOREACH (bActionGroup *, agrp, &act->groups) {
agrp->flag &= ~AGRP_TEMP;
}
LISTBASE_FOREACH (FCurve *, fcu, &act->curves) {
if (!STRPREFIX(fcu->rna_path, path_pose_prefix)) {
continue;
}
const char *name_esc = fcu->rna_path + path_pose_prefix_len;
const char *name_esc_end = BLI_str_escape_find_quote(name_esc);
/* While unlikely, an RNA path could be malformed. */
if (UNLIKELY(name_esc_end == NULL)) {
continue;
}
char name[MAXBONENAME];
const size_t name_esc_len = (size_t)(name_esc_end - name_esc);
const size_t name_len = BLI_str_unescape(name, name_esc, name_esc_len);
/* While unlikely, data paths could be constructed that have longer names than
* are currently supported. */
if (UNLIKELY(name_len >= sizeof(name))) {
continue;
}
/* When the flipped name differs, perform the rename. */
char name_flip[MAXBONENAME];
BLI_string_flip_side_name(name_flip, name, false, sizeof(name_flip));
if (!STREQ(name_flip, name)) {
char name_flip_esc[MAXBONENAME * 2];
BLI_str_escape(name_flip_esc, name_flip, sizeof(name_flip_esc));
char *path_flip = BLI_sprintfN("pose.bones[\"%s%s", name_flip_esc, name_esc_end);
MEM_freeN(fcu->rna_path);
fcu->rna_path = path_flip;
if (fcu->grp != NULL) {
fcu->grp->flag |= AGRP_TEMP;
}
}
}
/* Rename tagged groups. */
LISTBASE_FOREACH (bActionGroup *, agrp, &act->groups) {
if ((agrp->flag & AGRP_TEMP) == 0) {
continue;
}
agrp->flag &= ~AGRP_TEMP;
char name_flip[MAXBONENAME];
BLI_string_flip_side_name(name_flip, agrp->name, false, sizeof(name_flip));
if (!STREQ(name_flip, agrp->name)) {
STRNCPY(agrp->name, name_flip);
}
}
}
void BKE_action_flip_with_pose(struct bAction *act, struct Object *ob_arm)
{
struct FCurvePathCache *fcache = BKE_fcurve_pathcache_create(&act->curves);
int i;
LISTBASE_FOREACH_INDEX (bPoseChannel *, pchan, &ob_arm->pose->chanbase, i) {
action_flip_pchan(ob_arm, pchan, fcache);
}
BKE_fcurve_pathcache_destroy(fcache);
action_flip_pchan_rna_paths(act);
DEG_id_tag_update(&act->id, ID_RECALC_COPY_ON_WRITE);
}
/** \} */

Some files were not shown because too many files have changed in this diff Show More