Add Support for Geometry Node Cache #92890
3
.gitignore
vendored
@ -11,6 +11,3 @@ __pycache__
|
||||
/build/
|
||||
|
||||
/docs/_build
|
||||
|
||||
/.env
|
||||
/.venv
|
@ -127,7 +127,9 @@ class BlendFile:
|
||||
self.blocks = [] # type: BFBList
|
||||
"""BlendFileBlocks of this file, in disk order."""
|
||||
|
||||
self.code_index = collections.defaultdict(list) # type: typing.Dict[bytes, BFBList]
|
||||
self.code_index = collections.defaultdict(
|
||||
JonasDichelle marked this conversation as resolved
Outdated
|
||||
list
|
||||
) # type: typing.Dict[bytes, BFBList]
|
||||
self.structs = [] # type: typing.List[dna.Struct]
|
||||
self.sdna_index_from_id = {} # type: typing.Dict[bytes, int]
|
||||
self.block_from_addr = {} # type: typing.Dict[int, BlendFileBlock]
|
||||
|
@ -20,6 +20,7 @@
|
||||
# (c) 2014, Blender Foundation - Campbell Barton
|
||||
# (c) 2018, Blender Foundation - Sybren A. Stüvel
|
||||
import typing
|
||||
import copy
|
||||
|
||||
from blender_asset_tracer import cdefs
|
||||
from . import BlendFileBlock
|
||||
@ -72,26 +73,22 @@ def modifiers(object_block: BlendFileBlock) -> typing.Iterator[BlendFileBlock]:
|
||||
yield from listbase(mods, next_path=(b"modifier", b"next"))
|
||||
|
||||
|
||||
JonasDichelle marked this conversation as resolved
Sybren A. Stüvel
commented
I think it's fine to make this function a method on Then again, is there any reason to not use copy.copy() and avoid the need for this function altogether? I think it's fine to make this function a method on `BlendFileBlock`. It could then simply be named `.clone()` or `.copy()`.
Then again, is there any reason to not use [copy.copy()](https://docs.python.org/3/library/copy.html#copy.copy) and avoid the need for this function altogether?
Jonas Dichelle
commented
yes copy should work fine for this too. yes copy should work fine for this too.
|
||||
def copy_block(block: BlendFileBlock) -> BlendFileBlock:
|
||||
"""Create a new BlendFileBlock instance with the same slot data as the provided block."""
|
||||
if not isinstance(block, BlendFileBlock):
|
||||
raise ValueError("The existing_block must be an instance of BlendFileBlock")
|
||||
|
||||
new_block = BlendFileBlock(block.bfile)
|
||||
|
||||
for slot in BlendFileBlock.__slots__:
|
||||
setattr(new_block, slot, getattr(block, slot))
|
||||
|
||||
return new_block
|
||||
|
||||
|
||||
def dynamic_array(block: BlendFileBlock) -> typing.Iterator[BlendFileBlock]:
|
||||
"""Generator, yields all blocks in a block that is a dynamic array."""
|
||||
"""
|
||||
Generator that yields each element of a dynamic array as a separate block.
|
||||
|
||||
Dynamic arrays are multiple contiguous elements accessed via a single pointer.
|
||||
BAT interprets these as a single data block, making it hard to access individual elements.
|
||||
This function divides the array into individual blocks by creating modified copies of the original block.
|
||||
"""
|
||||
|
||||
offset = block.file_offset
|
||||
element_size = block.dna_type.size
|
||||
|
||||
for i in range(block.count):
|
||||
new_block = copy_block(block)
|
||||
new_block = copy.copy(block)
|
||||
Sybren A. Stüvel
commented
Please add a bit more explanation to this documentation. This first line is fine, but then I would love to see some explanation of what a "dynamic array" is in this context. Please add a bit more explanation to this documentation. This first line is fine, but then I would love to see some explanation of what a "dynamic array" is in this context.
|
||||
new_block.file_offset = offset
|
||||
new_block.size = block.dna_type.size // block.count
|
||||
new_block.size = element_size
|
||||
|
||||
yield new_block
|
||||
offset += block.dna_type.size
|
||||
offset += element_size
|
||||
JonasDichelle marked this conversation as resolved
Outdated
Sybren A. Stüvel
commented
Instead of making Python do the
Instead of making Python do the `block.dna_type.size` lookup twice per loop, do that once outside the loop and store the value in a local variable.
```
block_size = block.dna_type.size // block.count
```
|
||||
|
@ -52,6 +52,9 @@ eModifierType_MeshSequenceCache = 52
|
||||
eModifierType_Fluid = 56
|
||||
eModifierType_Nodes = 57
|
||||
|
||||
# NodesModifierBakeFlag
|
||||
NODES_MODIFIER_BAKE_CUSTOM_PATH = 1 << 1
|
||||
|
||||
# DNA_particle_types.h
|
||||
PART_DRAW_OB = 7
|
||||
PART_DRAW_GR = 8
|
||||
|
@ -369,9 +369,7 @@ def modifier_nodes(
|
||||
)
|
||||
|
||||
flag = bake.get(b"flag")
|
||||
flag_bin = bin(flag)
|
||||
flag_bin_padded = flag_bin[2:].zfill(2)
|
||||
use_custom_directory = flag_bin_padded[0] == "1"
|
||||
use_custom_directory = bool(flag & cdefs.NODES_MODIFIER_BAKE_CUSTOM_PATH)
|
||||
|
||||
if use_custom_directory:
|
||||
JonasDichelle marked this conversation as resolved
Sybren A. Stüvel
commented
Please don't use string operations to get a single bit flag. Add a constant to
Please don't use string operations to get a single bit flag. Add a constant to `cdefs.py` with the name of the flag, then use something like:
```python
use_custom_path = bool(flag & cdefs.NODES_MODIFIER_BAKE_CUSTOM_PATH)
```
|
||||
directory_ptr = bake_directory_ptr
|
||||
@ -382,7 +380,7 @@ def modifier_nodes(
|
||||
field = mod_directory_field
|
||||
block = modifier
|
||||
|
||||
if directory_ptr == 0:
|
||||
if not directory_ptr:
|
||||
continue
|
||||
directory = bake.bfile.dereference_pointer(directory_ptr)
|
||||
JonasDichelle marked this conversation as resolved
Sybren A. Stüvel
commented
I think it's slightly nicer to not compare to a concrete value, and just use I think it's slightly nicer to not compare to a concrete value, and just use `if not directory_ptr:`
|
||||
if not directory:
|
||||
|
Please keep formatting changes out of this PR. There is no direct need for this PR to modify this file.
Of course non-functional improvements like this are always welcome, but shouldn't be part of the same PR as functional changes.