Sculpt: Improve Expand performance #120125

Closed
Raul Fernandez Hernandez wants to merge 181 commits from farsthary/blender:improve-expand-perf into main

When changing the target branch, be careful to rebase the branch in your fork to match. See documentation.
304 changed files with 10466 additions and 1826 deletions
Showing only changes of commit 6c7d2cb02e - Show all commits

View File

@ -30,7 +30,7 @@ CHECKER_EXCLUDE_SOURCE_FILES = set(os.path.join(*f.split("/")) for f in (
"source/blender/draw/engines/eevee_next/eevee_lut.cc", "source/blender/draw/engines/eevee_next/eevee_lut.cc",
)) ))
CHECKER_ARGS = [ CHECKER_ARGS = (
# Speed up execution. # Speed up execution.
# As Blender has many defines, the total number of configurations is large making execution unreasonably slow. # As Blender has many defines, the total number of configurations is large making execution unreasonably slow.
# This could be increased but do so with care. # This could be increased but do so with care.
@ -39,9 +39,15 @@ CHECKER_ARGS = [
# Enable this when includes are missing. # Enable this when includes are missing.
# "--check-config", # "--check-config",
# This is slower, for a comprehensive output it is needed.
"--check-level=exhaustive",
# Shows many pedantic issues, some are quite useful. # Shows many pedantic issues, some are quite useful.
"--enable=all", "--enable=all",
# Generates many warnings, CPPCHECK known about system includes without resolving them.
"--suppress=missingIncludeSystem",
# Also shows useful messages, even if some are false-positives. # Also shows useful messages, even if some are false-positives.
"--inconclusive", "--inconclusive",
@ -50,7 +56,15 @@ CHECKER_ARGS = [
*(() if USE_VERBOSE else ("--quiet",)) *(() if USE_VERBOSE else ("--quiet",))
# NOTE: `--cppcheck-build-dir=<dir>` is added later as a temporary directory. # NOTE: `--cppcheck-build-dir=<dir>` is added later as a temporary directory.
] )
CHECKER_ARGS_C = (
"--std=c11",
)
CHECKER_ARGS_CXX = (
"--std=c++17",
)
def source_info_filter( def source_info_filter(
@ -74,22 +88,50 @@ def source_info_filter(
return source_info_result return source_info_result
def cppcheck() -> None: def cppcheck(temp_dir: str) -> None:
temp_build_dir = os.path.join(temp_dir, "build")
temp_source_dir = os.path.join(temp_dir, "source")
del temp_dir
os.mkdir(temp_build_dir)
os.mkdir(temp_source_dir)
source_info = project_source_info.build_info(ignore_prefix_list=CHECKER_IGNORE_PREFIX) source_info = project_source_info.build_info(ignore_prefix_list=CHECKER_IGNORE_PREFIX)
source_defines = project_source_info.build_defines_as_args() cppcheck_compiler_h = os.path.join(temp_source_dir, "cppcheck_compiler.h")
with open(cppcheck_compiler_h, "w", encoding="utf-8") as fh:
fh.write(project_source_info.build_defines_as_source())
# Add additional defines.
fh.write("\n")
# Python's `pyport.h` errors without this.
fh.write("#define UCHAR_MAX 255\n")
# `intern/atomic/intern/atomic_ops_utils.h` errors with `Cannot find int size` without this.
fh.write("#define UINT_MAX 0xFFFFFFFF\n")
# Apply exclusion. # Apply exclusion.
source_info = source_info_filter(source_info) source_info = source_info_filter(source_info)
check_commands = [] check_commands = []
for c, inc_dirs, defs in source_info: for c, inc_dirs, defs in source_info:
if c.endswith(".c"):
checker_args_extra = CHECKER_ARGS_C
else:
checker_args_extra = CHECKER_ARGS_CXX
cmd = ( cmd = (
[CHECKER_BIN] + CHECKER_BIN,
CHECKER_ARGS + *CHECKER_ARGS,
[c] + *checker_args_extra,
[("-I%s" % i) for i in inc_dirs] + "--cppcheck-build-dir=" + temp_build_dir,
[("-D%s" % d) for d in defs] + "--include=" + cppcheck_compiler_h,
source_defines # NOTE: for some reason failing to include this crease a large number of syntax errors
# from `intern/guardedalloc/MEM_guardedalloc.h`. Include directly to resolve.
"--include=" + os.path.join(
project_source_info.SOURCE_DIR, "source", "blender", "blenlib", "BLI_compiler_attrs.h",
),
c,
*[("-I%s" % i) for i in inc_dirs],
*[("-D%s" % d) for d in defs],
) )
check_commands.append((c, cmd)) check_commands.append((c, cmd))
@ -119,8 +161,7 @@ def cppcheck() -> None:
def main() -> None: def main() -> None:
with tempfile.TemporaryDirectory() as temp_dir: with tempfile.TemporaryDirectory() as temp_dir:
CHECKER_ARGS.append("--cppcheck-build-dir=" + temp_dir) cppcheck(temp_dir)
cppcheck()
if __name__ == "__main__": if __name__ == "__main__":

View File

@ -24,12 +24,12 @@ from typing import (
Any, Any,
Callable, Callable,
Generator, Generator,
IO,
List, List,
Optional, Optional,
Sequence, Sequence,
Tuple, Tuple,
Union, Union,
cast,
) )
import shlex import shlex
@ -120,12 +120,13 @@ def makefile_log() -> List[str]:
time.sleep(1) time.sleep(1)
# We know this is always true based on the input arguments to `Popen`. # We know this is always true based on the input arguments to `Popen`.
stdout: IO[bytes] = process.stdout # type: ignore assert process.stdout is not None
stdout: IO[bytes] = process.stdout
out = stdout.read() out = stdout.read()
stdout.close() stdout.close()
print("done!", len(out), "bytes") print("done!", len(out), "bytes")
return cast(List[str], out.decode("utf-8", errors="ignore").split("\n")) return out.decode("utf-8", errors="ignore").split("\n")
def build_info( def build_info(
@ -211,9 +212,10 @@ def build_defines_as_source() -> str:
) )
# We know this is always true based on the input arguments to `Popen`. # We know this is always true based on the input arguments to `Popen`.
stdout: IO[bytes] = process.stdout # type: ignore assert process.stdout is not None
stdout: IO[bytes] = process.stdout
return cast(str, stdout.read().strip().decode('ascii')) return stdout.read().strip().decode('ascii')
def build_defines_as_args() -> List[str]: def build_defines_as_args() -> List[str]:

View File

@ -33,7 +33,7 @@ def main() -> None:
blender_srcdir = Path(__file__).absolute().parent.parent.parent blender_srcdir = Path(__file__).absolute().parent.parent.parent
cli_parser = argparse.ArgumentParser( cli_parser = argparse.ArgumentParser(
description=f"Create a tarball of the Blender sources, optionally including sources of dependencies.", description="Create a tarball of the Blender sources, optionally including sources of dependencies.",
epilog="This script is intended to be run by `make source_archive_complete`.", epilog="This script is intended to be run by `make source_archive_complete`.",
) )
cli_parser.add_argument( cli_parser.add_argument(

View File

@ -393,7 +393,7 @@ def floating_checkout_add_origin_if_needed(
upstream_url = make_utils.git_get_remote_url(args.git_command, "upstream") upstream_url = make_utils.git_get_remote_url(args.git_command, "upstream")
call((args.git_command, "remote", "rename", "upstream", "origin")) call((args.git_command, "remote", "rename", "upstream", "origin"))
make_utils.git_set_config(args.git_command, f"remote.origin.url", origin_external_url) make_utils.git_set_config(args.git_command, "remote.origin.url", origin_external_url)
call((args.git_command, "remote", "add", "upstream", upstream_url)) call((args.git_command, "remote", "add", "upstream", upstream_url))
finally: finally:

View File

@ -32,6 +32,7 @@ endif()
add_subdirectory(rangetree) add_subdirectory(rangetree)
add_subdirectory(nanosvg) add_subdirectory(nanosvg)
add_subdirectory(wcwidth) add_subdirectory(wcwidth)
add_subdirectory(xxhash)
if(WITH_BULLET) if(WITH_BULLET)
if(NOT WITH_SYSTEM_BULLET) if(NOT WITH_SYSTEM_BULLET)

21
extern/xxhash/CMakeLists.txt vendored Normal file
View File

@ -0,0 +1,21 @@
# SPDX-FileCopyrightText: 2024 Blender Authors
#
# SPDX-License-Identifier: GPL-2.0-or-later
set(INC
PUBLIC .
)
set(INC_SYS
)
set(SRC
xxhash.c
xxhash.h
)
set(LIB
)
blender_add_lib(extern_xxhash "${SRC}" "${INC}" "${INC_SYS}" "${LIB}")
add_library(bf::extern::xxhash ALIAS extern_xxhash)

26
extern/xxhash/LICENSE vendored Normal file
View File

@ -0,0 +1,26 @@
xxHash Library
Copyright (c) 2012-2021 Yann Collet
All rights reserved.
BSD 2-Clause License (https://www.opensource.org/licenses/bsd-license.php)
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice, this
list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

6
extern/xxhash/README.blender vendored Normal file
View File

@ -0,0 +1,6 @@
Project: xxHash
URL: https://xxhash.com/
License: BSD 2-Clause
Upstream version: v0.8.2 (2023-07-21)
Local modifications:
* None

43
extern/xxhash/xxhash.c vendored Normal file
View File

@ -0,0 +1,43 @@
/*
* xxHash - Extremely Fast Hash algorithm
* Copyright (C) 2012-2021 Yann Collet
*
* BSD 2-Clause License (https://www.opensource.org/licenses/bsd-license.php)
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* You can contact the author at:
* - xxHash homepage: https://www.xxhash.com
* - xxHash source repository: https://github.com/Cyan4973/xxHash
*/
/*
* xxhash.c instantiates functions defined in xxhash.h
*/
#define XXH_STATIC_LINKING_ONLY /* access advanced declarations */
#define XXH_IMPLEMENTATION /* access definitions */
#include "xxhash.h"

6773
extern/xxhash/xxhash.h vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@ -175,9 +175,8 @@ static void clg_str_vappendf(CLogStringBuf *cstr, const char *fmt, va_list args)
{ {
/* Use limit because windows may use '-1' for a formatting error. */ /* Use limit because windows may use '-1' for a formatting error. */
const uint len_max = 65535; const uint len_max = 65535;
uint len_avail = cstr->len_alloc - cstr->len;
while (true) { while (true) {
uint len_avail = cstr->len_alloc - cstr->len;
va_list args_cpy; va_list args_cpy;
va_copy(args_cpy, args); va_copy(args_cpy, args);
int retval = vsnprintf(cstr->data + cstr->len, len_avail, fmt, args_cpy); int retval = vsnprintf(cstr->data + cstr->len, len_avail, fmt, args_cpy);
@ -188,22 +187,23 @@ static void clg_str_vappendf(CLogStringBuf *cstr, const char *fmt, va_list args)
* message. */ * message. */
break; break;
} }
else if ((uint)retval <= len_avail) {
if ((uint)retval <= len_avail) {
/* Copy was successful. */ /* Copy was successful. */
cstr->len += (uint)retval; cstr->len += (uint)retval;
break; break;
} }
else {
/* vsnprintf was not successful, due to lack of allocated space, retval contains expected /* `vsnprintf` was not successful, due to lack of allocated space, `retval` contains expected
* length of the formatted string, use it to allocate required amount of memory. */ * length of the formatted string, use it to allocate required amount of memory. */
uint len_alloc = cstr->len + (uint)retval; uint len_alloc = cstr->len + (uint)retval;
if (len_alloc >= len_max) { if (len_alloc >= len_max) {
/* Safe upper-limit, just in case... */ /* Safe upper-limit, just in case... */
break; break;
}
clg_str_reserve(cstr, len_alloc);
len_avail = cstr->len_alloc - cstr->len;
} }
clg_str_reserve(cstr, len_alloc);
len_avail = cstr->len_alloc - cstr->len;
} }
} }

View File

@ -773,8 +773,9 @@ void OneapiDevice::get_adjusted_global_and_local_sizes(SyclQueue *queue,
size_t &kernel_local_size) size_t &kernel_local_size)
{ {
assert(queue); assert(queue);
const static size_t preferred_work_group_size_intersect = 128;
const static size_t preferred_work_group_size_intersect_shading = 32; const static size_t preferred_work_group_size_shading = 256;
const static size_t preferred_work_group_size_shading_simd8 = 64;
/* Shader evaluation kernels seems to use some amount of shared memory, so better /* Shader evaluation kernels seems to use some amount of shared memory, so better
* to avoid usage of maximum work group sizes for them. */ * to avoid usage of maximum work group sizes for them. */
const static size_t preferred_work_group_size_shader_evaluation = 256; const static size_t preferred_work_group_size_shader_evaluation = 256;
@ -783,6 +784,9 @@ void OneapiDevice::get_adjusted_global_and_local_sizes(SyclQueue *queue,
const static size_t preferred_work_group_size_cryptomatte = 512; const static size_t preferred_work_group_size_cryptomatte = 512;
const static size_t preferred_work_group_size_default = 1024; const static size_t preferred_work_group_size_default = 1024;
const sycl::device &device = reinterpret_cast<sycl::queue *>(queue)->get_device();
const size_t max_work_group_size = device.get_info<sycl::info::device::max_work_group_size>();
size_t preferred_work_group_size = 0; size_t preferred_work_group_size = 0;
switch (kernel) { switch (kernel) {
case DEVICE_KERNEL_INTEGRATOR_INIT_FROM_CAMERA: case DEVICE_KERNEL_INTEGRATOR_INIT_FROM_CAMERA:
@ -792,6 +796,9 @@ void OneapiDevice::get_adjusted_global_and_local_sizes(SyclQueue *queue,
case DEVICE_KERNEL_INTEGRATOR_INTERSECT_SUBSURFACE: case DEVICE_KERNEL_INTEGRATOR_INTERSECT_SUBSURFACE:
case DEVICE_KERNEL_INTEGRATOR_INTERSECT_VOLUME_STACK: case DEVICE_KERNEL_INTEGRATOR_INTERSECT_VOLUME_STACK:
case DEVICE_KERNEL_INTEGRATOR_INTERSECT_DEDICATED_LIGHT: case DEVICE_KERNEL_INTEGRATOR_INTERSECT_DEDICATED_LIGHT:
preferred_work_group_size = preferred_work_group_size_intersect;
break;
case DEVICE_KERNEL_INTEGRATOR_SHADE_BACKGROUND: case DEVICE_KERNEL_INTEGRATOR_SHADE_BACKGROUND:
case DEVICE_KERNEL_INTEGRATOR_SHADE_LIGHT: case DEVICE_KERNEL_INTEGRATOR_SHADE_LIGHT:
case DEVICE_KERNEL_INTEGRATOR_SHADE_SURFACE: case DEVICE_KERNEL_INTEGRATOR_SHADE_SURFACE:
@ -799,9 +806,13 @@ void OneapiDevice::get_adjusted_global_and_local_sizes(SyclQueue *queue,
case DEVICE_KERNEL_INTEGRATOR_SHADE_SURFACE_MNEE: case DEVICE_KERNEL_INTEGRATOR_SHADE_SURFACE_MNEE:
case DEVICE_KERNEL_INTEGRATOR_SHADE_VOLUME: case DEVICE_KERNEL_INTEGRATOR_SHADE_VOLUME:
case DEVICE_KERNEL_INTEGRATOR_SHADE_SHADOW: case DEVICE_KERNEL_INTEGRATOR_SHADE_SHADOW:
case DEVICE_KERNEL_INTEGRATOR_SHADE_DEDICATED_LIGHT: case DEVICE_KERNEL_INTEGRATOR_SHADE_DEDICATED_LIGHT: {
preferred_work_group_size = preferred_work_group_size_intersect_shading; const bool device_is_simd8 =
break; (device.has(sycl::aspect::ext_intel_gpu_eu_simd_width) &&
device.get_info<sycl::ext::intel::info::device::gpu_eu_simd_width>() == 8);
preferred_work_group_size = (device_is_simd8) ? preferred_work_group_size_shading_simd8 :
preferred_work_group_size_shading;
} break;
case DEVICE_KERNEL_CRYPTOMATTE_POSTPROCESS: case DEVICE_KERNEL_CRYPTOMATTE_POSTPROCESS:
preferred_work_group_size = preferred_work_group_size_cryptomatte; preferred_work_group_size = preferred_work_group_size_cryptomatte;
@ -829,11 +840,7 @@ void OneapiDevice::get_adjusted_global_and_local_sizes(SyclQueue *queue,
preferred_work_group_size = preferred_work_group_size_default; preferred_work_group_size = preferred_work_group_size_default;
} }
const size_t limit_work_group_size = reinterpret_cast<sycl::queue *>(queue) kernel_local_size = std::min(max_work_group_size, preferred_work_group_size);
->get_device()
.get_info<sycl::info::device::max_work_group_size>();
kernel_local_size = std::min(limit_work_group_size, preferred_work_group_size);
/* NOTE(@nsirgien): As for now non-uniform work-groups don't work on most oneAPI devices, /* NOTE(@nsirgien): As for now non-uniform work-groups don't work on most oneAPI devices,
* we extend work size to fit uniformity requirements. */ * we extend work size to fit uniformity requirements. */

View File

@ -46,7 +46,7 @@ static const char *oidn_device_type_to_string(const OIDNDeviceType type)
return "HIP"; return "HIP";
# endif # endif
/* The Metal support was added in OIDN 2.2.*/ /* The Metal support was added in OIDN 2.2. */
# if (OIDN_VERSION_MAJOR > 2) || ((OIDN_VERSION_MAJOR == 2) && (OIDN_VERSION_MINOR >= 2)) # if (OIDN_VERSION_MAJOR > 2) || ((OIDN_VERSION_MAJOR == 2) && (OIDN_VERSION_MINOR >= 2))
case OIDN_DEVICE_TYPE_METAL: case OIDN_DEVICE_TYPE_METAL:
return "METAL"; return "METAL";

View File

@ -18,7 +18,7 @@ typedef struct HuangHairExtra {
/* Optional modulation factors. */ /* Optional modulation factors. */
float R, TT, TRT; float R, TT, TRT;
/* Local coordinate system. X is stored as `bsdf->N`.*/ /* Local coordinate system. X is stored as `bsdf->N`. */
float3 Y, Z; float3 Y, Z;
/* Incident direction in local coordinate system. */ /* Incident direction in local coordinate system. */

View File

@ -18,9 +18,8 @@
#include "util/texture.h" #include "util/texture.h"
#include "util/types.h" #include "util/types.h"
/* On x86_64, versions of glibc < 2.16 have an issue where expf is /* On x86_64, versions of GLIBC < 2.16 have an issue where `expf` is
* much slower than the double version. This was fixed in glibc 2.16. * much slower than the double version. This was fixed in GLIBC 2.16. */
*/
#if !defined(__KERNEL_GPU__) && defined(__x86_64__) && defined(__x86_64__) && \ #if !defined(__KERNEL_GPU__) && defined(__x86_64__) && defined(__x86_64__) && \
defined(__GNU_LIBRARY__) && defined(__GLIBC__) && defined(__GLIBC_MINOR__) && \ defined(__GNU_LIBRARY__) && defined(__GLIBC__) && defined(__GLIBC_MINOR__) && \
(__GLIBC__ <= 2 && __GLIBC_MINOR__ < 16) (__GLIBC__ <= 2 && __GLIBC_MINOR__ < 16)

View File

@ -38,7 +38,7 @@
#define ccl_global #define ccl_global
#define ccl_always_inline __attribute__((always_inline)) #define ccl_always_inline __attribute__((always_inline))
#define ccl_device_inline inline #define ccl_device_inline inline
#define ccl_noinline __attribute__((noinline)) #define ccl_noinline
#define ccl_inline_constant const constexpr #define ccl_inline_constant const constexpr
#define ccl_device_constant static constexpr #define ccl_device_constant static constexpr
#define ccl_static_constexpr static constexpr #define ccl_static_constexpr static constexpr

View File

@ -275,8 +275,8 @@ ccl_device_inline float4 improve_5throot_solution_sse2(const float4 &old_result,
/* Calculate powf(x, 2.4). Working domain: 1e-10 < x < 1e+10 */ /* Calculate powf(x, 2.4). Working domain: 1e-10 < x < 1e+10 */
ccl_device_inline float4 fastpow24_sse2(const float4 &arg) ccl_device_inline float4 fastpow24_sse2(const float4 &arg)
{ {
/* max, avg and |avg| errors were calculated in gcc without FMA instructions /* `max`, `avg` and |avg| errors were calculated in GCC without FMA instructions.
* The final precision should be better than powf in glibc */ * The final precision should be better than `powf` in GLIBC. */
/* Calculate x^4/5, coefficient 0.994 was constructed manually to minimize avg error */ /* Calculate x^4/5, coefficient 0.994 was constructed manually to minimize avg error */
/* 0x3F4CCCCD = 4/5 */ /* 0x3F4CCCCD = 4/5 */

View File

@ -14,7 +14,7 @@ CCL_NAMESPACE_BEGIN
thread::thread(function<void()> run_cb) : run_cb_(run_cb), joined_(false) thread::thread(function<void()> run_cb) : run_cb_(run_cb), joined_(false)
{ {
#if defined(__APPLE__) || defined(__linux__) && !defined(__GLIBC__) #if defined(__APPLE__) || defined(__linux__) && !defined(__GLIBC__)
/* Set the stack size to 2MB to match glibc. The default 512KB on macOS is /* Set the stack size to 2MB to match GLIBC. The default 512KB on macOS is
* too small for Embree, and consistent stack size also makes things more * too small for Embree, and consistent stack size also makes things more
* predictable in general. */ * predictable in general. */
pthread_attr_t attribute; pthread_attr_t attribute;

View File

@ -427,7 +427,7 @@ struct GWL_Cursor {
/** /**
* The name of the theme (set by an environment variable). * The name of the theme (set by an environment variable).
* When disabled, leave as an empty string and the default theme will be used. * When disabled, leave as an empty string and pass in nullptr to use the default theme.
*/ */
std::string theme_name; std::string theme_name;
/** /**
@ -2507,7 +2507,9 @@ static const wl_cursor *gwl_seat_cursor_find_from_shape(GWL_Seat *seat,
if (!cursor->wl.theme) { if (!cursor->wl.theme) {
/* The cursor wl_surface hasn't entered an output yet. Initialize theme with scale 1. */ /* The cursor wl_surface hasn't entered an output yet. Initialize theme with scale 1. */
cursor->wl.theme = wl_cursor_theme_load( cursor->wl.theme = wl_cursor_theme_load(
cursor->theme_name.c_str(), cursor->theme_size, seat->system->wl_shm_get()); (cursor->theme_name.empty() ? nullptr : cursor->theme_name.c_str()),
cursor->theme_size,
seat->system->wl_shm_get());
} }
if (cursor->wl.theme) { if (cursor->wl.theme) {
@ -3521,7 +3523,9 @@ static bool update_cursor_scale(GWL_Cursor &cursor,
} }
wl_cursor_theme_destroy(cursor.wl.theme); wl_cursor_theme_destroy(cursor.wl.theme);
cursor.wl.theme = wl_cursor_theme_load( cursor.wl.theme = wl_cursor_theme_load(
cursor.theme_name.c_str(), scale * cursor.theme_size, shm); (cursor.theme_name.empty() ? nullptr : cursor.theme_name.c_str()),
scale * cursor.theme_size,
shm);
if (cursor.wl.theme_cursor) { if (cursor.wl.theme_cursor) {
cursor.wl.theme_cursor = wl_cursor_theme_get_cursor(cursor.wl.theme, cursor.wl.theme_cursor = wl_cursor_theme_get_cursor(cursor.wl.theme,
cursor.wl.theme_cursor_name); cursor.wl.theme_cursor_name);

View File

@ -115,10 +115,10 @@ void *MEM_lockfree_dupallocN(const void *vmemh)
{ {
void *newp = NULL; void *newp = NULL;
if (vmemh) { if (vmemh) {
MemHead *memh = MEMHEAD_FROM_PTR(vmemh); const MemHead *memh = MEMHEAD_FROM_PTR(vmemh);
const size_t prev_size = MEM_lockfree_allocN_len(vmemh); const size_t prev_size = MEM_lockfree_allocN_len(vmemh);
if (UNLIKELY(MEMHEAD_IS_ALIGNED(memh))) { if (UNLIKELY(MEMHEAD_IS_ALIGNED(memh))) {
MemHeadAligned *memh_aligned = MEMHEAD_ALIGNED_FROM_PTR(vmemh); const MemHeadAligned *memh_aligned = MEMHEAD_ALIGNED_FROM_PTR(vmemh);
newp = MEM_lockfree_mallocN_aligned( newp = MEM_lockfree_mallocN_aligned(
prev_size, (size_t)memh_aligned->alignment, "dupli_malloc"); prev_size, (size_t)memh_aligned->alignment, "dupli_malloc");
} }
@ -135,14 +135,14 @@ void *MEM_lockfree_reallocN_id(void *vmemh, size_t len, const char *str)
void *newp = NULL; void *newp = NULL;
if (vmemh) { if (vmemh) {
MemHead *memh = MEMHEAD_FROM_PTR(vmemh); const MemHead *memh = MEMHEAD_FROM_PTR(vmemh);
size_t old_len = MEM_lockfree_allocN_len(vmemh); const size_t old_len = MEM_lockfree_allocN_len(vmemh);
if (LIKELY(!MEMHEAD_IS_ALIGNED(memh))) { if (LIKELY(!MEMHEAD_IS_ALIGNED(memh))) {
newp = MEM_lockfree_mallocN(len, "realloc"); newp = MEM_lockfree_mallocN(len, "realloc");
} }
else { else {
MemHeadAligned *memh_aligned = MEMHEAD_ALIGNED_FROM_PTR(vmemh); const MemHeadAligned *memh_aligned = MEMHEAD_ALIGNED_FROM_PTR(vmemh);
newp = MEM_lockfree_mallocN_aligned(len, (size_t)memh_aligned->alignment, "realloc"); newp = MEM_lockfree_mallocN_aligned(len, (size_t)memh_aligned->alignment, "realloc");
} }
@ -171,14 +171,14 @@ void *MEM_lockfree_recallocN_id(void *vmemh, size_t len, const char *str)
void *newp = NULL; void *newp = NULL;
if (vmemh) { if (vmemh) {
MemHead *memh = MEMHEAD_FROM_PTR(vmemh); const MemHead *memh = MEMHEAD_FROM_PTR(vmemh);
size_t old_len = MEM_lockfree_allocN_len(vmemh); const size_t old_len = MEM_lockfree_allocN_len(vmemh);
if (LIKELY(!MEMHEAD_IS_ALIGNED(memh))) { if (LIKELY(!MEMHEAD_IS_ALIGNED(memh))) {
newp = MEM_lockfree_mallocN(len, "recalloc"); newp = MEM_lockfree_mallocN(len, "recalloc");
} }
else { else {
MemHeadAligned *memh_aligned = MEMHEAD_ALIGNED_FROM_PTR(vmemh); const MemHeadAligned *memh_aligned = MEMHEAD_ALIGNED_FROM_PTR(vmemh);
newp = MEM_lockfree_mallocN_aligned(len, (size_t)memh_aligned->alignment, "recalloc"); newp = MEM_lockfree_mallocN_aligned(len, (size_t)memh_aligned->alignment, "recalloc");
} }

View File

@ -0,0 +1,23 @@
The 2-Clause BSD License
------------------------
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice, this
list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View File

@ -84,7 +84,7 @@ def _kmi_properties_to_lines_recursive(level, properties, lines):
lines_test = [] lines_test = []
_kmi_properties_to_lines_recursive(level + 2, value, lines_test) _kmi_properties_to_lines_recursive(level + 2, value, lines_test)
if lines_test: if lines_test:
lines.append(f"(") lines.append("(")
lines.append(f"\"{pname}\",\n") lines.append(f"\"{pname}\",\n")
lines.append(f"{indent(level + 3)}" "[") lines.append(f"{indent(level + 3)}" "[")
lines.extend(lines_test) lines.extend(lines_test)
@ -172,19 +172,19 @@ def keyconfig_export_as_data(wm, kc, filepath, *, all_keymaps=False):
fw("},\n") fw("},\n")
fw(f"{indent(2)}" "{") fw(f"{indent(2)}" "{")
is_modal = km.is_modal is_modal = km.is_modal
fw(f"\"items\":\n") fw("\"items\":\n")
fw(f"{indent(3)}[") fw(f"{indent(3)}[")
for kmi in km.keymap_items: for kmi in km.keymap_items:
if is_modal: if is_modal:
kmi_id = kmi.propvalue kmi_id = kmi.propvalue
else: else:
kmi_id = kmi.idname kmi_id = kmi.idname
fw(f"(") fw("(")
kmi_args = kmi_args_as_data(kmi) kmi_args = kmi_args_as_data(kmi)
kmi_data = _kmi_attrs_or_none(4, kmi) kmi_data = _kmi_attrs_or_none(4, kmi)
fw(f"\"{kmi_id:s}\"") fw(f"\"{kmi_id:s}\"")
if kmi_data is None: if kmi_data is None:
fw(f", ") fw(", ")
else: else:
fw(",\n" f"{indent(5)}") fw(",\n" f"{indent(5)}")

View File

@ -6142,6 +6142,7 @@ def km_edit_curves(params):
(op_tool_cycle, "builtin.tilt"), params), (op_tool_cycle, "builtin.tilt"), params),
("transform.transform", {"type": 'S', "value": 'PRESS', "alt": True}, ("transform.transform", {"type": 'S', "value": 'PRESS', "alt": True},
{"properties": [("mode", 'CURVE_SHRINKFATTEN')]}), {"properties": [("mode", 'CURVE_SHRINKFATTEN')]}),
("curves.cyclic_toggle", {"type": 'C', "value": 'PRESS', "alt": True}, None),
]) ])
return keymap return keymap

View File

@ -231,6 +231,72 @@ class DATA_PT_grease_pencil_layer_relations(LayerDataButtonsPanel, Panel):
col.prop_search(layer, "viewlayer_render", context.scene, "view_layers", text="View Layer") col.prop_search(layer, "viewlayer_render", context.scene, "view_layers", text="View Layer")
class DATA_PT_grease_pencil_onion_skinning(DataButtonsPanel, Panel):
bl_label = "Onion Skinning"
def draw(self, context):
grease_pencil = context.grease_pencil
layout = self.layout
layout.use_property_split = True
col = layout.column()
col.prop(grease_pencil, "onion_mode")
col.prop(grease_pencil, "onion_factor", text="Opacity", slider=True)
col.prop(grease_pencil, "onion_keyframe_type")
if grease_pencil.onion_mode == 'ABSOLUTE':
col = layout.column(align=True)
col.prop(grease_pencil, "ghost_before_range", text="Frames Before")
col.prop(grease_pencil, "ghost_after_range", text="Frames After")
elif grease_pencil.onion_mode == 'RELATIVE':
col = layout.column(align=True)
col.prop(grease_pencil, "ghost_before_range", text="Keyframes Before")
col.prop(grease_pencil, "ghost_after_range", text="Keyframes After")
class DATA_PT_grease_pencil_onion_skinning_custom_colors(DataButtonsPanel, Panel):
bl_parent_id = "DATA_PT_grease_pencil_onion_skinning"
bl_label = "Custom Colors"
bl_options = {'DEFAULT_CLOSED'}
def draw_header(self, context):
grease_pencil = context.grease_pencil
self.layout.prop(grease_pencil, "use_ghost_custom_colors", text="")
def draw(self, context):
grease_pencil = context.grease_pencil
layout = self.layout
layout.use_property_split = True
layout.enabled = grease_pencil.users <= 1 and grease_pencil.use_ghost_custom_colors
layout.prop(grease_pencil, "before_color", text="Before")
layout.prop(grease_pencil, "after_color", text="After")
class DATA_PT_grease_pencil_onion_skinning_display(DataButtonsPanel, Panel):
bl_parent_id = "DATA_PT_grease_pencil_onion_skinning"
bl_label = "Display"
bl_options = {'DEFAULT_CLOSED'}
def draw(self, context):
grease_pencil = context.grease_pencil
layout = self.layout
layout.use_property_split = True
# This was done in GPv2 but it's not entirely clear why. Presumably it was
# to indicate that the settings will affect the onion skinning of the
# other users.
layout.enabled = grease_pencil.users <= 1
col = layout.column(align=True)
col.prop(grease_pencil, "use_onion_fade", text="Fade")
sub = layout.column()
sub.active = grease_pencil.onion_mode in {'RELATIVE', 'SELECTED'}
sub.prop(grease_pencil, "use_onion_loop", text="Show Start Frame")
class DATA_PT_grease_pencil_settings(DataButtonsPanel, Panel): class DATA_PT_grease_pencil_settings(DataButtonsPanel, Panel):
bl_label = "Settings" bl_label = "Settings"
@ -257,6 +323,9 @@ classes = (
DATA_PT_grease_pencil_layer_masks, DATA_PT_grease_pencil_layer_masks,
DATA_PT_grease_pencil_layer_transform, DATA_PT_grease_pencil_layer_transform,
DATA_PT_grease_pencil_layer_relations, DATA_PT_grease_pencil_layer_relations,
DATA_PT_grease_pencil_onion_skinning,
DATA_PT_grease_pencil_onion_skinning_custom_colors,
DATA_PT_grease_pencil_onion_skinning_display,
DATA_PT_grease_pencil_settings, DATA_PT_grease_pencil_settings,
DATA_PT_grease_pencil_custom_props, DATA_PT_grease_pencil_custom_props,
GREASE_PENCIL_MT_grease_pencil_add_layer_extra, GREASE_PENCIL_MT_grease_pencil_add_layer_extra,

View File

@ -816,6 +816,27 @@ def brush_settings(layout, context, brush, popover=False):
col.active = not brush.curves_sculpt_settings.use_point_count_interpolate col.active = not brush.curves_sculpt_settings.use_point_count_interpolate
col.prop(brush.curves_sculpt_settings, "points_per_curve", text="Points") col.prop(brush.curves_sculpt_settings, "points_per_curve", text="Points")
if brush.curves_sculpt_tool == 'DENSITY':
col = layout.column()
col.prop(brush.curves_sculpt_settings, "density_add_attempts", text="Count Max")
col = layout.column(heading="Interpolate", align=True)
col.prop(brush.curves_sculpt_settings, "use_length_interpolate", text="Length")
col.prop(brush.curves_sculpt_settings, "use_radius_interpolate", text="Radius")
col.prop(brush.curves_sculpt_settings, "use_shape_interpolate", text="Shape")
col.prop(brush.curves_sculpt_settings, "use_point_count_interpolate", text="Point Count")
col = layout.column()
col.active = not brush.curves_sculpt_settings.use_length_interpolate
col.prop(brush.curves_sculpt_settings, "curve_length", text="Length")
col = layout.column()
col.active = not brush.curves_sculpt_settings.use_radius_interpolate
col.prop(brush.curves_sculpt_settings, "curve_radius", text="Radius")
col = layout.column()
col.active = not brush.curves_sculpt_settings.use_point_count_interpolate
col.prop(brush.curves_sculpt_settings, "points_per_curve", text="Points")
elif brush.curves_sculpt_tool == 'GROW_SHRINK': elif brush.curves_sculpt_tool == 'GROW_SHRINK':
layout.prop(brush.curves_sculpt_settings, "use_uniform_scale") layout.prop(brush.curves_sculpt_settings, "use_uniform_scale")
layout.prop(brush.curves_sculpt_settings, "minimum_length") layout.prop(brush.curves_sculpt_settings, "minimum_length")

View File

@ -671,8 +671,8 @@ class USERPREF_PT_system_os_settings(SystemPanel, CenterAlignMixIn, Panel):
import sys import sys
return sys.platform[:3] == "win" return sys.platform[:3] == "win"
def draw_centered(self, _context, layout): def draw_centered(self, context, layout):
if _context.preferences.system.is_microsoft_store_install: if context.preferences.system.is_microsoft_store_install:
layout.label(text="Microsoft Store installation") layout.label(text="Microsoft Store installation")
layout.label(text="Use Windows 'Default Apps' to associate with blend files") layout.label(text="Use Windows 'Default Apps' to associate with blend files")
else: else:

View File

@ -5911,6 +5911,8 @@ class VIEW3D_MT_edit_curves(Menu):
layout.separator() layout.separator()
layout.operator("curves.attribute_set") layout.operator("curves.attribute_set")
layout.operator("curves.delete") layout.operator("curves.delete")
layout.operator("curves.cyclic_toggle")
layout.operator_menu_enum("curves.curve_type_set", "type")
layout.template_node_operator_asset_menu_items(catalog_path=self.bl_label) layout.template_node_operator_asset_menu_items(catalog_path=self.bl_label)
@ -7861,6 +7863,8 @@ class VIEW3D_PT_overlay_grease_pencil_options(Panel):
'OBJECT': iface_("Grease Pencil"), 'OBJECT': iface_("Grease Pencil"),
}[context.mode], translate=False) }[context.mode], translate=False)
layout.prop(overlay, "use_gpencil_onion_skin", text="Onion Skin")
if ob.mode in {'EDIT'}: if ob.mode in {'EDIT'}:
split = layout.split() split = layout.split()
col = split.column() col = split.column()

View File

@ -105,6 +105,7 @@ set(SRC_DNA_DEFAULTS_INC
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_defaults.h ${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_defaults.h
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_fluid_defaults.h ${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_fluid_defaults.h
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_gpencil_modifier_defaults.h ${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_gpencil_modifier_defaults.h
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_grease_pencil_defaults.h
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_image_defaults.h ${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_image_defaults.h
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_lattice_defaults.h ${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_lattice_defaults.h
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_light_defaults.h ${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_light_defaults.h

View File

@ -30,7 +30,7 @@ class BoneColor : public ::BoneColor {
const ThemeWireColor *effective_color() const; const ThemeWireColor *effective_color() const;
/* Support for storing in a blender::Set<BoneColor>.*/ /* Support for storing in a #blender::Set<BoneColor>. */
bool operator==(const BoneColor &other) const; bool operator==(const BoneColor &other) const;
bool operator!=(const BoneColor &other) const; bool operator!=(const BoneColor &other) const;
uint64_t hash() const; uint64_t hash() const;

View File

@ -73,7 +73,8 @@ bool visualkey_can_use(PointerRNA *ptr, PropertyRNA *prop)
has_parent = (pchan->parent != nullptr); has_parent = (pchan->parent != nullptr);
} }
else { else {
BLI_assert(!"visualkey_can_use called for data-block that is not an Object or PoseBone."); BLI_assert_msg(false,
"visualkey_can_use called for data-block that is not an Object or PoseBone.");
return false; return false;
} }

View File

@ -280,7 +280,7 @@ std::unique_ptr<AssetCatalogDefinitionFile> AssetCatalogDefinitionFile::copy_and
continue; continue;
} }
BLI_assert(!"A CDF should only reference known catalogs."); BLI_assert_msg(false, "A CDF should only reference known catalogs.");
} }
return copy; return copy;

View File

@ -35,7 +35,7 @@ void BKE_addon_pref_type_init(void);
void BKE_addon_pref_type_free(void); void BKE_addon_pref_type_free(void);
struct bAddon *BKE_addon_new(void); struct bAddon *BKE_addon_new(void);
struct bAddon *BKE_addon_find(struct ListBase *addon_list, const char *module); struct bAddon *BKE_addon_find(const struct ListBase *addon_list, const char *module);
struct bAddon *BKE_addon_ensure(struct ListBase *addon_list, const char *module); struct bAddon *BKE_addon_ensure(struct ListBase *addon_list, const char *module);
bool BKE_addon_remove_safe(struct ListBase *addon_list, const char *module); bool BKE_addon_remove_safe(struct ListBase *addon_list, const char *module);
void BKE_addon_free(struct bAddon *addon); void BKE_addon_free(struct bAddon *addon);

View File

@ -280,17 +280,17 @@ void BKE_pose_where_is_bone_tail(bPoseChannel *pchan);
*/ */
void BKE_pose_apply_action_selected_bones(Object *ob, void BKE_pose_apply_action_selected_bones(Object *ob,
bAction *action, bAction *action,
AnimationEvalContext *anim_eval_context); const AnimationEvalContext *anim_eval_context);
/** /**
* Evaluate the action and apply it to the pose. Ignore selection state of the bones. * Evaluate the action and apply it to the pose. Ignore selection state of the bones.
*/ */
void BKE_pose_apply_action_all_bones(Object *ob, void BKE_pose_apply_action_all_bones(Object *ob,
bAction *action, bAction *action,
AnimationEvalContext *anim_eval_context); const AnimationEvalContext *anim_eval_context);
void BKE_pose_apply_action_blend(Object *ob, void BKE_pose_apply_action_blend(Object *ob,
bAction *action, bAction *action,
AnimationEvalContext *anim_eval_context, const AnimationEvalContext *anim_eval_context,
float blend_factor); float blend_factor);
void vec_roll_to_mat3(const float vec[3], float roll, float r_mat[3][3]); void vec_roll_to_mat3(const float vec[3], float roll, float r_mat[3][3]);

View File

@ -89,23 +89,11 @@ class BlobWriteSharing : NonCopyable, NonMovable {
*/ */
Map<const ImplicitSharingInfo *, StoredByRuntimeValue> stored_by_runtime_; Map<const ImplicitSharingInfo *, StoredByRuntimeValue> stored_by_runtime_;
struct SliceHash {
uint64_t a;
uint64_t b;
BLI_STRUCT_EQUALITY_OPERATORS_2(SliceHash, a, b)
uint64_t hash() const
{
return get_default_hash(this->a, this->b);
}
};
/** /**
* Remembers where data was stored based on the hash of the data. This allows us to skip writing * Remembers where data was stored based on the hash of the data. This allows us to skip writing
* the same array again if it has the same hash. * the same array again if it has the same hash.
*/ */
Map<SliceHash, BlobSlice> slice_by_content_hash_; Map<uint64_t, BlobSlice> slice_by_content_hash_;
public: public:
~BlobWriteSharing(); ~BlobWriteSharing();

View File

@ -11,7 +11,7 @@
#include "BLI_bounds_types.hh" #include "BLI_bounds_types.hh"
#include "BLI_generic_virtual_array.hh" #include "BLI_generic_virtual_array.hh"
#include "BLI_implicit_sharing.hh" #include "BLI_implicit_sharing_ptr.hh"
#include "BLI_index_mask_fwd.hh" #include "BLI_index_mask_fwd.hh"
#include "BLI_math_matrix_types.hh" #include "BLI_math_matrix_types.hh"
#include "BLI_math_vector_types.hh" #include "BLI_math_vector_types.hh"
@ -451,7 +451,7 @@ class CurvesEditHints {
* Evaluated positions for the points in #curves_orig. If this is empty, the positions from the * Evaluated positions for the points in #curves_orig. If this is empty, the positions from the
* evaluated #Curves should be used if possible. * evaluated #Curves should be used if possible.
*/ */
std::optional<Array<float3>> positions; ImplicitSharingPtrAndData positions_data;
/** /**
* Matrices which transform point movement vectors from original data to corresponding movements * Matrices which transform point movement vectors from original data to corresponding movements
* of evaluated data. * of evaluated data.
@ -460,6 +460,9 @@ class CurvesEditHints {
CurvesEditHints(const Curves &curves_id_orig) : curves_id_orig(curves_id_orig) {} CurvesEditHints(const Curves &curves_id_orig) : curves_id_orig(curves_id_orig) {}
std::optional<Span<float3>> positions() const;
std::optional<MutableSpan<float3>> positions_for_write();
/** /**
* The edit hints have to correspond to the original curves, i.e. the number of deformed points * The edit hints have to correspond to the original curves, i.e. the number of deformed points
* is the same as the number of original points. * is the same as the number of original points.

View File

@ -249,14 +249,13 @@ void *CustomData_add_layer(CustomData *data,
/** /**
* Adds a layer of the given type to the #CustomData object. The new layer takes ownership of the * Adds a layer of the given type to the #CustomData object. The new layer takes ownership of the
* passed in `layer_data`. If a #ImplicitSharingInfoHandle is passed in, its user count is * passed in `layer_data`. If a #ImplicitSharingInfo is passed in, its user count is increased.
* increased.
*/ */
const void *CustomData_add_layer_with_data(CustomData *data, const void *CustomData_add_layer_with_data(CustomData *data,
eCustomDataType type, eCustomDataType type,
void *layer_data, void *layer_data,
int totelem, int totelem,
const ImplicitSharingInfoHandle *sharing_info); const blender::ImplicitSharingInfo *sharing_info);
/** /**
* Same as above but accepts a name. * Same as above but accepts a name.
@ -272,7 +271,7 @@ const void *CustomData_add_layer_named_with_data(CustomData *data,
void *layer_data, void *layer_data,
int totelem, int totelem,
blender::StringRef name, blender::StringRef name,
const ImplicitSharingInfoHandle *sharing_info); const blender::ImplicitSharingInfo *sharing_info);
void *CustomData_add_layer_anonymous(CustomData *data, void *CustomData_add_layer_anonymous(CustomData *data,
eCustomDataType type, eCustomDataType type,
@ -285,7 +284,7 @@ const void *CustomData_add_layer_anonymous_with_data(
const AnonymousAttributeIDHandle *anonymous_id, const AnonymousAttributeIDHandle *anonymous_id,
int totelem, int totelem,
void *layer_data, void *layer_data,
const ImplicitSharingInfoHandle *sharing_info); const blender::ImplicitSharingInfo *sharing_info);
/** /**
* Frees the active or first data layer with the give type. * Frees the active or first data layer with the give type.

View File

@ -17,22 +17,38 @@ struct BMEditMesh;
namespace blender::bke { namespace blender::bke {
struct EditMeshData { struct EditMeshData {
/** when set, \a vertexNos, faceNos are lazy initialized */ /**
* Deformed positions calculated by modifiers in the modifier stack that can can process an
* edit mesh input. When this is not empty, the other arrays will depend on the values.
*/
Array<float3> vert_positions; Array<float3> vert_positions;
/** lazy initialize (when \a vert_positions is set) */ /**
* Lazily initialized vertex normal cache (used when `vert_positions` is set.
* Access via #BKE_editmesh_cache_ensure_vert_normals instead of directly.
*/
Array<float3> vert_normals; Array<float3> vert_normals;
/**
* Lazily initialized face normal cache (used when `vert_positions` is set.
* Access via #BKE_editmesh_cache_ensure_face_normals instead of directly.
*/
Array<float3> face_normals; Array<float3> face_normals;
/** also lazy init but don't depend on \a vert_positions */ /**
* Cache of face centers, also depends on `vert_positions` when it is not empty.
* Access via #BKE_editmesh_cache_ensure_face_centers instead of directly.
*/
Array<float3> face_centers; Array<float3> face_centers;
}; };
} // namespace blender::bke } // namespace blender::bke
void BKE_editmesh_cache_ensure_face_normals(BMEditMesh &em, blender::bke::EditMeshData &emd); blender::Span<blender::float3> BKE_editmesh_cache_ensure_face_normals(
void BKE_editmesh_cache_ensure_vert_normals(BMEditMesh &em, blender::bke::EditMeshData &emd); BMEditMesh &em, blender::bke::EditMeshData &emd);
blender::Span<blender::float3> BKE_editmesh_cache_ensure_vert_normals(
BMEditMesh &em, blender::bke::EditMeshData &emd);
void BKE_editmesh_cache_ensure_face_centers(BMEditMesh &em, blender::bke::EditMeshData &emd); blender::Span<blender::float3> BKE_editmesh_cache_ensure_face_centers(
BMEditMesh &em, blender::bke::EditMeshData &emd);
std::optional<blender::Bounds<blender::float3>> BKE_editmesh_cache_calc_minmax( std::optional<blender::Bounds<blender::float3>> BKE_editmesh_cache_calc_minmax(
const BMEditMesh &em, const blender::bke::EditMeshData &emd); const BMEditMesh &em, const blender::bke::EditMeshData &emd);

View File

@ -14,6 +14,7 @@
#include "BLI_array_utils.hh" #include "BLI_array_utils.hh"
#include "BLI_color.hh" #include "BLI_color.hh"
#include "BLI_function_ref.hh" #include "BLI_function_ref.hh"
#include "BLI_implicit_sharing_ptr.hh"
#include "BLI_map.hh" #include "BLI_map.hh"
#include "BLI_math_matrix_types.hh" #include "BLI_math_matrix_types.hh"
#include "BLI_math_vector_types.hh" #include "BLI_math_vector_types.hh"
@ -244,20 +245,23 @@ class TreeNode : public ::GreasePencilLayerTreeNode {
/** /**
* \returns this node as a #Layer. * \returns this node as a #Layer.
*/ */
Layer &as_layer();
const Layer &as_layer() const; const Layer &as_layer() const;
Layer &as_layer();
/** /**
* \returns this node as a #LayerGroup. * \returns this node as a #LayerGroup.
*/ */
LayerGroup &as_group();
const LayerGroup &as_group() const; const LayerGroup &as_group() const;
LayerGroup &as_group();
/** /**
* \returns the parent layer group or nullptr for the root group. * \returns the parent layer group or nullptr for the root group.
*/ */
LayerGroup *parent_group() const; const LayerGroup *parent_group() const;
TreeNode *parent_node() const; LayerGroup *parent_group();
const TreeNode *parent_node() const;
TreeNode *parent_node();
/** /**
* \returns the number of non-null parents of the node. * \returns the number of non-null parents of the node.
@ -373,7 +377,8 @@ class Layer : public ::GreasePencilLayer {
/** /**
* \returns the parent #LayerGroup of this layer. * \returns the parent #LayerGroup of this layer.
*/ */
LayerGroup &parent_group() const; const LayerGroup &parent_group() const;
LayerGroup &parent_group();
/** /**
* \returns the frames mapping. * \returns the frames mapping.
@ -702,7 +707,8 @@ inline void TreeNode::set_selected(const bool selected)
} }
inline bool TreeNode::use_onion_skinning() const inline bool TreeNode::use_onion_skinning() const
{ {
return ((this->flag & GP_LAYER_TREE_NODE_USE_ONION_SKINNING) != 0); return ((this->flag & GP_LAYER_TREE_NODE_HIDE_ONION_SKINNING) == 0) &&
(!this->parent_group() || this->parent_group()->as_node().use_onion_skinning());
} }
inline bool TreeNode::use_masks() const inline bool TreeNode::use_masks() const
{ {
@ -748,7 +754,11 @@ inline bool Layer::is_empty() const
{ {
return (this->frames().is_empty()); return (this->frames().is_empty());
} }
inline LayerGroup &Layer::parent_group() const inline const LayerGroup &Layer::parent_group() const
{
return *this->as_node().parent_group();
}
inline LayerGroup &Layer::parent_group()
{ {
return *this->as_node().parent_group(); return *this->as_node().parent_group();
} }
@ -773,7 +783,11 @@ class GreasePencilRuntime {
class GreasePencilDrawingEditHints { class GreasePencilDrawingEditHints {
public: public:
std::optional<Array<float3>> positions; const greasepencil::Drawing *drawing_orig;
ImplicitSharingPtrAndData positions_data;
std::optional<Span<float3>> positions() const;
std::optional<MutableSpan<float3>> positions_for_write();
}; };
/** /**

View File

@ -83,7 +83,7 @@ bool BKE_linestyle_geometry_modifier_move(FreestyleLineStyle *linestyle,
void BKE_linestyle_modifier_list_color_ramps(FreestyleLineStyle *linestyle, ListBase *listbase); void BKE_linestyle_modifier_list_color_ramps(FreestyleLineStyle *linestyle, ListBase *listbase);
std::optional<std::string> BKE_linestyle_path_to_color_ramp(FreestyleLineStyle *linestyle, std::optional<std::string> BKE_linestyle_path_to_color_ramp(FreestyleLineStyle *linestyle,
struct ColorBand *color_ramp); const struct ColorBand *color_ramp);
bool BKE_linestyle_use_textures(FreestyleLineStyle *linestyle, bool use_shading_nodes); bool BKE_linestyle_use_textures(FreestyleLineStyle *linestyle, bool use_shading_nodes);

View File

@ -67,8 +67,8 @@ void BKE_mask_point_free(struct MaskSplinePoint *point);
void BKE_mask_layer_unique_name(struct Mask *mask, struct MaskLayer *masklay); void BKE_mask_layer_unique_name(struct Mask *mask, struct MaskLayer *masklay);
void BKE_mask_layer_rename(struct Mask *mask, void BKE_mask_layer_rename(struct Mask *mask,
struct MaskLayer *masklay, struct MaskLayer *masklay,
char *oldname, const char *oldname,
char *newname); const char *newname);
struct MaskLayer *BKE_mask_layer_copy(const struct MaskLayer *masklay); struct MaskLayer *BKE_mask_layer_copy(const struct MaskLayer *masklay);
void BKE_mask_layer_copy_list(struct ListBase *masklayers_new, const struct ListBase *masklayers); void BKE_mask_layer_copy_list(struct ListBase *masklayers_new, const struct ListBase *masklayers);

View File

@ -494,9 +494,6 @@ bool BKE_mesh_validate_all_customdata(CustomData *vert_data,
void BKE_mesh_strip_loose_faces(Mesh *mesh); void BKE_mesh_strip_loose_faces(Mesh *mesh);
/* In DerivedMesh.cc */
void BKE_mesh_wrapper_deferred_finalize_mdata(Mesh *mesh_eval);
/* **** Depsgraph evaluation **** */ /* **** Depsgraph evaluation **** */
void BKE_mesh_eval_geometry(Depsgraph *depsgraph, Mesh *mesh); void BKE_mesh_eval_geometry(Depsgraph *depsgraph, Mesh *mesh);

View File

@ -163,11 +163,6 @@ struct MeshRuntime {
/** #eMeshWrapperType and others. */ /** #eMeshWrapperType and others. */
eMeshWrapperType wrapper_type = ME_WRAPPER_TYPE_MDATA; eMeshWrapperType wrapper_type = ME_WRAPPER_TYPE_MDATA;
/**
* A type mask from wrapper_type,
* in case there are differences in finalizing logic between types.
*/
eMeshWrapperType wrapper_type_finalize = ME_WRAPPER_TYPE_MDATA;
/** /**
* Settings for lazily evaluating the subdivision on the CPU if needed. These are * Settings for lazily evaluating the subdivision on the CPU if needed. These are

View File

@ -87,7 +87,7 @@ void BKE_movieclip_build_proxy_frame(struct MovieClip *clip,
int clip_flag, int clip_flag,
struct MovieDistortion *distortion, struct MovieDistortion *distortion,
int cfra, int cfra,
int *build_sizes, const int *build_sizes,
int build_count, int build_count,
bool undistorted); bool undistorted);
@ -99,7 +99,7 @@ void BKE_movieclip_build_proxy_frame_for_ibuf(struct MovieClip *clip,
struct ImBuf *ibuf, struct ImBuf *ibuf,
struct MovieDistortion *distortion, struct MovieDistortion *distortion,
int cfra, int cfra,
int *build_sizes, const int *build_sizes,
int build_count, int build_count,
bool undistorted); bool undistorted);
bool BKE_movieclip_proxy_enabled(struct MovieClip *clip); bool BKE_movieclip_proxy_enabled(struct MovieClip *clip);

View File

@ -123,7 +123,7 @@ int BKE_packedfile_count_all(struct Main *bmain);
*/ */
enum ePF_FileCompare BKE_packedfile_compare_to_file(const char *ref_file_name, enum ePF_FileCompare BKE_packedfile_compare_to_file(const char *ref_file_name,
const char *filepath_rel, const char *filepath_rel,
struct PackedFile *pf); const struct PackedFile *pf);
/* Read. */ /* Read. */
@ -143,7 +143,7 @@ void BKE_packedfile_id_unpack(struct Main *bmain,
struct ReportList *reports, struct ReportList *reports,
enum ePF_FileStatus how); enum ePF_FileStatus how);
void BKE_packedfile_blend_write(struct BlendWriter *writer, struct PackedFile *pf); void BKE_packedfile_blend_write(struct BlendWriter *writer, const struct PackedFile *pf);
void BKE_packedfile_blend_read(struct BlendDataReader *reader, struct PackedFile **pf_p); void BKE_packedfile_blend_read(struct BlendDataReader *reader, struct PackedFile **pf_p);
#ifdef __cplusplus #ifdef __cplusplus

View File

@ -220,11 +220,8 @@ void BKE_subdiv_ccg_topology_counters(const SubdivCCG &subdiv_ccg,
int &r_num_loops); int &r_num_loops);
struct SubdivCCGNeighbors { struct SubdivCCGNeighbors {
SubdivCCGCoord *coords; blender::Array<SubdivCCGCoord, 256> coords;
int size;
int num_duplicates; int num_duplicates;
SubdivCCGCoord coords_fixed[256];
}; };
void BKE_subdiv_ccg_print_coord(const char *message, const SubdivCCGCoord &coord); void BKE_subdiv_ccg_print_coord(const char *message, const SubdivCCGCoord &coord);
@ -244,9 +241,6 @@ bool BKE_subdiv_ccg_check_coord_valid(const SubdivCCG &subdiv_ccg, const SubdivC
* element inside of every neighboring grid. */ * element inside of every neighboring grid. */
/* Get actual neighbors of the given coordinate. /* Get actual neighbors of the given coordinate.
*
* SubdivCCGNeighbors.neighbors must be freed if it is not equal to
* SubdivCCGNeighbors.fixed_neighbors.
* *
* If include_duplicates is true, vertices in other grids that match * If include_duplicates is true, vertices in other grids that match
* the current vertex are added at the end of the coords array. */ * the current vertex are added at the end of the coords array. */

View File

@ -65,7 +65,7 @@ void txt_clean_text(struct Text *text);
void txt_order_cursors(struct Text *text, bool reverse); void txt_order_cursors(struct Text *text, bool reverse);
int txt_find_string(struct Text *text, const char *findstr, int wrap, int match_case); int txt_find_string(struct Text *text, const char *findstr, int wrap, int match_case);
bool txt_has_sel(const struct Text *text); bool txt_has_sel(const struct Text *text);
int txt_get_span(struct TextLine *from, const struct TextLine *to); int txt_get_span(const struct TextLine *from, const struct TextLine *to);
void txt_move_up(struct Text *text, bool sel); void txt_move_up(struct Text *text, bool sel);
void txt_move_down(struct Text *text, bool sel); void txt_move_down(struct Text *text, bool sel);
void txt_move_left(struct Text *text, bool sel); void txt_move_left(struct Text *text, bool sel);

View File

@ -579,6 +579,7 @@ set(LIB
bf_shader_fx bf_shader_fx
bf_simulation bf_simulation
PRIVATE bf::extern::fmtlib PRIVATE bf::extern::fmtlib
PRIVATE bf::extern::xxhash
PRIVATE bf::intern::atomic PRIVATE bf::intern::atomic
# For `vfontdata_freetype.c`. # For `vfontdata_freetype.c`.
${FREETYPE_LIBRARIES} ${BROTLI_LIBRARIES} ${FREETYPE_LIBRARIES} ${BROTLI_LIBRARIES}

View File

@ -221,7 +221,8 @@ struct CCGSubSurf {
(void)0 (void)0
#define NormCopy(av, bv) \ #define NormCopy(av, bv) \
{ \ { \
float *_a = (float *)av, *_b = (float *)bv; \ float *_a = (float *)av; \
const float *_b = (const float *)bv; \
_a[0] = _b[0]; \ _a[0] = _b[0]; \
_a[1] = _b[1]; \ _a[1] = _b[1]; \
_a[2] = _b[2]; \ _a[2] = _b[2]; \
@ -229,7 +230,8 @@ struct CCGSubSurf {
(void)0 (void)0
#define NormAdd(av, bv) \ #define NormAdd(av, bv) \
{ \ { \
float *_a = (float *)av, *_b = (float *)bv; \ float *_a = (float *)av; \
const float *_b = (const float *)bv; \
_a[0] += _b[0]; \ _a[0] += _b[0]; \
_a[1] += _b[1]; \ _a[1] += _b[1]; \
_a[2] += _b[2]; \ _a[2] += _b[2]; \

View File

@ -70,12 +70,16 @@ static float *_face_getIFNoEdge(CCGFace *f,
static void _face_calcIFNo( static void _face_calcIFNo(
CCGFace *f, int lvl, int S, int x, int y, float no[3], int levels, int dataSize) CCGFace *f, int lvl, int S, int x, int y, float no[3], int levels, int dataSize)
{ {
float *a = static_cast<float *>(ccg_face_getIFCo(f, lvl, S, x + 0, y + 0, levels, dataSize)); const float *a = static_cast<float *>(
float *b = static_cast<float *>(ccg_face_getIFCo(f, lvl, S, x + 1, y + 0, levels, dataSize)); ccg_face_getIFCo(f, lvl, S, x + 0, y + 0, levels, dataSize));
float *c = static_cast<float *>(ccg_face_getIFCo(f, lvl, S, x + 1, y + 1, levels, dataSize)); const float *b = static_cast<float *>(
float *d = static_cast<float *>(ccg_face_getIFCo(f, lvl, S, x + 0, y + 1, levels, dataSize)); ccg_face_getIFCo(f, lvl, S, x + 1, y + 0, levels, dataSize));
float a_cX = c[0] - a[0], a_cY = c[1] - a[1], a_cZ = c[2] - a[2]; const float *c = static_cast<float *>(
float b_dX = d[0] - b[0], b_dY = d[1] - b[1], b_dZ = d[2] - b[2]; ccg_face_getIFCo(f, lvl, S, x + 1, y + 1, levels, dataSize));
const float *d = static_cast<float *>(
ccg_face_getIFCo(f, lvl, S, x + 0, y + 1, levels, dataSize));
const float a_cX = c[0] - a[0], a_cY = c[1] - a[1], a_cZ = c[2] - a[2];
const float b_dX = d[0] - b[0], b_dY = d[1] - b[1], b_dZ = d[2] - b[2];
no[0] = b_dY * a_cZ - b_dZ * a_cY; no[0] = b_dY * a_cZ - b_dZ * a_cY;
no[1] = b_dZ * a_cX - b_dX * a_cZ; no[1] = b_dZ * a_cX - b_dX * a_cZ;

View File

@ -89,8 +89,6 @@ using blender::bke::MeshComponent;
#endif #endif
static void mesh_init_origspace(Mesh *mesh); static void mesh_init_origspace(Mesh *mesh);
static void editbmesh_calc_modifier_final_normals(Mesh *mesh_final);
static void editbmesh_calc_modifier_final_normals_or_defer(Mesh *mesh_final);
/* -------------------------------------------------------------------- */ /* -------------------------------------------------------------------- */
@ -465,16 +463,6 @@ static void mesh_calc_finalize(const Mesh *mesh_input, Mesh *mesh_eval)
mesh_eval->runtime->edit_mesh = mesh_input->runtime->edit_mesh; mesh_eval->runtime->edit_mesh = mesh_input->runtime->edit_mesh;
} }
void BKE_mesh_wrapper_deferred_finalize_mdata(Mesh *mesh_eval)
{
if (mesh_eval->runtime->wrapper_type_finalize & (1 << ME_WRAPPER_TYPE_BMESH)) {
editbmesh_calc_modifier_final_normals(mesh_eval);
mesh_eval->runtime->wrapper_type_finalize = eMeshWrapperType(
mesh_eval->runtime->wrapper_type_finalize & ~(1 << ME_WRAPPER_TYPE_BMESH));
}
BLI_assert(mesh_eval->runtime->wrapper_type_finalize == 0);
}
/** /**
* Modifies the given mesh and geometry set. The mesh is not passed as part of the mesh component * Modifies the given mesh and geometry set. The mesh is not passed as part of the mesh component
* in the \a geometry_set input, it is only passed in \a input_mesh and returned in the return * in the \a geometry_set input, it is only passed in \a input_mesh and returned in the return
@ -1001,36 +989,6 @@ bool editbmesh_modifier_is_enabled(const Scene *scene,
return true; return true;
} }
static void editbmesh_calc_modifier_final_normals(Mesh *mesh_final)
{
switch (mesh_final->runtime->wrapper_type) {
case ME_WRAPPER_TYPE_SUBD:
case ME_WRAPPER_TYPE_MDATA:
break;
case ME_WRAPPER_TYPE_BMESH: {
BMEditMesh &em = *mesh_final->runtime->edit_mesh;
blender::bke::EditMeshData &emd = *mesh_final->runtime->edit_data;
if (!emd.vert_positions.is_empty()) {
BKE_editmesh_cache_ensure_vert_normals(em, emd);
BKE_editmesh_cache_ensure_face_normals(em, emd);
}
return;
}
}
}
static void editbmesh_calc_modifier_final_normals_or_defer(Mesh *mesh_final)
{
if (mesh_final->runtime->wrapper_type != ME_WRAPPER_TYPE_MDATA) {
/* Generated at draw time. */
mesh_final->runtime->wrapper_type_finalize = eMeshWrapperType(
1 << mesh_final->runtime->wrapper_type);
return;
}
editbmesh_calc_modifier_final_normals(mesh_final);
}
static MutableSpan<float3> mesh_wrapper_vert_coords_ensure_for_write(Mesh *mesh) static MutableSpan<float3> mesh_wrapper_vert_coords_ensure_for_write(Mesh *mesh)
{ {
switch (mesh->runtime->wrapper_type) { switch (mesh->runtime->wrapper_type) {
@ -1244,12 +1202,6 @@ static void editbmesh_calc_modifiers(Depsgraph *depsgraph,
BKE_id_free(nullptr, mesh_orco); BKE_id_free(nullptr, mesh_orco);
} }
/* Compute normals. */
editbmesh_calc_modifier_final_normals_or_defer(mesh_final);
if (mesh_cage && (mesh_cage != mesh_final)) {
editbmesh_calc_modifier_final_normals_or_defer(mesh_cage);
}
/* Return final mesh. */ /* Return final mesh. */
*r_final = mesh_final; *r_final = mesh_final;
if (r_cage) { if (r_cage) {

View File

@ -350,8 +350,8 @@ void action_group_colors_sync(bActionGroup *grp, const bActionGroup *ref_grp)
if (grp->customCol) { if (grp->customCol) {
if (grp->customCol > 0) { if (grp->customCol > 0) {
/* copy theme colors on-to group's custom color in case user tries to edit color */ /* copy theme colors on-to group's custom color in case user tries to edit color */
bTheme *btheme = static_cast<bTheme *>(U.themes.first); const bTheme *btheme = static_cast<const bTheme *>(U.themes.first);
ThemeWireColor *col_set = &btheme->tarm[(grp->customCol - 1)]; const ThemeWireColor *col_set = &btheme->tarm[(grp->customCol - 1)];
memcpy(&grp->cs, col_set, sizeof(ThemeWireColor)); memcpy(&grp->cs, col_set, sizeof(ThemeWireColor));
} }
@ -1779,6 +1779,9 @@ void what_does_obaction(Object *ob,
/* execute effects of Action on to workob (or its PoseChannels) */ /* execute effects of Action on to workob (or its PoseChannels) */
BKE_animsys_evaluate_animdata(&workob->id, &adt, anim_eval_context, ADT_RECALC_ANIM, false); BKE_animsys_evaluate_animdata(&workob->id, &adt, anim_eval_context, ADT_RECALC_ANIM, false);
/* Ensure stack memory set here isn't accessed later, relates to !118847. */
workob->adt = nullptr;
} }
/* Ensure stack memory set here isn't accessed later, see !118847. */ /* Ensure stack memory set here isn't accessed later, see !118847. */
workob->runtime = nullptr; workob->runtime = nullptr;

View File

@ -38,7 +38,7 @@ bAddon *BKE_addon_new()
return addon; return addon;
} }
bAddon *BKE_addon_find(ListBase *addon_list, const char *module) bAddon *BKE_addon_find(const ListBase *addon_list, const char *module)
{ {
return static_cast<bAddon *>(BLI_findstring(addon_list, module, offsetof(bAddon, module))); return static_cast<bAddon *>(BLI_findstring(addon_list, module, offsetof(bAddon, module)));
} }

View File

@ -2850,8 +2850,9 @@ static void nlastrip_evaluate_transition(const int evaluation_mode,
break; break;
} }
case STRIP_EVAL_NOBLEND: { case STRIP_EVAL_NOBLEND: {
BLI_assert( !"This case shouldn't occur. Transitions assumed to not reference other " BLI_assert_msg(false,
"transitions. "); "This case shouldn't occur. "
"Transitions assumed to not reference other transitions.");
break; break;
} }
} }

View File

@ -34,14 +34,14 @@ void pose_apply_restore_fcurves(bAction *action);
void pose_apply(Object *ob, void pose_apply(Object *ob,
bAction *action, bAction *action,
AnimationEvalContext *anim_eval_context, const AnimationEvalContext *anim_eval_context,
ActionApplier applier); ActionApplier applier);
} // namespace } // namespace
void BKE_pose_apply_action_selected_bones(Object *ob, void BKE_pose_apply_action_selected_bones(Object *ob,
bAction *action, bAction *action,
AnimationEvalContext *anim_eval_context) const AnimationEvalContext *anim_eval_context)
{ {
auto evaluate_and_apply = auto evaluate_and_apply =
[](PointerRNA *ptr, bAction *act, const AnimationEvalContext *anim_eval_context) { [](PointerRNA *ptr, bAction *act, const AnimationEvalContext *anim_eval_context) {
@ -53,7 +53,7 @@ void BKE_pose_apply_action_selected_bones(Object *ob,
void BKE_pose_apply_action_all_bones(Object *ob, void BKE_pose_apply_action_all_bones(Object *ob,
bAction *action, bAction *action,
AnimationEvalContext *anim_eval_context) const AnimationEvalContext *anim_eval_context)
{ {
PointerRNA pose_owner_ptr = RNA_id_pointer_create(&ob->id); PointerRNA pose_owner_ptr = RNA_id_pointer_create(&ob->id);
animsys_evaluate_action(&pose_owner_ptr, action, anim_eval_context, false); animsys_evaluate_action(&pose_owner_ptr, action, anim_eval_context, false);
@ -61,7 +61,7 @@ void BKE_pose_apply_action_all_bones(Object *ob,
void BKE_pose_apply_action_blend(Object *ob, void BKE_pose_apply_action_blend(Object *ob,
bAction *action, bAction *action,
AnimationEvalContext *anim_eval_context, const AnimationEvalContext *anim_eval_context,
const float blend_factor) const float blend_factor)
{ {
auto evaluate_and_blend = [blend_factor](PointerRNA *ptr, auto evaluate_and_blend = [blend_factor](PointerRNA *ptr,
@ -76,7 +76,7 @@ void BKE_pose_apply_action_blend(Object *ob,
namespace { namespace {
void pose_apply(Object *ob, void pose_apply(Object *ob,
bAction *action, bAction *action,
AnimationEvalContext *anim_eval_context, const AnimationEvalContext *anim_eval_context,
ActionApplier applier) ActionApplier applier)
{ {
bPose *pose = ob->pose; bPose *pose = ob->pose;

View File

@ -338,7 +338,7 @@ static int position_tail_on_spline(bSplineIKConstraint *ik_data,
} }
/* Calculate the intersection point using the secant root finding method */ /* Calculate the intersection point using the secant root finding method */
float x0 = 0.0f, x1 = 1.0f, x2 = 0.5f; float x0 = 0.0f, x1 = 1.0f;
float x0_point[3], x1_point[3], start_p[3]; float x0_point[3], x1_point[3], start_p[3];
float epsilon = max_fff(1.0f, len_v3(head_pos), len_v3(bp->vec)) * FLT_EPSILON; float epsilon = max_fff(1.0f, len_v3(head_pos), len_v3(bp->vec)) * FLT_EPSILON;
@ -364,7 +364,7 @@ static int position_tail_on_spline(bSplineIKConstraint *ik_data,
break; break;
} }
x2 = x1 - f_x1 * (x1 - x0) / (f_x1 - f_x0); const float x2 = x1 - f_x1 * (x1 - x0) / (f_x1 - f_x0);
x0 = x1; x0 = x1;
x1 = x2; x1 = x2;
} }

View File

@ -14,7 +14,6 @@
#include "BLI_endian_defines.h" #include "BLI_endian_defines.h"
#include "BLI_endian_switch.h" #include "BLI_endian_switch.h"
#include "BLI_hash_md5.hh"
#include "BLI_math_matrix_types.hh" #include "BLI_math_matrix_types.hh"
#include "BLI_path_util.h" #include "BLI_path_util.h"
@ -26,6 +25,7 @@
#include <fmt/format.h> #include <fmt/format.h>
#include <sstream> #include <sstream>
#include <xxhash.h>
#ifdef WITH_OPENVDB #ifdef WITH_OPENVDB
# include <openvdb/io/Stream.h> # include <openvdb/io/Stream.h>
@ -192,8 +192,7 @@ DictionaryValuePtr BlobWriteSharing::write_implicitly_shared(
std::shared_ptr<io::serialize::DictionaryValue> BlobWriteSharing::write_deduplicated( std::shared_ptr<io::serialize::DictionaryValue> BlobWriteSharing::write_deduplicated(
BlobWriter &writer, const void *data, const int64_t size_in_bytes) BlobWriter &writer, const void *data, const int64_t size_in_bytes)
{ {
SliceHash content_hash; const uint64_t content_hash = XXH3_64bits(data, size_in_bytes);
BLI_hash_md5_buffer(static_cast<const char *>(data), size_in_bytes, &content_hash);
const BlobSlice slice = slice_by_content_hash_.lookup_or_add_cb( const BlobSlice slice = slice_by_content_hash_.lookup_or_add_cb(
content_hash, [&]() { return writer.write(data, size_in_bytes); }); content_hash, [&]() { return writer.write(data, size_in_bytes); });
return slice.serialize(); return slice.serialize();

View File

@ -182,7 +182,7 @@ static BlendHandle *link_append_context_library_blohandle_ensure(
lib_context->bf_reports.reports = reports; lib_context->bf_reports.reports = reports;
} }
char *libname = lib_context->path; const char *libname = lib_context->path;
BlendHandle *blo_handle = lib_context->blo_handle; BlendHandle *blo_handle = lib_context->blo_handle;
if (blo_handle == nullptr) { if (blo_handle == nullptr) {
if (STREQ(libname, BLO_EMBEDDED_STARTUP_BLEND)) { if (STREQ(libname, BLO_EMBEDDED_STARTUP_BLEND)) {
@ -1410,7 +1410,7 @@ void BKE_blendfile_link(BlendfileLinkAppendContext *lapp_context, ReportList *re
{ {
BlendfileLinkAppendContextLibrary *lib_context = BlendfileLinkAppendContextLibrary *lib_context =
static_cast<BlendfileLinkAppendContextLibrary *>(liblink->link); static_cast<BlendfileLinkAppendContextLibrary *>(liblink->link);
char *libname = lib_context->path; const char *libname = lib_context->path;
BlendHandle *blo_handle = link_append_context_library_blohandle_ensure( BlendHandle *blo_handle = link_append_context_library_blohandle_ensure(
lapp_context, lib_context, reports); lapp_context, lib_context, reports);

View File

@ -1359,8 +1359,6 @@ bool BKE_collection_object_add_notest(Main *bmain, Collection *collection, Objec
return false; return false;
} }
const int id_create_flag = (collection->id.tag & LIB_TAG_NO_MAIN) ? LIB_ID_CREATE_NO_MAIN : 0;
/* Only case where this pointer can be nullptr is when scene itself is linked, this case should /* Only case where this pointer can be nullptr is when scene itself is linked, this case should
* never be reached. */ * never be reached. */
BLI_assert(collection != nullptr); BLI_assert(collection != nullptr);
@ -1368,6 +1366,7 @@ bool BKE_collection_object_add_notest(Main *bmain, Collection *collection, Objec
return false; return false;
} }
const int id_create_flag = (collection->id.tag & LIB_TAG_NO_MAIN) ? LIB_ID_CREATE_NO_MAIN : 0;
if (!collection_object_add(bmain, collection, ob, nullptr, id_create_flag, true)) { if (!collection_object_add(bmain, collection, ob, nullptr, id_create_flag, true)) {
return false; return false;
} }

View File

@ -1659,6 +1659,64 @@ static bConstraintTypeInfo CTI_LOCLIMIT = {
/* -------- Limit Rotation --------- */ /* -------- Limit Rotation --------- */
/**
* Wraps a number to be in [-PI, +PI].
*/
static inline float wrap_rad_angle(const float angle)
{
const float b = angle * (0.5 / M_PI) + 0.5;
return ((b - std::floor(b)) - 0.5) * (2.0 * M_PI);
}
/**
* Clamps an angle between min and max.
*
* All angles are in radians.
*
* This function treats angles as existing in a looping (cyclic) space, and is therefore
* specifically not equivalent to a simple `clamp(angle, min, max)`. `min` and `max` are treated as
* a directed range on the unit circle and `angle` is treated as a point on the unit circle.
* `angle` is then clamped to be within the directed range defined by `min` and `max`.
*/
static float clamp_angle(const float angle, const float min, const float max)
{
/* If the allowed range exceeds 360 degrees no clamping can occur. */
if ((max - min) >= (2 * M_PI)) {
return angle;
}
/* Invalid case, just return min. */
if (max <= min) {
return min;
}
/* Move min and max into a space where `angle == 0.0`, and wrap them to
* [-PI, +PI] in that space. This simplifies the cases below, as we can
* just use 0.0 in place of `angle` and know that everything is in
* [-PI, +PI]. */
const float min_wrapped = wrap_rad_angle(min - angle);
const float max_wrapped = wrap_rad_angle(max - angle);
/* If the range defined by `min`/`max` doesn't contain the boundary at
* PI/-PI. This is the simple case, because it means we can do a simple
* clamp. */
if (min_wrapped < max_wrapped) {
return angle + std::clamp(0.0f, min_wrapped, max_wrapped);
}
/* At this point we know that `min_wrapped` >= `max_wrapped`, meaning the boundary is crossed.
* With that we know that no clamping is needed in the following case. */
if (max_wrapped >= 0.0 || min_wrapped <= 0.0) {
return angle;
}
/* If zero is outside of the range, we clamp to the closest of `min_wrapped` or `max_wrapped`. */
if (std::fabs(max_wrapped) < std::fabs(min_wrapped)) {
return angle + max_wrapped;
}
return angle + min_wrapped;
}
static void rotlimit_evaluate(bConstraint *con, bConstraintOb *cob, ListBase * /*targets*/) static void rotlimit_evaluate(bConstraint *con, bConstraintOb *cob, ListBase * /*targets*/)
{ {
bRotLimitConstraint *data = static_cast<bRotLimitConstraint *>(con->data); bRotLimitConstraint *data = static_cast<bRotLimitConstraint *>(con->data);
@ -1693,31 +1751,13 @@ static void rotlimit_evaluate(bConstraint *con, bConstraintOb *cob, ListBase * /
/* limiting of euler values... */ /* limiting of euler values... */
if (data->flag & LIMIT_XROT) { if (data->flag & LIMIT_XROT) {
if (eul[0] < data->xmin) { eul[0] = clamp_angle(eul[0], data->xmin, data->xmax);
eul[0] = data->xmin;
}
if (eul[0] > data->xmax) {
eul[0] = data->xmax;
}
} }
if (data->flag & LIMIT_YROT) { if (data->flag & LIMIT_YROT) {
if (eul[1] < data->ymin) { eul[1] = clamp_angle(eul[1], data->ymin, data->ymax);
eul[1] = data->ymin;
}
if (eul[1] > data->ymax) {
eul[1] = data->ymax;
}
} }
if (data->flag & LIMIT_ZROT) { if (data->flag & LIMIT_ZROT) {
if (eul[2] < data->zmin) { eul[2] = clamp_angle(eul[2], data->zmin, data->zmax);
eul[2] = data->zmin;
}
if (eul[2] > data->zmax) {
eul[2] = data->zmax;
}
} }
loc_eulO_size_to_mat4(cob->matrix, loc, eul, size, rot_order); loc_eulO_size_to_mat4(cob->matrix, loc, eul, size, rot_order);

View File

@ -599,9 +599,9 @@ GeometryDeformation get_evaluated_curves_deformation(const Object *ob_eval, cons
if (edit_component_eval != nullptr) { if (edit_component_eval != nullptr) {
const CurvesEditHints *edit_hints = edit_component_eval->curves_edit_hints_.get(); const CurvesEditHints *edit_hints = edit_component_eval->curves_edit_hints_.get();
if (edit_hints != nullptr && &edit_hints->curves_id_orig == &curves_id_orig) { if (edit_hints != nullptr && &edit_hints->curves_id_orig == &curves_id_orig) {
if (edit_hints->positions.has_value()) { if (const std::optional<Span<float3>> positions = edit_hints->positions()) {
BLI_assert(edit_hints->positions->size() == points_num); BLI_assert(positions->size() == points_num);
deformation.positions = *edit_hints->positions; deformation.positions = *positions;
uses_extra_positions = true; uses_extra_positions = true;
} }
if (edit_hints->deform_mats.has_value()) { if (edit_hints->deform_mats.has_value()) {
@ -677,8 +677,8 @@ GeometryDeformation get_evaluated_grease_pencil_drawing_deformation(const Object
BLI_assert(edit_hints->drawing_hints->size() == layers_orig.size()); BLI_assert(edit_hints->drawing_hints->size() == layers_orig.size());
const GreasePencilDrawingEditHints &drawing_hints = const GreasePencilDrawingEditHints &drawing_hints =
edit_hints->drawing_hints.value()[layer_index]; edit_hints->drawing_hints.value()[layer_index];
if (drawing_hints.positions.has_value()) { if (const std::optional<Span<float3>> positions = drawing_hints.positions()) {
deformation.positions = *drawing_hints.positions; deformation.positions = *positions;
return deformation; return deformation;
} }
} }

View File

@ -4750,7 +4750,6 @@ bool BKE_nurb_valid_message(const int pnts,
NURBSValidationStatus status = nurb_check_valid( NURBSValidationStatus status = nurb_check_valid(
pnts, order, flag, type, is_surf, &points_needed); pnts, order, flag, type, is_surf, &points_needed);
const char *msg_template = nullptr;
switch (status) { switch (status) {
case NURBSValidationStatus::Valid: case NURBSValidationStatus::Valid:
message_dst[0] = 0; message_dst[0] = 0;
@ -4761,20 +4760,24 @@ bool BKE_nurb_valid_message(const int pnts,
message_dst[0] = 0; message_dst[0] = 0;
return false; return false;
} }
msg_template = RPT_("At least two points required"); BLI_strncpy(message_dst, RPT_("At least two points required"), maxncpy);
break; break;
case NURBSValidationStatus::MorePointsThanOrderRequired: case NURBSValidationStatus::MorePointsThanOrderRequired:
msg_template = RPT_("Must have more control points than Order"); BLI_strncpy(message_dst, RPT_("Must have more control points than Order"), maxncpy);
break; break;
case NURBSValidationStatus::MoreRowsForBezierRequired: case NURBSValidationStatus::MoreRowsForBezierRequired:
msg_template = RPT_("%d more %s row(s) needed for Bézier"); BLI_snprintf(message_dst,
maxncpy,
RPT_("%d more %s row(s) needed for Bézier"),
points_needed,
dir == 0 ? "U" : "V");
break; break;
case NURBSValidationStatus::MorePointsForBezierRequired: case NURBSValidationStatus::MorePointsForBezierRequired:
msg_template = RPT_("%d more point(s) needed for Bézier"); BLI_snprintf(
message_dst, maxncpy, RPT_("%d more point(s) needed for Bézier"), points_needed);
break; break;
} }
BLI_snprintf(message_dst, maxncpy, msg_template, points_needed, dir == 0 ? "U" : "V");
return true; return true;
} }

View File

@ -333,8 +333,8 @@ CurvesSurfaceTransforms::CurvesSurfaceTransforms(const Object &curves_ob, const
bool CurvesEditHints::is_valid() const bool CurvesEditHints::is_valid() const
{ {
const int point_num = this->curves_id_orig.geometry.point_num; const int point_num = this->curves_id_orig.geometry.point_num;
if (this->positions.has_value()) { if (this->positions().has_value()) {
if (this->positions->size() != point_num) { if (this->positions()->size() != point_num) {
return false; return false;
} }
} }
@ -346,6 +346,35 @@ bool CurvesEditHints::is_valid() const
return true; return true;
} }
std::optional<Span<float3>> CurvesEditHints::positions() const
{
if (!this->positions_data.has_value()) {
return std::nullopt;
}
const int points_num = this->curves_id_orig.geometry.wrap().points_num();
return Span(static_cast<const float3 *>(this->positions_data.data), points_num);
}
std::optional<MutableSpan<float3>> CurvesEditHints::positions_for_write()
{
if (!this->positions_data.has_value()) {
return std::nullopt;
}
const int points_num = this->curves_id_orig.geometry.wrap().points_num();
ImplicitSharingPtrAndData &data = this->positions_data;
if (data.sharing_info->is_mutable()) {
data.sharing_info->tag_ensured_mutable();
}
else {
auto *new_sharing_info = new ImplicitSharedValue<Array<float3>>(*this->positions());
data.sharing_info = ImplicitSharingPtr<ImplicitSharingInfo>(new_sharing_info);
data.data = new_sharing_info->data.data();
}
return MutableSpan(const_cast<float3 *>(static_cast<const float3 *>(data.data)), points_num);
}
void curves_normals_point_domain_calc(const CurvesGeometry &curves, MutableSpan<float3> normals) void curves_normals_point_domain_calc(const CurvesGeometry &curves, MutableSpan<float3> normals)
{ {
const bke::CurvesFieldContext context(curves, AttrDomain::Point); const bke::CurvesFieldContext context(curves, AttrDomain::Point);

View File

@ -1754,8 +1754,8 @@ static const LayerTypeInfo LAYERTYPEINFO[CD_NUMTYPES] = {
nullptr, nullptr,
nullptr}, nullptr},
/* 18: CD_TANGENT */ /* 18: CD_TANGENT */
{sizeof(float[4][4]), {sizeof(float[4]),
alignof(float[4][4]), alignof(float[4]),
"", "",
0, 0,
N_("Tangent"), N_("Tangent"),

View File

@ -17,14 +17,18 @@
#include "BKE_editmesh.hh" #include "BKE_editmesh.hh"
#include "BKE_editmesh_cache.hh" /* own include */ #include "BKE_editmesh_cache.hh" /* own include */
using blender::float3;
using blender::Span;
/* -------------------------------------------------------------------- */ /* -------------------------------------------------------------------- */
/** \name Ensure Data (derived from coords) /** \name Ensure Data (derived from coords)
* \{ */ * \{ */
void BKE_editmesh_cache_ensure_face_normals(BMEditMesh &em, blender::bke::EditMeshData &emd) Span<float3> BKE_editmesh_cache_ensure_face_normals(BMEditMesh &em,
blender::bke::EditMeshData &emd)
{ {
if (emd.vert_positions.is_empty() || !emd.face_normals.is_empty()) { if (emd.vert_positions.is_empty() || !emd.face_normals.is_empty()) {
return; return emd.face_normals;
} }
BMesh *bm = em.bm; BMesh *bm = em.bm;
@ -36,37 +40,35 @@ void BKE_editmesh_cache_ensure_face_normals(BMEditMesh &em, blender::bke::EditMe
int i; int i;
BM_ITER_MESH_INDEX (efa, &fiter, bm, BM_FACES_OF_MESH, i) { BM_ITER_MESH_INDEX (efa, &fiter, bm, BM_FACES_OF_MESH, i) {
BM_elem_index_set(efa, i); /* set_inline */ BM_elem_index_set(efa, i); /* set_inline */
BM_face_calc_normal_vcos(bm, BM_face_calc_normal_vcos(bm, efa, emd.face_normals[i], emd.vert_positions);
efa,
emd.face_normals[i],
reinterpret_cast<const float(*)[3]>(emd.vert_positions.data()));
} }
bm->elem_index_dirty &= ~BM_FACE; bm->elem_index_dirty &= ~BM_FACE;
return emd.face_normals;
} }
void BKE_editmesh_cache_ensure_vert_normals(BMEditMesh &em, blender::bke::EditMeshData &emd) Span<float3> BKE_editmesh_cache_ensure_vert_normals(BMEditMesh &em,
blender::bke::EditMeshData &emd)
{ {
if (emd.vert_positions.is_empty() || !emd.vert_normals.is_empty()) { if (emd.vert_positions.is_empty() || !emd.vert_normals.is_empty()) {
return; return emd.vert_normals;
} }
BMesh *bm = em.bm; BMesh *bm = em.bm;
/* Calculate vertex normals from face normals. */ /* Calculate vertex normals from face normals. */
BKE_editmesh_cache_ensure_face_normals(em, emd); const Span<float3> face_normals = BKE_editmesh_cache_ensure_face_normals(em, emd);
emd.vert_normals.reinitialize(bm->totvert); emd.vert_normals.reinitialize(bm->totvert);
BM_mesh_elem_index_ensure(bm, BM_FACE); BM_mesh_elem_index_ensure(bm, BM_FACE);
BM_verts_calc_normal_vcos(bm, BM_verts_calc_normal_vcos(bm, face_normals, emd.vert_positions, emd.vert_normals);
reinterpret_cast<const float(*)[3]>(emd.face_normals.data()), return emd.vert_normals;
reinterpret_cast<const float(*)[3]>(emd.vert_positions.data()),
reinterpret_cast<float(*)[3]>(emd.vert_normals.data()));
} }
void BKE_editmesh_cache_ensure_face_centers(BMEditMesh &em, blender::bke::EditMeshData &emd) Span<float3> BKE_editmesh_cache_ensure_face_centers(BMEditMesh &em,
blender::bke::EditMeshData &emd)
{ {
if (!emd.face_centers.is_empty()) { if (!emd.face_centers.is_empty()) {
return; return emd.face_centers;
} }
BMesh *bm = em.bm; BMesh *bm = em.bm;
@ -86,6 +88,7 @@ void BKE_editmesh_cache_ensure_face_centers(BMEditMesh &em, blender::bke::EditMe
BM_face_calc_center_median_vcos(bm, efa, emd.face_centers[i], emd.vert_positions); BM_face_calc_center_median_vcos(bm, efa, emd.face_centers[i], emd.vert_positions);
} }
} }
return emd.face_centers;
} }
/** \} */ /** \} */

View File

@ -700,9 +700,9 @@ bool get_effector_data(EffectorCache *eff,
else if (eff->pd && eff->pd->shape == PFIELD_SHAPE_POINTS) { else if (eff->pd && eff->pd->shape == PFIELD_SHAPE_POINTS) {
/* TODO: hair and points object support */ /* TODO: hair and points object support */
const Mesh *mesh_eval = BKE_object_get_evaluated_mesh(eff->ob); const Mesh *mesh_eval = BKE_object_get_evaluated_mesh(eff->ob);
const blender::Span<blender::float3> positions = mesh_eval->vert_positions();
const blender::Span<blender::float3> vert_normals = mesh_eval->vert_normals();
if (mesh_eval != nullptr) { if (mesh_eval != nullptr) {
const blender::Span<blender::float3> positions = mesh_eval->vert_positions();
const blender::Span<blender::float3> vert_normals = mesh_eval->vert_normals();
copy_v3_v3(efd->loc, positions[*efd->index]); copy_v3_v3(efd->loc, positions[*efd->index]);
copy_v3_v3(efd->nor, vert_normals[*efd->index]); copy_v3_v3(efd->nor, vert_normals[*efd->index]);

View File

@ -40,25 +40,37 @@ void GeometryComponentEditData::clear()
grease_pencil_edit_hints_.reset(); grease_pencil_edit_hints_.reset();
} }
static ImplicitSharingPtrAndData save_shared_attribute(const GAttributeReader &attribute)
{
if (attribute.sharing_info && attribute.varray.is_span()) {
const void *data = attribute.varray.get_internal_span().data();
attribute.sharing_info->add_user();
return {ImplicitSharingPtr(attribute.sharing_info), data};
}
auto *data = new ImplicitSharedValue<GArray<>>(attribute.varray.type(), attribute.varray.size());
attribute.varray.materialize(data->data.data());
return {ImplicitSharingPtr<ImplicitSharingInfo>(data), data->data.data()};
}
static void remember_deformed_curve_positions_if_necessary( static void remember_deformed_curve_positions_if_necessary(
const Curves *curves_id, GeometryComponentEditData &edit_component) const Curves *curves_id, GeometryComponentEditData &edit_component)
{ {
if (!edit_component.curves_edit_hints_) { if (!edit_component.curves_edit_hints_) {
return; return;
} }
if (edit_component.curves_edit_hints_->positions.has_value()) { if (curves_id == nullptr) {
return; return;
} }
if (curves_id == nullptr) { CurvesEditHints &edit_hints = *edit_component.curves_edit_hints_;
if (edit_hints.positions().has_value()) {
return; return;
} }
const CurvesGeometry &curves = curves_id->geometry.wrap(); const CurvesGeometry &curves = curves_id->geometry.wrap();
const int points_num = curves.points_num(); const int points_num = curves.points_num();
if (points_num != edit_component.curves_edit_hints_->curves_id_orig.geometry.point_num) { if (points_num != edit_hints.curves_id_orig.geometry.point_num) {
return; return;
} }
edit_component.curves_edit_hints_->positions.emplace(points_num); edit_hints.positions_data = save_shared_attribute(curves.attributes().lookup("position"));
edit_component.curves_edit_hints_->positions->as_mutable_span().copy_from(curves.positions());
} }
static void remember_deformed_grease_pencil_if_necessary(const GreasePencil *grease_pencil, static void remember_deformed_grease_pencil_if_necessary(const GreasePencil *grease_pencil,
@ -91,14 +103,15 @@ static void remember_deformed_grease_pencil_if_necessary(const GreasePencil *gre
const greasepencil::Drawing *orig_drawing = orig_grease_pencil.get_drawing_at( const greasepencil::Drawing *orig_drawing = orig_grease_pencil.get_drawing_at(
orig_layer, grease_pencil->runtime->eval_frame); orig_layer, grease_pencil->runtime->eval_frame);
GreasePencilDrawingEditHints &drawing_hints = all_hints[layer_index]; GreasePencilDrawingEditHints &drawing_hints = all_hints[layer_index];
if (!drawing || !orig_drawing) { if (!drawing || !orig_drawing) {
continue; continue;
} }
if (drawing->strokes().points_num() != orig_drawing->strokes().points_num()) { drawing_hints.drawing_orig = orig_drawing;
const CurvesGeometry &curves = drawing->strokes();
if (curves.points_num() != orig_drawing->strokes().points_num()) {
continue; continue;
} }
drawing_hints.positions.emplace(drawing->strokes().positions()); drawing_hints.positions_data = save_shared_attribute(curves.attributes().lookup("position"));
} }
} }

View File

@ -1028,7 +1028,7 @@ void BKE_gpencil_stroke_copy_settings(const bGPDstroke *gps_src, bGPDstroke *gps
copy_v2_v2_short(gps_dst->caps, gps_src->caps); copy_v2_v2_short(gps_dst->caps, gps_src->caps);
gps_dst->hardness = gps_src->hardness; gps_dst->hardness = gps_src->hardness;
copy_v2_v2(gps_dst->aspect_ratio, gps_src->aspect_ratio); copy_v2_v2(gps_dst->aspect_ratio, gps_src->aspect_ratio);
gps_dst->fill_opacity_fac = gps_dst->fill_opacity_fac; gps_dst->fill_opacity_fac = gps_src->fill_opacity_fac;
copy_v3_v3(gps_dst->boundbox_min, gps_src->boundbox_min); copy_v3_v3(gps_dst->boundbox_min, gps_src->boundbox_min);
copy_v3_v3(gps_dst->boundbox_max, gps_src->boundbox_max); copy_v3_v3(gps_dst->boundbox_max, gps_src->boundbox_max);
gps_dst->uv_rotation = gps_src->uv_rotation; gps_dst->uv_rotation = gps_src->uv_rotation;

View File

@ -42,6 +42,7 @@
#include "BLI_string.h" #include "BLI_string.h"
#include "BLI_string_ref.hh" #include "BLI_string_ref.hh"
#include "BLI_string_utils.hh" #include "BLI_string_utils.hh"
#include "BLI_utildefines.h"
#include "BLI_vector_set.hh" #include "BLI_vector_set.hh"
#include "BLI_virtual_array.hh" #include "BLI_virtual_array.hh"
@ -52,6 +53,7 @@
#include "DNA_ID.h" #include "DNA_ID.h"
#include "DNA_ID_enums.h" #include "DNA_ID_enums.h"
#include "DNA_brush_types.h" #include "DNA_brush_types.h"
#include "DNA_defaults.h"
#include "DNA_gpencil_modifier_types.h" #include "DNA_gpencil_modifier_types.h"
#include "DNA_grease_pencil_types.h" #include "DNA_grease_pencil_types.h"
#include "DNA_material_types.h" #include "DNA_material_types.h"
@ -80,10 +82,12 @@ static void grease_pencil_init_data(ID *id)
using namespace blender::bke; using namespace blender::bke;
GreasePencil *grease_pencil = reinterpret_cast<GreasePencil *>(id); GreasePencil *grease_pencil = reinterpret_cast<GreasePencil *>(id);
BLI_assert(MEMCMP_STRUCT_AFTER_IS_ZERO(grease_pencil, id));
MEMCPY_STRUCT_AFTER(grease_pencil, DNA_struct_default_get(GreasePencil), id);
grease_pencil->root_group_ptr = MEM_new<greasepencil::LayerGroup>(__func__); grease_pencil->root_group_ptr = MEM_new<greasepencil::LayerGroup>(__func__);
grease_pencil->active_layer = nullptr; grease_pencil->active_layer = nullptr;
grease_pencil->flag |= GREASE_PENCIL_ANIM_CHANNEL_EXPANDED;
CustomData_reset(&grease_pencil->layers_data); CustomData_reset(&grease_pencil->layers_data);
@ -578,7 +582,7 @@ void Drawing::set_texture_matrices(Span<float4x2> matrices, const IndexMask &sel
const float4x2 texspace = matrices[pos]; const float4x2 texspace = matrices[pos];
/* We do the computation using doubles to avoid numerical precision errors. */ /* We do the computation using doubles to avoid numerical precision errors. */
double4x3 strokemat4x3 = double4x3(expand_4x2_mat(strokemat)); const double4x3 strokemat4x3 = double4x3(expand_4x2_mat(strokemat));
/* /*
* We want to solve for `texture_matrix` in the equation: `texspace = texture_matrix * * We want to solve for `texture_matrix` in the equation: `texspace = texture_matrix *
@ -766,7 +770,7 @@ TreeNode::TreeNode()
this->parent = nullptr; this->parent = nullptr;
this->GreasePencilLayerTreeNode::name = nullptr; this->GreasePencilLayerTreeNode::name = nullptr;
this->flag = GP_LAYER_TREE_NODE_HIDE_MASKS; this->flag = 0;
this->color[0] = this->color[1] = this->color[2] = 0; this->color[0] = this->color[1] = this->color[2] = 0;
} }
@ -819,12 +823,19 @@ Layer &TreeNode::as_layer()
return *reinterpret_cast<Layer *>(this); return *reinterpret_cast<Layer *>(this);
} }
LayerGroup *TreeNode::parent_group() const const LayerGroup *TreeNode::parent_group() const
{ {
return (this->parent) ? &this->parent->wrap() : nullptr; return (this->parent) ? &this->parent->wrap() : nullptr;
} }
LayerGroup *TreeNode::parent_group()
TreeNode *TreeNode::parent_node() const {
return (this->parent) ? &this->parent->wrap() : nullptr;
}
const TreeNode *TreeNode::parent_node() const
{
return this->parent_group() ? &this->parent->wrap().as_node() : nullptr;
}
TreeNode *TreeNode::parent_node()
{ {
return this->parent_group() ? &this->parent->wrap().as_node() : nullptr; return this->parent_group() ? &this->parent->wrap().as_node() : nullptr;
} }
@ -928,7 +939,7 @@ Layer::Layer(const Layer &other) : Layer()
/* Note: We do not duplicate the frame storage since it is only needed for writing to file. */ /* Note: We do not duplicate the frame storage since it is only needed for writing to file. */
this->runtime->frames_ = other.runtime->frames_; this->runtime->frames_ = other.runtime->frames_;
this->runtime->sorted_keys_cache_ = other.runtime->sorted_keys_cache_; this->runtime->sorted_keys_cache_ = other.runtime->sorted_keys_cache_;
/* Tag the frames map, so the frame storage is recreated once the DNA is saved.*/ /* Tag the frames map, so the frame storage is recreated once the DNA is saved. */
this->tag_frames_map_changed(); this->tag_frames_map_changed();
/* TODO: what about masks cache? */ /* TODO: what about masks cache? */
@ -1570,6 +1581,40 @@ void LayerGroup::update_from_dna_read()
} // namespace blender::bke::greasepencil } // namespace blender::bke::greasepencil
namespace blender::bke {
std::optional<Span<float3>> GreasePencilDrawingEditHints::positions() const
{
if (!this->positions_data.has_value()) {
return std::nullopt;
}
const int points_num = this->drawing_orig->geometry.wrap().points_num();
return Span(static_cast<const float3 *>(this->positions_data.data), points_num);
}
std::optional<MutableSpan<float3>> GreasePencilDrawingEditHints::positions_for_write()
{
if (!this->positions_data.has_value()) {
return std::nullopt;
}
const int points_num = this->drawing_orig->geometry.wrap().points_num();
ImplicitSharingPtrAndData &data = this->positions_data;
if (data.sharing_info->is_mutable()) {
/* If the referenced component is already mutable, return it directly. */
data.sharing_info->tag_ensured_mutable();
}
else {
auto *new_sharing_info = new ImplicitSharedValue<Array<float3>>(*this->positions());
data.sharing_info = ImplicitSharingPtr<ImplicitSharingInfo>(new_sharing_info);
data.data = new_sharing_info->data.data();
}
return MutableSpan(const_cast<float3 *>(static_cast<const float3 *>(data.data)), points_num);
}
} // namespace blender::bke
/* ------------------------------------------------------------------- */ /* ------------------------------------------------------------------- */
/** \name Grease Pencil kernel functions /** \name Grease Pencil kernel functions
* \{ */ * \{ */

View File

@ -172,6 +172,10 @@ static void find_used_vertex_groups(const bGPDframe &gpf,
Span<MDeformVert> dverts = {gps->dvert, gps->totpoints}; Span<MDeformVert> dverts = {gps->dvert, gps->totpoints};
for (const MDeformVert &dvert : dverts) { for (const MDeformVert &dvert : dverts) {
for (const MDeformWeight &weight : Span<MDeformWeight>{dvert.dw, dvert.totweight}) { for (const MDeformWeight &weight : Span<MDeformWeight>{dvert.dw, dvert.totweight}) {
if (weight.def_nr >= dvert.totweight) {
/* Ignore invalid deform weight group indices. */
continue;
}
is_group_used[weight.def_nr] = true; is_group_used[weight.def_nr] = true;
} }
} }
@ -362,6 +366,10 @@ void legacy_gpencil_frame_to_grease_pencil_drawing(const bGPDframe &gpf,
dst_dvert.dw = static_cast<MDeformWeight *>(MEM_dupallocN(src_dvert.dw)); dst_dvert.dw = static_cast<MDeformWeight *>(MEM_dupallocN(src_dvert.dw));
const MutableSpan<MDeformWeight> vertex_weights = {dst_dvert.dw, dst_dvert.totweight}; const MutableSpan<MDeformWeight> vertex_weights = {dst_dvert.dw, dst_dvert.totweight};
for (MDeformWeight &weight : vertex_weights) { for (MDeformWeight &weight : vertex_weights) {
if (weight.def_nr >= dst_dvert.totweight) {
/* Ignore invalid deform weight group indices. */
continue;
}
/* Map def_nr to the reduced vertex group list. */ /* Map def_nr to the reduced vertex group list. */
weight.def_nr = stroke_def_nr_map[weight.def_nr]; weight.def_nr = stroke_def_nr_map[weight.def_nr];
} }
@ -403,7 +411,11 @@ void legacy_gpencil_frame_to_grease_pencil_drawing(const bGPDframe &gpf,
SpanAttributeWriter<float> stroke_point_aspect_ratios = SpanAttributeWriter<float> stroke_point_aspect_ratios =
attributes.lookup_or_add_for_write_span<float>("aspect_ratio", AttrDomain::Curve); attributes.lookup_or_add_for_write_span<float>("aspect_ratio", AttrDomain::Curve);
SpanAttributeWriter<ColorGeometry4f> stroke_fill_colors = SpanAttributeWriter<ColorGeometry4f> stroke_fill_colors =
attributes.lookup_or_add_for_write_span<ColorGeometry4f>("fill_color", AttrDomain::Curve); attributes.lookup_or_add_for_write_span<ColorGeometry4f>(
"fill_color",
AttrDomain::Curve,
bke::AttributeInitVArray(VArray<ColorGeometry4f>::ForSingle(
ColorGeometry4f(float4(0.0f)), curves.curves_num())));
SpanAttributeWriter<int> stroke_materials = attributes.lookup_or_add_for_write_span<int>( SpanAttributeWriter<int> stroke_materials = attributes.lookup_or_add_for_write_span<int>(
"material_index", AttrDomain::Curve); "material_index", AttrDomain::Curve);
@ -573,8 +585,8 @@ void legacy_gpencil_to_grease_pencil(Main &bmain, GreasePencil &grease_pencil, b
SET_FLAG_FROM_TEST( SET_FLAG_FROM_TEST(
new_layer.base.flag, (gpl->flag & GP_LAYER_USE_LIGHTS), GP_LAYER_TREE_NODE_USE_LIGHTS); new_layer.base.flag, (gpl->flag & GP_LAYER_USE_LIGHTS), GP_LAYER_TREE_NODE_USE_LIGHTS);
SET_FLAG_FROM_TEST(new_layer.base.flag, SET_FLAG_FROM_TEST(new_layer.base.flag,
(gpl->onion_flag & GP_LAYER_ONIONSKIN), (gpl->onion_flag & GP_LAYER_ONIONSKIN) == 0,
GP_LAYER_TREE_NODE_USE_ONION_SKINNING); GP_LAYER_TREE_NODE_HIDE_ONION_SKINNING);
SET_FLAG_FROM_TEST( SET_FLAG_FROM_TEST(
new_layer.base.flag, (gpl->flag & GP_LAYER_USE_MASK) == 0, GP_LAYER_TREE_NODE_HIDE_MASKS); new_layer.base.flag, (gpl->flag & GP_LAYER_USE_MASK) == 0, GP_LAYER_TREE_NODE_HIDE_MASKS);
@ -638,18 +650,28 @@ void legacy_gpencil_to_grease_pencil(Main &bmain, GreasePencil &grease_pencil, b
grease_pencil.vertex_group_active_index = gpd.vertex_group_active_index; grease_pencil.vertex_group_active_index = gpd.vertex_group_active_index;
/* Convert the onion skinning settings. */ /* Convert the onion skinning settings. */
grease_pencil.onion_skinning_settings.opacity = gpd.onion_factor; GreasePencilOnionSkinningSettings &settings = grease_pencil.onion_skinning_settings;
grease_pencil.onion_skinning_settings.mode = gpd.onion_mode; settings.opacity = gpd.onion_factor;
settings.mode = gpd.onion_mode;
SET_FLAG_FROM_TEST(settings.flag,
((gpd.onion_flag & GP_ONION_GHOST_PREVCOL) != 0 &&
(gpd.onion_flag & GP_ONION_GHOST_NEXTCOL) != 0),
GP_ONION_SKINNING_USE_CUSTOM_COLORS);
SET_FLAG_FROM_TEST(
settings.flag, (gpd.onion_flag & GP_ONION_FADE) != 0, GP_ONION_SKINNING_USE_FADE);
SET_FLAG_FROM_TEST(
settings.flag, (gpd.onion_flag & GP_ONION_LOOP) != 0, GP_ONION_SKINNING_SHOW_LOOP);
/* Convert keytype filter to a bit flag. */
if (gpd.onion_keytype == -1) { if (gpd.onion_keytype == -1) {
grease_pencil.onion_skinning_settings.filter = GREASE_PENCIL_ONION_SKINNING_FILTER_ALL; settings.filter = GREASE_PENCIL_ONION_SKINNING_FILTER_ALL;
} }
else { else {
grease_pencil.onion_skinning_settings.filter = (1 << gpd.onion_keytype); settings.filter = (1 << gpd.onion_keytype);
} }
grease_pencil.onion_skinning_settings.num_frames_before = gpd.gstep; settings.num_frames_before = gpd.gstep;
grease_pencil.onion_skinning_settings.num_frames_after = gpd.gstep_next; settings.num_frames_after = gpd.gstep_next;
copy_v3_v3(grease_pencil.onion_skinning_settings.color_before, gpd.gcolor_prev); copy_v3_v3(settings.color_before, gpd.gcolor_prev);
copy_v3_v3(grease_pencil.onion_skinning_settings.color_after, gpd.gcolor_next); copy_v3_v3(settings.color_after, gpd.gcolor_next);
BKE_id_materials_copy(&bmain, &gpd.id, &grease_pencil.id); BKE_id_materials_copy(&bmain, &gpd.id, &grease_pencil.id);
@ -784,10 +806,10 @@ void layer_adjustments_to_modifiers(Main &bmain, bGPdata &src_object_data, Objec
* *
* NOTE: NLA animation in GPData that would control adjustment properties is not converted. This * NOTE: NLA animation in GPData that would control adjustment properties is not converted. This
* would require (partially) re-creating a copy of the potential bGPData NLA into the Object NLA, * would require (partially) re-creating a copy of the potential bGPData NLA into the Object NLA,
* which is too complex for the few potential usecases. * which is too complex for the few potential use cases.
* *
* This is achieved in several steps, roughly: * This is achieved in several steps, roughly:
* * For each GP layer, chack if there is animation on the adjutment data. * * For each GP layer, check if there is animation on the adjustment data.
* * Rename relevant FCurves RNA paths from GP animation data, and store their reference in * * Rename relevant FCurves RNA paths from GP animation data, and store their reference in
* temporary vectors. * temporary vectors.
* * Once all layers have been processed, move all affected FCurves from GPData animation to * * Once all layers have been processed, move all affected FCurves from GPData animation to
@ -838,7 +860,7 @@ void layer_adjustments_to_modifiers(Main &bmain, bGPdata &src_object_data, Objec
BLI_str_escape(layer_name_esc, gpl->info, sizeof(layer_name_esc)); BLI_str_escape(layer_name_esc, gpl->info, sizeof(layer_name_esc));
const std::string legacy_root_path = fmt::format("layers[\"{}\"]", layer_name_esc); const std::string legacy_root_path = fmt::format("layers[\"{}\"]", layer_name_esc);
/* If tint or thickness are animated, relevamt modifiers also need to be created. */ /* If tint or thickness are animated, relevant modifiers also need to be created. */
if (gpd_animdata) { if (gpd_animdata) {
auto adjustment_animation_detection = [&](bAction *owner_action, FCurve &fcurve) -> bool { auto adjustment_animation_detection = [&](bAction *owner_action, FCurve &fcurve) -> bool {
/* Early out if we already know that both data are animated. */ /* Early out if we already know that both data are animated. */

View File

@ -457,9 +457,7 @@ static ImageGPUTextures image_get_gpu_texture(Image *ima,
if (GPU_mipmap_enabled()) { if (GPU_mipmap_enabled()) {
GPU_texture_update_mipmap_chain(*tex); GPU_texture_update_mipmap_chain(*tex);
if (ima) { ima->gpuflag |= IMA_GPU_MIPMAP_COMPLETE;
ima->gpuflag |= IMA_GPU_MIPMAP_COMPLETE;
}
GPU_texture_mipmap_mode(*tex, true, true); GPU_texture_mipmap_mode(*tex, true, true);
} }
else { else {
@ -624,8 +622,8 @@ void BKE_image_free_old_gputextures(Main *bmain)
/** \name Paint Update /** \name Paint Update
* \{ */ * \{ */
static ImBuf *update_do_scale(uchar *rect, static ImBuf *update_do_scale(const uchar *rect,
float *rect_float, const float *rect_float,
int *x, int *x,
int *y, int *y,
int *w, int *w,
@ -664,8 +662,8 @@ static ImBuf *update_do_scale(uchar *rect,
} }
static void gpu_texture_update_scaled(GPUTexture *tex, static void gpu_texture_update_scaled(GPUTexture *tex,
uchar *rect, const uchar *rect,
float *rect_float, const float *rect_float,
int full_w, int full_w,
int full_h, int full_h,
int x, int x,

View File

@ -431,9 +431,7 @@ static void layer_aov_copy_data(ViewLayer *view_layer_dst,
ListBase *aovs_dst, ListBase *aovs_dst,
const ListBase *aovs_src) const ListBase *aovs_src)
{ {
if (aovs_src != nullptr) { BLI_duplicatelist(aovs_dst, aovs_src);
BLI_duplicatelist(aovs_dst, aovs_src);
}
ViewLayerAOV *aov_dst = static_cast<ViewLayerAOV *>(aovs_dst->first); ViewLayerAOV *aov_dst = static_cast<ViewLayerAOV *>(aovs_dst->first);
const ViewLayerAOV *aov_src = static_cast<const ViewLayerAOV *>(aovs_src->first); const ViewLayerAOV *aov_src = static_cast<const ViewLayerAOV *>(aovs_src->first);

View File

@ -287,5 +287,5 @@ int64_t BKE_lightprobe_grid_cache_frame_sample_count(const LightProbeGridCacheFr
return cache->block_len * cube_i(cache->block_size); return cache->block_len * cube_i(cache->block_size);
} }
/* LIGHTPROBE_CACHE_UNIFORM_GRID */ /* LIGHTPROBE_CACHE_UNIFORM_GRID */
return cache->size[0] * cache->size[1] * cache->size[2]; return int64_t(cache->size[0]) * cache->size[1] * cache->size[2];
} }

View File

@ -1852,7 +1852,7 @@ void BKE_linestyle_modifier_list_color_ramps(FreestyleLineStyle *linestyle, List
} }
std::optional<std::string> BKE_linestyle_path_to_color_ramp(FreestyleLineStyle *linestyle, std::optional<std::string> BKE_linestyle_path_to_color_ramp(FreestyleLineStyle *linestyle,
ColorBand *color_ramp) const ColorBand *color_ramp)
{ {
bool found = false; bool found = false;

View File

@ -340,7 +340,10 @@ void BKE_mask_layer_unique_name(Mask *mask, MaskLayer *masklay)
sizeof(masklay->name)); sizeof(masklay->name));
} }
void BKE_mask_layer_rename(Mask *mask, MaskLayer *masklay, char *oldname, char *newname) void BKE_mask_layer_rename(Mask *mask,
MaskLayer *masklay,
const char *oldname,
const char *newname)
{ {
STRNCPY(masklay->name, newname); STRNCPY(masklay->name, newname);

View File

@ -1158,6 +1158,19 @@ static void polygonize(PROCESS *process)
} }
} }
static bool object_has_zero_axis_matrix(const Object *bob)
{
if (has_zero_axis_m4(bob->object_to_world().ptr())) {
return true;
}
for (Object *pob = bob->parent; pob; pob = pob->parent) {
if (has_zero_axis_m4(pob->object_to_world().ptr())) {
return true;
}
}
return false;
}
/** /**
* Iterates over ALL objects in the scene and all of its sets, including * Iterates over ALL objects in the scene and all of its sets, including
* making all duplis (not only meta-elements). Copies meta-elements to #process.mainb array. * making all duplis (not only meta-elements). Copies meta-elements to #process.mainb array.
@ -1168,19 +1181,15 @@ static void init_meta(Depsgraph *depsgraph, PROCESS *process, Scene *scene, Obje
Scene *sce_iter = scene; Scene *sce_iter = scene;
Base *base; Base *base;
Object *bob; Object *bob;
MetaBall *mb; int obnr;
const MetaElem *ml;
float obinv[4][4], obmat[4][4];
uint i;
int obnr, zero_size = 0;
char obname[MAX_ID_NAME]; char obname[MAX_ID_NAME];
SceneBaseIter iter; SceneBaseIter iter;
const eEvaluationMode deg_eval_mode = DEG_get_mode(depsgraph); const eEvaluationMode deg_eval_mode = DEG_get_mode(depsgraph);
const short parenting_dupli_transflag = (OB_DUPLIFACES | OB_DUPLIVERTS); const short parenting_dupli_transflag = (OB_DUPLIFACES | OB_DUPLIVERTS);
copy_m4_m4( /* Copy object matrices to cope with duplicators from #BKE_scene_base_iter_next. */
obmat, float obinv[4][4], obmat[4][4];
ob->object_to_world().ptr()); /* to cope with duplicators from BKE_scene_base_iter_next */ copy_m4_m4(obmat, ob->object_to_world().ptr());
invert_m4_m4(obinv, ob->object_to_world().ptr()); invert_m4_m4(obinv, ob->object_to_world().ptr());
BLI_string_split_name_number(ob->id.name + 2, '.', obname, &obnr); BLI_string_split_name_number(ob->id.name + 2, '.', obname, &obnr);
@ -1188,187 +1197,154 @@ static void init_meta(Depsgraph *depsgraph, PROCESS *process, Scene *scene, Obje
/* make main array */ /* make main array */
BKE_scene_base_iter_next(depsgraph, &iter, &sce_iter, 0, nullptr, nullptr); BKE_scene_base_iter_next(depsgraph, &iter, &sce_iter, 0, nullptr, nullptr);
while (BKE_scene_base_iter_next(depsgraph, &iter, &sce_iter, 1, &base, &bob)) { while (BKE_scene_base_iter_next(depsgraph, &iter, &sce_iter, 1, &base, &bob)) {
if (bob->type == OB_MBALL) { if (bob->type != OB_MBALL) {
zero_size = 0; continue;
ml = nullptr; }
/* If this metaball is the original that's used for duplication, only have it visible when /* If this metaball is the original that's used for duplication, only have it visible when
* the instancer is visible too. */ * the instancer is visible too. */
if ((base->flag_legacy & OB_FROMDUPLI) == 0 && ob->parent != nullptr && if ((base->flag_legacy & OB_FROMDUPLI) == 0 && ob->parent != nullptr &&
(ob->parent->transflag & parenting_dupli_transflag) != 0 && (ob->parent->transflag & parenting_dupli_transflag) != 0 &&
(BKE_object_visibility(ob->parent, deg_eval_mode) & OB_VISIBLE_SELF) == 0) (BKE_object_visibility(ob->parent, deg_eval_mode) & OB_VISIBLE_SELF) == 0)
{ {
continue;
}
if (bob == ob && (base->flag_legacy & OB_FROMDUPLI) == 0) {
/* Pass. */
}
else {
char name[MAX_ID_NAME];
int nr;
BLI_string_split_name_number(bob->id.name + 2, '.', name, &nr);
if (!STREQ(obname, name)) {
/* Not part of the mother-ball, continue. */
continue; continue;
} }
}
if (bob == ob && (base->flag_legacy & OB_FROMDUPLI) == 0) { /* When metaball object has zero scale, then MetaElem to this MetaBall
mb = static_cast<MetaBall *>(ob->data); * will not be put to `mainb` array. */
if (object_has_zero_axis_matrix(bob)) {
continue;
}
if (mb->editelems) { const MetaBall *mb = static_cast<MetaBall *>(bob->data);
ml = static_cast<const MetaElem *>(mb->editelems->first); LISTBASE_FOREACH (const MetaElem *, ml, (mb->editelems ? mb->editelems : &mb->elems)) {
} if (ml->flag & MB_HIDE) {
else { continue;
ml = static_cast<const MetaElem *>(mb->elems.first); }
} float pos[4][4], rot[4][4];
float expx, expy, expz;
blender::float3 tempmin, tempmax;
/* make a copy because of duplicates */
MetaElem *new_ml = static_cast<MetaElem *>(
BLI_memarena_alloc(process->pgn_elements, sizeof(MetaElem)));
*(new_ml) = *ml;
new_ml->bb = static_cast<BoundBox *>(
BLI_memarena_alloc(process->pgn_elements, sizeof(BoundBox)));
new_ml->mat = static_cast<float *>(
BLI_memarena_alloc(process->pgn_elements, sizeof(float[4][4])));
new_ml->imat = static_cast<float *>(
BLI_memarena_alloc(process->pgn_elements, sizeof(float[4][4])));
/* too big stiffness seems only ugly due to linear interpolation
* no need to have possibility for too big stiffness */
if (ml->s > 10.0f) {
new_ml->s = 10.0f;
} }
else { else {
char name[MAX_ID_NAME]; new_ml->s = ml->s;
int nr;
BLI_string_split_name_number(bob->id.name + 2, '.', name, &nr);
if (STREQ(obname, name)) {
mb = static_cast<MetaBall *>(bob->data);
if (mb->editelems) {
ml = static_cast<const MetaElem *>(mb->editelems->first);
}
else {
ml = static_cast<const MetaElem *>(mb->elems.first);
}
}
} }
/* when metaball object has zero scale, then MetaElem to this MetaBall /* if metaball is negative, set stiffness negative */
* will not be put to mainb array */ if (new_ml->flag & MB_NEGATIVE) {
if (has_zero_axis_m4(bob->object_to_world().ptr())) { new_ml->s = -new_ml->s;
zero_size = 1;
}
else if (bob->parent) {
Object *pob = bob->parent;
while (pob) {
if (has_zero_axis_m4(pob->object_to_world().ptr())) {
zero_size = 1;
break;
}
pob = pob->parent;
}
} }
if (zero_size) { /* Translation of MetaElem */
while (ml) { unit_m4(pos);
ml = ml->next; pos[3][0] = ml->x;
} pos[3][1] = ml->y;
pos[3][2] = ml->z;
/* Rotation of MetaElem is stored in quat */
quat_to_mat4(rot, ml->quat);
/* Matrix multiply is as follows:
* basis object space ->
* world ->
* ml object space ->
* position ->
* rotation ->
* ml local space
*/
mul_m4_series((float(*)[4])new_ml->mat, obinv, bob->object_to_world().ptr(), pos, rot);
/* ml local space -> basis object space */
invert_m4_m4((float(*)[4])new_ml->imat, (float(*)[4])new_ml->mat);
/* rad2 is inverse of squared radius */
new_ml->rad2 = 1 / (ml->rad * ml->rad);
/* initial dimensions = radius */
expx = ml->rad;
expy = ml->rad;
expz = ml->rad;
switch (ml->type) {
case MB_BALL:
break;
case MB_CUBE: /* cube is "expanded" by expz, expy and expx */
expz += ml->expz;
ATTR_FALLTHROUGH;
case MB_PLANE: /* plane is "expanded" by expy and expx */
expy += ml->expy;
ATTR_FALLTHROUGH;
case MB_TUBE: /* tube is "expanded" by expx */
expx += ml->expx;
break;
case MB_ELIPSOID: /* ellipsoid is "stretched" by exp* */
expx *= ml->expx;
expy *= ml->expy;
expz *= ml->expz;
break;
} }
else {
while (ml) {
if (!(ml->flag & MB_HIDE)) {
float pos[4][4], rot[4][4];
float expx, expy, expz;
blender::float3 tempmin, tempmax;
MetaElem *new_ml; /* untransformed Bounding Box of MetaElem */
/* TODO: its possible the elem type has been changed and the exp*
* values can use a fallback. */
copy_v3_fl3(new_ml->bb->vec[0], -expx, -expy, -expz); /* 0 */
copy_v3_fl3(new_ml->bb->vec[1], +expx, -expy, -expz); /* 1 */
copy_v3_fl3(new_ml->bb->vec[2], +expx, +expy, -expz); /* 2 */
copy_v3_fl3(new_ml->bb->vec[3], -expx, +expy, -expz); /* 3 */
copy_v3_fl3(new_ml->bb->vec[4], -expx, -expy, +expz); /* 4 */
copy_v3_fl3(new_ml->bb->vec[5], +expx, -expy, +expz); /* 5 */
copy_v3_fl3(new_ml->bb->vec[6], +expx, +expy, +expz); /* 6 */
copy_v3_fl3(new_ml->bb->vec[7], -expx, +expy, +expz); /* 7 */
/* make a copy because of duplicates */ /* Transformation of meta-elem bounding-box. */
new_ml = static_cast<MetaElem *>( for (uint i = 0; i < 8; i++) {
BLI_memarena_alloc(process->pgn_elements, sizeof(MetaElem))); mul_m4_v3((float(*)[4])new_ml->mat, new_ml->bb->vec[i]);
*(new_ml) = *ml;
new_ml->bb = static_cast<BoundBox *>(
BLI_memarena_alloc(process->pgn_elements, sizeof(BoundBox)));
new_ml->mat = static_cast<float *>(
BLI_memarena_alloc(process->pgn_elements, sizeof(float[4][4])));
new_ml->imat = static_cast<float *>(
BLI_memarena_alloc(process->pgn_elements, sizeof(float[4][4])));
/* too big stiffness seems only ugly due to linear interpolation
* no need to have possibility for too big stiffness */
if (ml->s > 10.0f) {
new_ml->s = 10.0f;
}
else {
new_ml->s = ml->s;
}
/* if metaball is negative, set stiffness negative */
if (new_ml->flag & MB_NEGATIVE) {
new_ml->s = -new_ml->s;
}
/* Translation of MetaElem */
unit_m4(pos);
pos[3][0] = ml->x;
pos[3][1] = ml->y;
pos[3][2] = ml->z;
/* Rotation of MetaElem is stored in quat */
quat_to_mat4(rot, ml->quat);
/* Matrix multiply is as follows:
* basis object space ->
* world ->
* ml object space ->
* position ->
* rotation ->
* ml local space
*/
mul_m4_series((float(*)[4])new_ml->mat, obinv, bob->object_to_world().ptr(), pos, rot);
/* ml local space -> basis object space */
invert_m4_m4((float(*)[4])new_ml->imat, (float(*)[4])new_ml->mat);
/* rad2 is inverse of squared radius */
new_ml->rad2 = 1 / (ml->rad * ml->rad);
/* initial dimensions = radius */
expx = ml->rad;
expy = ml->rad;
expz = ml->rad;
switch (ml->type) {
case MB_BALL:
break;
case MB_CUBE: /* cube is "expanded" by expz, expy and expx */
expz += ml->expz;
ATTR_FALLTHROUGH;
case MB_PLANE: /* plane is "expanded" by expy and expx */
expy += ml->expy;
ATTR_FALLTHROUGH;
case MB_TUBE: /* tube is "expanded" by expx */
expx += ml->expx;
break;
case MB_ELIPSOID: /* ellipsoid is "stretched" by exp* */
expx *= ml->expx;
expy *= ml->expy;
expz *= ml->expz;
break;
}
/* untransformed Bounding Box of MetaElem */
/* TODO: its possible the elem type has been changed and the exp*
* values can use a fallback. */
copy_v3_fl3(new_ml->bb->vec[0], -expx, -expy, -expz); /* 0 */
copy_v3_fl3(new_ml->bb->vec[1], +expx, -expy, -expz); /* 1 */
copy_v3_fl3(new_ml->bb->vec[2], +expx, +expy, -expz); /* 2 */
copy_v3_fl3(new_ml->bb->vec[3], -expx, +expy, -expz); /* 3 */
copy_v3_fl3(new_ml->bb->vec[4], -expx, -expy, +expz); /* 4 */
copy_v3_fl3(new_ml->bb->vec[5], +expx, -expy, +expz); /* 5 */
copy_v3_fl3(new_ml->bb->vec[6], +expx, +expy, +expz); /* 6 */
copy_v3_fl3(new_ml->bb->vec[7], -expx, +expy, +expz); /* 7 */
/* Transformation of meta-elem bounding-box. */
for (i = 0; i < 8; i++) {
mul_m4_v3((float(*)[4])new_ml->mat, new_ml->bb->vec[i]);
}
/* Find max and min of transformed bounding-box. */
INIT_MINMAX(tempmin, tempmax);
for (i = 0; i < 8; i++) {
blender::math::min_max(blender::float3(new_ml->bb->vec[i]), tempmin, tempmax);
}
/* Set only point 0 and 6 - AABB of meta-elem. */
copy_v3_v3(new_ml->bb->vec[0], tempmin);
copy_v3_v3(new_ml->bb->vec[6], tempmax);
/* add new_ml to mainb[] */
if (UNLIKELY(process->totelem == process->mem)) {
process->mem = process->mem * 2 + 10;
process->mainb = static_cast<MetaElem **>(
MEM_reallocN(process->mainb, sizeof(MetaElem *) * process->mem));
}
process->mainb[process->totelem++] = new_ml;
}
ml = ml->next;
}
} }
/* Find max and min of transformed bounding-box. */
INIT_MINMAX(tempmin, tempmax);
for (uint i = 0; i < 8; i++) {
blender::math::min_max(blender::float3(new_ml->bb->vec[i]), tempmin, tempmax);
}
/* Set only point 0 and 6 - AABB of meta-elem. */
copy_v3_v3(new_ml->bb->vec[0], tempmin);
copy_v3_v3(new_ml->bb->vec[6], tempmax);
/* add new_ml to mainb[] */
if (UNLIKELY(process->totelem == process->mem)) {
process->mem = process->mem * 2 + 10;
process->mainb = static_cast<MetaElem **>(
MEM_reallocN(process->mainb, sizeof(MetaElem *) * process->mem));
}
process->mainb[process->totelem++] = new_ml;
} }
} }
@ -1376,7 +1352,7 @@ static void init_meta(Depsgraph *depsgraph, PROCESS *process, Scene *scene, Obje
if (process->totelem > 0) { if (process->totelem > 0) {
copy_v3_v3(process->allbb.min, process->mainb[0]->bb->vec[0]); copy_v3_v3(process->allbb.min, process->mainb[0]->bb->vec[0]);
copy_v3_v3(process->allbb.max, process->mainb[0]->bb->vec[6]); copy_v3_v3(process->allbb.max, process->mainb[0]->bb->vec[6]);
for (i = 1; i < process->totelem; i++) { for (uint i = 1; i < process->totelem; i++) {
make_box_union(process->mainb[i]->bb, &process->allbb, &process->allbb); make_box_union(process->mainb[i]->bb, &process->allbb, &process->allbb);
} }
} }

View File

@ -113,7 +113,6 @@ static void mesh_copy_data(Main *bmain,
mesh_dst->runtime = new blender::bke::MeshRuntime(); mesh_dst->runtime = new blender::bke::MeshRuntime();
mesh_dst->runtime->deformed_only = mesh_src->runtime->deformed_only; mesh_dst->runtime->deformed_only = mesh_src->runtime->deformed_only;
mesh_dst->runtime->wrapper_type = mesh_src->runtime->wrapper_type; mesh_dst->runtime->wrapper_type = mesh_src->runtime->wrapper_type;
mesh_dst->runtime->wrapper_type_finalize = mesh_src->runtime->wrapper_type_finalize;
mesh_dst->runtime->subsurf_runtime_data = mesh_src->runtime->subsurf_runtime_data; mesh_dst->runtime->subsurf_runtime_data = mesh_src->runtime->subsurf_runtime_data;
mesh_dst->runtime->cd_mask_extra = mesh_src->runtime->cd_mask_extra; mesh_dst->runtime->cd_mask_extra = mesh_src->runtime->cd_mask_extra;
/* Copy face dot tags and edge tags, since meshes may be duplicated after a subsurf modifier or /* Copy face dot tags and edge tags, since meshes may be duplicated after a subsurf modifier or

View File

@ -44,16 +44,16 @@ static void reserve_hash_maps(const Mesh &mesh,
edge_maps, [&](EdgeMap &edge_map) { edge_map.reserve(totedge_guess / edge_maps.size()); }); edge_maps, [&](EdgeMap &edge_map) { edge_map.reserve(totedge_guess / edge_maps.size()); });
} }
static void add_existing_edges_to_hash_maps(Mesh &mesh, static void add_existing_edges_to_hash_maps(const Mesh &mesh,
MutableSpan<EdgeMap> edge_maps, const uint32_t parallel_mask,
uint32_t parallel_mask) MutableSpan<EdgeMap> edge_maps)
{ {
/* Assume existing edges are valid. */ /* Assume existing edges are valid. */
const Span<int2> edges = mesh.edges(); const Span<int2> edges = mesh.edges();
threading::parallel_for_each(edge_maps, [&](EdgeMap &edge_map) { threading::parallel_for_each(edge_maps, [&](EdgeMap &edge_map) {
const int task_index = &edge_map - edge_maps.data(); const int task_index = &edge_map - edge_maps.data();
for (const int2 &edge : edges) { for (const int2 &edge : edges) {
OrderedEdge ordered_edge{edge[0], edge[1]}; const OrderedEdge ordered_edge(edge[0], edge[1]);
/* Only add the edge when it belongs into this map. */ /* Only add the edge when it belongs into this map. */
if (task_index == (parallel_mask & edge_hash_2(ordered_edge))) { if (task_index == (parallel_mask & edge_hash_2(ordered_edge))) {
edge_map.add_new(ordered_edge, {&edge}); edge_map.add_new(ordered_edge, {&edge});
@ -62,27 +62,27 @@ static void add_existing_edges_to_hash_maps(Mesh &mesh,
}); });
} }
static void add_face_edges_to_hash_maps(Mesh &mesh, static void add_face_edges_to_hash_maps(const Mesh &mesh,
MutableSpan<EdgeMap> edge_maps, const uint32_t parallel_mask,
uint32_t parallel_mask) MutableSpan<EdgeMap> edge_maps)
{ {
const OffsetIndices faces = mesh.faces(); const OffsetIndices<int> faces = mesh.faces();
const Span<int> corner_verts = mesh.corner_verts(); const Span<int> corner_verts = mesh.corner_verts();
threading::parallel_for_each(edge_maps, [&](EdgeMap &edge_map) { threading::parallel_for_each(edge_maps, [&](EdgeMap &edge_map) {
const int task_index = &edge_map - edge_maps.data(); const int task_index = &edge_map - edge_maps.data();
for (const int i : faces.index_range()) { for (const int face_i : faces.index_range()) {
const Span<int> face_verts = corner_verts.slice(faces[i]); const IndexRange face = faces[face_i];
int vert_prev = face_verts.last(); for (const int corner : face) {
for (const int vert : face_verts) { const int vert = corner_verts[corner];
const int vert_prev = corner_verts[bke::mesh::face_corner_prev(face, corner)];
/* Can only be the same when the mesh data is invalid. */ /* Can only be the same when the mesh data is invalid. */
if (vert_prev != vert) { if (vert_prev != vert) {
OrderedEdge ordered_edge{vert_prev, vert}; const OrderedEdge ordered_edge(vert_prev, vert);
/* Only add the edge when it belongs into this map. */ /* Only add the edge when it belongs into this map. */
if (task_index == (parallel_mask & edge_hash_2(ordered_edge))) { if (task_index == (parallel_mask & edge_hash_2(ordered_edge))) {
edge_map.lookup_or_add(ordered_edge, {nullptr}); edge_map.lookup_or_add(ordered_edge, {nullptr});
} }
} }
vert_prev = vert;
} }
} }
}); });
@ -94,16 +94,16 @@ static void serialize_and_initialize_deduplicated_edges(MutableSpan<EdgeMap> edg
/* All edges are distributed in the hash tables now. They have to be serialized into a single /* All edges are distributed in the hash tables now. They have to be serialized into a single
* array below. To be able to parallelize this, we have to compute edge index offsets for each * array below. To be able to parallelize this, we have to compute edge index offsets for each
* map. */ * map. */
Array<int> edge_index_offsets(edge_maps.size()); Array<int> edge_sizes(edge_maps.size() + 1);
edge_index_offsets[0] = 0; for (const int i : edge_maps.index_range()) {
for (const int i : IndexRange(edge_maps.size() - 1)) { edge_sizes[i] = edge_maps[i].size();
edge_index_offsets[i + 1] = edge_index_offsets[i] + edge_maps[i].size();
} }
const OffsetIndices<int> edge_offsets = offset_indices::accumulate_counts_to_offsets(edge_sizes);
threading::parallel_for_each(edge_maps, [&](EdgeMap &edge_map) { threading::parallel_for_each(edge_maps, [&](EdgeMap &edge_map) {
const int task_index = &edge_map - edge_maps.data(); const int task_index = &edge_map - edge_maps.data();
int new_edge_index = edge_index_offsets[task_index]; int new_edge_index = edge_offsets[task_index].first();
for (EdgeMap::MutableItem item : edge_map.items()) { for (EdgeMap::MutableItem item : edge_map.items()) {
int2 &new_edge = new_edges[new_edge_index]; int2 &new_edge = new_edges[new_edge_index];
const int2 *orig_edge = item.value.original_edge; const int2 *orig_edge = item.value.original_edge;
@ -113,8 +113,7 @@ static void serialize_and_initialize_deduplicated_edges(MutableSpan<EdgeMap> edg
} }
else { else {
/* Initialize new edge. */ /* Initialize new edge. */
new_edge[0] = item.key.v_low; new_edge = int2(item.key.v_low, item.key.v_high);
new_edge[1] = item.key.v_high;
} }
item.value.index = new_edge_index; item.value.index = new_edge_index;
new_edge_index++; new_edge_index++;
@ -131,14 +130,13 @@ static void update_edge_indices_in_face_loops(const OffsetIndices<int> faces,
threading::parallel_for(faces.index_range(), 100, [&](IndexRange range) { threading::parallel_for(faces.index_range(), 100, [&](IndexRange range) {
for (const int face_index : range) { for (const int face_index : range) {
const IndexRange face = faces[face_index]; const IndexRange face = faces[face_index];
int prev_corner = face.last(); for (const int corner : face) {
for (const int next_corner : face) { const int vert = corner_verts[corner];
const int vert = corner_verts[next_corner]; const int vert_prev = corner_verts[bke::mesh::face_corner_next(face, corner)];
const int vert_prev = corner_verts[prev_corner];
int edge_index; int edge_index;
if (vert_prev != vert) { if (vert_prev != vert) {
OrderedEdge ordered_edge{vert_prev, vert}; const OrderedEdge ordered_edge(vert_prev, vert);
/* Double lookup: First find the map that contains the edge, then lookup the edge. */ /* Double lookup: First find the map that contains the edge, then lookup the edge. */
const EdgeMap &edge_map = edge_maps[parallel_mask & edge_hash_2(ordered_edge)]; const EdgeMap &edge_map = edge_maps[parallel_mask & edge_hash_2(ordered_edge)];
edge_index = edge_map.lookup(ordered_edge).index; edge_index = edge_map.lookup(ordered_edge).index;
@ -149,8 +147,7 @@ static void update_edge_indices_in_face_loops(const OffsetIndices<int> faces,
* #76514. */ * #76514. */
edge_index = 0; edge_index = 0;
} }
corner_edges[prev_corner] = edge_index; corner_edges[corner] = edge_index;
prev_corner = next_corner;
} }
} }
}); });
@ -187,21 +184,20 @@ void mesh_calc_edges(Mesh &mesh, bool keep_existing_edges, const bool select_new
/* Add all edges. */ /* Add all edges. */
if (keep_existing_edges) { if (keep_existing_edges) {
calc_edges::add_existing_edges_to_hash_maps(mesh, edge_maps, parallel_mask); calc_edges::add_existing_edges_to_hash_maps(mesh, parallel_mask, edge_maps);
} }
calc_edges::add_face_edges_to_hash_maps(mesh, edge_maps, parallel_mask); calc_edges::add_face_edges_to_hash_maps(mesh, parallel_mask, edge_maps);
/* Compute total number of edges. */ /* Compute total number of edges. */
int new_totedge = 0; int new_totedge = 0;
for (calc_edges::EdgeMap &edge_map : edge_maps) { for (const calc_edges::EdgeMap &edge_map : edge_maps) {
new_totedge += edge_map.size(); new_totedge += edge_map.size();
} }
/* Create new edges. */ /* Create new edges. */
MutableAttributeAccessor attributes = mesh.attributes_for_write(); MutableAttributeAccessor attributes = mesh.attributes_for_write();
attributes.add<int>(".corner_edge", AttrDomain::Corner, AttributeInitConstruct()); attributes.add<int>(".corner_edge", AttrDomain::Corner, AttributeInitConstruct());
MutableSpan<int2> new_edges{ MutableSpan<int2> new_edges(MEM_cnew_array<int2>(new_totedge, __func__), new_totedge);
static_cast<int2 *>(MEM_calloc_arrayN(new_totedge, sizeof(int2), __func__)), new_totedge};
calc_edges::serialize_and_initialize_deduplicated_edges(edge_maps, new_edges); calc_edges::serialize_and_initialize_deduplicated_edges(edge_maps, new_edges);
calc_edges::update_edge_indices_in_face_loops( calc_edges::update_edge_indices_in_face_loops(
mesh.faces(), mesh.corner_verts(), edge_maps, parallel_mask, mesh.corner_edges_for_write()); mesh.faces(), mesh.corner_verts(), edge_maps, parallel_mask, mesh.corner_edges_for_write());
@ -219,7 +215,7 @@ void mesh_calc_edges(Mesh &mesh, bool keep_existing_edges, const bool select_new
if (select_edge) { if (select_edge) {
int new_edge_index = 0; int new_edge_index = 0;
for (const calc_edges::EdgeMap &edge_map : edge_maps) { for (const calc_edges::EdgeMap &edge_map : edge_maps) {
for (calc_edges::EdgeMap::Item item : edge_map.items()) { for (const calc_edges::EdgeMap::Item item : edge_map.items()) {
if (item.value.original_edge == nullptr) { if (item.value.original_edge == nullptr) {
select_edge.span[new_edge_index] = true; select_edge.span[new_edge_index] = true;
} }

View File

@ -57,7 +57,7 @@ void mesh_flip_faces(Mesh &mesh, const IndexMask &selection)
} }
}); });
flip_custom_data_type<float4x4>(faces, mesh.corner_data, selection, CD_TANGENT); flip_custom_data_type<float4>(faces, mesh.corner_data, selection, CD_TANGENT);
flip_custom_data_type<float4>(faces, mesh.corner_data, selection, CD_MLOOPTANGENT); flip_custom_data_type<float4>(faces, mesh.corner_data, selection, CD_MLOOPTANGENT);
flip_custom_data_type<short2>(faces, mesh.corner_data, selection, CD_CUSTOMLOOPNORMAL); flip_custom_data_type<short2>(faces, mesh.corner_data, selection, CD_CUSTOMLOOPNORMAL);
flip_custom_data_type<GridPaintMask>(faces, mesh.corner_data, selection, CD_GRID_PAINT_MASK); flip_custom_data_type<GridPaintMask>(faces, mesh.corner_data, selection, CD_GRID_PAINT_MASK);

View File

@ -45,8 +45,7 @@ void BKE_mesh_foreach_mapped_vert(
const blender::Span<blender::float3> positions = mesh->runtime->edit_data->vert_positions; const blender::Span<blender::float3> positions = mesh->runtime->edit_data->vert_positions;
blender::Span<blender::float3> vert_normals; blender::Span<blender::float3> vert_normals;
if (flag & MESH_FOREACH_USE_NORMAL) { if (flag & MESH_FOREACH_USE_NORMAL) {
BKE_editmesh_cache_ensure_vert_normals(*em, *mesh->runtime->edit_data); vert_normals = BKE_editmesh_cache_ensure_vert_normals(*em, *mesh->runtime->edit_data);
vert_normals = mesh->runtime->edit_data->vert_normals;
} }
BM_ITER_MESH_INDEX (eve, &iter, bm, BM_VERTS_OF_MESH, i) { BM_ITER_MESH_INDEX (eve, &iter, bm, BM_VERTS_OF_MESH, i) {
const float *no = (flag & MESH_FOREACH_USE_NORMAL) ? &vert_normals[i].x : nullptr; const float *no = (flag & MESH_FOREACH_USE_NORMAL) ? &vert_normals[i].x : nullptr;
@ -236,18 +235,16 @@ void BKE_mesh_foreach_mapped_face_center(
if (mesh->runtime->edit_mesh != nullptr && mesh->runtime->edit_data != nullptr) { if (mesh->runtime->edit_mesh != nullptr && mesh->runtime->edit_data != nullptr) {
BMEditMesh *em = mesh->runtime->edit_mesh; BMEditMesh *em = mesh->runtime->edit_mesh;
BMesh *bm = em->bm; BMesh *bm = em->bm;
blender::Span<blender::float3> face_centers;
blender::Span<blender::float3> face_normals;
BMFace *efa; BMFace *efa;
BMIter iter; BMIter iter;
int i; int i;
BKE_editmesh_cache_ensure_face_centers(*em, *mesh->runtime->edit_data); const Span<float3> face_centers = BKE_editmesh_cache_ensure_face_centers(
face_centers = mesh->runtime->edit_data->face_centers; /* always set */ *em, *mesh->runtime->edit_data);
Span<float3> face_normals;
if (flag & MESH_FOREACH_USE_NORMAL) { if (flag & MESH_FOREACH_USE_NORMAL) {
BKE_editmesh_cache_ensure_face_normals(*em, *mesh->runtime->edit_data); face_normals = BKE_editmesh_cache_ensure_face_normals(*em, *mesh->runtime->edit_data);
face_normals = mesh->runtime->edit_data->face_normals; /* maybe nullptr */
} }
if (!face_normals.is_empty()) { if (!face_normals.is_empty()) {

View File

@ -2431,6 +2431,16 @@ void BKE_main_mesh_legacy_convert_auto_smooth(Main &bmain)
BLI_insertlinkbefore(&object->modifiers, object->modifiers.last, new_md); BLI_insertlinkbefore(&object->modifiers, object->modifiers.last, new_md);
} }
} }
if (md->type == eModifierType_Nodes) {
NodesModifierData *nmd = reinterpret_cast<NodesModifierData *>(md);
if (nmd->node_group && is_auto_smooth_node_tree(*nmd->node_group)) {
/* This object has already been processed by versioning. If the mesh is linked from
* another file its auto-smooth flag may not be cleared, so this check is necessary to
* avoid adding a duplicate modifier. */
has_custom_normals = true;
break;
}
}
} }
/* Some modifiers always generate custom normals which disabled sharp edge tagging, making /* Some modifiers always generate custom normals which disabled sharp edge tagging, making

View File

@ -548,22 +548,14 @@ void BKE_mesh_calc_loop_tangent_ex(const float (*vert_positions)[3],
*tangent_mask_curr_p = tangent_mask_curr; *tangent_mask_curr_p = tangent_mask_curr;
/* Update active layer index */ /* Update active layer index */
int act_uv_index = (act_uv_n != -1) ? if (const char *active_uv_name = CustomData_get_active_layer_name(loopdata, CD_PROP_FLOAT2)) {
CustomData_get_layer_index_n(loopdata, CD_PROP_FLOAT2, act_uv_n) : int tan_index = CustomData_get_named_layer_index(loopdata_out, CD_TANGENT, active_uv_name);
-1;
if (act_uv_index != -1) {
int tan_index = CustomData_get_named_layer_index(
loopdata, CD_TANGENT, loopdata->layers[act_uv_index].name);
CustomData_set_layer_active_index(loopdata_out, CD_TANGENT, tan_index); CustomData_set_layer_active_index(loopdata_out, CD_TANGENT, tan_index);
} /* else tangent has been built from orco */ } /* else tangent has been built from orco */
/* Update render layer index */ /* Update render layer index */
int ren_uv_index = (ren_uv_n != -1) ? if (const char *render_uv_name = CustomData_get_render_layer_name(loopdata, CD_PROP_FLOAT2)) {
CustomData_get_layer_index_n(loopdata, CD_PROP_FLOAT2, ren_uv_n) : int tan_index = CustomData_get_named_layer_index(loopdata_out, CD_TANGENT, render_uv_name);
-1;
if (ren_uv_index != -1) {
int tan_index = CustomData_get_named_layer_index(
loopdata, CD_TANGENT, loopdata->layers[ren_uv_index].name);
CustomData_set_layer_render_index(loopdata_out, CD_TANGENT, tan_index); CustomData_set_layer_render_index(loopdata_out, CD_TANGENT, tan_index);
} /* else tangent has been built from orco */ } /* else tangent has been built from orco */
} }

View File

@ -30,6 +30,7 @@
#include "BKE_customdata.hh" #include "BKE_customdata.hh"
#include "BKE_deform.hh" #include "BKE_deform.hh"
#include "BKE_mesh.hh" #include "BKE_mesh.hh"
#include "BKE_mesh_runtime.hh"
#include "DEG_depsgraph.hh" #include "DEG_depsgraph.hh"
@ -1125,6 +1126,7 @@ bool BKE_mesh_validate(Mesh *mesh, const bool do_verbose, const bool cddata_chec
&changed); &changed);
if (changed) { if (changed) {
BKE_mesh_runtime_clear_cache(mesh);
DEG_id_tag_update(&mesh->id, ID_RECALC_GEOMETRY_ALL_MODES); DEG_id_tag_update(&mesh->id, ID_RECALC_GEOMETRY_ALL_MODES);
return true; return true;
} }

View File

@ -129,10 +129,6 @@ void BKE_mesh_wrapper_ensure_mdata(Mesh *mesh)
mesh->runtime->is_original_bmesh = false; mesh->runtime->is_original_bmesh = false;
} }
if (mesh->runtime->wrapper_type_finalize) {
BKE_mesh_wrapper_deferred_finalize_mdata(mesh);
}
mesh->runtime->edit_data.reset(); mesh->runtime->edit_data.reset();
break; break;
} }
@ -165,8 +161,8 @@ Span<float3> BKE_mesh_wrapper_face_normals(Mesh *mesh)
{ {
switch (mesh->runtime->wrapper_type) { switch (mesh->runtime->wrapper_type) {
case ME_WRAPPER_TYPE_BMESH: case ME_WRAPPER_TYPE_BMESH:
BKE_editmesh_cache_ensure_face_normals(*mesh->runtime->edit_mesh, *mesh->runtime->edit_data); return BKE_editmesh_cache_ensure_face_normals(*mesh->runtime->edit_mesh,
return mesh->runtime->edit_data->face_normals; *mesh->runtime->edit_data);
case ME_WRAPPER_TYPE_MDATA: case ME_WRAPPER_TYPE_MDATA:
case ME_WRAPPER_TYPE_SUBD: case ME_WRAPPER_TYPE_SUBD:
return mesh->face_normals(); return mesh->face_normals();
@ -179,10 +175,10 @@ void BKE_mesh_wrapper_tag_positions_changed(Mesh *mesh)
{ {
switch (mesh->runtime->wrapper_type) { switch (mesh->runtime->wrapper_type) {
case ME_WRAPPER_TYPE_BMESH: case ME_WRAPPER_TYPE_BMESH:
if (mesh->runtime->edit_data) { if (blender::bke::EditMeshData *edit_data = mesh->runtime->edit_data.get()) {
mesh->runtime->edit_data->vert_normals = {}; edit_data->vert_normals = {};
mesh->runtime->edit_data->face_centers = {}; edit_data->face_centers = {};
mesh->runtime->edit_data->face_normals = {}; edit_data->face_normals = {};
} }
break; break;
case ME_WRAPPER_TYPE_MDATA: case ME_WRAPPER_TYPE_MDATA:

View File

@ -1804,7 +1804,7 @@ void BKE_movieclip_build_proxy_frame(MovieClip *clip,
int clip_flag, int clip_flag,
MovieDistortion *distortion, MovieDistortion *distortion,
int cfra, int cfra,
int *build_sizes, const int *build_sizes,
int build_count, int build_count,
bool undistorted) bool undistorted)
{ {
@ -1845,7 +1845,7 @@ void BKE_movieclip_build_proxy_frame_for_ibuf(MovieClip *clip,
ImBuf *ibuf, ImBuf *ibuf,
MovieDistortion *distortion, MovieDistortion *distortion,
int cfra, int cfra,
int *build_sizes, const int *build_sizes,
int build_count, int build_count,
bool undistorted) bool undistorted)
{ {

View File

@ -4157,7 +4157,7 @@ static blender::Set<int> get_known_node_types_set()
static bool can_read_node_type(const int type) static bool can_read_node_type(const int type)
{ {
/* Can always read custom node types. */ /* Can always read custom node types. */
if (type == NODE_CUSTOM) { if (ELEM(type, NODE_CUSTOM, NODE_CUSTOM_GROUP)) {
return true; return true;
} }

View File

@ -1455,7 +1455,7 @@ bool BKE_object_modifier_stack_copy(Object *ob_dst,
const int flag_subdata) const int flag_subdata)
{ {
if ((ob_dst->type == OB_GPENCIL_LEGACY) != (ob_src->type == OB_GPENCIL_LEGACY)) { if ((ob_dst->type == OB_GPENCIL_LEGACY) != (ob_src->type == OB_GPENCIL_LEGACY)) {
BLI_assert_msg(0, BLI_assert_msg(false,
"Trying to copy a modifier stack between a GPencil object and another type."); "Trying to copy a modifier stack between a GPencil object and another type.");
return false; return false;
} }
@ -1463,8 +1463,9 @@ bool BKE_object_modifier_stack_copy(Object *ob_dst,
if (!BLI_listbase_is_empty(&ob_dst->modifiers) || if (!BLI_listbase_is_empty(&ob_dst->modifiers) ||
!BLI_listbase_is_empty(&ob_dst->greasepencil_modifiers)) !BLI_listbase_is_empty(&ob_dst->greasepencil_modifiers))
{ {
BLI_assert( BLI_assert_msg(
!"Trying to copy a modifier stack into an object having a non-empty modifier stack."); false,
"Trying to copy a modifier stack into an object having a non-empty modifier stack.");
return false; return false;
} }

View File

@ -544,7 +544,7 @@ bool BKE_object_defgroup_array_get(ID *id, MDeformVert **dvert_arr, int *dvert_t
return true; return true;
} }
case ID_GP: case ID_GP:
/* Should not be used with grease pencil objects.*/ /* Should not be used with grease pencil objects. */
BLI_assert_unreachable(); BLI_assert_unreachable();
break; break;
default: default:

View File

@ -444,17 +444,17 @@ static void make_child_duplis(const DupliContext *ctx,
static const Mesh *mesh_data_from_duplicator_object(Object *ob, static const Mesh *mesh_data_from_duplicator_object(Object *ob,
BMEditMesh **r_em, BMEditMesh **r_em,
const float (**r_vert_coords)[3], Span<float3> *r_vert_coords,
const float (**r_vert_normals)[3]) Span<float3> *r_vert_normals)
{ {
/* Gather mesh info. */ /* Gather mesh info. */
BMEditMesh *em = BKE_editmesh_from_object(ob); BMEditMesh *em = BKE_editmesh_from_object(ob);
const Mesh *mesh_eval; const Mesh *mesh_eval;
*r_em = nullptr; *r_em = nullptr;
*r_vert_coords = nullptr; *r_vert_coords = {};
if (r_vert_normals != nullptr) { if (r_vert_normals != nullptr) {
*r_vert_normals = nullptr; *r_vert_normals = {};
} }
/* We do not need any render-specific handling anymore, depsgraph takes care of that. */ /* We do not need any render-specific handling anymore, depsgraph takes care of that. */
@ -473,10 +473,9 @@ static const Mesh *mesh_data_from_duplicator_object(Object *ob,
mesh_eval = nullptr; mesh_eval = nullptr;
if ((emd != nullptr) && !emd->vert_positions.is_empty()) { if ((emd != nullptr) && !emd->vert_positions.is_empty()) {
*r_vert_coords = reinterpret_cast<const float(*)[3]>(emd->vert_positions.data()); *r_vert_coords = emd->vert_positions;
if (r_vert_normals != nullptr) { if (r_vert_normals != nullptr) {
BKE_editmesh_cache_ensure_vert_normals(*em, *emd); *r_vert_normals = BKE_editmesh_cache_ensure_vert_normals(*em, *emd);
*r_vert_normals = reinterpret_cast<const float(*)[3]>(emd->vert_normals.data());
} }
} }
} }
@ -563,9 +562,9 @@ struct VertexDupliData_EditMesh {
BMEditMesh *em; BMEditMesh *em;
/* Can be nullptr. */ /* Can be empty. */
const float (*vert_positions_deform)[3]; Span<float3> vert_positions_deform;
const float (*vert_normals_deform)[3]; Span<float3> vert_normals_deform;
/** /**
* \note The edit-mesh may assign #DupliObject.orco in cases when a regular mesh wouldn't. * \note The edit-mesh may assign #DupliObject.orco in cases when a regular mesh wouldn't.
@ -582,8 +581,8 @@ struct VertexDupliData_EditMesh {
* currently this is copied from a `short[3]` normal without division. * currently this is copied from a `short[3]` normal without division.
* Can be null when \a use_rotation is false. * Can be null when \a use_rotation is false.
*/ */
static void get_duplivert_transform(const float co[3], static void get_duplivert_transform(const float3 &co,
const float no[3], const float3 &no,
const bool use_rotation, const bool use_rotation,
const short axis, const short axis,
const short upflag, const short upflag,
@ -609,8 +608,8 @@ static DupliObject *vertex_dupli(const DupliContext *ctx,
Object *inst_ob, Object *inst_ob,
const float child_imat[4][4], const float child_imat[4][4],
int index, int index,
const float co[3], const float3 &co,
const float no[3], const float3 &no,
const bool use_rotation) const bool use_rotation)
{ {
/* `obmat` is transform to vertex. */ /* `obmat` is transform to vertex. */
@ -681,14 +680,13 @@ static void make_child_duplis_verts_from_editmesh(const DupliContext *ctx,
BMIter iter; BMIter iter;
int i; int i;
const float(*vert_positions_deform)[3] = vdd->vert_positions_deform; const Span<float3> vert_positions_deform = vdd->vert_positions_deform;
const float(*vert_normals_deform)[3] = vdd->vert_normals_deform; const Span<float3> vert_normals_deform = vdd->vert_normals_deform;
BM_ITER_MESH_INDEX (v, &iter, em->bm, BM_VERTS_OF_MESH, i) { BM_ITER_MESH_INDEX (v, &iter, em->bm, BM_VERTS_OF_MESH, i) {
const float *co, *no; float3 co, no;
if (vert_positions_deform != nullptr) { if (!vert_positions_deform.is_empty()) {
co = vert_positions_deform[i]; co = vert_positions_deform[i];
no = vert_normals_deform ? vert_normals_deform[i] : nullptr; no = !vert_normals_deform.is_empty() ? vert_normals_deform[i] : float3(0);
} }
else { else {
co = v->co; co = v->co;
@ -709,8 +707,8 @@ static void make_duplis_verts(const DupliContext *ctx)
/* Gather mesh info. */ /* Gather mesh info. */
BMEditMesh *em = nullptr; BMEditMesh *em = nullptr;
const float(*vert_positions_deform)[3] = nullptr; Span<float3> vert_positions_deform;
const float(*vert_normals_deform)[3] = nullptr; Span<float3> vert_normals_deform;
const Mesh *mesh_eval = mesh_data_from_duplicator_object( const Mesh *mesh_eval = mesh_data_from_duplicator_object(
parent, &em, &vert_positions_deform, use_rotation ? &vert_normals_deform : nullptr); parent, &em, &vert_positions_deform, use_rotation ? &vert_normals_deform : nullptr);
if (em == nullptr && mesh_eval == nullptr) { if (em == nullptr && mesh_eval == nullptr) {
@ -725,7 +723,7 @@ static void make_duplis_verts(const DupliContext *ctx)
vdd.em = em; vdd.em = em;
vdd.vert_positions_deform = vert_positions_deform; vdd.vert_positions_deform = vert_positions_deform;
vdd.vert_normals_deform = vert_normals_deform; vdd.vert_normals_deform = vert_normals_deform;
vdd.has_orco = (vert_positions_deform != nullptr); vdd.has_orco = !vert_positions_deform.is_empty();
make_child_duplis(ctx, &vdd, make_child_duplis_verts_from_editmesh); make_child_duplis(ctx, &vdd, make_child_duplis_verts_from_editmesh);
} }
@ -1080,8 +1078,8 @@ struct FaceDupliData_EditMesh {
bool has_orco, has_uvs; bool has_orco, has_uvs;
int cd_loop_uv_offset; int cd_loop_uv_offset;
/* Can be nullptr. */ /* Can be empty. */
const float (*vert_positions_deform)[3]; Span<float3> vert_positions_deform;
}; };
static void get_dupliface_transform_from_coords(Span<float3> coords, static void get_dupliface_transform_from_coords(Span<float3> coords,
@ -1186,7 +1184,7 @@ static DupliObject *face_dupli_from_editmesh(const DupliContext *ctx,
/* Mesh variables. */ /* Mesh variables. */
BMFace *f, BMFace *f,
const float (*vert_positions_deform)[3]) const Span<float3> vert_positions_deform)
{ {
const int coords_len = f->len; const int coords_len = f->len;
Array<float3, 64> coords(coords_len); Array<float3, 64> coords(coords_len);
@ -1194,7 +1192,7 @@ static DupliObject *face_dupli_from_editmesh(const DupliContext *ctx,
BMLoop *l_first, *l_iter; BMLoop *l_first, *l_iter;
int i = 0; int i = 0;
l_iter = l_first = BM_FACE_FIRST_LOOP(f); l_iter = l_first = BM_FACE_FIRST_LOOP(f);
if (vert_positions_deform != nullptr) { if (!vert_positions_deform.is_empty()) {
do { do {
copy_v3_v3(coords[i++], vert_positions_deform[BM_elem_index_get(l_iter->v)]); copy_v3_v3(coords[i++], vert_positions_deform[BM_elem_index_get(l_iter->v)]);
} while ((l_iter = l_iter->next) != l_first); } while ((l_iter = l_iter->next) != l_first);
@ -1263,9 +1261,9 @@ static void make_child_duplis_faces_from_editmesh(const DupliContext *ctx,
BMIter iter; BMIter iter;
const bool use_scale = fdd->params.use_scale; const bool use_scale = fdd->params.use_scale;
const float(*vert_positions_deform)[3] = fdd->vert_positions_deform; const Span<float3> vert_positions_deform = fdd->vert_positions_deform;
BLI_assert((vert_positions_deform == nullptr) || (em->bm->elem_index_dirty & BM_VERT) == 0); BLI_assert(vert_positions_deform.is_empty() || (em->bm->elem_index_dirty & BM_VERT) == 0);
invert_m4_m4(inst_ob->runtime->world_to_object.ptr(), inst_ob->object_to_world().ptr()); invert_m4_m4(inst_ob->runtime->world_to_object.ptr(), inst_ob->object_to_world().ptr());
/* Relative transform from parent to child space. */ /* Relative transform from parent to child space. */
@ -1296,7 +1294,7 @@ static void make_duplis_faces(const DupliContext *ctx)
/* Gather mesh info. */ /* Gather mesh info. */
BMEditMesh *em = nullptr; BMEditMesh *em = nullptr;
const float(*vert_positions_deform)[3] = nullptr; Span<float3> vert_positions_deform;
const Mesh *mesh_eval = mesh_data_from_duplicator_object( const Mesh *mesh_eval = mesh_data_from_duplicator_object(
parent, &em, &vert_positions_deform, nullptr); parent, &em, &vert_positions_deform, nullptr);
if (em == nullptr && mesh_eval == nullptr) { if (em == nullptr && mesh_eval == nullptr) {
@ -1311,7 +1309,7 @@ static void make_duplis_faces(const DupliContext *ctx)
fdd.params = fdd_params; fdd.params = fdd_params;
fdd.em = em; fdd.em = em;
fdd.vert_positions_deform = vert_positions_deform; fdd.vert_positions_deform = vert_positions_deform;
fdd.has_orco = (vert_positions_deform != nullptr); fdd.has_orco = !vert_positions_deform.is_empty();
fdd.has_uvs = (uv_idx != -1); fdd.has_uvs = (uv_idx != -1);
fdd.cd_loop_uv_offset = (uv_idx != -1) ? fdd.cd_loop_uv_offset = (uv_idx != -1) ?
CustomData_get_n_offset(&em->bm->ldata, CD_PROP_FLOAT2, uv_idx) : CustomData_get_n_offset(&em->bm->ldata, CD_PROP_FLOAT2, uv_idx) :

View File

@ -367,7 +367,7 @@ int BKE_packedfile_write_to_file(ReportList *reports,
enum ePF_FileCompare BKE_packedfile_compare_to_file(const char *ref_file_name, enum ePF_FileCompare BKE_packedfile_compare_to_file(const char *ref_file_name,
const char *filepath_rel, const char *filepath_rel,
PackedFile *pf) const PackedFile *pf)
{ {
BLI_stat_t st; BLI_stat_t st;
enum ePF_FileCompare ret_val; enum ePF_FileCompare ret_val;
@ -880,7 +880,7 @@ void BKE_packedfile_id_unpack(Main *bmain, ID *id, ReportList *reports, enum ePF
} }
} }
void BKE_packedfile_blend_write(BlendWriter *writer, PackedFile *pf) void BKE_packedfile_blend_write(BlendWriter *writer, const PackedFile *pf)
{ {
if (pf == nullptr) { if (pf == nullptr) {
return; return;

View File

@ -834,8 +834,8 @@ static int distribute_compare_orig_index(const void *p1, const void *p2, void *u
return -1; return -1;
} }
if (index1 == index2) { if (index1 == index2) {
/* this pointer comparison appears to make qsort stable for glibc, /* This pointer comparison appears to make #qsort stable for GLIBC,
* and apparently on solaris too, makes the renders reproducible */ * and apparently on SOLARIS too, makes the renders reproducible. */
if (p1 < p2) { if (p1 < p2) {
return -1; return -1;
} }

View File

@ -2287,7 +2287,7 @@ void clip_ray_ortho(
axis_dominant_v3_to_m3(mat, ray_normal); axis_dominant_v3_to_m3(mat, ray_normal);
float a[3], b[3], min[3] = {FLT_MAX, FLT_MAX, FLT_MAX}, max[3] = {FLT_MIN, FLT_MIN, FLT_MIN}; float a[3], b[3], min[3] = {FLT_MAX, FLT_MAX, FLT_MAX}, max[3] = {FLT_MIN, FLT_MIN, FLT_MIN};
/* Compute AABB bounds rotated along ray_normal.*/ /* Compute AABB bounds rotated along ray_normal. */
copy_v3_v3(a, bb_root.min); copy_v3_v3(a, bb_root.min);
copy_v3_v3(b, bb_root.max); copy_v3_v3(b, bb_root.max);
mul_m3_v3(mat, a); mul_m3_v3(mat, a);

View File

@ -312,7 +312,7 @@ UVVertex *UVEdge::get_other_uv_vertex(const int vertex)
UVVertex *UVIsland::lookup(const UVVertex &vertex) UVVertex *UVIsland::lookup(const UVVertex &vertex)
{ {
const int vert_index = vertex.vertex; const int vert_index = vertex.vertex;
Vector<UVVertex *> &vertices = uv_vertex_lookup.lookup_or_add_default(vert_index); const Vector<UVVertex *> &vertices = uv_vertex_lookup.lookup_or_add_default(vert_index);
for (UVVertex *v : vertices) { for (UVVertex *v : vertices) {
if (v->uv == vertex.uv) { if (v->uv == vertex.uv) {
return v; return v;
@ -1033,9 +1033,8 @@ static void reset_extendability_flags(UVIsland &island)
uv_vertex.flags.is_extended = false; uv_vertex.flags.is_extended = false;
} }
} }
for (const UVBorder &border : island.borders) {
for (UVBorder border : island.borders) { for (const UVBorderEdge &border_edge : border.edges) {
for (UVBorderEdge &border_edge : border.edges) {
border_edge.edge->vertices[0]->flags.is_border = true; border_edge.edge->vertices[0]->flags.is_border = true;
border_edge.edge->vertices[1]->flags.is_border = true; border_edge.edge->vertices[1]->flags.is_border = true;
} }

View File

@ -1136,13 +1136,12 @@ static void scene_blend_write(BlendWriter *writer, ID *id, const void *id_addres
if (sce->nodetree) { if (sce->nodetree) {
BLO_write_init_id_buffer_from_id( BLO_write_init_id_buffer_from_id(
temp_embedded_id_buffer, &sce->nodetree->id, BLO_write_is_undo(writer)); temp_embedded_id_buffer, &sce->nodetree->id, BLO_write_is_undo(writer));
BLO_write_struct_at_address(writer, bNodeTree *temp_nodetree = reinterpret_cast<bNodeTree *>(
bNodeTree, BLO_write_get_id_buffer_temp_id(temp_embedded_id_buffer));
sce->nodetree, /* Set deprecated chunksize for forward compatibility. */
BLO_write_get_id_buffer_temp_id(temp_embedded_id_buffer)); temp_nodetree->chunksize = 256;
ntreeBlendWrite( BLO_write_struct_at_address(writer, bNodeTree, sce->nodetree, temp_nodetree);
writer, ntreeBlendWrite(writer, temp_nodetree);
reinterpret_cast<bNodeTree *>(BLO_write_get_id_buffer_temp_id(temp_embedded_id_buffer)));
} }
BKE_color_managed_view_settings_blend_write(writer, &sce->view_settings); BKE_color_managed_view_settings_blend_write(writer, &sce->view_settings);

View File

@ -560,7 +560,7 @@ CCGKey BKE_subdiv_ccg_key_top_level(const SubdivCCG &subdiv_ccg)
* {(x, y), {x + 1, y}, {x + 1, y + 1}, {x, y + 1}} * {(x, y), {x + 1, y}, {x + 1, y + 1}, {x, y + 1}}
* *
* The result is stored in normals storage from TLS. */ * The result is stored in normals storage from TLS. */
static void subdiv_ccg_recalc_inner_face_normals(SubdivCCG &subdiv_ccg, static void subdiv_ccg_recalc_inner_face_normals(const SubdivCCG &subdiv_ccg,
const CCGKey &key, const CCGKey &key,
MutableSpan<float3> face_normals, MutableSpan<float3> face_normals,
const int corner) const int corner)
@ -590,7 +590,7 @@ static void subdiv_ccg_recalc_inner_face_normals(SubdivCCG &subdiv_ccg,
} }
/* Average normals at every grid element, using adjacent faces normals. */ /* Average normals at every grid element, using adjacent faces normals. */
static void subdiv_ccg_average_inner_face_normals(SubdivCCG &subdiv_ccg, static void subdiv_ccg_average_inner_face_normals(const SubdivCCG &subdiv_ccg,
const CCGKey &key, const CCGKey &key,
const Span<float3> face_normals, const Span<float3> face_normals,
const int corner) const int corner)
@ -690,7 +690,7 @@ static void average_grid_element_value_v3(float a[3], float b[3])
copy_v3_v3(b, a); copy_v3_v3(b, a);
} }
static void average_grid_element(SubdivCCG &subdiv_ccg, static void average_grid_element(const SubdivCCG &subdiv_ccg,
const CCGKey &key, const CCGKey &key,
CCGElem *grid_element_a, CCGElem *grid_element_a,
CCGElem *grid_element_b) CCGElem *grid_element_b)
@ -744,7 +744,7 @@ static void element_accumulator_mul_fl(GridElementAccumulator &accumulator, cons
accumulator.mask *= f; accumulator.mask *= f;
} }
static void element_accumulator_copy(SubdivCCG &subdiv_ccg, static void element_accumulator_copy(const SubdivCCG &subdiv_ccg,
const CCGKey &key, const CCGKey &key,
CCGElem &destination, CCGElem &destination,
const GridElementAccumulator &accumulator) const GridElementAccumulator &accumulator)
@ -795,7 +795,7 @@ static void subdiv_ccg_average_inner_face_grids(SubdivCCG &subdiv_ccg,
static void subdiv_ccg_average_grids_boundary(SubdivCCG &subdiv_ccg, static void subdiv_ccg_average_grids_boundary(SubdivCCG &subdiv_ccg,
const CCGKey &key, const CCGKey &key,
SubdivCCGAdjacentEdge &adjacent_edge, const SubdivCCGAdjacentEdge &adjacent_edge,
MutableSpan<GridElementAccumulator> accumulators) MutableSpan<GridElementAccumulator> accumulators)
{ {
const int num_adjacent_faces = adjacent_edge.num_adjacent_faces; const int num_adjacent_faces = adjacent_edge.num_adjacent_faces;
@ -837,7 +837,7 @@ struct AverageGridsCornerData {
static void subdiv_ccg_average_grids_corners(SubdivCCG &subdiv_ccg, static void subdiv_ccg_average_grids_corners(SubdivCCG &subdiv_ccg,
const CCGKey &key, const CCGKey &key,
SubdivCCGAdjacentVertex &adjacent_vertex) const SubdivCCGAdjacentVertex &adjacent_vertex)
{ {
const int num_adjacent_faces = adjacent_vertex.num_adjacent_faces; const int num_adjacent_faces = adjacent_vertex.num_adjacent_faces;
if (num_adjacent_faces == 1) { if (num_adjacent_faces == 1) {
@ -871,7 +871,7 @@ static void subdiv_ccg_average_boundaries(SubdivCCG &subdiv_ccg,
adjacent_edge_mask.foreach_segment(GrainSize(1024), [&](const IndexMaskSegment segment) { adjacent_edge_mask.foreach_segment(GrainSize(1024), [&](const IndexMaskSegment segment) {
MutableSpan<GridElementAccumulator> accumulators = all_accumulators.local(); MutableSpan<GridElementAccumulator> accumulators = all_accumulators.local();
for (const int i : segment) { for (const int i : segment) {
SubdivCCGAdjacentEdge &adjacent_edge = subdiv_ccg.adjacent_edges[i]; const SubdivCCGAdjacentEdge &adjacent_edge = subdiv_ccg.adjacent_edges[i];
subdiv_ccg_average_grids_boundary(subdiv_ccg, key, adjacent_edge, accumulators); subdiv_ccg_average_grids_boundary(subdiv_ccg, key, adjacent_edge, accumulators);
} }
}); });
@ -883,7 +883,7 @@ static void subdiv_ccg_average_corners(SubdivCCG &subdiv_ccg,
{ {
using namespace blender; using namespace blender;
adjacent_vert_mask.foreach_index(GrainSize(1024), [&](const int i) { adjacent_vert_mask.foreach_index(GrainSize(1024), [&](const int i) {
SubdivCCGAdjacentVertex &adjacent_vert = subdiv_ccg.adjacent_verts[i]; const SubdivCCGAdjacentVertex &adjacent_vert = subdiv_ccg.adjacent_verts[i];
subdiv_ccg_average_grids_corners(subdiv_ccg, key, adjacent_vert); subdiv_ccg_average_grids_corners(subdiv_ccg, key, adjacent_vert);
}); });
} }
@ -1004,15 +1004,8 @@ BLI_INLINE void subdiv_ccg_neighbors_init(SubdivCCGNeighbors &neighbors,
const int num_duplicates) const int num_duplicates)
{ {
const int size = num_unique + num_duplicates; const int size = num_unique + num_duplicates;
neighbors.size = size; neighbors.coords.reinitialize(size);
neighbors.num_duplicates = num_duplicates; neighbors.num_duplicates = num_duplicates;
if (size < ARRAY_SIZE(neighbors.coords_fixed)) {
neighbors.coords = neighbors.coords_fixed;
}
else {
neighbors.coords = static_cast<SubdivCCGCoord *>(
MEM_mallocN(sizeof(*neighbors.coords) * size, "SubdivCCGNeighbors.coords"));
}
} }
/* Check whether given coordinate belongs to a grid corner. */ /* Check whether given coordinate belongs to a grid corner. */
@ -1520,7 +1513,7 @@ void BKE_subdiv_ccg_neighbor_coords_get(const SubdivCCG &subdiv_ccg,
} }
#ifndef NDEBUG #ifndef NDEBUG
for (int i = 0; i < r_neighbors.size; i++) { for (const int i : r_neighbors.coords.index_range()) {
BLI_assert(BKE_subdiv_ccg_check_coord_valid(subdiv_ccg, r_neighbors.coords[i])); BLI_assert(BKE_subdiv_ccg_check_coord_valid(subdiv_ccg, r_neighbors.coords[i]));
} }
#endif #endif

View File

@ -673,10 +673,10 @@ void txt_clean_text(Text *text)
} }
} }
int txt_get_span(TextLine *from, const TextLine *to) int txt_get_span(const TextLine *from, const TextLine *to)
{ {
int ret = 0; int ret = 0;
TextLine *tmp = from; const TextLine *tmp = from;
if (!to || !from) { if (!to || !from) {
return 0; return 0;

View File

@ -2158,7 +2158,7 @@ void BKE_tracking_camera_get_reconstructed_interpolate(MovieTracking * /*trackin
return; return;
} }
if (cameras[a].framenr != framenr && a < reconstruction->camnr - 1) { if ((a < reconstruction->camnr - 1) && (cameras[a].framenr != framenr)) {
float t = (float(framenr) - cameras[a].framenr) / float t = (float(framenr) - cameras[a].framenr) /
(cameras[a + 1].framenr - cameras[a].framenr); (cameras[a + 1].framenr - cameras[a].framenr);
blend_m4_m4m4(mat, cameras[a].mat, cameras[a + 1].mat, t); blend_m4_m4m4(mat, cameras[a].mat, cameras[a + 1].mat, t);

View File

@ -806,8 +806,9 @@ bool BKE_undosys_step_load_data_ex(UndoStack *ustack,
} }
} }
BLI_assert( BLI_assert_msg(
!"This should never be reached, either undo stack is corrupted, or code above is buggy"); false,
"This should never be reached, either undo stack is corrupted, or code above is buggy");
return false; return false;
} }

View File

@ -46,6 +46,7 @@ extern "C" {
# include <libavformat/avformat.h> # include <libavformat/avformat.h>
# include <libavutil/buffer.h> # include <libavutil/buffer.h>
# include <libavutil/channel_layout.h> # include <libavutil/channel_layout.h>
# include <libavutil/cpu.h>
# include <libavutil/imgutils.h> # include <libavutil/imgutils.h>
# include <libavutil/opt.h> # include <libavutil/opt.h>
# include <libavutil/rational.h> # include <libavutil/rational.h>
@ -256,14 +257,15 @@ static AVFrame *alloc_picture(AVPixelFormat pix_fmt, int width, int height)
} }
/* allocate the actual picture buffer */ /* allocate the actual picture buffer */
int size = av_image_get_buffer_size(pix_fmt, width, height, 1); const size_t align = av_cpu_max_align();
int size = av_image_get_buffer_size(pix_fmt, width, height, align);
AVBufferRef *buf = av_buffer_alloc(size); AVBufferRef *buf = av_buffer_alloc(size);
if (buf == nullptr) { if (buf == nullptr) {
av_frame_free(&f); av_frame_free(&f);
return nullptr; return nullptr;
} }
av_image_fill_arrays(f->data, f->linesize, buf->data, pix_fmt, width, height, 1); av_image_fill_arrays(f->data, f->linesize, buf->data, pix_fmt, width, height, align);
f->buf[0] = buf; f->buf[0] = buf;
f->format = pix_fmt; f->format = pix_fmt;
f->width = width; f->width = width;
@ -418,15 +420,16 @@ static AVFrame *generate_video_frame(FFMpegContext *context, const ImBuf *image)
/* Copy the Blender pixels into the FFMPEG data-structure, taking care of endianness and flipping /* Copy the Blender pixels into the FFMPEG data-structure, taking care of endianness and flipping
* the image vertically. */ * the image vertically. */
int linesize = rgb_frame->linesize[0]; int linesize = rgb_frame->linesize[0];
int linesize_src = rgb_frame->width * 4;
for (int y = 0; y < height; y++) { for (int y = 0; y < height; y++) {
uint8_t *target = rgb_frame->data[0] + linesize * (height - y - 1); uint8_t *target = rgb_frame->data[0] + linesize * (height - y - 1);
const uint8_t *src = pixels + linesize * y; const uint8_t *src = pixels + linesize_src * y;
# if ENDIAN_ORDER == L_ENDIAN # if ENDIAN_ORDER == L_ENDIAN
memcpy(target, src, linesize); memcpy(target, src, linesize_src);
# elif ENDIAN_ORDER == B_ENDIAN # elif ENDIAN_ORDER == B_ENDIAN
const uint8_t *end = src + linesize; const uint8_t *end = src + linesize_src;
while (src != end) { while (src != end) {
target[3] = src[0]; target[3] = src[0];
target[2] = src[1]; target[2] = src[1];

View File

@ -27,7 +27,7 @@ BArrayStore *BLI_array_store_at_size_get(struct BArrayStore_AtSize *bs_stride, i
void BLI_array_store_at_size_clear(struct BArrayStore_AtSize *bs_stride); void BLI_array_store_at_size_clear(struct BArrayStore_AtSize *bs_stride);
void BLI_array_store_at_size_calc_memory_usage(struct BArrayStore_AtSize *bs_stride, void BLI_array_store_at_size_calc_memory_usage(const struct BArrayStore_AtSize *bs_stride,
size_t *r_size_expanded, size_t *r_size_expanded,
size_t *r_size_compacted); size_t *r_size_compacted);

View File

@ -13,6 +13,8 @@
#include "BLI_assert.h" #include "BLI_assert.h"
#include "BLI_utility_mixins.hh" #include "BLI_utility_mixins.hh"
#include "MEM_guardedalloc.h"
namespace blender { namespace blender {
/** /**
@ -199,6 +201,30 @@ class ImplicitSharingMixin : public ImplicitSharingInfo {
virtual void delete_self() = 0; virtual void delete_self() = 0;
}; };
/**
* Utility for creating an allocated shared resource, to be used like:
* `new ImplicitSharedValue<T>(args);`
*/
template<typename T> class ImplicitSharedValue : public ImplicitSharingInfo {
public:
T data;
template<typename... Args>
ImplicitSharedValue(Args &&...args) : data(std::forward<Args>(args)...)
{
}
#ifdef WITH_CXX_GUARDEDALLOC
MEM_CXX_CLASS_ALLOC_FUNCS("ImplicitSharedValue");
#endif
private:
void delete_self_with_data() override
{
delete this;
}
};
/** /**
* Utility that contains sharing information and the data that is shared. * Utility that contains sharing information and the data that is shared.
*/ */

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