* Merge branch 'master' into temp_bmesh_multires
* Implemented DynTopo option to dissolve 3 and 4-valence vertices. * Fixed bug in dyntopo collapse customdata snapping.
This commit is contained in:
commit
64337d087d
|
@ -35,7 +35,6 @@ Checks: >
|
|||
-modernize-use-auto,
|
||||
-modernize-use-trailing-return-type,
|
||||
-modernize-avoid-c-arrays,
|
||||
-modernize-use-equals-default,
|
||||
-modernize-use-nodiscard,
|
||||
-modernize-loop-convert,
|
||||
-modernize-pass-by-value,
|
||||
|
|
|
@ -75,7 +75,7 @@ FIND_PATH(OSL_SHADER_DIR
|
|||
/usr/share/OSL/
|
||||
/usr/include/OSL/
|
||||
PATH_SUFFIXES
|
||||
shaders
|
||||
share/OSL/shaders
|
||||
)
|
||||
|
||||
# handle the QUIETLY and REQUIRED arguments and set OSL_FOUND to TRUE if
|
||||
|
|
|
@ -22,7 +22,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 <path-to-blender> <output-filename>
|
||||
blender.1.py --blender <path-to-blender> --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.
|
||||
|
@ -30,108 +30,147 @@ and <output-filename> is where to write the generated man page.
|
|||
|
||||
# <pep8 compliant>
|
||||
|
||||
import argparse
|
||||
import os
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
import time
|
||||
|
||||
from typing import (
|
||||
Dict,
|
||||
TextIO,
|
||||
)
|
||||
|
||||
def man_format(data):
|
||||
|
||||
def man_format(data: str) -> str:
|
||||
data = data.replace("-", "\\-")
|
||||
data = data.replace("\t", " ")
|
||||
return data
|
||||
|
||||
|
||||
if len(sys.argv) != 3:
|
||||
import getopt
|
||||
raise getopt.GetoptError("Usage: %s <path-to-blender> <output-filename>" % sys.argv[0])
|
||||
def blender_extract_info(blender_bin: str) -> Dict[str, str]:
|
||||
|
||||
blender_bin = sys.argv[1]
|
||||
outfilename = sys.argv[2]
|
||||
blender_env = {
|
||||
"ASAN_OPTIONS": "exitcode=0:" + os.environ.get("ASAN_OPTIONS", ""),
|
||||
}
|
||||
|
||||
cmd = [blender_bin, "--help"]
|
||||
print(" executing:", " ".join(cmd))
|
||||
ASAN_OPTIONS = "exitcode=0:" + os.environ.get("ASAN_OPTIONS", "")
|
||||
blender_help = subprocess.run(
|
||||
cmd, env={"ASAN_OPTIONS": ASAN_OPTIONS}, check=True, stdout=subprocess.PIPE).stdout.decode(encoding="utf-8")
|
||||
blender_version = subprocess.run(
|
||||
[blender_bin, "--version"], env={"ASAN_OPTIONS": ASAN_OPTIONS}, check=True, stdout=subprocess.PIPE).stdout.decode(encoding="utf-8").strip()
|
||||
blender_version, blender_date = (blender_version.split("build") + [None, None])[0:2]
|
||||
blender_version = blender_version.rstrip().partition(" ")[2] # remove 'Blender' prefix.
|
||||
if blender_date is None:
|
||||
# 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()))))
|
||||
else:
|
||||
blender_date = blender_date.strip().partition(" ")[2] # remove 'date:' prefix
|
||||
date_string = time.strftime("%B %d, %Y", time.strptime(blender_date, "%Y-%m-%d"))
|
||||
blender_help = subprocess.run(
|
||||
[blender_bin, "--help"],
|
||||
env=blender_env,
|
||||
check=True,
|
||||
stdout=subprocess.PIPE,
|
||||
).stdout.decode(encoding="utf-8")
|
||||
|
||||
outfile = open(outfilename, "w")
|
||||
fw = outfile.write
|
||||
blender_version_ouput = subprocess.run(
|
||||
[blender_bin, "--version"],
|
||||
env=blender_env,
|
||||
check=True,
|
||||
stdout=subprocess.PIPE,
|
||||
).stdout.decode(encoding="utf-8")
|
||||
|
||||
fw('.TH "BLENDER" "1" "%s" "Blender %s"\n' % (date_string, blender_version.replace(".", "\\&.")))
|
||||
# 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_ouput.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
|
||||
|
||||
fw('''
|
||||
if not blender_date:
|
||||
# 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()))))
|
||||
else:
|
||||
date_string = time.strftime("%B %d, %Y", time.strptime(blender_date, "%Y-%m-%d"))
|
||||
|
||||
return {
|
||||
"help": blender_help,
|
||||
"version": blender_version,
|
||||
"date": date_string,
|
||||
}
|
||||
|
||||
|
||||
def man_page_from_blender_help(fh: TextIO, blender_bin: str) -> None:
|
||||
blender_info = blender_extract_info(blender_bin)
|
||||
|
||||
# Header Content.
|
||||
fh.write(
|
||||
'.TH "BLENDER" "1" "%s" "Blender %s"\n' %
|
||||
(blender_info["date"], blender_info["version"].replace(".", "\\&."))
|
||||
)
|
||||
|
||||
fh.write(r'''
|
||||
.SH NAME
|
||||
blender \- a full-featured 3D application''')
|
||||
|
||||
fw('''
|
||||
fh.write(r'''
|
||||
.SH SYNOPSIS
|
||||
.B blender [args ...] [file] [args ...]''')
|
||||
|
||||
fw('''
|
||||
fh.write(r'''
|
||||
.br
|
||||
.SH DESCRIPTION
|
||||
.PP
|
||||
.B blender
|
||||
is a full-featured 3D application. It supports the entirety of the 3D pipeline - modeling, rigging, animation, simulation, rendering, compositing, motion tracking, and video editing.
|
||||
is a full-featured 3D application. It supports the entirety of the 3D pipeline - '''
|
||||
'''modeling, rigging, animation, simulation, rendering, compositing, motion tracking, and video editing.
|
||||
|
||||
Use Blender to create 3D images and animations, films and commercials, content for games, architectural and industrial visualizatons, and scientific visualizations.
|
||||
Use Blender to create 3D images and animations, films and commercials, content for games, '''
|
||||
r'''architectural and industrial visualizatons, and scientific visualizations.
|
||||
|
||||
https://www.blender.org''')
|
||||
|
||||
fw('''
|
||||
fh.write(r'''
|
||||
.SH OPTIONS''')
|
||||
|
||||
fw("\n\n")
|
||||
fh.write("\n\n")
|
||||
|
||||
lines = [line.rstrip() for line in blender_help.split("\n")]
|
||||
# Body Content.
|
||||
|
||||
while lines:
|
||||
l = lines.pop(0)
|
||||
if l.startswith("Environment Variables:"):
|
||||
fw('.SH "ENVIRONMENT VARIABLES"\n')
|
||||
elif l.endswith(":"): # one line
|
||||
fw('.SS "%s"\n\n' % l)
|
||||
elif l.startswith("-") or l.startswith("/"): # can be multi line
|
||||
lines = [line.rstrip() for line in blender_info["help"].split("\n")]
|
||||
|
||||
fw('.TP\n')
|
||||
fw('.B %s\n' % man_format(l))
|
||||
while lines:
|
||||
l = lines.pop(0)
|
||||
if l.startswith("Environment Variables:"):
|
||||
fh.write('.SH "ENVIRONMENT VARIABLES"\n')
|
||||
elif l.endswith(":"): # One line.
|
||||
fh.write('.SS "%s"\n\n' % l)
|
||||
elif l.startswith("-") or l.startswith("/"): # Can be multi line.
|
||||
fh.write('.TP\n')
|
||||
fh.write('.B %s\n' % man_format(l))
|
||||
|
||||
while lines:
|
||||
# line with no
|
||||
if lines[0].strip() and len(lines[0].lstrip()) == len(lines[0]): # no white space
|
||||
break
|
||||
while lines:
|
||||
# line with no
|
||||
if lines[0].strip() and len(lines[0].lstrip()) == len(lines[0]): # No white space.
|
||||
break
|
||||
|
||||
if not l: # second blank line
|
||||
fw('.IP\n')
|
||||
else:
|
||||
fw('.br\n')
|
||||
if not l: # Second blank line.
|
||||
fh.write('.IP\n')
|
||||
else:
|
||||
fh.write('.br\n')
|
||||
|
||||
l = lines.pop(0)
|
||||
l = l[1:] # remove first whitespace (tab)
|
||||
l = lines.pop(0)
|
||||
if l:
|
||||
assert(l.startswith('\t'))
|
||||
l = l[1:] # Remove first white-space (tab).
|
||||
|
||||
fw('%s\n' % man_format(l))
|
||||
fh.write('%s\n' % man_format(l))
|
||||
|
||||
else:
|
||||
if not l.strip():
|
||||
fw('.br\n')
|
||||
else:
|
||||
fw('%s\n' % man_format(l))
|
||||
if not l.strip():
|
||||
fh.write('.br\n')
|
||||
else:
|
||||
fh.write('%s\n' % man_format(l))
|
||||
|
||||
# footer
|
||||
# Footer Content.
|
||||
|
||||
fw('''
|
||||
fh.write(r'''
|
||||
.br
|
||||
.SH SEE ALSO
|
||||
.B luxrender(1)
|
||||
|
@ -143,5 +182,33 @@ This manpage was written for a Debian GNU/Linux system by Daniel Mester
|
|||
<cyril.brulebois@enst-bretagne.fr> and Dan Eicher <dan@trollwerks.org>.
|
||||
''')
|
||||
|
||||
outfile.close()
|
||||
print("written:", outfilename)
|
||||
|
||||
def create_argparse() -> argparse.ArgumentParser:
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument(
|
||||
"--output",
|
||||
required=True,
|
||||
help="The man page to write to."
|
||||
)
|
||||
parser.add_argument(
|
||||
"--blender",
|
||||
required=True,
|
||||
help="Path to the blender binary."
|
||||
)
|
||||
|
||||
return parser
|
||||
|
||||
|
||||
def main() -> None:
|
||||
parser = create_argparse()
|
||||
args = parser.parse_args()
|
||||
|
||||
blender_bin = args.blender
|
||||
output_filename = args.output
|
||||
|
||||
with open(output_filename, "w", encoding="utf-8") as fh:
|
||||
man_page_from_blender_help(fh, blender_bin)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
|
|
@ -219,9 +219,12 @@ def do_versions(self):
|
|||
|
||||
if version <= (2, 93, 16):
|
||||
cscene = scene.cycles
|
||||
if scene.render.use_simplify and \
|
||||
(cscene.ao_bounces or cscene.ao_bounces_render):
|
||||
ao_bounces = cscene.get("ao_bounces", 0)
|
||||
ao_bounces_render = cscene.get("ao_bounces_render", 0)
|
||||
if scene.render.use_simplify and (ao_bounces or ao_bounces_render):
|
||||
cscene.use_fast_gi = True
|
||||
cscene.ao_bounces = ao_bounces
|
||||
cscene.ao_bounces_render = ao_bounces_render
|
||||
else:
|
||||
cscene.ao_bounces = 1
|
||||
cscene.ao_bounces_render = 1
|
||||
|
|
|
@ -26,7 +26,7 @@
|
|||
#ifdef WITH_OPENVDB
|
||||
# include <openvdb/openvdb.h>
|
||||
openvdb::GridBase::ConstPtr BKE_volume_grid_openvdb_for_read(const struct Volume *volume,
|
||||
struct VolumeGrid *grid);
|
||||
const struct VolumeGrid *grid);
|
||||
#endif
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
@ -227,7 +227,7 @@ class BlenderVolumeLoader : public VDBImageLoader {
|
|||
const bool unload = !b_volume_grid.is_loaded();
|
||||
|
||||
::Volume *volume = (::Volume *)b_volume.ptr.data;
|
||||
VolumeGrid *volume_grid = (VolumeGrid *)b_volume_grid.ptr.data;
|
||||
const VolumeGrid *volume_grid = (VolumeGrid *)b_volume_grid.ptr.data;
|
||||
grid = BKE_volume_grid_openvdb_for_read(volume, volume_grid);
|
||||
|
||||
if (unload) {
|
||||
|
|
|
@ -299,7 +299,7 @@ class Scene : public NodeOwner {
|
|||
* node array (e.g. Scene::geometry for Geometry nodes) and tag the appropriate
|
||||
* manager for an update.
|
||||
*/
|
||||
template<typename T, typename... Args> T *create_node(Args &&...args)
|
||||
template<typename T, typename... Args> T *create_node(Args &&... args)
|
||||
{
|
||||
T *node = new T(args...);
|
||||
node->set_owner(this);
|
||||
|
|
|
@ -788,7 +788,7 @@ ccl_device_inline float compare_floats(float a, float b, float abs_diff, int ulp
|
|||
}
|
||||
|
||||
/* Calculate the angle between the two vectors a and b.
|
||||
* The usual approach acos(dot(a, b)) has severe precision issues for small angles,
|
||||
* The usual approach `acos(dot(a, b))` has severe precision issues for small angles,
|
||||
* which are avoided by this method.
|
||||
* Based on "Mangled Angles" from https://people.eecs.berkeley.edu/~wkahan/Mindless.pdf
|
||||
*/
|
||||
|
|
|
@ -1131,7 +1131,8 @@ GHOST_TSuccess GHOST_WindowCocoa::hasCursorShape(GHOST_TStandardCursor shape)
|
|||
return success;
|
||||
}
|
||||
|
||||
/** Reverse the bits in a GHOST_TUns8
|
||||
/* Reverse the bits in a GHOST_TUns8 */
|
||||
#if 0
|
||||
static GHOST_TUns8 uns8ReverseBits(GHOST_TUns8 ch)
|
||||
{
|
||||
ch= ((ch >> 1) & 0x55) | ((ch << 1) & 0xAA);
|
||||
|
@ -1139,7 +1140,7 @@ static GHOST_TUns8 uns8ReverseBits(GHOST_TUns8 ch)
|
|||
ch= ((ch >> 4) & 0x0F) | ((ch << 4) & 0xF0);
|
||||
return ch;
|
||||
}
|
||||
*/
|
||||
#endif
|
||||
|
||||
/** Reverse the bits in a GHOST_TUns16 */
|
||||
static GHOST_TUns16 uns16ReverseBits(GHOST_TUns16 shrt)
|
||||
|
|
|
@ -555,7 +555,7 @@ class GHOST_WindowWin32 : public GHOST_Window {
|
|||
|
||||
/* Wintab API */
|
||||
struct {
|
||||
/** WinTab DLL handle. */
|
||||
/** `WinTab.dll` handle. */
|
||||
HMODULE handle = NULL;
|
||||
|
||||
/** API functions */
|
||||
|
@ -574,7 +574,7 @@ class GHOST_WindowWin32 : public GHOST_Window {
|
|||
|
||||
GHOST_TWindowState m_normal_state;
|
||||
|
||||
/** user32 dll handle*/
|
||||
/** `user32.dll` handle */
|
||||
HMODULE m_user32;
|
||||
GHOST_WIN32_GetPointerInfoHistory m_fpGetPointerInfoHistory;
|
||||
GHOST_WIN32_GetPointerPenInfoHistory m_fpGetPointerPenInfoHistory;
|
||||
|
|
|
@ -57,9 +57,11 @@
|
|||
extern "C" {
|
||||
#endif
|
||||
|
||||
/** Returns the length of the allocated memory segment pointed at
|
||||
/**
|
||||
* Returns the length of the allocated memory segment pointed at
|
||||
* by vmemh. If the pointer was not previously allocated by this
|
||||
* module, the result is undefined.*/
|
||||
* module, the result is undefined.
|
||||
*/
|
||||
extern size_t (*MEM_allocN_len)(const void *vmemh) ATTR_WARN_UNUSED_RESULT;
|
||||
|
||||
/**
|
||||
|
@ -103,7 +105,8 @@ extern void *(*MEM_recallocN_id)(void *vmemh,
|
|||
/**
|
||||
* Allocate a block of memory of size len, with tag name str. The
|
||||
* memory is cleared. The name must be static, because only a
|
||||
* pointer to it is stored ! */
|
||||
* pointer to it is stored!
|
||||
*/
|
||||
extern void *(*MEM_callocN)(size_t len, const char *str) /* ATTR_MALLOC */ ATTR_WARN_UNUSED_RESULT
|
||||
ATTR_ALLOC_SIZE(1) ATTR_NONNULL(2);
|
||||
|
||||
|
@ -143,12 +146,15 @@ extern void *(*MEM_mallocN_aligned)(size_t len,
|
|||
const char *str) /* ATTR_MALLOC */ ATTR_WARN_UNUSED_RESULT
|
||||
ATTR_ALLOC_SIZE(1) ATTR_NONNULL(3);
|
||||
|
||||
/** Print a list of the names and sizes of all allocated memory
|
||||
* blocks. as a python dict for easy investigation */
|
||||
/**
|
||||
* Print a list of the names and sizes of all allocated memory
|
||||
* blocks. as a python dict for easy investigation.
|
||||
*/
|
||||
extern void (*MEM_printmemlist_pydict)(void);
|
||||
|
||||
/** Print a list of the names and sizes of all allocated memory
|
||||
* blocks. */
|
||||
/**
|
||||
* Print a list of the names and sizes of all allocated memory blocks.
|
||||
*/
|
||||
extern void (*MEM_printmemlist)(void);
|
||||
|
||||
/** calls the function on all allocated memory blocks. */
|
||||
|
@ -163,7 +169,8 @@ extern void (*MEM_set_error_callback)(void (*func)(const char *));
|
|||
/**
|
||||
* Are the start/end block markers still correct ?
|
||||
*
|
||||
* \retval true for correct memory, false for corrupted memory. */
|
||||
* \retval true for correct memory, false for corrupted memory.
|
||||
*/
|
||||
extern bool (*MEM_consistency_check)(void);
|
||||
|
||||
/** Attempt to enforce OSX (or other OS's) to have malloc and stack nonzero */
|
||||
|
@ -209,8 +216,10 @@ extern size_t (*MEM_get_peak_memory)(void) ATTR_WARN_UNUSED_RESULT;
|
|||
extern const char *(*MEM_name_ptr)(void *vmemh);
|
||||
#endif
|
||||
|
||||
/** This should be called as early as possible in the program. When it has been called, information
|
||||
* about memory leaks will be printed on exit. */
|
||||
/**
|
||||
* This should be called as early as possible in the program. When it has been called, information
|
||||
* about memory leaks will be printed on exit.
|
||||
*/
|
||||
void MEM_init_memleak_detection(void);
|
||||
|
||||
/**
|
||||
|
@ -219,9 +228,11 @@ void MEM_init_memleak_detection(void);
|
|||
*/
|
||||
void MEM_use_memleak_detection(bool enabled);
|
||||
|
||||
/** When this has been called and memory leaks have been detected, the process will have an exit
|
||||
/**
|
||||
* When this has been called and memory leaks have been detected, the process will have an exit
|
||||
* code that indicates failure. This can be used for when checking for memory leaks with automated
|
||||
* tests. */
|
||||
* tests.
|
||||
*/
|
||||
void MEM_enable_fail_on_memleak(void);
|
||||
|
||||
/* Switch allocator to fast mode, with less tracking.
|
||||
|
|
|
@ -35,7 +35,7 @@ Development
|
|||
License
|
||||
-------
|
||||
|
||||
Blender as a whole is licensed under the GNU Public License, Version 3.
|
||||
Blender as a whole is licensed under the GNU General Public License, Version 3.
|
||||
Individual files may have a different, but compatible license.
|
||||
|
||||
See `blender.org/about/license <https://www.blender.org/about/license>`__ for details.
|
||||
|
|
|
@ -20,7 +20,6 @@
|
|||
from __future__ import annotations
|
||||
|
||||
import bpy
|
||||
import nodeitems_utils
|
||||
from bpy.types import (
|
||||
Operator,
|
||||
PropertyGroup,
|
||||
|
@ -195,6 +194,8 @@ class NODE_OT_add_search(NodeAddOperator, Operator):
|
|||
|
||||
# Create an enum list from node items
|
||||
def node_enum_items(self, context):
|
||||
import nodeitems_utils
|
||||
|
||||
enum_items = NODE_OT_add_search._enum_item_hack
|
||||
enum_items.clear()
|
||||
|
||||
|
@ -210,6 +211,8 @@ class NODE_OT_add_search(NodeAddOperator, Operator):
|
|||
|
||||
# Look up the item based on index
|
||||
def find_node_item(self, context):
|
||||
import nodeitems_utils
|
||||
|
||||
node_item = int(self.node_item)
|
||||
for index, item in enumerate(nodeitems_utils.node_items_iter(context)):
|
||||
if index == node_item:
|
||||
|
|
|
@ -38,13 +38,12 @@ class PhysicButtonsPanel:
|
|||
def physics_add(layout, md, name, type, typeicon, toggles):
|
||||
row = layout.row(align=True)
|
||||
if md:
|
||||
row.context_pointer_set("modifier", md)
|
||||
row.operator(
|
||||
"object.modifier_remove",
|
||||
text=name,
|
||||
text_ctxt=i18n_contexts.default,
|
||||
icon='X',
|
||||
)
|
||||
).modifier = md.name
|
||||
if toggles:
|
||||
row.prop(md, "show_viewport", text="")
|
||||
row.prop(md, "show_render", text="")
|
||||
|
|
|
@ -18,7 +18,6 @@
|
|||
|
||||
# <pep8 compliant>
|
||||
import bpy
|
||||
import nodeitems_utils
|
||||
from bpy.types import Header, Menu, Panel
|
||||
from bpy.app.translations import pgettext_iface as iface_
|
||||
from bpy.app.translations import contexts as i18n_contexts
|
||||
|
@ -225,6 +224,8 @@ class NODE_MT_add(bpy.types.Menu):
|
|||
bl_translation_context = i18n_contexts.operator_default
|
||||
|
||||
def draw(self, context):
|
||||
import nodeitems_utils
|
||||
|
||||
layout = self.layout
|
||||
|
||||
layout.operator_context = 'INVOKE_DEFAULT'
|
||||
|
|
|
@ -51,13 +51,13 @@ class OUTLINER_HT_header(Header):
|
|||
row.prop(space, "use_sync_select", icon='UV_SYNC_SELECT', text="")
|
||||
|
||||
row = layout.row(align=True)
|
||||
if display_mode in {'SCENES', 'VIEW_LAYER'}:
|
||||
if display_mode in {'SCENES', 'VIEW_LAYER', 'LIBRARY_OVERRIDES'}:
|
||||
row.popover(
|
||||
panel="OUTLINER_PT_filter",
|
||||
text="",
|
||||
icon='FILTER',
|
||||
)
|
||||
elif display_mode in {'LIBRARIES', 'ORPHAN_DATA'}:
|
||||
if display_mode in {'LIBRARIES', 'LIBRARY_OVERRIDES', 'ORPHAN_DATA'}:
|
||||
row.prop(space, "use_filter_id_type", text="", icon='FILTER')
|
||||
sub = row.row(align=True)
|
||||
sub.active = space.use_filter_id_type
|
||||
|
@ -341,19 +341,26 @@ class OUTLINER_PT_filter(Panel):
|
|||
col = layout.column(align=True)
|
||||
col.prop(space, "use_sort_alpha")
|
||||
|
||||
row = layout.row(align=True)
|
||||
row.prop(space, "use_sync_select", text="Sync Selection")
|
||||
if display_mode not in {'LIBRARY_OVERRIDES'}:
|
||||
row = layout.row(align=True)
|
||||
row.prop(space, "use_sync_select", text="Sync Selection")
|
||||
|
||||
row = layout.row(align=True)
|
||||
row.prop(space, "show_mode_column", text="Show Mode Column")
|
||||
layout.separator()
|
||||
row = layout.row(align=True)
|
||||
row.prop(space, "show_mode_column", text="Show Mode Column")
|
||||
layout.separator()
|
||||
|
||||
col = layout.column(align=True)
|
||||
col.label(text="Search")
|
||||
col.prop(space, "use_filter_complete", text="Exact Match")
|
||||
col.prop(space, "use_filter_case_sensitive", text="Case Sensitive")
|
||||
|
||||
if display_mode != 'VIEW_LAYER':
|
||||
if display_mode in {'LIBRARY_OVERRIDES'} and bpy.data.libraries:
|
||||
col.separator()
|
||||
row = col.row()
|
||||
row.label(icon='LIBRARY_DATA_OVERRIDE')
|
||||
row.prop(space, "use_filter_lib_override_system", text="System Overrides")
|
||||
|
||||
if display_mode not in {'VIEW_LAYER'}:
|
||||
return
|
||||
|
||||
layout.separator()
|
||||
|
@ -405,10 +412,6 @@ class OUTLINER_PT_filter(Panel):
|
|||
row = sub.row()
|
||||
row.label(icon='EMPTY_DATA')
|
||||
row.prop(space, "use_filter_object_empty", text="Empties")
|
||||
row = sub.row()
|
||||
if bpy.data.libraries:
|
||||
row.label(icon='LIBRARY_DATA_OVERRIDE')
|
||||
row.prop(space, "use_filter_lib_override", text="Library Overrides")
|
||||
|
||||
if (
|
||||
bpy.data.curves or
|
||||
|
@ -425,6 +428,16 @@ class OUTLINER_PT_filter(Panel):
|
|||
row.label(icon='BLANK1')
|
||||
row.prop(space, "use_filter_object_others", text="Others")
|
||||
|
||||
if bpy.data.libraries:
|
||||
col.separator()
|
||||
row = col.row()
|
||||
row.label(icon='LIBRARY_DATA_OVERRIDE')
|
||||
row.prop(space, "use_filter_lib_override", text="Library Overrides")
|
||||
row = col.row()
|
||||
row.label(icon='LIBRARY_DATA_OVERRIDE')
|
||||
row.prop(space, "use_filter_lib_override_system", text="System Overrides")
|
||||
|
||||
|
||||
|
||||
classes = (
|
||||
OUTLINER_HT_header,
|
||||
|
|
|
@ -812,6 +812,7 @@ class VIEW3D_PT_sculpt_dyntopo_advanced(Panel, View3DPaintPanel):
|
|||
col = layout.column()
|
||||
do_prop("subdivide")
|
||||
do_prop("collapse")
|
||||
do_prop("cleanup")
|
||||
do_prop("spacing")
|
||||
do_prop("detail_range")
|
||||
do_prop("detail_percent")
|
||||
|
@ -870,6 +871,7 @@ class VIEW3D_PT_sculpt_dyntopo(Panel, View3DPaintPanel):
|
|||
if sculpt.detail_type_method in {'CONSTANT', 'MANUAL'}:
|
||||
col.operator("sculpt.detail_flood_fill")
|
||||
|
||||
col.prop(sculpt, "use_dyntopo_cleanup")
|
||||
col.prop(sculpt, "use_smooth_shading")
|
||||
col.prop(sculpt, "use_flat_vcol_shading")
|
||||
|
||||
|
|
|
@ -505,6 +505,7 @@ geometry_node_categories = [
|
|||
NodeItem("ShaderNodeCombineRGB"),
|
||||
]),
|
||||
GeometryNodeCategory("GEO_GEOMETRY", "Geometry", items=[
|
||||
NodeItem("GeometryNodeBoundBox"),
|
||||
NodeItem("GeometryNodeTransform"),
|
||||
NodeItem("GeometryNodeJoinGeometry"),
|
||||
]),
|
||||
|
|
|
@ -26,22 +26,28 @@
|
|||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct ListBase;
|
||||
struct CurveCache;
|
||||
struct Object;
|
||||
struct Path;
|
||||
|
||||
/* ---------------------------------------------------- */
|
||||
/* Curve Paths */
|
||||
|
||||
void free_path(struct Path *path);
|
||||
void calc_curvepath(struct Object *ob, struct ListBase *nurbs);
|
||||
bool where_on_path(const struct Object *ob,
|
||||
float ctime,
|
||||
float r_vec[4],
|
||||
float r_dir[3],
|
||||
float r_quat[4],
|
||||
float *r_radius,
|
||||
float *r_weight);
|
||||
int BKE_anim_path_get_array_size(const struct CurveCache *curve_cache);
|
||||
float BKE_anim_path_get_length(const struct CurveCache *curve_cache);
|
||||
|
||||
/* This function populates the 'ob->runtime.curve_cache->anim_path_accum_length' data.
|
||||
* You should never have to call this manually as it should already have been called by
|
||||
* 'BKE_displist_make_curveTypes'. Do not call this manually unless you know what you are doing.
|
||||
*/
|
||||
void BKE_anim_path_calc_data(struct Object *ob);
|
||||
|
||||
bool BKE_where_on_path(const struct Object *ob,
|
||||
float ctime,
|
||||
float r_vec[4],
|
||||
float r_dir[3],
|
||||
float r_quat[4],
|
||||
float *r_radius,
|
||||
float *r_weight);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
|
|
@ -227,6 +227,8 @@ void BKE_scene_objects_iterator_begin(struct BLI_Iterator *iter, void *data_in);
|
|||
void BKE_scene_objects_iterator_next(struct BLI_Iterator *iter);
|
||||
void BKE_scene_objects_iterator_end(struct BLI_Iterator *iter);
|
||||
|
||||
struct GSet *BKE_scene_objects_as_gset(struct Scene *scene, struct GSet *objects_gset);
|
||||
|
||||
#define FOREACH_SCENE_COLLECTION_BEGIN(scene, _instance) \
|
||||
ITER_BEGIN (BKE_scene_collections_iterator_begin, \
|
||||
BKE_scene_collections_iterator_next, \
|
||||
|
|
|
@ -50,7 +50,13 @@ typedef struct CurveCache {
|
|||
ListBase disp;
|
||||
ListBase bev;
|
||||
ListBase deformed_nurbs;
|
||||
struct Path *path;
|
||||
/* This array contains the accumulative length of the curve segments.
|
||||
* So you can see this as a "total distance traveled" along the curve.
|
||||
* The first entry is the length between point 0 and 1 while the last is the
|
||||
* total length of the curve.
|
||||
*
|
||||
* Used by #BKE_where_on_path. */
|
||||
const float *anim_path_accum_length;
|
||||
} CurveCache;
|
||||
|
||||
/* Definitions needed for shape keys */
|
||||
|
|
|
@ -135,12 +135,18 @@ class GeometryComponent {
|
|||
|
||||
public:
|
||||
GeometryComponent(GeometryComponentType type);
|
||||
virtual ~GeometryComponent();
|
||||
virtual ~GeometryComponent() = default;
|
||||
static GeometryComponent *create(GeometryComponentType component_type);
|
||||
|
||||
/* The returned component should be of the same type as the type this is called on. */
|
||||
virtual GeometryComponent *copy() const = 0;
|
||||
|
||||
/* Direct data is everything except for instances of objects/collections.
|
||||
* If this returns true, the geometry set can be cached and is still valid after e.g. modifier
|
||||
* evaluation ends. Instances can only be valid as long as the data they instance is valid. */
|
||||
virtual bool owns_direct_data() const = 0;
|
||||
virtual void ensure_owns_direct_data() = 0;
|
||||
|
||||
void user_add() const;
|
||||
void user_remove() const;
|
||||
bool is_mutable() const;
|
||||
|
@ -180,7 +186,7 @@ class GeometryComponent {
|
|||
const CustomDataType data_type);
|
||||
|
||||
blender::Set<std::string> attribute_names() const;
|
||||
void attribute_foreach(const AttributeForeachCallback callback) const;
|
||||
bool attribute_foreach(const AttributeForeachCallback callback) const;
|
||||
|
||||
virtual bool is_empty() const;
|
||||
|
||||
|
@ -315,6 +321,8 @@ struct GeometrySet {
|
|||
|
||||
void clear();
|
||||
|
||||
void ensure_owns_direct_data();
|
||||
|
||||
/* Utility methods for creation. */
|
||||
static GeometrySet create_with_mesh(
|
||||
Mesh *mesh, GeometryOwnershipType ownership = GeometryOwnershipType::Owned);
|
||||
|
@ -374,6 +382,9 @@ class MeshComponent : public GeometryComponent {
|
|||
|
||||
bool is_empty() const final;
|
||||
|
||||
bool owns_direct_data() const override;
|
||||
void ensure_owns_direct_data() override;
|
||||
|
||||
static constexpr inline GeometryComponentType static_type = GEO_COMPONENT_TYPE_MESH;
|
||||
|
||||
private:
|
||||
|
@ -404,6 +415,9 @@ class PointCloudComponent : public GeometryComponent {
|
|||
|
||||
bool is_empty() const final;
|
||||
|
||||
bool owns_direct_data() const override;
|
||||
void ensure_owns_direct_data() override;
|
||||
|
||||
static constexpr inline GeometryComponentType static_type = GEO_COMPONENT_TYPE_POINT_CLOUD;
|
||||
|
||||
private:
|
||||
|
@ -444,6 +458,9 @@ class InstancesComponent : public GeometryComponent {
|
|||
|
||||
bool is_empty() const final;
|
||||
|
||||
bool owns_direct_data() const override;
|
||||
void ensure_owns_direct_data() override;
|
||||
|
||||
static constexpr inline GeometryComponentType static_type = GEO_COMPONENT_TYPE_INSTANCES;
|
||||
};
|
||||
|
||||
|
@ -466,5 +483,8 @@ class VolumeComponent : public GeometryComponent {
|
|||
const Volume *get_for_read() const;
|
||||
Volume *get_for_write();
|
||||
|
||||
bool owns_direct_data() const override;
|
||||
void ensure_owns_direct_data() override;
|
||||
|
||||
static constexpr inline GeometryComponentType static_type = GEO_COMPONENT_TYPE_VOLUME;
|
||||
};
|
||||
|
|
|
@ -39,6 +39,10 @@ struct GeometryInstanceGroup {
|
|||
Vector<float4x4> transforms;
|
||||
};
|
||||
|
||||
void geometry_set_instances_attribute_foreach(const GeometrySet &geometry_set,
|
||||
const AttributeForeachCallback callback,
|
||||
const int limit);
|
||||
|
||||
void geometry_set_gather_instances(const GeometrySet &geometry_set,
|
||||
Vector<GeometryInstanceGroup> &r_instance_groups);
|
||||
|
||||
|
@ -55,9 +59,9 @@ struct AttributeKind {
|
|||
* will contain the highest complexity data type and the highest priority domain among every
|
||||
* attribute with the given name on all of the input components.
|
||||
*/
|
||||
void gather_attribute_info(Map<std::string, AttributeKind> &attributes,
|
||||
Span<GeometryComponentType> component_types,
|
||||
Span<bke::GeometryInstanceGroup> set_groups,
|
||||
const Set<std::string> &ignored_attributes);
|
||||
void geometry_set_gather_instances_attribute_info(Span<GeometryInstanceGroup> set_groups,
|
||||
Span<GeometryComponentType> component_types,
|
||||
const Set<std::string> &ignored_attributes,
|
||||
Map<std::string, AttributeKind> &r_attributes);
|
||||
|
||||
} // namespace blender::bke
|
||||
|
|
|
@ -116,6 +116,8 @@ enum {
|
|||
LIB_ID_COPY_NO_ANIMDATA = 1 << 19,
|
||||
/** Mesh: Reference CD data layers instead of doing real copy - USE WITH CAUTION! */
|
||||
LIB_ID_COPY_CD_REFERENCE = 1 << 20,
|
||||
/** Do not copy id->override_library, used by ID datablock override routines. */
|
||||
LIB_ID_COPY_NO_LIB_OVERRIDE = 1 << 21,
|
||||
|
||||
/* *** XXX Hackish/not-so-nice specific behaviors needed for some corner cases. *** */
|
||||
/* *** Ideally we should not have those, but we need them for now... *** */
|
||||
|
@ -136,7 +138,8 @@ enum {
|
|||
LIB_ID_CREATE_LOCALIZE = LIB_ID_CREATE_NO_MAIN | LIB_ID_CREATE_NO_USER_REFCOUNT |
|
||||
LIB_ID_CREATE_NO_DEG_TAG,
|
||||
/** Generate a local copy, outside of bmain, to work on (used by COW e.g.). */
|
||||
LIB_ID_COPY_LOCALIZE = LIB_ID_CREATE_LOCALIZE | LIB_ID_COPY_NO_PREVIEW | LIB_ID_COPY_CACHES,
|
||||
LIB_ID_COPY_LOCALIZE = LIB_ID_CREATE_LOCALIZE | LIB_ID_COPY_NO_PREVIEW | LIB_ID_COPY_CACHES |
|
||||
LIB_ID_COPY_NO_LIB_OVERRIDE,
|
||||
};
|
||||
|
||||
void BKE_libblock_copy_ex(struct Main *bmain,
|
||||
|
|
|
@ -84,7 +84,8 @@ bool BKE_lib_override_library_resync(struct Main *bmain,
|
|||
struct ViewLayer *view_layer,
|
||||
struct ID *id_root,
|
||||
struct Collection *override_resync_residual_storage,
|
||||
const bool do_hierarchy_enforce);
|
||||
const bool do_hierarchy_enforce,
|
||||
const bool do_post_process);
|
||||
void BKE_lib_override_library_main_resync(struct Main *bmain,
|
||||
struct Scene *scene,
|
||||
struct ViewLayer *view_layer);
|
||||
|
|
|
@ -1398,6 +1398,7 @@ int ntreeTexExecTree(struct bNodeTree *ntree,
|
|||
#define GEO_NODE_MESH_PRIMITIVE_GRID 1039
|
||||
#define GEO_NODE_ATTRIBUTE_MAP_RANGE 1040
|
||||
#define GEO_NODE_ATTRIBUTE_CLAMP 1041
|
||||
#define GEO_NODE_BOUNDING_BOX 1042
|
||||
|
||||
/** \} */
|
||||
|
||||
|
|
|
@ -36,6 +36,7 @@ struct Base;
|
|||
struct BoundBox;
|
||||
struct Curve;
|
||||
struct Depsgraph;
|
||||
struct GeometrySet;
|
||||
struct GpencilModifierData;
|
||||
struct HookGpencilModifierData;
|
||||
struct HookModifierData;
|
||||
|
@ -71,6 +72,8 @@ void BKE_object_free_curve_cache(struct Object *ob);
|
|||
void BKE_object_free_derived_caches(struct Object *ob);
|
||||
void BKE_object_free_caches(struct Object *object);
|
||||
|
||||
void BKE_object_set_preview_geometry_set(struct Object *ob, struct GeometrySet *geometry_set);
|
||||
|
||||
void BKE_object_modifier_hook_reset(struct Object *ob, struct HookModifierData *hmd);
|
||||
void BKE_object_modifier_gpencil_hook_reset(struct Object *ob,
|
||||
struct HookGpencilModifierData *hmd);
|
||||
|
|
|
@ -355,6 +355,7 @@ void BKE_pbvh_bmesh_detail_size_set(PBVH *pbvh, float detail_size, float detail_
|
|||
typedef enum {
|
||||
PBVH_Subdivide = 1,
|
||||
PBVH_Collapse = 2,
|
||||
PBVH_Cleanup = 4, //dissolve verts surrounded by either 3 or 4 triangles then triangulate
|
||||
} PBVHTopologyUpdateMode;
|
||||
bool BKE_pbvh_bmesh_update_topology(PBVH *pbvh,
|
||||
PBVHTopologyUpdateMode mode,
|
||||
|
|
|
@ -78,16 +78,17 @@ extern void (*BKE_volume_batch_cache_free_cb)(struct Volume *volume);
|
|||
|
||||
typedef struct VolumeGrid VolumeGrid;
|
||||
|
||||
bool BKE_volume_load(struct Volume *volume, struct Main *bmain);
|
||||
bool BKE_volume_load(const struct Volume *volume, const struct Main *bmain);
|
||||
void BKE_volume_unload(struct Volume *volume);
|
||||
bool BKE_volume_is_loaded(const struct Volume *volume);
|
||||
|
||||
int BKE_volume_num_grids(const struct Volume *volume);
|
||||
const char *BKE_volume_grids_error_msg(const struct Volume *volume);
|
||||
const char *BKE_volume_grids_frame_filepath(const struct Volume *volume);
|
||||
VolumeGrid *BKE_volume_grid_get(const struct Volume *volume, int grid_index);
|
||||
VolumeGrid *BKE_volume_grid_active_get(const struct Volume *volume);
|
||||
VolumeGrid *BKE_volume_grid_find(const struct Volume *volume, const char *name);
|
||||
const VolumeGrid *BKE_volume_grid_get_for_read(const struct Volume *volume, int grid_index);
|
||||
VolumeGrid *BKE_volume_grid_get_for_write(struct Volume *volume, int grid_index);
|
||||
const VolumeGrid *BKE_volume_grid_active_get_for_read(const struct Volume *volume);
|
||||
const VolumeGrid *BKE_volume_grid_find_for_read(const struct Volume *volume, const char *name);
|
||||
|
||||
/* Grid
|
||||
*
|
||||
|
@ -109,8 +110,8 @@ typedef enum VolumeGridType {
|
|||
VOLUME_GRID_POINTS,
|
||||
} VolumeGridType;
|
||||
|
||||
bool BKE_volume_grid_load(const struct Volume *volume, struct VolumeGrid *grid);
|
||||
void BKE_volume_grid_unload(const struct Volume *volume, struct VolumeGrid *grid);
|
||||
bool BKE_volume_grid_load(const struct Volume *volume, const struct VolumeGrid *grid);
|
||||
void BKE_volume_grid_unload(const struct Volume *volume, const struct VolumeGrid *grid);
|
||||
bool BKE_volume_grid_is_loaded(const struct VolumeGrid *grid);
|
||||
|
||||
/* Metadata */
|
||||
|
@ -119,9 +120,6 @@ VolumeGridType BKE_volume_grid_type(const struct VolumeGrid *grid);
|
|||
int BKE_volume_grid_channels(const struct VolumeGrid *grid);
|
||||
void BKE_volume_grid_transform_matrix(const struct VolumeGrid *grid, float mat[4][4]);
|
||||
|
||||
/* Bounds */
|
||||
bool BKE_volume_grid_bounds(const struct VolumeGrid *grid, float min[3], float max[3]);
|
||||
|
||||
/* Volume Editing
|
||||
*
|
||||
* These are intended for modifiers to use on evaluated datablocks.
|
||||
|
@ -145,8 +143,8 @@ int BKE_volume_simplify_level(const struct Depsgraph *depsgraph);
|
|||
float BKE_volume_simplify_factor(const struct Depsgraph *depsgraph);
|
||||
|
||||
/* File Save */
|
||||
bool BKE_volume_save(struct Volume *volume,
|
||||
struct Main *bmain,
|
||||
bool BKE_volume_save(const struct Volume *volume,
|
||||
const struct Main *bmain,
|
||||
struct ReportList *reports,
|
||||
const char *filepath);
|
||||
|
||||
|
@ -159,13 +157,26 @@ bool BKE_volume_save(struct Volume *volume,
|
|||
* Access to OpenVDB grid for C++. These will automatically load grids from
|
||||
* file or copy shared grids to make them writeable. */
|
||||
|
||||
#if defined(__cplusplus) && defined(WITH_OPENVDB)
|
||||
# include <openvdb/openvdb.h>
|
||||
# include <openvdb/points/PointDataGrid.h>
|
||||
#ifdef __cplusplus
|
||||
# include "BLI_float3.hh"
|
||||
# include "BLI_float4x4.hh"
|
||||
|
||||
bool BKE_volume_min_max(const Volume *volume, blender::float3 &r_min, blender::float3 &r_max);
|
||||
|
||||
# ifdef WITH_OPENVDB
|
||||
# include <openvdb/openvdb.h>
|
||||
# include <openvdb/points/PointDataGrid.h>
|
||||
|
||||
bool BKE_volume_grid_bounds(openvdb::GridBase::ConstPtr grid,
|
||||
blender::float3 &r_min,
|
||||
blender::float3 &r_max);
|
||||
|
||||
openvdb::GridBase::ConstPtr BKE_volume_grid_shallow_transform(openvdb::GridBase::ConstPtr grid,
|
||||
const blender::float4x4 &transform);
|
||||
|
||||
openvdb::GridBase::ConstPtr BKE_volume_grid_openvdb_for_metadata(const struct VolumeGrid *grid);
|
||||
openvdb::GridBase::ConstPtr BKE_volume_grid_openvdb_for_read(const struct Volume *volume,
|
||||
struct VolumeGrid *grid);
|
||||
const struct VolumeGrid *grid);
|
||||
openvdb::GridBase::Ptr BKE_volume_grid_openvdb_for_write(const struct Volume *volume,
|
||||
struct VolumeGrid *grid,
|
||||
const bool clear);
|
||||
|
@ -212,4 +223,5 @@ openvdb::GridBase::Ptr BKE_volume_grid_create_with_changed_resolution(
|
|||
const openvdb::GridBase &old_grid,
|
||||
const float resolution_factor);
|
||||
|
||||
# endif
|
||||
#endif
|
||||
|
|
|
@ -43,7 +43,7 @@ typedef struct DenseFloatVolumeGrid {
|
|||
} DenseFloatVolumeGrid;
|
||||
|
||||
bool BKE_volume_grid_dense_floats(const struct Volume *volume,
|
||||
struct VolumeGrid *volume_grid,
|
||||
const struct VolumeGrid *volume_grid,
|
||||
DenseFloatVolumeGrid *r_dense_grid);
|
||||
void BKE_volume_dense_float_grid_clear(DenseFloatVolumeGrid *dense_grid);
|
||||
|
||||
|
@ -53,7 +53,7 @@ typedef void (*BKE_volume_wireframe_cb)(
|
|||
void *userdata, float (*verts)[3], int (*edges)[2], int totvert, int totedge);
|
||||
|
||||
void BKE_volume_grid_wireframe(const struct Volume *volume,
|
||||
struct VolumeGrid *volume_grid,
|
||||
const struct VolumeGrid *volume_grid,
|
||||
BKE_volume_wireframe_cb cb,
|
||||
void *cb_userdata);
|
||||
|
||||
|
@ -63,7 +63,7 @@ typedef void (*BKE_volume_selection_surface_cb)(
|
|||
void *userdata, float (*verts)[3], int (*tris)[3], int totvert, int tottris);
|
||||
|
||||
void BKE_volume_grid_selection_surface(const struct Volume *volume,
|
||||
struct VolumeGrid *volume_grid,
|
||||
const struct VolumeGrid *volume_grid,
|
||||
BKE_volume_selection_surface_cb cb,
|
||||
void *cb_userdata);
|
||||
|
||||
|
|
|
@ -287,8 +287,10 @@ bool BKE_animdata_id_is_animated(const struct ID *id)
|
|||
!BLI_listbase_is_empty(&adt->overrides);
|
||||
}
|
||||
|
||||
/** Callback used by lib_query to walk over all ID usages (mimics `foreach_id` callback of
|
||||
* `IDTypeInfo` structure). */
|
||||
/**
|
||||
* Callback used by lib_query to walk over all ID usages (mimics `foreach_id` callback of
|
||||
* `IDTypeInfo` structure).
|
||||
*/
|
||||
void BKE_animdata_foreach_id(AnimData *adt, LibraryForeachIDData *data)
|
||||
{
|
||||
LISTBASE_FOREACH (FCurve *, fcu, &adt->drivers) {
|
||||
|
|
|
@ -42,157 +42,192 @@ static CLG_LogRef LOG = {"bke.anim"};
|
|||
/* ******************************************************************** */
|
||||
/* Curve Paths - for curve deforms and/or curve following */
|
||||
|
||||
/**
|
||||
* Free curve path data
|
||||
*
|
||||
* \note Frees the path itself!
|
||||
* \note This is increasingly inaccurate with non-uniform #BevPoint subdivisions T24633.
|
||||
*/
|
||||
void free_path(Path *path)
|
||||
static int get_bevlist_seg_array_size(const BevList *bl)
|
||||
{
|
||||
if (path->data) {
|
||||
MEM_freeN(path->data);
|
||||
if (bl->poly >= 0) {
|
||||
/* Cyclic curve. */
|
||||
return bl->nr;
|
||||
}
|
||||
MEM_freeN(path);
|
||||
|
||||
return bl->nr - 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate a curve-deform path for a curve
|
||||
* - Only called from displist.c -> #do_makeDispListCurveTypes
|
||||
*/
|
||||
void calc_curvepath(Object *ob, ListBase *nurbs)
|
||||
int BKE_anim_path_get_array_size(const CurveCache *curve_cache)
|
||||
{
|
||||
BevList *bl;
|
||||
BevPoint *bevp, *bevpn, *bevpfirst, *bevplast;
|
||||
PathPoint *pp;
|
||||
Nurb *nu;
|
||||
Path *path;
|
||||
float *fp, *dist, *maxdist, xyz[3];
|
||||
float fac, d = 0, fac1, fac2;
|
||||
int a, tot, cycl = 0;
|
||||
BLI_assert(curve_cache != NULL);
|
||||
|
||||
/* in a path vertices are with equal differences: path->len = number of verts */
|
||||
/* NOW WITH BEVELCURVE!!! */
|
||||
BevList *bl = curve_cache->bev.first;
|
||||
|
||||
BLI_assert(bl != NULL && bl->nr > 1);
|
||||
|
||||
return get_bevlist_seg_array_size(bl);
|
||||
}
|
||||
|
||||
float BKE_anim_path_get_length(const CurveCache *curve_cache)
|
||||
{
|
||||
const int seg_size = BKE_anim_path_get_array_size(curve_cache);
|
||||
return curve_cache->anim_path_accum_length[seg_size - 1];
|
||||
}
|
||||
|
||||
void BKE_anim_path_calc_data(Object *ob)
|
||||
{
|
||||
if (ob == NULL || ob->type != OB_CURVE) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (ob->runtime.curve_cache->path) {
|
||||
free_path(ob->runtime.curve_cache->path);
|
||||
if (ob->runtime.curve_cache == NULL) {
|
||||
CLOG_WARN(&LOG, "No curve cache!");
|
||||
return;
|
||||
}
|
||||
ob->runtime.curve_cache->path = NULL;
|
||||
|
||||
/* weak! can only use first curve */
|
||||
bl = ob->runtime.curve_cache->bev.first;
|
||||
/* We only use the first curve. */
|
||||
BevList *bl = ob->runtime.curve_cache->bev.first;
|
||||
if (bl == NULL || !bl->nr) {
|
||||
CLOG_WARN(&LOG, "No bev list data!");
|
||||
return;
|
||||
}
|
||||
|
||||
nu = nurbs->first;
|
||||
|
||||
ob->runtime.curve_cache->path = path = MEM_callocN(sizeof(Path), "calc_curvepath");
|
||||
|
||||
/* if POLY: last vertice != first vertice */
|
||||
cycl = (bl->poly != -1);
|
||||
|
||||
tot = cycl ? bl->nr : bl->nr - 1;
|
||||
|
||||
path->len = tot + 1;
|
||||
/* Exception: vector handle paths and polygon paths should be subdivided
|
||||
* at least a factor resolution. */
|
||||
if (path->len < nu->resolu * SEGMENTSU(nu)) {
|
||||
path->len = nu->resolu * SEGMENTSU(nu);
|
||||
/* Free old data. */
|
||||
if (ob->runtime.curve_cache->anim_path_accum_length) {
|
||||
MEM_freeN((void *)ob->runtime.curve_cache->anim_path_accum_length);
|
||||
}
|
||||
|
||||
dist = (float *)MEM_mallocN(sizeof(float) * (tot + 1), "calcpathdist");
|
||||
/* We assume that we have at least two points.
|
||||
* If there is less than two points in the curve,
|
||||
* no BevList should have been generated.
|
||||
*/
|
||||
BLI_assert(bl->nr > 1);
|
||||
|
||||
/* all lengths in *dist */
|
||||
bevp = bevpfirst = bl->bevpoints;
|
||||
fp = dist;
|
||||
*fp = 0.0f;
|
||||
for (a = 0; a < tot; a++) {
|
||||
fp++;
|
||||
if (cycl && a == tot - 1) {
|
||||
sub_v3_v3v3(xyz, bevpfirst->vec, bevp->vec);
|
||||
}
|
||||
else {
|
||||
sub_v3_v3v3(xyz, (bevp + 1)->vec, bevp->vec);
|
||||
}
|
||||
const int seg_size = get_bevlist_seg_array_size(bl);
|
||||
float *len_data = (float *)MEM_mallocN(sizeof(float) * seg_size, "calcpathdist");
|
||||
ob->runtime.curve_cache->anim_path_accum_length = len_data;
|
||||
|
||||
*fp = *(fp - 1) + len_v3(xyz);
|
||||
bevp++;
|
||||
BevPoint *bp_arr = bl->bevpoints;
|
||||
float prev_len = 0.0f;
|
||||
for (int i = 0; i < bl->nr - 1; i++) {
|
||||
prev_len += len_v3v3(bp_arr[i].vec, bp_arr[i + 1].vec);
|
||||
len_data[i] = prev_len;
|
||||
}
|
||||
|
||||
path->totdist = *fp;
|
||||
|
||||
/* the path verts in path->data */
|
||||
/* now also with TILT value */
|
||||
pp = path->data = (PathPoint *)MEM_callocN(sizeof(PathPoint) * path->len, "pathdata");
|
||||
|
||||
bevp = bevpfirst;
|
||||
bevpn = bevp + 1;
|
||||
bevplast = bevpfirst + (bl->nr - 1);
|
||||
if (UNLIKELY(bevpn > bevplast)) {
|
||||
bevpn = cycl ? bevpfirst : bevplast;
|
||||
if (bl->poly >= 0) {
|
||||
/* Cyclic curve. */
|
||||
len_data[seg_size - 1] = prev_len + len_v3v3(bp_arr[0].vec, bp_arr[bl->nr - 1].vec);
|
||||
}
|
||||
fp = dist + 1;
|
||||
maxdist = dist + tot;
|
||||
fac = 1.0f / ((float)path->len - 1.0f);
|
||||
fac = fac * path->totdist;
|
||||
|
||||
for (a = 0; a < path->len; a++) {
|
||||
|
||||
d = ((float)a) * fac;
|
||||
|
||||
/* we're looking for location (distance) 'd' in the array */
|
||||
if (LIKELY(tot > 0)) {
|
||||
while ((fp < maxdist) && (d >= *fp)) {
|
||||
fp++;
|
||||
if (bevp < bevplast) {
|
||||
bevp++;
|
||||
}
|
||||
bevpn = bevp + 1;
|
||||
if (UNLIKELY(bevpn > bevplast)) {
|
||||
bevpn = cycl ? bevpfirst : bevplast;
|
||||
}
|
||||
}
|
||||
|
||||
fac1 = (*(fp)-d) / (*(fp) - *(fp - 1));
|
||||
fac2 = 1.0f - fac1;
|
||||
}
|
||||
else {
|
||||
fac1 = 1.0f;
|
||||
fac2 = 0.0f;
|
||||
}
|
||||
|
||||
interp_v3_v3v3(pp->vec, bevp->vec, bevpn->vec, fac2);
|
||||
pp->vec[3] = fac1 * bevp->tilt + fac2 * bevpn->tilt;
|
||||
pp->radius = fac1 * bevp->radius + fac2 * bevpn->radius;
|
||||
pp->weight = fac1 * bevp->weight + fac2 * bevpn->weight;
|
||||
interp_qt_qtqt(pp->quat, bevp->quat, bevpn->quat, fac2);
|
||||
normalize_qt(pp->quat);
|
||||
|
||||
pp++;
|
||||
}
|
||||
|
||||
MEM_freeN(dist);
|
||||
}
|
||||
|
||||
static int interval_test(const int min, const int max, int p1, const int cycl)
|
||||
static void get_curve_points_from_idx(const int idx,
|
||||
const BevList *bl,
|
||||
const bool is_cyclic,
|
||||
BevPoint const **r_p0,
|
||||
BevPoint const **r_p1,
|
||||
BevPoint const **r_p2,
|
||||
BevPoint const **r_p3)
|
||||
{
|
||||
if (cycl) {
|
||||
p1 = mod_i(p1 - min, (max - min + 1)) + min;
|
||||
}
|
||||
else {
|
||||
if (p1 < min) {
|
||||
p1 = min;
|
||||
BLI_assert(idx >= 0);
|
||||
BLI_assert(idx < bl->nr - 1 || (is_cyclic && idx < bl->nr));
|
||||
BLI_assert(bl->nr > 1);
|
||||
|
||||
const BevPoint *bp_arr = bl->bevpoints;
|
||||
|
||||
/* First segment. */
|
||||
if (idx == 0) {
|
||||
*r_p1 = &bp_arr[0];
|
||||
if (is_cyclic) {
|
||||
*r_p0 = &bp_arr[bl->nr - 1];
|
||||
}
|
||||
else if (p1 > max) {
|
||||
p1 = max;
|
||||
else {
|
||||
*r_p0 = *r_p1;
|
||||
}
|
||||
|
||||
*r_p2 = &bp_arr[1];
|
||||
|
||||
if (bl->nr > 2) {
|
||||
*r_p3 = &bp_arr[2];
|
||||
}
|
||||
else {
|
||||
*r_p3 = *r_p2;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/* Last segment (or next to last in a cyclic curve). */
|
||||
if (idx == bl->nr - 2) {
|
||||
/* The case when the bl->nr == 2 falls in to the "first segment" check above.
|
||||
* So here we can assume that bl->nr > 2.
|
||||
*/
|
||||
*r_p0 = &bp_arr[idx - 1];
|
||||
*r_p1 = &bp_arr[idx];
|
||||
*r_p2 = &bp_arr[idx + 1];
|
||||
|
||||
if (is_cyclic) {
|
||||
*r_p3 = &bp_arr[0];
|
||||
}
|
||||
else {
|
||||
*r_p3 = *r_p2;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (idx == bl->nr - 1) {
|
||||
/* Last segment in a cyclic curve. This should only trigger if the curve is cyclic
|
||||
* as it gets an extra segment between the end and the start point. */
|
||||
*r_p0 = &bp_arr[idx - 1];
|
||||
*r_p1 = &bp_arr[idx];
|
||||
*r_p2 = &bp_arr[0];
|
||||
*r_p3 = &bp_arr[1];
|
||||
return;
|
||||
}
|
||||
|
||||
/* To get here the curve has to have four curve points or more and idx can't
|
||||
* be the first or the last segment.
|
||||
* So we can assume that we can get four points without any special checks.
|
||||
*/
|
||||
*r_p0 = &bp_arr[idx - 1];
|
||||
*r_p1 = &bp_arr[idx];
|
||||
*r_p2 = &bp_arr[idx + 1];
|
||||
*r_p3 = &bp_arr[idx + 2];
|
||||
}
|
||||
|
||||
static bool binary_search_anim_path(const float *accum_len_arr,
|
||||
const int seg_size,
|
||||
const float goal_len,
|
||||
int *r_idx,
|
||||
float *r_frac)
|
||||
{
|
||||
float left_len, right_len;
|
||||
int cur_idx = 0, cur_base = 0;
|
||||
int cur_step = seg_size - 1;
|
||||
|
||||
while (true) {
|
||||
cur_idx = cur_base + cur_step / 2;
|
||||
left_len = accum_len_arr[cur_idx];
|
||||
right_len = accum_len_arr[cur_idx + 1];
|
||||
|
||||
if (left_len <= goal_len && right_len > goal_len) {
|
||||
*r_idx = cur_idx + 1;
|
||||
*r_frac = (goal_len - left_len) / (right_len - left_len);
|
||||
return true;
|
||||
}
|
||||
if (cur_idx == 0) {
|
||||
/* We ended up at the first segment. The point must be in here. */
|
||||
*r_idx = 0;
|
||||
*r_frac = goal_len / accum_len_arr[0];
|
||||
return true;
|
||||
}
|
||||
|
||||
if (UNLIKELY(cur_step == 0)) {
|
||||
/* This should never happen unless there is something horribly wrong. */
|
||||
CLOG_ERROR(&LOG, "Couldn't find any valid point on the animation path!");
|
||||
BLI_assert(!"Couldn't find any valid point on the animation path!");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (left_len < goal_len) {
|
||||
/* Go to the right. */
|
||||
cur_base = cur_idx + 1;
|
||||
cur_step--;
|
||||
} /* Else, go to the left. */
|
||||
|
||||
cur_step /= 2;
|
||||
}
|
||||
return p1;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -203,66 +238,70 @@ static int interval_test(const int min, const int max, int p1, const int cycl)
|
|||
*
|
||||
* \return success.
|
||||
*/
|
||||
bool where_on_path(const Object *ob,
|
||||
float ctime,
|
||||
float r_vec[4],
|
||||
float r_dir[3],
|
||||
float r_quat[4],
|
||||
float *r_radius,
|
||||
float *r_weight)
|
||||
bool BKE_where_on_path(const Object *ob,
|
||||
float ctime,
|
||||
float r_vec[4],
|
||||
float r_dir[3],
|
||||
float r_quat[4],
|
||||
float *r_radius,
|
||||
float *r_weight)
|
||||
{
|
||||
Curve *cu;
|
||||
const Nurb *nu;
|
||||
const BevList *bl;
|
||||
const Path *path;
|
||||
const PathPoint *pp, *p0, *p1, *p2, *p3;
|
||||
float fac;
|
||||
float data[4];
|
||||
int cycl = 0, s0, s1, s2, s3;
|
||||
const ListBase *nurbs;
|
||||
|
||||
if (ob == NULL || ob->type != OB_CURVE) {
|
||||
return false;
|
||||
}
|
||||
cu = ob->data;
|
||||
if (ob->runtime.curve_cache == NULL || ob->runtime.curve_cache->path == NULL ||
|
||||
ob->runtime.curve_cache->path->data == NULL) {
|
||||
CLOG_WARN(&LOG, "no path!");
|
||||
Curve *cu = ob->data;
|
||||
if (ob->runtime.curve_cache == NULL) {
|
||||
CLOG_WARN(&LOG, "No curve cache!");
|
||||
return false;
|
||||
}
|
||||
path = ob->runtime.curve_cache->path;
|
||||
pp = path->data;
|
||||
|
||||
/* test for cyclic */
|
||||
bl = ob->runtime.curve_cache->bev.first;
|
||||
if (!bl) {
|
||||
/* We only use the first curve. */
|
||||
BevList *bl = ob->runtime.curve_cache->bev.first;
|
||||
if (bl == NULL || !bl->nr) {
|
||||
CLOG_WARN(&LOG, "No bev list data!");
|
||||
return false;
|
||||
}
|
||||
if (!bl->nr) {
|
||||
return false;
|
||||
}
|
||||
if (bl->poly > -1) {
|
||||
cycl = 1;
|
||||
|
||||
/* Test for cyclic curve. */
|
||||
const bool is_cyclic = bl->poly >= 0;
|
||||
|
||||
if (is_cyclic) {
|
||||
/* Wrap the time into a 0.0 - 1.0 range. */
|
||||
if (ctime < 0.0f || ctime > 1.0f) {
|
||||
ctime -= floorf(ctime);
|
||||
}
|
||||
}
|
||||
|
||||
/* values below zero for non-cyclic curves give strange results */
|
||||
BLI_assert(cycl || ctime >= 0.0f);
|
||||
/* The curve points for this ctime value. */
|
||||
const BevPoint *p0, *p1, *p2, *p3;
|
||||
|
||||
ctime *= (path->len - 1);
|
||||
float frac;
|
||||
const int seg_size = get_bevlist_seg_array_size(bl);
|
||||
const float *accum_len_arr = ob->runtime.curve_cache->anim_path_accum_length;
|
||||
const float goal_len = ctime * accum_len_arr[seg_size - 1];
|
||||
|
||||
s1 = (int)floor(ctime);
|
||||
fac = (float)(s1 + 1) - ctime;
|
||||
/* Are we simply trying to get the start/end point? */
|
||||
if (ctime <= 0.0f || ctime >= 1.0f) {
|
||||
const float clamp_time = clamp_f(ctime, 0.0f, 1.0f);
|
||||
const int idx = clamp_time * (seg_size - 1);
|
||||
get_curve_points_from_idx(idx, bl, is_cyclic, &p0, &p1, &p2, &p3);
|
||||
|
||||
/* path->len is corrected for cyclic */
|
||||
s0 = interval_test(0, path->len - 1 - cycl, s1 - 1, cycl);
|
||||
s1 = interval_test(0, path->len - 1 - cycl, s1, cycl);
|
||||
s2 = interval_test(0, path->len - 1 - cycl, s1 + 1, cycl);
|
||||
s3 = interval_test(0, path->len - 1 - cycl, s1 + 2, cycl);
|
||||
if (idx == 0) {
|
||||
frac = goal_len / accum_len_arr[0];
|
||||
}
|
||||
else {
|
||||
frac = (goal_len - accum_len_arr[idx - 1]) / (accum_len_arr[idx] - accum_len_arr[idx - 1]);
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* Do binary search to get the correct segment. */
|
||||
int idx;
|
||||
const bool found_idx = binary_search_anim_path(accum_len_arr, seg_size, goal_len, &idx, &frac);
|
||||
|
||||
p0 = pp + s0;
|
||||
p1 = pp + s1;
|
||||
p2 = pp + s2;
|
||||
p3 = pp + s3;
|
||||
if (UNLIKELY(!found_idx)) {
|
||||
return false;
|
||||
}
|
||||
get_curve_points_from_idx(idx, bl, is_cyclic, &p0, &p1, &p2, &p3);
|
||||
}
|
||||
|
||||
/* NOTE: commented out for follow constraint
|
||||
*
|
||||
|
@ -272,65 +311,68 @@ bool where_on_path(const Object *ob,
|
|||
*/
|
||||
// if (cu->flag & CU_FOLLOW) {
|
||||
|
||||
key_curve_tangent_weights(1.0f - fac, data, KEY_BSPLINE);
|
||||
float w[4];
|
||||
|
||||
interp_v3_v3v3v3v3(r_dir, p0->vec, p1->vec, p2->vec, p3->vec, data);
|
||||
key_curve_tangent_weights(frac, w, KEY_BSPLINE);
|
||||
|
||||
interp_v3_v3v3v3v3(r_dir, p0->vec, p1->vec, p2->vec, p3->vec, w);
|
||||
|
||||
/* Make compatible with #vec_to_quat. */
|
||||
negate_v3(r_dir);
|
||||
//}
|
||||
|
||||
nurbs = BKE_curve_editNurbs_get(cu);
|
||||
const ListBase *nurbs = BKE_curve_editNurbs_get(cu);
|
||||
if (!nurbs) {
|
||||
nurbs = &cu->nurb;
|
||||
}
|
||||
nu = nurbs->first;
|
||||
const Nurb *nu = nurbs->first;
|
||||
|
||||
/* make sure that first and last frame are included in the vectors here */
|
||||
if (nu->type == CU_POLY) {
|
||||
key_curve_position_weights(1.0f - fac, data, KEY_LINEAR);
|
||||
if (ELEM(nu->type, CU_POLY, CU_BEZIER, CU_NURBS)) {
|
||||
key_curve_position_weights(frac, w, KEY_LINEAR);
|
||||
}
|
||||
else if (nu->type == CU_BEZIER) {
|
||||
key_curve_position_weights(1.0f - fac, data, KEY_LINEAR);
|
||||
}
|
||||
else if (s0 == s1 || p2 == p3) {
|
||||
key_curve_position_weights(1.0f - fac, data, KEY_CARDINAL);
|
||||
else if (p2 == p3) {
|
||||
key_curve_position_weights(frac, w, KEY_CARDINAL);
|
||||
}
|
||||
else {
|
||||
key_curve_position_weights(1.0f - fac, data, KEY_BSPLINE);
|
||||
key_curve_position_weights(frac, w, KEY_BSPLINE);
|
||||
}
|
||||
|
||||
r_vec[0] = /* X */
|
||||
data[0] * p0->vec[0] + data[1] * p1->vec[0] + data[2] * p2->vec[0] + data[3] * p3->vec[0];
|
||||
w[0] * p0->vec[0] + w[1] * p1->vec[0] + w[2] * p2->vec[0] + w[3] * p3->vec[0];
|
||||
r_vec[1] = /* Y */
|
||||
data[0] * p0->vec[1] + data[1] * p1->vec[1] + data[2] * p2->vec[1] + data[3] * p3->vec[1];
|
||||
w[0] * p0->vec[1] + w[1] * p1->vec[1] + w[2] * p2->vec[1] + w[3] * p3->vec[1];
|
||||
r_vec[2] = /* Z */
|
||||
data[0] * p0->vec[2] + data[1] * p1->vec[2] + data[2] * p2->vec[2] + data[3] * p3->vec[2];
|
||||
r_vec[3] = /* Tilt, should not be needed since we have quat still used */
|
||||
data[0] * p0->vec[3] + data[1] * p1->vec[3] + data[2] * p2->vec[3] + data[3] * p3->vec[3];
|
||||
w[0] * p0->vec[2] + w[1] * p1->vec[2] + w[2] * p2->vec[2] + w[3] * p3->vec[2];
|
||||
|
||||
/* Clamp weights to 0-1 as we don't want to extrapolate other values than position. */
|
||||
clamp_v4(w, 0.0f, 1.0f);
|
||||
|
||||
/* Tilt, should not be needed since we have quat still used. */
|
||||
r_vec[3] = w[0] * p0->tilt + w[1] * p1->tilt + w[2] * p2->tilt + w[3] * p3->tilt;
|
||||
|
||||
if (r_quat) {
|
||||
float totfac, q1[4], q2[4];
|
||||
|
||||
totfac = data[0] + data[3];
|
||||
totfac = w[0] + w[3];
|
||||
if (totfac > FLT_EPSILON) {
|
||||
interp_qt_qtqt(q1, p0->quat, p3->quat, data[3] / totfac);
|
||||
interp_qt_qtqt(q1, p0->quat, p3->quat, w[3] / totfac);
|
||||
}
|
||||
else {
|
||||
copy_qt_qt(q1, p1->quat);
|
||||
}
|
||||
|
||||
totfac = data[1] + data[2];
|
||||
totfac = w[1] + w[2];
|
||||
if (totfac > FLT_EPSILON) {
|
||||
interp_qt_qtqt(q2, p1->quat, p2->quat, data[2] / totfac);
|
||||
interp_qt_qtqt(q2, p1->quat, p2->quat, w[2] / totfac);
|
||||
}
|
||||
else {
|
||||
copy_qt_qt(q2, p3->quat);
|
||||
}
|
||||
|
||||
totfac = data[0] + data[1] + data[2] + data[3];
|
||||
totfac = w[0] + w[1] + w[2] + w[3];
|
||||
if (totfac > FLT_EPSILON) {
|
||||
interp_qt_qtqt(r_quat, q1, q2, (data[1] + data[2]) / totfac);
|
||||
interp_qt_qtqt(r_quat, q1, q2, (w[1] + w[2]) / totfac);
|
||||
}
|
||||
else {
|
||||
copy_qt_qt(r_quat, q2);
|
||||
|
@ -338,13 +380,11 @@ bool where_on_path(const Object *ob,
|
|||
}
|
||||
|
||||
if (r_radius) {
|
||||
*r_radius = data[0] * p0->radius + data[1] * p1->radius + data[2] * p2->radius +
|
||||
data[3] * p3->radius;
|
||||
*r_radius = w[0] * p0->radius + w[1] * p1->radius + w[2] * p2->radius + w[3] * p3->radius;
|
||||
}
|
||||
|
||||
if (r_weight) {
|
||||
*r_weight = data[0] * p0->weight + data[1] * p1->weight + data[2] * p2->weight +
|
||||
data[3] * p3->weight;
|
||||
*r_weight = w[0] * p0->weight + w[1] * p1->weight + w[2] * p2->weight + w[3] * p3->weight;
|
||||
}
|
||||
|
||||
return true;
|
||||
|
|
|
@ -1605,8 +1605,9 @@ static bool nla_combine_get_inverted_strip_value(const int mix_mode,
|
|||
}
|
||||
}
|
||||
|
||||
/** Accumulate quaternion channels for Combine mode according to influence.
|
||||
* \returns blended_value = lower_values @ strip_values^infl
|
||||
/**
|
||||
* Accumulate quaternion channels for Combine mode according to influence.
|
||||
* \returns `blended_value = lower_values @ strip_values^infl`
|
||||
*/
|
||||
static void nla_combine_quaternion(const float lower_values[4],
|
||||
const float strip_values[4],
|
||||
|
@ -2094,8 +2095,10 @@ static void animsys_evaluate_nla_domain(PointerRNA *ptr, NlaEvalData *channels,
|
|||
|
||||
/* ---------------------- */
|
||||
|
||||
/** Tweaked strip is evaluated differently from other strips. Adjacent strips are ignored
|
||||
* and includes a workaround for when user is not editing in place. */
|
||||
/**
|
||||
* Tweaked strip is evaluated differently from other strips. Adjacent strips are ignored
|
||||
* and includes a workaround for when user is not editing in place.
|
||||
*/
|
||||
static void animsys_create_tweak_strip(const AnimData *adt,
|
||||
const bool keyframing_to_strip,
|
||||
NlaStrip *r_tweak_strip)
|
||||
|
@ -2210,8 +2213,10 @@ static bool is_nlatrack_evaluatable(const AnimData *adt, const NlaTrack *nlt)
|
|||
return true;
|
||||
}
|
||||
|
||||
/** Check for special case of non-pushed action being evaluated with no NLA influence (off and no
|
||||
* strips evaluated) nor NLA interference (ensure NLA not soloing). */
|
||||
/**
|
||||
* Check for special case of non-pushed action being evaluated with no NLA influence (off and no
|
||||
* strips evaluated) nor NLA interference (ensure NLA not soloing).
|
||||
*/
|
||||
static bool is_action_track_evaluated_without_nla(const AnimData *adt,
|
||||
const bool any_strip_evaluated)
|
||||
{
|
||||
|
@ -2491,7 +2496,8 @@ void nlasnapshot_ensure_channels(NlaEvalData *eval_data, NlaEvalSnapshot *snapsh
|
|||
}
|
||||
}
|
||||
|
||||
/** Blends the \a lower_snapshot with the \a upper_snapshot into \a r_blended_snapshot according
|
||||
/**
|
||||
* Blends the \a lower_snapshot with the \a upper_snapshot into \a r_blended_snapshot according
|
||||
* to the given \a upper_blendmode and \a upper_influence.
|
||||
*
|
||||
* For \a upper_snapshot, blending limited to values in the \a blend_domain. For Replace blendmode,
|
||||
|
|
|
@ -229,7 +229,7 @@ static bool splineik_evaluate_init(tSplineIK_Tree *tree, tSplineIk_EvalState *st
|
|||
|
||||
CurveCache *cache = ikData->tar->runtime.curve_cache;
|
||||
|
||||
if (ELEM(NULL, cache, cache->path, cache->path->data)) {
|
||||
if (ELEM(NULL, cache, cache->anim_path_accum_length)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -242,7 +242,7 @@ static bool splineik_evaluate_init(tSplineIK_Tree *tree, tSplineIk_EvalState *st
|
|||
if ((ikData->yScaleMode != CONSTRAINT_SPLINEIK_YS_FIT_CURVE) && (tree->totlength != 0.0f)) {
|
||||
/* get the current length of the curve */
|
||||
/* NOTE: this is assumed to be correct even after the curve was resized */
|
||||
float splineLen = cache->path->totdist;
|
||||
const float splineLen = BKE_anim_path_get_length(cache);
|
||||
|
||||
/* calculate the scale factor to multiply all the path values by so that the
|
||||
* bone chain retains its current length, such that
|
||||
|
@ -297,7 +297,7 @@ static void splineik_evaluate_bone(
|
|||
}
|
||||
|
||||
/* tail endpoint */
|
||||
if (where_on_path(ikData->tar, pointEnd, vec, dir, NULL, &rad, NULL)) {
|
||||
if (BKE_where_on_path(ikData->tar, pointEnd, vec, dir, NULL, &rad, NULL)) {
|
||||
/* apply curve's object-mode transforms to the position
|
||||
* unless the option to allow curve to be positioned elsewhere is activated (i.e. no root)
|
||||
*/
|
||||
|
@ -314,7 +314,7 @@ static void splineik_evaluate_bone(
|
|||
}
|
||||
|
||||
/* head endpoint */
|
||||
if (where_on_path(ikData->tar, pointStart, vec, dir, NULL, &rad, NULL)) {
|
||||
if (BKE_where_on_path(ikData->tar, pointStart, vec, dir, NULL, &rad, NULL)) {
|
||||
/* apply curve's object-mode transforms to the position
|
||||
* unless the option to allow curve to be positioned elsewhere is activated (i.e. no root)
|
||||
*/
|
||||
|
|
|
@ -822,12 +822,16 @@ Set<std::string> GeometryComponent::attribute_names() const
|
|||
return attributes;
|
||||
}
|
||||
|
||||
void GeometryComponent::attribute_foreach(const AttributeForeachCallback callback) const
|
||||
/**
|
||||
* \return False if the callback explicitly returned false at any point, otherwise true,
|
||||
* meaning the callback made it all the way through.
|
||||
*/
|
||||
bool GeometryComponent::attribute_foreach(const AttributeForeachCallback callback) const
|
||||
{
|
||||
using namespace blender::bke;
|
||||
const ComponentAttributeProviders *providers = this->get_attribute_providers();
|
||||
if (providers == nullptr) {
|
||||
return;
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Keep track handled attribute names to make sure that we do not return the same name twice. */
|
||||
|
@ -838,7 +842,7 @@ void GeometryComponent::attribute_foreach(const AttributeForeachCallback callbac
|
|||
if (provider->exists(*this)) {
|
||||
AttributeMetaData meta_data{provider->domain(), provider->data_type()};
|
||||
if (!callback(provider->name(), meta_data)) {
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
handled_attribute_names.add_new(provider->name());
|
||||
}
|
||||
|
@ -852,9 +856,11 @@ void GeometryComponent::attribute_foreach(const AttributeForeachCallback callbac
|
|||
return true;
|
||||
});
|
||||
if (!continue_loop) {
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool GeometryComponent::attribute_exists(const blender::StringRef attribute_name) const
|
||||
|
|
|
@ -2667,4 +2667,13 @@ void BKE_brush_get_dyntopo(Brush *brush, Sculpt *sd, DynTopoSettings *out)
|
|||
out->flag &= ~DYNTOPO_COLLAPSE;
|
||||
}
|
||||
}
|
||||
|
||||
if (inherit & DYNTOPO_CLEANUP) {
|
||||
if (sd->flags & SCULPT_DYNTOPO_CLEANUP) {
|
||||
out->flag |= DYNTOPO_CLEANUP;
|
||||
}
|
||||
else {
|
||||
out->flag &= ~DYNTOPO_CLEANUP;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
@ -2016,12 +2016,10 @@ static void scene_collections_array(Scene *scene,
|
|||
BLI_assert(collection != NULL);
|
||||
scene_collection_callback(collection, scene_collections_count, r_collections_array_len);
|
||||
|
||||
if (*r_collections_array_len == 0) {
|
||||
return;
|
||||
}
|
||||
BLI_assert(*r_collections_array_len > 0);
|
||||
|
||||
Collection **array = MEM_mallocN(sizeof(Collection *) * (*r_collections_array_len),
|
||||
"CollectionArray");
|
||||
Collection **array = MEM_malloc_arrayN(
|
||||
*r_collections_array_len, sizeof(Collection *), "CollectionArray");
|
||||
*r_collections_array = array;
|
||||
scene_collection_callback(collection, scene_collections_build_array, &array);
|
||||
}
|
||||
|
@ -2036,8 +2034,9 @@ void BKE_scene_collections_iterator_begin(BLI_Iterator *iter, void *data_in)
|
|||
CollectionsIteratorData *data = MEM_callocN(sizeof(CollectionsIteratorData), __func__);
|
||||
|
||||
data->scene = scene;
|
||||
|
||||
BLI_ITERATOR_INIT(iter);
|
||||
iter->data = data;
|
||||
iter->valid = true;
|
||||
|
||||
scene_collections_array(scene, (Collection ***)&data->array, &data->tot);
|
||||
BLI_assert(data->tot != 0);
|
||||
|
@ -2079,16 +2078,22 @@ typedef struct SceneObjectsIteratorData {
|
|||
BLI_Iterator scene_collection_iter;
|
||||
} SceneObjectsIteratorData;
|
||||
|
||||
void BKE_scene_objects_iterator_begin(BLI_Iterator *iter, void *data_in)
|
||||
static void scene_objects_iterator_begin(BLI_Iterator *iter, Scene *scene, GSet *visited_objects)
|
||||
{
|
||||
Scene *scene = data_in;
|
||||
SceneObjectsIteratorData *data = MEM_callocN(sizeof(SceneObjectsIteratorData), __func__);
|
||||
|
||||
BLI_ITERATOR_INIT(iter);
|
||||
iter->data = data;
|
||||
|
||||
/* lookup list ot make sure each object is object called once */
|
||||
data->visited = BLI_gset_ptr_new(__func__);
|
||||
/* Lookup list to make sure that each object is only processed once. */
|
||||
if (visited_objects != NULL) {
|
||||
data->visited = visited_objects;
|
||||
}
|
||||
else {
|
||||
data->visited = BLI_gset_ptr_new(__func__);
|
||||
}
|
||||
|
||||
/* we wrap the scenecollection iterator here to go over the scene collections */
|
||||
/* We wrap the scenecollection iterator here to go over the scene collections. */
|
||||
BKE_scene_collections_iterator_begin(&data->scene_collection_iter, scene);
|
||||
|
||||
Collection *collection = data->scene_collection_iter.current;
|
||||
|
@ -2097,6 +2102,13 @@ void BKE_scene_objects_iterator_begin(BLI_Iterator *iter, void *data_in)
|
|||
BKE_scene_objects_iterator_next(iter);
|
||||
}
|
||||
|
||||
void BKE_scene_objects_iterator_begin(BLI_Iterator *iter, void *data_in)
|
||||
{
|
||||
Scene *scene = data_in;
|
||||
|
||||
scene_objects_iterator_begin(iter, scene, NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensures we only get each object once, even when included in several collections.
|
||||
*/
|
||||
|
@ -2150,9 +2162,36 @@ void BKE_scene_objects_iterator_end(BLI_Iterator *iter)
|
|||
SceneObjectsIteratorData *data = iter->data;
|
||||
if (data) {
|
||||
BKE_scene_collections_iterator_end(&data->scene_collection_iter);
|
||||
BLI_gset_free(data->visited, NULL);
|
||||
if (data->visited != NULL) {
|
||||
BLI_gset_free(data->visited, NULL);
|
||||
}
|
||||
MEM_freeN(data);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a new GSet (or extend given `objects_gset` if not NULL) with all objects referenced by
|
||||
* all collections of given `scene`.
|
||||
*
|
||||
* \note: This will include objects without a base currently (because they would belong to excluded
|
||||
* collections only e.g.).
|
||||
*/
|
||||
GSet *BKE_scene_objects_as_gset(Scene *scene, GSet *objects_gset)
|
||||
{
|
||||
BLI_Iterator iter;
|
||||
scene_objects_iterator_begin(&iter, scene, objects_gset);
|
||||
while (iter.valid) {
|
||||
BKE_scene_objects_iterator_next(&iter);
|
||||
}
|
||||
|
||||
/* `return_gset` is either given `objects_gset` (if non-NULL), or the GSet allocated by the
|
||||
* iterator. Either way, we want to get it back, and prevent `BKE_scene_objects_iterator_end`
|
||||
* from freeing it. */
|
||||
GSet *return_gset = ((SceneObjectsIteratorData *)iter.data)->visited;
|
||||
((SceneObjectsIteratorData *)iter.data)->visited = NULL;
|
||||
BKE_scene_objects_iterator_end(&iter);
|
||||
|
||||
return return_gset;
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
|
|
@ -1463,12 +1463,10 @@ static void followpath_get_tarmat(struct Depsgraph *UNUSED(depsgraph),
|
|||
* currently for paths to work it needs to go through the bevlist/displist system (ton)
|
||||
*/
|
||||
|
||||
if (ct->tar->runtime.curve_cache && ct->tar->runtime.curve_cache->path &&
|
||||
ct->tar->runtime.curve_cache->path->data) {
|
||||
if (ct->tar->runtime.curve_cache && ct->tar->runtime.curve_cache->anim_path_accum_length) {
|
||||
float quat[4];
|
||||
if ((data->followflag & FOLLOWPATH_STATIC) == 0) {
|
||||
/* animated position along curve depending on time */
|
||||
Nurb *nu = cu->nurb.first;
|
||||
curvetime = cu->ctime - data->offset;
|
||||
|
||||
/* ctime is now a proper var setting of Curve which gets set by Animato like any other var
|
||||
|
@ -1477,31 +1475,19 @@ static void followpath_get_tarmat(struct Depsgraph *UNUSED(depsgraph),
|
|||
* we divide the curvetime calculated in the previous step by the length of the path,
|
||||
* to get a time factor, which then gets clamped to lie within 0.0 - 1.0 range. */
|
||||
curvetime /= cu->pathlen;
|
||||
|
||||
if (nu && nu->flagu & CU_NURB_CYCLIC) {
|
||||
/* If the curve is cyclic, enable looping around if the time is
|
||||
* outside the bounds 0..1 */
|
||||
if ((curvetime < 0.0f) || (curvetime > 1.0f)) {
|
||||
curvetime -= floorf(curvetime);
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* The curve is not cyclic, so clamp to the begin/end points. */
|
||||
CLAMP(curvetime, 0.0f, 1.0f);
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* fixed position along curve */
|
||||
curvetime = data->offset_fac;
|
||||
}
|
||||
|
||||
if (where_on_path(ct->tar,
|
||||
curvetime,
|
||||
vec,
|
||||
dir,
|
||||
(data->followflag & FOLLOWPATH_FOLLOW) ? quat : NULL,
|
||||
&radius,
|
||||
NULL)) { /* quat_pt is quat or NULL*/
|
||||
if (BKE_where_on_path(ct->tar,
|
||||
curvetime,
|
||||
vec,
|
||||
dir,
|
||||
(data->followflag & FOLLOWPATH_FOLLOW) ? quat : NULL,
|
||||
&radius,
|
||||
NULL)) { /* quat_pt is quat or NULL*/
|
||||
float totmat[4][4];
|
||||
unit_m4(totmat);
|
||||
|
||||
|
@ -3784,8 +3770,7 @@ static void clampto_evaluate(bConstraint *con, bConstraintOb *cob, ListBase *tar
|
|||
BKE_object_minmax(ct->tar, curveMin, curveMax, true);
|
||||
|
||||
/* get targetmatrix */
|
||||
if (data->tar->runtime.curve_cache && data->tar->runtime.curve_cache->path &&
|
||||
data->tar->runtime.curve_cache->path->data) {
|
||||
if (data->tar->runtime.curve_cache && data->tar->runtime.curve_cache->anim_path_accum_length) {
|
||||
float vec[4], dir[3], totmat[4][4];
|
||||
float curvetime;
|
||||
short clamp_axis;
|
||||
|
@ -3869,7 +3854,7 @@ static void clampto_evaluate(bConstraint *con, bConstraintOb *cob, ListBase *tar
|
|||
}
|
||||
|
||||
/* 3. position on curve */
|
||||
if (where_on_path(ct->tar, curvetime, vec, dir, NULL, NULL, NULL)) {
|
||||
if (BKE_where_on_path(ct->tar, curvetime, vec, dir, NULL, NULL, NULL)) {
|
||||
unit_m4(totmat);
|
||||
copy_v3_v3(totmat[3], vec);
|
||||
|
||||
|
|
|
@ -54,7 +54,7 @@ struct CryptomatteSession {
|
|||
/* Layer names in order of creation. */
|
||||
blender::Vector<std::string> layer_names;
|
||||
|
||||
CryptomatteSession();
|
||||
CryptomatteSession() = default;
|
||||
CryptomatteSession(const Main *bmain);
|
||||
CryptomatteSession(StampData *stamp_data);
|
||||
CryptomatteSession(const Scene *scene);
|
||||
|
@ -67,10 +67,6 @@ struct CryptomatteSession {
|
|||
#endif
|
||||
};
|
||||
|
||||
CryptomatteSession::CryptomatteSession()
|
||||
{
|
||||
}
|
||||
|
||||
CryptomatteSession::CryptomatteSession(const Main *bmain)
|
||||
{
|
||||
if (!BLI_listbase_is_empty(&bmain->objects)) {
|
||||
|
|
|
@ -68,75 +68,7 @@ static void init_curve_deform(const Object *ob_curve, const Object *ob_target, C
|
|||
}
|
||||
|
||||
/**
|
||||
* This makes sure we can extend for non-cyclic.
|
||||
*
|
||||
* \return Success.
|
||||
*/
|
||||
static bool where_on_path_deform(const Object *ob_curve,
|
||||
float ctime,
|
||||
float r_vec[4],
|
||||
float r_dir[3],
|
||||
float r_quat[4],
|
||||
float *r_radius)
|
||||
{
|
||||
BevList *bl;
|
||||
float ctime1;
|
||||
int cycl = 0;
|
||||
|
||||
/* test for cyclic */
|
||||
bl = ob_curve->runtime.curve_cache->bev.first;
|
||||
if (!bl->nr) {
|
||||
return false;
|
||||
}
|
||||
if (bl->poly > -1) {
|
||||
cycl = 1;
|
||||
}
|
||||
|
||||
if (cycl == 0) {
|
||||
ctime1 = CLAMPIS(ctime, 0.0f, 1.0f);
|
||||
}
|
||||
else {
|
||||
ctime1 = ctime;
|
||||
}
|
||||
|
||||
/* vec needs 4 items */
|
||||
if (where_on_path(ob_curve, ctime1, r_vec, r_dir, r_quat, r_radius, NULL)) {
|
||||
|
||||
if (cycl == 0) {
|
||||
Path *path = ob_curve->runtime.curve_cache->path;
|
||||
float dvec[3];
|
||||
|
||||
if (ctime < 0.0f) {
|
||||
sub_v3_v3v3(dvec, path->data[1].vec, path->data[0].vec);
|
||||
mul_v3_fl(dvec, ctime * (float)path->len);
|
||||
add_v3_v3(r_vec, dvec);
|
||||
if (r_quat) {
|
||||
copy_qt_qt(r_quat, path->data[0].quat);
|
||||
}
|
||||
if (r_radius) {
|
||||
*r_radius = path->data[0].radius;
|
||||
}
|
||||
}
|
||||
else if (ctime > 1.0f) {
|
||||
sub_v3_v3v3(dvec, path->data[path->len - 1].vec, path->data[path->len - 2].vec);
|
||||
mul_v3_fl(dvec, (ctime - 1.0f) * (float)path->len);
|
||||
add_v3_v3(r_vec, dvec);
|
||||
if (r_quat) {
|
||||
copy_qt_qt(r_quat, path->data[path->len - 1].quat);
|
||||
}
|
||||
if (r_radius) {
|
||||
*r_radius = path->data[path->len - 1].radius;
|
||||
}
|
||||
/* weight - not used but could be added */
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* For each point, rotate & translate to curve use path, since it has constant distances.
|
||||
* For each point, rotate & translate to curve.
|
||||
*
|
||||
* \param co: local coord, result local too.
|
||||
* \param r_quat: returns quaternion for rotation,
|
||||
|
@ -155,7 +87,7 @@ static bool calc_curve_deform(
|
|||
return false;
|
||||
}
|
||||
|
||||
if (ob_curve->runtime.curve_cache->path == NULL) {
|
||||
if (ob_curve->runtime.curve_cache->anim_path_accum_length == NULL) {
|
||||
return false; /* happens on append, cyclic dependencies and empty curves */
|
||||
}
|
||||
|
||||
|
@ -172,8 +104,10 @@ static bool calc_curve_deform(
|
|||
}
|
||||
}
|
||||
else {
|
||||
if (LIKELY(ob_curve->runtime.curve_cache->path->totdist > FLT_EPSILON)) {
|
||||
fac = -(co[index] - cd->dmax[index]) / (ob_curve->runtime.curve_cache->path->totdist);
|
||||
CurveCache *cc = ob_curve->runtime.curve_cache;
|
||||
float totdist = BKE_anim_path_get_length(cc);
|
||||
if (LIKELY(totdist > FLT_EPSILON)) {
|
||||
fac = -(co[index] - cd->dmax[index]) / totdist;
|
||||
}
|
||||
else {
|
||||
fac = 0.0f;
|
||||
|
@ -192,8 +126,10 @@ static bool calc_curve_deform(
|
|||
}
|
||||
}
|
||||
else {
|
||||
if (LIKELY(ob_curve->runtime.curve_cache->path->totdist > FLT_EPSILON)) {
|
||||
fac = +(co[index] - cd->dmin[index]) / (ob_curve->runtime.curve_cache->path->totdist);
|
||||
CurveCache *cc = ob_curve->runtime.curve_cache;
|
||||
float totdist = BKE_anim_path_get_length(cc);
|
||||
if (LIKELY(totdist > FLT_EPSILON)) {
|
||||
fac = +(co[index] - cd->dmin[index]) / totdist;
|
||||
}
|
||||
else {
|
||||
fac = 0.0f;
|
||||
|
@ -201,7 +137,7 @@ static bool calc_curve_deform(
|
|||
}
|
||||
}
|
||||
|
||||
if (where_on_path_deform(ob_curve, fac, loc, dir, new_quat, &radius)) { /* returns OK */
|
||||
if (BKE_where_on_path(ob_curve, fac, loc, dir, new_quat, &radius, NULL)) { /* returns OK */
|
||||
float quat[4], cent[3];
|
||||
|
||||
if (cd->no_rot_axis) { /* set by caller */
|
||||
|
|
|
@ -1491,10 +1491,10 @@ static void do_makeDispListCurveTypes(Depsgraph *depsgraph,
|
|||
* was needed before and only not needed for orco calculation.
|
||||
*/
|
||||
if (!for_orco) {
|
||||
if (ob->runtime.curve_cache->path) {
|
||||
free_path(ob->runtime.curve_cache->path);
|
||||
if (ob->runtime.curve_cache->anim_path_accum_length) {
|
||||
MEM_freeN((void *)ob->runtime.curve_cache->anim_path_accum_length);
|
||||
}
|
||||
ob->runtime.curve_cache->path = NULL;
|
||||
ob->runtime.curve_cache->anim_path_accum_length = NULL;
|
||||
}
|
||||
|
||||
if (ob->type == OB_FONT) {
|
||||
|
@ -1703,7 +1703,7 @@ static void do_makeDispListCurveTypes(Depsgraph *depsgraph,
|
|||
if (!for_orco) {
|
||||
if ((cu->flag & CU_PATH) ||
|
||||
DEG_get_eval_flags_for_id(depsgraph, &ob->id) & DAG_EVAL_NEED_CURVE_PATH) {
|
||||
calc_curvepath(ob, &nubase);
|
||||
BKE_anim_path_calc_data(ob);
|
||||
}
|
||||
|
||||
BKE_nurbList_duplicate(&ob->runtime.curve_cache->deformed_nurbs, &nubase);
|
||||
|
|
|
@ -161,13 +161,13 @@ static void precalculate_effector(struct Depsgraph *depsgraph, EffectorCache *ef
|
|||
if (eff->pd->forcefield == PFIELD_GUIDE && eff->ob->type == OB_CURVE) {
|
||||
Curve *cu = eff->ob->data;
|
||||
if (cu->flag & CU_PATH) {
|
||||
if (eff->ob->runtime.curve_cache == NULL || eff->ob->runtime.curve_cache->path == NULL ||
|
||||
eff->ob->runtime.curve_cache->path->data == NULL) {
|
||||
if (eff->ob->runtime.curve_cache == NULL ||
|
||||
eff->ob->runtime.curve_cache->anim_path_accum_length == NULL) {
|
||||
BKE_displist_make_curveTypes(depsgraph, eff->scene, eff->ob, false, false);
|
||||
}
|
||||
|
||||
if (eff->ob->runtime.curve_cache->path && eff->ob->runtime.curve_cache->path->data) {
|
||||
where_on_path(
|
||||
if (eff->ob->runtime.curve_cache->anim_path_accum_length) {
|
||||
BKE_where_on_path(
|
||||
eff->ob, 0.0, eff->guide_loc, eff->guide_dir, NULL, &eff->guide_radius, NULL);
|
||||
mul_m4_v3(eff->ob->obmat, eff->guide_loc);
|
||||
mul_mat3_m4_v3(eff->ob->obmat, eff->guide_dir);
|
||||
|
|
|
@ -181,8 +181,10 @@ void BKE_fcurves_copy(ListBase *dst, ListBase *src)
|
|||
}
|
||||
}
|
||||
|
||||
/** Callback used by lib_query to walk over all ID usages (mimics `foreach_id` callback of
|
||||
* `IDTypeInfo` structure). */
|
||||
/**
|
||||
* Callback used by lib_query to walk over all ID usages (mimics `foreach_id` callback of
|
||||
* `IDTypeInfo` structure).
|
||||
*/
|
||||
void BKE_fcurve_foreach_id(FCurve *fcu, LibraryForeachIDData *data)
|
||||
{
|
||||
ChannelDriver *driver = fcu->driver;
|
||||
|
@ -1508,7 +1510,8 @@ bool test_time_fcurve(FCurve *fcu)
|
|||
/** \name F-Curve Calculations
|
||||
* \{ */
|
||||
|
||||
/* The length of each handle is not allowed to be more
|
||||
/**
|
||||
* The length of each handle is not allowed to be more
|
||||
* than the horizontal distance between (v1-v4).
|
||||
* This is to prevent curve loops.
|
||||
*
|
||||
|
@ -1555,9 +1558,13 @@ void BKE_fcurve_correct_bezpart(const float v1[2], float v2[2], float v3[2], con
|
|||
}
|
||||
}
|
||||
|
||||
/** Find roots of cubic equation (c0 x³ + c1 x² + c2 x + c3)
|
||||
/**
|
||||
.
|
||||
* Find roots of cubic equation (c0 x³ + c1 x² + c2 x + c3)
|
||||
* \return number of roots in `o`.
|
||||
* NOTE: it is up to the caller to allocate enough memory for `o`. */
|
||||
*
|
||||
* \note it is up to the caller to allocate enough memory for `o`.
|
||||
*/
|
||||
static int solve_cubic(double c0, double c1, double c2, double c3, float *o)
|
||||
{
|
||||
double a, b, c, p, q, d, t, phi;
|
||||
|
|
|
@ -1275,7 +1275,7 @@ static bool vfont_to_curve(Object *ob,
|
|||
if (cu->textoncurve && cu->textoncurve->type == OB_CURVE) {
|
||||
BLI_assert(cu->textoncurve->runtime.curve_cache != NULL);
|
||||
if (cu->textoncurve->runtime.curve_cache != NULL &&
|
||||
cu->textoncurve->runtime.curve_cache->path != NULL) {
|
||||
cu->textoncurve->runtime.curve_cache->anim_path_accum_length != NULL) {
|
||||
float distfac, imat[4][4], imat3[3][3], cmat[3][3];
|
||||
float minx, maxx;
|
||||
float timeofs, sizefac;
|
||||
|
@ -1309,7 +1309,8 @@ static bool vfont_to_curve(Object *ob,
|
|||
/* length correction */
|
||||
const float chartrans_size_x = maxx - minx;
|
||||
if (chartrans_size_x != 0.0f) {
|
||||
const float totdist = cu->textoncurve->runtime.curve_cache->path->totdist;
|
||||
const CurveCache *cc = cu->textoncurve->runtime.curve_cache;
|
||||
const float totdist = BKE_anim_path_get_length(cc);
|
||||
distfac = (sizefac * totdist) / chartrans_size_x;
|
||||
distfac = (distfac > 1.0f) ? (1.0f / distfac) : 1.0f;
|
||||
}
|
||||
|
@ -1363,8 +1364,8 @@ static bool vfont_to_curve(Object *ob,
|
|||
|
||||
/* calc the right loc AND the right rot separately */
|
||||
/* vec, tvec need 4 items */
|
||||
where_on_path(cu->textoncurve, ctime, vec, tvec, NULL, NULL, NULL);
|
||||
where_on_path(cu->textoncurve, ctime + dtime, tvec, rotvec, NULL, NULL, NULL);
|
||||
BKE_where_on_path(cu->textoncurve, ctime, vec, tvec, NULL, NULL, NULL);
|
||||
BKE_where_on_path(cu->textoncurve, ctime + dtime, tvec, rotvec, NULL, NULL, NULL);
|
||||
|
||||
mul_v3_fl(vec, sizefac);
|
||||
|
||||
|
|
|
@ -108,6 +108,18 @@ bool InstancesComponent::is_empty() const
|
|||
return transforms_.size() == 0;
|
||||
}
|
||||
|
||||
bool InstancesComponent::owns_direct_data() const
|
||||
{
|
||||
/* The object and collection instances are not direct data. Instance transforms are direct data
|
||||
* and are always owned. Therefore, instance components always own all their direct data. */
|
||||
return true;
|
||||
}
|
||||
|
||||
void InstancesComponent::ensure_owns_direct_data()
|
||||
{
|
||||
BLI_assert(this->is_mutable());
|
||||
}
|
||||
|
||||
static blender::Array<int> generate_unique_instance_ids(Span<int> original_ids)
|
||||
{
|
||||
using namespace blender;
|
||||
|
|
|
@ -157,6 +157,20 @@ bool MeshComponent::is_empty() const
|
|||
return mesh_ == nullptr;
|
||||
}
|
||||
|
||||
bool MeshComponent::owns_direct_data() const
|
||||
{
|
||||
return ownership_ == GeometryOwnershipType::Owned;
|
||||
}
|
||||
|
||||
void MeshComponent::ensure_owns_direct_data()
|
||||
{
|
||||
BLI_assert(this->is_mutable());
|
||||
if (ownership_ != GeometryOwnershipType::Owned) {
|
||||
mesh_ = BKE_mesh_copy_for_eval(mesh_, false);
|
||||
ownership_ = GeometryOwnershipType::Owned;
|
||||
}
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
|
|
|
@ -107,6 +107,20 @@ bool PointCloudComponent::is_empty() const
|
|||
return pointcloud_ == nullptr;
|
||||
}
|
||||
|
||||
bool PointCloudComponent::owns_direct_data() const
|
||||
{
|
||||
return ownership_ == GeometryOwnershipType::Owned;
|
||||
}
|
||||
|
||||
void PointCloudComponent::ensure_owns_direct_data()
|
||||
{
|
||||
BLI_assert(this->is_mutable());
|
||||
if (ownership_ != GeometryOwnershipType::Owned) {
|
||||
pointcloud_ = BKE_pointcloud_copy_for_eval(pointcloud_, false);
|
||||
ownership_ = GeometryOwnershipType::Owned;
|
||||
}
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
|
|
|
@ -97,4 +97,18 @@ Volume *VolumeComponent::get_for_write()
|
|||
return volume_;
|
||||
}
|
||||
|
||||
bool VolumeComponent::owns_direct_data() const
|
||||
{
|
||||
return ownership_ == GeometryOwnershipType::Owned;
|
||||
}
|
||||
|
||||
void VolumeComponent::ensure_owns_direct_data()
|
||||
{
|
||||
BLI_assert(this->is_mutable());
|
||||
if (ownership_ != GeometryOwnershipType::Owned) {
|
||||
volume_ = BKE_volume_copy_for_eval(volume_, false);
|
||||
ownership_ = GeometryOwnershipType::Owned;
|
||||
}
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
|
|
@ -49,10 +49,6 @@ GeometryComponent::GeometryComponent(GeometryComponentType type) : type_(type)
|
|||
{
|
||||
}
|
||||
|
||||
GeometryComponent ::~GeometryComponent()
|
||||
{
|
||||
}
|
||||
|
||||
GeometryComponent *GeometryComponent::create(GeometryComponentType component_type)
|
||||
{
|
||||
switch (component_type) {
|
||||
|
@ -182,6 +178,10 @@ void GeometrySet::compute_boundbox_without_instances(float3 *r_min, float3 *r_ma
|
|||
if (mesh != nullptr) {
|
||||
BKE_mesh_wrapper_minmax(mesh, *r_min, *r_max);
|
||||
}
|
||||
const Volume *volume = this->get_volume_for_read();
|
||||
if (volume != nullptr) {
|
||||
BKE_volume_min_max(volume, *r_min, *r_max);
|
||||
}
|
||||
}
|
||||
|
||||
std::ostream &operator<<(std::ostream &stream, const GeometrySet &geometry_set)
|
||||
|
@ -211,6 +211,19 @@ void GeometrySet::clear()
|
|||
components_.clear();
|
||||
}
|
||||
|
||||
/* Make sure that the geometry can be cached. This does not ensure ownership of object/collection
|
||||
* instances. */
|
||||
void GeometrySet::ensure_owns_direct_data()
|
||||
{
|
||||
for (GeometryComponentType type : components_.keys()) {
|
||||
const GeometryComponent *component = this->get_component_for_read(type);
|
||||
if (!component->owns_direct_data()) {
|
||||
GeometryComponent &component_for_write = this->get_component_for_write(type);
|
||||
component_for_write.ensure_owns_direct_data();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Returns a read-only mesh or null. */
|
||||
const Mesh *GeometrySet::get_mesh_for_read() const
|
||||
{
|
||||
|
|
|
@ -162,10 +162,126 @@ void geometry_set_gather_instances(const GeometrySet &geometry_set,
|
|||
geometry_set_collect_recursive(geometry_set, unit_transform, r_instance_groups);
|
||||
}
|
||||
|
||||
void gather_attribute_info(Map<std::string, AttributeKind> &attributes,
|
||||
Span<GeometryComponentType> component_types,
|
||||
Span<GeometryInstanceGroup> set_groups,
|
||||
const Set<std::string> &ignored_attributes)
|
||||
static bool collection_instance_attribute_foreach(const Collection &collection,
|
||||
const AttributeForeachCallback callback,
|
||||
const int limit,
|
||||
int &count);
|
||||
|
||||
static bool instances_attribute_foreach_recursive(const GeometrySet &geometry_set,
|
||||
const AttributeForeachCallback callback,
|
||||
const int limit,
|
||||
int &count);
|
||||
|
||||
static bool object_instance_attribute_foreach(const Object &object,
|
||||
const AttributeForeachCallback callback,
|
||||
const int limit,
|
||||
int &count)
|
||||
{
|
||||
GeometrySet instance_geometry_set = object_get_geometry_set_for_read(object);
|
||||
if (!instances_attribute_foreach_recursive(instance_geometry_set, callback, limit, count)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (object.type == OB_EMPTY) {
|
||||
const Collection *collection_instance = object.instance_collection;
|
||||
if (collection_instance != nullptr) {
|
||||
if (!collection_instance_attribute_foreach(*collection_instance, callback, limit, count)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool collection_instance_attribute_foreach(const Collection &collection,
|
||||
const AttributeForeachCallback callback,
|
||||
const int limit,
|
||||
int &count)
|
||||
{
|
||||
LISTBASE_FOREACH (const CollectionObject *, collection_object, &collection.gobject) {
|
||||
BLI_assert(collection_object->ob != nullptr);
|
||||
const Object &object = *collection_object->ob;
|
||||
if (!object_instance_attribute_foreach(object, callback, limit, count)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
LISTBASE_FOREACH (const CollectionChild *, collection_child, &collection.children) {
|
||||
BLI_assert(collection_child->collection != nullptr);
|
||||
const Collection &collection = *collection_child->collection;
|
||||
if (!collection_instance_attribute_foreach(collection, callback, limit, count)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* \return True if the recursive iteration should continue, false if the limit is reached or the
|
||||
* callback has returned false indicating it should stop.
|
||||
*/
|
||||
static bool instances_attribute_foreach_recursive(const GeometrySet &geometry_set,
|
||||
const AttributeForeachCallback callback,
|
||||
const int limit,
|
||||
int &count)
|
||||
{
|
||||
for (const GeometryComponent *component : geometry_set.get_components_for_read()) {
|
||||
if (!component->attribute_foreach(callback)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/* Now that this this geometry set is visited, increase the count and check with the limit. */
|
||||
if (limit > 0 && count++ > limit) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const InstancesComponent *instances_component =
|
||||
geometry_set.get_component_for_read<InstancesComponent>();
|
||||
if (instances_component == nullptr) {
|
||||
return true;
|
||||
}
|
||||
|
||||
for (const InstancedData &data : instances_component->instanced_data()) {
|
||||
if (data.type == INSTANCE_DATA_TYPE_OBJECT) {
|
||||
BLI_assert(data.data.object != nullptr);
|
||||
const Object &object = *data.data.object;
|
||||
if (!object_instance_attribute_foreach(object, callback, limit, count)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (data.type == INSTANCE_DATA_TYPE_COLLECTION) {
|
||||
BLI_assert(data.data.collection != nullptr);
|
||||
const Collection &collection = *data.data.collection;
|
||||
if (!collection_instance_attribute_foreach(collection, callback, limit, count)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Call the callback on all of this geometry set's components, including geometry sets from
|
||||
* instances and recursive instances. This is necessary to access available attributes without
|
||||
* making all of the set's geometry real.
|
||||
*
|
||||
* \param limit: The total number of geometry sets to visit before returning early. This is used
|
||||
* to avoid looking through too many geometry sets recursively, as an explicit tradeoff in favor
|
||||
* of performance at the cost of visiting every unique attribute.
|
||||
*/
|
||||
void geometry_set_instances_attribute_foreach(const GeometrySet &geometry_set,
|
||||
const AttributeForeachCallback callback,
|
||||
const int limit)
|
||||
{
|
||||
int count = 0;
|
||||
instances_attribute_foreach_recursive(geometry_set, callback, limit, count);
|
||||
}
|
||||
|
||||
void geometry_set_gather_instances_attribute_info(Span<GeometryInstanceGroup> set_groups,
|
||||
Span<GeometryComponentType> component_types,
|
||||
const Set<std::string> &ignored_attributes,
|
||||
Map<std::string, AttributeKind> &r_attributes)
|
||||
{
|
||||
for (const GeometryInstanceGroup &set_group : set_groups) {
|
||||
const GeometrySet &set = set_group.geometry_set;
|
||||
|
@ -189,7 +305,7 @@ void gather_attribute_info(Map<std::string, AttributeKind> &attributes,
|
|||
{attribute_kind->data_type, meta_data.data_type});
|
||||
};
|
||||
|
||||
attributes.add_or_modify(name, add_info, modify_info);
|
||||
r_attributes.add_or_modify(name, add_info, modify_info);
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
@ -383,10 +499,11 @@ static void join_instance_groups_mesh(Span<GeometryInstanceGroup> set_groups,
|
|||
|
||||
/* Don't copy attributes that are stored directly in the mesh data structs. */
|
||||
Map<std::string, AttributeKind> attributes;
|
||||
gather_attribute_info(attributes,
|
||||
component_types,
|
||||
set_groups,
|
||||
{"position", "material_index", "normal", "shade_smooth", "crease"});
|
||||
geometry_set_gather_instances_attribute_info(
|
||||
set_groups,
|
||||
component_types,
|
||||
{"position", "material_index", "normal", "shade_smooth", "crease"},
|
||||
attributes);
|
||||
join_attributes(
|
||||
set_groups, component_types, attributes, static_cast<GeometryComponent &>(dst_component));
|
||||
}
|
||||
|
@ -410,7 +527,8 @@ static void join_instance_groups_pointcloud(Span<GeometryInstanceGroup> set_grou
|
|||
PointCloud *pointcloud = BKE_pointcloud_new_nomain(totpoint);
|
||||
dst_component.replace(pointcloud);
|
||||
Map<std::string, AttributeKind> attributes;
|
||||
gather_attribute_info(attributes, {GEO_COMPONENT_TYPE_POINT_CLOUD}, set_groups, {});
|
||||
geometry_set_gather_instances_attribute_info(
|
||||
set_groups, {GEO_COMPONENT_TYPE_POINT_CLOUD}, {}, attributes);
|
||||
join_attributes(set_groups,
|
||||
{GEO_COMPONENT_TYPE_POINT_CLOUD},
|
||||
attributes,
|
||||
|
|
|
@ -222,7 +222,7 @@ void BKE_gpencil_blend_read_data(BlendDataReader *reader, bGPdata *gpd)
|
|||
/* relink palettes (old palettes deprecated, only to convert old files) */
|
||||
BLO_read_list(reader, &gpd->palettes);
|
||||
if (gpd->palettes.first != NULL) {
|
||||
LISTBASE_FOREACH (Palette *, palette, &gpd->palettes) {
|
||||
LISTBASE_FOREACH (bGPDpalette *, palette, &gpd->palettes) {
|
||||
BLO_read_list(reader, &palette->colors);
|
||||
}
|
||||
}
|
||||
|
@ -1293,7 +1293,8 @@ bGPDframe *BKE_gpencil_layer_frame_find(bGPDlayer *gpl, int cframe)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
/** Get the appropriate gp-frame from a given layer
|
||||
/**
|
||||
* Get the appropriate gp-frame from a given layer
|
||||
* - this sets the layer's actframe var (if allowed to)
|
||||
* - extension beyond range (if first gp-frame is after all frame in interest and cannot add)
|
||||
*
|
||||
|
|
|
@ -616,7 +616,8 @@ static int gpencil_remap_time_get(Depsgraph *depsgraph, Scene *scene, Object *ob
|
|||
return remap_cfra;
|
||||
}
|
||||
|
||||
/** Get the current frame re-timed with time modifiers.
|
||||
/**
|
||||
* Get the current frame re-timed with time modifiers.
|
||||
* \param depsgraph: Current depsgraph.
|
||||
* \param scene: Current scene
|
||||
* \param ob: Grease pencil object
|
||||
|
@ -746,7 +747,8 @@ void BKE_gpencil_prepare_eval_data(Depsgraph *depsgraph, Scene *scene, Object *o
|
|||
BKE_gpencil_update_orig_pointers(ob_orig, ob);
|
||||
}
|
||||
|
||||
/** Calculate gpencil modifiers.
|
||||
/**
|
||||
* Calculate gpencil modifiers.
|
||||
* \param depsgraph: Current depsgraph
|
||||
* \param scene: Current scene
|
||||
* \param ob: Grease pencil object
|
||||
|
|
|
@ -1264,9 +1264,7 @@ void BKE_libblock_copy_ex(Main *bmain, const ID *id, ID **r_newid, const int ori
|
|||
new_id->properties = IDP_CopyProperty_ex(id->properties, copy_data_flag);
|
||||
}
|
||||
|
||||
/* We may need our own flag to control that at some point, but for now 'no main' one should be
|
||||
* good enough. */
|
||||
if ((orig_flag & LIB_ID_CREATE_NO_MAIN) == 0) {
|
||||
if ((orig_flag & LIB_ID_COPY_NO_LIB_OVERRIDE) == 0) {
|
||||
if (ID_IS_OVERRIDE_LIBRARY_REAL(id)) {
|
||||
/* We do not want to copy existing override rules here, as they would break the proper
|
||||
* remapping between IDs. Proper overrides rules will be re-generated anyway. */
|
||||
|
|
|
@ -196,7 +196,10 @@ void BKE_lib_override_library_free(struct IDOverrideLibrary **override, const bo
|
|||
|
||||
static ID *lib_override_library_create_from(Main *bmain, ID *reference_id)
|
||||
{
|
||||
ID *local_id = BKE_id_copy(bmain, reference_id);
|
||||
/* Note: We do not want to copy possible override data from reference here (whether it is an
|
||||
* override template, or already an override of some other ref data). */
|
||||
ID *local_id = BKE_id_copy_ex(
|
||||
bmain, reference_id, NULL, LIB_ID_COPY_DEFAULT | LIB_ID_COPY_NO_LIB_OVERRIDE);
|
||||
|
||||
if (local_id == NULL) {
|
||||
return NULL;
|
||||
|
@ -218,10 +221,12 @@ static ID *lib_override_library_create_from(Main *bmain, ID *reference_id)
|
|||
return local_id;
|
||||
}
|
||||
|
||||
/** Check if given ID has some override rules that actually indicate the user edited it.
|
||||
/**
|
||||
* Check if given ID has some override rules that actually indicate the user edited it.
|
||||
*
|
||||
* TODO: This could be simplified by storing a flag in IDOverrideLibrary during the diffing
|
||||
* process? */
|
||||
* TODO: This could be simplified by storing a flag in #IDOverrideLibrary during the diffing
|
||||
* process?
|
||||
*/
|
||||
bool BKE_lib_override_library_is_user_edited(struct ID *id)
|
||||
{
|
||||
if (!ID_IS_OVERRIDE_LIBRARY(id)) {
|
||||
|
@ -650,18 +655,6 @@ static bool lib_override_library_create_do(Main *bmain, ID *id_root)
|
|||
return BKE_lib_override_library_create_from_tag(bmain);
|
||||
}
|
||||
|
||||
BLI_INLINE bool lib_override_library_create_post_process_object_is_instantiated(
|
||||
ViewLayer *view_layer, Object *object, const bool is_resync)
|
||||
{
|
||||
/* We cannot rely on check for object being actually instantiated in resync case, because often
|
||||
* the overridden collection is 'excluded' from the current view-layer.
|
||||
*
|
||||
* Fallback to a basic user-count check then, this is weak (since it could lead to some object
|
||||
* not being instantiated at all), but it should work fine in most common cases. */
|
||||
return ((is_resync && ID_REAL_USERS(object) >= 1) ||
|
||||
(!is_resync && BKE_view_layer_base_find(view_layer, object) != NULL));
|
||||
}
|
||||
|
||||
static void lib_override_library_create_post_process(Main *bmain,
|
||||
Scene *scene,
|
||||
ViewLayer *view_layer,
|
||||
|
@ -672,13 +665,23 @@ static void lib_override_library_create_post_process(Main *bmain,
|
|||
{
|
||||
BKE_main_collection_sync(bmain);
|
||||
|
||||
if (id_root->newid != NULL) {
|
||||
/* We create a set of all objects referenced into the scene by its hierarchy of collections.
|
||||
* NOTE: This is different that the list of bases, since objects in excluded collections etc.
|
||||
* won't have a base, but are still considered as instanced from our point of view. */
|
||||
GSet *all_objects_in_scene = BKE_scene_objects_as_gset(scene, NULL);
|
||||
|
||||
/* Instantiating the root collection or object should never be needed in resync case, since the
|
||||
* old override would be remapped to the new one. */
|
||||
if (!is_resync && id_root != NULL && id_root->newid != NULL) {
|
||||
switch (GS(id_root->name)) {
|
||||
case ID_GR: {
|
||||
Object *ob_reference = id_reference != NULL && GS(id_reference->name) == ID_OB ?
|
||||
(Object *)id_reference :
|
||||
NULL;
|
||||
Collection *collection_new = ((Collection *)id_root->newid);
|
||||
if (is_resync && BKE_collection_is_in_scene(collection_new)) {
|
||||
break;
|
||||
}
|
||||
if (ob_reference != NULL) {
|
||||
BKE_collection_add_from_object(bmain, scene, ob_reference, collection_new);
|
||||
}
|
||||
|
@ -692,43 +695,16 @@ static void lib_override_library_create_post_process(Main *bmain,
|
|||
bmain, scene, ((Collection *)id_root), collection_new);
|
||||
}
|
||||
|
||||
FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN (collection_new, ob_new) {
|
||||
if (ob_new != NULL && ob_new->id.override_library != NULL) {
|
||||
if (ob_reference != NULL) {
|
||||
Base *base = BKE_view_layer_base_find(view_layer, ob_new);
|
||||
if (!lib_override_library_create_post_process_object_is_instantiated(
|
||||
view_layer, ob_new, is_resync)) {
|
||||
BKE_collection_object_add_from(bmain, scene, ob_reference, ob_new);
|
||||
base = BKE_view_layer_base_find(view_layer, ob_new);
|
||||
DEG_id_tag_update_ex(
|
||||
bmain, &ob_new->id, ID_RECALC_TRANSFORM | ID_RECALC_BASE_FLAGS);
|
||||
}
|
||||
BLI_assert(BKE_collection_is_in_scene(collection_new));
|
||||
|
||||
if (ob_new == (Object *)ob_reference->id.newid && base != NULL) {
|
||||
/* TODO: is setting active needed? */
|
||||
BKE_view_layer_base_select_and_set_active(view_layer, base);
|
||||
}
|
||||
}
|
||||
else if (!lib_override_library_create_post_process_object_is_instantiated(
|
||||
view_layer, ob_new, is_resync)) {
|
||||
BKE_collection_object_add(bmain, collection_new, ob_new);
|
||||
DEG_id_tag_update_ex(bmain, &ob_new->id, ID_RECALC_TRANSFORM | ID_RECALC_BASE_FLAGS);
|
||||
}
|
||||
}
|
||||
}
|
||||
FOREACH_COLLECTION_OBJECT_RECURSIVE_END;
|
||||
all_objects_in_scene = BKE_scene_objects_as_gset(scene, all_objects_in_scene);
|
||||
break;
|
||||
}
|
||||
case ID_OB: {
|
||||
Object *ob_new = (Object *)id_root->newid;
|
||||
if (!lib_override_library_create_post_process_object_is_instantiated(
|
||||
view_layer, ob_new, is_resync)) {
|
||||
if (is_resync && residual_storage != NULL) {
|
||||
BKE_collection_object_add(bmain, residual_storage, ob_new);
|
||||
}
|
||||
else {
|
||||
BKE_collection_object_add_from(bmain, scene, (Object *)id_root, ob_new);
|
||||
}
|
||||
if (BLI_gset_lookup(all_objects_in_scene, ob_new) == NULL) {
|
||||
BKE_collection_object_add_from(bmain, scene, (Object *)id_root, ob_new);
|
||||
all_objects_in_scene = BKE_scene_objects_as_gset(scene, all_objects_in_scene);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -738,16 +714,15 @@ static void lib_override_library_create_post_process(Main *bmain,
|
|||
}
|
||||
|
||||
/* We need to ensure all new overrides of objects are properly instantiated. */
|
||||
Collection *default_instantiating_collection = residual_storage;
|
||||
LISTBASE_FOREACH (Object *, ob, &bmain->objects) {
|
||||
Object *ob_new = (Object *)ob->id.newid;
|
||||
if (ob_new != NULL) {
|
||||
BLI_assert(ob_new->id.override_library != NULL &&
|
||||
ob_new->id.override_library->reference == &ob->id);
|
||||
|
||||
Collection *default_instantiating_collection = residual_storage;
|
||||
if (!lib_override_library_create_post_process_object_is_instantiated(
|
||||
view_layer, ob_new, is_resync)) {
|
||||
if (default_instantiating_collection == NULL) {
|
||||
if (BLI_gset_lookup(all_objects_in_scene, ob_new) == NULL) {
|
||||
if (id_root != NULL && default_instantiating_collection == NULL) {
|
||||
switch (GS(id_root->name)) {
|
||||
case ID_GR: {
|
||||
default_instantiating_collection = BKE_collection_add(
|
||||
|
@ -768,21 +743,23 @@ static void lib_override_library_create_post_process(Main *bmain,
|
|||
default_instantiating_collection = collection;
|
||||
}
|
||||
}
|
||||
if (default_instantiating_collection == NULL) {
|
||||
default_instantiating_collection = scene->master_collection;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
BLI_assert(0);
|
||||
}
|
||||
}
|
||||
if (default_instantiating_collection == NULL) {
|
||||
default_instantiating_collection = scene->master_collection;
|
||||
}
|
||||
|
||||
BKE_collection_object_add(bmain, default_instantiating_collection, ob_new);
|
||||
DEG_id_tag_update_ex(bmain, &ob_new->id, ID_RECALC_TRANSFORM | ID_RECALC_BASE_FLAGS);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BLI_gset_free(all_objects_in_scene, NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -893,7 +870,8 @@ bool BKE_lib_override_library_resync(Main *bmain,
|
|||
ViewLayer *view_layer,
|
||||
ID *id_root,
|
||||
Collection *override_resync_residual_storage,
|
||||
const bool do_hierarchy_enforce)
|
||||
const bool do_hierarchy_enforce,
|
||||
const bool do_post_process)
|
||||
{
|
||||
BLI_assert(ID_IS_OVERRIDE_LIBRARY_REAL(id_root));
|
||||
BLI_assert(!ID_IS_LINKED(id_root));
|
||||
|
@ -917,7 +895,7 @@ bool BKE_lib_override_library_resync(Main *bmain,
|
|||
BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, __func__);
|
||||
ID *id;
|
||||
FOREACH_MAIN_ID_BEGIN (bmain, id) {
|
||||
if (id->tag & LIB_TAG_DOIT && ID_IS_OVERRIDE_LIBRARY_REAL(id)) {
|
||||
if (id->tag & LIB_TAG_DOIT && !ID_IS_LINKED(id) && ID_IS_OVERRIDE_LIBRARY_REAL(id)) {
|
||||
/* While this should not happen in typical cases (and won't be properly supported here), user
|
||||
* is free to do all kind of very bad things, including having different local overrides of a
|
||||
* same linked ID in a same hierarchy. */
|
||||
|
@ -1087,6 +1065,7 @@ bool BKE_lib_override_library_resync(Main *bmain,
|
|||
/* Otherwise, keep them, user needs to decide whether what to do with them. */
|
||||
BLI_assert((id->tag & LIB_TAG_DOIT) == 0);
|
||||
id_fake_user_set(id);
|
||||
id->flag |= LIB_LIB_OVERRIDE_RESYNC_LEFTOVER;
|
||||
CLOG_INFO(&LOG, 2, "Old override %s is being kept around as it was user-edited", id->name);
|
||||
}
|
||||
}
|
||||
|
@ -1099,18 +1078,20 @@ bool BKE_lib_override_library_resync(Main *bmain,
|
|||
*/
|
||||
id_root = id_root_reference->newid;
|
||||
|
||||
/* Essentially ensures that potentially new overrides of new objects will be instantiated. */
|
||||
/* Note: Here 'reference' collection and 'newly added' collection are the same, which is fine
|
||||
* since we already relinked old root override collection to new resync'ed one above. So this
|
||||
* call is not expected to instantiate this new resync'ed collection anywhere, just to ensure
|
||||
* that we do not have any stray objects. */
|
||||
lib_override_library_create_post_process(bmain,
|
||||
scene,
|
||||
view_layer,
|
||||
id_root_reference,
|
||||
id_root,
|
||||
override_resync_residual_storage,
|
||||
true);
|
||||
if (do_post_process) {
|
||||
/* Essentially ensures that potentially new overrides of new objects will be instantiated. */
|
||||
/* Note: Here 'reference' collection and 'newly added' collection are the same, which is fine
|
||||
* since we already relinked old root override collection to new resync'ed one above. So this
|
||||
* call is not expected to instantiate this new resync'ed collection anywhere, just to ensure
|
||||
* that we do not have any stray objects. */
|
||||
lib_override_library_create_post_process(bmain,
|
||||
scene,
|
||||
view_layer,
|
||||
id_root_reference,
|
||||
id_root,
|
||||
override_resync_residual_storage,
|
||||
true);
|
||||
}
|
||||
|
||||
/* Cleanup. */
|
||||
BLI_ghash_free(linkedref_to_old_override, NULL, NULL);
|
||||
|
@ -1242,9 +1223,10 @@ void BKE_lib_override_library_main_resync(Main *bmain, Scene *scene, ViewLayer *
|
|||
continue;
|
||||
}
|
||||
do_continue = true;
|
||||
|
||||
CLOG_INFO(&LOG, 2, "Resyncing %s...", id->name);
|
||||
const bool success = BKE_lib_override_library_resync(
|
||||
bmain, scene, view_layer, id, override_resync_residual_storage, false);
|
||||
bmain, scene, view_layer, id, override_resync_residual_storage, false, false);
|
||||
CLOG_INFO(&LOG, 2, "\tSuccess: %d", success);
|
||||
break;
|
||||
}
|
||||
|
@ -1256,6 +1238,10 @@ void BKE_lib_override_library_main_resync(Main *bmain, Scene *scene, ViewLayer *
|
|||
FOREACH_MAIN_LISTBASE_END;
|
||||
}
|
||||
|
||||
/* Essentially ensures that potentially new overrides of new objects will be instantiated. */
|
||||
lib_override_library_create_post_process(
|
||||
bmain, scene, view_layer, NULL, NULL, override_resync_residual_storage, true);
|
||||
|
||||
if (BKE_collection_is_empty(override_resync_residual_storage)) {
|
||||
BKE_collection_delete(bmain, override_resync_residual_storage, true);
|
||||
}
|
||||
|
@ -2426,8 +2412,10 @@ ID *BKE_lib_override_library_operations_store_start(Main *bmain,
|
|||
return storage_id;
|
||||
}
|
||||
|
||||
/** Restore given ID modified by \a BKE_lib_override_library_operations_store_start, to its
|
||||
* original state. */
|
||||
/**
|
||||
* Restore given ID modified by #BKE_lib_override_library_operations_store_start, to its
|
||||
* original state.
|
||||
*/
|
||||
void BKE_lib_override_library_operations_store_end(
|
||||
OverrideLibraryStorage *UNUSED(override_storage), ID *local)
|
||||
{
|
||||
|
|
|
@ -231,7 +231,8 @@ const MEdge *MeshesToIMeshInfo::input_medge_for_orig_index(int orig_index,
|
|||
return medge;
|
||||
}
|
||||
|
||||
/** Convert all of the meshes in `meshes` to an `IMesh` and return that.
|
||||
/**
|
||||
* Convert all of the meshes in `meshes` to an `IMesh` and return that.
|
||||
* All of the coordinates are transformed into the local space of the
|
||||
* first Mesh. To do this transformation, we also need the transformation
|
||||
* obmats corresponding to the Meshes, so they are in the `obmats` argument.
|
||||
|
@ -638,7 +639,8 @@ static void copy_or_interp_loop_attributes(Mesh *dest_mesh,
|
|||
}
|
||||
}
|
||||
|
||||
/** Make sure that there are custom data layers in the target mesh
|
||||
/**
|
||||
* Make sure that there are custom data layers in the target mesh
|
||||
* corresponding to all target layers in all of the operands after the first.
|
||||
* (The target should already have layers for those in the first operand mesh).
|
||||
* Edges done separately -- will have to be done later, after edges are made.
|
||||
|
@ -673,7 +675,8 @@ static void merge_edge_customdata_layers(Mesh *target, MeshesToIMeshInfo &mim)
|
|||
}
|
||||
}
|
||||
|
||||
/** Convert the output IMesh im to a Blender Mesh,
|
||||
/**
|
||||
* Convert the output IMesh im to a Blender Mesh,
|
||||
* using the information in mim to get all the attributes right.
|
||||
*/
|
||||
static Mesh *imesh_to_mesh(IMesh *im, MeshesToIMeshInfo &mim)
|
||||
|
|
|
@ -172,7 +172,7 @@ class FairingContext {
|
|||
}
|
||||
|
||||
/* Early return, nothing to do. */
|
||||
if (num_affected_vertices == 0 || num_affected_vertices == totvert_) {
|
||||
if (ELEM(num_affected_vertices, 0, totvert_)) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -434,8 +434,10 @@ NlaStrip *BKE_nla_add_soundstrip(Main *bmain, Scene *scene, Speaker *speaker)
|
|||
return strip;
|
||||
}
|
||||
|
||||
/** Callback used by lib_query to walk over all ID usages (mimics `foreach_id` callback of
|
||||
* `IDTypeInfo` structure). */
|
||||
/**
|
||||
* Callback used by lib_query to walk over all ID usages (mimics `foreach_id` callback of
|
||||
* `IDTypeInfo` structure).
|
||||
*/
|
||||
void BKE_nla_strip_foreach_id(NlaStrip *strip, LibraryForeachIDData *data)
|
||||
{
|
||||
BKE_LIB_FOREACHID_PROCESS(data, strip->act, IDWALK_CB_USER);
|
||||
|
@ -1380,8 +1382,10 @@ static void nlastrip_fix_resize_overlaps(NlaStrip *strip)
|
|||
}
|
||||
}
|
||||
|
||||
/** Recalculate the start and end frames for the strip to match the bounds of its action such that
|
||||
* the overall NLA animation result is unchanged. */
|
||||
/**
|
||||
* Recalculate the start and end frames for the strip to match the bounds of its action such that
|
||||
* the overall NLA animation result is unchanged.
|
||||
*/
|
||||
void BKE_nlastrip_recalculate_bounds_sync_action(NlaStrip *strip)
|
||||
{
|
||||
float prev_actstart;
|
||||
|
|
|
@ -1314,8 +1314,8 @@ void nodeUnregisterType(bNodeType *nt)
|
|||
bool nodeTypeUndefined(bNode *node)
|
||||
{
|
||||
return (node->typeinfo == &NodeTypeUndefined) ||
|
||||
(node->type == NODE_GROUP && node->id && ID_IS_LINKED(node->id) &&
|
||||
(node->id->tag & LIB_TAG_MISSING));
|
||||
((node->type == NODE_GROUP || node->type == NODE_CUSTOM_GROUP) && node->id &&
|
||||
ID_IS_LINKED(node->id) && (node->id->tag & LIB_TAG_MISSING));
|
||||
}
|
||||
|
||||
GHashIterator *nodeTypeGetIterator(void)
|
||||
|
@ -3096,10 +3096,12 @@ void ntreeSetOutput(bNodeTree *ntree)
|
|||
* might be different for editor or for "real" use... */
|
||||
}
|
||||
|
||||
/** Get address of potential nodetree pointer of given ID.
|
||||
/**
|
||||
* Get address of potential node-tree pointer of given ID.
|
||||
*
|
||||
* \warning Using this function directly is potentially dangerous, if you don't know or are not
|
||||
* sure, please use `ntreeFromID()` instead. */
|
||||
* sure, please use `ntreeFromID()` instead.
|
||||
*/
|
||||
bNodeTree **BKE_ntree_ptr_from_id(ID *id)
|
||||
{
|
||||
switch (GS(id->name)) {
|
||||
|
@ -4937,6 +4939,7 @@ static void registerGeometryNodes()
|
|||
register_node_type_geo_attribute_vector_math();
|
||||
register_node_type_geo_attribute_remove();
|
||||
register_node_type_geo_boolean();
|
||||
register_node_type_geo_bounding_box();
|
||||
register_node_type_geo_collection_info();
|
||||
register_node_type_geo_edge_split();
|
||||
register_node_type_geo_is_viewport();
|
||||
|
|
|
@ -311,8 +311,8 @@ static void object_free_data(ID *id)
|
|||
/* Free runtime curves data. */
|
||||
if (ob->runtime.curve_cache) {
|
||||
BKE_curve_bevelList_free(&ob->runtime.curve_cache->bev);
|
||||
if (ob->runtime.curve_cache->path) {
|
||||
free_path(ob->runtime.curve_cache->path);
|
||||
if (ob->runtime.curve_cache->anim_path_accum_length) {
|
||||
MEM_freeN((void *)ob->runtime.curve_cache->anim_path_accum_length);
|
||||
}
|
||||
MEM_freeN(ob->runtime.curve_cache);
|
||||
ob->runtime.curve_cache = NULL;
|
||||
|
@ -1188,8 +1188,8 @@ void BKE_object_free_curve_cache(Object *ob)
|
|||
if (ob->runtime.curve_cache) {
|
||||
BKE_displist_free(&ob->runtime.curve_cache->disp);
|
||||
BKE_curve_bevelList_free(&ob->runtime.curve_cache->bev);
|
||||
if (ob->runtime.curve_cache->path) {
|
||||
free_path(ob->runtime.curve_cache->path);
|
||||
if (ob->runtime.curve_cache->anim_path_accum_length) {
|
||||
MEM_freeN((void *)ob->runtime.curve_cache->anim_path_accum_length);
|
||||
}
|
||||
BKE_nurbList_free(&ob->runtime.curve_cache->deformed_nurbs);
|
||||
MEM_freeN(ob->runtime.curve_cache);
|
||||
|
@ -1359,8 +1359,9 @@ static bool object_modifier_type_copy_check(ModifierType md_type)
|
|||
return !ELEM(md_type, eModifierType_Hook, eModifierType_Collision);
|
||||
}
|
||||
|
||||
/** Find a `psys` matching given `psys_src` in `ob_dst` (i.e. sharing the same ParticleSettings
|
||||
* ID), or add one, and return valid `psys` from `ob_dst`.
|
||||
/**
|
||||
* Find a `psys` matching given `psys_src` in `ob_dst` (i.e. sharing the same ParticleSettings ID),
|
||||
* or add one, and return valid `psys` from `ob_dst`.
|
||||
*
|
||||
* \note Order handling is fairly weak here. This code assumes that it is called **before** the
|
||||
* modifier using the psys is actually copied, and that this copied modifier will be added at the
|
||||
|
@ -1392,7 +1393,8 @@ static ParticleSystem *object_copy_modifier_particle_system_ensure(Main *bmain,
|
|||
return psys_dst;
|
||||
}
|
||||
|
||||
/** Copy a single modifier.
|
||||
/**
|
||||
* Copy a single modifier.
|
||||
*
|
||||
* \note **Do not** use this function to copy a whole modifier stack (see note below too). Use
|
||||
* `BKE_object_modifier_stack_copy` instead.
|
||||
|
@ -1400,7 +1402,8 @@ static ParticleSystem *object_copy_modifier_particle_system_ensure(Main *bmain,
|
|||
* \note Complex modifiers relaying on other data (like e.g. dynamic paint or fluid using particle
|
||||
* systems) are not always 100% 'correctly' copied here, since we have to use heuristics to decide
|
||||
* which particle system to use or add in `ob_dst`, and it's placement in the stack, etc. If used
|
||||
* more than once, this function should preferably be called in stack order. */
|
||||
* more than once, this function should preferably be called in stack order.
|
||||
*/
|
||||
bool BKE_object_copy_modifier(
|
||||
Main *bmain, Scene *scene, Object *ob_dst, const Object *ob_src, ModifierData *md_src)
|
||||
{
|
||||
|
@ -1500,10 +1503,12 @@ bool BKE_object_copy_modifier(
|
|||
return true;
|
||||
}
|
||||
|
||||
/** Copy a single GPencil modifier.
|
||||
/**
|
||||
* Copy a single GPencil modifier.
|
||||
*
|
||||
* \note **Do not** use this function to copy a whole modifier stack. Use
|
||||
* `BKE_object_modifier_stack_copy` instead. */
|
||||
* `BKE_object_modifier_stack_copy` instead.
|
||||
*/
|
||||
bool BKE_object_copy_gpencil_modifier(struct Object *ob_dst, GpencilModifierData *gmd_src)
|
||||
{
|
||||
BLI_assert(ob_dst->type == OB_GPENCIL);
|
||||
|
@ -1756,6 +1761,10 @@ void BKE_object_free_derived_caches(Object *ob)
|
|||
BKE_geometry_set_free(ob->runtime.geometry_set_eval);
|
||||
ob->runtime.geometry_set_eval = NULL;
|
||||
}
|
||||
if (ob->runtime.geometry_set_preview != NULL) {
|
||||
BKE_geometry_set_free(ob->runtime.geometry_set_preview);
|
||||
ob->runtime.geometry_set_preview = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void BKE_object_free_caches(Object *object)
|
||||
|
@ -1806,6 +1815,18 @@ void BKE_object_free_caches(Object *object)
|
|||
}
|
||||
}
|
||||
|
||||
/* Can be called from multiple threads. */
|
||||
void BKE_object_set_preview_geometry_set(Object *ob, struct GeometrySet *geometry_set)
|
||||
{
|
||||
static ThreadMutex mutex = BLI_MUTEX_INITIALIZER;
|
||||
BLI_mutex_lock(&mutex);
|
||||
if (ob->runtime.geometry_set_preview != NULL) {
|
||||
BKE_geometry_set_free(ob->runtime.geometry_set_preview);
|
||||
}
|
||||
ob->runtime.geometry_set_preview = geometry_set;
|
||||
BLI_mutex_unlock(&mutex);
|
||||
}
|
||||
|
||||
/**
|
||||
* Actual check for internal data, not context or flags.
|
||||
*/
|
||||
|
@ -3244,7 +3265,7 @@ static bool ob_parcurve(Object *ob, Object *par, float r_mat[4][4])
|
|||
if (par->runtime.curve_cache == NULL) {
|
||||
return false;
|
||||
}
|
||||
if (par->runtime.curve_cache->path == NULL) {
|
||||
if (par->runtime.curve_cache->anim_path_accum_length == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -3260,12 +3281,12 @@ static bool ob_parcurve(Object *ob, Object *par, float r_mat[4][4])
|
|||
else {
|
||||
ctime = cu->ctime;
|
||||
}
|
||||
CLAMP(ctime, 0.0f, 1.0f);
|
||||
|
||||
unit_m4(r_mat);
|
||||
|
||||
/* vec: 4 items! */
|
||||
if (where_on_path(par, ctime, vec, dir, (cu->flag & CU_FOLLOW) ? quat : NULL, &radius, NULL)) {
|
||||
if (BKE_where_on_path(
|
||||
par, ctime, vec, dir, (cu->flag & CU_FOLLOW) ? quat : NULL, &radius, NULL)) {
|
||||
if (cu->flag & CU_FOLLOW) {
|
||||
quat_apply_track(quat, ob->trackflag, ob->upflag);
|
||||
normalize_qt(quat);
|
||||
|
|
|
@ -2417,14 +2417,15 @@ int do_guides(Depsgraph *depsgraph,
|
|||
cu = (Curve *)eff->ob->data;
|
||||
|
||||
if (pd->flag & PFIELD_GUIDE_PATH_ADD) {
|
||||
if (where_on_path(
|
||||
if (BKE_where_on_path(
|
||||
eff->ob, data->strength * guidetime, guidevec, guidedir, NULL, &radius, &weight) ==
|
||||
0) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (where_on_path(eff->ob, guidetime, guidevec, guidedir, NULL, &radius, &weight) == 0) {
|
||||
if (BKE_where_on_path(eff->ob, guidetime, guidevec, guidedir, NULL, &radius, &weight) ==
|
||||
0) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -641,7 +641,15 @@ static BMFace *pbvh_bmesh_face_create(
|
|||
/* ensure we never add existing face */
|
||||
BLI_assert(!BM_face_exists(v_tri, 3));
|
||||
|
||||
BMFace *f = BM_face_create(pbvh->bm, v_tri, e_tri, 3, f_example, BM_CREATE_NOP);
|
||||
BMFace *f;
|
||||
|
||||
if (!e_tri) {
|
||||
f = BM_face_create_verts(pbvh->bm, v_tri, 3, f_example, BM_CREATE_NOP, true);
|
||||
}
|
||||
else {
|
||||
f = BM_face_create(pbvh->bm, v_tri, e_tri, 3, f_example, BM_CREATE_NOP);
|
||||
}
|
||||
|
||||
f->head.hflag = f_example->head.hflag;
|
||||
|
||||
BLI_table_gset_insert(node->bm_faces, f);
|
||||
|
@ -2294,7 +2302,7 @@ static void pbvh_bmesh_collapse_edge(PBVH *pbvh,
|
|||
* really buy anything. */
|
||||
BLI_buffer_clear(deleted_faces);
|
||||
|
||||
#define MAX_LS 24
|
||||
#define MAX_LS 64
|
||||
|
||||
BMLoop *l;
|
||||
BMLoop *ls[MAX_LS];
|
||||
|
@ -2318,26 +2326,41 @@ static void pbvh_bmesh_collapse_edge(PBVH *pbvh,
|
|||
BM_LOOPS_OF_VERT_ITER_END;
|
||||
|
||||
void *blocks[MAX_LS];
|
||||
float ws[MAX_LS], w = totl > 1 ? 1.0f / (float)(totl - 1) : 1.0f;
|
||||
float ws[MAX_LS], w = totl > 0 ? 1.0f / (float)(totl) : 1.0f;
|
||||
|
||||
for (int i = 0; i < totl - 1; i++) {
|
||||
blocks[i] = ls[i + 1]->head.data;
|
||||
for (int i = 0; i < totl; i++) {
|
||||
blocks[i] = ls[i]->head.data;
|
||||
ws[i] = w;
|
||||
}
|
||||
|
||||
if (totl > 1) {
|
||||
CustomData_bmesh_interp(&pbvh->bm->ldata, blocks, ws, NULL, totl - 1, ls[0]->head.data);
|
||||
|
||||
//snap customdata
|
||||
if (totl > 0) {
|
||||
CustomData_bmesh_interp(&pbvh->bm->ldata, blocks, ws, NULL, totl, ls[0]->head.data);
|
||||
//*
|
||||
BM_LOOPS_OF_VERT_ITER_BEGIN (l, v_del) {
|
||||
BMLoop *l2 = l->v != v_del ? l->next : l;
|
||||
|
||||
if (l2 == ls[0]) {
|
||||
continue;
|
||||
}
|
||||
|
||||
CustomData_bmesh_copy_data(
|
||||
&pbvh->bm->ldata, &pbvh->bm->ldata, ls[0]->head.data, &l->head.data);
|
||||
&pbvh->bm->ldata, &pbvh->bm->ldata, ls[0]->head.data, &l2->head.data);
|
||||
}
|
||||
BM_LOOPS_OF_VERT_ITER_END;
|
||||
|
||||
BM_LOOPS_OF_VERT_ITER_BEGIN (l, v_conn) {
|
||||
BMLoop *l2 = l->v != v_conn ? l->next : l;
|
||||
|
||||
if (l2 == ls[0]) {
|
||||
continue;
|
||||
}
|
||||
|
||||
CustomData_bmesh_copy_data(
|
||||
&pbvh->bm->ldata, &pbvh->bm->ldata, ls[0]->head.data, &l->head.data);
|
||||
&pbvh->bm->ldata, &pbvh->bm->ldata, ls[0]->head.data, &l2->head.data);
|
||||
}
|
||||
BM_LOOPS_OF_VERT_ITER_END;
|
||||
//*/
|
||||
}
|
||||
|
||||
BM_LOOPS_OF_VERT_ITER_BEGIN (l, v_del) {
|
||||
|
@ -2456,8 +2479,6 @@ static void pbvh_bmesh_collapse_edge(PBVH *pbvh,
|
|||
// log vert in bmlog, but don't update original customata layers, we want them to be
|
||||
// interpolated
|
||||
BM_log_vert_before_modified(pbvh->bm_log, v_conn, eq_ctx->cd_vert_mask_offset, true);
|
||||
// void *dummy;
|
||||
// BKE_pbvh_bmesh_update_origvert(pbvh, v_conn, &dummy, &dummy, &dummy);
|
||||
|
||||
mid_v3_v3v3(v_conn->co, v_conn->co, v_del->co);
|
||||
add_v3_v3(v_conn->no, v_del->no);
|
||||
|
@ -3094,7 +3115,7 @@ static void pbvh_bmesh_create_nodes_fast_recursive(
|
|||
BKE_pbvh_node_mark_rebuild_draw(n);
|
||||
|
||||
BKE_pbvh_node_fully_hidden_set(n, !has_visible);
|
||||
n->flag |= PBVH_UpdateNormals|PBVH_UpdateCurvatureDir;
|
||||
n->flag |= PBVH_UpdateNormals | PBVH_UpdateCurvatureDir;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3254,6 +3275,151 @@ bool BKE_pbvh_bmesh_update_topology_nodes(PBVH *pbvh,
|
|||
return modified;
|
||||
}
|
||||
|
||||
__attribute__((optnone)) static bool cleanup_valence_3_4(PBVH *pbvh,
|
||||
const float center[3],
|
||||
const float view_normal[3],
|
||||
float radius,
|
||||
const bool use_frontface,
|
||||
const bool use_projected)
|
||||
{
|
||||
bool modified = false;
|
||||
|
||||
float radius2 = radius * 1.25;
|
||||
float rsqr = radius2 * radius2;
|
||||
|
||||
for (int n = 0; n < pbvh->totnode; n++) {
|
||||
PBVHNode *node = pbvh->nodes + n;
|
||||
|
||||
/* Check leaf nodes marked for topology update */
|
||||
bool ok = (node->flag & PBVH_Leaf) && (node->flag & PBVH_UpdateTopology);
|
||||
ok = ok && !(node->flag & PBVH_FullyHidden);
|
||||
|
||||
if (!ok) {
|
||||
continue;
|
||||
}
|
||||
|
||||
PBVHVertexIter vi;
|
||||
GSetIterator gi;
|
||||
BMVert *v;
|
||||
|
||||
TGSET_ITER (v, node->bm_unique_verts) {
|
||||
if (len_squared_v3v3(v->co, center) >= rsqr) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const int val = BM_vert_edge_count(v);
|
||||
if (val < 3 || val > 4) {
|
||||
continue;
|
||||
}
|
||||
|
||||
BMIter iter;
|
||||
BMLoop *l;
|
||||
BMLoop *ls[4];
|
||||
BMVert *vs[4];
|
||||
BMEdge *es[4];
|
||||
|
||||
l = v->e->l;
|
||||
|
||||
if (!l) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (l->v != v) {
|
||||
l = l->next;
|
||||
}
|
||||
|
||||
bool bad = false;
|
||||
int i = 0;
|
||||
|
||||
for (int j = 0; j < val; j++) {
|
||||
ls[i++] = l->v == v ? l->next : l;
|
||||
|
||||
l = l->prev->radial_next;
|
||||
|
||||
if (l->v != v) {
|
||||
l = l->next;
|
||||
}
|
||||
|
||||
if (l->radial_next == l || l->radial_next->radial_next != l) {
|
||||
bad = true;
|
||||
break;
|
||||
}
|
||||
|
||||
for (int k = 0; k < j; k++) {
|
||||
if (ls[k]->v == ls[j]->v) {
|
||||
if (ls[j]->next->v != v) {
|
||||
ls[j] = ls[j]->next;
|
||||
}
|
||||
else {
|
||||
bad = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (ls[k]->f == ls[j]->f) {
|
||||
bad = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (bad) {
|
||||
continue;
|
||||
}
|
||||
|
||||
pbvh_bmesh_vert_remove(pbvh, v);
|
||||
|
||||
BMFace *f;
|
||||
BM_ITER_ELEM (f, &iter, v, BM_FACES_OF_VERT) {
|
||||
pbvh_bmesh_face_remove(pbvh, f);
|
||||
}
|
||||
|
||||
modified = true;
|
||||
|
||||
l = v->e->l;
|
||||
|
||||
vs[0] = ls[0]->v;
|
||||
vs[1] = ls[1]->v;
|
||||
vs[2] = ls[2]->v;
|
||||
|
||||
BMFace *f1 = NULL;
|
||||
if (vs[0] != vs[1] && vs[1] != vs[2] && vs[0] != vs[2]) {
|
||||
f1 = pbvh_bmesh_face_create(pbvh, n, vs, NULL, l->f);
|
||||
}
|
||||
|
||||
if (val == 4 && vs[0] != vs[2] && vs[2] != vs[3] && vs[0] != vs[3]) {
|
||||
vs[0] = ls[0]->v;
|
||||
vs[1] = ls[2]->v;
|
||||
vs[2] = ls[3]->v;
|
||||
|
||||
BMFace *f2 = pbvh_bmesh_face_create(pbvh, n, vs, NULL, v->e->l->f);
|
||||
SWAP(void *, f2->l_first->prev->head.data, ls[3]->head.data);
|
||||
|
||||
CustomData_bmesh_copy_data(
|
||||
&pbvh->bm->ldata, &pbvh->bm->ldata, ls[0]->head.data, &f2->l_first->head.data);
|
||||
CustomData_bmesh_copy_data(
|
||||
&pbvh->bm->ldata, &pbvh->bm->ldata, ls[2]->head.data, &f2->l_first->next->head.data);
|
||||
}
|
||||
|
||||
if (f1) {
|
||||
SWAP(void *, f1->l_first->head.data, ls[0]->head.data);
|
||||
SWAP(void *, f1->l_first->next->head.data, ls[1]->head.data);
|
||||
SWAP(void *, f1->l_first->prev->head.data, ls[2]->head.data);
|
||||
}
|
||||
|
||||
BM_vert_kill(pbvh->bm, v);
|
||||
}
|
||||
TGSET_ITER_END
|
||||
}
|
||||
|
||||
if (modified) {
|
||||
pbvh->bm->elem_index_dirty |= BM_VERT | BM_FACE | BM_EDGE;
|
||||
pbvh->bm->elem_table_dirty |= BM_VERT | BM_FACE | BM_EDGE;
|
||||
}
|
||||
|
||||
return modified;
|
||||
}
|
||||
|
||||
/* Collapse short edges, subdivide long edges */
|
||||
bool BKE_pbvh_bmesh_update_topology(PBVH *pbvh,
|
||||
PBVHTopologyUpdateMode mode,
|
||||
|
@ -3288,6 +3454,7 @@ bool BKE_pbvh_bmesh_update_topology(PBVH *pbvh,
|
|||
if (view_normal) {
|
||||
BLI_assert(len_squared_v3(view_normal) != 0.0f);
|
||||
}
|
||||
|
||||
#if 1
|
||||
if (mode & PBVH_Collapse) {
|
||||
EdgeQueue q;
|
||||
|
@ -3335,7 +3502,13 @@ bool BKE_pbvh_bmesh_update_topology(PBVH *pbvh,
|
|||
BLI_heapsimple_free(q.heap, NULL);
|
||||
BLI_mempool_destroy(queue_pool);
|
||||
}
|
||||
|
||||
#endif
|
||||
if (mode & PBVH_Cleanup) {
|
||||
modified |= cleanup_valence_3_4(
|
||||
pbvh, center, view_normal, radius, use_frontface, use_projected);
|
||||
}
|
||||
|
||||
if (modified) {
|
||||
|
||||
#ifdef PROXY_ADVANCED
|
||||
|
@ -3696,7 +3869,7 @@ static void pbvh_bmesh_join_nodes(PBVH *bvh)
|
|||
j = 0;
|
||||
for (int i = 0; i < bvh->totnode; i++) {
|
||||
if (!(bvh->nodes[i].flag & PBVH_Delete)) {
|
||||
if (bvh->nodes[i].children_offset >= bvh->totnode-1) {
|
||||
if (bvh->nodes[i].children_offset >= bvh->totnode - 1) {
|
||||
printf("error %i %i\n", i, bvh->nodes[i].children_offset);
|
||||
continue;
|
||||
}
|
||||
|
|
|
@ -1350,6 +1350,13 @@ static void write_area(BlendWriter *writer, ScrArea *area)
|
|||
}
|
||||
else if (sl->spacetype == SPACE_SPREADSHEET) {
|
||||
BLO_write_struct(writer, SpaceSpreadsheet, sl);
|
||||
|
||||
SpaceSpreadsheet *sspreadsheet = (SpaceSpreadsheet *)sl;
|
||||
LISTBASE_FOREACH (SpreadsheetColumn *, column, &sspreadsheet->columns) {
|
||||
BLO_write_struct(writer, SpreadsheetColumn, column);
|
||||
BLO_write_struct(writer, SpreadsheetColumnID, column->id);
|
||||
BLO_write_string(writer, column->id->name);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1702,6 +1709,12 @@ static void direct_link_area(BlendDataReader *reader, ScrArea *area)
|
|||
SpaceSpreadsheet *sspreadsheet = (SpaceSpreadsheet *)sl;
|
||||
|
||||
sspreadsheet->runtime = NULL;
|
||||
|
||||
BLO_read_list(reader, &sspreadsheet->columns);
|
||||
LISTBASE_FOREACH (SpreadsheetColumn *, column, &sspreadsheet->columns) {
|
||||
BLO_read_data_address(reader, &column->id);
|
||||
BLO_read_data_address(reader, &column->id->name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -523,7 +523,8 @@ Text *BKE_text_load_ex(Main *bmain, const char *file, const char *relpath, const
|
|||
return ta;
|
||||
}
|
||||
|
||||
/** Load a text file.
|
||||
/**
|
||||
* Load a text file.
|
||||
*
|
||||
* \note Text data-blocks have no user by default, only the 'real user' flag.
|
||||
*/
|
||||
|
|
|
@ -28,7 +28,10 @@
|
|||
|
||||
#include "BLI_compiler_compat.h"
|
||||
#include "BLI_fileops.h"
|
||||
#include "BLI_float3.hh"
|
||||
#include "BLI_float4x4.hh"
|
||||
#include "BLI_ghash.h"
|
||||
#include "BLI_index_range.hh"
|
||||
#include "BLI_map.hh"
|
||||
#include "BLI_math.h"
|
||||
#include "BLI_path_util.h"
|
||||
|
@ -63,6 +66,10 @@ static CLG_LogRef LOG = {"bke.volume"};
|
|||
|
||||
#define VOLUME_FRAME_NONE INT_MAX
|
||||
|
||||
using blender::float3;
|
||||
using blender::float4x4;
|
||||
using blender::IndexRange;
|
||||
|
||||
#ifdef WITH_OPENVDB
|
||||
# include <atomic>
|
||||
# include <list>
|
||||
|
@ -144,14 +151,14 @@ static struct VolumeFileCache {
|
|||
blender::Map<int, openvdb::GridBase::Ptr> simplified_grids;
|
||||
|
||||
/* Has the grid tree been loaded? */
|
||||
bool is_loaded;
|
||||
mutable bool is_loaded;
|
||||
/* Error message if an error occurred while loading. */
|
||||
std::string error_msg;
|
||||
/* User counting. */
|
||||
int num_metadata_users;
|
||||
int num_tree_users;
|
||||
/* Mutex for on-demand reading of tree. */
|
||||
std::mutex mutex;
|
||||
mutable std::mutex mutex;
|
||||
};
|
||||
|
||||
struct EntryHasher {
|
||||
|
@ -171,10 +178,6 @@ static struct VolumeFileCache {
|
|||
};
|
||||
|
||||
/* Cache */
|
||||
VolumeFileCache()
|
||||
{
|
||||
}
|
||||
|
||||
~VolumeFileCache()
|
||||
{
|
||||
BLI_assert(cache.empty());
|
||||
|
@ -293,7 +296,7 @@ struct VolumeGrid {
|
|||
}
|
||||
}
|
||||
|
||||
void load(const char *volume_name, const char *filepath)
|
||||
void load(const char *volume_name, const char *filepath) const
|
||||
{
|
||||
/* If already loaded or not file-backed, nothing to do. */
|
||||
if (is_loaded || entry == nullptr) {
|
||||
|
@ -335,7 +338,7 @@ struct VolumeGrid {
|
|||
is_loaded = true;
|
||||
}
|
||||
|
||||
void unload(const char *volume_name)
|
||||
void unload(const char *volume_name) const
|
||||
{
|
||||
/* Not loaded or not file-backed, nothing to do. */
|
||||
if (!is_loaded || entry == nullptr) {
|
||||
|
@ -436,10 +439,14 @@ struct VolumeGrid {
|
|||
int simplify_level = 0;
|
||||
/* OpenVDB grid if it's not shared through the file cache. */
|
||||
openvdb::GridBase::Ptr local_grid;
|
||||
/* Indicates if the tree has been loaded for this grid. Note that vdb.tree()
|
||||
/**
|
||||
* Indicates if the tree has been loaded for this grid. Note that vdb.tree()
|
||||
* may actually be loaded by another user while this is false. But only after
|
||||
* calling load() and is_loaded changes to true is it safe to access. */
|
||||
bool is_loaded;
|
||||
* calling load() and is_loaded changes to true is it safe to access.
|
||||
*
|
||||
* Const write access to this must be protected by `entry->mutex`.
|
||||
*/
|
||||
mutable bool is_loaded;
|
||||
};
|
||||
|
||||
/* Volume Grid Vector
|
||||
|
@ -472,14 +479,15 @@ struct VolumeGridVector : public std::list<VolumeGrid> {
|
|||
metadata.reset();
|
||||
}
|
||||
|
||||
/* Mutex for file loading of grids list. Const write access to the fields after this must be
|
||||
* protected by locking with this mutex. */
|
||||
mutable std::mutex mutex;
|
||||
/* Absolute file path that grids have been loaded from. */
|
||||
char filepath[FILE_MAX];
|
||||
/* File loading error message. */
|
||||
std::string error_msg;
|
||||
/* File Metadata. */
|
||||
openvdb::MetaMap::Ptr metadata;
|
||||
/* Mutex for file loading of grids list. */
|
||||
std::mutex mutex;
|
||||
};
|
||||
#endif
|
||||
|
||||
|
@ -766,10 +774,10 @@ bool BKE_volume_is_loaded(const Volume *volume)
|
|||
#endif
|
||||
}
|
||||
|
||||
bool BKE_volume_load(Volume *volume, Main *bmain)
|
||||
bool BKE_volume_load(const Volume *volume, const Main *bmain)
|
||||
{
|
||||
#ifdef WITH_OPENVDB
|
||||
VolumeGridVector &grids = *volume->runtime.grids;
|
||||
const VolumeGridVector &const_grids = *volume->runtime.grids;
|
||||
|
||||
if (volume->runtime.frame == VOLUME_FRAME_NONE) {
|
||||
/* Skip loading this frame, outside of sequence range. */
|
||||
|
@ -777,15 +785,19 @@ bool BKE_volume_load(Volume *volume, Main *bmain)
|
|||
}
|
||||
|
||||
if (BKE_volume_is_loaded(volume)) {
|
||||
return grids.error_msg.empty();
|
||||
return const_grids.error_msg.empty();
|
||||
}
|
||||
|
||||
/* Double-checked lock. */
|
||||
std::lock_guard<std::mutex> lock(grids.mutex);
|
||||
std::lock_guard<std::mutex> lock(const_grids.mutex);
|
||||
if (BKE_volume_is_loaded(volume)) {
|
||||
return grids.error_msg.empty();
|
||||
return const_grids.error_msg.empty();
|
||||
}
|
||||
|
||||
/* Guarded by the lock, we can continue to access the grid vector,
|
||||
* adding error messages or a new grid, etc. */
|
||||
VolumeGridVector &grids = const_cast<VolumeGridVector &>(const_grids);
|
||||
|
||||
/* Get absolute file path at current frame. */
|
||||
const char *volume_name = volume->id.name + 2;
|
||||
char filepath[FILE_MAX];
|
||||
|
@ -850,7 +862,10 @@ void BKE_volume_unload(Volume *volume)
|
|||
|
||||
/* File Save */
|
||||
|
||||
bool BKE_volume_save(Volume *volume, Main *bmain, ReportList *reports, const char *filepath)
|
||||
bool BKE_volume_save(const Volume *volume,
|
||||
const Main *bmain,
|
||||
ReportList *reports,
|
||||
const char *filepath)
|
||||
{
|
||||
#ifdef WITH_OPENVDB
|
||||
if (!BKE_volume_load(volume, bmain)) {
|
||||
|
@ -882,6 +897,32 @@ bool BKE_volume_save(Volume *volume, Main *bmain, ReportList *reports, const cha
|
|||
#endif
|
||||
}
|
||||
|
||||
bool BKE_volume_min_max(const Volume *volume, float3 &r_min, float3 &r_max)
|
||||
{
|
||||
bool have_minmax = false;
|
||||
#ifdef WITH_OPENVDB
|
||||
/* TODO: if we know the volume is going to be displayed, it may be good to
|
||||
* load it as part of dependency graph evaluation for better threading. We
|
||||
* could also share the bounding box computation in the global volume cache. */
|
||||
if (BKE_volume_load(const_cast<Volume *>(volume), G.main)) {
|
||||
for (const int i : IndexRange(BKE_volume_num_grids(volume))) {
|
||||
const VolumeGrid *volume_grid = BKE_volume_grid_get_for_read(volume, i);
|
||||
openvdb::GridBase::ConstPtr grid = BKE_volume_grid_openvdb_for_read(volume, volume_grid);
|
||||
float3 grid_min;
|
||||
float3 grid_max;
|
||||
if (BKE_volume_grid_bounds(grid, grid_min, grid_max)) {
|
||||
DO_MIN(grid_min, r_min);
|
||||
DO_MAX(grid_max, r_max);
|
||||
have_minmax = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
#else
|
||||
UNUSED_VARS(volume, r_min, r_max);
|
||||
#endif
|
||||
return have_minmax;
|
||||
}
|
||||
|
||||
BoundBox *BKE_volume_boundbox_get(Object *ob)
|
||||
{
|
||||
BLI_assert(ob->type == OB_VOLUME);
|
||||
|
@ -891,41 +932,20 @@ BoundBox *BKE_volume_boundbox_get(Object *ob)
|
|||
}
|
||||
|
||||
if (ob->runtime.bb == nullptr) {
|
||||
Volume *volume = (Volume *)ob->data;
|
||||
|
||||
ob->runtime.bb = (BoundBox *)MEM_callocN(sizeof(BoundBox), "volume boundbox");
|
||||
|
||||
float min[3], max[3];
|
||||
bool have_minmax = false;
|
||||
INIT_MINMAX(min, max);
|
||||
|
||||
/* TODO: if we know the volume is going to be displayed, it may be good to
|
||||
* load it as part of dependency graph evaluation for better threading. We
|
||||
* could also share the bounding box computation in the global volume cache. */
|
||||
if (BKE_volume_load(volume, G.main)) {
|
||||
const int num_grids = BKE_volume_num_grids(volume);
|
||||
|
||||
for (int i = 0; i < num_grids; i++) {
|
||||
VolumeGrid *grid = BKE_volume_grid_get(volume, i);
|
||||
float grid_min[3], grid_max[3];
|
||||
|
||||
BKE_volume_grid_load(volume, grid);
|
||||
if (BKE_volume_grid_bounds(grid, grid_min, grid_max)) {
|
||||
DO_MIN(grid_min, min);
|
||||
DO_MAX(grid_max, max);
|
||||
have_minmax = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!have_minmax) {
|
||||
min[0] = min[1] = min[2] = -1.0f;
|
||||
max[0] = max[1] = max[2] = 1.0f;
|
||||
}
|
||||
|
||||
BKE_boundbox_init_from_minmax(ob->runtime.bb, min, max);
|
||||
ob->runtime.bb = (BoundBox *)MEM_callocN(sizeof(BoundBox), __func__);
|
||||
}
|
||||
|
||||
const Volume *volume = (Volume *)ob->data;
|
||||
|
||||
float3 min, max;
|
||||
INIT_MINMAX(min, max);
|
||||
if (!BKE_volume_min_max(volume, min, max)) {
|
||||
min = float3(-1);
|
||||
max = float3(1);
|
||||
}
|
||||
|
||||
BKE_boundbox_init_from_minmax(ob->runtime.bb, min, max);
|
||||
|
||||
return ob->runtime.bb;
|
||||
}
|
||||
|
||||
|
@ -957,7 +977,7 @@ bool BKE_volume_is_points_only(const Volume *volume)
|
|||
}
|
||||
|
||||
for (int i = 0; i < num_grids; i++) {
|
||||
VolumeGrid *grid = BKE_volume_grid_get(volume, i);
|
||||
const VolumeGrid *grid = BKE_volume_grid_get_for_read(volume, i);
|
||||
if (BKE_volume_grid_type(grid) != VOLUME_GRID_POINTS) {
|
||||
return false;
|
||||
}
|
||||
|
@ -1144,7 +1164,23 @@ const char *BKE_volume_grids_frame_filepath(const Volume *volume)
|
|||
#endif
|
||||
}
|
||||
|
||||
VolumeGrid *BKE_volume_grid_get(const Volume *volume, int grid_index)
|
||||
const VolumeGrid *BKE_volume_grid_get_for_read(const Volume *volume, int grid_index)
|
||||
{
|
||||
#ifdef WITH_OPENVDB
|
||||
const VolumeGridVector &grids = *volume->runtime.grids;
|
||||
for (const VolumeGrid &grid : grids) {
|
||||
if (grid_index-- == 0) {
|
||||
return &grid;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
#else
|
||||
UNUSED_VARS(volume, grid_index);
|
||||
return nullptr;
|
||||
#endif
|
||||
}
|
||||
|
||||
VolumeGrid *BKE_volume_grid_get_for_write(Volume *volume, int grid_index)
|
||||
{
|
||||
#ifdef WITH_OPENVDB
|
||||
VolumeGridVector &grids = *volume->runtime.grids;
|
||||
|
@ -1160,7 +1196,7 @@ VolumeGrid *BKE_volume_grid_get(const Volume *volume, int grid_index)
|
|||
#endif
|
||||
}
|
||||
|
||||
VolumeGrid *BKE_volume_grid_active_get(const Volume *volume)
|
||||
const VolumeGrid *BKE_volume_grid_active_get_for_read(const Volume *volume)
|
||||
{
|
||||
const int num_grids = BKE_volume_num_grids(volume);
|
||||
if (num_grids == 0) {
|
||||
|
@ -1168,15 +1204,15 @@ VolumeGrid *BKE_volume_grid_active_get(const Volume *volume)
|
|||
}
|
||||
|
||||
const int index = clamp_i(volume->active_grid, 0, num_grids - 1);
|
||||
return BKE_volume_grid_get(volume, index);
|
||||
return BKE_volume_grid_get_for_read(volume, index);
|
||||
}
|
||||
|
||||
/* Tries to find a grid with the given name. Make sure that that the volume has been loaded. */
|
||||
VolumeGrid *BKE_volume_grid_find(const Volume *volume, const char *name)
|
||||
const VolumeGrid *BKE_volume_grid_find_for_read(const Volume *volume, const char *name)
|
||||
{
|
||||
int num_grids = BKE_volume_num_grids(volume);
|
||||
for (int i = 0; i < num_grids; i++) {
|
||||
VolumeGrid *grid = BKE_volume_grid_get(volume, i);
|
||||
const VolumeGrid *grid = BKE_volume_grid_get_for_read(volume, i);
|
||||
if (STREQ(BKE_volume_grid_name(grid), name)) {
|
||||
return grid;
|
||||
}
|
||||
|
@ -1187,7 +1223,7 @@ VolumeGrid *BKE_volume_grid_find(const Volume *volume, const char *name)
|
|||
|
||||
/* Grid Loading */
|
||||
|
||||
bool BKE_volume_grid_load(const Volume *volume, VolumeGrid *grid)
|
||||
bool BKE_volume_grid_load(const Volume *volume, const VolumeGrid *grid)
|
||||
{
|
||||
#ifdef WITH_OPENVDB
|
||||
VolumeGridVector &grids = *volume->runtime.grids;
|
||||
|
@ -1205,7 +1241,7 @@ bool BKE_volume_grid_load(const Volume *volume, VolumeGrid *grid)
|
|||
#endif
|
||||
}
|
||||
|
||||
void BKE_volume_grid_unload(const Volume *volume, VolumeGrid *grid)
|
||||
void BKE_volume_grid_unload(const Volume *volume, const VolumeGrid *grid)
|
||||
{
|
||||
#ifdef WITH_OPENVDB
|
||||
const char *volume_name = volume->id.name + 2;
|
||||
|
@ -1335,34 +1371,6 @@ void BKE_volume_grid_transform_matrix(const VolumeGrid *volume_grid, float mat[4
|
|||
|
||||
/* Grid Tree and Voxels */
|
||||
|
||||
bool BKE_volume_grid_bounds(const VolumeGrid *volume_grid, float min[3], float max[3])
|
||||
{
|
||||
#ifdef WITH_OPENVDB
|
||||
/* TODO: we can get this from grid metadata in some cases? */
|
||||
const openvdb::GridBase::Ptr grid = volume_grid->grid();
|
||||
BLI_assert(BKE_volume_grid_is_loaded(volume_grid));
|
||||
|
||||
openvdb::CoordBBox coordbbox;
|
||||
if (!grid->baseTree().evalLeafBoundingBox(coordbbox)) {
|
||||
INIT_MINMAX(min, max);
|
||||
return false;
|
||||
}
|
||||
|
||||
openvdb::BBoxd bbox = grid->transform().indexToWorld(coordbbox);
|
||||
min[0] = (float)bbox.min().x();
|
||||
min[1] = (float)bbox.min().y();
|
||||
min[2] = (float)bbox.min().z();
|
||||
max[0] = (float)bbox.max().x();
|
||||
max[1] = (float)bbox.max().y();
|
||||
max[2] = (float)bbox.max().z();
|
||||
return true;
|
||||
#else
|
||||
UNUSED_VARS(volume_grid);
|
||||
INIT_MINMAX(min, max);
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Volume Editing */
|
||||
|
||||
Volume *BKE_volume_new_for_eval(const Volume *volume_src)
|
||||
|
@ -1410,7 +1418,7 @@ VolumeGrid *BKE_volume_grid_add(Volume *volume, const char *name, VolumeGridType
|
|||
{
|
||||
#ifdef WITH_OPENVDB
|
||||
VolumeGridVector &grids = *volume->runtime.grids;
|
||||
BLI_assert(BKE_volume_grid_find(volume, name) == nullptr);
|
||||
BLI_assert(BKE_volume_grid_find_for_read(volume, name) == nullptr);
|
||||
BLI_assert(type != VOLUME_GRID_UNKNOWN);
|
||||
|
||||
openvdb::GridBase::Ptr vdb_grid = BKE_volume_grid_type_operation(type, CreateGridOp{});
|
||||
|
@ -1472,13 +1480,45 @@ float BKE_volume_simplify_factor(const Depsgraph *depsgraph)
|
|||
/* OpenVDB Grid Access */
|
||||
|
||||
#ifdef WITH_OPENVDB
|
||||
|
||||
bool BKE_volume_grid_bounds(openvdb::GridBase::ConstPtr grid, float3 &r_min, float3 &r_max)
|
||||
{
|
||||
/* TODO: we can get this from grid metadata in some cases? */
|
||||
openvdb::CoordBBox coordbbox;
|
||||
if (!grid->baseTree().evalLeafBoundingBox(coordbbox)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
openvdb::BBoxd bbox = grid->transform().indexToWorld(coordbbox);
|
||||
|
||||
r_min = float3((float)bbox.min().x(), (float)bbox.min().y(), (float)bbox.min().z());
|
||||
r_max = float3((float)bbox.max().x(), (float)bbox.max().y(), (float)bbox.max().z());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a new grid pointer with only the metadata and transform changed.
|
||||
* This is useful for instances, where there is a separate transform on top of the original
|
||||
* grid transform that must be applied for some operations that only take a grid argument.
|
||||
*/
|
||||
openvdb::GridBase::ConstPtr BKE_volume_grid_shallow_transform(openvdb::GridBase::ConstPtr grid,
|
||||
const blender::float4x4 &transform)
|
||||
{
|
||||
openvdb::math::Transform::Ptr grid_transform = grid->transform().copy();
|
||||
grid_transform->postMult(openvdb::Mat4d(((float *)transform.values)));
|
||||
|
||||
/* Create a transformed grid. The underlying tree is shared. */
|
||||
return grid->copyGridReplacingTransform(grid_transform);
|
||||
}
|
||||
|
||||
openvdb::GridBase::ConstPtr BKE_volume_grid_openvdb_for_metadata(const VolumeGrid *grid)
|
||||
{
|
||||
return grid->grid();
|
||||
}
|
||||
|
||||
openvdb::GridBase::ConstPtr BKE_volume_grid_openvdb_for_read(const Volume *volume,
|
||||
VolumeGrid *grid)
|
||||
const VolumeGrid *grid)
|
||||
{
|
||||
BKE_volume_grid_load(volume, grid);
|
||||
return grid->grid();
|
||||
|
|
|
@ -104,7 +104,7 @@ static void create_texture_to_object_matrix(const openvdb::Mat4d &grid_transform
|
|||
#endif
|
||||
|
||||
bool BKE_volume_grid_dense_floats(const Volume *volume,
|
||||
VolumeGrid *volume_grid,
|
||||
const VolumeGrid *volume_grid,
|
||||
DenseFloatVolumeGrid *r_dense_grid)
|
||||
{
|
||||
#ifdef WITH_OPENVDB
|
||||
|
@ -334,7 +334,7 @@ static void boxes_to_cube_mesh(blender::Span<openvdb::CoordBBox> boxes,
|
|||
#endif
|
||||
|
||||
void BKE_volume_grid_wireframe(const Volume *volume,
|
||||
VolumeGrid *volume_grid,
|
||||
const VolumeGrid *volume_grid,
|
||||
BKE_volume_wireframe_cb cb,
|
||||
void *cb_userdata)
|
||||
{
|
||||
|
@ -411,7 +411,7 @@ static void grow_triangles(blender::MutableSpan<blender::float3> verts,
|
|||
#endif /* WITH_OPENVDB */
|
||||
|
||||
void BKE_volume_grid_selection_surface(const Volume *volume,
|
||||
VolumeGrid *volume_grid,
|
||||
const VolumeGrid *volume_grid,
|
||||
BKE_volume_selection_surface_cb cb,
|
||||
void *cb_userdata)
|
||||
{
|
||||
|
|
|
@ -34,13 +34,19 @@ typedef struct BLI_Iterator {
|
|||
typedef void (*IteratorCb)(BLI_Iterator *iter);
|
||||
typedef void (*IteratorBeginCb)(BLI_Iterator *iter, void *data_in);
|
||||
|
||||
#define BLI_ITERATOR_INIT(iter) \
|
||||
{ \
|
||||
(iter)->skip = false; \
|
||||
(iter)->valid = true; \
|
||||
} \
|
||||
((void)0)
|
||||
|
||||
#define ITER_BEGIN(callback_begin, callback_next, callback_end, _data_in, _type, _instance) \
|
||||
{ \
|
||||
_type _instance; \
|
||||
IteratorCb callback_end_func = callback_end; \
|
||||
BLI_Iterator iter_macro; \
|
||||
iter_macro.skip = false; \
|
||||
iter_macro.valid = true; \
|
||||
BLI_ITERATOR_INIT(&iter_macro); \
|
||||
for (callback_begin(&iter_macro, (_data_in)); iter_macro.valid; callback_next(&iter_macro)) { \
|
||||
if (iter_macro.skip) { \
|
||||
iter_macro.skip = false; \
|
||||
|
|
|
@ -72,38 +72,46 @@ class ResourceScope : NonCopyable, NonMovable {
|
|||
* Pass ownership of the resource to the ResourceScope. It will be destructed and freed when
|
||||
* the collector is destructed.
|
||||
*/
|
||||
template<typename T> void add(std::unique_ptr<T> resource, const char *name)
|
||||
template<typename T> T *add(std::unique_ptr<T> resource, const char *name)
|
||||
{
|
||||
BLI_assert(resource.get() != nullptr);
|
||||
T *ptr = resource.release();
|
||||
if (ptr == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
this->add(
|
||||
resource.release(),
|
||||
ptr,
|
||||
[](void *data) {
|
||||
T *typed_data = reinterpret_cast<T *>(data);
|
||||
delete typed_data;
|
||||
},
|
||||
name);
|
||||
return ptr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Pass ownership of the resource to the ResourceScope. It will be destructed when the
|
||||
* collector is destructed.
|
||||
*/
|
||||
template<typename T> void add(destruct_ptr<T> resource, const char *name)
|
||||
template<typename T> T *add(destruct_ptr<T> resource, const char *name)
|
||||
{
|
||||
T *ptr = resource.release();
|
||||
if (ptr == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
/* There is no need to keep track of such types. */
|
||||
if (std::is_trivially_destructible_v<T>) {
|
||||
resource.release();
|
||||
return;
|
||||
return ptr;
|
||||
}
|
||||
|
||||
BLI_assert(resource.get() != nullptr);
|
||||
this->add(
|
||||
resource.release(),
|
||||
ptr,
|
||||
[](void *data) {
|
||||
T *typed_data = reinterpret_cast<T *>(data);
|
||||
typed_data->~T();
|
||||
},
|
||||
name);
|
||||
return ptr;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -78,7 +78,7 @@ float BLI_dial_angle(Dial *dial, const float current_position[2])
|
|||
cosval = dot_v2v2(current_direction, dial->initial_direction);
|
||||
sinval = cross_v2v2(current_direction, dial->initial_direction);
|
||||
|
||||
/* clamp to avoid nans in acos */
|
||||
/* clamp to avoid nans in #acos */
|
||||
angle = atan2f(sinval, cosval);
|
||||
|
||||
/* change of sign, we passed the 180 degree threshold. This means we need to add a turn.
|
||||
|
|
|
@ -334,9 +334,6 @@ template<typename T> class CDT_state {
|
|||
T epsilon;
|
||||
|
||||
explicit CDT_state(int num_input_verts, int num_input_edges, int num_input_faces, T epsilon);
|
||||
~CDT_state()
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T> CDTArrangement<T>::~CDTArrangement()
|
||||
|
|
|
@ -527,9 +527,7 @@ IMeshArena::IMeshArena()
|
|||
pimpl_ = std::make_unique<IMeshArenaImpl>();
|
||||
}
|
||||
|
||||
IMeshArena::~IMeshArena()
|
||||
{
|
||||
}
|
||||
IMeshArena::~IMeshArena() = default;
|
||||
|
||||
void IMeshArena::reserve(int vert_num_hint, int face_num_hint)
|
||||
{
|
||||
|
@ -753,27 +751,6 @@ struct BoundingBox {
|
|||
BoundingBox(const float3 &min, const float3 &max) : min(min), max(max)
|
||||
{
|
||||
}
|
||||
BoundingBox(const BoundingBox &other) : min(other.min), max(other.max)
|
||||
{
|
||||
}
|
||||
BoundingBox(BoundingBox &&other) noexcept : min(std::move(other.min)), max(std::move(other.max))
|
||||
{
|
||||
}
|
||||
~BoundingBox() = default;
|
||||
BoundingBox operator=(const BoundingBox &other)
|
||||
{
|
||||
if (this != &other) {
|
||||
min = other.min;
|
||||
max = other.max;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
BoundingBox operator=(BoundingBox &&other) noexcept
|
||||
{
|
||||
min = std::move(other.min);
|
||||
max = std::move(other.max);
|
||||
return *this;
|
||||
}
|
||||
|
||||
void combine(const float3 &p)
|
||||
{
|
||||
|
@ -936,28 +913,6 @@ class CoplanarCluster {
|
|||
{
|
||||
this->add_tri(t, bb);
|
||||
}
|
||||
CoplanarCluster(const CoplanarCluster &other) : tris_(other.tris_), bb_(other.bb_)
|
||||
{
|
||||
}
|
||||
CoplanarCluster(CoplanarCluster &&other) noexcept
|
||||
: tris_(std::move(other.tris_)), bb_(std::move(other.bb_))
|
||||
{
|
||||
}
|
||||
~CoplanarCluster() = default;
|
||||
CoplanarCluster &operator=(const CoplanarCluster &other)
|
||||
{
|
||||
if (this != &other) {
|
||||
tris_ = other.tris_;
|
||||
bb_ = other.bb_;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
CoplanarCluster &operator=(CoplanarCluster &&other) noexcept
|
||||
{
|
||||
tris_ = std::move(other.tris_);
|
||||
bb_ = std::move(other.bb_);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/* Assume that caller knows this will not be a duplicate. */
|
||||
void add_tri(int t, const BoundingBox &bb)
|
||||
|
@ -1073,38 +1028,6 @@ struct ITT_value {
|
|||
ITT_value(ITT_value_kind k, const mpq3 &p1, const mpq3 &p2) : p1(p1), p2(p2), kind(k)
|
||||
{
|
||||
}
|
||||
ITT_value(const ITT_value &other)
|
||||
: p1(other.p1), p2(other.p2), t_source(other.t_source), kind(other.kind)
|
||||
{
|
||||
}
|
||||
ITT_value(ITT_value &&other) noexcept
|
||||
: p1(std::move(other.p1)),
|
||||
p2(std::move(other.p2)),
|
||||
t_source(other.t_source),
|
||||
kind(other.kind)
|
||||
{
|
||||
}
|
||||
~ITT_value()
|
||||
{
|
||||
}
|
||||
ITT_value &operator=(const ITT_value &other)
|
||||
{
|
||||
if (this != &other) {
|
||||
kind = other.kind;
|
||||
p1 = other.p1;
|
||||
p2 = other.p2;
|
||||
t_source = other.t_source;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
ITT_value &operator=(ITT_value &&other) noexcept
|
||||
{
|
||||
kind = other.kind;
|
||||
p1 = std::move(other.p1);
|
||||
p2 = std::move(other.p2);
|
||||
t_source = other.t_source;
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
static std::ostream &operator<<(std::ostream &os, const ITT_value &itt);
|
||||
|
|
|
@ -148,10 +148,6 @@ class TBBTaskGroup : public tbb::task_group {
|
|||
}
|
||||
# endif
|
||||
}
|
||||
|
||||
~TBBTaskGroup()
|
||||
{
|
||||
}
|
||||
};
|
||||
#endif
|
||||
|
||||
|
|
|
@ -2034,6 +2034,26 @@ void blo_do_versions_290(FileData *fd, Library *UNUSED(lib), Main *bmain)
|
|||
}
|
||||
FOREACH_NODETREE_END;
|
||||
}
|
||||
|
||||
/* The CU_2D flag has been removed. */
|
||||
LISTBASE_FOREACH (Curve *, cu, &bmain->curves) {
|
||||
#define CU_2D (1 << 3)
|
||||
ListBase *nurbs = BKE_curve_nurbs_get(cu);
|
||||
bool is_2d = true;
|
||||
|
||||
LISTBASE_FOREACH (Nurb *, nu, nurbs) {
|
||||
if (nu->flag & CU_2D) {
|
||||
nu->flag &= ~CU_2D;
|
||||
}
|
||||
else {
|
||||
is_2d = false;
|
||||
}
|
||||
}
|
||||
#undef CU_2D
|
||||
if (!is_2d && CU_IS_2D(cu)) {
|
||||
cu->flag |= CU_3D;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -2081,25 +2101,5 @@ void blo_do_versions_290(FileData *fd, Library *UNUSED(lib), Main *bmain)
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* The CU_2D flag has been removed. */
|
||||
LISTBASE_FOREACH (Curve *, cu, &bmain->curves) {
|
||||
#define CU_2D (1 << 3)
|
||||
ListBase *nurbs = BKE_curve_nurbs_get(cu);
|
||||
bool is_2d = true;
|
||||
|
||||
LISTBASE_FOREACH (Nurb *, nu, nurbs) {
|
||||
if (nu->flag & CU_2D) {
|
||||
nu->flag &= ~CU_2D;
|
||||
}
|
||||
else {
|
||||
is_2d = false;
|
||||
}
|
||||
}
|
||||
#undef CU_2D
|
||||
if (!is_2d && CU_IS_2D(cu)) {
|
||||
cu->flag |= CU_3D;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -50,10 +50,6 @@
|
|||
|
||||
#include "CLG_log.h"
|
||||
|
||||
BlendfileLoadingBaseTest::~BlendfileLoadingBaseTest()
|
||||
{
|
||||
}
|
||||
|
||||
void BlendfileLoadingBaseTest::SetUpTestCase()
|
||||
{
|
||||
testing::Test::SetUpTestCase();
|
||||
|
|
|
@ -30,8 +30,6 @@ class BlendfileLoadingBaseTest : public testing::Test {
|
|||
struct Depsgraph *depsgraph = nullptr;
|
||||
|
||||
public:
|
||||
virtual ~BlendfileLoadingBaseTest();
|
||||
|
||||
/* Sets up Blender just enough to not crash on loading
|
||||
* a blendfile and constructing a depsgraph. */
|
||||
static void SetUpTestCase();
|
||||
|
|
|
@ -38,7 +38,8 @@ namespace blender::meshintersect {
|
|||
|
||||
#ifdef WITH_GMP
|
||||
|
||||
/** Make a #blender::meshintersect::Mesh from #BMesh bm.
|
||||
/**
|
||||
* Make a #blender::meshintersect::Mesh from #BMesh bm.
|
||||
* We are given a triangulation of it from the caller via #looptris,
|
||||
* which are looptris_tot triples of loops that together tessellate
|
||||
* the faces of bm.
|
||||
|
|
|
@ -608,4 +608,8 @@ endif()
|
|||
|
||||
blender_add_lib(bf_compositor "${SRC}" "${INC}" "${INC_SYS}" "${LIB}")
|
||||
|
||||
if(CMAKE_COMPILER_IS_GNUCC OR CMAKE_C_COMPILER_ID MATCHES "Clang")
|
||||
target_compile_options(bf_compositor PRIVATE "-Wsuggest-override")
|
||||
endif()
|
||||
|
||||
add_dependencies(bf_compositor smaa_areatex_header)
|
||||
|
|
|
@ -451,6 +451,8 @@ void DebugInfo::graphviz(const ExecutionSystem *system)
|
|||
BLI_join_dirfile(filename, sizeof(filename), BKE_tempdir_session(), basename);
|
||||
m_file_index++;
|
||||
|
||||
std::cout << "Writing compositor debug to: " << filename << "\n";
|
||||
|
||||
FILE *fp = BLI_fopen(filename, "wb");
|
||||
fputs(str, fp);
|
||||
fclose(fp);
|
||||
|
|
|
@ -39,10 +39,6 @@ namespace blender::compositor {
|
|||
**** NodeGraph ****
|
||||
*******************/
|
||||
|
||||
NodeGraph::NodeGraph()
|
||||
{
|
||||
}
|
||||
|
||||
NodeGraph::~NodeGraph()
|
||||
{
|
||||
while (m_nodes.size()) {
|
||||
|
|
|
@ -56,7 +56,6 @@ class NodeGraph {
|
|||
Vector<Link> m_links;
|
||||
|
||||
public:
|
||||
NodeGraph();
|
||||
~NodeGraph();
|
||||
|
||||
const Vector<Node *> &nodes() const
|
||||
|
|
|
@ -259,17 +259,18 @@ std::ostream &operator<<(std::ostream &os, const NodeOperation &node_operation)
|
|||
{
|
||||
NodeOperationFlags flags = node_operation.get_flags();
|
||||
os << "NodeOperation(";
|
||||
os << "id=" << node_operation.get_id();
|
||||
if (!node_operation.get_name().empty()) {
|
||||
os << "name=" << node_operation.get_name() << ",";
|
||||
os << ",name=" << node_operation.get_name();
|
||||
}
|
||||
os << "flags={" << flags << "},";
|
||||
os << ",flags={" << flags << "}";
|
||||
if (flags.is_read_buffer_operation) {
|
||||
const ReadBufferOperation *read_operation = (const ReadBufferOperation *)&node_operation;
|
||||
const MemoryProxy *proxy = read_operation->getMemoryProxy();
|
||||
if (proxy) {
|
||||
const WriteBufferOperation *write_operation = proxy->getWriteBufferOperation();
|
||||
if (write_operation) {
|
||||
os << "write=" << (NodeOperation &)*write_operation << ",";
|
||||
os << ",write=" << (NodeOperation &)*write_operation;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -251,6 +251,7 @@ struct NodeOperationFlags {
|
|||
*/
|
||||
class NodeOperation {
|
||||
private:
|
||||
int m_id;
|
||||
std::string m_name;
|
||||
Vector<NodeOperationInput> m_inputs;
|
||||
Vector<NodeOperationOutput> m_outputs;
|
||||
|
@ -307,6 +308,16 @@ class NodeOperation {
|
|||
return m_name;
|
||||
}
|
||||
|
||||
void set_id(const int id)
|
||||
{
|
||||
m_id = id;
|
||||
}
|
||||
|
||||
const int get_id() const
|
||||
{
|
||||
return m_id;
|
||||
}
|
||||
|
||||
const NodeOperationFlags get_flags() const
|
||||
{
|
||||
return flags;
|
||||
|
|
|
@ -46,10 +46,6 @@ NodeOperationBuilder::NodeOperationBuilder(const CompositorContext *context, bNo
|
|||
m_graph.from_bNodeTree(*context, b_nodetree);
|
||||
}
|
||||
|
||||
NodeOperationBuilder::~NodeOperationBuilder()
|
||||
{
|
||||
}
|
||||
|
||||
void NodeOperationBuilder::convertToOperations(ExecutionSystem *system)
|
||||
{
|
||||
/* interface handle for nodes */
|
||||
|
@ -124,6 +120,7 @@ void NodeOperationBuilder::convertToOperations(ExecutionSystem *system)
|
|||
|
||||
void NodeOperationBuilder::addOperation(NodeOperation *operation)
|
||||
{
|
||||
operation->set_id(m_operations.size());
|
||||
m_operations.append(operation);
|
||||
if (m_current_node) {
|
||||
operation->set_name(m_current_node->getbNode()->name);
|
||||
|
@ -691,4 +688,41 @@ void NodeOperationBuilder::group_operations()
|
|||
}
|
||||
}
|
||||
|
||||
/** Create a graphviz representation of the NodeOperationBuilder. */
|
||||
std::ostream &operator<<(std::ostream &os, const NodeOperationBuilder &builder)
|
||||
{
|
||||
os << "# Builder start\n";
|
||||
os << "digraph G {\n";
|
||||
os << " rankdir=LR;\n";
|
||||
os << " node [shape=box];\n";
|
||||
for (const NodeOperation *operation : builder.get_operations()) {
|
||||
os << " op" << operation->get_id() << " [label=\"" << *operation << "\"];\n";
|
||||
}
|
||||
|
||||
os << "\n";
|
||||
for (const NodeOperationBuilder::Link &link : builder.get_links()) {
|
||||
os << " op" << link.from()->getOperation().get_id() << " -> op"
|
||||
<< link.to()->getOperation().get_id() << ";\n";
|
||||
}
|
||||
for (const NodeOperation *operation : builder.get_operations()) {
|
||||
if (operation->get_flags().is_read_buffer_operation) {
|
||||
const ReadBufferOperation &read_operation = static_cast<const ReadBufferOperation &>(
|
||||
*operation);
|
||||
const WriteBufferOperation &write_operation =
|
||||
*read_operation.getMemoryProxy()->getWriteBufferOperation();
|
||||
os << " op" << write_operation.get_id() << " -> op" << read_operation.get_id() << ";\n";
|
||||
}
|
||||
}
|
||||
|
||||
os << "}\n";
|
||||
os << "# Builder end\n";
|
||||
return os;
|
||||
}
|
||||
|
||||
std::ostream &operator<<(std::ostream &os, const NodeOperationBuilder::Link &link)
|
||||
{
|
||||
os << link.from()->getOperation().get_id() << " -> " << link.to()->getOperation().get_id();
|
||||
return os;
|
||||
}
|
||||
|
||||
} // namespace blender::compositor
|
||||
|
|
|
@ -87,7 +87,6 @@ class NodeOperationBuilder {
|
|||
|
||||
public:
|
||||
NodeOperationBuilder(const CompositorContext *context, bNodeTree *b_nodetree);
|
||||
~NodeOperationBuilder();
|
||||
|
||||
const CompositorContext &context() const
|
||||
{
|
||||
|
@ -119,6 +118,16 @@ class NodeOperationBuilder {
|
|||
return m_active_viewer;
|
||||
}
|
||||
|
||||
const Vector<NodeOperation *> &get_operations() const
|
||||
{
|
||||
return m_operations;
|
||||
}
|
||||
|
||||
const Vector<Link> &get_links() const
|
||||
{
|
||||
return m_links;
|
||||
}
|
||||
|
||||
protected:
|
||||
/** Add datatype conversion where needed */
|
||||
void add_datatype_conversions();
|
||||
|
@ -160,4 +169,7 @@ class NodeOperationBuilder {
|
|||
#endif
|
||||
};
|
||||
|
||||
std::ostream &operator<<(std::ostream &os, const NodeOperationBuilder &builder);
|
||||
std::ostream &operator<<(std::ostream &os, const NodeOperationBuilder::Link &link);
|
||||
|
||||
} // namespace blender::compositor
|
||||
|
|
|
@ -55,6 +55,6 @@ struct WorkPackage {
|
|||
#endif
|
||||
};
|
||||
|
||||
std::ostream &operator<<(std::ostream &os, const WorkPackage &WorkPackage);
|
||||
std::ostream &operator<<(std::ostream &os, const WorkPackage &work_package);
|
||||
|
||||
} // namespace blender::compositor
|
||||
|
|
|
@ -20,11 +20,6 @@
|
|||
|
||||
namespace blender::compositor {
|
||||
|
||||
AlphaOverKeyOperation::AlphaOverKeyOperation()
|
||||
{
|
||||
/* pass */
|
||||
}
|
||||
|
||||
void AlphaOverKeyOperation::executePixelSampled(float output[4],
|
||||
float x,
|
||||
float y,
|
||||
|
|
|
@ -28,11 +28,6 @@ namespace blender::compositor {
|
|||
*/
|
||||
class AlphaOverKeyOperation : public MixBaseOperation {
|
||||
public:
|
||||
/**
|
||||
* Default constructor
|
||||
*/
|
||||
AlphaOverKeyOperation();
|
||||
|
||||
/**
|
||||
* The inner loop of this operation.
|
||||
*/
|
||||
|
|
|
@ -20,11 +20,6 @@
|
|||
|
||||
namespace blender::compositor {
|
||||
|
||||
AlphaOverPremultiplyOperation::AlphaOverPremultiplyOperation()
|
||||
{
|
||||
/* pass */
|
||||
}
|
||||
|
||||
void AlphaOverPremultiplyOperation::executePixelSampled(float output[4],
|
||||
float x,
|
||||
float y,
|
||||
|
|
|
@ -28,11 +28,6 @@ namespace blender::compositor {
|
|||
*/
|
||||
class AlphaOverPremultiplyOperation : public MixBaseOperation {
|
||||
public:
|
||||
/**
|
||||
* Default constructor
|
||||
*/
|
||||
AlphaOverPremultiplyOperation();
|
||||
|
||||
/**
|
||||
* The inner loop of this operation.
|
||||
*/
|
||||
|
|
|
@ -24,11 +24,6 @@
|
|||
|
||||
namespace blender::compositor {
|
||||
|
||||
CalculateStandardDeviationOperation::CalculateStandardDeviationOperation()
|
||||
{
|
||||
/* pass */
|
||||
}
|
||||
|
||||
void CalculateStandardDeviationOperation::executePixel(float output[4],
|
||||
int /*x*/,
|
||||
int /*y*/,
|
||||
|
|
|
@ -34,8 +34,6 @@ class CalculateStandardDeviationOperation : public CalculateMeanOperation {
|
|||
float m_standardDeviation;
|
||||
|
||||
public:
|
||||
CalculateStandardDeviationOperation();
|
||||
|
||||
/**
|
||||
* The inner loop of this operation.
|
||||
*/
|
||||
|
|
|
@ -21,11 +21,6 @@
|
|||
|
||||
namespace blender::compositor {
|
||||
|
||||
ConvolutionEdgeFilterOperation::ConvolutionEdgeFilterOperation()
|
||||
{
|
||||
/* pass */
|
||||
}
|
||||
|
||||
void ConvolutionEdgeFilterOperation::executePixel(float output[4], int x, int y, void * /*data*/)
|
||||
{
|
||||
float in1[4], in2[4], res1[4] = {0.0}, res2[4] = {0.0};
|
||||
|
|
|
@ -24,7 +24,6 @@ namespace blender::compositor {
|
|||
|
||||
class ConvolutionEdgeFilterOperation : public ConvolutionFilterOperation {
|
||||
public:
|
||||
ConvolutionEdgeFilterOperation();
|
||||
void executePixel(float output[4], int x, int y, void *data) override;
|
||||
};
|
||||
|
||||
|
|
|
@ -21,11 +21,6 @@
|
|||
|
||||
namespace blender::compositor {
|
||||
|
||||
DistanceYCCMatteOperation::DistanceYCCMatteOperation()
|
||||
{
|
||||
/* pass */
|
||||
}
|
||||
|
||||
float DistanceYCCMatteOperation::calculateDistance(float key[4], float image[4])
|
||||
{
|
||||
/* only measure the second 2 values */
|
||||
|
|
|
@ -30,12 +30,6 @@ namespace blender::compositor {
|
|||
class DistanceYCCMatteOperation : public DistanceRGBMatteOperation {
|
||||
protected:
|
||||
float calculateDistance(float key[4], float image[4]) override;
|
||||
|
||||
public:
|
||||
/**
|
||||
* Default constructor
|
||||
*/
|
||||
DistanceYCCMatteOperation();
|
||||
};
|
||||
|
||||
} // namespace blender::compositor
|
||||
|
|
|
@ -99,11 +99,6 @@ void MixBaseOperation::deinitExecution()
|
|||
|
||||
/* ******** Mix Add Operation ******** */
|
||||
|
||||
MixAddOperation::MixAddOperation()
|
||||
{
|
||||
/* pass */
|
||||
}
|
||||
|
||||
void MixAddOperation::executePixelSampled(float output[4], float x, float y, PixelSampler sampler)
|
||||
{
|
||||
float inputColor1[4];
|
||||
|
@ -128,11 +123,6 @@ void MixAddOperation::executePixelSampled(float output[4], float x, float y, Pix
|
|||
|
||||
/* ******** Mix Blend Operation ******** */
|
||||
|
||||
MixBlendOperation::MixBlendOperation()
|
||||
{
|
||||
/* pass */
|
||||
}
|
||||
|
||||
void MixBlendOperation::executePixelSampled(float output[4],
|
||||
float x,
|
||||
float y,
|
||||
|
@ -162,11 +152,6 @@ void MixBlendOperation::executePixelSampled(float output[4],
|
|||
|
||||
/* ******** Mix Burn Operation ******** */
|
||||
|
||||
MixColorBurnOperation::MixColorBurnOperation()
|
||||
{
|
||||
/* pass */
|
||||
}
|
||||
|
||||
void MixColorBurnOperation::executePixelSampled(float output[4],
|
||||
float x,
|
||||
float y,
|
||||
|
@ -245,11 +230,6 @@ void MixColorBurnOperation::executePixelSampled(float output[4],
|
|||
|
||||
/* ******** Mix Color Operation ******** */
|
||||
|
||||
MixColorOperation::MixColorOperation()
|
||||
{
|
||||
/* pass */
|
||||
}
|
||||
|
||||
void MixColorOperation::executePixelSampled(float output[4],
|
||||
float x,
|
||||
float y,
|
||||
|
@ -290,11 +270,6 @@ void MixColorOperation::executePixelSampled(float output[4],
|
|||
|
||||
/* ******** Mix Darken Operation ******** */
|
||||
|
||||
MixDarkenOperation::MixDarkenOperation()
|
||||
{
|
||||
/* pass */
|
||||
}
|
||||
|
||||
void MixDarkenOperation::executePixelSampled(float output[4],
|
||||
float x,
|
||||
float y,
|
||||
|
@ -323,11 +298,6 @@ void MixDarkenOperation::executePixelSampled(float output[4],
|
|||
|
||||
/* ******** Mix Difference Operation ******** */
|
||||
|
||||
MixDifferenceOperation::MixDifferenceOperation()
|
||||
{
|
||||
/* pass */
|
||||
}
|
||||
|
||||
void MixDifferenceOperation::executePixelSampled(float output[4],
|
||||
float x,
|
||||
float y,
|
||||
|
@ -356,11 +326,6 @@ void MixDifferenceOperation::executePixelSampled(float output[4],
|
|||
|
||||
/* ******** Mix Difference Operation ******** */
|
||||
|
||||
MixDivideOperation::MixDivideOperation()
|
||||
{
|
||||
/* pass */
|
||||
}
|
||||
|
||||
void MixDivideOperation::executePixelSampled(float output[4],
|
||||
float x,
|
||||
float y,
|
||||
|
@ -406,11 +371,6 @@ void MixDivideOperation::executePixelSampled(float output[4],
|
|||
|
||||
/* ******** Mix Dodge Operation ******** */
|
||||
|
||||
MixDodgeOperation::MixDodgeOperation()
|
||||
{
|
||||
/* pass */
|
||||
}
|
||||
|
||||
void MixDodgeOperation::executePixelSampled(float output[4],
|
||||
float x,
|
||||
float y,
|
||||
|
@ -494,11 +454,6 @@ void MixDodgeOperation::executePixelSampled(float output[4],
|
|||
|
||||
/* ******** Mix Glare Operation ******** */
|
||||
|
||||
MixGlareOperation::MixGlareOperation()
|
||||
{
|
||||
/* pass */
|
||||
}
|
||||
|
||||
void MixGlareOperation::executePixelSampled(float output[4],
|
||||
float x,
|
||||
float y,
|
||||
|
@ -535,11 +490,6 @@ void MixGlareOperation::executePixelSampled(float output[4],
|
|||
|
||||
/* ******** Mix Hue Operation ******** */
|
||||
|
||||
MixHueOperation::MixHueOperation()
|
||||
{
|
||||
/* pass */
|
||||
}
|
||||
|
||||
void MixHueOperation::executePixelSampled(float output[4], float x, float y, PixelSampler sampler)
|
||||
{
|
||||
float inputColor1[4];
|
||||
|
@ -577,11 +527,6 @@ void MixHueOperation::executePixelSampled(float output[4], float x, float y, Pix
|
|||
|
||||
/* ******** Mix Lighten Operation ******** */
|
||||
|
||||
MixLightenOperation::MixLightenOperation()
|
||||
{
|
||||
/* pass */
|
||||
}
|
||||
|
||||
void MixLightenOperation::executePixelSampled(float output[4],
|
||||
float x,
|
||||
float y,
|
||||
|
@ -628,11 +573,6 @@ void MixLightenOperation::executePixelSampled(float output[4],
|
|||
|
||||
/* ******** Mix Linear Light Operation ******** */
|
||||
|
||||
MixLinearLightOperation::MixLinearLightOperation()
|
||||
{
|
||||
/* pass */
|
||||
}
|
||||
|
||||
void MixLinearLightOperation::executePixelSampled(float output[4],
|
||||
float x,
|
||||
float y,
|
||||
|
@ -676,11 +616,6 @@ void MixLinearLightOperation::executePixelSampled(float output[4],
|
|||
|
||||
/* ******** Mix Multiply Operation ******** */
|
||||
|
||||
MixMultiplyOperation::MixMultiplyOperation()
|
||||
{
|
||||
/* pass */
|
||||
}
|
||||
|
||||
void MixMultiplyOperation::executePixelSampled(float output[4],
|
||||
float x,
|
||||
float y,
|
||||
|
@ -709,11 +644,6 @@ void MixMultiplyOperation::executePixelSampled(float output[4],
|
|||
|
||||
/* ******** Mix Overlay Operation ******** */
|
||||
|
||||
MixOverlayOperation::MixOverlayOperation()
|
||||
{
|
||||
/* pass */
|
||||
}
|
||||
|
||||
void MixOverlayOperation::executePixelSampled(float output[4],
|
||||
float x,
|
||||
float y,
|
||||
|
@ -759,11 +689,6 @@ void MixOverlayOperation::executePixelSampled(float output[4],
|
|||
|
||||
/* ******** Mix Saturation Operation ******** */
|
||||
|
||||
MixSaturationOperation::MixSaturationOperation()
|
||||
{
|
||||
/* pass */
|
||||
}
|
||||
|
||||
void MixSaturationOperation::executePixelSampled(float output[4],
|
||||
float x,
|
||||
float y,
|
||||
|
@ -801,11 +726,6 @@ void MixSaturationOperation::executePixelSampled(float output[4],
|
|||
|
||||
/* ******** Mix Screen Operation ******** */
|
||||
|
||||
MixScreenOperation::MixScreenOperation()
|
||||
{
|
||||
/* pass */
|
||||
}
|
||||
|
||||
void MixScreenOperation::executePixelSampled(float output[4],
|
||||
float x,
|
||||
float y,
|
||||
|
@ -835,11 +755,6 @@ void MixScreenOperation::executePixelSampled(float output[4],
|
|||
|
||||
/* ******** Mix Soft Light Operation ******** */
|
||||
|
||||
MixSoftLightOperation::MixSoftLightOperation()
|
||||
{
|
||||
/* pass */
|
||||
}
|
||||
|
||||
void MixSoftLightOperation::executePixelSampled(float output[4],
|
||||
float x,
|
||||
float y,
|
||||
|
@ -881,11 +796,6 @@ void MixSoftLightOperation::executePixelSampled(float output[4],
|
|||
|
||||
/* ******** Mix Subtract Operation ******** */
|
||||
|
||||
MixSubtractOperation::MixSubtractOperation()
|
||||
{
|
||||
/* pass */
|
||||
}
|
||||
|
||||
void MixSubtractOperation::executePixelSampled(float output[4],
|
||||
float x,
|
||||
float y,
|
||||
|
@ -913,11 +823,6 @@ void MixSubtractOperation::executePixelSampled(float output[4],
|
|||
|
||||
/* ******** Mix Value Operation ******** */
|
||||
|
||||
MixValueOperation::MixValueOperation()
|
||||
{
|
||||
/* pass */
|
||||
}
|
||||
|
||||
void MixValueOperation::executePixelSampled(float output[4],
|
||||
float x,
|
||||
float y,
|
||||
|
|
|
@ -85,115 +85,96 @@ class MixBaseOperation : public NodeOperation {
|
|||
|
||||
class MixAddOperation : public MixBaseOperation {
|
||||
public:
|
||||
MixAddOperation();
|
||||
void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override;
|
||||
};
|
||||
|
||||
class MixBlendOperation : public MixBaseOperation {
|
||||
public:
|
||||
MixBlendOperation();
|
||||
void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override;
|
||||
};
|
||||
|
||||
class MixColorBurnOperation : public MixBaseOperation {
|
||||
public:
|
||||
MixColorBurnOperation();
|
||||
void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override;
|
||||
};
|
||||
|
||||
class MixColorOperation : public MixBaseOperation {
|
||||
public:
|
||||
MixColorOperation();
|
||||
void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override;
|
||||
};
|
||||
|
||||
class MixDarkenOperation : public MixBaseOperation {
|
||||
public:
|
||||
MixDarkenOperation();
|
||||
void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override;
|
||||
};
|
||||
|
||||
class MixDifferenceOperation : public MixBaseOperation {
|
||||
public:
|
||||
MixDifferenceOperation();
|
||||
void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override;
|
||||
};
|
||||
|
||||
class MixDivideOperation : public MixBaseOperation {
|
||||
public:
|
||||
MixDivideOperation();
|
||||
void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override;
|
||||
};
|
||||
|
||||
class MixDodgeOperation : public MixBaseOperation {
|
||||
public:
|
||||
MixDodgeOperation();
|
||||
void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override;
|
||||
};
|
||||
|
||||
class MixGlareOperation : public MixBaseOperation {
|
||||
public:
|
||||
MixGlareOperation();
|
||||
void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override;
|
||||
};
|
||||
|
||||
class MixHueOperation : public MixBaseOperation {
|
||||
public:
|
||||
MixHueOperation();
|
||||
void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override;
|
||||
};
|
||||
|
||||
class MixLightenOperation : public MixBaseOperation {
|
||||
public:
|
||||
MixLightenOperation();
|
||||
void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override;
|
||||
};
|
||||
|
||||
class MixLinearLightOperation : public MixBaseOperation {
|
||||
public:
|
||||
MixLinearLightOperation();
|
||||
void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override;
|
||||
};
|
||||
|
||||
class MixMultiplyOperation : public MixBaseOperation {
|
||||
public:
|
||||
MixMultiplyOperation();
|
||||
void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override;
|
||||
};
|
||||
|
||||
class MixOverlayOperation : public MixBaseOperation {
|
||||
public:
|
||||
MixOverlayOperation();
|
||||
void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override;
|
||||
};
|
||||
|
||||
class MixSaturationOperation : public MixBaseOperation {
|
||||
public:
|
||||
MixSaturationOperation();
|
||||
void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override;
|
||||
};
|
||||
|
||||
class MixScreenOperation : public MixBaseOperation {
|
||||
public:
|
||||
MixScreenOperation();
|
||||
void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override;
|
||||
};
|
||||
|
||||
class MixSoftLightOperation : public MixBaseOperation {
|
||||
public:
|
||||
MixSoftLightOperation();
|
||||
void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override;
|
||||
};
|
||||
|
||||
class MixSubtractOperation : public MixBaseOperation {
|
||||
public:
|
||||
MixSubtractOperation();
|
||||
void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override;
|
||||
};
|
||||
|
||||
class MixValueOperation : public MixBaseOperation {
|
||||
public:
|
||||
MixValueOperation();
|
||||
void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override;
|
||||
};
|
||||
|
||||
|
|
|
@ -384,7 +384,7 @@ void SMAABlendingWeightCalculationOperation::executePixel(float output[4],
|
|||
int bottom = searchYDown(x, y);
|
||||
int d1 = y - top, d2 = bottom - y;
|
||||
|
||||
/* Fetch the top ang bottom crossing edges: */
|
||||
/* Fetch the top and bottom crossing edges: */
|
||||
int e1 = 0, e2 = 0;
|
||||
sample(m_imageReader, x - 1, top, c);
|
||||
if (c[1] > 0.0) {
|
||||
|
|
|
@ -77,10 +77,6 @@ DepsgraphBuilder::DepsgraphBuilder(Main *bmain, Depsgraph *graph, DepsgraphBuild
|
|||
{
|
||||
}
|
||||
|
||||
DepsgraphBuilder::~DepsgraphBuilder()
|
||||
{
|
||||
}
|
||||
|
||||
bool DepsgraphBuilder::need_pull_base_into_graph(Base *base)
|
||||
{
|
||||
/* Simple check: enabled bases are always part of dependency graph. */
|
||||
|
|
|
@ -37,7 +37,7 @@ class DepsgraphBuilderCache;
|
|||
|
||||
class DepsgraphBuilder {
|
||||
public:
|
||||
virtual ~DepsgraphBuilder();
|
||||
virtual ~DepsgraphBuilder() = default;
|
||||
|
||||
virtual bool need_pull_base_into_graph(Base *base);
|
||||
|
||||
|
|
|
@ -149,10 +149,6 @@ bool AnimatedPropertyStorage::isPropertyAnimated(const PointerRNA *pointer_rna,
|
|||
|
||||
/* Builder cache itself. */
|
||||
|
||||
DepsgraphBuilderCache::DepsgraphBuilderCache()
|
||||
{
|
||||
}
|
||||
|
||||
DepsgraphBuilderCache::~DepsgraphBuilderCache()
|
||||
{
|
||||
for (AnimatedPropertyStorage *animated_property_storage :
|
||||
|
|
|
@ -81,7 +81,6 @@ class AnimatedPropertyStorage {
|
|||
/* Cached data which can be re-used by multiple builders. */
|
||||
class DepsgraphBuilderCache {
|
||||
public:
|
||||
DepsgraphBuilderCache();
|
||||
~DepsgraphBuilderCache();
|
||||
|
||||
/* Makes sure storage for animated properties exists and initialized for the given ID. */
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue