Initial Grease Pencil 3.0 stage #106848

Merged
Falk David merged 224 commits from filedescriptor/blender:grease-pencil-v3 into main 2023-05-30 11:14:22 +02:00
241 changed files with 7428 additions and 6461 deletions
Showing only changes of commit 847c3f3b92 - Show all commits

View File

@ -104,9 +104,9 @@
* merged in docs.
*/
/**
* \defgroup gui GUI
* \ingroup blender */
/** \defgroup gui GUI
* \ingroup blender
*/
/** \defgroup wm Window Manager
* \ingroup gui */

View File

@ -5,7 +5,7 @@
This script generates the blender.1 man page, embedding the help text
from the Blender executable itself. Invoke it as follows:
blender.1.py --blender <path-to-blender> --output <output-filename>
./blender.bin -b --python doc/manpage/blender.1.py -- --output <output-filename>
where <path-to-blender> is the path to the Blender executable,
and <output-filename> is where to write the generated man page.
@ -13,8 +13,8 @@ and <output-filename> is where to write the generated man page.
import argparse
import os
import subprocess
import time
import sys
from typing import (
Dict,
@ -28,61 +28,28 @@ def man_format(data: str) -> str:
return data
def blender_extract_info(blender_bin: str) -> Dict[str, str]:
def blender_extract_info() -> Dict[str, str]:
# Only use of `bpy` in this file.
import bpy # type: ignore
blender_help_text = bpy.app.help_text()
blender_version_text = bpy.app.version_string
blender_build_date_text = bpy.app.build_date
blender_env = {
"ASAN_OPTIONS": (
os.environ.get("ASAN_OPTIONS", "") +
":exitcode=0:check_initialization_order=0:strict_init_order=0"
).lstrip(":"),
}
blender_help = subprocess.run(
[blender_bin, "--help"],
env=blender_env,
check=True,
stdout=subprocess.PIPE,
).stdout.decode(encoding="utf-8")
blender_version_output = subprocess.run(
[blender_bin, "--version"],
env=blender_env,
check=True,
stdout=subprocess.PIPE,
).stdout.decode(encoding="utf-8")
# Extract information from the version string.
# Note that some internal modules may print errors (e.g. color management),
# check for each lines prefix to ensure these aren't included.
blender_version = ""
blender_date = ""
for l in blender_version_output.split("\n"):
if l.startswith("Blender "):
# Remove 'Blender' prefix.
blender_version = l.split(" ", 1)[1].strip()
elif l.lstrip().startswith("build date:"):
# Remove 'build date:' prefix.
blender_date = l.split(":", 1)[1].strip()
if blender_version and blender_date:
break
if not blender_date:
if blender_build_date_text == b'Unknown':
# Happens when built without WITH_BUILD_INFO e.g.
date_string = time.strftime("%B %d, %Y", time.gmtime(int(os.environ.get('SOURCE_DATE_EPOCH', time.time()))))
blender_date = time.strftime("%B %d, %Y", time.gmtime(int(os.environ.get('SOURCE_DATE_EPOCH', time.time()))))
else:
date_string = time.strftime("%B %d, %Y", time.strptime(blender_date, "%Y-%m-%d"))
blender_date = time.strftime("%B %d, %Y", time.strptime(blender_build_date_text, "%Y-%m-%d"))
return {
"help": blender_help,
"version": blender_version,
"date": date_string,
"help": blender_help_text,
"version": blender_version_text,
"date": blender_date,
}
def man_page_from_blender_help(fh: TextIO, blender_bin: str, verbose: bool) -> None:
if verbose:
print("Extracting help text:", blender_bin)
blender_info = blender_extract_info(blender_bin)
def man_page_from_blender_help(fh: TextIO, verbose: bool) -> None:
blender_info = blender_extract_info()
# Header Content.
fh.write(
@ -175,11 +142,6 @@ def create_argparse() -> argparse.ArgumentParser:
required=True,
help="The man page to write to."
)
parser.add_argument(
"--blender",
required=True,
help="Path to the blender binary."
)
parser.add_argument(
"--verbose",
default=False,
@ -192,15 +154,15 @@ def create_argparse() -> argparse.ArgumentParser:
def main() -> None:
argv = sys.argv[sys.argv.index("--") + 1:]
parser = create_argparse()
args = parser.parse_args()
args = parser.parse_args(argv)
blender_bin = args.blender
output_filename = args.output
verbose = args.verbose
with open(output_filename, "w", encoding="utf-8") as fh:
man_page_from_blender_help(fh, blender_bin, verbose)
man_page_from_blender_help(fh, verbose)
if verbose:
print("Written:", output_filename)

View File

@ -0,0 +1,10 @@
"""
Get the property associated with a hovered button.
Returns a tuple of the datablock, data path to the property, and array index.
"""
# Example inserting keyframe for the hovered property.
active_property = bpy.context.property
if active_property:
datablock, data_path, index = active_property
datablock.keyframe_insert(data_path=data_path, index=index, frame=1)

View File

@ -1202,6 +1202,7 @@ context_type_map = {
"particle_settings": ("ParticleSettings", False),
"particle_system": ("ParticleSystem", False),
"particle_system_editable": ("ParticleSystem", False),
"property": ("(:class:`bpy.types.ID`, :class:`string`, :class:`int`)", False),
"pointcloud": ("PointCloud", False),
"pose_bone": ("PoseBone", False),
"pose_object": ("Object", False),
@ -1347,7 +1348,11 @@ def pycontext2sphinx(basepath):
raise SystemExit(
"Error: context key %r not found in context_type_map; update %s" %
(member, __file__)) from None
fw(" :type: %s :class:`bpy.types.%s`\n\n" % ("sequence of " if is_seq else "", member_type))
if member_type.isidentifier():
member_type = ":class:`bpy.types.%s`" % member_type
fw(" :type: %s %s\n\n" % ("sequence of " if is_seq else "", member_type))
write_example_ref(" ", fw, "bpy.context." + member)
# Generate type-map:
# for member in sorted(unique_context_strings):

View File

@ -3,6 +3,7 @@
# Libs that adhere to strict flags
add_subdirectory(curve_fit_nd)
add_subdirectory(fmtlib)
# Otherwise we get warnings here that we cant fix in external projects
remove_strict_flags()

View File

@ -1,7 +1,7 @@
Project: fast_float
URL: https://github.com/fastfloat/fast_float
License: MIT
Upstream version: 4.0.0 (fbd5bd7, 2023 Mar 31)
Upstream version: 5.0.0 (f5a3e77, 2023 May 25)
Local modifications:
- Took only the fast_float.h header and the license/readme files

View File

@ -1,4 +1,8 @@
## fast_float number parsing library: 4x faster than strtod
[![Fuzzing Status](https://oss-fuzz-build-logs.storage.googleapis.com/badges/fast_float.svg)](https://bugs.chromium.org/p/oss-fuzz/issues/list?sort=-opened&can=1&q=proj:fast_float)
[![VS17-CI](https://github.com/fastfloat/fast_float/actions/workflows/vs17-ci.yml/badge.svg)](https://github.com/fastfloat/fast_float/actions/workflows/vs17-ci.yml)
[![Ubuntu 22.04 CI (GCC 11)](https://github.com/fastfloat/fast_float/actions/workflows/ubuntu22.yml/badge.svg)](https://github.com/fastfloat/fast_float/actions/workflows/ubuntu22.yml)
The fast_float library provides fast header-only implementations for the C++ from_chars
functions for `float` and `double` types. These functions convert ASCII strings representing
@ -93,6 +97,24 @@ constexpr double constexptest() {
}
```
## Non-ASCII Inputs
We also support UTF-16 and UTF-32 inputs, as well as ASCII/UTF-8, as in the following example:
``` C++
#include "fast_float/fast_float.h"
#include <iostream>
int main() {
const std::u16string input = u"3.1416 xyz ";
double result;
auto answer = fast_float::from_chars(input.data(), input.data()+input.size(), result);
if(answer.ec != std::errc()) { std::cerr << "parsing failure\n"; return EXIT_FAILURE; }
std::cout << "parsed the number " << result << std::endl;
return EXIT_SUCCESS;
}
```
## Using commas as decimal separator
@ -189,11 +211,11 @@ It can parse random floating-point numbers at a speed of 1 GB/s on some systems.
$ ./build/benchmarks/benchmark
# parsing random integers in the range [0,1)
volume = 2.09808 MB
netlib : 271.18 MB/s (+/- 1.2 %) 12.93 Mfloat/s
doubleconversion : 225.35 MB/s (+/- 1.2 %) 10.74 Mfloat/s
strtod : 190.94 MB/s (+/- 1.6 %) 9.10 Mfloat/s
abseil : 430.45 MB/s (+/- 2.2 %) 20.52 Mfloat/s
fastfloat : 1042.38 MB/s (+/- 9.9 %) 49.68 Mfloat/s
netlib : 271.18 MB/s (+/- 1.2 %) 12.93 Mfloat/s
doubleconversion : 225.35 MB/s (+/- 1.2 %) 10.74 Mfloat/s
strtod : 190.94 MB/s (+/- 1.6 %) 9.10 Mfloat/s
abseil : 430.45 MB/s (+/- 2.2 %) 20.52 Mfloat/s
fastfloat : 1042.38 MB/s (+/- 9.9 %) 49.68 Mfloat/s
```
See https://github.com/lemire/simple_fastfloat_benchmark for our benchmarking code.
@ -257,7 +279,7 @@ under the Apache 2.0 license.
<sup>
Licensed under either of <a href="LICENSE-APACHE">Apache License, Version
2.0</a> or <a href="LICENSE-MIT">MIT license</a> at your option.
2.0</a> or <a href="LICENSE-MIT">MIT license</a> or <a href="LICENSE-BOOST">BOOST license</a> .
</sup>
<br>
@ -265,5 +287,5 @@ Licensed under either of <a href="LICENSE-APACHE">Apache License, Version
<sub>
Unless you explicitly state otherwise, any contribution intentionally submitted
for inclusion in this repository by you, as defined in the Apache-2.0 license,
shall be dual licensed as above, without any additional terms or conditions.
shall be triple licensed as above, without any additional terms or conditions.
</sub>

File diff suppressed because it is too large Load Diff

20
extern/fmtlib/CMakeLists.txt vendored Normal file
View File

@ -0,0 +1,20 @@
# SPDX-License-Identifier: GPL-2.0-or-later
set(INC
include
)
set(INC_SYS
)
set(SRC
include/fmt/core.h
include/fmt/format-inl.h
include/fmt/format.h
src/format.cc
)
set(LIB
)
blender_add_lib(extern_fmtlib "${SRC}" "${INC}" "${INC_SYS}" "${LIB}")

View File

@ -1,4 +1,4 @@
Copyright (c) 2012 - present, Victor Zverovich
Copyright (c) 2012 - present, Victor Zverovich and {fmt} contributors
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the

View File

@ -1,8 +1,12 @@
Project: {fmt}
URL: https://github.com/fmtlib/fmt
License: MIT
Upstream version: 8.1.1 (b6f4cea)
Upstream version: 10.0.0 (a0b8a92, 2023 May 10)
Local modifications:
- Took only files needed for Blender: LICENSE, README and include/fmt
folder's core.h, format-inl.h, format.h
- Took only files needed for Blender:
- LICENSE, README
- include/fmt: core.h, format-inl.h, format.h
- src/format.cc
- CMakeLists.txt is not from fmtlib, but
made for Blender codebase

View File

@ -1,5 +1,7 @@
{fmt}
=====
.. image:: https://user-images.githubusercontent.com/
576385/156254208-f5b743a9-88cf-439d-b0c0-923d53e8d551.png
:width: 25%
:alt: {fmt}
.. image:: https://github.com/fmtlib/fmt/workflows/linux/badge.svg
:target: https://github.com/fmtlib/fmt/actions?query=workflow%3Alinux
@ -10,9 +12,6 @@
.. image:: https://github.com/fmtlib/fmt/workflows/windows/badge.svg
:target: https://github.com/fmtlib/fmt/actions?query=workflow%3Awindows
.. image:: https://ci.appveyor.com/api/projects/status/ehjkiefde6gucy1v?svg=true
:target: https://ci.appveyor.com/project/vitaut/fmt
.. image:: https://oss-fuzz-build-logs.storage.googleapis.com/badges/fmt.svg
:alt: fmt is continuously fuzzed at oss-fuzz
:target: https://bugs.chromium.org/p/oss-fuzz/issues/list?\
@ -26,12 +25,13 @@
**{fmt}** is an open-source formatting library providing a fast and safe
alternative to C stdio and C++ iostreams.
If you like this project, please consider donating to the BYSOL
Foundation that helps victims of political repressions in Belarus:
https://bysol.org/en/bs/general/.
If you like this project, please consider donating to one of the funds that
help victims of the war in Ukraine: https://www.stopputin.net/.
`Documentation <https://fmt.dev>`__
`Cheat Sheets <https://hackingcpp.com/cpp/libs/fmt.html>`__
Q&A: ask questions on `StackOverflow with the tag fmt
<https://stackoverflow.com/questions/tagged/fmt>`_.
@ -47,7 +47,8 @@ Features
* `Format string syntax <https://fmt.dev/latest/syntax.html>`_ similar to Python's
`format <https://docs.python.org/3/library/stdtypes.html#str.format>`_
* Fast IEEE 754 floating-point formatter with correct rounding, shortness and
round-trip guarantees
round-trip guarantees using the `Dragonbox <https://github.com/jk-jeon/dragonbox>`_
algorithm
* Safe `printf implementation
<https://fmt.dev/latest/api.html#printf-formatting>`_ including the POSIX
extension for positional arguments
@ -123,7 +124,7 @@ Output::
Default format: 42s 100ms
strftime-like format: 03:15:30
**Print a container** (`run <https://godbolt.org/z/MjsY7c>`_)
**Print a container** (`run <https://godbolt.org/z/MxM1YqjE7>`_)
.. code:: c++
@ -191,24 +192,24 @@ Speed tests
================= ============= ===========
Library Method Run Time, s
================= ============= ===========
libc printf 1.04
libc++ std::ostream 3.05
{fmt} 6.1.1 fmt::print 0.75
Boost Format 1.67 boost::format 7.24
Folly Format folly::format 2.23
libc printf 0.91
libc++ std::ostream 2.49
{fmt} 9.1 fmt::print 0.74
Boost Format 1.80 boost::format 6.26
Folly Format folly::format 1.87
================= ============= ===========
{fmt} is the fastest of the benchmarked methods, ~35% faster than ``printf``.
{fmt} is the fastest of the benchmarked methods, ~20% faster than ``printf``.
The above results were generated by building ``tinyformat_test.cpp`` on macOS
10.14.6 with ``clang++ -O3 -DNDEBUG -DSPEED_TEST -DHAVE_FORMAT``, and taking the
12.6.1 with ``clang++ -O3 -DNDEBUG -DSPEED_TEST -DHAVE_FORMAT``, and taking the
best of three runs. In the test, the format string ``"%0.10f:%04d:%+g:%s:%p:%c:%%\n"``
or equivalent is filled 2,000,000 times with output sent to ``/dev/null``; for
further details refer to the `source
<https://github.com/fmtlib/format-benchmark/blob/master/src/tinyformat-test.cc>`_.
{fmt} is up to 20-30x faster than ``std::ostringstream`` and ``sprintf`` on
floating-point formatting (`dtoa-benchmark <https://github.com/fmtlib/dtoa-benchmark>`_)
IEEE754 ``float`` and ``double`` formatting (`dtoa-benchmark <https://github.com/fmtlib/dtoa-benchmark>`_)
and faster than `double-conversion <https://github.com/google/double-conversion>`_ and
`ryu <https://github.com/ulfjack/ryu>`_:
@ -322,8 +323,10 @@ Projects using this library
* `ccache <https://ccache.dev/>`_: a compiler cache
* `ClickHouse <https://github.com/ClickHouse/ClickHouse>`_: analytical database
* `ClickHouse <https://github.com/ClickHouse/ClickHouse>`_: an analytical database
management system
* `Contour <https://github.com/contour-terminal/contour/>`_: a modern terminal emulator
* `CUAUV <https://cuauv.org/>`_: Cornell University's autonomous underwater
vehicle
@ -341,9 +344,12 @@ Projects using this library
* `Folly <https://github.com/facebook/folly>`_: Facebook open-source library
* `GemRB <https://gemrb.org/>`_: a portable open-source implementation of
Biowares Infinity Engine
* `Grand Mountain Adventure
<https://store.steampowered.com/app/1247360/Grand_Mountain_Adventure/>`_:
A beautiful open-world ski & snowboarding game
a beautiful open-world ski & snowboarding game
* `HarpyWar/pvpgn <https://github.com/pvpgn/pvpgn-server>`_:
Player vs Player Gaming Network with tweaks
@ -357,6 +363,10 @@ Projects using this library
* `Knuth <https://kth.cash/>`_: high-performance Bitcoin full-node
* `libunicode <https://github.com/contour-terminal/libunicode/>`_: a modern C++17 Unicode library
* `MariaDB <https://mariadb.org/>`_: relational database management system
* `Microsoft Verona <https://github.com/microsoft/verona>`_:
research programming language for concurrent ownership
@ -410,6 +420,9 @@ Projects using this library
* `TrinityCore <https://github.com/TrinityCore/TrinityCore>`_: open-source
MMORPG framework
* `🐙 userver framework <https://userver.tech/>`_: open-source asynchronous
framework with a rich set of abstractions and database drivers
* `Windows Terminal <https://github.com/microsoft/terminal>`_: the new Windows
terminal
@ -520,8 +533,7 @@ Maintainers
-----------
The {fmt} library is maintained by Victor Zverovich (`vitaut
<https://github.com/vitaut>`_) and Jonathan Müller (`foonathan
<https://github.com/foonathan>`_) with contributions from many other people.
<https://github.com/vitaut>`_) with contributions from many other people.
See `Contributors <https://github.com/fmtlib/fmt/graphs/contributors>`_ and
`Releases <https://github.com/fmtlib/fmt/releases>`_ for some of the names.
Let us know if your contribution is not listed or mentioned incorrectly and

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

43
extern/fmtlib/src/format.cc vendored Normal file
View File

@ -0,0 +1,43 @@
// Formatting library for C++
//
// Copyright (c) 2012 - 2016, Victor Zverovich
// All rights reserved.
//
// For the license information refer to format.h.
#include "fmt/format-inl.h"
FMT_BEGIN_NAMESPACE
namespace detail {
template FMT_API auto dragonbox::to_decimal(float x) noexcept
-> dragonbox::decimal_fp<float>;
template FMT_API auto dragonbox::to_decimal(double x) noexcept
-> dragonbox::decimal_fp<double>;
#ifndef FMT_STATIC_THOUSANDS_SEPARATOR
template FMT_API locale_ref::locale_ref(const std::locale& loc);
template FMT_API auto locale_ref::get<std::locale>() const -> std::locale;
#endif
// Explicit instantiations for char.
template FMT_API auto thousands_sep_impl(locale_ref)
-> thousands_sep_result<char>;
template FMT_API auto decimal_point_impl(locale_ref) -> char;
template FMT_API void buffer<char>::append(const char*, const char*);
template FMT_API void vformat_to(buffer<char>&, string_view,
typename vformat_args<>::type, locale_ref);
// Explicit instantiations for wchar_t.
template FMT_API auto thousands_sep_impl(locale_ref)
-> thousands_sep_result<wchar_t>;
template FMT_API auto decimal_point_impl(locale_ref) -> wchar_t;
template FMT_API void buffer<wchar_t>::append(const wchar_t*, const wchar_t*);
} // namespace detail
FMT_END_NAMESPACE

View File

@ -655,7 +655,7 @@ ccl_device_inline Spectrum bsdf_albedo(ccl_private const ShaderData *sd,
* extra overhead though. */
#if defined(__SVM__) || defined(__OSL__)
if (CLOSURE_IS_BSDF_MICROFACET(sc->type)) {
albedo *= microfacet_fresnel((ccl_private const MicrofacetBsdf *)sc, sd->wi, sc->N, false);
albedo *= bsdf_microfacet_estimate_fresnel(sd, (ccl_private const MicrofacetBsdf *)sc);
}
else if (sc->type == CLOSURE_BSDF_PRINCIPLED_SHEEN_ID) {
albedo *= ((ccl_private const PrincipledSheenBsdf *)sc)->avg_value;

View File

@ -262,19 +262,39 @@ ccl_device_forceinline Spectrum microfacet_fresnel(ccl_private const MicrofacetB
}
}
else if (bsdf->fresnel_type == MicrofacetFresnel::CONSTANT) {
kernel_assert(!refraction);
ccl_private FresnelConstant *fresnel = (ccl_private FresnelConstant *)bsdf->fresnel;
return fresnel->color;
/* CONSTANT is only used my MultiGGX, which doesn't call this function.
* Therefore, this case only happens when determining the albedo of a MultiGGX closure.
* In that case, return 1.0 since the constant color is already baked into the weight. */
return one_spectrum();
}
else {
return one_spectrum();
}
}
ccl_device_forceinline void bsdf_microfacet_adjust_weight(ccl_private const ShaderData *sd,
ccl_private MicrofacetBsdf *bsdf)
/* This function estimates the albedo of the BSDF (NOT including the bsdf->weight) as caused by
* the applied Fresnel model for the given view direction.
* The base microfacet model is assumed to have an albedo of 1, but e.g. a reflection-only
* closure with Fresnel applied can end up having a very low overall albedo.
* This is used to adjust the sample weight, as well as for the Diff/Gloss/Trans Color pass
* and the Denoising Albedo pass. */
ccl_device Spectrum bsdf_microfacet_estimate_fresnel(ccl_private const ShaderData *sd,
ccl_private const MicrofacetBsdf *bsdf)
{
bsdf->sample_weight *= average(microfacet_fresnel(bsdf, sd->wi, bsdf->N, false));
const bool is_glass = CLOSURE_IS_GLASS(bsdf->type);
const bool is_refractive = CLOSURE_IS_REFRACTIVE(bsdf->type);
Spectrum albedo = zero_spectrum();
if (!is_refractive || is_glass) {
/* BSDF has a reflective lobe. */
albedo += microfacet_fresnel(bsdf, sd->wi, bsdf->N, false);
}
if (is_refractive) {
/* BSDF has a refractive lobe (unless there's TIR). */
albedo += microfacet_fresnel(bsdf, sd->wi, bsdf->N, true);
}
return albedo;
}
/* Generalized Trowbridge-Reitz for clearcoat. */
@ -647,7 +667,7 @@ ccl_device void bsdf_microfacet_setup_fresnel_principledv1(
bsdf->fresnel_type = MicrofacetFresnel::PRINCIPLED_V1;
bsdf->fresnel = fresnel;
bsdf_microfacet_adjust_weight(sd, bsdf);
bsdf->sample_weight *= average(bsdf_microfacet_estimate_fresnel(sd, bsdf));
}
ccl_device void bsdf_microfacet_setup_fresnel_conductor(ccl_private MicrofacetBsdf *bsdf,
@ -656,7 +676,7 @@ ccl_device void bsdf_microfacet_setup_fresnel_conductor(ccl_private MicrofacetBs
{
bsdf->fresnel_type = MicrofacetFresnel::CONDUCTOR;
bsdf->fresnel = fresnel;
bsdf_microfacet_adjust_weight(sd, bsdf);
bsdf->sample_weight *= average(bsdf_microfacet_estimate_fresnel(sd, bsdf));
}
ccl_device void bsdf_microfacet_setup_fresnel_dielectric_tint(
@ -666,7 +686,7 @@ ccl_device void bsdf_microfacet_setup_fresnel_dielectric_tint(
{
bsdf->fresnel_type = MicrofacetFresnel::DIELECTRIC_TINT;
bsdf->fresnel = fresnel;
bsdf_microfacet_adjust_weight(sd, bsdf);
bsdf->sample_weight *= average(bsdf_microfacet_estimate_fresnel(sd, bsdf));
}
ccl_device void bsdf_microfacet_setup_fresnel_generalized_schlick(
@ -676,7 +696,7 @@ ccl_device void bsdf_microfacet_setup_fresnel_generalized_schlick(
{
bsdf->fresnel_type = MicrofacetFresnel::GENERALIZED_SCHLICK;
bsdf->fresnel = fresnel;
bsdf_microfacet_adjust_weight(sd, bsdf);
bsdf->sample_weight *= average(bsdf_microfacet_estimate_fresnel(sd, bsdf));
}
/* GGX microfacet with Smith shadow-masking from:
@ -711,8 +731,7 @@ ccl_device int bsdf_microfacet_ggx_clearcoat_setup(ccl_private MicrofacetBsdf *b
bsdf->fresnel_type = MicrofacetFresnel::DIELECTRIC;
bsdf->type = CLOSURE_BSDF_MICROFACET_GGX_CLEARCOAT_ID;
bsdf_microfacet_adjust_weight(sd, bsdf);
bsdf->sample_weight *= average(bsdf_microfacet_estimate_fresnel(sd, bsdf));
return SD_BSDF | SD_BSDF_HAS_EVAL;
}

View File

@ -407,8 +407,7 @@ ccl_device int bsdf_microfacet_multi_ggx_fresnel_setup(ccl_private MicrofacetBsd
bsdf->fresnel_type = MicrofacetFresnel::PRINCIPLED_V1;
bsdf->type = CLOSURE_BSDF_MICROFACET_MULTI_GGX_ID;
bsdf_microfacet_adjust_weight(sd, bsdf);
bsdf->sample_weight *= average(bsdf_microfacet_estimate_fresnel(sd, bsdf));
return bsdf_microfacet_multi_ggx_common_setup(bsdf);
}
@ -619,8 +618,7 @@ ccl_device int bsdf_microfacet_multi_ggx_glass_fresnel_setup(ccl_private Microfa
bsdf->fresnel_type = MicrofacetFresnel::PRINCIPLED_V1;
bsdf->type = CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID;
bsdf_microfacet_adjust_weight(sd, bsdf);
bsdf->sample_weight *= average(bsdf_microfacet_estimate_fresnel(sd, bsdf));
return SD_BSDF | SD_BSDF_HAS_EVAL | SD_BSDF_NEEDS_LCG;
}

View File

@ -36,7 +36,7 @@ KERNEL_STRUCT_MEMBER(background, int, map_res_x)
KERNEL_STRUCT_MEMBER(background, int, map_res_y)
/* Multiple importance sampling. */
KERNEL_STRUCT_MEMBER(background, int, use_mis)
/* Lightgroup. */
/* Light-group. */
KERNEL_STRUCT_MEMBER(background, int, lightgroup)
/* Light Index. */
KERNEL_STRUCT_MEMBER(background, int, light_index)

View File

@ -288,7 +288,7 @@ ccl_device_inline float object_pass_id(KernelGlobals kg, int object)
return kernel_data_fetch(objects, object).pass_id;
}
/* Lightgroup of lamp */
/* Light-group of lamp. */
ccl_device_inline int lamp_lightgroup(KernelGlobals kg, int lamp)
{
@ -298,7 +298,7 @@ ccl_device_inline int lamp_lightgroup(KernelGlobals kg, int lamp)
return kernel_data_fetch(lights, lamp).lightgroup;
}
/* Lightgroup of object */
/* Light-group of object. */
ccl_device_inline int object_lightgroup(KernelGlobals kg, int object)
{

View File

@ -61,7 +61,7 @@ ccl_device int shadow_linking_pick_mesh_intersection(KernelGlobals kg,
if (set_membership != LIGHT_LINK_MASK_ALL) {
++num_hits;
if ((linked_isect->prim == PRIM_NONE) && (lcg_step_float(lcg_state) < 1.0f / num_hits)) {
if ((linked_isect->prim == PRIM_NONE) || (lcg_step_float(lcg_state) < 1.0f / num_hits)) {
*linked_isect = current_isect;
}
}

View File

@ -221,7 +221,7 @@ integrate_direct_light_shadow_init_common(KernelGlobals kg,
state, path, bounce);
}
/* Write Lightgroup, +1 as lightgroup is int but we need to encode into a uint8_t. */
/* Write Light-group, +1 as light-group is int but we need to encode into a uint8_t. */
INTEGRATOR_STATE_WRITE(shadow_state, shadow_path, lightgroup) = light_group;
#ifdef __PATH_GUIDING__

View File

@ -879,7 +879,7 @@ ccl_device_forceinline void integrate_volume_direct_light(
state, path, transmission_bounce);
INTEGRATOR_STATE_WRITE(shadow_state, shadow_path, throughput) = throughput_phase;
/* Write Lightgroup, +1 as lightgroup is int but we need to encode into a uint8_t. */
/* Write Light-group, +1 as light-group is int but we need to encode into a uint8_t. */
INTEGRATOR_STATE_WRITE(
shadow_state, shadow_path, lightgroup) = (ls.type != LIGHT_BACKGROUND) ?
ls.group + 1 :

View File

@ -498,17 +498,30 @@ ccl_device void light_tree_child_importance(KernelGlobals kg,
}
}
ccl_device void sample_resevoir(const int current_index,
const float current_weight,
ccl_private int &selected_index,
ccl_private float &selected_weight,
ccl_private float &total_weight,
ccl_private float &rand)
ccl_device void sample_reservoir(const int current_index,
const float current_weight,
ccl_private int &selected_index,
ccl_private float &selected_weight,
ccl_private float &total_weight,
ccl_private float &rand)
{
if (current_weight == 0.0f) {
return;
}
total_weight += current_weight;
/* When `-ffast-math` is used it is possible that the threshold is almost 1 but not quite.
* For this case we check the first assignment explicitly (instead of relying on the threshold to
* be 1, giving it certain probability). */
if (selected_index == -1) {
selected_index = current_index;
selected_weight = current_weight;
/* The threshold is expected to be 1 in this case with strict mathematics, so no need to divide
* the rand. In fact, division in such case could lead the rand to exceed 1 because of division
* by something smaller than 1. */
return;
}
float thresh = current_weight / total_weight;
if (rand <= thresh) {
selected_index = current_index;
@ -518,11 +531,13 @@ ccl_device void sample_resevoir(const int current_index,
else {
rand = (rand - thresh) / (1.0f - thresh);
}
kernel_assert(rand >= 0.0f && rand <= 1.0f);
return;
/* Ensure the `rand` is always within 0..1 range, which could be violated above when
* `-ffast-math` is used. */
rand = saturatef(rand);
}
/* Pick an emitter from a leaf node using resevoir sampling, keep two reservoirs for upper and
/* Pick an emitter from a leaf node using reservoir sampling, keep two reservoirs for upper and
* lower bounds. */
template<bool in_volume_segment>
ccl_device int light_tree_cluster_select_emitter(KernelGlobals kg,
@ -540,7 +555,7 @@ ccl_device int light_tree_cluster_select_emitter(KernelGlobals kg,
const ccl_global KernelLightTreeNode *knode = &kernel_data_fetch(light_tree_nodes, *node_index);
*node_index = -1;
/* Mark emitters with zero importance. Used for resevoir when total minimum importance = 0. */
/* Mark emitters with zero importance. Used for reservoir when total minimum importance = 0. */
kernel_assert(knode->num_emitters <= sizeof(uint) * 8);
uint has_importance = 0;
@ -556,12 +571,12 @@ ccl_device int light_tree_cluster_select_emitter(KernelGlobals kg,
light_tree_emitter_importance<in_volume_segment>(
kg, P, N_or_D, t, has_transmission, current_index, importance[0], importance[1]);
sample_resevoir(current_index,
importance[!sample_max],
selected_index,
selected_importance[!sample_max],
total_importance[!sample_max],
rand);
sample_reservoir(current_index,
importance[!sample_max],
selected_index,
selected_importance[!sample_max],
total_importance[!sample_max],
rand);
if (selected_index == current_index) {
selected_importance[sample_max] = importance[sample_max];
}
@ -584,12 +599,12 @@ ccl_device int light_tree_cluster_select_emitter(KernelGlobals kg,
selected_index = -1;
for (int i = 0; i < knode->num_emitters; i++) {
int current_index = knode->leaf.first_emitter + i;
sample_resevoir(current_index,
float(has_importance & 1),
selected_index,
selected_importance[1],
total_importance[1],
rand);
sample_reservoir(current_index,
float(has_importance & 1),
selected_index,
selected_importance[1],
total_importance[1],
rand);
has_importance >>= 1;
}
@ -730,7 +745,7 @@ ccl_device_noinline bool light_tree_sample(KernelGlobals kg,
float discard;
float total_prob = left_prob;
node_index = left_index;
sample_resevoir(
sample_reservoir(
right_index, 1.0f - left_prob, node_index, discard, total_prob, rand_selection);
pdf_leaf *= (node_index == left_index) ? left_prob : (1.0f - left_prob);
}

View File

@ -1171,9 +1171,10 @@ class Octree {
return nleaf;
}
/** Locate a leaf
* WARNING: assuming this leaf already exists! */
/**
* Locate a leaf
* WARNING: assuming this leaf already exists!
*/
LeafNode *locateLeaf(int st[3])
{
Node *node = (Node *)root;

View File

@ -138,7 +138,6 @@ class GHOST_ContextCGL : public GHOST_Context {
bool m_useMetalForRendering = false;
NSView *m_metalView;
CAMetalLayer *m_metalLayer;
MTLCommandQueue *m_metalCmdQueue;
MTLRenderPipelineState *m_metalRenderPipeline;
bool m_ownsMetalDevice;
@ -182,6 +181,9 @@ class GHOST_ContextCGL : public GHOST_Context {
static NSOpenGLContext *s_sharedOpenGLContext;
static int s_sharedCount;
/* Single device queue for multiple contexts. */
static MTLCommandQueue *s_sharedMetalCommandQueue;
/* Metal functions */
void metalInit();
void metalFree();

View File

@ -43,6 +43,7 @@ static void ghost_fatal_error_dialog(const char *msg)
}
NSOpenGLContext *GHOST_ContextCGL::s_sharedOpenGLContext = nil;
MTLCommandQueue *GHOST_ContextCGL::s_sharedMetalCommandQueue = nil;
int GHOST_ContextCGL::s_sharedCount = 0;
GHOST_ContextCGL::GHOST_ContextCGL(bool stereoVisual,
@ -54,7 +55,6 @@ GHOST_ContextCGL::GHOST_ContextCGL(bool stereoVisual,
m_useMetalForRendering(type == GHOST_kDrawingContextTypeMetal),
m_metalView(metalView),
m_metalLayer(metalLayer),
m_metalCmdQueue(nil),
m_metalRenderPipeline(nil),
m_openGLView(openGLView),
m_openGLContext(nil),
@ -318,7 +318,7 @@ id<MTLTexture> GHOST_ContextCGL::metalOverlayTexture()
MTLCommandQueue *GHOST_ContextCGL::metalCommandQueue()
{
return m_metalCmdQueue;
return s_sharedMetalCommandQueue;
}
MTLDevice *GHOST_ContextCGL::metalDevice()
{
@ -530,10 +530,14 @@ void GHOST_ContextCGL::metalInit()
/* clang-format on */
id<MTLDevice> device = m_metalLayer.device;
/* Create a command queue for blit/present operation. */
m_metalCmdQueue = (MTLCommandQueue *)[device
newCommandQueueWithMaxCommandBufferCount:GHOST_ContextCGL::max_command_buffer_count];
[m_metalCmdQueue retain];
/* Create a command queue for blit/present operation. Note: All context should share a single
* command queue to ensure correct ordering of work submitted from multiple contexts. */
if (s_sharedMetalCommandQueue == nil) {
s_sharedMetalCommandQueue = (MTLCommandQueue *)[device
newCommandQueueWithMaxCommandBufferCount:GHOST_ContextCGL::max_command_buffer_count];
}
/* Ensure active GHOSTContext retains a reference to the shared context. */
[s_sharedMetalCommandQueue retain];
/* Create shaders for blit operation. */
NSString *source = @R"msl(
@ -616,9 +620,6 @@ void GHOST_ContextCGL::metalInit()
void GHOST_ContextCGL::metalFree()
{
if (m_metalCmdQueue) {
[m_metalCmdQueue release];
}
if (m_metalRenderPipeline) {
[m_metalRenderPipeline release];
}
@ -789,7 +790,7 @@ void GHOST_ContextCGL::metalUpdateFramebuffer()
overlayTex; //[(MTLTexture *)overlayTex retain];
/* Clear texture on create */
id<MTLCommandBuffer> cmdBuffer = [m_metalCmdQueue commandBuffer];
id<MTLCommandBuffer> cmdBuffer = [s_sharedMetalCommandQueue commandBuffer];
MTLRenderPassDescriptor *passDescriptor = [MTLRenderPassDescriptor renderPassDescriptor];
{
auto attachment = [passDescriptor.colorAttachments objectAtIndexedSubscript:0];
@ -854,7 +855,7 @@ void GHOST_ContextCGL::metalSwapBuffers()
}
if (!m_useMetalForRendering) {
id<MTLCommandBuffer> cmdBuffer = [m_metalCmdQueue commandBuffer];
id<MTLCommandBuffer> cmdBuffer = [s_sharedMetalCommandQueue commandBuffer];
{
assert(m_defaultFramebufferMetalTexture[current_swapchain_index].texture != nil);
id<MTLRenderCommandEncoder> enc = [cmdBuffer
@ -896,7 +897,7 @@ void GHOST_ContextCGL::initClear()
#if WITH_METAL
// TODO (mg_gpusw_apple) this path is never taken, this is legacy left from inital integration
// of metal and gl, the whole file should be cleaned up and stripped of the legacy path
id<MTLCommandBuffer> cmdBuffer = [m_metalCmdQueue commandBuffer];
id<MTLCommandBuffer> cmdBuffer = [s_sharedMetalCommandQueue commandBuffer];
MTLRenderPassDescriptor *passDescriptor = [MTLRenderPassDescriptor renderPassDescriptor];
{
auto attachment = [passDescriptor.colorAttachments objectAtIndexedSubscript:0];

View File

@ -429,8 +429,7 @@ extern "C" int GHOST_HACK_getFirstFile(char buf[FIRSTFILEBUFLG])
- (void)applicationWillTerminate:(NSNotification *)aNotification
{
#if 0
G.is_break = false; /* Let Cocoa perform the termination at the end. */
WM_exit(C);
WM_exit(C, EXIT_SUCCESS);
#endif
}

View File

@ -143,6 +143,11 @@ GHOST_SystemWin32::GHOST_SystemWin32()
* blurry scaling and enables WM_DPICHANGED to allow us to draw at proper DPI. */
SetProcessDpiAwareness(PROCESS_PER_MONITOR_DPI_AWARE);
/* Set App Id for the process so our console will be grouped on the Task Bar. */
UTF16_ENCODE(BLENDER_WIN_APPID);
HRESULT result = SetCurrentProcessExplicitAppUserModelID(BLENDER_WIN_APPID_16);
UTF16_UN_ENCODE(BLENDER_WIN_APPID);
/* Check if current keyboard layout uses AltGr and save keylayout ID for
* specialized handling if keys like VK_OEM_*. I.e. french keylayout
* generates #VK_OEM_8 for their exclamation key (key left of right shift). */
@ -1867,9 +1872,10 @@ LRESULT WINAPI GHOST_SystemWin32::s_wndProc(HWND hwnd, uint msg, WPARAM wParam,
/* Mouse Tracking is now off. TrackMouseEvent restarts in MouseMove. */
window->m_mousePresent = false;
/* Auto-focus only occurs within Blender windows, not with _other_ applications. */
/* Auto-focus only occurs within Blender windows, not with _other_ applications. We are
* notified of change of focus from our console, but it returns null from GetFocus. */
HWND old_hwnd = ::GetFocus();
if (hwnd != old_hwnd) {
if (old_hwnd && hwnd != old_hwnd) {
HWND new_parent = ::GetParent(hwnd);
HWND old_parent = ::GetParent(old_hwnd);
if (hwnd == old_parent || old_hwnd == new_parent) {

View File

@ -36,8 +36,10 @@ class AssetStorage;
*/
class AssetLibrary {
eAssetLibraryType library_type_;
/** The name this asset library will be displayed in the UI as. Will also be used as a weak way
* to identify an asset library (e.g. by #AssetWeakReference). */
/**
* The name this asset library will be displayed in the UI as. Will also be used as a weak way
* to identify an asset library (e.g. by #AssetWeakReference).
*/
std::string name_;
/** If this is an asset library on disk, the top-level directory path. Normalized using
* #normalize_directory_path(). Shared pointer so assets can safely point to it, and don't have
@ -45,7 +47,8 @@ class AssetLibrary {
* optimization is used). With thousands of assets this might make a reasonable difference. */
std::shared_ptr<std::string> root_path_;
/** Storage for assets (better said their representations) that are considered to be part of this
/**
* Storage for assets (better said their representations) that are considered to be part of this
* library. Assets are not automatically loaded into this when loading an asset library. Assets
* have to be loaded externally and added to this storage via #add_external_asset() or
* #add_local_id_asset(). So this really is arbitrary storage as far as #AssetLibrary is
@ -122,13 +125,15 @@ class AssetLibrary {
std::unique_ptr<AssetMetaData> metadata);
/** See #AssetLibrary::add_external_asset(). */
AssetRepresentation &add_local_id_asset(StringRef relative_asset_path, ID &id);
/** Remove an asset from the library that was added using #add_external_asset() or
/**
* Remove an asset from the library that was added using #add_external_asset() or
* #add_local_id_asset(). Can usually be expected to be constant time complexity (worst case may
* differ).
* \note This is save to call if \a asset is freed (dangling reference), will not perform any
* change then.
* \return True on success, false if the asset couldn't be found inside the library (also the
* case when the reference is dangling). */
* case when the reference is dangling).
*/
bool remove_asset(AssetRepresentation &asset);
/**
@ -143,7 +148,8 @@ class AssetLibrary {
*
* No-op if the catalog cannot be found. This could be the kind of "the
* catalog definition file is corrupt/lost" scenario that the simple name is
* meant to help recover from. */
* meant to help recover from.
*/
void refresh_catalog_simplename(AssetMetaData *asset_data);
void on_blend_save_handler_register();

View File

@ -30,8 +30,10 @@ class AssetLibrary;
class AssetRepresentation {
AssetIdentifier identifier_;
/** Indicate if this is a local or external asset, and as such, which of the union members below
* should be used. */
/**
* Indicate if this is a local or external asset, and as such, which of the union members below
* should be used.
*/
const bool is_local_id_ = false;
/** Asset library that owns this asset representation. */
const AssetLibrary *owner_asset_library_;
@ -53,8 +55,10 @@ class AssetRepresentation {
StringRef name,
std::unique_ptr<AssetMetaData> metadata,
const AssetLibrary &owner_asset_library);
/** Constructs an asset representation for an ID stored in the current file. This makes the asset
* local and fully editable. */
/**
* Constructs an asset representation for an ID stored in the current file. This makes the asset
* local and fully editable.
*/
AssetRepresentation(AssetIdentifier &&identifier,
ID &id,
const AssetLibrary &owner_asset_library);
@ -71,7 +75,8 @@ class AssetRepresentation {
const AssetIdentifier &get_identifier() const;
/** Create a weak reference for this asset that can be written to files, but can break under a
/**
* Create a weak reference for this asset that can be written to files, but can break under a
* number of conditions.
* A weak reference can only be created if an asset representation is owned by an asset library.
*/
@ -79,18 +84,23 @@ class AssetRepresentation {
StringRefNull get_name() const;
AssetMetaData &get_metadata() const;
/** Get the import method to use for this asset. A different one may be used if
/**
* Get the import method to use for this asset. A different one may be used if
* #may_override_import_method() returns true, otherwise, the returned value must be used. If
* there is no import method predefined for this asset no value is returned.
*/
std::optional<eAssetImportMethod> get_import_method() const;
/** Returns if this asset may be imported with an import method other than the one returned by
/**
* Returns if this asset may be imported with an import method other than the one returned by
* #get_import_method(). Also returns true if there is no predefined import method
* (when #get_import_method() returns no value). */
* (when #get_import_method() returns no value).
*/
bool may_override_import_method() const;
bool get_use_relative_path() const;
/** If this asset is stored inside this current file (#is_local_id() is true), this returns the
* ID's pointer, otherwise null. */
/**
* If this asset is stored inside this current file (#is_local_id() is true), this returns the
* ID's pointer, otherwise null.
*/
ID *local_id() const;
/** Returns if this asset is stored inside this current file, and as such fully editable. */
bool is_local_id() const;
@ -103,9 +113,11 @@ class AssetRepresentation {
struct AssetRepresentation;
std::string AS_asset_representation_full_path_get(const ::AssetRepresentation *asset);
/** Get the absolute path to the .blend file containing the given asset. String will be empty if
/**
* Get the absolute path to the .blend file containing the given asset. String will be empty if
* the asset could not be mapped to a valid .blend file path. Valid in this case also means that
* the file needs to exist on disk. */
* the file needs to exist on disk.
*/
std::string AS_asset_representation_full_library_path_get(const ::AssetRepresentation *asset);
std::optional<eAssetImportMethod> AS_asset_representation_import_method_get(
const ::AssetRepresentation *asset_handle);

View File

@ -142,9 +142,9 @@ struct DerivedMesh {
DMFlagMat *(*getGridFlagMats)(DerivedMesh *dm);
unsigned int **(*getGridHidden)(DerivedMesh *dm);
/** Direct Access Operations
/* Direct Access Operations
* - Can be undefined
* - Must be defined for modifiers that only deform however */
* - Must be defined for modifiers that only deform however. */
/** Release reference to the DerivedMesh. This function decides internally
* if the DerivedMesh will be freed, or cached for later use. */

View File

@ -919,4 +919,17 @@ inline const AnonymousAttributeID &AttributeIDRef::anonymous_id() const
return *anonymous_id_;
}
void gather_attributes(AttributeAccessor src_attributes,
eAttrDomain domain,
const AnonymousAttributePropagationInfo &propagation_info,
const Set<std::string> &skip,
const IndexMask &selection,
MutableAttributeAccessor dst_attributes);
void copy_attributes(const AttributeAccessor src_attributes,
const eAttrDomain domain,
const AnonymousAttributePropagationInfo &propagation_info,
const Set<std::string> &skip,
MutableAttributeAccessor dst_attributes);
} // namespace blender::bke

View File

@ -93,7 +93,8 @@ typedef struct BPathForeachPathData {
/** ID owning the path being processed. */
struct ID *owner_id;
/** IDTypeInfo callbacks are responsible to set this boolean if they modified one or more paths.
/**
* IDTypeInfo callbacks are responsible to set this boolean if they modified one or more paths.
*/
bool is_path_modified;
} BPathForeachPathData;

View File

@ -244,6 +244,7 @@ void CTX_wm_operator_poll_msg_clear(struct bContext *C);
enum {
CTX_DATA_TYPE_POINTER = 0,
CTX_DATA_TYPE_COLLECTION,
CTX_DATA_TYPE_PROPERTY,
};
PointerRNA CTX_data_pointer_get(const bContext *C, const char *member);
@ -260,8 +261,13 @@ ListBase CTX_data_collection_get(const bContext *C, const char *member);
*/
ListBase CTX_data_dir_get_ex(const bContext *C, bool use_store, bool use_rna, bool use_all);
ListBase CTX_data_dir_get(const bContext *C);
int /*eContextResult*/ CTX_data_get(
const bContext *C, const char *member, PointerRNA *r_ptr, ListBase *r_lb, short *r_type);
int /*eContextResult*/ CTX_data_get(const bContext *C,
const char *member,
PointerRNA *r_ptr,
ListBase *r_lb,
PropertyRNA **r_prop,
int *r_index,
short *r_type);
void CTX_data_id_pointer_set(bContextDataResult *result, struct ID *id);
void CTX_data_pointer_set_ptr(bContextDataResult *result, const PointerRNA *ptr);
@ -271,6 +277,15 @@ void CTX_data_id_list_add(bContextDataResult *result, struct ID *id);
void CTX_data_list_add_ptr(bContextDataResult *result, const PointerRNA *ptr);
void CTX_data_list_add(bContextDataResult *result, struct ID *id, StructRNA *type, void *data);
/**
* Stores a property in a result. Make sure to also call
* `CTX_data_type_set(result, CTX_DATA_TYPE_PROPERTY)`.
* \param result: The result to store the property in.
* \param prop: The property to store.
* \param index: The particular index in the property to store.
*/
void CTX_data_prop_set(bContextDataResult *result, PropertyRNA *prop, int index);
void CTX_data_dir_set(bContextDataResult *result, const char **dir);
void CTX_data_type_set(struct bContextDataResult *result, short type);

View File

@ -805,6 +805,16 @@ Curves *curves_new_nomain_single(int points_num, CurveType type);
*/
void curves_copy_parameters(const Curves &src, Curves &dst);
CurvesGeometry curves_copy_point_selection(
const CurvesGeometry &curves,
const IndexMask &points_to_copy,
const AnonymousAttributePropagationInfo &propagation_info);
CurvesGeometry curves_copy_curve_selection(
const CurvesGeometry &curves,
const IndexMask &curves_to_copy,
const AnonymousAttributePropagationInfo &propagation_info);
std::array<int, CURVE_TYPES_NUM> calculate_type_counts(const VArray<int8_t> &types);
/* -------------------------------------------------------------------- */

View File

@ -473,12 +473,6 @@ class IndexRangeCyclic {
* ranges, assuming that all curves have the same number of control points in #src_curves
* and #dst_curves.
*/
void copy_point_data(OffsetIndices<int> src_points_by_curve,
OffsetIndices<int> dst_points_by_curve,
Span<IndexRange> curve_ranges,
GSpan src,
GMutableSpan dst);
void copy_point_data(OffsetIndices<int> src_points_by_curve,
OffsetIndices<int> dst_points_by_curve,
const IndexMask &src_curve_selection,
@ -513,20 +507,6 @@ void fill_points(const OffsetIndices<int> points_by_curve,
fill_points(points_by_curve, curve_selection, &value, dst);
}
void fill_points(const OffsetIndices<int> points_by_curve,
Span<IndexRange> curve_ranges,
GPointer value,
GMutableSpan dst);
template<typename T>
void fill_points(const OffsetIndices<int> points_by_curve,
Span<IndexRange> curve_ranges,
const T &value,
MutableSpan<T> dst)
{
fill_points(points_by_curve, curve_ranges, &value, dst);
}
/**
* Create new curves with the same number of curves as the input, but no points. Copy all curve
* domain attributes to the new curves, except the offsets encoding the size of each curve.
@ -538,21 +518,6 @@ void fill_points(const OffsetIndices<int> points_by_curve,
*/
bke::CurvesGeometry copy_only_curve_domain(const bke::CurvesGeometry &src_curves);
/**
* Copy the number of points in every curve in the mask to the corresponding index in #sizes.
*/
void copy_curve_sizes(OffsetIndices<int> points_by_curve,
const IndexMask &mask,
MutableSpan<int> sizes);
/**
* Copy the number of points in every curve in #curve_ranges to the corresponding index in
* #sizes.
*/
void copy_curve_sizes(OffsetIndices<int> points_by_curve,
Span<IndexRange> curve_ranges,
MutableSpan<int> sizes);
IndexMask indices_for_type(const VArray<int8_t> &types,
const std::array<int, CURVE_TYPES_NUM> &type_counts,
const CurveType type,

View File

@ -647,7 +647,8 @@ bool BKE_id_can_be_asset(const struct ID *id);
*/
struct ID *BKE_id_owner_get(struct ID *id);
/** Check if that ID can be considered as editable from a high-level (editor) perspective.
/**
* Check if that ID can be considered as editable from a high-level (editor) perspective.
*
* NOTE: This used to be done with a check on whether ID was linked or not, but now with system
* overrides this is not enough anymore.

View File

@ -311,7 +311,8 @@ void BKE_lib_override_library_property_delete(struct IDOverrideLibrary *override
bool BKE_lib_override_library_property_search_and_delete(struct IDOverrideLibrary *override,
const char *rna_path);
/** Change the RNA path of a library override on a property.
/**
* Change the RNA path of a library override on a property.
*
* No-op if the property override cannot be found.
*

View File

@ -131,11 +131,14 @@ typedef int (*LibraryIDLinkCallback)(LibraryIDLinkCallbackData *cb_data);
/* Flags for the foreach function itself. */
enum {
IDWALK_NOP = 0,
/** The callback will never modify the ID pointers it processes.
/**
* The callback will never modify the ID pointers it processes.
* WARNING: It is very important to pass this flag when valid, as it can lead to important
* optimizations and debug/assert code. */
* optimizations and debug/assert code.
*/
IDWALK_READONLY = (1 << 0),
/** Recurse into 'descendant' IDs.
/**
* Recurse into 'descendant' IDs.
* Each ID is only processed once. Order of ID processing is not guaranteed.
*
* Also implies IDWALK_READONLY, and excludes IDWALK_DO_INTERNAL_RUNTIME_POINTERS.

View File

@ -73,20 +73,27 @@ enum {
*/
ID_REMAP_FORCE_OBDATA_IN_EDITMODE = 1 << 7,
/** Don't touch the special user counts (use when the 'old' remapped ID remains in use):
/**
* Don't touch the special user counts (use when the 'old' remapped ID remains in use):
* - Do not transfer 'fake user' status from old to new ID.
* - Do not clear 'extra user' from old ID. */
* - Do not clear 'extra user' from old ID.
*/
ID_REMAP_SKIP_USER_CLEAR = 1 << 16,
/** Force handling user count even for IDs that are outside of Main (used in some cases when
/**
* Force handling user count even for IDs that are outside of Main (used in some cases when
* dealing with IDs temporarily out of Main, but which will be put in it ultimately).
*/
ID_REMAP_FORCE_USER_REFCOUNT = 1 << 17,
/** Do NOT handle user count for IDs (used in some cases when dealing with IDs from different
/**
* Do NOT handle user count for IDs (used in some cases when dealing with IDs from different
* BMains, if usercount will be recomputed anyway afterwards, like e.g. in memfile reading during
* undo step decoding). */
* undo step decoding).
*/
ID_REMAP_SKIP_USER_REFCOUNT = 1 << 18,
/** Do NOT tag IDs which had some of their ID pointers updated for update in the depsgraph, or ID
* type specific updates, like e.g. with node trees. */
/**
* Do NOT tag IDs which had some of their ID pointers updated for update in the depsgraph, or ID
* type specific updates, like e.g. with node trees.
*/
ID_REMAP_SKIP_UPDATE_TAGGING = 1 << 19,
/**
* Do not attempt to access original ID pointers (triggers usages of

View File

@ -63,7 +63,8 @@ void BKE_main_namemap_remove_name(struct Main *bmain, struct ID *id, const char
*/
bool BKE_main_namemap_validate(struct Main *bmain) ATTR_NONNULL();
/** Same as #BKE_main_namemap_validate, but also fixes any issue by re-generating all name maps,
/**
* Same as #BKE_main_namemap_validate, but also fixes any issue by re-generating all name maps,
* and ensuring again all ID names are unique.
*
* This is typically only used in `do_versions` code to fix broken files.

View File

@ -199,12 +199,10 @@ void BKE_mesh_to_curve(struct Main *bmain,
struct Depsgraph *depsgraph,
struct Scene *scene,
struct Object *ob);
void BKE_pointcloud_from_mesh(const struct Mesh *me, struct PointCloud *pointcloud);
void BKE_mesh_to_pointcloud(struct Main *bmain,
struct Depsgraph *depsgraph,
struct Scene *scene,
struct Object *ob);
void BKE_mesh_from_pointcloud(const struct PointCloud *pointcloud, struct Mesh *me);
void BKE_pointcloud_to_mesh(struct Main *bmain,
struct Depsgraph *depsgraph,
struct Scene *scene,

View File

@ -52,7 +52,8 @@ typedef struct UvElement {
unsigned int island;
} UvElement;
/** UvElementMap is a container for UvElements of a BMesh.
/**
* UvElementMap is a container for UvElements of a BMesh.
*
* It simplifies access to UV information and ensures the
* different UV selection modes are respected.

View File

@ -316,7 +316,8 @@ typedef struct bNodeType {
bool (*poll)(const struct bNodeType *ntype,
const struct bNodeTree *nodetree,
const char **r_disabled_hint);
/** Can this node be added to a node tree?
/**
* Can this node be added to a node tree?
* \param r_disabled_hint: See `poll()`.
*/
bool (*poll_instance)(const struct bNode *node,

View File

@ -96,7 +96,8 @@ class bNodeTreeRuntime : NonCopyable, NonMovable {
*/
NodeIDVectorSet nodes_by_id;
/** Execution data.
/**
* Execution data.
*
* XXX It would be preferable to completely move this data out of the underlying node tree,
* so node tree execution could finally run independent of the tree itself.

View File

@ -726,7 +726,8 @@ void BKE_pbvh_face_iter_step(PBVHFaceIter *fd);
bool BKE_pbvh_face_iter_done(PBVHFaceIter *fd);
void BKE_pbvh_face_iter_finish(PBVHFaceIter *fd);
/** Iterate over faces inside a PBVHNode. These are either base mesh faces
/**
* Iterate over faces inside a #PBVHNode. These are either base mesh faces
* (for PBVH_FACES and PBVH_GRIDS) or BMesh faces (for PBVH_BMESH).
*/
#define BKE_pbvh_face_iter_begin(pbvh, node, fd) \

View File

@ -2490,7 +2490,8 @@ static void nlaevalchan_combine_quaternion_get_inverted_lower_evalchan(
BLI_bitmap_set_all(r_lower_necs->remap_domain.ptr, true, 4);
}
/** Based on blendmode and mix mode, solve for the lower values such that when lower blended or
/**
* Based on blendmode and mix mode, solve for the lower values such that when lower blended or
* combined with upper then we get blended values as a result.
*
* Only processes blended values in the remap domain. Successfully remapped lower values are placed
@ -3496,10 +3497,9 @@ static void animsys_evaluate_nla_for_keyframing(PointerRNA *ptr,
}
}
/** NOTE: Although we early out, we can still keyframe to the non-pushed action since the
/* NOTE: Although we early out, we can still keyframe to the non-pushed action since the
* keyframe remap function detects (r_context->strip.act == NULL) and will keyframe without
* remapping.
*/
* remapping. */
if (is_action_track_evaluated_without_nla(adt, has_strips)) {
BLI_freelistN(&lower_estrips);
return;

View File

@ -765,7 +765,8 @@ CustomDataLayer *BKE_id_attribute_from_index(ID *id,
return nullptr;
}
/** Get list of domain types but with ATTR_DOMAIN_FACE and
/**
* Get list of domain types but with ATTR_DOMAIN_FACE and
* ATTR_DOMAIN_CORNER swapped.
*/
static void get_domains_types(eAttrDomain domains[ATTR_DOMAIN_NUM])

View File

@ -980,11 +980,9 @@ Vector<AttributeTransferData> retrieve_attributes_for_transfer(
return true;
}
GVArray src = *src_attributes.lookup(id, meta_data.domain);
BLI_assert(src);
const GVArray src = *src_attributes.lookup(id, meta_data.domain);
bke::GSpanAttributeWriter dst = dst_attributes.lookup_or_add_for_write_only_span(
id, meta_data.domain, meta_data.data_type);
BLI_assert(dst);
attributes.append({std::move(src), meta_data, std::move(dst)});
return true;
@ -994,4 +992,53 @@ Vector<AttributeTransferData> retrieve_attributes_for_transfer(
/** \} */
void gather_attributes(const AttributeAccessor src_attributes,
const eAttrDomain domain,
const AnonymousAttributePropagationInfo &propagation_info,
const Set<std::string> &skip,
const IndexMask &selection,
MutableAttributeAccessor dst_attributes)
{
const int src_size = src_attributes.domain_size(domain);
src_attributes.for_all([&](const AttributeIDRef &id, const AttributeMetaData meta_data) {
if (meta_data.domain != domain) {
return true;
}
if (id.is_anonymous() && !propagation_info.propagate(id.anonymous_id())) {
return true;
}
if (skip.contains(id.name())) {
return true;
}
const bke::GAttributeReader src = src_attributes.lookup(id, domain);
if (selection.size() == src_size && src.sharing_info && src.varray.is_span()) {
const bke::AttributeInitShared init(src.varray.get_internal_span().data(),
*src.sharing_info);
if (dst_attributes.add(id, domain, meta_data.data_type, init)) {
return true;
}
}
bke::GSpanAttributeWriter dst = dst_attributes.lookup_or_add_for_write_only_span(
id, domain, meta_data.data_type);
array_utils::gather(src.varray, selection, dst.span);
dst.finish();
return true;
});
}
void copy_attributes(const AttributeAccessor src_attributes,
const eAttrDomain domain,
const AnonymousAttributePropagationInfo &propagation_info,
const Set<std::string> &skip,
MutableAttributeAccessor dst_attributes)
{
BLI_assert(src_attributes.domain_size(domain) == dst_attributes.domain_size(domain));
return gather_attributes(src_attributes,
domain,
propagation_info,
skip,
IndexMask(src_attributes.domain_size(domain)),
dst_attributes);
}
} // namespace blender::bke

View File

@ -442,6 +442,9 @@ static void setup_app_data(bContext *C,
* linked libraries. */
if (mode != LOAD_UNDO && !blendfile_or_libraries_versions_atleast(bmain, 302, 1)) {
BKE_lib_override_library_main_proxy_convert(bmain, reports);
/* Currently liboverride code can generate invalid namemap. This is a known issue, requires
* #107847 to be properly fixed. */
BKE_main_namemap_validate_and_fix(bmain);
}
if (mode != LOAD_UNDO && !blendfile_or_libraries_versions_atleast(bmain, 302, 3)) {

View File

@ -1011,6 +1011,10 @@ static void blendfile_link_append_proxies_convert(Main *bmain, ReportList *repor
BlendFileReadReport bf_reports = {.reports = reports};
BKE_lib_override_library_main_proxy_convert(bmain, &bf_reports);
/* Currently liboverride code can generate invalid namemap. This is a known issue, requires
* #107847 to be properly fixed. */
BKE_main_namemap_validate_and_fix(bmain);
if (bf_reports.count.proxies_to_lib_overrides_success != 0 ||
bf_reports.count.proxies_to_lib_overrides_failures != 0)
{

View File

@ -251,13 +251,14 @@ void BKE_bpath_missing_files_check(Main *bmain, ReportList *reports)
#define MAX_DIR_RECURSE 16
#define FILESIZE_INVALID_DIRECTORY -1
/** Find the given filename recursively in the given search directory and its sub-directories.
/**
* Find the given filename recursively in the given search directory and its sub-directories.
*
* \note Use the biggest matching file found, so that thumbnails don't get used by mistake.
*
* \param search_directory: Directory to search in.
* \param filename_src: Search for this filename.
* \param r_filename_new: The path of the new found file will be copied here, caller must
* \param r_filepath_new: The path of the new found file will be copied here, caller must
* initialize as empty string.
* \param r_filesize: Size of the file, `FILESIZE_INVALID_DIRECTORY` if search directory could not
* be opened.
@ -267,7 +268,7 @@ void BKE_bpath_missing_files_check(Main *bmain, ReportList *reports)
*/
static bool missing_files_find__recursive(const char *search_directory,
const char *filename_src,
char r_filename_new[FILE_MAX],
char r_filepath_new[FILE_MAX],
int64_t *r_filesize,
int *r_recurse_depth)
{
@ -306,7 +307,7 @@ static bool missing_files_find__recursive(const char *search_directory,
size = status.st_size;
if ((size > 0) && (size > *r_filesize)) { /* Find the biggest matching file. */
*r_filesize = size;
BLI_strncpy(r_filename_new, path, FILE_MAX);
BLI_strncpy(r_filepath_new, path, FILE_MAX);
found = true;
}
}
@ -315,7 +316,7 @@ static bool missing_files_find__recursive(const char *search_directory,
if (*r_recurse_depth <= MAX_DIR_RECURSE) {
(*r_recurse_depth)++;
found |= missing_files_find__recursive(
path, filename_src, r_filename_new, r_filesize, r_recurse_depth);
path, filename_src, r_filepath_new, r_filesize, r_recurse_depth);
(*r_recurse_depth)--;
}
}
@ -337,7 +338,7 @@ static bool missing_files_find_foreach_path_cb(BPathForeachPathData *bpath_data,
const char *path_src)
{
BPathFind_Data *data = (BPathFind_Data *)bpath_data->user_data;
char filename_new[FILE_MAX];
char filepath_new[FILE_MAX];
int64_t filesize = FILESIZE_INVALID_DIRECTORY;
int recurse_depth = 0;
@ -347,10 +348,10 @@ static bool missing_files_find_foreach_path_cb(BPathForeachPathData *bpath_data,
return false;
}
filename_new[0] = '\0';
filepath_new[0] = '\0';
is_found = missing_files_find__recursive(
data->searchdir, BLI_path_basename(path_src), filename_new, &filesize, &recurse_depth);
data->searchdir, BLI_path_basename(path_src), filepath_new, &filesize, &recurse_depth);
if (filesize == FILESIZE_INVALID_DIRECTORY) {
BKE_reportf(data->reports,
@ -370,7 +371,7 @@ static bool missing_files_find_foreach_path_cb(BPathForeachPathData *bpath_data,
bool was_relative = BLI_path_is_rel(path_dst);
BLI_strncpy(path_dst, filename_new, FILE_MAX);
BLI_strncpy(path_dst, filepath_new, FILE_MAX);
/* Keep the path relative if the previous one was relative. */
if (was_relative) {

View File

@ -247,6 +247,8 @@ void CTX_py_state_pop(bContext *C, bContext_PyState *pystate)
struct bContextDataResult {
PointerRNA ptr;
ListBase list;
PropertyRNA *prop;
int index;
const char **dir;
short type; /* 0: normal, 1: seq */
};
@ -496,8 +498,13 @@ ListBase CTX_data_collection_get(const bContext *C, const char *member)
return list;
}
int /*eContextResult*/ CTX_data_get(
const bContext *C, const char *member, PointerRNA *r_ptr, ListBase *r_lb, short *r_type)
int /*eContextResult*/ CTX_data_get(const bContext *C,
const char *member,
PointerRNA *r_ptr,
ListBase *r_lb,
PropertyRNA **r_prop,
int *r_index,
short *r_type)
{
bContextDataResult result;
eContextResult ret = ctx_data_get((bContext *)C, member, &result);
@ -505,6 +512,8 @@ int /*eContextResult*/ CTX_data_get(
if (ret == CTX_RESULT_OK) {
*r_ptr = result.ptr;
*r_lb = result.list;
*r_prop = result.prop;
*r_index = result.index;
*r_type = result.type;
}
else {
@ -675,6 +684,12 @@ int ctx_data_list_count(const bContext *C, bool (*func)(const bContext *, ListBa
return 0;
}
void CTX_data_prop_set(bContextDataResult *result, PropertyRNA *prop, int index)
{
result->prop = prop;
result->index = index;
}
void CTX_data_dir_set(bContextDataResult *result, const char **dir)
{
result->dir = dir;

View File

@ -15,6 +15,7 @@
#include "BLI_length_parameterize.hh"
#include "BLI_math_matrix.hh"
#include "BLI_math_rotation_legacy.hh"
#include "BLI_multi_value_map.hh"
#include "BLI_task.hh"
#include "BLO_read_write.h"
@ -1108,113 +1109,55 @@ bool CurvesGeometry::bounds_min_max(float3 &min, float3 &max) const
return true;
}
static void copy_construct_data(const GSpan src, GMutableSpan dst)
{
BLI_assert(src.size() == dst.size());
src.type().copy_construct_n(src.data(), dst.data(), src.size());
}
static CurvesGeometry copy_with_removed_points(
CurvesGeometry curves_copy_point_selection(
const CurvesGeometry &curves,
const IndexMask &points_to_delete,
const IndexMask &points_to_copy,
const AnonymousAttributePropagationInfo &propagation_info)
{
/* Use a map from points to curves to facilitate using an #IndexMask input. */
const Array<int> point_to_curve_map = curves.point_to_curve_map();
const Vector<IndexRange> copy_point_ranges = points_to_delete.to_ranges_invert(
curves.points_range());
/* For every range of points to copy, find the offset in the result curves point layers. */
int new_point_count = 0;
Array<int> copy_point_range_dst_offsets(copy_point_ranges.size());
for (const int i : copy_point_ranges.index_range()) {
copy_point_range_dst_offsets[i] = new_point_count;
new_point_count += copy_point_ranges[i].size();
}
BLI_assert(new_point_count == (curves.points_num() - points_to_delete.size()));
/* Find out how many non-deleted points there are in every curve. */
Array<int> curve_point_counts(curves.curves_num(), 0);
for (const IndexRange range : copy_point_ranges) {
for (const int point_i : range) {
curve_point_counts[point_to_curve_map[point_i]]++;
}
}
points_to_copy.foreach_index(
[&](const int64_t point_i) { curve_point_counts[point_to_curve_map[point_i]]++; });
/* Build the offsets for the new curve points, skipping curves that had all points deleted.
* Also store the original indices of the corresponding input curves, to facilitate parallel
* copying of curve domain data. */
int new_curve_count = 0;
int curve_point_offset = 0;
Vector<int> new_curve_offsets;
Vector<int> new_curve_orig_indices;
new_curve_offsets.append(0);
for (const int i : curve_point_counts.index_range()) {
if (curve_point_counts[i] > 0) {
curve_point_offset += curve_point_counts[i];
new_curve_offsets.append(curve_point_offset);
new_curve_count++;
new_curve_orig_indices.append(i);
}
}
CurvesGeometry new_curves{new_point_count, new_curve_count};
Vector<bke::AttributeTransferData> point_attributes = bke::retrieve_attributes_for_transfer(
curves.attributes(),
new_curves.attributes_for_write(),
ATTR_DOMAIN_MASK_POINT,
propagation_info);
Vector<bke::AttributeTransferData> curve_attributes = bke::retrieve_attributes_for_transfer(
curves.attributes(),
new_curves.attributes_for_write(),
ATTR_DOMAIN_MASK_CURVE,
propagation_info);
threading::parallel_invoke(
256 < new_point_count * new_curve_count,
/* Initialize curve offsets. */
[&]() { new_curves.offsets_for_write().copy_from(new_curve_offsets); },
[&]() {
/* Copy over point attributes. */
for (bke::AttributeTransferData &attribute : point_attributes) {
threading::parallel_for(copy_point_ranges.index_range(), 128, [&](IndexRange range) {
for (const int range_i : range) {
const IndexRange src_range = copy_point_ranges[range_i];
const IndexRange dst_range(copy_point_range_dst_offsets[range_i], src_range.size());
copy_construct_data(attribute.src.slice(src_range),
attribute.dst.span.slice(dst_range));
}
});
}
},
[&]() {
/* Copy over curve attributes.
* In some cases points are just dissolved, so the number of
* curves will be the same. That could be optimized in the future. */
for (bke::AttributeTransferData &attribute : curve_attributes) {
if (new_curves.curves_num() == curves.curves_num()) {
attribute.dst.span.copy_from(attribute.src);
}
else {
bke::attribute_math::gather(attribute.src, new_curve_orig_indices, attribute.dst.span);
}
}
IndexMaskMemory memory;
const IndexMask curves_to_copy = IndexMask::from_predicate(
curves.curves_range(), GrainSize(4096), memory, [&](const int64_t i) {
return curve_point_counts[i] > 0;
});
for (bke::AttributeTransferData &attribute : point_attributes) {
attribute.dst.finish();
CurvesGeometry dst_curves(points_to_copy.size(), curves_to_copy.size());
threading::parallel_invoke(
dst_curves.curves_num() > 1024,
[&]() {
MutableSpan<int> new_curve_offsets = dst_curves.offsets_for_write();
array_utils::gather(
curve_point_counts.as_span(), curves_to_copy, new_curve_offsets.drop_back(1));
offset_indices::accumulate_counts_to_offsets(new_curve_offsets);
},
[&]() {
gather_attributes(curves.attributes(),
ATTR_DOMAIN_POINT,
propagation_info,
{},
points_to_copy,
dst_curves.attributes_for_write());
gather_attributes(curves.attributes(),
ATTR_DOMAIN_CURVE,
propagation_info,
{},
curves_to_copy,
dst_curves.attributes_for_write());
});
if (dst_curves.curves_num() == curves.curves_num()) {
dst_curves.runtime->type_counts = curves.runtime->type_counts;
}
for (bke::AttributeTransferData &attribute : curve_attributes) {
attribute.dst.finish();
else {
dst_curves.remove_attributes_based_on_types();
}
if (new_curves.curves_num() != curves.curves_num()) {
new_curves.remove_attributes_based_on_types();
}
return new_curves;
return dst_curves;
}
void CurvesGeometry::remove_points(const IndexMask &points_to_delete,
@ -1226,106 +1169,75 @@ void CurvesGeometry::remove_points(const IndexMask &points_to_delete,
if (points_to_delete.size() == this->points_num()) {
*this = {};
}
*this = copy_with_removed_points(*this, points_to_delete, propagation_info);
IndexMaskMemory memory;
const IndexMask points_to_copy = points_to_delete.complement(this->points_range(), memory);
*this = curves_copy_point_selection(*this, points_to_copy, propagation_info);
}
static CurvesGeometry copy_with_removed_curves(
template<typename T>
static void gather_group_to_group(const OffsetIndices<int> src_offsets,
const OffsetIndices<int> dst_offsets,
const IndexMask &selection,
const Span<T> src,
MutableSpan<T> dst)
{
selection.foreach_index(GrainSize(256), [&](const int64_t src_i, const int64_t dst_i) {
dst.slice(dst_offsets[dst_i]).copy_from(src.slice(src_offsets[src_i]));
});
}
static void gather_group_to_group(const OffsetIndices<int> src_offsets,
const OffsetIndices<int> dst_offsets,
const IndexMask &selection,
const GSpan src,
GMutableSpan dst)
{
attribute_math::convert_to_static_type(src.type(), [&](auto dummy) {
using T = decltype(dummy);
gather_group_to_group(src_offsets, dst_offsets, selection, src.typed<T>(), dst.typed<T>());
});
}
CurvesGeometry curves_copy_curve_selection(
const CurvesGeometry &curves,
const IndexMask &curves_to_delete,
const IndexMask &curves_to_copy,
const AnonymousAttributePropagationInfo &propagation_info)
{
const OffsetIndices old_points_by_curve = curves.points_by_curve();
const Span<int> old_offsets = curves.offsets();
const Vector<IndexRange> old_curve_ranges = curves_to_delete.to_ranges_invert(
curves.curves_range());
Vector<IndexRange> new_curve_ranges;
Vector<IndexRange> old_point_ranges;
Vector<IndexRange> new_point_ranges;
int new_tot_points = 0;
int new_tot_curves = 0;
for (const IndexRange &curve_range : old_curve_ranges) {
new_curve_ranges.append(IndexRange(new_tot_curves, curve_range.size()));
new_tot_curves += curve_range.size();
CurvesGeometry dst_curves(0, curves_to_copy.size());
MutableSpan<int> new_curve_offsets = dst_curves.offsets_for_write();
offset_indices::gather_group_sizes(
curves.points_by_curve(), curves_to_copy, new_curve_offsets.drop_back(1));
offset_indices::accumulate_counts_to_offsets(new_curve_offsets);
dst_curves.resize(new_curve_offsets.last(), dst_curves.curves_num());
const IndexRange old_point_range = old_points_by_curve[curve_range];
old_point_ranges.append(old_point_range);
new_point_ranges.append(IndexRange(new_tot_points, old_point_range.size()));
new_tot_points += old_point_range.size();
}
const OffsetIndices src_points_by_curve = curves.points_by_curve();
const OffsetIndices dst_points_by_curve = dst_curves.points_by_curve();
CurvesGeometry new_curves{new_tot_points, new_tot_curves};
Vector<bke::AttributeTransferData> point_attributes = bke::retrieve_attributes_for_transfer(
curves.attributes(),
new_curves.attributes_for_write(),
ATTR_DOMAIN_MASK_POINT,
propagation_info);
Vector<bke::AttributeTransferData> curve_attributes = bke::retrieve_attributes_for_transfer(
curves.attributes(),
new_curves.attributes_for_write(),
ATTR_DOMAIN_MASK_CURVE,
propagation_info);
const AttributeAccessor src_attributes = curves.attributes();
MutableAttributeAccessor dst_attributes = dst_curves.attributes_for_write();
threading::parallel_invoke(
256 < new_tot_points * new_tot_curves,
/* Initialize curve offsets. */
[&]() {
MutableSpan<int> new_offsets = new_curves.offsets_for_write();
new_offsets.last() = new_tot_points;
threading::parallel_for(
old_curve_ranges.index_range(), 128, [&](const IndexRange ranges_range) {
for (const int range_i : ranges_range) {
const IndexRange old_curve_range = old_curve_ranges[range_i];
const IndexRange new_curve_range = new_curve_ranges[range_i];
const IndexRange old_point_range = old_point_ranges[range_i];
const IndexRange new_point_range = new_point_ranges[range_i];
const int offset_shift = new_point_range.start() - old_point_range.start();
const int curves_in_range = old_curve_range.size();
threading::parallel_for(
IndexRange(curves_in_range), 512, [&](const IndexRange range) {
for (const int i : range) {
const int old_curve_i = old_curve_range[i];
const int new_curve_i = new_curve_range[i];
const int old_offset = old_offsets[old_curve_i];
const int new_offset = old_offset + offset_shift;
new_offsets[new_curve_i] = new_offset;
}
});
}
});
},
[&]() {
/* Copy over point attributes. */
for (bke::AttributeTransferData &attribute : point_attributes) {
threading::parallel_for(old_curve_ranges.index_range(), 128, [&](IndexRange range) {
for (const int range_i : range) {
copy_construct_data(attribute.src.slice(old_point_ranges[range_i]),
attribute.dst.span.slice(new_point_ranges[range_i]));
}
});
}
},
[&]() {
/* Copy over curve attributes. */
for (bke::AttributeTransferData &attribute : curve_attributes) {
threading::parallel_for(old_curve_ranges.index_range(), 128, [&](IndexRange range) {
for (const int range_i : range) {
copy_construct_data(attribute.src.slice(old_curve_ranges[range_i]),
attribute.dst.span.slice(new_curve_ranges[range_i]));
}
});
}
});
src_attributes.for_all([&](const AttributeIDRef &id, const AttributeMetaData meta_data) {
if (meta_data.domain != ATTR_DOMAIN_POINT) {
return true;
}
if (id.is_anonymous() && !propagation_info.propagate(id.anonymous_id())) {
return true;
}
const GVArraySpan src = *src_attributes.lookup(id);
GSpanAttributeWriter dst = dst_attributes.lookup_or_add_for_write_only_span(
id, meta_data.domain, meta_data.data_type);
gather_group_to_group(src_points_by_curve, dst_points_by_curve, curves_to_copy, src, dst.span);
dst.finish();
return true;
});
for (bke::AttributeTransferData &attribute : point_attributes) {
attribute.dst.finish();
}
for (bke::AttributeTransferData &attribute : curve_attributes) {
attribute.dst.finish();
}
gather_attributes(
src_attributes, ATTR_DOMAIN_CURVE, propagation_info, {}, curves_to_copy, dst_attributes);
new_curves.remove_attributes_based_on_types();
dst_curves.remove_attributes_based_on_types();
dst_curves.update_curve_types();
return new_curves;
return dst_curves;
}
void CurvesGeometry::remove_curves(const IndexMask &curves_to_delete,
@ -1338,7 +1250,9 @@ void CurvesGeometry::remove_curves(const IndexMask &curves_to_delete,
*this = {};
return;
}
*this = copy_with_removed_curves(*this, curves_to_delete, propagation_info);
IndexMaskMemory memory;
const IndexMask curves_to_copy = curves_to_delete.complement(this->curves_range(), memory);
*this = curves_copy_curve_selection(*this, curves_to_copy, propagation_info);
}
template<typename T>

View File

@ -8,44 +8,6 @@
namespace blender::bke::curves {
void copy_curve_sizes(const OffsetIndices<int> points_by_curve,
const IndexMask &mask,
MutableSpan<int> sizes)
{
mask.foreach_index(GrainSize(4096), [&](const int i) { sizes[i] = points_by_curve[i].size(); });
}
void copy_curve_sizes(const OffsetIndices<int> points_by_curve,
const Span<IndexRange> curve_ranges,
MutableSpan<int> sizes)
{
threading::parallel_for(curve_ranges.index_range(), 512, [&](IndexRange ranges_range) {
for (const IndexRange curves_range : curve_ranges.slice(ranges_range)) {
threading::parallel_for(curves_range, 4096, [&](IndexRange range) {
for (const int i : range) {
sizes[i] = points_by_curve[i].size();
}
});
}
});
}
void copy_point_data(const OffsetIndices<int> src_points_by_curve,
const OffsetIndices<int> dst_points_by_curve,
const Span<IndexRange> curve_ranges,
const GSpan src,
GMutableSpan dst)
{
threading::parallel_for(curve_ranges.index_range(), 512, [&](IndexRange range) {
for (const IndexRange range : curve_ranges.slice(range)) {
const IndexRange src_points = src_points_by_curve[range];
const IndexRange dst_points = dst_points_by_curve[range];
/* The arrays might be large, so a threaded copy might make sense here too. */
dst.slice(dst_points).copy_from(src.slice(src_points));
}
});
}
void copy_point_data(const OffsetIndices<int> src_points_by_curve,
const OffsetIndices<int> dst_points_by_curve,
const IndexMask &src_curve_selection,
@ -73,21 +35,6 @@ void fill_points(const OffsetIndices<int> points_by_curve,
});
}
void fill_points(const OffsetIndices<int> points_by_curve,
Span<IndexRange> curve_ranges,
GPointer value,
GMutableSpan dst)
{
BLI_assert(*value.type() == dst.type());
const CPPType &type = dst.type();
threading::parallel_for(curve_ranges.index_range(), 512, [&](IndexRange range) {
for (const IndexRange range : curve_ranges.slice(range)) {
const IndexRange points = points_by_curve[range];
type.fill_assign_n(value.get(), dst.slice(points).data(), points.size());
}
});
}
bke::CurvesGeometry copy_only_curve_domain(const bke::CurvesGeometry &src_curves)
{
bke::CurvesGeometry dst_curves(0, src_curves.curves_num());

View File

@ -108,7 +108,6 @@ blender::Span<InstanceReference> Instances::references() const
void Instances::remove(const IndexMask &mask,
const AnonymousAttributePropagationInfo &propagation_info)
{
using namespace blender;
const std::optional<IndexRange> masked_range = mask.to_range();
if (masked_range.has_value() && masked_range->start() == 0) {
/* Deleting from the end of the array can be much faster since no data has to be shifted. */
@ -153,9 +152,6 @@ void Instances::remove(const IndexMask &mask,
void Instances::remove_unused_references()
{
using namespace blender;
using namespace blender::bke;
const int tot_instances = this->instances_num();
const int tot_references_before = references_.size();
@ -261,9 +257,8 @@ void Instances::ensure_owns_direct_data()
}
}
static blender::Array<int> generate_unique_instance_ids(Span<int> original_ids)
static Array<int> generate_unique_instance_ids(Span<int> original_ids)
{
using namespace blender;
Array<int> unique_ids(original_ids.size());
Set<int> used_unique_ids;
@ -314,7 +309,7 @@ static blender::Array<int> generate_unique_instance_ids(Span<int> original_ids)
return unique_ids;
}
blender::Span<int> Instances::almost_unique_ids() const
Span<int> Instances::almost_unique_ids() const
{
std::lock_guard lock(almost_unique_ids_mutex_);
std::optional<GSpan> instance_ids_gspan = attributes_.get_for_read("id");

View File

@ -1864,9 +1864,8 @@ KeyBlock *BKE_keyblock_add(Key *key, const char *name)
kb->slidermin = 0.0f;
kb->slidermax = 1.0f;
/**
* \note caller may want to set this to current time, but don't do it here since we need to sort
* which could cause problems in some cases, see #BKE_keyblock_add_ctime */
/* \note caller may want to set this to current time, but don't do it here since we need to sort
* which could cause problems in some cases, see #BKE_keyblock_add_ctime. */
kb->pos = curpos + 0.1f; /* only used for absolute shape keys */
return kb;

View File

@ -152,8 +152,10 @@ static bool lib_id_library_local_paths_callback(BPathForeachPathData *bpath_data
/**
* This has to be called from each make_local_* func, we could call from BKE_lib_id_make_local()
* but then the make local functions would not be self contained.
* Also note that the id _must_ have a library - campbell */
/* TODO: This can probably be replaced by an ID-level version of #BKE_bpath_relative_rebase. */
*
* NOTE(@ideasman42): that the id _must_ have a library.
* TODO: This can probably be replaced by an ID-level version of #BKE_bpath_relative_rebase.
*/
static void lib_id_library_local_paths(Main *bmain, Library *lib, ID *id)
{
const char *bpath_user_data[2] = {BKE_main_blendfile_path(bmain), lib->filepath_abs};
@ -1754,19 +1756,19 @@ static void library_make_local_copying_check(ID *id,
BLI_gset_remove(loop_tags, id, NULL);
}
/* NOTE: Old (2.77) version was simply making (tagging) data-blocks as local,
* without actually making any check whether they were also indirectly used or not...
*
* Current version uses regular id_make_local callback, with advanced pre-processing step to
* detect all cases of IDs currently indirectly used, but which will be used by local data only
* once this function is finished. This allows to avoid any unneeded duplication of IDs, and
* hence all time lost afterwards to remove orphaned linked data-blocks. */
void BKE_library_make_local(Main *bmain,
const Library *lib,
GHash *old_to_new_ids,
const bool untagged_only,
const bool set_fake)
{
/* NOTE: Old (2.77) version was simply making (tagging) data-blocks as local,
* without actually making any check whether they were also indirectly used or not...
*
* Current version uses regular id_make_local callback, with advanced pre-processing step to
* detect all cases of IDs currently indirectly used, but which will be used by local data only
* once this function is finished. This allows to avoid any unneeded duplication of IDs, and
* hence all time lost afterwards to remove orphaned linked data-blocks. */
ListBase *lbarray[INDEX_ID_MAX];

View File

@ -403,34 +403,51 @@ struct Uniqueness_Key {
static bool main_namemap_validate_and_fix(Main *bmain, const bool do_fix)
{
Set<Uniqueness_Key> id_names_libs;
Set<ID *> id_validated;
bool is_valid = true;
ListBase *lb_iter;
FOREACH_MAIN_LISTBASE_BEGIN (bmain, lb_iter) {
LISTBASE_FOREACH_MUTABLE (ID *, id_iter, lb_iter) {
if (id_validated.contains(id_iter)) {
/* Do not re-check an already validated ID. */
continue;
}
Uniqueness_Key key;
STRNCPY(key.name, id_iter->name);
key.lib = id_iter->lib;
if (!id_names_libs.add(key)) {
is_valid = false;
CLOG_ERROR(&LOG,
"ID name '%s' (from library '%s') is found more than once",
id_iter->name,
id_iter->lib != nullptr ? id_iter->lib->filepath : "<None>");
if (do_fix) {
/* NOTE: this may imply moving this ID in its listbase, however re-checking it later is
* not really an issue. */
CLOG_WARN(&LOG,
"ID name '%s' (from library '%s') is found more than once",
id_iter->name,
id_iter->lib != nullptr ? id_iter->lib->filepath : "<None>");
/* NOTE: this may imply moving this ID in its listbase. The logic below will add the ID
* to the validated set if it can now be added to `id_names_libs`, and will prevent
* further checking (which would fail again, since the new ID name/lib key has already
* been added to `id_names_libs`). */
BKE_id_new_name_validate(
bmain, which_libbase(bmain, GS(id_iter->name)), id_iter, nullptr, true);
STRNCPY(key.name, id_iter->name);
if (!id_names_libs.add(key)) {
/* This is a serious error, very likely a bug, keep it as CLOG_ERROR even when doing
* fixes. */
CLOG_ERROR(&LOG,
"\tID has been renamed to '%s', but it still seems to be already in use",
id_iter->name);
}
else {
CLOG_WARN(&LOG, "\tID has been renamed to '%s'", id_iter->name);
id_validated.add(id_iter);
}
}
else {
CLOG_ERROR(&LOG,
"ID name '%s' (from library '%s') is found more than once",
id_iter->name,
id_iter->lib != nullptr ? id_iter->lib->filepath : "<None>");
}
}
UniqueName_Map *name_map = get_namemap_for(bmain, id_iter, false);
@ -445,11 +462,23 @@ static bool main_namemap_validate_and_fix(Main *bmain, const bool do_fix)
STRNCPY(key_namemap.name, id_iter->name + 2);
if (!type_map->full_names.contains(key_namemap)) {
is_valid = false;
CLOG_ERROR(&LOG,
"ID name '%s' (from library '%s') exists in current Main, but is not listed in "
"the namemap",
id_iter->name,
id_iter->lib != nullptr ? id_iter->lib->filepath : "<None>");
if (do_fix) {
CLOG_INFO(
&LOG,
3,
"ID name '%s' (from library '%s') exists in current Main, but is not listed in "
"the namemap",
id_iter->name,
id_iter->lib != nullptr ? id_iter->lib->filepath : "<None>");
}
else {
CLOG_ERROR(
&LOG,
"ID name '%s' (from library '%s') exists in current Main, but is not listed in "
"the namemap",
id_iter->name,
id_iter->lib != nullptr ? id_iter->lib->filepath : "<None>");
}
}
}
}
@ -472,11 +501,23 @@ static bool main_namemap_validate_and_fix(Main *bmain, const bool do_fix)
key.lib = lib;
if (!id_names_libs.contains(key)) {
is_valid = false;
CLOG_ERROR(&LOG,
"ID name '%s' (from library '%s') is listed in the namemap, but does not "
"exists in current Main",
key.name,
lib != nullptr ? lib->filepath : "<None>");
if (do_fix) {
CLOG_INFO(
&LOG,
3,
"ID name '%s' (from library '%s') is listed in the namemap, but does not "
"exists in current Main",
key.name,
lib != nullptr ? lib->filepath : "<None>");
}
else {
CLOG_ERROR(
&LOG,
"ID name '%s' (from library '%s') is listed in the namemap, but does not "
"exists in current Main",
key.name,
lib != nullptr ? lib->filepath : "<None>");
}
}
}
}
@ -491,16 +532,7 @@ static bool main_namemap_validate_and_fix(Main *bmain, const bool do_fix)
}
/* Clear all existing namemaps. */
lib = nullptr;
UniqueName_Map **name_map_p = &bmain->name_map;
do {
BLI_assert(name_map_p != nullptr);
if (*name_map_p != nullptr) {
BKE_main_namemap_destroy(name_map_p);
}
lib = static_cast<Library *>((lib == nullptr) ? bmain->libraries.first : lib->id.next);
name_map_p = (lib != nullptr) ? &lib->runtime.name_map : nullptr;
} while (lib != nullptr);
BKE_main_namemap_clear(bmain);
return is_valid;
}

View File

@ -76,6 +76,8 @@
static CLG_LogRef LOG = {"bke.material"};
static void material_clear_data(ID *id);
static void material_init_data(ID *id)
{
Material *material = (Material *)id;
@ -133,6 +135,25 @@ static void material_copy_data(Main *bmain, ID *id_dst, const ID *id_src, const
/* TODO: Duplicate Engine Settings and set runtime to nullptr. */
}
/**
* Ensure pointers to allocated memory is cleared
* (the kind of data that would have to be copied).
*
* \note Keep in sync with #material_free_data.
*/
static void material_clear_data(ID *id)
{
Material *material = (Material *)id;
BLI_listbase_clear(&material->gpumaterial);
material->texpaintslot = nullptr;
material->gp_style = nullptr;
material->nodetree = nullptr;
material->preview = nullptr;
id->icon_id = 0;
}
static void material_free_data(ID *id)
{
Material *material = (Material *)id;
@ -151,8 +172,9 @@ static void material_free_data(ID *id)
MEM_SAFE_FREE(material->gp_style);
BKE_icon_id_delete((ID *)material);
BKE_previewimg_free(&material->preview);
BKE_icon_id_delete((ID *)material);
}
static void material_foreach_id(ID *id, LibraryForeachIDData *data)
@ -1920,19 +1942,20 @@ static short matcopied = 0;
void BKE_material_copybuf_clear(void)
{
if (matcopied) {
BKE_material_copybuf_free();
}
matcopybuf = blender::dna::shallow_zero_initialize();
matcopied = 0;
}
void BKE_material_copybuf_free(void)
{
BLI_assert(matcopybuf.id.icon_id == 0);
if (matcopybuf.nodetree) {
ntreeFreeLocalTree(matcopybuf.nodetree);
BLI_assert(!matcopybuf.nodetree->id.py_instance); /* Or call #BKE_libblock_free_data_py. */
MEM_freeN(matcopybuf.nodetree);
matcopybuf.nodetree = nullptr;
}
material_free_data(&matcopybuf.id);
matcopied = 0;
}
@ -1944,12 +1967,17 @@ void BKE_material_copybuf_copy(Main *bmain, Material *ma)
matcopybuf = blender::dna::shallow_copy(*ma);
/* Not essential, but we never want to use any ID values from the source,
* this ensures that never happens. */
memset(&matcopybuf.id, 0, sizeof(ID));
/* Ensure dangling pointers are never copied back into a material. */
material_clear_data(&matcopybuf.id);
if (ma->nodetree != nullptr) {
matcopybuf.nodetree = blender::bke::ntreeCopyTree_ex(ma->nodetree, bmain, false);
}
matcopybuf.preview = nullptr;
BLI_listbase_clear(&matcopybuf.gpumaterial);
/* TODO: Duplicate Engine Settings and set runtime to nullptr. */
matcopied = 1;
}
@ -1962,13 +1990,10 @@ void BKE_material_copybuf_paste(Main *bmain, Material *ma)
return;
}
/* Free gpu material before the ntree */
GPU_material_free(&ma->gpumaterial);
const bool has_node_tree = (ma->nodetree || matcopybuf.nodetree);
if (ma->nodetree) {
ntreeFreeEmbeddedTree(ma->nodetree);
MEM_freeN(ma->nodetree);
}
/* Handles freeing nodes and and other run-time data (previews) for e.g. */
material_free_data(&ma->id);
id = (ma->id);
*ma = blender::dna::shallow_copy(matcopybuf);
@ -1977,6 +2002,13 @@ void BKE_material_copybuf_paste(Main *bmain, Material *ma)
if (matcopybuf.nodetree != nullptr) {
ma->nodetree = blender::bke::ntreeCopyTree_ex(matcopybuf.nodetree, bmain, false);
}
if (has_node_tree) {
/* Important to run this when the embedded tree if freed,
* otherwise the depsgraph holds a reference to the (now freed) `ma->nodetree`.
* Also run this when a new node-tree is set to ensure it's accounted for. */
DEG_relations_tag_update(bmain);
}
}
void BKE_material_eval(struct Depsgraph *depsgraph, Material *material)

View File

@ -531,24 +531,19 @@ void BKE_mesh_to_curve(Main *bmain, Depsgraph *depsgraph, Scene * /*scene*/, Obj
}
}
void BKE_pointcloud_from_mesh(const Mesh *me, PointCloud *pointcloud)
{
CustomData_free(&pointcloud->pdata, pointcloud->totpoint);
pointcloud->totpoint = me->totvert;
CustomData_merge(&me->vdata, &pointcloud->pdata, CD_MASK_PROP_ALL, me->totvert);
}
void BKE_mesh_to_pointcloud(Main *bmain, Depsgraph *depsgraph, Scene * /*scene*/, Object *ob)
{
BLI_assert(ob->type == OB_MESH);
Scene *scene_eval = DEG_get_evaluated_scene(depsgraph);
Object *ob_eval = DEG_get_evaluated_object(depsgraph, ob);
Mesh *me_eval = mesh_get_eval_final(depsgraph, scene_eval, ob_eval, &CD_MASK_MESH);
const Mesh *mesh_eval = mesh_get_eval_final(depsgraph, scene_eval, ob_eval, &CD_MASK_MESH);
PointCloud *pointcloud = (PointCloud *)BKE_pointcloud_add(bmain, ob->id.name + 2);
BKE_pointcloud_from_mesh(me_eval, pointcloud);
CustomData_free(&pointcloud->pdata, pointcloud->totpoint);
pointcloud->totpoint = mesh_eval->totvert;
CustomData_merge(&mesh_eval->vdata, &pointcloud->pdata, CD_MASK_PROP_ALL, mesh_eval->totvert);
BKE_id_materials_copy(bmain, (ID *)ob->data, (ID *)pointcloud);
@ -559,27 +554,23 @@ void BKE_mesh_to_pointcloud(Main *bmain, Depsgraph *depsgraph, Scene * /*scene*/
BKE_object_free_derived_caches(ob);
}
void BKE_mesh_from_pointcloud(const PointCloud *pointcloud, Mesh *me)
{
me->totvert = pointcloud->totpoint;
CustomData_merge(&pointcloud->pdata, &me->vdata, CD_MASK_PROP_ALL, pointcloud->totpoint);
}
void BKE_pointcloud_to_mesh(Main *bmain, Depsgraph *depsgraph, Scene * /*scene*/, Object *ob)
{
BLI_assert(ob->type == OB_POINTCLOUD);
Object *ob_eval = DEG_get_evaluated_object(depsgraph, ob);
PointCloud *pointcloud_eval = (PointCloud *)ob_eval->runtime.data_eval;
const PointCloud *pointcloud_eval = (const PointCloud *)ob_eval->runtime.data_eval;
Mesh *me = BKE_mesh_add(bmain, ob->id.name + 2);
Mesh *mesh = BKE_mesh_add(bmain, ob->id.name + 2);
BKE_mesh_from_pointcloud(pointcloud_eval, me);
mesh->totvert = pointcloud_eval->totpoint;
CustomData_merge(
&pointcloud_eval->pdata, &mesh->vdata, CD_MASK_PROP_ALL, pointcloud_eval->totpoint);
BKE_id_materials_copy(bmain, (ID *)ob->data, (ID *)me);
BKE_id_materials_copy(bmain, (ID *)ob->data, (ID *)mesh);
id_us_min(&((PointCloud *)ob->data)->id);
ob->data = me;
ob->data = mesh;
ob->type = OB_MESH;
BKE_object_free_derived_caches(ob);

View File

@ -601,14 +601,14 @@ static ImBuf *movieclip_load_sequence_file(MovieClip *clip,
static void movieclip_open_anim_file(MovieClip *clip)
{
char str[FILE_MAX];
char filepath_abs[FILE_MAX];
if (!clip->anim) {
STRNCPY(str, clip->filepath);
BLI_path_abs(str, ID_BLEND_PATH_FROM_GLOBAL(&clip->id));
STRNCPY(filepath_abs, clip->filepath);
BLI_path_abs(filepath_abs, ID_BLEND_PATH_FROM_GLOBAL(&clip->id));
/* FIXME: make several stream accessible in image editor, too */
clip->anim = openanim(str, IB_rect, 0, clip->colorspace_settings.name);
clip->anim = openanim(filepath_abs, IB_rect, 0, clip->colorspace_settings.name);
if (clip->anim) {
if (clip->flag & MCLIP_USE_PROXY_CUSTOM_DIR) {
@ -968,13 +968,13 @@ MovieClip *BKE_movieclip_file_add(Main *bmain, const char *filepath)
{
MovieClip *clip;
int file;
char str[FILE_MAX];
char filepath_abs[FILE_MAX];
STRNCPY(str, filepath);
BLI_path_abs(str, BKE_main_blendfile_path(bmain));
STRNCPY(filepath_abs, filepath);
BLI_path_abs(filepath_abs, BKE_main_blendfile_path(bmain));
/* exists? */
file = BLI_open(str, O_BINARY | O_RDONLY, 0);
file = BLI_open(filepath_abs, O_BINARY | O_RDONLY, 0);
if (file == -1) {
return NULL;
}
@ -1003,17 +1003,17 @@ MovieClip *BKE_movieclip_file_add(Main *bmain, const char *filepath)
MovieClip *BKE_movieclip_file_add_exists_ex(Main *bmain, const char *filepath, bool *r_exists)
{
MovieClip *clip;
char str[FILE_MAX], strtest[FILE_MAX];
char filepath_abs[FILE_MAX], filepath_test[FILE_MAX];
STRNCPY(str, filepath);
BLI_path_abs(str, BKE_main_blendfile_path(bmain));
STRNCPY(filepath_abs, filepath);
BLI_path_abs(filepath_abs, BKE_main_blendfile_path(bmain));
/* first search an identical filepath */
for (clip = bmain->movieclips.first; clip; clip = clip->id.next) {
STRNCPY(strtest, clip->filepath);
BLI_path_abs(strtest, ID_BLEND_PATH(bmain, &clip->id));
STRNCPY(filepath_test, clip->filepath);
BLI_path_abs(filepath_test, ID_BLEND_PATH(bmain, &clip->id));
if (BLI_path_cmp(strtest, str) == 0) {
if (BLI_path_cmp(filepath_test, filepath_abs) == 0) {
id_us_plus(&clip->id); /* officially should not, it doesn't link here! */
if (r_exists) {
*r_exists = true;

View File

@ -1124,28 +1124,28 @@ static void cache_filepath(
char *filepath, const char *dirname, const char *relbase, int frame, int type)
{
char cachepath[FILE_MAX];
const char *fname;
const char *filename;
switch (type) {
case CACHE_TYPE_FOAM:
fname = "foam_";
filename = "foam_";
break;
case CACHE_TYPE_NORMAL:
fname = "normal_";
filename = "normal_";
break;
case CACHE_TYPE_SPRAY:
fname = "spray_";
filename = "spray_";
break;
case CACHE_TYPE_SPRAY_INVERSE:
fname = "spray_inverse_";
filename = "spray_inverse_";
break;
case CACHE_TYPE_DISPLACE:
default:
fname = "disp_";
filename = "disp_";
break;
}
BLI_path_join(cachepath, sizeof(cachepath), dirname, fname);
BLI_path_join(cachepath, sizeof(cachepath), dirname, filename);
BKE_image_path_from_imtype(
filepath, cachepath, relbase, frame, R_IMF_IMTYPE_OPENEXR, true, true, "");

View File

@ -2351,9 +2351,10 @@ int BKE_sculptsession_vertex_count(const SculptSession *ss)
return 0;
}
/** Returns pointer to a CustomData associated with a given domain, if
/**
* Returns pointer to a CustomData associated with a given domain, if
* one exists. If not nullptr is returned (this may happen with e.g.
* multires and ATTR_DOMAIN_POINT).
* multires and #ATTR_DOMAIN_POINT).
*/
static CustomData *sculpt_get_cdata(Object *ob, eAttrDomain domain)
{

View File

@ -1309,15 +1309,15 @@ static int ptcache_path(PTCacheID *pid, char dirname[MAX_PTCACHE_PATH])
{
const char *blendfile_path = BKE_main_blendfile_path_from_global();
Library *lib = (pid->owner_id) ? pid->owner_id->lib : NULL;
const char *blendfilename = (lib && (pid->cache->flag & PTCACHE_IGNORE_LIBPATH) == 0) ?
lib->filepath_abs :
blendfile_path;
const char *blendfile_path_lib = (lib && (pid->cache->flag & PTCACHE_IGNORE_LIBPATH) == 0) ?
lib->filepath_abs :
blendfile_path;
if (pid->cache->flag & PTCACHE_EXTERNAL) {
BLI_strncpy(dirname, pid->cache->path, MAX_PTCACHE_PATH);
if (BLI_path_is_rel(dirname)) {
BLI_path_abs(dirname, blendfilename);
BLI_path_abs(dirname, blendfile_path_lib);
}
return BLI_path_slash_ensure(dirname, MAX_PTCACHE_PATH); /* new strlen() */
@ -1325,14 +1325,14 @@ static int ptcache_path(PTCacheID *pid, char dirname[MAX_PTCACHE_PATH])
if ((blendfile_path[0] != '\0') || lib) {
char file[MAX_PTCACHE_PATH]; /* we don't want the dir, only the file */
BLI_path_split_file_part(blendfilename, file, sizeof(file));
BLI_path_split_file_part(blendfile_path_lib, file, sizeof(file));
/* Remove the `.blend` extension. */
BLI_path_extension_strip(file);
/* Add blend file name to pointcache dir. */
BLI_snprintf(dirname, MAX_PTCACHE_PATH, "//" PTCACHE_PATH "%s", file);
BLI_path_abs(dirname, blendfilename);
BLI_path_abs(dirname, blendfile_path_lib);
return BLI_path_slash_ensure(dirname, MAX_PTCACHE_PATH); /* new strlen() */
}

View File

@ -256,10 +256,10 @@ bSound *BKE_sound_new_file(Main *bmain, const char *filepath)
{
bSound *sound;
const char *blendfile_path = BKE_main_blendfile_path(bmain);
char str[FILE_MAX];
char filepath_abs[FILE_MAX];
STRNCPY(str, filepath);
BLI_path_abs(str, blendfile_path);
STRNCPY(filepath_abs, filepath);
BLI_path_abs(filepath_abs, blendfile_path);
sound = BKE_libblock_alloc(bmain, ID_SO, BLI_path_basename(filepath), 0);
STRNCPY(sound->filepath, filepath);
@ -284,17 +284,17 @@ bSound *BKE_sound_new_file(Main *bmain, const char *filepath)
bSound *BKE_sound_new_file_exists_ex(Main *bmain, const char *filepath, bool *r_exists)
{
bSound *sound;
char str[FILE_MAX], strtest[FILE_MAX];
char filepath_abs[FILE_MAX], filepath_test[FILE_MAX];
STRNCPY(str, filepath);
BLI_path_abs(str, BKE_main_blendfile_path(bmain));
STRNCPY(filepath_abs, filepath);
BLI_path_abs(filepath_abs, BKE_main_blendfile_path(bmain));
/* first search an identical filepath */
for (sound = bmain->sounds.first; sound; sound = sound->id.next) {
STRNCPY(strtest, sound->filepath);
BLI_path_abs(strtest, ID_BLEND_PATH(bmain, &sound->id));
STRNCPY(filepath_test, sound->filepath);
BLI_path_abs(filepath_test, ID_BLEND_PATH(bmain, &sound->id));
if (BLI_path_cmp(strtest, str) == 0) {
if (BLI_path_cmp(filepath_test, filepath_abs) == 0) {
id_us_plus(&sound->id); /* officially should not, it doesn't link here! */
if (r_exists) {
*r_exists = true;
@ -1258,15 +1258,15 @@ bool BKE_sound_stream_info_get(struct Main *main,
SoundStreamInfo *sound_info)
{
const char *blendfile_path = BKE_main_blendfile_path(main);
char str[FILE_MAX];
char filepath_abs[FILE_MAX];
AUD_Sound *sound;
AUD_StreamInfo *stream_infos;
int stream_count;
STRNCPY(str, filepath);
BLI_path_abs(str, blendfile_path);
STRNCPY(filepath_abs, filepath);
BLI_path_abs(filepath_abs, blendfile_path);
sound = AUD_Sound_file(str);
sound = AUD_Sound_file(filepath_abs);
if (!sound) {
return false;
}

View File

@ -366,17 +366,17 @@ VFont *BKE_vfont_load(Main *bmain, const char *filepath)
VFont *BKE_vfont_load_exists_ex(struct Main *bmain, const char *filepath, bool *r_exists)
{
VFont *vfont;
char str[FILE_MAX], strtest[FILE_MAX];
char filepath_abs[FILE_MAX], filepath_test[FILE_MAX];
STRNCPY(str, filepath);
BLI_path_abs(str, BKE_main_blendfile_path(bmain));
STRNCPY(filepath_abs, filepath);
BLI_path_abs(filepath_abs, BKE_main_blendfile_path(bmain));
/* first search an identical filepath */
for (vfont = bmain->fonts.first; vfont; vfont = vfont->id.next) {
STRNCPY(strtest, vfont->filepath);
BLI_path_abs(strtest, ID_BLEND_PATH(bmain, &vfont->id));
STRNCPY(filepath_test, vfont->filepath);
BLI_path_abs(filepath_test, ID_BLEND_PATH(bmain, &vfont->id));
if (BLI_path_cmp(strtest, str) == 0) {
if (BLI_path_cmp(filepath_test, filepath_abs) == 0) {
id_us_plus(&vfont->id); /* officially should not, it doesn't link here! */
if (r_exists) {
*r_exists = true;

View File

@ -103,7 +103,7 @@ typedef struct FFMpegContext {
static void ffmpeg_dict_set_int(AVDictionary **dict, const char *key, int value);
static void ffmpeg_filepath_get(FFMpegContext *context,
char string[FILE_MAX],
char filepath[FILE_MAX],
const struct RenderData *rd,
bool preview,
const char *suffix);
@ -1358,7 +1358,7 @@ static void flush_ffmpeg(AVCodecContext *c, AVStream *stream, AVFormatContext *o
/* Get the output filename-- similar to the other output formats */
static void ffmpeg_filepath_get(FFMpegContext *context,
char string[FILE_MAX],
char filepath[FILE_MAX],
const RenderData *rd,
bool preview,
const char *suffix)
@ -1369,7 +1369,7 @@ static void ffmpeg_filepath_get(FFMpegContext *context,
const char **fe = exts;
int sfra, efra;
if (!string || !exts) {
if (!filepath || !exts) {
return;
}
@ -1382,10 +1382,10 @@ static void ffmpeg_filepath_get(FFMpegContext *context,
efra = rd->efra;
}
BLI_strncpy(string, rd->pic, FILE_MAX);
BLI_path_abs(string, BKE_main_blendfile_path_from_global());
BLI_strncpy(filepath, rd->pic, FILE_MAX);
BLI_path_abs(filepath, BKE_main_blendfile_path_from_global());
BLI_file_ensure_parent_dir_exists(string);
BLI_file_ensure_parent_dir_exists(filepath);
autosplit[0] = '\0';
@ -1397,33 +1397,33 @@ static void ffmpeg_filepath_get(FFMpegContext *context,
if (rd->scemode & R_EXTENSION) {
while (*fe) {
if (BLI_strcasecmp(string + strlen(string) - strlen(*fe), *fe) == 0) {
if (BLI_strcasecmp(filepath + strlen(filepath) - strlen(*fe), *fe) == 0) {
break;
}
fe++;
}
if (*fe == NULL) {
BLI_strncat(string, autosplit, FILE_MAX);
BLI_strncat(filepath, autosplit, FILE_MAX);
BLI_path_frame_range(string, FILE_MAX, sfra, efra, 4);
BLI_strncat(string, *exts, FILE_MAX);
BLI_path_frame_range(filepath, FILE_MAX, sfra, efra, 4);
BLI_strncat(filepath, *exts, FILE_MAX);
}
else {
*(string + strlen(string) - strlen(*fe)) = '\0';
BLI_strncat(string, autosplit, FILE_MAX);
BLI_strncat(string, *fe, FILE_MAX);
*(filepath + strlen(filepath) - strlen(*fe)) = '\0';
BLI_strncat(filepath, autosplit, FILE_MAX);
BLI_strncat(filepath, *fe, FILE_MAX);
}
}
else {
if (BLI_path_frame_check_chars(string)) {
BLI_path_frame_range(string, FILE_MAX, sfra, efra, 4);
if (BLI_path_frame_check_chars(filepath)) {
BLI_path_frame_range(filepath, FILE_MAX, sfra, efra, 4);
}
BLI_strncat(string, autosplit, FILE_MAX);
BLI_strncat(filepath, autosplit, FILE_MAX);
}
BLI_path_suffix(string, FILE_MAX, suffix, "");
BLI_path_suffix(filepath, FILE_MAX, suffix, "");
}
void BKE_ffmpeg_filepath_get(char *filepath,

View File

@ -15,6 +15,10 @@ extern "C" {
struct bArgs;
typedef struct bArgs bArgs;
#include <stdarg.h> /* For `va_list`. */
#include "BLI_compiler_attrs.h"
/**
* Returns the number of extra arguments consumed by the function.
* - 0 is normal value,
@ -25,6 +29,12 @@ typedef int (*BA_ArgCallback)(int argc, const char **argv, void *data);
struct bArgs *BLI_args_create(int argc, const char **argv);
void BLI_args_destroy(struct bArgs *ba);
typedef void (*bArgPrintFn)(void *user_data, const char *format, va_list args);
void BLI_args_printf(struct bArgs *ba, const char *format, ...);
void BLI_args_print_fn_set(struct bArgs *ba,
ATTR_PRINTF_FORMAT(2, 0) bArgPrintFn print_fn,
void *user_data);
/** The pass to use for #BLI_args_add. */
void BLI_args_pass_set(struct bArgs *ba, int current_pass);

View File

@ -285,8 +285,9 @@ BLI_INLINE void BLI_listbase_clear(struct ListBase *lb)
lb->first = lb->last = (void *)0;
}
/** Validate the integrity of a given ListBase, returns `true` if everything is OK, false
* otherwise.
/**
* Validate the integrity of a given ListBase.
* \return true if everything is OK, false otherwise.
*/
bool BLI_listbase_validate(struct ListBase *lb);

View File

@ -113,7 +113,7 @@ MINLINE float scalenorm(float a, float b, float x);
*/
MINLINE double scalenormd(double a, double b, double x);
/* NOTE: Compilers will upcast all types smaller than int to int when performing arithmetic
/* NOTE: Compilers will up-cast all types smaller than int to int when performing arithmetic
* operation. */
MINLINE int square_s(short a);

View File

@ -97,7 +97,8 @@ typedef struct BLI_mempool_iter {
/** #BLI_mempool.flag */
enum {
BLI_MEMPOOL_NOP = 0,
/** allow iterating on this mempool.
/**
* Allow iterating on this mempool.
*
* \note this requires that the first four bytes of the elements
* never begin with 'free' (#FREEWORD).

View File

@ -4,6 +4,7 @@
#include <algorithm>
#include "BLI_index_mask.hh"
#include "BLI_index_range.hh"
#include "BLI_span.hh"
@ -137,6 +138,12 @@ template<typename T> struct GroupedSpan {
OffsetIndices<int> accumulate_counts_to_offsets(MutableSpan<int> counts_to_offsets,
int start_offset = 0);
/** Copy the number of indices in every group in the mask to the corresponding index. */
void copy_group_sizes(OffsetIndices<int> offsets, const IndexMask &mask, MutableSpan<int> sizes);
/** Gather the number of indices in each indexed group to sizes. */
void gather_group_sizes(OffsetIndices<int> offsets, const IndexMask &mask, MutableSpan<int> sizes);
/**
* Create a map from indexed elements to the source indices, in other words from the larger array
* to the smaller array.

View File

@ -42,6 +42,7 @@ bool BLI_path_name_at_index(const char *__restrict path,
bool BLI_path_is_unc(const char *path) ATTR_NONNULL(1) ATTR_WARN_UNUSED_RESULT;
bool BLI_path_is_win32_drive(const char *path);
bool BLI_path_is_win32_drive_only(const char *path);
bool BLI_path_is_win32_drive_with_slash(const char *path);
/** \} */
@ -94,7 +95,7 @@ const char *BLI_path_parent_dir_end(const char *path, size_t path_len)
* leveraged by higher layers to support "virtual filenames" which contain
* substitution markers delineated between the two characters.
*
* \return true if \a fname was changed, false otherwise.
* \return true if \a filename was changed, false otherwise.
*
* For now, simply replaces reserved chars (as listed in
* https://en.wikipedia.org/wiki/Filename#Reserved_characters_and_words )
@ -113,8 +114,8 @@ const char *BLI_path_parent_dir_end(const char *path, size_t path_len)
* \note On Windows, it also checks for forbidden names
* (see https://msdn.microsoft.com/en-us/library/windows/desktop/aa365247%28v=vs.85%29.aspx ).
*/
bool BLI_path_make_safe_filename_ex(char *fname, bool allow_tokens) ATTR_NONNULL(1);
bool BLI_path_make_safe_filename(char *fname) ATTR_NONNULL(1);
bool BLI_path_make_safe_filename_ex(char *filename, bool allow_tokens) ATTR_NONNULL(1);
bool BLI_path_make_safe_filename(char *filename) ATTR_NONNULL(1);
/**
* Make given path OS-safe.

View File

@ -66,8 +66,9 @@
namespace blender {
template<
/** Type of the elements that are stored in this set. It has to be movable. Furthermore, the
* hash and is-equal functions have to support it.
/**
* Type of the elements that are stored in this set. It has to be movable.
* Furthermore, the hash and is-equal functions have to support it.
*/
typename Key,
/**

View File

@ -95,7 +95,7 @@ bool BLI_windows_unregister_blend_extension(bool all_users);
* using a fall-back in case the root directory can't be found.
*/
void BLI_windows_get_default_root_dir(char root_dir[4]);
int BLI_windows_get_executable_dir(char *str);
int BLI_windows_get_executable_dir(char r_dirpath[/*FILE_MAXDIR*/]);
/* ShellExecute Helpers. */

View File

@ -48,6 +48,9 @@ struct bArgs {
int argc;
const char **argv;
int *passes;
/** For printing help text, defaults to `stdout`. */
bArgPrintFn print_fn;
void *print_user_data;
/* Only use when initializing arguments. */
int current_pass;
@ -96,6 +99,13 @@ static bArgument *lookUp(struct bArgs *ba, const char *arg, int pass, int case_s
return BLI_ghash_lookup(ba->items, &key);
}
/** Default print function. */
ATTR_PRINTF_FORMAT(2, 0)
static void args_print_wrapper(void *UNUSED(user_data), const char *format, va_list args)
{
vprintf(format, args);
}
bArgs *BLI_args_create(int argc, const char **argv)
{
bArgs *ba = MEM_callocN(sizeof(bArgs), "bArgs");
@ -108,6 +118,8 @@ bArgs *BLI_args_create(int argc, const char **argv)
/* Must be initialized by #BLI_args_pass_set. */
ba->current_pass = 0;
BLI_args_print_fn_set(ba, args_print_wrapper, NULL);
return ba;
}
@ -119,6 +131,20 @@ void BLI_args_destroy(struct bArgs *ba)
MEM_freeN(ba);
}
void BLI_args_printf(struct bArgs *ba, const char *format, ...)
{
va_list args;
va_start(args, format);
ba->print_fn(ba->print_user_data, format, args);
va_end(args);
}
void BLI_args_print_fn_set(struct bArgs *ba, bArgPrintFn print_fn, void *user_data)
{
ba->print_fn = print_fn;
ba->print_user_data = user_data;
}
void BLI_args_pass_set(struct bArgs *ba, int current_pass)
{
BLI_assert((current_pass != 0) && (current_pass >= -1));
@ -221,19 +247,19 @@ void BLI_args_add(struct bArgs *ba,
BLI_args_add_case(ba, short_arg, 0, long_arg, 0, doc, cb, data);
}
static void internalDocPrint(bArgDoc *d)
static void internalDocPrint(struct bArgs *ba, bArgDoc *d)
{
if (d->short_arg && d->long_arg) {
printf("%s or %s", d->short_arg, d->long_arg);
BLI_args_printf(ba, "%s or %s", d->short_arg, d->long_arg);
}
else if (d->short_arg) {
printf("%s", d->short_arg);
BLI_args_printf(ba, "%s", d->short_arg);
}
else if (d->long_arg) {
printf("%s", d->long_arg);
BLI_args_printf(ba, "%s", d->long_arg);
}
printf(" %s\n\n", d->documentation);
BLI_args_printf(ba, " %s\n\n", d->documentation);
}
void BLI_args_print_arg_doc(struct bArgs *ba, const char *arg)
@ -243,7 +269,7 @@ void BLI_args_print_arg_doc(struct bArgs *ba, const char *arg)
if (a) {
bArgDoc *d = a->doc;
internalDocPrint(d);
internalDocPrint(ba, d);
d->done = true;
}
@ -255,7 +281,7 @@ void BLI_args_print_other_doc(struct bArgs *ba)
for (d = ba->docs.first; d; d = d->next) {
if (d->done == 0) {
internalDocPrint(d);
internalDocPrint(ba, d);
}
}
}

View File

@ -302,7 +302,8 @@ static BVHNode *bvh_medianof3(BVHNode **a, int lo, int mid, int hi, int axis)
/**
* \note after a call to this function you can expect one of:
* - every node to left of a[n] are smaller or equal to it
* - every node to the right of a[n] are greater or equal to it */
* - every node to the right of a[n] are greater or equal to it.
*/
static void partition_nth_element(BVHNode **a, int begin, int end, const int n, const int axis)
{
while (end - begin > 3) {
@ -400,8 +401,9 @@ static void refit_kdop_hull(const BVHTree *tree, BVHNode *node, int start, int e
}
/**
* only supports x,y,z axis in the moment
* but we should use a plain and simple function here for speed sake */
* Only supports x,y,z axis in the moment
* but we should use a plain and simple function here for speed sake.
*/
static char get_largest_axis(const float *bv)
{
float middle_point[3];
@ -423,7 +425,8 @@ static char get_largest_axis(const float *bv)
/**
* bottom-up update of bvh node BV
* join the children on the parent BV */
* join the children on the parent BV.
*/
static void node_join(BVHTree *tree, BVHNode *node)
{
int i;

View File

@ -307,7 +307,7 @@ static bool dir_create_recursive(char *dirname, int len)
*dirname_parent_end = '\0';
#ifdef WIN32
/* Check special case `c:\foo`, don't try create `c:`, harmless but unnecessary. */
if (dirname[0] && !(isalpha(dirname[0]) && (dirname[1] == ':') && dirname[2] == '\0'))
if (dirname[0] && !BLI_path_is_win32_drive_only(dirname))
#endif
{
const int mode = BLI_exists(dirname);

View File

@ -122,10 +122,8 @@ struct SortInfo {
void *thunk;
#endif
/**
* Invariant: `ranks[i] == NULL || length(ranks[i]) >= 2**(i+1)`.
*
* ~ 128 bytes on 32bit, ~ 512 bytes on 64bit */
/* Invariant: `ranks[i] == NULL || length(ranks[i]) >= 2**(i+1)`.
* ~ 128 bytes on 32bit, ~ 512 bytes on 64bit. */
list_node *ranks[MAX_RANKS];
};

View File

@ -222,7 +222,8 @@ MatBase<T, Size, Size> pseudo_invert(const MatBase<T, Size, Size> &mat, T epsilo
using VectorT = Eigen::Matrix<T, Size, 1>;
/* Blender and Eigen matrices are both column-major by default.
* Since our matrix is squared, we can use thinU/V. */
/** WORKAROUND:
/**
* WORKAROUND:
* (ComputeThinU | ComputeThinV) must be set as runtime parameters in Eigen < 3.4.0.
* But this requires the matrix type to be dynamic to avoid an assert.
*/
@ -282,9 +283,9 @@ static void polar_decompose(const MatBase<T, 3, 3> &mat3,
using VectorT = Eigen::Matrix<T, 3, 1>;
/* Blender and Eigen matrices are both column-major by default.
* Since our matrix is squared, we can use thinU/V. */
/** WORKAROUND:
* (ComputeThinU | ComputeThinV) must be set as runtime parameters in Eigen < 3.4.0.
* But this requires the matrix type to be dynamic to avoid an assert.
/**
* WORKAROUND: (ComputeThinU | ComputeThinV) must be set as runtime parameters in
* Eigen < 3.4.0. But this requires the matrix type to be dynamic to avoid an assert.
*/
using MatrixDynamicT = Eigen::Matrix<T, Dynamic, Dynamic>;
JacobiSVD<MatrixDynamicT, NoQRPreconditioner> svd(

View File

@ -1583,7 +1583,8 @@ struct CDT_data {
Vector<bool> is_reversed;
/** Result of running CDT on input with (vert, edge, face). */
CDT_result<mpq_class> cdt_out;
/** To speed up get_cdt_edge_orig, sometimes populate this map from vertex pair to output edge.
/**
* To speed up get_cdt_edge_orig, sometimes populate this map from vertex pair to output edge.
*/
Map<std::pair<int, int>, int> verts_to_edge;
int proj_axis;

View File

@ -19,6 +19,23 @@ OffsetIndices<int> accumulate_counts_to_offsets(MutableSpan<int> counts_to_offse
return OffsetIndices<int>(counts_to_offsets);
}
void copy_group_sizes(const OffsetIndices<int> offsets,
const IndexMask &mask,
MutableSpan<int> sizes)
{
mask.foreach_index_optimized<int64_t>(GrainSize(4096),
[&](const int64_t i) { sizes[i] = offsets[i].size(); });
}
void gather_group_sizes(const OffsetIndices<int> offsets,
const IndexMask &mask,
MutableSpan<int> sizes)
{
mask.foreach_index_optimized<int64_t>(GrainSize(4096), [&](const int64_t i, const int64_t pos) {
sizes[pos] = offsets[i].size();
});
}
void build_reverse_map(OffsetIndices<int> offsets, MutableSpan<int> r_map)
{
threading::parallel_for(offsets.index_range(), 1024, [&](const IndexRange range) {

View File

@ -408,7 +408,7 @@ int BLI_path_canonicalize_native(char *path, int path_maxncpy)
return path_len;
}
bool BLI_path_make_safe_filename_ex(char *fname, bool allow_tokens)
bool BLI_path_make_safe_filename_ex(char *filename, bool allow_tokens)
{
#define INVALID_CHARS \
"\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f" \
@ -424,69 +424,69 @@ bool BLI_path_make_safe_filename_ex(char *fname, bool allow_tokens)
char *fn;
bool changed = false;
if (*fname == '\0') {
if (*filename == '\0') {
return changed;
}
for (fn = fname; *fn && (fn = strpbrk(fn, invalid)); fn++) {
for (fn = filename; *fn && (fn = strpbrk(fn, invalid)); fn++) {
*fn = '_';
changed = true;
}
/* Forbid only dots. */
for (fn = fname; *fn == '.'; fn++) {
for (fn = filename; *fn == '.'; fn++) {
/* Pass. */
}
if (*fn == '\0') {
*fname = '_';
*filename = '_';
changed = true;
}
#ifdef WIN32
{
const size_t len = strlen(fname);
const size_t len = strlen(filename);
const char *invalid_names[] = {
"con", "prn", "aux", "null", "com1", "com2", "com3", "com4",
"com5", "com6", "com7", "com8", "com9", "lpt1", "lpt2", "lpt3",
"lpt4", "lpt5", "lpt6", "lpt7", "lpt8", "lpt9", NULL,
};
char *lower_fname = BLI_strdup(fname);
char *filename_lower = BLI_strdup(filename);
const char **iname;
/* Forbid trailing dot (trailing space has already been replaced above). */
if (fname[len - 1] == '.') {
fname[len - 1] = '_';
if (filename[len - 1] == '.') {
filename[len - 1] = '_';
changed = true;
}
/* Check for forbidden names - not we have to check all combination
* of upper and lower cases, hence the usage of lower_fname
* of upper and lower cases, hence the usage of filename_lower
* (more efficient than using #BLI_strcasestr repeatedly). */
BLI_str_tolower_ascii(lower_fname, len);
BLI_str_tolower_ascii(filename_lower, len);
for (iname = invalid_names; *iname; iname++) {
if (strstr(lower_fname, *iname) == lower_fname) {
if (strstr(filename_lower, *iname) == filename_lower) {
const size_t iname_len = strlen(*iname);
/* Only invalid if the whole name is made of the invalid chunk, or it has an
* (assumed extension) dot just after. This means it will also catch *valid*
* names like `aux.foo.bar`, but should be good enough for us! */
if ((iname_len == len) || (lower_fname[iname_len] == '.')) {
*fname = '_';
if ((iname_len == len) || (filename_lower[iname_len] == '.')) {
*filename = '_';
changed = true;
break;
}
}
}
MEM_freeN(lower_fname);
MEM_freeN(filename_lower);
}
#endif
return changed;
}
bool BLI_path_make_safe_filename(char *fname)
bool BLI_path_make_safe_filename(char *filename)
{
return BLI_path_make_safe_filename_ex(fname, false);
return BLI_path_make_safe_filename_ex(filename, false);
}
bool BLI_path_make_safe(char *path)
@ -568,6 +568,11 @@ bool BLI_path_is_win32_drive(const char *path)
return isalpha(path[0]) && (path[1] == ':');
}
bool BLI_path_is_win32_drive_only(const char *path)
{
return isalpha(path[0]) && (path[1] == ':') && (path[2] == '\0');
}
bool BLI_path_is_win32_drive_with_slash(const char *path)
{
return isalpha(path[0]) && (path[1] == ':') && ELEM(path[2], '\\', '/');
@ -934,12 +939,7 @@ static bool path_frame_chars_find_range(const char *path, int *char_start, int *
*/
static void ensure_digits(char *path, int digits)
{
char *file = (char *)BLI_path_slash_rfind(path);
if (file == NULL) {
file = path;
}
char *file = (char *)BLI_path_basename(path);
if (strrchr(file, '#') == NULL) {
int len = strlen(file);

View File

@ -27,19 +27,20 @@
/* FILE_MAXDIR + FILE_MAXFILE */
int BLI_windows_get_executable_dir(char *str)
int BLI_windows_get_executable_dir(char r_dirpath[/*FILE_MAXDIR*/])
{
char dir[FILE_MAXDIR];
char filepath[FILE_MAX];
char dir[FILE_MAX];
int a;
/* Change to utf support. */
GetModuleFileName(NULL, str, FILE_MAX);
BLI_path_split_dir_part(str, dir, sizeof(dir)); /* shouldn't be relative */
GetModuleFileName(NULL, filepath, sizeof(filepath));
BLI_path_split_dir_part(filepath, dir, sizeof(dir)); /* shouldn't be relative */
a = strlen(dir);
if (dir[a - 1] == '\\') {
dir[a - 1] = 0;
}
strcpy(str, dir);
BLI_strncpy(r_dirpath, dir, FILE_MAXDIR);
return 1;
}

View File

@ -122,6 +122,33 @@ TEST(string, StrCopyUTF8_TerminateEncodingEarly)
/** \} */
/* -------------------------------------------------------------------- */
/** \name String Concatinate
* \{ */
TEST(string, StrCat)
{
#define STR_N_CAT(dst_init, dst_size, src, result_expect) \
{ \
char dst[dst_size + 1] = dst_init; \
dst[dst_size] = 0xff; \
BLI_strncat(dst, src, dst_size); \
EXPECT_STREQ(dst, result_expect); \
EXPECT_EQ(dst[dst_size], 0xff); \
}
STR_N_CAT("", 1, "", "");
STR_N_CAT("", 1, "Y", "");
STR_N_CAT("", 2, "Y", "Y");
STR_N_CAT("", 2, "YZ", "Y");
STR_N_CAT("X", 2, "YZ", "X");
STR_N_CAT("ABC", 4, "XYZ", "ABC");
STR_N_CAT("ABC", 7, "XYZ", "ABCXYZ");
#undef STR_N_CAT
}
/** \} */
/* -------------------------------------------------------------------- */
/** \name String Replace
* \{ */

View File

@ -42,7 +42,7 @@ set(SRC
intern/versioning_250.c
intern/versioning_260.c
intern/versioning_270.c
intern/versioning_280.c
intern/versioning_280.cc
intern/versioning_290.cc
intern/versioning_300.cc
intern/versioning_400.cc

View File

@ -2674,6 +2674,16 @@ static void direct_link_library(FileData *fd, Library *lib, Main *main)
{
Main *newmain;
/* Make sure we have full path in lib->filepath_abs */
/* NOTE: Since existing libraries are searched by their absolute path, this has to be generated
* before the lookup below. Otherwise, in case the stored absolute filepath is not 'correct' (may
* be empty, or have been stored in a different 'relative path context'), the comparison below
* will always fail, leading to creating duplicates IDs of a same library. */
/* TODO: May be worth checking whether comparison below could use `lib->filepath` instead? */
STRNCPY(lib->filepath_abs, lib->filepath);
BLI_path_abs(lib->filepath_abs, fd->relabase);
BLI_path_normalize(lib->filepath_abs);
/* check if the library was already read */
for (newmain = static_cast<Main *>(fd->mainlist->first); newmain; newmain = newmain->next) {
if (newmain->curlib) {
@ -2704,11 +2714,6 @@ static void direct_link_library(FileData *fd, Library *lib, Main *main)
}
}
/* Make sure we have full path in lib->filepath_abs */
STRNCPY(lib->filepath_abs, lib->filepath);
BLI_path_abs(lib->filepath_abs, fd->relabase);
BLI_path_normalize(lib->filepath_abs);
// printf("direct_link_library: filepath %s\n", lib->filepath);
// printf("direct_link_library: filepath_abs %s\n", lib->filepath_abs);

View File

@ -631,10 +631,11 @@ static bool seq_sound_proxy_update_cb(Sequence *seq, void *user_data)
{
Main *bmain = (Main *)user_data;
if (seq->type == SEQ_TYPE_SOUND_HD) {
char str[FILE_MAX];
BLI_path_join(str, sizeof(str), seq->strip->dirpath, seq->strip->stripdata->filename);
BLI_path_abs(str, BKE_main_blendfile_path(bmain));
seq->sound = BKE_sound_new_file(bmain, str);
char filepath_abs[FILE_MAX];
BLI_path_join(
filepath_abs, sizeof(filepath_abs), seq->strip->dirpath, seq->strip->stripdata->filename);
BLI_path_abs(filepath_abs, BKE_main_blendfile_path(bmain));
seq->sound = BKE_sound_new_file(bmain, filepath_abs);
}
#define SEQ_USE_PROXY_CUSTOM_DIR (1 << 19)
#define SEQ_USE_PROXY_CUSTOM_FILE (1 << 21)

View File

@ -841,7 +841,7 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *bmain)
if (bmain->versionfile <= 223) {
VFont *vf;
for (vf = bmain->fonts.first; vf; vf = vf->id.next) {
if (STREQ(vf->filepath + strlen(vf->filepath) - 6, ".Bfont")) {
if (BLI_str_endswith(vf->filepath, ".Bfont")) {
strcpy(vf->filepath, FO_BUILTIN_NAME);
}
}

View File

@ -476,9 +476,7 @@ enum {
BM_ELEM_SELECT = (1 << 0),
BM_ELEM_HIDDEN = (1 << 1),
BM_ELEM_SEAM = (1 << 2),
/**
* used for faces and edges, note from the user POV,
* this is a sharp edge when disabled */
/** Used for faces and edges, note from the user POV, this is a sharp edge when disabled. */
BM_ELEM_SMOOTH = (1 << 3),
/**
* Internal flag, used for ensuring correct normals
@ -652,14 +650,15 @@ typedef bool (*BMLoopPairFilterFunc)(const BMLoop *, const BMLoop *, void *user_
(((&e->v1_disk_link)[v == e->v2]).prev))
/**
* size to use for stack arrays when dealing with NGons,
* alloc after this limit is reached.
* this value is rather arbitrary */
* Size to use for stack arrays when dealing with NGons, allocate after this limit is reached.
* this value is rather arbitrary.
*/
#define BM_DEFAULT_NGON_STACK_SIZE 32
/**
* size to use for stack arrays dealing with connected mesh data
* Size to use for stack arrays dealing with connected mesh data
* verts of faces, edges of vert - etc.
* often used with #BM_iter_as_arrayN() */
* often used with #BM_iter_as_arrayN().
*/
#define BM_DEFAULT_ITER_STACK_SIZE 16
/* avoid inf loop, this value is arbitrary

View File

@ -197,7 +197,8 @@ const float *BM_log_original_vert_co(BMLog *log, BMVert *v);
*/
const float *BM_log_original_vert_no(BMLog *log, BMVert *v);
/** Get the logged mask of a vertex
/**
* Get the logged mask of a vertex
*
* Does not modify the log or the vertex.
*/

View File

@ -30,9 +30,8 @@ static void bm_rotate_edges_simple(BMesh *bm,
BMEdge *e;
BMO_ITER (e, &siter, op->slots_in, "edges", BM_EDGE) {
/**
* this ends up being called twice, could add option to not to call check in
* #BM_edge_rotate to get some extra speed */
/* This ends up being called twice, could add option to not to call check in
* #BM_edge_rotate to get some extra speed. */
if (BM_edge_rotate_check(e)) {
BMEdge *e_rotate = BM_edge_rotate(bm, e, use_ccw, check_flag);
if (e_rotate != NULL) {

View File

@ -29,7 +29,8 @@ void BM_mesh_decimate_collapse(BMesh *bm,
float symmetry_eps);
/**
* \param tag_only: so we can call this from an operator */
* \param tag_only: so we can call this from an operator.
*/
void BM_mesh_decimate_unsubdivide_ex(BMesh *bm, int iterations, bool tag_only);
void BM_mesh_decimate_unsubdivide(BMesh *bm, int iterations);

View File

@ -72,7 +72,8 @@ class NodeOperationInput {
private:
NodeOperation *operation_;
/** Datatype of this socket. Is used for automatically data transformation.
/**
* Datatype of this socket. Is used for automatically data transformation.
* \section data-conversion
*/
DataType datatype_;
@ -135,7 +136,8 @@ class NodeOperationOutput {
private:
NodeOperation *operation_;
/** Datatype of this socket. Is used for automatically data transformation.
/**
* Datatype of this socket. Is used for automatically data transformation.
* \section data-conversion
*/
DataType datatype_;

View File

@ -63,9 +63,9 @@ class NodeOperationBuilder {
Node *current_node_;
/** Operation that will be writing to the viewer image
* Only one operation can occupy this place at a time,
* to avoid race conditions
/**
* Operation that will be writing to the viewer image
* Only one operation can occupy this place at a time, to avoid race conditions.
*/
ViewerOperation *active_viewer_;

View File

@ -24,7 +24,8 @@ class ChannelMatteOperation : public MultiThreadedOperation {
float limit_range_;
/** ids to use for the operations (max and simple)
/**
* ids to use for the operations (max and simple)
* alpha = in[ids[0]] - MAX2(in[ids[1]], in[ids[2]])
* the simple operation is using:
* alpha = in[ids[0]] - in[ids[1]]

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