Initial Grease Pencil 3.0 stage #106848
|
@ -104,9 +104,9 @@
|
|||
* merged in docs.
|
||||
*/
|
||||
|
||||
/**
|
||||
* \defgroup gui GUI
|
||||
* \ingroup blender */
|
||||
/** \defgroup gui GUI
|
||||
* \ingroup blender
|
||||
*/
|
||||
|
||||
/** \defgroup wm Window Manager
|
||||
* \ingroup gui */
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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)
|
|
@ -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):
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
@ -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}")
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
Bioware’s 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
|
@ -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
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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__
|
||||
|
|
|
@ -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 :
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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];
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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. */
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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.
|
||||
*
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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) \
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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])
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)) {
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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];
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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, "");
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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() */
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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).
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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,
|
||||
/**
|
||||
|
|
|
@ -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. */
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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];
|
||||
};
|
||||
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
* \{ */
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
*/
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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_;
|
||||
|
|
|
@ -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_;
|
||||
|
||||
|
|
|
@ -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
Loading…
Reference in New Issue