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
JonasDichelle marked this conversation as resolved Outdated

The use of these directories is quite personal, and differs from developer to developer. Please put those into your .git/info/exclude file. That behaves like an extra .gitignore but isn't tracked by Git.

The use of these directories is quite personal, and differs from developer to developer. Please put those into your `.git/info/exclude` file. That behaves like an extra `.gitignore` but isn't tracked by Git.
/.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]
JonasDichelle marked this conversation as resolved Outdated

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.

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.
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,6 +350,22 @@ class BlendFile:
else:
dna_size = dna_type.size * dna_name.array_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
@ -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()