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/
/docs/_build
# envs
/.env
/.venv

View File

@ -127,9 +127,7 @@ 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(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]
@ -352,9 +350,25 @@ class BlendFile:
else:
dna_size = dna_type.size * dna_name.array_size
field = dna.Field(dna_type, dna_name, dna_size, dna_offset)
dna_struct.append_field(field)
dna_offset += dna_size
if dna_name.name_only == b"bakes":
array_count = 3 # Total elements in the array
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:
"""Construct an absolute path from a blendfile-relative path."""
@ -796,6 +810,29 @@ class BlendFileBlock:
continue
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):
return self.get(path)

View File

@ -22,12 +22,18 @@
The modifier_xxx() functions all yield result.BlockUsage objects for external
files used by the modifiers.
"""
import struct
import logging
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 . import result
import ctypes
log = logging.getLogger(__name__)
modifier_handlers = {} # type: typing.Dict[int, typing.Callable]
@ -317,3 +323,51 @@ def modifier_cloth(
yield from _walk_point_cache(
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()