Add Support for Geometry Node Cache #92890

Open
Jonas Dichelle wants to merge 14 commits from JonasDichelle/blender-asset-tracer:geonodes_support into main

When changing the target branch, be careful to rebase the branch in your fork to match. See documentation.
3 changed files with 102 additions and 6 deletions
Showing only changes of commit 8a6c103f7d - Show all commits

5
.gitignore vendored
View File

@ -11,3 +11,8 @@ __pycache__
/build/ /build/
/docs/_build /docs/_build
# envs
/.env
/.venv

View File

@ -127,9 +127,7 @@ 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( self.code_index = collections.defaultdict(list) # type: typing.Dict[bytes, BFBList]
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]
@ -352,9 +350,25 @@ class BlendFile:
else: else:
dna_size = dna_type.size * dna_name.array_size dna_size = dna_type.size * dna_name.array_size
field = dna.Field(dna_type, dna_name, dna_size, dna_offset) if dna_name.name_only == b"bakes":
dna_struct.append_field(field) array_count = 3 # Total elements in the array
dna_offset += dna_size item_size = 48 # Size of each item in the array
dna_size = (
item_size * array_count
) # Total size occupied by the array
# Create a single field for the entire array
field = dna.Field(dna_type, dna_name, dna_size, dna_offset)
dna_struct.append_field(field)
dna_offset += (
dna_size # Increment offset by the total size of the array
)
else:
# For other fields, proceed as usual
field = dna.Field(dna_type, dna_name, dna_size, dna_offset)
dna_struct.append_field(field)
dna_offset += dna_size
def abspath(self, relpath: bpathlib.BlendPath) -> bpathlib.BlendPath: def abspath(self, relpath: bpathlib.BlendPath) -> bpathlib.BlendPath:
"""Construct an absolute path from a blendfile-relative path.""" """Construct an absolute path from a blendfile-relative path."""
@ -796,6 +810,29 @@ class BlendFileBlock:
continue continue
yield dereferenced yield dereferenced
def iter_bakes(self, array_size: int) -> typing.Iterator["BlendFileBlock"]:
"""Iterate over an array of NodesModifierBake pointers with known size."""
path = (
b"bakes" # Assuming 'bakes' is the DNA field name for the array of pointers
)
if array_size == 0:
return
array = self.get_pointer(path)
assert array and array.code == b"DATA", "Expected DATA block, got {}".format(
array.code.decode()
)
file_offset = array.file_offset
ps = self.bfile.header.pointer_size
for i in range(array_size):
address = self.bfile.read_pointer_at(file_offset + ps * i)
if address:
dereferenced = self.bfile.dereference_pointer(address)
if dereferenced:
yield dereferenced
def __getitem__(self, path: dna.FieldPath): def __getitem__(self, path: dna.FieldPath):
return self.get(path) return self.get(path)

View File

@ -22,12 +22,18 @@
The modifier_xxx() functions all yield result.BlockUsage objects for external The modifier_xxx() functions all yield result.BlockUsage objects for external
files used by the modifiers. files used by the modifiers.
""" """
import struct
import logging import logging
import typing import typing
from blender_asset_tracer.blendfile import iterators
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
import ctypes
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
modifier_handlers = {} # type: typing.Dict[int, typing.Callable] modifier_handlers = {} # type: typing.Dict[int, typing.Callable]
@ -317,3 +323,51 @@ def modifier_cloth(
yield from _walk_point_cache( yield from _walk_point_cache(
ctx, block_name, modifier.bfile, pointcache, cdefs.PTCACHE_EXT ctx, block_name, modifier.bfile, pointcache, cdefs.PTCACHE_EXT
) )
def split_bytes_array(raw_data: bytes, item_size: int) -> typing.Iterator[bytes]:
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):
"""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]
value = field_data.hex()
struct_instance[field.name.name_only] = value
return struct_instance
@mod_handler(cdefs.eModifierType_Nodes)
def modifier_nodes(
ctx: ModifierContext, modifier: blendfile.BlendFileBlock, block_name: bytes
) -> typing.Iterator[result.BlockUsage]:
bake_directory = modifier.get_pointer(b"simulation_bake_directory")
# print(bake_directory)
bakes_ptr = modifier.get(b"bakes")
bakes_num = modifier.get(b"bakes_num")
bakes = modifier.get_pointer(b"bakes")
raw_bakes = bakes.raw_data()
dna_type = bakes.dna_type
print(list(bakes.values()))
bakes_split = split_bytes_array(raw_bakes, dna_type.size)
for bake_bytes in bakes_split:
bake_struct = bytes_to_struct(bake_bytes, dna_type)
print(bake_struct)
# yield bake_struct
quit()