Mesh: Lines index buffer creation improvement #120720
|
@ -279,5 +279,6 @@ StatementMacros:
|
|||
MacroBlockBegin: "^OSL_CLOSURE_STRUCT_BEGIN$"
|
||||
MacroBlockEnd: "^OSL_CLOSURE_STRUCT_END$"
|
||||
|
||||
# Ensure new line at the end of source files.
|
||||
# Ensure single new line at the end of source files.
|
||||
InsertNewlineAtEOF: True
|
||||
KeepEmptyLinesAtEOF: False
|
||||
|
|
|
@ -56,6 +56,7 @@ waveletNoiseTile.bin
|
|||
# External repositories.
|
||||
/scripts/addons/
|
||||
/scripts/addons_contrib/
|
||||
/tests/benchmarks/
|
||||
|
||||
# Ignore old submodules directories.
|
||||
# Eventually need to get rid of those, but for the first time of transition
|
||||
|
|
|
@ -0,0 +1,29 @@
|
|||
[submodule "lib/linux_x64"]
|
||||
update = none
|
||||
path = lib/linux_x64
|
||||
url = https://projects.blender.org/blender/lib-linux_x64.git
|
||||
branch = main
|
||||
[submodule "lib/macos_arm64"]
|
||||
update = none
|
||||
path = lib/macos_arm64
|
||||
url = https://projects.blender.org/blender/lib-macos_arm64.git
|
||||
branch = main
|
||||
[submodule "lib/macos_x64"]
|
||||
update = none
|
||||
path = lib/macos_x64
|
||||
url = https://projects.blender.org/blender/lib-macos_x64.git
|
||||
branch = main
|
||||
[submodule "lib/windows_x64"]
|
||||
update = none
|
||||
path = lib/windows_x64
|
||||
url = https://projects.blender.org/blender/lib-windows_x64.git
|
||||
branch = main
|
||||
[submodule "release/datafiles/assets"]
|
||||
path = release/datafiles/assets
|
||||
url = https://projects.blender.org/blender/blender-assets.git
|
||||
branch = main
|
||||
[submodule "tests/data"]
|
||||
update = none
|
||||
path = tests/data
|
||||
url = https://projects.blender.org/blender/blender-test-data.git
|
||||
branch = main
|
|
@ -259,6 +259,28 @@ else()
|
|||
set(WITH_UNITY_BUILD OFF)
|
||||
endif()
|
||||
|
||||
if(COMMAND target_precompile_headers)
|
||||
# Disabling is needed for `./tools/utils_maintenance/code_clean.py` to function.
|
||||
option(WITH_COMPILER_PRECOMPILED_HEADERS "\
|
||||
Use pre-compiled headers to speed up compilation."
|
||||
ON
|
||||
)
|
||||
mark_as_advanced(WITH_COMPILER_PRECOMPILED_HEADERS)
|
||||
|
||||
if(WITH_CLANG_TIDY AND CMAKE_COMPILER_IS_GNUCC)
|
||||
if(WITH_COMPILER_PRECOMPILED_HEADERS)
|
||||
message(STATUS
|
||||
"Clang-Tidy and GCC precompiled headers are incompatible, disabling precompiled headers"
|
||||
)
|
||||
set(WITH_COMPILER_PRECOMPILED_HEADERS OFF)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(NOT WITH_COMPILER_PRECOMPILED_HEADERS)
|
||||
set(CMAKE_DISABLE_PRECOMPILE_HEADERS ON)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
option(WITH_IK_ITASC "\
|
||||
Enable ITASC IK solver (only disable for development & for incompatible C++ compilers)"
|
||||
ON
|
||||
|
@ -387,6 +409,18 @@ else()
|
|||
set(WITH_SYSTEM_EIGEN3 OFF)
|
||||
endif()
|
||||
|
||||
if((NOT WITH_PYTHON_MODULE) AND (
|
||||
(WIN32 AND (CMAKE_SYSTEM_PROCESSOR STREQUAL "AMD64")) OR
|
||||
((UNIX AND NOT APPLE) AND (CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64"))))
|
||||
option(WITH_CPU_CHECK "\
|
||||
Report when a CPU is not compatible on startup \
|
||||
instead of failing to start with an inscrutable error."
|
||||
ON
|
||||
)
|
||||
mark_as_advanced(WITH_CPU_CHECK)
|
||||
else()
|
||||
set(WITH_CPU_CHECK OFF)
|
||||
endif()
|
||||
|
||||
# Modifiers
|
||||
option(WITH_MOD_FLUID "Enable Mantaflow Fluid Simulation Framework" ON)
|
||||
|
@ -400,7 +434,6 @@ option(WITH_IMAGE_CINEON "Enable CINEON and DPX Image Support" ON)
|
|||
option(WITH_IMAGE_WEBP "Enable WebP Image Support" ON)
|
||||
|
||||
# Audio/Video format support
|
||||
option(WITH_CODEC_AVI "Enable Blenders own AVI file support (raw/jpeg)" ON)
|
||||
option(WITH_CODEC_FFMPEG "Enable FFMPeg Support (http://ffmpeg.org)" ON)
|
||||
option(WITH_CODEC_SNDFILE "Enable libsndfile Support (http://www.mega-nerd.com/libsndfile)" ON)
|
||||
|
||||
|
@ -748,8 +781,10 @@ if(WIN32)
|
|||
option(WITH_TBB_MALLOC_PROXY "Enable the TBB malloc replacement" ON)
|
||||
endif()
|
||||
|
||||
option(WITH_EXPERIMENTAL_FEATURES "Enable experimental features" ON)
|
||||
|
||||
# This should be turned off when Blender enter beta/rc/release
|
||||
if("${BLENDER_VERSION_CYCLE}" STREQUAL "alpha")
|
||||
if("${BLENDER_VERSION_CYCLE}" STREQUAL "alpha" AND WITH_EXPERIMENTAL_FEATURES)
|
||||
set(WITH_EXPERIMENTAL_FEATURES ON)
|
||||
else()
|
||||
set(WITH_EXPERIMENTAL_FEATURES OFF)
|
||||
|
@ -2378,7 +2413,6 @@ if(FIRST_RUN)
|
|||
info_cfg_option(WITH_IMAGE_OPENJPEG)
|
||||
|
||||
info_cfg_text("Audio:")
|
||||
info_cfg_option(WITH_CODEC_AVI)
|
||||
info_cfg_option(WITH_CODEC_FFMPEG)
|
||||
info_cfg_option(WITH_CODEC_SNDFILE)
|
||||
info_cfg_option(WITH_COREAUDIO)
|
||||
|
|
33
GNUmakefile
33
GNUmakefile
|
@ -2,7 +2,7 @@
|
|||
#
|
||||
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
# This Makefile does an out-of-source CMake build in ../build_`OS`_`CPU`
|
||||
# This Makefile does an out-of-source CMake build in ../build_`OS`
|
||||
# eg:
|
||||
# ../build_linux_i386
|
||||
# This is for users who like to configure & build blender with a single command.
|
||||
|
@ -35,7 +35,7 @@ Other Convenience Targets
|
|||
* deps: Build library dependencies (intended only for platform maintainers).
|
||||
|
||||
The existence of locally build dependencies overrides the pre-built dependencies from subversion.
|
||||
These must be manually removed from '../lib/' to go back to using the pre-compiled libraries.
|
||||
These must be manually removed from 'lib/' to go back to using the pre-compiled libraries.
|
||||
|
||||
Project Files
|
||||
Generate project files for development environments.
|
||||
|
@ -165,6 +165,16 @@ OS:=$(shell uname -s)
|
|||
OS_NCASE:=$(shell uname -s | tr '[A-Z]' '[a-z]')
|
||||
CPU:=$(shell uname -m)
|
||||
|
||||
# Use our OS and CPU architecture naming conventions.
|
||||
ifeq ($(CPU),x86_64)
|
||||
CPU:=x64
|
||||
endif
|
||||
ifeq ($(OS_NCASE),darwin)
|
||||
OS_LIBDIR:=macos
|
||||
else
|
||||
OS_LIBDIR:=$(OS_NCASE)
|
||||
endif
|
||||
|
||||
|
||||
# Source and Build DIR's
|
||||
BLENDER_DIR:=$(shell pwd -P)
|
||||
|
@ -186,26 +196,13 @@ ifndef DEPS_BUILD_DIR
|
|||
endif
|
||||
|
||||
ifndef DEPS_INSTALL_DIR
|
||||
DEPS_INSTALL_DIR:=$(shell dirname "$(BLENDER_DIR)")/lib/$(OS_NCASE)
|
||||
|
||||
# Add processor type to directory name, except for darwin x86_64
|
||||
# which by convention does not have it.
|
||||
ifeq ($(OS_NCASE),darwin)
|
||||
ifneq ($(CPU),x86_64)
|
||||
DEPS_INSTALL_DIR:=$(DEPS_INSTALL_DIR)_$(CPU)
|
||||
endif
|
||||
else
|
||||
DEPS_INSTALL_DIR:=$(DEPS_INSTALL_DIR)_$(CPU)
|
||||
endif
|
||||
DEPS_INSTALL_DIR:=$(shell dirname "$(BLENDER_DIR)")/lib/$(OS_LIBDIR)_$(CPU)
|
||||
endif
|
||||
|
||||
# Set the LIBDIR, an empty string when not found.
|
||||
LIBDIR:=$(wildcard ../lib/${OS_NCASE}_${CPU})
|
||||
LIBDIR:=$(wildcard $(BLENDER_DIR)/lib/${OS_LIBDIR}_${CPU})
|
||||
ifeq (, $(LIBDIR))
|
||||
LIBDIR:=$(wildcard ../lib/${OS_NCASE}_${CPU}_glibc_228)
|
||||
endif
|
||||
ifeq (, $(LIBDIR))
|
||||
LIBDIR:=$(wildcard ../lib/${OS_NCASE})
|
||||
LIBDIR:=$(wildcard $(BLENDER_DIR)/lib/${OS_LIBDIR})
|
||||
endif
|
||||
|
||||
# Find the newest Python version bundled in `LIBDIR`.
|
||||
|
|
|
@ -133,10 +133,19 @@ BUILD_MANDATORY_SUBPACKAGES = (
|
|||
DISTRO_ID_ARCH: "base-devel",
|
||||
},
|
||||
),
|
||||
Package(name="Git",
|
||||
Package(name="Git", is_group=True,
|
||||
sub_packages=(
|
||||
Package(name="Git LFS",
|
||||
distro_package_names={DISTRO_ID_DEBIAN: "git-lfs",
|
||||
DISTRO_ID_FEDORA: "git-lfs",
|
||||
DISTRO_ID_SUSE: "git-lfs",
|
||||
DISTRO_ID_ARCH: "git-lfs",
|
||||
},
|
||||
),
|
||||
),
|
||||
distro_package_names={DISTRO_ID_DEBIAN: "git",
|
||||
DISTRO_ID_FEDORA: "git",
|
||||
DISTRO_ID_SUSE: None,
|
||||
DISTRO_ID_SUSE: "git",
|
||||
DISTRO_ID_ARCH: "git",
|
||||
},
|
||||
),
|
||||
|
|
|
@ -12,7 +12,6 @@ set(WITH_ALEMBIC ON CACHE BOOL "" FORCE)
|
|||
set(WITH_AUDASPACE ON CACHE BOOL "" FORCE)
|
||||
set(WITH_BUILDINFO ON CACHE BOOL "" FORCE)
|
||||
set(WITH_BULLET ON CACHE BOOL "" FORCE)
|
||||
set(WITH_CODEC_AVI ON CACHE BOOL "" FORCE)
|
||||
set(WITH_CODEC_FFMPEG ON CACHE BOOL "" FORCE)
|
||||
set(WITH_CODEC_SNDFILE ON CACHE BOOL "" FORCE)
|
||||
set(WITH_COMPOSITOR_CPU ON CACHE BOOL "" FORCE)
|
||||
|
|
|
@ -15,7 +15,6 @@ set(WITH_BLENDER_THUMBNAILER OFF CACHE BOOL "" FORCE)
|
|||
set(WITH_BOOST OFF CACHE BOOL "" FORCE)
|
||||
set(WITH_BUILDINFO OFF CACHE BOOL "" FORCE)
|
||||
set(WITH_BULLET OFF CACHE BOOL "" FORCE)
|
||||
set(WITH_CODEC_AVI OFF CACHE BOOL "" FORCE)
|
||||
set(WITH_CODEC_FFMPEG OFF CACHE BOOL "" FORCE)
|
||||
set(WITH_CODEC_SNDFILE OFF CACHE BOOL "" FORCE)
|
||||
set(WITH_COMPOSITOR_CPU OFF CACHE BOOL "" FORCE)
|
||||
|
|
|
@ -16,7 +16,6 @@ set(WITH_ASSERT_ABORT OFF CACHE BOOL "" FORCE)
|
|||
set(WITH_AUDASPACE ON CACHE BOOL "" FORCE)
|
||||
set(WITH_BUILDINFO ON CACHE BOOL "" FORCE)
|
||||
set(WITH_BULLET ON CACHE BOOL "" FORCE)
|
||||
set(WITH_CODEC_AVI ON CACHE BOOL "" FORCE)
|
||||
set(WITH_CODEC_FFMPEG ON CACHE BOOL "" FORCE)
|
||||
set(WITH_CODEC_SNDFILE ON CACHE BOOL "" FORCE)
|
||||
set(WITH_COMPOSITOR_CPU ON CACHE BOOL "" FORCE)
|
||||
|
|
|
@ -49,18 +49,17 @@ endif()
|
|||
|
||||
if(NOT DEFINED LIBDIR)
|
||||
if("${CMAKE_OSX_ARCHITECTURES}" STREQUAL "x86_64")
|
||||
set(LIBDIR ${CMAKE_SOURCE_DIR}/../lib/darwin)
|
||||
set(LIBDIR ${CMAKE_SOURCE_DIR}/lib/macos_x64)
|
||||
else()
|
||||
set(LIBDIR ${CMAKE_SOURCE_DIR}/../lib/darwin_${CMAKE_OSX_ARCHITECTURES})
|
||||
endif()
|
||||
else()
|
||||
if(FIRST_RUN)
|
||||
message(STATUS "Using pre-compiled LIBDIR: ${LIBDIR}")
|
||||
set(LIBDIR ${CMAKE_SOURCE_DIR}/lib/macos_${CMAKE_OSX_ARCHITECTURES})
|
||||
endif()
|
||||
endif()
|
||||
if(NOT EXISTS "${LIBDIR}/")
|
||||
if(NOT EXISTS "${LIBDIR}/.git")
|
||||
message(FATAL_ERROR "Mac OSX requires pre-compiled libs at: '${LIBDIR}'")
|
||||
endif()
|
||||
if(FIRST_RUN)
|
||||
message(STATUS "Using pre-compiled LIBDIR: ${LIBDIR}")
|
||||
endif()
|
||||
|
||||
# Avoid searching for headers since this would otherwise override our lib
|
||||
# directory as well as PYTHON_ROOT_DIR.
|
||||
|
|
|
@ -16,13 +16,13 @@ else()
|
|||
set(LIBDIR_NATIVE_ABI ${CMAKE_SOURCE_DIR}/../lib/${LIBDIR_NAME})
|
||||
|
||||
# Path to precompiled libraries with known glibc 2.28 ABI.
|
||||
set(LIBDIR_GLIBC228_ABI ${CMAKE_SOURCE_DIR}/../lib/linux_x86_64_glibc_228)
|
||||
set(LIBDIR_GLIBC228_ABI ${CMAKE_SOURCE_DIR}/lib/linux_x64)
|
||||
|
||||
# Choose the best suitable libraries.
|
||||
if(EXISTS ${LIBDIR_NATIVE_ABI})
|
||||
set(LIBDIR ${LIBDIR_NATIVE_ABI})
|
||||
set(WITH_LIBC_MALLOC_HOOK_WORKAROUND TRUE)
|
||||
elseif(EXISTS ${LIBDIR_GLIBC228_ABI})
|
||||
elseif(EXISTS "${LIBDIR_GLIBC228_ABI}/.git")
|
||||
set(LIBDIR ${LIBDIR_GLIBC228_ABI})
|
||||
if(WITH_MEM_JEMALLOC)
|
||||
# jemalloc provides malloc hooks.
|
||||
|
|
|
@ -266,23 +266,23 @@ if(NOT DEFINED LIBDIR)
|
|||
# Setup 64bit and 64bit windows systems
|
||||
if(CMAKE_CL_64)
|
||||
message(STATUS "64 bit compiler detected.")
|
||||
set(LIBDIR_BASE "win64")
|
||||
set(LIBDIR_BASE "windows_x64")
|
||||
else()
|
||||
message(FATAL_ERROR "32 bit compiler detected, blender no longer provides pre-build libraries for 32 bit windows, please set the LIBDIR cmake variable to your own library folder")
|
||||
endif()
|
||||
if(CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 19.30.30423)
|
||||
message(STATUS "Visual Studio 2022 detected.")
|
||||
set(LIBDIR ${CMAKE_SOURCE_DIR}/../lib/${LIBDIR_BASE}_vc15)
|
||||
set(LIBDIR ${CMAKE_SOURCE_DIR}/lib/${LIBDIR_BASE})
|
||||
elseif(MSVC_VERSION GREATER 1919)
|
||||
message(STATUS "Visual Studio 2019 detected.")
|
||||
set(LIBDIR ${CMAKE_SOURCE_DIR}/../lib/${LIBDIR_BASE}_vc15)
|
||||
set(LIBDIR ${CMAKE_SOURCE_DIR}/lib/${LIBDIR_BASE})
|
||||
endif()
|
||||
else()
|
||||
if(FIRST_RUN)
|
||||
message(STATUS "Using pre-compiled LIBDIR: ${LIBDIR}")
|
||||
endif()
|
||||
endif()
|
||||
if(NOT EXISTS "${LIBDIR}/")
|
||||
if(NOT EXISTS "${LIBDIR}/.git")
|
||||
message(FATAL_ERROR "\n\nWindows requires pre-compiled libs at: '${LIBDIR}'. Please run `make update` in the blender source folder to obtain them.")
|
||||
endif()
|
||||
|
||||
|
|
|
@ -163,14 +163,14 @@ function(blender_add_ctests)
|
|||
TEST_PREFIX ${ARGS_SUITE_NAME}
|
||||
WORKING_DIRECTORY "${TEST_INSTALL_DIR}"
|
||||
EXTRA_ARGS
|
||||
--test-assets-dir "${CMAKE_SOURCE_DIR}/../lib/tests"
|
||||
--test-assets-dir "${CMAKE_SOURCE_DIR}/tests/data"
|
||||
--test-release-dir "${_test_release_dir}"
|
||||
)
|
||||
else()
|
||||
add_test(
|
||||
NAME ${ARGS_SUITE_NAME}
|
||||
COMMAND ${ARGS_TARGET}
|
||||
--test-assets-dir "${CMAKE_SOURCE_DIR}/../lib/tests"
|
||||
--test-assets-dir "${CMAKE_SOURCE_DIR}/tests/data"
|
||||
--test-release-dir "${_test_release_dir}"
|
||||
WORKING_DIRECTORY ${TEST_INSTALL_DIR}
|
||||
)
|
||||
|
|
|
@ -13,6 +13,7 @@ import sys
|
|||
|
||||
import make_utils
|
||||
from make_utils import call
|
||||
from pathlib import Path
|
||||
|
||||
# Parse arguments.
|
||||
|
||||
|
@ -21,7 +22,6 @@ def parse_arguments() -> argparse.Namespace:
|
|||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument("--ctest-command", default="ctest")
|
||||
parser.add_argument("--cmake-command", default="cmake")
|
||||
parser.add_argument("--svn-command", default="svn")
|
||||
parser.add_argument("--git-command", default="git")
|
||||
parser.add_argument("--config", default="")
|
||||
parser.add_argument("build_directory")
|
||||
|
@ -30,7 +30,6 @@ def parse_arguments() -> argparse.Namespace:
|
|||
|
||||
args = parse_arguments()
|
||||
git_command = args.git_command
|
||||
svn_command = args.svn_command
|
||||
ctest_command = args.ctest_command
|
||||
cmake_command = args.cmake_command
|
||||
config = args.config
|
||||
|
@ -45,24 +44,18 @@ if make_utils.command_missing(git_command):
|
|||
sys.exit(1)
|
||||
|
||||
# Test if we are building a specific release version.
|
||||
branch = make_utils.git_branch(git_command)
|
||||
tag = make_utils.git_tag(git_command)
|
||||
release_version = make_utils.git_branch_release_version(branch, tag)
|
||||
lib_tests_dirpath = os.path.join('..', 'lib', "tests")
|
||||
lib_tests_dirpath = Path("tests") / "data"
|
||||
|
||||
if not os.path.exists(lib_tests_dirpath):
|
||||
if not (lib_tests_dirpath / ".git").exists():
|
||||
print("Tests files not found, downloading...")
|
||||
|
||||
if make_utils.command_missing(svn_command):
|
||||
sys.stderr.write("svn not found, can't checkout test files\n")
|
||||
sys.exit(1)
|
||||
|
||||
if make_utils.command_missing(cmake_command):
|
||||
sys.stderr.write("cmake not found, can't checkout test files\n")
|
||||
sys.exit(1)
|
||||
|
||||
svn_url = make_utils.svn_libraries_base_url(release_version) + "/tests"
|
||||
call([svn_command, "checkout", svn_url, lib_tests_dirpath])
|
||||
# Ensure the test data files sub-module is configured and present.
|
||||
make_utils.git_enable_submodule(git_command, "tests/data")
|
||||
make_utils.git_update_submodule(args.git_command, lib_tests_dirpath)
|
||||
|
||||
# Run cmake again to detect tests files.
|
||||
os.chdir(build_dir)
|
||||
|
|
|
@ -4,11 +4,11 @@
|
|||
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
"""
|
||||
"make update" for all platforms, updating svn libraries and tests and Blender
|
||||
git repository and sub-modules.
|
||||
"make update" for all platforms, updating Git LFS submodules for libraries and
|
||||
tests, and Blender git repository.
|
||||
|
||||
For release branches, this will check out the appropriate branches of
|
||||
sub-modules and libraries.
|
||||
submodules and libraries.
|
||||
"""
|
||||
|
||||
import argparse
|
||||
|
@ -20,168 +20,176 @@ import sys
|
|||
import make_utils
|
||||
from pathlib import Path
|
||||
from make_utils import call, check_output
|
||||
from urllib.parse import urljoin
|
||||
from urllib.parse import urljoin, urlsplit
|
||||
|
||||
from typing import (
|
||||
Optional,
|
||||
)
|
||||
|
||||
|
||||
class Submodule:
|
||||
path: str
|
||||
branch: str
|
||||
branch_fallback: str
|
||||
|
||||
def __init__(self, path: str, branch: str, branch_fallback: str) -> None:
|
||||
self.path = path
|
||||
self.branch = branch
|
||||
self.branch_fallback = branch_fallback
|
||||
from typing import Optional
|
||||
|
||||
|
||||
def print_stage(text: str) -> None:
|
||||
print("")
|
||||
print(text)
|
||||
print("=" * len(text))
|
||||
print("")
|
||||
|
||||
# Parse arguments
|
||||
|
||||
|
||||
def parse_arguments() -> argparse.Namespace:
|
||||
"""
|
||||
Parse command line line arguments.
|
||||
|
||||
Returns parsed object from which the command line arguments can be accessed
|
||||
as properties. The name of the properties matches the command line argument,
|
||||
but with the leading dashed omitted and all remaining dashes replaced with
|
||||
underscore.
|
||||
"""
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument("--no-libraries", action="store_true")
|
||||
parser.add_argument("--no-blender", action="store_true")
|
||||
parser.add_argument("--no-submodules", action="store_true")
|
||||
parser.add_argument("--use-tests", action="store_true")
|
||||
parser.add_argument("--svn-command", default="svn")
|
||||
parser.add_argument("--svn-branch", default=None)
|
||||
parser.add_argument("--git-command", default="git")
|
||||
parser.add_argument("--use-linux-libraries", action="store_true")
|
||||
parser.add_argument("--architecture", type=str, choices=("x86_64", "amd64", "arm64",))
|
||||
parser.add_argument("--architecture", type=str,
|
||||
choices=("x86_64", "amd64", "arm64",))
|
||||
return parser.parse_args()
|
||||
|
||||
|
||||
def get_blender_git_root() -> str:
|
||||
return check_output([args.git_command, "rev-parse", "--show-toplevel"])
|
||||
def get_blender_git_root() -> Path:
|
||||
"""
|
||||
Get root directory of the current Git directory.
|
||||
"""
|
||||
return Path(
|
||||
check_output([args.git_command, "rev-parse", "--show-toplevel"]))
|
||||
|
||||
# Setup for precompiled libraries and tests from svn.
|
||||
|
||||
def get_effective_platform(args: argparse.Namespace) -> str:
|
||||
"""
|
||||
Get platform of the host.
|
||||
|
||||
The result string is normalized to the name used by Blender releases and
|
||||
library repository name prefixes: linux, macos, windows.
|
||||
"""
|
||||
|
||||
if sys.platform == "darwin":
|
||||
platform = "macos"
|
||||
elif sys.platform == "win32":
|
||||
platform = "windows"
|
||||
else:
|
||||
platform = sys.platform
|
||||
|
||||
assert (platform in ("linux", "macos", "windows"))
|
||||
|
||||
return platform
|
||||
|
||||
|
||||
def get_effective_architecture(args: argparse.Namespace) -> str:
|
||||
"""
|
||||
Get architecture of the host.
|
||||
|
||||
The result string is normalized to the architecture name used by the Blender
|
||||
releases and library repository name suffixes: x64, arm64.
|
||||
|
||||
NOTE: When cross-compiling the architecture is coming from the command line
|
||||
argument.
|
||||
"""
|
||||
architecture = args.architecture
|
||||
if architecture:
|
||||
assert isinstance(architecture, str)
|
||||
return architecture
|
||||
|
||||
# Check platform.version to detect arm64 with x86_64 python binary.
|
||||
if "ARM64" in platform.version():
|
||||
return "arm64"
|
||||
|
||||
return platform.machine().lower()
|
||||
|
||||
|
||||
def svn_update(args: argparse.Namespace, release_version: Optional[str]) -> None:
|
||||
svn_non_interactive = [args.svn_command, '--non-interactive']
|
||||
|
||||
lib_dirpath = os.path.join(get_blender_git_root(), '..', 'lib')
|
||||
svn_url = make_utils.svn_libraries_base_url(release_version, args.svn_branch)
|
||||
|
||||
# Checkout precompiled libraries
|
||||
architecture = get_effective_architecture(args)
|
||||
if sys.platform == 'darwin':
|
||||
if architecture == 'arm64':
|
||||
lib_platform = "darwin_arm64"
|
||||
elif architecture == 'x86_64':
|
||||
lib_platform = "darwin"
|
||||
else:
|
||||
lib_platform = None
|
||||
elif sys.platform == 'win32':
|
||||
# Windows checkout is usually handled by bat scripts since python3 to run
|
||||
# this script is bundled as part of the precompiled libraries. However it
|
||||
# is used by the buildbot.
|
||||
lib_platform = "win64_vc15"
|
||||
elif args.use_linux_libraries:
|
||||
lib_platform = "linux_x86_64_glibc_228"
|
||||
elif "ARM64" in platform.version():
|
||||
# Check platform.version to detect arm64 with x86_64 python binary.
|
||||
architecture = "arm64"
|
||||
else:
|
||||
# No precompiled libraries for Linux.
|
||||
lib_platform = None
|
||||
architecture = platform.machine().lower()
|
||||
|
||||
if lib_platform:
|
||||
lib_platform_dirpath = os.path.join(lib_dirpath, lib_platform)
|
||||
# Normalize the architecture name.
|
||||
if architecture in ("x86_64", "amd64"):
|
||||
architecture = "x64"
|
||||
|
||||
if not os.path.exists(lib_platform_dirpath):
|
||||
print_stage("Checking out Precompiled Libraries")
|
||||
assert (architecture in ("x64", "arm64"))
|
||||
|
||||
if make_utils.command_missing(args.svn_command):
|
||||
sys.stderr.write("svn not found, can't checkout libraries\n")
|
||||
sys.exit(1)
|
||||
|
||||
svn_url_platform = svn_url + lib_platform
|
||||
call(svn_non_interactive + ["checkout", svn_url_platform, lib_platform_dirpath])
|
||||
|
||||
if args.use_tests:
|
||||
lib_tests = "tests"
|
||||
lib_tests_dirpath = os.path.join(lib_dirpath, lib_tests)
|
||||
|
||||
if not os.path.exists(lib_tests_dirpath):
|
||||
print_stage("Checking out Tests")
|
||||
|
||||
if make_utils.command_missing(args.svn_command):
|
||||
sys.stderr.write("svn not found, can't checkout tests\n")
|
||||
sys.exit(1)
|
||||
|
||||
svn_url_tests = svn_url + lib_tests
|
||||
call(svn_non_interactive + ["checkout", svn_url_tests, lib_tests_dirpath])
|
||||
|
||||
lib_assets = "assets"
|
||||
lib_assets_dirpath = os.path.join(lib_dirpath, lib_assets)
|
||||
|
||||
if not os.path.exists(lib_assets_dirpath):
|
||||
print_stage("Checking out Assets")
|
||||
|
||||
if make_utils.command_missing(args.svn_command):
|
||||
sys.stderr.write("svn not found, can't checkout assets\n")
|
||||
sys.exit(1)
|
||||
|
||||
svn_url_assets = svn_url + lib_assets
|
||||
call(svn_non_interactive + ["checkout", svn_url_assets, lib_assets_dirpath])
|
||||
|
||||
# Update precompiled libraries, assets and tests
|
||||
|
||||
if not os.path.isdir(lib_dirpath):
|
||||
print("Library path: %r, not found, skipping" % lib_dirpath)
|
||||
else:
|
||||
paths_local_and_remote = []
|
||||
if os.path.exists(os.path.join(lib_dirpath, ".svn")):
|
||||
print_stage("Updating Precompiled Libraries, Assets and Tests (one repository)")
|
||||
paths_local_and_remote.append((lib_dirpath, svn_url))
|
||||
else:
|
||||
print_stage("Updating Precompiled Libraries, Assets and Tests (multiple repositories)")
|
||||
# Separate paths checked out.
|
||||
for dirname in os.listdir(lib_dirpath):
|
||||
if dirname.startswith("."):
|
||||
# Temporary paths such as ".mypy_cache" will report a warning, skip hidden directories.
|
||||
continue
|
||||
|
||||
dirpath = os.path.join(lib_dirpath, dirname)
|
||||
if not (os.path.isdir(dirpath) and os.path.exists(os.path.join(dirpath, ".svn"))):
|
||||
continue
|
||||
|
||||
paths_local_and_remote.append((dirpath, svn_url + dirname))
|
||||
|
||||
if paths_local_and_remote:
|
||||
if make_utils.command_missing(args.svn_command):
|
||||
sys.stderr.write("svn not found, can't update libraries\n")
|
||||
sys.exit(1)
|
||||
|
||||
for dirpath, svn_url_full in paths_local_and_remote:
|
||||
call(svn_non_interactive + ["cleanup", dirpath])
|
||||
# Switch to appropriate branch and update.
|
||||
call(svn_non_interactive + ["switch", svn_url_full, dirpath], exit_on_error=False)
|
||||
call(svn_non_interactive + ["update", dirpath])
|
||||
return architecture
|
||||
|
||||
|
||||
def get_submodule_directories(args: argparse.Namespace):
|
||||
"""
|
||||
Get list of all configured submodule directories.
|
||||
"""
|
||||
|
||||
blender_git_root = get_blender_git_root()
|
||||
dot_modules = blender_git_root / ".gitmodules"
|
||||
|
||||
if not dot_modules.exists():
|
||||
return ()
|
||||
|
||||
submodule_directories_output = check_output(
|
||||
[args.git_command, "config", "--file", dot_modules, "--get-regexp", "path"])
|
||||
return (Path(line.split(' ', 1)[1]) for line in submodule_directories_output.strip().splitlines())
|
||||
|
||||
|
||||
def ensure_git_lfs(args: argparse.Namespace) -> None:
|
||||
# Use `--skip-repo` to avoid creating git hooks.
|
||||
# This is called from the `blender.git` checkout, so we don't need to install hooks there.
|
||||
call((args.git_command, "lfs", "install", "--skip-repo"), exit_on_error=True)
|
||||
|
||||
|
||||
def update_precompiled_libraries(args: argparse.Namespace) -> str:
|
||||
"""
|
||||
Configure and update submodule for precompiled libraries
|
||||
|
||||
This function detects the current host architecture and enables
|
||||
corresponding submodule, and updates the submodule.
|
||||
|
||||
NOTE: When cross-compiling the architecture is coming from the command line
|
||||
argument.
|
||||
"""
|
||||
|
||||
print_stage("Configuring Precompiled Libraries")
|
||||
|
||||
platform = get_effective_platform(args)
|
||||
arch = get_effective_architecture(args)
|
||||
|
||||
print(f"Detected platform : {platform}")
|
||||
print(f"Detected architecture : {arch}")
|
||||
print()
|
||||
|
||||
if sys.platform == "linux" and not args.use_linux_libraries:
|
||||
print("Skipping Linux libraries configuration")
|
||||
return ""
|
||||
|
||||
submodule_dir = f"lib/{platform}_{arch}"
|
||||
|
||||
submodule_directories = get_submodule_directories(args)
|
||||
|
||||
if Path(submodule_dir) not in submodule_directories:
|
||||
return "Skipping libraries update: no configured submodule\n"
|
||||
|
||||
make_utils.git_enable_submodule(args.git_command, submodule_dir)
|
||||
|
||||
if not make_utils.git_update_submodule(args.git_command, submodule_dir):
|
||||
return "Error updating precompiled libraries\n"
|
||||
|
||||
return ""
|
||||
|
||||
|
||||
def update_tests_data_files(args: argparse.Namespace) -> str:
|
||||
"""
|
||||
Configure and update submodule with files used by regression tests
|
||||
"""
|
||||
|
||||
print_stage("Configuring Tests Data Files")
|
||||
|
||||
submodule_dir = "tests/data"
|
||||
|
||||
make_utils.git_enable_submodule(args.git_command, submodule_dir)
|
||||
|
||||
if not make_utils.git_update_submodule(args.git_command, submodule_dir):
|
||||
return "Error updating test data\n"
|
||||
|
||||
return ""
|
||||
|
||||
|
||||
# Test if git repo can be updated.
|
||||
def git_update_skip(args: argparse.Namespace, check_remote_exists: bool = True) -> str:
|
||||
"""Test if git repo can be updated."""
|
||||
|
||||
if make_utils.command_missing(args.git_command):
|
||||
sys.stderr.write("git not found, can't update code\n")
|
||||
sys.exit(1)
|
||||
|
@ -274,23 +282,22 @@ def resolve_external_url(blender_url: str, repo_name: str) -> str:
|
|||
return urljoin(blender_url + "/", "../" + repo_name)
|
||||
|
||||
|
||||
def external_script_copy_old_submodule_over(args: argparse.Namespace, directory_name: str) -> None:
|
||||
blender_git_root = Path(get_blender_git_root())
|
||||
scripts_dir = blender_git_root / "scripts"
|
||||
external_dir = scripts_dir / directory_name
|
||||
def external_script_copy_old_submodule_over(
|
||||
args: argparse.Namespace,
|
||||
directory: Path,
|
||||
old_submodules_dir: Path) -> None:
|
||||
blender_git_root = get_blender_git_root()
|
||||
external_dir = blender_git_root / directory
|
||||
|
||||
old_submodule_relative_dir = Path("release") / "scripts" / directory_name
|
||||
print(f"Moving {old_submodule_relative_dir} to scripts/{directory_name} ...")
|
||||
|
||||
old_submodule_dir = blender_git_root / old_submodule_relative_dir
|
||||
shutil.move(old_submodule_dir, external_dir)
|
||||
print(f"Moving {old_submodules_dir} to {directory} ...")
|
||||
shutil.move(blender_git_root / old_submodules_dir, external_dir)
|
||||
|
||||
# Remove old ".git" which is a file with path to a submodule bare repo inside of main
|
||||
# repo .git/modules directory.
|
||||
(external_dir / ".git").unlink()
|
||||
|
||||
bare_repo_relative_dir = Path(".git") / "modules" / "release" / "scripts" / directory_name
|
||||
print(f"Copying {bare_repo_relative_dir} to scripts/{directory_name}/.git ...")
|
||||
bare_repo_relative_dir = Path(".git") / "modules" / old_submodules_dir
|
||||
print(f"Copying {bare_repo_relative_dir} to {directory}/.git ...")
|
||||
bare_repo_dir = blender_git_root / bare_repo_relative_dir
|
||||
shutil.copytree(bare_repo_dir, external_dir / ".git")
|
||||
|
||||
|
@ -298,25 +305,26 @@ def external_script_copy_old_submodule_over(args: argparse.Namespace, directory_
|
|||
call((args.git_command, "config", "--file", str(git_config), "--unset", "core.worktree"))
|
||||
|
||||
|
||||
def external_script_initialize_if_needed(args: argparse.Namespace,
|
||||
repo_name: str,
|
||||
directory_name: str) -> None:
|
||||
"""Initialize checkout of an external repository scripts directory"""
|
||||
def floating_checkout_initialize_if_needed(args: argparse.Namespace,
|
||||
repo_name: str,
|
||||
directory: Path,
|
||||
old_submodules_dir: Path = None) -> None:
|
||||
"""Initialize checkout of an external repository"""
|
||||
|
||||
blender_git_root = Path(get_blender_git_root())
|
||||
blender_git_root = get_blender_git_root()
|
||||
blender_dot_git = blender_git_root / ".git"
|
||||
scripts_dir = blender_git_root / "scripts"
|
||||
external_dir = scripts_dir / directory_name
|
||||
external_dir = blender_git_root / directory
|
||||
|
||||
if external_dir.exists():
|
||||
return
|
||||
|
||||
print(f"Initializing scripts/{directory_name} ...")
|
||||
print(f"Initializing {directory} ...")
|
||||
|
||||
old_submodule_dot_git = blender_git_root / "release" / "scripts" / directory_name / ".git"
|
||||
if old_submodule_dot_git.exists() and blender_dot_git.is_dir():
|
||||
external_script_copy_old_submodule_over(args, directory_name)
|
||||
return
|
||||
if old_submodules_dir is not None:
|
||||
old_submodule_dot_git = blender_git_root / old_submodules_dir / ".git"
|
||||
if old_submodule_dot_git.exists() and blender_dot_git.is_dir():
|
||||
external_script_copy_old_submodule_over(args, directory, old_submodules_dir)
|
||||
return
|
||||
|
||||
origin_name = "upstream" if use_upstream_workflow(args) else "origin"
|
||||
blender_url = make_utils.git_get_remote_url(args.git_command, origin_name)
|
||||
|
@ -330,9 +338,9 @@ def external_script_initialize_if_needed(args: argparse.Namespace,
|
|||
call((args.git_command, "clone", "--origin", origin_name, external_url, str(external_dir)))
|
||||
|
||||
|
||||
def external_script_add_origin_if_needed(args: argparse.Namespace,
|
||||
repo_name: str,
|
||||
directory_name: str) -> None:
|
||||
def floating_checkout_add_origin_if_needed(args: argparse.Namespace,
|
||||
repo_name: str,
|
||||
directory: Path) -> None:
|
||||
"""
|
||||
Add remote called 'origin' if there is a fork of the external repository available
|
||||
|
||||
|
@ -344,9 +352,8 @@ def external_script_add_origin_if_needed(args: argparse.Namespace,
|
|||
|
||||
cwd = os.getcwd()
|
||||
|
||||
blender_git_root = Path(get_blender_git_root())
|
||||
scripts_dir = blender_git_root / "scripts"
|
||||
external_dir = scripts_dir / directory_name
|
||||
blender_git_root = get_blender_git_root()
|
||||
external_dir = blender_git_root / directory
|
||||
|
||||
origin_blender_url = make_utils.git_get_remote_url(args.git_command, "origin")
|
||||
origin_external_url = resolve_external_url(origin_blender_url, repo_name)
|
||||
|
@ -361,7 +368,7 @@ def external_script_add_origin_if_needed(args: argparse.Namespace,
|
|||
if not make_utils.git_is_remote_repository(args.git_command, origin_external_url):
|
||||
return
|
||||
|
||||
print(f"Adding origin remote to {directory_name} pointing to fork ...")
|
||||
print(f"Adding origin remote to {directory} pointing to fork ...")
|
||||
|
||||
# Non-obvious tricks to introduce the new remote called "origin" to the existing
|
||||
# submodule configuration.
|
||||
|
@ -390,23 +397,30 @@ def external_script_add_origin_if_needed(args: argparse.Namespace,
|
|||
return
|
||||
|
||||
|
||||
def external_scripts_update(args: argparse.Namespace,
|
||||
repo_name: str,
|
||||
directory_name: str,
|
||||
branch: Optional[str]) -> str:
|
||||
def floating_checkout_update(args: argparse.Namespace,
|
||||
repo_name: str,
|
||||
directory: Path,
|
||||
branch: Optional[str],
|
||||
old_submodules_dir: Path = None,
|
||||
only_update=False) -> str:
|
||||
"""Update a single external checkout with the given name in the scripts folder"""
|
||||
|
||||
external_script_initialize_if_needed(args, repo_name, directory_name)
|
||||
external_script_add_origin_if_needed(args, repo_name, directory_name)
|
||||
blender_git_root = get_blender_git_root()
|
||||
external_dir = blender_git_root / directory
|
||||
|
||||
print(f"Updating scripts/{directory_name} ...")
|
||||
if only_update and not external_dir.exists():
|
||||
return ""
|
||||
|
||||
floating_checkout_initialize_if_needed(args, repo_name, directory, old_submodules_dir)
|
||||
floating_checkout_add_origin_if_needed(args, repo_name, directory)
|
||||
|
||||
blender_git_root = get_blender_git_root()
|
||||
external_dir = blender_git_root / directory
|
||||
|
||||
print(f"* Updating {directory} ...")
|
||||
|
||||
cwd = os.getcwd()
|
||||
|
||||
blender_git_root = Path(get_blender_git_root())
|
||||
scripts_dir = blender_git_root / "scripts"
|
||||
external_dir = scripts_dir / directory_name
|
||||
|
||||
# Update externals to appropriate given branch, falling back to main if none is given and/or
|
||||
# found in a sub-repository.
|
||||
branch_fallback = "main"
|
||||
|
@ -419,7 +433,7 @@ def external_scripts_update(args: argparse.Namespace,
|
|||
os.chdir(external_dir)
|
||||
msg = git_update_skip(args, check_remote_exists=False)
|
||||
if msg:
|
||||
skip_msg += directory_name + " skipped: " + msg + "\n"
|
||||
skip_msg += str(directory) + " skipped: " + msg + "\n"
|
||||
else:
|
||||
# Find a matching branch that exists.
|
||||
for remote in ("origin", "upstream"):
|
||||
|
@ -465,6 +479,17 @@ def external_scripts_update(args: argparse.Namespace,
|
|||
return skip_msg
|
||||
|
||||
|
||||
def external_scripts_update(args: argparse.Namespace,
|
||||
repo_name: str,
|
||||
directory_name: str,
|
||||
branch: Optional[str]) -> str:
|
||||
return floating_checkout_update(args,
|
||||
repo_name,
|
||||
Path("scripts") / directory_name,
|
||||
branch,
|
||||
old_submodules_dir=Path("release") / "scripts" / directory_name)
|
||||
|
||||
|
||||
def scripts_submodules_update(args: argparse.Namespace, branch: Optional[str]) -> str:
|
||||
"""Update working trees of addons and addons_contrib within the scripts/ directory"""
|
||||
msg = ""
|
||||
|
@ -475,18 +500,91 @@ def scripts_submodules_update(args: argparse.Namespace, branch: Optional[str]) -
|
|||
return msg
|
||||
|
||||
|
||||
def floating_libraries_update(args: argparse.Namespace, branch: Optional[str]) -> str:
|
||||
"""Update libraries checkouts which are floating (not attached as Git submodules)"""
|
||||
msg = ""
|
||||
|
||||
msg += floating_checkout_update(args,
|
||||
"benchmarks",
|
||||
Path("tests") / "benchmarks",
|
||||
branch,
|
||||
only_update=True)
|
||||
|
||||
return msg
|
||||
|
||||
|
||||
def add_submodule_push_url(args: argparse.Namespace):
|
||||
"""
|
||||
Add pushURL configuration for all locally activated submodules, pointing to SSH protocol.
|
||||
"""
|
||||
|
||||
blender_git_root = get_blender_git_root()
|
||||
modules = blender_git_root / ".git" / "modules"
|
||||
|
||||
submodule_directories = get_submodule_directories(args)
|
||||
|
||||
for submodule_path in submodule_directories:
|
||||
module_path = modules / submodule_path
|
||||
config = module_path / "config"
|
||||
|
||||
if not config.exists():
|
||||
# Ignore modules which are not initialized
|
||||
continue
|
||||
|
||||
push_url = check_output((args.git_command, "config", "--file", str(config),
|
||||
"--get", "remote.origin.pushURL"), exit_on_error=False)
|
||||
if push_url and push_url != "git@projects.blender.org:blender/lib-darwin_arm64.git":
|
||||
# Ignore modules which have pushURL configured.
|
||||
# Keep special exception, as some debug code sneaked into the production for a short
|
||||
# while.
|
||||
continue
|
||||
|
||||
url = make_utils.git_get_config(args.git_command, "remote.origin.url", str(config))
|
||||
if not url.startswith("https:"):
|
||||
# Ignore non-URL URLs.
|
||||
continue
|
||||
|
||||
url_parts = urlsplit(url)
|
||||
push_url = f"git@{url_parts.netloc}:{url_parts.path[1:]}"
|
||||
|
||||
print(f"Setting pushURL to {push_url} for {submodule_path}")
|
||||
make_utils.git_set_config(args.git_command, "remote.origin.pushURL", push_url, str(config))
|
||||
|
||||
|
||||
def submodules_update(args: argparse.Namespace, branch: Optional[str]) -> str:
|
||||
"""Update submodules or other externally tracked source trees"""
|
||||
print_stage("Updating Submodules")
|
||||
|
||||
msg = ""
|
||||
|
||||
msg += scripts_submodules_update(args, branch)
|
||||
|
||||
msg += floating_libraries_update(args, branch)
|
||||
|
||||
print("* Updating Git submodules")
|
||||
|
||||
submodule_directories = get_submodule_directories(args)
|
||||
for submodule_path in submodule_directories:
|
||||
if submodule_path.parts[0] == "lib" and args.no_libraries:
|
||||
print(f"Skipping library submodule {submodule_path}")
|
||||
continue
|
||||
|
||||
if submodule_path.parts[0] == "tests" and not args.use_tests:
|
||||
print(f"Skipping tests submodule {submodule_path}")
|
||||
continue
|
||||
|
||||
if not make_utils.git_update_submodule(args.git_command, submodule_path):
|
||||
msg += f"Error updating Git submodule {submodule_path}\n"
|
||||
|
||||
add_submodule_push_url(args)
|
||||
|
||||
return msg
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
args = parse_arguments()
|
||||
blender_skip_msg = ""
|
||||
libraries_skip_msg = ""
|
||||
submodules_skip_msg = ""
|
||||
|
||||
blender_version = make_utils. parse_blender_version()
|
||||
|
@ -494,26 +592,32 @@ if __name__ == "__main__":
|
|||
major = blender_version.version // 100
|
||||
minor = blender_version.version % 100
|
||||
branch = f"blender-v{major}.{minor}-release"
|
||||
release_version: Optional[str] = f"{major}.{minor}"
|
||||
else:
|
||||
branch = 'main'
|
||||
release_version = None
|
||||
|
||||
if not args.no_libraries:
|
||||
svn_update(args, release_version)
|
||||
# Submodules and precompiled libraries require Git LFS.
|
||||
ensure_git_lfs(args)
|
||||
|
||||
if not args.no_blender:
|
||||
blender_skip_msg = git_update_skip(args)
|
||||
if not blender_skip_msg:
|
||||
blender_skip_msg = blender_update(args)
|
||||
if blender_skip_msg:
|
||||
blender_skip_msg = "Blender repository skipped: " + blender_skip_msg + "\n"
|
||||
|
||||
if not args.no_libraries:
|
||||
libraries_skip_msg += update_precompiled_libraries(args)
|
||||
if args.use_tests:
|
||||
libraries_skip_msg += update_tests_data_files(args)
|
||||
|
||||
if not args.no_submodules:
|
||||
submodules_skip_msg = submodules_update(args, branch)
|
||||
|
||||
# Report any skipped repositories at the end, so it's not as easy to miss.
|
||||
skip_msg = blender_skip_msg + submodules_skip_msg
|
||||
skip_msg = blender_skip_msg + libraries_skip_msg + submodules_skip_msg
|
||||
if skip_msg:
|
||||
print_stage(skip_msg.strip())
|
||||
print_stage("Update finished with the following messages")
|
||||
print(skip_msg.strip())
|
||||
|
||||
# For failed submodule update we throw an error, since not having correct
|
||||
# submodules can make Blender throw errors.
|
||||
|
|
|
@ -8,12 +8,11 @@ Utility functions for make update and make tests.
|
|||
"""
|
||||
|
||||
import re
|
||||
import os
|
||||
import shutil
|
||||
import subprocess
|
||||
import sys
|
||||
import os
|
||||
from pathlib import Path
|
||||
from urllib.parse import urljoin
|
||||
|
||||
from typing import (
|
||||
Sequence,
|
||||
|
@ -21,18 +20,30 @@ from typing import (
|
|||
)
|
||||
|
||||
|
||||
def call(cmd: Sequence[str], exit_on_error: bool = True, silent: bool = False) -> int:
|
||||
def call(cmd: Sequence[str], exit_on_error: bool = True, silent: bool = False, env=None) -> int:
|
||||
if not silent:
|
||||
print(" ".join([str(x) for x in cmd]))
|
||||
cmd_str = ""
|
||||
if env:
|
||||
cmd_str += " ".join([f"{item[0]}={item[1]}" for item in env.items()])
|
||||
cmd_str += " "
|
||||
cmd_str += " ".join([str(x) for x in cmd])
|
||||
print(cmd_str)
|
||||
|
||||
env_full = None
|
||||
if env:
|
||||
env_full = os.environ.copy()
|
||||
for key, value in env.items():
|
||||
env_full[key] = value
|
||||
|
||||
# Flush to ensure correct order output on Windows.
|
||||
sys.stdout.flush()
|
||||
sys.stderr.flush()
|
||||
|
||||
if silent:
|
||||
retcode = subprocess.call(cmd, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
|
||||
retcode = subprocess.call(
|
||||
cmd, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL, env=env_full)
|
||||
else:
|
||||
retcode = subprocess.call(cmd)
|
||||
retcode = subprocess.call(cmd, env=env_full)
|
||||
|
||||
if exit_on_error and retcode != 0:
|
||||
sys.exit(retcode)
|
||||
|
@ -48,7 +59,7 @@ def check_output(cmd: Sequence[str], exit_on_error: bool = True) -> str:
|
|||
output = subprocess.check_output(cmd, stderr=subprocess.STDOUT, universal_newlines=True)
|
||||
except subprocess.CalledProcessError as e:
|
||||
if exit_on_error:
|
||||
sys.stderr.write(" ".join(cmd))
|
||||
sys.stderr.write(" ".join(cmd) + "\n")
|
||||
sys.stderr.write(e.output + "\n")
|
||||
sys.exit(e.returncode)
|
||||
output = ""
|
||||
|
@ -87,25 +98,6 @@ def git_remote_exist(git_command: str, remote_name: str) -> bool:
|
|||
return remote_url != remote_name
|
||||
|
||||
|
||||
def git_get_resolved_submodule_url(git_command: str, blender_url: str, submodule_path: str) -> str:
|
||||
git_root = check_output([git_command, "rev-parse", "--show-toplevel"])
|
||||
dot_gitmodules = os.path.join(git_root, ".gitmodules")
|
||||
|
||||
submodule_key_prefix = f"submodule.{submodule_path}"
|
||||
submodule_key_url = f"{submodule_key_prefix}.url"
|
||||
|
||||
gitmodule_url = git_get_config(
|
||||
git_command, submodule_key_url, file=dot_gitmodules)
|
||||
|
||||
# A bit of a trickery to construct final URL.
|
||||
# Only works for the relative submodule URLs.
|
||||
#
|
||||
# Note that unless the LHS URL ends up with a slash urljoin treats the last component as a
|
||||
# file.
|
||||
assert gitmodule_url.startswith('..')
|
||||
return urljoin(blender_url + "/", gitmodule_url)
|
||||
|
||||
|
||||
def git_is_remote_repository(git_command: str, repo: str) -> bool:
|
||||
"""Returns true if the given repository is a valid/clonable git repo"""
|
||||
exit_code = call((git_command, "ls-remote", repo, "HEAD"), exit_on_error=False, silent=True)
|
||||
|
@ -113,7 +105,8 @@ def git_is_remote_repository(git_command: str, repo: str) -> bool:
|
|||
|
||||
|
||||
def git_branch(git_command: str) -> str:
|
||||
# Get current branch name.
|
||||
"""Get current branch name."""
|
||||
|
||||
try:
|
||||
branch = subprocess.check_output([git_command, "rev-parse", "--abbrev-ref", "HEAD"])
|
||||
except subprocess.CalledProcessError as e:
|
||||
|
@ -137,44 +130,60 @@ def git_set_config(git_command: str, key: str, value: str, file: Optional[str] =
|
|||
return check_output([git_command, "config", key, value])
|
||||
|
||||
|
||||
def git_tag(git_command: str) -> Optional[str]:
|
||||
# Get current tag name.
|
||||
try:
|
||||
tag = subprocess.check_output([git_command, "describe", "--exact-match"], stderr=subprocess.STDOUT)
|
||||
except subprocess.CalledProcessError as e:
|
||||
return None
|
||||
def git_enable_submodule(git_command: str, submodule_dir: str):
|
||||
"""Enable submodule denoted by its directory within the repository"""
|
||||
|
||||
return tag.strip().decode('utf8')
|
||||
command = (git_command,
|
||||
"config",
|
||||
"--local",
|
||||
f"submodule.{submodule_dir}.update", "checkout")
|
||||
call(command, exit_on_error=True, silent=False)
|
||||
|
||||
|
||||
def git_branch_release_version(branch: str, tag: Optional[str]) -> Optional[str]:
|
||||
re_match = re.search("^blender-v(.*)-release$", branch)
|
||||
release_version = None
|
||||
if re_match:
|
||||
release_version = re_match.group(1)
|
||||
elif tag:
|
||||
re_match = re.search(r"^v([0-9]*\.[0-9]*).*", tag)
|
||||
if re_match:
|
||||
release_version = re_match.group(1)
|
||||
return release_version
|
||||
def git_update_submodule(git_command: str, submodule_dir: str) -> bool:
|
||||
"""
|
||||
Update the given submodule.
|
||||
|
||||
The submodule is denoted by its path within the repository.
|
||||
This function will initialize the submodule if it has not been initialized.
|
||||
|
||||
def svn_libraries_base_url(release_version: Optional[str], branch: Optional[str] = None) -> str:
|
||||
if release_version:
|
||||
svn_branch = "tags/blender-" + release_version + "-release"
|
||||
elif branch:
|
||||
svn_branch = "branches/" + branch
|
||||
else:
|
||||
svn_branch = "trunk"
|
||||
return "https://svn.blender.org/svnroot/bf-blender/" + svn_branch + "/lib/"
|
||||
Returns true if the update succeeded
|
||||
"""
|
||||
|
||||
# Use the two stage update process:
|
||||
# - Step 1: checkout the submodule to the desired (by the parent repository) hash, but
|
||||
# skip the LFS smudging.
|
||||
# - Step 2: Fetch LFS files, if needed.
|
||||
#
|
||||
# This allows to show download progress, potentially allowing resuming the download
|
||||
# progress, and even recovering from partial/corrupted checkout of submodules.
|
||||
#
|
||||
# This bypasses the limitation of submodules which are configured as "update=checkout"
|
||||
# with regular `git submodule update` which, depending on the Git version will not report
|
||||
# any progress. This is because submodule--helper.c configures Git checkout process with
|
||||
# the "quiet" flag, so that there is no detached head information printed after submodule
|
||||
# update, and since Git 2.33 the LFS messages "Filtering contents..." is suppressed by
|
||||
#
|
||||
# https://github.com/git/git/commit/7a132c628e57b9bceeb88832ea051395c0637b16
|
||||
#
|
||||
# Doing "git lfs pull" after checkout with GIT_LFS_SKIP_SMUDGE=true seems to be the
|
||||
# valid process. For example, https://www.mankier.com/7/git-lfs-faq
|
||||
|
||||
env = {"GIT_LFS_SKIP_SMUDGE": "1"}
|
||||
|
||||
if call((git_command, "submodule", "update", "--init", "--progress", submodule_dir),
|
||||
exit_on_error=False, env=env) != 0:
|
||||
return False
|
||||
|
||||
return call((git_command, "-C", submodule_dir, "lfs", "pull"),
|
||||
exit_on_error=False) == 0
|
||||
|
||||
|
||||
def command_missing(command: str) -> bool:
|
||||
# Support running with Python 2 for macOS
|
||||
if sys.version_info >= (3, 0):
|
||||
return shutil.which(command) is None
|
||||
else:
|
||||
return False
|
||||
return False
|
||||
|
||||
|
||||
class BlenderVersion:
|
||||
|
|
|
@ -1,49 +1,55 @@
|
|||
if "%BUILD_VS_YEAR%"=="2019" set BUILD_VS_LIBDIRPOST=vc15
|
||||
if "%BUILD_VS_YEAR%"=="2022" set BUILD_VS_LIBDIRPOST=vc15
|
||||
|
||||
set BUILD_VS_SVNDIR=win64_%BUILD_VS_LIBDIRPOST%
|
||||
set BUILD_VS_LIBDIR="%BLENDER_DIR%..\lib\%BUILD_VS_SVNDIR%"
|
||||
set BUILD_VS_LIBDIR=lib/windows_x64
|
||||
|
||||
if NOT "%verbose%" == "" (
|
||||
echo Library Directory = "%BUILD_VS_LIBDIR%"
|
||||
)
|
||||
if NOT EXIST %BUILD_VS_LIBDIR% (
|
||||
rem libs not found, but svn is on the system
|
||||
if not "%SVN%"=="" (
|
||||
if NOT EXIST "%BUILD_VS_LIBDIR%\.git" (
|
||||
rem libs not found, but git is on the system
|
||||
if not "%GIT%"=="" (
|
||||
echo.
|
||||
echo The required external libraries in %BUILD_VS_LIBDIR% are missing
|
||||
echo.
|
||||
set /p GetLibs= "Would you like to download them? (y/n)"
|
||||
if /I "!GetLibs!"=="Y" (
|
||||
echo.
|
||||
echo Downloading %BUILD_VS_SVNDIR% libraries, please wait.
|
||||
echo Downloading %BUILD_VS_LIBDIR% libraries, please wait.
|
||||
echo.
|
||||
:RETRY
|
||||
"%SVN%" checkout https://svn.blender.org/svnroot/bf-blender/trunk/lib/%BUILD_VS_SVNDIR% %BUILD_VS_LIBDIR%
|
||||
echo *********************************************************
|
||||
echo * *
|
||||
echo * Note: Once the initial download finishes and you see *
|
||||
echo * "Resolving deltas: 100%% (nnn/nnn) done" *
|
||||
echo * a second, much larger, update will occur with *
|
||||
echo * no visible updates. Please do not interrupt *
|
||||
echo * this process. It may take over an hour to *
|
||||
echo * complete depending on your internet connection. *
|
||||
echo * *
|
||||
echo *********************************************************
|
||||
:RETRY
|
||||
"%GIT%" -C "%BLENDER_DIR%\" config --local "submodule.%BUILD_VS_LIBDIR%.update" "checkout"
|
||||
"%GIT%" -C "%BLENDER_DIR%\" submodule update --progress --init "%BUILD_VS_LIBDIR%"
|
||||
if errorlevel 1 (
|
||||
set /p LibRetry= "Error during download, retry? y/n"
|
||||
if /I "!LibRetry!"=="Y" (
|
||||
cd %BUILD_VS_LIBDIR%
|
||||
"%SVN%" cleanup
|
||||
cd %BLENDER_DIR%
|
||||
goto RETRY
|
||||
)
|
||||
echo.
|
||||
echo Error: Download of external libraries failed.
|
||||
echo This is needed for building, please manually run 'svn cleanup' and 'svn update' in
|
||||
echo %BUILD_VS_LIBDIR% , until this is resolved you CANNOT make a successful blender build
|
||||
echo Until this is resolved you CANNOT make a successful blender build.
|
||||
echo.
|
||||
exit /b 1
|
||||
)
|
||||
)
|
||||
) else (
|
||||
echo Not downloading libraries, until this is resolved you CANNOT make a successful blender build.
|
||||
exit /b 1
|
||||
)
|
||||
)
|
||||
) else (
|
||||
if NOT EXIST %PYTHON% (
|
||||
if not "%SVN%"=="" (
|
||||
if not "%GIT%"=="" (
|
||||
echo.
|
||||
echo Python not found in external libraries, updating to latest version
|
||||
echo.
|
||||
"%SVN%" update %BUILD_VS_LIBDIR%
|
||||
"%GIT%" -C "%BLENDER_DIR%" submodule update "%BUILD_VS_LIBDIR%"
|
||||
)
|
||||
)
|
||||
)
|
||||
|
@ -53,8 +59,8 @@ if NOT EXIST %BUILD_VS_LIBDIR% (
|
|||
echo Error: Required libraries not found at "%BUILD_VS_LIBDIR%"
|
||||
echo This is needed for building, aborting!
|
||||
echo.
|
||||
if "%SVN%"=="" (
|
||||
echo This is most likely caused by svn.exe not being available.
|
||||
if "%GIT%"=="" (
|
||||
echo This is most likely caused by git.exe not being available.
|
||||
)
|
||||
exit /b 1
|
||||
)
|
|
@ -1,5 +1,4 @@
|
|||
REM find all dependencies and set the corresponding environment variables.
|
||||
for %%X in (svn.exe) do (set SVN=%%~$PATH:X)
|
||||
for %%X in (cmake.exe) do (set CMAKE=%%~$PATH:X)
|
||||
for %%X in (ctest.exe) do (set CTEST=%%~$PATH:X)
|
||||
for %%X in (git.exe) do (set GIT=%%~$PATH:X)
|
||||
|
@ -7,31 +6,32 @@ REM For python, default on 310 but if that does not exist also check
|
|||
REM the 311, 312 and finally 39 folders to see if those are there, it checks
|
||||
REM this far ahead to ensure good lib folder compatibility in the future
|
||||
REM it falls back to 3.9 just incase it is a very old lib folder.
|
||||
set PYTHON=%BLENDER_DIR%\..\lib\win64_vc15\python\310\bin\python.exe
|
||||
set PYTHON=%BLENDER_DIR%\lib\windows_x64\python\310\bin\python.exe
|
||||
if EXIST %PYTHON% (
|
||||
goto detect_python_done
|
||||
)
|
||||
set PYTHON=%BLENDER_DIR%\..\lib\win64_vc15\python\311\bin\python.exe
|
||||
set PYTHON=%BLENDER_DIR%\lib\windows_x64\python\311\bin\python.exe
|
||||
if EXIST %PYTHON% (
|
||||
goto detect_python_done
|
||||
)
|
||||
set PYTHON=%BLENDER_DIR%\..\lib\win64_vc15\python\312\bin\python.exe
|
||||
set PYTHON=%BLENDER_DIR%\lib\windows_x64\python\312\bin\python.exe
|
||||
if EXIST %PYTHON% (
|
||||
goto detect_python_done
|
||||
)
|
||||
set PYTHON=%BLENDER_DIR%\..\lib\win64_vc15\python\39\bin\python.exe
|
||||
set PYTHON=%BLENDER_DIR%\lib\windows_x64\python\39\bin\python.exe
|
||||
if EXIST %PYTHON% (
|
||||
goto detect_python_done
|
||||
)
|
||||
|
||||
if NOT EXIST %PYTHON% (
|
||||
echo Warning: Python not found, there is likely an issue with the library folder
|
||||
if EXIST %BLENDER_DIR%\lib\windows_x64\ (
|
||||
echo Warning: Python not found, there is likely an issue with the library folder
|
||||
)
|
||||
set PYTHON=""
|
||||
)
|
||||
|
||||
:detect_python_done
|
||||
if NOT "%verbose%" == "" (
|
||||
echo svn : "%SVN%"
|
||||
echo cmake : "%CMAKE%"
|
||||
echo ctest : "%CTEST%"
|
||||
echo git : "%GIT%"
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
if EXIST %BLENDER_DIR%\..\lib\win64_vc15\llvm\bin\clang-format.exe (
|
||||
set CF_PATH=..\lib\win64_vc15\llvm\bin
|
||||
if EXIST %BLENDER_DIR%\lib\windows_x64\llvm\bin\clang-format.exe (
|
||||
set CF_PATH=lib\windows_x64\llvm\bin
|
||||
goto detect_done
|
||||
)
|
||||
|
||||
|
|
|
@ -0,0 +1,19 @@
|
|||
set BUILD_VS_LIBDIR=lib/windows_x64
|
||||
|
||||
:RETRY
|
||||
"%GIT%" -C "%BLENDER_DIR%\" config --local "submodule.%BUILD_VS_LIBDIR%.update" "checkout"
|
||||
"%GIT%" -C "%BLENDER_DIR%\" submodule update --progress --init "%BUILD_VS_LIBDIR%"
|
||||
if errorlevel 1 (
|
||||
set /p LibRetry= "Error during update, retry? y/n"
|
||||
if /I "!LibRetry!"=="Y" (
|
||||
goto RETRY
|
||||
)
|
||||
echo.
|
||||
echo Error: Download of external libraries failed.
|
||||
echo Until this is resolved you CANNOT make a successful blender build.
|
||||
echo.
|
||||
exit /b 1
|
||||
)
|
||||
REM re-detect the dependencies after updating the libraries so any python version
|
||||
REM changes are accounted for.
|
||||
call "%~dp0\find_dependencies.cmd"
|
|
@ -110,9 +110,6 @@ if NOT "%1" == "" (
|
|||
) else if "%1" == "doc_py" (
|
||||
set DOC_PY=1
|
||||
goto EOF
|
||||
) else if "%1" == "svnfix" (
|
||||
set SVN_FIX=1
|
||||
goto EOF
|
||||
) else (
|
||||
echo Command "%1" unknown, aborting!
|
||||
goto ERR
|
||||
|
|
|
@ -4,9 +4,7 @@ set BUILD_CMAKE_ARGS=
|
|||
set BUILD_ARCH=
|
||||
set BUILD_VS_VER=
|
||||
set BUILD_VS_YEAR=
|
||||
set BUILD_VS_LIBDIRPOST=
|
||||
set BUILD_VS_LIBDIR=
|
||||
set BUILD_VS_SVNDIR=
|
||||
set KEY_NAME=
|
||||
set MSBUILD_PLATFORM=
|
||||
set MUST_CLEAN=
|
||||
|
|
|
@ -8,13 +8,10 @@ for /f "delims=" %%i in ('"%GIT%" rev-parse HEAD') do echo Branch_hash=%%i
|
|||
cd "%BLENDER_DIR%/scripts/addons"
|
||||
for /f "delims=" %%i in ('"%GIT%" rev-parse --abbrev-ref HEAD') do echo Addons_Branch_name=%%i
|
||||
for /f "delims=" %%i in ('"%GIT%" rev-parse HEAD') do echo Addons_Branch_hash=%%i
|
||||
if "%SVN%" == "" (
|
||||
echo SVN not found, cannot library information.
|
||||
goto EOF
|
||||
)
|
||||
set BUILD_VS_LIBDIR=%BLENDER_DIR%..\lib\win64_vc15
|
||||
for /f "delims=" %%i in ('"%SVN%" info --show-item=url --no-newline %BUILD_VS_LIBDIR% ') do echo Libs_URL=%%i
|
||||
for /f "delims=" %%i in ('"%SVN%" info --show-item=revision --no-newline %BUILD_VS_LIBDIR% ') do echo Libs_Revision=%%i
|
||||
for /f "delims=" %%i in ('"%SVN%" info --show-item=last-changed-date --no-newline %BUILD_VS_LIBDIR% ') do echo Libs_LastChange=%%i
|
||||
|
||||
cd "%BLENDER_DIR%/lib/windows_x64"
|
||||
for /f "delims=" %%i in ('"%GIT%" rev-parse --abbrev-ref HEAD') do echo Libs_Branch_name=%%i
|
||||
for /f "delims=" %%i in ('"%GIT%" rev-parse HEAD') do echo Libs_Branch_hash=%%i
|
||||
|
||||
cd "%BLENDER_DIR%"
|
||||
:EOF
|
|
@ -1,25 +0,0 @@
|
|||
if "%BUILD_VS_YEAR%"=="2019" set BUILD_VS_LIBDIRPOST=vc15
|
||||
if "%BUILD_VS_YEAR%"=="2022" set BUILD_VS_LIBDIRPOST=vc15
|
||||
|
||||
set BUILD_VS_SVNDIR=win64_%BUILD_VS_LIBDIRPOST%
|
||||
set BUILD_VS_LIBDIR="%BLENDER_DIR%..\lib\%BUILD_VS_SVNDIR%"
|
||||
|
||||
echo Starting cleanup in %BUILD_VS_LIBDIR%.
|
||||
cd %BUILD_VS_LIBDIR%
|
||||
:RETRY
|
||||
"%SVN%" cleanup
|
||||
"%SVN%" update
|
||||
if errorlevel 1 (
|
||||
set /p LibRetry= "Error during update, retry? y/n"
|
||||
if /I "!LibRetry!"=="Y" (
|
||||
goto RETRY
|
||||
)
|
||||
echo.
|
||||
echo Error: Download of external libraries failed.
|
||||
echo This is needed for building, please manually run 'svn cleanup' and 'svn update' in
|
||||
echo %BUILD_VS_LIBDIR% , until this is resolved you CANNOT make a successful blender build
|
||||
echo.
|
||||
exit /b 1
|
||||
)
|
||||
echo Cleanup complete
|
||||
|
|
@ -1,24 +0,0 @@
|
|||
if "%BUILD_VS_YEAR%"=="2019" set BUILD_VS_LIBDIRPOST=vc15
|
||||
if "%BUILD_VS_YEAR%"=="2022" set BUILD_VS_LIBDIRPOST=vc15
|
||||
|
||||
set BUILD_VS_SVNDIR=win64_%BUILD_VS_LIBDIRPOST%
|
||||
set BUILD_VS_LIBDIR="%BLENDER_DIR%..\lib\%BUILD_VS_SVNDIR%"
|
||||
|
||||
cd %BUILD_VS_LIBDIR%
|
||||
:RETRY
|
||||
"%SVN%" update
|
||||
if errorlevel 1 (
|
||||
set /p LibRetry= "Error during update, retry? y/n"
|
||||
if /I "!LibRetry!"=="Y" (
|
||||
"%SVN%" cleanup
|
||||
goto RETRY
|
||||
)
|
||||
echo.
|
||||
echo Error: Download of external libraries failed.
|
||||
echo This is needed for building, please manually run 'svn cleanup' and 'svn update' in
|
||||
echo %BUILD_VS_LIBDIR% , until this is resolved you CANNOT make a successful blender build
|
||||
echo.
|
||||
exit /b 1
|
||||
)
|
||||
|
||||
cd %BLENDER_DIR%
|
|
@ -8,6 +8,6 @@ exit /b 1
|
|||
:detect_python_done
|
||||
|
||||
REM Use -B to avoid writing __pycache__ in lib directory and causing update conflicts.
|
||||
%PYTHON% -B %BLENDER_DIR%\build_files\utils\make_test.py --git-command "%GIT%" --svn-command "%SVN%" --cmake-command="%CMAKE%" --ctest-command="%CTEST%" --config="%BUILD_TYPE%" %BUILD_DIR%
|
||||
%PYTHON% -B %BLENDER_DIR%\build_files\utils\make_test.py --git-command "%GIT%" --cmake-command="%CMAKE%" --ctest-command="%CTEST%" --config="%BUILD_TYPE%" %BUILD_DIR%
|
||||
|
||||
:EOF
|
||||
|
|
|
@ -5,6 +5,6 @@ if NOT EXIST %PYTHON% (
|
|||
:detect_python_done
|
||||
|
||||
REM Use -B to avoid writing __pycache__ in lib directory and causing update conflicts.
|
||||
%PYTHON% -B %BLENDER_DIR%\build_files\utils\make_update.py --git-command "%GIT%" --svn-command "%SVN%" %BUILD_UPDATE_ARGS%
|
||||
%PYTHON% -B %BLENDER_DIR%\build_files\utils\make_update.py --git-command "%GIT%" %BUILD_UPDATE_ARGS%
|
||||
|
||||
:EOF
|
||||
|
|
|
@ -35,8 +35,8 @@ but not to fully cover each topic.
|
|||
|
||||
A quick list of helpful things to know before starting:
|
||||
|
||||
- Enable :ref:`Developer Extra <blender_manual:prefs-interface-dev-extras>`
|
||||
and :ref:`Python Tooltips <blender_manual:prefs-interface-tooltips-python>`.
|
||||
- Enable :ref:`Developer Extra <blender_manual:bpy.types.PreferencesView.show_developer_ui>`
|
||||
and :ref:`Python Tooltips <blender_manual:bpy.types.PreferencesView.show_tooltips_python>`.
|
||||
- The :ref:`Python Console <blender_manual:bpy.types.SpaceConsole>`
|
||||
is great for testing one-liners; it has autocompletion so you can inspect the API quickly.
|
||||
- Button tooltips show Python attributes and operator names (when enabled see above).
|
||||
|
|
|
@ -26,7 +26,11 @@ extern "C" {
|
|||
|
||||
/* you can set this to either 2 (which support 0 and 1 as well) or 3 */
|
||||
/* #define XDND_VERSION 2 */
|
||||
#define XDND_VERSION 3
|
||||
|
||||
/* NOTE(@ideasman42): Use version 5 otherwise the chrome browser can't drop URL or text data.
|
||||
* Ideally all aspects of the updated specification would also be supported although none seem
|
||||
* essential for use in Blender, see: https://www.freedesktop.org/wiki/Specifications/XDND/ */
|
||||
#define XDND_VERSION 5
|
||||
|
||||
|
||||
/* XdndEnter */
|
||||
|
|
|
@ -29,6 +29,12 @@ typedef struct HuangHairExtra {
|
|||
|
||||
/* Squared Eccentricity. */
|
||||
float e2;
|
||||
|
||||
/* The projected width of half a pixel at `sd->P` in `h` space. */
|
||||
float pixel_coverage;
|
||||
|
||||
/* Valid integration interval. */
|
||||
float gamma_m_min, gamma_m_max;
|
||||
} HuangHairExtra;
|
||||
|
||||
typedef struct HuangHairBSDF {
|
||||
|
@ -135,6 +141,14 @@ ccl_device_inline float to_gamma(float phi, float b)
|
|||
return atan2f(sin_phi, b * cos_phi);
|
||||
}
|
||||
|
||||
/* Intersect `wi` with the ellipse defined by `x = sin_gamma, y = b * cos_gamma` results in solving
|
||||
* for `gamma` in equation `-cos_phi_i * sin_gamma + b * sin_phi_i * cos_gamma = h`.
|
||||
* Also, make use of `r = sqrt(sqr(cos_phi_i) + sqr(b * sin_phi_i))` to pre-map `h` to [-1, 1]. */
|
||||
ccl_device_inline float h_to_gamma(const float h_div_r, const float b, const float3 wi)
|
||||
{
|
||||
return (b == 1.0f) ? -asinf(h_div_r) : atan2f(wi.z, -b * wi.x) - acosf(-h_div_r);
|
||||
}
|
||||
|
||||
/* Compute the coordinate on the ellipse, given `gamma` and the aspect ratio between the minor axis
|
||||
* and the major axis. */
|
||||
ccl_device_inline float2 to_point(float gamma, float b)
|
||||
|
@ -170,6 +184,11 @@ ccl_device_inline float arc_length(float e2, float gamma)
|
|||
return e2 == 0 ? 1.0f : sqrtf(1.0f - e2 * sqr(sinf(gamma)));
|
||||
}
|
||||
|
||||
ccl_device_inline bool is_nearfield(ccl_private const HuangHairBSDF *bsdf)
|
||||
{
|
||||
return bsdf->extra->radius > bsdf->extra->pixel_coverage;
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
#ifdef __HAIR__
|
||||
|
@ -188,8 +207,8 @@ ccl_device int bsdf_hair_huang_setup(ccl_private ShaderData *sd,
|
|||
/* Compute local frame. The Y axis is aligned with the curve tangent; the X axis is perpendicular
|
||||
to the ray direction for circular cross-sections, or aligned with the major axis for elliptical
|
||||
cross-sections. */
|
||||
const float3 Y = safe_normalize(sd->dPdu);
|
||||
const float3 X = safe_normalize(cross(Y, sd->wi));
|
||||
bsdf->extra->Y = safe_normalize(sd->dPdu);
|
||||
const float3 X = safe_normalize(cross(sd->dPdu, sd->wi));
|
||||
|
||||
/* h from -1..0..1 means the rays goes from grazing the hair, to hitting it at the center, to
|
||||
* grazing the other edge. This is the cosine of the angle between `sd->N` and `X`. */
|
||||
|
@ -199,6 +218,8 @@ ccl_device int bsdf_hair_huang_setup(ccl_private ShaderData *sd,
|
|||
kernel_assert(isfinite_safe(bsdf->h));
|
||||
|
||||
if (bsdf->aspect_ratio != 1.0f && (sd->type & PRIMITIVE_CURVE)) {
|
||||
/* Adjust `bsdf->N` to be orthogonal to `sd->dPdu`. */
|
||||
bsdf->N = safe_normalize(cross(sd->dPdu, safe_normalize(cross(bsdf->N, sd->dPdu))));
|
||||
/* Align local frame with the curve normal. */
|
||||
if (bsdf->aspect_ratio > 1.0f) {
|
||||
/* Switch major and minor axis. */
|
||||
|
@ -214,14 +235,12 @@ ccl_device int bsdf_hair_huang_setup(ccl_private ShaderData *sd,
|
|||
|
||||
/* Fill extra closure. */
|
||||
if (is_zero(bsdf->N) || !isfinite_safe(bsdf->N)) {
|
||||
bsdf->extra->Y = Y;
|
||||
/* Construct arbitrary local coordinate system. The implementation should ensure smooth
|
||||
* transition along the hair shaft. */
|
||||
make_orthonormals(Y, &bsdf->extra->Z, &bsdf->N);
|
||||
make_orthonormals(bsdf->extra->Y, &bsdf->extra->Z, &bsdf->N);
|
||||
}
|
||||
else {
|
||||
bsdf->extra->Z = safe_normalize(cross(bsdf->N, sd->dPdu));
|
||||
bsdf->extra->Y = safe_normalize(cross(bsdf->extra->Z, bsdf->N));
|
||||
}
|
||||
|
||||
const float3 I = make_float3(
|
||||
|
@ -311,50 +330,6 @@ ccl_device Spectrum bsdf_hair_huang_eval_r(KernelGlobals kg,
|
|||
|
||||
/* Get minor axis, assuming major axis is 1. */
|
||||
const float b = bsdf->aspect_ratio;
|
||||
const bool is_circular = (b == 1.0f);
|
||||
|
||||
const float phi_i = is_circular ? 0.0f : dir_phi(wi);
|
||||
const float phi_o = dir_phi(wo);
|
||||
|
||||
/* Compute visible azimuthal range from incoming and outgoing directions. */
|
||||
/* `dot(wi, wmi) > 0` */
|
||||
const float tan_tilt = tanf(bsdf->tilt);
|
||||
float phi_m_max1 = acosf(fmaxf(-tan_tilt * tan_theta(wi), 0.0f)) + phi_i;
|
||||
if (isnan_safe(phi_m_max1)) {
|
||||
return zero_spectrum();
|
||||
}
|
||||
float phi_m_min1 = -phi_m_max1 + 2.0f * phi_i;
|
||||
|
||||
/* `dot(wo, wmi) > 0` */
|
||||
float phi_m_max2 = acosf(fmaxf(-tan_tilt * tan_theta(wo), 0.0f)) + phi_o;
|
||||
if (isnan_safe(phi_m_max2)) {
|
||||
return zero_spectrum();
|
||||
}
|
||||
float phi_m_min2 = -phi_m_max2 + 2.0f * phi_o;
|
||||
|
||||
if (!is_circular) {
|
||||
/* Try to wrap range. */
|
||||
if ((phi_m_max2 - phi_m_min1) > M_2PI_F) {
|
||||
phi_m_min2 -= M_2PI_F;
|
||||
phi_m_max2 -= M_2PI_F;
|
||||
}
|
||||
if ((phi_m_max1 - phi_m_min2) > M_2PI_F) {
|
||||
phi_m_min1 -= M_2PI_F;
|
||||
phi_m_max1 -= M_2PI_F;
|
||||
}
|
||||
}
|
||||
|
||||
const float phi_m_min = fmaxf(phi_m_min1, phi_m_min2) + 1e-3f;
|
||||
const float phi_m_max = fminf(phi_m_max1, phi_m_max2) - 1e-3f;
|
||||
if (phi_m_min > phi_m_max) {
|
||||
return zero_spectrum();
|
||||
}
|
||||
|
||||
const float gamma_m_min = to_gamma(phi_m_min, b);
|
||||
float gamma_m_max = to_gamma(phi_m_max, b);
|
||||
if (gamma_m_max < gamma_m_min) {
|
||||
gamma_m_max += M_2PI_F;
|
||||
}
|
||||
|
||||
const float3 wh = normalize(wi + wo);
|
||||
|
||||
|
@ -363,16 +338,19 @@ ccl_device Spectrum bsdf_hair_huang_eval_r(KernelGlobals kg,
|
|||
|
||||
/* Maximal sample resolution. */
|
||||
float res = roughness * 0.7f;
|
||||
|
||||
const float gamma_m_range = bsdf->extra->gamma_m_max - bsdf->extra->gamma_m_min;
|
||||
|
||||
/* Number of intervals should be even. */
|
||||
const size_t intervals = 2 * (size_t)ceilf((gamma_m_max - gamma_m_min) / res * 0.5f);
|
||||
const size_t intervals = 2 * (size_t)ceilf(gamma_m_range / res * 0.5f);
|
||||
|
||||
/* Modified resolution based on numbers of intervals. */
|
||||
res = (gamma_m_max - gamma_m_min) / float(intervals);
|
||||
res = gamma_m_range / float(intervals);
|
||||
|
||||
/* Integrate using Composite Simpson's 1/3 rule. */
|
||||
float integral = 0.0f;
|
||||
for (size_t i = 0; i <= intervals; i++) {
|
||||
const float gamma_m = gamma_m_min + i * res;
|
||||
const float gamma_m = bsdf->extra->gamma_m_min + i * res;
|
||||
const float3 wm = sphg_dir(bsdf->tilt, gamma_m, b);
|
||||
|
||||
if (microfacet_visible(wi, wo, make_float3(wm.x, 0.0f, wm.z), wh)) {
|
||||
|
@ -385,11 +363,12 @@ ccl_device Spectrum bsdf_hair_huang_eval_r(KernelGlobals kg,
|
|||
}
|
||||
}
|
||||
|
||||
/* Simpson coefficient */
|
||||
integral *= (2.0f / 3.0f * res);
|
||||
|
||||
const float F = fresnel_dielectric_cos(dot(wi, wh), bsdf->eta);
|
||||
|
||||
return make_spectrum(bsdf->extra->R * 0.125f * F * integral / bsdf->extra->radius);
|
||||
return make_spectrum(bsdf->extra->R * 0.25f * F * integral);
|
||||
}
|
||||
|
||||
/* Approximate components beyond TRT (starting TRRT) by summing up a geometric series. Attenuations
|
||||
|
@ -420,46 +399,25 @@ ccl_device Spectrum bsdf_hair_huang_eval_residual(KernelGlobals kg,
|
|||
const float b = bsdf->aspect_ratio;
|
||||
const bool is_circular = (b == 1.0f);
|
||||
|
||||
const float phi_i = is_circular ? 0.0f : dir_phi(wi);
|
||||
|
||||
/* Compute visible azimuthal range from the incoming direction. */
|
||||
const float tan_tilt = tanf(bsdf->tilt);
|
||||
const float phi_m_max = acosf(fmaxf(-tan_tilt * tan_theta(wi), 0.0f)) + phi_i;
|
||||
if (isnan_safe(phi_m_max)) {
|
||||
/* Early detection of `dot(wi, wmi) < 0`. */
|
||||
return zero_spectrum();
|
||||
}
|
||||
const float phi_m_min = -phi_m_max + 2.0f * phi_i;
|
||||
|
||||
if (tan_tilt * tan_theta(wo) < -1.0f) {
|
||||
/* Early detection of `dot(wo, wmo) < 0`. */
|
||||
return zero_spectrum();
|
||||
}
|
||||
|
||||
const Spectrum mu_a = bsdf->sigma;
|
||||
const float eta = bsdf->eta;
|
||||
const float inv_eta = 1.0f / eta;
|
||||
|
||||
const float gamma_m_min = to_gamma(phi_m_min, b) + 1e-3f;
|
||||
float gamma_m_max = to_gamma(phi_m_max, b) - 1e-3f;
|
||||
if (gamma_m_max < gamma_m_min) {
|
||||
gamma_m_max += M_2PI_F;
|
||||
}
|
||||
|
||||
const float roughness = bsdf->roughness;
|
||||
const float roughness2 = sqr(roughness);
|
||||
const float sqrt_roughness = sqrtf(roughness);
|
||||
|
||||
float res = roughness * 0.8f;
|
||||
const size_t intervals = 2 * (size_t)ceilf((gamma_m_max - gamma_m_min) / res * 0.5f);
|
||||
res = (gamma_m_max - gamma_m_min) / intervals;
|
||||
const float gamma_m_range = bsdf->extra->gamma_m_max - bsdf->extra->gamma_m_min;
|
||||
const size_t intervals = 2 * (size_t)ceilf(gamma_m_range / res * 0.5f);
|
||||
res = gamma_m_range / intervals;
|
||||
|
||||
Spectrum S_tt = zero_spectrum();
|
||||
Spectrum S_trt = zero_spectrum();
|
||||
Spectrum S_trrt = zero_spectrum();
|
||||
for (size_t i = 0; i <= intervals; i++) {
|
||||
|
||||
const float gamma_mi = gamma_m_min + i * res;
|
||||
const float gamma_mi = bsdf->extra->gamma_m_min + i * res;
|
||||
|
||||
const float3 wmi = sphg_dir(bsdf->tilt, gamma_mi, b);
|
||||
const float3 wmi_ = sphg_dir(0.0f, gamma_mi, b);
|
||||
|
@ -470,7 +428,7 @@ ccl_device Spectrum bsdf_hair_huang_eval_residual(KernelGlobals kg,
|
|||
|
||||
const float3 wh1 = sample_wh(kg, roughness, wi, wmi, sample1);
|
||||
const float cos_hi1 = dot(wi, wh1);
|
||||
if (!(cos_hi1 > 0)) {
|
||||
if (!(cos_hi1 > 0.0f)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -535,7 +493,7 @@ ccl_device Spectrum bsdf_hair_huang_eval_residual(KernelGlobals kg,
|
|||
lcg_step_float(&rng_quadrature));
|
||||
const float3 wh2 = sample_wh(kg, roughness, -wt, wmt, sample2);
|
||||
const float cos_hi2 = dot(-wt, wh2);
|
||||
if (!(cos_hi2 > 0)) {
|
||||
if (!(cos_hi2 > 0.0f)) {
|
||||
continue;
|
||||
}
|
||||
const float R2 = fresnel_dielectric_cos(cos_hi2, inv_eta);
|
||||
|
@ -603,8 +561,9 @@ ccl_device Spectrum bsdf_hair_huang_eval_residual(KernelGlobals kg,
|
|||
sin_theta(wi), cos_theta(wi), sin_theta(wo), cos_theta(wo), 4.0f * bsdf->roughness);
|
||||
const float N = M_1_2PI_F;
|
||||
|
||||
return ((S_tt + S_trt) * sqr(inv_eta) / bsdf->extra->radius + S_trrt * M * N * M_2_PI_F) * res /
|
||||
3.0f;
|
||||
const float simpson_coeff = 2.0f / 3.0f * res;
|
||||
|
||||
return ((S_tt + S_trt) * sqr(inv_eta) + S_trrt * M * N * M_2_PI_F) * simpson_coeff;
|
||||
}
|
||||
|
||||
ccl_device int bsdf_hair_huang_sample(const KernelGlobals kg,
|
||||
|
@ -635,20 +594,14 @@ ccl_device int bsdf_hair_huang_sample(const KernelGlobals kg,
|
|||
/* Get `wi` in local coordinate. */
|
||||
const float3 wi = bsdf->extra->wi;
|
||||
|
||||
const float2 sincos_phi_i = sincos_phi(wi);
|
||||
const float sin_phi_i = sincos_phi_i.x;
|
||||
const float cos_phi_i = sincos_phi_i.y;
|
||||
|
||||
/* Get minor axis, assuming major axis is 1. */
|
||||
const float b = bsdf->aspect_ratio;
|
||||
const bool is_circular = (b == 1.0f);
|
||||
|
||||
const float h = sample_h * 2.0f - 1.0f;
|
||||
const float gamma_mi = is_circular ?
|
||||
asinf(h) :
|
||||
atan2f(cos_phi_i, -b * sin_phi_i) -
|
||||
acosf(h * bsdf->extra->radius *
|
||||
inversesqrtf(sqr(cos_phi_i) + sqr(b * sin_phi_i)));
|
||||
/* Sample `h` for farfield model, as the computed intersection might have numerical issues. */
|
||||
const float h_div_r = is_nearfield(bsdf) ? bsdf->h / bsdf->extra->radius :
|
||||
(sample_h * 2.0f - 1.0f);
|
||||
const float gamma_mi = h_to_gamma(h_div_r, b, wi);
|
||||
|
||||
/* Macronormal. */
|
||||
const float3 wmi_ = sphg_dir(0, gamma_mi, b);
|
||||
|
@ -717,7 +670,7 @@ ccl_device int bsdf_hair_huang_sample(const KernelGlobals kg,
|
|||
|
||||
wtt = refract_angle(-wt, wh2, cos_theta_t2, bsdf->eta);
|
||||
|
||||
if (dot(wmt, -wtt) > 0.0f && cos_theta_t2 != 0.0f && microfacet_visible(-wtt, wmt_, wh2)) {
|
||||
if (dot(wmt, -wtt) > 0.0f && T2 > 0.0f && microfacet_visible(-wtt, wmt_, wh2)) {
|
||||
TT = bsdf->extra->TT * T1 * A_t * T2 * scale2 * bsdf_Go(roughness2, cos_mi2, dot(wmt, -wtt));
|
||||
}
|
||||
|
||||
|
@ -737,7 +690,7 @@ ccl_device int bsdf_hair_huang_sample(const KernelGlobals kg,
|
|||
if (cos_mi3 > 0.0f) {
|
||||
const Spectrum A_tr = exp(mu_a / cos_theta(wtr) *
|
||||
-(is_circular ?
|
||||
2.0f * fabsf(cos(phi_tr - gamma_mt)) :
|
||||
2.0f * fabsf(cosf(phi_tr - gamma_mt)) :
|
||||
len(to_point(gamma_mt, b) - to_point(gamma_mtr, b))));
|
||||
|
||||
const Spectrum TR = T1 * R2 * scale2 * A_t * A_tr *
|
||||
|
@ -746,9 +699,7 @@ ccl_device int bsdf_hair_huang_sample(const KernelGlobals kg,
|
|||
|
||||
const float T3 = 1.0f - R3;
|
||||
|
||||
if (cos_theta_t3 != 0.0f &&
|
||||
microfacet_visible(wtr, -wtrt, make_float3(wmtr.x, 0.0f, wmtr.z), wh3))
|
||||
{
|
||||
if (T3 > 0.0f && microfacet_visible(wtr, -wtrt, make_float3(wmtr.x, 0.0f, wmtr.z), wh3)) {
|
||||
TRT = bsdf->extra->TRT * TR * make_spectrum(T3) *
|
||||
bsdf_Go(roughness2, cos_mi3, dot(wmtr, -wtrt));
|
||||
}
|
||||
|
@ -760,8 +711,8 @@ ccl_device int bsdf_hair_huang_sample(const KernelGlobals kg,
|
|||
/* Sample `theta_o`. */
|
||||
const float rand_theta = max(lcg_step_float(&sd->lcg_state), 1e-5f);
|
||||
const float fac = 1.0f +
|
||||
bsdf->roughness *
|
||||
logf(rand_theta + (1.0f - rand_theta) * expf(-2.0f / bsdf->roughness));
|
||||
4.0f * bsdf->roughness *
|
||||
logf(rand_theta + (1.0f - rand_theta) * expf(-0.5f / bsdf->roughness));
|
||||
const float sin_theta_o = -fac * sin_theta(wi) +
|
||||
cos_from_sin(fac) *
|
||||
cosf(M_2PI_F * lcg_step_float(&sd->lcg_state)) * cos_theta(wi);
|
||||
|
@ -855,9 +806,74 @@ ccl_device Spectrum bsdf_hair_huang_eval(KernelGlobals kg,
|
|||
/* TODO: better estimation of the pdf */
|
||||
*pdf = 1.0f;
|
||||
|
||||
/* Early detection of `dot(wo, wmo) < 0`. */
|
||||
const float tan_tilt = tanf(bsdf->tilt);
|
||||
if (tan_tilt * tan_theta(local_O) < -1.0f) {
|
||||
return zero_spectrum();
|
||||
}
|
||||
|
||||
/* Compute visible azimuthal range from the incoming direction. */
|
||||
const float half_span = acosf(fmaxf(-tan_tilt * tan_theta(local_I), 0.0f));
|
||||
if (isnan_safe(half_span)) {
|
||||
/* Early detection of `dot(wi, wmi) < 0`. */
|
||||
return zero_spectrum();
|
||||
}
|
||||
const float r = bsdf->extra->radius;
|
||||
const float b = bsdf->aspect_ratio;
|
||||
const float phi_i = (b == 1.0f) ? 0.0f : dir_phi(local_I);
|
||||
float gamma_m_min = to_gamma(phi_i - half_span, b);
|
||||
float gamma_m_max = to_gamma(phi_i + half_span, b);
|
||||
if (gamma_m_max < gamma_m_min) {
|
||||
gamma_m_max += M_2PI_F;
|
||||
}
|
||||
|
||||
/* Prevent numerical issues at the boundary. */
|
||||
gamma_m_min += 1e-3f;
|
||||
gamma_m_max -= 1e-3f;
|
||||
|
||||
/* Length of the integral interval. */
|
||||
float dh = 2.0f * r;
|
||||
|
||||
if (is_nearfield(bsdf)) {
|
||||
/* Reduce the integration interval to the subset that's visible to the current pixel.
|
||||
* Inspired by [An Efficient and Practical Near and Far Field Fur Reflectance Model]
|
||||
* (https://sites.cs.ucsb.edu/~lingqi/publications/paper_fur2.pdf) by Ling-Qi Yan, Henrik Wann
|
||||
* Jensen and Ravi Ramamoorthi. */
|
||||
const float h_max = min(bsdf->h + bsdf->extra->pixel_coverage, r);
|
||||
const float h_min = max(bsdf->h - bsdf->extra->pixel_coverage, -r);
|
||||
|
||||
/* At the boundaries the hair might not cover the whole pixel. */
|
||||
dh = h_max - h_min;
|
||||
|
||||
float nearfield_gamma_min = h_to_gamma(h_max / r, bsdf->aspect_ratio, local_I);
|
||||
float nearfield_gamma_max = h_to_gamma(h_min / r, bsdf->aspect_ratio, local_I);
|
||||
|
||||
if (nearfield_gamma_max < nearfield_gamma_min) {
|
||||
nearfield_gamma_max += M_2PI_F;
|
||||
}
|
||||
|
||||
/* Wrap range to compute the intersection. */
|
||||
if ((gamma_m_max - nearfield_gamma_min) > M_2PI_F) {
|
||||
gamma_m_min -= M_2PI_F;
|
||||
gamma_m_max -= M_2PI_F;
|
||||
}
|
||||
else if ((nearfield_gamma_max - gamma_m_min) > M_2PI_F) {
|
||||
nearfield_gamma_min -= M_2PI_F;
|
||||
nearfield_gamma_max -= M_2PI_F;
|
||||
}
|
||||
|
||||
gamma_m_min = fmaxf(gamma_m_min, nearfield_gamma_min);
|
||||
gamma_m_max = fminf(gamma_m_max, nearfield_gamma_max);
|
||||
}
|
||||
|
||||
bsdf->extra->gamma_m_min = gamma_m_min;
|
||||
bsdf->extra->gamma_m_max = gamma_m_max;
|
||||
|
||||
const float projected_area = cos_theta(local_I) * dh;
|
||||
|
||||
return (bsdf_hair_huang_eval_r(kg, sc, local_I, local_O) +
|
||||
bsdf_hair_huang_eval_residual(kg, sc, local_I, local_O, sd->lcg_state)) /
|
||||
cos_theta(local_I);
|
||||
projected_area;
|
||||
}
|
||||
|
||||
/* Implements Filter Glossy by capping the effective roughness. */
|
||||
|
|
|
@ -201,7 +201,7 @@ ccl_device void light_tree_importance(const float3 N_or_D,
|
|||
cos_min_outgoing_angle = 1.0f;
|
||||
}
|
||||
else if ((bcone.theta_o + bcone.theta_e > M_PI_F) ||
|
||||
(cos_theta_minus_theta_u > cos(bcone.theta_o + bcone.theta_e)))
|
||||
(cos_theta_minus_theta_u > cosf(bcone.theta_o + bcone.theta_e)))
|
||||
{
|
||||
/* theta' = theta - theta_o - theta_u < theta_e */
|
||||
kernel_assert(
|
||||
|
@ -231,7 +231,7 @@ ccl_device void light_tree_importance(const float3 N_or_D,
|
|||
float cos_max_outgoing_angle;
|
||||
const float cos_theta_plus_theta_u = cos_theta * cos_theta_u - sin_theta * sin_theta_u;
|
||||
if (bcone.theta_e - bcone.theta_o < 0 || cos_theta < 0 || cos_theta_u < 0 ||
|
||||
cos_theta_plus_theta_u < cos(bcone.theta_e - bcone.theta_o))
|
||||
cos_theta_plus_theta_u < cosf(bcone.theta_e - bcone.theta_o))
|
||||
{
|
||||
min_importance = 0.0f;
|
||||
}
|
||||
|
|
|
@ -135,18 +135,26 @@ ccl_device_forceinline bool triangle_light_sample(KernelGlobals kg,
|
|||
const float3 e1 = V[2] - V[0];
|
||||
const float3 e2 = V[2] - V[1];
|
||||
const float longest_edge_squared = max(len_squared(e0), max(len_squared(e1), len_squared(e2)));
|
||||
const float3 N0 = cross(e0, e1);
|
||||
float3 N0 = cross(e0, e1);
|
||||
/* Flip normal if necessary. */
|
||||
const int object_flag = kernel_data_fetch(object_flag, object);
|
||||
if (object_flag & SD_OBJECT_NEGATIVE_SCALE) {
|
||||
N0 = -N0;
|
||||
}
|
||||
|
||||
/* Do not draw samples from the side without MIS. */
|
||||
ls->shader = kernel_data_fetch(tri_shader, prim);
|
||||
const float distance_to_plane = dot(N0, V[0] - P) / dot(N0, N0);
|
||||
const int ls_shader_flag = kernel_data_fetch(shaders, ls->shader & SHADER_MASK).flags;
|
||||
if (!(ls_shader_flag & (distance_to_plane > 0 ? SD_MIS_BACK : SD_MIS_FRONT))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
float Nl = 0.0f;
|
||||
ls->Ng = safe_normalize_len(N0, &Nl);
|
||||
const float area = 0.5f * Nl;
|
||||
|
||||
/* flip normal if necessary */
|
||||
const int object_flag = kernel_data_fetch(object_flag, object);
|
||||
if (object_flag & SD_OBJECT_NEGATIVE_SCALE) {
|
||||
ls->Ng = -ls->Ng;
|
||||
}
|
||||
ls->eval_fac = 1.0f;
|
||||
ls->shader = kernel_data_fetch(tri_shader, prim);
|
||||
ls->object = object;
|
||||
ls->prim = prim;
|
||||
ls->lamp = LAMP_NONE;
|
||||
|
@ -154,8 +162,6 @@ ccl_device_forceinline bool triangle_light_sample(KernelGlobals kg,
|
|||
ls->type = LIGHT_TRIANGLE;
|
||||
ls->group = object_lightgroup(kg, object);
|
||||
|
||||
float distance_to_plane = fabsf(dot(N0, V[0] - P) / dot(N0, N0));
|
||||
|
||||
if (!in_volume_segment && (longest_edge_squared > distance_to_plane * distance_to_plane)) {
|
||||
/* A modified version of James Arvo, "Stratified Sampling of Spherical Triangles"
|
||||
* http://www.graphics.cornell.edu/pubs/1995/Arv95c.pdf */
|
||||
|
|
|
@ -988,6 +988,21 @@ ccl_device void osl_closure_hair_huang_setup(KernelGlobals kg,
|
|||
bsdf->extra->TT = closure->tt_lobe;
|
||||
bsdf->extra->TRT = closure->trt_lobe;
|
||||
|
||||
bsdf->extra->pixel_coverage = 1.0f;
|
||||
|
||||
/* For camera ray, check if the hair covers more than one pixel, in which case a nearfield model
|
||||
* is needed to prevent ribbon-like appearance. */
|
||||
if ((path_flag & PATH_RAY_CAMERA) && (sd->type & PRIMITIVE_CURVE)) {
|
||||
/* Interpolate radius between curve keys. */
|
||||
const KernelCurve kcurve = kernel_data_fetch(curves, sd->prim);
|
||||
const int k0 = kcurve.first_key + PRIMITIVE_UNPACK_SEGMENT(sd->type);
|
||||
const int k1 = k0 + 1;
|
||||
const float radius = mix(
|
||||
kernel_data_fetch(curve_keys, k0).w, kernel_data_fetch(curve_keys, k1).w, sd->u);
|
||||
|
||||
bsdf->extra->pixel_coverage = 0.5f * sd->dP / radius;
|
||||
}
|
||||
|
||||
sd->flag |= bsdf_hair_huang_setup(sd, bsdf, path_flag);
|
||||
#endif
|
||||
}
|
||||
|
|
|
@ -790,6 +790,21 @@ ccl_device
|
|||
bsdf->extra->TT = fmaxf(0.0f, TT);
|
||||
bsdf->extra->TRT = fmaxf(0.0f, TRT);
|
||||
|
||||
bsdf->extra->pixel_coverage = 1.0f;
|
||||
|
||||
/* For camera ray, check if the hair covers more than one pixel, in which case a
|
||||
* nearfield model is needed to prevent ribbon-like appearance. */
|
||||
if ((path_flag & PATH_RAY_CAMERA) && (sd->type & PRIMITIVE_CURVE)) {
|
||||
/* Interpolate radius between curve keys. */
|
||||
const KernelCurve kcurve = kernel_data_fetch(curves, sd->prim);
|
||||
const int k0 = kcurve.first_key + PRIMITIVE_UNPACK_SEGMENT(sd->type);
|
||||
const int k1 = k0 + 1;
|
||||
const float radius = mix(
|
||||
kernel_data_fetch(curve_keys, k0).w, kernel_data_fetch(curve_keys, k1).w, sd->u);
|
||||
|
||||
bsdf->extra->pixel_coverage = 0.5f * sd->dP / radius;
|
||||
}
|
||||
|
||||
bsdf->aspect_ratio = stack_load_float_default(stack, shared_ofs1, data_node3.w);
|
||||
if (bsdf->aspect_ratio != 1.0f) {
|
||||
/* Align ellipse major axis with the curve normal direction. */
|
||||
|
|
|
@ -1331,7 +1331,7 @@ void LightManager::device_update_lights(Device *device, DeviceScene *dscene, Sce
|
|||
|
||||
float3 dir = safe_normalize(light->get_dir());
|
||||
|
||||
if (light->use_mis && area != 0.0f) {
|
||||
if (light->use_mis && area != 0.0f && light->spread > 0.0f) {
|
||||
shader_id |= SHADER_USE_MIS;
|
||||
}
|
||||
|
||||
|
|
|
@ -108,7 +108,9 @@ LightTreeEmitter::LightTreeEmitter(Scene *scene,
|
|||
|
||||
/* TODO: need a better way to handle this when textures are used. */
|
||||
float area = triangle_area(vertices[0], vertices[1], vertices[2]);
|
||||
measure.energy = area * average(shader->emission_estimate);
|
||||
/* Use absolute value of emission_estimate so lights with negative strength are properly
|
||||
* supported in the light tree. */
|
||||
measure.energy = area * average(fabs(shader->emission_estimate));
|
||||
|
||||
/* NOTE: the original implementation used the bounding box centroid, but triangle centroid
|
||||
* seems to work fine */
|
||||
|
@ -220,7 +222,7 @@ LightTreeEmitter::LightTreeEmitter(Scene *scene,
|
|||
|
||||
/* Use absolute value of energy so lights with negative strength are properly supported in the
|
||||
* light tree. */
|
||||
measure.energy = fabsf(average(strength));
|
||||
measure.energy = average(fabs(strength));
|
||||
|
||||
light_set_membership = lamp->get_light_set_membership();
|
||||
}
|
||||
|
|
|
@ -264,7 +264,7 @@ void Shader::estimate_emission()
|
|||
}
|
||||
|
||||
ShaderInput *surf = graph->output()->input("Surface");
|
||||
emission_estimate = fabs(output_estimate_emission(surf->link, emission_is_constant));
|
||||
emission_estimate = output_estimate_emission(surf->link, emission_is_constant);
|
||||
|
||||
if (is_zero(emission_estimate)) {
|
||||
emission_sampling = EMISSION_SAMPLING_NONE;
|
||||
|
@ -274,8 +274,9 @@ void Shader::estimate_emission()
|
|||
* using a lot of memory in the light tree and potentially wasting samples
|
||||
* where indirect light samples are sufficient.
|
||||
* Possible optimization: estimate front and back emission separately. */
|
||||
emission_sampling = (reduce_max(emission_estimate) > 0.5f) ? EMISSION_SAMPLING_FRONT_BACK :
|
||||
EMISSION_SAMPLING_NONE;
|
||||
emission_sampling = (reduce_max(fabs(emission_estimate)) > 0.5f) ?
|
||||
EMISSION_SAMPLING_FRONT_BACK :
|
||||
EMISSION_SAMPLING_NONE;
|
||||
}
|
||||
else {
|
||||
emission_sampling = emission_sampling_method;
|
||||
|
|
|
@ -844,7 +844,7 @@ class PrincipledHairBsdfNode : public BsdfBaseNode {
|
|||
NODE_SOCKET_API(float, random)
|
||||
/* Selected coloring parametrization. */
|
||||
NODE_SOCKET_API(NodePrincipledHairParametrization, parametrization)
|
||||
/* Selected scattering model (near-/far-field). */
|
||||
/* Selected scattering model (chiang/huang). */
|
||||
NODE_SOCKET_API(NodePrincipledHairModel, model)
|
||||
|
||||
virtual int get_feature()
|
||||
|
|
|
@ -111,6 +111,19 @@ static const char *get_egl_error_message_string(EGLint error)
|
|||
}
|
||||
}
|
||||
|
||||
static void egl_print_error(const char *message, const EGLint error)
|
||||
{
|
||||
const char *code = get_egl_error_enum_string(error);
|
||||
const char *msg = get_egl_error_message_string(error);
|
||||
|
||||
fprintf(stderr,
|
||||
"%sEGL Error (0x%04X): %s: %s\n",
|
||||
message,
|
||||
uint(error),
|
||||
code ? code : "<Unknown>",
|
||||
msg ? msg : "<Unknown>");
|
||||
}
|
||||
|
||||
static bool egl_chk(bool result,
|
||||
const char *file = nullptr,
|
||||
int line = 0,
|
||||
|
@ -118,11 +131,9 @@ static bool egl_chk(bool result,
|
|||
{
|
||||
if (!result) {
|
||||
const EGLint error = eglGetError();
|
||||
|
||||
#ifndef NDEBUG
|
||||
const char *code = get_egl_error_enum_string(error);
|
||||
const char *msg = get_egl_error_message_string(error);
|
||||
|
||||
#ifndef NDEBUG
|
||||
fprintf(stderr,
|
||||
"%s:%d: [%s] -> EGL Error (0x%04X): %s: %s\n",
|
||||
file,
|
||||
|
@ -132,11 +143,7 @@ static bool egl_chk(bool result,
|
|||
code ? code : "<Unknown>",
|
||||
msg ? msg : "<Unknown>");
|
||||
#else
|
||||
fprintf(stderr,
|
||||
"EGL Error (0x%04X): %s: %s\n",
|
||||
uint(error),
|
||||
code ? code : "<Unknown>",
|
||||
msg ? msg : "<Unknown>");
|
||||
egl_print_error("", error);
|
||||
(void)(file);
|
||||
(void)(line);
|
||||
(void)(text);
|
||||
|
@ -343,33 +350,43 @@ GHOST_TSuccess GHOST_ContextEGL::initializeDrawingContext()
|
|||
goto error;
|
||||
}
|
||||
|
||||
if (!EGL_CHK(::eglInitialize(m_display, &egl_major, &egl_minor)) ||
|
||||
(egl_major == 0 && egl_minor == 0))
|
||||
{
|
||||
/* We failed to create a regular render window, retry and see if we can create a headless
|
||||
* render context. */
|
||||
::eglTerminate(m_display);
|
||||
const EGLBoolean init_display_result = ::eglInitialize(m_display, &egl_major, &egl_minor);
|
||||
const EGLint init_display_error = (init_display_result) ? 0 : eglGetError();
|
||||
|
||||
const char *egl_extension_st = eglQueryString(EGL_NO_DISPLAY, EGL_EXTENSIONS);
|
||||
assert(egl_extension_st != nullptr);
|
||||
assert(egl_extension_st == nullptr ||
|
||||
strstr(egl_extension_st, "EGL_MESA_platform_surfaceless") != nullptr);
|
||||
if (egl_extension_st == nullptr ||
|
||||
strstr(egl_extension_st, "EGL_MESA_platform_surfaceless") == nullptr)
|
||||
{
|
||||
goto error;
|
||||
if (!init_display_result || (egl_major == 0 && egl_minor == 0)) {
|
||||
/* We failed to create a regular render window, retry and see if we can create a headless
|
||||
* render context. */
|
||||
::eglTerminate(m_display);
|
||||
|
||||
const char *egl_extension_st = eglQueryString(EGL_NO_DISPLAY, EGL_EXTENSIONS);
|
||||
assert(egl_extension_st != nullptr);
|
||||
assert(egl_extension_st == nullptr ||
|
||||
strstr(egl_extension_st, "EGL_MESA_platform_surfaceless") != nullptr);
|
||||
if (egl_extension_st == nullptr ||
|
||||
strstr(egl_extension_st, "EGL_MESA_platform_surfaceless") == nullptr)
|
||||
{
|
||||
egl_print_error("Failed to create display GPU context: ", init_display_error);
|
||||
fprintf(
|
||||
stderr,
|
||||
"Failed to create headless GPU context: No EGL_MESA_platform_surfaceless extension");
|
||||
goto error;
|
||||
}
|
||||
|
||||
m_display = eglGetPlatformDisplayEXT(
|
||||
EGL_PLATFORM_SURFACELESS_MESA, EGL_DEFAULT_DISPLAY, nullptr);
|
||||
|
||||
const EGLBoolean headless_result = ::eglInitialize(m_display, &egl_major, &egl_minor);
|
||||
const EGLint init_headless_error = (headless_result) ? 0 : eglGetError();
|
||||
|
||||
if (!headless_result) {
|
||||
egl_print_error("Failed to create display GPU context: ", init_display_error);
|
||||
egl_print_error("Failed to create headless GPU context: ", init_headless_error);
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
m_display = eglGetPlatformDisplayEXT(
|
||||
EGL_PLATFORM_SURFACELESS_MESA, EGL_DEFAULT_DISPLAY, nullptr);
|
||||
|
||||
if (!EGL_CHK(::eglInitialize(m_display, &egl_major, &egl_minor))) {
|
||||
goto error;
|
||||
}
|
||||
/* Because the first eglInitialize will print an error to the terminal, print a "success"
|
||||
* message here to let the user know that we successfully recovered from the error. */
|
||||
fprintf(stderr, "\nManaged to successfully fallback to surfaceless EGL rendering!\n\n");
|
||||
}
|
||||
|
||||
#ifdef WITH_GHOST_DEBUG
|
||||
fprintf(stderr, "EGL Version %d.%d\n", egl_major, egl_minor);
|
||||
#endif
|
||||
|
|
|
@ -135,6 +135,12 @@ static int gwl_registry_handler_interface_slot_max();
|
|||
static int gwl_registry_handler_interface_slot_from_string(const char *interface);
|
||||
static const GWL_RegistryHandler *gwl_registry_handler_from_interface_slot(int interface_slot);
|
||||
|
||||
static bool xkb_compose_state_feed_and_get_utf8(
|
||||
xkb_compose_state *compose_state,
|
||||
xkb_state *state,
|
||||
const xkb_keycode_t key,
|
||||
char r_utf8_buf[sizeof(GHOST_TEventKeyData::utf8_buf)]);
|
||||
|
||||
#ifdef USE_EVENT_BACKGROUND_THREAD
|
||||
static void gwl_display_event_thread_destroy(GWL_Display *display);
|
||||
|
||||
|
@ -1103,6 +1109,37 @@ static void gwl_seat_key_layout_active_state_update_mask(GWL_Seat *seat)
|
|||
}
|
||||
}
|
||||
|
||||
/** Callback that runs from GHOST's timer. */
|
||||
static void gwl_seat_key_repeat_timer_fn(GHOST_ITimerTask *task, uint64_t time_ms)
|
||||
{
|
||||
GWL_KeyRepeatPlayload *payload = static_cast<GWL_KeyRepeatPlayload *>(task->getUserData());
|
||||
|
||||
GWL_Seat *seat = payload->seat;
|
||||
wl_surface *wl_surface_focus = seat->keyboard.wl.surface_window;
|
||||
if (UNLIKELY(wl_surface_focus == nullptr)) {
|
||||
return;
|
||||
}
|
||||
|
||||
GHOST_IWindow *win = ghost_wl_surface_user_data(wl_surface_focus);
|
||||
GHOST_SystemWayland *system = seat->system;
|
||||
const uint64_t event_ms = payload->time_ms_init + time_ms;
|
||||
/* Calculate this value every time in case modifier keys are pressed. */
|
||||
|
||||
char utf8_buf[sizeof(GHOST_TEventKeyData::utf8_buf)] = {'\0'};
|
||||
if (seat->xkb.compose_state &&
|
||||
xkb_compose_state_feed_and_get_utf8(
|
||||
seat->xkb.compose_state, seat->xkb.state, payload->key_code, utf8_buf))
|
||||
{
|
||||
/* `utf8_buf` has been filled by a compose action. */
|
||||
}
|
||||
else {
|
||||
xkb_state_key_get_utf8(seat->xkb.state, payload->key_code, utf8_buf, sizeof(utf8_buf));
|
||||
}
|
||||
|
||||
system->pushEvent_maybe_pending(new GHOST_EventKey(
|
||||
event_ms, GHOST_kEventKeyDown, win, payload->key_data.gkey, true, utf8_buf));
|
||||
}
|
||||
|
||||
/**
|
||||
* \note Caller must lock `timer_mutex`.
|
||||
*/
|
||||
|
@ -1743,6 +1780,8 @@ static void ghost_wayland_log_handler(const char *msg, va_list arg)
|
|||
__attribute__((format(printf, 1, 0)));
|
||||
#endif
|
||||
|
||||
static bool ghost_wayland_log_handler_is_background = false;
|
||||
|
||||
/**
|
||||
* Callback for WAYLAND to run when there is an error.
|
||||
*
|
||||
|
@ -1751,6 +1790,15 @@ static void ghost_wayland_log_handler(const char *msg, va_list arg)
|
|||
*/
|
||||
static void ghost_wayland_log_handler(const char *msg, va_list arg)
|
||||
{
|
||||
/* This is fine in background mode, we will try to fall back to headless GPU context.
|
||||
* Happens when render farm process runs without user login session. */
|
||||
if (ghost_wayland_log_handler_is_background &&
|
||||
(strstr(msg, "error: XDG_RUNTIME_DIR not set in the environment") ||
|
||||
strstr(msg, "error: XDG_RUNTIME_DIR is invalid or not set in the environment")))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
fprintf(stderr, "GHOST/Wayland: ");
|
||||
vfprintf(stderr, msg, arg); /* Includes newline. */
|
||||
|
||||
|
@ -2761,13 +2809,11 @@ static void keyboard_depressed_state_key_event(GWL_Seat *seat,
|
|||
}
|
||||
|
||||
static void keyboard_depressed_state_push_events_from_change(
|
||||
GWL_Seat *seat, const GWL_KeyboardDepressedState &key_depressed_prev)
|
||||
GWL_Seat *seat,
|
||||
GHOST_IWindow *win,
|
||||
const uint64_t event_ms,
|
||||
const GWL_KeyboardDepressedState &key_depressed_prev)
|
||||
{
|
||||
GHOST_IWindow *win = ghost_wl_surface_user_data(seat->keyboard.wl.surface_window);
|
||||
const GHOST_SystemWayland *system = seat->system;
|
||||
/* Caller has no time-stamp, set from system. */
|
||||
const uint64_t event_ms = system->getMilliSeconds();
|
||||
|
||||
/* Separate key up and down into separate passes so key down events always come after key up.
|
||||
* Do this so users of GHOST can use the last pressed or released modifier to check
|
||||
* if the modifier is held instead of counting modifiers pressed as is done here,
|
||||
|
@ -4718,6 +4764,8 @@ static void keyboard_handle_enter(void *data,
|
|||
CLOG_INFO(LOG, 2, "enter");
|
||||
|
||||
GWL_Seat *seat = static_cast<GWL_Seat *>(data);
|
||||
GHOST_IWindow *win = ghost_wl_surface_user_data(wl_surface);
|
||||
|
||||
seat->keyboard.serial = serial;
|
||||
seat->keyboard.wl.surface_window = wl_surface;
|
||||
|
||||
|
@ -4729,6 +4777,12 @@ static void keyboard_handle_enter(void *data,
|
|||
GWL_KeyboardDepressedState key_depressed_prev = seat->key_depressed;
|
||||
keyboard_depressed_state_reset(seat);
|
||||
|
||||
/* Keep track of the last held repeating key, start the repeat timer if one exists. */
|
||||
struct {
|
||||
uint32_t key = std::numeric_limits<uint32_t>::max();
|
||||
xkb_keysym_t sym = 0;
|
||||
} repeat;
|
||||
|
||||
uint32_t *key;
|
||||
WL_ARRAY_FOR_EACH (key, keys) {
|
||||
const xkb_keycode_t key_code = *key + EVDEV_OFFSET;
|
||||
|
@ -4738,9 +4792,41 @@ static void keyboard_handle_enter(void *data,
|
|||
if (gkey != GHOST_kKeyUnknown) {
|
||||
keyboard_depressed_state_key_event(seat, gkey, GHOST_kEventKeyDown);
|
||||
}
|
||||
|
||||
if (xkb_keymap_key_repeats(xkb_state_get_keymap(seat->xkb.state), key_code)) {
|
||||
repeat.key = *key;
|
||||
repeat.sym = sym;
|
||||
}
|
||||
}
|
||||
|
||||
keyboard_depressed_state_push_events_from_change(seat, key_depressed_prev);
|
||||
/* Caller has no time-stamp, set from system. */
|
||||
const uint64_t event_ms = seat->system->getMilliSeconds();
|
||||
keyboard_depressed_state_push_events_from_change(seat, win, event_ms, key_depressed_prev);
|
||||
|
||||
if ((repeat.key != std::numeric_limits<uint32_t>::max()) && (seat->key_repeat.rate > 0)) {
|
||||
/* Since the key has been held, immediately send a press event.
|
||||
* This also ensures the key will be registered as pressed, see #117896. */
|
||||
#ifdef USE_EVENT_BACKGROUND_THREAD
|
||||
std::lock_guard lock_timer_guard{*seat->system->timer_mutex};
|
||||
#endif
|
||||
/* Should have been cleared on leave, set here just in case. */
|
||||
if (UNLIKELY(seat->key_repeat.timer)) {
|
||||
keyboard_handle_key_repeat_cancel(seat);
|
||||
}
|
||||
|
||||
const xkb_keycode_t key_code = repeat.key + EVDEV_OFFSET;
|
||||
const GHOST_TKey gkey = xkb_map_gkey_or_scan_code(repeat.sym, repeat.key);
|
||||
|
||||
GWL_KeyRepeatPlayload *key_repeat_payload = new GWL_KeyRepeatPlayload();
|
||||
key_repeat_payload->seat = seat;
|
||||
key_repeat_payload->key_code = key_code;
|
||||
key_repeat_payload->key_data.gkey = gkey;
|
||||
|
||||
gwl_seat_key_repeat_timer_add(seat, gwl_seat_key_repeat_timer_fn, key_repeat_payload, false);
|
||||
/* Ensure there is a press event on enter so this is known to be held before any mouse
|
||||
* button events which may use a key-binding that depends on this key being held. */
|
||||
gwl_seat_key_repeat_timer_fn(seat->key_repeat.timer, 0);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -5031,33 +5117,7 @@ static void keyboard_handle_key(void *data,
|
|||
}
|
||||
|
||||
if (key_repeat_payload) {
|
||||
auto key_repeat_fn = [](GHOST_ITimerTask *task, uint64_t time_ms) {
|
||||
GWL_KeyRepeatPlayload *payload = static_cast<GWL_KeyRepeatPlayload *>(task->getUserData());
|
||||
|
||||
GWL_Seat *seat = payload->seat;
|
||||
if (wl_surface *wl_surface_focus = seat->keyboard.wl.surface_window) {
|
||||
GHOST_IWindow *win = ghost_wl_surface_user_data(wl_surface_focus);
|
||||
GHOST_SystemWayland *system = seat->system;
|
||||
const uint64_t event_ms = payload->time_ms_init + time_ms;
|
||||
/* Calculate this value every time in case modifier keys are pressed. */
|
||||
|
||||
char utf8_buf[sizeof(GHOST_TEventKeyData::utf8_buf)] = {'\0'};
|
||||
if (seat->xkb.compose_state &&
|
||||
xkb_compose_state_feed_and_get_utf8(
|
||||
seat->xkb.compose_state, seat->xkb.state, payload->key_code, utf8_buf))
|
||||
{
|
||||
/* `utf8_buf` has been filled by a compose action. */
|
||||
}
|
||||
else {
|
||||
xkb_state_key_get_utf8(seat->xkb.state, payload->key_code, utf8_buf, sizeof(utf8_buf));
|
||||
}
|
||||
|
||||
system->pushEvent_maybe_pending(new GHOST_EventKey(
|
||||
event_ms, GHOST_kEventKeyDown, win, payload->key_data.gkey, true, utf8_buf));
|
||||
}
|
||||
};
|
||||
|
||||
gwl_seat_key_repeat_timer_add(seat, key_repeat_fn, key_repeat_payload, true);
|
||||
gwl_seat_key_repeat_timer_add(seat, gwl_seat_key_repeat_timer_fn, key_repeat_payload, true);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -6853,6 +6913,7 @@ GHOST_SystemWayland::GHOST_SystemWayland(bool background)
|
|||
#endif
|
||||
display_(new GWL_Display)
|
||||
{
|
||||
ghost_wayland_log_handler_is_background = background;
|
||||
wl_log_set_handler_client(ghost_wayland_log_handler);
|
||||
|
||||
display_->system = this;
|
||||
|
|
|
@ -1002,7 +1002,7 @@ NSCursor *GHOST_WindowCocoa::getStandardCursor(GHOST_TStandardCursor shape) cons
|
|||
case GHOST_kStandardCursorStop:
|
||||
return [NSCursor operationNotAllowedCursor];
|
||||
case GHOST_kStandardCursorMove:
|
||||
return [NSCursor pointingHandCursor];
|
||||
return [NSCursor openHandCursor];
|
||||
case GHOST_kStandardCursorDefault:
|
||||
return [NSCursor arrowCursor];
|
||||
case GHOST_kStandardCursorKnife:
|
||||
|
|
|
@ -339,7 +339,11 @@ template<typename T> inline T *MEM_cnew(const char *allocation_name, const T &ot
|
|||
public: \
|
||||
void *operator new(size_t num_bytes) \
|
||||
{ \
|
||||
return MEM_mallocN(num_bytes, _id); \
|
||||
return MEM_mallocN_aligned(num_bytes, __STDCPP_DEFAULT_NEW_ALIGNMENT__, _id); \
|
||||
} \
|
||||
void *operator new(size_t num_bytes, std::align_val_t alignment) \
|
||||
{ \
|
||||
return MEM_mallocN_aligned(num_bytes, size_t(alignment), _id); \
|
||||
} \
|
||||
void operator delete(void *mem) \
|
||||
{ \
|
||||
|
@ -349,7 +353,11 @@ template<typename T> inline T *MEM_cnew(const char *allocation_name, const T &ot
|
|||
} \
|
||||
void *operator new[](size_t num_bytes) \
|
||||
{ \
|
||||
return MEM_mallocN(num_bytes, _id "[]"); \
|
||||
return MEM_mallocN_aligned(num_bytes, __STDCPP_DEFAULT_NEW_ALIGNMENT__, _id "[]"); \
|
||||
} \
|
||||
void *operator new[](size_t num_bytes, std::align_val_t alignment) \
|
||||
{ \
|
||||
return MEM_mallocN_aligned(num_bytes, size_t(alignment), _id "[]"); \
|
||||
} \
|
||||
void operator delete[](void *mem) \
|
||||
{ \
|
||||
|
|
|
@ -34,6 +34,7 @@ class Renderdoc {
|
|||
RENDERDOC_WindowHandle window_handle);
|
||||
void end_frame_capture(RENDERDOC_DevicePointer device_handle,
|
||||
RENDERDOC_WindowHandle window_handle);
|
||||
void set_frame_capture_title(const char *capture_title);
|
||||
|
||||
private:
|
||||
/**
|
||||
|
@ -44,4 +45,4 @@ class Renderdoc {
|
|||
bool check_loaded();
|
||||
void load();
|
||||
};
|
||||
} // namespace renderdoc::api
|
||||
} // namespace renderdoc::api
|
||||
|
|
|
@ -33,6 +33,14 @@ void Renderdoc::end_frame_capture(RENDERDOC_DevicePointer device_handle,
|
|||
renderdoc_api_->EndFrameCapture(device_handle, window_handle);
|
||||
}
|
||||
|
||||
void Renderdoc::set_frame_capture_title(const char *title)
|
||||
{
|
||||
if (!check_loaded()) {
|
||||
return;
|
||||
}
|
||||
renderdoc_api_->SetCaptureTitle(title);
|
||||
}
|
||||
|
||||
bool Renderdoc::check_loaded()
|
||||
{
|
||||
switch (state_) {
|
||||
|
@ -64,4 +72,4 @@ void Renderdoc::load()
|
|||
#endif
|
||||
}
|
||||
|
||||
} // namespace renderdoc::api
|
||||
} // namespace renderdoc::api
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
Subproject commit 014844518a90dd96685f6f3f114b9ce6b2522e43
|
|
@ -0,0 +1 @@
|
|||
Subproject commit 9e78c2e377a75ab8fa33430d8e6567f34b2b05b2
|
|
@ -0,0 +1 @@
|
|||
Subproject commit 0a6d9ad4c6effa4227a9c0a324c7b588c1f9f71b
|
|
@ -0,0 +1 @@
|
|||
Subproject commit 19b2b87f5ef0d8caa39e0882fbf832052974b785
|
7
make.bat
7
make.bat
|
@ -56,11 +56,6 @@ if "%BUILD_VS_YEAR%" == "" (
|
|||
)
|
||||
)
|
||||
|
||||
if "%SVN_FIX%" == "1" (
|
||||
call "%BLENDER_DIR%\build_files\windows\svn_fix.cmd"
|
||||
goto EOF
|
||||
)
|
||||
|
||||
if "%BUILD_UPDATE%" == "1" (
|
||||
REM First see if the SVN libs are there and check them out if they are not.
|
||||
call "%BLENDER_DIR%\build_files\windows\check_libraries.cmd"
|
||||
|
@ -70,7 +65,7 @@ if "%BUILD_UPDATE%" == "1" (
|
|||
REM running tends to be problematic. The python script that update_sources
|
||||
REM calls later on may still try to switch branches and run into trouble,
|
||||
REM but for *most* people this will side step the problem.
|
||||
call "%BLENDER_DIR%\build_files\windows\svn_update.cmd"
|
||||
call "%BLENDER_DIR%\build_files\windows\lib_update.cmd"
|
||||
)
|
||||
REM Finally call the python script shared between all platforms that updates git
|
||||
REM and does any other SVN work like update the tests or branch switches
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
Subproject commit 3a36a5abc7b8866fe1e4d23ddea9aed1ff01c80d
|
|
@ -57,7 +57,7 @@ if not os.path.exists(blender_bin):
|
|||
blender_bin = blender_app_path
|
||||
|
||||
icons_blend = (
|
||||
os.path.join(ROOTDIR, "..", "lib", "resources", "icon_geom.blend"),
|
||||
os.path.join(ROOTDIR, "release", "datafiles", "assets", "icons", "toolbar.blend"),
|
||||
)
|
||||
|
||||
|
||||
|
|
|
@ -450,7 +450,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
** AutoPackage; version 1.0 -- http://autopackage.org
|
||||
BinReloc - a library for creating relocatable executables
|
||||
Written by: Hongli Lai <h.lai@chello.nl>
|
||||
** LZMA SDK; version 5.2.5 -- https://www.7-zip.org/sdk.html
|
||||
** LZMA SDK; version 23.01 -- https://www.7-zip.org/sdk.html
|
||||
LZMA SDK: Public Domain
|
||||
|
||||
Creative Commons Legal Code
|
||||
|
@ -3462,7 +3462,7 @@ SOFTWARE.
|
|||
|
||||
------
|
||||
|
||||
** {fmt}; version 10.0.0 -- https://github.com/fmtlib/fmt
|
||||
** {fmt}; version 10.1.1 -- https://github.com/fmtlib/fmt
|
||||
Copyright (c) 2012 - present, Victor Zverovich and {fmt} contributors
|
||||
** Brotli; version 1.0.9 -- https://github.com/google/brotli
|
||||
Copyright (c) 2009, 2010, 2013-2016 by the Brotli Authors.
|
||||
|
|
|
@ -1312,24 +1312,6 @@ class RenderEngine(StructRNA, metaclass=RNAMeta):
|
|||
__slots__ = ()
|
||||
|
||||
|
||||
class UserExtensionRepo(StructRNA):
|
||||
__slots__ = ()
|
||||
|
||||
@property
|
||||
def directory(self):
|
||||
"""Return ``directory`` or a default path derived from the users scripts path."""
|
||||
if self.use_custom_directory:
|
||||
return self.custom_directory
|
||||
import bpy
|
||||
import os
|
||||
# TODO: this should eventually be accessed via `bpy.utils.user_resource('EXTENSIONS')`
|
||||
# which points to the same location (by default).
|
||||
if (path := bpy.utils.resource_path('USER')):
|
||||
return os.path.join(path, "extensions", self.module)
|
||||
# Unlikely this is ever encountered.
|
||||
return ""
|
||||
|
||||
|
||||
class HydraRenderEngine(RenderEngine):
|
||||
__slots__ = ()
|
||||
|
||||
|
|
|
@ -42,6 +42,10 @@ url_manual_mapping = (
|
|||
("bpy.types.gpencilsculptsettings.use_automasking_layer_stroke*", "grease_pencil/modes/sculpting/introduction.html#bpy-types-gpencilsculptsettings-use-automasking-layer-stroke"),
|
||||
("bpy.types.lineartgpencilmodifier.use_image_boundary_trimming*", "grease_pencil/modifiers/generate/line_art.html#bpy-types-lineartgpencilmodifier-use-image-boundary-trimming"),
|
||||
("bpy.types.materiallineart.use_intersection_priority_override*", "render/materials/line_art.html#bpy-types-materiallineart-use-intersection-priority-override"),
|
||||
("bpy.types.preferencesedit.show_only_selected_curve_keyframes*", "editors/preferences/animation.html#bpy-types-preferencesedit-show-only-selected-curve-keyframes"),
|
||||
("bpy.types.preferencesfilepaths.use_auto_save_temporary_files*", "editors/preferences/save_load.html#bpy-types-preferencesfilepaths-use-auto-save-temporary-files"),
|
||||
("bpy.types.preferencesinput.view_rotate_sensitivity_turntable*", "editors/preferences/navigation.html#bpy-types-preferencesinput-view-rotate-sensitivity-turntable"),
|
||||
("bpy.types.preferencessystem.sequencer_disk_cache_compression*", "editors/preferences/system.html#bpy-types-preferencessystem-sequencer-disk-cache-compression"),
|
||||
("bpy.types.rigidbodyconstraint.use_override_solver_iterations*", "physics/rigid_body/constraints/introduction.html#bpy-types-rigidbodyconstraint-use-override-solver-iterations"),
|
||||
("bpy.types.toolsettings.use_gpencil_vertex_select_mask_stroke*", "grease_pencil/modes/vertex_paint/introduction.html#bpy-types-toolsettings-use-gpencil-vertex-select-mask-stroke"),
|
||||
("bpy.types.toolsettings.use_transform_correct_face_attributes*", "modeling/meshes/tools/tool_settings.html#bpy-types-toolsettings-use-transform-correct-face-attributes"),
|
||||
|
@ -49,6 +53,8 @@ url_manual_mapping = (
|
|||
("bpy.types.cyclesrendersettings.adaptive_scrambling_distance*", "render/cycles/render_settings/sampling.html#bpy-types-cyclesrendersettings-adaptive-scrambling-distance"),
|
||||
("bpy.types.cyclesrendersettings.preview_adaptive_min_samples*", "render/cycles/render_settings/sampling.html#bpy-types-cyclesrendersettings-preview-adaptive-min-samples"),
|
||||
("bpy.types.lineartgpencilmodifier.use_face_mark_keep_contour*", "grease_pencil/modifiers/generate/line_art.html#bpy-types-lineartgpencilmodifier-use-face-mark-keep-contour"),
|
||||
("bpy.types.preferencesfilepaths.show_hidden_files_datablocks*", "editors/preferences/save_load.html#bpy-types-preferencesfilepaths-show-hidden-files-datablocks"),
|
||||
("bpy.types.preferencessystem.sequencer_disk_cache_size_limit*", "editors/preferences/system.html#bpy-types-preferencessystem-sequencer-disk-cache-size-limit"),
|
||||
("bpy.types.rendersettings.use_sequencer_override_scene_strip*", "editors/video_sequencer/preview/sidebar.html#bpy-types-rendersettings-use-sequencer-override-scene-strip"),
|
||||
("bpy.types.toolsettings.use_transform_correct_keep_connected*", "modeling/meshes/tools/tool_settings.html#bpy-types-toolsettings-use-transform-correct-keep-connected"),
|
||||
("bpy.types.clothsettings.internal_compression_stiffness_max*", "physics/cloth/settings/physical_properties.html#bpy-types-clothsettings-internal-compression-stiffness-max"),
|
||||
|
@ -56,6 +62,9 @@ url_manual_mapping = (
|
|||
("bpy.types.cyclesrendersettings.preview_scrambling_distance*", "render/cycles/render_settings/sampling.html#bpy-types-cyclesrendersettings-preview-scrambling-distance"),
|
||||
("bpy.types.fluiddomainsettings.sndparticle_potential_radius*", "physics/fluid/type/domain/liquid/particles.html#bpy-types-fluiddomainsettings-sndparticle-potential-radius"),
|
||||
("bpy.types.objectlineart.use_intersection_priority_override*", "scene_layout/object/properties/line_art.html#bpy-types-objectlineart-use-intersection-priority-override"),
|
||||
("bpy.types.preferencesedit.grease_pencil_euclidean_distance*", "editors/preferences/editing.html#bpy-types-preferencesedit-grease-pencil-euclidean-distance"),
|
||||
("bpy.types.preferencesedit.grease_pencil_manhattan_distance*", "editors/preferences/editing.html#bpy-types-preferencesedit-grease-pencil-manhattan-distance"),
|
||||
("bpy.types.preferencesinput.mouse_emulate_3_button_modifier*", "editors/preferences/input.html#bpy-types-preferencesinput-mouse-emulate-3-button-modifier"),
|
||||
("bpy.types.brushgpencilsettings.use_stroke_random_strength*", "grease_pencil/modes/draw/tools/draw.html#bpy-types-brushgpencilsettings-use-stroke-random-strength"),
|
||||
("bpy.types.clothsettings.vertex_group_structural_stiffness*", "physics/cloth/settings/property_weights.html#bpy-types-clothsettings-vertex-group-structural-stiffness"),
|
||||
("bpy.types.cyclesrendersettings.film_transparent_roughness*", "render/cycles/render_settings/film.html#bpy-types-cyclesrendersettings-film-transparent-roughness"),
|
||||
|
@ -67,6 +76,9 @@ url_manual_mapping = (
|
|||
("bpy.types.fluiddomainsettings.vector_scale_with_magnitude*", "physics/fluid/type/domain/gas/viewport_display.html#bpy-types-fluiddomainsettings-vector-scale-with-magnitude"),
|
||||
("bpy.types.lineartgpencilmodifier.use_face_mark_boundaries*", "grease_pencil/modifiers/generate/line_art.html#bpy-types-lineartgpencilmodifier-use-face-mark-boundaries"),
|
||||
("bpy.types.movietrackingstabilization.use_2d_stabilization*", "movie_clip/tracking/clip/sidebar/stabilization/panel.html#bpy-types-movietrackingstabilization-use-2d-stabilization"),
|
||||
("bpy.types.preferencesedit.keyframe_new_interpolation_type*", "editors/preferences/animation.html#bpy-types-preferencesedit-keyframe-new-interpolation-type"),
|
||||
("bpy.types.preferencesedit.use_auto_keyframe_insert_needed*", "editors/preferences/animation.html#bpy-types-preferencesedit-use-auto-keyframe-insert-needed"),
|
||||
("bpy.types.preferencesedit.use_fcurve_high_quality_drawing*", "editors/preferences/animation.html#bpy-types-preferencesedit-use-fcurve-high-quality-drawing"),
|
||||
("bpy.types.spacespreadsheet.display_context_path_collapsed*", "editors/spreadsheet.html#bpy-types-spacespreadsheet-display-context-path-collapsed"),
|
||||
("bpy.types.toolsettings.annotation_stroke_placement_view2d*", "interface/annotate_tool.html#bpy-types-toolsettings-annotation-stroke-placement-view2d"),
|
||||
("bpy.types.toolsettings.annotation_stroke_placement_view3d*", "interface/annotate_tool.html#bpy-types-toolsettings-annotation-stroke-placement-view3d"),
|
||||
|
@ -77,6 +89,7 @@ url_manual_mapping = (
|
|||
("bpy.types.fluiddomainsettings.use_collision_border_front*", "physics/fluid/type/domain/settings.html#bpy-types-fluiddomainsettings-use-collision-border-front"),
|
||||
("bpy.types.fluiddomainsettings.use_collision_border_right*", "physics/fluid/type/domain/settings.html#bpy-types-fluiddomainsettings-use-collision-border-right"),
|
||||
("bpy.types.lineartgpencilmodifier.shadow_region_filtering*", "grease_pencil/modifiers/generate/line_art.html#bpy-types-lineartgpencilmodifier-shadow-region-filtering"),
|
||||
("bpy.types.preferencesedit.collection_instance_empty_size*", "editors/preferences/editing.html#bpy-types-preferencesedit-collection-instance-empty-size"),
|
||||
("bpy.types.sequencertimelineoverlay.waveform_display_type*", "editors/video_sequencer/sequencer/display.html#bpy-types-sequencertimelineoverlay-waveform-display-type"),
|
||||
("bpy.types.view3doverlay.use_normals_constant_screen_size*", "editors/3dview/display/overlays.html#bpy-types-view3doverlay-use-normals-constant-screen-size"),
|
||||
("bpy.types.brushgpencilsettings.random_saturation_factor*", "grease_pencil/modes/draw/tools/draw.html#bpy-types-brushgpencilsettings-random-saturation-factor"),
|
||||
|
@ -94,6 +107,10 @@ url_manual_mapping = (
|
|||
("bpy.types.fluiddomainsettings.use_collision_border_back*", "physics/fluid/type/domain/settings.html#bpy-types-fluiddomainsettings-use-collision-border-back"),
|
||||
("bpy.types.fluiddomainsettings.use_collision_border_left*", "physics/fluid/type/domain/settings.html#bpy-types-fluiddomainsettings-use-collision-border-left"),
|
||||
("bpy.types.lineartgpencilmodifier.use_intersection_match*", "grease_pencil/modifiers/generate/line_art.html#bpy-types-lineartgpencilmodifier-use-intersection-match"),
|
||||
("bpy.types.preferencesedit.use_anim_channel_group_colors*", "editors/preferences/animation.html#bpy-types-preferencesedit-use-anim-channel-group-colors"),
|
||||
("bpy.types.preferencesedit.use_keyframe_insert_available*", "editors/preferences/animation.html#bpy-types-preferencesedit-use-keyframe-insert-available"),
|
||||
("bpy.types.preferencesexperimental.show_asset_debug_info*", "editors/preferences/experimental.html#bpy-types-preferencesexperimental-show-asset-debug-info"),
|
||||
("bpy.types.preferencesfilepaths.use_scripts_auto_execute*", "editors/preferences/save_load.html#bpy-types-preferencesfilepaths-use-scripts-auto-execute"),
|
||||
("bpy.types.rendersettings_simplify_gpencil_view_modifier*", "render/cycles/render_settings/simplify.html#bpy-types-rendersettings-simplify-gpencil-view-modifier"),
|
||||
("bpy.types.sequencertimelineoverlay.show_strip_tag_color*", "editors/video_sequencer/sequencer/display.html#bpy-types-sequencertimelineoverlay-show-strip-tag-color"),
|
||||
("bpy.types.spaceoutliner.use_filter_object_grease_pencil*", "editors/outliner/interface.html#bpy-types-spaceoutliner-use-filter-object-grease-pencil"),
|
||||
|
@ -116,6 +133,10 @@ url_manual_mapping = (
|
|||
("bpy.types.lineartgpencilmodifier.use_invert_collection*", "grease_pencil/modifiers/generate/line_art.html#bpy-types-lineartgpencilmodifier-use-invert-collection"),
|
||||
("bpy.types.lineartgpencilmodifier.use_invert_silhouette*", "grease_pencil/modifiers/generate/line_art.html#bpy-types-lineartgpencilmodifier-use-invert-silhouette"),
|
||||
("bpy.types.movietrackingsettings.use_keyframe_selection*", "movie_clip/tracking/clip/toolbar/solve.html#bpy-types-movietrackingsettings-use-keyframe-selection"),
|
||||
("bpy.types.preferencesexperimental.override_auto_resync*", "editors/preferences/experimental.html#bpy-types-preferencesexperimental-override-auto-resync"),
|
||||
("bpy.types.preferencesfilepaths.animation_player_preset*", "editors/preferences/file_paths.html#bpy-types-preferencesfilepaths-animation-player-preset"),
|
||||
("bpy.types.preferencesfilepaths.i18n_branches_directory*", "editors/preferences/file_paths.html#bpy-types-preferencesfilepaths-i18n-branches-directory"),
|
||||
("bpy.types.preferencesfilepaths.render_output_directory*", "editors/preferences/file_paths.html#bpy-types-preferencesfilepaths-render-output-directory"),
|
||||
("bpy.types.rendersettings.simplify_gpencil_antialiasing*", "render/cycles/render_settings/simplify.html#bpy-types-rendersettings-simplify-gpencil-antialiasing"),
|
||||
("bpy.types.sequencertimelineoverlay.show_strip_duration*", "editors/video_sequencer/sequencer/display.html#bpy-types-sequencertimelineoverlay-show-strip-duration"),
|
||||
("bpy.types.spaceoutliner.use_filter_lib_override_system*", "editors/outliner/interface.html#bpy-types-spaceoutliner-use-filter-lib-override-system"),
|
||||
|
@ -131,12 +152,20 @@ url_manual_mapping = (
|
|||
("bpy.types.cyclesrendersettings.film_transparent_glass*", "render/cycles/render_settings/film.html#bpy-types-cyclesrendersettings-film-transparent-glass"),
|
||||
("bpy.types.cyclesrendersettings.offscreen_dicing_scale*", "render/cycles/render_settings/subdivision.html#bpy-types-cyclesrendersettings-offscreen-dicing-scale"),
|
||||
("bpy.types.fluiddomainsettings.sndparticle_bubble_drag*", "physics/fluid/type/domain/liquid/particles.html#bpy-types-fluiddomainsettings-sndparticle-bubble-drag"),
|
||||
("bpy.types.keyingsetpath.use_insertkey_override_needed*", "animation/keyframes/keying_sets.html#bpy-types-keyingsetpath-use-insertkey-override-needed"),
|
||||
("bpy.types.keyingsetpath.use_insertkey_override_visual*", "animation/keyframes/keying_sets.html#bpy-types-keyingsetpath-use-insertkey-override-visual"),
|
||||
("bpy.types.lineartgpencilmodifier.light_contour_object*", "grease_pencil/modifiers/generate/line_art.html#bpy-types-lineartgpencilmodifier-light-contour-object"),
|
||||
("bpy.types.lineartgpencilmodifier.silhouette_filtering*", "grease_pencil/modifiers/generate/line_art.html#bpy-types-lineartgpencilmodifier-silhouette-filtering"),
|
||||
("bpy.types.lineartgpencilmodifier.use_crease_on_smooth*", "grease_pencil/modifiers/generate/line_art.html#bpy-types-lineartgpencilmodifier-use-crease-on-smooth"),
|
||||
("bpy.types.lineartgpencilmodifier.use_face_mark_invert*", "grease_pencil/modifiers/generate/line_art.html#bpy-types-lineartgpencilmodifier-use-face-mark-invert"),
|
||||
("bpy.types.linestylegeometrymodifier_backbonestretcher*", "render/freestyle/view_layer/line_style/modifiers/geometry/backbone_stretcher.html#bpy-types-linestylegeometrymodifier-backbonestretcher"),
|
||||
("bpy.types.linestylegeometrymodifier_sinusdisplacement*", "render/freestyle/view_layer/line_style/modifiers/geometry/sinus_displacement.html#bpy-types-linestylegeometrymodifier-sinusdisplacement"),
|
||||
("bpy.types.preferencesedit.grease_pencil_default_color*", "editors/preferences/editing.html#bpy-types-preferencesedit-grease-pencil-default-color"),
|
||||
("bpy.types.preferencesedit.grease_pencil_eraser_radius*", "editors/preferences/editing.html#bpy-types-preferencesedit-grease-pencil-eraser-radius"),
|
||||
("bpy.types.preferencesfilepaths.render_cache_directory*", "editors/preferences/file_paths.html#bpy-types-preferencesfilepaths-render-cache-directory"),
|
||||
("bpy.types.preferencesinput.use_mouse_emulate_3_button*", "editors/preferences/input.html#bpy-types-preferencesinput-use-mouse-emulate-3-button"),
|
||||
("bpy.types.preferencesinput.use_numeric_input_advanced*", "editors/preferences/input.html#bpy-types-preferencesinput-use-numeric-input-advanced"),
|
||||
("bpy.types.preferencessystem.use_edit_mode_smooth_wire*", "editors/preferences/viewport.html#bpy-types-preferencessystem-use-edit-mode-smooth-wire"),
|
||||
("bpy.types.sequencertoolsettings.snap_to_current_frame*", "video_editing/edit/montage/editing.html#bpy-types-sequencertoolsettings-snap-to-current-frame"),
|
||||
("bpy.types.view3doverlay.sculpt_mode_face_sets_opacity*", "sculpt_paint/sculpting/editing/face_sets.html#bpy-types-view3doverlay-sculpt-mode-face-sets-opacity"),
|
||||
("bpy.ops.object.geometry_nodes_input_attribute_toggle*", "modeling/modifiers/generate/geometry_nodes.html#bpy-ops-object-geometry-nodes-input-attribute-toggle"),
|
||||
|
@ -166,8 +195,20 @@ url_manual_mapping = (
|
|||
("bpy.types.lineartgpencilmodifier.stroke_depth_offset*", "grease_pencil/modifiers/generate/line_art.html#bpy-types-lineartgpencilmodifier-stroke-depth-offset"),
|
||||
("bpy.types.lineartgpencilmodifier.use_crease_on_sharp*", "grease_pencil/modifiers/generate/line_art.html#bpy-types-lineartgpencilmodifier-use-crease-on-sharp"),
|
||||
("bpy.types.linestylegeometrymodifier_polygonalization*", "render/freestyle/view_layer/line_style/modifiers/geometry/polygonization.html#bpy-types-linestylegeometrymodifier-polygonalization"),
|
||||
("bpy.types.preferencesedit.sculpt_paint_overlay_color*", "editors/preferences/editing.html#bpy-types-preferencesedit-sculpt-paint-overlay-color"),
|
||||
("bpy.types.preferencesedit.use_keyframe_insert_needed*", "editors/preferences/animation.html#bpy-types-preferencesedit-use-keyframe-insert-needed"),
|
||||
("bpy.types.preferencesexperimental.use_asset_indexing*", "editors/preferences/experimental.html#bpy-types-preferencesexperimental-use-asset-indexing"),
|
||||
("bpy.types.preferencesexperimental.use_viewport_debug*", "editors/preferences/experimental.html#bpy-types-preferencesexperimental-use-viewport-debug"),
|
||||
("bpy.types.preferencesfilepaths.show_recent_locations*", "editors/preferences/save_load.html#bpy-types-preferencesfilepaths-show-recent-locations"),
|
||||
("bpy.types.preferencesfilepaths.show_system_bookmarks*", "editors/preferences/save_load.html#bpy-types-preferencesfilepaths-show-system-bookmarks"),
|
||||
("bpy.types.preferencesinput.ndof_lock_camera_pan_zoom*", "editors/preferences/input.html#bpy-types-preferencesinput-ndof-lock-camera-pan-zoom"),
|
||||
("bpy.types.preferencesinput.ndof_view_navigate_method*", "editors/preferences/input.html#bpy-types-preferencesinput-ndof-view-navigate-method"),
|
||||
("bpy.types.preferencessystem.sequencer_disk_cache_dir*", "editors/preferences/system.html#bpy-types-preferencessystem-sequencer-disk-cache-dir"),
|
||||
("bpy.types.preferencessystem.use_sequencer_disk_cache*", "editors/preferences/system.html#bpy-types-preferencessystem-use-sequencer-disk-cache"),
|
||||
("bpy.types.preferencesview.use_text_render_subpixelaa*", "editors/preferences/interface.html#bpy-types-preferencesview-use-text-render-subpixelaa"),
|
||||
("bpy.types.sequencertimelineoverlay.show_strip_source*", "editors/video_sequencer/sequencer/display.html#bpy-types-sequencertimelineoverlay-show-strip-source"),
|
||||
("bpy.types.toolsettings.use_gpencil_automerge_strokes*", "grease_pencil/modes/draw/introduction.html#bpy-types-toolsettings-use-gpencil-automerge-strokes"),
|
||||
("bpy.types.toolsettings.use_keyframe_insert_keyingset*", "editors/timeline.html#bpy-types-toolsettings-use-keyframe-insert-keyingset"),
|
||||
("bpy.types.toolsettings.use_proportional_edit_objects*", "editors/3dview/controls/proportional_editing.html#bpy-types-toolsettings-use-proportional-edit-objects"),
|
||||
("bpy.ops.outliner.liboverride_troubleshoot_operation*", "files/linked_libraries/library_overrides.html#bpy-ops-outliner-liboverride-troubleshoot-operation"),
|
||||
("bpy.ops.view3d.edit_mesh_extrude_move_shrink_fatten*", "modeling/meshes/editing/face/extrude_faces_normal.html#bpy-ops-view3d-edit-mesh-extrude-move-shrink-fatten"),
|
||||
|
@ -201,6 +242,12 @@ url_manual_mapping = (
|
|||
("bpy.types.lineartgpencilmodifier.shadow_camera_near*", "grease_pencil/modifiers/generate/line_art.html#bpy-types-lineartgpencilmodifier-shadow-camera-near"),
|
||||
("bpy.types.lineartgpencilmodifier.shadow_camera_size*", "grease_pencil/modifiers/generate/line_art.html#bpy-types-lineartgpencilmodifier-shadow-camera-size"),
|
||||
("bpy.types.materialgpencilstyle.use_fill_texture_mix*", "grease_pencil/materials/properties.html#bpy-types-materialgpencilstyle-use-fill-texture-mix"),
|
||||
("bpy.types.preferencesedit.fcurve_new_auto_smoothing*", "editors/preferences/animation.html#bpy-types-preferencesedit-fcurve-new-auto-smoothing"),
|
||||
("bpy.types.preferencesfilepaths.use_file_compression*", "editors/preferences/save_load.html#bpy-types-preferencesfilepaths-use-file-compression"),
|
||||
("bpy.types.preferencesinput.use_mouse_depth_navigate*", "editors/preferences/navigation.html#bpy-types-preferencesinput-use-mouse-depth-navigate"),
|
||||
("bpy.types.preferencesinput.use_rotate_around_active*", "editors/preferences/navigation.html#bpy-types-preferencesinput-use-rotate-around-active"),
|
||||
("bpy.types.preferencessystem.texture_collection_rate*", "editors/preferences/system.html#bpy-types-preferencessystem-texture-collection-rate"),
|
||||
("bpy.types.preferencessystem.use_overlay_smooth_wire*", "editors/preferences/viewport.html#bpy-types-preferencessystem-use-overlay-smooth-wire"),
|
||||
("bpy.types.rendersettings_simplify_gpencil_shader_fx*", "render/cycles/render_settings/simplify.html#bpy-types-rendersettings-simplify-gpencil-shader-fx"),
|
||||
("bpy.types.rendersettings_simplify_gpencil_view_fill*", "render/cycles/render_settings/simplify.html#bpy-types-rendersettings-simplify-gpencil-view-fill"),
|
||||
("bpy.types.sculpt.use_automasking_boundary_face_sets*", "sculpt_paint/sculpting/controls.html#bpy-types-sculpt-use-automasking-boundary-face-sets"),
|
||||
|
@ -246,6 +293,15 @@ url_manual_mapping = (
|
|||
("bpy.types.materialgpencilstyle.use_overlap_strokes*", "grease_pencil/materials/properties.html#bpy-types-materialgpencilstyle-use-overlap-strokes"),
|
||||
("bpy.types.movietrackingtrack.use_grayscale_preview*", "movie_clip/tracking/clip/sidebar/track/track.html#bpy-types-movietrackingtrack-use-grayscale-preview"),
|
||||
("bpy.types.nodetreeinterfacesocket.hide_in_modifier*", "interface/controls/nodes/groups.html#bpy-types-nodetreeinterfacesocket-hide-in-modifier"),
|
||||
("bpy.types.preferencesedit.keyframe_new_handle_type*", "editors/preferences/animation.html#bpy-types-preferencesedit-keyframe-new-handle-type"),
|
||||
("bpy.types.preferencesedit.use_insertkey_xyz_to_rgb*", "editors/preferences/animation.html#bpy-types-preferencesedit-use-insertkey-xyz-to-rgb"),
|
||||
("bpy.types.preferencesedit.use_text_edit_auto_close*", "editors/preferences/editing.html#bpy-types-preferencesedit-use-text-edit-auto-close"),
|
||||
("bpy.types.preferencesexperimental.use_cycles_debug*", "editors/preferences/experimental.html#bpy-types-preferencesexperimental-use-cycles-debug"),
|
||||
("bpy.types.preferencesfilepaths.temporary_directory*", "editors/preferences/file_paths.html#bpy-types-preferencesfilepaths-temporary-directory"),
|
||||
("bpy.types.preferencesinput.mouse_double_click_time*", "editors/preferences/input.html#bpy-types-preferencesinput-mouse-double-click-time"),
|
||||
("bpy.types.preferencesinput.ndof_view_rotate_method*", "editors/preferences/input.html#bpy-types-preferencesinput-ndof-view-rotate-method"),
|
||||
("bpy.types.preferencesinput.use_multitouch_gestures*", "editors/preferences/input.html#bpy-types-preferencesinput-use-multitouch-gestures"),
|
||||
("bpy.types.preferencesview.filebrowser_display_type*", "editors/preferences/interface.html#bpy-types-preferencesview-filebrowser-display-type"),
|
||||
("bpy.types.sequencertimelineoverlay.show_strip_name*", "editors/video_sequencer/sequencer/display.html#bpy-types-sequencertimelineoverlay-show-strip-name"),
|
||||
("bpy.types.sequencertimelineoverlay.show_thumbnails*", "editors/video_sequencer/sequencer/display.html#bpy-types-sequencertimelineoverlay-show-thumbnails"),
|
||||
("bpy.types.spacespreadsheet.geometry_component_type*", "editors/spreadsheet.html#bpy-types-spacespreadsheet-geometry-component-type"),
|
||||
|
@ -281,6 +337,8 @@ url_manual_mapping = (
|
|||
("bpy.types.freestylesettings.kr_derivative_epsilon*", "render/freestyle/view_layer/freestyle.html#bpy-types-freestylesettings-kr-derivative-epsilon"),
|
||||
("bpy.types.geometrynodecurveprimitivebeziersegment*", "modeling/geometry_nodes/curve/primitives/bezier_segment.html#bpy-types-geometrynodecurveprimitivebeziersegment"),
|
||||
("bpy.types.geometrynodecurveprimitivequadrilateral*", "modeling/geometry_nodes/curve/primitives/quadrilateral.html#bpy-types-geometrynodecurveprimitivequadrilateral"),
|
||||
("bpy.types.keyingset.use_insertkey_override_needed*", "animation/keyframes/keying_sets.html#bpy-types-keyingset-use-insertkey-override-needed"),
|
||||
("bpy.types.keyingset.use_insertkey_override_visual*", "animation/keyframes/keying_sets.html#bpy-types-keyingset-use-insertkey-override-visual"),
|
||||
("bpy.types.lineartgpencilmodifier.crease_threshold*", "grease_pencil/modifiers/generate/line_art.html#bpy-types-lineartgpencilmodifier-crease-threshold"),
|
||||
("bpy.types.lineartgpencilmodifier.smooth_tolerance*", "grease_pencil/modifiers/generate/line_art.html#bpy-types-lineartgpencilmodifier-smooth-tolerance"),
|
||||
("bpy.types.lineartgpencilmodifier.use_intersection*", "grease_pencil/modifiers/generate/line_art.html#bpy-types-lineartgpencilmodifier-use-intersection"),
|
||||
|
@ -291,6 +349,19 @@ url_manual_mapping = (
|
|||
("bpy.types.movietrackingsettings.use_tripod_solver*", "movie_clip/tracking/clip/toolbar/solve.html#bpy-types-movietrackingsettings-use-tripod-solver"),
|
||||
("bpy.types.nodesmodifier.simulation_bake_directory*", "modeling/modifiers/generate/geometry_nodes.html#bpy-types-nodesmodifier-simulation-bake-directory"),
|
||||
("bpy.types.nodetreeinterfacesocket.force_non_field*", "interface/controls/nodes/groups.html#bpy-types-nodetreeinterfacesocket-force-non-field"),
|
||||
("bpy.types.preferencesedit.fcurve_unselected_alpha*", "editors/preferences/animation.html#bpy-types-preferencesedit-fcurve-unselected-alpha"),
|
||||
("bpy.types.preferencesedit.use_auto_keying_warning*", "editors/preferences/animation.html#bpy-types-preferencesedit-use-auto-keying-warning"),
|
||||
("bpy.types.preferencesexperimental.use_eevee_debug*", "editors/preferences/experimental.html#bpy-types-preferencesexperimental-use-eevee-debug"),
|
||||
("bpy.types.preferencesexperimental.use_undo_legacy*", "editors/preferences/experimental.html#bpy-types-preferencesexperimental-use-undo-legacy"),
|
||||
("bpy.types.preferencesfilepaths.use_relative_paths*", "editors/preferences/save_load.html#bpy-types-preferencesfilepaths-use-relative-paths"),
|
||||
("bpy.types.preferencesfilepaths.use_tabs_as_spaces*", "editors/preferences/save_load.html#bpy-types-preferencesfilepaths-use-tabs-as-spaces"),
|
||||
("bpy.types.preferencesinput.ndof_orbit_sensitivity*", "editors/preferences/input.html#bpy-types-preferencesinput-ndof-orbit-sensitivity"),
|
||||
("bpy.types.preferencesinput.pressure_threshold_max*", "editors/preferences/input.html#bpy-types-preferencesinput-pressure-threshold-max"),
|
||||
("bpy.types.preferencessystem.sequencer_proxy_setup*", "editors/preferences/system.html#bpy-types-preferencessystem-sequencer-proxy-setup"),
|
||||
("bpy.types.preferencessystem.use_select_pick_depth*", "editors/preferences/viewport.html#bpy-types-preferencessystem-use-select-pick-depth"),
|
||||
("bpy.types.preferencessystem.use_studio_light_edit*", "editors/preferences/lights.html#bpy-types-preferencessystem-use-studio-light-edit"),
|
||||
("bpy.types.preferencesview.gizmo_size_navigate_v3d*", "editors/preferences/viewport.html#bpy-types-preferencesview-gizmo-size-navigate-v3d"),
|
||||
("bpy.types.preferencesview.view2d_grid_spacing_min*", "editors/preferences/animation.html#bpy-types-preferencesview-view2d-grid-spacing-min"),
|
||||
("bpy.types.rendersettings.simplify_child_particles*", "render/cycles/render_settings/simplify.html#bpy-types-rendersettings-simplify-child-particles"),
|
||||
("bpy.types.rendersettings.use_high_quality_normals*", "render/eevee/render_settings/performance.html#bpy-types-rendersettings-use-high-quality-normals"),
|
||||
("bpy.types.sculpt.automasking_start_normal_falloff*", "sculpt_paint/sculpting/controls.html#bpy-types-sculpt-automasking-start-normal-falloff"),
|
||||
|
@ -342,6 +413,16 @@ url_manual_mapping = (
|
|||
("bpy.types.materiallineart.use_material_mask_bits*", "render/materials/line_art.html#bpy-types-materiallineart-use-material-mask-bits"),
|
||||
("bpy.types.movietrackingdopesheet.use_invert_sort*", "movie_clip/tracking/dope_sheet.html#bpy-types-movietrackingdopesheet-use-invert-sort"),
|
||||
("bpy.types.nodetreeinterfacesocket*.default_value*", "interface/controls/nodes/groups.html#bpy-types-nodetreeinterfacesocket-default-value"),
|
||||
("bpy.types.preferencesedit.node_use_insert_offset*", "editors/preferences/editing.html#bpy-types-preferencesedit-node-use-insert-offset"),
|
||||
("bpy.types.preferencesedit.use_cursor_lock_adjust*", "editors/preferences/editing.html#bpy-types-preferencesedit-use-cursor-lock-adjust"),
|
||||
("bpy.types.preferencesedit.use_mouse_depth_cursor*", "editors/preferences/editing.html#bpy-types-preferencesedit-use-mouse-depth-cursor"),
|
||||
("bpy.types.preferencesfilepaths.file_preview_type*", "editors/preferences/save_load.html#bpy-types-preferencesfilepaths-file-preview-type"),
|
||||
("bpy.types.preferencesfilepaths.texture_directory*", "editors/preferences/file_paths.html#bpy-types-preferencesfilepaths-texture-directory"),
|
||||
("bpy.types.preferencesinput.drag_threshold_tablet*", "editors/preferences/input.html#bpy-types-preferencesinput-drag-threshold-tablet"),
|
||||
("bpy.types.preferencesinput.ndof_pan_yz_swap_axis*", "editors/preferences/input.html#bpy-types-preferencesinput-ndof-pan-yz-swap-axis"),
|
||||
("bpy.types.preferencesinput.ndof_panx_invert_axis*", "editors/preferences/input.html#bpy-types-preferencesinput-ndof-panx-invert-axis"),
|
||||
("bpy.types.preferencesinput.ndof_rotx_invert_axis*", "editors/preferences/input.html#bpy-types-preferencesinput-ndof-rotx-invert-axis"),
|
||||
("bpy.types.preferencesview.use_weight_color_range*", "editors/preferences/editing.html#bpy-types-preferencesview-use-weight-color-range"),
|
||||
("bpy.types.rendersettings_simplify_gpencil_onplay*", "render/cycles/render_settings/simplify.html#bpy-types-rendersettings-simplify-gpencil-onplay"),
|
||||
("bpy.types.rigidbodyconstraint.breaking_threshold*", "physics/rigid_body/constraints/introduction.html#bpy-types-rigidbodyconstraint-breaking-threshold"),
|
||||
("bpy.types.sculpt.use_automasking_cavity_inverted*", "sculpt_paint/sculpting/controls.html#bpy-types-sculpt-use-automasking-cavity-inverted"),
|
||||
|
@ -402,6 +483,18 @@ url_manual_mapping = (
|
|||
("bpy.types.materiallineart.intersection_priority*", "render/materials/line_art.html#bpy-types-materiallineart-intersection-priority"),
|
||||
("bpy.types.movietrackingplanetrack.image_opacity*", "movie_clip/tracking/clip/sidebar/track/plane_track.html#bpy-types-movietrackingplanetrack-image-opacity"),
|
||||
("bpy.types.particlesettings.use_parent_particles*", "physics/particles/emitter/render.html#bpy-types-particlesettings-use-parent-particles"),
|
||||
("bpy.types.preferencesfilepaths.text_editor_args*", "editors/preferences/file_paths.html#bpy-types-preferencesfilepaths-text-editor-args"),
|
||||
("bpy.types.preferencesfilepaths.use_filter_files*", "editors/preferences/save_load.html#bpy-types-preferencesfilepaths-use-filter-files"),
|
||||
("bpy.types.preferencesinput.drag_threshold_mouse*", "editors/preferences/input.html#bpy-types-preferencesinput-drag-threshold-mouse"),
|
||||
("bpy.types.preferencesinput.use_auto_perspective*", "editors/preferences/navigation.html#bpy-types-preferencesinput-use-auto-perspective"),
|
||||
("bpy.types.preferencesinput.use_drag_immediately*", "editors/preferences/input.html#bpy-types-preferencesinput-use-drag-immediately"),
|
||||
("bpy.types.preferencesinput.use_mouse_continuous*", "editors/preferences/input.html#bpy-types-preferencesinput-use-mouse-continuous"),
|
||||
("bpy.types.preferencessystem.audio_mixing_buffer*", "editors/preferences/system.html#bpy-types-preferencessystem-audio-mixing-buffer"),
|
||||
("bpy.types.preferencessystem.audio_sample_format*", "editors/preferences/system.html#bpy-types-preferencessystem-audio-sample-format"),
|
||||
("bpy.types.preferencessystem.use_gpu_subdivision*", "editors/preferences/viewport.html#bpy-types-preferencessystem-use-gpu-subdivision"),
|
||||
("bpy.types.preferencessystem.vbo_collection_rate*", "editors/preferences/system.html#bpy-types-preferencessystem-vbo-collection-rate"),
|
||||
("bpy.types.preferencesview.pie_animation_timeout*", "editors/preferences/interface.html#bpy-types-preferencesview-pie-animation-timeout"),
|
||||
("bpy.types.preferencesview.use_text_antialiasing*", "editors/preferences/interface.html#bpy-types-preferencesview-use-text-antialiasing"),
|
||||
("bpy.types.rigidbodyconstraint.solver_iterations*", "physics/rigid_body/constraints/introduction.html#bpy-types-rigidbodyconstraint-solver-iterations"),
|
||||
("bpy.types.rigidbodyobject.collision_collections*", "physics/rigid_body/properties/collisions.html#bpy-types-rigidbodyobject-collision-collections"),
|
||||
("bpy.types.sculpt.automasking_start_normal_limit*", "sculpt_paint/sculpting/controls.html#bpy-types-sculpt-automasking-start-normal-limit"),
|
||||
|
@ -465,6 +558,14 @@ url_manual_mapping = (
|
|||
("bpy.types.movietrackingcamera.distortion_model*", "movie_clip/tracking/clip/sidebar/track/camera.html#bpy-types-movietrackingcamera-distortion-model"),
|
||||
("bpy.types.movietrackingtrack.use_alpha_preview*", "movie_clip/tracking/clip/sidebar/track/track.html#bpy-types-movietrackingtrack-use-alpha-preview"),
|
||||
("bpy.types.movietrackingtrack.use_green_channel*", "movie_clip/tracking/clip/sidebar/track/track.html#bpy-types-movietrackingtrack-use-green-channel"),
|
||||
("bpy.types.preferencesfilepaths.sound_directory*", "editors/preferences/file_paths.html#bpy-types-preferencesfilepaths-sound-directory"),
|
||||
("bpy.types.preferencesinput.ndof_fly_helicopter*", "editors/preferences/input.html#bpy-types-preferencesinput-ndof-fly-helicopter"),
|
||||
("bpy.types.preferencessystem.anisotropic_filter*", "editors/preferences/viewport.html#bpy-types-preferencessystem-anisotropic-filter"),
|
||||
("bpy.types.preferencessystem.memory_cache_limit*", "editors/preferences/system.html#bpy-types-preferencessystem-memory-cache-limit"),
|
||||
("bpy.types.preferencessystem.use_region_overlap*", "editors/preferences/interface.html#bpy-types-preferencessystem-use-region-overlap"),
|
||||
("bpy.types.preferencesview.mini_axis_brightness*", "editors/preferences/viewport.html#bpy-types-preferencesview-mini-axis-brightness"),
|
||||
("bpy.types.preferencesview.playback_fps_samples*", "editors/preferences/viewport.html#bpy-types-preferencesview-playback-fps-samples"),
|
||||
("bpy.types.preferencesview.show_tooltips_python*", "editors/preferences/interface.html#bpy-types-preferencesview-show-tooltips-python"),
|
||||
("bpy.types.rendersettings.resolution_percentage*", "render/output/properties/format.html#bpy-types-rendersettings-resolution-percentage"),
|
||||
("bpy.types.rendersettings_simplify_gpencil_tint*", "render/cycles/render_settings/simplify.html#bpy-types-rendersettings-simplify-gpencil-tint"),
|
||||
("bpy.types.softbodysettings.use_estimate_matrix*", "physics/soft_body/settings/solver.html#bpy-types-softbodysettings-use-estimate-matrix"),
|
||||
|
@ -533,6 +634,22 @@ url_manual_mapping = (
|
|||
("bpy.types.nodetreeinterfacesocket.description*", "interface/controls/nodes/groups.html#bpy-types-nodetreeinterfacesocket-description"),
|
||||
("bpy.types.objectlineart.intersection_priority*", "scene_layout/object/properties/line_art.html#bpy-types-objectlineart-intersection-priority"),
|
||||
("bpy.types.particlesettings.use_modifier_stack*", "physics/particles/emitter/emission.html#bpy-types-particlesettings-use-modifier-stack"),
|
||||
("bpy.types.preferencesedit.key_insert_channels*", "editors/preferences/animation.html#bpy-types-preferencesedit-key-insert-channels"),
|
||||
("bpy.types.preferencesedit.use_enter_edit_mode*", "editors/preferences/editing.html#bpy-types-preferencesedit-use-enter-edit-mode"),
|
||||
("bpy.types.preferencesedit.use_negative_frames*", "editors/preferences/animation.html#bpy-types-preferencesedit-use-negative-frames"),
|
||||
("bpy.types.preferencesfilepaths.auto_save_time*", "editors/preferences/save_load.html#bpy-types-preferencesfilepaths-auto-save-time"),
|
||||
("bpy.types.preferencesfilepaths.font_directory*", "editors/preferences/file_paths.html#bpy-types-preferencesfilepaths-font-directory"),
|
||||
("bpy.types.preferencesinput.use_emulate_numpad*", "editors/preferences/input.html#bpy-types-preferencesinput-use-emulate-numpad"),
|
||||
("bpy.types.preferencesinput.view_rotate_method*", "editors/preferences/navigation.html#bpy-types-preferencesinput-view-rotate-method"),
|
||||
("bpy.types.preferencessystem.audio_sample_rate*", "editors/preferences/system.html#bpy-types-preferencessystem-audio-sample-rate"),
|
||||
("bpy.types.preferencessystem.image_draw_method*", "editors/preferences/viewport.html#bpy-types-preferencessystem-image-draw-method"),
|
||||
("bpy.types.preferencesview.factor_display_type*", "editors/preferences/interface.html#bpy-types-preferencesview-factor-display-type"),
|
||||
("bpy.types.preferencesview.lookdev_sphere_size*", "editors/preferences/viewport.html#bpy-types-preferencesview-lookdev-sphere-size"),
|
||||
("bpy.types.preferencesview.open_sublevel_delay*", "editors/preferences/interface.html#bpy-types-preferencesview-open-sublevel-delay"),
|
||||
("bpy.types.preferencesview.open_toplevel_delay*", "editors/preferences/interface.html#bpy-types-preferencesview-open-toplevel-delay"),
|
||||
("bpy.types.preferencesview.pie_initial_timeout*", "editors/preferences/interface.html#bpy-types-preferencesview-pie-initial-timeout"),
|
||||
("bpy.types.preferencesview.render_display_type*", "editors/preferences/interface.html#bpy-types-preferencesview-render-display-type"),
|
||||
("bpy.types.preferencesview.use_mouse_over_open*", "editors/preferences/interface.html#bpy-types-preferencesview-use-mouse-over-open"),
|
||||
("bpy.types.rendersettings.sequencer_gl_preview*", "editors/video_sequencer/preview/sidebar.html#bpy-types-rendersettings-sequencer-gl-preview"),
|
||||
("bpy.types.rendersettings.simplify_subdivision*", "render/cycles/render_settings/simplify.html#bpy-types-rendersettings-simplify-subdivision"),
|
||||
("bpy.types.rendersettings.use_simplify_normals*", "render/cycles/render_settings/simplify.html#bpy-types-rendersettings-use-simplify-normals"),
|
||||
|
@ -616,6 +733,14 @@ url_manual_mapping = (
|
|||
("bpy.types.nodetreeinterfacesocket*.min_value*", "interface/controls/nodes/groups.html#bpy-types-nodetreeinterfacesocket-min-value"),
|
||||
("bpy.types.nodetreeinterfacesocket.hide_value*", "interface/controls/nodes/groups.html#bpy-types-nodetreeinterfacesocket-hide-value"),
|
||||
("bpy.types.object.add_rest_position_attribute*", "animation/shape_keys/shape_keys_panel.html#bpy-types-object-add-rest-position-attribute"),
|
||||
("bpy.types.preferencesinput.invert_mouse_zoom*", "editors/preferences/navigation.html#bpy-types-preferencesinput-invert-mouse-zoom"),
|
||||
("bpy.types.preferencesinput.invert_zoom_wheel*", "editors/preferences/navigation.html#bpy-types-preferencesinput-invert-zoom-wheel"),
|
||||
("bpy.types.preferencesinput.ndof_lock_horizon*", "editors/preferences/input.html#bpy-types-preferencesinput-ndof-lock-horizon"),
|
||||
("bpy.types.preferencesinput.pressure_softness*", "editors/preferences/input.html#bpy-types-preferencesinput-pressure-softness"),
|
||||
("bpy.types.preferencesinput.use_zoom_to_mouse*", "editors/preferences/navigation.html#bpy-types-preferencesinput-use-zoom-to-mouse"),
|
||||
("bpy.types.preferencessystem.gl_texture_limit*", "editors/preferences/viewport.html#bpy-types-preferencessystem-gl-texture-limit"),
|
||||
("bpy.types.preferencessystem.texture_time_out*", "editors/preferences/system.html#bpy-types-preferencessystem-texture-time-out"),
|
||||
("bpy.types.preferencesview.pie_menu_threshold*", "editors/preferences/interface.html#bpy-types-preferencesview-pie-menu-threshold"),
|
||||
("bpy.types.rendersettings.line_thickness_mode*", "render/freestyle/render.html#bpy-types-rendersettings-line-thickness-mode"),
|
||||
("bpy.types.rendersettings.motion_blur_shutter*", "render/cycles/render_settings/motion_blur.html#bpy-types-rendersettings-motion-blur-shutter"),
|
||||
("bpy.types.rendersettings.use_persistent_data*", "render/cycles/render_settings/performance.html#bpy-types-rendersettings-use-persistent-data"),
|
||||
|
@ -638,6 +763,7 @@ url_manual_mapping = (
|
|||
("bpy.types.toolsettings.use_proportional_edit*", "editors/3dview/controls/proportional_editing.html#bpy-types-toolsettings-use-proportional-edit"),
|
||||
("bpy.types.toolsettings.uv_sticky_select_mode*", "editors/uv/selecting.html#bpy-types-toolsettings-uv-sticky-select-mode"),
|
||||
("bpy.types.transformsequence.translation_unit*", "video_editing/edit/montage/strips/effects/transform.html#bpy-types-transformsequence-translation-unit"),
|
||||
("bpy.types.userassetlibrary.use_relative_path*", "editors/preferences/file_paths.html#bpy-types-userassetlibrary-use-relative-path"),
|
||||
("bpy.types.view3dshading.wireframe_color_type*", "editors/3dview/display/shading.html#bpy-types-view3dshading-wireframe-color-type"),
|
||||
("bpy.types.volumedisplay.interpolation_method*", "modeling/volumes/properties.html#bpy-types-volumedisplay-interpolation-method"),
|
||||
("bpy.ops.armature.collection_solo_visibility*", "animation/armatures/properties/bone_collections.html#bpy-ops-armature-collection-solo-visibility"),
|
||||
|
@ -683,6 +809,18 @@ url_manual_mapping = (
|
|||
("bpy.types.materiallineart.use_material_mask*", "render/materials/line_art.html#bpy-types-materiallineart-use-material-mask"),
|
||||
("bpy.types.movietracking.active_object_index*", "movie_clip/tracking/clip/sidebar/track/objects.html#bpy-types-movietracking-active-object-index"),
|
||||
("bpy.types.objectlineart.use_crease_override*", "scene_layout/object/properties/line_art.html#bpy-types-objectlineart-use-crease-override"),
|
||||
("bpy.types.preferencesedit.undo_memory_limit*", "editors/preferences/system.html#bpy-types-preferencesedit-undo-memory-limit"),
|
||||
("bpy.types.preferencesedit.use_visual_keying*", "editors/preferences/animation.html#bpy-types-preferencesedit-use-visual-keying"),
|
||||
("bpy.types.preferencesfilepaths.image_editor*", "editors/preferences/file_paths.html#bpy-types-preferencesfilepaths-image-editor"),
|
||||
("bpy.types.preferencesfilepaths.recent_files*", "editors/preferences/save_load.html#bpy-types-preferencesfilepaths-recent-files"),
|
||||
("bpy.types.preferencesfilepaths.save_version*", "editors/preferences/save_load.html#bpy-types-preferencesfilepaths-save-version"),
|
||||
("bpy.types.preferencesinput.ndof_sensitivity*", "editors/preferences/input.html#bpy-types-preferencesinput-ndof-sensitivity"),
|
||||
("bpy.types.preferencesinput.ndof_zoom_invert*", "editors/preferences/input.html#bpy-types-preferencesinput-ndof-zoom-invert"),
|
||||
("bpy.types.preferencesinput.view_zoom_method*", "editors/preferences/navigation.html#bpy-types-preferencesinput-view-zoom-method"),
|
||||
("bpy.types.preferencesview.color_picker_type*", "editors/preferences/interface.html#bpy-types-preferencesview-color-picker-type"),
|
||||
("bpy.types.preferencesview.font_path_ui_mono*", "editors/preferences/interface.html#bpy-types-preferencesview-font-path-ui-mono"),
|
||||
("bpy.types.preferencesview.show_developer_ui*", "editors/preferences/interface.html#bpy-types-preferencesview-show-developer-ui"),
|
||||
("bpy.types.preferencesview.show_playback_fps*", "editors/preferences/viewport.html#bpy-types-preferencesview-show-playback-fps"),
|
||||
("bpy.types.rendersettings.preview_pixel_size*", "render/cycles/render_settings/performance.html#bpy-types-rendersettings-preview-pixel-size"),
|
||||
("bpy.types.rendersettings.use_crop_to_border*", "render/output/properties/format.html#bpy-types-rendersettings-use-crop-to-border"),
|
||||
("bpy.types.rendersettings.use_file_extension*", "render/output/properties/output.html#bpy-types-rendersettings-use-file-extension"),
|
||||
|
@ -775,6 +913,15 @@ url_manual_mapping = (
|
|||
("bpy.types.movietrackingcamera.pixel_aspect*", "movie_clip/tracking/clip/sidebar/track/camera.html#bpy-types-movietrackingcamera-pixel-aspect"),
|
||||
("bpy.types.movietrackingcamera.sensor_width*", "movie_clip/tracking/clip/sidebar/track/camera.html#bpy-types-movietrackingcamera-sensor-width"),
|
||||
("bpy.types.posebone.use_ik_rotation_control*", "animation/armatures/posing/bone_constraints/inverse_kinematics/introduction.html#bpy-types-posebone-use-ik-rotation-control"),
|
||||
("bpy.types.preferencesfilepaths.text_editor*", "editors/preferences/file_paths.html#bpy-types-preferencesfilepaths-text-editor"),
|
||||
("bpy.types.preferencesfilepaths.use_load_ui*", "editors/preferences/save_load.html#bpy-types-preferencesfilepaths-use-load-ui"),
|
||||
("bpy.types.preferencesinput.navigation_mode*", "editors/preferences/navigation.html#bpy-types-preferencesinput-navigation-mode"),
|
||||
("bpy.types.preferencesinput.ndof_show_guide*", "editors/preferences/input.html#bpy-types-preferencesinput-ndof-show-guide"),
|
||||
("bpy.types.preferencessystem.audio_channels*", "editors/preferences/system.html#bpy-types-preferencessystem-audio-channels"),
|
||||
("bpy.types.preferencesview.pie_menu_confirm*", "editors/preferences/interface.html#bpy-types-preferencesview-pie-menu-confirm"),
|
||||
("bpy.types.preferencesview.show_navigate_ui*", "editors/preferences/interface.html#bpy-types-preferencesview-show-navigate-ui"),
|
||||
("bpy.types.preferencesview.show_object_info*", "editors/preferences/viewport.html#bpy-types-preferencesview-show-object-info"),
|
||||
("bpy.types.preferencesview.use_fresnel_edit*", "editors/preferences/viewport.html#bpy-types-preferencesview-use-fresnel-edit"),
|
||||
("bpy.types.rendersettings.use_bake_multires*", "render/cycles/baking.html#bpy-types-rendersettings-use-bake-multires"),
|
||||
("bpy.types.rigidbodyobject.collision_margin*", "physics/rigid_body/properties/collisions.html#bpy-types-rigidbodyobject-collision-margin"),
|
||||
("bpy.types.scenegpencil.antialias_threshold*", "render/cycles/render_settings/grease_pencil.html#bpy-types-scenegpencil-antialias-threshold"),
|
||||
|
@ -788,10 +935,13 @@ url_manual_mapping = (
|
|||
("bpy.types.spacenodeoverlay.show_wire_color*", "interface/controls/nodes/introduction.html#bpy-types-spacenodeoverlay-show-wire-color"),
|
||||
("bpy.types.spacesequenceeditor.display_mode*", "editors/video_sequencer/preview/display/display_mode.html#bpy-types-spacesequenceeditor-display-mode"),
|
||||
("bpy.types.spaceview3d.show_object_viewport*", "editors/3dview/display/visibility.html#bpy-types-spaceview3d-show-object-viewport"),
|
||||
("bpy.types.toolsettings.use_record_with_nla*", "editors/timeline.html#bpy-types-toolsettings-use-record-with-nla"),
|
||||
("bpy.types.toolsettings.use_snap_selectable*", "editors/3dview/controls/snapping.html#bpy-types-toolsettings-use-snap-selectable"),
|
||||
("bpy.types.transformsequence.rotation_start*", "video_editing/edit/montage/strips/effects/transform.html#bpy-types-transformsequence-rotation-start"),
|
||||
("bpy.types.view3doverlay.show_fade_inactive*", "editors/3dview/display/overlays.html#bpy-types-view3doverlay-show-fade-inactive"),
|
||||
("bpy.types.viewlayer.pass_cryptomatte_depth*", "render/layers/passes.html#bpy-types-viewlayer-pass-cryptomatte-depth"),
|
||||
("bpy.types.walknavigation.use_mouse_reverse*", "editors/preferences/navigation.html#bpy-types-walknavigation-use-mouse-reverse"),
|
||||
("bpy.types.walknavigation.walk_speed_factor*", "editors/preferences/navigation.html#bpy-types-walknavigation-walk-speed-factor"),
|
||||
("bpy.ops.clip.stabilize_2d_rotation_select*", "movie_clip/tracking/clip/selecting.html#bpy-ops-clip-stabilize-2d-rotation-select"),
|
||||
("bpy.ops.constraint.disable_keep_transform*", "animation/constraints/interface/common.html#bpy-ops-constraint-disable-keep-transform"),
|
||||
("bpy.ops.curves.convert_to_particle_system*", "sculpt_paint/curves_sculpting/introduction.html#bpy-ops-curves-convert-to-particle-system"),
|
||||
|
@ -862,6 +1012,18 @@ url_manual_mapping = (
|
|||
("bpy.types.materialgpencilstyle.fill_style*", "grease_pencil/materials/properties.html#bpy-types-materialgpencilstyle-fill-style"),
|
||||
("bpy.types.materialgpencilstyle.mix_factor*", "grease_pencil/materials/properties.html#bpy-types-materialgpencilstyle-mix-factor"),
|
||||
("bpy.types.materialgpencilstyle.pass_index*", "grease_pencil/materials/properties.html#bpy-types-materialgpencilstyle-pass-index"),
|
||||
("bpy.types.preferences.use_recent_searches*", "editors/preferences/interface.html#bpy-types-preferences-use-recent-searches"),
|
||||
("bpy.types.preferencesedit.use_auto_keying*", "editors/preferences/animation.html#bpy-types-preferencesedit-use-auto-keying"),
|
||||
("bpy.types.preferencesedit.use_global_undo*", "editors/preferences/system.html#bpy-types-preferencesedit-use-global-undo"),
|
||||
("bpy.types.preferencesinput.drag_threshold*", "editors/preferences/input.html#bpy-types-preferencesinput-drag-threshold"),
|
||||
("bpy.types.preferencesinput.move_threshold*", "editors/preferences/input.html#bpy-types-preferencesinput-move-threshold"),
|
||||
("bpy.types.preferencesinput.view_zoom_axis*", "editors/preferences/navigation.html#bpy-types-preferencesinput-view-zoom-axis"),
|
||||
("bpy.types.preferencessystem.gl_clip_alpha*", "editors/preferences/viewport.html#bpy-types-preferencessystem-gl-clip-alpha"),
|
||||
("bpy.types.preferencessystem.light_ambient*", "editors/preferences/lights.html#bpy-types-preferencessystem-light-ambient"),
|
||||
("bpy.types.preferencesview.pie_menu_radius*", "editors/preferences/interface.html#bpy-types-preferencesview-pie-menu-radius"),
|
||||
("bpy.types.preferencesview.pie_tap_timeout*", "editors/preferences/interface.html#bpy-types-preferencesview-pie-tap-timeout"),
|
||||
("bpy.types.preferencesview.use_save_prompt*", "editors/preferences/save_load.html#bpy-types-preferencesview-use-save-prompt"),
|
||||
("bpy.types.preferencesview.view_frame_type*", "editors/preferences/animation.html#bpy-types-preferencesview-view-frame-type"),
|
||||
("bpy.types.rendersettings.dither_intensity*", "render/output/properties/post_processing.html#bpy-types-rendersettings-dither-intensity"),
|
||||
("bpy.types.rendersettings.film_transparent*", "render/cycles/render_settings/film.html#bpy-types-rendersettings-film-transparent"),
|
||||
("bpy.types.rendersettings.simplify_volumes*", "render/cycles/render_settings/simplify.html#bpy-types-rendersettings-simplify-volumes"),
|
||||
|
@ -952,6 +1114,7 @@ url_manual_mapping = (
|
|||
("bpy.types.greasepencil.use_ghosts_always*", "grease_pencil/properties/onion_skinning.html#bpy-types-greasepencil-use-ghosts-always"),
|
||||
("bpy.types.imageformatsettings.color_mode*", "render/output/properties/output.html#bpy-types-imageformatsettings-color-mode"),
|
||||
("bpy.types.imagetexture.use_interpolation*", "render/materials/legacy_textures/types/image_movie.html#bpy-types-imagetexture-use-interpolation"),
|
||||
("bpy.types.keyingsetpath.use_entire_array*", "animation/keyframes/keying_sets.html#bpy-types-keyingsetpath-use-entire-array"),
|
||||
("bpy.types.linestyle*modifier_alongstroke*", "render/freestyle/view_layer/line_style/modifiers/color/along_stroke.html#bpy-types-linestyle-modifier-alongstroke"),
|
||||
("bpy.types.linestyle*modifier_creaseangle*", "render/freestyle/view_layer/line_style/modifiers/color/crease_angle.html#bpy-types-linestyle-modifier-creaseangle"),
|
||||
("bpy.types.linestylecolormodifier_tangent*", "render/freestyle/view_layer/line_style/modifiers/color/tangent.html#bpy-types-linestylecolormodifier-tangent"),
|
||||
|
@ -966,6 +1129,13 @@ url_manual_mapping = (
|
|||
("bpy.types.movietrackingtrack.weight_stab*", "movie_clip/tracking/clip/sidebar/track/track.html#bpy-types-movietrackingtrack-weight-stab"),
|
||||
("bpy.types.object.use_shape_key_edit_mode*", "animation/shape_keys/shape_keys_panel.html#bpy-types-object-use-shape-key-edit-mode"),
|
||||
("bpy.types.objectlineart.crease_threshold*", "scene_layout/object/properties/line_art.html#bpy-types-objectlineart-crease-threshold"),
|
||||
("bpy.types.preferencesinput.ndof_deadzone*", "editors/preferences/input.html#bpy-types-preferencesinput-ndof-deadzone"),
|
||||
("bpy.types.preferencessystem.audio_device*", "editors/preferences/system.html#bpy-types-preferencessystem-audio-device"),
|
||||
("bpy.types.preferencessystem.vbo_time_out*", "editors/preferences/system.html#bpy-types-preferencessystem-vbo-time-out"),
|
||||
("bpy.types.preferencesview.mini_axis_type*", "editors/preferences/viewport.html#bpy-types-preferencesview-mini-axis-type"),
|
||||
("bpy.types.preferencesview.rotation_angle*", "editors/preferences/navigation.html#bpy-types-preferencesview-rotation-angle"),
|
||||
("bpy.types.preferencesview.show_view_name*", "editors/preferences/viewport.html#bpy-types-preferencesview-show-view-name"),
|
||||
("bpy.types.preferencesview.timecode_style*", "editors/preferences/animation.html#bpy-types-preferencesview-timecode-style"),
|
||||
("bpy.types.rendersettings.use_compositing*", "render/output/properties/post_processing.html#bpy-types-rendersettings-use-compositing"),
|
||||
("bpy.types.rendersettings.use_motion_blur*", "render/cycles/render_settings/motion_blur.html#bpy-types-rendersettings-use-motion-blur"),
|
||||
("bpy.types.rendersettings.use_placeholder*", "render/output/properties/output.html#bpy-types-rendersettings-use-placeholder"),
|
||||
|
@ -986,6 +1156,7 @@ url_manual_mapping = (
|
|||
("bpy.types.toolsettings.snap_anim_element*", "editors/graph_editor/introduction.html#bpy-types-toolsettings-snap-anim-element"),
|
||||
("bpy.types.toolsettings.use_lock_relative*", "sculpt_paint/weight_paint/tool_settings/options.html#bpy-types-toolsettings-use-lock-relative"),
|
||||
("bpy.types.toolsettings.vertex_group_user*", "editors/3dview/display/overlays.html#bpy-types-toolsettings-vertex-group-user"),
|
||||
("bpy.types.userassetlibrary.import_method*", "editors/preferences/file_paths.html#bpy-types-userassetlibrary-import-method"),
|
||||
("bpy.types.vertexpaint.use_group_restrict*", "sculpt_paint/weight_paint/tool_settings/options.html#bpy-types-vertexpaint-use-group-restrict"),
|
||||
("bpy.types.volumedisplay.wireframe_detail*", "modeling/volumes/properties.html#bpy-types-volumedisplay-wireframe-detail"),
|
||||
("bpy.types.windowmanager.asset_path_dummy*", "editors/asset_browser.html#bpy-types-windowmanager-asset-path-dummy"),
|
||||
|
@ -1067,6 +1238,12 @@ url_manual_mapping = (
|
|||
("bpy.types.object.active_shape_key_index*", "animation/shape_keys/shape_keys_panel.html#bpy-types-object-active-shape-key-index"),
|
||||
("bpy.types.object.use_camera_lock_parent*", "scene_layout/object/properties/relations.html#bpy-types-object-use-camera-lock-parent"),
|
||||
("bpy.types.object.visible_volume_scatter*", "render/cycles/object_settings/object_data.html#bpy-types-object-visible-volume-scatter"),
|
||||
("bpy.types.preferencesedit.material_link*", "editors/preferences/editing.html#bpy-types-preferencesedit-material-link"),
|
||||
("bpy.types.preferencesedit.use_duplicate*", "editors/preferences/editing.html#bpy-types-preferencesedit-use-duplicate"),
|
||||
("bpy.types.preferencessystem.viewport_aa*", "editors/preferences/viewport.html#bpy-types-preferencessystem-viewport-aa"),
|
||||
("bpy.types.preferencesview.show_tooltips*", "editors/preferences/interface.html#bpy-types-preferencesview-show-tooltips"),
|
||||
("bpy.types.preferencesview.ui_line_width*", "editors/preferences/interface.html#bpy-types-preferencesview-ui-line-width"),
|
||||
("bpy.types.preferencesview.use_translate*", "editors/preferences/interface.html#bpy-types-preferencesview-use-translate"),
|
||||
("bpy.types.rendersettings.line_thickness*", "render/freestyle/render.html#bpy-types-rendersettings-line-thickness"),
|
||||
("bpy.types.rendersettings.pixel_aspect_x*", "render/output/properties/format.html#bpy-types-rendersettings-pixel-aspect-x"),
|
||||
("bpy.types.rendersettings.pixel_aspect_y*", "render/output/properties/format.html#bpy-types-rendersettings-pixel-aspect-y"),
|
||||
|
@ -1086,6 +1263,7 @@ url_manual_mapping = (
|
|||
("bpy.types.spaceuveditor.tile_grid_shape*", "editors/uv/overlays.html#bpy-types-spaceuveditor-tile-grid-shape"),
|
||||
("bpy.types.spaceuveditor.use_live_unwrap*", "modeling/meshes/uv/editing.html#bpy-types-spaceuveditor-use-live-unwrap"),
|
||||
("bpy.types.spaceview3d.use_render_border*", "editors/3dview/sidebar.html#bpy-types-spaceview3d-use-render-border"),
|
||||
("bpy.types.toolsettings.auto_keying_mode*", "editors/timeline.html#bpy-types-toolsettings-auto-keying-mode"),
|
||||
("bpy.types.toolsettings.double_threshold*", "modeling/meshes/tools/tool_settings.html#bpy-types-toolsettings-double-threshold"),
|
||||
("bpy.types.toolsettings.lock_object_mode*", "interface/window_system/topbar.html#bpy-types-toolsettings-lock-object-mode"),
|
||||
("bpy.types.toolsettings.mesh_select_mode*", "modeling/meshes/selecting/introduction.html#bpy-types-toolsettings-mesh-select-mode"),
|
||||
|
@ -1093,6 +1271,7 @@ url_manual_mapping = (
|
|||
("bpy.types.transformorientationslot.type*", "editors/3dview/controls/orientation.html#bpy-types-transformorientationslot-type"),
|
||||
("bpy.types.transformsequence.scale_start*", "video_editing/edit/montage/strips/effects/transform.html#bpy-types-transformsequence-scale-start"),
|
||||
("bpy.types.unitsettings.temperature_unit*", "scene_layout/scene/properties.html#bpy-types-unitsettings-temperature-unit"),
|
||||
("bpy.types.usersolidlight.specular_color*", "editors/preferences/lights.html#bpy-types-usersolidlight-specular-color"),
|
||||
("bpy.types.vertexweightproximitymodifier*", "modeling/modifiers/modify/weight_proximity.html#bpy-types-vertexweightproximitymodifier"),
|
||||
("bpy.types.view3doverlay.bone_wire_alpha*", "editors/3dview/display/overlays.html#bpy-types-view3doverlay-bone-wire-alpha"),
|
||||
("bpy.types.view3doverlay.show_retopology*", "editors/3dview/display/overlays.html#bpy-types-view3doverlay-show-retopology"),
|
||||
|
@ -1159,6 +1338,11 @@ url_manual_mapping = (
|
|||
("bpy.types.movietrackingplanetrack.name*", "movie_clip/tracking/clip/sidebar/track/plane_track.html#bpy-types-movietrackingplanetrack-name"),
|
||||
("bpy.types.nodetreeinterfacesocket.name*", "interface/controls/nodes/groups.html#bpy-types-nodetreeinterfacesocket-name"),
|
||||
("bpy.types.object.use_empty_image_alpha*", "modeling/empties.html#bpy-types-object-use-empty-image-alpha"),
|
||||
("bpy.types.preferencesedit.object_align*", "editors/preferences/editing.html#bpy-types-preferencesedit-object-align"),
|
||||
("bpy.types.preferencessystem.scrollback*", "editors/preferences/system.html#bpy-types-preferencessystem-scrollback"),
|
||||
("bpy.types.preferencesview.font_path_ui*", "editors/preferences/interface.html#bpy-types-preferencesview-font-path-ui"),
|
||||
("bpy.types.preferencesview.header_align*", "editors/preferences/interface.html#bpy-types-preferencesview-header-align"),
|
||||
("bpy.types.preferencesview.text_hinting*", "editors/preferences/interface.html#bpy-types-preferencesview-text-hinting"),
|
||||
("bpy.types.rendersettings.frame_map_new*", "render/output/properties/frame_range.html#bpy-types-rendersettings-frame-map-new"),
|
||||
("bpy.types.rendersettings.frame_map_old*", "render/output/properties/frame_range.html#bpy-types-rendersettings-frame-map-old"),
|
||||
("bpy.types.rendersettings.use_auto_tile*", "render/cycles/render_settings/performance.html#bpy-types-rendersettings-use-auto-tile"),
|
||||
|
@ -1189,8 +1373,10 @@ url_manual_mapping = (
|
|||
("bpy.types.toolsettings.use_snap_rotate*", "editors/3dview/controls/snapping.html#bpy-types-toolsettings-use-snap-rotate"),
|
||||
("bpy.types.toolsettings.uv_relax_method*", "modeling/meshes/uv/tools/relax.html#bpy-types-toolsettings-uv-relax-method"),
|
||||
("bpy.types.unitsettings.system_rotation*", "scene_layout/scene/properties.html#bpy-types-unitsettings-system-rotation"),
|
||||
("bpy.types.usersolidlight.diffuse_color*", "editors/preferences/lights.html#bpy-types-usersolidlight-diffuse-color"),
|
||||
("bpy.types.view3doverlay.display_handle*", "editors/3dview/display/overlays.html#bpy-types-view3doverlay-display-handle"),
|
||||
("bpy.types.volumedisplay.wireframe_type*", "modeling/volumes/properties.html#bpy-types-volumedisplay-wireframe-type"),
|
||||
("bpy.types.walknavigation.teleport_time*", "editors/preferences/navigation.html#bpy-types-walknavigation-teleport-time"),
|
||||
("bpy.ops.anim.channels_editable_toggle*", "editors/graph_editor/channels/editing.html#bpy-ops-anim-channels-editable-toggle"),
|
||||
("bpy.ops.anim.channels_setting_disable*", "editors/graph_editor/channels/editing.html#bpy-ops-anim-channels-setting-disable"),
|
||||
("bpy.ops.brush.stencil_reset_transform*", "sculpt_paint/brush/texture.html#bpy-ops-brush-stencil-reset-transform"),
|
||||
|
@ -1279,6 +1465,7 @@ url_manual_mapping = (
|
|||
("bpy.types.greasepencil.use_onion_fade*", "grease_pencil/properties/onion_skinning.html#bpy-types-greasepencil-use-onion-fade"),
|
||||
("bpy.types.greasepencil.use_onion_loop*", "grease_pencil/properties/onion_skinning.html#bpy-types-greasepencil-use-onion-loop"),
|
||||
("bpy.types.imagepaint.screen_grab_size*", "sculpt_paint/texture_paint/tool_settings/options.html#bpy-types-imagepaint-screen-grab-size"),
|
||||
("bpy.types.keyingsetpaths.active_index*", "animation/keyframes/keying_sets.html#bpy-types-keyingsetpaths-active-index"),
|
||||
("bpy.types.linestyle*modifier_material*", "render/freestyle/view_layer/line_style/modifiers/color/material.html#bpy-types-linestyle-modifier-material"),
|
||||
("bpy.types.motionpath.use_custom_color*", "animation/motion_paths.html#bpy-types-motionpath-use-custom-color"),
|
||||
("bpy.types.movietrackingcamera.brown_k*", "movie_clip/tracking/clip/sidebar/track/camera.html#bpy-types-movietrackingcamera-brown-k"),
|
||||
|
@ -1288,6 +1475,10 @@ url_manual_mapping = (
|
|||
("bpy.types.particlesettingstextureslot*", "physics/particles/texture_influence.html#bpy-types-particlesettingstextureslot"),
|
||||
("bpy.types.pointlight.shadow_soft_size*", "render/lights/light_object.html#bpy-types-pointlight-shadow-soft-size"),
|
||||
("bpy.types.posebone.ik_rotation_weight*", "animation/armatures/posing/bone_constraints/inverse_kinematics/introduction.html#bpy-types-posebone-ik-rotation-weight"),
|
||||
("bpy.types.preferencesedit.node_margin*", "editors/preferences/editing.html#bpy-types-preferencesedit-node-margin"),
|
||||
("bpy.types.preferencesinput.tablet_api*", "editors/preferences/input.html#bpy-types-preferencesinput-tablet-api"),
|
||||
("bpy.types.preferencesview.show_splash*", "editors/preferences/interface.html#bpy-types-preferencesview-show-splash"),
|
||||
("bpy.types.preferencesview.smooth_view*", "editors/preferences/navigation.html#bpy-types-preferencesview-smooth-view"),
|
||||
("bpy.types.regionview3d.show_sync_view*", "editors/3dview/navigate/views.html#bpy-types-regionview3d-show-sync-view"),
|
||||
("bpy.types.rendersettings.resolution_x*", "render/output/properties/format.html#bpy-types-rendersettings-resolution-x"),
|
||||
("bpy.types.rendersettings.resolution_y*", "render/output/properties/format.html#bpy-types-rendersettings-resolution-y"),
|
||||
|
@ -1336,6 +1527,8 @@ url_manual_mapping = (
|
|||
("bpy.ops.object.parent_no_inverse_set*", "scene_layout/object/editing/parent.html#bpy-ops-object-parent-no-inverse-set"),
|
||||
("bpy.ops.object.vertex_group_quantize*", "sculpt_paint/weight_paint/editing.html#bpy-ops-object-vertex-group-quantize"),
|
||||
("bpy.ops.outliner.collection_instance*", "editors/outliner/editing.html#bpy-ops-outliner-collection-instance"),
|
||||
("bpy.ops.preferences.keyconfig_export*", "editors/preferences/keymap.html#bpy-ops-preferences-keyconfig-export"),
|
||||
("bpy.ops.preferences.keyconfig_import*", "editors/preferences/keymap.html#bpy-ops-preferences-keyconfig-import"),
|
||||
("bpy.ops.sequencer.change_effect_type*", "video_editing/edit/montage/editing.html#bpy-ops-sequencer-change-effect-type"),
|
||||
("bpy.ops.transform.create_orientation*", "editors/3dview/controls/orientation.html#bpy-ops-transform-create-orientation"),
|
||||
("bpy.ops.transform.delete_orientation*", "editors/3dview/controls/orientation.html#bpy-ops-transform-delete-orientation"),
|
||||
|
@ -1391,11 +1584,14 @@ url_manual_mapping = (
|
|||
("bpy.types.greasepencil.use_multiedit*", "grease_pencil/multiframe.html#bpy-types-greasepencil-use-multiedit"),
|
||||
("bpy.types.imagetexture.use_flip_axis*", "render/materials/legacy_textures/types/image_movie.html#bpy-types-imagetexture-use-flip-axis"),
|
||||
("bpy.types.keyframe.handle_right_type*", "editors/graph_editor/fcurves/properties.html#bpy-types-keyframe-handle-right-type"),
|
||||
("bpy.types.keyingsetpath.group_method*", "animation/keyframes/keying_sets.html#bpy-types-keyingsetpath-group-method"),
|
||||
("bpy.types.materialgpencilstyle.color*", "grease_pencil/materials/properties.html#bpy-types-materialgpencilstyle-color"),
|
||||
("bpy.types.movietrackingcamera.nuke_k*", "movie_clip/tracking/clip/sidebar/track/camera.html#bpy-types-movietrackingcamera-nuke-k"),
|
||||
("bpy.types.movietrackingstabilization*", "movie_clip/tracking/clip/sidebar/stabilization/index.html#bpy-types-movietrackingstabilization"),
|
||||
("bpy.types.object.display_bounds_type*", "scene_layout/object/properties/display.html#bpy-types-object-display-bounds-type"),
|
||||
("bpy.types.object.show_only_shape_key*", "animation/shape_keys/shape_keys_panel.html#bpy-types-object-show-only-shape-key"),
|
||||
("bpy.types.preferencesedit.undo_steps*", "editors/preferences/system.html#bpy-types-preferencesedit-undo-steps"),
|
||||
("bpy.types.preferencesview.gizmo_size*", "editors/preferences/viewport.html#bpy-types-preferencesview-gizmo-size"),
|
||||
("bpy.types.regionview3d.lock_rotation*", "editors/3dview/navigate/views.html#bpy-types-regionview3d-lock-rotation"),
|
||||
("bpy.types.rendersettings.hair_subdiv*", "render/eevee/render_settings/hair.html#bpy-types-rendersettings-hair-subdiv"),
|
||||
("bpy.types.rigidbodyobject.use_deform*", "physics/rigid_body/properties/collisions.html#bpy-types-rigidbodyobject-use-deform"),
|
||||
|
@ -1422,7 +1618,12 @@ url_manual_mapping = (
|
|||
("bpy.types.toolsettings.use_snap_node*", "interface/controls/nodes/arranging.html#bpy-types-toolsettings-use-snap-node"),
|
||||
("bpy.types.toolsettings.use_snap_self*", "editors/3dview/controls/snapping.html#bpy-types-toolsettings-use-snap-self"),
|
||||
("bpy.types.viewlayer.active_aov_index*", "render/layers/passes.html#bpy-types-viewlayer-active-aov-index"),
|
||||
("bpy.types.walknavigation.jump_height*", "editors/preferences/navigation.html#bpy-types-walknavigation-jump-height"),
|
||||
("bpy.types.walknavigation.mouse_speed*", "editors/preferences/navigation.html#bpy-types-walknavigation-mouse-speed"),
|
||||
("bpy.types.walknavigation.use_gravity*", "editors/preferences/navigation.html#bpy-types-walknavigation-use-gravity"),
|
||||
("bpy.types.walknavigation.view_height*", "editors/preferences/navigation.html#bpy-types-walknavigation-view-height"),
|
||||
("bpy.ops.anim.channels_view_selected*", "editors/graph_editor/channels/editing.html#bpy-ops-anim-channels-view-selected"),
|
||||
("bpy.ops.anim.keying_set_path_remove*", "animation/keyframes/keying_sets.html#bpy-ops-anim-keying-set-path-remove"),
|
||||
("bpy.ops.armature.move_to_collection*", "animation/armatures/properties/bone_collections.html#bpy-ops-armature-move-to-collection"),
|
||||
("bpy.ops.clip.tracking_object_remove*", "movie_clip/tracking/clip/sidebar/track/objects.html#bpy-ops-clip-tracking-object-remove"),
|
||||
("bpy.ops.constraint.copy_to_selected*", "animation/constraints/interface/header.html#bpy-ops-constraint-copy-to-selected"),
|
||||
|
@ -1454,6 +1655,7 @@ url_manual_mapping = (
|
|||
("bpy.ops.outliner.collection_isolate*", "editors/outliner/editing.html#bpy-ops-outliner-collection-isolate"),
|
||||
("bpy.ops.pose.visual_transform_apply*", "animation/armatures/posing/editing/apply.html#bpy-ops-pose-visual-transform-apply"),
|
||||
("bpy.ops.poselib.convert_old_poselib*", "animation/armatures/posing/editing/pose_library.html#bpy-ops-poselib-convert-old-poselib"),
|
||||
("bpy.ops.preferences.studiolight_new*", "editors/preferences/lights.html#bpy-ops-preferences-studiolight-new"),
|
||||
("bpy.ops.render.shutter_curve_preset*", "render/cycles/render_settings/motion_blur.html#bpy-ops-render-shutter-curve-preset"),
|
||||
("bpy.ops.scene.view_layer_remove_aov*", "render/layers/passes.html#bpy-ops-scene-view-layer-remove-aov"),
|
||||
("bpy.ops.sculpt.project_line_gesture*", "sculpt_paint/sculpting/editing/sculpt.html#bpy-ops-sculpt-project-line-gesture"),
|
||||
|
@ -1497,7 +1699,7 @@ url_manual_mapping = (
|
|||
("bpy.types.freestylelineset.qi_start*", "render/freestyle/view_layer/line_set.html#bpy-types-freestylelineset-qi-start"),
|
||||
("bpy.types.freestylelinestyle.rounds*", "render/freestyle/view_layer/line_style/strokes.html#bpy-types-freestylelinestyle-rounds"),
|
||||
("bpy.types.functionnodereplacestring*", "modeling/geometry_nodes/utilities/text/replace_string.html#bpy-types-functionnodereplacestring"),
|
||||
("bpy.types.functionnodeseparatecolor*", "editors/texture_node/types/color/separate_color.html#bpy-types-functionnodeseparatecolor"),
|
||||
("bpy.types.functionnodeseparatecolor*", "modeling/geometry_nodes/utilities/color/separate_color.html#bpy-types-functionnodeseparatecolor"),
|
||||
("bpy.types.functionnodevaluetostring*", "modeling/geometry_nodes/utilities/text/value_to_string.html#bpy-types-functionnodevaluetostring"),
|
||||
("bpy.types.geometrynodeblurattribute*", "modeling/geometry_nodes/attribute/blur_attribute.html#bpy-types-geometrynodeblurattribute"),
|
||||
("bpy.types.geometrynodecornersofedge*", "modeling/geometry_nodes/mesh/topology/corners_of_edge.html#bpy-types-geometrynodecornersofedge"),
|
||||
|
@ -1566,7 +1768,9 @@ url_manual_mapping = (
|
|||
("bpy.types.view3doverlay.show_weight*", "editors/3dview/display/overlays.html#bpy-types-view3doverlay-show-weight"),
|
||||
("bpy.types.viewlayer.use_motion_blur*", "render/layers/introduction.html#bpy-types-viewlayer-use-motion-blur"),
|
||||
("bpy.types.volumedisplay.slice_depth*", "modeling/volumes/properties.html#bpy-types-volumedisplay-slice-depth"),
|
||||
("bpy.types.walknavigation.walk_speed*", "editors/preferences/navigation.html#bpy-types-walknavigation-walk-speed"),
|
||||
("bpy.types.worldmistsettings.falloff*", "render/cycles/world_settings.html#bpy-types-worldmistsettings-falloff"),
|
||||
("bpy.ops.anim.keying_set_active_set*", "animation/keyframes/keying_sets.html#bpy-ops-anim-keying-set-active-set"),
|
||||
("bpy.ops.armature.collection_assign*", "animation/armatures/properties/bone_collections.html#bpy-ops-armature-collection-assign"),
|
||||
("bpy.ops.armature.collection_select*", "animation/armatures/properties/bone_collections.html#bpy-ops-armature-collection-select"),
|
||||
("bpy.ops.clip.lock_selection_toggle*", "editors/clip/introduction.html#bpy-ops-clip-lock-selection-toggle"),
|
||||
|
@ -1663,6 +1867,7 @@ url_manual_mapping = (
|
|||
("bpy.types.imagepaint.interpolation*", "sculpt_paint/texture_paint/tool_settings/texture_slots.html#bpy-types-imagepaint-interpolation"),
|
||||
("bpy.types.imagetexture.filter_size*", "render/materials/legacy_textures/types/image_movie.html#bpy-types-imagetexture-filter-size"),
|
||||
("bpy.types.imagetexture.filter_type*", "render/materials/legacy_textures/types/image_movie.html#bpy-types-imagetexture-filter-type"),
|
||||
("bpy.types.keyingset.bl_description*", "animation/keyframes/keying_sets.html#bpy-types-keyingset-bl-description"),
|
||||
("bpy.types.linestyle*modifier_noise*", "render/freestyle/view_layer/line_style/modifiers/color/noise.html#bpy-types-linestyle-modifier-noise"),
|
||||
("bpy.types.maintainvolumeconstraint*", "animation/constraints/transform/maintain_volume.html#bpy-types-maintainvolumeconstraint"),
|
||||
("bpy.types.material.alpha_threshold*", "render/eevee/materials/settings.html#bpy-types-material-alpha-threshold"),
|
||||
|
@ -1671,6 +1876,8 @@ url_manual_mapping = (
|
|||
("bpy.types.movietrackingtrack.color*", "movie_clip/tracking/clip/sidebar/track/track.html#bpy-types-movietrackingtrack-color"),
|
||||
("bpy.types.object.is_shadow_catcher*", "render/cycles/object_settings/object_data.html#bpy-types-object-is-shadow-catcher"),
|
||||
("bpy.types.particleinstancemodifier*", "modeling/modifiers/physics/particle_instance.html#bpy-types-particleinstancemodifier"),
|
||||
("bpy.types.preferencesview.language*", "editors/preferences/interface.html#bpy-types-preferencesview-language"),
|
||||
("bpy.types.preferencesview.ui_scale*", "editors/preferences/interface.html#bpy-types-preferencesview-ui-scale"),
|
||||
("bpy.types.rendersettings.hair_type*", "render/eevee/render_settings/hair.html#bpy-types-rendersettings-hair-type"),
|
||||
("bpy.types.rendersettings.tile_size*", "render/cycles/render_settings/performance.html#bpy-types-rendersettings-tile-size"),
|
||||
("bpy.types.rigidbodyobject.friction*", "physics/rigid_body/properties/collisions.html#bpy-types-rigidbodyobject-friction"),
|
||||
|
@ -1696,12 +1903,14 @@ url_manual_mapping = (
|
|||
("bpy.types.toolsettings.snap_target*", "editors/3dview/controls/snapping.html#bpy-types-toolsettings-snap-target"),
|
||||
("bpy.types.transformcacheconstraint*", "animation/constraints/transform/transform_cache.html#bpy-types-transformcacheconstraint"),
|
||||
("bpy.types.unitsettings.length_unit*", "scene_layout/scene/properties.html#bpy-types-unitsettings-length-unit"),
|
||||
("bpy.types.usersolidlight.direction*", "editors/preferences/lights.html#bpy-types-usersolidlight-direction"),
|
||||
("bpy.types.vertexweighteditmodifier*", "modeling/modifiers/modify/weight_edit.html#bpy-types-vertexweighteditmodifier"),
|
||||
("bpy.types.view3dshading.color_type*", "render/workbench/color.html#bpy-types-view3dshading-color-type"),
|
||||
("bpy.types.volumedisplay.slice_axis*", "modeling/volumes/properties.html#bpy-types-volumedisplay-slice-axis"),
|
||||
("bpy.ops.action.markers_make_local*", "animation/markers.html#bpy-ops-action-markers-make-local"),
|
||||
("bpy.ops.anim.channels_clean_empty*", "editors/nla/editing.html#bpy-ops-anim-channels-clean-empty"),
|
||||
("bpy.ops.anim.driver_button_remove*", "animation/drivers/usage.html#bpy-ops-anim-driver-button-remove"),
|
||||
("bpy.ops.anim.keyframe_insert_menu*", "animation/keyframes/editing.html#bpy-ops-anim-keyframe-insert-menu"),
|
||||
("bpy.ops.anim.keyingset_button_add*", "animation/keyframes/keying_sets.html#bpy-ops-anim-keyingset-button-add"),
|
||||
("bpy.ops.armature.select_hierarchy*", "animation/armatures/bones/selecting.html#bpy-ops-armature-select-hierarchy"),
|
||||
("bpy.ops.armature.switch_direction*", "animation/armatures/bones/editing/switch_direction.html#bpy-ops-armature-switch-direction"),
|
||||
|
@ -1732,6 +1941,7 @@ url_manual_mapping = (
|
|||
("bpy.ops.paint.vertex_color_smooth*", "sculpt_paint/vertex_paint/editing.html#bpy-ops-paint-vertex-color-smooth"),
|
||||
("bpy.ops.paint.weight_sample_group*", "sculpt_paint/weight_paint/editing.html#bpy-ops-paint-weight-sample-group"),
|
||||
("bpy.ops.poselib.create_pose_asset*", "animation/armatures/posing/editing/pose_library.html#bpy-ops-poselib-create-pose-asset"),
|
||||
("bpy.ops.preferences.autoexec_path*", "editors/preferences/save_load.html#bpy-ops-preferences-autoexec-path"),
|
||||
("bpy.ops.preferences.theme_install*", "editors/preferences/themes.html#bpy-ops-preferences-theme-install"),
|
||||
("bpy.ops.render.play_rendered_anim*", "render/output/animation_player.html#bpy-ops-render-play-rendered-anim"),
|
||||
("bpy.ops.sculpt.set_pivot_position*", "sculpt_paint/sculpting/editing/sculpt.html#bpy-ops-sculpt-set-pivot-position"),
|
||||
|
@ -1813,6 +2023,9 @@ url_manual_mapping = (
|
|||
("bpy.types.greasepencilgrid.offset*", "grease_pencil/properties/display.html#bpy-types-greasepencilgrid-offset"),
|
||||
("bpy.types.imagepaint.normal_angle*", "sculpt_paint/brush/falloff.html#bpy-types-imagepaint-normal-angle"),
|
||||
("bpy.types.imagetexture.use_mipmap*", "render/materials/legacy_textures/types/image_movie.html#bpy-types-imagetexture-use-mipmap"),
|
||||
("bpy.types.keyingsetpath.data_path*", "animation/keyframes/keying_sets.html#bpy-types-keyingsetpath-data-path"),
|
||||
("bpy.types.keyingsets.active_index*", "animation/keyframes/keying_sets.html#bpy-types-keyingsets-active-index"),
|
||||
("bpy.types.keymapitem.key_modifier*", "editors/preferences/keymap.html#bpy-types-keymapitem-key-modifier"),
|
||||
("bpy.types.laplaciandeformmodifier*", "modeling/modifiers/deform/laplacian_deform.html#bpy-types-laplaciandeformmodifier"),
|
||||
("bpy.types.laplaciansmoothmodifier*", "modeling/modifiers/deform/laplacian_smooth.html#bpy-types-laplaciansmoothmodifier"),
|
||||
("bpy.types.layercollection.exclude*", "editors/outliner/interface.html#bpy-types-layercollection-exclude"),
|
||||
|
@ -1824,6 +2037,7 @@ url_manual_mapping = (
|
|||
("bpy.types.movietrackingtrack.lock*", "movie_clip/tracking/clip/sidebar/track/track.html#bpy-types-movietrackingtrack-lock"),
|
||||
("bpy.types.movietrackingtrack.name*", "movie_clip/tracking/clip/sidebar/track/track.html#bpy-types-movietrackingtrack-name"),
|
||||
("bpy.types.multiplygpencilmodifier*", "grease_pencil/modifiers/generate/multiple_strokes.html#bpy-types-multiplygpencilmodifier"),
|
||||
("bpy.types.preferencesexperimental*", "editors/preferences/experimental.html#bpy-types-preferencesexperimental"),
|
||||
("bpy.types.rendersettings.filepath*", "render/output/properties/output.html#bpy-types-rendersettings-filepath"),
|
||||
("bpy.types.rendersettings.fps_base*", "render/output/properties/format.html#bpy-types-rendersettings-fps-base"),
|
||||
("bpy.types.rigidbodyobject.enabled*", "physics/rigid_body/properties/settings.html#bpy-types-rigidbodyobject-enabled"),
|
||||
|
@ -1851,6 +2065,7 @@ url_manual_mapping = (
|
|||
("bpy.types.worldlighting.ao_factor*", "render/cycles/render_settings/light_paths.html#bpy-types-worldlighting-ao-factor"),
|
||||
("bpy.types.worldmistsettings.depth*", "render/cycles/world_settings.html#bpy-types-worldmistsettings-depth"),
|
||||
("bpy.types.worldmistsettings.start*", "render/cycles/world_settings.html#bpy-types-worldmistsettings-start"),
|
||||
("bpy.ops.anim.keying_set_path_add*", "animation/keyframes/keying_sets.html#bpy-ops-anim-keying-set-path-add"),
|
||||
("bpy.ops.clip.stabilize_2d_select*", "movie_clip/tracking/clip/selecting.html#bpy-ops-clip-stabilize-2d-select"),
|
||||
("bpy.ops.clip.tracking_object_new*", "movie_clip/tracking/clip/sidebar/track/objects.html#bpy-ops-clip-tracking-object-new"),
|
||||
("bpy.ops.constraint.move_to_index*", "animation/constraints/interface/header.html#bpy-ops-constraint-move-to-index"),
|
||||
|
@ -2129,6 +2344,7 @@ url_manual_mapping = (
|
|||
("bpy.types.gpencillayer.rotation*", "grease_pencil/properties/layers.html#bpy-types-gpencillayer-rotation"),
|
||||
("bpy.types.gpencilsculptsettings*", "grease_pencil/properties/index.html#bpy-types-gpencilsculptsettings"),
|
||||
("bpy.types.keyframe.handle_right*", "editors/graph_editor/fcurves/properties.html#bpy-types-keyframe-handle-right"),
|
||||
("bpy.types.keyingsetpath.id_type*", "animation/keyframes/keying_sets.html#bpy-types-keyingsetpath-id-type"),
|
||||
("bpy.types.lengthgpencilmodifier*", "grease_pencil/modifiers/generate/length.html#bpy-types-lengthgpencilmodifier"),
|
||||
("bpy.types.light.cutoff_distance*", "render/eevee/lighting.html#bpy-types-light-cutoff-distance"),
|
||||
("bpy.types.lockedtrackconstraint*", "animation/constraints/tracking/locked_track.html#bpy-types-lockedtrackconstraint"),
|
||||
|
@ -2172,6 +2388,7 @@ url_manual_mapping = (
|
|||
("bpy.types.surfacedeformmodifier*", "modeling/modifiers/deform/surface_deform.html#bpy-types-surfacedeformmodifier"),
|
||||
("bpy.types.texturenodetexvoronoi*", "editors/texture_node/types/textures/voronoi.html#bpy-types-texturenodetexvoronoi"),
|
||||
("bpy.types.toolsettings.use_snap*", "editors/3dview/controls/snapping.html#bpy-types-toolsettings-use-snap"),
|
||||
("bpy.types.usersolidlight.smooth*", "editors/preferences/lights.html#bpy-types-usersolidlight-smooth"),
|
||||
("bpy.types.viewlayer.use_volumes*", "render/layers/introduction.html#bpy-types-viewlayer-use-volumes"),
|
||||
("bpy.types.volume.frame_duration*", "modeling/volumes/properties.html#bpy-types-volume-frame-duration"),
|
||||
("bpy.types.volumedisplay.density*", "modeling/volumes/properties.html#bpy-types-volumedisplay-density"),
|
||||
|
@ -2179,6 +2396,8 @@ url_manual_mapping = (
|
|||
("bpy.types.workspace.object_mode*", "interface/window_system/workspaces.html#bpy-types-workspace-object-mode"),
|
||||
("bpy.ops.anim.channels_collapse*", "editors/graph_editor/channels/editing.html#bpy-ops-anim-channels-collapse"),
|
||||
("bpy.ops.anim.driver_button_add*", "animation/drivers/usage.html#bpy-ops-anim-driver-button-add"),
|
||||
("bpy.ops.anim.keying_set_export*", "animation/keyframes/keying_sets.html#bpy-ops-anim-keying-set-export"),
|
||||
("bpy.ops.anim.keying_set_remove*", "animation/keyframes/keying_sets.html#bpy-ops-anim-keying-set-remove"),
|
||||
("bpy.ops.armature.click_extrude*", "animation/armatures/bones/editing/extrude.html#bpy-ops-armature-click-extrude"),
|
||||
("bpy.ops.armature.select_linked*", "animation/armatures/bones/selecting.html#bpy-ops-armature-select-linked"),
|
||||
("bpy.ops.armature.select_mirror*", "animation/armatures/bones/selecting.html#bpy-ops-armature-select-mirror"),
|
||||
|
@ -2418,6 +2637,7 @@ url_manual_mapping = (
|
|||
("bpy.types.gpencillayer.parent*", "grease_pencil/properties/layers.html#bpy-types-gpencillayer-parent"),
|
||||
("bpy.types.hookgpencilmodifier*", "grease_pencil/modifiers/deform/hook.html#bpy-types-hookgpencilmodifier"),
|
||||
("bpy.types.imageformatsettings*", "files/media/image_formats.html#bpy-types-imageformatsettings"),
|
||||
("bpy.types.keymapitem.map_type*", "editors/preferences/keymap.html#bpy-types-keymapitem-map-type"),
|
||||
("bpy.types.kinematicconstraint*", "animation/constraints/tracking/ik_solver.html#bpy-types-kinematicconstraint"),
|
||||
("bpy.types.material.line_color*", "render/freestyle/material.html#bpy-types-material-line-color"),
|
||||
("bpy.types.material.pass_index*", "render/materials/settings.html#bpy-types-material-pass-index"),
|
||||
|
@ -2610,6 +2830,7 @@ url_manual_mapping = (
|
|||
("bpy.types.texturenodetexture*", "editors/texture_node/types/input/texture.html#bpy-types-texturenodetexture"),
|
||||
("bpy.types.texturenodetexwood*", "editors/texture_node/types/textures/wood.html#bpy-types-texturenodetexwood"),
|
||||
("bpy.types.textureslot.offset*", "sculpt_paint/brush/texture.html#bpy-types-textureslot-offset"),
|
||||
("bpy.types.usersolidlight.use*", "editors/preferences/lights.html#bpy-types-usersolidlight-use"),
|
||||
("bpy.types.view3dshading.type*", "editors/3dview/display/shading.html#bpy-types-view3dshading-type"),
|
||||
("bpy.types.volume.frame_start*", "modeling/volumes/properties.html#bpy-types-volume-frame-start"),
|
||||
("bpy.types.volume.is_sequence*", "modeling/volumes/properties.html#bpy-types-volume-is-sequence"),
|
||||
|
@ -2719,6 +2940,8 @@ url_manual_mapping = (
|
|||
("bpy.types.gpencillayer.lock*", "grease_pencil/properties/layers.html#bpy-types-gpencillayer-lock"),
|
||||
("bpy.types.image.seam_margin*", "editors/image/image_settings.html#bpy-types-image-seam-margin"),
|
||||
("bpy.types.imagepaint.dither*", "sculpt_paint/texture_paint/tool_settings/options.html#bpy-types-imagepaint-dither"),
|
||||
("bpy.types.keymapitem.active*", "editors/preferences/keymap.html#bpy-types-keymapitem-active"),
|
||||
("bpy.types.keymapitem.idname*", "editors/preferences/keymap.html#bpy-types-keymapitem-idname"),
|
||||
("bpy.types.material.metallic*", "render/materials/settings.html#bpy-types-material-metallic"),
|
||||
("bpy.types.materialslot.link*", "render/materials/assignment.html#bpy-types-materialslot-link"),
|
||||
("bpy.types.mesh.texture_mesh*", "modeling/meshes/uv/uv_texture_spaces.html#bpy-types-mesh-texture-mesh"),
|
||||
|
@ -2859,6 +3082,8 @@ url_manual_mapping = (
|
|||
("bpy.types.greasepencilgrid*", "grease_pencil/properties/display.html#bpy-types-greasepencilgrid"),
|
||||
("bpy.types.image.alpha_mode*", "editors/image/image_settings.html#bpy-types-image-alpha-mode"),
|
||||
("bpy.types.key.use_relative*", "animation/shape_keys/shape_keys_panel.html#bpy-types-key-use-relative"),
|
||||
("bpy.types.keyingsetpath.id*", "animation/keyframes/keying_sets.html#bpy-types-keyingsetpath-id"),
|
||||
("bpy.types.keymapitem.value*", "editors/preferences/keymap.html#bpy-types-keymapitem-value"),
|
||||
("bpy.types.mask.frame_start*", "movie_clip/masking/sidebar.html#bpy-types-mask-frame-start"),
|
||||
("bpy.types.motionpath.color*", "animation/motion_paths.html#bpy-types-motionpath-color"),
|
||||
("bpy.types.motionpath.lines*", "animation/motion_paths.html#bpy-types-motionpath-lines"),
|
||||
|
@ -2904,6 +3129,8 @@ url_manual_mapping = (
|
|||
("bpy.types.texturenodegroup*", "editors/texture_node/types/groups.html#bpy-types-texturenodegroup"),
|
||||
("bpy.types.texturenodeimage*", "editors/texture_node/types/input/image.html#bpy-types-texturenodeimage"),
|
||||
("bpy.types.texturenodescale*", "editors/texture_node/types/distort/scale.html#bpy-types-texturenodescale"),
|
||||
("bpy.types.userassetlibrary*", "editors/preferences/file_paths.html#bpy-types-userassetlibrary"),
|
||||
("bpy.types.window.workspace*", "interface/window_system/workspaces.html#bpy-types-window-workspace"),
|
||||
("bpy.types.world.lightgroup*", "render/cycles/world_settings.html#bpy-types-world-lightgroup"),
|
||||
("bpy.ops.armature.dissolve*", "animation/armatures/bones/editing/delete.html#bpy-ops-armature-dissolve"),
|
||||
("bpy.ops.armature.separate*", "animation/armatures/bones/editing/separate_bones.html#bpy-ops-armature-separate"),
|
||||
|
@ -2983,6 +3210,7 @@ url_manual_mapping = (
|
|||
("bpy.types.fmodifiercycles*", "editors/graph_editor/fcurves/modifiers.html#bpy-types-fmodifiercycles"),
|
||||
("bpy.types.fmodifierlimits*", "editors/graph_editor/fcurves/modifiers.html#bpy-types-fmodifierlimits"),
|
||||
("bpy.types.imagepaint.mode*", "sculpt_paint/texture_paint/tool_settings/texture_slots.html#bpy-types-imagepaint-mode"),
|
||||
("bpy.types.keymapitem.type*", "editors/preferences/keymap.html#bpy-types-keymapitem-type"),
|
||||
("bpy.types.latticemodifier*", "modeling/modifiers/deform/lattice.html#bpy-types-latticemodifier"),
|
||||
("bpy.types.materiallineart*", "render/materials/line_art.html#bpy-types-materiallineart"),
|
||||
("bpy.types.musgravetexture*", "render/materials/legacy_textures/types/musgrave.html#bpy-types-musgravetexture"),
|
||||
|
@ -2997,6 +3225,7 @@ url_manual_mapping = (
|
|||
("bpy.types.scene.sync_mode*", "editors/timeline.html#bpy-types-scene-sync-mode"),
|
||||
("bpy.types.sceneeevee.gtao*", "render/eevee/render_settings/ambient_occlusion.html#bpy-types-sceneeevee-gtao"),
|
||||
("bpy.types.screen.use_play*", "editors/timeline.html#bpy-types-screen-use-play"),
|
||||
("bpy.types.scriptdirectory*", "editors/preferences/file_paths.html#bpy-types-scriptdirectory"),
|
||||
("bpy.types.shadernodebevel*", "render/shader_nodes/input/bevel.html#bpy-types-shadernodebevel"),
|
||||
("bpy.types.shadernodeclamp*", "render/shader_nodes/converter/clamp.html#bpy-types-shadernodeclamp"),
|
||||
("bpy.types.shadernodegamma*", "render/shader_nodes/color/gamma.html#bpy-types-shadernodegamma"),
|
||||
|
@ -3114,9 +3343,8 @@ url_manual_mapping = (
|
|||
("bpy.types.uvwarpmodifier*", "modeling/modifiers/modify/uv_warp.html#bpy-types-uvwarpmodifier"),
|
||||
("bpy.types.viewlayer.name*", "render/layers/introduction.html#bpy-types-viewlayer-name"),
|
||||
("bpy.types.voronoitexture*", "render/materials/legacy_textures/types/voronoi.html#bpy-types-voronoitexture"),
|
||||
("bpy.types.walknavigation*", "editors/3dview/navigate/walk_fly.html#bpy-types-walknavigation"),
|
||||
("bpy.types.walknavigation*", "editors/preferences/navigation.html#bpy-types-walknavigation"),
|
||||
("bpy.ops.*.select_circle*", "interface/selecting.html#bpy-ops-select-circle"),
|
||||
("bpy.ops.anim.keying_set*", "animation/keyframes/keying_sets.html#bpy-ops-anim-keying-set"),
|
||||
("bpy.ops.armature.delete*", "animation/armatures/bones/editing/delete.html#bpy-ops-armature-delete"),
|
||||
("bpy.ops.clip.select_all*", "movie_clip/tracking/clip/selecting.html#bpy-ops-clip-select-all"),
|
||||
("bpy.ops.clip.select_box*", "movie_clip/tracking/clip/selecting.html#bpy-ops-clip-select-box"),
|
||||
|
@ -3200,6 +3428,7 @@ url_manual_mapping = (
|
|||
("bpy.types.fieldsettings*", "physics/forces/force_fields/index.html#bpy-types-fieldsettings"),
|
||||
("bpy.types.imagesequence*", "video_editing/edit/montage/strips/image.html#bpy-types-imagesequence"),
|
||||
("bpy.types.key.eval_time*", "animation/shape_keys/shape_keys_panel.html#bpy-types-key-eval-time"),
|
||||
("bpy.types.keyingsetpath*", "animation/keyframes/keying_sets.html#bpy-types-keyingsetpath"),
|
||||
("bpy.types.marbletexture*", "render/materials/legacy_textures/types/marble.html#bpy-types-marbletexture"),
|
||||
("bpy.types.modifier.name*", "modeling/modifiers/introduction.html#bpy-types-modifier-name"),
|
||||
("bpy.types.modifier.show*", "modeling/modifiers/introduction.html#bpy-types-modifier-show"),
|
||||
|
@ -3356,6 +3585,7 @@ url_manual_mapping = (
|
|||
("bpy.ops.wm.properties*", "files/custom_properties.html#bpy-ops-wm-properties"),
|
||||
("bpy.ops.wm.stl_import*", "files/import_export/stl.html#bpy-ops-wm-stl-import"),
|
||||
("bpy.ops.wm.usd_export*", "files/import_export/usd.html#bpy-ops-wm-usd-export"),
|
||||
("bpy.ops.workspace.add*", "interface/window_system/workspaces.html#bpy-ops-workspace-add"),
|
||||
("bpy.types.addsequence*", "video_editing/edit/montage/strips/effects/add.html#bpy-types-addsequence"),
|
||||
("bpy.types.brush.cloth*", "sculpt_paint/sculpting/tools/cloth.html#bpy-types-brush-cloth"),
|
||||
("bpy.types.brush.curve*", "sculpt_paint/brush/falloff.html#bpy-types-brush-curve"),
|
||||
|
@ -3369,6 +3599,7 @@ url_manual_mapping = (
|
|||
("bpy.types.object.lock*", "scene_layout/object/properties/transforms.html#bpy-types-object-lock"),
|
||||
("bpy.types.object.show*", "scene_layout/object/properties/display.html#bpy-types-object-show"),
|
||||
("bpy.types.particlekey*", "physics/particles/emitter/physics/keyed.html#bpy-types-particlekey"),
|
||||
("bpy.types.pathcompare*", "editors/preferences/save_load.html#bpy-types-pathcompare"),
|
||||
("bpy.types.posebone.ik*", "animation/armatures/posing/bone_constraints/inverse_kinematics/introduction.html#bpy-types-posebone-ik"),
|
||||
("bpy.types.preferences*", "editors/preferences/index.html#bpy-types-preferences"),
|
||||
("bpy.types.renderlayer*", "render/layers/passes.html#bpy-types-renderlayer"),
|
||||
|
@ -3416,6 +3647,7 @@ url_manual_mapping = (
|
|||
("bpy.types.compositor*", "compositing/index.html#bpy-types-compositor"),
|
||||
("bpy.types.constraint*", "animation/constraints/index.html#bpy-types-constraint"),
|
||||
("bpy.types.imagepaint*", "sculpt_paint/texture_paint/index.html#bpy-types-imagepaint"),
|
||||
("bpy.types.keyingsets*", "animation/keyframes/keying_sets.html#bpy-types-keyingsets"),
|
||||
("bpy.types.keymapitem*", "editors/preferences/keymap.html#bpy-types-keymapitem"),
|
||||
("bpy.types.light.type*", "render/lights/light_object.html#bpy-types-light-type"),
|
||||
("bpy.types.lightprobe*", "render/eevee/light_probes/index.html#bpy-types-lightprobe"),
|
||||
|
@ -3553,6 +3785,7 @@ url_manual_mapping = (
|
|||
("bpy.ops.uv.unwrap*", "modeling/meshes/editing/uv.html#bpy-ops-uv-unwrap"),
|
||||
("bpy.ops.wm.append*", "files/linked_libraries/link_append.html#bpy-ops-wm-append"),
|
||||
("bpy.ops.wm.splash*", "interface/window_system/splash.html#bpy-ops-wm-splash"),
|
||||
("bpy.ops.workspace*", "interface/window_system/workspaces.html#bpy-ops-workspace"),
|
||||
("bpy.types.lattice*", "animation/lattice.html#bpy-types-lattice"),
|
||||
("bpy.types.library*", "files/linked_libraries/index.html#bpy-types-library"),
|
||||
("bpy.types.speaker*", "render/output/audio/speaker.html#bpy-types-speaker"),
|
||||
|
|
|
@ -427,9 +427,9 @@ class PREFERENCES_OT_keyconfig_remove(Operator):
|
|||
# Add-on Operators
|
||||
|
||||
class PREFERENCES_OT_addon_enable(Operator):
|
||||
"""Enable an add-on"""
|
||||
"""Turn on this extension"""
|
||||
bl_idname = "preferences.addon_enable"
|
||||
bl_label = "Enable Add-on"
|
||||
bl_label = "Enable Extension"
|
||||
|
||||
module: StringProperty(
|
||||
name="Module",
|
||||
|
@ -473,9 +473,9 @@ class PREFERENCES_OT_addon_enable(Operator):
|
|||
|
||||
|
||||
class PREFERENCES_OT_addon_disable(Operator):
|
||||
"""Disable an add-on"""
|
||||
"""Turn off this extension"""
|
||||
bl_idname = "preferences.addon_disable"
|
||||
bl_label = "Disable Add-on"
|
||||
bl_label = "Disable Extension"
|
||||
|
||||
module: StringProperty(
|
||||
name="Module",
|
||||
|
|
|
@ -666,6 +666,7 @@ class NODE_MT_category_GEO_VOLUME(Menu):
|
|||
layout = self.layout
|
||||
if context.preferences.experimental.use_new_volume_nodes:
|
||||
layout.menu("NODE_MT_geometry_node_GEO_VOLUME_READ")
|
||||
layout.menu("NODE_MT_geometry_node_volume_sample")
|
||||
layout.menu("NODE_MT_geometry_node_GEO_VOLUME_WRITE")
|
||||
layout.separator()
|
||||
layout.menu("NODE_MT_geometry_node_GEO_VOLUME_OPERATIONS")
|
||||
|
@ -693,6 +694,16 @@ class NODE_MT_geometry_node_GEO_VOLUME_WRITE(Menu):
|
|||
node_add_menu.draw_assets_for_catalog(layout, "Volume/Write")
|
||||
|
||||
|
||||
class NODE_MT_geometry_node_volume_sample(Menu):
|
||||
bl_idname = "NODE_MT_geometry_node_volume_sample"
|
||||
bl_label = "Sample"
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
node_add_menu.add_node_type(layout, "GeometryNodeSampleGrid")
|
||||
node_add_menu.draw_assets_for_catalog(layout, "Volume/Sample")
|
||||
|
||||
|
||||
class NODE_MT_geometry_node_GEO_VOLUME_OPERATIONS(Menu):
|
||||
bl_idname = "NODE_MT_geometry_node_GEO_VOLUME_OPERATIONS"
|
||||
bl_label = "Operations"
|
||||
|
@ -785,6 +796,7 @@ classes = (
|
|||
NODE_MT_category_simulation,
|
||||
NODE_MT_category_GEO_VOLUME,
|
||||
NODE_MT_geometry_node_GEO_VOLUME_READ,
|
||||
NODE_MT_geometry_node_volume_sample,
|
||||
NODE_MT_geometry_node_GEO_VOLUME_WRITE,
|
||||
NODE_MT_geometry_node_GEO_VOLUME_OPERATIONS,
|
||||
NODE_MT_geometry_node_GEO_VOLUME_PRIMITIVES,
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
import bpy
|
||||
from bpy.types import Panel
|
||||
from rna_prop_ui import PropertyPanel
|
||||
import rna_prop_ui
|
||||
|
||||
from bpy.app.translations import contexts as i18n_contexts
|
||||
|
||||
|
@ -260,6 +260,16 @@ class BONE_PT_collections(BoneButtonsPanel, Panel):
|
|||
layout.use_property_split = False
|
||||
|
||||
bone = context.bone or context.edit_bone
|
||||
object = context.pose_object or context.edit_object or context.object
|
||||
if not object:
|
||||
layout.active = False
|
||||
sub = layout.column(align=True)
|
||||
sub.label(text="Cannot figure out which object this bone belongs to.")
|
||||
sub.label(text="Please file a bug report.")
|
||||
return
|
||||
|
||||
armature = object.data
|
||||
is_solo_active = armature.collections.is_solo_active
|
||||
|
||||
if not bone.collections:
|
||||
layout.active = False
|
||||
|
@ -275,8 +285,15 @@ class BONE_PT_collections(BoneButtonsPanel, Panel):
|
|||
# Name & visibility of bcoll. Safe things, so aligned together.
|
||||
row = bcoll_row.row(align=True)
|
||||
row.label(text=bcoll.name)
|
||||
row.prop(bcoll, "is_visible", text="",
|
||||
icon='HIDE_OFF' if bcoll.is_visible else 'HIDE_ON')
|
||||
|
||||
# Sub-layout that's dimmed when the bone collection's own visibility flag doesn't matter.
|
||||
sub_visible = row.row(align=True)
|
||||
sub_visible.active = (not is_solo_active) and bcoll.is_visible_ancestors
|
||||
sub_visible.prop(bcoll, "is_visible", text="",
|
||||
icon='HIDE_OFF' if bcoll.is_visible else 'HIDE_ON')
|
||||
|
||||
row.prop(bcoll, "is_solo", text="",
|
||||
icon='SOLO_ON' if bcoll.is_solo else 'SOLO_OFF')
|
||||
|
||||
# Unassignment operator, less safe so with a bit of spacing.
|
||||
props = bcoll_row.operator("armature.collection_unassign_named",
|
||||
|
@ -530,7 +547,7 @@ class BONE_PT_deform(BoneButtonsPanel, Panel):
|
|||
col.prop(bone, "tail_radius", text="Tail")
|
||||
|
||||
|
||||
class BONE_PT_custom_props(BoneButtonsPanel, PropertyPanel, Panel):
|
||||
class BONE_PT_custom_props(BoneButtonsPanel, rna_prop_ui.PropertyPanel, Panel):
|
||||
COMPAT_ENGINES = {
|
||||
'BLENDER_RENDER',
|
||||
'BLENDER_EEVEE',
|
||||
|
@ -539,14 +556,45 @@ class BONE_PT_custom_props(BoneButtonsPanel, PropertyPanel, Panel):
|
|||
}
|
||||
_property_type = bpy.types.Bone, bpy.types.EditBone, bpy.types.PoseBone
|
||||
|
||||
@property
|
||||
def _context_path(self):
|
||||
obj = bpy.context.object
|
||||
if obj and obj.mode == 'POSE':
|
||||
return "active_pose_bone"
|
||||
else:
|
||||
@classmethod
|
||||
def _poll(cls, context):
|
||||
context_path = cls._get_context_path(context)
|
||||
rna_item, _context_member = rna_prop_ui.rna_idprop_context_value(
|
||||
context, context_path, cls._property_type)
|
||||
return bool(rna_item)
|
||||
|
||||
def draw(self, context):
|
||||
context_path = self._get_context_path(context)
|
||||
rna_prop_ui.draw(self.layout, context, context_path, self._property_type)
|
||||
|
||||
@classmethod
|
||||
def _get_context_path(self, context):
|
||||
obj = context.object
|
||||
if not obj:
|
||||
# We have to return _something_. If there is some bone by some
|
||||
# miracle, just use it.
|
||||
return "bone"
|
||||
|
||||
if obj.mode != 'POSE':
|
||||
# Outside of pose mode, active_bone is the one to use. It's either a
|
||||
# Bone or an EditBone, depending on the mode.
|
||||
return "active_bone"
|
||||
|
||||
if context.active_pose_bone is not None:
|
||||
# There is an active pose bone, so use it.
|
||||
return "active_pose_bone"
|
||||
|
||||
# When the active bone is hidden, `context.active_pose_bone` is None, but
|
||||
# `context.bone` still points to it. Use that to still get the pose bone.
|
||||
if context.bone is None:
|
||||
# If there is no active bone, let the rest of the code refer to the
|
||||
# also-None active pose bone, as that's more appropriate given we're
|
||||
# currently in pose mode.
|
||||
return "active_pose_bone"
|
||||
|
||||
bone_path = obj.pose.bones[context.bone.name].path_from_id()
|
||||
return f"object.{bone_path}"
|
||||
|
||||
|
||||
classes = (
|
||||
BONE_PT_context_bone,
|
||||
|
|
|
@ -143,6 +143,11 @@ class DATA_PT_grease_pencil_layer_relations(LayerDataButtonsPanel, Panel):
|
|||
row = layout.row(align=True)
|
||||
row.prop_search(layer, "parent_bone", layer.parent.data, "bones", text="Bone")
|
||||
|
||||
layout.separator()
|
||||
|
||||
col = layout.row(align=True)
|
||||
col.prop(layer, "pass_index")
|
||||
|
||||
|
||||
classes = (
|
||||
DATA_PT_context_grease_pencil,
|
||||
|
|
|
@ -196,6 +196,7 @@ class OBJECT_MT_modifier_add_deform(ModifierAddMenu, Menu):
|
|||
if ob_type == 'VOLUME':
|
||||
self.operator_modifier_add(layout, 'VOLUME_DISPLACE')
|
||||
if ob_type == 'GREASEPENCIL':
|
||||
self.operator_modifier_add(layout, 'GREASE_PENCIL_HOOK')
|
||||
self.operator_modifier_add(layout, 'GREASE_PENCIL_LATTICE')
|
||||
self.operator_modifier_add(layout, 'GREASE_PENCIL_NOISE')
|
||||
self.operator_modifier_add(layout, 'GREASE_PENCIL_OFFSET')
|
||||
|
|
|
@ -106,7 +106,7 @@ class PHYSICS_PT_add(PhysicButtonsPanel, Panel):
|
|||
)
|
||||
|
||||
|
||||
# cache-type can be 'PSYS' 'HAIR' 'FLUID' etc.
|
||||
# cache-type can be 'PSYS' 'HAIR' etc. ('FLUID' uses its own cache)
|
||||
|
||||
def point_cache_ui(self, cache, enabled, cachetype):
|
||||
layout = self.layout
|
||||
|
@ -130,12 +130,8 @@ def point_cache_ui(self, cache, enabled, cachetype):
|
|||
col.operator("ptcache.add", icon='ADD', text="")
|
||||
col.operator("ptcache.remove", icon='REMOVE', text="")
|
||||
|
||||
if cachetype in {'PSYS', 'HAIR', 'FLUID'}:
|
||||
if cachetype in {'PSYS', 'HAIR'}:
|
||||
col = layout.column()
|
||||
|
||||
if cachetype == 'FLUID':
|
||||
col.prop(cache, "use_library_path", text="Use Library Path")
|
||||
|
||||
col.prop(cache, "use_external")
|
||||
|
||||
if cache.use_external:
|
||||
|
@ -149,14 +145,14 @@ def point_cache_ui(self, cache, enabled, cachetype):
|
|||
col.alignment = 'RIGHT'
|
||||
col.label(text=cache_info)
|
||||
else:
|
||||
if cachetype in {'FLUID', 'DYNAMIC_PAINT'}:
|
||||
if cachetype == 'DYNAMIC_PAINT':
|
||||
if not is_saved:
|
||||
col = layout.column(align=True)
|
||||
col.alignment = 'RIGHT'
|
||||
col.label(text="Cache is disabled until the file is saved")
|
||||
layout.enabled = False
|
||||
|
||||
if not cache.use_external or cachetype == 'FLUID':
|
||||
if not cache.use_external:
|
||||
col = layout.column(align=True)
|
||||
|
||||
if cachetype not in {'PSYS', 'DYNAMIC_PAINT'}:
|
||||
|
@ -164,18 +160,18 @@ def point_cache_ui(self, cache, enabled, cachetype):
|
|||
col.prop(cache, "frame_start", text="Simulation Start")
|
||||
col.prop(cache, "frame_end")
|
||||
|
||||
if cachetype not in {'FLUID', 'CLOTH', 'DYNAMIC_PAINT', 'RIGID_BODY'}:
|
||||
if cachetype not in {'CLOTH', 'DYNAMIC_PAINT', 'RIGID_BODY'}:
|
||||
col.prop(cache, "frame_step")
|
||||
|
||||
cache_info = cache.info
|
||||
if cachetype != 'FLUID' and cache_info: # avoid empty space.
|
||||
if cache_info: # avoid empty space.
|
||||
col = layout.column(align=True)
|
||||
col.alignment = 'RIGHT'
|
||||
col.label(text=cache_info)
|
||||
|
||||
can_bake = True
|
||||
|
||||
if cachetype not in {'FLUID', 'DYNAMIC_PAINT', 'RIGID_BODY'}:
|
||||
if cachetype not in {'DYNAMIC_PAINT', 'RIGID_BODY'}:
|
||||
if not is_saved:
|
||||
col = layout.column(align=True)
|
||||
col.alignment = 'RIGHT'
|
||||
|
|
|
@ -1575,10 +1575,10 @@ class IMAGE_PT_overlay_guides(Panel):
|
|||
layout.prop(uvedit, "tile_grid_shape", text="Tiles")
|
||||
|
||||
|
||||
class IMAGE_PT_overlay_uv_edit(Panel):
|
||||
class IMAGE_PT_overlay_uv_stretch(Panel):
|
||||
bl_space_type = 'IMAGE_EDITOR'
|
||||
bl_region_type = 'HEADER'
|
||||
bl_label = "UV Editing"
|
||||
bl_label = "UV Stretch"
|
||||
bl_parent_id = "IMAGE_PT_overlay"
|
||||
|
||||
@classmethod
|
||||
|
@ -1595,12 +1595,12 @@ class IMAGE_PT_overlay_uv_edit(Panel):
|
|||
|
||||
layout.active = overlay.show_overlays
|
||||
|
||||
# UV Stretching
|
||||
row = layout.row()
|
||||
row.prop(uvedit, "show_stretch")
|
||||
subrow = row.row(align=True)
|
||||
row = layout.row(align=True)
|
||||
row.row().prop(uvedit, "show_stretch", text="")
|
||||
subrow = row.row()
|
||||
subrow.active = uvedit.show_stretch
|
||||
subrow.prop(uvedit, "display_stretch_type", text="")
|
||||
subrow.prop(uvedit, "stretch_opacity", text="Opacity")
|
||||
|
||||
|
||||
class IMAGE_PT_overlay_uv_edit_geometry(Panel):
|
||||
|
@ -1752,7 +1752,7 @@ classes = (
|
|||
IMAGE_PT_gizmo_display,
|
||||
IMAGE_PT_overlay,
|
||||
IMAGE_PT_overlay_guides,
|
||||
IMAGE_PT_overlay_uv_edit,
|
||||
IMAGE_PT_overlay_uv_stretch,
|
||||
IMAGE_PT_overlay_uv_edit_geometry,
|
||||
IMAGE_PT_overlay_texture_paint,
|
||||
IMAGE_PT_overlay_image,
|
||||
|
|
|
@ -1597,7 +1597,7 @@ class USERPREF_UL_asset_libraries(UIList):
|
|||
class USERPREF_UL_extension_repos(UIList):
|
||||
def draw_item(self, _context, layout, _data, item, icon, _active_data, _active_propname, _index):
|
||||
repo = item
|
||||
icon = 'WORLD' if repo.use_remote_path else 'DISK_DRIVE'
|
||||
icon = 'NETWORK_DRIVE' if repo.use_remote_path else 'DISK_DRIVE'
|
||||
if self.layout_type in {'DEFAULT', 'COMPACT'}:
|
||||
layout.prop(repo, "name", text="", icon=icon, emboss=False)
|
||||
elif self.layout_type == 'GRID':
|
||||
|
@ -1614,6 +1614,24 @@ class USERPREF_UL_extension_repos(UIList):
|
|||
|
||||
layout.prop(repo, "enabled", text="", emboss=False, icon='CHECKBOX_HLT' if repo.enabled else 'CHECKBOX_DEHLT')
|
||||
|
||||
def filter_items(self, _context, data, propname):
|
||||
# Repositories has no index, converting to a list.
|
||||
items = list(getattr(data, propname))
|
||||
|
||||
flags = [self.bitflag_filter_item] * len(items)
|
||||
|
||||
indices = [None] * len(items)
|
||||
for index, orig_index in enumerate(sorted(
|
||||
range(len(items)),
|
||||
key=lambda i: (
|
||||
items[i].use_remote_path is False,
|
||||
items[i].name.lower(),
|
||||
)
|
||||
)):
|
||||
indices[orig_index] = index
|
||||
|
||||
return flags, indices
|
||||
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# Save/Load Panels
|
||||
|
@ -2103,9 +2121,13 @@ class USERPREF_PT_extensions_repos(Panel):
|
|||
if active_repo.use_custom_directory:
|
||||
if active_repo.custom_directory == "":
|
||||
row.alert = True
|
||||
row.prop(active_repo, "custom_directory", text="")
|
||||
else:
|
||||
row.active = False
|
||||
row.prop(active_repo, "custom_directory", text="")
|
||||
# Show the read-only directory property.
|
||||
# Apart from being consistent with the custom directory UI,
|
||||
# prefer a read-only property over a label because this is not necessarily
|
||||
# valid UTF-8 which will raise a Python exception when passed in as text.
|
||||
row.prop(active_repo, "directory", text="")
|
||||
|
||||
layout_panel.separator()
|
||||
|
||||
|
|
|
@ -7,14 +7,6 @@ if(WITH_LEGACY_OPENGL)
|
|||
endif()
|
||||
|
||||
if(WITH_CLANG_TIDY AND NOT MSVC)
|
||||
if(NOT CMAKE_C_COMPILER_ID MATCHES "Clang")
|
||||
message(WARNING "Currently Clang-Tidy might fail with GCC toolchain, switch to Clang toolchain if that happens")
|
||||
if(COMMAND target_precompile_headers)
|
||||
message(STATUS "Clang-Tidy and GCC precompiled headers are incompatible, disabling precompiled headers")
|
||||
set(CMAKE_DISABLE_PRECOMPILE_HEADERS ON)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
find_package(ClangTidy REQUIRED)
|
||||
set(CMAKE_C_CLANG_TIDY
|
||||
${CLANG_TIDY_EXECUTABLE};--extra-arg=-Wno-error=unknown-warning-option)
|
||||
|
|
|
@ -84,8 +84,13 @@ class AssetCatalogService {
|
|||
/**
|
||||
* Duplicate the catalogs from \a other_service into this one. Does not rebuild the tree, this
|
||||
* needs to be done by the caller (call #rebuild_tree()!).
|
||||
*
|
||||
* \note If a catalog from \a other already exists in this collection (identified by catalog ID),
|
||||
* it will be skipped and \a on_duplicate_items will be called.
|
||||
*/
|
||||
void add_from_existing(const AssetCatalogService &other_service);
|
||||
void add_from_existing(const AssetCatalogService &other_service,
|
||||
FunctionRef<void(const AssetCatalog &existing,
|
||||
const AssetCatalog &to_be_ignored)> on_duplicate_items);
|
||||
|
||||
/**
|
||||
* Write the catalog definitions to disk.
|
||||
|
@ -178,7 +183,7 @@ class AssetCatalogService {
|
|||
*/
|
||||
void update_catalog_path(CatalogID catalog_id, const AssetCatalogPath &new_catalog_path);
|
||||
|
||||
AssetCatalogTree *get_catalog_tree();
|
||||
const AssetCatalogTree *get_catalog_tree() const;
|
||||
|
||||
/** Return true only if there are no catalogs known. */
|
||||
bool is_empty() const;
|
||||
|
@ -239,7 +244,7 @@ class AssetCatalogService {
|
|||
* Construct an in-memory catalog definition file (CDF) from the currently known catalogs.
|
||||
* This object can then be processed further before saving to disk. */
|
||||
std::unique_ptr<AssetCatalogDefinitionFile> construct_cdf_in_memory(
|
||||
const CatalogFilePath &file_path);
|
||||
const CatalogFilePath &file_path) const;
|
||||
|
||||
/**
|
||||
* Find a suitable path to write a CDF to.
|
||||
|
@ -250,7 +255,7 @@ class AssetCatalogService {
|
|||
static CatalogFilePath find_suitable_cdf_path_for_writing(
|
||||
const CatalogFilePath &blend_file_path);
|
||||
|
||||
std::unique_ptr<AssetCatalogTree> read_into_tree();
|
||||
std::unique_ptr<AssetCatalogTree> read_into_tree() const;
|
||||
|
||||
/**
|
||||
* For every catalog, ensure that its parent path also has a known catalog.
|
||||
|
@ -263,9 +268,9 @@ class AssetCatalogService {
|
|||
void tag_all_catalogs_as_unsaved_changes();
|
||||
|
||||
/* For access by subclasses, as those will not be marked as friend by #AssetCatalogCollection. */
|
||||
AssetCatalogDefinitionFile *get_catalog_definition_file();
|
||||
OwningAssetCatalogMap &get_catalogs();
|
||||
OwningAssetCatalogMap &get_deleted_catalogs();
|
||||
AssetCatalogDefinitionFile *get_catalog_definition_file() const;
|
||||
OwningAssetCatalogMap &get_catalogs() const;
|
||||
OwningAssetCatalogMap &get_deleted_catalogs() const;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -298,11 +303,17 @@ class AssetCatalogCollection {
|
|||
AssetCatalogCollection(AssetCatalogCollection &&other) noexcept = default;
|
||||
|
||||
std::unique_ptr<AssetCatalogCollection> deep_copy() const;
|
||||
using OnDuplicateCatalogIdFn =
|
||||
FunctionRef<void(const AssetCatalog &existing, const AssetCatalog &to_be_ignored)>;
|
||||
/**
|
||||
* Copy the catalogs from \a other and append them to this collection. Copies no other data
|
||||
* otherwise.
|
||||
*
|
||||
* \note If a catalog from \a other already exists in this collection (identified by catalog ID),
|
||||
* it will be skipped and \a on_duplicate_items will be called.
|
||||
*/
|
||||
void add_catalogs_from_existing(const AssetCatalogCollection &other);
|
||||
void add_catalogs_from_existing(const AssetCatalogCollection &other,
|
||||
OnDuplicateCatalogIdFn on_duplicate_items);
|
||||
|
||||
protected:
|
||||
static OwningAssetCatalogMap copy_catalog_map(const OwningAssetCatalogMap &orig);
|
||||
|
|
|
@ -28,7 +28,7 @@ class AssetCatalogTreeItem {
|
|||
/** Container for child items. Uses a #std::map to keep items ordered by their name (i.e. their
|
||||
* last catalog component). */
|
||||
using ChildMap = std::map<std::string, AssetCatalogTreeItem>;
|
||||
using ItemIterFn = FunctionRef<void(AssetCatalogTreeItem &)>;
|
||||
using ItemIterFn = FunctionRef<void(const AssetCatalogTreeItem &)>;
|
||||
|
||||
private:
|
||||
/** Child tree items, ordered by their names. */
|
||||
|
@ -65,10 +65,10 @@ class AssetCatalogTreeItem {
|
|||
|
||||
/** Iterate over children calling \a callback for each of them, but do not recurse into their
|
||||
* children. */
|
||||
void foreach_child(ItemIterFn callback);
|
||||
void foreach_child(ItemIterFn callback) const;
|
||||
|
||||
private:
|
||||
static void foreach_item_recursive(ChildMap &children_, ItemIterFn callback);
|
||||
static void foreach_item_recursive(const ChildMap &children_, ItemIterFn callback);
|
||||
};
|
||||
|
||||
class AssetCatalogTree {
|
||||
|
@ -82,15 +82,15 @@ class AssetCatalogTree {
|
|||
/** Ensure an item representing \a path is in the tree, adding it if necessary. */
|
||||
void insert_item(const AssetCatalog &catalog);
|
||||
|
||||
void foreach_item(ItemIterFn callback);
|
||||
void foreach_item(ItemIterFn callback) const;
|
||||
/** Iterate over root items calling \a callback for each of them, but do not recurse into their
|
||||
* children. */
|
||||
void foreach_root_item(ItemIterFn callback);
|
||||
void foreach_root_item(ItemIterFn callback) const;
|
||||
|
||||
bool is_empty() const;
|
||||
|
||||
AssetCatalogTreeItem *find_item(const AssetCatalogPath &path);
|
||||
AssetCatalogTreeItem *find_root_item(const AssetCatalogPath &path);
|
||||
const AssetCatalogTreeItem *find_item(const AssetCatalogPath &path) const;
|
||||
const AssetCatalogTreeItem *find_root_item(const AssetCatalogPath &path) const;
|
||||
};
|
||||
|
||||
} // namespace blender::asset_system
|
||||
|
|
|
@ -179,6 +179,7 @@ class AssetLibrary {
|
|||
Vector<AssetLibraryReference> all_valid_asset_library_refs();
|
||||
|
||||
AssetLibraryReference all_library_reference();
|
||||
void all_library_reload_catalogs_if_dirty();
|
||||
|
||||
} // namespace blender::asset_system
|
||||
|
||||
|
|
|
@ -116,16 +116,16 @@ bool AssetCatalogService::is_empty() const
|
|||
return catalog_collection_->catalogs_.is_empty();
|
||||
}
|
||||
|
||||
OwningAssetCatalogMap &AssetCatalogService::get_catalogs()
|
||||
OwningAssetCatalogMap &AssetCatalogService::get_catalogs() const
|
||||
{
|
||||
return catalog_collection_->catalogs_;
|
||||
}
|
||||
OwningAssetCatalogMap &AssetCatalogService::get_deleted_catalogs()
|
||||
OwningAssetCatalogMap &AssetCatalogService::get_deleted_catalogs() const
|
||||
{
|
||||
return catalog_collection_->deleted_catalogs_;
|
||||
}
|
||||
|
||||
AssetCatalogDefinitionFile *AssetCatalogService::get_catalog_definition_file()
|
||||
AssetCatalogDefinitionFile *AssetCatalogService::get_catalog_definition_file() const
|
||||
{
|
||||
return catalog_collection_->catalog_definition_file_.get();
|
||||
}
|
||||
|
@ -238,7 +238,7 @@ void AssetCatalogService::prune_catalogs_by_path(const AssetCatalogPath &path)
|
|||
}
|
||||
|
||||
this->rebuild_tree();
|
||||
AssetLibraryService::get()->rebuild_all_library();
|
||||
AssetLibraryService::get()->tag_all_library_catalogs_dirty();
|
||||
}
|
||||
|
||||
void AssetCatalogService::prune_catalogs_by_id(const CatalogID catalog_id)
|
||||
|
@ -273,7 +273,7 @@ void AssetCatalogService::update_catalog_path(const CatalogID catalog_id,
|
|||
}
|
||||
|
||||
this->rebuild_tree();
|
||||
AssetLibraryService::get()->rebuild_all_library();
|
||||
AssetLibraryService::get()->tag_all_library_catalogs_dirty();
|
||||
}
|
||||
|
||||
AssetCatalog *AssetCatalogService::create_catalog(const AssetCatalogPath &catalog_path)
|
||||
|
@ -299,8 +299,7 @@ AssetCatalog *AssetCatalogService::create_catalog(const AssetCatalogPath &catalo
|
|||
|
||||
BLI_assert_msg(catalog_tree_, "An Asset Catalog tree should always exist.");
|
||||
catalog_tree_->insert_item(*catalog_ptr);
|
||||
|
||||
AssetLibraryService::get()->rebuild_all_library();
|
||||
AssetLibraryService::get()->tag_all_library_catalogs_dirty();
|
||||
|
||||
return catalog_ptr;
|
||||
}
|
||||
|
@ -344,9 +343,12 @@ void AssetCatalogService::load_from_disk(const CatalogFilePath &file_or_director
|
|||
this->rebuild_tree();
|
||||
}
|
||||
|
||||
void AssetCatalogService::add_from_existing(const AssetCatalogService &other_service)
|
||||
void AssetCatalogService::add_from_existing(
|
||||
const AssetCatalogService &other_service,
|
||||
AssetCatalogCollection::OnDuplicateCatalogIdFn on_duplicate_items)
|
||||
{
|
||||
catalog_collection_->add_catalogs_from_existing(*other_service.catalog_collection_);
|
||||
catalog_collection_->add_catalogs_from_existing(*other_service.catalog_collection_,
|
||||
on_duplicate_items);
|
||||
}
|
||||
|
||||
void AssetCatalogService::load_directory_recursive(const CatalogFilePath &directory_path)
|
||||
|
@ -560,7 +562,7 @@ CatalogFilePath AssetCatalogService::find_suitable_cdf_path_for_writing(
|
|||
}
|
||||
|
||||
std::unique_ptr<AssetCatalogDefinitionFile> AssetCatalogService::construct_cdf_in_memory(
|
||||
const CatalogFilePath &file_path)
|
||||
const CatalogFilePath &file_path) const
|
||||
{
|
||||
auto cdf = std::make_unique<AssetCatalogDefinitionFile>();
|
||||
cdf->file_path = file_path;
|
||||
|
@ -572,12 +574,12 @@ std::unique_ptr<AssetCatalogDefinitionFile> AssetCatalogService::construct_cdf_i
|
|||
return cdf;
|
||||
}
|
||||
|
||||
AssetCatalogTree *AssetCatalogService::get_catalog_tree()
|
||||
const AssetCatalogTree *AssetCatalogService::get_catalog_tree() const
|
||||
{
|
||||
return catalog_tree_.get();
|
||||
}
|
||||
|
||||
std::unique_ptr<AssetCatalogTree> AssetCatalogService::read_into_tree()
|
||||
std::unique_ptr<AssetCatalogTree> AssetCatalogService::read_into_tree() const
|
||||
{
|
||||
auto tree = std::make_unique<AssetCatalogTree>();
|
||||
|
||||
|
@ -652,7 +654,7 @@ void AssetCatalogService::undo()
|
|||
redo_snapshots_.append(std::move(catalog_collection_));
|
||||
catalog_collection_ = undo_snapshots_.pop_last();
|
||||
this->rebuild_tree();
|
||||
AssetLibraryService::get()->rebuild_all_library();
|
||||
AssetLibraryService::get()->tag_all_library_catalogs_dirty();
|
||||
}
|
||||
|
||||
void AssetCatalogService::redo()
|
||||
|
@ -663,7 +665,7 @@ void AssetCatalogService::redo()
|
|||
undo_snapshots_.append(std::move(catalog_collection_));
|
||||
catalog_collection_ = redo_snapshots_.pop_last();
|
||||
this->rebuild_tree();
|
||||
AssetLibraryService::get()->rebuild_all_library();
|
||||
AssetLibraryService::get()->tag_all_library_catalogs_dirty();
|
||||
}
|
||||
|
||||
void AssetCatalogService::undo_push()
|
||||
|
@ -692,24 +694,40 @@ std::unique_ptr<AssetCatalogCollection> AssetCatalogCollection::deep_copy() cons
|
|||
return copy;
|
||||
}
|
||||
|
||||
static void copy_catalog_map_into_existing(const OwningAssetCatalogMap &source,
|
||||
OwningAssetCatalogMap &dest)
|
||||
static void copy_catalog_map_into_existing(
|
||||
const OwningAssetCatalogMap &source,
|
||||
OwningAssetCatalogMap &dest,
|
||||
AssetCatalogCollection::OnDuplicateCatalogIdFn on_duplicate_items)
|
||||
{
|
||||
for (const auto &orig_catalog_uptr : source.values()) {
|
||||
if (dest.contains(orig_catalog_uptr->catalog_id)) {
|
||||
if (on_duplicate_items) {
|
||||
on_duplicate_items(*dest.lookup(orig_catalog_uptr->catalog_id), *orig_catalog_uptr);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
auto copy_catalog_uptr = std::make_unique<AssetCatalog>(*orig_catalog_uptr);
|
||||
dest.add_new(copy_catalog_uptr->catalog_id, std::move(copy_catalog_uptr));
|
||||
}
|
||||
}
|
||||
|
||||
void AssetCatalogCollection::add_catalogs_from_existing(const AssetCatalogCollection &other)
|
||||
void AssetCatalogCollection::add_catalogs_from_existing(
|
||||
const AssetCatalogCollection &other,
|
||||
AssetCatalogCollection::OnDuplicateCatalogIdFn on_duplicate_items)
|
||||
{
|
||||
copy_catalog_map_into_existing(other.catalogs_, catalogs_);
|
||||
copy_catalog_map_into_existing(other.catalogs_, catalogs_, on_duplicate_items);
|
||||
}
|
||||
|
||||
OwningAssetCatalogMap AssetCatalogCollection::copy_catalog_map(const OwningAssetCatalogMap &orig)
|
||||
{
|
||||
OwningAssetCatalogMap copy;
|
||||
copy_catalog_map_into_existing(orig, copy);
|
||||
copy_catalog_map_into_existing(
|
||||
orig, copy, /*on_duplicate_items=*/[](const AssetCatalog &, const AssetCatalog &) {
|
||||
/* `copy` was empty before. If this happens it means there was a duplicate in the `orig`
|
||||
* catalog map which should've been caught already. */
|
||||
BLI_assert_unreachable();
|
||||
});
|
||||
return copy;
|
||||
}
|
||||
|
||||
|
|
|
@ -60,7 +60,7 @@ bool AssetCatalogTreeItem::has_children() const
|
|||
return !children_.empty();
|
||||
}
|
||||
|
||||
void AssetCatalogTreeItem::foreach_item_recursive(AssetCatalogTreeItem::ChildMap &children,
|
||||
void AssetCatalogTreeItem::foreach_item_recursive(const AssetCatalogTreeItem::ChildMap &children,
|
||||
const ItemIterFn callback)
|
||||
{
|
||||
for (auto &[key, item] : children) {
|
||||
|
@ -69,7 +69,7 @@ void AssetCatalogTreeItem::foreach_item_recursive(AssetCatalogTreeItem::ChildMap
|
|||
}
|
||||
}
|
||||
|
||||
void AssetCatalogTreeItem::foreach_child(const ItemIterFn callback)
|
||||
void AssetCatalogTreeItem::foreach_child(const ItemIterFn callback) const
|
||||
{
|
||||
for (auto &[key, item] : children_) {
|
||||
callback(item);
|
||||
|
@ -115,12 +115,12 @@ void AssetCatalogTree::insert_item(const AssetCatalog &catalog)
|
|||
});
|
||||
}
|
||||
|
||||
void AssetCatalogTree::foreach_item(AssetCatalogTreeItem::ItemIterFn callback)
|
||||
void AssetCatalogTree::foreach_item(AssetCatalogTreeItem::ItemIterFn callback) const
|
||||
{
|
||||
AssetCatalogTreeItem::foreach_item_recursive(root_items_, callback);
|
||||
}
|
||||
|
||||
void AssetCatalogTree::foreach_root_item(const ItemIterFn callback)
|
||||
void AssetCatalogTree::foreach_root_item(const ItemIterFn callback) const
|
||||
{
|
||||
for (auto &[key, item] : root_items_) {
|
||||
callback(item);
|
||||
|
@ -132,10 +132,10 @@ bool AssetCatalogTree::is_empty() const
|
|||
return root_items_.empty();
|
||||
}
|
||||
|
||||
AssetCatalogTreeItem *AssetCatalogTree::find_item(const AssetCatalogPath &path)
|
||||
const AssetCatalogTreeItem *AssetCatalogTree::find_item(const AssetCatalogPath &path) const
|
||||
{
|
||||
AssetCatalogTreeItem *result = nullptr;
|
||||
this->foreach_item([&](AssetCatalogTreeItem &item) {
|
||||
const AssetCatalogTreeItem *result = nullptr;
|
||||
this->foreach_item([&](const AssetCatalogTreeItem &item) {
|
||||
if (result) {
|
||||
/* There is no way to stop iteration. */
|
||||
return;
|
||||
|
@ -147,10 +147,10 @@ AssetCatalogTreeItem *AssetCatalogTree::find_item(const AssetCatalogPath &path)
|
|||
return result;
|
||||
}
|
||||
|
||||
AssetCatalogTreeItem *AssetCatalogTree::find_root_item(const AssetCatalogPath &path)
|
||||
const AssetCatalogTreeItem *AssetCatalogTree::find_root_item(const AssetCatalogPath &path) const
|
||||
{
|
||||
AssetCatalogTreeItem *result = nullptr;
|
||||
this->foreach_root_item([&](AssetCatalogTreeItem &item) {
|
||||
const AssetCatalogTreeItem *result = nullptr;
|
||||
this->foreach_root_item([&](const AssetCatalogTreeItem &item) {
|
||||
if (result) {
|
||||
/* There is no way to stop iteration. */
|
||||
return;
|
||||
|
|
|
@ -340,4 +340,10 @@ AssetLibraryReference all_library_reference()
|
|||
return all_library_ref;
|
||||
}
|
||||
|
||||
void all_library_reload_catalogs_if_dirty()
|
||||
{
|
||||
AssetLibraryService *service = AssetLibraryService::get();
|
||||
service->reload_all_library_catalogs_if_dirty();
|
||||
}
|
||||
|
||||
} // namespace blender::asset_system
|
||||
|
|
|
@ -12,29 +12,69 @@
|
|||
|
||||
#include "asset_library_all.hh"
|
||||
|
||||
#include "CLG_log.h"
|
||||
|
||||
static CLG_LogRef LOG = {"asset_system.all_asset_library"};
|
||||
|
||||
namespace blender::asset_system {
|
||||
|
||||
AllAssetLibrary::AllAssetLibrary() : AssetLibrary(ASSET_LIBRARY_ALL) {}
|
||||
|
||||
void AllAssetLibrary::rebuild(const bool reload_catalogs)
|
||||
void AllAssetLibrary::rebuild_catalogs_from_nested(const bool reload_nested_catalogs)
|
||||
{
|
||||
/* Start with empty catalog storage. */
|
||||
catalog_service = std::make_unique<AssetCatalogService>(AssetCatalogService::read_only_tag());
|
||||
/* Start with empty catalog storage. Don't do this directly in #this.catalog_service to avoid
|
||||
* race conditions. Rather build into a new service and replace the current one when done. */
|
||||
std::unique_ptr<AssetCatalogService> new_catalog_service = std::make_unique<AssetCatalogService>(
|
||||
AssetCatalogService::read_only_tag());
|
||||
|
||||
AssetLibrary::foreach_loaded(
|
||||
[&](AssetLibrary &nested) {
|
||||
if (reload_catalogs) {
|
||||
if (reload_nested_catalogs) {
|
||||
nested.catalog_service->reload_catalogs();
|
||||
}
|
||||
catalog_service->add_from_existing(*nested.catalog_service);
|
||||
|
||||
new_catalog_service->add_from_existing(
|
||||
*nested.catalog_service,
|
||||
/*on_duplicate_items=*/[](const AssetCatalog &existing,
|
||||
const AssetCatalog &to_be_ignored) {
|
||||
if (existing.path == to_be_ignored.path) {
|
||||
CLOG_INFO(&LOG,
|
||||
2,
|
||||
"multiple definitions of catalog %s (path: %s), ignoring duplicate",
|
||||
existing.catalog_id.str().c_str(),
|
||||
existing.path.c_str());
|
||||
}
|
||||
else {
|
||||
CLOG_ERROR(&LOG,
|
||||
"multiple definitions of catalog %s with differing paths (%s vs. %s), "
|
||||
"ignoring second one",
|
||||
existing.catalog_id.str().c_str(),
|
||||
existing.path.c_str(),
|
||||
to_be_ignored.path.c_str());
|
||||
}
|
||||
});
|
||||
},
|
||||
false);
|
||||
catalog_service->rebuild_tree();
|
||||
|
||||
new_catalog_service->rebuild_tree();
|
||||
|
||||
this->catalog_service = std::move(new_catalog_service);
|
||||
catalogs_dirty_ = false;
|
||||
}
|
||||
|
||||
void AllAssetLibrary::tag_catalogs_dirty()
|
||||
{
|
||||
catalogs_dirty_ = true;
|
||||
}
|
||||
|
||||
bool AllAssetLibrary::is_catalogs_dirty() const
|
||||
{
|
||||
return catalogs_dirty_;
|
||||
}
|
||||
|
||||
void AllAssetLibrary::refresh_catalogs()
|
||||
{
|
||||
rebuild(/*reload_catalogs=*/true);
|
||||
rebuild_catalogs_from_nested(/*reload_nested_catalogs=*/true);
|
||||
}
|
||||
|
||||
} // namespace blender::asset_system
|
||||
|
|
|
@ -13,12 +13,24 @@
|
|||
namespace blender::asset_system {
|
||||
|
||||
class AllAssetLibrary : public AssetLibrary {
|
||||
bool catalogs_dirty_ = true;
|
||||
|
||||
public:
|
||||
AllAssetLibrary();
|
||||
|
||||
void refresh_catalogs() override;
|
||||
|
||||
void rebuild(const bool reload_catalogs);
|
||||
/**
|
||||
* Update the available catalogs and catalog tree from the nested asset libraries. Completely
|
||||
* recreates the catalog service (invalidating pointers to the previous one).
|
||||
*
|
||||
* \param reload_nested_catalogs: Re-read catalog definitions of nested libraries from disk and
|
||||
* merge them into the in-memory representations.
|
||||
*/
|
||||
void rebuild_catalogs_from_nested(bool reload_nested_catalogs);
|
||||
|
||||
void tag_catalogs_dirty();
|
||||
bool is_catalogs_dirty() const;
|
||||
};
|
||||
|
||||
} // namespace blender::asset_system
|
||||
|
|
|
@ -187,15 +187,32 @@ AssetLibrary *AssetLibraryService::get_asset_library_current_file()
|
|||
return lib;
|
||||
}
|
||||
|
||||
void AssetLibraryService::rebuild_all_library()
|
||||
void AssetLibraryService::tag_all_library_catalogs_dirty()
|
||||
{
|
||||
if (all_library_) {
|
||||
all_library_->rebuild(false);
|
||||
all_library_->tag_catalogs_dirty();
|
||||
}
|
||||
}
|
||||
|
||||
void AssetLibraryService::reload_all_library_catalogs_if_dirty()
|
||||
{
|
||||
if (all_library_ && all_library_->is_catalogs_dirty()) {
|
||||
/* Don't reload catalogs from nested libraries from disk, just reflect their currently known
|
||||
* state in the "All" library. Loading catalog changes from disk is only done with a
|
||||
* #AS_asset_library_load()/#AssetLibraryService:get_asset_library() call. */
|
||||
const bool reload_nested_catalogs = false;
|
||||
all_library_->rebuild_catalogs_from_nested(reload_nested_catalogs);
|
||||
}
|
||||
}
|
||||
|
||||
AssetLibrary *AssetLibraryService::get_asset_library_all(const Main *bmain)
|
||||
{
|
||||
if (all_library_) {
|
||||
CLOG_INFO(&LOG, 2, "get all lib (cached)");
|
||||
all_library_->refresh_catalogs();
|
||||
return all_library_.get();
|
||||
}
|
||||
|
||||
/* (Re-)load all other asset libraries. */
|
||||
for (AssetLibraryReference &library_ref : all_valid_asset_library_refs()) {
|
||||
/* Skip self :) */
|
||||
|
@ -207,17 +224,11 @@ AssetLibrary *AssetLibraryService::get_asset_library_all(const Main *bmain)
|
|||
this->get_asset_library(bmain, library_ref);
|
||||
}
|
||||
|
||||
if (all_library_) {
|
||||
CLOG_INFO(&LOG, 2, "get all lib (cached)");
|
||||
all_library_->refresh_catalogs();
|
||||
return all_library_.get();
|
||||
}
|
||||
|
||||
CLOG_INFO(&LOG, 2, "get all lib (loaded)");
|
||||
all_library_ = std::make_unique<AllAssetLibrary>();
|
||||
|
||||
/* Don't reload catalogs on this initial read, they've just been loaded above. */
|
||||
all_library_->rebuild(/*reload_catalogs=*/false);
|
||||
all_library_->rebuild_catalogs_from_nested(/*reload_nested_catalogs=*/false);
|
||||
|
||||
return all_library_.get();
|
||||
}
|
||||
|
|
|
@ -88,7 +88,13 @@ class AssetLibraryService {
|
|||
AssetLibrary *get_asset_library_current_file();
|
||||
/** Get the "All" asset library, which loads all others and merges them into one. */
|
||||
AssetLibrary *get_asset_library_all(const Main *bmain);
|
||||
void rebuild_all_library();
|
||||
/**
|
||||
* Tag the "All" asset library as needing to reload catalogs. This should be called when catalog
|
||||
* data of other asset libraries changes. Note that changes to the catalog definition file on
|
||||
* disk don't ever affect this "dirty" flag. It only reflects changes from this Blender session.
|
||||
*/
|
||||
void tag_all_library_catalogs_dirty();
|
||||
void reload_all_library_catalogs_if_dirty();
|
||||
|
||||
/**
|
||||
* Return the start position of the last blend-file extension in given path,
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
|
||||
namespace blender::asset_system::tests {
|
||||
|
||||
/* UUIDs from lib/tests/asset_library/blender_assets.cats.txt */
|
||||
/* UUIDs from tests/data/asset_library/blender_assets.cats.txt */
|
||||
const bUUID UUID_ID_WITHOUT_PATH("e34dd2c5-5d2e-4668-9794-1db5de2a4f71");
|
||||
const bUUID UUID_POSES_ELLIE("df60e1f6-2259-475b-93d9-69a1b4a8db78");
|
||||
const bUUID UUID_POSES_ELLIE_WHITESPACE("b06132f6-5687-4751-a6dd-392740eb3c46");
|
||||
|
@ -31,7 +31,7 @@ const bUUID UUID_POSES_RUZENA_FACE("82162c1f-06cc-4d91-a9bf-4f72c104e348");
|
|||
const bUUID UUID_WITHOUT_SIMPLENAME("d7916a31-6ca9-4909-955f-182ca2b81fa3");
|
||||
const bUUID UUID_ANOTHER_RUZENA("00000000-d9fa-4b91-b704-e6af1f1339ef");
|
||||
|
||||
/* UUIDs from lib/tests/asset_library/modified_assets.cats.txt */
|
||||
/* UUIDs from tests/data/asset_library/modified_assets.cats.txt */
|
||||
const bUUID UUID_AGENT_47("c5744ba5-43f5-4f73-8e52-010ad4a61b34");
|
||||
|
||||
/* Subclass that adds accessors such that protected fields can be used in tests. */
|
||||
|
@ -49,7 +49,7 @@ class TestableAssetCatalogService : public AssetCatalogService {
|
|||
return AssetCatalogService::get_catalog_definition_file();
|
||||
}
|
||||
|
||||
OwningAssetCatalogMap &get_deleted_catalogs()
|
||||
OwningAssetCatalogMap &get_deleted_catalogs() const
|
||||
{
|
||||
return AssetCatalogService::get_deleted_catalogs();
|
||||
}
|
||||
|
@ -566,8 +566,8 @@ TEST_F(AssetCatalogTest, delete_catalog_leaf)
|
|||
"path/without/simplename",
|
||||
};
|
||||
|
||||
AssetCatalogTree *tree = service.get_catalog_tree();
|
||||
AssetCatalogTreeTestFunctions::expect_tree_items(tree, expected_paths);
|
||||
const AssetCatalogTree *tree = service.get_catalog_tree();
|
||||
AssetCatalogTreeTestFunctions::expect_tree_items(*tree, expected_paths);
|
||||
}
|
||||
|
||||
TEST_F(AssetCatalogTest, delete_catalog_parent_by_id)
|
||||
|
@ -620,8 +620,8 @@ TEST_F(AssetCatalogTest, delete_catalog_parent_by_path)
|
|||
"path/without/simplename",
|
||||
};
|
||||
|
||||
AssetCatalogTree *tree = service.get_catalog_tree();
|
||||
AssetCatalogTreeTestFunctions::expect_tree_items(tree, expected_paths);
|
||||
const AssetCatalogTree *tree = service.get_catalog_tree();
|
||||
AssetCatalogTreeTestFunctions::expect_tree_items(*tree, expected_paths);
|
||||
}
|
||||
|
||||
TEST_F(AssetCatalogTest, delete_catalog_write_to_disk)
|
||||
|
|
|
@ -22,7 +22,7 @@ TEST_F(AssetCatalogTreeTest, insert_item_into_tree)
|
|||
std::unique_ptr<AssetCatalog> catalog_empty_path = AssetCatalog::from_path("");
|
||||
tree.insert_item(*catalog_empty_path);
|
||||
|
||||
expect_tree_items(&tree, {});
|
||||
expect_tree_items(tree, {});
|
||||
}
|
||||
|
||||
{
|
||||
|
@ -30,12 +30,12 @@ TEST_F(AssetCatalogTreeTest, insert_item_into_tree)
|
|||
|
||||
std::unique_ptr<AssetCatalog> catalog = AssetCatalog::from_path("item");
|
||||
tree.insert_item(*catalog);
|
||||
expect_tree_items(&tree, {"item"});
|
||||
expect_tree_items(tree, {"item"});
|
||||
|
||||
/* Insert child after parent already exists. */
|
||||
std::unique_ptr<AssetCatalog> child_catalog = AssetCatalog::from_path("item/child");
|
||||
tree.insert_item(*catalog);
|
||||
expect_tree_items(&tree, {"item", "item/child"});
|
||||
expect_tree_items(tree, {"item", "item/child"});
|
||||
|
||||
std::vector<AssetCatalogPath> expected_paths;
|
||||
|
||||
|
@ -45,7 +45,7 @@ TEST_F(AssetCatalogTreeTest, insert_item_into_tree)
|
|||
tree.insert_item(*catalog);
|
||||
expected_paths = {
|
||||
"item", "item/child", "item/child/grandchild", "item/child/grandchild/grandgrandchild"};
|
||||
expect_tree_items(&tree, expected_paths);
|
||||
expect_tree_items(tree, expected_paths);
|
||||
|
||||
std::unique_ptr<AssetCatalog> root_level_catalog = AssetCatalog::from_path("root level");
|
||||
tree.insert_item(*catalog);
|
||||
|
@ -54,7 +54,7 @@ TEST_F(AssetCatalogTreeTest, insert_item_into_tree)
|
|||
"item/child/grandchild",
|
||||
"item/child/grandchild/grandgrandchild",
|
||||
"root level"};
|
||||
expect_tree_items(&tree, expected_paths);
|
||||
expect_tree_items(tree, expected_paths);
|
||||
}
|
||||
|
||||
{
|
||||
|
@ -62,7 +62,7 @@ TEST_F(AssetCatalogTreeTest, insert_item_into_tree)
|
|||
|
||||
std::unique_ptr<AssetCatalog> catalog = AssetCatalog::from_path("item/child");
|
||||
tree.insert_item(*catalog);
|
||||
expect_tree_items(&tree, {"item", "item/child"});
|
||||
expect_tree_items(tree, {"item", "item/child"});
|
||||
}
|
||||
|
||||
{
|
||||
|
@ -70,7 +70,7 @@ TEST_F(AssetCatalogTreeTest, insert_item_into_tree)
|
|||
|
||||
std::unique_ptr<AssetCatalog> catalog = AssetCatalog::from_path("white space");
|
||||
tree.insert_item(*catalog);
|
||||
expect_tree_items(&tree, {"white space"});
|
||||
expect_tree_items(tree, {"white space"});
|
||||
}
|
||||
|
||||
{
|
||||
|
@ -78,7 +78,7 @@ TEST_F(AssetCatalogTreeTest, insert_item_into_tree)
|
|||
|
||||
std::unique_ptr<AssetCatalog> catalog = AssetCatalog::from_path("/item/white space");
|
||||
tree.insert_item(*catalog);
|
||||
expect_tree_items(&tree, {"item", "item/white space"});
|
||||
expect_tree_items(tree, {"item", "item/white space"});
|
||||
}
|
||||
|
||||
{
|
||||
|
@ -86,11 +86,11 @@ TEST_F(AssetCatalogTreeTest, insert_item_into_tree)
|
|||
|
||||
std::unique_ptr<AssetCatalog> catalog_unicode_path = AssetCatalog::from_path("Ružena");
|
||||
tree.insert_item(*catalog_unicode_path);
|
||||
expect_tree_items(&tree, {"Ružena"});
|
||||
expect_tree_items(tree, {"Ružena"});
|
||||
|
||||
catalog_unicode_path = AssetCatalog::from_path("Ružena/Ružena");
|
||||
tree.insert_item(*catalog_unicode_path);
|
||||
expect_tree_items(&tree, {"Ružena", "Ružena/Ružena"});
|
||||
expect_tree_items(tree, {"Ružena", "Ružena/Ružena"});
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -117,8 +117,8 @@ TEST_F(AssetCatalogTreeTest, load_single_file_into_tree)
|
|||
"path/without/simplename", /* From CDF. */
|
||||
};
|
||||
|
||||
AssetCatalogTree *tree = service.get_catalog_tree();
|
||||
expect_tree_items(tree, expected_paths);
|
||||
const AssetCatalogTree *tree = service.get_catalog_tree();
|
||||
expect_tree_items(*tree, expected_paths);
|
||||
}
|
||||
|
||||
TEST_F(AssetCatalogTreeTest, foreach_in_tree)
|
||||
|
@ -127,13 +127,13 @@ TEST_F(AssetCatalogTreeTest, foreach_in_tree)
|
|||
AssetCatalogTree tree{};
|
||||
const std::vector<AssetCatalogPath> no_catalogs{};
|
||||
|
||||
expect_tree_items(&tree, no_catalogs);
|
||||
expect_tree_root_items(&tree, no_catalogs);
|
||||
expect_tree_items(tree, no_catalogs);
|
||||
expect_tree_root_items(tree, no_catalogs);
|
||||
/* Need a root item to check child items. */
|
||||
std::unique_ptr<AssetCatalog> catalog = AssetCatalog::from_path("something");
|
||||
tree.insert_item(*catalog);
|
||||
tree.foreach_root_item([&no_catalogs](AssetCatalogTreeItem &item) {
|
||||
expect_tree_item_child_items(&item, no_catalogs);
|
||||
tree.foreach_root_item([&no_catalogs](const AssetCatalogTreeItem &item) {
|
||||
expect_tree_item_child_items(item, no_catalogs);
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -141,8 +141,8 @@ TEST_F(AssetCatalogTreeTest, foreach_in_tree)
|
|||
service.load_from_disk(asset_library_root_ + SEP_STR + "blender_assets.cats.txt");
|
||||
|
||||
std::vector<AssetCatalogPath> expected_root_items{{"character", "path"}};
|
||||
AssetCatalogTree *tree = service.get_catalog_tree();
|
||||
expect_tree_root_items(tree, expected_root_items);
|
||||
const AssetCatalogTree *tree = service.get_catalog_tree();
|
||||
expect_tree_root_items(*tree, expected_root_items);
|
||||
|
||||
/* Test if the direct children of the root item are what's expected. */
|
||||
std::vector<std::vector<AssetCatalogPath>> expected_root_child_items = {
|
||||
|
@ -152,8 +152,8 @@ TEST_F(AssetCatalogTreeTest, foreach_in_tree)
|
|||
{"path/without"},
|
||||
};
|
||||
int i = 0;
|
||||
tree->foreach_root_item([&expected_root_child_items, &i](AssetCatalogTreeItem &item) {
|
||||
expect_tree_item_child_items(&item, expected_root_child_items[i]);
|
||||
tree->foreach_root_item([&expected_root_child_items, &i](const AssetCatalogTreeItem &item) {
|
||||
expect_tree_item_child_items(item, expected_root_child_items[i]);
|
||||
i++;
|
||||
});
|
||||
}
|
||||
|
|
|
@ -99,7 +99,7 @@ class AssetCatalogTreeTestFunctions {
|
|||
* Recursively iterate over all tree items using #AssetCatalogTree::foreach_item() and check if
|
||||
* the items map exactly to \a expected_paths.
|
||||
*/
|
||||
static void expect_tree_items(AssetCatalogTree *tree,
|
||||
static void expect_tree_items(const AssetCatalogTree &tree,
|
||||
const std::vector<AssetCatalogPath> &expected_paths);
|
||||
|
||||
/**
|
||||
|
@ -107,7 +107,7 @@ class AssetCatalogTreeTestFunctions {
|
|||
* expected_paths. Similar to #assert_expected_tree_items() but calls
|
||||
* #AssetCatalogTree::foreach_root_item() instead of #AssetCatalogTree::foreach_item().
|
||||
*/
|
||||
static void expect_tree_root_items(AssetCatalogTree *tree,
|
||||
static void expect_tree_root_items(const AssetCatalogTree &tree,
|
||||
const std::vector<AssetCatalogPath> &expected_paths);
|
||||
|
||||
/**
|
||||
|
@ -115,7 +115,7 @@ class AssetCatalogTreeTestFunctions {
|
|||
* expected_paths. Similar to #assert_expected_tree_items() but calls
|
||||
* #AssetCatalogTreeItem::foreach_child() instead of #AssetCatalogTree::foreach_item().
|
||||
*/
|
||||
static void expect_tree_item_child_items(AssetCatalogTreeItem *parent_item,
|
||||
static void expect_tree_item_child_items(const AssetCatalogTreeItem &parent_item,
|
||||
const std::vector<AssetCatalogPath> &expected_paths);
|
||||
};
|
||||
|
||||
|
@ -139,10 +139,10 @@ static inline void compare_item_with_path(const AssetCatalogPath &expected_path,
|
|||
}
|
||||
|
||||
inline void AssetCatalogTreeTestFunctions::expect_tree_items(
|
||||
AssetCatalogTree *tree, const std::vector<AssetCatalogPath> &expected_paths)
|
||||
const AssetCatalogTree &tree, const std::vector<AssetCatalogPath> &expected_paths)
|
||||
{
|
||||
int i = 0;
|
||||
tree->foreach_item([&](const AssetCatalogTreeItem &actual_item) {
|
||||
tree.foreach_item([&](const AssetCatalogTreeItem &actual_item) {
|
||||
ASSERT_LT(i, expected_paths.size())
|
||||
<< "More catalogs in tree than expected; did not expect " << actual_item.catalog_path();
|
||||
compare_item_with_path(expected_paths[i], actual_item);
|
||||
|
@ -151,10 +151,10 @@ inline void AssetCatalogTreeTestFunctions::expect_tree_items(
|
|||
}
|
||||
|
||||
inline void AssetCatalogTreeTestFunctions::expect_tree_root_items(
|
||||
AssetCatalogTree *tree, const std::vector<AssetCatalogPath> &expected_paths)
|
||||
const AssetCatalogTree &tree, const std::vector<AssetCatalogPath> &expected_paths)
|
||||
{
|
||||
int i = 0;
|
||||
tree->foreach_root_item([&](const AssetCatalogTreeItem &actual_item) {
|
||||
tree.foreach_root_item([&](const AssetCatalogTreeItem &actual_item) {
|
||||
ASSERT_LT(i, expected_paths.size())
|
||||
<< "More catalogs in tree root than expected; did not expect "
|
||||
<< actual_item.catalog_path();
|
||||
|
@ -164,10 +164,10 @@ inline void AssetCatalogTreeTestFunctions::expect_tree_root_items(
|
|||
}
|
||||
|
||||
inline void AssetCatalogTreeTestFunctions::expect_tree_item_child_items(
|
||||
AssetCatalogTreeItem *parent_item, const std::vector<AssetCatalogPath> &expected_paths)
|
||||
const AssetCatalogTreeItem &parent_item, const std::vector<AssetCatalogPath> &expected_paths)
|
||||
{
|
||||
int i = 0;
|
||||
parent_item->foreach_child([&](const AssetCatalogTreeItem &actual_item) {
|
||||
parent_item.foreach_child([&](const AssetCatalogTreeItem &actual_item) {
|
||||
ASSERT_LT(i, expected_paths.size())
|
||||
<< "More catalogs in tree item than expected; did not expect "
|
||||
<< actual_item.catalog_path();
|
||||
|
|
|
@ -9,7 +9,9 @@
|
|||
#pragma once
|
||||
|
||||
#include "BLI_compiler_attrs.h"
|
||||
#include "BLI_string_ref.hh"
|
||||
#include "BLI_sys_types.h"
|
||||
#include "BLI_vector.hh"
|
||||
|
||||
/* Name of sub-directory inside #BLENDER_DATAFILES that contains font files. */
|
||||
#define BLF_DATAFILES_FONTS_DIR "fonts"
|
||||
|
@ -254,6 +256,10 @@ void BLF_rotation(int fontid, float angle);
|
|||
void BLF_clipping(int fontid, int xmin, int ymin, int xmax, int ymax);
|
||||
void BLF_wordwrap(int fontid, int wrap_width);
|
||||
|
||||
blender::Vector<blender::StringRef> BLF_string_wrap(int fontid,
|
||||
blender::StringRef str,
|
||||
const int max_pixel_width);
|
||||
|
||||
#if BLF_BLUR_ENABLE
|
||||
void BLF_blur(int fontid, int size);
|
||||
#endif
|
||||
|
|
|
@ -23,8 +23,6 @@ set(SRC
|
|||
intern/blf_font_default.cc
|
||||
intern/blf_glyph.cc
|
||||
intern/blf_thumbs.cc
|
||||
intern/blf_util.cc
|
||||
|
||||
BLF_api.hh
|
||||
intern/blf_internal.hh
|
||||
intern/blf_internal_types.hh
|
||||
|
|
|
@ -935,6 +935,17 @@ void BLF_draw_buffer(int fontid, const char *str, const size_t str_len)
|
|||
BLF_draw_buffer_ex(fontid, str, str_len, nullptr);
|
||||
}
|
||||
|
||||
blender::Vector<blender::StringRef> BLF_string_wrap(int fontid,
|
||||
blender::StringRef str,
|
||||
const int max_pixel_width)
|
||||
{
|
||||
FontBLF *font = blf_get(fontid);
|
||||
if (!font) {
|
||||
return {};
|
||||
}
|
||||
return blf_font_string_wrap(font, str, max_pixel_width);
|
||||
}
|
||||
|
||||
char *BLF_display_name_from_file(const char *filepath)
|
||||
{
|
||||
/* While listing font directories this function can be called simultaneously from a greater
|
||||
|
|
|
@ -37,6 +37,7 @@
|
|||
#include "BLI_string_cursor_utf8.h"
|
||||
#include "BLI_string_utf8.h"
|
||||
#include "BLI_threads.h"
|
||||
#include "BLI_vector.hh"
|
||||
|
||||
#include "BLF_api.hh"
|
||||
|
||||
|
@ -1085,6 +1086,7 @@ void blf_str_offset_to_glyph_bounds(FontBLF *font,
|
|||
static void blf_font_wrap_apply(FontBLF *font,
|
||||
const char *str,
|
||||
const size_t str_len,
|
||||
const int max_pixel_width,
|
||||
ResultBLF *r_info,
|
||||
void (*callback)(FontBLF *font,
|
||||
GlyphCacheBLF *gc,
|
||||
|
@ -1109,7 +1111,7 @@ static void blf_font_wrap_apply(FontBLF *font,
|
|||
struct WordWrapVars {
|
||||
ft_pix wrap_width;
|
||||
size_t start, last[2];
|
||||
} wrap = {font->wrap_width != -1 ? ft_pix_from_int(font->wrap_width) : INT_MAX, 0, {0, 0}};
|
||||
} wrap = {max_pixel_width != -1 ? ft_pix_from_int(max_pixel_width) : INT_MAX, 0, {0, 0}};
|
||||
|
||||
// printf("%s wrapping (%d, %d) `%s`:\n", __func__, str_len, strlen(str), str);
|
||||
while ((i < str_len) && str[i]) {
|
||||
|
@ -1198,7 +1200,8 @@ static void blf_font_draw__wrap_cb(FontBLF *font,
|
|||
}
|
||||
void blf_font_draw__wrap(FontBLF *font, const char *str, const size_t str_len, ResultBLF *r_info)
|
||||
{
|
||||
blf_font_wrap_apply(font, str, str_len, r_info, blf_font_draw__wrap_cb, nullptr);
|
||||
blf_font_wrap_apply(
|
||||
font, str, str_len, font->wrap_width, r_info, blf_font_draw__wrap_cb, nullptr);
|
||||
}
|
||||
|
||||
/** Utility for #blf_font_boundbox__wrap. */
|
||||
|
@ -1223,7 +1226,8 @@ void blf_font_boundbox__wrap(
|
|||
box->ymin = 32000;
|
||||
box->ymax = -32000;
|
||||
|
||||
blf_font_wrap_apply(font, str, str_len, r_info, blf_font_boundbox_wrap_cb, box);
|
||||
blf_font_wrap_apply(
|
||||
font, str, str_len, font->wrap_width, r_info, blf_font_boundbox_wrap_cb, box);
|
||||
}
|
||||
|
||||
/** Utility for #blf_font_draw_buffer__wrap. */
|
||||
|
@ -1241,7 +1245,37 @@ void blf_font_draw_buffer__wrap(FontBLF *font,
|
|||
const size_t str_len,
|
||||
ResultBLF *r_info)
|
||||
{
|
||||
blf_font_wrap_apply(font, str, str_len, r_info, blf_font_draw_buffer__wrap_cb, nullptr);
|
||||
blf_font_wrap_apply(
|
||||
font, str, str_len, font->wrap_width, r_info, blf_font_draw_buffer__wrap_cb, nullptr);
|
||||
}
|
||||
|
||||
/** Wrap a blender::StringRef. */
|
||||
static void blf_font_string_wrap_cb(FontBLF * /*font*/,
|
||||
GlyphCacheBLF * /*gc*/,
|
||||
const char *str,
|
||||
const size_t str_len,
|
||||
ft_pix /*pen_y*/,
|
||||
void *str_list_ptr)
|
||||
{
|
||||
blender::Vector<blender::StringRef> *list = static_cast<blender::Vector<blender::StringRef> *>(
|
||||
str_list_ptr);
|
||||
blender::StringRef line(str, str + str_len);
|
||||
list->append(line);
|
||||
}
|
||||
|
||||
blender::Vector<blender::StringRef> blf_font_string_wrap(FontBLF *font,
|
||||
blender::StringRef str,
|
||||
int max_pixel_width)
|
||||
{
|
||||
blender::Vector<blender::StringRef> list;
|
||||
blf_font_wrap_apply(font,
|
||||
str.data(),
|
||||
size_t(str.size()),
|
||||
max_pixel_width,
|
||||
nullptr,
|
||||
blf_font_string_wrap_cb,
|
||||
&list);
|
||||
return list;
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
|
|
@ -75,10 +75,10 @@ static float from_16dot16(FT_Fixed value)
|
|||
/** \name Glyph Cache
|
||||
* \{ */
|
||||
|
||||
static GlyphCacheBLF *blf_glyph_cache_find(FontBLF *font, const float size)
|
||||
static GlyphCacheBLF *blf_glyph_cache_find(FontBLF *font)
|
||||
{
|
||||
for (std::unique_ptr<GlyphCacheBLF> &gc : font->cache) {
|
||||
if (gc->size == size && (gc->bold == ((font->flags & BLF_BOLD) != 0)) &&
|
||||
if (gc->size == font->size && (gc->bold == ((font->flags & BLF_BOLD) != 0)) &&
|
||||
(gc->italic == ((font->flags & BLF_ITALIC) != 0)) &&
|
||||
(gc->char_weight == font->char_weight) && (gc->char_slant == font->char_slant) &&
|
||||
(gc->char_width == font->char_width) && (gc->char_spacing == font->char_spacing))
|
||||
|
@ -91,7 +91,7 @@ static GlyphCacheBLF *blf_glyph_cache_find(FontBLF *font, const float size)
|
|||
|
||||
static GlyphCacheBLF *blf_glyph_cache_new(FontBLF *font)
|
||||
{
|
||||
std::unique_ptr<GlyphCacheBLF> gc = std::make_unique<GlyphCacheBLF>(GlyphCacheBLF{});
|
||||
std::unique_ptr<GlyphCacheBLF> gc = std::make_unique<GlyphCacheBLF>();
|
||||
|
||||
gc->size = font->size;
|
||||
gc->bold = ((font->flags & BLF_BOLD) != 0);
|
||||
|
@ -101,8 +101,6 @@ static GlyphCacheBLF *blf_glyph_cache_new(FontBLF *font)
|
|||
gc->char_width = font->char_width;
|
||||
gc->char_spacing = font->char_spacing;
|
||||
|
||||
memset(gc->bucket, 0, sizeof(gc->bucket));
|
||||
|
||||
blf_ensure_size(font);
|
||||
|
||||
/* Determine ideal fixed-width size for monospaced output. */
|
||||
|
@ -130,7 +128,7 @@ GlyphCacheBLF *blf_glyph_cache_acquire(FontBLF *font)
|
|||
{
|
||||
font->glyph_cache_mutex.lock();
|
||||
|
||||
GlyphCacheBLF *gc = blf_glyph_cache_find(font, font->size);
|
||||
GlyphCacheBLF *gc = blf_glyph_cache_find(font);
|
||||
|
||||
if (!gc) {
|
||||
gc = blf_glyph_cache_new(font);
|
||||
|
@ -146,11 +144,7 @@ void blf_glyph_cache_release(FontBLF *font)
|
|||
|
||||
GlyphCacheBLF::~GlyphCacheBLF()
|
||||
{
|
||||
for (uint i = 0; i < ARRAY_SIZE(this->bucket); i++) {
|
||||
while (GlyphBLF *g = static_cast<GlyphBLF *>(BLI_pophead(&this->bucket[i]))) {
|
||||
blf_glyph_free(g);
|
||||
}
|
||||
}
|
||||
this->glyphs.clear_and_shrink();
|
||||
if (this->texture) {
|
||||
GPU_texture_free(this->texture);
|
||||
}
|
||||
|
@ -174,12 +168,10 @@ static GlyphBLF *blf_glyph_cache_find_glyph(const GlyphCacheBLF *gc,
|
|||
uint charcode,
|
||||
uint8_t subpixel)
|
||||
{
|
||||
GlyphBLF *g = static_cast<GlyphBLF *>(gc->bucket[blf_hash(charcode << 6 | subpixel)].first);
|
||||
while (g) {
|
||||
if (g->c == charcode && g->subpixel == subpixel) {
|
||||
return g;
|
||||
}
|
||||
g = g->next;
|
||||
const std::unique_ptr<GlyphBLF> *ptr = gc->glyphs.lookup_ptr_as(
|
||||
GlyphCacheKey{charcode, subpixel});
|
||||
if (ptr != nullptr) {
|
||||
return ptr->get();
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
@ -231,7 +223,7 @@ static GlyphBLF *blf_glyph_cache_add_glyph(FontBLF *font,
|
|||
FT_UInt glyph_index,
|
||||
uint8_t subpixel)
|
||||
{
|
||||
GlyphBLF *g = (GlyphBLF *)MEM_callocN(sizeof(GlyphBLF), "blf_glyph_get");
|
||||
std::unique_ptr<GlyphBLF> g = std::make_unique<GlyphBLF>();
|
||||
g->c = charcode;
|
||||
g->idx = glyph_index;
|
||||
g->advance_x = (ft_pix)glyph->advance.x;
|
||||
|
@ -344,9 +336,9 @@ static GlyphBLF *blf_glyph_cache_add_glyph(FontBLF *font,
|
|||
}
|
||||
}
|
||||
|
||||
BLI_addhead(&(gc->bucket[blf_hash(g->c << 6 | subpixel)]), g);
|
||||
|
||||
return g;
|
||||
GlyphCacheKey key = {charcode, subpixel};
|
||||
gc->glyphs.add(key, std::move(g));
|
||||
return gc->glyphs.lookup(key).get();
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
@ -1277,10 +1269,7 @@ static FT_GlyphSlot blf_glyph_render(FontBLF *settings_font,
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
static GlyphBLF *blf_glyph_ensure_ex(FontBLF *font,
|
||||
GlyphCacheBLF *gc,
|
||||
const uint charcode,
|
||||
uint8_t subpixel)
|
||||
GlyphBLF *blf_glyph_ensure(FontBLF *font, GlyphCacheBLF *gc, const uint charcode, uint8_t subpixel)
|
||||
{
|
||||
GlyphBLF *g = blf_glyph_cache_find_glyph(gc, charcode, subpixel);
|
||||
if (g) {
|
||||
|
@ -1306,11 +1295,6 @@ static GlyphBLF *blf_glyph_ensure_ex(FontBLF *font,
|
|||
return g;
|
||||
}
|
||||
|
||||
GlyphBLF *blf_glyph_ensure(FontBLF *font, GlyphCacheBLF *gc, const uint charcode)
|
||||
{
|
||||
return blf_glyph_ensure_ex(font, gc, charcode, 0);
|
||||
}
|
||||
|
||||
#ifdef BLF_SUBPIXEL_AA
|
||||
GlyphBLF *blf_glyph_ensure_subpixel(FontBLF *font, GlyphCacheBLF *gc, GlyphBLF *g, int32_t pen_x)
|
||||
{
|
||||
|
@ -1328,18 +1312,17 @@ GlyphBLF *blf_glyph_ensure_subpixel(FontBLF *font, GlyphCacheBLF *gc, GlyphBLF *
|
|||
const uint8_t subpixel = uint8_t(pen_x & ((font->size > 16.0f) ? 32L : 48L));
|
||||
|
||||
if (g->subpixel != subpixel) {
|
||||
g = blf_glyph_ensure_ex(font, gc, g->c, subpixel);
|
||||
g = blf_glyph_ensure(font, gc, g->c, subpixel);
|
||||
}
|
||||
return g;
|
||||
}
|
||||
#endif
|
||||
|
||||
void blf_glyph_free(GlyphBLF *g)
|
||||
GlyphBLF::~GlyphBLF()
|
||||
{
|
||||
if (g->bitmap) {
|
||||
MEM_freeN(g->bitmap);
|
||||
if (this->bitmap) {
|
||||
MEM_freeN(this->bitmap);
|
||||
}
|
||||
MEM_freeN(g);
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
|
|
@ -8,6 +8,9 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "BLI_string_ref.hh"
|
||||
#include "BLI_vector.hh"
|
||||
|
||||
struct FontBLF;
|
||||
struct GlyphBLF;
|
||||
struct GlyphCacheBLF;
|
||||
|
@ -51,8 +54,6 @@ extern struct FontBLF *global_font[BLF_MAX_FONT];
|
|||
void blf_batch_draw_begin(struct FontBLF *font);
|
||||
void blf_batch_draw(void);
|
||||
|
||||
unsigned int blf_next_p2(unsigned int x);
|
||||
unsigned int blf_hash(unsigned int val);
|
||||
/**
|
||||
* Some font have additional file with metrics information,
|
||||
* in general, the extension of the file is: `.afm` or `.pfm`
|
||||
|
@ -96,6 +97,10 @@ void blf_font_draw__wrap(struct FontBLF *font,
|
|||
size_t str_len,
|
||||
struct ResultBLF *r_info);
|
||||
|
||||
blender::Vector<blender::StringRef> blf_font_string_wrap(FontBLF *font,
|
||||
blender::StringRef str,
|
||||
int max_pixel_width);
|
||||
|
||||
/**
|
||||
* Use fixed column width, but an utf8 character may occupy multiple columns.
|
||||
*/
|
||||
|
@ -173,7 +178,10 @@ void blf_glyph_cache_clear(struct FontBLF *font);
|
|||
/**
|
||||
* Create (or load from cache) a fully-rendered bitmap glyph.
|
||||
*/
|
||||
struct GlyphBLF *blf_glyph_ensure(struct FontBLF *font, struct GlyphCacheBLF *gc, uint charcode);
|
||||
struct GlyphBLF *blf_glyph_ensure(struct FontBLF *font,
|
||||
struct GlyphCacheBLF *gc,
|
||||
uint charcode,
|
||||
uint8_t subpixel = 0);
|
||||
|
||||
#ifdef BLF_SUBPIXEL_AA
|
||||
struct GlyphBLF *blf_glyph_ensure_subpixel(struct FontBLF *font,
|
||||
|
@ -190,7 +198,6 @@ float blf_character_to_curves(FontBLF *font,
|
|||
struct ListBase *nurbsbase,
|
||||
const float scale);
|
||||
|
||||
void blf_glyph_free(struct GlyphBLF *g);
|
||||
void blf_glyph_draw(
|
||||
struct FontBLF *font, struct GlyphCacheBLF *gc, struct GlyphBLF *g, int x, int y);
|
||||
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
|
||||
#include <mutex>
|
||||
|
||||
#include "BLI_map.hh"
|
||||
#include "BLI_vector.hh"
|
||||
|
||||
#include "GPU_texture.h"
|
||||
|
@ -116,6 +117,19 @@ struct KerningCacheBLF {
|
|||
int ascii_table[KERNING_CACHE_TABLE_SIZE][KERNING_CACHE_TABLE_SIZE];
|
||||
};
|
||||
|
||||
struct GlyphCacheKey {
|
||||
uint charcode;
|
||||
uint8_t subpixel;
|
||||
friend bool operator==(const GlyphCacheKey &a, const GlyphCacheKey &b)
|
||||
{
|
||||
return a.charcode == b.charcode && a.subpixel == b.subpixel;
|
||||
}
|
||||
uint64_t hash() const
|
||||
{
|
||||
return blender::get_default_hash(charcode, subpixel);
|
||||
}
|
||||
};
|
||||
|
||||
struct GlyphCacheBLF {
|
||||
/** Font size. */
|
||||
float size;
|
||||
|
@ -132,7 +146,7 @@ struct GlyphCacheBLF {
|
|||
int fixed_width;
|
||||
|
||||
/** The glyphs. */
|
||||
ListBase bucket[257];
|
||||
blender::Map<GlyphCacheKey, std::unique_ptr<GlyphBLF>> glyphs;
|
||||
|
||||
/** Texture array, to draw the glyphs. */
|
||||
GPUTexture *texture;
|
||||
|
@ -145,9 +159,6 @@ struct GlyphCacheBLF {
|
|||
};
|
||||
|
||||
struct GlyphBLF {
|
||||
GlyphBLF *next;
|
||||
GlyphBLF *prev;
|
||||
|
||||
/** The character, as UTF-32. */
|
||||
unsigned int c;
|
||||
|
||||
|
@ -192,6 +203,8 @@ struct GlyphBLF {
|
|||
int pos[2];
|
||||
|
||||
GlyphCacheBLF *glyph_cache;
|
||||
|
||||
~GlyphBLF();
|
||||
};
|
||||
|
||||
struct FontBufInfoBLF {
|
||||
|
|
|
@ -1,43 +0,0 @@
|
|||
/* SPDX-FileCopyrightText: 2009 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
/** \file
|
||||
* \ingroup blf
|
||||
*
|
||||
* Internal utility API for BLF.
|
||||
*/
|
||||
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
|
||||
#include "BLI_utildefines.h"
|
||||
|
||||
#include "blf_internal.hh"
|
||||
|
||||
uint blf_next_p2(uint x)
|
||||
{
|
||||
x -= 1;
|
||||
x |= (x >> 16);
|
||||
x |= (x >> 8);
|
||||
x |= (x >> 4);
|
||||
x |= (x >> 2);
|
||||
x |= (x >> 1);
|
||||
x += 1;
|
||||
return x;
|
||||
}
|
||||
|
||||
uint blf_hash(uint val)
|
||||
{
|
||||
uint key;
|
||||
|
||||
key = val;
|
||||
key += ~(key << 16);
|
||||
key ^= (key >> 5);
|
||||
key += (key << 3);
|
||||
key ^= (key >> 13);
|
||||
key += ~(key << 9);
|
||||
key ^= (key >> 17);
|
||||
return key % 257;
|
||||
}
|
|
@ -176,7 +176,7 @@ enum {
|
|||
BLENDER_SYSTEM_PYTHON = 54,
|
||||
};
|
||||
|
||||
/* for BKE_appdir_folder_id_version only */
|
||||
/** For #BKE_appdir_folder_id_version only. */
|
||||
enum {
|
||||
BLENDER_RESOURCE_PATH_USER = 0,
|
||||
BLENDER_RESOURCE_PATH_LOCAL = 1,
|
||||
|
|
|
@ -76,6 +76,5 @@ PreviewImage *BKE_asset_metadata_preview_get_from_id(const AssetMetaData *asset_
|
|||
void BKE_asset_metadata_write(BlendWriter *writer, AssetMetaData *asset_data);
|
||||
void BKE_asset_metadata_read(BlendDataReader *reader, AssetMetaData *asset_data);
|
||||
|
||||
AssetWeakReference *BKE_asset_weak_reference_copy(AssetWeakReference *weak_ref);
|
||||
void BKE_asset_weak_reference_write(BlendWriter *writer, const AssetWeakReference *weak_ref);
|
||||
void BKE_asset_weak_reference_read(BlendDataReader *reader, AssetWeakReference *weak_ref);
|
||||
|
|
|
@ -29,7 +29,7 @@ extern "C" {
|
|||
|
||||
/* Blender file format version. */
|
||||
#define BLENDER_FILE_VERSION BLENDER_VERSION
|
||||
#define BLENDER_FILE_SUBVERSION 3
|
||||
#define BLENDER_FILE_SUBVERSION 6
|
||||
|
||||
/* Minimum Blender version that supports reading file written with the current
|
||||
* version. Older Blender versions will test this and cancel loading the file, showing a warning to
|
||||
|
|
|
@ -122,6 +122,20 @@ void BKE_bvhtree_from_mesh_tris_init(const Mesh &mesh,
|
|||
const blender::IndexMask &faces_mask,
|
||||
BVHTreeFromMesh &r_data);
|
||||
|
||||
/**
|
||||
* Build a bvh tree containing the given edges.
|
||||
*/
|
||||
void BKE_bvhtree_from_mesh_edges_init(const Mesh &mesh,
|
||||
const blender::IndexMask &edges_mask,
|
||||
BVHTreeFromMesh &r_data);
|
||||
|
||||
/**
|
||||
* Build a bvh tree containing the given vertices.
|
||||
*/
|
||||
void BKE_bvhtree_from_mesh_verts_init(const Mesh &mesh,
|
||||
const blender::IndexMask &verts_mask,
|
||||
BVHTreeFromMesh &r_data);
|
||||
|
||||
/**
|
||||
* Frees data allocated by a call to `bvhtree_from_mesh_*`.
|
||||
*/
|
||||
|
@ -147,9 +161,9 @@ struct BVHTreeFromPointCloud {
|
|||
const float (*coords)[3];
|
||||
};
|
||||
|
||||
[[nodiscard]] BVHTree *BKE_bvhtree_from_pointcloud_get(BVHTreeFromPointCloud *data,
|
||||
const PointCloud *pointcloud,
|
||||
int tree_type);
|
||||
void BKE_bvhtree_from_pointcloud_get(const PointCloud &pointcloud,
|
||||
const blender::IndexMask &points_mask,
|
||||
BVHTreeFromPointCloud &r_data);
|
||||
|
||||
void free_bvhtree_from_pointcloud(BVHTreeFromPointCloud *data);
|
||||
|
||||
|
|
|
@ -110,6 +110,7 @@ enum eCbEvent {
|
|||
BKE_CB_EVT_EXTENSION_REPOS_UPDATE_POST,
|
||||
BKE_CB_EVT_EXTENSION_REPOS_SYNC,
|
||||
BKE_CB_EVT_EXTENSION_REPOS_UPGRADE,
|
||||
BKE_CB_EVT_EXTENSION_DROP_URL,
|
||||
BKE_CB_EVT_TOT,
|
||||
};
|
||||
|
||||
|
|
|
@ -812,4 +812,5 @@ void CustomData_debug_info_from_layers(const CustomData *data, const char *inden
|
|||
|
||||
namespace blender::bke {
|
||||
std::optional<VolumeGridType> custom_data_type_to_volume_grid_type(eCustomDataType type);
|
||||
std::optional<eCustomDataType> volume_grid_type_to_custom_data_type(VolumeGridType type);
|
||||
} // namespace blender::bke
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
#include "BLI_math_matrix_types.hh"
|
||||
#include "BLI_shared_cache.hh"
|
||||
#include "BLI_vector.hh"
|
||||
#include "BLI_virtual_array_fwd.hh"
|
||||
|
||||
#include "DNA_customdata_types.h"
|
||||
|
||||
|
@ -99,8 +100,7 @@ class Instances {
|
|||
*/
|
||||
Vector<InstanceReference> references_;
|
||||
|
||||
/** Transformation of the instances. */
|
||||
Vector<float4x4> transforms_;
|
||||
int instances_num_ = 0;
|
||||
|
||||
CustomData attributes_;
|
||||
|
||||
|
@ -159,8 +159,8 @@ class Instances {
|
|||
|
||||
Span<int> reference_handles() const;
|
||||
MutableSpan<int> reference_handles_for_write();
|
||||
MutableSpan<float4x4> transforms();
|
||||
Span<float4x4> transforms() const;
|
||||
MutableSpan<float4x4> transforms_for_write();
|
||||
|
||||
int instances_num() const;
|
||||
int references_num() const;
|
||||
|
@ -193,6 +193,9 @@ class Instances {
|
|||
}
|
||||
};
|
||||
|
||||
VArray<float3> instance_position_varray(const Instances &instances);
|
||||
VMutableArray<float3> instance_position_varray_for_write(Instances &instances);
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name #InstanceReference Inline Methods
|
||||
* \{ */
|
||||
|
|
|
@ -31,9 +31,9 @@
|
|||
*/
|
||||
|
||||
#include "BLI_compiler_attrs.h"
|
||||
#include "BLI_utildefines.h"
|
||||
|
||||
#include "BLI_set.hh"
|
||||
#include "BLI_utildefines.h"
|
||||
#include "BLI_vector.hh"
|
||||
|
||||
#include "DNA_userdef_enums.h"
|
||||
|
||||
|
@ -662,9 +662,8 @@ bool BKE_id_is_editable(const Main *bmain, const ID *id);
|
|||
|
||||
/**
|
||||
* Returns ordered list of data-blocks for display in the UI.
|
||||
* Result is list of #LinkData of IDs that must be freed.
|
||||
*/
|
||||
void BKE_id_ordered_list(ListBase *ordered_lb, const ListBase *lb);
|
||||
blender::Vector<ID *> BKE_id_ordered_list(const ListBase *lb);
|
||||
/**
|
||||
* Reorder ID in the list, before or after the "relative" ID.
|
||||
*/
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
|
||||
#include "DNA_ID.h"
|
||||
|
||||
#include "BLI_function_ref.hh"
|
||||
#include "BLI_sys_types.h"
|
||||
|
||||
#include <array>
|
||||
|
@ -324,15 +325,24 @@ void BKE_library_ID_test_usages(Main *bmain,
|
|||
/** Parameters and result data structure for the 'unused IDs' functions below. */
|
||||
struct LibQueryUnusedIDsData {
|
||||
/** Process local data-blocks. */
|
||||
bool do_local_ids;
|
||||
bool do_local_ids = false;
|
||||
/** Process linked data-blocks. */
|
||||
bool do_linked_ids;
|
||||
bool do_linked_ids = false;
|
||||
/**
|
||||
* Process all actually unused data-blocks, including these that are currently only used by
|
||||
* other unused data-blocks, and 'dependency islands' of several data-blocks using each-other,
|
||||
* without any external valid user.
|
||||
*/
|
||||
bool do_recursive;
|
||||
bool do_recursive = false;
|
||||
|
||||
/**
|
||||
* Callback filter, if defined and it returns `true`, the given `id` may be considered as unused,
|
||||
* otherwise it will always be considered as used.
|
||||
*
|
||||
* Allows for more complex handling of which IDs should be deleted, on top of the basic
|
||||
* local/linked choices.
|
||||
*/
|
||||
blender::FunctionRef<bool(ID *id)> filter_fn = nullptr;
|
||||
|
||||
/**
|
||||
* Amount of detected as unused data-blocks, per type and total as the last value of the array
|
||||
|
|
|
@ -15,3 +15,9 @@ struct Library;
|
|||
struct Main;
|
||||
|
||||
void BKE_library_filepath_set(Main *bmain, Library *lib, const char *filepath);
|
||||
|
||||
/**
|
||||
* Rebuild the hierarchy of libraries, after e.g. deleting or relocating one, often some indirectly
|
||||
* linked libraries lose their 'parent' pointer, making them wrongly directly used ones.
|
||||
*/
|
||||
void BKE_library_main_rebuild_hierarchy(Main *bmain);
|
||||
|
|
|
@ -1329,6 +1329,7 @@ void BKE_nodetree_remove_layer_n(struct bNodeTree *ntree, struct Scene *scene, i
|
|||
#define GEO_NODE_STORE_NAMED_GRID 2122
|
||||
#define GEO_NODE_SORT_ELEMENTS 2123
|
||||
#define GEO_NODE_MENU_SWITCH 2124
|
||||
#define GEO_NODE_SAMPLE_GRID 2125
|
||||
|
||||
/** \} */
|
||||
|
||||
|
|
|
@ -481,6 +481,11 @@ inline const bNode *bNodeTree::group_output_node() const
|
|||
return this->runtime->group_output_node;
|
||||
}
|
||||
|
||||
inline blender::Span<bNode *> bNodeTree::group_input_nodes()
|
||||
{
|
||||
return this->nodes_by_type("NodeGroupInput");
|
||||
}
|
||||
|
||||
inline blender::Span<const bNode *> bNodeTree::group_input_nodes() const
|
||||
{
|
||||
return this->nodes_by_type("NodeGroupInput");
|
||||
|
|
|
@ -13,6 +13,7 @@ extern "C" {
|
|||
#endif
|
||||
|
||||
#include "BLI_compiler_attrs.h"
|
||||
#include "BLI_sys_types.h"
|
||||
|
||||
struct UserDef;
|
||||
struct bUserExtensionRepo;
|
||||
|
@ -84,6 +85,8 @@ bUserExtensionRepo *BKE_preferences_extension_repo_add(UserDef *userdef,
|
|||
const char *module,
|
||||
const char *custom_dirpath);
|
||||
void BKE_preferences_extension_repo_remove(UserDef *userdef, bUserExtensionRepo *repo);
|
||||
bUserExtensionRepo *BKE_preferences_extension_repo_add_default(UserDef *userdef);
|
||||
bUserExtensionRepo *BKE_preferences_extension_repo_add_default_user(UserDef *userdef);
|
||||
|
||||
void BKE_preferences_extension_repo_name_set(UserDef *userdef,
|
||||
bUserExtensionRepo *repo,
|
||||
|
@ -93,13 +96,27 @@ void BKE_preferences_extension_repo_module_set(UserDef *userdef,
|
|||
const char *module);
|
||||
|
||||
void BKE_preferences_extension_repo_custom_dirpath_set(bUserExtensionRepo *repo, const char *path);
|
||||
void BKE_preferences_extension_repo_dirpath_get(const bUserExtensionRepo *repo,
|
||||
char *dirpath,
|
||||
int dirpath_maxncpy);
|
||||
size_t BKE_preferences_extension_repo_dirpath_get(const bUserExtensionRepo *repo,
|
||||
char *dirpath,
|
||||
int dirpath_maxncpy);
|
||||
|
||||
bUserExtensionRepo *BKE_preferences_extension_repo_find_index(const UserDef *userdef, int index);
|
||||
bUserExtensionRepo *BKE_preferences_extension_repo_find_by_module(const UserDef *userdef,
|
||||
const char *module);
|
||||
/**
|
||||
* Using a full URL/remote path to find a repository that shares its prefix.
|
||||
*/
|
||||
bUserExtensionRepo *BKE_preferences_extension_repo_find_by_remote_path_prefix(
|
||||
const UserDef *userdef, const char *remote_path_full, const bool only_enabled);
|
||||
/**
|
||||
* Skip the `https` or `http` part of a URL `https://`, return zero if none is found.
|
||||
*/
|
||||
int BKE_preferences_extension_repo_remote_scheme_end(const char *url);
|
||||
/**
|
||||
* Set a name based on a URL, e.g. `https://www.example.com/path` -> `www.example.com`.
|
||||
*/
|
||||
void BKE_preferences_extension_remote_to_name(const char *remote_path, char name[64]);
|
||||
|
||||
int BKE_preferences_extension_repo_get_index(const UserDef *userdef,
|
||||
const bUserExtensionRepo *repo);
|
||||
|
||||
|
|
|
@ -41,24 +41,24 @@ struct ReportList;
|
|||
struct Scene;
|
||||
struct SwsContext;
|
||||
|
||||
int BKE_ffmpeg_start(void *context_v,
|
||||
const Scene *scene,
|
||||
RenderData *rd,
|
||||
int rectx,
|
||||
int recty,
|
||||
ReportList *reports,
|
||||
bool preview,
|
||||
const char *suffix);
|
||||
void BKE_ffmpeg_end(void *context_v);
|
||||
int BKE_ffmpeg_append(void *context_v,
|
||||
struct ImBuf;
|
||||
|
||||
bool BKE_ffmpeg_start(void *context_v,
|
||||
const Scene *scene,
|
||||
RenderData *rd,
|
||||
int start_frame,
|
||||
int frame,
|
||||
int *pixels,
|
||||
int rectx,
|
||||
int recty,
|
||||
const char *suffix,
|
||||
ReportList *reports);
|
||||
ReportList *reports,
|
||||
bool preview,
|
||||
const char *suffix);
|
||||
void BKE_ffmpeg_end(void *context_v);
|
||||
bool BKE_ffmpeg_append(void *context_v,
|
||||
RenderData *rd,
|
||||
int start_frame,
|
||||
int frame,
|
||||
const ImBuf *image,
|
||||
const char *suffix,
|
||||
ReportList *reports);
|
||||
void BKE_ffmpeg_filepath_get(char filepath[/*FILE_MAX*/ 1024],
|
||||
const RenderData *rd,
|
||||
bool preview,
|
||||
|
|
|
@ -8,45 +8,40 @@
|
|||
* \ingroup bke
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* generic blender movie support, could move to own module */
|
||||
|
||||
struct ImBuf;
|
||||
struct RenderData;
|
||||
struct ReportList;
|
||||
struct Scene;
|
||||
|
||||
typedef struct bMovieHandle {
|
||||
int (*start_movie)(void *context_v,
|
||||
const struct Scene *scene,
|
||||
struct RenderData *rd,
|
||||
int rectx,
|
||||
int recty,
|
||||
struct ReportList *reports,
|
||||
bool preview,
|
||||
const char *suffix);
|
||||
int (*append_movie)(void *context_v,
|
||||
struct RenderData *rd,
|
||||
int start_frame,
|
||||
int frame,
|
||||
int *pixels,
|
||||
struct bMovieHandle {
|
||||
bool (*start_movie)(void *context_v,
|
||||
const Scene *scene,
|
||||
RenderData *rd,
|
||||
int rectx,
|
||||
int recty,
|
||||
const char *suffix,
|
||||
struct ReportList *reports);
|
||||
ReportList *reports,
|
||||
bool preview,
|
||||
const char *suffix);
|
||||
bool (*append_movie)(void *context_v,
|
||||
RenderData *rd,
|
||||
int start_frame,
|
||||
int frame,
|
||||
const ImBuf *image,
|
||||
const char *suffix,
|
||||
ReportList *reports);
|
||||
void (*end_movie)(void *context_v);
|
||||
|
||||
/* Optional function. */
|
||||
void (*get_movie_path)(char filepath[/*FILE_MAX*/ 1024],
|
||||
const struct RenderData *rd,
|
||||
const RenderData *rd,
|
||||
bool preview,
|
||||
const char *suffix);
|
||||
|
||||
void *(*context_create)(void);
|
||||
void (*context_free)(void *context_v);
|
||||
} bMovieHandle;
|
||||
};
|
||||
|
||||
bMovieHandle *BKE_movie_handle_get(char imtype);
|
||||
|
||||
|
@ -54,10 +49,6 @@ bMovieHandle *BKE_movie_handle_get(char imtype);
|
|||
* \note Similar to #BKE_image_path_from_imformat()
|
||||
*/
|
||||
void BKE_movie_filepath_get(char filepath[/*FILE_MAX*/ 1024],
|
||||
const struct RenderData *rd,
|
||||
const RenderData *rd,
|
||||
bool preview,
|
||||
const char *suffix);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
|
@ -318,7 +318,7 @@ set(SRC
|
|||
intern/wm_runtime.cc
|
||||
intern/workspace.cc
|
||||
intern/world.cc
|
||||
intern/writeavi.cc
|
||||
intern/writemovie.cc
|
||||
|
||||
BKE_DerivedMesh.hh
|
||||
BKE_action.h
|
||||
|
@ -526,7 +526,7 @@ set(SRC
|
|||
BKE_wm_runtime.hh
|
||||
BKE_workspace.h
|
||||
BKE_world.h
|
||||
BKE_writeavi.h
|
||||
BKE_writemovie.hh
|
||||
|
||||
nla_private.h
|
||||
particle_private.h
|
||||
|
@ -644,13 +644,6 @@ if(WITH_IMAGE_WEBP)
|
|||
add_definitions(-DWITH_WEBP)
|
||||
endif()
|
||||
|
||||
if(WITH_CODEC_AVI)
|
||||
list(APPEND INC
|
||||
../io/avi
|
||||
)
|
||||
add_definitions(-DWITH_AVI)
|
||||
endif()
|
||||
|
||||
if(WITH_CODEC_FFMPEG)
|
||||
list(APPEND SRC
|
||||
intern/writeffmpeg.cc
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue