WIP: Brush assets project #106303
|
@ -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:
|
||||
|
|
|
@ -5,6 +5,17 @@
|
|||
import time
|
||||
|
||||
|
||||
def has_module(module_name):
|
||||
found = False
|
||||
try:
|
||||
__import__(module_name)
|
||||
found = True
|
||||
except ModuleNotFoundError as ex:
|
||||
if ex.name != module_name:
|
||||
raise ex
|
||||
return found
|
||||
|
||||
|
||||
# These are substituted when this file is copied to the build directory.
|
||||
BLENDER_VERSION_STRING = "${BLENDER_VERSION_STRING}"
|
||||
BLENDER_VERSION_DOTS = "${BLENDER_VERSION_DOTS}"
|
||||
|
@ -27,6 +38,16 @@ else:
|
|||
|
||||
extensions = ["sphinx.ext.intersphinx"]
|
||||
intersphinx_mapping = {"blender_manual": ("https://docs.blender.org/manual/en/dev/", None)}
|
||||
|
||||
|
||||
# Provides copy button next to code-blocks (nice to have but not essential).
|
||||
if has_module("sphinx_copybutton"):
|
||||
extensions.append("sphinx_copybutton")
|
||||
|
||||
# Exclude line numbers, prompts, and console text.
|
||||
copybutton_exclude = ".linenos, .gp, .go"
|
||||
|
||||
|
||||
project = "Blender %s Python API" % BLENDER_VERSION_STRING
|
||||
root_doc = "index"
|
||||
copyright = "Blender Authors"
|
||||
|
@ -48,14 +69,8 @@ html_title = "Blender Python API"
|
|||
# The fallback to a built-in theme when `furo` is not found.
|
||||
html_theme = "default"
|
||||
|
||||
try:
|
||||
import furo
|
||||
if has_module("furo"):
|
||||
html_theme = "furo"
|
||||
del furo
|
||||
except ModuleNotFoundError:
|
||||
pass
|
||||
|
||||
if html_theme == "furo":
|
||||
html_theme_options = {
|
||||
"light_css_variables": {
|
||||
"color-brand-primary": "#265787",
|
||||
|
|
|
@ -17,10 +17,10 @@ animation or modifiers into account:
|
|||
|
||||
When is used on evaluated object all modifiers are taken into account.
|
||||
|
||||
.. note:: The result mesh is owned by the object. It can be freed by calling `object.to_mesh_clear()`.
|
||||
.. note:: The result mesh is owned by the object. It can be freed by calling :meth:`~Object.to_mesh_clear`.
|
||||
.. note::
|
||||
The result mesh must be treated as temporary, and cannot be referenced from objects in the main
|
||||
database. If the mesh intended to be used in a persistent manner use bpy.data.meshes.new_from_object()
|
||||
database. If the mesh intended to be used in a persistent manner use :meth:`~BlendDataMeshes.new_from_object`
|
||||
instead.
|
||||
.. note:: If object does not have geometry (i.e. camera) the functions returns None.
|
||||
"""
|
||||
|
|
|
@ -15,7 +15,7 @@ If the object is a text object. The text will be converted into a 3D curve and r
|
|||
never applied on text objects and apply_modifiers will be ignored. If the object is neither a curve nor
|
||||
a text object, an error will be reported.
|
||||
|
||||
.. note:: The resulting curve is owned by the object. It can be freed by calling `object.to_curve_clear()`.
|
||||
.. note:: The resulting curve is owned by the object. It can be freed by calling :meth:`~Object.to_curve_clear`.
|
||||
.. note::
|
||||
The resulting curve must be treated as temporary, and cannot be referenced from objects in the main
|
||||
database.
|
||||
|
|
|
@ -11,3 +11,6 @@ requests==2.31.0
|
|||
# Without this theme, the default theme will be used.
|
||||
furo==2024.1.29
|
||||
sphinx-basic-ng==1.0.0b2
|
||||
|
||||
# Show a copy button (convenience only).
|
||||
sphinx-copybutton==0.5.2
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -124,13 +124,12 @@ void PulseAudioDevice::playing(bool playing)
|
|||
|
||||
AUD_pa_threaded_mainloop_lock(m_mainloop);
|
||||
AUD_pa_stream_cork(m_stream, playing ? 0 : 1, nullptr, nullptr);
|
||||
AUD_pa_threaded_mainloop_unlock(m_mainloop);
|
||||
|
||||
if(!playing)
|
||||
{
|
||||
AUD_pa_stream_flush(m_stream, nullptr, nullptr);
|
||||
m_clear = true;
|
||||
}
|
||||
AUD_pa_threaded_mainloop_unlock(m_mainloop);
|
||||
}
|
||||
|
||||
PulseAudioDevice::PulseAudioDevice(const std::string &name, DeviceSpecs specs, int buffersize) :
|
||||
|
|
|
@ -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)
|
|
@ -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.
|
|
@ -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
|
|
@ -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"
|
File diff suppressed because it is too large
Load Diff
|
@ -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);
|
||||
|
|
|
@ -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)}")
|
||||
|
||||
|
|
|
@ -108,6 +108,7 @@ class OBJECT_MT_modifier_add_edit(ModifierAddMenu, Menu):
|
|||
self.operator_modifier_add(layout, 'VERTEX_WEIGHT_MIX')
|
||||
self.operator_modifier_add(layout, 'VERTEX_WEIGHT_PROXIMITY')
|
||||
if ob_type == 'GREASEPENCIL':
|
||||
self.operator_modifier_add(layout, 'GREASE_PENCIL_TEXTURE')
|
||||
self.operator_modifier_add(layout, 'GREASE_PENCIL_TIME')
|
||||
self.operator_modifier_add(layout, 'GREASE_PENCIL_VERTEX_WEIGHT_PROXIMITY')
|
||||
self.operator_modifier_add(layout, 'GREASE_PENCIL_VERTEX_WEIGHT_ANGLE')
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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"
|
||||
|
@ -76,12 +77,12 @@ class Drawing : public ::GreasePencilDrawing {
|
|||
void tag_positions_changed();
|
||||
void tag_topology_changed();
|
||||
|
||||
/*
|
||||
/**
|
||||
* Returns the matrices that transform from a 3D point in layer-space to a 2D point in
|
||||
* texture-space.
|
||||
*/
|
||||
Span<float4x2> texture_matrices() const;
|
||||
/*
|
||||
/**
|
||||
* Sets the matrices the that transform from a 3D point in layer-space to a 2D point in
|
||||
* texture-space
|
||||
*/
|
||||
|
@ -773,7 +774,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);
|
||||
|
|
|
@ -580,6 +580,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));
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -578,7 +578,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 *
|
||||
|
@ -1570,6 +1570,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];
|
||||
}
|
||||
|
@ -784,10 +792,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 +846,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. */
|
||||
|
@ -1840,6 +1848,55 @@ static void legacy_object_modifier_subdiv(Object &object, GpencilModifierData &l
|
|||
false);
|
||||
}
|
||||
|
||||
static void legacy_object_modifier_texture(Object &object, GpencilModifierData &legacy_md)
|
||||
{
|
||||
ModifierData &md = legacy_object_modifier_common(
|
||||
object, eModifierType_GreasePencilTexture, legacy_md);
|
||||
auto &md_texture = reinterpret_cast<GreasePencilTextureModifierData &>(md);
|
||||
auto &legacy_md_texture = reinterpret_cast<TextureGpencilModifierData &>(legacy_md);
|
||||
|
||||
switch (eTextureGpencil_Mode(legacy_md_texture.mode)) {
|
||||
case STROKE:
|
||||
md_texture.mode = MOD_GREASE_PENCIL_TEXTURE_STROKE;
|
||||
break;
|
||||
case FILL:
|
||||
md_texture.mode = MOD_GREASE_PENCIL_TEXTURE_FILL;
|
||||
break;
|
||||
case STROKE_AND_FILL:
|
||||
md_texture.mode = MOD_GREASE_PENCIL_TEXTURE_STROKE_AND_FILL;
|
||||
break;
|
||||
}
|
||||
switch (eTextureGpencil_Fit(legacy_md_texture.fit_method)) {
|
||||
case GP_TEX_FIT_STROKE:
|
||||
md_texture.fit_method = MOD_GREASE_PENCIL_TEXTURE_FIT_STROKE;
|
||||
break;
|
||||
case GP_TEX_CONSTANT_LENGTH:
|
||||
md_texture.fit_method = MOD_GREASE_PENCIL_TEXTURE_CONSTANT_LENGTH;
|
||||
break;
|
||||
}
|
||||
md_texture.uv_offset = legacy_md_texture.uv_offset;
|
||||
md_texture.uv_scale = legacy_md_texture.uv_scale;
|
||||
md_texture.fill_rotation = legacy_md_texture.fill_rotation;
|
||||
copy_v2_v2(md_texture.fill_offset, legacy_md_texture.fill_offset);
|
||||
md_texture.fill_scale = legacy_md_texture.fill_scale;
|
||||
md_texture.layer_pass = legacy_md_texture.layer_pass;
|
||||
md_texture.alignment_rotation = legacy_md_texture.alignment_rotation;
|
||||
|
||||
legacy_object_modifier_influence(md_texture.influence,
|
||||
legacy_md_texture.layername,
|
||||
legacy_md_texture.layer_pass,
|
||||
legacy_md_texture.flag & GP_TEX_INVERT_LAYER,
|
||||
legacy_md_texture.flag & GP_TEX_INVERT_LAYERPASS,
|
||||
&legacy_md_texture.material,
|
||||
legacy_md_texture.pass_index,
|
||||
legacy_md_texture.flag & GP_TEX_INVERT_MATERIAL,
|
||||
legacy_md_texture.flag & GP_TEX_INVERT_PASS,
|
||||
legacy_md_texture.vgname,
|
||||
legacy_md_texture.flag & GP_TEX_INVERT_VGROUP,
|
||||
nullptr,
|
||||
false);
|
||||
}
|
||||
|
||||
static void legacy_object_modifier_thickness(Object &object, GpencilModifierData &legacy_md)
|
||||
{
|
||||
ModifierData &md = legacy_object_modifier_common(
|
||||
|
@ -2286,6 +2343,9 @@ static void legacy_object_modifiers(Main & /*bmain*/, Object &object)
|
|||
case eGpencilModifierType_Subdiv:
|
||||
legacy_object_modifier_subdiv(object, *gpd_md);
|
||||
break;
|
||||
case eGpencilModifierType_Texture:
|
||||
legacy_object_modifier_texture(object, *gpd_md);
|
||||
break;
|
||||
case eGpencilModifierType_Thick:
|
||||
legacy_object_modifier_thickness(object, *gpd_md);
|
||||
break;
|
||||
|
@ -2310,7 +2370,6 @@ static void legacy_object_modifiers(Main & /*bmain*/, Object &object)
|
|||
case eGpencilModifierType_Simplify:
|
||||
legacy_object_modifier_simplify(object, *gpd_md);
|
||||
break;
|
||||
case eGpencilModifierType_Texture:
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
|
@ -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()) {
|
||||
|
|
|
@ -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 */
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -125,11 +125,11 @@ template<typename T, int Size>
|
|||
[[nodiscard]] inline bool less_or_equal_than(const VecBase<T, Size> &a, const VecBase<T, Size> &b)
|
||||
{
|
||||
for (int i = 0; i < Size; i++) {
|
||||
if (a[i] > b[i]) {
|
||||
return false;
|
||||
if (a[i] <= b[i]) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
|
|
|
@ -199,6 +199,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.
|
||||
*/
|
||||
|
|
|
@ -8,6 +8,9 @@
|
|||
* \ingroup bli
|
||||
*/
|
||||
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
|
||||
#include "BLI_implicit_sharing.hh"
|
||||
#include "BLI_struct_equality_utils.hh"
|
||||
|
||||
|
@ -132,4 +135,64 @@ template<typename T> class ImplicitSharingPtr {
|
|||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Utility struct to allow used #ImplicitSharingPtr when it's necessary to type-erase the backing
|
||||
* storage for user-exposed data. For example, #blender::Vector, or #std::vector might be used to
|
||||
* store an implicitly shared array that is only accessed with #Span or #MutableSpan.
|
||||
*
|
||||
* This class handles RAII for the sharing info and the exposed data pointer.
|
||||
* Retrieving the data with write access and type safety must be handled elsewhere.
|
||||
*/
|
||||
class ImplicitSharingPtrAndData {
|
||||
public:
|
||||
ImplicitSharingPtr<ImplicitSharingInfo> sharing_info;
|
||||
const void *data = nullptr;
|
||||
|
||||
ImplicitSharingPtrAndData() = default;
|
||||
ImplicitSharingPtrAndData(ImplicitSharingPtr<ImplicitSharingInfo> sharing_info, const void *data)
|
||||
: sharing_info(std::move(sharing_info)), data(data)
|
||||
{
|
||||
}
|
||||
|
||||
ImplicitSharingPtrAndData(const ImplicitSharingPtrAndData &other)
|
||||
: sharing_info(other.sharing_info), data(other.data)
|
||||
{
|
||||
}
|
||||
|
||||
ImplicitSharingPtrAndData(ImplicitSharingPtrAndData &&other)
|
||||
: sharing_info(std::move(other.sharing_info)), data(std::exchange(other.data, nullptr))
|
||||
{
|
||||
}
|
||||
|
||||
ImplicitSharingPtrAndData &operator=(const ImplicitSharingPtrAndData &other)
|
||||
{
|
||||
if (this == &other) {
|
||||
return *this;
|
||||
}
|
||||
std::destroy_at(this);
|
||||
new (this) ImplicitSharingPtrAndData(other);
|
||||
return *this;
|
||||
}
|
||||
|
||||
ImplicitSharingPtrAndData &operator=(ImplicitSharingPtrAndData &&other)
|
||||
{
|
||||
if (this == &other) {
|
||||
return *this;
|
||||
}
|
||||
std::destroy_at(this);
|
||||
new (this) ImplicitSharingPtrAndData(std::move(other));
|
||||
return *this;
|
||||
}
|
||||
|
||||
~ImplicitSharingPtrAndData()
|
||||
{
|
||||
this->data = nullptr;
|
||||
}
|
||||
|
||||
bool has_value() const
|
||||
{
|
||||
return this->sharing_info.has_value();
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace blender
|
||||
|
|
|
@ -45,6 +45,10 @@ extern "C" {
|
|||
#define BLI_STR_UTF8_DOWNWARDS_ARROW "\xe2\x86\x93"
|
||||
/** u21E7: `⇧` */
|
||||
#define BLI_STR_UTF8_UPWARDS_WHITE_ARROW "\xe2\x87\xa7"
|
||||
/** u21FF: `⇪` For caps lock */
|
||||
#define BLI_STR_UTF8_UPWARDS_UP_ARROW_FROM_BAR "\xe2\x87\xaa"
|
||||
/** u2277: `≷` Greater than / Less than */
|
||||
#define BLI_STR_UTF8_GREATER_THAN_OR_LESS_THAN "\xe2\x89\xb7"
|
||||
/** u2303: `⌃` */
|
||||
#define BLI_STR_UTF8_UP_ARROWHEAD "\xe2\x8c\x83"
|
||||
/** u2318: `⌘` */
|
||||
|
@ -67,12 +71,22 @@ extern "C" {
|
|||
#define BLI_STR_UTF8_BLACK_SQUARE_FOR_STOP "\xe2\x8f\xb9"
|
||||
/** u2423: `␣` */
|
||||
#define BLI_STR_UTF8_OPEN_BOX "\xe2\x90\xa3"
|
||||
/** u25A6: `▦` */
|
||||
#define BLI_STR_UTF8_SQUARE_WITH_ORTHOGONAL_CROSSHATCH "\xe2\x96\xa6"
|
||||
/** u25B8: `▸` */
|
||||
#define BLI_STR_UTF8_BLACK_RIGHT_POINTING_SMALL_TRIANGLE "\xe2\x96\xb8"
|
||||
/** u2B7E: `⭾` */
|
||||
#define BLI_STR_UTF8_HORIZONTAL_TAB_KEY "\xe2\xad\xbe"
|
||||
/** u270E: `✎` Tablet Pen */
|
||||
#define BLI_STR_UTF8_LOWER_RIGHT_PENCIL "\xe2\x9c\x8e"
|
||||
/** u2710: `✐` Tablet Eraser */
|
||||
#define BLI_STR_UTF8_UPPER_RIGHT_PENCIL "\xe2\x9c\x90"
|
||||
/** u2756: `❖` */
|
||||
#define BLI_STR_UTF8_BLACK_DIAMOND_MINUS_WHITE_X "\xe2\x9d\x96"
|
||||
/** u29BE: `⦾` Use for 3D Mice */
|
||||
#define BLI_STR_UTF8_CIRCLED_WHITE_BULLET "\xe2\xa6\xbe"
|
||||
/** u2B2E: `⬮` Generic Mouse */
|
||||
#define BLI_STR_UTF8_BLACK_VERTICAL_ELLIPSE "\xe2\xac\xae"
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
|
|
@ -59,7 +59,7 @@ inline void parallel_for_each(Range &&range, const Function &function)
|
|||
#ifdef WITH_TBB
|
||||
tbb::parallel_for_each(range, function);
|
||||
#else
|
||||
for (auto &value : range) {
|
||||
for (auto &&value : range) {
|
||||
function(value);
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -254,8 +254,8 @@ set(SRC
|
|||
BLI_implicit_sharing.hh
|
||||
BLI_implicit_sharing_ptr.hh
|
||||
BLI_index_mask.hh
|
||||
BLI_index_mask_fwd.hh
|
||||
BLI_index_mask_expression.hh
|
||||
BLI_index_mask_fwd.hh
|
||||
BLI_index_range.hh
|
||||
BLI_inplace_priority_queue.hh
|
||||
BLI_iterator.h
|
||||
|
@ -521,8 +521,8 @@ if(WITH_GTESTS)
|
|||
tests/BLI_heap_simple_test.cc
|
||||
tests/BLI_heap_test.cc
|
||||
tests/BLI_implicit_sharing_test.cc
|
||||
tests/BLI_index_mask_test.cc
|
||||
tests/BLI_index_mask_expression_test.cc
|
||||
tests/BLI_index_mask_test.cc
|
||||
tests/BLI_index_range_test.cc
|
||||
tests/BLI_inplace_priority_queue_test.cc
|
||||
tests/BLI_kdopbvh_test.cc
|
||||
|
|
|
@ -59,14 +59,14 @@ void BLI_array_store_at_size_clear(BArrayStore_AtSize *bs_stride)
|
|||
bs_stride->stride_table_len = 0;
|
||||
}
|
||||
|
||||
void BLI_array_store_at_size_calc_memory_usage(BArrayStore_AtSize *bs_stride,
|
||||
void BLI_array_store_at_size_calc_memory_usage(const BArrayStore_AtSize *bs_stride,
|
||||
size_t *r_size_expanded,
|
||||
size_t *r_size_compacted)
|
||||
{
|
||||
size_t size_compacted = 0;
|
||||
size_t size_expanded = 0;
|
||||
for (int i = 0; i < bs_stride->stride_table_len; i++) {
|
||||
BArrayStore *bs = bs_stride->stride_table[i];
|
||||
const BArrayStore *bs = bs_stride->stride_table[i];
|
||||
if (bs) {
|
||||
size_compacted += BLI_array_store_calc_size_compacted_get(bs);
|
||||
size_expanded += BLI_array_store_calc_size_expanded_get(bs);
|
||||
|
|
|
@ -26,6 +26,15 @@
|
|||
*/
|
||||
// #define USE_BRUTE_FORCE_ASSERT
|
||||
|
||||
/**
|
||||
* Assert that the angles the iterator is looping over are in order.
|
||||
* This works as a general rule however it can fail for large near co-linear edges.
|
||||
* Even though the hull is convex, the angles calculated from the edges may not consistently
|
||||
* wind in in the same direction. Even when it does occur the angle discrepancy is so small
|
||||
* that it can be safely ignored.
|
||||
*/
|
||||
// #define USE_ANGLE_ITER_ORDER_ASSERT
|
||||
|
||||
using namespace blender;
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
|
@ -233,17 +242,18 @@ int BLI_convexhull_2d(const float (*points)[2], const int points_num, int r_poin
|
|||
* \{ */
|
||||
|
||||
#if defined(USE_BRUTE_FORCE_ASSERT) && !defined(NDEBUG)
|
||||
static float convexhull_aabb_fit_hull_2d_brute_force(const float (*points_hull)[2],
|
||||
int points_hull_num)
|
||||
static float2 convexhull_aabb_fit_hull_2d_brute_force(const float (*points_hull)[2],
|
||||
int points_hull_num)
|
||||
{
|
||||
float area_best = FLT_MAX;
|
||||
float2 sincos_best = {0.0f, 1.0f}; /* Track the best angle as a unit vector, delaying `atan2`. */
|
||||
|
||||
for (int i = 0, i_prev = points_hull_num - 1; i < points_hull_num; i_prev = i++) {
|
||||
for (int i = 0; i < points_hull_num; i++) {
|
||||
const int i_next = (i + 1) % points_hull_num;
|
||||
/* 2D rotation matrix. */
|
||||
float dvec_length = 0.0f;
|
||||
const float2 sincos = math::normalize_and_get_length(
|
||||
float2(points_hull[i]) - float2(points_hull[i_prev]), dvec_length);
|
||||
float2(points_hull[i_next]) - float2(points_hull[i]), dvec_length);
|
||||
if (UNLIKELY(dvec_length == 0.0f)) {
|
||||
continue;
|
||||
}
|
||||
|
@ -274,12 +284,273 @@ static float convexhull_aabb_fit_hull_2d_brute_force(const float (*points_hull)[
|
|||
}
|
||||
}
|
||||
|
||||
return (area_best != FLT_MAX) ? float(atan2(sincos_best[0], sincos_best[1])) : 0.0f;
|
||||
return sincos_best;
|
||||
}
|
||||
#endif
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Hull Angle Iteration
|
||||
*
|
||||
* Step over all angles defined by a convex hull in order from 0-90 degrees,
|
||||
* when angles are converted into their canonical form (see #sincos_canonical).
|
||||
* \{ */
|
||||
|
||||
/**
|
||||
* Return a canonical version of `sincos` for the purpose of bounding box fitting,
|
||||
* this maps any `sincos` to 0-1 range for both `sin` & `cos`.
|
||||
*/
|
||||
static float2 sincos_canonical(const float2 &sincos)
|
||||
{
|
||||
|
||||
/* Normalize doesn't ensure a `sin` / `cos` of 1.0/-1.0 ensures the other value is zero.
|
||||
* Without the check for both 0.0 and 1.0, iteration may not be ordered. */
|
||||
float2 result;
|
||||
if (sincos[0] < 0.0f) {
|
||||
if (sincos[1] < 0.0f) {
|
||||
result[0] = -sincos[0];
|
||||
result[1] = -sincos[1];
|
||||
}
|
||||
else if ((sincos[0] == -1.0f) && (sincos[1] == 0.0f)) {
|
||||
result[0] = -sincos[0];
|
||||
result[1] = sincos[1];
|
||||
}
|
||||
else {
|
||||
result[0] = sincos[1];
|
||||
result[1] = -sincos[0];
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (sincos[1] < 0.0f) {
|
||||
result[0] = -sincos[1];
|
||||
result[1] = sincos[0];
|
||||
}
|
||||
else if ((sincos[0] == 0.0f) && (sincos[1] == 1.0f)) {
|
||||
result[0] = sincos[1];
|
||||
result[1] = sincos[0];
|
||||
}
|
||||
else {
|
||||
result = sincos;
|
||||
}
|
||||
}
|
||||
|
||||
/* The range is [1.0, 0.0], it will approach but never return [0.0, 1.0],
|
||||
* as the canonical version of this value gets flipped to [1.0, 0.0]. */
|
||||
BLI_assert(result[0] > 0.0f);
|
||||
BLI_assert(result[1] >= 0.0f);
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* An angle calculated from an edge in a convex hull.
|
||||
*/
|
||||
struct AngleCanonical {
|
||||
/** The edges normalized vector. */
|
||||
float2 sincos;
|
||||
/** The result of `sincos_canonical(sincos)` */
|
||||
float2 sincos_canonical;
|
||||
/** The index value for the edge `sincos` was calculated from, used as a tie breaker. */
|
||||
int index;
|
||||
};
|
||||
|
||||
static int hull_angle_canonical_cmp(const AngleCanonical &a, const AngleCanonical &b)
|
||||
{
|
||||
if (a.sincos_canonical[0] < b.sincos_canonical[0]) {
|
||||
return -1;
|
||||
}
|
||||
if (a.sincos_canonical[0] > b.sincos_canonical[0]) {
|
||||
return 1;
|
||||
}
|
||||
/* Flipped intentionally. */
|
||||
if (a.sincos_canonical[1] > b.sincos_canonical[1]) {
|
||||
return -1;
|
||||
}
|
||||
if (a.sincos_canonical[1] < b.sincos_canonical[1]) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Flipped intentionally. */
|
||||
if (a.index > b.index) {
|
||||
return -1;
|
||||
}
|
||||
if (a.index < b.index) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* This represents an angle at index `index`.
|
||||
*/
|
||||
struct HullAngleStep {
|
||||
/** Single linked list. */
|
||||
HullAngleStep *next;
|
||||
|
||||
/** The current angle value. */
|
||||
AngleCanonical angle;
|
||||
|
||||
/** The next index value to step into. */
|
||||
int index;
|
||||
/** Do not seek past this index. */
|
||||
int index_max;
|
||||
};
|
||||
|
||||
/**
|
||||
* Iterate over all angles of a convex hull (defined by `points_hull`) in-order.
|
||||
*/
|
||||
struct HullAngleIter {
|
||||
/** Linked list of up to 4 items (kept in order), * to support walking over angles in order. */
|
||||
HullAngleStep *axis_ordered = nullptr;
|
||||
/** [X/Y][min/max]. */
|
||||
HullAngleStep axis[2][2];
|
||||
/** The convex hull being iterated over. */
|
||||
const float (*points_hull)[2];
|
||||
int points_hull_num;
|
||||
};
|
||||
|
||||
static void hull_angle_insert_ordered(HullAngleIter &hiter, HullAngleStep *insert)
|
||||
{
|
||||
HullAngleStep **prev_p = &hiter.axis_ordered;
|
||||
HullAngleStep *iter = hiter.axis_ordered;
|
||||
while (iter && hull_angle_canonical_cmp(iter->angle, insert->angle) > 0) {
|
||||
prev_p = &iter->next;
|
||||
iter = iter->next;
|
||||
}
|
||||
*prev_p = insert;
|
||||
insert->next = iter;
|
||||
}
|
||||
|
||||
static bool convexhull_2d_angle_iter_step_on_axis(const HullAngleIter &hiter, HullAngleStep &hstep)
|
||||
{
|
||||
BLI_assert(hstep.index != -1);
|
||||
while (hstep.index != hstep.index_max) {
|
||||
const int i_curr = hstep.index;
|
||||
const int i_next = (hstep.index + 1) % hiter.points_hull_num;
|
||||
const float2 dir = float2(hiter.points_hull[i_next]) - float2(hiter.points_hull[i_curr]);
|
||||
float dir_length = 0.0f;
|
||||
const float2 sincos_test = math::normalize_and_get_length(dir, dir_length);
|
||||
hstep.index = i_next;
|
||||
if (LIKELY(dir_length != 0.0f)) {
|
||||
hstep.angle.sincos = sincos_test;
|
||||
hstep.angle.sincos_canonical = sincos_canonical(sincos_test);
|
||||
hstep.angle.index = i_curr;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/* Reached the end, signal this axis shouldn't be stepped over. */
|
||||
hstep.index = -1;
|
||||
return false;
|
||||
}
|
||||
|
||||
static HullAngleIter convexhull_2d_angle_iter_init(const float (*points_hull)[2],
|
||||
const int points_hull_num)
|
||||
{
|
||||
const int points_hull_num_minus_1 = points_hull_num - 1;
|
||||
HullAngleIter hiter = {};
|
||||
/* Aligned with `hiter.axis`. */
|
||||
float range[2][2];
|
||||
/* Initialize min-max range from the first point. */
|
||||
for (int axis = 0; axis < 2; axis++) {
|
||||
range[axis][0] = points_hull[0][axis];
|
||||
range[axis][1] = points_hull[0][axis];
|
||||
}
|
||||
/* Expand from all other points.
|
||||
*
|
||||
* NOTE: Don't attempt to pick either side when there are multiple equal points.
|
||||
* Walking backwards while checking `sincos_canonical` handles that. */
|
||||
for (int i = 1; i < points_hull_num; i++) {
|
||||
const float *p = points_hull[i];
|
||||
for (int axis = 0; axis < 2; axis++) {
|
||||
if (range[axis][0] < p[axis]) {
|
||||
range[axis][0] = p[axis];
|
||||
hiter.axis[axis][0].index = i;
|
||||
}
|
||||
if (range[axis][1] > p[axis]) {
|
||||
range[axis][1] = p[axis];
|
||||
hiter.axis[axis][1].index = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Step backwards, compute the actual `sincos_canonical` because it's possible
|
||||
* an edge which is not *exactly* axis aligned normalizes to a value which is.
|
||||
* Instead of attempting to guess when this might happen,
|
||||
* simply calculate the value and walk backwards for a long as the canonical angle
|
||||
* has a `sin` of 1.0 (which must always come first). */
|
||||
for (int axis = 0; axis < 2; axis++) {
|
||||
for (int i = 0; i < 2; i++) {
|
||||
int count = 0;
|
||||
const int i_orig = hiter.axis[axis][i].index;
|
||||
int i_curr = i_orig, i_prev;
|
||||
/* Prevent an eternal loop (incredibly unlikely).
|
||||
* In virtually all cases this will step back once
|
||||
* (in the case of an axis-aligned edge) or not at all. */
|
||||
while ((i_prev = (i_curr + points_hull_num_minus_1) % points_hull_num) != i_orig) {
|
||||
float dir_length = 0.0f;
|
||||
const float2 sincos_test = math::normalize_and_get_length(
|
||||
float2(points_hull[i_curr]) - float2(points_hull[i_prev]), dir_length);
|
||||
if (LIKELY(dir_length != 0.0f)) {
|
||||
/* Account for 90 degree corners that may also have an axis-aligned canonical angle. */
|
||||
if (math::abs(sincos_test[axis]) > 0.5f) {
|
||||
break;
|
||||
}
|
||||
const float2 sincos_test_canonical = sincos_canonical(sincos_test);
|
||||
if (LIKELY(sincos_test_canonical[0] != 1.0f)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
i_curr = i_prev;
|
||||
hiter.axis[axis][i].index = i_curr;
|
||||
count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Setup counter-clockwise limits. */
|
||||
hiter.axis[0][0].index_max = hiter.axis[1][0].index; /* West to south. */
|
||||
hiter.axis[1][0].index_max = hiter.axis[0][1].index; /* South to east. */
|
||||
hiter.axis[0][1].index_max = hiter.axis[1][1].index; /* East to north. */
|
||||
hiter.axis[1][1].index_max = hiter.axis[0][0].index; /* North to west. */
|
||||
|
||||
hiter.points_hull = points_hull;
|
||||
hiter.points_hull_num = points_hull_num;
|
||||
|
||||
for (int axis = 0; axis < 2; axis++) {
|
||||
for (int i = 0; i < 2; i++) {
|
||||
hiter.axis[axis][i].angle.index = hiter.axis[axis][i].index;
|
||||
if (convexhull_2d_angle_iter_step_on_axis(hiter, hiter.axis[axis][i])) {
|
||||
hull_angle_insert_ordered(hiter, &hiter.axis[axis][i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return hiter;
|
||||
}
|
||||
|
||||
static void convexhull_2d_angle_iter_step(HullAngleIter &hiter)
|
||||
{
|
||||
HullAngleStep *hstep = hiter.axis_ordered;
|
||||
#ifdef USE_ANGLE_ITER_ORDER_ASSERT
|
||||
const AngleCanonical angle_prev = hstep->angle;
|
||||
#endif
|
||||
|
||||
hiter.axis_ordered = hiter.axis_ordered->next;
|
||||
if (convexhull_2d_angle_iter_step_on_axis(hiter, *hstep)) {
|
||||
hull_angle_insert_ordered(hiter, hstep);
|
||||
}
|
||||
|
||||
#ifdef USE_ANGLE_ITER_ORDER_ASSERT
|
||||
if (hiter.axis_ordered) {
|
||||
hstep = hiter.axis_ordered;
|
||||
BLI_assert(hull_angle_canonical_cmp(angle_prev, hiter.axis_ordered->angle) > 0);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Comupte AABB Fitting Angle (Optimized)
|
||||
* \{ */
|
||||
|
@ -295,18 +566,12 @@ static float convexhull_2d_compute_extent_on_axis(const float (*points_hull)[2],
|
|||
const float2 &sincos,
|
||||
int *index_p)
|
||||
{
|
||||
/* NOTE(@ideasman42): This could be optimized to use a search strategy
|
||||
* that computes the upper bounds and narrows down the result instead of
|
||||
* simply checking every point until the new maximum is reached.
|
||||
* From looking into I couldn't find cases where doing this has significant benefits,
|
||||
* especially when compared with the complexity of using more involved logic for
|
||||
* the common case, where only a few steps are needed.
|
||||
* Typically the number of points to scan is small (around [0..8]).
|
||||
* And while a high-detail hull with single outliner points will cause stepping over
|
||||
* many more points, in practice there are rarely more than a few of these in a convex-hull.
|
||||
* Nevertheless, a high-poly hull that has subtle curves containing many points as well as
|
||||
* some sharp-corners wont perform as well with this method. */
|
||||
|
||||
/* NOTE(@ideasman42): Use a forward search instead of attempting a search strategy
|
||||
* computing upper & lower bounds (similar to a binary search). The rotating calipers
|
||||
* are ensured to test ordered rotations between 0-90 degrees, meaning any cases where
|
||||
* this function needs to step over many points will be limited to a small number of cases.
|
||||
* Since scanning forward isn't expensive it shouldn't pose a problem. */
|
||||
BLI_assert(*index_p >= 0);
|
||||
const int index_init = *index_p;
|
||||
int index_best = index_init;
|
||||
float value_init = (Axis == 0) ? sincos_rotate_cw_x(sincos, points_hull[index_best]) :
|
||||
|
@ -331,74 +596,46 @@ static float convexhull_2d_compute_extent_on_axis(const float (*points_hull)[2],
|
|||
static float convexhull_aabb_fit_hull_2d(const float (*points_hull)[2], int points_hull_num)
|
||||
{
|
||||
float area_best = FLT_MAX;
|
||||
float2 sincos_best; /* Track the best angle as a unit vector, delaying `atan2`. */
|
||||
bool is_first = true;
|
||||
float2 sincos_best = {0.0f, 1.0f}; /* Track the best angle as a unit vector, delaying `atan2`. */
|
||||
int index_best = INT_MAX;
|
||||
|
||||
/* Initialize to zero because the first pass uses the first index to set the bounds. */
|
||||
blender::Bounds<int> bounds_index[2] = {{0, 0}, {0, 0}};
|
||||
|
||||
for (int i = 0, i_prev = points_hull_num - 1; i < points_hull_num; i_prev = i++) {
|
||||
/* 2D rotation matrix. */
|
||||
float dvec_length = 0.0f;
|
||||
const float2 sincos = math::normalize_and_get_length(
|
||||
float2(points_hull[i]) - float2(points_hull[i_prev]), dvec_length);
|
||||
if (UNLIKELY(dvec_length == 0.0f)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (UNLIKELY(is_first)) {
|
||||
is_first = false;
|
||||
|
||||
blender::Bounds<float> bounds[2];
|
||||
|
||||
bounds[0].min = bounds[0].max = sincos_rotate_cw_x(sincos, points_hull[0]);
|
||||
bounds[1].min = bounds[1].max = sincos_rotate_cw_y(sincos, points_hull[0]);
|
||||
|
||||
bounds_index[0].min = bounds_index[0].max = 0;
|
||||
bounds_index[1].min = bounds_index[1].max = 0;
|
||||
|
||||
for (int j = 1; j < points_hull_num; j++) {
|
||||
const float2 tvec = {
|
||||
sincos_rotate_cw_x(sincos, points_hull[j]),
|
||||
sincos_rotate_cw_y(sincos, points_hull[j]),
|
||||
};
|
||||
for (int axis = 0; axis < 2; axis++) {
|
||||
if (tvec[axis] < bounds[axis].min) {
|
||||
bounds[axis].min = tvec[axis];
|
||||
bounds_index[axis].min = j;
|
||||
}
|
||||
if (tvec[axis] > bounds[axis].max) {
|
||||
bounds[axis].max = tvec[axis];
|
||||
bounds_index[axis].max = j;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
area_best = (bounds[0].max - bounds[0].min) * (bounds[1].max - bounds[1].min);
|
||||
sincos_best = sincos;
|
||||
continue;
|
||||
}
|
||||
HullAngleIter hull_iter = convexhull_2d_angle_iter_init(points_hull, points_hull_num);
|
||||
|
||||
/* Use the axis aligned bounds as starting points. */
|
||||
bounds_index[0].min = hull_iter.axis[0][1].angle.index;
|
||||
bounds_index[0].max = hull_iter.axis[0][0].angle.index;
|
||||
bounds_index[1].min = hull_iter.axis[1][0].angle.index;
|
||||
bounds_index[1].max = hull_iter.axis[1][1].angle.index;
|
||||
while (const HullAngleStep *hstep = hull_iter.axis_ordered) {
|
||||
/* Step the calipers to the new rotation `sincos`, returning the bounds at the same time. */
|
||||
blender::Bounds<float> bounds_test[2] = {
|
||||
{convexhull_2d_compute_extent_on_axis<0, -1>(
|
||||
points_hull, points_hull_num, sincos, &bounds_index[0].min),
|
||||
points_hull, points_hull_num, hstep->angle.sincos_canonical, &bounds_index[0].min),
|
||||
convexhull_2d_compute_extent_on_axis<0, 1>(
|
||||
points_hull, points_hull_num, sincos, &bounds_index[0].max)},
|
||||
points_hull, points_hull_num, hstep->angle.sincos_canonical, &bounds_index[0].max)},
|
||||
{convexhull_2d_compute_extent_on_axis<1, -1>(
|
||||
points_hull, points_hull_num, sincos, &bounds_index[1].min),
|
||||
points_hull, points_hull_num, hstep->angle.sincos_canonical, &bounds_index[1].min),
|
||||
convexhull_2d_compute_extent_on_axis<1, 1>(
|
||||
points_hull, points_hull_num, sincos, &bounds_index[1].max)},
|
||||
|
||||
points_hull, points_hull_num, hstep->angle.sincos_canonical, &bounds_index[1].max)},
|
||||
};
|
||||
|
||||
const float area_test = (bounds_test[0].max - bounds_test[0].min) *
|
||||
(bounds_test[1].max - bounds_test[1].min);
|
||||
|
||||
if (area_test < area_best) {
|
||||
if (area_test < area_best ||
|
||||
/* Use the index as a tie breaker, this simply matches the behavior of checking
|
||||
* all edges in-order and only overwriting past results when they're an improvement. */
|
||||
((area_test == area_best) && (hstep->angle.index < index_best)))
|
||||
{
|
||||
area_best = area_test;
|
||||
sincos_best = sincos;
|
||||
sincos_best = hstep->angle.sincos;
|
||||
index_best = hstep->angle.index;
|
||||
}
|
||||
|
||||
convexhull_2d_angle_iter_step(hull_iter);
|
||||
}
|
||||
|
||||
const float angle = (area_best != FLT_MAX) ? float(atan2(sincos_best[0], sincos_best[1])) : 0.0f;
|
||||
|
@ -406,8 +643,11 @@ static float convexhull_aabb_fit_hull_2d(const float (*points_hull)[2], int poin
|
|||
#if defined(USE_BRUTE_FORCE_ASSERT) && !defined(NDEBUG)
|
||||
{
|
||||
/* Ensure the optimized result matches the brute-force version. */
|
||||
const float angle_test = convexhull_aabb_fit_hull_2d_brute_force(points_hull, points_hull_num);
|
||||
BLI_assert(angle == angle_test);
|
||||
const float2 sincos_test = convexhull_aabb_fit_hull_2d_brute_force(points_hull,
|
||||
points_hull_num);
|
||||
if (sincos_best != sincos_test) {
|
||||
BLI_assert(sincos_best == sincos_test);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
|
@ -475,31 +475,31 @@ int BLI_rename(const char *from, const char *to)
|
|||
|
||||
#ifdef WIN32
|
||||
return urename(from, to, false);
|
||||
#elif defined(__APPLE__)
|
||||
return renamex_np(from, to, RENAME_EXCL);
|
||||
#else
|
||||
# if defined(__APPLE__)
|
||||
int ret = renamex_np(from, to, RENAME_EXCL);
|
||||
if (!(ret < 0 && errno == ENOTSUP)) {
|
||||
return ret;
|
||||
}
|
||||
# endif
|
||||
|
||||
# if defined(__GLIBC_PREREQ)
|
||||
# if __GLIBC_PREREQ(2, 28)
|
||||
/* Most common Linux case, use `RENAME_NOREPLACE` when available. */
|
||||
{
|
||||
const int ret = renameat2(AT_FDCWD, from, AT_FDCWD, to, RENAME_NOREPLACE);
|
||||
if (!(ret < 0 && errno == EINVAL)) {
|
||||
return ret;
|
||||
}
|
||||
/* Most likely a file-system that doesn't support RENAME_NOREPLACE.
|
||||
* (For example NFS, Samba, exFAT, NTFS, etc)
|
||||
* Fall through to use the generic UNIX non atomic operation, see #116049. */
|
||||
int ret = renameat2(AT_FDCWD, from, AT_FDCWD, to, RENAME_NOREPLACE);
|
||||
if (!(ret < 0 && errno == EINVAL)) {
|
||||
return ret;
|
||||
}
|
||||
# endif /* __GLIBC_PREREQ(2, 28) */
|
||||
# endif /* __GLIBC_PREREQ */
|
||||
|
||||
/* All BSD's currently & fallback for Linux. */
|
||||
/* A naive non-atomic implementation, which is used for OS where atomic rename is not supported
|
||||
* at all, or not implemented for specific file systems (for example NFS, Samba, exFAT, NTFS,
|
||||
* etc). For those see #116049, #119966. */
|
||||
if (BLI_exists(to)) {
|
||||
return 1;
|
||||
}
|
||||
return rename(from, to);
|
||||
#endif /* !defined(WIN32) && !defined(__APPLE__) */
|
||||
#endif /* !defined(WIN32) */
|
||||
}
|
||||
|
||||
int BLI_rename_overwrite(const char *from, const char *to)
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
|
||||
# include <algorithm>
|
||||
# include <fstream>
|
||||
# include <functional>
|
||||
# include <iostream>
|
||||
# include <memory>
|
||||
|
||||
|
@ -945,7 +946,7 @@ class CoplanarClusterInfo {
|
|||
return tri_cluster_[t];
|
||||
}
|
||||
|
||||
int add_cluster(CoplanarCluster cl)
|
||||
int add_cluster(const CoplanarCluster &cl)
|
||||
{
|
||||
int c_index = clusters_.append_and_get_index(cl);
|
||||
for (int t : cl) {
|
||||
|
|
|
@ -39,7 +39,7 @@ typedef struct PolyFill {
|
|||
uint edges, verts;
|
||||
float min_xy[2], max_xy[2];
|
||||
ushort nr;
|
||||
bool f;
|
||||
uchar f;
|
||||
} PolyFill;
|
||||
|
||||
typedef struct ScanFillVertLink {
|
||||
|
@ -52,19 +52,19 @@ typedef struct ScanFillVertLink {
|
|||
#define SF_EPSILON 0.00003f
|
||||
#define SF_EPSILON_SQ (SF_EPSILON * SF_EPSILON)
|
||||
|
||||
/** #ScanFillVert.status */
|
||||
/** #ScanFillVert::f (status) */
|
||||
#define SF_VERT_NEW 0 /* all new verts have this flag set */
|
||||
#define SF_VERT_AVAILABLE 1 /* available - in an edge */
|
||||
#define SF_VERT_ZERO_LEN 2
|
||||
|
||||
/** #ScanFillEdge.status */
|
||||
/** #ScanFillEdge::f (status) */
|
||||
/* Optionally set ScanFillEdge f to this to mark original boundary edges.
|
||||
* Only needed if there are internal diagonal edges passed to BLI_scanfill_calc. */
|
||||
#define SF_EDGE_NEW 0 /* all new edges have this flag set */
|
||||
// #define SF_EDGE_BOUNDARY 1 /* UNUSED */
|
||||
#define SF_EDGE_INTERNAL 2 /* edge is created while scan-filling */
|
||||
|
||||
/** #PolyFill.status */
|
||||
/** #PolyFill::f (status) */
|
||||
#define SF_POLY_NEW 0 /* all polys initialized to this */
|
||||
#define SF_POLY_VALID 1 /* has at least 3 verts */
|
||||
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
#include "BLI_math_geom.h"
|
||||
#include "BLI_math_matrix.h"
|
||||
#include "BLI_math_matrix_types.hh"
|
||||
#include "BLI_math_rotation.h"
|
||||
#include "BLI_math_rotation.hh"
|
||||
#include "BLI_math_vector.h"
|
||||
#include "BLI_math_vector.hh"
|
||||
|
@ -146,7 +147,7 @@ TEST(convexhull_2d, Lines_AxisAligned)
|
|||
for (int sign_x = -1; sign_x <= 2; sign_x += 2) {
|
||||
blender::Array<float2> points = {{0.0f, 0.0f}, {1.0f * sign_x, 0.0}};
|
||||
EXPECT_NEAR(convexhull_2d_aabb_fit_points_2d(points),
|
||||
float(math::AngleRadian::from_degree(-90.0f)),
|
||||
float(math::AngleRadian::from_degree(90.0f)),
|
||||
ROTATION_EPS);
|
||||
}
|
||||
}
|
||||
|
@ -154,7 +155,7 @@ TEST(convexhull_2d, Lines_AxisAligned)
|
|||
for (int sign_x = -1; sign_x <= 2; sign_x += 2) {
|
||||
blender::Array<float2> points = {{0.0f, 0.0f}, {1.0f * sign_x, 0.0}, {2.0f * sign_x, 0.0}};
|
||||
EXPECT_NEAR(convexhull_2d_aabb_fit_points_2d(points),
|
||||
float(math::AngleRadian::from_degree(-90.0f)),
|
||||
float(math::AngleRadian::from_degree(90.0f)),
|
||||
ROTATION_EPS);
|
||||
}
|
||||
}
|
||||
|
@ -163,7 +164,7 @@ TEST(convexhull_2d, Lines_AxisAligned)
|
|||
for (int sign_y = -1; sign_y <= 2; sign_y += 2) {
|
||||
blender::Array<float2> points = {{0.0f, 0.0f}, {0.0f, 1.0f * sign_y}};
|
||||
EXPECT_NEAR(convexhull_2d_aabb_fit_points_2d(points),
|
||||
float(math::AngleRadian::from_degree(180.0f)),
|
||||
float(math::AngleRadian::from_degree(0.0f)),
|
||||
ROTATION_EPS);
|
||||
}
|
||||
}
|
||||
|
@ -171,7 +172,7 @@ TEST(convexhull_2d, Lines_AxisAligned)
|
|||
for (int sign_y = -1; sign_y <= 2; sign_y += 2) {
|
||||
blender::Array<float2> points = {{0.0f, 0.0f}, {0.0f, 1.0f * sign_y}, {0.0f, 2.0f * sign_y}};
|
||||
EXPECT_NEAR(convexhull_2d_aabb_fit_points_2d(points),
|
||||
float(math::AngleRadian::from_degree(180.0f)),
|
||||
float(math::AngleRadian::from_degree(0.0f)),
|
||||
ROTATION_EPS);
|
||||
}
|
||||
}
|
||||
|
@ -186,7 +187,7 @@ TEST(convexhull_2d, Lines_AxisAligned)
|
|||
p[0] = 0.0;
|
||||
}
|
||||
|
||||
EXPECT_NEAR(convexhull_2d_aabb_fit_points_2d(points), M_PI, ROTATION_EPS);
|
||||
EXPECT_NEAR(convexhull_2d_aabb_fit_points_2d(points), 0.0f, ROTATION_EPS);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -201,7 +202,7 @@ TEST(convexhull_2d, Lines_AxisAligned)
|
|||
}
|
||||
|
||||
blender::Array<float2> points_hull = convexhull_2d_as_array(points);
|
||||
EXPECT_NEAR(convexhull_2d_aabb_fit_points_2d(points_hull), M_PI, ROTATION_EPS);
|
||||
EXPECT_NEAR(convexhull_2d_aabb_fit_points_2d(points_hull), 0.0f, ROTATION_EPS);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -209,7 +210,7 @@ TEST(convexhull_2d, Lines_AxisAligned)
|
|||
TEST(convexhull_2d, Lines_Diagonal)
|
||||
{
|
||||
{ /* Diagonal line (2 points). */
|
||||
const float expected[4] = {-135, 135, 135, -135};
|
||||
const float expected[4] = {45, -45, -45, 45};
|
||||
int index = 0;
|
||||
for (int sign_x = -1; sign_x <= 2; sign_x += 2) {
|
||||
for (int sign_y = -1; sign_y <= 2; sign_y += 2) {
|
||||
|
@ -223,7 +224,7 @@ TEST(convexhull_2d, Lines_Diagonal)
|
|||
}
|
||||
|
||||
{ /* Diagonal line (3 points). */
|
||||
const float expected[4] = {-135, 135, 135, -135};
|
||||
const float expected[4] = {45, -45, -45, 45};
|
||||
int index = 0;
|
||||
for (int sign_x = -1; sign_x <= 2; sign_x += 2) {
|
||||
for (int sign_y = -1; sign_y <= 2; sign_y += 2) {
|
||||
|
@ -251,7 +252,7 @@ TEST(convexhull_2d, Simple)
|
|||
{1.0f, 0.0f},
|
||||
};
|
||||
EXPECT_NEAR(convexhull_2d_aabb_fit_points_2d(points),
|
||||
float(math::AngleRadian::from_degree(135.0f)),
|
||||
float(math::AngleRadian::from_degree(45.0f)),
|
||||
ROTATION_EPS);
|
||||
}
|
||||
|
||||
|
@ -263,7 +264,51 @@ TEST(convexhull_2d, Simple)
|
|||
{1.0f, -1.0f},
|
||||
};
|
||||
EXPECT_NEAR(convexhull_2d_aabb_fit_points_2d(points),
|
||||
float(math::AngleRadian::from_degree(180.0f)),
|
||||
float(math::AngleRadian::from_degree(90.0f)),
|
||||
ROTATION_EPS);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(convexhull_2d, Octagon)
|
||||
{
|
||||
auto shape_octagon_fn = [](RandomNumberGenerator &rng,
|
||||
const int points_num) -> blender::Array<float2> {
|
||||
/* Avoid zero area boxes. */
|
||||
blender::Array<float2> points(points_num);
|
||||
for (int i = 0; i < points_num; i++) {
|
||||
sin_cos_from_fraction(i, points_num, &points[i][0], &points[i][1]);
|
||||
}
|
||||
rng.shuffle<float2>(points);
|
||||
return points;
|
||||
};
|
||||
|
||||
RandomNumberGenerator rng = RandomNumberGenerator(DEFAULT_TEST_RANDOM_SEED);
|
||||
for (int iter = 0; iter < DEFAULT_TEST_ITER; iter++) {
|
||||
blender::Array<float2> points = shape_octagon_fn(rng, 8);
|
||||
EXPECT_NEAR(convexhull_2d_aabb_fit_points_2d(points),
|
||||
float(math::AngleRadian::from_degree(67.5f)),
|
||||
ROTATION_EPS);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(convexhull_2d, OctagonAxisAligned)
|
||||
{
|
||||
auto shape_octagon_fn = [](RandomNumberGenerator &rng,
|
||||
const int points_num) -> blender::Array<float2> {
|
||||
/* Avoid zero area boxes. */
|
||||
blender::Array<float2> points(points_num);
|
||||
for (int i = 0; i < points_num; i++) {
|
||||
sin_cos_from_fraction((i * 2) + 1, points_num * 2, &points[i][0], &points[i][1]);
|
||||
}
|
||||
rng.shuffle<float2>(points);
|
||||
return points;
|
||||
};
|
||||
|
||||
RandomNumberGenerator rng = RandomNumberGenerator(DEFAULT_TEST_RANDOM_SEED);
|
||||
for (int iter = 0; iter < DEFAULT_TEST_ITER; iter++) {
|
||||
blender::Array<float2> points = shape_octagon_fn(rng, 8);
|
||||
EXPECT_NEAR(convexhull_2d_aabb_fit_points_2d(points),
|
||||
float(math::AngleRadian::from_degree(90.0f)),
|
||||
ROTATION_EPS);
|
||||
}
|
||||
}
|
||||
|
@ -343,4 +388,58 @@ TEST(convexhull_2d, Complex)
|
|||
}
|
||||
}
|
||||
|
||||
/* Keep these as they're handy for generating a lot of random data.
|
||||
* To brute force check results are as expected:
|
||||
* - Increase #DEFAULT_TEST_ITER to a large number (100k or so).
|
||||
* - Uncomment #USE_BRUTE_FORCE_ASSERT define in `convexhull_2d.cc` to ensure results
|
||||
* match a reference implementation.
|
||||
*/
|
||||
#if 0
|
||||
TEST(convexhull_2d, Circle)
|
||||
{
|
||||
auto shape_circle_fn = [](RandomNumberGenerator &rng,
|
||||
const int points_num) -> blender::Array<float2> {
|
||||
/* Avoid zero area boxes. */
|
||||
blender::Array<float2> points(points_num);
|
||||
|
||||
/* Going this way ends up with normal(s) upward */
|
||||
for (int i = 0; i < points_num; i++) {
|
||||
sin_cos_from_fraction(i, points_num, &points[i][0], &points[i][1]);
|
||||
}
|
||||
rng.shuffle<float2>(points);
|
||||
return points;
|
||||
};
|
||||
|
||||
RandomNumberGenerator rng = RandomNumberGenerator(DEFAULT_TEST_RANDOM_SEED);
|
||||
for (int iter = 0; iter < DEFAULT_TEST_ITER; iter++) {
|
||||
blender::Array<float2> points = shape_circle_fn(rng, DEFAULT_TEST_POLY_NUM);
|
||||
const float angle = convexhull_2d_aabb_fit_points_2d(points);
|
||||
(void)angle;
|
||||
}
|
||||
}
|
||||
|
||||
TEST(convexhull_2d, Random)
|
||||
{
|
||||
auto shape_random_unit_fn = [](RandomNumberGenerator &rng,
|
||||
const int points_num) -> blender::Array<float2> {
|
||||
/* Avoid zero area boxes. */
|
||||
blender::Array<float2> points(points_num);
|
||||
|
||||
/* Going this way ends up with normal(s) upward */
|
||||
for (int i = 0; i < points_num; i++) {
|
||||
points[i] = rng.get_unit_float2();
|
||||
}
|
||||
return points;
|
||||
};
|
||||
|
||||
RandomNumberGenerator rng = RandomNumberGenerator(DEFAULT_TEST_RANDOM_SEED);
|
||||
|
||||
for (int iter = 0; iter < DEFAULT_TEST_ITER; iter++) {
|
||||
blender::Array<float2> points = shape_random_unit_fn(rng, DEFAULT_TEST_POLY_NUM);
|
||||
const float angle = convexhull_2d_aabb_fit_points_2d(points);
|
||||
(void)angle;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/** \} */
|
||||
|
|
|
@ -126,7 +126,7 @@ bool BLO_main_validate_libraries(Main *bmain, ReportList *reports)
|
|||
|
||||
LinkNode *name = names;
|
||||
for (; name; name = name->next) {
|
||||
char *str_name = (char *)name->link;
|
||||
const char *str_name = (const char *)name->link;
|
||||
if (id->name[2] == str_name[0] && STREQ(str_name, id->name + 2)) {
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -1335,8 +1335,9 @@ void blo_do_versions_290(FileData *fd, Library * /*lib*/, Main *bmain)
|
|||
}
|
||||
}
|
||||
if (relation->parentid == 0) {
|
||||
BLI_assert(
|
||||
!"Found a valid parent for workspace data relation, but no valid parent id.");
|
||||
BLI_assert_msg(
|
||||
false,
|
||||
"Found a valid parent for workspace data relation, but no valid parent id.");
|
||||
}
|
||||
}
|
||||
if (relation->parentid == 0) {
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
|
||||
#include "DNA_scene_types.h"
|
||||
|
||||
#include "BLI_array.hh"
|
||||
#include "BLI_bitmap.h"
|
||||
#include "BLI_linklist_stack.h"
|
||||
#include "BLI_math_base.hh"
|
||||
|
@ -29,15 +30,18 @@
|
|||
|
||||
#include "intern/bmesh_private.hh"
|
||||
|
||||
using blender::Array;
|
||||
using blender::float3;
|
||||
using blender::MutableSpan;
|
||||
using blender::Span;
|
||||
|
||||
/* Smooth angle to use when tagging edges is disabled entirely. */
|
||||
#define EDGE_TAG_FROM_SPLIT_ANGLE_BYPASS -FLT_MAX
|
||||
|
||||
static void bm_edge_tag_from_smooth_and_set_sharp(const float (*fnos)[3],
|
||||
static void bm_edge_tag_from_smooth_and_set_sharp(Span<float3> fnos,
|
||||
BMEdge *e,
|
||||
const float split_angle_cos);
|
||||
static void bm_edge_tag_from_smooth(const float (*fnos)[3],
|
||||
BMEdge *e,
|
||||
const float split_angle_cos);
|
||||
static void bm_edge_tag_from_smooth(Span<float3> fnos, BMEdge *e, const float split_angle_cos);
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Update Vertex & Face Normals
|
||||
|
@ -53,11 +57,11 @@ static void bm_edge_tag_from_smooth(const float (*fnos)[3],
|
|||
|
||||
struct BMVertsCalcNormalsWithCoordsData {
|
||||
/* Read-only data. */
|
||||
const float (*fnos)[3];
|
||||
const float (*vcos)[3];
|
||||
Span<float3> fnos;
|
||||
Span<float3> vcos;
|
||||
|
||||
/* Write data. */
|
||||
float (*vnos)[3];
|
||||
MutableSpan<float3> vnos;
|
||||
};
|
||||
|
||||
BLI_INLINE void bm_vert_calc_normals_accum_loop(const BMLoop *l_iter,
|
||||
|
@ -204,21 +208,21 @@ static void bm_vert_calc_normals_with_coords_cb(void *userdata,
|
|||
}
|
||||
|
||||
static void bm_mesh_verts_calc_normals(BMesh *bm,
|
||||
const float (*fnos)[3],
|
||||
const float (*vcos)[3],
|
||||
float (*vnos)[3])
|
||||
const Span<float3> fnos,
|
||||
const Span<float3> vcos,
|
||||
MutableSpan<float3> vnos)
|
||||
{
|
||||
BM_mesh_elem_index_ensure(bm, BM_FACE | ((vnos || vcos) ? BM_VERT : 0));
|
||||
BM_mesh_elem_index_ensure(bm, BM_FACE | ((!vnos.is_empty() || !vcos.is_empty()) ? BM_VERT : 0));
|
||||
|
||||
TaskParallelSettings settings;
|
||||
BLI_parallel_mempool_settings_defaults(&settings);
|
||||
settings.use_threading = bm->totvert >= BM_THREAD_LIMIT;
|
||||
|
||||
if (vcos == nullptr) {
|
||||
if (vcos.is_empty()) {
|
||||
BM_iter_parallel(bm, BM_VERTS_OF_MESH, bm_vert_calc_normals_cb, nullptr, &settings);
|
||||
}
|
||||
else {
|
||||
BLI_assert(!ELEM(nullptr, fnos, vnos));
|
||||
BLI_assert(!fnos.is_empty() || !vnos.is_empty());
|
||||
BMVertsCalcNormalsWithCoordsData data{};
|
||||
data.fnos = fnos;
|
||||
data.vcos = vcos;
|
||||
|
@ -248,7 +252,7 @@ void BM_mesh_normals_update_ex(BMesh *bm, const BMeshNormalsUpdate_Params *param
|
|||
}
|
||||
|
||||
/* Add weighted face normals to vertices, and normalize vert normals. */
|
||||
bm_mesh_verts_calc_normals(bm, nullptr, nullptr, nullptr);
|
||||
bm_mesh_verts_calc_normals(bm, {}, {}, {});
|
||||
}
|
||||
|
||||
void BM_mesh_normals_update(BMesh *bm)
|
||||
|
@ -321,9 +325,9 @@ void BM_mesh_normals_update_with_partial(BMesh *bm, const BMPartialUpdate *bmpin
|
|||
* \{ */
|
||||
|
||||
void BM_verts_calc_normal_vcos(BMesh *bm,
|
||||
const float (*fnos)[3],
|
||||
const float (*vcos)[3],
|
||||
float (*vnos)[3])
|
||||
const Span<float3> fnos,
|
||||
const Span<float3> vcos,
|
||||
MutableSpan<float3> vnos)
|
||||
{
|
||||
/* Add weighted face normals to vertices, and normalize vert normals. */
|
||||
bm_mesh_verts_calc_normals(bm, fnos, vcos, vnos);
|
||||
|
@ -374,7 +378,7 @@ void BM_normals_loops_edges_tag(BMesh *bm, const bool do_edges)
|
|||
* Helpers for #BM_mesh_loop_normals_update and #BM_loops_calc_normal_vcos
|
||||
*/
|
||||
static void bm_mesh_edges_sharp_tag(BMesh *bm,
|
||||
const float (*fnos)[3],
|
||||
const Span<float3> fnos,
|
||||
float split_angle_cos,
|
||||
const bool do_sharp_edges_tag)
|
||||
{
|
||||
|
@ -382,7 +386,7 @@ static void bm_mesh_edges_sharp_tag(BMesh *bm,
|
|||
BMEdge *e;
|
||||
int i;
|
||||
|
||||
if (fnos) {
|
||||
if (!fnos.is_empty()) {
|
||||
BM_mesh_elem_index_ensure(bm, BM_FACE);
|
||||
}
|
||||
|
||||
|
@ -413,7 +417,7 @@ void BM_edges_sharp_from_angle_set(BMesh *bm, const float split_angle)
|
|||
return;
|
||||
}
|
||||
|
||||
bm_mesh_edges_sharp_tag(bm, nullptr, cosf(split_angle), true);
|
||||
bm_mesh_edges_sharp_tag(bm, {}, cosf(split_angle), true);
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
@ -467,8 +471,8 @@ bool BM_loop_check_cyclic_smooth_fan(BMLoop *l_curr)
|
|||
* \return The number of loops that were handled (for early exit when all have been handled).
|
||||
*/
|
||||
static int bm_mesh_loops_calc_normals_for_loop(BMesh *bm,
|
||||
const float (*vcos)[3],
|
||||
const float (*fnos)[3],
|
||||
const Span<float3> vcos,
|
||||
const Span<float3> fnos,
|
||||
const short (*clnors_data)[2],
|
||||
const int cd_loop_clnors_offset,
|
||||
const bool has_clnors,
|
||||
|
@ -477,12 +481,12 @@ static int bm_mesh_loops_calc_normals_for_loop(BMesh *bm,
|
|||
/* Iterate. */
|
||||
BMLoop *l_curr,
|
||||
/* Result. */
|
||||
float (*r_lnos)[3],
|
||||
MutableSpan<float3> r_lnos,
|
||||
MLoopNorSpaceArray *r_lnors_spacearr)
|
||||
{
|
||||
BLI_assert((bm->elem_index_dirty & BM_LOOP) == 0);
|
||||
BLI_assert((fnos == nullptr) || ((bm->elem_index_dirty & BM_FACE) == 0));
|
||||
BLI_assert((vcos == nullptr) || ((bm->elem_index_dirty & BM_VERT) == 0));
|
||||
BLI_assert(fnos.is_empty() || ((bm->elem_index_dirty & BM_FACE) == 0));
|
||||
BLI_assert(vcos.is_empty() || ((bm->elem_index_dirty & BM_VERT) == 0));
|
||||
UNUSED_VARS_NDEBUG(bm);
|
||||
|
||||
int handled = 0;
|
||||
|
@ -514,7 +518,8 @@ static int bm_mesh_loops_calc_normals_for_loop(BMesh *bm,
|
|||
* this vertex just takes its face normal.
|
||||
*/
|
||||
const int l_curr_index = BM_elem_index_get(l_curr);
|
||||
const float *no = fnos ? fnos[BM_elem_index_get(l_curr->f)] : l_curr->f->no;
|
||||
const float3 no = !fnos.is_empty() ? fnos[BM_elem_index_get(l_curr->f)] :
|
||||
float3(l_curr->f->no);
|
||||
copy_v3_v3(r_lnos[l_curr_index], no);
|
||||
|
||||
/* If needed, generate this (simple!) lnor space. */
|
||||
|
@ -524,11 +529,12 @@ static int bm_mesh_loops_calc_normals_for_loop(BMesh *bm,
|
|||
|
||||
{
|
||||
const BMVert *v_pivot = l_curr->v;
|
||||
const float *co_pivot = vcos ? vcos[BM_elem_index_get(v_pivot)] : v_pivot->co;
|
||||
const float3 co_pivot = !vcos.is_empty() ? vcos[BM_elem_index_get(v_pivot)] :
|
||||
float3(v_pivot->co);
|
||||
const BMVert *v_1 = l_curr->next->v;
|
||||
const float *co_1 = vcos ? vcos[BM_elem_index_get(v_1)] : v_1->co;
|
||||
const float3 co_1 = !vcos.is_empty() ? vcos[BM_elem_index_get(v_1)] : float3(v_1->co);
|
||||
const BMVert *v_2 = l_curr->prev->v;
|
||||
const float *co_2 = vcos ? vcos[BM_elem_index_get(v_2)] : v_2->co;
|
||||
const float3 co_2 = !vcos.is_empty() ? vcos[BM_elem_index_get(v_2)] : float3(v_2->co);
|
||||
|
||||
BLI_assert(v_1 == BM_edge_other_vert(l_curr->e, v_pivot));
|
||||
BLI_assert(v_2 == BM_edge_other_vert(l_curr->prev->e, v_pivot));
|
||||
|
@ -586,7 +592,8 @@ static int bm_mesh_loops_calc_normals_for_loop(BMesh *bm,
|
|||
int clnors_count = 0;
|
||||
bool clnors_invalid = false;
|
||||
|
||||
const float *co_pivot = vcos ? vcos[BM_elem_index_get(v_pivot)] : v_pivot->co;
|
||||
const float3 co_pivot = !vcos.is_empty() ? vcos[BM_elem_index_get(v_pivot)] :
|
||||
float3(v_pivot->co);
|
||||
|
||||
MLoopNorSpace *lnor_space = r_lnors_spacearr ? BKE_lnor_space_create(r_lnors_spacearr) :
|
||||
nullptr;
|
||||
|
@ -601,7 +608,7 @@ static int bm_mesh_loops_calc_normals_for_loop(BMesh *bm,
|
|||
* then we can just reuse old current one! */
|
||||
{
|
||||
const BMVert *v_2 = lfan_pivot->next->v;
|
||||
const float *co_2 = vcos ? vcos[BM_elem_index_get(v_2)] : v_2->co;
|
||||
const float3 co_2 = !vcos.is_empty() ? vcos[BM_elem_index_get(v_2)] : float3(v_2->co);
|
||||
|
||||
BLI_assert(v_2 == BM_edge_other_vert(e_next, v_pivot));
|
||||
|
||||
|
@ -633,7 +640,7 @@ static int bm_mesh_loops_calc_normals_for_loop(BMesh *bm,
|
|||
*/
|
||||
{
|
||||
const BMVert *v_2 = BM_edge_other_vert(e_next, v_pivot);
|
||||
const float *co_2 = vcos ? vcos[BM_elem_index_get(v_2)] : v_2->co;
|
||||
const float3 co_2 = !vcos.is_empty() ? vcos[BM_elem_index_get(v_2)] : float3(v_2->co);
|
||||
|
||||
sub_v3_v3v3(vec_next, co_2, co_pivot);
|
||||
normalize_v3(vec_next);
|
||||
|
@ -644,7 +651,7 @@ static int bm_mesh_loops_calc_normals_for_loop(BMesh *bm,
|
|||
/* Calculate angle between the two face edges incident on this vertex. */
|
||||
const BMFace *f = lfan_pivot->f;
|
||||
const float fac = blender::math::safe_acos_approx(dot_v3v3(vec_next, vec_curr));
|
||||
const float *no = fnos ? fnos[BM_elem_index_get(f)] : f->no;
|
||||
const float3 no = !fnos.is_empty() ? fnos[BM_elem_index_get(f)] : float3(f->no);
|
||||
/* Accumulate */
|
||||
madd_v3_v3fl(lnor, no, fac);
|
||||
|
||||
|
@ -795,16 +802,18 @@ BLI_INLINE bool bm_edge_is_smooth_no_angle_test(const BMEdge *e,
|
|||
BM_elem_flag_test(l_a->f, BM_ELEM_SMOOTH) && BM_elem_flag_test(l_b->f, BM_ELEM_SMOOTH));
|
||||
}
|
||||
|
||||
static void bm_edge_tag_from_smooth(const float (*fnos)[3], BMEdge *e, const float split_angle_cos)
|
||||
static void bm_edge_tag_from_smooth(const Span<float3> fnos,
|
||||
BMEdge *e,
|
||||
const float split_angle_cos)
|
||||
{
|
||||
BLI_assert(e->l != nullptr);
|
||||
BMLoop *l_a = e->l, *l_b = l_a->radial_next;
|
||||
bool is_smooth = false;
|
||||
if (bm_edge_is_smooth_no_angle_test(e, l_a, l_b)) {
|
||||
if (split_angle_cos != -1.0f) {
|
||||
const float dot = (fnos == nullptr) ? dot_v3v3(l_a->f->no, l_b->f->no) :
|
||||
dot_v3v3(fnos[BM_elem_index_get(l_a->f)],
|
||||
fnos[BM_elem_index_get(l_b->f)]);
|
||||
const float dot = fnos.is_empty() ? dot_v3v3(l_a->f->no, l_b->f->no) :
|
||||
dot_v3v3(fnos[BM_elem_index_get(l_a->f)],
|
||||
fnos[BM_elem_index_get(l_b->f)]);
|
||||
if (dot >= split_angle_cos) {
|
||||
is_smooth = true;
|
||||
}
|
||||
|
@ -834,7 +843,7 @@ static void bm_edge_tag_from_smooth(const float (*fnos)[3], BMEdge *e, const flo
|
|||
* \note This doesn't have the same atomic requirement as #bm_edge_tag_from_smooth
|
||||
* since it isn't run from multiple threads at once.
|
||||
*/
|
||||
static void bm_edge_tag_from_smooth_and_set_sharp(const float (*fnos)[3],
|
||||
static void bm_edge_tag_from_smooth_and_set_sharp(const Span<float3> fnos,
|
||||
BMEdge *e,
|
||||
const float split_angle_cos)
|
||||
{
|
||||
|
@ -843,9 +852,9 @@ static void bm_edge_tag_from_smooth_and_set_sharp(const float (*fnos)[3],
|
|||
bool is_smooth = false;
|
||||
if (bm_edge_is_smooth_no_angle_test(e, l_a, l_b)) {
|
||||
if (split_angle_cos != -1.0f) {
|
||||
const float dot = (fnos == nullptr) ? dot_v3v3(l_a->f->no, l_b->f->no) :
|
||||
dot_v3v3(fnos[BM_elem_index_get(l_a->f)],
|
||||
fnos[BM_elem_index_get(l_b->f)]);
|
||||
const float dot = fnos.is_empty() ? dot_v3v3(l_a->f->no, l_b->f->no) :
|
||||
dot_v3v3(fnos[BM_elem_index_get(l_a->f)],
|
||||
fnos[BM_elem_index_get(l_b->f)]);
|
||||
if (dot >= split_angle_cos) {
|
||||
is_smooth = true;
|
||||
}
|
||||
|
@ -871,9 +880,9 @@ static void bm_edge_tag_from_smooth_and_set_sharp(const float (*fnos)[3],
|
|||
*/
|
||||
static void bm_mesh_loops_calc_normals_for_vert_with_clnors(
|
||||
BMesh *bm,
|
||||
const float (*vcos)[3],
|
||||
const float (*fnos)[3],
|
||||
float (*r_lnos)[3],
|
||||
const Span<float3> vcos,
|
||||
const Span<float3> fnos,
|
||||
MutableSpan<float3> r_lnos,
|
||||
const short (*clnors_data)[2],
|
||||
const int cd_loop_clnors_offset,
|
||||
const bool do_rebuild,
|
||||
|
@ -993,9 +1002,9 @@ static void bm_mesh_loops_calc_normals_for_vert_with_clnors(
|
|||
*/
|
||||
static void bm_mesh_loops_calc_normals_for_vert_without_clnors(
|
||||
BMesh *bm,
|
||||
const float (*vcos)[3],
|
||||
const float (*fnos)[3],
|
||||
float (*r_lnos)[3],
|
||||
const Span<float3> vcos,
|
||||
const Span<float3> fnos,
|
||||
MutableSpan<float3> r_lnos,
|
||||
const bool do_rebuild,
|
||||
const float split_angle_cos,
|
||||
/* TLS */
|
||||
|
@ -1070,9 +1079,9 @@ static void bm_mesh_loops_calc_normals_for_vert_without_clnors(
|
|||
* we could add a low-level API flag for this, see #BM_ELEM_API_FLAG_ENABLE and friends.
|
||||
*/
|
||||
static void bm_mesh_loops_calc_normals__single_threaded(BMesh *bm,
|
||||
const float (*vcos)[3],
|
||||
const float (*fnos)[3],
|
||||
float (*r_lnos)[3],
|
||||
const Span<float3> vcos,
|
||||
const Span<float3> fnos,
|
||||
MutableSpan<float3> r_lnos,
|
||||
MLoopNorSpaceArray *r_lnors_spacearr,
|
||||
const short (*clnors_data)[2],
|
||||
const int cd_loop_clnors_offset,
|
||||
|
@ -1091,7 +1100,7 @@ static void bm_mesh_loops_calc_normals__single_threaded(BMesh *bm,
|
|||
|
||||
{
|
||||
char htype = 0;
|
||||
if (vcos) {
|
||||
if (!vcos.is_empty()) {
|
||||
htype |= BM_VERT;
|
||||
}
|
||||
/* Face/Loop indices are set inline below. */
|
||||
|
@ -1164,8 +1173,8 @@ static void bm_mesh_loops_calc_normals__single_threaded(BMesh *bm,
|
|||
|
||||
struct BMLoopsCalcNormalsWithCoordsData {
|
||||
/* Read-only data. */
|
||||
const float (*fnos)[3];
|
||||
const float (*vcos)[3];
|
||||
Span<float3> vcos;
|
||||
Span<float3> fnos;
|
||||
BMesh *bm;
|
||||
const short (*clnors_data)[2];
|
||||
int cd_loop_clnors_offset;
|
||||
|
@ -1173,7 +1182,7 @@ struct BMLoopsCalcNormalsWithCoordsData {
|
|||
float split_angle_cos;
|
||||
|
||||
/* Output. */
|
||||
float (*r_lnos)[3];
|
||||
MutableSpan<float3> r_lnos;
|
||||
MLoopNorSpaceArray *r_lnors_spacearr;
|
||||
};
|
||||
|
||||
|
@ -1272,9 +1281,9 @@ static void bm_mesh_loops_calc_normals_for_vert_without_clnors_fn(
|
|||
}
|
||||
|
||||
static void bm_mesh_loops_calc_normals__multi_threaded(BMesh *bm,
|
||||
const float (*vcos)[3],
|
||||
const float (*fnos)[3],
|
||||
float (*r_lnos)[3],
|
||||
const Span<float3> vcos,
|
||||
const Span<float3> fnos,
|
||||
MutableSpan<float3> r_lnos,
|
||||
MLoopNorSpaceArray *r_lnors_spacearr,
|
||||
const short (*clnors_data)[2],
|
||||
const int cd_loop_clnors_offset,
|
||||
|
@ -1286,10 +1295,10 @@ static void bm_mesh_loops_calc_normals__multi_threaded(BMesh *bm,
|
|||
|
||||
{
|
||||
char htype = BM_LOOP;
|
||||
if (vcos) {
|
||||
if (!vcos.is_empty()) {
|
||||
htype |= BM_VERT;
|
||||
}
|
||||
if (fnos) {
|
||||
if (!fnos.is_empty()) {
|
||||
htype |= BM_FACE;
|
||||
}
|
||||
/* Face/Loop indices are set inline below. */
|
||||
|
@ -1347,9 +1356,9 @@ static void bm_mesh_loops_calc_normals__multi_threaded(BMesh *bm,
|
|||
}
|
||||
|
||||
static void bm_mesh_loops_calc_normals(BMesh *bm,
|
||||
const float (*vcos)[3],
|
||||
const float (*fnos)[3],
|
||||
float (*r_lnos)[3],
|
||||
const Span<float3> vcos,
|
||||
const Span<float3> fnos,
|
||||
MutableSpan<float3> r_lnos,
|
||||
MLoopNorSpaceArray *r_lnors_spacearr,
|
||||
const short (*clnors_data)[2],
|
||||
const int cd_loop_clnors_offset,
|
||||
|
@ -1572,8 +1581,8 @@ static void bm_mesh_loops_assign_normal_data(BMesh *bm,
|
|||
* instead, depending on the do_split_fans parameter.
|
||||
*/
|
||||
static void bm_mesh_loops_custom_normals_set(BMesh *bm,
|
||||
const float (*vcos)[3],
|
||||
const float (*fnos)[3],
|
||||
const Span<float3> vcos,
|
||||
const Span<float3> fnos,
|
||||
MLoopNorSpaceArray *r_lnors_spacearr,
|
||||
short (*r_clnors_data)[2],
|
||||
const int cd_loop_clnors_offset,
|
||||
|
@ -1584,8 +1593,7 @@ static void bm_mesh_loops_custom_normals_set(BMesh *bm,
|
|||
BMFace *f;
|
||||
BMLoop *l;
|
||||
BMIter liter, fiter;
|
||||
float(*cur_lnors)[3] = static_cast<float(*)[3]>(
|
||||
MEM_mallocN(sizeof(*cur_lnors) * bm->totloop, __func__));
|
||||
Array<float3> cur_lnors(bm->totloop);
|
||||
|
||||
BKE_lnor_spacearr_clear(r_lnors_spacearr);
|
||||
|
||||
|
@ -1653,27 +1661,25 @@ static void bm_mesh_loops_custom_normals_set(BMesh *bm,
|
|||
bm_mesh_loops_assign_normal_data(
|
||||
bm, r_lnors_spacearr, r_clnors_data, cd_loop_clnors_offset, custom_lnors);
|
||||
|
||||
MEM_freeN(cur_lnors);
|
||||
|
||||
if (custom_lnors != new_lnors) {
|
||||
MEM_freeN(custom_lnors);
|
||||
}
|
||||
}
|
||||
|
||||
static void bm_mesh_loops_calc_normals_no_autosmooth(BMesh *bm,
|
||||
const float (*vnos)[3],
|
||||
const float (*fnos)[3],
|
||||
float (*r_lnos)[3])
|
||||
const Span<float3> vnos,
|
||||
const Span<float3> fnos,
|
||||
MutableSpan<float3> r_lnos)
|
||||
{
|
||||
BMIter fiter;
|
||||
BMFace *f_curr;
|
||||
|
||||
{
|
||||
char htype = BM_LOOP;
|
||||
if (vnos) {
|
||||
if (!vnos.is_empty()) {
|
||||
htype |= BM_VERT;
|
||||
}
|
||||
if (fnos) {
|
||||
if (!fnos.is_empty()) {
|
||||
htype |= BM_FACE;
|
||||
}
|
||||
BM_mesh_elem_index_ensure(bm, htype);
|
||||
|
@ -1685,8 +1691,10 @@ static void bm_mesh_loops_calc_normals_no_autosmooth(BMesh *bm,
|
|||
|
||||
l_curr = l_first = BM_FACE_FIRST_LOOP(f_curr);
|
||||
do {
|
||||
const float *no = is_face_flat ? (fnos ? fnos[BM_elem_index_get(f_curr)] : f_curr->no) :
|
||||
(vnos ? vnos[BM_elem_index_get(l_curr->v)] : l_curr->v->no);
|
||||
const float3 no = is_face_flat ? (!fnos.is_empty() ? fnos[BM_elem_index_get(f_curr)] :
|
||||
float3(f_curr->no)) :
|
||||
(!vnos.is_empty() ? vnos[BM_elem_index_get(l_curr->v)] :
|
||||
float3(l_curr->v->no));
|
||||
copy_v3_v3(r_lnos[BM_elem_index_get(l_curr)], no);
|
||||
|
||||
} while ((l_curr = l_curr->next) != l_first);
|
||||
|
@ -1694,11 +1702,11 @@ static void bm_mesh_loops_calc_normals_no_autosmooth(BMesh *bm,
|
|||
}
|
||||
|
||||
void BM_loops_calc_normal_vcos(BMesh *bm,
|
||||
const float (*vcos)[3],
|
||||
const float (*vnos)[3],
|
||||
const float (*fnos)[3],
|
||||
const Span<float3> vcos,
|
||||
const Span<float3> vnos,
|
||||
const Span<float3> fnos,
|
||||
const bool use_split_normals,
|
||||
float (*r_lnos)[3],
|
||||
MutableSpan<float3> r_lnos,
|
||||
MLoopNorSpaceArray *r_lnors_spacearr,
|
||||
short (*clnors_data)[2],
|
||||
const int cd_loop_clnors_offset,
|
||||
|
@ -1728,7 +1736,7 @@ void BM_loops_calc_normal_vcos(BMesh *bm,
|
|||
/** \name Loop Normal Space API
|
||||
* \{ */
|
||||
|
||||
void BM_lnorspacearr_store(BMesh *bm, float (*r_lnors)[3])
|
||||
void BM_lnorspacearr_store(BMesh *bm, MutableSpan<float3> r_lnors)
|
||||
{
|
||||
BLI_assert(bm->lnor_spacearr != nullptr);
|
||||
|
||||
|
@ -1738,16 +1746,8 @@ void BM_lnorspacearr_store(BMesh *bm, float (*r_lnors)[3])
|
|||
|
||||
int cd_loop_clnors_offset = CustomData_get_offset(&bm->ldata, CD_CUSTOMLOOPNORMAL);
|
||||
|
||||
BM_loops_calc_normal_vcos(bm,
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr,
|
||||
true,
|
||||
r_lnors,
|
||||
bm->lnor_spacearr,
|
||||
nullptr,
|
||||
cd_loop_clnors_offset,
|
||||
false);
|
||||
BM_loops_calc_normal_vcos(
|
||||
bm, {}, {}, {}, true, r_lnors, bm->lnor_spacearr, nullptr, cd_loop_clnors_offset, false);
|
||||
bm->spacearr_dirty &= ~(BM_SPACEARR_DIRTY | BM_SPACEARR_DIRTY_ALL);
|
||||
}
|
||||
|
||||
|
@ -1834,10 +1834,8 @@ void BM_lnorspace_rebuild(BMesh *bm, bool preserve_clnor)
|
|||
BMLoop *l;
|
||||
BMIter fiter, liter;
|
||||
|
||||
float(*r_lnors)[3] = static_cast<float(*)[3]>(
|
||||
MEM_callocN(sizeof(*r_lnors) * bm->totloop, __func__));
|
||||
float(*oldnors)[3] = static_cast<float(*)[3]>(
|
||||
preserve_clnor ? MEM_mallocN(sizeof(*oldnors) * bm->totloop, __func__) : nullptr);
|
||||
Array<float3> r_lnors(bm->totloop, float3(0));
|
||||
Array<float3> oldnors(preserve_clnor ? bm->totloop : 0, float3(0));
|
||||
|
||||
int cd_loop_clnors_offset = CustomData_get_offset(&bm->ldata, CD_CUSTOMLOOPNORMAL);
|
||||
|
||||
|
@ -1865,17 +1863,8 @@ void BM_lnorspace_rebuild(BMesh *bm, bool preserve_clnor)
|
|||
if (bm->spacearr_dirty & BM_SPACEARR_DIRTY_ALL) {
|
||||
BKE_lnor_spacearr_clear(bm->lnor_spacearr);
|
||||
}
|
||||
BM_loops_calc_normal_vcos(bm,
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr,
|
||||
true,
|
||||
r_lnors,
|
||||
bm->lnor_spacearr,
|
||||
nullptr,
|
||||
cd_loop_clnors_offset,
|
||||
true);
|
||||
MEM_freeN(r_lnors);
|
||||
BM_loops_calc_normal_vcos(
|
||||
bm, {}, {}, {}, true, r_lnors, bm->lnor_spacearr, nullptr, cd_loop_clnors_offset, true);
|
||||
|
||||
BM_ITER_MESH (f, &fiter, bm, BM_FACES_OF_MESH) {
|
||||
BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) {
|
||||
|
@ -1894,7 +1883,6 @@ void BM_lnorspace_rebuild(BMesh *bm, bool preserve_clnor)
|
|||
}
|
||||
}
|
||||
|
||||
MEM_SAFE_FREE(oldnors);
|
||||
bm->spacearr_dirty &= ~(BM_SPACEARR_DIRTY | BM_SPACEARR_DIRTY_ALL);
|
||||
|
||||
#ifndef NDEBUG
|
||||
|
@ -1908,12 +1896,8 @@ void BM_lnorspace_update(BMesh *bm)
|
|||
bm->lnor_spacearr = MEM_cnew<MLoopNorSpaceArray>(__func__);
|
||||
}
|
||||
if (bm->lnor_spacearr->lspacearr == nullptr) {
|
||||
float(*lnors)[3] = static_cast<float(*)[3]>(
|
||||
MEM_callocN(sizeof(*lnors) * bm->totloop, __func__));
|
||||
|
||||
Array<float3> lnors(bm->totloop, float3(0));
|
||||
BM_lnorspacearr_store(bm, lnors);
|
||||
|
||||
MEM_freeN(lnors);
|
||||
}
|
||||
else if (bm->spacearr_dirty & (BM_SPACEARR_DIRTY | BM_SPACEARR_DIRTY_ALL)) {
|
||||
BM_lnorspace_rebuild(bm, false);
|
||||
|
@ -1945,9 +1929,9 @@ void BM_lnorspace_err(BMesh *bm)
|
|||
BKE_lnor_spacearr_init(temp, bm->totloop, MLNOR_SPACEARR_BMLOOP_PTR);
|
||||
|
||||
int cd_loop_clnors_offset = CustomData_get_offset(&bm->ldata, CD_CUSTOMLOOPNORMAL);
|
||||
float(*lnors)[3] = static_cast<float(*)[3]>(MEM_callocN(sizeof(*lnors) * bm->totloop, __func__));
|
||||
Array<float3> lnors(bm->totloop, float3(0));
|
||||
BM_loops_calc_normal_vcos(
|
||||
bm, nullptr, nullptr, nullptr, true, lnors, temp, nullptr, cd_loop_clnors_offset, true);
|
||||
bm, {}, {}, {}, true, lnors, temp, nullptr, cd_loop_clnors_offset, true);
|
||||
|
||||
for (int i = 0; i < bm->totloop; i++) {
|
||||
int j = 0;
|
||||
|
@ -1969,7 +1953,6 @@ void BM_lnorspace_err(BMesh *bm)
|
|||
}
|
||||
BKE_lnor_spacearr_free(temp);
|
||||
MEM_freeN(temp);
|
||||
MEM_freeN(lnors);
|
||||
BLI_assert(clear);
|
||||
|
||||
bm->spacearr_dirty &= ~BM_SPACEARR_DIRTY_ALL;
|
||||
|
@ -2268,8 +2251,8 @@ void BM_custom_loop_normals_from_vector_layer(BMesh *bm, bool add_sharp_edges)
|
|||
}
|
||||
|
||||
bm_mesh_loops_custom_normals_set(bm,
|
||||
nullptr,
|
||||
nullptr,
|
||||
{},
|
||||
{},
|
||||
bm->lnor_spacearr,
|
||||
nullptr,
|
||||
cd_custom_normal_offset,
|
||||
|
|
|
@ -43,9 +43,9 @@ void BM_mesh_normals_update_with_partial(BMesh *bm, const BMPartialUpdate *bmpin
|
|||
* using given vertex coordinates (vcos) and polygon normals (fnos).
|
||||
*/
|
||||
void BM_verts_calc_normal_vcos(BMesh *bm,
|
||||
const float (*fnos)[3],
|
||||
const float (*vcos)[3],
|
||||
float (*vnos)[3]);
|
||||
blender::Span<blender::float3> fnos,
|
||||
blender::Span<blender::float3> vcos,
|
||||
blender::MutableSpan<blender::float3> vnos);
|
||||
/**
|
||||
* \brief BMesh Compute Loop Normals from/to external data.
|
||||
*
|
||||
|
@ -54,11 +54,11 @@ void BM_verts_calc_normal_vcos(BMesh *bm,
|
|||
* (splitting edges).
|
||||
*/
|
||||
void BM_loops_calc_normal_vcos(BMesh *bm,
|
||||
const float (*vcos)[3],
|
||||
const float (*vnos)[3],
|
||||
const float (*fnos)[3],
|
||||
blender::Span<blender::float3> vcos,
|
||||
blender::Span<blender::float3> vnos,
|
||||
blender::Span<blender::float3> fnos,
|
||||
bool use_split_normals,
|
||||
float (*r_lnos)[3],
|
||||
blender::MutableSpan<blender::float3> r_lnos,
|
||||
MLoopNorSpaceArray *r_lnors_spacearr,
|
||||
short (*clnors_data)[2],
|
||||
int cd_loop_clnors_offset,
|
||||
|
@ -70,7 +70,7 @@ void BM_loops_calc_normal_vcos(BMesh *bm,
|
|||
* and yet we need to walk them once, and only once.
|
||||
*/
|
||||
bool BM_loop_check_cyclic_smooth_fan(BMLoop *l_curr);
|
||||
void BM_lnorspacearr_store(BMesh *bm, float (*r_lnors)[3]);
|
||||
void BM_lnorspacearr_store(BMesh *bm, blender::MutableSpan<blender::float3> r_lnors);
|
||||
void BM_lnorspace_invalidate(BMesh *bm, bool do_invalidate_all);
|
||||
void BM_lnorspace_rebuild(BMesh *bm, bool preserve_clnor);
|
||||
/**
|
||||
|
|
|
@ -31,6 +31,9 @@
|
|||
|
||||
#include "intern/bmesh_private.hh"
|
||||
|
||||
using blender::float3;
|
||||
using blender::Span;
|
||||
|
||||
/**
|
||||
* \brief COMPUTE POLY NORMAL (BMFace)
|
||||
*
|
||||
|
@ -66,7 +69,7 @@ static float bm_face_calc_poly_normal(const BMFace *f, float n[3])
|
|||
*/
|
||||
static float bm_face_calc_poly_normal_vertex_cos(const BMFace *f,
|
||||
float r_no[3],
|
||||
float const (*vertexCos)[3])
|
||||
const Span<float3> vertexCos)
|
||||
{
|
||||
BMLoop *l_first = BM_FACE_FIRST_LOOP(f);
|
||||
BMLoop *l_iter = l_first;
|
||||
|
@ -742,7 +745,7 @@ void BM_face_normal_update(BMFace *f)
|
|||
float BM_face_calc_normal_vcos(const BMesh *bm,
|
||||
const BMFace *f,
|
||||
float r_no[3],
|
||||
float const (*vertexCos)[3])
|
||||
const Span<float3> vertexCos)
|
||||
{
|
||||
BMLoop *l;
|
||||
|
||||
|
|
|
@ -46,7 +46,7 @@ float BM_face_calc_normal(const BMFace *f, float r_no[3]) ATTR_NONNULL();
|
|||
float BM_face_calc_normal_vcos(const BMesh *bm,
|
||||
const BMFace *f,
|
||||
float r_no[3],
|
||||
float const (*vertexCos)[3]) ATTR_NONNULL();
|
||||
blender::Span<blender::float3> vertexCos) ATTR_NONNULL();
|
||||
|
||||
/**
|
||||
* Calculate a normal from a vertex cloud.
|
||||
|
|
|
@ -49,8 +49,8 @@ class ConversionOperation : public SimpleOperation {
|
|||
/* -------------------------------------------------------------------- */
|
||||
/** \name Convert Float to Vector Operation
|
||||
*
|
||||
* Takes a float result and outputs a vector result. All three components of the output are filled
|
||||
* with the input float.
|
||||
* Takes a float result and outputs a vector result. The first three components of the output are
|
||||
* filled with the input float, while the fourth component is set to 1.
|
||||
* \{ */
|
||||
|
||||
class ConvertFloatToVectorOperation : public ConversionOperation {
|
||||
|
@ -103,8 +103,8 @@ class ConvertColorToFloatOperation : public ConversionOperation {
|
|||
/* -------------------------------------------------------------------- */
|
||||
/** \name Convert Color to Vector Operation
|
||||
*
|
||||
* Takes a color result and outputs a vector result. The output is a copy of the three color
|
||||
* channels to the three vector components.
|
||||
* Takes a color result and outputs a vector result. The output is an exact copy of the input since
|
||||
* vectors are 4D.
|
||||
* \{ */
|
||||
|
||||
class ConvertColorToVectorOperation : public ConversionOperation {
|
||||
|
|
|
@ -49,7 +49,10 @@ class FileOutput {
|
|||
public:
|
||||
/* Allocate and initialize the internal render result of the file output using the give
|
||||
* parameters. See the implementation for more information. */
|
||||
FileOutput(std::string path, ImageFormatData format, int2 size, bool save_as_render);
|
||||
FileOutput(const std::string &path,
|
||||
const ImageFormatData &format,
|
||||
int2 size,
|
||||
bool save_as_render);
|
||||
|
||||
/* Free the internal render result. */
|
||||
~FileOutput();
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue