Merge branch 'master' into temp_bmesh_multires

This commit is contained in:
Joseph Eagar 2021-08-15 18:14:41 -07:00
commit ab632243e6
286 changed files with 4787 additions and 2513 deletions

View File

@ -84,7 +84,7 @@ include(cmake/openimageio.cmake)
include(cmake/tiff.cmake)
if(WIN32)
include(cmake/flexbison.cmake)
else()
elseif(UNIX AND NOT APPLE)
include(cmake/flex.cmake)
endif()
include(cmake/osl.cmake)

View File

@ -29,13 +29,13 @@ elseif(APPLE)
if("${CMAKE_HOST_SYSTEM_PROCESSOR}" STREQUAL "arm64")
set(ISPC_EXTRA_ARGS_APPLE
-DBISON_EXECUTABLE=/opt/homebrew/opt/bison/bin/bison
-DFLEX_EXECUTABLE=${LIBDIR}/flex/bin/flex
-DFLEX_EXECUTABLE=/opt/homebrew/opt/flex/bin/flex
-DARM_ENABLED=On
)
else()
set(ISPC_EXTRA_ARGS_APPLE
-DBISON_EXECUTABLE=/usr/local/opt/bison/bin/bison
-DFLEX_EXECUTABLE=${LIBDIR}/flex/bin/flex
-DFLEX_EXECUTABLE=/usr/local/opt/flex/bin/flex
-DARM_ENABLED=Off
)
endif()
@ -84,7 +84,7 @@ if(WIN32)
external_ispc
external_flexbison
)
else()
elseif(UNIX AND NOT APPLE)
add_dependencies(
external_ispc
external_flex

View File

@ -16,12 +16,18 @@
#
# ***** END GPL LICENSE BLOCK *****
if(APPLE)
set(OPENMP_PATCH_COMMAND ${PATCH_CMD} -p 1 -d ${BUILD_DIR}/openmp/src/external_openmp < ${PATCH_DIR}/openmp.diff)
else()
set(OPENMP_PATCH_COMMAND)
endif()
ExternalProject_Add(external_openmp
URL file://${PACKAGE_DIR}/${OPENMP_FILE}
DOWNLOAD_DIR ${DOWNLOAD_DIR}
URL_HASH ${OPENMP_HASH_TYPE}=${OPENMP_HASH}
PREFIX ${BUILD_DIR}/openmp
PATCH_COMMAND ${OPENMP_PATCH_COMMAND}
CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${LIBDIR}/openmp ${DEFAULT_CMAKE_FLAGS}
INSTALL_COMMAND cd ${BUILD_DIR}/openmp/src/external_openmp-build && install_name_tool -id @rpath/libomp.dylib runtime/src/libomp.dylib && make install
INSTALL_DIR ${LIBDIR}/openmp

View File

@ -96,7 +96,7 @@ if(WIN32)
external_osl
external_flexbison
)
else()
elseif(UNIX AND NOT APPLE)
add_dependencies(
external_osl
external_flex

View File

@ -23,7 +23,7 @@ set(PNG_EXTRA_ARGS
)
if(BLENDER_PLATFORM_ARM)
set(PNG_EXTRA_ARGS ${PNG_EXTRA_ARGS} -DPNG_HARDWARE_OPTIMIZATIONS=ON -DPNG_ARM_NEON=ON -DCMAKE_SYSTEM_PROCESSOR="aarch64")
set(PNG_EXTRA_ARGS ${PNG_EXTRA_ARGS} -DPNG_HARDWARE_OPTIMIZATIONS=ON -DPNG_ARM_NEON=on -DCMAKE_SYSTEM_PROCESSOR="aarch64")
endif()
ExternalProject_Add(external_png

View File

@ -158,10 +158,18 @@ set(LLVM_HASH 5a4fab4d7fc84aefffb118ac2c8a4fc0)
set(LLVM_HASH_TYPE MD5)
set(LLVM_FILE llvm-project-${LLVM_VERSION}.src.tar.xz)
set(OPENMP_URI https://github.com/llvm/llvm-project/releases/download/llvmorg-${LLVM_VERSION}/openmp-${LLVM_VERSION}.src.tar.xz)
set(OPENMP_HASH ac48ce3e4582ccb82f81ab59eb3fc9dc)
if(APPLE)
# Cloth physics test is crashing due to this bug:
# https://bugs.llvm.org/show_bug.cgi?id=50579
set(OPENMP_VERSION 9.0.1)
set(OPENMP_HASH 6eade16057edbdecb3c4eef9daa2bfcf)
else()
set(OPENMP_VERSION ${LLVM_VERSION})
set(OPENMP_HASH ac48ce3e4582ccb82f81ab59eb3fc9dc)
endif()
set(OPENMP_URI https://github.com/llvm/llvm-project/releases/download/llvmorg-${OPENMP_VERSION}/openmp-${OPENMP_VERSION}.src.tar.xz)
set(OPENMP_HASH_TYPE MD5)
set(OPENMP_FILE openmp-${LLVM_VERSION}.src.tar.xz)
set(OPENMP_FILE openmp-${OPENMP_VERSION}.src.tar.xz)
set(OPENIMAGEIO_VERSION 2.2.15.1)
set(OPENIMAGEIO_URI https://github.com/OpenImageIO/oiio/archive/Release-${OPENIMAGEIO_VERSION}.tar.gz)

View File

@ -0,0 +1,23 @@
diff --git a/runtime/src/z_Linux_asm.S b/runtime/src/z_Linux_asm.S
index 0d8885e..42aa5ad 100644
--- a/runtime/src/z_Linux_asm.S
+++ b/runtime/src/z_Linux_asm.S
@@ -1540,10 +1540,12 @@ __kmp_unnamed_critical_addr:
.comm .gomp_critical_user_,32,8
.data
.align 8
- .global __kmp_unnamed_critical_addr
-__kmp_unnamed_critical_addr:
+ .global ___kmp_unnamed_critical_addr
+___kmp_unnamed_critical_addr:
.8byte .gomp_critical_user_
- .size __kmp_unnamed_critical_addr,8
+# if !(KMP_OS_DARWIN)
+ .size ___kmp_unnamed_critical_addr,8
+# endif
#endif /* KMP_ARCH_PPC64 || KMP_ARCH_AARCH64 */
#if KMP_OS_LINUX

View File

@ -500,17 +500,10 @@ endif()
# makesdna, tests, etc.), we add an rpath to the OpenMP library dir through
# CMAKE_BUILD_RPATH. This avoids having to make many copies of the dylib next to each binary.
#
# For the installed Blender executable, CMAKE_INSTALL_RPATH will be used
# to locate the dylibs at @executable_path, next to the Blender executable.
#
# For the installed Python module, CMAKE_INSTALL_RPATH is modified to find the
# dylib in an adjacent folder.
# For the installed Python module and installed Blender executable, CMAKE_INSTALL_RPATH
# is modified to find the dylib in an adjacent folder. Install step puts the libraries there.
set(CMAKE_SKIP_BUILD_RPATH FALSE)
list(APPEND CMAKE_BUILD_RPATH "${OpenMP_LIBRARY_DIR}")
set(CMAKE_SKIP_INSTALL_RPATH FALSE)
list(APPEND CMAKE_INSTALL_RPATH "@executable_path")
if(WITH_PYTHON_MODULE)
list(APPEND CMAKE_INSTALL_RPATH "@loader_path/../Resources/${BLENDER_VERSION}/lib")
endif()
list(APPEND CMAKE_INSTALL_RPATH "@loader_path/../Resources/${BLENDER_VERSION}/lib")

View File

@ -0,0 +1,34 @@
set SOURCEDIR=%BLENDER_DIR%/doc/python_api/sphinx-in
set BUILDDIR=%BLENDER_DIR%/doc/python_api/sphinx-out
if "%BF_LANG%" == "" set BF_LANG=en
set SPHINXOPTS=-j auto -D language=%BF_LANG%
call "%~dp0\find_sphinx.cmd"
if EXIST "%SPHINX_BIN%" (
goto detect_sphinx_done
)
echo unable to locate sphinx-build, run "set sphinx_BIN=full_path_to_sphinx-build.exe"
exit /b 1
:detect_sphinx_done
call "%~dp0\find_blender.cmd"
if EXIST "%BLENDER_BIN%" (
goto detect_blender_done
)
echo unable to locate blender, run "set BLENDER_BIN=full_path_to_blender.exe"
exit /b 1
:detect_blender_done
%BLENDER_BIN% ^
--background -noaudio --factory-startup ^
--python %BLENDER_DIR%/doc/python_api/sphinx_doc_gen.py
"%SPHINX_BIN%" -b html %SPHINXOPTS% %O% %SOURCEDIR% %BUILDDIR%
:EOF

View File

@ -0,0 +1,23 @@
REM First see if there is an environment variable set
if EXIST "%SPHINX_BIN%" (
goto detect_sphinx_done
)
REM Then see if inkscape is available in the path
for %%X in (sphinx-build.exe) do (set SPHINX_BIN=%%~$PATH:X)
if EXIST "%SPHINX_BIN%" (
goto detect_sphinx_done
)
echo.The 'sphinx-build' command was not found. Make sure you have Sphinx
echo.installed, then set the SPHINX_BIN environment variable to point
echo.to the full path of the 'sphinx-build' executable. Alternatively you
echo.may add the Sphinx directory to PATH.
echo.
echo.If you don't have Sphinx installed, grab it from
echo.http://sphinx-doc.org/
REM If still not found clear the variable
set SPHINX_BIN=
:detect_sphinx_done

View File

@ -113,6 +113,9 @@ if NOT "%1" == "" (
) else if "%1" == "icons_geom" (
set ICONS_GEOM=1
goto EOF
) else if "%1" == "doc_py" (
set DOC_PY=1
goto EOF
) else (
echo Command "%1" unknown, aborting!
goto ERR

View File

@ -32,4 +32,5 @@ set FORMAT=
set TEST=
set BUILD_WITH_SCCACHE=
set ICONS=
set ICONS_GEOM=
set ICONS_GEOM=
set DOC_PY=

View File

@ -31,6 +31,10 @@ echo - 2019 ^(build with visual studio 2019^)
echo - 2019pre ^(build with visual studio 2019 pre-release^)
echo - 2019b ^(build with visual studio 2019 Build Tools^)
echo.
echo Documentation Targets ^(Not associated with building^)
echo - doc_py ^(Generate sphinx python api docs^)
echo.
echo Experimental options
echo - with_opengl_tests ^(enable both the render and draw opengl test suites^)

View File

@ -123,7 +123,7 @@ def Align(handle):
class BlendFile:
'''
Reads a blendfile and store the header, all the fileblocks, and catalogue
structs foound in the DNA fileblock
structs found in the DNA fileblock
- BlendFile.Header (BlendFileHeader instance)
- BlendFile.Blocks (list of BlendFileBlock instances)

View File

@ -1047,7 +1047,7 @@ context_type_map = {
"annotation_data": ("GreasePencil", False),
"annotation_data_owner": ("ID", False),
"armature": ("Armature", False),
"asset_library": ("AssetLibraryReference", False),
"asset_library_ref": ("AssetLibraryReference", False),
"bone": ("Bone", False),
"brush": ("Brush", False),
"camera": ("Camera", False),

View File

@ -1,4 +1,4 @@
# -*- coding: utf-8 -*-
# -*- coding: utf-8 -*-
import sys
import os

View File

@ -487,6 +487,24 @@ static PyObject *osl_update_node_func(PyObject * /*self*/, PyObject *args)
if (param->varlenarray || param->isstruct || param->type.arraylen > 1)
continue;
/* Read metadata. */
bool is_bool_param = false;
ustring param_label = param->name;
for (const OSL::OSLQuery::Parameter &metadata : param->metadata) {
if (metadata.type == TypeDesc::STRING) {
if (metadata.name == "widget") {
/* Boolean socket. */
if (metadata.sdefault[0] == "boolean" || metadata.sdefault[0] == "checkBox") {
is_bool_param = true;
}
}
else if (metadata.name == "label") {
/* Socket label. */
param_label = metadata.sdefault[0];
}
}
}
/* determine socket type */
string socket_type;
BL::NodeSocket::type_enum data_type = BL::NodeSocket::type_VALUE;
@ -494,6 +512,7 @@ static PyObject *osl_update_node_func(PyObject * /*self*/, PyObject *args)
float default_float = 0.0f;
int default_int = 0;
string default_string = "";
bool default_boolean = false;
if (param->isclosure) {
socket_type = "NodeSocketShader";
@ -523,10 +542,19 @@ static PyObject *osl_update_node_func(PyObject * /*self*/, PyObject *args)
}
else if (param->type.aggregate == TypeDesc::SCALAR) {
if (param->type.basetype == TypeDesc::INT) {
socket_type = "NodeSocketInt";
data_type = BL::NodeSocket::type_INT;
if (param->validdefault)
default_int = param->idefault[0];
if (is_bool_param) {
socket_type = "NodeSocketBool";
data_type = BL::NodeSocket::type_BOOLEAN;
if (param->validdefault) {
default_boolean = (bool)param->idefault[0];
}
}
else {
socket_type = "NodeSocketInt";
data_type = BL::NodeSocket::type_INT;
if (param->validdefault)
default_int = param->idefault[0];
}
}
else if (param->type.basetype == TypeDesc::FLOAT) {
socket_type = "NodeSocketFloat";
@ -546,33 +574,57 @@ static PyObject *osl_update_node_func(PyObject * /*self*/, PyObject *args)
else
continue;
/* find socket socket */
BL::NodeSocket b_sock(PointerRNA_NULL);
/* Update existing socket. */
bool found_existing = false;
if (param->isoutput) {
b_sock = b_node.outputs[param->name.string()];
/* remove if type no longer matches */
if (b_sock && b_sock.bl_idname() != socket_type) {
b_node.outputs.remove(b_data, b_sock);
b_sock = BL::NodeSocket(PointerRNA_NULL);
for (BL::NodeSocket &b_sock : b_node.outputs) {
if (b_sock.identifier() == param->name) {
if (b_sock.bl_idname() != socket_type) {
/* Remove if type no longer matches. */
b_node.outputs.remove(b_data, b_sock);
}
else {
/* Reuse and update label. */
if (b_sock.name() != param_label) {
b_sock.name(param_label.string());
}
used_sockets.insert(b_sock.ptr.data);
found_existing = true;
}
break;
}
}
}
else {
b_sock = b_node.inputs[param->name.string()];
/* remove if type no longer matches */
if (b_sock && b_sock.bl_idname() != socket_type) {
b_node.inputs.remove(b_data, b_sock);
b_sock = BL::NodeSocket(PointerRNA_NULL);
for (BL::NodeSocket &b_sock : b_node.inputs) {
if (b_sock.identifier() == param->name) {
if (b_sock.bl_idname() != socket_type) {
/* Remove if type no longer matches. */
b_node.inputs.remove(b_data, b_sock);
}
else {
/* Reuse and update label. */
if (b_sock.name() != param_label) {
b_sock.name(param_label.string());
}
used_sockets.insert(b_sock.ptr.data);
found_existing = true;
}
break;
}
}
}
if (!b_sock) {
/* create new socket */
if (param->isoutput)
b_sock = b_node.outputs.create(
b_data, socket_type.c_str(), param->name.c_str(), param->name.c_str());
else
b_sock = b_node.inputs.create(
b_data, socket_type.c_str(), param->name.c_str(), param->name.c_str());
if (!found_existing) {
/* Create new socket. */
BL::NodeSocket b_sock = (param->isoutput) ? b_node.outputs.create(b_data,
socket_type.c_str(),
param_label.c_str(),
param->name.c_str()) :
b_node.inputs.create(b_data,
socket_type.c_str(),
param_label.c_str(),
param->name.c_str());
/* set default value */
if (data_type == BL::NodeSocket::type_VALUE) {
@ -590,9 +642,12 @@ static PyObject *osl_update_node_func(PyObject * /*self*/, PyObject *args)
else if (data_type == BL::NodeSocket::type_STRING) {
set_string(b_sock.ptr, "default_value", default_string);
}
}
else if (data_type == BL::NodeSocket::type_BOOLEAN) {
set_boolean(b_sock.ptr, "default_value", default_boolean);
}
used_sockets.insert(b_sock.ptr.data);
used_sockets.insert(b_sock.ptr.data);
}
}
/* remove unused parameters */

View File

@ -149,7 +149,7 @@ BlenderAttributeType blender_attribute_name_split_type(ustring name, string *r_r
static BL::NodeSocket get_node_output(BL::Node &b_node, const string &name)
{
for (BL::NodeSocket &b_out : b_node.outputs) {
if (b_out.name() == name) {
if (b_out.identifier() == name) {
return b_out;
}
}
@ -215,7 +215,12 @@ static void set_default_value(ShaderInput *input,
break;
}
case SocketType::INT: {
node->set(socket, get_int(b_sock.ptr, "default_value"));
if (b_sock.type() == BL::NodeSocket::type_BOOLEAN) {
node->set(socket, get_boolean(b_sock.ptr, "default_value"));
}
else {
node->set(socket, get_int(b_sock.ptr, "default_value"));
}
break;
}
case SocketType::COLOR: {
@ -1002,71 +1007,48 @@ static bool node_use_modified_socket_name(ShaderNode *node)
return true;
}
static ShaderInput *node_find_input_by_name(ShaderNode *node,
BL::Node &b_node,
BL::NodeSocket &b_socket)
static ShaderInput *node_find_input_by_name(ShaderNode *node, BL::NodeSocket &b_socket)
{
string name = b_socket.name();
string name = b_socket.identifier();
ShaderInput *input = node->input(name.c_str());
if (node_use_modified_socket_name(node)) {
bool found = false;
int counter = 0, total = 0;
if (!input && node_use_modified_socket_name(node)) {
/* Different internal name for shader. */
if (string_startswith(name, "Shader")) {
string_replace(name, "Shader", "Closure");
}
input = node->input(name.c_str());
for (BL::NodeSocket &b_input : b_node.inputs) {
if (b_input.name() == name) {
if (!found) {
counter++;
}
total++;
if (!input) {
/* Different internal numbering of two sockets with same name. */
if (string_endswith(name, "_001")) {
string_replace(name, "_001", "2");
}
else {
name += "1";
}
if (b_input.ptr.data == b_socket.ptr.data)
found = true;
input = node->input(name.c_str());
}
/* rename if needed */
if (name == "Shader")
name = "Closure";
if (total > 1)
name = string_printf("%s%d", name.c_str(), counter);
}
return node->input(name.c_str());
return input;
}
static ShaderOutput *node_find_output_by_name(ShaderNode *node,
BL::Node &b_node,
BL::NodeSocket &b_socket)
static ShaderOutput *node_find_output_by_name(ShaderNode *node, BL::NodeSocket &b_socket)
{
string name = b_socket.name();
string name = b_socket.identifier();
ShaderOutput *output = node->output(name.c_str());
if (node_use_modified_socket_name(node)) {
bool found = false;
int counter = 0, total = 0;
for (BL::NodeSocket &b_output : b_node.outputs) {
if (b_output.name() == name) {
if (!found) {
counter++;
}
total++;
}
if (b_output.ptr.data == b_socket.ptr.data) {
found = true;
}
}
/* rename if needed */
if (name == "Shader")
if (!output && node_use_modified_socket_name(node)) {
/* Different internal name for shader. */
if (name == "Shader") {
name = "Closure";
if (total > 1)
name = string_printf("%s%d", name.c_str(), counter);
output = node->output(name.c_str());
}
}
return node->output(name.c_str());
return output;
}
static void add_nodes(Scene *scene,
@ -1209,7 +1191,7 @@ static void add_nodes(Scene *scene,
if (node) {
/* map node sockets for linking */
for (BL::NodeSocket &b_input : b_node.inputs) {
ShaderInput *input = node_find_input_by_name(node, b_node, b_input);
ShaderInput *input = node_find_input_by_name(node, b_input);
if (!input) {
/* XXX should not happen, report error? */
continue;
@ -1219,7 +1201,7 @@ static void add_nodes(Scene *scene,
set_default_value(input, b_input, b_data, b_ntree);
}
for (BL::NodeSocket &b_output : b_node.outputs) {
ShaderOutput *output = node_find_output_by_name(node, b_node, b_output);
ShaderOutput *output = node_find_output_by_name(node, b_output);
if (!output) {
/* XXX should not happen, report error? */
continue;

View File

@ -145,7 +145,7 @@ static inline void curvemapping_minmax(/*const*/ BL::CurveMapping &cumap,
float *min_x,
float *max_x)
{
/* const int num_curves = cumap.curves.length(); */ /* Gives linking error so far. */
// const int num_curves = cumap.curves.length(); /* Gives linking error so far. */
const int num_curves = rgb_curve ? 4 : 3;
*min_x = FLT_MAX;
*max_x = -FLT_MAX;

View File

@ -185,6 +185,8 @@ void Session::reset_gpu(BufferParams &buffer_params, int samples)
gpu_need_display_buffer_update_ = false;
gpu_need_display_buffer_update_cond_.notify_all();
new_work_added_ = true;
pause_cond_.notify_all();
}

View File

@ -1102,7 +1102,7 @@ int GHOST_XrSyncActions(GHOST_XrContextHandle xr_context, const char *action_set
int GHOST_XrApplyHapticAction(GHOST_XrContextHandle xr_context,
const char *action_set_name,
const char *action_name,
const char **subaction_path,
const char *subaction_path,
const int64_t *duration,
const float *frequency,
const float *amplitude);
@ -1113,7 +1113,7 @@ int GHOST_XrApplyHapticAction(GHOST_XrContextHandle xr_context,
void GHOST_XrStopHapticAction(GHOST_XrContextHandle xr_context,
const char *action_set_name,
const char *action_name,
const char **subaction_path);
const char *subaction_path);
/**
* Get action set custom data (owned by Blender, not GHOST).

View File

@ -1005,7 +1005,7 @@ int GHOST_XrSyncActions(GHOST_XrContextHandle xr_contexthandle, const char *acti
int GHOST_XrApplyHapticAction(GHOST_XrContextHandle xr_contexthandle,
const char *action_set_name,
const char *action_name,
const char **subaction_path,
const char *subaction_path,
const int64_t *duration,
const float *frequency,
const float *amplitude)
@ -1022,7 +1022,7 @@ int GHOST_XrApplyHapticAction(GHOST_XrContextHandle xr_contexthandle,
void GHOST_XrStopHapticAction(GHOST_XrContextHandle xr_contexthandle,
const char *action_set_name,
const char *action_name,
const char **subaction_path)
const char *subaction_path)
{
GHOST_IXrContext *xr_context = (GHOST_IXrContext *)xr_contexthandle;
GHOST_XrSession *xr_session = xr_context->getSession();

View File

@ -30,9 +30,15 @@
# include "GHOST_WindowWin32.h"
# include "utfconv.h"
/* ISO_639-1 2-Letter Abbreviations. */
# define IMELANG_ENGLISH "en"
# define IMELANG_CHINESE "zh"
# define IMELANG_JAPANESE "ja"
# define IMELANG_KOREAN "ko"
GHOST_ImeWin32::GHOST_ImeWin32()
: is_composing_(false),
input_language_id_(LANG_USER_DEFAULT),
language_(IMELANG_ENGLISH),
conversion_modes_(IME_CMODE_ALPHANUMERIC),
sentence_mode_(IME_SMODE_NONE),
system_caret_(false),
@ -48,16 +54,21 @@ GHOST_ImeWin32::~GHOST_ImeWin32()
void GHOST_ImeWin32::UpdateInputLanguage()
{
/**
* Store the current input language.
*/
HKL input_locale = ::GetKeyboardLayout(0);
input_language_id_ = LOWORD(input_locale);
/* Get the current input locale full name. */
WCHAR locale[LOCALE_NAME_MAX_LENGTH];
LCIDToLocaleName(
MAKELCID(LOWORD(::GetKeyboardLayout(0)), SORT_DEFAULT), locale, LOCALE_NAME_MAX_LENGTH, 0);
/* Get the 2-letter ISO-63901 abbreviation of the input locale name. */
WCHAR language_u16[W32_ISO639_LEN];
GetLocaleInfoEx(locale, LOCALE_SISO639LANGNAME, language_u16, W32_ISO639_LEN);
/* Store this as a UTF-8 string. */
WideCharToMultiByte(
CP_UTF8, 0, language_u16, W32_ISO639_LEN, language_, W32_ISO639_LEN, NULL, NULL);
}
WORD GHOST_ImeWin32::GetInputLanguage()
BOOL GHOST_ImeWin32::IsLanguage(const char name[W32_ISO639_LEN])
{
return input_language_id_;
return (strcmp(name, language_) == 0);
}
void GHOST_ImeWin32::UpdateConversionStatus(HWND window_handle)
@ -92,21 +103,11 @@ bool GHOST_ImeWin32::IsImeKeyEvent(char ascii)
if ((ascii >= 'A' && ascii <= 'Z') || (ascii >= 'a' && ascii <= 'z')) {
return true;
}
switch (PRIMARYLANGID(GetInputLanguage())) {
/* In Japanese, all symbolic characters are also processed by IME. */
case LANG_JAPANESE: {
if (ascii >= ' ' && ascii <= '~') {
return true;
}
break;
}
/* In Chinese, some symbolic characters are also processed by IME. */
case LANG_CHINESE: {
if (ascii && strchr("!\"$'(),.:;<>?[\\]^_`", ascii)) {
return true;
}
break;
}
if (IsLanguage(IMELANG_JAPANESE) && (ascii >= ' ' && ascii <= '~')) {
return true;
}
else if (IsLanguage(IMELANG_CHINESE) && ascii && strchr("!\"$'(),.:;<>?[\\]^_`", ascii)) {
return true;
}
}
return false;
@ -126,13 +127,8 @@ void GHOST_ImeWin32::CreateImeWindow(HWND window_handle)
* Since some third-party Japanese IME also uses ::GetCaretPos() to determine
* their window position, we also create a caret for Japanese IMEs.
*/
if (PRIMARYLANGID(input_language_id_) == LANG_CHINESE ||
PRIMARYLANGID(input_language_id_) == LANG_JAPANESE) {
if (!system_caret_) {
if (::CreateCaret(window_handle, NULL, 1, 1)) {
system_caret_ = true;
}
}
if (!system_caret_ && (IsLanguage(IMELANG_CHINESE) || IsLanguage(IMELANG_JAPANESE))) {
system_caret_ = ::CreateCaret(window_handle, NULL, 1, 1);
}
/* Restore the positions of the IME windows. */
UpdateImeWindow(window_handle);
@ -185,16 +181,9 @@ void GHOST_ImeWin32::MoveImeWindow(HWND window_handle, HIMC imm_context)
CANDIDATEFORM candidate_position = {0, CFS_CANDIDATEPOS, {x, y}, {0, 0, 0, 0}};
::ImmSetCandidateWindow(imm_context, &candidate_position);
if (system_caret_) {
switch (PRIMARYLANGID(input_language_id_)) {
case LANG_JAPANESE:
::SetCaretPos(x, y + caret_rect_.getHeight());
break;
default:
::SetCaretPos(x, y);
break;
}
::SetCaretPos(x, y);
}
if (PRIMARYLANGID(input_language_id_) == LANG_KOREAN) {
if (IsLanguage(IMELANG_KOREAN)) {
/**
* Chinese IMEs and Japanese IMEs require the upper-left corner of
* the caret to move the position of their candidate windows.
@ -284,83 +273,79 @@ void GHOST_ImeWin32::GetCaret(HIMC imm_context, LPARAM lparam, ImeComposition *c
*/
int target_start = -1;
int target_end = -1;
switch (PRIMARYLANGID(input_language_id_)) {
case LANG_KOREAN:
if (lparam & CS_NOMOVECARET) {
target_start = 0;
target_end = 1;
}
break;
case LANG_CHINESE: {
int clause_size = ImmGetCompositionStringW(imm_context, GCS_COMPCLAUSE, NULL, 0);
if (clause_size) {
static std::vector<unsigned long> clauses;
clause_size = clause_size / sizeof(clauses[0]);
clauses.resize(clause_size);
ImmGetCompositionStringW(
imm_context, GCS_COMPCLAUSE, &clauses[0], sizeof(clauses[0]) * clause_size);
if (composition->cursor_position == composition->ime_string.size()) {
target_start = clauses[clause_size - 2];
target_end = clauses[clause_size - 1];
}
else {
for (int i = 0; i < clause_size - 1; i++) {
if (clauses[i] == composition->cursor_position) {
target_start = clauses[i];
target_end = clauses[i + 1];
break;
}
}
}
if (IsLanguage(IMELANG_KOREAN)) {
if (lparam & CS_NOMOVECARET) {
target_start = 0;
target_end = 1;
}
}
else if (IsLanguage(IMELANG_CHINESE)) {
int clause_size = ImmGetCompositionStringW(imm_context, GCS_COMPCLAUSE, NULL, 0);
if (clause_size) {
static std::vector<unsigned long> clauses;
clause_size = clause_size / sizeof(clauses[0]);
clauses.resize(clause_size);
ImmGetCompositionStringW(
imm_context, GCS_COMPCLAUSE, &clauses[0], sizeof(clauses[0]) * clause_size);
if (composition->cursor_position == composition->ime_string.size()) {
target_start = clauses[clause_size - 2];
target_end = clauses[clause_size - 1];
}
else {
if (composition->cursor_position != -1) {
target_start = composition->cursor_position;
target_end = composition->ime_string.size();
}
}
break;
}
case LANG_JAPANESE:
/**
* For Japanese IMEs, the robustest way to retrieve the caret
* is scanning the attribute of the latest composition string and
* retrieving the beginning and the end of the target clause, i.e.
* a clause being converted.
*/
if (lparam & GCS_COMPATTR) {
int attribute_size = ::ImmGetCompositionStringW(imm_context, GCS_COMPATTR, NULL, 0);
if (attribute_size > 0) {
char *attribute_data = new char[attribute_size];
if (attribute_data) {
::ImmGetCompositionStringW(imm_context, GCS_COMPATTR, attribute_data, attribute_size);
for (target_start = 0; target_start < attribute_size; ++target_start) {
if (IsTargetAttribute(attribute_data[target_start]))
break;
}
for (target_end = target_start; target_end < attribute_size; ++target_end) {
if (!IsTargetAttribute(attribute_data[target_end]))
break;
}
if (target_start == attribute_size) {
/**
* This composition clause does not contain any target clauses,
* i.e. this clauses is an input clause.
* We treat whole this clause as a target clause.
*/
target_end = target_start;
target_start = 0;
}
if (target_start != -1 && target_start < attribute_size &&
attribute_data[target_start] == ATTR_TARGET_NOTCONVERTED) {
composition->cursor_position = target_start;
}
for (int i = 0; i < clause_size - 1; i++) {
if (clauses[i] == composition->cursor_position) {
target_start = clauses[i];
target_end = clauses[i + 1];
break;
}
delete[] attribute_data;
}
}
break;
}
else {
if (composition->cursor_position != -1) {
target_start = composition->cursor_position;
target_end = composition->ime_string.size();
}
}
}
else if (IsLanguage(IMELANG_JAPANESE)) {
/**
* For Japanese IMEs, the robustest way to retrieve the caret
* is scanning the attribute of the latest composition string and
* retrieving the beginning and the end of the target clause, i.e.
* a clause being converted.
*/
if (lparam & GCS_COMPATTR) {
int attribute_size = ::ImmGetCompositionStringW(imm_context, GCS_COMPATTR, NULL, 0);
if (attribute_size > 0) {
char *attribute_data = new char[attribute_size];
if (attribute_data) {
::ImmGetCompositionStringW(imm_context, GCS_COMPATTR, attribute_data, attribute_size);
for (target_start = 0; target_start < attribute_size; ++target_start) {
if (IsTargetAttribute(attribute_data[target_start]))
break;
}
for (target_end = target_start; target_end < attribute_size; ++target_end) {
if (!IsTargetAttribute(attribute_data[target_end]))
break;
}
if (target_start == attribute_size) {
/**
* This composition clause does not contain any target clauses,
* i.e. this clauses is an input clause.
* We treat whole this clause as a target clause.
*/
target_end = target_start;
target_start = 0;
}
if (target_start != -1 && target_start < attribute_size &&
attribute_data[target_start] == ATTR_TARGET_NOTCONVERTED) {
composition->cursor_position = target_start;
}
}
delete[] attribute_data;
}
}
}
composition->target_start = target_start;
composition->target_end = target_end;

View File

@ -36,6 +36,9 @@
# include "GHOST_Rect.h"
# include <vector>
/* MSDN LOCALE_SISO639LANGNAME states maximum length of 9, including terminating null. */
# define W32_ISO639_LEN 9
class GHOST_EventIME : public GHOST_Event {
public:
/**
@ -146,13 +149,10 @@ class GHOST_ImeWin32 {
return is_composing_;
}
/**
* Retrieves the input language from Windows and update it.
*/
/* Retrieve the input language from Windows and store it. */
void UpdateInputLanguage();
/* Returns the current input language id. */
WORD GetInputLanguage();
BOOL IsLanguage(const char name[W32_ISO639_LEN]);
/* Saves the current conversion status. */
void UpdateConversionStatus(HWND window_handle);
@ -345,29 +345,8 @@ class GHOST_ImeWin32 {
*/
bool is_composing_;
/**
* The current input Language ID retrieved from Windows, which consists of:
* * Primary Language ID (bit 0 to bit 9), which shows a natural language
* (English, Korean, Chinese, Japanese, etc.) and;
* * Sub-Language ID (bit 10 to bit 15), which shows a geometrical region
* the language is spoken (For English, United States, United Kingdom,
* Australia, Canada, etc.)
* The following list enumerates some examples for the Language ID:
* * "en-US" (0x0409)
* MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US);
* * "ko-KR" (0x0412)
* MAKELANGID(LANG_KOREAN, SUBLANG_KOREAN);
* * "zh-TW" (0x0404)
* MAKELANGID(LANG_CHINESE, SUBLANG_CHINESE_TRADITIONAL);
* * "zh-CN" (0x0804)
* MAKELANGID(LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED);
* * "ja-JP" (0x0411)
* MAKELANGID(LANG_JAPANESE, SUBLANG_JAPANESE_JAPAN), etc.
* (See `winnt.h` for other available values.)
* This Language ID is used for processing language-specific operations in
* IME functions.
*/
LANGID input_language_id_;
/* Abbreviated ISO 639-1 name of the input language, such as "en" for English. */
char language_[W32_ISO639_LEN];
/* Current Conversion Mode Values. Retrieved with ImmGetConversionStatus. */
DWORD conversion_modes_;

View File

@ -1629,7 +1629,7 @@ GHOST_TSuccess GHOST_SystemCocoa::handleMouseEvent(void *eventPtr)
y_accum + (y_mouse - warped_y_mouse));
/* This is the current time that matches NSEvent timestamp. */
m_last_warp_timestamp = mach_absolute_time() * 1e-9;
m_last_warp_timestamp = [[NSProcessInfo processInfo] systemUptime];
}
// Generate event

View File

@ -375,7 +375,7 @@ void GHOST_XrAction::updateState(XrSession session,
void GHOST_XrAction::applyHapticFeedback(XrSession session,
const char *action_name,
const char **subaction_path_str,
const char *subaction_path_str,
const int64_t &duration,
const float &frequency,
const float &amplitude)
@ -390,7 +390,7 @@ void GHOST_XrAction::applyHapticFeedback(XrSession session,
haptic_info.action = m_action;
if (subaction_path_str != nullptr) {
SubactionIndexMap::iterator it = m_subaction_indices.find(*subaction_path_str);
SubactionIndexMap::iterator it = m_subaction_indices.find(subaction_path_str);
if (it != m_subaction_indices.end()) {
haptic_info.subactionPath = m_subaction_paths[it->second];
CHECK_XR(
@ -410,13 +410,13 @@ void GHOST_XrAction::applyHapticFeedback(XrSession session,
void GHOST_XrAction::stopHapticFeedback(XrSession session,
const char *action_name,
const char **subaction_path_str)
const char *subaction_path_str)
{
XrHapticActionInfo haptic_info{XR_TYPE_HAPTIC_ACTION_INFO};
haptic_info.action = m_action;
if (subaction_path_str != nullptr) {
SubactionIndexMap::iterator it = m_subaction_indices.find(*subaction_path_str);
SubactionIndexMap::iterator it = m_subaction_indices.find(subaction_path_str);
if (it != m_subaction_indices.end()) {
haptic_info.subactionPath = m_subaction_paths[it->second];
CHECK_XR(xrStopHapticFeedback(session, &haptic_info),

View File

@ -103,11 +103,11 @@ class GHOST_XrAction {
const XrTime &predicted_display_time);
void applyHapticFeedback(XrSession session,
const char *action_name,
const char **subaction_path,
const char *subaction_path,
const int64_t &duration,
const float &frequency,
const float &amplitude);
void stopHapticFeedback(XrSession session, const char *action_name, const char **subaction_path);
void stopHapticFeedback(XrSession session, const char *action_name, const char *subaction_path);
void *getCustomdata();
void getBindings(std::map<XrPath, std::vector<XrActionSuggestedBinding>> &r_bindings) const;

View File

@ -754,7 +754,7 @@ bool GHOST_XrSession::syncActions(const char *action_set_name)
bool GHOST_XrSession::applyHapticAction(const char *action_set_name,
const char *action_name,
const char **subaction_path,
const char *subaction_path,
const int64_t &duration,
const float &frequency,
const float &amplitude)
@ -777,7 +777,7 @@ bool GHOST_XrSession::applyHapticAction(const char *action_set_name,
void GHOST_XrSession::stopHapticAction(const char *action_set_name,
const char *action_name,
const char **subaction_path)
const char *subaction_path)
{
GHOST_XrActionSet *action_set = find_action_set(m_oxr.get(), action_set_name);
if (action_set == nullptr) {

View File

@ -76,13 +76,13 @@ class GHOST_XrSession {
bool syncActions(const char *action_set_name = nullptr);
bool applyHapticAction(const char *action_set_name,
const char *action_name,
const char **subaction_path,
const char *subaction_path,
const int64_t &duration,
const float &frequency,
const float &amplitude);
void stopHapticAction(const char *action_set_name,
const char *action_name,
const char **subaction_path);
const char *subaction_path);
/* Custom data (owned by Blender, not GHOST) accessors. */
void *getActionSetCustomdata(const char *action_set_name);

View File

@ -871,7 +871,7 @@ void MEM_guarded_freeN(void *vmemh)
if (memh == NULL) {
MemorY_ErroR("free", "attempt to free NULL pointer");
/* print_error(err_stream, "%d\n", (memh+4000)->tag1); */
// print_error(err_stream, "%d\n", (memh+4000)->tag1);
return;
}

View File

@ -13,6 +13,14 @@ if errorlevel 1 goto EOF
call "%BLENDER_DIR%\build_files\windows\parse_arguments.cmd" %*
if errorlevel 1 goto EOF
REM if it is one of the convenience targets and BLENDER_BIN is set
REM skip compiler detection
if "%ICONS%%ICONS_GEOM%%DOC_PY%" == "1" (
if EXIST "%BLENDER_BIN%" (
goto convenience_targets
)
)
call "%BLENDER_DIR%\build_files\windows\find_dependencies.cmd"
if errorlevel 1 goto EOF
@ -58,6 +66,8 @@ if "%BUILD_UPDATE%" == "1" (
call "%BLENDER_DIR%\build_files\windows\set_build_dir.cmd"
:convenience_targets
if "%ICONS%" == "1" (
call "%BLENDER_DIR%\build_files\windows\icons.cmd"
goto EOF
@ -68,6 +78,11 @@ if "%ICONS_GEOM%" == "1" (
goto EOF
)
if "%DOC_PY%" == "1" (
call "%BLENDER_DIR%\build_files\windows\doc_py.cmd"
goto EOF
)
echo Building blender with VS%BUILD_VS_YEAR% for %BUILD_ARCH% in %BUILD_DIR%
call "%BLENDER_DIR%\build_files\windows\check_libraries.cmd"

Binary file not shown.

View File

@ -1355,7 +1355,7 @@ class I18n:
print(prefix.join(lines))
@classmethod
def check_py_module_has_translations(clss, src, settings=settings):
def check_py_module_has_translations(cls, src, settings=settings):
"""
Check whether a given src (a py module, either a directory or a py file) has some i18n translation data,
and returns a tuple (src_file, translations_tuple) if yes, else (None, None).
@ -1367,11 +1367,11 @@ class I18n:
if not fname.endswith(".py"):
continue
path = os.path.join(root, fname)
_1, txt, _2, has_trans = clss._parser_check_file(path)
_1, txt, _2, has_trans = cls._parser_check_file(path)
if has_trans:
txts.append((path, txt))
elif src.endswith(".py") and os.path.isfile(src):
_1, txt, _2, has_trans = clss._parser_check_file(src)
_1, txt, _2, has_trans = cls._parser_check_file(src)
if has_trans:
txts.append((src, txt))
for path, txt in txts:

View File

@ -48,6 +48,7 @@ class SpellChecker:
"equi", # equi-angular, etc.
"fader",
"globbing",
"haptics",
"hasn", # hasn't
"hetero",
"hoc", # ad-hoc
@ -188,7 +189,7 @@ class SpellChecker:
"reprojection", "reproject", "reprojecting",
"resize",
"restpose",
"resync",
"resync", "resynced",
"retarget", "retargets", "retargeting", "retargeted",
"retiming",
"rigidbody",
@ -227,6 +228,7 @@ class SpellChecker:
"un",
"unassociate", "unassociated",
"unbake",
"uncheck",
"unclosed",
"uncomment",
"unculled",
@ -381,6 +383,7 @@ class SpellChecker:
"albedo",
"anamorphic",
"anisotropic", "anisotropy",
"bimanual", # OpenXR?
"bitangent",
"boid", "boids",
"ceil",
@ -430,6 +433,7 @@ class SpellChecker:
"spacebar",
"subtractive",
"superellipse",
"thumbstick",
"tooltip", "tooltips",
"trackpad",
"tuple",
@ -493,7 +497,7 @@ class SpellChecker:
"pinlight",
"qi",
"radiosity",
"raycasting",
"raycast", "raycasting",
"raytrace", "raytracing", "raytraced",
"refractions",
"remesher", "remeshing", "remesh",
@ -698,6 +702,7 @@ class SpellChecker:
"msgid", "msgids",
"mux",
"ndof",
"pbr", # Physically Based Rendering
"ppc",
"precisa",
"px",

View File

@ -754,12 +754,10 @@ def register_classes_factory(classes):
which simply registers and unregisters a sequence of classes.
"""
def register():
from bpy.utils import register_class
for cls in classes:
register_class(cls)
def unregister():
from bpy.utils import unregister_class
for cls in reversed(classes):
unregister_class(cls)

View File

@ -477,29 +477,34 @@ class Mesh(bpy_types.ID):
face_lengths = tuple(map(len, faces))
self.vertices.add(len(vertices))
self.edges.add(len(edges))
# NOTE: check non-empty lists by length because of how `numpy` handles truth tests, see: T90268.
vertices_len = len(vertices)
edges_len = len(edges)
faces_len = len(faces)
self.vertices.add(vertices_len)
self.edges.add(edges_len)
self.loops.add(sum(face_lengths))
self.polygons.add(len(faces))
self.polygons.add(faces_len)
self.vertices.foreach_set("co", tuple(chain.from_iterable(vertices)))
self.edges.foreach_set("vertices", tuple(chain.from_iterable(edges)))
vertex_indices = tuple(chain.from_iterable(faces))
loop_starts = tuple(islice(chain([0], accumulate(face_lengths)), len(faces)))
loop_starts = tuple(islice(chain([0], accumulate(face_lengths)), faces_len))
self.polygons.foreach_set("loop_total", face_lengths)
self.polygons.foreach_set("loop_start", loop_starts)
self.polygons.foreach_set("vertices", vertex_indices)
if edges or faces:
if edges_len or faces_len:
self.update(
# Needed to either:
# - Calculate edges that don't exist for polygons.
# - Assign edges to polygon loops.
calc_edges=bool(faces),
calc_edges=bool(faces_len),
# Flag loose edges.
calc_edges_loose=bool(edges),
calc_edges_loose=bool(edges_len),
)
@property
@ -761,9 +766,9 @@ class Macro(StructRNA):
__slots__ = ()
@classmethod
def define(self, opname):
def define(cls, opname):
from _bpy import ops
return ops.macro_define(self, opname)
return ops.macro_define(cls, opname)
class PropertyGroup(StructRNA, metaclass=RNAMetaPropGroup):

View File

@ -775,6 +775,8 @@ def km_property_editor(_params):
# Constraint panels
("constraint.delete", {"type": 'X', "value": 'PRESS'}, {"properties": [("report", True)]}),
("constraint.delete", {"type": 'DEL', "value": 'PRESS'}, {"properties": [("report", True)]}),
("constraint.copy", {"type": 'D', "value": 'PRESS', "shift": True}, None),
("constraint.apply", {"type": 'A', "value": 'PRESS', "ctrl": True}, {"properties": [("report", True)]}),
])
return keymap
@ -1999,6 +2001,10 @@ def km_file_browser(params):
{"properties": [("increment", -10)]}),
("file.filenum", {"type": 'NUMPAD_MINUS', "value": 'PRESS', "ctrl": True, "repeat": True},
{"properties": [("increment", -100)]}),
# Select file under cursor before spawning the context menu.
("file.select", {"type": 'RIGHTMOUSE', "value": 'PRESS'},
{"properties": [("open", False), ("only_activate_if_selected", params.select_mouse == 'LEFTMOUSE'), ("pass_through", True)]}),
*_template_items_context_menu("FILEBROWSER_MT_context_menu", params.context_menu_event),
*_template_items_context_menu("ASSETBROWSER_MT_context_menu", params.context_menu_event),
])

View File

@ -139,12 +139,12 @@ def _template_items_basic_tools(*, connected=False):
]
def _template_items_tool_select(params, operator, *, extend):
return [
(operator, {"type": 'LEFTMOUSE', "value": 'PRESS'},
{"properties": [("deselect_all", True)]}),
(operator, {"type": 'LEFTMOUSE', "value": 'PRESS', "shift": True},
{"properties": [(extend, True)]}),
]
return [
(operator, {"type": 'LEFTMOUSE', "value": 'PRESS'},
{"properties": [("deselect_all", True)]}),
(operator, {"type": 'LEFTMOUSE', "value": 'PRESS', "shift": True},
{"properties": [(extend, True)]}),
]
def _template_items_tool_select_actions(operator, *, type, value):
@ -465,6 +465,7 @@ def km_property_editor(params):
# Constraint panels
("constraint.delete", {"type": 'BACK_SPACE', "value": 'PRESS'}, {"properties": [("report", True)]}),
("constraint.delete", {"type": 'DEL', "value": 'PRESS'}, {"properties": [("report", True)]}),
("constraint.copy", {"type": 'D', "value": 'PRESS', "ctrl": True}, None),
])
return keymap
@ -1248,6 +1249,10 @@ def km_file_browser(params):
{"properties": [("increment", -10)]}),
("file.filenum", {"type": 'NUMPAD_MINUS', "value": 'PRESS', "ctrl": True, "repeat": True},
{"properties": [("increment", -100)]}),
# Select file under cursor before spawning the context menu.
("file.select", {"type": 'RIGHTMOUSE', "value": 'PRESS'},
{"properties": [("open", False), ("only_activate_if_selected", True), ("pass_through", True)]}),
*_template_items_context_menu("FILEBROWSER_MT_context_menu", {"type": 'RIGHTMOUSE', "value": 'PRESS'}),
*_template_items_context_menu("ASSETBROWSER_MT_context_menu", {"type": 'RIGHTMOUSE', "value": 'PRESS'}),
])

View File

@ -21,48 +21,43 @@
import bpy
from bpy.app.handlers import persistent
def update_factory_startup_screens():
# 2D Animation.
screen = bpy.data.screens["2D Animation"]
for area in screen.areas:
if area.type == 'PROPERTIES':
# Set Tool settings as default in properties panel.
space = area.spaces.active
space.context = 'TOOL'
elif area.type == 'DOPESHEET_EDITOR':
# Open sidebar in Dopesheet.
space = area.spaces.active
space.show_region_ui = True
# 2D Full Canvas.
screen = bpy.data.screens["2D Full Canvas"]
for area in screen.areas:
if area.type == 'VIEW_3D':
space = area.spaces.active
space.shading.type = 'MATERIAL'
space.shading.use_scene_world = True
def update_factory_startup_scenes():
for scene in bpy.data.scenes:
scene.tool_settings.use_keyframe_insert_auto = True
def update_factory_startup_grease_pencils():
for gpd in bpy.data.grease_pencils:
gpd.onion_keyframe_type = 'ALL'
@persistent
def load_handler(_):
import bpy
# 2D Animation
screen = bpy.data.screens['2D Animation']
if screen:
for area in screen.areas:
# Set Tool settings as default in properties panel.
if area.type == 'PROPERTIES':
for space in area.spaces:
if space.type != 'PROPERTIES':
continue
space.context = 'TOOL'
# Open sidebar in Dopesheet.
elif area.type == 'DOPESHEET_EDITOR':
for space in area.spaces:
if space.type != 'DOPESHEET_EDITOR':
continue
space.show_region_ui = True
# 2D Full Canvas
screen = bpy.data.screens['2D Full Canvas']
if screen:
for area in screen.areas:
if area.type == 'VIEW_3D':
for space in area.spaces:
if space.type != 'VIEW_3D':
continue
space.shading.type = 'MATERIAL'
space.shading.use_scene_world = True
# Grease pencil object
scene = bpy.data.scenes[0]
if scene:
scene.tool_settings.use_keyframe_insert_auto = True
for ob in scene.objects:
if ob.type == 'GPENCIL':
gpd = ob.data
gpd.onion_keyframe_type = 'ALL'
update_factory_startup_screens()
update_factory_startup_scenes()
update_factory_startup_grease_pencils()
def register():

View File

@ -20,10 +20,8 @@ import bpy
from bpy.app.handlers import persistent
@persistent
def load_handler(_):
from bpy import context
screen = context.screen
def update_factory_startup_screens():
screen = bpy.data.screens["Video Editing"]
for area in screen.areas:
if area.type == 'FILE_BROWSER':
space = area.spaces.active
@ -31,6 +29,11 @@ def load_handler(_):
params.use_filter_folder = True
@persistent
def load_handler(_):
update_factory_startup_screens()
def register():
bpy.app.handlers.load_factory_startup_post.append(load_handler)

View File

@ -130,7 +130,7 @@ class ASSET_OT_open_containing_blend_file(Operator):
return {'RUNNING_MODAL'}
if returncode:
self.report({'WARNING'}, "Blender subprocess exited with error code %d" % returncode)
self.report({'WARNING'}, "Blender sub-process exited with error code %d" % returncode)
# TODO(Sybren): Replace this with a generic "reload assets" operator
# that can run outside of the Asset Browser context.

View File

@ -237,9 +237,8 @@ class MASK_PT_point:
class MASK_PT_display:
# subclasses must define...
# ~ bl_space_type = 'CLIP_EDITOR'
# ~ bl_region_type = 'UI'
# ~ bl_region_type = 'HEADER'
bl_label = "Mask Display"
bl_options = {'DEFAULT_CLOSED'}
@classmethod
def poll(cls, context):

View File

@ -216,6 +216,7 @@ class OBJECT_PT_display(ObjectButtonsPanel, Panel):
obj = context.object
obj_type = obj.type
is_geometry = (obj_type in {'MESH', 'CURVE', 'SURFACE', 'META', 'FONT', 'VOLUME', 'HAIR', 'POINTCLOUD'})
has_bounds = (is_geometry or obj_type in {'LATTICE', 'ARMATURE'})
is_wire = (obj_type in {'CAMERA', 'EMPTY'})
is_empty_image = (obj_type == 'EMPTY' and obj.empty_display_type == 'IMAGE')
is_dupli = (obj.instance_type != 'NONE')
@ -247,21 +248,27 @@ class OBJECT_PT_display(ObjectButtonsPanel, Panel):
# Only useful with object having faces/materials...
col.prop(obj, "color")
col = layout.column(align=False, heading="Bounds")
col.use_property_decorate = False
row = col.row(align=True)
sub = row.row(align=True)
sub.prop(obj, "show_bounds", text="")
sub = sub.row(align=True)
sub.active = obj.show_bounds or (obj.display_type == 'BOUNDS')
sub.prop(obj, "display_bounds_type", text="")
row.prop_decorator(obj, "display_bounds_type")
if has_bounds:
col = layout.column(align=False, heading="Bounds")
col.use_property_decorate = False
row = col.row(align=True)
sub = row.row(align=True)
sub.prop(obj, "show_bounds", text="")
sub = sub.row(align=True)
sub.active = obj.show_bounds or (obj.display_type == 'BOUNDS')
sub.prop(obj, "display_bounds_type", text="")
row.prop_decorator(obj, "display_bounds_type")
class OBJECT_PT_instancing(ObjectButtonsPanel, Panel):
bl_label = "Instancing"
bl_options = {'DEFAULT_CLOSED'}
@classmethod
def poll(cls, context):
ob = context.object
return (ob.type in {'MESH', 'EMPTY', 'POINTCLOUD'})
def draw(self, context):
layout = self.layout

View File

@ -1205,14 +1205,15 @@ def brush_basic__draw_color_selector(context, layout, brush, gp_settings, props)
if not gp_settings.use_material_pin:
ma = context.object.active_material
icon_id = 0
txt_ma = ""
if ma:
icon_id = ma.id_data.preview.icon_id
txt_ma = ma.name
maxw = 25
if len(txt_ma) > maxw:
txt_ma = txt_ma[:maxw - 5] + '..' + txt_ma[-3:]
else:
txt_ma = ""
ma.id_data.preview_ensure()
if ma.id_data.preview:
icon_id = ma.id_data.preview.icon_id
txt_ma = ma.name
maxw = 25
if len(txt_ma) > maxw:
txt_ma = txt_ma[:maxw - 5] + '..' + txt_ma[-3:]
sub = row.row()
sub.ui_units_x = 8

View File

@ -1075,6 +1075,31 @@ class CLIP_PT_stabilization(CLIP_PT_reconstruction_panel, Panel):
layout.prop(stab, "filter_type")
class CLIP_PT_2d_cursor(Panel):
bl_space_type = 'CLIP_EDITOR'
bl_region_type = 'UI'
bl_category = "View"
bl_label = "2D Cursor"
@classmethod
def poll(cls, context):
sc = context.space_data
if CLIP_PT_clip_view_panel.poll(context):
return sc.pivot_point == 'CURSOR' or sc.mode == 'MASK'
def draw(self, context):
layout = self.layout
sc = context.space_data
layout.use_property_split = True
layout.use_property_decorate = False
col = layout.column()
col.prop(sc, "cursor_location", text="Location")
class CLIP_PT_proxy(CLIP_PT_clip_view_panel, Panel):
bl_space_type = 'CLIP_EDITOR'
bl_region_type = 'UI'
@ -1156,12 +1181,6 @@ class CLIP_PT_mask_layers(MASK_PT_layers, Panel):
bl_category = "Mask"
class CLIP_PT_mask_display(MASK_PT_display, Panel):
bl_space_type = 'CLIP_EDITOR'
bl_region_type = 'HEADER'
bl_category = "Mask"
class CLIP_PT_active_mask_spline(MASK_PT_spline, Panel):
bl_space_type = 'CLIP_EDITOR'
bl_region_type = 'UI'
@ -1191,6 +1210,11 @@ class CLIP_PT_tools_mask_tools(MASK_PT_tools, Panel):
bl_region_type = 'TOOLS'
bl_category = "Mask"
class CLIP_PT_mask_display(MASK_PT_display, Panel):
bl_space_type = 'CLIP_EDITOR'
bl_region_type = 'HEADER'
# --- end mask ---
@ -1240,7 +1264,7 @@ class CLIP_PT_tools_scenesetup(Panel):
class CLIP_PT_annotation(AnnotationDataPanel, CLIP_PT_clip_view_panel, Panel):
bl_space_type = 'CLIP_EDITOR'
bl_region_type = 'UI'
bl_category = "Annotation"
bl_category = "View"
bl_options = set()
# NOTE: this is just a wrapper around the generic GP Panel
@ -1863,6 +1887,7 @@ classes = (
CLIP_PT_proxy,
CLIP_PT_footage,
CLIP_PT_stabilization,
CLIP_PT_2d_cursor,
CLIP_PT_mask,
CLIP_PT_mask_layers,
CLIP_PT_mask_display,

View File

@ -195,7 +195,7 @@ class FILEBROWSER_PT_filter(FileBrowserPanel, Panel):
sub = row.column(align=True)
if context.preferences.experimental.use_asset_browser:
if context.preferences.experimental.use_extended_asset_browser:
sub.prop(params, "use_filter_asset_only")
filter_id = params.filter_id
@ -653,6 +653,10 @@ class ASSETBROWSER_PT_navigation_bar(asset_utils.AssetBrowserPanel, Panel):
bl_region_type = 'TOOLS'
bl_options = {'HIDE_HEADER'}
@classmethod
def poll(cls, context):
return context.preferences.experimental.use_extended_asset_browser
def draw(self, context):
layout = self.layout

View File

@ -817,7 +817,7 @@ class IMAGE_HT_header(Header):
row.prop(sima, "show_stereo_3d", text="")
if show_maskedit:
row = layout.row()
row.popover(panel='CLIP_PT_mask_display')
row.popover(panel='IMAGE_PT_mask_display')
# layers.
layout.template_image_layers(ima, iuser)
@ -826,12 +826,6 @@ class IMAGE_HT_header(Header):
row = layout.row()
row.prop(sima, "display_channels", icon_only=True)
row = layout.row(align=True)
if ima.type == 'COMPOSITE':
row.operator("image.record_composite", icon='REC')
if ima.type == 'COMPOSITE' and ima.source in {'MOVIE', 'SEQUENCE'}:
row.operator("image.play_composite", icon='PLAY')
class IMAGE_MT_editor_menus(Menu):
bl_idname = "IMAGE_MT_editor_menus"
@ -917,8 +911,7 @@ class IMAGE_PT_active_mask_point(MASK_PT_point, Panel):
class IMAGE_PT_mask_display(MASK_PT_display, Panel):
bl_space_type = 'IMAGE_EDITOR'
bl_region_type = 'UI'
bl_category = "Mask"
bl_region_type = 'HEADER'
# --- end mask ---

View File

@ -315,7 +315,7 @@ class OUTLINER_MT_asset(Menu):
@classmethod
def poll(cls, context):
return context.preferences.experimental.use_asset_browser
return context.preferences.experimental.use_extended_asset_browser
def draw(self, context):
layout = self.layout

View File

@ -148,20 +148,6 @@ class SEQUENCER_HT_header(Header):
layout.separator_spacer()
if st.view_type in {'PREVIEW', 'SEQUENCER_PREVIEW'}:
layout.prop(st, "display_mode", text="", icon_only=True)
layout.prop(st, "preview_channels", text="", icon_only=True)
gpd = context.gpencil_data
tool_settings = context.tool_settings
# Proportional editing
if gpd and gpd.use_stroke_edit_mode:
row = layout.row(align=True)
row.prop(tool_settings, "use_proportional_edit", icon_only=True)
if tool_settings.use_proportional_edit:
row.prop(tool_settings, "proportional_edit_falloff", icon_only=True)
if st.view_type in {'SEQUENCER', 'SEQUENCER_PREVIEW'}:
tool_settings = context.tool_settings
row = layout.row(align=True)
@ -170,6 +156,10 @@ class SEQUENCER_HT_header(Header):
sub.popover(panel="SEQUENCER_PT_snapping")
layout.separator_spacer()
if st.view_type in {'PREVIEW', 'SEQUENCER_PREVIEW'}:
layout.prop(st, "display_mode", text="", icon_only=True)
layout.prop(st, "preview_channels", text="", icon_only=True)
row = layout.row(align=True)
row.prop(st, "show_strip_overlay", text="", icon='OVERLAY')
sub = row.row(align=True)

View File

@ -55,7 +55,7 @@ class SPREADSHEET_HT_header(bpy.types.Header):
layout.operator("spreadsheet.toggle_pin", text="", icon=pin_icon, emboss=False)
if space.object_eval_state == 'VIEWER_NODE' and len(context_path) < 3:
layout.label(text="No active viewer node.", icon='INFO')
layout.label(text="No active viewer node", icon='INFO')
layout.separator_spacer()

View File

@ -268,10 +268,7 @@ class TEXT_MT_text(Menu):
layout.operator("text.make_internal")
layout.separator()
row = layout.row()
row.active = text.name.endswith(".py")
row.prop(text, "use_module")
row = layout.row()
layout.prop(text, "use_module")
layout.prop(st, "use_live_edit")

View File

@ -1905,6 +1905,7 @@ class _defs_gpencil_paint:
brush_basic__draw_color_selector(context, layout, brush, gp_settings, props)
brush_basic_gpencil_paint_settings(layout, context, brush, compact=True)
return True
@staticmethod
def generate_from_brushes(context):

View File

@ -1366,11 +1366,6 @@ class USERPREF_PT_saveload_autorun(FilePathsPanel, Panel):
class USERPREF_PT_file_paths_asset_libraries(FilePathsPanel, Panel):
bl_label = "Asset Libraries"
@classmethod
def poll(cls, context):
prefs = context.preferences
return prefs.experimental.use_asset_browser
def draw(self, context):
layout = self.layout
layout.use_property_split = False
@ -2259,7 +2254,7 @@ class USERPREF_PT_experimental_new_features(ExperimentalPanel, Panel):
({"property": "use_sculpt_vertex_colors"}, "T71947"),
({"property": "use_sculpt_uvsmooth"}, ""),
({"property": "use_sculpt_tools_tilt"}, "T82877"),
({"property": "use_asset_browser"}, ("project/profile/124/", "Milestone 1")),
({"property": "use_extended_asset_browser"}, ("project/view/130/", "Project Page")),
({"property": "use_override_templates"}, ("T73318", "Milestone 4")),
),
)

View File

@ -1854,6 +1854,7 @@ class VIEW3D_MT_select_gpencil(Menu):
layout.operator("gpencil.select_linked", text="Linked")
layout.operator("gpencil.select_alternate")
layout.operator("gpencil.select_random")
layout.operator_menu_enum("gpencil.select_grouped", "type", text="Grouped")
if context.mode == 'VERTEX_GPENCIL':

View File

@ -1100,7 +1100,7 @@ class VIEW3D_PT_tools_vertexpaint_options(Panel, View3DPaintPanel):
bl_options = {'DEFAULT_CLOSED'}
@classmethod
def poll(self, _context):
def poll(cls, _context):
# This is currently unused, since there aren't any Vertex Paint mode specific options.
return False

View File

@ -308,28 +308,6 @@ void blf_font_size(FontBLF *font, unsigned int size, unsigned int dpi)
blf_glyph_cache_release(font);
}
static GlyphBLF **blf_font_ensure_ascii_table(FontBLF *font, GlyphCacheBLF *gc)
{
GlyphBLF **glyph_ascii_table;
glyph_ascii_table = gc->glyph_ascii_table;
/* build ascii on demand */
if (glyph_ascii_table['0'] == NULL) {
GlyphBLF *g;
for (uint i = 0; i < 256; i++) {
g = blf_glyph_search(gc, i);
if (!g) {
FT_UInt glyph_index = FT_Get_Char_Index(font->face, i);
g = blf_glyph_add(font, gc, glyph_index, i);
}
glyph_ascii_table[i] = g;
}
}
return glyph_ascii_table;
}
static void blf_font_ensure_ascii_kerning(FontBLF *font,
GlyphCacheBLF *gc,
const FT_UInt kern_mode)
@ -351,11 +329,12 @@ static void blf_font_ensure_ascii_kerning(FontBLF *font,
* characters.
*/
/* NOTE: `blf_font_ensure_ascii_table(font, gc);` must be called before this macro. */
#define BLF_UTF8_NEXT_FAST(_font, _gc, _g, _str, _i, _c, _glyph_ascii_table) \
if (((_c) = (_str)[_i]) < 0x80) { \
_g = (_glyph_ascii_table)[_c]; \
#define BLF_UTF8_NEXT_FAST(_font, _gc, _g, _str, _i, _c) \
if (((_c) = (_str)[_i]) < GLYPH_ASCII_TABLE_SIZE) { \
if ((_g = (_gc->glyph_ascii_table)[_c]) == NULL) { \
_g = blf_glyph_add(_font, _gc, FT_Get_Char_Index((_font)->face, _c), _c); \
_gc->glyph_ascii_table[_c] = _g; \
} \
_i++; \
} \
else if ((_c = BLI_str_utf8_as_unicode_step(_str, &(_i))) != BLI_UTF8_ERR) { \
@ -369,11 +348,10 @@ static void blf_font_ensure_ascii_kerning(FontBLF *font,
(void)0
#define BLF_KERNING_VARS(_font, _has_kerning, _kern_mode) \
const bool _has_kerning = FT_HAS_KERNING((_font)->face) != 0; \
const FT_UInt _kern_mode = (_has_kerning == 0) ? 0 : \
(((_font)->flags & BLF_KERNING_DEFAULT) ? \
ft_kerning_default : \
(FT_UInt)FT_KERNING_UNFITTED)
const bool _has_kerning = FT_HAS_KERNING((_font)->face); \
const FT_UInt _kern_mode = (_has_kerning && !((_font)->flags & BLF_KERNING_DEFAULT)) ? \
FT_KERNING_UNFITTED : \
FT_KERNING_DEFAULT;
/* NOTE: `blf_font_ensure_ascii_kerning(font, gc, kern_mode);` must be called before this macro. */
@ -381,7 +359,7 @@ static void blf_font_ensure_ascii_kerning(FontBLF *font,
{ \
if (_g_prev) { \
FT_Vector _delta; \
if (_c_prev < 0x80 && _c < 0x80) { \
if (_c_prev < KERNING_CACHE_TABLE_SIZE && _c < GLYPH_ASCII_TABLE_SIZE) { \
_pen_x += (_font)->kerning_cache->table[_c][_c_prev]; \
} \
else if (FT_Get_Kerning((_font)->face, (_g_prev)->idx, (_g)->idx, _kern_mode, &(_delta)) == \
@ -420,8 +398,6 @@ static void blf_font_draw_ex(FontBLF *font,
return;
}
GlyphBLF **glyph_ascii_table = blf_font_ensure_ascii_table(font, gc);
BLF_KERNING_VARS(font, has_kerning, kern_mode);
blf_font_ensure_ascii_kerning(font, gc, kern_mode);
@ -429,7 +405,7 @@ static void blf_font_draw_ex(FontBLF *font,
blf_batch_draw_begin(font);
while ((i < len) && str[i]) {
BLF_UTF8_NEXT_FAST(font, gc, g, str, i, c, glyph_ascii_table);
BLF_UTF8_NEXT_FAST(font, gc, g, str, i, c);
if (UNLIKELY(c == BLI_UTF8_ERR)) {
break;
@ -472,7 +448,6 @@ static void blf_font_draw_ascii_ex(
int pen_x = 0;
GlyphCacheBLF *gc = blf_glyph_cache_acquire(font);
GlyphBLF **glyph_ascii_table = blf_font_ensure_ascii_table(font, gc);
BLF_KERNING_VARS(font, has_kerning, kern_mode);
@ -481,9 +456,12 @@ static void blf_font_draw_ascii_ex(
blf_batch_draw_begin(font);
while ((c = *(str++)) && len--) {
BLI_assert(c < 128);
if ((g = glyph_ascii_table[c]) == NULL) {
continue;
BLI_assert(c < GLYPH_ASCII_TABLE_SIZE);
if ((g = gc->glyph_ascii_table[c]) == NULL) {
g = blf_glyph_add(font, gc, FT_Get_Char_Index((font)->face, c), c);
if ((gc->glyph_ascii_table[c] = g) == NULL) {
continue;
}
}
if (has_kerning) {
BLF_KERNING_STEP_FAST(font, kern_mode, g_prev, g, c_prev, c, pen_x);
@ -522,12 +500,11 @@ int blf_font_draw_mono(FontBLF *font, const char *str, size_t len, int cwidth)
size_t i = 0;
GlyphCacheBLF *gc = blf_glyph_cache_acquire(font);
GlyphBLF **glyph_ascii_table = blf_font_ensure_ascii_table(font, gc);
blf_batch_draw_begin(font);
while ((i < len) && str[i]) {
BLF_UTF8_NEXT_FAST(font, gc, g, str, i, c, glyph_ascii_table);
BLF_UTF8_NEXT_FAST(font, gc, g, str, i, c);
if (UNLIKELY(c == BLI_UTF8_ERR)) {
break;
@ -568,8 +545,6 @@ static void blf_font_draw_buffer_ex(FontBLF *font,
int pen_y_basis = (int)font->pos[1] + pen_y;
size_t i = 0;
GlyphBLF **glyph_ascii_table = blf_font_ensure_ascii_table(font, gc);
/* buffer specific vars */
FontBufInfoBLF *buf_info = &font->buf_info;
const float *b_col_float = buf_info->col_float;
@ -584,7 +559,7 @@ static void blf_font_draw_buffer_ex(FontBLF *font,
/* another buffer specific call for color conversion */
while ((i < len) && str[i]) {
BLF_UTF8_NEXT_FAST(font, gc, g, str, i, c, glyph_ascii_table);
BLF_UTF8_NEXT_FAST(font, gc, g, str, i, c);
if (UNLIKELY(c == BLI_UTF8_ERR)) {
break;
@ -741,7 +716,6 @@ size_t blf_font_width_to_strlen(
size_t i, i_prev;
GlyphCacheBLF *gc = blf_glyph_cache_acquire(font);
GlyphBLF **glyph_ascii_table = blf_font_ensure_ascii_table(font, gc);
const int width_i = (int)width;
BLF_KERNING_VARS(font, has_kerning, kern_mode);
@ -752,7 +726,7 @@ size_t blf_font_width_to_strlen(
for (i_prev = i = 0, width_new = pen_x = 0, g_prev = NULL, c_prev = 0; (i < len) && str[i];
i_prev = i, width_new = pen_x, c_prev = c, g_prev = g) {
BLF_UTF8_NEXT_FAST(font, gc, g, str, i, c, glyph_ascii_table);
BLF_UTF8_NEXT_FAST(font, gc, g, str, i, c);
if (blf_font_width_to_strlen_glyph_process(
font, has_kerning, kern_mode, c_prev, c, g_prev, g, &pen_x, width_i)) {
@ -778,7 +752,6 @@ size_t blf_font_width_to_rstrlen(
char *s, *s_prev;
GlyphCacheBLF *gc = blf_glyph_cache_acquire(font);
GlyphBLF **glyph_ascii_table = blf_font_ensure_ascii_table(font, gc);
const int width_i = (int)width;
BLF_KERNING_VARS(font, has_kerning, kern_mode);
@ -794,7 +767,7 @@ size_t blf_font_width_to_rstrlen(
i_prev = (size_t)((s_prev != NULL) ? s_prev - str : 0);
i_tmp = i;
BLF_UTF8_NEXT_FAST(font, gc, g, str, i_tmp, c, glyph_ascii_table);
BLF_UTF8_NEXT_FAST(font, gc, g, str, i_tmp, c);
for (width_new = pen_x = 0; (s != NULL);
i = i_prev, s = s_prev, c = c_prev, g = g_prev, g_prev = NULL, width_new = pen_x) {
s_prev = BLI_str_find_prev_char_utf8(str, s);
@ -802,7 +775,7 @@ size_t blf_font_width_to_rstrlen(
if (s_prev != NULL) {
i_tmp = i_prev;
BLF_UTF8_NEXT_FAST(font, gc, g_prev, str, i_tmp, c_prev, glyph_ascii_table);
BLF_UTF8_NEXT_FAST(font, gc, g_prev, str, i_tmp, c_prev);
BLI_assert(i_tmp == i);
}
@ -832,9 +805,6 @@ static void blf_font_boundbox_ex(FontBLF *font,
GlyphBLF *g, *g_prev = NULL;
int pen_x = 0;
size_t i = 0;
GlyphBLF **glyph_ascii_table = blf_font_ensure_ascii_table(font, gc);
rctf gbox;
BLF_KERNING_VARS(font, has_kerning, kern_mode);
@ -847,7 +817,7 @@ static void blf_font_boundbox_ex(FontBLF *font,
blf_font_ensure_ascii_kerning(font, gc, kern_mode);
while ((i < len) && str[i]) {
BLF_UTF8_NEXT_FAST(font, gc, g, str, i, c, glyph_ascii_table);
BLF_UTF8_NEXT_FAST(font, gc, g, str, i, c);
if (UNLIKELY(c == BLI_UTF8_ERR)) {
break;
@ -937,7 +907,6 @@ static void blf_font_wrap_apply(FontBLF *font,
int pen_x_next = 0;
GlyphCacheBLF *gc = blf_glyph_cache_acquire(font);
GlyphBLF **glyph_ascii_table = blf_font_ensure_ascii_table(font, gc);
BLF_KERNING_VARS(font, has_kerning, kern_mode);
@ -953,7 +922,7 @@ static void blf_font_wrap_apply(FontBLF *font,
size_t i_curr = i;
bool do_draw = false;
BLF_UTF8_NEXT_FAST(font, gc, g, str, i, c, glyph_ascii_table);
BLF_UTF8_NEXT_FAST(font, gc, g, str, i, c);
if (UNLIKELY(c == BLI_UTF8_ERR)) {
break;
@ -1154,8 +1123,6 @@ float blf_font_fixed_width(FontBLF *font)
const unsigned int c = ' ';
GlyphCacheBLF *gc = blf_glyph_cache_acquire(font);
blf_font_ensure_ascii_table(font, gc);
GlyphBLF *g = blf_glyph_search(gc, c);
if (!g) {
g = blf_glyph_add(font, gc, FT_Get_Char_Index(font->face, c), c);
@ -1195,15 +1162,13 @@ static void blf_font_boundbox_foreach_glyph_ex(FontBLF *font,
return;
}
GlyphBLF **glyph_ascii_table = blf_font_ensure_ascii_table(font, gc);
BLF_KERNING_VARS(font, has_kerning, kern_mode);
blf_font_ensure_ascii_kerning(font, gc, kern_mode);
while ((i < len) && str[i]) {
i_curr = i;
BLF_UTF8_NEXT_FAST(font, gc, g, str, i, c, glyph_ascii_table);
BLF_UTF8_NEXT_FAST(font, gc, g, str, i, c);
if (UNLIKELY(c == BLI_UTF8_ERR)) {
break;
@ -1261,7 +1226,7 @@ int blf_font_count_missing_chars(FontBLF *font,
while (i < len) {
unsigned int c;
if ((c = str[i]) < 0x80) {
if ((c = str[i]) < GLYPH_ASCII_TABLE_SIZE) {
i++;
}
else if ((c = BLI_str_utf8_as_unicode_step(str, &i)) != BLI_UTF8_ERR) {
@ -1429,7 +1394,6 @@ int blf_font_height_max(FontBLF *font)
int height_max;
GlyphCacheBLF *gc = blf_glyph_cache_acquire(font);
blf_font_ensure_ascii_table(font, gc);
height_max = gc->glyph_height_max;
blf_glyph_cache_release(font);
@ -1441,7 +1405,6 @@ int blf_font_width_max(FontBLF *font)
int width_max;
GlyphCacheBLF *gc = blf_glyph_cache_acquire(font);
blf_font_ensure_ascii_table(font, gc);
width_max = gc->glyph_width_max;
blf_glyph_cache_release(font);
@ -1453,7 +1416,6 @@ float blf_font_descender(FontBLF *font)
float descender;
GlyphCacheBLF *gc = blf_glyph_cache_acquire(font);
blf_font_ensure_ascii_table(font, gc);
descender = gc->descender;
blf_glyph_cache_release(font);
@ -1465,7 +1427,6 @@ float blf_font_ascender(FontBLF *font)
float ascender;
GlyphCacheBLF *gc = blf_glyph_cache_acquire(font);
blf_font_ensure_ascii_table(font, gc);
ascender = gc->ascender;
blf_glyph_cache_release(font);

View File

@ -80,8 +80,8 @@ KerningCacheBLF *blf_kerning_cache_new(FontBLF *font, GlyphCacheBLF *gc)
kc->mode = font->kerning_mode;
unsigned int i, j;
for (i = 0; i < 0x80; i++) {
for (j = 0; j < 0x80; j++) {
for (i = 0; i < KERNING_CACHE_TABLE_SIZE; i++) {
for (j = 0; j < KERNING_CACHE_TABLE_SIZE; j++) {
GlyphBLF *g = blf_glyph_search(gc, i);
if (!g) {
FT_UInt glyph_index = FT_Get_Char_Index(font->face, i);
@ -144,8 +144,6 @@ GlyphCacheBLF *blf_glyph_cache_new(FontBLF *font)
memset(gc->glyph_ascii_table, 0, sizeof(gc->glyph_ascii_table));
memset(gc->bucket, 0, sizeof(gc->bucket));
gc->glyphs_len_max = (int)font->face->num_glyphs;
gc->glyphs_len_free = (int)font->face->num_glyphs;
gc->ascender = ((float)font->face->size->metrics.ascender) / 64.0f;
gc->descender = ((float)font->face->size->metrics.descender) / 64.0f;
@ -514,7 +512,6 @@ void blf_glyph_render(FontBLF *font, GlyphCacheBLF *gc, GlyphBLF *g, float x, fl
memcpy(&gc->bitmap_result[gc->bitmap_len], g->bitmap, (size_t)buff_size);
gc->bitmap_len = bitmap_len;
gc->glyphs_len_free--;
g->glyph_cache = gc;
}

View File

@ -28,6 +28,12 @@
#define BLF_BATCH_DRAW_LEN_MAX 2048 /* in glyph */
/* Number of characters in GlyphCacheBLF.glyph_ascii_table. */
#define GLYPH_ASCII_TABLE_SIZE 128
/* Number of characters in KerningCacheBLF.table. */
#define KERNING_CACHE_TABLE_SIZE 128
typedef struct BatchBLF {
struct FontBLF *font; /* can only batch glyph from the same font */
struct GPUBatch *batch;
@ -51,7 +57,7 @@ typedef struct KerningCacheBLF {
/* only cache a ascii glyph pairs. Only store the x
* offset we are interested in, instead of the full FT_Vector. */
int table[0x80][0x80];
int table[KERNING_CACHE_TABLE_SIZE][KERNING_CACHE_TABLE_SIZE];
} KerningCacheBLF;
typedef struct GlyphCacheBLF {
@ -71,7 +77,7 @@ typedef struct GlyphCacheBLF {
ListBase bucket[257];
/* fast ascii lookup */
struct GlyphBLF *glyph_ascii_table[256];
struct GlyphBLF *glyph_ascii_table[GLYPH_ASCII_TABLE_SIZE];
/* texture array, to draw the glyphs. */
GPUTexture *texture;
@ -84,12 +90,6 @@ typedef struct GlyphCacheBLF {
int glyph_width_max;
int glyph_height_max;
/* number of glyphs in the font. */
int glyphs_len_max;
/* number of glyphs not yet loaded (decreases every glyph loaded). */
int glyphs_len_free;
/* ascender and descender value. */
float ascender;
float descender;
@ -99,7 +99,7 @@ typedef struct GlyphBLF {
struct GlyphBLF *next;
struct GlyphBLF *prev;
/* and the character, as UTF8 */
/* and the character, as UTF-32 */
unsigned int c;
/* freetype2 index, to speed-up the search. */

View File

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

View File

@ -69,7 +69,7 @@ typedef struct BVHTreeFromMesh {
BVHTree_NearestPointCallback nearest_callback;
BVHTree_RayCastCallback raycast_callback;
/* Vertex array, so that callbacks have instante access to data */
/* Vertex array, so that callbacks have instant access to data. */
const struct MVert *vert;
const struct MEdge *edge; /* only used for BVHTreeFromMeshEdges */
const struct MFace *face;

View File

@ -65,7 +65,7 @@ void BKE_collection_add_from_collection(struct Main *bmain,
struct Scene *scene,
struct Collection *collection_src,
struct Collection *collection_dst);
void BKE_collection_free(struct Collection *collection);
void BKE_collection_free_data(struct Collection *collection);
bool BKE_collection_delete(struct Main *bmain, struct Collection *collection, bool hierarchy);
struct Collection *BKE_collection_duplicate(struct Main *bmain,

View File

@ -192,6 +192,28 @@ bool BKE_constraint_remove_ex(ListBase *list,
bool clear_dep);
bool BKE_constraint_remove(ListBase *list, struct bConstraint *con);
bool BKE_constraint_apply_for_object(struct Depsgraph *depsgraph,
struct Scene *scene,
struct Object *ob,
struct bConstraint *con);
bool BKE_constraint_apply_and_remove_for_object(struct Depsgraph *depsgraph,
struct Scene *scene,
ListBase /*bConstraint*/ *constraints,
struct Object *ob,
struct bConstraint *con);
bool BKE_constraint_apply_for_pose(struct Depsgraph *depsgraph,
struct Scene *scene,
struct Object *ob,
struct bPoseChannel *pchan,
struct bConstraint *con);
bool BKE_constraint_apply_and_remove_for_pose(struct Depsgraph *depsgraph,
struct Scene *scene,
ListBase /*bConstraint*/ *constraints,
struct Object *ob,
struct bConstraint *con,
struct bPoseChannel *pchan);
void BKE_constraint_panel_expand(struct bConstraint *con);
/* Constraints + Proxies function prototypes */

View File

@ -145,7 +145,8 @@ enum {
G_DEBUG_DEPSGRAPH_TIME = (1 << 11), /* depsgraph timing statistics and messages */
G_DEBUG_DEPSGRAPH_NO_THREADS = (1 << 12), /* single threaded depsgraph */
G_DEBUG_DEPSGRAPH_PRETTY = (1 << 13), /* use pretty colors in depsgraph messages */
G_DEBUG_DEPSGRAPH_UUID = (1 << 14), /* use pretty colors in depsgraph messages */
G_DEBUG_DEPSGRAPH_UUID = (1 << 14), /* Verify validness of session-wide identifiers
* assigned to ID datablocks */
G_DEBUG_DEPSGRAPH = (G_DEBUG_DEPSGRAPH_BUILD | G_DEBUG_DEPSGRAPH_EVAL | G_DEBUG_DEPSGRAPH_TAG |
G_DEBUG_DEPSGRAPH_TIME | G_DEBUG_DEPSGRAPH_UUID),
G_DEBUG_SIMDATA = (1 << 15), /* sim debug data display */

View File

@ -152,8 +152,6 @@ void BKE_libblock_copy_ex(struct Main *bmain,
const int orig_flag);
void *BKE_libblock_copy(struct Main *bmain, const struct ID *id) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL();
/* Special version: used by data-block localization. */
void *BKE_libblock_copy_for_localize(const struct ID *id);
void BKE_libblock_rename(struct Main *bmain, struct ID *id, const char *name) ATTR_NONNULL();
void BLI_libblock_ensure_unique_name(struct Main *bmain, const char *name) ATTR_NONNULL();
@ -201,6 +199,8 @@ enum {
void BKE_libblock_free_datablock(struct ID *id, const int flag) ATTR_NONNULL();
void BKE_libblock_free_data(struct ID *id, const bool do_id_user) ATTR_NONNULL();
void BKE_libblock_free_data_py(struct ID *id);
void BKE_id_free_ex(struct Main *bmain, void *idv, int flag, const bool use_flag_from_idtag);
void BKE_id_free(struct Main *bmain, void *idv);

View File

@ -282,39 +282,21 @@ void BKE_mesh_recalc_looptri_with_normals(const struct MLoop *mloop,
/* *** mesh_normals.cc *** */
void BKE_mesh_normals_tag_dirty(struct Mesh *mesh);
void BKE_mesh_calc_normals_mapping_simple(struct Mesh *me);
void BKE_mesh_calc_normals_mapping(struct MVert *mverts,
int numVerts,
const struct MLoop *mloop,
const struct MPoly *mpolys,
int numLoops,
int numPolys,
float (*r_polyNors)[3],
const struct MFace *mfaces,
int numFaces,
const int *origIndexFace,
float (*r_faceNors)[3]);
void BKE_mesh_calc_normals_mapping_ex(struct MVert *mverts,
int numVerts,
const struct MLoop *mloop,
const struct MPoly *mpolys,
int numLoops,
int numPolys,
float (*r_polyNors)[3],
const struct MFace *mfaces,
int numFaces,
const int *origIndexFace,
float (*r_faceNors)[3],
const bool only_face_normals);
void BKE_mesh_calc_normals_poly(struct MVert *mverts,
float (*r_vertnors)[3],
int numVerts,
void BKE_mesh_calc_normals_poly(const struct MVert *mvert,
int mvert_len,
const struct MLoop *mloop,
const struct MPoly *mpolys,
int numLoops,
int numPolys,
float (*r_polyNors)[3],
const bool only_face_normals);
int mloop_len,
const struct MPoly *mpoly,
int mpoly_len,
float (*r_poly_normals)[3]);
void BKE_mesh_calc_normals_poly_and_vertex(struct MVert *mvert,
int mvert_len,
const struct MLoop *mloop,
int mloop_len,
const struct MPoly *mpolys,
int mpoly_len,
float (*r_poly_normals)[3],
float (*r_vert_normals)[3]);
void BKE_mesh_calc_normals(struct Mesh *me);
void BKE_mesh_ensure_normals(struct Mesh *me);
void BKE_mesh_ensure_normals_for_display(struct Mesh *mesh);

View File

@ -360,7 +360,7 @@ void DM_init(DerivedMesh *dm,
dm->needsFree = 1;
dm->dirty = (DMDirtyFlag)0;
/* Don't use CustomData_reset(...); because we don't want to touch custom-data. */
/* Don't use #CustomData_reset because we don't want to touch custom-data. */
copy_vn_i(dm->vertData.typemap, CD_NUMTYPES, -1);
copy_vn_i(dm->edgeData.typemap, CD_NUMTYPES, -1);
copy_vn_i(dm->faceData.typemap, CD_NUMTYPES, -1);
@ -816,15 +816,14 @@ static void mesh_calc_modifier_final_normals(const Mesh *mesh_input,
if (!CustomData_has_layer(&mesh_final->pdata, CD_NORMAL)) {
float(*polynors)[3] = (float(*)[3])CustomData_add_layer(
&mesh_final->pdata, CD_NORMAL, CD_CALLOC, nullptr, mesh_final->totpoly);
BKE_mesh_calc_normals_poly(mesh_final->mvert,
nullptr,
mesh_final->totvert,
mesh_final->mloop,
mesh_final->mpoly,
mesh_final->totloop,
mesh_final->totpoly,
polynors,
false);
BKE_mesh_calc_normals_poly_and_vertex(mesh_final->mvert,
mesh_final->totvert,
mesh_final->mloop,
mesh_final->totloop,
mesh_final->mpoly,
mesh_final->totpoly,
polynors,
nullptr);
}
}
@ -1536,15 +1535,14 @@ static void editbmesh_calc_modifier_final_normals(Mesh *mesh_final,
if (!CustomData_has_layer(&mesh_final->pdata, CD_NORMAL)) {
float(*polynors)[3] = (float(*)[3])CustomData_add_layer(
&mesh_final->pdata, CD_NORMAL, CD_CALLOC, nullptr, mesh_final->totpoly);
BKE_mesh_calc_normals_poly(mesh_final->mvert,
nullptr,
mesh_final->totvert,
mesh_final->mloop,
mesh_final->mpoly,
mesh_final->totloop,
mesh_final->totpoly,
polynors,
false);
BKE_mesh_calc_normals_poly_and_vertex(mesh_final->mvert,
mesh_final->totvert,
mesh_final->mloop,
mesh_final->totloop,
mesh_final->mpoly,
mesh_final->totpoly,
polynors,
nullptr);
}
}

View File

@ -2671,7 +2671,7 @@ static void animsys_create_action_track_strip(const AnimData *adt,
static bool is_nlatrack_evaluatable(const AnimData *adt, const NlaTrack *nlt)
{
/* Skip disabled tracks unless it contains the tweaked strip. */
const bool contains_tweak_strip = (adt->flag & ADT_NLA_EDIT_ON) &&
const bool contains_tweak_strip = (adt->flag & ADT_NLA_EDIT_ON) && adt->act_track &&
(nlt->index == adt->act_track->index);
if ((nlt->flag & NLATRACK_DISABLED) && !contains_tweak_strip) {
return false;

View File

@ -660,10 +660,6 @@ UserDef *BKE_blendfile_userdef_from_defaults(void)
BKE_studiolight_default(userdef->light_param, userdef->light_ambient);
BKE_preferences_asset_library_default_add(userdef);
/* Enable asset browser features by default for alpha testing.
* BLO_sanitize_experimental_features_userpref_blend() will disable it again for non-alpha
* builds. */
userdef->experimental.use_asset_browser = true;
return userdef;
}

View File

@ -508,7 +508,7 @@ void BKE_collection_add_from_collection(Main *bmain,
* \{ */
/** Free (or release) any data used by this collection (does not free the collection itself). */
void BKE_collection_free(Collection *collection)
void BKE_collection_free_data(Collection *collection)
{
BKE_libblock_free_data(&collection->id, false);
collection_free_data(&collection->id);

View File

@ -5677,6 +5677,111 @@ bool BKE_constraint_remove_ex(ListBase *list, Object *ob, bConstraint *con, bool
return false;
}
/* Apply the specified constraint in the given constraint stack */
bool BKE_constraint_apply_for_object(Depsgraph *depsgraph,
Scene *scene,
Object *ob,
bConstraint *con)
{
if (!con) {
return false;
}
const float ctime = BKE_scene_frame_get(scene);
bConstraint *new_con = BKE_constraint_duplicate_ex(con, 0, !ID_IS_LINKED(ob));
ListBase single_con = {new_con, new_con};
bConstraintOb *cob = BKE_constraints_make_evalob(
depsgraph, scene, ob, NULL, CONSTRAINT_OBTYPE_OBJECT);
/* Undo the effect of the current constraint stack evaluation. */
mul_m4_m4m4(cob->matrix, ob->constinv, cob->matrix);
/* Evaluate single constraint. */
BKE_constraints_solve(depsgraph, &single_con, cob, ctime);
/* Copy transforms back. This will leave the object in a bad state
* as ob->constinv will be wrong until next evaluation. */
BKE_constraints_clear_evalob(cob);
/* Free the copied constraint. */
BKE_constraint_free_data(new_con);
BLI_freelinkN(&single_con, new_con);
/* Apply transform from matrix. */
BKE_object_apply_mat4(ob, ob->obmat, true, true);
return true;
}
bool BKE_constraint_apply_and_remove_for_object(Depsgraph *depsgraph,
Scene *scene,
ListBase /*bConstraint*/ *constraints,
Object *ob,
bConstraint *con)
{
if (!BKE_constraint_apply_for_object(depsgraph, scene, ob, con)) {
return false;
}
return BKE_constraint_remove_ex(constraints, ob, con, true);
}
bool BKE_constraint_apply_for_pose(
Depsgraph *depsgraph, Scene *scene, Object *ob, bPoseChannel *pchan, bConstraint *con)
{
if (!con) {
return false;
}
const float ctime = BKE_scene_frame_get(scene);
bConstraint *new_con = BKE_constraint_duplicate_ex(con, 0, !ID_IS_LINKED(ob));
ListBase single_con;
single_con.first = new_con;
single_con.last = new_con;
float vec[3];
copy_v3_v3(vec, pchan->pose_mat[3]);
bConstraintOb *cob = BKE_constraints_make_evalob(
depsgraph, scene, ob, pchan, CONSTRAINT_OBTYPE_BONE);
/* Undo the effects of currently applied constraints. */
mul_m4_m4m4(cob->matrix, pchan->constinv, cob->matrix);
/* Evaluate single constraint. */
BKE_constraints_solve(depsgraph, &single_con, cob, ctime);
BKE_constraints_clear_evalob(cob);
/* Free the copied constraint. */
BKE_constraint_free_data(new_con);
BLI_freelinkN(&single_con, new_con);
/* Prevent constraints breaking a chain. */
if (pchan->bone->flag & BONE_CONNECTED) {
copy_v3_v3(pchan->pose_mat[3], vec);
}
/* Apply transform from matrix. */
float mat[4][4];
BKE_armature_mat_pose_to_bone(pchan, pchan->pose_mat, mat);
BKE_pchan_apply_mat4(pchan, mat, true);
return true;
}
bool BKE_constraint_apply_and_remove_for_pose(Depsgraph *depsgraph,
Scene *scene,
ListBase /*bConstraint*/ *constraints,
Object *ob,
bConstraint *con,
bPoseChannel *pchan)
{
if (!BKE_constraint_apply_for_pose(depsgraph, scene, ob, pchan, con)) {
return false;
}
return BKE_constraint_remove_ex(constraints, ob, con, true);
}
void BKE_constraint_panel_expand(bConstraint *con)
{
con->ui_expand_flag |= UI_PANEL_DATA_EXPAND_ROOT;

View File

@ -638,7 +638,7 @@ void BKE_nurb_free(Nurb *nu)
MEM_freeN(nu->knotsv);
}
nu->knotsv = NULL;
/* if (nu->trim.first) freeNurblist(&(nu->trim)); */
// if (nu->trim.first) freeNurblist(&(nu->trim));
MEM_freeN(nu);
}

View File

@ -4524,7 +4524,7 @@ void CustomData_blend_write_prepare(CustomData *data,
CustomDataLayer *layer = &data->layers[i];
if (layer->flag & CD_FLAG_NOCOPY) { /* Layers with this flag set are not written to file. */
data->totlayer--;
/* CLOG_WARN(&LOG, "skipping layer %p (%s)", layer, layer->name); */
// CLOG_WARN(&LOG, "skipping layer %p (%s)", layer, layer->name);
}
else {
if (UNLIKELY((size_t)j >= write_layers_size)) {

View File

@ -304,14 +304,12 @@ static void data_transfer_dtdata_type_preprocess(Mesh *me_src,
}
if (dirty_nors_dst || do_poly_nors_dst) {
BKE_mesh_calc_normals_poly(verts_dst,
NULL,
num_verts_dst,
loops_dst,
polys_dst,
num_loops_dst,
polys_dst,
num_polys_dst,
poly_nors_dst,
true);
poly_nors_dst);
}
/* Cache loop nors into a temp CDLayer. */
loop_nors_dst = CustomData_get_layer(ldata_dst, CD_NORMAL);

View File

@ -1003,7 +1003,7 @@ static void curve_calc_modifiers_post(Depsgraph *depsgraph,
modified = temp_mesh;
BKE_mesh_vert_coords_apply(modified, vertCos);
BKE_mesh_calc_normals_mapping_simple(modified);
BKE_mesh_calc_normals(modified);
MEM_freeN(vertCos);
}

View File

@ -715,6 +715,11 @@ typedef struct VFontToCurveIter {
float max;
} bisect;
bool ok;
/**
* Disables checking if word wrapping is needed to fit the text-box width.
* Currently only used when scale-to-fit is enabled.
*/
bool word_wrap;
int status;
} VFontToCurveIter;
@ -777,6 +782,7 @@ static bool vfont_to_curve(Object *ob,
char32_t ascii;
bool ok = false;
const float font_size = cu->fsize * iter_data->scale_to_fit;
const bool word_wrap = iter_data->word_wrap;
const float xof_scale = cu->xof / font_size;
const float yof_scale = cu->yof / font_size;
int last_line = -1;
@ -947,43 +953,59 @@ static bool vfont_to_curve(Object *ob,
twidth = char_width(cu, che, info);
/* Calculate positions */
if ((tb_scale.w != 0.0f) && (ct->dobreak == 0) &&
(((xof - tb_scale.x) + twidth) > xof_scale + tb_scale.w)) {
// CLOG_WARN(&LOG, "linewidth exceeded: %c%c%c...", mem[i], mem[i+1], mem[i+2]);
for (j = i; j && (mem[j] != '\n') && (chartransdata[j].dobreak == 0); j--) {
bool dobreak = false;
if (ELEM(mem[j], ' ', '-')) {
ct -= (i - (j - 1));
cnr -= (i - (j - 1));
if (mem[j] == ' ') {
wsnr--;
}
if (mem[j] == '-') {
wsnr++;
}
i = j - 1;
xof = ct->xof;
ct[1].dobreak = 1;
custrinfo[i + 1].flag |= CU_CHINFO_WRAP;
dobreak = true;
/* Calculate positions. */
if ((tb_scale.w != 0.0f) && (ct->dobreak == 0)) { /* May need wrapping. */
const float x_available = xof_scale + tb_scale.w;
const float x_used = (xof - tb_scale.x) + twidth;
if (word_wrap == false) {
/* When scale to fit is used, don't do any wrapping.
*
* Floating precision error can cause the text to be slightly larger.
* Assert this is a small value as large values indicate incorrect
* calculations with scale-to-fit which shouldn't be ignored. See T89241. */
if (x_used > x_available) {
BLI_assert_msg(compare_ff_relative(x_used, x_available, FLT_EPSILON, 64),
"VFontToCurveIter.scale_to_fit not set correctly!");
}
else if (chartransdata[j].dobreak) {
// CLOG_WARN(&LOG, "word too long: %c%c%c...", mem[j], mem[j+1], mem[j+2]);
ct->dobreak = 1;
custrinfo[i + 1].flag |= CU_CHINFO_WRAP;
ct -= 1;
cnr -= 1;
i--;
xof = ct->xof;
dobreak = true;
}
if (dobreak) {
if (tb_scale.h == 0.0f) {
/* NOTE: If underlined text is truncated away, the extra space is also truncated. */
custrinfo[i + 1].flag |= CU_CHINFO_OVERFLOW;
}
else if (x_used > x_available) {
// CLOG_WARN(&LOG, "linewidth exceeded: %c%c%c...", mem[i], mem[i+1], mem[i+2]);
for (j = i; j && (mem[j] != '\n') && (chartransdata[j].dobreak == 0); j--) {
bool dobreak = false;
if (ELEM(mem[j], ' ', '-')) {
ct -= (i - (j - 1));
cnr -= (i - (j - 1));
if (mem[j] == ' ') {
wsnr--;
}
if (mem[j] == '-') {
wsnr++;
}
i = j - 1;
xof = ct->xof;
ct[1].dobreak = 1;
custrinfo[i + 1].flag |= CU_CHINFO_WRAP;
dobreak = true;
}
else if (chartransdata[j].dobreak) {
// CLOG_WARN(&LOG, "word too long: %c%c%c...", mem[j], mem[j+1], mem[j+2]);
ct->dobreak = 1;
custrinfo[i + 1].flag |= CU_CHINFO_WRAP;
ct -= 1;
cnr -= 1;
i--;
xof = ct->xof;
dobreak = true;
}
if (dobreak) {
if (tb_scale.h == 0.0f) {
/* NOTE: If underlined text is truncated away, the extra space is also truncated. */
custrinfo[i + 1].flag |= CU_CHINFO_OVERFLOW;
}
goto makebreak;
}
goto makebreak;
}
}
}
@ -1545,6 +1567,7 @@ static bool vfont_to_curve(Object *ob,
const float total_text_height = lnr * linedist;
iter_data->scale_to_fit = tb_scale.h / total_text_height;
iter_data->status = VFONT_TO_CURVE_SCALE_ONCE;
iter_data->word_wrap = false;
}
}
else if (tb_scale.h == 0.0f) {
@ -1552,10 +1575,10 @@ static bool vfont_to_curve(Object *ob,
if (longest_line_length > tb_scale.w) {
/* We make sure longest line before it broke can fit here. */
float scale_to_fit = tb_scale.w / longest_line_length;
scale_to_fit -= FLT_EPSILON;
iter_data->scale_to_fit = scale_to_fit;
iter_data->status = VFONT_TO_CURVE_SCALE_ONCE;
iter_data->word_wrap = false;
}
}
}
@ -1616,6 +1639,7 @@ static bool vfont_to_curve(Object *ob,
else {
iter_data->scale_to_fit = iter_data->bisect.min;
iter_data->status = VFONT_TO_CURVE_SCALE_ONCE;
iter_data->word_wrap = false;
}
}
}
@ -1685,6 +1709,7 @@ bool BKE_vfont_to_curve_ex(Object *ob,
VFontToCurveIter data = {
.iteraction = cu->totbox * FONT_TO_CURVE_SCALE_ITERATIONS,
.scale_to_fit = 1.0f,
.word_wrap = true,
.ok = true,
.status = VFONT_TO_CURVE_INIT,
};

View File

@ -491,6 +491,10 @@ static Mesh *join_mesh_topology_and_builtin_attributes(Span<GeometryInstanceGrou
}
}
/* A possible optimization is to only tag the normals dirty when there are transforms that change
* normals. */
BKE_mesh_normals_tag_dirty(new_mesh);
return new_mesh;
}

View File

@ -521,6 +521,7 @@ void BKE_gpencil_eval_delete(bGPdata *gpd_eval)
{
BKE_gpencil_free(gpd_eval, true);
BKE_libblock_free_data(&gpd_eval->id, false);
BLI_assert(!gpd_eval->id.py_instance); /* Or call #BKE_libblock_free_data_py. */
MEM_freeN(gpd_eval);
}

View File

@ -1,4 +1,4 @@
/*
/*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2

View File

@ -1020,7 +1020,7 @@ Image *BKE_image_add_generated(Main *bmain,
int view_id;
const char *names[2] = {STEREO_LEFT_NAME, STEREO_RIGHT_NAME};
/* STRNCPY(ima->filepath, name); */ /* don't do this, this writes in ain invalid filepath! */
// STRNCPY(ima->filepath, name); /* don't do this, this writes in ain invalid filepath! */
ima->gen_x = width;
ima->gen_y = height;
ima->gen_type = gen_type;

View File

@ -2281,15 +2281,8 @@ void BKE_keyblock_mesh_calc_normals(struct KeyBlock *kb,
r_polynors = MEM_mallocN(sizeof(float[3]) * me.totpoly, __func__);
free_polynors = true;
}
BKE_mesh_calc_normals_poly(me.mvert,
r_vertnors,
me.totvert,
me.mloop,
me.mpoly,
me.totloop,
me.totpoly,
r_polynors,
false);
BKE_mesh_calc_normals_poly_and_vertex(
me.mvert, me.totvert, me.mloop, me.totloop, me.mpoly, me.totpoly, r_polynors, r_vertnors);
if (r_loopnors) {
short(*clnors)[2] = CustomData_get_layer(&mesh->ldata, CD_CUSTOMLOOPNORMAL); /* May be NULL. */

View File

@ -1174,6 +1174,52 @@ static void layer_collection_sync(ViewLayer *view_layer,
parent_local_collections_bits);
}
#ifndef NDEBUG
static bool view_layer_objects_base_cache_validate(ViewLayer *view_layer, LayerCollection *layer)
{
bool is_valid = true;
if (layer == NULL) {
layer = view_layer->layer_collections.first;
}
/* Only check for a collection's objects if its layer is not excluded. */
if ((layer->flag & LAYER_COLLECTION_EXCLUDE) == 0) {
LISTBASE_FOREACH (CollectionObject *, cob, &layer->collection->gobject) {
if (cob->ob == NULL) {
continue;
}
if (BLI_ghash_lookup(view_layer->object_bases_hash, cob->ob) == NULL) {
CLOG_FATAL(
&LOG,
"Object '%s' from collection '%s' has no entry in view layer's object bases cache",
cob->ob->id.name + 2,
layer->collection->id.name + 2);
is_valid = false;
break;
}
}
}
if (is_valid) {
LISTBASE_FOREACH (LayerCollection *, layer_child, &layer->layer_collections) {
if (!view_layer_objects_base_cache_validate(view_layer, layer_child)) {
is_valid = false;
break;
}
}
}
return is_valid;
}
#else
static bool view_layer_objects_base_cache_validate(ViewLayer *UNUSED(view_layer),
LayerCollection *UNUSED(layer))
{
return true;
}
#endif
/**
* Update view layer collection tree from collections used in the scene.
* This is used when collections are removed or added, both while editing
@ -1240,6 +1286,12 @@ void BKE_layer_collection_sync(const Scene *scene, ViewLayer *view_layer)
}
if (base->object) {
/* Those asserts are commented, since they are too expensive to perform even in debug, as
* this layer resync function currently gets called way too often. */
#if 0
BLI_assert(BLI_findindex(&new_object_bases, base) == -1);
BLI_assert(BLI_findptr(&new_object_bases, base->object, offsetof(Base, object)) == NULL);
#endif
BLI_ghash_remove(view_layer->object_bases_hash, base->object, NULL, NULL);
}
}
@ -1247,6 +1299,8 @@ void BKE_layer_collection_sync(const Scene *scene, ViewLayer *view_layer)
BLI_freelistN(&view_layer->object_bases);
view_layer->object_bases = new_object_bases;
view_layer_objects_base_cache_validate(view_layer, NULL);
LISTBASE_FOREACH (Base *, base, &view_layer->object_bases) {
BKE_base_eval_flags(base);
}

View File

@ -1321,14 +1321,6 @@ void *BKE_libblock_copy(Main *bmain, const ID *id)
return idn;
}
/* XXX TODO: get rid of this useless wrapper at some point... */
void *BKE_libblock_copy_for_localize(const ID *id)
{
ID *idn;
BKE_libblock_copy_ex(NULL, id, &idn, LIB_ID_COPY_LOCALIZE | LIB_ID_COPY_NO_ANIMDATA);
return idn;
}
/* ***************** ID ************************ */
ID *BKE_libblock_find_name(struct Main *bmain, const short type, const char *name)
{

View File

@ -142,14 +142,7 @@ void BKE_id_free_ex(Main *bmain, void *idv, int flag, const bool use_flag_from_i
DEG_id_type_tag(bmain, type);
}
#ifdef WITH_PYTHON
# ifdef WITH_PYTHON_SAFETY
BPY_id_release(id);
# endif
if (id->py_instance) {
BPY_DECREF_RNA_INVALIDATE(id->py_instance);
}
#endif
BKE_libblock_free_data_py(id);
Key *key = ((flag & LIB_ID_FREE_NO_MAIN) == 0) ? BKE_key_from_id(id) : NULL;
@ -406,3 +399,29 @@ size_t BKE_id_multi_tagged_delete(Main *bmain)
{
return id_delete(bmain, true);
}
/* -------------------------------------------------------------------- */
/** \name Python Data Handling
* \{ */
/**
* In most cases #BKE_id_free_ex handles this, when lower level functions are called directly
* this function will need to be called too, if Python has access to the data.
*
* ID data-blocks such as #Material.nodetree are not stored in #Main.
*/
void BKE_libblock_free_data_py(ID *id)
{
#ifdef WITH_PYTHON
# ifdef WITH_PYTHON_SAFETY
BPY_id_release(id);
# endif
if (id->py_instance) {
BPY_DECREF_RNA_INVALIDATE(id->py_instance);
}
#else
UNUSED_VARS(id);
#endif
}
/** \} */

View File

@ -1020,7 +1020,7 @@ bool BKE_lib_override_library_resync(Main *bmain,
if (id_root_reference->tag & LIB_TAG_MISSING) {
BKE_reportf(reports != NULL ? reports->reports : NULL,
RPT_ERROR,
"impossible to resync data-block %s and its dependencies, as its linked reference "
"Impossible to resync data-block %s and its dependencies, as its linked reference "
"is missing",
id_root->name + 2);
return false;
@ -1631,7 +1631,7 @@ static void lib_override_library_main_resync_on_library_indirect_level(
CLOG_INFO(&LOG, 2, "\tSuccess: %d", success);
if (success) {
reports->count.resynced_lib_overrides++;
if (library_indirect_level > 0 &&
if (library_indirect_level > 0 && reports->do_resynced_lib_overrides_libraries_list &&
BLI_linklist_index(reports->resynced_lib_overrides_libraries, library) < 0) {
BLI_linklist_prepend(&reports->resynced_lib_overrides_libraries, library);
reports->resynced_lib_overrides_libraries_count++;

View File

@ -292,10 +292,10 @@ static void maskrasterize_spline_differentiate_point_outset(float (*diff_feather
co_curr = diff_points[k_curr];
co_next = diff_points[k_next];
/* sub_v2_v2v2(d_prev, co_prev, co_curr); */ /* precalc */
// sub_v2_v2v2(d_prev, co_prev, co_curr); /* precalc */
sub_v2_v2v2(d_next, co_curr, co_next);
/* normalize_v2(d_prev); */ /* precalc */
// normalize_v2(d_prev); /* precalc */
normalize_v2(d_next);
if ((do_test == false) ||

View File

@ -1802,6 +1802,7 @@ void BKE_material_copybuf_free(void)
{
if (matcopybuf.nodetree) {
ntreeFreeLocalTree(matcopybuf.nodetree);
BLI_assert(!matcopybuf.nodetree->id.py_instance); /* Or call #BKE_libblock_free_data_py. */
MEM_freeN(matcopybuf.nodetree);
matcopybuf.nodetree = NULL;
}

View File

@ -289,7 +289,7 @@ void BKE_mball_texspace_calc(Object *ob)
bb = ob->runtime.bb;
/* Weird one, this. */
/* INIT_MINMAX(min, max); */
// INIT_MINMAX(min, max);
(min)[0] = (min)[1] = (min)[2] = 1.0e30f;
(max)[0] = (max)[1] = (max)[2] = -1.0e30f;

View File

@ -262,7 +262,7 @@ static void mesh_blend_write(BlendWriter *writer, ID *id, const void *id_address
CD_LAYERS_FREE(vlayers);
CD_LAYERS_FREE(elayers);
/* CD_LAYER_FREE(flayers); */ /* Never allocated. */
// CD_LAYER_FREE(flayers); /* Never allocated. */
CD_LAYERS_FREE(llayers);
CD_LAYERS_FREE(players);
@ -430,57 +430,159 @@ static int customdata_compare(
{
const float thresh_sq = thresh * thresh;
CustomDataLayer *l1, *l2;
int i1 = 0, i2 = 0, tot, j;
int layer_count1 = 0, layer_count2 = 0, j;
const uint64_t cd_mask_non_generic = CD_MASK_MVERT | CD_MASK_MEDGE | CD_MASK_MPOLY |
CD_MASK_MLOOPUV | CD_MASK_MLOOPCOL | CD_MASK_MDEFORMVERT;
const uint64_t cd_mask_all_attr = CD_MASK_PROP_ALL | cd_mask_non_generic;
for (int i = 0; i < c1->totlayer; i++) {
if (ELEM(c1->layers[i].type,
CD_MVERT,
CD_MEDGE,
CD_MPOLY,
CD_MLOOPUV,
CD_MLOOPCOL,
CD_MDEFORMVERT)) {
i1++;
if (CD_TYPE_AS_MASK(c1->layers[i].type) & cd_mask_all_attr) {
layer_count1++;
}
}
for (int i = 0; i < c2->totlayer; i++) {
if (ELEM(c2->layers[i].type,
CD_MVERT,
CD_MEDGE,
CD_MPOLY,
CD_MLOOPUV,
CD_MLOOPCOL,
CD_MDEFORMVERT)) {
i2++;
if (CD_TYPE_AS_MASK(c2->layers[i].type) & cd_mask_all_attr) {
layer_count2++;
}
}
if (i1 != i2) {
if (layer_count1 != layer_count2) {
return MESHCMP_CDLAYERS_MISMATCH;
}
l1 = c1->layers;
l2 = c2->layers;
for (i1 = 0; i1 < c1->totlayer; i1++) {
for (int i1 = 0; i1 < c1->totlayer; i1++) {
l1 = c1->layers + i1;
if ((CD_TYPE_AS_MASK(l1->type) & CD_MASK_PROP_ALL) == 0) {
/* Skip non generic attribute layers. */
continue;
}
bool found_corresponding_layer = false;
for (i2 = 0; i2 < c2->totlayer; i2++) {
for (int i2 = 0; i2 < c2->totlayer; i2++) {
l2 = c2->layers + i2;
if (l1->type != l2->type || !STREQ(l1->name, l2->name)) {
continue;
}
found_corresponding_layer = true;
/* At this point `l1` and `l2` have the same name and type, so they should be compared. */
switch (l1->type) {
case CD_MVERT: {
MVert *v1 = l1->data;
MVert *v2 = l2->data;
int vtot = m1->totvert;
for (j = 0; j < vtot; j++, v1++, v2++) {
if (len_squared_v3v3(v1->co, v2->co) > thresh_sq) {
return MESHCMP_VERTCOMISMATCH;
}
/* I don't care about normals, let's just do coordinates. */
}
break;
}
/* We're order-agnostic for edges here. */
case CD_MEDGE: {
MEdge *e1 = l1->data;
MEdge *e2 = l2->data;
int etot = m1->totedge;
EdgeHash *eh = BLI_edgehash_new_ex(__func__, etot);
for (j = 0; j < etot; j++, e1++) {
BLI_edgehash_insert(eh, e1->v1, e1->v2, e1);
}
for (j = 0; j < etot; j++, e2++) {
if (!BLI_edgehash_lookup(eh, e2->v1, e2->v2)) {
return MESHCMP_EDGEUNKNOWN;
}
}
BLI_edgehash_free(eh, NULL);
break;
}
case CD_MPOLY: {
MPoly *p1 = l1->data;
MPoly *p2 = l2->data;
int ptot = m1->totpoly;
for (j = 0; j < ptot; j++, p1++, p2++) {
MLoop *lp1, *lp2;
int k;
if (p1->totloop != p2->totloop) {
return MESHCMP_POLYMISMATCH;
}
lp1 = m1->mloop + p1->loopstart;
lp2 = m2->mloop + p2->loopstart;
for (k = 0; k < p1->totloop; k++, lp1++, lp2++) {
if (lp1->v != lp2->v) {
return MESHCMP_POLYVERTMISMATCH;
}
}
}
break;
}
case CD_MLOOP: {
MLoop *lp1 = l1->data;
MLoop *lp2 = l2->data;
int ltot = m1->totloop;
for (j = 0; j < ltot; j++, lp1++, lp2++) {
if (lp1->v != lp2->v) {
return MESHCMP_LOOPMISMATCH;
}
}
break;
}
case CD_MLOOPUV: {
MLoopUV *lp1 = l1->data;
MLoopUV *lp2 = l2->data;
int ltot = m1->totloop;
for (j = 0; j < ltot; j++, lp1++, lp2++) {
if (len_squared_v2v2(lp1->uv, lp2->uv) > thresh_sq) {
return MESHCMP_LOOPUVMISMATCH;
}
}
break;
}
case CD_MLOOPCOL: {
MLoopCol *lp1 = l1->data;
MLoopCol *lp2 = l2->data;
int ltot = m1->totloop;
for (j = 0; j < ltot; j++, lp1++, lp2++) {
if (abs(lp1->r - lp2->r) > thresh || abs(lp1->g - lp2->g) > thresh ||
abs(lp1->b - lp2->b) > thresh || abs(lp1->a - lp2->a) > thresh) {
return MESHCMP_LOOPCOLMISMATCH;
}
}
break;
}
case CD_MDEFORMVERT: {
MDeformVert *dv1 = l1->data;
MDeformVert *dv2 = l2->data;
int dvtot = m1->totvert;
for (j = 0; j < dvtot; j++, dv1++, dv2++) {
int k;
MDeformWeight *dw1 = dv1->dw, *dw2 = dv2->dw;
if (dv1->totweight != dv2->totweight) {
return MESHCMP_DVERT_TOTGROUPMISMATCH;
}
for (k = 0; k < dv1->totweight; k++, dw1++, dw2++) {
if (dw1->def_nr != dw2->def_nr) {
return MESHCMP_DVERT_GROUPMISMATCH;
}
if (fabsf(dw1->weight - dw2->weight) > thresh) {
return MESHCMP_DVERT_WEIGHTMISMATCH;
}
}
}
break;
}
case CD_PROP_FLOAT: {
const float *l1_data = l1->data;
const float *l2_data = l2->data;
@ -514,157 +616,30 @@ static int customdata_compare(
}
break;
}
default: {
int element_size = CustomData_sizeof(l1->type);
case CD_PROP_INT32: {
const int *l1_data = l1->data;
const int *l2_data = l2->data;
for (int i = 0; i < total_length; i++) {
int offset = element_size * i;
if (!CustomData_data_equals(l1->type,
POINTER_OFFSET(l1->data, offset),
POINTER_OFFSET(l2->data, offset))) {
if (l1_data[i] != l2_data[i]) {
return MESHCMP_ATTRIBUTE_VALUE_MISMATCH;
}
}
break;
}
}
}
case CD_PROP_BOOL: {
const bool *l1_data = l1->data;
const bool *l2_data = l2->data;
if (!found_corresponding_layer) {
return MESHCMP_CDLAYERS_MISMATCH;
}
}
l1 = c1->layers;
l2 = c2->layers;
tot = i1;
i1 = 0;
i2 = 0;
for (int i = 0; i < tot; i++) {
while (
i1 < c1->totlayer &&
!ELEM(l1->type, CD_MVERT, CD_MEDGE, CD_MPOLY, CD_MLOOPUV, CD_MLOOPCOL, CD_MDEFORMVERT)) {
i1++;
l1++;
}
while (
i2 < c2->totlayer &&
!ELEM(l2->type, CD_MVERT, CD_MEDGE, CD_MPOLY, CD_MLOOPUV, CD_MLOOPCOL, CD_MDEFORMVERT)) {
i2++;
l2++;
}
if (l1->type == CD_MVERT) {
MVert *v1 = l1->data;
MVert *v2 = l2->data;
int vtot = m1->totvert;
for (j = 0; j < vtot; j++, v1++, v2++) {
if (len_squared_v3v3(v1->co, v2->co) > thresh_sq) {
return MESHCMP_VERTCOMISMATCH;
}
/* I don't care about normals, let's just do coordinates. */
}
}
/* We're order-agnostic for edges here. */
if (l1->type == CD_MEDGE) {
MEdge *e1 = l1->data;
MEdge *e2 = l2->data;
int etot = m1->totedge;
EdgeHash *eh = BLI_edgehash_new_ex(__func__, etot);
for (j = 0; j < etot; j++, e1++) {
BLI_edgehash_insert(eh, e1->v1, e1->v2, e1);
}
for (j = 0; j < etot; j++, e2++) {
if (!BLI_edgehash_lookup(eh, e2->v1, e2->v2)) {
return MESHCMP_EDGEUNKNOWN;
}
}
BLI_edgehash_free(eh, NULL);
}
if (l1->type == CD_MPOLY) {
MPoly *p1 = l1->data;
MPoly *p2 = l2->data;
int ptot = m1->totpoly;
for (j = 0; j < ptot; j++, p1++, p2++) {
MLoop *lp1, *lp2;
int k;
if (p1->totloop != p2->totloop) {
return MESHCMP_POLYMISMATCH;
}
lp1 = m1->mloop + p1->loopstart;
lp2 = m2->mloop + p2->loopstart;
for (k = 0; k < p1->totloop; k++, lp1++, lp2++) {
if (lp1->v != lp2->v) {
return MESHCMP_POLYVERTMISMATCH;
for (int i = 0; i < total_length; i++) {
if (l1_data[i] != l2_data[i]) {
return MESHCMP_ATTRIBUTE_VALUE_MISMATCH;
}
}
break;
}
}
}
if (l1->type == CD_MLOOP) {
MLoop *lp1 = l1->data;
MLoop *lp2 = l2->data;
int ltot = m1->totloop;
for (j = 0; j < ltot; j++, lp1++, lp2++) {
if (lp1->v != lp2->v) {
return MESHCMP_LOOPMISMATCH;
}
}
}
if (l1->type == CD_MLOOPUV) {
MLoopUV *lp1 = l1->data;
MLoopUV *lp2 = l2->data;
int ltot = m1->totloop;
for (j = 0; j < ltot; j++, lp1++, lp2++) {
if (len_squared_v2v2(lp1->uv, lp2->uv) > thresh_sq) {
return MESHCMP_LOOPUVMISMATCH;
}
}
}
if (l1->type == CD_MLOOPCOL) {
MLoopCol *lp1 = l1->data;
MLoopCol *lp2 = l2->data;
int ltot = m1->totloop;
for (j = 0; j < ltot; j++, lp1++, lp2++) {
if (abs(lp1->r - lp2->r) > thresh || abs(lp1->g - lp2->g) > thresh ||
abs(lp1->b - lp2->b) > thresh || abs(lp1->a - lp2->a) > thresh) {
return MESHCMP_LOOPCOLMISMATCH;
}
}
}
if (l1->type == CD_MDEFORMVERT) {
MDeformVert *dv1 = l1->data;
MDeformVert *dv2 = l2->data;
int dvtot = m1->totvert;
for (j = 0; j < dvtot; j++, dv1++, dv2++) {
int k;
MDeformWeight *dw1 = dv1->dw, *dw2 = dv2->dw;
if (dv1->totweight != dv2->totweight) {
return MESHCMP_DVERT_TOTGROUPMISMATCH;
}
for (k = 0; k < dv1->totweight; k++, dw1++, dw2++) {
if (dw1->def_nr != dw2->def_nr) {
return MESHCMP_DVERT_GROUPMISMATCH;
}
if (fabsf(dw1->weight - dw2->weight) > thresh) {
return MESHCMP_DVERT_WEIGHTMISMATCH;
}
default: {
break;
}
}
}
@ -967,7 +942,7 @@ Mesh *BKE_mesh_new_nomain(
NULL, ID_ME, BKE_idtype_idcode_to_name(ID_ME), LIB_ID_CREATE_LOCALIZE);
BKE_libblock_init_empty(&mesh->id);
/* Don't use CustomData_reset(...); because we don't want to touch custom-data. */
/* Don't use #CustomData_reset because we don't want to touch custom-data. */
copy_vn_i(mesh->vdata.typemap, CD_NUMTYPES, -1);
copy_vn_i(mesh->edata.typemap, CD_NUMTYPES, -1);
copy_vn_i(mesh->fdata.typemap, CD_NUMTYPES, -1);
@ -1922,15 +1897,14 @@ void BKE_mesh_calc_normals_split_ex(Mesh *mesh, MLoopNorSpaceArray *r_lnors_spac
}
else {
polynors = MEM_malloc_arrayN(mesh->totpoly, sizeof(float[3]), __func__);
BKE_mesh_calc_normals_poly(mesh->mvert,
NULL,
mesh->totvert,
mesh->mloop,
mesh->mpoly,
mesh->totloop,
mesh->totpoly,
polynors,
false);
BKE_mesh_calc_normals_poly_and_vertex(mesh->mvert,
mesh->totvert,
mesh->mloop,
mesh->totloop,
mesh->mpoly,
mesh->totpoly,
polynors,
NULL);
free_polynors = true;
}

View File

@ -272,8 +272,8 @@ static int mesh_nurbs_displist_to_mdata(const Curve *cu,
}
if (totvert == 0) {
/* error("can't convert"); */
/* Make Sure you check ob->data is a curve */
/* Make Sure you check ob->data is a curve. */
// error("can't convert");
return -1;
}

View File

@ -397,15 +397,14 @@ Mesh *BKE_mesh_mirror_apply_mirror_on_axis_for_modifier(MirrorModifierData *mmd,
/* calculate custom normals into loop_normals, then mirror first half into second half */
BKE_mesh_calc_normals_poly(result->mvert,
NULL,
result->totvert,
result->mloop,
result->mpoly,
totloop,
totpoly,
poly_normals,
false);
BKE_mesh_calc_normals_poly_and_vertex(result->mvert,
result->totvert,
result->mloop,
totloop,
result->mpoly,
totpoly,
poly_normals,
NULL);
BKE_mesh_normals_loop_split(result->mvert,
result->totvert,

View File

@ -27,8 +27,6 @@
#include <climits>
#include "CLG_log.h"
#include "MEM_guardedalloc.h"
#include "DNA_mesh_types.h"
@ -50,6 +48,8 @@
#include "BKE_global.h"
#include "BKE_mesh.h"
#include "atomic_ops.h"
// #define DEBUG_TIME
#ifdef DEBUG_TIME
@ -57,10 +57,50 @@
# include "PIL_time_utildefines.h"
#endif
static CLG_LogRef LOG = {"bke.mesh_normals"};
/* -------------------------------------------------------------------- */
/** \name Private Utility Functions
* \{ */
/**
* A thread-safe version of #add_v3_v3 that uses a spin-lock.
*
* \note Avoid using this when the chance of contention is high.
*/
static void add_v3_v3_atomic(float r[3], const float a[3])
{
#define FLT_EQ_NONAN(_fa, _fb) (*((const uint32_t *)&_fa) == *((const uint32_t *)&_fb))
float virtual_lock = r[0];
while (true) {
/* This loops until following conditions are met:
* - `r[0]` has same value as virtual_lock (i.e. it did not change since last try).
* - `r[0]` was not `FLT_MAX`, i.e. it was not locked by another thread. */
const float test_lock = atomic_cas_float(&r[0], virtual_lock, FLT_MAX);
if (_ATOMIC_LIKELY(FLT_EQ_NONAN(test_lock, virtual_lock) && (test_lock != FLT_MAX))) {
break;
}
virtual_lock = test_lock;
}
virtual_lock += a[0];
r[1] += a[1];
r[2] += a[2];
/* Second atomic operation to 'release'
* our lock on that vector and set its first scalar value. */
/* Note that we do not need to loop here, since we 'locked' `r[0]`,
* nobody should have changed it in the mean time. */
virtual_lock = atomic_cas_float(&r[0], FLT_MAX, virtual_lock);
BLI_assert(virtual_lock == FLT_MAX);
#undef FLT_EQ_NONAN
}
/** \} */
/* -------------------------------------------------------------------- */
/** \name Mesh Normal Calculation
/** \name Public Utility Functions
*
* Related to managing normals but not directly related to calculating normals.
* \{ */
void BKE_mesh_normals_tag_dirty(Mesh *mesh)
@ -69,313 +109,205 @@ void BKE_mesh_normals_tag_dirty(Mesh *mesh)
mesh->runtime.cd_dirty_poly |= CD_MASK_NORMAL;
}
/**
* Call when there are no polygons.
*/
static void mesh_calc_normals_vert_fallback(MVert *mverts, int numVerts)
{
for (int i = 0; i < numVerts; i++) {
MVert *mv = &mverts[i];
float no[3];
/** \} */
normalize_v3_v3(no, mv->co);
normal_float_to_short_v3(mv->no, no);
}
}
/* -------------------------------------------------------------------- */
/** \name Mesh Normal Calculation (Polygons)
* \{ */
/* TODO(Sybren): we can probably rename this to BKE_mesh_calc_normals_mapping(),
* and remove the function of the same name below, as that one doesn't seem to be
* called anywhere. */
void BKE_mesh_calc_normals_mapping_simple(struct Mesh *mesh)
{
const bool only_face_normals = CustomData_is_referenced_layer(&mesh->vdata, CD_MVERT);
BKE_mesh_calc_normals_mapping_ex(mesh->mvert,
mesh->totvert,
mesh->mloop,
mesh->mpoly,
mesh->totloop,
mesh->totpoly,
nullptr,
mesh->mface,
mesh->totface,
nullptr,
nullptr,
only_face_normals);
}
/* Calculate vertex and face normals, face normals are returned in *r_faceNors if non-nullptr
* and vertex normals are stored in actual mverts.
*/
void BKE_mesh_calc_normals_mapping(MVert *mverts,
int numVerts,
const MLoop *mloop,
const MPoly *mpolys,
int numLoops,
int numPolys,
float (*r_polyNors)[3],
const MFace *mfaces,
int numFaces,
const int *origIndexFace,
float (*r_faceNors)[3])
{
BKE_mesh_calc_normals_mapping_ex(mverts,
numVerts,
mloop,
mpolys,
numLoops,
numPolys,
r_polyNors,
mfaces,
numFaces,
origIndexFace,
r_faceNors,
false);
}
/* extended version of 'BKE_mesh_calc_normals_poly' with option not to calc vertex normals */
void BKE_mesh_calc_normals_mapping_ex(MVert *mverts,
int numVerts,
const MLoop *mloop,
const MPoly *mpolys,
int numLoops,
int numPolys,
float (*r_polyNors)[3],
const MFace *mfaces,
int numFaces,
const int *origIndexFace,
float (*r_faceNors)[3],
const bool only_face_normals)
{
float(*pnors)[3] = r_polyNors, (*fnors)[3] = r_faceNors;
if (numPolys == 0) {
if (only_face_normals == false) {
mesh_calc_normals_vert_fallback(mverts, numVerts);
}
return;
}
/* if we are not calculating verts and no verts were passes then we have nothing to do */
if ((only_face_normals == true) && (r_polyNors == nullptr) && (r_faceNors == nullptr)) {
CLOG_WARN(&LOG, "called with nothing to do");
return;
}
if (!pnors) {
pnors = (float(*)[3])MEM_calloc_arrayN((size_t)numPolys, sizeof(float[3]), __func__);
}
/* NO NEED TO ALLOC YET */
/* if (!fnors) fnors = MEM_calloc_arrayN(numFaces, sizeof(float[3]), "face nors mesh.c"); */
if (only_face_normals == false) {
/* vertex normals are optional, they require some extra calculations,
* so make them optional */
BKE_mesh_calc_normals_poly(
mverts, nullptr, numVerts, mloop, mpolys, numLoops, numPolys, pnors, false);
}
else {
/* only calc poly normals */
const MPoly *mp = mpolys;
for (int i = 0; i < numPolys; i++, mp++) {
BKE_mesh_calc_poly_normal(mp, mloop + mp->loopstart, mverts, pnors[i]);
}
}
if (origIndexFace &&
/* fnors == r_faceNors */ /* NO NEED TO ALLOC YET */
fnors != nullptr &&
numFaces) {
const MFace *mf = mfaces;
for (int i = 0; i < numFaces; i++, mf++, origIndexFace++) {
if (*origIndexFace < numPolys) {
copy_v3_v3(fnors[i], pnors[*origIndexFace]);
}
else {
/* eek, we're not corresponding to polys */
CLOG_ERROR(&LOG, "tessellation face indices are incorrect. normals may look bad.");
}
}
}
if (pnors != r_polyNors) {
MEM_freeN(pnors);
}
/* if (fnors != r_faceNors) MEM_freeN(fnors); */ /* NO NEED TO ALLOC YET */
fnors = pnors = nullptr;
}
struct MeshCalcNormalsData {
const MPoly *mpolys;
struct MeshCalcNormalsData_Poly {
const MVert *mvert;
const MLoop *mloop;
MVert *mverts;
const MPoly *mpoly;
/** Polygon normal output. */
float (*pnors)[3];
float (*lnors_weighted)[3];
float (*vnors)[3];
};
static void mesh_calc_normals_poly_cb(void *__restrict userdata,
static void mesh_calc_normals_poly_fn(void *__restrict userdata,
const int pidx,
const TaskParallelTLS *__restrict UNUSED(tls))
{
MeshCalcNormalsData *data = (MeshCalcNormalsData *)userdata;
const MPoly *mp = &data->mpolys[pidx];
BKE_mesh_calc_poly_normal(mp, data->mloop + mp->loopstart, data->mverts, data->pnors[pidx]);
const MeshCalcNormalsData_Poly *data = (MeshCalcNormalsData_Poly *)userdata;
const MPoly *mp = &data->mpoly[pidx];
BKE_mesh_calc_poly_normal(mp, data->mloop + mp->loopstart, data->mvert, data->pnors[pidx]);
}
static void mesh_calc_normals_poly_prepare_cb(void *__restrict userdata,
const int pidx,
const TaskParallelTLS *__restrict UNUSED(tls))
void BKE_mesh_calc_normals_poly(const MVert *mvert,
int UNUSED(mvert_len),
const MLoop *mloop,
int UNUSED(mloop_len),
const MPoly *mpoly,
int mpoly_len,
float (*r_poly_normals)[3])
{
MeshCalcNormalsData *data = (MeshCalcNormalsData *)userdata;
const MPoly *mp = &data->mpolys[pidx];
TaskParallelSettings settings;
BLI_parallel_range_settings_defaults(&settings);
settings.min_iter_per_thread = 1024;
BLI_assert((r_poly_normals != nullptr) || (mpoly_len == 0));
MeshCalcNormalsData_Poly data = {};
data.mpoly = mpoly;
data.mloop = mloop;
data.mvert = mvert;
data.pnors = r_poly_normals;
BLI_task_parallel_range(0, mpoly_len, &data, mesh_calc_normals_poly_fn, &settings);
}
/** \} */
/* -------------------------------------------------------------------- */
/** \name Mesh Normal Calculation (Polygons & Vertices)
*
* Implement #BKE_mesh_calc_normals_poly_and_vertex,
*
* Take care making optimizations to this function as improvements to low-poly
* meshes can slow down high-poly meshes. For details on performance, see D11993.
* \{ */
struct MeshCalcNormalsData_PolyAndVertex {
/** Write into vertex normals #MVert.no. */
MVert *mvert;
const MLoop *mloop;
const MPoly *mpoly;
/** Polygon normal output. */
float (*pnors)[3];
/** Vertex normal output (may be freed, copied into #MVert.no). */
float (*vnors)[3];
};
static void mesh_calc_normals_poly_and_vertex_accum_fn(
void *__restrict userdata, const int pidx, const TaskParallelTLS *__restrict UNUSED(tls))
{
const MeshCalcNormalsData_PolyAndVertex *data = (MeshCalcNormalsData_PolyAndVertex *)userdata;
const MPoly *mp = &data->mpoly[pidx];
const MLoop *ml = &data->mloop[mp->loopstart];
const MVert *mverts = data->mverts;
const MVert *mverts = data->mvert;
float(*vnors)[3] = data->vnors;
float pnor_temp[3];
float *pnor = data->pnors ? data->pnors[pidx] : pnor_temp;
float(*lnors_weighted)[3] = data->lnors_weighted;
const int nverts = mp->totloop;
float(*edgevecbuf)[3] = (float(*)[3])BLI_array_alloca(edgevecbuf, (size_t)nverts);
const int i_end = mp->totloop - 1;
/* Polygon Normal and edge-vector */
/* inline version of #BKE_mesh_calc_poly_normal, also does edge-vectors */
/* Polygon Normal and edge-vector. */
/* Inline version of #BKE_mesh_calc_poly_normal, also does edge-vectors. */
{
int i_prev = nverts - 1;
const float *v_prev = mverts[ml[i_prev].v].co;
const float *v_curr;
zero_v3(pnor);
/* Newell's Method */
for (int i = 0; i < nverts; i++) {
v_curr = mverts[ml[i].v].co;
add_newell_cross_v3_v3v3(pnor, v_prev, v_curr);
/* Unrelated to normalize, calculate edge-vector */
sub_v3_v3v3(edgevecbuf[i_prev], v_prev, v_curr);
normalize_v3(edgevecbuf[i_prev]);
i_prev = i;
v_prev = v_curr;
const float *v_curr = mverts[ml[i_end].v].co;
for (int i_next = 0; i_next <= i_end; i_next++) {
const float *v_next = mverts[ml[i_next].v].co;
add_newell_cross_v3_v3v3(pnor, v_curr, v_next);
v_curr = v_next;
}
if (UNLIKELY(normalize_v3(pnor) == 0.0f)) {
pnor[2] = 1.0f; /* other axes set to 0.0 */
pnor[2] = 1.0f; /* Other axes set to zero. */
}
}
/* accumulate angle weighted face normal */
/* inline version of #accumulate_vertex_normals_poly_v3,
* split between this threaded callback and #mesh_calc_normals_poly_accum_cb. */
/* Accumulate angle weighted face normal into the vertex normal. */
/* Inline version of #accumulate_vertex_normals_poly_v3. */
{
const float *prev_edge = edgevecbuf[nverts - 1];
float edvec_prev[3], edvec_next[3], edvec_end[3];
const float *v_curr = mverts[ml[i_end].v].co;
sub_v3_v3v3(edvec_prev, mverts[ml[i_end - 1].v].co, v_curr);
normalize_v3(edvec_prev);
copy_v3_v3(edvec_end, edvec_prev);
for (int i = 0; i < nverts; i++) {
const int lidx = mp->loopstart + i;
const float *cur_edge = edgevecbuf[i];
for (int i_next = 0, i_curr = i_end; i_next <= i_end; i_curr = i_next++) {
const float *v_next = mverts[ml[i_next].v].co;
/* calculate angle between the two poly edges incident on
* this vertex */
const float fac = saacos(-dot_v3v3(cur_edge, prev_edge));
/* Skip an extra normalization by reusing the first calculated edge. */
if (i_next != i_end) {
sub_v3_v3v3(edvec_next, v_curr, v_next);
normalize_v3(edvec_next);
}
else {
copy_v3_v3(edvec_next, edvec_end);
}
/* Store for later accumulation */
mul_v3_v3fl(lnors_weighted[lidx], pnor, fac);
/* Calculate angle between the two poly edges incident on this vertex. */
const float fac = saacos(-dot_v3v3(edvec_prev, edvec_next));
const float vnor_add[3] = {pnor[0] * fac, pnor[1] * fac, pnor[2] * fac};
prev_edge = cur_edge;
add_v3_v3_atomic(vnors[ml[i_curr].v], vnor_add);
v_curr = v_next;
copy_v3_v3(edvec_prev, edvec_next);
}
}
}
static void mesh_calc_normals_poly_finalize_cb(void *__restrict userdata,
const int vidx,
const TaskParallelTLS *__restrict UNUSED(tls))
static void mesh_calc_normals_poly_and_vertex_finalize_fn(
void *__restrict userdata, const int vidx, const TaskParallelTLS *__restrict UNUSED(tls))
{
MeshCalcNormalsData *data = (MeshCalcNormalsData *)userdata;
MeshCalcNormalsData_PolyAndVertex *data = (MeshCalcNormalsData_PolyAndVertex *)userdata;
MVert *mv = &data->mverts[vidx];
MVert *mv = &data->mvert[vidx];
float *no = data->vnors[vidx];
if (UNLIKELY(normalize_v3(no) == 0.0f)) {
/* following Mesh convention; we use vertex coordinate itself for normal in this case */
/* Following Mesh convention; we use vertex coordinate itself for normal in this case. */
normalize_v3_v3(no, mv->co);
}
normal_float_to_short_v3(mv->no, no);
}
void BKE_mesh_calc_normals_poly(MVert *mverts,
float (*r_vertnors)[3],
int numVerts,
const MLoop *mloop,
const MPoly *mpolys,
int numLoops,
int numPolys,
float (*r_polynors)[3],
const bool only_face_normals)
void BKE_mesh_calc_normals_poly_and_vertex(MVert *mvert,
const int mvert_len,
const MLoop *mloop,
const int UNUSED(mloop_len),
const MPoly *mpoly,
const int mpoly_len,
float (*r_poly_normals)[3],
float (*r_vert_normals)[3])
{
float(*pnors)[3] = r_polynors;
TaskParallelSettings settings;
BLI_parallel_range_settings_defaults(&settings);
settings.min_iter_per_thread = 1024;
if (only_face_normals) {
BLI_assert((pnors != nullptr) || (numPolys == 0));
BLI_assert(r_vertnors == nullptr);
MeshCalcNormalsData data;
data.mpolys = mpolys;
data.mloop = mloop;
data.mverts = mverts;
data.pnors = pnors;
BLI_task_parallel_range(0, numPolys, &data, mesh_calc_normals_poly_cb, &settings);
return;
}
float(*vnors)[3] = r_vertnors;
float(*lnors_weighted)[3] = (float(*)[3])MEM_malloc_arrayN(
(size_t)numLoops, sizeof(*lnors_weighted), __func__);
float(*vnors)[3] = r_vert_normals;
bool free_vnors = false;
/* first go through and calculate normals for all the polys */
/* First go through and calculate normals for all the polys. */
if (vnors == nullptr) {
vnors = (float(*)[3])MEM_calloc_arrayN((size_t)numVerts, sizeof(*vnors), __func__);
vnors = (float(*)[3])MEM_calloc_arrayN((size_t)mvert_len, sizeof(*vnors), __func__);
free_vnors = true;
}
else {
memset(vnors, 0, sizeof(*vnors) * (size_t)numVerts);
memset(vnors, 0, sizeof(*vnors) * (size_t)mvert_len);
}
MeshCalcNormalsData data;
data.mpolys = mpolys;
MeshCalcNormalsData_PolyAndVertex data = {};
data.mpoly = mpoly;
data.mloop = mloop;
data.mverts = mverts;
data.pnors = pnors;
data.lnors_weighted = lnors_weighted;
data.mvert = mvert;
data.pnors = r_poly_normals;
data.vnors = vnors;
/* Compute poly normals, and prepare weighted loop normals. */
BLI_task_parallel_range(0, numPolys, &data, mesh_calc_normals_poly_prepare_cb, &settings);
/* Compute poly normals (`pnors`), accumulating them into vertex normals (`vnors`). */
BLI_task_parallel_range(
0, mpoly_len, &data, mesh_calc_normals_poly_and_vertex_accum_fn, &settings);
/* Actually accumulate weighted loop normals into vertex ones. */
/* Unfortunately, not possible to thread that
* (not in a reasonable, totally lock- and barrier-free fashion),
* since several loops will point to the same vertex... */
for (int lidx = 0; lidx < numLoops; lidx++) {
add_v3_v3(vnors[mloop[lidx].v], data.lnors_weighted[lidx]);
}
/* Normalize and validate computed vertex normals. */
BLI_task_parallel_range(0, numVerts, &data, mesh_calc_normals_poly_finalize_cb, &settings);
/* Normalize and validate computed vertex normals (`vnors`). */
BLI_task_parallel_range(
0, mvert_len, &data, mesh_calc_normals_poly_and_vertex_finalize_fn, &settings);
if (free_vnors) {
MEM_freeN(vnors);
}
MEM_freeN(lnors_weighted);
}
/** \} */
/* -------------------------------------------------------------------- */
/** \name Mesh Normal Calculation
* \{ */
void BKE_mesh_ensure_normals(Mesh *mesh)
{
if (mesh->runtime.cd_dirty_vert & CD_MASK_NORMAL) {
@ -416,16 +348,26 @@ void BKE_mesh_ensure_normals_for_display(Mesh *mesh)
(size_t)mesh->totpoly, sizeof(*poly_nors), __func__);
}
/* calculate poly/vert normals */
BKE_mesh_calc_normals_poly(mesh->mvert,
nullptr,
mesh->totvert,
mesh->mloop,
mesh->mpoly,
mesh->totloop,
mesh->totpoly,
poly_nors,
!do_vert_normals);
/* Calculate poly/vert normals. */
if (do_vert_normals) {
BKE_mesh_calc_normals_poly_and_vertex(mesh->mvert,
mesh->totvert,
mesh->mloop,
mesh->totloop,
mesh->mpoly,
mesh->totpoly,
poly_nors,
nullptr);
}
else {
BKE_mesh_calc_normals_poly(mesh->mvert,
mesh->totvert,
mesh->mloop,
mesh->totloop,
mesh->mpoly,
mesh->totpoly,
poly_nors);
}
if (do_add_poly_nors_cddata) {
CustomData_add_layer(&mesh->pdata, CD_NORMAL, CD_ASSIGN, poly_nors, mesh->totpoly);
@ -436,22 +378,23 @@ void BKE_mesh_ensure_normals_for_display(Mesh *mesh)
}
}
/* Note that this does not update the CD_NORMAL layer,
* but does update the normals in the CD_MVERT layer. */
/**
* NOTE: this does not update the #CD_NORMAL layer,
* but does update the normals in the #CD_MVERT layer.
*/
void BKE_mesh_calc_normals(Mesh *mesh)
{
#ifdef DEBUG_TIME
TIMEIT_START_AVERAGED(BKE_mesh_calc_normals);
#endif
BKE_mesh_calc_normals_poly(mesh->mvert,
nullptr,
mesh->totvert,
mesh->mloop,
mesh->mpoly,
mesh->totloop,
mesh->totpoly,
nullptr,
false);
BKE_mesh_calc_normals_poly_and_vertex(mesh->mvert,
mesh->totvert,
mesh->mloop,
mesh->totloop,
mesh->mpoly,
mesh->totpoly,
nullptr,
nullptr);
#ifdef DEBUG_TIME
TIMEIT_END_AVERAGED(BKE_mesh_calc_normals);
#endif
@ -494,7 +437,7 @@ void BKE_mesh_calc_normals_looptri(MVert *mverts,
mverts[vtri[2]].co);
}
/* following Mesh convention; we use vertex coordinate itself for normal in this case */
/* Following Mesh convention; we use vertex coordinate itself for normal in this case. */
for (int i = 0; i < numVerts; i++) {
MVert *mv = &mverts[i];
float *no = tnorms[i];
@ -634,11 +577,11 @@ void BKE_lnor_space_define(MLoopNorSpace *lnor_space,
BLI_stack_discard(edge_vectors);
nbr++;
}
/* NOTE: In theory, this could be 'nbr > 2',
* but there is one case where we only have two edges for two loops:
* a smooth vertex with only two edges and two faces (our Monkey's nose has that, e.g.).
/* NOTE: In theory, this could be `nbr > 2`,
* but there is one case where we only have two edges for two loops:
* a smooth vertex with only two edges and two faces (our Monkey's nose has that, e.g.).
*/
BLI_assert(nbr >= 2); /* This piece of code shall only be called for more than one loop... */
BLI_assert(nbr >= 2); /* This piece of code shall only be called for more than one loop. */
lnor_space->ref_alpha = alpha / (float)nbr;
}
else {
@ -710,7 +653,7 @@ MINLINE float unit_short_to_float(const short val)
MINLINE short unit_float_to_short(const float val)
{
/* Rounding... */
/* Rounding. */
return (short)floorf(val * (float)SHRT_MAX + 0.5f);
}
@ -921,7 +864,7 @@ static void mesh_edges_sharp_tag(LoopSplitTaskDataCommon *data,
e2l[1] = INDEX_INVALID;
/* We want to avoid tagging edges as sharp when it is already defined as such by
* other causes than angle threshold... */
* other causes than angle threshold. */
if (do_sharp_edges_tag && is_angle_sharp) {
BLI_BITMAP_SET(sharp_edges, ml_curr->e, true);
}
@ -935,7 +878,7 @@ static void mesh_edges_sharp_tag(LoopSplitTaskDataCommon *data,
e2l[1] = INDEX_INVALID;
/* We want to avoid tagging edges as sharp when it is already defined as such by
* other causes than angle threshold... */
* other causes than angle threshold. */
if (do_sharp_edges_tag) {
BLI_BITMAP_SET(sharp_edges, ml_curr->e, false);
}
@ -1017,14 +960,13 @@ void BKE_mesh_loop_manifold_fan_around_vert_next(const MLoop *mloops,
const MLoop *mlfan_next;
const MPoly *mpfan_next;
/* Warning! This is rather complex!
/* WARNING: This is rather complex!
* We have to find our next edge around the vertex (fan mode).
* First we find the next loop, which is either previous or next to mlfan_curr_index, depending
* whether both loops using current edge are in the same direction or not, and whether
* mlfan_curr_index actually uses the vertex we are fanning around!
* mlfan_curr_index is the index of mlfan_next here, and mlfan_next is not the real next one
* (i.e. not the future mlfan_curr)...
*/
* (i.e. not the future `mlfan_curr`). */
*r_mlfan_curr_index = (e2lfan_curr[0] == *r_mlfan_curr_index) ? e2lfan_curr[1] : e2lfan_curr[0];
*r_mpfan_curr_index = loop_to_poly[*r_mlfan_curr_index];
@ -1049,7 +991,7 @@ void BKE_mesh_loop_manifold_fan_around_vert_next(const MLoop *mloops,
*r_mlfan_vert_index = *r_mlfan_curr_index;
}
*r_mlfan_curr = &mloops[*r_mlfan_curr_index];
/* And now we are back in sync, mlfan_curr_index is the index of mlfan_curr! Pff! */
/* And now we are back in sync, mlfan_curr_index is the index of `mlfan_curr`! Pff! */
}
static void split_loop_nor_single_do(LoopSplitTaskDataCommon *common_data, LoopSplitTaskData *data)
@ -1104,8 +1046,7 @@ static void split_loop_nor_single_do(LoopSplitTaskDataCommon *common_data, LoopS
normalize_v3(vec_prev);
BKE_lnor_space_define(lnor_space, *lnor, vec_curr, vec_prev, nullptr);
/* We know there is only one loop in this space,
* no need to create a linklist in this case... */
/* We know there is only one loop in this space, no need to create a link-list in this case. */
BKE_lnor_space_add_loop(lnors_spacearr, lnor_space, ml_curr_index, nullptr, true);
if (clnors_data) {
@ -1141,24 +1082,24 @@ static void split_loop_nor_fan_do(LoopSplitTaskDataCommon *common_data, LoopSpli
BLI_Stack *edge_vectors = data->edge_vectors;
/* Gah... We have to fan around current vertex, until we find the other non-smooth edge,
/* Sigh! we have to fan around current vertex, until we find the other non-smooth edge,
* and accumulate face normals into the vertex!
* Note in case this vertex has only one sharp edges, this is a waste because the normal is the
* same as the vertex normal, but I do not see any easy way to detect that (would need to count
* number of sharp edges per vertex, I doubt the additional memory usage would be worth it,
* especially as it should not be a common case in real-life meshes anyway).
*/
* especially as it should not be a common case in real-life meshes anyway). */
const uint mv_pivot_index = ml_curr->v; /* The vertex we are "fanning" around! */
const MVert *mv_pivot = &mverts[mv_pivot_index];
/* ml_curr would be mlfan_prev if we needed that one. */
/* `ml_curr` would be mlfan_prev if we needed that one. */
const MEdge *me_org = &medges[ml_curr->e];
const int *e2lfan_curr;
float vec_curr[3], vec_prev[3], vec_org[3];
const MLoop *mlfan_curr;
float lnor[3] = {0.0f, 0.0f, 0.0f};
/* mlfan_vert_index: the loop of our current edge might not be the loop of our current vertex! */
/* `mlfan_vert_index` the loop of our current edge might not be the loop of our current vertex!
*/
int mlfan_curr_index, mlfan_vert_index, mpfan_curr_index;
/* We validate clnors data on the fly - cheapest way to do! */
@ -1202,7 +1143,7 @@ static void split_loop_nor_fan_do(LoopSplitTaskDataCommon *common_data, LoopSpli
/* Compute edge vectors.
* NOTE: We could pre-compute those into an array, in the first iteration, instead of computing
* them twice (or more) here. However, time gained is not worth memory and time lost,
* given the fact that this code should not be called that much in real-life meshes...
* given the fact that this code should not be called that much in real-life meshes.
*/
{
const MVert *mv_2 = (me_curr->v1 == mv_pivot_index) ? &mverts[me_curr->v2] :
@ -1394,12 +1335,13 @@ static bool loop_split_generator_check_cyclic_smooth_fan(const MLoop *mloops,
const uint mv_pivot_index = ml_curr->v; /* The vertex we are "fanning" around! */
const int *e2lfan_curr;
const MLoop *mlfan_curr;
/* mlfan_vert_index: the loop of our current edge might not be the loop of our current vertex! */
/* `mlfan_vert_index` the loop of our current edge might not be the loop of our current vertex!
*/
int mlfan_curr_index, mlfan_vert_index, mpfan_curr_index;
e2lfan_curr = e2l_prev;
if (IS_EDGE_SHARP(e2lfan_curr)) {
/* Sharp loop, so not a cyclic smooth fan... */
/* Sharp loop, so not a cyclic smooth fan. */
return false;
}
@ -1430,21 +1372,21 @@ static bool loop_split_generator_check_cyclic_smooth_fan(const MLoop *mloops,
e2lfan_curr = edge_to_loops[mlfan_curr->e];
if (IS_EDGE_SHARP(e2lfan_curr)) {
/* Sharp loop/edge, so not a cyclic smooth fan... */
/* Sharp loop/edge, so not a cyclic smooth fan. */
return false;
}
/* Smooth loop/edge... */
/* Smooth loop/edge. */
if (BLI_BITMAP_TEST(skip_loops, mlfan_vert_index)) {
if (mlfan_vert_index == ml_curr_index) {
/* We walked around a whole cyclic smooth fan without finding any already-processed loop,
* means we can use initial ml_curr/ml_prev edge as start for this smooth fan. */
* means we can use initial `ml_curr` / `ml_prev` edge as start for this smooth fan. */
return true;
}
/* ... already checked in some previous looping, we can abort. */
/* Already checked in some previous looping, we can abort. */
return false;
}
/* ... we can skip it in future, and keep checking the smooth fan. */
/* We can skip it in future, and keep checking the smooth fan. */
BLI_BITMAP_ENABLE(skip_loops, mlfan_vert_index);
}
}
@ -1506,7 +1448,7 @@ static void loop_split_generator(TaskPool *pool, LoopSplitTaskDataCommon *common
const int *e2l_prev = edge_to_loops[ml_prev->e];
#if 0
printf("Checking loop %d / edge %u / vert %u (sharp edge: %d, skiploop: %d)...",
printf("Checking loop %d / edge %u / vert %u (sharp edge: %d, skiploop: %d)",
ml_curr_index,
ml_curr->e,
ml_curr->v,
@ -1610,7 +1552,7 @@ static void loop_split_generator(TaskPool *pool, LoopSplitTaskDataCommon *common
}
}
/* Last block of data... Since it is calloc'ed and we use first nullptr item as stopper,
/* Last block of data. Since it is calloc'ed and we use first nullptr item as stopper,
* everything is fine. */
if (pool && data_idx) {
BLI_task_pool_push(pool, loop_split_worker, data_buff, true, nullptr);
@ -1657,8 +1599,7 @@ void BKE_mesh_normals_loop_split(const MVert *mverts,
* since we may want to use lnors even when mesh's 'autosmooth' is disabled
* (see e.g. mesh mapping code).
* As usual, we could handle that on case-by-case basis,
* but simpler to keep it well confined here.
*/
* but simpler to keep it well confined here. */
int mp_index;
for (mp_index = 0; mp_index < numPolys; mp_index++) {
@ -1741,7 +1682,7 @@ void BKE_mesh_normals_loop_split(const MVert *mverts,
mesh_edges_sharp_tag(&common_data, check_angle, split_angle, false);
if (numLoops < LOOP_SPLIT_TASK_BLOCK_SIZE * 8) {
/* Not enough loops to be worth the whole threading overhead... */
/* Not enough loops to be worth the whole threading overhead. */
loop_split_generator(nullptr, &common_data);
}
else {
@ -1796,13 +1737,12 @@ static void mesh_normals_loop_custom_set(const MVert *mverts,
short (*r_clnors_data)[2],
const bool use_vertices)
{
/* We *may* make that poor BKE_mesh_normals_loop_split() even more complex by making it handling
/* We *may* make that poor #BKE_mesh_normals_loop_split() even more complex by making it handling
* that feature too, would probably be more efficient in absolute.
* However, this function *is not* performance-critical, since it is mostly expected to be called
* by io addons when importing custom normals, and modifier
* by io add-ons when importing custom normals, and modifier
* (and perhaps from some editing tools later?).
* So better to keep some simplicity here, and just call BKE_mesh_normals_loop_split() twice!
*/
* So better to keep some simplicity here, and just call #BKE_mesh_normals_loop_split() twice! */
MLoopNorSpaceArray lnors_spacearr = {nullptr};
BLI_bitmap *done_loops = BLI_BITMAP_NEW((size_t)numLoops, __func__);
float(*lnors)[3] = (float(*)[3])MEM_calloc_arrayN((size_t)numLoops, sizeof(*lnors), __func__);
@ -1854,15 +1794,13 @@ static void mesh_normals_loop_custom_set(const MVert *mverts,
* This way, next time we run BKE_mesh_normals_loop_split(), we'll get lnor spacearr/smooth fans
* matching given custom lnors.
* Note this code *will never* unsharp edges! And quite obviously,
* when we set custom normals per vertices, running this is absolutely useless.
*/
* when we set custom normals per vertices, running this is absolutely useless. */
if (!use_vertices) {
for (int i = 0; i < numLoops; i++) {
if (!lnors_spacearr.lspacearr[i]) {
/* This should not happen in theory, but in some rare case (probably ugly geometry)
* we can get some nullptr loopspacearr at this point. :/
* Maybe we should set those loops' edges as sharp?
*/
* Maybe we should set those loops' edges as sharp? */
BLI_BITMAP_ENABLE(done_loops, i);
if (G.debug & G_DEBUG) {
printf("WARNING! Getting invalid nullptr loop space for loop %d!\n", i);
@ -1872,12 +1810,12 @@ static void mesh_normals_loop_custom_set(const MVert *mverts,
if (!BLI_BITMAP_TEST(done_loops, i)) {
/* Notes:
* * In case of mono-loop smooth fan, we have nothing to do.
* * Loops in this linklist are ordered (in reversed order compared to how they were
* - In case of mono-loop smooth fan, we have nothing to do.
* - Loops in this linklist are ordered (in reversed order compared to how they were
* discovered by BKE_mesh_normals_loop_split(), but this is not a problem).
* Which means if we find a mismatching clnor,
* we know all remaining loops will have to be in a new, different smooth fan/lnor space.
* * In smooth fan case, we compare each clnor against a ref one,
* - In smooth fan case, we compare each clnor against a ref one,
* to avoid small differences adding up into a real big one in the end!
*/
if (lnors_spacearr.lspacearr[i]->flags & MLNOR_SPACE_IS_SINGLE) {
@ -1902,8 +1840,7 @@ static void mesh_normals_loop_custom_set(const MVert *mverts,
/* Current normal differs too much from org one, we have to tag the edge between
* previous loop's face and current's one as sharp.
* We know those two loops do not point to the same edge,
* since we do not allow reversed winding in a same smooth fan.
*/
* since we do not allow reversed winding in a same smooth fan. */
const MPoly *mp = &mpolys[loop_to_poly[lidx]];
const MLoop *mlp =
&mloops[(lidx == mp->loopstart) ? mp->loopstart + mp->totloop - 1 : lidx - 1];
@ -1975,8 +1912,7 @@ static void mesh_normals_loop_custom_set(const MVert *mverts,
if (BLI_BITMAP_TEST_BOOL(done_loops, i)) {
/* Note we accumulate and average all custom normals in current smooth fan,
* to avoid getting different clnors data (tiny differences in plain custom normals can
* give rather huge differences in computed 2D factors).
*/
* give rather huge differences in computed 2D factors). */
LinkNode *loops = lnors_spacearr.lspacearr[i]->loops;
if (lnors_spacearr.lspacearr[i]->flags & MLNOR_SPACE_IS_SINGLE) {
BLI_assert(POINTER_AS_INT(loops) == i);
@ -2092,15 +2028,14 @@ static void mesh_set_custom_normals(Mesh *mesh, float (*r_custom_nors)[3], const
bool free_polynors = false;
if (polynors == nullptr) {
polynors = (float(*)[3])MEM_mallocN(sizeof(float[3]) * (size_t)mesh->totpoly, __func__);
BKE_mesh_calc_normals_poly(mesh->mvert,
nullptr,
mesh->totvert,
mesh->mloop,
mesh->mpoly,
mesh->totloop,
mesh->totpoly,
polynors,
false);
BKE_mesh_calc_normals_poly_and_vertex(mesh->mvert,
mesh->totvert,
mesh->mloop,
mesh->totloop,
mesh->mpoly,
mesh->totpoly,
polynors,
nullptr);
free_polynors = true;
}

View File

@ -1381,14 +1381,12 @@ void BKE_mesh_remap_calc_loops_from_mesh(const int mode,
}
if (dirty_nors_dst || do_poly_nors_dst) {
BKE_mesh_calc_normals_poly(verts_dst,
NULL,
numverts_dst,
loops_dst,
polys_dst,
numloops_dst,
polys_dst,
numpolys_dst,
poly_nors_dst,
true);
poly_nors_dst);
}
}
if (need_lnors_dst) {
@ -2239,14 +2237,12 @@ void BKE_mesh_remap_calc_polys_from_mesh(const int mode,
}
if (dirty_nors_dst) {
BKE_mesh_calc_normals_poly(verts_dst,
NULL,
numverts_dst,
loops_dst,
polys_dst,
numloops_dst,
polys_dst,
numpolys_dst,
poly_nors_dst,
true);
poly_nors_dst);
}
}

View File

@ -2364,7 +2364,7 @@ bNodeLink *nodeAddLink(
ntree->update |= NTREE_UPDATE_LINKS;
}
if (link->tosock->flag & SOCK_MULTI_INPUT) {
if (link != nullptr && link->tosock->flag & SOCK_MULTI_INPUT) {
link->multi_input_socket_index = node_count_links(ntree, link->tosock) - 1;
}
@ -3194,6 +3194,7 @@ void ntreeFreeEmbeddedTree(bNodeTree *ntree)
{
ntreeFreeTree(ntree);
BKE_libblock_free_data(&ntree->id, true);
BKE_libblock_free_data_py(&ntree->id);
}
void ntreeFreeLocalTree(bNodeTree *ntree)

View File

@ -914,7 +914,7 @@ static void object_blend_read_lib(BlendLibReader *reader, ID *id)
if (ob->id.lib) {
BLO_reportf_wrap(reports,
RPT_INFO,
TIP_("Can't find obdata of %s lib %s\n"),
TIP_("Can't find object data of %s lib %s\n"),
ob->id.name + 2,
ob->id.lib->filepath);
}

View File

@ -530,7 +530,7 @@ static void ocean_compute_jacobian_jxx(TaskPool *__restrict pool, void *UNUSED(t
for (j = 0; j <= o->_N / 2; j++) {
fftw_complex mul_param;
/* init_complex(mul_param, -scale, 0); */
// init_complex(mul_param, -scale, 0);
init_complex(mul_param, -1, 0);
mul_complex_f(mul_param, mul_param, chop_amount);
@ -563,7 +563,7 @@ static void ocean_compute_jacobian_jzz(TaskPool *__restrict pool, void *UNUSED(t
for (j = 0; j <= o->_N / 2; j++) {
fftw_complex mul_param;
/* init_complex(mul_param, -scale, 0); */
// init_complex(mul_param, -scale, 0);
init_complex(mul_param, -1, 0);
mul_complex_f(mul_param, mul_param, chop_amount);
@ -596,7 +596,7 @@ static void ocean_compute_jacobian_jxz(TaskPool *__restrict pool, void *UNUSED(t
for (j = 0; j <= o->_N / 2; j++) {
fftw_complex mul_param;
/* init_complex(mul_param, -scale, 0); */
// init_complex(mul_param, -scale, 0);
init_complex(mul_param, -1, 0);
mul_complex_f(mul_param, mul_param, chop_amount);
@ -1015,7 +1015,7 @@ bool BKE_ocean_init(struct Ocean *o,
"ocean_fft_in_nz");
o->_N_x = (double *)MEM_mallocN(o->_M * o->_N * sizeof(double), "ocean_N_x");
/* o->_N_y = (float *) fftwf_malloc(o->_M * o->_N * sizeof(float)); (MEM01) */
// o->_N_y = (float *) fftwf_malloc(o->_M * o->_N * sizeof(float)); /* (MEM01) */
o->_N_z = (double *)MEM_mallocN(o->_M * o->_N * sizeof(double), "ocean_N_z");
o->_N_x_plan = fftw_plan_dft_c2r_2d(o->_M, o->_N, o->_fft_in_nx, o->_N_x, FFTW_ESTIMATE);
@ -1083,7 +1083,7 @@ void BKE_ocean_free_data(struct Ocean *oc)
fftw_destroy_plan(oc->_N_x_plan);
fftw_destroy_plan(oc->_N_z_plan);
MEM_freeN(oc->_N_x);
/* fftwf_free(oc->_N_y); (MEM01) */
// fftwf_free(oc->_N_y); /* (MEM01) */
MEM_freeN(oc->_N_z);
}

View File

@ -77,7 +77,7 @@ static float ocean_spectrum_wind_and_damp(const Ocean *oc,
float newval = val * pow(fabs(k_dot_w), oc->_wind_alignment);
/* Eliminate wavelengths smaller than cutoff. */
/* val *= exp(-k2 * m_cutoff); */
// val *= exp(-k2 * m_cutoff);
/* Reduce reflected waves. */
if (k_dot_w < 0.0f) {

View File

@ -4761,6 +4761,7 @@ static void particle_settings_free_local(ParticleSettings *particle_settings)
{
BKE_libblock_free_datablock(&particle_settings->id, 0);
BKE_libblock_free_data(&particle_settings->id, false);
BLI_assert(!particle_settings->id.py_instance); /* Or call #BKE_libblock_free_data_py. */
MEM_freeN(particle_settings);
}

View File

@ -445,7 +445,8 @@ static void scene_free_data(ID *id)
* for objects directly in the master collection? then other
* collections in the scene need to do it too? */
if (scene->master_collection) {
BKE_collection_free(scene->master_collection);
BKE_collection_free_data(scene->master_collection);
BKE_libblock_free_data_py(&scene->master_collection->id);
MEM_freeN(scene->master_collection);
scene->master_collection = NULL;
}

View File

@ -2277,7 +2277,7 @@ static void softbody_calc_forces(
float fieldfactor = -1.0f, windfactor = 0.25;
int do_deflector /*, do_selfcollision */, do_springcollision, do_aero;
/* gravity = sb->grav * sb_grav_force_scale(ob); */ /* UNUSED */
// gravity = sb->grav * sb_grav_force_scale(ob); /* UNUSED */
/* check conditions for various options */
do_deflector = query_external_colliders(depsgraph, sb->collision_group);
@ -2749,7 +2749,7 @@ static void mesh_to_softbody(Object *ob)
build_bps_springlist(ob); /* scan for springs attached to bodypoints ONCE */
/* insert *other second order* springs if desired */
if (sb->secondspring > 0.0000001f) {
/* exploits the first run of build_bps_springlist(ob); */
/* Exploits the first run of `build_bps_springlist(ob)`. */
add_2nd_order_springs(ob, sb->secondspring);
/* yes we need to do it again. */
build_bps_springlist(ob);

View File

@ -1145,6 +1145,9 @@ MINLINE float len_v3v3(const float a[3], const float b[3])
return len_v3(d);
}
/**
* \note any vectors containing `nan` will be zeroed out.
*/
MINLINE float normalize_v2_v2_length(float r[2], const float a[2], const float unit_length)
{
float d = dot_v2v2(a, a);
@ -1154,6 +1157,7 @@ MINLINE float normalize_v2_v2_length(float r[2], const float a[2], const float u
mul_v2_v2fl(r, a, unit_length / d);
}
else {
/* Either the vector is small or one of it's values contained `nan`. */
zero_v2(r);
d = 0.0f;
}
@ -1175,17 +1179,20 @@ MINLINE float normalize_v2_length(float n[2], const float unit_length)
return normalize_v2_v2_length(n, n, unit_length);
}
/**
* \note any vectors containing `nan` will be zeroed out.
*/
MINLINE float normalize_v3_v3_length(float r[3], const float a[3], const float unit_length)
{
float d = dot_v3v3(a, a);
/* a larger value causes normalize errors in a
* scaled down models with camera extreme close */
/* A larger value causes normalize errors in a scaled down models with camera extreme close. */
if (d > 1.0e-35f) {
d = sqrtf(d);
mul_v3_v3fl(r, a, unit_length / d);
}
else {
/* Either the vector is small or one of it's values contained `nan`. */
zero_v3(r);
d = 0.0f;
}

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