Add Support for Geometry Node Cache #92890
5
.gitignore
vendored
@ -10,7 +10,4 @@ __pycache__
|
|||||||
/dist/
|
/dist/
|
||||||
/build/
|
/build/
|
||||||
|
|
||||||
/docs/_build
|
/docs/_build
|
||||||
|
|
||||||
/.env
|
|
||||||
/.venv
|
|
@ -127,7 +127,9 @@ class BlendFile:
|
|||||||
self.blocks = [] # type: BFBList
|
self.blocks = [] # type: BFBList
|
||||||
"""BlendFileBlocks of this file, in disk order."""
|
"""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.structs = [] # type: typing.List[dna.Struct]
|
||||||
self.sdna_index_from_id = {} # type: typing.Dict[bytes, int]
|
self.sdna_index_from_id = {} # type: typing.Dict[bytes, int]
|
||||||
self.block_from_addr = {} # type: typing.Dict[int, BlendFileBlock]
|
self.block_from_addr = {} # type: typing.Dict[int, BlendFileBlock]
|
||||||
|
@ -20,6 +20,7 @@
|
|||||||
# (c) 2014, Blender Foundation - Campbell Barton
|
# (c) 2014, Blender Foundation - Campbell Barton
|
||||||
# (c) 2018, Blender Foundation - Sybren A. Stüvel
|
# (c) 2018, Blender Foundation - Sybren A. Stüvel
|
||||||
import typing
|
import typing
|
||||||
|
import copy
|
||||||
|
|
||||||
from blender_asset_tracer import cdefs
|
from blender_asset_tracer import cdefs
|
||||||
from . import BlendFileBlock
|
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"))
|
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]:
|
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
|
offset = block.file_offset
|
||||||
|
element_size = block.dna_type.size
|
||||||
|
|
||||||
for i in range(block.count):
|
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.file_offset = offset
|
||||||
new_block.size = block.dna_type.size // block.count
|
new_block.size = element_size
|
||||||
|
|
||||||
yield new_block
|
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_Fluid = 56
|
||||||
eModifierType_Nodes = 57
|
eModifierType_Nodes = 57
|
||||||
|
|
||||||
|
# NodesModifierBakeFlag
|
||||||
|
NODES_MODIFIER_BAKE_CUSTOM_PATH = 1 << 1
|
||||||
|
|
||||||
# DNA_particle_types.h
|
# DNA_particle_types.h
|
||||||
PART_DRAW_OB = 7
|
PART_DRAW_OB = 7
|
||||||
PART_DRAW_GR = 8
|
PART_DRAW_GR = 8
|
||||||
@ -101,4 +104,4 @@ PTCACHE_PATH = b"blendcache_"
|
|||||||
|
|
||||||
# BKE_node.h
|
# BKE_node.h
|
||||||
SH_NODE_TEX_IMAGE = 143
|
SH_NODE_TEX_IMAGE = 143
|
||||||
CMP_NODE_R_LAYERS = 221
|
CMP_NODE_R_LAYERS = 221
|
@ -369,9 +369,7 @@ def modifier_nodes(
|
|||||||
)
|
)
|
||||||
|
|
||||||
flag = bake.get(b"flag")
|
flag = bake.get(b"flag")
|
||||||
flag_bin = bin(flag)
|
use_custom_directory = bool(flag & cdefs.NODES_MODIFIER_BAKE_CUSTOM_PATH)
|
||||||
flag_bin_padded = flag_bin[2:].zfill(2)
|
|
||||||
use_custom_directory = flag_bin_padded[0] == "1"
|
|
||||||
|
|
||||||
if use_custom_directory:
|
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
|
directory_ptr = bake_directory_ptr
|
||||||
@ -382,7 +380,7 @@ def modifier_nodes(
|
|||||||
field = mod_directory_field
|
field = mod_directory_field
|
||||||
block = modifier
|
block = modifier
|
||||||
|
|
||||||
if directory_ptr == 0:
|
if not directory_ptr:
|
||||||
continue
|
continue
|
||||||
directory = bake.bfile.dereference_pointer(directory_ptr)
|
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:
|
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.