Sculpt: Improve Expand performance #120125
@ -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",
|
||||
))
|
||||
|
||||
CHECKER_ARGS = [
|
||||
CHECKER_ARGS = (
|
||||
# Speed up execution.
|
||||
# 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.
|
||||
@ -39,9 +39,15 @@ CHECKER_ARGS = [
|
||||
# Enable this when includes are missing.
|
||||
# "--check-config",
|
||||
|
||||
# This is slower, for a comprehensive output it is needed.
|
||||
"--check-level=exhaustive",
|
||||
|
||||
# Shows many pedantic issues, some are quite useful.
|
||||
"--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.
|
||||
"--inconclusive",
|
||||
|
||||
@ -50,7 +56,15 @@ CHECKER_ARGS = [
|
||||
*(() if USE_VERBOSE else ("--quiet",))
|
||||
|
||||
# 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(
|
||||
@ -74,22 +88,50 @@ def source_info_filter(
|
||||
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_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.
|
||||
source_info = source_info_filter(source_info)
|
||||
|
||||
check_commands = []
|
||||
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 = (
|
||||
[CHECKER_BIN] +
|
||||
CHECKER_ARGS +
|
||||
[c] +
|
||||
[("-I%s" % i) for i in inc_dirs] +
|
||||
[("-D%s" % d) for d in defs] +
|
||||
source_defines
|
||||
CHECKER_BIN,
|
||||
*CHECKER_ARGS,
|
||||
*checker_args_extra,
|
||||
"--cppcheck-build-dir=" + temp_build_dir,
|
||||
"--include=" + cppcheck_compiler_h,
|
||||
# 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))
|
||||
@ -119,8 +161,7 @@ def cppcheck() -> None:
|
||||
|
||||
def main() -> None:
|
||||
with tempfile.TemporaryDirectory() as temp_dir:
|
||||
CHECKER_ARGS.append("--cppcheck-build-dir=" + temp_dir)
|
||||
cppcheck()
|
||||
cppcheck(temp_dir)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
@ -24,12 +24,12 @@ from typing import (
|
||||
Any,
|
||||
Callable,
|
||||
Generator,
|
||||
IO,
|
||||
List,
|
||||
Optional,
|
||||
Sequence,
|
||||
Tuple,
|
||||
Union,
|
||||
cast,
|
||||
)
|
||||
|
||||
import shlex
|
||||
@ -120,12 +120,13 @@ def makefile_log() -> List[str]:
|
||||
time.sleep(1)
|
||||
|
||||
# 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()
|
||||
stdout.close()
|
||||
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(
|
||||
@ -211,9 +212,10 @@ def build_defines_as_source() -> str:
|
||||
)
|
||||
|
||||
# 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]:
|
||||
|
@ -33,7 +33,7 @@ def main() -> None:
|
||||
blender_srcdir = Path(__file__).absolute().parent.parent.parent
|
||||
|
||||
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`.",
|
||||
)
|
||||
cli_parser.add_argument(
|
||||
|
@ -393,7 +393,7 @@ def floating_checkout_add_origin_if_needed(
|
||||
upstream_url = make_utils.git_get_remote_url(args.git_command, "upstream")
|
||||
|
||||
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))
|
||||
finally:
|
||||
|
1
extern/CMakeLists.txt
vendored
1
extern/CMakeLists.txt
vendored
@ -32,6 +32,7 @@ endif()
|
||||
add_subdirectory(rangetree)
|
||||
add_subdirectory(nanosvg)
|
||||
add_subdirectory(wcwidth)
|
||||
add_subdirectory(xxhash)
|
||||
|
||||
if(WITH_BULLET)
|
||||
if(NOT WITH_SYSTEM_BULLET)
|
||||
|
21
extern/xxhash/CMakeLists.txt
vendored
Normal file
21
extern/xxhash/CMakeLists.txt
vendored
Normal 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
26
extern/xxhash/LICENSE
vendored
Normal 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
6
extern/xxhash/README.blender
vendored
Normal 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
43
extern/xxhash/xxhash.c
vendored
Normal 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
6773
extern/xxhash/xxhash.h
vendored
Normal file
File diff suppressed because it is too large
Load Diff
@ -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. */
|
||||
const uint len_max = 65535;
|
||||
uint len_avail = cstr->len_alloc - cstr->len;
|
||||
while (true) {
|
||||
uint len_avail = cstr->len_alloc - cstr->len;
|
||||
|
||||
va_list args_cpy;
|
||||
va_copy(args_cpy, args);
|
||||
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. */
|
||||
break;
|
||||
}
|
||||
else if ((uint)retval <= len_avail) {
|
||||
|
||||
if ((uint)retval <= len_avail) {
|
||||
/* Copy was successful. */
|
||||
cstr->len += (uint)retval;
|
||||
break;
|
||||
}
|
||||
else {
|
||||
/* 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. */
|
||||
uint len_alloc = cstr->len + (uint)retval;
|
||||
if (len_alloc >= len_max) {
|
||||
/* Safe upper-limit, just in case... */
|
||||
break;
|
||||
}
|
||||
clg_str_reserve(cstr, len_alloc);
|
||||
len_avail = cstr->len_alloc - cstr->len;
|
||||
|
||||
/* `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. */
|
||||
uint len_alloc = cstr->len + (uint)retval;
|
||||
if (len_alloc >= len_max) {
|
||||
/* Safe upper-limit, just in case... */
|
||||
break;
|
||||
}
|
||||
|
||||
clg_str_reserve(cstr, len_alloc);
|
||||
len_avail = cstr->len_alloc - cstr->len;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -773,8 +773,9 @@ void OneapiDevice::get_adjusted_global_and_local_sizes(SyclQueue *queue,
|
||||
size_t &kernel_local_size)
|
||||
{
|
||||
assert(queue);
|
||||
|
||||
const static size_t preferred_work_group_size_intersect_shading = 32;
|
||||
const static size_t preferred_work_group_size_intersect = 128;
|
||||
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
|
||||
* to avoid usage of maximum work group sizes for them. */
|
||||
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_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;
|
||||
switch (kernel) {
|
||||
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_VOLUME_STACK:
|
||||
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_LIGHT:
|
||||
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_VOLUME:
|
||||
case DEVICE_KERNEL_INTEGRATOR_SHADE_SHADOW:
|
||||
case DEVICE_KERNEL_INTEGRATOR_SHADE_DEDICATED_LIGHT:
|
||||
preferred_work_group_size = preferred_work_group_size_intersect_shading;
|
||||
break;
|
||||
case DEVICE_KERNEL_INTEGRATOR_SHADE_DEDICATED_LIGHT: {
|
||||
const bool device_is_simd8 =
|
||||
(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:
|
||||
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;
|
||||
}
|
||||
|
||||
const size_t limit_work_group_size = reinterpret_cast<sycl::queue *>(queue)
|
||||
->get_device()
|
||||
.get_info<sycl::info::device::max_work_group_size>();
|
||||
|
||||
kernel_local_size = std::min(limit_work_group_size, preferred_work_group_size);
|
||||
kernel_local_size = std::min(max_work_group_size, preferred_work_group_size);
|
||||
|
||||
/* NOTE(@nsirgien): As for now non-uniform work-groups don't work on most oneAPI devices,
|
||||
* we extend work size to fit uniformity requirements. */
|
||||
|
@ -46,7 +46,7 @@ static const char *oidn_device_type_to_string(const OIDNDeviceType type)
|
||||
return "HIP";
|
||||
# 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))
|
||||
case OIDN_DEVICE_TYPE_METAL:
|
||||
return "METAL";
|
||||
|
@ -18,7 +18,7 @@ typedef struct HuangHairExtra {
|
||||
/* Optional modulation factors. */
|
||||
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;
|
||||
|
||||
/* Incident direction in local coordinate system. */
|
||||
|
@ -18,9 +18,8 @@
|
||||
#include "util/texture.h"
|
||||
#include "util/types.h"
|
||||
|
||||
/* 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.
|
||||
*/
|
||||
/* 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. */
|
||||
#if !defined(__KERNEL_GPU__) && defined(__x86_64__) && defined(__x86_64__) && \
|
||||
defined(__GNU_LIBRARY__) && defined(__GLIBC__) && defined(__GLIBC_MINOR__) && \
|
||||
(__GLIBC__ <= 2 && __GLIBC_MINOR__ < 16)
|
||||
|
@ -38,7 +38,7 @@
|
||||
#define ccl_global
|
||||
#define ccl_always_inline __attribute__((always_inline))
|
||||
#define ccl_device_inline inline
|
||||
#define ccl_noinline __attribute__((noinline))
|
||||
#define ccl_noinline
|
||||
#define ccl_inline_constant const constexpr
|
||||
#define ccl_device_constant static constexpr
|
||||
#define ccl_static_constexpr static constexpr
|
||||
|
@ -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 */
|
||||
ccl_device_inline float4 fastpow24_sse2(const float4 &arg)
|
||||
{
|
||||
/* max, avg and |avg| errors were calculated in gcc without FMA instructions
|
||||
* The final precision should be better than powf in glibc */
|
||||
/* `max`, `avg` and |avg| errors were calculated in GCC without FMA instructions.
|
||||
* The final precision should be better than `powf` in GLIBC. */
|
||||
|
||||
/* Calculate x^4/5, coefficient 0.994 was constructed manually to minimize avg error */
|
||||
/* 0x3F4CCCCD = 4/5 */
|
||||
|
@ -14,7 +14,7 @@ CCL_NAMESPACE_BEGIN
|
||||
thread::thread(function<void()> run_cb) : run_cb_(run_cb), joined_(false)
|
||||
{
|
||||
#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
|
||||
* predictable in general. */
|
||||
pthread_attr_t attribute;
|
||||
|
@ -427,7 +427,7 @@ struct GWL_Cursor {
|
||||
|
||||
/**
|
||||
* 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;
|
||||
/**
|
||||
@ -2507,7 +2507,9 @@ static const wl_cursor *gwl_seat_cursor_find_from_shape(GWL_Seat *seat,
|
||||
if (!cursor->wl.theme) {
|
||||
/* The cursor wl_surface hasn't entered an output yet. Initialize theme with scale 1. */
|
||||
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) {
|
||||
@ -3521,7 +3523,9 @@ static bool update_cursor_scale(GWL_Cursor &cursor,
|
||||
}
|
||||
wl_cursor_theme_destroy(cursor.wl.theme);
|
||||
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) {
|
||||
cursor.wl.theme_cursor = wl_cursor_theme_get_cursor(cursor.wl.theme,
|
||||
cursor.wl.theme_cursor_name);
|
||||
|
@ -115,10 +115,10 @@ void *MEM_lockfree_dupallocN(const void *vmemh)
|
||||
{
|
||||
void *newp = NULL;
|
||||
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);
|
||||
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(
|
||||
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;
|
||||
|
||||
if (vmemh) {
|
||||
MemHead *memh = MEMHEAD_FROM_PTR(vmemh);
|
||||
size_t old_len = MEM_lockfree_allocN_len(vmemh);
|
||||
const MemHead *memh = MEMHEAD_FROM_PTR(vmemh);
|
||||
const size_t old_len = MEM_lockfree_allocN_len(vmemh);
|
||||
|
||||
if (LIKELY(!MEMHEAD_IS_ALIGNED(memh))) {
|
||||
newp = MEM_lockfree_mallocN(len, "realloc");
|
||||
}
|
||||
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");
|
||||
}
|
||||
|
||||
@ -171,14 +171,14 @@ void *MEM_lockfree_recallocN_id(void *vmemh, size_t len, const char *str)
|
||||
void *newp = NULL;
|
||||
|
||||
if (vmemh) {
|
||||
MemHead *memh = MEMHEAD_FROM_PTR(vmemh);
|
||||
size_t old_len = MEM_lockfree_allocN_len(vmemh);
|
||||
const MemHead *memh = MEMHEAD_FROM_PTR(vmemh);
|
||||
const size_t old_len = MEM_lockfree_allocN_len(vmemh);
|
||||
|
||||
if (LIKELY(!MEMHEAD_IS_ALIGNED(memh))) {
|
||||
newp = MEM_lockfree_mallocN(len, "recalloc");
|
||||
}
|
||||
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");
|
||||
}
|
||||
|
||||
|
23
release/license/BSD-2-Clause.txt
Normal file
23
release/license/BSD-2-Clause.txt
Normal 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.
|
@ -84,7 +84,7 @@ def _kmi_properties_to_lines_recursive(level, properties, lines):
|
||||
lines_test = []
|
||||
_kmi_properties_to_lines_recursive(level + 2, value, lines_test)
|
||||
if lines_test:
|
||||
lines.append(f"(")
|
||||
lines.append("(")
|
||||
lines.append(f"\"{pname}\",\n")
|
||||
lines.append(f"{indent(level + 3)}" "[")
|
||||
lines.extend(lines_test)
|
||||
@ -172,19 +172,19 @@ def keyconfig_export_as_data(wm, kc, filepath, *, all_keymaps=False):
|
||||
fw("},\n")
|
||||
fw(f"{indent(2)}" "{")
|
||||
is_modal = km.is_modal
|
||||
fw(f"\"items\":\n")
|
||||
fw("\"items\":\n")
|
||||
fw(f"{indent(3)}[")
|
||||
for kmi in km.keymap_items:
|
||||
if is_modal:
|
||||
kmi_id = kmi.propvalue
|
||||
else:
|
||||
kmi_id = kmi.idname
|
||||
fw(f"(")
|
||||
fw("(")
|
||||
kmi_args = kmi_args_as_data(kmi)
|
||||
kmi_data = _kmi_attrs_or_none(4, kmi)
|
||||
fw(f"\"{kmi_id:s}\"")
|
||||
if kmi_data is None:
|
||||
fw(f", ")
|
||||
fw(", ")
|
||||
else:
|
||||
fw(",\n" f"{indent(5)}")
|
||||
|
||||
|
@ -6142,6 +6142,7 @@ def km_edit_curves(params):
|
||||
(op_tool_cycle, "builtin.tilt"), params),
|
||||
("transform.transform", {"type": 'S', "value": 'PRESS', "alt": True},
|
||||
{"properties": [("mode", 'CURVE_SHRINKFATTEN')]}),
|
||||
("curves.cyclic_toggle", {"type": 'C', "value": 'PRESS', "alt": True}, None),
|
||||
])
|
||||
|
||||
return keymap
|
||||
|
@ -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")
|
||||
|
||||
|
||||
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):
|
||||
bl_label = "Settings"
|
||||
|
||||
@ -257,6 +323,9 @@ classes = (
|
||||
DATA_PT_grease_pencil_layer_masks,
|
||||
DATA_PT_grease_pencil_layer_transform,
|
||||
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_custom_props,
|
||||
GREASE_PENCIL_MT_grease_pencil_add_layer_extra,
|
||||
|
@ -816,6 +816,27 @@ def brush_settings(layout, context, brush, popover=False):
|
||||
col.active = not brush.curves_sculpt_settings.use_point_count_interpolate
|
||||
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':
|
||||
layout.prop(brush.curves_sculpt_settings, "use_uniform_scale")
|
||||
layout.prop(brush.curves_sculpt_settings, "minimum_length")
|
||||
|
@ -671,8 +671,8 @@ class USERPREF_PT_system_os_settings(SystemPanel, CenterAlignMixIn, Panel):
|
||||
import sys
|
||||
return sys.platform[:3] == "win"
|
||||
|
||||
def draw_centered(self, _context, layout):
|
||||
if _context.preferences.system.is_microsoft_store_install:
|
||||
def draw_centered(self, context, layout):
|
||||
if context.preferences.system.is_microsoft_store_install:
|
||||
layout.label(text="Microsoft Store installation")
|
||||
layout.label(text="Use Windows 'Default Apps' to associate with blend files")
|
||||
else:
|
||||
|
@ -5911,6 +5911,8 @@ class VIEW3D_MT_edit_curves(Menu):
|
||||
layout.separator()
|
||||
layout.operator("curves.attribute_set")
|
||||
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)
|
||||
|
||||
|
||||
@ -7861,6 +7863,8 @@ class VIEW3D_PT_overlay_grease_pencil_options(Panel):
|
||||
'OBJECT': iface_("Grease Pencil"),
|
||||
}[context.mode], translate=False)
|
||||
|
||||
layout.prop(overlay, "use_gpencil_onion_skin", text="Onion Skin")
|
||||
|
||||
if ob.mode in {'EDIT'}:
|
||||
split = layout.split()
|
||||
col = split.column()
|
||||
|
@ -105,6 +105,7 @@ set(SRC_DNA_DEFAULTS_INC
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_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_grease_pencil_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_light_defaults.h
|
||||
|
@ -30,7 +30,7 @@ class BoneColor : public ::BoneColor {
|
||||
|
||||
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;
|
||||
uint64_t hash() const;
|
||||
|
@ -73,7 +73,8 @@ bool visualkey_can_use(PointerRNA *ptr, PropertyRNA *prop)
|
||||
has_parent = (pchan->parent != nullptr);
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -280,7 +280,7 @@ std::unique_ptr<AssetCatalogDefinitionFile> AssetCatalogDefinitionFile::copy_and
|
||||
continue;
|
||||
}
|
||||
|
||||
BLI_assert(!"A CDF should only reference known catalogs.");
|
||||
BLI_assert_msg(false, "A CDF should only reference known catalogs.");
|
||||
}
|
||||
|
||||
return copy;
|
||||
|
@ -35,7 +35,7 @@ void BKE_addon_pref_type_init(void);
|
||||
void BKE_addon_pref_type_free(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);
|
||||
bool BKE_addon_remove_safe(struct ListBase *addon_list, const char *module);
|
||||
void BKE_addon_free(struct bAddon *addon);
|
||||
|
@ -280,17 +280,17 @@ void BKE_pose_where_is_bone_tail(bPoseChannel *pchan);
|
||||
*/
|
||||
void BKE_pose_apply_action_selected_bones(Object *ob,
|
||||
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.
|
||||
*/
|
||||
void BKE_pose_apply_action_all_bones(Object *ob,
|
||||
bAction *action,
|
||||
AnimationEvalContext *anim_eval_context);
|
||||
const AnimationEvalContext *anim_eval_context);
|
||||
|
||||
void BKE_pose_apply_action_blend(Object *ob,
|
||||
bAction *action,
|
||||
AnimationEvalContext *anim_eval_context,
|
||||
const AnimationEvalContext *anim_eval_context,
|
||||
float blend_factor);
|
||||
|
||||
void vec_roll_to_mat3(const float vec[3], float roll, float r_mat[3][3]);
|
||||
|
@ -89,23 +89,11 @@ class BlobWriteSharing : NonCopyable, NonMovable {
|
||||
*/
|
||||
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
|
||||
* 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:
|
||||
~BlobWriteSharing();
|
||||
|
@ -11,7 +11,7 @@
|
||||
|
||||
#include "BLI_bounds_types.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_math_matrix_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 #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
|
||||
* of evaluated data.
|
||||
@ -460,6 +460,9 @@ class CurvesEditHints {
|
||||
|
||||
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
|
||||
* is the same as the number of original points.
|
||||
|
@ -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
|
||||
* passed in `layer_data`. If a #ImplicitSharingInfoHandle is passed in, its user count is
|
||||
* increased.
|
||||
* passed in `layer_data`. If a #ImplicitSharingInfo is passed in, its user count is increased.
|
||||
*/
|
||||
const void *CustomData_add_layer_with_data(CustomData *data,
|
||||
eCustomDataType type,
|
||||
void *layer_data,
|
||||
int totelem,
|
||||
const ImplicitSharingInfoHandle *sharing_info);
|
||||
const blender::ImplicitSharingInfo *sharing_info);
|
||||
|
||||
/**
|
||||
* Same as above but accepts a name.
|
||||
@ -272,7 +271,7 @@ const void *CustomData_add_layer_named_with_data(CustomData *data,
|
||||
void *layer_data,
|
||||
int totelem,
|
||||
blender::StringRef name,
|
||||
const ImplicitSharingInfoHandle *sharing_info);
|
||||
const blender::ImplicitSharingInfo *sharing_info);
|
||||
|
||||
void *CustomData_add_layer_anonymous(CustomData *data,
|
||||
eCustomDataType type,
|
||||
@ -285,7 +284,7 @@ const void *CustomData_add_layer_anonymous_with_data(
|
||||
const AnonymousAttributeIDHandle *anonymous_id,
|
||||
int totelem,
|
||||
void *layer_data,
|
||||
const ImplicitSharingInfoHandle *sharing_info);
|
||||
const blender::ImplicitSharingInfo *sharing_info);
|
||||
|
||||
/**
|
||||
* Frees the active or first data layer with the give type.
|
||||
|
@ -17,22 +17,38 @@ struct BMEditMesh;
|
||||
namespace blender::bke {
|
||||
|
||||
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;
|
||||
|
||||
/** 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;
|
||||
/**
|
||||
* 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;
|
||||
/** 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;
|
||||
};
|
||||
|
||||
} // namespace blender::bke
|
||||
|
||||
void BKE_editmesh_cache_ensure_face_normals(BMEditMesh &em, blender::bke::EditMeshData &emd);
|
||||
void BKE_editmesh_cache_ensure_vert_normals(BMEditMesh &em, blender::bke::EditMeshData &emd);
|
||||
blender::Span<blender::float3> BKE_editmesh_cache_ensure_face_normals(
|
||||
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(
|
||||
const BMEditMesh &em, const blender::bke::EditMeshData &emd);
|
||||
|
@ -14,6 +14,7 @@
|
||||
#include "BLI_array_utils.hh"
|
||||
#include "BLI_color.hh"
|
||||
#include "BLI_function_ref.hh"
|
||||
#include "BLI_implicit_sharing_ptr.hh"
|
||||
#include "BLI_map.hh"
|
||||
#include "BLI_math_matrix_types.hh"
|
||||
#include "BLI_math_vector_types.hh"
|
||||
@ -244,20 +245,23 @@ class TreeNode : public ::GreasePencilLayerTreeNode {
|
||||
/**
|
||||
* \returns this node as a #Layer.
|
||||
*/
|
||||
Layer &as_layer();
|
||||
const Layer &as_layer() const;
|
||||
Layer &as_layer();
|
||||
|
||||
/**
|
||||
* \returns this node as a #LayerGroup.
|
||||
*/
|
||||
LayerGroup &as_group();
|
||||
const LayerGroup &as_group() const;
|
||||
LayerGroup &as_group();
|
||||
|
||||
/**
|
||||
* \returns the parent layer group or nullptr for the root group.
|
||||
*/
|
||||
LayerGroup *parent_group() const;
|
||||
TreeNode *parent_node() const;
|
||||
const LayerGroup *parent_group() const;
|
||||
LayerGroup *parent_group();
|
||||
|
||||
const TreeNode *parent_node() const;
|
||||
TreeNode *parent_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.
|
||||
*/
|
||||
LayerGroup &parent_group() const;
|
||||
const LayerGroup &parent_group() const;
|
||||
LayerGroup &parent_group();
|
||||
|
||||
/**
|
||||
* \returns the frames mapping.
|
||||
@ -702,7 +707,8 @@ inline void TreeNode::set_selected(const bool selected)
|
||||
}
|
||||
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
|
||||
{
|
||||
@ -748,7 +754,11 @@ inline bool Layer::is_empty() const
|
||||
{
|
||||
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();
|
||||
}
|
||||
@ -773,7 +783,11 @@ class GreasePencilRuntime {
|
||||
|
||||
class GreasePencilDrawingEditHints {
|
||||
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();
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -83,7 +83,7 @@ bool BKE_linestyle_geometry_modifier_move(FreestyleLineStyle *linestyle,
|
||||
|
||||
void BKE_linestyle_modifier_list_color_ramps(FreestyleLineStyle *linestyle, ListBase *listbase);
|
||||
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);
|
||||
|
||||
|
@ -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_rename(struct Mask *mask,
|
||||
struct MaskLayer *masklay,
|
||||
char *oldname,
|
||||
char *newname);
|
||||
const char *oldname,
|
||||
const char *newname);
|
||||
|
||||
struct MaskLayer *BKE_mask_layer_copy(const struct MaskLayer *masklay);
|
||||
void BKE_mask_layer_copy_list(struct ListBase *masklayers_new, const struct ListBase *masklayers);
|
||||
|
@ -494,9 +494,6 @@ bool BKE_mesh_validate_all_customdata(CustomData *vert_data,
|
||||
|
||||
void BKE_mesh_strip_loose_faces(Mesh *mesh);
|
||||
|
||||
/* In DerivedMesh.cc */
|
||||
void BKE_mesh_wrapper_deferred_finalize_mdata(Mesh *mesh_eval);
|
||||
|
||||
/* **** Depsgraph evaluation **** */
|
||||
|
||||
void BKE_mesh_eval_geometry(Depsgraph *depsgraph, Mesh *mesh);
|
||||
|
@ -163,11 +163,6 @@ struct MeshRuntime {
|
||||
|
||||
/** #eMeshWrapperType and others. */
|
||||
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
|
||||
|
@ -87,7 +87,7 @@ void BKE_movieclip_build_proxy_frame(struct MovieClip *clip,
|
||||
int clip_flag,
|
||||
struct MovieDistortion *distortion,
|
||||
int cfra,
|
||||
int *build_sizes,
|
||||
const int *build_sizes,
|
||||
int build_count,
|
||||
bool undistorted);
|
||||
|
||||
@ -99,7 +99,7 @@ void BKE_movieclip_build_proxy_frame_for_ibuf(struct MovieClip *clip,
|
||||
struct ImBuf *ibuf,
|
||||
struct MovieDistortion *distortion,
|
||||
int cfra,
|
||||
int *build_sizes,
|
||||
const int *build_sizes,
|
||||
int build_count,
|
||||
bool undistorted);
|
||||
bool BKE_movieclip_proxy_enabled(struct MovieClip *clip);
|
||||
|
@ -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,
|
||||
const char *filepath_rel,
|
||||
struct PackedFile *pf);
|
||||
const struct PackedFile *pf);
|
||||
|
||||
/* Read. */
|
||||
|
||||
@ -143,7 +143,7 @@ void BKE_packedfile_id_unpack(struct Main *bmain,
|
||||
struct ReportList *reports,
|
||||
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);
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
@ -220,11 +220,8 @@ void BKE_subdiv_ccg_topology_counters(const SubdivCCG &subdiv_ccg,
|
||||
int &r_num_loops);
|
||||
|
||||
struct SubdivCCGNeighbors {
|
||||
SubdivCCGCoord *coords;
|
||||
int size;
|
||||
blender::Array<SubdivCCGCoord, 256> coords;
|
||||
int num_duplicates;
|
||||
|
||||
SubdivCCGCoord coords_fixed[256];
|
||||
};
|
||||
|
||||
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. */
|
||||
|
||||
/* 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
|
||||
* the current vertex are added at the end of the coords array. */
|
||||
|
@ -65,7 +65,7 @@ void txt_clean_text(struct Text *text);
|
||||
void txt_order_cursors(struct Text *text, bool reverse);
|
||||
int txt_find_string(struct Text *text, const char *findstr, int wrap, int match_case);
|
||||
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_down(struct Text *text, bool sel);
|
||||
void txt_move_left(struct Text *text, bool sel);
|
||||
|
@ -579,6 +579,7 @@ set(LIB
|
||||
bf_shader_fx
|
||||
bf_simulation
|
||||
PRIVATE bf::extern::fmtlib
|
||||
PRIVATE bf::extern::xxhash
|
||||
PRIVATE bf::intern::atomic
|
||||
# For `vfontdata_freetype.c`.
|
||||
${FREETYPE_LIBRARIES} ${BROTLI_LIBRARIES}
|
||||
|
@ -221,7 +221,8 @@ struct CCGSubSurf {
|
||||
(void)0
|
||||
#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[1] = _b[1]; \
|
||||
_a[2] = _b[2]; \
|
||||
@ -229,7 +230,8 @@ struct CCGSubSurf {
|
||||
(void)0
|
||||
#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[1] += _b[1]; \
|
||||
_a[2] += _b[2]; \
|
||||
|
@ -70,12 +70,16 @@ static float *_face_getIFNoEdge(CCGFace *f,
|
||||
static void _face_calcIFNo(
|
||||
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));
|
||||
float *b = static_cast<float *>(ccg_face_getIFCo(f, lvl, S, x + 1, y + 0, levels, dataSize));
|
||||
float *c = static_cast<float *>(ccg_face_getIFCo(f, lvl, S, x + 1, y + 1, levels, dataSize));
|
||||
float *d = static_cast<float *>(ccg_face_getIFCo(f, lvl, S, x + 0, y + 1, levels, dataSize));
|
||||
float a_cX = c[0] - a[0], a_cY = c[1] - a[1], a_cZ = c[2] - a[2];
|
||||
float b_dX = d[0] - b[0], b_dY = d[1] - b[1], b_dZ = d[2] - b[2];
|
||||
const float *a = static_cast<float *>(
|
||||
ccg_face_getIFCo(f, lvl, S, x + 0, y + 0, levels, dataSize));
|
||||
const float *b = static_cast<float *>(
|
||||
ccg_face_getIFCo(f, lvl, S, x + 1, y + 0, levels, dataSize));
|
||||
const float *c = static_cast<float *>(
|
||||
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[1] = b_dZ * a_cX - b_dX * a_cZ;
|
||||
|
@ -89,8 +89,6 @@ using blender::bke::MeshComponent;
|
||||
#endif
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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
|
||||
* 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;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
switch (mesh->runtime->wrapper_type) {
|
||||
@ -1244,12 +1202,6 @@ static void editbmesh_calc_modifiers(Depsgraph *depsgraph,
|
||||
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. */
|
||||
*r_final = mesh_final;
|
||||
if (r_cage) {
|
||||
|
@ -350,8 +350,8 @@ void action_group_colors_sync(bActionGroup *grp, const bActionGroup *ref_grp)
|
||||
if (grp->customCol) {
|
||||
if (grp->customCol > 0) {
|
||||
/* copy theme colors on-to group's custom color in case user tries to edit color */
|
||||
bTheme *btheme = static_cast<bTheme *>(U.themes.first);
|
||||
ThemeWireColor *col_set = &btheme->tarm[(grp->customCol - 1)];
|
||||
const bTheme *btheme = static_cast<const bTheme *>(U.themes.first);
|
||||
const ThemeWireColor *col_set = &btheme->tarm[(grp->customCol - 1)];
|
||||
|
||||
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) */
|
||||
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. */
|
||||
workob->runtime = nullptr;
|
||||
|
@ -38,7 +38,7 @@ bAddon *BKE_addon_new()
|
||||
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)));
|
||||
}
|
||||
|
@ -2850,8 +2850,9 @@ static void nlastrip_evaluate_transition(const int evaluation_mode,
|
||||
break;
|
||||
}
|
||||
case STRIP_EVAL_NOBLEND: {
|
||||
BLI_assert( !"This case shouldn't occur. Transitions assumed to not reference other "
|
||||
"transitions. ");
|
||||
BLI_assert_msg(false,
|
||||
"This case shouldn't occur. "
|
||||
"Transitions assumed to not reference other transitions.");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -34,14 +34,14 @@ void pose_apply_restore_fcurves(bAction *action);
|
||||
|
||||
void pose_apply(Object *ob,
|
||||
bAction *action,
|
||||
AnimationEvalContext *anim_eval_context,
|
||||
const AnimationEvalContext *anim_eval_context,
|
||||
ActionApplier applier);
|
||||
|
||||
} // namespace
|
||||
|
||||
void BKE_pose_apply_action_selected_bones(Object *ob,
|
||||
bAction *action,
|
||||
AnimationEvalContext *anim_eval_context)
|
||||
const AnimationEvalContext *anim_eval_context)
|
||||
{
|
||||
auto evaluate_and_apply =
|
||||
[](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,
|
||||
bAction *action,
|
||||
AnimationEvalContext *anim_eval_context)
|
||||
const AnimationEvalContext *anim_eval_context)
|
||||
{
|
||||
PointerRNA pose_owner_ptr = RNA_id_pointer_create(&ob->id);
|
||||
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,
|
||||
bAction *action,
|
||||
AnimationEvalContext *anim_eval_context,
|
||||
const AnimationEvalContext *anim_eval_context,
|
||||
const float blend_factor)
|
||||
{
|
||||
auto evaluate_and_blend = [blend_factor](PointerRNA *ptr,
|
||||
@ -76,7 +76,7 @@ void BKE_pose_apply_action_blend(Object *ob,
|
||||
namespace {
|
||||
void pose_apply(Object *ob,
|
||||
bAction *action,
|
||||
AnimationEvalContext *anim_eval_context,
|
||||
const AnimationEvalContext *anim_eval_context,
|
||||
ActionApplier applier)
|
||||
{
|
||||
bPose *pose = ob->pose;
|
||||
|
@ -338,7 +338,7 @@ static int position_tail_on_spline(bSplineIKConstraint *ik_data,
|
||||
}
|
||||
|
||||
/* 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 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;
|
||||
}
|
||||
|
||||
x2 = x1 - f_x1 * (x1 - x0) / (f_x1 - f_x0);
|
||||
const float x2 = x1 - f_x1 * (x1 - x0) / (f_x1 - f_x0);
|
||||
x0 = x1;
|
||||
x1 = x2;
|
||||
}
|
||||
|
@ -14,7 +14,6 @@
|
||||
|
||||
#include "BLI_endian_defines.h"
|
||||
#include "BLI_endian_switch.h"
|
||||
#include "BLI_hash_md5.hh"
|
||||
#include "BLI_math_matrix_types.hh"
|
||||
#include "BLI_path_util.h"
|
||||
|
||||
@ -26,6 +25,7 @@
|
||||
|
||||
#include <fmt/format.h>
|
||||
#include <sstream>
|
||||
#include <xxhash.h>
|
||||
|
||||
#ifdef WITH_OPENVDB
|
||||
# include <openvdb/io/Stream.h>
|
||||
@ -192,8 +192,7 @@ DictionaryValuePtr BlobWriteSharing::write_implicitly_shared(
|
||||
std::shared_ptr<io::serialize::DictionaryValue> BlobWriteSharing::write_deduplicated(
|
||||
BlobWriter &writer, const void *data, const int64_t size_in_bytes)
|
||||
{
|
||||
SliceHash content_hash;
|
||||
BLI_hash_md5_buffer(static_cast<const char *>(data), size_in_bytes, &content_hash);
|
||||
const uint64_t content_hash = XXH3_64bits(data, size_in_bytes);
|
||||
const BlobSlice slice = slice_by_content_hash_.lookup_or_add_cb(
|
||||
content_hash, [&]() { return writer.write(data, size_in_bytes); });
|
||||
return slice.serialize();
|
||||
|
@ -182,7 +182,7 @@ static BlendHandle *link_append_context_library_blohandle_ensure(
|
||||
lib_context->bf_reports.reports = reports;
|
||||
}
|
||||
|
||||
char *libname = lib_context->path;
|
||||
const char *libname = lib_context->path;
|
||||
BlendHandle *blo_handle = lib_context->blo_handle;
|
||||
if (blo_handle == nullptr) {
|
||||
if (STREQ(libname, BLO_EMBEDDED_STARTUP_BLEND)) {
|
||||
@ -1410,7 +1410,7 @@ void BKE_blendfile_link(BlendfileLinkAppendContext *lapp_context, ReportList *re
|
||||
{
|
||||
BlendfileLinkAppendContextLibrary *lib_context =
|
||||
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(
|
||||
lapp_context, lib_context, reports);
|
||||
|
||||
|
@ -1359,8 +1359,6 @@ bool BKE_collection_object_add_notest(Main *bmain, Collection *collection, Objec
|
||||
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
|
||||
* never be reached. */
|
||||
BLI_assert(collection != nullptr);
|
||||
@ -1368,6 +1366,7 @@ bool BKE_collection_object_add_notest(Main *bmain, Collection *collection, Objec
|
||||
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)) {
|
||||
return false;
|
||||
}
|
||||
|
@ -1659,6 +1659,64 @@ static bConstraintTypeInfo CTI_LOCLIMIT = {
|
||||
|
||||
/* -------- 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*/)
|
||||
{
|
||||
bRotLimitConstraint *data = static_cast<bRotLimitConstraint *>(con->data);
|
||||
@ -1693,31 +1751,13 @@ static void rotlimit_evaluate(bConstraint *con, bConstraintOb *cob, ListBase * /
|
||||
|
||||
/* limiting of euler values... */
|
||||
if (data->flag & LIMIT_XROT) {
|
||||
if (eul[0] < data->xmin) {
|
||||
eul[0] = data->xmin;
|
||||
}
|
||||
|
||||
if (eul[0] > data->xmax) {
|
||||
eul[0] = data->xmax;
|
||||
}
|
||||
eul[0] = clamp_angle(eul[0], data->xmin, data->xmax);
|
||||
}
|
||||
if (data->flag & LIMIT_YROT) {
|
||||
if (eul[1] < data->ymin) {
|
||||
eul[1] = data->ymin;
|
||||
}
|
||||
|
||||
if (eul[1] > data->ymax) {
|
||||
eul[1] = data->ymax;
|
||||
}
|
||||
eul[1] = clamp_angle(eul[1], data->ymin, data->ymax);
|
||||
}
|
||||
if (data->flag & LIMIT_ZROT) {
|
||||
if (eul[2] < data->zmin) {
|
||||
eul[2] = data->zmin;
|
||||
}
|
||||
|
||||
if (eul[2] > data->zmax) {
|
||||
eul[2] = data->zmax;
|
||||
}
|
||||
eul[2] = clamp_angle(eul[2], data->zmin, data->zmax);
|
||||
}
|
||||
|
||||
loc_eulO_size_to_mat4(cob->matrix, loc, eul, size, rot_order);
|
||||
|
@ -599,9 +599,9 @@ GeometryDeformation get_evaluated_curves_deformation(const Object *ob_eval, cons
|
||||
if (edit_component_eval != nullptr) {
|
||||
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->positions.has_value()) {
|
||||
BLI_assert(edit_hints->positions->size() == points_num);
|
||||
deformation.positions = *edit_hints->positions;
|
||||
if (const std::optional<Span<float3>> positions = edit_hints->positions()) {
|
||||
BLI_assert(positions->size() == points_num);
|
||||
deformation.positions = *positions;
|
||||
uses_extra_positions = true;
|
||||
}
|
||||
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());
|
||||
const GreasePencilDrawingEditHints &drawing_hints =
|
||||
edit_hints->drawing_hints.value()[layer_index];
|
||||
if (drawing_hints.positions.has_value()) {
|
||||
deformation.positions = *drawing_hints.positions;
|
||||
if (const std::optional<Span<float3>> positions = drawing_hints.positions()) {
|
||||
deformation.positions = *positions;
|
||||
return deformation;
|
||||
}
|
||||
}
|
||||
|
@ -4750,7 +4750,6 @@ bool BKE_nurb_valid_message(const int pnts,
|
||||
NURBSValidationStatus status = nurb_check_valid(
|
||||
pnts, order, flag, type, is_surf, &points_needed);
|
||||
|
||||
const char *msg_template = nullptr;
|
||||
switch (status) {
|
||||
case NURBSValidationStatus::Valid:
|
||||
message_dst[0] = 0;
|
||||
@ -4761,20 +4760,24 @@ bool BKE_nurb_valid_message(const int pnts,
|
||||
message_dst[0] = 0;
|
||||
return false;
|
||||
}
|
||||
msg_template = RPT_("At least two points required");
|
||||
BLI_strncpy(message_dst, RPT_("At least two points required"), maxncpy);
|
||||
break;
|
||||
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;
|
||||
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;
|
||||
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;
|
||||
}
|
||||
|
||||
BLI_snprintf(message_dst, maxncpy, msg_template, points_needed, dir == 0 ? "U" : "V");
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -333,8 +333,8 @@ CurvesSurfaceTransforms::CurvesSurfaceTransforms(const Object &curves_ob, const
|
||||
bool CurvesEditHints::is_valid() const
|
||||
{
|
||||
const int point_num = this->curves_id_orig.geometry.point_num;
|
||||
if (this->positions.has_value()) {
|
||||
if (this->positions->size() != point_num) {
|
||||
if (this->positions().has_value()) {
|
||||
if (this->positions()->size() != point_num) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@ -346,6 +346,35 @@ bool CurvesEditHints::is_valid() const
|
||||
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)
|
||||
{
|
||||
const bke::CurvesFieldContext context(curves, AttrDomain::Point);
|
||||
|
@ -1754,8 +1754,8 @@ static const LayerTypeInfo LAYERTYPEINFO[CD_NUMTYPES] = {
|
||||
nullptr,
|
||||
nullptr},
|
||||
/* 18: CD_TANGENT */
|
||||
{sizeof(float[4][4]),
|
||||
alignof(float[4][4]),
|
||||
{sizeof(float[4]),
|
||||
alignof(float[4]),
|
||||
"",
|
||||
0,
|
||||
N_("Tangent"),
|
||||
|
@ -17,14 +17,18 @@
|
||||
#include "BKE_editmesh.hh"
|
||||
#include "BKE_editmesh_cache.hh" /* own include */
|
||||
|
||||
using blender::float3;
|
||||
using blender::Span;
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \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()) {
|
||||
return;
|
||||
return emd.face_normals;
|
||||
}
|
||||
BMesh *bm = em.bm;
|
||||
|
||||
@ -36,37 +40,35 @@ void BKE_editmesh_cache_ensure_face_normals(BMEditMesh &em, blender::bke::EditMe
|
||||
int i;
|
||||
BM_ITER_MESH_INDEX (efa, &fiter, bm, BM_FACES_OF_MESH, i) {
|
||||
BM_elem_index_set(efa, i); /* set_inline */
|
||||
BM_face_calc_normal_vcos(bm,
|
||||
efa,
|
||||
emd.face_normals[i],
|
||||
reinterpret_cast<const float(*)[3]>(emd.vert_positions.data()));
|
||||
BM_face_calc_normal_vcos(bm, efa, emd.face_normals[i], emd.vert_positions);
|
||||
}
|
||||
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()) {
|
||||
return;
|
||||
return emd.vert_normals;
|
||||
}
|
||||
BMesh *bm = em.bm;
|
||||
|
||||
/* 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);
|
||||
|
||||
BM_mesh_elem_index_ensure(bm, BM_FACE);
|
||||
BM_verts_calc_normal_vcos(bm,
|
||||
reinterpret_cast<const float(*)[3]>(emd.face_normals.data()),
|
||||
reinterpret_cast<const float(*)[3]>(emd.vert_positions.data()),
|
||||
reinterpret_cast<float(*)[3]>(emd.vert_normals.data()));
|
||||
BM_verts_calc_normal_vcos(bm, face_normals, emd.vert_positions, emd.vert_normals);
|
||||
return emd.vert_normals;
|
||||
}
|
||||
|
||||
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()) {
|
||||
return;
|
||||
return emd.face_centers;
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
return emd.face_centers;
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
@ -700,9 +700,9 @@ bool get_effector_data(EffectorCache *eff,
|
||||
else if (eff->pd && eff->pd->shape == PFIELD_SHAPE_POINTS) {
|
||||
/* TODO: hair and points object support */
|
||||
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) {
|
||||
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->nor, vert_normals[*efd->index]);
|
||||
|
||||
|
@ -40,25 +40,37 @@ void GeometryComponentEditData::clear()
|
||||
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(
|
||||
const Curves *curves_id, GeometryComponentEditData &edit_component)
|
||||
{
|
||||
if (!edit_component.curves_edit_hints_) {
|
||||
return;
|
||||
}
|
||||
if (edit_component.curves_edit_hints_->positions.has_value()) {
|
||||
if (curves_id == nullptr) {
|
||||
return;
|
||||
}
|
||||
if (curves_id == nullptr) {
|
||||
CurvesEditHints &edit_hints = *edit_component.curves_edit_hints_;
|
||||
if (edit_hints.positions().has_value()) {
|
||||
return;
|
||||
}
|
||||
const CurvesGeometry &curves = curves_id->geometry.wrap();
|
||||
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;
|
||||
}
|
||||
edit_component.curves_edit_hints_->positions.emplace(points_num);
|
||||
edit_component.curves_edit_hints_->positions->as_mutable_span().copy_from(curves.positions());
|
||||
edit_hints.positions_data = save_shared_attribute(curves.attributes().lookup("position"));
|
||||
}
|
||||
|
||||
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(
|
||||
orig_layer, grease_pencil->runtime->eval_frame);
|
||||
GreasePencilDrawingEditHints &drawing_hints = all_hints[layer_index];
|
||||
|
||||
if (!drawing || !orig_drawing) {
|
||||
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;
|
||||
}
|
||||
drawing_hints.positions.emplace(drawing->strokes().positions());
|
||||
drawing_hints.positions_data = save_shared_attribute(curves.attributes().lookup("position"));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
gps_dst->hardness = gps_src->hardness;
|
||||
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_max, gps_src->boundbox_max);
|
||||
gps_dst->uv_rotation = gps_src->uv_rotation;
|
||||
|
@ -42,6 +42,7 @@
|
||||
#include "BLI_string.h"
|
||||
#include "BLI_string_ref.hh"
|
||||
#include "BLI_string_utils.hh"
|
||||
#include "BLI_utildefines.h"
|
||||
#include "BLI_vector_set.hh"
|
||||
#include "BLI_virtual_array.hh"
|
||||
|
||||
@ -52,6 +53,7 @@
|
||||
#include "DNA_ID.h"
|
||||
#include "DNA_ID_enums.h"
|
||||
#include "DNA_brush_types.h"
|
||||
#include "DNA_defaults.h"
|
||||
#include "DNA_gpencil_modifier_types.h"
|
||||
#include "DNA_grease_pencil_types.h"
|
||||
#include "DNA_material_types.h"
|
||||
@ -80,10 +82,12 @@ static void grease_pencil_init_data(ID *id)
|
||||
using namespace blender::bke;
|
||||
|
||||
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->active_layer = nullptr;
|
||||
grease_pencil->flag |= GREASE_PENCIL_ANIM_CHANNEL_EXPANDED;
|
||||
|
||||
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];
|
||||
|
||||
/* 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 *
|
||||
@ -766,7 +770,7 @@ TreeNode::TreeNode()
|
||||
this->parent = 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;
|
||||
}
|
||||
|
||||
@ -819,12 +823,19 @@ Layer &TreeNode::as_layer()
|
||||
return *reinterpret_cast<Layer *>(this);
|
||||
}
|
||||
|
||||
LayerGroup *TreeNode::parent_group() const
|
||||
const LayerGroup *TreeNode::parent_group() const
|
||||
{
|
||||
return (this->parent) ? &this->parent->wrap() : nullptr;
|
||||
}
|
||||
|
||||
TreeNode *TreeNode::parent_node() const
|
||||
LayerGroup *TreeNode::parent_group()
|
||||
{
|
||||
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;
|
||||
}
|
||||
@ -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. */
|
||||
this->runtime->frames_ = other.runtime->frames_;
|
||||
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();
|
||||
|
||||
/* TODO: what about masks cache? */
|
||||
@ -1570,6 +1581,40 @@ void LayerGroup::update_from_dna_read()
|
||||
|
||||
} // 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
|
||||
* \{ */
|
||||
|
@ -172,6 +172,10 @@ static void find_used_vertex_groups(const bGPDframe &gpf,
|
||||
Span<MDeformVert> dverts = {gps->dvert, gps->totpoints};
|
||||
for (const MDeformVert &dvert : dverts) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
@ -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));
|
||||
const MutableSpan<MDeformWeight> vertex_weights = {dst_dvert.dw, dst_dvert.totweight};
|
||||
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. */
|
||||
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 =
|
||||
attributes.lookup_or_add_for_write_span<float>("aspect_ratio", AttrDomain::Curve);
|
||||
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>(
|
||||
"material_index", AttrDomain::Curve);
|
||||
|
||||
@ -573,8 +585,8 @@ void legacy_gpencil_to_grease_pencil(Main &bmain, GreasePencil &grease_pencil, b
|
||||
SET_FLAG_FROM_TEST(
|
||||
new_layer.base.flag, (gpl->flag & GP_LAYER_USE_LIGHTS), GP_LAYER_TREE_NODE_USE_LIGHTS);
|
||||
SET_FLAG_FROM_TEST(new_layer.base.flag,
|
||||
(gpl->onion_flag & GP_LAYER_ONIONSKIN),
|
||||
GP_LAYER_TREE_NODE_USE_ONION_SKINNING);
|
||||
(gpl->onion_flag & GP_LAYER_ONIONSKIN) == 0,
|
||||
GP_LAYER_TREE_NODE_HIDE_ONION_SKINNING);
|
||||
SET_FLAG_FROM_TEST(
|
||||
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;
|
||||
|
||||
/* Convert the onion skinning settings. */
|
||||
grease_pencil.onion_skinning_settings.opacity = gpd.onion_factor;
|
||||
grease_pencil.onion_skinning_settings.mode = gpd.onion_mode;
|
||||
GreasePencilOnionSkinningSettings &settings = grease_pencil.onion_skinning_settings;
|
||||
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) {
|
||||
grease_pencil.onion_skinning_settings.filter = GREASE_PENCIL_ONION_SKINNING_FILTER_ALL;
|
||||
settings.filter = GREASE_PENCIL_ONION_SKINNING_FILTER_ALL;
|
||||
}
|
||||
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;
|
||||
grease_pencil.onion_skinning_settings.num_frames_after = gpd.gstep_next;
|
||||
copy_v3_v3(grease_pencil.onion_skinning_settings.color_before, gpd.gcolor_prev);
|
||||
copy_v3_v3(grease_pencil.onion_skinning_settings.color_after, gpd.gcolor_next);
|
||||
settings.num_frames_before = gpd.gstep;
|
||||
settings.num_frames_after = gpd.gstep_next;
|
||||
copy_v3_v3(settings.color_before, gpd.gcolor_prev);
|
||||
copy_v3_v3(settings.color_after, gpd.gcolor_next);
|
||||
|
||||
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
|
||||
* 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:
|
||||
* * 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
|
||||
* temporary vectors.
|
||||
* * 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));
|
||||
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) {
|
||||
auto adjustment_animation_detection = [&](bAction *owner_action, FCurve &fcurve) -> bool {
|
||||
/* Early out if we already know that both data are animated. */
|
||||
|
@ -457,9 +457,7 @@ static ImageGPUTextures image_get_gpu_texture(Image *ima,
|
||||
|
||||
if (GPU_mipmap_enabled()) {
|
||||
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);
|
||||
}
|
||||
else {
|
||||
@ -624,8 +622,8 @@ void BKE_image_free_old_gputextures(Main *bmain)
|
||||
/** \name Paint Update
|
||||
* \{ */
|
||||
|
||||
static ImBuf *update_do_scale(uchar *rect,
|
||||
float *rect_float,
|
||||
static ImBuf *update_do_scale(const uchar *rect,
|
||||
const float *rect_float,
|
||||
int *x,
|
||||
int *y,
|
||||
int *w,
|
||||
@ -664,8 +662,8 @@ static ImBuf *update_do_scale(uchar *rect,
|
||||
}
|
||||
|
||||
static void gpu_texture_update_scaled(GPUTexture *tex,
|
||||
uchar *rect,
|
||||
float *rect_float,
|
||||
const uchar *rect,
|
||||
const float *rect_float,
|
||||
int full_w,
|
||||
int full_h,
|
||||
int x,
|
||||
|
@ -431,9 +431,7 @@ static void layer_aov_copy_data(ViewLayer *view_layer_dst,
|
||||
ListBase *aovs_dst,
|
||||
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);
|
||||
const ViewLayerAOV *aov_src = static_cast<const ViewLayerAOV *>(aovs_src->first);
|
||||
|
@ -287,5 +287,5 @@ int64_t BKE_lightprobe_grid_cache_frame_sample_count(const LightProbeGridCacheFr
|
||||
return cache->block_len * cube_i(cache->block_size);
|
||||
}
|
||||
/* 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];
|
||||
}
|
||||
|
@ -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,
|
||||
ColorBand *color_ramp)
|
||||
const ColorBand *color_ramp)
|
||||
{
|
||||
bool found = false;
|
||||
|
||||
|
@ -340,7 +340,10 @@ void BKE_mask_layer_unique_name(Mask *mask, MaskLayer *masklay)
|
||||
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);
|
||||
|
||||
|
@ -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
|
||||
* 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;
|
||||
Base *base;
|
||||
Object *bob;
|
||||
MetaBall *mb;
|
||||
const MetaElem *ml;
|
||||
float obinv[4][4], obmat[4][4];
|
||||
uint i;
|
||||
int obnr, zero_size = 0;
|
||||
int obnr;
|
||||
char obname[MAX_ID_NAME];
|
||||
SceneBaseIter iter;
|
||||
const eEvaluationMode deg_eval_mode = DEG_get_mode(depsgraph);
|
||||
const short parenting_dupli_transflag = (OB_DUPLIFACES | OB_DUPLIVERTS);
|
||||
|
||||
copy_m4_m4(
|
||||
obmat,
|
||||
ob->object_to_world().ptr()); /* to cope with duplicators from BKE_scene_base_iter_next */
|
||||
/* Copy object matrices to cope with duplicators from #BKE_scene_base_iter_next. */
|
||||
float obinv[4][4], obmat[4][4];
|
||||
copy_m4_m4(obmat, 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);
|
||||
@ -1188,187 +1197,154 @@ static void init_meta(Depsgraph *depsgraph, PROCESS *process, Scene *scene, Obje
|
||||
/* make main array */
|
||||
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)) {
|
||||
if (bob->type == OB_MBALL) {
|
||||
zero_size = 0;
|
||||
ml = nullptr;
|
||||
if (bob->type != OB_MBALL) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* If this metaball is the original that's used for duplication, only have it visible when
|
||||
* the instancer is visible too. */
|
||||
if ((base->flag_legacy & OB_FROMDUPLI) == 0 && ob->parent != nullptr &&
|
||||
(ob->parent->transflag & parenting_dupli_transflag) != 0 &&
|
||||
(BKE_object_visibility(ob->parent, deg_eval_mode) & OB_VISIBLE_SELF) == 0)
|
||||
{
|
||||
/* If this metaball is the original that's used for duplication, only have it visible when
|
||||
* the instancer is visible too. */
|
||||
if ((base->flag_legacy & OB_FROMDUPLI) == 0 && ob->parent != nullptr &&
|
||||
(ob->parent->transflag & parenting_dupli_transflag) != 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;
|
||||
}
|
||||
}
|
||||
|
||||
if (bob == ob && (base->flag_legacy & OB_FROMDUPLI) == 0) {
|
||||
mb = static_cast<MetaBall *>(ob->data);
|
||||
/* When metaball object has zero scale, then MetaElem to this MetaBall
|
||||
* will not be put to `mainb` array. */
|
||||
if (object_has_zero_axis_matrix(bob)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (mb->editelems) {
|
||||
ml = static_cast<const MetaElem *>(mb->editelems->first);
|
||||
}
|
||||
else {
|
||||
ml = static_cast<const MetaElem *>(mb->elems.first);
|
||||
}
|
||||
const MetaBall *mb = static_cast<MetaBall *>(bob->data);
|
||||
LISTBASE_FOREACH (const MetaElem *, ml, (mb->editelems ? mb->editelems : &mb->elems)) {
|
||||
if (ml->flag & MB_HIDE) {
|
||||
continue;
|
||||
}
|
||||
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 {
|
||||
char name[MAX_ID_NAME];
|
||||
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);
|
||||
}
|
||||
}
|
||||
new_ml->s = ml->s;
|
||||
}
|
||||
|
||||
/* when metaball object has zero scale, then MetaElem to this MetaBall
|
||||
* will not be put to mainb array */
|
||||
if (has_zero_axis_m4(bob->object_to_world().ptr())) {
|
||||
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 metaball is negative, set stiffness negative */
|
||||
if (new_ml->flag & MB_NEGATIVE) {
|
||||
new_ml->s = -new_ml->s;
|
||||
}
|
||||
|
||||
if (zero_size) {
|
||||
while (ml) {
|
||||
ml = ml->next;
|
||||
}
|
||||
/* 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;
|
||||
}
|
||||
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 */
|
||||
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 {
|
||||
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;
|
||||
}
|
||||
/* Transformation of meta-elem bounding-box. */
|
||||
for (uint 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 (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) {
|
||||
copy_v3_v3(process->allbb.min, process->mainb[0]->bb->vec[0]);
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
@ -113,7 +113,6 @@ static void mesh_copy_data(Main *bmain,
|
||||
mesh_dst->runtime = new blender::bke::MeshRuntime();
|
||||
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_finalize = mesh_src->runtime->wrapper_type_finalize;
|
||||
mesh_dst->runtime->subsurf_runtime_data = mesh_src->runtime->subsurf_runtime_data;
|
||||
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
|
||||
|
@ -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()); });
|
||||
}
|
||||
|
||||
static void add_existing_edges_to_hash_maps(Mesh &mesh,
|
||||
MutableSpan<EdgeMap> edge_maps,
|
||||
uint32_t parallel_mask)
|
||||
static void add_existing_edges_to_hash_maps(const Mesh &mesh,
|
||||
const uint32_t parallel_mask,
|
||||
MutableSpan<EdgeMap> edge_maps)
|
||||
{
|
||||
/* Assume existing edges are valid. */
|
||||
const Span<int2> edges = mesh.edges();
|
||||
threading::parallel_for_each(edge_maps, [&](EdgeMap &edge_map) {
|
||||
const int task_index = &edge_map - edge_maps.data();
|
||||
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. */
|
||||
if (task_index == (parallel_mask & edge_hash_2(ordered_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,
|
||||
MutableSpan<EdgeMap> edge_maps,
|
||||
uint32_t parallel_mask)
|
||||
static void add_face_edges_to_hash_maps(const Mesh &mesh,
|
||||
const 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();
|
||||
threading::parallel_for_each(edge_maps, [&](EdgeMap &edge_map) {
|
||||
const int task_index = &edge_map - edge_maps.data();
|
||||
for (const int i : faces.index_range()) {
|
||||
const Span<int> face_verts = corner_verts.slice(faces[i]);
|
||||
int vert_prev = face_verts.last();
|
||||
for (const int vert : face_verts) {
|
||||
for (const int face_i : faces.index_range()) {
|
||||
const IndexRange face = faces[face_i];
|
||||
for (const int corner : face) {
|
||||
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. */
|
||||
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. */
|
||||
if (task_index == (parallel_mask & edge_hash_2(ordered_edge))) {
|
||||
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
|
||||
* array below. To be able to parallelize this, we have to compute edge index offsets for each
|
||||
* map. */
|
||||
Array<int> edge_index_offsets(edge_maps.size());
|
||||
edge_index_offsets[0] = 0;
|
||||
for (const int i : IndexRange(edge_maps.size() - 1)) {
|
||||
edge_index_offsets[i + 1] = edge_index_offsets[i] + edge_maps[i].size();
|
||||
Array<int> edge_sizes(edge_maps.size() + 1);
|
||||
for (const int i : edge_maps.index_range()) {
|
||||
edge_sizes[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) {
|
||||
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()) {
|
||||
int2 &new_edge = new_edges[new_edge_index];
|
||||
const int2 *orig_edge = item.value.original_edge;
|
||||
@ -113,8 +113,7 @@ static void serialize_and_initialize_deduplicated_edges(MutableSpan<EdgeMap> edg
|
||||
}
|
||||
else {
|
||||
/* Initialize new edge. */
|
||||
new_edge[0] = item.key.v_low;
|
||||
new_edge[1] = item.key.v_high;
|
||||
new_edge = int2(item.key.v_low, item.key.v_high);
|
||||
}
|
||||
item.value.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) {
|
||||
for (const int face_index : range) {
|
||||
const IndexRange face = faces[face_index];
|
||||
int prev_corner = face.last();
|
||||
for (const int next_corner : face) {
|
||||
const int vert = corner_verts[next_corner];
|
||||
const int vert_prev = corner_verts[prev_corner];
|
||||
for (const int corner : face) {
|
||||
const int vert = corner_verts[corner];
|
||||
const int vert_prev = corner_verts[bke::mesh::face_corner_next(face, corner)];
|
||||
|
||||
int edge_index;
|
||||
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. */
|
||||
const EdgeMap &edge_map = edge_maps[parallel_mask & edge_hash_2(ordered_edge)];
|
||||
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. */
|
||||
edge_index = 0;
|
||||
}
|
||||
corner_edges[prev_corner] = edge_index;
|
||||
prev_corner = next_corner;
|
||||
corner_edges[corner] = edge_index;
|
||||
}
|
||||
}
|
||||
});
|
||||
@ -187,21 +184,20 @@ void mesh_calc_edges(Mesh &mesh, bool keep_existing_edges, const bool select_new
|
||||
|
||||
/* Add all 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. */
|
||||
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();
|
||||
}
|
||||
|
||||
/* Create new edges. */
|
||||
MutableAttributeAccessor attributes = mesh.attributes_for_write();
|
||||
attributes.add<int>(".corner_edge", AttrDomain::Corner, AttributeInitConstruct());
|
||||
MutableSpan<int2> new_edges{
|
||||
static_cast<int2 *>(MEM_calloc_arrayN(new_totedge, sizeof(int2), __func__)), new_totedge};
|
||||
MutableSpan<int2> new_edges(MEM_cnew_array<int2>(new_totedge, __func__), new_totedge);
|
||||
calc_edges::serialize_and_initialize_deduplicated_edges(edge_maps, new_edges);
|
||||
calc_edges::update_edge_indices_in_face_loops(
|
||||
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) {
|
||||
int new_edge_index = 0;
|
||||
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) {
|
||||
select_edge.span[new_edge_index] = true;
|
||||
}
|
||||
|
@ -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<short2>(faces, mesh.corner_data, selection, CD_CUSTOMLOOPNORMAL);
|
||||
flip_custom_data_type<GridPaintMask>(faces, mesh.corner_data, selection, CD_GRID_PAINT_MASK);
|
||||
|
@ -45,8 +45,7 @@ void BKE_mesh_foreach_mapped_vert(
|
||||
const blender::Span<blender::float3> positions = mesh->runtime->edit_data->vert_positions;
|
||||
blender::Span<blender::float3> vert_normals;
|
||||
if (flag & MESH_FOREACH_USE_NORMAL) {
|
||||
BKE_editmesh_cache_ensure_vert_normals(*em, *mesh->runtime->edit_data);
|
||||
vert_normals = mesh->runtime->edit_data->vert_normals;
|
||||
vert_normals = BKE_editmesh_cache_ensure_vert_normals(*em, *mesh->runtime->edit_data);
|
||||
}
|
||||
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;
|
||||
@ -236,18 +235,16 @@ void BKE_mesh_foreach_mapped_face_center(
|
||||
if (mesh->runtime->edit_mesh != nullptr && mesh->runtime->edit_data != nullptr) {
|
||||
BMEditMesh *em = mesh->runtime->edit_mesh;
|
||||
BMesh *bm = em->bm;
|
||||
blender::Span<blender::float3> face_centers;
|
||||
blender::Span<blender::float3> face_normals;
|
||||
BMFace *efa;
|
||||
BMIter iter;
|
||||
int i;
|
||||
|
||||
BKE_editmesh_cache_ensure_face_centers(*em, *mesh->runtime->edit_data);
|
||||
face_centers = mesh->runtime->edit_data->face_centers; /* always set */
|
||||
const Span<float3> face_centers = BKE_editmesh_cache_ensure_face_centers(
|
||||
*em, *mesh->runtime->edit_data);
|
||||
|
||||
Span<float3> face_normals;
|
||||
if (flag & MESH_FOREACH_USE_NORMAL) {
|
||||
BKE_editmesh_cache_ensure_face_normals(*em, *mesh->runtime->edit_data);
|
||||
face_normals = mesh->runtime->edit_data->face_normals; /* maybe nullptr */
|
||||
face_normals = BKE_editmesh_cache_ensure_face_normals(*em, *mesh->runtime->edit_data);
|
||||
}
|
||||
|
||||
if (!face_normals.is_empty()) {
|
||||
|
@ -2431,6 +2431,16 @@ void BKE_main_mesh_legacy_convert_auto_smooth(Main &bmain)
|
||||
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
|
||||
|
@ -548,22 +548,14 @@ void BKE_mesh_calc_loop_tangent_ex(const float (*vert_positions)[3],
|
||||
*tangent_mask_curr_p = tangent_mask_curr;
|
||||
|
||||
/* Update active layer index */
|
||||
int act_uv_index = (act_uv_n != -1) ?
|
||||
CustomData_get_layer_index_n(loopdata, CD_PROP_FLOAT2, act_uv_n) :
|
||||
-1;
|
||||
if (act_uv_index != -1) {
|
||||
int tan_index = CustomData_get_named_layer_index(
|
||||
loopdata, CD_TANGENT, loopdata->layers[act_uv_index].name);
|
||||
if (const char *active_uv_name = CustomData_get_active_layer_name(loopdata, CD_PROP_FLOAT2)) {
|
||||
int tan_index = CustomData_get_named_layer_index(loopdata_out, CD_TANGENT, active_uv_name);
|
||||
CustomData_set_layer_active_index(loopdata_out, CD_TANGENT, tan_index);
|
||||
} /* else tangent has been built from orco */
|
||||
|
||||
/* Update render layer index */
|
||||
int ren_uv_index = (ren_uv_n != -1) ?
|
||||
CustomData_get_layer_index_n(loopdata, CD_PROP_FLOAT2, ren_uv_n) :
|
||||
-1;
|
||||
if (ren_uv_index != -1) {
|
||||
int tan_index = CustomData_get_named_layer_index(
|
||||
loopdata, CD_TANGENT, loopdata->layers[ren_uv_index].name);
|
||||
if (const char *render_uv_name = CustomData_get_render_layer_name(loopdata, CD_PROP_FLOAT2)) {
|
||||
int tan_index = CustomData_get_named_layer_index(loopdata_out, CD_TANGENT, render_uv_name);
|
||||
CustomData_set_layer_render_index(loopdata_out, CD_TANGENT, tan_index);
|
||||
} /* else tangent has been built from orco */
|
||||
}
|
||||
|
@ -30,6 +30,7 @@
|
||||
#include "BKE_customdata.hh"
|
||||
#include "BKE_deform.hh"
|
||||
#include "BKE_mesh.hh"
|
||||
#include "BKE_mesh_runtime.hh"
|
||||
|
||||
#include "DEG_depsgraph.hh"
|
||||
|
||||
@ -1125,6 +1126,7 @@ bool BKE_mesh_validate(Mesh *mesh, const bool do_verbose, const bool cddata_chec
|
||||
&changed);
|
||||
|
||||
if (changed) {
|
||||
BKE_mesh_runtime_clear_cache(mesh);
|
||||
DEG_id_tag_update(&mesh->id, ID_RECALC_GEOMETRY_ALL_MODES);
|
||||
return true;
|
||||
}
|
||||
|
@ -129,10 +129,6 @@ void BKE_mesh_wrapper_ensure_mdata(Mesh *mesh)
|
||||
mesh->runtime->is_original_bmesh = false;
|
||||
}
|
||||
|
||||
if (mesh->runtime->wrapper_type_finalize) {
|
||||
BKE_mesh_wrapper_deferred_finalize_mdata(mesh);
|
||||
}
|
||||
|
||||
mesh->runtime->edit_data.reset();
|
||||
break;
|
||||
}
|
||||
@ -165,8 +161,8 @@ Span<float3> BKE_mesh_wrapper_face_normals(Mesh *mesh)
|
||||
{
|
||||
switch (mesh->runtime->wrapper_type) {
|
||||
case ME_WRAPPER_TYPE_BMESH:
|
||||
BKE_editmesh_cache_ensure_face_normals(*mesh->runtime->edit_mesh, *mesh->runtime->edit_data);
|
||||
return mesh->runtime->edit_data->face_normals;
|
||||
return BKE_editmesh_cache_ensure_face_normals(*mesh->runtime->edit_mesh,
|
||||
*mesh->runtime->edit_data);
|
||||
case ME_WRAPPER_TYPE_MDATA:
|
||||
case ME_WRAPPER_TYPE_SUBD:
|
||||
return mesh->face_normals();
|
||||
@ -179,10 +175,10 @@ void BKE_mesh_wrapper_tag_positions_changed(Mesh *mesh)
|
||||
{
|
||||
switch (mesh->runtime->wrapper_type) {
|
||||
case ME_WRAPPER_TYPE_BMESH:
|
||||
if (mesh->runtime->edit_data) {
|
||||
mesh->runtime->edit_data->vert_normals = {};
|
||||
mesh->runtime->edit_data->face_centers = {};
|
||||
mesh->runtime->edit_data->face_normals = {};
|
||||
if (blender::bke::EditMeshData *edit_data = mesh->runtime->edit_data.get()) {
|
||||
edit_data->vert_normals = {};
|
||||
edit_data->face_centers = {};
|
||||
edit_data->face_normals = {};
|
||||
}
|
||||
break;
|
||||
case ME_WRAPPER_TYPE_MDATA:
|
||||
|
@ -1804,7 +1804,7 @@ void BKE_movieclip_build_proxy_frame(MovieClip *clip,
|
||||
int clip_flag,
|
||||
MovieDistortion *distortion,
|
||||
int cfra,
|
||||
int *build_sizes,
|
||||
const int *build_sizes,
|
||||
int build_count,
|
||||
bool undistorted)
|
||||
{
|
||||
@ -1845,7 +1845,7 @@ void BKE_movieclip_build_proxy_frame_for_ibuf(MovieClip *clip,
|
||||
ImBuf *ibuf,
|
||||
MovieDistortion *distortion,
|
||||
int cfra,
|
||||
int *build_sizes,
|
||||
const int *build_sizes,
|
||||
int build_count,
|
||||
bool undistorted)
|
||||
{
|
||||
|
@ -4157,7 +4157,7 @@ static blender::Set<int> get_known_node_types_set()
|
||||
static bool can_read_node_type(const int type)
|
||||
{
|
||||
/* Can always read custom node types. */
|
||||
if (type == NODE_CUSTOM) {
|
||||
if (ELEM(type, NODE_CUSTOM, NODE_CUSTOM_GROUP)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -1455,7 +1455,7 @@ bool BKE_object_modifier_stack_copy(Object *ob_dst,
|
||||
const int flag_subdata)
|
||||
{
|
||||
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.");
|
||||
return false;
|
||||
}
|
||||
@ -1463,8 +1463,9 @@ bool BKE_object_modifier_stack_copy(Object *ob_dst,
|
||||
if (!BLI_listbase_is_empty(&ob_dst->modifiers) ||
|
||||
!BLI_listbase_is_empty(&ob_dst->greasepencil_modifiers))
|
||||
{
|
||||
BLI_assert(
|
||||
!"Trying to copy a modifier stack into an object having a non-empty modifier stack.");
|
||||
BLI_assert_msg(
|
||||
false,
|
||||
"Trying to copy a modifier stack into an object having a non-empty modifier stack.");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -544,7 +544,7 @@ bool BKE_object_defgroup_array_get(ID *id, MDeformVert **dvert_arr, int *dvert_t
|
||||
return true;
|
||||
}
|
||||
case ID_GP:
|
||||
/* Should not be used with grease pencil objects.*/
|
||||
/* Should not be used with grease pencil objects. */
|
||||
BLI_assert_unreachable();
|
||||
break;
|
||||
default:
|
||||
|
@ -444,17 +444,17 @@ static void make_child_duplis(const DupliContext *ctx,
|
||||
|
||||
static const Mesh *mesh_data_from_duplicator_object(Object *ob,
|
||||
BMEditMesh **r_em,
|
||||
const float (**r_vert_coords)[3],
|
||||
const float (**r_vert_normals)[3])
|
||||
Span<float3> *r_vert_coords,
|
||||
Span<float3> *r_vert_normals)
|
||||
{
|
||||
/* Gather mesh info. */
|
||||
BMEditMesh *em = BKE_editmesh_from_object(ob);
|
||||
const Mesh *mesh_eval;
|
||||
|
||||
*r_em = nullptr;
|
||||
*r_vert_coords = nullptr;
|
||||
*r_vert_coords = {};
|
||||
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. */
|
||||
@ -473,10 +473,9 @@ static const Mesh *mesh_data_from_duplicator_object(Object *ob,
|
||||
mesh_eval = nullptr;
|
||||
|
||||
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) {
|
||||
BKE_editmesh_cache_ensure_vert_normals(*em, *emd);
|
||||
*r_vert_normals = reinterpret_cast<const float(*)[3]>(emd->vert_normals.data());
|
||||
*r_vert_normals = BKE_editmesh_cache_ensure_vert_normals(*em, *emd);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -563,9 +562,9 @@ struct VertexDupliData_EditMesh {
|
||||
|
||||
BMEditMesh *em;
|
||||
|
||||
/* Can be nullptr. */
|
||||
const float (*vert_positions_deform)[3];
|
||||
const float (*vert_normals_deform)[3];
|
||||
/* Can be empty. */
|
||||
Span<float3> vert_positions_deform;
|
||||
Span<float3> vert_normals_deform;
|
||||
|
||||
/**
|
||||
* \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.
|
||||
* Can be null when \a use_rotation is false.
|
||||
*/
|
||||
static void get_duplivert_transform(const float co[3],
|
||||
const float no[3],
|
||||
static void get_duplivert_transform(const float3 &co,
|
||||
const float3 &no,
|
||||
const bool use_rotation,
|
||||
const short axis,
|
||||
const short upflag,
|
||||
@ -609,8 +608,8 @@ static DupliObject *vertex_dupli(const DupliContext *ctx,
|
||||
Object *inst_ob,
|
||||
const float child_imat[4][4],
|
||||
int index,
|
||||
const float co[3],
|
||||
const float no[3],
|
||||
const float3 &co,
|
||||
const float3 &no,
|
||||
const bool use_rotation)
|
||||
{
|
||||
/* `obmat` is transform to vertex. */
|
||||
@ -681,14 +680,13 @@ static void make_child_duplis_verts_from_editmesh(const DupliContext *ctx,
|
||||
BMIter iter;
|
||||
int i;
|
||||
|
||||
const float(*vert_positions_deform)[3] = vdd->vert_positions_deform;
|
||||
const float(*vert_normals_deform)[3] = vdd->vert_normals_deform;
|
||||
|
||||
const Span<float3> vert_positions_deform = vdd->vert_positions_deform;
|
||||
const Span<float3> vert_normals_deform = vdd->vert_normals_deform;
|
||||
BM_ITER_MESH_INDEX (v, &iter, em->bm, BM_VERTS_OF_MESH, i) {
|
||||
const float *co, *no;
|
||||
if (vert_positions_deform != nullptr) {
|
||||
float3 co, no;
|
||||
if (!vert_positions_deform.is_empty()) {
|
||||
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 {
|
||||
co = v->co;
|
||||
@ -709,8 +707,8 @@ static void make_duplis_verts(const DupliContext *ctx)
|
||||
|
||||
/* Gather mesh info. */
|
||||
BMEditMesh *em = nullptr;
|
||||
const float(*vert_positions_deform)[3] = nullptr;
|
||||
const float(*vert_normals_deform)[3] = nullptr;
|
||||
Span<float3> vert_positions_deform;
|
||||
Span<float3> vert_normals_deform;
|
||||
const Mesh *mesh_eval = mesh_data_from_duplicator_object(
|
||||
parent, &em, &vert_positions_deform, use_rotation ? &vert_normals_deform : nullptr);
|
||||
if (em == nullptr && mesh_eval == nullptr) {
|
||||
@ -725,7 +723,7 @@ static void make_duplis_verts(const DupliContext *ctx)
|
||||
vdd.em = em;
|
||||
vdd.vert_positions_deform = vert_positions_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);
|
||||
}
|
||||
@ -1080,8 +1078,8 @@ struct FaceDupliData_EditMesh {
|
||||
|
||||
bool has_orco, has_uvs;
|
||||
int cd_loop_uv_offset;
|
||||
/* Can be nullptr. */
|
||||
const float (*vert_positions_deform)[3];
|
||||
/* Can be empty. */
|
||||
Span<float3> vert_positions_deform;
|
||||
};
|
||||
|
||||
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. */
|
||||
BMFace *f,
|
||||
const float (*vert_positions_deform)[3])
|
||||
const Span<float3> vert_positions_deform)
|
||||
{
|
||||
const int coords_len = f->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;
|
||||
int i = 0;
|
||||
l_iter = l_first = BM_FACE_FIRST_LOOP(f);
|
||||
if (vert_positions_deform != nullptr) {
|
||||
if (!vert_positions_deform.is_empty()) {
|
||||
do {
|
||||
copy_v3_v3(coords[i++], vert_positions_deform[BM_elem_index_get(l_iter->v)]);
|
||||
} 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;
|
||||
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());
|
||||
/* Relative transform from parent to child space. */
|
||||
@ -1296,7 +1294,7 @@ static void make_duplis_faces(const DupliContext *ctx)
|
||||
|
||||
/* Gather mesh info. */
|
||||
BMEditMesh *em = nullptr;
|
||||
const float(*vert_positions_deform)[3] = nullptr;
|
||||
Span<float3> vert_positions_deform;
|
||||
const Mesh *mesh_eval = mesh_data_from_duplicator_object(
|
||||
parent, &em, &vert_positions_deform, nullptr);
|
||||
if (em == nullptr && mesh_eval == nullptr) {
|
||||
@ -1311,7 +1309,7 @@ static void make_duplis_faces(const DupliContext *ctx)
|
||||
fdd.params = fdd_params;
|
||||
fdd.em = em;
|
||||
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.cd_loop_uv_offset = (uv_idx != -1) ?
|
||||
CustomData_get_n_offset(&em->bm->ldata, CD_PROP_FLOAT2, uv_idx) :
|
||||
|
@ -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,
|
||||
const char *filepath_rel,
|
||||
PackedFile *pf)
|
||||
const PackedFile *pf)
|
||||
{
|
||||
BLI_stat_t st;
|
||||
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) {
|
||||
return;
|
||||
|
@ -834,8 +834,8 @@ static int distribute_compare_orig_index(const void *p1, const void *p2, void *u
|
||||
return -1;
|
||||
}
|
||||
if (index1 == index2) {
|
||||
/* this pointer comparison appears to make qsort stable for glibc,
|
||||
* and apparently on solaris too, makes the renders reproducible */
|
||||
/* This pointer comparison appears to make #qsort stable for GLIBC,
|
||||
* and apparently on SOLARIS too, makes the renders reproducible. */
|
||||
if (p1 < p2) {
|
||||
return -1;
|
||||
}
|
||||
|
@ -2287,7 +2287,7 @@ void clip_ray_ortho(
|
||||
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};
|
||||
|
||||
/* Compute AABB bounds rotated along ray_normal.*/
|
||||
/* Compute AABB bounds rotated along ray_normal. */
|
||||
copy_v3_v3(a, bb_root.min);
|
||||
copy_v3_v3(b, bb_root.max);
|
||||
mul_m3_v3(mat, a);
|
||||
|
@ -312,7 +312,7 @@ UVVertex *UVEdge::get_other_uv_vertex(const int vertex)
|
||||
UVVertex *UVIsland::lookup(const UVVertex &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) {
|
||||
if (v->uv == vertex.uv) {
|
||||
return v;
|
||||
@ -1033,9 +1033,8 @@ static void reset_extendability_flags(UVIsland &island)
|
||||
uv_vertex.flags.is_extended = false;
|
||||
}
|
||||
}
|
||||
|
||||
for (UVBorder border : island.borders) {
|
||||
for (UVBorderEdge &border_edge : border.edges) {
|
||||
for (const UVBorder &border : island.borders) {
|
||||
for (const UVBorderEdge &border_edge : border.edges) {
|
||||
border_edge.edge->vertices[0]->flags.is_border = true;
|
||||
border_edge.edge->vertices[1]->flags.is_border = true;
|
||||
}
|
||||
|
@ -1136,13 +1136,12 @@ static void scene_blend_write(BlendWriter *writer, ID *id, const void *id_addres
|
||||
if (sce->nodetree) {
|
||||
BLO_write_init_id_buffer_from_id(
|
||||
temp_embedded_id_buffer, &sce->nodetree->id, BLO_write_is_undo(writer));
|
||||
BLO_write_struct_at_address(writer,
|
||||
bNodeTree,
|
||||
sce->nodetree,
|
||||
BLO_write_get_id_buffer_temp_id(temp_embedded_id_buffer));
|
||||
ntreeBlendWrite(
|
||||
writer,
|
||||
reinterpret_cast<bNodeTree *>(BLO_write_get_id_buffer_temp_id(temp_embedded_id_buffer)));
|
||||
bNodeTree *temp_nodetree = reinterpret_cast<bNodeTree *>(
|
||||
BLO_write_get_id_buffer_temp_id(temp_embedded_id_buffer));
|
||||
/* Set deprecated chunksize for forward compatibility. */
|
||||
temp_nodetree->chunksize = 256;
|
||||
BLO_write_struct_at_address(writer, bNodeTree, sce->nodetree, temp_nodetree);
|
||||
ntreeBlendWrite(writer, temp_nodetree);
|
||||
}
|
||||
|
||||
BKE_color_managed_view_settings_blend_write(writer, &sce->view_settings);
|
||||
|
@ -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}}
|
||||
*
|
||||
* 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,
|
||||
MutableSpan<float3> face_normals,
|
||||
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. */
|
||||
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 Span<float3> face_normals,
|
||||
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);
|
||||
}
|
||||
|
||||
static void average_grid_element(SubdivCCG &subdiv_ccg,
|
||||
static void average_grid_element(const SubdivCCG &subdiv_ccg,
|
||||
const CCGKey &key,
|
||||
CCGElem *grid_element_a,
|
||||
CCGElem *grid_element_b)
|
||||
@ -744,7 +744,7 @@ static void element_accumulator_mul_fl(GridElementAccumulator &accumulator, cons
|
||||
accumulator.mask *= f;
|
||||
}
|
||||
|
||||
static void element_accumulator_copy(SubdivCCG &subdiv_ccg,
|
||||
static void element_accumulator_copy(const SubdivCCG &subdiv_ccg,
|
||||
const CCGKey &key,
|
||||
CCGElem &destination,
|
||||
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,
|
||||
const CCGKey &key,
|
||||
SubdivCCGAdjacentEdge &adjacent_edge,
|
||||
const SubdivCCGAdjacentEdge &adjacent_edge,
|
||||
MutableSpan<GridElementAccumulator> accumulators)
|
||||
{
|
||||
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,
|
||||
const CCGKey &key,
|
||||
SubdivCCGAdjacentVertex &adjacent_vertex)
|
||||
const SubdivCCGAdjacentVertex &adjacent_vertex)
|
||||
{
|
||||
const int num_adjacent_faces = adjacent_vertex.num_adjacent_faces;
|
||||
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) {
|
||||
MutableSpan<GridElementAccumulator> accumulators = all_accumulators.local();
|
||||
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);
|
||||
}
|
||||
});
|
||||
@ -883,7 +883,7 @@ static void subdiv_ccg_average_corners(SubdivCCG &subdiv_ccg,
|
||||
{
|
||||
using namespace blender;
|
||||
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);
|
||||
});
|
||||
}
|
||||
@ -1004,15 +1004,8 @@ BLI_INLINE void subdiv_ccg_neighbors_init(SubdivCCGNeighbors &neighbors,
|
||||
const int num_duplicates)
|
||||
{
|
||||
const int size = num_unique + num_duplicates;
|
||||
neighbors.size = size;
|
||||
neighbors.coords.reinitialize(size);
|
||||
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. */
|
||||
@ -1520,7 +1513,7 @@ void BKE_subdiv_ccg_neighbor_coords_get(const SubdivCCG &subdiv_ccg,
|
||||
}
|
||||
|
||||
#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]));
|
||||
}
|
||||
#endif
|
||||
|
@ -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;
|
||||
TextLine *tmp = from;
|
||||
const TextLine *tmp = from;
|
||||
|
||||
if (!to || !from) {
|
||||
return 0;
|
||||
|
@ -2158,7 +2158,7 @@ void BKE_tracking_camera_get_reconstructed_interpolate(MovieTracking * /*trackin
|
||||
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) /
|
||||
(cameras[a + 1].framenr - cameras[a].framenr);
|
||||
blend_m4_m4m4(mat, cameras[a].mat, cameras[a + 1].mat, t);
|
||||
|
@ -806,8 +806,9 @@ bool BKE_undosys_step_load_data_ex(UndoStack *ustack,
|
||||
}
|
||||
}
|
||||
|
||||
BLI_assert(
|
||||
!"This should never be reached, either undo stack is corrupted, or code above is buggy");
|
||||
BLI_assert_msg(
|
||||
false,
|
||||
"This should never be reached, either undo stack is corrupted, or code above is buggy");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -46,6 +46,7 @@ extern "C" {
|
||||
# include <libavformat/avformat.h>
|
||||
# include <libavutil/buffer.h>
|
||||
# include <libavutil/channel_layout.h>
|
||||
# include <libavutil/cpu.h>
|
||||
# include <libavutil/imgutils.h>
|
||||
# include <libavutil/opt.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 */
|
||||
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);
|
||||
if (buf == nullptr) {
|
||||
av_frame_free(&f);
|
||||
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->format = pix_fmt;
|
||||
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
|
||||
* the image vertically. */
|
||||
int linesize = rgb_frame->linesize[0];
|
||||
int linesize_src = rgb_frame->width * 4;
|
||||
for (int y = 0; y < height; y++) {
|
||||
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
|
||||
memcpy(target, src, linesize);
|
||||
memcpy(target, src, linesize_src);
|
||||
|
||||
# elif ENDIAN_ORDER == B_ENDIAN
|
||||
const uint8_t *end = src + linesize;
|
||||
const uint8_t *end = src + linesize_src;
|
||||
while (src != end) {
|
||||
target[3] = src[0];
|
||||
target[2] = src[1];
|
||||
|
@ -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_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_compacted);
|
||||
|
||||
|
@ -13,6 +13,8 @@
|
||||
#include "BLI_assert.h"
|
||||
#include "BLI_utility_mixins.hh"
|
||||
|
||||
#include "MEM_guardedalloc.h"
|
||||
|
||||
namespace blender {
|
||||
|
||||
/**
|
||||
@ -199,6 +201,30 @@ class ImplicitSharingMixin : public ImplicitSharingInfo {
|
||||
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.
|
||||
*/
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user