Merge branch 'master' into temp_bmesh_multires
This commit is contained in:
commit
ab632243e6
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -96,7 +96,7 @@ if(WIN32)
|
|||
external_osl
|
||||
external_flexbison
|
||||
)
|
||||
else()
|
||||
elseif(UNIX AND NOT APPLE)
|
||||
add_dependencies(
|
||||
external_osl
|
||||
external_flex
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
||||
|
||||
|
|
@ -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")
|
||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
||||
|
|
|
@ -32,4 +32,5 @@ set FORMAT=
|
|||
set TEST=
|
||||
set BUILD_WITH_SCCACHE=
|
||||
set ICONS=
|
||||
set ICONS_GEOM=
|
||||
set ICONS_GEOM=
|
||||
set DOC_PY=
|
||||
|
|
|
@ -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^)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import sys
|
||||
import os
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
|
@ -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).
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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_;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 &litude)
|
||||
|
@ -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),
|
||||
|
|
|
@ -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 &litude);
|
||||
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;
|
||||
|
|
|
@ -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 &litude)
|
||||
|
@ -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) {
|
||||
|
|
|
@ -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 &litude);
|
||||
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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
15
make.bat
15
make.bat
|
@ -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.
|
@ -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:
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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),
|
||||
])
|
||||
|
|
|
@ -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'}),
|
||||
])
|
||||
|
|
|
@ -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():
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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 ---
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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()
|
||||
|
||||
|
|
|
@ -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")
|
||||
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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")),
|
||||
),
|
||||
)
|
||||
|
|
|
@ -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':
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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. */
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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)) {
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
};
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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. */
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
|
|
@ -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++;
|
||||
|
|
|
@ -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) ||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
Loading…
Reference in New Issue