Geometry Nodes: Rewrite mesh delete geometry node #108435
|
@ -104,9 +104,9 @@
|
|||
* merged in docs.
|
||||
*/
|
||||
|
||||
/**
|
||||
* \defgroup gui GUI
|
||||
* \ingroup blender */
|
||||
/** \defgroup gui GUI
|
||||
* \ingroup blender
|
||||
*/
|
||||
|
||||
/** \defgroup wm Window Manager
|
||||
* \ingroup gui */
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
This script generates the blender.1 man page, embedding the help text
|
||||
from the Blender executable itself. Invoke it as follows:
|
||||
|
||||
blender.1.py --blender <path-to-blender> --output <output-filename>
|
||||
./blender.bin -b --python doc/manpage/blender.1.py -- --output <output-filename>
|
||||
|
||||
where <path-to-blender> is the path to the Blender executable,
|
||||
and <output-filename> is where to write the generated man page.
|
||||
|
@ -13,8 +13,8 @@ and <output-filename> is where to write the generated man page.
|
|||
|
||||
import argparse
|
||||
import os
|
||||
import subprocess
|
||||
import time
|
||||
import sys
|
||||
|
||||
from typing import (
|
||||
Dict,
|
||||
|
@ -28,61 +28,28 @@ def man_format(data: str) -> str:
|
|||
return data
|
||||
|
||||
|
||||
def blender_extract_info(blender_bin: str) -> Dict[str, str]:
|
||||
def blender_extract_info() -> Dict[str, str]:
|
||||
# Only use of `bpy` in this file.
|
||||
import bpy # type: ignore
|
||||
blender_help_text = bpy.app.help_text()
|
||||
blender_version_text = bpy.app.version_string
|
||||
blender_build_date_text = bpy.app.build_date
|
||||
|
||||
blender_env = {
|
||||
"ASAN_OPTIONS": (
|
||||
os.environ.get("ASAN_OPTIONS", "") +
|
||||
":exitcode=0:check_initialization_order=0:strict_init_order=0"
|
||||
).lstrip(":"),
|
||||
}
|
||||
|
||||
blender_help = subprocess.run(
|
||||
[blender_bin, "--help"],
|
||||
env=blender_env,
|
||||
check=True,
|
||||
stdout=subprocess.PIPE,
|
||||
).stdout.decode(encoding="utf-8")
|
||||
|
||||
blender_version_output = subprocess.run(
|
||||
[blender_bin, "--version"],
|
||||
env=blender_env,
|
||||
check=True,
|
||||
stdout=subprocess.PIPE,
|
||||
).stdout.decode(encoding="utf-8")
|
||||
|
||||
# Extract information from the version string.
|
||||
# Note that some internal modules may print errors (e.g. color management),
|
||||
# check for each lines prefix to ensure these aren't included.
|
||||
blender_version = ""
|
||||
blender_date = ""
|
||||
for l in blender_version_output.split("\n"):
|
||||
if l.startswith("Blender "):
|
||||
# Remove 'Blender' prefix.
|
||||
blender_version = l.split(" ", 1)[1].strip()
|
||||
elif l.lstrip().startswith("build date:"):
|
||||
# Remove 'build date:' prefix.
|
||||
blender_date = l.split(":", 1)[1].strip()
|
||||
if blender_version and blender_date:
|
||||
break
|
||||
|
||||
if not blender_date:
|
||||
if blender_build_date_text == b'Unknown':
|
||||
# Happens when built without WITH_BUILD_INFO e.g.
|
||||
date_string = time.strftime("%B %d, %Y", time.gmtime(int(os.environ.get('SOURCE_DATE_EPOCH', time.time()))))
|
||||
blender_date = time.strftime("%B %d, %Y", time.gmtime(int(os.environ.get('SOURCE_DATE_EPOCH', time.time()))))
|
||||
else:
|
||||
date_string = time.strftime("%B %d, %Y", time.strptime(blender_date, "%Y-%m-%d"))
|
||||
blender_date = time.strftime("%B %d, %Y", time.strptime(blender_build_date_text, "%Y-%m-%d"))
|
||||
|
||||
return {
|
||||
"help": blender_help,
|
||||
"version": blender_version,
|
||||
"date": date_string,
|
||||
"help": blender_help_text,
|
||||
"version": blender_version_text,
|
||||
"date": blender_date,
|
||||
}
|
||||
|
||||
|
||||
def man_page_from_blender_help(fh: TextIO, blender_bin: str, verbose: bool) -> None:
|
||||
if verbose:
|
||||
print("Extracting help text:", blender_bin)
|
||||
blender_info = blender_extract_info(blender_bin)
|
||||
def man_page_from_blender_help(fh: TextIO, verbose: bool) -> None:
|
||||
blender_info = blender_extract_info()
|
||||
|
||||
# Header Content.
|
||||
fh.write(
|
||||
|
@ -175,11 +142,6 @@ def create_argparse() -> argparse.ArgumentParser:
|
|||
required=True,
|
||||
help="The man page to write to."
|
||||
)
|
||||
parser.add_argument(
|
||||
"--blender",
|
||||
required=True,
|
||||
help="Path to the blender binary."
|
||||
)
|
||||
parser.add_argument(
|
||||
"--verbose",
|
||||
default=False,
|
||||
|
@ -192,15 +154,15 @@ def create_argparse() -> argparse.ArgumentParser:
|
|||
|
||||
|
||||
def main() -> None:
|
||||
argv = sys.argv[sys.argv.index("--") + 1:]
|
||||
parser = create_argparse()
|
||||
args = parser.parse_args()
|
||||
args = parser.parse_args(argv)
|
||||
|
||||
blender_bin = args.blender
|
||||
output_filename = args.output
|
||||
verbose = args.verbose
|
||||
|
||||
with open(output_filename, "w", encoding="utf-8") as fh:
|
||||
man_page_from_blender_help(fh, blender_bin, verbose)
|
||||
man_page_from_blender_help(fh, verbose)
|
||||
if verbose:
|
||||
print("Written:", output_filename)
|
||||
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
# Libs that adhere to strict flags
|
||||
add_subdirectory(curve_fit_nd)
|
||||
add_subdirectory(fmtlib)
|
||||
|
||||
# Otherwise we get warnings here that we cant fix in external projects
|
||||
remove_strict_flags()
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
Project: fast_float
|
||||
URL: https://github.com/fastfloat/fast_float
|
||||
License: MIT
|
||||
Upstream version: 4.0.0 (fbd5bd7, 2023 Mar 31)
|
||||
Upstream version: 5.0.0 (f5a3e77, 2023 May 25)
|
||||
Local modifications:
|
||||
|
||||
- Took only the fast_float.h header and the license/readme files
|
||||
|
|
|
@ -1,4 +1,8 @@
|
|||
|
||||
## fast_float number parsing library: 4x faster than strtod
|
||||
[![Fuzzing Status](https://oss-fuzz-build-logs.storage.googleapis.com/badges/fast_float.svg)](https://bugs.chromium.org/p/oss-fuzz/issues/list?sort=-opened&can=1&q=proj:fast_float)
|
||||
[![VS17-CI](https://github.com/fastfloat/fast_float/actions/workflows/vs17-ci.yml/badge.svg)](https://github.com/fastfloat/fast_float/actions/workflows/vs17-ci.yml)
|
||||
[![Ubuntu 22.04 CI (GCC 11)](https://github.com/fastfloat/fast_float/actions/workflows/ubuntu22.yml/badge.svg)](https://github.com/fastfloat/fast_float/actions/workflows/ubuntu22.yml)
|
||||
|
||||
The fast_float library provides fast header-only implementations for the C++ from_chars
|
||||
functions for `float` and `double` types. These functions convert ASCII strings representing
|
||||
|
@ -93,6 +97,24 @@ constexpr double constexptest() {
|
|||
}
|
||||
```
|
||||
|
||||
## Non-ASCII Inputs
|
||||
|
||||
We also support UTF-16 and UTF-32 inputs, as well as ASCII/UTF-8, as in the following example:
|
||||
|
||||
``` C++
|
||||
#include "fast_float/fast_float.h"
|
||||
#include <iostream>
|
||||
|
||||
int main() {
|
||||
const std::u16string input = u"3.1416 xyz ";
|
||||
double result;
|
||||
auto answer = fast_float::from_chars(input.data(), input.data()+input.size(), result);
|
||||
if(answer.ec != std::errc()) { std::cerr << "parsing failure\n"; return EXIT_FAILURE; }
|
||||
std::cout << "parsed the number " << result << std::endl;
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
```
|
||||
|
||||
## Using commas as decimal separator
|
||||
|
||||
|
||||
|
@ -189,11 +211,11 @@ It can parse random floating-point numbers at a speed of 1 GB/s on some systems.
|
|||
$ ./build/benchmarks/benchmark
|
||||
# parsing random integers in the range [0,1)
|
||||
volume = 2.09808 MB
|
||||
netlib : 271.18 MB/s (+/- 1.2 %) 12.93 Mfloat/s
|
||||
doubleconversion : 225.35 MB/s (+/- 1.2 %) 10.74 Mfloat/s
|
||||
strtod : 190.94 MB/s (+/- 1.6 %) 9.10 Mfloat/s
|
||||
abseil : 430.45 MB/s (+/- 2.2 %) 20.52 Mfloat/s
|
||||
fastfloat : 1042.38 MB/s (+/- 9.9 %) 49.68 Mfloat/s
|
||||
netlib : 271.18 MB/s (+/- 1.2 %) 12.93 Mfloat/s
|
||||
doubleconversion : 225.35 MB/s (+/- 1.2 %) 10.74 Mfloat/s
|
||||
strtod : 190.94 MB/s (+/- 1.6 %) 9.10 Mfloat/s
|
||||
abseil : 430.45 MB/s (+/- 2.2 %) 20.52 Mfloat/s
|
||||
fastfloat : 1042.38 MB/s (+/- 9.9 %) 49.68 Mfloat/s
|
||||
```
|
||||
|
||||
See https://github.com/lemire/simple_fastfloat_benchmark for our benchmarking code.
|
||||
|
@ -257,7 +279,7 @@ under the Apache 2.0 license.
|
|||
|
||||
<sup>
|
||||
Licensed under either of <a href="LICENSE-APACHE">Apache License, Version
|
||||
2.0</a> or <a href="LICENSE-MIT">MIT license</a> at your option.
|
||||
2.0</a> or <a href="LICENSE-MIT">MIT license</a> or <a href="LICENSE-BOOST">BOOST license</a> .
|
||||
</sup>
|
||||
|
||||
<br>
|
||||
|
@ -265,5 +287,5 @@ Licensed under either of <a href="LICENSE-APACHE">Apache License, Version
|
|||
<sub>
|
||||
Unless you explicitly state otherwise, any contribution intentionally submitted
|
||||
for inclusion in this repository by you, as defined in the Apache-2.0 license,
|
||||
shall be dual licensed as above, without any additional terms or conditions.
|
||||
shall be triple licensed as above, without any additional terms or conditions.
|
||||
</sub>
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,20 @@
|
|||
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
set(INC
|
||||
include
|
||||
)
|
||||
|
||||
set(INC_SYS
|
||||
)
|
||||
|
||||
set(SRC
|
||||
include/fmt/core.h
|
||||
include/fmt/format-inl.h
|
||||
include/fmt/format.h
|
||||
src/format.cc
|
||||
)
|
||||
|
||||
set(LIB
|
||||
)
|
||||
|
||||
blender_add_lib(extern_fmtlib "${SRC}" "${INC}" "${INC_SYS}" "${LIB}")
|
|
@ -1,4 +1,4 @@
|
|||
Copyright (c) 2012 - present, Victor Zverovich
|
||||
Copyright (c) 2012 - present, Victor Zverovich and {fmt} contributors
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
|
|
|
@ -1,8 +1,12 @@
|
|||
Project: {fmt}
|
||||
URL: https://github.com/fmtlib/fmt
|
||||
License: MIT
|
||||
Upstream version: 8.1.1 (b6f4cea)
|
||||
Upstream version: 10.0.0 (a0b8a92, 2023 May 10)
|
||||
Local modifications:
|
||||
|
||||
- Took only files needed for Blender: LICENSE, README and include/fmt
|
||||
folder's core.h, format-inl.h, format.h
|
||||
- Took only files needed for Blender:
|
||||
- LICENSE, README
|
||||
- include/fmt: core.h, format-inl.h, format.h
|
||||
- src/format.cc
|
||||
- CMakeLists.txt is not from fmtlib, but
|
||||
made for Blender codebase
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
{fmt}
|
||||
=====
|
||||
.. image:: https://user-images.githubusercontent.com/
|
||||
576385/156254208-f5b743a9-88cf-439d-b0c0-923d53e8d551.png
|
||||
:width: 25%
|
||||
:alt: {fmt}
|
||||
|
||||
.. image:: https://github.com/fmtlib/fmt/workflows/linux/badge.svg
|
||||
:target: https://github.com/fmtlib/fmt/actions?query=workflow%3Alinux
|
||||
|
@ -10,9 +12,6 @@
|
|||
.. image:: https://github.com/fmtlib/fmt/workflows/windows/badge.svg
|
||||
:target: https://github.com/fmtlib/fmt/actions?query=workflow%3Awindows
|
||||
|
||||
.. image:: https://ci.appveyor.com/api/projects/status/ehjkiefde6gucy1v?svg=true
|
||||
:target: https://ci.appveyor.com/project/vitaut/fmt
|
||||
|
||||
.. image:: https://oss-fuzz-build-logs.storage.googleapis.com/badges/fmt.svg
|
||||
:alt: fmt is continuously fuzzed at oss-fuzz
|
||||
:target: https://bugs.chromium.org/p/oss-fuzz/issues/list?\
|
||||
|
@ -26,12 +25,13 @@
|
|||
**{fmt}** is an open-source formatting library providing a fast and safe
|
||||
alternative to C stdio and C++ iostreams.
|
||||
|
||||
If you like this project, please consider donating to the BYSOL
|
||||
Foundation that helps victims of political repressions in Belarus:
|
||||
https://bysol.org/en/bs/general/.
|
||||
If you like this project, please consider donating to one of the funds that
|
||||
help victims of the war in Ukraine: https://www.stopputin.net/.
|
||||
|
||||
`Documentation <https://fmt.dev>`__
|
||||
|
||||
`Cheat Sheets <https://hackingcpp.com/cpp/libs/fmt.html>`__
|
||||
|
||||
Q&A: ask questions on `StackOverflow with the tag fmt
|
||||
<https://stackoverflow.com/questions/tagged/fmt>`_.
|
||||
|
||||
|
@ -47,7 +47,8 @@ Features
|
|||
* `Format string syntax <https://fmt.dev/latest/syntax.html>`_ similar to Python's
|
||||
`format <https://docs.python.org/3/library/stdtypes.html#str.format>`_
|
||||
* Fast IEEE 754 floating-point formatter with correct rounding, shortness and
|
||||
round-trip guarantees
|
||||
round-trip guarantees using the `Dragonbox <https://github.com/jk-jeon/dragonbox>`_
|
||||
algorithm
|
||||
* Safe `printf implementation
|
||||
<https://fmt.dev/latest/api.html#printf-formatting>`_ including the POSIX
|
||||
extension for positional arguments
|
||||
|
@ -123,7 +124,7 @@ Output::
|
|||
Default format: 42s 100ms
|
||||
strftime-like format: 03:15:30
|
||||
|
||||
**Print a container** (`run <https://godbolt.org/z/MjsY7c>`_)
|
||||
**Print a container** (`run <https://godbolt.org/z/MxM1YqjE7>`_)
|
||||
|
||||
.. code:: c++
|
||||
|
||||
|
@ -191,24 +192,24 @@ Speed tests
|
|||
================= ============= ===========
|
||||
Library Method Run Time, s
|
||||
================= ============= ===========
|
||||
libc printf 1.04
|
||||
libc++ std::ostream 3.05
|
||||
{fmt} 6.1.1 fmt::print 0.75
|
||||
Boost Format 1.67 boost::format 7.24
|
||||
Folly Format folly::format 2.23
|
||||
libc printf 0.91
|
||||
libc++ std::ostream 2.49
|
||||
{fmt} 9.1 fmt::print 0.74
|
||||
Boost Format 1.80 boost::format 6.26
|
||||
Folly Format folly::format 1.87
|
||||
================= ============= ===========
|
||||
|
||||
{fmt} is the fastest of the benchmarked methods, ~35% faster than ``printf``.
|
||||
{fmt} is the fastest of the benchmarked methods, ~20% faster than ``printf``.
|
||||
|
||||
The above results were generated by building ``tinyformat_test.cpp`` on macOS
|
||||
10.14.6 with ``clang++ -O3 -DNDEBUG -DSPEED_TEST -DHAVE_FORMAT``, and taking the
|
||||
12.6.1 with ``clang++ -O3 -DNDEBUG -DSPEED_TEST -DHAVE_FORMAT``, and taking the
|
||||
best of three runs. In the test, the format string ``"%0.10f:%04d:%+g:%s:%p:%c:%%\n"``
|
||||
or equivalent is filled 2,000,000 times with output sent to ``/dev/null``; for
|
||||
further details refer to the `source
|
||||
<https://github.com/fmtlib/format-benchmark/blob/master/src/tinyformat-test.cc>`_.
|
||||
|
||||
{fmt} is up to 20-30x faster than ``std::ostringstream`` and ``sprintf`` on
|
||||
floating-point formatting (`dtoa-benchmark <https://github.com/fmtlib/dtoa-benchmark>`_)
|
||||
IEEE754 ``float`` and ``double`` formatting (`dtoa-benchmark <https://github.com/fmtlib/dtoa-benchmark>`_)
|
||||
and faster than `double-conversion <https://github.com/google/double-conversion>`_ and
|
||||
`ryu <https://github.com/ulfjack/ryu>`_:
|
||||
|
||||
|
@ -322,8 +323,10 @@ Projects using this library
|
|||
|
||||
* `ccache <https://ccache.dev/>`_: a compiler cache
|
||||
|
||||
* `ClickHouse <https://github.com/ClickHouse/ClickHouse>`_: analytical database
|
||||
* `ClickHouse <https://github.com/ClickHouse/ClickHouse>`_: an analytical database
|
||||
management system
|
||||
|
||||
* `Contour <https://github.com/contour-terminal/contour/>`_: a modern terminal emulator
|
||||
|
||||
* `CUAUV <https://cuauv.org/>`_: Cornell University's autonomous underwater
|
||||
vehicle
|
||||
|
@ -341,9 +344,12 @@ Projects using this library
|
|||
|
||||
* `Folly <https://github.com/facebook/folly>`_: Facebook open-source library
|
||||
|
||||
* `GemRB <https://gemrb.org/>`_: a portable open-source implementation of
|
||||
Bioware’s Infinity Engine
|
||||
|
||||
* `Grand Mountain Adventure
|
||||
<https://store.steampowered.com/app/1247360/Grand_Mountain_Adventure/>`_:
|
||||
A beautiful open-world ski & snowboarding game
|
||||
a beautiful open-world ski & snowboarding game
|
||||
|
||||
* `HarpyWar/pvpgn <https://github.com/pvpgn/pvpgn-server>`_:
|
||||
Player vs Player Gaming Network with tweaks
|
||||
|
@ -357,6 +363,10 @@ Projects using this library
|
|||
|
||||
* `Knuth <https://kth.cash/>`_: high-performance Bitcoin full-node
|
||||
|
||||
* `libunicode <https://github.com/contour-terminal/libunicode/>`_: a modern C++17 Unicode library
|
||||
|
||||
* `MariaDB <https://mariadb.org/>`_: relational database management system
|
||||
|
||||
* `Microsoft Verona <https://github.com/microsoft/verona>`_:
|
||||
research programming language for concurrent ownership
|
||||
|
||||
|
@ -410,6 +420,9 @@ Projects using this library
|
|||
* `TrinityCore <https://github.com/TrinityCore/TrinityCore>`_: open-source
|
||||
MMORPG framework
|
||||
|
||||
* `🐙 userver framework <https://userver.tech/>`_: open-source asynchronous
|
||||
framework with a rich set of abstractions and database drivers
|
||||
|
||||
* `Windows Terminal <https://github.com/microsoft/terminal>`_: the new Windows
|
||||
terminal
|
||||
|
||||
|
@ -520,8 +533,7 @@ Maintainers
|
|||
-----------
|
||||
|
||||
The {fmt} library is maintained by Victor Zverovich (`vitaut
|
||||
<https://github.com/vitaut>`_) and Jonathan Müller (`foonathan
|
||||
<https://github.com/foonathan>`_) with contributions from many other people.
|
||||
<https://github.com/vitaut>`_) with contributions from many other people.
|
||||
See `Contributors <https://github.com/fmtlib/fmt/graphs/contributors>`_ and
|
||||
`Releases <https://github.com/fmtlib/fmt/releases>`_ for some of the names.
|
||||
Let us know if your contribution is not listed or mentioned incorrectly and
|
||||
|
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,43 @@
|
|||
// Formatting library for C++
|
||||
//
|
||||
// Copyright (c) 2012 - 2016, Victor Zverovich
|
||||
// All rights reserved.
|
||||
//
|
||||
// For the license information refer to format.h.
|
||||
|
||||
#include "fmt/format-inl.h"
|
||||
|
||||
FMT_BEGIN_NAMESPACE
|
||||
namespace detail {
|
||||
|
||||
template FMT_API auto dragonbox::to_decimal(float x) noexcept
|
||||
-> dragonbox::decimal_fp<float>;
|
||||
template FMT_API auto dragonbox::to_decimal(double x) noexcept
|
||||
-> dragonbox::decimal_fp<double>;
|
||||
|
||||
#ifndef FMT_STATIC_THOUSANDS_SEPARATOR
|
||||
template FMT_API locale_ref::locale_ref(const std::locale& loc);
|
||||
template FMT_API auto locale_ref::get<std::locale>() const -> std::locale;
|
||||
#endif
|
||||
|
||||
// Explicit instantiations for char.
|
||||
|
||||
template FMT_API auto thousands_sep_impl(locale_ref)
|
||||
-> thousands_sep_result<char>;
|
||||
template FMT_API auto decimal_point_impl(locale_ref) -> char;
|
||||
|
||||
template FMT_API void buffer<char>::append(const char*, const char*);
|
||||
|
||||
template FMT_API void vformat_to(buffer<char>&, string_view,
|
||||
typename vformat_args<>::type, locale_ref);
|
||||
|
||||
// Explicit instantiations for wchar_t.
|
||||
|
||||
template FMT_API auto thousands_sep_impl(locale_ref)
|
||||
-> thousands_sep_result<wchar_t>;
|
||||
template FMT_API auto decimal_point_impl(locale_ref) -> wchar_t;
|
||||
|
||||
template FMT_API void buffer<wchar_t>::append(const wchar_t*, const wchar_t*);
|
||||
|
||||
} // namespace detail
|
||||
FMT_END_NAMESPACE
|
|
@ -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"
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -655,7 +655,7 @@ ccl_device_inline Spectrum bsdf_albedo(ccl_private const ShaderData *sd,
|
|||
* extra overhead though. */
|
||||
#if defined(__SVM__) || defined(__OSL__)
|
||||
if (CLOSURE_IS_BSDF_MICROFACET(sc->type)) {
|
||||
albedo *= microfacet_fresnel((ccl_private const MicrofacetBsdf *)sc, sd->wi, sc->N, false);
|
||||
albedo *= bsdf_microfacet_estimate_fresnel(sd, (ccl_private const MicrofacetBsdf *)sc);
|
||||
}
|
||||
else if (sc->type == CLOSURE_BSDF_PRINCIPLED_SHEEN_ID) {
|
||||
albedo *= ((ccl_private const PrincipledSheenBsdf *)sc)->avg_value;
|
||||
|
|
|
@ -262,19 +262,39 @@ ccl_device_forceinline Spectrum microfacet_fresnel(ccl_private const MicrofacetB
|
|||
}
|
||||
}
|
||||
else if (bsdf->fresnel_type == MicrofacetFresnel::CONSTANT) {
|
||||
kernel_assert(!refraction);
|
||||
ccl_private FresnelConstant *fresnel = (ccl_private FresnelConstant *)bsdf->fresnel;
|
||||
return fresnel->color;
|
||||
/* CONSTANT is only used my MultiGGX, which doesn't call this function.
|
||||
* Therefore, this case only happens when determining the albedo of a MultiGGX closure.
|
||||
* In that case, return 1.0 since the constant color is already baked into the weight. */
|
||||
return one_spectrum();
|
||||
}
|
||||
else {
|
||||
return one_spectrum();
|
||||
}
|
||||
}
|
||||
|
||||
ccl_device_forceinline void bsdf_microfacet_adjust_weight(ccl_private const ShaderData *sd,
|
||||
ccl_private MicrofacetBsdf *bsdf)
|
||||
/* This function estimates the albedo of the BSDF (NOT including the bsdf->weight) as caused by
|
||||
* the applied Fresnel model for the given view direction.
|
||||
* The base microfacet model is assumed to have an albedo of 1, but e.g. a reflection-only
|
||||
* closure with Fresnel applied can end up having a very low overall albedo.
|
||||
* This is used to adjust the sample weight, as well as for the Diff/Gloss/Trans Color pass
|
||||
* and the Denoising Albedo pass. */
|
||||
ccl_device Spectrum bsdf_microfacet_estimate_fresnel(ccl_private const ShaderData *sd,
|
||||
ccl_private const MicrofacetBsdf *bsdf)
|
||||
{
|
||||
bsdf->sample_weight *= average(microfacet_fresnel(bsdf, sd->wi, bsdf->N, false));
|
||||
const bool is_glass = CLOSURE_IS_GLASS(bsdf->type);
|
||||
const bool is_refractive = CLOSURE_IS_REFRACTIVE(bsdf->type);
|
||||
|
||||
Spectrum albedo = zero_spectrum();
|
||||
if (!is_refractive || is_glass) {
|
||||
/* BSDF has a reflective lobe. */
|
||||
albedo += microfacet_fresnel(bsdf, sd->wi, bsdf->N, false);
|
||||
}
|
||||
if (is_refractive) {
|
||||
/* BSDF has a refractive lobe (unless there's TIR). */
|
||||
albedo += microfacet_fresnel(bsdf, sd->wi, bsdf->N, true);
|
||||
}
|
||||
|
||||
return albedo;
|
||||
}
|
||||
|
||||
/* Generalized Trowbridge-Reitz for clearcoat. */
|
||||
|
@ -647,7 +667,7 @@ ccl_device void bsdf_microfacet_setup_fresnel_principledv1(
|
|||
|
||||
bsdf->fresnel_type = MicrofacetFresnel::PRINCIPLED_V1;
|
||||
bsdf->fresnel = fresnel;
|
||||
bsdf_microfacet_adjust_weight(sd, bsdf);
|
||||
bsdf->sample_weight *= average(bsdf_microfacet_estimate_fresnel(sd, bsdf));
|
||||
}
|
||||
|
||||
ccl_device void bsdf_microfacet_setup_fresnel_conductor(ccl_private MicrofacetBsdf *bsdf,
|
||||
|
@ -656,7 +676,7 @@ ccl_device void bsdf_microfacet_setup_fresnel_conductor(ccl_private MicrofacetBs
|
|||
{
|
||||
bsdf->fresnel_type = MicrofacetFresnel::CONDUCTOR;
|
||||
bsdf->fresnel = fresnel;
|
||||
bsdf_microfacet_adjust_weight(sd, bsdf);
|
||||
bsdf->sample_weight *= average(bsdf_microfacet_estimate_fresnel(sd, bsdf));
|
||||
}
|
||||
|
||||
ccl_device void bsdf_microfacet_setup_fresnel_dielectric_tint(
|
||||
|
@ -666,7 +686,7 @@ ccl_device void bsdf_microfacet_setup_fresnel_dielectric_tint(
|
|||
{
|
||||
bsdf->fresnel_type = MicrofacetFresnel::DIELECTRIC_TINT;
|
||||
bsdf->fresnel = fresnel;
|
||||
bsdf_microfacet_adjust_weight(sd, bsdf);
|
||||
bsdf->sample_weight *= average(bsdf_microfacet_estimate_fresnel(sd, bsdf));
|
||||
}
|
||||
|
||||
ccl_device void bsdf_microfacet_setup_fresnel_generalized_schlick(
|
||||
|
@ -676,7 +696,7 @@ ccl_device void bsdf_microfacet_setup_fresnel_generalized_schlick(
|
|||
{
|
||||
bsdf->fresnel_type = MicrofacetFresnel::GENERALIZED_SCHLICK;
|
||||
bsdf->fresnel = fresnel;
|
||||
bsdf_microfacet_adjust_weight(sd, bsdf);
|
||||
bsdf->sample_weight *= average(bsdf_microfacet_estimate_fresnel(sd, bsdf));
|
||||
}
|
||||
|
||||
/* GGX microfacet with Smith shadow-masking from:
|
||||
|
@ -711,8 +731,7 @@ ccl_device int bsdf_microfacet_ggx_clearcoat_setup(ccl_private MicrofacetBsdf *b
|
|||
|
||||
bsdf->fresnel_type = MicrofacetFresnel::DIELECTRIC;
|
||||
bsdf->type = CLOSURE_BSDF_MICROFACET_GGX_CLEARCOAT_ID;
|
||||
|
||||
bsdf_microfacet_adjust_weight(sd, bsdf);
|
||||
bsdf->sample_weight *= average(bsdf_microfacet_estimate_fresnel(sd, bsdf));
|
||||
|
||||
return SD_BSDF | SD_BSDF_HAS_EVAL;
|
||||
}
|
||||
|
|
|
@ -407,8 +407,7 @@ ccl_device int bsdf_microfacet_multi_ggx_fresnel_setup(ccl_private MicrofacetBsd
|
|||
|
||||
bsdf->fresnel_type = MicrofacetFresnel::PRINCIPLED_V1;
|
||||
bsdf->type = CLOSURE_BSDF_MICROFACET_MULTI_GGX_ID;
|
||||
|
||||
bsdf_microfacet_adjust_weight(sd, bsdf);
|
||||
bsdf->sample_weight *= average(bsdf_microfacet_estimate_fresnel(sd, bsdf));
|
||||
|
||||
return bsdf_microfacet_multi_ggx_common_setup(bsdf);
|
||||
}
|
||||
|
@ -619,8 +618,7 @@ ccl_device int bsdf_microfacet_multi_ggx_glass_fresnel_setup(ccl_private Microfa
|
|||
|
||||
bsdf->fresnel_type = MicrofacetFresnel::PRINCIPLED_V1;
|
||||
bsdf->type = CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID;
|
||||
|
||||
bsdf_microfacet_adjust_weight(sd, bsdf);
|
||||
bsdf->sample_weight *= average(bsdf_microfacet_estimate_fresnel(sd, bsdf));
|
||||
|
||||
return SD_BSDF | SD_BSDF_HAS_EVAL | SD_BSDF_NEEDS_LCG;
|
||||
}
|
||||
|
|
|
@ -36,7 +36,7 @@ KERNEL_STRUCT_MEMBER(background, int, map_res_x)
|
|||
KERNEL_STRUCT_MEMBER(background, int, map_res_y)
|
||||
/* Multiple importance sampling. */
|
||||
KERNEL_STRUCT_MEMBER(background, int, use_mis)
|
||||
/* Lightgroup. */
|
||||
/* Light-group. */
|
||||
KERNEL_STRUCT_MEMBER(background, int, lightgroup)
|
||||
/* Light Index. */
|
||||
KERNEL_STRUCT_MEMBER(background, int, light_index)
|
||||
|
|
|
@ -288,7 +288,7 @@ ccl_device_inline float object_pass_id(KernelGlobals kg, int object)
|
|||
return kernel_data_fetch(objects, object).pass_id;
|
||||
}
|
||||
|
||||
/* Lightgroup of lamp */
|
||||
/* Light-group of lamp. */
|
||||
|
||||
ccl_device_inline int lamp_lightgroup(KernelGlobals kg, int lamp)
|
||||
{
|
||||
|
@ -298,7 +298,7 @@ ccl_device_inline int lamp_lightgroup(KernelGlobals kg, int lamp)
|
|||
return kernel_data_fetch(lights, lamp).lightgroup;
|
||||
}
|
||||
|
||||
/* Lightgroup of object */
|
||||
/* Light-group of object. */
|
||||
|
||||
ccl_device_inline int object_lightgroup(KernelGlobals kg, int object)
|
||||
{
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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__
|
||||
|
|
|
@ -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 :
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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. */
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -429,8 +429,7 @@ extern "C" int GHOST_HACK_getFirstFile(char buf[FIRSTFILEBUFLG])
|
|||
- (void)applicationWillTerminate:(NSNotification *)aNotification
|
||||
{
|
||||
#if 0
|
||||
G.is_break = false; /* Let Cocoa perform the termination at the end. */
|
||||
WM_exit(C);
|
||||
WM_exit(C, EXIT_SUCCESS);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
|
@ -143,6 +143,11 @@ GHOST_SystemWin32::GHOST_SystemWin32()
|
|||
* blurry scaling and enables WM_DPICHANGED to allow us to draw at proper DPI. */
|
||||
SetProcessDpiAwareness(PROCESS_PER_MONITOR_DPI_AWARE);
|
||||
|
||||
/* Set App Id for the process so our console will be grouped on the Task Bar. */
|
||||
UTF16_ENCODE(BLENDER_WIN_APPID);
|
||||
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) {
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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,
|
||||
),
|
||||
)
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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.",
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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")),
|
||||
),
|
||||
)
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -36,8 +36,10 @@ class AssetStorage;
|
|||
*/
|
||||
class AssetLibrary {
|
||||
eAssetLibraryType library_type_;
|
||||
/** The name this asset library will be displayed in the UI as. Will also be used as a weak way
|
||||
* to identify an asset library (e.g. by #AssetWeakReference). */
|
||||
/**
|
||||
* The name this asset library will be displayed in the UI as. Will also be used as a weak way
|
||||
* to identify an asset library (e.g. by #AssetWeakReference).
|
||||
*/
|
||||
std::string name_;
|
||||
/** If this is an asset library on disk, the top-level directory path. Normalized using
|
||||
* #normalize_directory_path(). Shared pointer so assets can safely point to it, and don't have
|
||||
|
@ -45,7 +47,8 @@ class AssetLibrary {
|
|||
* optimization is used). With thousands of assets this might make a reasonable difference. */
|
||||
std::shared_ptr<std::string> root_path_;
|
||||
|
||||
/** Storage for assets (better said their representations) that are considered to be part of this
|
||||
/**
|
||||
* Storage for assets (better said their representations) that are considered to be part of this
|
||||
* library. Assets are not automatically loaded into this when loading an asset library. Assets
|
||||
* have to be loaded externally and added to this storage via #add_external_asset() or
|
||||
* #add_local_id_asset(). So this really is arbitrary storage as far as #AssetLibrary is
|
||||
|
@ -122,13 +125,15 @@ class AssetLibrary {
|
|||
std::unique_ptr<AssetMetaData> metadata);
|
||||
/** See #AssetLibrary::add_external_asset(). */
|
||||
AssetRepresentation &add_local_id_asset(StringRef relative_asset_path, ID &id);
|
||||
/** Remove an asset from the library that was added using #add_external_asset() or
|
||||
/**
|
||||
* Remove an asset from the library that was added using #add_external_asset() or
|
||||
* #add_local_id_asset(). Can usually be expected to be constant time complexity (worst case may
|
||||
* differ).
|
||||
* \note This is save to call if \a asset is freed (dangling reference), will not perform any
|
||||
* change then.
|
||||
* \return True on success, false if the asset couldn't be found inside the library (also the
|
||||
* case when the reference is dangling). */
|
||||
* case when the reference is dangling).
|
||||
*/
|
||||
bool remove_asset(AssetRepresentation &asset);
|
||||
|
||||
/**
|
||||
|
@ -143,7 +148,8 @@ class AssetLibrary {
|
|||
*
|
||||
* No-op if the catalog cannot be found. This could be the kind of "the
|
||||
* catalog definition file is corrupt/lost" scenario that the simple name is
|
||||
* meant to help recover from. */
|
||||
* meant to help recover from.
|
||||
*/
|
||||
void refresh_catalog_simplename(AssetMetaData *asset_data);
|
||||
|
||||
void on_blend_save_handler_register();
|
||||
|
|
|
@ -30,8 +30,10 @@ class AssetLibrary;
|
|||
|
||||
class AssetRepresentation {
|
||||
AssetIdentifier identifier_;
|
||||
/** Indicate if this is a local or external asset, and as such, which of the union members below
|
||||
* should be used. */
|
||||
/**
|
||||
* Indicate if this is a local or external asset, and as such, which of the union members below
|
||||
* should be used.
|
||||
*/
|
||||
const bool is_local_id_ = false;
|
||||
/** Asset library that owns this asset representation. */
|
||||
const AssetLibrary *owner_asset_library_;
|
||||
|
@ -53,8 +55,10 @@ class AssetRepresentation {
|
|||
StringRef name,
|
||||
std::unique_ptr<AssetMetaData> metadata,
|
||||
const AssetLibrary &owner_asset_library);
|
||||
/** Constructs an asset representation for an ID stored in the current file. This makes the asset
|
||||
* local and fully editable. */
|
||||
/**
|
||||
* Constructs an asset representation for an ID stored in the current file. This makes the asset
|
||||
* local and fully editable.
|
||||
*/
|
||||
AssetRepresentation(AssetIdentifier &&identifier,
|
||||
ID &id,
|
||||
const AssetLibrary &owner_asset_library);
|
||||
|
@ -71,7 +75,8 @@ class AssetRepresentation {
|
|||
|
||||
const AssetIdentifier &get_identifier() const;
|
||||
|
||||
/** Create a weak reference for this asset that can be written to files, but can break under a
|
||||
/**
|
||||
* Create a weak reference for this asset that can be written to files, but can break under a
|
||||
* number of conditions.
|
||||
* A weak reference can only be created if an asset representation is owned by an asset library.
|
||||
*/
|
||||
|
@ -79,18 +84,23 @@ class AssetRepresentation {
|
|||
|
||||
StringRefNull get_name() const;
|
||||
AssetMetaData &get_metadata() const;
|
||||
/** Get the import method to use for this asset. A different one may be used if
|
||||
/**
|
||||
* Get the import method to use for this asset. A different one may be used if
|
||||
* #may_override_import_method() returns true, otherwise, the returned value must be used. If
|
||||
* there is no import method predefined for this asset no value is returned.
|
||||
*/
|
||||
std::optional<eAssetImportMethod> get_import_method() const;
|
||||
/** Returns if this asset may be imported with an import method other than the one returned by
|
||||
/**
|
||||
* Returns if this asset may be imported with an import method other than the one returned by
|
||||
* #get_import_method(). Also returns true if there is no predefined import method
|
||||
* (when #get_import_method() returns no value). */
|
||||
* (when #get_import_method() returns no value).
|
||||
*/
|
||||
bool may_override_import_method() const;
|
||||
bool get_use_relative_path() const;
|
||||
/** If this asset is stored inside this current file (#is_local_id() is true), this returns the
|
||||
* ID's pointer, otherwise null. */
|
||||
/**
|
||||
* If this asset is stored inside this current file (#is_local_id() is true), this returns the
|
||||
* ID's pointer, otherwise null.
|
||||
*/
|
||||
ID *local_id() const;
|
||||
/** Returns if this asset is stored inside this current file, and as such fully editable. */
|
||||
bool is_local_id() const;
|
||||
|
@ -103,9 +113,11 @@ class AssetRepresentation {
|
|||
struct AssetRepresentation;
|
||||
|
||||
std::string AS_asset_representation_full_path_get(const ::AssetRepresentation *asset);
|
||||
/** Get the absolute path to the .blend file containing the given asset. String will be empty if
|
||||
/**
|
||||
* Get the absolute path to the .blend file containing the given asset. String will be empty if
|
||||
* the asset could not be mapped to a valid .blend file path. Valid in this case also means that
|
||||
* the file needs to exist on disk. */
|
||||
* the file needs to exist on disk.
|
||||
*/
|
||||
std::string AS_asset_representation_full_library_path_get(const ::AssetRepresentation *asset);
|
||||
std::optional<eAssetImportMethod> AS_asset_representation_import_method_get(
|
||||
const ::AssetRepresentation *asset_handle);
|
||||
|
|
|
@ -142,9 +142,9 @@ struct DerivedMesh {
|
|||
DMFlagMat *(*getGridFlagMats)(DerivedMesh *dm);
|
||||
unsigned int **(*getGridHidden)(DerivedMesh *dm);
|
||||
|
||||
/** Direct Access Operations
|
||||
/* Direct Access Operations
|
||||
* - Can be undefined
|
||||
* - Must be defined for modifiers that only deform however */
|
||||
* - Must be defined for modifiers that only deform however. */
|
||||
|
||||
/** Release reference to the DerivedMesh. This function decides internally
|
||||
* if the DerivedMesh will be freed, or cached for later use. */
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
|
@ -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);
|
|
@ -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;
|
||||
|
|
|
@ -647,7 +647,8 @@ bool BKE_id_can_be_asset(const struct ID *id);
|
|||
*/
|
||||
struct ID *BKE_id_owner_get(struct ID *id);
|
||||
|
||||
/** Check if that ID can be considered as editable from a high-level (editor) perspective.
|
||||
/**
|
||||
* Check if that ID can be considered as editable from a high-level (editor) perspective.
|
||||
*
|
||||
* NOTE: This used to be done with a check on whether ID was linked or not, but now with system
|
||||
* overrides this is not enough anymore.
|
||||
|
|
|
@ -311,7 +311,8 @@ void BKE_lib_override_library_property_delete(struct IDOverrideLibrary *override
|
|||
bool BKE_lib_override_library_property_search_and_delete(struct IDOverrideLibrary *override,
|
||||
const char *rna_path);
|
||||
|
||||
/** Change the RNA path of a library override on a property.
|
||||
/**
|
||||
* Change the RNA path of a library override on a property.
|
||||
*
|
||||
* No-op if the property override cannot be found.
|
||||
*
|
||||
|
|
|
@ -131,11 +131,14 @@ typedef int (*LibraryIDLinkCallback)(LibraryIDLinkCallbackData *cb_data);
|
|||
/* Flags for the foreach function itself. */
|
||||
enum {
|
||||
IDWALK_NOP = 0,
|
||||
/** The callback will never modify the ID pointers it processes.
|
||||
/**
|
||||
* The callback will never modify the ID pointers it processes.
|
||||
* WARNING: It is very important to pass this flag when valid, as it can lead to important
|
||||
* optimizations and debug/assert code. */
|
||||
* optimizations and debug/assert code.
|
||||
*/
|
||||
IDWALK_READONLY = (1 << 0),
|
||||
/** Recurse into 'descendant' IDs.
|
||||
/**
|
||||
* Recurse into 'descendant' IDs.
|
||||
* Each ID is only processed once. Order of ID processing is not guaranteed.
|
||||
*
|
||||
* Also implies IDWALK_READONLY, and excludes IDWALK_DO_INTERNAL_RUNTIME_POINTERS.
|
||||
|
|
|
@ -73,20 +73,27 @@ enum {
|
|||
*/
|
||||
ID_REMAP_FORCE_OBDATA_IN_EDITMODE = 1 << 7,
|
||||
|
||||
/** Don't touch the special user counts (use when the 'old' remapped ID remains in use):
|
||||
/**
|
||||
* Don't touch the special user counts (use when the 'old' remapped ID remains in use):
|
||||
* - Do not transfer 'fake user' status from old to new ID.
|
||||
* - Do not clear 'extra user' from old ID. */
|
||||
* - Do not clear 'extra user' from old ID.
|
||||
*/
|
||||
ID_REMAP_SKIP_USER_CLEAR = 1 << 16,
|
||||
/** Force handling user count even for IDs that are outside of Main (used in some cases when
|
||||
/**
|
||||
* Force handling user count even for IDs that are outside of Main (used in some cases when
|
||||
* dealing with IDs temporarily out of Main, but which will be put in it ultimately).
|
||||
*/
|
||||
ID_REMAP_FORCE_USER_REFCOUNT = 1 << 17,
|
||||
/** Do NOT handle user count for IDs (used in some cases when dealing with IDs from different
|
||||
/**
|
||||
* Do NOT handle user count for IDs (used in some cases when dealing with IDs from different
|
||||
* BMains, if usercount will be recomputed anyway afterwards, like e.g. in memfile reading during
|
||||
* undo step decoding). */
|
||||
* undo step decoding).
|
||||
*/
|
||||
ID_REMAP_SKIP_USER_REFCOUNT = 1 << 18,
|
||||
/** Do NOT tag IDs which had some of their ID pointers updated for update in the depsgraph, or ID
|
||||
* type specific updates, like e.g. with node trees. */
|
||||
/**
|
||||
* Do NOT tag IDs which had some of their ID pointers updated for update in the depsgraph, or ID
|
||||
* type specific updates, like e.g. with node trees.
|
||||
*/
|
||||
ID_REMAP_SKIP_UPDATE_TAGGING = 1 << 19,
|
||||
/**
|
||||
* Do not attempt to access original ID pointers (triggers usages of
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -316,7 +316,8 @@ typedef struct bNodeType {
|
|||
bool (*poll)(const struct bNodeType *ntype,
|
||||
const struct bNodeTree *nodetree,
|
||||
const char **r_disabled_hint);
|
||||
/** Can this node be added to a node tree?
|
||||
/**
|
||||
* Can this node be added to a node tree?
|
||||
* \param r_disabled_hint: See `poll()`.
|
||||
*/
|
||||
bool (*poll_instance)(const struct bNode *node,
|
||||
|
|
|
@ -96,7 +96,8 @@ class bNodeTreeRuntime : NonCopyable, NonMovable {
|
|||
*/
|
||||
NodeIDVectorSet nodes_by_id;
|
||||
|
||||
/** Execution data.
|
||||
/**
|
||||
* Execution data.
|
||||
*
|
||||
* XXX It would be preferable to completely move this data out of the underlying node tree,
|
||||
* so node tree execution could finally run independent of the tree itself.
|
||||
|
|
|
@ -726,7 +726,8 @@ void BKE_pbvh_face_iter_step(PBVHFaceIter *fd);
|
|||
bool BKE_pbvh_face_iter_done(PBVHFaceIter *fd);
|
||||
void BKE_pbvh_face_iter_finish(PBVHFaceIter *fd);
|
||||
|
||||
/** Iterate over faces inside a PBVHNode. These are either base mesh faces
|
||||
/**
|
||||
* Iterate over faces inside a #PBVHNode. These are either base mesh faces
|
||||
* (for PBVH_FACES and PBVH_GRIDS) or BMesh faces (for PBVH_BMESH).
|
||||
*/
|
||||
#define BKE_pbvh_face_iter_begin(pbvh, node, fd) \
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -2490,7 +2490,8 @@ static void nlaevalchan_combine_quaternion_get_inverted_lower_evalchan(
|
|||
BLI_bitmap_set_all(r_lower_necs->remap_domain.ptr, true, 4);
|
||||
}
|
||||
|
||||
/** Based on blendmode and mix mode, solve for the lower values such that when lower blended or
|
||||
/**
|
||||
* Based on blendmode and mix mode, solve for the lower values such that when lower blended or
|
||||
* combined with upper then we get blended values as a result.
|
||||
*
|
||||
* Only processes blended values in the remap domain. Successfully remapped lower values are placed
|
||||
|
@ -3496,10 +3497,9 @@ static void animsys_evaluate_nla_for_keyframing(PointerRNA *ptr,
|
|||
}
|
||||
}
|
||||
|
||||
/** NOTE: Although we early out, we can still keyframe to the non-pushed action since the
|
||||
/* NOTE: Although we early out, we can still keyframe to the non-pushed action since the
|
||||
* keyframe remap function detects (r_context->strip.act == NULL) and will keyframe without
|
||||
* remapping.
|
||||
*/
|
||||
* remapping. */
|
||||
if (is_action_track_evaluated_without_nla(adt, has_strips)) {
|
||||
BLI_freelistN(&lower_estrips);
|
||||
return;
|
||||
|
|
|
@ -765,7 +765,8 @@ CustomDataLayer *BKE_id_attribute_from_index(ID *id,
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
/** Get list of domain types but with ATTR_DOMAIN_FACE and
|
||||
/**
|
||||
* Get list of domain types but with ATTR_DOMAIN_FACE and
|
||||
* ATTR_DOMAIN_CORNER swapped.
|
||||
*/
|
||||
static void get_domains_types(eAttrDomain domains[ATTR_DOMAIN_NUM])
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
@ -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
|
|
@ -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
|
|
@ -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);
|
||||
|
|
|
@ -1864,9 +1864,8 @@ KeyBlock *BKE_keyblock_add(Key *key, const char *name)
|
|||
kb->slidermin = 0.0f;
|
||||
kb->slidermax = 1.0f;
|
||||
|
||||
/**
|
||||
* \note caller may want to set this to current time, but don't do it here since we need to sort
|
||||
* which could cause problems in some cases, see #BKE_keyblock_add_ctime */
|
||||
/* \note caller may want to set this to current time, but don't do it here since we need to sort
|
||||
* which could cause problems in some cases, see #BKE_keyblock_add_ctime. */
|
||||
kb->pos = curpos + 0.1f; /* only used for absolute shape keys */
|
||||
|
||||
return kb;
|
||||
|
|
|
@ -152,8 +152,10 @@ static bool lib_id_library_local_paths_callback(BPathForeachPathData *bpath_data
|
|||
/**
|
||||
* This has to be called from each make_local_* func, we could call from BKE_lib_id_make_local()
|
||||
* but then the make local functions would not be self contained.
|
||||
* Also note that the id _must_ have a library - campbell */
|
||||
/* TODO: This can probably be replaced by an ID-level version of #BKE_bpath_relative_rebase. */
|
||||
*
|
||||
* NOTE(@ideasman42): that the id _must_ have a library.
|
||||
* TODO: This can probably be replaced by an ID-level version of #BKE_bpath_relative_rebase.
|
||||
*/
|
||||
static void lib_id_library_local_paths(Main *bmain, Library *lib, ID *id)
|
||||
{
|
||||
const char *bpath_user_data[2] = {BKE_main_blendfile_path(bmain), lib->filepath_abs};
|
||||
|
@ -1754,19 +1756,19 @@ static void library_make_local_copying_check(ID *id,
|
|||
BLI_gset_remove(loop_tags, id, NULL);
|
||||
}
|
||||
|
||||
/* NOTE: Old (2.77) version was simply making (tagging) data-blocks as local,
|
||||
* without actually making any check whether they were also indirectly used or not...
|
||||
*
|
||||
* Current version uses regular id_make_local callback, with advanced pre-processing step to
|
||||
* detect all cases of IDs currently indirectly used, but which will be used by local data only
|
||||
* once this function is finished. This allows to avoid any unneeded duplication of IDs, and
|
||||
* hence all time lost afterwards to remove orphaned linked data-blocks. */
|
||||
void BKE_library_make_local(Main *bmain,
|
||||
const Library *lib,
|
||||
GHash *old_to_new_ids,
|
||||
const bool untagged_only,
|
||||
const bool set_fake)
|
||||
{
|
||||
/* NOTE: Old (2.77) version was simply making (tagging) data-blocks as local,
|
||||
* without actually making any check whether they were also indirectly used or not...
|
||||
*
|
||||
* Current version uses regular id_make_local callback, with advanced pre-processing step to
|
||||
* detect all cases of IDs currently indirectly used, but which will be used by local data only
|
||||
* once this function is finished. This allows to avoid any unneeded duplication of IDs, and
|
||||
* hence all time lost afterwards to remove orphaned linked data-blocks. */
|
||||
|
||||
ListBase *lbarray[INDEX_ID_MAX];
|
||||
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -1124,28 +1124,28 @@ static void cache_filepath(
|
|||
char *filepath, const char *dirname, const char *relbase, int frame, int type)
|
||||
{
|
||||
char cachepath[FILE_MAX];
|
||||
const char *fname;
|
||||
const char *filename;
|
||||
|
||||
switch (type) {
|
||||
case CACHE_TYPE_FOAM:
|
||||
fname = "foam_";
|
||||
filename = "foam_";
|
||||
break;
|
||||
case CACHE_TYPE_NORMAL:
|
||||
fname = "normal_";
|
||||
filename = "normal_";
|
||||
break;
|
||||
case CACHE_TYPE_SPRAY:
|
||||
fname = "spray_";
|
||||
filename = "spray_";
|
||||
break;
|
||||
case CACHE_TYPE_SPRAY_INVERSE:
|
||||
fname = "spray_inverse_";
|
||||
filename = "spray_inverse_";
|
||||
break;
|
||||
case CACHE_TYPE_DISPLACE:
|
||||
default:
|
||||
fname = "disp_";
|
||||
filename = "disp_";
|
||||
break;
|
||||
}
|
||||
|
||||
BLI_path_join(cachepath, sizeof(cachepath), dirname, fname);
|
||||
BLI_path_join(cachepath, sizeof(cachepath), dirname, filename);
|
||||
|
||||
BKE_image_path_from_imtype(
|
||||
filepath, cachepath, relbase, frame, R_IMF_IMTYPE_OPENEXR, true, true, "");
|
||||
|
|
|
@ -2351,9 +2351,10 @@ int BKE_sculptsession_vertex_count(const SculptSession *ss)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/** Returns pointer to a CustomData associated with a given domain, if
|
||||
/**
|
||||
* Returns pointer to a CustomData associated with a given domain, if
|
||||
* one exists. If not nullptr is returned (this may happen with e.g.
|
||||
* multires and ATTR_DOMAIN_POINT).
|
||||
* multires and #ATTR_DOMAIN_POINT).
|
||||
*/
|
||||
static CustomData *sculpt_get_cdata(Object *ob, eAttrDomain domain)
|
||||
{
|
||||
|
|
|
@ -1309,15 +1309,15 @@ static int ptcache_path(PTCacheID *pid, char dirname[MAX_PTCACHE_PATH])
|
|||
{
|
||||
const char *blendfile_path = BKE_main_blendfile_path_from_global();
|
||||
Library *lib = (pid->owner_id) ? pid->owner_id->lib : NULL;
|
||||
const char *blendfilename = (lib && (pid->cache->flag & PTCACHE_IGNORE_LIBPATH) == 0) ?
|
||||
lib->filepath_abs :
|
||||
blendfile_path;
|
||||
const char *blendfile_path_lib = (lib && (pid->cache->flag & PTCACHE_IGNORE_LIBPATH) == 0) ?
|
||||
lib->filepath_abs :
|
||||
blendfile_path;
|
||||
|
||||
if (pid->cache->flag & PTCACHE_EXTERNAL) {
|
||||
BLI_strncpy(dirname, pid->cache->path, MAX_PTCACHE_PATH);
|
||||
|
||||
if (BLI_path_is_rel(dirname)) {
|
||||
BLI_path_abs(dirname, blendfilename);
|
||||
BLI_path_abs(dirname, blendfile_path_lib);
|
||||
}
|
||||
|
||||
return BLI_path_slash_ensure(dirname, MAX_PTCACHE_PATH); /* new strlen() */
|
||||
|
@ -1325,14 +1325,14 @@ static int ptcache_path(PTCacheID *pid, char dirname[MAX_PTCACHE_PATH])
|
|||
if ((blendfile_path[0] != '\0') || lib) {
|
||||
char file[MAX_PTCACHE_PATH]; /* we don't want the dir, only the file */
|
||||
|
||||
BLI_path_split_file_part(blendfilename, file, sizeof(file));
|
||||
BLI_path_split_file_part(blendfile_path_lib, file, sizeof(file));
|
||||
/* Remove the `.blend` extension. */
|
||||
BLI_path_extension_strip(file);
|
||||
|
||||
/* Add blend file name to pointcache dir. */
|
||||
BLI_snprintf(dirname, MAX_PTCACHE_PATH, "//" PTCACHE_PATH "%s", file);
|
||||
|
||||
BLI_path_abs(dirname, blendfilename);
|
||||
BLI_path_abs(dirname, blendfile_path_lib);
|
||||
return BLI_path_slash_ensure(dirname, MAX_PTCACHE_PATH); /* new strlen() */
|
||||
}
|
||||
|
||||
|
|
|
@ -256,10 +256,10 @@ bSound *BKE_sound_new_file(Main *bmain, const char *filepath)
|
|||
{
|
||||
bSound *sound;
|
||||
const char *blendfile_path = BKE_main_blendfile_path(bmain);
|
||||
char str[FILE_MAX];
|
||||
char filepath_abs[FILE_MAX];
|
||||
|
||||
STRNCPY(str, filepath);
|
||||
BLI_path_abs(str, blendfile_path);
|
||||
STRNCPY(filepath_abs, filepath);
|
||||
BLI_path_abs(filepath_abs, blendfile_path);
|
||||
|
||||
sound = BKE_libblock_alloc(bmain, ID_SO, BLI_path_basename(filepath), 0);
|
||||
STRNCPY(sound->filepath, filepath);
|
||||
|
@ -284,17 +284,17 @@ bSound *BKE_sound_new_file(Main *bmain, const char *filepath)
|
|||
bSound *BKE_sound_new_file_exists_ex(Main *bmain, const char *filepath, bool *r_exists)
|
||||
{
|
||||
bSound *sound;
|
||||
char str[FILE_MAX], strtest[FILE_MAX];
|
||||
char filepath_abs[FILE_MAX], filepath_test[FILE_MAX];
|
||||
|
||||
STRNCPY(str, filepath);
|
||||
BLI_path_abs(str, BKE_main_blendfile_path(bmain));
|
||||
STRNCPY(filepath_abs, filepath);
|
||||
BLI_path_abs(filepath_abs, BKE_main_blendfile_path(bmain));
|
||||
|
||||
/* first search an identical filepath */
|
||||
for (sound = bmain->sounds.first; sound; sound = sound->id.next) {
|
||||
STRNCPY(strtest, sound->filepath);
|
||||
BLI_path_abs(strtest, ID_BLEND_PATH(bmain, &sound->id));
|
||||
STRNCPY(filepath_test, sound->filepath);
|
||||
BLI_path_abs(filepath_test, ID_BLEND_PATH(bmain, &sound->id));
|
||||
|
||||
if (BLI_path_cmp(strtest, str) == 0) {
|
||||
if (BLI_path_cmp(filepath_test, filepath_abs) == 0) {
|
||||
id_us_plus(&sound->id); /* officially should not, it doesn't link here! */
|
||||
if (r_exists) {
|
||||
*r_exists = true;
|
||||
|
@ -1258,15 +1258,15 @@ bool BKE_sound_stream_info_get(struct Main *main,
|
|||
SoundStreamInfo *sound_info)
|
||||
{
|
||||
const char *blendfile_path = BKE_main_blendfile_path(main);
|
||||
char str[FILE_MAX];
|
||||
char filepath_abs[FILE_MAX];
|
||||
AUD_Sound *sound;
|
||||
AUD_StreamInfo *stream_infos;
|
||||
int stream_count;
|
||||
|
||||
STRNCPY(str, filepath);
|
||||
BLI_path_abs(str, blendfile_path);
|
||||
STRNCPY(filepath_abs, filepath);
|
||||
BLI_path_abs(filepath_abs, blendfile_path);
|
||||
|
||||
sound = AUD_Sound_file(str);
|
||||
sound = AUD_Sound_file(filepath_abs);
|
||||
if (!sound) {
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -366,17 +366,17 @@ VFont *BKE_vfont_load(Main *bmain, const char *filepath)
|
|||
VFont *BKE_vfont_load_exists_ex(struct Main *bmain, const char *filepath, bool *r_exists)
|
||||
{
|
||||
VFont *vfont;
|
||||
char str[FILE_MAX], strtest[FILE_MAX];
|
||||
char filepath_abs[FILE_MAX], filepath_test[FILE_MAX];
|
||||
|
||||
STRNCPY(str, filepath);
|
||||
BLI_path_abs(str, BKE_main_blendfile_path(bmain));
|
||||
STRNCPY(filepath_abs, filepath);
|
||||
BLI_path_abs(filepath_abs, BKE_main_blendfile_path(bmain));
|
||||
|
||||
/* first search an identical filepath */
|
||||
for (vfont = bmain->fonts.first; vfont; vfont = vfont->id.next) {
|
||||
STRNCPY(strtest, vfont->filepath);
|
||||
BLI_path_abs(strtest, ID_BLEND_PATH(bmain, &vfont->id));
|
||||
STRNCPY(filepath_test, vfont->filepath);
|
||||
BLI_path_abs(filepath_test, ID_BLEND_PATH(bmain, &vfont->id));
|
||||
|
||||
if (BLI_path_cmp(strtest, str) == 0) {
|
||||
if (BLI_path_cmp(filepath_test, filepath_abs) == 0) {
|
||||
id_us_plus(&vfont->id); /* officially should not, it doesn't link here! */
|
||||
if (r_exists) {
|
||||
*r_exists = true;
|
||||
|
|
|
@ -103,7 +103,7 @@ typedef struct FFMpegContext {
|
|||
|
||||
static void ffmpeg_dict_set_int(AVDictionary **dict, const char *key, int value);
|
||||
static void ffmpeg_filepath_get(FFMpegContext *context,
|
||||
char string[FILE_MAX],
|
||||
char filepath[FILE_MAX],
|
||||
const struct RenderData *rd,
|
||||
bool preview,
|
||||
const char *suffix);
|
||||
|
@ -1358,7 +1358,7 @@ static void flush_ffmpeg(AVCodecContext *c, AVStream *stream, AVFormatContext *o
|
|||
|
||||
/* Get the output filename-- similar to the other output formats */
|
||||
static void ffmpeg_filepath_get(FFMpegContext *context,
|
||||
char string[FILE_MAX],
|
||||
char filepath[FILE_MAX],
|
||||
const RenderData *rd,
|
||||
bool preview,
|
||||
const char *suffix)
|
||||
|
@ -1369,7 +1369,7 @@ static void ffmpeg_filepath_get(FFMpegContext *context,
|
|||
const char **fe = exts;
|
||||
int sfra, efra;
|
||||
|
||||
if (!string || !exts) {
|
||||
if (!filepath || !exts) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -1382,10 +1382,10 @@ static void ffmpeg_filepath_get(FFMpegContext *context,
|
|||
efra = rd->efra;
|
||||
}
|
||||
|
||||
BLI_strncpy(string, rd->pic, FILE_MAX);
|
||||
BLI_path_abs(string, BKE_main_blendfile_path_from_global());
|
||||
BLI_strncpy(filepath, rd->pic, FILE_MAX);
|
||||
BLI_path_abs(filepath, BKE_main_blendfile_path_from_global());
|
||||
|
||||
BLI_file_ensure_parent_dir_exists(string);
|
||||
BLI_file_ensure_parent_dir_exists(filepath);
|
||||
|
||||
autosplit[0] = '\0';
|
||||
|
||||
|
@ -1397,33 +1397,33 @@ static void ffmpeg_filepath_get(FFMpegContext *context,
|
|||
|
||||
if (rd->scemode & R_EXTENSION) {
|
||||
while (*fe) {
|
||||
if (BLI_strcasecmp(string + strlen(string) - strlen(*fe), *fe) == 0) {
|
||||
if (BLI_strcasecmp(filepath + strlen(filepath) - strlen(*fe), *fe) == 0) {
|
||||
break;
|
||||
}
|
||||
fe++;
|
||||
}
|
||||
|
||||
if (*fe == NULL) {
|
||||
BLI_strncat(string, autosplit, FILE_MAX);
|
||||
BLI_strncat(filepath, autosplit, FILE_MAX);
|
||||
|
||||
BLI_path_frame_range(string, FILE_MAX, sfra, efra, 4);
|
||||
BLI_strncat(string, *exts, FILE_MAX);
|
||||
BLI_path_frame_range(filepath, FILE_MAX, sfra, efra, 4);
|
||||
BLI_strncat(filepath, *exts, FILE_MAX);
|
||||
}
|
||||
else {
|
||||
*(string + strlen(string) - strlen(*fe)) = '\0';
|
||||
BLI_strncat(string, autosplit, FILE_MAX);
|
||||
BLI_strncat(string, *fe, FILE_MAX);
|
||||
*(filepath + strlen(filepath) - strlen(*fe)) = '\0';
|
||||
BLI_strncat(filepath, autosplit, FILE_MAX);
|
||||
BLI_strncat(filepath, *fe, FILE_MAX);
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (BLI_path_frame_check_chars(string)) {
|
||||
BLI_path_frame_range(string, FILE_MAX, sfra, efra, 4);
|
||||
if (BLI_path_frame_check_chars(filepath)) {
|
||||
BLI_path_frame_range(filepath, FILE_MAX, sfra, efra, 4);
|
||||
}
|
||||
|
||||
BLI_strncat(string, autosplit, FILE_MAX);
|
||||
BLI_strncat(filepath, autosplit, FILE_MAX);
|
||||
}
|
||||
|
||||
BLI_path_suffix(string, FILE_MAX, suffix, "");
|
||||
BLI_path_suffix(filepath, FILE_MAX, suffix, "");
|
||||
}
|
||||
|
||||
void BKE_ffmpeg_filepath_get(char *filepath,
|
||||
|
|
|
@ -15,6 +15,10 @@ extern "C" {
|
|||
struct bArgs;
|
||||
typedef struct bArgs bArgs;
|
||||
|
||||
#include <stdarg.h> /* For `va_list`. */
|
||||
|
||||
#include "BLI_compiler_attrs.h"
|
||||
|
||||
/**
|
||||
* Returns the number of extra arguments consumed by the function.
|
||||
* - 0 is normal value,
|
||||
|
@ -25,6 +29,12 @@ typedef int (*BA_ArgCallback)(int argc, const char **argv, void *data);
|
|||
struct bArgs *BLI_args_create(int argc, const char **argv);
|
||||
void BLI_args_destroy(struct bArgs *ba);
|
||||
|
||||
typedef void (*bArgPrintFn)(void *user_data, const char *format, va_list args);
|
||||
void BLI_args_printf(struct bArgs *ba, const char *format, ...);
|
||||
void BLI_args_print_fn_set(struct bArgs *ba,
|
||||
ATTR_PRINTF_FORMAT(2, 0) bArgPrintFn print_fn,
|
||||
void *user_data);
|
||||
|
||||
/** The pass to use for #BLI_args_add. */
|
||||
void BLI_args_pass_set(struct bArgs *ba, int current_pass);
|
||||
|
||||
|
|
|
@ -285,8 +285,9 @@ BLI_INLINE void BLI_listbase_clear(struct ListBase *lb)
|
|||
lb->first = lb->last = (void *)0;
|
||||
}
|
||||
|
||||
/** Validate the integrity of a given ListBase, returns `true` if everything is OK, false
|
||||
* otherwise.
|
||||
/**
|
||||
* Validate the integrity of a given ListBase.
|
||||
* \return true if everything is OK, false otherwise.
|
||||
*/
|
||||
bool BLI_listbase_validate(struct ListBase *lb);
|
||||
|
||||
|
|
|
@ -113,7 +113,7 @@ MINLINE float scalenorm(float a, float b, float x);
|
|||
*/
|
||||
MINLINE double scalenormd(double a, double b, double x);
|
||||
|
||||
/* NOTE: Compilers will upcast all types smaller than int to int when performing arithmetic
|
||||
/* NOTE: Compilers will up-cast all types smaller than int to int when performing arithmetic
|
||||
* operation. */
|
||||
|
||||
MINLINE int square_s(short a);
|
||||
|
|
|
@ -97,7 +97,8 @@ typedef struct BLI_mempool_iter {
|
|||
/** #BLI_mempool.flag */
|
||||
enum {
|
||||
BLI_MEMPOOL_NOP = 0,
|
||||
/** allow iterating on this mempool.
|
||||
/**
|
||||
* Allow iterating on this mempool.
|
||||
*
|
||||
* \note this requires that the first four bytes of the elements
|
||||
* never begin with 'free' (#FREEWORD).
|
||||
|
|
|
@ -42,6 +42,7 @@ bool BLI_path_name_at_index(const char *__restrict path,
|
|||
bool BLI_path_is_unc(const char *path) ATTR_NONNULL(1) ATTR_WARN_UNUSED_RESULT;
|
||||
|
||||
bool BLI_path_is_win32_drive(const char *path);
|
||||
bool BLI_path_is_win32_drive_only(const char *path);
|
||||
bool BLI_path_is_win32_drive_with_slash(const char *path);
|
||||
|
||||
/** \} */
|
||||
|
@ -94,7 +95,7 @@ const char *BLI_path_parent_dir_end(const char *path, size_t path_len)
|
|||
* leveraged by higher layers to support "virtual filenames" which contain
|
||||
* substitution markers delineated between the two characters.
|
||||
*
|
||||
* \return true if \a fname was changed, false otherwise.
|
||||
* \return true if \a filename was changed, false otherwise.
|
||||
*
|
||||
* For now, simply replaces reserved chars (as listed in
|
||||
* https://en.wikipedia.org/wiki/Filename#Reserved_characters_and_words )
|
||||
|
@ -113,8 +114,8 @@ const char *BLI_path_parent_dir_end(const char *path, size_t path_len)
|
|||
* \note On Windows, it also checks for forbidden names
|
||||
* (see https://msdn.microsoft.com/en-us/library/windows/desktop/aa365247%28v=vs.85%29.aspx ).
|
||||
*/
|
||||
bool BLI_path_make_safe_filename_ex(char *fname, bool allow_tokens) ATTR_NONNULL(1);
|
||||
bool BLI_path_make_safe_filename(char *fname) ATTR_NONNULL(1);
|
||||
bool BLI_path_make_safe_filename_ex(char *filename, bool allow_tokens) ATTR_NONNULL(1);
|
||||
bool BLI_path_make_safe_filename(char *filename) ATTR_NONNULL(1);
|
||||
|
||||
/**
|
||||
* Make given path OS-safe.
|
||||
|
|
|
@ -66,8 +66,9 @@
|
|||
namespace blender {
|
||||
|
||||
template<
|
||||
/** Type of the elements that are stored in this set. It has to be movable. Furthermore, the
|
||||
* hash and is-equal functions have to support it.
|
||||
/**
|
||||
* Type of the elements that are stored in this set. It has to be movable.
|
||||
* Furthermore, the hash and is-equal functions have to support it.
|
||||
*/
|
||||
typename Key,
|
||||
/**
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue