Geometry Nodes: Rewrite mesh delete geometry node #108435

Merged
Hans Goudey merged 24 commits from HooglyBoogly/blender:delete-mesh-rewrite into main 2023-06-01 14:55:27 +02:00
388 changed files with 14291 additions and 7067 deletions
Showing only changes of commit 1986befeee - Show all commits

View File

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

View File

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

View File

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

View File

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

View File

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

File diff suppressed because it is too large Load Diff

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

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

View File

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

View File

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

View File

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

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

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

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

View File

@ -9,4 +9,13 @@
#define VMA_IMPLEMENTATION
/*
* Disabling internal asserts of VMA.
*
* Blender can destroy logical device before all the resources are freed. This is because static
* resources are freed as a last step during quiting. As long as Vulkan isn't feature complete
* we don't want to change this behavior. So for now we just disable the asserts.
*/
#define VMA_ASSERT(test)
#include "vk_mem_alloc.h"

View File

@ -345,7 +345,9 @@ string MetalDevice::preprocess_source(MetalPipelineType pso_type,
case METAL_GPU_APPLE:
global_defines += "#define __KERNEL_METAL_APPLE__\n";
# ifdef WITH_NANOVDB
global_defines += "#define WITH_NANOVDB\n";
if (DebugFlags().metal.use_nanovdb) {
global_defines += "#define WITH_NANOVDB\n";
}
# endif
break;
}

View File

@ -681,7 +681,7 @@ void MetalKernelPipeline::compile()
__block bool compilation_finished = false;
__block string error_str;
if (loading_existing_archive) {
if (loading_existing_archive || !DebugFlags().metal.use_async_pso_creation) {
/* Use the blocking variant of newComputePipelineStateWithDescriptor if an archive exists on
* disk. It should load almost instantaneously, and will fail gracefully when loading a
* corrupt archive (unlike the async variant). */
@ -694,29 +694,6 @@ void MetalKernelPipeline::compile()
error_str = err ? err : "nil";
}
else {
/* TODO / MetalRT workaround:
* Workaround for a crash when addComputePipelineFunctionsWithDescriptor is called *after*
* newComputePipelineStateWithDescriptor with linked functions (i.e. with MetalRT enabled).
* Ideally we would like to call newComputePipelineStateWithDescriptor (async) first so we
* can bail out if needed, but we can stop the crash by flipping the order when there are
* linked functions. However when addComputePipelineFunctionsWithDescriptor is called first
* it will block while it builds the pipeline, offering no way of bailing out. */
auto addComputePipelineFunctionsWithDescriptor = [&]() {
if (creating_new_archive && ShaderCache::running) {
NSError *error;
if (![archive addComputePipelineFunctionsWithDescriptor:computePipelineStateDescriptor
error:&error])
{
NSString *errStr = [error localizedDescription];
metal_printf("Failed to add PSO to archive:\n%s\n",
errStr ? [errStr UTF8String] : "nil");
}
}
};
if (linked_functions) {
addComputePipelineFunctionsWithDescriptor();
}
/* Use the async variant of newComputePipelineStateWithDescriptor if no archive exists on
* disk. This allows us to respond to app shutdown. */
[mtlDevice
@ -744,10 +721,16 @@ void MetalKernelPipeline::compile()
while (ShaderCache::running && !compilation_finished) {
std::this_thread::sleep_for(std::chrono::milliseconds(5));
}
}
/* Add pipeline into the new archive (unless we did it earlier). */
if (pipeline && !linked_functions) {
addComputePipelineFunctionsWithDescriptor();
if (creating_new_archive && pipeline) {
/* Add pipeline into the new archive. */
NSError *error;
if (![archive addComputePipelineFunctionsWithDescriptor:computePipelineStateDescriptor
error:&error])
{
NSString *errStr = [error localizedDescription];
metal_printf("Failed to add PSO to archive:\n%s\n", errStr ? [errStr UTF8String] : "nil");
}
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -218,7 +218,7 @@ ccl_device void shadow_linking_shade(KernelGlobals kg,
/* Branch off shadow kernel. */
IntegratorShadowState shadow_state = integrate_direct_light_shadow_init_common(
kg, state, &ray, bsdf_spectrum, 0, light_group);
kg, state, &ray, bsdf_spectrum, light_group, 0);
/* The light is accumulated from the shade_surface kernel, which will make the clamping decision
* based on the actual value of the bounce. For the dedicated shadow ray we want to follow the

View File

@ -221,8 +221,8 @@ 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. */
INTEGRATOR_STATE_WRITE(shadow_state, shadow_path, lightgroup) = light_group;
/* 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 + 1;
#ifdef __PATH_GUIDING__
INTEGRATOR_STATE_WRITE(shadow_state, shadow_path, unlit_throughput) = unlit_throughput;
@ -351,7 +351,7 @@ ccl_device_forceinline void integrate_surface_direct_light(KernelGlobals kg,
const int light_group = ls.type != LIGHT_BACKGROUND ? ls.group :
kernel_data.background.lightgroup;
IntegratorShadowState shadow_state = integrate_direct_light_shadow_init_common(
kg, state, &ray, bsdf_eval_sum(&bsdf_eval), mnee_vertex_count, light_group);
kg, state, &ray, bsdf_eval_sum(&bsdf_eval), light_group, mnee_vertex_count);
if (is_transmission) {
#ifdef __VOLUME__

View File

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

View File

@ -509,6 +509,19 @@ ccl_device void sample_reservoir(const int current_index,
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,8 +531,10 @@ ccl_device void sample_reservoir(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 reservoir sampling, keep two reservoirs for upper and

View File

@ -703,7 +703,15 @@ static std::pair<int, LightTreeMeasure> light_tree_specialize_nodes_flatten(
}
assert(first_emitter != -1);
new_node.make_leaf(first_emitter, num_emitters);
/* Preserve the type of the node, so that the kernel can do proper decision when sampling node
* with multiple distant lights in it. */
if (node->is_leaf()) {
new_node.make_leaf(first_emitter, num_emitters);
}
else {
new_node.make_distant(first_emitter, num_emitters);
}
}
else {
assert(node->is_inner());

View File

@ -418,6 +418,11 @@ LightTreeNode *LightTree::build(Scene *scene, DeviceScene *dscene)
root_->light_link = root_->get_inner().children[left]->light_link +
root_->get_inner().children[right]->light_link;
/* Root nodes are never meant to be be shared, even if the local and distant lights are from the
* same light linking set. Attempting to sharing it will make it so the specialized tree will
* try to use the same root as the default tree. */
root_->light_link.shareable = false;
std::move(distant_lights_.begin(), distant_lights_.end(), std::back_inserter(emitters_));
return root_.get();

View File

@ -72,6 +72,12 @@ void DebugFlags::Metal::reset()
if (auto str = getenv("CYCLES_METAL_LOCAL_ATOMIC_SORT"))
use_local_atomic_sort = (atoi(str) != 0);
if (auto str = getenv("CYCLES_METAL_NANOVDB"))
use_nanovdb = (atoi(str) != 0);
if (auto str = getenv("CYCLES_METAL_ASYNC_PSO_CREATION"))
use_async_pso_creation = (atoi(str) != 0);
}
DebugFlags::OptiX::OptiX()

View File

@ -100,6 +100,12 @@ class DebugFlags {
/* Whether local atomic sorting is enabled or not. */
bool use_local_atomic_sort = true;
/* Whether nanovdb is enabled or not. */
bool use_nanovdb = true;
/* Whether async PSO creation is enabled or not. */
bool use_async_pso_creation = true;
};
/* Get instance of debug flags registry. */

View File

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

View File

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

View File

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

View File

@ -34,8 +34,8 @@
#include <Eigen/SVD>
#if !defined(__MINGW64__)
# if defined(_WIN32) || defined(__APPLE__) || defined(__FreeBSD__) || \
defined(__NetBSD__) || defined(__HAIKU__)
# if defined(_WIN32) || defined(__APPLE__) || defined(__NetBSD__) || \
defined(__HAIKU__)
inline void sincos(double x, double* sinx, double* cosx) {
*sinx = sin(x);
*cosx = cos(x);

View File

@ -127,8 +127,10 @@ def clean_name(name, *, replace="_"):
Returns a name with characters replaced that
may cause problems under various circumstances,
such as writing to a file.
All characters besides A-Z/a-z, 0-9 are replaced with "_"
or the *replace* argument if defined.
:arg name: The path name.
:type name: string or bytes
:arg replace: The replacement for non-valid characters.
@ -233,6 +235,7 @@ def display_name_to_filepath(name):
"""
Performs the reverse of display_name using literal versions of characters
which aren't supported in a filepath.
:arg name: The display name to convert.
:type name: string
:return: The file path.
@ -247,6 +250,7 @@ def display_name_from_filepath(name):
"""
Returns the path stripped of directory and extension,
ensured to be utf8 compatible.
:arg name: The file path to convert.
:type name: string
:return: The display name.
@ -262,6 +266,7 @@ def resolve_ncase(path):
"""
Resolve a case insensitive path on a case sensitive system,
returning a string with the path if found else return the original path.
:arg path: The path name to resolve.
:type path: string
:return: The resolved path.
@ -390,6 +395,7 @@ def basename(path):
Equivalent to ``os.path.basename``, but skips a "//" prefix.
Use for Windows compatibility.
:return: The base name of the given path.
:rtype: string
"""
@ -399,6 +405,7 @@ def basename(path):
def native_pathsep(path):
"""
Replace the path separator with the systems native ``os.sep``.
:arg path: The path to replace.
:type path: string
:return: The path with system native separators.

View File

@ -382,6 +382,7 @@ def load():
use_alt_click_leader=kc_prefs.use_alt_click_leader,
use_pie_click_drag=kc_prefs.use_pie_click_drag,
use_file_single_click=kc_prefs.use_file_single_click,
experimental=prefs.experimental,
use_transform_navigation=kc_prefs.use_transform_navigation,
),
)

View File

@ -95,6 +95,8 @@ class Params:
# Since this means with RMB select enabled in edit-mode for e.g.
# `Ctrl-LMB` would be caught by box-select instead of add/extrude.
"tool_maybe_tweak_event",
# Access to bpy.context.preferences.experimental
"experimental",
# Changes some transformers modal key-map items to avoid conflicts with navigation operations
"use_transform_navigation",
)
@ -124,6 +126,7 @@ class Params:
use_file_single_click=False,
v3d_tilde_action='VIEW',
v3d_alt_mmb_drag_action='RELATIVE',
experimental=None,
use_transform_navigation=False,
):
from sys import platform
@ -225,6 +228,8 @@ class Params:
self.tool_maybe_tweak_event = {"type": self.tool_mouse, "value": self.tool_maybe_tweak_value}
self.use_transform_navigation = use_transform_navigation
self.experimental = experimental
# ------------------------------------------------------------------------------
# Constants
@ -3830,18 +3835,31 @@ def km_grease_pencil_stroke_paint_draw_brush(params):
{"items": items},
)
# Draw
if params.experimental and params.experimental.use_grease_pencil_version3:
items.extend([
("grease_pencil.brush_stroke", {"type": 'LEFTMOUSE', "value": 'PRESS'},
{"properties": [("mode", 'NORMAL')]}),
("grease_pencil.brush_stroke", {"type": 'LEFTMOUSE', "value": 'PRESS', "ctrl": True},
{"properties": [("mode", 'INVERT')]}),
("grease_pencil.brush_stroke", {"type": 'LEFTMOUSE', "value": 'PRESS', "shift": True},
{"properties": [("mode", 'SMOOTH')]}),
])
else:
items.extend([
("gpencil.draw", {"type": 'LEFTMOUSE', "value": 'PRESS'},
{"properties": [("mode", 'DRAW'), ("wait_for_input", False)]}),
("gpencil.draw", {"type": 'LEFTMOUSE', "value": 'PRESS', "shift": True},
{"properties": [("mode", 'DRAW'), ("wait_for_input", False)]}),
# Draw - straight lines
("gpencil.draw", {"type": 'LEFTMOUSE', "value": 'PRESS', "alt": True},
{"properties": [("mode", 'DRAW_STRAIGHT'), ("wait_for_input", False)]}),
# Erase
("gpencil.draw", {"type": 'LEFTMOUSE', "value": 'PRESS', "ctrl": True},
{"properties": [("mode", 'ERASER'), ("wait_for_input", False)]}),
])
items.extend([
# Draw
("gpencil.draw", {"type": 'LEFTMOUSE', "value": 'PRESS'},
{"properties": [("mode", 'DRAW'), ("wait_for_input", False)]}),
("gpencil.draw", {"type": 'LEFTMOUSE', "value": 'PRESS', "shift": True},
{"properties": [("mode", 'DRAW'), ("wait_for_input", False)]}),
# Draw - straight lines
("gpencil.draw", {"type": 'LEFTMOUSE', "value": 'PRESS', "alt": True},
{"properties": [("mode", 'DRAW_STRAIGHT'), ("wait_for_input", False)]}),
# Erase
("gpencil.draw", {"type": 'LEFTMOUSE', "value": 'PRESS', "ctrl": True},
{"properties": [("mode", 'ERASER'), ("wait_for_input", False)]}),
# Constrain Guides Speedlines
# Freehand
("gpencil.draw", {"type": 'O', "value": 'PRESS'}, None),

View File

@ -500,6 +500,8 @@ class GreasePencilMaterialsPanel:
show_full_ui = (self.bl_space_type == 'PROPERTIES')
is_view3d = (self.bl_space_type == 'VIEW_3D')
is_grease_pencil_version3 = context.preferences.experimental.use_grease_pencil_version3
tool_settings = context.scene.tool_settings
gpencil_paint = tool_settings.gpencil_paint
brush = gpencil_paint.brush if gpencil_paint else None
@ -550,7 +552,7 @@ class GreasePencilMaterialsPanel:
icon_link = 'MESH_DATA' if slot.link == 'DATA' else 'OBJECT_DATA'
row.prop(slot, "link", icon=icon_link, icon_only=True)
if ob.data.use_stroke_edit_mode:
if not is_grease_pencil_version3 and ob.data.use_stroke_edit_mode:
row = layout.row(align=True)
row.operator("gpencil.stroke_change_color", text="Assign")
row.operator("gpencil.material_select", text="Select").deselect = False

View File

@ -1970,6 +1970,13 @@ class _defs_gpencil_paint:
@staticmethod
def generate_from_brushes(context):
if context and context.preferences.experimental.use_grease_pencil_version3:
return tuple([ToolDef.from_dict(dict(
idname="builtin_brush.draw",
label="Draw",
icon="brush.gpencil_draw.draw",
data_block='DRAW',
))])
return generate_from_enum_ex(
context,
idname_prefix="builtin_brush.",

View File

@ -476,7 +476,7 @@ class TOPBAR_MT_file_import(Menu):
if bpy.app.build_options.io_wavefront_obj:
self.layout.operator("wm.obj_import", text="Wavefront (.obj)")
if bpy.app.build_options.io_ply:
self.layout.operator("wm.ply_import", text="Stanford PLY (.ply) (experimental)")
self.layout.operator("wm.ply_import", text="Stanford PLY (.ply)")
if bpy.app.build_options.io_stl:
self.layout.operator("wm.stl_import", text="STL (.stl) (experimental)")
@ -506,7 +506,7 @@ class TOPBAR_MT_file_export(Menu):
if bpy.app.build_options.io_wavefront_obj:
self.layout.operator("wm.obj_export", text="Wavefront (.obj)")
if bpy.app.build_options.io_ply:
self.layout.operator("wm.ply_export", text="Stanford PLY (.ply) (experimental)")
self.layout.operator("wm.ply_export", text="Stanford PLY (.ply)")
class TOPBAR_MT_file_external_data(Menu):

View File

@ -2398,6 +2398,7 @@ class USERPREF_PT_experimental_prototypes(ExperimentalPanel, Panel):
({"property": "use_full_frame_compositor"}, ("blender/blender/issues/88150", "#88150")),
({"property": "enable_eevee_next"}, ("blender/blender/issues/93220", "#93220")),
({"property": "enable_workbench_next"}, ("blender/blender/issues/101619", "#101619")),
({"property": "use_grease_pencil_version3"}, ("blender/blender/projects/40", "Grease Pencil 3.0")),
({"property": "enable_overlay_next"}, ("blender/blender/issues/102179", "#102179")),
),
)

View File

@ -1981,7 +1981,7 @@ class VIEW3D_MT_paint_gpencil(Menu):
layout.operator("gpencil.vertex_color_brightness_contrast", text="Brightness/Contrast")
class VIEW3D_MT_select_gpencil(Menu):
class VIEW3D_MT_select_edit_gpencil(Menu):
bl_label = "Select"
def draw(self, context):
@ -5414,6 +5414,13 @@ class VIEW3D_MT_edit_gpencil_showhide(Menu):
layout.operator("gpencil.hide", text="Hide Inactive Layers").unselected = True
class VIEW3D_MT_edit_greasepencil(Menu):
bl_label = "Grease Pencil"
def draw(self, _context):
pass
class VIEW3D_MT_edit_curves(Menu):
bl_label = "Curves"
@ -8163,7 +8170,7 @@ classes = (
VIEW3D_MT_edit_lattice_context_menu,
VIEW3D_MT_select_edit_lattice,
VIEW3D_MT_select_edit_armature,
VIEW3D_MT_select_gpencil,
VIEW3D_MT_select_edit_gpencil,
VIEW3D_MT_select_paint_mask,
VIEW3D_MT_select_paint_mask_vertex,
VIEW3D_MT_edit_curves_select_more_less,
@ -8267,6 +8274,7 @@ classes = (
VIEW3D_MT_gpencil_simplify,
VIEW3D_MT_gpencil_autoweights,
VIEW3D_MT_gpencil_edit_context_menu,
VIEW3D_MT_edit_greasepencil,
VIEW3D_MT_edit_curve,
VIEW3D_MT_edit_curve_ctrlpoints,
VIEW3D_MT_edit_curve_segments,

View File

@ -32,6 +32,7 @@ set(SRC_DNA_INC
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_gpencil_legacy_types.h
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_gpencil_modifier_types.h
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_gpu_types.h
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_grease_pencil_types.h
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_image_types.h
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_ipo_types.h
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_key_types.h

View File

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

View File

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

View File

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

View File

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

View File

@ -261,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, PropertyRNA **r_prop, int *r_index, 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);
@ -273,7 +278,8 @@ 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)'.
* 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.

View File

@ -140,7 +140,6 @@ enum {
* from \a ob_src, to get (as much as possible) exact copy of source data layout.
*/
void BKE_object_data_transfer_layout(struct Depsgraph *depsgraph,
struct Scene *scene,
struct Object *ob_src,
struct Object *ob_dst,
int data_types,
@ -149,7 +148,6 @@ void BKE_object_data_transfer_layout(struct Depsgraph *depsgraph,
const int tolayers_select[DT_MULTILAYER_INDEX_MAX]);
bool BKE_object_data_transfer_mesh(struct Depsgraph *depsgraph,
struct Scene *scene,
struct Object *ob_src,
struct Object *ob_dst,
int data_types,
@ -171,7 +169,6 @@ bool BKE_object_data_transfer_mesh(struct Depsgraph *depsgraph,
bool invert_vgroup,
struct ReportList *reports);
bool BKE_object_data_transfer_ex(struct Depsgraph *depsgraph,
struct Scene *scene,
struct Object *ob_src,
struct Object *ob_dst,
struct Mesh *me_dst,

View File

@ -0,0 +1,29 @@
/* SPDX-License-Identifier: GPL-2.0-or-later
* Copyright 2023 Blender Foundation. */
#pragma once
#include "DNA_grease_pencil_types.h"
/** \file
* \ingroup bke
* \brief Low-level operations for grease pencil that cannot be defined in the C++ header yet.
*/
#ifdef __cplusplus
extern "C" {
#endif
enum {
BKE_GREASEPENCIL_BATCH_DIRTY_ALL = 0,
};
extern void (*BKE_grease_pencil_batch_cache_dirty_tag_cb)(GreasePencil *grease_pencil, int mode);
extern void (*BKE_grease_pencil_batch_cache_free_cb)(GreasePencil *grease_pencil);
void BKE_grease_pencil_batch_cache_dirty_tag(GreasePencil *grease_pencil, int mode);
void BKE_grease_pencil_batch_cache_free(GreasePencil *grease_pencil);
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,381 @@
/* SPDX-License-Identifier: GPL-2.0-or-later
* Copyright 2023 Blender Foundation. */
#pragma once
/** \file
* \ingroup bke
* \brief Low-level operations for grease pencil.
*/
#include "BLI_function_ref.hh"
#include "BLI_map.hh"
#include "BLI_math_vector_types.hh"
#include "BLI_shared_cache.hh"
#include "BLI_utility_mixins.hh"
#include "DNA_gpencil_legacy_types.h"
#include "DNA_grease_pencil_types.h"
namespace blender::bke {
namespace greasepencil {
/**
* A single point for a stroke that is currently being drawn.
*/
struct StrokePoint {
float3 position;
float radius;
float opacity;
float4 color;
};
/**
* Stroke cache for a stroke that is currently being drawn.
*/
struct StrokeCache {
Vector<StrokePoint> points;
Vector<uint3> triangles;
int mat = 0;
void clear()
{
this->points.clear_and_shrink();
this->triangles.clear_and_shrink();
this->mat = 0;
}
};
class DrawingRuntime {
public:
/**
* Triangle cache for all the strokes in the drawing.
*/
mutable SharedCache<Vector<uint3>> triangles_cache;
StrokeCache stroke_cache;
};
class LayerGroup;
class Layer;
/**
* A TreeNode represents one node in the layer tree.
* It can either be a layer or a group. The node has zero children if it is a layer or zero or
more
* children if it is a group.
*/
class TreeNode : public ::GreasePencilLayerTreeNode {
public:
TreeNode();
explicit TreeNode(GreasePencilLayerTreeNodeType type);
explicit TreeNode(GreasePencilLayerTreeNodeType type, StringRefNull name);
TreeNode(const TreeNode &other);
public:
/**
* \returns true if this node is a LayerGroup.
*/
bool is_group() const
{
return this->type == GP_LAYER_TREE_GROUP;
}
/**
* \returns true if this node is a Layer.
*/
bool is_layer() const
{
return this->type == GP_LAYER_TREE_LEAF;
}
/**
* \returns this tree node as a LayerGroup.
* \note This results in undefined behavior if the node is not a LayerGroup.
*/
const LayerGroup &as_group() const;
/**
* \returns this tree node as a Layer.
* \note This results in undefined behavior if the node is not a Layer.
*/
const Layer &as_layer() const;
/**
* \returns this tree node as a mutable LayerGroup.
* \note This results in undefined behavior if the node is not a LayerGroup.
*/
LayerGroup &as_group_for_write();
/**
* \returns this tree node as a mutable Layer.
* \note This results in undefined behavior if the node is not a Layer.
*/
Layer &as_layer_for_write();
};
/**
* A layer mask stores a reference to a layer that will mask other layers.
*/
class LayerMask : public ::GreasePencilLayerMask {
public:
LayerMask();
explicit LayerMask(StringRefNull name);
LayerMask(const LayerMask &other);
~LayerMask();
};
class LayerRuntime {
public:
/**
* This Map maps a scene frame number (key) to a GreasePencilFrame. This struct holds an index
* (drawing_index) to the drawing in the GreasePencil->drawings array. The frame number indicates
* the first frame the drawing is shown. The end time is implicitly defined by the next greater
* frame number (key) in the map. If the value mapped to (index) is -1, no drawing is shown at
* this frame.
*
* \example:
*
* {0: 0, 5: 1, 10: -1, 12: 2, 16: -1}
*
* In this example there are three drawings (drawing #0, drawing #1 and drawing #2). The first
* drawing starts at frame 0 and ends at frame 5 (exclusive). The second drawing starts at
* frame 5 and ends at frame 10. Finally, the third drawing starts at frame 12 and ends at
* frame 16.
*
* | | | | | | | | | | |1|1|1|1|1|1|1|
* Scene Frame: |0|1|2|3|4|5|6|7|8|9|0|1|2|3|4|5|6|...
* Drawing: [#0 ][#1 ] [#2 ]
*
* \note If a drawing references another data-block, all of the drawings in that data-block are
* mapped sequentially to the frames (frame-by-frame). If another frame starts, the rest of the
* referenced drawings are discarded. If the frame is longer than the number of referenced
* drawings, then the last referenced drawing is held for the rest of the duration.
*/
Map<int, GreasePencilFrame> frames_;
/**
* Caches a sorted vector of the keys of `frames_`.
*/
mutable SharedCache<Vector<int>> sorted_keys_cache_;
/**
* A vector of LayerMask. This layer will be masked by the layers referenced in the masks.
* A layer can have zero or more layer masks.
*/
Vector<LayerMask> masks_;
};
/**
* A layer maps drawings to scene frames. It can be thought of as one independent channel in the
* timeline.
*/
class Layer : public ::GreasePencilLayer {
public:
Layer();
explicit Layer(StringRefNull name);
Layer(const Layer &other);
~Layer();
StringRefNull name() const
{
return this->base.name;
}
/**
* \returns the frames mapping.
*/
const Map<int, GreasePencilFrame> &frames() const;
Map<int, GreasePencilFrame> &frames_for_write();
bool is_visible() const;
bool is_locked() const;
/**
* Inserts the frame into the layer. Fails if there exists a frame at \a frame_number already.
* \returns true on success.
*/
bool insert_frame(int frame_number, const GreasePencilFrame &frame);
bool insert_frame(int frame_number, GreasePencilFrame &&frame);
/**
* Inserts the frame into the layer. If there exists a frame at \a frame_number already, it is
* overwritten.
* \returns true on success.
*/
bool overwrite_frame(int frame_number, const GreasePencilFrame &frame);
bool overwrite_frame(int frame_number, GreasePencilFrame &&frame);
/**
* Returns the sorted (start) frame numbers of the frames of this layer.
* \note This will cache the keys lazily.
*/
Span<int> sorted_keys() const;
/**
* \returns the index of the drawing at frame \a frame or -1 if there is no drawing.
*/
int drawing_index_at(const int frame) const;
void tag_frames_map_changed();
/**
* Should be called whenever the keys in the frames map have changed. E.g. when new keys were
* added, removed or updated.
*/
void tag_frames_map_keys_changed();
};
class LayerGroupRuntime {
public:
/**
* CacheMutex for `nodes_cache_` and `layer_cache_`;
*/
mutable CacheMutex nodes_cache_mutex_;
/**
* Caches all the nodes of this group in a single pre-ordered vector.
*/
mutable Vector<TreeNode *> nodes_cache_;
/**
* Caches all the layers in this group in a single pre-ordered vector.
*/
mutable Vector<Layer *> layer_cache_;
};
/**
* A LayerGroup is a grouping of zero or more Layers.
*/
class LayerGroup : public ::GreasePencilLayerTreeGroup {
public:
LayerGroup();
explicit LayerGroup(StringRefNull name);
LayerGroup(const LayerGroup &other);
~LayerGroup();
public:
/**
* Adds a group at the end of this group.
*/
LayerGroup &add_group(LayerGroup *group);
LayerGroup &add_group(StringRefNull name);
/**
* Adds a layer at the end of this group and returns it.
*/
Layer &add_layer(Layer *layer);
Layer &add_layer(StringRefNull name);
/**
* Returns the number of direct nodes in this group.
*/
int64_t num_direct_nodes() const;
/**
* Returns the total number of nodes in this group.
*/
int64_t num_nodes_total() const;
/**
* Removes a child from the group by index. Does not free the memory.
* \note: Assumes the removed child is not the active layer.
*/
void remove_child(int64_t index);
/**
* Returns a `Span` of pointers to all the `TreeNode`s in this group.
*/
Span<const TreeNode *> nodes() const;
Span<TreeNode *> nodes_for_write();
/**
* Returns a `Span` of pointers to all the `Layer`s in this group.
*/
Span<const Layer *> layers() const;
Span<Layer *> layers_for_write();
/**
* Returns a pointer to the layer with \a name. If no such layer was found, returns nullptr.
*/
const Layer *find_layer_by_name(StringRefNull name) const;
Layer *find_layer_by_name(StringRefNull name);
/**
* Print the nodes. For debugging purposes.
*/
void print_nodes(StringRefNull header) const;
private:
void ensure_nodes_cache() const;
void tag_nodes_cache_dirty() const;
};
namespace convert {
void legacy_gpencil_frame_to_grease_pencil_drawing(const bGPDframe &gpf,
GreasePencilDrawing &r_drawing);
void legacy_gpencil_to_grease_pencil(Main &main, GreasePencil &grease_pencil, bGPdata &gpd);
} // namespace convert
} // namespace greasepencil
class GreasePencilRuntime {
public:
/**
* Allocated and freed by the drawing code. See `DRW_grease_pencil_batch_cache_*` functions.
*/
void *batch_cache = nullptr;
public:
GreasePencilRuntime() {}
~GreasePencilRuntime() {}
};
} // namespace blender::bke
inline blender::bke::greasepencil::TreeNode &GreasePencilLayerTreeNode::wrap()
{
return *reinterpret_cast<blender::bke::greasepencil::TreeNode *>(this);
}
inline const blender::bke::greasepencil::TreeNode &GreasePencilLayerTreeNode::wrap() const
{
return *reinterpret_cast<const blender::bke::greasepencil::TreeNode *>(this);
}
inline blender::bke::greasepencil::Layer &GreasePencilLayer::wrap()
{
return *reinterpret_cast<blender::bke::greasepencil::Layer *>(this);
}
inline const blender::bke::greasepencil::Layer &GreasePencilLayer::wrap() const
{
return *reinterpret_cast<const blender::bke::greasepencil::Layer *>(this);
}
inline blender::bke::greasepencil::LayerGroup &GreasePencilLayerTreeGroup::wrap()
{
return *reinterpret_cast<blender::bke::greasepencil::LayerGroup *>(this);
}
inline const blender::bke::greasepencil::LayerGroup &GreasePencilLayerTreeGroup::wrap() const
{
return *reinterpret_cast<const blender::bke::greasepencil::LayerGroup *>(this);
}
inline bool GreasePencil::has_active_layer() const
{
return (this->active_layer != nullptr);
}
struct Main;
struct Depsgraph;
struct BoundBox;
struct Scene;
struct Object;
void *BKE_grease_pencil_add(Main *bmain, const char *name);
GreasePencil *BKE_grease_pencil_new_nomain();
BoundBox *BKE_grease_pencil_boundbox_get(Object *ob);
void BKE_grease_pencil_data_update(struct Depsgraph *depsgraph,
struct Scene *scene,
struct Object *object);
bool BKE_grease_pencil_references_cyclic_check(const GreasePencil *id_reference,
const GreasePencil *grease_pencil);

View File

@ -273,6 +273,7 @@ extern IDTypeInfo IDType_ID_CV;
extern IDTypeInfo IDType_ID_PT;
extern IDTypeInfo IDType_ID_VO;
extern IDTypeInfo IDType_ID_SIM;
extern IDTypeInfo IDType_ID_GP;
/** Empty shell mostly, but needed for read code. */
extern IDTypeInfo IDType_ID_LINK_PLACEHOLDER;

View File

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

View File

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

View File

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

View File

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

View File

@ -211,6 +211,7 @@ typedef struct Main {
ListBase paintcurves;
ListBase wm; /* Singleton (exception). */
ListBase gpencils; /* Legacy Grease Pencil. */
ListBase grease_pencils;
ListBase movieclips;
ListBase masks;
ListBase linestyles;

View File

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

View File

@ -51,7 +51,9 @@ void BKE_mesh_foreach_mapped_subdiv_face_center(
void *userData,
MeshForeachFlag flag);
void BKE_mesh_foreach_mapped_vert_coords_get(struct Mesh *me_eval, float (*r_cos)[3], int totcos);
void BKE_mesh_foreach_mapped_vert_coords_get(const struct Mesh *me_eval,
float (*r_cos)[3],
int totcos);
#ifdef __cplusplus
}

View File

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

View File

@ -77,11 +77,6 @@ eMeshWrapperType BKE_mesh_wrapper_type(const struct Mesh *mesh);
* They should also be renamed to use conventions from BKE, not old DerivedMesh.cc.
* For now keep the names similar to avoid confusion. */
struct Mesh *mesh_get_eval_final(struct Depsgraph *depsgraph,
const struct Scene *scene,
struct Object *ob,
const struct CustomData_MeshMasks *dataMask);
struct Mesh *mesh_get_eval_deform(struct Depsgraph *depsgraph,
const struct Scene *scene,
struct Object *ob,

View File

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

View File

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

View File

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

View File

@ -149,6 +149,8 @@ set(SRC
intern/gpencil_legacy.c
intern/gpencil_modifier_legacy.c
intern/gpencil_update_cache_legacy.c
intern/grease_pencil_convert_legacy.cc
intern/grease_pencil.cc
intern/icons.cc
intern/icons_rasterize.c
intern/idprop.c
@ -393,6 +395,8 @@ set(SRC
BKE_gpencil_legacy.h
BKE_gpencil_modifier_legacy.h
BKE_gpencil_update_cache_legacy.h
BKE_grease_pencil.h
BKE_grease_pencil.hh
BKE_icons.h
BKE_idprop.h
BKE_idprop.hh
@ -836,6 +840,7 @@ if(WITH_GTESTS)
intern/lib_remap_test.cc
intern/nla_test.cc
intern/tracking_test.cc
intern/grease_pencil_test.cc
)
set(TEST_INC
../editors/include

View File

@ -632,12 +632,10 @@ static void mesh_calc_modifiers(struct Depsgraph *depsgraph,
const bool sculpt_dyntopo = (sculpt_mode && ob->sculpt->bm) && !use_render;
/* Modifier evaluation contexts for different types of modifiers. */
ModifierApplyFlag apply_render = use_render ? MOD_APPLY_RENDER : (ModifierApplyFlag)0;
ModifierApplyFlag apply_cache = use_cache ? MOD_APPLY_USECACHE : (ModifierApplyFlag)0;
const ModifierEvalContext mectx = {
depsgraph, ob, (ModifierApplyFlag)(apply_render | apply_cache)};
const ModifierEvalContext mectx_orco = {
depsgraph, ob, (ModifierApplyFlag)(apply_render | MOD_APPLY_ORCO)};
ModifierApplyFlag apply_render = use_render ? MOD_APPLY_RENDER : ModifierApplyFlag(0);
ModifierApplyFlag apply_cache = use_cache ? MOD_APPLY_USECACHE : ModifierApplyFlag(0);
const ModifierEvalContext mectx = {depsgraph, ob, apply_render | apply_cache};
const ModifierEvalContext mectx_orco = {depsgraph, ob, apply_render | MOD_APPLY_ORCO};
/* Get effective list of modifiers to execute. Some effects like shape keys
* are added as virtual modifiers before the user created modifiers. */
@ -1166,9 +1164,8 @@ static void editbmesh_calc_modifiers(struct Depsgraph *depsgraph,
const bool use_render = (DEG_get_mode(depsgraph) == DAG_EVAL_RENDER);
/* Modifier evaluation contexts for different types of modifiers. */
ModifierApplyFlag apply_render = use_render ? MOD_APPLY_RENDER : (ModifierApplyFlag)0;
const ModifierEvalContext mectx = {
depsgraph, ob, (ModifierApplyFlag)(MOD_APPLY_USECACHE | apply_render)};
ModifierApplyFlag apply_render = use_render ? MOD_APPLY_RENDER : ModifierApplyFlag(0);
const ModifierEvalContext mectx = {depsgraph, ob, MOD_APPLY_USECACHE | apply_render};
const ModifierEvalContext mectx_orco = {depsgraph, ob, MOD_APPLY_ORCO};
/* Get effective list of modifiers to execute. Some effects like shape keys
@ -1645,40 +1642,6 @@ void makeDerivedMesh(struct Depsgraph *depsgraph,
/***/
Mesh *mesh_get_eval_final(struct Depsgraph *depsgraph,
const Scene *scene,
Object *ob,
const CustomData_MeshMasks *dataMask)
{
/* This function isn't thread-safe and can't be used during evaluation. */
BLI_assert(DEG_is_evaluating(depsgraph) == false);
/* Evaluated meshes aren't supposed to be created on original instances. If you do,
* they aren't cleaned up properly on mode switch, causing crashes, e.g #58150. */
BLI_assert(ob->id.tag & LIB_TAG_COPIED_ON_WRITE);
/* if there's no evaluated mesh or the last data mask used doesn't include
* the data we need, rebuild the derived mesh
*/
bool need_mapping;
CustomData_MeshMasks cddata_masks = *dataMask;
object_get_datamask(depsgraph, ob, &cddata_masks, &need_mapping);
Mesh *mesh_eval = BKE_object_get_evaluated_mesh(ob);
if ((mesh_eval == nullptr) ||
!CustomData_MeshMasks_are_matching(&(ob->runtime.last_data_mask), &cddata_masks) ||
(need_mapping && !ob->runtime.last_need_mapping))
{
CustomData_MeshMasks_update(&cddata_masks, &ob->runtime.last_data_mask);
makeDerivedMesh(depsgraph, scene, ob, dataMask);
mesh_eval = BKE_object_get_evaluated_mesh(ob);
}
return mesh_eval;
}
Mesh *mesh_get_eval_deform(struct Depsgraph *depsgraph,
const Scene *scene,
Object *ob,

View File

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

View File

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

View File

@ -749,12 +749,10 @@ UserDef *BKE_blendfile_userdef_from_defaults(void)
const char *addons[] = {
"io_anim_bvh",
"io_curve_svg",
"io_mesh_ply",
"io_mesh_stl",
"io_mesh_uv_layout",
"io_scene_fbx",
"io_scene_gltf2",
"io_scene_obj",
"io_scene_x3d",
"cycles",
"pose_library",

View File

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

View File

@ -498,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, PropertyRNA **r_prop, int *r_index, 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);
@ -1179,6 +1184,8 @@ enum eContextObjectMode CTX_data_mode_enum_ex(const Object *obedit,
return CTX_MODE_EDIT_LATTICE;
case OB_CURVES:
return CTX_MODE_EDIT_CURVES;
case OB_GREASE_PENCIL:
return CTX_MODE_EDIT_GPENCIL;
}
}
else {

View File

@ -5,8 +5,6 @@
* \ingroup bke
*/
#include "CLG_log.h"
#include "MEM_guardedalloc.h"
#include "DNA_customdata_types.h"
@ -34,9 +32,9 @@
#include "BKE_object_deform.h"
#include "BKE_report.h"
#include "data_transfer_intern.h"
#include "DEG_depsgraph_query.h"
static CLG_LogRef LOG = {"bke.data_transfer"};
#include "data_transfer_intern.h"
void BKE_object_data_transfer_dttypes_to_cdmask(const int dtdata_types,
CustomData_MeshMasks *r_data_masks)
@ -1172,7 +1170,6 @@ static bool data_transfer_layersmapping_generate(ListBase *r_map,
}
void BKE_object_data_transfer_layout(struct Depsgraph *depsgraph,
Scene *scene,
Object *ob_src,
Object *ob_dst,
const int data_types,
@ -1180,20 +1177,17 @@ void BKE_object_data_transfer_layout(struct Depsgraph *depsgraph,
const int fromlayers_select[DT_MULTILAYER_INDEX_MAX],
const int tolayers_select[DT_MULTILAYER_INDEX_MAX])
{
Mesh *me_src;
Mesh *me_dst;
const bool use_create = true; /* We always create needed layers here. */
CustomData_MeshMasks me_src_mask = CD_MASK_BAREMESH;
BLI_assert((ob_src != ob_dst) && (ob_src->type == OB_MESH) && (ob_dst->type == OB_MESH));
me_dst = static_cast<Mesh *>(ob_dst->data);
/* Get source evaluated mesh. */
BKE_object_data_transfer_dttypes_to_cdmask(data_types, &me_src_mask);
me_src = mesh_get_eval_final(depsgraph, scene, ob_src, &me_src_mask);
const Object *ob_src_eval = DEG_get_evaluated_object(depsgraph, ob_src);
const Mesh *me_src = BKE_object_get_evaluated_mesh(ob_src_eval);
if (!me_src) {
return;
}
@ -1320,7 +1314,6 @@ void BKE_object_data_transfer_layout(struct Depsgraph *depsgraph,
}
bool BKE_object_data_transfer_ex(struct Depsgraph *depsgraph,
Scene *scene,
Object *ob_src,
Object *ob_dst,
Mesh *me_dst,
@ -1367,8 +1360,6 @@ bool BKE_object_data_transfer_ex(struct Depsgraph *depsgraph,
const bool use_delete = false; /* We never delete data layers from destination here. */
CustomData_MeshMasks me_src_mask = CD_MASK_BAREMESH;
BLI_assert((ob_src != ob_dst) && (ob_src->type == OB_MESH) && (ob_dst->type == OB_MESH));
if (me_dst) {
@ -1390,21 +1381,12 @@ bool BKE_object_data_transfer_ex(struct Depsgraph *depsgraph,
}
/* Get source evaluated mesh. */
BKE_object_data_transfer_dttypes_to_cdmask(data_types, &me_src_mask);
BKE_mesh_remap_calc_source_cddata_masks_from_map_modes(
map_vert_mode, map_edge_mode, map_loop_mode, map_poly_mode, &me_src_mask);
if (is_modifier) {
me_src = BKE_modifier_get_evaluated_mesh_from_evaluated_object(ob_src);
if (me_src == nullptr ||
!CustomData_MeshMasks_are_matching(&ob_src->runtime.last_data_mask, &me_src_mask))
{
CLOG_WARN(&LOG, "Data Transfer: source mesh data is not ready - dependency cycle?");
return changed;
}
}
else {
me_src = mesh_get_eval_final(depsgraph, scene, ob_src, &me_src_mask);
const Object *ob_eval = DEG_get_evaluated_object(depsgraph, ob_src);
me_src = BKE_object_get_evaluated_mesh(ob_eval);
}
if (!me_src) {
return changed;
@ -1827,7 +1809,6 @@ bool BKE_object_data_transfer_ex(struct Depsgraph *depsgraph,
}
bool BKE_object_data_transfer_mesh(struct Depsgraph *depsgraph,
Scene *scene,
Object *ob_src,
Object *ob_dst,
const int data_types,
@ -1850,7 +1831,6 @@ bool BKE_object_data_transfer_mesh(struct Depsgraph *depsgraph,
ReportList *reports)
{
return BKE_object_data_transfer_ex(depsgraph,
scene,
ob_src,
ob_dst,
nullptr,

View File

@ -571,7 +571,7 @@ void BKE_curve_calc_modifiers_pre(Depsgraph *depsgraph,
required_mode = (ModifierMode)(int(required_mode) | eModifierMode_Editmode);
}
ModifierApplyFlag apply_flag = (ModifierApplyFlag)0;
ModifierApplyFlag apply_flag = ModifierApplyFlag(0);
if (editmode) {
apply_flag = MOD_APPLY_USECACHE;
}
@ -695,18 +695,16 @@ static GeometrySet curve_calc_modifiers_post(Depsgraph *depsgraph,
const bool editmode = (!for_render && (cu->editnurb || cu->editfont));
const bool use_cache = !for_render;
ModifierApplyFlag apply_flag = for_render ? MOD_APPLY_RENDER : (ModifierApplyFlag)0;
ModifierApplyFlag apply_flag = for_render ? MOD_APPLY_RENDER : ModifierApplyFlag(0);
ModifierMode required_mode = for_render ? eModifierMode_Render : eModifierMode_Realtime;
if (editmode) {
required_mode = (ModifierMode)(int(required_mode) | eModifierMode_Editmode);
required_mode = ModifierMode(int(required_mode) | eModifierMode_Editmode);
}
const ModifierEvalContext mectx_deform = {
depsgraph, ob, editmode ? (ModifierApplyFlag)(apply_flag | MOD_APPLY_USECACHE) : apply_flag};
depsgraph, ob, editmode ? (apply_flag | MOD_APPLY_USECACHE) : apply_flag};
const ModifierEvalContext mectx_apply = {
depsgraph,
ob,
use_cache ? (ModifierApplyFlag)(apply_flag | MOD_APPLY_USECACHE) : apply_flag};
depsgraph, ob, use_cache ? (apply_flag | MOD_APPLY_USECACHE) : apply_flag};
ModifierData *pretessellatePoint = curve_get_tessellate_point(scene, ob, for_render, editmode);

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,262 @@
/* SPDX-License-Identifier: GPL-2.0-or-later
* Copyright 2023 Blender Foundation. */
/** \file
* \ingroup bke
*/
#include "BKE_curves.hh"
#include "BKE_grease_pencil.hh"
#include "BKE_material.h"
#include "BLI_color.hh"
#include "BLI_listbase.h"
#include "BLI_math_vector_types.hh"
#include "BLI_vector.hh"
#include "DNA_gpencil_legacy_types.h"
#include "DNA_grease_pencil_types.h"
namespace blender::bke::greasepencil::convert {
void legacy_gpencil_frame_to_grease_pencil_drawing(const bGPDframe &gpf,
GreasePencilDrawing &r_drawing)
{
/* Construct an empty CurvesGeometry in-place. */
new (&r_drawing.geometry) CurvesGeometry();
r_drawing.base.type = GP_DRAWING;
r_drawing.runtime = MEM_new<bke::greasepencil::DrawingRuntime>(__func__);
/* Get the number of points, number of strokes and the offsets for each stroke. */
Vector<int> offsets;
offsets.append(0);
int num_strokes = 0;
int num_points = 0;
LISTBASE_FOREACH (bGPDstroke *, gps, &gpf.strokes) {
num_points += gps->totpoints;
offsets.append(num_points);
num_strokes++;
}
/* Resize the CurvesGeometry. */
CurvesGeometry &curves = r_drawing.geometry.wrap();
curves.resize(num_points, num_strokes);
if (num_strokes > 0) {
curves.offsets_for_write().copy_from(offsets);
}
OffsetIndices<int> points_by_curve = curves.points_by_curve();
MutableAttributeAccessor attributes = curves.attributes_for_write();
/* All strokes are poly curves. */
curves.fill_curve_types(CURVE_TYPE_POLY);
/* Point Attributes. */
MutableSpan<float3> positions = curves.positions_for_write();
SpanAttributeWriter<float> radii = attributes.lookup_or_add_for_write_span<float>(
"radius", ATTR_DOMAIN_POINT);
SpanAttributeWriter<float> opacities = attributes.lookup_or_add_for_write_span<float>(
"opacity", ATTR_DOMAIN_POINT);
SpanAttributeWriter<float> delta_times = attributes.lookup_or_add_for_write_span<float>(
"delta_time", ATTR_DOMAIN_POINT);
SpanAttributeWriter<float> rotations = attributes.lookup_or_add_for_write_span<float>(
"rotation", ATTR_DOMAIN_POINT);
SpanAttributeWriter<ColorGeometry4f> vertex_colors =
attributes.lookup_or_add_for_write_span<ColorGeometry4f>("vertex_color", ATTR_DOMAIN_POINT);
SpanAttributeWriter<bool> selection = attributes.lookup_or_add_for_write_span<bool>(
".selection", ATTR_DOMAIN_POINT);
/* Curve Attributes. */
SpanAttributeWriter<bool> stroke_cyclic = attributes.lookup_or_add_for_write_span<bool>(
"cyclic", ATTR_DOMAIN_CURVE);
/* TODO: This should be a `double` attribute. */
SpanAttributeWriter<float> stroke_init_times = attributes.lookup_or_add_for_write_span<float>(
"init_time", ATTR_DOMAIN_CURVE);
SpanAttributeWriter<int8_t> stroke_start_caps = attributes.lookup_or_add_for_write_span<int8_t>(
"start_cap", ATTR_DOMAIN_CURVE);
SpanAttributeWriter<int8_t> stroke_end_caps = attributes.lookup_or_add_for_write_span<int8_t>(
"end_cap", ATTR_DOMAIN_CURVE);
SpanAttributeWriter<float> stroke_hardnesses = attributes.lookup_or_add_for_write_span<float>(
"hardness", ATTR_DOMAIN_CURVE);
SpanAttributeWriter<float> stroke_point_aspect_ratios =
attributes.lookup_or_add_for_write_span<float>("point_aspect_ratio", ATTR_DOMAIN_CURVE);
SpanAttributeWriter<float2> stroke_fill_translations =
attributes.lookup_or_add_for_write_span<float2>("fill_translation", ATTR_DOMAIN_CURVE);
SpanAttributeWriter<float> stroke_fill_rotations =
attributes.lookup_or_add_for_write_span<float>("fill_rotation", ATTR_DOMAIN_CURVE);
SpanAttributeWriter<float2> stroke_fill_scales = attributes.lookup_or_add_for_write_span<float2>(
"fill_scale", ATTR_DOMAIN_CURVE);
SpanAttributeWriter<ColorGeometry4f> stroke_fill_colors =
attributes.lookup_or_add_for_write_span<ColorGeometry4f>("fill_color", ATTR_DOMAIN_CURVE);
SpanAttributeWriter<int> stroke_materials = attributes.lookup_or_add_for_write_span<int>(
"material_index", ATTR_DOMAIN_CURVE);
int stroke_i = 0;
LISTBASE_FOREACH_INDEX (bGPDstroke *, gps, &gpf.strokes, stroke_i) {
/* TODO: check if gps->editcurve is not nullptr and parse bezier curve instead. */
/* Write curve attributes. */
stroke_cyclic.span[stroke_i] = (gps->flag & GP_STROKE_CYCLIC) != 0;
/* TODO: This should be a `double` attribute. */
stroke_init_times.span[stroke_i] = static_cast<float>(gps->inittime);
stroke_start_caps.span[stroke_i] = static_cast<int8_t>(gps->caps[0]);
stroke_end_caps.span[stroke_i] = static_cast<int8_t>(gps->caps[1]);
stroke_hardnesses.span[stroke_i] = gps->hardeness;
stroke_point_aspect_ratios.span[stroke_i] = gps->aspect_ratio[0] /
max_ff(gps->aspect_ratio[1], 1e-8);
stroke_fill_translations.span[stroke_i] = float2(gps->uv_translation);
stroke_fill_rotations.span[stroke_i] = gps->uv_rotation;
stroke_fill_scales.span[stroke_i] = float2(gps->uv_scale);
stroke_fill_colors.span[stroke_i] = ColorGeometry4f(gps->vert_color_fill);
stroke_materials.span[stroke_i] = gps->mat_nr;
/* Write point attributes. */
IndexRange stroke_points_range = points_by_curve[stroke_i];
if (stroke_points_range.size() == 0) {
continue;
}
Span<bGPDspoint> stroke_points{gps->points, gps->totpoints};
MutableSpan<float3> stroke_positions = positions.slice(stroke_points_range);
MutableSpan<float> stroke_radii = radii.span.slice(stroke_points_range);
MutableSpan<float> stroke_opacities = opacities.span.slice(stroke_points_range);
MutableSpan<float> stroke_deltatimes = delta_times.span.slice(stroke_points_range);
MutableSpan<float> stroke_rotations = rotations.span.slice(stroke_points_range);
MutableSpan<ColorGeometry4f> stroke_vertex_colors = vertex_colors.span.slice(
stroke_points_range);
MutableSpan<bool> stroke_selections = selection.span.slice(stroke_points_range);
/* Do first point. */
const bGPDspoint &first_pt = stroke_points.first();
stroke_positions.first() = float3(first_pt.x, first_pt.y, first_pt.z);
/* Store the actual radius of the stroke (without layer adjustment). */
stroke_radii.first() = gps->thickness * first_pt.pressure;
stroke_opacities.first() = first_pt.strength;
stroke_deltatimes.first() = 0;
stroke_rotations.first() = first_pt.uv_rot;
stroke_vertex_colors.first() = ColorGeometry4f(first_pt.vert_color);
stroke_selections.first() = (first_pt.flag & GP_SPOINT_SELECT) != 0;
/* Do the rest of the points. */
for (const int i : stroke_points.index_range().drop_back(1)) {
const int point_i = i + 1;
const bGPDspoint &pt_prev = stroke_points[point_i - 1];
const bGPDspoint &pt = stroke_points[point_i];
stroke_positions[point_i] = float3(pt.x, pt.y, pt.z);
/* Store the actual radius of the stroke (without layer adjustment). */
stroke_radii[point_i] = gps->thickness * pt.pressure;
stroke_opacities[point_i] = pt.strength;
stroke_deltatimes[point_i] = pt.time - pt_prev.time;
stroke_rotations[point_i] = pt.uv_rot;
stroke_vertex_colors[point_i] = ColorGeometry4f(pt.vert_color);
stroke_selections[point_i] = (pt.flag & GP_SPOINT_SELECT) != 0;
}
}
radii.finish();
opacities.finish();
delta_times.finish();
rotations.finish();
vertex_colors.finish();
selection.finish();
stroke_cyclic.finish();
stroke_init_times.finish();
stroke_start_caps.finish();
stroke_end_caps.finish();
stroke_hardnesses.finish();
stroke_point_aspect_ratios.finish();
stroke_fill_translations.finish();
stroke_fill_rotations.finish();
stroke_fill_scales.finish();
stroke_fill_colors.finish();
stroke_materials.finish();
}
void legacy_gpencil_to_grease_pencil(Main &bmain, GreasePencil &grease_pencil, bGPdata &gpd)
{
using namespace blender::bke::greasepencil;
int num_layers = 0;
int num_drawings = 0;
LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd.layers) {
num_drawings += BLI_listbase_count(&gpl->frames);
num_layers++;
}
grease_pencil.drawing_array_size = num_drawings;
grease_pencil.drawing_array = reinterpret_cast<GreasePencilDrawingBase **>(
MEM_cnew_array<GreasePencilDrawing *>(num_drawings, __func__));
int i = 0, layer_idx = 0;
LayerGroup &root_group = grease_pencil.root_group.wrap();
LISTBASE_FOREACH_INDEX (bGPDlayer *, gpl, &gpd.layers, layer_idx) {
/* Create a new layer. */
Layer &new_layer = grease_pencil.add_layer(
root_group, StringRefNull(gpl->info, BLI_strnlen(gpl->info, 128)));
/* Flags. */
SET_FLAG_FROM_TEST(new_layer.base.flag, (gpl->flag & GP_LAYER_HIDE), GP_LAYER_TREE_NODE_HIDE);
SET_FLAG_FROM_TEST(
new_layer.base.flag, (gpl->flag & GP_LAYER_LOCKED), GP_LAYER_TREE_NODE_LOCKED);
SET_FLAG_FROM_TEST(
new_layer.base.flag, (gpl->flag & GP_LAYER_SELECT), GP_LAYER_TREE_NODE_SELECT);
SET_FLAG_FROM_TEST(
new_layer.base.flag, (gpl->flag & GP_LAYER_FRAMELOCK), GP_LAYER_TREE_NODE_MUTE);
SET_FLAG_FROM_TEST(
new_layer.base.flag, (gpl->flag & GP_LAYER_USE_LIGHTS), GP_LAYER_TREE_NODE_USE_LIGHTS);
SET_FLAG_FROM_TEST(new_layer.base.flag,
(gpl->onion_flag & GP_LAYER_ONIONSKIN),
GP_LAYER_TREE_NODE_USE_ONION_SKINNING);
new_layer.blend_mode = static_cast<int8_t>(gpl->blend_mode);
/* Convert the layer masks. */
LISTBASE_FOREACH (bGPDlayer_Mask *, mask, &gpl->mask_layers) {
LayerMask *new_mask = new LayerMask(mask->name);
new_mask->flag = mask->flag;
BLI_addtail(&new_layer.masks, new_mask);
}
new_layer.opacity = gpl->opacity;
LISTBASE_FOREACH (bGPDframe *, gpf, &gpl->frames) {
grease_pencil.drawing_array[i] = reinterpret_cast<GreasePencilDrawingBase *>(
MEM_new<GreasePencilDrawing>(__func__));
GreasePencilDrawing &drawing = *reinterpret_cast<GreasePencilDrawing *>(
grease_pencil.drawing_array[i]);
/* Convert the frame to a drawing. */
legacy_gpencil_frame_to_grease_pencil_drawing(*gpf, drawing);
GreasePencilFrame new_frame;
new_frame.drawing_index = i;
new_frame.type = gpf->key_type;
SET_FLAG_FROM_TEST(new_frame.flag, (gpf->flag & GP_FRAME_SELECT), GP_FRAME_SELECTED);
new_layer.insert_frame(gpf->framenum, std::move(new_frame));
i++;
}
if ((gpl->flag & GP_LAYER_ACTIVE) != 0) {
grease_pencil.active_layer = static_cast<GreasePencilLayer *>(&new_layer);
}
/* TODO: Update drawing user counts. */
}
/* Convert the onion skinning settings. */
grease_pencil.onion_skinning_settings.opacity = gpd.onion_factor;
grease_pencil.onion_skinning_settings.mode = gpd.onion_mode;
if (gpd.onion_keytype == -1) {
grease_pencil.onion_skinning_settings.filter = GREASE_PENCIL_ONION_SKINNING_FILTER_ALL;
}
else {
grease_pencil.onion_skinning_settings.filter = (1 << gpd.onion_keytype);
}
grease_pencil.onion_skinning_settings.num_frames_before = gpd.gstep;
grease_pencil.onion_skinning_settings.num_frames_after = gpd.gstep_next;
copy_v3_v3(grease_pencil.onion_skinning_settings.color_before, gpd.gcolor_prev);
copy_v3_v3(grease_pencil.onion_skinning_settings.color_after, gpd.gcolor_next);
BKE_id_materials_copy(&bmain, &gpd.id, &grease_pencil.id);
}
} // namespace blender::bke::greasepencil::convert

View File

@ -0,0 +1,181 @@
/* SPDX-License-Identifier: GPL-2.0-or-later
* Copyright 2023 Blender Foundation. */
#include "testing/testing.h"
#include "BKE_curves.hh"
#include "BKE_grease_pencil.hh"
#include "BKE_idtype.h"
#include "BKE_lib_id.h"
#include "BKE_main.h"
using namespace blender::bke::greasepencil;
namespace blender::bke::greasepencil::tests {
/* --------------------------------------------------------------------------------------------- */
/* Grease Pencil ID Tests. */
/* Note: Using a struct with constructor and destructor instead of a fixture here, to have all the
* tests in the same group (`greasepencil`). */
struct GreasePencilIDTestContext {
Main *bmain = nullptr;
GreasePencilIDTestContext()
{
BKE_idtype_init();
bmain = BKE_main_new();
}
~GreasePencilIDTestContext()
{
BKE_main_free(bmain);
}
};
TEST(greasepencil, create_grease_pencil_id)
{
GreasePencilIDTestContext ctx;
GreasePencil &grease_pencil = *static_cast<GreasePencil *>(BKE_id_new(ctx.bmain, ID_GP, "GP"));
EXPECT_EQ(grease_pencil.drawings().size(), 0);
EXPECT_EQ(grease_pencil.root_group.wrap().num_nodes_total(), 0);
}
/* --------------------------------------------------------------------------------------------- */
/* Drawing Array Tests. */
TEST(greasepencil, add_empty_drawings)
{
GreasePencilIDTestContext ctx;
GreasePencil &grease_pencil = *static_cast<GreasePencil *>(BKE_id_new(ctx.bmain, ID_GP, "GP"));
grease_pencil.add_empty_drawings(3);
EXPECT_EQ(grease_pencil.drawings().size(), 3);
}
TEST(greasepencil, remove_drawing)
{
GreasePencilIDTestContext ctx;
GreasePencil &grease_pencil = *static_cast<GreasePencil *>(BKE_id_new(ctx.bmain, ID_GP, "GP"));
grease_pencil.add_empty_drawings(3);
GreasePencilDrawing *drawing = reinterpret_cast<GreasePencilDrawing *>(
grease_pencil.drawings_for_write()[1]);
drawing->geometry.wrap().resize(0, 10);
Layer &layer1 = grease_pencil.root_group.wrap().add_layer("Layer1");
Layer &layer2 = grease_pencil.root_group.wrap().add_layer("Layer2");
layer1.insert_frame(0, GreasePencilFrame{0});
layer1.insert_frame(10, GreasePencilFrame{1});
layer1.insert_frame(20, GreasePencilFrame{2});
layer1.tag_frames_map_keys_changed();
layer2.insert_frame(0, GreasePencilFrame{1});
layer2.tag_frames_map_keys_changed();
grease_pencil.remove_drawing(1);
EXPECT_EQ(grease_pencil.drawings().size(), 2);
static int expected_frames_size[] = {2, 0};
static int expected_frames_pairs_layer0[][2] = {{0, 0}, {20, 1}};
Span<const Layer *> layers = grease_pencil.layers();
EXPECT_EQ(layers[0]->frames().size(), expected_frames_size[0]);
EXPECT_EQ(layers[1]->frames().size(), expected_frames_size[1]);
EXPECT_EQ(layers[0]->frames().lookup(expected_frames_pairs_layer0[0][0]).drawing_index,
expected_frames_pairs_layer0[0][1]);
EXPECT_EQ(layers[0]->frames().lookup(expected_frames_pairs_layer0[1][0]).drawing_index,
expected_frames_pairs_layer0[1][1]);
}
TEST(greasepencil, overwrite_frame)
{
Layer layer1("Layer1");
layer1.insert_frame(0, GreasePencilFrame{0});
layer1.tag_frames_map_keys_changed();
EXPECT_EQ(layer1.frames().lookup(0).drawing_index, 0);
layer1.overwrite_frame(0, GreasePencilFrame{42});
EXPECT_EQ(layer1.frames().lookup(0).drawing_index, 42);
}
/* --------------------------------------------------------------------------------------------- */
/* Layer Tree Tests. */
TEST(greasepencil, layer_tree_empty)
{
LayerGroup root;
}
TEST(greasepencil, layer_tree_build_simple)
{
LayerGroup root;
LayerGroup &group = root.add_group("Group1");
group.add_layer("Layer1");
group.add_layer("Layer2");
}
struct GreasePencilLayerTreeExample {
StringRefNull names[7] = {"Group1", "Layer1", "Layer2", "Group2", "Layer3", "Layer4", "Layer5"};
const bool is_layer[7] = {false, true, true, false, true, true, true};
LayerGroup root;
GreasePencilLayerTreeExample()
{
LayerGroup &group = root.add_group(names[0]);
group.add_layer(names[1]);
group.add_layer(names[2]);
LayerGroup &group2 = group.add_group(names[3]);
group2.add_layer(names[4]);
group2.add_layer(names[5]);
root.add_layer(names[6]);
}
};
TEST(greasepencil, layer_tree_pre_order_iteration)
{
GreasePencilLayerTreeExample ex;
Span<const TreeNode *> children = ex.root.nodes();
for (const int i : children.index_range()) {
const TreeNode &child = *children[i];
EXPECT_STREQ(child.name, ex.names[i].data());
}
}
TEST(greasepencil, layer_tree_pre_order_iteration2)
{
GreasePencilLayerTreeExample ex;
Span<const Layer *> layers = ex.root.layers();
char name[64];
for (const int i : layers.index_range()) {
const Layer &layer = *layers[i];
snprintf(name, 64, "%s%d", "Layer", i + 1);
EXPECT_STREQ(layer.name().data(), name);
}
}
TEST(greasepencil, layer_tree_total_size)
{
GreasePencilLayerTreeExample ex;
EXPECT_EQ(ex.root.num_nodes_total(), 7);
}
TEST(greasepencil, layer_tree_node_types)
{
GreasePencilLayerTreeExample ex;
Span<const TreeNode *> children = ex.root.nodes();
for (const int i : children.index_range()) {
const TreeNode &child = *children[i];
EXPECT_EQ(child.is_layer(), ex.is_layer[i]);
EXPECT_EQ(child.is_group(), !ex.is_layer[i]);
}
}
} // namespace blender::bke::greasepencil::tests

View File

@ -95,6 +95,7 @@ static void id_type_init(void)
INIT_TYPE(ID_PT);
INIT_TYPE(ID_VO);
INIT_TYPE(ID_SIM);
INIT_TYPE(ID_GP);
/* Special naughty boy... */
BLI_assert(IDType_ID_LINK_PLACEHOLDER.main_listbase_index == INDEX_ID_NULL);
@ -222,6 +223,7 @@ uint64_t BKE_idtype_idcode_to_idfilter(const short idcode)
CASE_IDFILTER(CF);
CASE_IDFILTER(CU_LEGACY);
CASE_IDFILTER(GD_LEGACY);
CASE_IDFILTER(GP);
CASE_IDFILTER(GR);
CASE_IDFILTER(CV);
CASE_IDFILTER(IM);
@ -280,6 +282,7 @@ short BKE_idtype_idcode_from_idfilter(const uint64_t idfilter)
CASE_IDFILTER(CF);
CASE_IDFILTER(CU_LEGACY);
CASE_IDFILTER(GD_LEGACY);
CASE_IDFILTER(GP);
CASE_IDFILTER(GR);
CASE_IDFILTER(CV);
CASE_IDFILTER(IM);
@ -336,6 +339,7 @@ int BKE_idtype_idcode_to_index(const short idcode)
CASE_IDINDEX(CF);
CASE_IDINDEX(CU_LEGACY);
CASE_IDINDEX(GD_LEGACY);
CASE_IDINDEX(GP);
CASE_IDINDEX(GR);
CASE_IDINDEX(CV);
CASE_IDINDEX(IM);
@ -395,6 +399,7 @@ short BKE_idtype_idcode_from_index(const int index)
CASE_IDCODE(CF);
CASE_IDCODE(CU_LEGACY);
CASE_IDCODE(GD_LEGACY);
CASE_IDCODE(GP);
CASE_IDCODE(GR);
CASE_IDCODE(CV);
CASE_IDCODE(IM);

View File

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

View File

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

View File

@ -464,6 +464,8 @@ uint64_t BKE_library_id_can_use_filter_id(const ID *owner_id, const bool include
return FILTER_ID_IM;
case ID_GD_LEGACY:
return FILTER_ID_MA;
case ID_GP:
return FILTER_ID_GP | FILTER_ID_MA;
case ID_WS:
return FILTER_ID_SCE;
case ID_CV:

View File

@ -628,6 +628,8 @@ ListBase *which_libbase(Main *bmain, short type)
return &(bmain->wm);
case ID_GD_LEGACY:
return &(bmain->gpencils);
case ID_GP:
return &(bmain->grease_pencils);
case ID_MC:
return &(bmain->movieclips);
case ID_MSK:
@ -671,6 +673,7 @@ int set_listbasepointers(Main *bmain, ListBase *lb[/*INDEX_ID_MAX*/])
/* Referenced by nodes, objects, view, scene etc, before to free after. */
lb[INDEX_ID_GD_LEGACY] = &(bmain->gpencils);
lb[INDEX_ID_GP] = &(bmain->grease_pencils);
lb[INDEX_ID_NT] = &(bmain->nodetrees);
lb[INDEX_ID_IM] = &(bmain->images);

View File

@ -24,6 +24,7 @@
#include "DNA_customdata_types.h"
#include "DNA_defaults.h"
#include "DNA_gpencil_legacy_types.h"
#include "DNA_grease_pencil_types.h"
#include "DNA_material_types.h"
#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
@ -75,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;
@ -132,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;
@ -150,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)
@ -353,6 +376,10 @@ Material ***BKE_object_material_array_p(Object *ob)
Volume *volume = static_cast<Volume *>(ob->data);
return &(volume->mat);
}
if (ob->type == OB_GREASE_PENCIL) {
GreasePencil *grease_pencil = static_cast<GreasePencil *>(ob->data);
return &(grease_pencil->material_array);
}
return nullptr;
}
@ -386,6 +413,10 @@ short *BKE_object_material_len_p(Object *ob)
Volume *volume = static_cast<Volume *>(ob->data);
return &(volume->totcol);
}
if (ob->type == OB_GREASE_PENCIL) {
GreasePencil *grease_pencil = static_cast<GreasePencil *>(ob->data);
return &(grease_pencil->material_array_size);
}
return nullptr;
}
@ -409,6 +440,8 @@ Material ***BKE_id_material_array_p(ID *id)
return &(((PointCloud *)id)->mat);
case ID_VO:
return &(((Volume *)id)->mat);
case ID_GP:
return &(((GreasePencil *)id)->material_array);
default:
break;
}
@ -435,6 +468,8 @@ short *BKE_id_material_len_p(ID *id)
return &(((PointCloud *)id)->totcol);
case ID_VO:
return &(((Volume *)id)->totcol);
case ID_GP:
return &(((GreasePencil *)id)->material_array_size);
default:
break;
}
@ -1907,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;
}
@ -1931,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;
}
@ -1949,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);
@ -1964,6 +2002,13 @@ void BKE_material_copybuf_paste(Main *bmain, Material *ma)
if (matcopybuf.nodetree != nullptr) {
ma->nodetree = blender::bke::ntreeCopyTree_ex(matcopybuf.nodetree, bmain, false);
}
if (has_node_tree) {
/* Important to run this when the embedded tree if freed,
* otherwise the depsgraph holds a reference to the (now freed) `ma->nodetree`.
* Also run this when a new node-tree is set to ensure it's accounted for. */
DEG_relations_tag_update(bmain);
}
}
void BKE_material_eval(struct Depsgraph *depsgraph, Material *material)

View File

@ -34,6 +34,7 @@
#include "BKE_displist.h"
#include "BKE_editmesh.h"
#include "BKE_geometry_set.hh"
#include "BKE_geometry_set_instances.hh"
#include "BKE_key.h"
#include "BKE_lib_id.h"
#include "BKE_lib_query.h"
@ -508,10 +509,15 @@ void BKE_mesh_to_curve_nurblist(const Mesh *me, ListBase *nurblist, const int ed
void BKE_mesh_to_curve(Main *bmain, Depsgraph *depsgraph, Scene * /*scene*/, Object *ob)
{
/* make new mesh data from the original copy */
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 Object *ob_eval = DEG_get_evaluated_object(depsgraph, ob);
if (!ob_eval) {
return;
}
const Mesh *me_eval = BKE_object_get_evaluated_mesh_no_subsurf(ob_eval);
if (!me_eval) {
return;
}
ListBase nurblist = {nullptr, nullptr};
BKE_mesh_to_curve_nurblist(me_eval, &nurblist, 0);
@ -534,10 +540,14 @@ void BKE_mesh_to_curve(Main *bmain, Depsgraph *depsgraph, Scene * /*scene*/, Obj
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);
const Mesh *mesh_eval = mesh_get_eval_final(depsgraph, scene_eval, ob_eval, &CD_MASK_MESH);
const Object *ob_eval = DEG_get_evaluated_object(depsgraph, ob);
if (!ob_eval) {
return;
}
const Mesh *mesh_eval = BKE_object_get_evaluated_mesh(ob_eval);
if (!mesh_eval) {
return;
}
PointCloud *pointcloud = (PointCloud *)BKE_pointcloud_add(bmain, ob->id.name + 2);
@ -558,14 +568,15 @@ void BKE_pointcloud_to_mesh(Main *bmain, Depsgraph *depsgraph, Scene * /*scene*/
{
BLI_assert(ob->type == OB_POINTCLOUD);
Object *ob_eval = DEG_get_evaluated_object(depsgraph, ob);
const PointCloud *pointcloud_eval = (const PointCloud *)ob_eval->runtime.data_eval;
const Object *ob_eval = DEG_get_evaluated_object(depsgraph, ob);
const GeometrySet geometry = blender::bke::object_get_evaluated_geometry_set(*ob_eval);
Mesh *mesh = BKE_mesh_add(bmain, ob->id.name + 2);
mesh->totvert = pointcloud_eval->totpoint;
CustomData_merge(
&pointcloud_eval->pdata, &mesh->vdata, CD_MASK_PROP_ALL, pointcloud_eval->totpoint);
if (const PointCloud *points = geometry.get_pointcloud_for_read()) {
mesh->totvert = points->totpoint;
CustomData_merge(&points->pdata, &mesh->vdata, CD_MASK_PROP_ALL, points->totpoint);
}
BKE_id_materials_copy(bmain, (ID *)ob->data, (ID *)mesh);

View File

@ -379,7 +379,9 @@ static void get_vertexcos__mapFunc(void *user_data,
}
}
void BKE_mesh_foreach_mapped_vert_coords_get(Mesh *me_eval, float (*r_cos)[3], const int totcos)
void BKE_mesh_foreach_mapped_vert_coords_get(const Mesh *me_eval,
float (*r_cos)[3],
const int totcos)
{
MappedVCosData user_data;
memset(r_cos, 0, sizeof(*r_cos) * totcos);

View File

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

View File

@ -18,6 +18,7 @@
#include "BKE_mesh_runtime.h"
#include "BKE_modifier.h"
#include "BKE_multires.h"
#include "BKE_object.h"
#include "BKE_subdiv.h"
#include "BKE_subsurf.h"
#include "BLI_math_vector.h"
@ -59,9 +60,14 @@ bool multiresModifier_reshapeFromObject(Depsgraph *depsgraph,
Object *dst,
Object *src)
{
Scene *scene_eval = DEG_get_evaluated_scene(depsgraph);
Object *src_eval = DEG_get_evaluated_object(depsgraph, src);
Mesh *src_mesh_eval = mesh_get_eval_final(depsgraph, scene_eval, src_eval, &CD_MASK_BAREMESH);
const Object *ob_eval = DEG_get_evaluated_object(depsgraph, src);
if (!ob_eval) {
return false;
}
const Mesh *src_mesh_eval = BKE_object_get_evaluated_mesh(ob_eval);
if (!src_mesh_eval) {
return false;
}
int num_deformed_verts;
float(*deformed_verts)[3] = BKE_mesh_vert_coords_alloc(src_mesh_eval, &num_deformed_verts);

View File

@ -27,6 +27,7 @@
#include "DNA_fluid_types.h"
#include "DNA_gpencil_legacy_types.h"
#include "DNA_gpencil_modifier_types.h"
#include "DNA_grease_pencil_types.h"
#include "DNA_key_types.h"
#include "DNA_lattice_types.h"
#include "DNA_light_types.h"
@ -89,6 +90,7 @@
#include "BKE_gpencil_geom_legacy.h"
#include "BKE_gpencil_legacy.h"
#include "BKE_gpencil_modifier_legacy.h"
#include "BKE_grease_pencil.hh"
#include "BKE_icons.h"
#include "BKE_idprop.h"
#include "BKE_idtype.h"
@ -1467,7 +1469,8 @@ bool BKE_object_supports_modifiers(const Object *ob)
OB_FONT,
OB_LATTICE,
OB_POINTCLOUD,
OB_VOLUME);
OB_VOLUME,
OB_GREASE_PENCIL);
}
bool BKE_object_support_modifier_type_check(const Object *ob, int modifier_type)
@ -1970,6 +1973,8 @@ bool BKE_object_is_in_editmode(const Object *ob)
case OB_CURVES:
/* Curves object has no edit mode data. */
return ob->mode == OB_MODE_EDIT;
case OB_GREASE_PENCIL:
return ob->mode == OB_MODE_EDIT;
default:
return false;
}
@ -1997,6 +2002,7 @@ bool BKE_object_data_is_in_editmode(const Object *ob, const ID *id)
case ID_AR:
return ((const bArmature *)id)->edbo != nullptr;
case ID_CV:
case ID_GP:
if (ob) {
return BKE_object_is_in_editmode(ob);
}
@ -2052,6 +2058,10 @@ char *BKE_object_data_editmode_flush_ptr_get(struct ID *id)
/* Curves have no edit mode data. */
return nullptr;
}
case ID_GP: {
/* Grease Pencil has no edit mode data. */
return nullptr;
}
default:
BLI_assert_unreachable();
return nullptr;
@ -2195,6 +2205,8 @@ static const char *get_obdata_defname(int type)
return DATA_("GPencil");
case OB_LIGHTPROBE:
return DATA_("LightProbe");
case OB_GREASE_PENCIL:
return DATA_("GreasePencil");
default:
CLOG_ERROR(&LOG, "Internal error, bad type: %d", type);
return CTX_DATA_(BLT_I18NCONTEXT_ID_ID, "Empty");
@ -2264,6 +2276,8 @@ void *BKE_object_obdata_add_from_type(Main *bmain, int type, const char *name)
return BKE_pointcloud_add_default(bmain, name);
case OB_VOLUME:
return BKE_volume_add(bmain, name);
case OB_GREASE_PENCIL:
return BKE_grease_pencil_add(bmain, name);
case OB_EMPTY:
return nullptr;
default:
@ -2302,6 +2316,8 @@ int BKE_object_obdata_to_type(const ID *id)
return OB_POINTCLOUD;
case ID_VO:
return OB_VOLUME;
case ID_GP:
return OB_GREASE_PENCIL;
default:
return -1;
}
@ -3813,6 +3829,8 @@ const BoundBox *BKE_object_boundbox_get(Object *ob)
case OB_VOLUME:
bb = BKE_volume_boundbox_get(ob);
break;
case OB_GREASE_PENCIL:
bb = BKE_grease_pencil_boundbox_get(ob);
default:
break;
}
@ -3997,7 +4015,6 @@ void BKE_object_minmax(Object *ob, float r_min[3], float r_max[3], const bool us
changed = true;
break;
}
case OB_POINTCLOUD: {
const BoundBox bb = *BKE_pointcloud_boundbox_get(ob);
BKE_boundbox_minmax(&bb, ob->object_to_world, r_min, r_max);
@ -4010,6 +4027,12 @@ void BKE_object_minmax(Object *ob, float r_min[3], float r_max[3], const bool us
changed = true;
break;
}
case OB_GREASE_PENCIL: {
const BoundBox bb = *BKE_grease_pencil_boundbox_get(ob);
BKE_boundbox_minmax(&bb, ob->object_to_world, r_min, r_max);
changed = true;
break;
}
}
if (changed == false) {
@ -5185,7 +5208,8 @@ bool BKE_object_supports_material_slots(struct Object *ob)
OB_CURVES,
OB_POINTCLOUD,
OB_VOLUME,
OB_GPENCIL_LEGACY);
OB_GPENCIL_LEGACY,
OB_GREASE_PENCIL);
}
/** \} */

View File

@ -31,6 +31,8 @@
#include "BKE_effect.h"
#include "BKE_gpencil_legacy.h"
#include "BKE_gpencil_modifier_legacy.h"
#include "BKE_grease_pencil.h"
#include "BKE_grease_pencil.hh"
#include "BKE_image.h"
#include "BKE_key.h"
#include "BKE_lattice.h"
@ -199,6 +201,9 @@ void BKE_object_handle_data_update(Depsgraph *depsgraph, Scene *scene, Object *o
case OB_VOLUME:
BKE_volume_data_update(depsgraph, scene, ob);
break;
case OB_GREASE_PENCIL:
BKE_grease_pencil_data_update(depsgraph, scene, ob);
break;
}
/* particles */
@ -319,6 +324,10 @@ void BKE_object_batch_cache_dirty_tag(Object *ob)
case OB_VOLUME:
BKE_volume_batch_cache_dirty_tag((struct Volume *)ob->data, BKE_VOLUME_BATCH_DIRTY_ALL);
break;
case OB_GREASE_PENCIL:
BKE_grease_pencil_batch_cache_dirty_tag((struct GreasePencil *)ob->data,
BKE_GREASEPENCIL_BATCH_DIRTY_ALL);
break;
default:
break;
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

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