diff options
763 files changed, 19545 insertions, 5342 deletions
diff --git a/.clang-format b/.clang-format index 79aa893cada..9f3e37dea56 100644 --- a/.clang-format +++ b/.clang-format @@ -255,7 +255,6 @@ 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 diff --git a/.clang-tidy b/.clang-tidy index 98fa36db790..23a541eefd1 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -43,7 +43,6 @@ Checks: > # the windows compiler currently. -modernize-raw-string-literal -WarningsAsErrors: '*' CheckOptions: - key: modernize-use-default-member-init.UseAssignment value: 1 diff --git a/.gitignore b/.gitignore index b1f351255b7..96b70c2be70 100644 --- a/.gitignore +++ b/.gitignore @@ -46,3 +46,6 @@ Desktop.ini # smoke simulation noise tile (generated) waveletNoiseTile.bin + +# testing environment +/Testing diff --git a/CMakeLists.txt b/CMakeLists.txt index 2743d2d334c..ba863cf32b6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -236,9 +236,7 @@ option(WITH_SYSTEM_AUDASPACE "Build with external audaspace library installed on mark_as_advanced(WITH_AUDASPACE) mark_as_advanced(WITH_SYSTEM_AUDASPACE) -if(NOT WITH_AUDASPACE) - set(WITH_SYSTEM_AUDASPACE OFF) -endif() +set_and_warn_dependency(WITH_AUDASPACE WITH_SYSTEM_AUDASPACE OFF) option(WITH_OPENMP "Enable OpenMP (has to be supported by the compiler)" ON) if(UNIX AND NOT APPLE) @@ -522,10 +520,10 @@ if(CMAKE_COMPILER_IS_GNUCC) mark_as_advanced(WITH_LINKER_LLD) endif() -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) +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") if(WITH_COMPILER_ASAN) set(_asan_defaults "\ -fsanitize=address \ @@ -704,10 +702,8 @@ if(WITH_PYTHON_MODULE AND WITH_PYTHON_INSTALL) message(FATAL_ERROR "WITH_PYTHON_MODULE requires WITH_PYTHON_INSTALL to be OFF") endif() -if(NOT WITH_PYTHON) - set(WITH_CYCLES OFF) - set(WITH_DRACO OFF) -endif() +set_and_warn_dependency(WITH_PYTHON WITH_CYCLES OFF) +set_and_warn_dependency(WITH_PYTHON WITH_DRACO OFF) if(WITH_DRACO AND NOT WITH_PYTHON_INSTALL) message(STATUS "WITH_DRACO requires WITH_PYTHON_INSTALL to be ON, disabling WITH_DRACO for now") @@ -779,6 +775,7 @@ 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) @@ -809,7 +806,7 @@ endif() if(NOT WITH_CUDA_DYNLOAD) find_package(CUDA) if(NOT CUDA_FOUND) - message("CUDA toolkit not found, using dynamic runtime loading of libraries instead") + message(STATUS "CUDA toolkit not found, using dynamic runtime loading of libraries (WITH_CUDA_DYNLOAD) instead") set(WITH_CUDA_DYNLOAD ON) endif() endif() @@ -1235,6 +1232,7 @@ 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 @@ -1245,6 +1243,7 @@ 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() @@ -1320,6 +1319,7 @@ 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() diff --git a/GNUmakefile b/GNUmakefile index 3fe1850ca73..3f7804557aa 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -129,7 +129,10 @@ Utilities Create a compressed archive of the source code. * update: - updates git and all submodules + Updates git and all submodules and svn. + + * update_code: + Updates git and all submodules but not svn. * format: Format source code using clang (uses PATHS if passed in). For example:: @@ -522,6 +525,9 @@ 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) diff --git a/build_files/build_environment/cmake/options.cmake b/build_files/build_environment/cmake/options.cmake index 5091a5d9496..15ceb693ae0 100644 --- a/build_files/build_environment/cmake/options.cmake +++ b/build_files/build_environment/cmake/options.cmake @@ -21,7 +21,8 @@ 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) -set(MAKE_THREADS 1 CACHE STRING "Number of threads to run make with") +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") if(NOT BUILD_MODE) set(BUILD_MODE "Release") diff --git a/build_files/cmake/platform/platform_apple.cmake b/build_files/cmake/platform/platform_apple.cmake index 6276032d85c..a5eee46349a 100644 --- a/build_files/cmake/platform/platform_apple.cmake +++ b/build_files/cmake/platform/platform_apple.cmake @@ -56,6 +56,7 @@ 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() @@ -65,6 +66,7 @@ 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) @@ -102,6 +104,7 @@ 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() @@ -146,7 +149,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}/config-${PYTHON_VERSION}") + set(PYTHON_LIBPATH "${_py_framework}/lib/python${PYTHON_VERSION}") # set(PYTHON_LIBRARY python${PYTHON_VERSION}) # set(PYTHON_LINKFLAGS "-u _PyMac_Error -framework Python") # won't build with this enabled @@ -308,7 +311,7 @@ if(WITH_OPENCOLORIO) if(NOT OPENCOLORIO_FOUND) set(WITH_OPENCOLORIO OFF) - message(STATUS "OpenColorIO not found") + message(STATUS "OpenColorIO not found, disabling WITH_OPENCOLORIO") endif() endif() @@ -357,7 +360,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(STATUS "OSL not found") + message(WARNING "OSL not found, disabling WITH_CYCLES_OSL") set(WITH_CYCLES_OSL OFF) endif() endif() @@ -385,7 +388,7 @@ if(WITH_OPENIMAGEDENOISE) if(NOT OPENIMAGEDENOISE_FOUND) set(WITH_OPENIMAGEDENOISE OFF) - message(STATUS "OpenImageDenoise not found") + message(STATUS "OpenImageDenoise not found, disabling WITH_OPENIMAGEDENOISE") endif() endif() @@ -413,7 +416,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 diff --git a/build_files/cmake/platform/platform_win32.cmake b/build_files/cmake/platform/platform_win32.cmake index acd6028e2ae..b6ec016aa95 100644 --- a/build_files/cmake/platform/platform_win32.cmake +++ b/build_files/cmake/platform/platform_win32.cmake @@ -149,11 +149,6 @@ 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") @@ -162,6 +157,21 @@ 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-") @@ -174,14 +184,41 @@ 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) - set(SYMBOL_FORMAT /ZI) + 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") endif() string(APPEND CMAKE_CXX_FLAGS_DEBUG " /MDd ${SYMBOL_FORMAT}") @@ -190,9 +227,11 @@ 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}") -string(APPEND CMAKE_C_FLAGS_RELWITHDEBINFO " /MD ${SYMBOL_FORMAT}") +string(APPEND CMAKE_CXX_FLAGS_RELWITHDEBINFO " /MD ${SYMBOL_FORMAT_RELEASE}") +string(APPEND CMAKE_C_FLAGS_RELWITHDEBINFO " /MD ${SYMBOL_FORMAT_RELEASE}") 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") diff --git a/build_files/windows/configure_msbuild.cmd b/build_files/windows/configure_msbuild.cmd index 4956f1e3ea1..be69f99a8e8 100644 --- a/build_files/windows/configure_msbuild.cmd +++ b/build_files/windows/configure_msbuild.cmd @@ -9,14 +9,10 @@ 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" ( diff --git a/build_files/windows/configure_ninja.cmd b/build_files/windows/configure_ninja.cmd index d68d94a3bcf..90085feb2bd 100644 --- a/build_files/windows/configure_ninja.cmd +++ b/build_files/windows/configure_ninja.cmd @@ -46,16 +46,10 @@ 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" ( - if "%WITH_CLANG%" == "" ( - echo ASAN is only supported with clang. - exit /b 1 - ) + set BUILD_CMAKE_ARGS=%BUILD_CMAKE_ARGS% -DWITH_COMPILER_ASAN=On ) if NOT "%verbose%" == "" ( diff --git a/doc/python_api/sphinx_doc_gen.py b/doc/python_api/sphinx_doc_gen.py index 5c6cf24a178..8be194a58a2 100644 --- a/doc/python_api/sphinx_doc_gen.py +++ b/doc/python_api/sphinx_doc_gen.py @@ -553,7 +553,7 @@ def example_extract_docstring(filepath): line_no += 1 else: file.close() - return "", 0 + return "", 0, False for line in file: line_no += 1 @@ -563,15 +563,17 @@ 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 + return "\n".join(text), line_no, line_no_has_content def title_string(text, heading_char, double=False): @@ -590,16 +592,18 @@ 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 = example_extract_docstring(filepath_full) + text, line_no, line_no_has_content = example_extract_docstring(filepath_full) for line in text.split("\n"): fw("%s\n" % (ident + line).rstrip()) fw("\n") - fw("%s.. literalinclude:: %s\n" % (ident, filepath)) - if line_no > 0: - fw("%s :lines: %d-\n" % (ident, line_no)) - 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") EXAMPLE_SET_USED.add(example_id) else: if bpy.app.debug: @@ -1408,7 +1412,8 @@ def pyrna2sphinx(basepath): else: fw(" .. attribute:: %s\n\n" % prop.identifier) if prop.description: - fw(" %s\n\n" % prop.description) + write_indented_lines(" ", fw, prop.description, False) + fw("\n") # special exception, can't use generic code here for enums if prop.type == "enum": diff --git a/extern/CMakeLists.txt b/extern/CMakeLists.txt index 235c2fa931a..824b2fb0e9c 100644 --- a/extern/CMakeLists.txt +++ b/extern/CMakeLists.txt @@ -109,3 +109,7 @@ endif() if(WITH_MOD_FLUID) add_subdirectory(mantaflow) endif() + +if (WITH_COMPOSITOR) + add_subdirectory(smaa_areatex) +endif() diff --git a/extern/audaspace/CMakeLists.txt b/extern/audaspace/CMakeLists.txt index fe1bf5dc742..1599c03cbad 100644 --- a/extern/audaspace/CMakeLists.txt +++ b/extern/audaspace/CMakeLists.txt @@ -42,6 +42,7 @@ 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 @@ -148,6 +149,7 @@ 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 diff --git a/extern/audaspace/include/devices/SoftwareDevice.h b/extern/audaspace/include/devices/SoftwareDevice.h index a350550048b..209be9941b1 100644 --- a/extern/audaspace/include/devices/SoftwareDevice.h +++ b/extern/audaspace/include/devices/SoftwareDevice.h @@ -255,6 +255,7 @@ 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; diff --git a/extern/audaspace/include/devices/ThreadedDevice.h b/extern/audaspace/include/devices/ThreadedDevice.h new file mode 100644 index 00000000000..36c2e68e36f --- /dev/null +++ b/extern/audaspace/include/devices/ThreadedDevice.h @@ -0,0 +1,95 @@ +/******************************************************************************* + * 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 diff --git a/extern/audaspace/plugins/pulseaudio/PulseAudioDevice.cpp b/extern/audaspace/plugins/pulseaudio/PulseAudioDevice.cpp index 0a50d5db2c7..3ffe97661d8 100644 --- a/extern/audaspace/plugins/pulseaudio/PulseAudioDevice.cpp +++ b/extern/audaspace/plugins/pulseaudio/PulseAudioDevice.cpp @@ -27,9 +27,9 @@ void PulseAudioDevice::PulseAudio_state_callback(pa_context *context, void *data { PulseAudioDevice* device = (PulseAudioDevice*)data; - device->m_state = AUD_pa_context_get_state(context); + std::lock_guard<ILockable> lock(*device); - AUD_pa_threaded_mainloop_signal(device->m_mainloop, 0); + device->m_state = AUD_pa_context_get_state(context); } void PulseAudioDevice::PulseAudio_request(pa_stream *stream, size_t num_bytes, void *data) @@ -68,29 +68,40 @@ void PulseAudioDevice::PulseAudio_underflow(pa_stream *stream, void *data) } } -void PulseAudioDevice::playing(bool playing) +void PulseAudioDevice::runMixingThread() { - m_playback = playing; + for(;;) + { + { + std::lock_guard<ILockable> lock(*this); + + 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_stream_cork(m_stream, playing ? 0 : 1, nullptr, nullptr); + AUD_pa_mainloop_iterate(m_mainloop, true, 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_threaded_mainloop_new(); + m_mainloop = AUD_pa_mainloop_new(); - AUD_pa_threaded_mainloop_lock(m_mainloop); - - m_context = AUD_pa_context_new(AUD_pa_threaded_mainloop_get_api(m_mainloop), name.c_str()); + m_context = AUD_pa_context_new(AUD_pa_mainloop_get_api(m_mainloop), name.c_str()); if(!m_context) { - AUD_pa_threaded_mainloop_unlock(m_mainloop); - AUD_pa_threaded_mainloop_free(m_mainloop); + AUD_pa_mainloop_free(m_mainloop); AUD_THROW(DeviceException, "Could not connect to PulseAudio."); } @@ -99,26 +110,21 @@ 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_threaded_mainloop_free(m_mainloop); + AUD_pa_mainloop_free(m_mainloop); AUD_THROW(DeviceException, "Could not connect to PulseAudio."); break; default: - AUD_pa_threaded_mainloop_wait(m_mainloop); + AUD_pa_mainloop_iterate(m_mainloop, true, nullptr); break; } } @@ -166,13 +172,10 @@ 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_threaded_mainloop_free(m_mainloop); + AUD_pa_mainloop_free(m_mainloop); AUD_THROW(DeviceException, "Could not create PulseAudio stream."); } @@ -188,32 +191,27 @@ 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_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_START_CORKED | 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_threaded_mainloop_free(m_mainloop); + AUD_pa_mainloop_free(m_mainloop); AUD_THROW(DeviceException, "Could not connect PulseAudio stream."); } - AUD_pa_threaded_mainloop_unlock(m_mainloop); - create(); } PulseAudioDevice::~PulseAudioDevice() { - AUD_pa_threaded_mainloop_stop(m_mainloop); + stopMixingThread(); AUD_pa_context_disconnect(m_context); AUD_pa_context_unref(m_context); - AUD_pa_threaded_mainloop_free(m_mainloop); + AUD_pa_mainloop_free(m_mainloop); destroy(); } diff --git a/extern/audaspace/plugins/pulseaudio/PulseAudioDevice.h b/extern/audaspace/plugins/pulseaudio/PulseAudioDevice.h index 9efae5128b1..be34cc9032b 100644 --- a/extern/audaspace/plugins/pulseaudio/PulseAudioDevice.h +++ b/extern/audaspace/plugins/pulseaudio/PulseAudioDevice.h @@ -26,7 +26,7 @@ * The PulseAudioDevice class. */ -#include "devices/SoftwareDevice.h" +#include "devices/ThreadedDevice.h" #include <pulse/pulseaudio.h> @@ -35,15 +35,10 @@ AUD_NAMESPACE_BEGIN /** * This device plays back through PulseAudio, the simple direct media layer. */ -class AUD_PLUGIN_API PulseAudioDevice : public SoftwareDevice +class AUD_PLUGIN_API PulseAudioDevice : public ThreadedDevice { private: - /** - * Whether there is currently playback. - */ - volatile bool m_playback; - - pa_threaded_mainloop* m_mainloop; + pa_mainloop* m_mainloop; pa_context* m_context; pa_stream* m_stream; pa_context_state_t m_state; @@ -74,13 +69,15 @@ 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. diff --git a/extern/audaspace/plugins/pulseaudio/PulseAudioSymbols.h b/extern/audaspace/plugins/pulseaudio/PulseAudioSymbols.h index 9cefbc0c7e2..4b9e1ffea2b 100644 --- a/extern/audaspace/plugins/pulseaudio/PulseAudioSymbols.h +++ b/extern/audaspace/plugins/pulseaudio/PulseAudioSymbols.h @@ -24,18 +24,14 @@ 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_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); +PULSEAUDIO_SYMBOL(pa_mainloop_free); +PULSEAUDIO_SYMBOL(pa_mainloop_get_api); +PULSEAUDIO_SYMBOL(pa_mainloop_new); +PULSEAUDIO_SYMBOL(pa_mainloop_iterate); diff --git a/extern/audaspace/plugins/wasapi/WASAPIDevice.cpp b/extern/audaspace/plugins/wasapi/WASAPIDevice.cpp index 4f213dc8468..b4632ebb83e 100644 --- a/extern/audaspace/plugins/wasapi/WASAPIDevice.cpp +++ b/extern/audaspace/plugins/wasapi/WASAPIDevice.cpp @@ -31,159 +31,83 @@ template <class T> void SafeRelease(T **ppT) } } -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() +void WASAPIDevice::runMixingThread() { UINT32 buffer_size; + UINT32 padding; + UINT32 length; data_t* buffer; - lock(); + IAudioRenderClient* render_client = nullptr; - if(FAILED(m_audio_client->GetBufferSize(&buffer_size))) { - m_playing = false; - m_stop = false; - unlock(); - return; - } + std::lock_guard<ILockable> lock(*this); - IAudioRenderClient* render_client = nullptr; - const IID IID_IAudioRenderClient = __uuidof(IAudioRenderClient); + 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; - } + if(FAILED(m_audio_client->GetBufferSize(&buffer_size))) + goto init_error; - UINT32 padding; + if(FAILED(m_audio_client->GetService(IID_IAudioRenderClient, reinterpret_cast<void**>(&render_client)))) + goto init_error; - if(FAILED(m_audio_client->GetCurrentPadding(&padding))) - { - SafeRelease(&render_client); - m_playing = false; - m_stop = false; - unlock(); - return; - } + if(FAILED(m_audio_client->GetCurrentPadding(&padding))) + goto init_error; - UINT32 length = buffer_size - padding; + length = buffer_size - padding; - if(FAILED(render_client->GetBuffer(length, &buffer))) - { - SafeRelease(&render_client); - m_playing = false; - m_stop = false; - unlock(); - return; - } + if(FAILED(render_client->GetBuffer(length, &buffer))) + goto init_error; - mix((data_t*)buffer, length); + mix((data_t*)buffer, length); - if(FAILED(render_client->ReleaseBuffer(length, 0))) - { - SafeRelease(&render_client); - m_playing = false; - m_stop = false; - unlock(); - return; + if(FAILED(render_client->ReleaseBuffer(length, 0))) + { + init_error: + SafeRelease(&render_client); + doStop(); + 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))) { - m_audio_client->Stop(); - SafeRelease(&render_client); - m_playing = false; - m_stop = false; - unlock(); - return; - } + std::lock_guard<ILockable> lock(*this); - length = buffer_size - padding; + if(FAILED(m_audio_client->GetCurrentPadding(&padding))) + goto stop_thread; - if(FAILED(render_client->GetBuffer(length, &buffer))) - { - m_audio_client->Stop(); - SafeRelease(&render_client); - m_playing = false; - m_stop = false; - unlock(); - return; - } + length = buffer_size - padding; - mix((data_t*)buffer, length); + if(FAILED(render_client->GetBuffer(length, &buffer))) + goto stop_thread; - if(FAILED(render_client->ReleaseBuffer(length, 0))) - { - m_audio_client->Stop(); - SafeRelease(&render_client); - m_playing = false; - m_stop = false; - unlock(); - return; - } + mix((data_t*)buffer, length); - // stop thread - if(m_stop) - { - m_audio_client->Stop(); - SafeRelease(&render_client); - m_playing = false; - m_stop = false; - unlock(); - return; - } + if(FAILED(render_client->ReleaseBuffer(length, 0))) + goto stop_thread; - unlock(); + // stop thread + if(shouldStop()) + { + stop_thread: + m_audio_client->Stop(); + SafeRelease(&render_client); + doStop(); + return; + } + } 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), @@ -361,14 +285,7 @@ WASAPIDevice::WASAPIDevice(DeviceSpecs specs, int buffersize) : WASAPIDevice::~WASAPIDevice() { - lock(); - - stopAll(); - - unlock(); - - if(m_thread.joinable()) - m_thread.join(); + stopMixingThread(); SafeRelease(&m_audio_client); SafeRelease(&m_imm_device); diff --git a/extern/audaspace/plugins/wasapi/WASAPIDevice.h b/extern/audaspace/plugins/wasapi/WASAPIDevice.h index ae25a09c432..375f03bd255 100644 --- a/extern/audaspace/plugins/wasapi/WASAPIDevice.h +++ b/extern/audaspace/plugins/wasapi/WASAPIDevice.h @@ -26,7 +26,7 @@ * The WASAPIDevice class. */ -#include "devices/SoftwareDevice.h" +#include "devices/ThreadedDevice.h" #include <thread> @@ -40,46 +40,23 @@ AUD_NAMESPACE_BEGIN /** * This device plays back through WASAPI, the Windows audio API. */ -class AUD_PLUGIN_API WASAPIDevice : public SoftwareDevice +class AUD_PLUGIN_API WASAPIDevice : public ThreadedDevice { 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 updateStream(); + AUD_LOCAL void runMixingThread(); // 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. diff --git a/extern/audaspace/src/devices/SoftwareDevice.cpp b/extern/audaspace/src/devices/SoftwareDevice.cpp index c8c1c6081c2..7a2561515f4 100644 --- a/extern/audaspace/src/devices/SoftwareDevice.cpp +++ b/extern/audaspace/src/devices/SoftwareDevice.cpp @@ -737,7 +737,7 @@ void SoftwareDevice::mix(data_t* buffer, int length) { m_buffer.assureSize(length * AUD_SAMPLE_SIZE(m_specs)); - std::lock_guard<std::recursive_mutex> lock(m_mutex); + std::lock_guard<ILockable> lock(*this); { 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<std::recursive_mutex> lock(m_mutex); + std::lock_guard<ILockable> lock(*this); 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<std::recursive_mutex> lock(m_mutex); + std::lock_guard<ILockable> lock(*this); while(!m_playingSounds.empty()) m_playingSounds.front()->stop(); diff --git a/extern/audaspace/src/devices/ThreadedDevice.cpp b/extern/audaspace/src/devices/ThreadedDevice.cpp new file mode 100644 index 00000000000..44ceccb8a60 --- /dev/null +++ b/extern/audaspace/src/devices/ThreadedDevice.cpp @@ -0,0 +1,65 @@ +/******************************************************************************* + * 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 diff --git a/extern/smaa_areatex/CMakeLists.txt b/extern/smaa_areatex/CMakeLists.txt new file mode 100644 index 00000000000..2386b0e7b79 --- /dev/null +++ b/extern/smaa_areatex/CMakeLists.txt @@ -0,0 +1,26 @@ +# ***** 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) diff --git a/extern/smaa_areatex/README.blender b/extern/smaa_areatex/README.blender new file mode 100644 index 00000000000..9c409142ae8 --- /dev/null +++ b/extern/smaa_areatex/README.blender @@ -0,0 +1,5 @@ +Project: smaa-cpp +URL: https://github.com/iRi-E/smaa-cpp +License: MIT +Upstream version: 0.4.0 +Local modifications: diff --git a/extern/smaa_areatex/smaa_areatex.cpp b/extern/smaa_areatex/smaa_areatex.cpp new file mode 100644 index 00000000000..971706fd64d --- /dev/null +++ b/extern/smaa_areatex/smaa_areatex.cpp @@ -0,0 +1,1208 @@ +/** + * Copyright (C) 2016-2017 IRIE Shinsuke + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* + * smaa_areatex.cpp version 0.4.0 + * + * This is a part of smaa-cpp that is an implementation of + * Enhanced Subpixel Morphological Antialiasing (SMAA) written in C++. + * + * This program is C++ rewrite of AreaTex.py included in the original + * SMAA ditribution: + * + * https://github.com/iryoku/smaa/tree/master/Scripts + */ + +#include <cstdio> +#include <cstdlib> +#include <cstring> + +#include <cmath> + +/*------------------------------------------------------------------------------*/ +/* Type Definitions */ + +class Int2; +class Dbl2; + +class Int2 { +public: + int x, y; + + Int2() { this->x = this->y = 0; } + Int2(int x) { this->x = this->y = x; } + Int2(int x, int y) { this->x = x; this->y = y; } + + operator Dbl2(); + + Int2 operator + (Int2 other) { return Int2(x + other.x, y + other.y); } + Int2 operator * (Int2 other) { return Int2(x * other.x, y * other.y); } +}; + +class Dbl2 { +public: + double x, y; + + Dbl2() { this->x = this->y = 0.0; } + Dbl2(double x) { this->x = this->y = x; } + Dbl2(double x, double y) { this->x = x; this->y = y; } + + Dbl2 apply(double (* func)(double)) { return Dbl2(func(x), func(y)); } + + operator Int2(); + + Dbl2 operator + (Dbl2 other) { return Dbl2(x + other.x, y + other.y); } + Dbl2 operator - (Dbl2 other) { return Dbl2(x - other.x, y - other.y); } + Dbl2 operator * (Dbl2 other) { return Dbl2(x * other.x, y * other.y); } + Dbl2 operator / (Dbl2 other) { return Dbl2(x / other.x, y / other.y); } + Dbl2 operator += (Dbl2 other) { return Dbl2(x += other.x, y += other.y); } + bool operator == (Dbl2 other) { return (x == other.x && y == other.y); } +}; + +Int2::operator Dbl2() { return Dbl2((double)x, (double)y); } +Dbl2::operator Int2() { return Int2((int)x, (int)y); } + +/*------------------------------------------------------------------------------*/ +/* Data to Calculate Areatex */ + +/* Texture sizes: */ +/* (it's quite possible that this is not easily configurable) */ +static const int SUBSAMPLES_ORTHO = 7; +static const int SUBSAMPLES_DIAG = 5; +static const int MAX_DIST_ORTHO_COMPAT = 16; +static const int MAX_DIST_ORTHO = 20; +static const int MAX_DIST_DIAG = 20; +static const int TEX_SIZE_ORTHO = 80; /* 16 * 5 slots = 80 */ +static const int TEX_SIZE_DIAG = 80; /* 20 * 4 slots = 80 */ + +/* Number of samples for calculating areas in the diagonal textures: */ +/* (diagonal areas are calculated using brute force sampling) */ +static const int SAMPLES_DIAG = 30; + +/* Maximum distance for smoothing u-shapes: */ +static const int SMOOTH_MAX_DISTANCE = 32; + +/*------------------------------------------------------------------------------*/ +/* Offset Tables */ + +/* Offsets for subsample rendering */ +static const double subsample_offsets_ortho[SUBSAMPLES_ORTHO] = { + 0.0, /* 0 */ + -0.25, /* 1 */ + 0.25, /* 2 */ + -0.125, /* 3 */ + 0.125, /* 4 */ + -0.375, /* 5 */ + 0.375 /* 6 */ +}; + +static const Dbl2 subsample_offsets_diag[SUBSAMPLES_DIAG] = { + { 0.00, 0.00}, /* 0 */ + { 0.25, -0.25}, /* 1 */ + {-0.25, 0.25}, /* 2 */ + { 0.125, -0.125}, /* 3 */ + {-0.125, 0.125} /* 4 */ +}; + +/* Mapping offsets for placing each pattern subtexture into its place */ +enum edgesorthoIndices +{ + EDGESORTHO_NONE_NONE = 0, + EDGESORTHO_NONE_NEGA = 1, + EDGESORTHO_NONE_POSI = 2, + EDGESORTHO_NONE_BOTH = 3, + EDGESORTHO_NEGA_NONE = 4, + EDGESORTHO_NEGA_NEGA = 5, + EDGESORTHO_NEGA_POSI = 6, + EDGESORTHO_NEGA_BOTH = 7, + EDGESORTHO_POSI_NONE = 8, + EDGESORTHO_POSI_NEGA = 9, + EDGESORTHO_POSI_POSI = 10, + EDGESORTHO_POSI_BOTH = 11, + EDGESORTHO_BOTH_NONE = 12, + EDGESORTHO_BOTH_NEGA = 13, + EDGESORTHO_BOTH_POSI = 14, + EDGESORTHO_BOTH_BOTH = 15, +}; + +static const Int2 edgesortho_compat[16] = { + {0, 0}, {0, 1}, {0, 3}, {0, 4}, {1, 0}, {1, 1}, {1, 3}, {1, 4}, + {3, 0}, {3, 1}, {3, 3}, {3, 4}, {4, 0}, {4, 1}, {4, 3}, {4, 4} +}; + +static const Int2 edgesortho[16] = { + {0, 0}, {0, 1}, {0, 2}, {0, 3}, {1, 0}, {1, 1}, {1, 2}, {1, 3}, + {2, 0}, {2, 1}, {2, 2}, {2, 3}, {3, 0}, {3, 1}, {3, 2}, {3, 3} +}; + +enum edgesdiagIndices +{ + EDGESDIAG_NONE_NONE = 0, + EDGESDIAG_NONE_VERT = 1, + EDGESDIAG_NONE_HORZ = 2, + EDGESDIAG_NONE_BOTH = 3, + EDGESDIAG_VERT_NONE = 4, + EDGESDIAG_VERT_VERT = 5, + EDGESDIAG_VERT_HORZ = 6, + EDGESDIAG_VERT_BOTH = 7, + EDGESDIAG_HORZ_NONE = 8, + EDGESDIAG_HORZ_VERT = 9, + EDGESDIAG_HORZ_HORZ = 10, + EDGESDIAG_HORZ_BOTH = 11, + EDGESDIAG_BOTH_NONE = 12, + EDGESDIAG_BOTH_VERT = 13, + EDGESDIAG_BOTH_HORZ = 14, + EDGESDIAG_BOTH_BOTH = 15, +}; + +static const Int2 edgesdiag[16] = { + {0, 0}, {0, 1}, {0, 2}, {0, 3}, {1, 0}, {1, 1}, {1, 2}, {1, 3}, + {2, 0}, {2, 1}, {2, 2}, {2, 3}, {3, 0}, {3, 1}, {3, 2}, {3, 3} +}; + +/*------------------------------------------------------------------------------*/ +/* Miscellaneous Utility Functions */ + +/* Linear interpolation: */ +static Dbl2 lerp(Dbl2 a, Dbl2 b, double p) +{ + return a + (b - a) * Dbl2(p); +} + +/* Saturates a value to [0..1] range: */ +static double saturate(double x) +{ + return 0.0 < x ? (x < 1.0 ? x : 1.0) : 0.0; +} + +/*------------------------------------------------------------------------------*/ +/* Horizontal/Vertical Areas */ + +class AreaOrtho { + double m_data[SUBSAMPLES_ORTHO][TEX_SIZE_ORTHO][TEX_SIZE_ORTHO][2]; + bool m_compat; + bool m_orig_u; +public: + AreaOrtho(bool compat, bool orig_u) : m_compat(compat), m_orig_u(orig_u) {} + + double *getData() { return (double *)&m_data; } + Dbl2 getPixel(int offset_index, Int2 coords) { + return Dbl2(m_data[offset_index][coords.y][coords.x][0], + m_data[offset_index][coords.y][coords.x][1]); + } + + void areaTex(int offset_index); +private: + void putPixel(int offset_index, Int2 coords, Dbl2 pixel) { + m_data[offset_index][coords.y][coords.x][0] = pixel.x; + m_data[offset_index][coords.y][coords.x][1] = pixel.y; + } + + Dbl2 smoothArea(double d, Dbl2 a1, Dbl2 a2); + Dbl2 makeQuad(int x, double d, double o); + Dbl2 area(Dbl2 p1, Dbl2 p2, int x); + Dbl2 calculate(int pattern, int left, int right, double offset); +}; + +/* Smoothing function for small u-patterns: */ +Dbl2 AreaOrtho::smoothArea(double d, Dbl2 a1, Dbl2 a2) +{ + Dbl2 b1 = (a1 * Dbl2(2.0)).apply(sqrt) * Dbl2(0.5); + Dbl2 b2 = (a2 * Dbl2(2.0)).apply(sqrt) * Dbl2(0.5); + double p = saturate(d / (double)SMOOTH_MAX_DISTANCE); + return lerp(b1, a1, p) + lerp(b2, a2, p); +} + +/* Smoothing u-patterns by quadratic function: */ +Dbl2 AreaOrtho::makeQuad(int x, double d, double o) +{ + double r = (double)x; + + /* fmin() below is a trick to smooth tiny u-patterns: */ + return Dbl2(r, (1.0 - fmin(4.0, d) * r * (d - r) / (d * d)) * o); +} + +/* Calculates the area under the line p1->p2, for the pixel x..x+1: */ +Dbl2 AreaOrtho::area(Dbl2 p1, Dbl2 p2, int x) +{ + Dbl2 d = p2 - p1; + double x1 = (double)x; + double x2 = x1 + 1.0; + + if ((x1 >= p1.x && x1 < p2.x) || (x2 > p1.x && x2 <= p2.x)) { /* inside? */ + double y1 = p1.y + (x1 - p1.x) * d.y / d.x; + double y2 = p1.y + (x2 - p1.x) * d.y / d.x; + + if ((copysign(1.0, y1) == copysign(1.0, y2) || + fabs(y1) < 1e-4 || fabs(y2) < 1e-4)) { /* trapezoid? */ + double a = (y1 + y2) / 2.0; + if (a < 0.0) + return Dbl2(fabs(a), 0.0); + else + return Dbl2(0.0, fabs(a)); + } + else { /* Then, we got two triangles: */ + double x = p1.x - p1.y * d.x / d.y, xi; + double a1 = x > p1.x ? y1 * modf(x, &xi) / 2.0 : 0.0; + double a2 = x < p2.x ? y2 * (1.0 - modf(x, &xi)) / 2.0 : 0.0; + double a = fabs(a1) > fabs(a2) ? a1 : -a2; + if (a < 0.0) + return Dbl2(fabs(a1), fabs(a2)); + else + return Dbl2(fabs(a2), fabs(a1)); + } + } + else + return Dbl2(0.0, 0.0); +} + +/* Calculates the area for a given pattern and distances to the left and to the */ +/* right, biased by an offset: */ +Dbl2 AreaOrtho::calculate(int pattern, int left, int right, double offset) +{ + Dbl2 a1, a2; + + /* + * o1 | + * .-------´ + * o2 | + * + * <---d---> + */ + double d = (double)(left + right + 1); + + double o1 = 0.5 + offset; + double o2 = 0.5 + offset - 1.0; + + switch (pattern) { + case EDGESORTHO_NONE_NONE: + { + /* + * + * ------ + * + */ + return Dbl2(0.0, 0.0); + break; + } + case EDGESORTHO_POSI_NONE: + { + /* + * + * .------ + * | + * + * We only offset L patterns in the crossing edge side, to make it + * converge with the unfiltered pattern 0 (we don't want to filter the + * pattern 0 to avoid artifacts). + */ + if (left <= right) + return area(Dbl2(0.0, o2), Dbl2(d / 2.0, 0.0), left); + else + return Dbl2(0.0, 0.0); + break; + } + case EDGESORTHO_NONE_POSI: + { + /* + * + * ------. + * | + */ + if (left >= right) + return area(Dbl2(d / 2.0, 0.0), Dbl2(d, o2), left); + else + return Dbl2(0.0, 0.0); + break; + } + case EDGESORTHO_POSI_POSI: + { + /* + * + * .------. + * | | + */ + if (m_orig_u) { + a1 = area(Dbl2(0.0, o2), Dbl2(d / 2.0, 0.0), left); + a2 = area(Dbl2(d / 2.0, 0.0), Dbl2(d, o2), left); + return smoothArea(d, a1, a2); + } + else + return area(makeQuad(left, d, o2), makeQuad(left + 1, d, o2), left); + break; + } + case EDGESORTHO_NEGA_NONE: + { + /* + * | + * `------ + * + */ + if (left <= right) + return area(Dbl2(0.0, o1), Dbl2(d / 2.0, 0.0), left); + else + return Dbl2(0.0, 0.0); + break; + } + case EDGESORTHO_BOTH_NONE: + { + /* + * | + * +------ + * | + */ + return Dbl2(0.0, 0.0); + break; + } + case EDGESORTHO_NEGA_POSI: + { + /* + * | + * `------. + * | + * + * A problem of not offseting L patterns (see above), is that for certain + * max search distances, the pixels in the center of a Z pattern will + * detect the full Z pattern, while the pixels in the sides will detect a + * L pattern. To avoid discontinuities, we blend the full offsetted Z + * revectorization with partially offsetted L patterns. + */ + if (fabs(offset) > 0.0) { + a1 = area(Dbl2(0.0, o1), Dbl2(d, o2), left); + a2 = area(Dbl2(0.0, o1), Dbl2(d / 2.0, 0.0), left); + a2 += area(Dbl2(d / 2.0, 0.0), Dbl2(d, o2), left); + return (a1 + a2) / Dbl2(2.0); + } + else + return area(Dbl2(0.0, o1), Dbl2(d, o2), left); + break; + } + case EDGESORTHO_BOTH_POSI: + { + /* + * | + * +------. + * | | + */ + return area(Dbl2(0.0, o1), Dbl2(d, o2), left); + break; + } + case EDGESORTHO_NONE_NEGA: + { + /* + * | + * ------´ + * + */ + if (left >= right) + return area(Dbl2(d / 2.0, 0.0), Dbl2(d, o1), left); + else + return Dbl2(0.0, 0.0); + break; + } + case EDGESORTHO_POSI_NEGA: + { + /* + * | + * .------´ + * | + */ + if (fabs(offset) > 0.0) { + a1 = area(Dbl2(0.0, o2), Dbl2(d, o1), left); + a2 = area(Dbl2(0.0, o2), Dbl2(d / 2.0, 0.0), left); + a2 += area(Dbl2(d / 2.0, 0.0), Dbl2(d, o1), left); + return (a1 + a2) / Dbl2(2.0); + } + else + return area(Dbl2(0.0, o2), Dbl2(d, o1), left); + break; + } + case EDGESORTHO_NONE_BOTH: + { + /* + * | + * ------+ + * | + */ + return Dbl2(0.0, 0.0); + break; + } + case EDGESORTHO_POSI_BOTH: + { + /* + * | + * .------+ + * | | + */ + return area(Dbl2(0.0, o2), Dbl2(d, o1), left); + break; + } + case EDGESORTHO_NEGA_NEGA: + { + /* + * | | + * `------´ + * + */ + if (m_orig_u) { + a1 = area(Dbl2(0.0, o1), Dbl2(d / 2.0, 0.0), left); + a2 = area(Dbl2(d / 2.0, 0.0), Dbl2(d, o1), left); + return smoothArea(d, a1, a2); + } + else + return area(makeQuad(left, d, o1), makeQuad(left + 1, d, o1), left); + break; + } + case EDGESORTHO_BOTH_NEGA: + { + /* + * | | + * +------´ + * | + */ + return area(Dbl2(0.0, o2), Dbl2(d, o1), left); + break; + } + case EDGESORTHO_NEGA_BOTH: + { + /* + * | | + * `------+ + * | + */ + return area(Dbl2(0.0, o1), Dbl2(d, o2), left); + break; + } + case EDGESORTHO_BOTH_BOTH: + { + /* + * | | + * +------+ + * | | + */ + return Dbl2(0.0, 0.0); + break; + } + } + + return Dbl2(0.0, 0.0); +} + +/*------------------------------------------------------------------------------*/ +/* Diagonal Areas */ + +class AreaDiag { + double m_data[SUBSAMPLES_DIAG][TEX_SIZE_DIAG][TEX_SIZE_DIAG][2]; + bool m_numeric; + bool m_orig_u; +public: + AreaDiag(bool numeric, bool orig_u) : m_numeric(numeric), m_orig_u(orig_u) {} + + double *getData() { return (double *)&m_data; } + Dbl2 getPixel(int offset_index, Int2 coords) { + return Dbl2(m_data[offset_index][coords.y][coords.x][0], + m_data[offset_index][coords.y][coords.x][1]); + } + + void areaTex(int offset_index); +private: + void putPixel(int offset_index, Int2 coords, Dbl2 pixel) { + m_data[offset_index][coords.y][coords.x][0] = pixel.x; + m_data[offset_index][coords.y][coords.x][1] = pixel.y; + } + + double area1(Dbl2 p1, Dbl2 p2, Int2 p); + Dbl2 area(Dbl2 p1, Dbl2 p2, int left); + Dbl2 areaTriangle(Dbl2 p1L, Dbl2 p2L, Dbl2 p1R, Dbl2 p2R, int left); + Dbl2 calculate(int pattern, int left, int right, Dbl2 offset); +}; + +/* Calculates the area under the line p1->p2 for the pixel 'p' using brute */ +/* force sampling: */ +/* (quick and dirty solution, but it works) */ +double AreaDiag::area1(Dbl2 p1, Dbl2 p2, Int2 p) +{ + if (p1 == p2) + return 1.0; + + double xm = (p1.x + p2.x) / 2.0, ym = (p1.y + p2.y) / 2.0; + double a = p2.y - p1.y; + double b = p1.x - p2.x; + int count = 0; + + for (int ix = 0; ix < SAMPLES_DIAG; ix++) { + double x = (double)p.x + (double)ix / (double)(SAMPLES_DIAG - 1); + for (int iy = 0; iy < SAMPLES_DIAG; iy++) { + double y = (double)p.y + (double)iy / (double)(SAMPLES_DIAG - 1); + if (a * (x - xm) + b * (y - ym) > 0.0) /* inside? */ + count++; + } + } + return (double)count / (double)(SAMPLES_DIAG * SAMPLES_DIAG); +} + +/* Calculates the area under the line p1->p2: */ +/* (includes the pixel and its opposite) */ +Dbl2 AreaDiag::area(Dbl2 p1, Dbl2 p2, int left) +{ + if (m_numeric) { + double a1 = area1(p1, p2, Int2(1, 0) + Int2(left)); + double a2 = area1(p1, p2, Int2(1, 1) + Int2(left)); + return Dbl2(1.0 - a1, a2); + } + + /* Calculates the area under the line p1->p2 for the pixel 'p' analytically */ + Dbl2 d = p2 - p1; + if (d.x == 0.0) + return Dbl2(0.0, 1.0); + + double x1 = (double)(1 + left); + double x2 = x1 + 1.0; + double ymid = x1; + double xtop = p1.x + (ymid + 1.0 - p1.y) * d.x / d.y; + double xmid = p1.x + (ymid - p1.y) * d.x / d.y; + double xbot = p1.x + (ymid - 1.0 - p1.y) * d.x / d.y; + + double y1 = p1.y + (x1 - p1.x) * d.y / d.x; + double y2 = p1.y + (x2 - p1.x) * d.y / d.x; + double fy1 = y1 - floor(y1); + double fy2 = y2 - floor(y2); + int iy1 = (int)floor(y1 - ymid); + int iy2 = (int)floor(y2 - ymid); + + if (iy1 <= -2) { + if (iy2 == -1) + return Dbl2(1.0 - (x2 - xbot) * fy2 * 0.5, 0.0); + else if (iy2 == 0) + return Dbl2((xmid + xbot) * 0.5 - x1, (x2 - xmid) * fy2 * 0.5); + else if (iy2 >= 1) + return Dbl2((xmid + xbot) * 0.5 - x1, x2 - (xtop + xmid) * 0.5); + else /* iy2 < -1 */ + return Dbl2(1.0, 0.0); + } + else if (iy1 == -1) { + if (iy2 == -1) + return Dbl2(1.0 - (fy1 + fy2) * 0.5, 0.0); + else if (iy2 == 0) + return Dbl2((xmid - x1) * (1.0 - fy1) * 0.5, (x2 - xmid) * fy2 * 0.5); + else if (iy2 >= 1) + return Dbl2((xmid - x1) * (1.0 - fy1) * 0.5, x2 - (xtop + xmid) * 0.5); + else /* iy2 < -1 */ + return Dbl2(1.0 - (xbot - x1) * fy1 * 0.5, 0.0); + } + else if (iy1 == 0) { + if (iy2 == -1) + return Dbl2((x2 - xmid) * (1.0 - fy2) * 0.5, (xmid - x1) * fy1 * 0.5); + else if (iy2 == 0) + return Dbl2(0.0, (fy1 + fy2) * 0.5); + else if (iy2 >= 1) + return Dbl2(0.0, 1.0 - (xtop - x1) * (1.0 - fy1) * 0.5); + else /* iy2 < -1 */ + return Dbl2(x2 - (xmid + xbot) * 0.5, (xmid - x1) * fy1 * 0.5); + } + else { /* iy1 > 0 */ + if (iy2 == -1) + return Dbl2((x2 - xtop) * (1.0 - fy2) * 0.5, (xtop + xmid) * 0.5 - x1); + else if (iy2 == 0) + return Dbl2(0.0, 1.0 - (x1 - xtop) * (1.0 - fy2) * 0.5); + else if (iy2 >= 1) + return Dbl2(0.0, 1.0); + else /* iy2 < -1 */ + return Dbl2(x2 - (xmid + xbot) * 0.5, (xtop + xmid) * 0.5 - x1); + } +} + +/* Calculate u-patterns using a triangle: */ +Dbl2 AreaDiag::areaTriangle(Dbl2 p1L, Dbl2 p2L, Dbl2 p1R, Dbl2 p2R, int left) +{ + double x1 = (double)(1 + left); + double x2 = x1 + 1.0; + + Dbl2 dL = p2L - p1L; + Dbl2 dR = p2R - p1R; + double xm = ((p1L.x * dL.y / dL.x - p1L.y) - (p1R.x * dR.y / dR.x - p1R.y)) / (dL.y / dL.x - dR.y / dR.x); + + double y1 = (x1 < xm) ? p1L.y + (x1 - p1L.x) * dL.y / dL.x : p1R.y + (x1 - p1R.x) * dR.y / dR.x; + double y2 = (x2 < xm) ? p1L.y + (x2 - p1L.x) * dL.y / dL.x : p1R.y + (x2 - p1R.x) * dR.y / dR.x; + + return area(Dbl2(x1, y1), Dbl2(x2, y2), left); +} + +/* Calculates the area for a given pattern and distances to the left and to the */ +/* right, biased by an offset: */ +Dbl2 AreaDiag::calculate(int pattern, int left, int right, Dbl2 offset) +{ + Dbl2 a1, a2; + + double d = (double)(left + right + 1); + + /* + * There is some Black Magic around diagonal area calculations. Unlike + * orthogonal patterns, the 'null' pattern (one without crossing edges) must be + * filtered, and the ends of both the 'null' and L patterns are not known: L + * and U patterns have different endings, and we don't know what is the + * adjacent pattern. So, what we do is calculate a blend of both possibilites. + */ + switch (pattern) { + case EDGESDIAG_NONE_NONE: + { + /* + * + * .-´ + * .-´ + * .-´ + * .-´ + * ´ + * + */ + a1 = area(Dbl2(1.0, 1.0), Dbl2(1.0, 1.0) + Dbl2(d), left); /* 1st possibility */ + a2 = area(Dbl2(1.0, 0.0), Dbl2(1.0, 0.0) + Dbl2(d), left); /* 2nd possibility */ + return (a1 + a2) / Dbl2(2.0); /* Blend them */ + break; + } + case EDGESDIAG_VERT_NONE: + { + /* + * + * .-´ + * .-´ + * .-´ + * .-´ + * | + * | + */ + a1 = area(Dbl2(1.0, 0.0) + offset, Dbl2(0.0, 0.0) + Dbl2(d), left); + a2 = area(Dbl2(1.0, 0.0) + offset, Dbl2(1.0, 0.0) + Dbl2(d), left); + return (a1 + a2) / Dbl2(2.0); + break; + } + case EDGESDIAG_NONE_HORZ: + { + /* + * + * .---- + * .-´ + * .-´ + * .-´ + * ´ + * + */ + a1 = area(Dbl2(0.0, 0.0), Dbl2(1.0, 0.0) + Dbl2(d) + offset, left); + a2 = area(Dbl2(1.0, 0.0), Dbl2(1.0, 0.0) + Dbl2(d) + offset, left); + return (a1 + a2) / Dbl2(2.0); + break; + } + case EDGESDIAG_VERT_HORZ: + { + /* + * + * .---- + * .-´ + * .-´ + * .-´ + * | + * | + */ + if (m_orig_u) + return area(Dbl2(1.0, 0.0) + offset, Dbl2(1.0, 0.0) + Dbl2(d) + offset, left); + else + return areaTriangle(Dbl2(1.0, 0.0) + offset, Dbl2(1.0, 1.0) + Dbl2(d), + Dbl2(0.0, 0.0), Dbl2(1.0, 0.0) + Dbl2(d) + offset, left); + break; + } + case EDGESDIAG_HORZ_NONE: + { + /* + * + * .-´ + * .-´ + * .-´ + * ----´ + * + * + */ + a1 = area(Dbl2(1.0, 1.0) + offset, Dbl2(0.0, 0.0) + Dbl2(d), left); + a2 = area(Dbl2(1.0, 1.0) + offset, Dbl2(1.0, 0.0) + Dbl2(d), left); + return (a1 + a2) / Dbl2(2.0); + break; + } + case EDGESDIAG_BOTH_NONE: + { + /* + * + * .-´ + * .-´ + * .-´ + * --.-´ + * | + * | + */ + a1 = area(Dbl2(1.0, 1.0) + offset, Dbl2(0.0, 0.0) + Dbl2(d), left); + a2 = area(Dbl2(1.0, 0.0) + offset, Dbl2(1.0, 0.0) + Dbl2(d), left); + return (a1 + a2) / Dbl2(2.0); + break; + } + case EDGESDIAG_HORZ_HORZ: + { + /* + * + * .---- + * .-´ + * .-´ + * ----´ + * + * + */ + return area(Dbl2(1.0, 1.0) + offset, Dbl2(1.0, 0.0) + Dbl2(d) + offset, left); + break; + } + case EDGESDIAG_BOTH_HORZ: + { + /* + * + * .---- + * .-´ + * .-´ + * --.-´ + * | + * | + */ + a1 = area(Dbl2(1.0, 1.0) + offset, Dbl2(1.0, 0.0) + Dbl2(d) + offset, left); + a2 = area(Dbl2(1.0, 0.0) + offset, Dbl2(1.0, 0.0) + Dbl2(d) + offset, left); + return (a1 + a2) / Dbl2(2.0); + break; + } + case EDGESDIAG_NONE_VERT: + { + /* + * | + * | + * .-´ + * .-´ + * .-´ + * ´ + * + */ + a1 = area(Dbl2(0.0, 0.0), Dbl2(1.0, 1.0) + Dbl2(d) + offset, left); + a2 = area(Dbl2(1.0, 0.0), Dbl2(1.0, 1.0) + Dbl2(d) + offset, left); + return (a1 + a2) / Dbl2(2.0); + break; + } + case EDGESDIAG_VERT_VERT: + { + /* + * | + * | + * .-´ + * .-´ + * .-´ + * | + * | + */ + return area(Dbl2(1.0, 0.0) + offset, Dbl2(1.0, 1.0) + Dbl2(d) + offset, left); + break; + } + case EDGESDIAG_NONE_BOTH: + { + /* + * | + * .---- + * .-´ + * .-´ + * .-´ + * ´ + * + */ + a1 = area(Dbl2(0.0, 0.0), Dbl2(1.0, 1.0) + Dbl2(d) + offset, left); + a2 = area(Dbl2(1.0, 0.0), Dbl2(1.0, 0.0) + Dbl2(d) + offset, left); + return (a1 + a2) / Dbl2(2.0); + break; + } + case EDGESDIAG_VERT_BOTH: + { + /* + * | + * .---- + * .-´ + * .-´ + * .-´ + * | + * | + */ + a1 = area(Dbl2(1.0, 0.0) + offset, Dbl2(1.0, 1.0) + Dbl2(d) + offset, left); + a2 = area(Dbl2(1.0, 0.0) + offset, Dbl2(1.0, 0.0) + Dbl2(d) + offset, left); + return (a1 + a2) / Dbl2(2.0); + break; + } + case EDGESDIAG_HORZ_VERT: + { + /* + * | + * | + * .-´ + * .-´ + * ----´ + * + * + */ + if (m_orig_u) + return area(Dbl2(1.0, 1.0) + offset, Dbl2(1.0, 1.0) + Dbl2(d) + offset, left); + else + return areaTriangle(Dbl2(1.0, 1.0) + offset, Dbl2(2.0, 1.0) + Dbl2(d), + Dbl2(1.0, 0.0), Dbl2(1.0, 1.0) + Dbl2(d) + offset, left); + break; + } + case EDGESDIAG_BOTH_VERT: + { + /* + * | + * | + * .-´ + * .-´ + * --.-´ + * | + * | + */ + a1 = area(Dbl2(1.0, 1.0) + offset, Dbl2(1.0, 1.0) + Dbl2(d) + offset, left); + a2 = area(Dbl2(1.0, 0.0) + offset, Dbl2(1.0, 1.0) + Dbl2(d) + offset, left); + return (a1 + a2) / Dbl2(2.0); + break; + } + case EDGESDIAG_HORZ_BOTH: + { + /* + * | + * .---- + * .-´ + * .-´ + * ----´ + * + * + */ + a1 = area(Dbl2(1.0, 1.0) + offset, Dbl2(1.0, 1.0) + Dbl2(d) + offset, left); + a2 = area(Dbl2(1.0, 1.0) + offset, Dbl2(1.0, 0.0) + Dbl2(d) + offset, left); + return (a1 + a2) / Dbl2(2.0); + break; + } + case EDGESDIAG_BOTH_BOTH: + { + /* + * | + * .---- + * .-´ + * .-´ + * --.-´ + * | + * | + */ + a1 = area(Dbl2(1.0, 1.0) + offset, Dbl2(1.0, 1.0) + Dbl2(d) + offset, left); + a2 = area(Dbl2(1.0, 0.0) + offset, Dbl2(1.0, 0.0) + Dbl2(d) + offset, left); + return (a1 + a2) / Dbl2(2.0); + break; + } + } + + return Dbl2(0.0, 0.0); +} + +/*------------------------------------------------------------------------------*/ +/* Main Loops */ + +void AreaOrtho::areaTex(int offset_index) +{ + double offset = subsample_offsets_ortho[offset_index]; + int max_dist = m_compat ? MAX_DIST_ORTHO_COMPAT : MAX_DIST_ORTHO; + + for (int pattern = 0; pattern < 16; pattern++) { + Int2 e = Int2(max_dist) * (m_compat ? edgesortho_compat : edgesortho)[pattern]; + for (int left = 0; left < max_dist; left++) { + for (int right = 0; right < max_dist; right++) { + Dbl2 p = calculate(pattern, left * left, right * right, offset); + Int2 coords = e + Int2(left, right); + + putPixel(offset_index, coords, p); + } + } + } + return; +} + +void AreaDiag::areaTex(int offset_index) +{ + Dbl2 offset = subsample_offsets_diag[offset_index]; + + for (int pattern = 0; pattern < 16; pattern++) { + Int2 e = Int2(MAX_DIST_DIAG) * edgesdiag[pattern]; + for (int left = 0; left < MAX_DIST_DIAG; left++) { + for (int right = 0; right < MAX_DIST_DIAG; right++) { + Dbl2 p = calculate(pattern, left, right, offset); + Int2 coords = e + Int2(left, right); + + putPixel(offset_index, coords, p); + } + } + } + return; +} + +/*------------------------------------------------------------------------------*/ +/* Write File to Specified Location on Disk */ + +/* C/C++ source code (arrays of floats) */ +static void write_double_array(FILE *fp, const double *ptr, int length, const char *array_name, bool quantize) +{ + fprintf(fp, "static const float %s[%d] = {", array_name, length); + + for (int n = 0; n < length; n++) { + if (n > 0) + fprintf(fp, ","); + fprintf(fp, (n % 8 != 0) ? " " : "\n\t"); + + if (quantize) + fprintf(fp, "%3d / 255.0", (int)(*(ptr++) * 255.0)); + else + fprintf(fp, "%1.8lf", *(ptr++)); + } + + fprintf(fp, "\n};\n"); +} + +static void write_csource(AreaOrtho *ortho, AreaDiag *diag, FILE *fp, bool subsampling, bool quantize) +{ + fprintf(fp, "/* This file was generated by smaa_areatex.cpp */\n"); + + fprintf(fp, "\n/* Horizontal/Vertical Areas */\n"); + write_double_array(fp, ortho->getData(), + TEX_SIZE_ORTHO * TEX_SIZE_ORTHO * 2 * (subsampling ? SUBSAMPLES_ORTHO : 1), + "areatex", quantize); + + fprintf(fp, "\n/* Diagonal Areas */\n"); + write_double_array(fp, diag->getData(), + TEX_SIZE_DIAG * TEX_SIZE_DIAG * 2 * (subsampling ? SUBSAMPLES_DIAG : 1), + "areatex_diag", quantize); +} + +/* .tga File (RGBA 32bit uncompressed) */ +static void write_tga(AreaOrtho *ortho, AreaDiag *diag, FILE *fp, bool subsampling) +{ + int subsamples = subsampling ? SUBSAMPLES_ORTHO : 1; + unsigned char header[18] = {0, 0, + 2, /* uncompressed RGB */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 32, /* 32bit */ + 8}; /* 8bit alpha, left to right, bottom to top */ + + /* Set width and height */ + header[12] = (TEX_SIZE_ORTHO + TEX_SIZE_DIAG) & 0xff; + header[13] = ((TEX_SIZE_ORTHO + TEX_SIZE_DIAG) >> 8) & 0xff; + header[14] = (subsamples * TEX_SIZE_ORTHO) & 0xff; + header[15] = ((subsamples * TEX_SIZE_ORTHO) >> 8) & 0xff; + + /* Write .tga header */ + fwrite(header, sizeof(unsigned char), sizeof(header) / sizeof(unsigned char), fp); + + /* Write pixel data */ + for (int i = subsamples - 1; i >= 0; i--) { + for (int y = TEX_SIZE_ORTHO - 1; y >= 0; y--) { + for (int x = 0; x < TEX_SIZE_ORTHO; x++) { + Dbl2 p = ortho->getPixel(i, Int2(x, y)); + fputc(0, fp); /* B */ + fputc((unsigned char)(p.y * 255.0), fp); /* G */ + fputc((unsigned char)(p.x * 255.0), fp); /* R */ + fputc(0, fp); /* A */ + } + + for (int x = 0; x < TEX_SIZE_DIAG; x++) { + if (i < SUBSAMPLES_DIAG) { + Dbl2 p = diag->getPixel(i, Int2(x, y)); + fputc(0, fp); /* B */ + fputc((unsigned char)(p.y * 255.0), fp); /* G */ + fputc((unsigned char)(p.x * 255.0), fp); /* R */ + fputc(0, fp); /* A */ + } + else { + fputc(0, fp); + fputc(0, fp); + fputc(0, fp); + fputc(0, fp); + } + } + } + } +} + +/* .raw File (R8G8 raw data) */ +static void write_raw(AreaOrtho *ortho, AreaDiag *diag, FILE *fp, bool subsampling) +{ + int subsamples = subsampling ? SUBSAMPLES_ORTHO : 1; + + /* Write pixel data */ + for (int i = 0; i < subsamples; i++) { + for (int y = 0; y < TEX_SIZE_ORTHO; y++) { + for (int x = 0; x < TEX_SIZE_ORTHO; x++) { + Dbl2 p = ortho->getPixel(i, Int2(x, y)); + fputc((unsigned char)(p.x * 255.0), fp); /* R */ + fputc((unsigned char)(p.y * 255.0), fp); /* G */ + } + + for (int x = 0; x < TEX_SIZE_DIAG; x++) { + if (i < SUBSAMPLES_DIAG) { + Dbl2 p = diag->getPixel(i, Int2(x, y)); + fputc((unsigned char)(p.x * 255.0), fp); /* R */ + fputc((unsigned char)(p.y * 255.0), fp); /* G */ + } + else { + fputc(0, fp); + fputc(0, fp); + } + } + } + } +} + +static int generate_file(AreaOrtho *ortho, AreaDiag *diag, const char *path, bool subsampling, bool quantize, bool tga, bool raw) +{ + FILE *fp = fopen(path, tga ? "wb" : "w"); + + if (!fp) { + fprintf(stderr, "Unable to open file: %s\n", path); + return 1; + } + + fprintf(stderr, "Generating %s\n", path); + + if (tga) + write_tga(ortho, diag, fp, subsampling); + else if (raw) + write_raw(ortho, diag, fp, subsampling); + else + write_csource(ortho, diag, fp, subsampling, quantize); + + fclose(fp); + + return 0; +} + +int main(int argc, char **argv) +{ + bool subsampling = false; + bool quantize = false; + bool tga = false; + bool raw = false; + bool compat = false; + bool numeric = false; + bool orig_u = false; + bool help = false; + char *outfile = NULL; + int status = 0; + + for (int i = 1; i < argc; i++) { + char *ptr = argv[i]; + if (*ptr++ == '-' && *ptr != '\0') { + char c; + while ((c = *ptr++) != '\0') { + if (c == 's') + subsampling = true; + else if (c == 'q') + quantize = true; + else if (c == 't') + tga = true; + else if (c == 'r') + raw = true; + else if (c == 'c') + compat = true; + else if (c == 'n') + numeric = true; + else if (c == 'u') + orig_u = true; + else if (c == 'h') + help = true; + else { + fprintf(stderr, "Unknown option: -%c\n", c); + status = 1; + break; + } + } + } + else if (outfile) { + fprintf(stderr, "Too much file names: %s, %s\n", outfile, argv[i]); + status = 1; + } + else + outfile = argv[i]; + + if (status != 0) + break; + } + + if (status == 0 && !help && !outfile) { + fprintf(stderr, "File name was not specified.\n"); + status = 1; + } + + if (status != 0 || help) { + fprintf(stderr, "Usage: %s [OPTION]... OUTFILE\n", argv[0]); + fprintf(stderr, "Options:\n"); + fprintf(stderr, " -s Calculate data for subpixel rendering\n"); + fprintf(stderr, " -q Quantize data to 256 levels\n"); + fprintf(stderr, " -t Write TGA image instead of C/C++ source\n"); + fprintf(stderr, " -r Write R8G8 raw image instead of C/C++ source\n"); + fprintf(stderr, " -c Generate compatible orthogonal data that subtexture size is 16\n"); + fprintf(stderr, " -n Numerically calculate diagonal data using brute force sampling\n"); + fprintf(stderr, " -u Process orthogonal / diagonal U patterns in older ways\n"); + fprintf(stderr, " -h Print this help and exit\n"); + fprintf(stderr, "File name OUTFILE usually should have an extension such as .c, .h, or .tga,\n"); + fprintf(stderr, "except for a special name '-' that means standard output.\n\n"); + fprintf(stderr, "Example:\n"); + fprintf(stderr, " Generate TGA file exactly same as AreaTexDX10.tga bundled with the\n"); + fprintf(stderr, " original implementation:\n\n"); + fprintf(stderr, " $ smaa_areatex -stcnu AreaTexDX10.tga\n\n"); + return status; + } + + AreaOrtho *ortho = new AreaOrtho(compat, orig_u); + AreaDiag *diag = new AreaDiag(numeric, orig_u); + + /* Calculate areatex data */ + for (int i = 0; i < (subsampling ? SUBSAMPLES_ORTHO : 1); i++) + ortho->areaTex(i); + + for (int i = 0; i < (subsampling ? SUBSAMPLES_DIAG : 1); i++) + diag->areaTex(i); + + /* Generate .tga, .raw, or C/C++ source file, or write the data to stdout */ + if (strcmp(outfile, "-") != 0) + status = generate_file(ortho, diag, outfile, subsampling, quantize, tga, raw); + else if (tga) + write_tga(ortho, diag, stdout, subsampling); + else if (raw) + write_raw(ortho, diag, stdout, subsampling); + else + write_csource(ortho, diag, stdout, subsampling, quantize); + + delete ortho; + delete diag; + + return status; +} + +/* smaa_areatex.cpp ends here */ diff --git a/intern/cycles/blender/blender_image.cpp b/intern/cycles/blender/blender_image.cpp index 459dc1779fb..3a9d159e461 100644 --- a/intern/cycles/blender/blender_image.cpp +++ b/intern/cycles/blender/blender_image.cpp @@ -29,7 +29,7 @@ BlenderImageLoader::BlenderImageLoader(BL::Image b_image, int frame) { } -bool BlenderImageLoader::load_metadata(ImageMetaData &metadata) +bool BlenderImageLoader::load_metadata(const ImageDeviceFeatures &, 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(ImageMetaData &metadata) +bool BlenderPointDensityLoader::load_metadata(const ImageDeviceFeatures &, ImageMetaData &metadata) { metadata.channels = 4; metadata.width = b_node.resolution(); diff --git a/intern/cycles/blender/blender_image.h b/intern/cycles/blender/blender_image.h index b58a159a6ba..fddbbfd9c37 100644 --- a/intern/cycles/blender/blender_image.h +++ b/intern/cycles/blender/blender_image.h @@ -27,7 +27,7 @@ class BlenderImageLoader : public ImageLoader { public: BlenderImageLoader(BL::Image b_image, int frame); - bool load_metadata(ImageMetaData &metadata) override; + bool load_metadata(const ImageDeviceFeatures &features, 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(ImageMetaData &metadata) override; + bool load_metadata(const ImageDeviceFeatures &features, ImageMetaData &metadata) override; bool load_pixels(const ImageMetaData &metadata, void *pixels, const size_t pixels_size, diff --git a/intern/cycles/blender/blender_mesh.cpp b/intern/cycles/blender/blender_mesh.cpp index c7b49354d53..11158532738 100644 --- a/intern/cycles/blender/blender_mesh.cpp +++ b/intern/cycles/blender/blender_mesh.cpp @@ -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_POLYGON: + case BL::Attribute::domain_FACE: element = ATTR_ELEMENT_FACE; break; default: diff --git a/intern/cycles/blender/blender_volume.cpp b/intern/cycles/blender/blender_volume.cpp index 410f7a72cf5..0ff4de846e1 100644 --- a/intern/cycles/blender/blender_volume.cpp +++ b/intern/cycles/blender/blender_volume.cpp @@ -41,7 +41,7 @@ class BlenderSmokeLoader : public ImageLoader { mesh_texture_space(b_mesh, texspace_loc, texspace_size); } - bool load_metadata(ImageMetaData &metadata) override + bool load_metadata(const ImageDeviceFeatures &, ImageMetaData &metadata) override { if (!b_domain) { return false; diff --git a/intern/cycles/device/device.cpp b/intern/cycles/device/device.cpp index 94732cd1855..ed53fbb54ae 100644 --- a/intern/cycles/device/device.cpp +++ b/intern/cycles/device/device.cpp @@ -619,6 +619,7 @@ 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; @@ -665,6 +666,7 @@ 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; diff --git a/intern/cycles/device/device.h b/intern/cycles/device/device.h index 0a731969c79..b5468248e5a 100644 --- a/intern/cycles/device/device.h +++ b/intern/cycles/device/device.h @@ -78,6 +78,7 @@ 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. */ @@ -99,6 +100,7 @@ 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; diff --git a/intern/cycles/device/device_cpu.cpp b/intern/cycles/device/device_cpu.cpp index e2f9c7391da..0e3c771dbc3 100644 --- a/intern/cycles/device/device_cpu.cpp +++ b/intern/cycles/device/device_cpu.cpp @@ -1654,6 +1654,7 @@ 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()) { diff --git a/intern/cycles/device/device_cuda.cpp b/intern/cycles/device/device_cuda.cpp index d9ffcceb06e..2e225ecfaf8 100644 --- a/intern/cycles/device/device_cuda.cpp +++ b/intern/cycles/device/device_cuda.cpp @@ -128,6 +128,7 @@ 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; diff --git a/intern/cycles/device/device_multi.cpp b/intern/cycles/device/device_multi.cpp index b272e59f99d..35faadcbec5 100644 --- a/intern/cycles/device/device_multi.cpp +++ b/intern/cycles/device/device_multi.cpp @@ -46,10 +46,13 @@ 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) + : Device(info, stats, profiler, background_), + unique_key(1), + use_denoising(!info.denoising_devices.empty()) { foreach (DeviceInfo &subinfo, info.multi_devices) { /* Always add CPU devices at the back since GPU devices can change @@ -194,6 +197,7 @@ 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; @@ -400,7 +404,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) { + if (strcmp(mem.name, "RenderBuffers") == 0 && use_denoising) { foreach (SubDevice &sub, devices) { mem.device = sub.device; mem.device_pointer = (existing_key) ? sub.ptr_map[existing_key] : 0; @@ -466,7 +470,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) { + if (strcmp(mem.name, "RenderBuffers") == 0 && use_denoising) { vector<device_ptr> device_pointers; device_pointers.reserve(devices.size()); @@ -518,7 +522,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 (strcmp(mem.name, "RenderBuffers") == 0 || mem.type == MEM_PIXELS) { + if (mem.type == MEM_PIXELS || (strcmp(mem.name, "RenderBuffers") == 0 && use_denoising)) { foreach (SubDevice &sub, devices) { mem.device = sub.device; mem.device_pointer = sub.ptr_map[key]; diff --git a/intern/cycles/device/device_opencl.cpp b/intern/cycles/device/device_opencl.cpp index 11376ee4883..9abb7cfb7fe 100644 --- a/intern/cycles/device/device_opencl.cpp +++ b/intern/cycles/device/device_opencl.cpp @@ -126,6 +126,9 @@ 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++; } diff --git a/intern/cycles/device/opencl/device_opencl_impl.cpp b/intern/cycles/device/opencl/device_opencl_impl.cpp index aee3b0fb64f..d378d32914c 100644 --- a/intern/cycles/device/opencl/device_opencl_impl.cpp +++ b/intern/cycles/device/opencl/device_opencl_impl.cpp @@ -2036,7 +2036,9 @@ string OpenCLDevice::kernel_build_options(const string *debug_src) # endif # ifdef WITH_NANOVDB - build_options += "-DWITH_NANOVDB "; + if (info.has_nanovdb) { + build_options += "-DWITH_NANOVDB "; + } # endif return build_options; diff --git a/intern/cycles/kernel/svm/svm_math_util.h b/intern/cycles/kernel/svm/svm_math_util.h index 389c44ab1da..19fb1da5a1f 100644 --- a/intern/cycles/kernel/svm/svm_math_util.h +++ b/intern/cycles/kernel/svm/svm_math_util.h @@ -242,12 +242,15 @@ 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]; diff --git a/intern/cycles/render/alembic.cpp b/intern/cycles/render/alembic.cpp index 1336f81896a..c3a7b20f512 100644 --- a/intern/cycles/render/alembic.cpp +++ b/intern/cycles/render/alembic.cpp @@ -1407,6 +1407,15 @@ 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); @@ -1586,6 +1595,11 @@ 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()); @@ -1653,6 +1667,11 @@ 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()) { @@ -1743,6 +1762,11 @@ 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()); diff --git a/intern/cycles/render/alembic.h b/intern/cycles/render/alembic.h index d0c5856a353..3bbd10fad61 100644 --- a/intern/cycles/render/alembic.h +++ b/intern/cycles/render/alembic.h @@ -239,6 +239,7 @@ template<typename T> class DataStore { { invalidate_last_loaded_time(); data.clear(); + index_data_map.clear(); } void invalidate_last_loaded_time() @@ -480,16 +481,23 @@ class AlembicProcedural : public Procedural { * invocation, and updates the data on subsequent invocations if the frame changed. */ void generate(Scene *scene, Progress &progress); - /* 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. */ + /* 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); + /* Load the data for all the objects whose data has not yet been loaded. */ void load_objects(Progress &progress); diff --git a/intern/cycles/render/background.cpp b/intern/cycles/render/background.cpp index b3d383afae4..f0a779da012 100644 --- a/intern/cycles/render/background.cpp +++ b/intern/cycles/render/background.cpp @@ -130,6 +130,14 @@ 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); } diff --git a/intern/cycles/render/geometry.cpp b/intern/cycles/render/geometry.cpp index 124a41db21e..8b0c0d94155 100644 --- a/intern/cycles/render/geometry.cpp +++ b/intern/cycles/render/geometry.cpp @@ -1584,7 +1584,6 @@ 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(); diff --git a/intern/cycles/render/image.cpp b/intern/cycles/render/image.cpp index 29a95beaf7e..27f9b7df1dd 100644 --- a/intern/cycles/render/image.cpp +++ b/intern/cycles/render/image.cpp @@ -303,7 +303,8 @@ ImageManager::ImageManager(const DeviceInfo &info) animation_frame = 0; /* Set image limits */ - has_half_images = info.has_half_images; + features.has_half_float = info.has_half_images; + features.has_nanovdb = info.has_nanovdb; } ImageManager::~ImageManager() @@ -347,7 +348,7 @@ void ImageManager::load_image_metadata(Image *img) metadata = ImageMetaData(); metadata.colorspace = img->params.colorspace; - if (img->loader->load_metadata(metadata)) { + if (img->loader->load_metadata(features, metadata)) { assert(metadata.type != IMAGE_DATA_NUM_TYPES); } else { @@ -356,15 +357,10 @@ void ImageManager::load_image_metadata(Image *img) metadata.detect_colorspace(); - /* 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; - } - } + 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)); img->need_metadata = false; } diff --git a/intern/cycles/render/image.h b/intern/cycles/render/image.h index c802521db56..dede9513d5f 100644 --- a/intern/cycles/render/image.h +++ b/intern/cycles/render/image.h @@ -97,6 +97,13 @@ 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 { @@ -105,7 +112,7 @@ class ImageLoader { virtual ~ImageLoader(){}; /* Load metadata without actual image yet, should be fast. */ - virtual bool load_metadata(ImageMetaData &metadata) = 0; + virtual bool load_metadata(const ImageDeviceFeatures &features, ImageMetaData &metadata) = 0; /* Load actual image contents. */ virtual bool load_pixels(const ImageMetaData &metadata, @@ -212,7 +219,8 @@ class ImageManager { private: bool need_update_; - bool has_half_images; + + ImageDeviceFeatures features; thread_mutex device_mutex; thread_mutex images_mutex; diff --git a/intern/cycles/render/image_oiio.cpp b/intern/cycles/render/image_oiio.cpp index e9c87461822..4867efe6ac0 100644 --- a/intern/cycles/render/image_oiio.cpp +++ b/intern/cycles/render/image_oiio.cpp @@ -30,7 +30,7 @@ OIIOImageLoader::~OIIOImageLoader() { } -bool OIIOImageLoader::load_metadata(ImageMetaData &metadata) +bool OIIOImageLoader::load_metadata(const ImageDeviceFeatures &features, ImageMetaData &metadata) { /* Perform preliminary checks, with meaningful logging. */ if (!path_exists(filepath.string())) { @@ -76,7 +76,7 @@ bool OIIOImageLoader::load_metadata(ImageMetaData &metadata) } /* check if it's half float */ - if (spec.format == TypeDesc::HALF) { + if (spec.format == TypeDesc::HALF && features.has_half_float) { is_half = true; } diff --git a/intern/cycles/render/image_oiio.h b/intern/cycles/render/image_oiio.h index a234b968557..a6dbb168b65 100644 --- a/intern/cycles/render/image_oiio.h +++ b/intern/cycles/render/image_oiio.h @@ -26,7 +26,7 @@ class OIIOImageLoader : public ImageLoader { OIIOImageLoader(const string &filepath); ~OIIOImageLoader(); - bool load_metadata(ImageMetaData &metadata) override; + bool load_metadata(const ImageDeviceFeatures &features, ImageMetaData &metadata) override; bool load_pixels(const ImageMetaData &metadata, void *pixels, diff --git a/intern/cycles/render/image_sky.cpp b/intern/cycles/render/image_sky.cpp index 0560907c63e..7f9b85836f8 100644 --- a/intern/cycles/render/image_sky.cpp +++ b/intern/cycles/render/image_sky.cpp @@ -40,7 +40,7 @@ SkyLoader::SkyLoader(float sun_elevation, SkyLoader::~SkyLoader(){}; -bool SkyLoader::load_metadata(ImageMetaData &metadata) +bool SkyLoader::load_metadata(const ImageDeviceFeatures &, ImageMetaData &metadata) { metadata.width = 512; metadata.height = 128; diff --git a/intern/cycles/render/image_sky.h b/intern/cycles/render/image_sky.h index 686f4e5b885..89ff586e7fd 100644 --- a/intern/cycles/render/image_sky.h +++ b/intern/cycles/render/image_sky.h @@ -34,7 +34,7 @@ class SkyLoader : public ImageLoader { float ozone_density); ~SkyLoader(); - bool load_metadata(ImageMetaData &metadata) override; + bool load_metadata(const ImageDeviceFeatures &features, ImageMetaData &metadata) override; bool load_pixels(const ImageMetaData &metadata, void *pixels, diff --git a/intern/cycles/render/image_vdb.cpp b/intern/cycles/render/image_vdb.cpp index 70b3de5a939..63e6214f1c8 100644 --- a/intern/cycles/render/image_vdb.cpp +++ b/intern/cycles/render/image_vdb.cpp @@ -34,7 +34,7 @@ VDBImageLoader::~VDBImageLoader() { } -bool VDBImageLoader::load_metadata(ImageMetaData &metadata) +bool VDBImageLoader::load_metadata(const ImageDeviceFeatures &features, ImageMetaData &metadata) { #ifdef WITH_OPENVDB if (!grid) { @@ -56,55 +56,71 @@ bool VDBImageLoader::load_metadata(ImageMetaData &metadata) if (grid->isType<openvdb::FloatGrid>()) { metadata.channels = 1; # ifdef WITH_NANOVDB - nanogrid = nanovdb::openToNanoVDB(*openvdb::gridConstPtrCast<openvdb::FloatGrid>(grid)); + if (features.has_nanovdb) { + nanogrid = nanovdb::openToNanoVDB(*openvdb::gridConstPtrCast<openvdb::FloatGrid>(grid)); + } # endif } else if (grid->isType<openvdb::Vec3fGrid>()) { metadata.channels = 3; # ifdef WITH_NANOVDB - nanogrid = nanovdb::openToNanoVDB(*openvdb::gridConstPtrCast<openvdb::Vec3fGrid>(grid)); + if (features.has_nanovdb) { + nanogrid = nanovdb::openToNanoVDB(*openvdb::gridConstPtrCast<openvdb::Vec3fGrid>(grid)); + } # endif } else if (grid->isType<openvdb::BoolGrid>()) { metadata.channels = 1; # ifdef WITH_NANOVDB - nanogrid = nanovdb::openToNanoVDB( - openvdb::FloatGrid(*openvdb::gridConstPtrCast<openvdb::BoolGrid>(grid))); + if (features.has_nanovdb) { + nanogrid = nanovdb::openToNanoVDB( + openvdb::FloatGrid(*openvdb::gridConstPtrCast<openvdb::BoolGrid>(grid))); + } # endif } else if (grid->isType<openvdb::DoubleGrid>()) { metadata.channels = 1; # ifdef WITH_NANOVDB - nanogrid = nanovdb::openToNanoVDB( - openvdb::FloatGrid(*openvdb::gridConstPtrCast<openvdb::DoubleGrid>(grid))); + if (features.has_nanovdb) { + nanogrid = nanovdb::openToNanoVDB( + openvdb::FloatGrid(*openvdb::gridConstPtrCast<openvdb::DoubleGrid>(grid))); + } # endif } else if (grid->isType<openvdb::Int32Grid>()) { metadata.channels = 1; # ifdef WITH_NANOVDB - nanogrid = nanovdb::openToNanoVDB( - openvdb::FloatGrid(*openvdb::gridConstPtrCast<openvdb::Int32Grid>(grid))); + if (features.has_nanovdb) { + nanogrid = nanovdb::openToNanoVDB( + openvdb::FloatGrid(*openvdb::gridConstPtrCast<openvdb::Int32Grid>(grid))); + } # endif } else if (grid->isType<openvdb::Int64Grid>()) { metadata.channels = 1; # ifdef WITH_NANOVDB - nanogrid = nanovdb::openToNanoVDB( - openvdb::FloatGrid(*openvdb::gridConstPtrCast<openvdb::Int64Grid>(grid))); + if (features.has_nanovdb) { + nanogrid = nanovdb::openToNanoVDB( + openvdb::FloatGrid(*openvdb::gridConstPtrCast<openvdb::Int64Grid>(grid))); + } # endif } else if (grid->isType<openvdb::Vec3IGrid>()) { metadata.channels = 3; # ifdef WITH_NANOVDB - nanogrid = nanovdb::openToNanoVDB( - openvdb::Vec3fGrid(*openvdb::gridConstPtrCast<openvdb::Vec3IGrid>(grid))); + if (features.has_nanovdb) { + nanogrid = nanovdb::openToNanoVDB( + openvdb::Vec3fGrid(*openvdb::gridConstPtrCast<openvdb::Vec3IGrid>(grid))); + } # endif } else if (grid->isType<openvdb::Vec3dGrid>()) { metadata.channels = 3; # ifdef WITH_NANOVDB - nanogrid = nanovdb::openToNanoVDB( - openvdb::Vec3fGrid(*openvdb::gridConstPtrCast<openvdb::Vec3dGrid>(grid))); + if (features.has_nanovdb) { + nanogrid = nanovdb::openToNanoVDB( + openvdb::Vec3fGrid(*openvdb::gridConstPtrCast<openvdb::Vec3dGrid>(grid))); + } # endif } else if (grid->isType<openvdb::MaskGrid>()) { @@ -118,21 +134,25 @@ bool VDBImageLoader::load_metadata(ImageMetaData &metadata) } # ifdef WITH_NANOVDB - 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; + 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; + } } + 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(); @@ -143,13 +163,18 @@ bool VDBImageLoader::load_metadata(ImageMetaData &metadata) } } + Transform texture_to_index; # ifdef WITH_NANOVDB - 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()); + if (nanogrid) { + texture_to_index = transform_identity(); + } + else # 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; @@ -165,48 +190,52 @@ bool VDBImageLoader::load_pixels(const ImageMetaData &, void *pixels, const size { #ifdef WITH_OPENVDB # ifdef WITH_NANOVDB - 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); + if (nanogrid) { + memcpy(pixels, nanogrid.data(), nanogrid.size()); } + 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; diff --git a/intern/cycles/render/image_vdb.h b/intern/cycles/render/image_vdb.h index 71d10cc39f5..763196f2a15 100644 --- a/intern/cycles/render/image_vdb.h +++ b/intern/cycles/render/image_vdb.h @@ -33,7 +33,8 @@ class VDBImageLoader : public ImageLoader { VDBImageLoader(const string &grid_name); ~VDBImageLoader(); - virtual bool load_metadata(ImageMetaData &metadata) override; + virtual bool load_metadata(const ImageDeviceFeatures &features, + ImageMetaData &metadata) override; virtual bool load_pixels(const ImageMetaData &metadata, void *pixels, diff --git a/intern/cycles/render/object.cpp b/intern/cycles/render/object.cpp index 52f63685aeb..8b3ac31cf8b 100644 --- a/intern/cycles/render/object.cpp +++ b/intern/cycles/render/object.cpp @@ -153,10 +153,6 @@ 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()) { diff --git a/intern/ghost/intern/GHOST_IconX11.h b/intern/ghost/intern/GHOST_IconX11.h index 615a7dae6b5..403d611b71d 100644 --- a/intern/ghost/intern/GHOST_IconX11.h +++ b/intern/ghost/intern/GHOST_IconX11.h @@ -24,7 +24,8 @@ #pragma once -/* +/** + * \code{.py} * import bpy * import textwrap * @@ -42,6 +43,7 @@ * print("%d,%d," % (w, h)) * text = ", ".join(["0x%x" % p for p in pixels]) * print(textwrap.fill(text, width=120), end=",\n") + * \endcode */ /** diff --git a/intern/ghost/intern/GHOST_WindowWin32.cpp b/intern/ghost/intern/GHOST_WindowWin32.cpp index 70901954df2..28ce1381562 100644 --- a/intern/ghost/intern/GHOST_WindowWin32.cpp +++ b/intern/ghost/intern/GHOST_WindowWin32.cpp @@ -533,11 +533,18 @@ GHOST_TSuccess GHOST_WindowWin32::setState(GHOST_TWindowState state) wp.showCmd = SW_SHOWMAXIMIZED; wp.ptMaxPosition.x = 0; wp.ptMaxPosition.y = 0; - style &= ~WS_CAPTION; + style &= ~(WS_CAPTION | WS_MAXIMIZE); break; case GHOST_kWindowStateNormal: default: - wp.showCmd = SW_SHOWNORMAL; + if (curstate == GHOST_kWindowStateFullScreen && + m_normal_state == GHOST_kWindowStateMaximized) { + wp.showCmd = SW_SHOWMAXIMIZED; + m_normal_state = GHOST_kWindowStateNormal; + } + else { + wp.showCmd = SW_SHOWNORMAL; + } break; } ::SetWindowLongPtr(m_hWnd, GWL_STYLE, style); diff --git a/release/scripts/addons b/release/scripts/addons -Subproject bcd08a9506d33bdd7358201031b04d041ef22d9 +Subproject 63492d3d0334e1827f611f8fe5a931f3ccbddfc diff --git a/release/scripts/modules/addon_utils.py b/release/scripts/modules/addon_utils.py index 83bed69d8d2..387691f9f05 100644 --- a/release/scripts/modules/addon_utils.py +++ b/release/scripts/modules/addon_utils.py @@ -349,6 +349,10 @@ 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: diff --git a/release/scripts/modules/animsys_refactor.py b/release/scripts/modules/animsys_refactor.py index 97e8a8dd144..fd4952e2a53 100644 --- a/release/scripts/modules/animsys_refactor.py +++ b/release/scripts/modules/animsys_refactor.py @@ -32,12 +32,6 @@ 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] @@ -66,7 +60,7 @@ class DataPathBuilder: if type(key) is int: str_value = '[%d]' % key elif type(key) is str: - str_value = '[%s]' % drepr(key) + str_value = '["%s"]' % bpy.utils.escape_identifier(key) else: raise Exception("unsupported accessor %r of type %r (internal error)" % (key, type(key))) return DataPathBuilder(self.data_path + (str_value, )) diff --git a/release/scripts/modules/bl_rna_utils/__init__.py b/release/scripts/modules/bl_rna_utils/__init__.py new file mode 100644 index 00000000000..e69de29bb2d --- /dev/null +++ b/release/scripts/modules/bl_rna_utils/__init__.py diff --git a/release/scripts/modules/bl_rna_utils/data_path.py b/release/scripts/modules/bl_rna_utils/data_path.py new file mode 100644 index 00000000000..42942b7a295 --- /dev/null +++ b/release/scripts/modules/bl_rna_utils/data_path.py @@ -0,0 +1,91 @@ +# ##### 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 diff --git a/release/scripts/presets/keyconfig/keymap_data/blender_default.py b/release/scripts/presets/keyconfig/keymap_data/blender_default.py index 2fb0e9a0bea..68e273f2244 100644 --- a/release/scripts/presets/keyconfig/keymap_data/blender_default.py +++ b/release/scripts/presets/keyconfig/keymap_data/blender_default.py @@ -1694,6 +1694,7 @@ 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), diff --git a/release/scripts/startup/bl_operators/anim.py b/release/scripts/startup/bl_operators/anim.py index 8ec9bececc5..81a28964389 100644 --- a/release/scripts/startup/bl_operators/anim.py +++ b/release/scripts/startup/bl_operators/anim.py @@ -355,7 +355,8 @@ class UpdateAnimatedTransformConstraint(Operator): use_convert_to_radians: BoolProperty( name="Convert to Radians", - description="Convert fcurves/drivers affecting rotations to radians (Warning: use this only once!)", + description="Convert f-curves/drivers affecting rotations to radians.\n" + "Warning: Use this only once", default=True, ) @@ -430,22 +431,9 @@ 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, ) diff --git a/release/scripts/startup/bl_operators/wm.py b/release/scripts/startup/bl_operators/wm.py index 2f97942faa4..35826cea860 100644 --- a/release/scripts/startup/bl_operators/wm.py +++ b/release/scripts/startup/bl_operators/wm.py @@ -95,6 +95,76 @@ 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 @@ -120,12 +190,9 @@ def operator_value_is_undo(value): def operator_path_is_undo(context, 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] + data_path_head, _, _ = context_path_decompose(data_path) + # When we can't find the data owner assume no undo is needed. if not data_path_head: return False @@ -168,6 +235,10 @@ 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 @@ -185,6 +256,10 @@ 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 @@ -201,6 +276,10 @@ 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: @@ -235,6 +314,10 @@ 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: @@ -274,6 +357,10 @@ 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 @@ -290,6 +377,10 @@ 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 @@ -306,6 +397,10 @@ 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 @@ -322,6 +417,10 @@ 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: @@ -339,6 +438,13 @@ 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 @@ -375,6 +481,11 @@ 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 @@ -406,6 +517,10 @@ 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) @@ -442,6 +557,10 @@ 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) @@ -450,22 +569,11 @@ class WM_OT_context_cycle_enum(Operator): orig_value = value - # 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] - + rna_prop = context_path_to_rna_property(context, data_path) if type(rna_prop) != bpy.types.EnumProperty: raise Exception("expected an enum property") - enums = rna_struct.properties[rna_prop_str].enum_items.keys() + enums = rna_prop.enum_items.keys() orig_index = enums.index(orig_value) # Have the info we need, advance to the next item. @@ -498,6 +606,10 @@ 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) @@ -523,6 +635,10 @@ 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) @@ -530,15 +646,15 @@ class WM_OT_context_menu_enum(Operator): if value is Ellipsis: return {'PASS_THROUGH'} - base_path, prop_string = data_path.rsplit(".", 1) + base_path, prop_attr, _ = context_path_decompose(data_path) value_base = context_path_validate(context, base_path) - prop = value_base.bl_rna.properties[prop_string] + rna_prop = context_path_to_rna_property(context, data_path) def draw_cb(self, context): layout = self.layout - layout.prop(value_base, prop_string, expand=True) + layout.prop(value_base, prop_attr, expand=True) - context.window_manager.popup_menu(draw_func=draw_cb, title=prop.name, icon=prop.icon) + context.window_manager.popup_menu(draw_func=draw_cb, title=rna_prop.name, icon=rna_prop.icon) return {'FINISHED'} @@ -550,6 +666,10 @@ 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 @@ -558,15 +678,15 @@ class WM_OT_context_pie_enum(Operator): if value is Ellipsis: return {'PASS_THROUGH'} - base_path, prop_string = data_path.rsplit(".", 1) + base_path, prop_attr, _ = context_path_decompose(data_path) value_base = context_path_validate(context, base_path) - prop = value_base.bl_rna.properties[prop_string] + rna_prop = context_path_to_rna_property(context, data_path) def draw_cb(self, context): layout = self.layout - layout.prop(value_base, prop_string, expand=True) + layout.prop(value_base, prop_attr, expand=True) - wm.popup_menu_pie(draw_func=draw_cb, title=prop.name, icon=prop.icon, event=event) + wm.popup_menu_pie(draw_func=draw_cb, title=rna_prop.name, icon=rna_prop.icon, event=event) return {'FINISHED'} @@ -587,11 +707,15 @@ 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_string = self.prop_string + prop_attr = self.prop_string # same as eval("bpy.ops." + data_path) op_mod_str, ob_id_str = data_path.split(".", 1) @@ -607,7 +731,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_string) + pie.operator_enum(data_path, prop_attr) wm.popup_menu_pie(draw_func=draw_cb, title=op_rna.name, event=event) @@ -631,17 +755,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. - 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 + + rna_prop = context_path_to_rna_property(context, data_path) + rna_prop_fixed_type = rna_prop.fixed_type id_iter = None for prop in bpy.data.rna_type.properties: if prop.rna_type.identifier == "CollectionProperty": - if prop.fixed_type == data_prop_rna_type: + if prop.fixed_type == rna_prop_fixed_type: id_iter = prop.identifier break diff --git a/release/scripts/startup/bl_ui/properties_collection.py b/release/scripts/startup/bl_ui/properties_collection.py index 186314f9591..c5c35121135 100644 --- a/release/scripts/startup/bl_ui/properties_collection.py +++ b/release/scripts/startup/bl_ui/properties_collection.py @@ -77,6 +77,7 @@ 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 diff --git a/release/scripts/startup/bl_ui/properties_data_armature.py b/release/scripts/startup/bl_ui/properties_data_armature.py index 4cdcab45926..87572fcd438 100644 --- a/release/scripts/startup/bl_ui/properties_data_armature.py +++ b/release/scripts/startup/bl_ui/properties_data_armature.py @@ -86,12 +86,19 @@ 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" diff --git a/release/scripts/startup/bl_ui/properties_material.py b/release/scripts/startup/bl_ui/properties_material.py index d85078d4ec2..aca7ba3c5ad 100644 --- a/release/scripts/startup/bl_ui/properties_material.py +++ b/release/scripts/startup/bl_ui/properties_material.py @@ -277,6 +277,7 @@ 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): diff --git a/release/scripts/startup/bl_ui/properties_object.py b/release/scripts/startup/bl_ui/properties_object.py index b74100aa570..033e6196323 100644 --- a/release/scripts/startup/bl_ui/properties_object.py +++ b/release/scripts/startup/bl_ui/properties_object.py @@ -311,6 +311,7 @@ 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): diff --git a/release/scripts/startup/bl_ui/properties_physics_common.py b/release/scripts/startup/bl_ui/properties_physics_common.py index 82f43790d72..4ddb4953fbd 100644 --- a/release/scripts/startup/bl_ui/properties_physics_common.py +++ b/release/scripts/startup/bl_ui/properties_physics_common.py @@ -74,10 +74,6 @@ 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 diff --git a/release/scripts/startup/bl_ui/space_dopesheet.py b/release/scripts/startup/bl_ui/space_dopesheet.py index 84f83559da6..e7893b8c448 100644 --- a/release/scripts/startup/bl_ui/space_dopesheet.py +++ b/release/scripts/startup/bl_ui/space_dopesheet.py @@ -348,8 +348,6 @@ 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") diff --git a/release/scripts/startup/bl_ui/space_graph.py b/release/scripts/startup/bl_ui/space_graph.py index 9ba3bd8f8cc..f8521592dd9 100644 --- a/release/scripts/startup/bl_ui/space_graph.py +++ b/release/scripts/startup/bl_ui/space_graph.py @@ -18,7 +18,6 @@ # <pep8 compliant> -import bpy from bpy.types import Header, Menu, Panel from bl_ui.space_dopesheet import ( DopesheetFilterPopoverBase, @@ -120,10 +119,6 @@ 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': diff --git a/release/scripts/startup/bl_ui/space_node.py b/release/scripts/startup/bl_ui/space_node.py index a85dd70e8f4..d8cfa9dcc82 100644 --- a/release/scripts/startup/bl_ui/space_node.py +++ b/release/scripts/startup/bl_ui/space_node.py @@ -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 = "Item" + bl_category = "Node" 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 = "Item" + bl_category = "Node" 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 = "Item" + bl_category = "Node" 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 = "Item" + bl_category = "Node" bl_label = "Texture Mapping" bl_options = {'DEFAULT_CLOSED'} COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_WORKBENCH'} diff --git a/release/scripts/startup/bl_ui/space_topbar.py b/release/scripts/startup/bl_ui/space_topbar.py index 7219922c379..adab0b0c88a 100644 --- a/release/scripts/startup/bl_ui/space_topbar.py +++ b/release/scripts/startup/bl_ui/space_topbar.py @@ -469,6 +469,8 @@ class TOPBAR_MT_file_import(Menu): if bpy.app.build_options.alembic: self.layout.operator("wm.alembic_import", text="Alembic (.abc)") + self.layout.operator("wm.gpencil_import_svg", text="SVG as Grease Pencil") + class TOPBAR_MT_file_export(Menu): bl_idname = "TOPBAR_MT_file_export" @@ -485,6 +487,13 @@ class TOPBAR_MT_file_export(Menu): self.layout.operator( "wm.usd_export", text="Universal Scene Description (.usd, .usdc, .usda)") + # Pugixml lib dependency + if bpy.app.build_options.pugixml: + self.layout.operator("wm.gpencil_export_svg", text="Grease Pencil as SVG") + # Haru lib dependency + if bpy.app.build_options.haru: + self.layout.operator("wm.gpencil_export_pdf", text="Grease Pencil as PDF") + class TOPBAR_MT_file_external_data(Menu): bl_label = "External Data" diff --git a/release/scripts/startup/bl_ui/space_userpref.py b/release/scripts/startup/bl_ui/space_userpref.py index 96695ff1be5..f44cf23fb58 100644 --- a/release/scripts/startup/bl_ui/space_userpref.py +++ b/release/scripts/startup/bl_ui/space_userpref.py @@ -2244,6 +2244,7 @@ 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")), ), ) diff --git a/release/scripts/startup/bl_ui/space_view3d_toolbar.py b/release/scripts/startup/bl_ui/space_view3d_toolbar.py index 72baa5331bf..831fc06eda5 100644 --- a/release/scripts/startup/bl_ui/space_view3d_toolbar.py +++ b/release/scripts/startup/bl_ui/space_view3d_toolbar.py @@ -622,9 +622,15 @@ class VIEW3D_PT_tools_brush_texture(Panel, View3DPaintPanel): @classmethod def poll(cls, context): - settings = cls.paint_settings(context) - return (settings and settings.brush and - (context.sculpt_object or context.image_paint_object or context.vertex_paint_object)) + 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 def draw(self, context): layout = self.layout diff --git a/release/scripts/startup/nodeitems_builtins.py b/release/scripts/startup/nodeitems_builtins.py index febb31af188..7e887caf3f2 100644 --- a/release/scripts/startup/nodeitems_builtins.py +++ b/release/scripts/startup/nodeitems_builtins.py @@ -368,6 +368,7 @@ compositor_node_categories = [ NodeItem("CompositorNodePixelate"), NodeItem("CompositorNodeSunBeams"), NodeItem("CompositorNodeDenoise"), + NodeItem("CompositorNodeAntiAliasing"), ]), CompositorNodeCategory("CMP_OP_VECTOR", "Vector", items=[ NodeItem("CompositorNodeNormal"), @@ -484,6 +485,7 @@ geometry_node_categories = [ GeometryNodeCategory("GEO_ATTRIBUTE", "Attribute", items=[ NodeItem("GeometryNodeAttributeRandomize"), NodeItem("GeometryNodeAttributeMath"), + NodeItem("GeometryNodeAttributeClamp"), NodeItem("GeometryNodeAttributeCompare"), NodeItem("GeometryNodeAttributeConvert"), NodeItem("GeometryNodeAttributeFill"), @@ -495,6 +497,7 @@ geometry_node_categories = [ NodeItem("GeometryNodeAttributeCombineXYZ"), NodeItem("GeometryNodeAttributeSeparateXYZ"), NodeItem("GeometryNodeAttributeRemove"), + NodeItem("GeometryNodeAttributeMapRange"), ]), GeometryNodeCategory("GEO_COLOR", "Color", items=[ NodeItem("ShaderNodeValToRGB"), @@ -520,7 +523,16 @@ 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"), @@ -531,20 +543,6 @@ 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"), @@ -558,6 +556,10 @@ 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"), diff --git a/release/scripts/templates_osl/basic_shader.osl b/release/scripts/templates_osl/basic_shader.osl new file mode 100644 index 00000000000..3c5240a1bbd --- /dev/null +++ b/release/scripts/templates_osl/basic_shader.osl @@ -0,0 +1,10 @@ +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; +} diff --git a/release/scripts/templates_py/image_processing.py b/release/scripts/templates_py/image_processing.py new file mode 100644 index 00000000000..2392faf440c --- /dev/null +++ b/release/scripts/templates_py/image_processing.py @@ -0,0 +1,35 @@ +# 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() diff --git a/source/blender/blendthumb/CMakeLists.txt b/source/blender/blendthumb/CMakeLists.txt index cb121cb9c8d..b42ca284ecb 100644 --- a/source/blender/blendthumb/CMakeLists.txt +++ b/source/blender/blendthumb/CMakeLists.txt @@ -31,6 +31,7 @@ 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( diff --git a/source/blender/blenkernel/BKE_action.h b/source/blender/blenkernel/BKE_action.h index 717cfa607ad..e27cb2be8ee 100644 --- a/source/blender/blenkernel/BKE_action.h +++ b/source/blender/blenkernel/BKE_action.h @@ -188,10 +188,6 @@ 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 */ @@ -227,6 +223,9 @@ 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 diff --git a/source/blender/blenkernel/BKE_armature.h b/source/blender/blenkernel/BKE_armature.h index a0ba1415b41..0bd817f0da1 100644 --- a/source/blender/blenkernel/BKE_armature.h +++ b/source/blender/blenkernel/BKE_armature.h @@ -342,6 +342,8 @@ 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) { \ diff --git a/source/blender/blenkernel/BKE_attribute.h b/source/blender/blenkernel/BKE_attribute.h index a98bfd1e3df..30a595dba8e 100644 --- a/source/blender/blenkernel/BKE_attribute.h +++ b/source/blender/blenkernel/BKE_attribute.h @@ -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_POLYGON = 3, /* Mesh Polygon */ - 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_FACE = 3, /* Mesh Face */ + ATTR_DOMAIN_CURVE = 4, /* Hair Curve */ ATTR_DOMAIN_NUM } AttributeDomain; diff --git a/source/blender/blenkernel/BKE_blender_version.h b/source/blender/blenkernel/BKE_blender_version.h index c9585430ae2..0fcc2fe8f46 100644 --- a/source/blender/blenkernel/BKE_blender_version.h +++ b/source/blender/blenkernel/BKE_blender_version.h @@ -39,7 +39,7 @@ extern "C" { /* Blender file format version. */ #define BLENDER_FILE_VERSION BLENDER_VERSION -#define BLENDER_FILE_SUBVERSION 14 +#define BLENDER_FILE_SUBVERSION 15 /* 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 diff --git a/source/blender/blenkernel/BKE_displist.h b/source/blender/blenkernel/BKE_displist.h index 05e60d38487..1883cebe203 100644 --- a/source/blender/blenkernel/BKE_displist.h +++ b/source/blender/blenkernel/BKE_displist.h @@ -75,8 +75,6 @@ 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, struct ListBase *lb); diff --git a/source/blender/blenkernel/BKE_fcurve.h b/source/blender/blenkernel/BKE_fcurve.h index 4569e68ea4a..589d1839dd4 100644 --- a/source/blender/blenkernel/BKE_fcurve.h +++ b/source/blender/blenkernel/BKE_fcurve.h @@ -232,6 +232,19 @@ 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); @@ -245,6 +258,14 @@ 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); diff --git a/source/blender/blenkernel/BKE_geometry_set.hh b/source/blender/blenkernel/BKE_geometry_set.hh index 8cc37a3e711..4454669b59a 100644 --- a/source/blender/blenkernel/BKE_geometry_set.hh +++ b/source/blender/blenkernel/BKE_geometry_set.hh @@ -313,6 +313,8 @@ struct GeometrySet { friend bool operator==(const GeometrySet &a, const GeometrySet &b); uint64_t hash() const; + void clear(); + /* Utility methods for creation. */ static GeometrySet create_with_mesh( Mesh *mesh, GeometryOwnershipType ownership = GeometryOwnershipType::Owned); diff --git a/source/blender/blenkernel/BKE_geometry_set_instances.hh b/source/blender/blenkernel/BKE_geometry_set_instances.hh index 16c28e32e3c..c372fdff049 100644 --- a/source/blender/blenkernel/BKE_geometry_set_instances.hh +++ b/source/blender/blenkernel/BKE_geometry_set_instances.hh @@ -39,7 +39,8 @@ struct GeometryInstanceGroup { Vector<float4x4> transforms; }; -Vector<GeometryInstanceGroup> geometry_set_gather_instances(const GeometrySet &geometry_set); +void geometry_set_gather_instances(const GeometrySet &geometry_set, + Vector<GeometryInstanceGroup> &r_instance_groups); GeometrySet geometry_set_realize_mesh_for_modifier(const GeometrySet &geometry_set); GeometrySet geometry_set_realize_instances(const GeometrySet &geometry_set); diff --git a/source/blender/blenkernel/BKE_gpencil_geom.h b/source/blender/blenkernel/BKE_gpencil_geom.h index 89a794f2df3..a9bd0a524c4 100644 --- a/source/blender/blenkernel/BKE_gpencil_geom.h +++ b/source/blender/blenkernel/BKE_gpencil_geom.h @@ -27,10 +27,10 @@ extern "C" { #endif -struct BoundBox; struct Depsgraph; struct Main; struct Object; +struct RegionView3D; struct Scene; struct bGPDcurve; struct bGPDframe; @@ -173,6 +173,20 @@ void BKE_gpencil_stroke_uniform_subdivide(struct bGPdata *gpd, const uint32_t target_number, const bool select); +void BKE_gpencil_stroke_to_view_space(struct RegionView3D *rv3d, + struct bGPDstroke *gps, + const float diff_mat[4][4]); +void BKE_gpencil_stroke_from_view_space(struct RegionView3D *rv3d, + struct bGPDstroke *gps, + const float diff_mat[4][4]); +struct bGPDstroke *BKE_gpencil_stroke_perimeter_from_view(struct RegionView3D *rv3d, + struct bGPdata *gpd, + const struct bGPDlayer *gpl, + struct bGPDstroke *gps, + const int subdivisions, + const float diff_mat[4][4]); +float BKE_gpencil_stroke_average_pressure_get(struct bGPDstroke *gps); +bool BKE_gpencil_stroke_is_pressure_constant(struct bGPDstroke *gps); #ifdef __cplusplus } #endif diff --git a/source/blender/blenkernel/BKE_lib_override.h b/source/blender/blenkernel/BKE_lib_override.h index f69580d38be..0750a3332a8 100644 --- a/source/blender/blenkernel/BKE_lib_override.h +++ b/source/blender/blenkernel/BKE_lib_override.h @@ -74,6 +74,7 @@ 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, diff --git a/source/blender/blenkernel/BKE_node.h b/source/blender/blenkernel/BKE_node.h index 71f188a2de1..42ed026cb01 100644 --- a/source/blender/blenkernel/BKE_node.h +++ b/source/blender/blenkernel/BKE_node.h @@ -483,14 +483,14 @@ void ntreeBlendReadExpand(struct BlendExpander *expander, struct bNodeTree *ntre /** \name Node Tree Interface * \{ */ struct bNodeSocket *ntreeFindSocketInterface(struct bNodeTree *ntree, - int in_out, + eNodeSocketInOut in_out, const char *identifier); struct bNodeSocket *ntreeAddSocketInterface(struct bNodeTree *ntree, - int in_out, + eNodeSocketInOut in_out, const char *idname, const char *name); struct bNodeSocket *ntreeInsertSocketInterface(struct bNodeTree *ntree, - int in_out, + eNodeSocketInOut in_out, const char *idname, struct bNodeSocket *next_sock, const char *name); @@ -556,30 +556,32 @@ const char *nodeStaticSocketInterfaceType(int type, int subtype); } \ ((void)0) -struct bNodeSocket *nodeFindSocket(const struct bNode *node, int in_out, const char *identifier); +struct bNodeSocket *nodeFindSocket(const struct bNode *node, + eNodeSocketInOut in_out, + const char *identifier); struct bNodeSocket *nodeAddSocket(struct bNodeTree *ntree, struct bNode *node, - int in_out, + eNodeSocketInOut in_out, const char *idname, const char *identifier, const char *name); struct bNodeSocket *nodeInsertSocket(struct bNodeTree *ntree, struct bNode *node, - int in_out, + eNodeSocketInOut in_out, const char *idname, struct bNodeSocket *next_sock, const char *identifier, const char *name); struct bNodeSocket *nodeAddStaticSocket(struct bNodeTree *ntree, struct bNode *node, - int in_out, + eNodeSocketInOut in_out, int type, int subtype, const char *identifier, const char *name); struct bNodeSocket *nodeInsertStaticSocket(struct bNodeTree *ntree, struct bNode *node, - int in_out, + eNodeSocketInOut in_out, int type, int subtype, struct bNodeSocket *next_sock, @@ -1188,6 +1190,7 @@ 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 @@ -1393,7 +1396,9 @@ 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_PLANE 1039 +#define GEO_NODE_MESH_PRIMITIVE_GRID 1039 +#define GEO_NODE_ATTRIBUTE_MAP_RANGE 1040 +#define GEO_NODE_ATTRIBUTE_CLAMP 1041 /** \} */ diff --git a/source/blender/blenkernel/BKE_node_ui_storage.hh b/source/blender/blenkernel/BKE_node_ui_storage.hh index a8fdbec1e8c..aa7e5180b03 100644 --- a/source/blender/blenkernel/BKE_node_ui_storage.hh +++ b/source/blender/blenkernel/BKE_node_ui_storage.hh @@ -58,9 +58,7 @@ class NodeTreeEvaluationContext { uint64_t hash() const { - 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. */ + return blender::get_default_hash_2(object_name_, modifier_session_uuid_); } friend bool operator==(const NodeTreeEvaluationContext &a, const NodeTreeEvaluationContext &b) diff --git a/source/blender/blenkernel/BKE_object.h b/source/blender/blenkernel/BKE_object.h index 12c40e891c9..0c2c6313dde 100644 --- a/source/blender/blenkernel/BKE_object.h +++ b/source/blender/blenkernel/BKE_object.h @@ -336,6 +336,12 @@ 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, diff --git a/source/blender/blenkernel/CMakeLists.txt b/source/blender/blenkernel/CMakeLists.txt index 310ac6c4903..8fbf49b31d4 100644 --- a/source/blender/blenkernel/CMakeLists.txt +++ b/source/blender/blenkernel/CMakeLists.txt @@ -69,6 +69,7 @@ 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 @@ -126,6 +127,7 @@ 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 @@ -385,6 +387,7 @@ 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 @@ -434,10 +437,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 @@ -742,7 +745,7 @@ if(WITH_GMP) list(APPEND INC_SYS ${GMP_INCLUDE_DIRS} ) - endif() +endif() # # Warnings as errors, this is too strict! # if(MSVC) diff --git a/source/blender/blenkernel/intern/action.c b/source/blender/blenkernel/intern/action.c index f9c2a4e53ad..0b38e2d9f75 100644 --- a/source/blender/blenkernel/intern/action.c +++ b/source/blender/blenkernel/intern/action.c @@ -1316,30 +1316,6 @@ 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) */ diff --git a/source/blender/blenkernel/intern/action_mirror.c b/source/blender/blenkernel/intern/action_mirror.c new file mode 100644 index 00000000000..c975d2bfb9c --- /dev/null +++ b/source/blender/blenkernel/intern/action_mirror.c @@ -0,0 +1,457 @@ +/* + * 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); +} + +/** \} */ diff --git a/source/blender/blenkernel/intern/armature_pose.cc b/source/blender/blenkernel/intern/armature_pose.cc index bb371b16c42..ca11692372b 100644 --- a/source/blender/blenkernel/intern/armature_pose.cc +++ b/source/blender/blenkernel/intern/armature_pose.cc @@ -39,7 +39,7 @@ namespace { using BoneNameSet = blender::Set<std::string>; // Forward declarations. -BoneNameSet pose_apply_find_selected_bones(const bPose *pose); +BoneNameSet pose_apply_find_selected_bones(const bArmature *armature, const bPose *pose); void pose_apply_disable_fcurves_for_unselected_bones(bAction *action, const BoneNameSet &selected_bone_names); void pose_apply_restore_fcurves(bAction *action); @@ -54,7 +54,8 @@ void BKE_pose_apply_action(struct Object *ob, return; } - const BoneNameSet selected_bone_names = pose_apply_find_selected_bones(pose); + const bArmature *armature = (bArmature *)ob->data; + const BoneNameSet selected_bone_names = pose_apply_find_selected_bones(armature, pose); const bool limit_to_selected_bones = !selected_bone_names.is_empty(); if (limit_to_selected_bones) { @@ -74,15 +75,14 @@ void BKE_pose_apply_action(struct Object *ob, } namespace { -BoneNameSet pose_apply_find_selected_bones(const bPose *pose) +BoneNameSet pose_apply_find_selected_bones(const bArmature *armature, const bPose *pose) { BoneNameSet selected_bone_names; bool all_bones_selected = true; bool no_bones_selected = true; LISTBASE_FOREACH (bPoseChannel *, pchan, &pose->chanbase) { - const bool is_selected = (pchan->bone->flag & BONE_SELECTED) != 0 && - (pchan->bone->flag & BONE_HIDDEN_P) == 0; + const bool is_selected = PBONE_SELECTED(armature, pchan->bone); all_bones_selected &= is_selected; no_bones_selected &= !is_selected; diff --git a/source/blender/blenkernel/intern/attribute.c b/source/blender/blenkernel/intern/attribute.c index d8fd3a19303..5db45471f0a 100644 --- a/source/blender/blenkernel/intern/attribute.c +++ b/source/blender/blenkernel/intern/attribute.c @@ -69,8 +69,8 @@ static void get_domains(ID *id, DomainInfo info[ATTR_DOMAIN_NUM]) info[ATTR_DOMAIN_EDGE].length = mesh->totedge; info[ATTR_DOMAIN_CORNER].customdata = &mesh->ldata; info[ATTR_DOMAIN_CORNER].length = mesh->totloop; - info[ATTR_DOMAIN_POLYGON].customdata = &mesh->pdata; - info[ATTR_DOMAIN_POLYGON].length = mesh->totpoly; + info[ATTR_DOMAIN_FACE].customdata = &mesh->pdata; + info[ATTR_DOMAIN_FACE].length = mesh->totpoly; break; } case ID_HA: { diff --git a/source/blender/blenkernel/intern/attribute_access.cc b/source/blender/blenkernel/intern/attribute_access.cc index 6a8ceb467e7..52f89ca302b 100644 --- a/source/blender/blenkernel/intern/attribute_access.cc +++ b/source/blender/blenkernel/intern/attribute_access.cc @@ -331,7 +331,7 @@ static int attribute_domain_priority(const AttributeDomain domain) case ATTR_DOMAIN_CURVE: return 0; #endif - case ATTR_DOMAIN_POLYGON: + case ATTR_DOMAIN_FACE: return 1; case ATTR_DOMAIN_EDGE: return 2; @@ -893,7 +893,7 @@ ReadAttributePtr GeometryComponent::attribute_try_get_for_read( return {}; } - if (attribute->domain() != domain) { + if (domain != ATTR_DOMAIN_AUTO && attribute->domain() != domain) { attribute = this->attribute_try_adapt_domain(std::move(attribute), domain); if (!attribute) { return {}; diff --git a/source/blender/blenkernel/intern/blendfile.c b/source/blender/blenkernel/intern/blendfile.c index efbf19c7381..a61e7a2d1d8 100644 --- a/source/blender/blenkernel/intern/blendfile.c +++ b/source/blender/blenkernel/intern/blendfile.c @@ -400,6 +400,8 @@ static void setup_app_data(bContext *C, bmain, curscene, bfd->cur_view_layer ? bfd->cur_view_layer : BKE_view_layer_default_view(curscene)); + /* We need to rebuild some of the deleted override rules (for UI feedback purpose). */ + BKE_lib_override_library_main_operations_create(bmain, true); } } diff --git a/source/blender/blenkernel/intern/brush.c b/source/blender/blenkernel/intern/brush.c index 13ba1957a32..ef567044282 100644 --- a/source/blender/blenkernel/intern/brush.c +++ b/source/blender/blenkernel/intern/brush.c @@ -574,8 +574,8 @@ bool BKE_brush_delete(Main *bmain, Brush *brush) if (brush->id.tag & LIB_TAG_INDIRECT) { return false; } - if (BKE_library_ID_is_indirectly_used(bmain, brush) && ID_REAL_USERS(brush) <= 1 && - ID_EXTRA_USERS(brush) == 0) { + if (ID_REAL_USERS(brush) <= 1 && ID_EXTRA_USERS(brush) == 0 && + BKE_library_ID_is_indirectly_used(bmain, brush)) { return false; } diff --git a/source/blender/blenkernel/intern/cachefile.c b/source/blender/blenkernel/intern/cachefile.c index d233022fd3f..feae033337d 100644 --- a/source/blender/blenkernel/intern/cachefile.c +++ b/source/blender/blenkernel/intern/cachefile.c @@ -99,6 +99,7 @@ static void cache_file_blend_write(BlendWriter *writer, ID *id, const void *id_a cache_file->handle_readers = NULL; BLO_write_id_struct(writer, CacheFile, id_address, &cache_file->id); + BKE_id_blend_write(writer, &cache_file->id); if (cache_file->adt) { BKE_animdata_blend_write(writer, cache_file->adt); diff --git a/source/blender/blenkernel/intern/cryptomatte.cc b/source/blender/blenkernel/intern/cryptomatte.cc index 6c7b3d82c3b..895f06da5fe 100644 --- a/source/blender/blenkernel/intern/cryptomatte.cc +++ b/source/blender/blenkernel/intern/cryptomatte.cc @@ -433,6 +433,9 @@ static bool from_manifest(CryptomatteLayer &layer, blender::StringRefNull manife } const int quoted_hash_len = quoted_string_len_(ref); + if (quoted_hash_len < 2) { + return false; + } const int hash_len = quoted_hash_len - 2; CryptomatteHash hash = CryptomatteHash::from_hex_encoded(ref.substr(1, hash_len)); ref = ref.drop_prefix(quoted_hash_len); diff --git a/source/blender/blenkernel/intern/curve.c b/source/blender/blenkernel/intern/curve.c index f3551c98f07..b0ea9b0f0d3 100644 --- a/source/blender/blenkernel/intern/curve.c +++ b/source/blender/blenkernel/intern/curve.c @@ -2756,7 +2756,6 @@ void BKE_curve_bevelList_make(Object *ob, ListBase *nurbs, bool for_render) bevp->tilt = bp->tilt; bevp->radius = bp->radius; bevp->weight = bp->weight; - bevp->split_tag = true; bp++; if (seglen != NULL && len != 0) { *seglen = len_v3v3(bevp->vec, bp->vec); @@ -2828,7 +2827,6 @@ void BKE_curve_bevelList_make(Object *ob, ListBase *nurbs, bool for_render) bevp->tilt = prevbezt->tilt; bevp->radius = prevbezt->radius; bevp->weight = prevbezt->weight; - bevp->split_tag = true; bevp->dupe_tag = false; bevp++; bl->nr++; @@ -2879,21 +2877,6 @@ void BKE_curve_bevelList_make(Object *ob, ListBase *nurbs, bool for_render) sizeof(BevPoint)); } - /* indicate with handlecodes double points */ - if (prevbezt->h1 == prevbezt->h2) { - if (ELEM(prevbezt->h1, 0, HD_VECT)) { - bevp->split_tag = true; - } - } - else { - if (ELEM(prevbezt->h1, 0, HD_VECT)) { - bevp->split_tag = true; - } - else if (ELEM(prevbezt->h2, 0, HD_VECT)) { - bevp->split_tag = true; - } - } - /* seglen */ if (seglen != NULL) { *seglen = 0; diff --git a/source/blender/blenkernel/intern/displist.c b/source/blender/blenkernel/intern/displist.c index d4581991566..829f9a94b66 100644 --- a/source/blender/blenkernel/intern/displist.c +++ b/source/blender/blenkernel/intern/displist.c @@ -74,9 +74,6 @@ void BKE_displist_elem_free(DispList *dl) if (dl->index) { MEM_freeN(dl->index); } - if (dl->bevel_split) { - MEM_freeN(dl->bevel_split); - } MEM_freeN(dl); } } @@ -137,10 +134,6 @@ void BKE_displist_copy(ListBase *lbn, ListBase *lb) dln->verts = MEM_dupallocN(dl->verts); dln->nors = MEM_dupallocN(dl->nors); dln->index = MEM_dupallocN(dl->index); - - if (dl->bevel_split) { - dln->bevel_split = MEM_dupallocN(dl->bevel_split); - } } } @@ -1609,8 +1602,6 @@ static void do_makeDispListCurveTypes(Depsgraph *depsgraph, /* CU_2D conflicts with R_NOPUNOFLIP */ dl->rt = nu->flag & ~CU_2D; - dl->bevel_split = BLI_BITMAP_NEW(steps, "bevel_split"); - /* for each point of poly make a bevel piece */ BevPoint *bevp_first = bl->bevpoints; BevPoint *bevp_last = &bl->bevpoints[bl->nr - 1]; @@ -1659,10 +1650,6 @@ static void do_makeDispListCurveTypes(Depsgraph *depsgraph, } } - if (bevp->split_tag) { - BLI_BITMAP_ENABLE(dl->bevel_split, a); - } - /* rotate bevel piece and write in data */ if ((a == 0) && (bevp != bevp_last)) { rotateBevelPiece( diff --git a/source/blender/blenkernel/intern/fcurve.c b/source/blender/blenkernel/intern/fcurve.c index 8e1fa9732ea..010ab09bb31 100644 --- a/source/blender/blenkernel/intern/fcurve.c +++ b/source/blender/blenkernel/intern/fcurve.c @@ -35,7 +35,9 @@ #include "BLI_blenlib.h" #include "BLI_easing.h" +#include "BLI_ghash.h" #include "BLI_math.h" +#include "BLI_sort_utils.h" #include "BKE_anim_data.h" #include "BKE_animsys.h" @@ -290,6 +292,12 @@ FCurve *BKE_fcurve_find(ListBase *list, const char rna_path[], const int array_i return NULL; } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name FCurve Iteration + * \{ */ + /* Quick way to loop over all fcurves of a given 'path'. */ FCurve *BKE_fcurve_iter_step(FCurve *fcu_iter, const char rna_path[]) { @@ -829,6 +837,56 @@ bool BKE_fcurve_calc_range( return foundvert; } +/** + * Return an array of keyed frames, rounded to `interval`. + * + * \param interval: Set to 1.0 to round to whole keyframes, 0.5 for in-between key-frames, etc. + * + * \note An interval of zero could be supported (this implies no rounding at all), + * however this risks very small differences in float values being treated as separate keyframes. + */ +float *BKE_fcurves_calc_keyed_frames_ex(FCurve **fcurve_array, + int fcurve_array_len, + const float interval, + int *r_frames_len) +{ + /* Use `1e-3f` as the smallest possible value since these are converted to integers + * and we can be sure `MAXFRAME / 1e-3f < INT_MAX` as it's around half the size. */ + const double interval_db = max_ff(interval, 1e-3f); + GSet *frames_unique = BLI_gset_int_new(__func__); + for (int fcurve_index = 0; fcurve_index < fcurve_array_len; fcurve_index++) { + const FCurve *fcu = fcurve_array[fcurve_index]; + for (int i = 0; i < fcu->totvert; i++) { + const BezTriple *bezt = &fcu->bezt[i]; + const double value = round((double)bezt->vec[1][0] / interval_db); + BLI_assert(value > INT_MIN && value < INT_MAX); + BLI_gset_add(frames_unique, POINTER_FROM_INT((int)value)); + } + } + + const size_t frames_len = BLI_gset_len(frames_unique); + float *frames = MEM_mallocN(sizeof(*frames) * frames_len, __func__); + + GSetIterator gs_iter; + int i = 0; + GSET_ITER_INDEX (gs_iter, frames_unique, i) { + const int value = POINTER_AS_INT(BLI_gsetIterator_getKey(&gs_iter)); + frames[i] = (double)value * interval_db; + } + BLI_gset_free(frames_unique, NULL); + + qsort(frames, frames_len, sizeof(*frames), BLI_sortutil_cmp_float); + *r_frames_len = frames_len; + return frames; +} + +float *BKE_fcurves_calc_keyed_frames(FCurve **fcurve_array, + int fcurve_array_len, + int *r_frames_len) +{ + return BKE_fcurves_calc_keyed_frames_ex(fcurve_array, fcurve_array_len, 1.0f, r_frames_len); +} + /** \} */ /* -------------------------------------------------------------------- */ diff --git a/source/blender/blenkernel/intern/fcurve_cache.c b/source/blender/blenkernel/intern/fcurve_cache.c new file mode 100644 index 00000000000..8142b871edd --- /dev/null +++ b/source/blender/blenkernel/intern/fcurve_cache.c @@ -0,0 +1,189 @@ +/* + * 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 + * + * Cache F-Curve look-ups. + */ + +#include <stdlib.h> +#include <string.h> + +#include "MEM_guardedalloc.h" + +#include "DNA_anim_types.h" + +#include "BLI_ghash.h" +#include "BLI_listbase.h" + +#include "BKE_fcurve.h" + +/* -------------------------------------------------------------------- */ +/** \name F-Curve Path Cache + * + * Cache for finding curves by RNA path & array index. + * \{ */ + +struct FCurvePathCache_Span { + /** Index in the #FCurvePathCache.fcurve_array indicating the start of the span. */ + uint index; + /** Number of items in the span in #FCurvePathCache.fcurve_array that share an RNA path. */ + uint len; +}; + +struct FCurvePathCache { + /** All curves sorted by (#FCurve.rna_path, #FCurve.array_index) */ + FCurve **fcurve_array; + uint fcurve_array_len; + /** Storage for values of `span_from_rna_path`. */ + struct FCurvePathCache_Span *span_table; + /** Map `FCurve.rna_path` to elements in #FCurvePathCache.span_table */ + GHash *span_from_rna_path; +}; + +/** + * #qsort callback for an #FCurve array. + */ +static int fcurve_cmp_for_cache(const void *fcu_a_p, const void *fcu_b_p) +{ + const FCurve *fcu_a = *((const FCurve **)fcu_a_p); + const FCurve *fcu_b = *((const FCurve **)fcu_b_p); + const int cmp = strcmp(fcu_a->rna_path, fcu_b->rna_path); + if (cmp != 0) { + return cmp; + } + if (fcu_a->array_index < fcu_b->array_index) { + return -1; + } + if (fcu_a->array_index > fcu_b->array_index) { + return 1; + } + return 0; +} + +struct FCurvePathCache *BKE_fcurve_pathcache_create(ListBase *list) +{ + const uint fcurve_array_len = BLI_listbase_count(list); + FCurve **fcurve_array = MEM_mallocN(sizeof(*fcurve_array) * fcurve_array_len, __func__); + uint i; + LISTBASE_FOREACH_INDEX (FCurve *, fcu, list, i) { + fcurve_array[i] = fcu; + } + qsort(fcurve_array, fcurve_array_len, sizeof(FCurve *), fcurve_cmp_for_cache); + + /* Allow for the case no F-curves share an RNA-path, otherwise this is over-allocated. + * Although in practice it's likely to only be 3-4x as large as is needed + * (with transform channels for e.g.). */ + struct FCurvePathCache_Span *span_table = MEM_mallocN(sizeof(*span_table) * fcurve_array_len, + __func__); + + /* May over reserve, harmless. */ + GHash *span_from_rna_path = BLI_ghash_str_new_ex(__func__, fcurve_array_len); + uint span_index = 0; + i = 0; + while (i < fcurve_array_len) { + uint i_end; + for (i_end = i + 1; i_end < fcurve_array_len; i_end++) { + /* As the indices are sorted, we know a decrease means a new RNA path is found. */ + if (fcurve_array[i]->array_index > fcurve_array[i_end]->array_index) { + BLI_assert(!STREQ(fcurve_array[i]->rna_path, fcurve_array[i_end]->rna_path)); + break; + } + if (!STREQ(fcurve_array[i]->rna_path, fcurve_array[i_end]->rna_path)) { + break; + } + } + + struct FCurvePathCache_Span *span = &span_table[span_index++]; + span->index = i; + span->len = i_end - i; + BLI_ghash_insert(span_from_rna_path, fcurve_array[i]->rna_path, span); + i = i_end; + } + + struct FCurvePathCache *fcache = MEM_callocN(sizeof(struct FCurvePathCache), __func__); + fcache->fcurve_array = fcurve_array; + fcache->fcurve_array_len = fcurve_array_len; + fcache->span_table = span_table; + fcache->span_from_rna_path = span_from_rna_path; + + return fcache; +} + +void BKE_fcurve_pathcache_destroy(struct FCurvePathCache *fcache) +{ + MEM_freeN(fcache->fcurve_array); + MEM_freeN(fcache->span_table); + BLI_ghash_free(fcache->span_from_rna_path, NULL, NULL); + MEM_freeN(fcache); +} + +FCurve *BKE_fcurve_pathcache_find(struct FCurvePathCache *fcache, + const char *rna_path, + const int array_index) +{ + const struct FCurvePathCache_Span *span = BLI_ghash_lookup(fcache->span_from_rna_path, rna_path); + if (span == NULL) { + return NULL; + } + + FCurve **fcurve = fcache->fcurve_array + span->index; + const uint len = span->len; + for (int i = 0; i < len; i++) { + if (fcurve[i]->array_index == array_index) { + return fcurve[i]; + } + /* As these are sorted, early exit. */ + if (fcurve[i]->array_index > array_index) { + break; + } + } + return NULL; +} + +/** + * Fill in an array of F-Curve, leave NULL when not found. + * + * \return The number of F-Curves found. + */ +int BKE_fcurve_pathcache_find_array(struct FCurvePathCache *fcache, + const char *rna_path, + FCurve **fcurve_result, + int fcurve_result_len) +{ + memset(fcurve_result, 0x0, sizeof(*fcurve_result) * fcurve_result_len); + + const struct FCurvePathCache_Span *span = BLI_ghash_lookup(fcache->span_from_rna_path, rna_path); + if (span == NULL) { + return 0; + } + + int found = 0; + FCurve **fcurve = fcache->fcurve_array + span->index; + const uint len = span->len; + for (int i = 0; i < len; i++) { + /* As these are sorted, early exit. */ + if ((uint)fcurve[i]->array_index > (uint)fcurve_result_len) { + break; + } + fcurve_result[fcurve[i]->array_index] = fcurve[i]; + found += 1; + } + return found; +} + +/** \} */ diff --git a/source/blender/blenkernel/intern/geometry_component_mesh.cc b/source/blender/blenkernel/intern/geometry_component_mesh.cc index d7cdc8ad880..27756e3cbed 100644 --- a/source/blender/blenkernel/intern/geometry_component_mesh.cc +++ b/source/blender/blenkernel/intern/geometry_component_mesh.cc @@ -175,7 +175,7 @@ int MeshComponent::attribute_domain_size(const AttributeDomain domain) const return mesh_->totvert; case ATTR_DOMAIN_EDGE: return mesh_->totedge; - case ATTR_DOMAIN_POLYGON: + case ATTR_DOMAIN_FACE: return mesh_->totpoly; default: break; @@ -259,9 +259,9 @@ static ReadAttributePtr adapt_mesh_domain_point_to_corner(const Mesh &mesh, * only some values are required. */ template<typename T> -static void adapt_mesh_domain_corner_to_polygon_impl(const Mesh &mesh, - Span<T> old_values, - MutableSpan<T> r_values) +static void adapt_mesh_domain_corner_to_face_impl(const Mesh &mesh, + Span<T> old_values, + MutableSpan<T> r_values) { BLI_assert(r_values.size() == mesh.totpoly); attribute_math::DefaultMixer<T> mixer(r_values); @@ -277,8 +277,8 @@ static void adapt_mesh_domain_corner_to_polygon_impl(const Mesh &mesh, mixer.finalize(); } -static ReadAttributePtr adapt_mesh_domain_corner_to_polygon(const Mesh &mesh, - ReadAttributePtr attribute) +static ReadAttributePtr adapt_mesh_domain_corner_to_face(const Mesh &mesh, + ReadAttributePtr attribute) { ReadAttributePtr new_attribute; const CustomDataType data_type = attribute->custom_data_type(); @@ -286,7 +286,7 @@ static ReadAttributePtr adapt_mesh_domain_corner_to_polygon(const Mesh &mesh, using T = decltype(dummy); if constexpr (!std::is_void_v<attribute_math::DefaultMixer<T>>) { Array<T> values(mesh.totpoly); - adapt_mesh_domain_corner_to_polygon_impl<T>(mesh, attribute->get_span<T>(), values); + adapt_mesh_domain_corner_to_face_impl<T>(mesh, attribute->get_span<T>(), values); new_attribute = std::make_unique<OwnedArrayReadAttribute<T>>(ATTR_DOMAIN_POINT, std::move(values)); } @@ -336,9 +336,9 @@ static ReadAttributePtr adapt_mesh_domain_corner_to_edge(const Mesh &mesh, } template<typename T> -void adapt_mesh_domain_polygon_to_point_impl(const Mesh &mesh, - Span<T> old_values, - MutableSpan<T> r_values) +void adapt_mesh_domain_face_to_point_impl(const Mesh &mesh, + Span<T> old_values, + MutableSpan<T> r_values) { BLI_assert(r_values.size() == mesh.totvert); attribute_math::DefaultMixer<T> mixer(r_values); @@ -356,8 +356,8 @@ void adapt_mesh_domain_polygon_to_point_impl(const Mesh &mesh, mixer.finalize(); } -static ReadAttributePtr adapt_mesh_domain_polygon_to_point(const Mesh &mesh, - ReadAttributePtr attribute) +static ReadAttributePtr adapt_mesh_domain_face_to_point(const Mesh &mesh, + ReadAttributePtr attribute) { ReadAttributePtr new_attribute; const CustomDataType data_type = attribute->custom_data_type(); @@ -365,7 +365,7 @@ static ReadAttributePtr adapt_mesh_domain_polygon_to_point(const Mesh &mesh, using T = decltype(dummy); if constexpr (!std::is_void_v<attribute_math::DefaultMixer<T>>) { Array<T> values(mesh.totvert); - adapt_mesh_domain_polygon_to_point_impl<T>(mesh, attribute->get_span<T>(), values); + adapt_mesh_domain_face_to_point_impl<T>(mesh, attribute->get_span<T>(), values); new_attribute = std::make_unique<OwnedArrayReadAttribute<T>>(ATTR_DOMAIN_POINT, std::move(values)); } @@ -374,9 +374,9 @@ static ReadAttributePtr adapt_mesh_domain_polygon_to_point(const Mesh &mesh, } template<typename T> -void adapt_mesh_domain_polygon_to_corner_impl(const Mesh &mesh, - const Span<T> old_values, - MutableSpan<T> r_values) +void adapt_mesh_domain_face_to_corner_impl(const Mesh &mesh, + const Span<T> old_values, + MutableSpan<T> r_values) { BLI_assert(r_values.size() == mesh.totloop); @@ -387,8 +387,8 @@ void adapt_mesh_domain_polygon_to_corner_impl(const Mesh &mesh, } } -static ReadAttributePtr adapt_mesh_domain_polygon_to_corner(const Mesh &mesh, - ReadAttributePtr attribute) +static ReadAttributePtr adapt_mesh_domain_face_to_corner(const Mesh &mesh, + ReadAttributePtr attribute) { ReadAttributePtr new_attribute; const CustomDataType data_type = attribute->custom_data_type(); @@ -396,7 +396,7 @@ static ReadAttributePtr adapt_mesh_domain_polygon_to_corner(const Mesh &mesh, using T = decltype(dummy); if constexpr (!std::is_void_v<attribute_math::DefaultMixer<T>>) { Array<T> values(mesh.totloop); - adapt_mesh_domain_polygon_to_corner_impl<T>(mesh, attribute->get_span<T>(), values); + adapt_mesh_domain_face_to_corner_impl<T>(mesh, attribute->get_span<T>(), values); new_attribute = std::make_unique<OwnedArrayReadAttribute<T>>(ATTR_DOMAIN_POINT, std::move(values)); } @@ -405,9 +405,9 @@ static ReadAttributePtr adapt_mesh_domain_polygon_to_corner(const Mesh &mesh, } template<typename T> -void adapt_mesh_domain_polygon_to_edge_impl(const Mesh &mesh, - const Span<T> old_values, - MutableSpan<T> r_values) +void adapt_mesh_domain_face_to_edge_impl(const Mesh &mesh, + const Span<T> old_values, + MutableSpan<T> r_values) { BLI_assert(r_values.size() == mesh.totedge); attribute_math::DefaultMixer<T> mixer(r_values); @@ -423,8 +423,8 @@ void adapt_mesh_domain_polygon_to_edge_impl(const Mesh &mesh, mixer.finalize(); } -static ReadAttributePtr adapt_mesh_domain_polygon_to_edge(const Mesh &mesh, - ReadAttributePtr attribute) +static ReadAttributePtr adapt_mesh_domain_face_to_edge(const Mesh &mesh, + ReadAttributePtr attribute) { ReadAttributePtr new_attribute; const CustomDataType data_type = attribute->custom_data_type(); @@ -432,7 +432,7 @@ static ReadAttributePtr adapt_mesh_domain_polygon_to_edge(const Mesh &mesh, using T = decltype(dummy); if constexpr (!std::is_void_v<attribute_math::DefaultMixer<T>>) { Array<T> values(mesh.totedge); - adapt_mesh_domain_polygon_to_edge_impl<T>(mesh, attribute->get_span<T>(), values); + adapt_mesh_domain_face_to_edge_impl<T>(mesh, attribute->get_span<T>(), values); new_attribute = std::make_unique<OwnedArrayReadAttribute<T>>(ATTR_DOMAIN_POINT, std::move(values)); } @@ -446,9 +446,9 @@ static ReadAttributePtr adapt_mesh_domain_polygon_to_edge(const Mesh &mesh, * only some values are required. */ template<typename T> -static void adapt_mesh_domain_point_to_polygon_impl(const Mesh &mesh, - const Span<T> old_values, - MutableSpan<T> r_values) +static void adapt_mesh_domain_point_to_face_impl(const Mesh &mesh, + const Span<T> old_values, + MutableSpan<T> r_values) { BLI_assert(r_values.size() == mesh.totpoly); attribute_math::DefaultMixer<T> mixer(r_values); @@ -464,8 +464,8 @@ static void adapt_mesh_domain_point_to_polygon_impl(const Mesh &mesh, mixer.finalize(); } -static ReadAttributePtr adapt_mesh_domain_point_to_polygon(const Mesh &mesh, - ReadAttributePtr attribute) +static ReadAttributePtr adapt_mesh_domain_point_to_face(const Mesh &mesh, + ReadAttributePtr attribute) { ReadAttributePtr new_attribute; const CustomDataType data_type = attribute->custom_data_type(); @@ -473,7 +473,7 @@ static ReadAttributePtr adapt_mesh_domain_point_to_polygon(const Mesh &mesh, using T = decltype(dummy); if constexpr (!std::is_void_v<attribute_math::DefaultMixer<T>>) { Array<T> values(mesh.totpoly); - adapt_mesh_domain_point_to_polygon_impl<T>(mesh, attribute->get_span<T>(), values); + adapt_mesh_domain_point_to_face_impl<T>(mesh, attribute->get_span<T>(), values); new_attribute = std::make_unique<OwnedArrayReadAttribute<T>>(ATTR_DOMAIN_POINT, std::move(values)); } @@ -531,7 +531,7 @@ void adapt_mesh_domain_edge_to_corner_impl(const Mesh &mesh, for (const int poly_index : IndexRange(mesh.totpoly)) { const MPoly &poly = mesh.mpoly[poly_index]; - /* For every corner, mix the values from the adjacent edges on the polygon. */ + /* For every corner, mix the values from the adjacent edges on the face. */ for (const int loop_index : IndexRange(poly.loopstart, poly.totloop)) { const int loop_index_prev = (loop_index - 1) % poly.totloop; const MLoop &loop = mesh.mloop[loop_index]; @@ -602,9 +602,9 @@ static ReadAttributePtr adapt_mesh_domain_edge_to_point(const Mesh &mesh, * only some values are required. */ template<typename T> -static void adapt_mesh_domain_edge_to_polygon_impl(const Mesh &mesh, - const Span<T> old_values, - MutableSpan<T> r_values) +static void adapt_mesh_domain_edge_to_face_impl(const Mesh &mesh, + const Span<T> old_values, + MutableSpan<T> r_values) { BLI_assert(r_values.size() == mesh.totpoly); attribute_math::DefaultMixer<T> mixer(r_values); @@ -620,8 +620,8 @@ static void adapt_mesh_domain_edge_to_polygon_impl(const Mesh &mesh, mixer.finalize(); } -static ReadAttributePtr adapt_mesh_domain_edge_to_polygon(const Mesh &mesh, - ReadAttributePtr attribute) +static ReadAttributePtr adapt_mesh_domain_edge_to_face(const Mesh &mesh, + ReadAttributePtr attribute) { ReadAttributePtr new_attribute; const CustomDataType data_type = attribute->custom_data_type(); @@ -629,7 +629,7 @@ static ReadAttributePtr adapt_mesh_domain_edge_to_polygon(const Mesh &mesh, using T = decltype(dummy); if constexpr (!std::is_void_v<attribute_math::DefaultMixer<T>>) { Array<T> values(mesh.totpoly); - adapt_mesh_domain_edge_to_polygon_impl<T>(mesh, attribute->get_span<T>(), values); + adapt_mesh_domain_edge_to_face_impl<T>(mesh, attribute->get_span<T>(), values); new_attribute = std::make_unique<OwnedArrayReadAttribute<T>>(ATTR_DOMAIN_POINT, std::move(values)); } @@ -658,8 +658,8 @@ ReadAttributePtr MeshComponent::attribute_try_adapt_domain(ReadAttributePtr attr switch (new_domain) { case ATTR_DOMAIN_POINT: return blender::bke::adapt_mesh_domain_corner_to_point(*mesh_, std::move(attribute)); - case ATTR_DOMAIN_POLYGON: - return blender::bke::adapt_mesh_domain_corner_to_polygon(*mesh_, std::move(attribute)); + case ATTR_DOMAIN_FACE: + return blender::bke::adapt_mesh_domain_corner_to_face(*mesh_, std::move(attribute)); case ATTR_DOMAIN_EDGE: return blender::bke::adapt_mesh_domain_corner_to_edge(*mesh_, std::move(attribute)); default: @@ -672,8 +672,8 @@ ReadAttributePtr MeshComponent::attribute_try_adapt_domain(ReadAttributePtr attr switch (new_domain) { case ATTR_DOMAIN_CORNER: return blender::bke::adapt_mesh_domain_point_to_corner(*mesh_, std::move(attribute)); - case ATTR_DOMAIN_POLYGON: - return blender::bke::adapt_mesh_domain_point_to_polygon(*mesh_, std::move(attribute)); + case ATTR_DOMAIN_FACE: + return blender::bke::adapt_mesh_domain_point_to_face(*mesh_, std::move(attribute)); case ATTR_DOMAIN_EDGE: return blender::bke::adapt_mesh_domain_point_to_edge(*mesh_, std::move(attribute)); default: @@ -682,14 +682,14 @@ ReadAttributePtr MeshComponent::attribute_try_adapt_domain(ReadAttributePtr attr } break; } - case ATTR_DOMAIN_POLYGON: { + case ATTR_DOMAIN_FACE: { switch (new_domain) { case ATTR_DOMAIN_POINT: - return blender::bke::adapt_mesh_domain_polygon_to_point(*mesh_, std::move(attribute)); + return blender::bke::adapt_mesh_domain_face_to_point(*mesh_, std::move(attribute)); case ATTR_DOMAIN_CORNER: - return blender::bke::adapt_mesh_domain_polygon_to_corner(*mesh_, std::move(attribute)); + return blender::bke::adapt_mesh_domain_face_to_corner(*mesh_, std::move(attribute)); case ATTR_DOMAIN_EDGE: - return blender::bke::adapt_mesh_domain_polygon_to_edge(*mesh_, std::move(attribute)); + return blender::bke::adapt_mesh_domain_face_to_edge(*mesh_, std::move(attribute)); default: break; } @@ -701,8 +701,8 @@ ReadAttributePtr MeshComponent::attribute_try_adapt_domain(ReadAttributePtr attr return blender::bke::adapt_mesh_domain_edge_to_corner(*mesh_, std::move(attribute)); case ATTR_DOMAIN_POINT: return blender::bke::adapt_mesh_domain_edge_to_point(*mesh_, std::move(attribute)); - case ATTR_DOMAIN_POLYGON: - return blender::bke::adapt_mesh_domain_edge_to_polygon(*mesh_, std::move(attribute)); + case ATTR_DOMAIN_FACE: + return blender::bke::adapt_mesh_domain_edge_to_face(*mesh_, std::move(attribute)); default: BLI_assert(false); break; @@ -733,28 +733,35 @@ static const Mesh *get_mesh_from_component_for_read(const GeometryComponent &com namespace blender::bke { -static float3 get_vertex_position(const MVert &vert) +template<typename StructT, + typename ElemT, + ElemT (*GetFunc)(const StructT &), + AttributeDomain Domain> +static ReadAttributePtr make_derived_read_attribute(const void *data, const int domain_size) { - return float3(vert.co); + return std::make_unique<DerivedArrayReadAttribute<StructT, ElemT, GetFunc>>( + Domain, Span<StructT>((const StructT *)data, domain_size)); } -static void set_vertex_position(MVert &vert, const float3 &position) +template<typename StructT, + typename ElemT, + ElemT (*GetFunc)(const StructT &), + void (*SetFunc)(StructT &, const ElemT &), + AttributeDomain Domain> +static WriteAttributePtr make_derived_write_attribute(void *data, const int domain_size) { - copy_v3_v3(vert.co, position); + return std::make_unique<DerivedArrayWriteAttribute<StructT, ElemT, GetFunc, SetFunc>>( + Domain, MutableSpan<StructT>((StructT *)data, domain_size)); } -static ReadAttributePtr make_vertex_position_read_attribute(const void *data, - const int domain_size) +static float3 get_vertex_position(const MVert &vert) { - return std::make_unique<DerivedArrayReadAttribute<MVert, float3, get_vertex_position>>( - ATTR_DOMAIN_POINT, Span<MVert>((const MVert *)data, domain_size)); + return float3(vert.co); } -static WriteAttributePtr make_vertex_position_write_attribute(void *data, const int domain_size) +static void set_vertex_position(MVert &vert, const float3 &position) { - return std::make_unique< - DerivedArrayWriteAttribute<MVert, float3, get_vertex_position, set_vertex_position>>( - ATTR_DOMAIN_POINT, MutableSpan<MVert>((MVert *)data, domain_size)); + copy_v3_v3(vert.co, position); } static void tag_normals_dirty_when_writing_position(GeometryComponent &component) @@ -775,19 +782,6 @@ static void set_material_index(MPoly &mpoly, const int &index) mpoly.mat_nr = static_cast<short>(std::clamp(index, 0, SHRT_MAX)); } -static ReadAttributePtr make_material_index_read_attribute(const void *data, const int domain_size) -{ - return std::make_unique<DerivedArrayReadAttribute<MPoly, int, get_material_index>>( - ATTR_DOMAIN_POLYGON, Span<MPoly>((const MPoly *)data, domain_size)); -} - -static WriteAttributePtr make_material_index_write_attribute(void *data, const int domain_size) -{ - return std::make_unique< - DerivedArrayWriteAttribute<MPoly, int, get_material_index, set_material_index>>( - ATTR_DOMAIN_POLYGON, MutableSpan<MPoly>((MPoly *)data, domain_size)); -} - static bool get_shade_smooth(const MPoly &mpoly) { return mpoly.flag & ME_SMOOTH; @@ -798,19 +792,6 @@ static void set_shade_smooth(MPoly &mpoly, const bool &value) SET_FLAG_FROM_TEST(mpoly.flag, value, ME_SMOOTH); } -static ReadAttributePtr make_shade_smooth_read_attribute(const void *data, const int domain_size) -{ - return std::make_unique<DerivedArrayReadAttribute<MPoly, bool, get_shade_smooth>>( - ATTR_DOMAIN_POLYGON, Span<MPoly>((const MPoly *)data, domain_size)); -} - -static WriteAttributePtr make_shade_smooth_write_attribute(void *data, const int domain_size) -{ - return std::make_unique< - DerivedArrayWriteAttribute<MPoly, bool, get_shade_smooth, set_shade_smooth>>( - ATTR_DOMAIN_POLYGON, MutableSpan<MPoly>((MPoly *)data, domain_size)); -} - static float2 get_loop_uv(const MLoopUV &uv) { return float2(uv.uv); @@ -821,18 +802,6 @@ static void set_loop_uv(MLoopUV &uv, const float2 &co) copy_v2_v2(uv.uv, co); } -static ReadAttributePtr make_uvs_read_attribute(const void *data, const int domain_size) -{ - return std::make_unique<DerivedArrayReadAttribute<MLoopUV, float2, get_loop_uv>>( - ATTR_DOMAIN_CORNER, Span((const MLoopUV *)data, domain_size)); -} - -static WriteAttributePtr make_uvs_write_attribute(void *data, const int domain_size) -{ - return std::make_unique<DerivedArrayWriteAttribute<MLoopUV, float2, get_loop_uv, set_loop_uv>>( - ATTR_DOMAIN_CORNER, MutableSpan((MLoopUV *)data, domain_size)); -} - static Color4f get_loop_color(const MLoopCol &col) { Color4f value; @@ -845,19 +814,6 @@ static void set_loop_color(MLoopCol &col, const Color4f &value) rgba_float_to_uchar(&col.r, value); } -static ReadAttributePtr make_vertex_color_read_attribute(const void *data, const int domain_size) -{ - return std::make_unique<DerivedArrayReadAttribute<MLoopCol, Color4f, get_loop_color>>( - ATTR_DOMAIN_CORNER, Span((const MLoopCol *)data, domain_size)); -} - -static WriteAttributePtr make_vertex_color_write_attribute(void *data, const int domain_size) -{ - return std::make_unique< - DerivedArrayWriteAttribute<MLoopCol, Color4f, get_loop_color, set_loop_color>>( - ATTR_DOMAIN_CORNER, MutableSpan((MLoopCol *)data, domain_size)); -} - static float get_crease(const MEdge &edge) { return edge.crease / 255.0f; @@ -868,18 +824,6 @@ static void set_crease(MEdge &edge, const float &value) edge.crease = round_fl_to_uchar_clamp(value * 255.0f); } -static ReadAttributePtr make_crease_read_attribute(const void *data, const int domain_size) -{ - return std::make_unique<DerivedArrayReadAttribute<MEdge, float, get_crease>>( - ATTR_DOMAIN_EDGE, Span((const MEdge *)data, domain_size)); -} - -static WriteAttributePtr make_crease_write_attribute(void *data, const int domain_size) -{ - return std::make_unique<DerivedArrayWriteAttribute<MEdge, float, get_crease, set_crease>>( - ATTR_DOMAIN_EDGE, MutableSpan((MEdge *)data, domain_size)); -} - class VertexWeightWriteAttribute final : public WriteAttribute { private: MDeformVert *dverts_; @@ -1049,7 +993,7 @@ class NormalAttributeProvider final : public BuiltinAttributeProvider { public: NormalAttributeProvider() : BuiltinAttributeProvider( - "normal", ATTR_DOMAIN_POLYGON, CD_PROP_FLOAT3, NonCreatable, Readonly, NonDeletable) + "normal", ATTR_DOMAIN_FACE, CD_PROP_FLOAT3, NonCreatable, Readonly, NonDeletable) { } @@ -1067,7 +1011,7 @@ class NormalAttributeProvider final : public BuiltinAttributeProvider { const void *data = CustomData_get_layer(&mesh->pdata, CD_NORMAL); return std::make_unique<ArrayReadAttribute<float3>>( - ATTR_DOMAIN_POLYGON, Span<float3>((const float3 *)data, mesh->totpoly)); + ATTR_DOMAIN_FACE, Span<float3>((const float3 *)data, mesh->totpoly)); } Array<float3> normals(mesh->totpoly); @@ -1076,8 +1020,7 @@ class NormalAttributeProvider final : public BuiltinAttributeProvider { BKE_mesh_calc_poly_normal(poly, &mesh->mloop[poly->loopstart], mesh->mvert, normals[i]); } - return std::make_unique<OwnedArrayReadAttribute<float3>>(ATTR_DOMAIN_POLYGON, - std::move(normals)); + return std::make_unique<OwnedArrayReadAttribute<float3>>(ATTR_DOMAIN_FACE, std::move(normals)); } WriteAttributePtr try_get_for_write(GeometryComponent &UNUSED(component)) const final @@ -1097,7 +1040,7 @@ class NormalAttributeProvider final : public BuiltinAttributeProvider { bool exists(const GeometryComponent &component) const final { - return component.attribute_domain_size(ATTR_DOMAIN_POLYGON) != 0; + return component.attribute_domain_size(ATTR_DOMAIN_FACE) != 0; } }; @@ -1134,82 +1077,104 @@ static ComponentAttributeProviders create_attribute_providers_for_mesh() static CustomDataAccessInfo edge_access = {MAKE_MUTABLE_CUSTOM_DATA_GETTER(edata), MAKE_CONST_CUSTOM_DATA_GETTER(edata), update_custom_data_pointers}; - static CustomDataAccessInfo polygon_access = {MAKE_MUTABLE_CUSTOM_DATA_GETTER(pdata), - MAKE_CONST_CUSTOM_DATA_GETTER(pdata), - update_custom_data_pointers}; + static CustomDataAccessInfo face_access = {MAKE_MUTABLE_CUSTOM_DATA_GETTER(pdata), + MAKE_CONST_CUSTOM_DATA_GETTER(pdata), + update_custom_data_pointers}; #undef MAKE_CONST_CUSTOM_DATA_GETTER #undef MAKE_MUTABLE_CUSTOM_DATA_GETTER - static BuiltinCustomDataLayerProvider position("position", - ATTR_DOMAIN_POINT, - CD_PROP_FLOAT3, - CD_MVERT, - BuiltinAttributeProvider::NonCreatable, - BuiltinAttributeProvider::Writable, - BuiltinAttributeProvider::NonDeletable, - point_access, - make_vertex_position_read_attribute, - make_vertex_position_write_attribute, - tag_normals_dirty_when_writing_position); + static BuiltinCustomDataLayerProvider position( + "position", + ATTR_DOMAIN_POINT, + CD_PROP_FLOAT3, + CD_MVERT, + BuiltinAttributeProvider::NonCreatable, + BuiltinAttributeProvider::Writable, + BuiltinAttributeProvider::NonDeletable, + point_access, + make_derived_read_attribute<MVert, float3, get_vertex_position, ATTR_DOMAIN_POINT>, + make_derived_write_attribute<MVert, + float3, + get_vertex_position, + set_vertex_position, + ATTR_DOMAIN_POINT>, + tag_normals_dirty_when_writing_position); static NormalAttributeProvider normal; - static BuiltinCustomDataLayerProvider material_index("material_index", - ATTR_DOMAIN_POLYGON, - CD_PROP_INT32, - CD_MPOLY, - BuiltinAttributeProvider::NonCreatable, - BuiltinAttributeProvider::Writable, - BuiltinAttributeProvider::NonDeletable, - polygon_access, - make_material_index_read_attribute, - make_material_index_write_attribute, - nullptr); - - static BuiltinCustomDataLayerProvider shade_smooth("shade_smooth", - ATTR_DOMAIN_POLYGON, - CD_PROP_BOOL, - CD_MPOLY, - BuiltinAttributeProvider::NonCreatable, - BuiltinAttributeProvider::Writable, - BuiltinAttributeProvider::NonDeletable, - polygon_access, - make_shade_smooth_read_attribute, - make_shade_smooth_write_attribute, - nullptr); - - static BuiltinCustomDataLayerProvider crease("crease", - ATTR_DOMAIN_EDGE, - CD_PROP_FLOAT, - CD_MEDGE, - BuiltinAttributeProvider::NonCreatable, - BuiltinAttributeProvider::Writable, - BuiltinAttributeProvider::NonDeletable, - edge_access, - make_crease_read_attribute, - make_crease_write_attribute, - nullptr); - - static NamedLegacyCustomDataProvider uvs(ATTR_DOMAIN_CORNER, - CD_PROP_FLOAT2, - CD_MLOOPUV, - corner_access, - make_uvs_read_attribute, - make_uvs_write_attribute); - - static NamedLegacyCustomDataProvider vertex_colors(ATTR_DOMAIN_CORNER, - CD_PROP_COLOR, - CD_MLOOPCOL, - corner_access, - make_vertex_color_read_attribute, - make_vertex_color_write_attribute); + static BuiltinCustomDataLayerProvider material_index( + "material_index", + ATTR_DOMAIN_FACE, + CD_PROP_INT32, + CD_MPOLY, + BuiltinAttributeProvider::NonCreatable, + BuiltinAttributeProvider::Writable, + BuiltinAttributeProvider::NonDeletable, + face_access, + make_derived_read_attribute<MPoly, int, get_material_index, ATTR_DOMAIN_FACE>, + make_derived_write_attribute<MPoly, + int, + get_material_index, + set_material_index, + ATTR_DOMAIN_FACE>, + nullptr); + + static BuiltinCustomDataLayerProvider shade_smooth( + "shade_smooth", + ATTR_DOMAIN_FACE, + CD_PROP_BOOL, + CD_MPOLY, + BuiltinAttributeProvider::NonCreatable, + BuiltinAttributeProvider::Writable, + BuiltinAttributeProvider::NonDeletable, + face_access, + make_derived_read_attribute<MPoly, bool, get_shade_smooth, ATTR_DOMAIN_FACE>, + make_derived_write_attribute<MPoly, + bool, + get_shade_smooth, + set_shade_smooth, + ATTR_DOMAIN_FACE>, + nullptr); + + static BuiltinCustomDataLayerProvider crease( + "crease", + ATTR_DOMAIN_EDGE, + CD_PROP_FLOAT, + CD_MEDGE, + BuiltinAttributeProvider::NonCreatable, + BuiltinAttributeProvider::Writable, + BuiltinAttributeProvider::NonDeletable, + edge_access, + make_derived_read_attribute<MEdge, float, get_crease, ATTR_DOMAIN_EDGE>, + make_derived_write_attribute<MEdge, float, get_crease, set_crease, ATTR_DOMAIN_EDGE>, + nullptr); + + static NamedLegacyCustomDataProvider uvs( + ATTR_DOMAIN_CORNER, + CD_PROP_FLOAT2, + CD_MLOOPUV, + corner_access, + make_derived_read_attribute<MLoopUV, float2, get_loop_uv, ATTR_DOMAIN_CORNER>, + make_derived_write_attribute<MLoopUV, float2, get_loop_uv, set_loop_uv, ATTR_DOMAIN_CORNER>); + + static NamedLegacyCustomDataProvider vertex_colors( + ATTR_DOMAIN_CORNER, + CD_PROP_COLOR, + CD_MLOOPCOL, + corner_access, + make_derived_read_attribute<MLoopCol, Color4f, get_loop_color, ATTR_DOMAIN_CORNER>, + make_derived_write_attribute<MLoopCol, + Color4f, + get_loop_color, + set_loop_color, + ATTR_DOMAIN_CORNER>); static VertexGroupsAttributeProvider vertex_groups; static CustomDataAttributeProvider corner_custom_data(ATTR_DOMAIN_CORNER, corner_access); static CustomDataAttributeProvider point_custom_data(ATTR_DOMAIN_POINT, point_access); static CustomDataAttributeProvider edge_custom_data(ATTR_DOMAIN_EDGE, edge_access); - static CustomDataAttributeProvider polygon_custom_data(ATTR_DOMAIN_POLYGON, polygon_access); + static CustomDataAttributeProvider face_custom_data(ATTR_DOMAIN_FACE, face_access); return ComponentAttributeProviders({&position, &material_index, &shade_smooth, &normal, &crease}, {&uvs, @@ -1218,7 +1183,7 @@ static ComponentAttributeProviders create_attribute_providers_for_mesh() &vertex_groups, &point_custom_data, &edge_custom_data, - &polygon_custom_data}); + &face_custom_data}); } } // namespace blender::bke diff --git a/source/blender/blenkernel/intern/geometry_set.cc b/source/blender/blenkernel/intern/geometry_set.cc index a09c3f5f3d3..9f57fcfb2ba 100644 --- a/source/blender/blenkernel/intern/geometry_set.cc +++ b/source/blender/blenkernel/intern/geometry_set.cc @@ -205,6 +205,12 @@ uint64_t GeometrySet::hash() const return reinterpret_cast<uint64_t>(this); } +/* Remove all geometry components from the geometry set. */ +void GeometrySet::clear() +{ + components_.clear(); +} + /* Returns a read-only mesh or null. */ const Mesh *GeometrySet::get_mesh_for_read() const { diff --git a/source/blender/blenkernel/intern/geometry_set_instances.cc b/source/blender/blenkernel/intern/geometry_set_instances.cc index 24a402ac545..10c88a47416 100644 --- a/source/blender/blenkernel/intern/geometry_set_instances.cc +++ b/source/blender/blenkernel/intern/geometry_set_instances.cc @@ -153,16 +153,13 @@ static void geometry_set_collect_recursive(const GeometrySet &geometry_set, * * \note This doesn't extract instances from the "dupli" system for non-geometry-nodes instances. */ -Vector<GeometryInstanceGroup> geometry_set_gather_instances(const GeometrySet &geometry_set) +void geometry_set_gather_instances(const GeometrySet &geometry_set, + Vector<GeometryInstanceGroup> &r_instance_groups) { - Vector<GeometryInstanceGroup> result_vector; - float4x4 unit_transform; unit_m4(unit_transform.values); - geometry_set_collect_recursive(geometry_set, unit_transform, result_vector); - - return result_vector; + geometry_set_collect_recursive(geometry_set, unit_transform, r_instance_groups); } void gather_attribute_info(Map<std::string, AttributeKind> &attributes, @@ -436,7 +433,8 @@ GeometrySet geometry_set_realize_mesh_for_modifier(const GeometrySet &geometry_s } GeometrySet new_geometry_set = geometry_set; - Vector<GeometryInstanceGroup> set_groups = geometry_set_gather_instances(geometry_set); + Vector<GeometryInstanceGroup> set_groups; + geometry_set_gather_instances(geometry_set, set_groups); join_instance_groups_mesh(set_groups, true, new_geometry_set); /* Remove all instances, even though some might contain other non-mesh data. We can't really * keep only non-mesh instances in general. */ @@ -454,7 +452,8 @@ GeometrySet geometry_set_realize_instances(const GeometrySet &geometry_set) GeometrySet new_geometry_set; - Vector<GeometryInstanceGroup> set_groups = geometry_set_gather_instances(geometry_set); + Vector<GeometryInstanceGroup> set_groups; + geometry_set_gather_instances(geometry_set, set_groups); join_instance_groups_mesh(set_groups, false, new_geometry_set); join_instance_groups_pointcloud(set_groups, new_geometry_set); join_instance_groups_volume(set_groups, new_geometry_set); diff --git a/source/blender/blenkernel/intern/gpencil_geom.c b/source/blender/blenkernel/intern/gpencil_geom.c index 8c4882854d1..27c2d9e146b 100644 --- a/source/blender/blenkernel/intern/gpencil_geom.c +++ b/source/blender/blenkernel/intern/gpencil_geom.c @@ -46,9 +46,11 @@ #include "DNA_mesh_types.h" #include "DNA_meshdata_types.h" #include "DNA_scene_types.h" +#include "DNA_screen_types.h" #include "BLT_translation.h" +#include "BKE_context.h" #include "BKE_deform.h" #include "BKE_gpencil.h" #include "BKE_gpencil_curve.h" @@ -3460,4 +3462,555 @@ void BKE_gpencil_stroke_uniform_subdivide(bGPdata *gpd, BKE_gpencil_stroke_geometry_update(gpd, gps); } +/** + * Stroke to view space + * Transforms a stroke to view space. This allows for manipulations in 2D but also easy conversion + * back to 3D. + * Note: also takes care of parent space transform + */ +void BKE_gpencil_stroke_to_view_space(RegionView3D *rv3d, + bGPDstroke *gps, + const float diff_mat[4][4]) +{ + for (int i = 0; i < gps->totpoints; i++) { + bGPDspoint *pt = &gps->points[i]; + /* Point to parent space. */ + mul_v3_m4v3(&pt->x, diff_mat, &pt->x); + /* point to view space */ + mul_m4_v3(rv3d->viewmat, &pt->x); + } +} + +/** + * Stroke from view space + * Transforms a stroke from view space back to world space. Inverse of + * BKE_gpencil_stroke_to_view_space + * Note: also takes care of parent space transform + */ +void BKE_gpencil_stroke_from_view_space(RegionView3D *rv3d, + bGPDstroke *gps, + const float diff_mat[4][4]) +{ + float inverse_diff_mat[4][4]; + invert_m4_m4(inverse_diff_mat, diff_mat); + + for (int i = 0; i < gps->totpoints; i++) { + bGPDspoint *pt = &gps->points[i]; + mul_v3_m4v3(&pt->x, rv3d->viewinv, &pt->x); + mul_m4_v3(inverse_diff_mat, &pt->x); + } +} + +/* ----------------------------------------------------------------------------- */ +/* Stroke to perimeter */ + +typedef struct tPerimeterPoint { + struct tPerimeterPoint *next, *prev; + float x, y, z; +} tPerimeterPoint; + +static tPerimeterPoint *new_perimeter_point(const float pt[3]) +{ + tPerimeterPoint *new_pt = MEM_callocN(sizeof(tPerimeterPoint), __func__); + copy_v3_v3(&new_pt->x, pt); + return new_pt; +} + +static int generate_arc_from_point_to_point(ListBase *list, + tPerimeterPoint *from, + tPerimeterPoint *to, + float center_pt[3], + int subdivisions, + bool clockwise) +{ + float vec_from[2]; + float vec_to[2]; + sub_v2_v2v2(vec_from, &from->x, center_pt); + sub_v2_v2v2(vec_to, &to->x, center_pt); + if (is_zero_v2(vec_from) || is_zero_v2(vec_to)) { + return 0; + } + + float dot = dot_v2v2(vec_from, vec_to); + float det = cross_v2v2(vec_from, vec_to); + float angle = clockwise ? M_PI - atan2f(-det, -dot) : atan2f(-det, -dot) + M_PI; + + /* Number of points is 2^(n+1) + 1 on half a circle (n=subdivisions) + * so we multiply by (angle / pi) to get the right amount of + * points to insert. */ + int num_points = (int)(((1 << (subdivisions + 1)) - 1) * (angle / M_PI)); + if (num_points > 0) { + float angle_incr = angle / (float)num_points; + + float vec_p[3]; + float vec_t[3]; + float tmp_angle; + tPerimeterPoint *last_point; + if (clockwise) { + last_point = to; + copy_v2_v2(vec_t, vec_to); + } + else { + last_point = from; + copy_v2_v2(vec_t, vec_from); + } + + for (int i = 0; i < num_points - 1; i++) { + tmp_angle = (i + 1) * angle_incr; + + rotate_v2_v2fl(vec_p, vec_t, tmp_angle); + add_v2_v2(vec_p, center_pt); + vec_p[2] = center_pt[2]; + + tPerimeterPoint *new_point = new_perimeter_point(vec_p); + if (clockwise) { + BLI_insertlinkbefore(list, last_point, new_point); + } + else { + BLI_insertlinkafter(list, last_point, new_point); + } + + last_point = new_point; + } + + return num_points - 1; + } + + return 0; +} + +static int generate_semi_circle_from_point_to_point(ListBase *list, + tPerimeterPoint *from, + tPerimeterPoint *to, + int subdivisions) +{ + int num_points = (1 << (subdivisions + 1)) + 1; + float center_pt[3]; + interp_v3_v3v3(center_pt, &from->x, &to->x, 0.5f); + + float vec_center[2]; + sub_v2_v2v2(vec_center, &from->x, center_pt); + if (is_zero_v2(vec_center)) { + return 0; + } + + float vec_p[3]; + float angle_incr = M_PI / ((float)num_points - 1); + + tPerimeterPoint *last_point = from; + for (int i = 1; i < num_points; i++) { + float angle = i * angle_incr; + + /* Rotate vector around point to get perimeter points. */ + rotate_v2_v2fl(vec_p, vec_center, angle); + add_v2_v2(vec_p, center_pt); + vec_p[2] = center_pt[2]; + + tPerimeterPoint *new_point = new_perimeter_point(vec_p); + BLI_insertlinkafter(list, last_point, new_point); + + last_point = new_point; + } + + return num_points - 1; +} + +static int generate_perimeter_cap(const float point[4], + const float other_point[4], + float radius, + ListBase *list, + int subdivisions, + short cap_type) +{ + float cap_vec[2]; + sub_v2_v2v2(cap_vec, other_point, point); + normalize_v2(cap_vec); + + float cap_nvec[2]; + if (is_zero_v2(cap_vec)) { + cap_nvec[0] = 0; + cap_nvec[1] = radius; + } + else { + cap_nvec[0] = -cap_vec[1]; + cap_nvec[1] = cap_vec[0]; + mul_v2_fl(cap_nvec, radius); + } + float cap_nvec_inv[2]; + negate_v2_v2(cap_nvec_inv, cap_nvec); + + float vec_perimeter[3]; + copy_v3_v3(vec_perimeter, point); + add_v2_v2(vec_perimeter, cap_nvec); + + float vec_perimeter_inv[3]; + copy_v3_v3(vec_perimeter_inv, point); + add_v2_v2(vec_perimeter_inv, cap_nvec_inv); + + tPerimeterPoint *p_pt = new_perimeter_point(vec_perimeter); + tPerimeterPoint *p_pt_inv = new_perimeter_point(vec_perimeter_inv); + + BLI_addtail(list, p_pt); + BLI_addtail(list, p_pt_inv); + + int num_points = 0; + if (cap_type == GP_STROKE_CAP_ROUND) { + num_points += generate_semi_circle_from_point_to_point(list, p_pt, p_pt_inv, subdivisions); + } + + return num_points + 2; +} + +/** + * Calculate the perimeter (outline) of a stroke as list of tPerimeterPoint. + * \param subdivisions: Number of subdivisions for the start and end caps + * \return: list of tPerimeterPoint + */ +static ListBase *gpencil_stroke_perimeter_ex(const bGPdata *gpd, + const bGPDlayer *gpl, + const bGPDstroke *gps, + int subdivisions, + int *r_num_perimeter_points) +{ + /* sanity check */ + if (gps->totpoints < 1) { + return NULL; + } + + float defaultpixsize = 1000.0f / gpd->pixfactor; + float stroke_radius = ((gps->thickness + gpl->line_change) / defaultpixsize) / 2.0f; + + ListBase *perimeter_right_side = MEM_callocN(sizeof(ListBase), __func__); + ListBase *perimeter_left_side = MEM_callocN(sizeof(ListBase), __func__); + int num_perimeter_points = 0; + + bGPDspoint *first = &gps->points[0]; + bGPDspoint *last = &gps->points[gps->totpoints - 1]; + + float first_radius = stroke_radius * first->pressure; + float last_radius = stroke_radius * last->pressure; + + bGPDspoint *first_next; + bGPDspoint *last_prev; + if (gps->totpoints > 1) { + first_next = &gps->points[1]; + last_prev = &gps->points[gps->totpoints - 2]; + } + else { + first_next = first; + last_prev = last; + } + + float first_pt[3]; + float last_pt[3]; + float first_next_pt[3]; + float last_prev_pt[3]; + copy_v3_v3(first_pt, &first->x); + copy_v3_v3(last_pt, &last->x); + copy_v3_v3(first_next_pt, &first_next->x); + copy_v3_v3(last_prev_pt, &last_prev->x); + + /* Edge-case if single point. */ + if (gps->totpoints == 1) { + first_next_pt[0] += 1.0f; + last_prev_pt[0] -= 1.0f; + } + + /* generate points for start cap */ + num_perimeter_points += generate_perimeter_cap( + first_pt, first_next_pt, first_radius, perimeter_right_side, subdivisions, gps->caps[0]); + + /* generate perimeter points */ + float curr_pt[3], next_pt[3], prev_pt[3]; + float vec_next[2], vec_prev[2]; + float nvec_next[2], nvec_prev[2]; + float nvec_next_pt[3], nvec_prev_pt[3]; + float vec_tangent[2]; + + float vec_miter_left[2], vec_miter_right[2]; + float miter_left_pt[3], miter_right_pt[3]; + + for (int i = 1; i < gps->totpoints - 1; i++) { + bGPDspoint *curr = &gps->points[i]; + bGPDspoint *prev = &gps->points[i - 1]; + bGPDspoint *next = &gps->points[i + 1]; + float radius = stroke_radius * curr->pressure; + + copy_v3_v3(curr_pt, &curr->x); + copy_v3_v3(next_pt, &next->x); + copy_v3_v3(prev_pt, &prev->x); + + sub_v2_v2v2(vec_prev, curr_pt, prev_pt); + sub_v2_v2v2(vec_next, next_pt, curr_pt); + float prev_length = len_v2(vec_prev); + float next_length = len_v2(vec_next); + + if (normalize_v2(vec_prev) == 0.0f) { + vec_prev[0] = 1.0f; + vec_prev[1] = 0.0f; + } + if (normalize_v2(vec_next) == 0.0f) { + vec_next[0] = 1.0f; + vec_next[1] = 0.0f; + } + + nvec_prev[0] = -vec_prev[1]; + nvec_prev[1] = vec_prev[0]; + + nvec_next[0] = -vec_next[1]; + nvec_next[1] = vec_next[0]; + + add_v2_v2v2(vec_tangent, vec_prev, vec_next); + if (normalize_v2(vec_tangent) == 0.0f) { + copy_v2_v2(vec_tangent, nvec_prev); + } + + vec_miter_left[0] = -vec_tangent[1]; + vec_miter_left[1] = vec_tangent[0]; + + /* calculate miter length */ + float an1 = dot_v2v2(vec_miter_left, nvec_prev); + if (an1 == 0.0f) { + an1 = 1.0f; + } + float miter_length = radius / an1; + if (miter_length <= 0.0f) { + miter_length = 0.01f; + } + + normalize_v2_length(vec_miter_left, miter_length); + + copy_v2_v2(vec_miter_right, vec_miter_left); + negate_v2(vec_miter_right); + + float angle = dot_v2v2(vec_next, nvec_prev); + /* Add two points if angle is close to being straight. */ + if (fabsf(angle) < 0.0001f) { + normalize_v2_length(nvec_prev, radius); + normalize_v2_length(nvec_next, radius); + + copy_v3_v3(nvec_prev_pt, curr_pt); + add_v2_v2(nvec_prev_pt, nvec_prev); + + copy_v3_v3(nvec_next_pt, curr_pt); + negate_v2(nvec_next); + add_v2_v2(nvec_next_pt, nvec_next); + + tPerimeterPoint *normal_prev = new_perimeter_point(nvec_prev_pt); + tPerimeterPoint *normal_next = new_perimeter_point(nvec_next_pt); + + BLI_addtail(perimeter_left_side, normal_prev); + BLI_addtail(perimeter_right_side, normal_next); + num_perimeter_points += 2; + } + else { + /* bend to the left */ + if (angle < 0.0f) { + normalize_v2_length(nvec_prev, radius); + normalize_v2_length(nvec_next, radius); + + copy_v3_v3(nvec_prev_pt, curr_pt); + add_v2_v2(nvec_prev_pt, nvec_prev); + + copy_v3_v3(nvec_next_pt, curr_pt); + add_v2_v2(nvec_next_pt, nvec_next); + + tPerimeterPoint *normal_prev = new_perimeter_point(nvec_prev_pt); + tPerimeterPoint *normal_next = new_perimeter_point(nvec_next_pt); + + BLI_addtail(perimeter_left_side, normal_prev); + BLI_addtail(perimeter_left_side, normal_next); + num_perimeter_points += 2; + + num_perimeter_points += generate_arc_from_point_to_point( + perimeter_left_side, normal_prev, normal_next, curr_pt, subdivisions, true); + + if (miter_length < prev_length && miter_length < next_length) { + copy_v3_v3(miter_right_pt, curr_pt); + add_v2_v2(miter_right_pt, vec_miter_right); + } + else { + copy_v3_v3(miter_right_pt, curr_pt); + negate_v2(nvec_next); + add_v2_v2(miter_right_pt, nvec_next); + } + + tPerimeterPoint *miter_right = new_perimeter_point(miter_right_pt); + BLI_addtail(perimeter_right_side, miter_right); + num_perimeter_points++; + } + /* bend to the right */ + else { + normalize_v2_length(nvec_prev, -radius); + normalize_v2_length(nvec_next, -radius); + + copy_v3_v3(nvec_prev_pt, curr_pt); + add_v2_v2(nvec_prev_pt, nvec_prev); + + copy_v3_v3(nvec_next_pt, curr_pt); + add_v2_v2(nvec_next_pt, nvec_next); + + tPerimeterPoint *normal_prev = new_perimeter_point(nvec_prev_pt); + tPerimeterPoint *normal_next = new_perimeter_point(nvec_next_pt); + + BLI_addtail(perimeter_right_side, normal_prev); + BLI_addtail(perimeter_right_side, normal_next); + num_perimeter_points += 2; + + num_perimeter_points += generate_arc_from_point_to_point( + perimeter_right_side, normal_prev, normal_next, curr_pt, subdivisions, false); + + if (miter_length < prev_length && miter_length < next_length) { + copy_v3_v3(miter_left_pt, curr_pt); + add_v2_v2(miter_left_pt, vec_miter_left); + } + else { + copy_v3_v3(miter_left_pt, curr_pt); + negate_v2(nvec_prev); + add_v2_v2(miter_left_pt, nvec_prev); + } + + tPerimeterPoint *miter_left = new_perimeter_point(miter_left_pt); + BLI_addtail(perimeter_left_side, miter_left); + num_perimeter_points++; + } + } + } + + /* generate points for end cap */ + num_perimeter_points += generate_perimeter_cap( + last_pt, last_prev_pt, last_radius, perimeter_right_side, subdivisions, gps->caps[1]); + + /* merge both sides to one list */ + BLI_listbase_reverse(perimeter_right_side); + BLI_movelisttolist(perimeter_left_side, + perimeter_right_side); // perimeter_left_side contains entire list + ListBase *perimeter_list = perimeter_left_side; + + /* close by creating a point close to the first (make a small gap) */ + float close_pt[3]; + tPerimeterPoint *close_first = (tPerimeterPoint *)perimeter_list->first; + tPerimeterPoint *close_last = (tPerimeterPoint *)perimeter_list->last; + interp_v3_v3v3(close_pt, &close_last->x, &close_first->x, 0.99f); + + if (compare_v3v3(close_pt, &close_first->x, FLT_EPSILON) == false) { + tPerimeterPoint *close_p_pt = new_perimeter_point(close_pt); + BLI_addtail(perimeter_list, close_p_pt); + num_perimeter_points++; + } + + /* free temp data */ + BLI_freelistN(perimeter_right_side); + MEM_freeN(perimeter_right_side); + + *r_num_perimeter_points = num_perimeter_points; + return perimeter_list; +} + +/** + * Calculates the perimeter of a stroke projected from the view and + * returns it as a new stroke. + * \param subdivisions: Number of subdivisions for the start and end caps + * \return: bGPDstroke pointer to stroke perimeter + */ +bGPDstroke *BKE_gpencil_stroke_perimeter_from_view(struct RegionView3D *rv3d, + bGPdata *gpd, + const bGPDlayer *gpl, + bGPDstroke *gps, + const int subdivisions, + const float diff_mat[4][4]) +{ + if (gps->totpoints == 0) { + return NULL; + } + bGPDstroke *gps_temp = BKE_gpencil_stroke_duplicate(gps, true, false); + const bool cyclic = ((gps_temp->flag & GP_STROKE_CYCLIC) != 0); + + /* If Cyclic, add a new point. */ + if (cyclic && (gps_temp->totpoints > 1)) { + gps_temp->totpoints++; + gps_temp->points = MEM_recallocN(gps_temp->points, + sizeof(*gps_temp->points) * gps_temp->totpoints); + bGPDspoint *pt_src = &gps_temp->points[0]; + bGPDspoint *pt_dst = &gps_temp->points[gps_temp->totpoints - 1]; + copy_v3_v3(&pt_dst->x, &pt_src->x); + pt_dst->pressure = pt_src->pressure; + pt_dst->strength = pt_src->strength; + pt_dst->uv_fac = 1.0f; + pt_dst->uv_rot = 0; + } + + BKE_gpencil_stroke_to_view_space(rv3d, gps_temp, diff_mat); + int num_perimeter_points = 0; + ListBase *perimeter_points = gpencil_stroke_perimeter_ex( + gpd, gpl, gps_temp, subdivisions, &num_perimeter_points); + + if (num_perimeter_points == 0) { + return NULL; + } + + /* Create new stroke. */ + bGPDstroke *perimeter_stroke = BKE_gpencil_stroke_new(gps_temp->mat_nr, num_perimeter_points, 1); + + int i = 0; + LISTBASE_FOREACH_INDEX (tPerimeterPoint *, curr, perimeter_points, i) { + bGPDspoint *pt = &perimeter_stroke->points[i]; + + copy_v3_v3(&pt->x, &curr->x); + pt->pressure = 0.0f; + pt->strength = 1.0f; + + pt->flag |= GP_SPOINT_SELECT; + } + + BKE_gpencil_stroke_from_view_space(rv3d, perimeter_stroke, diff_mat); + + /* Free temp data. */ + BLI_freelistN(perimeter_points); + MEM_freeN(perimeter_points); + + /* Triangles cache needs to be recalculated. */ + BKE_gpencil_stroke_geometry_update(gpd, perimeter_stroke); + + perimeter_stroke->flag |= GP_STROKE_SELECT | GP_STROKE_CYCLIC; + + BKE_gpencil_free_stroke(gps_temp); + + return perimeter_stroke; +} + +/** Get average pressure. */ +float BKE_gpencil_stroke_average_pressure_get(bGPDstroke *gps) +{ + + if (gps->totpoints == 1) { + return gps->points[0].pressure; + } + + float tot = 0.0f; + for (int i = 0; i < gps->totpoints; i++) { + const bGPDspoint *pt = &gps->points[i]; + tot += pt->pressure; + } + + return tot / (float)gps->totpoints; +} + +/** Check if the thickness of the stroke is constant. */ +bool BKE_gpencil_stroke_is_pressure_constant(bGPDstroke *gps) +{ + if (gps->totpoints == 1) { + return true; + } + + const float first_pressure = gps->points[0].pressure; + for (int i = 0; i < gps->totpoints; i++) { + const bGPDspoint *pt = &gps->points[i]; + if (pt->pressure != first_pressure) { + return false; + } + } + + return true; +} /** \} */ diff --git a/source/blender/blenkernel/intern/lattice.c b/source/blender/blenkernel/intern/lattice.c index 7c451051727..48104e72825 100644 --- a/source/blender/blenkernel/intern/lattice.c +++ b/source/blender/blenkernel/intern/lattice.c @@ -540,10 +540,12 @@ void BKE_lattice_vert_coords_apply(Lattice *lt, const float (*vert_coords)[3]) void BKE_lattice_modifiers_calc(struct Depsgraph *depsgraph, Scene *scene, Object *ob) { + BKE_object_free_derived_caches(ob); + if (ob->runtime.curve_cache == NULL) { + ob->runtime.curve_cache = MEM_callocN(sizeof(CurveCache), "CurveCache for lattice"); + } + Lattice *lt = ob->data; - /* Get vertex coordinates from the original copy; - * otherwise we get already-modified coordinates. */ - Object *ob_orig = DEG_get_original_object(ob); VirtualModifierData virtualModifierData; ModifierData *md = BKE_modifiers_get_virtual_modifierlist(ob, &virtualModifierData); float(*vert_coords)[3] = NULL; @@ -551,13 +553,6 @@ void BKE_lattice_modifiers_calc(struct Depsgraph *depsgraph, Scene *scene, Objec const bool is_editmode = (lt->editlatt != NULL); const ModifierEvalContext mectx = {depsgraph, ob, 0}; - if (ob->runtime.curve_cache) { - BKE_displist_free(&ob->runtime.curve_cache->disp); - } - else { - ob->runtime.curve_cache = MEM_callocN(sizeof(CurveCache), "CurveCache for lattice"); - } - for (; md; md = md->next) { const ModifierTypeInfo *mti = BKE_modifier_get_info(md->type); @@ -577,49 +572,33 @@ void BKE_lattice_modifiers_calc(struct Depsgraph *depsgraph, Scene *scene, Objec continue; } - if (!vert_coords) { - Lattice *lt_orig = ob_orig->data; - if (lt_orig->editlatt) { - lt_orig = lt_orig->editlatt->latt; - } - vert_coords = BKE_lattice_vert_coords_alloc(lt_orig, &numVerts); + if (vert_coords == NULL) { + /* Get either the edit-mode or regular lattice, whichever is in use now. */ + const Lattice *effective_lattice = BKE_object_get_lattice(ob); + vert_coords = BKE_lattice_vert_coords_alloc(effective_lattice, &numVerts); } + mti->deformVerts(md, &mectx, NULL, vert_coords, numVerts); } - if (ob->id.tag & LIB_TAG_COPIED_ON_WRITE) { - if (vert_coords) { - BKE_lattice_vert_coords_apply(ob->data, vert_coords); - MEM_freeN(vert_coords); - } + if (vert_coords == NULL) { + return; } - else { - /* Displist won't do anything; this is just for posterity's sake until we remove it. */ - if (!vert_coords) { - Lattice *lt_orig = ob_orig->data; - if (lt_orig->editlatt) { - lt_orig = lt_orig->editlatt->latt; - } - vert_coords = BKE_lattice_vert_coords_alloc(lt_orig, &numVerts); - } - - DispList *dl = MEM_callocN(sizeof(*dl), "lt_dl"); - dl->type = DL_VERTS; - dl->parts = 1; - dl->nr = numVerts; - dl->verts = (float *)vert_coords; - BLI_addtail(&ob->runtime.curve_cache->disp, dl); + Lattice *lt_eval = BKE_object_get_evaluated_lattice(ob); + if (lt_eval == NULL) { + BKE_id_copy_ex(NULL, <->id, (ID **)<_eval, LIB_ID_COPY_LOCALIZE); + BKE_object_eval_assign_data(ob, <_eval->id, true); } + + BKE_lattice_vert_coords_apply(lt_eval, vert_coords); + MEM_freeN(vert_coords); } struct MDeformVert *BKE_lattice_deform_verts_get(const struct Object *oblatt) { - Lattice *lt = (Lattice *)oblatt->data; BLI_assert(oblatt->type == OB_LATTICE); - if (lt->editlatt) { - lt = lt->editlatt->latt; - } + Lattice *lt = BKE_object_get_lattice(oblatt); return lt->dvert; } diff --git a/source/blender/blenkernel/intern/lattice_deform.c b/source/blender/blenkernel/intern/lattice_deform.c index 2651042939f..4a926ee3d96 100644 --- a/source/blender/blenkernel/intern/lattice_deform.c +++ b/source/blender/blenkernel/intern/lattice_deform.c @@ -47,6 +47,7 @@ #include "BKE_key.h" #include "BKE_lattice.h" #include "BKE_modifier.h" +#include "BKE_object.h" #include "BKE_deform.h" @@ -69,7 +70,7 @@ typedef struct LatticeDeformData { LatticeDeformData *BKE_lattice_deform_data_create(const Object *oblatt, const Object *ob) { /* we make an array with all differences */ - Lattice *lt = oblatt->data; + Lattice *lt = BKE_object_get_lattice(oblatt); BPoint *bp; DispList *dl = oblatt->runtime.curve_cache ? BKE_displist_find(&oblatt->runtime.curve_cache->disp, DL_VERTS) : @@ -83,9 +84,6 @@ LatticeDeformData *BKE_lattice_deform_data_create(const Object *oblatt, const Ob float latmat[4][4]; LatticeDeformData *lattice_deform_data; - if (lt->editlatt) { - lt = lt->editlatt->latt; - } bp = lt->def; const int32_t num_points = lt->pntsu * lt->pntsv * lt->pntsw; diff --git a/source/blender/blenkernel/intern/lattice_deform_test.cc b/source/blender/blenkernel/intern/lattice_deform_test.cc index f08d0349598..a7cd5c36ec2 100644 --- a/source/blender/blenkernel/intern/lattice_deform_test.cc +++ b/source/blender/blenkernel/intern/lattice_deform_test.cc @@ -51,6 +51,7 @@ static void test_lattice_deform_init(LatticeDeformTestContext *ctx, ctx->coords[index][2] = (rng->get_float() - 0.5f) * 10; } IDType_ID_LT.init_data(&ctx->lattice.id); + strcpy(ctx->lattice.id.name, "LTLattice"); IDType_ID_OB.init_data(&ctx->ob_lattice.id); ctx->ob_lattice.type = OB_LATTICE; ctx->ob_lattice.data = &ctx->lattice; diff --git a/source/blender/blenkernel/intern/lib_override.c b/source/blender/blenkernel/intern/lib_override.c index 8b23acdde9b..ebe8043d41d 100644 --- a/source/blender/blenkernel/intern/lib_override.c +++ b/source/blender/blenkernel/intern/lib_override.c @@ -118,7 +118,7 @@ IDOverrideLibrary *BKE_lib_override_library_init(ID *local_id, ID *reference_id) /** Shalow or deep copy of a whole override from \a src_id to \a dst_id. */ void BKE_lib_override_library_copy(ID *dst_id, const ID *src_id, const bool do_full_copy) { - BLI_assert(ID_IS_OVERRIDE_LIBRARY(src_id)); + BLI_assert(ID_IS_OVERRIDE_LIBRARY(src_id) || ID_IS_OVERRIDE_LIBRARY_TEMPLATE(src_id)); if (dst_id->override_library != NULL) { if (src_id->override_library == NULL) { @@ -437,6 +437,10 @@ static bool lib_override_hierarchy_dependencies_recursive_tag(LibOverrideGroupTa } /* We only consider IDs from the same library. */ ID *to_id = *to_id_entry->id_pointer.to; + if (!ID_IS_LINKED(to_id) && !ID_IS_OVERRIDE_LIBRARY(to_id)) { + /* Pure local data is a barrier of dependency in override cases. */ + continue; + } if (to_id != NULL && to_id->lib == id->lib) { LibOverrideGroupTagData sub_data = *data; sub_data.id_root = to_id; @@ -812,10 +816,29 @@ bool BKE_lib_override_library_create( BKE_main_id_clear_newpoins(bmain); BKE_main_id_tag_all(bmain, LIB_TAG_DOIT, false); + /* We need to rebuild some of the deleted override rules (for UI feedback purpose). */ + BKE_lib_override_library_main_operations_create(bmain, true); + return success; } /** + * Create a library override template. + */ +bool BKE_lib_override_library_template_create(struct ID *id) +{ + if (ID_IS_LINKED(id)) { + return false; + } + if (ID_IS_OVERRIDE_LIBRARY(id)) { + return false; + } + + BKE_lib_override_library_init(id, NULL); + return true; +} + +/** * Convert a given proxy object into a library override. * * \note This is a thin wrapper around \a BKE_lib_override_library_create, only extra work is to diff --git a/source/blender/blenkernel/intern/mask.c b/source/blender/blenkernel/intern/mask.c index 3a3ad9ef051..a3f122115d8 100644 --- a/source/blender/blenkernel/intern/mask.c +++ b/source/blender/blenkernel/intern/mask.c @@ -1893,10 +1893,17 @@ static void interp_weights_uv_v2_calc(float r_uv[2], const float pt_a[2], const float pt_b[2]) { + const float segment_len = len_v2v2(pt_a, pt_b); + if (segment_len == 0.0f) { + r_uv[0] = 1.0f; + r_uv[1] = 0.0f; + return; + } + float pt_on_line[2]; r_uv[0] = closest_to_line_v2(pt_on_line, pt, pt_a, pt_b); - r_uv[1] = (len_v2v2(pt_on_line, pt) / len_v2v2(pt_a, pt_b)) * + r_uv[1] = (len_v2v2(pt_on_line, pt) / segment_len) * /* This line only sets the sign. */ ((line_point_side_v2(pt_a, pt_b, pt) < 0.0f) ? -1.0f : 1.0f); } diff --git a/source/blender/blenkernel/intern/node.cc b/source/blender/blenkernel/intern/node.cc index d06e4030117..315ff40289d 100644 --- a/source/blender/blenkernel/intern/node.cc +++ b/source/blender/blenkernel/intern/node.cc @@ -778,6 +778,13 @@ static void lib_link_node_socket(BlendLibReader *reader, Library *lib, bNodeSock { IDP_BlendReadLib(reader, sock->prop); + /* This can happen for all socket types when a file is saved in an older version of Blender than + * it was originally created in (T86298). Some socket types still require a default value. The + * default value of those sockets will be created in `ntreeSetTypes`. */ + if (sock->default_value == nullptr) { + return; + } + switch ((eNodeSocketDatatype)sock->type) { case SOCK_OBJECT: { bNodeSocketValueObject *default_value = (bNodeSocketValueObject *)sock->default_value; @@ -1364,7 +1371,9 @@ GHashIterator *nodeSocketTypeGetIterator(void) return BLI_ghashIterator_new(nodesockettypes_hash); } -struct bNodeSocket *nodeFindSocket(const bNode *node, int in_out, const char *identifier) +struct bNodeSocket *nodeFindSocket(const bNode *node, + eNodeSocketInOut in_out, + const char *identifier) { const ListBase *sockets = (in_out == SOCK_IN) ? &node->inputs : &node->outputs; LISTBASE_FOREACH (bNodeSocket *, sock, sockets) { @@ -1521,7 +1530,7 @@ void nodeModifySocketType( bNodeSocket *nodeAddSocket(bNodeTree *ntree, bNode *node, - int in_out, + eNodeSocketInOut in_out, const char *idname, const char *identifier, const char *name) @@ -1543,7 +1552,7 @@ bNodeSocket *nodeAddSocket(bNodeTree *ntree, bNodeSocket *nodeInsertSocket(bNodeTree *ntree, bNode *node, - int in_out, + eNodeSocketInOut in_out, const char *idname, bNodeSocket *next_sock, const char *identifier, @@ -1704,7 +1713,7 @@ const char *nodeStaticSocketInterfaceType(int type, int subtype) bNodeSocket *nodeAddStaticSocket(bNodeTree *ntree, bNode *node, - int in_out, + eNodeSocketInOut in_out, int type, int subtype, const char *identifier, @@ -1724,7 +1733,7 @@ bNodeSocket *nodeAddStaticSocket(bNodeTree *ntree, bNodeSocket *nodeInsertStaticSocket(bNodeTree *ntree, bNode *node, - int in_out, + eNodeSocketInOut in_out, int type, int subtype, bNodeSocket *next_sock, @@ -3220,7 +3229,7 @@ void ntreeLocalMerge(Main *bmain, bNodeTree *localtree, bNodeTree *ntree) /* ************ NODE TREE INTERFACE *************** */ static bNodeSocket *make_socket_interface(bNodeTree *ntree, - int in_out, + eNodeSocketInOut in_out, const char *idname, const char *name) { @@ -3256,7 +3265,9 @@ static bNodeSocket *make_socket_interface(bNodeTree *ntree, return sock; } -bNodeSocket *ntreeFindSocketInterface(bNodeTree *ntree, int in_out, const char *identifier) +bNodeSocket *ntreeFindSocketInterface(bNodeTree *ntree, + eNodeSocketInOut in_out, + const char *identifier) { ListBase *sockets = (in_out == SOCK_IN) ? &ntree->inputs : &ntree->outputs; LISTBASE_FOREACH (bNodeSocket *, iosock, sockets) { @@ -3268,7 +3279,7 @@ bNodeSocket *ntreeFindSocketInterface(bNodeTree *ntree, int in_out, const char * } bNodeSocket *ntreeAddSocketInterface(bNodeTree *ntree, - int in_out, + eNodeSocketInOut in_out, const char *idname, const char *name) { @@ -3284,8 +3295,11 @@ bNodeSocket *ntreeAddSocketInterface(bNodeTree *ntree, return iosock; } -bNodeSocket *ntreeInsertSocketInterface( - bNodeTree *ntree, int in_out, const char *idname, bNodeSocket *next_sock, const char *name) +bNodeSocket *ntreeInsertSocketInterface(bNodeTree *ntree, + eNodeSocketInOut in_out, + const char *idname, + bNodeSocket *next_sock, + const char *name) { bNodeSocket *iosock = make_socket_interface(ntree, in_out, idname, name); if (in_out == SOCK_IN) { @@ -3304,7 +3318,7 @@ struct bNodeSocket *ntreeAddSocketInterfaceFromSocket(bNodeTree *ntree, bNodeSocket *from_sock) { bNodeSocket *iosock = ntreeAddSocketInterface( - ntree, from_sock->in_out, from_sock->idname, from_sock->name); + ntree, static_cast<eNodeSocketInOut>(from_sock->in_out), from_sock->idname, from_sock->name); if (iosock) { if (iosock->typeinfo->interface_from_socket) { iosock->typeinfo->interface_from_socket(ntree, iosock, from_node, from_sock); @@ -3319,7 +3333,11 @@ struct bNodeSocket *ntreeInsertSocketInterfaceFromSocket(bNodeTree *ntree, bNodeSocket *from_sock) { bNodeSocket *iosock = ntreeInsertSocketInterface( - ntree, from_sock->in_out, from_sock->idname, next_sock, from_sock->name); + ntree, + static_cast<eNodeSocketInOut>(from_sock->in_out), + from_sock->idname, + next_sock, + from_sock->name); if (iosock) { if (iosock->typeinfo->interface_from_socket) { iosock->typeinfo->interface_from_socket(ntree, iosock, from_node, from_sock); @@ -4693,6 +4711,7 @@ static void registerCompositNodes() register_node_type_cmp_defocus(); register_node_type_cmp_sunbeams(); register_node_type_cmp_denoise(); + register_node_type_cmp_antialiasing(); register_node_type_cmp_valtorgb(); register_node_type_cmp_rgbtobw(); @@ -4903,11 +4922,13 @@ static void registerGeometryNodes() register_node_type_geo_group(); register_node_type_geo_align_rotation_to_vector(); + register_node_type_geo_attribute_clamp(); register_node_type_geo_attribute_color_ramp(); register_node_type_geo_attribute_combine_xyz(); register_node_type_geo_attribute_compare(); register_node_type_geo_attribute_convert(); register_node_type_geo_attribute_fill(); + register_node_type_geo_attribute_map_range(); register_node_type_geo_attribute_math(); register_node_type_geo_attribute_mix(); register_node_type_geo_attribute_proximity(); @@ -4924,9 +4945,9 @@ static void registerGeometryNodes() register_node_type_geo_mesh_primitive_cone(); register_node_type_geo_mesh_primitive_cube(); register_node_type_geo_mesh_primitive_cylinder(); + register_node_type_geo_mesh_primitive_grid(); register_node_type_geo_mesh_primitive_ico_sphere(); register_node_type_geo_mesh_primitive_line(); - register_node_type_geo_mesh_primitive_plane(); register_node_type_geo_mesh_primitive_uv_sphere(); register_node_type_geo_object_info(); register_node_type_geo_point_distribute(); diff --git a/source/blender/blenkernel/intern/object.c b/source/blender/blenkernel/intern/object.c index b07c4b22c39..8c5a4966633 100644 --- a/source/blender/blenkernel/intern/object.c +++ b/source/blender/blenkernel/intern/object.c @@ -4353,8 +4353,6 @@ void BKE_object_handle_update_ex(Depsgraph *depsgraph, BKE_object_handle_data_update(depsgraph, scene, ob); } - ob->id.recalc &= ID_RECALC_ALL; - object_handle_update_proxy(depsgraph, scene, ob, do_proxy_update); } @@ -4474,6 +4472,37 @@ Mesh *BKE_object_get_original_mesh(Object *object) return result; } +Lattice *BKE_object_get_lattice(const Object *object) +{ + ID *data = object->data; + if (data == NULL || GS(data->name) != ID_LT) { + return NULL; + } + + Lattice *lt = (Lattice *)data; + if (lt->editlatt) { + return lt->editlatt->latt; + } + + return lt; +} + +Lattice *BKE_object_get_evaluated_lattice(const Object *object) +{ + ID *data_eval = object->runtime.data_eval; + + if (data_eval == NULL || GS(data_eval->name) != ID_LT) { + return NULL; + } + + Lattice *lt_eval = (Lattice *)data_eval; + if (lt_eval->editlatt) { + return lt_eval->editlatt->latt; + } + + return lt_eval; +} + static int pc_cmp(const void *a, const void *b) { const LinkData *ad = a, *bd = b; diff --git a/source/blender/blenkernel/intern/screen.c b/source/blender/blenkernel/intern/screen.c index 6a0c9460a01..89451d70c74 100644 --- a/source/blender/blenkernel/intern/screen.c +++ b/source/blender/blenkernel/intern/screen.c @@ -1530,9 +1530,6 @@ static void direct_link_area(BlendDataReader *reader, ScrArea *area) if (sl->spacetype == SPACE_VIEW3D) { View3D *v3d = (View3D *)sl; - - v3d->flag |= V3D_INVALID_BACKBUF; - if (v3d->gpd) { BLO_read_data_address(reader, &v3d->gpd); BKE_gpencil_blend_read_data(reader, v3d->gpd); diff --git a/source/blender/blenkernel/intern/softbody.c b/source/blender/blenkernel/intern/softbody.c index de88e8a941c..d52e4443ac1 100644 --- a/source/blender/blenkernel/intern/softbody.c +++ b/source/blender/blenkernel/intern/softbody.c @@ -3181,9 +3181,11 @@ void sbFree(Object *ob) return; } + const bool is_orig = (ob->id.tag & LIB_TAG_COPIED_ON_WRITE) == 0; + free_softbody_intern(sb); - if ((ob->id.tag & LIB_TAG_NO_MAIN) == 0) { + if (is_orig) { /* Only free shared data on non-CoW copies */ BKE_ptcache_free_list(&sb->shared->ptcaches); sb->shared->pointcache = NULL; diff --git a/source/blender/blenkernel/intern/tracking.c b/source/blender/blenkernel/intern/tracking.c index d124922acd1..f3d6bc4a6e3 100644 --- a/source/blender/blenkernel/intern/tracking.c +++ b/source/blender/blenkernel/intern/tracking.c @@ -3251,6 +3251,11 @@ static void tracking_dopesheet_calc_coverage(MovieTracking *tracking) end_frame = max_ii(end_frame, track->markers[track->markersnr - 1].framenr); } + if (start_frame > end_frame) { + /* There are no markers at all, nothing to calculate coverage from. */ + return; + } + frames = end_frame - start_frame + 1; /* this is a per-frame counter of markers (how many markers belongs to the same frame) */ diff --git a/source/blender/blenkernel/intern/writeffmpeg.c b/source/blender/blenkernel/intern/writeffmpeg.c index 0991d804882..7fc9e8cc0ef 100644 --- a/source/blender/blenkernel/intern/writeffmpeg.c +++ b/source/blender/blenkernel/intern/writeffmpeg.c @@ -567,9 +567,6 @@ static AVStream *alloc_video_stream(FFMpegContext *context, /* Set up the codec context */ c = st->codec; - c->thread_count = BLI_system_thread_count(); - c->thread_type = FF_THREAD_SLICE; - c->codec_id = codec_id; c->codec_type = AVMEDIA_TYPE_VIDEO; @@ -727,6 +724,20 @@ static AVStream *alloc_video_stream(FFMpegContext *context, set_ffmpeg_properties(rd, c, "video", &opts); + if (codec->capabilities & AV_CODEC_CAP_AUTO_THREADS) { + c->thread_count = 0; + } + else { + c->thread_count = BLI_system_thread_count(); + } + + if (codec->capabilities & AV_CODEC_CAP_FRAME_THREADS) { + c->thread_type = FF_THREAD_FRAME; + } + else if (codec->capabilities & AV_CODEC_CAP_SLICE_THREADS) { + c->thread_type = FF_THREAD_SLICE; + } + if (avcodec_open2(c, codec, &opts) < 0) { BLI_strncpy(error, IMB_ffmpeg_last_error(), error_size); av_dict_free(&opts); diff --git a/source/blender/blenlib/BLI_asan.h b/source/blender/blenlib/BLI_asan.h index a2a44e164ab..c38ad6b39d0 100644 --- a/source/blender/blenlib/BLI_asan.h +++ b/source/blender/blenlib/BLI_asan.h @@ -21,7 +21,7 @@ # define __has_feature(x) 0 #endif -#if defined(__SANITIZE_ADDRESS__) || __has_feature(address_sanitizer) +#if (defined(__SANITIZE_ADDRESS__) || __has_feature(address_sanitizer)) && !defined(_MSC_VER) # include "sanitizer/asan_interface.h" #else /* Ensure return value is used. Just using UNUSED_VARS results in a warning. */ diff --git a/source/blender/blenlib/BLI_hash.hh b/source/blender/blenlib/BLI_hash.hh index 39695b110b1..4022c2baa1f 100644 --- a/source/blender/blenlib/BLI_hash.hh +++ b/source/blender/blenlib/BLI_hash.hh @@ -206,19 +206,38 @@ template<typename T> struct DefaultHash<T *> { } }; +template<typename T> uint64_t get_default_hash(const T &v) +{ + return DefaultHash<T>{}(v); +} + +template<typename T1, typename T2> uint64_t get_default_hash_2(const T1 &v1, const T2 &v2) +{ + const uint64_t h1 = get_default_hash(v1); + const uint64_t h2 = get_default_hash(v2); + return h1 ^ (h2 * 19349669); +} + +template<typename T1, typename T2, typename T3> +uint64_t get_default_hash_3(const T1 &v1, const T2 &v2, const T3 &v3) +{ + const uint64_t h1 = get_default_hash(v1); + const uint64_t h2 = get_default_hash(v2); + const uint64_t h3 = get_default_hash(v3); + return h1 ^ (h2 * 19349669) ^ (h3 * 83492791); +} + template<typename T> struct DefaultHash<std::unique_ptr<T>> { uint64_t operator()(const std::unique_ptr<T> &value) const { - return DefaultHash<T *>{}(value.get()); + return get_default_hash(value.get()); } }; template<typename T1, typename T2> struct DefaultHash<std::pair<T1, T2>> { uint64_t operator()(const std::pair<T1, T2> &value) const { - uint64_t hash1 = DefaultHash<T1>{}(value.first); - uint64_t hash2 = DefaultHash<T2>{}(value.second); - return hash1 ^ (hash2 * 33); + return get_default_hash_2(value.first, value.second); } }; diff --git a/source/blender/blenlib/BLI_set.hh b/source/blender/blenlib/BLI_set.hh index fef657b2d8f..a8ccf957f6c 100644 --- a/source/blender/blenlib/BLI_set.hh +++ b/source/blender/blenlib/BLI_set.hh @@ -788,6 +788,8 @@ class Set { template<typename ForwardKey> const Key &lookup_key_or_add__impl(ForwardKey &&key, const uint64_t hash) { + this->ensure_can_add(); + SET_SLOT_PROBING_BEGIN (hash, slot) { if (slot.contains(key, is_equal_, hash)) { return *slot.key(); diff --git a/source/blender/blenlib/BLI_user_counter.hh b/source/blender/blenlib/BLI_user_counter.hh index ef276814981..3e6d5af4c3f 100644 --- a/source/blender/blenlib/BLI_user_counter.hh +++ b/source/blender/blenlib/BLI_user_counter.hh @@ -125,7 +125,7 @@ template<typename T> class UserCounter { uint64_t hash() const { - return DefaultHash<T *>{}(data_); + return get_default_hash(data_); } friend bool operator==(const UserCounter &a, const UserCounter &b) diff --git a/source/blender/blenlib/CMakeLists.txt b/source/blender/blenlib/CMakeLists.txt index 37b0f742b8b..d7a27cc4531 100644 --- a/source/blender/blenlib/CMakeLists.txt +++ b/source/blender/blenlib/CMakeLists.txt @@ -263,6 +263,7 @@ set(SRC BLI_session_uuid.h BLI_set.hh BLI_set_slots.hh + BLI_simd.h BLI_smallhash.h BLI_sort.h BLI_sort_utils.h diff --git a/source/blender/blenlib/intern/math_base_inline.c b/source/blender/blenlib/intern/math_base_inline.c index 6481fac5a14..2a7c091d1b9 100644 --- a/source/blender/blenlib/intern/math_base_inline.c +++ b/source/blender/blenlib/intern/math_base_inline.c @@ -192,6 +192,13 @@ MINLINE double ratiod(double min, double max, double pos) return range == 0 ? 0 : ((pos - min) / range); } +/* Map a normalized value, i.e. from interval [0, 1] to interval [a, b] */ +MINLINE float scalenorm(float a, float b, float x) +{ + BLI_assert(x <= 1 && x >= 0); + return (x * (b - a)) + a; +} + /* used for zoom values*/ MINLINE float power_of_2(float val) { diff --git a/source/blender/blenlib/intern/math_vec.cc b/source/blender/blenlib/intern/math_vec.cc index 1d138d0b0f4..223c0e273f0 100644 --- a/source/blender/blenlib/intern/math_vec.cc +++ b/source/blender/blenlib/intern/math_vec.cc @@ -173,7 +173,7 @@ mpq3 mpq3::cross_poly(Span<mpq3> poly) uint64_t hash_mpq_class(const mpq_class &value) { /* TODO: better/faster implementation of this. */ - return DefaultHash<float>{}(static_cast<float>(value.get_d())); + return get_default_hash(static_cast<float>(value.get_d())); } uint64_t mpq2::hash() const diff --git a/source/blender/blenlib/intern/mesh_boolean.cc b/source/blender/blenlib/intern/mesh_boolean.cc index bc12ff1a652..bf70b044d0d 100644 --- a/source/blender/blenlib/intern/mesh_boolean.cc +++ b/source/blender/blenlib/intern/mesh_boolean.cc @@ -97,10 +97,7 @@ class Edge { uint64_t hash() const { - constexpr uint64_t h1 = 33; - uint64_t v0hash = DefaultHash<int>{}(v_[0]->id); - uint64_t v1hash = DefaultHash<int>{}(v_[1]->id); - return v0hash ^ (v1hash * h1); + return get_default_hash_2(v_[0]->id, v_[1]->id); } }; diff --git a/source/blender/blenlib/tests/BLI_set_test.cc b/source/blender/blenlib/tests/BLI_set_test.cc index 56f1d57e4ae..3a4733a218f 100644 --- a/source/blender/blenlib/tests/BLI_set_test.cc +++ b/source/blender/blenlib/tests/BLI_set_test.cc @@ -456,8 +456,8 @@ TEST(set, LookupKeyPtr) TEST(set, LookupKeyOrAdd) { Set<MyKeyType> set; - set.add({1, 10}); - set.add({2, 20}); + set.lookup_key_or_add({1, 10}); + set.lookup_key_or_add({2, 20}); EXPECT_EQ(set.size(), 2); EXPECT_EQ(set.lookup_key_or_add({2, 40}).attached_data, 20); EXPECT_EQ(set.size(), 2); diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c index f97f6f65551..b657cb8b2f9 100644 --- a/source/blender/blenloader/intern/readfile.c +++ b/source/blender/blenloader/intern/readfile.c @@ -2497,9 +2497,12 @@ static void direct_link_id_common( /* Link direct data of overrides. */ if (id->override_library) { BLO_read_data_address(reader, &id->override_library); - BLO_read_list_cb( - reader, &id->override_library->properties, direct_link_id_override_property_cb); - id->override_library->runtime = NULL; + /* Work around file corruption on writing, see T86853. */ + if (id->override_library != NULL) { + BLO_read_list_cb( + reader, &id->override_library->properties, direct_link_id_override_property_cb); + id->override_library->runtime = NULL; + } } DrawDataList *drawdata = DRW_drawdatalist_from_id(id); diff --git a/source/blender/blenloader/intern/versioning_290.c b/source/blender/blenloader/intern/versioning_290.c index 80cd21338d6..0cd18d27587 100644 --- a/source/blender/blenloader/intern/versioning_290.c +++ b/source/blender/blenloader/intern/versioning_290.c @@ -27,6 +27,7 @@ #include "BLI_utildefines.h" #include "DNA_anim_types.h" +#include "DNA_armature_types.h" #include "DNA_brush_types.h" #include "DNA_cachefile_types.h" #include "DNA_collection_types.h" @@ -1926,6 +1927,18 @@ void blo_do_versions_290(FileData *fd, Library *UNUSED(lib), Main *bmain) } } + if (!MAIN_VERSION_ATLEAST(bmain, 293, 15)) { + LISTBASE_FOREACH (bNodeTree *, ntree, &bmain->nodetrees) { + if (ntree->type == NTREE_GEOMETRY) { + LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { + if (STREQ(node->idname, "GeometryNodeMeshPlane")) { + STRNCPY(node->idname, "GeometryNodeMeshGrid"); + } + } + } + } + } + /** * Versioning code until next subversion bump goes here. * @@ -1937,6 +1950,20 @@ void blo_do_versions_290(FileData *fd, Library *UNUSED(lib), Main *bmain) */ { /* Keep this block, even when empty. */ + + FOREACH_NODETREE_BEGIN (bmain, ntree, id) { + if (ntree->type == NTREE_GEOMETRY) { + version_node_socket_name(ntree, GEO_NODE_VOLUME_TO_MESH, "Grid", "Density"); + } + } + FOREACH_NODETREE_END; + + if (!DNA_struct_elem_find(fd->filesdna, "bArmature", "float", "axes_position")) { + /* Convert the axes draw position to its old default (tip of bone). */ + LISTBASE_FOREACH (struct bArmature *, arm, &bmain->armatures) { + arm->axes_position = 1.0; + } + } } { diff --git a/source/blender/blenloader/intern/versioning_legacy.c b/source/blender/blenloader/intern/versioning_legacy.c index e43f8153bd1..f2e73e161ca 100644 --- a/source/blender/blenloader/intern/versioning_legacy.c +++ b/source/blender/blenloader/intern/versioning_legacy.c @@ -81,6 +81,7 @@ #include "BKE_pointcache.h" #include "SEQ_iterator.h" +#include "SEQ_sequencer.h" #include "NOD_socket.h" @@ -2560,18 +2561,16 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *bmain) if (bmain->versionfile < 249 && bmain->subversionfile < 2) { Scene *sce = bmain->scenes.first; - Sequence *seq; Editing *ed; while (sce) { ed = sce->ed; if (ed) { - SEQ_CURRENT_BEGIN (ed, seq) { + LISTBASE_FOREACH (Sequence *, seq, SEQ_active_seqbase_get(ed)) { if (seq->strip && seq->strip->proxy) { seq->strip->proxy->quality = 90; } } - SEQ_CURRENT_END; } sce = sce->id.next; diff --git a/source/blender/blenloader/intern/versioning_userdef.c b/source/blender/blenloader/intern/versioning_userdef.c index 8cbedb05931..847b10192f8 100644 --- a/source/blender/blenloader/intern/versioning_userdef.c +++ b/source/blender/blenloader/intern/versioning_userdef.c @@ -261,17 +261,7 @@ static void do_versions_theme(const UserDef *userdef, bTheme *btheme) FROM_DEFAULT_V4_UCHAR(space_node.nodeclass_shader); } - /** - * Versioning code until next subversion bump goes here. - * - * \note Be sure to check when bumping the version: - * - #blo_do_versions_userdef in this file. - * - "versioning_{BLENDER_VERSION}.c" - * - * \note Keep this message at the bottom of the function. - */ - { - /* Keep this block, even when empty. */ + if (!USER_VERSION_ATLEAST(293, 15)) { FROM_DEFAULT_V4_UCHAR(space_properties.active); FROM_DEFAULT_V4_UCHAR(space_info.info_error); @@ -286,6 +276,19 @@ static void do_versions_theme(const UserDef *userdef, bTheme *btheme) btheme->space_spreadsheet = btheme->space_outliner; } + /** + * Versioning code until next subversion bump goes here. + * + * \note Be sure to check when bumping the version: + * - #blo_do_versions_userdef in this file. + * - "versioning_{BLENDER_VERSION}.c" + * + * \note Keep this message at the bottom of the function. + */ + { + /* Keep this block, even when empty. */ + } + #undef FROM_DEFAULT_V4_UCHAR #undef USER_VERSION_ATLEAST diff --git a/source/blender/compositor/CMakeLists.txt b/source/blender/compositor/CMakeLists.txt index 64033cbe5c4..c8ee8af4542 100644 --- a/source/blender/compositor/CMakeLists.txt +++ b/source/blender/compositor/CMakeLists.txt @@ -87,8 +87,6 @@ set(SRC intern/COM_OpenCLDevice.h intern/COM_SingleThreadedOperation.cc intern/COM_SingleThreadedOperation.h - intern/COM_SocketReader.cc - intern/COM_SocketReader.h intern/COM_WorkPackage.cc intern/COM_WorkPackage.h intern/COM_WorkScheduler.cc @@ -296,6 +294,9 @@ set(SRC nodes/COM_FilterNode.h nodes/COM_InpaintNode.cc nodes/COM_InpaintNode.h + nodes/COM_AntiAliasingNode.cc + nodes/COM_AntiAliasingNode.h + operations/COM_BlurBaseOperation.cc operations/COM_BlurBaseOperation.h operations/COM_BokehBlurOperation.cc @@ -322,6 +323,8 @@ set(SRC operations/COM_MovieDistortionOperation.h operations/COM_VariableSizeBokehBlurOperation.cc operations/COM_VariableSizeBokehBlurOperation.h + operations/COM_SMAAOperation.cc + operations/COM_SMAAOperation.h # Matte nodes nodes/COM_BoxMaskNode.cc @@ -568,6 +571,23 @@ data_to_c( add_definitions(-DCL_USE_DEPRECATED_OPENCL_1_1_APIS) +set(GENSRC_DIR ${CMAKE_CURRENT_BINARY_DIR}/operations) +set(GENSRC ${GENSRC_DIR}/COM_SMAAAreaTexture.h) +add_custom_command( + OUTPUT ${GENSRC} + COMMAND ${CMAKE_COMMAND} -E make_directory ${GENSRC_DIR} + COMMAND "$<TARGET_FILE:smaa_areatex>" ${GENSRC} + DEPENDS smaa_areatex +) +add_custom_target(smaa_areatex_header + SOURCES ${GENSRC} +) +list(APPEND SRC + ${GENSRC} +) +unset(GENSRC) +unset(GENSRC_DIR) + if(WITH_INTERNATIONAL) add_definitions(-DWITH_INTERNATIONAL) endif() @@ -586,3 +606,5 @@ if(WITH_OPENIMAGEDENOISE) endif() blender_add_lib(bf_compositor "${SRC}" "${INC}" "${INC_SYS}" "${LIB}") + +add_dependencies(bf_compositor smaa_areatex_header) diff --git a/source/blender/compositor/COM_compositor.h b/source/blender/compositor/COM_compositor.h index 8e3caf7aaf5..300a06005ac 100644 --- a/source/blender/compositor/COM_compositor.h +++ b/source/blender/compositor/COM_compositor.h @@ -113,11 +113,11 @@ extern "C" { * * When the chunk-order is determined, the first few chunks will be checked if they can be scheduled. * Chunks can have three states: - * - [@ref eChunkExecutionState.NOT_SCHEDULED]: + * - [@ref eChunkExecutionState.NotScheduled]: * Chunk is not yet scheduled, or dependencies are not met. - * - [@ref eChunkExecutionState.SCHEDULED]: + * - [@ref eChunkExecutionState.Scheduled]: * All dependencies are met, chunk is scheduled, but not finished. - * - [@ref eChunkExecutionState.EXECUTED]: + * - [@ref eChunkExecutionState.Executed]: * Chunk is finished. * * \see ExecutionGroup.execute diff --git a/source/blender/compositor/COM_defines.h b/source/blender/compositor/COM_defines.h index 266f532ebb8..5a5868f1909 100644 --- a/source/blender/compositor/COM_defines.h +++ b/source/blender/compositor/COM_defines.h @@ -18,6 +18,8 @@ #pragma once +namespace blender::compositor { + /** * \brief possible data types for sockets * \ingroup Model @@ -32,6 +34,25 @@ enum class DataType { }; /** + * Utility to get the number of channels of the given data type. + */ +constexpr int COM_data_type_num_channels(const DataType datatype) +{ + switch (datatype) { + case DataType::Value: + return 1; + case DataType::Vector: + return 3; + case DataType::Color: + default: + return 4; + } +} + +constexpr int COM_DATA_TYPE_VALUE_CHANNELS = COM_data_type_num_channels(DataType::Value); +constexpr int COM_DATA_TYPE_COLOR_CHANNELS = COM_data_type_num_channels(DataType::Color); + +/** * \brief Possible quality settings * \see CompositorContext.quality * \ingroup Execution @@ -58,11 +79,29 @@ enum class CompositorPriority { Low = 0, }; +/** + * \brief the execution state of a chunk in an ExecutionGroup + * \ingroup Execution + */ +enum class eChunkExecutionState { + /** + * \brief chunk is not yet scheduled + */ + NotScheduled = 0, + /** + * \brief chunk is scheduled, but not yet executed + */ + Scheduled = 1, + /** + * \brief chunk is executed. + */ + Executed = 2, +}; + // configurable items // chunk size determination -#define COM_PREVIEW_SIZE 140.0f -//#define COM_DEBUG +// #define COM_DEBUG // chunk order /** @@ -82,10 +121,8 @@ enum class ChunkOrdering { Default = ChunkOrdering::CenterOut, }; -#define COM_RULE_OF_THIRDS_DIVIDER 100.0f - -#define COM_NUM_CHANNELS_VALUE 1 -#define COM_NUM_CHANNELS_VECTOR 3 -#define COM_NUM_CHANNELS_COLOR 4 +constexpr float COM_PREVIEW_SIZE = 140.f; +constexpr float COM_RULE_OF_THIRDS_DIVIDER = 100.0f; +constexpr float COM_BLUR_BOKEH_PIXELS = 512; -#define COM_BLUR_BOKEH_PIXELS 512 +} // namespace blender::compositor diff --git a/source/blender/compositor/intern/COM_CPUDevice.cc b/source/blender/compositor/intern/COM_CPUDevice.cc index b520a437008..29a82bec636 100644 --- a/source/blender/compositor/intern/COM_CPUDevice.cc +++ b/source/blender/compositor/intern/COM_CPUDevice.cc @@ -18,19 +18,23 @@ #include "COM_CPUDevice.h" +#include "COM_ExecutionGroup.h" + +#include "BLI_rect.h" + +namespace blender::compositor { + CPUDevice::CPUDevice(int thread_id) : m_thread_id(thread_id) { } -void CPUDevice::execute(WorkPackage *work) +void CPUDevice::execute(WorkPackage *work_package) { - const unsigned int chunkNumber = work->chunk_number; - ExecutionGroup *executionGroup = work->execution_group; - rcti rect; - - executionGroup->determineChunkRect(&rect, chunkNumber); - - executionGroup->getOutputOperation()->executeRegion(&rect, chunkNumber); + const unsigned int chunkNumber = work_package->chunk_number; + ExecutionGroup *executionGroup = work_package->execution_group; + executionGroup->getOutputOperation()->executeRegion(&work_package->rect, chunkNumber); executionGroup->finalizeChunkExecution(chunkNumber, nullptr); } + +} // namespace blender::compositor diff --git a/source/blender/compositor/intern/COM_CPUDevice.h b/source/blender/compositor/intern/COM_CPUDevice.h index 962380d7bc8..99629890b30 100644 --- a/source/blender/compositor/intern/COM_CPUDevice.h +++ b/source/blender/compositor/intern/COM_CPUDevice.h @@ -20,6 +20,8 @@ #include "COM_Device.h" +namespace blender::compositor { + /** * \brief class representing a CPU device. * \note for every hardware thread in the system a CPUDevice instance @@ -33,7 +35,7 @@ class CPUDevice : public Device { * \brief execute a WorkPackage * \param work: the WorkPackage to execute */ - void execute(WorkPackage *work); + void execute(WorkPackage *work) override; int thread_id() { @@ -43,3 +45,5 @@ class CPUDevice : public Device { protected: int m_thread_id; }; + +} // namespace blender::compositor diff --git a/source/blender/compositor/intern/COM_ChunkOrder.cc b/source/blender/compositor/intern/COM_ChunkOrder.cc index 9687154120d..a03718d720d 100644 --- a/source/blender/compositor/intern/COM_ChunkOrder.cc +++ b/source/blender/compositor/intern/COM_ChunkOrder.cc @@ -20,6 +20,8 @@ #include "BLI_math.h" +namespace blender::compositor { + void ChunkOrder::update_distance(ChunkOrderHotspot *hotspots, unsigned int len_hotspots) { double new_distance = DBL_MAX; @@ -36,3 +38,5 @@ bool operator<(const ChunkOrder &a, const ChunkOrder &b) { return a.distance < b.distance; } + +} // namespace blender::compositor diff --git a/source/blender/compositor/intern/COM_ChunkOrder.h b/source/blender/compositor/intern/COM_ChunkOrder.h index a634309f345..a697f9231d9 100644 --- a/source/blender/compositor/intern/COM_ChunkOrder.h +++ b/source/blender/compositor/intern/COM_ChunkOrder.h @@ -24,6 +24,8 @@ #include "COM_ChunkOrderHotspot.h" +namespace blender::compositor { + /** Helper to determine the order how chunks are prioritized during execution. */ struct ChunkOrder { unsigned int index = 0; @@ -39,3 +41,5 @@ struct ChunkOrder { MEM_CXX_CLASS_ALLOC_FUNCS("COM:ChunkOrderHotspot") #endif }; + +} // namespace blender::compositor diff --git a/source/blender/compositor/intern/COM_ChunkOrderHotspot.cc b/source/blender/compositor/intern/COM_ChunkOrderHotspot.cc index d31ff518ecd..79afcc9deea 100644 --- a/source/blender/compositor/intern/COM_ChunkOrderHotspot.cc +++ b/source/blender/compositor/intern/COM_ChunkOrderHotspot.cc @@ -19,6 +19,8 @@ #include "COM_ChunkOrderHotspot.h" #include <cmath> +namespace blender::compositor { + double ChunkOrderHotspot::calc_distance(int x, int y) { int dx = this->x - x; @@ -27,3 +29,5 @@ double ChunkOrderHotspot::calc_distance(int x, int y) result += (double)this->addition; return result; } + +} // namespace blender::compositor
\ No newline at end of file diff --git a/source/blender/compositor/intern/COM_ChunkOrderHotspot.h b/source/blender/compositor/intern/COM_ChunkOrderHotspot.h index d7f40921836..249b328f5c2 100644 --- a/source/blender/compositor/intern/COM_ChunkOrderHotspot.h +++ b/source/blender/compositor/intern/COM_ChunkOrderHotspot.h @@ -22,6 +22,8 @@ # include "MEM_guardedalloc.h" #endif +namespace blender::compositor { + struct ChunkOrderHotspot { int x; int y; @@ -37,3 +39,5 @@ struct ChunkOrderHotspot { MEM_CXX_CLASS_ALLOC_FUNCS("COM:ChunkOrderHotspot") #endif }; + +} // namespace blender::compositor diff --git a/source/blender/compositor/intern/COM_CompositorContext.cc b/source/blender/compositor/intern/COM_CompositorContext.cc index e2447fb5c13..fdd47a6ca79 100644 --- a/source/blender/compositor/intern/COM_CompositorContext.cc +++ b/source/blender/compositor/intern/COM_CompositorContext.cc @@ -20,6 +20,10 @@ #include "COM_defines.h" #include <cstdio> +#include "BLI_assert.h" + +namespace blender::compositor { + CompositorContext::CompositorContext() { this->m_scene = nullptr; @@ -33,9 +37,8 @@ CompositorContext::CompositorContext() int CompositorContext::getFramenumber() const { - if (this->m_rd) { - return this->m_rd->cfra; - } - - return -1; /* this should never happen */ + BLI_assert(m_rd); + return m_rd->cfra; } + +} // namespace blender::compositor diff --git a/source/blender/compositor/intern/COM_CompositorContext.h b/source/blender/compositor/intern/COM_CompositorContext.h index 46cf65bbb79..c6468865fc8 100644 --- a/source/blender/compositor/intern/COM_CompositorContext.h +++ b/source/blender/compositor/intern/COM_CompositorContext.h @@ -26,6 +26,8 @@ #include <string> #include <vector> +namespace blender::compositor { + /** * \brief Overall context of the compositor */ @@ -277,3 +279,5 @@ class CompositorContext { return m_rd->size * 0.01f; } }; + +} // namespace blender::compositor diff --git a/source/blender/compositor/intern/COM_Converter.cc b/source/blender/compositor/intern/COM_Converter.cc index d5bce636b8c..af593b2e1b5 100644 --- a/source/blender/compositor/intern/COM_Converter.cc +++ b/source/blender/compositor/intern/COM_Converter.cc @@ -26,6 +26,7 @@ #include "COM_NodeOperationBuilder.h" #include "COM_AlphaOverNode.h" +#include "COM_AntiAliasingNode.h" #include "COM_BilateralBlurNode.h" #include "COM_BlurNode.h" #include "COM_BokehBlurNode.h" @@ -115,6 +116,8 @@ #include "COM_ViewerNode.h" #include "COM_ZCombineNode.h" +namespace blender::compositor { + bool COM_bnode_is_fast_node(const bNode &b_node) { return !ELEM(b_node.type, @@ -418,6 +421,9 @@ Node *COM_convert_bnode(bNode *b_node) case CMP_NODE_EXPOSURE: node = new ExposureNode(b_node); break; + case CMP_NODE_ANTIALIASING: + node = new AntiAliasingNode(b_node); + break; } return node; } @@ -454,7 +460,7 @@ void COM_convert_resolution(NodeOperationBuilder &builder, NodeOperationOutput *fromSocket, NodeOperationInput *toSocket) { - InputResizeMode mode = toSocket->getResizeMode(); + ResizeMode mode = toSocket->getResizeMode(); NodeOperation *toOperation = &toSocket->getOperation(); const float toWidth = toOperation->getWidth(); @@ -470,22 +476,22 @@ void COM_convert_resolution(NodeOperationBuilder &builder, float scaleY = 0; switch (mode) { - case COM_SC_NO_RESIZE: + case ResizeMode::None: break; - case COM_SC_CENTER: + case ResizeMode::Center: doCenter = true; break; - case COM_SC_FIT_WIDTH: + case ResizeMode::FitWidth: doCenter = true; doScale = true; scaleX = scaleY = toWidth / fromWidth; break; - case COM_SC_FIT_HEIGHT: + case ResizeMode::FitHeight: doCenter = true; doScale = true; scaleX = scaleY = toHeight / fromHeight; break; - case COM_SC_FIT: + case ResizeMode::FitAny: doCenter = true; doScale = true; scaleX = toWidth / fromWidth; @@ -497,7 +503,7 @@ void COM_convert_resolution(NodeOperationBuilder &builder, scaleY = scaleX; } break; - case COM_SC_STRETCH: + case ResizeMode::Stretch: doCenter = true; doScale = true; scaleX = toWidth / fromWidth; @@ -510,8 +516,8 @@ void COM_convert_resolution(NodeOperationBuilder &builder, ScaleOperation *scaleOperation = nullptr; if (doScale) { scaleOperation = new ScaleOperation(); - scaleOperation->getInputSocket(1)->setResizeMode(COM_SC_NO_RESIZE); - scaleOperation->getInputSocket(2)->setResizeMode(COM_SC_NO_RESIZE); + scaleOperation->getInputSocket(1)->setResizeMode(ResizeMode::None); + scaleOperation->getInputSocket(2)->setResizeMode(ResizeMode::None); first = scaleOperation; SetValueOperation *sxop = new SetValueOperation(); sxop->setValue(scaleX); @@ -530,8 +536,8 @@ void COM_convert_resolution(NodeOperationBuilder &builder, } TranslateOperation *translateOperation = new TranslateOperation(); - translateOperation->getInputSocket(1)->setResizeMode(COM_SC_NO_RESIZE); - translateOperation->getInputSocket(2)->setResizeMode(COM_SC_NO_RESIZE); + translateOperation->getInputSocket(1)->setResizeMode(ResizeMode::None); + translateOperation->getInputSocket(2)->setResizeMode(ResizeMode::None); if (!first) { first = translateOperation; } @@ -551,15 +557,17 @@ void COM_convert_resolution(NodeOperationBuilder &builder, builder.addOperation(translateOperation); if (doScale) { - translateOperation->getInputSocket(0)->setResizeMode(COM_SC_NO_RESIZE); + translateOperation->getInputSocket(0)->setResizeMode(ResizeMode::None); builder.addLink(scaleOperation->getOutputSocket(), translateOperation->getInputSocket(0)); } /* remove previous link and replace */ builder.removeInputLink(toSocket); - first->getInputSocket(0)->setResizeMode(COM_SC_NO_RESIZE); - toSocket->setResizeMode(COM_SC_NO_RESIZE); + first->getInputSocket(0)->setResizeMode(ResizeMode::None); + toSocket->setResizeMode(ResizeMode::None); builder.addLink(fromSocket, first->getInputSocket(0)); builder.addLink(translateOperation->getOutputSocket(), toSocket); } } + +} // namespace blender::compositor diff --git a/source/blender/compositor/intern/COM_Converter.h b/source/blender/compositor/intern/COM_Converter.h index 59be34bf0e3..28136437103 100644 --- a/source/blender/compositor/intern/COM_Converter.h +++ b/source/blender/compositor/intern/COM_Converter.h @@ -18,14 +18,17 @@ #pragma once +#include "COM_NodeOperation.h" + #ifdef WITH_CXX_GUARDEDALLOC # include "MEM_guardedalloc.h" #endif struct bNode; +namespace blender::compositor { + class Node; -class NodeOperation; class NodeOperationInput; class NodeOperationOutput; class NodeOperationBuilder; @@ -65,3 +68,5 @@ NodeOperation *COM_convert_data_type(const NodeOperationOutput &from, void COM_convert_resolution(NodeOperationBuilder &builder, NodeOperationOutput *fromSocket, NodeOperationInput *toSocket); + +} // namespace blender::compositor diff --git a/source/blender/compositor/intern/COM_Debug.cc b/source/blender/compositor/intern/COM_Debug.cc index c299bd1c72d..56bc2dc947f 100644 --- a/source/blender/compositor/intern/COM_Debug.cc +++ b/source/blender/compositor/intern/COM_Debug.cc @@ -18,30 +18,31 @@ #include "COM_Debug.h" -#ifdef COM_DEBUG - -# include <map> -# include <typeinfo> -# include <vector> +#include <map> +#include <typeinfo> +#include <vector> extern "C" { -# include "BLI_fileops.h" -# include "BLI_path_util.h" -# include "BLI_string.h" -# include "BLI_sys_types.h" - -# include "BKE_appdir.h" -# include "BKE_node.h" -# include "DNA_node_types.h" +#include "BLI_fileops.h" +#include "BLI_path_util.h" +#include "BLI_string.h" +#include "BLI_sys_types.h" + +#include "BKE_appdir.h" +#include "BKE_node.h" +#include "DNA_node_types.h" } -# include "COM_ExecutionGroup.h" -# include "COM_ExecutionSystem.h" -# include "COM_Node.h" +#include "COM_ExecutionSystem.h" +#include "COM_Node.h" + +#include "COM_ReadBufferOperation.h" +#include "COM_ViewerOperation.h" +#include "COM_WriteBufferOperation.h" -# include "COM_ReadBufferOperation.h" -# include "COM_ViewerOperation.h" -# include "COM_WriteBufferOperation.h" +namespace blender::compositor { + +#ifdef COM_DEBUG int DebugInfo::m_file_index = 0; DebugInfo::NodeNameMap DebugInfo::m_node_names; @@ -113,7 +114,7 @@ void DebugInfo::execution_group_finished(const ExecutionGroup *group) } int DebugInfo::graphviz_operation(const ExecutionSystem *system, - const NodeOperation *operation, + NodeOperation *operation, const ExecutionGroup *group, char *str, int maxlen) @@ -121,7 +122,7 @@ int DebugInfo::graphviz_operation(const ExecutionSystem *system, int len = 0; std::string fillcolor = "gainsboro"; - if (operation->isViewerOperation()) { + if (operation->get_flags().is_viewer_operation) { const ViewerOperation *viewer = (const ViewerOperation *)operation; if (viewer->isActiveViewerOutput()) { fillcolor = "lightskyblue1"; @@ -133,13 +134,13 @@ int DebugInfo::graphviz_operation(const ExecutionSystem *system, else if (operation->isOutputOperation(system->getContext().isRendering())) { fillcolor = "dodgerblue1"; } - else if (operation->isSetOperation()) { + else if (operation->get_flags().is_set_operation) { fillcolor = "khaki1"; } - else if (operation->isReadBufferOperation()) { + else if (operation->get_flags().is_read_buffer_operation) { fillcolor = "darkolivegreen3"; } - else if (operation->isWriteBufferOperation()) { + else if (operation->get_flags().is_write_buffer_operation) { fillcolor = "darkorange"; } @@ -360,7 +361,7 @@ bool DebugInfo::graphviz_system(const ExecutionSystem *system, char *str, int ma } for (NodeOperation *operation : system->m_operations) { - if (operation->isReadBufferOperation()) { + if (operation->get_flags().is_read_buffer_operation) { ReadBufferOperation *read = (ReadBufferOperation *)operation; WriteBufferOperation *write = read->getMemoryProxy()->getWriteBufferOperation(); std::vector<std::string> &read_groups = op_groups[read]; @@ -381,8 +382,8 @@ bool DebugInfo::graphviz_system(const ExecutionSystem *system, char *str, int ma } for (NodeOperation *op : system->m_operations) { - for (NodeOperationInput *to : op->m_inputs) { - NodeOperationOutput *from = to->getLink(); + for (NodeOperationInput &to : op->m_inputs) { + NodeOperationOutput *from = to.getLink(); if (!from) { continue; @@ -401,7 +402,7 @@ bool DebugInfo::graphviz_system(const ExecutionSystem *system, char *str, int ma break; } - NodeOperation *to_op = &to->getOperation(); + NodeOperation *to_op = &to.getOperation(); NodeOperation *from_op = &from->getOperation(); std::vector<std::string> &from_groups = op_groups[from_op]; std::vector<std::string> &to_groups = op_groups[to_op]; @@ -412,7 +413,7 @@ bool DebugInfo::graphviz_system(const ExecutionSystem *system, char *str, int ma from_op, from, to_op, - to); + &to); for (int k = 0; k < from_groups.size(); k++) { for (int l = 0; l < to_groups.size(); l++) { len += snprintf(str + len, @@ -423,7 +424,7 @@ bool DebugInfo::graphviz_system(const ExecutionSystem *system, char *str, int ma from, to_op, to_groups[l].c_str(), - to); + &to); len += snprintf( str + len, maxlen > len ? maxlen - len : 0, " [color=%s]", color.c_str()); len += snprintf(str + len, maxlen > len ? maxlen - len : 0, "\r\n"); @@ -495,3 +496,5 @@ void DebugInfo::graphviz(const ExecutionSystem * /*system*/) } #endif + +} // namespace blender::compositor diff --git a/source/blender/compositor/intern/COM_Debug.h b/source/blender/compositor/intern/COM_Debug.h index 0107d8b396d..bf7b981fbd5 100644 --- a/source/blender/compositor/intern/COM_Debug.h +++ b/source/blender/compositor/intern/COM_Debug.h @@ -21,10 +21,12 @@ #include <map> #include <string> +#include "COM_NodeOperation.h" #include "COM_defines.h" +namespace blender::compositor { + class Node; -class NodeOperation; class ExecutionSystem; class ExecutionGroup; @@ -55,7 +57,7 @@ class DebugInfo { #ifdef COM_DEBUG protected: static int graphviz_operation(const ExecutionSystem *system, - const NodeOperation *operation, + NodeOperation *operation, const ExecutionGroup *group, char *str, int maxlen); @@ -81,3 +83,5 @@ class DebugInfo { static GroupStateMap m_group_states; #endif }; + +} // namespace blender::compositor diff --git a/source/blender/compositor/intern/COM_Device.h b/source/blender/compositor/intern/COM_Device.h index 0b0f0f5c1c6..2a43c1be2b4 100644 --- a/source/blender/compositor/intern/COM_Device.h +++ b/source/blender/compositor/intern/COM_Device.h @@ -20,6 +20,8 @@ #include "COM_WorkPackage.h" +namespace blender::compositor { + /** * \brief Abstract class for device implementations to be used by the Compositor. * devices are queried, initialized and used by the WorkScheduler. @@ -37,21 +39,6 @@ class Device { } /** - * \brief initialize the device - */ - virtual bool initialize() - { - return true; - } - - /** - * \brief deinitialize the device - */ - virtual void deinitialize() - { - } - - /** * \brief execute a WorkPackage * \param work: the WorkPackage to execute */ @@ -61,3 +48,5 @@ class Device { MEM_CXX_CLASS_ALLOC_FUNCS("COM:Device") #endif }; + +} // namespace blender::compositor diff --git a/source/blender/compositor/intern/COM_ExecutionGroup.cc b/source/blender/compositor/intern/COM_ExecutionGroup.cc index 3cedc5da663..37c363501ad 100644 --- a/source/blender/compositor/intern/COM_ExecutionGroup.cc +++ b/source/blender/compositor/intern/COM_ExecutionGroup.cc @@ -46,10 +46,10 @@ #include "WM_api.h" #include "WM_types.h" +namespace blender::compositor { + ExecutionGroup::ExecutionGroup() { - this->m_is_output = false; - this->m_complex = false; this->m_bTree = nullptr; this->m_height = 0; this->m_width = 0; @@ -57,42 +57,39 @@ ExecutionGroup::ExecutionGroup() this->m_x_chunks_len = 0; this->m_y_chunks_len = 0; this->m_chunks_len = 0; - this->m_initialized = false; - this->m_openCL = false; - this->m_singleThreaded = false; this->m_chunks_finished = 0; BLI_rcti_init(&this->m_viewerBorder, 0, 0, 0, 0); this->m_executionStartTime = 0; } -CompositorPriority ExecutionGroup::getRenderPriotrity() +CompositorPriority ExecutionGroup::getRenderPriority() { return this->getOutputOperation()->getRenderPriority(); } bool ExecutionGroup::can_contain(NodeOperation &operation) { - if (!this->m_initialized) { + if (!m_flags.initialized) { return true; } - if (operation.isReadBufferOperation()) { + if (operation.get_flags().is_read_buffer_operation) { return true; } - if (operation.isWriteBufferOperation()) { + if (operation.get_flags().is_write_buffer_operation) { return false; } - if (operation.isSetOperation()) { + if (operation.get_flags().is_set_operation) { return true; } /* complex groups don't allow further ops (except read buffer and values, see above) */ - if (m_complex) { + if (m_flags.complex) { return false; } /* complex ops can't be added to other groups (except their own, which they initialize, see * above) */ - if (operation.isComplex()) { + if (operation.get_flags().complex) { return false; } @@ -105,11 +102,12 @@ bool ExecutionGroup::addOperation(NodeOperation *operation) return false; } - if (!operation->isReadBufferOperation() && !operation->isWriteBufferOperation()) { - m_complex = operation->isComplex(); - m_openCL = operation->isOpenCL(); - m_singleThreaded = operation->isSingleThreaded(); - m_initialized = true; + if (!operation->get_flags().is_read_buffer_operation && + !operation->get_flags().is_write_buffer_operation) { + m_flags.complex = operation->get_flags().complex; + m_flags.open_cl = operation->get_flags().open_cl; + m_flags.single_threaded = operation->get_flags().single_threaded; + m_flags.initialized = true; } m_operations.append(operation); @@ -125,20 +123,23 @@ NodeOperation *ExecutionGroup::getOutputOperation() const void ExecutionGroup::initExecution() { - m_chunk_execution_states.clear(); + m_work_packages.clear(); determineNumberOfChunks(); if (this->m_chunks_len != 0) { - m_chunk_execution_states.resize(this->m_chunks_len); - for (int index = 0; index < this->m_chunks_len; index++) { - m_chunk_execution_states[index] = eChunkExecutionState::NOT_SCHEDULED; + m_work_packages.resize(this->m_chunks_len); + for (unsigned int index = 0; index < m_chunks_len; index++) { + m_work_packages[index].state = eChunkExecutionState::NotScheduled; + m_work_packages[index].execution_group = this; + m_work_packages[index].chunk_number = index; + determineChunkRect(&m_work_packages[index].rect, index); } } unsigned int max_offset = 0; for (NodeOperation *operation : m_operations) { - if (operation->isReadBufferOperation()) { + if (operation->get_flags().is_read_buffer_operation) { ReadBufferOperation *readOperation = static_cast<ReadBufferOperation *>(operation); this->m_read_operations.append(readOperation); max_offset = MAX2(max_offset, readOperation->getOffset()); @@ -150,7 +151,7 @@ void ExecutionGroup::initExecution() void ExecutionGroup::deinitExecution() { - m_chunk_execution_states.clear(); + m_work_packages.clear(); this->m_chunks_len = 0; this->m_x_chunks_len = 0; this->m_y_chunks_len = 0; @@ -168,7 +169,7 @@ void ExecutionGroup::determineResolution(unsigned int resolution[2]) void ExecutionGroup::determineNumberOfChunks() { - if (this->m_singleThreaded) { + if (this->m_flags.single_threaded) { this->m_x_chunks_len = 1; this->m_y_chunks_len = 1; this->m_chunks_len = 1; @@ -185,7 +186,6 @@ void ExecutionGroup::determineNumberOfChunks() blender::Array<unsigned int> ExecutionGroup::determine_chunk_execution_order() const { - int index; blender::Array<unsigned int> chunk_order(m_chunks_len); for (int chunk_index = 0; chunk_index < this->m_chunks_len; chunk_index++) { chunk_order[chunk_index] = chunk_index; @@ -196,7 +196,7 @@ blender::Array<unsigned int> ExecutionGroup::determine_chunk_execution_order() c float centerY = 0.5f; ChunkOrdering order_type = ChunkOrdering::Default; - if (operation->isViewerOperation()) { + if (operation->get_flags().is_viewer_operation) { ViewerOperation *viewer = (ViewerOperation *)operation; centerX = viewer->getCenterX(); centerY = viewer->getCenterY(); @@ -205,7 +205,7 @@ blender::Array<unsigned int> ExecutionGroup::determine_chunk_execution_order() c const int border_width = BLI_rcti_size_x(&this->m_viewerBorder); const int border_height = BLI_rcti_size_y(&this->m_viewerBorder); - + int index; switch (order_type) { case ChunkOrdering::Random: { static blender::RandomNumberGenerator rng; @@ -219,11 +219,10 @@ blender::Array<unsigned int> ExecutionGroup::determine_chunk_execution_order() c ChunkOrderHotspot hotspot(border_width * centerX, border_height * centerY, 0.0f); blender::Array<ChunkOrder> chunk_orders(m_chunks_len); for (index = 0; index < this->m_chunks_len; index++) { - rcti rect; - determineChunkRect(&rect, index); + const WorkPackage &work_package = m_work_packages[index]; chunk_orders[index].index = index; - chunk_orders[index].x = rect.xmin - this->m_viewerBorder.xmin; - chunk_orders[index].y = rect.ymin - this->m_viewerBorder.ymin; + chunk_orders[index].x = work_package.rect.xmin - this->m_viewerBorder.xmin; + chunk_orders[index].y = work_package.rect.ymin - this->m_viewerBorder.ymin; chunk_orders[index].update_distance(&hotspot, 1); } @@ -257,11 +256,10 @@ blender::Array<unsigned int> ExecutionGroup::determine_chunk_execution_order() c blender::Array<ChunkOrder> chunk_orders(m_chunks_len); for (index = 0; index < this->m_chunks_len; index++) { - rcti rect; - determineChunkRect(&rect, index); + const WorkPackage &work_package = m_work_packages[index]; chunk_orders[index].index = index; - chunk_orders[index].x = rect.xmin - this->m_viewerBorder.xmin; - chunk_orders[index].y = rect.ymin - this->m_viewerBorder.ymin; + chunk_orders[index].x = work_package.rect.xmin - this->m_viewerBorder.xmin; + chunk_orders[index].y = work_package.rect.ymin - this->m_viewerBorder.ymin; chunk_orders[index].update_distance(hotspots, 9); } @@ -303,7 +301,6 @@ void ExecutionGroup::execute(ExecutionSystem *graph) this->m_chunks_finished = 0; this->m_bTree = bTree; - unsigned int index; blender::Array<unsigned int> chunk_order = determine_chunk_execution_order(); @@ -320,13 +317,15 @@ void ExecutionGroup::execute(ExecutionSystem *graph) finished = true; int numberEvaluated = 0; - for (index = startIndex; index < this->m_chunks_len && numberEvaluated < maxNumberEvaluated; + for (int index = startIndex; + index < this->m_chunks_len && numberEvaluated < maxNumberEvaluated; index++) { chunk_index = chunk_order[index]; int yChunk = chunk_index / this->m_x_chunks_len; int xChunk = chunk_index - (yChunk * this->m_x_chunks_len); - switch (m_chunk_execution_states[chunk_index]) { - case eChunkExecutionState::NOT_SCHEDULED: { + const WorkPackage &work_package = m_work_packages[chunk_index]; + switch (work_package.state) { + case eChunkExecutionState::NotScheduled: { scheduleChunkWhenPossible(graph, xChunk, yChunk); finished = false; startEvaluated = true; @@ -337,13 +336,13 @@ void ExecutionGroup::execute(ExecutionSystem *graph) } break; } - case eChunkExecutionState::SCHEDULED: { + case eChunkExecutionState::Scheduled: { finished = false; startEvaluated = true; numberEvaluated++; break; } - case eChunkExecutionState::EXECUTED: { + case eChunkExecutionState::Executed: { if (!startEvaluated) { startIndex = index + 1; } @@ -363,15 +362,14 @@ void ExecutionGroup::execute(ExecutionSystem *graph) MemoryBuffer **ExecutionGroup::getInputBuffersOpenCL(int chunkNumber) { - rcti rect; - determineChunkRect(&rect, chunkNumber); + WorkPackage &work_package = m_work_packages[chunkNumber]; MemoryBuffer **memoryBuffers = (MemoryBuffer **)MEM_callocN( sizeof(MemoryBuffer *) * this->m_max_read_buffer_offset, __func__); rcti output; for (ReadBufferOperation *readOperation : m_read_operations) { MemoryProxy *memoryProxy = readOperation->getMemoryProxy(); - this->determineDependingAreaOfInterest(&rect, readOperation, &output); + this->determineDependingAreaOfInterest(&work_package.rect, readOperation, &output); MemoryBuffer *memoryBuffer = memoryProxy->getExecutor()->constructConsolidatedMemoryBuffer( *memoryProxy, output); memoryBuffers[readOperation->getOffset()] = memoryBuffer; @@ -390,8 +388,9 @@ MemoryBuffer *ExecutionGroup::constructConsolidatedMemoryBuffer(MemoryProxy &mem void ExecutionGroup::finalizeChunkExecution(int chunkNumber, MemoryBuffer **memoryBuffers) { - if (this->m_chunk_execution_states[chunkNumber] == eChunkExecutionState::SCHEDULED) { - this->m_chunk_execution_states[chunkNumber] = eChunkExecutionState::EXECUTED; + WorkPackage &work_package = m_work_packages[chunkNumber]; + if (work_package.state == eChunkExecutionState::Scheduled) { + work_package.state = eChunkExecutionState::Executed; } atomic_add_and_fetch_u(&this->m_chunks_finished, 1); @@ -423,23 +422,23 @@ void ExecutionGroup::finalizeChunkExecution(int chunkNumber, MemoryBuffer **memo } } -inline void ExecutionGroup::determineChunkRect(rcti *rect, +inline void ExecutionGroup::determineChunkRect(rcti *r_rect, const unsigned int xChunk, const unsigned int yChunk) const { const int border_width = BLI_rcti_size_x(&this->m_viewerBorder); const int border_height = BLI_rcti_size_y(&this->m_viewerBorder); - if (this->m_singleThreaded) { + if (this->m_flags.single_threaded) { BLI_rcti_init( - rect, this->m_viewerBorder.xmin, border_width, this->m_viewerBorder.ymin, border_height); + r_rect, this->m_viewerBorder.xmin, border_width, this->m_viewerBorder.ymin, border_height); } else { const unsigned int minx = xChunk * this->m_chunkSize + this->m_viewerBorder.xmin; const unsigned int miny = yChunk * this->m_chunkSize + this->m_viewerBorder.ymin; const unsigned int width = MIN2((unsigned int)this->m_viewerBorder.xmax, this->m_width); const unsigned int height = MIN2((unsigned int)this->m_viewerBorder.ymax, this->m_height); - BLI_rcti_init(rect, + BLI_rcti_init(r_rect, MIN2(minx, this->m_width), MIN2(minx + this->m_chunkSize, width), MIN2(miny, this->m_height), @@ -447,18 +446,18 @@ inline void ExecutionGroup::determineChunkRect(rcti *rect, } } -void ExecutionGroup::determineChunkRect(rcti *rect, const unsigned int chunkNumber) const +void ExecutionGroup::determineChunkRect(rcti *r_rect, const unsigned int chunkNumber) const { const unsigned int yChunk = chunkNumber / this->m_x_chunks_len; const unsigned int xChunk = chunkNumber - (yChunk * this->m_x_chunks_len); - determineChunkRect(rect, xChunk, yChunk); + determineChunkRect(r_rect, xChunk, yChunk); } MemoryBuffer *ExecutionGroup::allocateOutputBuffer(rcti &rect) { // we assume that this method is only called from complex execution groups. NodeOperation *operation = this->getOutputOperation(); - if (operation->isWriteBufferOperation()) { + if (operation->get_flags().is_write_buffer_operation) { WriteBufferOperation *writeOperation = (WriteBufferOperation *)operation; MemoryBuffer *buffer = new MemoryBuffer( writeOperation->getMemoryProxy(), rect, MemoryBufferState::Temporary); @@ -469,7 +468,7 @@ MemoryBuffer *ExecutionGroup::allocateOutputBuffer(rcti &rect) bool ExecutionGroup::scheduleAreaWhenPossible(ExecutionSystem *graph, rcti *area) { - if (this->m_singleThreaded) { + if (this->m_flags.single_threaded) { return scheduleChunkWhenPossible(graph, 0, 0); } // find all chunks inside the rect @@ -503,9 +502,10 @@ bool ExecutionGroup::scheduleAreaWhenPossible(ExecutionSystem *graph, rcti *area bool ExecutionGroup::scheduleChunk(unsigned int chunkNumber) { - if (this->m_chunk_execution_states[chunkNumber] == eChunkExecutionState::NOT_SCHEDULED) { - this->m_chunk_execution_states[chunkNumber] = eChunkExecutionState::SCHEDULED; - WorkScheduler::schedule(this, chunkNumber); + WorkPackage &work_package = m_work_packages[chunkNumber]; + if (work_package.state == eChunkExecutionState::NotScheduled) { + work_package.state = eChunkExecutionState::Scheduled; + WorkScheduler::schedule(&work_package); return true; } return false; @@ -524,22 +524,21 @@ bool ExecutionGroup::scheduleChunkWhenPossible(ExecutionSystem *graph, // Check if chunk is already executed or scheduled and not yet executed. const int chunk_index = chunk_y * this->m_x_chunks_len + chunk_x; - if (this->m_chunk_execution_states[chunk_index] == eChunkExecutionState::EXECUTED) { + WorkPackage &work_package = m_work_packages[chunk_index]; + if (work_package.state == eChunkExecutionState::Executed) { return true; } - if (this->m_chunk_execution_states[chunk_index] == eChunkExecutionState::SCHEDULED) { + if (work_package.state == eChunkExecutionState::Scheduled) { return false; } - rcti rect; - determineChunkRect(&rect, chunk_x, chunk_y); bool can_be_executed = true; rcti area; for (ReadBufferOperation *read_operation : m_read_operations) { BLI_rcti_init(&area, 0, 0, 0, 0); MemoryProxy *memory_proxy = read_operation->getMemoryProxy(); - determineDependingAreaOfInterest(&rect, read_operation, &area); + determineDependingAreaOfInterest(&work_package.rect, read_operation, &area); ExecutionGroup *group = memory_proxy->getExecutor(); if (!group->scheduleAreaWhenPossible(graph, &area)) { @@ -561,16 +560,10 @@ void ExecutionGroup::determineDependingAreaOfInterest(rcti *input, this->getOutputOperation()->determineDependingAreaOfInterest(input, readOperation, output); } -bool ExecutionGroup::isOpenCL() -{ - return this->m_openCL; -} - void ExecutionGroup::setViewerBorder(float xmin, float xmax, float ymin, float ymax) { - NodeOperation *operation = this->getOutputOperation(); - - if (operation->isViewerOperation() || operation->isPreviewOperation()) { + const NodeOperation &operation = *this->getOutputOperation(); + if (operation.get_flags().use_viewer_border) { BLI_rcti_init(&this->m_viewerBorder, xmin * this->m_width, xmax * this->m_width, @@ -581,32 +574,14 @@ void ExecutionGroup::setViewerBorder(float xmin, float xmax, float ymin, float y void ExecutionGroup::setRenderBorder(float xmin, float xmax, float ymin, float ymax) { - NodeOperation *operation = this->getOutputOperation(); - - if (operation->isOutputOperation(true)) { - /* Basically, setting border need to happen for only operations - * which operates in render resolution buffers (like compositor - * output nodes). - * - * In this cases adding border will lead to mapping coordinates - * from output buffer space to input buffer spaces when executing - * operation. - * - * But nodes like viewer and file output just shall display or - * safe the same exact buffer which goes to their input, no need - * in any kind of coordinates mapping. - */ - - bool operationNeedsBorder = !(operation->isViewerOperation() || - operation->isPreviewOperation() || - operation->isFileOutputOperation()); - - if (operationNeedsBorder) { - BLI_rcti_init(&this->m_viewerBorder, - xmin * this->m_width, - xmax * this->m_width, - ymin * this->m_height, - ymax * this->m_height); - } + const NodeOperation &operation = *this->getOutputOperation(); + if (operation.isOutputOperation(true) && operation.get_flags().use_render_border) { + BLI_rcti_init(&this->m_viewerBorder, + xmin * this->m_width, + xmax * this->m_width, + ymin * this->m_height, + ymax * this->m_height); } } + +} // namespace blender::compositor diff --git a/source/blender/compositor/intern/COM_ExecutionGroup.h b/source/blender/compositor/intern/COM_ExecutionGroup.h index 6fd93d2d93c..ff5c1698a75 100644 --- a/source/blender/compositor/intern/COM_ExecutionGroup.h +++ b/source/blender/compositor/intern/COM_ExecutionGroup.h @@ -31,30 +31,46 @@ #include "COM_MemoryProxy.h" #include "COM_Node.h" #include "COM_NodeOperation.h" +#include "COM_WorkPackage.h" #include <vector> +namespace blender::compositor { + class ExecutionSystem; class MemoryProxy; +class MemoryBuffer; class ReadBufferOperation; class Device; -/** - * \brief the execution state of a chunk in an ExecutionGroup - * \ingroup Execution - */ -enum class eChunkExecutionState { +struct ExecutionGroupFlags { + bool initialized : 1; /** - * \brief chunk is not yet scheduled + * Is this ExecutionGroup an output ExecutionGroup + * An OutputExecution group are groups containing a + * ViewerOperation, CompositeOperation, PreviewOperation. */ - NOT_SCHEDULED = 0, + bool is_output : 1; + bool complex : 1; + /** - * \brief chunk is scheduled, but not yet executed + * Can this ExecutionGroup be scheduled on an OpenCLDevice. */ - SCHEDULED = 1, + bool open_cl : 1; + /** - * \brief chunk is executed. + * Schedule this execution group as a single chunk. This + * chunk will be executed by a single thread. */ - EXECUTED = 2, + bool single_threaded : 1; + + ExecutionGroupFlags() + { + initialized = false; + is_output = false; + complex = false; + open_cl = false; + single_threaded = false; + } }; /** @@ -72,12 +88,7 @@ class ExecutionGroup { */ blender::Vector<NodeOperation *> m_operations; - /** - * \brief is this ExecutionGroup an input ExecutionGroup - * an input execution group is a group that is at the end of the calculation - * (the output is important for the user). - */ - bool m_is_output; + ExecutionGroupFlags m_flags; /** * \brief Width of the output @@ -111,21 +122,6 @@ class ExecutionGroup { unsigned int m_chunks_len; /** - * \brief contains this ExecutionGroup a complex NodeOperation. - */ - bool m_complex; - - /** - * \brief can this ExecutionGroup be scheduled on an OpenCLDevice - */ - bool m_openCL; - - /** - * \brief Is this Execution group SingleThreaded - */ - bool m_singleThreaded; - - /** * \brief what is the maximum number field of all ReadBufferOperation in this ExecutionGroup. * \note this is used to construct the MemoryBuffers that will be passed during execution. */ @@ -149,24 +145,9 @@ class ExecutionGroup { unsigned int m_chunks_finished; /** - * \brief m_chunk_execution_states holds per chunk the execution state. this state can be - * - eChunkExecutionState::NOT_SCHEDULED: not scheduled - * - eChunkExecutionState::SCHEDULED: scheduled - * - eChunkExecutionState::EXECUTED: executed + * \brief m_work_packages holds all unit of work. */ - blender::Vector<eChunkExecutionState> m_chunk_execution_states; - - /** - * \brief indicator when this ExecutionGroup has valid Operations in its vector for Execution - * \note When building the ExecutionGroup Operations are added via recursion. - * First a WriteBufferOperations is added, then the. - * \note Operation containing the settings that is important for the ExecutiongGroup is added, - * \note When this occurs, these settings are copied over from the node to the ExecutionGroup - * \note and the Initialized flag is set to true. - * \see complex - * \see openCL - */ - bool m_initialized; + blender::Vector<WorkPackage> m_work_packages; /** * \brief denotes boundary for border compositing @@ -187,19 +168,11 @@ class ExecutionGroup { bool can_contain(NodeOperation &operation); /** - * \brief calculate the actual chunk size of this execution group. - * \note A chunk size is an unsigned int that is both the height and width of a chunk. - * \note The chunk size will not be stored in the chunkSize field. This needs to be done - * \note by the calling method. - */ - unsigned int determineChunkSize(); - - /** * \brief Determine the rect (minx, maxx, miny, maxy) of a chunk at a position. - * \note Only gives useful results after the determination of the chunksize - * \see determineChunkSize() */ - void determineChunkRect(rcti *rect, const unsigned int xChunk, const unsigned int yChunk) const; + void determineChunkRect(rcti *r_rect, + const unsigned int xChunk, + const unsigned int yChunk) const; /** * \brief determine the number of chunks, based on the chunkSize, width and height. @@ -258,6 +231,11 @@ class ExecutionGroup { // constructors ExecutionGroup(); + const ExecutionGroupFlags get_flags() const + { + return m_flags; + } + // methods /** * \brief add an operation to this ExecutionGroup @@ -270,23 +248,12 @@ class ExecutionGroup { bool addOperation(NodeOperation *operation); /** - * \brief is this ExecutionGroup an output ExecutionGroup - * \note An OutputExecution group are groups containing a - * \note ViewerOperation, CompositeOperation, PreviewOperation. - * \see NodeOperation.isOutputOperation - */ - bool isOutputExecutionGroup() const - { - return this->m_is_output; - } - - /** * \brief set whether this ExecutionGroup is an output * \param isOutput: */ void setOutputExecutionGroup(bool is_output) { - this->m_is_output = is_output; + this->m_flags.is_output = is_output; } /** @@ -322,14 +289,6 @@ class ExecutionGroup { } /** - * \brief does this ExecutionGroup contains a complex NodeOperation - */ - bool isComplex() const - { - return m_complex; - } - - /** * \brief get the output operation of this ExecutionGroup * \return NodeOperation *output operation */ @@ -404,16 +363,8 @@ class ExecutionGroup { /** * \brief Determine the rect (minx, maxx, miny, maxy) of a chunk. - * \note Only gives useful results after the determination of the chunksize - * \see determineChunkSize() */ - void determineChunkRect(rcti *rect, const unsigned int chunkNumber) const; - - /** - * \brief can this ExecutionGroup be scheduled on an OpenCLDevice - * \see WorkScheduler.schedule - */ - bool isOpenCL(); + void determineChunkRect(rcti *r_rect, const unsigned int chunkNumber) const; void setChunksize(int chunksize) { @@ -424,7 +375,7 @@ class ExecutionGroup { * \brief get the Render priority of this ExecutionGroup * \see ExecutionSystem.execute */ - CompositorPriority getRenderPriotrity(); + CompositorPriority getRenderPriority(); /** * \brief set border for viewer operation @@ -441,3 +392,5 @@ class ExecutionGroup { MEM_CXX_CLASS_ALLOC_FUNCS("COM:ExecutionGroup") #endif }; + +} // namespace blender::compositor diff --git a/source/blender/compositor/intern/COM_ExecutionSystem.cc b/source/blender/compositor/intern/COM_ExecutionSystem.cc index 993aedf7715..9a3dc6ee56f 100644 --- a/source/blender/compositor/intern/COM_ExecutionSystem.cc +++ b/source/blender/compositor/intern/COM_ExecutionSystem.cc @@ -37,6 +37,8 @@ # include "MEM_guardedalloc.h" #endif +namespace blender::compositor { + ExecutionSystem::ExecutionSystem(RenderData *rd, Scene *scene, bNodeTree *editingtree, @@ -71,7 +73,6 @@ ExecutionSystem::ExecutionSystem(RenderData *rd, builder.convertToOperations(this); } - unsigned int index; unsigned int resolution[2]; rctf *viewer_border = &editingtree->viewer_border; @@ -81,10 +82,9 @@ ExecutionSystem::ExecutionSystem(RenderData *rd, editingtree->stats_draw(editingtree->sdh, TIP_("Compositing | Determining resolution")); - for (index = 0; index < this->m_groups.size(); index++) { + for (ExecutionGroup *executionGroup : m_groups) { resolution[0] = 0; resolution[1] = 0; - ExecutionGroup *executionGroup = this->m_groups[index]; executionGroup->determineResolution(resolution); if (rendering) { @@ -108,14 +108,12 @@ ExecutionSystem::ExecutionSystem(RenderData *rd, ExecutionSystem::~ExecutionSystem() { - unsigned int index; - for (index = 0; index < this->m_operations.size(); index++) { - NodeOperation *operation = this->m_operations[index]; + for (NodeOperation *operation : m_operations) { delete operation; } this->m_operations.clear(); - for (index = 0; index < this->m_groups.size(); index++) { - ExecutionGroup *group = this->m_groups[index]; + + for (ExecutionGroup *group : m_groups) { delete group; } this->m_groups.clear(); @@ -128,92 +126,100 @@ void ExecutionSystem::set_operations(const blender::Vector<NodeOperation *> &ope m_groups = groups; } -void ExecutionSystem::execute() +static void update_read_buffer_offset(blender::Vector<NodeOperation *> &operations) { - const bNodeTree *editingtree = this->m_context.getbNodeTree(); - editingtree->stats_draw(editingtree->sdh, TIP_("Compositing | Initializing execution")); - - DebugInfo::execute_started(this); - unsigned int order = 0; - for (NodeOperation *operation : m_operations) { - if (operation->isReadBufferOperation()) { + for (NodeOperation *operation : operations) { + if (operation->get_flags().is_read_buffer_operation) { ReadBufferOperation *readOperation = (ReadBufferOperation *)operation; readOperation->setOffset(order); order++; } } - unsigned int index; +} - // First allocale all write buffer - for (index = 0; index < this->m_operations.size(); index++) { - NodeOperation *operation = this->m_operations[index]; - if (operation->isWriteBufferOperation()) { - operation->setbNodeTree(this->m_context.getbNodeTree()); +static void init_write_operations_for_execution(blender::Vector<NodeOperation *> &operations, + const bNodeTree *bTree) +{ + for (NodeOperation *operation : operations) { + if (operation->get_flags().is_write_buffer_operation) { + operation->setbNodeTree(bTree); operation->initExecution(); } } - // Connect read buffers to their write buffers - for (index = 0; index < this->m_operations.size(); index++) { - NodeOperation *operation = this->m_operations[index]; - if (operation->isReadBufferOperation()) { - ReadBufferOperation *readOperation = (ReadBufferOperation *)operation; +} + +static void link_write_buffers(blender::Vector<NodeOperation *> &operations) +{ + for (NodeOperation *operation : operations) { + if (operation->get_flags().is_read_buffer_operation) { + ReadBufferOperation *readOperation = static_cast<ReadBufferOperation *>(operation); readOperation->updateMemoryBuffer(); } } - // initialize other operations - for (index = 0; index < this->m_operations.size(); index++) { - NodeOperation *operation = this->m_operations[index]; - if (!operation->isWriteBufferOperation()) { - operation->setbNodeTree(this->m_context.getbNodeTree()); +} + +static void init_non_write_operations_for_execution(blender::Vector<NodeOperation *> &operations, + const bNodeTree *bTree) +{ + for (NodeOperation *operation : operations) { + if (!operation->get_flags().is_write_buffer_operation) { + operation->setbNodeTree(bTree); operation->initExecution(); } } - for (index = 0; index < this->m_groups.size(); index++) { - ExecutionGroup *executionGroup = this->m_groups[index]; - executionGroup->setChunksize(this->m_context.getChunksize()); - executionGroup->initExecution(); +} + +static void init_execution_groups_for_execution(blender::Vector<ExecutionGroup *> &groups, + const int chunk_size) +{ + for (ExecutionGroup *execution_group : groups) { + execution_group->setChunksize(chunk_size); + execution_group->initExecution(); } +} - WorkScheduler::start(this->m_context); +void ExecutionSystem::execute() +{ + const bNodeTree *editingtree = this->m_context.getbNodeTree(); + editingtree->stats_draw(editingtree->sdh, TIP_("Compositing | Initializing execution")); + + DebugInfo::execute_started(this); + update_read_buffer_offset(m_operations); + init_write_operations_for_execution(m_operations, m_context.getbNodeTree()); + link_write_buffers(m_operations); + init_non_write_operations_for_execution(m_operations, m_context.getbNodeTree()); + init_execution_groups_for_execution(m_groups, m_context.getChunksize()); + + WorkScheduler::start(this->m_context); execute_groups(CompositorPriority::High); if (!this->getContext().isFastCalculation()) { execute_groups(CompositorPriority::Medium); execute_groups(CompositorPriority::Low); } - WorkScheduler::finish(); WorkScheduler::stop(); editingtree->stats_draw(editingtree->sdh, TIP_("Compositing | De-initializing execution")); - for (index = 0; index < this->m_operations.size(); index++) { - NodeOperation *operation = this->m_operations[index]; + + for (NodeOperation *operation : m_operations) { operation->deinitExecution(); } - for (index = 0; index < this->m_groups.size(); index++) { - ExecutionGroup *executionGroup = this->m_groups[index]; - executionGroup->deinitExecution(); - } -} -void ExecutionSystem::execute_groups(CompositorPriority priority) -{ - blender::Vector<ExecutionGroup *> execution_groups = find_output_execution_groups(priority); - for (ExecutionGroup *group : execution_groups) { - group->execute(this); + for (ExecutionGroup *execution_group : m_groups) { + execution_group->deinitExecution(); } } -blender::Vector<ExecutionGroup *> ExecutionSystem::find_output_execution_groups( - CompositorPriority priority) const +void ExecutionSystem::execute_groups(CompositorPriority priority) { - blender::Vector<ExecutionGroup *> result; - - for (ExecutionGroup *group : m_groups) { - if (group->isOutputExecutionGroup() && group->getRenderPriotrity() == priority) { - result.append(group); + for (ExecutionGroup *execution_group : m_groups) { + if (execution_group->get_flags().is_output && + execution_group->getRenderPriority() == priority) { + execution_group->execute(this); } } - return result; } + +} // namespace blender::compositor diff --git a/source/blender/compositor/intern/COM_ExecutionSystem.h b/source/blender/compositor/intern/COM_ExecutionSystem.h index 6a50cc6906b..b8dcd90e1a6 100644 --- a/source/blender/compositor/intern/COM_ExecutionSystem.h +++ b/source/blender/compositor/intern/COM_ExecutionSystem.h @@ -31,6 +31,8 @@ class ExecutionGroup; #include "BLI_vector.hh" +namespace blender::compositor { + /** * \page execution Execution model * In order to get to an efficient model for execution, several steps are being done. these steps @@ -70,17 +72,17 @@ class ExecutionGroup; * * - Image size conversions: the system can automatically convert when resolutions do not match. * An NodeInput has a resize mode. This can be any of the following settings. - * - [@ref InputSocketResizeMode.COM_SC_CENTER]: + * - [@ref InputSocketResizeMode.ResizeMode::Center]: * The center of both images are aligned - * - [@ref InputSocketResizeMode.COM_SC_FIT_WIDTH]: + * - [@ref InputSocketResizeMode.ResizeMode::FitWidth]: * The width of both images are aligned - * - [@ref InputSocketResizeMode.COM_SC_FIT_HEIGHT]: + * - [@ref InputSocketResizeMode.ResizeMode::FitHeight]: * The height of both images are aligned - * - [@ref InputSocketResizeMode.COM_SC_FIT]: + * - [@ref InputSocketResizeMode.ResizeMode::FitAny]: * The width, or the height of both images are aligned to make sure that it fits. - * - [@ref InputSocketResizeMode.COM_SC_STRETCH]: + * - [@ref InputSocketResizeMode.ResizeMode::Stretch]: * The width and the height of both images are aligned. - * - [@ref InputSocketResizeMode.COM_SC_NO_RESIZE]: + * - [@ref InputSocketResizeMode.ResizeMode::None]: * Bottom left of the images are aligned. * * \see COM_convert_data_type Datatype conversions @@ -135,12 +137,6 @@ class ExecutionSystem { blender::Vector<ExecutionGroup *> m_groups; private: // methods - /** - * find all execution group with output nodes - */ - blender::Vector<ExecutionGroup *> find_output_execution_groups( - CompositorPriority priority) const; - public: /** * \brief Create a new ExecutionSystem and initialize it with the @@ -192,3 +188,5 @@ class ExecutionSystem { MEM_CXX_CLASS_ALLOC_FUNCS("COM:ExecutionSystem") #endif }; + +} // namespace blender::compositor diff --git a/source/blender/compositor/intern/COM_MemoryBuffer.cc b/source/blender/compositor/intern/COM_MemoryBuffer.cc index 0b28168720e..68e39b19eaf 100644 --- a/source/blender/compositor/intern/COM_MemoryBuffer.cc +++ b/source/blender/compositor/intern/COM_MemoryBuffer.cc @@ -20,24 +20,13 @@ #include "MEM_guardedalloc.h" -static unsigned int determine_num_channels(DataType datatype) -{ - switch (datatype) { - case DataType::Value: - return COM_NUM_CHANNELS_VALUE; - case DataType::Vector: - return COM_NUM_CHANNELS_VECTOR; - case DataType::Color: - default: - return COM_NUM_CHANNELS_COLOR; - } -} +namespace blender::compositor { MemoryBuffer::MemoryBuffer(MemoryProxy *memoryProxy, const rcti &rect, MemoryBufferState state) { m_rect = rect; this->m_memoryProxy = memoryProxy; - this->m_num_channels = determine_num_channels(memoryProxy->getDataType()); + this->m_num_channels = COM_data_type_num_channels(memoryProxy->getDataType()); this->m_buffer = (float *)MEM_mallocN_aligned( sizeof(float) * buffer_len() * this->m_num_channels, 16, "COM_MemoryBuffer"); this->m_state = state; @@ -48,7 +37,7 @@ MemoryBuffer::MemoryBuffer(DataType dataType, const rcti &rect) { m_rect = rect; this->m_memoryProxy = nullptr; - this->m_num_channels = determine_num_channels(dataType); + this->m_num_channels = COM_data_type_num_channels(dataType); this->m_buffer = (float *)MEM_mallocN_aligned( sizeof(float) * buffer_len() * this->m_num_channels, 16, "COM_MemoryBuffer"); this->m_state = MemoryBufferState::Temporary; @@ -183,3 +172,5 @@ void MemoryBuffer::readEWA(float *result, const float uv[2], const float derivat this, result); } + +} // namespace blender::compositor diff --git a/source/blender/compositor/intern/COM_MemoryBuffer.h b/source/blender/compositor/intern/COM_MemoryBuffer.h index 6f719b61122..060a67f8797 100644 --- a/source/blender/compositor/intern/COM_MemoryBuffer.h +++ b/source/blender/compositor/intern/COM_MemoryBuffer.h @@ -16,17 +16,16 @@ * Copyright 2011, Blender Foundation. */ -class MemoryBuffer; - #pragma once #include "COM_ExecutionGroup.h" #include "COM_MemoryProxy.h" -#include "COM_SocketReader.h" #include "BLI_math.h" #include "BLI_rect.h" +namespace blender::compositor { + /** * \brief state of a memory buffer * \ingroup Memory @@ -331,3 +330,5 @@ class MemoryBuffer { MEM_CXX_CLASS_ALLOC_FUNCS("COM:MemoryBuffer") #endif }; + +} // namespace blender::compositor diff --git a/source/blender/compositor/intern/COM_MemoryProxy.cc b/source/blender/compositor/intern/COM_MemoryProxy.cc index 8ef834e1efe..6023850c944 100644 --- a/source/blender/compositor/intern/COM_MemoryProxy.cc +++ b/source/blender/compositor/intern/COM_MemoryProxy.cc @@ -18,6 +18,12 @@ #include "COM_MemoryProxy.h" +#include "COM_MemoryBuffer.h" + +#include "BLI_rect.h" + +namespace blender::compositor { + MemoryProxy::MemoryProxy(DataType datatype) { this->m_writeBufferOperation = nullptr; @@ -43,3 +49,5 @@ void MemoryProxy::free() this->m_buffer = nullptr; } } + +} // namespace blender::compositor diff --git a/source/blender/compositor/intern/COM_MemoryProxy.h b/source/blender/compositor/intern/COM_MemoryProxy.h index a40e6f95dce..0966eadadb2 100644 --- a/source/blender/compositor/intern/COM_MemoryProxy.h +++ b/source/blender/compositor/intern/COM_MemoryProxy.h @@ -16,13 +16,14 @@ * Copyright 2011, Blender Foundation. */ -class MemoryProxy; - #pragma once -#include "COM_ExecutionGroup.h" -#include "COM_MemoryBuffer.h" +#include "COM_defines.h" + +namespace blender::compositor { +/* Forward declarations. */ +class MemoryBuffer; class ExecutionGroup; class WriteBufferOperation; @@ -45,16 +46,6 @@ class MemoryProxy { ExecutionGroup *m_executor; /** - * \brief datatype of this MemoryProxy - */ - /* DataType m_datatype; */ /* UNUSED */ - - /** - * \brief channel information of this buffer - */ - /* ChannelInfo m_channelInfo[COM_NUMBER_OF_CHANNELS]; */ /* UNUSED */ - - /** * \brief the allocated memory */ MemoryBuffer *m_buffer; @@ -129,3 +120,5 @@ class MemoryProxy { MEM_CXX_CLASS_ALLOC_FUNCS("COM:MemoryProxy") #endif }; + +} // namespace blender::compositor diff --git a/source/blender/compositor/intern/COM_MetaData.cc b/source/blender/compositor/intern/COM_MetaData.cc index ad72b242c8c..6762955ef78 100644 --- a/source/blender/compositor/intern/COM_MetaData.cc +++ b/source/blender/compositor/intern/COM_MetaData.cc @@ -24,6 +24,8 @@ #include <string_view> +namespace blender::compositor { + void MetaData::add(const blender::StringRef key, const blender::StringRef value) { entries_.add(key, value); @@ -104,3 +106,5 @@ void MetaDataExtractCallbackData::extract_cryptomatte_meta_data(void *_data, data->addMetaData(META_DATA_KEY_CRYPTOMATTE_MANIFEST, propvalue); } } + +} // namespace blender::compositor diff --git a/source/blender/compositor/intern/COM_MetaData.h b/source/blender/compositor/intern/COM_MetaData.h index fa3de895b4e..ce437fd5df8 100644 --- a/source/blender/compositor/intern/COM_MetaData.h +++ b/source/blender/compositor/intern/COM_MetaData.h @@ -28,6 +28,8 @@ /* Forward declarations. */ struct RenderResult; +namespace blender::compositor { + /* Cryptomatte includes hash in its meta data keys. The hash is generated from the render * layer/pass name. Compositing happens without the knowledge of the original layer and pass. The * next keys are used to transfer the cryptomatte meta data in a neutral way. The file output node @@ -69,3 +71,5 @@ struct MetaDataExtractCallbackData { char *propvalue, int UNUSED(len)); }; + +} // namespace blender::compositor diff --git a/source/blender/compositor/intern/COM_Node.cc b/source/blender/compositor/intern/COM_Node.cc index 819f1c02b14..6ac48e3646c 100644 --- a/source/blender/compositor/intern/COM_Node.cc +++ b/source/blender/compositor/intern/COM_Node.cc @@ -32,6 +32,8 @@ #include "COM_Node.h" /* own include */ +namespace blender::compositor { + /************** **** Node **** **************/ @@ -74,13 +76,11 @@ Node::Node(bNode *editorNode, bool create_sockets) Node::~Node() { - while (!this->m_outputsockets.empty()) { - delete (this->m_outputsockets.back()); - this->m_outputsockets.pop_back(); + while (!this->outputs.is_empty()) { + delete (this->outputs.pop_last()); } - while (!this->m_inputsockets.empty()) { - delete (this->m_inputsockets.back()); - this->m_inputsockets.pop_back(); + while (!this->inputs.is_empty()) { + delete (this->inputs.pop_last()); } } @@ -92,7 +92,7 @@ void Node::addInputSocket(DataType datatype) void Node::addInputSocket(DataType datatype, bNodeSocket *bSocket) { NodeInput *socket = new NodeInput(this, bSocket, datatype); - this->m_inputsockets.push_back(socket); + this->inputs.append(socket); } void Node::addOutputSocket(DataType datatype) @@ -102,19 +102,17 @@ void Node::addOutputSocket(DataType datatype) void Node::addOutputSocket(DataType datatype, bNodeSocket *bSocket) { NodeOutput *socket = new NodeOutput(this, bSocket, datatype); - this->m_outputsockets.push_back(socket); + outputs.append(socket); } NodeOutput *Node::getOutputSocket(unsigned int index) const { - BLI_assert(index < this->m_outputsockets.size()); - return this->m_outputsockets[index]; + return outputs[index]; } NodeInput *Node::getInputSocket(unsigned int index) const { - BLI_assert(index < this->m_inputsockets.size()); - return this->m_inputsockets[index]; + return inputs[index]; } bNodeSocket *Node::getEditorInputSocket(int editorNodeInputSocketIndex) @@ -208,3 +206,5 @@ void NodeOutput::getEditorValueVector(float *value) RNA_pointer_create((ID *)getNode()->getbNodeTree(), &RNA_NodeSocket, getbNodeSocket(), &ptr); return RNA_float_get_array(&ptr, "default_value", value); } + +} // namespace blender::compositor diff --git a/source/blender/compositor/intern/COM_Node.h b/source/blender/compositor/intern/COM_Node.h index 99f1b58b5ef..9aca1a8ff44 100644 --- a/source/blender/compositor/intern/COM_Node.h +++ b/source/blender/compositor/intern/COM_Node.h @@ -18,10 +18,12 @@ #pragma once +#include "BLI_vector.hh" + #include "DNA_node_types.h" + #include <algorithm> #include <string> -#include <vector> /* common node includes * added here so node files don't have to include themselves @@ -29,7 +31,8 @@ #include "COM_CompositorContext.h" #include "COM_NodeConverter.h" -class Node; +namespace blender::compositor { + class NodeOperation; class NodeConverter; @@ -37,10 +40,6 @@ class NodeConverter; * My node documentation. */ class Node { - public: - typedef std::vector<NodeInput *> Inputs; - typedef std::vector<NodeOutput *> Outputs; - private: /** * \brief stores the reference to the SDNA bNode struct @@ -53,16 +52,6 @@ class Node { bNode *m_editorNode; /** - * \brief the list of actual inputsockets \see NodeInput - */ - Inputs m_inputsockets; - - /** - * \brief the list of actual outputsockets \see NodeOutput - */ - Outputs m_outputsockets; - - /** * \brief Is this node part of the active group */ bool m_inActiveGroup; @@ -74,20 +63,14 @@ class Node { protected: /** - * \brief get access to the vector of input sockets + * \brief the list of actual inputsockets \see NodeInput */ - const Inputs &getInputSockets() const - { - return this->m_inputsockets; - } + blender::Vector<NodeInput *> inputs; /** - * \brief get access to the vector of input sockets + * \brief the list of actual outputsockets \see NodeOutput */ - const Outputs &getOutputSockets() const - { - return this->m_outputsockets; - } + blender::Vector<NodeOutput *> outputs; public: Node(bNode *editorNode, bool create_sockets = true); @@ -130,19 +113,19 @@ class Node { } /** - * \brief Return the number of input sockets of this node. + * \brief get access to the vector of input sockets */ - unsigned int getNumberOfInputSockets() const + const blender::Vector<NodeInput *> &getInputSockets() const { - return this->m_inputsockets.size(); + return this->inputs; } /** - * \brief Return the number of output sockets of this node. + * \brief get access to the vector of input sockets */ - unsigned int getNumberOfOutputSockets() const + const blender::Vector<NodeOutput *> &getOutputSockets() const { - return this->m_outputsockets.size(); + return this->outputs; } /** @@ -150,17 +133,7 @@ class Node { * \param index: * the index of the needed outputsocket */ - NodeOutput *getOutputSocket(const unsigned int index) const; - - /** - * get the reference to the first outputsocket - * \param index: - * the index of the needed outputsocket - */ - inline NodeOutput *getOutputSocket() const - { - return getOutputSocket(0); - } + NodeOutput *getOutputSocket(const unsigned int index = 0) const; /** * get the reference to a certain inputsocket @@ -169,14 +142,6 @@ class Node { */ NodeInput *getInputSocket(const unsigned int index) const; - /** Check if this is an input node - * An input node is a node that only has output sockets and no input sockets - */ - bool isInputNode() const - { - return m_inputsockets.empty(); - } - /** * \brief Is this node in the active group (the group that is being edited) * \param isInActiveGroup: @@ -317,3 +282,5 @@ class NodeOutput { void getEditorValueColor(float *value); void getEditorValueVector(float *value); }; + +} // namespace blender::compositor diff --git a/source/blender/compositor/intern/COM_NodeConverter.cc b/source/blender/compositor/intern/COM_NodeConverter.cc index 2db31bd4133..49a2e7988c4 100644 --- a/source/blender/compositor/intern/COM_NodeConverter.cc +++ b/source/blender/compositor/intern/COM_NodeConverter.cc @@ -29,6 +29,8 @@ #include "COM_NodeConverter.h" /* own include */ +namespace blender::compositor { + NodeConverter::NodeConverter(NodeOperationBuilder *builder) : m_builder(builder) { } @@ -160,3 +162,5 @@ ViewerOperation *NodeConverter::active_viewer() const { return m_builder->active_viewer(); } + +} // namespace blender::compositor diff --git a/source/blender/compositor/intern/COM_NodeConverter.h b/source/blender/compositor/intern/COM_NodeConverter.h index e9b05184857..b3f03485249 100644 --- a/source/blender/compositor/intern/COM_NodeConverter.h +++ b/source/blender/compositor/intern/COM_NodeConverter.h @@ -22,6 +22,8 @@ # include "MEM_guardedalloc.h" #endif +namespace blender::compositor { + class NodeInput; class NodeOutput; @@ -120,3 +122,5 @@ class NodeConverter { MEM_CXX_CLASS_ALLOC_FUNCS("COM:NodeCompiler") #endif }; + +} // namespace blender::compositor diff --git a/source/blender/compositor/intern/COM_NodeGraph.cc b/source/blender/compositor/intern/COM_NodeGraph.cc index d8220099f1f..7e05bf637b7 100644 --- a/source/blender/compositor/intern/COM_NodeGraph.cc +++ b/source/blender/compositor/intern/COM_NodeGraph.cc @@ -33,6 +33,8 @@ #include "COM_NodeGraph.h" /* own include */ +namespace blender::compositor { + /******************* **** NodeGraph **** *******************/ @@ -43,9 +45,8 @@ NodeGraph::NodeGraph() NodeGraph::~NodeGraph() { - for (int index = 0; index < this->m_nodes.size(); index++) { - Node *node = this->m_nodes[index]; - delete node; + while (m_nodes.size()) { + delete m_nodes.pop_last(); } } @@ -83,7 +84,7 @@ void NodeGraph::add_node(Node *node, node->setInstanceKey(key); node->setIsInActiveGroup(is_active_group); - m_nodes.push_back(node); + m_nodes.append(node); DebugInfo::node_added(node); } @@ -153,27 +154,11 @@ void NodeGraph::add_bNode(const CompositorContext &context, } } -NodeGraph::NodeInputs NodeGraph::find_inputs(const NodeRange &node_range, bNodeSocket *b_socket) -{ - NodeInputs result; - for (NodeGraph::NodeIterator it = node_range.first; it != node_range.second; ++it) { - Node *node = *it; - for (int index = 0; index < node->getNumberOfInputSockets(); index++) { - NodeInput *input = node->getInputSocket(index); - if (input->getbNodeSocket() == b_socket) { - result.push_back(input); - } - } - } - return result; -} - NodeOutput *NodeGraph::find_output(const NodeRange &node_range, bNodeSocket *b_socket) { - for (NodeGraph::NodeIterator it = node_range.first; it != node_range.second; ++it) { + for (blender::Vector<Node *>::iterator it = node_range.first; it != node_range.second; ++it) { Node *node = *it; - for (int index = 0; index < node->getNumberOfOutputSockets(); index++) { - NodeOutput *output = node->getOutputSocket(index); + for (NodeOutput *output : node->getOutputSockets()) { if (output->getbNodeSocket() == b_socket) { return output; } @@ -202,12 +187,13 @@ void NodeGraph::add_bNodeLink(const NodeRange &node_range, bNodeLink *b_nodelink return; } - NodeInputs inputs = find_inputs(node_range, b_nodelink->tosock); - for (NodeInput *input : inputs) { - if (input->isLinked()) { - continue; + for (blender::Vector<Node *>::iterator it = node_range.first; it != node_range.second; ++it) { + Node *node = *it; + for (NodeInput *input : node->getInputSockets()) { + if (input->getbNodeSocket() == b_nodelink->tosock && !input->isLinked()) { + add_link(output, input); + } } - add_link(output, input); } } @@ -331,3 +317,5 @@ void NodeGraph::add_proxies_reroute(bNodeTree *b_ntree, b_node, (bNodeSocket *)b_node->inputs.first, (bNodeSocket *)b_node->outputs.first, false); add_node(proxy, b_ntree, key, is_active_group); } + +} // namespace blender::compositor diff --git a/source/blender/compositor/intern/COM_NodeGraph.h b/source/blender/compositor/intern/COM_NodeGraph.h index 990e3a30831..9347df5d9e2 100644 --- a/source/blender/compositor/intern/COM_NodeGraph.h +++ b/source/blender/compositor/intern/COM_NodeGraph.h @@ -22,7 +22,6 @@ #include <map> #include <set> -#include <vector> #include "DNA_node_types.h" @@ -30,6 +29,8 @@ # include "MEM_guardedalloc.h" #endif +namespace blender::compositor { + class CompositorContext; class Node; class NodeInput; @@ -50,18 +51,15 @@ class NodeGraph { } }; - typedef std::vector<Node *> Nodes; - typedef Nodes::iterator NodeIterator; - private: - Nodes m_nodes; + blender::Vector<Node *> m_nodes; blender::Vector<Link> m_links; public: NodeGraph(); ~NodeGraph(); - const Nodes &nodes() const + const blender::Vector<Node *> &nodes() const { return m_nodes; } @@ -73,8 +71,8 @@ class NodeGraph { void from_bNodeTree(const CompositorContext &context, bNodeTree *tree); protected: - typedef std::pair<NodeIterator, NodeIterator> NodeRange; - typedef std::vector<NodeInput *> NodeInputs; + typedef std::pair<blender::Vector<Node *>::iterator, blender::Vector<Node *>::iterator> + NodeRange; static bNodeSocket *find_b_node_input(bNode *b_node, const char *identifier); static bNodeSocket *find_b_node_output(bNode *b_node, const char *identifier); @@ -93,7 +91,6 @@ class NodeGraph { bNodeInstanceKey key, bool is_active_group); - NodeInputs find_inputs(const NodeRange &node_range, bNodeSocket *b_socket); NodeOutput *find_output(const NodeRange &node_range, bNodeSocket *b_socket); void add_bNodeLink(const NodeRange &node_range, bNodeLink *b_nodelink); @@ -124,3 +121,5 @@ class NodeGraph { MEM_CXX_CLASS_ALLOC_FUNCS("COM:NodeGraph") #endif }; + +} // namespace blender::compositor diff --git a/source/blender/compositor/intern/COM_NodeOperation.cc b/source/blender/compositor/intern/COM_NodeOperation.cc index 0cc642479ac..297ef100a1b 100644 --- a/source/blender/compositor/intern/COM_NodeOperation.cc +++ b/source/blender/compositor/intern/COM_NodeOperation.cc @@ -24,6 +24,8 @@ #include "COM_NodeOperation.h" /* own include */ +namespace blender::compositor { + /******************* **** NodeOperation **** *******************/ @@ -31,76 +33,52 @@ NodeOperation::NodeOperation() { this->m_resolutionInputSocketIndex = 0; - this->m_complex = false; this->m_width = 0; this->m_height = 0; - this->m_isResolutionSet = false; - this->m_openCL = false; this->m_btree = nullptr; } -NodeOperation::~NodeOperation() -{ - while (!this->m_outputs.empty()) { - delete (this->m_outputs.back()); - this->m_outputs.pop_back(); - } - while (!this->m_inputs.empty()) { - delete (this->m_inputs.back()); - this->m_inputs.pop_back(); - } -} - -NodeOperationOutput *NodeOperation::getOutputSocket(unsigned int index) const +NodeOperationOutput *NodeOperation::getOutputSocket(unsigned int index) { - BLI_assert(index < m_outputs.size()); - return m_outputs[index]; + return &m_outputs[index]; } -NodeOperationInput *NodeOperation::getInputSocket(unsigned int index) const +NodeOperationInput *NodeOperation::getInputSocket(unsigned int index) { - BLI_assert(index < m_inputs.size()); - return m_inputs[index]; + return &m_inputs[index]; } -void NodeOperation::addInputSocket(DataType datatype, InputResizeMode resize_mode) +void NodeOperation::addInputSocket(DataType datatype, ResizeMode resize_mode) { - NodeOperationInput *socket = new NodeOperationInput(this, datatype, resize_mode); - m_inputs.push_back(socket); + m_inputs.append(NodeOperationInput(this, datatype, resize_mode)); } void NodeOperation::addOutputSocket(DataType datatype) { - NodeOperationOutput *socket = new NodeOperationOutput(this, datatype); - m_outputs.push_back(socket); + m_outputs.append(NodeOperationOutput(this, datatype)); } void NodeOperation::determineResolution(unsigned int resolution[2], unsigned int preferredResolution[2]) { - unsigned int temp[2]; - unsigned int temp2[2]; + if (m_resolutionInputSocketIndex < m_inputs.size()) { + NodeOperationInput &input = m_inputs[m_resolutionInputSocketIndex]; + input.determineResolution(resolution, preferredResolution); + } + unsigned int temp2[2] = {resolution[0], resolution[1]}; + unsigned int temp[2]; for (unsigned int index = 0; index < m_inputs.size(); index++) { - NodeOperationInput *input = m_inputs[index]; - if (input->isConnected()) { - if (index == this->m_resolutionInputSocketIndex) { - input->determineResolution(resolution, preferredResolution); - temp2[0] = resolution[0]; - temp2[1] = resolution[1]; - break; - } + if (index == this->m_resolutionInputSocketIndex) { + continue; } - } - for (unsigned int index = 0; index < m_inputs.size(); index++) { - NodeOperationInput *input = m_inputs[index]; - if (input->isConnected()) { - if (index != this->m_resolutionInputSocketIndex) { - input->determineResolution(temp, temp2); - } + NodeOperationInput &input = m_inputs[index]; + if (input.isConnected()) { + input.determineResolution(temp, temp2); } } } + void NodeOperation::setResolutionInputSocketIndex(unsigned int index) { this->m_resolutionInputSocketIndex = index; @@ -149,20 +127,11 @@ NodeOperation *NodeOperation::getInputOperation(unsigned int inputSocketIndex) return nullptr; } -void NodeOperation::getConnectedInputSockets(Inputs *sockets) -{ - for (NodeOperationInput *input : m_inputs) { - if (input->isConnected()) { - sockets->push_back(input); - } - } -} - bool NodeOperation::determineDependingAreaOfInterest(rcti *input, ReadBufferOperation *readOperation, rcti *output) { - if (isInputOperation()) { + if (m_inputs.size() == 0) { BLI_rcti_init(output, input->xmin, input->xmax, input->ymin, input->ymax); return false; } @@ -195,9 +164,7 @@ bool NodeOperation::determineDependingAreaOfInterest(rcti *input, **** OpInput **** *****************/ -NodeOperationInput::NodeOperationInput(NodeOperation *op, - DataType datatype, - InputResizeMode resizeMode) +NodeOperationInput::NodeOperationInput(NodeOperation *op, DataType datatype, ResizeMode resizeMode) : m_operation(op), m_datatype(datatype), m_resizeMode(resizeMode), m_link(nullptr) { } @@ -232,7 +199,7 @@ void NodeOperationOutput::determineResolution(unsigned int resolution[2], unsigned int preferredResolution[2]) { NodeOperation &operation = getOperation(); - if (operation.isResolutionSet()) { + if (operation.get_flags().is_resolution_set) { resolution[0] = operation.getWidth(); resolution[1] = operation.getHeight(); } @@ -241,3 +208,5 @@ void NodeOperationOutput::determineResolution(unsigned int resolution[2], operation.setResolution(resolution); } } + +} // namespace blender::compositor diff --git a/source/blender/compositor/intern/COM_NodeOperation.h b/source/blender/compositor/intern/COM_NodeOperation.h index 7857837a95d..f300fb092a3 100644 --- a/source/blender/compositor/intern/COM_NodeOperation.h +++ b/source/blender/compositor/intern/COM_NodeOperation.h @@ -28,75 +28,235 @@ #include "COM_MemoryBuffer.h" #include "COM_MemoryProxy.h" +#include "COM_MetaData.h" #include "COM_Node.h" -#include "COM_SocketReader.h" #include "clew.h" +namespace blender::compositor { + class OpenCLDevice; class ReadBufferOperation; class WriteBufferOperation; -class NodeOperationInput; -class NodeOperationOutput; +class NodeOperation; +typedef NodeOperation SocketReader; /** * \brief Resize modes of inputsockets * How are the input and working resolutions matched * \ingroup Model */ -typedef enum InputResizeMode { +enum class ResizeMode { /** \brief Center the input image to the center of the working area of the node, no resizing * occurs */ - COM_SC_CENTER = NS_CR_CENTER, + Center = NS_CR_CENTER, /** \brief The bottom left of the input image is the bottom left of the working area of the node, * no resizing occurs */ - COM_SC_NO_RESIZE = NS_CR_NONE, + None = NS_CR_NONE, /** \brief Fit the width of the input image to the width of the working area of the node */ - COM_SC_FIT_WIDTH = NS_CR_FIT_WIDTH, + FitWidth = NS_CR_FIT_WIDTH, /** \brief Fit the height of the input image to the height of the working area of the node */ - COM_SC_FIT_HEIGHT = NS_CR_FIT_HEIGHT, + FitHeight = NS_CR_FIT_HEIGHT, /** \brief Fit the width or the height of the input image to the width or height of the working * area of the node, image will be larger than the working area */ - COM_SC_FIT = NS_CR_FIT, + FitAny = NS_CR_FIT, /** \brief Fit the width and the height of the input image to the width and height of the working * area of the node, image will be equally larger than the working area */ - COM_SC_STRETCH = NS_CR_STRETCH, -} InputResizeMode; + Stretch = NS_CR_STRETCH, +}; + +enum class PixelSampler { + Nearest = 0, + Bilinear = 1, + Bicubic = 2, +}; + +class NodeOperationInput { + private: + NodeOperation *m_operation; + + /** Datatype of this socket. Is used for automatically data transformation. + * \section data-conversion + */ + DataType m_datatype; + + /** Resize mode of this socket */ + ResizeMode m_resizeMode; + + /** Connected output */ + NodeOperationOutput *m_link; -/** - * \brief NodeOperation contains calculation logic - * - * Subclasses needs to implement the execution method (defined in SocketReader) to implement logic. - * \ingroup Model - */ -class NodeOperation : public SocketReader { public: - typedef std::vector<NodeOperationInput *> Inputs; - typedef std::vector<NodeOperationOutput *> Outputs; + NodeOperationInput(NodeOperation *op, + DataType datatype, + ResizeMode resizeMode = ResizeMode::Center); + NodeOperation &getOperation() const + { + return *m_operation; + } + DataType getDataType() const + { + return m_datatype; + } + + void setLink(NodeOperationOutput *link) + { + m_link = link; + } + NodeOperationOutput *getLink() const + { + return m_link; + } + bool isConnected() const + { + return m_link; + } + + void setResizeMode(ResizeMode resizeMode) + { + this->m_resizeMode = resizeMode; + } + ResizeMode getResizeMode() const + { + return this->m_resizeMode; + } + + SocketReader *getReader(); + + void determineResolution(unsigned int resolution[2], unsigned int preferredResolution[2]); + +#ifdef WITH_CXX_GUARDEDALLOC + MEM_CXX_CLASS_ALLOC_FUNCS("COM:NodeOperation") +#endif +}; + +class NodeOperationOutput { private: - Inputs m_inputs; - Outputs m_outputs; + NodeOperation *m_operation; + + /** Datatype of this socket. Is used for automatically data transformation. + * \section data-conversion + */ + DataType m_datatype; + + public: + NodeOperationOutput(NodeOperation *op, DataType datatype); + + NodeOperation &getOperation() const + { + return *m_operation; + } + DataType getDataType() const + { + return m_datatype; + } /** - * \brief the index of the input socket that will be used to determine the resolution + * \brief determine the resolution of this data going through this socket + * \param resolution: the result of this operation + * \param preferredResolution: the preferable resolution as no resolution could be determined */ - unsigned int m_resolutionInputSocketIndex; + void determineResolution(unsigned int resolution[2], unsigned int preferredResolution[2]); + +#ifdef WITH_CXX_GUARDEDALLOC + MEM_CXX_CLASS_ALLOC_FUNCS("COM:NodeOperation") +#endif +}; +struct NodeOperationFlags { /** - * \brief is this operation a complex one. + * Is this an complex operation. + * + * The input and output buffers of Complex operations are stored in buffers. It allows + * sequential and read/write. * * Complex operations are typically doing many reads to calculate the output of a single pixel. * Mostly Filter types (Blurs, Convolution, Defocus etc) need this to be set to true. */ - bool m_complex; + bool complex : 1; + + /** + * Does this operation support OpenCL. + */ + bool open_cl : 1; + + bool single_threaded : 1; + + /** + * Does the operation needs a viewer border. + * Basically, setting border need to happen for only operations + * which operates in render resolution buffers (like compositor + * output nodes). + * + * In this cases adding border will lead to mapping coordinates + * from output buffer space to input buffer spaces when executing + * operation. + * + * But nodes like viewer and file output just shall display or + * safe the same exact buffer which goes to their input, no need + * in any kind of coordinates mapping. + */ + bool use_render_border : 1; + bool use_viewer_border : 1; + + /** + * Is the resolution of the operation set. + */ + bool is_resolution_set : 1; + + /** + * Is this a set operation (value, color, vector). + */ + bool is_set_operation : 1; + bool is_write_buffer_operation : 1; + bool is_read_buffer_operation : 1; + bool is_proxy_operation : 1; + bool is_viewer_operation : 1; + bool is_preview_operation : 1; + + /** + * When set additional data conversion operations are added to + * convert the data. SocketProxyOperation don't always need to do data conversions. + * + * By default data conversions are enabled. + */ + bool use_datatype_conversion : 1; + + NodeOperationFlags() + { + complex = false; + single_threaded = false; + open_cl = false; + use_render_border = false; + use_viewer_border = false; + is_resolution_set = false; + is_set_operation = false; + is_read_buffer_operation = false; + is_write_buffer_operation = false; + is_proxy_operation = false; + is_viewer_operation = false; + is_preview_operation = false; + use_datatype_conversion = true; + } +}; + +/** + * \brief NodeOperation contains calculation logic + * + * Subclasses needs to implement the execution method (defined in SocketReader) to implement logic. + * \ingroup Model + */ +class NodeOperation { + private: + blender::Vector<NodeOperationInput> m_inputs; + blender::Vector<NodeOperationOutput> m_outputs; /** - * \brief can this operation be scheduled on an OpenCL device. - * \note Only applicable if complex is True + * \brief the index of the input socket that will be used to determine the resolution */ - bool m_openCL; + unsigned int m_resolutionInputSocketIndex; /** * \brief mutex reference for very special node initializations @@ -114,13 +274,31 @@ class NodeOperation : public SocketReader { */ const bNodeTree *m_btree; + protected: /** - * \brief set to truth when resolution for this operation is set + * Width of the output of this operation. */ - bool m_isResolutionSet; + unsigned int m_width; + + /** + * Height of the output of this operation. + */ + unsigned int m_height; + + /** + * Flags how to evaluate this operation. + */ + NodeOperationFlags flags; public: - virtual ~NodeOperation(); + virtual ~NodeOperation() + { + } + + const NodeOperationFlags get_flags() const + { + return flags; + } unsigned int getNumberOfInputSockets() const { @@ -130,20 +308,8 @@ class NodeOperation : public SocketReader { { return m_outputs.size(); } - NodeOperationOutput *getOutputSocket(unsigned int index) const; - NodeOperationOutput *getOutputSocket() const - { - return getOutputSocket(0); - } - NodeOperationInput *getInputSocket(unsigned int index) const; - - /** Check if this is an input operation - * An input operation is an operation that only has output sockets and no input sockets - */ - bool isInputOperation() const - { - return m_inputs.empty(); - } + NodeOperationOutput *getOutputSocket(unsigned int index = 0); + NodeOperationInput *getInputSocket(unsigned int index); /** * \brief determine the resolution of this node @@ -155,11 +321,11 @@ class NodeOperation : public SocketReader { unsigned int preferredResolution[2]); /** - * \brief isOutputOperation determines whether this operation is an output of the ExecutionSystem - * during rendering or editing. + * \brief isOutputOperation determines whether this operation is an output of the + * ExecutionSystem during rendering or editing. * - * Default behavior if not overridden, this operation will not be evaluated as being an output of - * the ExecutionSystem. + * Default behavior if not overridden, this operation will not be evaluated as being an output + * of the ExecutionSystem. * * \see ExecutionSystem * \ingroup check @@ -174,11 +340,6 @@ class NodeOperation : public SocketReader { return false; } - virtual int isSingleThreaded() - { - return false; - } - void setbNodeTree(const bNodeTree *tree) { this->m_btree = tree; @@ -241,62 +402,19 @@ class NodeOperation : public SocketReader { } virtual void deinitExecution(); - bool isResolutionSet() - { - return this->m_isResolutionSet; - } - /** * \brief set the resolution * \param resolution: the resolution to set */ void setResolution(unsigned int resolution[2]) { - if (!isResolutionSet()) { + if (!this->flags.is_resolution_set) { this->m_width = resolution[0]; this->m_height = resolution[1]; - this->m_isResolutionSet = true; + this->flags.is_resolution_set = true; } } - void getConnectedInputSockets(Inputs *sockets); - - /** - * \brief is this operation complex - * - * Complex operations are typically doing many reads to calculate the output of a single pixel. - * Mostly Filter types (Blurs, Convolution, Defocus etc) need this to be set to true. - */ - bool isComplex() const - { - return this->m_complex; - } - - virtual bool isSetOperation() const - { - return false; - } - - /** - * \brief is this operation of type ReadBufferOperation - * \return [true:false] - * \see ReadBufferOperation - */ - virtual bool isReadBufferOperation() const - { - return false; - } - - /** - * \brief is this operation of type WriteBufferOperation - * \return [true:false] - * \see WriteBufferOperation - */ - virtual bool isWriteBufferOperation() const - { - return false; - } - /** * \brief is this operation the active viewer output * user can select an ViewerNode to be active @@ -314,8 +432,8 @@ class NodeOperation : public SocketReader { rcti *output); /** - * \brief set the index of the input socket that will determine the resolution of this operation - * \param index: the index to set + * \brief set the index of the input socket that will determine the resolution of this + * operation \param index: the index to set */ void setResolutionInputSocketIndex(unsigned int index); @@ -329,65 +447,81 @@ class NodeOperation : public SocketReader { return CompositorPriority::Low; } - /** - * \brief can this NodeOperation be scheduled on an OpenCLDevice - * \see WorkScheduler.schedule - * \see ExecutionGroup.addOperation - */ - bool isOpenCL() const + inline bool isBraked() const { - return this->m_openCL; + return this->m_btree->test_break(this->m_btree->tbh); } - virtual bool isViewerOperation() const + inline void updateDraw() { - return false; + if (this->m_btree->update_draw) { + this->m_btree->update_draw(this->m_btree->udh); + } } - virtual bool isPreviewOperation() const + + unsigned int getWidth() const { - return false; + return m_width; } - virtual bool isFileOutputOperation() const + + unsigned int getHeight() const { - return false; + return m_height; } - virtual bool isProxyOperation() const + + inline void readSampled(float result[4], float x, float y, PixelSampler sampler) { - return false; + executePixelSampled(result, x, y, sampler); } - virtual bool useDatatypeConversion() const + inline void readFiltered(float result[4], float x, float y, float dx[2], float dy[2]) { - return true; + executePixelFiltered(result, x, y, dx, dy); } - inline bool isBraked() const + inline void read(float result[4], int x, int y, void *chunkData) { - return this->m_btree->test_break(this->m_btree->tbh); + executePixel(result, x, y, chunkData); } - inline void updateDraw() + virtual void *initializeTileData(rcti * /*rect*/) + { + return 0; + } + + virtual void deinitializeTileData(rcti * /*rect*/, void * /*data*/) { - if (this->m_btree->update_draw) { - this->m_btree->update_draw(this->m_btree->udh); - } + } + + virtual MemoryBuffer *getInputMemoryBuffer(MemoryBuffer ** /*memoryBuffers*/) + { + return 0; + } + + /** + * Return the meta data associated with this branch. + * + * The return parameter holds an instance or is an nullptr. */ + virtual std::unique_ptr<MetaData> getMetaData() + { + return std::unique_ptr<MetaData>(); } protected: NodeOperation(); - void addInputSocket(DataType datatype, InputResizeMode resize_mode = COM_SC_CENTER); + void addInputSocket(DataType datatype, ResizeMode resize_mode = ResizeMode::Center); void addOutputSocket(DataType datatype); void setWidth(unsigned int width) { this->m_width = width; - this->m_isResolutionSet = true; + this->flags.is_resolution_set = true; } void setHeight(unsigned int height) { this->m_height = height; - this->m_isResolutionSet = true; + this->flags.is_resolution_set = true; } SocketReader *getInputSocketReader(unsigned int inputSocketindex); NodeOperation *getInputOperation(unsigned int inputSocketindex); @@ -405,114 +539,59 @@ class NodeOperation : public SocketReader { */ void setComplex(bool complex) { - this->m_complex = complex; + this->flags.complex = complex; } /** - * \brief set if this NodeOperation can be scheduled on a OpenCLDevice + * \brief calculate a single pixel + * \note this method is called for non-complex + * \param result: is a float[4] array to store the result + * \param x: the x-coordinate of the pixel to calculate in image space + * \param y: the y-coordinate of the pixel to calculate in image space + * \param inputBuffers: chunks that can be read by their ReadBufferOperation. */ - void setOpenCL(bool openCL) + virtual void executePixelSampled(float /*output*/[4], + float /*x*/, + float /*y*/, + PixelSampler /*sampler*/) { - this->m_openCL = openCL; } - /* allow the DebugInfo class to look at internals */ - friend class DebugInfo; - -#ifdef WITH_CXX_GUARDEDALLOC - MEM_CXX_CLASS_ALLOC_FUNCS("COM:NodeOperation") -#endif -}; - -class NodeOperationInput { - private: - NodeOperation *m_operation; - - /** Datatype of this socket. Is used for automatically data transformation. - * \section data-conversion + /** + * \brief calculate a single pixel + * \note this method is called for complex + * \param result: is a float[4] array to store the result + * \param x: the x-coordinate of the pixel to calculate in image space + * \param y: the y-coordinate of the pixel to calculate in image space + * \param inputBuffers: chunks that can be read by their ReadBufferOperation. + * \param chunkData: chunk specific data a during execution time. */ - DataType m_datatype; - - /** Resize mode of this socket */ - InputResizeMode m_resizeMode; - - /** Connected output */ - NodeOperationOutput *m_link; - - public: - NodeOperationInput(NodeOperation *op, - DataType datatype, - InputResizeMode resizeMode = COM_SC_CENTER); - - NodeOperation &getOperation() const - { - return *m_operation; - } - DataType getDataType() const - { - return m_datatype; - } - - void setLink(NodeOperationOutput *link) - { - m_link = link; - } - NodeOperationOutput *getLink() const - { - return m_link; - } - bool isConnected() const - { - return m_link; - } - - void setResizeMode(InputResizeMode resizeMode) - { - this->m_resizeMode = resizeMode; - } - InputResizeMode getResizeMode() const + virtual void executePixel(float output[4], int x, int y, void * /*chunkData*/) { - return this->m_resizeMode; + executePixelSampled(output, x, y, PixelSampler::Nearest); } - SocketReader *getReader(); - - void determineResolution(unsigned int resolution[2], unsigned int preferredResolution[2]); - -#ifdef WITH_CXX_GUARDEDALLOC - MEM_CXX_CLASS_ALLOC_FUNCS("COM:NodeOperation") -#endif -}; - -class NodeOperationOutput { - private: - NodeOperation *m_operation; - - /** Datatype of this socket. Is used for automatically data transformation. - * \section data-conversion + /** + * \brief calculate a single pixel using an EWA filter + * \note this method is called for complex + * \param result: is a float[4] array to store the result + * \param x: the x-coordinate of the pixel to calculate in image space + * \param y: the y-coordinate of the pixel to calculate in image space + * \param dx: + * \param dy: + * \param inputBuffers: chunks that can be read by their ReadBufferOperation. */ - DataType m_datatype; - - public: - NodeOperationOutput(NodeOperation *op, DataType datatype); - - NodeOperation &getOperation() const + virtual void executePixelFiltered( + float /*output*/[4], float /*x*/, float /*y*/, float /*dx*/[2], float /*dy*/[2]) { - return *m_operation; - } - DataType getDataType() const - { - return m_datatype; } - /** - * \brief determine the resolution of this data going through this socket - * \param resolution: the result of this operation - * \param preferredResolution: the preferable resolution as no resolution could be determined - */ - void determineResolution(unsigned int resolution[2], unsigned int preferredResolution[2]); + /* allow the DebugInfo class to look at internals */ + friend class DebugInfo; #ifdef WITH_CXX_GUARDEDALLOC MEM_CXX_CLASS_ALLOC_FUNCS("COM:NodeOperation") #endif }; + +} // namespace blender::compositor diff --git a/source/blender/compositor/intern/COM_NodeOperationBuilder.cc b/source/blender/compositor/intern/COM_NodeOperationBuilder.cc index 1c741283c7b..fdd48da3fb4 100644 --- a/source/blender/compositor/intern/COM_NodeOperationBuilder.cc +++ b/source/blender/compositor/intern/COM_NodeOperationBuilder.cc @@ -38,6 +38,8 @@ #include "COM_NodeOperationBuilder.h" /* own include */ +namespace blender::compositor { + NodeOperationBuilder::NodeOperationBuilder(const CompositorContext *context, bNodeTree *b_nodetree) : m_context(context), m_current_node(nullptr), m_active_viewer(nullptr) { @@ -53,9 +55,7 @@ void NodeOperationBuilder::convertToOperations(ExecutionSystem *system) /* interface handle for nodes */ NodeConverter converter(this); - for (int index = 0; index < m_graph.nodes().size(); index++) { - Node *node = (Node *)m_graph.nodes()[index]; - + for (Node *node : m_graph.nodes()) { m_current_node = node; DebugInfo::node_to_operations(node); @@ -256,7 +256,8 @@ void NodeOperationBuilder::add_datatype_conversions() /* proxy operations can skip data type conversion */ NodeOperation *from_op = &link.from()->getOperation(); NodeOperation *to_op = &link.to()->getOperation(); - if (!(from_op->useDatatypeConversion() || to_op->useDatatypeConversion())) { + if (!(from_op->get_flags().use_datatype_conversion || + to_op->get_flags().use_datatype_conversion)) { continue; } @@ -352,8 +353,8 @@ void NodeOperationBuilder::resolve_proxies() blender::Vector<Link> proxy_links; for (const Link &link : m_links) { /* don't replace links from proxy to proxy, since we may need them for replacing others! */ - if (link.from()->getOperation().isProxyOperation() && - !link.to()->getOperation().isProxyOperation()) { + if (link.from()->getOperation().get_flags().is_proxy_operation && + !link.to()->getOperation().get_flags().is_proxy_operation) { proxy_links.append(link); } } @@ -364,7 +365,7 @@ void NodeOperationBuilder::resolve_proxies() do { /* walk upstream bypassing the proxy operation */ from = from->getOperation().getInputSocket(0)->getLink(); - } while (from && from->getOperation().isProxyOperation()); + } while (from && from->getOperation().get_flags().is_proxy_operation); removeInputLink(to); /* we may not have a final proxy input link, @@ -380,7 +381,7 @@ void NodeOperationBuilder::determineResolutions() { /* determine all resolutions of the operations (Width/Height) */ for (NodeOperation *op : m_operations) { - if (op->isOutputOperation(m_context->isRendering()) && !op->isPreviewOperation()) { + if (op->isOutputOperation(m_context->isRendering()) && !op->get_flags().is_preview_operation) { unsigned int resolution[2] = {0, 0}; unsigned int preferredResolution[2] = {0, 0}; op->determineResolution(resolution, preferredResolution); @@ -389,7 +390,7 @@ void NodeOperationBuilder::determineResolutions() } for (NodeOperation *op : m_operations) { - if (op->isOutputOperation(m_context->isRendering()) && op->isPreviewOperation()) { + if (op->isOutputOperation(m_context->isRendering()) && op->get_flags().is_preview_operation) { unsigned int resolution[2] = {0, 0}; unsigned int preferredResolution[2] = {0, 0}; op->determineResolution(resolution, preferredResolution); @@ -401,7 +402,7 @@ void NodeOperationBuilder::determineResolutions() { blender::Vector<Link> convert_links; for (const Link &link : m_links) { - if (link.to()->getResizeMode() != COM_SC_NO_RESIZE) { + if (link.to()->getResizeMode() != ResizeMode::None) { NodeOperation &from_op = link.from()->getOperation(); NodeOperation &to_op = link.to()->getOperation(); if (from_op.getWidth() != to_op.getWidth() || from_op.getHeight() != to_op.getHeight()) { @@ -433,7 +434,7 @@ WriteBufferOperation *NodeOperationBuilder::find_attached_write_buffer_operation for (const Link &link : m_links) { if (link.from() == output) { NodeOperation &op = link.to()->getOperation(); - if (op.isWriteBufferOperation()) { + if (op.get_flags().is_write_buffer_operation) { return (WriteBufferOperation *)(&op); } } @@ -449,7 +450,7 @@ void NodeOperationBuilder::add_input_buffers(NodeOperation * /*operation*/, } NodeOperationOutput *output = input->getLink(); - if (output->getOperation().isReadBufferOperation()) { + if (output->getOperation().get_flags().is_read_buffer_operation) { /* input is already buffered, no need to add another */ return; } @@ -491,7 +492,7 @@ void NodeOperationBuilder::add_output_buffers(NodeOperation *operation, WriteBufferOperation *writeOperation = nullptr; for (NodeOperationInput *target : targets) { /* try to find existing write buffer operation */ - if (target->getOperation().isWriteBufferOperation()) { + if (target->getOperation().get_flags().is_write_buffer_operation) { BLI_assert(writeOperation == nullptr); /* there should only be one write op connected */ writeOperation = (WriteBufferOperation *)(&target->getOperation()); } @@ -536,7 +537,7 @@ void NodeOperationBuilder::add_complex_operation_buffers() */ blender::Vector<NodeOperation *> complex_ops; for (NodeOperation *operation : m_operations) { - if (operation->isComplex()) { + if (operation->get_flags().complex) { complex_ops.append(operation); } } @@ -571,7 +572,7 @@ static void find_reachable_operations_recursive(Tags &reachable, NodeOperation * } /* associated write-buffer operations are executed as well */ - if (op->isReadBufferOperation()) { + if (op->get_flags().is_read_buffer_operation) { ReadBufferOperation *read_op = (ReadBufferOperation *)op; MemoryProxy *memproxy = read_op->getMemoryProxy(); find_reachable_operations_recursive(reachable, memproxy->getWriteBufferOperation()); @@ -675,7 +676,7 @@ void NodeOperationBuilder::group_operations() } /* add new groups for associated memory proxies where needed */ - if (op->isReadBufferOperation()) { + if (op->get_flags().is_read_buffer_operation) { ReadBufferOperation *read_op = (ReadBufferOperation *)op; MemoryProxy *memproxy = read_op->getMemoryProxy(); @@ -686,3 +687,5 @@ void NodeOperationBuilder::group_operations() } } } + +} // namespace blender::compositor diff --git a/source/blender/compositor/intern/COM_NodeOperationBuilder.h b/source/blender/compositor/intern/COM_NodeOperationBuilder.h index 8f55574fa88..8e5ec58c3be 100644 --- a/source/blender/compositor/intern/COM_NodeOperationBuilder.h +++ b/source/blender/compositor/intern/COM_NodeOperationBuilder.h @@ -24,6 +24,8 @@ #include "COM_NodeGraph.h" +namespace blender::compositor { + class CompositorContext; class Node; @@ -157,3 +159,5 @@ class NodeOperationBuilder { MEM_CXX_CLASS_ALLOC_FUNCS("COM:NodeCompilerImpl") #endif }; + +} // namespace blender::compositor diff --git a/source/blender/compositor/intern/COM_OpenCLDevice.cc b/source/blender/compositor/intern/COM_OpenCLDevice.cc index 9a6012e5c68..b96dbe91434 100644 --- a/source/blender/compositor/intern/COM_OpenCLDevice.cc +++ b/source/blender/compositor/intern/COM_OpenCLDevice.cc @@ -19,6 +19,8 @@ #include "COM_OpenCLDevice.h" #include "COM_WorkScheduler.h" +namespace blender::compositor { + enum COM_VendorID { NVIDIA = 0x10DE, AMD = 0x1002 }; const cl_image_format IMAGE_FORMAT_COLOR = { CL_RGBA, @@ -43,34 +45,28 @@ OpenCLDevice::OpenCLDevice(cl_context context, this->m_program = program; this->m_queue = nullptr; this->m_vendorID = vendorId; -} -bool OpenCLDevice::initialize() -{ cl_int error; this->m_queue = clCreateCommandQueue(this->m_context, this->m_device, 0, &error); - return false; } -void OpenCLDevice::deinitialize() +OpenCLDevice::~OpenCLDevice() { if (this->m_queue) { clReleaseCommandQueue(this->m_queue); } } -void OpenCLDevice::execute(WorkPackage *work) +void OpenCLDevice::execute(WorkPackage *work_package) { - const unsigned int chunkNumber = work->chunk_number; - ExecutionGroup *executionGroup = work->execution_group; - rcti rect; + const unsigned int chunkNumber = work_package->chunk_number; + ExecutionGroup *executionGroup = work_package->execution_group; - executionGroup->determineChunkRect(&rect, chunkNumber); MemoryBuffer **inputBuffers = executionGroup->getInputBuffersOpenCL(chunkNumber); - MemoryBuffer *outputBuffer = executionGroup->allocateOutputBuffer(rect); + MemoryBuffer *outputBuffer = executionGroup->allocateOutputBuffer(work_package->rect); executionGroup->getOutputOperation()->executeOpenCLRegion( - this, &rect, chunkNumber, inputBuffers, outputBuffer); + this, &work_package->rect, chunkNumber, inputBuffers, outputBuffer); delete outputBuffer; @@ -274,3 +270,5 @@ cl_kernel OpenCLDevice::COM_clCreateKernel(const char *kernelname, } return kernel; } + +} // namespace blender::compositor diff --git a/source/blender/compositor/intern/COM_OpenCLDevice.h b/source/blender/compositor/intern/COM_OpenCLDevice.h index e4fd397b4e8..355451cef68 100644 --- a/source/blender/compositor/intern/COM_OpenCLDevice.h +++ b/source/blender/compositor/intern/COM_OpenCLDevice.h @@ -25,6 +25,8 @@ class OpenCLDevice; #include "COM_WorkScheduler.h" #include "clew.h" +namespace blender::compositor { + /** * \brief device representing an GPU OpenCL device. * an instance of this class represents a single cl_device @@ -65,26 +67,13 @@ class OpenCLDevice : public Device { * \param vendorID: */ OpenCLDevice(cl_context context, cl_device_id device, cl_program program, cl_int vendorId); - - /** - * \brief initialize the device - * During initialization the OpenCL cl_command_queue is created - * the command queue is stored in the field queue. - * \see queue - */ - bool initialize(); - - /** - * \brief de-initialize the device - * During de-initialization the command queue is cleared - */ - void deinitialize(); + ~OpenCLDevice(); /** * \brief execute a WorkPackage * \param work: the WorkPackage to execute */ - void execute(WorkPackage *work); + void execute(WorkPackage *work) override; /** * \brief determine an image format @@ -130,3 +119,5 @@ class OpenCLDevice : public Device { NodeOperation *operation); cl_kernel COM_clCreateKernel(const char *kernelname, std::list<cl_kernel> *clKernelsToCleanUp); }; + +} // namespace blender::compositor diff --git a/source/blender/compositor/intern/COM_SingleThreadedOperation.cc b/source/blender/compositor/intern/COM_SingleThreadedOperation.cc index 5febf3802de..01be6e1afed 100644 --- a/source/blender/compositor/intern/COM_SingleThreadedOperation.cc +++ b/source/blender/compositor/intern/COM_SingleThreadedOperation.cc @@ -18,10 +18,13 @@ #include "COM_SingleThreadedOperation.h" +namespace blender::compositor { + SingleThreadedOperation::SingleThreadedOperation() { this->m_cachedInstance = nullptr; - setComplex(true); + flags.complex = true; + flags.single_threaded = true; } void SingleThreadedOperation::initExecution() @@ -56,3 +59,5 @@ void *SingleThreadedOperation::initializeTileData(rcti *rect) unlockMutex(); return this->m_cachedInstance; } + +} // namespace blender::compositor diff --git a/source/blender/compositor/intern/COM_SingleThreadedOperation.h b/source/blender/compositor/intern/COM_SingleThreadedOperation.h index 32f4515cf2a..9945f938ff9 100644 --- a/source/blender/compositor/intern/COM_SingleThreadedOperation.h +++ b/source/blender/compositor/intern/COM_SingleThreadedOperation.h @@ -20,6 +20,8 @@ #include "COM_NodeOperation.h" +namespace blender::compositor { + class SingleThreadedOperation : public NodeOperation { private: MemoryBuffer *m_cachedInstance; @@ -36,24 +38,21 @@ class SingleThreadedOperation : public NodeOperation { /** * The inner loop of this operation. */ - void executePixel(float output[4], int x, int y, void *data); + void executePixel(float output[4], int x, int y, void *data) override; /** * Initialize the execution */ - void initExecution(); + void initExecution() override; /** * Deinitialize the execution */ - void deinitExecution(); + void deinitExecution() override; - void *initializeTileData(rcti *rect); + void *initializeTileData(rcti *rect) override; virtual MemoryBuffer *createMemoryBuffer(rcti *rect) = 0; - - int isSingleThreaded() - { - return true; - } }; + +} // namespace blender::compositor diff --git a/source/blender/compositor/intern/COM_SocketReader.h b/source/blender/compositor/intern/COM_SocketReader.h deleted file mode 100644 index 7c4132efe60..00000000000 --- a/source/blender/compositor/intern/COM_SocketReader.h +++ /dev/null @@ -1,153 +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. - * - * Copyright 2011, Blender Foundation. - */ - -#pragma once - -#include "BLI_rect.h" -#include "COM_MetaData.h" -#include "COM_defines.h" - -#include <memory> -#include <optional> - -#ifdef WITH_CXX_GUARDEDALLOC -# include "MEM_guardedalloc.h" -#endif - -typedef enum PixelSampler { - COM_PS_NEAREST = 0, - COM_PS_BILINEAR = 1, - COM_PS_BICUBIC = 2, -} PixelSampler; - -class MemoryBuffer; - -/** - * \brief Helper class for reading socket data. - * Only use this class for dispatching (un-ary and n-ary) executions. - * \ingroup Execution - */ -class SocketReader { - private: - protected: - /** - * \brief Holds the width of the output of this operation. - */ - unsigned int m_width; - - /** - * \brief Holds the height of the output of this operation. - */ - unsigned int m_height; - - /** - * \brief calculate a single pixel - * \note this method is called for non-complex - * \param result: is a float[4] array to store the result - * \param x: the x-coordinate of the pixel to calculate in image space - * \param y: the y-coordinate of the pixel to calculate in image space - * \param inputBuffers: chunks that can be read by their ReadBufferOperation. - */ - virtual void executePixelSampled(float /*output*/[4], - float /*x*/, - float /*y*/, - PixelSampler /*sampler*/) - { - } - - /** - * \brief calculate a single pixel - * \note this method is called for complex - * \param result: is a float[4] array to store the result - * \param x: the x-coordinate of the pixel to calculate in image space - * \param y: the y-coordinate of the pixel to calculate in image space - * \param inputBuffers: chunks that can be read by their ReadBufferOperation. - * \param chunkData: chunk specific data a during execution time. - */ - virtual void executePixel(float output[4], int x, int y, void * /*chunkData*/) - { - executePixelSampled(output, x, y, COM_PS_NEAREST); - } - - /** - * \brief calculate a single pixel using an EWA filter - * \note this method is called for complex - * \param result: is a float[4] array to store the result - * \param x: the x-coordinate of the pixel to calculate in image space - * \param y: the y-coordinate of the pixel to calculate in image space - * \param dx: - * \param dy: - * \param inputBuffers: chunks that can be read by their ReadBufferOperation. - */ - virtual void executePixelFiltered( - float /*output*/[4], float /*x*/, float /*y*/, float /*dx*/[2], float /*dy*/[2]) - { - } - - public: - inline void readSampled(float result[4], float x, float y, PixelSampler sampler) - { - executePixelSampled(result, x, y, sampler); - } - inline void read(float result[4], int x, int y, void *chunkData) - { - executePixel(result, x, y, chunkData); - } - inline void readFiltered(float result[4], float x, float y, float dx[2], float dy[2]) - { - executePixelFiltered(result, x, y, dx, dy); - } - - virtual void *initializeTileData(rcti * /*rect*/) - { - return 0; - } - virtual void deinitializeTileData(rcti * /*rect*/, void * /*data*/) - { - } - - virtual ~SocketReader() - { - } - - virtual MemoryBuffer *getInputMemoryBuffer(MemoryBuffer ** /*memoryBuffers*/) - { - return 0; - } - - inline unsigned int getWidth() const - { - return this->m_width; - } - inline unsigned int getHeight() const - { - return this->m_height; - } - - /* Return the meta data associated with this branch. - * - * The return parameter holds an instance or is an nullptr. */ - virtual std::unique_ptr<MetaData> getMetaData() const - { - return std::unique_ptr<MetaData>(); - } - -#ifdef WITH_CXX_GUARDEDALLOC - MEM_CXX_CLASS_ALLOC_FUNCS("COM:SocketReader") -#endif -}; diff --git a/source/blender/compositor/intern/COM_WorkPackage.cc b/source/blender/compositor/intern/COM_WorkPackage.cc index 60684f2c45c..c0bc274da8f 100644 --- a/source/blender/compositor/intern/COM_WorkPackage.cc +++ b/source/blender/compositor/intern/COM_WorkPackage.cc @@ -18,8 +18,6 @@ #include "COM_WorkPackage.h" -WorkPackage::WorkPackage(ExecutionGroup *execution_group, unsigned int chunk_number) -{ - this->execution_group = execution_group; - this->chunk_number = chunk_number; -} +namespace blender::compositor { + +} // namespace blender::compositor diff --git a/source/blender/compositor/intern/COM_WorkPackage.h b/source/blender/compositor/intern/COM_WorkPackage.h index db5eb3d3072..4541a778711 100644 --- a/source/blender/compositor/intern/COM_WorkPackage.h +++ b/source/blender/compositor/intern/COM_WorkPackage.h @@ -18,14 +18,21 @@ #pragma once +#include "COM_defines.h" + +#include "BLI_rect.h" + +namespace blender::compositor { +// Forward Declarations. class ExecutionGroup; -#include "COM_ExecutionGroup.h" /** * \brief contains data about work that can be scheduled * \see WorkScheduler */ struct WorkPackage { + eChunkExecutionState state = eChunkExecutionState::NotScheduled; + /** * \brief executionGroup with the operations-setup to be evaluated */ @@ -37,13 +44,13 @@ struct WorkPackage { unsigned int chunk_number; /** - * constructor - * \param group: the ExecutionGroup - * \param chunk_number: the number of the chunk + * Area of the execution group that the work package calculates. */ - WorkPackage(ExecutionGroup *group, unsigned int chunk_number); + rcti rect; #ifdef WITH_CXX_GUARDEDALLOC MEM_CXX_CLASS_ALLOC_FUNCS("COM:WorkPackage") #endif }; + +} // namespace blender::compositor diff --git a/source/blender/compositor/intern/COM_WorkScheduler.cc b/source/blender/compositor/intern/COM_WorkScheduler.cc index 56956b9d097..55114e6b72a 100644 --- a/source/blender/compositor/intern/COM_WorkScheduler.cc +++ b/source/blender/compositor/intern/COM_WorkScheduler.cc @@ -37,6 +37,8 @@ #include "BKE_global.h" +namespace blender::compositor { + enum class ThreadingModel { /** Everything is executed in the caller thread. easy for debugging. */ SingleThreaded, @@ -70,7 +72,7 @@ static struct { /** \brief list of all CPUDevices. for every hardware thread an instance of CPUDevice is * created */ - blender::Vector<CPUDevice *> devices; + blender::Vector<CPUDevice> devices; /** \brief list of all thread for every CPUDevice in cpudevices a thread exists. */ ListBase threads; @@ -89,7 +91,7 @@ static struct { cl_program program; /** \brief list of all OpenCLDevices. for every OpenCL GPU device an instance of OpenCLDevice * is created. */ - blender::Vector<OpenCLDevice *> devices; + blender::Vector<OpenCLDevice> devices; /** \brief list of all thread for every GPUDevice in cpudevices a thread exists. */ ListBase threads; /** \brief all scheduled work for the GPU. */ @@ -117,7 +119,6 @@ static void *thread_execute_gpu(void *data) while ((work = (WorkPackage *)BLI_thread_queue_pop(g_work_scheduler.opencl.queue))) { device->execute(work); - delete work; } return nullptr; @@ -130,9 +131,8 @@ static void opencl_start(CompositorContext &context) BLI_threadpool_init(&g_work_scheduler.opencl.threads, thread_execute_gpu, g_work_scheduler.opencl.devices.size()); - for (int index = 0; index < g_work_scheduler.opencl.devices.size(); index++) { - Device *device = g_work_scheduler.opencl.devices[index]; - BLI_threadpool_insert(&g_work_scheduler.opencl.threads, device); + for (Device &device : g_work_scheduler.opencl.devices) { + BLI_threadpool_insert(&g_work_scheduler.opencl.threads, &device); } g_work_scheduler.opencl.active = true; } @@ -143,7 +143,7 @@ static void opencl_start(CompositorContext &context) static bool opencl_schedule(WorkPackage *package) { - if (package->execution_group->isOpenCL() && g_work_scheduler.opencl.active) { + if (package->execution_group->get_flags().open_cl && g_work_scheduler.opencl.active) { BLI_thread_queue_push(g_work_scheduler.opencl.queue, package); return true; } @@ -263,12 +263,10 @@ static void opencl_initialize(const bool use_opencl) if (error2 != CL_SUCCESS) { printf("CLERROR[%d]: %s\n", error2, clewErrorString(error2)); } - OpenCLDevice *clDevice = new OpenCLDevice(g_work_scheduler.opencl.context, - device, - g_work_scheduler.opencl.program, - vendorID); - clDevice->initialize(); - g_work_scheduler.opencl.devices.append(clDevice); + g_work_scheduler.opencl.devices.append(OpenCLDevice(g_work_scheduler.opencl.context, + device, + g_work_scheduler.opencl.program, + vendorID)); } } MEM_freeN(cldevices); @@ -282,26 +280,19 @@ static void opencl_initialize(const bool use_opencl) static void opencl_deinitialize() { - /* Deinitialize OpenCL GPU's. */ - if (g_work_scheduler.opencl.initialized) { - while (!g_work_scheduler.opencl.devices.is_empty()) { - Device *device = g_work_scheduler.opencl.devices.pop_last(); - device->deinitialize(); - delete device; - } - g_work_scheduler.opencl.devices.clear_and_make_inline(); + g_work_scheduler.opencl.devices.clear_and_make_inline(); - if (g_work_scheduler.opencl.program) { - clReleaseProgram(g_work_scheduler.opencl.program); - g_work_scheduler.opencl.program = nullptr; - } - if (g_work_scheduler.opencl.context) { - clReleaseContext(g_work_scheduler.opencl.context); - g_work_scheduler.opencl.context = nullptr; - } + if (g_work_scheduler.opencl.program) { + clReleaseProgram(g_work_scheduler.opencl.program); + g_work_scheduler.opencl.program = nullptr; + } - g_work_scheduler.opencl.initialized = false; + if (g_work_scheduler.opencl.context) { + clReleaseContext(g_work_scheduler.opencl.context); + g_work_scheduler.opencl.context = nullptr; } + + g_work_scheduler.opencl.initialized = false; } /* \} */ @@ -314,7 +305,6 @@ static void threading_model_single_thread_execute(WorkPackage *package) { CPUDevice device(0); device.execute(package); - delete package; } /* \} */ @@ -330,7 +320,6 @@ static void *threading_model_queue_execute(void *data) BLI_thread_local_set(g_thread_device, device); while ((work = (WorkPackage *)BLI_thread_queue_pop(g_work_scheduler.queue.queue))) { device->execute(work); - delete work; } return nullptr; @@ -347,9 +336,8 @@ static void threading_model_queue_start() BLI_threadpool_init(&g_work_scheduler.queue.threads, threading_model_queue_execute, g_work_scheduler.queue.devices.size()); - for (int index = 0; index < g_work_scheduler.queue.devices.size(); index++) { - Device *device = g_work_scheduler.queue.devices[index]; - BLI_threadpool_insert(&g_work_scheduler.queue.threads, device); + for (Device &device : g_work_scheduler.queue.devices) { + BLI_threadpool_insert(&g_work_scheduler.queue.threads, &device); } } @@ -370,25 +358,17 @@ static void threading_model_queue_initialize(const int num_cpu_threads) { /* Reinitialize if number of threads doesn't match. */ if (g_work_scheduler.queue.devices.size() != num_cpu_threads) { - Device *device; - - while (!g_work_scheduler.queue.devices.is_empty()) { - device = g_work_scheduler.queue.devices.pop_last(); - device->deinitialize(); - delete device; - } + g_work_scheduler.queue.devices.clear(); if (g_work_scheduler.queue.initialized) { BLI_thread_local_delete(g_thread_device); + g_work_scheduler.queue.initialized = false; } - g_work_scheduler.queue.initialized = false; } /* Initialize CPU threads. */ if (!g_work_scheduler.queue.initialized) { for (int index = 0; index < num_cpu_threads; index++) { - CPUDevice *device = new CPUDevice(index); - device->initialize(); - g_work_scheduler.queue.devices.append(device); + g_work_scheduler.queue.devices.append(CPUDevice(index)); } BLI_thread_local_create(g_thread_device); g_work_scheduler.queue.initialized = true; @@ -398,11 +378,6 @@ static void threading_model_queue_deinitialize() { /* deinitialize CPU threads */ if (g_work_scheduler.queue.initialized) { - while (!g_work_scheduler.queue.devices.is_empty()) { - Device *device = g_work_scheduler.queue.devices.pop_last(); - device->deinitialize(); - delete device; - } g_work_scheduler.queue.devices.clear_and_make_inline(); BLI_thread_local_delete(g_thread_device); @@ -455,10 +430,8 @@ static void threading_model_task_stop() /** \name Public API * \{ */ -void WorkScheduler::schedule(ExecutionGroup *group, int chunkNumber) +void WorkScheduler::schedule(WorkPackage *package) { - WorkPackage *package = new WorkPackage(group, chunkNumber); - if (COM_is_opencl_enabled()) { if (opencl_schedule(package)) { return; @@ -607,3 +580,5 @@ int WorkScheduler::current_thread_id() } /* \} */ + +} // namespace blender::compositor diff --git a/source/blender/compositor/intern/COM_WorkScheduler.h b/source/blender/compositor/intern/COM_WorkScheduler.h index 6b53cc3efd6..85b1d7e2ebf 100644 --- a/source/blender/compositor/intern/COM_WorkScheduler.h +++ b/source/blender/compositor/intern/COM_WorkScheduler.h @@ -24,6 +24,8 @@ #include "COM_WorkPackage.h" #include "COM_defines.h" +namespace blender::compositor { + /** \brief the workscheduler * \ingroup execution */ @@ -31,13 +33,11 @@ struct WorkScheduler { /** * \brief schedule a chunk of a group to be calculated. * An execution group schedules a chunk in the WorkScheduler - * when ExecutionGroup.isOpenCL is set the work will be handled by a OpenCLDevice + * when ExecutionGroup.get_flags().open_cl is set the work will be handled by a OpenCLDevice * otherwise the work is scheduled for an CPUDevice * \see ExecutionGroup.execute - * \param group: the execution group - * \param chunkNumber: the number of the chunk in the group to be executed */ - static void schedule(ExecutionGroup *group, int chunkNumber); + static void schedule(WorkPackage *package); /** * \brief initialize the WorkScheduler @@ -93,3 +93,5 @@ struct WorkScheduler { MEM_CXX_CLASS_ALLOC_FUNCS("COM:WorkScheduler") #endif }; + +} // namespace blender::compositor diff --git a/source/blender/compositor/intern/COM_compositor.cc b/source/blender/compositor/intern/COM_compositor.cc index 68e4f80f91f..5839f53976b 100644 --- a/source/blender/compositor/intern/COM_compositor.cc +++ b/source/blender/compositor/intern/COM_compositor.cc @@ -46,12 +46,12 @@ static void compositor_init_node_previews(const RenderData *render_data, bNodeTr 1.0f; int preview_width, preview_height; if (aspect < 1.0f) { - preview_width = COM_PREVIEW_SIZE; - preview_height = (int)(COM_PREVIEW_SIZE * aspect); + preview_width = blender::compositor::COM_PREVIEW_SIZE; + preview_height = (int)(blender::compositor::COM_PREVIEW_SIZE * aspect); } else { - preview_width = (int)(COM_PREVIEW_SIZE / aspect); - preview_height = COM_PREVIEW_SIZE; + preview_width = (int)(blender::compositor::COM_PREVIEW_SIZE / aspect); + preview_height = blender::compositor::COM_PREVIEW_SIZE; } BKE_node_preview_init_tree(node_tree, preview_width, preview_height, false); } @@ -92,12 +92,12 @@ void COM_execute(RenderData *render_data, /* Initialize workscheduler. */ const bool use_opencl = (node_tree->flag & NTREE_COM_OPENCL) != 0; - WorkScheduler::initialize(use_opencl, BKE_render_num_threads(render_data)); + blender::compositor::WorkScheduler::initialize(use_opencl, BKE_render_num_threads(render_data)); /* Execute. */ const bool twopass = (node_tree->flag & NTREE_TWO_PASS) && !rendering; if (twopass) { - ExecutionSystem fast_pass( + blender::compositor::ExecutionSystem fast_pass( render_data, scene, node_tree, rendering, true, viewSettings, displaySettings, viewName); fast_pass.execute(); @@ -107,7 +107,7 @@ void COM_execute(RenderData *render_data, } } - ExecutionSystem system( + blender::compositor::ExecutionSystem system( render_data, scene, node_tree, rendering, false, viewSettings, displaySettings, viewName); system.execute(); @@ -118,7 +118,7 @@ void COM_deinitialize() { if (g_compositor.is_initialized) { BLI_mutex_lock(&g_compositor.mutex); - WorkScheduler::deinitialize(); + blender::compositor::WorkScheduler::deinitialize(); g_compositor.is_initialized = false; BLI_mutex_unlock(&g_compositor.mutex); BLI_mutex_end(&g_compositor.mutex); diff --git a/source/blender/compositor/nodes/COM_AlphaOverNode.cc b/source/blender/compositor/nodes/COM_AlphaOverNode.cc index 640fbf49808..5e09902aee2 100644 --- a/source/blender/compositor/nodes/COM_AlphaOverNode.cc +++ b/source/blender/compositor/nodes/COM_AlphaOverNode.cc @@ -26,6 +26,8 @@ #include "COM_SetValueOperation.h" #include "DNA_material_types.h" /* the ramp types */ +namespace blender::compositor { + void AlphaOverNode::convertToOperations(NodeConverter &converter, const CompositorContext & /*context*/) const { @@ -64,3 +66,5 @@ void AlphaOverNode::convertToOperations(NodeConverter &converter, converter.mapInputSocket(getInputSocket(2), convertProg->getInputSocket(2)); converter.mapOutputSocket(getOutputSocket(0), convertProg->getOutputSocket(0)); } + +} // namespace blender::compositor diff --git a/source/blender/compositor/nodes/COM_AlphaOverNode.h b/source/blender/compositor/nodes/COM_AlphaOverNode.h index 32cd2e20204..201c8ed5b6e 100644 --- a/source/blender/compositor/nodes/COM_AlphaOverNode.h +++ b/source/blender/compositor/nodes/COM_AlphaOverNode.h @@ -20,6 +20,8 @@ #include "COM_Node.h" +namespace blender::compositor { + /** * \brief AlphaOverNode * \ingroup Node @@ -29,5 +31,8 @@ class AlphaOverNode : public Node { AlphaOverNode(bNode *editorNode) : Node(editorNode) { } - void convertToOperations(NodeConverter &converter, const CompositorContext &context) const; + void convertToOperations(NodeConverter &converter, + const CompositorContext &context) const override; }; + +} // namespace blender::compositor diff --git a/source/blender/compositor/nodes/COM_AntiAliasingNode.cc b/source/blender/compositor/nodes/COM_AntiAliasingNode.cc new file mode 100644 index 00000000000..af4832665df --- /dev/null +++ b/source/blender/compositor/nodes/COM_AntiAliasingNode.cc @@ -0,0 +1,60 @@ +/* + * Copyright 2017, Blender Foundation. + * + * 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. + * + * Contributor: IRIE Shinsuke + */ + +#include "COM_AntiAliasingNode.h" +#include "COM_SMAAOperation.h" +#include "DNA_node_types.h" + +namespace blender::compositor { + +void AntiAliasingNode::convertToOperations(NodeConverter &converter, + const CompositorContext & /*context*/) const +{ + bNode *node = this->getbNode(); + NodeAntiAliasingData *data = (NodeAntiAliasingData *)node->storage; + + /* Edge Detection (First Pass) */ + SMAAEdgeDetectionOperation *operation1 = nullptr; + + operation1 = new SMAAEdgeDetectionOperation(); + operation1->setThreshold(data->threshold); + operation1->setLocalContrastAdaptationFactor(data->contrast_limit); + converter.addOperation(operation1); + + converter.mapInputSocket(getInputSocket(0), operation1->getInputSocket(0)); + + /* Blending Weight Calculation Pixel Shader (Second Pass) */ + SMAABlendingWeightCalculationOperation *operation2 = + new SMAABlendingWeightCalculationOperation(); + operation2->setCornerRounding(data->corner_rounding); + converter.addOperation(operation2); + + converter.addLink(operation1->getOutputSocket(), operation2->getInputSocket(0)); + + /* Neighborhood Blending Pixel Shader (Third Pass) */ + SMAANeighborhoodBlendingOperation *operation3 = new SMAANeighborhoodBlendingOperation(); + converter.addOperation(operation3); + + converter.mapInputSocket(getInputSocket(0), operation3->getInputSocket(0)); + converter.addLink(operation2->getOutputSocket(), operation3->getInputSocket(1)); + converter.mapOutputSocket(getOutputSocket(0), operation3->getOutputSocket()); +} + +} // namespace blender::compositor diff --git a/source/blender/compositor/nodes/COM_AntiAliasingNode.h b/source/blender/compositor/nodes/COM_AntiAliasingNode.h new file mode 100644 index 00000000000..d4a6d0d26dc --- /dev/null +++ b/source/blender/compositor/nodes/COM_AntiAliasingNode.h @@ -0,0 +1,40 @@ +/* + * Copyright 2017, Blender Foundation. + * + * 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. + * + * Contributor: IRIE Shinsuke + */ + +#pragma once + +#include "COM_Node.h" + +namespace blender::compositor { + +/** + * @brief AntiAliasingNode + * @ingroup Node + */ +class AntiAliasingNode : public Node { + public: + AntiAliasingNode(bNode *editorNode) : Node(editorNode) + { + } + void convertToOperations(NodeConverter &converter, + const CompositorContext &context) const override; +}; + +} // namespace blender::compositor diff --git a/source/blender/compositor/nodes/COM_BilateralBlurNode.cc b/source/blender/compositor/nodes/COM_BilateralBlurNode.cc index e8037f923f2..1b9da789d3c 100644 --- a/source/blender/compositor/nodes/COM_BilateralBlurNode.cc +++ b/source/blender/compositor/nodes/COM_BilateralBlurNode.cc @@ -21,6 +21,8 @@ #include "COM_ExecutionSystem.h" #include "DNA_node_types.h" +namespace blender::compositor { + BilateralBlurNode::BilateralBlurNode(bNode *editorNode) : Node(editorNode) { /* pass */ @@ -39,3 +41,5 @@ void BilateralBlurNode::convertToOperations(NodeConverter &converter, converter.mapInputSocket(getInputSocket(1), operation->getInputSocket(1)); converter.mapOutputSocket(getOutputSocket(0), operation->getOutputSocket(0)); } + +} // namespace blender::compositor diff --git a/source/blender/compositor/nodes/COM_BilateralBlurNode.h b/source/blender/compositor/nodes/COM_BilateralBlurNode.h index 39308c7d1b6..fed2612ac02 100644 --- a/source/blender/compositor/nodes/COM_BilateralBlurNode.h +++ b/source/blender/compositor/nodes/COM_BilateralBlurNode.h @@ -20,6 +20,8 @@ #include "COM_Node.h" +namespace blender::compositor { + /** * \brief BilateralBlurNode * \ingroup Node @@ -27,5 +29,8 @@ class BilateralBlurNode : public Node { public: BilateralBlurNode(bNode *editorNode); - void convertToOperations(NodeConverter &converter, const CompositorContext &context) const; + void convertToOperations(NodeConverter &converter, + const CompositorContext &context) const override; }; + +} // namespace blender::compositor diff --git a/source/blender/compositor/nodes/COM_BlurNode.cc b/source/blender/compositor/nodes/COM_BlurNode.cc index b82bede8443..e55a594b9c0 100644 --- a/source/blender/compositor/nodes/COM_BlurNode.cc +++ b/source/blender/compositor/nodes/COM_BlurNode.cc @@ -29,6 +29,8 @@ #include "COM_SetValueOperation.h" #include "DNA_node_types.h" +namespace blender::compositor { + BlurNode::BlurNode(bNode *editorNode) : Node(editorNode) { /* pass */ @@ -168,3 +170,5 @@ void BlurNode::convertToOperations(NodeConverter &converter, converter.addPreview(output_operation->getOutputSocket()); } } + +} // namespace blender::compositor diff --git a/source/blender/compositor/nodes/COM_BlurNode.h b/source/blender/compositor/nodes/COM_BlurNode.h index 3c832c93ca2..61cdc17f3a9 100644 --- a/source/blender/compositor/nodes/COM_BlurNode.h +++ b/source/blender/compositor/nodes/COM_BlurNode.h @@ -20,6 +20,8 @@ #include "COM_Node.h" +namespace blender::compositor { + /** * \brief BlurNode * \ingroup Node @@ -27,5 +29,8 @@ class BlurNode : public Node { public: BlurNode(bNode *editorNode); - void convertToOperations(NodeConverter &converter, const CompositorContext &context) const; + void convertToOperations(NodeConverter &converter, + const CompositorContext &context) const override; }; + +} // namespace blender::compositor diff --git a/source/blender/compositor/nodes/COM_BokehBlurNode.cc b/source/blender/compositor/nodes/COM_BokehBlurNode.cc index 5096dbef608..1d2a0dae390 100644 --- a/source/blender/compositor/nodes/COM_BokehBlurNode.cc +++ b/source/blender/compositor/nodes/COM_BokehBlurNode.cc @@ -25,6 +25,8 @@ #include "DNA_node_types.h" #include "DNA_object_types.h" +namespace blender::compositor { + BokehBlurNode::BokehBlurNode(bNode *editorNode) : Node(editorNode) { /* pass */ @@ -75,3 +77,5 @@ void BokehBlurNode::convertToOperations(NodeConverter &converter, } } } + +} // namespace blender::compositor diff --git a/source/blender/compositor/nodes/COM_BokehBlurNode.h b/source/blender/compositor/nodes/COM_BokehBlurNode.h index 87aca9af1f6..2c060936025 100644 --- a/source/blender/compositor/nodes/COM_BokehBlurNode.h +++ b/source/blender/compositor/nodes/COM_BokehBlurNode.h @@ -20,6 +20,8 @@ #include "COM_Node.h" +namespace blender::compositor { + /** * \brief BokehBlurNode * \ingroup Node @@ -27,5 +29,8 @@ class BokehBlurNode : public Node { public: BokehBlurNode(bNode *editorNode); - void convertToOperations(NodeConverter &converter, const CompositorContext &context) const; + void convertToOperations(NodeConverter &converter, + const CompositorContext &context) const override; }; + +} // namespace blender::compositor diff --git a/source/blender/compositor/nodes/COM_BokehImageNode.cc b/source/blender/compositor/nodes/COM_BokehImageNode.cc index 87fe4979c1d..2b0a47c76bc 100644 --- a/source/blender/compositor/nodes/COM_BokehImageNode.cc +++ b/source/blender/compositor/nodes/COM_BokehImageNode.cc @@ -20,6 +20,8 @@ #include "COM_BokehImageOperation.h" #include "COM_ExecutionSystem.h" +namespace blender::compositor { + BokehImageNode::BokehImageNode(bNode *editorNode) : Node(editorNode) { /* pass */ @@ -36,3 +38,5 @@ void BokehImageNode::convertToOperations(NodeConverter &converter, converter.addPreview(operation->getOutputSocket(0)); } + +} // namespace blender::compositor diff --git a/source/blender/compositor/nodes/COM_BokehImageNode.h b/source/blender/compositor/nodes/COM_BokehImageNode.h index b9d957cd6df..323561a7e4f 100644 --- a/source/blender/compositor/nodes/COM_BokehImageNode.h +++ b/source/blender/compositor/nodes/COM_BokehImageNode.h @@ -20,6 +20,8 @@ #include "COM_Node.h" +namespace blender::compositor { + /** * \brief BokehImageNode * \ingroup Node @@ -27,5 +29,8 @@ class BokehImageNode : public Node { public: BokehImageNode(bNode *editorNode); - void convertToOperations(NodeConverter &converter, const CompositorContext &context) const; + void convertToOperations(NodeConverter &converter, + const CompositorContext &context) const override; }; + +} // namespace blender::compositor diff --git a/source/blender/compositor/nodes/COM_BoxMaskNode.cc b/source/blender/compositor/nodes/COM_BoxMaskNode.cc index fe59bd32939..14f42cc42f7 100644 --- a/source/blender/compositor/nodes/COM_BoxMaskNode.cc +++ b/source/blender/compositor/nodes/COM_BoxMaskNode.cc @@ -23,6 +23,8 @@ #include "COM_ScaleOperation.h" #include "COM_SetValueOperation.h" +namespace blender::compositor { + BoxMaskNode::BoxMaskNode(bNode *editorNode) : Node(editorNode) { /* pass */ @@ -60,7 +62,7 @@ void BoxMaskNode::convertToOperations(NodeConverter &converter, scaleOperation->setOffset(0.0f, 0.0f); scaleOperation->setNewWidth(rd->xsch * render_size_factor); scaleOperation->setNewHeight(rd->ysch * render_size_factor); - scaleOperation->getInputSocket(0)->setResizeMode(COM_SC_NO_RESIZE); + scaleOperation->getInputSocket(0)->setResizeMode(ResizeMode::None); converter.addOperation(scaleOperation); converter.addLink(valueOperation->getOutputSocket(0), scaleOperation->getInputSocket(0)); @@ -70,3 +72,5 @@ void BoxMaskNode::convertToOperations(NodeConverter &converter, converter.mapInputSocket(getInputSocket(1), operation->getInputSocket(1)); } + +} // namespace blender::compositor diff --git a/source/blender/compositor/nodes/COM_BoxMaskNode.h b/source/blender/compositor/nodes/COM_BoxMaskNode.h index b815fd75284..46cedf7af75 100644 --- a/source/blender/compositor/nodes/COM_BoxMaskNode.h +++ b/source/blender/compositor/nodes/COM_BoxMaskNode.h @@ -20,6 +20,8 @@ #include "COM_Node.h" +namespace blender::compositor { + /** * \brief BoxMaskNode * \ingroup Node @@ -27,5 +29,8 @@ class BoxMaskNode : public Node { public: BoxMaskNode(bNode *editorNode); - void convertToOperations(NodeConverter &converter, const CompositorContext &context) const; + void convertToOperations(NodeConverter &converter, + const CompositorContext &context) const override; }; + +} // namespace blender::compositor diff --git a/source/blender/compositor/nodes/COM_BrightnessNode.cc b/source/blender/compositor/nodes/COM_BrightnessNode.cc index fcd2a6de1f4..b64f1fea99f 100644 --- a/source/blender/compositor/nodes/COM_BrightnessNode.cc +++ b/source/blender/compositor/nodes/COM_BrightnessNode.cc @@ -20,6 +20,8 @@ #include "COM_BrightnessOperation.h" #include "COM_ExecutionSystem.h" +namespace blender::compositor { + BrightnessNode::BrightnessNode(bNode *editorNode) : Node(editorNode) { /* pass */ @@ -38,3 +40,5 @@ void BrightnessNode::convertToOperations(NodeConverter &converter, converter.mapInputSocket(getInputSocket(2), operation->getInputSocket(2)); converter.mapOutputSocket(getOutputSocket(0), operation->getOutputSocket(0)); } + +} // namespace blender::compositor diff --git a/source/blender/compositor/nodes/COM_BrightnessNode.h b/source/blender/compositor/nodes/COM_BrightnessNode.h index b64b622dd71..1084108b1c3 100644 --- a/source/blender/compositor/nodes/COM_BrightnessNode.h +++ b/source/blender/compositor/nodes/COM_BrightnessNode.h @@ -20,6 +20,8 @@ #include "COM_Node.h" +namespace blender::compositor { + /** * \brief BrightnessNode * \ingroup Node @@ -27,5 +29,8 @@ class BrightnessNode : public Node { public: BrightnessNode(bNode *editorNode); - void convertToOperations(NodeConverter &converter, const CompositorContext &context) const; + void convertToOperations(NodeConverter &converter, + const CompositorContext &context) const override; }; + +} // namespace blender::compositor diff --git a/source/blender/compositor/nodes/COM_ChannelMatteNode.cc b/source/blender/compositor/nodes/COM_ChannelMatteNode.cc index 598cd7b7745..d0f72274aea 100644 --- a/source/blender/compositor/nodes/COM_ChannelMatteNode.cc +++ b/source/blender/compositor/nodes/COM_ChannelMatteNode.cc @@ -22,6 +22,8 @@ #include "COM_ConvertOperation.h" #include "COM_SetAlphaMultiplyOperation.h" +namespace blender::compositor { + ChannelMatteNode::ChannelMatteNode(bNode *editorNode) : Node(editorNode) { /* pass */ @@ -93,3 +95,5 @@ void ChannelMatteNode::convertToOperations(NodeConverter &converter, converter.addPreview(operationAlpha->getOutputSocket()); } } + +} // namespace blender::compositor diff --git a/source/blender/compositor/nodes/COM_ChannelMatteNode.h b/source/blender/compositor/nodes/COM_ChannelMatteNode.h index bca821fa60c..46100b3f7ea 100644 --- a/source/blender/compositor/nodes/COM_ChannelMatteNode.h +++ b/source/blender/compositor/nodes/COM_ChannelMatteNode.h @@ -20,6 +20,8 @@ #include "COM_Node.h" +namespace blender::compositor { + /** * \brief ChannelMatteNode * \ingroup Node @@ -27,5 +29,8 @@ class ChannelMatteNode : public Node { public: ChannelMatteNode(bNode *editorNode); - void convertToOperations(NodeConverter &converter, const CompositorContext &context) const; + void convertToOperations(NodeConverter &converter, + const CompositorContext &context) const override; }; + +} // namespace blender::compositor diff --git a/source/blender/compositor/nodes/COM_ChromaMatteNode.cc b/source/blender/compositor/nodes/COM_ChromaMatteNode.cc index 83e88b35f92..9abf183a843 100644 --- a/source/blender/compositor/nodes/COM_ChromaMatteNode.cc +++ b/source/blender/compositor/nodes/COM_ChromaMatteNode.cc @@ -22,6 +22,8 @@ #include "COM_ConvertOperation.h" #include "COM_SetAlphaMultiplyOperation.h" +namespace blender::compositor { + ChromaMatteNode::ChromaMatteNode(bNode *editorNode) : Node(editorNode) { /* pass */ @@ -63,3 +65,5 @@ void ChromaMatteNode::convertToOperations(NodeConverter &converter, converter.addPreview(operationAlpha->getOutputSocket()); } + +} // namespace blender::compositor diff --git a/source/blender/compositor/nodes/COM_ChromaMatteNode.h b/source/blender/compositor/nodes/COM_ChromaMatteNode.h index d8febdde36f..f3ddd013fa4 100644 --- a/source/blender/compositor/nodes/COM_ChromaMatteNode.h +++ b/source/blender/compositor/nodes/COM_ChromaMatteNode.h @@ -20,6 +20,8 @@ #include "COM_Node.h" +namespace blender::compositor { + /** * \brief ChromaMatteNode * \ingroup Node @@ -27,5 +29,8 @@ class ChromaMatteNode : public Node { public: ChromaMatteNode(bNode *editorNode); - void convertToOperations(NodeConverter &converter, const CompositorContext &context) const; + void convertToOperations(NodeConverter &converter, + const CompositorContext &context) const override; }; + +} // namespace blender::compositor diff --git a/source/blender/compositor/nodes/COM_ColorBalanceNode.cc b/source/blender/compositor/nodes/COM_ColorBalanceNode.cc index 596d9631297..03e4e143061 100644 --- a/source/blender/compositor/nodes/COM_ColorBalanceNode.cc +++ b/source/blender/compositor/nodes/COM_ColorBalanceNode.cc @@ -23,6 +23,8 @@ #include "COM_ExecutionSystem.h" #include "COM_MixOperation.h" +namespace blender::compositor { + ColorBalanceNode::ColorBalanceNode(bNode *editorNode) : Node(editorNode) { /* pass */ @@ -71,3 +73,5 @@ void ColorBalanceNode::convertToOperations(NodeConverter &converter, converter.mapInputSocket(inputImageSocket, operation->getInputSocket(1)); converter.mapOutputSocket(outputSocket, operation->getOutputSocket(0)); } + +} // namespace blender::compositor diff --git a/source/blender/compositor/nodes/COM_ColorBalanceNode.h b/source/blender/compositor/nodes/COM_ColorBalanceNode.h index 302b66863ca..243713b4912 100644 --- a/source/blender/compositor/nodes/COM_ColorBalanceNode.h +++ b/source/blender/compositor/nodes/COM_ColorBalanceNode.h @@ -20,6 +20,8 @@ #include "COM_Node.h" +namespace blender::compositor { + /** * \brief ColorBalanceNode * \ingroup Node @@ -27,5 +29,8 @@ class ColorBalanceNode : public Node { public: ColorBalanceNode(bNode *editorNode); - void convertToOperations(NodeConverter &converter, const CompositorContext &context) const; + void convertToOperations(NodeConverter &converter, + const CompositorContext &context) const override; }; + +} // namespace blender::compositor diff --git a/source/blender/compositor/nodes/COM_ColorCorrectionNode.cc b/source/blender/compositor/nodes/COM_ColorCorrectionNode.cc index 92b334fddb9..6397b1d8e4b 100644 --- a/source/blender/compositor/nodes/COM_ColorCorrectionNode.cc +++ b/source/blender/compositor/nodes/COM_ColorCorrectionNode.cc @@ -20,6 +20,8 @@ #include "COM_ColorCorrectionOperation.h" #include "COM_ExecutionSystem.h" +namespace blender::compositor { + ColorCorrectionNode::ColorCorrectionNode(bNode *editorNode) : Node(editorNode) { /* pass */ @@ -41,3 +43,5 @@ void ColorCorrectionNode::convertToOperations(NodeConverter &converter, converter.mapInputSocket(getInputSocket(1), operation->getInputSocket(1)); converter.mapOutputSocket(getOutputSocket(0), operation->getOutputSocket(0)); } + +} // namespace blender::compositor diff --git a/source/blender/compositor/nodes/COM_ColorCorrectionNode.h b/source/blender/compositor/nodes/COM_ColorCorrectionNode.h index be6545f0cfa..aee07ee07a3 100644 --- a/source/blender/compositor/nodes/COM_ColorCorrectionNode.h +++ b/source/blender/compositor/nodes/COM_ColorCorrectionNode.h @@ -20,6 +20,8 @@ #include "COM_Node.h" +namespace blender::compositor { + /** * \brief ColorCorrectionNode * \ingroup Node @@ -27,5 +29,8 @@ class ColorCorrectionNode : public Node { public: ColorCorrectionNode(bNode *editorNode); - void convertToOperations(NodeConverter &converter, const CompositorContext &context) const; + void convertToOperations(NodeConverter &converter, + const CompositorContext &context) const override; }; + +} // namespace blender::compositor diff --git a/source/blender/compositor/nodes/COM_ColorCurveNode.cc b/source/blender/compositor/nodes/COM_ColorCurveNode.cc index e1888f3f0bc..774dd689a46 100644 --- a/source/blender/compositor/nodes/COM_ColorCurveNode.cc +++ b/source/blender/compositor/nodes/COM_ColorCurveNode.cc @@ -20,6 +20,8 @@ #include "COM_ColorCurveOperation.h" #include "COM_ExecutionSystem.h" +namespace blender::compositor { + ColorCurveNode::ColorCurveNode(bNode *editorNode) : Node(editorNode) { /* pass */ @@ -55,3 +57,5 @@ void ColorCurveNode::convertToOperations(NodeConverter &converter, converter.mapOutputSocket(getOutputSocket(0), operation->getOutputSocket()); } } + +} // namespace blender::compositor diff --git a/source/blender/compositor/nodes/COM_ColorCurveNode.h b/source/blender/compositor/nodes/COM_ColorCurveNode.h index 6eaf1db6fbb..89786b47cf5 100644 --- a/source/blender/compositor/nodes/COM_ColorCurveNode.h +++ b/source/blender/compositor/nodes/COM_ColorCurveNode.h @@ -20,6 +20,8 @@ #include "COM_Node.h" +namespace blender::compositor { + /** * \brief ColorCurveNode * \ingroup Node @@ -27,5 +29,8 @@ class ColorCurveNode : public Node { public: ColorCurveNode(bNode *editorNode); - void convertToOperations(NodeConverter &converter, const CompositorContext &context) const; + void convertToOperations(NodeConverter &converter, + const CompositorContext &context) const override; }; + +} // namespace blender::compositor diff --git a/source/blender/compositor/nodes/COM_ColorExposureNode.cc b/source/blender/compositor/nodes/COM_ColorExposureNode.cc index cd0285ac373..a8f164e6b66 100644 --- a/source/blender/compositor/nodes/COM_ColorExposureNode.cc +++ b/source/blender/compositor/nodes/COM_ColorExposureNode.cc @@ -20,6 +20,8 @@ #include "COM_ColorExposureOperation.h" #include "COM_ExecutionSystem.h" +namespace blender::compositor { + ExposureNode::ExposureNode(bNode *editorNode) : Node(editorNode) { /* pass */ @@ -35,3 +37,5 @@ void ExposureNode::convertToOperations(NodeConverter &converter, converter.mapInputSocket(getInputSocket(1), operation->getInputSocket(1)); converter.mapOutputSocket(getOutputSocket(0), operation->getOutputSocket(0)); } + +} // namespace blender::compositor diff --git a/source/blender/compositor/nodes/COM_ColorExposureNode.h b/source/blender/compositor/nodes/COM_ColorExposureNode.h index c17e798b979..df9bfc65f81 100644 --- a/source/blender/compositor/nodes/COM_ColorExposureNode.h +++ b/source/blender/compositor/nodes/COM_ColorExposureNode.h @@ -20,6 +20,8 @@ #include "COM_Node.h" +namespace blender::compositor { + /** * \brief ExposureNode * \ingroup Node @@ -27,5 +29,8 @@ class ExposureNode : public Node { public: ExposureNode(bNode *editorNode); - void convertToOperations(NodeConverter &converter, const CompositorContext &context) const; + void convertToOperations(NodeConverter &converter, + const CompositorContext &context) const override; }; + +} // namespace blender::compositor diff --git a/source/blender/compositor/nodes/COM_ColorMatteNode.cc b/source/blender/compositor/nodes/COM_ColorMatteNode.cc index 865eee5427f..eadb8ce4f96 100644 --- a/source/blender/compositor/nodes/COM_ColorMatteNode.cc +++ b/source/blender/compositor/nodes/COM_ColorMatteNode.cc @@ -22,6 +22,8 @@ #include "COM_ConvertOperation.h" #include "COM_SetAlphaMultiplyOperation.h" +namespace blender::compositor { + ColorMatteNode::ColorMatteNode(bNode *editorNode) : Node(editorNode) { /* pass */ @@ -61,3 +63,5 @@ void ColorMatteNode::convertToOperations(NodeConverter &converter, converter.addPreview(operationAlpha->getOutputSocket()); } + +} // namespace blender::compositor diff --git a/source/blender/compositor/nodes/COM_ColorMatteNode.h b/source/blender/compositor/nodes/COM_ColorMatteNode.h index e84bdfc836f..9d70b6d8416 100644 --- a/source/blender/compositor/nodes/COM_ColorMatteNode.h +++ b/source/blender/compositor/nodes/COM_ColorMatteNode.h @@ -20,6 +20,8 @@ #include "COM_Node.h" +namespace blender::compositor { + /** * \brief ColorMatteNode * \ingroup Node @@ -27,5 +29,8 @@ class ColorMatteNode : public Node { public: ColorMatteNode(bNode *editorNode); - void convertToOperations(NodeConverter &converter, const CompositorContext &context) const; + void convertToOperations(NodeConverter &converter, + const CompositorContext &context) const override; }; + +} // namespace blender::compositor diff --git a/source/blender/compositor/nodes/COM_ColorNode.cc b/source/blender/compositor/nodes/COM_ColorNode.cc index e6f8bfa01fe..f8277645a4b 100644 --- a/source/blender/compositor/nodes/COM_ColorNode.cc +++ b/source/blender/compositor/nodes/COM_ColorNode.cc @@ -20,6 +20,8 @@ #include "COM_ExecutionSystem.h" #include "COM_SetColorOperation.h" +namespace blender::compositor { + ColorNode::ColorNode(bNode *editorNode) : Node(editorNode) { /* pass */ @@ -37,3 +39,5 @@ void ColorNode::convertToOperations(NodeConverter &converter, converter.mapOutputSocket(output, operation->getOutputSocket()); } + +} // namespace blender::compositor diff --git a/source/blender/compositor/nodes/COM_ColorNode.h b/source/blender/compositor/nodes/COM_ColorNode.h index 9b50e9ab7d4..ae3bf575bb4 100644 --- a/source/blender/compositor/nodes/COM_ColorNode.h +++ b/source/blender/compositor/nodes/COM_ColorNode.h @@ -20,6 +20,8 @@ #include "COM_Node.h" +namespace blender::compositor { + /** * \brief ColorNode * \ingroup Node @@ -27,5 +29,8 @@ class ColorNode : public Node { public: ColorNode(bNode *editorNode); - void convertToOperations(NodeConverter &converter, const CompositorContext &context) const; + void convertToOperations(NodeConverter &converter, + const CompositorContext &context) const override; }; + +} // namespace blender::compositor diff --git a/source/blender/compositor/nodes/COM_ColorRampNode.cc b/source/blender/compositor/nodes/COM_ColorRampNode.cc index 1504a76cee7..6b44ef3057e 100644 --- a/source/blender/compositor/nodes/COM_ColorRampNode.cc +++ b/source/blender/compositor/nodes/COM_ColorRampNode.cc @@ -23,6 +23,8 @@ #include "COM_ExecutionSystem.h" #include "DNA_texture_types.h" +namespace blender::compositor { + ColorRampNode::ColorRampNode(bNode *editorNode) : Node(editorNode) { /* pass */ @@ -50,3 +52,5 @@ void ColorRampNode::convertToOperations(NodeConverter &converter, converter.addLink(operation->getOutputSocket(), operation2->getInputSocket(0)); converter.mapOutputSocket(outputSocketAlpha, operation2->getOutputSocket()); } + +} // namespace blender::compositor diff --git a/source/blender/compositor/nodes/COM_ColorRampNode.h b/source/blender/compositor/nodes/COM_ColorRampNode.h index b53edf14dbd..d0c0e43d56c 100644 --- a/source/blender/compositor/nodes/COM_ColorRampNode.h +++ b/source/blender/compositor/nodes/COM_ColorRampNode.h @@ -20,6 +20,8 @@ #include "COM_Node.h" +namespace blender::compositor { + /** * \brief ColorRampNode * \ingroup Node @@ -27,5 +29,8 @@ class ColorRampNode : public Node { public: ColorRampNode(bNode *editorNode); - void convertToOperations(NodeConverter &converter, const CompositorContext &context) const; + void convertToOperations(NodeConverter &converter, + const CompositorContext &context) const override; }; + +} // namespace blender::compositor diff --git a/source/blender/compositor/nodes/COM_ColorSpillNode.cc b/source/blender/compositor/nodes/COM_ColorSpillNode.cc index d1a3099e998..119cff93e84 100644 --- a/source/blender/compositor/nodes/COM_ColorSpillNode.cc +++ b/source/blender/compositor/nodes/COM_ColorSpillNode.cc @@ -20,6 +20,8 @@ #include "BKE_node.h" #include "COM_ColorSpillOperation.h" +namespace blender::compositor { + ColorSpillNode::ColorSpillNode(bNode *editorNode) : Node(editorNode) { /* pass */ @@ -45,3 +47,5 @@ void ColorSpillNode::convertToOperations(NodeConverter &converter, converter.mapInputSocket(inputSocketFac, operation->getInputSocket(1)); converter.mapOutputSocket(outputSocketImage, operation->getOutputSocket()); } + +} // namespace blender::compositor diff --git a/source/blender/compositor/nodes/COM_ColorSpillNode.h b/source/blender/compositor/nodes/COM_ColorSpillNode.h index 3cf8072c7b7..731a76e8811 100644 --- a/source/blender/compositor/nodes/COM_ColorSpillNode.h +++ b/source/blender/compositor/nodes/COM_ColorSpillNode.h @@ -20,6 +20,8 @@ #include "COM_Node.h" +namespace blender::compositor { + /** * \brief ColorSpillNode * \ingroup Node @@ -27,5 +29,8 @@ class ColorSpillNode : public Node { public: ColorSpillNode(bNode *editorNode); - void convertToOperations(NodeConverter &converter, const CompositorContext &context) const; + void convertToOperations(NodeConverter &converter, + const CompositorContext &context) const override; }; + +} // namespace blender::compositor diff --git a/source/blender/compositor/nodes/COM_ColorToBWNode.cc b/source/blender/compositor/nodes/COM_ColorToBWNode.cc index 4115bad5d3f..dcedfc19e4d 100644 --- a/source/blender/compositor/nodes/COM_ColorToBWNode.cc +++ b/source/blender/compositor/nodes/COM_ColorToBWNode.cc @@ -21,6 +21,8 @@ #include "COM_ConvertOperation.h" #include "COM_ExecutionSystem.h" +namespace blender::compositor { + ColorToBWNode::ColorToBWNode(bNode *editorNode) : Node(editorNode) { /* pass */ @@ -38,3 +40,5 @@ void ColorToBWNode::convertToOperations(NodeConverter &converter, converter.mapInputSocket(colorSocket, convertProg->getInputSocket(0)); converter.mapOutputSocket(valueSocket, convertProg->getOutputSocket(0)); } + +} // namespace blender::compositor diff --git a/source/blender/compositor/nodes/COM_ColorToBWNode.h b/source/blender/compositor/nodes/COM_ColorToBWNode.h index 6e7025de496..60c08a3c886 100644 --- a/source/blender/compositor/nodes/COM_ColorToBWNode.h +++ b/source/blender/compositor/nodes/COM_ColorToBWNode.h @@ -20,6 +20,9 @@ #include "COM_Node.h" #include "DNA_node_types.h" + +namespace blender::compositor { + /** * \brief ColorToBWNode * \ingroup Node @@ -27,5 +30,8 @@ class ColorToBWNode : public Node { public: ColorToBWNode(bNode *editorNode); - void convertToOperations(NodeConverter &converter, const CompositorContext &context) const; + void convertToOperations(NodeConverter &converter, + const CompositorContext &context) const override; }; + +} // namespace blender::compositor diff --git a/source/blender/compositor/nodes/COM_CombineColorNode.cc b/source/blender/compositor/nodes/COM_CombineColorNode.cc index 12968f06a10..8a2bbba1c1e 100644 --- a/source/blender/compositor/nodes/COM_CombineColorNode.cc +++ b/source/blender/compositor/nodes/COM_CombineColorNode.cc @@ -20,6 +20,8 @@ #include "COM_ConvertOperation.h" +namespace blender::compositor { + CombineColorNode::CombineColorNode(bNode *editorNode) : Node(editorNode) { } @@ -87,3 +89,5 @@ NodeOperation *CombineYUVANode::getColorConverter(const CompositorContext & /*co { return new ConvertYUVToRGBOperation(); } + +} // namespace blender::compositor diff --git a/source/blender/compositor/nodes/COM_CombineColorNode.h b/source/blender/compositor/nodes/COM_CombineColorNode.h index 378a4855abf..29d3fa37817 100644 --- a/source/blender/compositor/nodes/COM_CombineColorNode.h +++ b/source/blender/compositor/nodes/COM_CombineColorNode.h @@ -20,10 +20,13 @@ #include "COM_Node.h" +namespace blender::compositor { + class CombineColorNode : public Node { public: CombineColorNode(bNode *editorNode); - void convertToOperations(NodeConverter &converter, const CompositorContext &context) const; + void convertToOperations(NodeConverter &converter, + const CompositorContext &context) const override; protected: virtual NodeOperation *getColorConverter(const CompositorContext &context) const = 0; @@ -35,7 +38,7 @@ class CombineRGBANode : public CombineColorNode { { } - NodeOperation *getColorConverter(const CompositorContext &context) const; + NodeOperation *getColorConverter(const CompositorContext &context) const override; }; class CombineHSVANode : public CombineColorNode { @@ -44,7 +47,7 @@ class CombineHSVANode : public CombineColorNode { { } - NodeOperation *getColorConverter(const CompositorContext &context) const; + NodeOperation *getColorConverter(const CompositorContext &context) const override; }; class CombineYCCANode : public CombineColorNode { @@ -53,7 +56,7 @@ class CombineYCCANode : public CombineColorNode { { } - NodeOperation *getColorConverter(const CompositorContext &context) const; + NodeOperation *getColorConverter(const CompositorContext &context) const override; }; class CombineYUVANode : public CombineColorNode { @@ -62,5 +65,7 @@ class CombineYUVANode : public CombineColorNode { { } - NodeOperation *getColorConverter(const CompositorContext &context) const; + NodeOperation *getColorConverter(const CompositorContext &context) const override; }; + +} // namespace blender::compositor diff --git a/source/blender/compositor/nodes/COM_CompositorNode.cc b/source/blender/compositor/nodes/COM_CompositorNode.cc index 32ac1fccec9..262fa550915 100644 --- a/source/blender/compositor/nodes/COM_CompositorNode.cc +++ b/source/blender/compositor/nodes/COM_CompositorNode.cc @@ -20,6 +20,8 @@ #include "COM_CompositorOperation.h" #include "COM_ExecutionSystem.h" +namespace blender::compositor { + CompositorNode::CompositorNode(bNode *editorNode) : Node(editorNode) { /* pass */ @@ -59,3 +61,5 @@ void CompositorNode::convertToOperations(NodeConverter &converter, converter.addNodeInputPreview(imageSocket); } + +} // namespace blender::compositor diff --git a/source/blender/compositor/nodes/COM_CompositorNode.h b/source/blender/compositor/nodes/COM_CompositorNode.h index a75355dfc14..4da9f9a766f 100644 --- a/source/blender/compositor/nodes/COM_CompositorNode.h +++ b/source/blender/compositor/nodes/COM_CompositorNode.h @@ -20,6 +20,9 @@ #include "COM_Node.h" #include "DNA_node_types.h" + +namespace blender::compositor { + /** * \brief CompositorNode * \ingroup Node @@ -27,5 +30,8 @@ class CompositorNode : public Node { public: CompositorNode(bNode *editorNode); - void convertToOperations(NodeConverter &converter, const CompositorContext &context) const; + void convertToOperations(NodeConverter &converter, + const CompositorContext &context) const override; }; + +} // namespace blender::compositor diff --git a/source/blender/compositor/nodes/COM_ConvertAlphaNode.cc b/source/blender/compositor/nodes/COM_ConvertAlphaNode.cc index 2921b44c95b..ac4e45357dc 100644 --- a/source/blender/compositor/nodes/COM_ConvertAlphaNode.cc +++ b/source/blender/compositor/nodes/COM_ConvertAlphaNode.cc @@ -20,6 +20,8 @@ #include "COM_ConvertOperation.h" #include "COM_ExecutionSystem.h" +namespace blender::compositor { + void ConvertAlphaNode::convertToOperations(NodeConverter &converter, const CompositorContext & /*context*/) const { @@ -39,3 +41,5 @@ void ConvertAlphaNode::convertToOperations(NodeConverter &converter, converter.mapInputSocket(getInputSocket(0), operation->getInputSocket(0)); converter.mapOutputSocket(getOutputSocket(0), operation->getOutputSocket()); } + +} // namespace blender::compositor diff --git a/source/blender/compositor/nodes/COM_ConvertAlphaNode.h b/source/blender/compositor/nodes/COM_ConvertAlphaNode.h index 372f34a576f..f3d0ef2cd5b 100644 --- a/source/blender/compositor/nodes/COM_ConvertAlphaNode.h +++ b/source/blender/compositor/nodes/COM_ConvertAlphaNode.h @@ -20,6 +20,8 @@ #include "COM_Node.h" +namespace blender::compositor { + /** * \brief ConvertAlphaNode * \ingroup Node @@ -29,5 +31,8 @@ class ConvertAlphaNode : public Node { ConvertAlphaNode(bNode *editorNode) : Node(editorNode) { } - void convertToOperations(NodeConverter &converter, const CompositorContext &context) const; + void convertToOperations(NodeConverter &converter, + const CompositorContext &context) const override; }; + +} // namespace blender::compositor diff --git a/source/blender/compositor/nodes/COM_CornerPinNode.cc b/source/blender/compositor/nodes/COM_CornerPinNode.cc index efe847bbfbf..6a120cffe0a 100644 --- a/source/blender/compositor/nodes/COM_CornerPinNode.cc +++ b/source/blender/compositor/nodes/COM_CornerPinNode.cc @@ -20,6 +20,8 @@ #include "COM_PlaneCornerPinOperation.h" +namespace blender::compositor { + CornerPinNode::CornerPinNode(bNode *editorNode) : Node(editorNode) { } @@ -53,3 +55,5 @@ void CornerPinNode::convertToOperations(NodeConverter &converter, converter.mapOutputSocket(output_warped_image, warp_image_operation->getOutputSocket()); converter.mapOutputSocket(output_plane, plane_mask_operation->getOutputSocket()); } + +} // namespace blender::compositor diff --git a/source/blender/compositor/nodes/COM_CornerPinNode.h b/source/blender/compositor/nodes/COM_CornerPinNode.h index ba845a614fb..779e057ebb5 100644 --- a/source/blender/compositor/nodes/COM_CornerPinNode.h +++ b/source/blender/compositor/nodes/COM_CornerPinNode.h @@ -21,6 +21,8 @@ #include "DNA_node_types.h" +namespace blender::compositor { + /** * \brief CornerPinNode * \ingroup Node @@ -28,5 +30,8 @@ class CornerPinNode : public Node { public: CornerPinNode(bNode *editorNode); - void convertToOperations(NodeConverter &converter, const CompositorContext &context) const; + void convertToOperations(NodeConverter &converter, + const CompositorContext &context) const override; }; + +} // namespace blender::compositor diff --git a/source/blender/compositor/nodes/COM_CropNode.cc b/source/blender/compositor/nodes/COM_CropNode.cc index 0f0883b0151..3f01062c789 100644 --- a/source/blender/compositor/nodes/COM_CropNode.cc +++ b/source/blender/compositor/nodes/COM_CropNode.cc @@ -19,6 +19,8 @@ #include "COM_CropNode.h" #include "COM_CropOperation.h" +namespace blender::compositor { + CropNode::CropNode(bNode *editorNode) : Node(editorNode) { /* pass */ @@ -45,3 +47,5 @@ void CropNode::convertToOperations(NodeConverter &converter, converter.mapInputSocket(getInputSocket(0), operation->getInputSocket(0)); converter.mapOutputSocket(getOutputSocket(), operation->getOutputSocket()); } + +} // namespace blender::compositor diff --git a/source/blender/compositor/nodes/COM_CropNode.h b/source/blender/compositor/nodes/COM_CropNode.h index f643ebbabcc..be3c9a268f9 100644 --- a/source/blender/compositor/nodes/COM_CropNode.h +++ b/source/blender/compositor/nodes/COM_CropNode.h @@ -20,6 +20,8 @@ #include "COM_Node.h" +namespace blender::compositor { + /** * \brief CropNode * \ingroup Node @@ -27,5 +29,8 @@ class CropNode : public Node { public: CropNode(bNode *editorNode); - void convertToOperations(NodeConverter &converter, const CompositorContext &context) const; + void convertToOperations(NodeConverter &converter, + const CompositorContext &context) const override; }; + +} // namespace blender::compositor diff --git a/source/blender/compositor/nodes/COM_CryptomatteNode.cc b/source/blender/compositor/nodes/COM_CryptomatteNode.cc index 591db8a96e5..23305fa06f8 100644 --- a/source/blender/compositor/nodes/COM_CryptomatteNode.cc +++ b/source/blender/compositor/nodes/COM_CryptomatteNode.cc @@ -31,6 +31,8 @@ #include <iterator> #include <string> +namespace blender::compositor { + /** \name Cryptomatte base * \{ */ @@ -176,7 +178,12 @@ void CryptomatteNode::input_operations_from_image_source( } const std::string prefix = prefix_from_node(node); - LISTBASE_FOREACH (RenderLayer *, render_layer, &image->rr->layers) { + int layer_index; + LISTBASE_FOREACH_INDEX (RenderLayer *, render_layer, &image->rr->layers, layer_index) { + if (!blender::StringRef(prefix).startswith(blender::StringRef( + render_layer->name, BLI_strnlen(render_layer->name, sizeof(render_layer->name))))) { + continue; + } LISTBASE_FOREACH (RenderPass *, render_pass, &render_layer->passes) { const std::string combined_name = combined_layer_pass_name(render_layer, render_pass); if (blender::StringRef(combined_name).startswith(prefix)) { @@ -184,10 +191,12 @@ void CryptomatteNode::input_operations_from_image_source( render_layer, render_pass, view); op->setImage(image); op->setImageUser(iuser); + iuser->layer = layer_index; op->setFramenumber(context.getFramenumber()); r_input_operations.append(op); } } + break; } } BKE_image_release_ibuf(image, ibuf, nullptr); @@ -245,7 +254,7 @@ CryptomatteOperation *CryptomatteLegacyNode::create_cryptomatte_operation( const bNode &UNUSED(node), const NodeCryptomatte *cryptomatte_settings) const { - const int num_inputs = getNumberOfInputSockets() - 1; + const int num_inputs = inputs.size() - 1; CryptomatteOperation *operation = new CryptomatteOperation(num_inputs); if (cryptomatte_settings) { LISTBASE_FOREACH (CryptomatteEntry *, cryptomatte_entry, &cryptomatte_settings->entries) { @@ -261,3 +270,5 @@ CryptomatteOperation *CryptomatteLegacyNode::create_cryptomatte_operation( } /* \} */ + +} // namespace blender::compositor diff --git a/source/blender/compositor/nodes/COM_CryptomatteNode.h b/source/blender/compositor/nodes/COM_CryptomatteNode.h index e99a104c914..a6ba860c678 100644 --- a/source/blender/compositor/nodes/COM_CryptomatteNode.h +++ b/source/blender/compositor/nodes/COM_CryptomatteNode.h @@ -24,6 +24,8 @@ #include "COM_CryptomatteOperation.h" #include "COM_Node.h" +namespace blender::compositor { + /** * \brief CryptomatteNode * \ingroup Node @@ -36,7 +38,8 @@ class CryptomatteBaseNode : public Node { } public: - void convertToOperations(NodeConverter &converter, const CompositorContext &context) const; + void convertToOperations(NodeConverter &converter, + const CompositorContext &context) const override; protected: virtual CryptomatteOperation *create_cryptomatte_operation( @@ -87,3 +90,5 @@ class CryptomatteLegacyNode : public CryptomatteBaseNode { const bNode &node, const NodeCryptomatte *cryptomatte_settings) const override; }; + +} // namespace blender::compositor diff --git a/source/blender/compositor/nodes/COM_DefocusNode.cc b/source/blender/compositor/nodes/COM_DefocusNode.cc index 2343b14f68d..fee7c477d9c 100644 --- a/source/blender/compositor/nodes/COM_DefocusNode.cc +++ b/source/blender/compositor/nodes/COM_DefocusNode.cc @@ -30,6 +30,8 @@ #include "DNA_object_types.h" #include "DNA_scene_types.h" +namespace blender::compositor { + DefocusNode::DefocusNode(bNode *editorNode) : Node(editorNode) { /* pass */ @@ -141,3 +143,5 @@ void DefocusNode::convertToOperations(NodeConverter &converter, converter.mapOutputSocket(getOutputSocket(), operation->getOutputSocket()); } } + +} // namespace blender::compositor diff --git a/source/blender/compositor/nodes/COM_DefocusNode.h b/source/blender/compositor/nodes/COM_DefocusNode.h index c042e98c515..5e51a0ccd52 100644 --- a/source/blender/compositor/nodes/COM_DefocusNode.h +++ b/source/blender/compositor/nodes/COM_DefocusNode.h @@ -20,6 +20,8 @@ #include "COM_Node.h" +namespace blender::compositor { + /** * \brief DefocusNode * \ingroup Node @@ -27,5 +29,8 @@ class DefocusNode : public Node { public: DefocusNode(bNode *editorNode); - void convertToOperations(NodeConverter &converter, const CompositorContext &context) const; + void convertToOperations(NodeConverter &converter, + const CompositorContext &context) const override; }; + +} // namespace blender::compositor diff --git a/source/blender/compositor/nodes/COM_DenoiseNode.cc b/source/blender/compositor/nodes/COM_DenoiseNode.cc index 1aae81e1e7b..e58a9c7ba9a 100644 --- a/source/blender/compositor/nodes/COM_DenoiseNode.cc +++ b/source/blender/compositor/nodes/COM_DenoiseNode.cc @@ -21,6 +21,8 @@ #include "COM_SetValueOperation.h" #include "DNA_node_types.h" +namespace blender::compositor { + DenoiseNode::DenoiseNode(bNode *editorNode) : Node(editorNode) { /* pass */ @@ -41,3 +43,5 @@ void DenoiseNode::convertToOperations(NodeConverter &converter, converter.mapInputSocket(getInputSocket(2), operation->getInputSocket(2)); converter.mapOutputSocket(getOutputSocket(0), operation->getOutputSocket(0)); } + +} // namespace blender::compositor diff --git a/source/blender/compositor/nodes/COM_DenoiseNode.h b/source/blender/compositor/nodes/COM_DenoiseNode.h index 99f59c89fdb..91be8e3e3ad 100644 --- a/source/blender/compositor/nodes/COM_DenoiseNode.h +++ b/source/blender/compositor/nodes/COM_DenoiseNode.h @@ -20,6 +20,8 @@ #include "COM_Node.h" +namespace blender::compositor { + /** * \brief DenoiseNode * \ingroup Node @@ -27,5 +29,8 @@ class DenoiseNode : public Node { public: DenoiseNode(bNode *editorNode); - void convertToOperations(NodeConverter &converter, const CompositorContext &context) const; + void convertToOperations(NodeConverter &converter, + const CompositorContext &context) const override; }; + +} // namespace blender::compositor diff --git a/source/blender/compositor/nodes/COM_DespeckleNode.cc b/source/blender/compositor/nodes/COM_DespeckleNode.cc index 58734917831..beda479025d 100644 --- a/source/blender/compositor/nodes/COM_DespeckleNode.cc +++ b/source/blender/compositor/nodes/COM_DespeckleNode.cc @@ -22,6 +22,8 @@ #include "COM_ExecutionSystem.h" #include "DNA_scene_types.h" +namespace blender::compositor { + DespeckleNode::DespeckleNode(bNode *editorNode) : Node(editorNode) { /* pass */ @@ -46,3 +48,5 @@ void DespeckleNode::convertToOperations(NodeConverter &converter, converter.addPreview(operation->getOutputSocket(0)); } + +} // namespace blender::compositor diff --git a/source/blender/compositor/nodes/COM_DespeckleNode.h b/source/blender/compositor/nodes/COM_DespeckleNode.h index 6b39dd94ac7..2f268e99e1b 100644 --- a/source/blender/compositor/nodes/COM_DespeckleNode.h +++ b/source/blender/compositor/nodes/COM_DespeckleNode.h @@ -20,6 +20,8 @@ #include "COM_Node.h" +namespace blender::compositor { + /** * \brief DespeckleNode * \ingroup Node @@ -27,5 +29,8 @@ class DespeckleNode : public Node { public: DespeckleNode(bNode *editorNode); - void convertToOperations(NodeConverter &converter, const CompositorContext &context) const; + void convertToOperations(NodeConverter &converter, + const CompositorContext &context) const override; }; + +} // namespace blender::compositor diff --git a/source/blender/compositor/nodes/COM_DifferenceMatteNode.cc b/source/blender/compositor/nodes/COM_DifferenceMatteNode.cc index 3d538e9b4a0..8c989bfc04e 100644 --- a/source/blender/compositor/nodes/COM_DifferenceMatteNode.cc +++ b/source/blender/compositor/nodes/COM_DifferenceMatteNode.cc @@ -21,6 +21,8 @@ #include "COM_DifferenceMatteOperation.h" #include "COM_SetAlphaMultiplyOperation.h" +namespace blender::compositor { + DifferenceMatteNode::DifferenceMatteNode(bNode *editorNode) : Node(editorNode) { /* pass */ @@ -52,3 +54,5 @@ void DifferenceMatteNode::convertToOperations(NodeConverter &converter, converter.addPreview(operation->getOutputSocket()); } + +} // namespace blender::compositor diff --git a/source/blender/compositor/nodes/COM_DifferenceMatteNode.h b/source/blender/compositor/nodes/COM_DifferenceMatteNode.h index 26be5fe1e80..a173c723192 100644 --- a/source/blender/compositor/nodes/COM_DifferenceMatteNode.h +++ b/source/blender/compositor/nodes/COM_DifferenceMatteNode.h @@ -20,6 +20,8 @@ #include "COM_Node.h" +namespace blender::compositor { + /** * \brief DifferenceMatteNode * \ingroup Node @@ -27,5 +29,8 @@ class DifferenceMatteNode : public Node { public: DifferenceMatteNode(bNode *editorNode); - void convertToOperations(NodeConverter &converter, const CompositorContext &context) const; + void convertToOperations(NodeConverter &converter, + const CompositorContext &context) const override; }; + +} // namespace blender::compositor diff --git a/source/blender/compositor/nodes/COM_DilateErodeNode.cc b/source/blender/compositor/nodes/COM_DilateErodeNode.cc index e90707618e5..81af1687959 100644 --- a/source/blender/compositor/nodes/COM_DilateErodeNode.cc +++ b/source/blender/compositor/nodes/COM_DilateErodeNode.cc @@ -24,6 +24,8 @@ #include "COM_GaussianAlphaXBlurOperation.h" #include "COM_GaussianAlphaYBlurOperation.h" +namespace blender::compositor { + DilateErodeNode::DilateErodeNode(bNode *editorNode) : Node(editorNode) { /* initialize node data */ @@ -147,3 +149,5 @@ void DilateErodeNode::convertToOperations(NodeConverter &converter, } } } + +} // namespace blender::compositor diff --git a/source/blender/compositor/nodes/COM_DilateErodeNode.h b/source/blender/compositor/nodes/COM_DilateErodeNode.h index 090095df447..7684d7e3834 100644 --- a/source/blender/compositor/nodes/COM_DilateErodeNode.h +++ b/source/blender/compositor/nodes/COM_DilateErodeNode.h @@ -20,6 +20,8 @@ #include "COM_Node.h" +namespace blender::compositor { + /** * \brief DilateErodeNode * \ingroup Node @@ -30,5 +32,8 @@ class DilateErodeNode : public Node { public: DilateErodeNode(bNode *editorNode); - void convertToOperations(NodeConverter &converter, const CompositorContext &context) const; + void convertToOperations(NodeConverter &converter, + const CompositorContext &context) const override; }; + +} // namespace blender::compositor diff --git a/source/blender/compositor/nodes/COM_DirectionalBlurNode.cc b/source/blender/compositor/nodes/COM_DirectionalBlurNode.cc index f8d0eaf4675..90c4236bce8 100644 --- a/source/blender/compositor/nodes/COM_DirectionalBlurNode.cc +++ b/source/blender/compositor/nodes/COM_DirectionalBlurNode.cc @@ -21,6 +21,8 @@ #include "COM_ExecutionSystem.h" #include "DNA_node_types.h" +namespace blender::compositor { + DirectionalBlurNode::DirectionalBlurNode(bNode *editorNode) : Node(editorNode) { /* pass */ @@ -38,3 +40,5 @@ void DirectionalBlurNode::convertToOperations(NodeConverter &converter, converter.mapInputSocket(getInputSocket(0), operation->getInputSocket(0)); converter.mapOutputSocket(getOutputSocket(0), operation->getOutputSocket()); } + +} // namespace blender::compositor diff --git a/source/blender/compositor/nodes/COM_DirectionalBlurNode.h b/source/blender/compositor/nodes/COM_DirectionalBlurNode.h index dfb705cbe64..ce3ef378aaf 100644 --- a/source/blender/compositor/nodes/COM_DirectionalBlurNode.h +++ b/source/blender/compositor/nodes/COM_DirectionalBlurNode.h @@ -20,6 +20,8 @@ #include "COM_Node.h" +namespace blender::compositor { + /** * \brief DirectionalBlurNode * \ingroup Node @@ -27,5 +29,8 @@ class DirectionalBlurNode : public Node { public: DirectionalBlurNode(bNode *editorNode); - void convertToOperations(NodeConverter &converter, const CompositorContext &context) const; + void convertToOperations(NodeConverter &converter, + const CompositorContext &context) const override; }; + +} // namespace blender::compositor diff --git a/source/blender/compositor/nodes/COM_DisplaceNode.cc b/source/blender/compositor/nodes/COM_DisplaceNode.cc index 5b63bc1f393..8217caecf44 100644 --- a/source/blender/compositor/nodes/COM_DisplaceNode.cc +++ b/source/blender/compositor/nodes/COM_DisplaceNode.cc @@ -21,6 +21,8 @@ #include "COM_DisplaceSimpleOperation.h" #include "COM_ExecutionSystem.h" +namespace blender::compositor { + DisplaceNode::DisplaceNode(bNode *editorNode) : Node(editorNode) { /* pass */ @@ -44,3 +46,5 @@ void DisplaceNode::convertToOperations(NodeConverter &converter, converter.mapInputSocket(getInputSocket(3), operation->getInputSocket(3)); converter.mapOutputSocket(getOutputSocket(0), operation->getOutputSocket()); } + +} // namespace blender::compositor diff --git a/source/blender/compositor/nodes/COM_DisplaceNode.h b/source/blender/compositor/nodes/COM_DisplaceNode.h index a9e8a5ad657..b2495839da3 100644 --- a/source/blender/compositor/nodes/COM_DisplaceNode.h +++ b/source/blender/compositor/nodes/COM_DisplaceNode.h @@ -20,6 +20,8 @@ #include "COM_Node.h" +namespace blender::compositor { + /** * \brief DisplaceNode * \ingroup Node @@ -27,5 +29,8 @@ class DisplaceNode : public Node { public: DisplaceNode(bNode *editorNode); - void convertToOperations(NodeConverter &converter, const CompositorContext &context) const; + void convertToOperations(NodeConverter &converter, + const CompositorContext &context) const override; }; + +} // namespace blender::compositor diff --git a/source/blender/compositor/nodes/COM_DistanceMatteNode.cc b/source/blender/compositor/nodes/COM_DistanceMatteNode.cc index 37aeb5c8504..4450c4a2f4a 100644 --- a/source/blender/compositor/nodes/COM_DistanceMatteNode.cc +++ b/source/blender/compositor/nodes/COM_DistanceMatteNode.cc @@ -23,6 +23,8 @@ #include "COM_DistanceYCCMatteOperation.h" #include "COM_SetAlphaMultiplyOperation.h" +namespace blender::compositor { + DistanceMatteNode::DistanceMatteNode(bNode *editorNode) : Node(editorNode) { /* pass */ @@ -96,3 +98,5 @@ void DistanceMatteNode::convertToOperations(NodeConverter &converter, converter.addPreview(operationAlpha->getOutputSocket()); } } + +} // namespace blender::compositor diff --git a/source/blender/compositor/nodes/COM_DistanceMatteNode.h b/source/blender/compositor/nodes/COM_DistanceMatteNode.h index 6ae71ef715f..0baa531b4d2 100644 --- a/source/blender/compositor/nodes/COM_DistanceMatteNode.h +++ b/source/blender/compositor/nodes/COM_DistanceMatteNode.h @@ -20,6 +20,8 @@ #include "COM_Node.h" +namespace blender::compositor { + /** * \brief DistanceMatteNode * \ingroup Node @@ -27,5 +29,8 @@ class DistanceMatteNode : public Node { public: DistanceMatteNode(bNode *editorNode); - void convertToOperations(NodeConverter &converter, const CompositorContext &context) const; + void convertToOperations(NodeConverter &converter, + const CompositorContext &context) const override; }; + +} // namespace blender::compositor diff --git a/source/blender/compositor/nodes/COM_DoubleEdgeMaskNode.cc b/source/blender/compositor/nodes/COM_DoubleEdgeMaskNode.cc index 907a9f49353..847dcc2f8f1 100644 --- a/source/blender/compositor/nodes/COM_DoubleEdgeMaskNode.cc +++ b/source/blender/compositor/nodes/COM_DoubleEdgeMaskNode.cc @@ -20,6 +20,8 @@ #include "COM_DoubleEdgeMaskOperation.h" #include "COM_ExecutionSystem.h" +namespace blender::compositor { + DoubleEdgeMaskNode::DoubleEdgeMaskNode(bNode *editorNode) : Node(editorNode) { /* pass */ @@ -40,3 +42,5 @@ void DoubleEdgeMaskNode::convertToOperations(NodeConverter &converter, converter.mapInputSocket(getInputSocket(1), operation->getInputSocket(1)); converter.mapOutputSocket(getOutputSocket(0), operation->getOutputSocket(0)); } + +} // namespace blender::compositor diff --git a/source/blender/compositor/nodes/COM_DoubleEdgeMaskNode.h b/source/blender/compositor/nodes/COM_DoubleEdgeMaskNode.h index 6d26cbbf528..90e009747c1 100644 --- a/source/blender/compositor/nodes/COM_DoubleEdgeMaskNode.h +++ b/source/blender/compositor/nodes/COM_DoubleEdgeMaskNode.h @@ -20,6 +20,8 @@ #include "COM_Node.h" +namespace blender::compositor { + /** * \brief DoubleEdgeMaskNode * \ingroup Node @@ -27,5 +29,8 @@ class DoubleEdgeMaskNode : public Node { public: DoubleEdgeMaskNode(bNode *editorNode); - void convertToOperations(NodeConverter &converter, const CompositorContext &context) const; + void convertToOperations(NodeConverter &converter, + const CompositorContext &context) const override; }; + +} // namespace blender::compositor diff --git a/source/blender/compositor/nodes/COM_EllipseMaskNode.cc b/source/blender/compositor/nodes/COM_EllipseMaskNode.cc index 1ae855c0f1d..3b4f5ca8c94 100644 --- a/source/blender/compositor/nodes/COM_EllipseMaskNode.cc +++ b/source/blender/compositor/nodes/COM_EllipseMaskNode.cc @@ -23,6 +23,8 @@ #include "COM_ScaleOperation.h" #include "COM_SetValueOperation.h" +namespace blender::compositor { + EllipseMaskNode::EllipseMaskNode(bNode *editorNode) : Node(editorNode) { /* pass */ @@ -60,7 +62,7 @@ void EllipseMaskNode::convertToOperations(NodeConverter &converter, scaleOperation->setOffset(0.0f, 0.0f); scaleOperation->setNewWidth(rd->xsch * render_size_factor); scaleOperation->setNewHeight(rd->ysch * render_size_factor); - scaleOperation->getInputSocket(0)->setResizeMode(COM_SC_NO_RESIZE); + scaleOperation->getInputSocket(0)->setResizeMode(ResizeMode::None); converter.addOperation(scaleOperation); converter.addLink(valueOperation->getOutputSocket(0), scaleOperation->getInputSocket(0)); @@ -70,3 +72,5 @@ void EllipseMaskNode::convertToOperations(NodeConverter &converter, converter.mapInputSocket(getInputSocket(1), operation->getInputSocket(1)); } + +} // namespace blender::compositor diff --git a/source/blender/compositor/nodes/COM_EllipseMaskNode.h b/source/blender/compositor/nodes/COM_EllipseMaskNode.h index d7376cad52e..cbe189be9f6 100644 --- a/source/blender/compositor/nodes/COM_EllipseMaskNode.h +++ b/source/blender/compositor/nodes/COM_EllipseMaskNode.h @@ -20,6 +20,8 @@ #include "COM_Node.h" +namespace blender::compositor { + /** * \brief EllipseMaskNode * \ingroup Node @@ -27,5 +29,8 @@ class EllipseMaskNode : public Node { public: EllipseMaskNode(bNode *editorNode); - void convertToOperations(NodeConverter &converter, const CompositorContext &context) const; + void convertToOperations(NodeConverter &converter, + const CompositorContext &context) const override; }; + +} // namespace blender::compositor diff --git a/source/blender/compositor/nodes/COM_FilterNode.cc b/source/blender/compositor/nodes/COM_FilterNode.cc index 1147c11794f..351219155c2 100644 --- a/source/blender/compositor/nodes/COM_FilterNode.cc +++ b/source/blender/compositor/nodes/COM_FilterNode.cc @@ -23,6 +23,8 @@ #include "COM_ExecutionSystem.h" #include "COM_MixOperation.h" +namespace blender::compositor { + FilterNode::FilterNode(bNode *editorNode) : Node(editorNode) { /* pass */ @@ -94,3 +96,5 @@ void FilterNode::convertToOperations(NodeConverter &converter, converter.addPreview(operation->getOutputSocket(0)); } + +} // namespace blender::compositor diff --git a/source/blender/compositor/nodes/COM_FilterNode.h b/source/blender/compositor/nodes/COM_FilterNode.h index 735d8925b48..f7f4176cea5 100644 --- a/source/blender/compositor/nodes/COM_FilterNode.h +++ b/source/blender/compositor/nodes/COM_FilterNode.h @@ -20,6 +20,8 @@ #include "COM_Node.h" +namespace blender::compositor { + /** * \brief FilterNode * \ingroup Node @@ -27,5 +29,8 @@ class FilterNode : public Node { public: FilterNode(bNode *editorNode); - void convertToOperations(NodeConverter &converter, const CompositorContext &context) const; + void convertToOperations(NodeConverter &converter, + const CompositorContext &context) const override; }; + +} // namespace blender::compositor diff --git a/source/blender/compositor/nodes/COM_FlipNode.cc b/source/blender/compositor/nodes/COM_FlipNode.cc index d89e6b7b844..bca6cd3c4f7 100644 --- a/source/blender/compositor/nodes/COM_FlipNode.cc +++ b/source/blender/compositor/nodes/COM_FlipNode.cc @@ -21,6 +21,8 @@ #include "COM_ExecutionSystem.h" #include "COM_FlipOperation.h" +namespace blender::compositor { + FlipNode::FlipNode(bNode *editorNode) : Node(editorNode) { /* pass */ @@ -52,3 +54,5 @@ void FlipNode::convertToOperations(NodeConverter &converter, converter.mapInputSocket(inputSocket, operation->getInputSocket(0)); converter.mapOutputSocket(outputSocket, operation->getOutputSocket(0)); } + +} // namespace blender::compositor diff --git a/source/blender/compositor/nodes/COM_FlipNode.h b/source/blender/compositor/nodes/COM_FlipNode.h index e819c003430..ee61d09fbba 100644 --- a/source/blender/compositor/nodes/COM_FlipNode.h +++ b/source/blender/compositor/nodes/COM_FlipNode.h @@ -20,6 +20,8 @@ #include "COM_Node.h" +namespace blender::compositor { + /** * \brief FlipNode * \ingroup Node @@ -27,5 +29,8 @@ class FlipNode : public Node { public: FlipNode(bNode *editorNode); - void convertToOperations(NodeConverter &converter, const CompositorContext &context) const; + void convertToOperations(NodeConverter &converter, + const CompositorContext &context) const override; }; + +} // namespace blender::compositor diff --git a/source/blender/compositor/nodes/COM_GammaNode.cc b/source/blender/compositor/nodes/COM_GammaNode.cc index 1ce17faa0dc..52148a80a8f 100644 --- a/source/blender/compositor/nodes/COM_GammaNode.cc +++ b/source/blender/compositor/nodes/COM_GammaNode.cc @@ -20,6 +20,8 @@ #include "COM_ExecutionSystem.h" #include "COM_GammaOperation.h" +namespace blender::compositor { + GammaNode::GammaNode(bNode *editorNode) : Node(editorNode) { /* pass */ @@ -35,3 +37,5 @@ void GammaNode::convertToOperations(NodeConverter &converter, converter.mapInputSocket(getInputSocket(1), operation->getInputSocket(1)); converter.mapOutputSocket(getOutputSocket(0), operation->getOutputSocket(0)); } + +} // namespace blender::compositor diff --git a/source/blender/compositor/nodes/COM_GammaNode.h b/source/blender/compositor/nodes/COM_GammaNode.h index 1a4d02af160..29c9ed170fa 100644 --- a/source/blender/compositor/nodes/COM_GammaNode.h +++ b/source/blender/compositor/nodes/COM_GammaNode.h @@ -20,6 +20,8 @@ #include "COM_Node.h" +namespace blender::compositor { + /** * \brief GammaNode * \ingroup Node @@ -27,5 +29,8 @@ class GammaNode : public Node { public: GammaNode(bNode *editorNode); - void convertToOperations(NodeConverter &converter, const CompositorContext &context) const; + void convertToOperations(NodeConverter &converter, + const CompositorContext &context) const override; }; + +} // namespace blender::compositor diff --git a/source/blender/compositor/nodes/COM_GlareNode.cc b/source/blender/compositor/nodes/COM_GlareNode.cc index ef088e42205..dbe9aaf73ed 100644 --- a/source/blender/compositor/nodes/COM_GlareNode.cc +++ b/source/blender/compositor/nodes/COM_GlareNode.cc @@ -27,6 +27,8 @@ #include "COM_SetValueOperation.h" #include "DNA_node_types.h" +namespace blender::compositor { + GlareNode::GlareNode(bNode *editorNode) : Node(editorNode) { /* pass */ @@ -65,7 +67,7 @@ void GlareNode::convertToOperations(NodeConverter &converter, MixGlareOperation *mixoperation = new MixGlareOperation(); mixoperation->setResolutionInputSocketIndex(1); - mixoperation->getInputSocket(2)->setResizeMode(COM_SC_FIT); + mixoperation->getInputSocket(2)->setResizeMode(ResizeMode::FitAny); converter.addOperation(glareoperation); converter.addOperation(thresholdOperation); @@ -80,3 +82,5 @@ void GlareNode::convertToOperations(NodeConverter &converter, converter.addLink(glareoperation->getOutputSocket(), mixoperation->getInputSocket(2)); converter.mapOutputSocket(getOutputSocket(), mixoperation->getOutputSocket()); } + +} // namespace blender::compositor diff --git a/source/blender/compositor/nodes/COM_GlareNode.h b/source/blender/compositor/nodes/COM_GlareNode.h index 7463af97306..7db5fa85e04 100644 --- a/source/blender/compositor/nodes/COM_GlareNode.h +++ b/source/blender/compositor/nodes/COM_GlareNode.h @@ -20,6 +20,8 @@ #include "COM_Node.h" +namespace blender::compositor { + /** * \brief GlareNode * \ingroup Node @@ -27,5 +29,8 @@ class GlareNode : public Node { public: GlareNode(bNode *editorNode); - void convertToOperations(NodeConverter &converter, const CompositorContext &context) const; + void convertToOperations(NodeConverter &converter, + const CompositorContext &context) const override; }; + +} // namespace blender::compositor diff --git a/source/blender/compositor/nodes/COM_HueSaturationValueCorrectNode.cc b/source/blender/compositor/nodes/COM_HueSaturationValueCorrectNode.cc index 00125ba2ea5..5042d217f9a 100644 --- a/source/blender/compositor/nodes/COM_HueSaturationValueCorrectNode.cc +++ b/source/blender/compositor/nodes/COM_HueSaturationValueCorrectNode.cc @@ -26,6 +26,8 @@ #include "COM_SetValueOperation.h" #include "DNA_node_types.h" +namespace blender::compositor { + HueSaturationValueCorrectNode::HueSaturationValueCorrectNode(bNode *editorNode) : Node(editorNode) { /* pass */ @@ -62,3 +64,5 @@ void HueSaturationValueCorrectNode::convertToOperations( converter.mapInputSocket(valueSocket, blend->getInputSocket(0)); converter.mapOutputSocket(outputSocket, blend->getOutputSocket()); } + +} // namespace blender::compositor diff --git a/source/blender/compositor/nodes/COM_HueSaturationValueCorrectNode.h b/source/blender/compositor/nodes/COM_HueSaturationValueCorrectNode.h index 01790c1a5fb..d75b2ba51ca 100644 --- a/source/blender/compositor/nodes/COM_HueSaturationValueCorrectNode.h +++ b/source/blender/compositor/nodes/COM_HueSaturationValueCorrectNode.h @@ -20,6 +20,8 @@ #include "COM_Node.h" +namespace blender::compositor { + /** * \brief HueSaturationValueCorrectNode * \ingroup Node @@ -27,5 +29,8 @@ class HueSaturationValueCorrectNode : public Node { public: HueSaturationValueCorrectNode(bNode *editorNode); - void convertToOperations(NodeConverter &converter, const CompositorContext &context) const; + void convertToOperations(NodeConverter &converter, + const CompositorContext &context) const override; }; + +} // namespace blender::compositor diff --git a/source/blender/compositor/nodes/COM_HueSaturationValueNode.cc b/source/blender/compositor/nodes/COM_HueSaturationValueNode.cc index dc2e5187e8f..54d2caa75af 100644 --- a/source/blender/compositor/nodes/COM_HueSaturationValueNode.cc +++ b/source/blender/compositor/nodes/COM_HueSaturationValueNode.cc @@ -26,6 +26,8 @@ #include "COM_SetValueOperation.h" #include "DNA_node_types.h" +namespace blender::compositor { + HueSaturationValueNode::HueSaturationValueNode(bNode *editorNode) : Node(editorNode) { /* pass */ @@ -65,3 +67,5 @@ void HueSaturationValueNode::convertToOperations(NodeConverter &converter, converter.mapInputSocket(facSocket, blend->getInputSocket(0)); converter.mapOutputSocket(outputSocket, blend->getOutputSocket()); } + +} // namespace blender::compositor diff --git a/source/blender/compositor/nodes/COM_HueSaturationValueNode.h b/source/blender/compositor/nodes/COM_HueSaturationValueNode.h index 7ef7abe4188..0b295158cc7 100644 --- a/source/blender/compositor/nodes/COM_HueSaturationValueNode.h +++ b/source/blender/compositor/nodes/COM_HueSaturationValueNode.h @@ -20,6 +20,8 @@ #include "COM_Node.h" +namespace blender::compositor { + /** * \brief HueSaturationValueNode * \ingroup Node @@ -27,5 +29,8 @@ class HueSaturationValueNode : public Node { public: HueSaturationValueNode(bNode *editorNode); - void convertToOperations(NodeConverter &converter, const CompositorContext &context) const; + void convertToOperations(NodeConverter &converter, + const CompositorContext &context) const override; }; + +} // namespace blender::compositor diff --git a/source/blender/compositor/nodes/COM_IDMaskNode.cc b/source/blender/compositor/nodes/COM_IDMaskNode.cc index 5ba54d75bcd..9798dabd035 100644 --- a/source/blender/compositor/nodes/COM_IDMaskNode.cc +++ b/source/blender/compositor/nodes/COM_IDMaskNode.cc @@ -21,6 +21,8 @@ #include "COM_ExecutionSystem.h" #include "COM_IDMaskOperation.h" +namespace blender::compositor { + IDMaskNode::IDMaskNode(bNode *editorNode) : Node(editorNode) { /* pass */ @@ -47,3 +49,5 @@ void IDMaskNode::convertToOperations(NodeConverter &converter, converter.mapOutputSocket(getOutputSocket(0), antiAliasOperation->getOutputSocket(0)); } } + +} // namespace blender::compositor diff --git a/source/blender/compositor/nodes/COM_IDMaskNode.h b/source/blender/compositor/nodes/COM_IDMaskNode.h index 51076619951..f702732a8ed 100644 --- a/source/blender/compositor/nodes/COM_IDMaskNode.h +++ b/source/blender/compositor/nodes/COM_IDMaskNode.h @@ -20,6 +20,8 @@ #include "COM_Node.h" +namespace blender::compositor { + /** * \brief IDMaskNode * \ingroup Node @@ -27,5 +29,8 @@ class IDMaskNode : public Node { public: IDMaskNode(bNode *editorNode); - void convertToOperations(NodeConverter &converter, const CompositorContext &context) const; + void convertToOperations(NodeConverter &converter, + const CompositorContext &context) const override; }; + +} // namespace blender::compositor diff --git a/source/blender/compositor/nodes/COM_ImageNode.cc b/source/blender/compositor/nodes/COM_ImageNode.cc index 711399ccd63..f0bfda0f40e 100644 --- a/source/blender/compositor/nodes/COM_ImageNode.cc +++ b/source/blender/compositor/nodes/COM_ImageNode.cc @@ -29,6 +29,8 @@ #include "COM_SetValueOperation.h" #include "COM_SetVectorOperation.h" +namespace blender::compositor { + ImageNode::ImageNode(bNode *editorNode) : Node(editorNode) { /* pass */ @@ -77,7 +79,6 @@ void ImageNode::convertToOperations(NodeConverter &converter, Image *image = (Image *)editorNode->id; ImageUser *imageuser = (ImageUser *)editorNode->storage; int framenumber = context.getFramenumber(); - int numberOfOutputs = this->getNumberOfOutputSockets(); bool outputStraightAlpha = (editorNode->custom1 & CMP_NODE_IMAGE_USE_STRAIGHT_OUTPUT) != 0; BKE_image_user_frame_calc(image, imageuser, context.getFramenumber()); /* force a load, we assume iuser index will be set OK anyway */ @@ -87,14 +88,11 @@ void ImageNode::convertToOperations(NodeConverter &converter, if (image->rr) { RenderLayer *rl = (RenderLayer *)BLI_findlink(&image->rr->layers, imageuser->layer); if (rl) { - NodeOutput *socket; - int index; - is_multilayer_ok = true; - for (index = 0; index < numberOfOutputs; index++) { + for (int64_t index = 0; index < outputs.size(); index++) { + NodeOutput *socket = outputs[index]; NodeOperation *operation = nullptr; - socket = this->getOutputSocket(index); bNodeSocket *bnodeSocket = socket->getbNodeSocket(); NodeImageLayer *storage = (NodeImageLayer *)bnodeSocket->storage; RenderPass *rpass = (RenderPass *)BLI_findstring( @@ -171,8 +169,7 @@ void ImageNode::convertToOperations(NodeConverter &converter, converter.addPreview(operation->getOutputSocket()); } if (STREQ(rpass->name, RE_PASSNAME_COMBINED)) { - for (int alphaIndex = 0; alphaIndex < numberOfOutputs; alphaIndex++) { - NodeOutput *alphaSocket = this->getOutputSocket(alphaIndex); + for (NodeOutput *alphaSocket : getOutputSockets()) { bNodeSocket *bnodeAlphaSocket = alphaSocket->getbNodeSocket(); if (!STREQ(bnodeAlphaSocket->name, "Alpha")) { continue; @@ -204,12 +201,13 @@ void ImageNode::convertToOperations(NodeConverter &converter, /* without this, multilayer that fail to load will crash blender T32490. */ if (is_multilayer_ok == false) { - for (int i = 0; i < getNumberOfOutputSockets(); i++) { - converter.setInvalidOutput(getOutputSocket(i)); + for (NodeOutput *output : getOutputSockets()) { + converter.setInvalidOutput(output); } } } else { + const int64_t numberOfOutputs = getOutputSockets().size(); if (numberOfOutputs > 0) { ImageOperation *operation = new ImageOperation(); operation->setImage(image); @@ -296,4 +294,6 @@ void ImageNode::convertToOperations(NodeConverter &converter, } } } -} +} // namespace blender::compositor + +} // namespace blender::compositor diff --git a/source/blender/compositor/nodes/COM_ImageNode.h b/source/blender/compositor/nodes/COM_ImageNode.h index b99fc07f105..047cc496f83 100644 --- a/source/blender/compositor/nodes/COM_ImageNode.h +++ b/source/blender/compositor/nodes/COM_ImageNode.h @@ -26,6 +26,8 @@ #include "RE_engine.h" #include "RE_pipeline.h" +namespace blender::compositor { + /** * \brief ImageNode * \ingroup Node @@ -44,5 +46,8 @@ class ImageNode : public Node { public: ImageNode(bNode *editorNode); - void convertToOperations(NodeConverter &converter, const CompositorContext &context) const; + void convertToOperations(NodeConverter &converter, + const CompositorContext &context) const override; }; + +} // namespace blender::compositor diff --git a/source/blender/compositor/nodes/COM_InpaintNode.cc b/source/blender/compositor/nodes/COM_InpaintNode.cc index 40fe63ec9f3..01ec5523939 100644 --- a/source/blender/compositor/nodes/COM_InpaintNode.cc +++ b/source/blender/compositor/nodes/COM_InpaintNode.cc @@ -22,6 +22,8 @@ #include "COM_InpaintOperation.h" #include "DNA_scene_types.h" +namespace blender::compositor { + InpaintNode::InpaintNode(bNode *editorNode) : Node(editorNode) { /* pass */ @@ -43,3 +45,5 @@ void InpaintNode::convertToOperations(NodeConverter &converter, converter.mapOutputSocket(getOutputSocket(0), operation->getOutputSocket(0)); } } + +} // namespace blender::compositor diff --git a/source/blender/compositor/nodes/COM_InpaintNode.h b/source/blender/compositor/nodes/COM_InpaintNode.h index 3f778c8ba5c..3a10c11bf61 100644 --- a/source/blender/compositor/nodes/COM_InpaintNode.h +++ b/source/blender/compositor/nodes/COM_InpaintNode.h @@ -20,6 +20,8 @@ #include "COM_Node.h" +namespace blender::compositor { + /** * \brief InpaintNode * \ingroup Node @@ -27,5 +29,8 @@ class InpaintNode : public Node { public: InpaintNode(bNode *editorNode); - void convertToOperations(NodeConverter &converter, const CompositorContext &context) const; + void convertToOperations(NodeConverter &converter, + const CompositorContext &context) const override; }; + +} // namespace blender::compositor diff --git a/source/blender/compositor/nodes/COM_InvertNode.cc b/source/blender/compositor/nodes/COM_InvertNode.cc index 913452c42c8..5fe2033227f 100644 --- a/source/blender/compositor/nodes/COM_InvertNode.cc +++ b/source/blender/compositor/nodes/COM_InvertNode.cc @@ -21,6 +21,8 @@ #include "COM_ExecutionSystem.h" #include "COM_InvertOperation.h" +namespace blender::compositor { + InvertNode::InvertNode(bNode *editorNode) : Node(editorNode) { /* pass */ @@ -39,3 +41,5 @@ void InvertNode::convertToOperations(NodeConverter &converter, converter.mapInputSocket(getInputSocket(1), operation->getInputSocket(1)); converter.mapOutputSocket(getOutputSocket(0), operation->getOutputSocket(0)); } + +} // namespace blender::compositor diff --git a/source/blender/compositor/nodes/COM_InvertNode.h b/source/blender/compositor/nodes/COM_InvertNode.h index d90d6e48713..1cc975b8236 100644 --- a/source/blender/compositor/nodes/COM_InvertNode.h +++ b/source/blender/compositor/nodes/COM_InvertNode.h @@ -20,6 +20,8 @@ #include "COM_Node.h" +namespace blender::compositor { + /** * \brief InvertNode * \ingroup Node @@ -27,5 +29,8 @@ class InvertNode : public Node { public: InvertNode(bNode *editorNode); - void convertToOperations(NodeConverter &converter, const CompositorContext &context) const; + void convertToOperations(NodeConverter &converter, + const CompositorContext &context) const override; }; + +} // namespace blender::compositor diff --git a/source/blender/compositor/nodes/COM_KeyingNode.cc b/source/blender/compositor/nodes/COM_KeyingNode.cc index 9b493d3f332..2054ed67190 100644 --- a/source/blender/compositor/nodes/COM_KeyingNode.cc +++ b/source/blender/compositor/nodes/COM_KeyingNode.cc @@ -37,6 +37,8 @@ #include "COM_GaussianAlphaXBlurOperation.h" #include "COM_GaussianAlphaYBlurOperation.h" +namespace blender::compositor { + KeyingNode::KeyingNode(bNode *editorNode) : Node(editorNode) { /* pass */ @@ -348,3 +350,5 @@ void KeyingNode::convertToOperations(NodeConverter &converter, converter.mapOutputSocket(outputEdges, edgesMatte); } } + +} // namespace blender::compositor diff --git a/source/blender/compositor/nodes/COM_KeyingNode.h b/source/blender/compositor/nodes/COM_KeyingNode.h index 6920d2af09d..6d5e3ca1883 100644 --- a/source/blender/compositor/nodes/COM_KeyingNode.h +++ b/source/blender/compositor/nodes/COM_KeyingNode.h @@ -20,6 +20,8 @@ #include "COM_Node.h" +namespace blender::compositor { + /** * \brief KeyingNode * \ingroup Node @@ -55,5 +57,8 @@ class KeyingNode : public Node { public: KeyingNode(bNode *editorNode); - void convertToOperations(NodeConverter &converter, const CompositorContext &context) const; + void convertToOperations(NodeConverter &converter, + const CompositorContext &context) const override; }; + +} // namespace blender::compositor diff --git a/source/blender/compositor/nodes/COM_KeyingScreenNode.cc b/source/blender/compositor/nodes/COM_KeyingScreenNode.cc index 93a9a071226..cbe4f165a45 100644 --- a/source/blender/compositor/nodes/COM_KeyingScreenNode.cc +++ b/source/blender/compositor/nodes/COM_KeyingScreenNode.cc @@ -22,6 +22,8 @@ #include "DNA_movieclip_types.h" +namespace blender::compositor { + KeyingScreenNode::KeyingScreenNode(bNode *editorNode) : Node(editorNode) { /* pass */ @@ -45,3 +47,5 @@ void KeyingScreenNode::convertToOperations(NodeConverter &converter, converter.mapOutputSocket(outputScreen, operation->getOutputSocket()); } + +} // namespace blender::compositor diff --git a/source/blender/compositor/nodes/COM_KeyingScreenNode.h b/source/blender/compositor/nodes/COM_KeyingScreenNode.h index ce9ef54543d..f2ad3b344f1 100644 --- a/source/blender/compositor/nodes/COM_KeyingScreenNode.h +++ b/source/blender/compositor/nodes/COM_KeyingScreenNode.h @@ -21,6 +21,8 @@ #include "COM_Node.h" #include "DNA_node_types.h" +namespace blender::compositor { + /** * \brief KeyingScreenNode * \ingroup Node @@ -28,5 +30,8 @@ class KeyingScreenNode : public Node { public: KeyingScreenNode(bNode *editorNode); - void convertToOperations(NodeConverter &converter, const CompositorContext &context) const; + void convertToOperations(NodeConverter &converter, + const CompositorContext &context) const override; }; + +} // namespace blender::compositor diff --git a/source/blender/compositor/nodes/COM_LensDistortionNode.cc b/source/blender/compositor/nodes/COM_LensDistortionNode.cc index 34d2fba6433..f5226d31989 100644 --- a/source/blender/compositor/nodes/COM_LensDistortionNode.cc +++ b/source/blender/compositor/nodes/COM_LensDistortionNode.cc @@ -21,6 +21,8 @@ #include "COM_ProjectorLensDistortionOperation.h" #include "COM_ScreenLensDistortionOperation.h" +namespace blender::compositor { + LensDistortionNode::LensDistortionNode(bNode *editorNode) : Node(editorNode) { /* pass */ @@ -59,3 +61,5 @@ void LensDistortionNode::convertToOperations(NodeConverter &converter, converter.mapOutputSocket(getOutputSocket(0), operation->getOutputSocket(0)); } } + +} // namespace blender::compositor diff --git a/source/blender/compositor/nodes/COM_LensDistortionNode.h b/source/blender/compositor/nodes/COM_LensDistortionNode.h index 8df0e3f7df1..4de1b0fe4da 100644 --- a/source/blender/compositor/nodes/COM_LensDistortionNode.h +++ b/source/blender/compositor/nodes/COM_LensDistortionNode.h @@ -20,6 +20,8 @@ #include "COM_Node.h" +namespace blender::compositor { + /** * \brief LensDistortionNode * \ingroup Node @@ -27,5 +29,8 @@ class LensDistortionNode : public Node { public: LensDistortionNode(bNode *editorNode); - void convertToOperations(NodeConverter &converter, const CompositorContext &context) const; + void convertToOperations(NodeConverter &converter, + const CompositorContext &context) const override; }; + +} // namespace blender::compositor diff --git a/source/blender/compositor/nodes/COM_LuminanceMatteNode.cc b/source/blender/compositor/nodes/COM_LuminanceMatteNode.cc index 8bfea1eff49..920da53231f 100644 --- a/source/blender/compositor/nodes/COM_LuminanceMatteNode.cc +++ b/source/blender/compositor/nodes/COM_LuminanceMatteNode.cc @@ -22,6 +22,8 @@ #include "COM_LuminanceMatteOperation.h" #include "COM_SetAlphaMultiplyOperation.h" +namespace blender::compositor { + LuminanceMatteNode::LuminanceMatteNode(bNode *editorNode) : Node(editorNode) { /* pass */ @@ -51,3 +53,5 @@ void LuminanceMatteNode::convertToOperations(NodeConverter &converter, converter.addPreview(operation->getOutputSocket()); } + +} // namespace blender::compositor diff --git a/source/blender/compositor/nodes/COM_LuminanceMatteNode.h b/source/blender/compositor/nodes/COM_LuminanceMatteNode.h index 7f2d9dfbe95..ef4ebc8ad92 100644 --- a/source/blender/compositor/nodes/COM_LuminanceMatteNode.h +++ b/source/blender/compositor/nodes/COM_LuminanceMatteNode.h @@ -20,6 +20,8 @@ #include "COM_Node.h" +namespace blender::compositor { + /** * \brief LuminanceMatteNode * \ingroup Node @@ -27,5 +29,8 @@ class LuminanceMatteNode : public Node { public: LuminanceMatteNode(bNode *editorNode); - void convertToOperations(NodeConverter &converter, const CompositorContext &context) const; + void convertToOperations(NodeConverter &converter, + const CompositorContext &context) const override; }; + +} // namespace blender::compositor diff --git a/source/blender/compositor/nodes/COM_MapRangeNode.cc b/source/blender/compositor/nodes/COM_MapRangeNode.cc index 352bc0dd48d..718a6d9e47b 100644 --- a/source/blender/compositor/nodes/COM_MapRangeNode.cc +++ b/source/blender/compositor/nodes/COM_MapRangeNode.cc @@ -21,6 +21,8 @@ #include "COM_ExecutionSystem.h" #include "COM_MapRangeOperation.h" +namespace blender::compositor { + MapRangeNode::MapRangeNode(bNode *editorNode) : Node(editorNode) { /* pass */ @@ -47,3 +49,5 @@ void MapRangeNode::convertToOperations(NodeConverter &converter, converter.mapInputSocket(destMaxSocket, operation->getInputSocket(4)); converter.mapOutputSocket(outputSocket, operation->getOutputSocket(0)); } + +} // namespace blender::compositor diff --git a/source/blender/compositor/nodes/COM_MapRangeNode.h b/source/blender/compositor/nodes/COM_MapRangeNode.h index b838ea858ee..ad6fd78a7d5 100644 --- a/source/blender/compositor/nodes/COM_MapRangeNode.h +++ b/source/blender/compositor/nodes/COM_MapRangeNode.h @@ -20,6 +20,9 @@ #include "COM_Node.h" #include "DNA_node_types.h" + +namespace blender::compositor { + /** * \brief MapRangeNode * \ingroup Node @@ -27,5 +30,8 @@ class MapRangeNode : public Node { public: MapRangeNode(bNode *editorNode); - void convertToOperations(NodeConverter &converter, const CompositorContext &context) const; + void convertToOperations(NodeConverter &converter, + const CompositorContext &context) const override; }; + +} // namespace blender::compositor diff --git a/source/blender/compositor/nodes/COM_MapUVNode.cc b/source/blender/compositor/nodes/COM_MapUVNode.cc index feb9c75ec56..4b7a9e8af0f 100644 --- a/source/blender/compositor/nodes/COM_MapUVNode.cc +++ b/source/blender/compositor/nodes/COM_MapUVNode.cc @@ -20,6 +20,8 @@ #include "COM_ExecutionSystem.h" #include "COM_MapUVOperation.h" +namespace blender::compositor { + MapUVNode::MapUVNode(bNode *editorNode) : Node(editorNode) { /* pass */ @@ -39,3 +41,5 @@ void MapUVNode::convertToOperations(NodeConverter &converter, converter.mapInputSocket(getInputSocket(1), operation->getInputSocket(1)); converter.mapOutputSocket(getOutputSocket(0), operation->getOutputSocket()); } + +} // namespace blender::compositor diff --git a/source/blender/compositor/nodes/COM_MapUVNode.h b/source/blender/compositor/nodes/COM_MapUVNode.h index f9fc413dbe5..f7f4db167ea 100644 --- a/source/blender/compositor/nodes/COM_MapUVNode.h +++ b/source/blender/compositor/nodes/COM_MapUVNode.h @@ -20,6 +20,8 @@ #include "COM_Node.h" +namespace blender::compositor { + /** * \brief MapUVNode * \ingroup Node @@ -27,5 +29,8 @@ class MapUVNode : public Node { public: MapUVNode(bNode *editorNode); - void convertToOperations(NodeConverter &converter, const CompositorContext &context) const; + void convertToOperations(NodeConverter &converter, + const CompositorContext &context) const override; }; + +} // namespace blender::compositor diff --git a/source/blender/compositor/nodes/COM_MapValueNode.cc b/source/blender/compositor/nodes/COM_MapValueNode.cc index e07df8ad367..ae48bda6cb8 100644 --- a/source/blender/compositor/nodes/COM_MapValueNode.cc +++ b/source/blender/compositor/nodes/COM_MapValueNode.cc @@ -21,6 +21,8 @@ #include "COM_ExecutionSystem.h" #include "COM_MapValueOperation.h" +namespace blender::compositor { + MapValueNode::MapValueNode(bNode *editorNode) : Node(editorNode) { /* pass */ @@ -41,3 +43,5 @@ void MapValueNode::convertToOperations(NodeConverter &converter, converter.mapInputSocket(colorSocket, convertProg->getInputSocket(0)); converter.mapOutputSocket(valueSocket, convertProg->getOutputSocket(0)); } + +} // namespace blender::compositor diff --git a/source/blender/compositor/nodes/COM_MapValueNode.h b/source/blender/compositor/nodes/COM_MapValueNode.h index 60ee262d447..dcac1d6e3c5 100644 --- a/source/blender/compositor/nodes/COM_MapValueNode.h +++ b/source/blender/compositor/nodes/COM_MapValueNode.h @@ -20,6 +20,9 @@ #include "COM_Node.h" #include "DNA_node_types.h" + +namespace blender::compositor { + /** * \brief MapValueNode * \ingroup Node @@ -27,5 +30,8 @@ class MapValueNode : public Node { public: MapValueNode(bNode *editorNode); - void convertToOperations(NodeConverter &converter, const CompositorContext &context) const; + void convertToOperations(NodeConverter &converter, + const CompositorContext &context) const override; }; + +} // namespace blender::compositor diff --git a/source/blender/compositor/nodes/COM_MaskNode.cc b/source/blender/compositor/nodes/COM_MaskNode.cc index a6415a3992e..ef171c01653 100644 --- a/source/blender/compositor/nodes/COM_MaskNode.cc +++ b/source/blender/compositor/nodes/COM_MaskNode.cc @@ -22,6 +22,8 @@ #include "DNA_mask_types.h" +namespace blender::compositor { + MaskNode::MaskNode(bNode *editorNode) : Node(editorNode) { /* pass */ @@ -68,3 +70,5 @@ void MaskNode::convertToOperations(NodeConverter &converter, converter.addOperation(operation); converter.mapOutputSocket(outputMask, operation->getOutputSocket()); } + +} // namespace blender::compositor diff --git a/source/blender/compositor/nodes/COM_MaskNode.h b/source/blender/compositor/nodes/COM_MaskNode.h index 4a03916b3c2..5890cf5957a 100644 --- a/source/blender/compositor/nodes/COM_MaskNode.h +++ b/source/blender/compositor/nodes/COM_MaskNode.h @@ -21,6 +21,8 @@ #include "COM_Node.h" #include "DNA_node_types.h" +namespace blender::compositor { + /** * \brief MaskNode * \ingroup Node @@ -28,5 +30,8 @@ class MaskNode : public Node { public: MaskNode(bNode *editorNode); - void convertToOperations(NodeConverter &converter, const CompositorContext &context) const; + void convertToOperations(NodeConverter &converter, + const CompositorContext &context) const override; }; + +} // namespace blender::compositor diff --git a/source/blender/compositor/nodes/COM_MathNode.cc b/source/blender/compositor/nodes/COM_MathNode.cc index 0edf880400f..dd0d8931d58 100644 --- a/source/blender/compositor/nodes/COM_MathNode.cc +++ b/source/blender/compositor/nodes/COM_MathNode.cc @@ -20,6 +20,8 @@ #include "COM_ExecutionSystem.h" #include "COM_MathBaseOperation.h" +namespace blender::compositor { + void MathNode::convertToOperations(NodeConverter &converter, const CompositorContext & /*context*/) const { @@ -159,3 +161,5 @@ void MathNode::convertToOperations(NodeConverter &converter, converter.mapOutputSocket(getOutputSocket(0), operation->getOutputSocket()); } } + +} // namespace blender::compositor diff --git a/source/blender/compositor/nodes/COM_MathNode.h b/source/blender/compositor/nodes/COM_MathNode.h index 41b144679ac..5db59e62bab 100644 --- a/source/blender/compositor/nodes/COM_MathNode.h +++ b/source/blender/compositor/nodes/COM_MathNode.h @@ -20,6 +20,8 @@ #include "COM_Node.h" +namespace blender::compositor { + /** * \brief MathNode * \ingroup Node @@ -29,5 +31,8 @@ class MathNode : public Node { MathNode(bNode *editorNode) : Node(editorNode) { } - void convertToOperations(NodeConverter &converter, const CompositorContext &context) const; + void convertToOperations(NodeConverter &converter, + const CompositorContext &context) const override; }; + +} // namespace blender::compositor diff --git a/source/blender/compositor/nodes/COM_MixNode.cc b/source/blender/compositor/nodes/COM_MixNode.cc index d082590d21b..cfa8d0ee6a6 100644 --- a/source/blender/compositor/nodes/COM_MixNode.cc +++ b/source/blender/compositor/nodes/COM_MixNode.cc @@ -24,6 +24,8 @@ #include "COM_SetValueOperation.h" #include "DNA_material_types.h" /* the ramp types */ +namespace blender::compositor { + MixNode::MixNode(bNode *editorNode) : Node(editorNode) { /* pass */ @@ -110,3 +112,5 @@ void MixNode::convertToOperations(NodeConverter &converter, converter.addPreview(convertProg->getOutputSocket(0)); } + +} // namespace blender::compositor diff --git a/source/blender/compositor/nodes/COM_MixNode.h b/source/blender/compositor/nodes/COM_MixNode.h index 91ce29fdbf2..81f9c41871e 100644 --- a/source/blender/compositor/nodes/COM_MixNode.h +++ b/source/blender/compositor/nodes/COM_MixNode.h @@ -20,6 +20,9 @@ #include "COM_Node.h" #include "DNA_node_types.h" + +namespace blender::compositor { + /** * \brief MixNode * \ingroup Node @@ -27,5 +30,8 @@ class MixNode : public Node { public: MixNode(bNode *editorNode); - void convertToOperations(NodeConverter &converter, const CompositorContext &context) const; + void convertToOperations(NodeConverter &converter, + const CompositorContext &context) const override; }; + +} // namespace blender::compositor diff --git a/source/blender/compositor/nodes/COM_MovieClipNode.cc b/source/blender/compositor/nodes/COM_MovieClipNode.cc index 7cc8f2ea19c..50bd9b4d71b 100644 --- a/source/blender/compositor/nodes/COM_MovieClipNode.cc +++ b/source/blender/compositor/nodes/COM_MovieClipNode.cc @@ -29,6 +29,8 @@ #include "IMB_imbuf.h" +namespace blender::compositor { + MovieClipNode::MovieClipNode(bNode *editorNode) : Node(editorNode) { /* pass */ @@ -106,3 +108,5 @@ void MovieClipNode::convertToOperations(NodeConverter &converter, IMB_freeImBuf(ibuf); } } + +} // namespace blender::compositor diff --git a/source/blender/compositor/nodes/COM_MovieClipNode.h b/source/blender/compositor/nodes/COM_MovieClipNode.h index 58262592dca..a469ce9e2a4 100644 --- a/source/blender/compositor/nodes/COM_MovieClipNode.h +++ b/source/blender/compositor/nodes/COM_MovieClipNode.h @@ -21,6 +21,8 @@ #include "COM_Node.h" #include "DNA_node_types.h" +namespace blender::compositor { + /** * \brief MovieClipNode * \ingroup Node @@ -28,5 +30,8 @@ class MovieClipNode : public Node { public: MovieClipNode(bNode *editorNode); - void convertToOperations(NodeConverter &converter, const CompositorContext &context) const; + void convertToOperations(NodeConverter &converter, + const CompositorContext &context) const override; }; + +} // namespace blender::compositor diff --git a/source/blender/compositor/nodes/COM_MovieDistortionNode.cc b/source/blender/compositor/nodes/COM_MovieDistortionNode.cc index ebace6d5fff..8f17ef8bb98 100644 --- a/source/blender/compositor/nodes/COM_MovieDistortionNode.cc +++ b/source/blender/compositor/nodes/COM_MovieDistortionNode.cc @@ -22,6 +22,8 @@ #include "COM_MovieDistortionOperation.h" #include "DNA_movieclip_types.h" +namespace blender::compositor { + MovieDistortionNode::MovieDistortionNode(bNode *editorNode) : Node(editorNode) { /* pass */ @@ -44,3 +46,5 @@ void MovieDistortionNode::convertToOperations(NodeConverter &converter, converter.mapInputSocket(inputSocket, operation->getInputSocket(0)); converter.mapOutputSocket(outputSocket, operation->getOutputSocket(0)); } + +} // namespace blender::compositor diff --git a/source/blender/compositor/nodes/COM_MovieDistortionNode.h b/source/blender/compositor/nodes/COM_MovieDistortionNode.h index f4df48dac13..0c1610aa3d3 100644 --- a/source/blender/compositor/nodes/COM_MovieDistortionNode.h +++ b/source/blender/compositor/nodes/COM_MovieDistortionNode.h @@ -20,6 +20,8 @@ #include "COM_Node.h" +namespace blender::compositor { + /** * \brief MovieDistortionNode * \ingroup Node @@ -27,5 +29,8 @@ class MovieDistortionNode : public Node { public: MovieDistortionNode(bNode *editorNode); - void convertToOperations(NodeConverter &converter, const CompositorContext &context) const; + void convertToOperations(NodeConverter &converter, + const CompositorContext &context) const override; }; + +} // namespace blender::compositor diff --git a/source/blender/compositor/nodes/COM_NormalNode.cc b/source/blender/compositor/nodes/COM_NormalNode.cc index 1f48a26fd75..5a97b0932ef 100644 --- a/source/blender/compositor/nodes/COM_NormalNode.cc +++ b/source/blender/compositor/nodes/COM_NormalNode.cc @@ -22,6 +22,8 @@ #include "COM_ExecutionSystem.h" #include "COM_SetVectorOperation.h" +namespace blender::compositor { + NormalNode::NormalNode(bNode *editorNode) : Node(editorNode) { /* pass */ @@ -54,3 +56,5 @@ void NormalNode::convertToOperations(NodeConverter &converter, converter.addLink(operationSet->getOutputSocket(0), operation->getInputSocket(1)); converter.mapOutputSocket(outputSocketDotproduct, operation->getOutputSocket(0)); } + +} // namespace blender::compositor diff --git a/source/blender/compositor/nodes/COM_NormalNode.h b/source/blender/compositor/nodes/COM_NormalNode.h index c23e83fb023..6d5cbb394a0 100644 --- a/source/blender/compositor/nodes/COM_NormalNode.h +++ b/source/blender/compositor/nodes/COM_NormalNode.h @@ -20,6 +20,8 @@ #include "COM_Node.h" +namespace blender::compositor { + /** * \brief NormalNode * \ingroup Node @@ -27,5 +29,8 @@ class NormalNode : public Node { public: NormalNode(bNode *editorNode); - void convertToOperations(NodeConverter &converter, const CompositorContext &context) const; + void convertToOperations(NodeConverter &converter, + const CompositorContext &context) const override; }; + +} // namespace blender::compositor diff --git a/source/blender/compositor/nodes/COM_NormalizeNode.cc b/source/blender/compositor/nodes/COM_NormalizeNode.cc index 72459fd477c..639dd8e5a51 100644 --- a/source/blender/compositor/nodes/COM_NormalizeNode.cc +++ b/source/blender/compositor/nodes/COM_NormalizeNode.cc @@ -20,6 +20,8 @@ #include "COM_ExecutionSystem.h" #include "COM_NormalizeOperation.h" +namespace blender::compositor { + NormalizeNode::NormalizeNode(bNode *editorNode) : Node(editorNode) { /* pass */ @@ -34,3 +36,5 @@ void NormalizeNode::convertToOperations(NodeConverter &converter, converter.mapInputSocket(getInputSocket(0), operation->getInputSocket(0)); converter.mapOutputSocket(getOutputSocket(0), operation->getOutputSocket(0)); } + +} // namespace blender::compositor diff --git a/source/blender/compositor/nodes/COM_NormalizeNode.h b/source/blender/compositor/nodes/COM_NormalizeNode.h index 7e53ac7e9a0..7770fc49b61 100644 --- a/source/blender/compositor/nodes/COM_NormalizeNode.h +++ b/source/blender/compositor/nodes/COM_NormalizeNode.h @@ -20,6 +20,8 @@ #include "COM_Node.h" +namespace blender::compositor { + /** * \brief NormalizeNode * \ingroup Node @@ -27,5 +29,8 @@ class NormalizeNode : public Node { public: NormalizeNode(bNode *editorNode); - void convertToOperations(NodeConverter &converter, const CompositorContext &context) const; + void convertToOperations(NodeConverter &converter, + const CompositorContext &context) const override; }; + +} // namespace blender::compositor diff --git a/source/blender/compositor/nodes/COM_OutputFileNode.cc b/source/blender/compositor/nodes/COM_OutputFileNode.cc index dcc1fbdec67..10f176d71f5 100644 --- a/source/blender/compositor/nodes/COM_OutputFileNode.cc +++ b/source/blender/compositor/nodes/COM_OutputFileNode.cc @@ -25,6 +25,8 @@ #include "BLI_path_util.h" +namespace blender::compositor { + OutputFileNode::OutputFileNode(bNode *editorNode) : Node(editorNode) { /* pass */ @@ -69,17 +71,16 @@ void OutputFileNode::convertToOperations(NodeConverter &converter, } converter.addOperation(outputOperation); - int num_inputs = getNumberOfInputSockets(); bool previewAdded = false; - for (int i = 0; i < num_inputs; i++) { - NodeInput *input = getInputSocket(i); + int index = 0; + for (NodeInput *input : inputs) { NodeImageMultiFileSocket *sockdata = (NodeImageMultiFileSocket *)input->getbNodeSocket()->storage; /* note: layer becomes an empty placeholder if the input is not linked */ outputOperation->add_layer(sockdata->layer, input->getDataType(), input->isLinked()); - converter.mapInputSocket(input, outputOperation->getInputSocket(i)); + converter.mapInputSocket(input, outputOperation->getInputSocket(index++)); if (!previewAdded) { converter.addNodeInputPreview(input); @@ -88,10 +89,8 @@ void OutputFileNode::convertToOperations(NodeConverter &converter, } } else { /* single layer format */ - int num_inputs = getNumberOfInputSockets(); bool previewAdded = false; - for (int i = 0; i < num_inputs; i++) { - NodeInput *input = getInputSocket(i); + for (NodeInput *input : inputs) { if (input->isLinked()) { NodeImageMultiFileSocket *sockdata = (NodeImageMultiFileSocket *)input->getbNodeSocket()->storage; @@ -151,3 +150,5 @@ void OutputFileNode::convertToOperations(NodeConverter &converter, } } } + +} // namespace blender::compositor diff --git a/source/blender/compositor/nodes/COM_OutputFileNode.h b/source/blender/compositor/nodes/COM_OutputFileNode.h index 037a345fa50..d1826797c6e 100644 --- a/source/blender/compositor/nodes/COM_OutputFileNode.h +++ b/source/blender/compositor/nodes/COM_OutputFileNode.h @@ -21,6 +21,8 @@ #include "COM_Node.h" #include "DNA_node_types.h" +namespace blender::compositor { + /** * \brief OutputFileNode * \ingroup Node @@ -28,5 +30,8 @@ class OutputFileNode : public Node { public: OutputFileNode(bNode *editorNode); - void convertToOperations(NodeConverter &converter, const CompositorContext &context) const; + void convertToOperations(NodeConverter &converter, + const CompositorContext &context) const override; }; + +} // namespace blender::compositor diff --git a/source/blender/compositor/nodes/COM_PixelateNode.cc b/source/blender/compositor/nodes/COM_PixelateNode.cc index f238f68727e..396f339e5a2 100644 --- a/source/blender/compositor/nodes/COM_PixelateNode.cc +++ b/source/blender/compositor/nodes/COM_PixelateNode.cc @@ -21,6 +21,8 @@ #include "COM_ExecutionSystem.h" #include "COM_PixelateOperation.h" +namespace blender::compositor { + PixelateNode::PixelateNode(bNode *editorNode) : Node(editorNode) { /* pass */ @@ -44,3 +46,5 @@ void PixelateNode::convertToOperations(NodeConverter &converter, converter.mapInputSocket(inputSocket, operation->getInputSocket(0)); converter.mapOutputSocket(outputSocket, operation->getOutputSocket(0)); } + +} // namespace blender::compositor diff --git a/source/blender/compositor/nodes/COM_PixelateNode.h b/source/blender/compositor/nodes/COM_PixelateNode.h index 87cb4df59e8..1a6555550cf 100644 --- a/source/blender/compositor/nodes/COM_PixelateNode.h +++ b/source/blender/compositor/nodes/COM_PixelateNode.h @@ -20,6 +20,8 @@ #include "COM_Node.h" +namespace blender::compositor { + /** * \brief PixelateNode * \ingroup Node @@ -27,5 +29,8 @@ class PixelateNode : public Node { public: PixelateNode(bNode *editorNode); - void convertToOperations(NodeConverter &converter, const CompositorContext &context) const; + void convertToOperations(NodeConverter &converter, + const CompositorContext &context) const override; }; + +} // namespace blender::compositor diff --git a/source/blender/compositor/nodes/COM_PlaneTrackDeformNode.cc b/source/blender/compositor/nodes/COM_PlaneTrackDeformNode.cc index 6b9b51631ec..54a0f4d0452 100644 --- a/source/blender/compositor/nodes/COM_PlaneTrackDeformNode.cc +++ b/source/blender/compositor/nodes/COM_PlaneTrackDeformNode.cc @@ -25,6 +25,8 @@ #include "BKE_node.h" #include "BKE_tracking.h" +namespace blender::compositor { + PlaneTrackDeformNode::PlaneTrackDeformNode(bNode *editorNode) : Node(editorNode) { /* pass */ @@ -70,3 +72,5 @@ void PlaneTrackDeformNode::convertToOperations(NodeConverter &converter, converter.mapOutputSocket(output_plane, plane_mask_operation->getOutputSocket()); } + +} // namespace blender::compositor diff --git a/source/blender/compositor/nodes/COM_PlaneTrackDeformNode.h b/source/blender/compositor/nodes/COM_PlaneTrackDeformNode.h index 36844bc1650..307738fcaf0 100644 --- a/source/blender/compositor/nodes/COM_PlaneTrackDeformNode.h +++ b/source/blender/compositor/nodes/COM_PlaneTrackDeformNode.h @@ -23,6 +23,8 @@ #include "DNA_movieclip_types.h" #include "DNA_node_types.h" +namespace blender::compositor { + /** * \brief PlaneTrackDeformNode * \ingroup Node @@ -30,5 +32,8 @@ class PlaneTrackDeformNode : public Node { public: PlaneTrackDeformNode(bNode *editorNode); - void convertToOperations(NodeConverter &converter, const CompositorContext &context) const; + void convertToOperations(NodeConverter &converter, + const CompositorContext &context) const override; }; + +} // namespace blender::compositor diff --git a/source/blender/compositor/nodes/COM_RenderLayersNode.cc b/source/blender/compositor/nodes/COM_RenderLayersNode.cc index ea3eeb13393..851d0366546 100644 --- a/source/blender/compositor/nodes/COM_RenderLayersNode.cc +++ b/source/blender/compositor/nodes/COM_RenderLayersNode.cc @@ -25,6 +25,8 @@ #include "COM_SetVectorOperation.h" #include "COM_TranslateOperation.h" +namespace blender::compositor { + RenderLayersNode::RenderLayersNode(bNode *editorNode) : Node(editorNode) { /* pass */ @@ -72,9 +74,8 @@ void RenderLayersNode::testRenderLink(NodeConverter &converter, missingRenderLink(converter); return; } - const int num_outputs = this->getNumberOfOutputSockets(); - for (int i = 0; i < num_outputs; i++) { - NodeOutput *output = this->getOutputSocket(i); + + for (NodeOutput *output : getOutputSockets()) { NodeImageLayer *storage = (NodeImageLayer *)output->getbNodeSocket()->storage; RenderPass *rpass = (RenderPass *)BLI_findstring( &rl->passes, storage->pass_name, offsetof(RenderPass, name)); @@ -153,9 +154,7 @@ void RenderLayersNode::missingSocketLink(NodeConverter &converter, NodeOutput *o void RenderLayersNode::missingRenderLink(NodeConverter &converter) const { - const int num_outputs = this->getNumberOfOutputSockets(); - for (int i = 0; i < num_outputs; i++) { - NodeOutput *output = this->getOutputSocket(i); + for (NodeOutput *output : outputs) { missingSocketLink(converter, output); } } @@ -174,3 +173,5 @@ void RenderLayersNode::convertToOperations(NodeConverter &converter, missingRenderLink(converter); } } + +} // namespace blender::compositor diff --git a/source/blender/compositor/nodes/COM_RenderLayersNode.h b/source/blender/compositor/nodes/COM_RenderLayersNode.h index 1ffd084ad1e..4eb2427c8e0 100644 --- a/source/blender/compositor/nodes/COM_RenderLayersNode.h +++ b/source/blender/compositor/nodes/COM_RenderLayersNode.h @@ -23,6 +23,7 @@ #include "DNA_node_types.h" struct Render; +namespace blender::compositor { /** * \brief RenderLayersNode @@ -31,7 +32,8 @@ struct Render; class RenderLayersNode : public Node { public: RenderLayersNode(bNode *editorNode); - void convertToOperations(NodeConverter &converter, const CompositorContext &context) const; + void convertToOperations(NodeConverter &converter, + const CompositorContext &context) const override; private: void testSocketLink(NodeConverter &converter, @@ -48,3 +50,5 @@ class RenderLayersNode : public Node { void missingSocketLink(NodeConverter &converter, NodeOutput *output) const; void missingRenderLink(NodeConverter &converter) const; }; + +} // namespace blender::compositor diff --git a/source/blender/compositor/nodes/COM_RotateNode.cc b/source/blender/compositor/nodes/COM_RotateNode.cc index cbade778bcb..af5baa733dc 100644 --- a/source/blender/compositor/nodes/COM_RotateNode.cc +++ b/source/blender/compositor/nodes/COM_RotateNode.cc @@ -22,6 +22,8 @@ #include "COM_RotateOperation.h" #include "COM_SetSamplerOperation.h" +namespace blender::compositor { + RotateNode::RotateNode(bNode *editorNode) : Node(editorNode) { /* pass */ @@ -45,3 +47,5 @@ void RotateNode::convertToOperations(NodeConverter &converter, converter.mapInputSocket(inputDegreeSocket, operation->getInputSocket(1)); converter.mapOutputSocket(outputSocket, operation->getOutputSocket(0)); } + +} // namespace blender::compositor diff --git a/source/blender/compositor/nodes/COM_RotateNode.h b/source/blender/compositor/nodes/COM_RotateNode.h index b75fdd52683..5d8bcb2e3e4 100644 --- a/source/blender/compositor/nodes/COM_RotateNode.h +++ b/source/blender/compositor/nodes/COM_RotateNode.h @@ -20,6 +20,8 @@ #include "COM_Node.h" +namespace blender::compositor { + /** * \brief RotateNode * \ingroup Node @@ -27,5 +29,8 @@ class RotateNode : public Node { public: RotateNode(bNode *editorNode); - void convertToOperations(NodeConverter &converter, const CompositorContext &context) const; + void convertToOperations(NodeConverter &converter, + const CompositorContext &context) const override; }; + +} // namespace blender::compositor diff --git a/source/blender/compositor/nodes/COM_ScaleNode.cc b/source/blender/compositor/nodes/COM_ScaleNode.cc index 9ffcd5306b0..50d2902f375 100644 --- a/source/blender/compositor/nodes/COM_ScaleNode.cc +++ b/source/blender/compositor/nodes/COM_ScaleNode.cc @@ -24,6 +24,8 @@ #include "COM_SetSamplerOperation.h" #include "COM_SetValueOperation.h" +namespace blender::compositor { + ScaleNode::ScaleNode(bNode *editorNode) : Node(editorNode) { /* pass */ @@ -79,7 +81,7 @@ void ScaleNode::convertToOperations(NodeConverter &converter, operation->setOffset(bnode->custom3, bnode->custom4); operation->setNewWidth(rd->xsch * render_size_factor); operation->setNewHeight(rd->ysch * render_size_factor); - operation->getInputSocket(0)->setResizeMode(COM_SC_NO_RESIZE); + operation->getInputSocket(0)->setResizeMode(ResizeMode::None); converter.addOperation(operation); converter.mapInputSocket(inputSocket, operation->getInputSocket(0)); @@ -105,3 +107,5 @@ void ScaleNode::convertToOperations(NodeConverter &converter, } } } + +} // namespace blender::compositor diff --git a/source/blender/compositor/nodes/COM_ScaleNode.h b/source/blender/compositor/nodes/COM_ScaleNode.h index c9a02411b1c..186ffa8bdce 100644 --- a/source/blender/compositor/nodes/COM_ScaleNode.h +++ b/source/blender/compositor/nodes/COM_ScaleNode.h @@ -20,6 +20,8 @@ #include "COM_Node.h" +namespace blender::compositor { + /** * \brief ScaleNode * \ingroup Node @@ -27,5 +29,8 @@ class ScaleNode : public Node { public: ScaleNode(bNode *editorNode); - void convertToOperations(NodeConverter &converter, const CompositorContext &context) const; + void convertToOperations(NodeConverter &converter, + const CompositorContext &context) const override; }; + +} // namespace blender::compositor diff --git a/source/blender/compositor/nodes/COM_SeparateColorNode.cc b/source/blender/compositor/nodes/COM_SeparateColorNode.cc index 203aa25c9e9..fcaf52c701d 100644 --- a/source/blender/compositor/nodes/COM_SeparateColorNode.cc +++ b/source/blender/compositor/nodes/COM_SeparateColorNode.cc @@ -20,6 +20,8 @@ #include "COM_ConvertOperation.h" +namespace blender::compositor { + SeparateColorNode::SeparateColorNode(bNode *editorNode) : Node(editorNode) { } @@ -119,3 +121,5 @@ NodeOperation *SeparateYUVANode::getColorConverter(const CompositorContext & /*c { return new ConvertRGBToYUVOperation(); } + +} // namespace blender::compositor diff --git a/source/blender/compositor/nodes/COM_SeparateColorNode.h b/source/blender/compositor/nodes/COM_SeparateColorNode.h index aaf86c6e22b..eaf543df51f 100644 --- a/source/blender/compositor/nodes/COM_SeparateColorNode.h +++ b/source/blender/compositor/nodes/COM_SeparateColorNode.h @@ -20,10 +20,13 @@ #include "COM_Node.h" +namespace blender::compositor { + class SeparateColorNode : public Node { public: SeparateColorNode(bNode *editorNode); - void convertToOperations(NodeConverter &converter, const CompositorContext &context) const; + void convertToOperations(NodeConverter &converter, + const CompositorContext &context) const override; protected: virtual NodeOperation *getColorConverter(const CompositorContext &context) const = 0; @@ -35,7 +38,7 @@ class SeparateRGBANode : public SeparateColorNode { { } - NodeOperation *getColorConverter(const CompositorContext &context) const; + NodeOperation *getColorConverter(const CompositorContext &context) const override; }; class SeparateHSVANode : public SeparateColorNode { @@ -44,7 +47,7 @@ class SeparateHSVANode : public SeparateColorNode { { } - NodeOperation *getColorConverter(const CompositorContext &context) const; + NodeOperation *getColorConverter(const CompositorContext &context) const override; }; class SeparateYCCANode : public SeparateColorNode { @@ -53,7 +56,7 @@ class SeparateYCCANode : public SeparateColorNode { { } - NodeOperation *getColorConverter(const CompositorContext &context) const; + NodeOperation *getColorConverter(const CompositorContext &context) const override; }; class SeparateYUVANode : public SeparateColorNode { @@ -62,5 +65,7 @@ class SeparateYUVANode : public SeparateColorNode { { } - NodeOperation *getColorConverter(const CompositorContext &context) const; + NodeOperation *getColorConverter(const CompositorContext &context) const override; }; + +} // namespace blender::compositor diff --git a/source/blender/compositor/nodes/COM_SetAlphaNode.cc b/source/blender/compositor/nodes/COM_SetAlphaNode.cc index 233a5e96ff4..dc41c126ba8 100644 --- a/source/blender/compositor/nodes/COM_SetAlphaNode.cc +++ b/source/blender/compositor/nodes/COM_SetAlphaNode.cc @@ -21,6 +21,8 @@ #include "COM_SetAlphaMultiplyOperation.h" #include "COM_SetAlphaReplaceOperation.h" +namespace blender::compositor { + void SetAlphaNode::convertToOperations(NodeConverter &converter, const CompositorContext & /*context*/) const { @@ -46,3 +48,5 @@ void SetAlphaNode::convertToOperations(NodeConverter &converter, converter.mapInputSocket(getInputSocket(1), operation->getInputSocket(1)); converter.mapOutputSocket(getOutputSocket(0), operation->getOutputSocket()); } + +} // namespace blender::compositor diff --git a/source/blender/compositor/nodes/COM_SetAlphaNode.h b/source/blender/compositor/nodes/COM_SetAlphaNode.h index 2e652539cec..c8d340eb64b 100644 --- a/source/blender/compositor/nodes/COM_SetAlphaNode.h +++ b/source/blender/compositor/nodes/COM_SetAlphaNode.h @@ -20,6 +20,8 @@ #include "COM_Node.h" +namespace blender::compositor { + /** * \brief SetAlphaNode * \ingroup Node @@ -29,5 +31,8 @@ class SetAlphaNode : public Node { SetAlphaNode(bNode *editorNode) : Node(editorNode) { } - void convertToOperations(NodeConverter &converter, const CompositorContext &context) const; + void convertToOperations(NodeConverter &converter, + const CompositorContext &context) const override; }; + +} // namespace blender::compositor diff --git a/source/blender/compositor/nodes/COM_SocketProxyNode.cc b/source/blender/compositor/nodes/COM_SocketProxyNode.cc index 93d8d399cad..b3aa1770551 100644 --- a/source/blender/compositor/nodes/COM_SocketProxyNode.cc +++ b/source/blender/compositor/nodes/COM_SocketProxyNode.cc @@ -25,6 +25,8 @@ #include "COM_SocketProxyOperation.h" #include "COM_WriteBufferOperation.h" +namespace blender::compositor { + SocketProxyNode::SocketProxyNode(bNode *editorNode, bNodeSocket *editorInput, bNodeSocket *editorOutput, @@ -101,3 +103,5 @@ void SocketBufferNode::convertToOperations(NodeConverter &converter, converter.mapInputSocket(input, writeOperation->getInputSocket(0)); converter.mapOutputSocket(output, readOperation->getOutputSocket()); } + +} // namespace blender::compositor diff --git a/source/blender/compositor/nodes/COM_SocketProxyNode.h b/source/blender/compositor/nodes/COM_SocketProxyNode.h index a0c0b63dafd..d19fb802767 100644 --- a/source/blender/compositor/nodes/COM_SocketProxyNode.h +++ b/source/blender/compositor/nodes/COM_SocketProxyNode.h @@ -20,6 +20,8 @@ #include "COM_Node.h" +namespace blender::compositor { + /** * \brief SocketProxyNode * \ingroup Node @@ -30,7 +32,8 @@ class SocketProxyNode : public Node { bNodeSocket *editorInput, bNodeSocket *editorOutput, bool use_conversion); - void convertToOperations(NodeConverter &converter, const CompositorContext &context) const; + void convertToOperations(NodeConverter &converter, + const CompositorContext &context) const override; bool getUseConversion() const { @@ -49,5 +52,8 @@ class SocketProxyNode : public Node { class SocketBufferNode : public Node { public: SocketBufferNode(bNode *editorNode, bNodeSocket *editorInput, bNodeSocket *editorOutput); - void convertToOperations(NodeConverter &converter, const CompositorContext &context) const; + void convertToOperations(NodeConverter &converter, + const CompositorContext &context) const override; }; + +} // namespace blender::compositor diff --git a/source/blender/compositor/nodes/COM_SplitViewerNode.cc b/source/blender/compositor/nodes/COM_SplitViewerNode.cc index 681adeaf1d3..582c650f205 100644 --- a/source/blender/compositor/nodes/COM_SplitViewerNode.cc +++ b/source/blender/compositor/nodes/COM_SplitViewerNode.cc @@ -25,6 +25,8 @@ #include "COM_SplitOperation.h" #include "COM_ViewerOperation.h" +namespace blender::compositor { + SplitViewerNode::SplitViewerNode(bNode *editorNode) : Node(editorNode) { /* pass */ @@ -73,3 +75,5 @@ void SplitViewerNode::convertToOperations(NodeConverter &converter, converter.registerViewer(viewerOperation); } } + +} // namespace blender::compositor diff --git a/source/blender/compositor/nodes/COM_SplitViewerNode.h b/source/blender/compositor/nodes/COM_SplitViewerNode.h index c9ce5164ef4..8a42775eb0d 100644 --- a/source/blender/compositor/nodes/COM_SplitViewerNode.h +++ b/source/blender/compositor/nodes/COM_SplitViewerNode.h @@ -20,6 +20,9 @@ #include "COM_Node.h" #include "DNA_node_types.h" + +namespace blender::compositor { + /** * \brief SplitViewerNode * \ingroup Node @@ -27,5 +30,8 @@ class SplitViewerNode : public Node { public: SplitViewerNode(bNode *editorNode); - void convertToOperations(NodeConverter &converter, const CompositorContext &context) const; + void convertToOperations(NodeConverter &converter, + const CompositorContext &context) const override; }; + +} // namespace blender::compositor diff --git a/source/blender/compositor/nodes/COM_Stabilize2dNode.cc b/source/blender/compositor/nodes/COM_Stabilize2dNode.cc index 38db080a154..fc72b48eca2 100644 --- a/source/blender/compositor/nodes/COM_Stabilize2dNode.cc +++ b/source/blender/compositor/nodes/COM_Stabilize2dNode.cc @@ -28,6 +28,8 @@ #include "DNA_movieclip_types.h" +namespace blender::compositor { + Stabilize2dNode::Stabilize2dNode(bNode *editorNode) : Node(editorNode) { /* pass */ @@ -111,3 +113,5 @@ void Stabilize2dNode::convertToOperations(NodeConverter &converter, converter.addLink(translateOperation->getOutputSocket(), psoperation->getInputSocket(0)); } } + +} // namespace blender::compositor diff --git a/source/blender/compositor/nodes/COM_Stabilize2dNode.h b/source/blender/compositor/nodes/COM_Stabilize2dNode.h index cb46926a3f3..34ed8871e33 100644 --- a/source/blender/compositor/nodes/COM_Stabilize2dNode.h +++ b/source/blender/compositor/nodes/COM_Stabilize2dNode.h @@ -21,6 +21,8 @@ #include "COM_Node.h" #include "DNA_node_types.h" +namespace blender::compositor { + /** * \brief Stabilize2dNode * \ingroup Node @@ -28,5 +30,8 @@ class Stabilize2dNode : public Node { public: Stabilize2dNode(bNode *editorNode); - void convertToOperations(NodeConverter &converter, const CompositorContext &context) const; + void convertToOperations(NodeConverter &converter, + const CompositorContext &context) const override; }; + +} // namespace blender::compositor diff --git a/source/blender/compositor/nodes/COM_SunBeamsNode.cc b/source/blender/compositor/nodes/COM_SunBeamsNode.cc index d899a54c03c..1e5aa0b8020 100644 --- a/source/blender/compositor/nodes/COM_SunBeamsNode.cc +++ b/source/blender/compositor/nodes/COM_SunBeamsNode.cc @@ -18,6 +18,8 @@ #include "COM_SunBeamsNode.h" #include "COM_SunBeamsOperation.h" +namespace blender::compositor { + SunBeamsNode::SunBeamsNode(bNode *editorNode) : Node(editorNode) { /* pass */ @@ -37,3 +39,5 @@ void SunBeamsNode::convertToOperations(NodeConverter &converter, converter.mapInputSocket(inputSocket, operation->getInputSocket(0)); converter.mapOutputSocket(outputSocket, operation->getOutputSocket(0)); } + +} // namespace blender::compositor diff --git a/source/blender/compositor/nodes/COM_SunBeamsNode.h b/source/blender/compositor/nodes/COM_SunBeamsNode.h index 9a56fc1fcea..8b68d3f4cb5 100644 --- a/source/blender/compositor/nodes/COM_SunBeamsNode.h +++ b/source/blender/compositor/nodes/COM_SunBeamsNode.h @@ -19,6 +19,8 @@ #include "COM_Node.h" +namespace blender::compositor { + /** * \brief SunBeamsNode * \ingroup Node @@ -26,5 +28,8 @@ class SunBeamsNode : public Node { public: SunBeamsNode(bNode *editorNode); - void convertToOperations(NodeConverter &converter, const CompositorContext &context) const; + void convertToOperations(NodeConverter &converter, + const CompositorContext &context) const override; }; + +} // namespace blender::compositor diff --git a/source/blender/compositor/nodes/COM_SwitchNode.cc b/source/blender/compositor/nodes/COM_SwitchNode.cc index 947774e98ae..4006d10dafb 100644 --- a/source/blender/compositor/nodes/COM_SwitchNode.cc +++ b/source/blender/compositor/nodes/COM_SwitchNode.cc @@ -18,6 +18,8 @@ #include "COM_SwitchNode.h" +namespace blender::compositor { + SwitchNode::SwitchNode(bNode *editorNode) : Node(editorNode) { /* pass */ @@ -38,3 +40,5 @@ void SwitchNode::convertToOperations(NodeConverter &converter, converter.mapOutputSocket(getOutputSocket(0), result); } + +} // namespace blender::compositor diff --git a/source/blender/compositor/nodes/COM_SwitchNode.h b/source/blender/compositor/nodes/COM_SwitchNode.h index d4d8dd23a98..aa6caa2e59f 100644 --- a/source/blender/compositor/nodes/COM_SwitchNode.h +++ b/source/blender/compositor/nodes/COM_SwitchNode.h @@ -21,6 +21,9 @@ #include "COM_Node.h" #include "COM_NodeOperation.h" #include "DNA_node_types.h" + +namespace blender::compositor { + /** * \brief SwitchNode * \ingroup Node @@ -28,5 +31,8 @@ class SwitchNode : public Node { public: SwitchNode(bNode *editorNode); - void convertToOperations(NodeConverter &converter, const CompositorContext &context) const; + void convertToOperations(NodeConverter &converter, + const CompositorContext &context) const override; }; + +} // namespace blender::compositor diff --git a/source/blender/compositor/nodes/COM_SwitchViewNode.cc b/source/blender/compositor/nodes/COM_SwitchViewNode.cc index e534ebfac9a..395122dd11b 100644 --- a/source/blender/compositor/nodes/COM_SwitchViewNode.cc +++ b/source/blender/compositor/nodes/COM_SwitchViewNode.cc @@ -19,6 +19,8 @@ #include "COM_SwitchViewNode.h" #include "BLI_listbase.h" +namespace blender::compositor { + SwitchViewNode::SwitchViewNode(bNode *editorNode) : Node(editorNode) { /* pass */ @@ -38,3 +40,5 @@ void SwitchViewNode::convertToOperations(NodeConverter &converter, result = converter.addInputProxy(getInputSocket(nr), false); converter.mapOutputSocket(getOutputSocket(0), result); } + +} // namespace blender::compositor diff --git a/source/blender/compositor/nodes/COM_SwitchViewNode.h b/source/blender/compositor/nodes/COM_SwitchViewNode.h index 9423740f668..ce6de52182c 100644 --- a/source/blender/compositor/nodes/COM_SwitchViewNode.h +++ b/source/blender/compositor/nodes/COM_SwitchViewNode.h @@ -21,6 +21,9 @@ #include "COM_Node.h" #include "COM_NodeOperation.h" #include "DNA_node_types.h" + +namespace blender::compositor { + /** * \brief SwitchViewNode * \ingroup Node @@ -28,5 +31,8 @@ class SwitchViewNode : public Node { public: SwitchViewNode(bNode *editorNode); - void convertToOperations(NodeConverter &converter, const CompositorContext &context) const; + void convertToOperations(NodeConverter &converter, + const CompositorContext &context) const override; }; + +} // namespace blender::compositor diff --git a/source/blender/compositor/nodes/COM_TextureNode.cc b/source/blender/compositor/nodes/COM_TextureNode.cc index 3381b5098d7..317355b8c9a 100644 --- a/source/blender/compositor/nodes/COM_TextureNode.cc +++ b/source/blender/compositor/nodes/COM_TextureNode.cc @@ -20,6 +20,8 @@ #include "COM_ExecutionSystem.h" #include "COM_TextureOperation.h" +namespace blender::compositor { + TextureNode::TextureNode(bNode *editorNode) : Node(editorNode) { /* pass */ @@ -54,3 +56,5 @@ void TextureNode::convertToOperations(NodeConverter &converter, converter.mapInputSocket(getInputSocket(1), alphaOperation->getInputSocket(1)); converter.mapOutputSocket(getOutputSocket(0), alphaOperation->getOutputSocket()); } + +} // namespace blender::compositor diff --git a/source/blender/compositor/nodes/COM_TextureNode.h b/source/blender/compositor/nodes/COM_TextureNode.h index 4d780850190..b886e3b74e1 100644 --- a/source/blender/compositor/nodes/COM_TextureNode.h +++ b/source/blender/compositor/nodes/COM_TextureNode.h @@ -21,6 +21,8 @@ #include "COM_Node.h" #include "DNA_node_types.h" +namespace blender::compositor { + /** * \brief TextureNode * \ingroup Node @@ -28,5 +30,8 @@ class TextureNode : public Node { public: TextureNode(bNode *editorNode); - void convertToOperations(NodeConverter &converter, const CompositorContext &context) const; + void convertToOperations(NodeConverter &converter, + const CompositorContext &context) const override; }; + +} // namespace blender::compositor diff --git a/source/blender/compositor/nodes/COM_TimeNode.cc b/source/blender/compositor/nodes/COM_TimeNode.cc index 247e0d11df6..c14c5344eee 100644 --- a/source/blender/compositor/nodes/COM_TimeNode.cc +++ b/source/blender/compositor/nodes/COM_TimeNode.cc @@ -24,6 +24,8 @@ #include "BLI_utildefines.h" +namespace blender::compositor { + TimeNode::TimeNode(bNode *editorNode) : Node(editorNode) { /* pass */ @@ -56,3 +58,5 @@ void TimeNode::convertToOperations(NodeConverter &converter, converter.mapOutputSocket(getOutputSocket(0), operation->getOutputSocket()); } + +} // namespace blender::compositor diff --git a/source/blender/compositor/nodes/COM_TimeNode.h b/source/blender/compositor/nodes/COM_TimeNode.h index 78177014dc1..5688e2cff03 100644 --- a/source/blender/compositor/nodes/COM_TimeNode.h +++ b/source/blender/compositor/nodes/COM_TimeNode.h @@ -20,6 +20,8 @@ #include "COM_Node.h" +namespace blender::compositor { + /** * \brief TimeNode * \ingroup Node @@ -27,5 +29,8 @@ class TimeNode : public Node { public: TimeNode(bNode *editorNode); - void convertToOperations(NodeConverter &converter, const CompositorContext &context) const; + void convertToOperations(NodeConverter &converter, + const CompositorContext &context) const override; }; + +} // namespace blender::compositor diff --git a/source/blender/compositor/nodes/COM_TonemapNode.cc b/source/blender/compositor/nodes/COM_TonemapNode.cc index db329e56f9b..844fe3e8cb6 100644 --- a/source/blender/compositor/nodes/COM_TonemapNode.cc +++ b/source/blender/compositor/nodes/COM_TonemapNode.cc @@ -20,6 +20,8 @@ #include "COM_ExecutionSystem.h" #include "COM_TonemapOperation.h" +namespace blender::compositor { + TonemapNode::TonemapNode(bNode *editorNode) : Node(editorNode) { /* pass */ @@ -38,3 +40,5 @@ void TonemapNode::convertToOperations(NodeConverter &converter, converter.mapInputSocket(getInputSocket(0), operation->getInputSocket(0)); converter.mapOutputSocket(getOutputSocket(0), operation->getOutputSocket(0)); } + +} // namespace blender::compositor diff --git a/source/blender/compositor/nodes/COM_TonemapNode.h b/source/blender/compositor/nodes/COM_TonemapNode.h index d934a1ede5b..cac9004c32a 100644 --- a/source/blender/compositor/nodes/COM_TonemapNode.h +++ b/source/blender/compositor/nodes/COM_TonemapNode.h @@ -20,6 +20,8 @@ #include "COM_Node.h" +namespace blender::compositor { + /** * \brief TonemapNode * \ingroup Node @@ -27,5 +29,8 @@ class TonemapNode : public Node { public: TonemapNode(bNode *editorNode); - void convertToOperations(NodeConverter &converter, const CompositorContext &context) const; + void convertToOperations(NodeConverter &converter, + const CompositorContext &context) const override; }; + +} // namespace blender::compositor diff --git a/source/blender/compositor/nodes/COM_TrackPositionNode.cc b/source/blender/compositor/nodes/COM_TrackPositionNode.cc index 52e7f7d832b..3fb5fc02f20 100644 --- a/source/blender/compositor/nodes/COM_TrackPositionNode.cc +++ b/source/blender/compositor/nodes/COM_TrackPositionNode.cc @@ -26,6 +26,8 @@ #include "BKE_node.h" +namespace blender::compositor { + TrackPositionNode::TrackPositionNode(bNode *editorNode) : Node(editorNode) { /* pass */ @@ -109,3 +111,5 @@ void TrackPositionNode::convertToOperations(NodeConverter &converter, converter.addLink(operationMotionPostY->getOutputSocket(), combine_operation->getInputSocket(3)); converter.mapOutputSocket(outputSpeed, combine_operation->getOutputSocket()); } + +} // namespace blender::compositor diff --git a/source/blender/compositor/nodes/COM_TrackPositionNode.h b/source/blender/compositor/nodes/COM_TrackPositionNode.h index 37d3d25d592..665ba36fe09 100644 --- a/source/blender/compositor/nodes/COM_TrackPositionNode.h +++ b/source/blender/compositor/nodes/COM_TrackPositionNode.h @@ -21,6 +21,8 @@ #include "COM_Node.h" #include "DNA_node_types.h" +namespace blender::compositor { + /** * \brief TrackPositionNode * \ingroup Node @@ -28,5 +30,8 @@ class TrackPositionNode : public Node { public: TrackPositionNode(bNode *editorNode); - void convertToOperations(NodeConverter &converter, const CompositorContext &context) const; + void convertToOperations(NodeConverter &converter, + const CompositorContext &context) const override; }; + +} // namespace blender::compositor diff --git a/source/blender/compositor/nodes/COM_TransformNode.cc b/source/blender/compositor/nodes/COM_TransformNode.cc index cd5ba8ba201..cd12939ab43 100644 --- a/source/blender/compositor/nodes/COM_TransformNode.cc +++ b/source/blender/compositor/nodes/COM_TransformNode.cc @@ -24,6 +24,8 @@ #include "COM_SetValueOperation.h" #include "COM_TranslateOperation.h" +namespace blender::compositor { + TransformNode::TransformNode(bNode *editorNode) : Node(editorNode) { /* pass */ @@ -66,3 +68,5 @@ void TransformNode::convertToOperations(NodeConverter &converter, converter.mapOutputSocket(getOutputSocket(), translateOperation->getOutputSocket()); } + +} // namespace blender::compositor diff --git a/source/blender/compositor/nodes/COM_TransformNode.h b/source/blender/compositor/nodes/COM_TransformNode.h index bd01808d662..137e162256d 100644 --- a/source/blender/compositor/nodes/COM_TransformNode.h +++ b/source/blender/compositor/nodes/COM_TransformNode.h @@ -21,6 +21,8 @@ #include "COM_Node.h" #include "DNA_node_types.h" +namespace blender::compositor { + /** * \brief TransformNode * \ingroup Node @@ -28,5 +30,8 @@ class TransformNode : public Node { public: TransformNode(bNode *editorNode); - void convertToOperations(NodeConverter &converter, const CompositorContext &context) const; + void convertToOperations(NodeConverter &converter, + const CompositorContext &context) const override; }; + +} // namespace blender::compositor diff --git a/source/blender/compositor/nodes/COM_TranslateNode.cc b/source/blender/compositor/nodes/COM_TranslateNode.cc index 13a73953ea0..922393f006a 100644 --- a/source/blender/compositor/nodes/COM_TranslateNode.cc +++ b/source/blender/compositor/nodes/COM_TranslateNode.cc @@ -23,6 +23,8 @@ #include "COM_WrapOperation.h" #include "COM_WriteBufferOperation.h" +namespace blender::compositor { + TranslateNode::TranslateNode(bNode *editorNode) : Node(editorNode) { /* pass */ @@ -69,3 +71,5 @@ void TranslateNode::convertToOperations(NodeConverter &converter, converter.mapInputSocket(inputSocket, operation->getInputSocket(0)); } } + +} // namespace blender::compositor diff --git a/source/blender/compositor/nodes/COM_TranslateNode.h b/source/blender/compositor/nodes/COM_TranslateNode.h index d381274c0e5..0cea234bff8 100644 --- a/source/blender/compositor/nodes/COM_TranslateNode.h +++ b/source/blender/compositor/nodes/COM_TranslateNode.h @@ -20,6 +20,8 @@ #include "COM_Node.h" +namespace blender::compositor { + /** * \brief TranslateNode * \ingroup Node @@ -27,5 +29,8 @@ class TranslateNode : public Node { public: TranslateNode(bNode *editorNode); - void convertToOperations(NodeConverter &converter, const CompositorContext &context) const; + void convertToOperations(NodeConverter &converter, + const CompositorContext &context) const override; }; + +} // namespace blender::compositor diff --git a/source/blender/compositor/nodes/COM_ValueNode.cc b/source/blender/compositor/nodes/COM_ValueNode.cc index 4227db0d10e..6b640fa2a3a 100644 --- a/source/blender/compositor/nodes/COM_ValueNode.cc +++ b/source/blender/compositor/nodes/COM_ValueNode.cc @@ -20,6 +20,8 @@ #include "COM_ExecutionSystem.h" #include "COM_SetValueOperation.h" +namespace blender::compositor { + ValueNode::ValueNode(bNode *editorNode) : Node(editorNode) { /* pass */ @@ -35,3 +37,5 @@ void ValueNode::convertToOperations(NodeConverter &converter, converter.mapOutputSocket(output, operation->getOutputSocket()); } + +} // namespace blender::compositor diff --git a/source/blender/compositor/nodes/COM_ValueNode.h b/source/blender/compositor/nodes/COM_ValueNode.h index 5179e6828e4..1401b2c7e0a 100644 --- a/source/blender/compositor/nodes/COM_ValueNode.h +++ b/source/blender/compositor/nodes/COM_ValueNode.h @@ -20,6 +20,8 @@ #include "COM_Node.h" +namespace blender::compositor { + /** * \brief ValueNode * \ingroup Node @@ -27,5 +29,8 @@ class ValueNode : public Node { public: ValueNode(bNode *editorNode); - void convertToOperations(NodeConverter &converter, const CompositorContext &context) const; + void convertToOperations(NodeConverter &converter, + const CompositorContext &context) const override; }; + +} // namespace blender::compositor diff --git a/source/blender/compositor/nodes/COM_VectorBlurNode.cc b/source/blender/compositor/nodes/COM_VectorBlurNode.cc index a92991c8b49..7aa5f5668c9 100644 --- a/source/blender/compositor/nodes/COM_VectorBlurNode.cc +++ b/source/blender/compositor/nodes/COM_VectorBlurNode.cc @@ -20,6 +20,8 @@ #include "COM_VectorBlurOperation.h" #include "DNA_node_types.h" +namespace blender::compositor { + VectorBlurNode::VectorBlurNode(bNode *editorNode) : Node(editorNode) { /* pass */ @@ -41,3 +43,5 @@ void VectorBlurNode::convertToOperations(NodeConverter &converter, converter.mapInputSocket(getInputSocket(2), operation->getInputSocket(2)); converter.mapOutputSocket(getOutputSocket(), operation->getOutputSocket()); } + +} // namespace blender::compositor diff --git a/source/blender/compositor/nodes/COM_VectorBlurNode.h b/source/blender/compositor/nodes/COM_VectorBlurNode.h index f370c82a1ee..8c98a0b81a1 100644 --- a/source/blender/compositor/nodes/COM_VectorBlurNode.h +++ b/source/blender/compositor/nodes/COM_VectorBlurNode.h @@ -20,6 +20,8 @@ #include "COM_Node.h" +namespace blender::compositor { + /** * \brief VectorBlurNode * \ingroup Node @@ -27,5 +29,8 @@ class VectorBlurNode : public Node { public: VectorBlurNode(bNode *editorNode); - void convertToOperations(NodeConverter &converter, const CompositorContext &context) const; + void convertToOperations(NodeConverter &converter, + const CompositorContext &context) const override; }; + +} // namespace blender::compositor diff --git a/source/blender/compositor/nodes/COM_VectorCurveNode.cc b/source/blender/compositor/nodes/COM_VectorCurveNode.cc index 1201a9f9613..f2fd80cd93e 100644 --- a/source/blender/compositor/nodes/COM_VectorCurveNode.cc +++ b/source/blender/compositor/nodes/COM_VectorCurveNode.cc @@ -20,6 +20,8 @@ #include "COM_ExecutionSystem.h" #include "COM_VectorCurveOperation.h" +namespace blender::compositor { + VectorCurveNode::VectorCurveNode(bNode *editorNode) : Node(editorNode) { /* pass */ @@ -35,3 +37,5 @@ void VectorCurveNode::convertToOperations(NodeConverter &converter, converter.mapInputSocket(getInputSocket(0), operation->getInputSocket(0)); converter.mapOutputSocket(getOutputSocket(0), operation->getOutputSocket()); } + +} // namespace blender::compositor diff --git a/source/blender/compositor/nodes/COM_VectorCurveNode.h b/source/blender/compositor/nodes/COM_VectorCurveNode.h index 4d7f92897a1..ee4df5d3a42 100644 --- a/source/blender/compositor/nodes/COM_VectorCurveNode.h +++ b/source/blender/compositor/nodes/COM_VectorCurveNode.h @@ -20,6 +20,8 @@ #include "COM_Node.h" +namespace blender::compositor { + /** * \brief VectorCurveNode * \ingroup Node @@ -27,5 +29,8 @@ class VectorCurveNode : public Node { public: VectorCurveNode(bNode *editorNode); - void convertToOperations(NodeConverter &converter, const CompositorContext &context) const; + void convertToOperations(NodeConverter &converter, + const CompositorContext &context) const override; }; + +} // namespace blender::compositor diff --git a/source/blender/compositor/nodes/COM_ViewLevelsNode.cc b/source/blender/compositor/nodes/COM_ViewLevelsNode.cc index 7b86fb1d64d..dc454b95080 100644 --- a/source/blender/compositor/nodes/COM_ViewLevelsNode.cc +++ b/source/blender/compositor/nodes/COM_ViewLevelsNode.cc @@ -22,6 +22,8 @@ #include "COM_ExecutionSystem.h" #include "COM_SetValueOperation.h" +namespace blender::compositor { + ViewLevelsNode::ViewLevelsNode(bNode *editorNode) : Node(editorNode) { /* pass */ @@ -59,3 +61,5 @@ void ViewLevelsNode::convertToOperations(NodeConverter &converter, converter.addOutputValue(getOutputSocket(1), 0.0f); } } + +} // namespace blender::compositor diff --git a/source/blender/compositor/nodes/COM_ViewLevelsNode.h b/source/blender/compositor/nodes/COM_ViewLevelsNode.h index 0e931fed055..055d871498e 100644 --- a/source/blender/compositor/nodes/COM_ViewLevelsNode.h +++ b/source/blender/compositor/nodes/COM_ViewLevelsNode.h @@ -20,6 +20,8 @@ #include "COM_Node.h" +namespace blender::compositor { + /** * \brief ViewLevelsNode * \ingroup Node @@ -27,5 +29,8 @@ class ViewLevelsNode : public Node { public: ViewLevelsNode(bNode *editorNode); - void convertToOperations(NodeConverter &converter, const CompositorContext &context) const; + void convertToOperations(NodeConverter &converter, + const CompositorContext &context) const override; }; + +} // namespace blender::compositor diff --git a/source/blender/compositor/nodes/COM_ViewerNode.cc b/source/blender/compositor/nodes/COM_ViewerNode.cc index 359c3d3031d..3833a8d7ca8 100644 --- a/source/blender/compositor/nodes/COM_ViewerNode.cc +++ b/source/blender/compositor/nodes/COM_ViewerNode.cc @@ -25,6 +25,8 @@ #include "COM_ExecutionSystem.h" #include "COM_ViewerOperation.h" +namespace blender::compositor { + ViewerNode::ViewerNode(bNode *editorNode) : Node(editorNode) { /* pass */ @@ -82,3 +84,5 @@ void ViewerNode::convertToOperations(NodeConverter &converter, converter.registerViewer(viewerOperation); } } + +} // namespace blender::compositor diff --git a/source/blender/compositor/nodes/COM_ViewerNode.h b/source/blender/compositor/nodes/COM_ViewerNode.h index 74758417014..544a5e6a504 100644 --- a/source/blender/compositor/nodes/COM_ViewerNode.h +++ b/source/blender/compositor/nodes/COM_ViewerNode.h @@ -20,6 +20,9 @@ #include "COM_Node.h" #include "DNA_node_types.h" + +namespace blender::compositor { + /** * \brief ViewerNode * \ingroup Node @@ -27,5 +30,8 @@ class ViewerNode : public Node { public: ViewerNode(bNode *editorNode); - void convertToOperations(NodeConverter &converter, const CompositorContext &context) const; + void convertToOperations(NodeConverter &converter, + const CompositorContext &context) const override; }; + +} // namespace blender::compositor diff --git a/source/blender/compositor/nodes/COM_ZCombineNode.cc b/source/blender/compositor/nodes/COM_ZCombineNode.cc index b61c018d029..a76049ff249 100644 --- a/source/blender/compositor/nodes/COM_ZCombineNode.cc +++ b/source/blender/compositor/nodes/COM_ZCombineNode.cc @@ -28,6 +28,8 @@ #include "DNA_material_types.h" /* the ramp types */ +namespace blender::compositor { + void ZCombineNode::convertToOperations(NodeConverter &converter, const CompositorContext &context) const { @@ -99,3 +101,5 @@ void ZCombineNode::convertToOperations(NodeConverter &converter, converter.mapOutputSocket(getOutputSocket(1), zoperation->getOutputSocket()); } } + +} // namespace blender::compositor diff --git a/source/blender/compositor/nodes/COM_ZCombineNode.h b/source/blender/compositor/nodes/COM_ZCombineNode.h index ca54fd7fffa..82f2f30fb3c 100644 --- a/source/blender/compositor/nodes/COM_ZCombineNode.h +++ b/source/blender/compositor/nodes/COM_ZCombineNode.h @@ -20,6 +20,8 @@ #include "COM_Node.h" +namespace blender::compositor { + /** * \brief ZCombineNode * \ingroup Node @@ -29,5 +31,8 @@ class ZCombineNode : public Node { ZCombineNode(bNode *editorNode) : Node(editorNode) { } - void convertToOperations(NodeConverter &converter, const CompositorContext &context) const; + void convertToOperations(NodeConverter &converter, + const CompositorContext &context) const override; }; + +} // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_AlphaOverKeyOperation.cc b/source/blender/compositor/operations/COM_AlphaOverKeyOperation.cc index 668d07c7c3d..34638cbe7d6 100644 --- a/source/blender/compositor/operations/COM_AlphaOverKeyOperation.cc +++ b/source/blender/compositor/operations/COM_AlphaOverKeyOperation.cc @@ -18,6 +18,8 @@ #include "COM_AlphaOverKeyOperation.h" +namespace blender::compositor { + AlphaOverKeyOperation::AlphaOverKeyOperation() { /* pass */ @@ -52,3 +54,5 @@ void AlphaOverKeyOperation::executePixelSampled(float output[4], output[3] = (mul * inputColor1[3]) + value[0] * inputOverColor[3]; } } + +} // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_AlphaOverKeyOperation.h b/source/blender/compositor/operations/COM_AlphaOverKeyOperation.h index f2ec5ff12c2..8b8debefa7a 100644 --- a/source/blender/compositor/operations/COM_AlphaOverKeyOperation.h +++ b/source/blender/compositor/operations/COM_AlphaOverKeyOperation.h @@ -20,6 +20,8 @@ #include "COM_MixOperation.h" +namespace blender::compositor { + /** * this program converts an input color to an output value. * it assumes we are in sRGB color space. @@ -34,5 +36,7 @@ class AlphaOverKeyOperation : public MixBaseOperation { /** * The inner loop of this operation. */ - void executePixelSampled(float output[4], float x, float y, PixelSampler sampler); + void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; }; + +} // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_AlphaOverMixedOperation.cc b/source/blender/compositor/operations/COM_AlphaOverMixedOperation.cc index b8465ab7ccf..c68c79d2263 100644 --- a/source/blender/compositor/operations/COM_AlphaOverMixedOperation.cc +++ b/source/blender/compositor/operations/COM_AlphaOverMixedOperation.cc @@ -18,6 +18,8 @@ #include "COM_AlphaOverMixedOperation.h" +namespace blender::compositor { + AlphaOverMixedOperation::AlphaOverMixedOperation() { this->m_x = 0.0f; @@ -53,3 +55,5 @@ void AlphaOverMixedOperation::executePixelSampled(float output[4], output[3] = (mul * inputColor1[3]) + value[0] * inputOverColor[3]; } } + +} // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_AlphaOverMixedOperation.h b/source/blender/compositor/operations/COM_AlphaOverMixedOperation.h index 73433ec3077..e2b3af84162 100644 --- a/source/blender/compositor/operations/COM_AlphaOverMixedOperation.h +++ b/source/blender/compositor/operations/COM_AlphaOverMixedOperation.h @@ -20,6 +20,8 @@ #include "COM_MixOperation.h" +namespace blender::compositor { + /** * this program converts an input color to an output value. * it assumes we are in sRGB color space. @@ -37,10 +39,12 @@ class AlphaOverMixedOperation : public MixBaseOperation { /** * The inner loop of this operation. */ - void executePixelSampled(float output[4], float x, float y, PixelSampler sampler); + void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; void setX(float x) { this->m_x = x; } }; + +} // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_AlphaOverPremultiplyOperation.cc b/source/blender/compositor/operations/COM_AlphaOverPremultiplyOperation.cc index 4510c027d46..edb248d16e8 100644 --- a/source/blender/compositor/operations/COM_AlphaOverPremultiplyOperation.cc +++ b/source/blender/compositor/operations/COM_AlphaOverPremultiplyOperation.cc @@ -18,6 +18,8 @@ #include "COM_AlphaOverPremultiplyOperation.h" +namespace blender::compositor { + AlphaOverPremultiplyOperation::AlphaOverPremultiplyOperation() { /* pass */ @@ -52,3 +54,5 @@ void AlphaOverPremultiplyOperation::executePixelSampled(float output[4], output[3] = (mul * inputColor1[3]) + value[0] * inputOverColor[3]; } } + +} // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_AlphaOverPremultiplyOperation.h b/source/blender/compositor/operations/COM_AlphaOverPremultiplyOperation.h index b149789878e..16246231a57 100644 --- a/source/blender/compositor/operations/COM_AlphaOverPremultiplyOperation.h +++ b/source/blender/compositor/operations/COM_AlphaOverPremultiplyOperation.h @@ -20,6 +20,8 @@ #include "COM_MixOperation.h" +namespace blender::compositor { + /** * this program converts an input color to an output value. * it assumes we are in sRGB color space. @@ -34,5 +36,7 @@ class AlphaOverPremultiplyOperation : public MixBaseOperation { /** * The inner loop of this operation. */ - void executePixelSampled(float output[4], float x, float y, PixelSampler sampler); + void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; }; + +} // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_AntiAliasOperation.cc b/source/blender/compositor/operations/COM_AntiAliasOperation.cc index 740cd3ff609..23d6f4b80c7 100644 --- a/source/blender/compositor/operations/COM_AntiAliasOperation.cc +++ b/source/blender/compositor/operations/COM_AntiAliasOperation.cc @@ -24,6 +24,8 @@ #include "RE_texture.h" +namespace blender::compositor { + /* An implementation of the Scale3X edge-extrapolation algorithm. * * Code from GIMP plugin, based on code from Adam D. Moss <adam@gimp.org> @@ -117,7 +119,7 @@ AntiAliasOperation::AntiAliasOperation() this->addInputSocket(DataType::Value); this->addOutputSocket(DataType::Value); this->m_valueReader = nullptr; - this->setComplex(true); + this->flags.complex = true; } void AntiAliasOperation::initExecution() @@ -199,3 +201,5 @@ void *AntiAliasOperation::initializeTileData(rcti *rect) { return getInputOperation(0)->initializeTileData(rect); } + +} // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_AntiAliasOperation.h b/source/blender/compositor/operations/COM_AntiAliasOperation.h index 571655813ae..fc9102b5b4c 100644 --- a/source/blender/compositor/operations/COM_AntiAliasOperation.h +++ b/source/blender/compositor/operations/COM_AntiAliasOperation.h @@ -21,6 +21,8 @@ #include "COM_NodeOperation.h" #include "DNA_node_types.h" +namespace blender::compositor { + /** * \brief AntiAlias operations * it only supports anti aliasing on BW buffers. @@ -39,20 +41,22 @@ class AntiAliasOperation : public NodeOperation { /** * The inner loop of this operation. */ - void executePixel(float output[4], int x, int y, void *data); + void executePixel(float output[4], int x, int y, void *data) override; /** * Initialize the execution */ - void initExecution(); + void initExecution() override; - void *initializeTileData(rcti *rect); + void *initializeTileData(rcti *rect) override; /** * Deinitialize the execution */ - void deinitExecution(); + void deinitExecution() override; bool determineDependingAreaOfInterest(rcti *input, ReadBufferOperation *readOperation, - rcti *output); + rcti *output) override; }; + +} // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_BilateralBlurOperation.cc b/source/blender/compositor/operations/COM_BilateralBlurOperation.cc index d04fade2e93..64448e2ae95 100644 --- a/source/blender/compositor/operations/COM_BilateralBlurOperation.cc +++ b/source/blender/compositor/operations/COM_BilateralBlurOperation.cc @@ -21,12 +21,14 @@ #include "RE_pipeline.h" +namespace blender::compositor { + BilateralBlurOperation::BilateralBlurOperation() { this->addInputSocket(DataType::Color); this->addInputSocket(DataType::Color); this->addOutputSocket(DataType::Color); - this->setComplex(true); + this->flags.complex = true; this->m_inputColorProgram = nullptr; this->m_inputDeterminatorProgram = nullptr; @@ -112,3 +114,5 @@ bool BilateralBlurOperation::determineDependingAreaOfInterest(rcti *input, return NodeOperation::determineDependingAreaOfInterest(&newInput, readOperation, output); } + +} // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_BilateralBlurOperation.h b/source/blender/compositor/operations/COM_BilateralBlurOperation.h index d059510f0bc..c56cef35050 100644 --- a/source/blender/compositor/operations/COM_BilateralBlurOperation.h +++ b/source/blender/compositor/operations/COM_BilateralBlurOperation.h @@ -21,6 +21,8 @@ #include "COM_NodeOperation.h" #include "COM_QualityStepHelper.h" +namespace blender::compositor { + class BilateralBlurOperation : public NodeOperation, public QualityStepHelper { private: SocketReader *m_inputColorProgram; @@ -34,24 +36,26 @@ class BilateralBlurOperation : public NodeOperation, public QualityStepHelper { /** * The inner loop of this operation. */ - void executePixel(float output[4], int x, int y, void *data); + void executePixel(float output[4], int x, int y, void *data) override; /** * Initialize the execution */ - void initExecution(); + void initExecution() override; /** * Deinitialize the execution */ - void deinitExecution(); + void deinitExecution() override; bool determineDependingAreaOfInterest(rcti *input, ReadBufferOperation *readOperation, - rcti *output); + rcti *output) override; void setData(NodeBilateralBlurData *data) { this->m_data = data; } }; + +} // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_BlurBaseOperation.cc b/source/blender/compositor/operations/COM_BlurBaseOperation.cc index fe6ca1cfd4e..8b73624ca79 100644 --- a/source/blender/compositor/operations/COM_BlurBaseOperation.cc +++ b/source/blender/compositor/operations/COM_BlurBaseOperation.cc @@ -22,13 +22,15 @@ #include "RE_pipeline.h" +namespace blender::compositor { + BlurBaseOperation::BlurBaseOperation(DataType data_type) { /* data_type is almost always DataType::Color except for alpha-blur */ this->addInputSocket(data_type); this->addInputSocket(DataType::Value); this->addOutputSocket(data_type); - this->setComplex(true); + this->flags.complex = true; this->m_inputProgram = nullptr; memset(&m_data, 0, sizeof(NodeBlurData)); this->m_size = 1.0f; @@ -167,7 +169,7 @@ void BlurBaseOperation::updateSize() { if (!this->m_sizeavailable) { float result[4]; - this->getInputSocketReader(1)->readSampled(result, 0, 0, COM_PS_NEAREST); + this->getInputSocketReader(1)->readSampled(result, 0, 0, PixelSampler::Nearest); this->m_size = result[0]; this->m_sizeavailable = true; } @@ -182,3 +184,5 @@ void BlurBaseOperation::determineResolution(unsigned int resolution[2], resolution[1] += 2 * this->m_size * m_data.sizey; } } + +} // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_BlurBaseOperation.h b/source/blender/compositor/operations/COM_BlurBaseOperation.h index 56dacc96710..7937ebd69dc 100644 --- a/source/blender/compositor/operations/COM_BlurBaseOperation.h +++ b/source/blender/compositor/operations/COM_BlurBaseOperation.h @@ -25,6 +25,8 @@ #include "BLI_simd.h" +namespace blender::compositor { + class BlurBaseOperation : public NodeOperation, public QualityStepHelper { private: protected: @@ -53,12 +55,12 @@ class BlurBaseOperation : public NodeOperation, public QualityStepHelper { /** * Initialize the execution */ - void initExecution(); + void initExecution() override; /** * Deinitialize the execution */ - void deinitExecution(); + void deinitExecution() override; void setData(const NodeBlurData *data); @@ -73,5 +75,8 @@ class BlurBaseOperation : public NodeOperation, public QualityStepHelper { this->m_extend_bounds = extend_bounds; } - void determineResolution(unsigned int resolution[2], unsigned int preferredResolution[2]); + void determineResolution(unsigned int resolution[2], + unsigned int preferredResolution[2]) override; }; + +} // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_BokehBlurOperation.cc b/source/blender/compositor/operations/COM_BokehBlurOperation.cc index 7bb8cd49bfc..3f98732b403 100644 --- a/source/blender/compositor/operations/COM_BokehBlurOperation.cc +++ b/source/blender/compositor/operations/COM_BokehBlurOperation.cc @@ -22,15 +22,18 @@ #include "RE_pipeline.h" +namespace blender::compositor { + BokehBlurOperation::BokehBlurOperation() { this->addInputSocket(DataType::Color); - this->addInputSocket(DataType::Color, COM_SC_NO_RESIZE); + this->addInputSocket(DataType::Color, ResizeMode::None); this->addInputSocket(DataType::Value); this->addInputSocket(DataType::Value); this->addOutputSocket(DataType::Color); - this->setComplex(true); - this->setOpenCL(true); + + flags.complex = true; + flags.open_cl = true; this->m_size = 1.0f; this->m_sizeavailable = false; @@ -76,7 +79,7 @@ void BokehBlurOperation::executePixel(float output[4], int x, int y, void *data) float tempBoundingBox[4]; float bokeh[4]; - this->m_inputBoundingBoxReader->readSampled(tempBoundingBox, x, y, COM_PS_NEAREST); + this->m_inputBoundingBoxReader->readSampled(tempBoundingBox, x, y, PixelSampler::Nearest); if (tempBoundingBox[0] > 0.0f) { float multiplier_accum[4] = {0.0f, 0.0f, 0.0f, 0.0f}; MemoryBuffer *inputBuffer = (MemoryBuffer *)data; @@ -90,7 +93,7 @@ void BokehBlurOperation::executePixel(float output[4], int x, int y, void *data) zero_v4(color_accum); if (pixelSize < 2) { - this->m_inputProgram->readSampled(color_accum, x, y, COM_PS_NEAREST); + this->m_inputProgram->readSampled(color_accum, x, y, PixelSampler::Nearest); multiplier_accum[0] = 1.0f; multiplier_accum[1] = 1.0f; multiplier_accum[2] = 1.0f; @@ -106,16 +109,16 @@ void BokehBlurOperation::executePixel(float output[4], int x, int y, void *data) maxx = MIN2(maxx, input_rect.xmax); int step = getStep(); - int offsetadd = getOffsetAdd() * COM_NUM_CHANNELS_COLOR; + int offsetadd = getOffsetAdd() * COM_DATA_TYPE_COLOR_CHANNELS; float m = this->m_bokehDimension / pixelSize; for (int ny = miny; ny < maxy; ny += step) { - int bufferindex = ((minx - bufferstartx) * COM_NUM_CHANNELS_COLOR) + - ((ny - bufferstarty) * COM_NUM_CHANNELS_COLOR * bufferwidth); + int bufferindex = ((minx - bufferstartx) * COM_DATA_TYPE_COLOR_CHANNELS) + + ((ny - bufferstarty) * COM_DATA_TYPE_COLOR_CHANNELS * bufferwidth); for (int nx = minx; nx < maxx; nx += step) { float u = this->m_bokehMidX - (nx - x) * m; float v = this->m_bokehMidY - (ny - y) * m; - this->m_inputBokehProgram->readSampled(bokeh, u, v, COM_PS_NEAREST); + this->m_inputBokehProgram->readSampled(bokeh, u, v, PixelSampler::Nearest); madd_v4_v4v4(color_accum, bokeh, &buffer[bufferindex]); add_v4_v4(multiplier_accum, bokeh); bufferindex += offsetadd; @@ -127,7 +130,7 @@ void BokehBlurOperation::executePixel(float output[4], int x, int y, void *data) output[3] = color_accum[3] * (1.0f / multiplier_accum[3]); } else { - this->m_inputProgram->readSampled(output, x, y, COM_PS_NEAREST); + this->m_inputProgram->readSampled(output, x, y, PixelSampler::Nearest); } } @@ -224,7 +227,7 @@ void BokehBlurOperation::updateSize() { if (!this->m_sizeavailable) { float result[4]; - this->getInputSocketReader(3)->readSampled(result, 0, 0, COM_PS_NEAREST); + this->getInputSocketReader(3)->readSampled(result, 0, 0, PixelSampler::Nearest); this->m_size = result[0]; CLAMP(this->m_size, 0.0f, 10.0f); this->m_sizeavailable = true; @@ -241,3 +244,5 @@ void BokehBlurOperation::determineResolution(unsigned int resolution[2], resolution[1] += 2 * this->m_size * max_dim / 100.0f; } } + +} // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_BokehBlurOperation.h b/source/blender/compositor/operations/COM_BokehBlurOperation.h index a2e320dfdad..3ce06adb5d6 100644 --- a/source/blender/compositor/operations/COM_BokehBlurOperation.h +++ b/source/blender/compositor/operations/COM_BokehBlurOperation.h @@ -21,6 +21,8 @@ #include "COM_NodeOperation.h" #include "COM_QualityStepHelper.h" +namespace blender::compositor { + class BokehBlurOperation : public NodeOperation, public QualityStepHelper { private: SocketReader *m_inputProgram; @@ -37,25 +39,25 @@ class BokehBlurOperation : public NodeOperation, public QualityStepHelper { public: BokehBlurOperation(); - void *initializeTileData(rcti *rect); + void *initializeTileData(rcti *rect) override; /** * The inner loop of this operation. */ - void executePixel(float output[4], int x, int y, void *data); + void executePixel(float output[4], int x, int y, void *data) override; /** * Initialize the execution */ - void initExecution(); + void initExecution() override; /** * Deinitialize the execution */ - void deinitExecution(); + void deinitExecution() override; bool determineDependingAreaOfInterest(rcti *input, ReadBufferOperation *readOperation, - rcti *output); + rcti *output) override; void setSize(float size) { @@ -68,12 +70,15 @@ class BokehBlurOperation : public NodeOperation, public QualityStepHelper { cl_mem clOutputBuffer, MemoryBuffer **inputMemoryBuffers, std::list<cl_mem> *clMemToCleanUp, - std::list<cl_kernel> *clKernelsToCleanUp); + std::list<cl_kernel> *clKernelsToCleanUp) override; void setExtendBounds(bool extend_bounds) { this->m_extend_bounds = extend_bounds; } - void determineResolution(unsigned int resolution[2], unsigned int preferredResolution[2]); + void determineResolution(unsigned int resolution[2], + unsigned int preferredResolution[2]) override; }; + +} // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_BokehImageOperation.cc b/source/blender/compositor/operations/COM_BokehImageOperation.cc index 01f8c81b3b7..63f283b6acc 100644 --- a/source/blender/compositor/operations/COM_BokehImageOperation.cc +++ b/source/blender/compositor/operations/COM_BokehImageOperation.cc @@ -19,6 +19,8 @@ #include "COM_BokehImageOperation.h" #include "BLI_math.h" +namespace blender::compositor { + BokehImageOperation::BokehImageOperation() { this->addOutputSocket(DataType::Color); @@ -124,3 +126,5 @@ void BokehImageOperation::determineResolution(unsigned int resolution[2], resolution[0] = COM_BLUR_BOKEH_PIXELS; resolution[1] = COM_BLUR_BOKEH_PIXELS; } + +} // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_BokehImageOperation.h b/source/blender/compositor/operations/COM_BokehImageOperation.h index 2d775bdf738..2e0bc8a34dc 100644 --- a/source/blender/compositor/operations/COM_BokehImageOperation.h +++ b/source/blender/compositor/operations/COM_BokehImageOperation.h @@ -20,6 +20,8 @@ #include "COM_NodeOperation.h" +namespace blender::compositor { + /** * \brief The BokehImageOperation class is an operation that creates an image useful to mimic the *internals of a camera. @@ -110,23 +112,24 @@ class BokehImageOperation : public NodeOperation { /** * \brief The inner loop of this operation. */ - void executePixelSampled(float output[4], float x, float y, PixelSampler sampler); + void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; /** * \brief Initialize the execution */ - void initExecution(); + void initExecution() override; /** * \brief Deinitialize the execution */ - void deinitExecution(); + void deinitExecution() override; /** * \brief determine the resolution of this operation. currently fixed at [COM_BLUR_BOKEH_PIXELS, * COM_BLUR_BOKEH_PIXELS] \param resolution: \param preferredResolution: */ - void determineResolution(unsigned int resolution[2], unsigned int preferredResolution[2]); + void determineResolution(unsigned int resolution[2], + unsigned int preferredResolution[2]) override; /** * \brief set the node data @@ -149,3 +152,5 @@ class BokehImageOperation : public NodeOperation { this->m_deleteData = true; } }; + +} // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_BoxMaskOperation.cc b/source/blender/compositor/operations/COM_BoxMaskOperation.cc index 51b1ea98456..9938d4a85ed 100644 --- a/source/blender/compositor/operations/COM_BoxMaskOperation.cc +++ b/source/blender/compositor/operations/COM_BoxMaskOperation.cc @@ -20,6 +20,8 @@ #include "BLI_math.h" #include "DNA_node_types.h" +namespace blender::compositor { + BoxMaskOperation::BoxMaskOperation() { this->addInputSocket(DataType::Value); @@ -108,3 +110,5 @@ void BoxMaskOperation::deinitExecution() this->m_inputMask = nullptr; this->m_inputValue = nullptr; } + +} // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_BoxMaskOperation.h b/source/blender/compositor/operations/COM_BoxMaskOperation.h index c98972b82b7..fdec7bdd8ca 100644 --- a/source/blender/compositor/operations/COM_BoxMaskOperation.h +++ b/source/blender/compositor/operations/COM_BoxMaskOperation.h @@ -20,6 +20,8 @@ #include "COM_NodeOperation.h" +namespace blender::compositor { + class BoxMaskOperation : public NodeOperation { private: /** @@ -41,17 +43,17 @@ class BoxMaskOperation : public NodeOperation { /** * The inner loop of this operation. */ - void executePixelSampled(float output[4], float x, float y, PixelSampler sampler); + void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; /** * Initialize the execution */ - void initExecution(); + void initExecution() override; /** * Deinitialize the execution */ - void deinitExecution(); + void deinitExecution() override; void setData(NodeBoxMask *data) { @@ -63,3 +65,5 @@ class BoxMaskOperation : public NodeOperation { this->m_maskType = maskType; } }; + +} // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_BrightnessOperation.cc b/source/blender/compositor/operations/COM_BrightnessOperation.cc index 3a6ddd178e8..92cab47318a 100644 --- a/source/blender/compositor/operations/COM_BrightnessOperation.cc +++ b/source/blender/compositor/operations/COM_BrightnessOperation.cc @@ -18,6 +18,8 @@ #include "COM_BrightnessOperation.h" +namespace blender::compositor { + BrightnessOperation::BrightnessOperation() { this->addInputSocket(DataType::Color); @@ -89,3 +91,5 @@ void BrightnessOperation::deinitExecution() this->m_inputBrightnessProgram = nullptr; this->m_inputContrastProgram = nullptr; } + +} // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_BrightnessOperation.h b/source/blender/compositor/operations/COM_BrightnessOperation.h index 6fbcfe3a17a..7c33e0b35ec 100644 --- a/source/blender/compositor/operations/COM_BrightnessOperation.h +++ b/source/blender/compositor/operations/COM_BrightnessOperation.h @@ -20,6 +20,8 @@ #include "COM_NodeOperation.h" +namespace blender::compositor { + class BrightnessOperation : public NodeOperation { private: /** @@ -37,17 +39,19 @@ class BrightnessOperation : public NodeOperation { /** * The inner loop of this operation. */ - void executePixelSampled(float output[4], float x, float y, PixelSampler sampler); + void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; /** * Initialize the execution */ - void initExecution(); + void initExecution() override; /** * Deinitialize the execution */ - void deinitExecution(); + void deinitExecution() override; void setUsePremultiply(bool use_premultiply); }; + +} // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_CalculateMeanOperation.cc b/source/blender/compositor/operations/COM_CalculateMeanOperation.cc index fdeecd0cb29..a7ea49aed8d 100644 --- a/source/blender/compositor/operations/COM_CalculateMeanOperation.cc +++ b/source/blender/compositor/operations/COM_CalculateMeanOperation.cc @@ -22,14 +22,16 @@ #include "IMB_colormanagement.h" +namespace blender::compositor { + CalculateMeanOperation::CalculateMeanOperation() { - this->addInputSocket(DataType::Color, COM_SC_NO_RESIZE); + this->addInputSocket(DataType::Color, ResizeMode::None); this->addOutputSocket(DataType::Value); this->m_imageReader = nullptr; this->m_iscalculated = false; this->m_setting = 1; - this->setComplex(true); + this->flags.complex = true; } void CalculateMeanOperation::initExecution() { @@ -125,3 +127,5 @@ void CalculateMeanOperation::calculateMean(MemoryBuffer *tile) } this->m_result = sum / pixels; } + +} // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_CalculateMeanOperation.h b/source/blender/compositor/operations/COM_CalculateMeanOperation.h index e4937931df0..8b3bf281c93 100644 --- a/source/blender/compositor/operations/COM_CalculateMeanOperation.h +++ b/source/blender/compositor/operations/COM_CalculateMeanOperation.h @@ -21,6 +21,8 @@ #include "COM_NodeOperation.h" #include "DNA_node_types.h" +namespace blender::compositor { + /** * \brief base class of CalculateMean, implementing the simple CalculateMean * \ingroup operation @@ -42,23 +44,23 @@ class CalculateMeanOperation : public NodeOperation { /** * The inner loop of this operation. */ - void executePixel(float output[4], int x, int y, void *data); + void executePixel(float output[4], int x, int y, void *data) override; /** * Initialize the execution */ - void initExecution(); + void initExecution() override; - void *initializeTileData(rcti *rect); + void *initializeTileData(rcti *rect) override; /** * Deinitialize the execution */ - void deinitExecution(); + void deinitExecution() override; bool determineDependingAreaOfInterest(rcti *input, ReadBufferOperation *readOperation, - rcti *output); + rcti *output) override; void setSetting(int setting) { this->m_setting = setting; @@ -67,3 +69,5 @@ class CalculateMeanOperation : public NodeOperation { protected: void calculateMean(MemoryBuffer *tile); }; + +} // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_CalculateStandardDeviationOperation.cc b/source/blender/compositor/operations/COM_CalculateStandardDeviationOperation.cc index 9a1e48177ed..5ddb4b1c859 100644 --- a/source/blender/compositor/operations/COM_CalculateStandardDeviationOperation.cc +++ b/source/blender/compositor/operations/COM_CalculateStandardDeviationOperation.cc @@ -22,6 +22,8 @@ #include "IMB_colormanagement.h" +namespace blender::compositor { + CalculateStandardDeviationOperation::CalculateStandardDeviationOperation() { /* pass */ @@ -98,3 +100,5 @@ void *CalculateStandardDeviationOperation::initializeTileData(rcti *rect) unlockMutex(); return nullptr; } + +} // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_CalculateStandardDeviationOperation.h b/source/blender/compositor/operations/COM_CalculateStandardDeviationOperation.h index a267663cfc8..b8487e0aa4c 100644 --- a/source/blender/compositor/operations/COM_CalculateStandardDeviationOperation.h +++ b/source/blender/compositor/operations/COM_CalculateStandardDeviationOperation.h @@ -21,6 +21,9 @@ #include "COM_CalculateMeanOperation.h" #include "COM_NodeOperation.h" #include "DNA_node_types.h" + +namespace blender::compositor { + /** * \brief base class of CalculateStandardDeviation, * implementing the simple CalculateStandardDeviation. @@ -36,7 +39,9 @@ class CalculateStandardDeviationOperation : public CalculateMeanOperation { /** * The inner loop of this operation. */ - void executePixel(float output[4], int x, int y, void *data); + void executePixel(float output[4], int x, int y, void *data) override; - void *initializeTileData(rcti *rect); + void *initializeTileData(rcti *rect) override; }; + +} // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_ChangeHSVOperation.cc b/source/blender/compositor/operations/COM_ChangeHSVOperation.cc index e53a416f0dd..eee007ce9e6 100644 --- a/source/blender/compositor/operations/COM_ChangeHSVOperation.cc +++ b/source/blender/compositor/operations/COM_ChangeHSVOperation.cc @@ -18,6 +18,8 @@ #include "COM_ChangeHSVOperation.h" +namespace blender::compositor { + ChangeHSVOperation::ChangeHSVOperation() { this->addInputSocket(DataType::Color); @@ -68,3 +70,5 @@ void ChangeHSVOperation::executePixelSampled(float output[4], output[2] = inputColor1[2] * value[0]; output[3] = inputColor1[3]; } + +} // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_ChangeHSVOperation.h b/source/blender/compositor/operations/COM_ChangeHSVOperation.h index edc532a3f43..d38b4be3efe 100644 --- a/source/blender/compositor/operations/COM_ChangeHSVOperation.h +++ b/source/blender/compositor/operations/COM_ChangeHSVOperation.h @@ -20,6 +20,8 @@ #include "COM_MixOperation.h" +namespace blender::compositor { + /** * this program converts an input color to an output value. * it assumes we are in sRGB color space. @@ -37,11 +39,13 @@ class ChangeHSVOperation : public NodeOperation { */ ChangeHSVOperation(); - void initExecution(); - void deinitExecution(); + void initExecution() override; + void deinitExecution() override; /** * The inner loop of this operation. */ - void executePixelSampled(float output[4], float x, float y, PixelSampler sampler); + void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; }; + +} // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_ChannelMatteOperation.cc b/source/blender/compositor/operations/COM_ChannelMatteOperation.cc index 98105a9dfde..89290978608 100644 --- a/source/blender/compositor/operations/COM_ChannelMatteOperation.cc +++ b/source/blender/compositor/operations/COM_ChannelMatteOperation.cc @@ -19,6 +19,8 @@ #include "COM_ChannelMatteOperation.h" #include "BLI_math.h" +namespace blender::compositor { + ChannelMatteOperation::ChannelMatteOperation() { addInputSocket(DataType::Color); @@ -118,3 +120,5 @@ void ChannelMatteOperation::executePixelSampled(float output[4], /* Don't make something that was more transparent less transparent. */ output[0] = MIN2(alpha, inColor[3]); } + +} // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_ChannelMatteOperation.h b/source/blender/compositor/operations/COM_ChannelMatteOperation.h index 9a0b888b5a2..6e9dcccd36e 100644 --- a/source/blender/compositor/operations/COM_ChannelMatteOperation.h +++ b/source/blender/compositor/operations/COM_ChannelMatteOperation.h @@ -20,6 +20,8 @@ #include "COM_MixOperation.h" +namespace blender::compositor { + /** * this program converts an input color to an output value. * it assumes we are in sRGB color space. @@ -56,10 +58,10 @@ class ChannelMatteOperation : public NodeOperation { /** * The inner loop of this operation. */ - void executePixelSampled(float output[4], float x, float y, PixelSampler sampler); + void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; - void initExecution(); - void deinitExecution(); + void initExecution() override; + void deinitExecution() override; void setSettings(NodeChroma *nodeChroma, const int custom2) { @@ -70,3 +72,5 @@ class ChannelMatteOperation : public NodeOperation { this->m_matte_channel = custom2; } }; + +} // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_ChromaMatteOperation.cc b/source/blender/compositor/operations/COM_ChromaMatteOperation.cc index 09bf9c76e55..69aa4aac163 100644 --- a/source/blender/compositor/operations/COM_ChromaMatteOperation.cc +++ b/source/blender/compositor/operations/COM_ChromaMatteOperation.cc @@ -19,6 +19,8 @@ #include "COM_ChromaMatteOperation.h" #include "BLI_math.h" +namespace blender::compositor { + ChromaMatteOperation::ChromaMatteOperation() { addInputSocket(DataType::Color); @@ -107,3 +109,5 @@ void ChromaMatteOperation::executePixelSampled(float output[4], output[0] = inImage[3]; /* make pixel just as transparent as it was before */ } } + +} // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_ChromaMatteOperation.h b/source/blender/compositor/operations/COM_ChromaMatteOperation.h index c8d261284ed..48c3a785011 100644 --- a/source/blender/compositor/operations/COM_ChromaMatteOperation.h +++ b/source/blender/compositor/operations/COM_ChromaMatteOperation.h @@ -20,6 +20,8 @@ #include "COM_MixOperation.h" +namespace blender::compositor { + /** * this program converts an input color to an output value. * it assumes we are in sRGB color space. @@ -39,13 +41,15 @@ class ChromaMatteOperation : public NodeOperation { /** * The inner loop of this operation. */ - void executePixelSampled(float output[4], float x, float y, PixelSampler sampler); + void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; - void initExecution(); - void deinitExecution(); + void initExecution() override; + void deinitExecution() override; void setSettings(NodeChroma *nodeChroma) { this->m_settings = nodeChroma; } }; + +} // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_ColorBalanceASCCDLOperation.cc b/source/blender/compositor/operations/COM_ColorBalanceASCCDLOperation.cc index b21e453699b..d1d3752e402 100644 --- a/source/blender/compositor/operations/COM_ColorBalanceASCCDLOperation.cc +++ b/source/blender/compositor/operations/COM_ColorBalanceASCCDLOperation.cc @@ -19,6 +19,8 @@ #include "COM_ColorBalanceASCCDLOperation.h" #include "BLI_math.h" +namespace blender::compositor { + inline float colorbalance_cdl(float in, float offset, float power, float slope) { float x = in * slope + offset; @@ -79,3 +81,5 @@ void ColorBalanceASCCDLOperation::deinitExecution() this->m_inputValueOperation = nullptr; this->m_inputColorOperation = nullptr; } + +} // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_ColorBalanceASCCDLOperation.h b/source/blender/compositor/operations/COM_ColorBalanceASCCDLOperation.h index 1ec920cb2da..5851600190f 100644 --- a/source/blender/compositor/operations/COM_ColorBalanceASCCDLOperation.h +++ b/source/blender/compositor/operations/COM_ColorBalanceASCCDLOperation.h @@ -20,6 +20,8 @@ #include "COM_NodeOperation.h" +namespace blender::compositor { + /** * this program converts an input color to an output value. * it assumes we are in sRGB color space. @@ -45,17 +47,17 @@ class ColorBalanceASCCDLOperation : public NodeOperation { /** * The inner loop of this operation. */ - void executePixelSampled(float output[4], float x, float y, PixelSampler sampler); + void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; /** * Initialize the execution */ - void initExecution(); + void initExecution() override; /** * Deinitialize the execution */ - void deinitExecution(); + void deinitExecution() override; void setOffset(float offset[3]) { @@ -70,3 +72,5 @@ class ColorBalanceASCCDLOperation : public NodeOperation { copy_v3_v3(this->m_slope, slope); } }; + +} // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_ColorBalanceLGGOperation.cc b/source/blender/compositor/operations/COM_ColorBalanceLGGOperation.cc index b6ff636bce9..cac16a3f7b0 100644 --- a/source/blender/compositor/operations/COM_ColorBalanceLGGOperation.cc +++ b/source/blender/compositor/operations/COM_ColorBalanceLGGOperation.cc @@ -19,6 +19,8 @@ #include "COM_ColorBalanceLGGOperation.h" #include "BLI_math.h" +namespace blender::compositor { + inline float colorbalance_lgg(float in, float lift_lgg, float gamma_inv, float gain) { /* 1:1 match with the sequencer with linear/srgb conversions, the conversion isn't pretty @@ -84,3 +86,5 @@ void ColorBalanceLGGOperation::deinitExecution() this->m_inputValueOperation = nullptr; this->m_inputColorOperation = nullptr; } + +} // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_ColorBalanceLGGOperation.h b/source/blender/compositor/operations/COM_ColorBalanceLGGOperation.h index e6acd16e4f0..23f70247b66 100644 --- a/source/blender/compositor/operations/COM_ColorBalanceLGGOperation.h +++ b/source/blender/compositor/operations/COM_ColorBalanceLGGOperation.h @@ -20,6 +20,8 @@ #include "COM_NodeOperation.h" +namespace blender::compositor { + /** * this program converts an input color to an output value. * it assumes we are in sRGB color space. @@ -45,17 +47,17 @@ class ColorBalanceLGGOperation : public NodeOperation { /** * The inner loop of this operation. */ - void executePixelSampled(float output[4], float x, float y, PixelSampler sampler); + void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; /** * Initialize the execution */ - void initExecution(); + void initExecution() override; /** * Deinitialize the execution */ - void deinitExecution(); + void deinitExecution() override; void setGain(const float gain[3]) { @@ -70,3 +72,5 @@ class ColorBalanceLGGOperation : public NodeOperation { copy_v3_v3(this->m_gamma_inv, gamma_inv); } }; + +} // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_ColorCorrectionOperation.cc b/source/blender/compositor/operations/COM_ColorCorrectionOperation.cc index b2578451180..168e9b57eb2 100644 --- a/source/blender/compositor/operations/COM_ColorCorrectionOperation.cc +++ b/source/blender/compositor/operations/COM_ColorCorrectionOperation.cc @@ -21,6 +21,8 @@ #include "IMB_colormanagement.h" +namespace blender::compositor { + ColorCorrectionOperation::ColorCorrectionOperation() { this->addInputSocket(DataType::Color); @@ -160,3 +162,5 @@ void ColorCorrectionOperation::deinitExecution() this->m_inputImage = nullptr; this->m_inputMask = nullptr; } + +} // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_ColorCorrectionOperation.h b/source/blender/compositor/operations/COM_ColorCorrectionOperation.h index 9a2e60c0d77..c5826ed0152 100644 --- a/source/blender/compositor/operations/COM_ColorCorrectionOperation.h +++ b/source/blender/compositor/operations/COM_ColorCorrectionOperation.h @@ -20,6 +20,8 @@ #include "COM_NodeOperation.h" +namespace blender::compositor { + class ColorCorrectionOperation : public NodeOperation { private: /** @@ -39,17 +41,17 @@ class ColorCorrectionOperation : public NodeOperation { /** * The inner loop of this operation. */ - void executePixelSampled(float output[4], float x, float y, PixelSampler sampler); + void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; /** * Initialize the execution */ - void initExecution(); + void initExecution() override; /** * Deinitialize the execution */ - void deinitExecution(); + void deinitExecution() override; void setData(NodeColorCorrection *data) { @@ -68,3 +70,5 @@ class ColorCorrectionOperation : public NodeOperation { this->m_blueChannelEnabled = enabled; } }; + +} // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_ColorCurveOperation.cc b/source/blender/compositor/operations/COM_ColorCurveOperation.cc index 35218cef7cc..cb0565a81a2 100644 --- a/source/blender/compositor/operations/COM_ColorCurveOperation.cc +++ b/source/blender/compositor/operations/COM_ColorCurveOperation.cc @@ -22,6 +22,8 @@ #include "MEM_guardedalloc.h" +namespace blender::compositor { + ColorCurveOperation::ColorCurveOperation() { this->addInputSocket(DataType::Value); @@ -151,3 +153,5 @@ void ConstantLevelColorCurveOperation::deinitExecution() this->m_inputFacProgram = nullptr; this->m_inputImageProgram = nullptr; } + +} // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_ColorCurveOperation.h b/source/blender/compositor/operations/COM_ColorCurveOperation.h index 2eb20148db9..6fc7759b8d2 100644 --- a/source/blender/compositor/operations/COM_ColorCurveOperation.h +++ b/source/blender/compositor/operations/COM_ColorCurveOperation.h @@ -22,6 +22,8 @@ #include "COM_NodeOperation.h" #include "DNA_color_types.h" +namespace blender::compositor { + class ColorCurveOperation : public CurveBaseOperation { private: /** @@ -38,17 +40,17 @@ class ColorCurveOperation : public CurveBaseOperation { /** * The inner loop of this operation. */ - void executePixelSampled(float output[4], float x, float y, PixelSampler sampler); + void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; /** * Initialize the execution */ - void initExecution(); + void initExecution() override; /** * Deinitialize the execution */ - void deinitExecution(); + void deinitExecution() override; }; class ConstantLevelColorCurveOperation : public CurveBaseOperation { @@ -67,17 +69,17 @@ class ConstantLevelColorCurveOperation : public CurveBaseOperation { /** * The inner loop of this operation. */ - void executePixelSampled(float output[4], float x, float y, PixelSampler sampler); + void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; /** * Initialize the execution */ - void initExecution(); + void initExecution() override; /** * Deinitialize the execution */ - void deinitExecution(); + void deinitExecution() override; void setBlackLevel(float black[3]) { @@ -88,3 +90,5 @@ class ConstantLevelColorCurveOperation : public CurveBaseOperation { copy_v3_v3(this->m_white, white); } }; + +} // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_ColorExposureOperation.cc b/source/blender/compositor/operations/COM_ColorExposureOperation.cc index 0e24620846e..1512ff87658 100644 --- a/source/blender/compositor/operations/COM_ColorExposureOperation.cc +++ b/source/blender/compositor/operations/COM_ColorExposureOperation.cc @@ -18,6 +18,8 @@ #include "COM_ColorExposureOperation.h" +namespace blender::compositor { + ExposureOperation::ExposureOperation() { this->addInputSocket(DataType::Color); @@ -55,3 +57,5 @@ void ExposureOperation::deinitExecution() this->m_inputProgram = nullptr; this->m_inputExposureProgram = nullptr; } + +} // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_ColorExposureOperation.h b/source/blender/compositor/operations/COM_ColorExposureOperation.h index 97590b85d77..0cfaa059e41 100644 --- a/source/blender/compositor/operations/COM_ColorExposureOperation.h +++ b/source/blender/compositor/operations/COM_ColorExposureOperation.h @@ -20,6 +20,8 @@ #include "COM_NodeOperation.h" +namespace blender::compositor { + class ExposureOperation : public NodeOperation { private: /** @@ -34,15 +36,17 @@ class ExposureOperation : public NodeOperation { /** * The inner loop of this operation. */ - void executePixelSampled(float output[4], float x, float y, PixelSampler sampler); + void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; /** * Initialize the execution */ - void initExecution(); + void initExecution() override; /** * Deinitialize the execution */ - void deinitExecution(); + void deinitExecution() override; }; + +} // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_ColorMatteOperation.cc b/source/blender/compositor/operations/COM_ColorMatteOperation.cc index cc7a81f68d1..89f56ac4aae 100644 --- a/source/blender/compositor/operations/COM_ColorMatteOperation.cc +++ b/source/blender/compositor/operations/COM_ColorMatteOperation.cc @@ -19,6 +19,8 @@ #include "COM_ColorMatteOperation.h" #include "BLI_math.h" +namespace blender::compositor { + ColorMatteOperation::ColorMatteOperation() { addInputSocket(DataType::Color); @@ -79,3 +81,5 @@ void ColorMatteOperation::executePixelSampled(float output[4], output[0] = inColor[3]; /* make pixel just as transparent as it was before */ } } + +} // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_ColorMatteOperation.h b/source/blender/compositor/operations/COM_ColorMatteOperation.h index 91ba27ce2b6..439a3b0741d 100644 --- a/source/blender/compositor/operations/COM_ColorMatteOperation.h +++ b/source/blender/compositor/operations/COM_ColorMatteOperation.h @@ -20,6 +20,8 @@ #include "COM_MixOperation.h" +namespace blender::compositor { + /** * this program converts an input color to an output value. * it assumes we are in sRGB color space. @@ -39,13 +41,15 @@ class ColorMatteOperation : public NodeOperation { /** * The inner loop of this operation. */ - void executePixelSampled(float output[4], float x, float y, PixelSampler sampler); + void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; - void initExecution(); - void deinitExecution(); + void initExecution() override; + void deinitExecution() override; void setSettings(NodeChroma *nodeChroma) { this->m_settings = nodeChroma; } }; + +} // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_ColorRampOperation.cc b/source/blender/compositor/operations/COM_ColorRampOperation.cc index 4fde951fd3c..0ee65a6529e 100644 --- a/source/blender/compositor/operations/COM_ColorRampOperation.cc +++ b/source/blender/compositor/operations/COM_ColorRampOperation.cc @@ -20,6 +20,8 @@ #include "BKE_colorband.h" +namespace blender::compositor { + ColorRampOperation::ColorRampOperation() { this->addInputSocket(DataType::Value); @@ -48,3 +50,5 @@ void ColorRampOperation::deinitExecution() { this->m_inputProgram = nullptr; } + +} // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_ColorRampOperation.h b/source/blender/compositor/operations/COM_ColorRampOperation.h index 49bdb266ce9..d32af9bea24 100644 --- a/source/blender/compositor/operations/COM_ColorRampOperation.h +++ b/source/blender/compositor/operations/COM_ColorRampOperation.h @@ -21,6 +21,8 @@ #include "COM_NodeOperation.h" #include "DNA_texture_types.h" +namespace blender::compositor { + class ColorRampOperation : public NodeOperation { private: /** @@ -35,20 +37,22 @@ class ColorRampOperation : public NodeOperation { /** * The inner loop of this operation. */ - void executePixelSampled(float output[4], float x, float y, PixelSampler sampler); + void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; /** * Initialize the execution */ - void initExecution(); + void initExecution() override; /** * Deinitialize the execution */ - void deinitExecution(); + void deinitExecution() override; void setColorBand(ColorBand *colorBand) { this->m_colorBand = colorBand; } }; + +} // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_ColorSpillOperation.cc b/source/blender/compositor/operations/COM_ColorSpillOperation.cc index 8e8eaabfc6b..7dc7e2775fc 100644 --- a/source/blender/compositor/operations/COM_ColorSpillOperation.cc +++ b/source/blender/compositor/operations/COM_ColorSpillOperation.cc @@ -20,6 +20,8 @@ #include "BLI_math.h" #define AVG(a, b) ((a + b) / 2) +namespace blender::compositor { + ColorSpillOperation::ColorSpillOperation() { addInputSocket(DataType::Color); @@ -115,3 +117,5 @@ void ColorSpillOperation::executePixelSampled(float output[4], copy_v4_v4(output, input); } } + +} // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_ColorSpillOperation.h b/source/blender/compositor/operations/COM_ColorSpillOperation.h index e51101adf84..9b82e720527 100644 --- a/source/blender/compositor/operations/COM_ColorSpillOperation.h +++ b/source/blender/compositor/operations/COM_ColorSpillOperation.h @@ -20,6 +20,8 @@ #include "COM_NodeOperation.h" +namespace blender::compositor { + /** * this program converts an input color to an output value. * it assumes we are in sRGB color space. @@ -44,10 +46,10 @@ class ColorSpillOperation : public NodeOperation { /** * The inner loop of this operation. */ - void executePixelSampled(float output[4], float x, float y, PixelSampler sampler); + void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; - void initExecution(); - void deinitExecution(); + void initExecution() override; + void deinitExecution() override; void setSettings(NodeColorspill *nodeColorSpill) { @@ -64,3 +66,5 @@ class ColorSpillOperation : public NodeOperation { float calculateMapValue(float fac, float *input); }; + +} // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_CompositorOperation.cc b/source/blender/compositor/operations/COM_CompositorOperation.cc index 0454bae8b38..94d41b28f5d 100644 --- a/source/blender/compositor/operations/COM_CompositorOperation.cc +++ b/source/blender/compositor/operations/COM_CompositorOperation.cc @@ -31,6 +31,8 @@ #include "PIL_time.h" +namespace blender::compositor { + CompositorOperation::CompositorOperation() { this->addInputSocket(DataType::Color); @@ -50,6 +52,8 @@ CompositorOperation::CompositorOperation() this->m_scene = nullptr; this->m_sceneName[0] = '\0'; this->m_viewName = nullptr; + + flags.use_render_border = true; } void CompositorOperation::initExecution() @@ -147,7 +151,7 @@ void CompositorOperation::executeRegion(rcti *rect, unsigned int /*tileNumber*/) int y2 = rect->ymax; int offset = (y1 * this->getWidth() + x1); int add = (this->getWidth() - (x2 - x1)); - int offset4 = offset * COM_NUM_CHANNELS_COLOR; + int offset4 = offset * COM_DATA_TYPE_COLOR_CHANNELS; int x; int y; bool breaked = false; @@ -196,23 +200,23 @@ void CompositorOperation::executeRegion(rcti *rect, unsigned int /*tileNumber*/) for (x = x1; x < x2 && (!breaked); x++) { int input_x = x + dx, input_y = y + dy; - this->m_imageInput->readSampled(color, input_x, input_y, COM_PS_NEAREST); + this->m_imageInput->readSampled(color, input_x, input_y, PixelSampler::Nearest); if (this->m_useAlphaInput) { - this->m_alphaInput->readSampled(&(color[3]), input_x, input_y, COM_PS_NEAREST); + this->m_alphaInput->readSampled(&(color[3]), input_x, input_y, PixelSampler::Nearest); } copy_v4_v4(buffer + offset4, color); - this->m_depthInput->readSampled(color, input_x, input_y, COM_PS_NEAREST); + this->m_depthInput->readSampled(color, input_x, input_y, PixelSampler::Nearest); zbuffer[offset] = color[0]; - offset4 += COM_NUM_CHANNELS_COLOR; + offset4 += COM_DATA_TYPE_COLOR_CHANNELS; offset++; if (isBraked()) { breaked = true; } } offset += add; - offset4 += add * COM_NUM_CHANNELS_COLOR; + offset4 += add * COM_DATA_TYPE_COLOR_CHANNELS; } } @@ -242,3 +246,5 @@ void CompositorOperation::determineResolution(unsigned int resolution[2], resolution[0] = width; resolution[1] = height; } + +} // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_CompositorOperation.h b/source/blender/compositor/operations/COM_CompositorOperation.h index 63b87563852..49ed65f01fc 100644 --- a/source/blender/compositor/operations/COM_CompositorOperation.h +++ b/source/blender/compositor/operations/COM_CompositorOperation.h @@ -24,6 +24,8 @@ struct Scene; +namespace blender::compositor { + /** * \brief Compositor output operation */ @@ -86,7 +88,7 @@ class CompositorOperation : public NodeOperation { { return this->m_active; } - void executeRegion(rcti *rect, unsigned int tileNumber); + void executeRegion(rcti *rect, unsigned int tileNumber) override; void setScene(const struct Scene *scene) { m_scene = scene; @@ -103,17 +105,18 @@ class CompositorOperation : public NodeOperation { { this->m_rd = rd; } - bool isOutputOperation(bool /*rendering*/) const + bool isOutputOperation(bool /*rendering*/) const override { return this->isActiveCompositorOutput(); } - void initExecution(); - void deinitExecution(); - CompositorPriority getRenderPriority() const + void initExecution() override; + void deinitExecution() override; + CompositorPriority getRenderPriority() const override { return CompositorPriority::Medium; } - void determineResolution(unsigned int resolution[2], unsigned int preferredResolution[2]); + void determineResolution(unsigned int resolution[2], + unsigned int preferredResolution[2]) override; void setUseAlphaInput(bool value) { this->m_useAlphaInput = value; @@ -123,3 +126,5 @@ class CompositorOperation : public NodeOperation { this->m_active = active; } }; + +} // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_ConvertColorProfileOperation.cc b/source/blender/compositor/operations/COM_ConvertColorProfileOperation.cc index 431f0e9c880..c00fe5d5f61 100644 --- a/source/blender/compositor/operations/COM_ConvertColorProfileOperation.cc +++ b/source/blender/compositor/operations/COM_ConvertColorProfileOperation.cc @@ -20,6 +20,8 @@ #include "IMB_imbuf.h" +namespace blender::compositor { + ConvertColorProfileOperation::ConvertColorProfileOperation() { this->addInputSocket(DataType::Color); @@ -48,3 +50,5 @@ void ConvertColorProfileOperation::deinitExecution() { this->m_inputOperation = nullptr; } + +} // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_ConvertColorProfileOperation.h b/source/blender/compositor/operations/COM_ConvertColorProfileOperation.h index 7b96895d845..6162408501b 100644 --- a/source/blender/compositor/operations/COM_ConvertColorProfileOperation.h +++ b/source/blender/compositor/operations/COM_ConvertColorProfileOperation.h @@ -20,6 +20,8 @@ #include "COM_NodeOperation.h" +namespace blender::compositor { + /** * this program converts an input color to an output value. * it assumes we are in sRGB color space. @@ -55,17 +57,17 @@ class ConvertColorProfileOperation : public NodeOperation { /** * The inner loop of this operation. */ - void executePixelSampled(float output[4], float x, float y, PixelSampler sampler); + void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; /** * Initialize the execution */ - void initExecution(); + void initExecution() override; /** * Deinitialize the execution */ - void deinitExecution(); + void deinitExecution() override; void setFromColorProfile(int colorProfile) { @@ -80,3 +82,5 @@ class ConvertColorProfileOperation : public NodeOperation { this->m_predivided = predivided; } }; + +} // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_ConvertDepthToRadiusOperation.cc b/source/blender/compositor/operations/COM_ConvertDepthToRadiusOperation.cc index 17b351cb14c..57027c11949 100644 --- a/source/blender/compositor/operations/COM_ConvertDepthToRadiusOperation.cc +++ b/source/blender/compositor/operations/COM_ConvertDepthToRadiusOperation.cc @@ -21,6 +21,8 @@ #include "BLI_math.h" #include "DNA_camera_types.h" +namespace blender::compositor { + ConvertDepthToRadiusOperation::ConvertDepthToRadiusOperation() { this->addInputSocket(DataType::Value); @@ -113,3 +115,5 @@ void ConvertDepthToRadiusOperation::deinitExecution() { this->m_inputOperation = nullptr; } + +} // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_ConvertDepthToRadiusOperation.h b/source/blender/compositor/operations/COM_ConvertDepthToRadiusOperation.h index 564a0facec7..1f4e856b128 100644 --- a/source/blender/compositor/operations/COM_ConvertDepthToRadiusOperation.h +++ b/source/blender/compositor/operations/COM_ConvertDepthToRadiusOperation.h @@ -21,6 +21,9 @@ #include "COM_FastGaussianBlurOperation.h" #include "COM_NodeOperation.h" #include "DNA_object_types.h" + +namespace blender::compositor { + /** * this program converts an input color to an output value. * it assumes we are in sRGB color space. @@ -51,17 +54,17 @@ class ConvertDepthToRadiusOperation : public NodeOperation { /** * The inner loop of this operation. */ - void executePixelSampled(float output[4], float x, float y, PixelSampler sampler); + void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; /** * Initialize the execution */ - void initExecution(); + void initExecution() override; /** * Deinitialize the execution */ - void deinitExecution(); + void deinitExecution() override; void setfStop(float fStop) { @@ -81,3 +84,5 @@ class ConvertDepthToRadiusOperation : public NodeOperation { this->m_blurPostOperation = operation; } }; + +} // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_ConvertOperation.cc b/source/blender/compositor/operations/COM_ConvertOperation.cc index 648b3f0b30a..2ea15185c0f 100644 --- a/source/blender/compositor/operations/COM_ConvertOperation.cc +++ b/source/blender/compositor/operations/COM_ConvertOperation.cc @@ -20,6 +20,8 @@ #include "IMB_colormanagement.h" +namespace blender::compositor { + ConvertBaseOperation::ConvertBaseOperation() { this->m_inputOperation = nullptr; @@ -478,3 +480,5 @@ void CombineChannelsOperation::executePixelSampled(float output[4], output[3] = input[0]; } } + +} // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_ConvertOperation.h b/source/blender/compositor/operations/COM_ConvertOperation.h index ca026528a38..7a726e35c7c 100644 --- a/source/blender/compositor/operations/COM_ConvertOperation.h +++ b/source/blender/compositor/operations/COM_ConvertOperation.h @@ -20,6 +20,8 @@ #include "COM_NodeOperation.h" +namespace blender::compositor { + class ConvertBaseOperation : public NodeOperation { protected: SocketReader *m_inputOperation; @@ -27,57 +29,57 @@ class ConvertBaseOperation : public NodeOperation { public: ConvertBaseOperation(); - void initExecution(); - void deinitExecution(); + void initExecution() override; + void deinitExecution() override; }; class ConvertValueToColorOperation : public ConvertBaseOperation { public: ConvertValueToColorOperation(); - void executePixelSampled(float output[4], float x, float y, PixelSampler sampler); + void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; }; class ConvertColorToValueOperation : public ConvertBaseOperation { public: ConvertColorToValueOperation(); - void executePixelSampled(float output[4], float x, float y, PixelSampler sampler); + void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; }; class ConvertColorToBWOperation : public ConvertBaseOperation { public: ConvertColorToBWOperation(); - void executePixelSampled(float output[4], float x, float y, PixelSampler sampler); + void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; }; class ConvertColorToVectorOperation : public ConvertBaseOperation { public: ConvertColorToVectorOperation(); - void executePixelSampled(float output[4], float x, float y, PixelSampler sampler); + void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; }; class ConvertValueToVectorOperation : public ConvertBaseOperation { public: ConvertValueToVectorOperation(); - void executePixelSampled(float output[4], float x, float y, PixelSampler sampler); + void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; }; class ConvertVectorToColorOperation : public ConvertBaseOperation { public: ConvertVectorToColorOperation(); - void executePixelSampled(float output[4], float x, float y, PixelSampler sampler); + void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; }; class ConvertVectorToValueOperation : public ConvertBaseOperation { public: ConvertVectorToValueOperation(); - void executePixelSampled(float output[4], float x, float y, PixelSampler sampler); + void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; }; class ConvertRGBToYCCOperation : public ConvertBaseOperation { @@ -88,7 +90,7 @@ class ConvertRGBToYCCOperation : public ConvertBaseOperation { public: ConvertRGBToYCCOperation(); - void executePixelSampled(float output[4], float x, float y, PixelSampler sampler); + void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; /** Set the YCC mode */ void setMode(int mode); @@ -102,7 +104,7 @@ class ConvertYCCToRGBOperation : public ConvertBaseOperation { public: ConvertYCCToRGBOperation(); - void executePixelSampled(float output[4], float x, float y, PixelSampler sampler); + void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; /** Set the YCC mode */ void setMode(int mode); @@ -112,42 +114,42 @@ class ConvertRGBToYUVOperation : public ConvertBaseOperation { public: ConvertRGBToYUVOperation(); - void executePixelSampled(float output[4], float x, float y, PixelSampler sampler); + void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; }; class ConvertYUVToRGBOperation : public ConvertBaseOperation { public: ConvertYUVToRGBOperation(); - void executePixelSampled(float output[4], float x, float y, PixelSampler sampler); + void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; }; class ConvertRGBToHSVOperation : public ConvertBaseOperation { public: ConvertRGBToHSVOperation(); - void executePixelSampled(float output[4], float x, float y, PixelSampler sampler); + void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; }; class ConvertHSVToRGBOperation : public ConvertBaseOperation { public: ConvertHSVToRGBOperation(); - void executePixelSampled(float output[4], float x, float y, PixelSampler sampler); + void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; }; class ConvertPremulToStraightOperation : public ConvertBaseOperation { public: ConvertPremulToStraightOperation(); - void executePixelSampled(float output[4], float x, float y, PixelSampler sampler); + void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; }; class ConvertStraightToPremulOperation : public ConvertBaseOperation { public: ConvertStraightToPremulOperation(); - void executePixelSampled(float output[4], float x, float y, PixelSampler sampler); + void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; }; class SeparateChannelOperation : public NodeOperation { @@ -157,10 +159,10 @@ class SeparateChannelOperation : public NodeOperation { public: SeparateChannelOperation(); - void executePixelSampled(float output[4], float x, float y, PixelSampler sampler); + void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; - void initExecution(); - void deinitExecution(); + void initExecution() override; + void deinitExecution() override; void setChannel(int channel) { @@ -177,8 +179,10 @@ class CombineChannelsOperation : public NodeOperation { public: CombineChannelsOperation(); - void executePixelSampled(float output[4], float x, float y, PixelSampler sampler); + void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; - void initExecution(); - void deinitExecution(); + void initExecution() override; + void deinitExecution() override; }; + +} // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_ConvolutionEdgeFilterOperation.cc b/source/blender/compositor/operations/COM_ConvolutionEdgeFilterOperation.cc index a5f2ae404e3..9114200a8ec 100644 --- a/source/blender/compositor/operations/COM_ConvolutionEdgeFilterOperation.cc +++ b/source/blender/compositor/operations/COM_ConvolutionEdgeFilterOperation.cc @@ -19,6 +19,8 @@ #include "COM_ConvolutionEdgeFilterOperation.h" #include "BLI_math.h" +namespace blender::compositor { + ConvolutionEdgeFilterOperation::ConvolutionEdgeFilterOperation() { /* pass */ @@ -97,3 +99,5 @@ void ConvolutionEdgeFilterOperation::executePixel(float output[4], int x, int y, output[2] = MAX2(output[2], 0.0f); output[3] = MAX2(output[3], 0.0f); } + +} // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_ConvolutionEdgeFilterOperation.h b/source/blender/compositor/operations/COM_ConvolutionEdgeFilterOperation.h index ab4b8a1dad1..98bfa1768d8 100644 --- a/source/blender/compositor/operations/COM_ConvolutionEdgeFilterOperation.h +++ b/source/blender/compositor/operations/COM_ConvolutionEdgeFilterOperation.h @@ -20,8 +20,12 @@ #include "COM_ConvolutionFilterOperation.h" +namespace blender::compositor { + class ConvolutionEdgeFilterOperation : public ConvolutionFilterOperation { public: ConvolutionEdgeFilterOperation(); - void executePixel(float output[4], int x, int y, void *data); + void executePixel(float output[4], int x, int y, void *data) override; }; + +} // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_ConvolutionFilterOperation.cc b/source/blender/compositor/operations/COM_ConvolutionFilterOperation.cc index f80144fb06d..72cbbf4283a 100644 --- a/source/blender/compositor/operations/COM_ConvolutionFilterOperation.cc +++ b/source/blender/compositor/operations/COM_ConvolutionFilterOperation.cc @@ -22,6 +22,8 @@ #include "MEM_guardedalloc.h" +namespace blender::compositor { + ConvolutionFilterOperation::ConvolutionFilterOperation() { this->addInputSocket(DataType::Color); @@ -29,7 +31,7 @@ ConvolutionFilterOperation::ConvolutionFilterOperation() this->addOutputSocket(DataType::Color); this->setResolutionInputSocketIndex(0); this->m_inputOperation = nullptr; - this->setComplex(true); + this->flags.complex = true; } void ConvolutionFilterOperation::initExecution() { @@ -124,3 +126,5 @@ bool ConvolutionFilterOperation::determineDependingAreaOfInterest( return NodeOperation::determineDependingAreaOfInterest(&newInput, readOperation, output); } + +} // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_ConvolutionFilterOperation.h b/source/blender/compositor/operations/COM_ConvolutionFilterOperation.h index d178b0a7418..16dee502929 100644 --- a/source/blender/compositor/operations/COM_ConvolutionFilterOperation.h +++ b/source/blender/compositor/operations/COM_ConvolutionFilterOperation.h @@ -20,6 +20,8 @@ #include "COM_NodeOperation.h" +namespace blender::compositor { + class ConvolutionFilterOperation : public NodeOperation { private: int m_filterWidth; @@ -36,9 +38,11 @@ class ConvolutionFilterOperation : public NodeOperation { float f1, float f2, float f3, float f4, float f5, float f6, float f7, float f8, float f9); bool determineDependingAreaOfInterest(rcti *input, ReadBufferOperation *readOperation, - rcti *output); - void executePixel(float output[4], int x, int y, void *data); + rcti *output) override; + void executePixel(float output[4], int x, int y, void *data) override; - void initExecution(); - void deinitExecution(); + void initExecution() override; + void deinitExecution() override; }; + +} // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_CropOperation.cc b/source/blender/compositor/operations/COM_CropOperation.cc index 55a1e505ec8..f12d93bc8d3 100644 --- a/source/blender/compositor/operations/COM_CropOperation.cc +++ b/source/blender/compositor/operations/COM_CropOperation.cc @@ -19,9 +19,11 @@ #include "COM_CropOperation.h" #include "BLI_math.h" +namespace blender::compositor { + CropBaseOperation::CropBaseOperation() { - this->addInputSocket(DataType::Color, COM_SC_NO_RESIZE); + this->addInputSocket(DataType::Color, ResizeMode::None); this->addOutputSocket(DataType::Color); this->m_inputOperation = nullptr; this->m_settings = nullptr; @@ -133,3 +135,5 @@ void CropImageOperation::executePixelSampled(float output[4], zero_v4(output); } } + +} // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_CropOperation.h b/source/blender/compositor/operations/COM_CropOperation.h index f20664f0501..acdff79a77c 100644 --- a/source/blender/compositor/operations/COM_CropOperation.h +++ b/source/blender/compositor/operations/COM_CropOperation.h @@ -20,6 +20,8 @@ #include "COM_NodeOperation.h" +namespace blender::compositor { + class CropBaseOperation : public NodeOperation { protected: SocketReader *m_inputOperation; @@ -34,8 +36,8 @@ class CropBaseOperation : public NodeOperation { public: CropBaseOperation(); - void initExecution(); - void deinitExecution(); + void initExecution() override; + void deinitExecution() override; void setCropSettings(NodeTwoXYs *settings) { this->m_settings = settings; @@ -50,7 +52,7 @@ class CropOperation : public CropBaseOperation { private: public: CropOperation(); - void executePixelSampled(float output[4], float x, float y, PixelSampler sampler); + void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; }; class CropImageOperation : public CropBaseOperation { @@ -59,7 +61,10 @@ class CropImageOperation : public CropBaseOperation { CropImageOperation(); bool determineDependingAreaOfInterest(rcti *input, ReadBufferOperation *readOperation, - rcti *output); - void determineResolution(unsigned int resolution[2], unsigned int preferredResolution[2]); - void executePixelSampled(float output[4], float x, float y, PixelSampler sampler); + rcti *output) override; + void determineResolution(unsigned int resolution[2], + unsigned int preferredResolution[2]) override; + void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; }; + +} // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_CryptomatteOperation.cc b/source/blender/compositor/operations/COM_CryptomatteOperation.cc index 8d42a756f51..52ae1d6d5b5 100644 --- a/source/blender/compositor/operations/COM_CryptomatteOperation.cc +++ b/source/blender/compositor/operations/COM_CryptomatteOperation.cc @@ -18,14 +18,16 @@ #include "COM_CryptomatteOperation.h" +namespace blender::compositor { + CryptomatteOperation::CryptomatteOperation(size_t num_inputs) { + inputs.resize(num_inputs); for (size_t i = 0; i < num_inputs; i++) { this->addInputSocket(DataType::Color); } - inputs.resize(num_inputs); this->addOutputSocket(DataType::Color); - this->setComplex(true); + this->flags.complex = true; } void CryptomatteOperation::initExecution() @@ -38,7 +40,7 @@ void CryptomatteOperation::initExecution() void CryptomatteOperation::addObjectIndex(float objectIndex) { if (objectIndex != 0.0f) { - m_objectIndex.push_back(objectIndex); + m_objectIndex.append(objectIndex); } } @@ -58,13 +60,15 @@ void CryptomatteOperation::executePixel(float output[4], int x, int y, void *dat output[1] = ((float)((m3hash << 8)) / (float)UINT32_MAX); output[2] = ((float)((m3hash << 16)) / (float)UINT32_MAX); } - for (size_t i = 0; i < m_objectIndex.size(); i++) { - if (m_objectIndex[i] == input[0]) { + for (float hash : m_objectIndex) { + if (input[0] == hash) { output[3] += input[1]; } - if (m_objectIndex[i] == input[2]) { + if (input[2] == hash) { output[3] += input[3]; } } } } + +} // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_CryptomatteOperation.h b/source/blender/compositor/operations/COM_CryptomatteOperation.h index 8c5a3134720..40a1fbf5a80 100644 --- a/source/blender/compositor/operations/COM_CryptomatteOperation.h +++ b/source/blender/compositor/operations/COM_CryptomatteOperation.h @@ -20,17 +20,21 @@ #include "COM_NodeOperation.h" +namespace blender::compositor { + class CryptomatteOperation : public NodeOperation { private: - std::vector<float> m_objectIndex; + blender::Vector<float> m_objectIndex; public: - std::vector<SocketReader *> inputs; + blender::Vector<SocketReader *> inputs; CryptomatteOperation(size_t num_inputs = 6); - void initExecution(); - void executePixel(float output[4], int x, int y, void *data); + void initExecution() override; + void executePixel(float output[4], int x, int y, void *data) override; void addObjectIndex(float objectIndex); }; + +} // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_CurveBaseOperation.cc b/source/blender/compositor/operations/COM_CurveBaseOperation.cc index b58efcf0cca..8f655964570 100644 --- a/source/blender/compositor/operations/COM_CurveBaseOperation.cc +++ b/source/blender/compositor/operations/COM_CurveBaseOperation.cc @@ -20,6 +20,8 @@ #include "BKE_colortools.h" +namespace blender::compositor { + CurveBaseOperation::CurveBaseOperation() { this->m_curveMapping = nullptr; @@ -53,3 +55,5 @@ void CurveBaseOperation::setCurveMapping(CurveMapping *mapping) } this->m_curveMapping = BKE_curvemapping_copy(mapping); } + +} // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_CurveBaseOperation.h b/source/blender/compositor/operations/COM_CurveBaseOperation.h index 63e667cfe12..fff0f3168ba 100644 --- a/source/blender/compositor/operations/COM_CurveBaseOperation.h +++ b/source/blender/compositor/operations/COM_CurveBaseOperation.h @@ -21,6 +21,8 @@ #include "COM_NodeOperation.h" #include "DNA_color_types.h" +namespace blender::compositor { + class CurveBaseOperation : public NodeOperation { protected: /** @@ -35,8 +37,10 @@ class CurveBaseOperation : public NodeOperation { /** * Initialize the execution */ - void initExecution(); - void deinitExecution(); + void initExecution() override; + void deinitExecution() override; void setCurveMapping(CurveMapping *mapping); }; + +} // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_DenoiseOperation.cc b/source/blender/compositor/operations/COM_DenoiseOperation.cc index 66d0f3fd9bd..587afdc2d00 100644 --- a/source/blender/compositor/operations/COM_DenoiseOperation.cc +++ b/source/blender/compositor/operations/COM_DenoiseOperation.cc @@ -26,6 +26,8 @@ static pthread_mutex_t oidn_lock = BLI_MUTEX_INITIALIZER; #endif #include <iostream> +namespace blender::compositor { + DenoiseOperation::DenoiseOperation() { this->addInputSocket(DataType::Color); @@ -164,3 +166,5 @@ void DenoiseOperation::generateDenoise(float *data, inputBufferColor, sizeof(float[4]) * inputTileColor->getWidth() * inputTileColor->getHeight()); } + +} // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_DenoiseOperation.h b/source/blender/compositor/operations/COM_DenoiseOperation.h index 5af6e16c958..a9298c17e92 100644 --- a/source/blender/compositor/operations/COM_DenoiseOperation.h +++ b/source/blender/compositor/operations/COM_DenoiseOperation.h @@ -21,6 +21,8 @@ #include "COM_SingleThreadedOperation.h" #include "DNA_node_types.h" +namespace blender::compositor { + class DenoiseOperation : public SingleThreadedOperation { private: /** @@ -40,12 +42,12 @@ class DenoiseOperation : public SingleThreadedOperation { /** * Initialize the execution */ - void initExecution(); + void initExecution() override; /** * Deinitialize the execution */ - void deinitExecution(); + void deinitExecution() override; void setDenoiseSettings(NodeDenoise *settings) { @@ -53,7 +55,7 @@ class DenoiseOperation : public SingleThreadedOperation { } bool determineDependingAreaOfInterest(rcti *input, ReadBufferOperation *readOperation, - rcti *output); + rcti *output) override; protected: void generateDenoise(float *data, @@ -62,5 +64,7 @@ class DenoiseOperation : public SingleThreadedOperation { MemoryBuffer *inputTileAlbedo, NodeDenoise *settings); - MemoryBuffer *createMemoryBuffer(rcti *rect); + MemoryBuffer *createMemoryBuffer(rcti *rect) override; }; + +} // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_DespeckleOperation.cc b/source/blender/compositor/operations/COM_DespeckleOperation.cc index 813ae07a97a..fc8778c7d2e 100644 --- a/source/blender/compositor/operations/COM_DespeckleOperation.cc +++ b/source/blender/compositor/operations/COM_DespeckleOperation.cc @@ -22,6 +22,8 @@ #include "BLI_utildefines.h" +namespace blender::compositor { + DespeckleOperation::DespeckleOperation() { this->addInputSocket(DataType::Color); @@ -29,7 +31,7 @@ DespeckleOperation::DespeckleOperation() this->addOutputSocket(DataType::Color); this->setResolutionInputSocketIndex(0); this->m_inputOperation = nullptr; - this->setComplex(true); + this->flags.complex = true; } void DespeckleOperation::initExecution() { @@ -141,3 +143,5 @@ bool DespeckleOperation::determineDependingAreaOfInterest(rcti *input, return NodeOperation::determineDependingAreaOfInterest(&newInput, readOperation, output); } + +} // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_DespeckleOperation.h b/source/blender/compositor/operations/COM_DespeckleOperation.h index af37c276bd2..e8d3461d2ec 100644 --- a/source/blender/compositor/operations/COM_DespeckleOperation.h +++ b/source/blender/compositor/operations/COM_DespeckleOperation.h @@ -20,6 +20,8 @@ #include "COM_NodeOperation.h" +namespace blender::compositor { + class DespeckleOperation : public NodeOperation { private: float m_threshold; @@ -36,8 +38,8 @@ class DespeckleOperation : public NodeOperation { DespeckleOperation(); bool determineDependingAreaOfInterest(rcti *input, ReadBufferOperation *readOperation, - rcti *output); - void executePixel(float output[4], int x, int y, void *data); + rcti *output) override; + void executePixel(float output[4], int x, int y, void *data) override; void setThreshold(float threshold) { @@ -48,6 +50,8 @@ class DespeckleOperation : public NodeOperation { this->m_threshold_neighbor = threshold; } - void initExecution(); - void deinitExecution(); + void initExecution() override; + void deinitExecution() override; }; + +} // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_DifferenceMatteOperation.cc b/source/blender/compositor/operations/COM_DifferenceMatteOperation.cc index 1ce91aeb4c3..e380131634f 100644 --- a/source/blender/compositor/operations/COM_DifferenceMatteOperation.cc +++ b/source/blender/compositor/operations/COM_DifferenceMatteOperation.cc @@ -19,6 +19,8 @@ #include "COM_DifferenceMatteOperation.h" #include "BLI_math.h" +namespace blender::compositor { + DifferenceMatteOperation::DifferenceMatteOperation() { addInputSocket(DataType::Color); @@ -83,3 +85,5 @@ void DifferenceMatteOperation::executePixelSampled(float output[4], output[0] = inColor1[3]; } } + +} // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_DifferenceMatteOperation.h b/source/blender/compositor/operations/COM_DifferenceMatteOperation.h index 0ee5eab3fe7..d3963fee1c1 100644 --- a/source/blender/compositor/operations/COM_DifferenceMatteOperation.h +++ b/source/blender/compositor/operations/COM_DifferenceMatteOperation.h @@ -20,6 +20,8 @@ #include "COM_MixOperation.h" +namespace blender::compositor { + /** * this program converts an input color to an output value. * it assumes we are in sRGB color space. @@ -39,13 +41,15 @@ class DifferenceMatteOperation : public NodeOperation { /** * The inner loop of this operation. */ - void executePixelSampled(float output[4], float x, float y, PixelSampler sampler); + void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; - void initExecution(); - void deinitExecution(); + void initExecution() override; + void deinitExecution() override; void setSettings(NodeChroma *nodeChroma) { this->m_settings = nodeChroma; } }; + +} // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_DilateErodeOperation.cc b/source/blender/compositor/operations/COM_DilateErodeOperation.cc index 33ddf9187b0..9e18a8e2f2c 100644 --- a/source/blender/compositor/operations/COM_DilateErodeOperation.cc +++ b/source/blender/compositor/operations/COM_DilateErodeOperation.cc @@ -22,12 +22,14 @@ #include "MEM_guardedalloc.h" +namespace blender::compositor { + // DilateErode Distance Threshold DilateErodeThresholdOperation::DilateErodeThresholdOperation() { this->addInputSocket(DataType::Value); this->addOutputSocket(DataType::Value); - this->setComplex(true); + this->flags.complex = true; this->m_inputProgram = nullptr; this->m_inset = 0.0f; this->m__switch = 0.5f; @@ -163,10 +165,10 @@ DilateDistanceOperation::DilateDistanceOperation() { this->addInputSocket(DataType::Value); this->addOutputSocket(DataType::Value); - this->setComplex(true); this->m_inputProgram = nullptr; this->m_distance = 0.0f; - this->setOpenCL(true); + flags.complex = true; + flags.open_cl = true; } void DilateDistanceOperation::initExecution() { @@ -321,7 +323,7 @@ DilateStepOperation::DilateStepOperation() { this->addInputSocket(DataType::Value); this->addOutputSocket(DataType::Value); - this->setComplex(true); + this->flags.complex = true; this->m_inputProgram = nullptr; } void DilateStepOperation::initExecution() @@ -568,3 +570,5 @@ void *ErodeStepOperation::initializeTileData(rcti *rect) return result; } + +} // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_DilateErodeOperation.h b/source/blender/compositor/operations/COM_DilateErodeOperation.h index 35f9be89220..a489e293e8e 100644 --- a/source/blender/compositor/operations/COM_DilateErodeOperation.h +++ b/source/blender/compositor/operations/COM_DilateErodeOperation.h @@ -20,6 +20,8 @@ #include "COM_NodeOperation.h" +namespace blender::compositor { + class DilateErodeThresholdOperation : public NodeOperation { private: /** @@ -43,18 +45,18 @@ class DilateErodeThresholdOperation : public NodeOperation { /** * The inner loop of this operation. */ - void executePixel(float output[4], int x, int y, void *data); + void executePixel(float output[4], int x, int y, void *data) override; /** * Initialize the execution */ - void initExecution(); + void initExecution() override; - void *initializeTileData(rcti *rect); + void *initializeTileData(rcti *rect) override; /** * Deinitialize the execution */ - void deinitExecution(); + void deinitExecution() override; void setDistance(float distance) { @@ -71,7 +73,7 @@ class DilateErodeThresholdOperation : public NodeOperation { bool determineDependingAreaOfInterest(rcti *input, ReadBufferOperation *readOperation, - rcti *output); + rcti *output) override; }; class DilateDistanceOperation : public NodeOperation { @@ -90,18 +92,18 @@ class DilateDistanceOperation : public NodeOperation { /** * The inner loop of this operation. */ - void executePixel(float output[4], int x, int y, void *data); + void executePixel(float output[4], int x, int y, void *data) override; /** * Initialize the execution */ - void initExecution(); + void initExecution() override; - void *initializeTileData(rcti *rect); + void *initializeTileData(rcti *rect) override; /** * Deinitialize the execution */ - void deinitExecution(); + void deinitExecution() override; void setDistance(float distance) { @@ -109,14 +111,14 @@ class DilateDistanceOperation : public NodeOperation { } bool determineDependingAreaOfInterest(rcti *input, ReadBufferOperation *readOperation, - rcti *output); + rcti *output) override; void executeOpenCL(OpenCLDevice *device, MemoryBuffer *outputMemoryBuffer, cl_mem clOutputBuffer, MemoryBuffer **inputMemoryBuffers, std::list<cl_mem> *clMemToCleanUp, - std::list<cl_kernel> *clKernelsToCleanUp); + std::list<cl_kernel> *clKernelsToCleanUp) override; }; class ErodeDistanceOperation : public DilateDistanceOperation { public: @@ -125,14 +127,14 @@ class ErodeDistanceOperation : public DilateDistanceOperation { /** * The inner loop of this operation. */ - void executePixel(float output[4], int x, int y, void *data); + void executePixel(float output[4], int x, int y, void *data) override; void executeOpenCL(OpenCLDevice *device, MemoryBuffer *outputMemoryBuffer, cl_mem clOutputBuffer, MemoryBuffer **inputMemoryBuffers, std::list<cl_mem> *clMemToCleanUp, - std::list<cl_kernel> *clKernelsToCleanUp); + std::list<cl_kernel> *clKernelsToCleanUp) override; }; class DilateStepOperation : public NodeOperation { @@ -150,19 +152,19 @@ class DilateStepOperation : public NodeOperation { /** * The inner loop of this operation. */ - void executePixel(float output[4], int x, int y, void *data); + void executePixel(float output[4], int x, int y, void *data) override; /** * Initialize the execution */ - void initExecution(); + void initExecution() override; - void *initializeTileData(rcti *rect); + void *initializeTileData(rcti *rect) override; /** * Deinitialize the execution */ - void deinitExecution(); - void deinitializeTileData(rcti *rect, void *data); + void deinitExecution() override; + void deinitializeTileData(rcti *rect, void *data) override; void setIterations(int iterations) { @@ -171,12 +173,14 @@ class DilateStepOperation : public NodeOperation { bool determineDependingAreaOfInterest(rcti *input, ReadBufferOperation *readOperation, - rcti *output); + rcti *output) override; }; class ErodeStepOperation : public DilateStepOperation { public: ErodeStepOperation(); - void *initializeTileData(rcti *rect); + void *initializeTileData(rcti *rect) override; }; + +} // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_DirectionalBlurOperation.cc b/source/blender/compositor/operations/COM_DirectionalBlurOperation.cc index 1a2701a681d..97bdc25af3b 100644 --- a/source/blender/compositor/operations/COM_DirectionalBlurOperation.cc +++ b/source/blender/compositor/operations/COM_DirectionalBlurOperation.cc @@ -23,13 +23,14 @@ #include "RE_pipeline.h" +namespace blender::compositor { + DirectionalBlurOperation::DirectionalBlurOperation() { this->addInputSocket(DataType::Color); this->addOutputSocket(DataType::Color); - this->setComplex(true); - - this->setOpenCL(true); + flags.complex = true; + flags.open_cl = true; this->m_inputProgram = nullptr; } @@ -66,7 +67,7 @@ void DirectionalBlurOperation::executePixel(float output[4], int x, int y, void const int iterations = pow(2.0f, this->m_data->iter); float col[4] = {0.0f, 0.0f, 0.0f, 0.0f}; float col2[4] = {0.0f, 0.0f, 0.0f, 0.0f}; - this->m_inputProgram->readSampled(col2, x, y, COM_PS_BILINEAR); + this->m_inputProgram->readSampled(col2, x, y, PixelSampler::Bilinear); float ltx = this->m_tx; float lty = this->m_ty; float lsc = this->m_sc; @@ -82,7 +83,7 @@ void DirectionalBlurOperation::executePixel(float output[4], int x, int y, void this->m_inputProgram->readSampled(col, cs * u + ss * v + this->m_center_x_pix, cs * v - ss * u + this->m_center_y_pix, - COM_PS_BILINEAR); + PixelSampler::Bilinear); add_v4_v4(col2, col); @@ -144,3 +145,5 @@ bool DirectionalBlurOperation::determineDependingAreaOfInterest(rcti * /*input*/ return NodeOperation::determineDependingAreaOfInterest(&newInput, readOperation, output); } + +} // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_DirectionalBlurOperation.h b/source/blender/compositor/operations/COM_DirectionalBlurOperation.h index 0c220f0e239..5555520462b 100644 --- a/source/blender/compositor/operations/COM_DirectionalBlurOperation.h +++ b/source/blender/compositor/operations/COM_DirectionalBlurOperation.h @@ -21,6 +21,8 @@ #include "COM_NodeOperation.h" #include "COM_QualityStepHelper.h" +namespace blender::compositor { + class DirectionalBlurOperation : public NodeOperation, public QualityStepHelper { private: SocketReader *m_inputProgram; @@ -36,21 +38,21 @@ class DirectionalBlurOperation : public NodeOperation, public QualityStepHelper /** * The inner loop of this operation. */ - void executePixel(float output[4], int x, int y, void *data); + void executePixel(float output[4], int x, int y, void *data) override; /** * Initialize the execution */ - void initExecution(); + void initExecution() override; /** * Deinitialize the execution */ - void deinitExecution(); + void deinitExecution() override; bool determineDependingAreaOfInterest(rcti *input, ReadBufferOperation *readOperation, - rcti *output); + rcti *output) override; void setData(NodeDBlurData *data) { @@ -62,5 +64,7 @@ class DirectionalBlurOperation : public NodeOperation, public QualityStepHelper cl_mem clOutputBuffer, MemoryBuffer **inputMemoryBuffers, std::list<cl_mem> *clMemToCleanUp, - std::list<cl_kernel> *clKernelsToCleanUp); + std::list<cl_kernel> *clKernelsToCleanUp) override; }; + +} // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_DisplaceOperation.cc b/source/blender/compositor/operations/COM_DisplaceOperation.cc index 12c7d29a210..9f3f5cfe489 100644 --- a/source/blender/compositor/operations/COM_DisplaceOperation.cc +++ b/source/blender/compositor/operations/COM_DisplaceOperation.cc @@ -20,6 +20,8 @@ #include "BLI_math.h" #include "BLI_utildefines.h" +namespace blender::compositor { + DisplaceOperation::DisplaceOperation() { this->addInputSocket(DataType::Color); @@ -27,7 +29,7 @@ DisplaceOperation::DisplaceOperation() this->addInputSocket(DataType::Value); this->addInputSocket(DataType::Value); this->addOutputSocket(DataType::Color); - this->setComplex(true); + this->flags.complex = true; this->m_inputColorProgram = nullptr; this->m_inputVectorProgram = nullptr; @@ -56,7 +58,7 @@ void DisplaceOperation::executePixelSampled(float output[4], pixelTransform(xy, uv, deriv); if (is_zero_v2(deriv[0]) && is_zero_v2(deriv[1])) { - this->m_inputColorProgram->readSampled(output, uv[0], uv[1], COM_PS_BILINEAR); + this->m_inputColorProgram->readSampled(output, uv[0], uv[1], PixelSampler::Bilinear); } else { /* EWA filtering (without nearest it gets blurry with NO distortion) */ @@ -76,7 +78,7 @@ bool DisplaceOperation::read_displacement( } float col[4]; - m_inputVectorProgram->readSampled(col, x, y, COM_PS_BILINEAR); + m_inputVectorProgram->readSampled(col, x, y, PixelSampler::Bilinear); r_u = origin[0] - col[0] * xscale; r_v = origin[1] - col[1] * yscale; return true; @@ -88,9 +90,9 @@ void DisplaceOperation::pixelTransform(const float xy[2], float r_uv[2], float r float uv[2]; /* temporary variables for derivative estimation */ int num; - m_inputScaleXProgram->readSampled(col, xy[0], xy[1], COM_PS_NEAREST); + m_inputScaleXProgram->readSampled(col, xy[0], xy[1], PixelSampler::Nearest); float xs = col[0]; - m_inputScaleYProgram->readSampled(col, xy[0], xy[1], COM_PS_NEAREST); + m_inputScaleYProgram->readSampled(col, xy[0], xy[1], PixelSampler::Nearest); float ys = col[0]; /* clamp x and y displacement to triple image resolution - * to prevent hangs from huge values mistakenly plugged in eg. z buffers */ @@ -192,3 +194,5 @@ bool DisplaceOperation::determineDependingAreaOfInterest(rcti *input, return false; } + +} // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_DisplaceOperation.h b/source/blender/compositor/operations/COM_DisplaceOperation.h index 52874779f73..fd82692f687 100644 --- a/source/blender/compositor/operations/COM_DisplaceOperation.h +++ b/source/blender/compositor/operations/COM_DisplaceOperation.h @@ -20,6 +20,8 @@ #include "COM_NodeOperation.h" +namespace blender::compositor { + class DisplaceOperation : public NodeOperation { private: /** @@ -41,26 +43,28 @@ class DisplaceOperation : public NodeOperation { */ bool determineDependingAreaOfInterest(rcti *input, ReadBufferOperation *readOperation, - rcti *output); + rcti *output) override; /** * The inner loop of this operation. */ - void executePixelSampled(float output[4], float x, float y, PixelSampler sampler); + void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; void pixelTransform(const float xy[2], float r_uv[2], float r_deriv[2][2]); /** * Initialize the execution */ - void initExecution(); + void initExecution() override; /** * Deinitialize the execution */ - void deinitExecution(); + void deinitExecution() override; private: bool read_displacement( float x, float y, float xscale, float yscale, const float origin[2], float &r_u, float &r_v); }; + +} // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_DisplaceSimpleOperation.cc b/source/blender/compositor/operations/COM_DisplaceSimpleOperation.cc index 9d00c2cb148..f4b77f5d32c 100644 --- a/source/blender/compositor/operations/COM_DisplaceSimpleOperation.cc +++ b/source/blender/compositor/operations/COM_DisplaceSimpleOperation.cc @@ -20,6 +20,8 @@ #include "BLI_math.h" #include "BLI_utildefines.h" +namespace blender::compositor { + DisplaceSimpleOperation::DisplaceSimpleOperation() { this->addInputSocket(DataType::Color); @@ -129,3 +131,5 @@ bool DisplaceSimpleOperation::determineDependingAreaOfInterest(rcti *input, return false; } + +} // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_DisplaceSimpleOperation.h b/source/blender/compositor/operations/COM_DisplaceSimpleOperation.h index 3b850d94750..15e6fcd0523 100644 --- a/source/blender/compositor/operations/COM_DisplaceSimpleOperation.h +++ b/source/blender/compositor/operations/COM_DisplaceSimpleOperation.h @@ -20,6 +20,8 @@ #include "COM_NodeOperation.h" +namespace blender::compositor { + class DisplaceSimpleOperation : public NodeOperation { private: /** @@ -41,20 +43,22 @@ class DisplaceSimpleOperation : public NodeOperation { */ bool determineDependingAreaOfInterest(rcti *input, ReadBufferOperation *readOperation, - rcti *output); + rcti *output) override; /** * The inner loop of this operation. */ - void executePixelSampled(float output[4], float x, float y, PixelSampler sampler); + void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; /** * Initialize the execution */ - void initExecution(); + void initExecution() override; /** * Deinitialize the execution */ - void deinitExecution(); + void deinitExecution() override; }; + +} // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_DistanceRGBMatteOperation.cc b/source/blender/compositor/operations/COM_DistanceRGBMatteOperation.cc index ae024d497d6..12cb7e7d075 100644 --- a/source/blender/compositor/operations/COM_DistanceRGBMatteOperation.cc +++ b/source/blender/compositor/operations/COM_DistanceRGBMatteOperation.cc @@ -19,6 +19,8 @@ #include "COM_DistanceRGBMatteOperation.h" #include "BLI_math.h" +namespace blender::compositor { + DistanceRGBMatteOperation::DistanceRGBMatteOperation() { this->addInputSocket(DataType::Color); @@ -90,3 +92,5 @@ void DistanceRGBMatteOperation::executePixelSampled(float output[4], output[0] = inImage[3]; } } + +} // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_DistanceRGBMatteOperation.h b/source/blender/compositor/operations/COM_DistanceRGBMatteOperation.h index 5c8c2204637..6fe603233b7 100644 --- a/source/blender/compositor/operations/COM_DistanceRGBMatteOperation.h +++ b/source/blender/compositor/operations/COM_DistanceRGBMatteOperation.h @@ -20,6 +20,8 @@ #include "COM_MixOperation.h" +namespace blender::compositor { + /** * this program converts an input color to an output value. * it assumes we are in sRGB color space. @@ -41,13 +43,15 @@ class DistanceRGBMatteOperation : public NodeOperation { /** * The inner loop of this operation. */ - void executePixelSampled(float output[4], float x, float y, PixelSampler sampler); + void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; - void initExecution(); - void deinitExecution(); + void initExecution() override; + void deinitExecution() override; void setSettings(NodeChroma *nodeChroma) { this->m_settings = nodeChroma; } }; + +} // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_DistanceYCCMatteOperation.cc b/source/blender/compositor/operations/COM_DistanceYCCMatteOperation.cc index f333cc1ecd9..15ed2b0aaa4 100644 --- a/source/blender/compositor/operations/COM_DistanceYCCMatteOperation.cc +++ b/source/blender/compositor/operations/COM_DistanceYCCMatteOperation.cc @@ -19,6 +19,8 @@ #include "COM_DistanceYCCMatteOperation.h" #include "BLI_math.h" +namespace blender::compositor { + DistanceYCCMatteOperation::DistanceYCCMatteOperation() { /* pass */ @@ -29,3 +31,5 @@ float DistanceYCCMatteOperation::calculateDistance(float key[4], float image[4]) /* only measure the second 2 values */ return len_v2v2(key + 1, image + 1); } + +} // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_DistanceYCCMatteOperation.h b/source/blender/compositor/operations/COM_DistanceYCCMatteOperation.h index e9b2cda6251..9027fbabe7b 100644 --- a/source/blender/compositor/operations/COM_DistanceYCCMatteOperation.h +++ b/source/blender/compositor/operations/COM_DistanceYCCMatteOperation.h @@ -21,13 +21,15 @@ #include "COM_DistanceRGBMatteOperation.h" #include "COM_MixOperation.h" +namespace blender::compositor { + /** * this program converts an input color to an output value. * it assumes we are in sRGB color space. */ class DistanceYCCMatteOperation : public DistanceRGBMatteOperation { protected: - virtual float calculateDistance(float key[4], float image[4]); + float calculateDistance(float key[4], float image[4]) override; public: /** @@ -35,3 +37,5 @@ class DistanceYCCMatteOperation : public DistanceRGBMatteOperation { */ DistanceYCCMatteOperation(); }; + +} // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_DotproductOperation.cc b/source/blender/compositor/operations/COM_DotproductOperation.cc index c5b89bb7fae..07075ae1d9d 100644 --- a/source/blender/compositor/operations/COM_DotproductOperation.cc +++ b/source/blender/compositor/operations/COM_DotproductOperation.cc @@ -18,6 +18,8 @@ #include "COM_DotproductOperation.h" +namespace blender::compositor { + DotproductOperation::DotproductOperation() { this->addInputSocket(DataType::Vector); @@ -52,3 +54,5 @@ void DotproductOperation::executePixelSampled(float output[4], this->m_input2Operation->readSampled(input2, x, y, sampler); output[0] = -(input1[0] * input2[0] + input1[1] * input2[1] + input1[2] * input2[2]); } + +} // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_DotproductOperation.h b/source/blender/compositor/operations/COM_DotproductOperation.h index 63b735ce30f..728033bcf32 100644 --- a/source/blender/compositor/operations/COM_DotproductOperation.h +++ b/source/blender/compositor/operations/COM_DotproductOperation.h @@ -20,6 +20,8 @@ #include "COM_NodeOperation.h" +namespace blender::compositor { + class DotproductOperation : public NodeOperation { private: SocketReader *m_input1Operation; @@ -27,8 +29,10 @@ class DotproductOperation : public NodeOperation { public: DotproductOperation(); - void executePixelSampled(float output[4], float x, float y, PixelSampler sampler); + void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; - void initExecution(); - void deinitExecution(); + void initExecution() override; + void deinitExecution() override; }; + +} // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_DoubleEdgeMaskOperation.cc b/source/blender/compositor/operations/COM_DoubleEdgeMaskOperation.cc index 4c7cbb3cc7e..a3a86a6c502 100644 --- a/source/blender/compositor/operations/COM_DoubleEdgeMaskOperation.cc +++ b/source/blender/compositor/operations/COM_DoubleEdgeMaskOperation.cc @@ -23,6 +23,8 @@ #include "DNA_node_types.h" #include "MEM_guardedalloc.h" +namespace blender::compositor { + // this part has been copied from the double edge mask static void do_adjacentKeepBorders(unsigned int t, unsigned int rw, @@ -1315,7 +1317,7 @@ DoubleEdgeMaskOperation::DoubleEdgeMaskOperation() this->m_inputOuterMask = nullptr; this->m_adjacentOnly = false; this->m_keepInside = false; - this->setComplex(true); + this->flags.complex = true; } bool DoubleEdgeMaskOperation::determineDependingAreaOfInterest(rcti * /*input*/, @@ -1379,3 +1381,5 @@ void DoubleEdgeMaskOperation::deinitExecution() this->m_cachedInstance = nullptr; } } + +} // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_DoubleEdgeMaskOperation.h b/source/blender/compositor/operations/COM_DoubleEdgeMaskOperation.h index 813f5009815..e956e8edc3e 100644 --- a/source/blender/compositor/operations/COM_DoubleEdgeMaskOperation.h +++ b/source/blender/compositor/operations/COM_DoubleEdgeMaskOperation.h @@ -20,6 +20,8 @@ #include "COM_NodeOperation.h" +namespace blender::compositor { + class DoubleEdgeMaskOperation : public NodeOperation { private: /** @@ -38,23 +40,23 @@ class DoubleEdgeMaskOperation : public NodeOperation { /** * The inner loop of this operation. */ - void executePixel(float output[4], int x, int y, void *data); + void executePixel(float output[4], int x, int y, void *data) override; /** * Initialize the execution */ - void initExecution(); + void initExecution() override; /** * Deinitialize the execution */ - void deinitExecution(); + void deinitExecution() override; - void *initializeTileData(rcti *rect); + void *initializeTileData(rcti *rect) override; bool determineDependingAreaOfInterest(rcti *input, ReadBufferOperation *readOperation, - rcti *output); + rcti *output) override; void setAdjecentOnly(bool adjacentOnly) { @@ -65,3 +67,5 @@ class DoubleEdgeMaskOperation : public NodeOperation { this->m_keepInside = keepInside; } }; + +} // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_EllipseMaskOperation.cc b/source/blender/compositor/operations/COM_EllipseMaskOperation.cc index 956b5e50edc..5a4503fecec 100644 --- a/source/blender/compositor/operations/COM_EllipseMaskOperation.cc +++ b/source/blender/compositor/operations/COM_EllipseMaskOperation.cc @@ -20,6 +20,8 @@ #include "BLI_math.h" #include "DNA_node_types.h" +namespace blender::compositor { + EllipseMaskOperation::EllipseMaskOperation() { this->addInputSocket(DataType::Value); @@ -117,3 +119,5 @@ void EllipseMaskOperation::deinitExecution() this->m_inputMask = nullptr; this->m_inputValue = nullptr; } + +} // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_EllipseMaskOperation.h b/source/blender/compositor/operations/COM_EllipseMaskOperation.h index 8fce7166900..64afe0145cf 100644 --- a/source/blender/compositor/operations/COM_EllipseMaskOperation.h +++ b/source/blender/compositor/operations/COM_EllipseMaskOperation.h @@ -20,6 +20,8 @@ #include "COM_NodeOperation.h" +namespace blender::compositor { + class EllipseMaskOperation : public NodeOperation { private: /** @@ -41,17 +43,17 @@ class EllipseMaskOperation : public NodeOperation { /** * The inner loop of this operation. */ - void executePixelSampled(float output[4], float x, float y, PixelSampler sampler); + void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; /** * Initialize the execution */ - void initExecution(); + void initExecution() override; /** * Deinitialize the execution */ - void deinitExecution(); + void deinitExecution() override; void setData(NodeEllipseMask *data) { @@ -63,3 +65,5 @@ class EllipseMaskOperation : public NodeOperation { this->m_maskType = maskType; } }; + +} // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_FastGaussianBlurOperation.cc b/source/blender/compositor/operations/COM_FastGaussianBlurOperation.cc index 4dded61fba5..2be6e4d1be7 100644 --- a/source/blender/compositor/operations/COM_FastGaussianBlurOperation.cc +++ b/source/blender/compositor/operations/COM_FastGaussianBlurOperation.cc @@ -22,6 +22,8 @@ #include "COM_FastGaussianBlurOperation.h" #include "MEM_guardedalloc.h" +namespace blender::compositor { + FastGaussianBlurOperation::FastGaussianBlurOperation() : BlurBaseOperation(DataType::Color) { this->m_iirgaus = nullptr; @@ -88,18 +90,18 @@ void *FastGaussianBlurOperation::initializeTileData(rcti *rect) this->m_sy = this->m_data.sizey * this->m_size / 2.0f; if ((this->m_sx == this->m_sy) && (this->m_sx > 0.0f)) { - for (c = 0; c < COM_NUM_CHANNELS_COLOR; c++) { + for (c = 0; c < COM_DATA_TYPE_COLOR_CHANNELS; c++) { IIR_gauss(copy, this->m_sx, c, 3); } } else { if (this->m_sx > 0.0f) { - for (c = 0; c < COM_NUM_CHANNELS_COLOR; c++) { + for (c = 0; c < COM_DATA_TYPE_COLOR_CHANNELS; c++) { IIR_gauss(copy, this->m_sx, c, 1); } } if (this->m_sy > 0.0f) { - for (c = 0; c < COM_NUM_CHANNELS_COLOR; c++) { + for (c = 0; c < COM_DATA_TYPE_COLOR_CHANNELS; c++) { IIR_gauss(copy, this->m_sy, c, 2); } } @@ -264,7 +266,7 @@ FastGaussianBlurValueOperation::FastGaussianBlurValueOperation() this->m_inputprogram = nullptr; this->m_sigma = 1.0f; this->m_overlay = 0; - setComplex(true); + flags.complex = true; } void FastGaussianBlurValueOperation::executePixel(float output[4], int x, int y, void *data) @@ -317,7 +319,7 @@ void *FastGaussianBlurValueOperation::initializeTileData(rcti *rect) float *src = newBuf->getBuffer(); float *dst = copy->getBuffer(); for (int i = copy->getWidth() * copy->getHeight(); i != 0; - i--, src += COM_NUM_CHANNELS_VALUE, dst += COM_NUM_CHANNELS_VALUE) { + i--, src += COM_DATA_TYPE_VALUE_CHANNELS, dst += COM_DATA_TYPE_VALUE_CHANNELS) { if (*src < *dst) { *dst = *src; } @@ -327,7 +329,7 @@ void *FastGaussianBlurValueOperation::initializeTileData(rcti *rect) float *src = newBuf->getBuffer(); float *dst = copy->getBuffer(); for (int i = copy->getWidth() * copy->getHeight(); i != 0; - i--, src += COM_NUM_CHANNELS_VALUE, dst += COM_NUM_CHANNELS_VALUE) { + i--, src += COM_DATA_TYPE_VALUE_CHANNELS, dst += COM_DATA_TYPE_VALUE_CHANNELS) { if (*src > *dst) { *dst = *src; } @@ -341,3 +343,5 @@ void *FastGaussianBlurValueOperation::initializeTileData(rcti *rect) unlockMutex(); return this->m_iirgaus; } + +} // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_FastGaussianBlurOperation.h b/source/blender/compositor/operations/COM_FastGaussianBlurOperation.h index 6ab6474c20a..c25afe6c4a4 100644 --- a/source/blender/compositor/operations/COM_FastGaussianBlurOperation.h +++ b/source/blender/compositor/operations/COM_FastGaussianBlurOperation.h @@ -21,6 +21,8 @@ #include "COM_BlurBaseOperation.h" #include "DNA_node_types.h" +namespace blender::compositor { + class FastGaussianBlurOperation : public BlurBaseOperation { private: float m_sx; @@ -31,13 +33,13 @@ class FastGaussianBlurOperation : public BlurBaseOperation { FastGaussianBlurOperation(); bool determineDependingAreaOfInterest(rcti *input, ReadBufferOperation *readOperation, - rcti *output); - void executePixel(float output[4], int x, int y, void *data); + rcti *output) override; + void executePixel(float output[4], int x, int y, void *data) override; static void IIR_gauss(MemoryBuffer *src, float sigma, unsigned int channel, unsigned int xy); - void *initializeTileData(rcti *rect); - void deinitExecution(); - void initExecution(); + void *initializeTileData(rcti *rect) override; + void deinitExecution() override; + void initExecution() override; }; enum { @@ -62,12 +64,12 @@ class FastGaussianBlurValueOperation : public NodeOperation { FastGaussianBlurValueOperation(); bool determineDependingAreaOfInterest(rcti *input, ReadBufferOperation *readOperation, - rcti *output); - void executePixel(float output[4], int x, int y, void *data); + rcti *output) override; + void executePixel(float output[4], int x, int y, void *data) override; - void *initializeTileData(rcti *rect); - void deinitExecution(); - void initExecution(); + void *initializeTileData(rcti *rect) override; + void deinitExecution() override; + void initExecution() override; void setSigma(float sigma) { this->m_sigma = sigma; @@ -79,3 +81,5 @@ class FastGaussianBlurValueOperation : public NodeOperation { this->m_overlay = overlay; } }; + +} // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_FlipOperation.cc b/source/blender/compositor/operations/COM_FlipOperation.cc index 4837766b5eb..8afbec4ddbe 100644 --- a/source/blender/compositor/operations/COM_FlipOperation.cc +++ b/source/blender/compositor/operations/COM_FlipOperation.cc @@ -18,6 +18,8 @@ #include "COM_FlipOperation.h" +namespace blender::compositor { + FlipOperation::FlipOperation() { this->addInputSocket(DataType::Color); @@ -72,3 +74,5 @@ bool FlipOperation::determineDependingAreaOfInterest(rcti *input, return NodeOperation::determineDependingAreaOfInterest(&newInput, readOperation, output); } + +} // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_FlipOperation.h b/source/blender/compositor/operations/COM_FlipOperation.h index 711b51261e6..f26d587fde6 100644 --- a/source/blender/compositor/operations/COM_FlipOperation.h +++ b/source/blender/compositor/operations/COM_FlipOperation.h @@ -20,6 +20,8 @@ #include "COM_NodeOperation.h" +namespace blender::compositor { + class FlipOperation : public NodeOperation { private: SocketReader *m_inputOperation; @@ -30,11 +32,11 @@ class FlipOperation : public NodeOperation { FlipOperation(); bool determineDependingAreaOfInterest(rcti *input, ReadBufferOperation *readOperation, - rcti *output); - void executePixelSampled(float output[4], float x, float y, PixelSampler sampler); + rcti *output) override; + void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; - void initExecution(); - void deinitExecution(); + void initExecution() override; + void deinitExecution() override; void setFlipX(bool flipX) { this->m_flipX = flipX; @@ -44,3 +46,5 @@ class FlipOperation : public NodeOperation { this->m_flipY = flipY; } }; + +} // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_GammaCorrectOperation.cc b/source/blender/compositor/operations/COM_GammaCorrectOperation.cc index 51c033498ef..16b79fddd06 100644 --- a/source/blender/compositor/operations/COM_GammaCorrectOperation.cc +++ b/source/blender/compositor/operations/COM_GammaCorrectOperation.cc @@ -19,6 +19,8 @@ #include "COM_GammaCorrectOperation.h" #include "BLI_math.h" +namespace blender::compositor { + GammaCorrectOperation::GammaCorrectOperation() { this->addInputSocket(DataType::Color); @@ -102,3 +104,5 @@ void GammaUncorrectOperation::deinitExecution() { this->m_inputProgram = nullptr; } + +} // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_GammaCorrectOperation.h b/source/blender/compositor/operations/COM_GammaCorrectOperation.h index 077493bbd2f..ac3d45b94b1 100644 --- a/source/blender/compositor/operations/COM_GammaCorrectOperation.h +++ b/source/blender/compositor/operations/COM_GammaCorrectOperation.h @@ -20,6 +20,8 @@ #include "COM_NodeOperation.h" +namespace blender::compositor { + class GammaCorrectOperation : public NodeOperation { private: /** @@ -33,17 +35,17 @@ class GammaCorrectOperation : public NodeOperation { /** * The inner loop of this operation. */ - void executePixelSampled(float output[4], float x, float y, PixelSampler sampler); + void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; /** * Initialize the execution */ - void initExecution(); + void initExecution() override; /** * Deinitialize the execution */ - void deinitExecution(); + void deinitExecution() override; }; class GammaUncorrectOperation : public NodeOperation { @@ -59,15 +61,17 @@ class GammaUncorrectOperation : public NodeOperation { /** * The inner loop of this operation. */ - void executePixelSampled(float output[4], float x, float y, PixelSampler sampler); + void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; /** * Initialize the execution */ - void initExecution(); + void initExecution() override; /** * Deinitialize the execution */ - void deinitExecution(); + void deinitExecution() override; }; + +} // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_GammaOperation.cc b/source/blender/compositor/operations/COM_GammaOperation.cc index 327c5c24929..343e335070a 100644 --- a/source/blender/compositor/operations/COM_GammaOperation.cc +++ b/source/blender/compositor/operations/COM_GammaOperation.cc @@ -19,6 +19,8 @@ #include "COM_GammaOperation.h" #include "BLI_math.h" +namespace blender::compositor { + GammaOperation::GammaOperation() { this->addInputSocket(DataType::Color); @@ -54,3 +56,5 @@ void GammaOperation::deinitExecution() this->m_inputProgram = nullptr; this->m_inputGammaProgram = nullptr; } + +} // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_GammaOperation.h b/source/blender/compositor/operations/COM_GammaOperation.h index 8641f2fde62..034046106d6 100644 --- a/source/blender/compositor/operations/COM_GammaOperation.h +++ b/source/blender/compositor/operations/COM_GammaOperation.h @@ -20,6 +20,8 @@ #include "COM_NodeOperation.h" +namespace blender::compositor { + class GammaOperation : public NodeOperation { private: /** @@ -34,15 +36,17 @@ class GammaOperation : public NodeOperation { /** * The inner loop of this operation. */ - void executePixelSampled(float output[4], float x, float y, PixelSampler sampler); + void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; /** * Initialize the execution */ - void initExecution(); + void initExecution() override; /** * Deinitialize the execution */ - void deinitExecution(); + void deinitExecution() override; }; + +} // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_GaussianAlphaXBlurOperation.cc b/source/blender/compositor/operations/COM_GaussianAlphaXBlurOperation.cc index 1f03bb8d9cb..7ca5dc4ca76 100644 --- a/source/blender/compositor/operations/COM_GaussianAlphaXBlurOperation.cc +++ b/source/blender/compositor/operations/COM_GaussianAlphaXBlurOperation.cc @@ -22,6 +22,8 @@ #include "RE_pipeline.h" +namespace blender::compositor { + GaussianAlphaXBlurOperation::GaussianAlphaXBlurOperation() : BlurBaseOperation(DataType::Value) { this->m_gausstab = nullptr; @@ -190,3 +192,5 @@ bool GaussianAlphaXBlurOperation::determineDependingAreaOfInterest( return NodeOperation::determineDependingAreaOfInterest(&newInput, readOperation, output); } } + +} // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_GaussianAlphaXBlurOperation.h b/source/blender/compositor/operations/COM_GaussianAlphaXBlurOperation.h index 2d536a98bee..949956fae04 100644 --- a/source/blender/compositor/operations/COM_GaussianAlphaXBlurOperation.h +++ b/source/blender/compositor/operations/COM_GaussianAlphaXBlurOperation.h @@ -21,6 +21,8 @@ #include "COM_BlurBaseOperation.h" #include "COM_NodeOperation.h" +namespace blender::compositor { + class GaussianAlphaXBlurOperation : public BlurBaseOperation { private: float *m_gausstab; @@ -36,22 +38,22 @@ class GaussianAlphaXBlurOperation : public BlurBaseOperation { /** * \brief The inner loop of this operation. */ - void executePixel(float output[4], int x, int y, void *data); + void executePixel(float output[4], int x, int y, void *data) override; /** * \brief initialize the execution */ - void initExecution(); + void initExecution() override; /** * \brief Deinitialize the execution */ - void deinitExecution(); + void deinitExecution() override; - void *initializeTileData(rcti *rect); + void *initializeTileData(rcti *rect) override; bool determineDependingAreaOfInterest(rcti *input, ReadBufferOperation *readOperation, - rcti *output); + rcti *output) override; /** * Set subtract for Dilate/Erode functionality @@ -65,3 +67,5 @@ class GaussianAlphaXBlurOperation : public BlurBaseOperation { this->m_falloff = falloff; } }; + +} // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_GaussianAlphaYBlurOperation.cc b/source/blender/compositor/operations/COM_GaussianAlphaYBlurOperation.cc index de35c164fc7..d2385a972dd 100644 --- a/source/blender/compositor/operations/COM_GaussianAlphaYBlurOperation.cc +++ b/source/blender/compositor/operations/COM_GaussianAlphaYBlurOperation.cc @@ -22,6 +22,8 @@ #include "RE_pipeline.h" +namespace blender::compositor { + GaussianAlphaYBlurOperation::GaussianAlphaYBlurOperation() : BlurBaseOperation(DataType::Value) { this->m_gausstab = nullptr; @@ -189,3 +191,5 @@ bool GaussianAlphaYBlurOperation::determineDependingAreaOfInterest( return NodeOperation::determineDependingAreaOfInterest(&newInput, readOperation, output); } } + +} // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_GaussianAlphaYBlurOperation.h b/source/blender/compositor/operations/COM_GaussianAlphaYBlurOperation.h index 7f1dfd78e7c..d25770386c4 100644 --- a/source/blender/compositor/operations/COM_GaussianAlphaYBlurOperation.h +++ b/source/blender/compositor/operations/COM_GaussianAlphaYBlurOperation.h @@ -21,6 +21,8 @@ #include "COM_BlurBaseOperation.h" #include "COM_NodeOperation.h" +namespace blender::compositor { + class GaussianAlphaYBlurOperation : public BlurBaseOperation { private: float *m_gausstab; @@ -36,22 +38,22 @@ class GaussianAlphaYBlurOperation : public BlurBaseOperation { /** * The inner loop of this operation. */ - void executePixel(float output[4], int x, int y, void *data); + void executePixel(float output[4], int x, int y, void *data) override; /** * \brief initialize the execution */ - void initExecution(); + void initExecution() override; /** * Deinitialize the execution */ - void deinitExecution(); + void deinitExecution() override; - void *initializeTileData(rcti *rect); + void *initializeTileData(rcti *rect) override; bool determineDependingAreaOfInterest(rcti *input, ReadBufferOperation *readOperation, - rcti *output); + rcti *output) override; /** * Set subtract for Dilate/Erode functionality @@ -65,3 +67,5 @@ class GaussianAlphaYBlurOperation : public BlurBaseOperation { this->m_falloff = falloff; } }; + +} // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_GaussianBokehBlurOperation.cc b/source/blender/compositor/operations/COM_GaussianBokehBlurOperation.cc index 73b0914c086..b2c65ff2c96 100644 --- a/source/blender/compositor/operations/COM_GaussianBokehBlurOperation.cc +++ b/source/blender/compositor/operations/COM_GaussianBokehBlurOperation.cc @@ -22,6 +22,8 @@ #include "RE_pipeline.h" +namespace blender::compositor { + GaussianBokehBlurOperation::GaussianBokehBlurOperation() : BlurBaseOperation(DataType::Color) { this->m_gausstab = nullptr; @@ -303,7 +305,7 @@ void GaussianBlurReferenceOperation::executePixel(float output[4], int x, int y, int minyr = y - refrady < 0 ? -y : -refrady; int maxyr = y + refrady > imgy ? imgy - y : refrady; - float *srcd = buffer + COM_NUM_CHANNELS_COLOR * ((y + minyr) * imgx + x + minxr); + float *srcd = buffer + COM_DATA_TYPE_COLOR_CHANNELS * ((y + minyr) * imgx + x + minxr); gausstabx = m_maintabs[refradx - 1]; gausstabcentx = gausstabx + refradx; @@ -311,9 +313,9 @@ void GaussianBlurReferenceOperation::executePixel(float output[4], int x, int y, gausstabcenty = gausstaby + refrady; sum = gval = rval = bval = aval = 0.0f; - for (i = minyr; i < maxyr; i++, srcd += COM_NUM_CHANNELS_COLOR * imgx) { + for (i = minyr; i < maxyr; i++, srcd += COM_DATA_TYPE_COLOR_CHANNELS * imgx) { src = srcd; - for (j = minxr; j < maxxr; j++, src += COM_NUM_CHANNELS_COLOR) { + for (j = minxr; j < maxxr; j++, src += COM_DATA_TYPE_COLOR_CHANNELS) { val = gausstabcenty[i] * gausstabcentx[j]; sum += val; @@ -360,3 +362,5 @@ bool GaussianBlurReferenceOperation::determineDependingAreaOfInterest( newInput.ymin = input->ymin - addy; return NodeOperation::determineDependingAreaOfInterest(&newInput, readOperation, output); } + +} // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_GaussianBokehBlurOperation.h b/source/blender/compositor/operations/COM_GaussianBokehBlurOperation.h index a37a70b4b33..59ba3d06619 100644 --- a/source/blender/compositor/operations/COM_GaussianBokehBlurOperation.h +++ b/source/blender/compositor/operations/COM_GaussianBokehBlurOperation.h @@ -22,6 +22,8 @@ #include "COM_NodeOperation.h" #include "COM_QualityStepHelper.h" +namespace blender::compositor { + class GaussianBokehBlurOperation : public BlurBaseOperation { private: float *m_gausstab; @@ -30,21 +32,21 @@ class GaussianBokehBlurOperation : public BlurBaseOperation { public: GaussianBokehBlurOperation(); - void initExecution(); - void *initializeTileData(rcti *rect); + void initExecution() override; + void *initializeTileData(rcti *rect) override; /** * The inner loop of this operation. */ - void executePixel(float output[4], int x, int y, void *data); + void executePixel(float output[4], int x, int y, void *data) override; /** * Deinitialize the execution */ - void deinitExecution(); + void deinitExecution() override; bool determineDependingAreaOfInterest(rcti *input, ReadBufferOperation *readOperation, - rcti *output); + rcti *output) override; }; class GaussianBlurReferenceOperation : public BlurBaseOperation { @@ -59,19 +61,21 @@ class GaussianBlurReferenceOperation : public BlurBaseOperation { public: GaussianBlurReferenceOperation(); - void initExecution(); - void *initializeTileData(rcti *rect); + void initExecution() override; + void *initializeTileData(rcti *rect) override; /** * The inner loop of this operation. */ - void executePixel(float output[4], int x, int y, void *data); + void executePixel(float output[4], int x, int y, void *data) override; /** * Deinitialize the execution */ - void deinitExecution(); + void deinitExecution() override; bool determineDependingAreaOfInterest(rcti *input, ReadBufferOperation *readOperation, - rcti *output); + rcti *output) override; }; + +} // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_GaussianXBlurOperation.cc b/source/blender/compositor/operations/COM_GaussianXBlurOperation.cc index 43bf961cfc4..4b46cfc8776 100644 --- a/source/blender/compositor/operations/COM_GaussianXBlurOperation.cc +++ b/source/blender/compositor/operations/COM_GaussianXBlurOperation.cc @@ -23,6 +23,8 @@ #include "RE_pipeline.h" +namespace blender::compositor { + GaussianXBlurOperation::GaussianXBlurOperation() : BlurBaseOperation(DataType::Color) { this->m_gausstab = nullptr; @@ -205,3 +207,5 @@ bool GaussianXBlurOperation::determineDependingAreaOfInterest(rcti *input, return NodeOperation::determineDependingAreaOfInterest(&newInput, readOperation, output); } } + +} // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_GaussianXBlurOperation.h b/source/blender/compositor/operations/COM_GaussianXBlurOperation.h index 78ea6aa3cc2..15277f0a42d 100644 --- a/source/blender/compositor/operations/COM_GaussianXBlurOperation.h +++ b/source/blender/compositor/operations/COM_GaussianXBlurOperation.h @@ -21,6 +21,8 @@ #include "COM_BlurBaseOperation.h" #include "COM_NodeOperation.h" +namespace blender::compositor { + class GaussianXBlurOperation : public BlurBaseOperation { private: float *m_gausstab; @@ -36,32 +38,34 @@ class GaussianXBlurOperation : public BlurBaseOperation { /** * \brief The inner loop of this operation. */ - void executePixel(float output[4], int x, int y, void *data); + void executePixel(float output[4], int x, int y, void *data) override; void executeOpenCL(OpenCLDevice *device, MemoryBuffer *outputMemoryBuffer, cl_mem clOutputBuffer, MemoryBuffer **inputMemoryBuffers, std::list<cl_mem> *clMemToCleanUp, - std::list<cl_kernel> *clKernelsToCleanUp); + std::list<cl_kernel> *clKernelsToCleanUp) override; /** * \brief initialize the execution */ - void initExecution(); + void initExecution() override; /** * \brief Deinitialize the execution */ - void deinitExecution(); + void deinitExecution() override; - void *initializeTileData(rcti *rect); + void *initializeTileData(rcti *rect) override; bool determineDependingAreaOfInterest(rcti *input, ReadBufferOperation *readOperation, - rcti *output); + rcti *output) override; void checkOpenCL() { - this->setOpenCL(m_data.sizex >= 128); + flags.open_cl = (m_data.sizex >= 128); } }; + +} // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_GaussianYBlurOperation.cc b/source/blender/compositor/operations/COM_GaussianYBlurOperation.cc index 1e853dfb8f9..590ac5faa6a 100644 --- a/source/blender/compositor/operations/COM_GaussianYBlurOperation.cc +++ b/source/blender/compositor/operations/COM_GaussianYBlurOperation.cc @@ -23,6 +23,8 @@ #include "RE_pipeline.h" +namespace blender::compositor { + GaussianYBlurOperation::GaussianYBlurOperation() : BlurBaseOperation(DataType::Color) { this->m_gausstab = nullptr; @@ -205,3 +207,5 @@ bool GaussianYBlurOperation::determineDependingAreaOfInterest(rcti *input, return NodeOperation::determineDependingAreaOfInterest(&newInput, readOperation, output); } } + +} // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_GaussianYBlurOperation.h b/source/blender/compositor/operations/COM_GaussianYBlurOperation.h index 8e7440b6fe4..56d40849ba4 100644 --- a/source/blender/compositor/operations/COM_GaussianYBlurOperation.h +++ b/source/blender/compositor/operations/COM_GaussianYBlurOperation.h @@ -21,6 +21,8 @@ #include "COM_BlurBaseOperation.h" #include "COM_NodeOperation.h" +namespace blender::compositor { + class GaussianYBlurOperation : public BlurBaseOperation { private: float *m_gausstab; @@ -36,32 +38,34 @@ class GaussianYBlurOperation : public BlurBaseOperation { /** * The inner loop of this operation. */ - void executePixel(float output[4], int x, int y, void *data); + void executePixel(float output[4], int x, int y, void *data) override; void executeOpenCL(OpenCLDevice *device, MemoryBuffer *outputMemoryBuffer, cl_mem clOutputBuffer, MemoryBuffer **inputMemoryBuffers, std::list<cl_mem> *clMemToCleanUp, - std::list<cl_kernel> *clKernelsToCleanUp); + std::list<cl_kernel> *clKernelsToCleanUp) override; /** * \brief initialize the execution */ - void initExecution(); + void initExecution() override; /** * Deinitialize the execution */ - void deinitExecution(); + void deinitExecution() override; - void *initializeTileData(rcti *rect); + void *initializeTileData(rcti *rect) override; bool determineDependingAreaOfInterest(rcti *input, ReadBufferOperation *readOperation, - rcti *output); + rcti *output) override; void checkOpenCL() { - this->setOpenCL(m_data.sizex >= 128); + flags.open_cl = (m_data.sizex >= 128); } }; + +} // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_GlareBaseOperation.cc b/source/blender/compositor/operations/COM_GlareBaseOperation.cc index cdf64ed8b5a..90755d9f27a 100644 --- a/source/blender/compositor/operations/COM_GlareBaseOperation.cc +++ b/source/blender/compositor/operations/COM_GlareBaseOperation.cc @@ -19,6 +19,8 @@ #include "COM_GlareBaseOperation.h" #include "BLI_math.h" +namespace blender::compositor { + GlareBaseOperation::GlareBaseOperation() { this->addInputSocket(DataType::Color); @@ -66,3 +68,5 @@ bool GlareBaseOperation::determineDependingAreaOfInterest(rcti * /*input*/, newInput.ymin = 0; return NodeOperation::determineDependingAreaOfInterest(&newInput, readOperation, output); } + +} // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_GlareBaseOperation.h b/source/blender/compositor/operations/COM_GlareBaseOperation.h index aabb76f5cf0..7ae15595e3b 100644 --- a/source/blender/compositor/operations/COM_GlareBaseOperation.h +++ b/source/blender/compositor/operations/COM_GlareBaseOperation.h @@ -21,6 +21,8 @@ #include "COM_SingleThreadedOperation.h" #include "DNA_node_types.h" +namespace blender::compositor { + /* utility functions used by glare, tonemap and lens distortion */ /* soms macros for color handling */ typedef float fRGB[4]; @@ -51,12 +53,12 @@ class GlareBaseOperation : public SingleThreadedOperation { /** * Initialize the execution */ - void initExecution(); + void initExecution() override; /** * Deinitialize the execution */ - void deinitExecution(); + void deinitExecution() override; void setGlareSettings(NodeGlare *settings) { @@ -64,12 +66,14 @@ class GlareBaseOperation : public SingleThreadedOperation { } bool determineDependingAreaOfInterest(rcti *input, ReadBufferOperation *readOperation, - rcti *output); + rcti *output) override; protected: GlareBaseOperation(); virtual void generateGlare(float *data, MemoryBuffer *inputTile, NodeGlare *settings) = 0; - MemoryBuffer *createMemoryBuffer(rcti *rect); + MemoryBuffer *createMemoryBuffer(rcti *rect) override; }; + +} // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_GlareFogGlowOperation.cc b/source/blender/compositor/operations/COM_GlareFogGlowOperation.cc index 23dfc95f9e3..1c1eaebd331 100644 --- a/source/blender/compositor/operations/COM_GlareFogGlowOperation.cc +++ b/source/blender/compositor/operations/COM_GlareFogGlowOperation.cc @@ -19,6 +19,8 @@ #include "COM_GlareFogGlowOperation.h" #include "MEM_guardedalloc.h" +namespace blender::compositor { + /* * 2D Fast Hartley Transform, used for convolution */ @@ -271,7 +273,7 @@ static void convolve(float *dst, MemoryBuffer *in1, MemoryBuffer *in2) MemoryBuffer *rdst = new MemoryBuffer(DataType::Color, in1->get_rect()); memset(rdst->getBuffer(), 0, - rdst->getWidth() * rdst->getHeight() * COM_NUM_CHANNELS_COLOR * sizeof(float)); + rdst->getWidth() * rdst->getHeight() * COM_DATA_TYPE_COLOR_CHANNELS * sizeof(float)); // convolution result width & height w2 = 2 * kernelWidth - 1; @@ -287,7 +289,7 @@ static void convolve(float *dst, MemoryBuffer *in1, MemoryBuffer *in2) // normalize convolutor wt[0] = wt[1] = wt[2] = 0.0f; for (y = 0; y < kernelHeight; y++) { - colp = (fRGB *)&kernelBuffer[y * kernelWidth * COM_NUM_CHANNELS_COLOR]; + colp = (fRGB *)&kernelBuffer[y * kernelWidth * COM_DATA_TYPE_COLOR_CHANNELS]; for (x = 0; x < kernelWidth; x++) { add_v3_v3(wt, colp[x]); } @@ -302,7 +304,7 @@ static void convolve(float *dst, MemoryBuffer *in1, MemoryBuffer *in2) wt[2] = 1.0f / wt[2]; } for (y = 0; y < kernelHeight; y++) { - colp = (fRGB *)&kernelBuffer[y * kernelWidth * COM_NUM_CHANNELS_COLOR]; + colp = (fRGB *)&kernelBuffer[y * kernelWidth * COM_DATA_TYPE_COLOR_CHANNELS]; for (x = 0; x < kernelWidth; x++) { mul_v3_v3(colp[x], wt); } @@ -336,7 +338,7 @@ static void convolve(float *dst, MemoryBuffer *in1, MemoryBuffer *in2) // in2, channel ch -> data1 for (y = 0; y < kernelHeight; y++) { fp = &data1ch[y * w2]; - colp = (fRGB *)&kernelBuffer[y * kernelWidth * COM_NUM_CHANNELS_COLOR]; + colp = (fRGB *)&kernelBuffer[y * kernelWidth * COM_DATA_TYPE_COLOR_CHANNELS]; for (x = 0; x < kernelWidth; x++) { fp[x] = colp[x][ch]; } @@ -351,7 +353,7 @@ static void convolve(float *dst, MemoryBuffer *in1, MemoryBuffer *in2) continue; } fp = &data2[y * w2]; - colp = (fRGB *)&imageBuffer[yy * imageWidth * COM_NUM_CHANNELS_COLOR]; + colp = (fRGB *)&imageBuffer[yy * imageWidth * COM_DATA_TYPE_COLOR_CHANNELS]; for (x = 0; x < xbsz; x++) { int xx = xbl * xbsz + x; if (xx >= imageWidth) { @@ -381,7 +383,7 @@ static void convolve(float *dst, MemoryBuffer *in1, MemoryBuffer *in2) continue; } fp = &data2[y * w2]; - colp = (fRGB *)&rdst->getBuffer()[yy * imageWidth * COM_NUM_CHANNELS_COLOR]; + colp = (fRGB *)&rdst->getBuffer()[yy * imageWidth * COM_DATA_TYPE_COLOR_CHANNELS]; for (x = 0; x < (int)w2; x++) { const int xx = xbl * xbsz + x - hw; if ((xx < 0) || (xx >= imageWidth)) { @@ -397,8 +399,9 @@ static void convolve(float *dst, MemoryBuffer *in1, MemoryBuffer *in2) MEM_freeN(data2); MEM_freeN(data1); - memcpy( - dst, rdst->getBuffer(), sizeof(float) * imageWidth * imageHeight * COM_NUM_CHANNELS_COLOR); + memcpy(dst, + rdst->getBuffer(), + sizeof(float) * imageWidth * imageHeight * COM_DATA_TYPE_COLOR_CHANNELS); delete (rdst); } @@ -442,3 +445,5 @@ void GlareFogGlowOperation::generateGlare(float *data, convolve(data, inputTile, ckrn); delete ckrn; } + +} // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_GlareFogGlowOperation.h b/source/blender/compositor/operations/COM_GlareFogGlowOperation.h index 9084f27052e..5701f76ab13 100644 --- a/source/blender/compositor/operations/COM_GlareFogGlowOperation.h +++ b/source/blender/compositor/operations/COM_GlareFogGlowOperation.h @@ -22,6 +22,8 @@ #include "COM_NodeOperation.h" #include "DNA_node_types.h" +namespace blender::compositor { + class GlareFogGlowOperation : public GlareBaseOperation { public: GlareFogGlowOperation() : GlareBaseOperation() @@ -29,5 +31,7 @@ class GlareFogGlowOperation : public GlareBaseOperation { } protected: - void generateGlare(float *data, MemoryBuffer *inputTile, NodeGlare *settings); + void generateGlare(float *data, MemoryBuffer *inputTile, NodeGlare *settings) override; }; + +} // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_GlareGhostOperation.cc b/source/blender/compositor/operations/COM_GlareGhostOperation.cc index a4cd6dc60c1..22c8767632e 100644 --- a/source/blender/compositor/operations/COM_GlareGhostOperation.cc +++ b/source/blender/compositor/operations/COM_GlareGhostOperation.cc @@ -20,6 +20,8 @@ #include "BLI_math.h" #include "COM_FastGaussianBlurOperation.h" +namespace blender::compositor { + static float smoothMask(float x, float y) { float t; @@ -123,7 +125,7 @@ void GlareGhostOperation::generateGlare(float *data, MemoryBuffer *inputTile, No memset(tbuf1.getBuffer(), 0, - tbuf1.getWidth() * tbuf1.getHeight() * COM_NUM_CHANNELS_COLOR * sizeof(float)); + tbuf1.getWidth() * tbuf1.getHeight() * COM_DATA_TYPE_COLOR_CHANNELS * sizeof(float)); for (n = 1; n < settings->iter && (!breaked); n++) { for (y = 0; y < gbuf.getHeight() && (!breaked); y++) { v = ((float)y + 0.5f) / (float)gbuf.getHeight(); @@ -147,9 +149,11 @@ void GlareGhostOperation::generateGlare(float *data, MemoryBuffer *inputTile, No } memcpy(gbuf.getBuffer(), tbuf1.getBuffer(), - tbuf1.getWidth() * tbuf1.getHeight() * COM_NUM_CHANNELS_COLOR * sizeof(float)); + tbuf1.getWidth() * tbuf1.getHeight() * COM_DATA_TYPE_COLOR_CHANNELS * sizeof(float)); } memcpy(data, gbuf.getBuffer(), - gbuf.getWidth() * gbuf.getHeight() * COM_NUM_CHANNELS_COLOR * sizeof(float)); + gbuf.getWidth() * gbuf.getHeight() * COM_DATA_TYPE_COLOR_CHANNELS * sizeof(float)); } + +} // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_GlareGhostOperation.h b/source/blender/compositor/operations/COM_GlareGhostOperation.h index 8ecf8da3385..60256d8e0ef 100644 --- a/source/blender/compositor/operations/COM_GlareGhostOperation.h +++ b/source/blender/compositor/operations/COM_GlareGhostOperation.h @@ -22,6 +22,8 @@ #include "COM_NodeOperation.h" #include "DNA_node_types.h" +namespace blender::compositor { + class GlareGhostOperation : public GlareBaseOperation { public: GlareGhostOperation() : GlareBaseOperation() @@ -29,5 +31,7 @@ class GlareGhostOperation : public GlareBaseOperation { } protected: - void generateGlare(float *data, MemoryBuffer *inputTile, NodeGlare *settings); + void generateGlare(float *data, MemoryBuffer *inputTile, NodeGlare *settings) override; }; + +} // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_GlareSimpleStarOperation.cc b/source/blender/compositor/operations/COM_GlareSimpleStarOperation.cc index a2cecb7e171..cc24a50a307 100644 --- a/source/blender/compositor/operations/COM_GlareSimpleStarOperation.cc +++ b/source/blender/compositor/operations/COM_GlareSimpleStarOperation.cc @@ -18,6 +18,8 @@ #include "COM_GlareSimpleStarOperation.h" +namespace blender::compositor { + void GlareSimpleStarOperation::generateGlare(float *data, MemoryBuffer *inputTile, NodeGlare *settings) @@ -97,3 +99,5 @@ void GlareSimpleStarOperation::generateGlare(float *data, data[i] = tbuf1.getBuffer()[i] + tbuf2.getBuffer()[i]; } } + +} // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_GlareSimpleStarOperation.h b/source/blender/compositor/operations/COM_GlareSimpleStarOperation.h index 0f5913fcef9..4a074f53e7b 100644 --- a/source/blender/compositor/operations/COM_GlareSimpleStarOperation.h +++ b/source/blender/compositor/operations/COM_GlareSimpleStarOperation.h @@ -22,6 +22,8 @@ #include "COM_NodeOperation.h" #include "DNA_node_types.h" +namespace blender::compositor { + class GlareSimpleStarOperation : public GlareBaseOperation { public: GlareSimpleStarOperation() : GlareBaseOperation() @@ -29,5 +31,7 @@ class GlareSimpleStarOperation : public GlareBaseOperation { } protected: - void generateGlare(float *data, MemoryBuffer *inputTile, NodeGlare *settings); + void generateGlare(float *data, MemoryBuffer *inputTile, NodeGlare *settings) override; }; + +} // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_GlareStreaksOperation.cc b/source/blender/compositor/operations/COM_GlareStreaksOperation.cc index 0ea277881da..0af4eb43624 100644 --- a/source/blender/compositor/operations/COM_GlareStreaksOperation.cc +++ b/source/blender/compositor/operations/COM_GlareStreaksOperation.cc @@ -19,6 +19,8 @@ #include "COM_GlareStreaksOperation.h" #include "BLI_math.h" +namespace blender::compositor { + void GlareStreaksOperation::generateGlare(float *data, MemoryBuffer *inputTile, NodeGlare *settings) @@ -97,3 +99,5 @@ void GlareStreaksOperation::generateGlare(float *data, nump++; } } + +} // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_GlareStreaksOperation.h b/source/blender/compositor/operations/COM_GlareStreaksOperation.h index df31981170d..487c910960a 100644 --- a/source/blender/compositor/operations/COM_GlareStreaksOperation.h +++ b/source/blender/compositor/operations/COM_GlareStreaksOperation.h @@ -22,6 +22,8 @@ #include "COM_NodeOperation.h" #include "DNA_node_types.h" +namespace blender::compositor { + class GlareStreaksOperation : public GlareBaseOperation { public: GlareStreaksOperation() : GlareBaseOperation() @@ -29,5 +31,7 @@ class GlareStreaksOperation : public GlareBaseOperation { } protected: - void generateGlare(float *data, MemoryBuffer *inputTile, NodeGlare *settings); + void generateGlare(float *data, MemoryBuffer *inputTile, NodeGlare *settings) override; }; + +} // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_GlareThresholdOperation.cc b/source/blender/compositor/operations/COM_GlareThresholdOperation.cc index 984b433469a..1d3402f5b7b 100644 --- a/source/blender/compositor/operations/COM_GlareThresholdOperation.cc +++ b/source/blender/compositor/operations/COM_GlareThresholdOperation.cc @@ -21,9 +21,11 @@ #include "IMB_colormanagement.h" +namespace blender::compositor { + GlareThresholdOperation::GlareThresholdOperation() { - this->addInputSocket(DataType::Color, COM_SC_FIT); + this->addInputSocket(DataType::Color, ResizeMode::FitAny); this->addOutputSocket(DataType::Color); this->m_inputProgram = nullptr; } @@ -67,3 +69,5 @@ void GlareThresholdOperation::deinitExecution() { this->m_inputProgram = nullptr; } + +} // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_GlareThresholdOperation.h b/source/blender/compositor/operations/COM_GlareThresholdOperation.h index 1e55f401ef3..a6e971dada7 100644 --- a/source/blender/compositor/operations/COM_GlareThresholdOperation.h +++ b/source/blender/compositor/operations/COM_GlareThresholdOperation.h @@ -21,6 +21,8 @@ #include "COM_NodeOperation.h" #include "DNA_light_types.h" +namespace blender::compositor { + class GlareThresholdOperation : public NodeOperation { private: /** @@ -39,22 +41,25 @@ class GlareThresholdOperation : public NodeOperation { /** * The inner loop of this operation. */ - void executePixelSampled(float output[4], float x, float y, PixelSampler sampler); + void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; /** * Initialize the execution */ - void initExecution(); + void initExecution() override; /** * Deinitialize the execution */ - void deinitExecution(); + void deinitExecution() override; void setGlareSettings(NodeGlare *settings) { this->m_settings = settings; } - void determineResolution(unsigned int resolution[2], unsigned int preferredResolution[2]); + void determineResolution(unsigned int resolution[2], + unsigned int preferredResolution[2]) override; }; + +} // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_HueSaturationValueCorrectOperation.cc b/source/blender/compositor/operations/COM_HueSaturationValueCorrectOperation.cc index 0ef15b2b3d7..e341a88ff71 100644 --- a/source/blender/compositor/operations/COM_HueSaturationValueCorrectOperation.cc +++ b/source/blender/compositor/operations/COM_HueSaturationValueCorrectOperation.cc @@ -22,6 +22,8 @@ #include "BKE_colortools.h" +namespace blender::compositor { + HueSaturationValueCorrectOperation::HueSaturationValueCorrectOperation() { this->addInputSocket(DataType::Color); @@ -70,3 +72,5 @@ void HueSaturationValueCorrectOperation::deinitExecution() CurveBaseOperation::deinitExecution(); this->m_inputProgram = nullptr; } + +} // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_HueSaturationValueCorrectOperation.h b/source/blender/compositor/operations/COM_HueSaturationValueCorrectOperation.h index dea7eae4a15..703b2894bdb 100644 --- a/source/blender/compositor/operations/COM_HueSaturationValueCorrectOperation.h +++ b/source/blender/compositor/operations/COM_HueSaturationValueCorrectOperation.h @@ -21,6 +21,8 @@ #include "COM_CurveBaseOperation.h" #include "COM_NodeOperation.h" +namespace blender::compositor { + class HueSaturationValueCorrectOperation : public CurveBaseOperation { private: /** @@ -34,15 +36,17 @@ class HueSaturationValueCorrectOperation : public CurveBaseOperation { /** * The inner loop of this operation. */ - void executePixelSampled(float output[4], float x, float y, PixelSampler sampler); + void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; /** * Initialize the execution */ - void initExecution(); + void initExecution() override; /** * Deinitialize the execution */ - void deinitExecution(); + void deinitExecution() override; }; + +} // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_IDMaskOperation.cc b/source/blender/compositor/operations/COM_IDMaskOperation.cc index 8757908e354..1bb247e9bc5 100644 --- a/source/blender/compositor/operations/COM_IDMaskOperation.cc +++ b/source/blender/compositor/operations/COM_IDMaskOperation.cc @@ -18,11 +18,13 @@ #include "COM_IDMaskOperation.h" +namespace blender::compositor { + IDMaskOperation::IDMaskOperation() { this->addInputSocket(DataType::Value); this->addOutputSocket(DataType::Value); - this->setComplex(true); + this->flags.complex = true; } void *IDMaskOperation::initializeTileData(rcti *rect) @@ -39,3 +41,5 @@ void IDMaskOperation::executePixel(float output[4], int x, int y, void *data) int buffer_index = (y * buffer_width + x); output[0] = (roundf(buffer[buffer_index]) == this->m_objectIndex) ? 1.0f : 0.0f; } + +} // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_IDMaskOperation.h b/source/blender/compositor/operations/COM_IDMaskOperation.h index abd2a719371..79b7e53b67c 100644 --- a/source/blender/compositor/operations/COM_IDMaskOperation.h +++ b/source/blender/compositor/operations/COM_IDMaskOperation.h @@ -20,6 +20,8 @@ #include "COM_NodeOperation.h" +namespace blender::compositor { + class IDMaskOperation : public NodeOperation { private: float m_objectIndex; @@ -27,11 +29,13 @@ class IDMaskOperation : public NodeOperation { public: IDMaskOperation(); - void *initializeTileData(rcti *rect); - void executePixel(float output[4], int x, int y, void *data); + void *initializeTileData(rcti *rect) override; + void executePixel(float output[4], int x, int y, void *data) override; void setObjectIndex(float objectIndex) { this->m_objectIndex = objectIndex; } }; + +} // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_ImageOperation.cc b/source/blender/compositor/operations/COM_ImageOperation.cc index 06e8db7b467..a1d401d4499 100644 --- a/source/blender/compositor/operations/COM_ImageOperation.cc +++ b/source/blender/compositor/operations/COM_ImageOperation.cc @@ -31,6 +31,8 @@ #include "RE_pipeline.h" #include "RE_texture.h" +namespace blender::compositor { + BaseImageOperation::BaseImageOperation() { this->m_image = nullptr; @@ -123,13 +125,13 @@ static void sampleImageAtLocation( { if (ibuf->rect_float) { switch (sampler) { - case COM_PS_NEAREST: + case PixelSampler::Nearest: nearest_interpolation_color(ibuf, nullptr, color, x, y); break; - case COM_PS_BILINEAR: + case PixelSampler::Bilinear: bilinear_interpolation_color(ibuf, nullptr, color, x, y); break; - case COM_PS_BICUBIC: + case PixelSampler::Bicubic: bicubic_interpolation_color(ibuf, nullptr, color, x, y); break; } @@ -137,13 +139,13 @@ static void sampleImageAtLocation( else { unsigned char byte_color[4]; switch (sampler) { - case COM_PS_NEAREST: + case PixelSampler::Nearest: nearest_interpolation_color(ibuf, byte_color, nullptr, x, y); break; - case COM_PS_BILINEAR: + case PixelSampler::Bilinear: bilinear_interpolation_color(ibuf, byte_color, nullptr, x, y); break; - case COM_PS_BICUBIC: + case PixelSampler::Bicubic: bicubic_interpolation_color(ibuf, byte_color, nullptr, x, y); break; } @@ -203,3 +205,5 @@ void ImageDepthOperation::executePixelSampled(float output[4], } } } + +} // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_ImageOperation.h b/source/blender/compositor/operations/COM_ImageOperation.h index bff8dcc1cea..58373663db5 100644 --- a/source/blender/compositor/operations/COM_ImageOperation.h +++ b/source/blender/compositor/operations/COM_ImageOperation.h @@ -27,6 +27,8 @@ #include "RE_pipeline.h" #include "RE_texture.h" +namespace blender::compositor { + /** * \brief Base class for all image operations */ @@ -49,13 +51,14 @@ class BaseImageOperation : public NodeOperation { /** * Determine the output resolution. The resolution is retrieved from the Renderer */ - void determineResolution(unsigned int resolution[2], unsigned int preferredResolution[2]); + void determineResolution(unsigned int resolution[2], + unsigned int preferredResolution[2]) override; virtual ImBuf *getImBuf(); public: - void initExecution(); - void deinitExecution(); + void initExecution() override; + void deinitExecution() override; void setImage(Image *image) { this->m_image = image; @@ -83,7 +86,7 @@ class ImageOperation : public BaseImageOperation { * Constructor */ ImageOperation(); - void executePixelSampled(float output[4], float x, float y, PixelSampler sampler); + void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; }; class ImageAlphaOperation : public BaseImageOperation { public: @@ -91,7 +94,7 @@ class ImageAlphaOperation : public BaseImageOperation { * Constructor */ ImageAlphaOperation(); - void executePixelSampled(float output[4], float x, float y, PixelSampler sampler); + void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; }; class ImageDepthOperation : public BaseImageOperation { public: @@ -99,5 +102,7 @@ class ImageDepthOperation : public BaseImageOperation { * Constructor */ ImageDepthOperation(); - void executePixelSampled(float output[4], float x, float y, PixelSampler sampler); + void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; }; + +} // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_InpaintOperation.cc b/source/blender/compositor/operations/COM_InpaintOperation.cc index f4e38c85e50..413ed2694a9 100644 --- a/source/blender/compositor/operations/COM_InpaintOperation.cc +++ b/source/blender/compositor/operations/COM_InpaintOperation.cc @@ -23,6 +23,8 @@ #include "BLI_math.h" +namespace blender::compositor { + #define ASSERT_XY_RANGE(x, y) \ BLI_assert(x >= 0 && x < this->getWidth() && y >= 0 && y < this->getHeight()) @@ -31,7 +33,7 @@ InpaintSimpleOperation::InpaintSimpleOperation() { this->addInputSocket(DataType::Color); this->addOutputSocket(DataType::Color); - this->setComplex(true); + this->flags.complex = true; this->m_inputImageProgram = nullptr; this->m_pixelorder = nullptr; this->m_manhattan_distance = nullptr; @@ -76,7 +78,8 @@ float *InpaintSimpleOperation::get_pixel(int x, int y) ASSERT_XY_RANGE(x, y); - return &this->m_cached_buffer[y * width * COM_NUM_CHANNELS_COLOR + x * COM_NUM_CHANNELS_COLOR]; + return &this->m_cached_buffer[y * width * COM_DATA_TYPE_COLOR_CHANNELS + + x * COM_DATA_TYPE_COLOR_CHANNELS]; } int InpaintSimpleOperation::mdist(int x, int y) @@ -282,3 +285,5 @@ bool InpaintSimpleOperation::determineDependingAreaOfInterest(rcti * /*input*/, return NodeOperation::determineDependingAreaOfInterest(&newInput, readOperation, output); } + +} // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_InpaintOperation.h b/source/blender/compositor/operations/COM_InpaintOperation.h index 4c43e433dec..e3d27bf7704 100644 --- a/source/blender/compositor/operations/COM_InpaintOperation.h +++ b/source/blender/compositor/operations/COM_InpaintOperation.h @@ -20,6 +20,8 @@ #include "COM_NodeOperation.h" +namespace blender::compositor { + class InpaintSimpleOperation : public NodeOperation { protected: /** @@ -42,18 +44,18 @@ class InpaintSimpleOperation : public NodeOperation { /** * The inner loop of this operation. */ - void executePixel(float output[4], int x, int y, void *data); + void executePixel(float output[4], int x, int y, void *data) override; /** * Initialize the execution */ - void initExecution(); + void initExecution() override; - void *initializeTileData(rcti *rect); + void *initializeTileData(rcti *rect) override; /** * Deinitialize the execution */ - void deinitExecution(); + void deinitExecution() override; void setIterations(int iterations) { @@ -62,7 +64,7 @@ class InpaintSimpleOperation : public NodeOperation { bool determineDependingAreaOfInterest(rcti *input, ReadBufferOperation *readOperation, - rcti *output); + rcti *output) override; private: void calc_manhattan_distance(); @@ -72,3 +74,5 @@ class InpaintSimpleOperation : public NodeOperation { bool next_pixel(int &x, int &y, int &curr, int iters); void pix_step(int x, int y); }; + +} // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_InvertOperation.cc b/source/blender/compositor/operations/COM_InvertOperation.cc index 53e32baaa3d..339e40a5d1f 100644 --- a/source/blender/compositor/operations/COM_InvertOperation.cc +++ b/source/blender/compositor/operations/COM_InvertOperation.cc @@ -18,6 +18,8 @@ #include "COM_InvertOperation.h" +namespace blender::compositor { + InvertOperation::InvertOperation() { this->addInputSocket(DataType::Value); @@ -67,3 +69,5 @@ void InvertOperation::deinitExecution() this->m_inputValueProgram = nullptr; this->m_inputColorProgram = nullptr; } + +} // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_InvertOperation.h b/source/blender/compositor/operations/COM_InvertOperation.h index ac0b1c3ab2e..17e5eb95f3e 100644 --- a/source/blender/compositor/operations/COM_InvertOperation.h +++ b/source/blender/compositor/operations/COM_InvertOperation.h @@ -20,6 +20,8 @@ #include "COM_NodeOperation.h" +namespace blender::compositor { + class InvertOperation : public NodeOperation { private: /** @@ -37,17 +39,17 @@ class InvertOperation : public NodeOperation { /** * The inner loop of this operation. */ - void executePixelSampled(float output[4], float x, float y, PixelSampler sampler); + void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; /** * Initialize the execution */ - void initExecution(); + void initExecution() override; /** * Deinitialize the execution */ - void deinitExecution(); + void deinitExecution() override; void setColor(bool color) { @@ -58,3 +60,5 @@ class InvertOperation : public NodeOperation { this->m_alpha = alpha; } }; + +} // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_KeyingBlurOperation.cc b/source/blender/compositor/operations/COM_KeyingBlurOperation.cc index 0d9613eea96..994b00cd3f4 100644 --- a/source/blender/compositor/operations/COM_KeyingBlurOperation.cc +++ b/source/blender/compositor/operations/COM_KeyingBlurOperation.cc @@ -23,6 +23,8 @@ #include "BLI_listbase.h" #include "BLI_math.h" +namespace blender::compositor { + KeyingBlurOperation::KeyingBlurOperation() { this->addInputSocket(DataType::Value); @@ -31,7 +33,7 @@ KeyingBlurOperation::KeyingBlurOperation() this->m_size = 0; this->m_axis = BLUR_AXIS_X; - this->setComplex(true); + this->flags.complex = true; } void *KeyingBlurOperation::initializeTileData(rcti *rect) @@ -93,3 +95,5 @@ bool KeyingBlurOperation::determineDependingAreaOfInterest(rcti *input, return NodeOperation::determineDependingAreaOfInterest(&newInput, readOperation, output); } + +} // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_KeyingBlurOperation.h b/source/blender/compositor/operations/COM_KeyingBlurOperation.h index 6a2b43a6cd4..b055d7713f1 100644 --- a/source/blender/compositor/operations/COM_KeyingBlurOperation.h +++ b/source/blender/compositor/operations/COM_KeyingBlurOperation.h @@ -20,6 +20,8 @@ #include "COM_NodeOperation.h" +namespace blender::compositor { + /** * Class with implementation of blurring for keying node */ @@ -45,11 +47,13 @@ class KeyingBlurOperation : public NodeOperation { this->m_axis = value; } - void *initializeTileData(rcti *rect); + void *initializeTileData(rcti *rect) override; - void executePixel(float output[4], int x, int y, void *data); + void executePixel(float output[4], int x, int y, void *data) override; bool determineDependingAreaOfInterest(rcti *input, ReadBufferOperation *readOperation, - rcti *output); + rcti *output) override; }; + +} // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_KeyingClipOperation.cc b/source/blender/compositor/operations/COM_KeyingClipOperation.cc index e8556d9d8c9..4029be4e077 100644 --- a/source/blender/compositor/operations/COM_KeyingClipOperation.cc +++ b/source/blender/compositor/operations/COM_KeyingClipOperation.cc @@ -23,6 +23,8 @@ #include "BLI_listbase.h" #include "BLI_math.h" +namespace blender::compositor { + KeyingClipOperation::KeyingClipOperation() { this->addInputSocket(DataType::Value); @@ -36,7 +38,7 @@ KeyingClipOperation::KeyingClipOperation() this->m_isEdgeMatte = false; - this->setComplex(true); + this->flags.complex = true; } void *KeyingClipOperation::initializeTileData(rcti *rect) @@ -127,3 +129,5 @@ bool KeyingClipOperation::determineDependingAreaOfInterest(rcti *input, return NodeOperation::determineDependingAreaOfInterest(&newInput, readOperation, output); } + +} // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_KeyingClipOperation.h b/source/blender/compositor/operations/COM_KeyingClipOperation.h index 9d876966e96..0a21fb48c99 100644 --- a/source/blender/compositor/operations/COM_KeyingClipOperation.h +++ b/source/blender/compositor/operations/COM_KeyingClipOperation.h @@ -20,6 +20,8 @@ #include "COM_NodeOperation.h" +namespace blender::compositor { + /** * Class with implementation of black/white clipping for keying node */ @@ -59,11 +61,13 @@ class KeyingClipOperation : public NodeOperation { this->m_isEdgeMatte = value; } - void *initializeTileData(rcti *rect); + void *initializeTileData(rcti *rect) override; - void executePixel(float output[4], int x, int y, void *data); + void executePixel(float output[4], int x, int y, void *data) override; bool determineDependingAreaOfInterest(rcti *input, ReadBufferOperation *readOperation, - rcti *output); + rcti *output) override; }; + +} // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_KeyingDespillOperation.cc b/source/blender/compositor/operations/COM_KeyingDespillOperation.cc index 5caa450a878..d31a88cb91e 100644 --- a/source/blender/compositor/operations/COM_KeyingDespillOperation.cc +++ b/source/blender/compositor/operations/COM_KeyingDespillOperation.cc @@ -23,6 +23,8 @@ #include "BLI_listbase.h" #include "BLI_math.h" +namespace blender::compositor { + KeyingDespillOperation::KeyingDespillOperation() { this->addInputSocket(DataType::Color); @@ -79,3 +81,5 @@ void KeyingDespillOperation::executePixelSampled(float output[4], output[screen_primary_channel] = pixelColor[screen_primary_channel] - amount_despill; } } + +} // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_KeyingDespillOperation.h b/source/blender/compositor/operations/COM_KeyingDespillOperation.h index 32df7939c43..279ac60e6e9 100644 --- a/source/blender/compositor/operations/COM_KeyingDespillOperation.h +++ b/source/blender/compositor/operations/COM_KeyingDespillOperation.h @@ -20,6 +20,8 @@ #include "COM_NodeOperation.h" +namespace blender::compositor { + /** * Class with implementation of keying despill node */ @@ -33,8 +35,8 @@ class KeyingDespillOperation : public NodeOperation { public: KeyingDespillOperation(); - void initExecution(); - void deinitExecution(); + void initExecution() override; + void deinitExecution() override; void setDespillFactor(float value) { @@ -45,5 +47,7 @@ class KeyingDespillOperation : public NodeOperation { this->m_colorBalance = value; } - void executePixelSampled(float output[4], float x, float y, PixelSampler sampler); + void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; }; + +} // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_KeyingOperation.cc b/source/blender/compositor/operations/COM_KeyingOperation.cc index 108b7c60874..e786e4b8219 100644 --- a/source/blender/compositor/operations/COM_KeyingOperation.cc +++ b/source/blender/compositor/operations/COM_KeyingOperation.cc @@ -23,6 +23,8 @@ #include "BLI_listbase.h" #include "BLI_math.h" +namespace blender::compositor { + static float get_pixel_saturation(const float pixelColor[4], float screen_balance, int primary_channel) @@ -107,3 +109,5 @@ void KeyingOperation::executePixelSampled(float output[4], float x, float y, Pix } } } + +} // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_KeyingOperation.h b/source/blender/compositor/operations/COM_KeyingOperation.h index 946d7bdc1f7..3d41ecaa0f6 100644 --- a/source/blender/compositor/operations/COM_KeyingOperation.h +++ b/source/blender/compositor/operations/COM_KeyingOperation.h @@ -24,6 +24,8 @@ #include "BLI_listbase.h" +namespace blender::compositor { + /** * Class with implementation of keying node */ @@ -37,13 +39,15 @@ class KeyingOperation : public NodeOperation { public: KeyingOperation(); - void initExecution(); - void deinitExecution(); + void initExecution() override; + void deinitExecution() override; void setScreenBalance(float value) { this->m_screenBalance = value; } - void executePixelSampled(float output[4], float x, float y, PixelSampler sampler); + void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; }; + +} // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_KeyingScreenOperation.cc b/source/blender/compositor/operations/COM_KeyingScreenOperation.cc index 801750d99d0..17b613246ad 100644 --- a/source/blender/compositor/operations/COM_KeyingScreenOperation.cc +++ b/source/blender/compositor/operations/COM_KeyingScreenOperation.cc @@ -30,13 +30,15 @@ #include "IMB_imbuf.h" #include "IMB_imbuf_types.h" +namespace blender::compositor { + KeyingScreenOperation::KeyingScreenOperation() { this->addOutputSocket(DataType::Color); this->m_movieClip = nullptr; this->m_framenumber = 0; this->m_trackingObject[0] = 0; - setComplex(true); + flags.complex = true; } void KeyingScreenOperation::initExecution() @@ -344,3 +346,5 @@ void KeyingScreenOperation::executePixel(float output[4], int x, int y, void *da } } } + +} // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_KeyingScreenOperation.h b/source/blender/compositor/operations/COM_KeyingScreenOperation.h index 595301bb951..4118d229be9 100644 --- a/source/blender/compositor/operations/COM_KeyingScreenOperation.h +++ b/source/blender/compositor/operations/COM_KeyingScreenOperation.h @@ -29,6 +29,8 @@ #include "BLI_voronoi_2d.h" +namespace blender::compositor { + /** * Class with implementation of green screen gradient rasterization */ @@ -54,18 +56,19 @@ class KeyingScreenOperation : public NodeOperation { /** * Determine the output resolution. The resolution is retrieved from the Renderer */ - void determineResolution(unsigned int resolution[2], unsigned int preferredResolution[2]); + void determineResolution(unsigned int resolution[2], + unsigned int preferredResolution[2]) override; TriangulationData *buildVoronoiTriangulation(); public: KeyingScreenOperation(); - void initExecution(); - void deinitExecution(); + void initExecution() override; + void deinitExecution() override; - void *initializeTileData(rcti *rect); - void deinitializeTileData(rcti *rect, void *data); + void *initializeTileData(rcti *rect) override; + void deinitializeTileData(rcti *rect, void *data) override; void setMovieClip(MovieClip *clip) { @@ -80,5 +83,7 @@ class KeyingScreenOperation : public NodeOperation { this->m_framenumber = framenumber; } - void executePixel(float output[4], int x, int y, void *data); + void executePixel(float output[4], int x, int y, void *data) override; }; + +} // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_LuminanceMatteOperation.cc b/source/blender/compositor/operations/COM_LuminanceMatteOperation.cc index 43cc8f8bf71..0afc4278a45 100644 --- a/source/blender/compositor/operations/COM_LuminanceMatteOperation.cc +++ b/source/blender/compositor/operations/COM_LuminanceMatteOperation.cc @@ -21,6 +21,8 @@ #include "IMB_colormanagement.h" +namespace blender::compositor { + LuminanceMatteOperation::LuminanceMatteOperation() { addInputSocket(DataType::Color); @@ -75,3 +77,5 @@ void LuminanceMatteOperation::executePixelSampled(float output[4], /* don't make something that was more transparent less transparent */ output[0] = min_ff(alpha, inColor[3]); } + +} // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_LuminanceMatteOperation.h b/source/blender/compositor/operations/COM_LuminanceMatteOperation.h index 2c3a61d8755..035c68b9d59 100644 --- a/source/blender/compositor/operations/COM_LuminanceMatteOperation.h +++ b/source/blender/compositor/operations/COM_LuminanceMatteOperation.h @@ -20,6 +20,8 @@ #include "COM_MixOperation.h" +namespace blender::compositor { + /** * this program converts an input color to an output value. * it assumes we are in sRGB color space. @@ -38,13 +40,15 @@ class LuminanceMatteOperation : public NodeOperation { /** * The inner loop of this operation. */ - void executePixelSampled(float output[4], float x, float y, PixelSampler sampler); + void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; - void initExecution(); - void deinitExecution(); + void initExecution() override; + void deinitExecution() override; void setSettings(NodeChroma *nodeChroma) { this->m_settings = nodeChroma; } }; + +} // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_MapRangeOperation.cc b/source/blender/compositor/operations/COM_MapRangeOperation.cc index 78ba446051e..ada3cd6f159 100644 --- a/source/blender/compositor/operations/COM_MapRangeOperation.cc +++ b/source/blender/compositor/operations/COM_MapRangeOperation.cc @@ -18,6 +18,8 @@ #include "COM_MapRangeOperation.h" +namespace blender::compositor { + MapRangeOperation::MapRangeOperation() { this->addInputSocket(DataType::Value); @@ -101,3 +103,5 @@ void MapRangeOperation::deinitExecution() this->m_destMinOperation = nullptr; this->m_destMaxOperation = nullptr; } + +} // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_MapRangeOperation.h b/source/blender/compositor/operations/COM_MapRangeOperation.h index 95268d5699f..a544c59887e 100644 --- a/source/blender/compositor/operations/COM_MapRangeOperation.h +++ b/source/blender/compositor/operations/COM_MapRangeOperation.h @@ -21,6 +21,8 @@ #include "COM_NodeOperation.h" #include "DNA_texture_types.h" +namespace blender::compositor { + /** * this program converts an input color to an output value. * it assumes we are in sRGB color space. @@ -47,17 +49,17 @@ class MapRangeOperation : public NodeOperation { /** * The inner loop of this operation. */ - void executePixelSampled(float output[4], float x, float y, PixelSampler sampler); + void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; /** * Initialize the execution */ - void initExecution(); + void initExecution() override; /** * Deinitialize the execution */ - void deinitExecution(); + void deinitExecution() override; /** * Clamp the output @@ -67,3 +69,5 @@ class MapRangeOperation : public NodeOperation { this->m_useClamp = value; } }; + +} // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_MapUVOperation.cc b/source/blender/compositor/operations/COM_MapUVOperation.cc index 7328de7f49f..74e3d965d41 100644 --- a/source/blender/compositor/operations/COM_MapUVOperation.cc +++ b/source/blender/compositor/operations/COM_MapUVOperation.cc @@ -19,13 +19,15 @@ #include "COM_MapUVOperation.h" #include "BLI_math.h" +namespace blender::compositor { + MapUVOperation::MapUVOperation() { - this->addInputSocket(DataType::Color, COM_SC_NO_RESIZE); + this->addInputSocket(DataType::Color, ResizeMode::None); this->addInputSocket(DataType::Vector); this->addOutputSocket(DataType::Color); this->m_alpha = 0.0f; - this->setComplex(true); + this->flags.complex = true; setResolutionInputSocketIndex(1); this->m_inputUVProgram = nullptr; @@ -89,7 +91,7 @@ bool MapUVOperation::read_uv(float x, float y, float &r_u, float &r_v, float &r_ } float vector[3]; - m_inputUVProgram->readSampled(vector, x, y, COM_PS_BILINEAR); + m_inputUVProgram->readSampled(vector, x, y, PixelSampler::Bilinear); r_u = vector[0] * m_inputColorProgram->getWidth(); r_v = vector[1] * m_inputColorProgram->getHeight(); r_alpha = vector[2]; @@ -183,3 +185,5 @@ bool MapUVOperation::determineDependingAreaOfInterest(rcti *input, return false; } + +} // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_MapUVOperation.h b/source/blender/compositor/operations/COM_MapUVOperation.h index 66e70a7ab83..eb5f7d49122 100644 --- a/source/blender/compositor/operations/COM_MapUVOperation.h +++ b/source/blender/compositor/operations/COM_MapUVOperation.h @@ -20,6 +20,8 @@ #include "COM_NodeOperation.h" +namespace blender::compositor { + class MapUVOperation : public NodeOperation { private: /** @@ -38,24 +40,24 @@ class MapUVOperation : public NodeOperation { */ bool determineDependingAreaOfInterest(rcti *input, ReadBufferOperation *readOperation, - rcti *output); + rcti *output) override; /** * The inner loop of this operation. */ - void executePixelSampled(float output[4], float x, float y, PixelSampler sampler); + void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; void pixelTransform(const float xy[2], float r_uv[2], float r_deriv[2][2], float &r_alpha); /** * Initialize the execution */ - void initExecution(); + void initExecution() override; /** * Deinitialize the execution */ - void deinitExecution(); + void deinitExecution() override; void setAlpha(float alpha) { @@ -65,3 +67,5 @@ class MapUVOperation : public NodeOperation { private: bool read_uv(float x, float y, float &r_u, float &r_v, float &r_alpha); }; + +} // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_MapValueOperation.cc b/source/blender/compositor/operations/COM_MapValueOperation.cc index 9c28e3c2577..03fa80d220d 100644 --- a/source/blender/compositor/operations/COM_MapValueOperation.cc +++ b/source/blender/compositor/operations/COM_MapValueOperation.cc @@ -18,6 +18,8 @@ #include "COM_MapValueOperation.h" +namespace blender::compositor { + MapValueOperation::MapValueOperation() { this->addInputSocket(DataType::Value); @@ -57,3 +59,5 @@ void MapValueOperation::deinitExecution() { this->m_inputOperation = nullptr; } + +} // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_MapValueOperation.h b/source/blender/compositor/operations/COM_MapValueOperation.h index 3de377ed0fc..eb7714714e9 100644 --- a/source/blender/compositor/operations/COM_MapValueOperation.h +++ b/source/blender/compositor/operations/COM_MapValueOperation.h @@ -21,6 +21,8 @@ #include "COM_NodeOperation.h" #include "DNA_texture_types.h" +namespace blender::compositor { + /** * this program converts an input color to an output value. * it assumes we are in sRGB color space. @@ -42,17 +44,17 @@ class MapValueOperation : public NodeOperation { /** * The inner loop of this operation. */ - void executePixelSampled(float output[4], float x, float y, PixelSampler sampler); + void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; /** * Initialize the execution */ - void initExecution(); + void initExecution() override; /** * Deinitialize the execution */ - void deinitExecution(); + void deinitExecution() override; /** * \brief set the TexMapping settings @@ -62,3 +64,5 @@ class MapValueOperation : public NodeOperation { this->m_settings = settings; } }; + +} // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_MaskOperation.cc b/source/blender/compositor/operations/COM_MaskOperation.cc index 64d8c9a5492..c7763f08e71 100644 --- a/source/blender/compositor/operations/COM_MaskOperation.cc +++ b/source/blender/compositor/operations/COM_MaskOperation.cc @@ -26,6 +26,8 @@ #include "BKE_lib_id.h" #include "BKE_mask.h" +namespace blender::compositor { + MaskOperation::MaskOperation() { this->addOutputSocket(DataType::Value); @@ -158,3 +160,5 @@ void MaskOperation::executePixelSampled(float output[4], output[0] /= this->m_rasterMaskHandleTot; } } + +} // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_MaskOperation.h b/source/blender/compositor/operations/COM_MaskOperation.h index 67e6b64315c..48fd54b00fe 100644 --- a/source/blender/compositor/operations/COM_MaskOperation.h +++ b/source/blender/compositor/operations/COM_MaskOperation.h @@ -23,6 +23,11 @@ #include "DNA_mask_types.h" #include "IMB_imbuf_types.h" +/* Forward declarations. */ +struct MaskRasterHandle; + +namespace blender::compositor { + /** * Class with implementation of mask rasterization */ @@ -49,13 +54,14 @@ class MaskOperation : public NodeOperation { /** * Determine the output resolution. The resolution is retrieved from the Renderer */ - void determineResolution(unsigned int resolution[2], unsigned int preferredResolution[2]); + void determineResolution(unsigned int resolution[2], + unsigned int preferredResolution[2]) override; public: MaskOperation(); - void initExecution(); - void deinitExecution(); + void initExecution() override; + void deinitExecution() override; void setMask(Mask *mask) { @@ -91,5 +97,7 @@ class MaskOperation : public NodeOperation { this->m_frame_shutter = shutter; } - void executePixelSampled(float output[4], float x, float y, PixelSampler sampler); + void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; }; + +} // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_MathBaseOperation.cc b/source/blender/compositor/operations/COM_MathBaseOperation.cc index 57ccbe7792b..a94c14347fb 100644 --- a/source/blender/compositor/operations/COM_MathBaseOperation.cc +++ b/source/blender/compositor/operations/COM_MathBaseOperation.cc @@ -20,6 +20,8 @@ #include "BLI_math.h" +namespace blender::compositor { + MathBaseOperation::MathBaseOperation() { this->addInputSocket(DataType::Value); @@ -748,3 +750,5 @@ void MathSmoothMaxOperation::executePixelSampled(float output[4], clampIfNeeded(output); } + +} // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_MathBaseOperation.h b/source/blender/compositor/operations/COM_MathBaseOperation.h index 292326caded..69555524274 100644 --- a/source/blender/compositor/operations/COM_MathBaseOperation.h +++ b/source/blender/compositor/operations/COM_MathBaseOperation.h @@ -20,6 +20,8 @@ #include "COM_NodeOperation.h" +namespace blender::compositor { + /** * this program converts an input color to an output value. * it assumes we are in sRGB color space. @@ -45,24 +47,20 @@ class MathBaseOperation : public NodeOperation { public: /** - * The inner loop of this operation. - */ - void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) = 0; - - /** * Initialize the execution */ - void initExecution(); + void initExecution() override; /** * Deinitialize the execution */ - void deinitExecution(); + void deinitExecution() override; /** * Determine resolution */ - void determineResolution(unsigned int resolution[2], unsigned int preferredResolution[2]); + void determineResolution(unsigned int resolution[2], + unsigned int preferredResolution[2]) override; void setUseClamp(bool value) { @@ -75,49 +73,49 @@ class MathAddOperation : public MathBaseOperation { MathAddOperation() : MathBaseOperation() { } - void executePixelSampled(float output[4], float x, float y, PixelSampler sampler); + void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; }; class MathSubtractOperation : public MathBaseOperation { public: MathSubtractOperation() : MathBaseOperation() { } - void executePixelSampled(float output[4], float x, float y, PixelSampler sampler); + void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; }; class MathMultiplyOperation : public MathBaseOperation { public: MathMultiplyOperation() : MathBaseOperation() { } - void executePixelSampled(float output[4], float x, float y, PixelSampler sampler); + void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; }; class MathDivideOperation : public MathBaseOperation { public: MathDivideOperation() : MathBaseOperation() { } - void executePixelSampled(float output[4], float x, float y, PixelSampler sampler); + void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; }; class MathSineOperation : public MathBaseOperation { public: MathSineOperation() : MathBaseOperation() { } - void executePixelSampled(float output[4], float x, float y, PixelSampler sampler); + void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; }; class MathCosineOperation : public MathBaseOperation { public: MathCosineOperation() : MathBaseOperation() { } - void executePixelSampled(float output[4], float x, float y, PixelSampler sampler); + void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; }; class MathTangentOperation : public MathBaseOperation { public: MathTangentOperation() : MathBaseOperation() { } - void executePixelSampled(float output[4], float x, float y, PixelSampler sampler); + void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; }; class MathHyperbolicSineOperation : public MathBaseOperation { @@ -125,21 +123,21 @@ class MathHyperbolicSineOperation : public MathBaseOperation { MathHyperbolicSineOperation() : MathBaseOperation() { } - void executePixelSampled(float output[4], float x, float y, PixelSampler sampler); + void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; }; class MathHyperbolicCosineOperation : public MathBaseOperation { public: MathHyperbolicCosineOperation() : MathBaseOperation() { } - void executePixelSampled(float output[4], float x, float y, PixelSampler sampler); + void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; }; class MathHyperbolicTangentOperation : public MathBaseOperation { public: MathHyperbolicTangentOperation() : MathBaseOperation() { } - void executePixelSampled(float output[4], float x, float y, PixelSampler sampler); + void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; }; class MathArcSineOperation : public MathBaseOperation { @@ -147,70 +145,70 @@ class MathArcSineOperation : public MathBaseOperation { MathArcSineOperation() : MathBaseOperation() { } - void executePixelSampled(float output[4], float x, float y, PixelSampler sampler); + void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; }; class MathArcCosineOperation : public MathBaseOperation { public: MathArcCosineOperation() : MathBaseOperation() { } - void executePixelSampled(float output[4], float x, float y, PixelSampler sampler); + void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; }; class MathArcTangentOperation : public MathBaseOperation { public: MathArcTangentOperation() : MathBaseOperation() { } - void executePixelSampled(float output[4], float x, float y, PixelSampler sampler); + void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; }; class MathPowerOperation : public MathBaseOperation { public: MathPowerOperation() : MathBaseOperation() { } - void executePixelSampled(float output[4], float x, float y, PixelSampler sampler); + void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; }; class MathLogarithmOperation : public MathBaseOperation { public: MathLogarithmOperation() : MathBaseOperation() { } - void executePixelSampled(float output[4], float x, float y, PixelSampler sampler); + void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; }; class MathMinimumOperation : public MathBaseOperation { public: MathMinimumOperation() : MathBaseOperation() { } - void executePixelSampled(float output[4], float x, float y, PixelSampler sampler); + void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; }; class MathMaximumOperation : public MathBaseOperation { public: MathMaximumOperation() : MathBaseOperation() { } - void executePixelSampled(float output[4], float x, float y, PixelSampler sampler); + void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; }; class MathRoundOperation : public MathBaseOperation { public: MathRoundOperation() : MathBaseOperation() { } - void executePixelSampled(float output[4], float x, float y, PixelSampler sampler); + void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; }; class MathLessThanOperation : public MathBaseOperation { public: MathLessThanOperation() : MathBaseOperation() { } - void executePixelSampled(float output[4], float x, float y, PixelSampler sampler); + void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; }; class MathGreaterThanOperation : public MathBaseOperation { public: MathGreaterThanOperation() : MathBaseOperation() { } - void executePixelSampled(float output[4], float x, float y, PixelSampler sampler); + void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; }; class MathModuloOperation : public MathBaseOperation { @@ -218,7 +216,7 @@ class MathModuloOperation : public MathBaseOperation { MathModuloOperation() : MathBaseOperation() { } - void executePixelSampled(float output[4], float x, float y, PixelSampler sampler); + void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; }; class MathAbsoluteOperation : public MathBaseOperation { @@ -226,7 +224,7 @@ class MathAbsoluteOperation : public MathBaseOperation { MathAbsoluteOperation() : MathBaseOperation() { } - void executePixelSampled(float output[4], float x, float y, PixelSampler sampler); + void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; }; class MathRadiansOperation : public MathBaseOperation { @@ -234,7 +232,7 @@ class MathRadiansOperation : public MathBaseOperation { MathRadiansOperation() : MathBaseOperation() { } - void executePixelSampled(float output[4], float x, float y, PixelSampler sampler); + void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; }; class MathDegreesOperation : public MathBaseOperation { @@ -242,7 +240,7 @@ class MathDegreesOperation : public MathBaseOperation { MathDegreesOperation() : MathBaseOperation() { } - void executePixelSampled(float output[4], float x, float y, PixelSampler sampler); + void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; }; class MathArcTan2Operation : public MathBaseOperation { @@ -250,7 +248,7 @@ class MathArcTan2Operation : public MathBaseOperation { MathArcTan2Operation() : MathBaseOperation() { } - void executePixelSampled(float output[4], float x, float y, PixelSampler sampler); + void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; }; class MathFloorOperation : public MathBaseOperation { @@ -258,7 +256,7 @@ class MathFloorOperation : public MathBaseOperation { MathFloorOperation() : MathBaseOperation() { } - void executePixelSampled(float output[4], float x, float y, PixelSampler sampler); + void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; }; class MathCeilOperation : public MathBaseOperation { @@ -266,7 +264,7 @@ class MathCeilOperation : public MathBaseOperation { MathCeilOperation() : MathBaseOperation() { } - void executePixelSampled(float output[4], float x, float y, PixelSampler sampler); + void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; }; class MathFractOperation : public MathBaseOperation { @@ -274,7 +272,7 @@ class MathFractOperation : public MathBaseOperation { MathFractOperation() : MathBaseOperation() { } - void executePixelSampled(float output[4], float x, float y, PixelSampler sampler); + void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; }; class MathSqrtOperation : public MathBaseOperation { @@ -282,7 +280,7 @@ class MathSqrtOperation : public MathBaseOperation { MathSqrtOperation() : MathBaseOperation() { } - void executePixelSampled(float output[4], float x, float y, PixelSampler sampler); + void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; }; class MathInverseSqrtOperation : public MathBaseOperation { @@ -290,7 +288,7 @@ class MathInverseSqrtOperation : public MathBaseOperation { MathInverseSqrtOperation() : MathBaseOperation() { } - void executePixelSampled(float output[4], float x, float y, PixelSampler sampler); + void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; }; class MathSignOperation : public MathBaseOperation { @@ -298,7 +296,7 @@ class MathSignOperation : public MathBaseOperation { MathSignOperation() : MathBaseOperation() { } - void executePixelSampled(float output[4], float x, float y, PixelSampler sampler); + void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; }; class MathExponentOperation : public MathBaseOperation { @@ -306,7 +304,7 @@ class MathExponentOperation : public MathBaseOperation { MathExponentOperation() : MathBaseOperation() { } - void executePixelSampled(float output[4], float x, float y, PixelSampler sampler); + void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; }; class MathTruncOperation : public MathBaseOperation { @@ -314,7 +312,7 @@ class MathTruncOperation : public MathBaseOperation { MathTruncOperation() : MathBaseOperation() { } - void executePixelSampled(float output[4], float x, float y, PixelSampler sampler); + void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; }; class MathSnapOperation : public MathBaseOperation { @@ -322,7 +320,7 @@ class MathSnapOperation : public MathBaseOperation { MathSnapOperation() : MathBaseOperation() { } - void executePixelSampled(float output[4], float x, float y, PixelSampler sampler); + void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; }; class MathWrapOperation : public MathBaseOperation { @@ -330,7 +328,7 @@ class MathWrapOperation : public MathBaseOperation { MathWrapOperation() : MathBaseOperation() { } - void executePixelSampled(float output[4], float x, float y, PixelSampler sampler); + void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; }; class MathPingpongOperation : public MathBaseOperation { @@ -338,7 +336,7 @@ class MathPingpongOperation : public MathBaseOperation { MathPingpongOperation() : MathBaseOperation() { } - void executePixelSampled(float output[4], float x, float y, PixelSampler sampler); + void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; }; class MathCompareOperation : public MathBaseOperation { @@ -346,7 +344,7 @@ class MathCompareOperation : public MathBaseOperation { MathCompareOperation() : MathBaseOperation() { } - void executePixelSampled(float output[4], float x, float y, PixelSampler sampler); + void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; }; class MathMultiplyAddOperation : public MathBaseOperation { @@ -354,7 +352,7 @@ class MathMultiplyAddOperation : public MathBaseOperation { MathMultiplyAddOperation() : MathBaseOperation() { } - void executePixelSampled(float output[4], float x, float y, PixelSampler sampler); + void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; }; class MathSmoothMinOperation : public MathBaseOperation { @@ -362,7 +360,7 @@ class MathSmoothMinOperation : public MathBaseOperation { MathSmoothMinOperation() : MathBaseOperation() { } - void executePixelSampled(float output[4], float x, float y, PixelSampler sampler); + void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; }; class MathSmoothMaxOperation : public MathBaseOperation { @@ -370,5 +368,7 @@ class MathSmoothMaxOperation : public MathBaseOperation { MathSmoothMaxOperation() : MathBaseOperation() { } - void executePixelSampled(float output[4], float x, float y, PixelSampler sampler); + void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; }; + +} // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_MixOperation.cc b/source/blender/compositor/operations/COM_MixOperation.cc index e70c59c6a01..70f3242c076 100644 --- a/source/blender/compositor/operations/COM_MixOperation.cc +++ b/source/blender/compositor/operations/COM_MixOperation.cc @@ -20,6 +20,8 @@ #include "BLI_math.h" +namespace blender::compositor { + /* ******** Mix Base Operation ******** */ MixBaseOperation::MixBaseOperation() @@ -944,3 +946,5 @@ void MixValueOperation::executePixelSampled(float output[4], clampIfNeeded(output); } + +} // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_MixOperation.h b/source/blender/compositor/operations/COM_MixOperation.h index 2f6e03ca7a3..86200c9836e 100644 --- a/source/blender/compositor/operations/COM_MixOperation.h +++ b/source/blender/compositor/operations/COM_MixOperation.h @@ -20,6 +20,8 @@ #include "COM_NodeOperation.h" +namespace blender::compositor { + /** * All this programs converts an input color to an output value. * it assumes we are in sRGB color space. @@ -52,19 +54,20 @@ class MixBaseOperation : public NodeOperation { /** * The inner loop of this operation. */ - void executePixelSampled(float output[4], float x, float y, PixelSampler sampler); + void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; /** * Initialize the execution */ - void initExecution(); + void initExecution() override; /** * Deinitialize the execution */ - void deinitExecution(); + void deinitExecution() override; - void determineResolution(unsigned int resolution[2], unsigned int preferredResolution[2]); + void determineResolution(unsigned int resolution[2], + unsigned int preferredResolution[2]) override; void setUseValueAlphaMultiply(const bool value) { @@ -83,113 +86,115 @@ class MixBaseOperation : public NodeOperation { class MixAddOperation : public MixBaseOperation { public: MixAddOperation(); - void executePixelSampled(float output[4], float x, float y, PixelSampler sampler); + void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; }; class MixBlendOperation : public MixBaseOperation { public: MixBlendOperation(); - void executePixelSampled(float output[4], float x, float y, PixelSampler sampler); + void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; }; class MixColorBurnOperation : public MixBaseOperation { public: MixColorBurnOperation(); - void executePixelSampled(float output[4], float x, float y, PixelSampler sampler); + void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; }; class MixColorOperation : public MixBaseOperation { public: MixColorOperation(); - void executePixelSampled(float output[4], float x, float y, PixelSampler sampler); + void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; }; class MixDarkenOperation : public MixBaseOperation { public: MixDarkenOperation(); - void executePixelSampled(float output[4], float x, float y, PixelSampler sampler); + void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; }; class MixDifferenceOperation : public MixBaseOperation { public: MixDifferenceOperation(); - void executePixelSampled(float output[4], float x, float y, PixelSampler sampler); + void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; }; class MixDivideOperation : public MixBaseOperation { public: MixDivideOperation(); - void executePixelSampled(float output[4], float x, float y, PixelSampler sampler); + void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; }; class MixDodgeOperation : public MixBaseOperation { public: MixDodgeOperation(); - void executePixelSampled(float output[4], float x, float y, PixelSampler sampler); + void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; }; class MixGlareOperation : public MixBaseOperation { public: MixGlareOperation(); - void executePixelSampled(float output[4], float x, float y, PixelSampler sampler); + void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; }; class MixHueOperation : public MixBaseOperation { public: MixHueOperation(); - void executePixelSampled(float output[4], float x, float y, PixelSampler sampler); + void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; }; class MixLightenOperation : public MixBaseOperation { public: MixLightenOperation(); - void executePixelSampled(float output[4], float x, float y, PixelSampler sampler); + void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; }; class MixLinearLightOperation : public MixBaseOperation { public: MixLinearLightOperation(); - void executePixelSampled(float output[4], float x, float y, PixelSampler sampler); + void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; }; class MixMultiplyOperation : public MixBaseOperation { public: MixMultiplyOperation(); - void executePixelSampled(float output[4], float x, float y, PixelSampler sampler); + void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; }; class MixOverlayOperation : public MixBaseOperation { public: MixOverlayOperation(); - void executePixelSampled(float output[4], float x, float y, PixelSampler sampler); + void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; }; class MixSaturationOperation : public MixBaseOperation { public: MixSaturationOperation(); - void executePixelSampled(float output[4], float x, float y, PixelSampler sampler); + void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; }; class MixScreenOperation : public MixBaseOperation { public: MixScreenOperation(); - void executePixelSampled(float output[4], float x, float y, PixelSampler sampler); + void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; }; class MixSoftLightOperation : public MixBaseOperation { public: MixSoftLightOperation(); - void executePixelSampled(float output[4], float x, float y, PixelSampler sampler); + void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; }; class MixSubtractOperation : public MixBaseOperation { public: MixSubtractOperation(); - void executePixelSampled(float output[4], float x, float y, PixelSampler sampler); + void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; }; class MixValueOperation : public MixBaseOperation { public: MixValueOperation(); - void executePixelSampled(float output[4], float x, float y, PixelSampler sampler); + void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; }; + +} // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_MovieClipAttributeOperation.cc b/source/blender/compositor/operations/COM_MovieClipAttributeOperation.cc index 3920b4c02bd..a9f187258b2 100644 --- a/source/blender/compositor/operations/COM_MovieClipAttributeOperation.cc +++ b/source/blender/compositor/operations/COM_MovieClipAttributeOperation.cc @@ -21,6 +21,8 @@ #include "BKE_movieclip.h" #include "BKE_tracking.h" +namespace blender::compositor { + MovieClipAttributeOperation::MovieClipAttributeOperation() { this->addOutputSocket(DataType::Value); @@ -80,3 +82,5 @@ void MovieClipAttributeOperation::determineResolution(unsigned int resolution[2] resolution[0] = preferredResolution[0]; resolution[1] = preferredResolution[1]; } + +} // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_MovieClipAttributeOperation.h b/source/blender/compositor/operations/COM_MovieClipAttributeOperation.h index 50ed6cdb69e..8507e98d08f 100644 --- a/source/blender/compositor/operations/COM_MovieClipAttributeOperation.h +++ b/source/blender/compositor/operations/COM_MovieClipAttributeOperation.h @@ -21,6 +21,8 @@ #include "COM_NodeOperation.h" #include "DNA_movieclip_types.h" +namespace blender::compositor { + typedef enum MovieClipAttribute { MCA_SCALE, MCA_X, @@ -45,13 +47,14 @@ class MovieClipAttributeOperation : public NodeOperation { */ MovieClipAttributeOperation(); - void initExecution(); + void initExecution() override; /** * The inner loop of this operation. */ - void executePixelSampled(float output[4], float x, float y, PixelSampler sampler); - void determineResolution(unsigned int resolution[2], unsigned int preferredResolution[2]); + void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; + void determineResolution(unsigned int resolution[2], + unsigned int preferredResolution[2]) override; void setMovieClip(MovieClip *clip) { @@ -70,3 +73,5 @@ class MovieClipAttributeOperation : public NodeOperation { this->m_invert = invert; } }; + +} // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_MovieClipOperation.cc b/source/blender/compositor/operations/COM_MovieClipOperation.cc index 5d5880e14b0..d93a75407c4 100644 --- a/source/blender/compositor/operations/COM_MovieClipOperation.cc +++ b/source/blender/compositor/operations/COM_MovieClipOperation.cc @@ -26,6 +26,8 @@ #include "IMB_imbuf.h" +namespace blender::compositor { + MovieClipBaseOperation::MovieClipBaseOperation() { this->m_movieClip = nullptr; @@ -101,13 +103,13 @@ void MovieClipBaseOperation::executePixelSampled(float output[4], } else { switch (sampler) { - case COM_PS_NEAREST: + case PixelSampler::Nearest: nearest_interpolation_color(ibuf, nullptr, output, x, y); break; - case COM_PS_BILINEAR: + case PixelSampler::Bilinear: bilinear_interpolation_color(ibuf, nullptr, output, x, y); break; - case COM_PS_BICUBIC: + case PixelSampler::Bicubic: bicubic_interpolation_color(ibuf, nullptr, output, x, y); break; } @@ -133,3 +135,5 @@ void MovieClipAlphaOperation::executePixelSampled(float output[4], MovieClipBaseOperation::executePixelSampled(result, x, y, sampler); output[0] = result[3]; } + +} // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_MovieClipOperation.h b/source/blender/compositor/operations/COM_MovieClipOperation.h index 8897f85f77c..c853ea43762 100644 --- a/source/blender/compositor/operations/COM_MovieClipOperation.h +++ b/source/blender/compositor/operations/COM_MovieClipOperation.h @@ -23,6 +23,8 @@ #include "DNA_movieclip_types.h" #include "IMB_imbuf_types.h" +namespace blender::compositor { + /** * Base class for movie clip */ @@ -39,13 +41,14 @@ class MovieClipBaseOperation : public NodeOperation { /** * Determine the output resolution. The resolution is retrieved from the Renderer */ - void determineResolution(unsigned int resolution[2], unsigned int preferredResolution[2]); + void determineResolution(unsigned int resolution[2], + unsigned int preferredResolution[2]) override; public: MovieClipBaseOperation(); - void initExecution(); - void deinitExecution(); + void initExecution() override; + void deinitExecution() override; void setMovieClip(MovieClip *image) { this->m_movieClip = image; @@ -63,7 +66,7 @@ class MovieClipBaseOperation : public NodeOperation { { this->m_framenumber = framenumber; } - void executePixelSampled(float output[4], float x, float y, PixelSampler sampler); + void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; }; class MovieClipOperation : public MovieClipBaseOperation { @@ -74,5 +77,7 @@ class MovieClipOperation : public MovieClipBaseOperation { class MovieClipAlphaOperation : public MovieClipBaseOperation { public: MovieClipAlphaOperation(); - void executePixelSampled(float output[4], float x, float y, PixelSampler sampler); + void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; }; + +} // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_MovieDistortionOperation.cc b/source/blender/compositor/operations/COM_MovieDistortionOperation.cc index fcd482a69ef..c8e045ea117 100644 --- a/source/blender/compositor/operations/COM_MovieDistortionOperation.cc +++ b/source/blender/compositor/operations/COM_MovieDistortionOperation.cc @@ -23,6 +23,8 @@ #include "BLI_linklist.h" +namespace blender::compositor { + MovieDistortionOperation::MovieDistortionOperation(bool distortion) { this->addInputSocket(DataType::Color); @@ -107,10 +109,10 @@ void MovieDistortionOperation::executePixelSampled(float output[4], float u = out[0] * aspx /* + 0.5 * overscan * w */, v = (out[1] * aspy /* + 0.5 * overscan * h */) * pixel_aspect; - this->m_inputOperation->readSampled(output, u, v, COM_PS_BILINEAR); + this->m_inputOperation->readSampled(output, u, v, PixelSampler::Bilinear); } else { - this->m_inputOperation->readSampled(output, x, y, COM_PS_BILINEAR); + this->m_inputOperation->readSampled(output, x, y, PixelSampler::Bilinear); } } @@ -125,3 +127,5 @@ bool MovieDistortionOperation::determineDependingAreaOfInterest(rcti *input, newInput.ymax = input->ymax + m_margin[1]; return NodeOperation::determineDependingAreaOfInterest(&newInput, readOperation, output); } + +} // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_MovieDistortionOperation.h b/source/blender/compositor/operations/COM_MovieDistortionOperation.h index f11ce485f97..631a62f7ebf 100644 --- a/source/blender/compositor/operations/COM_MovieDistortionOperation.h +++ b/source/blender/compositor/operations/COM_MovieDistortionOperation.h @@ -24,6 +24,8 @@ #include "BKE_tracking.h" +namespace blender::compositor { + class MovieDistortionOperation : public NodeOperation { private: SocketReader *m_inputOperation; @@ -40,10 +42,10 @@ class MovieDistortionOperation : public NodeOperation { public: MovieDistortionOperation(bool distortion); - void executePixelSampled(float output[4], float x, float y, PixelSampler sampler); + void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; - void initExecution(); - void deinitExecution(); + void initExecution() override; + void deinitExecution() override; void setMovieClip(MovieClip *clip) { @@ -55,5 +57,7 @@ class MovieDistortionOperation : public NodeOperation { } bool determineDependingAreaOfInterest(rcti *input, ReadBufferOperation *readOperation, - rcti *output); + rcti *output) override; }; + +} // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_MultilayerImageOperation.cc b/source/blender/compositor/operations/COM_MultilayerImageOperation.cc index 60936ee1939..647e93225e5 100644 --- a/source/blender/compositor/operations/COM_MultilayerImageOperation.cc +++ b/source/blender/compositor/operations/COM_MultilayerImageOperation.cc @@ -21,6 +21,8 @@ #include "IMB_imbuf.h" #include "IMB_imbuf_types.h" +namespace blender::compositor { + MultilayerBaseOperation::MultilayerBaseOperation(RenderLayer *render_layer, RenderPass *render_pass, int view) @@ -49,7 +51,7 @@ ImBuf *MultilayerBaseOperation::getImBuf() return nullptr; } -std::unique_ptr<MetaData> MultilayerColorOperation::getMetaData() const +std::unique_ptr<MetaData> MultilayerColorOperation::getMetaData() { BLI_assert(this->m_buffer); MetaDataExtractCallbackData callback_data = {nullptr}; @@ -86,13 +88,13 @@ void MultilayerColorOperation::executePixelSampled(float output[4], else { if (this->m_numberOfChannels == 4) { switch (sampler) { - case COM_PS_NEAREST: + case PixelSampler::Nearest: nearest_interpolation_color(this->m_buffer, nullptr, output, x, y); break; - case COM_PS_BILINEAR: + case PixelSampler::Bilinear: bilinear_interpolation_color(this->m_buffer, nullptr, output, x, y); break; - case COM_PS_BICUBIC: + case PixelSampler::Bicubic: bicubic_interpolation_color(this->m_buffer, nullptr, output, x, y); break; } @@ -155,3 +157,5 @@ void MultilayerVectorOperation::executePixelSampled(float output[4], } } } + +} // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_MultilayerImageOperation.h b/source/blender/compositor/operations/COM_MultilayerImageOperation.h index dceb57de140..6e6062cf854 100644 --- a/source/blender/compositor/operations/COM_MultilayerImageOperation.h +++ b/source/blender/compositor/operations/COM_MultilayerImageOperation.h @@ -20,6 +20,8 @@ #include "COM_ImageOperation.h" +namespace blender::compositor { + class MultilayerBaseOperation : public BaseImageOperation { private: int m_passId; @@ -45,7 +47,7 @@ class MultilayerColorOperation : public MultilayerBaseOperation { this->addOutputSocket(DataType::Color); } void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; - std::unique_ptr<MetaData> getMetaData() const override; + std::unique_ptr<MetaData> getMetaData() override; }; class MultilayerValueOperation : public MultilayerBaseOperation { @@ -67,3 +69,5 @@ class MultilayerVectorOperation : public MultilayerBaseOperation { } void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; }; + +} // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_NormalizeOperation.cc b/source/blender/compositor/operations/COM_NormalizeOperation.cc index fd3b951c842..faacb429f71 100644 --- a/source/blender/compositor/operations/COM_NormalizeOperation.cc +++ b/source/blender/compositor/operations/COM_NormalizeOperation.cc @@ -18,13 +18,15 @@ #include "COM_NormalizeOperation.h" +namespace blender::compositor { + NormalizeOperation::NormalizeOperation() { this->addInputSocket(DataType::Value); this->addOutputSocket(DataType::Value); this->m_imageReader = nullptr; this->m_cachedInstance = nullptr; - this->setComplex(true); + this->flags.complex = true; } void NormalizeOperation::initExecution() { @@ -124,3 +126,5 @@ void NormalizeOperation::deinitializeTileData(rcti * /*rect*/, void * /*data*/) { /* pass */ } + +} // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_NormalizeOperation.h b/source/blender/compositor/operations/COM_NormalizeOperation.h index 8090cf4973b..93d4a0fc67d 100644 --- a/source/blender/compositor/operations/COM_NormalizeOperation.h +++ b/source/blender/compositor/operations/COM_NormalizeOperation.h @@ -21,6 +21,8 @@ #include "COM_NodeOperation.h" #include "DNA_node_types.h" +namespace blender::compositor { + /** * \brief base class of normalize, implementing the simple normalize * \ingroup operation @@ -44,22 +46,24 @@ class NormalizeOperation : public NodeOperation { /** * The inner loop of this operation. */ - void executePixel(float output[4], int x, int y, void *data); + void executePixel(float output[4], int x, int y, void *data) override; /** * Initialize the execution */ - void initExecution(); + void initExecution() override; - void *initializeTileData(rcti *rect); - void deinitializeTileData(rcti *rect, void *data); + void *initializeTileData(rcti *rect) override; + void deinitializeTileData(rcti *rect, void *data) override; /** * Deinitialize the execution */ - void deinitExecution(); + void deinitExecution() override; bool determineDependingAreaOfInterest(rcti *input, ReadBufferOperation *readOperation, - rcti *output); + rcti *output) override; }; + +} // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_OutputFileMultiViewOperation.cc b/source/blender/compositor/operations/COM_OutputFileMultiViewOperation.cc index 7044fe402eb..5b6f650d40e 100644 --- a/source/blender/compositor/operations/COM_OutputFileMultiViewOperation.cc +++ b/source/blender/compositor/operations/COM_OutputFileMultiViewOperation.cc @@ -37,6 +37,8 @@ #include "IMB_imbuf.h" #include "IMB_imbuf_types.h" +namespace blender::compositor { + /************************************ OpenEXR Singlelayer Multiview ******************************/ OutputOpenExrSingleLayerMultiViewOperation::OutputOpenExrSingleLayerMultiViewOperation( @@ -380,3 +382,5 @@ void OutputStereoOperation::deinitExecution() } } } + +} // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_OutputFileMultiViewOperation.h b/source/blender/compositor/operations/COM_OutputFileMultiViewOperation.h index 258ac1f9e98..6230a6f306b 100644 --- a/source/blender/compositor/operations/COM_OutputFileMultiViewOperation.h +++ b/source/blender/compositor/operations/COM_OutputFileMultiViewOperation.h @@ -28,6 +28,8 @@ #include "intern/openexr/openexr_multi.h" +namespace blender::compositor { + class OutputOpenExrSingleLayerMultiViewOperation : public OutputSingleLayerOperation { private: public: @@ -42,7 +44,7 @@ class OutputOpenExrSingleLayerMultiViewOperation : public OutputSingleLayerOpera const bool saveAsRender); void *get_handle(const char *filename); - void deinitExecution(); + void deinitExecution() override; }; /* Writes inputs into OpenEXR multilayer channels. */ @@ -58,7 +60,7 @@ class OutputOpenExrMultiLayerMultiViewOperation : public OutputOpenExrMultiLayer const char *viewName); void *get_handle(const char *filename); - void deinitExecution(); + void deinitExecution() override; }; class OutputStereoOperation : public OutputSingleLayerOperation { @@ -78,5 +80,7 @@ class OutputStereoOperation : public OutputSingleLayerOperation { const char *viewName, const bool saveAsRender); void *get_handle(const char *filename); - void deinitExecution(); + void deinitExecution() override; }; + +} // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_OutputFileOperation.cc b/source/blender/compositor/operations/COM_OutputFileOperation.cc index a6135ef064c..5184cd42b9e 100644 --- a/source/blender/compositor/operations/COM_OutputFileOperation.cc +++ b/source/blender/compositor/operations/COM_OutputFileOperation.cc @@ -40,6 +40,8 @@ #include "RE_pipeline.h" +namespace blender::compositor { + void add_exr_channels(void *exrhandle, const char *layerName, const DataType datatype, @@ -191,7 +193,7 @@ static void write_buffer_rect(rcti *rect, for (y = y1; y < y2 && (!breaked); y++) { for (x = x1; x < x2 && (!breaked); x++) { - reader->readSampled(color, x, y, COM_PS_NEAREST); + reader->readSampled(color, x, y, PixelSampler::Nearest); for (i = 0; i < size; i++) { buffer[offset + i] = color[i]; @@ -328,7 +330,7 @@ void OutputOpenExrMultiLayerOperation::add_layer(const char *name, bool use_layer) { this->addInputSocket(datatype); - this->m_layers.push_back(OutputOpenExrLayer(name, datatype, use_layer)); + this->m_layers.append(OutputOpenExrLayer(name, datatype, use_layer)); } StampData *OutputOpenExrMultiLayerOperation::createStampData() const @@ -338,17 +340,16 @@ StampData *OutputOpenExrMultiLayerOperation::createStampData() const RenderResult render_result; StampData *stamp_data = BKE_stamp_info_from_scene_static(m_scene); render_result.stamp_data = stamp_data; - for (int i = 0; i < this->m_layers.size(); i++) { - const OutputOpenExrLayer *layer = &this->m_layers[i]; + for (const OutputOpenExrLayer &layer : m_layers) { /* Skip unconnected sockets. */ - if (layer->imageInput == nullptr) { + if (layer.imageInput == nullptr) { continue; } - std::unique_ptr<MetaData> meta_data = layer->imageInput->getMetaData(); + std::unique_ptr<MetaData> meta_data = layer.imageInput->getMetaData(); if (meta_data) { blender::StringRef layer_name = blender::bke::cryptomatte::BKE_cryptomatte_extract_layer_name( - blender::StringRef(layer->name, BLI_strnlen(layer->name, sizeof(layer->name)))); + blender::StringRef(layer.name, BLI_strnlen(layer.name, sizeof(layer.name)))); meta_data->replaceHashNeutralCryptomatteKeys(layer_name); meta_data->addToRenderResult(&render_result); } @@ -441,3 +442,5 @@ void OutputOpenExrMultiLayerOperation::deinitExecution() BKE_stamp_data_free(stamp_data); } } + +} // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_OutputFileOperation.h b/source/blender/compositor/operations/COM_OutputFileOperation.h index ecc52355824..6415891032a 100644 --- a/source/blender/compositor/operations/COM_OutputFileOperation.h +++ b/source/blender/compositor/operations/COM_OutputFileOperation.h @@ -27,6 +27,8 @@ #include "intern/openexr/openexr_multi.h" +namespace blender::compositor { + /* Writes the image to a single-layer file. */ class OutputSingleLayerOperation : public NodeOperation { protected: @@ -57,22 +59,17 @@ class OutputSingleLayerOperation : public NodeOperation { const char *viewName, const bool saveAsRender); - void executeRegion(rcti *rect, unsigned int tileNumber); - bool isOutputOperation(bool /*rendering*/) const + void executeRegion(rcti *rect, unsigned int tileNumber) override; + bool isOutputOperation(bool /*rendering*/) const override { return true; } - void initExecution(); - void deinitExecution(); - CompositorPriority getRenderPriority() const + void initExecution() override; + void deinitExecution() override; + CompositorPriority getRenderPriority() const override { return CompositorPriority::Low; } - - bool isFileOutputOperation() const - { - return true; - } }; /* extra info for OpenEXR layers */ @@ -91,8 +88,6 @@ struct OutputOpenExrLayer { /* Writes inputs into OpenEXR multilayer channels. */ class OutputOpenExrMultiLayerOperation : public NodeOperation { protected: - typedef std::vector<OutputOpenExrLayer> LayerList; - const Scene *m_scene; const RenderData *m_rd; const bNodeTree *m_tree; @@ -100,7 +95,7 @@ class OutputOpenExrMultiLayerOperation : public NodeOperation { char m_path[FILE_MAX]; char m_exr_codec; bool m_exr_half_float; - LayerList m_layers; + blender::Vector<OutputOpenExrLayer> m_layers; const char *m_viewName; StampData *createStampData() const; @@ -116,22 +111,17 @@ class OutputOpenExrMultiLayerOperation : public NodeOperation { void add_layer(const char *name, DataType datatype, bool use_layer); - void executeRegion(rcti *rect, unsigned int tileNumber); - bool isOutputOperation(bool /*rendering*/) const + void executeRegion(rcti *rect, unsigned int tileNumber) override; + bool isOutputOperation(bool /*rendering*/) const override { return true; } - void initExecution(); - void deinitExecution(); - CompositorPriority getRenderPriority() const + void initExecution() override; + void deinitExecution() override; + CompositorPriority getRenderPriority() const override { return CompositorPriority::Low; } - - bool isFileOutputOperation() const - { - return true; - } }; void add_exr_channels(void *exrhandle, @@ -146,3 +136,5 @@ void free_exr_channels(void *exrhandle, const char *layerName, const DataType datatype); int get_datatype_size(DataType datatype); + +} // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_PixelateOperation.cc b/source/blender/compositor/operations/COM_PixelateOperation.cc index 0d810c80ab4..94827cd1b02 100644 --- a/source/blender/compositor/operations/COM_PixelateOperation.cc +++ b/source/blender/compositor/operations/COM_PixelateOperation.cc @@ -18,6 +18,8 @@ #include "COM_PixelateOperation.h" +namespace blender::compositor { + PixelateOperation::PixelateOperation(DataType datatype) { this->addInputSocket(datatype); @@ -45,3 +47,5 @@ void PixelateOperation::executePixelSampled(float output[4], float ny = round(y); this->m_inputOperation->readSampled(output, nx, ny, sampler); } + +} // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_PixelateOperation.h b/source/blender/compositor/operations/COM_PixelateOperation.h index c7595756d39..e8b272853da 100644 --- a/source/blender/compositor/operations/COM_PixelateOperation.h +++ b/source/blender/compositor/operations/COM_PixelateOperation.h @@ -20,6 +20,8 @@ #include "COM_NodeOperation.h" +namespace blender::compositor { + /** * \brief Pixelate operation * @@ -44,12 +46,12 @@ class PixelateOperation : public NodeOperation { /** * \brief initialization of the execution */ - void initExecution(); + void initExecution() override; /** * \brief de-initialization of the execution */ - void deinitExecution(); + void deinitExecution() override; /** * \brief executePixel @@ -58,5 +60,7 @@ class PixelateOperation : public NodeOperation { * \param y: y-coordinate * \param sampler: sampler */ - void executePixelSampled(float output[4], float x, float y, PixelSampler sampler); + void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; }; + +} // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_PlaneCornerPinOperation.cc b/source/blender/compositor/operations/COM_PlaneCornerPinOperation.cc index bcf79e1c6c6..3577860b93d 100644 --- a/source/blender/compositor/operations/COM_PlaneCornerPinOperation.cc +++ b/source/blender/compositor/operations/COM_PlaneCornerPinOperation.cc @@ -26,6 +26,8 @@ #include "BKE_node.h" +namespace blender::compositor { + static bool check_corners(float corners[4][2]) { int i, next, prev; @@ -60,7 +62,7 @@ static void readCornersFromSockets(rcti *rect, SocketReader *readers[4], float c { for (int i = 0; i < 4; i++) { float result[4] = {0.0f, 0.0f, 0.0f, 0.0f}; - readers[i]->readSampled(result, rect->xmin, rect->ymin, COM_PS_NEAREST); + readers[i]->readSampled(result, rect->xmin, rect->ymin, PixelSampler::Nearest); corners[i][0] = result[0]; corners[i][1] = result[1]; } @@ -98,7 +100,7 @@ PlaneCornerPinMaskOperation::PlaneCornerPinMaskOperation() : m_corners_ready(fal * so we can use the initializeTileData function * to read corners from input sockets ... */ - setComplex(true); + flags.complex = true; } void PlaneCornerPinMaskOperation::initExecution() @@ -224,3 +226,5 @@ bool PlaneCornerPinWarpImageOperation::determineDependingAreaOfInterest( input, readOperation, output); #endif } + +} // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_PlaneCornerPinOperation.h b/source/blender/compositor/operations/COM_PlaneCornerPinOperation.h index 1e892465db8..91c0cd9e16b 100644 --- a/source/blender/compositor/operations/COM_PlaneCornerPinOperation.h +++ b/source/blender/compositor/operations/COM_PlaneCornerPinOperation.h @@ -27,6 +27,8 @@ #include "BLI_listbase.h" #include "BLI_string.h" +namespace blender::compositor { + class PlaneCornerPinMaskOperation : public PlaneDistortMaskOperation { private: bool m_corners_ready; @@ -34,12 +36,13 @@ class PlaneCornerPinMaskOperation : public PlaneDistortMaskOperation { public: PlaneCornerPinMaskOperation(); - void initExecution(); - void deinitExecution(); + void initExecution() override; + void deinitExecution() override; - void *initializeTileData(rcti *rect); + void *initializeTileData(rcti *rect) override; - void determineResolution(unsigned int resolution[2], unsigned int preferredResolution[2]); + void determineResolution(unsigned int resolution[2], + unsigned int preferredResolution[2]) override; }; class PlaneCornerPinWarpImageOperation : public PlaneDistortWarpImageOperation { @@ -49,12 +52,14 @@ class PlaneCornerPinWarpImageOperation : public PlaneDistortWarpImageOperation { public: PlaneCornerPinWarpImageOperation(); - void initExecution(); - void deinitExecution(); + void initExecution() override; + void deinitExecution() override; - void *initializeTileData(rcti *rect); + void *initializeTileData(rcti *rect) override; bool determineDependingAreaOfInterest(rcti *input, ReadBufferOperation *readOperation, - rcti *output); + rcti *output) override; }; + +} // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_PlaneDistortCommonOperation.cc b/source/blender/compositor/operations/COM_PlaneDistortCommonOperation.cc index 87f837973d2..46ae00dee34 100644 --- a/source/blender/compositor/operations/COM_PlaneDistortCommonOperation.cc +++ b/source/blender/compositor/operations/COM_PlaneDistortCommonOperation.cc @@ -29,6 +29,8 @@ #include "BKE_node.h" #include "BKE_tracking.h" +namespace blender::compositor { + /* ******** PlaneDistort WarpImage ******** */ BLI_INLINE void warpCoord(float x, float y, float matrix[3][3], float uv[2], float deriv[2][2]) @@ -46,12 +48,12 @@ BLI_INLINE void warpCoord(float x, float y, float matrix[3][3], float uv[2], flo PlaneDistortWarpImageOperation::PlaneDistortWarpImageOperation() { - this->addInputSocket(DataType::Color, COM_SC_NO_RESIZE); + this->addInputSocket(DataType::Color, ResizeMode::None); this->addOutputSocket(DataType::Color); this->m_pixelReader = nullptr; this->m_motion_blur_samples = 1; this->m_motion_blur_shutter = 0.5f; - this->setComplex(true); + this->flags.complex = true; } void PlaneDistortWarpImageOperation::calculateCorners(const float corners[4][2], @@ -226,3 +228,5 @@ void PlaneDistortMaskOperation::executePixelSampled(float output[4], output[0] = (float)inside_counter / (this->m_osa * this->m_motion_blur_samples); } } + +} // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_PlaneDistortCommonOperation.h b/source/blender/compositor/operations/COM_PlaneDistortCommonOperation.h index 6cc9456c13f..95e5c86bd4d 100644 --- a/source/blender/compositor/operations/COM_PlaneDistortCommonOperation.h +++ b/source/blender/compositor/operations/COM_PlaneDistortCommonOperation.h @@ -28,6 +28,8 @@ #include "BLI_listbase.h" #include "BLI_string.h" +namespace blender::compositor { + #define PLANE_DISTORT_MAX_SAMPLES 64 class PlaneDistortWarpImageOperation : public NodeOperation { @@ -46,14 +48,14 @@ class PlaneDistortWarpImageOperation : public NodeOperation { void calculateCorners(const float corners[4][2], bool normalized, int sample); - void initExecution(); - void deinitExecution(); + void initExecution() override; + void deinitExecution() override; - void executePixelSampled(float output[4], float x, float y, PixelSampler sampler); + void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; bool determineDependingAreaOfInterest(rcti *input, ReadBufferOperation *readOperation, - rcti *output); + rcti *output) override; void setMotionBlurSamples(int samples) { @@ -82,9 +84,9 @@ class PlaneDistortMaskOperation : public NodeOperation { void calculateCorners(const float corners[4][2], bool normalized, int sample); - void initExecution(); + void initExecution() override; - void executePixelSampled(float output[4], float x, float y, PixelSampler sampler); + void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; void setMotionBlurSamples(int samples) { @@ -96,3 +98,5 @@ class PlaneDistortMaskOperation : public NodeOperation { this->m_motion_blur_shutter = shutter; } }; + +} // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_PlaneTrackOperation.cc b/source/blender/compositor/operations/COM_PlaneTrackOperation.cc index 81a598e937b..565bde6c945 100644 --- a/source/blender/compositor/operations/COM_PlaneTrackOperation.cc +++ b/source/blender/compositor/operations/COM_PlaneTrackOperation.cc @@ -29,6 +29,8 @@ #include "BKE_node.h" #include "BKE_tracking.h" +namespace blender::compositor { + /* ******** PlaneTrackCommon ******** */ PlaneTrackCommon::PlaneTrackCommon() @@ -121,3 +123,5 @@ void PlaneTrackWarpImageOperation::initExecution() } } } + +} // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_PlaneTrackOperation.h b/source/blender/compositor/operations/COM_PlaneTrackOperation.h index fc325c7db7d..95a7d536742 100644 --- a/source/blender/compositor/operations/COM_PlaneTrackOperation.h +++ b/source/blender/compositor/operations/COM_PlaneTrackOperation.h @@ -28,6 +28,8 @@ #include "BLI_listbase.h" #include "BLI_string.h" +namespace blender::compositor { + class PlaneTrackCommon { protected: MovieClip *m_movieClip; @@ -68,9 +70,10 @@ class PlaneTrackMaskOperation : public PlaneDistortMaskOperation, public PlaneTr { } - void initExecution(); + void initExecution() override; - void determineResolution(unsigned int resolution[2], unsigned int preferredResolution[2]) + void determineResolution(unsigned int resolution[2], + unsigned int preferredResolution[2]) override { PlaneTrackCommon::determineResolution(resolution, preferredResolution); @@ -86,12 +89,15 @@ class PlaneTrackWarpImageOperation : public PlaneDistortWarpImageOperation, { } - void initExecution(); + void initExecution() override; - void determineResolution(unsigned int resolution[2], unsigned int preferredResolution[2]) + void determineResolution(unsigned int resolution[2], + unsigned int preferredResolution[2]) override { PlaneTrackCommon::determineResolution(resolution, preferredResolution); unsigned int temp[2]; NodeOperation::determineResolution(temp, resolution); } }; + +} // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_PreviewOperation.cc b/source/blender/compositor/operations/COM_PreviewOperation.cc index 6d1199ab118..9a1990740f4 100644 --- a/source/blender/compositor/operations/COM_PreviewOperation.cc +++ b/source/blender/compositor/operations/COM_PreviewOperation.cc @@ -33,13 +33,15 @@ #include "IMB_imbuf.h" #include "IMB_imbuf_types.h" +namespace blender::compositor { + PreviewOperation::PreviewOperation(const ColorManagedViewSettings *viewSettings, const ColorManagedDisplaySettings *displaySettings, const unsigned int defaultWidth, const unsigned int defaultHeight) { - this->addInputSocket(DataType::Color, COM_SC_NO_RESIZE); + this->addInputSocket(DataType::Color, ResizeMode::None); this->m_preview = nullptr; this->m_outputBuffer = nullptr; this->m_input = nullptr; @@ -48,6 +50,8 @@ PreviewOperation::PreviewOperation(const ColorManagedViewSettings *viewSettings, this->m_displaySettings = displaySettings; this->m_defaultWidth = defaultWidth; this->m_defaultHeight = defaultHeight; + flags.use_viewer_border = true; + flags.is_preview_operation = true; } void PreviewOperation::verifyPreview(bNodeInstanceHash *previews, bNodeInstanceKey key) @@ -104,7 +108,7 @@ void PreviewOperation::executeRegion(rcti *rect, unsigned int /*tileNumber*/) color[1] = 0.0f; color[2] = 0.0f; color[3] = 1.0f; - this->m_input->readSampled(color, rx, ry, COM_PS_NEAREST); + this->m_input->readSampled(color, rx, ry, PixelSampler::Nearest); IMB_colormanagement_processor_apply_v4(cm_processor, color); rgba_float_to_uchar(this->m_outputBuffer + offset, color); offset += 4; @@ -166,3 +170,5 @@ CompositorPriority PreviewOperation::getRenderPriority() const { return CompositorPriority::Low; } + +} // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_PreviewOperation.h b/source/blender/compositor/operations/COM_PreviewOperation.h index 03ae6a6c42e..5e2b27475a1 100644 --- a/source/blender/compositor/operations/COM_PreviewOperation.h +++ b/source/blender/compositor/operations/COM_PreviewOperation.h @@ -24,6 +24,8 @@ #include "DNA_color_types.h" #include "DNA_image_types.h" +namespace blender::compositor { + class PreviewOperation : public NodeOperation { protected: unsigned char *m_outputBuffer; @@ -47,21 +49,20 @@ class PreviewOperation : public NodeOperation { unsigned int defaultHeight); void verifyPreview(bNodeInstanceHash *previews, bNodeInstanceKey key); - bool isOutputOperation(bool /*rendering*/) const + bool isOutputOperation(bool /*rendering*/) const override { return !G.background; } - void initExecution(); - void deinitExecution(); - CompositorPriority getRenderPriority() const; + void initExecution() override; + void deinitExecution() override; + CompositorPriority getRenderPriority() const override; - void executeRegion(rcti *rect, unsigned int tileNumber); - void determineResolution(unsigned int resolution[2], unsigned int preferredResolution[2]); + void executeRegion(rcti *rect, unsigned int tileNumber) override; + void determineResolution(unsigned int resolution[2], + unsigned int preferredResolution[2]) override; bool determineDependingAreaOfInterest(rcti *input, ReadBufferOperation *readOperation, - rcti *output); - bool isPreviewOperation() const - { - return true; - } + rcti *output) override; }; + +} // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_ProjectorLensDistortionOperation.cc b/source/blender/compositor/operations/COM_ProjectorLensDistortionOperation.cc index 5494c3cd46b..93702d3f0cf 100644 --- a/source/blender/compositor/operations/COM_ProjectorLensDistortionOperation.cc +++ b/source/blender/compositor/operations/COM_ProjectorLensDistortionOperation.cc @@ -20,12 +20,14 @@ #include "BLI_math.h" #include "BLI_utildefines.h" +namespace blender::compositor { + ProjectorLensDistortionOperation::ProjectorLensDistortionOperation() { this->addInputSocket(DataType::Color); this->addInputSocket(DataType::Value); this->addOutputSocket(DataType::Color); - this->setComplex(true); + this->flags.complex = true; this->m_inputProgram = nullptr; this->m_dispersionAvailable = false; this->m_dispersion = 0.0f; @@ -103,7 +105,7 @@ void ProjectorLensDistortionOperation::updateDispersion() this->lockMutex(); if (!this->m_dispersionAvailable) { float result[4]; - this->getInputSocketReader(1)->readSampled(result, 1, 1, COM_PS_NEAREST); + this->getInputSocketReader(1)->readSampled(result, 1, 1, PixelSampler::Nearest); this->m_dispersion = result[0]; this->m_kr = 0.25f * max_ff(min_ff(this->m_dispersion, 1.0f), 0.0f); this->m_kr2 = this->m_kr * 20; @@ -111,3 +113,5 @@ void ProjectorLensDistortionOperation::updateDispersion() } this->unlockMutex(); } + +} // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_ProjectorLensDistortionOperation.h b/source/blender/compositor/operations/COM_ProjectorLensDistortionOperation.h index 96bede20623..bce61d3de15 100644 --- a/source/blender/compositor/operations/COM_ProjectorLensDistortionOperation.h +++ b/source/blender/compositor/operations/COM_ProjectorLensDistortionOperation.h @@ -21,6 +21,8 @@ #include "COM_NodeOperation.h" #include "DNA_node_types.h" +namespace blender::compositor { + class ProjectorLensDistortionOperation : public NodeOperation { private: /** @@ -39,22 +41,24 @@ class ProjectorLensDistortionOperation : public NodeOperation { /** * The inner loop of this operation. */ - void executePixel(float output[4], int x, int y, void *data); + void executePixel(float output[4], int x, int y, void *data) override; /** * Initialize the execution */ - void initExecution(); + void initExecution() override; - void *initializeTileData(rcti *rect); + void *initializeTileData(rcti *rect) override; /** * Deinitialize the execution */ - void deinitExecution(); + void deinitExecution() override; bool determineDependingAreaOfInterest(rcti *input, ReadBufferOperation *readOperation, - rcti *output); + rcti *output) override; void updateDispersion(); }; + +} // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_QualityStepHelper.cc b/source/blender/compositor/operations/COM_QualityStepHelper.cc index c0d86314fb7..385e0bebca4 100644 --- a/source/blender/compositor/operations/COM_QualityStepHelper.cc +++ b/source/blender/compositor/operations/COM_QualityStepHelper.cc @@ -18,6 +18,8 @@ #include "COM_QualityStepHelper.h" +namespace blender::compositor { + QualityStepHelper::QualityStepHelper() { this->m_quality = CompositorQuality::High; @@ -64,3 +66,5 @@ void QualityStepHelper::initExecution(QualityHelper helper) break; } } + +} // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_QualityStepHelper.h b/source/blender/compositor/operations/COM_QualityStepHelper.h index e437613fb29..bc2eaa88e3d 100644 --- a/source/blender/compositor/operations/COM_QualityStepHelper.h +++ b/source/blender/compositor/operations/COM_QualityStepHelper.h @@ -20,6 +20,8 @@ #include "COM_defines.h" +namespace blender::compositor { + typedef enum QualityHelper { COM_QH_INCREASE, COM_QH_MULTIPLY, @@ -54,3 +56,5 @@ class QualityStepHelper { this->m_quality = quality; } }; + +} // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_ReadBufferOperation.cc b/source/blender/compositor/operations/COM_ReadBufferOperation.cc index 2977e6685d2..cc58f29e8d9 100644 --- a/source/blender/compositor/operations/COM_ReadBufferOperation.cc +++ b/source/blender/compositor/operations/COM_ReadBufferOperation.cc @@ -20,12 +20,15 @@ #include "COM_WriteBufferOperation.h" #include "COM_defines.h" +namespace blender::compositor { + ReadBufferOperation::ReadBufferOperation(DataType datatype) { this->addOutputSocket(datatype); this->m_single_value = false; this->m_offset = 0; this->m_buffer = nullptr; + flags.is_read_buffer_operation = true; } void *ReadBufferOperation::initializeTileData(rcti * /*rect*/) @@ -60,14 +63,14 @@ void ReadBufferOperation::executePixelSampled(float output[4], } else { switch (sampler) { - case COM_PS_NEAREST: + case PixelSampler::Nearest: m_buffer->read(output, x, y); break; - case COM_PS_BILINEAR: + case PixelSampler::Bilinear: default: m_buffer->readBilinear(output, x, y); break; - case COM_PS_BICUBIC: + case PixelSampler::Bicubic: m_buffer->readBilinear(output, x, y); break; } @@ -85,7 +88,7 @@ void ReadBufferOperation::executePixelExtend(float output[4], /* write buffer has a single value stored at (0,0) */ m_buffer->read(output, 0, 0); } - else if (sampler == COM_PS_NEAREST) { + else if (sampler == PixelSampler::Nearest) { m_buffer->read(output, x, y, extend_x, extend_y); } else { @@ -131,3 +134,5 @@ void ReadBufferOperation::updateMemoryBuffer() { this->m_buffer = this->getMemoryProxy()->getBuffer(); } + +} // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_ReadBufferOperation.h b/source/blender/compositor/operations/COM_ReadBufferOperation.h index 2ada33906ef..981c09292af 100644 --- a/source/blender/compositor/operations/COM_ReadBufferOperation.h +++ b/source/blender/compositor/operations/COM_ReadBufferOperation.h @@ -22,6 +22,8 @@ #include "COM_MemoryProxy.h" #include "COM_NodeOperation.h" +namespace blender::compositor { + class ReadBufferOperation : public NodeOperation { private: MemoryProxy *m_memoryProxy; @@ -39,21 +41,18 @@ class ReadBufferOperation : public NodeOperation { { return this->m_memoryProxy; } - void determineResolution(unsigned int resolution[2], unsigned int preferredResolution[2]); + void determineResolution(unsigned int resolution[2], + unsigned int preferredResolution[2]) override; - void *initializeTileData(rcti *rect); - void executePixelSampled(float output[4], float x, float y, PixelSampler sampler); + void *initializeTileData(rcti *rect) override; + void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; void executePixelExtend(float output[4], float x, float y, PixelSampler sampler, MemoryBufferExtend extend_x, MemoryBufferExtend extend_y); - void executePixelFiltered(float output[4], float x, float y, float dx[2], float dy[2]); - bool isReadBufferOperation() const - { - return true; - } + void executePixelFiltered(float output[4], float x, float y, float dx[2], float dy[2]) override; void setOffset(unsigned int offset) { this->m_offset = offset; @@ -64,11 +63,13 @@ class ReadBufferOperation : public NodeOperation { } bool determineDependingAreaOfInterest(rcti *input, ReadBufferOperation *readOperation, - rcti *output); - MemoryBuffer *getInputMemoryBuffer(MemoryBuffer **memoryBuffers) + rcti *output) override; + MemoryBuffer *getInputMemoryBuffer(MemoryBuffer **memoryBuffers) override { return memoryBuffers[this->m_offset]; } void readResolutionFromWriteBuffer(); void updateMemoryBuffer(); }; + +} // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_RenderLayersProg.cc b/source/blender/compositor/operations/COM_RenderLayersProg.cc index d622e14b585..1ac451b95c2 100644 --- a/source/blender/compositor/operations/COM_RenderLayersProg.cc +++ b/source/blender/compositor/operations/COM_RenderLayersProg.cc @@ -32,6 +32,8 @@ #include "RE_pipeline.h" #include "RE_texture.h" +namespace blender::compositor { + /* ******** Render Layers Base Prog ******** */ RenderLayersProg::RenderLayersProg(const char *passName, DataType type, int elementsize) @@ -92,7 +94,7 @@ void RenderLayersProg::doInterpolation(float output[4], float x, float y, PixelS } switch (sampler) { - case COM_PS_NEAREST: { + case PixelSampler::Nearest: { offset = (iy * width + ix) * this->m_elementsize; if (this->m_elementsize == 1) { @@ -107,12 +109,12 @@ void RenderLayersProg::doInterpolation(float output[4], float x, float y, PixelS break; } - case COM_PS_BILINEAR: + case PixelSampler::Bilinear: BLI_bilinear_interpolation_fl( this->m_inputBuffer, output, width, height, this->m_elementsize, x, y); break; - case COM_PS_BICUBIC: + case PixelSampler::Bicubic: BLI_bicubic_interpolation_fl( this->m_inputBuffer, output, width, height, this->m_elementsize, x, y); break; @@ -216,7 +218,7 @@ void RenderLayersProg::determineResolution(unsigned int resolution[2], } } -std::unique_ptr<MetaData> RenderLayersProg::getMetaData() const +std::unique_ptr<MetaData> RenderLayersProg::getMetaData() { Scene *scene = this->getScene(); Render *re = (scene) ? RE_GetSceneRender(scene) : nullptr; @@ -306,3 +308,5 @@ void RenderLayersDepthProg::executePixelSampled(float output[4], output[0] = inputBuffer[offset]; } } + +} // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_RenderLayersProg.h b/source/blender/compositor/operations/COM_RenderLayersProg.h index a0d5bc2953b..33e4fb163c5 100644 --- a/source/blender/compositor/operations/COM_RenderLayersProg.h +++ b/source/blender/compositor/operations/COM_RenderLayersProg.h @@ -26,6 +26,8 @@ #include "RE_pipeline.h" +namespace blender::compositor { + /** * Base class for all renderlayeroperations * @@ -123,7 +125,7 @@ class RenderLayersProg : public NodeOperation { void deinitExecution() override; void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; - std::unique_ptr<MetaData> getMetaData() const override; + std::unique_ptr<MetaData> getMetaData() override; }; class RenderLayersAOOperation : public RenderLayersProg { @@ -132,7 +134,7 @@ class RenderLayersAOOperation : public RenderLayersProg { : RenderLayersProg(passName, type, elementsize) { } - void executePixelSampled(float output[4], float x, float y, PixelSampler sampler); + void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; }; class RenderLayersAlphaProg : public RenderLayersProg { @@ -141,7 +143,7 @@ class RenderLayersAlphaProg : public RenderLayersProg { : RenderLayersProg(passName, type, elementsize) { } - void executePixelSampled(float output[4], float x, float y, PixelSampler sampler); + void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; }; class RenderLayersDepthProg : public RenderLayersProg { @@ -150,5 +152,7 @@ class RenderLayersDepthProg : public RenderLayersProg { : RenderLayersProg(passName, type, elementsize) { } - void executePixelSampled(float output[4], float x, float y, PixelSampler sampler); + void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; }; + +} // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_RotateOperation.cc b/source/blender/compositor/operations/COM_RotateOperation.cc index c2105efe246..4fb3d324992 100644 --- a/source/blender/compositor/operations/COM_RotateOperation.cc +++ b/source/blender/compositor/operations/COM_RotateOperation.cc @@ -19,6 +19,8 @@ #include "COM_RotateOperation.h" #include "BLI_math.h" +namespace blender::compositor { + RotateOperation::RotateOperation() { this->addInputSocket(DataType::Color); @@ -48,7 +50,7 @@ inline void RotateOperation::ensureDegree() { if (!this->m_isDegreeSet) { float degree[4]; - this->m_degreeSocket->readSampled(degree, 0, 0, COM_PS_NEAREST); + this->m_degreeSocket->readSampled(degree, 0, 0, PixelSampler::Nearest); double rad; if (this->m_doDegree2RadConversion) { rad = DEG2RAD((double)degree[0]); @@ -105,3 +107,5 @@ bool RotateOperation::determineDependingAreaOfInterest(rcti *input, return NodeOperation::determineDependingAreaOfInterest(&newInput, readOperation, output); } + +} // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_RotateOperation.h b/source/blender/compositor/operations/COM_RotateOperation.h index 0ef4466671a..d76507f9816 100644 --- a/source/blender/compositor/operations/COM_RotateOperation.h +++ b/source/blender/compositor/operations/COM_RotateOperation.h @@ -20,6 +20,8 @@ #include "COM_NodeOperation.h" +namespace blender::compositor { + class RotateOperation : public NodeOperation { private: SocketReader *m_imageSocket; @@ -35,10 +37,10 @@ class RotateOperation : public NodeOperation { RotateOperation(); bool determineDependingAreaOfInterest(rcti *input, ReadBufferOperation *readOperation, - rcti *output); - void executePixelSampled(float output[4], float x, float y, PixelSampler sampler); - void initExecution(); - void deinitExecution(); + rcti *output) override; + void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; + void initExecution() override; + void deinitExecution() override; void setDoDegree2RadConversion(bool abool) { this->m_doDegree2RadConversion = abool; @@ -46,3 +48,5 @@ class RotateOperation : public NodeOperation { void ensureDegree(); }; + +} // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_SMAAOperation.cc b/source/blender/compositor/operations/COM_SMAAOperation.cc new file mode 100644 index 00000000000..38700c76f07 --- /dev/null +++ b/source/blender/compositor/operations/COM_SMAAOperation.cc @@ -0,0 +1,868 @@ +/* + * Copyright 2017, Blender Foundation. + * + * 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. + * + * Contributor: IRIE Shinsuke + */ + +#include "COM_SMAAOperation.h" +#include "BLI_math.h" +#include "COM_SMAAAreaTexture.h" + +extern "C" { +#include "IMB_colormanagement.h" +} + +namespace blender::compositor { + +/* + * An implementation of Enhanced Subpixel Morphological Antialiasing (SMAA) + * + * The algorithm was proposed by: + * Jorge Jimenez, Jose I. Echevarria, Tiago Sousa, Diego Gutierrez + * + * http://www.iryoku.com/smaa/ + * + * This file is based on smaa-cpp: + * + * https://github.com/iRi-E/smaa-cpp + * + * Currently only SMAA 1x mode is provided, so the operation will be done + * with no spatial multisampling nor temporal supersampling. + * + * Note: This program assumes the screen coordinates are DirectX style, so + * the vertical direction is upside-down. "top" and "bottom" actually mean + * bottom and top, respectively. + */ + +/*-----------------------------------------------------------------------------*/ +/* Non-Configurable Defines */ + +#define SMAA_AREATEX_SIZE 80 +#define SMAA_AREATEX_MAX_DISTANCE 20 +#define SMAA_AREATEX_MAX_DISTANCE_DIAG 20 +#define SMAA_MAX_SEARCH_STEPS 362 /* 362 - 1 = 19^2 */ +#define SMAA_MAX_SEARCH_STEPS_DIAG 19 + +/*-----------------------------------------------------------------------------*/ +/* Internal Functions to Sample Pixel Color from Image */ + +static inline void sample(SocketReader *reader, int x, int y, float color[4]) +{ + if (x < 0 || x >= reader->getWidth() || y < 0 || y >= reader->getHeight()) { + color[0] = color[1] = color[2] = color[3] = 0.0; + return; + } + + reader->read(color, x, y, nullptr); +} + +static void sample_bilinear_vertical( + SocketReader *reader, int x, int y, float yoffset, float color[4]) +{ + float iy = floorf(yoffset); + float fy = yoffset - iy; + y += (int)iy; + + float color00[4], color01[4]; + + sample(reader, x + 0, y + 0, color00); + sample(reader, x + 0, y + 1, color01); + + color[0] = interpf(color01[0], color00[0], fy); + color[1] = interpf(color01[1], color00[1], fy); + color[2] = interpf(color01[2], color00[2], fy); + color[3] = interpf(color01[3], color00[3], fy); +} + +static void sample_bilinear_horizontal( + SocketReader *reader, int x, int y, float xoffset, float color[4]) +{ + float ix = floorf(xoffset); + float fx = xoffset - ix; + x += (int)ix; + + float color00[4], color10[4]; + + sample(reader, x + 0, y + 0, color00); + sample(reader, x + 1, y + 0, color10); + + color[0] = interpf(color10[0], color00[0], fx); + color[1] = interpf(color10[1], color00[1], fx); + color[2] = interpf(color10[2], color00[2], fx); + color[3] = interpf(color10[3], color00[3], fx); +} + +/*-----------------------------------------------------------------------------*/ +/* Internal Functions to Sample Blending Weights from AreaTex */ + +static inline const float *areatex_sample_internal(const float *areatex, int x, int y) +{ + return &areatex[(CLAMPIS(x, 0, SMAA_AREATEX_SIZE - 1) + + CLAMPIS(y, 0, SMAA_AREATEX_SIZE - 1) * SMAA_AREATEX_SIZE) * + 2]; +} + +/** + * We have the distance and both crossing edges. So, what are the areas + * at each side of current edge? + */ +static void area(int d1, int d2, int e1, int e2, float weights[2]) +{ + /* The areas texture is compressed quadratically: */ + float x = (float)(SMAA_AREATEX_MAX_DISTANCE * e1) + sqrtf((float)d1); + float y = (float)(SMAA_AREATEX_MAX_DISTANCE * e2) + sqrtf((float)d2); + + float ix = floorf(x), iy = floorf(y); + float fx = x - ix, fy = y - iy; + int X = (int)ix, Y = (int)iy; + + const float *weights00 = areatex_sample_internal(areatex, X + 0, Y + 0); + const float *weights10 = areatex_sample_internal(areatex, X + 1, Y + 0); + const float *weights01 = areatex_sample_internal(areatex, X + 0, Y + 1); + const float *weights11 = areatex_sample_internal(areatex, X + 1, Y + 1); + + weights[0] = interpf( + interpf(weights11[0], weights01[0], fx), interpf(weights10[0], weights00[0], fx), fy); + weights[1] = interpf( + interpf(weights11[1], weights01[1], fx), interpf(weights10[1], weights00[1], fx), fy); +} + +/** + * Similar to area(), this calculates the area corresponding to a certain + * diagonal distance and crossing edges 'e'. + */ +static void area_diag(int d1, int d2, int e1, int e2, float weights[2]) +{ + int x = SMAA_AREATEX_MAX_DISTANCE_DIAG * e1 + d1; + int y = SMAA_AREATEX_MAX_DISTANCE_DIAG * e2 + d2; + + const float *w = areatex_sample_internal(areatex_diag, x, y); + copy_v2_v2(weights, w); +} + +/*-----------------------------------------------------------------------------*/ +/* Edge Detection (First Pass) */ +/*-----------------------------------------------------------------------------*/ + +SMAAEdgeDetectionOperation::SMAAEdgeDetectionOperation() +{ + this->addInputSocket(DataType::Color); /* image */ + this->addInputSocket(DataType::Value); /* depth, material ID, etc. */ + this->addOutputSocket(DataType::Color); + this->flags.complex = true; + this->m_imageReader = nullptr; + this->m_valueReader = nullptr; + this->m_threshold = 0.1f; + this->m_contrast_limit = 2.0f; +} + +void SMAAEdgeDetectionOperation::initExecution() +{ + this->m_imageReader = this->getInputSocketReader(0); + this->m_valueReader = this->getInputSocketReader(1); +} + +void SMAAEdgeDetectionOperation::deinitExecution() +{ + this->m_imageReader = nullptr; + this->m_valueReader = nullptr; +} + +void SMAAEdgeDetectionOperation::setThreshold(float threshold) +{ + /* UI values are between 0 and 1 for simplicity but algorithm expects values between 0 and 0.5 */ + m_threshold = scalenorm(0, 0.5, threshold); +} + +void SMAAEdgeDetectionOperation::setLocalContrastAdaptationFactor(float factor) +{ + /* UI values are between 0 and 1 for simplicity but algorithm expects values between 1 and 10 */ + m_contrast_limit = scalenorm(1, 10, factor); +} + +bool SMAAEdgeDetectionOperation::determineDependingAreaOfInterest( + rcti *input, ReadBufferOperation *readOperation, rcti *output) +{ + rcti newInput; + newInput.xmax = input->xmax + 1; + newInput.xmin = input->xmin - 2; + newInput.ymax = input->ymax + 1; + newInput.ymin = input->ymin - 2; + + return NodeOperation::determineDependingAreaOfInterest(&newInput, readOperation, output); +} + +void SMAAEdgeDetectionOperation::executePixel(float output[4], int x, int y, void * /*data*/) +{ + float color[4]; + + /* Calculate luma deltas: */ + sample(m_imageReader, x, y, color); + float L = IMB_colormanagement_get_luminance(color); + sample(m_imageReader, x - 1, y, color); + float Lleft = IMB_colormanagement_get_luminance(color); + sample(m_imageReader, x, y - 1, color); + float Ltop = IMB_colormanagement_get_luminance(color); + float Dleft = fabsf(L - Lleft); + float Dtop = fabsf(L - Ltop); + + /* We do the usual threshold: */ + output[0] = (x > 0 && Dleft >= m_threshold) ? 1.0f : 0.0f; + output[1] = (y > 0 && Dtop >= m_threshold) ? 1.0f : 0.0f; + output[2] = 0.0f; + output[3] = 1.0f; + + /* Then discard if there is no edge: */ + if (is_zero_v2(output)) { + return; + } + + /* Calculate right and bottom deltas: */ + sample(m_imageReader, x + 1, y, color); + float Lright = IMB_colormanagement_get_luminance(color); + sample(m_imageReader, x, y + 1, color); + float Lbottom = IMB_colormanagement_get_luminance(color); + float Dright = fabsf(L - Lright); + float Dbottom = fabsf(L - Lbottom); + + /* Calculate the maximum delta in the direct neighborhood: */ + float maxDelta = fmaxf(fmaxf(Dleft, Dright), fmaxf(Dtop, Dbottom)); + + /* Calculate luma used for both left and top edges: */ + sample(m_imageReader, x - 1, y - 1, color); + float Llefttop = IMB_colormanagement_get_luminance(color); + + /* Left edge */ + if (output[0] != 0.0f) { + /* Calculate deltas around the left pixel: */ + sample(m_imageReader, x - 2, y, color); + float Lleftleft = IMB_colormanagement_get_luminance(color); + sample(m_imageReader, x - 1, y + 1, color); + float Lleftbottom = IMB_colormanagement_get_luminance(color); + float Dleftleft = fabsf(Lleft - Lleftleft); + float Dlefttop = fabsf(Lleft - Llefttop); + float Dleftbottom = fabsf(Lleft - Lleftbottom); + + /* Calculate the final maximum delta: */ + maxDelta = fmaxf(maxDelta, fmaxf(Dleftleft, fmaxf(Dlefttop, Dleftbottom))); + + /* Local contrast adaptation: */ + if (maxDelta > m_contrast_limit * Dleft) { + output[0] = 0.0f; + } + } + + /* Top edge */ + if (output[1] != 0.0f) { + /* Calculate top-top delta: */ + sample(m_imageReader, x, y - 2, color); + float Ltoptop = IMB_colormanagement_get_luminance(color); + sample(m_imageReader, x + 1, y - 1, color); + float Ltopright = IMB_colormanagement_get_luminance(color); + float Dtoptop = fabsf(Ltop - Ltoptop); + float Dtopleft = fabsf(Ltop - Llefttop); + float Dtopright = fabsf(Ltop - Ltopright); + + /* Calculate the final maximum delta: */ + maxDelta = fmaxf(maxDelta, fmaxf(Dtoptop, fmaxf(Dtopleft, Dtopright))); + + /* Local contrast adaptation: */ + if (maxDelta > m_contrast_limit * Dtop) { + output[1] = 0.0f; + } + } +} + +/*-----------------------------------------------------------------------------*/ +/* Blending Weight Calculation (Second Pass) */ +/*-----------------------------------------------------------------------------*/ + +SMAABlendingWeightCalculationOperation::SMAABlendingWeightCalculationOperation() +{ + this->addInputSocket(DataType::Color); /* edges */ + this->addOutputSocket(DataType::Color); + this->flags.complex = true; + this->m_imageReader = nullptr; + this->m_corner_rounding = 25; +} + +void *SMAABlendingWeightCalculationOperation::initializeTileData(rcti *rect) +{ + return getInputOperation(0)->initializeTileData(rect); +} + +void SMAABlendingWeightCalculationOperation::initExecution() +{ + this->m_imageReader = this->getInputSocketReader(0); +} + +void SMAABlendingWeightCalculationOperation::setCornerRounding(float rounding) +{ + /* UI values are between 0 and 1 for simplicity but algorithm expects values between 0 and 100 */ + m_corner_rounding = static_cast<int>(scalenorm(0, 100, rounding)); +} + +void SMAABlendingWeightCalculationOperation::executePixel(float output[4], + int x, + int y, + void * /*data*/) +{ + float edges[4], c[4]; + + zero_v4(output); + sample(m_imageReader, x, y, edges); + + /* Edge at north */ + if (edges[1] > 0.0f) { + /* Diagonals have both north and west edges, so calculating weights for them */ + /* in one of the boundaries is enough. */ + calculateDiagWeights(x, y, edges, output); + + /* We give priority to diagonals, so if we find a diagonal we skip */ + /* horizontal/vertical processing. */ + if (!is_zero_v2(output)) { + return; + } + + /* Find the distance to the left and the right: */ + int left = searchXLeft(x, y); + int right = searchXRight(x, y); + int d1 = x - left, d2 = right - x; + + /* Fetch the left and right crossing edges: */ + int e1 = 0, e2 = 0; + sample(m_imageReader, left, y - 1, c); + if (c[0] > 0.0) { + e1 += 1; + } + sample(m_imageReader, left, y, c); + if (c[0] > 0.0) { + e1 += 2; + } + sample(m_imageReader, right + 1, y - 1, c); + if (c[0] > 0.0) { + e2 += 1; + } + sample(m_imageReader, right + 1, y, c); + if (c[0] > 0.0) { + e2 += 2; + } + + /* Ok, we know how this pattern looks like, now it is time for getting */ + /* the actual area: */ + area(d1, d2, e1, e2, output); /* R, G */ + + /* Fix corners: */ + if (m_corner_rounding) { + detectHorizontalCornerPattern(output, left, right, y, d1, d2); + } + } + + /* Edge at west */ + if (edges[0] > 0.0f) { + /* Did we already do diagonal search for this west edge from the left neighboring pixel? */ + if (isVerticalSearchUnneeded(x, y)) { + return; + } + + /* Find the distance to the top and the bottom: */ + int top = searchYUp(x, y); + int bottom = searchYDown(x, y); + int d1 = y - top, d2 = bottom - y; + + /* Fetch the top ang bottom crossing edges: */ + int e1 = 0, e2 = 0; + sample(m_imageReader, x - 1, top, c); + if (c[1] > 0.0) { + e1 += 1; + } + sample(m_imageReader, x, top, c); + if (c[1] > 0.0) { + e1 += 2; + } + sample(m_imageReader, x - 1, bottom + 1, c); + if (c[1] > 0.0) { + e2 += 1; + } + sample(m_imageReader, x, bottom + 1, c); + if (c[1] > 0.0) { + e2 += 2; + } + + /* Get the area for this direction: */ + area(d1, d2, e1, e2, output + 2); /* B, A */ + + /* Fix corners: */ + if (m_corner_rounding) { + detectVerticalCornerPattern(output + 2, x, top, bottom, d1, d2); + } + } +} + +void SMAABlendingWeightCalculationOperation::deinitExecution() +{ + this->m_imageReader = nullptr; +} + +bool SMAABlendingWeightCalculationOperation::determineDependingAreaOfInterest( + rcti *input, ReadBufferOperation *readOperation, rcti *output) +{ + rcti newInput; + + newInput.xmax = input->xmax + fmax(SMAA_MAX_SEARCH_STEPS, SMAA_MAX_SEARCH_STEPS_DIAG + 1); + newInput.xmin = input->xmin - + fmax(fmax(SMAA_MAX_SEARCH_STEPS - 1, 1), SMAA_MAX_SEARCH_STEPS_DIAG + 1); + newInput.ymax = input->ymax + fmax(SMAA_MAX_SEARCH_STEPS, SMAA_MAX_SEARCH_STEPS_DIAG); + newInput.ymin = input->ymin - + fmax(fmax(SMAA_MAX_SEARCH_STEPS - 1, 1), SMAA_MAX_SEARCH_STEPS_DIAG); + + return NodeOperation::determineDependingAreaOfInterest(&newInput, readOperation, output); +} + +/*-----------------------------------------------------------------------------*/ +/* Diagonal Search Functions */ + +/** + * These functions allows to perform diagonal pattern searches. + */ +int SMAABlendingWeightCalculationOperation::searchDiag1(int x, int y, int dir, bool *found) +{ + float e[4]; + int end = x + SMAA_MAX_SEARCH_STEPS_DIAG * dir; + *found = false; + + while (x != end) { + x += dir; + y -= dir; + sample(m_imageReader, x, y, e); + if (e[1] == 0.0f) { + *found = true; + break; + } + if (e[0] == 0.0f) { + *found = true; + return (dir < 0) ? x : x - dir; + } + } + + return x - dir; +} + +int SMAABlendingWeightCalculationOperation::searchDiag2(int x, int y, int dir, bool *found) +{ + float e[4]; + int end = x + SMAA_MAX_SEARCH_STEPS_DIAG * dir; + *found = false; + + while (x != end) { + x += dir; + y += dir; + sample(m_imageReader, x, y, e); + if (e[1] == 0.0f) { + *found = true; + break; + } + sample(m_imageReader, x + 1, y, e); + if (e[0] == 0.0f) { + *found = true; + return (dir > 0) ? x : x - dir; + } + } + + return x - dir; +} + +/** + * This searches for diagonal patterns and returns the corresponding weights. + */ +void SMAABlendingWeightCalculationOperation::calculateDiagWeights(int x, + int y, + const float edges[2], + float weights[2]) +{ + int d1, d2; + bool d1_found, d2_found; + float e[4], c[4]; + + zero_v2(weights); + + if (SMAA_MAX_SEARCH_STEPS_DIAG <= 0) { + return; + } + + /* Search for the line ends: */ + if (edges[0] > 0.0f) { + d1 = x - searchDiag1(x, y, -1, &d1_found); + } + else { + d1 = 0; + d1_found = true; + } + d2 = searchDiag1(x, y, 1, &d2_found) - x; + + if (d1 + d2 > 2) { /* d1 + d2 + 1 > 3 */ + int e1 = 0, e2 = 0; + + if (d1_found) { + /* Fetch the crossing edges: */ + int left = x - d1, bottom = y + d1; + + sample(m_imageReader, left - 1, bottom, c); + if (c[1] > 0.0) { + e1 += 2; + } + sample(m_imageReader, left, bottom, c); + if (c[0] > 0.0) { + e1 += 1; + } + } + + if (d2_found) { + /* Fetch the crossing edges: */ + int right = x + d2, top = y - d2; + + sample(m_imageReader, right + 1, top, c); + if (c[1] > 0.0) { + e2 += 2; + } + sample(m_imageReader, right + 1, top - 1, c); + if (c[0] > 0.0) { + e2 += 1; + } + } + + /* Fetch the areas for this line: */ + area_diag(d1, d2, e1, e2, weights); + } + + /* Search for the line ends: */ + d1 = x - searchDiag2(x, y, -1, &d1_found); + sample(m_imageReader, x + 1, y, e); + if (e[0] > 0.0f) { + d2 = searchDiag2(x, y, 1, &d2_found) - x; + } + else { + d2 = 0; + d2_found = true; + } + + if (d1 + d2 > 2) { /* d1 + d2 + 1 > 3 */ + int e1 = 0, e2 = 0; + + if (d1_found) { + /* Fetch the crossing edges: */ + int left = x - d1, top = y - d1; + + sample(m_imageReader, left - 1, top, c); + if (c[1] > 0.0) { + e1 += 2; + } + sample(m_imageReader, left, top - 1, c); + if (c[0] > 0.0) { + e1 += 1; + } + } + + if (d2_found) { + /* Fetch the crossing edges: */ + int right = x + d2, bottom = y + d2; + + sample(m_imageReader, right + 1, bottom, c); + if (c[1] > 0.0) { + e2 += 2; + } + if (c[0] > 0.0) { + e2 += 1; + } + } + + /* Fetch the areas for this line: */ + float w[2]; + area_diag(d1, d2, e1, e2, w); + weights[0] += w[1]; + weights[1] += w[0]; + } +} + +bool SMAABlendingWeightCalculationOperation::isVerticalSearchUnneeded(int x, int y) +{ + int d1, d2; + bool found; + float e[4]; + + if (SMAA_MAX_SEARCH_STEPS_DIAG <= 0) { + return false; + } + + /* Search for the line ends: */ + sample(m_imageReader, x - 1, y, e); + if (e[1] > 0.0f) { + d1 = x - searchDiag2(x - 1, y, -1, &found); + } + else { + d1 = 0; + } + d2 = searchDiag2(x - 1, y, 1, &found) - x; + + return (d1 + d2 > 2); /* d1 + d2 + 1 > 3 */ +} + +/*-----------------------------------------------------------------------------*/ +/* Horizontal/Vertical Search Functions */ + +int SMAABlendingWeightCalculationOperation::searchXLeft(int x, int y) +{ + int end = x - SMAA_MAX_SEARCH_STEPS; + float e[4]; + + while (x > end) { + sample(m_imageReader, x, y, e); + if (e[1] == 0.0f) { /* Is the edge not activated? */ + break; + } + if (e[0] != 0.0f) { /* Or is there a crossing edge that breaks the line? */ + return x; + } + sample(m_imageReader, x, y - 1, e); + if (e[0] != 0.0f) { /* Or is there a crossing edge that breaks the line? */ + return x; + } + x--; + } + + return x + 1; +} + +int SMAABlendingWeightCalculationOperation::searchXRight(int x, int y) +{ + int end = x + SMAA_MAX_SEARCH_STEPS; + float e[4]; + + while (x < end) { + x++; + sample(m_imageReader, x, y, e); + if (e[1] == 0.0f || /* Is the edge not activated? */ + e[0] != 0.0f) { /* Or is there a crossing edge that breaks the line? */ + break; + } + sample(m_imageReader, x, y - 1, e); + if (e[0] != 0.0f) { /* Or is there a crossing edge that breaks the line? */ + break; + } + } + + return x - 1; +} + +int SMAABlendingWeightCalculationOperation::searchYUp(int x, int y) +{ + int end = y - SMAA_MAX_SEARCH_STEPS; + float e[4]; + + while (y > end) { + sample(m_imageReader, x, y, e); + if (e[0] == 0.0f) { /* Is the edge not activated? */ + break; + } + if (e[1] != 0.0f) { /* Or is there a crossing edge that breaks the line? */ + return y; + } + sample(m_imageReader, x - 1, y, e); + if (e[1] != 0.0f) { /* Or is there a crossing edge that breaks the line? */ + return y; + } + y--; + } + + return y + 1; +} + +int SMAABlendingWeightCalculationOperation::searchYDown(int x, int y) +{ + int end = y + SMAA_MAX_SEARCH_STEPS; + float e[4]; + + while (y < end) { + y++; + sample(m_imageReader, x, y, e); + if (e[0] == 0.0f || /* Is the edge not activated? */ + e[1] != 0.0f) { /* Or is there a crossing edge that breaks the line? */ + break; + } + sample(m_imageReader, x - 1, y, e); + if (e[1] != 0.0f) { /* Or is there a crossing edge that breaks the line? */ + break; + } + } + + return y - 1; +} + +/*-----------------------------------------------------------------------------*/ +/* Corner Detection Functions */ + +void SMAABlendingWeightCalculationOperation::detectHorizontalCornerPattern( + float weights[2], int left, int right, int y, int d1, int d2) +{ + float factor[2] = {1.0f, 1.0f}; + float rounding = m_corner_rounding / 100.0f; + float e[4]; + + /* Reduce blending for pixels in the center of a line. */ + rounding *= (d1 == d2) ? 0.5f : 1.0f; + + /* Near the left corner */ + if (d1 <= d2) { + sample(m_imageReader, left, y + 1, e); + factor[0] -= rounding * e[0]; + sample(m_imageReader, left, y - 2, e); + factor[1] -= rounding * e[0]; + } + /* Near the right corner */ + if (d1 >= d2) { + sample(m_imageReader, right + 1, y + 1, e); + factor[0] -= rounding * e[0]; + sample(m_imageReader, right + 1, y - 2, e); + factor[1] -= rounding * e[0]; + } + + weights[0] *= CLAMPIS(factor[0], 0.0f, 1.0f); + weights[1] *= CLAMPIS(factor[1], 0.0f, 1.0f); +} + +void SMAABlendingWeightCalculationOperation::detectVerticalCornerPattern( + float weights[2], int x, int top, int bottom, int d1, int d2) +{ + float factor[2] = {1.0f, 1.0f}; + float rounding = m_corner_rounding / 100.0f; + float e[4]; + + /* Reduce blending for pixels in the center of a line. */ + rounding *= (d1 == d2) ? 0.5f : 1.0f; + + /* Near the top corner */ + if (d1 <= d2) { + sample(m_imageReader, x + 1, top, e); + factor[0] -= rounding * e[1]; + sample(m_imageReader, x - 2, top, e); + factor[1] -= rounding * e[1]; + } + /* Near the bottom corner */ + if (d1 >= d2) { + sample(m_imageReader, x + 1, bottom + 1, e); + factor[0] -= rounding * e[1]; + sample(m_imageReader, x - 2, bottom + 1, e); + factor[1] -= rounding * e[1]; + } + + weights[0] *= CLAMPIS(factor[0], 0.0f, 1.0f); + weights[1] *= CLAMPIS(factor[1], 0.0f, 1.0f); +} + +/*-----------------------------------------------------------------------------*/ +/* Neighborhood Blending (Third Pass) */ +/*-----------------------------------------------------------------------------*/ + +SMAANeighborhoodBlendingOperation::SMAANeighborhoodBlendingOperation() +{ + this->addInputSocket(DataType::Color); /* image */ + this->addInputSocket(DataType::Color); /* blend */ + this->addOutputSocket(DataType::Color); + this->flags.complex = true; + this->m_image1Reader = nullptr; + this->m_image2Reader = nullptr; +} + +void *SMAANeighborhoodBlendingOperation::initializeTileData(rcti *rect) +{ + return getInputOperation(0)->initializeTileData(rect); +} + +void SMAANeighborhoodBlendingOperation::initExecution() +{ + this->m_image1Reader = this->getInputSocketReader(0); + this->m_image2Reader = this->getInputSocketReader(1); +} + +void SMAANeighborhoodBlendingOperation::executePixel(float output[4], + int x, + int y, + void * /*data*/) +{ + float w[4]; + + /* Fetch the blending weights for current pixel: */ + sample(m_image2Reader, x, y, w); + float left = w[2], top = w[0]; + sample(m_image2Reader, x + 1, y, w); + float right = w[3]; + sample(m_image2Reader, x, y + 1, w); + float bottom = w[1]; + + /* Is there any blending weight with a value greater than 0.0? */ + if (right + bottom + left + top < 1e-5f) { + sample(m_image1Reader, x, y, output); + return; + } + + /* Calculate the blending offsets: */ + void (*samplefunc)(SocketReader * reader, int x, int y, float xoffset, float color[4]); + float offset1, offset2, weight1, weight2, color1[4], color2[4]; + + if (fmaxf(right, left) > fmaxf(bottom, top)) { /* max(horizontal) > max(vertical) */ + samplefunc = sample_bilinear_horizontal; + offset1 = right; + offset2 = -left; + weight1 = right / (right + left); + weight2 = left / (right + left); + } + else { + samplefunc = sample_bilinear_vertical; + offset1 = bottom; + offset2 = -top; + weight1 = bottom / (bottom + top); + weight2 = top / (bottom + top); + } + + /* We exploit bilinear filtering to mix current pixel with the chosen neighbor: */ + samplefunc(m_image1Reader, x, y, offset1, color1); + samplefunc(m_image1Reader, x, y, offset2, color2); + + mul_v4_v4fl(output, color1, weight1); + madd_v4_v4fl(output, color2, weight2); +} + +void SMAANeighborhoodBlendingOperation::deinitExecution() +{ + this->m_image1Reader = nullptr; + this->m_image2Reader = nullptr; +} + +bool SMAANeighborhoodBlendingOperation::determineDependingAreaOfInterest( + rcti *input, ReadBufferOperation *readOperation, rcti *output) +{ + rcti newInput; + + newInput.xmax = input->xmax + 1; + newInput.xmin = input->xmin - 1; + newInput.ymax = input->ymax + 1; + newInput.ymin = input->ymin - 1; + + return NodeOperation::determineDependingAreaOfInterest(&newInput, readOperation, output); +} + +} // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_SMAAOperation.h b/source/blender/compositor/operations/COM_SMAAOperation.h new file mode 100644 index 00000000000..781762202b4 --- /dev/null +++ b/source/blender/compositor/operations/COM_SMAAOperation.h @@ -0,0 +1,149 @@ +/* + * Copyright 2017, Blender Foundation. + * + * 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. + * + * Contributor: IRIE Shinsuke + */ + +#pragma once + +#include "COM_NodeOperation.h" + +namespace blender::compositor { + +/*-----------------------------------------------------------------------------*/ +/* Edge Detection (First Pass) */ + +class SMAAEdgeDetectionOperation : public NodeOperation { + protected: + SocketReader *m_imageReader; + SocketReader *m_valueReader; + + float m_threshold; + float m_contrast_limit; + + public: + SMAAEdgeDetectionOperation(); + + /** + * the inner loop of this program + */ + virtual void executePixel(float output[4], int x, int y, void *data) override; + + /** + * Initialize the execution + */ + void initExecution() override; + + /** + * Deinitialize the execution + */ + void deinitExecution() override; + + void setThreshold(float threshold); + + void setLocalContrastAdaptationFactor(float factor); + + bool determineDependingAreaOfInterest(rcti *input, + ReadBufferOperation *readOperation, + rcti *output) override; +}; + +/*-----------------------------------------------------------------------------*/ +/* Blending Weight Calculation (Second Pass) */ + +class SMAABlendingWeightCalculationOperation : public NodeOperation { + private: + SocketReader *m_imageReader; + + int m_corner_rounding; + + public: + SMAABlendingWeightCalculationOperation(); + + /** + * the inner loop of this program + */ + void executePixel(float output[4], int x, int y, void *data) override; + + /** + * Initialize the execution + */ + void initExecution() override; + void *initializeTileData(rcti *rect) override; + + /** + * Deinitialize the execution + */ + void deinitExecution() override; + + void setCornerRounding(float rounding); + + bool determineDependingAreaOfInterest(rcti *input, + ReadBufferOperation *readOperation, + rcti *output) override; + + private: + /* Diagonal Search Functions */ + int searchDiag1(int x, int y, int dir, bool *found); + int searchDiag2(int x, int y, int dir, bool *found); + void calculateDiagWeights(int x, int y, const float edges[2], float weights[2]); + bool isVerticalSearchUnneeded(int x, int y); + + /* Horizontal/Vertical Search Functions */ + int searchXLeft(int x, int y); + int searchXRight(int x, int y); + int searchYUp(int x, int y); + int searchYDown(int x, int y); + + /* Corner Detection Functions */ + void detectHorizontalCornerPattern(float weights[2], int left, int right, int y, int d1, int d2); + void detectVerticalCornerPattern(float weights[2], int x, int top, int bottom, int d1, int d2); +}; + +/*-----------------------------------------------------------------------------*/ +/* Neighborhood Blending (Third Pass) */ + +class SMAANeighborhoodBlendingOperation : public NodeOperation { + private: + SocketReader *m_image1Reader; + SocketReader *m_image2Reader; + + public: + SMAANeighborhoodBlendingOperation(); + + /** + * the inner loop of this program + */ + void executePixel(float output[4], int x, int y, void *data) override; + + /** + * Initialize the execution + */ + void initExecution() override; + void *initializeTileData(rcti *rect) override; + + /** + * Deinitialize the execution + */ + void deinitExecution() override; + + bool determineDependingAreaOfInterest(rcti *input, + ReadBufferOperation *readOperation, + rcti *output) override; +}; + +} // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_ScaleOperation.cc b/source/blender/compositor/operations/COM_ScaleOperation.cc index b0c9bfb2663..03525d4ea01 100644 --- a/source/blender/compositor/operations/COM_ScaleOperation.cc +++ b/source/blender/compositor/operations/COM_ScaleOperation.cc @@ -18,6 +18,8 @@ #include "COM_ScaleOperation.h" +namespace blender::compositor { + #define USE_FORCE_BILINEAR /* XXX - ignore input and use default from old compositor, * could become an option like the transform node - campbell @@ -28,7 +30,7 @@ BaseScaleOperation::BaseScaleOperation() { #ifdef USE_FORCE_BILINEAR - m_sampler = (int)COM_PS_BILINEAR; + m_sampler = (int)PixelSampler::Bilinear; #else m_sampler = -1; #endif @@ -89,8 +91,8 @@ bool ScaleOperation::determineDependingAreaOfInterest(rcti *input, float scaleX[4]; float scaleY[4]; - this->m_inputXOperation->readSampled(scaleX, 0, 0, COM_PS_NEAREST); - this->m_inputYOperation->readSampled(scaleY, 0, 0, COM_PS_NEAREST); + this->m_inputXOperation->readSampled(scaleX, 0, 0, PixelSampler::Nearest); + this->m_inputYOperation->readSampled(scaleY, 0, 0, PixelSampler::Nearest); const float scx = scaleX[0]; const float scy = scaleY[0]; @@ -174,8 +176,8 @@ bool ScaleAbsoluteOperation::determineDependingAreaOfInterest(rcti *input, float scaleX[4]; float scaleY[4]; - this->m_inputXOperation->readSampled(scaleX, 0, 0, COM_PS_NEAREST); - this->m_inputYOperation->readSampled(scaleY, 0, 0, COM_PS_NEAREST); + this->m_inputXOperation->readSampled(scaleX, 0, 0, PixelSampler::Nearest); + this->m_inputYOperation->readSampled(scaleY, 0, 0, PixelSampler::Nearest); const float scx = scaleX[0]; const float scy = scaleY[0]; @@ -203,7 +205,7 @@ bool ScaleAbsoluteOperation::determineDependingAreaOfInterest(rcti *input, // Absolute fixed size ScaleFixedSizeOperation::ScaleFixedSizeOperation() : BaseScaleOperation() { - this->addInputSocket(DataType::Color, COM_SC_NO_RESIZE); + this->addInputSocket(DataType::Color, ResizeMode::None); this->addOutputSocket(DataType::Color); this->setResolutionInputSocketIndex(0); this->m_inputOperation = nullptr; @@ -308,3 +310,5 @@ void ScaleFixedSizeOperation::determineResolution(unsigned int resolution[2], resolution[0] = this->m_newWidth; resolution[1] = this->m_newHeight; } + +} // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_ScaleOperation.h b/source/blender/compositor/operations/COM_ScaleOperation.h index f28b8237485..dc3de3602bf 100644 --- a/source/blender/compositor/operations/COM_ScaleOperation.h +++ b/source/blender/compositor/operations/COM_ScaleOperation.h @@ -20,6 +20,8 @@ #include "COM_NodeOperation.h" +namespace blender::compositor { + class BaseScaleOperation : public NodeOperation { public: void setSampler(PixelSampler sampler) @@ -55,11 +57,11 @@ class ScaleOperation : public BaseScaleOperation { ScaleOperation(); bool determineDependingAreaOfInterest(rcti *input, ReadBufferOperation *readOperation, - rcti *output); - void executePixelSampled(float output[4], float x, float y, PixelSampler sampler); + rcti *output) override; + void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; - void initExecution(); - void deinitExecution(); + void initExecution() override; + void deinitExecution() override; }; class ScaleAbsoluteOperation : public BaseScaleOperation { @@ -73,11 +75,11 @@ class ScaleAbsoluteOperation : public BaseScaleOperation { ScaleAbsoluteOperation(); bool determineDependingAreaOfInterest(rcti *input, ReadBufferOperation *readOperation, - rcti *output); - void executePixelSampled(float output[4], float x, float y, PixelSampler sampler); + rcti *output) override; + void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; - void initExecution(); - void deinitExecution(); + void initExecution() override; + void deinitExecution() override; }; class ScaleFixedSizeOperation : public BaseScaleOperation { @@ -100,12 +102,13 @@ class ScaleFixedSizeOperation : public BaseScaleOperation { ScaleFixedSizeOperation(); bool determineDependingAreaOfInterest(rcti *input, ReadBufferOperation *readOperation, - rcti *output); - void determineResolution(unsigned int resolution[2], unsigned int preferredResolution[2]); - void executePixelSampled(float output[4], float x, float y, PixelSampler sampler); + rcti *output) override; + void determineResolution(unsigned int resolution[2], + unsigned int preferredResolution[2]) override; + void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; - void initExecution(); - void deinitExecution(); + void initExecution() override; + void deinitExecution() override; void setNewWidth(int width) { this->m_newWidth = width; @@ -128,3 +131,5 @@ class ScaleFixedSizeOperation : public BaseScaleOperation { this->m_offsetY = y; } }; + +} // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_ScreenLensDistortionOperation.cc b/source/blender/compositor/operations/COM_ScreenLensDistortionOperation.cc index d5918dfa6f5..634fe66b0dd 100644 --- a/source/blender/compositor/operations/COM_ScreenLensDistortionOperation.cc +++ b/source/blender/compositor/operations/COM_ScreenLensDistortionOperation.cc @@ -24,13 +24,15 @@ #include "PIL_time.h" +namespace blender::compositor { + ScreenLensDistortionOperation::ScreenLensDistortionOperation() { this->addInputSocket(DataType::Color); this->addInputSocket(DataType::Value); this->addInputSocket(DataType::Value); this->addOutputSocket(DataType::Color); - this->setComplex(true); + this->flags.complex = true; this->m_inputProgram = nullptr; this->m_distortion = 0.0f; this->m_dispersion = 0.0f; @@ -83,12 +85,12 @@ void *ScreenLensDistortionOperation::initializeTileData(rcti * /*rect*/) if (!m_distortion_const) { float result[4]; - getInputSocketReader(1)->readSampled(result, 0, 0, COM_PS_NEAREST); + getInputSocketReader(1)->readSampled(result, 0, 0, PixelSampler::Nearest); m_distortion = result[0]; } if (!m_dispersion_const) { float result[4]; - getInputSocketReader(2)->readSampled(result, 0, 0, COM_PS_NEAREST); + getInputSocketReader(2)->readSampled(result, 0, 0, PixelSampler::Nearest); m_dispersion = result[0]; } @@ -351,3 +353,5 @@ void ScreenLensDistortionOperation::updateVariables(float distortion, float disp mul_v3_v3fl(m_k4, m_k, 4.0f); } + +} // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_ScreenLensDistortionOperation.h b/source/blender/compositor/operations/COM_ScreenLensDistortionOperation.h index 35d2bccce68..98872bfe142 100644 --- a/source/blender/compositor/operations/COM_ScreenLensDistortionOperation.h +++ b/source/blender/compositor/operations/COM_ScreenLensDistortionOperation.h @@ -21,6 +21,10 @@ #include "COM_NodeOperation.h" #include "DNA_node_types.h" +struct RNG; + +namespace blender::compositor { + class ScreenLensDistortionOperation : public NodeOperation { private: /** @@ -49,18 +53,18 @@ class ScreenLensDistortionOperation : public NodeOperation { /** * The inner loop of this operation. */ - void executePixel(float output[4], int x, int y, void *data); + void executePixel(float output[4], int x, int y, void *data) override; /** * Initialize the execution */ - void initExecution(); + void initExecution() override; - void *initializeTileData(rcti *rect); + void *initializeTileData(rcti *rect) override; /** * Deinitialize the execution */ - void deinitExecution(); + void deinitExecution() override; void setFit(bool fit) { @@ -78,7 +82,7 @@ class ScreenLensDistortionOperation : public NodeOperation { bool determineDependingAreaOfInterest(rcti *input, ReadBufferOperation *readOperation, - rcti *output); + rcti *output) override; private: void determineUV(float result[6], float x, float y) const; @@ -96,3 +100,5 @@ class ScreenLensDistortionOperation : public NodeOperation { float sum[4], int count[3]) const; }; + +} // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_SetAlphaMultiplyOperation.cc b/source/blender/compositor/operations/COM_SetAlphaMultiplyOperation.cc index 3151bad5e4a..24edbc61d40 100644 --- a/source/blender/compositor/operations/COM_SetAlphaMultiplyOperation.cc +++ b/source/blender/compositor/operations/COM_SetAlphaMultiplyOperation.cc @@ -18,6 +18,8 @@ #include "COM_SetAlphaMultiplyOperation.h" +namespace blender::compositor { + SetAlphaMultiplyOperation::SetAlphaMultiplyOperation() { this->addInputSocket(DataType::Color); @@ -53,3 +55,5 @@ void SetAlphaMultiplyOperation::deinitExecution() this->m_inputColor = nullptr; this->m_inputAlpha = nullptr; } + +} // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_SetAlphaMultiplyOperation.h b/source/blender/compositor/operations/COM_SetAlphaMultiplyOperation.h index db58b18688a..b4eea659fa2 100644 --- a/source/blender/compositor/operations/COM_SetAlphaMultiplyOperation.h +++ b/source/blender/compositor/operations/COM_SetAlphaMultiplyOperation.h @@ -20,6 +20,8 @@ #include "COM_NodeOperation.h" +namespace blender::compositor { + /** * This operation will apply a mask to its input image. * @@ -33,8 +35,10 @@ class SetAlphaMultiplyOperation : public NodeOperation { public: SetAlphaMultiplyOperation(); - void executePixelSampled(float output[4], float x, float y, PixelSampler sampler); + void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; - void initExecution(); - void deinitExecution(); + void initExecution() override; + void deinitExecution() override; }; + +} // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_SetAlphaReplaceOperation.cc b/source/blender/compositor/operations/COM_SetAlphaReplaceOperation.cc index cd9bf039f3e..90bfc814b09 100644 --- a/source/blender/compositor/operations/COM_SetAlphaReplaceOperation.cc +++ b/source/blender/compositor/operations/COM_SetAlphaReplaceOperation.cc @@ -18,6 +18,8 @@ #include "COM_SetAlphaReplaceOperation.h" +namespace blender::compositor { + SetAlphaReplaceOperation::SetAlphaReplaceOperation() { this->addInputSocket(DataType::Color); @@ -51,3 +53,5 @@ void SetAlphaReplaceOperation::deinitExecution() this->m_inputColor = nullptr; this->m_inputAlpha = nullptr; } + +} // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_SetAlphaReplaceOperation.h b/source/blender/compositor/operations/COM_SetAlphaReplaceOperation.h index b4cab82855b..c84299b6d82 100644 --- a/source/blender/compositor/operations/COM_SetAlphaReplaceOperation.h +++ b/source/blender/compositor/operations/COM_SetAlphaReplaceOperation.h @@ -20,6 +20,8 @@ #include "COM_NodeOperation.h" +namespace blender::compositor { + /** * this program converts an input color to an output value. * it assumes we are in sRGB color space. @@ -38,8 +40,10 @@ class SetAlphaReplaceOperation : public NodeOperation { /** * the inner loop of this program */ - void executePixelSampled(float output[4], float x, float y, PixelSampler sampler); + void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; - void initExecution(); - void deinitExecution(); + void initExecution() override; + void deinitExecution() override; }; + +} // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_SetColorOperation.cc b/source/blender/compositor/operations/COM_SetColorOperation.cc index b08381963fd..dbe45fa60db 100644 --- a/source/blender/compositor/operations/COM_SetColorOperation.cc +++ b/source/blender/compositor/operations/COM_SetColorOperation.cc @@ -18,9 +18,12 @@ #include "COM_SetColorOperation.h" +namespace blender::compositor { + SetColorOperation::SetColorOperation() { this->addOutputSocket(DataType::Color); + flags.is_set_operation = true; } void SetColorOperation::executePixelSampled(float output[4], @@ -37,3 +40,5 @@ void SetColorOperation::determineResolution(unsigned int resolution[2], resolution[0] = preferredResolution[0]; resolution[1] = preferredResolution[1]; } + +} // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_SetColorOperation.h b/source/blender/compositor/operations/COM_SetColorOperation.h index c61a4e10ac0..4b9b80013d4 100644 --- a/source/blender/compositor/operations/COM_SetColorOperation.h +++ b/source/blender/compositor/operations/COM_SetColorOperation.h @@ -20,6 +20,8 @@ #include "COM_NodeOperation.h" +namespace blender::compositor { + /** * this program converts an input color to an output value. * it assumes we are in sRGB color space. @@ -74,11 +76,10 @@ class SetColorOperation : public NodeOperation { /** * The inner loop of this operation. */ - void executePixelSampled(float output[4], float x, float y, PixelSampler sampler); + void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; - void determineResolution(unsigned int resolution[2], unsigned int preferredResolution[2]); - bool isSetOperation() const - { - return true; - } + void determineResolution(unsigned int resolution[2], + unsigned int preferredResolution[2]) override; }; + +} // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_SetSamplerOperation.cc b/source/blender/compositor/operations/COM_SetSamplerOperation.cc index 8272ad7583d..e68774736f3 100644 --- a/source/blender/compositor/operations/COM_SetSamplerOperation.cc +++ b/source/blender/compositor/operations/COM_SetSamplerOperation.cc @@ -18,6 +18,8 @@ #include "COM_SetSamplerOperation.h" +namespace blender::compositor { + SetSamplerOperation::SetSamplerOperation() { this->addInputSocket(DataType::Color); @@ -40,3 +42,5 @@ void SetSamplerOperation::executePixelSampled(float output[4], { this->m_reader->readSampled(output, x, y, this->m_sampler); } + +} // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_SetSamplerOperation.h b/source/blender/compositor/operations/COM_SetSamplerOperation.h index 5c1ed9b12d6..d355d937806 100644 --- a/source/blender/compositor/operations/COM_SetSamplerOperation.h +++ b/source/blender/compositor/operations/COM_SetSamplerOperation.h @@ -20,6 +20,8 @@ #include "COM_NodeOperation.h" +namespace blender::compositor { + /** * this program converts an input color to an output Sampler. * it assumes we are in sRGB color space. @@ -43,7 +45,9 @@ class SetSamplerOperation : public NodeOperation { /** * The inner loop of this operation. */ - void executePixelSampled(float output[4], float x, float y, PixelSampler sampler); - void initExecution(); - void deinitExecution(); + void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; + void initExecution() override; + void deinitExecution() override; }; + +} // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_SetValueOperation.cc b/source/blender/compositor/operations/COM_SetValueOperation.cc index 98d0ad630ad..ef43cf64653 100644 --- a/source/blender/compositor/operations/COM_SetValueOperation.cc +++ b/source/blender/compositor/operations/COM_SetValueOperation.cc @@ -18,9 +18,12 @@ #include "COM_SetValueOperation.h" +namespace blender::compositor { + SetValueOperation::SetValueOperation() { this->addOutputSocket(DataType::Value); + flags.is_set_operation = true; } void SetValueOperation::executePixelSampled(float output[4], @@ -37,3 +40,5 @@ void SetValueOperation::determineResolution(unsigned int resolution[2], resolution[0] = preferredResolution[0]; resolution[1] = preferredResolution[1]; } + +} // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_SetValueOperation.h b/source/blender/compositor/operations/COM_SetValueOperation.h index 72cd70ec1f6..5383f3b5fd3 100644 --- a/source/blender/compositor/operations/COM_SetValueOperation.h +++ b/source/blender/compositor/operations/COM_SetValueOperation.h @@ -20,6 +20,8 @@ #include "COM_NodeOperation.h" +namespace blender::compositor { + /** * this program converts an input color to an output value. * it assumes we are in sRGB color space. @@ -46,11 +48,9 @@ class SetValueOperation : public NodeOperation { /** * The inner loop of this operation. */ - void executePixelSampled(float output[4], float x, float y, PixelSampler sampler); - void determineResolution(unsigned int resolution[2], unsigned int preferredResolution[2]); - - bool isSetOperation() const - { - return true; - } + void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; + void determineResolution(unsigned int resolution[2], + unsigned int preferredResolution[2]) override; }; + +} // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_SetVectorOperation.cc b/source/blender/compositor/operations/COM_SetVectorOperation.cc index 6b6bcad02f3..7152d5e61d4 100644 --- a/source/blender/compositor/operations/COM_SetVectorOperation.cc +++ b/source/blender/compositor/operations/COM_SetVectorOperation.cc @@ -19,9 +19,12 @@ #include "COM_SetVectorOperation.h" #include "COM_defines.h" +namespace blender::compositor { + SetVectorOperation::SetVectorOperation() { this->addOutputSocket(DataType::Vector); + flags.is_set_operation = true; } void SetVectorOperation::executePixelSampled(float output[4], @@ -40,3 +43,5 @@ void SetVectorOperation::determineResolution(unsigned int resolution[2], resolution[0] = preferredResolution[0]; resolution[1] = preferredResolution[1]; } + +} // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_SetVectorOperation.h b/source/blender/compositor/operations/COM_SetVectorOperation.h index 4bdd03809de..b444339fcb2 100644 --- a/source/blender/compositor/operations/COM_SetVectorOperation.h +++ b/source/blender/compositor/operations/COM_SetVectorOperation.h @@ -20,6 +20,8 @@ #include "COM_NodeOperation.h" +namespace blender::compositor { + /** * this program converts an input color to an output value. * it assumes we are in sRGB color space. @@ -73,13 +75,10 @@ class SetVectorOperation : public NodeOperation { /** * The inner loop of this operation. */ - void executePixelSampled(float output[4], float x, float y, PixelSampler sampler); + void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; - void determineResolution(unsigned int resolution[2], unsigned int preferredResolution[2]); - bool isSetOperation() const - { - return true; - } + void determineResolution(unsigned int resolution[2], + unsigned int preferredResolution[2]) override; void setVector(const float vector[3]) { @@ -88,3 +87,5 @@ class SetVectorOperation : public NodeOperation { setZ(vector[2]); } }; + +} // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_SocketProxyOperation.cc b/source/blender/compositor/operations/COM_SocketProxyOperation.cc index 53f5fea8795..39876439b7b 100644 --- a/source/blender/compositor/operations/COM_SocketProxyOperation.cc +++ b/source/blender/compositor/operations/COM_SocketProxyOperation.cc @@ -18,14 +18,19 @@ #include "COM_SocketProxyOperation.h" +namespace blender::compositor { + SocketProxyOperation::SocketProxyOperation(DataType type, bool use_conversion) - : m_use_conversion(use_conversion) { this->addInputSocket(type); this->addOutputSocket(type); + flags.is_proxy_operation = true; + flags.use_datatype_conversion = use_conversion; } -std::unique_ptr<MetaData> SocketProxyOperation::getMetaData() const +std::unique_ptr<MetaData> SocketProxyOperation::getMetaData() { return this->getInputSocket(0)->getReader()->getMetaData(); } + +} // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_SocketProxyOperation.h b/source/blender/compositor/operations/COM_SocketProxyOperation.h index 712347a8ea2..1d3b76055bd 100644 --- a/source/blender/compositor/operations/COM_SocketProxyOperation.h +++ b/source/blender/compositor/operations/COM_SocketProxyOperation.h @@ -20,29 +20,13 @@ #include "COM_NodeOperation.h" +namespace blender::compositor { + class SocketProxyOperation : public NodeOperation { public: SocketProxyOperation(DataType type, bool use_conversion); - bool isProxyOperation() const override - { - return true; - } - bool useDatatypeConversion() const override - { - return m_use_conversion; - } - - bool getUseConversion() const - { - return m_use_conversion; - } - void setUseConversion(bool use_conversion) - { - m_use_conversion = use_conversion; - } - std::unique_ptr<MetaData> getMetaData() const override; - - private: - bool m_use_conversion; + std::unique_ptr<MetaData> getMetaData() override; }; + +} // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_SplitOperation.cc b/source/blender/compositor/operations/COM_SplitOperation.cc index 25438259973..a4754de370d 100644 --- a/source/blender/compositor/operations/COM_SplitOperation.cc +++ b/source/blender/compositor/operations/COM_SplitOperation.cc @@ -27,6 +27,8 @@ #include "IMB_imbuf.h" #include "IMB_imbuf_types.h" +namespace blender::compositor { + SplitOperation::SplitOperation() { this->addInputSocket(DataType::Color); @@ -58,10 +60,10 @@ void SplitOperation::executePixelSampled(float output[4], this->m_splitPercentage * this->getHeight() / 100.0f; bool image1 = this->m_xSplit ? x > perc : y > perc; if (image1) { - this->m_image1Input->readSampled(output, x, y, COM_PS_NEAREST); + this->m_image1Input->readSampled(output, x, y, PixelSampler::Nearest); } else { - this->m_image2Input->readSampled(output, x, y, COM_PS_NEAREST); + this->m_image2Input->readSampled(output, x, y, PixelSampler::Nearest); } } @@ -76,3 +78,5 @@ void SplitOperation::determineResolution(unsigned int resolution[2], NodeOperation::determineResolution(resolution, preferredResolution); } + +} // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_SplitOperation.h b/source/blender/compositor/operations/COM_SplitOperation.h index 62d41a615ff..09e48821dd0 100644 --- a/source/blender/compositor/operations/COM_SplitOperation.h +++ b/source/blender/compositor/operations/COM_SplitOperation.h @@ -20,6 +20,8 @@ #include "COM_NodeOperation.h" +namespace blender::compositor { + class SplitOperation : public NodeOperation { private: SocketReader *m_image1Input; @@ -30,10 +32,11 @@ class SplitOperation : public NodeOperation { public: SplitOperation(); - void initExecution(); - void deinitExecution(); - void executePixelSampled(float output[4], float x, float y, PixelSampler sampler); - void determineResolution(unsigned int resolution[2], unsigned int preferredResolution[2]); + void initExecution() override; + void deinitExecution() override; + void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; + void determineResolution(unsigned int resolution[2], + unsigned int preferredResolution[2]) override; void setSplitPercentage(float splitPercentage) { this->m_splitPercentage = splitPercentage; @@ -43,3 +46,5 @@ class SplitOperation : public NodeOperation { this->m_xSplit = xsplit; } }; + +} // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_SunBeamsOperation.cc b/source/blender/compositor/operations/COM_SunBeamsOperation.cc index 23bf5897297..839eeb9ff8f 100644 --- a/source/blender/compositor/operations/COM_SunBeamsOperation.cc +++ b/source/blender/compositor/operations/COM_SunBeamsOperation.cc @@ -19,13 +19,15 @@ #include "COM_SunBeamsOperation.h" +namespace blender::compositor { + SunBeamsOperation::SunBeamsOperation() { this->addInputSocket(DataType::Color); this->addOutputSocket(DataType::Color); this->setResolutionInputSocketIndex(0); - this->setComplex(true); + this->flags.complex = true; } void SunBeamsOperation::initExecution() @@ -138,7 +140,7 @@ template<int fxu, int fxv, int fyu, int fyv> struct BufferLineAccumulator { falloff_factor = dist_max > dist_min ? dr / (float)(dist_max - dist_min) : 0.0f; - float *iter = input->getBuffer() + COM_NUM_CHANNELS_COLOR * (x + input->getWidth() * y); + float *iter = input->getBuffer() + COM_DATA_TYPE_COLOR_CHANNELS * (x + input->getWidth() * y); return iter; } @@ -167,7 +169,7 @@ template<int fxu, int fxv, int fyu, int fyv> struct BufferLineAccumulator { if ((int)(co[0] - source[0]) == 0 && (int)(co[1] - source[1]) == 0) { copy_v4_v4(output, - input->getBuffer() + COM_NUM_CHANNELS_COLOR * + input->getBuffer() + COM_DATA_TYPE_COLOR_CHANNELS * ((int)source[0] + input->getWidth() * (int)source[1])); return; } @@ -208,7 +210,7 @@ template<int fxu, int fxv, int fyu, int fyv> struct BufferLineAccumulator { /* decrement u */ x -= fxu; y -= fyu; - buffer -= (fxu + fyu * buffer_width) * COM_NUM_CHANNELS_COLOR; + buffer -= (fxu + fyu * buffer_width) * COM_DATA_TYPE_COLOR_CHANNELS; /* decrement v (in steps of dv < 1) */ v_local -= dv; @@ -217,7 +219,7 @@ template<int fxu, int fxv, int fyu, int fyv> struct BufferLineAccumulator { x -= fxv; y -= fyv; - buffer -= (fxv + fyv * buffer_width) * COM_NUM_CHANNELS_COLOR; + buffer -= (fxv + fyv * buffer_width) * COM_DATA_TYPE_COLOR_CHANNELS; } } @@ -353,3 +355,5 @@ bool SunBeamsOperation::determineDependingAreaOfInterest(rcti *input, return NodeOperation::determineDependingAreaOfInterest(&rect, readOperation, output); } + +} // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_SunBeamsOperation.h b/source/blender/compositor/operations/COM_SunBeamsOperation.h index 09bdb018cc3..d3725021cde 100644 --- a/source/blender/compositor/operations/COM_SunBeamsOperation.h +++ b/source/blender/compositor/operations/COM_SunBeamsOperation.h @@ -19,19 +19,21 @@ #include "COM_NodeOperation.h" +namespace blender::compositor { + class SunBeamsOperation : public NodeOperation { public: SunBeamsOperation(); - void executePixel(float output[4], int x, int y, void *data); + void executePixel(float output[4], int x, int y, void *data) override; - void initExecution(); + void initExecution() override; - void *initializeTileData(rcti *rect); + void *initializeTileData(rcti *rect) override; bool determineDependingAreaOfInterest(rcti *input, ReadBufferOperation *readOperation, - rcti *output); + rcti *output) override; void setData(const NodeSunBeams &data) { @@ -44,3 +46,5 @@ class SunBeamsOperation : public NodeOperation { float m_source_px[2]; float m_ray_length_px; }; + +} // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_TextureOperation.cc b/source/blender/compositor/operations/COM_TextureOperation.cc index 146f43dbe3a..e94c457f981 100644 --- a/source/blender/compositor/operations/COM_TextureOperation.cc +++ b/source/blender/compositor/operations/COM_TextureOperation.cc @@ -25,6 +25,8 @@ #include "BLI_listbase.h" #include "BLI_threads.h" +namespace blender::compositor { + TextureBaseOperation::TextureBaseOperation() { this->addInputSocket(DataType::Vector); // offset @@ -35,7 +37,7 @@ TextureBaseOperation::TextureBaseOperation() this->m_rd = nullptr; this->m_pool = nullptr; this->m_sceneColorManage = false; - setComplex(true); + flags.complex = true; } TextureOperation::TextureOperation() : TextureBaseOperation() { @@ -155,3 +157,5 @@ void TextureBaseOperation::executePixelSampled(float output[4], output[0] = output[1] = output[2] = output[3]; } } + +} // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_TextureOperation.h b/source/blender/compositor/operations/COM_TextureOperation.h index a40dafd14cf..e1e04611c6c 100644 --- a/source/blender/compositor/operations/COM_TextureOperation.h +++ b/source/blender/compositor/operations/COM_TextureOperation.h @@ -26,6 +26,8 @@ #include "RE_pipeline.h" #include "RE_texture.h" +namespace blender::compositor { + /** * Base class for all renderlayeroperations * @@ -44,7 +46,8 @@ class TextureBaseOperation : public NodeOperation { /** * Determine the output resolution. The resolution is retrieved from the Renderer */ - void determineResolution(unsigned int resolution[2], unsigned int preferredResolution[2]); + void determineResolution(unsigned int resolution[2], + unsigned int preferredResolution[2]) override; /** * Constructor @@ -52,14 +55,14 @@ class TextureBaseOperation : public NodeOperation { TextureBaseOperation(); public: - void executePixelSampled(float output[4], float x, float y, PixelSampler sampler); + void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; void setTexture(Tex *texture) { this->m_texture = texture; } - void initExecution(); - void deinitExecution(); + void initExecution() override; + void deinitExecution() override; void setRenderData(const RenderData *rd) { this->m_rd = rd; @@ -77,5 +80,7 @@ class TextureOperation : public TextureBaseOperation { class TextureAlphaOperation : public TextureBaseOperation { public: TextureAlphaOperation(); - void executePixelSampled(float output[4], float x, float y, PixelSampler sampler); + void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; }; + +} // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_TonemapOperation.cc b/source/blender/compositor/operations/COM_TonemapOperation.cc index 85011171432..6bfacb0c75d 100644 --- a/source/blender/compositor/operations/COM_TonemapOperation.cc +++ b/source/blender/compositor/operations/COM_TonemapOperation.cc @@ -22,14 +22,16 @@ #include "IMB_colormanagement.h" +namespace blender::compositor { + TonemapOperation::TonemapOperation() { - this->addInputSocket(DataType::Color, COM_SC_NO_RESIZE); + this->addInputSocket(DataType::Color, ResizeMode::None); this->addOutputSocket(DataType::Color); this->m_imageReader = nullptr; this->m_data = nullptr; this->m_cachedInstance = nullptr; - this->setComplex(true); + this->flags.complex = true; } void TonemapOperation::initExecution() { @@ -150,3 +152,5 @@ void TonemapOperation::deinitializeTileData(rcti * /*rect*/, void * /*data*/) { /* pass */ } + +} // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_TonemapOperation.h b/source/blender/compositor/operations/COM_TonemapOperation.h index cb8816b93b3..7ecb179504d 100644 --- a/source/blender/compositor/operations/COM_TonemapOperation.h +++ b/source/blender/compositor/operations/COM_TonemapOperation.h @@ -21,6 +21,8 @@ #include "COM_NodeOperation.h" #include "DNA_node_types.h" +namespace blender::compositor { + /** * \brief temporarily storage during execution of Tone-map * \ingroup operation @@ -60,20 +62,20 @@ class TonemapOperation : public NodeOperation { /** * The inner loop of this operation. */ - void executePixel(float output[4], int x, int y, void *data); + void executePixel(float output[4], int x, int y, void *data) override; /** * Initialize the execution */ - void initExecution(); + void initExecution() override; - void *initializeTileData(rcti *rect); - void deinitializeTileData(rcti *rect, void *data); + void *initializeTileData(rcti *rect) override; + void deinitializeTileData(rcti *rect, void *data) override; /** * Deinitialize the execution */ - void deinitExecution(); + void deinitExecution() override; void setData(NodeTonemap *data) { @@ -82,7 +84,7 @@ class TonemapOperation : public NodeOperation { bool determineDependingAreaOfInterest(rcti *input, ReadBufferOperation *readOperation, - rcti *output); + rcti *output) override; }; /** @@ -96,5 +98,7 @@ class PhotoreceptorTonemapOperation : public TonemapOperation { /** * The inner loop of this operation. */ - void executePixel(float output[4], int x, int y, void *data); + void executePixel(float output[4], int x, int y, void *data) override; }; + +} // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_TrackPositionOperation.cc b/source/blender/compositor/operations/COM_TrackPositionOperation.cc index 97d602aa458..993410e3e84 100644 --- a/source/blender/compositor/operations/COM_TrackPositionOperation.cc +++ b/source/blender/compositor/operations/COM_TrackPositionOperation.cc @@ -28,6 +28,8 @@ #include "BKE_node.h" #include "BKE_tracking.h" +namespace blender::compositor { + TrackPositionOperation::TrackPositionOperation() { this->addOutputSocket(DataType::Value); @@ -39,6 +41,7 @@ TrackPositionOperation::TrackPositionOperation() this->m_position = CMP_TRACKPOS_ABSOLUTE; this->m_relativeFrame = 0; this->m_speed_output = false; + flags.is_set_operation = true; } void TrackPositionOperation::initExecution() @@ -134,3 +137,5 @@ void TrackPositionOperation::determineResolution(unsigned int resolution[2], resolution[0] = preferredResolution[0]; resolution[1] = preferredResolution[1]; } + +} // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_TrackPositionOperation.h b/source/blender/compositor/operations/COM_TrackPositionOperation.h index 7d831ec5d8d..b0b0a123bd6 100644 --- a/source/blender/compositor/operations/COM_TrackPositionOperation.h +++ b/source/blender/compositor/operations/COM_TrackPositionOperation.h @@ -28,6 +28,8 @@ #include "BLI_listbase.h" #include "BLI_string.h" +namespace blender::compositor { + /** * Class with implementation of green screen gradient rasterization */ @@ -49,7 +51,8 @@ class TrackPositionOperation : public NodeOperation { /** * Determine the output resolution. The resolution is retrieved from the Renderer */ - void determineResolution(unsigned int resolution[2], unsigned int preferredResolution[2]); + void determineResolution(unsigned int resolution[2], + unsigned int preferredResolution[2]) override; public: TrackPositionOperation(); @@ -87,12 +90,9 @@ class TrackPositionOperation : public NodeOperation { this->m_speed_output = speed_output; } - void initExecution(); - - void executePixelSampled(float output[4], float x, float y, PixelSampler sampler); + void initExecution() override; - bool isSetOperation() const - { - return true; - } + void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; }; + +} // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_TranslateOperation.cc b/source/blender/compositor/operations/COM_TranslateOperation.cc index 7efd655b1df..49135f25320 100644 --- a/source/blender/compositor/operations/COM_TranslateOperation.cc +++ b/source/blender/compositor/operations/COM_TranslateOperation.cc @@ -18,6 +18,8 @@ #include "COM_TranslateOperation.h" +namespace blender::compositor { + TranslateOperation::TranslateOperation() { this->addInputSocket(DataType::Color); @@ -56,7 +58,7 @@ void TranslateOperation::executePixelSampled(float output[4], float originalXPos = x - this->getDeltaX(); float originalYPos = y - this->getDeltaY(); - this->m_inputOperation->readSampled(output, originalXPos, originalYPos, COM_PS_BILINEAR); + this->m_inputOperation->readSampled(output, originalXPos, originalYPos, PixelSampler::Bilinear); } bool TranslateOperation::determineDependingAreaOfInterest(rcti *input, @@ -80,3 +82,5 @@ void TranslateOperation::setFactorXY(float factorX, float factorY) m_factorX = factorX; m_factorY = factorY; } + +} // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_TranslateOperation.h b/source/blender/compositor/operations/COM_TranslateOperation.h index 99cfb528858..eb3a664159f 100644 --- a/source/blender/compositor/operations/COM_TranslateOperation.h +++ b/source/blender/compositor/operations/COM_TranslateOperation.h @@ -20,6 +20,8 @@ #include "COM_NodeOperation.h" +namespace blender::compositor { + class TranslateOperation : public NodeOperation { private: SocketReader *m_inputOperation; @@ -35,11 +37,11 @@ class TranslateOperation : public NodeOperation { TranslateOperation(); bool determineDependingAreaOfInterest(rcti *input, ReadBufferOperation *readOperation, - rcti *output); - void executePixelSampled(float output[4], float x, float y, PixelSampler sampler); + rcti *output) override; + void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; - void initExecution(); - void deinitExecution(); + void initExecution() override; + void deinitExecution() override; float getDeltaX() { @@ -54,9 +56,9 @@ class TranslateOperation : public NodeOperation { { if (!this->m_isDeltaSet) { float tempDelta[4]; - this->m_inputXOperation->readSampled(tempDelta, 0, 0, COM_PS_NEAREST); + this->m_inputXOperation->readSampled(tempDelta, 0, 0, PixelSampler::Nearest); this->m_deltaX = tempDelta[0]; - this->m_inputYOperation->readSampled(tempDelta, 0, 0, COM_PS_NEAREST); + this->m_inputYOperation->readSampled(tempDelta, 0, 0, PixelSampler::Nearest); this->m_deltaY = tempDelta[0]; this->m_isDeltaSet = true; } @@ -64,3 +66,5 @@ class TranslateOperation : public NodeOperation { void setFactorXY(float factorX, float factorY); }; + +} // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_VariableSizeBokehBlurOperation.cc b/source/blender/compositor/operations/COM_VariableSizeBokehBlurOperation.cc index ea33f3cd787..19cd5a53084 100644 --- a/source/blender/compositor/operations/COM_VariableSizeBokehBlurOperation.cc +++ b/source/blender/compositor/operations/COM_VariableSizeBokehBlurOperation.cc @@ -22,18 +22,20 @@ #include "RE_pipeline.h" +namespace blender::compositor { + VariableSizeBokehBlurOperation::VariableSizeBokehBlurOperation() { this->addInputSocket(DataType::Color); - this->addInputSocket(DataType::Color, COM_SC_NO_RESIZE); // do not resize the bokeh image. + this->addInputSocket(DataType::Color, ResizeMode::None); // do not resize the bokeh image. this->addInputSocket(DataType::Value); // radius #ifdef COM_DEFOCUS_SEARCH this->addInputSocket(DataType::Color, - COM_SC_NO_RESIZE); // inverse search radius optimization structure. + ResizeMode::None); // inverse search radius optimization structure. #endif this->addOutputSocket(DataType::Color); - this->setComplex(true); - this->setOpenCL(true); + flags.complex = true; + flags.open_cl = true; this->m_inputProgram = nullptr; this->m_inputBokehProgram = nullptr; @@ -135,14 +137,14 @@ void VariableSizeBokehBlurOperation::executePixel(float output[4], int x, int y, const int addXStepValue = QualityStepHelper::getStep(); const int addYStepValue = addXStepValue; - const int addXStepColor = addXStepValue * COM_NUM_CHANNELS_COLOR; + const int addXStepColor = addXStepValue * COM_DATA_TYPE_COLOR_CHANNELS; if (size_center > this->m_threshold) { for (int ny = miny; ny < maxy; ny += addYStepValue) { float dy = ny - y; int offsetValueNy = ny * inputSizeBuffer->getWidth(); int offsetValueNxNy = offsetValueNy + (minx); - int offsetColorNxNy = offsetValueNxNy * COM_NUM_CHANNELS_COLOR; + int offsetColorNxNy = offsetValueNxNy * COM_DATA_TYPE_COLOR_CHANNELS; for (int nx = minx; nx < maxx; nx += addXStepValue) { if (nx != x || ny != y) { float size = MIN2(inputSizeFloatBuffer[offsetValueNxNy] * scalar, size_center); @@ -278,9 +280,9 @@ bool VariableSizeBokehBlurOperation::determineDependingAreaOfInterest( // InverseSearchRadiusOperation InverseSearchRadiusOperation::InverseSearchRadiusOperation() { - this->addInputSocket(DataType::Value, COM_SC_NO_RESIZE); // radius + this->addInputSocket(DataType::Value, ResizeMode::None); // radius this->addOutputSocket(DataType::Color); - this->setComplex(true); + this->flags.complex = true; this->m_inputRadius = nullptr; } @@ -319,7 +321,7 @@ void *InverseSearchRadiusOperation::initializeTileData(rcti *rect) // for (int x2 = 0 ; x2 < DIVIDER ; x2 ++) { // for (int y2 = 0 ; y2 < DIVIDER ; y2 ++) { - // this->m_inputRadius->read(temp, rx+x2, ry+y2, COM_PS_NEAREST); + // this->m_inputRadius->read(temp, rx+x2, ry+y2, PixelSampler::Nearest); // if (radius < temp[0]) { // radius = temp[0]; // maxx = x2; @@ -381,3 +383,5 @@ bool InverseSearchRadiusOperation::determineDependingAreaOfInterest( return NodeOperation::determineDependingAreaOfInterest(&newRect, readOperation, output); } #endif + +} // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_VariableSizeBokehBlurOperation.h b/source/blender/compositor/operations/COM_VariableSizeBokehBlurOperation.h index fe927f791fa..baeab6a646e 100644 --- a/source/blender/compositor/operations/COM_VariableSizeBokehBlurOperation.h +++ b/source/blender/compositor/operations/COM_VariableSizeBokehBlurOperation.h @@ -21,6 +21,8 @@ #include "COM_NodeOperation.h" #include "COM_QualityStepHelper.h" +namespace blender::compositor { + //#define COM_DEFOCUS_SEARCH class VariableSizeBokehBlurOperation : public NodeOperation, public QualityStepHelper { @@ -41,25 +43,25 @@ class VariableSizeBokehBlurOperation : public NodeOperation, public QualityStepH /** * The inner loop of this operation. */ - void executePixel(float output[4], int x, int y, void *data); + void executePixel(float output[4], int x, int y, void *data) override; /** * Initialize the execution */ - void initExecution(); + void initExecution() override; - void *initializeTileData(rcti *rect); + void *initializeTileData(rcti *rect) override; - void deinitializeTileData(rcti *rect, void *data); + void deinitializeTileData(rcti *rect, void *data) override; /** * Deinitialize the execution */ - void deinitExecution(); + void deinitExecution() override; bool determineDependingAreaOfInterest(rcti *input, ReadBufferOperation *readOperation, - rcti *output); + rcti *output) override; void setMaxBlur(int maxRadius) { @@ -81,7 +83,7 @@ class VariableSizeBokehBlurOperation : public NodeOperation, public QualityStepH cl_mem clOutputBuffer, MemoryBuffer **inputMemoryBuffers, std::list<cl_mem> *clMemToCleanUp, - std::list<cl_kernel> *clKernelsToCleanUp); + std::list<cl_kernel> *clKernelsToCleanUp) override; }; #ifdef COM_DEFOCUS_SEARCH @@ -103,19 +105,20 @@ class InverseSearchRadiusOperation : public NodeOperation { /** * Initialize the execution */ - void initExecution(); - void *initializeTileData(rcti *rect); - void deinitializeTileData(rcti *rect, void *data); + void initExecution() override; + void *initializeTileData(rcti *rect) override; + void deinitializeTileData(rcti *rect, void *data) override; /** * Deinitialize the execution */ - void deinitExecution(); + void deinitExecution() override; bool determineDependingAreaOfInterest(rcti *input, ReadBufferOperation *readOperation, - rcti *output); - void determineResolution(unsigned int resolution[2], unsigned int preferredResolution[2]); + rcti *output) override; + void determineResolution(unsigned int resolution[2], + unsigned int preferredResolution[2]) override; void setMaxBlur(int maxRadius) { @@ -123,3 +126,5 @@ class InverseSearchRadiusOperation : public NodeOperation { } }; #endif + +} // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_VectorBlurOperation.cc b/source/blender/compositor/operations/COM_VectorBlurOperation.cc index ff9eef8a7e1..fd64bda156b 100644 --- a/source/blender/compositor/operations/COM_VectorBlurOperation.cc +++ b/source/blender/compositor/operations/COM_VectorBlurOperation.cc @@ -25,6 +25,8 @@ #include "COM_VectorBlurOperation.h" +namespace blender::compositor { + /* Defined */ #define PASS_VECTOR_MAX 10000.0f @@ -54,7 +56,7 @@ VectorBlurOperation::VectorBlurOperation() this->m_inputImageProgram = nullptr; this->m_inputSpeedProgram = nullptr; this->m_inputZProgram = nullptr; - setComplex(true); + flags.complex = true; } void VectorBlurOperation::initExecution() { @@ -69,7 +71,7 @@ void VectorBlurOperation::initExecution() void VectorBlurOperation::executePixel(float output[4], int x, int y, void *data) { float *buffer = (float *)data; - int index = (y * this->getWidth() + x) * COM_NUM_CHANNELS_COLOR; + int index = (y * this->getWidth() + x) * COM_DATA_TYPE_COLOR_CHANNELS; copy_v4_v4(output, &buffer[index]); } @@ -897,3 +899,5 @@ void zbuf_accumulate_vecblur(NodeBlurData *nbd, } zbuf_free_span(&zspan); } + +} // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_VectorBlurOperation.h b/source/blender/compositor/operations/COM_VectorBlurOperation.h index 222e8b26968..dfcf1fb16f7 100644 --- a/source/blender/compositor/operations/COM_VectorBlurOperation.h +++ b/source/blender/compositor/operations/COM_VectorBlurOperation.h @@ -22,6 +22,8 @@ #include "COM_QualityStepHelper.h" #include "DNA_node_types.h" +namespace blender::compositor { + class VectorBlurOperation : public NodeOperation, public QualityStepHelper { private: /** @@ -44,19 +46,19 @@ class VectorBlurOperation : public NodeOperation, public QualityStepHelper { /** * The inner loop of this operation. */ - void executePixel(float output[4], int x, int y, void *data); + void executePixel(float output[4], int x, int y, void *data) override; /** * Initialize the execution */ - void initExecution(); + void initExecution() override; /** * Deinitialize the execution */ - void deinitExecution(); + void deinitExecution() override; - void *initializeTileData(rcti *rect); + void *initializeTileData(rcti *rect) override; void setVectorBlurSettings(NodeBlurData *settings) { @@ -64,7 +66,7 @@ class VectorBlurOperation : public NodeOperation, public QualityStepHelper { } bool determineDependingAreaOfInterest(rcti *input, ReadBufferOperation *readOperation, - rcti *output); + rcti *output) override; protected: void generateVectorBlur(float *data, @@ -72,3 +74,5 @@ class VectorBlurOperation : public NodeOperation, public QualityStepHelper { MemoryBuffer *inputSpeed, MemoryBuffer *inputZ); }; + +} // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_VectorCurveOperation.cc b/source/blender/compositor/operations/COM_VectorCurveOperation.cc index a6638a78e88..9d53ed5d8ee 100644 --- a/source/blender/compositor/operations/COM_VectorCurveOperation.cc +++ b/source/blender/compositor/operations/COM_VectorCurveOperation.cc @@ -20,6 +20,8 @@ #include "BKE_colortools.h" +namespace blender::compositor { + VectorCurveOperation::VectorCurveOperation() { this->addInputSocket(DataType::Vector); @@ -50,3 +52,5 @@ void VectorCurveOperation::deinitExecution() CurveBaseOperation::deinitExecution(); this->m_inputProgram = nullptr; } + +} // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_VectorCurveOperation.h b/source/blender/compositor/operations/COM_VectorCurveOperation.h index cf0d22eca1a..8cbb80e27c7 100644 --- a/source/blender/compositor/operations/COM_VectorCurveOperation.h +++ b/source/blender/compositor/operations/COM_VectorCurveOperation.h @@ -21,6 +21,8 @@ #include "COM_CurveBaseOperation.h" #include "COM_NodeOperation.h" +namespace blender::compositor { + class VectorCurveOperation : public CurveBaseOperation { private: /** @@ -34,15 +36,17 @@ class VectorCurveOperation : public CurveBaseOperation { /** * The inner loop of this operation. */ - void executePixelSampled(float output[4], float x, float y, PixelSampler sampler); + void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; /** * Initialize the execution */ - void initExecution(); + void initExecution() override; /** * Deinitialize the execution */ - void deinitExecution(); + void deinitExecution() override; }; + +} // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_ViewerOperation.cc b/source/blender/compositor/operations/COM_ViewerOperation.cc index ea5937d8afb..1ae0fe6101f 100644 --- a/source/blender/compositor/operations/COM_ViewerOperation.cc +++ b/source/blender/compositor/operations/COM_ViewerOperation.cc @@ -32,6 +32,8 @@ #include "IMB_imbuf.h" #include "IMB_imbuf_types.h" +namespace blender::compositor { + ViewerOperation::ViewerOperation() { this->setImage(nullptr); @@ -53,6 +55,8 @@ ViewerOperation::ViewerOperation() this->m_depthInput = nullptr; this->m_rd = nullptr; this->m_viewName = nullptr; + flags.use_viewer_border = true; + flags.is_viewer_operation = true; } void ViewerOperation::initExecution() @@ -98,12 +102,12 @@ void ViewerOperation::executeRegion(rcti *rect, unsigned int /*tileNumber*/) for (y = y1; y < y2 && (!breaked); y++) { for (x = x1; x < x2; x++) { - this->m_imageInput->readSampled(&(buffer[offset4]), x, y, COM_PS_NEAREST); + this->m_imageInput->readSampled(&(buffer[offset4]), x, y, PixelSampler::Nearest); if (this->m_useAlphaInput) { - this->m_alphaInput->readSampled(alpha, x, y, COM_PS_NEAREST); + this->m_alphaInput->readSampled(alpha, x, y, PixelSampler::Nearest); buffer[offset4 + 3] = alpha[0]; } - this->m_depthInput->readSampled(depth, x, y, COM_PS_NEAREST); + this->m_depthInput->readSampled(depth, x, y, PixelSampler::Nearest); depthbuffer[offset] = depth[0]; offset++; @@ -213,3 +217,5 @@ CompositorPriority ViewerOperation::getRenderPriority() const return CompositorPriority::Low; } + +} // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_ViewerOperation.h b/source/blender/compositor/operations/COM_ViewerOperation.h index 513c6eae487..8406ea41f20 100644 --- a/source/blender/compositor/operations/COM_ViewerOperation.h +++ b/source/blender/compositor/operations/COM_ViewerOperation.h @@ -23,6 +23,8 @@ #include "COM_NodeOperation.h" #include "DNA_image_types.h" +namespace blender::compositor { + class ViewerOperation : public NodeOperation { private: float *m_outputBuffer; @@ -48,11 +50,12 @@ class ViewerOperation : public NodeOperation { public: ViewerOperation(); - void initExecution(); - void deinitExecution(); - void executeRegion(rcti *rect, unsigned int tileNumber); - void determineResolution(unsigned int resolution[2], unsigned int preferredResolution[2]); - bool isOutputOperation(bool /*rendering*/) const + void initExecution() override; + void deinitExecution() override; + void executeRegion(rcti *rect, unsigned int tileNumber) override; + void determineResolution(unsigned int resolution[2], + unsigned int preferredResolution[2]) override; + bool isOutputOperation(bool /*rendering*/) const override { if (G.background) { return false; @@ -67,7 +70,7 @@ class ViewerOperation : public NodeOperation { { this->m_imageUser = imageUser; } - bool isActiveViewerOutput() const + bool isActiveViewerOutput() const override { return this->m_active; } @@ -99,11 +102,7 @@ class ViewerOperation : public NodeOperation { { return this->m_chunkOrder; } - CompositorPriority getRenderPriority() const; - bool isViewerOperation() const - { - return true; - } + CompositorPriority getRenderPriority() const override; void setUseAlphaInput(bool value) { this->m_useAlphaInput = value; @@ -130,3 +129,5 @@ class ViewerOperation : public NodeOperation { void updateImage(rcti *rect); void initImage(); }; + +} // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_WrapOperation.cc b/source/blender/compositor/operations/COM_WrapOperation.cc index a869666967e..d0d2fcac3ac 100644 --- a/source/blender/compositor/operations/COM_WrapOperation.cc +++ b/source/blender/compositor/operations/COM_WrapOperation.cc @@ -20,6 +20,8 @@ #include "COM_WrapOperation.h" +namespace blender::compositor { + WrapOperation::WrapOperation(DataType datatype) : ReadBufferOperation(datatype) { this->m_wrappingType = CMP_NODE_WRAP_NONE; @@ -115,3 +117,5 @@ void WrapOperation::setWrapping(int wrapping_type) { m_wrappingType = wrapping_type; } + +} // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_WrapOperation.h b/source/blender/compositor/operations/COM_WrapOperation.h index a72b90e7e94..6279129a550 100644 --- a/source/blender/compositor/operations/COM_WrapOperation.h +++ b/source/blender/compositor/operations/COM_WrapOperation.h @@ -20,6 +20,8 @@ #include "COM_ReadBufferOperation.h" +namespace blender::compositor { + class WrapOperation : public ReadBufferOperation { private: int m_wrappingType; @@ -28,8 +30,8 @@ class WrapOperation : public ReadBufferOperation { WrapOperation(DataType datatype); bool determineDependingAreaOfInterest(rcti *input, ReadBufferOperation *readOperation, - rcti *output); - void executePixelSampled(float output[4], float x, float y, PixelSampler sampler); + rcti *output) override; + void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; void setWrapping(int wrapping_type); float getWrappedOriginalXPos(float x); @@ -37,3 +39,5 @@ class WrapOperation : public ReadBufferOperation { void setFactorXY(float factorX, float factorY); }; + +} // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_WriteBufferOperation.cc b/source/blender/compositor/operations/COM_WriteBufferOperation.cc index e426bc76ef3..1aa19f26e2b 100644 --- a/source/blender/compositor/operations/COM_WriteBufferOperation.cc +++ b/source/blender/compositor/operations/COM_WriteBufferOperation.cc @@ -21,12 +21,15 @@ #include "COM_defines.h" #include <cstdio> +namespace blender::compositor { + WriteBufferOperation::WriteBufferOperation(DataType datatype) { this->addInputSocket(datatype); this->m_memoryProxy = new MemoryProxy(datatype); this->m_memoryProxy->setWriteBufferOperation(this); this->m_memoryProxy->setExecutor(nullptr); + flags.is_write_buffer_operation = true; } WriteBufferOperation::~WriteBufferOperation() { @@ -61,7 +64,7 @@ void WriteBufferOperation::executeRegion(rcti *rect, unsigned int /*tileNumber*/ MemoryBuffer *memoryBuffer = this->m_memoryProxy->getBuffer(); float *buffer = memoryBuffer->getBuffer(); const uint8_t num_channels = memoryBuffer->get_num_channels(); - if (this->m_input->isComplex()) { + if (this->m_input->get_flags().complex) { void *data = this->m_input->initializeTileData(rect); int x1 = rect->xmin; int y1 = rect->ymin; @@ -97,7 +100,7 @@ void WriteBufferOperation::executeRegion(rcti *rect, unsigned int /*tileNumber*/ for (y = y1; y < y2 && (!breaked); y++) { int offset4 = (y * memoryBuffer->getWidth() + x1) * num_channels; for (x = x1; x < x2; x++) { - this->m_input->readSampled(&(buffer[offset4]), x, y, COM_PS_NEAREST); + this->m_input->readSampled(&(buffer[offset4]), x, y, PixelSampler::Nearest); offset4 += num_channels; } if (isBraked()) { @@ -225,3 +228,5 @@ void WriteBufferOperation::readResolutionFromInputSocket() this->setWidth(inputOperation->getWidth()); this->setHeight(inputOperation->getHeight()); } + +} // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_WriteBufferOperation.h b/source/blender/compositor/operations/COM_WriteBufferOperation.h index a9f90830a92..2817fbe24b9 100644 --- a/source/blender/compositor/operations/COM_WriteBufferOperation.h +++ b/source/blender/compositor/operations/COM_WriteBufferOperation.h @@ -20,7 +20,12 @@ #include "COM_MemoryProxy.h" #include "COM_NodeOperation.h" -#include "COM_SocketReader.h" + +namespace blender::compositor { + +class OpenCLDevice; +class MemoryProxy; + /** * \brief NodeOperation to write to a tile * \ingroup Operation @@ -37,28 +42,27 @@ class WriteBufferOperation : public NodeOperation { { return this->m_memoryProxy; } - void executePixelSampled(float output[4], float x, float y, PixelSampler sampler); - bool isWriteBufferOperation() const - { - return true; - } + void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; bool isSingleValue() const { return m_single_value; } - void executeRegion(rcti *rect, unsigned int tileNumber); - void initExecution(); - void deinitExecution(); + void executeRegion(rcti *rect, unsigned int tileNumber) override; + void initExecution() override; + void deinitExecution() override; void executeOpenCLRegion(OpenCLDevice *device, rcti *rect, unsigned int chunkNumber, MemoryBuffer **memoryBuffers, - MemoryBuffer *outputBuffer); - void determineResolution(unsigned int resolution[2], unsigned int preferredResolution[2]); + MemoryBuffer *outputBuffer) override; + void determineResolution(unsigned int resolution[2], + unsigned int preferredResolution[2]) override; void readResolutionFromInputSocket(); inline NodeOperation *getInput() { return m_input; } }; + +} // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_ZCombineOperation.cc b/source/blender/compositor/operations/COM_ZCombineOperation.cc index 8afdbcc7c2d..9d3ca7e736e 100644 --- a/source/blender/compositor/operations/COM_ZCombineOperation.cc +++ b/source/blender/compositor/operations/COM_ZCombineOperation.cc @@ -19,6 +19,8 @@ #include "COM_ZCombineOperation.h" #include "BLI_utildefines.h" +namespace blender::compositor { + ZCombineOperation::ZCombineOperation() { this->addInputSocket(DataType::Color); @@ -158,3 +160,5 @@ void ZCombineMaskOperation::deinitExecution() this->m_maskReader = nullptr; this->m_image2Reader = nullptr; } + +} // namespace blender::compositor diff --git a/source/blender/compositor/operations/COM_ZCombineOperation.h b/source/blender/compositor/operations/COM_ZCombineOperation.h index a64e3c5b70f..d0b1aee7310 100644 --- a/source/blender/compositor/operations/COM_ZCombineOperation.h +++ b/source/blender/compositor/operations/COM_ZCombineOperation.h @@ -20,6 +20,8 @@ #include "COM_MixOperation.h" +namespace blender::compositor { + /** * this program converts an input color to an output value. * it assumes we are in sRGB color space. @@ -37,17 +39,17 @@ class ZCombineOperation : public NodeOperation { */ ZCombineOperation(); - void initExecution(); - void deinitExecution(); + void initExecution() override; + void deinitExecution() override; /** * The inner loop of this operation. */ - void executePixelSampled(float output[4], float x, float y, PixelSampler sampler); + void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; }; class ZCombineAlphaOperation : public ZCombineOperation { - void executePixelSampled(float output[4], float x, float y, PixelSampler sampler); + void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; }; class ZCombineMaskOperation : public NodeOperation { @@ -59,10 +61,12 @@ class ZCombineMaskOperation : public NodeOperation { public: ZCombineMaskOperation(); - void initExecution(); - void deinitExecution(); - void executePixelSampled(float output[4], float x, float y, PixelSampler sampler); + void initExecution() override; + void deinitExecution() override; + void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; }; class ZCombineMaskAlphaOperation : public ZCombineMaskOperation { - void executePixelSampled(float output[4], float x, float y, PixelSampler sampler); + void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; }; + +} // namespace blender::compositor diff --git a/source/blender/depsgraph/intern/builder/pipeline.cc b/source/blender/depsgraph/intern/builder/pipeline.cc index f7feeea9593..b96236ba2e3 100644 --- a/source/blender/depsgraph/intern/builder/pipeline.cc +++ b/source/blender/depsgraph/intern/builder/pipeline.cc @@ -98,7 +98,7 @@ void AbstractBuilderPipeline::build_step_finalize() if (G.debug_value == 799) { deg_graph_transitive_reduction(deg_graph_); } - /* Store pointers to commonly used valuated datablocks. */ + /* Store pointers to commonly used evaluated datablocks. */ deg_graph_->scene_cow = (Scene *)deg_graph_->get_cow_id(°_graph_->scene->id); /* Flush visibility layer and re-schedule nodes for update. */ deg_graph_build_finalize(bmain_, deg_graph_); diff --git a/source/blender/draw/DRW_engine.h b/source/blender/draw/DRW_engine.h index 2d5b93f4272..8a35ab2aeb9 100644 --- a/source/blender/draw/DRW_engine.h +++ b/source/blender/draw/DRW_engine.h @@ -118,8 +118,7 @@ void DRW_draw_select_loop(struct Depsgraph *depsgraph, void DRW_draw_depth_loop(struct Depsgraph *depsgraph, struct ARegion *region, struct View3D *v3d, - struct GPUViewport *viewport, - bool use_opengl_context); + struct GPUViewport *viewport); void DRW_draw_depth_loop_gpencil(struct Depsgraph *depsgraph, struct ARegion *region, struct View3D *v3d, diff --git a/source/blender/draw/engines/overlay/overlay_armature.c b/source/blender/draw/engines/overlay/overlay_armature.c index 7042d095b56..54224071d23 100644 --- a/source/blender/draw/engines/overlay/overlay_armature.c +++ b/source/blender/draw/engines/overlay/overlay_armature.c @@ -1293,11 +1293,15 @@ static void draw_axes(ArmatureDrawContext *ctx, float length = pchan->bone->length; copy_m4_m4(axis_mat, pchan->custom_tx ? pchan->custom_tx->pose_mat : pchan->pose_mat); rescale_m4(axis_mat, (float[3]){length, length, length}); + translate_m4(axis_mat, 0.0, arm->axes_position - 1.0, 0.0); drw_shgroup_bone_axes(ctx, axis_mat, final_col); } else { - drw_shgroup_bone_axes(ctx, BONE_VAR(eBone, pchan, disp_mat), final_col); + float disp_mat[4][4]; + copy_m4_m4(disp_mat, BONE_VAR(eBone, pchan, disp_mat)); + translate_m4(disp_mat, 0.0, arm->axes_position - 1.0, 0.0); + drw_shgroup_bone_axes(ctx, disp_mat, final_col); } } diff --git a/source/blender/draw/intern/draw_manager.c b/source/blender/draw/intern/draw_manager.c index a088c27d3f3..c09b4719f3a 100644 --- a/source/blender/draw/intern/draw_manager.c +++ b/source/blender/draw/intern/draw_manager.c @@ -2601,8 +2601,7 @@ static void drw_draw_depth_loop_impl(struct Depsgraph *depsgraph, void DRW_draw_depth_loop(struct Depsgraph *depsgraph, ARegion *region, View3D *v3d, - GPUViewport *viewport, - bool use_opengl_context) + GPUViewport *viewport) { /* Reset before using it. */ drw_state_prepare_clean_for_draw(&DST); @@ -2618,7 +2617,7 @@ void DRW_draw_depth_loop(struct Depsgraph *depsgraph, } } - drw_draw_depth_loop_impl(depsgraph, region, v3d, viewport, use_opengl_context); + drw_draw_depth_loop_impl(depsgraph, region, v3d, viewport, false); } /** @@ -2634,7 +2633,7 @@ void DRW_draw_depth_loop_gpencil(struct Depsgraph *depsgraph, use_drw_engine(&draw_engine_gpencil_type); - drw_draw_depth_loop_impl(depsgraph, region, v3d, viewport, true); + drw_draw_depth_loop_impl(depsgraph, region, v3d, viewport, false); } void DRW_draw_select_id(Depsgraph *depsgraph, ARegion *region, View3D *v3d, const rcti *rect) @@ -2725,7 +2724,6 @@ void DRW_draw_depth_object( { RegionView3D *rv3d = region->regiondata; - DRW_opengl_context_enable(); GPU_matrix_projection_set(rv3d->winmat); GPU_matrix_set(rv3d->viewmat); GPU_matrix_mul(object->obmat); @@ -2784,7 +2782,6 @@ void DRW_draw_depth_object( GPU_matrix_set(rv3d->viewmat); GPU_depth_test(GPU_DEPTH_NONE); GPU_framebuffer_restore(); - DRW_opengl_context_disable(); } /** \} */ diff --git a/source/blender/editors/animation/keyframing.c b/source/blender/editors/animation/keyframing.c index 4cc0413be5b..9cbb799082c 100644 --- a/source/blender/editors/animation/keyframing.c +++ b/source/blender/editors/animation/keyframing.c @@ -3034,19 +3034,9 @@ bool ED_autokeyframe_pchan( ANIM_apply_keyingset(C, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, (float)CFRA); BLI_freelistN(&dsources); - /* clear any unkeyed tags */ - if (pchan->bone) { - pchan->bone->flag &= ~BONE_UNKEYED; - } - return true; } - /* add unkeyed tags */ - if (pchan->bone) { - pchan->bone->flag |= BONE_UNKEYED; - } - return false; } diff --git a/source/blender/editors/armature/armature_naming.c b/source/blender/editors/armature/armature_naming.c index 8bcaf72f678..70154695dcd 100644 --- a/source/blender/editors/armature/armature_naming.c +++ b/source/blender/editors/armature/armature_naming.c @@ -525,8 +525,8 @@ void ARMATURE_OT_flip_names(wmOperatorType *ot) "do_strip_numbers", false, "Strip Numbers", - "Try to remove right-most dot-number from flipped names " - "(WARNING: may result in incoherent naming in some cases)"); + "Try to remove right-most dot-number from flipped names.\n" + "Warning: May result in incoherent naming in some cases"); } /** \} */ diff --git a/source/blender/editors/armature/pose_edit.c b/source/blender/editors/armature/pose_edit.c index e65871c0896..f5daa427149 100644 --- a/source/blender/editors/armature/pose_edit.c +++ b/source/blender/editors/armature/pose_edit.c @@ -593,8 +593,8 @@ void POSE_OT_flip_names(wmOperatorType *ot) "do_strip_numbers", false, "Strip Numbers", - "Try to remove right-most dot-number from flipped names " - "(WARNING: may result in incoherent naming in some cases)"); + "Try to remove right-most dot-number from flipped names.\n" + "Warning: May result in incoherent naming in some cases"); } /* ------------------ */ diff --git a/source/blender/editors/armature/pose_lib.c b/source/blender/editors/armature/pose_lib.c index dd90f9f2cc3..21fcbf8886b 100644 --- a/source/blender/editors/armature/pose_lib.c +++ b/source/blender/editors/armature/pose_lib.c @@ -1108,17 +1108,6 @@ static void poselib_keytag_pose(bContext *C, Scene *scene, tPoseLib_PreviewData if (autokey) { /* Add data-source override for the PoseChannel, to be used later. */ ANIM_relative_keyingset_add_source(&dsources, &pld->ob->id, &RNA_PoseBone, pchan); - - /* clear any unkeyed tags */ - if (pchan->bone) { - pchan->bone->flag &= ~BONE_UNKEYED; - } - } - else { - /* add unkeyed tags */ - if (pchan->bone) { - pchan->bone->flag |= BONE_UNKEYED; - } } } } diff --git a/source/blender/editors/armature/pose_transform.c b/source/blender/editors/armature/pose_transform.c index 8d1c196e9c2..43ab20eb71c 100644 --- a/source/blender/editors/armature/pose_transform.c +++ b/source/blender/editors/armature/pose_transform.c @@ -172,9 +172,6 @@ static void applyarmature_transfer_properties(EditBone *curbone, unit_qt(pchan->quat); unit_axis_angle(pchan->rotAxis, &pchan->rotAngle); pchan->size[0] = pchan->size[1] = pchan->size[2] = 1.0f; - - /* Set anim lock. */ - curbone->flag |= BONE_UNKEYED; } /* Adjust the current edit position of the bone using the pose space matrix. */ @@ -1200,10 +1197,6 @@ static int pose_clear_transform_generic_exec(bContext *C, /* do auto-keyframing as appropriate */ if (autokeyframe_cfra_can_key(scene, &ob_iter->id)) { - /* clear any unkeyed tags */ - if (pchan->bone) { - pchan->bone->flag &= ~BONE_UNKEYED; - } /* tag for autokeying later */ ANIM_relative_keyingset_add_source(&dsources, &ob_iter->id, &RNA_PoseBone, pchan); @@ -1212,12 +1205,6 @@ static int pose_clear_transform_generic_exec(bContext *C, clear_func(ob_iter->pose, pchan_eval); #endif } - else { - /* add unkeyed tags */ - if (pchan->bone) { - pchan->bone->flag |= BONE_UNKEYED; - } - } } FOREACH_PCHAN_SELECTED_IN_OBJECT_END; diff --git a/source/blender/editors/armature/pose_utils.c b/source/blender/editors/armature/pose_utils.c index c75e9c9ef69..75348c2b196 100644 --- a/source/blender/editors/armature/pose_utils.c +++ b/source/blender/editors/armature/pose_utils.c @@ -313,11 +313,6 @@ void poseAnim_mapping_autoKeyframe(bContext *C, Scene *scene, ListBase *pfLinks, /* Add data-source override for the PoseChannel, to be used later. */ ANIM_relative_keyingset_add_source(&dsources, &pfl->ob->id, &RNA_PoseBone, pchan); - - /* clear any unkeyed tags */ - if (pchan->bone) { - pchan->bone->flag &= ~BONE_UNKEYED; - } } /* insert keyframes for all relevant bones in one go */ diff --git a/source/blender/editors/curve/editcurve_paint.c b/source/blender/editors/curve/editcurve_paint.c index 48a36ff276d..0d071f2e595 100644 --- a/source/blender/editors/curve/editcurve_paint.c +++ b/source/blender/editors/curve/editcurve_paint.c @@ -1083,13 +1083,8 @@ static int curve_draw_invoke(bContext *C, wmOperator *op, const wmEvent *event) /* needed or else the draw matrix can be incorrect */ view3d_operator_needs_opengl(C); - ED_view3d_autodist_init(cdd->vc.depsgraph, cdd->vc.region, cdd->vc.v3d, 0); - - if (cdd->vc.rv3d->depths) { - cdd->vc.rv3d->depths->damaged = true; - } - - ED_view3d_depth_update(cdd->vc.region); + ED_view3d_depth_override( + cdd->vc.depsgraph, cdd->vc.region, cdd->vc.v3d, NULL, V3D_DEPTH_NO_GPENCIL, true); if (cdd->vc.rv3d->depths != NULL) { cdd->project.use_depth = true; diff --git a/source/blender/editors/curve/editcurve_select.c b/source/blender/editors/curve/editcurve_select.c index d362ec23370..e3fc8b73172 100644 --- a/source/blender/editors/curve/editcurve_select.c +++ b/source/blender/editors/curve/editcurve_select.c @@ -578,8 +578,8 @@ static int de_select_all_exec(bContext *C, wmOperator *op) changed = ED_curve_deselect_all(cu->editnurb); break; case SEL_INVERT: - changed = ED_curve_select_swap(cu->editnurb, - v3d->overlay.handle_display == CURVE_HANDLE_NONE); + changed = ED_curve_select_swap( + cu->editnurb, (v3d && (v3d->overlay.handle_display == CURVE_HANDLE_NONE))); break; } diff --git a/source/blender/editors/geometry/geometry_attributes.c b/source/blender/editors/geometry/geometry_attributes.c index 2807e7c4392..12f6bb90677 100644 --- a/source/blender/editors/geometry/geometry_attributes.c +++ b/source/blender/editors/geometry/geometry_attributes.c @@ -53,7 +53,11 @@ static const EnumPropertyItem *geometry_attribute_domain_itemf(bContext *C, bool *r_free) { Object *ob = ED_object_context(C); - return rna_enum_attribute_domain_itemf(ob->data, r_free); + if (ob != NULL) { + return rna_enum_attribute_domain_itemf(ob->data, r_free); + } + + return DummyRNA_NULL_items; } static int geometry_attribute_add_exec(bContext *C, wmOperator *op) diff --git a/source/blender/editors/gizmo_library/gizmo_types/snap3d_gizmo.c b/source/blender/editors/gizmo_library/gizmo_types/snap3d_gizmo.c index b8ee1722cb3..c21535de4d5 100644 --- a/source/blender/editors/gizmo_library/gizmo_types/snap3d_gizmo.c +++ b/source/blender/editors/gizmo_library/gizmo_types/snap3d_gizmo.c @@ -27,11 +27,14 @@ * \brief Snap gizmo which exposes the location, normal and index in the props. */ +#include "BLI_listbase.h" #include "BLI_math.h" #include "DNA_scene_types.h" #include "BKE_context.h" +#include "BKE_global.h" +#include "BKE_main.h" #include "GPU_immediate.h" #include "GPU_state.h" @@ -57,11 +60,6 @@ typedef struct SnapGizmo3D { wmGizmo gizmo; - PropertyRNA *prop_prevpoint; - PropertyRNA *prop_location; - PropertyRNA *prop_normal; - PropertyRNA *prop_elem_index; - PropertyRNA *prop_snap_force; /* We could have other snap contexts, for now only support 3D view. */ SnapObjectContext *snap_context_v3d; @@ -78,8 +76,18 @@ typedef struct SnapGizmo3D { int snap_on; bool invert_snap; #endif + + /* Setup. */ + float *prevpoint; + float prevpoint_stack[3]; int use_snap_override; + short snap_elem_force; + + /* Return values. */ short snap_elem; + float loc[3]; + float nor[3]; + int elem_index[3]; /** Enabled when snap is activated, even if it didn't find anything. */ bool is_enabled; @@ -158,6 +166,19 @@ static bool invert_snap(SnapGizmo3D *snap_gizmo, const wmWindowManager *wm) } #endif +static short snap_gizmo_snap_elements(SnapGizmo3D *snap_gizmo) +{ + int snap_elements = snap_gizmo->snap_elem_force; + + wmGizmoProperty *gz_prop = WM_gizmo_target_property_find(&snap_gizmo->gizmo, "snap_elements"); + if (gz_prop->prop) { + snap_elements |= RNA_property_enum_get(&gz_prop->ptr, gz_prop->prop); + } + snap_elements &= (SCE_SNAP_MODE_VERTEX | SCE_SNAP_MODE_EDGE | SCE_SNAP_MODE_FACE | + SCE_SNAP_MODE_EDGE_MIDPOINT | SCE_SNAP_MODE_EDGE_PERPENDICULAR); + return (ushort)snap_elements; +} + /* -------------------------------------------------------------------- */ /** \name ED_gizmo_library specific API * \{ */ @@ -298,9 +319,7 @@ short ED_gizmotypes_snap_3d_update(wmGizmo *gz, const ARegion *region, const View3D *v3d, const wmWindowManager *wm, - const float mval_fl[2], - float r_loc[3], - float r_nor[3]) + const float mval_fl[2]) { SnapGizmo3D *snap_gizmo = (SnapGizmo3D *)gz; snap_gizmo->is_enabled = false; @@ -336,19 +355,12 @@ short ED_gizmotypes_snap_3d_update(wmGizmo *gz, int snap_elem_index[3] = {-1, -1, -1}; int index = -1; - wmGizmoProperty *gz_prop = WM_gizmo_target_property_find(gz, "snap_elements"); - int snap_elements = RNA_property_enum_get(&gz_prop->ptr, gz_prop->prop); - if (gz_prop->prop != snap_gizmo->prop_snap_force) { - int snap_elements_force = RNA_property_enum_get(gz->ptr, snap_gizmo->prop_snap_force); - snap_elements |= snap_elements_force; - } - snap_elements &= (SCE_SNAP_MODE_VERTEX | SCE_SNAP_MODE_EDGE | SCE_SNAP_MODE_FACE | - SCE_SNAP_MODE_EDGE_MIDPOINT | SCE_SNAP_MODE_EDGE_PERPENDICULAR); + ushort snap_elements = snap_gizmo_snap_elements(snap_gizmo); if (snap_elements) { float prev_co[3] = {0.0f}; - if (RNA_property_is_set(gz->ptr, snap_gizmo->prop_prevpoint)) { - RNA_property_float_get_array(gz->ptr, snap_gizmo->prop_prevpoint, prev_co); + if (snap_gizmo->prevpoint) { + copy_v3_v3(prev_co, snap_gizmo->prevpoint); } else { snap_elements &= ~SCE_SNAP_MODE_EDGE_PERPENDICULAR; @@ -392,19 +404,147 @@ short ED_gizmotypes_snap_3d_update(wmGizmo *gz, } snap_gizmo->snap_elem = snap_elem; - RNA_property_float_set_array(gz->ptr, snap_gizmo->prop_location, co); - RNA_property_float_set_array(gz->ptr, snap_gizmo->prop_normal, no); - RNA_property_int_set_array(gz->ptr, snap_gizmo->prop_elem_index, snap_elem_index); + copy_v3_v3(snap_gizmo->loc, co); + copy_v3_v3(snap_gizmo->nor, no); + copy_v3_v3_int(snap_gizmo->elem_index, snap_elem_index); + + return snap_elem; +} +void ED_gizmotypes_snap_3d_data_get( + wmGizmo *gz, float r_loc[3], float r_nor[3], int r_elem_index[3], int *r_snap_elem) +{ + SnapGizmo3D *snap_gizmo = (SnapGizmo3D *)gz; if (r_loc) { - copy_v3_v3(r_loc, co); + copy_v3_v3(r_loc, snap_gizmo->loc); } - if (r_nor) { - copy_v3_v3(r_nor, no); + copy_v3_v3(r_nor, snap_gizmo->nor); + } + if (r_elem_index) { + copy_v3_v3_int(r_elem_index, snap_gizmo->elem_index); } + if (r_snap_elem) { + *r_snap_elem = snap_gizmo->snap_elem; + } +} - return snap_elem; +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name RNA callbacks + * \{ */ + +/* Based on 'rna_GizmoProperties_find_operator'. */ +static struct SnapGizmo3D *gizmo_snap_rna_find_operator(PointerRNA *ptr) +{ + IDProperty *properties = ptr->data; + for (bScreen *screen = G_MAIN->screens.first; screen; screen = screen->id.next) { + LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) { + if (area->spacetype != SPACE_VIEW3D) { + continue; + } + LISTBASE_FOREACH (ARegion *, region, &area->regionbase) { + if (region->regiontype == RGN_TYPE_WINDOW && region->gizmo_map) { + wmGizmoMap *gzmap = region->gizmo_map; + LISTBASE_FOREACH (wmGizmoGroup *, gzgroup, WM_gizmomap_group_list(gzmap)) { + LISTBASE_FOREACH (wmGizmo *, gz, &gzgroup->gizmos) { + if (gz->properties == properties) { + return (SnapGizmo3D *)gz; + } + } + } + } + } + } + } + return NULL; +} + +static int gizmo_snap_rna_snap_elements_force_get_fn(struct PointerRNA *ptr, + struct PropertyRNA *UNUSED(prop)) +{ + SnapGizmo3D *snap_gizmo = gizmo_snap_rna_find_operator(ptr); + if (snap_gizmo) { + return snap_gizmo->snap_elem_force; + } + return 0; +} + +static void gizmo_snap_rna_snap_elements_force_set_fn(struct PointerRNA *ptr, + struct PropertyRNA *UNUSED(prop), + int value) +{ + SnapGizmo3D *snap_gizmo = gizmo_snap_rna_find_operator(ptr); + if (snap_gizmo) { + snap_gizmo->snap_elem_force = (short)value; + } +} + +static void gizmo_snap_rna_prevpoint_get_fn(struct PointerRNA *ptr, + struct PropertyRNA *UNUSED(prop), + float *values) +{ + SnapGizmo3D *snap_gizmo = gizmo_snap_rna_find_operator(ptr); + if (snap_gizmo) { + copy_v3_v3(values, snap_gizmo->prevpoint_stack); + } +} + +static void gizmo_snap_rna_prevpoint_set_fn(struct PointerRNA *ptr, + struct PropertyRNA *UNUSED(prop), + const float *values) +{ + SnapGizmo3D *snap_gizmo = gizmo_snap_rna_find_operator(ptr); + if (snap_gizmo) { + if (values) { + copy_v3_v3(snap_gizmo->prevpoint_stack, values); + snap_gizmo->prevpoint = snap_gizmo->prevpoint_stack; + } + else { + snap_gizmo->prevpoint = NULL; + } + } +} + +static void gizmo_snap_rna_location_get_fn(struct PointerRNA *ptr, + struct PropertyRNA *UNUSED(prop), + float *values) +{ + SnapGizmo3D *snap_gizmo = gizmo_snap_rna_find_operator(ptr); + if (snap_gizmo) { + copy_v3_v3(values, snap_gizmo->loc); + } +} + +static void gizmo_snap_rna_location_set_fn(struct PointerRNA *ptr, + struct PropertyRNA *UNUSED(prop), + const float *values) +{ + SnapGizmo3D *snap_gizmo = gizmo_snap_rna_find_operator(ptr); + if (snap_gizmo) { + copy_v3_v3(snap_gizmo->loc, values); + } +} + +static void gizmo_snap_rna_normal_get_fn(struct PointerRNA *ptr, + struct PropertyRNA *UNUSED(prop), + float *values) +{ + SnapGizmo3D *snap_gizmo = gizmo_snap_rna_find_operator(ptr); + if (snap_gizmo) { + copy_v3_v3(values, snap_gizmo->nor); + } +} + +static void gizmo_snap_rna_snap_elem_index_get_fn(struct PointerRNA *ptr, + struct PropertyRNA *UNUSED(prop), + int *values) +{ + SnapGizmo3D *snap_gizmo = gizmo_snap_rna_find_operator(ptr); + if (snap_gizmo) { + copy_v3_v3_int(values, snap_gizmo->elem_index); + } } /** \} */ @@ -416,19 +556,8 @@ short ED_gizmotypes_snap_3d_update(wmGizmo *gz, static void snap_gizmo_setup(wmGizmo *gz) { SnapGizmo3D *snap_gizmo = (SnapGizmo3D *)gz; - - /* For quick access to the props. */ - snap_gizmo->prop_prevpoint = RNA_struct_find_property(gz->ptr, "prev_point"); - snap_gizmo->prop_location = RNA_struct_find_property(gz->ptr, "location"); - snap_gizmo->prop_normal = RNA_struct_find_property(gz->ptr, "normal"); - snap_gizmo->prop_elem_index = RNA_struct_find_property(gz->ptr, "snap_elem_index"); - snap_gizmo->prop_snap_force = RNA_struct_find_property(gz->ptr, "snap_elements_force"); - snap_gizmo->use_snap_override = -1; - /* Prop fallback. */ - WM_gizmo_target_property_def_rna(gz, "snap_elements", gz->ptr, "snap_elements_force", -1); - /* Flags. */ gz->flag |= WM_GIZMO_NO_TOOLTIP; } @@ -455,26 +584,23 @@ static void snap_gizmo_draw(const bContext *C, wmGizmo *gz) return; } - float location[3], prev_point_stack[3], *prev_point = NULL; uchar color_line[4], color_point[4]; - - RNA_property_float_get_array(gz->ptr, snap_gizmo->prop_location, location); - UI_GetThemeColor3ubv(TH_TRANSFORM, color_line); color_line[3] = 128; rgba_float_to_uchar(color_point, gz->color); - if (RNA_property_is_set(gz->ptr, snap_gizmo->prop_prevpoint)) { - RNA_property_float_get_array(gz->ptr, snap_gizmo->prop_prevpoint, prev_point_stack); - prev_point = prev_point_stack; - } - GPU_line_smooth(false); GPU_line_width(1.0f); + + const float *prev_point = snap_gizmo_snap_elements(snap_gizmo) & + SCE_SNAP_MODE_EDGE_PERPENDICULAR ? + snap_gizmo->prevpoint : + NULL; + ED_gizmotypes_snap_3d_draw_util( - rv3d, prev_point, location, NULL, color_line, color_point, snap_gizmo->snap_elem); + rv3d, prev_point, snap_gizmo->loc, NULL, color_line, color_point, snap_gizmo->snap_elem); } static int snap_gizmo_test_select(bContext *C, wmGizmo *gz, const int mval[2]) @@ -490,7 +616,7 @@ static int snap_gizmo_test_select(bContext *C, wmGizmo *gz, const int mval[2]) View3D *v3d = CTX_wm_view3d(C); const float mval_fl[2] = {UNPACK2(mval)}; short snap_elem = ED_gizmotypes_snap_3d_update( - gz, CTX_data_ensure_evaluated_depsgraph(C), region, v3d, wm, mval_fl, NULL, NULL); + gz, CTX_data_ensure_evaluated_depsgraph(C), region, v3d, wm, mval_fl); if (snap_elem) { ED_region_tag_redraw_editor_overlays(region); @@ -553,57 +679,74 @@ static void GIZMO_GT_snap_3d(wmGizmoType *gzt) } /* Setup. */ - RNA_def_enum_flag(gzt->srna, - "snap_elements_force", - rna_enum_snap_element_items, - SCE_SNAP_MODE_VERTEX | SCE_SNAP_MODE_EDGE | SCE_SNAP_MODE_FACE, - "Snap Elements", - ""); - - RNA_def_float_vector(gzt->srna, - "prev_point", - 3, - NULL, - FLT_MIN, - FLT_MAX, - "Previous Point", - "Point that defines the location of the perpendicular snap", - FLT_MIN, - FLT_MAX); + PropertyRNA *prop; + prop = RNA_def_enum_flag(gzt->srna, + "snap_elements_force", + rna_enum_snap_element_items, + SCE_SNAP_MODE_VERTEX | SCE_SNAP_MODE_EDGE | SCE_SNAP_MODE_FACE, + "Snap Elements", + ""); + + RNA_def_property_enum_funcs_runtime(prop, + gizmo_snap_rna_snap_elements_force_get_fn, + gizmo_snap_rna_snap_elements_force_set_fn, + NULL); + + prop = RNA_def_float_array(gzt->srna, + "prev_point", + 3, + NULL, + FLT_MIN, + FLT_MAX, + "Previous Point", + "Point that defines the location of the perpendicular snap", + FLT_MIN, + FLT_MAX); + + RNA_def_property_float_array_funcs_runtime( + prop, gizmo_snap_rna_prevpoint_get_fn, gizmo_snap_rna_prevpoint_set_fn, NULL); /* Returns. */ - RNA_def_float_vector(gzt->srna, - "location", - 3, - NULL, - FLT_MIN, - FLT_MAX, - "Location", - "Snap Point Location", - FLT_MIN, - FLT_MAX); - - RNA_def_float_vector(gzt->srna, - "normal", - 3, - NULL, - FLT_MIN, - FLT_MAX, - "Normal", - "Snap Point Normal", - FLT_MIN, - FLT_MAX); - - RNA_def_int_vector(gzt->srna, - "snap_elem_index", - 3, - NULL, - INT_MIN, - INT_MAX, - "Snap Element", - "Array index of face, edge and vert snapped", - INT_MIN, - INT_MAX); + prop = RNA_def_float_translation(gzt->srna, + "location", + 3, + NULL, + FLT_MIN, + FLT_MAX, + "Location", + "Snap Point Location", + FLT_MIN, + FLT_MAX); + + RNA_def_property_float_array_funcs_runtime( + prop, gizmo_snap_rna_location_get_fn, gizmo_snap_rna_location_set_fn, NULL); + + prop = RNA_def_float_vector_xyz(gzt->srna, + "normal", + 3, + NULL, + FLT_MIN, + FLT_MAX, + "Normal", + "Snap Point Normal", + FLT_MIN, + FLT_MAX); + + RNA_def_property_float_array_funcs_runtime(prop, gizmo_snap_rna_normal_get_fn, NULL, NULL); + + prop = RNA_def_int_vector(gzt->srna, + "snap_elem_index", + 3, + NULL, + INT_MIN, + INT_MAX, + "Snap Element", + "Array index of face, edge and vert snapped", + INT_MIN, + INT_MAX); + + RNA_def_property_int_array_funcs_runtime( + prop, gizmo_snap_rna_snap_elem_index_get_fn, NULL, NULL); /* Read/Write. */ WM_gizmotype_target_property_def(gzt, "snap_elements", PROP_ENUM, 1); diff --git a/source/blender/editors/gpencil/annotate_paint.c b/source/blender/editors/gpencil/annotate_paint.c index e9817f82090..5c40bc8e418 100644 --- a/source/blender/editors/gpencil/annotate_paint.c +++ b/source/blender/editors/gpencil/annotate_paint.c @@ -660,10 +660,14 @@ static short annotation_stroke_addpoint(tGPsdata *p, View3D *v3d = p->area->spacedata.first; view3d_region_operator_needs_opengl(p->win, p->region); - ED_view3d_autodist_init(p->depsgraph, - p->region, - v3d, - (ts->annotate_v3d_align & GP_PROJECT_DEPTH_STROKE) ? 1 : 0); + ED_view3d_depth_override(p->depsgraph, + p->region, + v3d, + NULL, + (ts->annotate_v3d_align & GP_PROJECT_DEPTH_STROKE) ? + V3D_DEPTH_GPENCIL_ONLY : + V3D_DEPTH_NO_GPENCIL, + false); } /* convert screen-coordinates to appropriate coordinates (and store them) */ @@ -1222,7 +1226,7 @@ static void annotation_stroke_doeraser(tGPsdata *p) if (p->flags & GP_PAINTFLAG_V3D_ERASER_DEPTH) { View3D *v3d = p->area->spacedata.first; view3d_region_operator_needs_opengl(p->win, p->region); - ED_view3d_autodist_init(p->depsgraph, p->region, v3d, 0); + ED_view3d_depth_override(p->depsgraph, p->region, v3d, NULL, V3D_DEPTH_NO_GPENCIL, false); } } @@ -1695,8 +1699,14 @@ static void annotation_paint_strokeend(tGPsdata *p) /* need to restore the original projection settings before packing up */ view3d_region_operator_needs_opengl(p->win, p->region); - ED_view3d_autodist_init( - p->depsgraph, p->region, v3d, (ts->annotate_v3d_align & GP_PROJECT_DEPTH_STROKE) ? 1 : 0); + ED_view3d_depth_override(p->depsgraph, + p->region, + v3d, + NULL, + (ts->annotate_v3d_align & GP_PROJECT_DEPTH_STROKE) ? + V3D_DEPTH_GPENCIL_ONLY : + V3D_DEPTH_NO_GPENCIL, + false); } /* check if doing eraser or not */ diff --git a/source/blender/editors/gpencil/gpencil_edit.c b/source/blender/editors/gpencil/gpencil_edit.c index 4bbd475dd2c..66beb74d566 100644 --- a/source/blender/editors/gpencil/gpencil_edit.c +++ b/source/blender/editors/gpencil/gpencil_edit.c @@ -3951,7 +3951,7 @@ static void gpencil_smooth_stroke(bContext *C, wmOperator *op) } if (smooth_thickness) { /* thickness need to repeat process several times */ - for (int r2 = 0; r2 < r * 20; r2++) { + for (int r2 = 0; r2 < 20; r2++) { BKE_gpencil_stroke_smooth_thickness(gps, i, factor); } } @@ -4979,17 +4979,27 @@ static int gpencil_cutter_lasso_select(bContext *C, /* init space conversion stuff */ gpencil_point_conversion_init(C, &gsc); - /* deselect all strokes first */ - CTX_DATA_BEGIN (C, bGPDstroke *, gps, editable_gpencil_strokes) { - int i; - for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) { - pt->flag &= ~GP_SPOINT_SELECT; - } + /* Deselect all strokes. */ + LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) { + bGPDframe *init_gpf = (is_multiedit) ? gpl->frames.first : gpl->actframe; + for (bGPDframe *gpf = init_gpf; gpf; gpf = gpf->next) { + LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) { + if (gps->flag & GP_STROKE_SELECT) { + int i; + for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) { + pt->flag &= ~GP_SPOINT_SELECT; + } - gps->flag &= ~GP_STROKE_SELECT; - BKE_gpencil_stroke_select_index_reset(gps); + gps->flag &= ~GP_STROKE_SELECT; + BKE_gpencil_stroke_select_index_reset(gps); + } + } + /* if not multiedit, exit loop. */ + if (!is_multiedit) { + break; + } + } } - CTX_DATA_END; /* Select points */ LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) { diff --git a/source/blender/editors/gpencil/gpencil_fill.c b/source/blender/editors/gpencil/gpencil_fill.c index 4749f40fac5..3f86e5474c5 100644 --- a/source/blender/editors/gpencil/gpencil_fill.c +++ b/source/blender/editors/gpencil/gpencil_fill.c @@ -1363,7 +1363,8 @@ static void gpencil_get_depth_array(tGPDfill *tgpf) if (ts->gpencil_v3d_align & GP_PROJECT_DEPTH_VIEW) { /* need to restore the original projection settings before packing up */ view3d_region_operator_needs_opengl(tgpf->win, tgpf->region); - ED_view3d_autodist_init(tgpf->depsgraph, tgpf->region, tgpf->v3d, 0); + ED_view3d_depth_override( + tgpf->depsgraph, tgpf->region, tgpf->v3d, NULL, V3D_DEPTH_NO_GPENCIL, false); /* Since strokes are so fine, when using their depth we need a margin * otherwise they might get missed. */ diff --git a/source/blender/editors/gpencil/gpencil_interpolate.c b/source/blender/editors/gpencil/gpencil_interpolate.c index bfa1ee6bcaf..e6a6c65243e 100644 --- a/source/blender/editors/gpencil/gpencil_interpolate.c +++ b/source/blender/editors/gpencil/gpencil_interpolate.c @@ -84,7 +84,8 @@ typedef struct tGPDinterpolate_layer { /** interpolate factor */ float factor; - /* Hash tablets to create temp relationship between strokes. */ + /* List of strokes and Hash tablets to create temp relationship between strokes. */ + struct ListBase selected_strokes; struct GHash *used_strokes; struct GHash *pair_strokes; @@ -282,6 +283,7 @@ static void gpencil_stroke_pair_table(bContext *C, const bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gpd); /* Create hash tablets with relationship between strokes. */ + BLI_listbase_clear(&tgpil->selected_strokes); tgpil->used_strokes = BLI_ghash_ptr_new(__func__); tgpil->pair_strokes = BLI_ghash_ptr_new(__func__); @@ -315,7 +317,8 @@ static void gpencil_stroke_pair_table(bContext *C, if (ELEM(NULL, gps_from, gps_to)) { continue; } - /* Insert the pair entry in the hash table. */ + /* Insert the pair entry in the hash table and the list of strokes to keep order. */ + BLI_addtail(&tgpil->selected_strokes, BLI_genericNodeN(gps_from)); BLI_ghash_insert(tgpil->pair_strokes, gps_from, gps_to); } } @@ -405,10 +408,13 @@ static void gpencil_interpolate_update_strokes(bContext *C, tGPDinterpolate *tgp /* Clear previous interpolations. */ gpencil_interpolate_free_tagged_strokes(tgpil->interFrame); - GHashIterator gh_iter; - GHASH_ITER (gh_iter, tgpil->pair_strokes) { - bGPDstroke *gps_from = (bGPDstroke *)BLI_ghashIterator_getKey(&gh_iter); - bGPDstroke *gps_to = (bGPDstroke *)BLI_ghashIterator_getValue(&gh_iter); + LISTBASE_FOREACH (LinkData *, link, &tgpil->selected_strokes) { + bGPDstroke *gps_from = link->data; + if (!BLI_ghash_haskey(tgpil->pair_strokes, gps_from)) { + continue; + } + bGPDstroke *gps_to = (bGPDstroke *)BLI_ghash_lookup(tgpil->pair_strokes, gps_from); + /* Create new stroke. */ bGPDstroke *new_stroke = BKE_gpencil_stroke_duplicate(gps_from, true, true); new_stroke->flag |= GP_STROKE_TAG; @@ -527,10 +533,12 @@ static void gpencil_interpolate_set_points(bContext *C, tGPDinterpolate *tgpi) gpencil_stroke_pair_table(C, tgpi, tgpil); /* Create new strokes data with interpolated points reading original stroke. */ - GHashIterator gh_iter; - GHASH_ITER (gh_iter, tgpil->pair_strokes) { - bGPDstroke *gps_from = (bGPDstroke *)BLI_ghashIterator_getKey(&gh_iter); - bGPDstroke *gps_to = (bGPDstroke *)BLI_ghashIterator_getValue(&gh_iter); + LISTBASE_FOREACH (LinkData *, link, &tgpil->selected_strokes) { + bGPDstroke *gps_from = link->data; + if (!BLI_ghash_haskey(tgpil->pair_strokes, gps_from)) { + continue; + } + bGPDstroke *gps_to = (bGPDstroke *)BLI_ghash_lookup(tgpil->pair_strokes, gps_from); /* If destination stroke is smaller, resize new_stroke to size of gps_to stroke. */ if (gps_from->totpoints > gps_to->totpoints) { @@ -658,6 +666,9 @@ static void gpencil_interpolate_exit(bContext *C, wmOperator *op) MEM_SAFE_FREE(tgpil->nextFrame); MEM_SAFE_FREE(tgpil->interFrame); + /* Free list of strokes. */ + BLI_freelistN(&tgpil->selected_strokes); + /* Free Hash tablets. */ if (tgpil->used_strokes != NULL) { BLI_ghash_free(tgpil->used_strokes, NULL, NULL); @@ -1292,9 +1303,9 @@ static int gpencil_interpolate_seq_exec(bContext *C, wmOperator *op) bGPDframe *nextFrame = BKE_gpencil_frame_duplicate(gpf_next, true); /* Create a table with source and target pair of strokes. */ + ListBase selected_strokes = {NULL}; GHash *used_strokes = BLI_ghash_ptr_new(__func__); GHash *pair_strokes = BLI_ghash_ptr_new(__func__); - LISTBASE_FOREACH (bGPDstroke *, gps_from, &prevFrame->strokes) { bGPDstroke *gps_to = NULL; /* Only selected. */ @@ -1342,7 +1353,9 @@ static int gpencil_interpolate_seq_exec(bContext *C, wmOperator *op) } } - /* Insert the pair entry in the hash table. */ + /* Insert the pair entry in the hash table and in the list of strokes to keep same order. + */ + BLI_addtail(&selected_strokes, BLI_genericNodeN(gps_from)); BLI_ghash_insert(pair_strokes, gps_from, gps_to); } @@ -1369,11 +1382,12 @@ static int gpencil_interpolate_seq_exec(bContext *C, wmOperator *op) } /* Apply the factor to all pair of strokes. */ - GHashIterator gh_iter; - GHASH_ITER (gh_iter, pair_strokes) { - bGPDstroke *gps_from = (bGPDstroke *)BLI_ghashIterator_getKey(&gh_iter); - bGPDstroke *gps_to = (bGPDstroke *)BLI_ghashIterator_getValue(&gh_iter); - + LISTBASE_FOREACH (LinkData *, link, &selected_strokes) { + bGPDstroke *gps_from = link->data; + if (!BLI_ghash_haskey(pair_strokes, gps_from)) { + continue; + } + bGPDstroke *gps_to = (bGPDstroke *)BLI_ghash_lookup(pair_strokes, gps_from); /* Create new stroke. */ bGPDstroke *new_stroke = BKE_gpencil_stroke_duplicate(gps_from, true, true); new_stroke->flag |= GP_STROKE_TAG; @@ -1394,6 +1408,8 @@ static int gpencil_interpolate_seq_exec(bContext *C, wmOperator *op) } } + BLI_freelistN(&selected_strokes); + /* Free Hash tablets. */ if (used_strokes != NULL) { BLI_ghash_free(used_strokes, NULL, NULL); diff --git a/source/blender/editors/gpencil/gpencil_paint.c b/source/blender/editors/gpencil/gpencil_paint.c index 1217a3a7e8f..d072d8a35df 100644 --- a/source/blender/editors/gpencil/gpencil_paint.c +++ b/source/blender/editors/gpencil/gpencil_paint.c @@ -1722,7 +1722,7 @@ static void gpencil_stroke_doeraser(tGPsdata *p) if ((gp_settings != NULL) && (gp_settings->flag & GP_BRUSH_OCCLUDE_ERASER)) { View3D *v3d = p->area->spacedata.first; view3d_region_operator_needs_opengl(p->win, p->region); - ED_view3d_autodist_init(p->depsgraph, p->region, v3d, 0); + ED_view3d_depth_override(p->depsgraph, p->region, v3d, NULL, V3D_DEPTH_NO_GPENCIL, false); } } @@ -2305,8 +2305,14 @@ static void gpencil_paint_strokeend(tGPsdata *p) /* need to restore the original projection settings before packing up */ view3d_region_operator_needs_opengl(p->win, p->region); - ED_view3d_autodist_init( - p->depsgraph, p->region, v3d, (ts->gpencil_v3d_align & GP_PROJECT_DEPTH_STROKE) ? 1 : 0); + ED_view3d_depth_override(p->depsgraph, + p->region, + v3d, + NULL, + (ts->gpencil_v3d_align & GP_PROJECT_DEPTH_STROKE) ? + V3D_DEPTH_GPENCIL_ONLY : + V3D_DEPTH_NO_GPENCIL, + false); } /* check if doing eraser or not */ @@ -3691,7 +3697,7 @@ static int gpencil_draw_modal(bContext *C, wmOperator *op, const wmEvent *event) /* Exit painting mode (and/or end current stroke). * */ - if (ELEM(event->type, EVT_RETKEY, EVT_PADENTER, EVT_ESCKEY, EVT_SPACEKEY, EVT_EKEY)) { + if (ELEM(event->type, EVT_RETKEY, EVT_PADENTER, EVT_ESCKEY, EVT_SPACEKEY)) { p->status = GP_STATUS_DONE; estate = OPERATOR_FINISHED; diff --git a/source/blender/editors/gpencil/gpencil_primitive.c b/source/blender/editors/gpencil/gpencil_primitive.c index dfff0ce639e..3d20e32ed49 100644 --- a/source/blender/editors/gpencil/gpencil_primitive.c +++ b/source/blender/editors/gpencil/gpencil_primitive.c @@ -785,10 +785,14 @@ static void gpencil_primitive_update_strokes(bContext *C, tGPDprimitive *tgpi) /* need to restore the original projection settings before packing up */ view3d_region_operator_needs_opengl(tgpi->win, tgpi->region); - ED_view3d_autodist_init(tgpi->depsgraph, - tgpi->region, - tgpi->v3d, - (ts->gpencil_v3d_align & GP_PROJECT_DEPTH_STROKE) ? 1 : 0); + ED_view3d_depth_override(tgpi->depsgraph, + tgpi->region, + tgpi->v3d, + NULL, + (ts->gpencil_v3d_align & GP_PROJECT_DEPTH_STROKE) ? + V3D_DEPTH_GPENCIL_ONLY : + V3D_DEPTH_NO_GPENCIL, + false); depth_arr = MEM_mallocN(sizeof(float) * gps->totpoints, "depth_points"); tGPspoint *ptc = &points2D[0]; diff --git a/source/blender/editors/gpencil/gpencil_trace_utils.c b/source/blender/editors/gpencil/gpencil_trace_utils.c index ada777d43f3..482f7015720 100644 --- a/source/blender/editors/gpencil/gpencil_trace_utils.c +++ b/source/blender/editors/gpencil/gpencil_trace_utils.c @@ -308,9 +308,16 @@ void ED_gpencil_trace_data_to_strokes(Main *bmain, if (gps->totpoints == 0) { add_point(gps, scalef, offset, c[n - 1][2].x, c[n - 1][2].y); } + else { + add_point(gps, scalef, offset, last[0], last[1]); + } + add_point(gps, scalef, offset, c[i][1].x, c[i][1].y); add_point(gps, scalef, offset, c[i][2].x, c[i][2].y); + + last[0] = c[i][2].x; + last[1] = c[i][2].y; break; } case POTRACE_CURVETO: { diff --git a/source/blender/editors/gpencil/gpencil_utils.c b/source/blender/editors/gpencil/gpencil_utils.c index 5c041134a74..8d42024a518 100644 --- a/source/blender/editors/gpencil/gpencil_utils.c +++ b/source/blender/editors/gpencil/gpencil_utils.c @@ -596,6 +596,21 @@ bool ED_gpencil_stroke_material_editable(Object *ob, const bGPDlayer *gpl, const return true; } +/* Check whether given stroke is visible for the current material. */ +bool ED_gpencil_stroke_material_visible(Object *ob, const bGPDstroke *gps) +{ + /* check if the color is editable */ + MaterialGPencilStyle *gp_style = BKE_gpencil_material_settings(ob, gps->mat_nr + 1); + + if (gp_style != NULL) { + if (gp_style->flag & GP_MATERIAL_HIDE) { + return false; + } + } + + return true; +} + /* ******************************************************** */ /* Space Conversion */ @@ -633,7 +648,7 @@ void gpencil_point_conversion_init(bContext *C, GP_SpaceConversion *r_gsc) view3d_operator_needs_opengl(C); view3d_region_operator_needs_opengl(win, region); - ED_view3d_autodist_init(depsgraph, region, v3d, 0); + ED_view3d_depth_override(depsgraph, region, v3d, NULL, V3D_DEPTH_NO_GPENCIL, false); /* for camera view set the subrect */ if (rv3d->persp == RV3D_CAMOB) { diff --git a/source/blender/editors/include/ED_gizmo_library.h b/source/blender/editors/include/ED_gizmo_library.h index dfc8cfea5ce..1c795896f86 100644 --- a/source/blender/editors/include/ED_gizmo_library.h +++ b/source/blender/editors/include/ED_gizmo_library.h @@ -271,9 +271,9 @@ short ED_gizmotypes_snap_3d_update(struct wmGizmo *gz, const struct ARegion *region, const struct View3D *v3d, const struct wmWindowManager *wm, - const float mval_fl[2], - float r_loc[3], - float r_nor[3]); + const float mval_fl[2]); +void ED_gizmotypes_snap_3d_data_get( + struct wmGizmo *gz, float r_loc[3], float r_nor[3], int r_elem_index[3], int *r_snap_elem); #ifdef __cplusplus } diff --git a/source/blender/editors/include/ED_gpencil.h b/source/blender/editors/include/ED_gpencil.h index f3b5abb1072..e9ac21f60cf 100644 --- a/source/blender/editors/include/ED_gpencil.h +++ b/source/blender/editors/include/ED_gpencil.h @@ -150,6 +150,7 @@ bool ED_gpencil_stroke_can_use(const struct bContext *C, const struct bGPDstroke bool ED_gpencil_stroke_material_editable(struct Object *ob, const struct bGPDlayer *gpl, const struct bGPDstroke *gps); +bool ED_gpencil_stroke_material_visible(struct Object *ob, const struct bGPDstroke *gps); /* ----------- Grease Pencil Operators ----------------- */ diff --git a/source/blender/editors/include/ED_mesh.h b/source/blender/editors/include/ED_mesh.h index 85e7a491feb..b8e9f6e8871 100644 --- a/source/blender/editors/include/ED_mesh.h +++ b/source/blender/editors/include/ED_mesh.h @@ -164,16 +164,16 @@ void EDBM_select_mirrored(struct BMEditMesh *em, int *r_totfail); struct BMVert *EDBM_vert_find_nearest_ex(struct ViewContext *vc, - float *r_dist, + float *dist_px_manhattan_p, const bool use_select_bias, bool use_cycle, struct Base **bases, uint bases_len, uint *r_base_index); -struct BMVert *EDBM_vert_find_nearest(struct ViewContext *vc, float *r_dist); +struct BMVert *EDBM_vert_find_nearest(struct ViewContext *vc, float *dist_px_manhattan_p); struct BMEdge *EDBM_edge_find_nearest_ex(struct ViewContext *vc, - float *r_dist, + float *dist_px_manhattan, float *r_dist_center, const bool use_select_bias, bool use_cycle, @@ -181,18 +181,19 @@ struct BMEdge *EDBM_edge_find_nearest_ex(struct ViewContext *vc, struct Base **bases, uint bases_len, uint *r_base_index); -struct BMEdge *EDBM_edge_find_nearest(struct ViewContext *vc, float *r_dist); +struct BMEdge *EDBM_edge_find_nearest(struct ViewContext *vc, float *dist_px_manhattan_p); struct BMFace *EDBM_face_find_nearest_ex(struct ViewContext *vc, - float *r_dist, + float *dist_px_manhattan, float *r_dist_center, + const bool use_zbuf_single_px, const bool use_select_bias, bool use_cycle, struct BMFace **r_efa_zbuf, struct Base **bases, uint bases_len, uint *r_base_index); -struct BMFace *EDBM_face_find_nearest(struct ViewContext *vc, float *r_dist); +struct BMFace *EDBM_face_find_nearest(struct ViewContext *vc, float *dist_px_manhattan_p); bool EDBM_unified_findnearest(struct ViewContext *vc, struct Base **bases, diff --git a/source/blender/editors/include/ED_object.h b/source/blender/editors/include/ED_object.h index 0767ce21382..b5a94bc7798 100644 --- a/source/blender/editors/include/ED_object.h +++ b/source/blender/editors/include/ED_object.h @@ -178,6 +178,9 @@ void ED_object_base_active_refresh(struct Main *bmain, struct Scene *scene, struct ViewLayer *view_layer); void ED_object_base_free_and_unlink(struct Main *bmain, struct Scene *scene, struct Object *ob); +void ED_object_base_free_and_unlink_no_indirect_check(struct Main *bmain, + struct Scene *scene, + struct Object *ob); bool ED_object_base_deselect_all_ex(struct ViewLayer *view_layer, struct View3D *v3d, int action, diff --git a/source/blender/editors/include/ED_view3d.h b/source/blender/editors/include/ED_view3d.h index 3b8e062ffec..d00d03abae7 100644 --- a/source/blender/editors/include/ED_view3d.h +++ b/source/blender/editors/include/ED_view3d.h @@ -144,7 +144,17 @@ bool ED_view3d_camera_to_view_selected(struct Main *bmain, void ED_view3d_lastview_store(struct RegionView3D *rv3d); /* Depth buffer */ -void ED_view3d_depth_update(struct ARegion *region); +typedef enum { + V3D_DEPTH_NO_GPENCIL = 0, + V3D_DEPTH_GPENCIL_ONLY, + V3D_DEPTH_OBJECT_ONLY, +} eV3DDepthOverrideMode; +void ED_view3d_depth_override(struct Depsgraph *depsgraph, + struct ARegion *region, + struct View3D *v3d, + struct Object *obact, + eV3DDepthOverrideMode mode, + bool update_cache); float ED_view3d_depth_read_cached(const struct ViewContext *vc, const int mval[2]); bool ED_view3d_depth_read_cached_normal(const ViewContext *vc, const int mval[2], @@ -481,11 +491,6 @@ bool ED_view3d_autodist(struct Depsgraph *depsgraph, const bool alphaoverride, const float fallback_depth_pt[3]); -/* Only draw so #ED_view3d_autodist_simple can be called many times after. */ -void ED_view3d_autodist_init(struct Depsgraph *depsgraph, - struct ARegion *region, - struct View3D *v3d, - int mode); bool ED_view3d_autodist_simple(struct ARegion *region, const int mval[2], float mouse_worldloc[3], diff --git a/source/blender/editors/interface/interface.c b/source/blender/editors/interface/interface.c index 279239fcc65..6caee42ac33 100644 --- a/source/blender/editors/interface/interface.c +++ b/source/blender/editors/interface/interface.c @@ -1038,7 +1038,6 @@ static bool ui_but_is_rna_undo(const uiBut *but) if (ID_CHECK_UNDO(id) == false) { return false; } - return true; } if (but->rnapoin.type && !RNA_struct_undo_check(but->rnapoin.type)) { return false; @@ -1817,9 +1816,9 @@ static void ui_but_validate(const uiBut *but) #endif /** - * Check if the operator \a ot poll is successfull with the context given by \a but (optionally). + * Check if the operator \a ot poll is successful with the context given by \a but (optionally). * \param but: The button that might store context. Can be NULL for convenience (e.g. if there is - * no button to take context from, but we still want to poll the operator). + * no button to take context from, but we still want to poll the operator). */ bool ui_but_context_poll_operator(bContext *C, wmOperatorType *ot, const uiBut *but) { diff --git a/source/blender/editors/interface/interface_eyedropper_color.c b/source/blender/editors/interface/interface_eyedropper_color.c index 4ae6f66281f..d5fb0e4e744 100644 --- a/source/blender/editors/interface/interface_eyedropper_color.c +++ b/source/blender/editors/interface/interface_eyedropper_color.c @@ -116,14 +116,11 @@ static bool eyedropper_init(bContext *C, wmOperator *op) float col[4]; RNA_property_float_get_array(&eye->ptr, eye->prop, col); - if (ELEM(eye->ptr.type, &RNA_CompositorNodeCryptomatteV2, &RNA_CompositorNodeCryptomatte)) { + if (eye->ptr.type == &RNA_CompositorNodeCryptomatteV2) { eye->crypto_node = (bNode *)eye->ptr.data; eye->cryptomatte_session = ntreeCompositCryptomatteSession(eye->crypto_node); eye->draw_handle_sample_text = WM_draw_cb_activate(CTX_wm_window(C), eyedropper_draw_cb, eye); } - else { - eye->crypto_node = NULL; - } if (prop_subtype != PROP_COLOR) { Scene *scene = CTX_data_scene(C); diff --git a/source/blender/editors/interface/interface_panel.c b/source/blender/editors/interface/interface_panel.c index 7343417137a..8922babc9b8 100644 --- a/source/blender/editors/interface/interface_panel.c +++ b/source/blender/editors/interface/interface_panel.c @@ -2529,9 +2529,8 @@ PointerRNA *UI_region_panel_custom_data_under_cursor(const bContext *C, const wm { ARegion *region = CTX_wm_region(C); - Panel *panel = NULL; LISTBASE_FOREACH (uiBlock *, block, ®ion->uiblocks) { - panel = block->panel; + Panel *panel = block->panel; if (panel == NULL) { continue; } @@ -2541,15 +2540,11 @@ PointerRNA *UI_region_panel_custom_data_under_cursor(const bContext *C, const wm ui_window_to_block(region, block, &mx, &my); const int mouse_state = ui_panel_mouse_state_get(block, panel, mx, my); if (ELEM(mouse_state, PANEL_MOUSE_INSIDE_CONTENT, PANEL_MOUSE_INSIDE_HEADER)) { - break; + return UI_panel_custom_data_get(panel); } } - if (panel == NULL) { - return NULL; - } - - return UI_panel_custom_data_get(panel); + return NULL; } /** \} */ diff --git a/source/blender/editors/io/CMakeLists.txt b/source/blender/editors/io/CMakeLists.txt index e7effd05d34..44b5f85050f 100644 --- a/source/blender/editors/io/CMakeLists.txt +++ b/source/blender/editors/io/CMakeLists.txt @@ -24,6 +24,7 @@ set(INC ../../depsgraph ../../io/alembic ../../io/collada + ../../io/gpencil ../../io/usd ../../makesdna ../../makesrna @@ -39,12 +40,16 @@ set(SRC io_alembic.c io_cache.c io_collada.c + io_gpencil_export.c + io_gpencil_import.c + io_gpencil_utils.c io_ops.c io_usd.c io_alembic.h io_cache.h io_collada.h + io_gpencil.h io_ops.h io_usd.h ) @@ -79,4 +84,14 @@ if(WITH_INTERNATIONAL) add_definitions(-DWITH_INTERNATIONAL) endif() +if(WITH_PUGIXML) + add_definitions(-DWITH_PUGIXML) +endif() + +if(WITH_HARU) + add_definitions(-DWITH_HARU) +endif() + +list(APPEND LIB bf_gpencil) + blender_add_lib(bf_editor_io "${SRC}" "${INC}" "${INC_SYS}" "${LIB}") diff --git a/source/blender/editors/io/io_gpencil.h b/source/blender/editors/io/io_gpencil.h new file mode 100644 index 00000000000..98cb8b13310 --- /dev/null +++ b/source/blender/editors/io/io_gpencil.h @@ -0,0 +1,45 @@ +/* + * 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) 2020 Blender Foundation. + * All rights reserved. + */ + +#ifndef __IO_GPENCIL_H__ +#define __IO_GPENCIL_H__ + +/** \file + * \ingroup editor/io + */ + +struct ARegion; +struct bContext; +struct View3D; +struct wmOperator; +struct wmOperatorType; + +void WM_OT_gpencil_import_svg(struct wmOperatorType *ot); + +#ifdef WITH_PUGIXML +void WM_OT_gpencil_export_svg(struct wmOperatorType *ot); +#endif +#ifdef WITH_HARU +void WM_OT_gpencil_export_pdf(struct wmOperatorType *ot); +#endif + +struct ARegion *get_invoke_region(struct bContext *C); +struct View3D *get_invoke_view3d(struct bContext *C); + +#endif /* __IO_GPENCIL_H__ */ diff --git a/source/blender/editors/io/io_gpencil_export.c b/source/blender/editors/io/io_gpencil_export.c new file mode 100644 index 00000000000..10e4e598bad --- /dev/null +++ b/source/blender/editors/io/io_gpencil_export.c @@ -0,0 +1,432 @@ +/* + * 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) 2020 Blender Foundation. + * All rights reserved. + */ + +/** \file + * \ingroup editor/io + */ + +#include "BLI_path_util.h" +#include "BLI_string.h" + +#include "DNA_gpencil_types.h" +#include "DNA_space_types.h" + +#include "BKE_gpencil.h" +#include "BKE_main.h" +#include "BKE_report.h" +#include "BKE_screen.h" + +#include "BLT_translation.h" + +#include "RNA_access.h" +#include "RNA_define.h" + +#include "UI_interface.h" +#include "UI_resources.h" + +#include "WM_api.h" +#include "WM_types.h" + +#include "DEG_depsgraph.h" +#include "DEG_depsgraph_query.h" + +#include "io_gpencil.h" + +#include "gpencil_io.h" + +#if defined(WITH_PUGIXML) || defined(WITH_HARU) +/* Definition of enum elements to export. */ +/* Common props for exporting. */ +static void gpencil_export_common_props_definition(wmOperatorType *ot) +{ + static const EnumPropertyItem select_items[] = { + {GP_EXPORT_ACTIVE, "ACTIVE", 0, "Active", "Include only the active object"}, + {GP_EXPORT_SELECTED, "SELECTED", 0, "Selected", "Include selected objects"}, + {GP_EXPORT_VISIBLE, "VISIBLE", 0, "Visible", "Include all visible objects"}, + {0, NULL, 0, NULL, NULL}, + }; + + RNA_def_boolean(ot->srna, "use_fill", true, "Fill", "Export strokes with fill enabled"); + RNA_def_enum(ot->srna, + "selected_object_type", + select_items, + GP_EXPORT_SELECTED, + "Object", + "Which objects to include in the export"); + RNA_def_float(ot->srna, + "stroke_sample", + 0.0f, + 0.0f, + 100.0f, + "Sampling", + "Precision of stroke sampling. Low values mean a more precise result, and zero " + "disables sampling", + 0.0f, + 100.0f); + RNA_def_boolean(ot->srna, + "use_normalized_thickness", + false, + "Normalize", + "Export strokes with constant thickness"); +} + +static void set_export_filepath(bContext *C, wmOperator *op, const char *extension) +{ + if (!RNA_struct_property_is_set(op->ptr, "filepath")) { + Main *bmain = CTX_data_main(C); + char filepath[FILE_MAX]; + + if (BKE_main_blendfile_path(bmain)[0] == '\0') { + BLI_strncpy(filepath, "untitled", sizeof(filepath)); + } + else { + BLI_strncpy(filepath, BKE_main_blendfile_path(bmain), sizeof(filepath)); + } + + BLI_path_extension_replace(filepath, sizeof(filepath), extension); + RNA_string_set(op->ptr, "filepath", filepath); + } +} +#endif + +/* <-------- SVG single frame export. --------> */ +#ifdef WITH_PUGIXML +static bool wm_gpencil_export_svg_common_check(bContext *UNUSED(C), wmOperator *op) +{ + char filepath[FILE_MAX]; + RNA_string_get(op->ptr, "filepath", filepath); + + if (!BLI_path_extension_check(filepath, ".svg")) { + BLI_path_extension_ensure(filepath, FILE_MAX, ".svg"); + RNA_string_set(op->ptr, "filepath", filepath); + return true; + } + + return false; +} + +static int wm_gpencil_export_svg_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) +{ + set_export_filepath(C, op, ".svg"); + + WM_event_add_fileselect(C, op); + + return OPERATOR_RUNNING_MODAL; +} + +static int wm_gpencil_export_svg_exec(bContext *C, wmOperator *op) +{ + Scene *scene = CTX_data_scene(C); + Object *ob = CTX_data_active_object(C); + + if (!RNA_struct_property_is_set(op->ptr, "filepath")) { + BKE_report(op->reports, RPT_ERROR, "No filename given"); + return OPERATOR_CANCELLED; + } + + ARegion *region = get_invoke_region(C); + if (region == NULL) { + BKE_report(op->reports, RPT_ERROR, "Unable to find valid 3D View area"); + return OPERATOR_CANCELLED; + } + View3D *v3d = get_invoke_view3d(C); + + char filename[FILE_MAX]; + RNA_string_get(op->ptr, "filepath", filename); + + const bool use_fill = RNA_boolean_get(op->ptr, "use_fill"); + const bool use_norm_thickness = RNA_boolean_get(op->ptr, "use_normalized_thickness"); + const eGpencilExportSelect select_mode = RNA_enum_get(op->ptr, "selected_object_type"); + + const bool use_clip_camera = RNA_boolean_get(op->ptr, "use_clip_camera"); + + /* Set flags. */ + int flag = 0; + SET_FLAG_FROM_TEST(flag, use_fill, GP_EXPORT_FILL); + SET_FLAG_FROM_TEST(flag, use_norm_thickness, GP_EXPORT_NORM_THICKNESS); + SET_FLAG_FROM_TEST(flag, use_clip_camera, GP_EXPORT_CLIP_CAMERA); + + GpencilIOParams params = {.C = C, + .region = region, + .v3d = v3d, + .ob = ob, + .mode = GP_EXPORT_TO_SVG, + .frame_start = CFRA, + .frame_end = CFRA, + .frame_cur = CFRA, + .flag = flag, + .scale = 1.0f, + .select_mode = select_mode, + .frame_mode = GP_EXPORT_FRAME_ACTIVE, + .stroke_sample = RNA_float_get(op->ptr, "stroke_sample"), + .resolution = 1.0f}; + + /* Do export. */ + WM_cursor_wait(true); + const bool done = gpencil_io_export(filename, ¶ms); + WM_cursor_wait(false); + + if (!done) { + BKE_report(op->reports, RPT_WARNING, "Unable to export SVG"); + } + + return OPERATOR_FINISHED; +} + +static void ui_gpencil_export_svg_settings(uiLayout *layout, PointerRNA *imfptr) +{ + uiLayout *box, *row; + + uiLayoutSetPropSep(layout, true); + uiLayoutSetPropDecorate(layout, false); + + box = uiLayoutBox(layout); + + row = uiLayoutRow(box, false); + uiItemL(row, IFACE_("Scene Options"), ICON_NONE); + + row = uiLayoutRow(box, false); + uiItemR(row, imfptr, "selected_object_type", 0, NULL, ICON_NONE); + + box = uiLayoutBox(layout); + row = uiLayoutRow(box, false); + uiItemL(row, IFACE_("Export Options"), ICON_NONE); + + uiLayout *col = uiLayoutColumn(box, false); + uiItemR(col, imfptr, "stroke_sample", 0, NULL, ICON_NONE); + uiItemR(col, imfptr, "use_fill", 0, NULL, ICON_NONE); + uiItemR(col, imfptr, "use_normalized_thickness", 0, NULL, ICON_NONE); + uiItemR(col, imfptr, "use_clip_camera", 0, NULL, ICON_NONE); +} + +static void wm_gpencil_export_svg_draw(bContext *UNUSED(C), wmOperator *op) +{ + PointerRNA ptr; + + RNA_pointer_create(NULL, op->type->srna, op->properties, &ptr); + + ui_gpencil_export_svg_settings(op->layout, &ptr); +} + +static bool wm_gpencil_export_svg_poll(bContext *C) +{ + if ((CTX_wm_window(C) == NULL) || (CTX_data_mode_enum(C) != CTX_MODE_OBJECT)) { + return false; + } + + return true; +} + +void WM_OT_gpencil_export_svg(wmOperatorType *ot) +{ + ot->name = "Export to SVG"; + ot->description = "Export grease pencil to SVG"; + ot->idname = "WM_OT_gpencil_export_svg"; + + ot->invoke = wm_gpencil_export_svg_invoke; + ot->exec = wm_gpencil_export_svg_exec; + ot->poll = wm_gpencil_export_svg_poll; + ot->ui = wm_gpencil_export_svg_draw; + ot->check = wm_gpencil_export_svg_common_check; + + WM_operator_properties_filesel(ot, + FILE_TYPE_OBJECT_IO, + FILE_BLENDER, + FILE_SAVE, + WM_FILESEL_FILEPATH | WM_FILESEL_SHOW_PROPS, + FILE_DEFAULTDISPLAY, + FILE_SORT_ALPHA); + + gpencil_export_common_props_definition(ot); + + RNA_def_boolean(ot->srna, + "use_clip_camera", + false, + "Clip Camera", + "Clip drawings to camera size when export in camera view"); +} +#endif + +/* <-------- PDF single frame export. --------> */ +#ifdef WITH_HARU +static bool wm_gpencil_export_pdf_common_check(bContext *UNUSED(C), wmOperator *op) +{ + + char filepath[FILE_MAX]; + RNA_string_get(op->ptr, "filepath", filepath); + + if (!BLI_path_extension_check(filepath, ".pdf")) { + BLI_path_extension_ensure(filepath, FILE_MAX, ".pdf"); + RNA_string_set(op->ptr, "filepath", filepath); + return true; + } + + return false; +} + +static int wm_gpencil_export_pdf_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) +{ + set_export_filepath(C, op, ".pdf"); + + WM_event_add_fileselect(C, op); + + return OPERATOR_RUNNING_MODAL; +} + +static int wm_gpencil_export_pdf_exec(bContext *C, wmOperator *op) +{ + Scene *scene = CTX_data_scene(C); + Object *ob = CTX_data_active_object(C); + + if (!RNA_struct_property_is_set(op->ptr, "filepath")) { + BKE_report(op->reports, RPT_ERROR, "No filename given"); + return OPERATOR_CANCELLED; + } + + ARegion *region = get_invoke_region(C); + if (region == NULL) { + BKE_report(op->reports, RPT_ERROR, "Unable to find valid 3D View area"); + return OPERATOR_CANCELLED; + } + View3D *v3d = get_invoke_view3d(C); + + char filename[FILE_MAX]; + RNA_string_get(op->ptr, "filepath", filename); + + const bool use_fill = RNA_boolean_get(op->ptr, "use_fill"); + const bool use_norm_thickness = RNA_boolean_get(op->ptr, "use_normalized_thickness"); + const short select_mode = RNA_enum_get(op->ptr, "selected_object_type"); + const short frame_mode = RNA_enum_get(op->ptr, "frame_mode"); + + /* Set flags. */ + int flag = 0; + SET_FLAG_FROM_TEST(flag, use_fill, GP_EXPORT_FILL); + SET_FLAG_FROM_TEST(flag, use_norm_thickness, GP_EXPORT_NORM_THICKNESS); + + GpencilIOParams params = {.C = C, + .region = region, + .v3d = v3d, + .ob = ob, + .mode = GP_EXPORT_TO_PDF, + .frame_start = SFRA, + .frame_end = EFRA, + .frame_cur = CFRA, + .flag = flag, + .scale = 1.0f, + .select_mode = select_mode, + .frame_mode = frame_mode, + .stroke_sample = RNA_float_get(op->ptr, "stroke_sample"), + .resolution = 1.0f}; + + /* Do export. */ + WM_cursor_wait(true); + const bool done = gpencil_io_export(filename, ¶ms); + WM_cursor_wait(false); + + if (!done) { + BKE_report(op->reports, RPT_WARNING, "Unable to export PDF"); + } + + return OPERATOR_FINISHED; +} + +static void ui_gpencil_export_pdf_settings(uiLayout *layout, PointerRNA *imfptr) +{ + uiLayout *box, *row, *col, *sub; + + uiLayoutSetPropSep(layout, true); + uiLayoutSetPropDecorate(layout, false); + + box = uiLayoutBox(layout); + + row = uiLayoutRow(box, false); + uiItemL(row, IFACE_("Scene Options"), ICON_NONE); + + row = uiLayoutRow(box, false); + uiItemR(row, imfptr, "selected_object_type", 0, NULL, ICON_NONE); + + box = uiLayoutBox(layout); + row = uiLayoutRow(box, false); + uiItemL(row, IFACE_("Export Options"), ICON_NONE); + + col = uiLayoutColumn(box, false); + sub = uiLayoutColumn(col, true); + uiItemR(sub, imfptr, "frame_mode", 0, IFACE_("Frame"), ICON_NONE); + + uiLayoutSetPropSep(box, true); + + sub = uiLayoutColumn(col, true); + uiItemR(sub, imfptr, "stroke_sample", 0, NULL, ICON_NONE); + uiItemR(sub, imfptr, "use_fill", 0, NULL, ICON_NONE); + uiItemR(sub, imfptr, "use_normalized_thickness", 0, NULL, ICON_NONE); +} + +static void wm_gpencil_export_pdf_draw(bContext *UNUSED(C), wmOperator *op) +{ + PointerRNA ptr; + + RNA_pointer_create(NULL, op->type->srna, op->properties, &ptr); + + ui_gpencil_export_pdf_settings(op->layout, &ptr); +} + +static bool wm_gpencil_export_pdf_poll(bContext *C) +{ + if ((CTX_wm_window(C) == NULL) || (CTX_data_mode_enum(C) != CTX_MODE_OBJECT)) { + return false; + } + + return true; +} + +void WM_OT_gpencil_export_pdf(wmOperatorType *ot) +{ + ot->name = "Export to PDF"; + ot->description = "Export grease pencil to PDF"; + ot->idname = "WM_OT_gpencil_export_pdf"; + + ot->invoke = wm_gpencil_export_pdf_invoke; + ot->exec = wm_gpencil_export_pdf_exec; + ot->poll = wm_gpencil_export_pdf_poll; + ot->ui = wm_gpencil_export_pdf_draw; + ot->check = wm_gpencil_export_pdf_common_check; + + WM_operator_properties_filesel(ot, + FILE_TYPE_OBJECT_IO, + FILE_BLENDER, + FILE_SAVE, + WM_FILESEL_FILEPATH | WM_FILESEL_SHOW_PROPS, + FILE_DEFAULTDISPLAY, + FILE_SORT_ALPHA); + + static const EnumPropertyItem gpencil_export_frame_items[] = { + {GP_EXPORT_FRAME_ACTIVE, "ACTIVE", 0, "Active", "Include only active frame"}, + {GP_EXPORT_FRAME_SELECTED, "SELECTED", 0, "Selected", "Include selected frames"}, + {0, NULL, 0, NULL, NULL}, + }; + + gpencil_export_common_props_definition(ot); + ot->prop = RNA_def_enum(ot->srna, + "frame_mode", + gpencil_export_frame_items, + GP_EXPORT_ACTIVE, + "Frames", + "Which frames to include in the export"); +} +#endif diff --git a/source/blender/editors/io/io_gpencil_import.c b/source/blender/editors/io/io_gpencil_import.c new file mode 100644 index 00000000000..9768da85940 --- /dev/null +++ b/source/blender/editors/io/io_gpencil_import.c @@ -0,0 +1,195 @@ +/* + * 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) 2020 Blender Foundation. + * All rights reserved. + */ + +/** \file + * \ingroup editor/io + */ + +#include "BLI_path_util.h" + +#include "DNA_gpencil_types.h" +#include "DNA_space_types.h" + +#include "BKE_context.h" +#include "BKE_gpencil.h" +#include "BKE_report.h" + +#include "BLT_translation.h" + +#include "RNA_access.h" +#include "RNA_define.h" + +#include "UI_interface.h" +#include "UI_resources.h" + +#include "WM_api.h" +#include "WM_types.h" + +#include "DEG_depsgraph.h" +#include "DEG_depsgraph_query.h" + +#include "ED_gpencil.h" + +#include "io_gpencil.h" + +#include "gpencil_io.h" + +/* <-------- SVG single frame import. --------> */ +static bool wm_gpencil_import_svg_common_check(bContext *UNUSED(C), wmOperator *op) +{ + + char filepath[FILE_MAX]; + RNA_string_get(op->ptr, "filepath", filepath); + + if (!BLI_path_extension_check(filepath, ".svg")) { + BLI_path_extension_ensure(filepath, FILE_MAX, ".svg"); + RNA_string_set(op->ptr, "filepath", filepath); + return true; + } + + return false; +} + +static int wm_gpencil_import_svg_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) +{ + WM_event_add_fileselect(C, op); + + return OPERATOR_RUNNING_MODAL; +} + +static int wm_gpencil_import_svg_exec(bContext *C, wmOperator *op) +{ + Scene *scene = CTX_data_scene(C); + + if (!RNA_struct_property_is_set(op->ptr, "filepath")) { + BKE_report(op->reports, RPT_ERROR, "No filename given"); + return OPERATOR_CANCELLED; + } + + ARegion *region = get_invoke_region(C); + if (region == NULL) { + BKE_report(op->reports, RPT_ERROR, "Unable to find valid 3D View area"); + return OPERATOR_CANCELLED; + } + View3D *v3d = get_invoke_view3d(C); + + char filename[FILE_MAX]; + RNA_string_get(op->ptr, "filepath", filename); + + /* Set flags. */ + int flag = 0; + + const int resolution = RNA_int_get(op->ptr, "resolution"); + const float scale = RNA_float_get(op->ptr, "scale"); + + GpencilIOParams params = { + .C = C, + .region = region, + .v3d = v3d, + .ob = NULL, + .mode = GP_IMPORT_FROM_SVG, + .frame_start = CFRA, + .frame_end = CFRA, + .frame_cur = CFRA, + .flag = flag, + .scale = scale, + .select_mode = 0, + .frame_mode = 0, + .stroke_sample = 0.0f, + .resolution = resolution, + }; + + /* Do Import. */ + WM_cursor_wait(1); + const bool done = gpencil_io_import(filename, ¶ms); + WM_cursor_wait(0); + + if (!done) { + BKE_report(op->reports, RPT_WARNING, "Unable to import SVG"); + } + + return OPERATOR_FINISHED; +} + +static void ui_gpencil_import_svg_settings(uiLayout *layout, PointerRNA *imfptr) +{ + uiLayoutSetPropSep(layout, true); + uiLayoutSetPropDecorate(layout, false); + uiLayout *col = uiLayoutColumn(layout, false); + uiItemR(col, imfptr, "resolution", 0, NULL, ICON_NONE); + uiItemR(col, imfptr, "scale", 0, NULL, ICON_NONE); +} + +static void wm_gpencil_import_svg_draw(bContext *UNUSED(C), wmOperator *op) +{ + PointerRNA ptr; + RNA_pointer_create(NULL, op->type->srna, op->properties, &ptr); + + ui_gpencil_import_svg_settings(op->layout, &ptr); +} + +static bool wm_gpencil_import_svg_poll(bContext *C) +{ + if ((CTX_wm_window(C) == NULL) || (CTX_data_mode_enum(C) != CTX_MODE_OBJECT)) { + return false; + } + + return true; +} + +void WM_OT_gpencil_import_svg(wmOperatorType *ot) +{ + ot->name = "Import SVG"; + ot->description = "Import SVG into grease pencil"; + ot->idname = "WM_OT_gpencil_import_svg"; + + ot->invoke = wm_gpencil_import_svg_invoke; + ot->exec = wm_gpencil_import_svg_exec; + ot->poll = wm_gpencil_import_svg_poll; + ot->ui = wm_gpencil_import_svg_draw; + ot->check = wm_gpencil_import_svg_common_check; + + WM_operator_properties_filesel(ot, + FILE_TYPE_OBJECT_IO, + FILE_BLENDER, + FILE_OPENFILE, + WM_FILESEL_FILEPATH | WM_FILESEL_RELPATH | WM_FILESEL_SHOW_PROPS, + FILE_DEFAULTDISPLAY, + FILE_SORT_DEFAULT); + + RNA_def_int(ot->srna, + "resolution", + 10, + 1, + 30, + "Resolution", + "Resolution of the generated strokes", + 1, + 20); + + RNA_def_float(ot->srna, + "scale", + 10.0f, + 0.001f, + 100.0f, + "Scale", + "Scale of the final strokes", + 0.001f, + 100.0f); +} diff --git a/source/blender/editors/io/io_gpencil_utils.c b/source/blender/editors/io/io_gpencil_utils.c new file mode 100644 index 00000000000..259a669519a --- /dev/null +++ b/source/blender/editors/io/io_gpencil_utils.c @@ -0,0 +1,64 @@ +/* + * 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) 2020 Blender Foundation. + * All rights reserved. + */ + +/** \file + * \ingroup editor/io + */ + +#include "DNA_space_types.h" + +#include "BKE_context.h" +#include "BKE_screen.h" + +#include "WM_api.h" + +#include "io_gpencil.h" + +ARegion *get_invoke_region(bContext *C) +{ + bScreen *screen = CTX_wm_screen(C); + if (screen == NULL) { + return NULL; + } + ScrArea *area = BKE_screen_find_big_area(screen, SPACE_VIEW3D, 0); + if (area == NULL) { + return NULL; + } + + ARegion *region = BKE_area_find_region_type(area, RGN_TYPE_WINDOW); + + return region; +} + +View3D *get_invoke_view3d(bContext *C) +{ + bScreen *screen = CTX_wm_screen(C); + if (screen == NULL) { + return NULL; + } + ScrArea *area = BKE_screen_find_big_area(screen, SPACE_VIEW3D, 0); + if (area == NULL) { + return NULL; + } + if (area) { + return area->spacedata.first; + } + + return NULL; +} diff --git a/source/blender/editors/io/io_ops.c b/source/blender/editors/io/io_ops.c index acb511a414d..9fa34a1c55d 100644 --- a/source/blender/editors/io/io_ops.c +++ b/source/blender/editors/io/io_ops.c @@ -38,6 +38,7 @@ #endif #include "io_cache.h" +#include "io_gpencil.h" void ED_operatortypes_io(void) { @@ -54,6 +55,16 @@ void ED_operatortypes_io(void) WM_operatortype_append(WM_OT_usd_export); #endif + WM_operatortype_append(WM_OT_gpencil_import_svg); + +#ifdef WITH_PUGIXML + WM_operatortype_append(WM_OT_gpencil_export_svg); +#endif + +#ifdef WITH_HARU + WM_operatortype_append(WM_OT_gpencil_export_pdf); +#endif + WM_operatortype_append(CACHEFILE_OT_open); WM_operatortype_append(CACHEFILE_OT_reload); } diff --git a/source/blender/editors/mask/mask_add.c b/source/blender/editors/mask/mask_add.c index 1226cc57359..36edbbe31d6 100644 --- a/source/blender/editors/mask/mask_add.c +++ b/source/blender/editors/mask/mask_add.c @@ -26,6 +26,7 @@ #include "BLI_math.h" #include "BKE_context.h" +#include "BKE_curve.h" #include "BKE_mask.h" #include "DEG_depsgraph.h" @@ -692,6 +693,33 @@ void MASK_OT_add_feather_vertex(wmOperatorType *ot) /******************** common primitive functions *********************/ +static BezTriple *points_to_bezier(const float (*points)[2], + const int num_points, + const char handle_type, + const float scale, + const float location[2]) +{ + BezTriple *bezier_points = MEM_calloc_arrayN(num_points, sizeof(BezTriple), __func__); + for (int i = 0; i < num_points; i++) { + copy_v2_v2(bezier_points[i].vec[1], points[i]); + mul_v2_fl(bezier_points[i].vec[1], scale); + add_v2_v2(bezier_points[i].vec[1], location); + + bezier_points[i].h1 = handle_type; + bezier_points[i].h2 = handle_type; + } + + for (int i = 0; i < num_points; i++) { + BKE_nurb_handle_calc(&bezier_points[i], + &bezier_points[(i - 1 + num_points) % num_points], + &bezier_points[(i + 1) % num_points], + false, + false); + } + + return bezier_points; +} + static int create_primitive_from_points( bContext *C, wmOperator *op, const float (*points)[2], int num_points, char handle_type) { @@ -734,25 +762,25 @@ static int create_primitive_from_points( const int spline_index = BKE_mask_layer_shape_spline_to_index(mask_layer, new_spline); + BezTriple *bezier_points = points_to_bezier(points, num_points, handle_type, scale, location); + for (int i = 0; i < num_points; i++) { new_spline->tot_point = i + 1; MaskSplinePoint *new_point = &new_spline->points[i]; BKE_mask_parent_init(&new_point->parent); - copy_v2_v2(new_point->bezt.vec[1], points[i]); - mul_v2_fl(new_point->bezt.vec[1], scale); - add_v2_v2(new_point->bezt.vec[1], location); + new_point->bezt = bezier_points[i]; - new_point->bezt.h1 = handle_type; - new_point->bezt.h2 = handle_type; BKE_mask_point_select_set(new_point, true); if (mask_layer->splines_shapes.first) { - BKE_mask_layer_shape_changed_add(mask_layer, spline_index + i, true, true); + BKE_mask_layer_shape_changed_add(mask_layer, spline_index + i, true, false); } } + MEM_freeN(bezier_points); + if (added_mask) { WM_event_add_notifier(C, NC_MASK | NA_ADDED, NULL); } diff --git a/source/blender/editors/mesh/editmesh_knife.c b/source/blender/editors/mesh/editmesh_knife.c index df0ca6e3cae..fb107795c2a 100644 --- a/source/blender/editors/mesh/editmesh_knife.c +++ b/source/blender/editors/mesh/editmesh_knife.c @@ -74,7 +74,7 @@ /* detect isolated holes and fill them */ #define USE_NET_ISLAND_CONNECT -#define KMAXDIST 10 /* max mouse distance from edge before not detecting it */ +#define KMAXDIST (10 * U.dpi_fac) /* max mouse distance from edge before not detecting it */ /* WARNING: knife float precision is fragile: * be careful before making changes here see: (T43229, T42864, T42459, T41164). @@ -146,6 +146,8 @@ typedef struct KnifePosData { KnifeVert *vert; KnifeEdge *edge; BMFace *bmface; + + /** When true, the cursor isn't over a face. */ bool is_space; float mval[2]; /* mouse screen position (may be non-integral if snapped to something) */ @@ -196,7 +198,10 @@ typedef struct KnifeTool_OpData { KnifePosData prev; /* last added cut (a line draws from the cursor to this) */ KnifePosData init; /* the first point in the cut-list, used for closing the loop */ - int totkedge, totkvert; + /** Number of knife edges `kedges`. */ + int totkedge; + /** Number of knife vertices, `kverts`. */ + int totkvert; BLI_mempool *refs; @@ -221,7 +226,7 @@ typedef struct KnifeTool_OpData { float clipsta, clipend; - enum { MODE_IDLE, MODE_DRAGGING, MODE_CONNECT, MODE_PANNING } mode; + enum { MODE_INVOKING, MODE_IDLE, MODE_DRAGGING, MODE_CONNECT, MODE_PANNING } mode; bool is_drag_hold; int prevmode; @@ -243,8 +248,8 @@ enum { KNF_MODAL_MIDPOINT_ON, KNF_MODAL_MIDPOINT_OFF, KNF_MODAL_NEW_CUT, - KNF_MODEL_IGNORE_SNAP_ON, - KNF_MODEL_IGNORE_SNAP_OFF, + KNF_MODAL_IGNORE_SNAP_ON, + KNF_MODAL_IGNORE_SNAP_OFF, KNF_MODAL_ADD_CUT, KNF_MODAL_ANGLE_SNAP_TOGGLE, KNF_MODAL_CUT_THROUGH_TOGGLE, @@ -252,19 +257,263 @@ enum { KNF_MODAL_ADD_CUT_CLOSED, }; -static ListBase *knife_get_face_kedges(KnifeTool_OpData *kcd, BMFace *f); +/* -------------------------------------------------------------------- */ +/** \name Drawing + * \{ */ -static void knife_input_ray_segment(KnifeTool_OpData *kcd, - const float mval[2], - const float ofs, - float r_origin[3], - float r_origin_ofs[3]); +static void knifetool_draw_angle_snapping(const KnifeTool_OpData *kcd) +{ + float v1[3], v2[3]; + float planes[4][4]; + + planes_from_projmat( + (const float(*)[4])kcd->projmat, planes[2], planes[0], planes[3], planes[1], NULL, NULL); + + /* ray-cast all planes */ + { + float ray_dir[3]; + float ray_hit_best[2][3] = {{UNPACK3(kcd->prev.cage)}, {UNPACK3(kcd->curr.cage)}}; + float lambda_best[2] = {-FLT_MAX, FLT_MAX}; + int i; + + /* we (sometimes) need the lines to be at the same depth before projecting */ +#if 0 + sub_v3_v3v3(ray_dir, kcd->curr.cage, kcd->prev.cage); +#else + { + float curr_cage_adjust[3]; + float co_depth[3]; + + copy_v3_v3(co_depth, kcd->prev.cage); + mul_m4_v3(kcd->ob->obmat, co_depth); + ED_view3d_win_to_3d(kcd->vc.v3d, kcd->region, co_depth, kcd->curr.mval, curr_cage_adjust); + mul_m4_v3(kcd->ob->imat, curr_cage_adjust); + + sub_v3_v3v3(ray_dir, curr_cage_adjust, kcd->prev.cage); + } +#endif + + for (i = 0; i < 4; i++) { + float ray_hit[3]; + float lambda_test; + if (isect_ray_plane_v3(kcd->prev.cage, ray_dir, planes[i], &lambda_test, false)) { + madd_v3_v3v3fl(ray_hit, kcd->prev.cage, ray_dir, lambda_test); + if (lambda_test < 0.0f) { + if (lambda_test > lambda_best[0]) { + copy_v3_v3(ray_hit_best[0], ray_hit); + lambda_best[0] = lambda_test; + } + } + else { + if (lambda_test < lambda_best[1]) { + copy_v3_v3(ray_hit_best[1], ray_hit); + lambda_best[1] = lambda_test; + } + } + } + } + + copy_v3_v3(v1, ray_hit_best[0]); + copy_v3_v3(v2, ray_hit_best[1]); + } + + uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT); + + immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR); + immUniformThemeColor3(TH_TRANSFORM); + GPU_line_width(2.0); + + immBegin(GPU_PRIM_LINES, 2); + immVertex3fv(pos, v1); + immVertex3fv(pos, v2); + immEnd(); + + immUnbindProgram(); +} + +/* modal loop selection drawing callback */ +static void knifetool_draw(const bContext *UNUSED(C), ARegion *UNUSED(region), void *arg) +{ + const KnifeTool_OpData *kcd = arg; + GPU_depth_test(GPU_DEPTH_NONE); + + GPU_matrix_push_projection(); + GPU_polygon_offset(1.0f, 1.0f); + + GPU_matrix_push(); + GPU_matrix_mul(kcd->ob->obmat); + + if (kcd->mode == MODE_DRAGGING && kcd->is_angle_snapping) { + knifetool_draw_angle_snapping(kcd); + } + + GPUVertFormat *format = immVertexFormat(); + uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT); + + immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR); + + if (kcd->mode == MODE_DRAGGING) { + immUniformColor3ubv(kcd->colors.line); + GPU_line_width(2.0); + + immBegin(GPU_PRIM_LINES, 2); + immVertex3fv(pos, kcd->prev.cage); + immVertex3fv(pos, kcd->curr.cage); + immEnd(); + } + + if (kcd->prev.vert) { + immUniformColor3ubv(kcd->colors.point); + GPU_point_size(11 * UI_DPI_FAC); + + immBegin(GPU_PRIM_POINTS, 1); + immVertex3fv(pos, kcd->prev.cage); + immEnd(); + } + + if (kcd->prev.bmface || kcd->prev.edge) { + immUniformColor3ubv(kcd->colors.curpoint); + GPU_point_size(9 * UI_DPI_FAC); + + immBegin(GPU_PRIM_POINTS, 1); + immVertex3fv(pos, kcd->prev.cage); + immEnd(); + } + + if (kcd->curr.vert) { + immUniformColor3ubv(kcd->colors.point); + GPU_point_size(11 * UI_DPI_FAC); + + immBegin(GPU_PRIM_POINTS, 1); + immVertex3fv(pos, kcd->curr.cage); + immEnd(); + } + else if (kcd->curr.edge) { + immUniformColor3ubv(kcd->colors.edge); + GPU_line_width(2.0); + + immBegin(GPU_PRIM_LINES, 2); + immVertex3fv(pos, kcd->curr.edge->v1->cageco); + immVertex3fv(pos, kcd->curr.edge->v2->cageco); + immEnd(); + } + + if (kcd->curr.bmface || kcd->curr.edge) { + immUniformColor3ubv(kcd->colors.curpoint); + GPU_point_size(9 * UI_DPI_FAC); + + immBegin(GPU_PRIM_POINTS, 1); + immVertex3fv(pos, kcd->curr.cage); + immEnd(); + } + + if (kcd->totlinehit > 0) { + KnifeLineHit *lh; + int i, snapped_verts_count, other_verts_count; + float fcol[4]; + + GPU_blend(GPU_BLEND_ALPHA); + + GPUVertBuf *vert = GPU_vertbuf_create_with_format(format); + GPU_vertbuf_data_alloc(vert, kcd->totlinehit); + + lh = kcd->linehits; + for (i = 0, snapped_verts_count = 0, other_verts_count = 0; i < kcd->totlinehit; i++, lh++) { + if (lh->v) { + GPU_vertbuf_attr_set(vert, pos, snapped_verts_count++, lh->cagehit); + } + else { + GPU_vertbuf_attr_set(vert, pos, kcd->totlinehit - 1 - other_verts_count++, lh->cagehit); + } + } + + GPUBatch *batch = GPU_batch_create_ex(GPU_PRIM_POINTS, vert, NULL, GPU_BATCH_OWNS_VBO); + GPU_batch_program_set_builtin(batch, GPU_SHADER_3D_UNIFORM_COLOR); + + /* draw any snapped verts first */ + rgba_uchar_to_float(fcol, kcd->colors.point_a); + GPU_batch_uniform_4fv(batch, "color", fcol); + GPU_point_size(11 * UI_DPI_FAC); + if (snapped_verts_count > 0) { + GPU_batch_draw_range(batch, 0, snapped_verts_count); + } + + /* now draw the rest */ + rgba_uchar_to_float(fcol, kcd->colors.curpoint_a); + GPU_batch_uniform_4fv(batch, "color", fcol); + GPU_point_size(7 * UI_DPI_FAC); + if (other_verts_count > 0) { + GPU_batch_draw_range(batch, snapped_verts_count, other_verts_count); + } + + GPU_batch_discard(batch); + + GPU_blend(GPU_BLEND_NONE); + } + + if (kcd->totkedge > 0) { + BLI_mempool_iter iter; + KnifeEdge *kfe; + + immUniformColor3ubv(kcd->colors.line); + GPU_line_width(1.0); + + GPUBatch *batch = immBeginBatchAtMost(GPU_PRIM_LINES, BLI_mempool_len(kcd->kedges) * 2); + + BLI_mempool_iternew(kcd->kedges, &iter); + for (kfe = BLI_mempool_iterstep(&iter); kfe; kfe = BLI_mempool_iterstep(&iter)) { + if (!kfe->is_cut) { + continue; + } + + immVertex3fv(pos, kfe->v1->cageco); + immVertex3fv(pos, kfe->v2->cageco); + } + + immEnd(); + + GPU_batch_draw(batch); + GPU_batch_discard(batch); + } + + if (kcd->totkvert > 0) { + BLI_mempool_iter iter; + KnifeVert *kfv; + + immUniformColor3ubv(kcd->colors.point); + GPU_point_size(5.0 * UI_DPI_FAC); + + GPUBatch *batch = immBeginBatchAtMost(GPU_PRIM_POINTS, BLI_mempool_len(kcd->kverts)); + + BLI_mempool_iternew(kcd->kverts, &iter); + for (kfv = BLI_mempool_iterstep(&iter); kfv; kfv = BLI_mempool_iterstep(&iter)) { + if (!kfv->is_cut) { + continue; + } -static bool knife_verts_edge_in_face(KnifeVert *v1, KnifeVert *v2, BMFace *f); + immVertex3fv(pos, kfv->cageco); + } -static void knifetool_free_bmbvh(KnifeTool_OpData *kcd); + immEnd(); -static int knifetool_modal(bContext *C, wmOperator *op, const wmEvent *event); + GPU_batch_draw(batch); + GPU_batch_discard(batch); + } + + immUnbindProgram(); + + GPU_matrix_pop(); + GPU_matrix_pop_projection(); + + /* Reset default */ + GPU_depth_test(GPU_DEPTH_LESS_EQUAL); +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Header + * \{ */ static void knife_update_header(bContext *C, wmOperator *op, KnifeTool_OpData *kcd) { @@ -292,7 +541,7 @@ static void knife_update_header(bContext *C, wmOperator *op, KnifeTool_OpData *k WM_MODALKEY(KNF_MODAL_NEW_CUT), WM_MODALKEY(KNF_MODAL_MIDPOINT_ON), WM_bool_as_string(kcd->snap_midpoints), - WM_MODALKEY(KNF_MODEL_IGNORE_SNAP_ON), + WM_MODALKEY(KNF_MODAL_IGNORE_SNAP_ON), WM_bool_as_string(kcd->ignore_edge_snapping), WM_MODALKEY(KNF_MODAL_ANGLE_SNAP_TOGGLE), WM_bool_as_string(kcd->angle_snapping), @@ -305,51 +554,162 @@ static void knife_update_header(bContext *C, wmOperator *op, KnifeTool_OpData *k ED_workspace_status_text(C, header); } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Geometry Utils + * \{ */ + static void knife_project_v2(const KnifeTool_OpData *kcd, const float co[3], float sco[2]) { ED_view3d_project_float_v2_m4(kcd->region, co, sco, (float(*)[4])kcd->projmat); } -/* use when lambda is in screen-space */ -static void knife_interp_v3_v3v3(const KnifeTool_OpData *kcd, - float r_co[3], - const float v1[3], - const float v2[3], - float lambda_ss) +static void knife_input_ray_segment(KnifeTool_OpData *kcd, + const float mval[2], + const float ofs, + float r_origin[3], + float r_origin_ofs[3]) { - if (kcd->is_ortho) { - interp_v3_v3v3(r_co, v1, v2, lambda_ss); + /* unproject to find view ray */ + ED_view3d_unproject(kcd->vc.region, mval[0], mval[1], 0.0f, r_origin); + ED_view3d_unproject(kcd->vc.region, mval[0], mval[1], ofs, r_origin_ofs); + + /* transform into object space */ + invert_m4_m4(kcd->ob->imat, kcd->ob->obmat); + + mul_m4_v3(kcd->ob->imat, r_origin); + mul_m4_v3(kcd->ob->imat, r_origin_ofs); +} + +static bool knife_verts_edge_in_face(KnifeVert *v1, KnifeVert *v2, BMFace *f) +{ + bool v1_inside, v2_inside; + bool v1_inface, v2_inface; + BMLoop *l1, *l2; + + if (!f || !v1 || !v2) { + return false; } - else { - /* transform into screen-space, interp, then transform back */ - float v1_ss[3], v2_ss[3]; - mul_v3_project_m4_v3(v1_ss, (float(*)[4])kcd->projmat, v1); - mul_v3_project_m4_v3(v2_ss, (float(*)[4])kcd->projmat, v2); + l1 = v1->v ? BM_face_vert_share_loop(f, v1->v) : NULL; + l2 = v2->v ? BM_face_vert_share_loop(f, v2->v) : NULL; - interp_v3_v3v3(r_co, v1_ss, v2_ss, lambda_ss); + if ((l1 && l2) && BM_loop_is_adjacent(l1, l2)) { + /* boundary-case, always false to avoid edge-in-face checks below */ + return false; + } - mul_project_m4_v3((float(*)[4])kcd->projmat_inv, r_co); + /* find out if v1 and v2, if set, are part of the face */ + v1_inface = (l1 != NULL); + v2_inface = (l2 != NULL); + + /* BM_face_point_inside_test uses best-axis projection so this isn't most accurate test... */ + v1_inside = v1_inface ? false : BM_face_point_inside_test(f, v1->co); + v2_inside = v2_inface ? false : BM_face_point_inside_test(f, v2->co); + if ((v1_inface && v2_inside) || (v2_inface && v1_inside) || (v1_inside && v2_inside)) { + return true; + } + + if (v1_inface && v2_inface) { + float mid[3]; + /* Can have case where v1 and v2 are on shared chain between two faces. + * BM_face_splits_check_legal does visibility and self-intersection tests, + * but it is expensive and maybe a bit buggy, so use a simple + * "is the midpoint in the face" test */ + mid_v3_v3v3(mid, v1->co, v2->co); + return BM_face_point_inside_test(f, mid); } + return false; } -static void knife_pos_data_clear(KnifePosData *kpd) +static void knife_recalc_projmat(KnifeTool_OpData *kcd) { - zero_v3(kpd->co); - zero_v3(kpd->cage); - kpd->vert = NULL; - kpd->edge = NULL; - kpd->bmface = NULL; - zero_v2(kpd->mval); + invert_m4_m4(kcd->ob->imat, kcd->ob->obmat); + ED_view3d_ob_project_mat_get(kcd->region->regiondata, kcd->ob, kcd->projmat); + invert_m4_m4(kcd->projmat_inv, kcd->projmat); + + mul_v3_mat3_m4v3(kcd->proj_zaxis, kcd->ob->imat, kcd->vc.rv3d->viewinv[2]); + normalize_v3(kcd->proj_zaxis); + + kcd->is_ortho = ED_view3d_clip_range_get( + kcd->vc.depsgraph, kcd->vc.v3d, kcd->vc.rv3d, &kcd->clipsta, &kcd->clipend, true); +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Knife Element Utils + * + * Currently only used in #knife_find_line_hits. + * \{ */ + +static BMElem *bm_elem_from_knife_vert(KnifeVert *kfv, KnifeEdge **r_kfe) +{ + BMElem *ele_test; + KnifeEdge *kfe = NULL; + + /* vert? */ + ele_test = (BMElem *)kfv->v; + + if (r_kfe || ele_test == NULL) { + if (kfv->v == NULL) { + Ref *ref; + for (ref = kfv->edges.first; ref; ref = ref->next) { + kfe = ref->ref; + if (kfe->e) { + if (r_kfe) { + *r_kfe = kfe; + } + break; + } + } + } + } + + /* edge? */ + if (ele_test == NULL) { + if (kfe) { + ele_test = (BMElem *)kfe->e; + } + } + + /* face? */ + if (ele_test == NULL) { + if (BLI_listbase_is_single(&kfe->faces)) { + ele_test = ((Ref *)kfe->faces.first)->ref; + } + } + + return ele_test; } +static BMElem *bm_elem_from_knife_edge(KnifeEdge *kfe) +{ + BMElem *ele_test; + + ele_test = (BMElem *)kfe->e; + + if (ele_test == NULL) { + ele_test = (BMElem *)kfe->basef; + } + + return ele_test; +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Knife Element List Utils + * \{ */ + static ListBase *knife_empty_list(KnifeTool_OpData *kcd) { - ListBase *lst; + ListBase *list; - lst = BLI_memarena_alloc(kcd->arena, sizeof(ListBase)); - BLI_listbase_clear(lst); - return lst; + list = BLI_memarena_alloc(kcd->arena, sizeof(ListBase)); + BLI_listbase_clear(list); + return list; } static void knife_append_list(KnifeTool_OpData *kcd, ListBase *lst, void *elem) @@ -381,12 +741,6 @@ static void knife_append_list_no_dup(KnifeTool_OpData *kcd, ListBase *lst, void } } -static KnifeEdge *new_knife_edge(KnifeTool_OpData *kcd) -{ - kcd->totkedge++; - return BLI_mempool_calloc(kcd->kedges); -} - static void knife_add_to_vert_edges(KnifeTool_OpData *kcd, KnifeEdge *kfe) { knife_append_list(kcd, &kfe->v1->edges, kfe); @@ -420,6 +774,12 @@ static BMFace *knife_find_common_face(ListBase *faces1, ListBase *faces2) return NULL; } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Knife Element Creation + * \{ */ + static KnifeVert *new_knife_vert(KnifeTool_OpData *kcd, const float co[3], const float cageco[3]) { KnifeVert *kfv = BLI_mempool_calloc(kcd->kverts); @@ -432,6 +792,12 @@ static KnifeVert *new_knife_vert(KnifeTool_OpData *kcd, const float co[3], const return kfv; } +static KnifeEdge *new_knife_edge(KnifeTool_OpData *kcd) +{ + kcd->totkedge++; + return BLI_mempool_calloc(kcd->kedges); +} + /* get a KnifeVert wrapper for an existing BMVert */ static KnifeVert *get_bm_knife_vert(KnifeTool_OpData *kcd, BMVert *v) { @@ -484,92 +850,24 @@ static KnifeEdge *get_bm_knife_edge(KnifeTool_OpData *kcd, BMEdge *e) return kfe; } -/* Record the index in kcd->em->looptris of first looptri triple for a given face, - * given an index for some triple in that array. - * This assumes that all of the triangles for a given face are contiguous - * in that array (as they are by the current tessellation routines). - * Actually store index + 1 in the hash, because 0 looks like "no entry" - * to hash lookup routine; will reverse this in the get routine. - * Doing this lazily rather than all at once for all faces. - */ -static void set_lowest_face_tri(KnifeTool_OpData *kcd, BMFace *f, int index) -{ - int i; - - if (BLI_ghash_lookup(kcd->facetrimap, f)) { - return; - } - - BLI_assert(index >= 0 && index < kcd->em->tottri); - BLI_assert(kcd->em->looptris[index][0]->f == f); - for (i = index - 1; i >= 0; i--) { - if (kcd->em->looptris[i][0]->f != f) { - i++; - break; - } - } - if (i == -1) { - i++; - } - - BLI_ghash_insert(kcd->facetrimap, f, POINTER_FROM_INT(i + 1)); -} - -/* This should only be called for faces that have had a lowest face tri set by previous function */ -static int get_lowest_face_tri(KnifeTool_OpData *kcd, BMFace *f) -{ - int ans; - - ans = POINTER_AS_INT(BLI_ghash_lookup(kcd->facetrimap, f)); - BLI_assert(ans != 0); - return ans - 1; -} - -/* User has just clicked for first time or first time after a restart (E key). - * Copy the current position data into prev. */ -static void knife_start_cut(KnifeTool_OpData *kcd) -{ - kcd->prev = kcd->curr; - kcd->curr.is_space = 0; /*TODO: why do we do this? */ - - if (kcd->prev.vert == NULL && kcd->prev.edge == NULL) { - float origin[3], origin_ofs[3]; - float ofs_local[3]; - - negate_v3_v3(ofs_local, kcd->vc.rv3d->ofs); - invert_m4_m4(kcd->ob->imat, kcd->ob->obmat); - mul_m4_v3(kcd->ob->imat, ofs_local); - - knife_input_ray_segment(kcd, kcd->curr.mval, 1.0f, origin, origin_ofs); - - if (!isect_line_plane_v3(kcd->prev.cage, origin, origin_ofs, ofs_local, kcd->proj_zaxis)) { - zero_v3(kcd->prev.cage); - } - - copy_v3_v3(kcd->prev.co, kcd->prev.cage); /*TODO: do we need this? */ - copy_v3_v3(kcd->curr.cage, kcd->prev.cage); - copy_v3_v3(kcd->curr.co, kcd->prev.co); - } -} - static ListBase *knife_get_face_kedges(KnifeTool_OpData *kcd, BMFace *f) { - ListBase *lst = BLI_ghash_lookup(kcd->kedgefacemap, f); + ListBase *list = BLI_ghash_lookup(kcd->kedgefacemap, f); - if (!lst) { + if (!list) { BMIter bmiter; BMEdge *e; - lst = knife_empty_list(kcd); + list = knife_empty_list(kcd); BM_ITER_ELEM (e, &bmiter, f, BM_EDGES_OF_FACE) { - knife_append_list(kcd, lst, get_bm_knife_edge(kcd, e)); + knife_append_list(kcd, list, get_bm_knife_edge(kcd, e)); } - BLI_ghash_insert(kcd->kedgefacemap, f, lst); + BLI_ghash_insert(kcd->kedgefacemap, f, list); } - return lst; + return list; } static void knife_edge_append_face(KnifeTool_OpData *kcd, KnifeEdge *kfe, BMFace *f) @@ -625,6 +923,39 @@ static KnifeVert *knife_split_edge(KnifeTool_OpData *kcd, return newkfe->v2; } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Cut/Hit Utils + * \{ */ + +/* User has just clicked for first time or first time after a restart (E key). + * Copy the current position data into prev. */ +static void knife_start_cut(KnifeTool_OpData *kcd) +{ + kcd->prev = kcd->curr; + kcd->curr.is_space = 0; /*TODO: why do we do this? */ + + if (kcd->prev.vert == NULL && kcd->prev.edge == NULL) { + float origin[3], origin_ofs[3]; + float ofs_local[3]; + + negate_v3_v3(ofs_local, kcd->vc.rv3d->ofs); + invert_m4_m4(kcd->ob->imat, kcd->ob->obmat); + mul_m4_v3(kcd->ob->imat, ofs_local); + + knife_input_ray_segment(kcd, kcd->curr.mval, 1.0f, origin, origin_ofs); + + if (!isect_line_plane_v3(kcd->prev.cage, origin, origin_ofs, ofs_local, kcd->proj_zaxis)) { + zero_v3(kcd->prev.cage); + } + + copy_v3_v3(kcd->prev.co, kcd->prev.cage); /*TODO: do we need this? */ + copy_v3_v3(kcd->curr.cage, kcd->prev.cage); + copy_v3_v3(kcd->curr.co, kcd->prev.co); + } +} + static void linehit_to_knifepos(KnifePosData *kpos, KnifeLineHit *lh) { kpos->bmface = lh->f; @@ -750,13 +1081,13 @@ static void add_hit_to_facehits(KnifeTool_OpData *kcd, BMFace *f, KnifeLineHit *hit) { - ListBase *lst = BLI_ghash_lookup(facehits, f); + ListBase *list = BLI_ghash_lookup(facehits, f); - if (!lst) { - lst = knife_empty_list(kcd); - BLI_ghash_insert(facehits, f, lst); + if (!list) { + list = knife_empty_list(kcd); + BLI_ghash_insert(facehits, f, list); } - knife_append_list_no_dup(kcd, lst, hit); + knife_append_list_no_dup(kcd, list, hit); } /** @@ -879,6 +1210,228 @@ static void knife_cut_face(KnifeTool_OpData *kcd, BMFace *f, ListBase *hits) } } +static void knife_make_face_cuts(KnifeTool_OpData *kcd, BMFace *f, ListBase *kfedges) +{ + BMesh *bm = kcd->em->bm; + KnifeEdge *kfe; + Ref *ref; + int edge_array_len = BLI_listbase_count(kfedges); + int i; + + BMEdge **edge_array = BLI_array_alloca(edge_array, edge_array_len); + + /* point to knife edges we've created edges in, edge_array aligned */ + KnifeEdge **kfe_array = BLI_array_alloca(kfe_array, edge_array_len); + + BLI_assert(BLI_gset_len(kcd->edgenet.edge_visit) == 0); + + i = 0; + for (ref = kfedges->first; ref; ref = ref->next) { + bool is_new_edge = false; + kfe = ref->ref; + + if (kfe->e == NULL) { + if (kfe->v1->v && kfe->v2->v) { + kfe->e = BM_edge_exists(kfe->v1->v, kfe->v2->v); + } + } + + if (kfe->e) { + if (BM_edge_in_face(kfe->e, f)) { + /* shouldn't happen, but in this case - just ignore */ + continue; + } + } + else { + if (kfe->v1->v == NULL) { + kfe->v1->v = BM_vert_create(bm, kfe->v1->co, NULL, 0); + } + if (kfe->v2->v == NULL) { + kfe->v2->v = BM_vert_create(bm, kfe->v2->co, NULL, 0); + } + BLI_assert(kfe->e == NULL); + kfe->e = BM_edge_create(bm, kfe->v1->v, kfe->v2->v, NULL, 0); + if (kfe->e) { + if (kcd->select_result || BM_elem_flag_test(f, BM_ELEM_SELECT)) { + BM_edge_select_set(bm, kfe->e, true); + } + is_new_edge = true; + } + } + + BLI_assert(kfe->e); + + if (BLI_gset_add(kcd->edgenet.edge_visit, kfe->e)) { + kfe_array[i] = is_new_edge ? kfe : 0; + edge_array[i] = kfe->e; + i += 1; + } + } + + if (i) { + const int edge_array_len_orig = i; + edge_array_len = i; + +#ifdef USE_NET_ISLAND_CONNECT + uint edge_array_holes_len; + BMEdge **edge_array_holes; + if (BM_face_split_edgenet_connect_islands(bm, + f, + edge_array, + edge_array_len, + true, + kcd->edgenet.arena, + &edge_array_holes, + &edge_array_holes_len)) { + if (BM_elem_flag_test(f, BM_ELEM_SELECT)) { + for (i = edge_array_len; i < edge_array_holes_len; i++) { + BM_edge_select_set(bm, edge_array_holes[i], true); + } + } + + edge_array_len = edge_array_holes_len; + edge_array = edge_array_holes; /* owned by the arena */ + } +#endif + + { + BMFace **face_arr = NULL; + int face_arr_len; + + BM_face_split_edgenet(bm, f, edge_array, edge_array_len, &face_arr, &face_arr_len); + + if (face_arr) { + MEM_freeN(face_arr); + } + } + + /* remove dangling edges, not essential - but nice for users */ + for (i = 0; i < edge_array_len_orig; i++) { + if (kfe_array[i]) { + if (BM_edge_is_wire(kfe_array[i]->e)) { + BM_edge_kill(bm, kfe_array[i]->e); + kfe_array[i]->e = NULL; + } + } + } + +#ifdef USE_NET_ISLAND_CONNECT + BLI_memarena_clear(kcd->edgenet.arena); +#endif + } + + BLI_gset_clear(kcd->edgenet.edge_visit, NULL); +} + +static int sort_verts_by_dist_cb(void *co_p, const void *cur_a_p, const void *cur_b_p) +{ + const KnifeVert *cur_a = ((const Ref *)cur_a_p)->ref; + const KnifeVert *cur_b = ((const Ref *)cur_b_p)->ref; + const float *co = co_p; + const float a_sq = len_squared_v3v3(co, cur_a->co); + const float b_sq = len_squared_v3v3(co, cur_b->co); + + if (a_sq < b_sq) { + return -1; + } + if (a_sq > b_sq) { + return 1; + } + return 0; +} + +/* Use the network of KnifeEdges and KnifeVerts accumulated to make real BMVerts and BMEdedges */ +static void knife_make_cuts(KnifeTool_OpData *kcd) +{ + BMesh *bm = kcd->em->bm; + KnifeEdge *kfe; + KnifeVert *kfv; + BMFace *f; + BMEdge *e, *enew; + ListBase *list; + Ref *ref; + float pct; + SmallHashIter hiter; + BLI_mempool_iter iter; + SmallHash fhash_, *fhash = &fhash_; + SmallHash ehash_, *ehash = &ehash_; + + BLI_smallhash_init(fhash); + BLI_smallhash_init(ehash); + + /* put list of cutting edges for a face into fhash, keyed by face */ + BLI_mempool_iternew(kcd->kedges, &iter); + for (kfe = BLI_mempool_iterstep(&iter); kfe; kfe = BLI_mempool_iterstep(&iter)) { + + /* select edges that lie directly on the cut */ + if (kcd->select_result) { + if (kfe->e && kfe->is_cut) { + BM_edge_select_set(bm, kfe->e, true); + } + } + + f = kfe->basef; + if (!f || kfe->e) { + continue; + } + list = BLI_smallhash_lookup(fhash, (uintptr_t)f); + if (!list) { + list = knife_empty_list(kcd); + BLI_smallhash_insert(fhash, (uintptr_t)f, list); + } + knife_append_list(kcd, list, kfe); + } + + /* put list of splitting vertices for an edge into ehash, keyed by edge */ + BLI_mempool_iternew(kcd->kverts, &iter); + for (kfv = BLI_mempool_iterstep(&iter); kfv; kfv = BLI_mempool_iterstep(&iter)) { + if (kfv->v) { + continue; /* already have a BMVert */ + } + for (ref = kfv->edges.first; ref; ref = ref->next) { + kfe = ref->ref; + e = kfe->e; + if (!e) { + continue; + } + list = BLI_smallhash_lookup(ehash, (uintptr_t)e); + if (!list) { + list = knife_empty_list(kcd); + BLI_smallhash_insert(ehash, (uintptr_t)e, list); + } + /* there can be more than one kfe in kfv's list with same e */ + if (!find_ref(list, kfv)) { + knife_append_list(kcd, list, kfv); + } + } + } + + /* split bmesh edges where needed */ + for (list = BLI_smallhash_iternew(ehash, &hiter, (uintptr_t *)&e); list; + list = BLI_smallhash_iternext(&hiter, (uintptr_t *)&e)) { + BLI_listbase_sort_r(list, sort_verts_by_dist_cb, e->v1->co); + + for (ref = list->first; ref; ref = ref->next) { + kfv = ref->ref; + pct = line_point_factor_v3(kfv->co, e->v1->co, e->v2->co); + kfv->v = BM_edge_split(bm, e, e->v1, &enew, pct); + } + } + + if (kcd->only_select) { + EDBM_flag_disable_all(kcd->em, BM_ELEM_SELECT); + } + + /* do cuts for each face */ + for (list = BLI_smallhash_iternew(fhash, &hiter, (uintptr_t *)&f); list; + list = BLI_smallhash_iternext(&hiter, (uintptr_t *)&f)) { + knife_make_face_cuts(kcd, f, list); + } + + BLI_smallhash_release(fhash); + BLI_smallhash_release(ehash); +} + /* User has just left-clicked after the first time. * Add all knife cuts implied by line from prev to curr. * If that line crossed edges then kcd->linehits will be non-NULL. @@ -891,7 +1444,7 @@ static void knife_add_cut(KnifeTool_OpData *kcd) BMFace *f; Ref *r; GHashIterator giter; - ListBase *lst; + ListBase *list; prepare_linehits_for_cut(kcd); if (kcd->totlinehit == 0) { @@ -926,8 +1479,8 @@ static void knife_add_cut(KnifeTool_OpData *kcd) * the v and the kfe or f fields will be non-NULL. */ GHASH_ITER (giter, facehits) { f = (BMFace *)BLI_ghashIterator_getKey(&giter); - lst = (ListBase *)BLI_ghashIterator_getValue(&giter); - knife_cut_face(kcd, f, lst); + list = (ListBase *)BLI_ghashIterator_getValue(&giter); + knife_cut_face(kcd, f, list); } /* set up for next cut */ @@ -960,267 +1513,51 @@ static void knife_finish_cut(KnifeTool_OpData *kcd) } } -static void knifetool_draw_angle_snapping(const KnifeTool_OpData *kcd) -{ - float v1[3], v2[3]; - float planes[4][4]; - - planes_from_projmat( - (const float(*)[4])kcd->projmat, planes[2], planes[0], planes[3], planes[1], NULL, NULL); - - /* ray-cast all planes */ - { - float ray_dir[3]; - float ray_hit_best[2][3] = {{UNPACK3(kcd->prev.cage)}, {UNPACK3(kcd->curr.cage)}}; - float lambda_best[2] = {-FLT_MAX, FLT_MAX}; - int i; - - /* we (sometimes) need the lines to be at the same depth before projecting */ -#if 0 - sub_v3_v3v3(ray_dir, kcd->curr.cage, kcd->prev.cage); -#else - { - float curr_cage_adjust[3]; - float co_depth[3]; - - copy_v3_v3(co_depth, kcd->prev.cage); - mul_m4_v3(kcd->ob->obmat, co_depth); - ED_view3d_win_to_3d(kcd->vc.v3d, kcd->region, co_depth, kcd->curr.mval, curr_cage_adjust); - mul_m4_v3(kcd->ob->imat, curr_cage_adjust); - - sub_v3_v3v3(ray_dir, curr_cage_adjust, kcd->prev.cage); - } -#endif - - for (i = 0; i < 4; i++) { - float ray_hit[3]; - float lambda_test; - if (isect_ray_plane_v3(kcd->prev.cage, ray_dir, planes[i], &lambda_test, false)) { - madd_v3_v3v3fl(ray_hit, kcd->prev.cage, ray_dir, lambda_test); - if (lambda_test < 0.0f) { - if (lambda_test > lambda_best[0]) { - copy_v3_v3(ray_hit_best[0], ray_hit); - lambda_best[0] = lambda_test; - } - } - else { - if (lambda_test < lambda_best[1]) { - copy_v3_v3(ray_hit_best[1], ray_hit); - lambda_best[1] = lambda_test; - } - } - } - } - - copy_v3_v3(v1, ray_hit_best[0]); - copy_v3_v3(v2, ray_hit_best[1]); - } - - uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT); +/** \} */ - immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR); - immUniformThemeColor3(TH_TRANSFORM); - GPU_line_width(2.0); - - immBegin(GPU_PRIM_LINES, 2); - immVertex3fv(pos, v1); - immVertex3fv(pos, v2); - immEnd(); - - immUnbindProgram(); -} - -static void knife_init_colors(KnifeColors *colors) -{ - /* possible BMESH_TODO: add explicit themes or calculate these by - * figuring out contrasting colors with grid / edges / verts - * a la UI_make_axis_color */ - UI_GetThemeColorType3ubv(TH_NURB_VLINE, SPACE_VIEW3D, colors->line); - UI_GetThemeColorType3ubv(TH_NURB_ULINE, SPACE_VIEW3D, colors->edge); - UI_GetThemeColorType3ubv(TH_HANDLE_SEL_VECT, SPACE_VIEW3D, colors->curpoint); - UI_GetThemeColorType3ubv(TH_HANDLE_SEL_VECT, SPACE_VIEW3D, colors->curpoint_a); - colors->curpoint_a[3] = 102; - UI_GetThemeColorType3ubv(TH_ACTIVE_SPLINE, SPACE_VIEW3D, colors->point); - UI_GetThemeColorType3ubv(TH_ACTIVE_SPLINE, SPACE_VIEW3D, colors->point_a); - colors->point_a[3] = 102; -} +/* -------------------------------------------------------------------- */ +/** \name Screen Line Hits (#knife_find_line_hits) + * \{ */ -/* modal loop selection drawing callback */ -static void knifetool_draw(const bContext *UNUSED(C), ARegion *UNUSED(region), void *arg) +/* Record the index in kcd->em->looptris of first looptri triple for a given face, + * given an index for some triple in that array. + * This assumes that all of the triangles for a given face are contiguous + * in that array (as they are by the current tessellation routines). + * Actually store index + 1 in the hash, because 0 looks like "no entry" + * to hash lookup routine; will reverse this in the get routine. + * Doing this lazily rather than all at once for all faces. + */ +static void set_lowest_face_tri(KnifeTool_OpData *kcd, BMFace *f, int index) { - const KnifeTool_OpData *kcd = arg; - GPU_depth_test(GPU_DEPTH_NONE); - - GPU_matrix_push_projection(); - GPU_polygon_offset(1.0f, 1.0f); - - GPU_matrix_push(); - GPU_matrix_mul(kcd->ob->obmat); - - if (kcd->mode == MODE_DRAGGING && kcd->is_angle_snapping) { - knifetool_draw_angle_snapping(kcd); - } - - GPUVertFormat *format = immVertexFormat(); - uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT); - - immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR); - - if (kcd->mode == MODE_DRAGGING) { - immUniformColor3ubv(kcd->colors.line); - GPU_line_width(2.0); - - immBegin(GPU_PRIM_LINES, 2); - immVertex3fv(pos, kcd->prev.cage); - immVertex3fv(pos, kcd->curr.cage); - immEnd(); - } - - if (kcd->prev.vert) { - immUniformColor3ubv(kcd->colors.point); - GPU_point_size(11); - - immBegin(GPU_PRIM_POINTS, 1); - immVertex3fv(pos, kcd->prev.cage); - immEnd(); - } - - if (kcd->prev.bmface) { - immUniformColor3ubv(kcd->colors.curpoint); - GPU_point_size(9); - - immBegin(GPU_PRIM_POINTS, 1); - immVertex3fv(pos, kcd->prev.cage); - immEnd(); - } - - if (kcd->curr.edge) { - immUniformColor3ubv(kcd->colors.edge); - GPU_line_width(2.0); - - immBegin(GPU_PRIM_LINES, 2); - immVertex3fv(pos, kcd->curr.edge->v1->cageco); - immVertex3fv(pos, kcd->curr.edge->v2->cageco); - immEnd(); - } - else if (kcd->curr.vert) { - immUniformColor3ubv(kcd->colors.point); - GPU_point_size(11); - - immBegin(GPU_PRIM_POINTS, 1); - immVertex3fv(pos, kcd->curr.cage); - immEnd(); - } - - if (kcd->curr.bmface) { - immUniformColor3ubv(kcd->colors.curpoint); - GPU_point_size(9); - - immBegin(GPU_PRIM_POINTS, 1); - immVertex3fv(pos, kcd->curr.cage); - immEnd(); - } - - if (kcd->totlinehit > 0) { - KnifeLineHit *lh; - int i, snapped_verts_count, other_verts_count; - float fcol[4]; - - GPU_blend(GPU_BLEND_ALPHA); - - GPUVertBuf *vert = GPU_vertbuf_create_with_format(format); - GPU_vertbuf_data_alloc(vert, kcd->totlinehit); - - lh = kcd->linehits; - for (i = 0, snapped_verts_count = 0, other_verts_count = 0; i < kcd->totlinehit; i++, lh++) { - if (lh->v) { - GPU_vertbuf_attr_set(vert, pos, snapped_verts_count++, lh->cagehit); - } - else { - GPU_vertbuf_attr_set(vert, pos, kcd->totlinehit - 1 - other_verts_count++, lh->cagehit); - } - } - - GPUBatch *batch = GPU_batch_create_ex(GPU_PRIM_POINTS, vert, NULL, GPU_BATCH_OWNS_VBO); - GPU_batch_program_set_builtin(batch, GPU_SHADER_3D_UNIFORM_COLOR); - - /* draw any snapped verts first */ - rgba_uchar_to_float(fcol, kcd->colors.point_a); - GPU_batch_uniform_4fv(batch, "color", fcol); - GPU_point_size(11); - if (snapped_verts_count > 0) { - GPU_batch_draw_range(batch, 0, snapped_verts_count); - } - - /* now draw the rest */ - rgba_uchar_to_float(fcol, kcd->colors.curpoint_a); - GPU_batch_uniform_4fv(batch, "color", fcol); - GPU_point_size(7); - if (other_verts_count > 0) { - GPU_batch_draw_range(batch, snapped_verts_count, other_verts_count); - } - - GPU_batch_discard(batch); + int i; - GPU_blend(GPU_BLEND_NONE); + if (BLI_ghash_lookup(kcd->facetrimap, f)) { + return; } - if (kcd->totkedge > 0) { - BLI_mempool_iter iter; - KnifeEdge *kfe; - - immUniformColor3ubv(kcd->colors.line); - GPU_line_width(1.0); - - GPUBatch *batch = immBeginBatchAtMost(GPU_PRIM_LINES, BLI_mempool_len(kcd->kedges) * 2); - - BLI_mempool_iternew(kcd->kedges, &iter); - for (kfe = BLI_mempool_iterstep(&iter); kfe; kfe = BLI_mempool_iterstep(&iter)) { - if (!kfe->is_cut) { - continue; - } - - immVertex3fv(pos, kfe->v1->cageco); - immVertex3fv(pos, kfe->v2->cageco); + BLI_assert(index >= 0 && index < kcd->em->tottri); + BLI_assert(kcd->em->looptris[index][0]->f == f); + for (i = index - 1; i >= 0; i--) { + if (kcd->em->looptris[i][0]->f != f) { + i++; + break; } - - immEnd(); - - GPU_batch_draw(batch); - GPU_batch_discard(batch); } - - if (kcd->totkvert > 0) { - BLI_mempool_iter iter; - KnifeVert *kfv; - - immUniformColor3ubv(kcd->colors.point); - GPU_point_size(5.0); - - GPUBatch *batch = immBeginBatchAtMost(GPU_PRIM_POINTS, BLI_mempool_len(kcd->kverts)); - - BLI_mempool_iternew(kcd->kverts, &iter); - for (kfv = BLI_mempool_iterstep(&iter); kfv; kfv = BLI_mempool_iterstep(&iter)) { - if (!kfv->is_cut) { - continue; - } - - immVertex3fv(pos, kfv->cageco); - } - - immEnd(); - - GPU_batch_draw(batch); - GPU_batch_discard(batch); + if (i == -1) { + i++; } - immUnbindProgram(); + BLI_ghash_insert(kcd->facetrimap, f, POINTER_FROM_INT(i + 1)); +} - GPU_matrix_pop(); - GPU_matrix_pop_projection(); +/* This should only be called for faces that have had a lowest face tri set by previous function */ +static int get_lowest_face_tri(KnifeTool_OpData *kcd, BMFace *f) +{ + int ans; - /* Reset default */ - GPU_depth_test(GPU_DEPTH_LESS_EQUAL); + ans = POINTER_AS_INT(BLI_ghash_lookup(kcd->facetrimap, f)); + BLI_assert(ans != 0); + return ans - 1; } /** @@ -1246,7 +1583,7 @@ static bool knife_ray_intersect_face(KnifeTool_OpData *kcd, float se1[2], se2[2]; float d, lambda; BMLoop **tri; - ListBase *lst; + ListBase *list; Ref *ref; KnifeEdge *kfe; @@ -1281,8 +1618,8 @@ static bool knife_ray_intersect_face(KnifeTool_OpData *kcd, } interp_v3_v3v3v3_uv(hit_cageco, lv1, lv2, lv3, ray_tri_uv); /* Now check that far enough away from verts and edges */ - lst = knife_get_face_kedges(kcd, f); - for (ref = lst->first; ref; ref = ref->next) { + list = knife_get_face_kedges(kcd, f); + for (ref = list->first; ref; ref = ref->next) { kfe = ref->ref; knife_project_v2(kcd, kfe->v1->cageco, se1); knife_project_v2(kcd, kfe->v2->cageco, se2); @@ -1323,59 +1660,6 @@ static void calc_ortho_extent(KnifeTool_OpData *kcd) mid_v3_v3v3(kcd->ortho_extent_center, min, max); } -static BMElem *bm_elem_from_knife_vert(KnifeVert *kfv, KnifeEdge **r_kfe) -{ - BMElem *ele_test; - KnifeEdge *kfe = NULL; - - /* vert? */ - ele_test = (BMElem *)kfv->v; - - if (r_kfe || ele_test == NULL) { - if (kfv->v == NULL) { - Ref *ref; - for (ref = kfv->edges.first; ref; ref = ref->next) { - kfe = ref->ref; - if (kfe->e) { - if (r_kfe) { - *r_kfe = kfe; - } - break; - } - } - } - } - - /* edge? */ - if (ele_test == NULL) { - if (kfe) { - ele_test = (BMElem *)kfe->e; - } - } - - /* face? */ - if (ele_test == NULL) { - if (BLI_listbase_is_single(&kfe->faces)) { - ele_test = ((Ref *)kfe->faces.first)->ref; - } - } - - return ele_test; -} - -static BMElem *bm_elem_from_knife_edge(KnifeEdge *kfe) -{ - BMElem *ele_test; - - ele_test = (BMElem *)kfe->e; - - if (ele_test == NULL) { - ele_test = (BMElem *)kfe->basef; - } - - return ele_test; -} - /* Do edges e1 and e2 go between exactly the same coordinates? */ static bool coinciding_edges(BMEdge *e1, BMEdge *e2) { @@ -1546,7 +1830,7 @@ static void knife_find_line_hits(KnifeTool_OpData *kcd) BMFace *f; KnifeEdge *kfe; KnifeVert *v; - ListBase *lst; + ListBase *list; Ref *ref; KnifeLineHit *linehits = NULL; BLI_array_declare(linehits); @@ -1650,8 +1934,8 @@ static void knife_find_line_hits(KnifeTool_OpData *kcd) /* don't care what the value is except that it is non-NULL, for iterator */ BLI_smallhash_insert(&faces, (uintptr_t)f, f); - lst = knife_get_face_kedges(kcd, f); - for (ref = lst->first; ref; ref = ref->next) { + list = knife_get_face_kedges(kcd, f); + for (ref = list->first; ref; ref = ref->next) { kfe = ref->ref; if (BLI_smallhash_haskey(&kfes, (uintptr_t)kfe)) { continue; @@ -1858,23 +2142,28 @@ static void knife_find_line_hits(KnifeTool_OpData *kcd) } } -static void knife_input_ray_segment(KnifeTool_OpData *kcd, - const float mval[2], - const float ofs, - float r_origin[3], - float r_origin_ofs[3]) -{ - /* unproject to find view ray */ - ED_view3d_unproject(kcd->vc.region, mval[0], mval[1], 0.0f, r_origin); - ED_view3d_unproject(kcd->vc.region, mval[0], mval[1], ofs, r_origin_ofs); +/** \} */ - /* transform into object space */ - invert_m4_m4(kcd->ob->imat, kcd->ob->obmat); +/* -------------------------------------------------------------------- */ +/** \name KnifePosData Utils + * \{ */ - mul_m4_v3(kcd->ob->imat, r_origin); - mul_m4_v3(kcd->ob->imat, r_origin_ofs); +static void knife_pos_data_clear(KnifePosData *kpd) +{ + zero_v3(kpd->co); + zero_v3(kpd->cage); + kpd->vert = NULL; + kpd->edge = NULL; + kpd->bmface = NULL; + zero_v2(kpd->mval); } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Snapping (#knife_snap_update_from_mval) + * \{ */ + static BMFace *knife_find_closest_face(KnifeTool_OpData *kcd, float co[3], float cageco[3], @@ -1917,6 +2206,8 @@ static BMFace *knife_find_closest_face(KnifeTool_OpData *kcd, * of a true coordinate on the face. * This just puts a point 1.0f in front of the view. */ add_v3_v3v3(co, origin, ray); + /* Use this value for the cage location too as it's used to find near edges/vertices. */ + copy_v3_v3(cageco, co); } } @@ -1926,64 +2217,119 @@ static BMFace *knife_find_closest_face(KnifeTool_OpData *kcd, /** * Find the 2d screen space density of vertices within a radius. * Used to scale snapping distance for picking edges/verts. + * + * Arguments `f` and `cageco` should be the result of a call to #knife_find_closest_face. */ -static int knife_sample_screen_density(KnifeTool_OpData *kcd, const float radius) +static int knife_sample_screen_density_from_closest_face(KnifeTool_OpData *kcd, + const float radius, + BMFace *f, + const float cageco[3]) { - BMFace *f; - bool is_space; - float co[3], cageco[3], sco[2]; - - BLI_assert(kcd->is_interactive == true); - - f = knife_find_closest_face(kcd, co, cageco, &is_space); - - if (f && !is_space) { - const float radius_sq = radius * radius; - ListBase *lst; - Ref *ref; - float dis_sq; - int c = 0; + const float radius_sq = radius * radius; + ListBase *list; + Ref *ref; + float sco[2]; + float dis_sq; + int c = 0; - knife_project_v2(kcd, cageco, sco); + knife_project_v2(kcd, cageco, sco); - lst = knife_get_face_kedges(kcd, f); - for (ref = lst->first; ref; ref = ref->next) { - KnifeEdge *kfe = ref->ref; - int i; + list = knife_get_face_kedges(kcd, f); + for (ref = list->first; ref; ref = ref->next) { + KnifeEdge *kfe = ref->ref; + int i; - for (i = 0; i < 2; i++) { - KnifeVert *kfv = i ? kfe->v2 : kfe->v1; - float kfv_sco[2]; + for (i = 0; i < 2; i++) { + KnifeVert *kfv = i ? kfe->v2 : kfe->v1; + float kfv_sco[2]; - knife_project_v2(kcd, kfv->cageco, kfv_sco); + knife_project_v2(kcd, kfv->cageco, kfv_sco); - dis_sq = len_squared_v2v2(kfv_sco, sco); - if (dis_sq < radius_sq) { - if (RV3D_CLIPPING_ENABLED(kcd->vc.v3d, kcd->vc.rv3d)) { - if (ED_view3d_clipping_test(kcd->vc.rv3d, kfv->cageco, true) == 0) { - c++; - } - } - else { + dis_sq = len_squared_v2v2(kfv_sco, sco); + if (dis_sq < radius_sq) { + if (RV3D_CLIPPING_ENABLED(kcd->vc.v3d, kcd->vc.rv3d)) { + if (ED_view3d_clipping_test(kcd->vc.rv3d, kfv->cageco, true) == 0) { c++; } } + else { + c++; + } } } - - return c; } - return 0; + return c; } -/* returns snapping distance for edges/verts, scaled by the density of the - * surrounding mesh (in screen space)*/ +/** + * \return the snapping distance for edges/verts, scaled by the density of the + * surrounding mesh (in screen space). + * + * \note Face values in `kcd->curr` must be up to date. + */ static float knife_snap_size(KnifeTool_OpData *kcd, float maxsize) { - float density = (float)knife_sample_screen_density(kcd, maxsize * 2.0f); + BLI_assert(kcd->is_interactive == true); + int density = 0; + + if (!kcd->curr.is_space) { + density = (float)knife_sample_screen_density_from_closest_face( + kcd, maxsize * 2.0f, kcd->curr.bmface, kcd->curr.cage); + } + + return density ? min_ff(maxsize / ((float)density * 0.5f), maxsize) : maxsize; +} + +/* Snap to edge in a specified angle. + * Returns 'lambda' calculated (in screen-space). */ +static bool knife_snap_edge_in_angle(KnifeTool_OpData *kcd, + const float sco[3], + const float kfv1_sco[2], + const float kfv2_sco[2], + float *r_dist_sq, + float *r_lambda) +{ + /* if snapping, check we're in bounds */ + float sco_snap[2]; + isect_line_line_v2_point(kfv1_sco, kfv2_sco, kcd->prev.mval, kcd->curr.mval, sco_snap); + float lambda = line_point_factor_v2(sco_snap, kfv1_sco, kfv2_sco); + + /* be strict about angle-snapping within edge */ + if ((lambda < 0.0f - KNIFE_FLT_EPSBIG) || (lambda > 1.0f + KNIFE_FLT_EPSBIG)) { + return false; + } + + float dis_sq = len_squared_v2v2(sco, sco_snap); + if (dis_sq < *r_dist_sq) { + *r_dist_sq = dis_sq; + *r_lambda = lambda; + return true; + } + return false; +} + +/* use when lambda is in screen-space */ +static void knife_interp_v3_v3v3(const KnifeTool_OpData *kcd, + float r_co[3], + const float v1[3], + const float v2[3], + float lambda_ss) +{ + if (kcd->is_ortho) { + interp_v3_v3v3(r_co, v1, v2, lambda_ss); + } + else { + /* transform into screen-space, interp, then transform back */ + float v1_ss[3], v2_ss[3]; + + mul_v3_project_m4_v3(v1_ss, (float(*)[4])kcd->projmat, v1); + mul_v3_project_m4_v3(v2_ss, (float(*)[4])kcd->projmat, v2); - return min_ff(maxsize / (density * 0.5f), maxsize); + interp_v3_v3v3(r_co, v1_ss, v2_ss, lambda_ss); + + mul_project_m4_v3((float(*)[4])kcd->projmat_inv, r_co); + } } /* p is closest point on edge to the mouse cursor */ @@ -2009,15 +2355,15 @@ static KnifeEdge *knife_find_closest_edge_of_face(KnifeTool_OpData *kcd, const float maxdist_sq = maxdist * maxdist; KnifeEdge *cure = NULL; float cur_cagep[3]; - ListBase *lst; + ListBase *list; Ref *ref; - float dis_sq, curdis_sq = FLT_MAX; + float dis_sq, curdis_sq = maxdist_sq; knife_project_v2(kcd, cagep, sco); /* look through all edges associated with this face */ - lst = knife_get_face_kedges(kcd, f); - for (ref = lst->first; ref; ref = ref->next) { + list = knife_get_face_kedges(kcd, f); + for (ref = list->first; ref; ref = ref->next) { KnifeEdge *kfe = ref->ref; float kfv1_sco[2], kfv2_sco[2], test_cagep[3]; float lambda; @@ -2028,27 +2374,14 @@ static KnifeEdge *knife_find_closest_edge_of_face(KnifeTool_OpData *kcd, /* check if we're close enough and calculate 'lambda' */ if (kcd->is_angle_snapping) { - /* if snapping, check we're in bounds */ - float sco_snap[2]; - isect_line_line_v2_point(kfv1_sco, kfv2_sco, kcd->prev.mval, kcd->curr.mval, sco_snap); - lambda = line_point_factor_v2(sco_snap, kfv1_sco, kfv2_sco); - - /* be strict about angle-snapping within edge */ - if ((lambda < 0.0f - KNIFE_FLT_EPSBIG) || (lambda > 1.0f + KNIFE_FLT_EPSBIG)) { - continue; - } - - dis_sq = len_squared_v2v2(sco, sco_snap); - if (dis_sq < curdis_sq && dis_sq < maxdist_sq) { - /* we already have 'lambda' */ - } - else { + dis_sq = curdis_sq; + if (!knife_snap_edge_in_angle(kcd, sco, kfv1_sco, kfv2_sco, &dis_sq, &lambda)) { continue; } } else { dis_sq = dist_squared_to_line_segment_v2(sco, kfv1_sco, kfv2_sco); - if (dis_sq < curdis_sq && dis_sq < maxdist_sq) { + if (dis_sq < curdis_sq) { lambda = line_point_factor_v2(sco, kfv1_sco, kfv2_sco); } else { @@ -2071,36 +2404,31 @@ static KnifeEdge *knife_find_closest_edge_of_face(KnifeTool_OpData *kcd, copy_v3_v3(cur_cagep, test_cagep); } - if (cure) { - if (!kcd->ignore_edge_snapping || !(cure->e)) { - KnifeVert *edgesnap = NULL; + if (cure && !kcd->ignore_edge_snapping) { + KnifeVert *edgesnap = NULL; - if (kcd->snap_midpoints) { - mid_v3_v3v3(p, cure->v1->co, cure->v2->co); - mid_v3_v3v3(cagep, cure->v1->cageco, cure->v2->cageco); - } - else { - float lambda = line_point_factor_v3(cur_cagep, cure->v1->cageco, cure->v2->cageco); - copy_v3_v3(cagep, cur_cagep); - interp_v3_v3v3(p, cure->v1->co, cure->v2->co, lambda); - } - - /* update mouse coordinates to the snapped-to edge's screen coordinates - * this is important for angle snap, which uses the previous mouse position */ - edgesnap = new_knife_vert(kcd, p, cagep); - knife_project_v2(kcd, edgesnap->cageco, kcd->curr.mval); + if (kcd->snap_midpoints) { + mid_v3_v3v3(p, cure->v1->co, cure->v2->co); + mid_v3_v3v3(cagep, cure->v1->cageco, cure->v2->cageco); } else { - return NULL; + float lambda = line_point_factor_v3(cur_cagep, cure->v1->cageco, cure->v2->cageco); + copy_v3_v3(cagep, cur_cagep); + interp_v3_v3v3(p, cure->v1->co, cure->v2->co, lambda); } + + /* update mouse coordinates to the snapped-to edge's screen coordinates + * this is important for angle snap, which uses the previous mouse position */ + edgesnap = new_knife_vert(kcd, p, cagep); + knife_project_v2(kcd, edgesnap->cageco, kcd->curr.mval); } return cure; } /* find a vertex near the mouse cursor, if it exists */ -static KnifeVert *knife_find_closest_vert_of_face(KnifeTool_OpData *kcd, - BMFace *f, +static KnifeVert *knife_find_closest_vert_of_edge(KnifeTool_OpData *kcd, + KnifeEdge *kfe, float p[3], float cagep[3]) { @@ -2118,60 +2446,48 @@ static KnifeVert *knife_find_closest_vert_of_face(KnifeTool_OpData *kcd, } const float maxdist_sq = maxdist * maxdist; - ListBase *lst; - Ref *ref; KnifeVert *curv = NULL; float cur_kfv_sco[2]; float dis_sq, curdis_sq = FLT_MAX; knife_project_v2(kcd, cagep, sco); - lst = knife_get_face_kedges(kcd, f); - for (ref = lst->first; ref; ref = ref->next) { - KnifeEdge *kfe = ref->ref; - int i; + for (int i = 0; i < 2; i++) { + KnifeVert *kfv = i ? kfe->v2 : kfe->v1; + float kfv_sco[2]; - for (i = 0; i < 2; i++) { - KnifeVert *kfv = i ? kfe->v2 : kfe->v1; - float kfv_sco[2]; + knife_project_v2(kcd, kfv->cageco, kfv_sco); - knife_project_v2(kcd, kfv->cageco, kfv_sco); - - /* be strict about angle snapping, the vertex needs to be very close to the angle, - * or we ignore */ - if (kcd->is_angle_snapping) { - if (dist_squared_to_line_segment_v2(kfv_sco, kcd->prev.mval, kcd->curr.mval) > - KNIFE_FLT_EPSBIG) { - continue; - } + /* be strict about angle snapping, the vertex needs to be very close to the angle, + * or we ignore */ + if (kcd->is_angle_snapping) { + if (dist_squared_to_line_segment_v2(kfv_sco, kcd->prev.mval, kcd->curr.mval) > + KNIFE_FLT_EPSBIG) { + continue; } + } - dis_sq = len_squared_v2v2(kfv_sco, sco); - if (dis_sq < curdis_sq && dis_sq < maxdist_sq) { - if (!RV3D_CLIPPING_ENABLED(kcd->vc.v3d, kcd->vc.rv3d) || - !ED_view3d_clipping_test(kcd->vc.rv3d, kfv->cageco, true)) { - curv = kfv; - curdis_sq = dis_sq; - copy_v2_v2(cur_kfv_sco, kfv_sco); - } + dis_sq = len_squared_v2v2(kfv_sco, sco); + if (dis_sq < curdis_sq && dis_sq < maxdist_sq) { + if (!RV3D_CLIPPING_ENABLED(kcd->vc.v3d, kcd->vc.rv3d) || + !ED_view3d_clipping_test(kcd->vc.rv3d, kfv->cageco, true)) { + curv = kfv; + curdis_sq = dis_sq; + copy_v2_v2(cur_kfv_sco, kfv_sco); } } } - if (!kcd->ignore_vert_snapping || !(curv && curv->v)) { - if (curv) { - copy_v3_v3(p, curv->co); - copy_v3_v3(cagep, curv->cageco); + if (curv && !kcd->ignore_vert_snapping) { + copy_v3_v3(p, curv->co); + copy_v3_v3(cagep, curv->cageco); - /* update mouse coordinates to the snapped-to vertex's screen coordinates - * this is important for angle snap, which uses the previous mouse position */ - copy_v2_v2(kcd->curr.mval, cur_kfv_sco); - } - - return curv; + /* update mouse coordinates to the snapped-to vertex's screen coordinates + * this is important for angle snap, which uses the previous mouse position */ + copy_v2_v2(kcd->curr.mval, cur_kfv_sco); } - return NULL; + return curv; } /** @@ -2215,7 +2531,15 @@ static bool knife_snap_angle(KnifeTool_OpData *kcd) return true; } -static void knife_snap_update_from_mval(KnifeTool_OpData *kcd, const float mval[2]) +/** + * \return true when `kcd->curr.co` & `kcd->curr.cage` are set. + * + * In this case `is_space` is nearly always false. + * There are some situations when vertex or edge can be snapped to, when `is_space` is true. + * In this case the selection-buffer is used to select the face, + * then the closest `vert` or `edge` is set, and those will enable `is_co_set`. + */ +static bool knife_snap_update_from_mval(KnifeTool_OpData *kcd, const float mval[2]) { knife_pos_data_clear(&kcd->curr); copy_v2_v2(kcd->curr.mval, mval); @@ -2230,410 +2554,33 @@ static void knife_snap_update_from_mval(KnifeTool_OpData *kcd, const float mval[ kcd->is_angle_snapping = false; } - kcd->curr.bmface = knife_find_closest_face( - kcd, kcd->curr.co, kcd->curr.cage, &kcd->curr.is_space); - - if (kcd->curr.bmface) { - kcd->curr.vert = knife_find_closest_vert_of_face( - kcd, kcd->curr.bmface, kcd->curr.co, kcd->curr.cage); + { + kcd->curr.bmface = knife_find_closest_face( + kcd, kcd->curr.co, kcd->curr.cage, &kcd->curr.is_space); - if (!kcd->curr.vert && - /* no edge snapping while dragging (edges are too sticky when cuts are immediate) */ - !kcd->is_drag_hold) { + if (kcd->curr.bmface) { kcd->curr.edge = knife_find_closest_edge_of_face( kcd, kcd->curr.bmface, kcd->curr.co, kcd->curr.cage); } - } -} - -/* update active knife edge/vert pointers */ -static int knife_update_active(KnifeTool_OpData *kcd) -{ - knife_snap_update_from_mval(kcd, kcd->mval); - - /* if no hits are found this would normally default to (0, 0, 0) so instead - * get a point at the mouse ray closest to the previous point. - * Note that drawing lines in `free-space` isn't properly supported - * but there's no guarantee (0, 0, 0) has any geometry either - campbell */ - if (kcd->curr.vert == NULL && kcd->curr.edge == NULL && kcd->curr.bmface == NULL) { - float origin[3]; - float origin_ofs[3]; - - knife_input_ray_segment(kcd, kcd->curr.mval, 1.0f, origin, origin_ofs); - - if (!isect_line_plane_v3( - kcd->curr.cage, origin, origin_ofs, kcd->prev.cage, kcd->proj_zaxis)) { - copy_v3_v3(kcd->curr.cage, kcd->prev.cage); - - /* should never fail! */ - BLI_assert(0); - } - } - - if (kcd->mode == MODE_DRAGGING) { - knife_find_line_hits(kcd); - } - return 1; -} - -static int sort_verts_by_dist_cb(void *co_p, const void *cur_a_p, const void *cur_b_p) -{ - const KnifeVert *cur_a = ((const Ref *)cur_a_p)->ref; - const KnifeVert *cur_b = ((const Ref *)cur_b_p)->ref; - const float *co = co_p; - const float a_sq = len_squared_v3v3(co, cur_a->co); - const float b_sq = len_squared_v3v3(co, cur_b->co); - - if (a_sq < b_sq) { - return -1; - } - if (a_sq > b_sq) { - return 1; - } - return 0; -} - -static bool knife_verts_edge_in_face(KnifeVert *v1, KnifeVert *v2, BMFace *f) -{ - bool v1_inside, v2_inside; - bool v1_inface, v2_inface; - BMLoop *l1, *l2; - - if (!f || !v1 || !v2) { - return false; - } - - l1 = v1->v ? BM_face_vert_share_loop(f, v1->v) : NULL; - l2 = v2->v ? BM_face_vert_share_loop(f, v2->v) : NULL; - - if ((l1 && l2) && BM_loop_is_adjacent(l1, l2)) { - /* boundary-case, always false to avoid edge-in-face checks below */ - return false; - } - - /* find out if v1 and v2, if set, are part of the face */ - v1_inface = (l1 != NULL); - v2_inface = (l2 != NULL); - - /* BM_face_point_inside_test uses best-axis projection so this isn't most accurate test... */ - v1_inside = v1_inface ? false : BM_face_point_inside_test(f, v1->co); - v2_inside = v2_inface ? false : BM_face_point_inside_test(f, v2->co); - if ((v1_inface && v2_inside) || (v2_inface && v1_inside) || (v1_inside && v2_inside)) { - return true; - } - - if (v1_inface && v2_inface) { - float mid[3]; - /* Can have case where v1 and v2 are on shared chain between two faces. - * BM_face_splits_check_legal does visibility and self-intersection tests, - * but it is expensive and maybe a bit buggy, so use a simple - * "is the midpoint in the face" test */ - mid_v3_v3v3(mid, v1->co, v2->co); - return BM_face_point_inside_test(f, mid); - } - return false; -} - -static void knife_make_face_cuts(KnifeTool_OpData *kcd, BMFace *f, ListBase *kfedges) -{ - BMesh *bm = kcd->em->bm; - KnifeEdge *kfe; - Ref *ref; - int edge_array_len = BLI_listbase_count(kfedges); - int i; - - BMEdge **edge_array = BLI_array_alloca(edge_array, edge_array_len); - - /* point to knife edges we've created edges in, edge_array aligned */ - KnifeEdge **kfe_array = BLI_array_alloca(kfe_array, edge_array_len); - - BLI_assert(BLI_gset_len(kcd->edgenet.edge_visit) == 0); - - i = 0; - for (ref = kfedges->first; ref; ref = ref->next) { - bool is_new_edge = false; - kfe = ref->ref; - - if (kfe->e == NULL) { - if (kfe->v1->v && kfe->v2->v) { - kfe->e = BM_edge_exists(kfe->v1->v, kfe->v2->v); - } - } - - if (kfe->e) { - if (BM_edge_in_face(kfe->e, f)) { - /* shouldn't happen, but in this case - just ignore */ - continue; - } - } - else { - if (kfe->v1->v == NULL) { - kfe->v1->v = BM_vert_create(bm, kfe->v1->co, NULL, 0); - } - if (kfe->v2->v == NULL) { - kfe->v2->v = BM_vert_create(bm, kfe->v2->co, NULL, 0); - } - BLI_assert(kfe->e == NULL); - kfe->e = BM_edge_create(bm, kfe->v1->v, kfe->v2->v, NULL, 0); - if (kfe->e) { - if (kcd->select_result || BM_elem_flag_test(f, BM_ELEM_SELECT)) { - BM_edge_select_set(bm, kfe->e, true); - } - is_new_edge = true; - } - } - - BLI_assert(kfe->e); - - if (BLI_gset_add(kcd->edgenet.edge_visit, kfe->e)) { - kfe_array[i] = is_new_edge ? kfe : 0; - edge_array[i] = kfe->e; - i += 1; - } - } - - if (i) { - const int edge_array_len_orig = i; - edge_array_len = i; - -#ifdef USE_NET_ISLAND_CONNECT - uint edge_array_holes_len; - BMEdge **edge_array_holes; - if (BM_face_split_edgenet_connect_islands(bm, - f, - edge_array, - edge_array_len, - true, - kcd->edgenet.arena, - &edge_array_holes, - &edge_array_holes_len)) { - if (BM_elem_flag_test(f, BM_ELEM_SELECT)) { - for (i = edge_array_len; i < edge_array_holes_len; i++) { - BM_edge_select_set(bm, edge_array_holes[i], true); - } - } - - edge_array_len = edge_array_holes_len; - edge_array = edge_array_holes; /* owned by the arena */ - } -#endif - - { - BMFace **face_arr = NULL; - int face_arr_len; - BM_face_split_edgenet(bm, f, edge_array, edge_array_len, &face_arr, &face_arr_len); + if (kcd->curr.edge) { + kcd->curr.vert = knife_find_closest_vert_of_edge( + kcd, kcd->curr.edge, kcd->curr.co, kcd->curr.cage); - if (face_arr) { - MEM_freeN(face_arr); + if (kcd->ignore_edge_snapping) { + kcd->curr.edge = NULL; } } - - /* remove dangling edges, not essential - but nice for users */ - for (i = 0; i < edge_array_len_orig; i++) { - if (kfe_array[i]) { - if (BM_edge_is_wire(kfe_array[i]->e)) { - BM_edge_kill(bm, kfe_array[i]->e); - kfe_array[i]->e = NULL; - } - } - } - -#ifdef USE_NET_ISLAND_CONNECT - BLI_memarena_clear(kcd->edgenet.arena); -#endif } - BLI_gset_clear(kcd->edgenet.edge_visit, NULL); + return kcd->curr.vert || kcd->curr.edge || (kcd->curr.bmface && !kcd->curr.is_space); } -/* Use the network of KnifeEdges and KnifeVerts accumulated to make real BMVerts and BMEdedges */ -static void knife_make_cuts(KnifeTool_OpData *kcd) -{ - BMesh *bm = kcd->em->bm; - KnifeEdge *kfe; - KnifeVert *kfv; - BMFace *f; - BMEdge *e, *enew; - ListBase *lst; - Ref *ref; - float pct; - SmallHashIter hiter; - BLI_mempool_iter iter; - SmallHash fhash_, *fhash = &fhash_; - SmallHash ehash_, *ehash = &ehash_; - - BLI_smallhash_init(fhash); - BLI_smallhash_init(ehash); - - /* put list of cutting edges for a face into fhash, keyed by face */ - BLI_mempool_iternew(kcd->kedges, &iter); - for (kfe = BLI_mempool_iterstep(&iter); kfe; kfe = BLI_mempool_iterstep(&iter)) { - - /* select edges that lie directly on the cut */ - if (kcd->select_result) { - if (kfe->e && kfe->is_cut) { - BM_edge_select_set(bm, kfe->e, true); - } - } - - f = kfe->basef; - if (!f || kfe->e) { - continue; - } - lst = BLI_smallhash_lookup(fhash, (uintptr_t)f); - if (!lst) { - lst = knife_empty_list(kcd); - BLI_smallhash_insert(fhash, (uintptr_t)f, lst); - } - knife_append_list(kcd, lst, kfe); - } - - /* put list of splitting vertices for an edge into ehash, keyed by edge */ - BLI_mempool_iternew(kcd->kverts, &iter); - for (kfv = BLI_mempool_iterstep(&iter); kfv; kfv = BLI_mempool_iterstep(&iter)) { - if (kfv->v) { - continue; /* already have a BMVert */ - } - for (ref = kfv->edges.first; ref; ref = ref->next) { - kfe = ref->ref; - e = kfe->e; - if (!e) { - continue; - } - lst = BLI_smallhash_lookup(ehash, (uintptr_t)e); - if (!lst) { - lst = knife_empty_list(kcd); - BLI_smallhash_insert(ehash, (uintptr_t)e, lst); - } - /* there can be more than one kfe in kfv's list with same e */ - if (!find_ref(lst, kfv)) { - knife_append_list(kcd, lst, kfv); - } - } - } - - /* split bmesh edges where needed */ - for (lst = BLI_smallhash_iternew(ehash, &hiter, (uintptr_t *)&e); lst; - lst = BLI_smallhash_iternext(&hiter, (uintptr_t *)&e)) { - BLI_listbase_sort_r(lst, sort_verts_by_dist_cb, e->v1->co); - - for (ref = lst->first; ref; ref = ref->next) { - kfv = ref->ref; - pct = line_point_factor_v3(kfv->co, e->v1->co, e->v2->co); - kfv->v = BM_edge_split(bm, e, e->v1, &enew, pct); - } - } - - if (kcd->only_select) { - EDBM_flag_disable_all(kcd->em, BM_ELEM_SELECT); - } - - /* do cuts for each face */ - for (lst = BLI_smallhash_iternew(fhash, &hiter, (uintptr_t *)&f); lst; - lst = BLI_smallhash_iternext(&hiter, (uintptr_t *)&f)) { - knife_make_face_cuts(kcd, f, lst); - } - - BLI_smallhash_release(fhash); - BLI_smallhash_release(ehash); -} - -/* called on tool confirmation */ -static void knifetool_finish_ex(KnifeTool_OpData *kcd) -{ - knife_make_cuts(kcd); - - EDBM_selectmode_flush(kcd->em); - EDBM_mesh_normals_update(kcd->em); - EDBM_update_generic(kcd->ob->data, true, true); - - /* Re-tessellating makes this invalid, don't use again by accident. */ - knifetool_free_bmbvh(kcd); -} -static void knifetool_finish(wmOperator *op) -{ - KnifeTool_OpData *kcd = op->customdata; - knifetool_finish_ex(kcd); -} - -static void knife_recalc_projmat(KnifeTool_OpData *kcd) -{ - invert_m4_m4(kcd->ob->imat, kcd->ob->obmat); - ED_view3d_ob_project_mat_get(kcd->region->regiondata, kcd->ob, kcd->projmat); - invert_m4_m4(kcd->projmat_inv, kcd->projmat); - - mul_v3_mat3_m4v3(kcd->proj_zaxis, kcd->ob->imat, kcd->vc.rv3d->viewinv[2]); - normalize_v3(kcd->proj_zaxis); - - kcd->is_ortho = ED_view3d_clip_range_get( - kcd->vc.depsgraph, kcd->vc.v3d, kcd->vc.rv3d, &kcd->clipsta, &kcd->clipend, true); -} - -/* called when modal loop selection is done... */ -static void knifetool_exit_ex(bContext *C, KnifeTool_OpData *kcd) -{ - if (!kcd) { - return; - } - - if (kcd->is_interactive) { - WM_cursor_modal_restore(CTX_wm_window(C)); - - /* deactivate the extra drawing stuff in 3D-View */ - ED_region_draw_cb_exit(kcd->region->type, kcd->draw_handle); - } - - /* free the custom data */ - BLI_mempool_destroy(kcd->refs); - BLI_mempool_destroy(kcd->kverts); - BLI_mempool_destroy(kcd->kedges); - - BLI_ghash_free(kcd->origedgemap, NULL, NULL); - BLI_ghash_free(kcd->origvertmap, NULL, NULL); - BLI_ghash_free(kcd->kedgefacemap, NULL, NULL); - BLI_ghash_free(kcd->facetrimap, NULL, NULL); - - BLI_memarena_free(kcd->arena); -#ifdef USE_NET_ISLAND_CONNECT - BLI_memarena_free(kcd->edgenet.arena); -#endif - BLI_gset_free(kcd->edgenet.edge_visit, NULL); - - /* tag for redraw */ - ED_region_tag_redraw(kcd->region); - - knifetool_free_bmbvh(kcd); - - if (kcd->linehits) { - MEM_freeN(kcd->linehits); - } - - /* destroy kcd itself */ - MEM_freeN(kcd); -} -static void knifetool_exit(bContext *C, wmOperator *op) -{ - KnifeTool_OpData *kcd = op->customdata; - knifetool_exit_ex(C, kcd); - op->customdata = NULL; -} - -static void knifetool_update_mval(KnifeTool_OpData *kcd, const float mval[2]) -{ - knife_recalc_projmat(kcd); - copy_v2_v2(kcd->mval, mval); - - if (knife_update_active(kcd)) { - ED_region_tag_redraw(kcd->region); - } -} +/** \} */ -static void knifetool_update_mval_i(KnifeTool_OpData *kcd, const int mval_i[2]) -{ - const float mval[2] = {UNPACK2(mval_i)}; - knifetool_update_mval(kcd, mval); -} +/* -------------------------------------------------------------------- */ +/** \name #KnifeTool_OpData (#op->customdata) Init and Free + * \{ */ static void knifetool_init_bmbvh(KnifeTool_OpData *kcd) { @@ -2667,6 +2614,21 @@ static void knifetool_free_bmbvh(KnifeTool_OpData *kcd) } } +static void knife_init_colors(KnifeColors *colors) +{ + /* possible BMESH_TODO: add explicit themes or calculate these by + * figuring out contrasting colors with grid / edges / verts + * a la UI_make_axis_color */ + UI_GetThemeColorType3ubv(TH_NURB_VLINE, SPACE_VIEW3D, colors->line); + UI_GetThemeColorType3ubv(TH_NURB_ULINE, SPACE_VIEW3D, colors->edge); + UI_GetThemeColorType3ubv(TH_HANDLE_SEL_VECT, SPACE_VIEW3D, colors->curpoint); + UI_GetThemeColorType3ubv(TH_HANDLE_SEL_VECT, SPACE_VIEW3D, colors->curpoint_a); + colors->curpoint_a[3] = 102; + UI_GetThemeColorType3ubv(TH_ACTIVE_SPLINE, SPACE_VIEW3D, colors->point); + UI_GetThemeColorType3ubv(TH_ACTIVE_SPLINE, SPACE_VIEW3D, colors->point_a); + colors->point_a[3] = 102; +} + /* called when modal loop selection gets set up... */ static void knifetool_init(bContext *C, KnifeTool_OpData *kcd, @@ -2690,6 +2652,7 @@ static void knifetool_init(bContext *C, kcd->is_interactive = is_interactive; kcd->cut_through = cut_through; kcd->only_select = only_select; + kcd->mode = MODE_INVOKING; knifetool_init_bmbvh(kcd); @@ -2729,57 +2692,140 @@ static void knifetool_init(bContext *C, } } -static void knifetool_cancel(bContext *C, wmOperator *op) +/* called when modal loop selection is done... */ +static void knifetool_exit_ex(bContext *C, KnifeTool_OpData *kcd) { - /* this is just a wrapper around exit() */ - knifetool_exit(C, op); + if (!kcd) { + return; + } + + if (kcd->is_interactive) { + WM_cursor_modal_restore(CTX_wm_window(C)); + + /* deactivate the extra drawing stuff in 3D-View */ + ED_region_draw_cb_exit(kcd->region->type, kcd->draw_handle); + } + + /* free the custom data */ + BLI_mempool_destroy(kcd->refs); + BLI_mempool_destroy(kcd->kverts); + BLI_mempool_destroy(kcd->kedges); + + BLI_ghash_free(kcd->origedgemap, NULL, NULL); + BLI_ghash_free(kcd->origvertmap, NULL, NULL); + BLI_ghash_free(kcd->kedgefacemap, NULL, NULL); + BLI_ghash_free(kcd->facetrimap, NULL, NULL); + + BLI_memarena_free(kcd->arena); +#ifdef USE_NET_ISLAND_CONNECT + BLI_memarena_free(kcd->edgenet.arena); +#endif + BLI_gset_free(kcd->edgenet.edge_visit, NULL); + + /* tag for redraw */ + ED_region_tag_redraw(kcd->region); + + knifetool_free_bmbvh(kcd); + + if (kcd->linehits) { + MEM_freeN(kcd->linehits); + } + + /* destroy kcd itself */ + MEM_freeN(kcd); +} +static void knifetool_exit(bContext *C, wmOperator *op) +{ + KnifeTool_OpData *kcd = op->customdata; + knifetool_exit_ex(C, kcd); + op->customdata = NULL; } -static int knifetool_invoke(bContext *C, wmOperator *op, const wmEvent *event) +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Mouse-Moving Event Updates + * \{ */ + +/* update active knife edge/vert pointers */ +static int knife_update_active(KnifeTool_OpData *kcd) { - const bool only_select = RNA_boolean_get(op->ptr, "only_selected"); - const bool cut_through = !RNA_boolean_get(op->ptr, "use_occlude_geometry"); - const bool wait_for_input = RNA_boolean_get(op->ptr, "wait_for_input"); + /* if no hits are found this would normally default to (0, 0, 0) so instead + * get a point at the mouse ray closest to the previous point. + * Note that drawing lines in `free-space` isn't properly supported + * but there's no guarantee (0, 0, 0) has any geometry either - campbell */ + if (!knife_snap_update_from_mval(kcd, kcd->mval)) { + float origin[3]; + float origin_ofs[3]; - KnifeTool_OpData *kcd; + knife_input_ray_segment(kcd, kcd->curr.mval, 1.0f, origin, origin_ofs); - if (only_select) { - Object *obedit = CTX_data_edit_object(C); - BMEditMesh *em = BKE_editmesh_from_object(obedit); - if (em->bm->totfacesel == 0) { - BKE_report(op->reports, RPT_ERROR, "Selected faces required"); - return OPERATOR_CANCELLED; + if (!isect_line_plane_v3( + kcd->curr.cage, origin, origin_ofs, kcd->prev.cage, kcd->proj_zaxis)) { + copy_v3_v3(kcd->curr.cage, kcd->prev.cage); + + /* should never fail! */ + BLI_assert(0); } } - /* alloc new customdata */ - kcd = op->customdata = MEM_callocN(sizeof(KnifeTool_OpData), __func__); + if (kcd->mode == MODE_DRAGGING) { + knife_find_line_hits(kcd); + } + return 1; +} - knifetool_init(C, kcd, only_select, cut_through, true); +static void knifetool_update_mval(KnifeTool_OpData *kcd, const float mval[2]) +{ + knife_recalc_projmat(kcd); + copy_v2_v2(kcd->mval, mval); - op->flag |= OP_IS_MODAL_CURSOR_REGION; + if (knife_update_active(kcd)) { + ED_region_tag_redraw(kcd->region); + } +} - /* add a modal handler for this operator - handles loop selection */ - WM_cursor_modal_set(CTX_wm_window(C), WM_CURSOR_KNIFE); - WM_event_add_modal_handler(C, op); +static void knifetool_update_mval_i(KnifeTool_OpData *kcd, const int mval_i[2]) +{ + const float mval[2] = {UNPACK2(mval_i)}; + knifetool_update_mval(kcd, mval); +} - knifetool_update_mval_i(kcd, event->mval); +/** \} */ - if (wait_for_input == false) { - /* Avoid copy-paste logic. */ - wmEvent event_modal = { - .prevval = KM_NOTHING, - .type = EVT_MODAL_MAP, - .val = KNF_MODAL_ADD_CUT, - }; - int ret = knifetool_modal(C, op, &event_modal); - BLI_assert(ret == OPERATOR_RUNNING_MODAL); - UNUSED_VARS_NDEBUG(ret); - } +/* -------------------------------------------------------------------- */ +/** \name Finalization + * \{ */ - knife_update_header(C, op, kcd); +/* called on tool confirmation */ +static void knifetool_finish_ex(KnifeTool_OpData *kcd) +{ + knife_make_cuts(kcd); - return OPERATOR_RUNNING_MODAL; + EDBM_selectmode_flush(kcd->em); + EDBM_mesh_normals_update(kcd->em); + EDBM_update_generic(kcd->ob->data, true, true); + + /* Re-tessellating makes this invalid, don't use again by accident. */ + knifetool_free_bmbvh(kcd); +} + +static void knifetool_finish(wmOperator *op) +{ + KnifeTool_OpData *kcd = op->customdata; + knifetool_finish_ex(kcd); +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Operator (#MESH_OT_knife_tool) + * \{ */ + +static void knifetool_cancel(bContext *C, wmOperator *op) +{ + /* this is just a wrapper around exit() */ + knifetool_exit(C, op); } wmKeyMap *knifetool_modal_keymap(wmKeyConfig *keyconf) @@ -2789,8 +2835,8 @@ wmKeyMap *knifetool_modal_keymap(wmKeyConfig *keyconf) {KNF_MODAL_CONFIRM, "CONFIRM", 0, "Confirm", ""}, {KNF_MODAL_MIDPOINT_ON, "SNAP_MIDPOINTS_ON", 0, "Snap to Midpoints On", ""}, {KNF_MODAL_MIDPOINT_OFF, "SNAP_MIDPOINTS_OFF", 0, "Snap to Midpoints Off", ""}, - {KNF_MODEL_IGNORE_SNAP_ON, "IGNORE_SNAP_ON", 0, "Ignore Snapping On", ""}, - {KNF_MODEL_IGNORE_SNAP_OFF, "IGNORE_SNAP_OFF", 0, "Ignore Snapping Off", ""}, + {KNF_MODAL_IGNORE_SNAP_ON, "IGNORE_SNAP_ON", 0, "Ignore Snapping On", ""}, + {KNF_MODAL_IGNORE_SNAP_OFF, "IGNORE_SNAP_OFF", 0, "Ignore Snapping Off", ""}, {KNF_MODAL_ANGLE_SNAP_TOGGLE, "ANGLE_SNAP_TOGGLE", 0, "Toggle Angle Snapping", ""}, {KNF_MODAL_CUT_THROUGH_TOGGLE, "CUT_THROUGH_TOGGLE", 0, "Toggle Cut Through", ""}, {KNF_MODAL_NEW_CUT, "NEW_CUT", 0, "End Current Cut", ""}, @@ -2873,13 +2919,13 @@ static int knifetool_modal(bContext *C, wmOperator *op, const wmEvent *event) ED_region_tag_redraw(kcd->region); do_refresh = true; break; - case KNF_MODEL_IGNORE_SNAP_ON: + case KNF_MODAL_IGNORE_SNAP_ON: ED_region_tag_redraw(kcd->region); kcd->ignore_vert_snapping = kcd->ignore_edge_snapping = true; knife_update_header(C, op, kcd); do_refresh = true; break; - case KNF_MODEL_IGNORE_SNAP_OFF: + case KNF_MODAL_IGNORE_SNAP_OFF: ED_region_tag_redraw(kcd->region); kcd->ignore_vert_snapping = kcd->ignore_edge_snapping = false; knife_update_header(C, op, kcd); @@ -2917,10 +2963,13 @@ static int knifetool_modal(bContext *C, wmOperator *op, const wmEvent *event) /* freehand drawing is incompatible with cut-through */ if (kcd->cut_through == false) { kcd->is_drag_hold = true; + /* No edge snapping while dragging (edges are too sticky when cuts are immediate). */ + kcd->ignore_edge_snapping = true; } } else { kcd->is_drag_hold = false; + kcd->ignore_edge_snapping = false; /* needed because the last face 'hit' is ignored when dragging */ knifetool_update_mval(kcd, kcd->curr.mval); @@ -3006,6 +3055,53 @@ static int knifetool_modal(bContext *C, wmOperator *op, const wmEvent *event) return OPERATOR_RUNNING_MODAL; } +static int knifetool_invoke(bContext *C, wmOperator *op, const wmEvent *event) +{ + const bool only_select = RNA_boolean_get(op->ptr, "only_selected"); + const bool cut_through = !RNA_boolean_get(op->ptr, "use_occlude_geometry"); + const bool wait_for_input = RNA_boolean_get(op->ptr, "wait_for_input"); + + KnifeTool_OpData *kcd; + + if (only_select) { + Object *obedit = CTX_data_edit_object(C); + BMEditMesh *em = BKE_editmesh_from_object(obedit); + if (em->bm->totfacesel == 0) { + BKE_report(op->reports, RPT_ERROR, "Selected faces required"); + return OPERATOR_CANCELLED; + } + } + + /* alloc new customdata */ + kcd = op->customdata = MEM_callocN(sizeof(KnifeTool_OpData), __func__); + + knifetool_init(C, kcd, only_select, cut_through, true); + + op->flag |= OP_IS_MODAL_CURSOR_REGION; + + /* add a modal handler for this operator - handles loop selection */ + WM_cursor_modal_set(CTX_wm_window(C), WM_CURSOR_KNIFE); + WM_event_add_modal_handler(C, op); + + knifetool_update_mval_i(kcd, event->mval); + + if (wait_for_input == false) { + /* Avoid copy-paste logic. */ + wmEvent event_modal = { + .prevval = KM_NOTHING, + .type = EVT_MODAL_MAP, + .val = KNF_MODAL_ADD_CUT, + }; + int ret = knifetool_modal(C, op, &event_modal); + BLI_assert(ret == OPERATOR_RUNNING_MODAL); + UNUSED_VARS_NDEBUG(ret); + } + + knife_update_header(C, op, kcd); + + return OPERATOR_RUNNING_MODAL; +} + void MESH_OT_knife_tool(wmOperatorType *ot) { /* description */ @@ -3035,9 +3131,13 @@ void MESH_OT_knife_tool(wmOperatorType *ot) RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE); } +/** \} */ + /* -------------------------------------------------------------------- */ -/* Knife tool as a utility function - * that can be used for internal slicing operations */ +/** \name Knife tool as a utility function + * + * Can be used for internal slicing operations. + * \{ */ static bool edbm_mesh_knife_point_isect(LinkNode *polys, const float cent_ss[2]) { @@ -3212,3 +3312,5 @@ void EDBM_mesh_knife(bContext *C, LinkNode *polys, bool use_tag, bool cut_throug kcd = NULL; } } + +/** \} */ diff --git a/source/blender/editors/mesh/editmesh_path.c b/source/blender/editors/mesh/editmesh_path.c index 2cb8da37260..b7f671a4157 100644 --- a/source/blender/editors/mesh/editmesh_path.c +++ b/source/blender/editors/mesh/editmesh_path.c @@ -669,18 +669,17 @@ static int edbm_shortest_path_pick_invoke(bContext *C, wmOperator *op, const wmE return edbm_shortest_path_pick_exec(C, op); } - Base *basact = NULL; BMVert *eve = NULL; BMEdge *eed = NULL; BMFace *efa = NULL; ViewContext vc; - BMEditMesh *em; bool track_active = true; em_setup_viewcontext(C, &vc); copy_v2_v2_int(vc.mval, event->mval); - em = vc.em; + Base *basact = BASACT(vc.view_layer); + BMEditMesh *em = vc.em; view3d_operator_needs_opengl(C); diff --git a/source/blender/editors/mesh/editmesh_select.c b/source/blender/editors/mesh/editmesh_select.c index 35608a4abde..4864c7de123 100644 --- a/source/blender/editors/mesh/editmesh_select.c +++ b/source/blender/editors/mesh/editmesh_select.c @@ -268,7 +268,8 @@ static void findnearestvert__doClosest(void *userData, /** * Nearest vertex under the cursor. * - * \param r_dist: (in/out), minimal distance to the nearest and at the end, actual distance + * \param dist_px_manhattan_p: (in/out), minimal distance to the nearest and at the end, + * actual distance. * \param use_select_bias: * - When true, selected vertices are given a 5 pixel bias * to make them further than unselect verts. @@ -276,7 +277,7 @@ static void findnearestvert__doClosest(void *userData, * \param use_cycle: Cycle over elements within #FIND_NEAR_CYCLE_THRESHOLD_MIN in order of index. */ BMVert *EDBM_vert_find_nearest_ex(ViewContext *vc, - float *r_dist, + float *dist_px_manhattan_p, const bool use_select_bias, bool use_cycle, Base **bases, @@ -286,7 +287,8 @@ BMVert *EDBM_vert_find_nearest_ex(ViewContext *vc, uint base_index = 0; if (!XRAY_FLAG_ENABLED(vc->v3d)) { - uint dist_px = (uint)ED_view3d_backbuf_sample_size_clamp(vc->region, *r_dist); + uint dist_px_manhattan_test = (uint)ED_view3d_backbuf_sample_size_clamp(vc->region, + *dist_px_manhattan_p); uint index; BMVert *eve; @@ -295,7 +297,7 @@ BMVert *EDBM_vert_find_nearest_ex(ViewContext *vc, DRW_select_buffer_context_create(bases, bases_len, SCE_SELECT_VERTEX); index = DRW_select_buffer_find_nearest_to_point( - vc->depsgraph, vc->region, vc->v3d, vc->mval, 1, UINT_MAX, &dist_px); + vc->depsgraph, vc->region, vc->v3d, vc->mval, 1, UINT_MAX, &dist_px_manhattan_test); if (index) { eve = (BMVert *)edbm_select_id_bm_elem_get(bases, index, &base_index); @@ -306,11 +308,11 @@ BMVert *EDBM_vert_find_nearest_ex(ViewContext *vc, } if (eve) { - if (dist_px < *r_dist) { + if (dist_px_manhattan_test < *dist_px_manhattan_p) { if (r_base_index) { *r_base_index = base_index; } - *r_dist = dist_px; + *dist_px_manhattan_p = dist_px_manhattan_test; return eve; } } @@ -348,18 +350,19 @@ BMVert *EDBM_vert_find_nearest_ex(ViewContext *vc, data.cycle_index_prev = 0; } - data.hit.dist = data.hit_cycle.dist = data.hit.dist_bias = data.hit_cycle.dist_bias = *r_dist; + data.hit.dist = data.hit_cycle.dist = data.hit.dist_bias = data.hit_cycle.dist_bias = + *dist_px_manhattan_p; ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d); mesh_foreachScreenVert(vc, findnearestvert__doClosest, &data, clip_flag); hit = (data.use_cycle && data.hit_cycle.vert) ? &data.hit_cycle : &data.hit; - if (hit->dist < *r_dist) { + if (hit->dist < *dist_px_manhattan_p) { if (r_base_index) { *r_base_index = base_index; } - *r_dist = hit->dist; + *dist_px_manhattan_p = hit->dist; prev_select_bm = vc->em->bm; } } @@ -375,10 +378,10 @@ BMVert *EDBM_vert_find_nearest_ex(ViewContext *vc, return hit->vert; } -BMVert *EDBM_vert_find_nearest(ViewContext *vc, float *r_dist) +BMVert *EDBM_vert_find_nearest(ViewContext *vc, float *dist_px_manhattan_p) { Base *base = BKE_view_layer_base_find(vc->view_layer, vc->obact); - return EDBM_vert_find_nearest_ex(vc, r_dist, false, false, &base, 1, NULL); + return EDBM_vert_find_nearest_ex(vc, dist_px_manhattan_p, false, false, &base, 1, NULL); } /* find the distance to the edge we already have */ @@ -417,7 +420,7 @@ struct NearestEdgeUserData_Hit { /* edges only, un-biased manhattan distance to which ever edge we pick * (not used for choosing) */ - float dist_center; + float dist_center_px_manhattan; }; struct NearestEdgeUserData { @@ -477,7 +480,7 @@ static void find_nearest_edge__doClosest( data->hit.edge = eed; mid_v2_v2v2(screen_co_mid, screen_co_a, screen_co_b); - data->hit.dist_center = len_manhattan_v2v2(data->mval_fl, screen_co_mid); + data->hit.dist_center_px_manhattan = len_manhattan_v2v2(data->mval_fl, screen_co_mid); } if (data->use_cycle) { @@ -491,14 +494,14 @@ static void find_nearest_edge__doClosest( data->hit_cycle.edge = eed; mid_v2_v2v2(screen_co_mid, screen_co_a, screen_co_b); - data->hit_cycle.dist_center = len_manhattan_v2v2(data->mval_fl, screen_co_mid); + data->hit_cycle.dist_center_px_manhattan = len_manhattan_v2v2(data->mval_fl, screen_co_mid); } } } BMEdge *EDBM_edge_find_nearest_ex(ViewContext *vc, - float *r_dist, - float *r_dist_center, + float *dist_px_manhattan_p, + float *r_dist_center_px_manhattan, const bool use_select_bias, bool use_cycle, BMEdge **r_eed_zbuf, @@ -509,7 +512,8 @@ BMEdge *EDBM_edge_find_nearest_ex(ViewContext *vc, uint base_index = 0; if (!XRAY_FLAG_ENABLED(vc->v3d)) { - uint dist_px = (uint)ED_view3d_backbuf_sample_size_clamp(vc->region, *r_dist); + uint dist_px_manhattan_test = (uint)ED_view3d_backbuf_sample_size_clamp(vc->region, + *dist_px_manhattan_p); uint index; BMEdge *eed; @@ -518,7 +522,7 @@ BMEdge *EDBM_edge_find_nearest_ex(ViewContext *vc, DRW_select_buffer_context_create(bases, bases_len, SCE_SELECT_EDGE); index = DRW_select_buffer_find_nearest_to_point( - vc->depsgraph, vc->region, vc->v3d, vc->mval, 1, UINT_MAX, &dist_px); + vc->depsgraph, vc->region, vc->v3d, vc->mval, 1, UINT_MAX, &dist_px_manhattan_test); if (index) { eed = (BMEdge *)edbm_select_id_bm_elem_get(bases, index, &base_index); @@ -533,7 +537,7 @@ BMEdge *EDBM_edge_find_nearest_ex(ViewContext *vc, } /* exception for faces (verts don't need this) */ - if (r_dist_center && eed) { + if (r_dist_center_px_manhattan && eed) { struct NearestEdgeUserData_ZBuf data; data.mval_fl[0] = vc->mval[0]; @@ -546,16 +550,16 @@ BMEdge *EDBM_edge_find_nearest_ex(ViewContext *vc, mesh_foreachScreenEdge( vc, find_nearest_edge_center__doZBuf, &data, V3D_PROJ_TEST_CLIP_DEFAULT); - *r_dist_center = data.dist; + *r_dist_center_px_manhattan = data.dist; } /* end exception */ if (eed) { - if (dist_px < *r_dist) { + if (dist_px_manhattan_test < *dist_px_manhattan_p) { if (r_base_index) { *r_base_index = base_index; } - *r_dist = dist_px; + *dist_px_manhattan_p = dist_px_manhattan_test; return eed; } } @@ -593,18 +597,19 @@ BMEdge *EDBM_edge_find_nearest_ex(ViewContext *vc, data.cycle_index_prev = 0; } - data.hit.dist = data.hit_cycle.dist = data.hit.dist_bias = data.hit_cycle.dist_bias = *r_dist; + data.hit.dist = data.hit_cycle.dist = data.hit.dist_bias = data.hit_cycle.dist_bias = + *dist_px_manhattan_p; ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d); mesh_foreachScreenEdge(vc, find_nearest_edge__doClosest, &data, clip_flag); hit = (data.use_cycle && data.hit_cycle.edge) ? &data.hit_cycle : &data.hit; - if (hit->dist < *r_dist) { + if (hit->dist < *dist_px_manhattan_p) { if (r_base_index) { *r_base_index = base_index; } - *r_dist = hit->dist; + *dist_px_manhattan_p = hit->dist; prev_select_bm = vc->em->bm; } } @@ -613,8 +618,8 @@ BMEdge *EDBM_edge_find_nearest_ex(ViewContext *vc, return NULL; } - if (r_dist_center) { - *r_dist_center = hit->dist_center; + if (r_dist_center_px_manhattan) { + *r_dist_center_px_manhattan = hit->dist_center_px_manhattan; } prev_select.index = hit->index; @@ -624,16 +629,17 @@ BMEdge *EDBM_edge_find_nearest_ex(ViewContext *vc, return hit->edge; } -BMEdge *EDBM_edge_find_nearest(ViewContext *vc, float *r_dist) +BMEdge *EDBM_edge_find_nearest(ViewContext *vc, float *dist_px_manhattan_p) { Base *base = BKE_view_layer_base_find(vc->view_layer, vc->obact); - return EDBM_edge_find_nearest_ex(vc, r_dist, NULL, false, false, NULL, &base, 1, NULL); + return EDBM_edge_find_nearest_ex( + vc, dist_px_manhattan_p, NULL, false, false, NULL, &base, 1, NULL); } /* find the distance to the face we already have */ struct NearestFaceUserData_ZBuf { float mval_fl[2]; - float dist; + float dist_px_manhattan; const BMFace *face_test; }; @@ -647,8 +653,8 @@ static void find_nearest_face_center__doZBuf(void *userData, if (efa == data->face_test) { const float dist_test = len_manhattan_v2v2(data->mval_fl, screen_co); - if (dist_test < data->dist) { - data->dist = dist_test; + if (dist_test < data->dist_px_manhattan) { + data->dist_px_manhattan = dist_test; } } } @@ -702,9 +708,17 @@ static void findnearestface__doClosest(void *userData, } } +/** + * \param use_zbuf_single_px: Special case, when using the back-buffer selection, + * only use the pixel at `vc->mval` instead of using `dist_px_manhattan_p` to search over a larger + * region. This is needed because historically selection worked this way for a long time, however + * it's reasonable that some callers might want to expand the region too. So add an argument to do + * this, + */ BMFace *EDBM_face_find_nearest_ex(ViewContext *vc, - float *r_dist, + float *dist_px_manhattan_p, float *r_dist_center, + const bool use_zbuf_single_px, const bool use_select_bias, bool use_cycle, BMFace **r_efa_zbuf, @@ -715,14 +729,28 @@ BMFace *EDBM_face_find_nearest_ex(ViewContext *vc, uint base_index = 0; if (!XRAY_FLAG_ENABLED(vc->v3d)) { - float dist_test = 0.0f; + float dist_test; uint index; BMFace *efa; { + uint dist_px_manhattan_test = 0; + if (*dist_px_manhattan_p != 0.0f && (use_zbuf_single_px == false)) { + dist_px_manhattan_test = (uint)ED_view3d_backbuf_sample_size_clamp(vc->region, + *dist_px_manhattan_p); + } + DRW_select_buffer_context_create(bases, bases_len, SCE_SELECT_FACE); - index = DRW_select_buffer_sample_point(vc->depsgraph, vc->region, vc->v3d, vc->mval); + if (dist_px_manhattan_test == 0) { + index = DRW_select_buffer_sample_point(vc->depsgraph, vc->region, vc->v3d, vc->mval); + dist_test = 0.0f; + } + else { + index = DRW_select_buffer_find_nearest_to_point( + vc->depsgraph, vc->region, vc->v3d, vc->mval, 1, UINT_MAX, &dist_px_manhattan_test); + dist_test = dist_px_manhattan_test; + } if (index) { efa = (BMFace *)edbm_select_id_bm_elem_get(bases, index, &base_index); @@ -742,7 +770,7 @@ BMFace *EDBM_face_find_nearest_ex(ViewContext *vc, data.mval_fl[0] = vc->mval[0]; data.mval_fl[1] = vc->mval[1]; - data.dist = FLT_MAX; + data.dist_px_manhattan = FLT_MAX; data.face_test = efa; ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d); @@ -750,16 +778,16 @@ BMFace *EDBM_face_find_nearest_ex(ViewContext *vc, mesh_foreachScreenFace( vc, find_nearest_face_center__doZBuf, &data, V3D_PROJ_TEST_CLIP_DEFAULT); - *r_dist_center = data.dist; + *r_dist_center = data.dist_px_manhattan; } /* end exception */ if (efa) { - if (dist_test < *r_dist) { + if (dist_test < *dist_px_manhattan_p) { if (r_base_index) { *r_base_index = base_index; } - *r_dist = dist_test; + *dist_px_manhattan_p = dist_test; return efa; } } @@ -795,18 +823,19 @@ BMFace *EDBM_face_find_nearest_ex(ViewContext *vc, data.cycle_index_prev = 0; } - data.hit.dist = data.hit_cycle.dist = data.hit.dist_bias = data.hit_cycle.dist_bias = *r_dist; + data.hit.dist = data.hit_cycle.dist = data.hit.dist_bias = data.hit_cycle.dist_bias = + *dist_px_manhattan_p; ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d); mesh_foreachScreenFace(vc, findnearestface__doClosest, &data, clip_flag); hit = (data.use_cycle && data.hit_cycle.face) ? &data.hit_cycle : &data.hit; - if (hit->dist < *r_dist) { + if (hit->dist < *dist_px_manhattan_p) { if (r_base_index) { *r_base_index = base_index; } - *r_dist = hit->dist; + *dist_px_manhattan_p = hit->dist; prev_select_bm = vc->em->bm; } } @@ -826,10 +855,11 @@ BMFace *EDBM_face_find_nearest_ex(ViewContext *vc, return hit->face; } -BMFace *EDBM_face_find_nearest(ViewContext *vc, float *r_dist) +BMFace *EDBM_face_find_nearest(ViewContext *vc, float *dist_px_manhattan_p) { Base *base = BKE_view_layer_base_find(vc->view_layer, vc->obact); - return EDBM_face_find_nearest_ex(vc, r_dist, NULL, false, false, NULL, &base, 1, NULL); + return EDBM_face_find_nearest_ex( + vc, dist_px_manhattan_p, NULL, false, false, false, NULL, &base, 1, NULL); } #undef FIND_NEAR_SELECT_BIAS @@ -883,7 +913,7 @@ static bool unified_findnearest(ViewContext *vc, uint base_index = 0; BMFace *efa_zbuf = NULL; BMFace *efa_test = EDBM_face_find_nearest_ex( - vc, &dist, dist_center_p, true, use_cycle, &efa_zbuf, bases, bases_len, &base_index); + vc, &dist, dist_center_p, true, true, use_cycle, &efa_zbuf, bases, bases_len, &base_index); if (efa_test && dist_center_p) { dist = min_ff(dist_margin, dist_center); diff --git a/source/blender/editors/mesh/editmesh_tools.c b/source/blender/editors/mesh/editmesh_tools.c index ade21f58232..56d971ea59b 100644 --- a/source/blender/editors/mesh/editmesh_tools.c +++ b/source/blender/editors/mesh/editmesh_tools.c @@ -6886,8 +6886,8 @@ void MESH_OT_sort_elements(wmOperatorType *ot) "SELECTED", 0, "Selected", - "Move all selected elements in first places, preserving their relative order " - "(WARNING: this will affect unselected elements' indices as well!)"}, + "Move all selected elements in first places, preserving their relative order.\n" + "Warning: This will affect unselected elements' indices as well"}, {SRT_RANDOMIZE, "RANDOMIZE", 0, "Randomize", "Randomize order of selected elements"}, {SRT_REVERSE, "REVERSE", 0, "Reverse", "Reverse current order of selected elements"}, {0, NULL, 0, NULL, NULL}, diff --git a/source/blender/editors/mesh/editmesh_utils.c b/source/blender/editors/mesh/editmesh_utils.c index 94f386e08d5..2e98f0558f3 100644 --- a/source/blender/editors/mesh/editmesh_utils.c +++ b/source/blender/editors/mesh/editmesh_utils.c @@ -785,7 +785,7 @@ UvElementMap *BM_uv_element_map_create(BMesh *bm, l = v->l; luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); uv = luv->uv; - uv_vert_sel = luv->flag & MLOOPUV_VERTSEL; + uv_vert_sel = uvedit_uv_select_test(scene, l, cd_loop_uv_offset); lastv = NULL; iterv = vlist; @@ -796,7 +796,7 @@ UvElementMap *BM_uv_element_map_create(BMesh *bm, l = iterv->l; luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); uv2 = luv->uv; - uv2_vert_sel = luv->flag & MLOOPUV_VERTSEL; + uv2_vert_sel = uvedit_uv_select_test(scene, l, cd_loop_uv_offset); /* Check if the uv loops share the same selection state (if not, they are not connected as * they have been ripped or other edit commands have separated them). */ diff --git a/source/blender/editors/object/object_add.c b/source/blender/editors/object/object_add.c index e4527740164..7f189abe870 100644 --- a/source/blender/editors/object/object_add.c +++ b/source/blender/editors/object/object_add.c @@ -1416,6 +1416,9 @@ static int object_gpencil_add_exec(bContext *C, wmOperator *op) /* Only created one layer and one material. */ strcpy(md->target_layer, ((bGPDlayer *)gpd->layers.first)->info); md->target_material = BKE_gpencil_material(ob, 1); + if (md->target_material) { + id_us_plus(&md->target_material->id); + } /* Stroke object is drawn in front of meshes by default. */ ob->dtx |= OB_DRAW_IN_FRONT; @@ -1440,41 +1443,6 @@ static int object_gpencil_add_exec(bContext *C, wmOperator *op) return OPERATOR_FINISHED; } -static const EnumPropertyItem *object_gpencil_add_options(bContext *C, - PointerRNA *UNUSED(ptr), - PropertyRNA *UNUSED(prop), - bool *r_free) -{ - EnumPropertyItem *item = NULL; - const EnumPropertyItem *item_ref = rna_enum_object_gpencil_type_items; - int totitem = 0; - int i = 0; - int orig_count = RNA_enum_items_count(item_ref); - - /* Default types. */ - for (i = 0; i < orig_count; i++) { - if (item_ref[i].value == GP_LRT_OBJECT || item_ref[i].value == GP_LRT_COLLECTION || - item_ref[i].value == GP_LRT_SCENE) { - if (item_ref[i].value == GP_LRT_SCENE) { - /* separator before line art types */ - RNA_enum_item_add_separator(&item, &totitem); - } - else if (item_ref[i].value == GP_LRT_OBJECT) { - Object *ob = CTX_data_active_object(C); - if (!ob || ob->type != OB_MESH) { - continue; - } - } - } - RNA_enum_item_add(&item, &totitem, &item_ref[i]); - } - - RNA_enum_item_end(&item, &totitem); - *r_free = true; - - return item; -} - void OBJECT_OT_gpencil_add(wmOperatorType *ot) { /* identifiers */ @@ -1495,7 +1463,6 @@ void OBJECT_OT_gpencil_add(wmOperatorType *ot) ED_object_add_generic_props(ot, false); ot->prop = RNA_def_enum(ot->srna, "type", rna_enum_object_gpencil_type_items, 0, "Type", ""); - RNA_def_enum_funcs(ot->prop, object_gpencil_add_options); } /** \} */ @@ -1932,8 +1899,8 @@ void OBJECT_OT_pointcloud_add(wmOperatorType *ot) /* note: now unlinks constraints as well */ void ED_object_base_free_and_unlink(Main *bmain, Scene *scene, Object *ob) { - if (BKE_library_ID_is_indirectly_used(bmain, ob) && ID_REAL_USERS(ob) <= 1 && - ID_EXTRA_USERS(ob) == 0) { + if (ID_REAL_USERS(ob) <= 1 && ID_EXTRA_USERS(ob) == 0 && + BKE_library_ID_is_indirectly_used(bmain, ob)) { /* We cannot delete indirectly used object... */ printf( "WARNING, undeletable object '%s', should have been caught before reaching this " @@ -1947,6 +1914,17 @@ void ED_object_base_free_and_unlink(Main *bmain, Scene *scene, Object *ob) BKE_scene_collections_object_remove(bmain, scene, ob, true); } +/** + * Remove base from a specific scene. + * `ob` must not be indirectly used. + */ +void ED_object_base_free_and_unlink_no_indirect_check(Main *bmain, Scene *scene, Object *ob) +{ + BLI_assert(!BKE_library_ID_is_indirectly_used(bmain, ob)); + DEG_id_tag_update_ex(bmain, &ob->id, ID_RECALC_BASE_FLAGS); + BKE_scene_collections_object_remove(bmain, scene, ob, true); +} + static int object_delete_exec(bContext *C, wmOperator *op) { Main *bmain = CTX_data_main(C); @@ -1954,13 +1932,15 @@ static int object_delete_exec(bContext *C, wmOperator *op) wmWindowManager *wm = CTX_wm_manager(C); const bool use_global = RNA_boolean_get(op->ptr, "use_global"); uint changed_count = 0; + uint tagged_count = 0; if (CTX_data_edit_object(C)) { return OPERATOR_CANCELLED; } + BKE_main_id_tag_all(bmain, LIB_TAG_DOIT, false); + CTX_DATA_BEGIN (C, Object *, ob, selected_objects) { - const bool is_indirectly_used = BKE_library_ID_is_indirectly_used(bmain, ob); if (ob->id.tag & LIB_TAG_INDIRECT) { /* Can this case ever happen? */ BKE_reportf(op->reports, @@ -1969,7 +1949,9 @@ static int object_delete_exec(bContext *C, wmOperator *op) ob->id.name + 2); continue; } - if (is_indirectly_used && ID_REAL_USERS(ob) <= 1 && ID_EXTRA_USERS(ob) == 0) { + + if (ID_REAL_USERS(ob) <= 1 && ID_EXTRA_USERS(ob) == 0 && + BKE_library_ID_is_indirectly_used(bmain, ob)) { BKE_reportf(op->reports, RPT_WARNING, "Cannot delete object '%s' from scene '%s', indirectly used objects need at " @@ -1985,63 +1967,41 @@ static int object_delete_exec(bContext *C, wmOperator *op) DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY); } - /* This is sort of a quick hack to address T51243 - - * Proper thing to do here would be to nuke most of all this custom scene/object/base handling, - * and use generic lib remap/query for that. - * But this is for later (aka 2.8, once layers & co are settled and working). - */ - if (use_global && ob->id.lib == NULL) { - /* We want to nuke the object, let's nuke it the easy way (not for linked data though)... */ - BKE_id_delete(bmain, &ob->id); - changed_count += 1; - continue; - } - - /* remove from Grease Pencil parent */ - /* XXX This is likely not correct? - * Will also remove parent from grease pencil from other scenes, - * even when use_global is false... */ - for (bGPdata *gpd = bmain->gpencils.first; gpd; gpd = gpd->id.next) { - LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) { - if (gpl->parent != NULL) { - if (gpl->parent == ob) { - gpl->parent = NULL; - } - } - } + /* Use multi tagged delete if `use_global=True`, or the object is used only in one scene. */ + if (use_global || ID_REAL_USERS(ob) <= 1) { + ob->id.tag |= LIB_TAG_DOIT; + tagged_count += 1; } + else { + /* Object is used in multiple scenes. Delete the object from the current scene only. */ + ED_object_base_free_and_unlink_no_indirect_check(bmain, scene, ob); + changed_count += 1; - /* remove from current scene only */ - ED_object_base_free_and_unlink(bmain, scene, ob); - changed_count += 1; - - if (use_global) { - Scene *scene_iter; - for (scene_iter = bmain->scenes.first; scene_iter; scene_iter = scene_iter->id.next) { - if (scene_iter != scene && !ID_IS_LINKED(scene_iter)) { - if (is_indirectly_used && ID_REAL_USERS(ob) <= 1 && ID_EXTRA_USERS(ob) == 0) { - BKE_reportf(op->reports, - RPT_WARNING, - "Cannot delete object '%s' from scene '%s', indirectly used objects need " - "at least one user", - ob->id.name + 2, - scene_iter->id.name + 2); - break; + /* FIXME: this will also remove parent from grease pencil from other scenes. */ + /* Remove from Grease Pencil parent */ + for (bGPdata *gpd = bmain->gpencils.first; gpd; gpd = gpd->id.next) { + LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) { + if (gpl->parent != NULL) { + if (gpl->parent == ob) { + gpl->parent = NULL; + } } - ED_object_base_free_and_unlink(bmain, scene_iter, ob); } } } - /* end global */ } CTX_DATA_END; - BKE_reportf(op->reports, RPT_INFO, "Deleted %u object(s)", changed_count); - - if (changed_count == 0) { + if ((changed_count + tagged_count) == 0) { return OPERATOR_CANCELLED; } + if (tagged_count > 0) { + BKE_id_multi_tagged_delete(bmain); + } + + BKE_reportf(op->reports, RPT_INFO, "Deleted %u object(s)", (changed_count + tagged_count)); + /* delete has to handle all open scenes */ BKE_main_id_tag_listbase(&bmain->scenes, LIB_TAG_DOIT, true); LISTBASE_FOREACH (wmWindow *, win, &wm->windows) { diff --git a/source/blender/editors/object/object_data_transfer.c b/source/blender/editors/object/object_data_transfer.c index 72ef72403cf..22c9d669ff3 100644 --- a/source/blender/editors/object/object_data_transfer.c +++ b/source/blender/editors/object/object_data_transfer.c @@ -684,7 +684,8 @@ void OBJECT_OT_data_transfer(wmOperatorType *ot) false, "Auto Transform", "Automatically compute transformation to get the best possible match between source and " - "destination meshes (WARNING: results will never be as good as manual matching of objects)"); + "destination meshes.\n" + "Warning: Results will never be as good as manual matching of objects"); RNA_def_boolean(ot->srna, "use_object_transform", true, diff --git a/source/blender/editors/object/object_modifier.c b/source/blender/editors/object/object_modifier.c index 7673649c261..b28b7478721 100644 --- a/source/blender/editors/object/object_modifier.c +++ b/source/blender/editors/object/object_modifier.c @@ -1115,6 +1115,40 @@ bool edit_modifier_invoke_properties(bContext *C, wmOperator *op) return false; } +/** + * If the "modifier" property is not set,fill the modifier property with the name of the modifier + * with a UI panel below the mouse cursor, without checking the context pointer. Used in order to + * apply modifier operators on hover over their panels. If this checked the context pointer then it + * would always use the active modifier, which isn't desired. + */ +bool edit_modifier_invoke_properties_with_hover_no_active(bContext *C, + wmOperator *op, + const wmEvent *event, + int *r_retval) +{ + if (RNA_struct_property_is_set(op->ptr, "modifier")) { + return true; + } + + PointerRNA *panel_ptr = UI_region_panel_custom_data_under_cursor(C, event); + if (panel_ptr == NULL || RNA_pointer_is_null(panel_ptr)) { + *r_retval = OPERATOR_CANCELLED; + return false; + } + + if (!RNA_struct_is_a(panel_ptr->type, &RNA_Modifier)) { + /* Work around multiple operators using the same shortcut. The operators for the other + * stacks in the property editor use the same key, and will not run after these return + * OPERATOR_CANCELLED. */ + *r_retval = (OPERATOR_PASS_THROUGH | OPERATOR_CANCELLED); + return false; + } + + const ModifierData *md = panel_ptr->data; + RNA_string_set(op->ptr, "modifier", md->name); + return true; +} + ModifierData *edit_modifier_property_get(wmOperator *op, Object *ob, int type) { char modifier_name[MAX_NAME]; @@ -1174,14 +1208,13 @@ static int modifier_remove_exec(bContext *C, wmOperator *op) return OPERATOR_FINISHED; } -static int modifier_remove_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) +static int modifier_remove_invoke(bContext *C, wmOperator *op, const wmEvent *event) { - if (edit_modifier_invoke_properties(C, op)) { + int retval; + if (edit_modifier_invoke_properties_with_hover_no_active(C, op, event, &retval)) { return modifier_remove_exec(C, op); } - - /* Work around multiple operators using the same shortcut. */ - return (OPERATOR_PASS_THROUGH | OPERATOR_CANCELLED); + return retval; } void OBJECT_OT_modifier_remove(wmOperatorType *ot) @@ -1221,13 +1254,13 @@ static int modifier_move_up_exec(bContext *C, wmOperator *op) return OPERATOR_FINISHED; } -static int modifier_move_up_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) +static int modifier_move_up_invoke(bContext *C, wmOperator *op, const wmEvent *event) { - if (edit_modifier_invoke_properties(C, op)) { + int retval; + if (edit_modifier_invoke_properties_with_hover_no_active(C, op, event, &retval)) { return modifier_move_up_exec(C, op); } - /* Work around multiple operators using the same shortcut. */ - return (OPERATOR_PASS_THROUGH | OPERATOR_CANCELLED); + return retval; } void OBJECT_OT_modifier_move_up(wmOperatorType *ot) @@ -1266,13 +1299,13 @@ static int modifier_move_down_exec(bContext *C, wmOperator *op) return OPERATOR_FINISHED; } -static int modifier_move_down_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) +static int modifier_move_down_invoke(bContext *C, wmOperator *op, const wmEvent *event) { - if (edit_modifier_invoke_properties(C, op)) { + int retval; + if (edit_modifier_invoke_properties_with_hover_no_active(C, op, event, &retval)) { return modifier_move_down_exec(C, op); } - /* Work around multiple operators using the same shortcut. */ - return (OPERATOR_PASS_THROUGH | OPERATOR_CANCELLED); + return retval; } void OBJECT_OT_modifier_move_down(wmOperatorType *ot) @@ -1309,12 +1342,13 @@ static int modifier_move_to_index_exec(bContext *C, wmOperator *op) return OPERATOR_FINISHED; } -static int modifier_move_to_index_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) +static int modifier_move_to_index_invoke(bContext *C, wmOperator *op, const wmEvent *event) { - if (edit_modifier_invoke_properties(C, op)) { + int retval; + if (edit_modifier_invoke_properties_with_hover_no_active(C, op, event, &retval)) { return modifier_move_to_index_exec(C, op); } - return OPERATOR_CANCELLED; + return retval; } void OBJECT_OT_modifier_move_to_index(wmOperatorType *ot) @@ -1421,13 +1455,13 @@ static int modifier_apply_exec(bContext *C, wmOperator *op) return modifier_apply_exec_ex(C, op, MODIFIER_APPLY_DATA, false); } -static int modifier_apply_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) +static int modifier_apply_invoke(bContext *C, wmOperator *op, const wmEvent *event) { - if (edit_modifier_invoke_properties(C, op)) { + int retval; + if (edit_modifier_invoke_properties_with_hover_no_active(C, op, event, &retval)) { return modifier_apply_exec(C, op); } - /* Work around multiple operators using the same shortcut. */ - return (OPERATOR_PASS_THROUGH | OPERATOR_CANCELLED); + return retval; } void OBJECT_OT_modifier_apply(wmOperatorType *ot) @@ -1465,15 +1499,13 @@ static int modifier_apply_as_shapekey_exec(bContext *C, wmOperator *op) return modifier_apply_exec_ex(C, op, MODIFIER_APPLY_SHAPE, keep); } -static int modifier_apply_as_shapekey_invoke(bContext *C, - wmOperator *op, - const wmEvent *UNUSED(event)) +static int modifier_apply_as_shapekey_invoke(bContext *C, wmOperator *op, const wmEvent *event) { - if (edit_modifier_invoke_properties(C, op)) { + int retval; + if (edit_modifier_invoke_properties_with_hover_no_active(C, op, event, &retval)) { return modifier_apply_as_shapekey_exec(C, op); } - /* Work around multiple operators using the same shortcut. */ - return (OPERATOR_PASS_THROUGH | OPERATOR_CANCELLED); + return retval; } static char *modifier_apply_as_shapekey_get_description(struct bContext *UNUSED(C), @@ -1579,13 +1611,13 @@ static int modifier_copy_exec(bContext *C, wmOperator *op) return OPERATOR_FINISHED; } -static int modifier_copy_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) +static int modifier_copy_invoke(bContext *C, wmOperator *op, const wmEvent *event) { - if (edit_modifier_invoke_properties(C, op)) { + int retval; + if (edit_modifier_invoke_properties_with_hover_no_active(C, op, event, &retval)) { return modifier_copy_exec(C, op); } - /* Work around multiple operators using the same shortcut. */ - return (OPERATOR_PASS_THROUGH | OPERATOR_CANCELLED); + return retval; } void OBJECT_OT_modifier_copy(wmOperatorType *ot) @@ -1622,54 +1654,12 @@ static int modifier_set_active_exec(bContext *C, wmOperator *op) return OPERATOR_FINISHED; } -/** - * Get the modifier below the mouse cursor modifier without checking the context pointer. - * Used in order to set the active modifier on mouse click. If this checked the context - * pointer then it would always set the active modifier to the already active modifier. - * - * \param event: If this isn't NULL, the operator will also look for panels underneath - * the cursor with custom-data set to a modifier. - * \param r_retval: This should be used if #event is used in order to return - * #OPERATOR_PASS_THROUGH to check other operators with the same key set. - */ -bool edit_modifier_invoke_properties_with_hover_no_active(bContext *C, - wmOperator *op, - const wmEvent *event, - int *r_retval) -{ - if (RNA_struct_property_is_set(op->ptr, "modifier")) { - return true; - } - - PointerRNA *panel_ptr = UI_region_panel_custom_data_under_cursor(C, event); - - if (!(panel_ptr == NULL || RNA_pointer_is_null(panel_ptr))) { - if (RNA_struct_is_a(panel_ptr->type, &RNA_Modifier)) { - ModifierData *md = panel_ptr->data; - RNA_string_set(op->ptr, "modifier", md->name); - return true; - } - BLI_assert(r_retval != NULL); /* We need the return value in this case. */ - if (r_retval != NULL) { - *r_retval = (OPERATOR_PASS_THROUGH | OPERATOR_CANCELLED); - } - return false; - } - - if (r_retval != NULL) { - *r_retval = OPERATOR_CANCELLED; - } - - return false; -} - static int modifier_set_active_invoke(bContext *C, wmOperator *op, const wmEvent *event) { int retval; if (edit_modifier_invoke_properties_with_hover_no_active(C, op, event, &retval)) { return modifier_set_active_exec(C, op); } - return retval; } @@ -1756,15 +1746,13 @@ static int modifier_copy_to_selected_exec(bContext *C, wmOperator *op) return OPERATOR_FINISHED; } -static int modifier_copy_to_selected_invoke(bContext *C, - wmOperator *op, - const wmEvent *UNUSED(event)) +static int modifier_copy_to_selected_invoke(bContext *C, wmOperator *op, const wmEvent *event) { - if (edit_modifier_invoke_properties(C, op)) { - return modifier_copy_to_selected_exec(C, op); + int retval; + if (edit_modifier_invoke_properties_with_hover_no_active(C, op, event, &retval)) { + return modifier_set_active_exec(C, op); } - /* Work around multiple operators using the same shortcut. */ - return (OPERATOR_PASS_THROUGH | OPERATOR_CANCELLED); + return retval; } static bool modifier_copy_to_selected_poll(bContext *C) diff --git a/source/blender/editors/object/object_transform.c b/source/blender/editors/object/object_transform.c index 13c0740bce6..1d7cf61bc3a 100644 --- a/source/blender/editors/object/object_transform.c +++ b/source/blender/editors/object/object_transform.c @@ -1782,12 +1782,7 @@ static int object_transform_axis_target_invoke(bContext *C, wmOperator *op, cons vc.v3d->flag2 |= V3D_HIDE_OVERLAYS; #endif - ED_view3d_autodist_init(vc.depsgraph, vc.region, vc.v3d, 0); - - if (vc.rv3d->depths != NULL) { - vc.rv3d->depths->damaged = true; - } - ED_view3d_depth_update(vc.region); + ED_view3d_depth_override(vc.depsgraph, vc.region, vc.v3d, NULL, V3D_DEPTH_NO_GPENCIL, true); #ifdef USE_RENDER_OVERRIDE vc.v3d->flag2 = flag2_prev; diff --git a/source/blender/editors/physics/particle_edit.c b/source/blender/editors/physics/particle_edit.c index 0ec8238f741..de4ad913d6d 100644 --- a/source/blender/editors/physics/particle_edit.c +++ b/source/blender/editors/physics/particle_edit.c @@ -524,15 +524,13 @@ static void PE_set_view3d_data(bContext *C, PEData *data) ED_view3d_viewcontext_init(C, &data->vc, data->depsgraph); if (!XRAY_ENABLED(data->vc.v3d)) { - if (data->vc.v3d->flag & V3D_INVALID_BACKBUF) { - /* needed or else the draw matrix can be incorrect */ - view3d_operator_needs_opengl(C); - - ED_view3d_backbuf_depth_validate(&data->vc); - /* we may need to force an update here by setting the rv3d as dirty - * for now it seems ok, but take care!: - * rv3d->depths->dirty = 1; */ - ED_view3d_depth_update(data->vc.region); + if (!(data->vc.v3d->runtime.flag & V3D_RUNTIME_DEPTHBUF_OVERRIDDEN)) { + ED_view3d_depth_override(data->depsgraph, + data->vc.region, + data->vc.v3d, + data->vc.obact, + V3D_DEPTH_OBJECT_ONLY, + true); } } } diff --git a/source/blender/editors/sculpt_paint/paint_cursor.c b/source/blender/editors/sculpt_paint/paint_cursor.c index b44f2f66d92..c5e7b2dc4d3 100644 --- a/source/blender/editors/sculpt_paint/paint_cursor.c +++ b/source/blender/editors/sculpt_paint/paint_cursor.c @@ -545,6 +545,7 @@ static bool paint_draw_tex_overlay(UnifiedPaintSettings *ups, int x, int y, float zoom, + const ePaintMode mode, bool col, bool primary) { @@ -556,6 +557,13 @@ static bool paint_draw_tex_overlay(UnifiedPaintSettings *ups, (brush->overlay_flags & BRUSH_OVERLAY_SECONDARY) != 0); int overlay_alpha = (primary) ? brush->texture_overlay_alpha : brush->mask_overlay_alpha; + if (mode == PAINT_MODE_TEXTURE_3D) { + if (primary && brush->imagepaint_tool == PAINT_TOOL_DRAW) { + /* All non-draw tools don't use the primary texture (clone, smear, soften.. etc). */ + return false; + } + } + if (!(mtex->tex) || !((mtex->brush_map_mode == MTEX_MAP_MODE_STENCIL) || (valid && ELEM(mtex->brush_map_mode, MTEX_MAP_MODE_VIEW, MTEX_MAP_MODE_TILED)))) { @@ -785,10 +793,11 @@ static bool paint_draw_alpha_overlay(UnifiedPaintSettings *ups, /* Colored overlay should be drawn separately. */ if (col) { if (!(flags & PAINT_OVERLAY_OVERRIDE_PRIMARY)) { - alpha_overlay_active = paint_draw_tex_overlay(ups, brush, vc, x, y, zoom, true, true); + alpha_overlay_active = paint_draw_tex_overlay(ups, brush, vc, x, y, zoom, mode, true, true); } if (!(flags & PAINT_OVERLAY_OVERRIDE_SECONDARY)) { - alpha_overlay_active = paint_draw_tex_overlay(ups, brush, vc, x, y, zoom, false, false); + alpha_overlay_active = paint_draw_tex_overlay( + ups, brush, vc, x, y, zoom, mode, false, false); } if (!(flags & PAINT_OVERLAY_OVERRIDE_CURSOR)) { alpha_overlay_active = paint_draw_cursor_overlay(ups, brush, vc, x, y, zoom); @@ -796,7 +805,7 @@ static bool paint_draw_alpha_overlay(UnifiedPaintSettings *ups, } else { if (!(flags & PAINT_OVERLAY_OVERRIDE_PRIMARY) && (mode != PAINT_MODE_WEIGHT)) { - alpha_overlay_active = paint_draw_tex_overlay(ups, brush, vc, x, y, zoom, false, true); + alpha_overlay_active = paint_draw_tex_overlay(ups, brush, vc, x, y, zoom, mode, false, true); } if (!(flags & PAINT_OVERLAY_OVERRIDE_CURSOR)) { alpha_overlay_active = paint_draw_cursor_overlay(ups, brush, vc, x, y, zoom); diff --git a/source/blender/editors/space_file/filelist.c b/source/blender/editors/space_file/filelist.c index 9bdca35468e..76bfb34c809 100644 --- a/source/blender/editors/space_file/filelist.c +++ b/source/blender/editors/space_file/filelist.c @@ -2543,7 +2543,7 @@ int ED_path_extension_type(const char *path) if (BLI_path_extension_check(path, ".zip")) { return FILE_TYPE_ARCHIVE; } - if (BLI_path_extension_check_n(path, ".obj", ".3ds", ".fbx", ".glb", ".gltf", NULL)) { + if (BLI_path_extension_check_n(path, ".obj", ".3ds", ".fbx", ".glb", ".gltf", ".svg", NULL)) { return FILE_TYPE_OBJECT_IO; } if (BLI_path_extension_check_array(path, imb_ext_image)) { diff --git a/source/blender/editors/space_image/image_intern.h b/source/blender/editors/space_image/image_intern.h index 0044c6072a4..d302f099772 100644 --- a/source/blender/editors/space_image/image_intern.h +++ b/source/blender/editors/space_image/image_intern.h @@ -50,6 +50,7 @@ void IMAGE_OT_view_all(struct wmOperatorType *ot); void IMAGE_OT_view_pan(struct wmOperatorType *ot); void IMAGE_OT_view_selected(struct wmOperatorType *ot); void IMAGE_OT_view_center_cursor(struct wmOperatorType *ot); +void IMAGE_OT_view_cursor_center(struct wmOperatorType *ot); void IMAGE_OT_view_zoom(struct wmOperatorType *ot); void IMAGE_OT_view_zoom_in(struct wmOperatorType *ot); void IMAGE_OT_view_zoom_out(struct wmOperatorType *ot); diff --git a/source/blender/editors/space_image/image_ops.c b/source/blender/editors/space_image/image_ops.c index 72405a51aca..48e1397601f 100644 --- a/source/blender/editors/space_image/image_ops.c +++ b/source/blender/editors/space_image/image_ops.c @@ -244,6 +244,70 @@ static bool image_not_packed_poll(bContext *C) return (ima && BLI_listbase_is_empty(&ima->packedfiles)); } +static void image_view_all(struct SpaceImage *sima, struct ARegion *region, struct wmOperator *op) +{ + float aspx, aspy, zoomx, zoomy, w, h; + int width, height; + const bool fit_view = RNA_boolean_get(op->ptr, "fit_view"); + + ED_space_image_get_size(sima, &width, &height); + ED_space_image_get_aspect(sima, &aspx, &aspy); + + w = width * aspx; + h = height * aspy; + + float xof = 0.0f, yof = 0.0f; + if ((sima->image == NULL) || (sima->image->source == IMA_SRC_TILED)) { + /* Extend the shown area to cover all UDIM tiles. */ + int x_tiles, y_tiles; + if (sima->image == NULL) { + x_tiles = sima->tile_grid_shape[0]; + y_tiles = sima->tile_grid_shape[1]; + } + else { + x_tiles = y_tiles = 1; + LISTBASE_FOREACH (ImageTile *, tile, &sima->image->tiles) { + int tile_x = (tile->tile_number - 1001) % 10; + int tile_y = (tile->tile_number - 1001) / 10; + x_tiles = max_ii(x_tiles, tile_x + 1); + y_tiles = max_ii(y_tiles, tile_y + 1); + } + } + xof = 0.5f * (x_tiles - 1.0f) * w; + yof = 0.5f * (y_tiles - 1.0f) * h; + w *= x_tiles; + h *= y_tiles; + } + + /* check if the image will fit in the image with (zoom == 1) */ + width = BLI_rcti_size_x(®ion->winrct) + 1; + height = BLI_rcti_size_y(®ion->winrct) + 1; + + if (fit_view) { + const int margin = 5; /* margin from border */ + + zoomx = (float)width / (w + 2 * margin); + zoomy = (float)height / (h + 2 * margin); + + sima_zoom_set(sima, region, min_ff(zoomx, zoomy), NULL, false); + } + else { + if ((w >= width || h >= height) && (width > 0 && height > 0)) { + zoomx = (float)width / w; + zoomy = (float)height / h; + + /* find the zoom value that will fit the image in the image space */ + sima_zoom_set(sima, region, 1.0f / power_of_2(1.0f / min_ff(zoomx, zoomy)), NULL, false); + } + else { + sima_zoom_set(sima, region, 1.0f, NULL, false); + } + } + + sima->xof = xof; + sima->yof = yof; +} + bool space_image_main_region_poll(bContext *C) { SpaceImage *sima = CTX_wm_space_image(C); @@ -736,70 +800,12 @@ static int image_view_all_exec(bContext *C, wmOperator *op) { SpaceImage *sima; ARegion *region; - float aspx, aspy, zoomx, zoomy, w, h; - int width, height; - const bool fit_view = RNA_boolean_get(op->ptr, "fit_view"); /* retrieve state */ sima = CTX_wm_space_image(C); region = CTX_wm_region(C); - ED_space_image_get_size(sima, &width, &height); - ED_space_image_get_aspect(sima, &aspx, &aspy); - - w = width * aspx; - h = height * aspy; - - float xof = 0.0f, yof = 0.0f; - if ((sima->image == NULL) || (sima->image->source == IMA_SRC_TILED)) { - /* Extend the shown area to cover all UDIM tiles. */ - int x_tiles, y_tiles; - if (sima->image == NULL) { - x_tiles = sima->tile_grid_shape[0]; - y_tiles = sima->tile_grid_shape[1]; - } - else { - x_tiles = y_tiles = 1; - LISTBASE_FOREACH (ImageTile *, tile, &sima->image->tiles) { - int tile_x = (tile->tile_number - 1001) % 10; - int tile_y = (tile->tile_number - 1001) / 10; - x_tiles = max_ii(x_tiles, tile_x + 1); - y_tiles = max_ii(y_tiles, tile_y + 1); - } - } - xof = 0.5f * (x_tiles - 1.0f) * w; - yof = 0.5f * (y_tiles - 1.0f) * h; - w *= x_tiles; - h *= y_tiles; - } - - /* check if the image will fit in the image with (zoom == 1) */ - width = BLI_rcti_size_x(®ion->winrct) + 1; - height = BLI_rcti_size_y(®ion->winrct) + 1; - - if (fit_view) { - const int margin = 5; /* margin from border */ - - zoomx = (float)width / (w + 2 * margin); - zoomy = (float)height / (h + 2 * margin); - - sima_zoom_set(sima, region, min_ff(zoomx, zoomy), NULL, false); - } - else { - if ((w >= width || h >= height) && (width > 0 && height > 0)) { - zoomx = (float)width / w; - zoomy = (float)height / h; - - /* find the zoom value that will fit the image in the image space */ - sima_zoom_set(sima, region, 1.0f / power_of_2(1.0f / min_ff(zoomx, zoomy)), NULL, false); - } - else { - sima_zoom_set(sima, region, 1.0f, NULL, false); - } - } - - sima->xof = xof; - sima->yof = yof; + image_view_all(sima, region, op); ED_region_tag_redraw(region); @@ -830,6 +836,49 @@ void IMAGE_OT_view_all(wmOperatorType *ot) /** \} */ /* -------------------------------------------------------------------- */ +/** \name Cursor To Center View Operator + * \{ */ + +static int view_cursor_center_exec(bContext *C, wmOperator *op) +{ + SpaceImage *sima; + ARegion *region; + + sima = CTX_wm_space_image(C); + region = CTX_wm_region(C); + + image_view_all(sima, region, op); + + sima->cursor[0] = 0.5f; + sima->cursor[1] = 0.5f; + + /* Needed for updating the cursor. */ + WM_event_add_notifier(C, NC_SPACE | ND_SPACE_IMAGE, NULL); + + return OPERATOR_FINISHED; +} + +void IMAGE_OT_view_cursor_center(wmOperatorType *ot) +{ + PropertyRNA *prop; + + /* identifiers */ + ot->name = "Cursor To Center View"; + ot->description = "Set 2D Cursor To Center View location"; + ot->idname = "IMAGE_OT_view_cursor_center"; + + /* api callbacks */ + ot->exec = view_cursor_center_exec; + ot->poll = ED_space_image_cursor_poll; + + /* properties */ + prop = RNA_def_boolean(ot->srna, "fit_view", 0, "Fit View", "Fit frame to the viewport"); + RNA_def_property_flag(prop, PROP_SKIP_SAVE); +} + +/** \} */ + +/* -------------------------------------------------------------------- */ /** \name Center View To Cursor Operator * \{ */ diff --git a/source/blender/editors/space_image/space_image.c b/source/blender/editors/space_image/space_image.c index c51d2f25efd..5a03b4f6ef0 100644 --- a/source/blender/editors/space_image/space_image.c +++ b/source/blender/editors/space_image/space_image.c @@ -200,6 +200,7 @@ static void image_operatortypes(void) WM_operatortype_append(IMAGE_OT_view_pan); WM_operatortype_append(IMAGE_OT_view_selected); WM_operatortype_append(IMAGE_OT_view_center_cursor); + WM_operatortype_append(IMAGE_OT_view_cursor_center); WM_operatortype_append(IMAGE_OT_view_zoom); WM_operatortype_append(IMAGE_OT_view_zoom_in); WM_operatortype_append(IMAGE_OT_view_zoom_out); diff --git a/source/blender/editors/space_node/drawnode.c b/source/blender/editors/space_node/drawnode.c index 0110de905d5..44da4b4ab11 100644 --- a/source/blender/editors/space_node/drawnode.c +++ b/source/blender/editors/space_node/drawnode.c @@ -1528,6 +1528,17 @@ static void node_composit_buts_defocus(uiLayout *layout, bContext *C, PointerRNA uiItemR(sub, ptr, "z_scale", DEFAULT_FLAGS, NULL, ICON_NONE); } +static void node_composit_buts_antialiasing(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) +{ + uiLayout *col; + + col = uiLayoutColumn(layout, false); + + uiItemR(col, ptr, "threshold", 0, NULL, ICON_NONE); + uiItemR(col, ptr, "contrast_limit", 0, NULL, ICON_NONE); + uiItemR(col, ptr, "corner_rounding", 0, NULL, ICON_NONE); +} + /* qdn: glare node */ static void node_composit_buts_glare(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { @@ -2799,6 +2810,9 @@ static void node_composit_set_butfunc(bNodeType *ntype) case CMP_NODE_DEFOCUS: ntype->draw_buttons = node_composit_buts_defocus; break; + case CMP_NODE_ANTIALIASING: + ntype->draw_buttons = node_composit_buts_antialiasing; + break; case CMP_NODE_GLARE: ntype->draw_buttons = node_composit_buts_glare; break; @@ -3429,7 +3443,7 @@ static void std_node_socket_draw( } break; case SOCK_RGBA: { - uiLayout *row = uiLayoutSplit(layout, 0.5f, false); + uiLayout *row = uiLayoutSplit(layout, 0.4f, false); uiItemL(row, text, 0); const bNodeTree *node_tree = (const bNodeTree *)node_ptr->owner_id; @@ -3443,7 +3457,7 @@ static void std_node_socket_draw( break; } case SOCK_STRING: { - uiLayout *row = uiLayoutSplit(layout, 0.5f, false); + uiLayout *row = uiLayoutSplit(layout, 0.4f, false); uiItemL(row, text, 0); const bNodeTree *node_tree = (const bNodeTree *)node_ptr->owner_id; diff --git a/source/blender/editors/space_node/node_add.c b/source/blender/editors/space_node/node_add.c index a646804e0fd..c4fe9e9e531 100644 --- a/source/blender/editors/space_node/node_add.c +++ b/source/blender/editors/space_node/node_add.c @@ -472,6 +472,8 @@ static int node_add_object_exec(bContext *C, wmOperator *op) snode_notify(C, snode); snode_dag_update(C, snode); + ED_node_tag_update_nodetree(bmain, ntree, object_node); + return OPERATOR_FINISHED; } @@ -496,7 +498,8 @@ static int node_add_object_invoke(bContext *C, wmOperator *op, const wmEvent *ev static bool node_add_object_poll(bContext *C) { const SpaceNode *snode = CTX_wm_space_node(C); - return ED_operator_node_editable(C) && ELEM(snode->nodetree->type, NTREE_GEOMETRY); + return ED_operator_node_editable(C) && ELEM(snode->nodetree->type, NTREE_GEOMETRY) && + !UI_but_active_drop_name(C); } void NODE_OT_add_object(wmOperatorType *ot) @@ -568,6 +571,8 @@ static int node_add_texture_exec(bContext *C, wmOperator *op) snode_notify(C, snode); snode_dag_update(C, snode); + ED_node_tag_update_nodetree(bmain, ntree, texture_node); + return OPERATOR_FINISHED; } @@ -592,7 +597,8 @@ static int node_add_texture_invoke(bContext *C, wmOperator *op, const wmEvent *e static bool node_add_texture_poll(bContext *C) { const SpaceNode *snode = CTX_wm_space_node(C); - return ED_operator_node_editable(C) && ELEM(snode->nodetree->type, NTREE_GEOMETRY); + return ED_operator_node_editable(C) && ELEM(snode->nodetree->type, NTREE_GEOMETRY) && + !UI_but_active_drop_name(C); } void NODE_OT_add_texture(wmOperatorType *ot) @@ -670,6 +676,8 @@ static int node_add_collection_exec(bContext *C, wmOperator *op) snode_notify(C, snode); snode_dag_update(C, snode); + ED_node_tag_update_nodetree(bmain, ntree, collection_node); + return OPERATOR_FINISHED; } @@ -694,7 +702,8 @@ static int node_add_collection_invoke(bContext *C, wmOperator *op, const wmEvent static bool node_add_collection_poll(bContext *C) { const SpaceNode *snode = CTX_wm_space_node(C); - return ED_operator_node_editable(C) && ELEM(snode->nodetree->type, NTREE_GEOMETRY); + return ED_operator_node_editable(C) && ELEM(snode->nodetree->type, NTREE_GEOMETRY) && + !UI_but_active_drop_name(C); } void NODE_OT_add_collection(wmOperatorType *ot) diff --git a/source/blender/editors/space_node/node_buttons.c b/source/blender/editors/space_node/node_buttons.c index fa4d6997c83..eb89658857b 100644 --- a/source/blender/editors/space_node/node_buttons.c +++ b/source/blender/editors/space_node/node_buttons.c @@ -198,7 +198,7 @@ void node_buttons_register(ARegionType *art) { PanelType *pt = MEM_callocN(sizeof(PanelType), __func__); strcpy(pt->idname, "NODE_PT_node_tree_interface_inputs"); - strcpy(pt->category, N_("Node")); + strcpy(pt->category, N_("Group")); strcpy(pt->label, N_("Inputs")); strcpy(pt->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA); pt->draw = node_tree_interface_inputs_panel; @@ -208,7 +208,7 @@ void node_buttons_register(ARegionType *art) { PanelType *pt = MEM_callocN(sizeof(PanelType), __func__); strcpy(pt->idname, "NODE_PT_node_tree_interface_outputs"); - strcpy(pt->category, N_("Node")); + strcpy(pt->category, N_("Group")); strcpy(pt->label, N_("Outputs")); strcpy(pt->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA); pt->draw = node_tree_interface_outputs_panel; diff --git a/source/blender/editors/space_node/node_edit.c b/source/blender/editors/space_node/node_edit.c index b72a6503749..8fdee01f78e 100644 --- a/source/blender/editors/space_node/node_edit.c +++ b/source/blender/editors/space_node/node_edit.c @@ -1128,10 +1128,15 @@ static bool cursor_isect_multi_input_socket(const float cursor[2], const bNodeSo { const float node_socket_height = node_socket_calculate_height(socket); const rctf multi_socket_rect = { - .xmin = socket->locx - NODE_SOCKSIZE * 4, - .xmax = socket->locx + NODE_SOCKSIZE, - .ymin = socket->locy - node_socket_height * 0.5 - NODE_SOCKSIZE * 2.0f, - .ymax = socket->locy + node_socket_height * 0.5 + NODE_SOCKSIZE * 2.0f, + .xmin = socket->locx - NODE_SOCKSIZE * 4.0f, + .xmax = socket->locx + NODE_SOCKSIZE * 2.0f, + /*.xmax = socket->locx + NODE_SOCKSIZE * 5.5f + * would be the same behavior as for regular sockets. + * But keep it smaller because for multi-input socket you + * sometimes want to drag the link to the other side, if you may + * accidentally pick the wrong link otherwise. */ + .ymin = socket->locy - node_socket_height * 0.5 - NODE_SOCKSIZE, + .ymax = socket->locy + node_socket_height * 0.5 + NODE_SOCKSIZE, }; if (BLI_rctf_isect_pt(&multi_socket_rect, cursor[0], cursor[1])) { return true; @@ -1141,7 +1146,7 @@ static bool cursor_isect_multi_input_socket(const float cursor[2], const bNodeSo /* type is SOCK_IN and/or SOCK_OUT */ int node_find_indicated_socket( - SpaceNode *snode, bNode **nodep, bNodeSocket **sockp, float cursor[2], int in_out) + SpaceNode *snode, bNode **nodep, bNodeSocket **sockp, const float cursor[2], int in_out) { rctf rect; diff --git a/source/blender/editors/space_node/node_intern.h b/source/blender/editors/space_node/node_intern.h index fbf9d8869ac..ff37496148f 100644 --- a/source/blender/editors/space_node/node_intern.h +++ b/source/blender/editors/space_node/node_intern.h @@ -262,7 +262,7 @@ int node_render_changed_exec(bContext *, struct wmOperator *); int node_find_indicated_socket(struct SpaceNode *snode, struct bNode **nodep, struct bNodeSocket **sockp, - float cursor[2], + const float cursor[2], int in_out); void NODE_OT_duplicate(struct wmOperatorType *ot); diff --git a/source/blender/editors/space_node/node_relationships.c b/source/blender/editors/space_node/node_relationships.c index 4b2290c094b..95584847d6e 100644 --- a/source/blender/editors/space_node/node_relationships.c +++ b/source/blender/editors/space_node/node_relationships.c @@ -245,18 +245,8 @@ static void pick_input_link_by_link_intersect(const bContext *C, bNodeSocket *socket; node_find_indicated_socket(snode, &node, &socket, drag_start, SOCK_IN); - const float trigger_drag_distance = 25.0f; - const float cursor_link_touch_distance = 25.0f; - - const float socket_height = node_socket_calculate_height(socket); - - float cursor_to_socket_relative[2]; - float socket_position[2] = {socket->locx, socket->locy}; - sub_v2_v2v2(cursor_to_socket_relative, cursor, socket_position); - float distance_from_socket_v2[2] = { - max_ff(0, fabs(cursor_to_socket_relative[0]) - NODE_SOCKSIZE * 0.5), - max_ff(0, fabs(cursor_to_socket_relative[1]) - socket_height)}; - const float distance_from_socket = len_v2(distance_from_socket_v2); + /* Distance to test overlapping of cursor on link. */ + const float cursor_link_touch_distance = 12.5f * UI_DPI_FAC; const int resolution = NODE_LINK_RESOL; @@ -301,7 +291,7 @@ static void pick_input_link_by_link_intersect(const bContext *C, link_to_pick->flag |= NODE_LINK_TEMP_HIGHLIGHT; ED_area_tag_redraw(CTX_wm_area(C)); - if (distance_from_socket > trigger_drag_distance) { + if (!node_find_indicated_socket(snode, &node, &socket, cursor, SOCK_IN)) { pick_link(C, op, nldrag, snode, node, link_to_pick); } } diff --git a/source/blender/editors/space_node/node_select.c b/source/blender/editors/space_node/node_select.c index 1da79671c8e..6548f6f5775 100644 --- a/source/blender/editors/space_node/node_select.c +++ b/source/blender/editors/space_node/node_select.c @@ -568,11 +568,19 @@ static int node_mouse_select(bContext *C, } } else if (deselect_all && node == NULL) { - /* Deselect in empty space. */ - for (tnode = snode->edittree->nodes.first; tnode; tnode = tnode->next) { - nodeSetSelected(tnode, false); + /* Rather than deselecting others, users may want to drag to box-select (drag from empty + * space) or tweak-translate an already selected item. If these cases may apply, delay + * deselection. */ + if (wait_to_deselect_others) { + ret_value = OPERATOR_RUNNING_MODAL; + } + else { + /* Deselect in empty space. */ + for (tnode = snode->edittree->nodes.first; tnode; tnode = tnode->next) { + nodeSetSelected(tnode, false); + } + ret_value = OPERATOR_FINISHED; } - ret_value = OPERATOR_FINISHED; } else if (node != NULL) { /* When clicking on an already selected node, we want to wait to deselect diff --git a/source/blender/editors/space_outliner/outliner_dragdrop.c b/source/blender/editors/space_outliner/outliner_dragdrop.c index b3b36811411..83f71292232 100644 --- a/source/blender/editors/space_outliner/outliner_dragdrop.c +++ b/source/blender/editors/space_outliner/outliner_dragdrop.c @@ -1104,9 +1104,7 @@ static bool collection_drop_init(bContext *C, const wmEvent *event, CollectionDrop *data) { - SpaceOutliner *space_outliner = CTX_wm_space_outliner(C); - - /* Get collection to drop into. */ +/* Get collection to drop into. */ TreeElementInsertType insert_type; TreeElement *te = outliner_drop_insert_collection_find(C, event, &insert_type); if (!te) { @@ -1140,7 +1138,7 @@ static bool collection_drop_init(bContext *C, /* Get collection to drag out of. */ ID *parent = drag_id->from_parent; Collection *from_collection = collection_parent_from_ID(parent); - if (event->ctrl || space_outliner->outlinevis == SO_SCENES) { + if (event->ctrl) { from_collection = NULL; } diff --git a/source/blender/editors/space_outliner/outliner_draw.c b/source/blender/editors/space_outliner/outliner_draw.c index 278162c4338..0916e106abf 100644 --- a/source/blender/editors/space_outliner/outliner_draw.c +++ b/source/blender/editors/space_outliner/outliner_draw.c @@ -63,6 +63,7 @@ #include "ED_screen.h" #include "WM_api.h" +#include "WM_message.h" #include "WM_types.h" #include "GPU_immediate.h" @@ -663,6 +664,7 @@ static void namebutton_fn(bContext *C, void *tsep, char *oldname) { Main *bmain = CTX_data_main(C); SpaceOutliner *space_outliner = CTX_wm_space_outliner(C); + struct wmMsgBus *mbus = CTX_wm_message_bus(C); BLI_mempool *ts = space_outliner->treestore; TreeStoreElem *tselem = tsep; @@ -672,6 +674,8 @@ static void namebutton_fn(bContext *C, void *tsep, char *oldname) if (tselem->type == TSE_SOME_ID) { BLI_libblock_ensure_unique_name(bmain, tselem->id->name); + WM_msg_publish_rna_prop(mbus, tselem->id, tselem->id, ID, name); + switch (GS(tselem->id->name)) { case ID_MA: WM_event_add_notifier(C, NC_MATERIAL, NULL); @@ -724,12 +728,19 @@ static void namebutton_fn(bContext *C, void *tsep, char *oldname) } else { switch (tselem->type) { - case TSE_DEFGROUP: - BKE_object_defgroup_unique_name(te->directdata, (Object *)tselem->id); /* id = object. */ + case TSE_DEFGROUP: { + Object *ob = (Object *)tselem->id; + bDeformGroup *vg = te->directdata; + BKE_object_defgroup_unique_name(vg, ob); + WM_msg_publish_rna_prop(mbus, &ob->id, vg, VertexGroup, name); break; - case TSE_NLA_ACTION: - BLI_libblock_ensure_unique_name(bmain, tselem->id->name); + } + case TSE_NLA_ACTION: { + bAction *act = (bAction *)tselem->id; + BLI_libblock_ensure_unique_name(bmain, act->id.name); + WM_msg_publish_rna_prop(mbus, &act->id, &act->id, ID, name); break; + } case TSE_EBONE: { bArmature *arm = (bArmature *)tselem->id; if (arm->edbo) { @@ -740,6 +751,7 @@ static void namebutton_fn(bContext *C, void *tsep, char *oldname) BLI_strncpy(newname, ebone->name, sizeof(ebone->name)); BLI_strncpy(ebone->name, oldname, sizeof(ebone->name)); ED_armature_bone_rename(bmain, arm, oldname, newname); + WM_msg_publish_rna_prop(mbus, &arm->id, ebone, EditBone, name); WM_event_add_notifier(C, NC_OBJECT | ND_POSE, NULL); } break; @@ -760,6 +772,7 @@ static void namebutton_fn(bContext *C, void *tsep, char *oldname) BLI_strncpy(newname, bone->name, sizeof(bone->name)); BLI_strncpy(bone->name, oldname, sizeof(bone->name)); ED_armature_bone_rename(bmain, arm, oldname, newname); + WM_msg_publish_rna_prop(mbus, &arm->id, bone, Bone, name); WM_event_add_notifier(C, NC_OBJECT | ND_POSE, NULL); break; } @@ -768,6 +781,7 @@ static void namebutton_fn(bContext *C, void *tsep, char *oldname) outliner_viewcontext_init(C, &tvc); Object *ob = (Object *)tselem->id; + bArmature *arm = (bArmature *)ob->data; bPoseChannel *pchan = te->directdata; char newname[sizeof(pchan->name)]; @@ -780,6 +794,7 @@ static void namebutton_fn(bContext *C, void *tsep, char *oldname) BLI_strncpy(newname, pchan->name, sizeof(pchan->name)); BLI_strncpy(pchan->name, oldname, sizeof(pchan->name)); ED_armature_bone_rename(bmain, ob->data, oldname, newname); + WM_msg_publish_rna_prop(mbus, &arm->id, pchan->bone, Bone, name); WM_event_add_notifier(C, NC_OBJECT | ND_POSE, NULL); break; } @@ -793,6 +808,7 @@ static void namebutton_fn(bContext *C, void *tsep, char *oldname) '.', offsetof(bActionGroup, name), sizeof(grp->name)); + WM_msg_publish_rna_prop(mbus, &ob->id, grp, ActionGroup, name); WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob); break; } @@ -807,6 +823,7 @@ static void namebutton_fn(bContext *C, void *tsep, char *oldname) BLI_uniquename( &gpd->layers, gpl, "GP Layer", '.', offsetof(bGPDlayer, info), sizeof(gpl->info)); + WM_msg_publish_rna_prop(mbus, &gpd->id, gpl, GPencilLayer, info); DEG_id_tag_update(&gpd->id, ID_RECALC_GEOMETRY); WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_SELECTED, gpd); break; @@ -822,11 +839,15 @@ static void namebutton_fn(bContext *C, void *tsep, char *oldname) /* Rename, preserving animation and compositing data. */ BKE_view_layer_rename(bmain, scene, view_layer, newname); + WM_msg_publish_rna_prop(mbus, &scene->id, view_layer, ViewLayer, name); WM_event_add_notifier(C, NC_ID | NA_RENAME, NULL); break; } case TSE_LAYER_COLLECTION: { - BLI_libblock_ensure_unique_name(bmain, tselem->id->name); + /* The ID is a #Collection, not a #LayerCollection */ + Collection *collection = (Collection *)tselem->id; + BLI_libblock_ensure_unique_name(bmain, collection->id.name); + WM_msg_publish_rna_prop(mbus, &collection->id, &collection->id, ID, name); WM_event_add_notifier(C, NC_ID | NA_RENAME, NULL); break; } diff --git a/source/blender/editors/space_outliner/outliner_edit.c b/source/blender/editors/space_outliner/outliner_edit.c index 681f7fab18a..7fe66b017a4 100644 --- a/source/blender/editors/space_outliner/outliner_edit.c +++ b/source/blender/editors/space_outliner/outliner_edit.c @@ -466,7 +466,7 @@ static void id_delete(bContext *C, ReportList *reports, TreeElement *te, TreeSto BKE_reportf(reports, RPT_WARNING, "Cannot delete indirectly linked id '%s'", id->name); return; } - if (BKE_library_ID_is_indirectly_used(bmain, id) && ID_REAL_USERS(id) <= 1) { + if (ID_REAL_USERS(id) <= 1 && BKE_library_ID_is_indirectly_used(bmain, id)) { BKE_reportf(reports, RPT_WARNING, "Cannot delete id '%s', indirectly used data-blocks need at least one user", diff --git a/source/blender/editors/space_outliner/outliner_tools.c b/source/blender/editors/space_outliner/outliner_tools.c index dc9205106ab..66eb6ab15dc 100644 --- a/source/blender/editors/space_outliner/outliner_tools.c +++ b/source/blender/editors/space_outliner/outliner_tools.c @@ -699,8 +699,8 @@ static void outliner_object_delete_fn(bContext *C, ReportList *reports, Scene *s reports, RPT_WARNING, "Cannot delete indirectly linked object '%s'", ob->id.name + 2); return; } - if (BKE_library_ID_is_indirectly_used(bmain, ob) && ID_REAL_USERS(ob) <= 1 && - ID_EXTRA_USERS(ob) == 0) { + if (ID_REAL_USERS(ob) <= 1 && ID_EXTRA_USERS(ob) == 0 && + BKE_library_ID_is_indirectly_used(bmain, ob)) { BKE_reportf(reports, RPT_WARNING, "Cannot delete object '%s' from scene '%s', indirectly used objects need at " @@ -1422,8 +1422,8 @@ static Base *outline_batch_delete_hierarchy( base->object->id.name + 2); return base_next; } - if (BKE_library_ID_is_indirectly_used(bmain, object) && ID_REAL_USERS(object) <= 1 && - ID_EXTRA_USERS(object) == 0) { + if (ID_REAL_USERS(object) <= 1 && ID_EXTRA_USERS(object) == 0 && + BKE_library_ID_is_indirectly_used(bmain, object)) { BKE_reportf(reports, RPT_WARNING, "Cannot delete object '%s' from scene '%s', indirectly used objects need at least " @@ -1873,7 +1873,7 @@ static bool outliner_id_operation_item_poll(bContext *C, case OUTLINER_IDOP_OVERRIDE_LIBRARY_RESYNC_HIERARCHY: case OUTLINER_IDOP_OVERRIDE_LIBRARY_RESYNC_HIERARCHY_ENFORCE: case OUTLINER_IDOP_OVERRIDE_LIBRARY_DELETE_HIERARCHY: - if (ID_IS_OVERRIDE_LIBRARY_REAL(tselem->id)) { + if (ID_IS_OVERRIDE_LIBRARY_REAL(tselem->id) && !ID_IS_LINKED(tselem->id)) { return true; } return false; @@ -2263,7 +2263,8 @@ static const EnumPropertyItem outliner_lib_op_type_items[] = { "DELETE", ICON_X, "Delete", - "Delete this library and all its item from Blender - WARNING: no undo"}, + "Delete this library and all its item.\n" + "Warning: No undo"}, {OL_LIB_RELOCATE, "RELOCATE", 0, diff --git a/source/blender/editors/space_outliner/tree/tree_display_view_layer.cc b/source/blender/editors/space_outliner/tree/tree_display_view_layer.cc index 89c9960a24f..f00cf3c34c0 100644 --- a/source/blender/editors/space_outliner/tree/tree_display_view_layer.cc +++ b/source/blender/editors/space_outliner/tree/tree_display_view_layer.cc @@ -148,6 +148,14 @@ void TreeDisplayViewLayer::add_layer_collections_recursive(ListBase &tree, if (!exclude && show_objects_) { add_layer_collection_objects(ten->subtree, *lc, *ten); } + + const bool lib_overrides_visible = !SUPPORT_FILTER_OUTLINER(&space_outliner_) || + ((space_outliner_.filter & SO_FILTER_NO_LIB_OVERRIDE) == 0); + + if (lib_overrides_visible && ID_IS_OVERRIDE_LIBRARY_REAL(&lc->collection->id)) { + outliner_add_element( + &space_outliner_, &ten->subtree, &lc->collection->id, ten, TSE_LIBRARY_OVERRIDE_BASE, 0); + } } } diff --git a/source/blender/editors/space_sequencer/sequencer_add.c b/source/blender/editors/space_sequencer/sequencer_add.c index a6e7903d1b1..2df8dce0b3c 100644 --- a/source/blender/editors/space_sequencer/sequencer_add.c +++ b/source/blender/editors/space_sequencer/sequencer_add.c @@ -228,7 +228,6 @@ static void load_data_init_from_operator(SeqLoadData *load_data, bContext *C, wm PropertyRNA *prop; const bool relative = (prop = RNA_struct_find_property(op->ptr, "relative_path")) && RNA_property_boolean_get(op->ptr, prop); - int is_file = -1; memset(load_data, 0, sizeof(SeqLoadData)); load_data->start_frame = RNA_int_get(op->ptr, "frame_start"); @@ -242,17 +241,26 @@ static void load_data_init_from_operator(SeqLoadData *load_data, bContext *C, wm } if ((prop = RNA_struct_find_property(op->ptr, "filepath"))) { - /* Full path, file is set by the caller. */ RNA_property_string_get(op->ptr, prop, load_data->path); - is_file = 1; + BLI_strncpy(load_data->name, BLI_path_basename(load_data->path), sizeof(load_data->name)); } else if ((prop = RNA_struct_find_property(op->ptr, "directory"))) { - /* Full path, file is set by the caller. */ - RNA_property_string_get(op->ptr, prop, load_data->path); - is_file = 0; + char *directory = RNA_string_get_alloc(op->ptr, "directory", NULL, 0); + + if ((prop = RNA_struct_find_property(op->ptr, "files"))) { + RNA_PROP_BEGIN (op->ptr, itemptr, prop) { + char *filename = RNA_string_get_alloc(&itemptr, "name", NULL, 0); + BLI_strncpy(load_data->name, filename, sizeof(load_data->name)); + BLI_snprintf(load_data->path, sizeof(load_data->path), "%s%s", directory, filename); + MEM_freeN(filename); + break; + } + RNA_PROP_END; + } + MEM_freeN(directory); } - if ((is_file != -1) && relative) { + if (relative) { BLI_path_rel(load_data->path, BKE_main_blendfile_path(bmain)); } @@ -276,19 +284,6 @@ static void load_data_init_from_operator(SeqLoadData *load_data, bContext *C, wm load_data->flags |= SEQ_LOAD_MOVIE_SYNC_FPS; } - if (is_file == 1) { - BLI_strncpy(load_data->name, BLI_path_basename(load_data->path), sizeof(load_data->name)); - } - else if ((prop = RNA_struct_find_property(op->ptr, "files"))) { - RNA_PROP_BEGIN (op->ptr, itemptr, prop) { - char *name = RNA_string_get_alloc(&itemptr, "name", NULL, 0); - BLI_strncpy(load_data->name, name, sizeof(load_data->name)); - MEM_freeN(name); - break; - } - RNA_PROP_END; - } - if ((prop = RNA_struct_find_property(op->ptr, "use_multiview")) && RNA_property_boolean_get(op->ptr, prop)) { if (op->customdata) { @@ -990,8 +985,10 @@ static void sequencer_add_image_strip_load_files( wmOperator *op, Sequence *seq, SeqLoadData *load_data, const int minframe, const int numdigits) { const bool use_placeholders = RNA_boolean_get(op->ptr, "use_placeholders"); - - SEQ_add_image_set_directory(seq, load_data->path); + /* size of Strip->dir. */ + char directory[768]; + BLI_split_dir_part(load_data->path, directory, sizeof(directory)); + SEQ_add_image_set_directory(seq, directory); if (use_placeholders) { sequencer_image_seq_reserve_frames( diff --git a/source/blender/editors/space_sequencer/sequencer_draw.c b/source/blender/editors/space_sequencer/sequencer_draw.c index e4afb27dd2e..7beb61e48d2 100644 --- a/source/blender/editors/space_sequencer/sequencer_draw.c +++ b/source/blender/editors/space_sequencer/sequencer_draw.c @@ -105,8 +105,6 @@ * it messes up transform. */ #undef SEQ_ALL_BEGIN #undef SEQ_ALL_END -#undef SEQ_CURRENT_BEGIN -#undef SEQ_CURRENT_END static Sequence *special_seq_update = NULL; diff --git a/source/blender/editors/space_sequencer/sequencer_edit.c b/source/blender/editors/space_sequencer/sequencer_edit.c index 78d263dffad..40a0af18b18 100644 --- a/source/blender/editors/space_sequencer/sequencer_edit.c +++ b/source/blender/editors/space_sequencer/sequencer_edit.c @@ -312,8 +312,7 @@ static int sequencer_snap_exec(bContext *C, wmOperator *op) } } - /* Test for effects and overlap. - * Don't use SEQ_CURRENT_BEGIN since that would be recursive. */ + /* Test for effects and overlap. */ for (seq = ed->seqbasep->first; seq; seq = seq->next) { if (seq->flag & SELECT && !(seq->depth == 0 && seq->flag & SEQ_LOCK)) { seq->flag &= ~SEQ_OVERLAP; @@ -1411,28 +1410,25 @@ static int sequencer_split_exec(bContext *C, wmOperator *op) } if (changed) { /* Got new strips? */ - Sequence *seq; if (ignore_selection) { if (use_cursor_position) { - SEQ_CURRENT_BEGIN (ed, seq) { + LISTBASE_FOREACH (Sequence *, seq, SEQ_active_seqbase_get(ed)) { if (seq->enddisp == split_frame && seq->machine == split_channel) { seq_selected = seq->flag & SEQ_ALLSEL; } } - SEQ_CURRENT_END; if (!seq_selected) { - SEQ_CURRENT_BEGIN (ed, seq) { + LISTBASE_FOREACH (Sequence *, seq, SEQ_active_seqbase_get(ed)) { if (seq->startdisp == split_frame && seq->machine == split_channel) { seq->flag &= ~SEQ_ALLSEL; } } - SEQ_CURRENT_END; } } } else { if (split_side != SEQ_SIDE_BOTH) { - SEQ_CURRENT_BEGIN (ed, seq) { + LISTBASE_FOREACH (Sequence *, seq, SEQ_active_seqbase_get(ed)) { if (split_side == SEQ_SIDE_LEFT) { if (seq->startdisp >= split_frame) { seq->flag &= ~SEQ_ALLSEL; @@ -1444,7 +1440,6 @@ static int sequencer_split_exec(bContext *C, wmOperator *op) } } } - SEQ_CURRENT_END; } } @@ -1652,16 +1647,14 @@ static int sequencer_delete_exec(bContext *C, wmOperator *UNUSED(op)) Main *bmain = CTX_data_main(C); Scene *scene = CTX_data_scene(C); Editing *ed = SEQ_editing_get(scene, false); - Sequence *seq; SEQ_prefetch_stop(scene); - SEQ_CURRENT_BEGIN (scene->ed, seq) { + LISTBASE_FOREACH (Sequence *, seq, SEQ_active_seqbase_get(ed)) { if (seq->flag & SELECT) { SEQ_edit_flag_for_removal(scene, ed->seqbasep, seq); } } - SEQ_CURRENT_END; SEQ_edit_remove_flagged_sequences(scene, ed->seqbasep); DEG_id_tag_update(&scene->id, ID_RECALC_SEQUENCER_STRIPS); @@ -2418,17 +2411,15 @@ void SEQUENCER_OT_copy(wmOperatorType *ot) void ED_sequencer_deselect_all(Scene *scene) { - Sequence *seq; Editing *ed = SEQ_editing_get(scene, false); if (ed == NULL) { return; } - SEQ_CURRENT_BEGIN (ed, seq) { + LISTBASE_FOREACH (Sequence *, seq, SEQ_active_seqbase_get(ed)) { seq->flag &= ~SEQ_ALLSEL; } - SEQ_CURRENT_END; } static int sequencer_paste_exec(bContext *C, wmOperator *op) diff --git a/source/blender/editors/space_sequencer/sequencer_modifier.c b/source/blender/editors/space_sequencer/sequencer_modifier.c index f11a879912c..9b3ecacceb9 100644 --- a/source/blender/editors/space_sequencer/sequencer_modifier.c +++ b/source/blender/editors/space_sequencer/sequencer_modifier.c @@ -230,14 +230,13 @@ static int strip_modifier_copy_exec(bContext *C, wmOperator *op) Scene *scene = CTX_data_scene(C); Editing *ed = scene->ed; Sequence *seq = SEQ_select_active_get(scene); - Sequence *seq_iter; const int type = RNA_enum_get(op->ptr, "type"); if (!seq || !seq->modifiers.first) { return OPERATOR_CANCELLED; } - SEQ_CURRENT_BEGIN (ed, seq_iter) { + LISTBASE_FOREACH (Sequence *, seq_iter, SEQ_active_seqbase_get(ed)) { if (seq_iter->flag & SELECT) { if (seq_iter == seq) { continue; @@ -259,7 +258,6 @@ static int strip_modifier_copy_exec(bContext *C, wmOperator *op) SEQ_modifier_list_copy(seq_iter, seq); } } - SEQ_CURRENT_END; SEQ_relations_invalidate_cache_preprocessed(scene, seq); WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene); diff --git a/source/blender/editors/space_sequencer/sequencer_proxy.c b/source/blender/editors/space_sequencer/sequencer_proxy.c index e44afde371a..df84772aa8c 100644 --- a/source/blender/editors/space_sequencer/sequencer_proxy.c +++ b/source/blender/editors/space_sequencer/sequencer_proxy.c @@ -58,7 +58,6 @@ static void seq_proxy_build_job(const bContext *C, ReportList *reports) Scene *scene = CTX_data_scene(C); Editing *ed = SEQ_editing_get(scene, false); ScrArea *area = CTX_wm_area(C); - Sequence *seq; if (ed == NULL) { return; @@ -70,7 +69,7 @@ static void seq_proxy_build_job(const bContext *C, ReportList *reports) GSet *file_list = BLI_gset_new(BLI_ghashutil_strhash_p, BLI_ghashutil_strcmp, "file list"); bool selected = false; /* Check for no selected strips */ - SEQ_CURRENT_BEGIN (ed, seq) { + LISTBASE_FOREACH (Sequence *, seq, SEQ_active_seqbase_get(ed)) { if (!ELEM(seq->type, SEQ_TYPE_MOVIE, SEQ_TYPE_IMAGE) || (seq->flag & SELECT) == 0) { continue; } @@ -92,7 +91,6 @@ static void seq_proxy_build_job(const bContext *C, ReportList *reports) BKE_reportf(reports, RPT_WARNING, "Overwrite is not checked for %s, skipping", seq->name); } } - SEQ_CURRENT_END; BLI_gset_free(file_list, MEM_freeN); @@ -124,7 +122,6 @@ static int sequencer_rebuild_proxy_exec(bContext *C, wmOperator *UNUSED(op)) struct Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C); Scene *scene = CTX_data_scene(C); Editing *ed = SEQ_editing_get(scene, false); - Sequence *seq; GSet *file_list; if (ed == NULL) { @@ -133,7 +130,7 @@ static int sequencer_rebuild_proxy_exec(bContext *C, wmOperator *UNUSED(op)) file_list = BLI_gset_new(BLI_ghashutil_strhash_p, BLI_ghashutil_strcmp, "file list"); - SEQ_CURRENT_BEGIN (ed, seq) { + LISTBASE_FOREACH (Sequence *, seq, SEQ_active_seqbase_get(ed)) { if ((seq->flag & SELECT)) { ListBase queue = {NULL, NULL}; LinkData *link; @@ -150,7 +147,6 @@ static int sequencer_rebuild_proxy_exec(bContext *C, wmOperator *UNUSED(op)) SEQ_relations_free_imbuf(scene, &ed->seqbase, false); } } - SEQ_CURRENT_END; BLI_gset_free(file_list, MEM_freeN); @@ -189,7 +185,6 @@ static int sequencer_enable_proxies_exec(bContext *C, wmOperator *op) { Scene *scene = CTX_data_scene(C); Editing *ed = SEQ_editing_get(scene, false); - Sequence *seq; bool proxy_25 = RNA_boolean_get(op->ptr, "proxy_25"); bool proxy_50 = RNA_boolean_get(op->ptr, "proxy_50"); bool proxy_75 = RNA_boolean_get(op->ptr, "proxy_75"); @@ -201,7 +196,7 @@ static int sequencer_enable_proxies_exec(bContext *C, wmOperator *op) turnon = false; } - SEQ_CURRENT_BEGIN (ed, seq) { + LISTBASE_FOREACH (Sequence *, seq, SEQ_active_seqbase_get(ed)) { if ((seq->flag & SELECT)) { if (ELEM(seq->type, SEQ_TYPE_MOVIE, SEQ_TYPE_IMAGE)) { SEQ_proxy_set(seq, turnon); @@ -246,7 +241,6 @@ static int sequencer_enable_proxies_exec(bContext *C, wmOperator *op) } } } - SEQ_CURRENT_END; WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene); diff --git a/source/blender/editors/space_sequencer/sequencer_select.c b/source/blender/editors/space_sequencer/sequencer_select.c index 5f0a18fbd0b..a9f8a70d61e 100644 --- a/source/blender/editors/space_sequencer/sequencer_select.c +++ b/source/blender/editors/space_sequencer/sequencer_select.c @@ -548,14 +548,14 @@ static int sequencer_select_exec(bContext *C, wmOperator *op) const float x = UI_view2d_region_to_view_x(v2d, mval[0]); - SEQ_CURRENT_BEGIN (ed, seq) { - if (((x < CFRA) && (seq->enddisp <= CFRA)) || ((x >= CFRA) && (seq->startdisp >= CFRA))) { + LISTBASE_FOREACH (Sequence *, seq_iter, SEQ_active_seqbase_get(ed)) { + if (((x < CFRA) && (seq_iter->enddisp <= CFRA)) || + ((x >= CFRA) && (seq_iter->startdisp >= CFRA))) { /* Select left or right. */ - seq->flag |= SELECT; - recurs_sel_seq(seq); + seq_iter->flag |= SELECT; + recurs_sel_seq(seq_iter); } } - SEQ_CURRENT_END; { SpaceSeq *sseq = CTX_wm_space_seq(C); @@ -1170,7 +1170,6 @@ static int sequencer_select_side_of_frame_exec(bContext *C, wmOperator *op) Editing *ed = SEQ_editing_get(scene, false); const bool extend = RNA_boolean_get(op->ptr, "extend"); const int side = RNA_enum_get(op->ptr, "side"); - Sequence *seq; if (ed == NULL) { return OPERATOR_CANCELLED; @@ -1179,7 +1178,7 @@ static int sequencer_select_side_of_frame_exec(bContext *C, wmOperator *op) ED_sequencer_deselect_all(scene); } const int timeline_frame = CFRA; - SEQ_CURRENT_BEGIN (ed, seq) { + LISTBASE_FOREACH (Sequence *, seq, SEQ_active_seqbase_get(ed)) { bool test = false; switch (side) { case -1: @@ -1198,7 +1197,6 @@ static int sequencer_select_side_of_frame_exec(bContext *C, wmOperator *op) recurs_sel_seq(seq); } } - SEQ_CURRENT_END; ED_outliner_select_sync_from_sequence_tag(C); @@ -1483,58 +1481,51 @@ static const EnumPropertyItem sequencer_prop_select_grouped_types[] = { static bool select_grouped_type(Editing *ed, Sequence *actseq, const int channel) { - Sequence *seq; bool changed = false; - SEQ_CURRENT_BEGIN (ed, seq) { + LISTBASE_FOREACH (Sequence *, seq, SEQ_active_seqbase_get(ed)) { if (SEQ_CHANNEL_CHECK(seq, channel) && seq->type == actseq->type) { seq->flag |= SELECT; changed = true; } } - SEQ_CURRENT_END; return changed; } static bool select_grouped_type_basic(Editing *ed, Sequence *actseq, const int channel) { - Sequence *seq; bool changed = false; const bool is_sound = SEQ_IS_SOUND(actseq); - SEQ_CURRENT_BEGIN (ed, seq) { + LISTBASE_FOREACH (Sequence *, seq, SEQ_active_seqbase_get(ed)) { if (SEQ_CHANNEL_CHECK(seq, channel) && (is_sound ? SEQ_IS_SOUND(seq) : !SEQ_IS_SOUND(seq))) { seq->flag |= SELECT; changed = true; } } - SEQ_CURRENT_END; return changed; } static bool select_grouped_type_effect(Editing *ed, Sequence *actseq, const int channel) { - Sequence *seq; bool changed = false; const bool is_effect = SEQ_IS_EFFECT(actseq); - SEQ_CURRENT_BEGIN (ed, seq) { + LISTBASE_FOREACH (Sequence *, seq, SEQ_active_seqbase_get(ed)) { if (SEQ_CHANNEL_CHECK(seq, channel) && (is_effect ? SEQ_IS_EFFECT(seq) : !SEQ_IS_EFFECT(seq))) { seq->flag |= SELECT; changed = true; } } - SEQ_CURRENT_END; return changed; } static bool select_grouped_data(Editing *ed, Sequence *actseq, const int channel) { - Sequence *seq; bool changed = false; const char *dir = actseq->strip ? actseq->strip->dir : NULL; @@ -1543,45 +1534,41 @@ static bool select_grouped_data(Editing *ed, Sequence *actseq, const int channel } if (SEQ_HAS_PATH(actseq) && dir) { - SEQ_CURRENT_BEGIN (ed, seq) { + LISTBASE_FOREACH (Sequence *, seq, SEQ_active_seqbase_get(ed)) { if (SEQ_CHANNEL_CHECK(seq, channel) && SEQ_HAS_PATH(seq) && seq->strip && STREQ(seq->strip->dir, dir)) { seq->flag |= SELECT; changed = true; } } - SEQ_CURRENT_END; } else if (actseq->type == SEQ_TYPE_SCENE) { Scene *sce = actseq->scene; - SEQ_CURRENT_BEGIN (ed, seq) { + LISTBASE_FOREACH (Sequence *, seq, SEQ_active_seqbase_get(ed)) { if (SEQ_CHANNEL_CHECK(seq, channel) && seq->type == SEQ_TYPE_SCENE && seq->scene == sce) { seq->flag |= SELECT; changed = true; } } - SEQ_CURRENT_END; } else if (actseq->type == SEQ_TYPE_MOVIECLIP) { MovieClip *clip = actseq->clip; - SEQ_CURRENT_BEGIN (ed, seq) { + LISTBASE_FOREACH (Sequence *, seq, SEQ_active_seqbase_get(ed)) { if (SEQ_CHANNEL_CHECK(seq, channel) && seq->type == SEQ_TYPE_MOVIECLIP && seq->clip == clip) { seq->flag |= SELECT; changed = true; } } - SEQ_CURRENT_END; } else if (actseq->type == SEQ_TYPE_MASK) { struct Mask *mask = actseq->mask; - SEQ_CURRENT_BEGIN (ed, seq) { + LISTBASE_FOREACH (Sequence *, seq, SEQ_active_seqbase_get(ed)) { if (SEQ_CHANNEL_CHECK(seq, channel) && seq->type == SEQ_TYPE_MASK && seq->mask == mask) { seq->flag |= SELECT; changed = true; } } - SEQ_CURRENT_END; } return changed; @@ -1589,7 +1576,6 @@ static bool select_grouped_data(Editing *ed, Sequence *actseq, const int channel static bool select_grouped_effect(Editing *ed, Sequence *actseq, const int channel) { - Sequence *seq; bool changed = false; bool effects[SEQ_TYPE_MAX + 1]; @@ -1597,15 +1583,14 @@ static bool select_grouped_effect(Editing *ed, Sequence *actseq, const int chann effects[i] = false; } - SEQ_CURRENT_BEGIN (ed, seq) { + LISTBASE_FOREACH (Sequence *, seq, SEQ_active_seqbase_get(ed)) { if (SEQ_CHANNEL_CHECK(seq, channel) && (seq->type & SEQ_TYPE_EFFECT) && ELEM(actseq, seq->seq1, seq->seq2, seq->seq3)) { effects[seq->type] = true; } } - SEQ_CURRENT_END; - SEQ_CURRENT_BEGIN (ed, seq) { + LISTBASE_FOREACH (Sequence *, seq, SEQ_active_seqbase_get(ed)) { if (SEQ_CHANNEL_CHECK(seq, channel) && effects[seq->type]) { if (seq->seq1) { seq->seq1->flag |= SELECT; @@ -1619,30 +1604,26 @@ static bool select_grouped_effect(Editing *ed, Sequence *actseq, const int chann changed = true; } } - SEQ_CURRENT_END; return changed; } static bool select_grouped_time_overlap(Editing *ed, Sequence *actseq) { - Sequence *seq; bool changed = false; - SEQ_CURRENT_BEGIN (ed, seq) { + LISTBASE_FOREACH (Sequence *, seq, SEQ_active_seqbase_get(ed)) { if (seq->startdisp < actseq->enddisp && seq->enddisp > actseq->startdisp) { seq->flag |= SELECT; changed = true; } } - SEQ_CURRENT_END; return changed; } static bool select_grouped_effect_link(Editing *ed, Sequence *actseq, const int channel) { - Sequence *seq = NULL; bool changed = false; const bool is_audio = ((actseq->type == SEQ_TYPE_META) || SEQ_IS_SOUND(actseq)); int startdisp = actseq->startdisp; @@ -1650,13 +1631,13 @@ static bool select_grouped_effect_link(Editing *ed, Sequence *actseq, const int int machine = actseq->machine; SeqIterator iter; - SEQ_CURRENT_BEGIN (ed, seq) { + LISTBASE_FOREACH (Sequence *, seq, SEQ_active_seqbase_get(ed)) { seq->tmp = NULL; } - SEQ_CURRENT_END; actseq->tmp = POINTER_FROM_INT(true); + Sequence *seq = NULL; for (SEQ_iterator_begin(ed, &iter, true); iter.valid; SEQ_iterator_next(&iter)) { seq = iter.seq; @@ -1711,7 +1692,7 @@ static int sequencer_select_grouped_exec(bContext *C, wmOperator *op) { Scene *scene = CTX_data_scene(C); Editing *ed = SEQ_editing_get(scene, false); - Sequence *seq, *actseq = SEQ_select_active_get(scene); + Sequence *actseq = SEQ_select_active_get(scene); if (actseq == NULL) { BKE_report(op->reports, RPT_ERROR, "No active sequence!"); @@ -1725,11 +1706,10 @@ static int sequencer_select_grouped_exec(bContext *C, wmOperator *op) bool changed = false; if (!extend) { - SEQ_CURRENT_BEGIN (ed, seq) { + LISTBASE_FOREACH (Sequence *, seq, SEQ_active_seqbase_get(ed)) { seq->flag &= ~SELECT; changed = true; } - SEQ_CURRENT_END; } switch (type) { diff --git a/source/blender/editors/space_spreadsheet/CMakeLists.txt b/source/blender/editors/space_spreadsheet/CMakeLists.txt index a77e74ffd93..1343ab8d851 100644 --- a/source/blender/editors/space_spreadsheet/CMakeLists.txt +++ b/source/blender/editors/space_spreadsheet/CMakeLists.txt @@ -17,9 +17,9 @@ set(INC ../include + ../../blenfont ../../blenkernel ../../blenlib - ../../blenfont ../../bmesh ../../depsgraph ../../functions @@ -38,8 +38,8 @@ set(SRC spreadsheet_from_geometry.cc spreadsheet_ops.cc - spreadsheet_draw.hh spreadsheet_column_layout.hh + spreadsheet_draw.hh spreadsheet_from_geometry.hh spreadsheet_intern.hh ) diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_column_layout.cc b/source/blender/editors/space_spreadsheet/spreadsheet_column_layout.cc index 46760c0dd4e..396767e96d9 100644 --- a/source/blender/editors/space_spreadsheet/spreadsheet_column_layout.cc +++ b/source/blender/editors/space_spreadsheet/spreadsheet_column_layout.cc @@ -41,7 +41,7 @@ class ColumnLayoutDrawer : public SpreadsheetDrawer { const int fontid = UI_style_get()->widget.uifont_id; /* Use a consistent font size for the width calculation. */ - BLF_size(fontid, 11 * U.pixelsize, U.dpi); + BLF_size(fontid, UI_style_get_dpi()->widget.points * U.pixelsize, U.dpi); /* The width of the index column depends on the maximum row index. */ left_column_width = std::to_string(std::max(0, column_layout_.tot_rows - 1)).size() * diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_from_geometry.cc b/source/blender/editors/space_spreadsheet/spreadsheet_from_geometry.cc index 590fbfb5024..910bc0a34ec 100644 --- a/source/blender/editors/space_spreadsheet/spreadsheet_from_geometry.cc +++ b/source/blender/editors/space_spreadsheet/spreadsheet_from_geometry.cc @@ -275,9 +275,9 @@ static void get_selected_corner_indices(const Mesh &mesh, } } -static void get_selected_polygon_indices(const Mesh &mesh, - const IsVertexSelectedFn is_vertex_selected_fn, - Vector<int64_t> &r_polygon_indices) +static void get_selected_face_indices(const Mesh &mesh, + const IsVertexSelectedFn is_vertex_selected_fn, + Vector<int64_t> &r_face_indices) { for (const int poly_index : IndexRange(mesh.totpoly)) { const MPoly &poly = mesh.mpoly[poly_index]; @@ -290,7 +290,7 @@ static void get_selected_polygon_indices(const Mesh &mesh, } } if (is_selected) { - r_polygon_indices.append(poly_index); + r_face_indices.append(poly_index); } } } @@ -315,8 +315,8 @@ static void get_selected_indices_on_domain(const Mesh &mesh, switch (domain) { case ATTR_DOMAIN_POINT: return get_selected_vertex_indices(mesh, is_vertex_selected_fn, r_indices); - case ATTR_DOMAIN_POLYGON: - return get_selected_polygon_indices(mesh, is_vertex_selected_fn, r_indices); + case ATTR_DOMAIN_FACE: + return get_selected_face_indices(mesh, is_vertex_selected_fn, r_indices); case ATTR_DOMAIN_CORNER: return get_selected_corner_indices(mesh, is_vertex_selected_fn, r_indices); case ATTR_DOMAIN_EDGE: diff --git a/source/blender/editors/space_view3d/view3d_draw.c b/source/blender/editors/space_view3d/view3d_draw.c index a46d093c039..0b30ca2771d 100644 --- a/source/blender/editors/space_view3d/view3d_draw.c +++ b/source/blender/editors/space_view3d/view3d_draw.c @@ -832,52 +832,6 @@ static void drawrenderborder(ARegion *region, View3D *v3d) immUnbindProgram(); } -void ED_view3d_draw_depth(Depsgraph *depsgraph, ARegion *region, View3D *v3d, bool alphaoverride) -{ - struct bThemeState theme_state; - Scene *scene = DEG_get_evaluated_scene(depsgraph); - RegionView3D *rv3d = region->regiondata; - - short flag = v3d->flag; - float glalphaclip = U.glalphaclip; - /* temp set drawtype to solid */ - /* Setting these temporarily is not nice */ - v3d->flag &= ~V3D_SELECT_OUTLINE; - - /* not that nice but means we wont zoom into billboards */ - U.glalphaclip = alphaoverride ? 0.5f : glalphaclip; - - /* Tools may request depth outside of regular drawing code. */ - UI_Theme_Store(&theme_state); - UI_SetTheme(SPACE_VIEW3D, RGN_TYPE_WINDOW); - - ED_view3d_draw_setup_view( - G_MAIN->wm.first, NULL, depsgraph, scene, region, v3d, NULL, NULL, NULL); - - /* get surface depth without bias */ - rv3d->rflag |= RV3D_ZOFFSET_DISABLED; - - /* Needed in cases the 3D Viewport isn't already setup. */ - WM_draw_region_viewport_ensure(region, SPACE_VIEW3D); - WM_draw_region_viewport_bind(region); - - GPUViewport *viewport = WM_draw_region_get_viewport(region); - /* When Blender is starting, a click event can trigger a depth test while the viewport is not - * yet available. */ - if (viewport != NULL) { - DRW_draw_depth_loop(depsgraph, region, v3d, viewport, false); - } - - WM_draw_region_viewport_unbind(region); - - rv3d->rflag &= ~RV3D_ZOFFSET_DISABLED; - - U.glalphaclip = glalphaclip; - v3d->flag = flag; - - UI_Theme_Restore(&theme_state); -} - /** \} */ /* -------------------------------------------------------------------- */ @@ -1634,7 +1588,8 @@ void view3d_main_region_draw(const bContext *C, ARegion *region) /* No depth test for drawing action zones afterwards. */ GPU_depth_test(GPU_DEPTH_NONE); - v3d->flag |= V3D_INVALID_BACKBUF; + v3d->runtime.flag &= ~V3D_RUNTIME_DEPTHBUF_OVERRIDDEN; + /* TODO: Clear cache? */ } /** \} */ @@ -2146,8 +2101,15 @@ static bool view3d_clipping_test(const float co[3], const float clip[6][4]) return true; } -/* For 'local' ED_view3d_clipping_local must run first - * then all comparisons can be done in localspace. */ +/** + * Return true when `co` is hidden by the 3D views clipping planes. + * + * \param local: When true use local (object-space) #ED_view3d_clipping_local must run first, + * then all comparisons can be done in local-space. + * \return True when `co` is outside all clipping planes. + * + * \note Callers should check #RV3D_CLIPPING_ENABLED first. + */ bool ED_view3d_clipping_test(const RegionView3D *rv3d, const float co[3], const bool is_local) { return view3d_clipping_test(co, is_local ? rv3d->clip_local : rv3d->clip); @@ -2168,6 +2130,10 @@ static void validate_object_select_id(struct Depsgraph *depsgraph, View3D *v3d, Object *obact) { + /* TODO: Use a flag in the selection engine itself. */ + if (v3d->runtime.flag & V3D_RUNTIME_DEPTHBUF_OVERRIDDEN) { + return; + } Object *obact_eval = DEG_get_evaluated_object(depsgraph, obact); BLI_assert(region->regiontype == RGN_TYPE_WINDOW); @@ -2186,11 +2152,7 @@ static void validate_object_select_id(struct Depsgraph *depsgraph, /* do nothing */ } else { - v3d->flag &= ~V3D_INVALID_BACKBUF; - return; - } - - if (!(v3d->flag & V3D_INVALID_BACKBUF)) { + v3d->runtime.flag |= V3D_RUNTIME_DEPTHBUF_OVERRIDDEN; return; } @@ -2199,9 +2161,7 @@ static void validate_object_select_id(struct Depsgraph *depsgraph, DRW_select_buffer_context_create(&base, 1, -1); } - /* TODO: Create a flag in `DRW_manager` because the drawing is no longer - * made on the back-buffer in this case. */ - v3d->flag &= ~V3D_INVALID_BACKBUF; + v3d->runtime.flag |= V3D_RUNTIME_DEPTHBUF_OVERRIDDEN; } /* TODO: Creating, attaching texture, and destroying a framebuffer is quite slow. @@ -2228,26 +2188,7 @@ static void view3d_opengl_read_Z_pixels(GPUViewport *viewport, rcti *rect, void void ED_view3d_select_id_validate(ViewContext *vc) { - /* TODO: Create a flag in `DRW_manager` because the drawing is no longer - * made on the back-buffer in this case. */ - if (vc->v3d->flag & V3D_INVALID_BACKBUF) { - validate_object_select_id(vc->depsgraph, vc->view_layer, vc->region, vc->v3d, vc->obact); - } -} - -void ED_view3d_backbuf_depth_validate(ViewContext *vc) -{ - if (vc->v3d->flag & V3D_INVALID_BACKBUF) { - ARegion *region = vc->region; - Object *obact_eval = DEG_get_evaluated_object(vc->depsgraph, vc->obact); - - if (obact_eval && ((obact_eval->base_flag & BASE_VISIBLE_DEPSGRAPH) != 0)) { - GPUViewport *viewport = WM_draw_region_get_viewport(region); - DRW_draw_depth_object(vc->scene, vc->region, vc->v3d, viewport, obact_eval); - } - - vc->v3d->flag &= ~V3D_INVALID_BACKBUF; - } + validate_object_select_id(vc->depsgraph, vc->view_layer, vc->region, vc->v3d, vc->obact); } /** @@ -2319,7 +2260,7 @@ void view3d_update_depths_rect(ARegion *region, ViewDepths *d, rcti *rect) } /* Note, with nouveau drivers the glReadPixels() is very slow. T24339. */ -void ED_view3d_depth_update(ARegion *region) +static void view3d_depth_cache_update(ARegion *region) { RegionView3D *rv3d = region->regiondata; @@ -2341,13 +2282,9 @@ void ED_view3d_depth_update(ARegion *region) if (d->damaged) { GPUViewport *viewport = WM_draw_region_get_viewport(region); - rcti r = { - .xmin = 0, - .xmax = d->w, - .ymin = 0, - .ymax = d->h, - }; - view3d_opengl_read_Z_pixels(viewport, &r, d->depths); + DefaultFramebufferList *fbl = GPU_viewport_framebuffer_list_get(viewport); + GPU_framebuffer_read_depth(fbl->depth_only_fb, 0, 0, d->w, d->h, GPU_DATA_FLOAT, d->depths); + /* Assumed to be this as they are never changed. */ d->depth_range[0] = 0.0; d->depth_range[1] = 1.0; @@ -2380,19 +2317,81 @@ float view3d_depth_near(ViewDepths *d) return far == far_real ? FLT_MAX : far; } -void ED_view3d_draw_depth_gpencil(Depsgraph *depsgraph, Scene *scene, ARegion *region, View3D *v3d) +/** + * Redraw the viewport depth buffer. + * + * \param mode: V3D_DEPTH_NO_GPENCIL - Redraw viewport without Grease Pencil and Annotations. + * V3D_DEPTH_GPENCIL_ONLY - Redraw viewport with Grease Pencil and Annotations only. + * V3D_DEPTH_OBJECT_ONLY - Redraw viewport with active object only. + * \param update_cache: If true, store the entire depth buffer in #rv3d->depths. + */ +void ED_view3d_depth_override(Depsgraph *depsgraph, + ARegion *region, + View3D *v3d, + Object *obact, + eV3DDepthOverrideMode mode, + bool update_cache) { - /* Setup view matrix. */ - ED_view3d_draw_setup_view(NULL, NULL, depsgraph, scene, region, v3d, NULL, NULL, NULL); + if (v3d->runtime.flag & V3D_RUNTIME_DEPTHBUF_OVERRIDDEN) { + return; + } + struct bThemeState theme_state; + Scene *scene = DEG_get_evaluated_scene(depsgraph); + RegionView3D *rv3d = region->regiondata; + + short flag = v3d->flag; + /* temp set drawtype to solid */ + /* Setting these temporarily is not nice */ + v3d->flag &= ~V3D_SELECT_OUTLINE; + + /* Tools may request depth outside of regular drawing code. */ + UI_Theme_Store(&theme_state); + UI_SetTheme(SPACE_VIEW3D, RGN_TYPE_WINDOW); + + ED_view3d_draw_setup_view( + G_MAIN->wm.first, NULL, depsgraph, scene, region, v3d, NULL, NULL, NULL); - GPU_clear_depth(1.0f); + /* get surface depth without bias */ + rv3d->rflag |= RV3D_ZOFFSET_DISABLED; - GPU_depth_test(GPU_DEPTH_LESS_EQUAL); + /* Needed in cases the 3D Viewport isn't already setup. */ + WM_draw_region_viewport_ensure(region, SPACE_VIEW3D); + WM_draw_region_viewport_bind(region); GPUViewport *viewport = WM_draw_region_get_viewport(region); - DRW_draw_depth_loop_gpencil(depsgraph, region, v3d, viewport); + /* When Blender is starting, a click event can trigger a depth test while the viewport is not + * yet available. */ + if (viewport != NULL) { + switch (mode) { + case V3D_DEPTH_NO_GPENCIL: + DRW_draw_depth_loop(depsgraph, region, v3d, viewport); + break; + case V3D_DEPTH_GPENCIL_ONLY: + DRW_draw_depth_loop_gpencil(depsgraph, region, v3d, viewport); + break; + case V3D_DEPTH_OBJECT_ONLY: + DRW_draw_depth_object( + scene, region, v3d, viewport, DEG_get_evaluated_object(depsgraph, obact)); + break; + } - GPU_depth_test(GPU_DEPTH_NONE); + if (rv3d->depths != NULL) { + rv3d->depths->damaged = true; + /* TODO: Clear cache? */ + } + if (update_cache) { + view3d_depth_cache_update(region); + } + } + + WM_draw_region_viewport_unbind(region); + + rv3d->rflag &= ~RV3D_ZOFFSET_DISABLED; + + v3d->flag = flag; + v3d->runtime.flag |= V3D_RUNTIME_DEPTHBUF_OVERRIDDEN; + + UI_Theme_Restore(&theme_state); } /** \} */ diff --git a/source/blender/editors/space_view3d/view3d_edit.c b/source/blender/editors/space_view3d/view3d_edit.c index dc590833368..5f3d71cc190 100644 --- a/source/blender/editors/space_view3d/view3d_edit.c +++ b/source/blender/editors/space_view3d/view3d_edit.c @@ -3628,9 +3628,8 @@ static int view3d_zoom_border_exec(bContext *C, wmOperator *op) ED_view3d_dist_range_get(v3d, dist_range); - /* Get Z Depths, needed for perspective, nice for ortho */ - ED_view3d_draw_depth(CTX_data_ensure_evaluated_depsgraph(C), region, v3d, true); - + ED_view3d_depth_override( + CTX_data_ensure_evaluated_depsgraph(C), region, v3d, NULL, V3D_DEPTH_NO_GPENCIL, false); { /* avoid allocating the whole depth buffer */ ViewDepths depth_temp = {0}; diff --git a/source/blender/editors/space_view3d/view3d_gizmo_navigate.c b/source/blender/editors/space_view3d/view3d_gizmo_navigate.c index 6fa974cdb09..f11b8566690 100644 --- a/source/blender/editors/space_view3d/view3d_gizmo_navigate.c +++ b/source/blender/editors/space_view3d/view3d_gizmo_navigate.c @@ -67,45 +67,73 @@ enum { GZ_INDEX_ORTHO = 4, GZ_INDEX_CAMERA = 5, - GZ_INDEX_TOTAL = 6, + /* overlaps GZ_INDEX_ORTHO (switch between) */ + GZ_INDEX_CAMERA_LOCK = 6, + GZ_INDEX_CAMERA_UNLOCK = 7, + + GZ_INDEX_TOTAL = 8, }; struct NavigateGizmoInfo { const char *opname; const char *gizmo; uint icon; + void (*op_prop_fn)(PointerRNA *ptr); }; +static void navigate_context_toggle_camera_lock_init(PointerRNA *ptr) +{ + RNA_string_set(ptr, "data_path", "space_data.lock_camera"); +} + static struct NavigateGizmoInfo g_navigate_params[GZ_INDEX_TOTAL] = { { .opname = "VIEW3D_OT_move", .gizmo = "GIZMO_GT_button_2d", - ICON_VIEW_PAN, + .icon = ICON_VIEW_PAN, + .op_prop_fn = NULL, }, { .opname = "VIEW3D_OT_rotate", .gizmo = "VIEW3D_GT_navigate_rotate", - 0, + .icon = ICON_NONE, + .op_prop_fn = NULL, }, { .opname = "VIEW3D_OT_zoom", .gizmo = "GIZMO_GT_button_2d", - ICON_VIEW_ZOOM, + .icon = ICON_VIEW_ZOOM, + .op_prop_fn = NULL, }, { .opname = "VIEW3D_OT_view_persportho", .gizmo = "GIZMO_GT_button_2d", - ICON_VIEW_PERSPECTIVE, + .icon = ICON_VIEW_PERSPECTIVE, + .op_prop_fn = NULL, }, { .opname = "VIEW3D_OT_view_persportho", .gizmo = "GIZMO_GT_button_2d", - ICON_VIEW_ORTHO, + .icon = ICON_VIEW_ORTHO, + .op_prop_fn = NULL, }, { .opname = "VIEW3D_OT_view_camera", .gizmo = "GIZMO_GT_button_2d", - ICON_VIEW_CAMERA, + .icon = ICON_VIEW_CAMERA, + .op_prop_fn = NULL, + }, + { + .opname = "WM_OT_context_toggle", /* GZ_INDEX_CAMERA_LOCK. Lock Camera to View. */ + .gizmo = "GIZMO_GT_button_2d", + .icon = ICON_UNLOCKED, + .op_prop_fn = navigate_context_toggle_camera_lock_init, + }, + { + .opname = "WM_OT_context_toggle", /* GZ_INDEX_CAMERA_UNLOCK. Unlock Camera to View. */ + .gizmo = "GIZMO_GT_button_2d", + .icon = ICON_LOCKED, + .op_prop_fn = navigate_context_toggle_camera_lock_init, }, }; @@ -115,8 +143,11 @@ struct NavigateWidgetGroup { struct { rcti rect_visible; struct { + int flag2; + } v3d; + struct { char is_persp; - char is_camera; + bool is_camera; char viewlock; } rv3d; } state; @@ -177,7 +208,7 @@ static void WIDGETGROUP_navigate_setup(const bContext *C, wmGizmoGroup *gzgroup) /* may be overwritten later */ gz->scale_basis = GIZMO_MINI_SIZE / 2.0f; - if (info->icon != 0) { + if (info->icon != ICON_NONE) { PropertyRNA *prop = RNA_struct_find_property(gz->ptr, "icon"); RNA_property_enum_set(gz->ptr, prop, info->icon); RNA_enum_set( @@ -185,7 +216,10 @@ static void WIDGETGROUP_navigate_setup(const bContext *C, wmGizmoGroup *gzgroup) } wmOperatorType *ot = WM_operatortype_find(info->opname, true); - WM_gizmo_operator_set(gz, 0, ot, NULL); + PointerRNA *ptr = WM_gizmo_operator_set(gz, 0, ot, NULL); + if (info->op_prop_fn != NULL) { + info->op_prop_fn(ptr); + } } { @@ -195,7 +229,13 @@ static void WIDGETGROUP_navigate_setup(const bContext *C, wmGizmoGroup *gzgroup) /* Click only buttons (not modal). */ { - int gz_ids[] = {GZ_INDEX_PERSP, GZ_INDEX_ORTHO, GZ_INDEX_CAMERA}; + int gz_ids[] = { + GZ_INDEX_PERSP, + GZ_INDEX_ORTHO, + GZ_INDEX_CAMERA, + GZ_INDEX_CAMERA_LOCK, + GZ_INDEX_CAMERA_UNLOCK, + }; for (int i = 0; i < ARRAY_SIZE(gz_ids); i++) { wmGizmo *gz = navgroup->gz_array[gz_ids[i]]; RNA_boolean_set(gz->ptr, "show_drag", false); @@ -243,6 +283,8 @@ static void WIDGETGROUP_navigate_draw_prepare(const bContext *C, wmGizmoGroup *g struct NavigateWidgetGroup *navgroup = gzgroup->customdata; ARegion *region = CTX_wm_region(C); const RegionView3D *rv3d = region->regiondata; + View3D *v3d = CTX_wm_view3d(C); + const int v3d_flag2_test = V3D_LOCK_CAMERA; for (int i = 0; i < 3; i++) { copy_v3_v3(navgroup->gz_array[GZ_INDEX_ROTATE]->matrix_offset[i], rv3d->viewmat[i]); @@ -250,8 +292,13 @@ static void WIDGETGROUP_navigate_draw_prepare(const bContext *C, wmGizmoGroup *g const rcti *rect_visible = ED_region_visible_rect(region); + /* Ensure types match so bits are never lost on assignment. */ + CHECK_TYPE_PAIR(navgroup->state.v3d.flag2, v3d->flag2); + CHECK_TYPE_PAIR(navgroup->state.rv3d.viewlock, rv3d->viewlock); + if ((navgroup->state.rect_visible.xmax == rect_visible->xmax) && (navgroup->state.rect_visible.ymax == rect_visible->ymax) && + (navgroup->state.v3d.flag2 == (v3d->flag2 & v3d_flag2_test)) && (navgroup->state.rv3d.is_persp == rv3d->is_persp) && (navgroup->state.rv3d.is_camera == (rv3d->persp == RV3D_CAMOB)) && (navgroup->state.rv3d.viewlock == RV3D_LOCK_FLAGS(rv3d))) { @@ -259,6 +306,7 @@ static void WIDGETGROUP_navigate_draw_prepare(const bContext *C, wmGizmoGroup *g } navgroup->state.rect_visible = *rect_visible; + navgroup->state.v3d.flag2 = v3d->flag2 & v3d_flag2_test; navgroup->state.rv3d.is_persp = rv3d->is_persp; navgroup->state.rv3d.is_camera = (rv3d->persp == RV3D_CAMOB); navgroup->state.rv3d.viewlock = RV3D_LOCK_FLAGS(rv3d); @@ -333,6 +381,14 @@ static void WIDGETGROUP_navigate_draw_prepare(const bContext *C, wmGizmoGroup *g WM_gizmo_set_flag(gz, WM_GIZMO_HIDDEN, false); } } + + if (navgroup->state.rv3d.is_camera == true) { + gz = navgroup->gz_array[(v3d->flag2 & V3D_LOCK_CAMERA) ? GZ_INDEX_CAMERA_UNLOCK : + GZ_INDEX_CAMERA_LOCK]; + gz->matrix_basis[3][0] = roundf(co[0]); + gz->matrix_basis[3][1] = roundf(co[1] - (icon_offset_mini * icon_mini_slot++)); + WM_gizmo_set_flag(gz, WM_GIZMO_HIDDEN, false); + } } } diff --git a/source/blender/editors/space_view3d/view3d_gizmo_ruler.c b/source/blender/editors/space_view3d/view3d_gizmo_ruler.c index 870996ddefa..833901b6770 100644 --- a/source/blender/editors/space_view3d/view3d_gizmo_ruler.c +++ b/source/blender/editors/space_view3d/view3d_gizmo_ruler.c @@ -387,7 +387,9 @@ static bool view3d_ruler_item_mousemove(struct Depsgraph *depsgraph, } ED_gizmotypes_snap_3d_update( - snap_gizmo, depsgraph, ruler_info->region, v3d, ruler_info->wm, mval_fl, co, NULL); + snap_gizmo, depsgraph, ruler_info->region, v3d, ruler_info->wm, mval_fl); + + ED_gizmotypes_snap_3d_data_get(snap_gizmo, co, NULL, NULL, NULL); } return true; } diff --git a/source/blender/editors/space_view3d/view3d_intern.h b/source/blender/editors/space_view3d/view3d_intern.h index 118ec2425fc..e766ae96c2f 100644 --- a/source/blender/editors/space_view3d/view3d_intern.h +++ b/source/blender/editors/space_view3d/view3d_intern.h @@ -122,17 +122,7 @@ void VIEW3D_OT_walk(struct wmOperatorType *ot); void view3d_main_region_draw(const struct bContext *C, struct ARegion *region); void view3d_draw_region_info(const struct bContext *C, struct ARegion *region); -void ED_view3d_draw_depth(struct Depsgraph *depsgraph, - struct ARegion *region, - View3D *v3d, - bool alphaoverride); - /* view3d_draw_legacy.c */ -void ED_view3d_draw_depth_gpencil(struct Depsgraph *depsgraph, - Scene *scene, - struct ARegion *region, - View3D *v3d); - void ED_view3d_draw_select_loop(struct Depsgraph *depsgraph, ViewContext *vc, Scene *scene, diff --git a/source/blender/editors/space_view3d/view3d_placement.c b/source/blender/editors/space_view3d/view3d_placement.c index 48f274ca71b..b0dfd4af7c5 100644 --- a/source/blender/editors/space_view3d/view3d_placement.c +++ b/source/blender/editors/space_view3d/view3d_placement.c @@ -1058,9 +1058,7 @@ static void view3d_interactive_add_begin(bContext *C, wmOperator *op, const wmEv ipd->region, ipd->v3d, G_MAIN->wm.first, - mval_fl, - NULL, - NULL); + mval_fl); } } @@ -1507,9 +1505,8 @@ static int view3d_interactive_add_modal(bContext *C, wmOperator *op, const wmEve ipd->region, ipd->v3d, G_MAIN->wm.first, - mval_fl, - ipd->snap_co, - NULL)) { + mval_fl)) { + ED_gizmotypes_snap_3d_data_get(ipd->snap_gizmo, ipd->snap_co, NULL, NULL, NULL); ipd->is_snap_found = true; } ED_gizmotypes_snap_3d_toggle_clear(ipd->snap_gizmo); diff --git a/source/blender/editors/space_view3d/view3d_utils.c b/source/blender/editors/space_view3d/view3d_utils.c index e3acda9bffb..3b4834045f8 100644 --- a/source/blender/editors/space_view3d/view3d_utils.c +++ b/source/blender/editors/space_view3d/view3d_utils.c @@ -1024,6 +1024,7 @@ static float view_autodist_depth_margin(ARegion *region, const int mval[2], int /** * Get the world-space 3d location from a screen-space 2d point. + * TODO: Implement #alphaoverride. We don't want to zoom into billboards. * * \param mval: Input screen-space pixel location. * \param mouse_worldloc: Output world-space location. @@ -1034,7 +1035,7 @@ bool ED_view3d_autodist(Depsgraph *depsgraph, View3D *v3d, const int mval[2], float mouse_worldloc[3], - const bool alphaoverride, + const bool UNUSED(alphaoverride), const float fallback_depth_pt[3]) { float depth_close; @@ -1042,7 +1043,7 @@ bool ED_view3d_autodist(Depsgraph *depsgraph, bool depth_ok = false; /* Get Z Depths, needed for perspective, nice for ortho */ - ED_view3d_draw_depth(depsgraph, region, v3d, alphaoverride); + ED_view3d_depth_override(depsgraph, region, v3d, NULL, V3D_DEPTH_NO_GPENCIL, false); /* Attempt with low margin's first */ int i = 0; @@ -1067,22 +1068,7 @@ bool ED_view3d_autodist(Depsgraph *depsgraph, return false; } -void ED_view3d_autodist_init(Depsgraph *depsgraph, ARegion *region, View3D *v3d, int mode) -{ - /* Get Z Depths, needed for perspective, nice for ortho */ - switch (mode) { - case 0: - ED_view3d_draw_depth(depsgraph, region, v3d, true); - break; - case 1: { - Scene *scene = DEG_get_evaluated_scene(depsgraph); - ED_view3d_draw_depth_gpencil(depsgraph, scene, region, v3d); - break; - } - } -} - -/* no 4x4 sampling, run #ED_view3d_autodist_init first */ +/* no 4x4 sampling, run #ED_view3d_depth_override first */ bool ED_view3d_autodist_simple(ARegion *region, const int mval[2], float mouse_worldloc[3], diff --git a/source/blender/editors/transform/transform_convert.c b/source/blender/editors/transform/transform_convert.c index 2cc3025c3a5..c021c084a23 100644 --- a/source/blender/editors/transform/transform_convert.c +++ b/source/blender/editors/transform/transform_convert.c @@ -1187,10 +1187,11 @@ static eTFlag flags_from_data_type(eTConvertType data_type) return T_EDIT; case TC_MESH_UV: return T_EDIT | T_POINTS | T_2D_EDIT; + case TC_CURSOR_IMAGE: + return T_2D_EDIT; case TC_PARTICLE_VERTS: return T_POINTS; case TC_POSE: - case TC_CURSOR_IMAGE: case TC_CURSOR_VIEW3D: case TC_OBJECT: case TC_OBJECT_TEXSPACE: @@ -1643,6 +1644,21 @@ void animrecord_check_state(TransInfo *t, struct Object *ob) } } +static void recalcData_cursor_image(TransInfo *t) +{ + TransDataContainer *tc = t->data_container; + TransData *td = tc->data; + float aspect_inv[2]; + + aspect_inv[0] = 1.0f / t->aspect[0]; + aspect_inv[1] = 1.0f / t->aspect[1]; + + td->loc[0] = td->loc[0] * aspect_inv[0]; + td->loc[1] = td->loc[1] * aspect_inv[1]; + + DEG_id_tag_update(&t->scene->id, ID_RECALC_COPY_ON_WRITE); +} + static void recalcData_cursor(TransInfo *t) { DEG_id_tag_update(&t->scene->id, ID_RECALC_COPY_ON_WRITE); @@ -1677,6 +1693,8 @@ void recalcData(TransInfo *t) recalcData_curve(t); break; case TC_CURSOR_IMAGE: + recalcData_cursor_image(t); + break; case TC_CURSOR_VIEW3D: recalcData_cursor(t); break; diff --git a/source/blender/editors/transform/transform_convert_armature.c b/source/blender/editors/transform/transform_convert_armature.c index a4edf51ffee..7f24a0fa5f8 100644 --- a/source/blender/editors/transform/transform_convert_armature.c +++ b/source/blender/editors/transform/transform_convert_armature.c @@ -99,15 +99,7 @@ static void autokeyframe_pose( bPoseChannel *pchan; FCurve *fcu; - /* TODO: this should probably be done per channel instead. */ if (!autokeyframe_cfra_can_key(scene, id)) { - /* tag channels that should have unkeyed data */ - for (pchan = pose->chanbase.first; pchan; pchan = pchan->next) { - if (pchan->bone->flag & BONE_TRANSFORM) { - /* tag this channel */ - pchan->bone->flag |= BONE_UNKEYED; - } - } return; } @@ -139,9 +131,6 @@ static void autokeyframe_pose( ListBase dsources = {NULL, NULL}; - /* clear any 'unkeyed' flag it may have */ - pchan->bone->flag &= ~BONE_UNKEYED; - /* add datasource override for the camera object */ ANIM_relative_keyingset_add_source(&dsources, id, &RNA_PoseBone, pchan); diff --git a/source/blender/editors/transform/transform_convert_cursor.c b/source/blender/editors/transform/transform_convert_cursor.c index e6a972bfc7c..67d85f9610b 100644 --- a/source/blender/editors/transform/transform_convert_cursor.c +++ b/source/blender/editors/transform/transform_convert_cursor.c @@ -56,6 +56,13 @@ void createTransCursor_image(TransInfo *t) } td->flag = TD_SELECTED; + + /* UV coords are scaled by aspects (see UVsToTransData). This also applies for the Cursor in the + * UV Editor which also means that for display and when the cursor coords are flushed + * (recalcData_cursor_image), these are converted each time. */ + cursor_location[0] = cursor_location[0] * t->aspect[0]; + cursor_location[1] = cursor_location[1] * t->aspect[1]; + copy_v3_v3(td->center, cursor_location); td->ob = NULL; diff --git a/source/blender/editors/util/CMakeLists.txt b/source/blender/editors/util/CMakeLists.txt index 7d7d10004a3..cf2b6ee19d5 100644 --- a/source/blender/editors/util/CMakeLists.txt +++ b/source/blender/editors/util/CMakeLists.txt @@ -18,10 +18,10 @@ set(INC ../include ../space_sequencer + ../../blenfont ../../blenkernel ../../blenlib ../../blentranslation - ../../blenfont ../../bmesh ../../depsgraph ../../gpu diff --git a/source/blender/editors/uvedit/uvedit_parametrizer.c b/source/blender/editors/uvedit/uvedit_parametrizer.c index e94aaa49839..7d82884760c 100644 --- a/source/blender/editors/uvedit/uvedit_parametrizer.c +++ b/source/blender/editors/uvedit/uvedit_parametrizer.c @@ -4546,7 +4546,10 @@ void param_edge_set_seam(ParamHandle *handle, ParamKey *vkeys) } } -void param_construct_end(ParamHandle *handle, ParamBool fill, ParamBool topology_from_uvs) +void param_construct_end(ParamHandle *handle, + ParamBool fill, + ParamBool topology_from_uvs, + int *count_fail) { PHandle *phandle = (PHandle *)handle; PChart *chart = phandle->construction_chart; @@ -4574,6 +4577,9 @@ void param_construct_end(ParamHandle *handle, ParamBool fill, ParamBool topology if (!topology_from_uvs && nboundaries == 0) { p_chart_delete(chart); + if (count_fail != NULL) { + *count_fail += 1; + } continue; } @@ -4611,12 +4617,11 @@ void param_lscm_begin(ParamHandle *handle, ParamBool live, ParamBool abf) } } -void param_lscm_solve(ParamHandle *handle) +void param_lscm_solve(ParamHandle *handle, int *count_changed, int *count_failed) { PHandle *phandle = (PHandle *)handle; PChart *chart; int i; - PBool result; param_assert(phandle->state == PHANDLE_STATE_LSCM); @@ -4624,7 +4629,7 @@ void param_lscm_solve(ParamHandle *handle) chart = phandle->charts[i]; if (chart->u.lscm.context) { - result = p_chart_lscm_solve(phandle, chart); + const PBool result = p_chart_lscm_solve(phandle, chart); if (result && !(chart->flag & PCHART_HAS_PINS)) { p_chart_rotate_minimum_area(chart); @@ -4637,6 +4642,17 @@ void param_lscm_solve(ParamHandle *handle) if (!result || !(chart->flag & PCHART_HAS_PINS)) { p_chart_lscm_end(chart); } + + if (result) { + if (count_changed != NULL) { + *count_changed += 1; + } + } + else { + if (count_failed != NULL) { + *count_failed += 1; + } + } } } } diff --git a/source/blender/editors/uvedit/uvedit_parametrizer.h b/source/blender/editors/uvedit/uvedit_parametrizer.h index 2427e589833..e69ce360e61 100644 --- a/source/blender/editors/uvedit/uvedit_parametrizer.h +++ b/source/blender/editors/uvedit/uvedit_parametrizer.h @@ -59,7 +59,10 @@ void param_face_add(ParamHandle *handle, void param_edge_set_seam(ParamHandle *handle, ParamKey *vkeys); -void param_construct_end(ParamHandle *handle, ParamBool fill, ParamBool topology_from_uvs); +void param_construct_end(ParamHandle *handle, + ParamBool fill, + ParamBool topology_from_uvs, + int *count_fail); void param_delete(ParamHandle *handle); /* Least Squares Conformal Maps: @@ -74,7 +77,7 @@ void param_delete(ParamHandle *handle); */ void param_lscm_begin(ParamHandle *handle, ParamBool live, ParamBool abf); -void param_lscm_solve(ParamHandle *handle); +void param_lscm_solve(ParamHandle *handle, int *count_changed, int *count_failed); void param_lscm_end(ParamHandle *handle); /* Stretch */ diff --git a/source/blender/editors/uvedit/uvedit_unwrap_ops.c b/source/blender/editors/uvedit/uvedit_unwrap_ops.c index fc5f41e8ed5..87ae112a237 100644 --- a/source/blender/editors/uvedit/uvedit_unwrap_ops.c +++ b/source/blender/editors/uvedit/uvedit_unwrap_ops.c @@ -165,6 +165,11 @@ typedef struct UnwrapOptions { bool correct_aspect; } UnwrapOptions; +typedef struct UnwrapResultInfo { + int count_changed; + int count_failed; +} UnwrapResultInfo; + static bool uvedit_have_selection(const Scene *scene, BMEditMesh *em, const UnwrapOptions *options) { BMFace *efa; @@ -281,7 +286,8 @@ static void construct_param_handle_face_add(ParamHandle *handle, static ParamHandle *construct_param_handle(const Scene *scene, Object *ob, BMesh *bm, - const UnwrapOptions *options) + const UnwrapOptions *options, + UnwrapResultInfo *result_info) { ParamHandle *handle; BMFace *efa; @@ -344,7 +350,10 @@ static ParamHandle *construct_param_handle(const Scene *scene, } } - param_construct_end(handle, options->fill_holes, options->topology_from_uvs); + param_construct_end(handle, + options->fill_holes, + options->topology_from_uvs, + result_info ? &result_info->count_failed : NULL); return handle; } @@ -355,7 +364,8 @@ static ParamHandle *construct_param_handle(const Scene *scene, static ParamHandle *construct_param_handle_multi(const Scene *scene, Object **objects, const uint objects_len, - const UnwrapOptions *options) + const UnwrapOptions *options, + int *count_fail) { ParamHandle *handle; BMFace *efa; @@ -431,7 +441,7 @@ static ParamHandle *construct_param_handle_multi(const Scene *scene, offset += bm->totface; } - param_construct_end(handle, options->fill_holes, options->topology_from_uvs); + param_construct_end(handle, options->fill_holes, options->topology_from_uvs, count_fail); return handle; } @@ -475,7 +485,8 @@ static void texface_from_original_index(const Scene *scene, static ParamHandle *construct_param_handle_subsurfed(const Scene *scene, Object *ob, BMEditMesh *em, - const UnwrapOptions *options) + const UnwrapOptions *options, + UnwrapResultInfo *result_info) { ParamHandle *handle; /* index pointers */ @@ -651,7 +662,10 @@ static ParamHandle *construct_param_handle_subsurfed(const Scene *scene, } } - param_construct_end(handle, options->fill_holes, options->topology_from_uvs); + param_construct_end(handle, + options->fill_holes, + options->topology_from_uvs, + result_info ? &result_info->count_failed : NULL); /* cleanup */ MEM_freeN(faceMap); @@ -707,7 +721,7 @@ static bool minimize_stretch_init(bContext *C, wmOperator *op) ms->blend = RNA_float_get(op->ptr, "blend"); ms->iterations = RNA_int_get(op->ptr, "iterations"); ms->i = 0; - ms->handle = construct_param_handle_multi(scene, objects, objects_len, &options); + ms->handle = construct_param_handle_multi(scene, objects, objects_len, &options, NULL); ms->lasttime = PIL_check_seconds_timer(); param_stretch_begin(ms->handle); @@ -959,7 +973,7 @@ static void uvedit_pack_islands(const Scene *scene, Object *ob, BMesh *bm) bool ignore_pinned = false; ParamHandle *handle; - handle = construct_param_handle(scene, ob, bm, &options); + handle = construct_param_handle(scene, ob, bm, &options, NULL); param_pack(handle, scene->toolsettings->uvcalc_margin, rotate, ignore_pinned); param_flush(handle); param_delete(handle); @@ -979,7 +993,7 @@ static void uvedit_pack_islands_multi(const Scene *scene, bool ignore_pinned) { ParamHandle *handle; - handle = construct_param_handle_multi(scene, objects, objects_len, options); + handle = construct_param_handle_multi(scene, objects, objects_len, options, NULL); param_pack(handle, scene->toolsettings->uvcalc_margin, rotate, ignore_pinned); param_flush(handle); param_delete(handle); @@ -1087,7 +1101,7 @@ static int average_islands_scale_exec(bContext *C, wmOperator *UNUSED(op)) return OPERATOR_CANCELLED; } - ParamHandle *handle = construct_param_handle_multi(scene, objects, objects_len, &options); + ParamHandle *handle = construct_param_handle_multi(scene, objects, objects_len, &options, NULL); param_average(handle, false); param_flush(handle); param_delete(handle); @@ -1154,10 +1168,10 @@ void ED_uvedit_live_unwrap_begin(Scene *scene, Object *obedit) }; if (use_subsurf) { - handle = construct_param_handle_subsurfed(scene, obedit, em, &options); + handle = construct_param_handle_subsurfed(scene, obedit, em, &options, NULL); } else { - handle = construct_param_handle(scene, obedit, em->bm, &options); + handle = construct_param_handle(scene, obedit, em->bm, &options, NULL); } param_lscm_begin(handle, PARAM_TRUE, abf); @@ -1182,7 +1196,7 @@ void ED_uvedit_live_unwrap_re_solve(void) { if (g_live_unwrap.handles) { for (int i = 0; i < g_live_unwrap.len; i++) { - param_lscm_solve(g_live_unwrap.handles[i]); + param_lscm_solve(g_live_unwrap.handles[i], NULL, NULL); param_flush(g_live_unwrap.handles[i]); } } @@ -1631,7 +1645,10 @@ static void uv_map_clip_correct(Object *ob, wmOperator *op) * \{ */ /* Assumes UV Map exists, doesn't run update funcs. */ -static void uvedit_unwrap(const Scene *scene, Object *obedit, const UnwrapOptions *options) +static void uvedit_unwrap(const Scene *scene, + Object *obedit, + const UnwrapOptions *options, + UnwrapResultInfo *result_info) { BMEditMesh *em = BKE_editmesh_from_object(obedit); if (!CustomData_has_layer(&em->bm->ldata, CD_MLOOPUV)) { @@ -1643,14 +1660,16 @@ static void uvedit_unwrap(const Scene *scene, Object *obedit, const UnwrapOption ParamHandle *handle; if (use_subsurf) { - handle = construct_param_handle_subsurfed(scene, obedit, em, options); + handle = construct_param_handle_subsurfed(scene, obedit, em, options, result_info); } else { - handle = construct_param_handle(scene, obedit, em->bm, options); + handle = construct_param_handle(scene, obedit, em->bm, options, result_info); } param_lscm_begin(handle, PARAM_FALSE, scene->toolsettings->unwrapper == 0); - param_lscm_solve(handle); + param_lscm_solve(handle, + result_info ? &result_info->count_changed : NULL, + result_info ? &result_info->count_failed : NULL); param_lscm_end(handle); param_average(handle, true); @@ -1663,11 +1682,12 @@ static void uvedit_unwrap(const Scene *scene, Object *obedit, const UnwrapOption static void uvedit_unwrap_multi(const Scene *scene, Object **objects, const int objects_len, - const UnwrapOptions *options) + const UnwrapOptions *options, + UnwrapResultInfo *result_info) { for (uint ob_index = 0; ob_index < objects_len; ob_index++) { Object *obedit = objects[ob_index]; - uvedit_unwrap(scene, obedit, options); + uvedit_unwrap(scene, obedit, options, result_info); DEG_id_tag_update(obedit->data, ID_RECALC_GEOMETRY); WM_main_add_notifier(NC_GEOM | ND_DATA, obedit->data); } @@ -1687,7 +1707,7 @@ void ED_uvedit_live_unwrap(const Scene *scene, Object **objects, int objects_len bool rotate = true; bool ignore_pinned = true; - uvedit_unwrap_multi(scene, objects, objects_len, &options); + uvedit_unwrap_multi(scene, objects, objects_len, &options, NULL); uvedit_pack_islands_multi(scene, objects, objects_len, &options, rotate, ignore_pinned); } } @@ -1816,11 +1836,28 @@ static int unwrap_exec(bContext *C, wmOperator *op) } /* execute unwrap */ - uvedit_unwrap_multi(scene, objects, objects_len, &options); + UnwrapResultInfo result_info = { + .count_changed = 0, + .count_failed = 0, + }; + uvedit_unwrap_multi(scene, objects, objects_len, &options, &result_info); uvedit_pack_islands_multi(scene, objects, objects_len, &options, rotate, ignore_pinned); MEM_freeN(objects); + if (result_info.count_failed == 0 && result_info.count_changed == 0) { + BKE_report(op->reports, + RPT_WARNING, + "Unwrap could not solve any island(s), edge seams may need to be added"); + } + else if (result_info.count_failed) { + BKE_reportf(op->reports, + RPT_WARNING, + "Unwrap failed to solve %d of %d island(s), edge seams may need to be added", + result_info.count_failed, + result_info.count_changed + result_info.count_failed); + } + return OPERATOR_FINISHED; } diff --git a/source/blender/functions/FN_cpp_type.hh b/source/blender/functions/FN_cpp_type.hh index 665296f30e1..54ea0103fe5 100644 --- a/source/blender/functions/FN_cpp_type.hh +++ b/source/blender/functions/FN_cpp_type.hh @@ -661,7 +661,7 @@ class CPPType : NonCopyable, NonMovable { uint64_t hash() const { - return DefaultHash<const CPPType *>{}(this); + return get_default_hash(this); } template<typename T> bool is() const @@ -674,6 +674,6 @@ class CPPType : NonCopyable, NonMovable { /* Utility for allocating an uninitialized buffer for a single value of the given #CPPType. */ #define BUFFER_FOR_CPP_TYPE_VALUE(type, variable_name) \ - blender::DynamicStackBuffer<64, 64> stack_buffer_for_##variable_name(type.size(), \ - type.alignment()); \ + blender::DynamicStackBuffer<64, 64> stack_buffer_for_##variable_name((type).size(), \ + (type).alignment()); \ void *variable_name = stack_buffer_for_##variable_name.buffer(); diff --git a/source/blender/functions/FN_cpp_type_make.hh b/source/blender/functions/FN_cpp_type_make.hh index 342161d01b6..cd14fe8c078 100644 --- a/source/blender/functions/FN_cpp_type_make.hh +++ b/source/blender/functions/FN_cpp_type_make.hh @@ -220,7 +220,7 @@ template<typename T> bool is_equal_cb(const void *a, const void *b) template<typename T> uint64_t hash_cb(const void *value) { const T &value_ = *static_cast<const T *>(value); - return DefaultHash<T>{}(value_); + return get_default_hash(value_); } } // namespace blender::fn::cpp_type_util diff --git a/source/blender/functions/FN_multi_function.hh b/source/blender/functions/FN_multi_function.hh index 2ce65426245..f6c4addfb52 100644 --- a/source/blender/functions/FN_multi_function.hh +++ b/source/blender/functions/FN_multi_function.hh @@ -64,7 +64,7 @@ class MultiFunction { virtual uint64_t hash() const { - return DefaultHash<const MultiFunction *>{}(this); + return get_default_hash(this); } virtual bool equals(const MultiFunction &UNUSED(other)) const diff --git a/source/blender/functions/FN_multi_function_builder.hh b/source/blender/functions/FN_multi_function_builder.hh index 95a9f52e29e..691abeb18c0 100644 --- a/source/blender/functions/FN_multi_function_builder.hh +++ b/source/blender/functions/FN_multi_function_builder.hh @@ -384,7 +384,7 @@ template<typename T> class CustomMF_Constant : public MultiFunction { uint64_t hash() const override { - return DefaultHash<T>{}(value_); + return get_default_hash(value_); } bool equals(const MultiFunction &other) const override diff --git a/source/blender/functions/FN_multi_function_data_type.hh b/source/blender/functions/FN_multi_function_data_type.hh index 713f73c2b5a..c3372151a1b 100644 --- a/source/blender/functions/FN_multi_function_data_type.hh +++ b/source/blender/functions/FN_multi_function_data_type.hh @@ -110,7 +110,7 @@ class MFDataType { uint64_t hash() const { - return DefaultHash<CPPType>{}(*type_) + static_cast<uint64_t>(category_); + return get_default_hash_2(*type_, category_); } }; diff --git a/source/blender/gpencil_modifiers/CMakeLists.txt b/source/blender/gpencil_modifiers/CMakeLists.txt index e3bb0d773a2..9690f47c862 100644 --- a/source/blender/gpencil_modifiers/CMakeLists.txt +++ b/source/blender/gpencil_modifiers/CMakeLists.txt @@ -53,8 +53,8 @@ set(SRC intern/MOD_gpencilbuild.c intern/MOD_gpencilcolor.c intern/MOD_gpencilhook.c - intern/MOD_gpencillineart.c intern/MOD_gpencillattice.c + intern/MOD_gpencillineart.c intern/MOD_gpencilmirror.c intern/MOD_gpencilmultiply.c intern/MOD_gpencilnoise.c @@ -68,18 +68,19 @@ set(SRC intern/MOD_gpenciltime.c intern/MOD_gpenciltint.c + MOD_gpencil_lineart.h MOD_gpencil_modifiertypes.h intern/MOD_gpencil_ui_common.h intern/MOD_gpencil_util.h # Lineart code - intern/lineart/lineart_ops.c - intern/lineart/lineart_cpu.c intern/lineart/lineart_chain.c + intern/lineart/lineart_cpu.c + intern/lineart/lineart_ops.c intern/lineart/lineart_util.c - intern/lineart/lineart_intern.h intern/lineart/MOD_lineart.h + intern/lineart/lineart_intern.h ) diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencillattice.c b/source/blender/gpencil_modifiers/intern/MOD_gpencillattice.c index 4efc1d9eaae..2934b89c747 100644 --- a/source/blender/gpencil_modifiers/intern/MOD_gpencillattice.c +++ b/source/blender/gpencil_modifiers/intern/MOD_gpencillattice.c @@ -136,36 +136,39 @@ static void bakeModifier(Main *UNUSED(bmain), bGPdata *gpd = ob->data; int oldframe = (int)DEG_get_ctime(depsgraph); - if (mmd->object == NULL) { + if ((mmd->object == NULL) || (mmd->object->type != OB_LATTICE)) { return; } LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) { LISTBASE_FOREACH (bGPDframe *, gpf, &gpl->frames) { - /* apply lattice effects on this frame - * NOTE: this assumes that we don't want lattice animation on non-keyframed frames + /* Apply lattice effects on this frame + * NOTE: this assumes that we don't want lattice animation on non-keyframed frames. */ CFRA = gpf->framenum; BKE_scene_graph_update_for_newframe(depsgraph); - /* recalculate lattice data */ - BKE_gpencil_lattice_init(ob); + /* Recalculate lattice data. */ + if (mmd->cache_data) { + BKE_lattice_deform_data_destroy(mmd->cache_data); + } + mmd->cache_data = BKE_lattice_deform_data_create(mmd->object, ob); - /* compute lattice effects on this frame */ + /* Compute lattice effects on this frame. */ LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) { deformStroke(md, depsgraph, ob, gpl, gpf, gps); } } } - /* free lingering data */ + /* Free lingering data. */ ldata = (struct LatticeDeformData *)mmd->cache_data; if (ldata) { BKE_lattice_deform_data_destroy(ldata); mmd->cache_data = NULL; } - /* return frame state and DB to original state */ + /* Return frame state and DB to original state. */ CFRA = oldframe; BKE_scene_graph_update_for_newframe(depsgraph); } diff --git a/source/blender/gpencil_modifiers/intern/lineart/lineart_cpu.c b/source/blender/gpencil_modifiers/intern/lineart/lineart_cpu.c index 7fb3981d9dc..2389e0c403c 100644 --- a/source/blender/gpencil_modifiers/intern/lineart/lineart_cpu.c +++ b/source/blender/gpencil_modifiers/intern/lineart/lineart_cpu.c @@ -3858,7 +3858,7 @@ static void lineart_gpencil_generate(LineartRenderBuffer *rb, BKE_gpencil_stroke_add_points(gps, stroke_data, count, mat); BKE_gpencil_dvert_ensure(gps); - gps->mat_nr = material_nr; + gps->mat_nr = max_ii(material_nr, 0); MEM_freeN(stroke_data); diff --git a/source/blender/imbuf/intern/anim_movie.c b/source/blender/imbuf/intern/anim_movie.c index d36c7bbe486..dc39af803e0 100644 --- a/source/blender/imbuf/intern/anim_movie.c +++ b/source/blender/imbuf/intern/anim_movie.c @@ -574,8 +574,19 @@ static int startffmpeg(struct anim *anim) pCodecCtx->workaround_bugs = 1; - pCodecCtx->thread_count = BLI_system_thread_count(); - pCodecCtx->thread_type = FF_THREAD_SLICE; + if (pCodec->capabilities & AV_CODEC_CAP_AUTO_THREADS) { + pCodecCtx->thread_count = 0; + } + else { + pCodecCtx->thread_count = BLI_system_thread_count(); + } + + if (pCodec->capabilities & AV_CODEC_CAP_FRAME_THREADS) { + pCodecCtx->thread_type = FF_THREAD_FRAME; + } + else if (pCodec->capabilities & AV_CODEC_CAP_SLICE_THREADS) { + pCodecCtx->thread_type = FF_THREAD_SLICE; + } if (avcodec_open2(pCodecCtx, pCodec, NULL) < 0) { avformat_close_input(&pFormatCtx); @@ -969,44 +980,6 @@ static int ffmpeg_decode_video_frame(struct anim *anim) return (rval >= 0); } -static void ffmpeg_decode_video_frame_scan(struct anim *anim, int64_t pts_to_search) -{ - /* there seem to exist *very* silly GOP lengths out in the wild... */ - int count = 1000; - - av_log(anim->pFormatCtx, - AV_LOG_DEBUG, - "SCAN start: considering pts=%" PRId64 " in search of %" PRId64 "\n", - (int64_t)anim->next_pts, - (int64_t)pts_to_search); - - while (count > 0 && anim->next_pts < pts_to_search) { - av_log(anim->pFormatCtx, - AV_LOG_DEBUG, - " WHILE: pts=%" PRId64 " in search of %" PRId64 "\n", - (int64_t)anim->next_pts, - (int64_t)pts_to_search); - if (!ffmpeg_decode_video_frame(anim)) { - break; - } - count--; - } - if (count == 0) { - av_log(anim->pFormatCtx, - AV_LOG_ERROR, - "SCAN failed: completely lost in stream, " - "bailing out at PTS=%" PRId64 ", searching for PTS=%" PRId64 "\n", - (int64_t)anim->next_pts, - (int64_t)pts_to_search); - } - if (anim->next_pts == pts_to_search) { - av_log(anim->pFormatCtx, AV_LOG_DEBUG, "SCAN HAPPY: we found our PTS!\n"); - } - else { - av_log(anim->pFormatCtx, AV_LOG_ERROR, "SCAN UNHAPPY: PTS not matched!\n"); - } -} - static int match_format(const char *name, AVFormatContext *pFormatCtx) { const char *p; @@ -1049,37 +1022,18 @@ static int ffmpeg_seek_by_byte(AVFormatContext *pFormatCtx) return false; } -static ImBuf *ffmpeg_fetchibuf(struct anim *anim, int position, IMB_Timecode_Type tc) +static int64_t ffmpeg_get_pts_to_search(struct anim *anim, + struct anim_index *tc_index, + int position) { - int64_t pts_to_search = 0; - double frame_rate; - double pts_time_base; - int64_t st_time; - struct anim_index *tc_index = 0; - AVStream *v_st; - int new_frame_index = 0; /* To quiet gcc barking... */ - int old_frame_index = 0; /* To quiet gcc barking... */ - - if (anim == NULL) { - return 0; - } - - av_log(anim->pFormatCtx, AV_LOG_DEBUG, "FETCH: pos=%d\n", position); - - if (tc != IMB_TC_NONE) { - tc_index = IMB_anim_open_index(anim, tc); - } - - v_st = anim->pFormatCtx->streams[anim->videoStream]; - - frame_rate = av_q2d(av_guess_frame_rate(anim->pFormatCtx, v_st, NULL)); - - st_time = anim->pFormatCtx->start_time; - pts_time_base = av_q2d(v_st->time_base); + int64_t pts_to_search; + int64_t st_time = anim->pFormatCtx->start_time; + AVStream *v_st = anim->pFormatCtx->streams[anim->videoStream]; + double frame_rate = av_q2d(av_guess_frame_rate(anim->pFormatCtx, v_st, NULL)); + double pts_time_base = av_q2d(v_st->time_base); if (tc_index) { - new_frame_index = IMB_indexer_get_frame_index(tc_index, position); - old_frame_index = IMB_indexer_get_frame_index(tc_index, anim->curposition); + int new_frame_index = IMB_indexer_get_frame_index(tc_index, position); pts_to_search = IMB_indexer_get_pts(tc_index, new_frame_index); } else { @@ -1089,117 +1043,259 @@ static ImBuf *ffmpeg_fetchibuf(struct anim *anim, int position, IMB_Timecode_Typ pts_to_search += st_time / pts_time_base / AV_TIME_BASE; } } + return pts_to_search; +} - av_log(anim->pFormatCtx, - AV_LOG_DEBUG, - "FETCH: looking for PTS=%" PRId64 " (pts_timebase=%g, frame_rate=%g, st_time=%" PRId64 - ")\n", - (int64_t)pts_to_search, - pts_time_base, - frame_rate, - st_time); +static bool ffmpeg_pts_matches_last_frame(struct anim *anim, int64_t pts_to_search) +{ + return anim->last_frame && anim->last_pts <= pts_to_search && anim->next_pts > pts_to_search; +} - if (anim->last_frame && anim->last_pts <= pts_to_search && anim->next_pts > pts_to_search) { - av_log(anim->pFormatCtx, - AV_LOG_DEBUG, - "FETCH: frame repeat: last: %" PRId64 " next: %" PRId64 "\n", - (int64_t)anim->last_pts, - (int64_t)anim->next_pts); - IMB_refImBuf(anim->last_frame); - anim->curposition = position; - return anim->last_frame; - } +/* Requested video frame is expected to be found within different GOP as last decoded frame. + * Seeking to new position and scanning is fastest way to get requested frame. + * Check whether ffmpeg_can_scan() and ffmpeg_pts_matches_last_frame() is false before using this + * function. */ +static bool ffmpeg_can_seek(struct anim *anim, int position) +{ + return position != anim->curposition + 1; +} +/* Requested video frame is expected to be found within same GOP as last decoded frame. + * Decoding frames in sequence until frame matches requested one is fastest way to get it. */ +static bool ffmpeg_can_scan(struct anim *anim, int position, struct anim_index *tc_index) +{ if (position > anim->curposition + 1 && anim->preseek && !tc_index && position - (anim->curposition + 1) < anim->preseek) { - av_log(anim->pFormatCtx, AV_LOG_DEBUG, "FETCH: within preseek interval (no index)\n"); + return true; + } - ffmpeg_decode_video_frame_scan(anim, pts_to_search); + if (tc_index == NULL) { + return false; } - else if (tc_index && IMB_indexer_can_scan(tc_index, old_frame_index, new_frame_index)) { + + int new_frame_index = IMB_indexer_get_frame_index(tc_index, position); + int old_frame_index = IMB_indexer_get_frame_index(tc_index, anim->curposition); + return IMB_indexer_can_scan(tc_index, old_frame_index, new_frame_index); +} + +static bool ffmpeg_is_first_frame_decode(struct anim *anim, int position) +{ + return position == 0 && anim->curposition == -1; +} + +/* Decode frames one by one until its PTS matches pts_to_search. */ +static void ffmpeg_decode_video_frame_scan(struct anim *anim, int64_t pts_to_search) +{ + av_log(anim->pFormatCtx, AV_LOG_DEBUG, "FETCH: within preseek interval\n"); + + /* there seem to exist *very* silly GOP lengths out in the wild... */ + int count = 1000; + + av_log(anim->pFormatCtx, + AV_LOG_DEBUG, + "SCAN start: considering pts=%" PRId64 " in search of %" PRId64 "\n", + (int64_t)anim->next_pts, + (int64_t)pts_to_search); + + while (count > 0 && anim->next_pts < pts_to_search) { av_log(anim->pFormatCtx, AV_LOG_DEBUG, - "FETCH: within preseek interval " - "(index tells us)\n"); + " WHILE: pts=%" PRId64 " in search of %" PRId64 "\n", + (int64_t)anim->next_pts, + (int64_t)pts_to_search); + if (!ffmpeg_decode_video_frame(anim)) { + break; + } + count--; + } + if (count == 0) { + av_log(anim->pFormatCtx, + AV_LOG_ERROR, + "SCAN failed: completely lost in stream, " + "bailing out at PTS=%" PRId64 ", searching for PTS=%" PRId64 "\n", + (int64_t)anim->next_pts, + (int64_t)pts_to_search); + } + if (anim->next_pts == pts_to_search) { + av_log(anim->pFormatCtx, AV_LOG_DEBUG, "SCAN HAPPY: we found our PTS!\n"); + } + else { + av_log(anim->pFormatCtx, AV_LOG_ERROR, "SCAN UNHAPPY: PTS not matched!\n"); + } +} - ffmpeg_decode_video_frame_scan(anim, pts_to_search); +/* Wrapper over av_seek_frame(), for formats that doesn't have it's own read_seek() or read_seek2() + * functions defined. When seeking in these formats, rule to seek to last necessary I-frame is not + * honored. It is not even guaranteed that I-frame, that must be decoded will be read. See + * https://trac.ffmpeg.org/ticket/1607 and https://developer.blender.org/T86944. */ +static int ffmpeg_generic_seek_workaround(struct anim *anim, int64_t requested_pos) +{ + AVStream *v_st = anim->pFormatCtx->streams[anim->videoStream]; + double frame_rate = av_q2d(av_guess_frame_rate(anim->pFormatCtx, v_st, NULL)); + int64_t current_pos = requested_pos; + + /* This time offset maximum limit is arbitrary. If some files fails to decode it may be + * increased. Seek performance will be negatively affected. Small initial offset is necessary + * because encoder can re-arrange frames as it needs but within it's delay, which is usually + * small. */ + for (int offset = 5; offset < 25; offset++) { + current_pos = requested_pos - ((int64_t)(offset)*AV_TIME_BASE / frame_rate); + + /* Seek to timestamp. */ + if (av_seek_frame(anim->pFormatCtx, -1, current_pos, AVSEEK_FLAG_BACKWARD) < 0) { + break; + } + + /* Read first video stream packet. */ + AVPacket read_packet = {0}; + while (av_read_frame(anim->pFormatCtx, &read_packet) >= 0) { + if (anim->next_packet.stream_index == anim->videoStream) { + break; + } + } + + /* If this packet contains I-frame, exit loop. This should be the frame that we need. */ + if (read_packet.flags & AV_PKT_FLAG_KEY) { + break; + } } - else if (position != anim->curposition + 1) { - int64_t pos; - int ret; - if (tc_index) { - uint64_t dts; + /* Re-seek to timestamp that gave I-frame, so it can be read by decode function. */ + return av_seek_frame(anim->pFormatCtx, -1, current_pos, AVSEEK_FLAG_BACKWARD); +} - pos = IMB_indexer_get_seek_pos(tc_index, new_frame_index); - dts = IMB_indexer_get_seek_pos_dts(tc_index, new_frame_index); +/* Seek to last necessary I-frame and scan-decode until requested frame is found. */ +static void ffmpeg_seek_and_decode(struct anim *anim, int position, struct anim_index *tc_index) +{ + AVStream *v_st = anim->pFormatCtx->streams[anim->videoStream]; + double frame_rate = av_q2d(av_guess_frame_rate(anim->pFormatCtx, v_st, NULL)); + int64_t st_time = anim->pFormatCtx->start_time; - av_log(anim->pFormatCtx, AV_LOG_DEBUG, "TC INDEX seek pos = %" PRId64 "\n", pos); - av_log(anim->pFormatCtx, AV_LOG_DEBUG, "TC INDEX seek dts = %" PRIu64 "\n", dts); + int64_t pts_to_search = ffmpeg_get_pts_to_search(anim, tc_index, position); - if (ffmpeg_seek_by_byte(anim->pFormatCtx)) { - av_log(anim->pFormatCtx, AV_LOG_DEBUG, "... using BYTE pos\n"); + int64_t pos; + int ret; - ret = av_seek_frame(anim->pFormatCtx, -1, pos, AVSEEK_FLAG_BYTE); - av_update_cur_dts(anim->pFormatCtx, v_st, dts); - } - else { - av_log(anim->pFormatCtx, AV_LOG_DEBUG, "... using DTS pos\n"); - ret = av_seek_frame(anim->pFormatCtx, anim->videoStream, dts, AVSEEK_FLAG_BACKWARD); - } + if (tc_index) { + int new_frame_index = IMB_indexer_get_frame_index(tc_index, position); + uint64_t dts; + + pos = IMB_indexer_get_seek_pos(tc_index, new_frame_index); + dts = IMB_indexer_get_seek_pos_dts(tc_index, new_frame_index); + + av_log(anim->pFormatCtx, AV_LOG_DEBUG, "TC INDEX seek pos = %" PRId64 "\n", pos); + av_log(anim->pFormatCtx, AV_LOG_DEBUG, "TC INDEX seek dts = %" PRIu64 "\n", dts); + + if (ffmpeg_seek_by_byte(anim->pFormatCtx)) { + av_log(anim->pFormatCtx, AV_LOG_DEBUG, "... using BYTE pos\n"); + + ret = av_seek_frame(anim->pFormatCtx, -1, pos, AVSEEK_FLAG_BYTE); + av_update_cur_dts(anim->pFormatCtx, v_st, dts); } else { - pos = (int64_t)position * AV_TIME_BASE / frame_rate; + av_log(anim->pFormatCtx, AV_LOG_DEBUG, "... using DTS pos\n"); + ret = av_seek_frame(anim->pFormatCtx, anim->videoStream, dts, AVSEEK_FLAG_BACKWARD); + } + } + else { + pos = (int64_t)(position)*AV_TIME_BASE / frame_rate; - av_log(anim->pFormatCtx, - AV_LOG_DEBUG, - "NO INDEX seek pos = %" PRId64 ", st_time = %" PRId64 "\n", - pos, - (st_time != AV_NOPTS_VALUE) ? st_time : 0); + av_log(anim->pFormatCtx, + AV_LOG_DEBUG, + "NO INDEX seek pos = %" PRId64 ", st_time = %" PRId64 "\n", + pos, + (st_time != AV_NOPTS_VALUE) ? st_time : 0); - if (pos < 0) { - pos = 0; - } + if (pos < 0) { + pos = 0; + } - if (st_time != AV_NOPTS_VALUE) { - pos += st_time; - } + if (st_time != AV_NOPTS_VALUE) { + pos += st_time; + } + + av_log(anim->pFormatCtx, AV_LOG_DEBUG, "NO INDEX final seek pos = %" PRId64 "\n", pos); - av_log(anim->pFormatCtx, AV_LOG_DEBUG, "NO INDEX final seek pos = %" PRId64 "\n", pos); + AVFormatContext *format_ctx = anim->pFormatCtx; + /* Condition based on av_seek_frame() code. */ + if (format_ctx->iformat->read_seek2 && !format_ctx->iformat->read_seek) { ret = av_seek_frame(anim->pFormatCtx, -1, pos, AVSEEK_FLAG_BACKWARD); } - - if (ret < 0) { - av_log(anim->pFormatCtx, - AV_LOG_ERROR, - "FETCH: " - "error while seeking to DTS = %" PRId64 " (frameno = %d, PTS = %" PRId64 - "): errcode = %d\n", - pos, - position, - (int64_t)pts_to_search, - ret); + else { + ret = ffmpeg_generic_seek_workaround(anim, pos); } + } - avcodec_flush_buffers(anim->pCodecCtx); + if (ret < 0) { + av_log(anim->pFormatCtx, + AV_LOG_ERROR, + "FETCH: " + "error while seeking to DTS = %" PRId64 " (frameno = %d, PTS = %" PRId64 + "): errcode = %d\n", + pos, + position, + (int64_t)pts_to_search, + ret); + } + avcodec_flush_buffers(anim->pCodecCtx); - anim->next_pts = -1; + anim->next_pts = -1; - if (anim->next_packet.stream_index == anim->videoStream) { - av_free_packet(&anim->next_packet); - anim->next_packet.stream_index = -1; - } + if (anim->next_packet.stream_index == anim->videoStream) { + av_free_packet(&anim->next_packet); + anim->next_packet.stream_index = -1; + } - /* memset(anim->pFrame, ...) ?? */ + /* memset(anim->pFrame, ...) ?? */ + if (ret < 0) { + /* Seek failed. */ + return; + } - if (ret >= 0) { - ffmpeg_decode_video_frame_scan(anim, pts_to_search); - } + ffmpeg_decode_video_frame_scan(anim, pts_to_search); +} + +static ImBuf *ffmpeg_fetchibuf(struct anim *anim, int position, IMB_Timecode_Type tc) +{ + if (anim == NULL) { + return NULL; + } + + av_log(anim->pFormatCtx, AV_LOG_DEBUG, "FETCH: pos=%d\n", position); + + struct anim_index *tc_index = IMB_anim_open_index(anim, tc); + int64_t pts_to_search = ffmpeg_get_pts_to_search(anim, tc_index, position); + AVStream *v_st = anim->pFormatCtx->streams[anim->videoStream]; + double frame_rate = av_q2d(av_guess_frame_rate(anim->pFormatCtx, v_st, NULL)); + double pts_time_base = av_q2d(v_st->time_base); + int64_t st_time = anim->pFormatCtx->start_time; + + av_log(anim->pFormatCtx, + AV_LOG_DEBUG, + "FETCH: looking for PTS=%" PRId64 " (pts_timebase=%g, frame_rate=%g, st_time=%" PRId64 + ")\n", + (int64_t)pts_to_search, + pts_time_base, + frame_rate, + st_time); + + if (ffmpeg_pts_matches_last_frame(anim, pts_to_search)) { + av_log(anim->pFormatCtx, + AV_LOG_DEBUG, + "FETCH: frame repeat: last: %" PRId64 " next: %" PRId64 "\n", + (int64_t)anim->last_pts, + (int64_t)anim->next_pts); + IMB_refImBuf(anim->last_frame); + anim->curposition = position; + return anim->last_frame; + } + + if (ffmpeg_can_scan(anim, position, tc_index) || ffmpeg_is_first_frame_decode(anim, position)) { + ffmpeg_decode_video_frame_scan(anim, pts_to_search); } - else if (position == 0 && anim->curposition == -1) { - /* first frame without seeking special case... */ - ffmpeg_decode_video_frame(anim); + else if (ffmpeg_can_seek(anim, position)) { + ffmpeg_seek_and_decode(anim, position, tc_index); } else { av_log(anim->pFormatCtx, AV_LOG_DEBUG, "FETCH: no seek necessary, just continue...\n"); diff --git a/source/blender/imbuf/intern/cineon/cineon_dpx.c b/source/blender/imbuf/intern/cineon/cineon_dpx.c index de54e6dab9d..91d7b9a8b9e 100644 --- a/source/blender/imbuf/intern/cineon/cineon_dpx.c +++ b/source/blender/imbuf/intern/cineon/cineon_dpx.c @@ -198,10 +198,10 @@ ImBuf *imb_load_cineon(const unsigned char *mem, int flags, char colorspace[IM_MAX_SPACE]) { - if (imb_is_a_cineon(mem, size)) { - return imb_load_dpx_cineon(mem, size, 1, flags, colorspace); + if (!imb_is_a_cineon(mem, size)) { + return NULL; } - return NULL; + return imb_load_dpx_cineon(mem, size, 1, flags, colorspace); } bool imb_save_dpx(struct ImBuf *buf, const char *filepath, int flags) @@ -219,8 +219,8 @@ ImBuf *imb_load_dpx(const unsigned char *mem, int flags, char colorspace[IM_MAX_SPACE]) { - if (imb_is_a_dpx(mem, size)) { - return imb_load_dpx_cineon(mem, size, 0, flags, colorspace); + if (!imb_is_a_dpx(mem, size)) { + return NULL; } - return NULL; + return imb_load_dpx_cineon(mem, size, 0, flags, colorspace); } diff --git a/source/blender/imbuf/intern/indexer.c b/source/blender/imbuf/intern/indexer.c index d331cfd533a..6496f2d05a4 100644 --- a/source/blender/imbuf/intern/indexer.c +++ b/source/blender/imbuf/intern/indexer.c @@ -541,8 +541,20 @@ static struct proxy_output_ctx *alloc_proxy_output_ffmpeg( av_dict_set_int(&codec_opts, "crf", crf, 0); /* Prefer smaller file-size. */ av_dict_set(&codec_opts, "preset", "slow", 0); - /* Thread count. */ - av_dict_set_int(&codec_opts, "threads", BLI_system_thread_count(), 0); + + if (rv->codec->capabilities & AV_CODEC_CAP_AUTO_THREADS) { + rv->c->thread_count = 0; + } + else { + rv->c->thread_count = BLI_system_thread_count(); + } + + if (rv->codec->capabilities & AV_CODEC_CAP_FRAME_THREADS) { + rv->c->thread_type = FF_THREAD_FRAME; + } + else if (rv->codec->capabilities & AV_CODEC_CAP_SLICE_THREADS) { + rv->c->thread_type = FF_THREAD_SLICE; + } if (rv->of->flags & AVFMT_GLOBALHEADER) { rv->c->flags |= CODEC_FLAG_GLOBAL_HEADER; @@ -794,11 +806,21 @@ static IndexBuildContext *index_ffmpeg_create_context(struct anim *anim, context->iCodecCtx->workaround_bugs = 1; - AVDictionary *codec_opts = NULL; - /* Thread count. */ - av_dict_set_int(&codec_opts, "threads", BLI_system_thread_count(), 0); + if (context->iCodec->capabilities & AV_CODEC_CAP_AUTO_THREADS) { + context->iCodecCtx->thread_count = 0; + } + else { + context->iCodecCtx->thread_count = BLI_system_thread_count(); + } + + if (context->iCodec->capabilities & AV_CODEC_CAP_FRAME_THREADS) { + context->iCodecCtx->thread_type = FF_THREAD_FRAME; + } + else if (context->iCodec->capabilities & AV_CODEC_CAP_SLICE_THREADS) { + context->iCodecCtx->thread_type = FF_THREAD_SLICE; + } - if (avcodec_open2(context->iCodecCtx, context->iCodec, &codec_opts) < 0) { + if (avcodec_open2(context->iCodecCtx, context->iCodec, NULL) < 0) { avformat_close_input(&context->iFormatCtx); MEM_freeN(context); return NULL; diff --git a/source/blender/imbuf/intern/iris.c b/source/blender/imbuf/intern/iris.c index 112b95bf1a1..547af472d73 100644 --- a/source/blender/imbuf/intern/iris.c +++ b/source/blender/imbuf/intern/iris.c @@ -270,11 +270,13 @@ struct ImBuf *imb_loadiris(const uchar *mem, size_t size, int flags, char colors ImBuf *ibuf = NULL; uchar dirty_flag = 0; - if (size < HEADER_SIZE) { + if (!imb_is_a_iris(mem, size)) { return NULL; } - if (!imb_is_a_iris(mem, size)) { + /* Could pe part of the magic check above, + * by convention this check only requests the size needed to read it's magic though. */ + if (size < HEADER_SIZE) { return NULL; } diff --git a/source/blender/imbuf/intern/metadata.c b/source/blender/imbuf/intern/metadata.c index d8abd3411cb..c59997b34f5 100644 --- a/source/blender/imbuf/intern/metadata.c +++ b/source/blender/imbuf/intern/metadata.c @@ -38,8 +38,6 @@ #include "IMB_metadata.h" -#define METADATA_MAX_VALUE_LENGTH 1024 - void IMB_metadata_ensure(struct IDProperty **metadata) { if (*metadata != NULL) { @@ -99,11 +97,11 @@ void IMB_metadata_set_field(struct IDProperty *metadata, const char *key, const } if (prop == NULL) { - prop = IDP_NewString(value, key, METADATA_MAX_VALUE_LENGTH); + prop = IDP_NewString(value, key, 0); IDP_AddToGroup(metadata, prop); } - IDP_AssignString(prop, value, METADATA_MAX_VALUE_LENGTH); + IDP_AssignString(prop, value, 0); } void IMB_metadata_foreach(struct ImBuf *ibuf, IMBMetadataForeachCb callback, void *userdata) diff --git a/source/blender/imbuf/intern/radiance_hdr.c b/source/blender/imbuf/intern/radiance_hdr.c index 285b18595f7..94b2a62aa26 100644 --- a/source/blender/imbuf/intern/radiance_hdr.c +++ b/source/blender/imbuf/intern/radiance_hdr.c @@ -229,87 +229,89 @@ struct ImBuf *imb_loadhdr(const unsigned char *mem, const unsigned char *ptr, *mem_eof = mem + size; char oriY[80], oriX[80]; - if (imb_is_a_hdr(mem, size)) { - colorspace_set_default_role(colorspace, IM_MAX_SPACE, COLOR_ROLE_DEFAULT_FLOAT); - - /* find empty line, next line is resolution info */ - size_t x; - for (x = 1; x < size; x++) { - if ((mem[x - 1] == '\n') && (mem[x] == '\n')) { - found = 1; - break; - } + if (!imb_is_a_hdr(mem, size)) { + return NULL; + } + + colorspace_set_default_role(colorspace, IM_MAX_SPACE, COLOR_ROLE_DEFAULT_FLOAT); + + /* find empty line, next line is resolution info */ + size_t x; + for (x = 1; x < size; x++) { + if ((mem[x - 1] == '\n') && (mem[x] == '\n')) { + found = 1; + break; } - if (found && (x < (size + 2))) { - if (sscanf((char *)&mem[x + 1], - "%79s %d %79s %d", - (char *)&oriY, - &height, - (char *)&oriX, - &width) != 4) { - return NULL; - } + } - /* find end of this line, data right behind it */ - ptr = (unsigned char *)strchr((char *)&mem[x + 1], '\n'); - ptr++; + if ((found && (x < (size + 2))) == 0) { + /* Data not found! */ + return NULL; + } - if (flags & IB_test) { - ibuf = IMB_allocImBuf(width, height, 32, 0); - } - else { - ibuf = IMB_allocImBuf(width, height, 32, (flags & IB_rect) | IB_rectfloat); - } + if (sscanf((const char *)&mem[x + 1], + "%79s %d %79s %d", + (char *)&oriY, + &height, + (char *)&oriX, + &width) != 4) { + return NULL; + } - if (UNLIKELY(ibuf == NULL)) { - return NULL; - } - ibuf->ftype = IMB_FTYPE_RADHDR; + /* find end of this line, data right behind it */ + ptr = (const unsigned char *)strchr((const char *)&mem[x + 1], '\n'); + ptr++; - if (flags & IB_alphamode_detect) { - ibuf->flags |= IB_alphamode_premul; - } + if (flags & IB_test) { + ibuf = IMB_allocImBuf(width, height, 32, 0); + } + else { + ibuf = IMB_allocImBuf(width, height, 32, (flags & IB_rect) | IB_rectfloat); + } - if (flags & IB_test) { - return ibuf; - } + if (UNLIKELY(ibuf == NULL)) { + return NULL; + } - /* read in and decode the actual data */ - sline = (RGBE *)MEM_mallocN(sizeof(*sline) * width, __func__); - rect_float = ibuf->rect_float; + ibuf->ftype = IMB_FTYPE_RADHDR; - for (size_t y = 0; y < height; y++) { - ptr = freadcolrs(sline, ptr, width, mem_eof); - if (ptr == NULL) { - printf( - "WARNING! HDR decode error, image may be just truncated, or completely wrong...\n"); - break; - } - for (x = 0; x < width; x++) { - /* convert to ldr */ - RGBE2FLOAT(sline[x], fcol); - *rect_float++ = fcol[RED]; - *rect_float++ = fcol[GRN]; - *rect_float++ = fcol[BLU]; - *rect_float++ = 1.0f; - } - } - MEM_freeN(sline); - if (oriY[0] == '-') { - IMB_flipy(ibuf); - } + if (flags & IB_alphamode_detect) { + ibuf->flags |= IB_alphamode_premul; + } - if (flags & IB_rect) { - IMB_rect_from_float(ibuf); - } + if (flags & IB_test) { + return ibuf; + } - return ibuf; + /* read in and decode the actual data */ + sline = (RGBE *)MEM_mallocN(sizeof(*sline) * width, __func__); + rect_float = ibuf->rect_float; + + for (size_t y = 0; y < height; y++) { + ptr = freadcolrs(sline, ptr, width, mem_eof); + if (ptr == NULL) { + printf("WARNING! HDR decode error, image may be just truncated, or completely wrong...\n"); + break; } - // else printf("Data not found!\n"); + for (x = 0; x < width; x++) { + /* convert to ldr */ + RGBE2FLOAT(sline[x], fcol); + *rect_float++ = fcol[RED]; + *rect_float++ = fcol[GRN]; + *rect_float++ = fcol[BLU]; + *rect_float++ = 1.0f; + } + } + MEM_freeN(sline); + if (oriY[0] == '-') { + IMB_flipy(ibuf); + } + + if (flags & IB_rect) { + IMB_rect_from_float(ibuf); } - // else printf("Not a valid radiance HDR file!\n"); - return NULL; + return ibuf; } /* ImBuf write */ diff --git a/source/blender/imbuf/intern/tiff.c b/source/blender/imbuf/intern/tiff.c index 2fb14e40d9d..001cd4e1575 100644 --- a/source/blender/imbuf/intern/tiff.c +++ b/source/blender/imbuf/intern/tiff.c @@ -576,11 +576,7 @@ ImBuf *imb_loadtiff(const unsigned char *mem, int ib_depth; int found; - /* check whether or not we have a TIFF file */ - if (size < IMB_TIFF_NCB) { - fprintf(stderr, "imb_loadtiff: size < IMB_TIFF_NCB\n"); - return NULL; - } + /* Check whether or not we have a TIFF file. */ if (imb_is_a_tiff(mem, size) == 0) { return NULL; } diff --git a/source/blender/io/CMakeLists.txt b/source/blender/io/CMakeLists.txt index 360cacc4360..f11ad7627b9 100644 --- a/source/blender/io/CMakeLists.txt +++ b/source/blender/io/CMakeLists.txt @@ -35,3 +35,5 @@ endif() if(WITH_USD) add_subdirectory(usd) endif() + +add_subdirectory(gpencil) diff --git a/source/blender/io/gpencil/CMakeLists.txt b/source/blender/io/gpencil/CMakeLists.txt new file mode 100644 index 00000000000..be46f876129 --- /dev/null +++ b/source/blender/io/gpencil/CMakeLists.txt @@ -0,0 +1,98 @@ +# ***** 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) 2006, Blender Foundation +# All rights reserved. +# ***** END GPL LICENSE BLOCK ***** + +set(INC + . + ../common + ../../blenkernel + ../../blenlib + ../../blenloader + ../../bmesh + ../../depsgraph + ../../editors/include + ../../makesdna + ../../makesrna + ../../windowmanager + ../../../../intern/clog + ../../../../intern/guardedalloc + ../../../../intern/utfconv +) + +set(INC_SYS +) + +set(SRC + intern/gpencil_io_capi.cc + intern/gpencil_io_base.cc + intern/gpencil_io_import_base.cc + intern/gpencil_io_import_svg.cc + + # This line must be removed if NanoSVG is moved to extern + nanosvg/nanosvg.h + + gpencil_io.h + intern/gpencil_io_base.hh + intern/gpencil_io_export_base.hh + intern/gpencil_io_import_base.hh + intern/gpencil_io_import_svg.hh +) + +set(LIB + bf_blenkernel + bf_blenlib + bf_io_common +) + +if(WITH_PUGIXML) + list(APPEND SRC + intern/gpencil_io_export_svg.cc + + intern/gpencil_io_export_svg.hh + ) + list(APPEND INC_SYS + ${PUGIXML_INCLUDE_DIR} + ) + list(APPEND LIB + ${PUGIXML_LIBRARIES} + ) + add_definitions(-DWITH_PUGIXML) +endif() + +if(WITH_HARU) + list(APPEND SRC + intern/gpencil_io_export_pdf.cc + + intern/gpencil_io_export_pdf.hh + ) + list(APPEND INC_SYS + ${HARU_INCLUDE_DIRS} + ) + list(APPEND LIB + ${HARU_LIBRARIES} + ) + add_definitions(-DWITH_HARU) +endif() + + +list(APPEND LIB + ${BOOST_LIBRARIES} +) + +blender_add_lib(bf_gpencil "${SRC}" "${INC}" "${INC_SYS}" "${LIB}") diff --git a/source/blender/io/gpencil/gpencil_io.h b/source/blender/io/gpencil/gpencil_io.h new file mode 100644 index 00000000000..24b13479359 --- /dev/null +++ b/source/blender/io/gpencil/gpencil_io.h @@ -0,0 +1,92 @@ +/* + * 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) 2020 Blender Foundation + * All rights reserved. + */ +#pragma once + +/** \file + * \ingroup bgpencil + */ + +#ifdef __cplusplus +extern "C" { +#endif + +struct ARegion; +struct bContext; +struct Object; +struct View3D; + +typedef struct GpencilIOParams { + bContext *C; + ARegion *region; + View3D *v3d; + /** Grease pencil object. */ + Object *ob; + /** Mode (see eGpencilIO_Modes). */ + uint16_t mode; + int32_t frame_start; + int32_t frame_end; + int32_t frame_cur; + uint32_t flag; + float scale; + /** Select mode (see eGpencilExportSelect). */ + uint16_t select_mode; + /** Frame mode (see eGpencilExportFrame). */ + uint16_t frame_mode; + /** Stroke sampling factor. */ + float stroke_sample; + int32_t resolution; +} GpencilIOParams; + +/* GpencilIOParams->flag. */ +typedef enum eGpencilIOParams_Flag { + /* Export Filled strokes. */ + GP_EXPORT_FILL = (1 << 0), + /* Export normalized thickness. */ + GP_EXPORT_NORM_THICKNESS = (1 << 1), + /* Clip camera area. */ + GP_EXPORT_CLIP_CAMERA = (1 << 2), +} eGpencilIOParams_Flag; + +typedef enum eGpencilIO_Modes { + GP_EXPORT_TO_SVG = 0, + GP_EXPORT_TO_PDF = 1, + + GP_IMPORT_FROM_SVG = 2, + /* Add new formats here. */ +} eGpencilIO_Modes; + +/* Object to be exported. */ +typedef enum eGpencilExportSelect { + GP_EXPORT_ACTIVE = 0, + GP_EXPORT_SELECTED = 1, + GP_EXPORT_VISIBLE = 2, +} eGpencilExportSelect; + +/** Frame-range to be exported. */ +typedef enum eGpencilExportFrame { + GP_EXPORT_FRAME_ACTIVE = 0, + GP_EXPORT_FRAME_SELECTED = 1, +} eGpencilExportFrame; + +bool gpencil_io_export(const char *filename, struct GpencilIOParams *iparams); +bool gpencil_io_import(const char *filename, struct GpencilIOParams *iparams); + +#ifdef __cplusplus +} +#endif diff --git a/source/blender/io/gpencil/intern/gpencil_io_base.cc b/source/blender/io/gpencil/intern/gpencil_io_base.cc new file mode 100644 index 00000000000..8da1ec27b9c --- /dev/null +++ b/source/blender/io/gpencil/intern/gpencil_io_base.cc @@ -0,0 +1,396 @@ + + +/* + * 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) 2020 Blender Foundation + * All rights reserved. + */ + +/** \file + * \ingroup bgpencil + */ + +#include "BLI_float2.hh" +#include "BLI_float3.hh" +#include "BLI_float4x4.hh" +#include "BLI_path_util.h" +#include "BLI_span.hh" + +#include "DNA_gpencil_types.h" +#include "DNA_layer_types.h" +#include "DNA_material_types.h" +#include "DNA_scene_types.h" +#include "DNA_screen_types.h" + +#include "BKE_camera.h" +#include "BKE_context.h" +#include "BKE_gpencil.h" +#include "BKE_gpencil_geom.h" +#include "BKE_main.h" +#include "BKE_material.h" + +#include "UI_view2d.h" + +#include "ED_view3d.h" + +#include "DEG_depsgraph.h" +#include "DEG_depsgraph_query.h" + +#include "gpencil_io_base.hh" + +using blender::Span; + +namespace blender::io::gpencil { + +/* Constructor. */ +GpencilIO::GpencilIO(const GpencilIOParams *iparams) +{ + params_ = *iparams; + + /* Easy access data. */ + bmain_ = CTX_data_main(params_.C); + depsgraph_ = CTX_data_depsgraph_pointer(params_.C); + scene_ = CTX_data_scene(params_.C); + rv3d_ = (RegionView3D *)params_.region->regiondata; + gpd_ = (params_.ob != nullptr) ? (bGPdata *)params_.ob->data : nullptr; + cfra_ = iparams->frame_cur; + + /* Calculate camera matrix. */ + Object *cam_ob = params_.v3d->camera; + if (cam_ob != nullptr) { + /* Set up parameters. */ + CameraParams params; + BKE_camera_params_init(¶ms); + BKE_camera_params_from_object(¶ms, cam_ob); + + /* Compute matrix, viewplane, .. */ + RenderData *rd = &scene_->r; + BKE_camera_params_compute_viewplane(¶ms, rd->xsch, rd->ysch, rd->xasp, rd->yasp); + BKE_camera_params_compute_matrix(¶ms); + + float viewmat[4][4]; + invert_m4_m4(viewmat, cam_ob->obmat); + + mul_m4_m4m4(persmat_, params.winmat, viewmat); + is_ortho_ = params.is_ortho; + } + else { + unit_m4(persmat_); + is_ortho_ = false; + } + + winx_ = params_.region->winx; + winy_ = params_.region->winy; + + /* Camera rectangle. */ + if (rv3d_->persp == RV3D_CAMOB) { + render_x_ = (scene_->r.xsch * scene_->r.size) / 100; + render_y_ = (scene_->r.ysch * scene_->r.size) / 100; + + ED_view3d_calc_camera_border(CTX_data_scene(params_.C), + depsgraph_, + params_.region, + params_.v3d, + rv3d_, + &camera_rect_, + true); + is_camera_ = true; + camera_ratio_ = render_x_ / (camera_rect_.xmax - camera_rect_.xmin); + offset_.x = camera_rect_.xmin; + offset_.y = camera_rect_.ymin; + } + else { + is_camera_ = false; + is_ortho_ = false; + /* Calc selected object boundbox. Need set initial value to some variables. */ + camera_ratio_ = 1.0f; + offset_.x = 0.0f; + offset_.y = 0.0f; + + selected_objects_boundbox_calc(); + rctf boundbox; + selected_objects_boundbox_get(&boundbox); + + render_x_ = boundbox.xmax - boundbox.xmin; + render_y_ = boundbox.ymax - boundbox.ymin; + offset_.x = boundbox.xmin; + offset_.y = boundbox.ymin; + } +} + +/** Create a list of selected objects sorted from back to front */ +void GpencilIO::create_object_list() +{ + ViewLayer *view_layer = CTX_data_view_layer(params_.C); + + float3 camera_z_axis; + copy_v3_v3(camera_z_axis, rv3d_->viewinv[2]); + ob_list_.clear(); + + LISTBASE_FOREACH (Base *, base, &view_layer->object_bases) { + Object *object = base->object; + + if (object->type != OB_GPENCIL) { + continue; + } + if ((params_.select_mode == GP_EXPORT_ACTIVE) && (params_.ob != object)) { + continue; + } + + if ((params_.select_mode == GP_EXPORT_SELECTED) && ((base->flag & BASE_SELECTED) == 0)) { + continue; + } + + /* Save z-depth from view to sort from back to front. */ + if (is_camera_) { + float camera_z = dot_v3v3(camera_z_axis, object->obmat[3]); + ObjectZ obz = {camera_z, object}; + ob_list_.append(obz); + } + else { + float zdepth = 0; + if (rv3d_) { + if (rv3d_->is_persp) { + zdepth = ED_view3d_calc_zfac(rv3d_, object->obmat[3], nullptr); + } + else { + zdepth = -dot_v3v3(rv3d_->viewinv[2], object->obmat[3]); + } + ObjectZ obz = {zdepth * -1.0f, object}; + ob_list_.append(obz); + } + } + } + /* Sort list of objects from point of view. */ + std::sort(ob_list_.begin(), ob_list_.end(), [](const ObjectZ &obz1, const ObjectZ &obz2) { + return obz1.zdepth < obz2.zdepth; + }); +} + +/** + * Set file input_text full path. + * \param filename: Path of the file provided by save dialog. + */ +void GpencilIO::filename_set(const char *filename) +{ + BLI_strncpy(filename_, filename, FILE_MAX); + BLI_path_abs(filename_, BKE_main_blendfile_path(bmain_)); +} + +/** Convert to screenspace. */ +bool GpencilIO::gpencil_3D_point_to_screen_space(const float3 co, float2 &r_co) +{ + float3 parent_co = diff_mat_ * co; + float2 screen_co; + eV3DProjTest test = (eV3DProjTest)(V3D_PROJ_RET_OK); + if (ED_view3d_project_float_global(params_.region, parent_co, screen_co, test) == + V3D_PROJ_RET_OK) { + if (!ELEM(V2D_IS_CLIPPED, screen_co[0], screen_co[1])) { + copy_v2_v2(r_co, screen_co); + /* Invert X axis. */ + if (invert_axis_[0]) { + r_co[0] = winx_ - r_co[0]; + } + /* Invert Y axis. */ + if (invert_axis_[1]) { + r_co[1] = winy_ - r_co[1]; + } + /* Apply offset and scale. */ + sub_v2_v2(r_co, &offset_.x); + mul_v2_fl(r_co, camera_ratio_); + + return true; + } + } + r_co[0] = V2D_IS_CLIPPED; + r_co[1] = V2D_IS_CLIPPED; + + /* Invert X axis. */ + if (invert_axis_[0]) { + r_co[0] = winx_ - r_co[0]; + } + /* Invert Y axis. */ + if (invert_axis_[1]) { + r_co[1] = winy_ - r_co[1]; + } + + return false; +} + +/** Convert to render space. */ +float2 GpencilIO::gpencil_3D_point_to_render_space(const float3 co, const bool is_ortho) +{ + float3 parent_co = diff_mat_ * co; + mul_m4_v3(persmat_, parent_co); + + if (!is_ortho) { + parent_co.x = parent_co.x / max_ff(FLT_MIN, parent_co.z); + parent_co.y = parent_co.y / max_ff(FLT_MIN, parent_co.z); + } + + float2 r_co; + r_co.x = (parent_co.x + 1.0f) / 2.0f * (float)render_x_; + r_co.y = (parent_co.y + 1.0f) / 2.0f * (float)render_y_; + + /* Invert X axis. */ + if (invert_axis_[0]) { + r_co.x = (float)render_x_ - r_co.x; + } + /* Invert Y axis. */ + if (invert_axis_[1]) { + r_co.y = (float)render_y_ - r_co.y; + } + + return r_co; +} + +/** Convert to 2D. */ +float2 GpencilIO::gpencil_3D_point_to_2D(const float3 co) +{ + const bool is_camera = (bool)(rv3d_->persp == RV3D_CAMOB); + if (is_camera) { + return gpencil_3D_point_to_render_space(co, is_orthographic()); + } + float2 result; + gpencil_3D_point_to_screen_space(co, result); + return result; +} + +/** Get radius of point. */ +float GpencilIO::stroke_point_radius_get(bGPDlayer *gpl, bGPDstroke *gps) +{ + bGPDspoint *pt = &gps->points[0]; + const float2 screen_co = gpencil_3D_point_to_2D(&pt->x); + + /* Radius. */ + bGPDstroke *gps_perimeter = BKE_gpencil_stroke_perimeter_from_view( + rv3d_, gpd_, gpl, gps, 3, diff_mat_.values); + + pt = &gps_perimeter->points[0]; + const float2 screen_ex = gpencil_3D_point_to_2D(&pt->x); + + const float2 v1 = screen_co - screen_ex; + float radius = v1.length(); + BKE_gpencil_free_stroke(gps_perimeter); + + return MAX2(radius, 1.0f); +} + +void GpencilIO::prepare_layer_export_matrix(Object *ob, bGPDlayer *gpl) +{ + BKE_gpencil_layer_transform_matrix_get(depsgraph_, ob, gpl, diff_mat_.values); + diff_mat_ = diff_mat_ * float4x4(gpl->layer_invmat); +} + +void GpencilIO::prepare_stroke_export_colors(Object *ob, bGPDstroke *gps) +{ + MaterialGPencilStyle *gp_style = BKE_gpencil_material_settings(ob, gps->mat_nr + 1); + + /* Stroke color. */ + copy_v4_v4(stroke_color_, gp_style->stroke_rgba); + avg_opacity_ = 0; + /* Get average vertex color and apply. */ + float avg_color[4] = {0.0f, 0.0f, 0.0f, 0.0f}; + for (const bGPDspoint &pt : Span(gps->points, gps->totpoints)) { + add_v4_v4(avg_color, pt.vert_color); + avg_opacity_ += pt.strength; + } + + mul_v4_v4fl(avg_color, avg_color, 1.0f / (float)gps->totpoints); + interp_v3_v3v3(stroke_color_, stroke_color_, avg_color, avg_color[3]); + avg_opacity_ /= (float)gps->totpoints; + + /* Fill color. */ + copy_v4_v4(fill_color_, gp_style->fill_rgba); + /* Apply vertex color for fill. */ + interp_v3_v3v3(fill_color_, fill_color_, gps->vert_color_fill, gps->vert_color_fill[3]); +} + +float GpencilIO::stroke_average_opacity_get() +{ + return avg_opacity_; +} + +bool GpencilIO::is_camera_mode() +{ + return is_camera_; +} + +bool GpencilIO::is_orthographic() +{ + return is_ortho_; +} + +/* Calculate selected strokes boundbox. */ +void GpencilIO::selected_objects_boundbox_calc() +{ + const float gap = 10.0f; + + float2 min, max; + INIT_MINMAX2(min, max); + + for (ObjectZ &obz : ob_list_) { + Object *ob = obz.ob; + /* Use evaluated version to get strokes with modifiers. */ + Object *ob_eval = (Object *)DEG_get_evaluated_id(depsgraph_, &ob->id); + bGPdata *gpd_eval = (bGPdata *)ob_eval->data; + + LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd_eval->layers) { + if (gpl->flag & GP_LAYER_HIDE) { + continue; + } + BKE_gpencil_layer_transform_matrix_get(depsgraph_, ob_eval, gpl, diff_mat_.values); + + bGPDframe *gpf = gpl->actframe; + if (gpf == nullptr) { + continue; + } + + LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) { + if (gps->totpoints == 0) { + continue; + } + for (const bGPDspoint &pt : MutableSpan(gps->points, gps->totpoints)) { + const float2 screen_co = gpencil_3D_point_to_2D(&pt.x); + minmax_v2v2_v2(min, max, screen_co); + } + } + } + } + /* Add small gap. */ + add_v2_fl(min, gap * -1.0f); + add_v2_fl(max, gap); + + select_boundbox_.xmin = min[0]; + select_boundbox_.ymin = min[1]; + select_boundbox_.xmax = max[0]; + select_boundbox_.ymax = max[1]; +} + +void GpencilIO::selected_objects_boundbox_get(rctf *boundbox) +{ + boundbox->xmin = select_boundbox_.xmin; + boundbox->xmax = select_boundbox_.xmax; + boundbox->ymin = select_boundbox_.ymin; + boundbox->ymax = select_boundbox_.ymax; +} + +void GpencilIO::frame_number_set(const int value) +{ + cfra_ = value; +} + +} // namespace blender::io::gpencil diff --git a/source/blender/io/gpencil/intern/gpencil_io_base.hh b/source/blender/io/gpencil/intern/gpencil_io_base.hh new file mode 100644 index 00000000000..cbcd35e470d --- /dev/null +++ b/source/blender/io/gpencil/intern/gpencil_io_base.hh @@ -0,0 +1,118 @@ +/* + * 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) 2020 Blender Foundation + * All rights reserved. + */ +#pragma once + +/** \file + * \ingroup bgpencil + */ + +#include "BLI_float2.hh" +#include "BLI_float3.hh" +#include "BLI_float4x4.hh" +#include "BLI_vector.hh" + +#include "DNA_space_types.h" /* for FILE_MAX */ + +#include "gpencil_io.h" + +struct Depsgraph; +struct Main; +struct Object; +struct RegionView3D; +struct Scene; + +struct bGPdata; +struct bGPDlayer; +struct bGPDstroke; + +using blender::Vector; + +namespace blender::io::gpencil { + +class GpencilIO { + public: + GpencilIO(const GpencilIOParams *iparams); + + void frame_number_set(const int value); + + protected: + GpencilIOParams params_; + + bool invert_axis_[2]; + float4x4 diff_mat_; + char filename_[FILE_MAX]; + + /* Used for sorting objects. */ + struct ObjectZ { + float zdepth; + struct Object *ob; + }; + + /** List of included objects. */ + blender::Vector<ObjectZ> ob_list_; + + /* Data for easy access. */ + struct Depsgraph *depsgraph_; + struct bGPdata *gpd_; + struct Main *bmain_; + struct Scene *scene_; + struct RegionView3D *rv3d_; + + int16_t winx_, winy_; + int16_t render_x_, render_y_; + float camera_ratio_; + rctf camera_rect_; + + float2 offset_; + + int cfra_; + + float stroke_color_[4], fill_color_[4]; + + /* Geometry functions. */ + bool gpencil_3D_point_to_screen_space(const float3 co, float2 &r_co); + float2 gpencil_3D_point_to_render_space(const float3 co, const bool is_ortho); + float2 gpencil_3D_point_to_2D(const float3 co); + + float stroke_point_radius_get(struct bGPDlayer *gpl, struct bGPDstroke *gps); + void create_object_list(); + + bool is_camera_mode(); + bool is_orthographic(); + + float stroke_average_opacity_get(); + + void prepare_layer_export_matrix(struct Object *ob, struct bGPDlayer *gpl); + void prepare_stroke_export_colors(struct Object *ob, struct bGPDstroke *gps); + + void selected_objects_boundbox_calc(); + void selected_objects_boundbox_get(rctf *boundbox); + void filename_set(const char *filename); + + private: + float avg_opacity_; + bool is_camera_; + bool is_ortho_; + rctf select_boundbox_; + + /* Camera matrix. */ + float persmat_[4][4]; +}; + +} // namespace blender::io::gpencil diff --git a/source/blender/io/gpencil/intern/gpencil_io_capi.cc b/source/blender/io/gpencil/intern/gpencil_io_capi.cc new file mode 100644 index 00000000000..a710c175a77 --- /dev/null +++ b/source/blender/io/gpencil/intern/gpencil_io_capi.cc @@ -0,0 +1,204 @@ +/* + * 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) 2020 Blender Foundation + * All rights reserved. + */ + +/** \file + * \ingroup bgpencil + */ + +#include <cstdio> + +#include "BLI_listbase.h" + +#include "DNA_gpencil_types.h" +#include "DNA_screen_types.h" +#include "DNA_space_types.h" + +#include "BKE_context.h" +#include "BKE_gpencil.h" +#include "BKE_main.h" +#include "BKE_scene.h" + +#include "DEG_depsgraph.h" +#include "DEG_depsgraph_query.h" + +#include "../gpencil_io.h" + +#ifdef WITH_HARU +# include "gpencil_io_export_pdf.hh" +#endif + +#ifdef WITH_PUGIXML +# include "gpencil_io_export_svg.hh" +#endif + +#include "gpencil_io_import_svg.hh" + +#ifdef WITH_HARU +using blender::io::gpencil::GpencilExporterPDF; +#endif +#ifdef WITH_PUGIXML +using blender::io::gpencil::GpencilExporterSVG; +#endif +using blender::io::gpencil::GpencilImporterSVG; + +/* Check if frame is included. */ +#ifdef WITH_HARU +static bool is_keyframe_included(bGPdata *gpd_, const int32_t framenum, const bool use_selected) +{ + /* Check if exist a frame. */ + LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd_->layers) { + if (gpl->flag & GP_LAYER_HIDE) { + continue; + } + LISTBASE_FOREACH (bGPDframe *, gpf, &gpl->frames) { + if (gpf->framenum == framenum) { + if ((!use_selected) || (use_selected && (gpf->flag & GP_FRAME_SELECT))) { + return true; + } + } + } + } + return false; +} +#endif + +/* Import frame. */ +static bool gpencil_io_import_frame(void *in_importer, const GpencilIOParams &iparams) +{ + + bool result = false; + switch (iparams.mode) { + case GP_IMPORT_FROM_SVG: { + GpencilImporterSVG *importer = (GpencilImporterSVG *)in_importer; + result |= importer->read(); + break; + } + /* Add new import formats here. */ + default: + break; + } + + return result; +} + +/* Export frame in PDF. */ +#ifdef WITH_HARU +static bool gpencil_io_export_pdf(Depsgraph *depsgraph, + Scene *scene, + Object *ob, + GpencilExporterPDF *exporter, + const GpencilIOParams *iparams) +{ + bool result = false; + Object *ob_eval_ = (Object *)DEG_get_evaluated_id(depsgraph, &ob->id); + bGPdata *gpd_eval = (bGPdata *)ob_eval_->data; + + exporter->frame_number_set(iparams->frame_cur); + result |= exporter->new_document(); + + const bool use_frame_selected = (iparams->frame_mode == GP_EXPORT_FRAME_SELECTED); + if (use_frame_selected) { + for (int32_t i = iparams->frame_start; i < iparams->frame_end + 1; i++) { + if (!is_keyframe_included(gpd_eval, i, use_frame_selected)) { + continue; + } + + CFRA = i; + BKE_scene_graph_update_for_newframe(depsgraph); + exporter->frame_number_set(i); + exporter->add_newpage(); + exporter->add_body(); + } + result = exporter->write(); + /* Back to original frame. */ + exporter->frame_number_set(iparams->frame_cur); + CFRA = iparams->frame_cur; + BKE_scene_graph_update_for_newframe(depsgraph); + } + else { + exporter->add_newpage(); + exporter->add_body(); + result = exporter->write(); + } + + return result; +} +#endif + +/* Export current frame in SVG. */ +#ifdef WITH_PUGIXML +static bool gpencil_io_export_frame_svg(GpencilExporterSVG *exporter, + const GpencilIOParams *iparams, + const bool newpage, + const bool body, + const bool savepage) +{ + bool result = false; + exporter->frame_number_set(iparams->frame_cur); + if (newpage) { + result |= exporter->add_newpage(); + } + if (body) { + result |= exporter->add_body(); + } + if (savepage) { + result = exporter->write(); + } + return result; +} +#endif + +/* Main import entry point function. */ +bool gpencil_io_import(const char *filename, GpencilIOParams *iparams) +{ + GpencilImporterSVG importer = GpencilImporterSVG(filename, iparams); + + return gpencil_io_import_frame(&importer, *iparams); +} + +/* Main export entry point function. */ +bool gpencil_io_export(const char *filename, GpencilIOParams *iparams) +{ + Depsgraph *depsgraph_ = CTX_data_depsgraph_pointer(iparams->C); + Scene *scene_ = CTX_data_scene(iparams->C); + Object *ob = CTX_data_active_object(iparams->C); + + UNUSED_VARS(filename, depsgraph_, scene_, ob); + + switch (iparams->mode) { +#ifdef WITH_PUGIXML + case GP_EXPORT_TO_SVG: { + GpencilExporterSVG exporter = GpencilExporterSVG(filename, iparams); + return gpencil_io_export_frame_svg(&exporter, iparams, true, true, true); + break; + } +#endif +#ifdef WITH_HARU + case GP_EXPORT_TO_PDF: { + GpencilExporterPDF exporter = GpencilExporterPDF(filename, iparams); + return gpencil_io_export_pdf(depsgraph_, scene_, ob, &exporter, iparams); + break; + } +#endif + /* Add new export formats here. */ + default: + break; + } + return false; +} diff --git a/source/blender/compositor/intern/COM_SocketReader.cc b/source/blender/io/gpencil/intern/gpencil_io_export_base.hh index 93c8a143b86..ffb1c6ce262 100644 --- a/source/blender/compositor/intern/COM_SocketReader.cc +++ b/source/blender/io/gpencil/intern/gpencil_io_export_base.hh @@ -13,7 +13,26 @@ * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * Copyright 2011, Blender Foundation. + * The Original Code is Copyright (C) 2020 Blender Foundation + * All rights reserved. */ +#pragma once -#include "COM_SocketReader.h" +/** \file + * \ingroup bgpencil + */ +#include "gpencil_io_base.hh" + +namespace blender::io::gpencil { + +class GpencilExporter : public GpencilIO { + + public: + GpencilExporter(const struct GpencilIOParams *iparams) : GpencilIO(iparams){}; + virtual bool write() = 0; + + protected: + private: +}; + +} // namespace blender::io::gpencil diff --git a/source/blender/io/gpencil/intern/gpencil_io_export_pdf.cc b/source/blender/io/gpencil/intern/gpencil_io_export_pdf.cc new file mode 100644 index 00000000000..9b2dc6d12a3 --- /dev/null +++ b/source/blender/io/gpencil/intern/gpencil_io_export_pdf.cc @@ -0,0 +1,311 @@ +/* + * 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) 2020 Blender Foundation + * All rights reserved. + */ + +/** \file + * \ingroup bgpencil + */ + +#include "BLI_math_vector.h" + +#include "DNA_gpencil_types.h" +#include "DNA_material_types.h" +#include "DNA_object_types.h" +#include "DNA_scene_types.h" +#include "DNA_screen_types.h" +#include "DNA_view3d_types.h" + +#include "BKE_context.h" +#include "BKE_gpencil.h" +#include "BKE_gpencil_geom.h" +#include "BKE_main.h" +#include "BKE_material.h" + +#include "DEG_depsgraph.h" +#include "DEG_depsgraph_query.h" + +#include "ED_gpencil.h" +#include "ED_view3d.h" + +#ifdef WIN32 +# include "utfconv.h" +#endif + +#include "UI_view2d.h" + +#include "gpencil_io.h" +#include "gpencil_io_export_pdf.hh" + +namespace blender ::io ::gpencil { + +static void error_handler(HPDF_STATUS error_no, HPDF_STATUS detail_no, void *UNUSED(user_data)) +{ + printf("ERROR: error_no=%04X, detail_no=%u\n", (HPDF_UINT)error_no, (HPDF_UINT)detail_no); +} + +/* Constructor. */ +GpencilExporterPDF::GpencilExporterPDF(const char *filename, const GpencilIOParams *iparams) + : GpencilExporter(iparams) +{ + filename_set(filename); + + invert_axis_[0] = false; + invert_axis_[1] = false; + + pdf_ = nullptr; + page_ = nullptr; + gstate_ = nullptr; +} + +bool GpencilExporterPDF::new_document() +{ + return create_document(); +} + +bool GpencilExporterPDF::add_newpage() +{ + return add_page(); +} + +bool GpencilExporterPDF::add_body() +{ + export_gpencil_layers(); + return true; +} + +bool GpencilExporterPDF::write() +{ + /* Support unicode character paths on Windows. */ + HPDF_STATUS res = 0; + /* TODO: It looks libharu does not support unicode. */ + //#ifdef WIN32 + // char filename_cstr[FILE_MAX]; + // BLI_strncpy(filename_cstr, filename_, FILE_MAX); + // + // UTF16_ENCODE(filename_cstr); + // std::wstring wstr(filename_cstr_16); + // res = HPDF_SaveToFile(pdf_, wstr.c_str()); + // + // UTF16_UN_ENCODE(filename_cstr); + //#else + res = HPDF_SaveToFile(pdf_, filename_); + //#endif + + return (res == 0) ? true : false; +} + +/* Create pdf document. */ +bool GpencilExporterPDF::create_document() +{ + pdf_ = HPDF_New(error_handler, nullptr); + if (!pdf_) { + std::cout << "error: cannot create PdfDoc object\n"; + return false; + } + return true; +} + +/* Add page. */ +bool GpencilExporterPDF::add_page() +{ + /* Add a new page object. */ + page_ = HPDF_AddPage(pdf_); + if (!pdf_) { + std::cout << "error: cannot create PdfPage\n"; + return false; + } + + HPDF_Page_SetWidth(page_, render_x_); + HPDF_Page_SetHeight(page_, render_y_); + + return true; +} + +/* Main layer loop. */ +void GpencilExporterPDF::export_gpencil_layers() +{ + /* If is doing a set of frames, the list of objects can change for each frame. */ + create_object_list(); + + const bool is_normalized = ((params_.flag & GP_EXPORT_NORM_THICKNESS) != 0); + + for (ObjectZ &obz : ob_list_) { + Object *ob = obz.ob; + + /* Use evaluated version to get strokes with modifiers. */ + Object *ob_eval_ = (Object *)DEG_get_evaluated_id(depsgraph_, &ob->id); + bGPdata *gpd_eval = (bGPdata *)ob_eval_->data; + + LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd_eval->layers) { + if (gpl->flag & GP_LAYER_HIDE) { + continue; + } + prepare_layer_export_matrix(ob, gpl); + + bGPDframe *gpf = gpl->actframe; + if ((gpf == nullptr) || (gpf->strokes.first == nullptr)) { + continue; + } + + LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) { + if (gps->totpoints < 2) { + continue; + } + if (!ED_gpencil_stroke_material_visible(ob, gps)) { + continue; + } + /* Duplicate the stroke to apply any layer thickness change. */ + bGPDstroke *gps_duplicate = BKE_gpencil_stroke_duplicate(gps, true, false); + MaterialGPencilStyle *gp_style = BKE_gpencil_material_settings(ob, + gps_duplicate->mat_nr + 1); + + const bool is_stroke = ((gp_style->flag & GP_MATERIAL_STROKE_SHOW) && + (gp_style->stroke_rgba[3] > GPENCIL_ALPHA_OPACITY_THRESH)); + const bool is_fill = ((gp_style->flag & GP_MATERIAL_FILL_SHOW) && + (gp_style->fill_rgba[3] > GPENCIL_ALPHA_OPACITY_THRESH)); + prepare_stroke_export_colors(ob, gps_duplicate); + + /* Apply layer thickness change. */ + gps_duplicate->thickness += gpl->line_change; + /* Apply object scale to thickness. */ + gps_duplicate->thickness *= mat4_to_scale(ob->obmat); + CLAMP_MIN(gps_duplicate->thickness, 1.0f); + /* Fill. */ + if ((is_fill) && (params_.flag & GP_EXPORT_FILL)) { + /* Fill is exported as polygon for fill and stroke in a different shape. */ + export_stroke_to_polyline(gpl, gps_duplicate, is_stroke, true, false); + } + + /* Stroke. */ + if (is_stroke) { + if (is_normalized) { + export_stroke_to_polyline(gpl, gps_duplicate, is_stroke, false, true); + } + else { + bGPDstroke *gps_perimeter = BKE_gpencil_stroke_perimeter_from_view( + rv3d_, gpd_, gpl, gps_duplicate, 3, diff_mat_.values); + + /* Sample stroke. */ + if (params_.stroke_sample > 0.0f) { + BKE_gpencil_stroke_sample(gpd_eval, gps_perimeter, params_.stroke_sample, false); + } + + export_stroke_to_polyline(gpl, gps_perimeter, is_stroke, false, false); + + BKE_gpencil_free_stroke(gps_perimeter); + } + } + BKE_gpencil_free_stroke(gps_duplicate); + } + } + } +} + +/** + * Export a stroke using polyline or polygon + * \param do_fill: True if the stroke is only fill + */ +void GpencilExporterPDF::export_stroke_to_polyline(bGPDlayer *gpl, + bGPDstroke *gps, + const bool is_stroke, + const bool do_fill, + const bool normalize) +{ + const bool cyclic = ((gps->flag & GP_STROKE_CYCLIC) != 0); + const float avg_pressure = BKE_gpencil_stroke_average_pressure_get(gps); + + /* Get the thickness in pixels using a simple 1 point stroke. */ + bGPDstroke *gps_temp = BKE_gpencil_stroke_duplicate(gps, false, false); + gps_temp->totpoints = 1; + gps_temp->points = (bGPDspoint *)MEM_callocN(sizeof(bGPDspoint), "gp_stroke_points"); + const bGPDspoint *pt_src = &gps->points[0]; + bGPDspoint *pt_dst = &gps_temp->points[0]; + copy_v3_v3(&pt_dst->x, &pt_src->x); + pt_dst->pressure = avg_pressure; + + const float radius = stroke_point_radius_get(gpl, gps_temp); + + BKE_gpencil_free_stroke(gps_temp); + + color_set(gpl, do_fill); + + if (is_stroke && !do_fill) { + HPDF_Page_SetLineJoin(page_, HPDF_ROUND_JOIN); + HPDF_Page_SetLineWidth(page_, MAX2((radius * 2.0f) - gpl->line_change, 1.0f)); + } + + /* Loop all points. */ + for (const int i : IndexRange(gps->totpoints)) { + bGPDspoint *pt = &gps->points[i]; + const float2 screen_co = gpencil_3D_point_to_2D(&pt->x); + if (i == 0) { + HPDF_Page_MoveTo(page_, screen_co.x, screen_co.y); + } + else { + HPDF_Page_LineTo(page_, screen_co.x, screen_co.y); + } + } + /* Close cyclic */ + if (cyclic) { + HPDF_Page_ClosePath(page_); + } + + if (do_fill || !normalize) { + HPDF_Page_Fill(page_); + } + else { + HPDF_Page_Stroke(page_); + } + + HPDF_Page_GRestore(page_); +} + +/** + * Set color + * @param do_fill: True if the stroke is only fill + */ +void GpencilExporterPDF::color_set(bGPDlayer *gpl, const bool do_fill) +{ + const float fill_opacity = fill_color_[3] * gpl->opacity; + const float stroke_opacity = stroke_color_[3] * stroke_average_opacity_get() * gpl->opacity; + + HPDF_Page_GSave(page_); + gstate_ = HPDF_CreateExtGState(pdf_); + + float col[3]; + if (do_fill) { + interp_v3_v3v3(col, fill_color_, gpl->tintcolor, gpl->tintcolor[3]); + linearrgb_to_srgb_v3_v3(col, col); + CLAMP3(col, 0.0f, 1.0f); + + HPDF_ExtGState_SetAlphaFill(gstate_, clamp_f(fill_opacity, 0.0f, 1.0f)); + HPDF_Page_SetRGBFill(page_, col[0], col[1], col[2]); + } + else { + interp_v3_v3v3(col, stroke_color_, gpl->tintcolor, gpl->tintcolor[3]); + linearrgb_to_srgb_v3_v3(col, col); + CLAMP3(col, 0.0f, 1.0f); + + HPDF_ExtGState_SetAlphaFill(gstate_, clamp_f(stroke_opacity, 0.0f, 1.0f)); + HPDF_ExtGState_SetAlphaStroke(gstate_, clamp_f(stroke_opacity, 0.0f, 1.0f)); + HPDF_Page_SetRGBFill(page_, col[0], col[1], col[2]); + HPDF_Page_SetRGBStroke(page_, col[0], col[1], col[2]); + } + HPDF_Page_SetExtGState(page_, gstate_); +} +} // namespace blender::io::gpencil diff --git a/source/blender/io/gpencil/intern/gpencil_io_export_pdf.hh b/source/blender/io/gpencil/intern/gpencil_io_export_pdf.hh new file mode 100644 index 00000000000..20970151344 --- /dev/null +++ b/source/blender/io/gpencil/intern/gpencil_io_export_pdf.hh @@ -0,0 +1,67 @@ +/* + * 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) 2020 Blender Foundation + * All rights reserved. + */ +#pragma once + +/** \file + * \ingroup bgpencil + */ + +#include "gpencil_io_export_base.hh" +#include "hpdf.h" + +struct GpencilIOParams; +struct bGPDlayer; +struct bGPDstroke; + +#define PDF_EXPORTER_NAME "PDF Exporter for Grease Pencil" +#define PDF_EXPORTER_VERSION "v1.0" + +namespace blender::io::gpencil { + +class GpencilExporterPDF : public GpencilExporter { + + public: + GpencilExporterPDF(const char *filename, const struct GpencilIOParams *iparams); + bool new_document(); + bool add_newpage(); + bool add_body(); + bool write(); + + protected: + private: + /* PDF document. */ + HPDF_Doc pdf_; + /* PDF page. */ + HPDF_Page page_; + /* State. */ + HPDF_ExtGState gstate_; + + bool create_document(); + bool add_page(); + void export_gpencil_layers(); + + void export_stroke_to_polyline(bGPDlayer *gpl, + bGPDstroke *gps, + const bool is_stroke, + const bool do_fill, + const bool normalize); + void color_set(bGPDlayer *gpl, const bool do_fill); +}; + +} // namespace blender::io::gpencil diff --git a/source/blender/io/gpencil/intern/gpencil_io_export_svg.cc b/source/blender/io/gpencil/intern/gpencil_io_export_svg.cc new file mode 100644 index 00000000000..c62764cca06 --- /dev/null +++ b/source/blender/io/gpencil/intern/gpencil_io_export_svg.cc @@ -0,0 +1,465 @@ +/* + * 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) 2020 Blender Foundation + * All rights reserved. + */ + +/** \file + * \ingroup bgpencil + */ + +#include "BLI_math_vector.h" +#include "BLI_string.h" +#include "BLI_utildefines.h" + +#include "DNA_gpencil_types.h" +#include "DNA_material_types.h" +#include "DNA_object_types.h" +#include "DNA_scene_types.h" +#include "DNA_screen_types.h" + +#include "BKE_gpencil.h" +#include "BKE_gpencil_geom.h" +#include "BKE_main.h" +#include "BKE_material.h" + +#include "DEG_depsgraph.h" +#include "DEG_depsgraph_query.h" + +#include "ED_gpencil.h" +#include "ED_view3d.h" + +#ifdef WIN32 +# include "utfconv.h" +#endif + +#include "UI_view2d.h" + +#include "gpencil_io.h" +#include "gpencil_io_export_svg.hh" + +#include "pugixml.hpp" + +namespace blender ::io ::gpencil { + +/* Constructor. */ +GpencilExporterSVG::GpencilExporterSVG(const char *filename, const GpencilIOParams *iparams) + : GpencilExporter(iparams) +{ + filename_set(filename); + + invert_axis_[0] = false; + invert_axis_[1] = true; +} + +bool GpencilExporterSVG::add_newpage() +{ + create_document_header(); + return true; +} + +bool GpencilExporterSVG::add_body() +{ + export_gpencil_layers(); + return true; +} + +bool GpencilExporterSVG::write() +{ + bool result = true; +/* Support unicode character paths on Windows. */ +#ifdef WIN32 + char filename_cstr[FILE_MAX]; + BLI_strncpy(filename_cstr, filename_, FILE_MAX); + + UTF16_ENCODE(filename_cstr); + std::wstring wstr(filename_cstr_16); + result = main_doc_.save_file(wstr.c_str()); + + UTF16_UN_ENCODE(filename_cstr); +#else + result = main_doc_.save_file(filename_); +#endif + + return result; +} + +/* Create document header and main svg node. */ +void GpencilExporterSVG::create_document_header() +{ + /* Add a custom document declaration node. */ + pugi::xml_node decl = main_doc_.prepend_child(pugi::node_declaration); + decl.append_attribute("version") = "1.0"; + decl.append_attribute("encoding") = "UTF-8"; + + pugi::xml_node comment = main_doc_.append_child(pugi::node_comment); + char txt[128]; + sprintf(txt, " Generator: Blender, %s - %s ", SVG_EXPORTER_NAME, SVG_EXPORTER_VERSION); + comment.set_value(txt); + + pugi::xml_node doctype = main_doc_.append_child(pugi::node_doctype); + doctype.set_value( + "svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\" " + "\"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\""); + + main_node_ = main_doc_.append_child("svg"); + main_node_.append_attribute("version").set_value("1.0"); + main_node_.append_attribute("x").set_value("0px"); + main_node_.append_attribute("y").set_value("0px"); + main_node_.append_attribute("xmlns").set_value("http://www.w3.org/2000/svg"); + + std::string width; + std::string height; + + width = std::to_string(render_x_); + height = std::to_string(render_y_); + + main_node_.append_attribute("width").set_value((width + "px").c_str()); + main_node_.append_attribute("height").set_value((height + "px").c_str()); + std::string viewbox = "0 0 " + width + " " + height; + main_node_.append_attribute("viewBox").set_value(viewbox.c_str()); +} + +/* Main layer loop. */ +void GpencilExporterSVG::export_gpencil_layers() +{ + const bool is_clipping = is_camera_mode() && (params_.flag & GP_EXPORT_CLIP_CAMERA) != 0; + + /* If is doing a set of frames, the list of objects can change for each frame. */ + create_object_list(); + + for (ObjectZ &obz : ob_list_) { + Object *ob = obz.ob; + + /* Camera clipping. */ + if (is_clipping) { + pugi::xml_node clip_node = main_node_.append_child("clipPath"); + clip_node.append_attribute("id").set_value(("clip-path" + std::to_string(cfra_)).c_str()); + + add_rect(clip_node, 0, 0, render_x_, render_y_, 0.0f, "#000000"); + } + + frame_node_ = main_node_.append_child("g"); + std::string frametxt = "blender_frame_" + std::to_string(cfra_); + frame_node_.append_attribute("id").set_value(frametxt.c_str()); + + /* Clip area. */ + if (is_clipping) { + frame_node_.append_attribute("clip-path") + .set_value(("url(#clip-path" + std::to_string(cfra_) + ")").c_str()); + } + + pugi::xml_node ob_node = frame_node_.append_child("g"); + + char obtxt[96]; + sprintf(obtxt, "blender_object_%s", ob->id.name + 2); + ob_node.append_attribute("id").set_value(obtxt); + + /* Use evaluated version to get strokes with modifiers. */ + Object *ob_eval_ = (Object *)DEG_get_evaluated_id(depsgraph_, &ob->id); + bGPdata *gpd_eval = (bGPdata *)ob_eval_->data; + + LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd_eval->layers) { + if (gpl->flag & GP_LAYER_HIDE) { + continue; + } + prepare_layer_export_matrix(ob, gpl); + + bGPDframe *gpf = gpl->actframe; + if ((gpf == nullptr) || (gpf->strokes.first == nullptr)) { + continue; + } + + /* Layer node. */ + std::string txt = "Layer: "; + txt.append(gpl->info); + ob_node.append_child(pugi::node_comment).set_value(txt.c_str()); + + pugi::xml_node node_gpl = ob_node.append_child("g"); + node_gpl.append_attribute("id").set_value(gpl->info); + + LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) { + if (gps->totpoints < 2) { + continue; + } + if (!ED_gpencil_stroke_material_visible(ob, gps)) { + continue; + } + + /* Duplicate the stroke to apply any layer thickness change. */ + bGPDstroke *gps_duplicate = BKE_gpencil_stroke_duplicate(gps, true, false); + + MaterialGPencilStyle *gp_style = BKE_gpencil_material_settings(ob, + gps_duplicate->mat_nr + 1); + + const bool is_stroke = ((gp_style->flag & GP_MATERIAL_STROKE_SHOW) && + (gp_style->stroke_rgba[3] > GPENCIL_ALPHA_OPACITY_THRESH)); + const bool is_fill = ((gp_style->flag & GP_MATERIAL_FILL_SHOW) && + (gp_style->fill_rgba[3] > GPENCIL_ALPHA_OPACITY_THRESH)); + + prepare_stroke_export_colors(ob, gps_duplicate); + + /* Apply layer thickness change. */ + gps_duplicate->thickness += gpl->line_change; + /* Apply object scale to thickness. */ + gps_duplicate->thickness *= mat4_to_scale(ob->obmat); + CLAMP_MIN(gps_duplicate->thickness, 1.0f); + + const bool is_normalized = ((params_.flag & GP_EXPORT_NORM_THICKNESS) != 0) || + BKE_gpencil_stroke_is_pressure_constant(gps); + + /* Fill. */ + if ((is_fill) && (params_.flag & GP_EXPORT_FILL)) { + /* Fill is always exported as polygon because the stroke of the fill is done + * in a different SVG command. */ + export_stroke_to_polyline(gpl, gps_duplicate, node_gpl, is_stroke, true); + } + + /* Stroke. */ + if (is_stroke) { + if (is_normalized) { + export_stroke_to_polyline(gpl, gps_duplicate, node_gpl, is_stroke, false); + } + else { + bGPDstroke *gps_perimeter = BKE_gpencil_stroke_perimeter_from_view( + rv3d_, gpd_, gpl, gps_duplicate, 3, diff_mat_.values); + + /* Sample stroke. */ + if (params_.stroke_sample > 0.0f) { + BKE_gpencil_stroke_sample(gpd_eval, gps_perimeter, params_.stroke_sample, false); + } + + export_stroke_to_path(gpl, gps_perimeter, node_gpl, false); + + BKE_gpencil_free_stroke(gps_perimeter); + } + } + + BKE_gpencil_free_stroke(gps_duplicate); + } + } + } +} + +/** + * Export a stroke using SVG path + * \param node_gpl: Node of the layer. + * \param do_fill: True if the stroke is only fill + */ +void GpencilExporterSVG::export_stroke_to_path(bGPDlayer *gpl, + bGPDstroke *gps, + pugi::xml_node node_gpl, + const bool do_fill) +{ + pugi::xml_node node_gps = node_gpl.append_child("path"); + + float col[3]; + std::string stroke_hex; + if (do_fill) { + node_gps.append_attribute("fill-opacity").set_value(fill_color_[3] * gpl->opacity); + + interp_v3_v3v3(col, fill_color_, gpl->tintcolor, gpl->tintcolor[3]); + } + else { + node_gps.append_attribute("fill-opacity") + .set_value(stroke_color_[3] * stroke_average_opacity_get() * gpl->opacity); + + interp_v3_v3v3(col, stroke_color_, gpl->tintcolor, gpl->tintcolor[3]); + } + + linearrgb_to_srgb_v3_v3(col, col); + stroke_hex = rgb_to_hexstr(col); + + node_gps.append_attribute("fill").set_value(stroke_hex.c_str()); + node_gps.append_attribute("stroke").set_value("none"); + + std::string txt = "M"; + for (const int i : IndexRange(gps->totpoints)) { + if (i > 0) { + txt.append("L"); + } + bGPDspoint &pt = gps->points[i]; + const float2 screen_co = gpencil_3D_point_to_2D(&pt.x); + txt.append(std::to_string(screen_co.x) + "," + std::to_string(screen_co.y)); + } + /* Close patch (cyclic)*/ + if (gps->flag & GP_STROKE_CYCLIC) { + txt.append("z"); + } + + node_gps.append_attribute("d").set_value(txt.c_str()); +} + +/** + * Export a stroke using polyline or polygon + * \param node_gpl: Node of the layer. + * \param do_fill: True if the stroke is only fill + */ +void GpencilExporterSVG::export_stroke_to_polyline(bGPDlayer *gpl, + bGPDstroke *gps, + pugi::xml_node node_gpl, + const bool is_stroke, + const bool do_fill) +{ + const bool cyclic = ((gps->flag & GP_STROKE_CYCLIC) != 0); + const float avg_pressure = BKE_gpencil_stroke_average_pressure_get(gps); + + /* Get the thickness in pixels using a simple 1 point stroke. */ + bGPDstroke *gps_temp = BKE_gpencil_stroke_duplicate(gps, false, false); + gps_temp->totpoints = 1; + gps_temp->points = (bGPDspoint *)MEM_callocN(sizeof(bGPDspoint), "gp_stroke_points"); + bGPDspoint *pt_src = &gps->points[0]; + bGPDspoint *pt_dst = &gps_temp->points[0]; + copy_v3_v3(&pt_dst->x, &pt_src->x); + pt_dst->pressure = avg_pressure; + + const float radius = stroke_point_radius_get(gpl, gps_temp); + + BKE_gpencil_free_stroke(gps_temp); + + pugi::xml_node node_gps = node_gpl.append_child(do_fill || cyclic ? "polygon" : "polyline"); + + color_string_set(gpl, gps, node_gps, do_fill); + + if (is_stroke && !do_fill) { + node_gps.append_attribute("stroke-width").set_value((radius * 2.0f) - gpl->line_change); + } + + std::string txt; + for (const int i : IndexRange(gps->totpoints)) { + if (i > 0) { + txt.append(" "); + } + bGPDspoint *pt = &gps->points[i]; + const float2 screen_co = gpencil_3D_point_to_2D(&pt->x); + txt.append(std::to_string(screen_co.x) + "," + std::to_string(screen_co.y)); + } + + node_gps.append_attribute("points").set_value(txt.c_str()); +} + +/** + * Set color SVG string for stroke + * \param node_gps: Stroke node + * @param do_fill: True if the stroke is only fill + */ +void GpencilExporterSVG::color_string_set(bGPDlayer *gpl, + bGPDstroke *gps, + pugi::xml_node node_gps, + const bool do_fill) +{ + const bool round_cap = (gps->caps[0] == GP_STROKE_CAP_ROUND || + gps->caps[1] == GP_STROKE_CAP_ROUND); + + float col[3]; + if (do_fill) { + interp_v3_v3v3(col, fill_color_, gpl->tintcolor, gpl->tintcolor[3]); + linearrgb_to_srgb_v3_v3(col, col); + std::string stroke_hex = rgb_to_hexstr(col); + node_gps.append_attribute("fill").set_value(stroke_hex.c_str()); + node_gps.append_attribute("stroke").set_value("none"); + node_gps.append_attribute("fill-opacity").set_value(fill_color_[3] * gpl->opacity); + } + else { + interp_v3_v3v3(col, stroke_color_, gpl->tintcolor, gpl->tintcolor[3]); + linearrgb_to_srgb_v3_v3(col, col); + std::string stroke_hex = rgb_to_hexstr(col); + node_gps.append_attribute("stroke").set_value(stroke_hex.c_str()); + node_gps.append_attribute("stroke-opacity") + .set_value(stroke_color_[3] * stroke_average_opacity_get() * gpl->opacity); + + if (gps->totpoints > 1) { + node_gps.append_attribute("fill").set_value("none"); + node_gps.append_attribute("stroke-linecap").set_value(round_cap ? "round" : "square"); + } + else { + node_gps.append_attribute("fill").set_value(stroke_hex.c_str()); + node_gps.append_attribute("fill-opacity").set_value(fill_color_[3] * gpl->opacity); + } + } +} + +/** + * Create a SVG rectangle + * \param node: Parent node + * \param x: X location + * \param y: Y location + * \param width: width of the rectangle + * \param height: Height of the rectangle + * \param thickness: Thickness of the line + * \param hexcolor: Color of the line + */ +void GpencilExporterSVG::add_rect(pugi::xml_node node, + float x, + float y, + float width, + float height, + float thickness, + std::string hexcolor) +{ + pugi::xml_node rect_node = node.append_child("rect"); + rect_node.append_attribute("x").set_value(x); + rect_node.append_attribute("y").set_value(y); + rect_node.append_attribute("width").set_value(width); + rect_node.append_attribute("height").set_value(height); + rect_node.append_attribute("fill").set_value("none"); + if (thickness > 0.0f) { + rect_node.append_attribute("stroke").set_value(hexcolor.c_str()); + rect_node.append_attribute("stroke-width").set_value(thickness); + } +} + +/** + * Create SVG text + * \param node: Parent node + * \param x: X location + * \param y: Y location + * \param text: Text to include + * \param size: Size of the text + * \param hexcolor: Color of the text + */ +void GpencilExporterSVG::add_text(pugi::xml_node node, + float x, + float y, + std::string text, + const float size, + std::string hexcolor) +{ + pugi::xml_node nodetxt = node.append_child("text"); + + nodetxt.append_attribute("x").set_value(x); + nodetxt.append_attribute("y").set_value(y); + // nodetxt.append_attribute("font-family").set_value("'system-ui'"); + nodetxt.append_attribute("font-size").set_value(size); + nodetxt.append_attribute("fill").set_value(hexcolor.c_str()); + nodetxt.text().set(text.c_str()); +} + +/** Convert a color to Hex value (#FFFFFF). */ +std::string GpencilExporterSVG::rgb_to_hexstr(const float color[3]) +{ + uint8_t r = color[0] * 255.0f; + uint8_t g = color[1] * 255.0f; + uint8_t b = color[2] * 255.0f; + char hex_string[20]; + sprintf(hex_string, "#%02X%02X%02X", r, g, b); + + std::string hexstr = hex_string; + + return hexstr; +} + +} // namespace blender::io::gpencil diff --git a/source/blender/io/gpencil/intern/gpencil_io_export_svg.hh b/source/blender/io/gpencil/intern/gpencil_io_export_svg.hh new file mode 100644 index 00000000000..3bff31f20bf --- /dev/null +++ b/source/blender/io/gpencil/intern/gpencil_io_export_svg.hh @@ -0,0 +1,89 @@ +/* + * 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) 2020 Blender Foundation + * All rights reserved. + */ +#pragma once + +/** \file + * \ingroup bgpencil + */ +#include "BLI_path_util.h" + +#include "gpencil_io_export_base.hh" +#include "pugixml.hpp" + +struct GpencilIOParams; + +#define SVG_EXPORTER_NAME "SVG Export for Grease Pencil" +#define SVG_EXPORTER_VERSION "v1.0" + +namespace blender::io::gpencil { + +class GpencilExporterSVG : public GpencilExporter { + + public: + GpencilExporterSVG(const char *filename, const struct GpencilIOParams *iparams); + bool add_newpage(); + bool add_body(); + bool write(); + + protected: + static void add_rect(pugi::xml_node node, + float x, + float y, + float width, + float height, + float thickness, + std::string hexcolor); + + static void add_text(pugi::xml_node node, + float x, + float y, + std::string text, + const float size, + std::string hexcolor); + + private: + /* XML doc. */ + pugi::xml_document main_doc_; + /* Main document node. */ + pugi::xml_node main_node_; + /** Frame node */ + pugi::xml_node frame_node_; + void create_document_header(); + void export_gpencil_layers(); + + void export_stroke_to_path(struct bGPDlayer *gpl, + struct bGPDstroke *gps, + pugi::xml_node node_gpl, + const bool do_fill); + + void export_stroke_to_polyline(struct bGPDlayer *gpl, + struct bGPDstroke *gps, + pugi::xml_node node_gpl, + const bool is_stroke, + const bool do_fill); + + void color_string_set(struct bGPDlayer *gpl, + struct bGPDstroke *gps, + pugi::xml_node node_gps, + const bool do_fill); + + std::string rgb_to_hexstr(const float color[3]); +}; + +} // namespace blender::io::gpencil diff --git a/source/blender/io/gpencil/intern/gpencil_io_import_base.cc b/source/blender/io/gpencil/intern/gpencil_io_import_base.cc new file mode 100644 index 00000000000..d0b6e20bda2 --- /dev/null +++ b/source/blender/io/gpencil/intern/gpencil_io_import_base.cc @@ -0,0 +1,83 @@ + + +/* + * 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) 2020 Blender Foundation + * All rights reserved. + */ + +/** \file + * \ingroup bgpencil + */ +#include "BLI_math_vector.h" + +#include "DNA_material_types.h" +#include "DNA_object_types.h" +#include "DNA_scene_types.h" + +#include "BKE_gpencil.h" +#include "BKE_material.h" + +#include "ED_gpencil.h" + +#include "gpencil_io_import_base.hh" + +namespace blender::io::gpencil { + +/* Constructor. */ +GpencilImporter::GpencilImporter(const GpencilIOParams *iparams) : GpencilIO(iparams) +{ + /* Nothing to do yet */ +} + +Object *GpencilImporter::create_object() +{ + const float *cur = scene_->cursor.location; + ushort local_view_bits = (params_.v3d && params_.v3d->localvd) ? params_.v3d->local_view_uuid : + (ushort)0; + Object *ob_gpencil = ED_gpencil_add_object(params_.C, cur, local_view_bits); + + return ob_gpencil; +} + +int32_t GpencilImporter::create_material(const char *name, const bool stroke, const bool fill) +{ + const float default_stroke_color[4] = {0.0f, 0.0f, 0.0f, 1.0f}; + const float default_fill_color[4] = {0.5f, 0.5f, 0.5f, 1.0f}; + int32_t mat_index = BKE_gpencil_material_find_index_by_name_prefix(params_.ob, name); + /* Stroke and Fill material. */ + if (mat_index == -1) { + int32_t new_idx; + Material *mat_gp = BKE_gpencil_object_material_new(bmain_, params_.ob, name, &new_idx); + MaterialGPencilStyle *gp_style = mat_gp->gp_style; + gp_style->flag &= ~GP_MATERIAL_STROKE_SHOW; + gp_style->flag &= ~GP_MATERIAL_FILL_SHOW; + + copy_v4_v4(gp_style->stroke_rgba, default_stroke_color); + copy_v4_v4(gp_style->fill_rgba, default_fill_color); + if (stroke) { + gp_style->flag |= GP_MATERIAL_STROKE_SHOW; + } + if (fill) { + gp_style->flag |= GP_MATERIAL_FILL_SHOW; + } + mat_index = params_.ob->totcol - 1; + } + + return mat_index; +} + +} // namespace blender::io::gpencil diff --git a/source/blender/io/gpencil/intern/gpencil_io_import_base.hh b/source/blender/io/gpencil/intern/gpencil_io_import_base.hh new file mode 100644 index 00000000000..7d6fad2340b --- /dev/null +++ b/source/blender/io/gpencil/intern/gpencil_io_import_base.hh @@ -0,0 +1,41 @@ +/* + * 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) 2020 Blender Foundation + * All rights reserved. + */ +#pragma once + +/** \file + * \ingroup bgpencil + */ +#include "gpencil_io_base.hh" + +namespace blender::io::gpencil { + +class GpencilImporter : public GpencilIO { + + public: + GpencilImporter(const struct GpencilIOParams *iparams); + virtual bool read() = 0; + + protected: + struct Object *create_object(); + int32_t create_material(const char *name, const bool stroke, const bool fill); + + private: +}; + +} // namespace blender::io::gpencil diff --git a/source/blender/io/gpencil/intern/gpencil_io_import_svg.cc b/source/blender/io/gpencil/intern/gpencil_io_import_svg.cc new file mode 100644 index 00000000000..4894cfc1ada --- /dev/null +++ b/source/blender/io/gpencil/intern/gpencil_io_import_svg.cc @@ -0,0 +1,253 @@ +/* + * 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) 2020 Blender Foundation + * All rights reserved. + */ + +/** \file + * \ingroup bgpencil + */ + +#include "BLI_float3.hh" +#include "BLI_math.h" +#include "BLI_span.hh" + +#include "DNA_gpencil_types.h" + +#include "BKE_gpencil.h" +#include "BKE_gpencil_geom.h" + +#include "DEG_depsgraph.h" +#include "DEG_depsgraph_query.h" + +#include "ED_gpencil.h" + +#include "gpencil_io.h" +#include "gpencil_io_import_svg.hh" + +/* Custom flags for NanoSVG. */ +#define NANOSVG_ALL_COLOR_KEYWORDS +#define NANOSVG_IMPLEMENTATION + +#include "nanosvg/nanosvg.h" + +using blender::MutableSpan; + +namespace blender::io::gpencil { + +/* Constructor. */ +GpencilImporterSVG::GpencilImporterSVG(const char *filename, const GpencilIOParams *iparams) + : GpencilImporter(iparams) +{ + filename_set(filename); +} + +bool GpencilImporterSVG::read() +{ + bool result = true; + NSVGimage *svg_data = nullptr; + svg_data = nsvgParseFromFile(filename_, "mm", 96.0f); + if (svg_data == nullptr) { + std::cout << " Could not open SVG.\n "; + return false; + } + + /* Create grease pencil object. */ + params_.ob = create_object(); + if (params_.ob == nullptr) { + std::cout << "Unable to create new object.\n"; + if (svg_data) { + nsvgDelete(svg_data); + } + + return false; + } + gpd_ = (bGPdata *)params_.ob->data; + + /* Grease pencil is rotated 90 degrees in X axis by default. */ + float matrix[4][4]; + const float3 scale = float3(params_.scale); + unit_m4(matrix); + rotate_m4(matrix, 'X', DEG2RADF(-90.0f)); + rescale_m4(matrix, scale); + + /* Loop all shapes. */ + char prv_id[70] = {"*"}; + int prefix = 0; + for (NSVGshape *shape = svg_data->shapes; shape; shape = shape->next) { + char *layer_id = (shape->id_parent[0] == '\0') ? BLI_sprintfN("Layer_%03d", prefix) : + BLI_sprintfN("%s", shape->id_parent); + if (!STREQ(prv_id, layer_id)) { + prefix++; + MEM_freeN(layer_id); + layer_id = (shape->id_parent[0] == '\0') ? BLI_sprintfN("Layer_%03d", prefix) : + BLI_sprintfN("%s", shape->id_parent); + strcpy(prv_id, layer_id); + } + + /* Check if the layer exist and create if needed. */ + bGPDlayer *gpl = (bGPDlayer *)BLI_findstring( + &gpd_->layers, layer_id, offsetof(bGPDlayer, info)); + if (gpl == nullptr) { + gpl = BKE_gpencil_layer_addnew(gpd_, layer_id, true); + /* Disable lights. */ + gpl->flag &= ~GP_LAYER_USE_LIGHTS; + } + MEM_freeN(layer_id); + + /* Check frame. */ + bGPDframe *gpf = BKE_gpencil_layer_frame_get(gpl, cfra_, GP_GETFRAME_ADD_NEW); + /* Create materials. */ + bool is_stroke = (bool)shape->stroke.type; + bool is_fill = (bool)shape->fill.type; + if ((!is_stroke) && (!is_fill)) { + is_stroke = true; + } + + /* Create_shape materials. */ + const char *const mat_names[] = {"Stroke", "Fill"}; + int index = 0; + if ((is_stroke) && (is_fill)) { + index = 0; + is_fill = false; + } + else if ((!is_stroke) && (is_fill)) { + index = 1; + } + int32_t mat_index = create_material(mat_names[index], is_stroke, is_fill); + + /* Loop all paths to create the stroke data. */ + for (NSVGpath *path = shape->paths; path; path = path->next) { + create_stroke(gpd_, gpf, shape, path, mat_index, matrix); + } + } + + /* Free SVG memory. */ + nsvgDelete(svg_data); + + /* Calculate bounding box and move all points to new origin center. */ + float gp_center[3]; + BKE_gpencil_centroid_3d(gpd_, gp_center); + + LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd_->layers) { + LISTBASE_FOREACH (bGPDframe *, gpf, &gpl->frames) { + LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) { + for (bGPDspoint &pt : MutableSpan(gps->points, gps->totpoints)) { + sub_v3_v3(&pt.x, gp_center); + } + } + } + } + + return result; +} + +void GpencilImporterSVG::create_stroke(bGPdata *gpd, + bGPDframe *gpf, + NSVGshape *shape, + NSVGpath *path, + const int32_t mat_index, + const float matrix[4][4]) +{ + const bool is_stroke = (bool)shape->stroke.type; + const bool is_fill = (bool)shape->fill.type; + + const int edges = params_.resolution; + const float step = 1.0f / (float)(edges - 1); + + const int totpoints = (path->npts / 3) * params_.resolution; + + bGPDstroke *gps = BKE_gpencil_stroke_new(mat_index, totpoints, 1.0f); + BLI_addtail(&gpf->strokes, gps); + + if (path->closed == '1') { + gps->flag |= GP_STROKE_CYCLIC; + } + if (is_stroke) { + gps->thickness = shape->strokeWidth * params_.scale; + } + /* Apply Fill vertex color. */ + if (is_fill) { + NSVGpaint fill = shape->fill; + convert_color(fill.color, gps->vert_color_fill); + gps->fill_opacity_fac = gps->vert_color_fill[3]; + gps->vert_color_fill[3] = 1.0f; + } + + int start_index = 0; + for (int i = 0; i < path->npts - 1; i += 3) { + float *p = &path->pts[i * 2]; + float a = 0.0f; + for (int v = 0; v < edges; v++) { + bGPDspoint *pt = &gps->points[start_index]; + pt->strength = shape->opacity; + pt->pressure = 1.0f; + pt->z = 0.0f; + /* TODO(antoniov): Can be improved loading curve data instead of loading strokes. */ + interp_v2_v2v2v2v2_cubic(&pt->x, &p[0], &p[2], &p[4], &p[6], a); + + /* Scale from millimeters. */ + mul_v3_fl(&pt->x, 0.001f); + mul_m4_v3(matrix, &pt->x); + + /* Apply color to vertex color. */ + if (is_fill) { + NSVGpaint fill = shape->fill; + convert_color(fill.color, pt->vert_color); + } + if (is_stroke) { + NSVGpaint stroke = shape->stroke; + convert_color(stroke.color, pt->vert_color); + gps->fill_opacity_fac = pt->vert_color[3]; + } + pt->vert_color[3] = 1.0f; + + a += step; + start_index++; + } + } + + /* Cleanup and recalculate geometry. */ + BKE_gpencil_stroke_merge_distance(gpd, gpf, gps, 0.001f, true); + BKE_gpencil_stroke_geometry_update(gpd, gps); +} + +/* Unpack internal NanoSVG color. */ +static void unpack_nano_color(const unsigned int pack, float r_col[4]) +{ + unsigned char rgb_u[4]; + + rgb_u[0] = ((pack) >> 0) & 0xFF; + rgb_u[1] = ((pack) >> 8) & 0xFF; + rgb_u[2] = ((pack) >> 16) & 0xFF; + rgb_u[3] = ((pack) >> 24) & 0xFF; + + r_col[0] = (float)rgb_u[0] / 255.0f; + r_col[1] = (float)rgb_u[1] / 255.0f; + r_col[2] = (float)rgb_u[2] / 255.0f; + r_col[3] = (float)rgb_u[3] / 255.0f; +} + +void GpencilImporterSVG::convert_color(const int32_t color, float r_linear_rgba[4]) +{ + float rgba[4]; + unpack_nano_color(color, rgba); + + srgb_to_linearrgb_v3_v3(r_linear_rgba, rgba); + r_linear_rgba[3] = rgba[3]; +} + +} // namespace blender::io::gpencil diff --git a/source/blender/io/gpencil/intern/gpencil_io_import_svg.hh b/source/blender/io/gpencil/intern/gpencil_io_import_svg.hh new file mode 100644 index 00000000000..0e9271dd2c6 --- /dev/null +++ b/source/blender/io/gpencil/intern/gpencil_io_import_svg.hh @@ -0,0 +1,56 @@ +/* + * 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) 2020 Blender Foundation + * All rights reserved. + */ +#pragma once + +/** \file + * \ingroup bgpencil + */ +#include "gpencil_io_import_base.hh" + +struct GpencilIOParams; +struct NSVGshape; +struct NSVGpath; +struct bGPdata; +struct bGPDframe; + +#define SVG_IMPORTER_NAME "SVG Import for Grease Pencil" +#define SVG_IMPORTER_VERSION "v1.0" + +namespace blender::io::gpencil { + +class GpencilImporterSVG : public GpencilImporter { + + public: + GpencilImporterSVG(const char *filename, const struct GpencilIOParams *iparams); + + bool read(); + + protected: + private: + void create_stroke(struct bGPdata *gpd_, + struct bGPDframe *gpf, + struct NSVGshape *shape, + struct NSVGpath *path, + const int32_t mat_index, + const float matrix[4][4]); + + void convert_color(const int32_t color, float r_linear_rgba[4]); +}; + +} // namespace blender::io::gpencil diff --git a/source/blender/io/gpencil/nanosvg/nanosvg.h b/source/blender/io/gpencil/nanosvg/nanosvg.h new file mode 100644 index 00000000000..6db32e9f40a --- /dev/null +++ b/source/blender/io/gpencil/nanosvg/nanosvg.h @@ -0,0 +1,3313 @@ +/* + * Copyright (c) 2013-14 `Mikko Mononen <memon@inside.org>` + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source distribution. + * + * The SVG parser is based on Anti-Grain Geometry 2.4 SVG example + * Copyright (C) 2002-2004 Maxim Shemanarev (McSeem) (http://www.antigrain.com/) + * + * Arc calculation code based on canvg (https://code.google.com/p/canvg/) + * + * Bounding box calculation based on + * http://blog.hackers-cafe.net/2009/06/how-to-calculate-bezier-curves-bounding.html + * + * This is a modified version for Blender used by importers. + * + */ + +#ifndef NANOSVG_H +#define NANOSVG_H + +#ifndef NANOSVG_CPLUSPLUS +# ifdef __cplusplus +extern "C" { +# endif +#endif + +// NanoSVG is a simple stupid single-header-file SVG parse. The output of the parser is a list of +// cubic bezier shapes. +// +// The library suits well for anything from rendering scalable icons in your editor application to +// prototyping a game. +// +// NanoSVG supports a wide range of SVG features, but something may be missing, feel free to create +// a pull request! +// +// The shapes in the SVG images are transformed by the viewBox and converted to specified units. +// That is, you should get the same looking data as your designed in your favorite app. +// +// NanoSVG can return the paths in few different units. For example if you want to render an image, +// you may choose to get the paths in pixels, or if you are feeding the data into a CNC-cutter, you +// may want to use millimeters. +// +// The units passed to NanoSVG should be one of: 'px', 'pt', 'pc' 'mm', 'cm', or 'in'. +// DPI (dots-per-inch) controls how the unit conversion is done. +// +// If you don't know or care about the units stuff, "px" and 96 should get you going. + +/* Example Usage: + // Load SVG + NSVGimage* image; + image = nsvgParseFromFile("test.svg", "px", 96); + printf("size: %f x %f\n", image->width, image->height); + // Use... + for (NSVGshape *shape = image->shapes; shape != NULL; shape = shape->next) { + for (NSVGpath *path = shape->paths; path != NULL; path = path->next) { + for (int i = 0; i < path->npts-1; i += 3) { + float* p = &path->pts[i*2]; + drawCubicBez(p[0],p[1], p[2],p[3], p[4],p[5], p[6],p[7]); + } + } + } + // Delete + nsvgDelete(image); +*/ + +enum NSVGpaintType { + NSVG_PAINT_NONE = 0, + NSVG_PAINT_COLOR = 1, + NSVG_PAINT_LINEAR_GRADIENT = 2, + NSVG_PAINT_RADIAL_GRADIENT = 3 +}; + +enum NSVGspreadType { NSVG_SPREAD_PAD = 0, NSVG_SPREAD_REFLECT = 1, NSVG_SPREAD_REPEAT = 2 }; + +enum NSVGlineJoin { NSVG_JOIN_MITER = 0, NSVG_JOIN_ROUND = 1, NSVG_JOIN_BEVEL = 2 }; + +enum NSVGlineCap { NSVG_CAP_BUTT = 0, NSVG_CAP_ROUND = 1, NSVG_CAP_SQUARE = 2 }; + +enum NSVGfillRule { NSVG_FILLRULE_NONZERO = 0, NSVG_FILLRULE_EVENODD = 1 }; + +enum NSVGflags { NSVG_FLAGS_VISIBLE = 0x01 }; + +typedef struct NSVGgradientStop { + unsigned int color; + float offset; +} NSVGgradientStop; + +typedef struct NSVGgradient { + float xform[6]; + char spread; + float fx, fy; + int nstops; + NSVGgradientStop stops[1]; +} NSVGgradient; + +typedef struct NSVGpaint { + char type; + union { + unsigned int color; + NSVGgradient *gradient; + }; +} NSVGpaint; + +typedef struct NSVGpath { + float *pts; // Cubic bezier points: x0,y0, [cpx1,cpx1,cpx2,cpy2,x1,y1], ... + int npts; // Total number of bezier points. + char closed; // Flag indicating if shapes should be treated as closed. + float bounds[4]; // Tight bounding box of the shape [minx,miny,maxx,maxy]. + struct NSVGpath *next; // Pointer to next path, or NULL if last element. +} NSVGpath; + +typedef struct NSVGshape { + char id[64]; // Optional 'id' attr of the shape or its group + /* Blender: Parent ID used for layer creation. */ + char id_parent[64]; + NSVGpaint fill; // Fill paint + NSVGpaint stroke; // Stroke paint + float opacity; // Opacity of the shape. + float strokeWidth; // Stroke width (scaled). + float strokeDashOffset; // Stroke dash offset (scaled). + float strokeDashArray[8]; // Stroke dash array (scaled). + char strokeDashCount; // Number of dash values in dash array. + char strokeLineJoin; // Stroke join type. + char strokeLineCap; // Stroke cap type. + float miterLimit; // Miter limit + char fillRule; // Fill rule, see NSVGfillRule. + unsigned char flags; // Logical or of NSVG_FLAGS_* flags + float bounds[4]; // Tight bounding box of the shape [minx,miny,maxx,maxy]. + NSVGpath *paths; // Linked list of paths in the image. + struct NSVGshape *next; // Pointer to next shape, or NULL if last element. +} NSVGshape; + +typedef struct NSVGimage { + float width; // Width of the image. + float height; // Height of the image. + NSVGshape *shapes; // Linked list of shapes in the image. +} NSVGimage; + +// Parses SVG file from a file, returns SVG image as paths. +NSVGimage *nsvgParseFromFile(const char *filename, const char *units, float dpi); + +// Parses SVG file from a null terminated string, returns SVG image as paths. +// Important note: changes the string. +NSVGimage *nsvgParse(char *input, const char *units, float dpi); + +// Duplicates a path. +NSVGpath *nsvgDuplicatePath(NSVGpath *p); + +// Deletes an image. +void nsvgDelete(NSVGimage *image); + +#ifndef NANOSVG_CPLUSPLUS +# ifdef __cplusplus +} +# endif +#endif + +#endif // NANOSVG_H + +#ifdef NANOSVG_IMPLEMENTATION + +#include <math.h> +#include <stdlib.h> +#include <string.h> + +#define NSVG_PI (3.14159265358979323846264338327f) +#define NSVG_KAPPA90 \ + (0.5522847493f) // Length proportional to radius of a cubic bezier handle for 90deg arcs. + +#define NSVG_ALIGN_MIN 0 +#define NSVG_ALIGN_MID 1 +#define NSVG_ALIGN_MAX 2 +#define NSVG_ALIGN_NONE 0 +#define NSVG_ALIGN_MEET 1 +#define NSVG_ALIGN_SLICE 2 + +#define NSVG_NOTUSED(v) \ + do { \ + (void)(1 ? (void)0 : ((void)(v))); \ + } while (0) +#define NSVG_RGB(r, g, b) (((unsigned int)r) | ((unsigned int)g << 8) | ((unsigned int)b << 16)) + +#ifdef _MSC_VER +# pragma warning(disable : 4996) // Switch off security warnings +# pragma warning(disable : 4100) // Switch off unreferenced formal parameter warnings +# ifdef __cplusplus +# define NSVG_INLINE inline +# else +# define NSVG_INLINE +# endif +#else +# define NSVG_INLINE inline +#endif + +static int nsvg__isspace(char c) +{ + return strchr(" \t\n\v\f\r", c) != 0; +} + +static int nsvg__isdigit(char c) +{ + return c >= '0' && c <= '9'; +} + +static NSVG_INLINE float nsvg__minf(float a, float b) +{ + return a < b ? a : b; +} +static NSVG_INLINE float nsvg__maxf(float a, float b) +{ + return a > b ? a : b; +} + +// Simple XML parser + +#define NSVG_XML_TAG 1 +#define NSVG_XML_CONTENT 2 +#define NSVG_XML_MAX_ATTRIBS 256 + +static void nsvg__parseContent(char *s, void (*contentCb)(void *ud, const char *s), void *ud) +{ + // Trim start white spaces + while (*s && nsvg__isspace(*s)) + s++; + if (!*s) + return; + + if (contentCb) + (*contentCb)(ud, s); +} + +static void nsvg__parseElement(char *s, + void (*startelCb)(void *ud, const char *el, const char **attr), + void (*endelCb)(void *ud, const char *el), + void *ud) +{ + const char *attr[NSVG_XML_MAX_ATTRIBS]; + int nattr = 0; + char *name; + int start = 0; + int end = 0; + char quote; + + // Skip white space after the '<' + while (*s && nsvg__isspace(*s)) + s++; + + // Check if the tag is end tag + if (*s == '/') { + s++; + end = 1; + } + else { + start = 1; + } + + // Skip comments, data and preprocessor stuff. + if (!*s || *s == '?' || *s == '!') + return; + + // Get tag name + name = s; + while (*s && !nsvg__isspace(*s)) + s++; + if (*s) { + *s++ = '\0'; + } + + // Get attribs + while (!end && *s && nattr < NSVG_XML_MAX_ATTRIBS - 3) { + char *name = NULL; + char *value = NULL; + + // Skip white space before the attrib name + while (*s && nsvg__isspace(*s)) + s++; + if (!*s) + break; + if (*s == '/') { + end = 1; + break; + } + name = s; + // Find end of the attrib name. + while (*s && !nsvg__isspace(*s) && *s != '=') + s++; + if (*s) { + *s++ = '\0'; + } + // Skip until the beginning of the value. + while (*s && *s != '\"' && *s != '\'') + s++; + if (!*s) + break; + quote = *s; + s++; + // Store value and find the end of it. + value = s; + while (*s && *s != quote) + s++; + if (*s) { + *s++ = '\0'; + } + + // Store only well formed attributes + if (name && value) { + attr[nattr++] = name; + attr[nattr++] = value; + } + } + + // List terminator + attr[nattr++] = 0; + attr[nattr++] = 0; + + // Call callbacks. + if (start && startelCb) + (*startelCb)(ud, name, attr); + if (end && endelCb) + (*endelCb)(ud, name); +} + +static int nsvg__parseXML(char *input, + void (*startelCb)(void *ud, const char *el, const char **attr), + void (*endelCb)(void *ud, const char *el), + void (*contentCb)(void *ud, const char *s), + void *ud) +{ + char *s = input; + char *mark = s; + int state = NSVG_XML_CONTENT; + while (*s) { + if (*s == '<' && state == NSVG_XML_CONTENT) { + // Start of a tag + *s++ = '\0'; + nsvg__parseContent(mark, contentCb, ud); + mark = s; + state = NSVG_XML_TAG; + } + else if (*s == '>' && state == NSVG_XML_TAG) { + // Start of a content or new tag. + *s++ = '\0'; + nsvg__parseElement(mark, startelCb, endelCb, ud); + mark = s; + state = NSVG_XML_CONTENT; + } + else { + s++; + } + } + + return 1; +} + +/* Simple SVG parser. */ + +#define NSVG_MAX_ATTR 128 +#define NSVG_MAX_BREADCRUMB 5 + +enum NSVGgradientUnits { NSVG_USER_SPACE = 0, NSVG_OBJECT_SPACE = 1 }; + +#define NSVG_MAX_DASHES 8 + +enum NSVGunits { + NSVG_UNITS_USER, + NSVG_UNITS_PX, + NSVG_UNITS_PT, + NSVG_UNITS_PC, + NSVG_UNITS_MM, + NSVG_UNITS_CM, + NSVG_UNITS_IN, + NSVG_UNITS_PERCENT, + NSVG_UNITS_EM, + NSVG_UNITS_EX +}; + +typedef struct NSVGcoordinate { + float value; + int units; +} NSVGcoordinate; + +typedef struct NSVGlinearData { + NSVGcoordinate x1, y1, x2, y2; +} NSVGlinearData; + +typedef struct NSVGradialData { + NSVGcoordinate cx, cy, r, fx, fy; +} NSVGradialData; + +typedef struct NSVGgradientData { + char id[64]; + char ref[64]; + char type; + union { + NSVGlinearData linear; + NSVGradialData radial; + }; + char spread; + char units; + float xform[6]; + int nstops; + NSVGgradientStop *stops; + struct NSVGgradientData *next; +} NSVGgradientData; + +typedef struct NSVGattrib { + char id[64]; + float xform[6]; + unsigned int fillColor; + unsigned int strokeColor; + float opacity; + float fillOpacity; + float strokeOpacity; + char fillGradient[64]; + char strokeGradient[64]; + float strokeWidth; + float strokeDashOffset; + float strokeDashArray[NSVG_MAX_DASHES]; + int strokeDashCount; + char strokeLineJoin; + char strokeLineCap; + float miterLimit; + char fillRule; + float fontSize; + unsigned int stopColor; + float stopOpacity; + float stopOffset; + char hasFill; + char hasStroke; + char visible; +} NSVGattrib; + +typedef struct NSVGparser { + NSVGattrib attr[NSVG_MAX_ATTR]; + int attrHead; + float *pts; + int npts; + int cpts; + NSVGpath *plist; + NSVGimage *image; + NSVGgradientData *gradients; + NSVGshape *shapesTail; + float viewMinx, viewMiny, viewWidth, viewHeight; + int alignX, alignY, alignType; + float dpi; + char pathFlag; + char defsFlag; + /** Blender breadcrumb for layers. */ + char breadcrumb[NSVG_MAX_BREADCRUMB][64]; + /** Blender number of elements in breadcrumb. */ + int breadcrumb_len; +} NSVGparser; + +static void nsvg__xformIdentity(float *t) +{ + t[0] = 1.0f; + t[1] = 0.0f; + t[2] = 0.0f; + t[3] = 1.0f; + t[4] = 0.0f; + t[5] = 0.0f; +} + +static void nsvg__xformSetTranslation(float *t, float tx, float ty) +{ + t[0] = 1.0f; + t[1] = 0.0f; + t[2] = 0.0f; + t[3] = 1.0f; + t[4] = tx; + t[5] = ty; +} + +static void nsvg__xformSetScale(float *t, float sx, float sy) +{ + t[0] = sx; + t[1] = 0.0f; + t[2] = 0.0f; + t[3] = sy; + t[4] = 0.0f; + t[5] = 0.0f; +} + +static void nsvg__xformSetSkewX(float *t, float a) +{ + t[0] = 1.0f; + t[1] = 0.0f; + t[2] = tanf(a); + t[3] = 1.0f; + t[4] = 0.0f; + t[5] = 0.0f; +} + +static void nsvg__xformSetSkewY(float *t, float a) +{ + t[0] = 1.0f; + t[1] = tanf(a); + t[2] = 0.0f; + t[3] = 1.0f; + t[4] = 0.0f; + t[5] = 0.0f; +} + +static void nsvg__xformSetRotation(float *t, float a) +{ + float cs = cosf(a), sn = sinf(a); + t[0] = cs; + t[1] = sn; + t[2] = -sn; + t[3] = cs; + t[4] = 0.0f; + t[5] = 0.0f; +} + +static void nsvg__xformMultiply(float *t, float *s) +{ + float t0 = t[0] * s[0] + t[1] * s[2]; + float t2 = t[2] * s[0] + t[3] * s[2]; + float t4 = t[4] * s[0] + t[5] * s[2] + s[4]; + t[1] = t[0] * s[1] + t[1] * s[3]; + t[3] = t[2] * s[1] + t[3] * s[3]; + t[5] = t[4] * s[1] + t[5] * s[3] + s[5]; + t[0] = t0; + t[2] = t2; + t[4] = t4; +} + +static void nsvg__xformInverse(float *inv, float *t) +{ + double invdet, det = (double)t[0] * t[3] - (double)t[2] * t[1]; + if (det > -1e-6 && det < 1e-6) { + nsvg__xformIdentity(t); + return; + } + invdet = 1.0 / det; + inv[0] = (float)(t[3] * invdet); + inv[2] = (float)(-t[2] * invdet); + inv[4] = (float)(((double)t[2] * t[5] - (double)t[3] * t[4]) * invdet); + inv[1] = (float)(-t[1] * invdet); + inv[3] = (float)(t[0] * invdet); + inv[5] = (float)(((double)t[1] * t[4] - (double)t[0] * t[5]) * invdet); +} + +static void nsvg__xformPremultiply(float *t, float *s) +{ + float s2[6]; + memcpy(s2, s, sizeof(float) * 6); + nsvg__xformMultiply(s2, t); + memcpy(t, s2, sizeof(float) * 6); +} + +static void nsvg__xformPoint(float *dx, float *dy, float x, float y, float *t) +{ + *dx = x * t[0] + y * t[2] + t[4]; + *dy = x * t[1] + y * t[3] + t[5]; +} + +static void nsvg__xformVec(float *dx, float *dy, float x, float y, float *t) +{ + *dx = x * t[0] + y * t[2]; + *dy = x * t[1] + y * t[3]; +} + +#define NSVG_EPSILON (1e-12) + +static int nsvg__ptInBounds(float *pt, float *bounds) +{ + return pt[0] >= bounds[0] && pt[0] <= bounds[2] && pt[1] >= bounds[1] && pt[1] <= bounds[3]; +} + +static double nsvg__evalBezier(double t, double p0, double p1, double p2, double p3) +{ + double it = 1.0 - t; + return it * it * it * p0 + 3.0 * it * it * t * p1 + 3.0 * it * t * t * p2 + t * t * t * p3; +} + +static void nsvg__curveBounds(float *bounds, float *curve) +{ + int i, j, count; + double roots[2], a, b, c, b2ac, t, v; + float *v0 = &curve[0]; + float *v1 = &curve[2]; + float *v2 = &curve[4]; + float *v3 = &curve[6]; + + // Start the bounding box by end points + bounds[0] = nsvg__minf(v0[0], v3[0]); + bounds[1] = nsvg__minf(v0[1], v3[1]); + bounds[2] = nsvg__maxf(v0[0], v3[0]); + bounds[3] = nsvg__maxf(v0[1], v3[1]); + + // Bezier curve fits inside the convex hull of it's control points. + // If control points are inside the bounds, we're done. + if (nsvg__ptInBounds(v1, bounds) && nsvg__ptInBounds(v2, bounds)) + return; + + // Add bezier curve inflection points in X and Y. + for (i = 0; i < 2; i++) { + a = -3.0 * v0[i] + 9.0 * v1[i] - 9.0 * v2[i] + 3.0 * v3[i]; + b = 6.0 * v0[i] - 12.0 * v1[i] + 6.0 * v2[i]; + c = 3.0 * v1[i] - 3.0 * v0[i]; + count = 0; + if (fabs(a) < NSVG_EPSILON) { + if (fabs(b) > NSVG_EPSILON) { + t = -c / b; + if (t > NSVG_EPSILON && t < 1.0 - NSVG_EPSILON) + roots[count++] = t; + } + } + else { + b2ac = b * b - 4.0 * c * a; + if (b2ac > NSVG_EPSILON) { + t = (-b + sqrt(b2ac)) / (2.0 * a); + if (t > NSVG_EPSILON && t < 1.0 - NSVG_EPSILON) + roots[count++] = t; + t = (-b - sqrt(b2ac)) / (2.0 * a); + if (t > NSVG_EPSILON && t < 1.0 - NSVG_EPSILON) + roots[count++] = t; + } + } + for (j = 0; j < count; j++) { + v = nsvg__evalBezier(roots[j], v0[i], v1[i], v2[i], v3[i]); + bounds[0 + i] = nsvg__minf(bounds[0 + i], (float)v); + bounds[2 + i] = nsvg__maxf(bounds[2 + i], (float)v); + } + } +} + +static NSVGparser *nsvg__createParser() +{ + NSVGparser *p; + p = (NSVGparser *)malloc(sizeof(NSVGparser)); + if (p == NULL) + goto error; + memset(p, 0, sizeof(NSVGparser)); + + p->image = (NSVGimage *)malloc(sizeof(NSVGimage)); + if (p->image == NULL) + goto error; + memset(p->image, 0, sizeof(NSVGimage)); + + // Init style + nsvg__xformIdentity(p->attr[0].xform); + memset(p->attr[0].id, 0, sizeof p->attr[0].id); + p->attr[0].fillColor = NSVG_RGB(0, 0, 0); + p->attr[0].strokeColor = NSVG_RGB(0, 0, 0); + p->attr[0].opacity = 1; + p->attr[0].fillOpacity = 1; + p->attr[0].strokeOpacity = 1; + p->attr[0].stopOpacity = 1; + p->attr[0].strokeWidth = 1; + p->attr[0].strokeLineJoin = NSVG_JOIN_MITER; + p->attr[0].strokeLineCap = NSVG_CAP_BUTT; + p->attr[0].miterLimit = 4; + p->attr[0].fillRule = NSVG_FILLRULE_NONZERO; + p->attr[0].hasFill = 1; + p->attr[0].visible = 1; + + return p; + +error: + if (p) { + if (p->image) + free(p->image); + free(p); + } + return NULL; +} + +static void nsvg__deletePaths(NSVGpath *path) +{ + while (path) { + NSVGpath *next = path->next; + if (path->pts != NULL) + free(path->pts); + free(path); + path = next; + } +} + +static void nsvg__deletePaint(NSVGpaint *paint) +{ + if (paint->type == NSVG_PAINT_LINEAR_GRADIENT || paint->type == NSVG_PAINT_RADIAL_GRADIENT) + free(paint->gradient); +} + +static void nsvg__deleteGradientData(NSVGgradientData *grad) +{ + NSVGgradientData *next; + while (grad != NULL) { + next = grad->next; + free(grad->stops); + free(grad); + grad = next; + } +} + +static void nsvg__deleteParser(NSVGparser *p) +{ + if (p != NULL) { + nsvg__deletePaths(p->plist); + nsvg__deleteGradientData(p->gradients); + nsvgDelete(p->image); + free(p->pts); + free(p); + } +} + +static void nsvg__resetPath(NSVGparser *p) +{ + p->npts = 0; +} + +static void nsvg__addPoint(NSVGparser *p, float x, float y) +{ + if (p->npts + 1 > p->cpts) { + p->cpts = p->cpts ? p->cpts * 2 : 8; + p->pts = (float *)realloc(p->pts, p->cpts * 2 * sizeof(float)); + if (!p->pts) + return; + } + p->pts[p->npts * 2 + 0] = x; + p->pts[p->npts * 2 + 1] = y; + p->npts++; +} + +static void nsvg__moveTo(NSVGparser *p, float x, float y) +{ + if (p->npts > 0) { + p->pts[(p->npts - 1) * 2 + 0] = x; + p->pts[(p->npts - 1) * 2 + 1] = y; + } + else { + nsvg__addPoint(p, x, y); + } +} + +static void nsvg__lineTo(NSVGparser *p, float x, float y) +{ + float px, py, dx, dy; + if (p->npts > 0) { + px = p->pts[(p->npts - 1) * 2 + 0]; + py = p->pts[(p->npts - 1) * 2 + 1]; + dx = x - px; + dy = y - py; + nsvg__addPoint(p, px + dx / 3.0f, py + dy / 3.0f); + nsvg__addPoint(p, x - dx / 3.0f, y - dy / 3.0f); + nsvg__addPoint(p, x, y); + } +} + +static void nsvg__cubicBezTo( + NSVGparser *p, float cpx1, float cpy1, float cpx2, float cpy2, float x, float y) +{ + if (p->npts > 0) { + nsvg__addPoint(p, cpx1, cpy1); + nsvg__addPoint(p, cpx2, cpy2); + nsvg__addPoint(p, x, y); + } +} + +static NSVGattrib *nsvg__getAttr(NSVGparser *p) +{ + return &p->attr[p->attrHead]; +} + +static void nsvg__pushAttr(NSVGparser *p) +{ + if (p->attrHead < NSVG_MAX_ATTR - 1) { + p->attrHead++; + memcpy(&p->attr[p->attrHead], &p->attr[p->attrHead - 1], sizeof(NSVGattrib)); + } +} + +static void nsvg__popAttr(NSVGparser *p) +{ + if (p->attrHead > 0) + p->attrHead--; +} + +static float nsvg__actualOrigX(NSVGparser *p) +{ + return p->viewMinx; +} + +static float nsvg__actualOrigY(NSVGparser *p) +{ + return p->viewMiny; +} + +static float nsvg__actualWidth(NSVGparser *p) +{ + return p->viewWidth; +} + +static float nsvg__actualHeight(NSVGparser *p) +{ + return p->viewHeight; +} + +static float nsvg__actualLength(NSVGparser *p) +{ + float w = nsvg__actualWidth(p), h = nsvg__actualHeight(p); + return sqrtf(w * w + h * h) / sqrtf(2.0f); +} + +static float nsvg__convertToPixels(NSVGparser *p, NSVGcoordinate c, float orig, float length) +{ + NSVGattrib *attr = nsvg__getAttr(p); + switch (c.units) { + case NSVG_UNITS_USER: + return c.value; + case NSVG_UNITS_PX: + return c.value; + case NSVG_UNITS_PT: + return c.value / 72.0f * p->dpi; + case NSVG_UNITS_PC: + return c.value / 6.0f * p->dpi; + case NSVG_UNITS_MM: + return c.value / 25.4f * p->dpi; + case NSVG_UNITS_CM: + return c.value / 2.54f * p->dpi; + case NSVG_UNITS_IN: + return c.value * p->dpi; + case NSVG_UNITS_EM: + return c.value * attr->fontSize; + case NSVG_UNITS_EX: + return c.value * attr->fontSize * 0.52f; // x-height of Helvetica. + case NSVG_UNITS_PERCENT: + return orig + c.value / 100.0f * length; + default: + return c.value; + } + return c.value; +} + +static NSVGgradientData *nsvg__findGradientData(NSVGparser *p, const char *id) +{ + NSVGgradientData *grad = p->gradients; + if (id == NULL || *id == '\0') + return NULL; + while (grad != NULL) { + if (strcmp(grad->id, id) == 0) + return grad; + grad = grad->next; + } + return NULL; +} + +static NSVGgradient *nsvg__createGradient(NSVGparser *p, + const char *id, + const float *localBounds, + char *paintType) +{ + NSVGattrib *attr = nsvg__getAttr(p); + NSVGgradientData *data = NULL; + NSVGgradientData *ref = NULL; + NSVGgradientStop *stops = NULL; + NSVGgradient *grad; + float ox, oy, sw, sh, sl; + int nstops = 0; + int refIter; + + data = nsvg__findGradientData(p, id); + if (data == NULL) + return NULL; + + // TODO: use ref to fill in all unset values too. + ref = data; + refIter = 0; + while (ref != NULL) { + NSVGgradientData *nextRef = NULL; + if (stops == NULL && ref->stops != NULL) { + stops = ref->stops; + nstops = ref->nstops; + break; + } + nextRef = nsvg__findGradientData(p, ref->ref); + if (nextRef == ref) + break; // prevent infite loops on malformed data + ref = nextRef; + refIter++; + if (refIter > 32) + break; // prevent infite loops on malformed data + } + if (stops == NULL) + return NULL; + + grad = (NSVGgradient *)malloc(sizeof(NSVGgradient) + sizeof(NSVGgradientStop) * (nstops - 1)); + if (grad == NULL) + return NULL; + + // The shape width and height. + if (data->units == NSVG_OBJECT_SPACE) { + ox = localBounds[0]; + oy = localBounds[1]; + sw = localBounds[2] - localBounds[0]; + sh = localBounds[3] - localBounds[1]; + } + else { + ox = nsvg__actualOrigX(p); + oy = nsvg__actualOrigY(p); + sw = nsvg__actualWidth(p); + sh = nsvg__actualHeight(p); + } + sl = sqrtf(sw * sw + sh * sh) / sqrtf(2.0f); + + if (data->type == NSVG_PAINT_LINEAR_GRADIENT) { + float x1, y1, x2, y2, dx, dy; + x1 = nsvg__convertToPixels(p, data->linear.x1, ox, sw); + y1 = nsvg__convertToPixels(p, data->linear.y1, oy, sh); + x2 = nsvg__convertToPixels(p, data->linear.x2, ox, sw); + y2 = nsvg__convertToPixels(p, data->linear.y2, oy, sh); + // Calculate transform aligned to the line + dx = x2 - x1; + dy = y2 - y1; + grad->xform[0] = dy; + grad->xform[1] = -dx; + grad->xform[2] = dx; + grad->xform[3] = dy; + grad->xform[4] = x1; + grad->xform[5] = y1; + } + else { + float cx, cy, fx, fy, r; + cx = nsvg__convertToPixels(p, data->radial.cx, ox, sw); + cy = nsvg__convertToPixels(p, data->radial.cy, oy, sh); + fx = nsvg__convertToPixels(p, data->radial.fx, ox, sw); + fy = nsvg__convertToPixels(p, data->radial.fy, oy, sh); + r = nsvg__convertToPixels(p, data->radial.r, 0, sl); + // Calculate transform aligned to the circle + grad->xform[0] = r; + grad->xform[1] = 0; + grad->xform[2] = 0; + grad->xform[3] = r; + grad->xform[4] = cx; + grad->xform[5] = cy; + grad->fx = fx / r; + grad->fy = fy / r; + } + + nsvg__xformMultiply(grad->xform, data->xform); + nsvg__xformMultiply(grad->xform, attr->xform); + + grad->spread = data->spread; + memcpy(grad->stops, stops, nstops * sizeof(NSVGgradientStop)); + grad->nstops = nstops; + + *paintType = data->type; + + return grad; +} + +static float nsvg__getAverageScale(float *t) +{ + float sx = sqrtf(t[0] * t[0] + t[2] * t[2]); + float sy = sqrtf(t[1] * t[1] + t[3] * t[3]); + return (sx + sy) * 0.5f; +} + +static void nsvg__getLocalBounds(float *bounds, NSVGshape *shape, float *xform) +{ + NSVGpath *path; + float curve[4 * 2], curveBounds[4]; + int i, first = 1; + for (path = shape->paths; path != NULL; path = path->next) { + nsvg__xformPoint(&curve[0], &curve[1], path->pts[0], path->pts[1], xform); + for (i = 0; i < path->npts - 1; i += 3) { + nsvg__xformPoint( + &curve[2], &curve[3], path->pts[(i + 1) * 2], path->pts[(i + 1) * 2 + 1], xform); + nsvg__xformPoint( + &curve[4], &curve[5], path->pts[(i + 2) * 2], path->pts[(i + 2) * 2 + 1], xform); + nsvg__xformPoint( + &curve[6], &curve[7], path->pts[(i + 3) * 2], path->pts[(i + 3) * 2 + 1], xform); + nsvg__curveBounds(curveBounds, curve); + if (first) { + bounds[0] = curveBounds[0]; + bounds[1] = curveBounds[1]; + bounds[2] = curveBounds[2]; + bounds[3] = curveBounds[3]; + first = 0; + } + else { + bounds[0] = nsvg__minf(bounds[0], curveBounds[0]); + bounds[1] = nsvg__minf(bounds[1], curveBounds[1]); + bounds[2] = nsvg__maxf(bounds[2], curveBounds[2]); + bounds[3] = nsvg__maxf(bounds[3], curveBounds[3]); + } + curve[0] = curve[6]; + curve[1] = curve[7]; + } + } +} + +static void nsvg__addShape(NSVGparser *p) +{ + NSVGattrib *attr = nsvg__getAttr(p); + float scale = 1.0f; + NSVGshape *shape; + NSVGpath *path; + int i; + + if (p->plist == NULL) + return; + + shape = (NSVGshape *)malloc(sizeof(NSVGshape)); + if (shape == NULL) + goto error; + memset(shape, 0, sizeof(NSVGshape)); + + memcpy(shape->id, attr->id, sizeof shape->id); + /* Copy parent id from breadcrumb. */ + if (p->breadcrumb_len > 0) { + memcpy(shape->id_parent, p->breadcrumb[0], sizeof shape->id_parent); + } + else { + memcpy(shape->id_parent, attr->id, sizeof shape->id_parent); + } + + scale = nsvg__getAverageScale(attr->xform); + shape->strokeWidth = attr->strokeWidth * scale; + shape->strokeDashOffset = attr->strokeDashOffset * scale; + shape->strokeDashCount = (char)attr->strokeDashCount; + for (i = 0; i < attr->strokeDashCount; i++) + shape->strokeDashArray[i] = attr->strokeDashArray[i] * scale; + shape->strokeLineJoin = attr->strokeLineJoin; + shape->strokeLineCap = attr->strokeLineCap; + shape->miterLimit = attr->miterLimit; + shape->fillRule = attr->fillRule; + shape->opacity = attr->opacity; + + shape->paths = p->plist; + p->plist = NULL; + + // Calculate shape bounds + shape->bounds[0] = shape->paths->bounds[0]; + shape->bounds[1] = shape->paths->bounds[1]; + shape->bounds[2] = shape->paths->bounds[2]; + shape->bounds[3] = shape->paths->bounds[3]; + for (path = shape->paths->next; path != NULL; path = path->next) { + shape->bounds[0] = nsvg__minf(shape->bounds[0], path->bounds[0]); + shape->bounds[1] = nsvg__minf(shape->bounds[1], path->bounds[1]); + shape->bounds[2] = nsvg__maxf(shape->bounds[2], path->bounds[2]); + shape->bounds[3] = nsvg__maxf(shape->bounds[3], path->bounds[3]); + } + + // Set fill + if (attr->hasFill == 0) { + shape->fill.type = NSVG_PAINT_NONE; + } + else if (attr->hasFill == 1) { + shape->fill.type = NSVG_PAINT_COLOR; + shape->fill.color = attr->fillColor; + shape->fill.color |= (unsigned int)(attr->fillOpacity * 255) << 24; + } + else if (attr->hasFill == 2) { + float inv[6], localBounds[4]; + nsvg__xformInverse(inv, attr->xform); + nsvg__getLocalBounds(localBounds, shape, inv); + shape->fill.gradient = nsvg__createGradient( + p, attr->fillGradient, localBounds, &shape->fill.type); + if (shape->fill.gradient == NULL) { + shape->fill.type = NSVG_PAINT_NONE; + } + } + + // Set stroke + if (attr->hasStroke == 0) { + shape->stroke.type = NSVG_PAINT_NONE; + } + else if (attr->hasStroke == 1) { + shape->stroke.type = NSVG_PAINT_COLOR; + shape->stroke.color = attr->strokeColor; + shape->stroke.color |= (unsigned int)(attr->strokeOpacity * 255) << 24; + } + else if (attr->hasStroke == 2) { + float inv[6], localBounds[4]; + nsvg__xformInverse(inv, attr->xform); + nsvg__getLocalBounds(localBounds, shape, inv); + shape->stroke.gradient = nsvg__createGradient( + p, attr->strokeGradient, localBounds, &shape->stroke.type); + if (shape->stroke.gradient == NULL) + shape->stroke.type = NSVG_PAINT_NONE; + } + + // Set flags + shape->flags = (attr->visible ? NSVG_FLAGS_VISIBLE : 0x00); + + // Add to tail + if (p->image->shapes == NULL) + p->image->shapes = shape; + else + p->shapesTail->next = shape; + p->shapesTail = shape; + + return; + +error: + if (shape) + free(shape); +} + +static void nsvg__addPath(NSVGparser *p, char closed) +{ + NSVGattrib *attr = nsvg__getAttr(p); + NSVGpath *path = NULL; + float bounds[4]; + float *curve; + int i; + + if (p->npts < 4) + return; + + if (closed) + nsvg__lineTo(p, p->pts[0], p->pts[1]); + + // Expect 1 + N*3 points (N = number of cubic bezier segments). + if ((p->npts % 3) != 1) + return; + + path = (NSVGpath *)malloc(sizeof(NSVGpath)); + if (path == NULL) + goto error; + memset(path, 0, sizeof(NSVGpath)); + + path->pts = (float *)malloc(p->npts * 2 * sizeof(float)); + if (path->pts == NULL) + goto error; + path->closed = closed; + path->npts = p->npts; + + // Transform path. + for (i = 0; i < p->npts; ++i) + nsvg__xformPoint( + &path->pts[i * 2], &path->pts[i * 2 + 1], p->pts[i * 2], p->pts[i * 2 + 1], attr->xform); + + // Find bounds + for (i = 0; i < path->npts - 1; i += 3) { + curve = &path->pts[i * 2]; + nsvg__curveBounds(bounds, curve); + if (i == 0) { + path->bounds[0] = bounds[0]; + path->bounds[1] = bounds[1]; + path->bounds[2] = bounds[2]; + path->bounds[3] = bounds[3]; + } + else { + path->bounds[0] = nsvg__minf(path->bounds[0], bounds[0]); + path->bounds[1] = nsvg__minf(path->bounds[1], bounds[1]); + path->bounds[2] = nsvg__maxf(path->bounds[2], bounds[2]); + path->bounds[3] = nsvg__maxf(path->bounds[3], bounds[3]); + } + } + + path->next = p->plist; + p->plist = path; + + return; + +error: + if (path != NULL) { + if (path->pts != NULL) + free(path->pts); + free(path); + } +} + +// We roll our own string to float because the std library one uses locale and messes things up. +static double nsvg__atof(const char *s) +{ + char *cur = (char *)s; + char *end = NULL; + double res = 0.0, sign = 1.0; + long long intPart = 0, fracPart = 0; + char hasIntPart = 0, hasFracPart = 0; + + // Parse optional sign + if (*cur == '+') { + cur++; + } + else if (*cur == '-') { + sign = -1; + cur++; + } + + // Parse integer part + if (nsvg__isdigit(*cur)) { + // Parse digit sequence + intPart = strtoll(cur, &end, 10); + if (cur != end) { + res = (double)intPart; + hasIntPart = 1; + cur = end; + } + } + + // Parse fractional part. + if (*cur == '.') { + cur++; // Skip '.' + if (nsvg__isdigit(*cur)) { + // Parse digit sequence + fracPart = strtoll(cur, &end, 10); + if (cur != end) { + res += (double)fracPart / pow(10.0, (double)(end - cur)); + hasFracPart = 1; + cur = end; + } + } + } + + // A valid number should have integer or fractional part. + if (!hasIntPart && !hasFracPart) + return 0.0; + + // Parse optional exponent + if (*cur == 'e' || *cur == 'E') { + long expPart = 0; + cur++; // skip 'E' + expPart = strtol(cur, &end, 10); // Parse digit sequence with sign + if (cur != end) { + res *= pow(10.0, (double)expPart); + } + } + + return res * sign; +} + +static const char *nsvg__parseNumber(const char *s, char *it, const int size) +{ + const int last = size - 1; + int i = 0; + + // sign + if (*s == '-' || *s == '+') { + if (i < last) + it[i++] = *s; + s++; + } + // integer part + while (*s && nsvg__isdigit(*s)) { + if (i < last) + it[i++] = *s; + s++; + } + if (*s == '.') { + // decimal point + if (i < last) + it[i++] = *s; + s++; + // fraction part + while (*s && nsvg__isdigit(*s)) { + if (i < last) + it[i++] = *s; + s++; + } + } + // exponent + if ((*s == 'e' || *s == 'E') && (s[1] != 'm' && s[1] != 'x')) { + if (i < last) + it[i++] = *s; + s++; + if (*s == '-' || *s == '+') { + if (i < last) + it[i++] = *s; + s++; + } + while (*s && nsvg__isdigit(*s)) { + if (i < last) + it[i++] = *s; + s++; + } + } + it[i] = '\0'; + + return s; +} + +static const char *nsvg__getNextPathItem(const char *s, char *it) +{ + it[0] = '\0'; + // Skip white spaces and commas + while (*s && (nsvg__isspace(*s) || *s == ',')) + s++; + if (!*s) + return s; + if (*s == '-' || *s == '+' || *s == '.' || nsvg__isdigit(*s)) { + s = nsvg__parseNumber(s, it, 64); + } + else { + // Parse command + it[0] = *s++; + it[1] = '\0'; + return s; + } + + return s; +} + +static unsigned int nsvg__parseColorHex(const char *str) +{ + unsigned int c = 0, r = 0, g = 0, b = 0; + int n = 0; + str++; // skip # + // Calculate number of characters. + while (str[n] && !nsvg__isspace(str[n])) + n++; + if (n == 6) { + sscanf(str, "%x", &c); + } + else if (n == 3) { + sscanf(str, "%x", &c); + c = (c & 0xf) | ((c & 0xf0) << 4) | ((c & 0xf00) << 8); + c |= c << 4; + } + r = (c >> 16) & 0xff; + g = (c >> 8) & 0xff; + b = c & 0xff; + return NSVG_RGB(r, g, b); +} + +static unsigned int nsvg__parseColorRGB(const char *str) +{ + int r = -1, g = -1, b = -1; + char s1[32] = "", s2[32] = ""; + sscanf(str + 4, "%d%[%%, \t]%d%[%%, \t]%d", &r, s1, &g, s2, &b); + if (strchr(s1, '%')) { + return NSVG_RGB((r * 255) / 100, (g * 255) / 100, (b * 255) / 100); + } + else { + return NSVG_RGB(r, g, b); + } +} + +typedef struct NSVGNamedColor { + const char *name; + unsigned int color; +} NSVGNamedColor; + +NSVGNamedColor nsvg__colors[] = { + + {"red", NSVG_RGB(255, 0, 0)}, + {"green", NSVG_RGB(0, 128, 0)}, + {"blue", NSVG_RGB(0, 0, 255)}, + {"yellow", NSVG_RGB(255, 255, 0)}, + {"cyan", NSVG_RGB(0, 255, 255)}, + {"magenta", NSVG_RGB(255, 0, 255)}, + {"black", NSVG_RGB(0, 0, 0)}, + {"grey", NSVG_RGB(128, 128, 128)}, + {"gray", NSVG_RGB(128, 128, 128)}, + {"white", NSVG_RGB(255, 255, 255)}, + +#ifdef NANOSVG_ALL_COLOR_KEYWORDS + {"aliceblue", NSVG_RGB(240, 248, 255)}, + {"antiquewhite", NSVG_RGB(250, 235, 215)}, + {"aqua", NSVG_RGB(0, 255, 255)}, + {"aquamarine", NSVG_RGB(127, 255, 212)}, + {"azure", NSVG_RGB(240, 255, 255)}, + {"beige", NSVG_RGB(245, 245, 220)}, + {"bisque", NSVG_RGB(255, 228, 196)}, + {"blanchedalmond", NSVG_RGB(255, 235, 205)}, + {"blueviolet", NSVG_RGB(138, 43, 226)}, + {"brown", NSVG_RGB(165, 42, 42)}, + {"burlywood", NSVG_RGB(222, 184, 135)}, + {"cadetblue", NSVG_RGB(95, 158, 160)}, + {"chartreuse", NSVG_RGB(127, 255, 0)}, + {"chocolate", NSVG_RGB(210, 105, 30)}, + {"coral", NSVG_RGB(255, 127, 80)}, + {"cornflowerblue", NSVG_RGB(100, 149, 237)}, + {"cornsilk", NSVG_RGB(255, 248, 220)}, + {"crimson", NSVG_RGB(220, 20, 60)}, + {"darkblue", NSVG_RGB(0, 0, 139)}, + {"darkcyan", NSVG_RGB(0, 139, 139)}, + {"darkgoldenrod", NSVG_RGB(184, 134, 11)}, + {"darkgray", NSVG_RGB(169, 169, 169)}, + {"darkgreen", NSVG_RGB(0, 100, 0)}, + {"darkgrey", NSVG_RGB(169, 169, 169)}, + {"darkkhaki", NSVG_RGB(189, 183, 107)}, + {"darkmagenta", NSVG_RGB(139, 0, 139)}, + {"darkolivegreen", NSVG_RGB(85, 107, 47)}, + {"darkorange", NSVG_RGB(255, 140, 0)}, + {"darkorchid", NSVG_RGB(153, 50, 204)}, + {"darkred", NSVG_RGB(139, 0, 0)}, + {"darksalmon", NSVG_RGB(233, 150, 122)}, + {"darkseagreen", NSVG_RGB(143, 188, 143)}, + {"darkslateblue", NSVG_RGB(72, 61, 139)}, + {"darkslategray", NSVG_RGB(47, 79, 79)}, + {"darkslategrey", NSVG_RGB(47, 79, 79)}, + {"darkturquoise", NSVG_RGB(0, 206, 209)}, + {"darkviolet", NSVG_RGB(148, 0, 211)}, + {"deeppink", NSVG_RGB(255, 20, 147)}, + {"deepskyblue", NSVG_RGB(0, 191, 255)}, + {"dimgray", NSVG_RGB(105, 105, 105)}, + {"dimgrey", NSVG_RGB(105, 105, 105)}, + {"dodgerblue", NSVG_RGB(30, 144, 255)}, + {"firebrick", NSVG_RGB(178, 34, 34)}, + {"floralwhite", NSVG_RGB(255, 250, 240)}, + {"forestgreen", NSVG_RGB(34, 139, 34)}, + {"fuchsia", NSVG_RGB(255, 0, 255)}, + {"gainsboro", NSVG_RGB(220, 220, 220)}, + {"ghostwhite", NSVG_RGB(248, 248, 255)}, + {"gold", NSVG_RGB(255, 215, 0)}, + {"goldenrod", NSVG_RGB(218, 165, 32)}, + {"greenyellow", NSVG_RGB(173, 255, 47)}, + {"honeydew", NSVG_RGB(240, 255, 240)}, + {"hotpink", NSVG_RGB(255, 105, 180)}, + {"indianred", NSVG_RGB(205, 92, 92)}, + {"indigo", NSVG_RGB(75, 0, 130)}, + {"ivory", NSVG_RGB(255, 255, 240)}, + {"khaki", NSVG_RGB(240, 230, 140)}, + {"lavender", NSVG_RGB(230, 230, 250)}, + {"lavenderblush", NSVG_RGB(255, 240, 245)}, + {"lawngreen", NSVG_RGB(124, 252, 0)}, + {"lemonchiffon", NSVG_RGB(255, 250, 205)}, + {"lightblue", NSVG_RGB(173, 216, 230)}, + {"lightcoral", NSVG_RGB(240, 128, 128)}, + {"lightcyan", NSVG_RGB(224, 255, 255)}, + {"lightgoldenrodyellow", NSVG_RGB(250, 250, 210)}, + {"lightgray", NSVG_RGB(211, 211, 211)}, + {"lightgreen", NSVG_RGB(144, 238, 144)}, + {"lightgrey", NSVG_RGB(211, 211, 211)}, + {"lightpink", NSVG_RGB(255, 182, 193)}, + {"lightsalmon", NSVG_RGB(255, 160, 122)}, + {"lightseagreen", NSVG_RGB(32, 178, 170)}, + {"lightskyblue", NSVG_RGB(135, 206, 250)}, + {"lightslategray", NSVG_RGB(119, 136, 153)}, + {"lightslategrey", NSVG_RGB(119, 136, 153)}, + {"lightsteelblue", NSVG_RGB(176, 196, 222)}, + {"lightyellow", NSVG_RGB(255, 255, 224)}, + {"lime", NSVG_RGB(0, 255, 0)}, + {"limegreen", NSVG_RGB(50, 205, 50)}, + {"linen", NSVG_RGB(250, 240, 230)}, + {"maroon", NSVG_RGB(128, 0, 0)}, + {"mediumaquamarine", NSVG_RGB(102, 205, 170)}, + {"mediumblue", NSVG_RGB(0, 0, 205)}, + {"mediumorchid", NSVG_RGB(186, 85, 211)}, + {"mediumpurple", NSVG_RGB(147, 112, 219)}, + {"mediumseagreen", NSVG_RGB(60, 179, 113)}, + {"mediumslateblue", NSVG_RGB(123, 104, 238)}, + {"mediumspringgreen", NSVG_RGB(0, 250, 154)}, + {"mediumturquoise", NSVG_RGB(72, 209, 204)}, + {"mediumvioletred", NSVG_RGB(199, 21, 133)}, + {"midnightblue", NSVG_RGB(25, 25, 112)}, + {"mintcream", NSVG_RGB(245, 255, 250)}, + {"mistyrose", NSVG_RGB(255, 228, 225)}, + {"moccasin", NSVG_RGB(255, 228, 181)}, + {"navajowhite", NSVG_RGB(255, 222, 173)}, + {"navy", NSVG_RGB(0, 0, 128)}, + {"oldlace", NSVG_RGB(253, 245, 230)}, + {"olive", NSVG_RGB(128, 128, 0)}, + {"olivedrab", NSVG_RGB(107, 142, 35)}, + {"orange", NSVG_RGB(255, 165, 0)}, + {"orangered", NSVG_RGB(255, 69, 0)}, + {"orchid", NSVG_RGB(218, 112, 214)}, + {"palegoldenrod", NSVG_RGB(238, 232, 170)}, + {"palegreen", NSVG_RGB(152, 251, 152)}, + {"paleturquoise", NSVG_RGB(175, 238, 238)}, + {"palevioletred", NSVG_RGB(219, 112, 147)}, + {"papayawhip", NSVG_RGB(255, 239, 213)}, + {"peachpuff", NSVG_RGB(255, 218, 185)}, + {"peru", NSVG_RGB(205, 133, 63)}, + {"pink", NSVG_RGB(255, 192, 203)}, + {"plum", NSVG_RGB(221, 160, 221)}, + {"powderblue", NSVG_RGB(176, 224, 230)}, + {"purple", NSVG_RGB(128, 0, 128)}, + {"rosybrown", NSVG_RGB(188, 143, 143)}, + {"royalblue", NSVG_RGB(65, 105, 225)}, + {"saddlebrown", NSVG_RGB(139, 69, 19)}, + {"salmon", NSVG_RGB(250, 128, 114)}, + {"sandybrown", NSVG_RGB(244, 164, 96)}, + {"seagreen", NSVG_RGB(46, 139, 87)}, + {"seashell", NSVG_RGB(255, 245, 238)}, + {"sienna", NSVG_RGB(160, 82, 45)}, + {"silver", NSVG_RGB(192, 192, 192)}, + {"skyblue", NSVG_RGB(135, 206, 235)}, + {"slateblue", NSVG_RGB(106, 90, 205)}, + {"slategray", NSVG_RGB(112, 128, 144)}, + {"slategrey", NSVG_RGB(112, 128, 144)}, + {"snow", NSVG_RGB(255, 250, 250)}, + {"springgreen", NSVG_RGB(0, 255, 127)}, + {"steelblue", NSVG_RGB(70, 130, 180)}, + {"tan", NSVG_RGB(210, 180, 140)}, + {"teal", NSVG_RGB(0, 128, 128)}, + {"thistle", NSVG_RGB(216, 191, 216)}, + {"tomato", NSVG_RGB(255, 99, 71)}, + {"turquoise", NSVG_RGB(64, 224, 208)}, + {"violet", NSVG_RGB(238, 130, 238)}, + {"wheat", NSVG_RGB(245, 222, 179)}, + {"whitesmoke", NSVG_RGB(245, 245, 245)}, + {"yellowgreen", NSVG_RGB(154, 205, 50)}, +#endif +}; + +static unsigned int nsvg__parseColorName(const char *str) +{ + int i, ncolors = sizeof(nsvg__colors) / sizeof(NSVGNamedColor); + + for (i = 0; i < ncolors; i++) { + if (strcmp(nsvg__colors[i].name, str) == 0) { + return nsvg__colors[i].color; + } + } + + return NSVG_RGB(128, 128, 128); +} + +static unsigned int nsvg__parseColor(const char *str) +{ + size_t len = 0; + while (*str == ' ') + ++str; + len = strlen(str); + if (len >= 1 && *str == '#') + return nsvg__parseColorHex(str); + else if (len >= 4 && str[0] == 'r' && str[1] == 'g' && str[2] == 'b' && str[3] == '(') + return nsvg__parseColorRGB(str); + return nsvg__parseColorName(str); +} + +static float nsvg__parseOpacity(const char *str) +{ + float val = nsvg__atof(str); + if (val < 0.0f) + val = 0.0f; + if (val > 1.0f) + val = 1.0f; + return val; +} + +static float nsvg__parseMiterLimit(const char *str) +{ + float val = nsvg__atof(str); + if (val < 0.0f) + val = 0.0f; + return val; +} + +static int nsvg__parseUnits(const char *units) +{ + if (units[0] == 'p' && units[1] == 'x') + return NSVG_UNITS_PX; + else if (units[0] == 'p' && units[1] == 't') + return NSVG_UNITS_PT; + else if (units[0] == 'p' && units[1] == 'c') + return NSVG_UNITS_PC; + else if (units[0] == 'm' && units[1] == 'm') + return NSVG_UNITS_MM; + else if (units[0] == 'c' && units[1] == 'm') + return NSVG_UNITS_CM; + else if (units[0] == 'i' && units[1] == 'n') + return NSVG_UNITS_IN; + else if (units[0] == '%') + return NSVG_UNITS_PERCENT; + else if (units[0] == 'e' && units[1] == 'm') + return NSVG_UNITS_EM; + else if (units[0] == 'e' && units[1] == 'x') + return NSVG_UNITS_EX; + return NSVG_UNITS_USER; +} + +static int nsvg__isCoordinate(const char *s) +{ + // optional sign + if (*s == '-' || *s == '+') + s++; + // must have at least one digit + return nsvg__isdigit(*s); +} + +static NSVGcoordinate nsvg__parseCoordinateRaw(const char *str) +{ + NSVGcoordinate coord = {0, NSVG_UNITS_USER}; + char buf[64]; + coord.units = nsvg__parseUnits(nsvg__parseNumber(str, buf, 64)); + coord.value = nsvg__atof(buf); + return coord; +} + +static NSVGcoordinate nsvg__coord(float v, int units) +{ + NSVGcoordinate coord = {v, units}; + return coord; +} + +static float nsvg__parseCoordinate(NSVGparser *p, const char *str, float orig, float length) +{ + NSVGcoordinate coord = nsvg__parseCoordinateRaw(str); + return nsvg__convertToPixels(p, coord, orig, length); +} + +static int nsvg__parseTransformArgs(const char *str, float *args, int maxNa, int *na) +{ + const char *end; + const char *ptr; + char it[64]; + + *na = 0; + ptr = str; + while (*ptr && *ptr != '(') + ++ptr; + if (*ptr == 0) + return 1; + end = ptr; + while (*end && *end != ')') + ++end; + if (*end == 0) + return 1; + + while (ptr < end) { + if (*ptr == '-' || *ptr == '+' || *ptr == '.' || nsvg__isdigit(*ptr)) { + if (*na >= maxNa) + return 0; + ptr = nsvg__parseNumber(ptr, it, 64); + args[(*na)++] = (float)nsvg__atof(it); + } + else { + ++ptr; + } + } + return (int)(end - str); +} + +static int nsvg__parseMatrix(float *xform, const char *str) +{ + float t[6]; + int na = 0; + int len = nsvg__parseTransformArgs(str, t, 6, &na); + if (na != 6) + return len; + memcpy(xform, t, sizeof(float) * 6); + return len; +} + +static int nsvg__parseTranslate(float *xform, const char *str) +{ + float args[2]; + float t[6]; + int na = 0; + int len = nsvg__parseTransformArgs(str, args, 2, &na); + if (na == 1) + args[1] = 0.0; + + nsvg__xformSetTranslation(t, args[0], args[1]); + memcpy(xform, t, sizeof(float) * 6); + return len; +} + +static int nsvg__parseScale(float *xform, const char *str) +{ + float args[2]; + int na = 0; + float t[6]; + int len = nsvg__parseTransformArgs(str, args, 2, &na); + if (na == 1) + args[1] = args[0]; + nsvg__xformSetScale(t, args[0], args[1]); + memcpy(xform, t, sizeof(float) * 6); + return len; +} + +static int nsvg__parseSkewX(float *xform, const char *str) +{ + float args[1]; + int na = 0; + float t[6]; + int len = nsvg__parseTransformArgs(str, args, 1, &na); + nsvg__xformSetSkewX(t, args[0] / 180.0f * NSVG_PI); + memcpy(xform, t, sizeof(float) * 6); + return len; +} + +static int nsvg__parseSkewY(float *xform, const char *str) +{ + float args[1]; + int na = 0; + float t[6]; + int len = nsvg__parseTransformArgs(str, args, 1, &na); + nsvg__xformSetSkewY(t, args[0] / 180.0f * NSVG_PI); + memcpy(xform, t, sizeof(float) * 6); + return len; +} + +static int nsvg__parseRotate(float *xform, const char *str) +{ + float args[3]; + int na = 0; + float m[6]; + float t[6]; + int len = nsvg__parseTransformArgs(str, args, 3, &na); + if (na == 1) + args[1] = args[2] = 0.0f; + nsvg__xformIdentity(m); + + if (na > 1) { + nsvg__xformSetTranslation(t, -args[1], -args[2]); + nsvg__xformMultiply(m, t); + } + + nsvg__xformSetRotation(t, args[0] / 180.0f * NSVG_PI); + nsvg__xformMultiply(m, t); + + if (na > 1) { + nsvg__xformSetTranslation(t, args[1], args[2]); + nsvg__xformMultiply(m, t); + } + + memcpy(xform, m, sizeof(float) * 6); + + return len; +} + +static void nsvg__parseTransform(float *xform, const char *str) +{ + float t[6]; + int len; + nsvg__xformIdentity(xform); + while (*str) { + if (strncmp(str, "matrix", 6) == 0) + len = nsvg__parseMatrix(t, str); + else if (strncmp(str, "translate", 9) == 0) + len = nsvg__parseTranslate(t, str); + else if (strncmp(str, "scale", 5) == 0) + len = nsvg__parseScale(t, str); + else if (strncmp(str, "rotate", 6) == 0) + len = nsvg__parseRotate(t, str); + else if (strncmp(str, "skewX", 5) == 0) + len = nsvg__parseSkewX(t, str); + else if (strncmp(str, "skewY", 5) == 0) + len = nsvg__parseSkewY(t, str); + else { + ++str; + continue; + } + if (len != 0) { + str += len; + } + else { + ++str; + continue; + } + + nsvg__xformPremultiply(xform, t); + } +} + +static void nsvg__parseUrl(char *id, const char *str) +{ + int i = 0; + str += 4; // "url("; + if (*str == '#') + str++; + while (i < 63 && *str != ')') { + id[i] = *str++; + i++; + } + id[i] = '\0'; +} + +static char nsvg__parseLineCap(const char *str) +{ + if (strcmp(str, "butt") == 0) + return NSVG_CAP_BUTT; + else if (strcmp(str, "round") == 0) + return NSVG_CAP_ROUND; + else if (strcmp(str, "square") == 0) + return NSVG_CAP_SQUARE; + // TODO: handle inherit. + return NSVG_CAP_BUTT; +} + +static char nsvg__parseLineJoin(const char *str) +{ + if (strcmp(str, "miter") == 0) + return NSVG_JOIN_MITER; + else if (strcmp(str, "round") == 0) + return NSVG_JOIN_ROUND; + else if (strcmp(str, "bevel") == 0) + return NSVG_JOIN_BEVEL; + // TODO: handle inherit. + return NSVG_JOIN_MITER; +} + +static char nsvg__parseFillRule(const char *str) +{ + if (strcmp(str, "nonzero") == 0) + return NSVG_FILLRULE_NONZERO; + else if (strcmp(str, "evenodd") == 0) + return NSVG_FILLRULE_EVENODD; + // TODO: handle inherit. + return NSVG_FILLRULE_NONZERO; +} + +static const char *nsvg__getNextDashItem(const char *s, char *it) +{ + int n = 0; + it[0] = '\0'; + // Skip white spaces and commas + while (*s && (nsvg__isspace(*s) || *s == ',')) + s++; + // Advance until whitespace, comma or end. + while (*s && (!nsvg__isspace(*s) && *s != ',')) { + if (n < 63) + it[n++] = *s; + s++; + } + it[n++] = '\0'; + return s; +} + +static int nsvg__parseStrokeDashArray(NSVGparser *p, const char *str, float *strokeDashArray) +{ + char item[64]; + int count = 0, i; + float sum = 0.0f; + + // Handle "none" + if (str[0] == 'n') + return 0; + + // Parse dashes + while (*str) { + str = nsvg__getNextDashItem(str, item); + if (!*item) + break; + if (count < NSVG_MAX_DASHES) + strokeDashArray[count++] = fabsf( + nsvg__parseCoordinate(p, item, 0.0f, nsvg__actualLength(p))); + } + + for (i = 0; i < count; i++) + sum += strokeDashArray[i]; + if (sum <= 1e-6f) + count = 0; + + return count; +} + +static void nsvg__parseStyle(NSVGparser *p, const char *str); + +static int nsvg__parseAttr(NSVGparser *p, const char *name, const char *value) +{ + float xform[6]; + NSVGattrib *attr = nsvg__getAttr(p); + if (!attr) + return 0; + + if (strcmp(name, "style") == 0) { + nsvg__parseStyle(p, value); + } + else if (strcmp(name, "display") == 0) { + if (strcmp(value, "none") == 0) + attr->visible = 0; + // Don't reset ->visible on display:inline, one display:none hides the whole subtree + } + else if (strcmp(name, "fill") == 0) { + if (strcmp(value, "none") == 0) { + attr->hasFill = 0; + } + else if (strncmp(value, "url(", 4) == 0) { + attr->hasFill = 2; + nsvg__parseUrl(attr->fillGradient, value); + } + else { + attr->hasFill = 1; + attr->fillColor = nsvg__parseColor(value); + } + } + else if (strcmp(name, "opacity") == 0) { + attr->opacity = nsvg__parseOpacity(value); + } + else if (strcmp(name, "fill-opacity") == 0) { + attr->fillOpacity = nsvg__parseOpacity(value); + } + else if (strcmp(name, "stroke") == 0) { + if (strcmp(value, "none") == 0) { + attr->hasStroke = 0; + } + else if (strncmp(value, "url(", 4) == 0) { + attr->hasStroke = 2; + nsvg__parseUrl(attr->strokeGradient, value); + } + else { + attr->hasStroke = 1; + attr->strokeColor = nsvg__parseColor(value); + } + } + else if (strcmp(name, "stroke-width") == 0) { + attr->strokeWidth = nsvg__parseCoordinate(p, value, 0.0f, nsvg__actualLength(p)); + } + else if (strcmp(name, "stroke-dasharray") == 0) { + attr->strokeDashCount = nsvg__parseStrokeDashArray(p, value, attr->strokeDashArray); + } + else if (strcmp(name, "stroke-dashoffset") == 0) { + attr->strokeDashOffset = nsvg__parseCoordinate(p, value, 0.0f, nsvg__actualLength(p)); + } + else if (strcmp(name, "stroke-opacity") == 0) { + attr->strokeOpacity = nsvg__parseOpacity(value); + } + else if (strcmp(name, "stroke-linecap") == 0) { + attr->strokeLineCap = nsvg__parseLineCap(value); + } + else if (strcmp(name, "stroke-linejoin") == 0) { + attr->strokeLineJoin = nsvg__parseLineJoin(value); + } + else if (strcmp(name, "stroke-miterlimit") == 0) { + attr->miterLimit = nsvg__parseMiterLimit(value); + } + else if (strcmp(name, "fill-rule") == 0) { + attr->fillRule = nsvg__parseFillRule(value); + } + else if (strcmp(name, "font-size") == 0) { + attr->fontSize = nsvg__parseCoordinate(p, value, 0.0f, nsvg__actualLength(p)); + } + else if (strcmp(name, "transform") == 0) { + nsvg__parseTransform(xform, value); + nsvg__xformPremultiply(attr->xform, xform); + } + else if (strcmp(name, "stop-color") == 0) { + attr->stopColor = nsvg__parseColor(value); + } + else if (strcmp(name, "stop-opacity") == 0) { + attr->stopOpacity = nsvg__parseOpacity(value); + } + else if (strcmp(name, "offset") == 0) { + attr->stopOffset = nsvg__parseCoordinate(p, value, 0.0f, 1.0f); + } + else if (strcmp(name, "id") == 0) { + strncpy(attr->id, value, 63); + attr->id[63] = '\0'; + } + else { + return 0; + } + return 1; +} + +static int nsvg__parseNameValue(NSVGparser *p, const char *start, const char *end) +{ + const char *str; + const char *val; + char name[512]; + char value[512]; + int n; + + str = start; + while (str < end && *str != ':') + ++str; + + val = str; + + // Right Trim + while (str > start && (*str == ':' || nsvg__isspace(*str))) + --str; + ++str; + + n = (int)(str - start); + if (n > 511) + n = 511; + if (n) + memcpy(name, start, n); + name[n] = 0; + + while (val < end && (*val == ':' || nsvg__isspace(*val))) + ++val; + + n = (int)(end - val); + if (n > 511) + n = 511; + if (n) + memcpy(value, val, n); + value[n] = 0; + + return nsvg__parseAttr(p, name, value); +} + +static void nsvg__parseStyle(NSVGparser *p, const char *str) +{ + const char *start; + const char *end; + + while (*str) { + // Left Trim + while (*str && nsvg__isspace(*str)) + ++str; + start = str; + while (*str && *str != ';') + ++str; + end = str; + + // Right Trim + while (end > start && (*end == ';' || nsvg__isspace(*end))) + --end; + ++end; + + nsvg__parseNameValue(p, start, end); + if (*str) + ++str; + } +} + +static void nsvg__parseAttribs(NSVGparser *p, const char **attr) +{ + int i; + for (i = 0; attr[i]; i += 2) { + if (strcmp(attr[i], "style") == 0) + nsvg__parseStyle(p, attr[i + 1]); + else + nsvg__parseAttr(p, attr[i], attr[i + 1]); + } +} + +static int nsvg__getArgsPerElement(char cmd) +{ + switch (cmd) { + case 'v': + case 'V': + case 'h': + case 'H': + return 1; + case 'm': + case 'M': + case 'l': + case 'L': + case 't': + case 'T': + return 2; + case 'q': + case 'Q': + case 's': + case 'S': + return 4; + case 'c': + case 'C': + return 6; + case 'a': + case 'A': + return 7; + case 'z': + case 'Z': + return 0; + } + return -1; +} + +static void nsvg__pathMoveTo(NSVGparser *p, float *cpx, float *cpy, float *args, int rel) +{ + if (rel) { + *cpx += args[0]; + *cpy += args[1]; + } + else { + *cpx = args[0]; + *cpy = args[1]; + } + nsvg__moveTo(p, *cpx, *cpy); +} + +static void nsvg__pathLineTo(NSVGparser *p, float *cpx, float *cpy, float *args, int rel) +{ + if (rel) { + *cpx += args[0]; + *cpy += args[1]; + } + else { + *cpx = args[0]; + *cpy = args[1]; + } + nsvg__lineTo(p, *cpx, *cpy); +} + +static void nsvg__pathHLineTo(NSVGparser *p, float *cpx, float *cpy, float *args, int rel) +{ + if (rel) + *cpx += args[0]; + else + *cpx = args[0]; + nsvg__lineTo(p, *cpx, *cpy); +} + +static void nsvg__pathVLineTo(NSVGparser *p, float *cpx, float *cpy, float *args, int rel) +{ + if (rel) + *cpy += args[0]; + else + *cpy = args[0]; + nsvg__lineTo(p, *cpx, *cpy); +} + +static void nsvg__pathCubicBezTo( + NSVGparser *p, float *cpx, float *cpy, float *cpx2, float *cpy2, float *args, int rel) +{ + float x2, y2, cx1, cy1, cx2, cy2; + + if (rel) { + cx1 = *cpx + args[0]; + cy1 = *cpy + args[1]; + cx2 = *cpx + args[2]; + cy2 = *cpy + args[3]; + x2 = *cpx + args[4]; + y2 = *cpy + args[5]; + } + else { + cx1 = args[0]; + cy1 = args[1]; + cx2 = args[2]; + cy2 = args[3]; + x2 = args[4]; + y2 = args[5]; + } + + nsvg__cubicBezTo(p, cx1, cy1, cx2, cy2, x2, y2); + + *cpx2 = cx2; + *cpy2 = cy2; + *cpx = x2; + *cpy = y2; +} + +static void nsvg__pathCubicBezShortTo( + NSVGparser *p, float *cpx, float *cpy, float *cpx2, float *cpy2, float *args, int rel) +{ + float x1, y1, x2, y2, cx1, cy1, cx2, cy2; + + x1 = *cpx; + y1 = *cpy; + if (rel) { + cx2 = *cpx + args[0]; + cy2 = *cpy + args[1]; + x2 = *cpx + args[2]; + y2 = *cpy + args[3]; + } + else { + cx2 = args[0]; + cy2 = args[1]; + x2 = args[2]; + y2 = args[3]; + } + + cx1 = 2 * x1 - *cpx2; + cy1 = 2 * y1 - *cpy2; + + nsvg__cubicBezTo(p, cx1, cy1, cx2, cy2, x2, y2); + + *cpx2 = cx2; + *cpy2 = cy2; + *cpx = x2; + *cpy = y2; +} + +static void nsvg__pathQuadBezTo( + NSVGparser *p, float *cpx, float *cpy, float *cpx2, float *cpy2, float *args, int rel) +{ + float x1, y1, x2, y2, cx, cy; + float cx1, cy1, cx2, cy2; + + x1 = *cpx; + y1 = *cpy; + if (rel) { + cx = *cpx + args[0]; + cy = *cpy + args[1]; + x2 = *cpx + args[2]; + y2 = *cpy + args[3]; + } + else { + cx = args[0]; + cy = args[1]; + x2 = args[2]; + y2 = args[3]; + } + + // Convert to cubic bezier + cx1 = x1 + 2.0f / 3.0f * (cx - x1); + cy1 = y1 + 2.0f / 3.0f * (cy - y1); + cx2 = x2 + 2.0f / 3.0f * (cx - x2); + cy2 = y2 + 2.0f / 3.0f * (cy - y2); + + nsvg__cubicBezTo(p, cx1, cy1, cx2, cy2, x2, y2); + + *cpx2 = cx; + *cpy2 = cy; + *cpx = x2; + *cpy = y2; +} + +static void nsvg__pathQuadBezShortTo( + NSVGparser *p, float *cpx, float *cpy, float *cpx2, float *cpy2, float *args, int rel) +{ + float x1, y1, x2, y2, cx, cy; + float cx1, cy1, cx2, cy2; + + x1 = *cpx; + y1 = *cpy; + if (rel) { + x2 = *cpx + args[0]; + y2 = *cpy + args[1]; + } + else { + x2 = args[0]; + y2 = args[1]; + } + + cx = 2 * x1 - *cpx2; + cy = 2 * y1 - *cpy2; + + // Convert to cubix bezier + cx1 = x1 + 2.0f / 3.0f * (cx - x1); + cy1 = y1 + 2.0f / 3.0f * (cy - y1); + cx2 = x2 + 2.0f / 3.0f * (cx - x2); + cy2 = y2 + 2.0f / 3.0f * (cy - y2); + + nsvg__cubicBezTo(p, cx1, cy1, cx2, cy2, x2, y2); + + *cpx2 = cx; + *cpy2 = cy; + *cpx = x2; + *cpy = y2; +} + +static float nsvg__sqr(float x) +{ + return x * x; +} +static float nsvg__vmag(float x, float y) +{ + return sqrtf(x * x + y * y); +} + +static float nsvg__vecrat(float ux, float uy, float vx, float vy) +{ + return (ux * vx + uy * vy) / (nsvg__vmag(ux, uy) * nsvg__vmag(vx, vy)); +} + +static float nsvg__vecang(float ux, float uy, float vx, float vy) +{ + float r = nsvg__vecrat(ux, uy, vx, vy); + if (r < -1.0f) + r = -1.0f; + if (r > 1.0f) + r = 1.0f; + return ((ux * vy < uy * vx) ? -1.0f : 1.0f) * acosf(r); +} + +static void nsvg__pathArcTo(NSVGparser *p, float *cpx, float *cpy, float *args, int rel) +{ + // Ported from canvg (https://code.google.com/p/canvg/) + float rx, ry, rotx; + float x1, y1, x2, y2, cx, cy, dx, dy, d; + float x1p, y1p, cxp, cyp, s, sa, sb; + float ux, uy, vx, vy, a1, da; + float x, y, tanx, tany, a, px = 0, py = 0, ptanx = 0, ptany = 0, t[6]; + float sinrx, cosrx; + int fa, fs; + int i, ndivs; + float hda, kappa; + + rx = fabsf(args[0]); // y radius + ry = fabsf(args[1]); // x radius + rotx = args[2] / 180.0f * NSVG_PI; // x rotation angle + fa = fabsf(args[3]) > 1e-6 ? 1 : 0; // Large arc + fs = fabsf(args[4]) > 1e-6 ? 1 : 0; // Sweep direction + x1 = *cpx; // start point + y1 = *cpy; + if (rel) { // end point + x2 = *cpx + args[5]; + y2 = *cpy + args[6]; + } + else { + x2 = args[5]; + y2 = args[6]; + } + + dx = x1 - x2; + dy = y1 - y2; + d = sqrtf(dx * dx + dy * dy); + if (d < 1e-6f || rx < 1e-6f || ry < 1e-6f) { + // The arc degenerates to a line + nsvg__lineTo(p, x2, y2); + *cpx = x2; + *cpy = y2; + return; + } + + sinrx = sinf(rotx); + cosrx = cosf(rotx); + + // Convert to center point parameterization. + // http://www.w3.org/TR/SVG11/implnote.html#ArcImplementationNotes + // 1) Compute x1', y1' + x1p = cosrx * dx / 2.0f + sinrx * dy / 2.0f; + y1p = -sinrx * dx / 2.0f + cosrx * dy / 2.0f; + d = nsvg__sqr(x1p) / nsvg__sqr(rx) + nsvg__sqr(y1p) / nsvg__sqr(ry); + if (d > 1) { + d = sqrtf(d); + rx *= d; + ry *= d; + } + // 2) Compute cx', cy' + s = 0.0f; + sa = nsvg__sqr(rx) * nsvg__sqr(ry) - nsvg__sqr(rx) * nsvg__sqr(y1p) - + nsvg__sqr(ry) * nsvg__sqr(x1p); + sb = nsvg__sqr(rx) * nsvg__sqr(y1p) + nsvg__sqr(ry) * nsvg__sqr(x1p); + if (sa < 0.0f) + sa = 0.0f; + if (sb > 0.0f) + s = sqrtf(sa / sb); + if (fa == fs) + s = -s; + cxp = s * rx * y1p / ry; + cyp = s * -ry * x1p / rx; + + // 3) Compute cx,cy from cx',cy' + cx = (x1 + x2) / 2.0f + cosrx * cxp - sinrx * cyp; + cy = (y1 + y2) / 2.0f + sinrx * cxp + cosrx * cyp; + + // 4) Calculate theta1, and delta theta. + ux = (x1p - cxp) / rx; + uy = (y1p - cyp) / ry; + vx = (-x1p - cxp) / rx; + vy = (-y1p - cyp) / ry; + a1 = nsvg__vecang(1.0f, 0.0f, ux, uy); // Initial angle + da = nsvg__vecang(ux, uy, vx, vy); // Delta angle + + // if (vecrat(ux,uy,vx,vy) <= -1.0f) da = NSVG_PI; + // if (vecrat(ux,uy,vx,vy) >= 1.0f) da = 0; + + if (fs == 0 && da > 0) + da -= 2 * NSVG_PI; + else if (fs == 1 && da < 0) + da += 2 * NSVG_PI; + + // Approximate the arc using cubic spline segments. + t[0] = cosrx; + t[1] = sinrx; + t[2] = -sinrx; + t[3] = cosrx; + t[4] = cx; + t[5] = cy; + + // Split arc into max 90 degree segments. + // The loop assumes an iteration per end point (including start and end), this +1. + ndivs = (int)(fabsf(da) / (NSVG_PI * 0.5f) + 1.0f); + hda = (da / (float)ndivs) / 2.0f; + kappa = fabsf(4.0f / 3.0f * (1.0f - cosf(hda)) / sinf(hda)); + if (da < 0.0f) + kappa = -kappa; + + for (i = 0; i <= ndivs; i++) { + a = a1 + da * ((float)i / (float)ndivs); + dx = cosf(a); + dy = sinf(a); + nsvg__xformPoint(&x, &y, dx * rx, dy * ry, t); // position + nsvg__xformVec(&tanx, &tany, -dy * rx * kappa, dx * ry * kappa, t); // tangent + if (i > 0) + nsvg__cubicBezTo(p, px + ptanx, py + ptany, x - tanx, y - tany, x, y); + px = x; + py = y; + ptanx = tanx; + ptany = tany; + } + + *cpx = x2; + *cpy = y2; +} + +static void nsvg__parsePath(NSVGparser *p, const char **attr) +{ + const char *s = NULL; + char cmd = '\0'; + float args[10]; + int nargs; + int rargs = 0; + char initPoint; + float cpx, cpy, cpx2, cpy2; + const char *tmp[4]; + char closedFlag; + int i; + char item[64]; + + for (i = 0; attr[i]; i += 2) { + if (strcmp(attr[i], "d") == 0) { + s = attr[i + 1]; + } + else { + tmp[0] = attr[i]; + tmp[1] = attr[i + 1]; + tmp[2] = 0; + tmp[3] = 0; + nsvg__parseAttribs(p, tmp); + } + } + + if (s) { + nsvg__resetPath(p); + cpx = 0; + cpy = 0; + cpx2 = 0; + cpy2 = 0; + initPoint = 0; + closedFlag = 0; + nargs = 0; + + while (*s) { + s = nsvg__getNextPathItem(s, item); + if (!*item) + break; + if (cmd != '\0' && nsvg__isCoordinate(item)) { + if (nargs < 10) + args[nargs++] = (float)nsvg__atof(item); + if (nargs >= rargs) { + switch (cmd) { + case 'm': + case 'M': + nsvg__pathMoveTo(p, &cpx, &cpy, args, cmd == 'm' ? 1 : 0); + // Moveto can be followed by multiple coordinate pairs, + // which should be treated as linetos. + cmd = (cmd == 'm') ? 'l' : 'L'; + rargs = nsvg__getArgsPerElement(cmd); + cpx2 = cpx; + cpy2 = cpy; + initPoint = 1; + break; + case 'l': + case 'L': + nsvg__pathLineTo(p, &cpx, &cpy, args, cmd == 'l' ? 1 : 0); + cpx2 = cpx; + cpy2 = cpy; + break; + case 'H': + case 'h': + nsvg__pathHLineTo(p, &cpx, &cpy, args, cmd == 'h' ? 1 : 0); + cpx2 = cpx; + cpy2 = cpy; + break; + case 'V': + case 'v': + nsvg__pathVLineTo(p, &cpx, &cpy, args, cmd == 'v' ? 1 : 0); + cpx2 = cpx; + cpy2 = cpy; + break; + case 'C': + case 'c': + nsvg__pathCubicBezTo(p, &cpx, &cpy, &cpx2, &cpy2, args, cmd == 'c' ? 1 : 0); + break; + case 'S': + case 's': + nsvg__pathCubicBezShortTo(p, &cpx, &cpy, &cpx2, &cpy2, args, cmd == 's' ? 1 : 0); + break; + case 'Q': + case 'q': + nsvg__pathQuadBezTo(p, &cpx, &cpy, &cpx2, &cpy2, args, cmd == 'q' ? 1 : 0); + break; + case 'T': + case 't': + nsvg__pathQuadBezShortTo(p, &cpx, &cpy, &cpx2, &cpy2, args, cmd == 't' ? 1 : 0); + break; + case 'A': + case 'a': + nsvg__pathArcTo(p, &cpx, &cpy, args, cmd == 'a' ? 1 : 0); + cpx2 = cpx; + cpy2 = cpy; + break; + default: + if (nargs >= 2) { + cpx = args[nargs - 2]; + cpy = args[nargs - 1]; + cpx2 = cpx; + cpy2 = cpy; + } + break; + } + nargs = 0; + } + } + else { + cmd = item[0]; + if (cmd == 'M' || cmd == 'm') { + // Commit path. + if (p->npts > 0) + nsvg__addPath(p, closedFlag); + // Start new subpath. + nsvg__resetPath(p); + closedFlag = 0; + nargs = 0; + } + else if (initPoint == 0) { + // Do not allow other commands until initial point has been set (moveTo called once). + cmd = '\0'; + } + if (cmd == 'Z' || cmd == 'z') { + closedFlag = 1; + // Commit path. + if (p->npts > 0) { + // Move current point to first point + cpx = p->pts[0]; + cpy = p->pts[1]; + cpx2 = cpx; + cpy2 = cpy; + nsvg__addPath(p, closedFlag); + } + // Start new subpath. + nsvg__resetPath(p); + nsvg__moveTo(p, cpx, cpy); + closedFlag = 0; + nargs = 0; + } + rargs = nsvg__getArgsPerElement(cmd); + if (rargs == -1) { + // Command not recognized + cmd = '\0'; + rargs = 0; + } + } + } + // Commit path. + if (p->npts) + nsvg__addPath(p, closedFlag); + } + + nsvg__addShape(p); +} + +static void nsvg__parseRect(NSVGparser *p, const char **attr) +{ + float x = 0.0f; + float y = 0.0f; + float w = 0.0f; + float h = 0.0f; + float rx = -1.0f; // marks not set + float ry = -1.0f; + int i; + + for (i = 0; attr[i]; i += 2) { + if (!nsvg__parseAttr(p, attr[i], attr[i + 1])) { + if (strcmp(attr[i], "x") == 0) + x = nsvg__parseCoordinate(p, attr[i + 1], nsvg__actualOrigX(p), nsvg__actualWidth(p)); + if (strcmp(attr[i], "y") == 0) + y = nsvg__parseCoordinate(p, attr[i + 1], nsvg__actualOrigY(p), nsvg__actualHeight(p)); + if (strcmp(attr[i], "width") == 0) + w = nsvg__parseCoordinate(p, attr[i + 1], 0.0f, nsvg__actualWidth(p)); + if (strcmp(attr[i], "height") == 0) + h = nsvg__parseCoordinate(p, attr[i + 1], 0.0f, nsvg__actualHeight(p)); + if (strcmp(attr[i], "rx") == 0) + rx = fabsf(nsvg__parseCoordinate(p, attr[i + 1], 0.0f, nsvg__actualWidth(p))); + if (strcmp(attr[i], "ry") == 0) + ry = fabsf(nsvg__parseCoordinate(p, attr[i + 1], 0.0f, nsvg__actualHeight(p))); + } + } + + if (rx < 0.0f && ry > 0.0f) + rx = ry; + if (ry < 0.0f && rx > 0.0f) + ry = rx; + if (rx < 0.0f) + rx = 0.0f; + if (ry < 0.0f) + ry = 0.0f; + if (rx > w / 2.0f) + rx = w / 2.0f; + if (ry > h / 2.0f) + ry = h / 2.0f; + + if (w != 0.0f && h != 0.0f) { + nsvg__resetPath(p); + + if (rx < 0.00001f || ry < 0.0001f) { + nsvg__moveTo(p, x, y); + nsvg__lineTo(p, x + w, y); + nsvg__lineTo(p, x + w, y + h); + nsvg__lineTo(p, x, y + h); + } + else { + // Rounded rectangle + nsvg__moveTo(p, x + rx, y); + nsvg__lineTo(p, x + w - rx, y); + nsvg__cubicBezTo(p, + x + w - rx * (1 - NSVG_KAPPA90), + y, + x + w, + y + ry * (1 - NSVG_KAPPA90), + x + w, + y + ry); + nsvg__lineTo(p, x + w, y + h - ry); + nsvg__cubicBezTo(p, + x + w, + y + h - ry * (1 - NSVG_KAPPA90), + x + w - rx * (1 - NSVG_KAPPA90), + y + h, + x + w - rx, + y + h); + nsvg__lineTo(p, x + rx, y + h); + nsvg__cubicBezTo(p, + x + rx * (1 - NSVG_KAPPA90), + y + h, + x, + y + h - ry * (1 - NSVG_KAPPA90), + x, + y + h - ry); + nsvg__lineTo(p, x, y + ry); + nsvg__cubicBezTo( + p, x, y + ry * (1 - NSVG_KAPPA90), x + rx * (1 - NSVG_KAPPA90), y, x + rx, y); + } + + nsvg__addPath(p, 1); + + nsvg__addShape(p); + } +} + +static void nsvg__parseCircle(NSVGparser *p, const char **attr) +{ + float cx = 0.0f; + float cy = 0.0f; + float r = 0.0f; + int i; + + for (i = 0; attr[i]; i += 2) { + if (!nsvg__parseAttr(p, attr[i], attr[i + 1])) { + if (strcmp(attr[i], "cx") == 0) + cx = nsvg__parseCoordinate(p, attr[i + 1], nsvg__actualOrigX(p), nsvg__actualWidth(p)); + if (strcmp(attr[i], "cy") == 0) + cy = nsvg__parseCoordinate(p, attr[i + 1], nsvg__actualOrigY(p), nsvg__actualHeight(p)); + if (strcmp(attr[i], "r") == 0) + r = fabsf(nsvg__parseCoordinate(p, attr[i + 1], 0.0f, nsvg__actualLength(p))); + } + } + + if (r > 0.0f) { + nsvg__resetPath(p); + + nsvg__moveTo(p, cx + r, cy); + nsvg__cubicBezTo(p, cx + r, cy + r * NSVG_KAPPA90, cx + r * NSVG_KAPPA90, cy + r, cx, cy + r); + nsvg__cubicBezTo(p, cx - r * NSVG_KAPPA90, cy + r, cx - r, cy + r * NSVG_KAPPA90, cx - r, cy); + nsvg__cubicBezTo(p, cx - r, cy - r * NSVG_KAPPA90, cx - r * NSVG_KAPPA90, cy - r, cx, cy - r); + nsvg__cubicBezTo(p, cx + r * NSVG_KAPPA90, cy - r, cx + r, cy - r * NSVG_KAPPA90, cx + r, cy); + + nsvg__addPath(p, 1); + + nsvg__addShape(p); + } +} + +static void nsvg__parseEllipse(NSVGparser *p, const char **attr) +{ + float cx = 0.0f; + float cy = 0.0f; + float rx = 0.0f; + float ry = 0.0f; + int i; + + for (i = 0; attr[i]; i += 2) { + if (!nsvg__parseAttr(p, attr[i], attr[i + 1])) { + if (strcmp(attr[i], "cx") == 0) + cx = nsvg__parseCoordinate(p, attr[i + 1], nsvg__actualOrigX(p), nsvg__actualWidth(p)); + if (strcmp(attr[i], "cy") == 0) + cy = nsvg__parseCoordinate(p, attr[i + 1], nsvg__actualOrigY(p), nsvg__actualHeight(p)); + if (strcmp(attr[i], "rx") == 0) + rx = fabsf(nsvg__parseCoordinate(p, attr[i + 1], 0.0f, nsvg__actualWidth(p))); + if (strcmp(attr[i], "ry") == 0) + ry = fabsf(nsvg__parseCoordinate(p, attr[i + 1], 0.0f, nsvg__actualHeight(p))); + } + } + + if (rx > 0.0f && ry > 0.0f) { + + nsvg__resetPath(p); + + nsvg__moveTo(p, cx + rx, cy); + nsvg__cubicBezTo( + p, cx + rx, cy + ry * NSVG_KAPPA90, cx + rx * NSVG_KAPPA90, cy + ry, cx, cy + ry); + nsvg__cubicBezTo( + p, cx - rx * NSVG_KAPPA90, cy + ry, cx - rx, cy + ry * NSVG_KAPPA90, cx - rx, cy); + nsvg__cubicBezTo( + p, cx - rx, cy - ry * NSVG_KAPPA90, cx - rx * NSVG_KAPPA90, cy - ry, cx, cy - ry); + nsvg__cubicBezTo( + p, cx + rx * NSVG_KAPPA90, cy - ry, cx + rx, cy - ry * NSVG_KAPPA90, cx + rx, cy); + + nsvg__addPath(p, 1); + + nsvg__addShape(p); + } +} + +static void nsvg__parseLine(NSVGparser *p, const char **attr) +{ + float x1 = 0.0; + float y1 = 0.0; + float x2 = 0.0; + float y2 = 0.0; + int i; + + for (i = 0; attr[i]; i += 2) { + if (!nsvg__parseAttr(p, attr[i], attr[i + 1])) { + if (strcmp(attr[i], "x1") == 0) + x1 = nsvg__parseCoordinate(p, attr[i + 1], nsvg__actualOrigX(p), nsvg__actualWidth(p)); + if (strcmp(attr[i], "y1") == 0) + y1 = nsvg__parseCoordinate(p, attr[i + 1], nsvg__actualOrigY(p), nsvg__actualHeight(p)); + if (strcmp(attr[i], "x2") == 0) + x2 = nsvg__parseCoordinate(p, attr[i + 1], nsvg__actualOrigX(p), nsvg__actualWidth(p)); + if (strcmp(attr[i], "y2") == 0) + y2 = nsvg__parseCoordinate(p, attr[i + 1], nsvg__actualOrigY(p), nsvg__actualHeight(p)); + } + } + + nsvg__resetPath(p); + + nsvg__moveTo(p, x1, y1); + nsvg__lineTo(p, x2, y2); + + nsvg__addPath(p, 0); + + nsvg__addShape(p); +} + +static void nsvg__parsePoly(NSVGparser *p, const char **attr, int closeFlag) +{ + int i; + const char *s; + float args[2]; + int nargs, npts = 0; + char item[64]; + + nsvg__resetPath(p); + + for (i = 0; attr[i]; i += 2) { + if (!nsvg__parseAttr(p, attr[i], attr[i + 1])) { + if (strcmp(attr[i], "points") == 0) { + s = attr[i + 1]; + nargs = 0; + while (*s) { + s = nsvg__getNextPathItem(s, item); + args[nargs++] = (float)nsvg__atof(item); + if (nargs >= 2) { + if (npts == 0) + nsvg__moveTo(p, args[0], args[1]); + else + nsvg__lineTo(p, args[0], args[1]); + nargs = 0; + npts++; + } + } + } + } + } + + nsvg__addPath(p, (char)closeFlag); + + nsvg__addShape(p); +} + +static void nsvg__parseSVG(NSVGparser *p, const char **attr) +{ + int i; + for (i = 0; attr[i]; i += 2) { + if (!nsvg__parseAttr(p, attr[i], attr[i + 1])) { + if (strcmp(attr[i], "width") == 0) { + p->image->width = nsvg__parseCoordinate(p, attr[i + 1], 0.0f, 0.0f); + } + else if (strcmp(attr[i], "height") == 0) { + p->image->height = nsvg__parseCoordinate(p, attr[i + 1], 0.0f, 0.0f); + } + else if (strcmp(attr[i], "viewBox") == 0) { + const char *s = attr[i + 1]; + char buf[64]; + s = nsvg__parseNumber(s, buf, 64); + p->viewMinx = nsvg__atof(buf); + while (*s && (nsvg__isspace(*s) || *s == '%' || *s == ',')) + s++; + if (!*s) + return; + s = nsvg__parseNumber(s, buf, 64); + p->viewMiny = nsvg__atof(buf); + while (*s && (nsvg__isspace(*s) || *s == '%' || *s == ',')) + s++; + if (!*s) + return; + s = nsvg__parseNumber(s, buf, 64); + p->viewWidth = nsvg__atof(buf); + while (*s && (nsvg__isspace(*s) || *s == '%' || *s == ',')) + s++; + if (!*s) + return; + s = nsvg__parseNumber(s, buf, 64); + p->viewHeight = nsvg__atof(buf); + } + else if (strcmp(attr[i], "preserveAspectRatio") == 0) { + if (strstr(attr[i + 1], "none") != 0) { + // No uniform scaling + p->alignType = NSVG_ALIGN_NONE; + } + else { + // Parse X align + if (strstr(attr[i + 1], "xMin") != 0) + p->alignX = NSVG_ALIGN_MIN; + else if (strstr(attr[i + 1], "xMid") != 0) + p->alignX = NSVG_ALIGN_MID; + else if (strstr(attr[i + 1], "xMax") != 0) + p->alignX = NSVG_ALIGN_MAX; + // Parse X align + if (strstr(attr[i + 1], "yMin") != 0) + p->alignY = NSVG_ALIGN_MIN; + else if (strstr(attr[i + 1], "yMid") != 0) + p->alignY = NSVG_ALIGN_MID; + else if (strstr(attr[i + 1], "yMax") != 0) + p->alignY = NSVG_ALIGN_MAX; + // Parse meet/slice + p->alignType = NSVG_ALIGN_MEET; + if (strstr(attr[i + 1], "slice") != 0) + p->alignType = NSVG_ALIGN_SLICE; + } + } + } + } +} + +static void nsvg__parseGradient(NSVGparser *p, const char **attr, char type) +{ + int i; + NSVGgradientData *grad = (NSVGgradientData *)malloc(sizeof(NSVGgradientData)); + if (grad == NULL) + return; + memset(grad, 0, sizeof(NSVGgradientData)); + grad->units = NSVG_OBJECT_SPACE; + grad->type = type; + if (grad->type == NSVG_PAINT_LINEAR_GRADIENT) { + grad->linear.x1 = nsvg__coord(0.0f, NSVG_UNITS_PERCENT); + grad->linear.y1 = nsvg__coord(0.0f, NSVG_UNITS_PERCENT); + grad->linear.x2 = nsvg__coord(100.0f, NSVG_UNITS_PERCENT); + grad->linear.y2 = nsvg__coord(0.0f, NSVG_UNITS_PERCENT); + } + else if (grad->type == NSVG_PAINT_RADIAL_GRADIENT) { + grad->radial.cx = nsvg__coord(50.0f, NSVG_UNITS_PERCENT); + grad->radial.cy = nsvg__coord(50.0f, NSVG_UNITS_PERCENT); + grad->radial.r = nsvg__coord(50.0f, NSVG_UNITS_PERCENT); + } + + nsvg__xformIdentity(grad->xform); + + for (i = 0; attr[i]; i += 2) { + if (strcmp(attr[i], "id") == 0) { + strncpy(grad->id, attr[i + 1], 63); + grad->id[63] = '\0'; + } + else if (!nsvg__parseAttr(p, attr[i], attr[i + 1])) { + if (strcmp(attr[i], "gradientUnits") == 0) { + if (strcmp(attr[i + 1], "objectBoundingBox") == 0) + grad->units = NSVG_OBJECT_SPACE; + else + grad->units = NSVG_USER_SPACE; + } + else if (strcmp(attr[i], "gradientTransform") == 0) { + nsvg__parseTransform(grad->xform, attr[i + 1]); + } + else if (strcmp(attr[i], "cx") == 0) { + grad->radial.cx = nsvg__parseCoordinateRaw(attr[i + 1]); + } + else if (strcmp(attr[i], "cy") == 0) { + grad->radial.cy = nsvg__parseCoordinateRaw(attr[i + 1]); + } + else if (strcmp(attr[i], "r") == 0) { + grad->radial.r = nsvg__parseCoordinateRaw(attr[i + 1]); + } + else if (strcmp(attr[i], "fx") == 0) { + grad->radial.fx = nsvg__parseCoordinateRaw(attr[i + 1]); + } + else if (strcmp(attr[i], "fy") == 0) { + grad->radial.fy = nsvg__parseCoordinateRaw(attr[i + 1]); + } + else if (strcmp(attr[i], "x1") == 0) { + grad->linear.x1 = nsvg__parseCoordinateRaw(attr[i + 1]); + } + else if (strcmp(attr[i], "y1") == 0) { + grad->linear.y1 = nsvg__parseCoordinateRaw(attr[i + 1]); + } + else if (strcmp(attr[i], "x2") == 0) { + grad->linear.x2 = nsvg__parseCoordinateRaw(attr[i + 1]); + } + else if (strcmp(attr[i], "y2") == 0) { + grad->linear.y2 = nsvg__parseCoordinateRaw(attr[i + 1]); + } + else if (strcmp(attr[i], "spreadMethod") == 0) { + if (strcmp(attr[i + 1], "pad") == 0) + grad->spread = NSVG_SPREAD_PAD; + else if (strcmp(attr[i + 1], "reflect") == 0) + grad->spread = NSVG_SPREAD_REFLECT; + else if (strcmp(attr[i + 1], "repeat") == 0) + grad->spread = NSVG_SPREAD_REPEAT; + } + else if (strcmp(attr[i], "xlink:href") == 0) { + const char *href = attr[i + 1]; + strncpy(grad->ref, href + 1, 62); + grad->ref[62] = '\0'; + } + } + } + + grad->next = p->gradients; + p->gradients = grad; +} + +static void nsvg__parseGradientStop(NSVGparser *p, const char **attr) +{ + NSVGattrib *curAttr = nsvg__getAttr(p); + NSVGgradientData *grad; + NSVGgradientStop *stop; + int i, idx; + + curAttr->stopOffset = 0; + curAttr->stopColor = 0; + curAttr->stopOpacity = 1.0f; + + for (i = 0; attr[i]; i += 2) { + nsvg__parseAttr(p, attr[i], attr[i + 1]); + } + + // Add stop to the last gradient. + grad = p->gradients; + if (grad == NULL) + return; + + grad->nstops++; + grad->stops = (NSVGgradientStop *)realloc(grad->stops, sizeof(NSVGgradientStop) * grad->nstops); + if (grad->stops == NULL) + return; + + // Insert + idx = grad->nstops - 1; + for (i = 0; i < grad->nstops - 1; i++) { + if (curAttr->stopOffset < grad->stops[i].offset) { + idx = i; + break; + } + } + if (idx != grad->nstops - 1) { + for (i = grad->nstops - 1; i > idx; i--) + grad->stops[i] = grad->stops[i - 1]; + } + + stop = &grad->stops[idx]; + stop->color = curAttr->stopColor; + stop->color |= (unsigned int)(curAttr->stopOpacity * 255) << 24; + stop->offset = curAttr->stopOffset; +} + +static void nsvg__startElement(void *ud, const char *el, const char **attr) +{ + NSVGparser *p = (NSVGparser *)ud; + + if (p->defsFlag) { + // Skip everything but gradients in defs + if (strcmp(el, "linearGradient") == 0) { + nsvg__parseGradient(p, attr, NSVG_PAINT_LINEAR_GRADIENT); + } + else if (strcmp(el, "radialGradient") == 0) { + nsvg__parseGradient(p, attr, NSVG_PAINT_RADIAL_GRADIENT); + } + else if (strcmp(el, "stop") == 0) { + nsvg__parseGradientStop(p, attr); + } + return; + } + + if (strcmp(el, "g") == 0) { + nsvg__pushAttr(p); + nsvg__parseAttribs(p, attr); + + /* Save the breadcrumb of groups. */ + if (p->breadcrumb_len < NSVG_MAX_BREADCRUMB) { + NSVGattrib *attr_id = nsvg__getAttr(p); + memcpy( + p->breadcrumb[p->breadcrumb_len], attr_id->id, sizeof(p->breadcrumb[p->breadcrumb_len])); + p->breadcrumb_len++; + } + } + else if (strcmp(el, "path") == 0) { + if (p->pathFlag) // Do not allow nested paths. + return; + nsvg__pushAttr(p); + nsvg__parsePath(p, attr); + nsvg__popAttr(p); + } + else if (strcmp(el, "rect") == 0) { + nsvg__pushAttr(p); + nsvg__parseRect(p, attr); + nsvg__popAttr(p); + } + else if (strcmp(el, "circle") == 0) { + nsvg__pushAttr(p); + nsvg__parseCircle(p, attr); + nsvg__popAttr(p); + } + else if (strcmp(el, "ellipse") == 0) { + nsvg__pushAttr(p); + nsvg__parseEllipse(p, attr); + nsvg__popAttr(p); + } + else if (strcmp(el, "line") == 0) { + nsvg__pushAttr(p); + nsvg__parseLine(p, attr); + nsvg__popAttr(p); + } + else if (strcmp(el, "polyline") == 0) { + nsvg__pushAttr(p); + nsvg__parsePoly(p, attr, 0); + nsvg__popAttr(p); + } + else if (strcmp(el, "polygon") == 0) { + nsvg__pushAttr(p); + nsvg__parsePoly(p, attr, 1); + nsvg__popAttr(p); + } + else if (strcmp(el, "linearGradient") == 0) { + nsvg__parseGradient(p, attr, NSVG_PAINT_LINEAR_GRADIENT); + } + else if (strcmp(el, "radialGradient") == 0) { + nsvg__parseGradient(p, attr, NSVG_PAINT_RADIAL_GRADIENT); + } + else if (strcmp(el, "stop") == 0) { + nsvg__parseGradientStop(p, attr); + } + else if (strcmp(el, "defs") == 0) { + p->defsFlag = 1; + } + else if (strcmp(el, "svg") == 0) { + nsvg__parseSVG(p, attr); + } +} + +static void nsvg__endElement(void *ud, const char *el) +{ + NSVGparser *p = (NSVGparser *)ud; + + if (strcmp(el, "g") == 0) { + /* Remove the breadcrumb level. */ + if (p->breadcrumb_len > 0) { + p->breadcrumb[p->breadcrumb_len - 1][0] = '\0'; + p->breadcrumb_len--; + } + + nsvg__popAttr(p); + } + else if (strcmp(el, "path") == 0) { + p->pathFlag = 0; + } + else if (strcmp(el, "defs") == 0) { + p->defsFlag = 0; + } +} + +static void nsvg__content(void *ud, const char *s) +{ + NSVG_NOTUSED(ud); + NSVG_NOTUSED(s); + // empty +} + +static void nsvg__imageBounds(NSVGparser *p, float *bounds) +{ + NSVGshape *shape; + shape = p->image->shapes; + if (shape == NULL) { + bounds[0] = bounds[1] = bounds[2] = bounds[3] = 0.0; + return; + } + bounds[0] = shape->bounds[0]; + bounds[1] = shape->bounds[1]; + bounds[2] = shape->bounds[2]; + bounds[3] = shape->bounds[3]; + for (shape = shape->next; shape != NULL; shape = shape->next) { + bounds[0] = nsvg__minf(bounds[0], shape->bounds[0]); + bounds[1] = nsvg__minf(bounds[1], shape->bounds[1]); + bounds[2] = nsvg__maxf(bounds[2], shape->bounds[2]); + bounds[3] = nsvg__maxf(bounds[3], shape->bounds[3]); + } +} + +static float nsvg__viewAlign(float content, float container, int type) +{ + if (type == NSVG_ALIGN_MIN) + return 0; + else if (type == NSVG_ALIGN_MAX) + return container - content; + // mid + return (container - content) * 0.5f; +} + +static void nsvg__scaleGradient(NSVGgradient *grad, float tx, float ty, float sx, float sy) +{ + float t[6]; + nsvg__xformSetTranslation(t, tx, ty); + nsvg__xformMultiply(grad->xform, t); + + nsvg__xformSetScale(t, sx, sy); + nsvg__xformMultiply(grad->xform, t); +} + +static void nsvg__scaleToViewbox(NSVGparser *p, const char *units) +{ + NSVGshape *shape; + NSVGpath *path; + float tx, ty, sx, sy, us, bounds[4], t[6], avgs; + int i; + float *pt; + + // Guess image size if not set completely. + nsvg__imageBounds(p, bounds); + + if (p->viewWidth == 0) { + if (p->image->width > 0) { + p->viewWidth = p->image->width; + } + else { + p->viewMinx = bounds[0]; + p->viewWidth = bounds[2] - bounds[0]; + } + } + if (p->viewHeight == 0) { + if (p->image->height > 0) { + p->viewHeight = p->image->height; + } + else { + p->viewMiny = bounds[1]; + p->viewHeight = bounds[3] - bounds[1]; + } + } + if (p->image->width == 0) + p->image->width = p->viewWidth; + if (p->image->height == 0) + p->image->height = p->viewHeight; + + tx = -p->viewMinx; + ty = -p->viewMiny; + sx = p->viewWidth > 0 ? p->image->width / p->viewWidth : 0; + sy = p->viewHeight > 0 ? p->image->height / p->viewHeight : 0; + // Unit scaling + us = 1.0f / nsvg__convertToPixels(p, nsvg__coord(1.0f, nsvg__parseUnits(units)), 0.0f, 1.0f); + + // Fix aspect ratio + if (p->alignType == NSVG_ALIGN_MEET) { + // fit whole image into viewbox + sx = sy = nsvg__minf(sx, sy); + tx += nsvg__viewAlign(p->viewWidth * sx, p->image->width, p->alignX) / sx; + ty += nsvg__viewAlign(p->viewHeight * sy, p->image->height, p->alignY) / sy; + } + else if (p->alignType == NSVG_ALIGN_SLICE) { + // fill whole viewbox with image + sx = sy = nsvg__maxf(sx, sy); + tx += nsvg__viewAlign(p->viewWidth * sx, p->image->width, p->alignX) / sx; + ty += nsvg__viewAlign(p->viewHeight * sy, p->image->height, p->alignY) / sy; + } + + // Transform + sx *= us; + sy *= us; + avgs = (sx + sy) / 2.0f; + for (shape = p->image->shapes; shape != NULL; shape = shape->next) { + shape->bounds[0] = (shape->bounds[0] + tx) * sx; + shape->bounds[1] = (shape->bounds[1] + ty) * sy; + shape->bounds[2] = (shape->bounds[2] + tx) * sx; + shape->bounds[3] = (shape->bounds[3] + ty) * sy; + for (path = shape->paths; path != NULL; path = path->next) { + path->bounds[0] = (path->bounds[0] + tx) * sx; + path->bounds[1] = (path->bounds[1] + ty) * sy; + path->bounds[2] = (path->bounds[2] + tx) * sx; + path->bounds[3] = (path->bounds[3] + ty) * sy; + for (i = 0; i < path->npts; i++) { + pt = &path->pts[i * 2]; + pt[0] = (pt[0] + tx) * sx; + pt[1] = (pt[1] + ty) * sy; + } + } + + if (shape->fill.type == NSVG_PAINT_LINEAR_GRADIENT || + shape->fill.type == NSVG_PAINT_RADIAL_GRADIENT) { + nsvg__scaleGradient(shape->fill.gradient, tx, ty, sx, sy); + memcpy(t, shape->fill.gradient->xform, sizeof(float) * 6); + nsvg__xformInverse(shape->fill.gradient->xform, t); + } + if (shape->stroke.type == NSVG_PAINT_LINEAR_GRADIENT || + shape->stroke.type == NSVG_PAINT_RADIAL_GRADIENT) { + nsvg__scaleGradient(shape->stroke.gradient, tx, ty, sx, sy); + memcpy(t, shape->stroke.gradient->xform, sizeof(float) * 6); + nsvg__xformInverse(shape->stroke.gradient->xform, t); + } + + shape->strokeWidth *= avgs; + shape->strokeDashOffset *= avgs; + for (i = 0; i < shape->strokeDashCount; i++) + shape->strokeDashArray[i] *= avgs; + } +} + +NSVGimage *nsvgParse(char *input, const char *units, float dpi) +{ + NSVGparser *p; + NSVGimage *ret = 0; + + p = nsvg__createParser(); + if (p == NULL) { + return NULL; + } + p->dpi = dpi; + + nsvg__parseXML(input, nsvg__startElement, nsvg__endElement, nsvg__content, p); + + // Scale to viewBox + nsvg__scaleToViewbox(p, units); + + ret = p->image; + p->image = NULL; + + nsvg__deleteParser(p); + + return ret; +} + +NSVGimage *nsvgParseFromFile(const char *filename, const char *units, float dpi) +{ + FILE *fp = NULL; + size_t size; + char *data = NULL; + NSVGimage *image = NULL; + + fp = fopen(filename, "rb"); + if (!fp) + goto error; + fseek(fp, 0, SEEK_END); + size = ftell(fp); + fseek(fp, 0, SEEK_SET); + data = (char *)malloc(size + 1); + if (data == NULL) + goto error; + if (fread(data, 1, size, fp) != size) + goto error; + data[size] = '\0'; // Must be null terminated. + fclose(fp); + image = nsvgParse(data, units, dpi); + free(data); + + return image; + +error: + if (fp) + fclose(fp); + if (data) + free(data); + if (image) + nsvgDelete(image); + return NULL; +} + +NSVGpath *nsvgDuplicatePath(NSVGpath *p) +{ + NSVGpath *res = NULL; + + if (p == NULL) + return NULL; + + res = (NSVGpath *)malloc(sizeof(NSVGpath)); + if (res == NULL) + goto error; + memset(res, 0, sizeof(NSVGpath)); + + res->pts = (float *)malloc(p->npts * 2 * sizeof(float)); + if (res->pts == NULL) + goto error; + memcpy(res->pts, p->pts, p->npts * sizeof(float) * 2); + res->npts = p->npts; + + memcpy(res->bounds, p->bounds, sizeof(p->bounds)); + + res->closed = p->closed; + + return res; + +error: + if (res != NULL) { + free(res->pts); + free(res); + } + return NULL; +} + +void nsvgDelete(NSVGimage *image) +{ + NSVGshape *snext, *shape; + if (image == NULL) + return; + shape = image->shapes; + while (shape != NULL) { + snext = shape->next; + nsvg__deletePaths(shape->paths); + nsvg__deletePaint(&shape->fill); + nsvg__deletePaint(&shape->stroke); + free(shape); + shape = snext; + } + free(image); +} + +#endif diff --git a/source/blender/makesdna/DNA_ID.h b/source/blender/makesdna/DNA_ID.h index 077f9bf8bdc..d88db091cc2 100644 --- a/source/blender/makesdna/DNA_ID.h +++ b/source/blender/makesdna/DNA_ID.h @@ -763,19 +763,53 @@ typedef enum IDRecalcFlag { * See e.g. how #BKE_library_unused_linked_data_set_tag is doing this. */ enum { + /* Special case: Library, should never ever depend on any other type. */ INDEX_ID_LI = 0, - INDEX_ID_IP, + + /* Animation types, might be used by almost all other types. */ + INDEX_ID_IP, /* Deprecated. */ INDEX_ID_AC, - INDEX_ID_KE, - INDEX_ID_PAL, + + /* Grease Pencil, special case, should be with the other obdata, but it can also be used by many + * other ID types, including node trees e.g. + * So there is no proper place for those, for now keep close to the lower end of the processing + * hierarchy, but we may want to re-evaluate that at some point. */ INDEX_ID_GD, + + /* Node trees, abstraction for procedural data, potentially used by many other ID types. + * + * NOTE: While node trees can also use many other ID types, they should not /own/ any of those, + * while they are being owned by many other ID types. This is why they are placed here. */ INDEX_ID_NT, + + /* File-wrapper types, those usually 'embed' external files in Blender, with no dependencies to + * other ID types. */ + INDEX_ID_VF, + INDEX_ID_TXT, + INDEX_ID_SO, + + /* Image/movie types, can be used by shading ID types, but also directly by Objects, Scenes, etc. + */ + INDEX_ID_MSK, INDEX_ID_IM, + INDEX_ID_MC, + + /* Shading types. */ INDEX_ID_TE, INDEX_ID_MA, - INDEX_ID_VF, - INDEX_ID_AR, + INDEX_ID_LS, + INDEX_ID_WO, + + /* Simulation-related types. */ INDEX_ID_CF, + INDEX_ID_SIM, + INDEX_ID_PA, + + /* Shape Keys snow-flake, can be used by several obdata types. */ + INDEX_ID_KE, + + /* Object data types. */ + INDEX_ID_AR, INDEX_ID_ME, INDEX_ID_CU, INDEX_ID_MB, @@ -785,26 +819,28 @@ enum { INDEX_ID_LT, INDEX_ID_LA, INDEX_ID_CA, - INDEX_ID_TXT, - INDEX_ID_SO, - INDEX_ID_GR, - INDEX_ID_PC, - INDEX_ID_BR, - INDEX_ID_PA, INDEX_ID_SPK, INDEX_ID_LP, - INDEX_ID_WO, - INDEX_ID_MC, - INDEX_ID_SCR, + + /* Collection and object types. */ INDEX_ID_OB, - INDEX_ID_LS, + INDEX_ID_GR, + + /* Preset-like, not-really-data types, can use many other ID types but should never be used by + * any actual data type (besides Scene, due to tool settings). */ + INDEX_ID_PAL, + INDEX_ID_PC, + INDEX_ID_BR, + + /* Scene, after preset-like ID types because of tool settings. */ INDEX_ID_SCE, + + /* UI-related types, should never be used by any other data type. */ + INDEX_ID_SCR, INDEX_ID_WS, INDEX_ID_WM, - /* TODO: This should probably be tweaked, #Mask and #Simulation are rather low-level types that - * should most likely be defined //before// #Object and geometry type indices? */ - INDEX_ID_MSK, - INDEX_ID_SIM, + + /* Special values. */ INDEX_ID_NULL, INDEX_ID_MAX, }; diff --git a/source/blender/makesdna/DNA_armature_types.h b/source/blender/makesdna/DNA_armature_types.h index 09304ce09f2..85780bc33c5 100644 --- a/source/blender/makesdna/DNA_armature_types.h +++ b/source/blender/makesdna/DNA_armature_types.h @@ -134,7 +134,7 @@ typedef struct bArmature { /** ID data is older than edit-mode data (TODO: move to edit-mode struct). */ char needs_flush_to_id; - char _pad0[7]; + char _pad0[3]; int flag; int drawtype; @@ -146,6 +146,9 @@ typedef struct bArmature { unsigned int layer_used; /** For buttons to work, both variables in this order together. */ unsigned int layer, layer_protected; + + /** Relative position of the axes on the bone, from head (0.0f) to tail (1.0f). */ + float axes_position; } bArmature; /* armature->flag */ @@ -230,8 +233,10 @@ typedef enum eBone_Flag { BONE_MULT_VG_ENV = (1 << 11), /** bone doesn't deform geometry */ BONE_NO_DEFORM = (1 << 12), +#ifdef DNA_DEPRECATED_ALLOW /** set to prevent destruction of its unkeyframed pose (after transform) */ BONE_UNKEYED = (1 << 13), +#endif /** set to prevent hinge child bones from influencing the transform center */ BONE_HINGE_CHILD_TRANSFORM = (1 << 14), #ifdef DNA_DEPRECATED_ALLOW diff --git a/source/blender/makesdna/DNA_curve_types.h b/source/blender/makesdna/DNA_curve_types.h index 4f914089347..ff2e7fc500a 100644 --- a/source/blender/makesdna/DNA_curve_types.h +++ b/source/blender/makesdna/DNA_curve_types.h @@ -72,7 +72,7 @@ typedef struct BevPoint { float sina, cosa; /** 3D Only. */ float dir[3], tan[3], quat[4]; - short split_tag, dupe_tag; + short dupe_tag; } BevPoint; /* These two Lines with # tell makesdna this struct can be excluded. */ diff --git a/source/blender/makesdna/DNA_node_types.h b/source/blender/makesdna/DNA_node_types.h index f24d0e40d19..7b4788737f8 100644 --- a/source/blender/makesdna/DNA_node_types.h +++ b/source/blender/makesdna/DNA_node_types.h @@ -715,6 +715,12 @@ typedef struct NodeBilateralBlurData { char _pad[2]; } NodeBilateralBlurData; +typedef struct NodeAntiAliasingData { + float threshold; + float contrast_limit; + float corner_rounding; +} NodeAntiAliasingData; + /* NOTE: Only for do-version code. */ typedef struct NodeHueSat { float hue, sat, val; @@ -1108,6 +1114,14 @@ typedef struct NodeDenoise { char hdr; } NodeDenoise; +typedef struct NodeAttributeClamp { + /* CustomDataType. */ + uint8_t data_type; + + /* NodeClampOperation. */ + uint8_t operation; +} NodeAttributeClamp; + typedef struct NodeAttributeCompare { /* FloatCompareOperation. */ uint8_t operation; @@ -1119,6 +1133,14 @@ typedef struct NodeAttributeCompare { char _pad[5]; } NodeAttributeCompare; +typedef struct NodeAttributeMapRange { + /* GeometryNodeAttributeDataType */ + uint8_t data_type; + + /* NodeMapRangeType. */ + uint8_t interpolation_type; +} NodeAttributeMapRange; + typedef struct NodeAttributeMath { /* NodeMathOperation. */ uint8_t operation; diff --git a/source/blender/makesdna/DNA_userdef_types.h b/source/blender/makesdna/DNA_userdef_types.h index 4595b12e9d4..334669d3433 100644 --- a/source/blender/makesdna/DNA_userdef_types.h +++ b/source/blender/makesdna/DNA_userdef_types.h @@ -646,7 +646,8 @@ typedef struct UserDef_Experimental { char use_switch_object_operator; char use_sculpt_tools_tilt; char use_asset_browser; - char _pad[6]; + char use_override_templates; + char _pad[5]; /** `makesdna` does not allow empty structs. */ } UserDef_Experimental; diff --git a/source/blender/makesdna/DNA_view3d_types.h b/source/blender/makesdna/DNA_view3d_types.h index b8e2256c3c6..2f4e4e57b9f 100644 --- a/source/blender/makesdna/DNA_view3d_types.h +++ b/source/blender/makesdna/DNA_view3d_types.h @@ -367,7 +367,7 @@ typedef struct View3D { #define V3D_LOCAL_COLLECTIONS (1 << 0) #define V3D_FLAG_UNUSED_1 (1 << 1) /* cleared */ #define V3D_HIDE_HELPLINES (1 << 2) -#define V3D_INVALID_BACKBUF (1 << 3) +#define V3D_FLAG_UNUSED_2 (1 << 3) /* cleared */ #define V3D_XR_SESSION_MIRROR (1 << 4) #define V3D_FLAG_UNUSED_10 (1 << 10) /* cleared */ @@ -380,6 +380,8 @@ typedef struct View3D { enum { /** The 3D view which the XR session was created in is flagged with this. */ V3D_RUNTIME_XR_SESSION_ROOT = (1 << 0), + /** Some operators override the depth buffer for dedicated occlusion operations. */ + V3D_RUNTIME_DEPTHBUF_OVERRIDDEN = (1 << 1), }; /** #RegionView3D.persp */ diff --git a/source/blender/makesdna/intern/dna_genfile.c b/source/blender/makesdna/intern/dna_genfile.c index 3690a1126d4..d199638710d 100644 --- a/source/blender/makesdna/intern/dna_genfile.c +++ b/source/blender/makesdna/intern/dna_genfile.c @@ -1194,7 +1194,10 @@ static void reconstruct_struct(const DNA_ReconstructInfo *reconstruct_info, new_block + step->data.substruct.new_offset); break; case RECONSTRUCT_STEP_INIT_ZERO: - /* Do nothing, because the memory block has been calloced. */ + /* Do nothing, because the memory block are zeroed (from #MEM_callocN). + * + * Note that the struct could be initialized with the default struct, + * however this complicates versioning, especially with flags, see: D4500. */ break; } } diff --git a/source/blender/makesrna/RNA_types.h b/source/blender/makesrna/RNA_types.h index c4f6707dad5..78192f937e6 100644 --- a/source/blender/makesrna/RNA_types.h +++ b/source/blender/makesrna/RNA_types.h @@ -619,7 +619,7 @@ typedef enum StructFlag { /** Indicates that this struct is an ID struct, and to use reference-counting. */ STRUCT_ID = (1 << 0), STRUCT_ID_REFCOUNT = (1 << 1), - /** defaults on, clear for user preferences and similar */ + /** defaults on, indicates when changes in members of a StructRNA should trigger undo steps. */ STRUCT_UNDO = (1 << 2), /* internal flags */ diff --git a/source/blender/makesrna/intern/rna_ID.c b/source/blender/makesrna/intern/rna_ID.c index d51fcba410a..f750ea8f665 100644 --- a/source/blender/makesrna/intern/rna_ID.c +++ b/source/blender/makesrna/intern/rna_ID.c @@ -85,6 +85,47 @@ const EnumPropertyItem rna_enum_id_type_items[] = { {0, NULL, 0, NULL, NULL}, }; +static const EnumPropertyItem rna_enum_override_library_property_operation_items[] = { + {IDOVERRIDE_LIBRARY_OP_NOOP, + "NOOP", + 0, + "No-Op", + "Does nothing, prevents adding actual overrides (NOT USED)"}, + {IDOVERRIDE_LIBRARY_OP_REPLACE, + "REPLACE", + 0, + "Replace", + "Replace value of reference by overriding one"}, + {IDOVERRIDE_LIBRARY_OP_ADD, + "DIFF_ADD", + 0, + "Differential", + "Stores and apply difference between reference and local value (NOT USED)"}, + {IDOVERRIDE_LIBRARY_OP_SUBTRACT, + "DIFF_SUB", + 0, + "Differential", + "Stores and apply difference between reference and local value (NOT USED)"}, + {IDOVERRIDE_LIBRARY_OP_MULTIPLY, + "FACT_MULTIPLY", + 0, + "Factor", + "Stores and apply multiplication factor between reference and local value (NOT USED)"}, + {IDOVERRIDE_LIBRARY_OP_INSERT_AFTER, + "INSERT_AFTER", + 0, + "Insert After", + "Insert a new item into collection after the one referenced in subitem_reference_name or " + "_index"}, + {IDOVERRIDE_LIBRARY_OP_INSERT_BEFORE, + "INSERT_BEFORE", + 0, + "Insert Before", + "Insert a new item into collection after the one referenced in subitem_reference_name or " + "_index (NOT USED)"}, + {0, NULL, 0, NULL, NULL}, +}; + /** * \note Uses #IDFilterEnumPropertyItem, not EnumPropertyItem to support 64 bit items. */ @@ -643,6 +684,65 @@ static ID *rna_ID_override_create(ID *id, Main *bmain, bool remap_local_usages) return local_id; } +static void rna_ID_override_template_create(ID *id, ReportList *reports) +{ + if (!U.experimental.use_override_templates) { + BKE_report(reports, RPT_ERROR, "Override template experimental feature is disabled"); + return; + } + if (ID_IS_LINKED(id)) { + BKE_report(reports, RPT_ERROR, "Unable to create override template for linked data-blocks"); + return; + } + if (ID_IS_OVERRIDE_LIBRARY(id)) { + BKE_report( + reports, RPT_ERROR, "Unable to create override template for overridden data-blocks"); + return; + } + BKE_lib_override_library_template_create(id); +} + +static IDOverrideLibraryProperty *rna_ID_override_library_properties_add( + IDOverrideLibrary *override_library, ReportList *reports, const char rna_path[]) +{ + bool created; + IDOverrideLibraryProperty *result = BKE_lib_override_library_property_get( + override_library, rna_path, &created); + + if (!created) { + BKE_report(reports, RPT_DEBUG, "No new override property created, property already exists"); + } + + return result; +} + +static IDOverrideLibraryPropertyOperation *rna_ID_override_library_property_operations_add( + IDOverrideLibraryProperty *override_property, + ReportList *reports, + int operation, + const char *subitem_refname, + const char *subitem_locname, + int subitem_refindex, + int subitem_locindex) +{ + bool created; + bool strict; + IDOverrideLibraryPropertyOperation *result = BKE_lib_override_library_property_operation_get( + override_property, + operation, + subitem_refname, + subitem_locname, + subitem_refindex, + subitem_locindex, + false, + &strict, + &created); + if (!created) { + BKE_report(reports, RPT_DEBUG, "No new override operation created, operation already exists"); + } + return result; +} + static void rna_ID_update_tag(ID *id, Main *bmain, ReportList *reports, int flag) { /* XXX, new function for this! */ @@ -1358,47 +1458,6 @@ static void rna_def_ID_override_library_property_operation(BlenderRNA *brna) StructRNA *srna; PropertyRNA *prop; - static const EnumPropertyItem override_library_property_operation_items[] = { - {IDOVERRIDE_LIBRARY_OP_NOOP, - "NOOP", - 0, - "No-Op", - "Does nothing, prevents adding actual overrides (NOT USED)"}, - {IDOVERRIDE_LIBRARY_OP_REPLACE, - "REPLACE", - 0, - "Replace", - "Replace value of reference by overriding one"}, - {IDOVERRIDE_LIBRARY_OP_ADD, - "DIFF_ADD", - 0, - "Differential", - "Stores and apply difference between reference and local value (NOT USED)"}, - {IDOVERRIDE_LIBRARY_OP_SUBTRACT, - "DIFF_SUB", - 0, - "Differential", - "Stores and apply difference between reference and local value (NOT USED)"}, - {IDOVERRIDE_LIBRARY_OP_MULTIPLY, - "FACT_MULTIPLY", - 0, - "Factor", - "Stores and apply multiplication factor between reference and local value (NOT USED)"}, - {IDOVERRIDE_LIBRARY_OP_INSERT_AFTER, - "INSERT_AFTER", - 0, - "Insert After", - "Insert a new item into collection after the one referenced in subitem_reference_name or " - "_index"}, - {IDOVERRIDE_LIBRARY_OP_INSERT_BEFORE, - "INSERT_BEFORE", - 0, - "Insert Before", - "Insert a new item into collection after the one referenced in subitem_reference_name or " - "_index (NOT USED)"}, - {0, NULL, 0, NULL, NULL}, - }; - static const EnumPropertyItem override_library_property_flag_items[] = { {IDOVERRIDE_LIBRARY_FLAG_MANDATORY, "MANDATORY", @@ -1420,7 +1479,7 @@ static void rna_def_ID_override_library_property_operation(BlenderRNA *brna) prop = RNA_def_enum(srna, "operation", - override_library_property_operation_items, + rna_enum_override_library_property_operation_items, IDOVERRIDE_LIBRARY_OP_REPLACE, "Operation", "What override operation is performed"); @@ -1477,6 +1536,66 @@ static void rna_def_ID_override_library_property_operation(BlenderRNA *brna) RNA_def_property_clear_flag(prop, PROP_EDITABLE); /* For now. */ } +static void rna_def_ID_override_library_property_operations(BlenderRNA *brna, PropertyRNA *cprop) +{ + StructRNA *srna; + FunctionRNA *func; + PropertyRNA *parm; + + RNA_def_property_srna(cprop, "IDOverrideLibraryPropertyOperations"); + srna = RNA_def_struct(brna, "IDOverrideLibraryPropertyOperations", NULL); + RNA_def_struct_sdna(srna, "IDOverrideLibraryProperty"); + RNA_def_struct_ui_text(srna, "Override Operations", "Collection of override operations"); + + /* Add Property */ + func = RNA_def_function(srna, "add", "rna_ID_override_library_property_operations_add"); + RNA_def_function_ui_description(func, "Add a new operation"); + RNA_def_function_flag(func, FUNC_USE_REPORTS); + parm = RNA_def_enum(func, + "operation", + rna_enum_override_library_property_operation_items, + IDOVERRIDE_LIBRARY_OP_REPLACE, + "Operation", + "What override operation is performed"); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); + parm = RNA_def_string(func, + "subitem_reference_name", + NULL, + INT_MAX, + "Subitem Reference Name", + "Used to handle insertions into collection"); + parm = RNA_def_string(func, + "subitem_local_name", + NULL, + INT_MAX, + "Subitem Local Name", + "Used to handle insertions into collection"); + parm = RNA_def_int(func, + "subitem_reference_index", + -1, + -1, + INT_MAX, + "Subitem Reference Index", + "Used to handle insertions into collection", + -1, + INT_MAX); + parm = RNA_def_int(func, + "subitem_local_index", + -1, + -1, + INT_MAX, + "Subitem Local Index", + "Used to handle insertions into collection", + -1, + INT_MAX); + parm = RNA_def_pointer(func, + "property", + "IDOverrideLibraryPropertyOperation", + "New Operation", + "Created operation"); + RNA_def_function_return(func, parm); +} + static void rna_def_ID_override_library_property(BlenderRNA *brna) { StructRNA *srna; @@ -1496,18 +1615,47 @@ static void rna_def_ID_override_library_property(BlenderRNA *brna) "RNA path leading to that property, from owning ID"); RNA_def_property_clear_flag(prop, PROP_EDITABLE); /* For now. */ - RNA_def_collection(srna, - "operations", - "IDOverrideLibraryPropertyOperation", - "Operations", - "List of overriding operations for a property"); + prop = RNA_def_collection(srna, + "operations", + "IDOverrideLibraryPropertyOperation", + "Operations", + "List of overriding operations for a property"); + rna_def_ID_override_library_property_operations(brna, prop); rna_def_ID_override_library_property_operation(brna); } +static void rna_def_ID_override_library_properties(BlenderRNA *brna, PropertyRNA *cprop) +{ + StructRNA *srna; + FunctionRNA *func; + PropertyRNA *parm; + + RNA_def_property_srna(cprop, "IDOverrideLibraryProperties"); + srna = RNA_def_struct(brna, "IDOverrideLibraryProperties", NULL); + RNA_def_struct_sdna(srna, "IDOverrideLibrary"); + RNA_def_struct_ui_text(srna, "Override Properties", "Collection of override properties"); + + /* Add Property */ + func = RNA_def_function(srna, "add", "rna_ID_override_library_properties_add"); + RNA_def_function_ui_description( + func, "Add a property to the override library when it doesn't exist yet"); + RNA_def_function_flag(func, FUNC_USE_REPORTS); + parm = RNA_def_pointer(func, + "property", + "IDOverrideLibraryProperty", + "New Property", + "Newly created override property or existing one"); + RNA_def_function_return(func, parm); + parm = RNA_def_string( + func, "rna_path", NULL, 256, "RNA Path", "RNA-Path of the property to add"); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); +} + static void rna_def_ID_override_library(BlenderRNA *brna) { StructRNA *srna; + PropertyRNA *prop; srna = RNA_def_struct(brna, "IDOverrideLibrary", NULL); RNA_def_struct_ui_text( @@ -1516,11 +1664,12 @@ static void rna_def_ID_override_library(BlenderRNA *brna) RNA_def_pointer( srna, "reference", "ID", "Reference ID", "Linked ID used as reference by this override"); - RNA_def_collection(srna, - "properties", - "IDOverrideLibraryProperty", - "Properties", - "List of overridden properties"); + prop = RNA_def_collection(srna, + "properties", + "IDOverrideLibraryProperty", + "Properties", + "List of overridden properties"); + rna_def_ID_override_library_properties(brna, prop); rna_def_ID_override_library_property(brna); } @@ -1672,6 +1821,10 @@ static void rna_def_ID(BlenderRNA *brna) "Whether local usages of the linked ID should be remapped to the new " "library override of it"); + func = RNA_def_function(srna, "override_template_create", "rna_ID_override_template_create"); + RNA_def_function_ui_description(func, "Create an override template for this ID"); + RNA_def_function_flag(func, FUNC_USE_REPORTS); + func = RNA_def_function(srna, "user_clear", "rna_ID_user_clear"); RNA_def_function_ui_description(func, "Clear the user count of a data-block so its not saved, " diff --git a/source/blender/makesrna/intern/rna_access_compare_override.c b/source/blender/makesrna/intern/rna_access_compare_override.c index 80833d4f992..39e7774e5a4 100644 --- a/source/blender/makesrna/intern/rna_access_compare_override.c +++ b/source/blender/makesrna/intern/rna_access_compare_override.c @@ -1098,6 +1098,10 @@ static void rna_property_override_check_resync(Main *bmain, ID *id_dst = rna_property_override_property_real_id_owner(bmain, ptr_item_dst, NULL, NULL); BLI_assert(id_src == NULL || ID_IS_OVERRIDE_LIBRARY_REAL(id_src)); + /* Work around file corruption on writing, see T86853. */ + if (id_src != NULL && !ID_IS_OVERRIDE_LIBRARY_REAL(id_src)) { + return; + } if (/* We might be in a case where id_dst has already been processed and its usages * remapped to its new local override. In that case overrides and linked data diff --git a/source/blender/makesrna/intern/rna_action.c b/source/blender/makesrna/intern/rna_action.c index 69ddcee60fa..fb9f5e0292e 100644 --- a/source/blender/makesrna/intern/rna_action.c +++ b/source/blender/makesrna/intern/rna_action.c @@ -407,8 +407,10 @@ static void rna_def_dopesheet(BlenderRNA *brna) /* Multi-word fuzzy search option for name/text filters */ prop = RNA_def_property(srna, "use_multi_word_filter", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", ADS_FLAG_FUZZY_NAMES); - RNA_def_property_ui_text( - prop, "Multi-Word Fuzzy Filter", "Perform fuzzy/multi-word matching (WARNING: May be slow)"); + RNA_def_property_ui_text(prop, + "Multi-Word Fuzzy Filter", + "Perform fuzzy/multi-word matching.\n" + "Warning: May be slow"); RNA_def_property_ui_icon(prop, ICON_SORTALPHA, 0); RNA_def_property_update(prop, NC_ANIMATION | ND_ANIMCHAN | NA_EDITED, NULL); diff --git a/source/blender/makesrna/intern/rna_action_api.c b/source/blender/makesrna/intern/rna_action_api.c index 48da32afba5..308a34f9cf1 100644 --- a/source/blender/makesrna/intern/rna_action_api.c +++ b/source/blender/makesrna/intern/rna_action_api.c @@ -41,10 +41,32 @@ # include "DNA_anim_types.h" # include "DNA_curve_types.h" +static void rna_Action_flip_with_pose(bAction *act, ReportList *reports, Object *ob) +{ + if (ob->type != OB_ARMATURE) { + BKE_report(reports, RPT_ERROR, "Only armature objects are supported"); + return; + } + BKE_action_flip_with_pose(act, ob); + + /* Only for redraw. */ + WM_main_add_notifier(NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL); +} + #else -void RNA_api_action(StructRNA *UNUSED(srna)) +void RNA_api_action(StructRNA *srna) { + FunctionRNA *func; + PropertyRNA *parm; + + func = RNA_def_function(srna, "flip_with_pose", "rna_Action_flip_with_pose"); + RNA_def_function_ui_description(func, "Flip the action around the X axis using a pose"); + RNA_def_function_flag(func, FUNC_USE_REPORTS); + + parm = RNA_def_pointer( + func, "object", "Object", "", "The reference armature object to use when flipping"); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED); } #endif diff --git a/source/blender/makesrna/intern/rna_armature.c b/source/blender/makesrna/intern/rna_armature.c index 554f04ca23c..c54621372ba 100644 --- a/source/blender/makesrna/intern/rna_armature.c +++ b/source/blender/makesrna/intern/rna_armature.c @@ -1537,6 +1537,16 @@ static void rna_def_armature(BlenderRNA *brna) RNA_def_property_update(prop, 0, "rna_Armature_redraw_data"); RNA_def_property_flag(prop, PROP_LIB_EXCEPTION); + prop = RNA_def_property(srna, "axes_position", PROP_FLOAT, PROP_FACTOR); + RNA_def_property_float_sdna(prop, NULL, "axes_position"); + RNA_def_property_range(prop, 0.0, 1.0); + RNA_def_property_ui_range(prop, 0.0, 1.0, 10, 1); + RNA_def_property_ui_text(prop, + "Axes Position", + "The position for the axes on the bone. Increasing the value moves it " + "closer to the tip; decreasing moves it closer to the root"); + RNA_def_property_update(prop, 0, "rna_Armature_redraw_data"); + prop = RNA_def_property(srna, "show_names", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", ARM_DRAWNAMES); RNA_def_property_ui_text(prop, "Display Names", "Display bone names"); diff --git a/source/blender/makesrna/intern/rna_attribute.c b/source/blender/makesrna/intern/rna_attribute.c index 8e3d2c9b9a2..7976df3e4e4 100644 --- a/source/blender/makesrna/intern/rna_attribute.c +++ b/source/blender/makesrna/intern/rna_attribute.c @@ -54,8 +54,8 @@ const EnumPropertyItem rna_enum_attribute_domain_items[] = { // {ATTR_DOMAIN_GEOMETRY, "GEOMETRY", 0, "Geometry", "Attribute on (whole) geometry"}, {ATTR_DOMAIN_POINT, "POINT", 0, "Point", "Attribute on point"}, {ATTR_DOMAIN_EDGE, "EDGE", 0, "Edge", "Attribute on mesh edge"}, - {ATTR_DOMAIN_CORNER, "CORNER", 0, "Corner", "Attribute on mesh polygon corner"}, - {ATTR_DOMAIN_POLYGON, "POLYGON", 0, "Polygon", "Attribute on mesh polygons"}, + {ATTR_DOMAIN_FACE, "FACE", 0, "Face", "Attribute on mesh faces"}, + {ATTR_DOMAIN_CORNER, "CORNER", 0, "Face Corner", "Attribute on mesh face corner"}, /* Not implement yet */ // {ATTR_DOMAIN_GRIDS, "GRIDS", 0, "Grids", "Attribute on mesh multires grids"}, {ATTR_DOMAIN_CURVE, "CURVE", 0, "Curve", "Attribute on hair curve"}, @@ -66,8 +66,8 @@ const EnumPropertyItem rna_enum_attribute_domain_with_auto_items[] = { {ATTR_DOMAIN_AUTO, "AUTO", 0, "Auto", ""}, {ATTR_DOMAIN_POINT, "POINT", 0, "Point", "Attribute on point"}, {ATTR_DOMAIN_EDGE, "EDGE", 0, "Edge", "Attribute on mesh edge"}, - {ATTR_DOMAIN_CORNER, "CORNER", 0, "Corner", "Attribute on mesh polygon corner"}, - {ATTR_DOMAIN_POLYGON, "POLYGON", 0, "Polygon", "Attribute on mesh polygons"}, + {ATTR_DOMAIN_FACE, "FACE", 0, "Face", "Attribute on mesh faces"}, + {ATTR_DOMAIN_CORNER, "CORNER", 0, "Face Corner", "Attribute on mesh face corner"}, {0, NULL, 0, NULL, NULL}, }; diff --git a/source/blender/makesrna/intern/rna_depsgraph.c b/source/blender/makesrna/intern/rna_depsgraph.c index 36d39c5c201..85071e8cd19 100644 --- a/source/blender/makesrna/intern/rna_depsgraph.c +++ b/source/blender/makesrna/intern/rna_depsgraph.c @@ -505,11 +505,10 @@ static void rna_def_depsgraph_instance(BlenderRNA *brna) PropertyRNA *prop; srna = RNA_def_struct(brna, "DepsgraphObjectInstance", NULL); - RNA_def_struct_ui_text( - srna, - "Dependency Graph Object Instance", - "Extended information about dependency graph object iterator " - "(WARNING: all data here is *evaluated* one, not original .blend IDs...)"); + RNA_def_struct_ui_text(srna, + "Dependency Graph Object Instance", + "Extended information about dependency graph object iterator " + "(Warning: All data here is 'evaluated' one, not original .blend IDs)"); prop = RNA_def_property(srna, "object", PROP_POINTER, PROP_NONE); RNA_def_property_struct_type(prop, "Object"); @@ -773,7 +772,7 @@ static void rna_def_depsgraph(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Object Instances", "All object instances to display or render " - "(WARNING: only use this as an iterator, never as a sequence, " + "(Warning: Only use this as an iterator, never as a sequence, " "and do not keep any references to its items)"); prop = RNA_def_property(srna, "updates", PROP_COLLECTION, PROP_NONE); diff --git a/source/blender/makesrna/intern/rna_gpencil_modifier.c b/source/blender/makesrna/intern/rna_gpencil_modifier.c index 0aa2e652d2d..6c6f18ab5a4 100644 --- a/source/blender/makesrna/intern/rna_gpencil_modifier.c +++ b/source/blender/makesrna/intern/rna_gpencil_modifier.c @@ -452,7 +452,7 @@ static void rna_def_modifier_gpencilnoise(BlenderRNA *brna) RNA_def_property_update(prop, 0, "rna_GpencilModifier_update"); prop = RNA_def_property(srna, "material", PROP_POINTER, PROP_NONE); - RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_SELF_CHECK); + RNA_def_property_flag(prop, PROP_EDITABLE); RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); RNA_def_property_ui_text(prop, "Material", "Material used for filtering effect"); RNA_def_property_update(prop, 0, "rna_GpencilModifier_update"); @@ -585,7 +585,7 @@ static void rna_def_modifier_gpencilsmooth(BlenderRNA *brna) RNA_def_property_update(prop, 0, "rna_GpencilModifier_update"); prop = RNA_def_property(srna, "material", PROP_POINTER, PROP_NONE); - RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_SELF_CHECK); + RNA_def_property_flag(prop, PROP_EDITABLE); RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); RNA_def_property_ui_text(prop, "Material", "Material used for filtering effect"); RNA_def_property_update(prop, 0, "rna_GpencilModifier_update"); @@ -698,7 +698,7 @@ static void rna_def_modifier_gpencilsubdiv(BlenderRNA *brna) RNA_def_property_update(prop, 0, "rna_GpencilModifier_update"); prop = RNA_def_property(srna, "material", PROP_POINTER, PROP_NONE); - RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_SELF_CHECK); + RNA_def_property_flag(prop, PROP_EDITABLE); RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); RNA_def_property_ui_text(prop, "Material", "Material used for filtering effect"); RNA_def_property_update(prop, 0, "rna_GpencilModifier_update"); @@ -788,7 +788,7 @@ static void rna_def_modifier_gpencilsimplify(BlenderRNA *brna) RNA_def_property_update(prop, 0, "rna_GpencilModifier_update"); prop = RNA_def_property(srna, "material", PROP_POINTER, PROP_NONE); - RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_SELF_CHECK); + RNA_def_property_flag(prop, PROP_EDITABLE); RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); RNA_def_property_ui_text(prop, "Material", "Material used for filtering effect"); RNA_def_property_update(prop, 0, "rna_GpencilModifier_update"); @@ -877,7 +877,7 @@ static void rna_def_modifier_gpencilthick(BlenderRNA *brna) RNA_def_property_update(prop, 0, "rna_GpencilModifier_update"); prop = RNA_def_property(srna, "material", PROP_POINTER, PROP_NONE); - RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_SELF_CHECK); + RNA_def_property_flag(prop, PROP_EDITABLE); RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); RNA_def_property_ui_text(prop, "Material", "Material used for filtering effect"); RNA_def_property_update(prop, 0, "rna_GpencilModifier_update"); @@ -971,7 +971,7 @@ static void rna_def_modifier_gpenciloffset(BlenderRNA *brna) RNA_def_property_update(prop, 0, "rna_GpencilModifier_update"); prop = RNA_def_property(srna, "material", PROP_POINTER, PROP_NONE); - RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_SELF_CHECK); + RNA_def_property_flag(prop, PROP_EDITABLE); RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); RNA_def_property_ui_text(prop, "Material", "Material used for filtering effect"); RNA_def_property_update(prop, 0, "rna_GpencilModifier_update"); @@ -1069,7 +1069,7 @@ static void rna_def_modifier_gpenciltint(BlenderRNA *brna) RNA_def_property_update(prop, 0, "rna_GpencilModifier_update"); prop = RNA_def_property(srna, "material", PROP_POINTER, PROP_NONE); - RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_SELF_CHECK); + RNA_def_property_flag(prop, PROP_EDITABLE); RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); RNA_def_property_ui_text(prop, "Material", "Material used for filtering effect"); RNA_def_property_update(prop, 0, "rna_GpencilModifier_update"); @@ -1273,7 +1273,7 @@ static void rna_def_modifier_gpencilcolor(BlenderRNA *brna) RNA_def_property_update(prop, 0, "rna_GpencilModifier_update"); prop = RNA_def_property(srna, "material", PROP_POINTER, PROP_NONE); - RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_SELF_CHECK); + RNA_def_property_flag(prop, PROP_EDITABLE); RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); RNA_def_property_ui_text(prop, "Material", "Material used for filtering effect"); RNA_def_property_update(prop, 0, "rna_GpencilModifier_update"); @@ -1364,7 +1364,7 @@ static void rna_def_modifier_gpencilopacity(BlenderRNA *brna) RNA_def_property_update(prop, 0, "rna_GpencilModifier_update"); prop = RNA_def_property(srna, "material", PROP_POINTER, PROP_NONE); - RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_SELF_CHECK); + RNA_def_property_flag(prop, PROP_EDITABLE); RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); RNA_def_property_ui_text(prop, "Material", "Material used for filtering effect"); RNA_def_property_update(prop, 0, "rna_GpencilModifier_update"); @@ -1460,7 +1460,7 @@ static void rna_def_modifier_gpencilarray(BlenderRNA *brna) RNA_def_property_update(prop, 0, "rna_GpencilModifier_update"); prop = RNA_def_property(srna, "material", PROP_POINTER, PROP_NONE); - RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_SELF_CHECK); + RNA_def_property_flag(prop, PROP_EDITABLE); RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); RNA_def_property_ui_text(prop, "Material", "Material used for filtering effect"); RNA_def_property_update(prop, 0, "rna_GpencilModifier_update"); @@ -1759,7 +1759,7 @@ static void rna_def_modifier_gpencillattice(BlenderRNA *brna) RNA_def_property_update(prop, 0, "rna_GpencilModifier_update"); prop = RNA_def_property(srna, "material", PROP_POINTER, PROP_NONE); - RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_SELF_CHECK); + RNA_def_property_flag(prop, PROP_EDITABLE); RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); RNA_def_property_ui_text(prop, "Material", "Material used for filtering effect"); RNA_def_property_update(prop, 0, "rna_GpencilModifier_update"); @@ -1838,7 +1838,7 @@ static void rna_def_modifier_gpencilmirror(BlenderRNA *brna) RNA_def_property_update(prop, 0, "rna_GpencilModifier_update"); prop = RNA_def_property(srna, "material", PROP_POINTER, PROP_NONE); - RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_SELF_CHECK); + RNA_def_property_flag(prop, PROP_EDITABLE); RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); RNA_def_property_ui_text(prop, "Material", "Material used for filtering effect"); RNA_def_property_update(prop, 0, "rna_GpencilModifier_update"); @@ -1936,7 +1936,7 @@ static void rna_def_modifier_gpencilhook(BlenderRNA *brna) RNA_def_property_update(prop, 0, "rna_GpencilModifier_update"); prop = RNA_def_property(srna, "material", PROP_POINTER, PROP_NONE); - RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_SELF_CHECK); + RNA_def_property_flag(prop, PROP_EDITABLE); RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); RNA_def_property_ui_text(prop, "Material", "Material used for filtering effect"); RNA_def_property_update(prop, 0, "rna_GpencilModifier_update"); @@ -2093,7 +2093,7 @@ static void rna_def_modifier_gpencilmultiply(BlenderRNA *brna) RNA_def_property_update(prop, 0, "rna_GpencilModifier_update"); prop = RNA_def_property(srna, "material", PROP_POINTER, PROP_NONE); - RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_SELF_CHECK); + RNA_def_property_flag(prop, PROP_EDITABLE); RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); RNA_def_property_ui_text(prop, "Material", "Material used for filtering effect"); RNA_def_property_update(prop, 0, "rna_GpencilModifier_update"); @@ -2216,7 +2216,7 @@ static void rna_def_modifier_gpenciltexture(BlenderRNA *brna) RNA_def_property_update(prop, 0, "rna_GpencilModifier_update"); prop = RNA_def_property(srna, "material", PROP_POINTER, PROP_NONE); - RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_SELF_CHECK); + RNA_def_property_flag(prop, PROP_EDITABLE); RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); RNA_def_property_ui_text(prop, "Material", "Material used for filtering effect"); RNA_def_property_update(prop, 0, "rna_GpencilModifier_update"); @@ -2466,7 +2466,7 @@ static void rna_def_modifier_gpencillineart(BlenderRNA *brna) RNA_def_property_update(prop, 0, "rna_GpencilModifier_update"); prop = RNA_def_property(srna, "target_material", PROP_POINTER, PROP_NONE); - RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_SELF_CHECK); + RNA_def_property_flag(prop, PROP_EDITABLE); RNA_def_property_struct_type(prop, "Material"); RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); RNA_def_property_ui_text( diff --git a/source/blender/makesrna/intern/rna_modifier.c b/source/blender/makesrna/intern/rna_modifier.c index 98a2b683f18..67335b81a31 100644 --- a/source/blender/makesrna/intern/rna_modifier.c +++ b/source/blender/makesrna/intern/rna_modifier.c @@ -5920,8 +5920,9 @@ static void rna_def_modifier_triangulate(BlenderRNA *brna) RNA_def_property_ui_text( prop, "Keep Normals", - "Try to preserve custom normals (WARNING: depending on chosen triangulation method, " - "shading may not be fully preserved, 'Fixed' method usually gives the best result here)"); + "Try to preserve custom normals.\n" + "Warning: Depending on chosen triangulation method, " + "shading may not be fully preserved, \"Fixed\" method usually gives the best result here"); RNA_def_property_update(prop, 0, "rna_Modifier_update"); RNA_define_lib_overridable(false); diff --git a/source/blender/makesrna/intern/rna_nodetree.c b/source/blender/makesrna/intern/rna_nodetree.c index d69a1e3dd06..277cfada44d 100644 --- a/source/blender/makesrna/intern/rna_nodetree.c +++ b/source/blender/makesrna/intern/rna_nodetree.c @@ -329,8 +329,12 @@ const EnumPropertyItem rna_enum_node_map_range_items[] = { }; const EnumPropertyItem rna_enum_node_clamp_items[] = { - {NODE_CLAMP_MINMAX, "MINMAX", 0, "Min Max", "Clamp values using Min and Max values"}, - {NODE_CLAMP_RANGE, "RANGE", 0, "Range", "Clamp values between Min and Max range"}, + {NODE_CLAMP_MINMAX, "MINMAX", 0, "Min Max", "Constrain value between min and max"}, + {NODE_CLAMP_RANGE, + "RANGE", + 0, + "Range", + "Constrain value between min and max, swapping arguments when min > max"}, {0, NULL, 0, NULL, NULL}, }; @@ -1886,6 +1890,19 @@ static const EnumPropertyItem *itemf_function_check( return item_array; } +static bool attribute_clamp_type_supported(const EnumPropertyItem *item) +{ + return ELEM(item->value, CD_PROP_FLOAT, CD_PROP_FLOAT3, CD_PROP_INT32, CD_PROP_COLOR); +} +static const EnumPropertyItem *rna_GeometryNodeAttributeClamp_type_itemf(bContext *UNUSED(C), + PointerRNA *UNUSED(ptr), + PropertyRNA *UNUSED(prop), + bool *r_free) +{ + *r_free = true; + return itemf_function_check(rna_enum_attribute_type_items, attribute_clamp_type_supported); +} + static bool attribute_random_type_supported(const EnumPropertyItem *item) { return ELEM(item->value, CD_PROP_FLOAT, CD_PROP_FLOAT3, CD_PROP_BOOL, CD_PROP_INT32); @@ -2065,6 +2082,17 @@ static void rna_GeometryNodeAttributeVectorMath_operation_update(Main *bmain, rna_Node_socket_update(bmain, scene, ptr); } +static bool attribute_map_range_type_supported(const EnumPropertyItem *item) +{ + return ELEM(item->value, CD_PROP_FLOAT, CD_PROP_FLOAT3); +} +static const EnumPropertyItem *rna_GeometryNodeAttributeMapRange_type_itemf( + bContext *UNUSED(C), PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), bool *r_free) +{ + *r_free = true; + return itemf_function_check(rna_enum_attribute_type_items, attribute_map_range_type_supported); +} + static StructRNA *rna_ShaderNode_register(Main *bmain, ReportList *reports, void *data, @@ -8634,6 +8662,41 @@ static void def_cmp_denoise(StructRNA *srna) RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); } +static void def_cmp_antialiasing(StructRNA *srna) +{ + PropertyRNA *prop; + + RNA_def_struct_sdna_from(srna, "NodeAntiAliasingData", "storage"); + + prop = RNA_def_property(srna, "threshold", PROP_FLOAT, PROP_FACTOR); + RNA_def_property_float_sdna(prop, NULL, "threshold"); + RNA_def_property_ui_range(prop, 0.0f, 1.0f, 0.1, 3); + RNA_def_property_ui_text( + prop, + "Threshold", + "Threshold to detect edges (smaller threshold makes more sensitive detection)"); + RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); + + prop = RNA_def_property(srna, "contrast_limit", PROP_FLOAT, PROP_FACTOR); + RNA_def_property_float_sdna(prop, NULL, "contrast_limit"); + RNA_def_property_range(prop, 0.0f, 1.0f); + RNA_def_property_ui_range(prop, 0.0f, 1.0f, 0.1, 3); + RNA_def_property_ui_text( + prop, + "Contrast Limit", + "How much to eliminate spurious edges to avoid artifacts (the larger value makes less " + "active; the value 2.0, for example, means discard a detected edge if there is a " + "neighboring edge that has 2.0 times bigger contrast than the current one)"); + RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); + + prop = RNA_def_property(srna, "corner_rounding", PROP_FLOAT, PROP_FACTOR); + RNA_def_property_float_sdna(prop, NULL, "corner_rounding"); + RNA_def_property_range(prop, 0.0f, 1.0f); + RNA_def_property_ui_range(prop, 0.0f, 1.0f, 0.1, 3); + RNA_def_property_ui_text(prop, "Corner Rounding", "How much sharp corners will be rounded"); + RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); +} + /* -- Texture Nodes --------------------------------------------------------- */ static void def_tex_output(StructRNA *srna) @@ -8915,6 +8978,26 @@ static void def_geo_attribute_vector_math(StructRNA *srna) RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update"); } +static void def_geo_attribute_map_range(StructRNA *srna) +{ + PropertyRNA *prop; + + RNA_def_struct_sdna_from(srna, "NodeAttributeMapRange", "storage"); + + prop = RNA_def_property(srna, "data_type", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_bitflag_sdna(prop, NULL, "data_type"); + RNA_def_property_enum_items(prop, rna_enum_attribute_type_items); + RNA_def_property_enum_funcs(prop, NULL, NULL, "rna_GeometryNodeAttributeMapRange_type_itemf"); + RNA_def_property_ui_text(prop, "Data Type", ""); + RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update"); + + prop = RNA_def_property(srna, "interpolation_type", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_sdna(prop, NULL, "interpolation_type"); + RNA_def_property_enum_items(prop, rna_enum_node_map_range_items); + RNA_def_property_ui_text(prop, "Interpolation Type", ""); + RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_ShaderNode_socket_update"); +} + static void def_geo_point_instance(StructRNA *srna) { static const EnumPropertyItem instance_type_items[] = { @@ -8975,6 +9058,26 @@ static void def_geo_attribute_mix(StructRNA *srna) RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update"); } +static void def_geo_attribute_clamp(StructRNA *srna) +{ + PropertyRNA *prop; + + RNA_def_struct_sdna_from(srna, "NodeAttributeClamp", "storage"); + + prop = RNA_def_property(srna, "data_type", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_bitflag_sdna(prop, NULL, "data_type"); + RNA_def_property_enum_items(prop, rna_enum_attribute_type_items); + RNA_def_property_enum_funcs(prop, NULL, NULL, "rna_GeometryNodeAttributeClamp_type_itemf"); + RNA_def_property_ui_text(prop, "Data Type", ""); + RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update"); + + prop = RNA_def_property(srna, "operation", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_items(prop, rna_enum_node_clamp_items); + RNA_def_property_enum_default(prop, NODE_CLAMP_MINMAX); + RNA_def_property_ui_text(prop, "Operation", ""); + RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); +} + static void def_geo_attribute_attribute_compare(StructRNA *srna) { PropertyRNA *prop; @@ -9594,6 +9697,12 @@ static void rna_def_node_socket(BlenderRNA *brna) RNA_def_property_clear_flag(prop, PROP_EDITABLE); RNA_def_property_ui_text(prop, "Linked", "True if the socket is connected"); + prop = RNA_def_property(srna, "is_multi_input", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", SOCK_MULTI_INPUT); + RNA_def_property_clear_flag(prop, PROP_EDITABLE); + RNA_def_property_ui_text( + prop, "Multi Input", "True if the socket can accept multiple ordered input links"); + prop = RNA_def_property(srna, "show_expanded", PROP_BOOLEAN, PROP_NONE); RNA_def_property_flag(prop, PROP_NO_DEG_UPDATE); RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", SOCK_COLLAPSED); diff --git a/source/blender/makesrna/intern/rna_object.c b/source/blender/makesrna/intern/rna_object.c index b04fea11a4d..21e9328d043 100644 --- a/source/blender/makesrna/intern/rna_object.c +++ b/source/blender/makesrna/intern/rna_object.c @@ -160,6 +160,7 @@ const EnumPropertyItem rna_enum_object_gpencil_type_items[] = { {GP_EMPTY, "EMPTY", ICON_EMPTY_AXIS, "Blank", "Create an empty grease pencil object"}, {GP_STROKE, "STROKE", ICON_STROKE, "Stroke", "Create a simple stroke with basic colors"}, {GP_MONKEY, "MONKEY", ICON_MONKEY, "Monkey", "Construct a Suzanne grease pencil object"}, + {0, "", 0, NULL, NULL}, {GP_LRT_SCENE, "LRT_SCENE", ICON_SCENE_DATA, @@ -2797,6 +2798,7 @@ static void rna_def_object(BlenderRNA *brna) RNA_def_property_multi_array(prop, 2, boundbox_dimsize); RNA_def_property_clear_flag(prop, PROP_EDITABLE); RNA_def_property_override_clear_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); + RNA_def_property_override_flag(prop, PROPOVERRIDE_NO_COMPARISON); RNA_def_property_float_funcs(prop, "rna_Object_boundbox_get", NULL, NULL); RNA_def_property_ui_text( prop, @@ -2967,12 +2969,11 @@ static void rna_def_object(BlenderRNA *brna) RNA_def_property_float_funcs( prop, "rna_Object_dimensions_get", "rna_Object_dimensions_set", NULL); RNA_def_property_ui_range(prop, 0.0f, FLT_MAX, 1, RNA_TRANSLATION_PREC_DEFAULT); - RNA_def_property_ui_text( - prop, - "Dimensions", - "Absolute bounding box dimensions of the object (WARNING: assigning to it or " - "its members multiple consecutive times will not work correctly, " - "as this needs up-to-date evaluated data)"); + RNA_def_property_ui_text(prop, + "Dimensions", + "Absolute bounding box dimensions of the object.\n" + "Warning: Assigning to it or its members multiple consecutive times " + "will not work correctly, as this needs up-to-date evaluated data"); RNA_def_property_update(prop, NC_OBJECT | ND_TRANSFORM, "rna_Object_internal_update"); /* delta transforms */ @@ -3075,8 +3076,8 @@ static void rna_def_object(BlenderRNA *brna) RNA_def_property_ui_text( prop, "Local Matrix", - "Parent relative transformation matrix - " - "WARNING: Only takes into account 'Object' parenting, so e.g. in case of bone parenting " + "Parent relative transformation matrix.\n" + "Warning: Only takes into account object parenting, so e.g. in case of bone parenting " "you get a matrix relative to the Armature object, not to the actual parent bone"); RNA_def_property_float_funcs( prop, "rna_Object_matrix_local_get", "rna_Object_matrix_local_set", NULL); diff --git a/source/blender/makesrna/intern/rna_rna.c b/source/blender/makesrna/intern/rna_rna.c index d8336e79064..f7a7b745493 100644 --- a/source/blender/makesrna/intern/rna_rna.c +++ b/source/blender/makesrna/intern/rna_rna.c @@ -20,6 +20,8 @@ #include <stdlib.h> +#include <CLG_log.h> + #include "DNA_ID.h" #include "BLI_utildefines.h" @@ -132,6 +134,8 @@ const EnumPropertyItem rna_enum_property_unit_items[] = { # include "BKE_idprop.h" # include "BKE_lib_override.h" +static CLG_LogRef LOG_COMPARE_OVERRIDE = {"rna.rna_compare_override"}; + /* Struct */ static void rna_Struct_identifier_get(PointerRNA *ptr, char *value) @@ -1366,11 +1370,11 @@ static int rna_property_override_diff_propptr(Main *bmain, /* In case one of the owner of the checked property is tagged as needing resync, do * not change the 'match reference' status of its ID pointer properties overrides, * since many non-matching ones are likely due to missing resync. */ - printf( - "%s: Not checking matching ID pointer properties, since owner %s is tagged as " - "needing resync.\n", - __func__, - id_a->name); + CLOG_INFO(&LOG_COMPARE_OVERRIDE, + 4, + "Not checking matching ID pointer properties, since owner %s is tagged as " + "needing resync.\n", + id_a->name); } else if (id_a->override_library != NULL && id_a->override_library->reference == id_b) { opop->flag |= IDOVERRIDE_LIBRARY_FLAG_IDPOINTER_MATCH_REFERENCE; diff --git a/source/blender/makesrna/intern/rna_scene.c b/source/blender/makesrna/intern/rna_scene.c index 3344b8c286d..65643aa92d7 100644 --- a/source/blender/makesrna/intern/rna_scene.c +++ b/source/blender/makesrna/intern/rna_scene.c @@ -2685,6 +2685,7 @@ static void rna_def_view3d_cursor(BlenderRNA *brna) RNA_def_struct_path_func(srna, "rna_View3DCursor_path"); RNA_def_struct_ui_text(srna, "3D Cursor", ""); RNA_def_struct_ui_icon(srna, ICON_CURSOR); + RNA_def_struct_clear_flag(srna, STRUCT_UNDO); prop = RNA_def_property(srna, "location", PROP_FLOAT, PROP_XYZ_LENGTH); RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); @@ -2855,7 +2856,7 @@ static void rna_def_tool_settings(BlenderRNA *brna) RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE); RNA_def_property_boolean_sdna(prop, NULL, "auto_normalize", 1); RNA_def_property_ui_text(prop, - "WPaint Auto-Normalize", + "Weight Paint Auto-Normalize", "Ensure all bone-deforming vertex groups add up " "to 1.0 while weight painting"); RNA_def_property_update(prop, 0, "rna_Scene_update_active_object_data"); @@ -2864,7 +2865,7 @@ static void rna_def_tool_settings(BlenderRNA *brna) RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE); RNA_def_property_boolean_sdna(prop, NULL, "wpaint_lock_relative", 1); RNA_def_property_ui_text(prop, - "WPaint Lock-Relative", + "Weight Paint Lock-Relative", "Display bone-deforming groups as if all locked deform groups " "were deleted, and the remaining ones were re-normalized"); RNA_def_property_update(prop, 0, "rna_Scene_update_active_object_data"); @@ -2873,7 +2874,7 @@ static void rna_def_tool_settings(BlenderRNA *brna) RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE); RNA_def_property_boolean_sdna(prop, NULL, "multipaint", 1); RNA_def_property_ui_text(prop, - "WPaint Multi-Paint", + "Weight Paint Multi-Paint", "Paint across the weights of all selected bones, " "maintaining their relative influence"); RNA_def_property_update(prop, 0, "rna_Scene_update_active_object_data"); diff --git a/source/blender/makesrna/intern/rna_sequencer_api.c b/source/blender/makesrna/intern/rna_sequencer_api.c index a49a404fe6c..8aab0c079a3 100644 --- a/source/blender/makesrna/intern/rna_sequencer_api.c +++ b/source/blender/makesrna/intern/rna_sequencer_api.c @@ -224,13 +224,15 @@ static Sequence *rna_Sequences_new_image(ID *id, const char *name, const char *file, int channel, - int frame_start) + int frame_start, + int fit_method) { Scene *scene = (Scene *)id; SeqLoadData load_data; SEQ_add_load_data_init(&load_data, name, file, frame_start, channel); load_data.image.len = 1; + load_data.fit_method = fit_method; Sequence *seq = SEQ_add_image_strip(bmain, scene, seqbase, &load_data); char dir[FILE_MAX], filename[FILE_MAX]; @@ -253,10 +255,11 @@ static Sequence *rna_Sequences_editing_new_image(ID *id, const char *name, const char *file, int channel, - int frame_start) + int frame_start, + int fit_method) { return rna_Sequences_new_image( - id, &ed->seqbase, bmain, reports, name, file, channel, frame_start); + id, &ed->seqbase, bmain, reports, name, file, channel, frame_start, fit_method); } static Sequence *rna_Sequences_meta_new_image(ID *id, @@ -266,10 +269,11 @@ static Sequence *rna_Sequences_meta_new_image(ID *id, const char *name, const char *file, int channel, - int frame_start) + int frame_start, + int fit_method) { return rna_Sequences_new_image( - id, &seq->seqbase, bmain, reports, name, file, channel, frame_start); + id, &seq->seqbase, bmain, reports, name, file, channel, frame_start, fit_method); } static Sequence *rna_Sequences_new_movie(ID *id, @@ -278,11 +282,13 @@ static Sequence *rna_Sequences_new_movie(ID *id, const char *name, const char *file, int channel, - int frame_start) + int frame_start, + int fit_method) { Scene *scene = (Scene *)id; SeqLoadData load_data; SEQ_add_load_data_init(&load_data, name, file, frame_start, channel); + load_data.fit_method = fit_method; load_data.allow_invalid_file = true; Sequence *seq = SEQ_add_movie_strip(bmain, scene, seqbase, &load_data); @@ -299,9 +305,11 @@ static Sequence *rna_Sequences_editing_new_movie(ID *id, const char *name, const char *file, int channel, - int frame_start) + int frame_start, + int fit_method) { - return rna_Sequences_new_movie(id, &ed->seqbase, bmain, name, file, channel, frame_start); + return rna_Sequences_new_movie( + id, &ed->seqbase, bmain, name, file, channel, frame_start, fit_method); } static Sequence *rna_Sequences_meta_new_movie(ID *id, @@ -310,9 +318,11 @@ static Sequence *rna_Sequences_meta_new_movie(ID *id, const char *name, const char *file, int channel, - int frame_start) + int frame_start, + int fit_method) { - return rna_Sequences_new_movie(id, &seq->seqbase, bmain, name, file, channel, frame_start); + return rna_Sequences_new_movie( + id, &seq->seqbase, bmain, name, file, channel, frame_start, fit_method); } # ifdef WITH_AUDASPACE @@ -724,6 +734,18 @@ void RNA_api_sequences(BlenderRNA *brna, PropertyRNA *cprop, const bool metastri {0, NULL, 0, NULL, NULL}, }; + static const EnumPropertyItem scale_fit_methods[] = { + {SEQ_SCALE_TO_FIT, "FIT", 0, "Scale to Fit", "Scale image so fits in preview"}, + {SEQ_SCALE_TO_FILL, + "FILL", + 0, + "Scale to Fill", + "Scale image so it fills preview completely"}, + {SEQ_STRETCH_TO_FILL, "STRETCH", 0, "Stretch to Fill", "Stretch image so it fills preview"}, + {SEQ_USE_ORIGINAL_SIZE, "ORIGINAL", 0, "Use Original Size", "Don't scale the image"}, + {0, NULL, 0, NULL, NULL}, + }; + const char *new_clip_func_name = "rna_Sequences_editing_new_clip"; const char *new_mask_func_name = "rna_Sequences_editing_new_mask"; const char *new_scene_func_name = "rna_Sequences_editing_new_scene"; @@ -849,6 +871,9 @@ void RNA_api_sequences(BlenderRNA *brna, PropertyRNA *cprop, const bool metastri -MAXFRAME, MAXFRAME); RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); + parm = RNA_def_enum( + func, "fit_method", scale_fit_methods, SEQ_USE_ORIGINAL_SIZE, "Image Fit Method", NULL); + RNA_def_parameter_flags(parm, 0, PARM_PYFUNC_OPTIONAL); /* return type */ parm = RNA_def_pointer(func, "sequence", "Sequence", "", "New Sequence"); RNA_def_function_return(func, parm); @@ -873,6 +898,9 @@ void RNA_api_sequences(BlenderRNA *brna, PropertyRNA *cprop, const bool metastri -MAXFRAME, MAXFRAME); RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); + parm = RNA_def_enum( + func, "fit_method", scale_fit_methods, SEQ_USE_ORIGINAL_SIZE, "Image Fit Method", NULL); + RNA_def_parameter_flags(parm, 0, PARM_PYFUNC_OPTIONAL); /* return type */ parm = RNA_def_pointer(func, "sequence", "Sequence", "", "New Sequence"); RNA_def_function_return(func, parm); diff --git a/source/blender/makesrna/intern/rna_space.c b/source/blender/makesrna/intern/rna_space.c index 26ec94c2b89..cf22ff95e74 100644 --- a/source/blender/makesrna/intern/rna_space.c +++ b/source/blender/makesrna/intern/rna_space.c @@ -3083,7 +3083,7 @@ const EnumPropertyItem *rna_SpaceSpreadsheet_attribute_domain_itemf(bContext *C, ATTR_DOMAIN_CORNER, ATTR_DOMAIN_EDGE, ATTR_DOMAIN_POINT, - ATTR_DOMAIN_POLYGON)) { + ATTR_DOMAIN_FACE)) { continue; } } @@ -7237,7 +7237,7 @@ static void rna_def_space_spreadsheet(BlenderRNA *brna) "MESH", ICON_MESH_DATA, "Mesh", - "Mesh component containing point, corner, edge and polygon data"}, + "Mesh component containing point, corner, edge and face data"}, {GEO_COMPONENT_TYPE_POINT_CLOUD, "POINTCLOUD", ICON_POINTCLOUD_DATA, diff --git a/source/blender/makesrna/intern/rna_userdef.c b/source/blender/makesrna/intern/rna_userdef.c index 4c86405a44d..baf77aae87f 100644 --- a/source/blender/makesrna/intern/rna_userdef.c +++ b/source/blender/makesrna/intern/rna_userdef.c @@ -6215,7 +6215,8 @@ static void rna_def_userdef_filepaths(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Auto Save Temporary Files", "Automatic saving of temporary files in temp directory, " - "uses process ID (sculpt and edit mode data won't be saved)"); + "uses process ID.\n" + "Warning: Sculpt and edit mode data won't be saved"); RNA_def_property_update(prop, 0, "rna_userdef_autosave_update"); prop = RNA_def_property(srna, "auto_save_time", PROP_INT, PROP_NONE); @@ -6304,6 +6305,11 @@ static void rna_def_userdef_experimental(BlenderRNA *brna) prop, "Asset Browser", "Enable Asset Browser editor and operators to manage data-blocks as asset"); + + prop = RNA_def_property(srna, "use_override_templates", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "use_override_templates", 1); + RNA_def_property_ui_text( + prop, "Override Templates", "Enable library override template in the python API"); } static void rna_def_userdef_addon_collection(BlenderRNA *brna, PropertyRNA *cprop) diff --git a/source/blender/makesrna/intern/rna_wm.c b/source/blender/makesrna/intern/rna_wm.c index d67d62d7af9..4a51db4e652 100644 --- a/source/blender/makesrna/intern/rna_wm.c +++ b/source/blender/makesrna/intern/rna_wm.c @@ -1781,41 +1781,40 @@ static void rna_Operator_bl_label_set(PointerRNA *ptr, const char *value) } } -static void rna_Operator_bl_translation_context_set(PointerRNA *ptr, const char *value) -{ - wmOperator *data = (wmOperator *)(ptr->data); - char *str = (char *)data->type->translation_context; - if (!str[0]) { - BLI_strncpy(str, value, RNA_DYN_DESCR_MAX); /* utf8 already ensured */ - } - else { - BLI_assert(!"setting the bl_translation_context on a non-builtin operator"); - } -} - -static void rna_Operator_bl_description_set(PointerRNA *ptr, const char *value) -{ - wmOperator *data = (wmOperator *)(ptr->data); - char *str = (char *)data->type->description; - if (!str[0]) { - BLI_strncpy(str, value, RNA_DYN_DESCR_MAX); /* utf8 already ensured */ - } - else { - BLI_assert(!"setting the bl_description on a non-builtin operator"); - } -} +/** + * Use callbacks that check for NULL instead of clearing #PROP_NEVER_NULL on the string property, + * so the internal value may be NULL, without allowing Python to assign `None` which doesn't + * make any sense in this case. + */ +# define OPERATOR_STR_MAYBE_NULL_GETSET(attr, len) \ + static void rna_Operator_bl_##attr##_set(PointerRNA *ptr, const char *value) \ + { \ + wmOperator *data = (wmOperator *)(ptr->data); \ + char *str = (char *)data->type->attr; \ + if (str && !str[0]) { \ + BLI_strncpy(str, value, len); /* utf8 already ensured */ \ + } \ + else { \ + BLI_assert( \ + !"setting the bl_" STRINGIFY(translation_context) " on a non-builtin operator"); \ + } \ + } \ + static void rna_Operator_bl_##attr##_get(PointerRNA *ptr, char *value) \ + { \ + const wmOperator *data = (wmOperator *)(ptr->data); \ + const char *str = data->type->attr; \ + BLI_strncpy(value, str ? str : "", len); \ + } \ + static int rna_Operator_bl_##attr##_length(PointerRNA *ptr) \ + { \ + const wmOperator *data = (wmOperator *)(ptr->data); \ + const char *str = data->type->attr; \ + return BLI_strnlen(str ? str : "", len); \ + } -static void rna_Operator_bl_undo_group_set(PointerRNA *ptr, const char *value) -{ - wmOperator *data = (wmOperator *)(ptr->data); - char *str = (char *)data->type->undo_group; - if (!str[0]) { - BLI_strncpy(str, value, OP_MAX_TYPENAME); /* utf8 already ensured */ - } - else { - BLI_assert(!"setting the bl_undo_group on a non-builtin operator"); - } -} +OPERATOR_STR_MAYBE_NULL_GETSET(translation_context, RNA_DYN_DESCR_MAX) +OPERATOR_STR_MAYBE_NULL_GETSET(description, RNA_DYN_DESCR_MAX) +OPERATOR_STR_MAYBE_NULL_GETSET(undo_group, OP_MAX_TYPENAME) static void rna_KeyMapItem_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr) { @@ -1930,26 +1929,32 @@ static void rna_def_operator(BlenderRNA *brna) prop = RNA_def_property(srna, "bl_translation_context", PROP_STRING, PROP_NONE); RNA_def_property_string_sdna(prop, NULL, "type->translation_context"); RNA_def_property_string_maxlength(prop, RNA_DYN_DESCR_MAX); /* else it uses the pointer size! */ - RNA_def_property_string_funcs(prop, NULL, NULL, "rna_Operator_bl_translation_context_set"); + RNA_def_property_string_funcs(prop, + "rna_Operator_bl_translation_context_get", + "rna_Operator_bl_translation_context_length", + "rna_Operator_bl_translation_context_set"); RNA_def_property_string_default(prop, BLT_I18NCONTEXT_OPERATOR_DEFAULT); RNA_def_property_flag(prop, PROP_REGISTER_OPTIONAL); - RNA_def_property_clear_flag(prop, PROP_NEVER_NULL); /* check for NULL */ prop = RNA_def_property(srna, "bl_description", PROP_STRING, PROP_NONE); RNA_def_property_string_sdna(prop, NULL, "type->description"); RNA_def_property_string_maxlength(prop, RNA_DYN_DESCR_MAX); /* else it uses the pointer size! */ - RNA_def_property_string_funcs(prop, NULL, NULL, "rna_Operator_bl_description_set"); + RNA_def_property_string_funcs(prop, + "rna_Operator_bl_description_get", + "rna_Operator_bl_description_length", + "rna_Operator_bl_description_set"); /* RNA_def_property_clear_flag(prop, PROP_EDITABLE); */ RNA_def_property_flag(prop, PROP_REGISTER_OPTIONAL); - RNA_def_property_clear_flag(prop, PROP_NEVER_NULL); /* check for NULL */ prop = RNA_def_property(srna, "bl_undo_group", PROP_STRING, PROP_NONE); RNA_def_property_string_sdna(prop, NULL, "type->undo_group"); RNA_def_property_string_maxlength(prop, OP_MAX_TYPENAME); /* else it uses the pointer size! */ - RNA_def_property_string_funcs(prop, NULL, NULL, "rna_Operator_bl_undo_group_set"); + RNA_def_property_string_funcs(prop, + "rna_Operator_bl_undo_group_get", + "rna_Operator_bl_undo_group_length", + "rna_Operator_bl_undo_group_set"); /* RNA_def_property_clear_flag(prop, PROP_EDITABLE); */ RNA_def_property_flag(prop, PROP_REGISTER_OPTIONAL); - RNA_def_property_clear_flag(prop, PROP_NEVER_NULL); /* check for NULL */ prop = RNA_def_property(srna, "bl_options", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "type->flag"); @@ -2022,26 +2027,32 @@ static void rna_def_macro_operator(BlenderRNA *brna) prop = RNA_def_property(srna, "bl_translation_context", PROP_STRING, PROP_NONE); RNA_def_property_string_sdna(prop, NULL, "type->translation_context"); RNA_def_property_string_maxlength(prop, RNA_DYN_DESCR_MAX); /* else it uses the pointer size! */ - RNA_def_property_string_funcs(prop, NULL, NULL, "rna_Operator_bl_translation_context_set"); + RNA_def_property_string_funcs(prop, + "rna_Operator_bl_translation_context_get", + "rna_Operator_bl_translation_context_length", + "rna_Operator_bl_translation_context_set"); RNA_def_property_string_default(prop, BLT_I18NCONTEXT_OPERATOR_DEFAULT); RNA_def_property_flag(prop, PROP_REGISTER_OPTIONAL); - RNA_def_property_clear_flag(prop, PROP_NEVER_NULL); /* check for NULL */ prop = RNA_def_property(srna, "bl_description", PROP_STRING, PROP_NONE); RNA_def_property_string_sdna(prop, NULL, "type->description"); RNA_def_property_string_maxlength(prop, RNA_DYN_DESCR_MAX); /* else it uses the pointer size! */ - RNA_def_property_string_funcs(prop, NULL, NULL, "rna_Operator_bl_description_set"); + RNA_def_property_string_funcs(prop, + "rna_Operator_bl_description_get", + "rna_Operator_bl_description_length", + "rna_Operator_bl_description_set"); /* RNA_def_property_clear_flag(prop, PROP_EDITABLE); */ RNA_def_property_flag(prop, PROP_REGISTER_OPTIONAL); - RNA_def_property_clear_flag(prop, PROP_NEVER_NULL); /* check for NULL */ prop = RNA_def_property(srna, "bl_undo_group", PROP_STRING, PROP_NONE); RNA_def_property_string_sdna(prop, NULL, "type->undo_group"); RNA_def_property_string_maxlength(prop, OP_MAX_TYPENAME); /* else it uses the pointer size! */ - RNA_def_property_string_funcs(prop, NULL, NULL, "rna_Operator_bl_undo_group_set"); + RNA_def_property_string_funcs(prop, + "rna_Operator_bl_undo_group_get", + "rna_Operator_bl_undo_group_length", + "rna_Operator_bl_undo_group_set"); /* RNA_def_property_clear_flag(prop, PROP_EDITABLE); */ RNA_def_property_flag(prop, PROP_REGISTER_OPTIONAL); - RNA_def_property_clear_flag(prop, PROP_NEVER_NULL); /* check for NULL */ prop = RNA_def_property(srna, "bl_options", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "type->flag"); diff --git a/source/blender/modifiers/intern/MOD_boolean.c b/source/blender/modifiers/intern/MOD_boolean.c index fae8ac72108..ffb40bea9ba 100644 --- a/source/blender/modifiers/intern/MOD_boolean.c +++ b/source/blender/modifiers/intern/MOD_boolean.c @@ -660,6 +660,9 @@ static Mesh *exact_boolean_mesh(BooleanModifierData *bmd, BLI_array_append(material_remaps, NULL); if (bmd->flag & eBooleanModifierFlag_Object) { mesh_operand = BKE_modifier_get_evaluated_mesh_from_evaluated_object(bmd->object, false); + if (!mesh_operand) { + return mesh; + } BKE_mesh_wrapper_ensure_mdata(mesh_operand); BLI_array_append(meshes, mesh_operand); BLI_array_append(obmats, &bmd->object->obmat); @@ -673,6 +676,9 @@ static Mesh *exact_boolean_mesh(BooleanModifierData *bmd, FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN (collection, ob) { if (ob->type == OB_MESH && ob != ctx->object) { Mesh *collection_mesh = BKE_modifier_get_evaluated_mesh_from_evaluated_object(ob, false); + if (!collection_mesh) { + continue; + } BKE_mesh_wrapper_ensure_mdata(collection_mesh); BLI_array_append(meshes, collection_mesh); BLI_array_append(obmats, &ob->obmat); diff --git a/source/blender/modifiers/intern/MOD_nodes.cc b/source/blender/modifiers/intern/MOD_nodes.cc index 6236dc87791..72842a1d32d 100644 --- a/source/blender/modifiers/intern/MOD_nodes.cc +++ b/source/blender/modifiers/intern/MOD_nodes.cc @@ -414,7 +414,9 @@ class GeometryNodesEvaluator { { const bNode &bnode = params.node(); - this->store_ui_hints(node, params); + if (DEG_is_active(depsgraph_)) { + this->store_ui_hints(node, params); + } /* Use the geometry-node-execute callback if it exists. */ if (bnode.typeinfo->geometry_node_execute != nullptr) { @@ -720,10 +722,17 @@ static const SocketPropertyType *get_socket_property_type(const bNodeSocket &bso [](const bNodeSocket &socket) { return (PropertyType)((bNodeSocketValueFloat *)socket.default_value)->subtype; }, - [](const IDProperty &property) { return property.type == IDP_FLOAT; }, + [](const IDProperty &property) { return ELEM(property.type, IDP_FLOAT, IDP_DOUBLE); }, [](const IDProperty &property, const PersistentDataHandleMap &UNUSED(handles), - void *r_value) { *(float *)r_value = IDP_Float(&property); }, + void *r_value) { + if (property.type == IDP_FLOAT) { + *(float *)r_value = IDP_Float(&property); + } + else if (property.type == IDP_DOUBLE) { + *(float *)r_value = (float)IDP_Double(&property); + } + }, }; return &float_type; } @@ -1048,7 +1057,7 @@ static void reset_tree_ui_storage(Span<const blender::nodes::NodeTreeRef *> tree * often than necessary. It's going to be replaced soon. */ static GeometrySet compute_geometry(const DerivedNodeTree &tree, - Span<const OutputSocketRef *> group_input_sockets, + Span<const NodeRef *> group_input_nodes, const InputSocketRef &socket_to_compute, GeometrySet input_geometry_set, NodesModifierData *nmd, @@ -1064,7 +1073,12 @@ static GeometrySet compute_geometry(const DerivedNodeTree &tree, Map<DOutputSocket, GMutablePointer> group_inputs; const DTreeContext *root_context = &tree.root_context(); - if (group_input_sockets.size() > 0) { + for (const NodeRef *group_input_node : group_input_nodes) { + Span<const OutputSocketRef *> group_input_sockets = group_input_node->outputs().drop_back(1); + if (group_input_sockets.is_empty()) { + continue; + } + Span<const OutputSocketRef *> remaining_input_sockets = group_input_sockets; /* If the group expects a geometry as first input, use the geometry that has been passed to @@ -1072,7 +1086,7 @@ static GeometrySet compute_geometry(const DerivedNodeTree &tree, const OutputSocketRef *first_input_socket = group_input_sockets[0]; if (first_input_socket->bsocket()->type == SOCK_GEOMETRY) { GeometrySet *geometry_set_in = - allocator.construct<GeometrySet>(std::move(input_geometry_set)).release(); + allocator.construct<GeometrySet>(input_geometry_set).release(); group_inputs.add_new({root_context, first_input_socket}, geometry_set_in); remaining_input_sockets = remaining_input_sockets.drop_front(1); } @@ -1086,6 +1100,9 @@ static GeometrySet compute_geometry(const DerivedNodeTree &tree, } } + /* Don't keep a reference to the input geometry components to avoid copies during evaluation. */ + input_geometry_set.clear(); + Vector<DInputSocket> group_outputs; group_outputs.append({root_context, &socket_to_compute}); @@ -1174,18 +1191,10 @@ static void modifyGeometry(ModifierData *md, Span<const NodeRef *> input_nodes = root_tree_ref.nodes_by_type("NodeGroupInput"); Span<const NodeRef *> output_nodes = root_tree_ref.nodes_by_type("NodeGroupOutput"); - if (input_nodes.size() > 1) { - return; - } if (output_nodes.size() != 1) { return; } - Span<const OutputSocketRef *> group_inputs; - if (input_nodes.size() == 1) { - group_inputs = input_nodes[0]->outputs().drop_back(1); - } - Span<const InputSocketRef *> group_outputs = output_nodes[0]->inputs().drop_back(1); if (group_outputs.size() == 0) { @@ -1197,10 +1206,12 @@ static void modifyGeometry(ModifierData *md, return; } - reset_tree_ui_storage(tree.used_node_tree_refs(), *ctx->object, *md); + if (DEG_is_active(ctx->depsgraph)) { + reset_tree_ui_storage(tree.used_node_tree_refs(), *ctx->object, *md); + } geometry_set = compute_geometry( - tree, group_inputs, *group_outputs[0], std::move(geometry_set), nmd, ctx); + tree, input_nodes, *group_outputs[0], std::move(geometry_set), nmd, ctx); } static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh) @@ -1359,6 +1370,7 @@ static void requiredDataMask(Object *UNUSED(ob), /* We don't know what the node tree will need. If there are vertex groups, it is likely that the * node tree wants to access them. */ r_cddata_masks->vmask |= CD_MASK_MDEFORMVERT; + r_cddata_masks->vmask |= CD_MASK_PROP_ALL; } ModifierTypeInfo modifierType_Nodes = { diff --git a/source/blender/modifiers/intern/MOD_solidify_extrude.c b/source/blender/modifiers/intern/MOD_solidify_extrude.c index 99069919120..a77a6e595ad 100644 --- a/source/blender/modifiers/intern/MOD_solidify_extrude.c +++ b/source/blender/modifiers/intern/MOD_solidify_extrude.c @@ -216,7 +216,7 @@ Mesh *MOD_solidify_extrude_modifyMesh(ModifierData *md, const ModifierEvalContex numVerts, sizeof(*old_vert_arr), "old_vert_arr in solidify"); uint *edge_users = NULL; - char *edge_order = NULL; + int *edge_order = NULL; float(*vert_nors)[3] = NULL; float(*poly_nors)[3] = NULL; diff --git a/source/blender/nodes/CMakeLists.txt b/source/blender/nodes/CMakeLists.txt index 271f4e5c5e4..07380addaff 100644 --- a/source/blender/nodes/CMakeLists.txt +++ b/source/blender/nodes/CMakeLists.txt @@ -46,6 +46,7 @@ set(INC set(SRC composite/nodes/node_composite_alphaOver.c + composite/nodes/node_composite_antialiasing.c composite/nodes/node_composite_bilateralblur.c composite/nodes/node_composite_blur.c composite/nodes/node_composite_bokehblur.c @@ -139,19 +140,21 @@ set(SRC function/node_function_util.cc geometry/nodes/node_geo_align_rotation_to_vector.cc + geometry/nodes/node_geo_attribute_clamp.cc geometry/nodes/node_geo_attribute_color_ramp.cc geometry/nodes/node_geo_attribute_combine_xyz.cc geometry/nodes/node_geo_attribute_compare.cc geometry/nodes/node_geo_attribute_convert.cc geometry/nodes/node_geo_attribute_fill.cc + geometry/nodes/node_geo_attribute_map_range.cc geometry/nodes/node_geo_attribute_math.cc geometry/nodes/node_geo_attribute_mix.cc geometry/nodes/node_geo_attribute_proximity.cc geometry/nodes/node_geo_attribute_randomize.cc + geometry/nodes/node_geo_attribute_remove.cc geometry/nodes/node_geo_attribute_sample_texture.cc geometry/nodes/node_geo_attribute_separate_xyz.cc geometry/nodes/node_geo_attribute_vector_math.cc - geometry/nodes/node_geo_attribute_remove.cc geometry/nodes/node_geo_boolean.cc geometry/nodes/node_geo_collection_info.cc geometry/nodes/node_geo_common.cc @@ -162,9 +165,9 @@ set(SRC geometry/nodes/node_geo_mesh_primitive_cone.cc geometry/nodes/node_geo_mesh_primitive_cube.cc geometry/nodes/node_geo_mesh_primitive_cylinder.cc + geometry/nodes/node_geo_mesh_primitive_grid.cc geometry/nodes/node_geo_mesh_primitive_ico_sphere.cc geometry/nodes/node_geo_mesh_primitive_line.cc - geometry/nodes/node_geo_mesh_primitive_plane.cc geometry/nodes/node_geo_mesh_primitive_uv_sphere.cc geometry/nodes/node_geo_object_info.cc geometry/nodes/node_geo_point_distribute.cc diff --git a/source/blender/nodes/NOD_composite.h b/source/blender/nodes/NOD_composite.h index b0dd0edeec5..258e4c961c9 100644 --- a/source/blender/nodes/NOD_composite.h +++ b/source/blender/nodes/NOD_composite.h @@ -79,6 +79,7 @@ void register_node_type_cmp_inpaint(void); void register_node_type_cmp_despeckle(void); void register_node_type_cmp_defocus(void); void register_node_type_cmp_denoise(void); +void register_node_type_cmp_antialiasing(void); void register_node_type_cmp_valtorgb(void); void register_node_type_cmp_rgbtobw(void); diff --git a/source/blender/nodes/NOD_derived_node_tree.hh b/source/blender/nodes/NOD_derived_node_tree.hh index e47774bb25a..c29de611e18 100644 --- a/source/blender/nodes/NOD_derived_node_tree.hh +++ b/source/blender/nodes/NOD_derived_node_tree.hh @@ -261,7 +261,7 @@ inline const NodeRef *DNode::operator->() const inline uint64_t DNode::hash() const { - return DefaultHash<const DTreeContext *>{}(context_) ^ DefaultHash<const NodeRef *>{}(node_ref_); + return get_default_hash_2(context_, node_ref_); } /* -------------------------------------------------------------------- @@ -316,8 +316,7 @@ inline const SocketRef *DSocket::operator->() const inline uint64_t DSocket::hash() const { - return DefaultHash<const DTreeContext *>{}(context_) ^ - DefaultHash<const SocketRef *>{}(socket_ref_); + return get_default_hash_2(context_, socket_ref_); } /* -------------------------------------------------------------------- diff --git a/source/blender/nodes/NOD_geometry.h b/source/blender/nodes/NOD_geometry.h index 03115852d80..3a26f38d6ba 100644 --- a/source/blender/nodes/NOD_geometry.h +++ b/source/blender/nodes/NOD_geometry.h @@ -27,11 +27,13 @@ void register_node_tree_type_geo(void); void register_node_type_geo_group(void); void register_node_type_geo_align_rotation_to_vector(void); +void register_node_type_geo_attribute_clamp(void); void register_node_type_geo_attribute_color_ramp(void); void register_node_type_geo_attribute_combine_xyz(void); void register_node_type_geo_attribute_compare(void); void register_node_type_geo_attribute_convert(void); void register_node_type_geo_attribute_fill(void); +void register_node_type_geo_attribute_map_range(void); void register_node_type_geo_attribute_math(void); void register_node_type_geo_attribute_mix(void); void register_node_type_geo_attribute_proximity(void); @@ -47,8 +49,8 @@ void register_node_type_geo_join_geometry(void); void register_node_type_geo_mesh_primitive_circle(void); void register_node_type_geo_mesh_primitive_cone(void); void register_node_type_geo_mesh_primitive_cube(void); -void register_node_type_geo_mesh_primitive_plane(void); void register_node_type_geo_mesh_primitive_cylinder(void); +void register_node_type_geo_mesh_primitive_grid(void); void register_node_type_geo_mesh_primitive_ico_sphere(void); void register_node_type_geo_mesh_primitive_line(void); void register_node_type_geo_mesh_primitive_uv_sphere(void); diff --git a/source/blender/nodes/NOD_math_functions.hh b/source/blender/nodes/NOD_math_functions.hh index 08496e044c5..45de1816549 100644 --- a/source/blender/nodes/NOD_math_functions.hh +++ b/source/blender/nodes/NOD_math_functions.hh @@ -379,7 +379,8 @@ inline bool try_dispatch_float_math_fl3_fl3_fl_to_fl3(const NodeVectorMathOperat switch (operation) { case NODE_VECTOR_MATH_REFRACT: - return dispatch([](float3 a, float3 b, float c) { return float3::refract(a, b.normalized(), c); }); + return dispatch( + [](float3 a, float3 b, float c) { return float3::refract(a, b.normalized(), c); }); default: return false; } diff --git a/source/blender/nodes/NOD_socket.h b/source/blender/nodes/NOD_socket.h index 3344a25bdea..6bcfda70d04 100644 --- a/source/blender/nodes/NOD_socket.h +++ b/source/blender/nodes/NOD_socket.h @@ -41,7 +41,7 @@ extern "C" { struct bNodeSocket *node_add_socket_from_template(struct bNodeTree *ntree, struct bNode *node, struct bNodeSocketTemplate *stemp, - int in_out); + eNodeSocketInOut in_out); void node_verify_socket_templates(struct bNodeTree *ntree, struct bNode *node); diff --git a/source/blender/nodes/NOD_static_types.h b/source/blender/nodes/NOD_static_types.h index ec687ae6b70..0b1efaca502 100644 --- a/source/blender/nodes/NOD_static_types.h +++ b/source/blender/nodes/NOD_static_types.h @@ -224,6 +224,7 @@ DefNode(CompositorNode, CMP_NODE_CRYPTOMATTE, def_cmp_cryptomatte, "CRYPTO DefNode(CompositorNode, CMP_NODE_CRYPTOMATTE_LEGACY, def_cmp_cryptomatte_legacy, "CRYPTOMATTE", Cryptomatte, "Cryptomatte (Legacy)", "" ) DefNode(CompositorNode, CMP_NODE_DENOISE, def_cmp_denoise, "DENOISE", Denoise, "Denoise", "" ) DefNode(CompositorNode, CMP_NODE_EXPOSURE, 0, "EXPOSURE", Exposure, "Exposure", "" ) +DefNode(CompositorNode, CMP_NODE_ANTIALIASING, def_cmp_antialiasing, "ANTIALIASING", AntiAliasing, "Anti-Aliasing", "" ) DefNode(TextureNode, TEX_NODE_OUTPUT, def_tex_output, "OUTPUT", Output, "Output", "" ) DefNode(TextureNode, TEX_NODE_CHECKER, 0, "CHECKER", Checker, "Checker", "" ) @@ -305,7 +306,9 @@ DefNode(GeometryNode, GEO_NODE_MESH_PRIMITIVE_CYLINDER, def_geo_mesh_cylinder, " DefNode(GeometryNode, GEO_NODE_MESH_PRIMITIVE_ICO_SPHERE, 0, "MESH_PRIMITIVE_ICO_SPHERE", MeshIcoSphere, "Ico Sphere", "") DefNode(GeometryNode, GEO_NODE_MESH_PRIMITIVE_CONE, def_geo_mesh_cone, "MESH_PRIMITIVE_CONE", MeshCone, "Cone", "") DefNode(GeometryNode, GEO_NODE_MESH_PRIMITIVE_LINE, def_geo_mesh_line, "MESH_PRIMITIVE_LINE", MeshLine, "Line", "") -DefNode(GeometryNode, GEO_NODE_MESH_PRIMITIVE_PLANE, 0, "MESH_PRIMITIVE_PLANE", MeshPlane, "Plane", "") +DefNode(GeometryNode, GEO_NODE_MESH_PRIMITIVE_GRID, 0, "MESH_PRIMITIVE_GRID", MeshGrid, "Grid", "") +DefNode(GeometryNode, GEO_NODE_ATTRIBUTE_MAP_RANGE, def_geo_attribute_map_range, "ATTRIBUTE_MAP_RANGE", AttributeMapRange, "Attribute Map Range", "") +DefNode(GeometryNode, GEO_NODE_ATTRIBUTE_CLAMP, def_geo_attribute_clamp, "ATTRIBUTE_CLAMP", AttributeClamp, "Attribute Clamp", "") /* undefine macros */ #undef DefNode diff --git a/source/blender/nodes/composite/nodes/node_composite_antialiasing.c b/source/blender/nodes/composite/nodes/node_composite_antialiasing.c new file mode 100644 index 00000000000..7437496d878 --- /dev/null +++ b/source/blender/nodes/composite/nodes/node_composite_antialiasing.c @@ -0,0 +1,65 @@ +/* + * ***** 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 ***** + */ + +/** \file blender/nodes/composite/nodes/node_composite_antialiasing.c + * \ingroup cmpnodes + */ + +#include "node_composite_util.h" + +/* **************** Anti-Aliasing (SMAA 1x) ******************** */ + +static bNodeSocketTemplate cmp_node_antialiasing_in[] = { + {SOCK_RGBA, N_("Image"), 1.0f, 1.0f, 1.0f, 1.0f}, {-1, ""}}; + +static bNodeSocketTemplate cmp_node_antialiasing_out[] = {{SOCK_RGBA, N_("Image")}, {-1, ""}}; + +static void node_composit_init_antialiasing(bNodeTree *UNUSED(ntree), bNode *node) +{ + NodeAntiAliasingData *data = MEM_callocN(sizeof(NodeAntiAliasingData), "node antialiasing data"); + + data->threshold = 1.0f; + data->contrast_limit = 0.2f; + data->corner_rounding = 0.25f; + + node->storage = data; +} + +void register_node_type_cmp_antialiasing(void) +{ + static bNodeType ntype; + + cmp_node_type_base( + &ntype, CMP_NODE_ANTIALIASING, "Anti-Aliasing", NODE_CLASS_OP_FILTER, NODE_PREVIEW); + node_type_socket_templates(&ntype, cmp_node_antialiasing_in, cmp_node_antialiasing_out); + node_type_size(&ntype, 170, 140, 200); + node_type_init(&ntype, node_composit_init_antialiasing); + node_type_storage( + &ntype, "NodeAntiAliasingData", node_free_standard_storage, node_copy_standard_storage); + + nodeRegisterType(&ntype); +} diff --git a/source/blender/nodes/geometry/nodes/node_geo_attribute_clamp.cc b/source/blender/nodes/geometry/nodes/node_geo_attribute_clamp.cc new file mode 100644 index 00000000000..93e4124bd70 --- /dev/null +++ b/source/blender/nodes/geometry/nodes/node_geo_attribute_clamp.cc @@ -0,0 +1,278 @@ + +/* + * 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. + */ + +#include "node_geometry_util.hh" + +#include "UI_interface.h" +#include "UI_resources.h" + +static bNodeSocketTemplate geo_node_attribute_clamp_in[] = { + {SOCK_GEOMETRY, N_("Geometry")}, + {SOCK_STRING, N_("Attribute")}, + {SOCK_STRING, N_("Result")}, + {SOCK_VECTOR, N_("Min"), 0.0f, 0.0f, 0.0f, 0.0f, -FLT_MAX, FLT_MAX}, + {SOCK_VECTOR, N_("Max"), 1.0f, 1.0f, 1.0f, 0.0f, -FLT_MAX, FLT_MAX}, + {SOCK_FLOAT, N_("Min"), 0.0f, 0.0f, 0.0f, 0.0f, -FLT_MAX, FLT_MAX}, + {SOCK_FLOAT, N_("Max"), 1.0f, 0.0f, 0.0f, 0.0f, -FLT_MAX, FLT_MAX}, + {SOCK_INT, N_("Min"), 0.0f, 0.0f, 0.0f, 0.0f, -100000, 100000}, + {SOCK_INT, N_("Max"), 100.0f, 0.0f, 0.0f, 0.0f, -100000, 100000}, + {SOCK_RGBA, N_("Min"), 0.5, 0.5, 0.5, 1.0}, + {SOCK_RGBA, N_("Max"), 0.5, 0.5, 0.5, 1.0}, + {-1, ""}, +}; + +static bNodeSocketTemplate geo_node_attribute_clamp_out[] = { + {SOCK_GEOMETRY, N_("Geometry")}, + {-1, ""}, +}; + +static void geo_node_attribute_clamp_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) +{ + uiItemR(layout, ptr, "data_type", 0, "", ICON_NONE); + uiItemR(layout, ptr, "operation", 0, "", ICON_NONE); +} + +static void geo_node_attribute_clamp_init(bNodeTree *UNUSED(tree), bNode *node) +{ + NodeAttributeClamp *data = (NodeAttributeClamp *)MEM_callocN(sizeof(NodeAttributeClamp), + __func__); + data->data_type = CD_PROP_FLOAT; + data->operation = NODE_CLAMP_MINMAX; + node->storage = data; +} + +static void geo_node_attribute_clamp_update(bNodeTree *UNUSED(ntree), bNode *node) +{ + bNodeSocket *sock_min_vector = (bNodeSocket *)BLI_findlink(&node->inputs, 3); + bNodeSocket *sock_max_vector = sock_min_vector->next; + bNodeSocket *sock_min_float = sock_max_vector->next; + bNodeSocket *sock_max_float = sock_min_float->next; + bNodeSocket *sock_min_int = sock_max_float->next; + bNodeSocket *sock_max_int = sock_min_int->next; + bNodeSocket *sock_min_color = sock_max_int->next; + bNodeSocket *sock_max_color = sock_min_color->next; + + const NodeAttributeClamp &storage = *(const NodeAttributeClamp *)node->storage; + const CustomDataType data_type = static_cast<CustomDataType>(storage.data_type); + nodeSetSocketAvailability(sock_min_vector, data_type == CD_PROP_FLOAT3); + nodeSetSocketAvailability(sock_max_vector, data_type == CD_PROP_FLOAT3); + nodeSetSocketAvailability(sock_min_float, data_type == CD_PROP_FLOAT); + nodeSetSocketAvailability(sock_max_float, data_type == CD_PROP_FLOAT); + nodeSetSocketAvailability(sock_min_int, data_type == CD_PROP_INT32); + nodeSetSocketAvailability(sock_max_int, data_type == CD_PROP_INT32); + nodeSetSocketAvailability(sock_min_color, data_type == CD_PROP_COLOR); + nodeSetSocketAvailability(sock_max_color, data_type == CD_PROP_COLOR); +} + +namespace blender::nodes { + +template<typename T> T clamp_value(const T val, const T min, const T max); + +template<> inline float clamp_value(const float val, const float min, const float max) +{ + return std::min(std::max(val, min), max); +} + +template<> inline int clamp_value(const int val, const int min, const int max) +{ + return std::min(std::max(val, min), max); +} + +template<> inline float3 clamp_value(const float3 val, const float3 min, const float3 max) +{ + float3 tmp; + tmp.x = std::min(std::max(val.x, min.x), max.x); + tmp.y = std::min(std::max(val.y, min.y), max.y); + tmp.z = std::min(std::max(val.z, min.z), max.z); + return tmp; +} + +template<> inline Color4f clamp_value(const Color4f val, const Color4f min, const Color4f max) +{ + Color4f tmp; + tmp.r = std::min(std::max(val.r, min.r), max.r); + tmp.g = std::min(std::max(val.g, min.g), max.g); + tmp.b = std::min(std::max(val.b, min.b), max.b); + tmp.a = std::min(std::max(val.a, min.a), max.a); + return tmp; +} + +template<typename T> +static void clamp_attribute(Span<T> read_span, MutableSpan<T> span, const T min, const T max) +{ + for (const int i : span.index_range()) { + span[i] = clamp_value<T>(read_span[i], min, max); + } +} + +static AttributeDomain get_result_domain(const GeometryComponent &component, + StringRef source_name, + StringRef result_name) +{ + ReadAttributePtr result_attribute = component.attribute_try_get_for_read(result_name); + if (result_attribute) { + return result_attribute->domain(); + } + ReadAttributePtr source_attribute = component.attribute_try_get_for_read(source_name); + if (source_attribute) { + return source_attribute->domain(); + } + return ATTR_DOMAIN_POINT; +} + +static void clamp_attribute(GeometryComponent &component, const GeoNodeExecParams ¶ms) +{ + const std::string attribute_name = params.get_input<std::string>("Attribute"); + const std::string result_name = params.get_input<std::string>("Result"); + + if (attribute_name.empty() || result_name.empty()) { + return; + } + + if (!component.attribute_exists(attribute_name)) { + params.error_message_add(NodeWarningType::Error, + TIP_("No attribute with name \"") + attribute_name + "\""); + return; + } + + const NodeAttributeClamp &storage = *(const NodeAttributeClamp *)params.node().storage; + const CustomDataType data_type = static_cast<CustomDataType>(storage.data_type); + const AttributeDomain domain = get_result_domain(component, attribute_name, result_name); + const int operation = static_cast<int>(storage.operation); + + ReadAttributePtr attribute_input = component.attribute_try_get_for_read( + attribute_name, domain, data_type); + + OutputAttributePtr attribute_result = component.attribute_try_get_for_output( + result_name, domain, data_type); + + if (!attribute_result) { + params.error_message_add(NodeWarningType::Error, + TIP_("Could not find or create attribute with name \"") + + result_name + "\""); + return; + } + + switch (data_type) { + case CD_PROP_FLOAT3: { + Span<float3> read_span = attribute_input->get_span<float3>(); + MutableSpan<float3> span = attribute_result->get_span_for_write_only<float3>(); + float3 min = params.get_input<float3>("Min"); + float3 max = params.get_input<float3>("Max"); + if (operation == NODE_CLAMP_RANGE) { + if (min.x > max.x) { + std::swap(min.x, max.x); + } + if (min.y > max.y) { + std::swap(min.y, max.y); + } + if (min.z > max.z) { + std::swap(min.z, max.z); + } + } + clamp_attribute<float3>(read_span, span, min, max); + break; + } + case CD_PROP_FLOAT: { + Span<float> read_span = attribute_input->get_span<float>(); + MutableSpan<float> span = attribute_result->get_span_for_write_only<float>(); + const float min = params.get_input<float>("Min_001"); + const float max = params.get_input<float>("Max_001"); + if (operation == NODE_CLAMP_RANGE && min > max) { + clamp_attribute<float>(read_span, span, max, min); + } + else { + clamp_attribute<float>(read_span, span, min, max); + } + break; + } + case CD_PROP_INT32: { + Span<int> read_span = attribute_input->get_span<int>(); + MutableSpan<int> span = attribute_result->get_span_for_write_only<int>(); + const int min = params.get_input<int>("Min_002"); + const int max = params.get_input<int>("Max_002"); + if (operation == NODE_CLAMP_RANGE && min > max) { + clamp_attribute<int>(read_span, span, max, min); + } + else { + clamp_attribute<int>(read_span, span, min, max); + } + break; + } + case CD_PROP_COLOR: { + Span<Color4f> read_span = attribute_input->get_span<Color4f>(); + MutableSpan<Color4f> span = attribute_result->get_span_for_write_only<Color4f>(); + Color4f min = params.get_input<Color4f>("Min_003"); + Color4f max = params.get_input<Color4f>("Max_003"); + if (operation == NODE_CLAMP_RANGE) { + if (min.r > max.r) { + std::swap(min.r, max.r); + } + if (min.g > max.g) { + std::swap(min.g, max.g); + } + if (min.b > max.b) { + std::swap(min.b, max.b); + } + if (min.a > max.a) { + std::swap(min.a, max.a); + } + } + clamp_attribute<Color4f>(read_span, span, min, max); + break; + } + default: { + BLI_assert(false); + break; + } + } + + attribute_result.apply_span_and_save(); +} + +static void geo_node_attribute_clamp_exec(GeoNodeExecParams params) +{ + GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry"); + + geometry_set = geometry_set_realize_instances(geometry_set); + + if (geometry_set.has<MeshComponent>()) { + clamp_attribute(geometry_set.get_component_for_write<MeshComponent>(), params); + } + if (geometry_set.has<PointCloudComponent>()) { + clamp_attribute(geometry_set.get_component_for_write<PointCloudComponent>(), params); + } + + params.set_output("Geometry", geometry_set); +} + +} // namespace blender::nodes + +void register_node_type_geo_attribute_clamp() +{ + static bNodeType ntype; + + geo_node_type_base(&ntype, GEO_NODE_ATTRIBUTE_CLAMP, "Attribute Clamp", NODE_CLASS_ATTRIBUTE, 0); + node_type_socket_templates(&ntype, geo_node_attribute_clamp_in, geo_node_attribute_clamp_out); + node_type_init(&ntype, geo_node_attribute_clamp_init); + node_type_update(&ntype, geo_node_attribute_clamp_update); + ntype.geometry_node_execute = blender::nodes::geo_node_attribute_clamp_exec; + ntype.draw_buttons = geo_node_attribute_clamp_layout; + node_type_storage( + &ntype, "NodeAttributeClamp", node_free_standard_storage, node_copy_standard_storage); + nodeRegisterType(&ntype); +} diff --git a/source/blender/nodes/geometry/nodes/node_geo_attribute_map_range.cc b/source/blender/nodes/geometry/nodes/node_geo_attribute_map_range.cc new file mode 100644 index 00000000000..4e0dfd3a636 --- /dev/null +++ b/source/blender/nodes/geometry/nodes/node_geo_attribute_map_range.cc @@ -0,0 +1,417 @@ +/* + * 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. + */ + +#include "node_geometry_util.hh" + +#include "BLI_math_base_safe.h" + +#include "UI_interface.h" +#include "UI_resources.h" + +static bNodeSocketTemplate geo_node_attribute_map_range_in[] = { + {SOCK_GEOMETRY, N_("Geometry")}, + {SOCK_STRING, N_("Attribute")}, + {SOCK_STRING, N_("Result")}, + {SOCK_FLOAT, N_("From Min"), 0.0f, 0.0f, 0.0f, 0.0f, -FLT_MAX, FLT_MAX}, + {SOCK_FLOAT, N_("From Max"), 1.0f, 0.0f, 0.0f, 0.0f, -FLT_MAX, FLT_MAX}, + {SOCK_FLOAT, N_("To Min"), 0.0f, 0.0f, 0.0f, 0.0f, -FLT_MAX, FLT_MAX}, + {SOCK_FLOAT, N_("To Max"), 1.0f, 0.0f, 0.0f, 0.0f, -FLT_MAX, FLT_MAX}, + {SOCK_FLOAT, N_("Steps"), 4.0f, 4.0f, 4.0f, 0.0f, -FLT_MAX, FLT_MAX}, + {SOCK_VECTOR, N_("From Min"), 0.0f, 0.0f, 0.0f, 0.0f, -FLT_MAX, FLT_MAX}, + {SOCK_VECTOR, N_("From Max"), 1.0f, 1.0f, 1.0f, 0.0f, -FLT_MAX, FLT_MAX}, + {SOCK_VECTOR, N_("To Min"), 0.0f, 0.0f, 0.0f, 0.0f, -FLT_MAX, FLT_MAX}, + {SOCK_VECTOR, N_("To Max"), 1.0f, 1.0f, 1.0f, 0.0f, -FLT_MAX, FLT_MAX}, + {SOCK_VECTOR, N_("Steps"), 4.0f, 4.0f, 4.0f, 0.0f, -FLT_MAX, FLT_MAX}, + {SOCK_BOOLEAN, N_("Clamp")}, + {-1, ""}, +}; + +static bNodeSocketTemplate geo_node_attribute_map_range_out[] = { + {SOCK_GEOMETRY, N_("Geometry")}, + {-1, ""}, +}; + +static void fn_attribute_map_range_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) +{ + uiItemR(layout, ptr, "data_type", 0, "", ICON_NONE); + uiItemR(layout, ptr, "interpolation_type", 0, "", ICON_NONE); +} + +static void geo_node_attribute_map_range_init(bNodeTree *UNUSED(ntree), bNode *node) +{ + NodeAttributeMapRange *data = (NodeAttributeMapRange *)MEM_callocN(sizeof(NodeAttributeMapRange), + __func__); + data->data_type = CD_PROP_FLOAT; + data->interpolation_type = NODE_MAP_RANGE_LINEAR; + + node->storage = data; +} +static void geo_node_attribute_map_range_update(bNodeTree *UNUSED(ntree), bNode *node) +{ + NodeAttributeMapRange &node_storage = *(NodeAttributeMapRange *)node->storage; + + bNodeSocket *sock_from_min_float = (bNodeSocket *)BLI_findlink(&node->inputs, 3); + bNodeSocket *sock_from_max_float = sock_from_min_float->next; + bNodeSocket *sock_to_min_float = sock_from_max_float->next; + bNodeSocket *sock_to_max_float = sock_to_min_float->next; + bNodeSocket *sock_steps_float = sock_to_max_float->next; + + bNodeSocket *sock_from_min_vector = sock_steps_float->next; + bNodeSocket *sock_from_max_vector = sock_from_min_vector->next; + bNodeSocket *sock_to_min_vector = sock_from_max_vector->next; + bNodeSocket *sock_to_max_vector = sock_to_min_vector->next; + bNodeSocket *sock_steps_vector = sock_to_max_vector->next; + + bNodeSocket *sock_clamp = sock_steps_vector->next; + + const CustomDataType data_type = static_cast<CustomDataType>(node_storage.data_type); + + nodeSetSocketAvailability(sock_clamp, + node_storage.interpolation_type == NODE_MAP_RANGE_LINEAR || + node_storage.interpolation_type == NODE_MAP_RANGE_STEPPED); + + nodeSetSocketAvailability(sock_from_min_float, data_type == CD_PROP_FLOAT); + nodeSetSocketAvailability(sock_from_max_float, data_type == CD_PROP_FLOAT); + nodeSetSocketAvailability(sock_to_min_float, data_type == CD_PROP_FLOAT); + nodeSetSocketAvailability(sock_to_max_float, data_type == CD_PROP_FLOAT); + nodeSetSocketAvailability(sock_steps_float, + data_type == CD_PROP_FLOAT && + node_storage.interpolation_type == NODE_MAP_RANGE_STEPPED); + + nodeSetSocketAvailability(sock_from_min_vector, data_type == CD_PROP_FLOAT3); + nodeSetSocketAvailability(sock_from_max_vector, data_type == CD_PROP_FLOAT3); + nodeSetSocketAvailability(sock_to_min_vector, data_type == CD_PROP_FLOAT3); + nodeSetSocketAvailability(sock_to_max_vector, data_type == CD_PROP_FLOAT3); + nodeSetSocketAvailability(sock_steps_vector, + data_type == CD_PROP_FLOAT3 && + node_storage.interpolation_type == NODE_MAP_RANGE_STEPPED); +} + +namespace blender::nodes { + +static float map_linear(const float value, + const float min_from, + const float max_from, + const float min_to, + const float max_to) +{ + /* First we calculate a fraction that measures how far along + * the [min_from, max_from] interval the value lies. + * + * value + * min_from [------>|------------------------] max_from + * factor (e.g. 0.25) + * + * Then to find where the value is mapped, we add the same fraction + * of the [min_to, max_to] interval to min_to. + * + * min_to [--->|-----------] max_to + * v + * min_to + (max_to - min_to) * factor + */ + const float factor = safe_divide(value - min_from, max_from - min_from); + return min_to + factor * (max_to - min_to); +} + +static float map_stepped(const float value, + const float min_from, + const float max_from, + const float min_to, + const float max_to, + const float steps) +{ + /* First the factor is calculated here in the same way as for the linear mapping. + * + * Then the factor is mapped to multiples of 1.0 / steps. + * This is best understood with a few examples. Assume steps == 3. + * ____________________________________ + * | factor | * 4.0 | floor() | / 3.0 | + * |--------|-------|---------|-------| + * | 0.0 | 0.0 | 0.0 | 0.0 | + * | 0.1 | 0.4 | 0.0 | 0.0 | + * | 0.25 | 1.0 | 1.0 | 0.333 | + * | 0.45 | 1.8 | 1.0 | 0.333 | + * | 0.5 | 2.0 | 2.0 | 0.666 | + * | 0.55 | 2.2 | 2.0 | 0.666 | + * | 0.999 | 3.999 | 3.0 | 1.0 | + * | 1.0 | 4.0 | 4.0 | 1.333 | + * ------------------------------------ + * Note that the factor is not always mapped the closest multiple of 1.0 /steps. + */ + const float factor = safe_divide(value - min_from, max_from - min_from); + const float factor_mapped = safe_divide(floorf(factor * (steps + 1.0f)), steps); + return min_to + factor_mapped * (max_to - min_to); +} + +static float smoothstep_polynomial(float x) +{ + /* This polynomial is only meant to be used for the [0, 1] range. */ + return (3.0f - 2.0f * x) * (x * x); +} + +static float map_smoothstep(const float value, + const float min_from, + const float max_from, + const float min_to, + const float max_to) +{ + const float factor = safe_divide(value - min_from, max_from - min_from); + const float factor_clamped = std::clamp(factor, 0.0f, 1.0f); + const float factor_mapped = smoothstep_polynomial(factor_clamped); + return min_to + factor_mapped * (max_to - min_to); +} + +static float smootherstep_polynomial(float x) +{ + /* This polynomial is only meant to be used for the [0, 1] range. */ + return x * x * x * (x * (x * 6.0f - 15.0f) + 10.0f); +} + +static float map_smootherstep(const float value, + const float min_from, + const float max_from, + const float min_to, + const float max_to) +{ + const float factor = safe_divide(value - min_from, max_from - min_from); + const float factor_clamped = std::clamp(factor, 0.0f, 1.0f); + const float factor_mapped = smootherstep_polynomial(factor_clamped); + return min_to + factor_mapped * (max_to - min_to); +} + +static void map_range_float(FloatReadAttribute attribute_input, + FloatWriteAttribute attribute_result, + const GeoNodeExecParams ¶ms) +{ + const bNode &node = params.node(); + NodeAttributeMapRange &node_storage = *(NodeAttributeMapRange *)node.storage; + const int interpolation_type = node_storage.interpolation_type; + const float min_from = params.get_input<float>("From Min"); + const float max_from = params.get_input<float>("From Max"); + const float min_to = params.get_input<float>("To Min"); + const float max_to = params.get_input<float>("To Max"); + + Span<float> span = attribute_input.get_span(); + MutableSpan<float> result_span = attribute_result.get_span(); + + switch (interpolation_type) { + case NODE_MAP_RANGE_LINEAR: { + for (int i : span.index_range()) { + result_span[i] = map_linear(span[i], min_from, max_from, min_to, max_to); + } + break; + } + case NODE_MAP_RANGE_STEPPED: { + const float steps = params.get_input<float>("Steps"); + for (int i : span.index_range()) { + result_span[i] = map_stepped(span[i], min_from, max_from, min_to, max_to, steps); + } + break; + } + case NODE_MAP_RANGE_SMOOTHSTEP: { + for (int i : span.index_range()) { + result_span[i] = map_smoothstep(span[i], min_from, max_from, min_to, max_to); + } + break; + } + case NODE_MAP_RANGE_SMOOTHERSTEP: { + for (int i : span.index_range()) { + result_span[i] = map_smootherstep(span[i], min_from, max_from, min_to, max_to); + } + break; + } + } + + if (ELEM(interpolation_type, NODE_MAP_RANGE_LINEAR, NODE_MAP_RANGE_STEPPED) && + params.get_input<bool>("Clamp")) { + /* Users can specify min_to > max_to, but clamping expects min < max. */ + const float clamp_min = min_to < max_to ? min_to : max_to; + const float clamp_max = min_to < max_to ? max_to : min_to; + + for (int i : result_span.index_range()) { + result_span[i] = std::clamp(result_span[i], clamp_min, clamp_max); + } + } +} + +static void map_range_float3(Float3ReadAttribute attribute_input, + Float3WriteAttribute attribute_result, + const GeoNodeExecParams ¶ms) +{ + const bNode &node = params.node(); + NodeAttributeMapRange &node_storage = *(NodeAttributeMapRange *)node.storage; + const int interpolation_type = node_storage.interpolation_type; + const float3 min_from = params.get_input<float3>("From Min_001"); + const float3 max_from = params.get_input<float3>("From Max_001"); + const float3 min_to = params.get_input<float3>("To Min_001"); + const float3 max_to = params.get_input<float3>("To Max_001"); + + Span<float3> span = attribute_input.get_span(); + MutableSpan<float3> result_span = attribute_result.get_span(); + + switch (interpolation_type) { + case NODE_MAP_RANGE_LINEAR: { + for (int i : span.index_range()) { + result_span[i].x = map_linear(span[i].x, min_from.x, max_from.x, min_to.x, max_to.x); + result_span[i].y = map_linear(span[i].y, min_from.y, max_from.y, min_to.y, max_to.y); + result_span[i].z = map_linear(span[i].z, min_from.z, max_from.z, min_to.z, max_to.z); + } + break; + } + case NODE_MAP_RANGE_STEPPED: { + const float3 steps = params.get_input<float3>("Steps_001"); + for (int i : span.index_range()) { + result_span[i].x = map_stepped( + span[i].x, min_from.x, max_from.x, min_to.x, max_to.x, steps.x); + result_span[i].y = map_stepped( + span[i].y, min_from.y, max_from.y, min_to.y, max_to.y, steps.y); + result_span[i].z = map_stepped( + span[i].z, min_from.z, max_from.z, min_to.z, max_to.z, steps.z); + } + break; + } + case NODE_MAP_RANGE_SMOOTHSTEP: { + for (int i : span.index_range()) { + result_span[i].x = map_smoothstep(span[i].x, min_from.x, max_from.x, min_to.x, max_to.x); + result_span[i].y = map_smoothstep(span[i].y, min_from.y, max_from.y, min_to.y, max_to.y); + result_span[i].z = map_smoothstep(span[i].z, min_from.z, max_from.z, min_to.z, max_to.z); + } + break; + } + case NODE_MAP_RANGE_SMOOTHERSTEP: { + for (int i : span.index_range()) { + result_span[i].x = map_smootherstep(span[i].x, min_from.x, max_from.x, min_to.x, max_to.x); + result_span[i].y = map_smootherstep(span[i].y, min_from.y, max_from.y, min_to.y, max_to.y); + result_span[i].z = map_smootherstep(span[i].z, min_from.z, max_from.z, min_to.z, max_to.z); + } + break; + } + } + + if (ELEM(interpolation_type, NODE_MAP_RANGE_LINEAR, NODE_MAP_RANGE_STEPPED) && + params.get_input<bool>("Clamp")) { + /* Users can specify min_to > max_to, but clamping expects min < max. */ + float3 clamp_min; + float3 clamp_max; + clamp_min.x = min_to.x < max_to.x ? min_to.x : max_to.x; + clamp_max.x = min_to.x < max_to.x ? max_to.x : min_to.x; + clamp_min.y = min_to.y < max_to.y ? min_to.y : max_to.y; + clamp_max.y = min_to.y < max_to.y ? max_to.y : min_to.y; + clamp_min.z = min_to.z < max_to.z ? min_to.z : max_to.z; + clamp_max.z = min_to.z < max_to.z ? max_to.z : min_to.z; + + for (int i : result_span.index_range()) { + clamp_v3_v3v3(result_span[i], clamp_min, clamp_max); + } + } +} + +static AttributeDomain get_result_domain(const GeometryComponent &component, + StringRef source_name, + StringRef result_name) +{ + ReadAttributePtr result_attribute = component.attribute_try_get_for_read(result_name); + if (result_attribute) { + return result_attribute->domain(); + } + ReadAttributePtr source_attribute = component.attribute_try_get_for_read(source_name); + if (source_attribute) { + return source_attribute->domain(); + } + return ATTR_DOMAIN_POINT; +} + +static void map_range_attribute(GeometryComponent &component, const GeoNodeExecParams ¶ms) +{ + const std::string input_name = params.get_input<std::string>("Attribute"); + const std::string result_name = params.get_input<std::string>("Result"); + + if (input_name.empty() || result_name.empty()) { + return; + } + + const bNode &node = params.node(); + NodeAttributeMapRange &node_storage = *(NodeAttributeMapRange *)node.storage; + const CustomDataType data_type = static_cast<CustomDataType>(node_storage.data_type); + + const AttributeDomain domain = get_result_domain(component, input_name, result_name); + + ReadAttributePtr attribute_input = component.attribute_try_get_for_read( + input_name, domain, data_type); + + if (!attribute_input) { + params.error_message_add(NodeWarningType::Error, + TIP_("No attribute with name \"") + input_name + "\""); + return; + } + + OutputAttributePtr attribute_result = component.attribute_try_get_for_output( + result_name, domain, data_type); + if (!attribute_result) { + params.error_message_add(NodeWarningType::Error, + TIP_("Could not find or create attribute with name \"") + + result_name + "\""); + return; + } + + switch (data_type) { + case CD_PROP_FLOAT: { + map_range_float(*attribute_input, *attribute_result, params); + break; + } + case CD_PROP_FLOAT3: { + map_range_float3(*attribute_input, *attribute_result, params); + break; + } + default: + BLI_assert_unreachable(); + } + + attribute_result.apply_span_and_save(); +} + +static void geo_node_attribute_map_range_exec(GeoNodeExecParams params) +{ + GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry"); + + if (geometry_set.has<MeshComponent>()) { + map_range_attribute(geometry_set.get_component_for_write<MeshComponent>(), params); + } + if (geometry_set.has<PointCloudComponent>()) { + map_range_attribute(geometry_set.get_component_for_write<PointCloudComponent>(), params); + } + + params.set_output("Geometry", geometry_set); +} + +} // namespace blender::nodes + +void register_node_type_geo_attribute_map_range() +{ + static bNodeType ntype; + + geo_node_type_base( + &ntype, GEO_NODE_ATTRIBUTE_MAP_RANGE, "Attribute Map Range", NODE_CLASS_ATTRIBUTE, 0); + node_type_socket_templates( + &ntype, geo_node_attribute_map_range_in, geo_node_attribute_map_range_out); + ntype.geometry_node_execute = blender::nodes::geo_node_attribute_map_range_exec; + node_type_init(&ntype, geo_node_attribute_map_range_init); + node_type_update(&ntype, geo_node_attribute_map_range_update); + node_type_storage( + &ntype, "NodeAttributeMapRange", node_free_standard_storage, node_copy_standard_storage); + ntype.draw_buttons = fn_attribute_map_range_layout; + nodeRegisterType(&ntype); +} diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cone.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cone.cc index 9c48e7c44ba..0c970f0d2e2 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cone.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cone.cc @@ -223,8 +223,10 @@ Mesh *create_cylinder_or_cone_mesh(const float radius_top, transform.values, true); + BMeshToMeshParams params{}; + params.calc_object_remap = false; Mesh *mesh = (Mesh *)BKE_id_new_nomain(ID_ME, nullptr); - BM_mesh_bm_to_me_for_eval(bm, mesh, nullptr); + BM_mesh_bm_to_me(nullptr, bm, mesh, ¶ms); BM_mesh_free(bm); return mesh; diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cube.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cube.cc index 1803a13f651..f8a9bfd2ed1 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cube.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cube.cc @@ -50,8 +50,10 @@ static Mesh *create_cube_mesh(const float size) size, true); + BMeshToMeshParams params{}; + params.calc_object_remap = false; Mesh *mesh = (Mesh *)BKE_id_new_nomain(ID_ME, nullptr); - BM_mesh_bm_to_me_for_eval(bm, mesh, nullptr); + BM_mesh_bm_to_me(nullptr, bm, mesh, ¶ms); BM_mesh_free(bm); return mesh; diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_plane.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_grid.cc index eff84d7d1ad..1b9ec91a2f6 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_plane.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_grid.cc @@ -27,14 +27,14 @@ #include "node_geometry_util.hh" -static bNodeSocketTemplate geo_node_mesh_primitive_plane_in[] = { +static bNodeSocketTemplate geo_node_mesh_primitive_grid_in[] = { {SOCK_FLOAT, N_("Size"), 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, FLT_MAX, PROP_DISTANCE}, - {SOCK_INT, N_("Vertices X"), 10, 0.0f, 0.0f, 0.0f, 2, 1000}, - {SOCK_INT, N_("Vertices Y"), 10, 0.0f, 0.0f, 0.0f, 2, 1000}, + {SOCK_INT, N_("Vertices X"), 3, 0.0f, 0.0f, 0.0f, 2, 1000}, + {SOCK_INT, N_("Vertices Y"), 3, 0.0f, 0.0f, 0.0f, 2, 1000}, {-1, ""}, }; -static bNodeSocketTemplate geo_node_mesh_primitive_plane_out[] = { +static bNodeSocketTemplate geo_node_mesh_primitive_grid_out[] = { {SOCK_GEOMETRY, N_("Geometry")}, {-1, ""}, }; @@ -51,14 +51,14 @@ static void calculate_uvs(Mesh *mesh, Span<MVert> verts, Span<MLoop> loops, cons for (const int i : loops.index_range()) { const float3 &co = verts[loops[i].v].co; - uvs[i].x = (co.x + size) / (size * 2.0f); - uvs[i].y = (co.y + size) / (size * 2.0f); + uvs[i].x = (co.x + (size * 0.5)) / size; + uvs[i].y = (co.y + (size * 0.5)) / size; } uv_attribute.apply_span_and_save(); } -static Mesh *create_plane_mesh(const int verts_x, const int verts_y, const float size) +static Mesh *create_grid_mesh(const int verts_x, const int verts_y, const float size) { const int edges_x = verts_x - 1; const int edges_y = verts_y - 1; @@ -75,9 +75,9 @@ static Mesh *create_plane_mesh(const int verts_x, const int verts_y, const float { const float dx = size / edges_x; const float dy = size / edges_y; - float x = -size; + float x = -size * 0.5; for (const int x_index : IndexRange(verts_x)) { - float y = -size; + float y = -size * 0.5; for (const int y_index : IndexRange(verts_y)) { const int vert_index = x_index * verts_y + y_index; verts[vert_index].co[0] = x; @@ -147,7 +147,7 @@ static Mesh *create_plane_mesh(const int verts_x, const int verts_y, const float return mesh; } -static void geo_node_mesh_primitive_plane_exec(GeoNodeExecParams params) +static void geo_node_mesh_primitive_grid_exec(GeoNodeExecParams params) { const float size = params.extract_input<float>("Size"); const int verts_x = params.extract_input<int>("Vertices X"); @@ -157,7 +157,7 @@ static void geo_node_mesh_primitive_plane_exec(GeoNodeExecParams params) return; } - Mesh *mesh = create_plane_mesh(verts_x, verts_y, size); + Mesh *mesh = create_grid_mesh(verts_x, verts_y, size); BLI_assert(BKE_mesh_is_valid(mesh)); params.set_output("Geometry", GeometrySet::create_with_mesh(mesh)); @@ -165,13 +165,13 @@ static void geo_node_mesh_primitive_plane_exec(GeoNodeExecParams params) } // namespace blender::nodes -void register_node_type_geo_mesh_primitive_plane() +void register_node_type_geo_mesh_primitive_grid() { static bNodeType ntype; - geo_node_type_base(&ntype, GEO_NODE_MESH_PRIMITIVE_PLANE, "Plane", NODE_CLASS_GEOMETRY, 0); + geo_node_type_base(&ntype, GEO_NODE_MESH_PRIMITIVE_GRID, "Grid", NODE_CLASS_GEOMETRY, 0); node_type_socket_templates( - &ntype, geo_node_mesh_primitive_plane_in, geo_node_mesh_primitive_plane_out); - ntype.geometry_node_execute = blender::nodes::geo_node_mesh_primitive_plane_exec; + &ntype, geo_node_mesh_primitive_grid_in, geo_node_mesh_primitive_grid_out); + ntype.geometry_node_execute = blender::nodes::geo_node_mesh_primitive_grid_exec; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_ico_sphere.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_ico_sphere.cc index f16b37fe977..242cc6ed7df 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_ico_sphere.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_ico_sphere.cc @@ -52,8 +52,10 @@ static Mesh *create_ico_sphere_mesh(const int subdivisions, const float radius) transform.values, true); + BMeshToMeshParams params{}; + params.calc_object_remap = false; Mesh *mesh = (Mesh *)BKE_id_new_nomain(ID_ME, nullptr); - BM_mesh_bm_to_me_for_eval(bm, mesh, nullptr); + BM_mesh_bm_to_me(nullptr, bm, mesh, ¶ms); BM_mesh_free(bm); return mesh; diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_uv_sphere.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_uv_sphere.cc index b7d249c18bc..8efba91da1a 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_uv_sphere.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_uv_sphere.cc @@ -85,8 +85,10 @@ static Mesh *create_uv_sphere_mesh_bmesh(const float radius, const int segments, transform.values, true); + BMeshToMeshParams params{}; + params.calc_object_remap = false; Mesh *mesh = (Mesh *)BKE_id_new_nomain(ID_ME, nullptr); - BM_mesh_bm_to_me_for_eval(bm, mesh, nullptr); + BM_mesh_bm_to_me(nullptr, bm, mesh, ¶ms); BM_mesh_free(bm); return mesh; diff --git a/source/blender/nodes/geometry/nodes/node_geo_point_distribute.cc b/source/blender/nodes/geometry/nodes/node_geo_point_distribute.cc index 4795970377a..1e1f5e9d085 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_point_distribute.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_point_distribute.cc @@ -310,10 +310,10 @@ BLI_NOINLINE static void interpolate_attribute_corner(const Mesh &mesh, } template<typename T> -BLI_NOINLINE static void interpolate_attribute_polygon(const Mesh &mesh, - const Span<int> looptri_indices, - const Span<T> data_in, - MutableSpan<T> data_out) +BLI_NOINLINE static void interpolate_attribute_face(const Mesh &mesh, + const Span<int> looptri_indices, + const Span<T> data_in, + MutableSpan<T> data_out) { BLI_assert(data_in.size() == mesh.totpoly); Span<MLoopTri> looptris = get_mesh_looptris(mesh); @@ -344,8 +344,8 @@ BLI_NOINLINE static void interpolate_attribute(const Mesh &mesh, mesh, bary_coords, looptri_indices, source_span, output_span); break; } - case ATTR_DOMAIN_POLYGON: { - interpolate_attribute_polygon<T>(mesh, looptri_indices, source_span, output_span); + case ATTR_DOMAIN_FACE: { + interpolate_attribute_face<T>(mesh, looptri_indices, source_span, output_span); break; } default: { @@ -636,7 +636,8 @@ static void geo_node_point_distribute_exec(GeoNodeExecParams params) return; } - Vector<GeometryInstanceGroup> set_groups = bke::geometry_set_gather_instances(geometry_set); + Vector<GeometryInstanceGroup> set_groups; + geometry_set_gather_instances(geometry_set, set_groups); if (set_groups.is_empty()) { params.set_output("Geometry", GeometrySet()); return; diff --git a/source/blender/nodes/geometry/nodes/node_geo_point_instance.cc b/source/blender/nodes/geometry/nodes/node_geo_point_instance.cc index dbbb73bd36d..5d8f0a76719 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_point_instance.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_point_instance.cc @@ -188,9 +188,8 @@ static void add_instances_from_geometry_component(InstancesComponent &instances, for (const int i : IndexRange(domain_size)) { if (instances_data[i].has_value()) { - float transform[4][4]; - loc_eul_size_to_mat4(transform, positions[i], rotations[i], scales[i]); - instances.add_instance(*instances_data[i], transform, ids[i]); + const float4x4 matrix = float4x4::from_loc_eul_scale(positions[i], rotations[i], scales[i]); + instances.add_instance(*instances_data[i], matrix, ids[i]); } } } diff --git a/source/blender/nodes/geometry/nodes/node_geo_points_to_volume.cc b/source/blender/nodes/geometry/nodes/node_geo_points_to_volume.cc index b79ca0a6197..eb441a0a568 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_points_to_volume.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_points_to_volume.cc @@ -38,7 +38,7 @@ static bNodeSocketTemplate geo_node_points_to_volume_in[] = { {-1, ""}, }; -static bNodeSocketTemplate geo_node_point_translate_out[] = { +static bNodeSocketTemplate geo_node_points_to_volume_out[] = { {SOCK_GEOMETRY, N_("Geometry")}, {-1, ""}, }; @@ -262,7 +262,7 @@ void register_node_type_geo_points_to_volume() geo_node_type_base( &ntype, GEO_NODE_POINTS_TO_VOLUME, "Points to Volume", NODE_CLASS_GEOMETRY, 0); - node_type_socket_templates(&ntype, geo_node_points_to_volume_in, geo_node_point_translate_out); + node_type_socket_templates(&ntype, geo_node_points_to_volume_in, geo_node_points_to_volume_out); node_type_storage(&ntype, "NodeGeometryPointsToVolume", node_free_standard_storage, diff --git a/source/blender/nodes/geometry/nodes/node_geo_transform.cc b/source/blender/nodes/geometry/nodes/node_geo_transform.cc index ef6f0be40f2..2c05c98c9ba 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_transform.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_transform.cc @@ -18,7 +18,7 @@ # include <openvdb/openvdb.h> #endif -#include "BLI_math_matrix.h" +#include "BLI_float4x4.hh" #include "DNA_pointcloud_types.h" #include "DNA_volume_types.h" @@ -65,13 +65,12 @@ void transform_mesh(Mesh *mesh, /* Use only translation if rotation and scale are zero. */ if (use_translate(rotation, scale)) { if (!translation.is_zero()) { - BKE_mesh_translate(mesh, translation, true); + BKE_mesh_translate(mesh, translation, false); } } else { - float mat[4][4]; - loc_eul_size_to_mat4(mat, translation, rotation, scale); - BKE_mesh_transform(mesh, mat, true); + const float4x4 matrix = float4x4::from_loc_eul_scale(translation, rotation, scale); + BKE_mesh_transform(mesh, matrix.values, false); BKE_mesh_calc_normals(mesh); } } @@ -83,15 +82,15 @@ static void transform_pointcloud(PointCloud *pointcloud, { /* Use only translation if rotation and scale don't apply. */ if (use_translate(rotation, scale)) { - for (int i = 0; i < pointcloud->totpoint; i++) { + for (const int i : IndexRange(pointcloud->totpoint)) { add_v3_v3(pointcloud->co[i], translation); } } else { - float mat[4][4]; - loc_eul_size_to_mat4(mat, translation, rotation, scale); - for (int i = 0; i < pointcloud->totpoint; i++) { - mul_m4_v3(mat, pointcloud->co[i]); + const float4x4 matrix = float4x4::from_loc_eul_scale(translation, rotation, scale); + for (const int i : IndexRange(pointcloud->totpoint)) { + float3 &co = *(float3 *)pointcloud->co[i]; + co = matrix * co; } } } @@ -110,11 +109,9 @@ static void transform_instances(InstancesComponent &instances, } } else { - float mat[4][4]; - - loc_eul_size_to_mat4(mat, translation, rotation, scale); + const float4x4 matrix = float4x4::from_loc_eul_scale(translation, rotation, scale); for (float4x4 &transform : transforms) { - mul_m4_m4_pre(transform.ptr(), mat); + transform = matrix * transform; } } } @@ -136,8 +133,7 @@ static void transform_volume(Volume *volume, Main *bmain = DEG_get_bmain(params.depsgraph()); BKE_volume_load(volume, bmain); - float matrix[4][4]; - loc_eul_size_to_mat4(matrix, translation, rotation, limited_scale); + const float4x4 matrix = float4x4::from_loc_eul_scale(translation, rotation, limited_scale); openvdb::Mat4s vdb_matrix; memcpy(vdb_matrix.asPointer(), matrix, sizeof(float[4][4])); diff --git a/source/blender/nodes/geometry/nodes/node_geo_volume_to_mesh.cc b/source/blender/nodes/geometry/nodes/node_geo_volume_to_mesh.cc index 54dccb613a1..1c0e7106b19 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_volume_to_mesh.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_volume_to_mesh.cc @@ -36,7 +36,7 @@ static bNodeSocketTemplate geo_node_volume_to_mesh_in[] = { {SOCK_GEOMETRY, N_("Geometry")}, - {SOCK_STRING, N_("Grid")}, + {SOCK_STRING, N_("Density")}, {SOCK_FLOAT, N_("Voxel Size"), 0.3f, 0.0f, 0.0f, 0.0f, 0.01f, FLT_MAX}, {SOCK_FLOAT, N_("Voxel Amount"), 64.0f, 0.0f, 0.0f, 0.0f, 0.0f, FLT_MAX}, {SOCK_FLOAT, N_("Threshold"), 0.1f, 0.0f, 0.0f, 0.0f, 0.0f, FLT_MAX}, @@ -64,7 +64,7 @@ static void geo_node_volume_to_mesh_init(bNodeTree *UNUSED(ntree), bNode *node) sizeof(NodeGeometryVolumeToMesh), __func__); data->resolution_mode = VOLUME_TO_MESH_RESOLUTION_MODE_GRID; - bNodeSocket *grid_socket = nodeFindSocket(node, SOCK_IN, "Grid"); + bNodeSocket *grid_socket = nodeFindSocket(node, SOCK_IN, "Density"); bNodeSocketValueString *grid_socket_value = (bNodeSocketValueString *)grid_socket->default_value; STRNCPY(grid_socket_value->value, "density"); @@ -120,7 +120,7 @@ static void create_mesh_from_volume(GeometrySet &geometry_set_in, Main *bmain = DEG_get_bmain(params.depsgraph()); BKE_volume_load(const_cast<Volume *>(volume), bmain); - const std::string grid_name = params.get_input<std::string>("Grid"); + const std::string grid_name = params.get_input<std::string>("Density"); VolumeGrid *volume_grid = BKE_volume_grid_find(volume, grid_name.c_str()); if (volume_grid == nullptr) { return; diff --git a/source/blender/nodes/intern/node_socket.cc b/source/blender/nodes/intern/node_socket.cc index 26df3f77738..b583523da98 100644 --- a/source/blender/nodes/intern/node_socket.cc +++ b/source/blender/nodes/intern/node_socket.cc @@ -52,7 +52,7 @@ struct bNodeSocket *node_add_socket_from_template(struct bNodeTree *ntree, struct bNode *node, struct bNodeSocketTemplate *stemp, - int in_out) + eNodeSocketInOut in_out) { bNodeSocket *sock = nodeAddStaticSocket( ntree, node, in_out, stemp->type, stemp->subtype, stemp->identifier, stemp->name); @@ -102,8 +102,11 @@ struct bNodeSocket *node_add_socket_from_template(struct bNodeTree *ntree, return sock; } -static bNodeSocket *verify_socket_template( - bNodeTree *ntree, bNode *node, int in_out, ListBase *socklist, bNodeSocketTemplate *stemp) +static bNodeSocket *verify_socket_template(bNodeTree *ntree, + bNode *node, + eNodeSocketInOut in_out, + ListBase *socklist, + bNodeSocketTemplate *stemp) { bNodeSocket *sock; @@ -132,7 +135,7 @@ static bNodeSocket *verify_socket_template( static void verify_socket_template_list(bNodeTree *ntree, bNode *node, - int in_out, + eNodeSocketInOut in_out, ListBase *socklist, bNodeSocketTemplate *stemp_first) { diff --git a/source/blender/nodes/intern/node_tree_multi_function.cc b/source/blender/nodes/intern/node_tree_multi_function.cc index b973350becd..c77a6b42f97 100644 --- a/source/blender/nodes/intern/node_tree_multi_function.cc +++ b/source/blender/nodes/intern/node_tree_multi_function.cc @@ -164,7 +164,8 @@ static DataTypeConversions create_implicit_conversions() add_implicit_conversion<float, float2>(conversions); add_implicit_conversion<float, float3>(conversions); add_implicit_conversion<float, int32_t>(conversions); - add_implicit_conversion<float, bool>(conversions); + add_implicit_conversion<float, bool>( + conversions, "float to boolean", [](float a) { return a > 0.0f; }); add_implicit_conversion<float, Color4f>( conversions, "float to Color4f", [](float a) { return Color4f(a, a, a, 1.0f); }); @@ -189,7 +190,8 @@ static DataTypeConversions create_implicit_conversions() add_implicit_conversion<float3, Color4f>( conversions, "float3 to Color4f", [](float3 a) { return Color4f(a.x, a.y, a.z, 1.0f); }); - add_implicit_conversion<int32_t, bool>(conversions); + add_implicit_conversion<int32_t, bool>( + conversions, "int32 to boolean", [](int32_t a) { return a > 0; }); add_implicit_conversion<int32_t, float>(conversions); add_implicit_conversion<int32_t, float2>( conversions, "int32 to float2", [](int32_t a) { return float2((float)a); }); @@ -209,9 +211,8 @@ static DataTypeConversions create_implicit_conversions() return (a) ? Color4f(1.0f, 1.0f, 1.0f, 1.0f) : Color4f(0.0f, 0.0f, 0.0f, 1.0f); }); - add_implicit_conversion<Color4f, bool>(conversions, "Color4f to boolean", [](Color4f a) { - return a.r != 0.0f && a.g != 0.0f && a.b != 0.0f; - }); + add_implicit_conversion<Color4f, bool>( + conversions, "Color4f to boolean", [](Color4f a) { return rgb_to_grayscale(a) > 0.0f; }); add_implicit_conversion<Color4f, float>( conversions, "Color4f to float", [](Color4f a) { return rgb_to_grayscale(a); }); add_implicit_conversion<Color4f, float2>( diff --git a/source/blender/nodes/shader/nodes/node_shader_vector_math.cc b/source/blender/nodes/shader/nodes/node_shader_vector_math.cc index 3a9822fbc8e..472f903e1a5 100644 --- a/source/blender/nodes/shader/nodes/node_shader_vector_math.cc +++ b/source/blender/nodes/shader/nodes/node_shader_vector_math.cc @@ -23,6 +23,8 @@ #include "node_shader_util.h" +#include "NOD_math_functions.hh" + /* **************** VECTOR MATH ******************** */ static bNodeSocketTemplate sh_node_vector_math_in[] = { {SOCK_VECTOR, N_("Vector"), 0.0f, 0.0f, 0.0f, 1.0f, -10000.0f, 10000.0f, PROP_NONE}, @@ -177,117 +179,79 @@ static const blender::fn::MultiFunction &get_multi_function( { using blender::float3; - const int mode = builder.bnode().custom1; - switch (mode) { - case NODE_VECTOR_MATH_ADD: { - static blender::fn::CustomMF_SI_SI_SO<float3, float3, float3> fn{ - "Add", [](float3 a, float3 b) { return a + b; }}; - return fn; - } - case NODE_VECTOR_MATH_SUBTRACT: { - static blender::fn::CustomMF_SI_SI_SO<float3, float3, float3> fn{ - "Subtract", [](float3 a, float3 b) { return a - b; }}; - return fn; - } - case NODE_VECTOR_MATH_MULTIPLY: { - static blender::fn::CustomMF_SI_SI_SO<float3, float3, float3> fn{ - "Multiply", [](float3 a, float3 b) { return a * b; }}; - return fn; - } - case NODE_VECTOR_MATH_DIVIDE: { - static blender::fn::CustomMF_SI_SI_SO<float3, float3, float3> fn{ - "Divide", [](float3 a, float3 b) { return float3::safe_divide(a, b); }}; - return fn; - } - case NODE_VECTOR_MATH_CROSS_PRODUCT: { - static blender::fn::CustomMF_SI_SI_SO<float3, float3, float3> fn{ - "Cross Product", float3::cross_high_precision}; - return fn; - } - case NODE_VECTOR_MATH_PROJECT: { - static blender::fn::CustomMF_SI_SI_SO<float3, float3, float3> fn{"Project", float3::project}; - return fn; - } - case NODE_VECTOR_MATH_REFLECT: { - static blender::fn::CustomMF_SI_SI_SO<float3, float3, float3> fn{ - "Reflect", [](float3 a, float3 b) { return a.reflected(b); }}; - return fn; - } - case NODE_VECTOR_MATH_DOT_PRODUCT: { - static blender::fn::CustomMF_SI_SI_SO<float3, float3, float> fn{"Dot Product", float3::dot}; - return fn; - } - case NODE_VECTOR_MATH_DISTANCE: { - static blender::fn::CustomMF_SI_SI_SO<float3, float3, float> fn{"Distance", - float3::distance}; - return fn; - } - case NODE_VECTOR_MATH_LENGTH: { - static blender::fn::CustomMF_SI_SO<float3, float> fn{"Length", - [](float3 a) { return a.length(); }}; - return fn; - } - case NODE_VECTOR_MATH_SCALE: { - static blender::fn::CustomMF_SI_SI_SO<float3, float, float3> fn{ - "Scale", [](float3 a, float factor) { return a * factor; }}; - return fn; - } - case NODE_VECTOR_MATH_NORMALIZE: { - static blender::fn::CustomMF_SI_SO<float3, float3> fn{ - "Normalize", [](float3 a) { return a.normalized(); }}; - return fn; - } - case NODE_VECTOR_MATH_REFRACT: { - static blender::fn::CustomMF_SI_SI_SI_SO<float3, float3, float, float3> fn{ - "Refract", - [](float3 a, float3 b, float c) { return float3::refract(a, b.normalized(), c); }}; - return fn; - } - case NODE_VECTOR_MATH_FACEFORWARD: { - static blender::fn::CustomMF_SI_SI_SI_SO<float3, float3, float3, float3> fn{ - "Faceforward", float3::faceforward}; - return fn; - } - case NODE_VECTOR_MATH_SNAP: { - return builder.get_not_implemented_fn(); - } - case NODE_VECTOR_MATH_FLOOR: { - return builder.get_not_implemented_fn(); - } - case NODE_VECTOR_MATH_CEIL: { - return builder.get_not_implemented_fn(); - } - case NODE_VECTOR_MATH_MODULO: { - return builder.get_not_implemented_fn(); - } - case NODE_VECTOR_MATH_FRACTION: { - return builder.get_not_implemented_fn(); - } - case NODE_VECTOR_MATH_ABSOLUTE: { - return builder.get_not_implemented_fn(); - } - case NODE_VECTOR_MATH_MINIMUM: { - return builder.get_not_implemented_fn(); - } - case NODE_VECTOR_MATH_MAXIMUM: { - return builder.get_not_implemented_fn(); - } - case NODE_VECTOR_MATH_WRAP: { - return builder.get_not_implemented_fn(); - } - case NODE_VECTOR_MATH_SINE: { - return builder.get_not_implemented_fn(); - } - case NODE_VECTOR_MATH_COSINE: { - return builder.get_not_implemented_fn(); - } - case NODE_VECTOR_MATH_TANGENT: { - return builder.get_not_implemented_fn(); - } - default: - BLI_assert_unreachable(); - return builder.get_not_implemented_fn(); - }; + NodeVectorMathOperation operation = NodeVectorMathOperation(builder.bnode().custom1); + + const blender::fn::MultiFunction *multi_fn = nullptr; + + blender::nodes::try_dispatch_float_math_fl3_fl3_to_fl3( + operation, [&](auto function, const blender::nodes::FloatMathOperationInfo &info) { + static blender::fn::CustomMF_SI_SI_SO<float3, float3, float3> fn{info.title_case_name, + function}; + multi_fn = &fn; + }); + if (multi_fn != nullptr) { + return *multi_fn; + } + + blender::nodes::try_dispatch_float_math_fl3_fl3_fl3_to_fl3( + operation, [&](auto function, const blender::nodes::FloatMathOperationInfo &info) { + static blender::fn::CustomMF_SI_SI_SI_SO<float3, float3, float3, float3> fn{ + info.title_case_name, function}; + multi_fn = &fn; + }); + if (multi_fn != nullptr) { + return *multi_fn; + } + + blender::nodes::try_dispatch_float_math_fl3_fl3_fl_to_fl3( + operation, [&](auto function, const blender::nodes::FloatMathOperationInfo &info) { + static blender::fn::CustomMF_SI_SI_SI_SO<float3, float3, float, float3> fn{ + info.title_case_name, function}; + multi_fn = &fn; + }); + if (multi_fn != nullptr) { + return *multi_fn; + } + + blender::nodes::try_dispatch_float_math_fl3_fl3_to_fl( + operation, [&](auto function, const blender::nodes::FloatMathOperationInfo &info) { + static blender::fn::CustomMF_SI_SI_SO<float3, float3, float> fn{info.title_case_name, + function}; + multi_fn = &fn; + }); + if (multi_fn != nullptr) { + return *multi_fn; + } + + blender::nodes::try_dispatch_float_math_fl3_fl_to_fl3( + operation, [&](auto function, const blender::nodes::FloatMathOperationInfo &info) { + static blender::fn::CustomMF_SI_SI_SO<float3, float, float3> fn{info.title_case_name, + function}; + multi_fn = &fn; + }); + if (multi_fn != nullptr) { + return *multi_fn; + } + + blender::nodes::try_dispatch_float_math_fl3_to_fl3( + operation, [&](auto function, const blender::nodes::FloatMathOperationInfo &info) { + static blender::fn::CustomMF_SI_SO<float3, float3> fn{info.title_case_name, function}; + multi_fn = &fn; + }); + if (multi_fn != nullptr) { + return *multi_fn; + } + + blender::nodes::try_dispatch_float_math_fl3_to_fl( + operation, [&](auto function, const blender::nodes::FloatMathOperationInfo &info) { + static blender::fn::CustomMF_SI_SO<float3, float> fn{info.title_case_name, function}; + multi_fn = &fn; + }); + if (multi_fn != nullptr) { + return *multi_fn; + } + + return builder.get_not_implemented_fn(); } static void sh_node_vector_math_expand_in_mf_network(blender::nodes::NodeMFNetworkBuilder &builder) diff --git a/source/blender/python/gpu/gpu_py_state.c b/source/blender/python/gpu/gpu_py_state.c index 110f5a6ff55..6b0fade8d1c 100644 --- a/source/blender/python/gpu/gpu_py_state.c +++ b/source/blender/python/gpu/gpu_py_state.c @@ -85,19 +85,20 @@ PyDoc_STRVAR( " Defines the fixed pipeline blending equation.\n" "\n" " :param mode: The type of blend mode.\n" - " * ``NONE`` No blending.\n" - " * ``ALPHA`` The original color channels are interpolated according to the alpha value.\n" - " * ``ALPHA_PREMULT`` The original color channels are interpolated according to the alpha " - "value with the new colors pre-multiplied by this value.\n" - " * ``ADDITIVE`` The original color channels are added by the corresponding ones.\n" - " * ``ADDITIVE_PREMULT`` The original color channels are added by the corresponding ones " + " * ``NONE`` No blending.\n" + " * ``ALPHA`` The original color channels are interpolated according to the alpha " + "value.\n" + " * ``ALPHA_PREMULT`` The original color channels are interpolated according to the " + "alpha value with the new colors pre-multiplied by this value.\n" + " * ``ADDITIVE`` The original color channels are added by the corresponding ones.\n" + " * ``ADDITIVE_PREMULT`` The original color channels are added by the corresponding ones " "that are pre-multiplied by the alpha value.\n" - " * ``MULTIPLY`` The original color channels are multiplied by the corresponding ones.\n" - " * ``SUBTRACT`` The original color channels are subtracted by the corresponding ones.\n" - " * ``INVERT`` The original color channels are replaced by its complementary color.\n" - //" * ``OIT``.\n" - //" * ``BACKGROUND`` .\n" - //" * ``CUSTOM`` .\n" + " * ``MULTIPLY`` The original color channels are multiplied by the corresponding ones.\n" + " * ``SUBTRACT`` The original color channels are subtracted by the corresponding ones.\n" + " * ``INVERT`` The original color channels are replaced by its complementary color.\n" + //" * ``OIT``.\n" + //" * ``BACKGROUND`` .\n" + //" * ``CUSTOM`` .\n" " :type mode: str\n"); static PyObject *pygpu_state_blend_set(PyObject *UNUSED(self), PyObject *value) { diff --git a/source/blender/python/intern/CMakeLists.txt b/source/blender/python/intern/CMakeLists.txt index c7816aed3c1..9ac8d4d9f47 100644 --- a/source/blender/python/intern/CMakeLists.txt +++ b/source/blender/python/intern/CMakeLists.txt @@ -363,4 +363,12 @@ if(WITH_POTRACE) add_definitions(-DWITH_POTRACE) endif() +if(WITH_PUGIXML) + add_definitions(-DWITH_PUGIXML) +endif() + +if(WITH_HARU) + add_definitions(-DWITH_HARU) +endif() + blender_add_lib(bf_python "${SRC}" "${INC}" "${INC_SYS}" "${LIB}") diff --git a/source/blender/python/intern/bpy_app_build_options.c b/source/blender/python/intern/bpy_app_build_options.c index 9f12c9f80f1..676d1b8045f 100644 --- a/source/blender/python/intern/bpy_app_build_options.c +++ b/source/blender/python/intern/bpy_app_build_options.c @@ -65,6 +65,8 @@ static PyStructSequence_Field app_builtopts_info_fields[] = { {"fluid", NULL}, {"xr_openxr", NULL}, {"potrace", NULL}, + {"pugixml", NULL}, + {"haru", NULL}, /* Sentinel (this line prevents `clang-format` wrapping into columns). */ {NULL}, }; @@ -311,6 +313,18 @@ static PyObject *make_builtopts_info(void) SetObjIncref(Py_False); #endif +#ifdef WITH_PUGIXML + SetObjIncref(Py_True); +#else + SetObjIncref(Py_False); +#endif + +#ifdef WITH_HARU + SetObjIncref(Py_True); +#else + SetObjIncref(Py_False); +#endif + #undef SetObjIncref return builtopts_info; diff --git a/source/blender/python/intern/bpy_rna.c b/source/blender/python/intern/bpy_rna.c index 49ac2662a31..b9ab0ce4c29 100644 --- a/source/blender/python/intern/bpy_rna.c +++ b/source/blender/python/intern/bpy_rna.c @@ -2546,7 +2546,7 @@ static int pyrna_prop_collection_subscript_str_lib_pair_ptr(BPy_PropertyRNA *sel if (lib == NULL) { if (err_not_found) { PyErr_Format(PyExc_KeyError, - "%s: lib name '%.240s' " + "%s: lib filepath '%.1024s' " "does not reference a valid library", err_prefix, keylib_str); diff --git a/source/blender/sequencer/CMakeLists.txt b/source/blender/sequencer/CMakeLists.txt index 9d9553ed858..2b402b4750f 100644 --- a/source/blender/sequencer/CMakeLists.txt +++ b/source/blender/sequencer/CMakeLists.txt @@ -72,9 +72,9 @@ set(SRC intern/multiview.h intern/prefetch.c intern/prefetch.h - intern/proxy_job.c intern/proxy.c intern/proxy.h + intern/proxy_job.c intern/render.c intern/render.h intern/sequencer.c diff --git a/source/blender/sequencer/SEQ_iterator.h b/source/blender/sequencer/SEQ_iterator.h index 44908dca85a..669c55e1f4c 100644 --- a/source/blender/sequencer/SEQ_iterator.h +++ b/source/blender/sequencer/SEQ_iterator.h @@ -51,15 +51,6 @@ typedef struct SeqIterator { } \ ((void)0) -#define SEQ_CURRENT_BEGIN(_ed, _seq) \ - { \ - SeqIterator iter_macro; \ - for (SEQ_iterator_begin(_ed, &iter_macro, true); iter_macro.valid; \ - SEQ_iterator_next(&iter_macro)) { \ - _seq = iter_macro.seq; - -#define SEQ_CURRENT_END SEQ_ALL_END - void SEQ_iterator_begin(struct Editing *ed, SeqIterator *iter, const bool use_current_sequences); void SEQ_iterator_next(SeqIterator *iter); void SEQ_iterator_end(SeqIterator *iter); diff --git a/source/blender/sequencer/intern/strip_add.c b/source/blender/sequencer/intern/strip_add.c index 33dd74cb527..55d92c1eb10 100644 --- a/source/blender/sequencer/intern/strip_add.c +++ b/source/blender/sequencer/intern/strip_add.c @@ -324,7 +324,7 @@ Sequence *SEQ_add_image_strip(Main *bmain, Scene *scene, ListBase *seqbase, SeqL /* Set initial scale based on load_data->fit_method. */ char file_path[FILE_MAX]; - BLI_join_dirfile(file_path, sizeof(file_path), load_data->path, load_data->name); + BLI_strncpy(file_path, load_data->path, sizeof(file_path)); BLI_path_abs(file_path, BKE_main_blendfile_path(bmain)); ImBuf *ibuf = IMB_loadiffname(file_path, IB_rect, seq->strip->colorspace_settings.name); if (ibuf != NULL) { diff --git a/source/blender/windowmanager/intern/wm_draw.c b/source/blender/windowmanager/intern/wm_draw.c index e0c4ab8eaf3..0922aaaee53 100644 --- a/source/blender/windowmanager/intern/wm_draw.c +++ b/source/blender/windowmanager/intern/wm_draw.c @@ -218,13 +218,6 @@ static bool wm_draw_region_stereo_set(Main *bmain, return false; } -static void wm_area_mark_invalid_backbuf(ScrArea *area) -{ - if (area->spacetype == SPACE_VIEW3D) { - ((View3D *)area->spacedata.first)->flag |= V3D_INVALID_BACKBUF; - } -} - static void wm_region_test_gizmo_do_draw(bContext *C, ScrArea *area, ARegion *region, @@ -739,7 +732,6 @@ static void wm_draw_window_offscreen(bContext *C, wmWindow *win, bool stereo) } } - wm_area_mark_invalid_backbuf(area); CTX_wm_area_set(C, NULL); GPU_debug_group_end(); diff --git a/source/creator/CMakeLists.txt b/source/creator/CMakeLists.txt index c7b940d0012..90840aa8358 100644 --- a/source/creator/CMakeLists.txt +++ b/source/creator/CMakeLists.txt @@ -326,7 +326,14 @@ elseif(WIN32) elseif(APPLE) if(WITH_PYTHON_MODULE) - set(TARGETDIR_VER ${BLENDER_VERSION}) + if(WITH_INSTALL_PORTABLE) + set(TARGETDIR_VER $<TARGET_FILE_DIR:blender>/../Resources/${BLENDER_VERSION}) + # Keep the `BLENDER_VERSION` folder and bpy.so in the build folder. + set(INSTALL_BPY_TO_SITE_PACKAGES OFF) + else() + set(TARGETDIR_VER "${PYTHON_LIBPATH}/Resources/${BLENDER_VERSION}") + set(INSTALL_BPY_TO_SITE_PACKAGES ON) + endif() else() set(TARGETDIR_VER Blender.app/Contents/Resources/${BLENDER_VERSION}) endif() @@ -686,6 +693,26 @@ elseif(WIN32) DESTINATION "." ) endif() + if(MSVC_ASAN) + # The asan dll's can be found in the same folder as the compiler, this is the easiest way to find these. + string(REPLACE "cl.exe" "clang_rt.asan_dynamic-x86_64.dll" ASAN_DLL ${CMAKE_C_COMPILER}) + string(REPLACE "cl.exe" "clang_rt.asan_dbg_dynamic-x86_64.dll" ASAN_DEBUG_DLL ${CMAKE_C_COMPILER}) + if(NOT EXISTS "${ASAN_DLL}") + message(FATAL_ERROR "Asan is enabled, but the ASAN runtime is not detected, this is an optional component during the MSVC install, please install it") + endif() + install( + FILES ${ASAN_DLL} + DESTINATION "." + CONFIGURATIONS Release;RelWithDebInfo;MinSizeRel + ) + install( + FILES ${ASAN_DEBUG_DLL} + DESTINATION "." + CONFIGURATIONS Debug + ) + unset(ASAN_DLL) + unset(ASAN_DEBUG_DLL) + endif() if(WITH_GMP) install( @@ -1005,6 +1032,20 @@ elseif(APPLE) FILES ${LIBDIR}/openmp/lib/libomp.dylib DESTINATION Blender.app/Contents/Resources/lib ) + if(WITH_PYTHON_MODULE) + # Move the dylib in a Blender version folder to keep the corresponding OpenMP version. + install( + DIRECTORY ${CMAKE_BINARY_DIR}/Resources/lib + DESTINATION ${TARGETDIR_VER} + ) + add_custom_command(TARGET blender POST_BUILD + # The old `LC_LOAD_DYLIB` is the `LC_ID_DYLIB` of the LIBDIR OpenMP dylib. + # Change it to support multiple rpaths. + COMMAND xcrun install_name_tool -change "@executable_path/../Resources/lib/libomp.dylib" "@rpath/libomp.dylib" "$<TARGET_FILE:blender>" + # For installation into site-packages. + COMMAND xcrun install_name_tool -add_rpath "@loader_path/../Resources/${BLENDER_VERSION}/lib" "$<TARGET_FILE:blender>" + ) + endif() endif() if(WITH_LLVM AND NOT LLVM_STATIC) @@ -1036,6 +1077,14 @@ elseif(APPLE) ) unset(_py_inc_suffix) endif() + if(WITH_PYTHON_MODULE) + if(INSTALL_BPY_TO_SITE_PACKAGES) + install( + TARGETS blender + LIBRARY DESTINATION ${PYTHON_LIBPATH}/site-packages + ) + endif() + endif() if(WITH_DRACO) install( diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 8941cc671dd..3d9201bec04 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -47,9 +47,14 @@ unset(_default_test_python_exe) set(TEST_BLENDER_EXE_PARAMS --background -noaudio --factory-startup --debug-memory --debug-exit-on-error --python-exit-code 1) # Python CTests -if(WITH_BLENDER AND WITH_PYTHON) +if(WITH_BLENDER AND WITH_PYTHON AND NOT WITH_PYTHON_MODULE) add_subdirectory(python) endif() +# Blender as python module tests. +if(WITH_PYTHON_MODULE) + add_subdirectory(blender_as_python_module) +endif() + # GTest add_subdirectory(gtests) diff --git a/tests/blender_as_python_module/CMakeLists.txt b/tests/blender_as_python_module/CMakeLists.txt new file mode 100644 index 00000000000..98e081672e9 --- /dev/null +++ b/tests/blender_as_python_module/CMakeLists.txt @@ -0,0 +1,33 @@ +# ***** 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) 2021, Blender Foundation +# All rights reserved. +# +# ***** END GPL LICENSE BLOCK ***** + +function(add_blender_as_python_module_test testname testscript) + if(NOT TEST_PYTHON_EXE) + message(FATAL_ERROR "No Python configured for running tests, set TEST_PYTHON_EXE.") + endif() + + add_test( + NAME ${testname} + COMMAND ${TEST_PYTHON_EXE} ${testscript} ${ARGN} + ) +endfunction() + +add_blender_as_python_module_test(import_bpy ${CMAKE_CURRENT_LIST_DIR}/import_bpy.py) diff --git a/tests/blender_as_python_module/import_bpy.py b/tests/blender_as_python_module/import_bpy.py new file mode 100644 index 00000000000..bdc0277cfec --- /dev/null +++ b/tests/blender_as_python_module/import_bpy.py @@ -0,0 +1,19 @@ +# ***** 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 ***** + +# Just import bpy and see if there are any dynamic loader errors. +import bpy diff --git a/tests/python/CMakeLists.txt b/tests/python/CMakeLists.txt index 969b748e973..92cebb7d274 100644 --- a/tests/python/CMakeLists.txt +++ b/tests/python/CMakeLists.txt @@ -713,6 +713,33 @@ if(WITH_CYCLES OR WITH_OPENGL_RENDER_TESTS) endif() endif() +if(WITH_COMPOSITOR) + set(compositor_tests + color + converter + distort + filter + input + matte + output + vector + + multiple_node_setups + ) + + foreach(comp_test ${compositor_tests}) + add_python_test( + compositor_${comp_test}_test + ${CMAKE_CURRENT_LIST_DIR}/compositor_render_tests.py + -blender "${TEST_BLENDER_EXE}" + -testdir "${TEST_SRC_DIR}/compositor/${comp_test}" + -idiff "${OPENIMAGEIO_IDIFF}" + -outdir "${TEST_OUT_DIR}/compositor" + ) + endforeach() + +endif() + if(WITH_OPENGL_DRAW_TESTS) if(NOT OPENIMAGEIO_IDIFF) MESSAGE(STATUS "Disabling OpenGL draw tests because OIIO idiff does not exist") diff --git a/tests/python/bl_blendfile_library_overrides.py b/tests/python/bl_blendfile_library_overrides.py index ab75a410590..e2c6432b380 100644 --- a/tests/python/bl_blendfile_library_overrides.py +++ b/tests/python/bl_blendfile_library_overrides.py @@ -1,6 +1,6 @@ # Apache License, Version 2.0 -# ./blender.bin --background -noaudio --python tests/python/bl_blendfile_library_overrides.py +# ./blender.bin --background -noaudio --python tests/python/bl_blendfile_library_overrides.py -- --output-dir=/tmp/ import pathlib import bpy import sys @@ -16,6 +16,8 @@ class TestLibraryOverrides(TestHelper, unittest.TestCase): OBJECT_LIBRARY_PARENT = "LibMeshParent" MESH_LIBRARY_CHILD = "LibMeshChild" OBJECT_LIBRARY_CHILD = "LibMeshChild" + MESH_LIBRARY_PERMISSIVE = "LibMeshPermissive" + OBJECT_LIBRARY_PERMISSIVE = "LibMeshPermissive" def __init__(self, args): self.args = args @@ -33,6 +35,14 @@ class TestLibraryOverrides(TestHelper, unittest.TestCase): obj_child = bpy.data.objects.new(TestLibraryOverrides.OBJECT_LIBRARY_CHILD, object_data=mesh_child) obj_child.parent = obj bpy.context.collection.objects.link(obj_child) + + mesh = bpy.data.meshes.new(TestLibraryOverrides.MESH_LIBRARY_PERMISSIVE) + obj = bpy.data.objects.new(TestLibraryOverrides.OBJECT_LIBRARY_PERMISSIVE, object_data=mesh) + bpy.context.collection.objects.link(obj) + obj.override_template_create() + prop = obj.override_library.properties.add(rna_path='scale') + prop.operations.add(operation='NOOP') + bpy.ops.wm.save_as_mainfile(filepath=str(self.output_path), check_existing=False, compress=False) def __ensure_override_library_updated(self): @@ -47,29 +57,109 @@ class TestLibraryOverrides(TestHelper, unittest.TestCase): bpy.ops.wm.link(directory=str(link_dir), filename=TestLibraryOverrides.OBJECT_LIBRARY_PARENT) obj = bpy.data.objects[TestLibraryOverrides.OBJECT_LIBRARY_PARENT] - assert(obj.override_library is None) + self.assertIsNone(obj.override_library) local_id = obj.override_create() - assert(local_id.override_library) - assert(local_id.data.override_library is None) + self.assertIsNotNone(local_id.override_library) + self.assertIsNone(local_id.data.override_library) assert(len(local_id.override_library.properties) == 0) local_id.location.y = 1.0 self.__ensure_override_library_updated() - assert (len(local_id.override_library.properties) == 1) assert(len(local_id.override_library.properties) == 1) override_prop = local_id.override_library.properties[0] assert(override_prop.rna_path == "location"); assert(len(override_prop.operations) == 1) override_operation = override_prop.operations[0] - assert (override_operation.operation == 'REPLACE') + assert(override_operation.operation == 'REPLACE') # Setting location.y overridded all elements in the location array. -1 is a wildcard. assert(override_operation.subitem_local_index == -1) + def test_link_permissive(self): + """ + Linked assets with a permissive template. + + - Checks if the NOOP is properly handled. + - Checks if the correct properties and operations are created/updated. + """ + bpy.ops.wm.read_homefile(use_empty=True, use_factory_startup=True) + bpy.data.orphans_purge() + + link_dir = self.output_path / "Object" + bpy.ops.wm.link(directory=str(link_dir), filename=TestLibraryOverrides.OBJECT_LIBRARY_PERMISSIVE) + + obj = bpy.data.objects[TestLibraryOverrides.OBJECT_LIBRARY_PERMISSIVE] + self.assertIsNotNone(obj.override_library) + local_id = obj.override_create() + self.assertIsNotNone(local_id.override_library) + self.assertIsNone(local_id.data.override_library) + assert(len(local_id.override_library.properties) == 1) + override_prop = local_id.override_library.properties[0] + assert(override_prop.rna_path == "scale"); + assert(len(override_prop.operations) == 1) + override_operation = override_prop.operations[0] + assert(override_operation.operation == 'NOOP') + assert(override_operation.subitem_local_index == -1) + + local_id.location.y = 1.0 + local_id.scale.x = 0.5 + # `scale.x` will apply, but will be reverted when the library overrides + # are updated. This is by design so python scripts can still alter the + # properties locally what is a typical usecase in productions. + assert(local_id.scale.x == 0.5) + assert(local_id.location.y == 1.0) + + self.__ensure_override_library_updated() + assert(local_id.scale.x == 1.0) + assert(local_id.location.y == 1.0) + + assert(len(local_id.override_library.properties) == 2) + override_prop = local_id.override_library.properties[0] + assert(override_prop.rna_path == "scale"); + assert(len(override_prop.operations) == 1) + override_operation = override_prop.operations[0] + assert(override_operation.operation == 'NOOP') + assert(override_operation.subitem_local_index == -1) + + override_prop = local_id.override_library.properties[1] + assert(override_prop.rna_path == "location"); + assert(len(override_prop.operations) == 1) + override_operation = override_prop.operations[0] + assert(override_operation.operation == 'REPLACE') + assert (override_operation.subitem_local_index == -1) + + +class TestLibraryTemplate(TestHelper, unittest.TestCase): + MESH_LIBRARY_PERMISSIVE = "LibMeshPermissive" + OBJECT_LIBRARY_PERMISSIVE = "LibMeshPermissive" + + def __init__(self, args): + pass + + def test_permissive_template(self): + """ + Test setting up a permissive template. + """ + bpy.ops.wm.read_homefile(use_empty=True, use_factory_startup=True) + mesh = bpy.data.meshes.new(TestLibraryTemplate.MESH_LIBRARY_PERMISSIVE) + obj = bpy.data.objects.new(TestLibraryTemplate.OBJECT_LIBRARY_PERMISSIVE, object_data=mesh) + bpy.context.collection.objects.link(obj) + assert(obj.override_library is None) + obj.override_template_create() + assert(obj.override_library is not None) + assert(len(obj.override_library.properties) == 0) + prop = obj.override_library.properties.add(rna_path='scale') + assert(len(obj.override_library.properties) == 1) + assert(len(prop.operations) == 0) + operation = prop.operations.add(operation='NOOP') + assert(len(prop.operations) == 1) + assert(operation.operation == 'NOOP') + TESTS = ( TestLibraryOverrides, + TestLibraryTemplate, ) @@ -95,6 +185,7 @@ def main(): # Don't write thumbnails into the home directory. bpy.context.preferences.filepaths.use_save_preview_images = False + bpy.context.preferences.experimental.use_override_templates = True for Test in TESTS: Test(args).run_all_tests() diff --git a/tests/python/compositor_render_tests.py b/tests/python/compositor_render_tests.py new file mode 100644 index 00000000000..6a026ae88d2 --- /dev/null +++ b/tests/python/compositor_render_tests.py @@ -0,0 +1,64 @@ +#!/usr/bin/env python3 +# Apache License, Version 2.0 + +import argparse +import os +import shlex +import shutil +import subprocess +import sys + + +# When run from inside Blender, render and exit. +try: + import bpy + inside_blender = True +except ImportError: + inside_blender = False + +def get_arguments(filepath, output_filepath): + return [ + "--background", + "-noaudio", + "--factory-startup", + "--enable-autoexec", + "--debug-memory", + "--debug-exit-on-error", + filepath, + "-P", + os.path.realpath(__file__), + "-o", output_filepath, + "-F", "PNG", + "-f", "1"] + + +def create_argparse(): + parser = argparse.ArgumentParser() + parser.add_argument("-blender", nargs="+") + parser.add_argument("-testdir", nargs=1) + parser.add_argument("-outdir", nargs=1) + parser.add_argument("-idiff", nargs=1) + return parser + + +def main(): + parser = create_argparse() + args = parser.parse_args() + + blender = args.blender[0] + test_dir = args.testdir[0] + idiff = args.idiff[0] + output_dir = args.outdir[0] + + from modules import render_report + report = render_report.Report("Compositor", output_dir, idiff) + report.set_pixelated(True) + report.set_reference_dir("compositor_renders") + ok = report.run(test_dir, blender, get_arguments, batch=True) + + sys.exit(not ok) + + +if not inside_blender and __name__ == "__main__": + main() + diff --git a/tests/python/operators.py b/tests/python/operators.py index 461880ec214..309a872ac67 100644 --- a/tests/python/operators.py +++ b/tests/python/operators.py @@ -137,7 +137,6 @@ def main(): MeshTest("CubeEdgeSplit", "testCubeEdgeSplit", "expectedCubeEdgeSplit", [OperatorSpecEditMode("edge_split", {}, "EDGE", {2, 5, 8, 11, 14, 17, 20, 23})]), - ### 25 # edge ring select - Cannot be tested. Need user input. # MeshTest("CubeEdgeRingSelect", "testCubeEdgeRingSelect", "expectedCubeEdgeRingSelect", # [OperatorSpecEditMode("edgering_select", {}, "EDGE", {5, 20, 25, 26})]), @@ -146,6 +145,16 @@ def main(): # MeshTest("EmptyMeshEdgeRingSelect", "testEmptyMeshdgeRingSelect", "expectedEmptyMeshEdgeRingSelect", # [OperatorSpecEditMode("edgering_select", {}, "VERT", {})]), + # edges select sharp + MeshTest("CubeEdgesSelectSharp", "testCubeEdgeSelectSharp", "expectedCubeEdgeSelectSharp", + [OperatorSpecEditMode("edges_select_sharp", {}, "EDGE", {20})]), + MeshTest("SphereEdgesSelectSharp", "testSphereEdgesSelectSharp", "expectedSphereEdgeSelectSharp", + [OperatorSpecEditMode("edges_select_sharp", {"sharpness": 0.25}, "EDGE", {288})]), + MeshTest("HoledSphereEdgesSelectSharp", "testHoledSphereEdgesSelectSharp", "expectedHoledSphereEdgeSelectSharp", + [OperatorSpecEditMode("edges_select_sharp", {"sharpness": 0.18}, "VERT", {})]), + MeshTest("EmptyMeshEdgesSelectSharp", "testEmptyMeshEdgeSelectSharp", "expectedEmptyMeshEdgeSelectSharp", + [OperatorSpecEditMode("edges_select_sharp", {}, "VERT", {})]), + # face make planar MeshTest("MonkeyFaceMakePlanar", "testMonkeyFaceMakePlanar", "expectedMonkeyFaceMakePlanar", @@ -208,6 +217,85 @@ def main(): [OperatorSpecEditMode("inset", {"thickness": 0.4, "use_relative_offset": True}, "FACE", {35, 36, 37, 45, 46, 47, 55, 56, 57})]), + + # loop multi select + MeshTest("MokeyLoopMultiSelect", "testMonkeyLoopMultiSelect", "expectedMonkeyLoopMultiSelect", + [OperatorSpecEditMode("loop_multi_select", {}, "VERT", {355, 359, 73, 301, 302})]), + MeshTest("HoledGridLoopMultiSelect", "testGridLoopMultiSelect", "expectedGridLoopMultiSelect", + [OperatorSpecEditMode("loop_multi_select", {}, "VERT", {257, 169, 202, 207, 274, 278, 63})]), + MeshTest("EmptyMeshLoopMultiSelect", "testEmptyMeshLoopMultiSelect", "expectedEmptyMeshLoopMultiSelect", + [OperatorSpecEditMode("loop_multi_select", {}, "VERT", {})]), + + # select all + MeshTest("CircleSelectAll", "testCircleSelectAll", "expectedCircleSelectAll", + [OperatorSpecEditMode("select_all", {}, "VERT", {1})]), + MeshTest("IsolatedVertsSelectAll", "testIsolatedVertsSelectAll", "expectedIsolatedVertsSelectAll", + [OperatorSpecEditMode("select_all", {}, "VERT", {})]), + MeshTest("EmptyMeshSelectAll", "testEmptyMeshSelectAll", "expectedEmptyMeshSelectAll", + [OperatorSpecEditMode("select_all", {}, "VERT", {})]), + + # select axis - Cannot be tested. Needs active vert selection + # MeshTest("MonkeySelectAxisX", "testMonkeySelectAxisX", "expectedMonkeySelectAxisX", + # [OperatorSpecEditMode("select_axis", {"axis": "X"}, "VERT", {13})]), + # MeshTest("MonkeySelectAxisY", "testMonkeySelectAxisY", "expectedMonkeySelectAxisY", + # [OperatorSpecEditMode("select_axis", {"axis": "Y", "sign": "NEG"}, "FACE", {317})]), + # MeshTest("MonkeySelectAxisXYZ", "testMonkeySelectAxisXYZ", "expectedMonkeySelectAxisXYZ", + # [OperatorSpecEditMode("select_axis", {"axis": "X", "sign": "NEG"}, "FACE", {317}), + # OperatorSpecEditMode("select_axis", {"axis": "Y", "sign": "POS"}, "FACE", {}), + # OperatorSpecEditMode("select_axis", {"axis": "Z", "sign": "NEG"}, "FACE", {})]), + + # select faces by sides + MeshTest("CubeSelectFacesBySide", "testCubeSelectFacesBySide", "expectedCubeSelectFacesBySide", + [OperatorSpecEditMode("select_face_by_sides", {"number": 4}, "FACE", {})]), + MeshTest("CubeSelectFacesBySideGreater", "testCubeSelectFacesBySideGreater", "expectedCubeSelectFacesBySideGreater", + [OperatorSpecEditMode("select_face_by_sides", {"number": 4, "type": "GREATER", "extend": True}, "FACE", {})]), + MeshTest("CubeSelectFacesBySideLess", "testCubeSelectFacesBySideLess", "expectedCubeSelectFacesBySideLess", + [OperatorSpecEditMode("select_face_by_sides", {"number": 4, "type": "GREATER", "extend": True}, "FACE", {})]), + + # select interior faces + MeshTest("CubeSelectInteriorFaces", "testCubeSelectInteriorFaces", "expectedCubeSelectInteriorFaces", + [OperatorSpecEditMode("select_face_by_sides", {"number": 4}, "FACE", {})]), + MeshTest("HoledCubeSelectInteriorFaces", "testHoledCubeSelectInteriorFaces", "expectedHoledCubeSelectInteriorFaces", + [OperatorSpecEditMode("select_face_by_sides", {"number": 4}, "FACE", {})]), + MeshTest("EmptyMeshSelectInteriorFaces", "testEmptyMeshSelectInteriorFaces", "expectedEmptyMeshSelectInteriorFaces", + [OperatorSpecEditMode("select_face_by_sides", {"number": 4}, "FACE", {})]), + + # select less + MeshTest("MonkeySelectLess", "testMonkeySelectLess", "expectedMonkeySelectLess", + [OperatorSpecEditMode("select_less", {}, "VERT", {2, 8, 24, 34, 44, 46, 48, 50, 52, 54, 56, 58, 60, 62, 64, 68, + 69, 70, 71, 74, 75, 78, 80, 81, 82, 83, 90, 91, 93, 95, 97, 99, + 101, 109, 111, 115, 117, 119, 121, 123, 125, 127, 129, 130, 131, + 132, 133, 134, 135, 136, 138, 141, 143, 145, 147, 149, 151, 153, + 155, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, + 175, 176, 177, 178, 181, 182, 184, 185, 186, 187, 188, 189, 190, + 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, + 206, 207, 208, 210, 216, 217, 218, 219, 220, 221, 222, 229, 230, + 231, 233, 235, 237, 239, 241, 243, 245, 247, 249, 251, 253, 255, + 257, 259, 263, 267, 269, 271, 275, 277, 289, 291, 293, 295, 309, + 310, 311, 312, 316, 317, 318, 319, 320, 323, 325, 327, 329, 331, + 341, 347, 349, 350, 351, 354, 356, 359, 361, 363, 365, 367, 369, + 375, 379, 381, 382, 385, 386, 387, 388, 389, 390, 391, 392, 393, + 394, 395, 396, 397, 398, 399, 400, 401, 402, 403, 404, 405, 406, + 407, 408, 409, 410, 411, 412, 413, 414, 415, 416, 417, 418, 419, + 420, 421, 423, 425, 426, 427, 428, 429, 430, 431, 432, 433, 434, + 435, 436, 437, 438, 439, 440, 441, 442, 443, 444, 445, 446, 447, + 448, 449, 450, 451, 452, 454, 455, 456, 457, 458, 459, 460, 461, + 462, 463, 464, 471, 473, 474, 475, 476, 477, 478, 479, 480, 481, + 482, 483, 484, 485, 486, 487, 488, 489, 490, 491, 492, 493, 495, + 496, 497, 498, 499, 502, 505})]), + MeshTest("HoledCubeSelectLess", "testHoledCubeSelectLess", "expectedHoledCubeSelectLess", + [OperatorSpecEditMode("select_face_by_sides", {}, "FACE", {})]), + MeshTest("EmptyMeshSelectLess", "testEmptyMeshSelectLess", "expectedEmptyMeshSelectLess", + [OperatorSpecEditMode("select_face_by_sides", {}, "VERT", {})]), + + # select linked + MeshTest("PlanesSelectLinked", "testPlanesSelectLinked", "expectedPlanesSelectedLinked", + [OperatorSpecEditMode("select_linked", {}, "VERT", {7})]), + MeshTest("CubesSelectLinked", "testCubesSelectLinked", "expectedCubesSelectLinked", + [OperatorSpecEditMode("select_linked", {}, "VERT", {11})]), + MeshTest("EmptyMeshSelectLinked", "testEmptyMeshSelectLinked", "expectedEmptyMeshSelectLinked", + [OperatorSpecEditMode("select_linked", {}, "VERT", {})]), + ] operators_test = RunTest(tests) |