Add Support for Geometry Node Cache #92890
@ -70,3 +70,28 @@ def modifiers(object_block: BlendFileBlock) -> typing.Iterator[BlendFileBlock]:
|
|||||||
# 'ob->modifiers[...]'
|
# 'ob->modifiers[...]'
|
||||||
mods = object_block.get_pointer((b"modifiers", b"first"))
|
mods = object_block.get_pointer((b"modifiers", b"first"))
|
||||||
yield from listbase(mods, next_path=(b"modifier", b"next"))
|
yield from listbase(mods, next_path=(b"modifier", b"next"))
|
||||||
|
|
||||||
|
|
||||||
|
def copy_block(block: BlendFileBlock) -> BlendFileBlock:
|
||||||
JonasDichelle marked this conversation as resolved
|
|||||||
|
"""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."""
|
||||||
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.
|
|||||||
|
offset = block.file_offset
|
||||||
|
for i in range(block.count):
|
||||||
|
new_block = copy_block(block)
|
||||||
|
new_block.file_offset = offset
|
||||||
|
new_block.size = block.dna_type.size // block.count
|
||||||
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
```
|
|||||||
|
|
||||||
|
yield new_block
|
||||||
|
offset += block.dna_type.size
|
||||||
JonasDichelle marked this conversation as resolved
Outdated
Sybren A. Stüvel
commented
Either Either `block.dna_type.size` is the total size of the entire array (in which case this needs the `// block.count`) or it is the size of a single element in the array (in which case the `// block.count` above is incorrect).
Jonas Dichelle
commented
It's the size of an element the division there is incorrect. It's the size of an element the division there is incorrect.
|
|||||||
|
@ -25,7 +25,6 @@ files used by the modifiers.
|
|||||||
|
|
||||||
import logging
|
import logging
|
||||||
import typing
|
import typing
|
||||||
from blender_asset_tracer.blendfile.dna import Struct
|
|
||||||
from blender_asset_tracer import blendfile, bpathlib, cdefs
|
from blender_asset_tracer import blendfile, bpathlib, cdefs
|
||||||
from . import result
|
from . import result
|
||||||
|
|
||||||
@ -320,60 +319,42 @@ def modifier_cloth(
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def split_bytes_array(block: blendfile.BlendFileBlock) -> typing.Iterator[bytes]:
|
|
||||||
"""Split a bytes array into parts based on the Struct definition."""
|
|
||||||
raw_data = block.raw_data()
|
|
||||||
item_size = block.dna_type.size
|
|
||||||
for i in range(0, len(raw_data), item_size):
|
|
||||||
data_part = raw_data[i : i + item_size]
|
|
||||||
yield data_part
|
|
||||||
|
|
||||||
|
|
||||||
def bytes_to_struct(
|
|
||||||
data_bytes: bytes, struct_type: Struct, block: blendfile.BlendFileBlock
|
|
||||||
) -> dict:
|
|
||||||
"""Convert raw bytes into a struct based on the provided Struct definition."""
|
|
||||||
struct_instance = {}
|
|
||||||
|
|
||||||
for field in struct_type.fields:
|
|
||||||
start = field.offset
|
|
||||||
end = start + field.size
|
|
||||||
field_data = data_bytes[start:end]
|
|
||||||
|
|
||||||
if field.name.name_only == b"directory":
|
|
||||||
directory_pointer = int.from_bytes(field_data, "little")
|
|
||||||
directory = block.bfile.dereference_pointer(directory_pointer).as_string()
|
|
||||||
struct_instance["directory"] = directory
|
|
||||||
|
|
||||||
if field.name.name_only == b"flag":
|
|
||||||
flag_bin = bin(int.from_bytes(field_data, "little"))
|
|
||||||
flag_bin_padded = flag_bin[2:].zfill(2)
|
|
||||||
use_custom_directory = flag_bin_padded[0]
|
|
||||||
struct_instance["use_custom_directory"] = use_custom_directory
|
|
||||||
|
|
||||||
return struct_instance
|
|
||||||
|
|
||||||
|
|
||||||
@mod_handler(cdefs.eModifierType_Nodes)
|
@mod_handler(cdefs.eModifierType_Nodes)
|
||||||
def modifier_nodes(
|
def modifier_nodes(
|
||||||
ctx: ModifierContext, modifier: blendfile.BlendFileBlock, block_name: bytes
|
ctx: ModifierContext, modifier: blendfile.BlendFileBlock, block_name: bytes
|
||||||
) -> typing.Iterator[result.BlockUsage]:
|
) -> typing.Iterator[result.BlockUsage]:
|
||||||
bake_directory = modifier.get_pointer(b"simulation_bake_directory")
|
mod_directory_ptr, mod_directory_field = modifier.get(
|
||||||
bake_directory = bake_directory.as_string()
|
b"simulation_bake_directory", return_field=True
|
||||||
|
)
|
||||||
|
|
||||||
bakes = modifier.get_pointer(b"bakes")
|
bakes = modifier.get_pointer(b"bakes")
|
||||||
|
|
||||||
dna_type = bakes.dna_type
|
for bake_idx, bake in enumerate(blendfile.iterators.dynamic_array(bakes)):
|
||||||
bakes_split = split_bytes_array(bakes)
|
bake_directory_ptr, bake_directory_field = bake.get(
|
||||||
|
b"directory", return_field=True
|
||||||
|
)
|
||||||
|
|
||||||
for bake_bytes in bakes_split:
|
flag = bake.get(b"flag")
|
||||||
bake_struct = bytes_to_struct(bake_bytes, dna_type, modifier)
|
flag_bin = bin(flag)
|
||||||
if bake_struct["use_custom_directory"] == "1":
|
flag_bin_padded = flag_bin[2:].zfill(2)
|
||||||
directory = bake_struct["directory"]
|
use_custom_directory = flag_bin_padded[0] == "1"
|
||||||
|
|
||||||
|
if use_custom_directory:
|
||||||
|
directory_ptr = bake_directory_ptr
|
||||||
|
field = bake_directory_field
|
||||||
else:
|
else:
|
||||||
directory = bake_directory
|
directory_ptr = mod_directory_ptr
|
||||||
|
field = mod_directory_field
|
||||||
|
|
||||||
print(directory)
|
if directory_ptr == 0:
|
||||||
|
continue
|
||||||
|
directory = bake.bfile.dereference_pointer(directory_ptr)
|
||||||
|
if not directory:
|
||||||
|
continue
|
||||||
|
|
||||||
# yield from _walk_point_cache(
|
bpath = bytes(directory.as_string(), "utf-8")
|
||||||
# ctx, block_name, modifier.bfile, pointcache, cdefs.PTCACHE_EXT
|
bake_block_name = block_name + b".bakes[%d]" % bake_idx
|
||||||
# )
|
|
||||||
|
yield result.BlockUsage(
|
||||||
|
modifier, bpath, block_name=bake_block_name, path_full_field=field
|
||||||
|
)
|
||||||
|
Loading…
Reference in New Issue
Block a user
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() and avoid the need for this function altogether?
yes copy should work fine for this too.